mirror of https://github.com/procxx/kepka.git
				
				
				
			Move Info::TopBarOverride to Info::TopBar.
This allows to improve animations in shared media items selection.
This commit is contained in:
		
							parent
							
								
									6afe18503d
								
							
						
					
					
						commit
						d014b47958
					
				|  | @ -26,18 +26,18 @@ template <typename T> | |||
| class unique_qptr { | ||||
| public: | ||||
| 	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) { | ||||
| 	} | ||||
| 
 | ||||
| 	unique_qptr(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)) { | ||||
| 	} | ||||
| 	unique_qptr &operator=(unique_qptr &&other) { | ||||
| 	unique_qptr &operator=(unique_qptr &&other) noexcept { | ||||
| 		if (_object != other._object) { | ||||
| 			destroy(); | ||||
| 			_object = base::take(other._object); | ||||
|  | @ -48,14 +48,14 @@ public: | |||
| 	template < | ||||
| 		typename 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)) { | ||||
| 	} | ||||
| 
 | ||||
| 	template < | ||||
| 		typename 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) { | ||||
| 			destroy(); | ||||
| 			_object = base::take(other._object); | ||||
|  | @ -63,49 +63,60 @@ public: | |||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	unique_qptr &operator=(std::nullptr_t) { | ||||
| 	unique_qptr &operator=(std::nullptr_t) noexcept { | ||||
| 		destroy(); | ||||
| 		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) { | ||||
| 			destroy(); | ||||
| 			_object = value; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	T *get() const { | ||||
| 	T *get() const noexcept { | ||||
| 		return static_cast<T*>(_object.data()); | ||||
| 	} | ||||
| 	operator T*() const { | ||||
| 	operator T*() const noexcept { | ||||
| 		return get(); | ||||
| 	} | ||||
| 
 | ||||
| 	T *release() { | ||||
| 	T *release() noexcept { | ||||
| 		return static_cast<T*>(base::take(_object).data()); | ||||
| 	} | ||||
| 
 | ||||
| 	explicit operator bool() const { | ||||
| 	explicit operator bool() const noexcept { | ||||
| 		return _object != nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	T *operator->() const { | ||||
| 	T *operator->() const noexcept { | ||||
| 		return get(); | ||||
| 	} | ||||
| 	T &operator*() const { | ||||
| 	T &operator*() const noexcept { | ||||
| 		return *get(); | ||||
| 	} | ||||
| 
 | ||||
| 	void destroy() { | ||||
| 		delete base::take(_object).data(); | ||||
| 	} | ||||
| 
 | ||||
| 	~unique_qptr() { | ||||
| 	~unique_qptr() noexcept { | ||||
| 		destroy(); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void destroy() noexcept { | ||||
| 		delete base::take(_object).data(); | ||||
| 	} | ||||
| 
 | ||||
| 	template <typename U> | ||||
| 	friend class unique_qptr; | ||||
| 
 | ||||
|  | @ -115,7 +126,7 @@ private: | |||
| 
 | ||||
| template <typename T, typename ...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
 | ||||
|  |  | |||
|  | @ -1350,7 +1350,7 @@ void StickersBox::Inner::rebuildMegagroupSet() { | |||
| 
 | ||||
| 	if (!_megagroupSelectedRemove) { | ||||
| 		_megagroupSelectedRemove.create(this, st::groupStickersRemove); | ||||
| 		_megagroupSelectedRemove->showFast(); | ||||
| 		_megagroupSelectedRemove->show(anim::type::instant); | ||||
| 		_megagroupSelectedRemove->setClickedCallback([this] { | ||||
| 			setMegagroupSelectedSet(MTP_inputStickerSetEmpty()); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -85,7 +85,9 @@ GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(p | |||
| 		} | ||||
| 	}); | ||||
| 	connect(_field, &Ui::InputField::changed, this, [this] { | ||||
| 		_cancel->toggleAnimated(!_field->getLastText().isEmpty()); | ||||
| 		_cancel->toggle( | ||||
| 			!_field->getLastText().isEmpty(), | ||||
| 			anim::type::normal); | ||||
| 		_pan->searchForGifs(_field->getLastText()); | ||||
| 	}); | ||||
| 	_cancel->setClickedCallback([this] { | ||||
|  |  | |||
|  | @ -267,7 +267,7 @@ void DialogsWidget::showAnimated(Window::SlideDirection direction, const Window: | |||
| 	_mainMenuToggle->hide(); | ||||
| 	if (_forwardCancel) _forwardCancel->hide(); | ||||
| 	_filter->hide(); | ||||
| 	_cancelSearch->hide(); | ||||
| 	_cancelSearch->hide(anim::type::instant); | ||||
| 	_jumpToDate->hide(anim::type::instant); | ||||
| 	_chooseFromUser->hide(anim::type::instant); | ||||
| 	_lockUnlock->hide(); | ||||
|  | @ -827,10 +827,8 @@ void DialogsWidget::onFilterUpdate(bool force) { | |||
| 	_inner->onFilterUpdate(filterText, force); | ||||
| 	if (filterText.isEmpty()) { | ||||
| 		clearSearchCache(); | ||||
| 		_cancelSearch->hideAnimated(); | ||||
| 	} else { | ||||
| 		_cancelSearch->showAnimated(); | ||||
| 	} | ||||
| 	_cancelSearch->toggle(!filterText.isEmpty(), anim::type::normal); | ||||
| 	updateJumpToDateVisibility(); | ||||
| 
 | ||||
| 	if (filterText.size() < MinUsernameLength) { | ||||
|  |  | |||
|  | @ -128,7 +128,7 @@ FixedBar::FixedBar( | |||
| 	connect(_field, &Ui::FlatInput::submitted, this, [this] { applySearch(); }); | ||||
| 	_searchTimer.setCallback([this] { applySearch(); }); | ||||
| 
 | ||||
| 	_cancel->hideFast(); | ||||
| 	_cancel->hide(anim::type::instant); | ||||
| } | ||||
| 
 | ||||
| void FixedBar::applyFilter(const FilterValue &value) { | ||||
|  | @ -148,7 +148,7 @@ void FixedBar::showSearch() { | |||
| 
 | ||||
| void FixedBar::toggleSearch() { | ||||
| 	_searchShown = !_searchShown; | ||||
| 	_cancel->toggleAnimated(_searchShown); | ||||
| 	_cancel->toggle(_searchShown, anim::type::normal); | ||||
| 	_searchShownAnimation.start([this] { searchAnimationCallback(); }, _searchShown ? 0. : 1., _searchShown ? 1. : 0., st::historyAdminLogSearchSlideDuration); | ||||
| 	_search->setDisabled(_searchShown); | ||||
| 	if (_searchShown) { | ||||
|  | @ -227,7 +227,7 @@ void FixedBar::setAnimatingMode(bool enabled) { | |||
| 			setAttribute(Qt::WA_OpaquePaintEvent); | ||||
| 			showChildren(); | ||||
| 			_field->hide(); | ||||
| 			_cancel->hide(); | ||||
| 			_cancel->setVisible(false); | ||||
| 		} | ||||
| 		show(); | ||||
| 	} | ||||
|  |  | |||
|  | @ -190,6 +190,8 @@ infoTopBar: InfoTopBar { | |||
| 	highlightBg: windowBgOver; | ||||
| 	highlightDuration: 240; | ||||
| } | ||||
| infoTopBarScale: 0.7; | ||||
| infoTopBarDuration: 150; | ||||
| 
 | ||||
| infoLayerTopMinimal: 20px; | ||||
| infoLayerTopMaximal: 40px; | ||||
|  |  | |||
|  | @ -50,18 +50,50 @@ TopBar::TopBar( | |||
| , _selectedItems(Section::MediaType::kCount) { | ||||
| 	setAttribute(Qt::WA_OpaquePaintEvent); | ||||
| 	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) { | ||||
| 	if (_title) { | ||||
| 		delete _title; | ||||
| 	} | ||||
| 	_title = Ui::CreateChild<Ui::FadeWrapScaled<Ui::FlatLabel>>( | ||||
| 	_title = Ui::CreateChild<Ui::FadeWrap<Ui::FlatLabel>>( | ||||
| 		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); | ||||
| 	_defaultControls.push_back(_title.data()); | ||||
| 	registerToggleControlCallback(_title.data(), [=] { | ||||
| 		return !selectionMode() && !searchMode(); | ||||
| 	}); | ||||
| 
 | ||||
| 	if (_back) { | ||||
| 		_title->setAttribute(Qt::WA_TransparentForMouseEvents); | ||||
|  | @ -73,13 +105,17 @@ void TopBar::enableBackButton() { | |||
| 	if (_back) { | ||||
| 		return; | ||||
| 	} | ||||
| 	_back = Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 	_back = Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>( | ||||
| 		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->entity()->clicks() | ||||
| 		| rpl::start_to_stream(_backClicks, _back->lifetime()); | ||||
| 	_defaultControls.push_back(_back.data()); | ||||
| 	registerToggleControlCallback(_back.data(), [=] { | ||||
| 		return !selectionMode(); | ||||
| 	}); | ||||
| 
 | ||||
| 	if (_title) { | ||||
| 		_title->setAttribute(Qt::WA_TransparentForMouseEvents); | ||||
|  | @ -95,14 +131,24 @@ void TopBar::createSearchView( | |||
| 		std::move(shown)); | ||||
| } | ||||
| 
 | ||||
| void TopBar::pushButton(base::unique_qptr<Ui::RpWidget> button) { | ||||
| 	auto weak = button.get(); | ||||
| 	_buttons.push_back(std::move(button)); | ||||
| 	weak->setParent(this); | ||||
| Ui::FadeWrap<Ui::RpWidget> *TopBar::pushButton( | ||||
| 		base::unique_qptr<Ui::RpWidget> button) { | ||||
| 	auto wrapped = base::make_unique_q<Ui::FadeWrap<Ui::RpWidget>>( | ||||
| 		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() | ||||
| 		| rpl::start_with_next([this] { | ||||
| 			updateControlsGeometry(width()); | ||||
| 		}, lifetime()); | ||||
| 	return weak; | ||||
| } | ||||
| 
 | ||||
| void TopBar::setSearchField( | ||||
|  | @ -122,59 +168,75 @@ void TopBar::createSearchView( | |||
| 		this, | ||||
| 		_st.searchRow.height); | ||||
| 	auto wrap = _searchView.get(); | ||||
| 	registerUpdateControlCallback(wrap, [=](anim::type) { | ||||
| 		wrap->setVisible(!selectionMode() && _searchModeAvailable); | ||||
| 	}); | ||||
| 
 | ||||
| 	field->setParent(wrap); | ||||
| 
 | ||||
| 	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>>( | ||||
| 	auto fieldWrap = Ui::CreateChild<Ui::FadeWrap<Ui::InputField>>( | ||||
| 		wrap, | ||||
| 		object_ptr<Ui::CrossButton>(wrap, _st.searchRow.fieldCancel)); | ||||
| 	_defaultControls.push_back(cancel); | ||||
| 		object_ptr<Ui::InputField>::fromRaw(field), | ||||
| 		st::infoTopBarScale); | ||||
| 	fieldWrap->setDuration(st::infoTopBarDuration); | ||||
| 
 | ||||
| 	auto toggleSearchMode = [=](bool enabled, anim::type animated) { | ||||
| 		if (!enabled) { | ||||
| 	auto focusLifetime = field->lifetime().make_state<rpl::lifetime>(); | ||||
| 	registerUpdateControlCallback(fieldWrap, [=](anim::type animated) { | ||||
| 		auto fieldShown = !selectionMode() && searchMode(); | ||||
| 		if (!fieldShown && field->hasFocus()) { | ||||
| 			setFocus(); | ||||
| 		} | ||||
| 		if (_title) { | ||||
| 			_title->entity()->setVisible(!enabled); | ||||
| 		fieldWrap->toggle(fieldShown, animated); | ||||
| 		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) { | ||||
| 			cancel->entity()->finishAnimations(); | ||||
| 		} | ||||
| 		search->wrapped()->toggle(!enabled, animated); | ||||
| 		if (enabled) { | ||||
| 			field->setFocus(); | ||||
| 		} | ||||
| 	}; | ||||
| 	}); | ||||
| 
 | ||||
| 	auto button = base::make_unique_q<Ui::IconButton>(this, _st.search); | ||||
| 	auto search = button.get(); | ||||
| 	search->addClickHandler([=] { | ||||
| 		_searchModeEnabled = true; | ||||
| 		updateControlsVisibility(anim::type::normal); | ||||
| 	}); | ||||
| 	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 = [=] { | ||||
| 		if (!field->getLastText().isEmpty()) { | ||||
| 			field->setText(QString()); | ||||
| 		} 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); | ||||
| 
 | ||||
| 	wrap->widthValue() | ||||
| 		| rpl::start_with_next([=](int newWidth) { | ||||
| 			auto availableWidth = newWidth | ||||
| 				- _st.searchRow.fieldCancelSkip; | ||||
| 			field->setGeometryToLeft( | ||||
| 			fieldWrap->resizeToWidth(availableWidth); | ||||
| 			fieldWrap->moveToLeft( | ||||
| 				_st.searchRow.padding.left(), | ||||
| 				_st.searchRow.padding.top(), | ||||
| 				availableWidth, | ||||
| 				field->height()); | ||||
| 				_st.searchRow.padding.top()); | ||||
| 			cancel->moveToRight(0, 0); | ||||
| 		}, wrap->lifetime()); | ||||
| 
 | ||||
|  | @ -191,10 +253,6 @@ void TopBar::createSearchView( | |||
| 				newWidth); | ||||
| 		}, wrap->lifetime()); | ||||
| 
 | ||||
| 	search->entity()->addClickHandler([=] { | ||||
| 		toggleSearchMode(true, anim::type::normal); | ||||
| 	}); | ||||
| 
 | ||||
| 	field->alive() | ||||
| 		| rpl::start_with_done([=] { | ||||
| 			field->setParent(nullptr); | ||||
|  | @ -202,18 +260,14 @@ void TopBar::createSearchView( | |||
| 			setSearchField(nullptr, rpl::never<bool>()); | ||||
| 		}, _searchView->lifetime()); | ||||
| 
 | ||||
| 	toggleSearchMode( | ||||
| 		!field->getLastText().isEmpty(), | ||||
| 		anim::type::instant); | ||||
| 	_searchModeEnabled = !field->getLastText().isEmpty(); | ||||
| 	updateControlsVisibility(anim::type::instant); | ||||
| 
 | ||||
| 	std::move(shown) | ||||
| 		| rpl::start_with_next([=](bool visible) { | ||||
| 			if (!field->getLastText().isEmpty()) { | ||||
| 				return; | ||||
| 			} | ||||
| 			toggleSearchMode(false, anim::type::instant); | ||||
| 			wrap->setVisible(visible); | ||||
| 			search->wrapped()->toggle(visible, anim::type::instant); | ||||
| 			auto alreadyInSearch = !field->getLastText().isEmpty(); | ||||
| 			_searchModeAvailable = visible || alreadyInSearch; | ||||
| 			updateControlsVisibility(anim::type::instant); | ||||
| 		}, wrap->lifetime()); | ||||
| } | ||||
| 
 | ||||
|  | @ -228,17 +282,6 @@ int TopBar::resizeGetHeight(int newWidth) { | |||
| 	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) { | ||||
| 	updateDefaultControlsGeometry(newWidth); | ||||
| 	updateSelectionControlsGeometry(newWidth); | ||||
|  | @ -286,7 +329,7 @@ void TopBar::updateSelectionControlsGeometry(int newWidth) { | |||
| 
 | ||||
| 	const auto top = 0; | ||||
| 	const auto availableWidth = newWidth - left - right; | ||||
| 	_selectionText->resizeToWidth(availableWidth); | ||||
| 	_selectionText->resizeToNaturalWidth(availableWidth); | ||||
| 	_selectionText->moveToLeft( | ||||
| 		left, | ||||
| 		top, | ||||
|  | @ -319,16 +362,31 @@ void TopBar::startHighlightAnimation() { | |||
| 		_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) { | ||||
| 	auto wasSelectionMode = selectionMode(); | ||||
| 	_selectedItems = std::move(items); | ||||
| 	if (selectionMode()) { | ||||
| 		if (_selectionText) { | ||||
| 			updateSelectionState(); | ||||
| 			if (!wasSelectionMode) { | ||||
| 				_selectionText->entity()->finishAnimating(); | ||||
| 			} | ||||
| 		} else { | ||||
| 			createSelectionControls(); | ||||
| 		} | ||||
| 	} | ||||
| 	toggleSelectionControls(); | ||||
| 	updateControlsVisibility(anim::type::normal); | ||||
| } | ||||
| 
 | ||||
| SelectedItems TopBar::takeSelectedItems() { | ||||
|  | @ -352,33 +410,43 @@ void TopBar::updateSelectionState() { | |||
| 
 | ||||
| void TopBar::createSelectionControls() { | ||||
| 	auto wrap = [&](auto created) { | ||||
| 		_selectionControls.push_back(created); | ||||
| 		registerToggleControlCallback( | ||||
| 			created, | ||||
| 			[this] { return selectionMode(); }); | ||||
| 		created->toggle(false, anim::type::instant); | ||||
| 		return created; | ||||
| 	}; | ||||
| 	_canDelete = computeCanDelete(); | ||||
| 	_cancelSelection = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 	_cancelSelection = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::IconButton>(this, _st.mediaCancel))); | ||||
| 		object_ptr<Ui::IconButton>(this, _st.mediaCancel), | ||||
| 		st::infoTopBarScale)); | ||||
| 	_cancelSelection->setDuration(st::infoTopBarDuration); | ||||
| 	_cancelSelection->entity()->clicks() | ||||
| 		| rpl::start_to_stream( | ||||
| 			_cancelSelectionClicks, | ||||
| 			_cancelSelection->lifetime()); | ||||
| 	_selectionText = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::LabelWithNumbers>>( | ||||
| 	_selectionText = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::LabelWithNumbers>>( | ||||
| 		this, | ||||
| 		object_ptr<Ui::LabelWithNumbers>( | ||||
| 			this, | ||||
| 			_st.title, | ||||
| 			_st.titlePosition.y(), | ||||
| 			generateSelectedText()))); | ||||
| 			generateSelectedText()), | ||||
| 		st::infoTopBarScale)); | ||||
| 	_selectionText->setDuration(st::infoTopBarDuration); | ||||
| 	_selectionText->entity()->resize(0, _st.height); | ||||
| 	_forward = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 	_forward = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>( | ||||
| 		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(); }); | ||||
| 	_delete = wrap(Ui::CreateChild<Ui::FadeWrapScaled<Ui::IconButton>>( | ||||
| 	_delete = wrap(Ui::CreateChild<Ui::FadeWrap<Ui::IconButton>>( | ||||
| 		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()->setVisible(_canDelete); | ||||
| 
 | ||||
|  | @ -392,23 +460,6 @@ bool TopBar::computeCanDelete() const { | |||
| 	) == _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 { | ||||
| 	using Data = Ui::StringWithNumbers; | ||||
| 	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::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()); | ||||
| } | ||||
|  | @ -431,27 +482,8 @@ bool TopBar::selectionMode() const { | |||
| 	return !_selectedItems.list.empty(); | ||||
| } | ||||
| 
 | ||||
| void TopBar::clearSelectionControls() { | ||||
| 	for (auto &&control : _selectionControls) { | ||||
| 		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; | ||||
| bool TopBar::searchMode() const { | ||||
| 	return _searchModeAvailable && _searchModeEnabled; | ||||
| } | ||||
| 
 | ||||
| SelectedItemSet TopBar::collectItems() const { | ||||
|  |  | |||
|  | @ -75,7 +75,6 @@ public: | |||
| 	SelectedItems takeSelectedItems(); | ||||
| 
 | ||||
| 	rpl::producer<> cancelSelectionRequests() const; | ||||
| 	void finishSelectionAnimations(); | ||||
| 
 | ||||
| protected: | ||||
| 	int resizeGetHeight(int newWidth) override; | ||||
|  | @ -85,17 +84,18 @@ private: | |||
| 	void updateControlsGeometry(int newWidth); | ||||
| 	void updateDefaultControlsGeometry(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 startHighlightAnimation(); | ||||
| 	void updateControlsVisibility(anim::type animated); | ||||
| 
 | ||||
| 	bool selectionMode() const; | ||||
| 	bool searchMode() const; | ||||
| 	Ui::StringWithNumbers generateSelectedText() const; | ||||
| 	[[nodiscard]] bool computeCanDelete() const; | ||||
| 	[[nodiscard]] SelectedItemSet collectSelectedItems() const; | ||||
| 	void updateSelectionState(); | ||||
| 	void createSelectionControls(); | ||||
| 	void toggleSelectionControls(); | ||||
| 	void clearSelectionControls(); | ||||
| 
 | ||||
| 	SelectedItemSet collectItems() const; | ||||
|  | @ -109,6 +109,12 @@ private: | |||
| 		not_null<Ui::InputField*> field, | ||||
| 		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; | ||||
| 	Animation _a_highlight; | ||||
| 	bool _highlight = false; | ||||
|  | @ -116,6 +122,8 @@ private: | |||
| 	std::vector<base::unique_qptr<Ui::RpWidget>> _buttons; | ||||
| 	QPointer<Ui::FadeWrap<Ui::FlatLabel>> _title; | ||||
| 
 | ||||
| 	bool _searchModeEnabled = false; | ||||
| 	bool _searchModeAvailable = false; | ||||
| 	base::unique_qptr<Ui::RpWidget> _searchView; | ||||
| 
 | ||||
| 	rpl::event_stream<> _backClicks; | ||||
|  | @ -128,9 +136,8 @@ private: | |||
| 	QPointer<Ui::FadeWrap<Ui::IconButton>> _delete; | ||||
| 	rpl::event_stream<> _cancelSelectionClicks; | ||||
| 
 | ||||
| 	using FadingControl = QPointer<Ui::FadeWrap<RpWidget>>; | ||||
| 	std::vector<FadingControl> _defaultControls; | ||||
| 	std::vector<FadingControl> _selectionControls; | ||||
| 	using UpdateCallback = base::lambda<bool(anim::type)>; | ||||
| 	std::map<QObject*, UpdateCallback> _updateControlCallbacks; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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
 | ||||
|  | @ -36,7 +36,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| #include "styles/style_info.h" | ||||
| #include "boxes/peer_list_controllers.h" | ||||
| #include "boxes/confirm_box.h" | ||||
| #include "info/info_top_bar_override.h" | ||||
| #include "core/file_utilities.h" | ||||
| 
 | ||||
| namespace Layout = Overview::Layout; | ||||
|  |  | |||
|  | @ -38,7 +38,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| #include "lang/lang_keys.h" | ||||
| #include "info/info_controller.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_values.h" | ||||
| #include "info/profile/info_profile_button.h" | ||||
|  |  | |||
|  | @ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | |||
| #include <rpl/flatten_latest.h> | ||||
| #include "info/info_memento.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_widget.h" | ||||
| #include "info/profile/info_profile_text.h" | ||||
|  |  | |||
|  | @ -187,7 +187,7 @@ void Members::setupButtons() { | |||
| 	}); | ||||
| 
 | ||||
| 	//_searchField->hide();
 | ||||
| 	//_cancelSearch->hideFast();
 | ||||
| 	//_cancelSearch->setVisible(false);
 | ||||
| 
 | ||||
| 	auto addMemberShown = CanAddMemberValue(_peer) | ||||
| 		| rpl::start_spawning(lifetime()); | ||||
|  | @ -344,15 +344,14 @@ void Members::addMember() { | |||
| //
 | ||||
| //void Members::toggleSearch(anim::type animated) {
 | ||||
| //	_searchShown = !_searchShown;
 | ||||
| //	_cancelSearch->toggle(_searchShown, animated);
 | ||||
| //	if (animated == anim::type::normal) {
 | ||||
| //		_cancelSearch->toggleAnimated(_searchShown);
 | ||||
| //		_searchShownAnimation.start(
 | ||||
| //			[this] { searchAnimationCallback(); },
 | ||||
| //			_searchShown ? 0. : 1.,
 | ||||
| //			_searchShown ? 1. : 0.,
 | ||||
| //			st::slideWrapDuration);
 | ||||
| //	} else {
 | ||||
| //		_cancelSearch->toggleFast(_searchShown);
 | ||||
| //		_searchShownAnimation.finish();
 | ||||
| //		searchAnimationCallback();
 | ||||
| //	}
 | ||||
|  |  | |||
|  | @ -27,9 +27,9 @@ constexpr int kWideScale = 5; | |||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| FadeAnimation::FadeAnimation(TWidget *widget, bool scaled) | ||||
| FadeAnimation::FadeAnimation(TWidget *widget, float64 scale) | ||||
| : _widget(widget) | ||||
| , _scaled(scaled) { | ||||
| , _scale(scale) { | ||||
| } | ||||
| 
 | ||||
| bool FadeAnimation::paint(Painter &p) { | ||||
|  | @ -37,13 +37,28 @@ bool FadeAnimation::paint(Painter &p) { | |||
| 
 | ||||
| 	auto opacity = _animation.current(getms(), _visible ? 1. : 0.); | ||||
| 	p.setOpacity(opacity); | ||||
| 	if (_scaled) { | ||||
| 	if (_scale < 1.) { | ||||
| 		PainterHighQualityEnabler hq(p); | ||||
| 		auto targetRect = QRect((1 - kWideScale) / 2 * _size.width(), (1 - kWideScale) / 2 * _size.height(), kWideScale * _size.width(), kWideScale * _size.height()); | ||||
| 		auto scale = opacity; | ||||
| 		auto shownWidth = anim::interpolate((1 - kWideScale) / 2 * _size.width(), 0, scale); | ||||
| 		auto shownHeight = anim::interpolate((1 - kWideScale) / 2 * _size.height(), 0, scale); | ||||
| 		p.drawPixmap(targetRect.marginsAdded(QMargins(shownWidth, shownHeight, shownWidth, shownHeight)), _cache); | ||||
| 		auto targetRect = QRect( | ||||
| 			(1 - kWideScale) / 2 * _size.width(), | ||||
| 			(1 - kWideScale) / 2 * _size.height(), | ||||
| 			kWideScale * _size.width(), | ||||
| 			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 { | ||||
| 		p.drawPixmap(0, 0, _cache); | ||||
| 	} | ||||
|  | @ -70,18 +85,17 @@ QPixmap FadeAnimation::grabContent() { | |||
| 		return App::pixmapFromImageInPlace(std::move(image)); | ||||
| 	} | ||||
| 	auto widgetContent = myGrab(_widget); | ||||
| 	if (!_scaled) { | ||||
| 		return widgetContent; | ||||
| 	if (_scale < 1.) { | ||||
| 		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)); | ||||
| 	} | ||||
| 
 | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| void FadeAnimation::setFinishedCallback(FinishedCallback &&callback) { | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ namespace Ui { | |||
| 
 | ||||
| class FadeAnimation { | ||||
| public: | ||||
| 	FadeAnimation(TWidget *widget, bool scaled = false); | ||||
| 	FadeAnimation(TWidget *widget, float64 scale = 1.); | ||||
| 
 | ||||
| 	bool paint(Painter &p); | ||||
| 	void refreshCache(); | ||||
|  | @ -63,7 +63,7 @@ private: | |||
| 	QPixmap grabContent(); | ||||
| 
 | ||||
| 	TWidget *_widget = nullptr; | ||||
| 	bool _scaled = false; | ||||
| 	float64 _scale = 1.; | ||||
| 
 | ||||
| 	Animation _animation; | ||||
| 	QSize _size; | ||||
|  |  | |||
|  | @ -105,6 +105,10 @@ int NumbersAnimation::countWidth() const { | |||
| 		anim::easeOutCirc(1., _a_ready.current(1.))); | ||||
| } | ||||
| 
 | ||||
| int NumbersAnimation::maxWidth() const { | ||||
| 	return std::max(_fromWidth, _toWidth); | ||||
| } | ||||
| 
 | ||||
| void NumbersAnimation::stepAnimation(TimeMs ms) { | ||||
| 	_a_ready.step(ms); | ||||
| } | ||||
|  | @ -212,6 +216,12 @@ void LabelWithNumbers::setValue(const StringWithNumbers &value) { | |||
| 	_afterWidth = _st.style.font->width(_after); | ||||
| } | ||||
| 
 | ||||
| void LabelWithNumbers::finishAnimating() { | ||||
| 	_beforeWidthAnimation.finish(); | ||||
| 	_numbers.finishAnimating(); | ||||
| 	update(); | ||||
| } | ||||
| 
 | ||||
| void LabelWithNumbers::paintEvent(QPaintEvent *e) { | ||||
| 	Painter p(this); | ||||
| 
 | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ public: | |||
| 
 | ||||
| 	void paint(Painter &p, int x, int y, int outerWidth); | ||||
| 	int countWidth() const; | ||||
| 	int maxWidth() const; | ||||
| 
 | ||||
| private: | ||||
| 	struct Digit { | ||||
|  | @ -90,6 +91,11 @@ public: | |||
| 		const StringWithNumbers &value); | ||||
| 
 | ||||
| 	void setValue(const StringWithNumbers &value); | ||||
| 	void finishAnimating(); | ||||
| 
 | ||||
| 	int naturalWidth() const override { | ||||
| 		return _beforeWidth + _numbers.maxWidth() + _afterWidth; | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	void paintEvent(QPaintEvent *e) override; | ||||
|  |  | |||
|  | @ -58,9 +58,9 @@ base::unique_qptr<Ui::RpWidget> SearchFieldController::createRowView( | |||
| 			return !value.isEmpty(); | ||||
| 		}) | ||||
| 		| rpl::start_with_next([cancel](bool shown) { | ||||
| 			cancel->toggleAnimated(shown); | ||||
| 			cancel->toggle(shown, anim::type::normal); | ||||
| 		}, cancel->lifetime()); | ||||
| 	cancel->finishAnimations(); | ||||
| 	cancel->finishAnimating(); | ||||
| 
 | ||||
| 	auto shadow = CreateChild<Ui::PlainShadow>(wrap); | ||||
| 	shadow->show(); | ||||
|  |  | |||
|  | @ -472,57 +472,70 @@ private: | |||
| template <typename Object> | ||||
| class object_ptr { | ||||
| public: | ||||
| 	object_ptr(std::nullptr_t) { | ||||
| 	object_ptr(std::nullptr_t) noexcept { | ||||
| 	} | ||||
| 
 | ||||
| 	// No default constructor, but constructors with at least
 | ||||
| 	// one argument are simply make functions.
 | ||||
| 	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 &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); | ||||
| 		destroy(); | ||||
| 		std::swap(_object, temp._object); | ||||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	template <typename OtherObject, typename = std::enable_if_t<std::is_base_of<Object, OtherObject>::value>> | ||||
| 	object_ptr(object_ptr<OtherObject> &&other) : _object(base::take(other._object)) { | ||||
| 	template < | ||||
| 		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>> | ||||
| 	object_ptr &operator=(object_ptr<OtherObject> &&other) { | ||||
| 	template < | ||||
| 		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); | ||||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	object_ptr &operator=(std::nullptr_t) { | ||||
| 	object_ptr &operator=(std::nullptr_t) noexcept { | ||||
| 		_object = nullptr; | ||||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	// So we can pass this pointer to methods like connect().
 | ||||
| 	Object *data() const { | ||||
| 	Object *data() const noexcept { | ||||
| 		return static_cast<Object*>(_object.data()); | ||||
| 	} | ||||
| 	operator Object*() const { | ||||
| 	operator Object*() const noexcept { | ||||
| 		return data(); | ||||
| 	} | ||||
| 
 | ||||
| 	explicit operator bool() const { | ||||
| 	explicit operator bool() const noexcept { | ||||
| 		return _object != nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	Object *operator->() const { | ||||
| 	Object *operator->() const noexcept { | ||||
| 		return data(); | ||||
| 	} | ||||
| 	Object &operator*() const { | ||||
| 	Object &operator*() const noexcept { | ||||
| 		return *data(); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -530,10 +543,12 @@ public: | |||
| 	template <typename Parent, typename... Args> | ||||
| 	Object *create(Parent &&parent, Args&&... args) { | ||||
| 		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(); | ||||
| 	} | ||||
| 	void destroy() { | ||||
| 	void destroy() noexcept { | ||||
| 		delete base::take(_object); | ||||
| 	} | ||||
| 	void destroyDelayed() { | ||||
|  | @ -545,7 +560,7 @@ public: | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	~object_ptr() { | ||||
| 	~object_ptr() noexcept { | ||||
| 		if (auto pointer = _object) { | ||||
| 			if (!pointer->parent()) { | ||||
| 				destroy(); | ||||
|  | @ -554,7 +569,8 @@ public: | |||
| 	} | ||||
| 
 | ||||
| 	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: | ||||
| 	template <typename OtherObject> | ||||
|  | @ -565,14 +581,23 @@ private: | |||
| }; | ||||
| 
 | ||||
| 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); | ||||
| 	result._object = static_cast<ResultType*>(base::take(source._object).data()); | ||||
| 	result._object = static_cast<ResultType*>( | ||||
| 		base::take(source._object).data()); | ||||
| 	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()); | ||||
| } | ||||
|  |  | |||
|  | @ -478,7 +478,7 @@ CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : Ripple | |||
| , _a_loading(animation(this, &CrossButton::step_loading)) { | ||||
| 	resize(_st.width, _st.height); | ||||
| 	setCursor(style::cur_pointer); | ||||
| 	hide(); | ||||
| 	setVisible(false); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	if (_shown == visible) { | ||||
| 		return; | ||||
| void CrossButton::toggle(bool visible, anim::type animated) { | ||||
| 	if (_shown != visible) { | ||||
| 		_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 (isHidden()) { | ||||
| 		show(); | ||||
| 	if (animated == anim::type::instant) { | ||||
| 		finishAnimating(); | ||||
| 	} | ||||
| 	_a_show.start([this] { animationCallback(); }, _shown ? 0. : 1., _shown ? 1. : 0., _st.duration); | ||||
| } | ||||
| 
 | ||||
| void CrossButton::animationCallback() { | ||||
| 	update(); | ||||
| 	if (!_shown && !_a_show.animating()) { | ||||
| 		hide(); | ||||
| 	if (!_a_show.animating()) { | ||||
| 		setVisible(_shown); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -212,28 +212,19 @@ class CrossButton : public RippleButton { | |||
| public: | ||||
| 	CrossButton(QWidget *parent, const style::CrossButton &st); | ||||
| 
 | ||||
| 	void showAnimated() { | ||||
| 		toggleAnimated(true); | ||||
| 	void toggle(bool shown, anim::type animated); | ||||
| 	void show(anim::type animated) { | ||||
| 		return toggle(true, animated); | ||||
| 	} | ||||
| 	void hideAnimated() { | ||||
| 		toggleAnimated(false); | ||||
| 	void hide(anim::type animated) { | ||||
| 		return toggle(false, animated); | ||||
| 	} | ||||
| 	void toggleAnimated(bool visible); | ||||
| 	void showFast() { | ||||
| 		toggleFast(true); | ||||
| 	} | ||||
| 	void hideFast() { | ||||
| 		toggleFast(false); | ||||
| 	} | ||||
| 	void toggleFast(bool visible) { | ||||
| 		toggleAnimated(visible); | ||||
| 		finishAnimations(); | ||||
| 	} | ||||
| 	void finishAnimations() { | ||||
| 	void finishAnimating() { | ||||
| 		_a_show.finish(); | ||||
| 		animationCallback(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool isShown() const { | ||||
| 	bool toggled() const { | ||||
| 		return _shown; | ||||
| 	} | ||||
| 	void setLoadingAnimation(bool enabled); | ||||
|  |  | |||
|  | @ -383,11 +383,7 @@ MultiSelect::Inner::Inner(QWidget *parent, const style::MultiSelect &st, base::l | |||
| 
 | ||||
| void MultiSelect::Inner::onQueryChanged() { | ||||
| 	auto query = getQuery(); | ||||
| 	if (query.isEmpty()) { | ||||
| 		_cancel->hideAnimated(); | ||||
| 	} else { | ||||
| 		_cancel->showAnimated(); | ||||
| 	} | ||||
| 	_cancel->toggle(!query.isEmpty(), anim::type::normal); | ||||
| 	updateFieldGeometry(); | ||||
| 	if (_queryChangedCallback) { | ||||
| 		_queryChangedCallback(query); | ||||
|  | @ -422,7 +418,7 @@ void MultiSelect::Inner::setSubmittedCallback(base::lambda<void(bool ctrlShiftEn | |||
| 
 | ||||
| void MultiSelect::Inner::updateFieldGeometry() { | ||||
| 	auto fieldFinalWidth = _fieldWidth; | ||||
| 	if (_cancel->isShown()) { | ||||
| 	if (_cancel->toggled()) { | ||||
| 		fieldFinalWidth -= _st.fieldCancelSkip; | ||||
| 	} | ||||
| 	_field->resizeToWidth(fieldFinalWidth); | ||||
|  |  | |||
|  | @ -27,9 +27,9 @@ namespace Ui { | |||
| FadeWrap<RpWidget>::FadeWrap( | ||||
| 	QWidget *parent, | ||||
| 	object_ptr<RpWidget> &&child, | ||||
| 	bool scaled) | ||||
| 	float64 scale) | ||||
| : Parent(parent, std::move(child)) | ||||
| , _animation(this, scaled) | ||||
| , _animation(this, scale) | ||||
| , _duration(st::fadeWrapDuration) { | ||||
| 	if (auto weak = wrapped()) { | ||||
| 		weak->show(); | ||||
|  |  | |||
|  | @ -36,13 +36,10 @@ class FadeWrap<RpWidget> : public Wrap<RpWidget> { | |||
| 	using Parent = Wrap<RpWidget>; | ||||
| 
 | ||||
| public: | ||||
| 	FadeWrap(QWidget *parent, object_ptr<RpWidget> &&child) | ||||
| 	: FadeWrap(parent, std::move(child), false) { | ||||
| 	} | ||||
| 	FadeWrap( | ||||
| 		QWidget *parent, | ||||
| 		object_ptr<RpWidget> &&child, | ||||
| 		bool scaled); | ||||
| 		float64 scale = 1.); | ||||
| 
 | ||||
| 	FadeWrap *setDuration(int duration); | ||||
| 	FadeWrap *toggle(bool shown, anim::type animated); | ||||
|  | @ -81,14 +78,11 @@ class FadeWrap : public Wrap<Widget, FadeWrap<RpWidget>> { | |||
| 	using Parent = Wrap<Widget, FadeWrap<RpWidget>>; | ||||
| 
 | ||||
| public: | ||||
| 	FadeWrap(QWidget *parent, object_ptr<Widget> &&child) | ||||
| 	: Parent(parent, std::move(child)) { | ||||
| 	} | ||||
| 	FadeWrap( | ||||
| 		QWidget *parent, | ||||
| 		object_ptr<Widget> &&child, | ||||
| 		bool scaled) | ||||
| 	: Parent(parent, std::move(child), scaled) { | ||||
| 		float64 scale = 1.) | ||||
| 	: Parent(parent, std::move(child), scale) { | ||||
| 	} | ||||
| 
 | ||||
| 	FadeWrap *setDuration(int duration) { | ||||
|  | @ -123,7 +117,7 @@ class FadeWrapScaled : public FadeWrap<Widget> { | |||
| 
 | ||||
| public: | ||||
| 	FadeWrapScaled(QWidget *parent, object_ptr<Widget> &&child) | ||||
| 	: Parent(parent, std::move(child), true) { | ||||
| 	: Parent(parent, std::move(child), 0.) { | ||||
| 	} | ||||
| 
 | ||||
| }; | ||||
|  |  | |||
|  | @ -727,7 +727,7 @@ Editor::Editor(QWidget*, const QString &path) | |||
| 		_scroll->scrollToY(top, bottom); | ||||
| 	}); | ||||
| 	_close->setClickedCallback([this] { closeEditor(); }); | ||||
| 	_close->showFast(); | ||||
| 	_close->show(anim::type::instant); | ||||
| 
 | ||||
| 	_select->resizeToWidth(st::windowMinWidth); | ||||
| 	_select->setQueryChangedCallback([this](const QString &query) { _inner->filterRows(query); _scroll->scrollToY(0); }); | ||||
|  |  | |||
|  | @ -234,8 +234,6 @@ | |||
| <(src_loc)/info/info_section_widget.h | ||||
| <(src_loc)/info/info_top_bar.cpp | ||||
| <(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.h | ||||
| <(src_loc)/info/common_groups/info_common_groups_inner_widget.cpp | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue