mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support reaction dropdown based on EmojiListWidget.
This commit is contained in:
parent
f72092a261
commit
c5fa4aae62
22 changed files with 529 additions and 160 deletions
|
@ -10,6 +10,25 @@ using "ui/basic.style";
|
||||||
using "boxes/boxes.style";
|
using "boxes/boxes.style";
|
||||||
using "ui/widgets/widgets.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) {
|
switchPmButton: RoundButton(defaultBoxButton) {
|
||||||
width: 320px;
|
width: 320px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
|
@ -147,23 +166,7 @@ emojiObjectsActive: icon {{ "emoji/emoji_objects", emojiSubIconFgActive }};
|
||||||
emojiSymbols: icon {{ "emoji/emoji_symbols", emojiIconFg }};
|
emojiSymbols: icon {{ "emoji/emoji_symbols", emojiIconFg }};
|
||||||
emojiSymbolsActive: icon {{ "emoji/emoji_symbols", emojiSubIconFgActive }};
|
emojiSymbolsActive: icon {{ "emoji/emoji_symbols", emojiSubIconFgActive }};
|
||||||
|
|
||||||
emojiFooterHeight: 46px;
|
emojiCategoryIconTop: 6px;
|
||||||
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; }
|
|
||||||
|
|
||||||
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
|
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
|
||||||
fadeBg: emojiPanBg;
|
fadeBg: emojiPanBg;
|
||||||
}
|
}
|
||||||
|
@ -176,21 +179,34 @@ emojiPanShowDuration: 200;
|
||||||
emojiPanDuration: 200;
|
emojiPanDuration: 200;
|
||||||
emojiPanHover: windowBgOver;
|
emojiPanHover: windowBgOver;
|
||||||
emojiPanSlideDuration: 200;
|
emojiPanSlideDuration: 200;
|
||||||
emojiPanDesiredSize: 39px;
|
|
||||||
emojiPanArea: size(34px, 32px);
|
emojiPanArea: size(34px, 32px);
|
||||||
emojiPanLeft: 13px;
|
emojiPanLeft: 13px;
|
||||||
emojiPanRight: 17px;
|
emojiPanRight: 17px;
|
||||||
emojiPanRadius: 8px;
|
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;
|
inlineResultsMinHeight: 278px;
|
||||||
inlineResultsMaxHeight: 640px;
|
inlineResultsMaxHeight: 640px;
|
||||||
|
|
||||||
emojiPanHeader: 40px;
|
|
||||||
emojiPanHeaderFont: semiboldFont;
|
emojiPanHeaderFont: semiboldFont;
|
||||||
emojiPanHeaderLeft: 23px;
|
|
||||||
emojiPanHeaderLockLeft: 17px;
|
|
||||||
emojiPanHeaderLockedLeft: 36px;
|
|
||||||
emojiPanHeaderTop: 12px;
|
|
||||||
emojiPanRemoveSkip: 10px;
|
emojiPanRemoveSkip: 10px;
|
||||||
|
|
||||||
emojiColorsPadding: 5px;
|
emojiColorsPadding: 5px;
|
||||||
|
@ -233,7 +249,6 @@ stickerPanDeleteOpacityFg: 0.8;
|
||||||
stickerPanDeleteOpacityFgOver: 1.;
|
stickerPanDeleteOpacityFgOver: 1.;
|
||||||
stickerPanRemoveSet: hashtagClose;
|
stickerPanRemoveSet: hashtagClose;
|
||||||
stickerIconWidth: 42px;
|
stickerIconWidth: 42px;
|
||||||
stickerIconHeight: emojiFooterHeight;
|
|
||||||
stickerIconPadding: 5px;
|
stickerIconPadding: 5px;
|
||||||
stickerIconOpacity: 0.7;
|
stickerIconOpacity: 0.7;
|
||||||
stickerIconSel: 2px;
|
stickerIconSel: 2px;
|
||||||
|
@ -242,9 +257,6 @@ stickerIconMove: 400;
|
||||||
stickerPreviewDuration: 150;
|
stickerPreviewDuration: 150;
|
||||||
stickerPreviewMin: 0.1;
|
stickerPreviewMin: 0.1;
|
||||||
|
|
||||||
emojiIconWidth: 35px;
|
|
||||||
emojiIconArea: 32px;
|
|
||||||
|
|
||||||
stickerGroupCategorySize: 28px;
|
stickerGroupCategorySize: 28px;
|
||||||
stickerGroupCategoryAbout: defaultTextStyle;
|
stickerGroupCategoryAbout: defaultTextStyle;
|
||||||
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
|
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
|
||||||
|
@ -315,9 +327,38 @@ stickersPremiumLock: icon{{ "emoji/premium_lock", premiumButtonFg }};
|
||||||
reactStripExtend: margins(21px, 49px, 39px, 0px);
|
reactStripExtend: margins(21px, 49px, 39px, 0px);
|
||||||
reactStripHeight: 40px;
|
reactStripHeight: 40px;
|
||||||
reactStripSize: 32px;
|
reactStripSize: 32px;
|
||||||
|
reactStripImage: 26px;
|
||||||
reactStripSkip: 7px;
|
reactStripSkip: 7px;
|
||||||
reactStripBubble: icon{
|
reactStripBubble: icon{
|
||||||
{ "chat/reactions_bubble_shadow", windowShadowFg },
|
{ "chat/reactions_bubble_shadow", windowShadowFg },
|
||||||
{ "chat/reactions_bubble", windowBg },
|
{ "chat/reactions_bubble", windowBg },
|
||||||
};
|
};
|
||||||
reactStripBubbleRight: 20px;
|
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 }};
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ using Core::RecentEmojiDocument;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class EmojiColorPicker : public Ui::RpWidget {
|
class EmojiColorPicker final : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
EmojiColorPicker(QWidget *parent);
|
EmojiColorPicker(QWidget *parent);
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ private:
|
||||||
QSize _singleSize;
|
QSize _singleSize;
|
||||||
QPoint _areaPosition;
|
QPoint _areaPosition;
|
||||||
QPoint _innerPosition;
|
QPoint _innerPosition;
|
||||||
|
Ui::RoundRect _overBg;
|
||||||
|
|
||||||
bool _hiding = false;
|
bool _hiding = false;
|
||||||
QPixmap _cache;
|
QPixmap _cache;
|
||||||
|
@ -110,7 +111,8 @@ struct EmojiListWidget::RecentOne {
|
||||||
};
|
};
|
||||||
|
|
||||||
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
||||||
: RpWidget(parent) {
|
: RpWidget(parent)
|
||||||
|
, _overBg(st::emojiPanRadius, st::emojiPanHover) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,11 +349,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
|
||||||
QPoint tl(w);
|
QPoint tl(w);
|
||||||
if (rtl()) tl.setX(width() - tl.x() - st::emojiPanArea.width());
|
if (rtl()) tl.setX(width() - tl.x() - st::emojiPanArea.width());
|
||||||
|
|
||||||
Ui::FillRoundRect(
|
_overBg.paint(p, QRect(tl, st::emojiPanArea));
|
||||||
p,
|
|
||||||
QRect(tl, st::emojiPanArea),
|
|
||||||
st::emojiPanHover,
|
|
||||||
Ui::EmojiHoverCorners);
|
|
||||||
}
|
}
|
||||||
Ui::Emoji::Draw(
|
Ui::Emoji::Draw(
|
||||||
p,
|
p,
|
||||||
|
@ -377,7 +375,11 @@ EmojiListWidget::EmojiListWidget(
|
||||||
EmojiListWidget::EmojiListWidget(
|
EmojiListWidget::EmojiListWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
EmojiListDescriptor &&descriptor)
|
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)
|
, _controller(descriptor.controller)
|
||||||
, _mode(descriptor.mode)
|
, _mode(descriptor.mode)
|
||||||
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
|
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
|
||||||
|
@ -386,6 +388,8 @@ EmojiListWidget::EmojiListWidget(
|
||||||
: nullptr)
|
: nullptr)
|
||||||
, _localSetsManager(
|
, _localSetsManager(
|
||||||
std::make_unique<LocalStickersManager>(&session()))
|
std::make_unique<LocalStickersManager>(&session()))
|
||||||
|
, _customRecentFactory(std::move(descriptor.customRecentFactory))
|
||||||
|
, _overBg(st::emojiPanRadius, st().overBg)
|
||||||
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
|
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
|
||||||
, _picker(this)
|
, _picker(this)
|
||||||
, _showPickerTimer([=] { showPicker(); }) {
|
, _showPickerTimer([=] { showPicker(); }) {
|
||||||
|
@ -433,6 +437,10 @@ EmojiListWidget::EmojiListWidget(
|
||||||
initButton(_unlock, tr::lng_emoji_featured_unlock(tr::now), true);
|
initButton(_unlock, tr::lng_emoji_featured_unlock(tr::now), true);
|
||||||
initButton(_restore, tr::lng_emoji_premium_restore(tr::now), true);
|
initButton(_restore, tr::lng_emoji_premium_restore(tr::now), true);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
if (!descriptor.customRecentList.empty()) {
|
||||||
|
fillRecentFrom(descriptor.customRecentList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmojiListWidget::~EmojiListWidget() {
|
EmojiListWidget::~EmojiListWidget() {
|
||||||
|
@ -535,6 +543,7 @@ object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
|
||||||
.session = &session(),
|
.session = &session(),
|
||||||
.paused = pausedMethod(),
|
.paused = pausedMethod(),
|
||||||
.parent = this,
|
.parent = this,
|
||||||
|
.st = &st(),
|
||||||
});
|
});
|
||||||
_footer = result;
|
_footer = result;
|
||||||
|
|
||||||
|
@ -557,7 +566,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
|
||||||
? kCollapsedRows
|
? kCollapsedRows
|
||||||
: (info.count + _columnCount - 1) / _columnCount;
|
: (info.count + _columnCount - 1) / _columnCount;
|
||||||
info.rowsTop = info.top
|
info.rowsTop = info.top
|
||||||
+ (i == 0 ? st::emojiPanPadding : st::emojiPanHeader);
|
+ (i == 0 ? st().padding.top() : st().header);
|
||||||
info.rowsBottom = info.rowsTop
|
info.rowsBottom = info.rowsTop
|
||||||
+ (info.rowsCount * _singleSize.height())
|
+ (info.rowsCount * _singleSize.height())
|
||||||
+ st::roundRadiusSmall;
|
+ st::roundRadiusSmall;
|
||||||
|
@ -637,18 +646,17 @@ void EmojiListWidget::setSingleSize(QSize size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int EmojiListWidget::countDesiredHeight(int newWidth) {
|
int EmojiListWidget::countDesiredHeight(int newWidth) {
|
||||||
const auto left = st::emojiPanLeft;
|
const auto fullWidth = st().margin.left()
|
||||||
const auto right = st::emojiPanRight;
|
|
||||||
const auto fullWidth = st::roundRadiusSmall
|
|
||||||
+ newWidth
|
+ newWidth
|
||||||
+ st::emojiScroll.width;
|
+ st().margin.right();
|
||||||
const auto innerWidth = fullWidth - left - right;
|
const auto padding = st().padding;
|
||||||
_columnCount = std::max(innerWidth / st::emojiPanDesiredSize, 1);
|
const auto innerWidth = fullWidth - padding.left() - padding.right();
|
||||||
|
_columnCount = std::max(innerWidth / st().desiredSize, 1);
|
||||||
const auto singleWidth = innerWidth / _columnCount;
|
const auto singleWidth = innerWidth / _columnCount;
|
||||||
_rowsLeft = left
|
_rowsLeft = padding.left()
|
||||||
+ (innerWidth - _columnCount * singleWidth) / 2
|
+ (innerWidth - _columnCount * singleWidth) / 2
|
||||||
- st::roundRadiusSmall;
|
- st().margin.left();
|
||||||
setSingleSize({ singleWidth, singleWidth - 4 * st::lineWidth });
|
setSingleSize({ singleWidth, singleWidth - 2 * st().verticalSizeSub });
|
||||||
|
|
||||||
auto visibleHeight = minimalHeight();
|
auto visibleHeight = minimalHeight();
|
||||||
auto minimalHeight = (visibleHeight - st::stickerPanPadding);
|
auto minimalHeight = (visibleHeight - st::stickerPanPadding);
|
||||||
|
@ -659,7 +667,13 @@ int EmojiListWidget::countDesiredHeight(int newWidth) {
|
||||||
};
|
};
|
||||||
const auto minimalLastHeight = minimalHeight;
|
const auto minimalLastHeight = minimalHeight;
|
||||||
return qMax(minimalHeight, countResult(minimalLastHeight))
|
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) {
|
void EmojiListWidget::ensureLoaded(int section) {
|
||||||
|
@ -688,6 +702,9 @@ void EmojiListWidget::ensureLoaded(int section) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::fillRecent() {
|
void EmojiListWidget::fillRecent() {
|
||||||
|
if (_mode != Mode::Full && _mode != Mode::EmojiStatus) {
|
||||||
|
return; // #TODO emoji_status
|
||||||
|
}
|
||||||
_recent.clear();
|
_recent.clear();
|
||||||
_recentCustomIds.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) {
|
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
|
@ -752,7 +784,7 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
? (selectedButton->section == info.section)
|
? (selectedButton->section == info.section)
|
||||||
: false;
|
: false;
|
||||||
const auto widthForTitle = emojiRight()
|
const auto widthForTitle = emojiRight()
|
||||||
- (st::emojiPanHeaderLeft - st::roundRadiusSmall)
|
- (st().headerLeft - st().margin.left())
|
||||||
- paintButtonGetWidth(p, info, buttonSelected, r);
|
- paintButtonGetWidth(p, info, buttonSelected, r);
|
||||||
if (info.section > 0 && r.top() < info.rowsTop) {
|
if (info.section > 0 && r.top() < info.rowsTop) {
|
||||||
p.setFont(st::emojiPanHeaderFont);
|
p.setFont(st::emojiPanHeaderFont);
|
||||||
|
@ -766,13 +798,13 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
titleWidth = st::emojiPanHeaderFont->width(titleText);
|
titleWidth = st::emojiPanHeaderFont->width(titleText);
|
||||||
}
|
}
|
||||||
const auto left = (info.premiumRequired
|
const auto left = (info.premiumRequired
|
||||||
? st::emojiPanHeaderLockedLeft
|
? st().headerLockedLeft
|
||||||
: st::emojiPanHeaderLeft) - st::roundRadiusSmall;
|
: st().headerLeft) - st().margin.left();
|
||||||
const auto top = info.top + st::emojiPanHeaderTop;
|
const auto top = info.top + st().headerTop;
|
||||||
if (info.premiumRequired) {
|
if (info.premiumRequired) {
|
||||||
st::emojiPremiumRequired.paint(
|
st::emojiPremiumRequired.paint(
|
||||||
p,
|
p,
|
||||||
st::emojiPanHeaderLockLeft - st::roundRadiusSmall,
|
st().headerLockLeft - st().margin.left(),
|
||||||
top,
|
top,
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
|
@ -807,16 +839,12 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
drawCollapsedBadge(p, w - _areaPosition, info.count);
|
drawCollapsedBadge(p, w - _areaPosition, info.count);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (selected) {
|
if (selected && st().overBg->c.alpha() > 0) {
|
||||||
auto tl = w;
|
auto tl = w;
|
||||||
if (rtl()) {
|
if (rtl()) {
|
||||||
tl.setX(width() - tl.x() - st::emojiPanArea.width());
|
tl.setX(width() - tl.x() - st::emojiPanArea.width());
|
||||||
}
|
}
|
||||||
Ui::FillRoundRect(
|
_overBg.paint(p, QRect(tl, st::emojiPanArea));
|
||||||
p,
|
|
||||||
QRect(tl, st::emojiPanArea),
|
|
||||||
st::emojiPanHover,
|
|
||||||
Ui::EmojiHoverCorners);
|
|
||||||
}
|
}
|
||||||
if (info.section == int(Section::Recent)) {
|
if (info.section == int(Section::Recent)) {
|
||||||
drawRecent(p, w, now, paused, index);
|
drawRecent(p, w, now, paused, index);
|
||||||
|
@ -1070,10 +1098,13 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
|
||||||
_premiumChosen.fire_copy(document);
|
_premiumChosen.fire_copy(document);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Core::App().settings().incrementRecentEmoji({ RecentEmojiDocument{
|
auto &settings = Core::App().settings();
|
||||||
document->id,
|
if (_mode == Mode::Full) {
|
||||||
document->session().isTestMode(),
|
settings.incrementRecentEmoji({ RecentEmojiDocument{
|
||||||
} });
|
document->id,
|
||||||
|
document->session().isTestMode(),
|
||||||
|
} });
|
||||||
|
}
|
||||||
_customChosen.fire({ .document = document });
|
_customChosen.fire({ .document = document });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1089,7 +1120,7 @@ void EmojiListWidget::showPicker() {
|
||||||
|
|
||||||
auto y = emojiRect(over->section, over->index).y();
|
auto y = emojiRect(over->section, over->index).y();
|
||||||
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
||||||
if (y < st::emojiPanHeader) {
|
if (y < st().header) {
|
||||||
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
||||||
}
|
}
|
||||||
auto xmax = width() - _picker->width();
|
auto xmax = width() - _picker->width();
|
||||||
|
@ -1124,11 +1155,14 @@ QRect EmojiListWidget::removeButtonRect(int index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const {
|
QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const {
|
||||||
|
if (_mode != Mode::Full) {
|
||||||
|
return QRect();
|
||||||
|
}
|
||||||
const auto buttonw = st::stickerPanRemoveSet.rippleAreaPosition.x()
|
const auto buttonw = st::stickerPanRemoveSet.rippleAreaPosition.x()
|
||||||
+ st::stickerPanRemoveSet.rippleAreaSize;
|
+ st::stickerPanRemoveSet.rippleAreaSize;
|
||||||
const auto buttonh = st::stickerPanRemoveSet.height;
|
const auto buttonh = st::stickerPanRemoveSet.height;
|
||||||
const auto buttonx = emojiRight() - st::emojiPanRemoveSkip - buttonw;
|
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);
|
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,12 +1356,18 @@ void EmojiListWidget::processPanelHideFinished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::refreshRecent() {
|
void EmojiListWidget::refreshRecent() {
|
||||||
|
if (_mode != Mode::Full && _mode != Mode::EmojiStatus) {
|
||||||
|
return; // #TODO emoji_status
|
||||||
|
}
|
||||||
clearSelection();
|
clearSelection();
|
||||||
fillRecent();
|
fillRecent();
|
||||||
resizeToWidth(width());
|
resizeToWidth(width());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::refreshCustom() {
|
void EmojiListWidget::refreshCustom() {
|
||||||
|
if (_mode == Mode::RecentReactions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto old = base::take(_custom);
|
auto old = base::take(_custom);
|
||||||
const auto session = &this->session();
|
const auto session = &this->session();
|
||||||
const auto premiumPossible = session->premiumPossible();
|
const auto premiumPossible = session->premiumPossible();
|
||||||
|
@ -1486,15 +1526,19 @@ not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
|
||||||
if (i != end(_customEmoji)) {
|
if (i != end(_customEmoji)) {
|
||||||
return i->second.emoji.get();
|
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(
|
return _customEmoji.emplace(
|
||||||
documentId,
|
documentId,
|
||||||
CustomEmojiInstance{
|
CustomEmojiInstance{ .emoji = std::move(custom), .recentOnly = true }
|
||||||
.emoji = session().data().customEmojiManager().create(
|
|
||||||
documentId,
|
|
||||||
repaintCallback(documentId, RecentEmojiSectionSetId()),
|
|
||||||
Data::CustomEmojiManager::SizeTag::Large),
|
|
||||||
.recentOnly = true,
|
|
||||||
}
|
|
||||||
).first->second.emoji.get();
|
).first->second.emoji.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1503,7 +1547,7 @@ std::vector<StickerIcon> EmojiListWidget::fillIcons() {
|
||||||
result.reserve(2 + _custom.size());
|
result.reserve(2 + _custom.size());
|
||||||
|
|
||||||
result.emplace_back(RecentEmojiSectionSetId());
|
result.emplace_back(RecentEmojiSectionSetId());
|
||||||
if (_mode == Mode::EmojiStatus) {
|
if (_mode != Mode::Full) {
|
||||||
} else if (_custom.empty()) {
|
} else if (_custom.empty()) {
|
||||||
using Section = Ui::Emoji::Section;
|
using Section = Ui::Emoji::Section;
|
||||||
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
|
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
|
||||||
|
@ -1534,7 +1578,9 @@ int EmojiListWidget::paintButtonGetWidth(
|
||||||
auto &custom = _custom[info.section - _staticCount];
|
auto &custom = _custom[info.section - _staticCount];
|
||||||
if (hasRemoveButton(info.section)) {
|
if (hasRemoveButton(info.section)) {
|
||||||
const auto remove = removeButtonRect(info);
|
const auto remove = removeButtonRect(info);
|
||||||
if (remove.intersects(clip)) {
|
if (remove.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
} else if (remove.intersects(clip)) {
|
||||||
if (custom.ripple) {
|
if (custom.ripple) {
|
||||||
custom.ripple->paint(
|
custom.ripple->paint(
|
||||||
p,
|
p,
|
||||||
|
@ -1603,7 +1649,7 @@ void EmojiListWidget::updateSelected() {
|
||||||
if (hasButton(section)
|
if (hasButton(section)
|
||||||
&& myrtlrect(buttonRect(section)).contains(p.x(), p.y())) {
|
&& myrtlrect(buttonRect(section)).contains(p.x(), p.y())) {
|
||||||
newSelected = OverButton{ section };
|
newSelected = OverButton{ section };
|
||||||
} else if (section >= _staticCount) {
|
} else if (section >= _staticCount && _mode == Mode::Full) {
|
||||||
newSelected = OverSet{ section };
|
newSelected = OverSet{ section };
|
||||||
}
|
}
|
||||||
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
||||||
|
|
|
@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/round_rect.h"
|
#include "ui/round_rect.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct EmojiPan;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
struct RecentEmojiId;
|
struct RecentEmojiId;
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -56,7 +60,8 @@ class LocalStickersManager;
|
||||||
enum class EmojiListMode {
|
enum class EmojiListMode {
|
||||||
Full,
|
Full,
|
||||||
EmojiStatus,
|
EmojiStatus,
|
||||||
Reactions,
|
FullReactions,
|
||||||
|
RecentReactions,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmojiListDescriptor {
|
struct EmojiListDescriptor {
|
||||||
|
@ -64,6 +69,11 @@ struct EmojiListDescriptor {
|
||||||
EmojiListMode mode = EmojiListMode::Full;
|
EmojiListMode mode = EmojiListMode::Full;
|
||||||
Window::SessionController *controller = nullptr;
|
Window::SessionController *controller = nullptr;
|
||||||
Fn<bool()> paused;
|
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
|
class EmojiListWidget
|
||||||
|
@ -120,6 +130,7 @@ protected:
|
||||||
void processHideFinished() override;
|
void processHideFinished() override;
|
||||||
void processPanelHideFinished() override;
|
void processPanelHideFinished() override;
|
||||||
int countDesiredHeight(int newWidth) override;
|
int countDesiredHeight(int newWidth) override;
|
||||||
|
int defaultMinimalHeight() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SectionInfo {
|
struct SectionInfo {
|
||||||
|
@ -272,6 +283,7 @@ private:
|
||||||
void repaintCustom(uint64 setId);
|
void repaintCustom(uint64 setId);
|
||||||
|
|
||||||
void fillRecent();
|
void fillRecent();
|
||||||
|
void fillRecentFrom(const std::vector<DocumentId> &list);
|
||||||
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
uint64 setId);
|
uint64 setId);
|
||||||
|
@ -289,6 +301,9 @@ private:
|
||||||
StickersListFooter *_footer = nullptr;
|
StickersListFooter *_footer = nullptr;
|
||||||
std::unique_ptr<GradientPremiumStar> _premiumIcon;
|
std::unique_ptr<GradientPremiumStar> _premiumIcon;
|
||||||
std::unique_ptr<LocalStickersManager> _localSetsManager;
|
std::unique_ptr<LocalStickersManager> _localSetsManager;
|
||||||
|
Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
|
||||||
|
DocumentId,
|
||||||
|
Fn<void()>)> _customRecentFactory;
|
||||||
|
|
||||||
int _counts[kEmojiSectionCount];
|
int _counts[kEmojiSectionCount];
|
||||||
std::vector<RecentOne> _recent;
|
std::vector<RecentOne> _recent;
|
||||||
|
@ -299,6 +314,7 @@ private:
|
||||||
std::vector<CustomSet> _custom;
|
std::vector<CustomSet> _custom;
|
||||||
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
|
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
|
||||||
bool _allowWithoutPremium = false;
|
bool _allowWithoutPremium = false;
|
||||||
|
Ui::RoundRect _overBg;
|
||||||
|
|
||||||
int _rowsLeft = 0;
|
int _rowsLeft = 0;
|
||||||
int _columnCount = 1;
|
int _columnCount = 1;
|
||||||
|
|
|
@ -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)
|
, _pan(parent)
|
||||||
, _field(this, st::gifsSearchField, tr::lng_gifs_search())
|
, _field(this, st::gifsSearchField, tr::lng_gifs_search())
|
||||||
, _cancel(this, st::gifsSearchCancel) {
|
, _cancel(this, st::gifsSearchCancel) {
|
||||||
|
@ -170,7 +171,11 @@ GifsListWidget::GifsListWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
Window::GifPauseReason level)
|
Window::GifPauseReason level)
|
||||||
: Inner(parent, &controller->session(), Window::PausedIn(controller, level))
|
: Inner(
|
||||||
|
parent,
|
||||||
|
st::defaultEmojiPan,
|
||||||
|
&controller->session(),
|
||||||
|
Window::PausedIn(controller, level))
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _api(&session().mtp())
|
, _api(&session().mtp())
|
||||||
, _section(Section::Gifs)
|
, _section(Section::Gifs)
|
||||||
|
|
|
@ -181,7 +181,9 @@ void GradientPremiumStar::renderOnDemand() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
StickersListFooter::StickersListFooter(Descriptor &&descriptor)
|
StickersListFooter::StickersListFooter(Descriptor &&descriptor)
|
||||||
: InnerFooter(descriptor.parent)
|
: InnerFooter(
|
||||||
|
descriptor.parent,
|
||||||
|
descriptor.st ? *descriptor.st : st::defaultEmojiPan)
|
||||||
, _session(descriptor.session)
|
, _session(descriptor.session)
|
||||||
, _paused(descriptor.paused)
|
, _paused(descriptor.paused)
|
||||||
, _searchButtonVisible(descriptor.searchButtonVisible)
|
, _searchButtonVisible(descriptor.searchButtonVisible)
|
||||||
|
@ -189,14 +191,14 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
|
||||||
, _iconState([=] { update(); })
|
, _iconState([=] { update(); })
|
||||||
, _subiconState([=] { update(); })
|
, _subiconState([=] { update(); })
|
||||||
, _selectionBg(st::roundRadiusLarge, st::windowBgRipple)
|
, _selectionBg(st::roundRadiusLarge, st::windowBgRipple)
|
||||||
, _subselectionBg(st::emojiIconArea / 2, st::windowBgRipple)
|
, _subselectionBg(st().iconArea / 2, st::windowBgRipple)
|
||||||
, _barSelection(descriptor.barSelection) {
|
, _barSelection(descriptor.barSelection) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
|
||||||
_iconsLeft = st::emojiCategorySkip + (_searchButtonVisible
|
_iconsLeft = st().iconSkip + (_searchButtonVisible
|
||||||
? st::stickerIconWidth
|
? st::stickerIconWidth
|
||||||
: 0);
|
: 0);
|
||||||
_iconsRight = st::emojiCategorySkip + (_settingsButtonVisible
|
_iconsRight = st().iconSkip + (_settingsButtonVisible
|
||||||
? st::stickerIconWidth
|
? st::stickerIconWidth
|
||||||
: 0);
|
: 0);
|
||||||
|
|
||||||
|
@ -552,7 +554,7 @@ void StickersListFooter::paintEvent(QPaintEvent *e) {
|
||||||
_iconsLeft,
|
_iconsLeft,
|
||||||
_iconsTop,
|
_iconsTop,
|
||||||
width() - _iconsLeft - _iconsRight,
|
width() - _iconsLeft - _iconsRight,
|
||||||
st::emojiFooterHeight);
|
st().footer);
|
||||||
if (rtl()) {
|
if (rtl()) {
|
||||||
clip.moveLeft(width() - _iconsLeft - clip.width());
|
clip.moveLeft(width() - _iconsLeft - clip.width());
|
||||||
}
|
}
|
||||||
|
@ -582,7 +584,7 @@ void StickersListFooter::paintSelectionBg(Painter &p) const {
|
||||||
selx = width() - selx - selw;
|
selx = width() - selx - selw;
|
||||||
}
|
}
|
||||||
const auto sely = _iconsTop;
|
const auto sely = _iconsTop;
|
||||||
const auto area = st::emojiIconArea;
|
const auto area = st().iconArea;
|
||||||
const auto rect = QRect(
|
const auto rect = QRect(
|
||||||
QPoint(selx, sely) + _areaPosition,
|
QPoint(selx, sely) + _areaPosition,
|
||||||
QSize(selw - 2 * _areaPosition.x(), area));
|
QSize(selw - 2 * _areaPosition.x(), area));
|
||||||
|
@ -613,7 +615,7 @@ void StickersListFooter::paintSelectionBar(Painter &p) const {
|
||||||
}
|
}
|
||||||
p.fillRect(
|
p.fillRect(
|
||||||
selx,
|
selx,
|
||||||
_iconsTop + st::emojiFooterHeight - st::stickerIconPadding,
|
_iconsTop + st().footer - st::stickerIconPadding,
|
||||||
selw,
|
selw,
|
||||||
st::stickerIconSel,
|
st::stickerIconSel,
|
||||||
st::stickerIconSelColor);
|
st::stickerIconSelColor);
|
||||||
|
@ -621,27 +623,27 @@ void StickersListFooter::paintSelectionBar(Painter &p) const {
|
||||||
|
|
||||||
void StickersListFooter::paintLeftRightFading(Painter &p) const {
|
void StickersListFooter::paintLeftRightFading(Painter &p) const {
|
||||||
auto o_left = std::clamp(
|
auto o_left = std::clamp(
|
||||||
_iconState.x.current() / st::stickerIconLeft.width(),
|
_iconState.x.current() / st().fadeLeft.width(),
|
||||||
0.,
|
0.,
|
||||||
1.);
|
1.);
|
||||||
if (o_left > 0) {
|
if (o_left > 0) {
|
||||||
p.setOpacity(o_left);
|
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.);
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
auto o_right = std::clamp(
|
auto o_right = std::clamp(
|
||||||
(_iconState.max - _iconState.x.current()) / st::stickerIconRight.width(),
|
(_iconState.max - _iconState.x.current()) / st().fadeRight.width(),
|
||||||
0.,
|
0.,
|
||||||
1.);
|
1.);
|
||||||
if (o_right > 0) {
|
if (o_right > 0) {
|
||||||
p.setOpacity(o_right);
|
p.setOpacity(o_right);
|
||||||
st::stickerIconRight.fill(
|
st().fadeRight.fill(
|
||||||
p,
|
p,
|
||||||
style::rtlrect(
|
style::rtlrect(
|
||||||
width() - _iconsRight - st::stickerIconRight.width(),
|
width() - _iconsRight - st().fadeRight.width(),
|
||||||
_iconsTop,
|
_iconsTop,
|
||||||
st::stickerIconRight.width(),
|
st().fadeRight.width(),
|
||||||
st::emojiFooterHeight, width()));
|
st().footer, width()));
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -880,19 +882,19 @@ void StickersListFooter::updateSelected() {
|
||||||
&& x >= searchLeft
|
&& x >= searchLeft
|
||||||
&& x < searchLeft + _singleWidth
|
&& x < searchLeft + _singleWidth
|
||||||
&& y >= _iconsTop
|
&& y >= _iconsTop
|
||||||
&& y < _iconsTop + st::emojiFooterHeight) {
|
&& y < _iconsTop + st().footer) {
|
||||||
newOver = SpecialOver::Search;
|
newOver = SpecialOver::Search;
|
||||||
} else if (_settingsButtonVisible
|
} else if (_settingsButtonVisible
|
||||||
&& x >= settingsLeft
|
&& x >= settingsLeft
|
||||||
&& x < settingsLeft + _singleWidth
|
&& x < settingsLeft + _singleWidth
|
||||||
&& y >= _iconsTop
|
&& y >= _iconsTop
|
||||||
&& y < _iconsTop + st::emojiFooterHeight) {
|
&& y < _iconsTop + st().footer) {
|
||||||
if (!_icons.empty() && !hasOnlyFeaturedSets()) {
|
if (!_icons.empty() && !hasOnlyFeaturedSets()) {
|
||||||
newOver = SpecialOver::Settings;
|
newOver = SpecialOver::Settings;
|
||||||
}
|
}
|
||||||
} else if (!_icons.empty()) {
|
} else if (!_icons.empty()) {
|
||||||
if (y >= _iconsTop
|
if (y >= _iconsTop
|
||||||
&& y < _iconsTop + st::emojiFooterHeight
|
&& y < _iconsTop + st().footer
|
||||||
&& x >= _iconsLeft
|
&& x >= _iconsLeft
|
||||||
&& x < width() - _iconsRight) {
|
&& x < width() - _iconsRight) {
|
||||||
enumerateIcons([&](const IconInfo &info) {
|
enumerateIcons([&](const IconInfo &info) {
|
||||||
|
@ -994,11 +996,11 @@ void StickersListFooter::refreshIconsGeometry(
|
||||||
&& _icons[1].setId == EmojiSectionSetId(EmojiSection::People)) {
|
&& _icons[1].setId == EmojiSectionSetId(EmojiSection::People)) {
|
||||||
_singleWidth = (width() - _iconsLeft - _iconsRight) / _icons.size();
|
_singleWidth = (width() - _iconsLeft - _iconsRight) / _icons.size();
|
||||||
} else {
|
} else {
|
||||||
_singleWidth = st::emojiIconWidth;
|
_singleWidth = st().iconWidth;
|
||||||
}
|
}
|
||||||
_areaPosition = QPoint(
|
_areaPosition = QPoint(
|
||||||
(_singleWidth - st::emojiIconArea) / 2,
|
(_singleWidth - st().iconArea) / 2,
|
||||||
(st::emojiFooterHeight - st::emojiIconArea) / 2);
|
(st().footer - st().iconArea) / 2);
|
||||||
refreshScrollableDimensions();
|
refreshScrollableDimensions();
|
||||||
refreshSubiconsGeometry();
|
refreshSubiconsGeometry();
|
||||||
_iconState.selected = _subiconState.selected = -1;
|
_iconState.selected = _subiconState.selected = -1;
|
||||||
|
@ -1047,7 +1049,7 @@ void StickersListFooter::paintStickerSettingsIcon(Painter &p) const {
|
||||||
p,
|
p,
|
||||||
settingsLeft
|
settingsLeft
|
||||||
+ (_singleWidth - st::stickersSettings.width()) / 2,
|
+ (_singleWidth - st::stickersSettings.width()) / 2,
|
||||||
_iconsTop + st::emojiCategory.iconPosition.y(),
|
_iconsTop + st::emojiCategoryIconTop,
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,7 +1058,7 @@ void StickersListFooter::paintSearchIcon(Painter &p) const {
|
||||||
st::stickersSearch.paint(
|
st::stickersSearch.paint(
|
||||||
p,
|
p,
|
||||||
searchLeft + (_singleWidth - st::stickersSearch.width()) / 2,
|
searchLeft + (_singleWidth - st::stickersSearch.width()) / 2,
|
||||||
_iconsTop + st::emojiCategory.iconPosition.y(),
|
_iconsTop + st::emojiCategoryIconTop,
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1145,7 +1147,7 @@ void StickersListFooter::updateSetIcon(uint64 setId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListFooter::updateSetIconAt(int left) {
|
void StickersListFooter::updateSetIconAt(int left) {
|
||||||
update(left, _iconsTop, _singleWidth, st::emojiFooterHeight);
|
update(left, _iconsTop, _singleWidth, st().footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListFooter::paintSetIcon(
|
void StickersListFooter::paintSetIcon(
|
||||||
|
@ -1164,7 +1166,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
? icon.stickerMedia->thumbnail()
|
? icon.stickerMedia->thumbnail()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto x = info.adjustedLeft + (_singleWidth - icon.pixw) / 2;
|
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) {
|
if (icon.custom) {
|
||||||
icon.custom->paint(p, x, y, now, st::emojiIconFg->c, paused);
|
icon.custom->paint(p, x, y, now, st::emojiIconFg->c, paused);
|
||||||
} else if (icon.lottie && icon.lottie->ready()) {
|
} else if (icon.lottie && icon.lottie->ready()) {
|
||||||
|
@ -1177,7 +1179,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRect(
|
QRect(
|
||||||
(info.adjustedLeft + (_singleWidth - size.width()) / 2),
|
(info.adjustedLeft + (_singleWidth - size.width()) / 2),
|
||||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
_iconsTop + (st().footer - size.height()) / 2,
|
||||||
size.width(),
|
size.width(),
|
||||||
size.height()),
|
size.height()),
|
||||||
frame);
|
frame);
|
||||||
|
@ -1212,14 +1214,14 @@ void StickersListFooter::paintSetIcon(
|
||||||
p,
|
p,
|
||||||
icon.megagroupUserpic,
|
icon.megagroupUserpic,
|
||||||
info.adjustedLeft + (_singleWidth - size) / 2,
|
info.adjustedLeft + (_singleWidth - size) / 2,
|
||||||
_iconsTop + (st::emojiFooterHeight - size) / 2,
|
_iconsTop + (st().footer - size) / 2,
|
||||||
width(),
|
width(),
|
||||||
st::stickerGroupCategorySize);
|
st::stickerGroupCategorySize);
|
||||||
} else if (icon.setId == Data::Stickers::PremiumSetId) {
|
} else if (icon.setId == Data::Stickers::PremiumSetId) {
|
||||||
const auto size = st::stickersPremium.size();
|
const auto size = st::stickersPremium.size();
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
info.adjustedLeft + (_singleWidth - size.width()) / 2,
|
info.adjustedLeft + (_singleWidth - size.width()) / 2,
|
||||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
_iconsTop + (st().footer - size.height()) / 2,
|
||||||
_premiumIcon.image());
|
_premiumIcon.image());
|
||||||
} else {
|
} else {
|
||||||
using Section = Ui::Emoji::Section;
|
using Section = Ui::Emoji::Section;
|
||||||
|
@ -1252,7 +1254,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
icon->paint(
|
icon->paint(
|
||||||
p,
|
p,
|
||||||
left + (_singleWidth - icon->width()) / 2,
|
left + (_singleWidth - icon->width()) / 2,
|
||||||
_iconsTop + (st::emojiFooterHeight - icon->height()) / 2,
|
_iconsTop + (st().footer - icon->height()) / 2,
|
||||||
width());
|
width());
|
||||||
};
|
};
|
||||||
if (_icons[info.index].setId == AllEmojiSectionSetId()
|
if (_icons[info.index].setId == AllEmojiSectionSetId()
|
||||||
|
@ -1263,7 +1265,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
left + skip,
|
left + skip,
|
||||||
_iconsTop,
|
_iconsTop,
|
||||||
info.width - 2 * skip,
|
info.width - 2 * skip,
|
||||||
st::emojiFooterHeight,
|
st().footer,
|
||||||
Qt::IntersectClip);
|
Qt::IntersectClip);
|
||||||
enumerateSubicons([&](const IconInfo &info) {
|
enumerateSubicons([&](const IconInfo &info) {
|
||||||
if (info.visible) {
|
if (info.visible) {
|
||||||
|
|
|
@ -33,6 +33,10 @@ namespace Window {
|
||||||
class SessionController;
|
class SessionController;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct EmojiPan;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
|
||||||
enum class ValidateIconAnimations {
|
enum class ValidateIconAnimations {
|
||||||
|
@ -98,6 +102,7 @@ public:
|
||||||
bool searchButtonVisible = false;
|
bool searchButtonVisible = false;
|
||||||
bool settingsButtonVisible = false;
|
bool settingsButtonVisible = false;
|
||||||
bool barSelection = false;
|
bool barSelection = false;
|
||||||
|
const style::EmojiPan *st = nullptr;
|
||||||
};
|
};
|
||||||
explicit StickersListFooter(Descriptor &&descriptor);
|
explicit StickersListFooter(Descriptor &&descriptor);
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,11 @@ StickersListWidget::StickersListWidget(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
Window::GifPauseReason level,
|
Window::GifPauseReason level,
|
||||||
bool masks)
|
bool masks)
|
||||||
: Inner(parent, &controller->session(), Window::PausedIn(controller, level))
|
: Inner(
|
||||||
|
parent,
|
||||||
|
st::defaultEmojiPan,
|
||||||
|
&controller->session(),
|
||||||
|
Window::PausedIn(controller, level))
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _api(&session().mtp())
|
, _api(&session().mtp())
|
||||||
, _localSetsManager(std::make_unique<LocalStickersManager>(&session()))
|
, _localSetsManager(std::make_unique<LocalStickersManager>(&session()))
|
||||||
|
@ -176,7 +180,7 @@ StickersListWidget::StickersListWidget(
|
||||||
st::windowBgRipple,
|
st::windowBgRipple,
|
||||||
st::windowBgOver,
|
st::windowBgOver,
|
||||||
[=] { update(); }))
|
[=] { 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())
|
, _addText(tr::lng_stickers_featured_add(tr::now).toUpper())
|
||||||
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
|
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
|
||||||
, _settings(this, tr::lng_stickers_you_have(tr::now))
|
, _settings(this, tr::lng_stickers_you_have(tr::now))
|
||||||
|
@ -411,7 +415,7 @@ bool StickersListWidget::enumerateSections(Callback callback) const {
|
||||||
const auto titleSkip = set.externalLayout
|
const auto titleSkip = set.externalLayout
|
||||||
? st::stickersTrendingHeader
|
? st::stickersTrendingHeader
|
||||||
: setHasTitle(set)
|
: setHasTitle(set)
|
||||||
? st::emojiPanHeader
|
? st().header
|
||||||
: st::stickerPanPadding;
|
: st::stickerPanPadding;
|
||||||
info.rowsTop = info.top + titleSkip;
|
info.rowsTop = info.top + titleSkip;
|
||||||
if (set.externalLayout) {
|
if (set.externalLayout) {
|
||||||
|
@ -462,16 +466,16 @@ int StickersListWidget::countDesiredHeight(int newWidth) {
|
||||||
if (newWidth <= st::stickerPanWidthMin) {
|
if (newWidth <= st::stickerPanWidthMin) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
auto availableWidth = newWidth - (st::stickerPanPadding - st::roundRadiusSmall);
|
auto availableWidth = newWidth - (st::stickerPanPadding - st().margin.left());
|
||||||
auto columnCount = availableWidth / st::stickerPanWidthMin;
|
auto columnCount = availableWidth / st::stickerPanWidthMin;
|
||||||
auto singleWidth = availableWidth / columnCount;
|
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;
|
auto rowsRight = (fullWidth - columnCount * singleWidth) / 2;
|
||||||
accumulate_max(rowsRight, st::emojiScroll.width);
|
accumulate_max(rowsRight, st::emojiScroll.width);
|
||||||
_rowsLeft = fullWidth
|
_rowsLeft = fullWidth
|
||||||
- columnCount * singleWidth
|
- columnCount * singleWidth
|
||||||
- rowsRight
|
- rowsRight
|
||||||
- st::roundRadiusSmall;
|
- st().margin.left();
|
||||||
_singleSize = QSize(singleWidth, singleWidth);
|
_singleSize = QSize(singleWidth, singleWidth);
|
||||||
setColumnCount(columnCount);
|
setColumnCount(columnCount);
|
||||||
|
|
||||||
|
@ -831,7 +835,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||||
? set.count
|
? set.count
|
||||||
: loadedCount;
|
: loadedCount;
|
||||||
|
|
||||||
auto widthForTitle = stickersRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
|
auto widthForTitle = stickersRight() - (st().headerLeft - st().margin.left());
|
||||||
if (featuredHasAddButton(info.section)) {
|
if (featuredHasAddButton(info.section)) {
|
||||||
auto add = featuredAddRect(info);
|
auto add = featuredAddRect(info);
|
||||||
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
||||||
|
@ -867,7 +871,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||||
}
|
}
|
||||||
p.setFont(st::stickersTrendingHeaderFont);
|
p.setFont(st::stickersTrendingHeaderFont);
|
||||||
p.setPen(st::stickersTrendingHeaderFg);
|
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) {
|
if (set.flags & SetFlag::Unread) {
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
|
@ -875,14 +879,14 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||||
|
|
||||||
{
|
{
|
||||||
PainterHighQualityEnabler hq(p);
|
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);
|
auto statusText = (count > 0) ? tr::lng_stickers_count(tr::now, lt_count, count) : tr::lng_contacts_loading(tr::now);
|
||||||
p.setFont(st::stickersTrendingSubheaderFont);
|
p.setFont(st::stickersTrendingSubheaderFont);
|
||||||
p.setPen(st::stickersTrendingSubheaderFg);
|
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()) {
|
if (info.rowsTop >= clip.y() + clip.height()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -904,7 +908,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||||
if (setHasTitle(set) && clip.top() < info.rowsTop) {
|
if (setHasTitle(set) && clip.top() < info.rowsTop) {
|
||||||
auto titleText = set.title;
|
auto titleText = set.title;
|
||||||
auto titleWidth = st::stickersTrendingHeaderFont->width(titleText);
|
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)) {
|
if (hasRemoveButton(info.section)) {
|
||||||
auto remove = removeButtonRect(info);
|
auto remove = removeButtonRect(info);
|
||||||
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
||||||
|
@ -924,7 +928,7 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
|
||||||
}
|
}
|
||||||
p.setFont(st::emojiPanHeaderFont);
|
p.setFont(st::emojiPanHeaderFont);
|
||||||
p.setPen(st::emojiPanHeaderFg);
|
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) {
|
if (clip.top() + clip.height() <= info.rowsTop) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1054,7 +1058,7 @@ void StickersListWidget::paintEmptySearchResults(Painter &p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int StickersListWidget::megagroupSetInfoLeft() const {
|
int StickersListWidget::megagroupSetInfoLeft() const {
|
||||||
return st::emojiPanHeaderLeft - st::roundRadiusSmall;
|
return st().headerLeft - st().margin.left();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected) {
|
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 buttonw = st::stickerPanRemoveSet.width;
|
||||||
auto buttonh = st::stickerPanRemoveSet.height;
|
auto buttonh = st::stickerPanRemoveSet.height;
|
||||||
auto buttonx = stickersRight() - buttonw;
|
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);
|
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2322,7 +2326,7 @@ std::vector<StickerIcon> StickersListWidget::fillIcons() {
|
||||||
Assert(set != nullptr);
|
Assert(set != nullptr);
|
||||||
const auto s = _mySets[i].thumbnailDocument;
|
const auto s = _mySets[i].thumbnailDocument;
|
||||||
const auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding;
|
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()
|
const auto size = set->hasThumbnail()
|
||||||
? QSize(
|
? QSize(
|
||||||
set->thumbnailLocation().width(),
|
set->thumbnailLocation().width(),
|
||||||
|
|
|
@ -46,6 +46,10 @@ class ReaderPointer;
|
||||||
enum class Notification;
|
enum class Notification;
|
||||||
} // namespace Media::Clip
|
} // namespace Media::Clip
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct EmojiPan;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
|
||||||
struct StickerIcon;
|
struct StickerIcon;
|
||||||
|
@ -320,8 +324,6 @@ private:
|
||||||
void addSearchRow(not_null<Data::StickersSet*> set);
|
void addSearchRow(not_null<Data::StickersSet*> set);
|
||||||
|
|
||||||
void showPreview();
|
void showPreview();
|
||||||
void validatePremiumLock(Set &set, int index, const QImage &frame);
|
|
||||||
void validatePremiumStar();
|
|
||||||
|
|
||||||
Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
|
Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
|
||||||
int section,
|
int section,
|
||||||
|
|
|
@ -107,7 +107,7 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage
|
||||||
_painterInnerBottom = _innerBottom / cIntRetinaFactor();
|
_painterInnerBottom = _innerBottom / cIntRetinaFactor();
|
||||||
_painterInnerWidth = _innerWidth / cIntRetinaFactor();
|
_painterInnerWidth = _innerWidth / cIntRetinaFactor();
|
||||||
_painterInnerHeight = _innerHeight / cIntRetinaFactor();
|
_painterInnerHeight = _innerHeight / cIntRetinaFactor();
|
||||||
_painterCategoriesTop = _painterInnerBottom - st::emojiFooterHeight;
|
_painterCategoriesTop = _painterInnerBottom - st::defaultEmojiPan.footer;
|
||||||
|
|
||||||
_wasSectionIcons = wasSectionIcons;
|
_wasSectionIcons = wasSectionIcons;
|
||||||
}
|
}
|
||||||
|
@ -294,6 +294,7 @@ TabbedSelector::TabbedSelector(
|
||||||
Window::GifPauseReason level,
|
Window::GifPauseReason level,
|
||||||
Mode mode)
|
Mode mode)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
|
, _st(st::defaultEmojiPan)
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _level(level)
|
, _level(level)
|
||||||
, _mode(mode)
|
, _mode(mode)
|
||||||
|
@ -605,7 +606,7 @@ void TabbedSelector::updateScrollGeometry(QSize oldSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabbedSelector::updateFooterGeometry() {
|
void TabbedSelector::updateFooterGeometry() {
|
||||||
_footerTop = _dropDown ? 0 : (height() - st::emojiFooterHeight);
|
_footerTop = _dropDown ? 0 : (height() - _st.footer);
|
||||||
for (auto &tab : _tabs) {
|
for (auto &tab : _tabs) {
|
||||||
tab.footer()->resizeToWidth(width());
|
tab.footer()->resizeToWidth(width());
|
||||||
tab.footer()->moveToLeft(0, _footerTop);
|
tab.footer()->moveToLeft(0, _footerTop);
|
||||||
|
@ -684,7 +685,7 @@ void TabbedSelector::paintContent(Painter &p) {
|
||||||
0,
|
0,
|
||||||
_footerTop - (_dropDown ? 0 : _roundRadius),
|
_footerTop - (_dropDown ? 0 : _roundRadius),
|
||||||
width(),
|
width(),
|
||||||
st::emojiFooterHeight + _roundRadius);
|
_st.footer + _roundRadius);
|
||||||
Ui::FillRoundRect(
|
Ui::FillRoundRect(
|
||||||
p,
|
p,
|
||||||
footerPart,
|
footerPart,
|
||||||
|
@ -696,7 +697,7 @@ void TabbedSelector::paintContent(Painter &p) {
|
||||||
if (_tabsSlider) {
|
if (_tabsSlider) {
|
||||||
p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg);
|
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();
|
auto sidesTop = marginTop();
|
||||||
|
@ -719,18 +720,18 @@ void TabbedSelector::paintContent(Painter &p) {
|
||||||
|
|
||||||
int TabbedSelector::marginTop() const {
|
int TabbedSelector::marginTop() const {
|
||||||
return _dropDown
|
return _dropDown
|
||||||
? st::emojiFooterHeight
|
? _st.footer
|
||||||
: _tabsSlider
|
: _tabsSlider
|
||||||
? (_tabsSlider->height() - st::lineWidth)
|
? (_tabsSlider->height() - st::lineWidth)
|
||||||
: _roundRadius;
|
: _roundRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TabbedSelector::scrollTop() const {
|
int TabbedSelector::scrollTop() const {
|
||||||
return tabbed() ? marginTop() : _dropDown ? st::emojiFooterHeight : 0;
|
return tabbed() ? marginTop() : _dropDown ? _st.footer : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TabbedSelector::marginBottom() const {
|
int TabbedSelector::marginBottom() const {
|
||||||
return _dropDown ? _roundRadius : st::emojiFooterHeight;
|
return _dropDown ? _roundRadius : _st.footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TabbedSelector::scrollBottom() const {
|
int TabbedSelector::scrollBottom() const {
|
||||||
|
@ -1200,15 +1201,18 @@ TabbedSelector::Inner::Inner(
|
||||||
Window::GifPauseReason level)
|
Window::GifPauseReason level)
|
||||||
: Inner(
|
: Inner(
|
||||||
parent,
|
parent,
|
||||||
|
st::defaultEmojiPan,
|
||||||
&controller->session(),
|
&controller->session(),
|
||||||
Window::PausedIn(controller, level)) {
|
Window::PausedIn(controller, level)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TabbedSelector::Inner::Inner(
|
TabbedSelector::Inner::Inner(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
const style::EmojiPan &st,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
Fn<bool()> paused)
|
Fn<bool()> paused)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
|
, _st(st)
|
||||||
, _session(session)
|
, _session(session)
|
||||||
, _paused(paused) {
|
, _paused(paused) {
|
||||||
}
|
}
|
||||||
|
@ -1271,7 +1275,11 @@ int TabbedSelector::Inner::resizeGetHeight(int newWidth) {
|
||||||
int TabbedSelector::Inner::minimalHeight() const {
|
int TabbedSelector::Inner::minimalHeight() const {
|
||||||
return (_minimalHeight > 0)
|
return (_minimalHeight > 0)
|
||||||
? _minimalHeight
|
? _minimalHeight
|
||||||
: (st::emojiPanMaxHeight - st::emojiFooterHeight);
|
: defaultMinimalHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TabbedSelector::Inner::defaultMinimalHeight() const {
|
||||||
|
return st::emojiPanMaxHeight - _st.footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabbedSelector::Inner::hideFinished() {
|
void TabbedSelector::Inner::hideFinished() {
|
||||||
|
@ -1289,9 +1297,16 @@ void TabbedSelector::Inner::panelHideFinished() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TabbedSelector::InnerFooter::InnerFooter(QWidget *parent)
|
TabbedSelector::InnerFooter::InnerFooter(
|
||||||
: RpWidget(parent) {
|
QWidget *parent,
|
||||||
resize(st::emojiPanWidth, st::emojiFooterHeight);
|
const style::EmojiPan &st)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _st(st) {
|
||||||
|
resize(st::emojiPanWidth, _st.footer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const style::EmojiPan &TabbedSelector::InnerFooter::st() const {
|
||||||
|
return _st;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|
|
@ -41,6 +41,10 @@ namespace SendMenu {
|
||||||
enum class Type;
|
enum class Type;
|
||||||
} // namespace SendMenu
|
} // namespace SendMenu
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct EmojiPan;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
|
||||||
enum class SelectorTab {
|
enum class SelectorTab {
|
||||||
|
@ -233,6 +237,7 @@ private:
|
||||||
not_null<GifsListWidget*> gifs() const;
|
not_null<GifsListWidget*> gifs() const;
|
||||||
not_null<StickersListWidget*> masks() const;
|
not_null<StickersListWidget*> masks() const;
|
||||||
|
|
||||||
|
const style::EmojiPan &_st;
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
const Window::GifPauseReason _level = {};
|
const Window::GifPauseReason _level = {};
|
||||||
|
|
||||||
|
@ -278,12 +283,16 @@ public:
|
||||||
Window::GifPauseReason level);
|
Window::GifPauseReason level);
|
||||||
Inner(
|
Inner(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
|
const style::EmojiPan &st,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
Fn<bool()> paused);
|
Fn<bool()> paused);
|
||||||
|
|
||||||
[[nodiscard]] Main::Session &session() const {
|
[[nodiscard]] Main::Session &session() const {
|
||||||
return *_session;
|
return *_session;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] const style::EmojiPan &st() const {
|
||||||
|
return _st;
|
||||||
|
}
|
||||||
[[nodiscard]] Fn<bool()> pausedMethod() const {
|
[[nodiscard]] Fn<bool()> pausedMethod() const {
|
||||||
return _paused;
|
return _paused;
|
||||||
}
|
}
|
||||||
|
@ -332,6 +341,7 @@ protected:
|
||||||
int visibleTop,
|
int visibleTop,
|
||||||
int visibleBottom) override;
|
int visibleBottom) override;
|
||||||
int minimalHeight() const;
|
int minimalHeight() const;
|
||||||
|
virtual int defaultMinimalHeight() const;
|
||||||
int resizeGetHeight(int newWidth) override final;
|
int resizeGetHeight(int newWidth) override final;
|
||||||
|
|
||||||
virtual int countDesiredHeight(int newWidth) = 0;
|
virtual int countDesiredHeight(int newWidth) = 0;
|
||||||
|
@ -347,6 +357,7 @@ protected:
|
||||||
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const style::EmojiPan &_st;
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
const Fn<bool()> _paused;
|
const Fn<bool()> _paused;
|
||||||
|
|
||||||
|
@ -364,7 +375,9 @@ private:
|
||||||
|
|
||||||
class TabbedSelector::InnerFooter : public Ui::RpWidget {
|
class TabbedSelector::InnerFooter : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
InnerFooter(QWidget *parent);
|
InnerFooter(QWidget *parent, const style::EmojiPan &st);
|
||||||
|
|
||||||
|
[[nodiscard]] const style::EmojiPan &st() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void processHideFinished() {
|
virtual void processHideFinished() {
|
||||||
|
@ -373,6 +386,9 @@ protected:
|
||||||
}
|
}
|
||||||
friend class Inner;
|
friend class Inner;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const style::EmojiPan &_st;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_chat_helpers.h"
|
||||||
|
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
@ -41,6 +42,7 @@ using SizeTag = CustomEmojiManager::SizeTag;
|
||||||
case SizeTag::Normal: return LottieSize::EmojiInteraction;
|
case SizeTag::Normal: return LottieSize::EmojiInteraction;
|
||||||
case SizeTag::Large: return LottieSize::EmojiInteractionReserved1;
|
case SizeTag::Large: return LottieSize::EmojiInteractionReserved1;
|
||||||
case SizeTag::Isolated: return LottieSize::EmojiInteractionReserved2;
|
case SizeTag::Isolated: return LottieSize::EmojiInteractionReserved2;
|
||||||
|
case SizeTag::ReactionFake: return LottieSize::EmojiInteractionReserved3;
|
||||||
}
|
}
|
||||||
Unexpected("SizeTag value in CustomEmojiManager-LottieSizeFromTag.");
|
Unexpected("SizeTag value in CustomEmojiManager-LottieSizeFromTag.");
|
||||||
}
|
}
|
||||||
|
@ -52,6 +54,8 @@ using SizeTag = CustomEmojiManager::SizeTag;
|
||||||
case SizeTag::Isolated:
|
case SizeTag::Isolated:
|
||||||
return (st::largeEmojiSize + 2 * st::largeEmojiOutline)
|
return (st::largeEmojiSize + 2 * st::largeEmojiOutline)
|
||||||
* style::DevicePixelRatio();
|
* style::DevicePixelRatio();
|
||||||
|
case SizeTag::ReactionFake:
|
||||||
|
return st::reactStripImage * style::DevicePixelRatio();
|
||||||
}
|
}
|
||||||
Unexpected("SizeTag value in CustomEmojiManager-SizeFromTag.");
|
Unexpected("SizeTag value in CustomEmojiManager-SizeFromTag.");
|
||||||
}
|
}
|
||||||
|
@ -663,6 +667,9 @@ Session &CustomEmojiManager::owner() const {
|
||||||
|
|
||||||
int FrameSizeFromTag(SizeTag tag) {
|
int FrameSizeFromTag(SizeTag tag) {
|
||||||
const auto emoji = EmojiSizeFromTag(tag);
|
const auto emoji = EmojiSizeFromTag(tag);
|
||||||
|
if (tag == SizeTag::ReactionFake) {
|
||||||
|
return emoji;
|
||||||
|
}
|
||||||
const auto factor = style::DevicePixelRatio();
|
const auto factor = style::DevicePixelRatio();
|
||||||
return Ui::Text::AdjustCustomEmojiSize(emoji / factor) * factor;
|
return Ui::Text::AdjustCustomEmojiSize(emoji / factor) * factor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
Normal,
|
Normal,
|
||||||
Large,
|
Large,
|
||||||
Isolated,
|
Isolated,
|
||||||
|
ReactionFake,
|
||||||
|
|
||||||
kCount,
|
kCount,
|
||||||
};
|
};
|
||||||
|
|
|
@ -318,6 +318,7 @@ Manager::Manager(
|
||||||
, _inner(QRect({}, st::reactionCornerSize))
|
, _inner(QRect({}, st::reactionCornerSize))
|
||||||
, _strip(
|
, _strip(
|
||||||
_inner,
|
_inner,
|
||||||
|
st::reactionCornerImage,
|
||||||
crl::guard(this, [=] { updateCurrentButton(); }),
|
crl::guard(this, [=] { updateCurrentButton(); }),
|
||||||
std::move(iconFactory))
|
std::move(iconFactory))
|
||||||
, _cachedRound(
|
, _cachedRound(
|
||||||
|
|
|
@ -7,13 +7,78 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "history/view/reactions/history_view_reactions_selector.h"
|
#include "history/view/reactions/history_view_reactions_selector.h"
|
||||||
|
|
||||||
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "chat_helpers/emoji_list_widget.h"
|
||||||
|
#include "chat_helpers/stickers_list_footer.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
namespace HistoryView::Reactions {
|
namespace HistoryView::Reactions {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ShiftedEmoji final : public Ui::Text::CustomEmoji {
|
||||||
|
public:
|
||||||
|
ShiftedEmoji(
|
||||||
|
not_null<Data::CustomEmojiManager*> manager,
|
||||||
|
DocumentId id,
|
||||||
|
Fn<void()> repaint,
|
||||||
|
QPoint shift);
|
||||||
|
|
||||||
|
QString entityData() override;
|
||||||
|
void paint(
|
||||||
|
QPainter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
crl::time now,
|
||||||
|
const QColor &preview,
|
||||||
|
bool paused) override;
|
||||||
|
void unload() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmoji> _real;
|
||||||
|
QPoint _shift;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ShiftedEmoji::ShiftedEmoji(
|
||||||
|
not_null<Data::CustomEmojiManager*> manager,
|
||||||
|
DocumentId id,
|
||||||
|
Fn<void()> repaint,
|
||||||
|
QPoint shift)
|
||||||
|
: _real(manager->create(
|
||||||
|
id,
|
||||||
|
std::move(repaint),
|
||||||
|
Data::CustomEmojiManager::SizeTag::ReactionFake))
|
||||||
|
, _shift(shift) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ShiftedEmoji::entityData() {
|
||||||
|
return _real->entityData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShiftedEmoji::paint(
|
||||||
|
QPainter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
crl::time now,
|
||||||
|
const QColor &preview,
|
||||||
|
bool paused) {
|
||||||
|
_real->paint(p, x + _shift.x(), y + _shift.y(), now, preview, paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShiftedEmoji::unload() {
|
||||||
|
_real->unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Selector::Selector(
|
Selector::Selector(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
|
@ -29,6 +94,7 @@ Selector::Selector(
|
||||||
st::reactStripHeight)
|
st::reactStripHeight)
|
||||||
, _strip(
|
, _strip(
|
||||||
QRect(0, 0, st::reactStripSize, st::reactStripSize),
|
QRect(0, 0, st::reactStripSize, st::reactStripSize),
|
||||||
|
st::reactStripImage,
|
||||||
crl::guard(this, [=] { update(_inner); }),
|
crl::guard(this, [=] { update(_inner); }),
|
||||||
std::move(iconFactory))
|
std::move(iconFactory))
|
||||||
, _size(st::reactStripSize)
|
, _size(st::reactStripSize)
|
||||||
|
@ -70,7 +136,7 @@ QMargins Selector::extentsForShadow() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Selector::extendTopForCategories() const {
|
int Selector::extendTopForCategories() const {
|
||||||
return _reactions.customAllowed ? st::emojiFooterHeight : 0;
|
return _reactions.customAllowed ? st::reactPanelEmojiPan.footer : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Selector::desiredHeight() const {
|
int Selector::desiredHeight() const {
|
||||||
|
@ -275,6 +341,10 @@ void Selector::finishExpand() {
|
||||||
if (!fill.isEmpty()) {
|
if (!fill.isEmpty()) {
|
||||||
q.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
q.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||||
}
|
}
|
||||||
|
if (_footer) {
|
||||||
|
_footer->show();
|
||||||
|
}
|
||||||
|
_scroll->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selector::paintBubble(QPainter &p, int innerWidth) {
|
void Selector::paintBubble(QPainter &p, int innerWidth) {
|
||||||
|
@ -348,9 +418,8 @@ void Selector::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
_premiumPromoChosen.fire({});
|
_premiumPromoChosen.fire({});
|
||||||
} else if (selected == Strip::AddedButton::Expand) {
|
} else if (selected == Strip::AddedButton::Expand) {
|
||||||
expand();
|
expand();
|
||||||
} else {
|
} else if (const auto id = std::get_if<Data::ReactionId>(&selected)) {
|
||||||
const auto id = std::get_if<Data::ReactionId>(&selected);
|
if (!id->empty()) {
|
||||||
if (id && !id->empty()) {
|
|
||||||
_chosen.fire({ .id = *id });
|
_chosen.fire({ .id = *id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,13 +429,23 @@ void Selector::expand() {
|
||||||
const auto parent = parentWidget()->geometry();
|
const auto parent = parentWidget()->geometry();
|
||||||
const auto additionalBottom = parent.height() - y() - height();
|
const auto additionalBottom = parent.height() - y() - height();
|
||||||
const auto additional = _specialExpandTopSkip + additionalBottom;
|
const auto additional = _specialExpandTopSkip + additionalBottom;
|
||||||
if (additionalBottom < 0 || additional <= 0) {
|
const auto strong = _parentController.get();
|
||||||
|
if (additionalBottom < 0 || additional <= 0 || !strong) {
|
||||||
return;
|
return;
|
||||||
}
|
} else if (additionalBottom > 0) {
|
||||||
if (additionalBottom > 0) {
|
|
||||||
resize(width(), height() + additionalBottom);
|
resize(width(), height() + additionalBottom);
|
||||||
raise();
|
raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createList(strong);
|
||||||
|
cacheExpandIcon();
|
||||||
|
|
||||||
|
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||||
|
_expanded = true;
|
||||||
|
_expanding.start([=] { update(); }, 0., 1., st::slideDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector::cacheExpandIcon() {
|
||||||
_expandIconCache = _cachedRound.PrepareImage({ _size, _size });
|
_expandIconCache = _cachedRound.PrepareImage({ _size, _size });
|
||||||
_expandIconCache.fill(Qt::transparent);
|
_expandIconCache.fill(Qt::transparent);
|
||||||
auto q = QPainter(&_expandIconCache);
|
auto q = QPainter(&_expandIconCache);
|
||||||
|
@ -378,9 +457,130 @@ void Selector::expand() {
|
||||||
QRect(-(count - 1) * _size, 0, count * _size, _size),
|
QRect(-(count - 1) * _size, 0, count * _size, _size),
|
||||||
1.,
|
1.,
|
||||||
false);
|
false);
|
||||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
}
|
||||||
_expanded = true;
|
|
||||||
_expanding.start([=] { update(); }, 0., 1., st::slideDuration);
|
void Selector::createList(not_null<Window::SessionController*> controller) {
|
||||||
|
using namespace ChatHelpers;
|
||||||
|
auto recent = std::vector<DocumentId>();
|
||||||
|
auto defaultReactionIds = base::flat_map<DocumentId, QString>();
|
||||||
|
recent.reserve(_reactions.recent.size());
|
||||||
|
for (const auto &reaction : _reactions.recent) {
|
||||||
|
if (const auto id = reaction->id.custom()) {
|
||||||
|
recent.push_back(id);
|
||||||
|
} else {
|
||||||
|
recent.push_back(reaction->selectAnimation->id);
|
||||||
|
defaultReactionIds.emplace(recent.back(), reaction->id.emoji());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto manager = &controller->session().data().customEmojiManager();
|
||||||
|
const auto shift = [&] {
|
||||||
|
// See EmojiListWidget custom emoji position resolving.
|
||||||
|
const auto area = st::emojiPanArea;
|
||||||
|
const auto areaPosition = QPoint(
|
||||||
|
(_size - area.width()) / 2,
|
||||||
|
(_size - area.height()) / 2);
|
||||||
|
const auto esize = Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio();
|
||||||
|
const auto innerPosition = QPoint(
|
||||||
|
(area.width() - esize) / 2,
|
||||||
|
(area.height() - esize) / 2);
|
||||||
|
const auto customSize = Ui::Text::AdjustCustomEmojiSize(esize);
|
||||||
|
const auto customSkip = (esize - customSize) / 2;
|
||||||
|
const auto customPosition = QPoint(customSkip, customSkip);
|
||||||
|
return QPoint(
|
||||||
|
(_size - st::reactStripImage) / 2,
|
||||||
|
(_size - st::reactStripImage) / 2
|
||||||
|
) - areaPosition - innerPosition - customPosition;
|
||||||
|
}();
|
||||||
|
auto factory = [=](DocumentId id, Fn<void()> repaint) {
|
||||||
|
return defaultReactionIds.contains(id)
|
||||||
|
? std::make_unique<ShiftedEmoji>(
|
||||||
|
manager,
|
||||||
|
id,
|
||||||
|
std::move(repaint),
|
||||||
|
shift)
|
||||||
|
: nullptr;
|
||||||
|
};
|
||||||
|
_scroll = Ui::CreateChild<Ui::ScrollArea>(this, st::reactPanelScroll);
|
||||||
|
_scroll->hide();
|
||||||
|
|
||||||
|
const auto st = lifetime().make_state<style::EmojiPan>(
|
||||||
|
st::reactPanelEmojiPan);
|
||||||
|
st->padding.setTop(_skipy);
|
||||||
|
_list = _scroll->setOwnedWidget(
|
||||||
|
object_ptr<EmojiListWidget>(_scroll, EmojiListDescriptor{
|
||||||
|
.session = &controller->session(),
|
||||||
|
.mode = (_reactions.customAllowed
|
||||||
|
? EmojiListMode::FullReactions
|
||||||
|
: EmojiListMode::RecentReactions),
|
||||||
|
.controller = controller,
|
||||||
|
.paused = [] { return false; },
|
||||||
|
.customRecentList = std::move(recent),
|
||||||
|
.customRecentFactory = std::move(factory),
|
||||||
|
.st = st,
|
||||||
|
})
|
||||||
|
).data();
|
||||||
|
|
||||||
|
_list->customChosen(
|
||||||
|
) | rpl::start_with_next([=](const TabbedSelector::FileChosen &chosen) {
|
||||||
|
const auto id = DocumentId{ chosen.document->id };
|
||||||
|
const auto i = defaultReactionIds.find(id);
|
||||||
|
if (i != end(defaultReactionIds)) {
|
||||||
|
_chosen.fire({ .id = { i->second } });
|
||||||
|
} else {
|
||||||
|
_chosen.fire({ .id = { id } });
|
||||||
|
}
|
||||||
|
}, _list->lifetime());
|
||||||
|
|
||||||
|
const auto inner = rect().marginsRemoved(extentsForShadow());
|
||||||
|
const auto footer = _reactions.customAllowed
|
||||||
|
? _list->createFooter().data()
|
||||||
|
: nullptr;
|
||||||
|
if ((_footer = static_cast<StickersListFooter*>(footer))) {
|
||||||
|
_footer->setParent(this);
|
||||||
|
_footer->hide();
|
||||||
|
_footer->setGeometry(
|
||||||
|
inner.x(),
|
||||||
|
inner.y(),
|
||||||
|
inner.width(),
|
||||||
|
_footer->height());
|
||||||
|
const auto shadow = Ui::CreateChild<Ui::PlainShadow>(this);
|
||||||
|
_footer->geometryValue() | rpl::start_with_next([=](QRect geometry) {
|
||||||
|
shadow->setGeometry(
|
||||||
|
geometry.x(),
|
||||||
|
geometry.y() + geometry.height(),
|
||||||
|
geometry.width(),
|
||||||
|
st::lineWidth);
|
||||||
|
}, shadow->lifetime());
|
||||||
|
shadow->show();
|
||||||
|
}
|
||||||
|
const auto geometry = inner.marginsRemoved(
|
||||||
|
st::reactPanelEmojiPan.margin);
|
||||||
|
_list->move(0, 0);
|
||||||
|
_list->refreshEmoji();
|
||||||
|
_list->resizeToWidth(geometry.width());
|
||||||
|
_list->show();
|
||||||
|
|
||||||
|
const auto updateVisibleTopBottom = [=] {
|
||||||
|
const auto scrollTop = _scroll->scrollTop();
|
||||||
|
const auto scrollBottom = scrollTop + _scroll->height();
|
||||||
|
_list->setVisibleTopBottom(scrollTop, scrollBottom);
|
||||||
|
};
|
||||||
|
_scroll->scrollTopChanges(
|
||||||
|
) | rpl::start_with_next(updateVisibleTopBottom, _list->lifetime());
|
||||||
|
|
||||||
|
_list->scrollToRequests(
|
||||||
|
) | rpl::start_with_next([=](int y) {
|
||||||
|
_scroll->scrollToY(y);
|
||||||
|
}, _list->lifetime());
|
||||||
|
|
||||||
|
_scroll->setGeometry(inner.marginsRemoved({
|
||||||
|
st::reactPanelEmojiPan.margin.left(),
|
||||||
|
_footer ? _footer->height() : 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
updateVisibleTopBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AdjustMenuGeometryForSelector(
|
bool AdjustMenuGeometryForSelector(
|
||||||
|
|
|
@ -20,6 +20,8 @@ struct ReactionId;
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
class TabbedPanel;
|
class TabbedPanel;
|
||||||
|
class EmojiListWidget;
|
||||||
|
class StickersListFooter;
|
||||||
} // namespace ChatHelpers
|
} // namespace ChatHelpers
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -28,6 +30,7 @@ class SessionController;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
class ScrollArea;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace HistoryView::Reactions {
|
namespace HistoryView::Reactions {
|
||||||
|
@ -78,12 +81,14 @@ private:
|
||||||
void paintExpanded(QPainter &p);
|
void paintExpanded(QPainter &p);
|
||||||
void paintBubble(QPainter &p, int innerWidth);
|
void paintBubble(QPainter &p, int innerWidth);
|
||||||
void paintBackgroundToBuffer();
|
void paintBackgroundToBuffer();
|
||||||
void finishExpand();
|
|
||||||
|
|
||||||
[[nodiscard]] int lookupSelectedIndex(QPoint position) const;
|
[[nodiscard]] int lookupSelectedIndex(QPoint position) const;
|
||||||
void setSelected(int index);
|
void setSelected(int index);
|
||||||
|
|
||||||
void expand();
|
void expand();
|
||||||
|
void cacheExpandIcon();
|
||||||
|
void createList(not_null<Window::SessionController*> controller);
|
||||||
|
void finishExpand();
|
||||||
|
|
||||||
const base::weak_ptr<Window::SessionController> _parentController;
|
const base::weak_ptr<Window::SessionController> _parentController;
|
||||||
const Data::PossibleItemReactions _reactions;
|
const Data::PossibleItemReactions _reactions;
|
||||||
|
@ -93,6 +98,10 @@ private:
|
||||||
rpl::event_stream<ChosenReaction> _chosen;
|
rpl::event_stream<ChosenReaction> _chosen;
|
||||||
rpl::event_stream<> _premiumPromoChosen;
|
rpl::event_stream<> _premiumPromoChosen;
|
||||||
|
|
||||||
|
Ui::ScrollArea *_scroll = nullptr;
|
||||||
|
ChatHelpers::EmojiListWidget *_list = nullptr;
|
||||||
|
ChatHelpers::StickersListFooter *_footer = nullptr;
|
||||||
|
|
||||||
QImage _paintBuffer;
|
QImage _paintBuffer;
|
||||||
Ui::Animations::Simple _expanding;
|
Ui::Animations::Simple _expanding;
|
||||||
float64 _appearProgress = 0.;
|
float64 _appearProgress = 0.;
|
||||||
|
|
|
@ -45,11 +45,12 @@ constexpr auto kHoverScale = 1.24;
|
||||||
|
|
||||||
Strip::Strip(
|
Strip::Strip(
|
||||||
QRect inner,
|
QRect inner,
|
||||||
|
int size,
|
||||||
Fn<void()> update,
|
Fn<void()> update,
|
||||||
IconFactory iconFactory)
|
IconFactory iconFactory)
|
||||||
: _iconFactory(std::move(iconFactory))
|
: _iconFactory(std::move(iconFactory))
|
||||||
, _inner(inner)
|
, _inner(inner)
|
||||||
, _finalSize(st::reactionCornerImage)
|
, _finalSize(size)
|
||||||
, _update(std::move(update)) {
|
, _update(std::move(update)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,8 +99,7 @@ void Strip::paint(
|
||||||
const auto animationRect = clip.marginsRemoved({ 0, skip, 0, skip });
|
const auto animationRect = clip.marginsRemoved({ 0, skip, 0, skip });
|
||||||
|
|
||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
const auto finalSize = st::reactionCornerImage;
|
const auto hoveredSize = int(base::SafeRound(_finalSize * kHoverScale));
|
||||||
const auto hoveredSize = int(base::SafeRound(finalSize * kHoverScale));
|
|
||||||
const auto basicTargetForScale = [&](int size, float64 scale) {
|
const auto basicTargetForScale = [&](int size, float64 scale) {
|
||||||
const auto remove = size * (1. - scale) / 2.;
|
const auto remove = size * (1. - scale) / 2.;
|
||||||
return QRectF(QRect(
|
return QRectF(QRect(
|
||||||
|
@ -109,7 +109,7 @@ void Strip::paint(
|
||||||
size
|
size
|
||||||
)).marginsRemoved({ remove, remove, remove, remove });
|
)).marginsRemoved({ remove, remove, remove, remove });
|
||||||
};
|
};
|
||||||
const auto basicTarget = basicTargetForScale(finalSize, scale);
|
const auto basicTarget = basicTargetForScale(_finalSize, scale);
|
||||||
const auto countTarget = [&](const ReactionIcons &icon) {
|
const auto countTarget = [&](const ReactionIcons &icon) {
|
||||||
const auto selectScale = icon.selectedScale.value(
|
const auto selectScale = icon.selectedScale.value(
|
||||||
icon.selected ? kHoverScale : 1.);
|
icon.selected ? kHoverScale : 1.);
|
||||||
|
@ -118,7 +118,7 @@ void Strip::paint(
|
||||||
}
|
}
|
||||||
const auto finalScale = scale * selectScale;
|
const auto finalScale = scale * selectScale;
|
||||||
return (finalScale <= 1.)
|
return (finalScale <= 1.)
|
||||||
? basicTargetForScale(finalSize, finalScale)
|
? basicTargetForScale(_finalSize, finalScale)
|
||||||
: basicTargetForScale(hoveredSize, finalScale / kHoverScale);
|
: basicTargetForScale(hoveredSize, finalScale / kHoverScale);
|
||||||
};
|
};
|
||||||
for (auto &icon : _icons) {
|
for (auto &icon : _icons) {
|
||||||
|
@ -288,7 +288,7 @@ auto Strip::selected() const -> std::variant<AddedButton, ReactionId> {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Strip::computeOverSize() const {
|
int Strip::computeOverSize() const {
|
||||||
return int(base::SafeRound(st::reactionCornerImage * kHoverScale));
|
return int(base::SafeRound(_finalSize * kHoverScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Strip::clearAppearAnimations(bool mainAppeared) {
|
void Strip::clearAppearAnimations(bool mainAppeared) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ class Strip final {
|
||||||
public:
|
public:
|
||||||
using ReactionId = Data::ReactionId;
|
using ReactionId = Data::ReactionId;
|
||||||
|
|
||||||
Strip(QRect inner, Fn<void()> update, IconFactory iconFactory);
|
Strip(QRect inner, int size, Fn<void()> update, IconFactory iconFactory);
|
||||||
|
|
||||||
enum class AddedButton : uchar {
|
enum class AddedButton : uchar {
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -1183,7 +1183,7 @@ void Contact::initDimensions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
int32 left = st::defaultEmojiPan.headerLeft - st::inlineResultsLeft;
|
||||||
|
|
||||||
left = st::inlineFileSize + st::inlineThumbSkip;
|
left = st::inlineFileSize + st::inlineThumbSkip;
|
||||||
prepareThumbnail(st::inlineFileSize, st::inlineFileSize);
|
prepareThumbnail(st::inlineFileSize, st::inlineFileSize);
|
||||||
|
@ -1272,7 +1272,7 @@ Article::Article(
|
||||||
|
|
||||||
void Article::initDimensions() {
|
void Article::initDimensions() {
|
||||||
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft;
|
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft;
|
||||||
int32 textWidth = _maxw - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::emojiPanHeaderLeft - st::inlineResultsLeft));
|
int32 textWidth = _maxw - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::defaultEmojiPan.headerLeft - st::inlineResultsLeft));
|
||||||
TextParseOptions titleOpts = { 0, textWidth, 2 * st::semiboldFont->height, Qt::LayoutDirectionAuto };
|
TextParseOptions titleOpts = { 0, textWidth, 2 * st::semiboldFont->height, Qt::LayoutDirectionAuto };
|
||||||
_title.setText(st::semiboldTextStyle, TextUtilities::SingleLine(_result->getLayoutTitle()), titleOpts);
|
_title.setText(st::semiboldTextStyle, TextUtilities::SingleLine(_result->getLayoutTitle()), titleOpts);
|
||||||
int32 titleHeight = qMin(_title.countHeight(textWidth), 2 * st::semiboldFont->height);
|
int32 titleHeight = qMin(_title.countHeight(textWidth), 2 * st::semiboldFont->height);
|
||||||
|
@ -1294,7 +1294,7 @@ int32 Article::resizeGetHeight(int32 width) {
|
||||||
if (_url) {
|
if (_url) {
|
||||||
_urlText = getResultUrl();
|
_urlText = getResultUrl();
|
||||||
_urlWidth = st::normalFont->width(_urlText);
|
_urlWidth = st::normalFont->width(_urlText);
|
||||||
int32 textWidth = _width - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::emojiPanHeaderLeft - st::inlineResultsLeft));
|
int32 textWidth = _width - (_withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : (st::defaultEmojiPan.headerLeft - st::inlineResultsLeft));
|
||||||
if (_urlWidth > textWidth) {
|
if (_urlWidth > textWidth) {
|
||||||
_urlText = st::normalFont->elided(_urlText, textWidth);
|
_urlText = st::normalFont->elided(_urlText, textWidth);
|
||||||
_urlWidth = st::normalFont->width(_urlText);
|
_urlWidth = st::normalFont->width(_urlText);
|
||||||
|
@ -1305,7 +1305,7 @@ int32 Article::resizeGetHeight(int32 width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Article::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
void Article::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
int32 left = st::defaultEmojiPan.headerLeft - st::inlineResultsLeft;
|
||||||
if (_withThumb) {
|
if (_withThumb) {
|
||||||
left = st::inlineThumbSize + st::inlineThumbSkip;
|
left = st::inlineThumbSize + st::inlineThumbSkip;
|
||||||
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
|
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
|
||||||
|
@ -1470,7 +1470,7 @@ void Game::setPosition(int32 position) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
|
||||||
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
|
int32 left = st::defaultEmojiPan.headerLeft - st::inlineResultsLeft;
|
||||||
|
|
||||||
left = st::inlineThumbSize + st::inlineThumbSkip;
|
left = st::inlineThumbSize + st::inlineThumbSkip;
|
||||||
auto rthumb = style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width);
|
auto rthumb = style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width);
|
||||||
|
|
|
@ -80,7 +80,6 @@ void CreatePaletteCorners() {
|
||||||
PrepareCorners(OverviewVideoSelectedCorners, st::overviewVideoStatusRadius, st::msgDateImgBgSelected);
|
PrepareCorners(OverviewVideoSelectedCorners, st::overviewVideoStatusRadius, st::msgDateImgBgSelected);
|
||||||
PrepareCorners(ForwardCorners, st::historyMessageRadius, st::historyForwardChooseBg);
|
PrepareCorners(ForwardCorners, st::historyMessageRadius, st::historyForwardChooseBg);
|
||||||
PrepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg);
|
PrepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg);
|
||||||
PrepareCorners(EmojiHoverCorners, st::emojiPanRadius, st::emojiPanHover);
|
|
||||||
PrepareCorners(StickerHoverCorners, st::roundRadiusSmall, st::emojiPanHover);
|
PrepareCorners(StickerHoverCorners, st::roundRadiusSmall, st::emojiPanHover);
|
||||||
PrepareCorners(BotKeyboardCorners, st::roundRadiusSmall, st::botKbBg);
|
PrepareCorners(BotKeyboardCorners, st::roundRadiusSmall, st::botKbBg);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ enum CachedRoundCorners : int {
|
||||||
OverviewVideoSelectedCorners,
|
OverviewVideoSelectedCorners,
|
||||||
ForwardCorners,
|
ForwardCorners,
|
||||||
MediaviewSaveCorners,
|
MediaviewSaveCorners,
|
||||||
EmojiHoverCorners,
|
|
||||||
StickerHoverCorners,
|
StickerHoverCorners,
|
||||||
BotKeyboardCorners,
|
BotKeyboardCorners,
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ notifySendReply: IconButton {
|
||||||
iconOver: historySendIconOver;
|
iconOver: historySendIconOver;
|
||||||
iconPosition: point(6px, 6px);
|
iconPosition: point(6px, 6px);
|
||||||
}
|
}
|
||||||
|
notifyFadeRight: icon {{ "fade_horizontal", notificationBg }};
|
||||||
|
|
||||||
titleUnreadCounterTop: 6px;
|
titleUnreadCounterTop: 6px;
|
||||||
titleUnreadCounterRight: 35px;
|
titleUnreadCounterRight: 35px;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a1ec2c9ade2b050bd307ecf669a2ae5019d70df4
|
Subproject commit 8162619cb17456f31d1be378a7ed72dc928e0831
|
Loading…
Add table
Reference in a new issue