Add rpl::take(count).

This commit is contained in:
John Preston 2017-10-01 12:39:07 +03:00
parent f0ad78d808
commit c4d33f9986
9 changed files with 135 additions and 18 deletions

View File

@ -20,6 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#include "boxes/change_phone_box.h"
#include <rpl/filter.h>
#include <rpl/mappers.h>
#include <rpl/take.h>
#include "lang/lang_keys.h"
#include "styles/style_boxes.h"
#include "ui/widgets/labels.h"
@ -39,13 +42,19 @@ void createErrorLabel(
int y) {
if (label) {
label->hide(anim::type::normal);
auto context = label.data();
App::CallDelayed(
st::fadeWrapDuration,
context,
[old = std::move(label)]() mutable {
old.destroy();
});
auto saved = label.data();
auto destroy = [old = std::move(label)]() mutable {
old.destroyDelayed();
};
using namespace rpl::mappers;
saved->shownValue()
| rpl::filter($1 == false)
| rpl::take(1)
| rpl::start_with_done(
std::move(destroy),
saved->lifetime());
}
if (!text.isEmpty()) {
label.create(

View File

@ -388,4 +388,18 @@ TEST_CASE("basic operators tests", "[rpl::operators]") {
}
REQUIRE(*sum == "0-11-22-3");
}
SECTION("take test") {
auto sum = std::make_shared<std::string>("");
{
rpl::lifetime lifetime;
rpl::ints(10) | take(3)
| start_with_next_done([=](int value) {
*sum += std::to_string(value);
}, [=] {
*sum += "done";
}, lifetime);
}
REQUIRE(*sum == "012done");
}
}

View File

@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <rpl/fail.h>
#include <rpl/never.h>
#include <rpl/take.h>
#include <rpl/then.h>
#include <rpl/deferred.h>
#include <rpl/map.h>

View File

@ -0,0 +1,74 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
namespace rpl {
namespace details {
class take_helper {
public:
take_helper(int count) : _count(count) {
}
template <
typename Value,
typename Error,
typename Generator>
auto operator()(producer<Value, Error, Generator> &&initial) {
return make_producer<Value, Error>([
initial = std::move(initial),
limit = _count
](const auto &consumer) mutable {
auto count = consumer.template make_state<int>(limit);
return std::move(initial).start(
[consumer, count](auto &&value) {
auto left = (*count)--;
if (left) {
consumer.put_next_forward(
std::forward<decltype(value)>(value));
--left;
}
if (!left) {
consumer.put_done();
}
}, [consumer](auto &&error) {
consumer.put_error_forward(
std::forward<decltype(error)>(error));
}, [consumer] {
consumer.put_done();
});
});
}
private:
int _count = 0;
};
} // namespace details
inline auto take(int count)
-> details::take_helper {
Expects(count >= 0);
return details::take_helper(count);
}
} // namespace rpl

View File

@ -20,8 +20,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#include "ui/abstract_button.h"
#include <rpl/filter.h>
#include <rpl/mappers.h>
namespace Ui {
AbstractButton::AbstractButton(QWidget *parent) : RpWidget(parent) {
setMouseTracking(true);
using namespace rpl::mappers;
shownValue()
| rpl::filter($1 == false)
| rpl::start_with_next([this] { clearState(); }, lifetime());
}
void AbstractButton::leaveEventHook(QEvent *e) {
if (_state & StateFlag::Down) return;

View File

@ -30,9 +30,7 @@ class AbstractButton : public RpWidget {
Q_OBJECT
public:
AbstractButton(QWidget *parent) : RpWidget(parent) {
setMouseTracking(true);
}
AbstractButton(QWidget *parent);
Qt::KeyboardModifiers clickModifiers() const {
return _modifiers;
@ -58,13 +56,6 @@ public:
_clickedCallback = std::move(callback);
}
void setVisible(bool visible) override {
TWidget::setVisible(visible);
if (!visible) {
clearState();
}
}
auto clicks() const {
return _clicks.events();
}

View File

@ -100,7 +100,6 @@ void FadeAnimation::stopAnimation() {
_animation.finish();
if (!_cache.isNull()) {
_cache = QPixmap();
updateCallback();
if (_visible) {
_widget->showChildren();
}

View File

@ -76,6 +76,10 @@ public:
virtual rpl::producer<int> desiredHeightValue() const {
return heightValue();
}
auto shownValue() const {
auto &stream = eventStreams().shown;
return stream.events_starting_with(!this->isHidden());
}
auto paintRequest() const {
return eventStreams().paint.events();
@ -85,6 +89,17 @@ public:
return eventStreams().alive.events();
}
void setVisible(bool visible) final override {
auto wasVisible = !this->isHidden();
Parent::setVisible(visible);
auto nowVisible = !this->isHidden();
if (nowVisible != wasVisible) {
if (auto streams = _eventStreams.get()) {
streams->shown.fire_copy(nowVisible);
}
}
}
template <typename Error, typename Generator>
void showOn(rpl::producer<bool, Error, Generator> &&shown) {
std::move(shown)
@ -133,6 +148,7 @@ private:
struct EventStreams {
rpl::event_stream<QRect> geometry;
rpl::event_stream<QRect> paint;
rpl::event_stream<bool> shown;
rpl::event_stream<> alive;
};
struct LifetimeHolder {

View File

@ -121,6 +121,7 @@
'<(src_loc)/rpl/producer_tests.cpp',
'<(src_loc)/rpl/range.h',
'<(src_loc)/rpl/rpl.h',
'<(src_loc)/rpl/take.h',
'<(src_loc)/rpl/then.h',
'<(src_loc)/rpl/type_erased.h',
'<(src_loc)/rpl/variable.h',