Move Info::TopBarOverride to Info::TopBar.

This allows to improve animations in shared media items selection.
This commit is contained in:
John Preston 2017-11-27 15:43:57 +04:00
parent 6afe18503d
commit d014b47958
27 changed files with 341 additions and 502 deletions

View File

@ -26,18 +26,18 @@ template <typename T>
class unique_qptr { class unique_qptr {
public: public:
unique_qptr() = default; unique_qptr() = default;
unique_qptr(std::nullptr_t) { unique_qptr(std::nullptr_t) noexcept {
} }
explicit unique_qptr(T *pointer) explicit unique_qptr(T *pointer) noexcept
: _object(pointer) { : _object(pointer) {
} }
unique_qptr(const unique_qptr &other) = delete; unique_qptr(const unique_qptr &other) = delete;
unique_qptr &operator=(const unique_qptr &other) = delete; unique_qptr &operator=(const unique_qptr &other) = delete;
unique_qptr(unique_qptr &&other) unique_qptr(unique_qptr &&other) noexcept
: _object(base::take(other._object)) { : _object(base::take(other._object)) {
} }
unique_qptr &operator=(unique_qptr &&other) { unique_qptr &operator=(unique_qptr &&other) noexcept {
if (_object != other._object) { if (_object != other._object) {
destroy(); destroy();
_object = base::take(other._object); _object = base::take(other._object);
@ -48,14 +48,14 @@ public:
template < template <
typename U, typename U,
typename = std::enable_if_t<std::is_base_of_v<T, U>>> typename = std::enable_if_t<std::is_base_of_v<T, U>>>
unique_qptr(unique_qptr<U> &&other) unique_qptr(unique_qptr<U> &&other) noexcept
: _object(base::take(other._object)) { : _object(base::take(other._object)) {
} }
template < template <
typename U, typename U,
typename = std::enable_if_t<std::is_base_of_v<T, U>>> typename = std::enable_if_t<std::is_base_of_v<T, U>>>
unique_qptr &operator=(unique_qptr<U> &&other) { unique_qptr &operator=(unique_qptr<U> &&other) noexcept {
if (_object != other._object) { if (_object != other._object) {
destroy(); destroy();
_object = base::take(other._object); _object = base::take(other._object);
@ -63,49 +63,60 @@ public:
return *this; return *this;
} }
unique_qptr &operator=(std::nullptr_t) { unique_qptr &operator=(std::nullptr_t) noexcept {
destroy(); destroy();
return *this; return *this;
} }
void reset(T *value = nullptr) { template <typename ...Args>
explicit unique_qptr(std::in_place_t, Args &&...args)
: _object(new T(std::forward<Args>(args)...)) {
}
template <typename ...Args>
T *emplace(Args &&...args) {
reset(new T(std::forward<Args>(args)...));
return get();
}
void reset(T *value = nullptr) noexcept {
if (_object != value) { if (_object != value) {
destroy(); destroy();
_object = value; _object = value;
} }
} }
T *get() const { T *get() const noexcept {
return static_cast<T*>(_object.data()); return static_cast<T*>(_object.data());
} }
operator T*() const { operator T*() const noexcept {
return get(); return get();
} }
T *release() { T *release() noexcept {
return static_cast<T*>(base::take(_object).data()); return static_cast<T*>(base::take(_object).data());
} }
explicit operator bool() const { explicit operator bool() const noexcept {
return _object != nullptr; return _object != nullptr;
} }
T *operator->() const { T *operator->() const noexcept {
return get(); return get();
} }
T &operator*() const { T &operator*() const noexcept {
return *get(); return *get();
} }
void destroy() { ~unique_qptr() noexcept {
delete base::take(_object).data();
}
~unique_qptr() {
destroy(); destroy();
} }
private: private:
void destroy() noexcept {
delete base::take(_object).data();
}
template <typename U> template <typename U>
friend class unique_qptr; friend class unique_qptr;
@ -115,7 +126,7 @@ private:
template <typename T, typename ...Args> template <typename T, typename ...Args>
inline unique_qptr<T> make_unique_q(Args &&...args) { inline unique_qptr<T> make_unique_q(Args &&...args) {
return unique_qptr<T>(new T(std::forward<Args>(args)...)); return unique_qptr<T>(std::in_place, std::forward<Args>(args)...);
} }
} // namespace base } // namespace base

View File

@ -1350,7 +1350,7 @@ void StickersBox::Inner::rebuildMegagroupSet() {
if (!_megagroupSelectedRemove) { if (!_megagroupSelectedRemove) {
_megagroupSelectedRemove.create(this, st::groupStickersRemove); _megagroupSelectedRemove.create(this, st::groupStickersRemove);
_megagroupSelectedRemove->showFast(); _megagroupSelectedRemove->show(anim::type::instant);
_megagroupSelectedRemove->setClickedCallback([this] { _megagroupSelectedRemove->setClickedCallback([this] {
setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
}); });

View File

@ -85,7 +85,9 @@ GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(p
} }
}); });
connect(_field, &Ui::InputField::changed, this, [this] { connect(_field, &Ui::InputField::changed, this, [this] {
_cancel->toggleAnimated(!_field->getLastText().isEmpty()); _cancel->toggle(
!_field->getLastText().isEmpty(),
anim::type::normal);
_pan->searchForGifs(_field->getLastText()); _pan->searchForGifs(_field->getLastText());
}); });
_cancel->setClickedCallback([this] { _cancel->setClickedCallback([this] {

View File

@ -267,7 +267,7 @@ void DialogsWidget::showAnimated(Window::SlideDirection direction, const Window:
_mainMenuToggle->hide(); _mainMenuToggle->hide();
if (_forwardCancel) _forwardCancel->hide(); if (_forwardCancel) _forwardCancel->hide();
_filter->hide(); _filter->hide();
_cancelSearch->hide(); _cancelSearch->hide(anim::type::instant);
_jumpToDate->hide(anim::type::instant); _jumpToDate->hide(anim::type::instant);
_chooseFromUser->hide(anim::type::instant); _chooseFromUser->hide(anim::type::instant);
_lockUnlock->hide(); _lockUnlock->hide();
@ -827,10 +827,8 @@ void DialogsWidget::onFilterUpdate(bool force) {
_inner->onFilterUpdate(filterText, force); _inner->onFilterUpdate(filterText, force);
if (filterText.isEmpty()) { if (filterText.isEmpty()) {
clearSearchCache(); clearSearchCache();
_cancelSearch->hideAnimated();
} else {
_cancelSearch->showAnimated();
} }
_cancelSearch->toggle(!filterText.isEmpty(), anim::type::normal);
updateJumpToDateVisibility(); updateJumpToDateVisibility();
if (filterText.size() < MinUsernameLength) { if (filterText.size() < MinUsernameLength) {

View File

@ -128,7 +128,7 @@ FixedBar::FixedBar(
connect(_field, &Ui::FlatInput::submitted, this, [this] { applySearch(); }); connect(_field, &Ui::FlatInput::submitted, this, [this] { applySearch(); });
_searchTimer.setCallback([this] { applySearch(); }); _searchTimer.setCallback([this] { applySearch(); });
_cancel->hideFast(); _cancel->hide(anim::type::instant);
} }
void FixedBar::applyFilter(const FilterValue &value) { void FixedBar::applyFilter(const FilterValue &value) {
@ -148,7 +148,7 @@ void FixedBar::showSearch() {
void FixedBar::toggleSearch() { void FixedBar::toggleSearch() {
_searchShown = !_searchShown; _searchShown = !_searchShown;
_cancel->toggleAnimated(_searchShown); _cancel->toggle(_searchShown, anim::type::normal);
_searchShownAnimation.start([this] { searchAnimationCallback(); }, _searchShown ? 0. : 1., _searchShown ? 1. : 0., st::historyAdminLogSearchSlideDuration); _searchShownAnimation.start([this] { searchAnimationCallback(); }, _searchShown ? 0. : 1., _searchShown ? 1. : 0., st::historyAdminLogSearchSlideDuration);
_search->setDisabled(_searchShown); _search->setDisabled(_searchShown);
if (_searchShown) { if (_searchShown) {
@ -227,7 +227,7 @@ void FixedBar::setAnimatingMode(bool enabled) {
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
showChildren(); showChildren();
_field->hide(); _field->hide();
_cancel->hide(); _cancel->setVisible(false);
} }
show(); show();
} }

View File

@ -190,6 +190,8 @@ infoTopBar: InfoTopBar {
highlightBg: windowBgOver; highlightBg: windowBgOver;
highlightDuration: 240; highlightDuration: 240;
} }
infoTopBarScale: 0.7;
infoTopBarDuration: 150;
infoLayerTopMinimal: 20px; infoLayerTopMinimal: 20px;
infoLayerTopMaximal: 40px; infoLayerTopMaximal: 40px;

View File

@ -50,18 +50,50 @@ TopBar::TopBar(
, _selectedItems(Section::MediaType::kCount) { , _selectedItems(Section::MediaType::kCount) {
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
setSelectedItems(std::move(selectedItems)); setSelectedItems(std::move(selectedItems));
finishSelectionAnimations(); updateControlsVisibility(anim::type::instant);
}
template <typename Callback>
void TopBar::registerUpdateControlCallback(
QObject *guard,
Callback &&callback) {
_updateControlCallbacks[guard] =[
object = weak(guard),
callback = std::forward<Callback>(callback)
](anim::type animated) {
if (!object) {
return false;
}
callback(animated);
return true;
};
}
template <typename Widget, typename IsVisible>
void TopBar::registerToggleControlCallback(
Widget *widget,
IsVisible &&callback) {
registerUpdateControlCallback(widget, [
widget,
isVisible = std::forward<IsVisible>(callback)
](anim::type animated) {
widget->toggle(isVisible(), animated);
});
} }
void TopBar::setTitle(rpl::producer<QString> &&title) { void TopBar::setTitle(rpl::producer<QString> &&title) {
if (_title) { if (_title) {
delete _title; delete _title;
} }
_title = Ui::CreateChild<Ui::FadeWrapScaled<Ui::FlatLabel>>( _title = Ui::CreateChild<Ui::FadeWrap<Ui::FlatLabel>>(
this, this,
object_ptr<Ui::FlatLabel>(this, std::move(title), _st.title)); object_ptr<Ui::FlatLabel>(this, std::move(title), _st.title),
st::infoTopBarScale);
_title->setDuration(st::infoTopBarDuration);
_title->toggle(!selectionMode(), anim::type::instant); _title->toggle(!selectionMode(), anim::type::instant);
_defaultControls.push_back(_title.data()); registerToggleControlCallback(_title.data(), [=] {
return !selectionMode() && !searchMode();
});
if (_back) { if (_back) {
_title->setAttribute(Qt::WA_TransparentForMouseEvents); _title->setAttribute(Qt::WA_TransparentForMouseEvents);
@ -73,13 +105,17 @@ void TopBar::enableBackButton() {
if (_back) { if (_back) {
return; return;
} }
_back = Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( _back = Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>(
this, this,
object_ptr<Ui::IconButton>(this, _st.back)); object_ptr<Ui::IconButton>(this, _st.back),
st::infoTopBarScale);
_back->setDuration(st::infoTopBarDuration);
_back->toggle(!selectionMode(), anim::type::instant); _back->toggle(!selectionMode(), anim::type::instant);
_back->entity()->clicks() _back->entity()->clicks()
| rpl::start_to_stream(_backClicks, _back->lifetime()); | rpl::start_to_stream(_backClicks, _back->lifetime());
_defaultControls.push_back(_back.data()); registerToggleControlCallback(_back.data(), [=] {
return !selectionMode();
});
if (_title) { if (_title) {
_title->setAttribute(Qt::WA_TransparentForMouseEvents); _title->setAttribute(Qt::WA_TransparentForMouseEvents);
@ -95,14 +131,24 @@ void TopBar::createSearchView(
std::move(shown)); std::move(shown));
} }
void TopBar::pushButton(base::unique_qptr<Ui::RpWidget> button) { Ui::FadeWrap<Ui::RpWidget> *TopBar::pushButton(
auto weak = button.get(); base::unique_qptr<Ui::RpWidget> button) {
_buttons.push_back(std::move(button)); auto wrapped = base::make_unique_q<Ui::FadeWrap<Ui::RpWidget>>(
weak->setParent(this); this,
object_ptr<Ui::RpWidget>::fromRaw(button.release()),
st::infoTopBarScale);
auto weak = wrapped.get();
_buttons.push_back(std::move(wrapped));
weak->setDuration(st::infoTopBarDuration);
registerToggleControlCallback(weak, [=] {
return !selectionMode()
&& !_searchModeEnabled;
});
weak->widthValue() weak->widthValue()
| rpl::start_with_next([this] { | rpl::start_with_next([this] {
updateControlsGeometry(width()); updateControlsGeometry(width());
}, lifetime()); }, lifetime());
return weak;
} }
void TopBar::setSearchField( void TopBar::setSearchField(
@ -122,59 +168,75 @@ void TopBar::createSearchView(
this, this,
_st.searchRow.height); _st.searchRow.height);
auto wrap = _searchView.get(); auto wrap = _searchView.get();
registerUpdateControlCallback(wrap, [=](anim::type) {
wrap->setVisible(!selectionMode() && _searchModeAvailable);
});
field->setParent(wrap); auto fieldWrap = Ui::CreateChild<Ui::FadeWrap<Ui::InputField>>(
auto search = addButton(
base::make_unique_q<Ui::FadeWrapScaled<Ui::FadeWrapScaled<Ui::IconButton>>>(
this,
object_ptr<Ui::FadeWrapScaled<Ui::IconButton>>(
this,
object_ptr<Ui::IconButton>(this, _st.search))));
_defaultControls.push_back(search);
auto cancel = Ui::CreateChild<Ui::FadeWrapScaled<Ui::CrossButton>>(
wrap, wrap,
object_ptr<Ui::CrossButton>(wrap, _st.searchRow.fieldCancel)); object_ptr<Ui::InputField>::fromRaw(field),
_defaultControls.push_back(cancel); st::infoTopBarScale);
fieldWrap->setDuration(st::infoTopBarDuration);
auto toggleSearchMode = [=](bool enabled, anim::type animated) { auto focusLifetime = field->lifetime().make_state<rpl::lifetime>();
if (!enabled) { registerUpdateControlCallback(fieldWrap, [=](anim::type animated) {
auto fieldShown = !selectionMode() && searchMode();
if (!fieldShown && field->hasFocus()) {
setFocus(); setFocus();
} }
if (_title) { fieldWrap->toggle(fieldShown, animated);
_title->entity()->setVisible(!enabled); if (fieldShown) {
*focusLifetime = field->shownValue()
| rpl::filter([](bool shown) { return shown; })
| rpl::take(1)
| rpl::start_with_next([=] {
field->setFocus();
});
} else {
focusLifetime->destroy();
} }
field->setVisible(enabled); });
cancel->entity()->toggleAnimated(enabled);
if (animated == anim::type::instant) { auto button = base::make_unique_q<Ui::IconButton>(this, _st.search);
cancel->entity()->finishAnimations(); auto search = button.get();
} search->addClickHandler([=] {
search->wrapped()->toggle(!enabled, animated); _searchModeEnabled = true;
if (enabled) { updateControlsVisibility(anim::type::normal);
field->setFocus(); });
} auto searchWrap = pushButton(std::move(button));
}; registerToggleControlCallback(searchWrap, [=] {
return !selectionMode()
&& _searchModeAvailable
&& !_searchModeEnabled;
});
auto cancel = Ui::CreateChild<Ui::CrossButton>(
wrap,
_st.searchRow.fieldCancel);
registerToggleControlCallback(cancel, [=] {
return !selectionMode() && searchMode();
});
auto cancelSearch = [=] { auto cancelSearch = [=] {
if (!field->getLastText().isEmpty()) { if (!field->getLastText().isEmpty()) {
field->setText(QString()); field->setText(QString());
} else { } else {
toggleSearchMode(false, anim::type::normal); _searchModeEnabled = false;
updateControlsVisibility(anim::type::normal);
} }
}; };
cancel->entity()->addClickHandler(cancelSearch); cancel->addClickHandler(cancelSearch);
field->connect(field, &Ui::InputField::cancelled, cancelSearch); field->connect(field, &Ui::InputField::cancelled, cancelSearch);
wrap->widthValue() wrap->widthValue()
| rpl::start_with_next([=](int newWidth) { | rpl::start_with_next([=](int newWidth) {
auto availableWidth = newWidth auto availableWidth = newWidth
- _st.searchRow.fieldCancelSkip; - _st.searchRow.fieldCancelSkip;
field->setGeometryToLeft( fieldWrap->resizeToWidth(availableWidth);
fieldWrap->moveToLeft(
_st.searchRow.padding.left(), _st.searchRow.padding.left(),
_st.searchRow.padding.top(), _st.searchRow.padding.top());
availableWidth,
field->height());
cancel->moveToRight(0, 0); cancel->moveToRight(0, 0);
}, wrap->lifetime()); }, wrap->lifetime());
@ -191,10 +253,6 @@ void TopBar::createSearchView(
newWidth); newWidth);
}, wrap->lifetime()); }, wrap->lifetime());
search->entity()->addClickHandler([=] {
toggleSearchMode(true, anim::type::normal);
});
field->alive() field->alive()
| rpl::start_with_done([=] { | rpl::start_with_done([=] {
field->setParent(nullptr); field->setParent(nullptr);
@ -202,18 +260,14 @@ void TopBar::createSearchView(
setSearchField(nullptr, rpl::never<bool>()); setSearchField(nullptr, rpl::never<bool>());
}, _searchView->lifetime()); }, _searchView->lifetime());
toggleSearchMode( _searchModeEnabled = !field->getLastText().isEmpty();
!field->getLastText().isEmpty(), updateControlsVisibility(anim::type::instant);
anim::type::instant);
std::move(shown) std::move(shown)
| rpl::start_with_next([=](bool visible) { | rpl::start_with_next([=](bool visible) {
if (!field->getLastText().isEmpty()) { auto alreadyInSearch = !field->getLastText().isEmpty();
return; _searchModeAvailable = visible || alreadyInSearch;
} updateControlsVisibility(anim::type::instant);
toggleSearchMode(false, anim::type::instant);
wrap->setVisible(visible);
search->wrapped()->toggle(visible, anim::type::instant);
}, wrap->lifetime()); }, wrap->lifetime());
} }
@ -228,17 +282,6 @@ int TopBar::resizeGetHeight(int newWidth) {
return _st.height; return _st.height;
} }
void TopBar::finishSelectionAnimations() {
ranges::for_each(ranges::view::concat(
_defaultControls,
_selectionControls
), [](auto &&control) {
if (auto pointer = control.data()) {
pointer->finishAnimating();
}
});
}
void TopBar::updateControlsGeometry(int newWidth) { void TopBar::updateControlsGeometry(int newWidth) {
updateDefaultControlsGeometry(newWidth); updateDefaultControlsGeometry(newWidth);
updateSelectionControlsGeometry(newWidth); updateSelectionControlsGeometry(newWidth);
@ -286,7 +329,7 @@ void TopBar::updateSelectionControlsGeometry(int newWidth) {
const auto top = 0; const auto top = 0;
const auto availableWidth = newWidth - left - right; const auto availableWidth = newWidth - left - right;
_selectionText->resizeToWidth(availableWidth); _selectionText->resizeToNaturalWidth(availableWidth);
_selectionText->moveToLeft( _selectionText->moveToLeft(
left, left,
top, top,
@ -319,16 +362,31 @@ void TopBar::startHighlightAnimation() {
_st.highlightDuration); _st.highlightDuration);
} }
void TopBar::updateControlsVisibility(anim::type animated) {
for (auto i = _updateControlCallbacks.begin(); i != _updateControlCallbacks.end();) {
auto &&[widget, callback] = *i;
if (!callback(animated)) {
i = _updateControlCallbacks.erase(i);
} else {
++i;
}
}
}
void TopBar::setSelectedItems(SelectedItems &&items) { void TopBar::setSelectedItems(SelectedItems &&items) {
auto wasSelectionMode = selectionMode();
_selectedItems = std::move(items); _selectedItems = std::move(items);
if (selectionMode()) { if (selectionMode()) {
if (_selectionText) { if (_selectionText) {
updateSelectionState(); updateSelectionState();
if (!wasSelectionMode) {
_selectionText->entity()->finishAnimating();
}
} else { } else {
createSelectionControls(); createSelectionControls();
} }
} }
toggleSelectionControls(); updateControlsVisibility(anim::type::normal);
} }
SelectedItems TopBar::takeSelectedItems() { SelectedItems TopBar::takeSelectedItems() {
@ -352,33 +410,43 @@ void TopBar::updateSelectionState() {
void TopBar::createSelectionControls() { void TopBar::createSelectionControls() {
auto wrap = [&](auto created) { auto wrap = [&](auto created) {
_selectionControls.push_back(created); registerToggleControlCallback(
created,
[this] { return selectionMode(); });
created->toggle(false, anim::type::instant); created->toggle(false, anim::type::instant);
return created; return created;
}; };
_canDelete = computeCanDelete(); _canDelete = computeCanDelete();
_cancelSelection = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( _cancelSelection = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>(
this, this,
object_ptr<Ui::IconButton>(this, _st.mediaCancel))); object_ptr<Ui::IconButton>(this, _st.mediaCancel),
st::infoTopBarScale));
_cancelSelection->setDuration(st::infoTopBarDuration);
_cancelSelection->entity()->clicks() _cancelSelection->entity()->clicks()
| rpl::start_to_stream( | rpl::start_to_stream(
_cancelSelectionClicks, _cancelSelectionClicks,
_cancelSelection->lifetime()); _cancelSelection->lifetime());
_selectionText = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::LabelWithNumbers>>( _selectionText = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::LabelWithNumbers>>(
this, this,
object_ptr<Ui::LabelWithNumbers>( object_ptr<Ui::LabelWithNumbers>(
this, this,
_st.title, _st.title,
_st.titlePosition.y(), _st.titlePosition.y(),
generateSelectedText()))); generateSelectedText()),
st::infoTopBarScale));
_selectionText->setDuration(st::infoTopBarDuration);
_selectionText->entity()->resize(0, _st.height); _selectionText->entity()->resize(0, _st.height);
_forward = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( _forward = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>(
this, this,
object_ptr<Ui::IconButton>(this, _st.mediaForward))); object_ptr<Ui::IconButton>(this, _st.mediaForward),
st::infoTopBarScale));
_forward->setDuration(st::infoTopBarDuration);
_forward->entity()->addClickHandler([this] { performForward(); }); _forward->entity()->addClickHandler([this] { performForward(); });
_delete = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( _delete = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>(
this, this,
object_ptr<Ui::IconButton>(this, _st.mediaDelete))); object_ptr<Ui::IconButton>(this, _st.mediaDelete),
st::infoTopBarScale));
_delete->setDuration(st::infoTopBarDuration);
_delete->entity()->addClickHandler([this] { performDelete(); }); _delete->entity()->addClickHandler([this] { performDelete(); });
_delete->entity()->setVisible(_canDelete); _delete->entity()->setVisible(_canDelete);
@ -392,23 +460,6 @@ bool TopBar::computeCanDelete() const {
) == _selectedItems.list.end(); ) == _selectedItems.list.end();
} }
void TopBar::toggleSelectionControls() {
auto toggle = [](bool shown) {
return [=](auto &&control) {
if (auto pointer = control.data()) {
pointer->toggle(shown, anim::type::normal);
}
};
};
auto shown = selectionMode();
ranges::for_each(_defaultControls, toggle(!shown));
ranges::for_each(_selectionControls, toggle(shown));
if (!shown) {
clearSelectionControls();
}
}
Ui::StringWithNumbers TopBar::generateSelectedText() const { Ui::StringWithNumbers TopBar::generateSelectedText() const {
using Data = Ui::StringWithNumbers; using Data = Ui::StringWithNumbers;
using Type = Storage::SharedMediaType; using Type = Storage::SharedMediaType;
@ -422,7 +473,7 @@ Ui::StringWithNumbers TopBar::generateSelectedText() const {
case Type::VoiceFile: return lng_media_selected_audio__generic<Data>; case Type::VoiceFile: return lng_media_selected_audio__generic<Data>;
// case Type::RoundFile: return lng_media_selected_round__generic<Data>; // case Type::RoundFile: return lng_media_selected_round__generic<Data>;
} }
Unexpected("Type in TopBarOverride::generateText()"); Unexpected("Type in TopBar::generateSelectedText()");
}(); }();
return phrase(lt_count, _selectedItems.list.size()); return phrase(lt_count, _selectedItems.list.size());
} }
@ -431,27 +482,8 @@ bool TopBar::selectionMode() const {
return !_selectedItems.list.empty(); return !_selectedItems.list.empty();
} }
void TopBar::clearSelectionControls() { bool TopBar::searchMode() const {
for (auto &&control : _selectionControls) { return _searchModeAvailable && _searchModeEnabled;
if (auto pointer = control.data()) {
pointer->shownValue()
| rpl::filter([](bool shown) { return !shown; })
| rpl::start_with_next([control] {
if (auto pointer = control.data()) {
InvokeQueued(pointer, [pointer] { delete pointer; });
}
}, pointer->lifetime());
}
}
auto isStale = [](auto &&control) { return !control; };
_defaultControls |= ranges::action::remove_if(isStale);
_selectionControls |= ranges::action::remove_if(isStale);
_cancelSelection = nullptr;
_selectionText = nullptr;
_forward = nullptr;
_delete = nullptr;
} }
SelectedItemSet TopBar::collectItems() const { SelectedItemSet TopBar::collectItems() const {

View File

@ -75,7 +75,6 @@ public:
SelectedItems takeSelectedItems(); SelectedItems takeSelectedItems();
rpl::producer<> cancelSelectionRequests() const; rpl::producer<> cancelSelectionRequests() const;
void finishSelectionAnimations();
protected: protected:
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
@ -85,17 +84,18 @@ private:
void updateControlsGeometry(int newWidth); void updateControlsGeometry(int newWidth);
void updateDefaultControlsGeometry(int newWidth); void updateDefaultControlsGeometry(int newWidth);
void updateSelectionControlsGeometry(int newWidth); void updateSelectionControlsGeometry(int newWidth);
void pushButton(base::unique_qptr<Ui::RpWidget> button); Ui::FadeWrap<Ui::RpWidget> *pushButton(base::unique_qptr<Ui::RpWidget> button);
void removeButton(not_null<Ui::RpWidget*> button); void removeButton(not_null<Ui::RpWidget*> button);
void startHighlightAnimation(); void startHighlightAnimation();
void updateControlsVisibility(anim::type animated);
bool selectionMode() const; bool selectionMode() const;
bool searchMode() const;
Ui::StringWithNumbers generateSelectedText() const; Ui::StringWithNumbers generateSelectedText() const;
[[nodiscard]] bool computeCanDelete() const; [[nodiscard]] bool computeCanDelete() const;
[[nodiscard]] SelectedItemSet collectSelectedItems() const; [[nodiscard]] SelectedItemSet collectSelectedItems() const;
void updateSelectionState(); void updateSelectionState();
void createSelectionControls(); void createSelectionControls();
void toggleSelectionControls();
void clearSelectionControls(); void clearSelectionControls();
SelectedItemSet collectItems() const; SelectedItemSet collectItems() const;
@ -109,6 +109,12 @@ private:
not_null<Ui::InputField*> field, not_null<Ui::InputField*> field,
rpl::producer<bool> &&shown); rpl::producer<bool> &&shown);
template <typename Callback>
void registerUpdateControlCallback(QObject *guard, Callback &&callback);
template <typename Widget, typename IsVisible>
void registerToggleControlCallback(Widget *widget, IsVisible &&callback);
const style::InfoTopBar &_st; const style::InfoTopBar &_st;
Animation _a_highlight; Animation _a_highlight;
bool _highlight = false; bool _highlight = false;
@ -116,6 +122,8 @@ private:
std::vector<base::unique_qptr<Ui::RpWidget>> _buttons; std::vector<base::unique_qptr<Ui::RpWidget>> _buttons;
QPointer<Ui::FadeWrap<Ui::FlatLabel>> _title; QPointer<Ui::FadeWrap<Ui::FlatLabel>> _title;
bool _searchModeEnabled = false;
bool _searchModeAvailable = false;
base::unique_qptr<Ui::RpWidget> _searchView; base::unique_qptr<Ui::RpWidget> _searchView;
rpl::event_stream<> _backClicks; rpl::event_stream<> _backClicks;
@ -128,9 +136,8 @@ private:
QPointer<Ui::FadeWrap<Ui::IconButton>> _delete; QPointer<Ui::FadeWrap<Ui::IconButton>> _delete;
rpl::event_stream<> _cancelSelectionClicks; rpl::event_stream<> _cancelSelectionClicks;
using FadingControl = QPointer<Ui::FadeWrap<RpWidget>>; using UpdateCallback = base::lambda<bool(anim::type)>;
std::vector<FadingControl> _defaultControls; std::map<QObject*, UpdateCallback> _updateControlCallbacks;
std::vector<FadingControl> _selectionControls;
}; };

View File

@ -1,174 +0,0 @@
/*
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
*/
#include "info/info_top_bar_override.h"
#include <rpl/merge.h>
#include "styles/style_info.h"
#include "lang/lang_keys.h"
#include "info/info_wrap_widget.h"
#include "storage/storage_shared_media.h"
#include "ui/effects/numbers_animation.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/shadow.h"
#include "ui/wrap/fade_wrap.h"
#include "mainwidget.h"
#include "boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
namespace Info {
TopBarOverride::TopBarOverride(
QWidget *parent,
const style::InfoTopBar &st,
SelectedItems &&items)
: RpWidget(parent)
, _st(st)
, _items(std::move(items))
, _canDelete(computeCanDelete())
, _cancel(this, _st.mediaCancel)
, _text(this, _st.title, _st.titlePosition.y(), generateText())
, _forward(this, _st.mediaForward)
, _delete(this, _st.mediaDelete) {
setAttribute(Qt::WA_OpaquePaintEvent);
updateControlsVisibility();
_forward->addClickHandler([this] { performForward(); });
_delete->addClickHandler([this] { performDelete(); });
}
Ui::StringWithNumbers TopBarOverride::generateText() const {
using Data = Ui::StringWithNumbers;
using Type = Storage::SharedMediaType;
auto phrase = [&] {
switch (_items.type) {
case Type::Photo: return lng_media_selected_photo__generic<Data>;
case Type::Video: return lng_media_selected_video__generic<Data>;
case Type::File: return lng_media_selected_file__generic<Data>;
case Type::MusicFile: return lng_media_selected_song__generic<Data>;
case Type::Link: return lng_media_selected_link__generic<Data>;
case Type::VoiceFile: return lng_media_selected_audio__generic<Data>;
// case Type::RoundFile: return lng_media_selected_round__generic<Data>;
}
Unexpected("Type in TopBarOverride::generateText()");
}();
return phrase(lt_count, _items.list.size());
}
bool TopBarOverride::computeCanDelete() const {
return ranges::find_if(_items.list, [](const SelectedItem &item) {
return !item.canDelete;
}) == _items.list.end();
}
void TopBarOverride::setItems(SelectedItems &&items) {
_items = std::move(items);
_canDelete = computeCanDelete();
_text->setValue(generateText());
updateControlsVisibility();
updateControlsGeometry(width());
}
SelectedItems TopBarOverride::takeItems() {
_canDelete = false;
return std::move(_items);
}
rpl::producer<> TopBarOverride::cancelRequests() const {
return rpl::merge(
_cancel->clicks(),
_correctionCancelRequests.events());
}
int TopBarOverride::resizeGetHeight(int newWidth) {
updateControlsGeometry(newWidth);
return _st.height;
}
void TopBarOverride::updateControlsGeometry(int newWidth) {
auto right = _st.mediaActionsSkip;
if (_canDelete) {
_delete->moveToRight(right, 0, newWidth);
right += _delete->width();
}
_forward->moveToRight(right, 0, newWidth);
right += _forward->width();
auto left = 0;
_cancel->moveToLeft(left, 0);
left += _cancel->width();
const auto availableWidth = newWidth - left - right;
_text->setGeometryToLeft(left, 0, availableWidth, _st.height, newWidth);
}
void TopBarOverride::updateControlsVisibility() {
_delete->setVisible(_canDelete);
}
void TopBarOverride::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), _st.bg);
}
SelectedItemSet TopBarOverride::collectItems() const {
auto result = SelectedItemSet();
for (auto value : _items.list) {
if (auto item = App::histItemById(value.msgId)) {
result.insert(result.size(), item);
}
}
return result;
}
void TopBarOverride::performForward() {
auto items = collectItems();
if (items.empty()) {
_correctionCancelRequests.fire({});
return;
}
auto callback = [items = std::move(items), that = weak(this)](
not_null<PeerData*> peer) {
App::main()->setForwardDraft(peer->id, items);
if (that) {
that->_correctionCancelRequests.fire({});
}
};
Ui::show(Box<PeerListBox>(
std::make_unique<ChooseRecipientBoxController>(std::move(callback)),
[](not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_cancel), [box] {
box->closeBox();
});
}));
}
void TopBarOverride::performDelete() {
auto items = collectItems();
if (items.empty()) {
_correctionCancelRequests.fire({});
} else {
Ui::show(Box<DeleteMessagesBox>(items));
}
}
} // namespace Info

