Support any size in the tabbed selector.

This commit is contained in:
John Preston 2017-11-12 13:54:18 +04:00
parent 5c12b0e5fa
commit 0255d0c59e
16 changed files with 368 additions and 238 deletions

View file

@ -133,11 +133,13 @@ emojiObjectsActive: icon {{ "emoji_objects", emojiIconFgActive }};
emojiSymbols: icon {{ "emoji_symbols", emojiIconFg }};
emojiSymbolsActive: icon {{ "emoji_symbols", emojiIconFgActive }};
emojiFooterHeight: 46px;
emojiCategorySkip: 4px;
emojiCategory: IconButton {
width: 42px;
height: 46px;
height: emojiFooterHeight;
iconPosition: point(8px, 9px);
iconPosition: point(-1px, 9px);
}
emojiCategoryRecent: IconButton(emojiCategory) { icon: emojiRecent; }
emojiCategoryPeople: IconButton(emojiCategory) { icon: emojiPeople; }
@ -152,7 +154,6 @@ emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
fadeBg: emojiPanBg;
}
emojiPanPadding: 12px;
emojiPanSize: size(45px, 41px);
emojiPanWidth: 345px;
emojiPanMinHeight: 278px;
emojiPanMaxHeight: 640px;
@ -192,7 +193,8 @@ hashtagClose: IconButton {
}
}
stickerPanSize: size(64px, 64px);
stickerPanWidthMin: 64px;
stickerPanSize: size(stickerPanWidthMin, stickerPanWidthMin);
stickerPanPadding: 11px;
stickerPanDeleteIconBg: icon {{ "emoji_delete_bg", stickerPanDeleteBg }};
stickerPanDeleteIconFg: icon {{ "emoji_delete", stickerPanDeleteFg }};
@ -201,6 +203,8 @@ stickerPanDeleteOpacityBgOver: 0.5;
stickerPanDeleteOpacityFg: 0.8;
stickerPanDeleteOpacityFgOver: 1.;
stickerPanRemoveSet: hashtagClose;
stickerIconWidth: 42px;
stickerIconHeight: emojiFooterHeight;
stickerIconPadding: 5px;
stickerIconOpacity: 0.7;
stickerIconSel: 2px;

View file

@ -41,6 +41,7 @@ public:
protected:
void processPanelHideFinished() override;
void resizeEvent(QResizeEvent *e) override;
private:
void prepareSection(int &left, int top, int _width, Ui::IconButton *sectionIcon, Section section);
@ -63,16 +64,27 @@ EmojiListWidget::Footer::Footer(not_null<EmojiListWidget*> parent) : InnerFooter
object_ptr<Ui::IconButton>(this, st::emojiCategoryObjects),
object_ptr<Ui::IconButton>(this, st::emojiCategorySymbols),
} } {
auto left = (st::emojiPanWidth - _sections.size() * st::emojiCategory.width) / 2;
for (auto i = 0; i != _sections.size(); ++i) {
auto &button = _sections[i];
button->moveToLeft(left, 0);
left += button->width();
button->setClickedCallback([this, value = static_cast<Section>(i)] { setActiveSection(value); });
auto value = static_cast<Section>(i);
_sections[i]->setClickedCallback([=] {
setActiveSection(value);
});
}
setCurrentSectionIcon(Section::Recent);
}
void EmojiListWidget::Footer::resizeEvent(QResizeEvent *e) {
auto availableWidth = (width() - st::emojiCategorySkip * 2);
auto buttonWidth = availableWidth / _sections.size();
auto buttonsWidth = buttonWidth * _sections.size();
auto left = (width() - buttonsWidth) / 2;
for (auto &button : _sections) {
button->resizeToWidth(buttonWidth);
button->moveToLeft(left, 0);
left += button->width();
}
}
void EmojiListWidget::Footer::processPanelHideFinished() {
// Preserve panel state through visibility toggles.
//setCurrentSectionIcon(Section::Recent);
@ -101,10 +113,6 @@ void EmojiListWidget::Footer::setActiveSection(Ui::Emoji::Section section) {
EmojiColorPicker::EmojiColorPicker(QWidget *parent) : TWidget(parent) {
setMouseTracking(true);
auto w = st::emojiPanMargins.left() + st::emojiPanSize.width() + st::emojiColorsSep + st::emojiPanMargins.right();
auto h = st::emojiPanMargins.top() + 2 * st::emojiColorsPadding + st::emojiPanSize.height() + st::emojiPanMargins.bottom();
resize(w, h);
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideAnimated()));
}
@ -120,14 +128,27 @@ void EmojiColorPicker::showEmoji(EmojiPtr emoji) {
_variants[i] = emoji->variant(i);
}
auto w = st::emojiPanMargins.left() + st::emojiPanSize.width() * _variants.size() + (_variants.size() - 2) * st::emojiColorsPadding + st::emojiColorsSep + st::emojiPanMargins.right();
auto h = st::emojiPanMargins.top() + 2 * st::emojiColorsPadding + st::emojiPanSize.height() + st::emojiPanMargins.bottom();
resize(w, h);
updateSize();
if (!_cache.isNull()) _cache = QPixmap();
showAnimated();
}
void EmojiColorPicker::updateSize() {
auto width = st::emojiPanMargins.left()
+ _singleSize.width() * _variants.size()
+ (_variants.size() - 2) * st::emojiColorsPadding
+ st::emojiColorsSep
+ st::emojiPanMargins.right();
auto height = st::emojiPanMargins.top()
+ 2 * st::emojiColorsPadding
+ _singleSize.height()
+ st::emojiPanMargins.bottom();
resize(width, height);
update();
updateSelected();
}
void EmojiColorPicker::paintEvent(QPaintEvent *e) {
Painter p(this);
@ -151,7 +172,7 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
Ui::Shadow::paint(p, inner, width(), st::defaultRoundShadow);
App::roundRect(p, inner, st::boxBg, BoxCorners);
auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + st::emojiPanSize.width();
auto x = st::emojiPanMargins.left() + 2 * st::emojiColorsPadding + _singleSize.width();
if (rtl()) x = width() - x - st::emojiColorsSep;
p.fillRect(x, st::emojiPanMargins.top() + st::emojiColorsPadding, st::emojiColorsSep, inner.height() - st::emojiColorsPadding * 2, st::emojiColorsSepColor);
@ -197,6 +218,11 @@ void EmojiColorPicker::handleMouseRelease(QPoint globalPos) {
hideAnimated();
}
void EmojiColorPicker::setSingleSize(QSize size) {
_singleSize = size;
updateSize();
}
void EmojiColorPicker::handleMouseMove(QPoint globalPos) {
_lastMousePos = globalPos;
updateSelected();
@ -262,14 +288,14 @@ void EmojiColorPicker::updateSelected() {
auto newSelected = -1;
auto p = mapFromGlobal(_lastMousePos);
auto sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::emojiPanMargins.top() - st::emojiColorsPadding;
if (y >= 0 && y < st::emojiPanSize.height()) {
if (y >= 0 && y < _singleSize.height()) {
auto x = sx - st::emojiPanMargins.left() - st::emojiColorsPadding;
if (x >= 0 && x < st::emojiPanSize.width()) {
if (x >= 0 && x < _singleSize.width()) {
newSelected = 0;
} else {
x -= st::emojiPanSize.width() + 2 * st::emojiColorsPadding + st::emojiColorsSep;
if (x >= 0 && x < st::emojiPanSize.width() * (_variants.size() - 1)) {
newSelected = (x / st::emojiPanSize.width()) + 1;
x -= _singleSize.width() + 2 * st::emojiColorsPadding + st::emojiColorsSep;
if (x >= 0 && x < _singleSize.width() * (_variants.size() - 1)) {
newSelected = (x / _singleSize.width()) + 1;
}
}
}
@ -283,7 +309,18 @@ void EmojiColorPicker::setSelected(int newSelected) {
}
auto updateSelectedRect = [this] {
if (_selected < 0) return;
rtlupdate(st::emojiPanMargins.left() + st::emojiColorsPadding + _selected * st::emojiPanSize.width() + (_selected ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::emojiPanMargins.top() + st::emojiColorsPadding, st::emojiPanSize.width(), st::emojiPanSize.height());
auto addedSkip = (_selected > 0)
? (2 * st::emojiColorsPadding + st::emojiColorsSep)
: 0;
auto left = st::emojiPanMargins.left()
+ st::emojiColorsPadding
+ _selected * _singleSize.width()
+ addedSkip;
rtlupdate(
left,
st::emojiPanMargins.top() + st::emojiColorsPadding,
_singleSize.width(),
_singleSize.height());
};
updateSelectedRect();
_selected = newSelected;
@ -292,20 +329,18 @@ void EmojiColorPicker::setSelected(int newSelected) {
}
void EmojiColorPicker::drawVariant(Painter &p, int variant) {
QPoint w(st::emojiPanMargins.left() + st::emojiColorsPadding + variant * st::emojiPanSize.width() + (variant ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::emojiPanMargins.top() + st::emojiColorsPadding);
QPoint w(st::emojiPanMargins.left() + st::emojiColorsPadding + variant * _singleSize.width() + (variant ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::emojiPanMargins.top() + st::emojiColorsPadding);
if (variant == _selected) {
QPoint tl(w);
if (rtl()) tl.setX(width() - tl.x() - st::emojiPanSize.width());
App::roundRect(p, QRect(tl, st::emojiPanSize), st::emojiPanHover, StickerHoverCorners);
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
}
auto esize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(_variants[variant]->x() * esize, _variants[variant]->y() * esize, esize, esize));
p.drawPixmapLeft(w.x() + (_singleSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (_singleSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(_variants[variant]->x() * esize, _variants[variant]->y() * esize, esize, esize));
}
EmojiListWidget::EmojiListWidget(QWidget *parent, not_null<Window::Controller*> controller) : Inner(parent, controller)
, _picker(this) {
updateSize();
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
@ -347,7 +382,7 @@ bool EmojiListWidget::enumerateSections(Callback callback) const {
info.count = _counts[i];
info.rowsCount = (info.count / kEmojiPanelPerRow) + ((info.count % kEmojiPanelPerRow) ? 1 : 0);
info.rowsTop = info.top + (i == 0 ? st::emojiPanPadding : st::emojiPanHeader);
info.rowsBottom = info.rowsTop + info.rowsCount * st::emojiPanSize.height();
info.rowsBottom = info.rowsTop + info.rowsCount * _singleSize.height();
if (!callback(info)) {
return false;
}
@ -381,7 +416,14 @@ EmojiListWidget::SectionInfo EmojiListWidget::sectionInfoByOffset(int yOffset) c
return result;
}
int EmojiListWidget::countDesiredHeight() {
int EmojiListWidget::countDesiredHeight(int newWidth) {
auto fullWidth = (st::buttonRadius + newWidth + st::emojiScroll.width);
_rowsLeft = fullWidth / (kEmojiPanelPerRow * 4 + 2);
auto rowsRight = std::max(_rowsLeft, st::emojiScroll.width);
auto singleWidth = (fullWidth - _rowsLeft - rowsRight)
/ kEmojiPanelPerRow;
_singleSize = QSize(singleWidth, singleWidth - 4 * st::lineWidth);
_picker->setSingleSize(_singleSize);
return sectionInfo(kEmojiSectionCount - 1).rowsBottom + st::emojiPanPadding;
}
@ -413,8 +455,8 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
}
p.fillRect(r, st::emojiPanBg);
auto fromColumn = floorclamp(r.x() - st::emojiPanPadding, st::emojiPanSize.width(), 0, kEmojiPanelPerRow);
auto toColumn = ceilclamp(r.x() + r.width() - st::emojiPanPadding, st::emojiPanSize.width(), 0, kEmojiPanelPerRow);
auto fromColumn = floorclamp(r.x() - _rowsLeft, _singleSize.width(), 0, kEmojiPanelPerRow);
auto toColumn = ceilclamp(r.x() + r.width() - _rowsLeft, _singleSize.width(), 0, kEmojiPanelPerRow);
if (rtl()) {
qSwap(fromColumn, toColumn);
fromColumn = kEmojiPanelPerRow - fromColumn;
@ -434,8 +476,8 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
}
if (r.top() + r.height() > info.rowsTop) {
ensureLoaded(info.section);
auto fromRow = floorclamp(r.y() - info.rowsTop, st::emojiPanSize.height(), 0, info.rowsCount);
auto toRow = ceilclamp(r.y() + r.height() - info.rowsTop, st::emojiPanSize.height(), 0, info.rowsCount);
auto fromRow = floorclamp(r.y() - info.rowsTop, _singleSize.height(), 0, info.rowsCount);
auto toRow = ceilclamp(r.y() + r.height() - info.rowsTop, _singleSize.height(), 0, info.rowsCount);
for (auto i = fromRow; i < toRow; ++i) {
for (auto j = fromColumn; j < toColumn; ++j) {
auto index = i * kEmojiPanelPerRow + j;
@ -443,15 +485,15 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
auto selected = (!_picker->isHidden() && info.section * MatrixRowShift + index == _pickerSel) || (info.section * MatrixRowShift + index == _selected);
auto w = QPoint(st::emojiPanPadding + j * st::emojiPanSize.width(), info.rowsTop + i * st::emojiPanSize.height());
auto w = QPoint(_rowsLeft + j * _singleSize.width(), info.rowsTop + i * _singleSize.height());
if (selected) {
auto tl = w;
if (rtl()) tl.setX(width() - tl.x() - st::emojiPanSize.width());
App::roundRect(p, QRect(tl, st::emojiPanSize), st::emojiPanHover, StickerHoverCorners);
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
}
auto sourceRect = QRect(_emoji[info.section][index]->x() * _esize, _emoji[info.section][index]->y() * _esize, _esize, _esize);
auto imageLeft = w.x() + (st::emojiPanSize.width() - (_esize / cIntRetinaFactor())) / 2;
auto imageTop = w.y() + (st::emojiPanSize.height() - (_esize / cIntRetinaFactor())) / 2;
auto imageLeft = w.x() + (_singleSize.width() - (_esize / cIntRetinaFactor())) / 2;
auto imageTop = w.y() + (_singleSize.height() - (_esize / cIntRetinaFactor())) / 2;
p.drawPixmapLeft(imageLeft, imageTop, width(), App::emojiLarge(), sourceRect);
}
}
@ -552,7 +594,7 @@ void EmojiListWidget::onShowPicker() {
auto y = emojiRect(section, sel).y();
y -= _picker->height() - st::buttonRadius + getVisibleTop();
if (y < st::emojiPanHeader) {
y += _picker->height() - st::buttonRadius + st::emojiPanSize.height() - st::buttonRadius;
y += _picker->height() - st::buttonRadius + _singleSize.height() - st::buttonRadius;
}
auto xmax = width() - _picker->width();
auto coef = float64(sel % kEmojiPanelPerRow) / float64(kEmojiPanelPerRow - 1);
@ -576,9 +618,9 @@ QRect EmojiListWidget::emojiRect(int section, int sel) {
auto info = sectionInfo(section);
auto countTillItem = (sel - (sel % kEmojiPanelPerRow));
auto rowsToSkip = (countTillItem / kEmojiPanelPerRow) + ((countTillItem % kEmojiPanelPerRow) ? 1 : 0);
auto x = st::emojiPanPadding + ((sel % kEmojiPanelPerRow) * st::emojiPanSize.width());
auto y = info.rowsTop + rowsToSkip * st::emojiPanSize.height();
return QRect(x, y, st::emojiPanSize.width(), st::emojiPanSize.height());
auto x = _rowsLeft + ((sel % kEmojiPanelPerRow) * _singleSize.width());
auto y = info.rowsTop + rowsToSkip * _singleSize.height();
return QRect(x, y, _singleSize.width(), _singleSize.height());
}
void EmojiListWidget::onColorSelected(EmojiPtr emoji) {
@ -648,7 +690,7 @@ void EmojiListWidget::refreshRecent() {
clearSelection();
_emoji[0] = Ui::Emoji::GetSection(Section::Recent);
_counts[0] = _emoji[0].size();
updateSize();
resizeToWidth(width());
}
bool EmojiListWidget::eventHook(QEvent *e) {
@ -668,9 +710,9 @@ void EmojiListWidget::updateSelected() {
auto p = mapFromGlobal(_lastMousePos);
auto info = sectionInfoByOffset(p.y());
if (p.y() >= info.rowsTop && p.y() < info.rowsBottom) {
auto sx = (rtl() ? width() - p.x() : p.x()) - st::emojiPanPadding;
if (sx >= 0 && sx < kEmojiPanelPerRow * st::emojiPanSize.width()) {
newSelected = qFloor((p.y() - info.rowsTop) / st::emojiPanSize.height()) * kEmojiPanelPerRow + qFloor(sx / st::emojiPanSize.width());
auto sx = (rtl() ? width() - p.x() : p.x()) - _rowsLeft;
if (sx >= 0 && sx < kEmojiPanelPerRow * _singleSize.width()) {
newSelected = qFloor((p.y() - info.rowsTop) / _singleSize.height()) * kEmojiPanelPerRow + qFloor(sx / _singleSize.width());
if (newSelected >= _emoji[info.section].size()) {
newSelected = -1;
} else {

View file

@ -41,6 +41,7 @@ public:
void clearSelection();
void handleMouseMove(QPoint globalPos);
void handleMouseRelease(QPoint globalPos);
void setSingleSize(QSize size);
void hideFast();
@ -62,6 +63,7 @@ protected:
private:
void animationCallback();
void updateSize();
void drawVariant(Painter &p, int variant);
@ -75,6 +77,7 @@ private:
int _selected = -1;
int _pressedSel = -1;
QPoint _lastMousePos;
QSize _singleSize;
bool _hiding = false;
QPixmap _cache;
@ -126,7 +129,7 @@ protected:
TabbedSelector::InnerFooter *getFooter() const override;
void processHideFinished() override;
int countDesiredHeight() override;
int countDesiredHeight(int newWidth) override;
private:
class Footer;
@ -159,7 +162,9 @@ private:
int _counts[kEmojiSectionCount];
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
int32 _esize;
int _rowsLeft = 0;
QSize _singleSize;
int _esize = 0;
int _selected = -1;
int _pressedSel = -1;

View file

@ -39,7 +39,6 @@ namespace {
constexpr auto kSaveChosenTabTimeout = 1000;
constexpr auto kSearchRequestDelay = 400;
constexpr auto kStickersPanelPerRow = Stickers::kPanelPerRow;
constexpr auto kInlineItemsMaxPerRow = 5;
constexpr auto kSearchBotUsername = str_const("gif");
@ -57,6 +56,7 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void processPanelHideFinished() override;
@ -74,8 +74,6 @@ GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(p
, _pan(parent)
, _field(this, st::gifsSearchField, langFactory(lng_gifs_search))
, _cancel(this, st::gifsSearchCancel) {
_field->resize(width() - st::gifsSearchFieldPosition.x() - st::gifsSearchCancelPosition.x() - st::gifsSearchCancel.width, _field->height());
_field->moveToLeft(st::gifsSearchFieldPosition.x(), st::gifsSearchFieldPosition.y());
connect(_field, &Ui::InputField::submitted, this, [this](bool ctrlShiftEnter) {
_pan->sendInlineRequest();
});
@ -90,7 +88,6 @@ GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(p
_cancel->toggleAnimated(!_field->getLastText().isEmpty());
_pan->searchForGifs(_field->getLastText());
});
_cancel->moveToRight(st::gifsSearchCancelPosition.x(), st::gifsSearchCancelPosition.y());
_cancel->setClickedCallback([this] {
_field->setText(QString());
});
@ -117,6 +114,16 @@ void GifsListWidget::Footer::paintEvent(QPaintEvent *e) {
st::gifsSearchIcon.paint(p, st::gifsSearchIconPosition.x(), st::gifsSearchIconPosition.y(), width());
}
void GifsListWidget::Footer::resizeEvent(QResizeEvent *e) {
auto fieldWidth = width()
- st::gifsSearchFieldPosition.x()
- st::gifsSearchCancelPosition.x()
- st::gifsSearchCancel.width;
_field->resizeToWidth(fieldWidth);
_field->moveToLeft(st::gifsSearchFieldPosition.x(), st::gifsSearchFieldPosition.y());
_cancel->moveToRight(st::gifsSearchCancelPosition.x(), st::gifsSearchCancelPosition.y());
}
void GifsListWidget::Footer::processPanelHideFinished() {
// Preserve panel state through visibility toggles.
//_field->setText(QString());
@ -127,8 +134,6 @@ GifsListWidget::GifsListWidget(
not_null<Window::Controller*> controller)
: Inner(parent, controller)
, _section(Section::Gifs) {
updateSize();
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
@ -180,9 +185,10 @@ void GifsListWidget::checkLoadMore() {
}
}
int GifsListWidget::countDesiredHeight() {
int GifsListWidget::countDesiredHeight(int newWidth) {
auto result = st::stickerPanPadding;
for (int i = 0, l = _rows.count(); i < l; ++i) {
layoutInlineRow(_rows[i], newWidth);
result += _rows[i].height;
}
return result + st::stickerPanPadding;
@ -448,9 +454,16 @@ bool GifsListWidget::inlineRowFinalize(Row &row, int32 &sumWidth, bool force) {
if (row.items.isEmpty()) return false;
auto full = (row.items.size() >= kInlineItemsMaxPerRow);
auto big = (sumWidth >= st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft);
// Currently use the same GIFs layout for all widget sizes.
// auto big = (sumWidth >= st::buttonRadius + width() - st::inlineResultsLeft);
auto big = (sumWidth >= st::emojiPanWidth - st::inlineResultsLeft);
if (full || big || force) {
_rows.push_back(layoutInlineRow(row, (full || big) ? sumWidth : 0));
row.maxWidth = (full || big) ? sumWidth : 0;
layoutInlineRow(
row,
width());
_rows.push_back(row);
row = Row();
row.items.reserve(kInlineItemsMaxPerRow);
sumWidth = 0;
@ -476,7 +489,7 @@ void GifsListWidget::refreshSavedGifs() {
}
deleteUnusedGifLayouts();
updateSize();
resizeToWidth(width());
update();
}
@ -561,7 +574,7 @@ void GifsListWidget::deleteUnusedInlineLayouts() {
}
}
GifsListWidget::Row &GifsListWidget::layoutInlineRow(Row &row, int32 sumWidth) {
void GifsListWidget::layoutInlineRow(Row &row, int fullWidth) {
auto count = int(row.items.size());
Assert(count <= kInlineItemsMaxPerRow);
@ -571,27 +584,30 @@ GifsListWidget::Row &GifsListWidget::layoutInlineRow(Row &row, int32 sumWidth) {
for (auto i = 0; i != count; ++i) {
indices[i] = i;
}
std::sort(indices, indices + count, [&row](int a, int b) -> bool {
return row.items.at(a)->maxWidth() < row.items.at(b)->maxWidth();
std::sort(indices, indices + count, [&](int a, int b) {
return row.items[a]->maxWidth()
< row.items[b]->maxWidth();
});
auto desiredWidth = row.maxWidth;
row.height = 0;
int availw = width() - (st::inlineResultsLeft - st::buttonRadius);
int availw = fullWidth - (st::inlineResultsLeft - st::buttonRadius);
for (int i = 0; i < count; ++i) {
int index = indices[i];
int w = sumWidth ? (row.items.at(index)->maxWidth() * availw / sumWidth) : row.items.at(index)->maxWidth();
int w = desiredWidth
? (row.items[index]->maxWidth() * availw / desiredWidth)
: row.items[index]->maxWidth();
int actualw = qMax(w, int(st::inlineResultsMinWidth));
row.height = qMax(row.height, row.items[index]->resizeGetHeight(actualw));
if (sumWidth) {
if (desiredWidth) {
availw -= actualw;
sumWidth -= row.items.at(index)->maxWidth();
if (index > 0 && row.items.at(index - 1)->hasRightSkip()) {
desiredWidth -= row.items[index]->maxWidth();
if (index > 0 && row.items[index - 1]->hasRightSkip()) {
availw -= st::inlineResultsSkip;
sumWidth -= st::inlineResultsSkip;
desiredWidth -= st::inlineResultsSkip;
}
}
}
return row;
}
void GifsListWidget::preloadImages() {
@ -639,7 +655,7 @@ int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool result
inlineRowFinalize(row, sumWidth, true);
}
updateSize();
resizeToWidth(width());
update();
_lastMousePos = QCursor::pos();
@ -680,7 +696,12 @@ int GifsListWidget::validateExistingInlineRows(const InlineResults &results) {
}
_rows.resize(untilrow + 1);
_rows[untilrow].items.resize(untilcol);
_rows[untilrow] = layoutInlineRow(_rows[untilrow]);
_rows[untilrow].maxWidth = std::accumulate(
_rows[untilrow].items.begin(),
_rows[untilrow].items.end(),
0,
[](int w, auto &row) { return w + row->maxWidth(); });
layoutInlineRow(_rows[untilrow], width());
return until;
}
if (untilrow && !untilcol) { // remove last row, maybe it is not full

View file

@ -86,7 +86,7 @@ protected:
TabbedSelector::InnerFooter *getFooter() const override;
void processHideFinished() override;
void processPanelHideFinished() override;
int countDesiredHeight() override;
int countDesiredHeight(int newWidth) override;
private slots:
void onPreview();
@ -136,6 +136,7 @@ private:
bool _inlineWithThumb = false;
struct Row {
int maxWidth = 0;
int height = 0;
QVector<LayoutItem*> items;
};
@ -151,7 +152,7 @@ private:
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, Row &row, int32 &sumWidth);
bool inlineRowFinalize(Row &row, int32 &sumWidth, bool force = false);
Row &layoutInlineRow(Row &row, int32 sumWidth = 0);
void layoutInlineRow(Row &row, int fullWidth);
void deleteUnusedGifLayouts();
void deleteUnusedInlineLayouts();

View file

@ -21,7 +21,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "chat_helpers/stickers_list_widget.h"
#include "data/data_document.h"
#include "styles/style_chat_helpers.h"
#include "ui/widgets/buttons.h"
#include "ui/effects/ripple_animation.h"
#include "boxes/stickers_box.h"
@ -37,11 +36,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h"
#include "observer_peer.h"
#include "apiwrap.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_window.h"
namespace ChatHelpers {
namespace {
constexpr auto kStickersPanelPerRow = Stickers::kPanelPerRow;
constexpr auto kInlineItemsMaxPerRow = 5;
} // namespace
@ -101,6 +101,7 @@ private:
BasicAnimation _a_icons;
QPoint _iconsMousePos, _iconsMouseDown;
int _iconsLeft = 0;
int _iconsRight = 0;
int _iconsTop = 0;
int _iconsStartX = 0;
int _iconsMax = 0;
@ -117,7 +118,7 @@ StickersListWidget::Footer::Footer(not_null<StickersListWidget*> parent) : Inner
, _a_icons(animation(this, &Footer::step_icons)) {
setMouseTracking(true);
_iconsLeft = (st::emojiPanWidth - kVisibleIconsCount * st::emojiCategory.width) / 2;
_iconsLeft = _iconsRight = st::emojiCategorySkip;
subscribe(Auth().downloaderTaskFinished(), [this] {
update();
@ -127,12 +128,13 @@ StickersListWidget::Footer::Footer(not_null<StickersListWidget*> parent) : Inner
template <typename Callback>
void StickersListWidget::Footer::enumerateVisibleIcons(Callback callback) {
auto iconsX = qRound(_iconsX.current());
auto index = iconsX / st::emojiCategory.width;
auto x = _iconsLeft - (iconsX % st::emojiCategory.width);
for (auto index = qMin(_icons.size(), iconsX / st::emojiCategory.width),
last = qMin(_icons.size(), index + kVisibleIconsCount); index != last; ++index) {
auto index = iconsX / st::stickerIconWidth;
auto x = _iconsLeft - (iconsX % st::stickerIconWidth);
auto first = floorclamp(iconsX, st::stickerIconWidth, 0, _icons.size());
auto last = ceilclamp(iconsX + width(), st::stickerIconWidth, 0, _icons.size());
for (auto index = first; index != last; ++index) {
callback(_icons[index], x);
x += st::emojiCategory.width;
x += st::stickerIconWidth;
}
}
@ -144,7 +146,9 @@ void StickersListWidget::Footer::preloadImages() {
});
}
void StickersListWidget::Footer::validateSelectedIcon(uint64 setId, ValidateIconAnimations animations) {
void StickersListWidget::Footer::validateSelectedIcon(
uint64 setId,
ValidateIconAnimations animations) {
auto newSel = 0;
for (auto i = 0, l = _icons.size(); i != l; ++i) {
if (_icons[i].setId == setId) {
@ -154,13 +158,19 @@ void StickersListWidget::Footer::validateSelectedIcon(uint64 setId, ValidateIcon
}
if (newSel != _iconSel) {
_iconSel = newSel;
auto iconSelXFinal = _iconSel * st::emojiCategory.width;
auto iconSelXFinal = _iconSel * st::stickerIconWidth;
if (animations == ValidateIconAnimations::Full) {
_iconSelX.start(iconSelXFinal);
} else {
_iconSelX = anim::value(iconSelXFinal, iconSelXFinal);
}
auto iconsXFinal = snap((2 * _iconSel + 1 - kVisibleIconsCount) * st::emojiCategory.width / 2, 0, _iconsMax);
auto iconsCountForCentering = (2 * _iconSel + 1);
auto iconsWidthForCentering = iconsCountForCentering
* st::stickerIconWidth;
auto iconsXFinal = snap(
(iconsWidthForCentering - width()) / 2,
0,
_iconsMax);
if (animations == ValidateIconAnimations::None) {
_iconsX = anim::value(iconsXFinal, iconsXFinal);
_a_icons.stop();
@ -202,7 +212,11 @@ void StickersListWidget::Footer::paintEvent(QPaintEvent *e) {
auto selxrel = _iconsLeft + qRound(_iconSelX.current());
auto selx = selxrel - qRound(_iconsX.current());
auto clip = QRect(_iconsLeft, _iconsTop, _iconsLeft + (kVisibleIconsCount - 1) * st::emojiCategory.width - _iconsLeft, st::emojiCategory.height);
auto clip = QRect(
_iconsLeft,
_iconsTop,
width() - _iconsLeft - _iconsRight - st::stickerIconWidth,
st::emojiFooterHeight);
if (rtl()) clip.moveLeft(width() - _iconsLeft - clip.width());
p.setClipRect(clip);
@ -211,9 +225,9 @@ void StickersListWidget::Footer::paintEvent(QPaintEvent *e) {
icon.sticker->thumb->load();
auto pix = icon.sticker->thumb->pix(icon.pixw, icon.pixh);
p.drawPixmapLeft(x + (st::emojiCategory.width - icon.pixw) / 2, _iconsTop + (st::emojiCategory.height - icon.pixh) / 2, width(), pix);
p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix);
} else if (icon.megagroup) {
icon.megagroup->paintUserpicLeft(p, x + (st::emojiCategory.width - st::stickerGroupCategorySize) / 2, _iconsTop + (st::emojiCategory.height - st::stickerGroupCategorySize) / 2, width(), st::stickerGroupCategorySize);
icon.megagroup->paintUserpicLeft(p, x + (st::stickerIconWidth - st::stickerGroupCategorySize) / 2, _iconsTop + (st::emojiFooterHeight - st::stickerGroupCategorySize) / 2, width(), st::stickerGroupCategorySize);
} else {
auto getSpecialSetIcon = [](uint64 setId) {
if (setId == Stickers::FeaturedSetId) {
@ -223,26 +237,27 @@ void StickersListWidget::Footer::paintEvent(QPaintEvent *e) {
}
return &st::emojiRecent;
};
getSpecialSetIcon(icon.setId)->paint(p, x + st::emojiCategory.iconPosition.x(), _iconsTop + st::emojiCategory.iconPosition.y(), width());
auto paintedIcon = getSpecialSetIcon(icon.setId);
paintedIcon->paint(p, x + (st::stickerIconWidth - paintedIcon->width()) / 2, _iconsTop + st::emojiCategory.iconPosition.y(), width());
if (icon.setId == Stickers::FeaturedSetId) {
paintFeaturedStickerSetsBadge(p, x);
}
}
});
if (rtl()) selx = width() - selx - st::emojiCategory.width;
p.fillRect(selx, _iconsTop + st::emojiCategory.height - st::stickerIconPadding, st::emojiCategory.width, st::stickerIconSel, st::stickerIconSelColor);
if (rtl()) selx = width() - selx - st::stickerIconWidth;
p.fillRect(selx, _iconsTop + st::emojiFooterHeight - st::stickerIconPadding, st::stickerIconWidth, st::stickerIconSel, st::stickerIconSelColor);
auto o_left = snap(_iconsX.current() / st::stickerIconLeft.width(), 0., 1.);
if (o_left > 0) {
p.setOpacity(o_left);
st::stickerIconLeft.fill(p, rtlrect(_iconsLeft, _iconsTop, st::stickerIconLeft.width(), st::emojiCategory.height, width()));
st::stickerIconLeft.fill(p, rtlrect(_iconsLeft, _iconsTop, st::stickerIconLeft.width(), st::emojiFooterHeight, width()));
p.setOpacity(1.);
}
auto o_right = snap((_iconsMax - _iconsX.current()) / st::stickerIconRight.width(), 0., 1.);
if (o_right > 0) {
p.setOpacity(o_right);
st::stickerIconRight.fill(p, rtlrect(_iconsLeft + (kVisibleIconsCount - 1) * st::emojiCategory.width - st::stickerIconRight.width(), _iconsTop, st::stickerIconRight.width(), st::emojiCategory.height, width()));
st::stickerIconRight.fill(p, rtlrect(width() - _iconsRight - st::stickerIconWidth - st::stickerIconRight.width(), _iconsTop, st::stickerIconRight.width(), st::emojiFooterHeight, width()));
p.setOpacity(1.);
}
}
@ -306,7 +321,7 @@ void StickersListWidget::Footer::mouseReleaseEvent(QMouseEvent *e) {
updateSelected();
if (wasDown == _iconOver && _iconOver >= 0 && _iconOver < _icons.size()) {
_iconSelX = anim::value(_iconOver * st::emojiCategory.width, _iconOver * st::emojiCategory.width);
_iconSelX = anim::value(_iconOver * st::stickerIconWidth, _iconOver * st::stickerIconWidth);
_pan->showStickerSet(_icons[_iconOver].setId);
}
}
@ -345,17 +360,26 @@ void StickersListWidget::Footer::updateSelected() {
}
auto p = mapFromGlobal(_iconsMousePos);
int32 x = p.x(), y = p.y(), newOver = -1;
auto x = p.x(), y = p.y(), newOver = -1;
if (rtl()) x = width() - x;
auto settingsLeft = width() - _iconsRight - st::stickerIconWidth;
x -= _iconsLeft;
if (x >= st::emojiCategory.width * (kVisibleIconsCount - 1) && x < st::emojiCategory.width * kVisibleIconsCount && y >= _iconsTop && y < _iconsTop + st::emojiCategory.height) {
settingsLeft -= _iconsLeft;
if (x >= settingsLeft
&& x < settingsLeft + st::stickerIconWidth
&& y >= _iconsTop
&& y < _iconsTop + st::emojiFooterHeight) {
if (!_icons.isEmpty() && !hasOnlyFeaturedSets()) {
newOver = _icons.size();
}
} else if (!_icons.isEmpty()) {
if (y >= _iconsTop && y < _iconsTop + st::emojiCategory.height && x >= 0 && x < (kVisibleIconsCount - 1) * st::emojiCategory.width && x < _icons.size() * st::emojiCategory.width) {
if (y >= _iconsTop
&& y < _iconsTop + st::emojiFooterHeight
&& x >= 0
&& x < settingsLeft
&& x < _icons.size() * st::stickerIconWidth) {
x += qRound(_iconsX.current());
newOver = qFloor(x / st::emojiCategory.width);
newOver = qFloor(x / st::stickerIconWidth);
}
}
if (newOver != _iconOver) {
@ -368,18 +392,17 @@ void StickersListWidget::Footer::updateSelected() {
}
}
void StickersListWidget::Footer::refreshIcons(ValidateIconAnimations animations) {
void StickersListWidget::Footer::refreshIcons(
ValidateIconAnimations animations) {
_iconOver = -1;
_pan->fillIcons(_icons);
_iconsX.finish();
_iconSelX.finish();
_iconsStartAnim = 0;
_a_icons.stop();
if (_icons.isEmpty()) {
_iconsMax = 0;
} else {
_iconsMax = qMax(int((_icons.size() + 1 - kVisibleIconsCount) * st::emojiCategory.width), 0);
}
_iconsMax = std::max(
int((_icons.size() + 1) * st::stickerIconWidth) - width(),
0);
if (_iconsX.current() > _iconsMax) {
_iconsX = anim::value(_iconsMax, _iconsMax);
}
@ -393,8 +416,8 @@ bool StickersListWidget::Footer::hasOnlyFeaturedSets() const {
}
void StickersListWidget::Footer::paintStickerSettingsIcon(Painter &p) const {
int settingsLeft = _iconsLeft + (kVisibleIconsCount - 1) * st::emojiCategory.width;
st::stickersSettings.paint(p, settingsLeft + st::emojiCategory.iconPosition.x(), _iconsTop + st::emojiCategory.iconPosition.y(), width());
int settingsLeft = width() - _iconsRight - st::stickerIconWidth;
st::stickersSettings.paint(p, settingsLeft + (st::stickerIconWidth - st::stickersSettings.width()) / 2, _iconsTop + st::emojiCategory.iconPosition.y(), width());
}
void StickersListWidget::Footer::paintFeaturedStickerSetsBadge(Painter &p, int iconLeft) const {
@ -402,7 +425,7 @@ void StickersListWidget::Footer::paintFeaturedStickerSetsBadge(Painter &p, int i
Dialogs::Layout::UnreadBadgeStyle unreadSt;
unreadSt.sizeId = Dialogs::Layout::UnreadBadgeInStickersPanel;
unreadSt.size = st::stickersSettingsUnreadSize;
int unreadRight = iconLeft + st::emojiCategory.width - st::stickersSettingsUnreadPosition.x();
int unreadRight = iconLeft + st::stickerIconWidth - st::stickersSettingsUnreadPosition.x();
if (rtl()) unreadRight = width() - unreadRight;
int unreadTop = _iconsTop + st::stickersSettingsUnreadPosition.y();
Dialogs::Layout::paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, unreadSt);
@ -437,12 +460,10 @@ void StickersListWidget::Footer::step_icons(TimeMs ms, bool timer) {
StickersListWidget::StickersListWidget(QWidget *parent, not_null<Window::Controller*> controller) : Inner(parent, controller)
, _section(Section::Stickers)
, _megagroupSetAbout(st::emojiPanWidth - st::emojiScroll.width - st::emojiPanHeaderLeft)
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st::emojiPanHeaderLeft)
, _addText(lang(lng_stickers_featured_add).toUpper())
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _settings(this, lang(lng_stickers_you_have)) {
updateSize();
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
@ -494,7 +515,7 @@ void StickersListWidget::readVisibleSets() {
if (i * rowHeight < itemsVisibleTop || (i + 1) * rowHeight > itemsVisibleBottom) {
continue;
}
int count = qMin(set.pack.size(), static_cast<int>(kStickersPanelPerRow));
int count = qMin(set.pack.size(), _columnCount);
int loaded = 0;
for (int j = 0; j < count; ++j) {
if (set.pack[j]->thumb->loaded() || set.pack[j]->loaded()) {
@ -508,7 +529,9 @@ void StickersListWidget::readVisibleSets() {
}
int StickersListWidget::featuredRowHeight() const {
return st::stickersTrendingHeader + st::stickerPanSize.height() + st::stickersTrendingSkip;
return st::stickersTrendingHeader
+ _singleSize.height()
+ st::stickersTrendingSkip;
}
template <typename Callback>
@ -524,8 +547,8 @@ bool StickersListWidget::enumerateSections(Callback callback) const {
info.rowsCount = 0;
info.rowsBottom = info.rowsTop + _megagroupSetButtonRect.y() + _megagroupSetButtonRect.height() + st::stickerGroupCategoryAddMargin.bottom();
} else {
info.rowsCount = (info.count / kStickersPanelPerRow) + ((info.count % kStickersPanelPerRow) ? 1 : 0);
info.rowsBottom = info.rowsTop + info.rowsCount * st::stickerPanSize.height();
info.rowsCount = (info.count / _columnCount) + ((info.count % _columnCount) ? 1 : 0);
info.rowsBottom = info.rowsTop + info.rowsCount * _singleSize.height();
}
if (!callback(info)) {
return false;
@ -560,7 +583,21 @@ StickersListWidget::SectionInfo StickersListWidget::sectionInfoByOffset(int yOff
return result;
}
int StickersListWidget::countDesiredHeight() {
int StickersListWidget::countDesiredHeight(int newWidth) {
if (newWidth <= st::stickerPanWidthMin) {
return 0;
}
auto availableWidth = newWidth - (st::stickerPanPadding - st::buttonRadius);
_columnCount = availableWidth / st::stickerPanWidthMin;
auto singleWidth = availableWidth / _columnCount;
auto fullWidth = (st::buttonRadius + newWidth + st::emojiScroll.width);
auto rowsRight = (fullWidth - _columnCount * singleWidth) / 2;
accumulate_max(rowsRight, st::emojiScroll.width);
_rowsLeft = fullWidth
- _columnCount * singleWidth
- rowsRight
- st::buttonRadius;
_singleSize = QSize(singleWidth, singleWidth);
auto visibleHeight = minimalHeight();
auto minimalLastHeight = (visibleHeight - st::stickerPanPadding);
auto countResult = [this, minimalLastHeight] {
@ -591,25 +628,25 @@ void StickersListWidget::clearInstalledLocally() {
}
int StickersListWidget::stickersLeft() const {
return (st::stickerPanPadding - st::buttonRadius);
return _rowsLeft;
}
QRect StickersListWidget::stickerRect(int section, int sel) {
int x = 0, y = 0;
if (_section == Section::Featured) {
x = stickersLeft() + (sel * st::stickerPanSize.width());
x = stickersLeft() + (sel * _singleSize.width());
y = st::stickerPanPadding + (section * featuredRowHeight()) + st::stickersTrendingHeader;
} else if (_section == Section::Stickers) {
auto info = sectionInfo(section);
if (sel >= _mySets[section].pack.size()) {
sel -= _mySets[section].pack.size();
}
auto countTillItem = (sel - (sel % kStickersPanelPerRow));
auto rowsToSkip = (countTillItem / kStickersPanelPerRow) + ((countTillItem % kStickersPanelPerRow) ? 1 : 0);
x = stickersLeft() + ((sel % kStickersPanelPerRow) * st::stickerPanSize.width());
y = info.rowsTop + rowsToSkip * st::stickerPanSize.height();
auto countTillItem = (sel - (sel % _columnCount));
auto rowsToSkip = (countTillItem / _columnCount) + ((countTillItem % _columnCount) ? 1 : 0);
x = stickersLeft() + ((sel % _columnCount) * _singleSize.width());
y = info.rowsTop + rowsToSkip * _singleSize.height();
}
return QRect(x, y, st::stickerPanSize.width(), st::stickerPanSize.height());
return QRect(QPoint(x, y), _singleSize);
}
void StickersListWidget::paintEvent(QPaintEvent *e) {
@ -625,12 +662,12 @@ void StickersListWidget::paintEvent(QPaintEvent *e) {
}
void StickersListWidget::paintFeaturedStickers(Painter &p, QRect clip) {
auto fromColumn = floorclamp(clip.x() - stickersLeft(), st::stickerPanSize.width(), 0, kStickersPanelPerRow);
auto toColumn = ceilclamp(clip.x() + clip.width() - stickersLeft(), st::stickerPanSize.width(), 0, kStickersPanelPerRow);
auto fromColumn = floorclamp(clip.x() - stickersLeft(), _singleSize.width(), 0, _columnCount);
auto toColumn = ceilclamp(clip.x() + clip.width() - stickersLeft(), _singleSize.width(), 0, _columnCount);
if (rtl()) {
qSwap(fromColumn, toColumn);
fromColumn = kStickersPanelPerRow - fromColumn;
toColumn = kStickersPanelPerRow - toColumn;
fromColumn = _columnCount - fromColumn;
toColumn = _columnCount - toColumn;
}
auto &sets = shownSets();
@ -716,12 +753,12 @@ void StickersListWidget::paintFeaturedStickers(Painter &p, QRect clip) {
}
void StickersListWidget::paintStickers(Painter &p, QRect clip) {
auto fromColumn = floorclamp(clip.x() - stickersLeft(), st::stickerPanSize.width(), 0, kStickersPanelPerRow);
auto toColumn = ceilclamp(clip.x() + clip.width() - stickersLeft(), st::stickerPanSize.width(), 0, kStickersPanelPerRow);
auto fromColumn = floorclamp(clip.x() - stickersLeft(), _singleSize.width(), 0, _columnCount);
auto toColumn = ceilclamp(clip.x() + clip.width() - stickersLeft(), _singleSize.width(), 0, _columnCount);
if (rtl()) {
qSwap(fromColumn, toColumn);
fromColumn = kStickersPanelPerRow - fromColumn;
toColumn = kStickersPanelPerRow - toColumn;
fromColumn = _columnCount - fromColumn;
toColumn = _columnCount - toColumn;
}
auto ms = getms();
@ -766,11 +803,11 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
paintMegagroupEmptySet(p, info.rowsTop, buttonSelected, ms);
} else {
auto special = (set.flags & MTPDstickerSet::Flag::f_official) != 0;
auto fromRow = floorclamp(clip.y() - info.rowsTop, st::stickerPanSize.height(), 0, info.rowsCount);
auto toRow = ceilclamp(clip.y() + clip.height() - info.rowsTop, st::stickerPanSize.height(), 0, info.rowsCount);
auto fromRow = floorclamp(clip.y() - info.rowsTop, _singleSize.height(), 0, info.rowsCount);
auto toRow = ceilclamp(clip.y() + clip.height() - info.rowsTop, _singleSize.height(), 0, info.rowsCount);
for (int i = fromRow; i < toRow; ++i) {
for (int j = fromColumn; j < toColumn; ++j) {
int index = i * kStickersPanelPerRow + j;
int index = i * _columnCount + j;
if (index >= info.count) break;
auto selected = selectedSticker ? (selectedSticker->section == info.section && selectedSticker->index == index) : false;
@ -811,13 +848,13 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int index, bo
auto sticker = set.pack[index];
if (!sticker->sticker()) return;
int row = (index / kStickersPanelPerRow), col = (index % kStickersPanelPerRow);
int row = (index / _columnCount), col = (index % _columnCount);
auto pos = QPoint(stickersLeft() + col * st::stickerPanSize.width(), y + row * st::stickerPanSize.height());
auto pos = QPoint(stickersLeft() + col * _singleSize.width(), y + row * _singleSize.height());
if (selected) {
auto tl = pos;
if (rtl()) tl.setX(width() - tl.x() - st::stickerPanSize.width());
App::roundRect(p, QRect(tl, st::stickerPanSize), st::emojiPanHover, StickerHoverCorners);
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
}
auto goodThumb = !sticker->thumb->isNull() && ((sticker->thumb->width() >= 128) || (sticker->thumb->height() >= 128));
@ -827,19 +864,19 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int index, bo
sticker->checkSticker();
}
auto coef = qMin((st::stickerPanSize.width() - st::buttonRadius * 2) / float64(sticker->dimensions.width()), (st::stickerPanSize.height() - st::buttonRadius * 2) / float64(sticker->dimensions.height()));
auto coef = qMin((_singleSize.width() - st::buttonRadius * 2) / float64(sticker->dimensions.width()), (_singleSize.height() - st::buttonRadius * 2) / float64(sticker->dimensions.height()));
if (coef > 1) coef = 1;
auto w = qMax(qRound(coef * sticker->dimensions.width()), 1);
auto h = qMax(qRound(coef * sticker->dimensions.height()), 1);
auto ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
auto ppos = pos + QPoint((_singleSize.width() - w) / 2, (_singleSize.height() - h) / 2);
if (goodThumb) {
p.drawPixmapLeft(ppos, width(), sticker->thumb->pix(w, h));
p.drawPixmapLeft(ppos, width(), sticker->thumb->pixSingle(w, h, w, h, ImageRoundRadius::None));
} else if (!sticker->sticker()->img->isNull()) {
p.drawPixmapLeft(ppos, width(), sticker->sticker()->img->pix(w, h));
p.drawPixmapLeft(ppos, width(), sticker->sticker()->img->pixSingle(w, h, w, h, ImageRoundRadius::None));
}
if (selected && stickerHasDeleteButton(set, index)) {
auto xPos = pos + QPoint(st::stickerPanSize.width() - st::stickerPanDeleteIconBg.width(), 0);
auto xPos = pos + QPoint(_singleSize.width() - st::stickerPanDeleteIconBg.width(), 0);
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityBgOver : st::stickerPanDeleteOpacityBg);
st::stickerPanDeleteIconBg.paint(p, xPos, width());
p.setOpacity(deleteSelected ? st::stickerPanDeleteOpacityFgOver : st::stickerPanDeleteOpacityFg);
@ -849,7 +886,7 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int index, bo
}
int StickersListWidget::stickersRight() const {
return stickersLeft() + (kStickersPanelPerRow * st::stickerPanSize.width());
return stickersLeft() + (_columnCount * _singleSize.width());
}
bool StickersListWidget::featuredHasAddButton(int index) const {
@ -1089,7 +1126,9 @@ void StickersListWidget::mouseMoveEvent(QMouseEvent *e) {
}
void StickersListWidget::resizeEvent(QResizeEvent *e) {
_settings->moveToLeft((st::emojiPanWidth - _settings->width()) / 2, height() / 3);
_settings->moveToLeft(
(width() - _settings->width()) / 2,
height() / 3);
}
void StickersListWidget::leaveEventHook(QEvent *e) {
@ -1152,9 +1191,9 @@ void StickersListWidget::refreshStickers() {
appendSet(_featuredSets, setId, AppendSkip::Installed);
}
updateSize();
resizeToWidth(width());
if (_footer) {
if (_footer && _columnCount > 0) {
_footer->refreshIcons(ValidateIconAnimations::None);
if (_footer->hasOnlyFeaturedSets() && _section != Section::Featured) {
showStickerSet(Stickers::FeaturedSetId);
@ -1173,10 +1212,10 @@ void StickersListWidget::preloadImages() {
for (int i = 0, l = sets.size(), k = 0; i < l; ++i) {
int count = sets[i].pack.size();
if (_section == Section::Featured) {
accumulate_min(count, kStickersPanelPerRow);
accumulate_min(count, _columnCount);
}
for (int j = 0; j != count; ++j) {
if (++k > kStickersPanelPerRow * (kStickersPanelPerRow + 1)) break;
if (++k > _columnCount * (_columnCount + 1)) break;
auto sticker = sets.at(i).pack.at(j);
if (!sticker || !sticker->sticker()) continue;
@ -1188,7 +1227,7 @@ void StickersListWidget::preloadImages() {
sticker->automaticLoad(0);
}
}
if (k > kStickersPanelPerRow * (kStickersPanelPerRow + 1)) break;
if (k > _columnCount * (_columnCount + 1)) break;
}
if (_footer) {
_footer->preloadImages();
@ -1278,7 +1317,7 @@ void StickersListWidget::refreshRecentStickers(bool performResize) {
}
if (performResize && (_section == Section::Stickers || _section == Section::Featured)) {
updateSize();
resizeToWidth(width());
updateSelected();
}
}
@ -1370,7 +1409,7 @@ void StickersListWidget::fillIcons(QList<StickerIcon> &icons) {
continue;
}
auto s = _mySets[i].pack[0];
auto availw = st::emojiCategory.width - 2 * st::stickerIconPadding, availh = st::emojiCategory.height - 2 * st::stickerIconPadding;
auto availw = st::stickerIconWidth - 2 * st::stickerIconPadding, availh = st::emojiFooterHeight - 2 * st::stickerIconPadding;
auto thumbw = s->thumb->width(), thumbh = s->thumb->height(), pixw = 1, pixh = 1;
if (availw * thumbh > availh * thumbw) {
pixh = availh;
@ -1421,9 +1460,9 @@ void StickersListWidget::updateSelected() {
} else {
newSelected = OverSet { section };
}
} else if (yOffset >= st::stickersTrendingHeader && yOffset < st::stickersTrendingHeader + st::stickerPanSize.height()) {
if (sx >= 0 && sx < kStickersPanelPerRow * st::stickerPanSize.width()) {
auto index = qFloor(sx / st::stickerPanSize.width());
} else if (yOffset >= st::stickersTrendingHeader && yOffset < st::stickersTrendingHeader + _singleSize.height()) {
if (sx >= 0 && sx < _columnCount * _singleSize.width()) {
auto index = qFloor(sx / _singleSize.width());
if (index >= 0 && index < set.pack.size()) {
auto overDelete = false;
newSelected = OverSticker { section, index, overDelete };
@ -1452,15 +1491,15 @@ void StickersListWidget::updateSelected() {
}
} else {
auto special = ((set.flags & MTPDstickerSet::Flag::f_official) != 0);
auto rowIndex = qFloor(yOffset / st::stickerPanSize.height());
auto columnIndex = qFloor(sx / st::stickerPanSize.width());
auto index = rowIndex * kStickersPanelPerRow + columnIndex;
auto rowIndex = qFloor(yOffset / _singleSize.height());
auto columnIndex = qFloor(sx / _singleSize.width());
auto index = rowIndex * _columnCount + columnIndex;
if (index >= 0 && index < set.pack.size()) {
auto overDelete = false;
if (stickerHasDeleteButton(set, index)) {
auto inx = sx - (columnIndex * st::stickerPanSize.width());
auto iny = yOffset - (rowIndex * st::stickerPanSize.height());
if (inx >= st::stickerPanSize.width() - st::stickerPanDeleteIconBg.width() && iny < st::stickerPanDeleteIconBg.height()) {
auto inx = sx - (columnIndex * _singleSize.width());
auto iny = yOffset - (rowIndex * _singleSize.height());
if (inx >= _singleSize.width() - st::stickerPanDeleteIconBg.width() && iny < st::stickerPanDeleteIconBg.height()) {
overDelete = true;
}
}

View file

@ -82,7 +82,7 @@ protected:
TabbedSelector::InnerFooter *getFooter() const override;
void processHideFinished() override;
void processPanelHideFinished() override;
int countDesiredHeight() override;
int countDesiredHeight(int newWidth) override;
private slots:
void onSettings();
@ -231,6 +231,9 @@ private:
uint64 _removingSetId = 0;
Footer *_footer = nullptr;
int _rowsLeft = 0;
int _columnCount = 0;
QSize _singleSize;
OverState _selected;
OverState _pressed;

View file

@ -37,11 +37,13 @@ object_ptr<Window::SectionWidget> TabbedMemento::createWidget(
not_null<Window::Controller*> controller,
Window::Column column,
const QRect &geometry) {
return object_ptr<TabbedSection>(
auto result = object_ptr<TabbedSection>(
parent,
controller,
std::move(_selector),
std::move(_returnMethod));
result->setGeometry(geometry);
return std::move(result);
}
TabbedMemento::~TabbedMemento() {
@ -68,8 +70,6 @@ TabbedSection::TabbedSection(
: Window::SectionWidget(parent, controller)
, _selector(std::move(selector))
, _returnMethod(std::move(returnMethod)) {
resize(st::emojiPanWidth, st::emojiPanMaxHeight);
_selector->setParent(this);
_selector->setRoundRadius(0);
_selector->setGeometry(rect());

View file

@ -107,7 +107,7 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage
_painterInnerBottom = _innerBottom / cIntRetinaFactor();
_painterInnerWidth = _innerWidth / cIntRetinaFactor();
_painterInnerHeight = _innerHeight / cIntRetinaFactor();
_painterCategoriesTop = _painterInnerBottom - st::emojiCategory.height;
_painterCategoriesTop = _painterInnerBottom - st::emojiFooterHeight;
_wasSectionIcons = wasSectionIcons;
}
@ -299,8 +299,6 @@ TabbedSelector::TabbedSelector(QWidget *parent, not_null<Window::Controller*> co
}
createTabsSlider();
_scroll->setGeometryToLeft(st::buttonRadius, marginTop(), st::emojiPanWidth - st::buttonRadius, height() - marginTop() - marginBottom());
setWidgetToScrollArea();
_bottomShadow->setGeometry(_tabsSlider->x(), _scroll->y() + _scroll->height() - st::lineWidth, _tabsSlider->width(), st::lineWidth);
@ -355,26 +353,47 @@ TabbedSelector::TabbedSelector(QWidget *parent, not_null<Window::Controller*> co
}
void TabbedSelector::resizeEvent(QResizeEvent *e) {
auto contentHeight = height() - marginTop() - marginBottom();
_tabsSlider->resizeToWidth(width());
_tabsSlider->moveToLeft(0, 0);
_topShadow->setGeometry(
_tabsSlider->x(),
_tabsSlider->bottomNoMargins() - st::lineWidth,
_tabsSlider->width(),
st::lineWidth);
auto scrollWidth = width() - st::buttonRadius;
auto scrollHeight = height() - marginTop() - marginBottom();
auto inner = currentTab()->widget();
auto innerWidth = scrollWidth - st::emojiScroll.width;
auto updateScrollGeometry = [&] {
_scroll->setGeometryToLeft(
st::buttonRadius,
marginTop(),
scrollWidth,
scrollHeight);
};
auto updateInnerGeometry = [&] {
auto scrollTop = _scroll->scrollTop();
auto scrollBottom = scrollTop + scrollHeight;
inner->setMinimalHeight(innerWidth, scrollHeight);
inner->setVisibleTopBottom(scrollTop, scrollBottom);
};
if (e->oldSize().height() > height()) {
_scroll->resize(_scroll->width(), contentHeight);
auto scrollTop = _scroll->scrollTop();
currentTab()->widget()->setMinimalHeight(contentHeight);
currentTab()->widget()->setVisibleTopBottom(scrollTop, scrollTop + contentHeight);
updateScrollGeometry();
updateInnerGeometry();
} else {
auto scrollTop = _scroll->scrollTop();
currentTab()->widget()->setMinimalHeight(contentHeight);
currentTab()->widget()->setVisibleTopBottom(scrollTop, scrollTop + contentHeight);
_scroll->resize(_scroll->width(), contentHeight);
updateInnerGeometry();
updateScrollGeometry();
}
_bottomShadow->setGeometry(_tabsSlider->x(), _scroll->y() + _scroll->height() - st::lineWidth, _tabsSlider->width(), st::lineWidth);
if (_restrictedLabel) {
_restrictedLabel->move((width() - _restrictedLabel->width()), (height() / 3 - _restrictedLabel->height() / 2));
}
_footerTop = height() - st::emojiCategory.height;
_footerTop = height() - st::emojiFooterHeight;
for (auto &tab : _tabs) {
tab.footer()->move(_tabsSlider->x(), _footerTop);
tab.footer()->resizeToWidth(width());
tab.footer()->moveToLeft(0, _footerTop);
}
update();
@ -416,12 +435,12 @@ void TabbedSelector::paintContent(Painter &p) {
auto topPart = QRect(0, 0, width(), _tabsSlider->height() + _roundRadius);
App::roundRect(p, topPart, st::emojiPanBg, ImageRoundRadius::Small, RectPart::FullTop | RectPart::NoTopBottom);
auto bottomPart = QRect(0, _footerTop - _roundRadius, width(), st::emojiCategory.height + _roundRadius);
auto bottomPart = QRect(0, _footerTop - _roundRadius, width(), st::emojiFooterHeight + _roundRadius);
auto bottomParts = RectPart::NoTopBottom | RectPart::FullBottom;
App::roundRect(p, bottomPart, bottomBg, ImageRoundRadius::Small, bottomParts);
} else {
p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg);
p.fillRect(0, _footerTop, width(), st::emojiCategory.height, bottomBg);
p.fillRect(0, _footerTop, width(), st::emojiFooterHeight, bottomBg);
}
auto sidesTop = marginTop();
@ -439,7 +458,7 @@ int TabbedSelector::marginTop() const {
}
int TabbedSelector::marginBottom() const {
return st::emojiCategory.height;
return st::emojiFooterHeight;
}
void TabbedSelector::refreshStickers() {
@ -606,10 +625,6 @@ void TabbedSelector::createTabsSlider() {
| rpl::start_with_next(
[this] { switchTab(); },
lifetime());
_tabsSlider->resizeToWidth(width());
_tabsSlider->moveToLeft(0, 0);
_topShadow->setGeometry(_tabsSlider->x(), _tabsSlider->bottomNoMargins() - st::lineWidth, _tabsSlider->width(), st::lineWidth);
}
bool TabbedSelector::hasSectionIcons() const {
@ -683,10 +698,12 @@ not_null<GifsListWidget*> TabbedSelector::gifs() const {
}
void TabbedSelector::setWidgetToScrollArea() {
_scroll->setOwnedWidget(currentTab()->takeWidget());
auto inner = _scroll->setOwnedWidget(currentTab()->takeWidget());
inner->resizeToWidth(_scroll->width() - st::emojiScroll.width);
inner->moveToLeft(0, 0);
inner->show();
_scroll->disableScroll(false);
currentTab()->widget()->moveToLeft(0, 0);
currentTab()->widget()->show();
scrollToY(currentTab()->getScrollTop());
onScroll();
}
@ -710,30 +727,32 @@ void TabbedSelector::Inner::visibleTopBottomUpdated(int visibleTop, int visibleB
_visibleBottom = visibleBottom;
}
void TabbedSelector::Inner::setMinimalHeight(int newMinimalHeight) {
void TabbedSelector::Inner::setMinimalHeight(
int newWidth,
int newMinimalHeight) {
if (_minimalHeight != newMinimalHeight) {
_minimalHeight = newMinimalHeight;
updateSize();
resizeToWidth(newWidth);
} else if (newWidth != width()) {
resizeToWidth(newWidth);
}
}
void TabbedSelector::Inner::updateSize() {
auto width = st::emojiPanWidth
- st::emojiScroll.width
- st::buttonRadius;
auto height = qMax(countDesiredHeight(), minimalHeight());
auto newSize = QSize(width, height);
if (size() != newSize) {
resize(newSize);
int TabbedSelector::Inner::resizeGetHeight(int newWidth) {
auto result = std::max(
countDesiredHeight(newWidth),
minimalHeight());
if (result != height()) {
update();
}
return result;
}
int TabbedSelector::Inner::minimalHeight() const {
auto result = _minimalHeight;
return (_minimalHeight > 0)
? _minimalHeight
: (st::emojiPanMaxHeight - st::emojiCategory.height);
: (st::emojiPanMaxHeight - st::emojiFooterHeight);
}
void TabbedSelector::Inner::hideFinished() {
@ -751,8 +770,9 @@ void TabbedSelector::Inner::panelHideFinished() {
}
}
TabbedSelector::InnerFooter::InnerFooter(QWidget *parent) : TWidget(parent) {
resize(st::emojiPanWidth, st::emojiCategory.height);
TabbedSelector::InnerFooter::InnerFooter(QWidget *parent)
: TWidget(parent) {
resize(st::emojiPanWidth, st::emojiFooterHeight);
}
} // namespace ChatHelpers

View file

@ -218,7 +218,7 @@ public:
int getVisibleBottom() const {
return _visibleBottom;
}
void setMinimalHeight(int newMinimalHeight);
void setMinimalHeight(int newWidth, int newMinimalHeight);
virtual void refreshRecent() = 0;
virtual void preloadImages() {
@ -242,14 +242,14 @@ protected:
void visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) override;
void updateSize();
int minimalHeight() const;
int resizeGetHeight(int newWidth) override final;
not_null<Window::Controller*> controller() const {
return _controller;
}
virtual int countDesiredHeight() = 0;
virtual int countDesiredHeight(int newWidth) = 0;
virtual InnerFooter *getFooter() const = 0;
virtual void processHideFinished() {
}

View file

@ -3789,16 +3789,13 @@ void HistoryWidget::topBarClick() {
}
}
void HistoryWidget::pushTabbedSelectorToThirdSection() {
void HistoryWidget::pushTabbedSelectorToThirdSection(
const Window::SectionShow &params) {
if (!_history || !_tabbedPanel) {
return;
} else if (!_canSendMessages) {
Auth().data().setTabbedReplacedWithInfo(true);
controller()->showPeerInfo(_peer,
Window::SectionShow(
Window::SectionShow::Way::ClearStack,
anim::type::instant,
anim::activation::background));
controller()->showPeerInfo(_peer, params);
return;
}
Auth().data().setTabbedReplacedWithInfo(false);
@ -3814,25 +3811,16 @@ void HistoryWidget::pushTabbedSelectorToThirdSection() {
returnTabbedSelector(std::move(selector));
}));
controller()->resizeForThirdSection();
controller()->showSection(
std::move(memento),
Window::SectionShow(
Window::SectionShow::Way::ClearStack,
anim::type::instant,
anim::activation::background));
controller()->showSection(std::move(memento), params);
destroyingPanel.destroy();
}
void HistoryWidget::pushInfoToThirdSection() {
void HistoryWidget::pushInfoToThirdSection(
const Window::SectionShow &params) {
if (!_peer) {
return;
}
controller()->showPeerInfo(
_peer,
Window::SectionShow(
Window::SectionShow::Way::ClearStack,
anim::type::instant,
anim::activation::background));
controller()->showPeerInfo(_peer, params);
}
void HistoryWidget::toggleTabbedSelectorMode() {
@ -3841,7 +3829,8 @@ void HistoryWidget::toggleTabbedSelectorMode() {
&& !Adaptive::OneColumn()) {
Auth().data().setTabbedSelectorSectionEnabled(true);
Auth().saveDataDelayed();
pushTabbedSelectorToThirdSection();
pushTabbedSelectorToThirdSection(
Window::SectionShow::Way::ClearStack);
} else {
_tabbedPanel->toggleAnimated();
}

View file

@ -208,8 +208,10 @@ public:
void unreadCountChanged(History *history);
QRect historyRect() const;
void pushTabbedSelectorToThirdSection();
void pushInfoToThirdSection();
void pushTabbedSelectorToThirdSection(
const Window::SectionShow &params);
void pushInfoToThirdSection(
const Window::SectionShow &params);
void updateSendAction(History *history, SendAction::Type type, int32 progress = 0);
void cancelSendAction(History *history, SendAction::Type type);

View file

@ -362,7 +362,7 @@ infoProfileButton: InfoProfileButton {
textBg: windowBg;
textBgOver: windowBgOver;
font: semiboldFont;
font: normalFont;
height: 20px;
padding: margins(79px, 10px, 8px, 8px);

View file

@ -3388,10 +3388,14 @@ void MainWidget::updateControlsGeometry() {
if (Adaptive::ThreeColumn()) {
if (!_thirdSection
&& !_controller->takeThirdSectionFromLayer()) {
auto params = Window::SectionShow(
Window::SectionShow::Way::ClearStack,
anim::type::instant,
anim::activation::background);
if (Auth().data().tabbedSelectorSectionEnabled()) {
_history->pushTabbedSelectorToThirdSection();
_history->pushTabbedSelectorToThirdSection(params);
} else if (Auth().data().thirdSectionInfoEnabled()) {
_history->pushInfoToThirdSection();
_history->pushInfoToThirdSection(params);
}
}
} else {
@ -3507,18 +3511,17 @@ void MainWidget::updateThirdColumnToCurrentPeer(
_thirdSection->createMemento());
}
};
auto params = Window::SectionShow(
Window::SectionShow::Way::ClearStack,
anim::type::instant,
anim::activation::background);
auto switchInfoFast = [&] {
saveOldThirdSection();
_controller->showPeerInfo(
peer,
SectionShow(
SectionShow::Way::ClearStack,
anim::type::instant,
anim::activation::background));
_controller->showPeerInfo(peer, params);
};
auto switchTabbedFast = [&] {
saveOldThirdSection();
_history->pushTabbedSelectorToThirdSection();
_history->pushTabbedSelectorToThirdSection(params);
};
if (Adaptive::ThreeColumn()
&& Auth().data().tabbedSelectorSectionEnabled()

View file

@ -32,7 +32,7 @@ windowShadowShift: 1px;
columnMinimalWidthLeft: 260px;
columnMinimalWidthMain: 380px;
columnMinimalWidthThird: 345px;
columnMinimalWidthThird: 292px;//345px;
adaptiveChatWideWidth: 880px;

View file

@ -162,7 +162,8 @@ void Controller::resizeForThirdSection() {
st::columnMinimalWidthThird);
auto newBodyWidth = layout.bodyWidth + extendBy;
auto currentRatio = Auth().data().dialogsWidthRatio();
Auth().data().setDialogsWidthRatio((currentRatio * layout.bodyWidth) / newBodyWidth);
Auth().data().setDialogsWidthRatio(
(currentRatio * layout.bodyWidth) / newBodyWidth);
window()->tryToExtendWidthBy(extendBy);
Auth().data().setTabbedSelectorSectionEnabled(