2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

Support reaction dropdown based on EmojiListWidget.

This commit is contained in:
John Preston
2022-08-22 19:41:23 +03:00
parent f72092a261
commit c5fa4aae62
22 changed files with 529 additions and 160 deletions

View File

@@ -10,6 +10,25 @@ using "ui/basic.style";
using "boxes/boxes.style";
using "ui/widgets/widgets.style";
EmojiPan {
margin: margins;
padding: margins;
desiredSize: pixels;
verticalSizeSub: pixels;
header: pixels;
headerLeft: pixels;
headerLockLeft: pixels;
headerLockedLeft: pixels;
headerTop: pixels;
footer: pixels;
iconSkip: pixels;
iconWidth: pixels;
iconArea: pixels;
overBg: color;
fadeLeft: icon;
fadeRight: icon;
}
switchPmButton: RoundButton(defaultBoxButton) {
width: 320px;
height: 34px;
@@ -147,23 +166,7 @@ emojiObjectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }};
emojiSymbols: icon {{ "emoji/emoji_symbols", emojiIconFg }};
emojiSymbolsActive: icon {{ "emoji/emoji_symbols", emojiSubIconFgActive }};
emojiFooterHeight: 46px;
emojiCategorySkip: 4px;
emojiCategory: IconButton {
width: 42px;
height: emojiFooterHeight;
iconPosition: point(-1px, 6px);
}
emojiCategoryRecent: IconButton(emojiCategory) { icon: emojiRecent; }
emojiCategoryPeople: IconButton(emojiCategory) { icon: emojiPeople; }
emojiCategoryNature: IconButton(emojiCategory) { icon: emojiNature; }
emojiCategoryFood: IconButton(emojiCategory) { icon: emojiFood; }
emojiCategoryActivity: IconButton(emojiCategory) { icon: emojiActivity; }
emojiCategoryTravel: IconButton(emojiCategory) { icon: emojiTravel; }
emojiCategoryObjects: IconButton(emojiCategory) { icon: emojiObjects; }
emojiCategorySymbols: IconButton(emojiCategory) { icon: emojiSymbols; }
emojiCategoryIconTop: 6px;
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
fadeBg: emojiPanBg;
}
@@ -176,21 +179,34 @@ emojiPanShowDuration: 200;
emojiPanDuration: 200;
emojiPanHover: windowBgOver;
emojiPanSlideDuration: 200;
emojiPanDesiredSize: 39px;
emojiPanArea: size(34px, 32px);
emojiPanLeft: 13px;
emojiPanRight: 17px;
emojiPanRadius: 8px;
defaultEmojiPan: EmojiPan {
margin: margins(roundRadiusSmall, 0px, 14px, 0px);
padding: margins(13px, 12px, 17px, 12px);
desiredSize: 39px;
verticalSizeSub: 2px;
header: 40px;
headerLeft: 23px;
headerLockLeft: 17px;
headerLockedLeft: 36px;
headerTop: 12px;
footer: 46px;
iconSkip: 4px;
iconWidth: 35px;
iconArea: 32px;
overBg: emojiPanHover;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", emojiPanCategories }};
fadeRight: icon {{ "fade_horizontal", emojiPanCategories }};
}
inlineResultsMinHeight: 278px;
inlineResultsMaxHeight: 640px;
emojiPanHeader: 40px;
emojiPanHeaderFont: semiboldFont;
emojiPanHeaderLeft: 23px;
emojiPanHeaderLockLeft: 17px;
emojiPanHeaderLockedLeft: 36px;
emojiPanHeaderTop: 12px;
emojiPanRemoveSkip: 10px;
emojiColorsPadding: 5px;
@@ -233,7 +249,6 @@ stickerPanDeleteOpacityFg: 0.8;
stickerPanDeleteOpacityFgOver: 1.;
stickerPanRemoveSet: hashtagClose;
stickerIconWidth: 42px;
stickerIconHeight: emojiFooterHeight;
stickerIconPadding: 5px;
stickerIconOpacity: 0.7;
stickerIconSel: 2px;
@@ -242,9 +257,6 @@ stickerIconMove: 400;
stickerPreviewDuration: 150;
stickerPreviewMin: 0.1;
emojiIconWidth: 35px;
emojiIconArea: 32px;
stickerGroupCategorySize: 28px;
stickerGroupCategoryAbout: defaultTextStyle;
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
@@ -315,9 +327,38 @@ stickersPremiumLock: icon{{ "emoji/premium_lock", premiumButtonFg }};
reactStripExtend: margins(21px, 49px, 39px, 0px);
reactStripHeight: 40px;
reactStripSize: 32px;
reactStripImage: 26px;
reactStripSkip: 7px;
reactStripBubble: icon{
{ "chat/reactions_bubble_shadow", windowShadowFg },
{ "chat/reactions_bubble", windowBg },
};
reactStripBubbleRight: 20px;
reactPanelEmojiPan: EmojiPan(defaultEmojiPan) {
margin: margins(reactStripSkip, 0px, reactStripSkip, 0px);
padding: margins(reactStripSkip, 0px, reactStripSkip, reactStripSkip);
desiredSize: reactStripSize;
verticalSizeSub: 0px;
headerLeft: 13px;
headerLockLeft: 7px;
headerLockedLeft: 26px;
footer: 42px;
iconSkip: 6px;
iconWidth: 33px;
iconArea: 30px;
overBg: transparent;
fadeLeft: icon {{ "fade_horizontal-flip_horizontal", windowBg }};
fadeRight: icon {{ "fade_horizontal", windowBg }};
}
reactPanelScroll: ScrollArea(defaultSolidScroll) {
deltat: 3px;
deltab: 3px;
round: 1px;
width: 7px;
deltax: 2px;
hiding: 0;
}
emojiSuggestionsFadeLeft: icon {{ "fade_horizontal-flip_horizontal", boxBg }};
emojiSuggestionsFadeRight: icon {{ "fade_horizontal", boxBg }};

View File

@@ -46,7 +46,7 @@ using Core::RecentEmojiDocument;
} // namespace
class EmojiColorPicker : public Ui::RpWidget {
class EmojiColorPicker final : public Ui::RpWidget {
public:
EmojiColorPicker(QWidget *parent);
@@ -89,6 +89,7 @@ private:
QSize _singleSize;
QPoint _areaPosition;
QPoint _innerPosition;
Ui::RoundRect _overBg;
bool _hiding = false;
QPixmap _cache;
@@ -110,7 +111,8 @@ struct EmojiListWidget::RecentOne {
};
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
: RpWidget(parent) {
: RpWidget(parent)
, _overBg(st::emojiPanRadius, st::emojiPanHover) {
setMouseTracking(true);
}
@@ -347,11 +349,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
QPoint tl(w);
if (rtl()) tl.setX(width() - tl.x() - st::emojiPanArea.width());
Ui::FillRoundRect(
p,
QRect(tl, st::emojiPanArea),
st::emojiPanHover,
Ui::EmojiHoverCorners);
_overBg.paint(p, QRect(tl, st::emojiPanArea));
}
Ui::Emoji::Draw(
p,
@@ -377,7 +375,11 @@ EmojiListWidget::EmojiListWidget(
EmojiListWidget::EmojiListWidget(
QWidget *parent,
EmojiListDescriptor &&descriptor)
: Inner(parent, descriptor.session, std::move(descriptor.paused))
: Inner(
parent,
descriptor.st ? *descriptor.st : st::defaultEmojiPan,
descriptor.session,
std::move(descriptor.paused))
, _controller(descriptor.controller)
, _mode(descriptor.mode)
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
@@ -386,6 +388,8 @@ EmojiListWidget::EmojiListWidget(
: nullptr)
, _localSetsManager(
std::make_unique<LocalStickersManager>(&session()))
, _customRecentFactory(std::move(descriptor.customRecentFactory))
, _overBg(st::emojiPanRadius, st().overBg)
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
, _picker(this)
, _showPickerTimer([=] { showPicker(); }) {
@@ -433,6 +437,10 @@ EmojiListWidget::EmojiListWidget(
initButton(_unlock, tr::lng_emoji_featured_unlock(tr::now), true);
initButton(_restore, tr::lng_emoji_premium_restore(tr::now), true);
}, lifetime());
if (!descriptor.customRecentList.empty()) {
fillRecentFrom(descriptor.customRecentList);
}
}
EmojiListWidget::~EmojiListWidget() {
@@ -535,6 +543,7 @@ object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
.session = &session(),
.paused = pausedMethod(),
.parent = this,
.st = &st(),
});
_footer = result;
@@ -557,7 +566,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
? kCollapsedRows
: (info.count + _columnCount - 1) / _columnCount;
info.rowsTop = info.top
+ (i == 0 ? st::emojiPanPadding : st::emojiPanHeader);
+ (i == 0 ? st().padding.top() : st().header);
info.rowsBottom = info.rowsTop
+ (info.rowsCount * _singleSize.height())
+ st::roundRadiusSmall;
@@ -637,18 +646,17 @@ void EmojiListWidget::setSingleSize(QSize size) {
}
int EmojiListWidget::countDesiredHeight(int newWidth) {
const auto left = st::emojiPanLeft;
const auto right = st::emojiPanRight;
const auto fullWidth = st::roundRadiusSmall
const auto fullWidth = st().margin.left()
+ newWidth
+ st::emojiScroll.width;
const auto innerWidth = fullWidth - left - right;
_columnCount = std::max(innerWidth / st::emojiPanDesiredSize, 1);
+ st().margin.right();
const auto padding = st().padding;
const auto innerWidth = fullWidth - padding.left() - padding.right();
_columnCount = std::max(innerWidth / st().desiredSize, 1);
const auto singleWidth = innerWidth / _columnCount;
_rowsLeft = left
_rowsLeft = padding.left()
+ (innerWidth - _columnCount * singleWidth) / 2
- st::roundRadiusSmall;
setSingleSize({ singleWidth, singleWidth - 4 * st::lineWidth });
- st().margin.left();
setSingleSize({ singleWidth, singleWidth - 2 * st().verticalSizeSub });
auto visibleHeight = minimalHeight();
auto minimalHeight = (visibleHeight - st::stickerPanPadding);
@@ -659,7 +667,13 @@ int EmojiListWidget::countDesiredHeight(int newWidth) {
};
const auto minimalLastHeight = minimalHeight;
return qMax(minimalHeight, countResult(minimalLastHeight))
+ st::emojiPanPadding;
+ padding.bottom();
}
int EmojiListWidget::defaultMinimalHeight() const {
return (_mode != Mode::Full)
? st::emojiPanArea.height()
: Inner::defaultMinimalHeight();
}
void EmojiListWidget::ensureLoaded(int section) {
@@ -688,6 +702,9 @@ void EmojiListWidget::ensureLoaded(int section) {
}
void EmojiListWidget::fillRecent() {
if (_mode != Mode::Full && _mode != Mode::EmojiStatus) {
return; // #TODO emoji_status
}
_recent.clear();
_recentCustomIds.clear();
@@ -718,6 +735,21 @@ void EmojiListWidget::fillRecent() {
}
}
void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
Expects(_recent.empty());
const auto test = session().isTestMode();
_recent.reserve(list.size());
for (const auto &id : list) {
_recent.push_back({
.custom = resolveCustomEmoji(id),
.id = { RecentEmojiDocument{.id = id, .test = test } },
});
_recentCustomIds.emplace(id);
}
}
void EmojiListWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
@@ -752,7 +784,7 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
? (selectedButton->section == info.section)
: false;
const auto widthForTitle = emojiRight()
- (st::emojiPanHeaderLeft - st::roundRadiusSmall)
- (st().headerLeft - st().margin.left())
- paintButtonGetWidth(p, info, buttonSelected, r);
if (info.section > 0 && r.top() < info.rowsTop) {
p.setFont(st::emojiPanHeaderFont);
@@ -766,13 +798,13 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
titleWidth = st::emojiPanHeaderFont->width(titleText);
}
const auto left = (info.premiumRequired
? st::emojiPanHeaderLockedLeft
: st::emojiPanHeaderLeft) - st::roundRadiusSmall;
const auto top = info.top + st::emojiPanHeaderTop;
? st().headerLockedLeft
: st().headerLeft) - st().margin.left();
const auto top = info.top + st().headerTop;
if (info.premiumRequired) {
st::emojiPremiumRequired.paint(
p,
st::emojiPanHeaderLockLeft - st::roundRadiusSmall,
st().headerLockLeft - st().margin.left(),
top,
width());
}
@@ -807,16 +839,12 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
drawCollapsedBadge(p, w - _areaPosition, info.count);
continue;
}
if (selected) {
if (selected && st().overBg->c.alpha() > 0) {
auto tl = w;
if (rtl()) {
tl.setX(width() - tl.x() - st::emojiPanArea.width());
}
Ui::FillRoundRect(
p,
QRect(tl, st::emojiPanArea),
st::emojiPanHover,
Ui::EmojiHoverCorners);
_overBg.paint(p, QRect(tl, st::emojiPanArea));
}
if (info.section == int(Section::Recent)) {
drawRecent(p, w, now, paused, index);
@@ -1070,10 +1098,13 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
_premiumChosen.fire_copy(document);
return;
}
Core::App().settings().incrementRecentEmoji({ RecentEmojiDocument{
document->id,
document->session().isTestMode(),
} });
auto &settings = Core::App().settings();
if (_mode == Mode::Full) {
settings.incrementRecentEmoji({ RecentEmojiDocument{
document->id,
document->session().isTestMode(),
} });
}
_customChosen.fire({ .document = document });
}
@@ -1089,7 +1120,7 @@ void EmojiListWidget::showPicker() {
auto y = emojiRect(over->section, over->index).y();
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
if (y < st::emojiPanHeader) {
if (y < st().header) {
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
}
auto xmax = width() - _picker->width();
@@ -1124,11 +1155,14 @@ QRect EmojiListWidget::removeButtonRect(int index) const {
}
QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const {
if (_mode != Mode::Full) {
return QRect();
}
const auto buttonw = st::stickerPanRemoveSet.rippleAreaPosition.x()
+ st::stickerPanRemoveSet.rippleAreaSize;
const auto buttonh = st::stickerPanRemoveSet.height;
const auto buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw;
const auto buttony = info.top + (st::emojiPanHeader - buttonh) / 2;
const auto buttony = info.top + (st().header - buttonh) / 2;
return QRect(buttonx, buttony, buttonw, buttonh);
}
@@ -1322,12 +1356,18 @@ void EmojiListWidget::processPanelHideFinished() {
}
void EmojiListWidget::refreshRecent() {
if (_mode != Mode::Full && _mode != Mode::EmojiStatus) {
return; // #TODO emoji_status
}
clearSelection();
fillRecent();
resizeToWidth(width());
}
void EmojiListWidget::refreshCustom() {
if (_mode == Mode::RecentReactions) {
return;
}
auto old = base::take(_custom);
const auto session = &this->session();
const auto premiumPossible = session->premiumPossible();
@@ -1486,15 +1526,19 @@ not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
if (i != end(_customEmoji)) {
return i->second.emoji.get();
}
auto repaint = repaintCallback(documentId, RecentEmojiSectionSetId());
auto custom = _customRecentFactory
? _customRecentFactory(documentId, repaint)
: nullptr;
if (!custom) {
custom = session().data().customEmojiManager().create(
documentId,
std::move(repaint),
Data::CustomEmojiManager::SizeTag::Large);
}
return _customEmoji.emplace(
documentId,
CustomEmojiInstance{
.emoji = session().data().customEmojiManager().create(
documentId,
repaintCallback(documentId, RecentEmojiSectionSetId()),
Data::CustomEmojiManager::SizeTag::Large),
.recentOnly = true,
}
CustomEmojiInstance{ .emoji = std::move(custom), .recentOnly = true }
).first->second.emoji.get();
}
@@ -1503,7 +1547,7 @@ std::vector<StickerIcon> EmojiListWidget::fillIcons() {
result.reserve(2 + _custom.size());
result.emplace_back(RecentEmojiSectionSetId());
if (_mode == Mode::EmojiStatus) {
if (_mode != Mode::Full) {
} else if (_custom.empty()) {
using Section = Ui::Emoji::Section;
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
@@ -1534,7 +1578,9 @@ int EmojiListWidget::paintButtonGetWidth(
auto &custom = _custom[info.section - _staticCount];
if (hasRemoveButton(info.section)) {
const auto remove = removeButtonRect(info);
if (remove.intersects(clip)) {
if (remove.isEmpty()) {
return 0;
} else if (remove.intersects(clip)) {
if (custom.ripple) {
custom.ripple->paint(
p,
@@ -1603,7 +1649,7 @@ void EmojiListWidget::updateSelected() {
if (hasButton(section)
&& myrtlrect(buttonRect(section)).contains(p.x(), p.y())) {
newSelected = OverButton{ section };
} else if (section >= _staticCount) {
} else if (section >= _staticCount && _mode == Mode::Full) {
newSelected = OverSet{ section };
}
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {

View File

@@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/round_rect.h"
#include "base/timer.h"
namespace style {
struct EmojiPan;
} // namespace style
namespace Core {
struct RecentEmojiId;
} // namespace Core
@@ -56,7 +60,8 @@ class LocalStickersManager;
enum class EmojiListMode {
Full,
EmojiStatus,
Reactions,
FullReactions,
RecentReactions,
};
struct EmojiListDescriptor {
@@ -64,6 +69,11 @@ struct EmojiListDescriptor {
EmojiListMode mode = EmojiListMode::Full;
Window::SessionController *controller = nullptr;
Fn<bool()> paused;
std::vector<DocumentId> customRecentList;
Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
DocumentId,
Fn<void()>)> customRecentFactory;
const style::EmojiPan *st = nullptr;
};
class EmojiListWidget
@@ -120,6 +130,7 @@ protected:
void processHideFinished() override;
void processPanelHideFinished() override;
int countDesiredHeight(int newWidth) override;
int defaultMinimalHeight() const override;
private:
struct SectionInfo {
@@ -272,6 +283,7 @@ private:
void repaintCustom(uint64 setId);
void fillRecent();
void fillRecentFrom(const std::vector<DocumentId> &list);
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
not_null<DocumentData*> document,
uint64 setId);
@@ -289,6 +301,9 @@ private:
StickersListFooter *_footer = nullptr;
std::unique_ptr<GradientPremiumStar> _premiumIcon;
std::unique_ptr<LocalStickersManager> _localSetsManager;
Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
DocumentId,
Fn<void()>)> _customRecentFactory;
int _counts[kEmojiSectionCount];
std::vector<RecentOne> _recent;
@@ -299,6 +314,7 @@ private:
std::vector<CustomSet> _custom;
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
bool _allowWithoutPremium = false;
Ui::RoundRect _overBg;
int _rowsLeft = 0;
int _columnCount = 1;

View File

@@ -105,7 +105,8 @@ private:
};
GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(parent)
GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent)
: InnerFooter(parent, st::defaultEmojiPan)
, _pan(parent)
, _field(this, st::gifsSearchField, tr::lng_gifs_search())
, _cancel(this, st::gifsSearchCancel) {
@@ -170,7 +171,11 @@ GifsListWidget::GifsListWidget(
QWidget *parent,
not_null<Window::SessionController*> controller,
Window::GifPauseReason level)
: Inner(parent, &controller->session(), Window::PausedIn(controller, level))
: Inner(
parent,
st::defaultEmojiPan,
&controller->session(),
Window::PausedIn(controller, level))
, _controller(controller)
, _api(&session().mtp())
, _section(Section::Gifs)

View File

@@ -181,7 +181,9 @@ void GradientPremiumStar::renderOnDemand() const {
}
StickersListFooter::StickersListFooter(Descriptor &&descriptor)
: InnerFooter(descriptor.parent)
: InnerFooter(
descriptor.parent,
descriptor.st ? *descriptor.st : st::defaultEmojiPan)
, _session(descriptor.session)
, _paused(descriptor.paused)
, _searchButtonVisible(descriptor.searchButtonVisible)
@@ -189,14 +191,14 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
, _iconState([=] { update(); })
, _subiconState([=] { update(); })
, _selectionBg(st::roundRadiusLarge, st::windowBgRipple)
, _subselectionBg(st::emojiIconArea / 2, st::windowBgRipple)
, _subselectionBg(st().iconArea / 2, st::windowBgRipple)
, _barSelection(descriptor.barSelection) {
setMouseTracking(true);
_iconsLeft = st::emojiCategorySkip + (_searchButtonVisible
_iconsLeft = st().iconSkip + (_searchButtonVisible
? st::stickerIconWidth
: 0);
_iconsRight = st::emojiCategorySkip + (_settingsButtonVisible
_iconsRight = st().iconSkip + (_settingsButtonVisible
? st::stickerIconWidth
: 0);
@@ -552,7 +554,7 @@ void StickersListFooter::paintEvent(QPaintEvent *e) {
_iconsLeft,
_iconsTop,
width() - _iconsLeft - _iconsRight,
st::emojiFooterHeight);
st().footer);
if (rtl()) {
clip.moveLeft(width() - _iconsLeft - clip.width());
}
@@ -582,7 +584,7 @@ void StickersListFooter::paintSelectionBg(Painter &p) const {
selx = width() - selx - selw;
}
const auto sely = _iconsTop;
const auto area = st::emojiIconArea;
const auto area = st().iconArea;
const auto rect = QRect(
QPoint(selx, sely) + _areaPosition,
QSize(selw - 2 * _areaPosition.x(), area));
@@ -613,7 +615,7 @@ void StickersListFooter::paintSelectionBar(Painter &p) const {
}
p.fillRect(
selx,
_iconsTop + st::emojiFooterHeight - st::stickerIconPadding,
_iconsTop + st().footer - st::stickerIconPadding,
selw,
st::stickerIconSel,
st::stickerIconSelColor);
@@ -621,27 +623,27 @@ void StickersListFooter::paintSelectionBar(Painter &p) const {
void StickersListFooter::paintLeftRightFading(Painter &p) const {
auto o_left = std::clamp(
_iconState.x.current() / st::stickerIconLeft.width(),
_iconState.x.current() / st().fadeLeft.width(),
0.,
1.);
if (o_left > 0) {
p.setOpacity(o_left);
st::stickerIconLeft.fill(p, style::rtlrect(_iconsLeft, _iconsTop, st::stickerIconLeft.width(), st::emojiFooterHeight, width()));
st().fadeLeft.fill(p, style::rtlrect(_iconsLeft, _iconsTop, st().fadeLeft.width(), st().footer, width()));
p.setOpacity(1.);
}
auto o_right = std::clamp(
(_iconState.max - _iconState.x.current()) / st::stickerIconRight.width(),
(_iconState.max - _iconState.x.current()) / st().fadeRight.width(),
0.,
1.);
if (o_right > 0) {
p.setOpacity(o_right);
st::stickerIconRight.fill(
st().fadeRight.fill(
p,
style::rtlrect(
width() - _iconsRight - st::stickerIconRight.width(),
width() - _iconsRight - st().fadeRight.width(),
_iconsTop,
st::stickerIconRight.width(),
st::emojiFooterHeight, width()));
st().fadeRight.width(),
st().footer, width()));
p.setOpacity(1.);
}
}
@@ -880,19 +882,19 @@ void StickersListFooter::updateSelected() {
&& x >= searchLeft
&& x < searchLeft + _singleWidth
&& y >= _iconsTop
&& y < _iconsTop + st::emojiFooterHeight) {
&& y < _iconsTop + st().footer) {
newOver = SpecialOver::Search;
} else if (_settingsButtonVisible
&& x >= settingsLeft
&& x < settingsLeft + _singleWidth
&& y >= _iconsTop
&& y < _iconsTop + st::emojiFooterHeight) {
&& y < _iconsTop + st().footer) {
if (!_icons.empty() && !hasOnlyFeaturedSets()) {
newOver = SpecialOver::Settings;
}
} else if (!_icons.empty()) {
if (y >= _iconsTop
&& y < _iconsTop + st::emojiFooterHeight
&& y < _iconsTop + st().footer
&& x >= _iconsLeft
&& x < width() - _iconsRight) {
enumerateIcons([&](const IconInfo &info) {
@@ -994,11 +996,11 @@ void StickersListFooter::refreshIconsGeometry(
&& _icons[1].setId == EmojiSectionSetId(EmojiSection::People)) {
_singleWidth = (width() - _iconsLeft - _iconsRight) / _icons.size();
} else {
_singleWidth = st::emojiIconWidth;
_singleWidth = st().iconWidth;
}
_areaPosition = QPoint(
(_singleWidth - st::emojiIconArea) / 2,
(st::emojiFooterHeight - st::emojiIconArea) / 2);
(_singleWidth - st().iconArea) / 2,
(st().footer - st().iconArea) / 2);
refreshScrollableDimensions();
refreshSubiconsGeometry();
_iconState.selected = _subiconState.selected = -1;
@@ -1047,7 +1049,7 @@ void StickersListFooter::paintStickerSettingsIcon(Painter &p) const {
p,
settingsLeft
+ (_singleWidth - st::stickersSettings.width()) / 2,
_iconsTop + st::emojiCategory.iconPosition.y(),
_iconsTop + st::emojiCategoryIconTop,
width());
}
@@ -1056,7 +1058,7 @@ void StickersListFooter::paintSearchIcon(Painter &p) const {
st::stickersSearch.paint(
p,
searchLeft + (_singleWidth - st::stickersSearch.width()) / 2,
_iconsTop + st::emojiCategory.iconPosition.y(),
_iconsTop + st::emojiCategoryIconTop,
width());
}
@@ -1145,7 +1147,7 @@ void StickersListFooter::updateSetIcon(uint64 setId) {
}
void StickersListFooter::updateSetIconAt(int left) {
update(left, _iconsTop, _singleWidth, st::emojiFooterHeight);
update(left, _iconsTop, _singleWidth, st().footer);
}
void StickersListFooter::paintSetIcon(
@@ -1164,7 +1166,7 @@ void StickersListFooter::paintSetIcon(
? icon.stickerMedia->thumbnail()
: nullptr;
const auto x = info.adjustedLeft + (_singleWidth - icon.pixw) / 2;
const auto y = _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2;
const auto y = _iconsTop + (st().footer - icon.pixh) / 2;
if (icon.custom) {
icon.custom->paint(p, x, y, now, st::emojiIconFg->c, paused);
} else if (icon.lottie && icon.lottie->ready()) {
@@ -1177,7 +1179,7 @@ void StickersListFooter::paintSetIcon(
p.drawImage(
QRect(
(info.adjustedLeft + (_singleWidth - size.width()) / 2),
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
_iconsTop + (st().footer - size.height()) / 2,
size.width(),
size.height()),
frame);
@@ -1212,14 +1214,14 @@ void StickersListFooter::paintSetIcon(
p,
icon.megagroupUserpic,
info.adjustedLeft + (_singleWidth - size) / 2,
_iconsTop + (st::emojiFooterHeight - size) / 2,
_iconsTop + (st().footer - size) / 2,
width(),
st::stickerGroupCategorySize);
} else if (icon.setId == Data::Stickers::PremiumSetId) {
const auto size = st::stickersPremium.size();
p.drawImage(
info.adjustedLeft + (_singleWidth - size.width()) / 2,
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
_iconsTop + (st().footer - size.height()) / 2,
_premiumIcon.image());
} else {
using Section = Ui::Emoji::Section;
@@ -1252,7 +1254,7 @@ void StickersListFooter::paintSetIcon(
icon->paint(
p,
left + (_singleWidth - icon->width()) / 2,
_iconsTop + (st::emojiFooterHeight - icon->height()) / 2,
_iconsTop + (st().footer - icon->height()) / 2,
width());
};
if (_icons[info.index].setId == AllEmojiSectionSetId()
@@ -1263,7 +1265,7 @@ void StickersListFooter::paintSetIcon(
left + skip,
_iconsTop,
info.width - 2 * skip,
st::emojiFooterHeight,
st().footer,
Qt::IntersectClip);
enumerateSubicons([&](const IconInfo &info) {
if (info.visible) {

View File

@@ -33,6 +33,10 @@ namespace Window {
class SessionController;
} // namespace Window
namespace style {
struct EmojiPan;
} // namespace style
namespace ChatHelpers {
enum class ValidateIconAnimations {
@@ -98,6 +102,7 @@ public:
bool searchButtonVisible = false;
bool settingsButtonVisible = false;
bool barSelection = false;
const style::EmojiPan *st = nullptr;
};
explicit StickersListFooter(Descriptor &&descriptor);

View File

@@ -164,7 +164,11 @@ StickersListWidget::StickersListWidget(
not_null<Window::SessionController*> controller,
Window::GifPauseReason level,
bool masks)
: Inner(parent, &controller->session(), Window::PausedIn(controller, level))
: Inner(
parent,
st::defaultEmojiPan,
&controller->session(),
Window::PausedIn(controller, level))
, _controller(controller)
, _api(&session().mtp())
, _localSetsManager(std::make_unique<LocalStickersManager>(&session()))
@@ -176,7 +180,7 @@ StickersListWidget::StickersListWidget(
st::windowBgRipple,
st::windowBgOver,
[=] { update(); }))
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st::emojiPanHeaderLeft)
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st().headerLeft)
, _addText(tr::lng_stickers_featured_add(tr::now).toUpper())
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _settings(this, tr::lng_stickers_you_have(tr::now))
@@ -411,7 +415,7 @@ bool StickersListWidget::enumerateSections(Callback callback) const {
const auto titleSkip = set.externalLayout
? st::stickersTrendingHeader
: setHasTitle(set)
? st::emojiPanHeader
? st().header
: st::stickerPanPadding;
info.rowsTop = info.top + titleSkip;
if (set.externalLayout) {
@@ -462,16 +466,16 @@ int StickersListWidget::countDesiredHeight(int newWidth) {
if (newWidth <= st::stickerPanWidthMin) {
return 0;
}
auto availableWidth = newWidth - (st::stickerPanPadding - st::roundRadiusSmall);
auto availableWidth = newWidth - (st::stickerPanPadding - st().margin.left());
auto columnCount = availableWidth / st::stickerPanWidthMin;
auto singleWidth = availableWidth / columnCount;
auto fullWidth = (st::roundRadiusSmall + newWidth + st::emojiScroll.width);
auto fullWidth = (st().margin.left() + newWidth + st::emojiScroll.width);
auto rowsRight = (fullWidth - columnCount * singleWidth) / 2;
accumulate_max(rowsRight, st::emojiScroll.width);
_rowsLeft = fullWidth
- columnCount * singleWidth
- rowsRight
- st::roundRadiusSmall;
- st().margin.left();
_singleSize = QSize(singleWidth, singleWidth);
setColumnCount(columnCount);
@@ -831,7 +835,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
? set.count
: loadedCount;
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
auto widthForTitle = stickersRight() - (st().headerLeft - st().margin.left());
if (featuredHasAddButton(info.section)) {
auto add = featuredAddRect(info);
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
@@ -867,7 +871,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
}
p.setFont(st::stickersTrendingHeaderFont);
p.setPen(st::stickersTrendingHeaderFg);
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, info.top + st::stickersTrendingHeaderTop, width(), titleText, titleWidth);
p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingHeaderTop, width(), titleText, titleWidth);
if (set.flags & SetFlag::Unread) {
p.setPen(Qt::NoPen);
@@ -875,14 +879,14 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
{
PainterHighQualityEnabler hq(p);
p.drawEllipse(style::rtlrect(st::emojiPanHeaderLeft - st::roundRadiusSmall + titleWidth + st::stickersFeaturedUnreadSkip, info.top + st::stickersTrendingHeaderTop + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
p.drawEllipse(style::rtlrect(st().headerLeft - st().margin.left() + titleWidth + st::stickersFeaturedUnreadSkip, info.top + st::stickersTrendingHeaderTop + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
}
}
auto statusText = (count > 0) ? tr::lng_stickers_count(tr::now, lt_count, count) : tr::lng_contacts_loading(tr::now);
p.setFont(st::stickersTrendingSubheaderFont);
p.setPen(st::stickersTrendingSubheaderFg);
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, info.top + st::stickersTrendingSubheaderTop, width(), statusText);
p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st::stickersTrendingSubheaderTop, width(), statusText);
if (info.rowsTop >= clip.y() + clip.height()) {
return true;
@@ -904,7 +908,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
if (setHasTitle(set) && clip.top() < info.rowsTop) {
auto titleText = set.title;
auto titleWidth = st::stickersTrendingHeaderFont->width(titleText);
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
auto widthForTitle = stickersRight() - (st().headerLeft - st().margin.left());
if (hasRemoveButton(info.section)) {
auto remove = removeButtonRect(info);
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
@@ -924,7 +928,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
}
p.setFont(st::emojiPanHeaderFont);
p.setPen(st::emojiPanHeaderFg);
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, info.top + st::emojiPanHeaderTop, width(), titleText, titleWidth);
p.drawTextLeft(st().headerLeft - st().margin.left(), info.top + st().headerTop, width(), titleText, titleWidth);
}
if (clip.top() + clip.height() <= info.rowsTop) {
return true;
@@ -1054,7 +1058,7 @@ void StickersListWidget::paintEmptySearchResults(Painter &p) {
}
int StickersListWidget::megagroupSetInfoLeft() const {
return st::emojiPanHeaderLeft - st::roundRadiusSmall;
return st().headerLeft - st().margin.left();
}
void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) {
@@ -1440,7 +1444,7 @@ QRect StickersListWidget::removeButtonRect(const SectionInfo &info) const {
auto buttonw = st::stickerPanRemoveSet.width;
auto buttonh = st::stickerPanRemoveSet.height;
auto buttonx = stickersRight() - buttonw;
auto buttony = info.top + (st::emojiPanHeader - buttonh) / 2;
auto buttony = info.top + (st().header - buttonh) / 2;
return QRect(buttonx, buttony, buttonw, buttonh);
}
@@ -2322,7 +2326,7 @@ std::vector<StickerIcon> StickersListWidget::fillIcons() {
Assert(set != nullptr);
const auto s = _mySets[i].thumbnailDocument;
const auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding;
const auto availh = st::emojiFooterHeight - 2 * st::stickerIconPadding;
const auto availh = st().footer - 2 * st::stickerIconPadding;
const auto size = set->hasThumbnail()
? QSize(
set->thumbnailLocation().width(),

View File

@@ -46,6 +46,10 @@ class ReaderPointer;
enum class Notification;
} // namespace Media::Clip
namespace style {
struct EmojiPan;
} // namespace style
namespace ChatHelpers {
struct StickerIcon;
@@ -320,8 +324,6 @@ private:
void addSearchRow(not_null<Data::StickersSet*> set);
void showPreview();
void validatePremiumLock(Set &set, int index, const QImage &frame);
void validatePremiumStar();
Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
int section,

View File

@@ -107,7 +107,7 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage
_painterInnerBottom = _innerBottom / cIntRetinaFactor();
_painterInnerWidth = _innerWidth / cIntRetinaFactor();
_painterInnerHeight = _innerHeight / cIntRetinaFactor();
_painterCategoriesTop = _painterInnerBottom - st::emojiFooterHeight;
_painterCategoriesTop = _painterInnerBottom - st::defaultEmojiPan.footer;
_wasSectionIcons = wasSectionIcons;
}
@@ -294,6 +294,7 @@ TabbedSelector::TabbedSelector(
Window::GifPauseReason level,
Mode mode)
: RpWidget(parent)
, _st(st::defaultEmojiPan)
, _controller(controller)
, _level(level)
, _mode(mode)
@@ -605,7 +606,7 @@ void TabbedSelector::updateScrollGeometry(QSize oldSize) {
}
void TabbedSelector::updateFooterGeometry() {
_footerTop = _dropDown ? 0 : (height() - st::emojiFooterHeight);
_footerTop = _dropDown ? 0 : (height() - _st.footer);
for (auto &tab : _tabs) {
tab.footer()->resizeToWidth(width());
tab.footer()->moveToLeft(0, _footerTop);
@@ -684,7 +685,7 @@ void TabbedSelector::paintContent(Painter &p) {
0,
_footerTop - (_dropDown ? 0 : _roundRadius),
width(),
st::emojiFooterHeight + _roundRadius);
_st.footer + _roundRadius);
Ui::FillRoundRect(
p,
footerPart,
@@ -696,7 +697,7 @@ void TabbedSelector::paintContent(Painter &p) {
if (_tabsSlider) {
p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg);
}
p.fillRect(0, _footerTop, width(), st::emojiFooterHeight, footerBg);
p.fillRect(0, _footerTop, width(), _st.footer, footerBg);
}
auto sidesTop = marginTop();
@@ -719,18 +720,18 @@ void TabbedSelector::paintContent(Painter &p) {
int TabbedSelector::marginTop() const {
return _dropDown
? st::emojiFooterHeight
? _st.footer
: _tabsSlider
? (_tabsSlider->height() - st::lineWidth)
: _roundRadius;
}
int TabbedSelector::scrollTop() const {
return tabbed() ? marginTop() : _dropDown ? st::emojiFooterHeight : 0;
return tabbed() ? marginTop() : _dropDown ? _st.footer : 0;
}
int TabbedSelector::marginBottom() const {
return _dropDown ? _roundRadius : st::emojiFooterHeight;
return _dropDown ? _roundRadius : _st.footer;
}
int TabbedSelector::scrollBottom() const {
@@ -1200,15 +1201,18 @@ TabbedSelector::Inner::Inner(
Window::GifPauseReason level)
: Inner(
parent,
st::defaultEmojiPan,
&controller->session(),
Window::PausedIn(controller, level)) {
}
TabbedSelector::Inner::Inner(
QWidget *parent,
const style::EmojiPan &st,
not_null<Main::Session*> session,
Fn<bool()> paused)
: RpWidget(parent)
, _st(st)
, _session(session)
, _paused(paused) {
}
@@ -1271,7 +1275,11 @@ int TabbedSelector::Inner::resizeGetHeight(int newWidth) {
int TabbedSelector::Inner::minimalHeight() const {
return (_minimalHeight > 0)
? _minimalHeight
: (st::emojiPanMaxHeight - st::emojiFooterHeight);
: defaultMinimalHeight();
}
int TabbedSelector::Inner::defaultMinimalHeight() const {
return st::emojiPanMaxHeight - _st.footer;
}
void TabbedSelector::Inner::hideFinished() {
@@ -1289,9 +1297,16 @@ void TabbedSelector::Inner::panelHideFinished() {
}
}
TabbedSelector::InnerFooter::InnerFooter(QWidget *parent)
: RpWidget(parent) {
resize(st::emojiPanWidth, st::emojiFooterHeight);
TabbedSelector::InnerFooter::InnerFooter(
QWidget *parent,
const style::EmojiPan &st)
: RpWidget(parent)
, _st(st) {
resize(st::emojiPanWidth, _st.footer);
}
const style::EmojiPan &TabbedSelector::InnerFooter::st() const {
return _st;
}
} // namespace ChatHelpers

View File

@@ -41,6 +41,10 @@ namespace SendMenu {
enum class Type;
} // namespace SendMenu
namespace style {
struct EmojiPan;
} // namespace style
namespace ChatHelpers {
enum class SelectorTab {
@@ -233,6 +237,7 @@ private:
not_null<GifsListWidget*> gifs() const;
not_null<StickersListWidget*> masks() const;
const style::EmojiPan &_st;
const not_null<Window::SessionController*> _controller;
const Window::GifPauseReason _level = {};
@@ -278,12 +283,16 @@ public:
Window::GifPauseReason level);
Inner(
QWidget *parent,
const style::EmojiPan &st,
not_null<Main::Session*> session,
Fn<bool()> paused);
[[nodiscard]] Main::Session &session() const {
return *_session;
}
[[nodiscard]] const style::EmojiPan &st() const {
return _st;
}
[[nodiscard]] Fn<bool()> pausedMethod() const {
return _paused;
}
@@ -332,6 +341,7 @@ protected:
int visibleTop,
int visibleBottom) override;
int minimalHeight() const;
virtual int defaultMinimalHeight() const;
int resizeGetHeight(int newWidth) override final;
virtual int countDesiredHeight(int newWidth) = 0;
@@ -347,6 +357,7 @@ protected:
void checkHideWithBox(QPointer<Ui::BoxContent> box);
private:
const style::EmojiPan &_st;
const not_null<Main::Session*> _session;
const Fn<bool()> _paused;
@@ -364,7 +375,9 @@ private:
class TabbedSelector::InnerFooter : public Ui::RpWidget {
public:
InnerFooter(QWidget *parent);
InnerFooter(QWidget *parent, const style::EmojiPan &st);
[[nodiscard]] const style::EmojiPan &st() const;
protected:
virtual void processHideFinished() {
@@ -373,6 +386,9 @@ protected:
}
friend class Inner;
private:
const style::EmojiPan &_st;
};
} // namespace ChatHelpers