View File

@ -1,77 +0,0 @@
/*
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
#include "ui/rp_widget.h"
#include "info/info_wrap_widget.h"
#include "boxes/peer_list_controllers.h"
namespace style {
struct InfoTopBar;
} // namespace style
namespace Ui {
class IconButton;
class LabelWithNumbers;
struct StringWithNumbers;
} // namespace Ui
namespace Info {
class TopBarOverride : public Ui::RpWidget {
public:
TopBarOverride(
QWidget *parent,
const style::InfoTopBar &st,
SelectedItems &&items);
void setItems(SelectedItems &&items);
SelectedItems takeItems();
rpl::producer<> cancelRequests() const;
protected:
int resizeGetHeight(int newWidth) override;
void paintEvent(QPaintEvent *e) override;
private:
void updateControlsVisibility();
void updateControlsGeometry(int newWidth);
Ui::StringWithNumbers generateText() const;
[[nodiscard]] bool computeCanDelete() const;
[[nodiscard]] SelectedItemSet collectItems() const;
void performForward();
void performDelete();
const style::InfoTopBar &_st;
SelectedItems _items;
bool _canDelete = false;
object_ptr<Ui::IconButton> _cancel;
object_ptr<Ui::LabelWithNumbers> _text;
object_ptr<Ui::IconButton> _forward;
object_ptr<Ui::IconButton> _delete;
rpl::event_stream<> _correctionCancelRequests;
};
} // namespace Info

View File

@ -36,7 +36,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_info.h" #include "styles/style_info.h"
#include "boxes/peer_list_controllers.h" #include "boxes/peer_list_controllers.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "info/info_top_bar_override.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
namespace Layout = Overview::Layout; namespace Layout = Overview::Layout;

View File

@ -38,7 +38,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_top_bar_override.h"
#include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "info/profile/info_profile_button.h" #include "info/profile/info_profile_button.h"

View File

@ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <rpl/flatten_latest.h> #include <rpl/flatten_latest.h>
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "info/info_top_bar_override.h"
#include "info/profile/info_profile_button.h" #include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_widget.h"
#include "info/profile/info_profile_text.h" #include "info/profile/info_profile_text.h"

View File

@ -187,7 +187,7 @@ void Members::setupButtons() {
}); });
//_searchField->hide(); //_searchField->hide();
//_cancelSearch->hideFast(); //_cancelSearch->setVisible(false);
auto addMemberShown = CanAddMemberValue(_peer) auto addMemberShown = CanAddMemberValue(_peer)
| rpl::start_spawning(lifetime()); | rpl::start_spawning(lifetime());
@ -344,15 +344,14 @@ void Members::addMember() {
// //
//void Members::toggleSearch(anim::type animated) { //void Members::toggleSearch(anim::type animated) {
// _searchShown = !_searchShown; // _searchShown = !_searchShown;
// _cancelSearch->toggle(_searchShown, animated);
// if (animated == anim::type::normal) { // if (animated == anim::type::normal) {
// _cancelSearch->toggleAnimated(_searchShown);
// _searchShownAnimation.start( // _searchShownAnimation.start(
// [this] { searchAnimationCallback(); }, // [this] { searchAnimationCallback(); },
// _searchShown ? 0. : 1., // _searchShown ? 0. : 1.,
// _searchShown ? 1. : 0., // _searchShown ? 1. : 0.,
// st::slideWrapDuration); // st::slideWrapDuration);
// } else { // } else {
// _cancelSearch->toggleFast(_searchShown);
// _searchShownAnimation.finish(); // _searchShownAnimation.finish();
// searchAnimationCallback(); // searchAnimationCallback();
// } // }

View File

@ -27,9 +27,9 @@ constexpr int kWideScale = 5;
} // namespace } // namespace
FadeAnimation::FadeAnimation(TWidget *widget, bool scaled) FadeAnimation::FadeAnimation(TWidget *widget, float64 scale)
: _widget(widget) : _widget(widget)
, _scaled(scaled) { , _scale(scale) {
} }
bool FadeAnimation::paint(Painter &p) { bool FadeAnimation::paint(Painter &p) {
@ -37,13 +37,28 @@ bool FadeAnimation::paint(Painter &p) {
auto opacity = _animation.current(getms(), _visible ? 1. : 0.); auto opacity = _animation.current(getms(), _visible ? 1. : 0.);
p.setOpacity(opacity); p.setOpacity(opacity);
if (_scaled) { if (_scale < 1.) {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
auto targetRect = QRect((1 - kWideScale) / 2 * _size.width(), (1 - kWideScale) / 2 * _size.height(), kWideScale * _size.width(), kWideScale * _size.height()); auto targetRect = QRect(
auto scale = opacity; (1 - kWideScale) / 2 * _size.width(),
auto shownWidth = anim::interpolate((1 - kWideScale) / 2 * _size.width(), 0, scale); (1 - kWideScale) / 2 * _size.height(),
auto shownHeight = anim::interpolate((1 - kWideScale) / 2 * _size.height(), 0, scale); kWideScale * _size.width(),
p.drawPixmap(targetRect.marginsAdded(QMargins(shownWidth, shownHeight, shownWidth, shownHeight)), _cache); kWideScale * _size.height());
auto scale = opacity + (1. - opacity) * _scale;
auto shownWidth = anim::interpolate(
(1 - kWideScale) / 2 * _size.width(),
0,
scale);
auto shownHeight = anim::interpolate(
(1 - kWideScale) / 2 * _size.height(),
0,
scale);
auto margins = QMargins(
shownWidth,
shownHeight,
shownWidth,
shownHeight);
p.drawPixmap(targetRect.marginsAdded(margins), _cache);
} else { } else {
p.drawPixmap(0, 0, _cache); p.drawPixmap(0, 0, _cache);
} }
@ -70,18 +85,17 @@ QPixmap FadeAnimation::grabContent() {
return App::pixmapFromImageInPlace(std::move(image)); return App::pixmapFromImageInPlace(std::move(image));
} }
auto widgetContent = myGrab(_widget); auto widgetContent = myGrab(_widget);
if (!_scaled) { if (_scale < 1.) {
return widgetContent; auto result = QImage(kWideScale * _size * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(cRetinaFactor());
result.fill(Qt::transparent);
{
Painter p(&result);
p.drawPixmap((kWideScale - 1) / 2 * _size.width(), (kWideScale - 1) / 2 * _size.height(), widgetContent);
}
return App::pixmapFromImageInPlace(std::move(result));
} }
return widgetContent;
auto result = QImage(kWideScale * _size * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(cRetinaFactor());
result.fill(Qt::transparent);
{
Painter p(&result);
p.drawPixmap((kWideScale - 1) / 2 * _size.width(), (kWideScale - 1) / 2 * _size.height(), widgetContent);
}
return App::pixmapFromImageInPlace(std::move(result));
} }
void FadeAnimation::setFinishedCallback(FinishedCallback &&callback) { void FadeAnimation::setFinishedCallback(FinishedCallback &&callback) {

View File

@ -27,7 +27,7 @@ namespace Ui {
class FadeAnimation { class FadeAnimation {
public: public:
FadeAnimation(TWidget *widget, bool scaled = false); FadeAnimation(TWidget *widget, float64 scale = 1.);
bool paint(Painter &p); bool paint(Painter &p);
void refreshCache(); void refreshCache();
@ -63,7 +63,7 @@ private:
QPixmap grabContent(); QPixmap grabContent();
TWidget *_widget = nullptr; TWidget *_widget = nullptr;
bool _scaled = false; float64 _scale = 1.;
Animation _animation; Animation _animation;
QSize _size; QSize _size;

View File

@ -105,6 +105,10 @@ int NumbersAnimation::countWidth() const {
anim::easeOutCirc(1., _a_ready.current(1.))); anim::easeOutCirc(1., _a_ready.current(1.)));
} }
int NumbersAnimation::maxWidth() const {
return std::max(_fromWidth, _toWidth);
}
void NumbersAnimation::stepAnimation(TimeMs ms) { void NumbersAnimation::stepAnimation(TimeMs ms) {
_a_ready.step(ms); _a_ready.step(ms);
} }
@ -212,6 +216,12 @@ void LabelWithNumbers::setValue(const StringWithNumbers &value) {
_afterWidth = _st.style.font->width(_after); _afterWidth = _st.style.font->width(_after);
} }
void LabelWithNumbers::finishAnimating() {
_beforeWidthAnimation.finish();
_numbers.finishAnimating();
update();
}
void LabelWithNumbers::paintEvent(QPaintEvent *e) { void LabelWithNumbers::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);

View File

@ -43,6 +43,7 @@ public:
void paint(Painter &p, int x, int y, int outerWidth); void paint(Painter &p, int x, int y, int outerWidth);
int countWidth() const; int countWidth() const;
int maxWidth() const;
private: private:
struct Digit { struct Digit {
@ -90,6 +91,11 @@ public:
const StringWithNumbers &value); const StringWithNumbers &value);
void setValue(const StringWithNumbers &value); void setValue(const StringWithNumbers &value);
void finishAnimating();
int naturalWidth() const override {
return _beforeWidth + _numbers.maxWidth() + _afterWidth;
}
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;

View File

@ -58,9 +58,9 @@ base::unique_qptr<Ui::RpWidget> SearchFieldController::createRowView(
return !value.isEmpty(); return !value.isEmpty();
}) })
| rpl::start_with_next([cancel](bool shown) { | rpl::start_with_next([cancel](bool shown) {
cancel->toggleAnimated(shown); cancel->toggle(shown, anim::type::normal);
}, cancel->lifetime()); }, cancel->lifetime());
cancel->finishAnimations(); cancel->finishAnimating();
auto shadow = CreateChild<Ui::PlainShadow>(wrap); auto shadow = CreateChild<Ui::PlainShadow>(wrap);
shadow->show(); shadow->show();

View File

@ -472,57 +472,70 @@ private:
template <typename Object> template <typename Object>
class object_ptr { class object_ptr {
public: public:
object_ptr(std::nullptr_t) { object_ptr(std::nullptr_t) noexcept {
} }
// No default constructor, but constructors with at least // No default constructor, but constructors with at least
// one argument are simply make functions. // one argument are simply make functions.
template <typename Parent, typename... Args> template <typename Parent, typename... Args>
explicit object_ptr(Parent &&parent, Args&&... args) : _object(new Object(std::forward<Parent>(parent), std::forward<Args>(args)...)) { explicit object_ptr(Parent &&parent, Args&&... args)
: _object(new Object(std::forward<Parent>(parent), std::forward<Args>(args)...)) {
}
static object_ptr<Object> fromRaw(Object *value) noexcept {
object_ptr<Object> result = { nullptr };
result._object = value;
return result;
} }
object_ptr(const object_ptr &other) = delete; object_ptr(const object_ptr &other) = delete;
object_ptr &operator=(const object_ptr &other) = delete; object_ptr &operator=(const object_ptr &other) = delete;
object_ptr(object_ptr &&other) : _object(base::take(other._object)) { object_ptr(object_ptr &&other) noexcept : _object(base::take(other._object)) {
} }
object_ptr &operator=(object_ptr &&other) { object_ptr &operator=(object_ptr &&other) noexcept {
auto temp = std::move(other); auto temp = std::move(other);
destroy(); destroy();
std::swap(_object, temp._object); std::swap(_object, temp._object);
return *this; return *this;
} }
template <typename OtherObject, typename = std::enable_if_t<std::is_base_of<Object, OtherObject>::value>> template <
object_ptr(object_ptr<OtherObject> &&other) : _object(base::take(other._object)) { typename OtherObject,
typename = std::enable_if_t<
std::is_base_of_v<Object, OtherObject>>>
object_ptr(object_ptr<OtherObject> &&other) noexcept
: _object(base::take(other._object)) {
} }
template <typename OtherObject, typename = std::enable_if_t<std::is_base_of<Object, OtherObject>::value>> template <
object_ptr &operator=(object_ptr<OtherObject> &&other) { typename OtherObject,
typename = std::enable_if_t<
std::is_base_of_v<Object, OtherObject>>>
object_ptr &operator=(object_ptr<OtherObject> &&other) noexcept {
_object = base::take(other._object); _object = base::take(other._object);
return *this; return *this;
} }
object_ptr &operator=(std::nullptr_t) { object_ptr &operator=(std::nullptr_t) noexcept {
_object = nullptr; _object = nullptr;
return *this; return *this;
} }
// So we can pass this pointer to methods like connect(). // So we can pass this pointer to methods like connect().
Object *data() const { Object *data() const noexcept {
return static_cast<Object*>(_object.data()); return static_cast<Object*>(_object.data());
} }
operator Object*() const { operator Object*() const noexcept {
return data(); return data();
} }
explicit operator bool() const { explicit operator bool() const noexcept {
return _object != nullptr; return _object != nullptr;
} }
Object *operator->() const { Object *operator->() const noexcept {
return data(); return data();
} }
Object &operator*() const { Object &operator*() const noexcept {
return *data(); return *data();
} }
@ -530,10 +543,12 @@ public:
template <typename Parent, typename... Args> template <typename Parent, typename... Args>
Object *create(Parent &&parent, Args&&... args) { Object *create(Parent &&parent, Args&&... args) {
destroy(); destroy();
_object = new Object(std::forward<Parent>(parent), std::forward<Args>(args)...); _object = new Object(
std::forward<Parent>(parent),
std::forward<Args>(args)...);
return data(); return data();
} }
void destroy() { void destroy() noexcept {
delete base::take(_object); delete base::take(_object);
} }
void destroyDelayed() { void destroyDelayed() {
@ -545,7 +560,7 @@ public:
} }
} }
~object_ptr() { ~object_ptr() noexcept {
if (auto pointer = _object) { if (auto pointer = _object) {
if (!pointer->parent()) { if (!pointer->parent()) {
destroy(); destroy();
@ -554,7 +569,8 @@ public:
} }
template <typename ResultType, typename SourceType> template <typename ResultType, typename SourceType>
friend object_ptr<ResultType> static_object_cast(object_ptr<SourceType> source); friend object_ptr<ResultType> static_object_cast(
object_ptr<SourceType> source);
private: private:
template <typename OtherObject> template <typename OtherObject>
@ -565,14 +581,23 @@ private:
}; };
template <typename ResultType, typename SourceType> template <typename ResultType, typename SourceType>
inline object_ptr<ResultType> static_object_cast(object_ptr<SourceType> source) { inline object_ptr<ResultType> static_object_cast(
object_ptr<SourceType> source) {
auto result = object_ptr<ResultType>(nullptr); auto result = object_ptr<ResultType>(nullptr);
result._object = static_cast<ResultType*>(base::take(source._object).data()); result._object = static_cast<ResultType*>(
base::take(source._object).data());
return std::move(result); return std::move(result);
} }
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint); void sendSynteticMouseEvent(
QWidget *widget,
QEvent::Type type,
Qt::MouseButton button,
const QPoint &globalPoint);
inline void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button) { inline void sendSynteticMouseEvent(
QWidget *widget,
QEvent::Type type,
Qt::MouseButton button) {
return sendSynteticMouseEvent(widget, type, button, QCursor::pos()); return sendSynteticMouseEvent(widget, type, button, QCursor::pos());
} }

View File

@ -478,7 +478,7 @@ CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : Ripple
, _a_loading(animation(this, &CrossButton::step_loading)) { , _a_loading(animation(this, &CrossButton::step_loading)) {
resize(_st.width, _st.height); resize(_st.width, _st.height);
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
hide(); setVisible(false);
} }
void CrossButton::step_loading(TimeMs ms, bool timer) { void CrossButton::step_loading(TimeMs ms, bool timer) {
@ -490,21 +490,29 @@ void CrossButton::step_loading(TimeMs ms, bool timer) {
} }
} }
void CrossButton::toggleAnimated(bool visible) { void CrossButton::toggle(bool visible, anim::type animated) {
if (_shown == visible) { if (_shown != visible) {
return; _shown = visible;
if (animated == anim::type::normal) {
if (isHidden()) {
setVisible(true);
}
_a_show.start(
[this] { animationCallback(); },
_shown ? 0. : 1.,
_shown ? 1. : 0.,
_st.duration);
}
} }
_shown = visible; if (animated == anim::type::instant) {
if (isHidden()) { finishAnimating();
show();
} }
_a_show.start([this] { animationCallback(); }, _shown ? 0. : 1., _shown ? 1. : 0., _st.duration);
} }
void CrossButton::animationCallback() { void CrossButton::animationCallback() {
update(); update();
if (!_shown && !_a_show.animating()) { if (!_a_show.animating()) {
hide(); setVisible(_shown);
} }
} }

View File

@ -212,28 +212,19 @@ class CrossButton : public RippleButton {
public: public:
CrossButton(QWidget *parent, const style::CrossButton &st); CrossButton(QWidget *parent, const style::CrossButton &st);
void showAnimated() { void toggle(bool shown, anim::type animated);
toggleAnimated(true); void show(anim::type animated) {
return toggle(true, animated);
} }
void hideAnimated() { void hide(anim::type animated) {
toggleAnimated(false); return toggle(false, animated);
} }
void toggleAnimated(bool visible); void finishAnimating() {
void showFast() {
toggleFast(true);
}
void hideFast() {
toggleFast(false);
}
void toggleFast(bool visible) {
toggleAnimated(visible);
finishAnimations();
}
void finishAnimations() {
_a_show.finish(); _a_show.finish();
animationCallback();
} }
bool isShown() const { bool toggled() const {
return _shown; return _shown;
} }
void setLoadingAnimation(bool enabled); void setLoadingAnimation(bool enabled);

View File

@ -383,11 +383,7 @@ MultiSelect::Inner::Inner(QWidget *parent, const style::MultiSelect &st, base::l
void MultiSelect::Inner::onQueryChanged() { void MultiSelect::Inner::onQueryChanged() {
auto query = getQuery(); auto query = getQuery();
if (query.isEmpty()) { _cancel->toggle(!query.isEmpty(), anim::type::normal);
_cancel->hideAnimated();
} else {
_cancel->showAnimated();
}
updateFieldGeometry(); updateFieldGeometry();
if (_queryChangedCallback) { if (_queryChangedCallback) {
_queryChangedCallback(query); _queryChangedCallback(query);
@ -422,7 +418,7 @@ void MultiSelect::Inner::setSubmittedCallback(base::lambda<void(bool ctrlShiftEn
void MultiSelect::Inner::updateFieldGeometry() { void MultiSelect::Inner::updateFieldGeometry() {
auto fieldFinalWidth = _fieldWidth; auto fieldFinalWidth = _fieldWidth;
if (_cancel->isShown()) { if (_cancel->toggled()) {
fieldFinalWidth -= _st.fieldCancelSkip; fieldFinalWidth -= _st.fieldCancelSkip;
} }
_field->resizeToWidth(fieldFinalWidth); _field->resizeToWidth(fieldFinalWidth);

View File

@ -27,9 +27,9 @@ namespace Ui {
FadeWrap<RpWidget>::FadeWrap( FadeWrap<RpWidget>::FadeWrap(
QWidget *parent, QWidget *parent,
object_ptr<RpWidget> &&child, object_ptr<RpWidget> &&child,
bool scaled) float64 scale)
: Parent(parent, std::move(child)) : Parent(parent, std::move(child))
, _animation(this, scaled) , _animation(this, scale)
, _duration(st::fadeWrapDuration) { , _duration(st::fadeWrapDuration) {
if (auto weak = wrapped()) { if (auto weak = wrapped()) {
weak->show(); weak->show();

View File

@ -36,13 +36,10 @@ class FadeWrap<RpWidget> : public Wrap<RpWidget> {
using Parent = Wrap<RpWidget>; using Parent = Wrap<RpWidget>;
public: public:
FadeWrap(QWidget *parent, object_ptr<RpWidget> &&child)
: FadeWrap(parent, std::move(child), false) {
}
FadeWrap( FadeWrap(
QWidget *parent, QWidget *parent,
object_ptr<RpWidget> &&child, object_ptr<RpWidget> &&child,
bool scaled); float64 scale = 1.);
FadeWrap *setDuration(int duration); FadeWrap *setDuration(int duration);
FadeWrap *toggle(bool shown, anim::type animated); FadeWrap *toggle(bool shown, anim::type animated);
@ -81,14 +78,11 @@ class FadeWrap : public Wrap<Widget, FadeWrap<RpWidget>> {
using Parent = Wrap<Widget, FadeWrap<RpWidget>>; using Parent = Wrap<Widget, FadeWrap<RpWidget>>;
public: public:
FadeWrap(QWidget *parent, object_ptr<Widget> &&child)
: Parent(parent, std::move(child)) {
}
FadeWrap( FadeWrap(
QWidget *parent, QWidget *parent,
object_ptr<Widget> &&child, object_ptr<Widget> &&child,
bool scaled) float64 scale = 1.)
: Parent(parent, std::move(child), scaled) { : Parent(parent, std::move(child), scale) {
} }
FadeWrap *setDuration(int duration) { FadeWrap *setDuration(int duration) {
@ -123,7 +117,7 @@ class FadeWrapScaled : public FadeWrap<Widget> {
public: public:
FadeWrapScaled(QWidget *parent, object_ptr<Widget> &&child) FadeWrapScaled(QWidget *parent, object_ptr<Widget> &&child)
: Parent(parent, std::move(child), true) { : Parent(parent, std::move(child), 0.) {
} }
}; };

View File

@ -727,7 +727,7 @@ Editor::Editor(QWidget*, const QString &path)
_scroll->scrollToY(top, bottom); _scroll->scrollToY(top, bottom);
}); });
_close->setClickedCallback([this] { closeEditor(); }); _close->setClickedCallback([this] { closeEditor(); });
_close->showFast(); _close->show(anim::type::instant);
_select->resizeToWidth(st::windowMinWidth); _select->resizeToWidth(st::windowMinWidth);
_select->setQueryChangedCallback([this](const QString &query) { _inner->filterRows(query); _scroll->scrollToY(0); }); _select->setQueryChangedCallback([this](const QString &query) { _inner->filterRows(query); _scroll->scrollToY(0); });

View File

@ -234,8 +234,6 @@
<(src_loc)/info/info_section_widget.h <(src_loc)/info/info_section_widget.h
<(src_loc)/info/info_top_bar.cpp <(src_loc)/info/info_top_bar.cpp
<(src_loc)/info/info_top_bar.h <(src_loc)/info/info_top_bar.h
<(src_loc)/info/info_top_bar_override.cpp
<(src_loc)/info/info_top_bar_override.h
<(src_loc)/info/info_wrap_widget.cpp <(src_loc)/info/info_wrap_widget.cpp
<(src_loc)/info/info_wrap_widget.h <(src_loc)/info/info_wrap_widget.h
<(src_loc)/info/common_groups/info_common_groups_inner_widget.cpp <(src_loc)/info/common_groups/info_common_groups_inner_widget.cpp