From 793f748d2e24d6dc7841754aeebd7a3f2e46b79b Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 26 Jul 2021 03:25:33 +0300 Subject: [PATCH] Replaced overview and inline mosaic layouts with new mosaic layout. --- Telegram/CMakeLists.txt | 4 - .../chat_helpers/gifs_list_widget.cpp | 45 ++- .../chat_helpers/gifs_list_widget.h | 4 +- .../info/media/info_media_list_widget.cpp | 22 +- .../inline_bots/inline_results_inner.cpp | 60 +-- .../inline_bots/inline_results_inner.h | 5 +- .../inline_results_mosaic_layout.cpp | 341 ------------------ .../inline_results_mosaic_layout.h | 76 ---- .../overview/overview_mosaic_layout.cpp | 327 ----------------- .../overview/overview_mosaic_layout.h | 72 ---- 10 files changed, 85 insertions(+), 871 deletions(-) delete mode 100644 Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.cpp delete mode 100644 Telegram/SourceFiles/overview/overview_mosaic_layout.cpp diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index a4d9b03e4d..b4deb047a0 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -676,8 +676,6 @@ PRIVATE inline_bots/inline_bot_send_data.h inline_bots/inline_results_inner.cpp inline_bots/inline_results_inner.h - inline_bots/inline_results_mosaic_layout.cpp - inline_bots/inline_results_mosaic_layout.h inline_bots/inline_results_widget.cpp inline_bots/inline_results_widget.h intro/intro_code.cpp @@ -817,8 +815,6 @@ PRIVATE overview/overview_layout.cpp overview/overview_layout.h overview/overview_layout_delegate.h - overview/overview_mosaic_layout.cpp - overview/overview_mosaic_layout.h passport/passport_encryption.cpp passport/passport_encryption.h passport/passport_form_controller.cpp diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 4db2e974d8..4e9993ace6 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -202,6 +202,11 @@ GifsListWidget::GifsListWidget( ) | rpl::start_with_next([=](const QSize &s) { _mosaic.setFullWidth(s.width()); }, lifetime()); + + _mosaic.setOffset( + st::inlineResultsLeft - st::roundRadiusSmall, + st::stickerPanPadding); + _mosaic.setRightSkip(st::inlineResultsSkip); } rpl::producer GifsListWidget::fileChosen() const { @@ -337,12 +342,15 @@ void GifsListWidget::paintInlineItems(Painter &p, QRect clip) { using namespace InlineBots::Layout; PaintContext context(crl::now(), false, gifPaused, false); - _mosaic.paint( - p, - st::stickerPanPadding, - st::inlineResultsLeft - st::roundRadiusSmall, - clip, - context); + auto paintItem = [&](const not_null item, QPoint point) { + p.translate(point.x(), point.y()); + item->paint( + p, + clip.translated(-point), + &context); + p.translate(-point.x(), -point.y()); + }; + _mosaic.paint(std::move(paintItem), clip); } void GifsListWidget::mousePressEvent(QMouseEvent *e) { @@ -520,7 +528,7 @@ void GifsListWidget::refreshSavedGifs() { return layoutPrepareSavedGif(gif); }) | ranges::views::filter([](const LayoutItem *item) { return item != nullptr; - }) | ranges::to_vector; + }) | ranges::to>>; _mosaic.addItems(layouts); } @@ -610,7 +618,9 @@ void GifsListWidget::deleteUnusedInlineLayouts() { } void GifsListWidget::preloadImages() { - _mosaic.preloadImages(); + _mosaic.forEach([](const not_null item) { + item->preload(); + }); } void GifsListWidget::switchToSavedGifs() { @@ -645,10 +655,11 @@ int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool result return layoutPrepareInlineResult(r.get()); }) | ranges::views::filter([](const LayoutItem *item) { return item != nullptr; - }) | ranges::to_vector; + }) | ranges::to>>; _mosaic.addItems(resultLayouts); added = resultLayouts.size(); + preloadImages(); } resizeToWidth(width()); @@ -661,7 +672,11 @@ int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool result } int GifsListWidget::validateExistingInlineRows(const InlineResults &results) { - const auto until = _mosaic.validateExistingRows(results); + const auto until = _mosaic.validateExistingRows([&]( + const not_null item, + int untilIndex) { + return item->getResult() != results[untilIndex].get(); + }, results.size()); if (_mosaic.empty()) { _inlineWithThumb = false; @@ -853,10 +868,12 @@ void GifsListWidget::updateSelected() { } const auto p = mapFromGlobal(_lastMousePos); - const auto sx = (rtl() ? width() - p.x() : p.x()) - - (st::inlineResultsLeft - st::roundRadiusSmall); - const auto sy = p.y() - st::stickerPanPadding; - const auto &[link, item, selected] = _mosaic.findByPoint({ sx, sy }); + const auto sx = rtl() ? (width() - p.x()) : p.x(); + const auto sy = p.y(); + const auto &[index, exact, relative] = _mosaic.findByPoint({ sx, sy }); + const auto selected = exact ? index : -1; + const auto item = exact ? _mosaic.itemAt(selected) : nullptr; + const auto link = exact ? item->getState(relative, {}).link : nullptr; if (_selected != selected) { if (const auto s = _mosaic.maybeItemAt(_selected)) { diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h index 0c0628d0b8..fe83d2630d 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h @@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/tabbed_selector.h" #include "base/timer.h" #include "inline_bots/inline_bot_layout_item.h" -#include "inline_bots/inline_results_mosaic_layout.h" +#include "layout/layout_mosaic.h" #include "app.h" #include @@ -167,7 +167,7 @@ private: Footer *_footer = nullptr; - InlineBots::Layout::MosaicLayout _mosaic; + Mosaic::Layout::MosaicLayout _mosaic; int _selected = -1; int _pressed = -1; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index af1f8979c4..c202cb4dd3 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/info_controller.h" #include "overview/overview_layout.h" -#include "overview/overview_mosaic_layout.h" +#include "layout/layout_mosaic.h" #include "data/data_media_types.h" #include "data/data_photo.h" #include "data/data_document.h" @@ -42,8 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include -namespace Layout = Overview::Layout; - namespace Info { namespace Media { namespace { @@ -88,7 +86,7 @@ bool HasFloatingHeader(Type type) { } // namespace struct ListWidget::Context { - Layout::PaintContext layoutContext; + Overview::Layout::PaintContext layoutContext; not_null selected; not_null dragSelected; DragSelectAction dragSelectAction; @@ -98,7 +96,8 @@ class ListWidget::Section { public: Section(Type type) : _type(type) - , _hasFloatingHeader(HasFloatingHeader(type)) { + , _hasFloatingHeader(HasFloatingHeader(type)) + , _mosaic(st::emojiPanWidth - st::inlineResultsLeft) { } bool addItem(not_null item); @@ -186,7 +185,7 @@ private: int _top = 0; int _height = 0; - Overview::Layout::MosaicLayout _mosaic; + Mosaic::Layout::MosaicLayout _mosaic; }; @@ -333,9 +332,10 @@ auto ListWidget::Section::findItemByPoint( Expects(!_items.empty()); if (!_mosaic.empty()) { const auto found = _mosaic.findByPoint(point); - Assert(found.item != nullptr); - const auto rect = findItemRect(found.item); - return { found.item, rect, found.exact }; + Assert(found.index != -1); + const auto item = _mosaic.itemAt(found.index); + const auto rect = findItemRect(item); + return { item, rect, found.exact }; } auto itemIt = findItemAfterTop(point.y()); if (itemIt == _items.end()) { @@ -1030,7 +1030,7 @@ std::unique_ptr ListWidget::createLayout( }; auto &songSt = st::overviewFileLayout; - using namespace Layout; + using namespace Overview::Layout; switch (type) { case Type::Photo: if (const auto photo = getPhoto()) { @@ -1386,7 +1386,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { fromSectionIt, clip.y() + clip.height()); auto context = Context { - Layout::PaintContext(ms, hasSelectedItems()), + Overview::Layout::PaintContext(ms, hasSelectedItems()), &_selected, &_dragSelected, _dragSelectAction diff --git a/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp b/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp index 7e8dcd973c..ef8f78e8b5 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_inner.cpp @@ -79,6 +79,8 @@ Inner::Inner( ) | rpl::start_with_next([=](const QSize &s) { _mosaic.setFullWidth(s.width()); }, lifetime()); + + _mosaic.setRightSkip(st::inlineResultsSkip); } void Inner::visibleTopBottomUpdated( @@ -189,16 +191,15 @@ void Inner::paintInlineItems(Painter &p, const QRect &r) { context.pathGradient = _pathGradient.get(); context.pathGradient->startFrame(0, width(), width() / 2); - const auto top = st::stickerPanPadding - + (_switchPmButton - ? _switchPmButton->height() + st::inlineResultsSkip - : 0); - _mosaic.paint( - p, - top, - st::inlineResultsLeft - st::roundRadiusSmall, - r, - context); + auto paintItem = [&](const not_null item, QPoint point) { + p.translate(point.x(), point.y()); + item->paint( + p, + r.translated(-point), + &context); + p.translate(-point.x(), -point.y()); + }; + _mosaic.paint(std::move(paintItem), r); } void Inner::mousePressEvent(QMouseEvent *e) { @@ -377,7 +378,9 @@ void Inner::deleteUnusedInlineLayouts() { } void Inner::preloadImages() { - _mosaic.preloadImages(); + _mosaic.forEach([](const not_null item) { + item->preload(); + }); } void Inner::hideInlineRowsPanel() { @@ -388,6 +391,16 @@ void Inner::clearInlineRowsPanel() { clearInlineRows(false); } +void Inner::refreshMosaicOffset() { + const auto top = st::stickerPanPadding + + (_switchPmButton + ? _switchPmButton->height() + st::inlineResultsSkip + : 0); + _mosaic.setOffset( + st::inlineResultsLeft - st::roundRadiusSmall, + top); +} + void Inner::refreshSwitchPmButton(const CacheEntry *entry) { if (!entry || entry->switchPmText.isEmpty()) { _switchPmButton.destroy(); @@ -414,6 +427,7 @@ int Inner::refreshInlineRows(PeerData *queryPeer, UserData *bot, const CacheEntr _inlineBot = bot; _inlineQueryPeer = queryPeer; refreshSwitchPmButton(entry); + refreshMosaicOffset(); auto clearResults = [&] { if (!entry) { return true; @@ -449,10 +463,11 @@ int Inner::refreshInlineRows(PeerData *queryPeer, UserData *bot, const CacheEntr return layoutPrepareInlineResult(r.get()); }) | ranges::views::filter([](const ItemBase *item) { return item != nullptr; - }) | ranges::to_vector; + }) | ranges::to>>; _mosaic.addItems(resultItems); added = resultItems.size(); + preloadImages(); } auto h = countHeight(); @@ -466,7 +481,11 @@ int Inner::refreshInlineRows(PeerData *queryPeer, UserData *bot, const CacheEntr } int Inner::validateExistingInlineRows(const Results &results) { - const auto until = _mosaic.validateExistingRows(results); + const auto until = _mosaic.validateExistingRows([&]( + const not_null item, + int untilIndex) { + return item->getResult() != results[untilIndex].get(); + }, results.size()); if (_mosaic.empty()) { _inlineWithThumb = false; @@ -528,15 +547,12 @@ void Inner::updateSelected() { } const auto p = mapFromGlobal(_lastMousePos); - - const auto sx = (rtl() ? width() - p.x() : p.x()) - - (st::inlineResultsLeft - st::roundRadiusSmall); - const auto sy = p.y() - - st::stickerPanPadding - - (_switchPmButton - ? _switchPmButton->height() + st::inlineResultsSkip - : 0); - const auto &[link, item, selected] = _mosaic.findByPoint({ sx, sy }); + const auto sx = rtl() ? (width() - p.x()) : p.x(); + const auto sy = p.y(); + const auto &[index, exact, relative] = _mosaic.findByPoint({ sx, sy }); + const auto selected = exact ? index : -1; + const auto item = exact ? _mosaic.itemAt(selected) : nullptr; + const auto link = exact ? item->getState(relative, {}).link : nullptr; if (_selected != selected) { if (const auto s = _mosaic.maybeItemAt(_selected)) { diff --git a/Telegram/SourceFiles/inline_bots/inline_results_inner.h b/Telegram/SourceFiles/inline_bots/inline_results_inner.h index 9338b43d84..405ab3275e 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_inner.h +++ b/Telegram/SourceFiles/inline_bots/inline_results_inner.h @@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" #include "mtproto/sender.h" #include "inline_bots/inline_bot_layout_item.h" -#include "inline_bots/inline_results_mosaic_layout.h" +#include "layout/layout_mosaic.h" namespace Api { struct SendOptions; @@ -131,6 +131,7 @@ private: void paintInlineItems(Painter &p, const QRect &r); void refreshSwitchPmButton(const CacheEntry *entry); + void refreshMosaicOffset(); void showPreview(); void updateInlineItems(); @@ -165,7 +166,7 @@ private: base::unique_qptr _menu; - InlineBots::Layout::MosaicLayout _mosaic; + Mosaic::Layout::MosaicLayout _mosaic; std::map> _inlineLayouts; diff --git a/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.cpp b/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.cpp deleted file mode 100644 index a67f5b59b0..0000000000 --- a/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "inline_bots/inline_results_mosaic_layout.h" - -#include "history/view/history_view_cursor_state.h" -#include "layout/layout_position.h" -#include "styles/style_chat_helpers.h" - -namespace InlineBots::Layout { -namespace { - -constexpr auto kInlineItemsMaxPerRow = 5; - -} // namespace - -MosaicLayout::MosaicLayout(int bigWidth) -: _bigWidth(bigWidth) { -} - -void MosaicLayout::setFullWidth(int w) { - _width = w; -} - -bool MosaicLayout::empty() const { - return _rows.empty(); -} - -int MosaicLayout::rowsCount() const { - return _rows.size(); -} - -int MosaicLayout::countDesiredHeight(int newWidth) { - auto result = 0; - for (auto &row : _rows) { - layoutRow(row, newWidth); - result += row.height; - } - return result; -} - -not_null MosaicLayout::itemAt(int row, int column) const { - Expects((row >= 0) - && (row < _rows.size()) - && (column >= 0) - && (column < _rows[row].items.size())); - return _rows[row].items[column]; -} - -not_null MosaicLayout::itemAt(int index) const { - const auto &[row, column] = ::Layout::IndexToPosition(index); - return itemAt(row, column); -} - -ItemBase *MosaicLayout::maybeItemAt(int row, int column) const { - if ((row >= 0) - && (row < _rows.size()) - && (column >= 0) - && (column < _rows[row].items.size())) { - return _rows[row].items[column]; - } - return nullptr; -} - -ItemBase *MosaicLayout::maybeItemAt(int index) const { - const auto &[row, column] = ::Layout::IndexToPosition(index); - return maybeItemAt(row, column); -} - -void MosaicLayout::addItems(const std::vector &items) { - _rows.reserve(items.size()); - auto row = Row(); - row.items.reserve(kInlineItemsMaxPerRow); - auto sumWidth = 0; - for (const auto &item : items) { - addItem(item, row, sumWidth); - } - rowFinalize(row, sumWidth, true); -} - -void MosaicLayout::addItem( - not_null item, - Row &row, - int &sumWidth) { - item->preload(); - - using namespace ::Layout; - item->setPosition(PositionToIndex(_rows.size(), row.items.size())); - if (rowFinalize(row, sumWidth, item->isFullLine())) { - item->setPosition(PositionToIndex(_rows.size(), 0)); - } - - sumWidth += item->maxWidth(); - if (!row.items.empty() && row.items.back()->hasRightSkip()) { - sumWidth += st::inlineResultsSkip; - } - - row.items.push_back(item); -} - -bool MosaicLayout::rowFinalize(Row &row, int &sumWidth, bool force) { - if (row.items.empty()) { - return false; - } - - const auto full = (row.items.size() >= kInlineItemsMaxPerRow); - // Currently use the same GIFs layout for all widget sizes. - const auto big = (sumWidth >= _bigWidth); - if (full || big || force) { - row.maxWidth = (full || big) ? sumWidth : 0; - layoutRow(row, _width); - _rows.push_back(std::move(row)); - row = Row(); - row.items.reserve(kInlineItemsMaxPerRow); - sumWidth = 0; - return true; - } - return false; -} - -void MosaicLayout::layoutRow(Row &row, int fullWidth) { - const auto count = int(row.items.size()); - Assert(count <= kInlineItemsMaxPerRow); - - // Enumerate items in the order of growing maxWidth() - // for that sort item indices by maxWidth(). - int indices[kInlineItemsMaxPerRow]; - for (auto i = 0; i != count; ++i) { - indices[i] = i; - } - 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; - auto availableWidth = fullWidth - - (st::inlineResultsLeft - st::roundRadiusSmall); - for (auto i = 0; i < count; ++i) { - const auto index = indices[i]; - const auto &item = row.items[index]; - const auto w = desiredWidth - ? (item->maxWidth() * availableWidth / desiredWidth) - : item->maxWidth(); - const auto actualWidth = std::max(w, st::inlineResultsMinWidth); - row.height = std::max(row.height, item->resizeGetHeight(actualWidth)); - if (desiredWidth) { - availableWidth -= actualWidth; - desiredWidth -= row.items[index]->maxWidth(); - if (index > 0 && row.items[index - 1]->hasRightSkip()) { - availableWidth -= st::inlineResultsSkip; - desiredWidth -= st::inlineResultsSkip; - } - } - } -} - -void MosaicLayout::paint( - Painter &p, - int top, - int startLeft, - const QRect &clip, - PaintContext &context) { - const auto fromX = rtl() ? (_width - clip.x() - clip.width()) : clip.x(); - const auto toX = rtl() ? (_width - clip.x()) : (clip.x() + clip.width()); - const auto rows = _rows.size(); - for (auto row = 0; row != rows; ++row) { - if (top >= clip.top() + clip.height()) { - break; - } - auto &inlineRow = _rows[row]; - if ((top + inlineRow.height) > clip.top()) { - auto left = startLeft; - if (row == (rows - 1)) { - context.lastRow = true; - } - for (const auto &item : inlineRow.items) { - if (left >= toX) { - break; - } - - const auto w = item->width(); - if ((left + w) > fromX) { - p.translate(left, top); - item->paint(p, clip.translated(-left, -top), &context); - p.translate(-left, -top); - } - left += w; - if (item->hasRightSkip()) { - left += st::inlineResultsSkip; - } - } - } - top += inlineRow.height; - } -} - -void MosaicLayout::clearRows(bool resultsDeleted) { - if (!resultsDeleted) { - for (const auto &row : _rows) { - for (const auto &item : row.items) { - item->setPosition(-1); - } - } - } - _rows.clear(); -} - -void MosaicLayout::preloadImages() { - for (const auto &row : _rows) { - for (const auto &item : row.items) { - item->preload(); - } - } -} - -int MosaicLayout::validateExistingRows(const Results &results) { - const auto count = results.size(); - auto until = 0; - auto untilRow = 0; - auto untilCol = 0; - while (until < count) { - auto &rowItems = _rows[untilRow].items; - if ((untilRow >= _rows.size()) - || (rowItems[untilCol]->getResult() != results[until].get())) { - break; - } - ++until; - if (++untilCol == rowItems.size()) { - ++untilRow; - untilCol = 0; - } - } - if (until == count) { // All items are layed out. - if (untilRow == _rows.size()) { // Nothing changed. - return until; - } - - { - const auto rows = _rows.size(); - auto skip = untilCol; - for (auto i = untilRow; i < rows; ++i) { - for (const auto &item : _rows[i].items) { - if (skip) { - --skip; - } else { - item->setPosition(-1); - } - } - } - } - if (!untilCol) { // All good rows are filled. - _rows.resize(untilRow); - return until; - } - _rows.resize(untilRow + 1); - _rows[untilRow].items.resize(untilCol); - _rows[untilRow].maxWidth = ranges::accumulate( - _rows[untilRow].items, - 0, - [](int w, auto &row) { return w + row->maxWidth(); }); - layoutRow(_rows[untilRow], _width); - return until; - } - if (untilRow && !untilCol) { // Remove last row, maybe it is not full. - --untilRow; - untilCol = _rows[untilRow].items.size(); - } - until -= untilCol; - - for (auto i = untilRow; i < _rows.size(); ++i) { - for (const auto &item : _rows[i].items) { - item->setPosition(-1); - } - } - _rows.resize(untilRow); - - return until; -} - -int MosaicLayout::columnsCountAt(int row) const { - Expects(row >= 0 && row < _rows.size()); - return _rows[row].items.size(); -} - -int MosaicLayout::rowHeightAt(int row) { - Expects(row >= 0 && row < _rows.size()); - return _rows[row].height; -} - -MosaicLayout::FoundItem MosaicLayout::findByPoint(const QPoint &globalPoint) { - auto sx = globalPoint.x(); - auto sy = globalPoint.y(); - auto row = -1; - auto col = -1; - auto sel = -1; - ClickHandlerPtr link; - ItemBase *item = nullptr; - if (sy >= 0) { - row = 0; - for (auto rows = rowsCount(); row < rows; ++row) { - const auto rowHeight = _rows[row].height; - if (sy < rowHeight) { - break; - } - sy -= rowHeight; - } - } - if (sx >= 0 && row >= 0 && row < rowsCount()) { - const auto columnsCount = _rows[row].items.size(); - col = 0; - for (int cols = columnsCount; col < cols; ++col) { - const auto item = itemAt(row, col); - const auto width = item->width(); - if (sx < width) { - break; - } - sx -= width; - if (item->hasRightSkip()) { - sx -= st::inlineResultsSkip; - } - } - if (col < columnsCount) { - item = itemAt(row, col); - sel = ::Layout::PositionToIndex(row, + col); - const auto result = item->getState(QPoint(sx, sy), {}); - link = result.link; - } else { - row = col = -1; - } - } else { - row = col = -1; - } - return { link, item, sel }; -} - -} // namespace InlineBots::Layout diff --git a/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.h b/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.h index 3834183f78..e69de29bb2 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.h +++ b/Telegram/SourceFiles/inline_bots/inline_results_mosaic_layout.h @@ -1,76 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -#include "inline_bots/inline_bot_layout_item.h" - -namespace InlineBots { -class Result; -} // namespace InlineBots - -namespace InlineBots::Layout { - -using Results = std::vector>; - -class MosaicLayout final { -public: - struct FoundItem { - ClickHandlerPtr link; - ItemBase *item = nullptr; - int index = -1; - }; - MosaicLayout(int bigWidth); - - [[nodiscard]] int rowHeightAt(int row); - [[nodiscard]] int countDesiredHeight(int newWidth); - - [[nodiscard]] FoundItem findByPoint(const QPoint &globalPoint); - - void addItems(const std::vector &items); - - void setFullWidth(int w); - [[nodiscard]] bool empty() const; - - [[nodiscard]] int rowsCount() const; - [[nodiscard]] int columnsCountAt(int row) const; - - [[nodiscard]] not_null itemAt(int row, int column) const; - [[nodiscard]] not_null itemAt(int index) const; - [[nodiscard]] ItemBase *maybeItemAt(int row, int column) const; - [[nodiscard]] ItemBase *maybeItemAt(int index) const; - - void clearRows(bool resultsDeleted); - [[nodiscard]]int validateExistingRows(const Results &results); - - void preloadImages(); - - void paint( - Painter &p, - int top, - int startLeft, - const QRect &clip, - PaintContext &context); - -private: - struct Row { - int maxWidth = 0; - int height = 0; - std::vector items; - }; - - void addItem(not_null item, Row &row, int &sumWidth); - - bool rowFinalize(Row &row, int &sumWidth, bool force); - void layoutRow(Row &row, int fullWidth); - - const int _bigWidth; - int _width = 0; - std::vector _rows; -}; - -} // namespace InlineBots::Layout diff --git a/Telegram/SourceFiles/overview/overview_mosaic_layout.cpp b/Telegram/SourceFiles/overview/overview_mosaic_layout.cpp deleted file mode 100644 index 9352c1c837..0000000000 --- a/Telegram/SourceFiles/overview/overview_mosaic_layout.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "overview/overview_mosaic_layout.h" - -#include "history/view/history_view_cursor_state.h" -#include "layout/layout_position.h" -#include "styles/style_chat_helpers.h" - -namespace Overview::Layout { -namespace { - -constexpr auto kInlineItemsMaxPerRow = 5; - -} // namespace - -MosaicLayout::MosaicLayout() -: _bigWidth(st::emojiPanWidth - st::inlineResultsLeft) { -} - -void MosaicLayout::setRightSkip(int rightSkip) { - _rightSkip = rightSkip; -} - -void MosaicLayout::setOffset(int left, int top) { - _offset = { left, top }; -} - -void MosaicLayout::setFullWidth(int w) { - _width = w; -} - -bool MosaicLayout::empty() const { - return _rows.empty(); -} - -int MosaicLayout::rowsCount() const { - return _rows.size(); -} - -int MosaicLayout::countDesiredHeight(int newWidth) { - auto result = 0; - for (auto &row : _rows) { - layoutRow(row, newWidth ? newWidth : _width); - result += row.height; - } - return result; -} - -not_null MosaicLayout::itemAt(int row, int column) const { - Expects((row >= 0) - && (row < _rows.size()) - && (column >= 0) - && (column < _rows[row].items.size())); - return _rows[row].items[column]; -} - -not_null MosaicLayout::itemAt(int index) const { - const auto &[row, column] = ::Layout::IndexToPosition(index); - return itemAt(row, column); -} - -ItemBase *MosaicLayout::maybeItemAt(int row, int column) const { - if ((row >= 0) - && (row < _rows.size()) - && (column >= 0) - && (column < _rows[row].items.size())) { - return _rows[row].items[column]; - } - return nullptr; -} - -ItemBase *MosaicLayout::maybeItemAt(int index) const { - const auto &[row, column] = ::Layout::IndexToPosition(index); - return maybeItemAt(row, column); -} - -void MosaicLayout::addItems(const std::vector> &items) { - _rows.reserve(items.size()); - auto row = Row(); - row.items.reserve(kInlineItemsMaxPerRow); - auto sumWidth = 0; - for (const auto &item : items) { - addItem(item, row, sumWidth); - } - rowFinalize(row, sumWidth, true); -} - -void MosaicLayout::addItem( - not_null item, - Row &row, - int &sumWidth) { - // item->preload(); - - using namespace ::Layout; - item->setPosition(PositionToIndex(_rows.size(), row.items.size())); - if (rowFinalize(row, sumWidth, false)) { - item->setPosition(PositionToIndex(_rows.size(), 0)); - } - - sumWidth += item->maxWidth(); - if (!row.items.empty() && _rightSkip) { - sumWidth += _rightSkip; - } - - row.items.push_back(item); -} - -bool MosaicLayout::rowFinalize(Row &row, int &sumWidth, bool force) { - if (row.items.empty()) { - return false; - } - - const auto full = (row.items.size() >= kInlineItemsMaxPerRow); - // Currently use the same GIFs layout for all widget sizes. - const auto big = (sumWidth >= _bigWidth); - if (full || big || force) { - row.maxWidth = (full || big) ? sumWidth : 0; - layoutRow(row, _width); - _rows.push_back(std::move(row)); - row = Row(); - row.items.reserve(kInlineItemsMaxPerRow); - sumWidth = 0; - return true; - } - return false; -} - -void MosaicLayout::layoutRow(Row &row, int fullWidth) { - const auto count = int(row.items.size()); - Assert(count <= kInlineItemsMaxPerRow); - - // Enumerate items in the order of growing maxWidth() - // for that sort item indices by maxWidth(). - int indices[kInlineItemsMaxPerRow]; - for (auto i = 0; i != count; ++i) { - indices[i] = i; - } - 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; - auto availableWidth = fullWidth - - (st::inlineResultsLeft - st::roundRadiusSmall); - for (auto i = 0; i < count; ++i) { - const auto index = indices[i]; - const auto &item = row.items[index]; - const auto w = desiredWidth - ? (item->maxWidth() * availableWidth / desiredWidth) - : item->maxWidth(); - const auto actualWidth = std::max(w, st::inlineResultsMinWidth); - row.height = std::max(row.height, item->resizeGetHeight(actualWidth)); - if (desiredWidth) { - availableWidth -= actualWidth; - desiredWidth -= row.items[index]->maxWidth(); - if (index > 0 && _rightSkip) { - availableWidth -= _rightSkip; - desiredWidth -= _rightSkip; - } - } - } -} - -QRect MosaicLayout::findRect(int index) const { - const auto clip = QRect(0, 0, _width, 100); - const auto fromX = rtl() ? (_width - clip.x() - clip.width()) : clip.x(); - const auto toX = rtl() ? (_width - clip.x()) : (clip.x() + clip.width()); - const auto rows = _rows.size(); - auto top = 0; - for (auto row = 0; row != rows; ++row) { - auto &inlineRow = _rows[row]; - // if ((top + inlineRow.height) > clip.top()) { - auto left = 0; - if (row == (rows - 1)) { -// context.lastRow = true; - } - for (const auto &item : inlineRow.items) { - if (left >= toX) { - break; - } - - const auto w = item->width(); - if ((left + w) > fromX) { - if (item->position() == index) { - return QRect( - left + _offset.x(), - top + _offset.y(), - item->width(), - item->height()); - } - } - left += w; - left += _rightSkip; - } - // } - top += inlineRow.height; - } - return QRect(); -} - -void MosaicLayout::paint( - Fn, QPoint)> paintItemCallback, - const QRect &clip) const { - auto top = _offset.y(); - const auto fromX = rtl() ? (_width - clip.x() - clip.width()) : clip.x(); - const auto toX = rtl() ? (_width - clip.x()) : (clip.x() + clip.width()); - const auto rows = _rows.size(); - for (auto row = 0; row != rows; ++row) { - if (top >= clip.top() + clip.height()) { - break; - } - auto &inlineRow = _rows[row]; - if ((top + inlineRow.height) > clip.top()) { - auto left = _offset.x(); - if (row == (rows - 1)) { -// context.lastRow = true; - } - for (const auto &item : inlineRow.items) { - if (left >= toX) { - break; - } - - const auto w = item->width(); - if ((left + w) > fromX) { - paintItemCallback(item, QPoint(left, top)); - } - left += w; - left += _rightSkip; - } - } - top += inlineRow.height; - } -} - -void MosaicLayout::clearRows(bool resultsDeleted) { - if (!resultsDeleted) { - for (const auto &row : _rows) { - for (const auto &item : row.items) { - item->setPosition(-1); - } - } - } - _rows.clear(); -} - -void MosaicLayout::preloadImages() { - // for (const auto &row : _rows) { - // for (const auto &item : row.items) { - // item->preload(); - // } - // } -} - -int MosaicLayout::columnsCountAt(int row) const { - Expects(row >= 0 && row < _rows.size()); - return _rows[row].items.size(); -} - -int MosaicLayout::rowHeightAt(int row) const { - Expects(row >= 0 && row < _rows.size()); - return _rows[row].height; -} - -MosaicLayout::FoundItem MosaicLayout::findByPoint( - const QPoint &globalPoint) const { - auto sx = globalPoint.x() - _offset.x(); - auto sy = globalPoint.y() - _offset.y(); - auto row = -1; - auto col = -1; - auto sel = -1; - bool exact = true; - ClickHandlerPtr link; - ItemBase *item = nullptr; - if (sy >= 0) { - row = 0; - for (auto rows = rowsCount(); row < rows; ++row) { - const auto rowHeight = _rows[row].height; - if (sy < rowHeight) { - break; - } - sy -= rowHeight; - } - } else { - row = 0; - exact = false; - } - if (row >= rowsCount()) { - row = rowsCount() - 1; - exact = false; - } - if (sx < 0) { - sx = 0; - exact = false; - } - if (sx >= 0 && row >= 0 && row < rowsCount()) { - const auto columnsCount = _rows[row].items.size(); - col = 0; - for (int cols = columnsCount; col < cols; ++col) { - const auto item = itemAt(row, col); - const auto width = item->width(); - if (sx < width) { - break; - } - sx -= width; - sx -= _rightSkip; - } - if (col >= columnsCount) { - col = columnsCount - 1; - exact = false; - } - item = itemAt(row, col); - sel = ::Layout::PositionToIndex(row, + col); - const auto result = item->getState(QPoint(sx, sy), {}); - link = result.link; - } else { - row = col = -1; - } - return { link, item, sel, exact }; -} - -} // namespace Overview::Layout diff --git a/Telegram/SourceFiles/overview/overview_mosaic_layout.h b/Telegram/SourceFiles/overview/overview_mosaic_layout.h index c58dbd9bee..e69de29bb2 100644 --- a/Telegram/SourceFiles/overview/overview_mosaic_layout.h +++ b/Telegram/SourceFiles/overview/overview_mosaic_layout.h @@ -1,72 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -#include "overview/overview_layout.h" - -namespace Overview::Layout { - -class MosaicLayout final { -public: - struct FoundItem { - ClickHandlerPtr link; - ItemBase *item = nullptr; - int index = -1; - bool exact = false; - }; - MosaicLayout(); - - [[nodiscard]] int rowHeightAt(int row) const; - [[nodiscard]] int countDesiredHeight(int newWidth); - - [[nodiscard]] FoundItem findByPoint(const QPoint &globalPoint) const; - [[nodiscard]] QRect findRect(int index) const; - - void addItems(const std::vector> &items); - - void setRightSkip(int rightSkip); - void setFullWidth(int w); - void setOffset(int left, int top); - [[nodiscard]] bool empty() const; - - [[nodiscard]] int rowsCount() const; - [[nodiscard]] int columnsCountAt(int row) const; - - [[nodiscard]] not_null itemAt(int row, int column) const; - [[nodiscard]] not_null itemAt(int index) const; - [[nodiscard]] ItemBase *maybeItemAt(int row, int column) const; - [[nodiscard]] ItemBase *maybeItemAt(int index) const; - - void clearRows(bool resultsDeleted); - - void preloadImages(); - - void paint( - Fn, QPoint)> paintItemCallback, - const QRect &clip) const; - -private: - struct Row { - int maxWidth = 0; - int height = 0; - std::vector items; - }; - - void addItem(not_null item, Row &row, int &sumWidth); - - bool rowFinalize(Row &row, int &sumWidth, bool force); - void layoutRow(Row &row, int fullWidth); - - int _bigWidth; - int _width = 0; - int _rightSkip = 0; - QPoint _offset; - std::vector _rows; -}; - -} // namespace Overview::Layout