mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Allow to open / remove sets from emoji panel.
This commit is contained in:
parent
a7e295ae64
commit
54d683171d
7 changed files with 419 additions and 214 deletions
|
@ -11,15 +11,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/text/custom_emoji_instance.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "layout/layout_position.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "chat_helpers/stickers_list_widget.h"
|
||||
#include "emoji_suggestions_data.h"
|
||||
#include "emoji_suggestions_helper.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -708,6 +711,9 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
const auto paused = controller()->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::SavedGifs);
|
||||
const auto now = crl::now();
|
||||
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
|
||||
? &_pressed
|
||||
: &_selected);
|
||||
enumerateSections([&](const SectionInfo &info) {
|
||||
if (r.top() >= info.rowsBottom) {
|
||||
return true;
|
||||
|
@ -717,14 +723,32 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
if (info.section > 0 && r.top() < info.rowsTop) {
|
||||
p.setFont(st::emojiPanHeaderFont);
|
||||
p.setPen(st::emojiPanHeaderFg);
|
||||
const auto text = (info.section < kEmojiSectionCount)
|
||||
auto titleText = (info.section < kEmojiSectionCount)
|
||||
? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now)
|
||||
: _custom[info.section - kEmojiSectionCount].title;
|
||||
p.drawTextLeft(
|
||||
st::emojiPanHeaderLeft - st::roundRadiusSmall,
|
||||
info.top + st::emojiPanHeaderTop,
|
||||
width(),
|
||||
text);
|
||||
auto titleWidth = st::stickersTrendingHeaderFont->width(titleText);
|
||||
auto widthForTitle = emojiRight() - (st::emojiPanHeaderLeft - st::roundRadiusSmall);
|
||||
if (hasRemoveButton(info.section)) {
|
||||
auto &custom = _custom[info.section - kEmojiSectionCount];
|
||||
auto remove = removeButtonRect(info.section);
|
||||
auto selected = selectedButton ? (selectedButton->section == info.section) : false;
|
||||
if (custom.ripple) {
|
||||
custom.ripple->paint(p, remove.x() + st::stickerPanRemoveSet.rippleAreaPosition.x(), remove.y() + st::stickerPanRemoveSet.rippleAreaPosition.y(), width());
|
||||
if (custom.ripple->empty()) {
|
||||
custom.ripple.reset();
|
||||
}
|
||||
}
|
||||
(selected ? st::stickerPanRemoveSet.iconOver : st::stickerPanRemoveSet.icon).paint(p, remove.topLeft() + st::stickerPanRemoveSet.iconPosition, width());
|
||||
|
||||
widthForTitle -= remove.width();
|
||||
}
|
||||
if (titleWidth > widthForTitle) {
|
||||
titleText = st::stickersTrendingHeaderFont->elided(titleText, widthForTitle);
|
||||
titleWidth = st::stickersTrendingHeaderFont->width(titleText);
|
||||
}
|
||||
p.setFont(st::emojiPanHeaderFont);
|
||||
p.setPen(st::emojiPanHeaderFg);
|
||||
p.drawTextLeft(st::emojiPanHeaderLeft - st::roundRadiusSmall, info.top + st::emojiPanHeaderTop, width(), titleText, titleWidth);
|
||||
}
|
||||
if (r.top() + r.height() > info.rowsTop) {
|
||||
ensureLoaded(info.section);
|
||||
|
@ -735,12 +759,13 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
auto index = i * _columnCount + j;
|
||||
if (index >= info.count) break;
|
||||
|
||||
const auto selectedIndex = Layout::PositionToIndex(
|
||||
info.section,
|
||||
index);
|
||||
auto selected = (selectedIndex == _selected)
|
||||
const auto state = OverEmoji{
|
||||
.section = info.section,
|
||||
.index = index,
|
||||
};
|
||||
const auto selected = (state == _selected)
|
||||
|| (!_picker->isHidden()
|
||||
&& selectedIndex == _pickerSel);
|
||||
&& state == _pickerSelected);
|
||||
|
||||
auto w = QPoint(_rowsLeft + j * _singleSize.width(), info.rowsTop + i * _singleSize.height());
|
||||
if (selected) {
|
||||
|
@ -794,9 +819,9 @@ void EmojiListWidget::drawCustom(
|
|||
}
|
||||
|
||||
bool EmojiListWidget::checkPickerHide() {
|
||||
if (!_picker->isHidden() && _pickerSel >= 0) {
|
||||
if (!_picker->isHidden() && !v::is_null(_pickerSelected)) {
|
||||
_picker->hideAnimated();
|
||||
_pickerSel = -1;
|
||||
_pickerSelected = v::null;
|
||||
updateSelected();
|
||||
return true;
|
||||
}
|
||||
|
@ -809,17 +834,15 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
|||
if (checkPickerHide() || e->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
_pressedSel = _selected;
|
||||
|
||||
if (_selected >= 0) {
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
||||
if (section < kEmojiSectionCount
|
||||
&& sel < _emoji[section].size()
|
||||
&& _emoji[section][sel]->hasVariants()) {
|
||||
_pickerSel = _selected;
|
||||
setPressed(_selected);
|
||||
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||
if (over->section < kEmojiSectionCount
|
||||
&& over->index < _emoji[over->section].size()
|
||||
&& _emoji[over->section][over->index]->hasVariants()) {
|
||||
_pickerSelected = _selected;
|
||||
setCursor(style::cur_default);
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
if (!variants.contains(_emoji[section][sel]->nonColoredId())) {
|
||||
if (!variants.contains(_emoji[over->section][over->index]->nonColoredId())) {
|
||||
showPicker();
|
||||
} else {
|
||||
_showPickerTimer.callOnce(500);
|
||||
|
@ -829,22 +852,22 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
int32 pressed = _pressedSel;
|
||||
_pressedSel = -1;
|
||||
|
||||
auto pressed = _pressed;
|
||||
setPressed(v::null);
|
||||
_lastMousePos = e->globalPos();
|
||||
if (!_picker->isHidden()) {
|
||||
if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) {
|
||||
return _picker->handleMouseRelease(QCursor::pos());
|
||||
} else if (_pickerSel >= 0) {
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_pickerSel);
|
||||
} else if (const auto over = std::get_if<OverEmoji>(&_pickerSelected)) {
|
||||
const auto section = over->section;
|
||||
const auto index = over->index;
|
||||
if (section < kEmojiSectionCount
|
||||
&& sel < _emoji[section].size()
|
||||
&& _emoji[section][sel]->hasVariants()) {
|
||||
&& index < _emoji[section].size()
|
||||
&& _emoji[section][index]->hasVariants()) {
|
||||
const auto &variants = Core::App().settings().emojiVariants();
|
||||
if (variants.contains(_emoji[section][sel]->nonColoredId())) {
|
||||
if (variants.contains(_emoji[section][index]->nonColoredId())) {
|
||||
_picker->hideAnimated();
|
||||
_pickerSel = -1;
|
||||
_pickerSelected = v::null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -853,25 +876,54 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
|||
|
||||
if (_showPickerTimer.isActive()) {
|
||||
_showPickerTimer.cancel();
|
||||
_pickerSel = -1;
|
||||
_pickerSelected = v::null;
|
||||
_picker->hide();
|
||||
}
|
||||
|
||||
if (_selected < 0 || _selected != pressed) {
|
||||
if (v::is_null(_selected) || _selected != pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
||||
if (section < kEmojiSectionCount && sel < _emoji[section].size()) {
|
||||
const auto emoji = _emoji[section][sel];
|
||||
if (emoji->hasVariants() && !_picker->isHidden()) {
|
||||
return;
|
||||
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||
const auto section = over->section;
|
||||
const auto index = over->index;
|
||||
if (section < kEmojiSectionCount && index < _emoji[section].size()) {
|
||||
const auto emoji = _emoji[section][index];
|
||||
if (emoji->hasVariants() && !_picker->isHidden()) {
|
||||
return;
|
||||
}
|
||||
selectEmoji(emoji);
|
||||
} else if (section >= kEmojiSectionCount
|
||||
&& index < _custom[section - kEmojiSectionCount].list.size()) {
|
||||
auto &set = _custom[section - kEmojiSectionCount];
|
||||
selectCustom(set.list[index].document);
|
||||
}
|
||||
selectEmoji(emoji);
|
||||
} else if (section >= kEmojiSectionCount
|
||||
&& sel < _custom[section - kEmojiSectionCount].list.size()) {
|
||||
auto &set = _custom[section - kEmojiSectionCount];
|
||||
selectCustom(set.list[sel].document);
|
||||
} else if (const auto set = std::get_if<OverSet>(&pressed)) {
|
||||
Assert(set->section >= kEmojiSectionCount
|
||||
&& set->section < kEmojiSectionCount + _custom.size());
|
||||
displaySet(_custom[set->section - kEmojiSectionCount].id);
|
||||
} else if (auto button = std::get_if<OverButton>(&pressed)) {
|
||||
Assert(button->section >= kEmojiSectionCount
|
||||
&& button->section < kEmojiSectionCount + _custom.size());
|
||||
removeSet(_custom[button->section - kEmojiSectionCount].id);
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::displaySet(uint64 setId) {
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
checkHideWithBox(controller()->show(
|
||||
Box<StickerSetBox>(controller(), it->second->identifier()),
|
||||
Ui::LayerOption::KeepOther).data());
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::removeSet(uint64 setId) {
|
||||
if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) {
|
||||
checkHideWithBox(controller()->show(
|
||||
std::move(box),
|
||||
Ui::LayerOption::KeepOther));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -885,19 +937,25 @@ void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
|
|||
}
|
||||
|
||||
void EmojiListWidget::showPicker() {
|
||||
if (_pickerSel < 0) return;
|
||||
if (v::is_null(_pickerSelected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_pickerSel);
|
||||
if (section < kEmojiSectionCount && sel < _emoji[section].size() && _emoji[section][sel]->hasVariants()) {
|
||||
_picker->showEmoji(_emoji[section][sel]);
|
||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||
const auto section = over ? over->section : -1;
|
||||
if (section >= 0
|
||||
&& section < kEmojiSectionCount
|
||||
&& over->index < _emoji[section].size()
|
||||
&& _emoji[section][over->index]->hasVariants()) {
|
||||
_picker->showEmoji(_emoji[section][over->index]);
|
||||
|
||||
auto y = emojiRect(section, sel).y();
|
||||
auto y = emojiRect(section, over->index).y();
|
||||
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
||||
if (y < st::emojiPanHeader) {
|
||||
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
||||
}
|
||||
auto xmax = width() - _picker->width();
|
||||
auto coef = float64(sel % _columnCount) / float64(_columnCount - 1);
|
||||
auto coef = float64(over->index % _columnCount) / float64(_columnCount - 1);
|
||||
if (rtl()) coef = 1. - coef;
|
||||
_picker->move(qRound(xmax * coef), y);
|
||||
|
||||
|
@ -906,7 +964,7 @@ void EmojiListWidget::showPicker() {
|
|||
}
|
||||
|
||||
void EmojiListWidget::pickerHidden() {
|
||||
_pickerSel = -1;
|
||||
_pickerSelected = v::null;
|
||||
update();
|
||||
disableScroll(false);
|
||||
|
||||
|
@ -914,14 +972,39 @@ void EmojiListWidget::pickerHidden() {
|
|||
updateSelected();
|
||||
}
|
||||
|
||||
QRect EmojiListWidget::emojiRect(int section, int sel) const {
|
||||
bool EmojiListWidget::hasRemoveButton(int index) const {
|
||||
if (index < kEmojiSectionCount
|
||||
|| index >= kEmojiSectionCount + _custom.size()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QRect EmojiListWidget::removeButtonRect(int index) const {
|
||||
auto buttonw = st::stickerPanRemoveSet.width;
|
||||
auto buttonh = st::stickerPanRemoveSet.height;
|
||||
auto buttonx = emojiRight() - buttonw;
|
||||
auto buttony = sectionInfo(index).top + (st::emojiPanHeader - buttonh) / 2;
|
||||
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||
}
|
||||
|
||||
int EmojiListWidget::emojiRight() const {
|
||||
return emojiLeft() + (_columnCount * _singleSize.width());
|
||||
}
|
||||
|
||||
int EmojiListWidget::emojiLeft() const {
|
||||
return _rowsLeft;
|
||||
}
|
||||
|
||||
QRect EmojiListWidget::emojiRect(int section, int index) const {
|
||||
Expects(_columnCount > 0);
|
||||
|
||||
auto info = sectionInfo(section);
|
||||
auto countTillItem = (sel - (sel % _columnCount));
|
||||
auto rowsToSkip = (countTillItem / _columnCount) + ((countTillItem % _columnCount) ? 1 : 0);
|
||||
auto x = _rowsLeft + ((sel % _columnCount) * _singleSize.width());
|
||||
auto y = info.rowsTop + rowsToSkip * _singleSize.height();
|
||||
const auto info = sectionInfo(section);
|
||||
const auto countTillItem = (index - (index % _columnCount));
|
||||
const auto rowsToSkip = (countTillItem / _columnCount)
|
||||
+ ((countTillItem % _columnCount) ? 1 : 0);
|
||||
const auto x = _rowsLeft + ((index % _columnCount) * _singleSize.width());
|
||||
const auto y = info.rowsTop + rowsToSkip * _singleSize.height();
|
||||
return QRect(x, y, _singleSize.width(), _singleSize.height());
|
||||
}
|
||||
|
||||
|
@ -929,12 +1012,10 @@ void EmojiListWidget::colorChosen(EmojiPtr emoji) {
|
|||
if (emoji->hasVariants()) {
|
||||
Core::App().settings().saveEmojiVariant(emoji);
|
||||
}
|
||||
if (_pickerSel >= 0) {
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_pickerSel);
|
||||
if (section >= 0 && section < kEmojiSectionCount) {
|
||||
_emoji[section][sel] = emoji;
|
||||
rtlupdate(emojiRect(section, sel));
|
||||
}
|
||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||
if (over && over->section >= 0 && over->section < kEmojiSectionCount) {
|
||||
_emoji[over->section][over->index] = emoji;
|
||||
rtlupdate(emojiRect(over->section, over->index));
|
||||
}
|
||||
selectEmoji(emoji);
|
||||
_picker->hideAnimated();
|
||||
|
@ -966,9 +1047,9 @@ void EmojiListWidget::enterFromChildEvent(QEvent *e, QWidget *child) {
|
|||
}
|
||||
|
||||
void EmojiListWidget::clearSelection() {
|
||||
setPressed(v::null);
|
||||
setSelected(v::null);
|
||||
_lastMousePos = mapToGlobal(QPoint(-10, -10));
|
||||
_pressedSel = -1;
|
||||
setSelected(-1);
|
||||
}
|
||||
|
||||
Ui::Emoji::Section EmojiListWidget::currentSection(int yOffset) const {
|
||||
|
@ -977,9 +1058,13 @@ Ui::Emoji::Section EmojiListWidget::currentSection(int yOffset) const {
|
|||
|
||||
QString EmojiListWidget::tooltipText() const {
|
||||
const auto &replacements = Ui::Emoji::internal::GetAllReplacements();
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
||||
if (_selected >= 0 && section < kEmojiSectionCount && sel < _emoji[section].size()) {
|
||||
const auto emoji = _emoji[section][sel]->original();
|
||||
const auto over = std::get_if<OverEmoji>(&_selected);
|
||||
const auto section = over ? over->section : -1;
|
||||
const auto index = over ? over->index : -1;
|
||||
if (section >= 0
|
||||
&& section < kEmojiSectionCount
|
||||
&& index < _emoji[section].size()) {
|
||||
const auto emoji = _emoji[section][index]->original();
|
||||
const auto text = emoji->text();
|
||||
// find the replacement belonging to the emoji
|
||||
const auto it = ranges::find_if(replacements, [&](const auto &one) {
|
||||
|
@ -1007,7 +1092,7 @@ TabbedSelector::InnerFooter *EmojiListWidget::getFooter() const {
|
|||
void EmojiListWidget::processHideFinished() {
|
||||
if (!_picker->isHidden()) {
|
||||
_picker->hideFast();
|
||||
_pickerSel = -1;
|
||||
_pickerSelected = v::null;
|
||||
}
|
||||
clearSelection();
|
||||
}
|
||||
|
@ -1102,48 +1187,59 @@ bool EmojiListWidget::eventHook(QEvent *e) {
|
|||
}
|
||||
|
||||
void EmojiListWidget::updateSelected() {
|
||||
if (_pressedSel >= 0 || _pickerSel >= 0) return;
|
||||
if (!v::is_null(_pressed) || !v::is_null(_pickerSelected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto newSelected = -1;
|
||||
auto newSelected = OverState{ v::null };
|
||||
auto p = mapFromGlobal(_lastMousePos);
|
||||
auto info = sectionInfoByOffset(p.y());
|
||||
if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
||||
auto section = info.section;
|
||||
if (p.y() >= info.top && p.y() < info.rowsTop) {
|
||||
if (hasRemoveButton(section) && myrtlrect(removeButtonRect(section)).contains(p.x(), p.y())) {
|
||||
newSelected = OverButton{ section };
|
||||
} else {
|
||||
newSelected = OverSet{ section };
|
||||
}
|
||||
} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
|
||||
auto sx = (rtl() ? width() - p.x() : p.x()) - _rowsLeft;
|
||||
if (sx >= 0 && sx < _columnCount * _singleSize.width()) {
|
||||
newSelected = qFloor((p.y() - info.rowsTop) / _singleSize.height()) * _columnCount + qFloor(sx / _singleSize.width());
|
||||
if (newSelected >= info.count) {
|
||||
newSelected = -1;
|
||||
} else {
|
||||
newSelected += Layout::PositionToIndex(info.section, 0);
|
||||
const auto index = qFloor((p.y() - info.rowsTop) / _singleSize.height()) * _columnCount + qFloor(sx / _singleSize.width());
|
||||
if (index < info.count) {
|
||||
newSelected = OverEmoji{ .section = section, .index = index };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSelected(newSelected);
|
||||
}
|
||||
|
||||
void EmojiListWidget::setSelected(int newSelected) {
|
||||
void EmojiListWidget::setSelected(OverState newSelected) {
|
||||
if (_selected == newSelected) {
|
||||
return;
|
||||
}
|
||||
auto updateSelected = [this]() {
|
||||
if (_selected < 0) {
|
||||
return;
|
||||
setCursor(!v::is_null(newSelected)
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
|
||||
const auto updateSelected = [&] {
|
||||
if (const auto sticker = std::get_if<OverEmoji>(&_selected)) {
|
||||
rtlupdate(emojiRect(sticker->section, sticker->index));
|
||||
} else if (const auto button = std::get_if<OverButton>(&_selected)) {
|
||||
rtlupdate(removeButtonRect(button->section));
|
||||
}
|
||||
const auto &[section, sel] = Layout::IndexToPosition(_selected);
|
||||
rtlupdate(emojiRect(section, sel));
|
||||
};
|
||||
updateSelected();
|
||||
_selected = newSelected;
|
||||
updateSelected();
|
||||
|
||||
if (_selected >= 0 && Core::App().settings().suggestEmoji()) {
|
||||
const auto hasSelection = !v::is_null(_selected);
|
||||
if (hasSelection && Core::App().settings().suggestEmoji()) {
|
||||
Ui::Tooltip::Show(1000, this);
|
||||
}
|
||||
|
||||
setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
|
||||
if (_selected >= 0 && !_picker->isHidden()) {
|
||||
if (_selected != _pickerSel) {
|
||||
setCursor(hasSelection ? style::cur_pointer : style::cur_default);
|
||||
if (hasSelection && !_picker->isHidden()) {
|
||||
if (_selected != _pickerSelected) {
|
||||
_picker->hideAnimated();
|
||||
} else {
|
||||
_picker->showAnimated();
|
||||
|
@ -1151,6 +1247,51 @@ void EmojiListWidget::setSelected(int newSelected) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::setPressed(OverState newPressed) {
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
Assert(button->section >= kEmojiSectionCount
|
||||
&& button->section < kEmojiSectionCount + _custom.size());
|
||||
auto &set = _custom[button->section - kEmojiSectionCount];
|
||||
if (set.ripple) {
|
||||
set.ripple->lastStop();
|
||||
}
|
||||
}
|
||||
_pressed = newPressed;
|
||||
if (auto button = std::get_if<OverButton>(&_pressed)) {
|
||||
Assert(button->section >= kEmojiSectionCount
|
||||
&& button->section < kEmojiSectionCount + _custom.size());
|
||||
auto &set = _custom[button->section - kEmojiSectionCount];
|
||||
if (!set.ripple) {
|
||||
set.ripple = createButtonRipple(button->section);
|
||||
}
|
||||
set.ripple->add(mapFromGlobal(QCursor::pos()) - buttonRippleTopLeft(button->section));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Ui::RippleAnimation> EmojiListWidget::createButtonRipple(
|
||||
int section) {
|
||||
Expects(section >= kEmojiSectionCount
|
||||
&& section < kEmojiSectionCount + _custom.size());
|
||||
|
||||
const auto set = section - kEmojiSectionCount;
|
||||
auto maskSize = QSize(
|
||||
st::stickerPanRemoveSet.rippleAreaSize,
|
||||
st::stickerPanRemoveSet.rippleAreaSize);
|
||||
auto mask = Ui::RippleAnimation::ellipseMask(maskSize);
|
||||
return std::make_unique<Ui::RippleAnimation>(
|
||||
st::stickerPanRemoveSet.ripple,
|
||||
std::move(mask),
|
||||
[this, section] { rtlupdate(removeButtonRect(section)); });
|
||||
}
|
||||
|
||||
QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
|
||||
Expects(section >= kEmojiSectionCount
|
||||
&& section < kEmojiSectionCount + _custom.size());
|
||||
|
||||
return myrtlrect(removeButtonRect(section)).topLeft()
|
||||
+ st::stickerPanRemoveSet.rippleAreaPosition;
|
||||
}
|
||||
|
||||
void EmojiListWidget::showEmojiSection(Section section) {
|
||||
clearSelection();
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ template <typename ...Tags>
|
|||
struct phrase;
|
||||
} // namespace tr
|
||||
|
||||
namespace Ui {
|
||||
class RippleAnimation;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::Emoji {
|
||||
enum class Section;
|
||||
} // namespace Ui::Emoji
|
||||
|
@ -102,12 +106,50 @@ private:
|
|||
uint64 id = 0;
|
||||
QString title;
|
||||
std::vector<CustomOne> list;
|
||||
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||
bool painted = false;
|
||||
};
|
||||
struct RepaintSet {
|
||||
base::flat_set<uint64> ids;
|
||||
crl::time when = 0;
|
||||
};
|
||||
struct OverEmoji {
|
||||
int section = 0;
|
||||
int index = 0;
|
||||
|
||||
inline bool operator==(OverEmoji other) const {
|
||||
return (section == other.section)
|
||||
&& (index == other.index);
|
||||
}
|
||||
inline bool operator!=(OverEmoji other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
struct OverSet {
|
||||
int section = 0;
|
||||
|
||||
inline bool operator==(OverSet other) const {
|
||||
return (section == other.section);
|
||||
}
|
||||
inline bool operator!=(OverSet other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
struct OverButton {
|
||||
int section = 0;
|
||||
|
||||
inline bool operator==(OverButton other) const {
|
||||
return (section == other.section);
|
||||
}
|
||||
inline bool operator!=(OverButton other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
using OverState = std::variant<
|
||||
v::null_t,
|
||||
OverEmoji,
|
||||
OverSet,
|
||||
OverButton>;
|
||||
|
||||
template <typename Callback>
|
||||
bool enumerateSections(Callback callback) const;
|
||||
|
@ -124,7 +166,8 @@ private:
|
|||
|
||||
void ensureLoaded(int section);
|
||||
void updateSelected();
|
||||
void setSelected(int newSelected);
|
||||
void setSelected(OverState newSelected);
|
||||
void setPressed(OverState newPressed);
|
||||
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
void selectCustom(not_null<DocumentData*> document);
|
||||
|
@ -140,7 +183,18 @@ private:
|
|||
bool paused,
|
||||
int set,
|
||||
int index);
|
||||
[[nodiscard]] QRect emojiRect(int section, int sel) const;
|
||||
[[nodiscard]] bool hasRemoveButton(int index) const;
|
||||
[[nodiscard]] QRect removeButtonRect(int index) const;
|
||||
[[nodiscard]] QRect emojiRect(int section, int index) const;
|
||||
[[nodiscard]] int emojiRight() const;
|
||||
[[nodiscard]] int emojiLeft() const;
|
||||
|
||||
void displaySet(uint64 setId);
|
||||
void removeSet(uint64 setId);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Ui::RippleAnimation> createButtonRipple(
|
||||
int section);
|
||||
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
|
||||
|
||||
void repaintLater(
|
||||
uint64 setId,
|
||||
|
@ -162,9 +216,9 @@ private:
|
|||
QSize _singleSize;
|
||||
int _esize = 0;
|
||||
|
||||
int _selected = -1;
|
||||
int _pressedSel = -1;
|
||||
int _pickerSel = -1;
|
||||
OverState _selected;
|
||||
OverState _pressed;
|
||||
OverState _pickerSelected;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
object_ptr<EmojiColorPicker> _picker;
|
||||
|
|
|
@ -1195,10 +1195,6 @@ StickersListWidget::StickersListWidget(
|
|||
}, lifetime());
|
||||
}
|
||||
|
||||
Main::Session &StickersListWidget::session() const {
|
||||
return controller()->session();
|
||||
}
|
||||
|
||||
rpl::producer<TabbedSelector::FileChosen> StickersListWidget::chosen() const {
|
||||
return _chosen.events();
|
||||
}
|
||||
|
@ -1207,10 +1203,6 @@ rpl::producer<> StickersListWidget::scrollUpdated() const {
|
|||
return _scrollUpdated.events();
|
||||
}
|
||||
|
||||
rpl::producer<> StickersListWidget::checkForHide() const {
|
||||
return _checkForHide.events();
|
||||
}
|
||||
|
||||
auto StickersListWidget::choosingUpdated() const
|
||||
-> rpl::producer<TabbedSelector::Action> {
|
||||
return _choosingUpdated.events();
|
||||
|
@ -2554,7 +2546,6 @@ QPoint StickersListWidget::buttonRippleTopLeft(int section) const {
|
|||
|
||||
void StickersListWidget::showStickerSetBox(not_null<DocumentData*> document) {
|
||||
if (document->sticker() && document->sticker()->set) {
|
||||
_displayingSet = true;
|
||||
checkHideWithBox(StickerSetBox::Show(controller(), document));
|
||||
}
|
||||
}
|
||||
|
@ -3364,10 +3355,6 @@ std::vector<StickerIcon> StickersListWidget::fillIcons() {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool StickersListWidget::preventAutoHide() {
|
||||
return _removingSetId != 0 || _displayingSet != 0;
|
||||
}
|
||||
|
||||
void StickersListWidget::updateSelected() {
|
||||
if (!v::is_null(_pressed) && !_previewShown) {
|
||||
return;
|
||||
|
@ -3598,7 +3585,6 @@ void StickersListWidget::beforeHiding() {
|
|||
void StickersListWidget::displaySet(uint64 setId) {
|
||||
if (setId == Data::Stickers::MegagroupSetId) {
|
||||
if (_megagroupSet->canEditStickers()) {
|
||||
_displayingSet = true;
|
||||
checkHideWithBox(controller()->show(
|
||||
Box<StickersBox>(controller(), _megagroupSet),
|
||||
Ui::LayerOption::KeepOther).data());
|
||||
|
@ -3612,23 +3598,12 @@ void StickersListWidget::displaySet(uint64 setId) {
|
|||
const auto &sets = session().data().stickers().sets();
|
||||
auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
_displayingSet = true;
|
||||
checkHideWithBox(controller()->show(
|
||||
Box<StickerSetBox>(controller(), it->second->identifier()),
|
||||
Ui::LayerOption::KeepOther).data());
|
||||
}
|
||||
}
|
||||
|
||||
void StickersListWidget::checkHideWithBox(QPointer<Ui::BoxContent> box) {
|
||||
if (!box) {
|
||||
return;
|
||||
}
|
||||
connect(box, &QObject::destroyed, this, [=] {
|
||||
_displayingSet = false;
|
||||
_checkForHide.fire({});
|
||||
});
|
||||
}
|
||||
|
||||
void StickersListWidget::installSet(uint64 setId) {
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
const auto it = sets.find(setId);
|
||||
|
@ -3680,8 +3655,7 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
|
|||
refreshStickers();
|
||||
return;
|
||||
}
|
||||
_removingSetId = Data::Stickers::MegagroupSetId;
|
||||
controller()->show(Ui::MakeConfirmBox({
|
||||
checkHideWithBox(controller()->show(Ui::MakeConfirmBox({
|
||||
.text = tr::lng_stickers_remove_group_set(),
|
||||
.confirmed = crl::guard(this, [this, group = _megagroupSet](
|
||||
Fn<void()> &&close) {
|
||||
|
@ -3691,92 +3665,19 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
|
|||
session().api().setGroupStickerSet(group, {});
|
||||
}
|
||||
close();
|
||||
_removingSetId = 0;
|
||||
_checkForHide.fire({});
|
||||
}),
|
||||
.cancelled = crl::guard(this, [this] {
|
||||
_removingSetId = 0;
|
||||
_checkForHide.fire({});
|
||||
.cancelled = crl::guard(this, [this](Fn<void()> &&close) {
|
||||
close();
|
||||
}),
|
||||
}));
|
||||
})));
|
||||
}
|
||||
|
||||
void StickersListWidget::removeSet(uint64 setId) {
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
const auto it = sets.find(setId);
|
||||
if (it == sets.cend()) {
|
||||
return;
|
||||
if (auto box = MakeConfirmRemoveSetBox(&session(), setId)) {
|
||||
checkHideWithBox(controller()->show(
|
||||
std::move(box),
|
||||
Ui::LayerOption::KeepOther));
|
||||
}
|
||||
const auto set = it->second.get();
|
||||
_removingSetId = set->id;
|
||||
const auto text = tr::lng_stickers_remove_pack(
|
||||
tr::now,
|
||||
lt_sticker_pack,
|
||||
set->title);
|
||||
controller()->show(Ui::MakeConfirmBox({
|
||||
.text = text,
|
||||
.confirmed = crl::guard(this, [=](Fn<void()> &&close) {
|
||||
close();
|
||||
const auto &sets = session().data().stickers().sets();
|
||||
const auto it = sets.find(_removingSetId);
|
||||
if (it != sets.cend()) {
|
||||
const auto set = it->second.get();
|
||||
if (set->id && set->accessHash) {
|
||||
_api.request(MTPmessages_UninstallStickerSet(
|
||||
MTP_inputStickerSetID(
|
||||
MTP_long(set->id),
|
||||
MTP_long(set->accessHash)))
|
||||
).send();
|
||||
} else if (!set->shortName.isEmpty()) {
|
||||
_api.request(MTPmessages_UninstallStickerSet(
|
||||
MTP_inputStickerSetShortName(
|
||||
MTP_string(set->shortName)))
|
||||
).send();
|
||||
}
|
||||
auto writeRecent = false;
|
||||
auto &recent = session().data().stickers().getRecentPack();
|
||||
for (auto i = recent.begin(); i != recent.cend();) {
|
||||
if (set->stickers.indexOf(i->first) >= 0) {
|
||||
i = recent.erase(i);
|
||||
writeRecent = true;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
set->flags &= ~SetFlag::Installed;
|
||||
set->installDate = TimeId(0);
|
||||
//
|
||||
// Set can be in search results.
|
||||
//
|
||||
//if (!(set->flags & SetFlag::Featured)
|
||||
// && !(set->flags & SetFlag::Special)) {
|
||||
// sets.erase(it);
|
||||
//}
|
||||
const auto removeIndex = defaultSetsOrder().indexOf(
|
||||
_removingSetId);
|
||||
if (removeIndex >= 0) {
|
||||
defaultSetsOrderRef().removeAt(removeIndex);
|
||||
}
|
||||
refreshStickers();
|
||||
if (set->flags & SetFlag::Masks) {
|
||||
session().local().writeInstalledMasks();
|
||||
} else {
|
||||
session().local().writeInstalledStickers();
|
||||
}
|
||||
if (writeRecent) {
|
||||
session().saveSettings();
|
||||
}
|
||||
session().data().stickers().notifyUpdated();
|
||||
}
|
||||
_removingSetId = 0;
|
||||
_checkForHide.fire({});
|
||||
}),
|
||||
.cancelled = crl::guard(this, [=] {
|
||||
_removingSetId = 0;
|
||||
_checkForHide.fire({});
|
||||
}),
|
||||
.confirmText = tr::lng_stickers_remove_pack_confirm(),
|
||||
}), Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
const Data::StickersSetsOrder &StickersListWidget::defaultSetsOrder() const {
|
||||
|
@ -3797,4 +3698,83 @@ bool StickersListWidget::mySetsEmpty() const {
|
|||
|
||||
StickersListWidget::~StickersListWidget() = default;
|
||||
|
||||
object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
|
||||
not_null<Main::Session*> session,
|
||||
uint64 setId) {
|
||||
const auto &sets = session->data().stickers().sets();
|
||||
const auto it = sets.find(setId);
|
||||
if (it == sets.cend()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto set = it->second.get();
|
||||
const auto text = tr::lng_stickers_remove_pack(
|
||||
tr::now,
|
||||
lt_sticker_pack,
|
||||
set->title);
|
||||
return Ui::MakeConfirmBox({
|
||||
.text = text,
|
||||
.confirmed = [=](Fn<void()> &&close) {
|
||||
close();
|
||||
const auto &sets = session->data().stickers().sets();
|
||||
const auto it = sets.find(setId);
|
||||
if (it != sets.cend()) {
|
||||
const auto set = it->second.get();
|
||||
if (set->id && set->accessHash) {
|
||||
session->api().request(MTPmessages_UninstallStickerSet(
|
||||
MTP_inputStickerSetID(
|
||||
MTP_long(set->id),
|
||||
MTP_long(set->accessHash)))
|
||||
).send();
|
||||
} else if (!set->shortName.isEmpty()) {
|
||||
session->api().request(MTPmessages_UninstallStickerSet(
|
||||
MTP_inputStickerSetShortName(
|
||||
MTP_string(set->shortName)))
|
||||
).send();
|
||||
}
|
||||
auto writeRecent = false;
|
||||
auto &recent = session->data().stickers().getRecentPack();
|
||||
for (auto i = recent.begin(); i != recent.cend();) {
|
||||
if (set->stickers.indexOf(i->first) >= 0) {
|
||||
i = recent.erase(i);
|
||||
writeRecent = true;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
set->flags &= ~SetFlag::Installed;
|
||||
set->installDate = TimeId(0);
|
||||
//
|
||||
// Set can be in search results.
|
||||
//
|
||||
//if (!(set->flags & SetFlag::Featured)
|
||||
// && !(set->flags & SetFlag::Special)) {
|
||||
// sets.erase(it);
|
||||
//}
|
||||
auto &orderRef = (set->flags & SetFlag::Emoji)
|
||||
? session->data().stickers().emojiSetsOrderRef()
|
||||
: (set->flags & SetFlag::Masks)
|
||||
? session->data().stickers().maskSetsOrderRef()
|
||||
: session->data().stickers().setsOrderRef();
|
||||
const auto removeIndex = orderRef.indexOf(setId);
|
||||
if (removeIndex >= 0) {
|
||||
orderRef.removeAt(removeIndex);
|
||||
}
|
||||
if (set->flags & SetFlag::Masks) {
|
||||
session->local().writeInstalledMasks();
|
||||
} else {
|
||||
session->local().writeInstalledStickers();
|
||||
}
|
||||
if (writeRecent) {
|
||||
session->saveSettings();
|
||||
}
|
||||
session->data().stickers().notifyUpdated();
|
||||
}
|
||||
},
|
||||
.cancelled = [=](Fn<void()> &&close) {
|
||||
close();
|
||||
},
|
||||
.confirmText = tr::lng_stickers_remove_pack_confirm(),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ChatHelpers
|
||||
|
|
|
@ -55,11 +55,8 @@ public:
|
|||
not_null<Window::SessionController*> controller,
|
||||
bool masks = false);
|
||||
|
||||
Main::Session &session() const;
|
||||
|
||||
rpl::producer<TabbedSelector::FileChosen> chosen() const;
|
||||
rpl::producer<> scrollUpdated() const;
|
||||
rpl::producer<> checkForHide() const;
|
||||
rpl::producer<TabbedSelector::Action> choosingUpdated() const;
|
||||
|
||||
void refreshRecent() override;
|
||||
|
@ -76,7 +73,6 @@ public:
|
|||
void refreshStickers();
|
||||
|
||||
std::vector<StickerIcon> fillIcons();
|
||||
bool preventAutoHide();
|
||||
|
||||
uint64 currentSet(int yOffset) const;
|
||||
|
||||
|
@ -205,7 +201,6 @@ private:
|
|||
|
||||
void setSection(Section section);
|
||||
void displaySet(uint64 setId);
|
||||
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
||||
void installSet(uint64 setId);
|
||||
void removeMegagroupSet(bool locally);
|
||||
void removeSet(uint64 setId);
|
||||
|
@ -367,7 +362,6 @@ private:
|
|||
base::Timer _updateSetsTimer;
|
||||
base::flat_set<uint64> _repaintSetsIds;
|
||||
|
||||
bool _displayingSet = false;
|
||||
uint64 _removingSetId = 0;
|
||||
|
||||
Footer *_footer = nullptr;
|
||||
|
@ -405,9 +399,12 @@ private:
|
|||
|
||||
rpl::event_stream<TabbedSelector::FileChosen> _chosen;
|
||||
rpl::event_stream<> _scrollUpdated;
|
||||
rpl::event_stream<> _checkForHide;
|
||||
rpl::event_stream<TabbedSelector::Action> _choosingUpdated;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(
|
||||
not_null<Main::Session*> session,
|
||||
uint64 setId);
|
||||
|
||||
} // namespace ChatHelpers
|
||||
|
|
|
@ -280,8 +280,9 @@ void TabbedPanel::opacityAnimationCallback() {
|
|||
}
|
||||
|
||||
void TabbedPanel::hideByTimerOrLeave() {
|
||||
if (isHidden() || preventAutoHide()) return;
|
||||
|
||||
if (isHidden() || preventAutoHide()) {
|
||||
return;
|
||||
}
|
||||
hideAnimated();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/discrete_sliders.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -509,7 +510,8 @@ rpl::producer<> TabbedSelector::checkForHide() const {
|
|||
auto never = rpl::never<>();
|
||||
return rpl::merge(
|
||||
hasStickersTab() ? stickers()->checkForHide() : never,
|
||||
hasMasksTab() ? masks()->checkForHide() : never);
|
||||
hasMasksTab() ? masks()->checkForHide() : never,
|
||||
hasEmojiTab() ? emoji()->checkForHide() : never);
|
||||
}
|
||||
|
||||
rpl::producer<> TabbedSelector::slideFinished() const {
|
||||
|
@ -723,8 +725,9 @@ void TabbedSelector::refreshStickers() {
|
|||
}
|
||||
|
||||
bool TabbedSelector::preventAutoHide() const {
|
||||
return (hasStickersTab() ? stickers()->preventAutoHide() : false)
|
||||
|| (hasMasksTab() ? masks()->preventAutoHide() : false)
|
||||
return (hasStickersTab() && stickers()->preventAutoHide())
|
||||
|| (hasMasksTab() && masks()->preventAutoHide())
|
||||
|| (hasEmojiTab() && emoji()->preventAutoHide())
|
||||
|| hasMenu();
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1136,10 @@ TabbedSelector::Inner::Inner(
|
|||
, _controller(controller) {
|
||||
}
|
||||
|
||||
Main::Session &TabbedSelector::Inner::session() const {
|
||||
return controller()->session();
|
||||
}
|
||||
|
||||
rpl::producer<int> TabbedSelector::Inner::scrollToRequests() const {
|
||||
return _scrollToRequests.events();
|
||||
}
|
||||
|
@ -1149,6 +1156,17 @@ void TabbedSelector::Inner::disableScroll(bool disabled) {
|
|||
_disableScrollRequests.fire_copy(disabled);
|
||||
}
|
||||
|
||||
void TabbedSelector::Inner::checkHideWithBox(QPointer<Ui::BoxContent> box) {
|
||||
if (!box) {
|
||||
return;
|
||||
}
|
||||
_preventHideWithBox = true;
|
||||
connect(box, &QObject::destroyed, this, [=] {
|
||||
_preventHideWithBox = false;
|
||||
_checkForHide.fire({});
|
||||
});
|
||||
}
|
||||
|
||||
void TabbedSelector::Inner::visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) {
|
||||
|
|
|
@ -29,6 +29,7 @@ class PopupMenu;
|
|||
class ScrollArea;
|
||||
class SettingsSlider;
|
||||
class FlatLabel;
|
||||
class BoxContent;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
|
@ -259,18 +260,26 @@ class TabbedSelector::Inner : public Ui::RpWidget {
|
|||
public:
|
||||
Inner(QWidget *parent, not_null<Window::SessionController*> controller);
|
||||
|
||||
not_null<Window::SessionController*> controller() const {
|
||||
[[nodiscard]] not_null<Window::SessionController*> controller() const {
|
||||
return _controller;
|
||||
}
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
|
||||
int getVisibleTop() const {
|
||||
[[nodiscard]] int getVisibleTop() const {
|
||||
return _visibleTop;
|
||||
}
|
||||
int getVisibleBottom() const {
|
||||
[[nodiscard]] int getVisibleBottom() const {
|
||||
return _visibleBottom;
|
||||
}
|
||||
void setMinimalHeight(int newWidth, int newMinimalHeight);
|
||||
|
||||
[[nodiscard]] rpl::producer<> checkForHide() const {
|
||||
return _checkForHide.events();
|
||||
}
|
||||
[[nodiscard]] bool preventAutoHide() const {
|
||||
return _preventHideWithBox;
|
||||
}
|
||||
|
||||
virtual void refreshRecent() = 0;
|
||||
virtual void preloadImages() {
|
||||
}
|
||||
|
@ -309,6 +318,8 @@ protected:
|
|||
void scrollTo(int y);
|
||||
void disableScroll(bool disabled);
|
||||
|
||||
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
||||
|
||||
private:
|
||||
not_null<Window::SessionController*> _controller;
|
||||
|
||||
|
@ -318,6 +329,9 @@ private:
|
|||
|
||||
rpl::event_stream<int> _scrollToRequests;
|
||||
rpl::event_stream<bool> _disableScrollRequests;
|
||||
rpl::event_stream<> _checkForHide;
|
||||
|
||||
bool _preventHideWithBox = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue