mirror of https://github.com/procxx/kepka.git
				
				
				
			Animate suggestions select-by-keyboard.
This commit is contained in:
		
							parent
							
								
									1da9385fe2
								
							
						
					
					
						commit
						c4357c7ad3
					
				| 
						 | 
				
			
			@ -25,6 +25,7 @@ namespace {
 | 
			
		|||
 | 
			
		||||
constexpr auto kShowExactDelay = crl::time(300);
 | 
			
		||||
constexpr auto kMaxNonScrolledEmoji = 7;
 | 
			
		||||
constexpr auto kAnimationDuration = crl::time(120);
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +146,9 @@ void SuggestionsWidget::resizeToRows() {
 | 
			
		|||
		? st::emojiSuggestionsScrolledWidth
 | 
			
		||||
		: fullWidth;
 | 
			
		||||
	_scrollMax = std::max(0, fullWidth - newWidth);
 | 
			
		||||
	_scroll = std::min(_scroll, _scrollMax);
 | 
			
		||||
	if (_scrollValue > _scrollMax || scrollCurrent() > _scrollMax) {
 | 
			
		||||
		scrollTo(std::min(_scrollValue, _scrollMax));
 | 
			
		||||
	}
 | 
			
		||||
	resize(_padding.left() + newWidth + _padding.right(), height());
 | 
			
		||||
	update();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -165,22 +168,23 @@ void SuggestionsWidget::scrollByWheelEvent(not_null<QWheelEvent*> e) {
 | 
			
		|||
		|| (e->orientation() == Qt::Horizontal);
 | 
			
		||||
	const auto vertical = (e->angleDelta().y() != 0)
 | 
			
		||||
		|| (e->orientation() == Qt::Vertical);
 | 
			
		||||
	const auto current = scrollCurrent();
 | 
			
		||||
	const auto scroll = [&] {
 | 
			
		||||
		if (horizontal) {
 | 
			
		||||
			const auto delta = e->pixelDelta().x()
 | 
			
		||||
				? e->pixelDelta().x()
 | 
			
		||||
				: e->angleDelta().x();
 | 
			
		||||
			return snap(_scroll - ((rtl() ? -1 : 1) * delta), 0, _scrollMax);
 | 
			
		||||
			return snap(current - ((rtl() ? -1 : 1) * delta), 0, _scrollMax);
 | 
			
		||||
		} else if (vertical) {
 | 
			
		||||
			const auto delta = e->pixelDelta().y()
 | 
			
		||||
				? e->pixelDelta().y()
 | 
			
		||||
				: e->angleDelta().y();
 | 
			
		||||
			return snap(_scroll - delta, 0, _scrollMax);
 | 
			
		||||
			return snap(current - delta, 0, _scrollMax);
 | 
			
		||||
		}
 | 
			
		||||
		return _scroll;
 | 
			
		||||
		return current;
 | 
			
		||||
	}();
 | 
			
		||||
	if (_scroll != scroll) {
 | 
			
		||||
		_scroll = scroll;
 | 
			
		||||
	if (current != scroll) {
 | 
			
		||||
		scrollTo(scroll);
 | 
			
		||||
		if (!_lastMousePosition) {
 | 
			
		||||
			_lastMousePosition = QCursor::pos();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -203,20 +207,23 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
 | 
			
		|||
		(paint.x() + paint.width() + _oneWidth - 1) / _oneWidth,
 | 
			
		||||
		int(_rows.size()));
 | 
			
		||||
 | 
			
		||||
	const auto selected = (_pressed >= 0)
 | 
			
		||||
		? _pressed
 | 
			
		||||
		: _selectedAnimation.value(_selected);
 | 
			
		||||
	if (selected > -1.) {
 | 
			
		||||
		App::roundRect(
 | 
			
		||||
			p,
 | 
			
		||||
			QRect(selected * _oneWidth, 0, _oneWidth, _oneWidth),
 | 
			
		||||
			st::emojiPanHover,
 | 
			
		||||
			StickerHoverCorners);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (auto i = from; i != till; ++i) {
 | 
			
		||||
		const auto &row = _rows[i];
 | 
			
		||||
		const auto emoji = row.emoji;
 | 
			
		||||
		const auto esize = Ui::Emoji::GetSizeLarge();
 | 
			
		||||
		const auto selected = (i == _selected || i == _pressed);
 | 
			
		||||
		const auto x = i * _oneWidth;
 | 
			
		||||
		const auto y = 0;
 | 
			
		||||
		if (selected) {
 | 
			
		||||
			App::roundRect(
 | 
			
		||||
				p,
 | 
			
		||||
				QRect(x, y, _oneWidth, _oneWidth),
 | 
			
		||||
				st::emojiPanHover,
 | 
			
		||||
				StickerHoverCorners);
 | 
			
		||||
		}
 | 
			
		||||
		Ui::Emoji::Draw(
 | 
			
		||||
			p,
 | 
			
		||||
			emoji,
 | 
			
		||||
| 
						 | 
				
			
			@ -228,8 +235,9 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void SuggestionsWidget::paintFadings(Painter &p) const {
 | 
			
		||||
	const auto scroll = scrollCurrent();
 | 
			
		||||
	const auto o_left = snap(
 | 
			
		||||
		_scroll / float64(st::emojiSuggestionsFadeAfter),
 | 
			
		||||
		scroll / float64(st::emojiSuggestionsFadeAfter),
 | 
			
		||||
		0.,
 | 
			
		||||
		1.);
 | 
			
		||||
	const auto shift = innerShift();
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +252,7 @@ void SuggestionsWidget::paintFadings(Painter &p) const {
 | 
			
		|||
		p.setOpacity(1.);
 | 
			
		||||
	}
 | 
			
		||||
	const auto o_right = snap(
 | 
			
		||||
		(_scrollMax - _scroll) / float64(st::emojiSuggestionsFadeAfter),
 | 
			
		||||
		(_scrollMax - scroll) / float64(st::emojiSuggestionsFadeAfter),
 | 
			
		||||
		0.,
 | 
			
		||||
		1.);
 | 
			
		||||
	if (o_right > 0.) {
 | 
			
		||||
| 
						 | 
				
			
			@ -298,14 +306,32 @@ bool SuggestionsWidget::handleKeyEvent(int key) {
 | 
			
		|||
 | 
			
		||||
	_mouseSelection = false;
 | 
			
		||||
	_lastMousePosition = std::nullopt;
 | 
			
		||||
	setSelected(newSelected);
 | 
			
		||||
	setSelected(newSelected, anim::type::normal);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SuggestionsWidget::setSelected(int selected) {
 | 
			
		||||
void SuggestionsWidget::setSelected(int selected, anim::type animated) {
 | 
			
		||||
	if (selected >= _rows.size()) {
 | 
			
		||||
		selected = -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (animated == anim::type::normal) {
 | 
			
		||||
		_selectedAnimation.start(
 | 
			
		||||
			[=] { update(); },
 | 
			
		||||
			_selected,
 | 
			
		||||
			selected,
 | 
			
		||||
			kAnimationDuration,
 | 
			
		||||
			anim::sineInOut);
 | 
			
		||||
		if (_scrollMax > 0) {
 | 
			
		||||
			const auto selectedMax = int(_rows.size()) - 3;
 | 
			
		||||
			const auto selectedForScroll = std::min(
 | 
			
		||||
				std::max(selected, 1) - 1,
 | 
			
		||||
				selectedMax);
 | 
			
		||||
			scrollTo((_scrollMax * selectedForScroll) / selectedMax, animated);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (_selectedAnimation.animating()) {
 | 
			
		||||
		_selectedAnimation.stop();
 | 
			
		||||
		update();
 | 
			
		||||
	}
 | 
			
		||||
	if (_selected != selected) {
 | 
			
		||||
		updateSelectedItem();
 | 
			
		||||
		_selected = selected;
 | 
			
		||||
| 
						 | 
				
			
			@ -313,6 +339,30 @@ void SuggestionsWidget::setSelected(int selected) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SuggestionsWidget::scrollCurrent() const {
 | 
			
		||||
	return _scrollAnimation.value(_scrollValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SuggestionsWidget::scrollTo(int value, anim::type animated) {
 | 
			
		||||
	if (animated == anim::type::instant) {
 | 
			
		||||
		_scrollAnimation.stop();
 | 
			
		||||
	} else {
 | 
			
		||||
		_scrollAnimation.start(
 | 
			
		||||
			[=] { update(); },
 | 
			
		||||
			_scrollValue,
 | 
			
		||||
			value,
 | 
			
		||||
			kAnimationDuration,
 | 
			
		||||
			anim::sineInOut);
 | 
			
		||||
	}
 | 
			
		||||
	_scrollValue = value;
 | 
			
		||||
	update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SuggestionsWidget::stopAnimations() {
 | 
			
		||||
	_scrollValue = _scrollAnimation.value(_scrollValue);
 | 
			
		||||
	_scrollAnimation.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SuggestionsWidget::setPressed(int pressed) {
 | 
			
		||||
	if (pressed >= _rows.size()) {
 | 
			
		||||
		pressed = -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +390,7 @@ void SuggestionsWidget::clearSelection() {
 | 
			
		|||
void SuggestionsWidget::updateItem(int index) {
 | 
			
		||||
	if (index >= 0 && index < _rows.size()) {
 | 
			
		||||
		update(
 | 
			
		||||
			_padding.left() + index * _oneWidth - _scroll,
 | 
			
		||||
			_padding.left() + index * _oneWidth - scrollCurrent(),
 | 
			
		||||
			_padding.top(),
 | 
			
		||||
			_oneWidth,
 | 
			
		||||
			_oneWidth);
 | 
			
		||||
| 
						 | 
				
			
			@ -356,7 +406,7 @@ QRect SuggestionsWidget::inner() const {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
QPoint SuggestionsWidget::innerShift() const {
 | 
			
		||||
	return QPoint(_scroll - _padding.left(), -_padding.top());
 | 
			
		||||
	return QPoint(scrollCurrent() - _padding.left(), -_padding.top());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPoint SuggestionsWidget::mapToInner(QPoint globalPosition) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -371,8 +421,8 @@ void SuggestionsWidget::mouseMoveEvent(QMouseEvent *e) {
 | 
			
		|||
			_dragScrollStart + (rtl() ? -1 : 1) * delta,
 | 
			
		||||
			0,
 | 
			
		||||
			_scrollMax);
 | 
			
		||||
		if (_scroll != scroll) {
 | 
			
		||||
			_scroll = scroll;
 | 
			
		||||
		if (scrollCurrent() != scroll) {
 | 
			
		||||
			scrollTo(scroll);
 | 
			
		||||
			update();
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -380,8 +430,9 @@ void SuggestionsWidget::mouseMoveEvent(QMouseEvent *e) {
 | 
			
		|||
		&& (_scrollMax > 0)
 | 
			
		||||
		&& ((_mousePressPosition - globalPosition).manhattanLength()
 | 
			
		||||
			>= QApplication::startDragDistance())) {
 | 
			
		||||
		_dragScrollStart = _scroll;
 | 
			
		||||
		_dragScrollStart = scrollCurrent();
 | 
			
		||||
		_mousePressPosition = globalPosition;
 | 
			
		||||
		scrollTo(_dragScrollStart);
 | 
			
		||||
	}
 | 
			
		||||
	if (inner().contains(mapToInner(globalPosition))) {
 | 
			
		||||
		if (!_lastMousePosition) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
			
		|||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "ui/effects/panel_animation.h"
 | 
			
		||||
#include "ui/effects/animations.h"
 | 
			
		||||
#include "ui/rp_widget.h"
 | 
			
		||||
#include "base/unique_qptr.h"
 | 
			
		||||
#include "base/timer.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,9 @@ private:
 | 
			
		|||
 | 
			
		||||
	std::vector<Row> getRowsByQuery() const;
 | 
			
		||||
	void resizeToRows();
 | 
			
		||||
	void setSelected(int selected);
 | 
			
		||||
	void setSelected(
 | 
			
		||||
		int selected,
 | 
			
		||||
		anim::type animated = anim::type::instant);
 | 
			
		||||
	void setPressed(int pressed);
 | 
			
		||||
	void clearMouseSelection();
 | 
			
		||||
	void clearSelection();
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +67,10 @@ private:
 | 
			
		|||
	bool triggerSelectedRow() const;
 | 
			
		||||
	void triggerRow(const Row &row) const;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] int scrollCurrent() const;
 | 
			
		||||
	void scrollTo(int value, anim::type animated = anim::type::instant);
 | 
			
		||||
	void stopAnimations();
 | 
			
		||||
 | 
			
		||||
	QString _query;
 | 
			
		||||
	std::vector<Row> _rows;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +79,9 @@ private:
 | 
			
		|||
	int _selected = -1;
 | 
			
		||||
	int _pressed = -1;
 | 
			
		||||
 | 
			
		||||
	int _scroll = 0;
 | 
			
		||||
	int _scrollValue = 0;
 | 
			
		||||
	Ui::Animations::Simple _scrollAnimation;
 | 
			
		||||
	Ui::Animations::Simple _selectedAnimation;
 | 
			
		||||
	int _scrollMax = 0;
 | 
			
		||||
	int _oneWidth = 0;
 | 
			
		||||
	QMargins _padding;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue