Modernized code style of InlineBots::Bots::MosaicLayout.

This commit is contained in:
23rd 2021-07-21 23:31:43 +03:00 committed by John Preston
parent 34d2d7bcba
commit 812f5d4311
2 changed files with 104 additions and 103 deletions

View file

@ -9,8 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
namespace InlineBots { namespace InlineBots::Layout {
namespace Layout {
namespace { namespace {
constexpr auto kInlineItemsMaxPerRow = 5; constexpr auto kInlineItemsMaxPerRow = 5;
@ -31,9 +30,9 @@ int MosaicLayout::rowsCount() const {
int MosaicLayout::countDesiredHeight(int newWidth) { int MosaicLayout::countDesiredHeight(int newWidth) {
auto result = 0; auto result = 0;
for (int i = 0, l = _rows.size(); i < l; ++i) { for (auto &row : _rows) {
layoutRow(_rows[i], newWidth); layoutRow(row, newWidth);
result += _rows[i].height; result += row.height;
} }
return result; return result;
} }
@ -67,7 +66,10 @@ void MosaicLayout::addItems(const std::vector<ItemBase*> &items) {
rowFinalize(row, sumWidth, true); rowFinalize(row, sumWidth, true);
} }
void MosaicLayout::addItem(ItemBase *item, Row &row, int32 &sumWidth) { void MosaicLayout::addItem(
not_null<ItemBase*> item,
Row &row,
int &sumWidth) {
item->preload(); item->preload();
item->setPosition(_rows.size() * MatrixRowShift + row.items.size()); item->setPosition(_rows.size() * MatrixRowShift + row.items.size());
@ -83,22 +85,18 @@ void MosaicLayout::addItem(ItemBase *item, Row &row, int32 &sumWidth) {
row.items.push_back(item); row.items.push_back(item);
} }
bool MosaicLayout::rowFinalize(Row &row, int32 &sumWidth, bool force) { bool MosaicLayout::rowFinalize(Row &row, int &sumWidth, bool force) {
if (row.items.empty()) { if (row.items.empty()) {
return false; return false;
} }
auto full = (row.items.size() >= kInlineItemsMaxPerRow); const auto full = (row.items.size() >= kInlineItemsMaxPerRow);
// Currently use the same GIFs layout for all widget sizes. // Currently use the same GIFs layout for all widget sizes.
// auto big = (sumWidth >= st::roundRadiusSmall + width() - st::inlineResultsLeft); const auto big = (sumWidth >= st::emojiPanWidth - st::inlineResultsLeft);
auto big = (sumWidth >= st::emojiPanWidth - st::inlineResultsLeft);
if (full || big || force) { if (full || big || force) {
row.maxWidth = (full || big) ? sumWidth : 0; row.maxWidth = (full || big) ? sumWidth : 0;
layoutRow( layoutRow(row, _width);
row, _rows.push_back(std::move(row));
_width);
_rows.push_back(row);
row = Row(); row = Row();
row.items.reserve(kInlineItemsMaxPerRow); row.items.reserve(kInlineItemsMaxPerRow);
sumWidth = 0; sumWidth = 0;
@ -108,11 +106,11 @@ bool MosaicLayout::rowFinalize(Row &row, int32 &sumWidth, bool force) {
} }
void MosaicLayout::layoutRow(Row &row, int fullWidth) { void MosaicLayout::layoutRow(Row &row, int fullWidth) {
auto count = int(row.items.size()); const auto count = int(row.items.size());
Assert(count <= kInlineItemsMaxPerRow); Assert(count <= kInlineItemsMaxPerRow);
// enumerate items in the order of growing maxWidth() // Enumerate items in the order of growing maxWidth()
// for that sort item indices by maxWidth() // for that sort item indices by maxWidth().
int indices[kInlineItemsMaxPerRow]; int indices[kInlineItemsMaxPerRow];
for (auto i = 0; i != count; ++i) { for (auto i = 0; i != count; ++i) {
indices[i] = i; indices[i] = i;
@ -123,20 +121,21 @@ void MosaicLayout::layoutRow(Row &row, int fullWidth) {
auto desiredWidth = row.maxWidth; auto desiredWidth = row.maxWidth;
row.height = 0; row.height = 0;
int availw = fullWidth - (st::inlineResultsLeft - st::roundRadiusSmall); auto availableWidth = fullWidth
for (int i = 0; i < count; ++i) { - (st::inlineResultsLeft - st::roundRadiusSmall);
for (auto i = 0; i < count; ++i) {
const auto index = indices[i]; const auto index = indices[i];
const auto &item = row.items[index]; const auto &item = row.items[index];
const auto w = desiredWidth const auto w = desiredWidth
? (item->maxWidth() * availw / desiredWidth) ? (item->maxWidth() * availableWidth / desiredWidth)
: item->maxWidth(); : item->maxWidth();
auto actualw = std::max(w, st::inlineResultsMinWidth); const auto actualWidth = std::max(w, st::inlineResultsMinWidth);
row.height = std::max(row.height, item->resizeGetHeight(actualw)); row.height = std::max(row.height, item->resizeGetHeight(actualWidth));
if (desiredWidth) { if (desiredWidth) {
availw -= actualw; availableWidth -= actualWidth;
desiredWidth -= row.items[index]->maxWidth(); desiredWidth -= row.items[index]->maxWidth();
if (index > 0 && row.items[index - 1]->hasRightSkip()) { if (index > 0 && row.items[index - 1]->hasRightSkip()) {
availw -= st::inlineResultsSkip; availableWidth -= st::inlineResultsSkip;
desiredWidth -= st::inlineResultsSkip; desiredWidth -= st::inlineResultsSkip;
} }
} }
@ -149,27 +148,26 @@ void MosaicLayout::paint(
int startLeft, int startLeft,
const QRect &clip, const QRect &clip,
PaintContext &context) { PaintContext &context) {
const auto fromx = rtl() ? (_width - clip.x() - clip.width()) : clip.x(); const auto fromX = rtl() ? (_width - clip.x() - clip.width()) : clip.x();
const auto tox = rtl() ? (_width - clip.x()) : (clip.x() + clip.width()); const auto toX = rtl() ? (_width - clip.x()) : (clip.x() + clip.width());
const auto rows = _rows.size(); const auto rows = _rows.size();
for (auto row = 0; row != rows; ++row) { for (auto row = 0; row != rows; ++row) {
auto &inlineRow = _rows[row];
if (top >= clip.top() + clip.height()) { if (top >= clip.top() + clip.height()) {
break; break;
} }
if (top + inlineRow.height > clip.top()) { auto &inlineRow = _rows[row];
if ((top + inlineRow.height) > clip.top()) {
auto left = startLeft; auto left = startLeft;
if (row == rows - 1) { if (row == (rows - 1)) {
context.lastRow = true; context.lastRow = true;
} }
for (int col = 0, cols = inlineRow.items.size(); col < cols; ++col) { for (const auto &item : inlineRow.items) {
if (left >= tox) { if (left >= toX) {
break; break;
} }
const auto &item = inlineRow.items[col];
const auto w = item->width(); const auto w = item->width();
if (left + w > fromx) { if ((left + w) > fromX) {
p.translate(left, top); p.translate(left, top);
item->paint(p, clip.translated(-left, -top), &context); item->paint(p, clip.translated(-left, -top), &context);
p.translate(-left, -top); p.translate(-left, -top);
@ -185,10 +183,7 @@ void MosaicLayout::paint(
} }
void MosaicLayout::clearRows(bool resultsDeleted) { void MosaicLayout::clearRows(bool resultsDeleted) {
if (resultsDeleted) { if (!resultsDeleted) {
// _selected = _pressed = -1;
} else {
// clearSelection();
for (const auto &row : _rows) { for (const auto &row : _rows) {
for (const auto &item : row.items) { for (const auto &item : row.items) {
item->setPosition(-1); item->setPosition(-1);
@ -207,70 +202,77 @@ void MosaicLayout::preloadImages() {
} }
int MosaicLayout::validateExistingRows(const Results &results) { int MosaicLayout::validateExistingRows(const Results &results) {
int count = results.size(), until = 0, untilrow = 0, untilcol = 0; const auto count = results.size();
auto until = 0;
auto untilRow = 0;
auto untilCol = 0;
while (until < count) { while (until < count) {
if (untilrow >= _rows.size() auto &rowItems = _rows[untilRow].items;
|| _rows[untilrow].items[untilcol]->getResult() != results[until].get()) { if ((untilRow >= _rows.size())
|| (rowItems[untilCol]->getResult() != results[until].get())) {
break; break;
} }
++until; ++until;
if (++untilcol == _rows[untilrow].items.size()) { if (++untilCol == rowItems.size()) {
++untilrow; ++untilRow;
untilcol = 0; untilCol = 0;
} }
} }
if (until == count) { // all items are layed out if (until == count) { // All items are layed out.
if (untilrow == _rows.size()) { // nothing changed if (untilRow == _rows.size()) { // Nothing changed.
return until; return until;
} }
for (int i = untilrow, l = _rows.size(), skip = untilcol; i < l; ++i) { {
for (int j = 0, s = _rows[i].items.size(); j < s; ++j) { const auto rows = _rows.size();
if (skip) { auto skip = untilCol;
--skip; for (auto i = untilRow; i < rows; ++i) {
} else { for (const auto &item : _rows[i].items) {
_rows[i].items[j]->setPosition(-1); if (skip) {
--skip;
} else {
item->setPosition(-1);
}
} }
} }
} }
if (!untilcol) { // all good rows are filled if (!untilCol) { // All good rows are filled.
_rows.resize(untilrow); _rows.resize(untilRow);
return until; return until;
} }
_rows.resize(untilrow + 1); _rows.resize(untilRow + 1);
_rows[untilrow].items.resize(untilcol); _rows[untilRow].items.resize(untilCol);
_rows[untilrow].maxWidth = std::accumulate( _rows[untilRow].maxWidth = ranges::accumulate(
_rows[untilrow].items.begin(), _rows[untilRow].items,
_rows[untilrow].items.end(),
0, 0,
[](int w, auto &row) { return w + row->maxWidth(); }); [](int w, auto &row) { return w + row->maxWidth(); });
layoutRow(_rows[untilrow], _width); layoutRow(_rows[untilRow], _width);
return until; return until;
} }
if (untilrow && !untilcol) { // remove last row, maybe it is not full if (untilRow && !untilCol) { // Remove last row, maybe it is not full.
--untilrow; --untilRow;
untilcol = _rows[untilrow].items.size(); untilCol = _rows[untilRow].items.size();
} }
until -= untilcol; until -= untilCol;
for (int i = untilrow, l = _rows.size(); i < l; ++i) { for (auto i = untilRow; i < _rows.size(); ++i) {
for (int j = 0, s = _rows[i].items.size(); j < s; ++j) { for (const auto &item : _rows[i].items) {
_rows[i].items[j]->setPosition(-1); item->setPosition(-1);
} }
} }
_rows.resize(untilrow); _rows.resize(untilRow);
// if (_rows.isEmpty()) {
// _inlineWithThumb = false;
// for (int i = until; i < count; ++i) {
// if (results.at(i)->hasThumbDisplay()) {
// _inlineWithThumb = true;
// break;
// }
// }
// }
return until; return until;
} }
} // namespace Layout int MosaicLayout::columnsCountAt(int row) const {
} // namespace InlineBots 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;
}
} // namespace InlineBots::Layout

View file

@ -13,44 +13,33 @@ namespace InlineBots {
class Result; class Result;
} // namespace InlineBots } // namespace InlineBots
namespace InlineBots { namespace InlineBots::Layout {
namespace Layout {
class ItemBase;
using Results = std::vector<std::unique_ptr<Result>>; using Results = std::vector<std::unique_ptr<Result>>;
class MosaicLayout final { class MosaicLayout final {
public: public:
struct Row {
int maxWidth = 0;
int height = 0;
std::vector<ItemBase*> items;
};
MosaicLayout() = default; MosaicLayout() = default;
int rowHeightAt(int row); [[nodiscard]] int rowHeightAt(int row);
[[nodiscard]] int countDesiredHeight(int newWidth);
void addItems(const std::vector<ItemBase*> &items); void addItems(const std::vector<ItemBase*> &items);
void addItem(ItemBase *item, Row &row, int32 &sumWidth);
void setFullWidth(int w); void setFullWidth(int w);
bool empty() const; [[nodiscard]] bool empty() const;
int rowsCount() const; [[nodiscard]] int rowsCount() const;
int columnsCountAt(int row) const; [[nodiscard]] int columnsCountAt(int row) const;
not_null<ItemBase*> itemAt(int row, int column) const; [[nodiscard]] not_null<ItemBase*> itemAt(int row, int column) const;
ItemBase *maybeItemAt(int row, int column) const; [[nodiscard]] ItemBase *maybeItemAt(int row, int column) const;
void clearRows(bool resultsDeleted);
[[nodiscard]]int validateExistingRows(const Results &results);
void preloadImages(); void preloadImages();
bool rowFinalize(Row &row, int32 &sumWidth, bool force);
void layoutRow(Row &row, int fullWidth);
void clearRows(bool resultsDeleted);
int validateExistingRows(const Results &results);
int countDesiredHeight(int newWidth);
void paint( void paint(
Painter &p, Painter &p,
int top, int top,
@ -59,9 +48,19 @@ public:
PaintContext &context); PaintContext &context);
private: private:
struct Row {
int maxWidth = 0;
int height = 0;
std::vector<ItemBase*> items;
};
void addItem(not_null<ItemBase*> item, Row &row, int &sumWidth);
bool rowFinalize(Row &row, int &sumWidth, bool force);
void layoutRow(Row &row, int fullWidth);
int _width = 0; int _width = 0;
std::vector<Row> _rows; std::vector<Row> _rows;
}; };
} // namespace Layout } // namespace InlineBots::Layout
} // namespace InlineBots