mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 15:47:11 +02:00
Menu reactions selector without enabled compositing.
This commit is contained in:
parent
688cd70c91
commit
c13221a984
3 changed files with 104 additions and 35 deletions
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/text/text_custom_emoji.h"
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
#include "history/history_item.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -34,6 +35,7 @@ constexpr auto kScaleDuration = crl::time(120);
|
|||
constexpr auto kFullDuration = kExpandDuration + kScaleDuration;
|
||||
constexpr auto kExpandDelay = crl::time(40);
|
||||
constexpr auto kDefaultColumns = 8;
|
||||
constexpr auto kMinNonTransparentColumns = 7;
|
||||
|
||||
class StripEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
|
@ -164,12 +166,18 @@ Selector::Selector(
|
|||
, _skipy((st::reactStripHeight - st::reactStripSize) / 2) {
|
||||
setMouseTracking(true);
|
||||
|
||||
_useTransparency = Ui::Platform::TranslucentWindowsSupported();
|
||||
|
||||
parentController->content()->alive(
|
||||
) | rpl::start_with_done([=] {
|
||||
close(true);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
bool Selector::useTransparency() const {
|
||||
return _useTransparency;
|
||||
}
|
||||
|
||||
int Selector::recentCount() const {
|
||||
return int(_strip ? _reactions.recent.size() : _recent.size());
|
||||
}
|
||||
|
@ -188,8 +196,11 @@ int Selector::countWidth(int desiredWidth, int maxWidth) {
|
|||
const auto addedToMax = _reactions.customAllowed
|
||||
|| _reactions.morePremiumAvailable;
|
||||
const auto max = recentCount() + (addedToMax ? 1 : 0);
|
||||
const auto possibleColumns = std::min(
|
||||
const auto desiredColumns = std::max(
|
||||
(desiredWidth - 2 * _skipx + _size - 1) / _size,
|
||||
kMinNonTransparentColumns);
|
||||
const auto possibleColumns = std::min(
|
||||
desiredColumns,
|
||||
(maxWidth - 2 * _skipx) / _size);
|
||||
_columns = _strip ? std::min(possibleColumns, max) : kDefaultColumns;
|
||||
_small = (possibleColumns - _columns > 1);
|
||||
|
@ -223,7 +234,10 @@ int Selector::countWidth(int desiredWidth, int maxWidth) {
|
|||
}
|
||||
|
||||
QMargins Selector::extentsForShadow() const {
|
||||
return st::reactionCornerShadow;
|
||||
const auto line = st::lineWidth;
|
||||
return useTransparency()
|
||||
? st::reactionCornerShadow
|
||||
: QMargins(line, line, line, line);
|
||||
}
|
||||
|
||||
int Selector::extendTopForCategories() const {
|
||||
|
@ -246,10 +260,14 @@ void Selector::initGeometry(int innerTop) {
|
|||
const auto parent = parentWidget()->rect();
|
||||
const auto innerWidth = 2 * _skipx + _columns * _size;
|
||||
const auto innerHeight = st::reactStripHeight;
|
||||
const auto width = innerWidth + extents.left() + extents.right();
|
||||
const auto width = _useTransparency
|
||||
? (innerWidth + extents.left() + extents.right())
|
||||
: parent.width();
|
||||
const auto height = innerHeight + extents.top() + extents.bottom();
|
||||
const auto left = style::RightToLeft() ? 0 : (parent.width() - width);
|
||||
_collapsedTopSkip = extendTopForCategories() + _specialExpandTopSkip;
|
||||
_collapsedTopSkip = _useTransparency
|
||||
? (extendTopForCategories() + _specialExpandTopSkip)
|
||||
: 0;
|
||||
const auto top = innerTop - extents.top() - _collapsedTopSkip;
|
||||
const auto add = st::reactStripBubble.height() - extents.bottom();
|
||||
_outer = QRect(0, _collapsedTopSkip, width, height);
|
||||
|
@ -269,7 +287,10 @@ void Selector::updateShowState(
|
|||
float64 opacity,
|
||||
bool appearing,
|
||||
bool toggling) {
|
||||
if (_appearing && !appearing && !_paintBuffer.isNull()) {
|
||||
if (_useTransparency
|
||||
&& _appearing
|
||||
&& !appearing
|
||||
&& !_paintBuffer.isNull()) {
|
||||
paintBackgroundToBuffer();
|
||||
}
|
||||
_appearing = appearing;
|
||||
|
@ -343,12 +364,18 @@ void Selector::paintAppearing(QPainter &p) {
|
|||
}
|
||||
|
||||
void Selector::paintBackgroundToBuffer() {
|
||||
if (!_useTransparency) {
|
||||
return;
|
||||
}
|
||||
const auto factor = style::DevicePixelRatio();
|
||||
if (_paintBuffer.size() != _outerWithBubble.size() * factor) {
|
||||
_paintBuffer = _cachedRound.PrepareImage(_outerWithBubble.size());
|
||||
}
|
||||
_paintBuffer.fill(Qt::transparent);
|
||||
|
||||
_cachedRound.setBackgroundColor(st::defaultPopupMenu.menu.itemBg->c);
|
||||
_cachedRound.setShadowColor(st::shadowFg->c);
|
||||
|
||||
auto p = QPainter(&_paintBuffer);
|
||||
const auto radius = _inner.height() / 2.;
|
||||
const auto frame = _cachedRound.validateFrame(0, 1., radius);
|
||||
|
@ -360,10 +387,14 @@ void Selector::paintBackgroundToBuffer() {
|
|||
void Selector::paintCollapsed(QPainter &p) {
|
||||
Expects(_strip != nullptr);
|
||||
|
||||
if (_paintBuffer.isNull()) {
|
||||
paintBackgroundToBuffer();
|
||||
if (_useTransparency) {
|
||||
if (_paintBuffer.isNull()) {
|
||||
paintBackgroundToBuffer();
|
||||
}
|
||||
p.drawImage(_outer.topLeft(), _paintBuffer);
|
||||
} else {
|
||||
p.fillRect(_inner, st::defaultPopupMenu.menu.itemBg);
|
||||
}
|
||||
p.drawImage(_outer.topLeft(), _paintBuffer);
|
||||
_strip->paint(
|
||||
p,
|
||||
_inner.topLeft() + QPoint(_skipx, _skipy),
|
||||
|
@ -412,10 +443,21 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
|||
(height() - _outer.y() - _outer.height()),
|
||||
expanding);
|
||||
const auto outer = _outer.marginsAdded({ 0, expandUp, 0, expandDown });
|
||||
const auto pattern = _cachedRound.validateFrame(frame, 1., radius);
|
||||
const auto fill = _cachedRound.FillWithImage(p, outer, pattern);
|
||||
if (!fill.isEmpty()) {
|
||||
p.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||
if (_useTransparency) {
|
||||
const auto pattern = _cachedRound.validateFrame(frame, 1., radius);
|
||||
const auto fill = _cachedRound.FillWithImage(p, outer, pattern);
|
||||
if (!fill.isEmpty()) {
|
||||
p.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||
}
|
||||
} else {
|
||||
const auto inner = outer.marginsRemoved(extentsForShadow());
|
||||
p.fillRect(inner, st::defaultPopupMenu.menu.itemBg);
|
||||
p.fillRect(
|
||||
inner.x(),
|
||||
inner.y() + inner.height(),
|
||||
inner.width(),
|
||||
st::lineWidth,
|
||||
st::defaultPopupMenu.shadow.fallback);
|
||||
}
|
||||
const auto categories = anim::interpolate(
|
||||
0,
|
||||
|
@ -423,7 +465,7 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
|||
expanding);
|
||||
const auto inner = outer.marginsRemoved(extents);
|
||||
_shadowTop = inner.y() + categories;
|
||||
_shadowSkip = (categories < radius)
|
||||
_shadowSkip = (_useTransparency && categories < radius)
|
||||
? int(base::SafeRound(
|
||||
radius - sqrt(categories * (2 * radius - categories))))
|
||||
: 0;
|
||||
|
@ -455,22 +497,35 @@ void Selector::paintExpanded(QPainter &p) {
|
|||
if (!_expandFinished) {
|
||||
finishExpand();
|
||||
}
|
||||
p.drawImage(0, 0, _paintBuffer);
|
||||
if (_useTransparency) {
|
||||
p.drawImage(0, 0, _paintBuffer);
|
||||
} else {
|
||||
const auto inner = rect().marginsRemoved(extentsForShadow());
|
||||
p.fillRect(inner, st::defaultPopupMenu.menu.itemBg);
|
||||
p.fillRect(
|
||||
inner.x(),
|
||||
inner.y() + inner.height(),
|
||||
inner.width(),
|
||||
st::lineWidth,
|
||||
st::defaultPopupMenu.shadow.fallback);
|
||||
}
|
||||
}
|
||||
|
||||
void Selector::finishExpand() {
|
||||
Expects(!_expandFinished);
|
||||
|
||||
_expandFinished = true;
|
||||
auto q = QPainter(&_paintBuffer);
|
||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
const auto pattern = _cachedRound.validateFrame(
|
||||
kFramesCount - 1,
|
||||
1.,
|
||||
st::roundRadiusSmall);
|
||||
const auto fill = _cachedRound.FillWithImage(q, rect(), pattern);
|
||||
if (!fill.isEmpty()) {
|
||||
q.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||
if (_useTransparency) {
|
||||
auto q = QPainter(&_paintBuffer);
|
||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
const auto pattern = _cachedRound.validateFrame(
|
||||
kFramesCount - 1,
|
||||
1.,
|
||||
st::roundRadiusSmall);
|
||||
const auto fill = _cachedRound.FillWithImage(q, rect(), pattern);
|
||||
if (!fill.isEmpty()) {
|
||||
q.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||
}
|
||||
}
|
||||
if (_footer) {
|
||||
_footer->show();
|
||||
|
@ -496,7 +551,7 @@ void Selector::paintBubble(QPainter &p, int innerWidth) {
|
|||
|
||||
void Selector::paintEvent(QPaintEvent *e) {
|
||||
auto p = Painter(this);
|
||||
if (_strip && _appearing) {
|
||||
if (_strip && _appearing && _useTransparency) {
|
||||
paintAppearing(p);
|
||||
} else if (_strip && !_expanded) {
|
||||
paintCollapsed(p);
|
||||
|
@ -736,19 +791,19 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
|
|||
inner.width(),
|
||||
_footer->height());
|
||||
_shadowTop = _outer.y();
|
||||
_shadowSkip = (st::reactStripHeight / 2);
|
||||
const auto shadow = Ui::CreateChild<Ui::PlainShadow>(this);
|
||||
_shadowSkip = _useTransparency ? (st::reactStripHeight / 2) : 0;
|
||||
_shadow = Ui::CreateChild<Ui::PlainShadow>(this);
|
||||
rpl::combine(
|
||||
_shadowTop.value(),
|
||||
_shadowSkip.value()
|
||||
) | rpl::start_with_next([=](int top, int skip) {
|
||||
shadow->setGeometry(
|
||||
_shadow->setGeometry(
|
||||
inner.x() + skip,
|
||||
top,
|
||||
inner.width() - 2 * skip,
|
||||
st::lineWidth);
|
||||
}, shadow->lifetime());
|
||||
shadow->show();
|
||||
}, _shadow->lifetime());
|
||||
_shadow->show();
|
||||
}
|
||||
const auto geometry = inner.marginsRemoved(
|
||||
st::reactPanelEmojiPan.margin);
|
||||
|
@ -768,6 +823,7 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
|
|||
_list->scrollToRequests(
|
||||
) | rpl::start_with_next([=](int y) {
|
||||
_scroll->scrollToY(y);
|
||||
_shadow->update();
|
||||
}, _list->lifetime());
|
||||
|
||||
_scroll->setGeometry(inner.marginsRemoved({
|
||||
|
@ -785,13 +841,18 @@ bool AdjustMenuGeometryForSelector(
|
|||
not_null<Ui::PopupMenu*> menu,
|
||||
QPoint desiredPosition,
|
||||
not_null<Selector*> selector) {
|
||||
const auto extend = st::reactStripExtend;
|
||||
const auto useTransparency = selector->useTransparency();
|
||||
const auto extend = useTransparency
|
||||
? st::reactStripExtend
|
||||
: QMargins(0, st::lineWidth + st::reactStripHeight, 0, 0);
|
||||
const auto added = extend.left() + extend.right();
|
||||
const auto desiredWidth = menu->menu()->width() + added;
|
||||
const auto maxWidth = menu->st().menu.widthMax + added;
|
||||
const auto width = selector->countWidth(desiredWidth, maxWidth);
|
||||
const auto extents = selector->extentsForShadow();
|
||||
const auto categoriesTop = selector->extendTopForCategories();
|
||||
const auto categoriesTop = selector->useTransparency()
|
||||
? selector->extendTopForCategories()
|
||||
: 0;
|
||||
menu->setForceWidth(width - added);
|
||||
const auto height = menu->height();
|
||||
const auto fullTop = extents.top() + categoriesTop + extend.top();
|
||||
|
@ -802,7 +863,9 @@ bool AdjustMenuGeometryForSelector(
|
|||
+ height
|
||||
- menu->st().shadow.extend.top();
|
||||
const auto additionalPaddingBottom
|
||||
= (willBeHeightWithoutBottomPadding < minimalHeight
|
||||
= (willBeHeightWithoutBottomPadding >= minimalHeight
|
||||
? 0
|
||||
: useTransparency
|
||||
? (minimalHeight - willBeHeightWithoutBottomPadding)
|
||||
: 0);
|
||||
menu->setAdditionalMenuPadding(QMargins(
|
||||
|
@ -920,8 +983,9 @@ AttachSelectorResult AttachSelectorToMenu(
|
|||
if (!AdjustMenuGeometryForSelector(menu, desiredPosition, selector)) {
|
||||
return AttachSelectorResult::Failed;
|
||||
}
|
||||
const auto selectorInnerTop = menu->preparedPadding().top()
|
||||
- st::reactStripExtend.top();
|
||||
const auto selectorInnerTop = selector->useTransparency()
|
||||
? (menu->preparedPadding().top() - st::reactStripExtend.top())
|
||||
: st::lineWidth;
|
||||
selector->initGeometry(selectorInnerTop);
|
||||
selector->show();
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ class SessionController;
|
|||
namespace Ui {
|
||||
class PopupMenu;
|
||||
class ScrollArea;
|
||||
class PlainShadow;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
|
@ -51,6 +52,8 @@ public:
|
|||
std::vector<DocumentId> recent,
|
||||
Fn<void(bool fast)> close);
|
||||
|
||||
[[nodiscard]] bool useTransparency() const;
|
||||
|
||||
int countWidth(int desiredWidth, int maxWidth);
|
||||
[[nodiscard]] QMargins extentsForShadow() const;
|
||||
[[nodiscard]] int extendTopForCategories() const;
|
||||
|
@ -132,6 +135,7 @@ private:
|
|||
Ui::ScrollArea *_scroll = nullptr;
|
||||
ChatHelpers::EmojiListWidget *_list = nullptr;
|
||||
ChatHelpers::StickersListFooter *_footer = nullptr;
|
||||
Ui::PlainShadow *_shadow = nullptr;
|
||||
rpl::variable<int> _shadowTop = 0;
|
||||
rpl::variable<int> _shadowSkip = 0;
|
||||
|
||||
|
@ -152,6 +156,7 @@ private:
|
|||
int _skipx = 0;
|
||||
int _skipy = 0;
|
||||
int _pressed = -1;
|
||||
bool _useTransparency = false;
|
||||
bool _appearing = false;
|
||||
bool _toggling = false;
|
||||
bool _expanded = false;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 746eb80300f788e1c340f8d5b363a9eac94f7499
|
||||
Subproject commit f420e302d7992e10cae8924701c3a3a85c0aa8b9
|
Loading…
Add table
Reference in a new issue