Replaced mosaic drawing in ChatHelpers::GifsListWidget.
This commit is contained in:
		
							parent
							
								
									812f5d4311
								
							
						
					
					
						commit
						c4d8d52aed
					
				
					 2 changed files with 77 additions and 255 deletions
				
			
		| 
						 | 
					@ -195,6 +195,11 @@ GifsListWidget::GifsListWidget(
 | 
				
			||||||
			update();
 | 
								update();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}, lifetime());
 | 
						}, lifetime());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sizeValue(
 | 
				
			||||||
 | 
						) | rpl::start_with_next([=](const QSize &s) {
 | 
				
			||||||
 | 
							_mosaic.setFullWidth(s.width());
 | 
				
			||||||
 | 
						}, lifetime());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rpl::producer<TabbedSelector::FileChosen> GifsListWidget::fileChosen() const {
 | 
					rpl::producer<TabbedSelector::FileChosen> GifsListWidget::fileChosen() const {
 | 
				
			||||||
| 
						 | 
					@ -238,12 +243,7 @@ void GifsListWidget::checkLoadMore() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int GifsListWidget::countDesiredHeight(int newWidth) {
 | 
					int GifsListWidget::countDesiredHeight(int newWidth) {
 | 
				
			||||||
	auto result = st::stickerPanPadding;
 | 
						return _mosaic.countDesiredHeight(newWidth) + st::stickerPanPadding * 2;
 | 
				
			||||||
	for (int i = 0, l = _rows.count(); i < l; ++i) {
 | 
					 | 
				
			||||||
		layoutInlineRow(_rows[i], newWidth);
 | 
					 | 
				
			||||||
		result += _rows[i].height;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return result + st::stickerPanPadding;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GifsListWidget::~GifsListWidget() {
 | 
					GifsListWidget::~GifsListWidget() {
 | 
				
			||||||
| 
						 | 
					@ -321,7 +321,7 @@ void GifsListWidget::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GifsListWidget::paintInlineItems(Painter &p, QRect clip) {
 | 
					void GifsListWidget::paintInlineItems(Painter &p, QRect clip) {
 | 
				
			||||||
	if (_rows.isEmpty()) {
 | 
						if (_mosaic.empty()) {
 | 
				
			||||||
		p.setFont(st::normalFont);
 | 
							p.setFont(st::normalFont);
 | 
				
			||||||
		p.setPen(st::noContactsColor);
 | 
							p.setPen(st::noContactsColor);
 | 
				
			||||||
		auto text = _inlineQuery.isEmpty()
 | 
							auto text = _inlineQuery.isEmpty()
 | 
				
			||||||
| 
						 | 
					@ -333,35 +333,12 @@ void GifsListWidget::paintInlineItems(Painter &p, QRect clip) {
 | 
				
			||||||
	auto gifPaused = controller()->isGifPausedAtLeastFor(Window::GifPauseReason::SavedGifs);
 | 
						auto gifPaused = controller()->isGifPausedAtLeastFor(Window::GifPauseReason::SavedGifs);
 | 
				
			||||||
	InlineBots::Layout::PaintContext context(crl::now(), false, gifPaused, false);
 | 
						InlineBots::Layout::PaintContext context(crl::now(), false, gifPaused, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto top = st::stickerPanPadding;
 | 
						_mosaic.paint(
 | 
				
			||||||
	auto fromx = rtl() ? (width() - clip.x() - clip.width()) : clip.x();
 | 
							p,
 | 
				
			||||||
	auto tox = rtl() ? (width() - clip.x()) : (clip.x() + clip.width());
 | 
							st::stickerPanPadding,
 | 
				
			||||||
	for (auto row = 0, rows = _rows.size(); row != rows; ++row) {
 | 
							st::inlineResultsLeft - st::roundRadiusSmall,
 | 
				
			||||||
		auto &inlineRow = _rows[row];
 | 
							clip,
 | 
				
			||||||
		if (top >= clip.top() + clip.height()) {
 | 
							context);
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (top + inlineRow.height > clip.top()) {
 | 
					 | 
				
			||||||
			auto left = st::inlineResultsLeft - st::roundRadiusSmall;
 | 
					 | 
				
			||||||
			if (row == rows - 1) context.lastRow = true;
 | 
					 | 
				
			||||||
			for (int col = 0, cols = inlineRow.items.size(); col < cols; ++col) {
 | 
					 | 
				
			||||||
				if (left >= tox) break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				auto item = inlineRow.items.at(col);
 | 
					 | 
				
			||||||
				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 GifsListWidget::mousePressEvent(QMouseEvent *e) {
 | 
					void GifsListWidget::mousePressEvent(QMouseEvent *e) {
 | 
				
			||||||
| 
						 | 
					@ -394,8 +371,7 @@ void GifsListWidget::fillContextMenu(
 | 
				
			||||||
		SendMenu::DefaultSilentCallback(send),
 | 
							SendMenu::DefaultSilentCallback(send),
 | 
				
			||||||
		SendMenu::DefaultScheduleCallback(this, type, send));
 | 
							SendMenu::DefaultScheduleCallback(this, type, send));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(row >= _rows.size() || column >= _rows[row].items.size())) {
 | 
						if (const auto item = _mosaic.maybeItemAt(row, column)) {
 | 
				
			||||||
		const auto item = _rows[row].items[column];
 | 
					 | 
				
			||||||
		const auto document = item->getDocument()
 | 
							const auto document = item->getDocument()
 | 
				
			||||||
			? item->getDocument() // Saved GIF.
 | 
								? item->getDocument() // Saved GIF.
 | 
				
			||||||
			: item->getPreviewDocument(); // Searched GIF.
 | 
								: item->getPreviewDocument(); // Searched GIF.
 | 
				
			||||||
| 
						 | 
					@ -443,13 +419,13 @@ void GifsListWidget::selectInlineResult(
 | 
				
			||||||
		int column,
 | 
							int column,
 | 
				
			||||||
		Api::SendOptions options,
 | 
							Api::SendOptions options,
 | 
				
			||||||
		bool forceSend) {
 | 
							bool forceSend) {
 | 
				
			||||||
	if (row >= _rows.size() || column >= _rows[row].items.size()) {
 | 
						const auto item = _mosaic.maybeItemAt(row, column);
 | 
				
			||||||
 | 
						if (!item) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	forceSend |= (QGuiApplication::keyboardModifiers()
 | 
						forceSend |= (QGuiApplication::keyboardModifiers()
 | 
				
			||||||
		== Qt::ControlModifier);
 | 
							== Qt::ControlModifier);
 | 
				
			||||||
	auto item = _rows[row].items[column];
 | 
					 | 
				
			||||||
	if (const auto photo = item->getPhoto()) {
 | 
						if (const auto photo = item->getPhoto()) {
 | 
				
			||||||
		using Data::PhotoSize;
 | 
							using Data::PhotoSize;
 | 
				
			||||||
		const auto media = photo->activeMediaView();
 | 
							const auto media = photo->activeMediaView();
 | 
				
			||||||
| 
						 | 
					@ -506,8 +482,7 @@ void GifsListWidget::enterFromChildEvent(QEvent *e, QWidget *child) {
 | 
				
			||||||
void GifsListWidget::clearSelection() {
 | 
					void GifsListWidget::clearSelection() {
 | 
				
			||||||
	if (_selected >= 0) {
 | 
						if (_selected >= 0) {
 | 
				
			||||||
		int srow = _selected / MatrixRowShift, scol = _selected % MatrixRowShift;
 | 
							int srow = _selected / MatrixRowShift, scol = _selected % MatrixRowShift;
 | 
				
			||||||
		Assert(srow >= 0 && srow < _rows.size() && scol >= 0 && scol < _rows[srow].items.size());
 | 
							ClickHandler::clearActive(_mosaic.itemAt(srow, scol));
 | 
				
			||||||
		ClickHandler::clearActive(_rows[srow].items[scol]);
 | 
					 | 
				
			||||||
		setCursor(style::cur_default);
 | 
							setCursor(style::cur_default);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_selected = _pressed = -1;
 | 
						_selected = _pressed = -1;
 | 
				
			||||||
| 
						 | 
					@ -538,65 +513,21 @@ void GifsListWidget::clearHeavyData() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool GifsListWidget::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, Row &row, int32 &sumWidth) {
 | 
					 | 
				
			||||||
	LayoutItem *layout = nullptr;
 | 
					 | 
				
			||||||
	if (savedGif) {
 | 
					 | 
				
			||||||
		layout = layoutPrepareSavedGif(savedGif, (_rows.size() * MatrixRowShift) + row.items.size());
 | 
					 | 
				
			||||||
	} else if (result) {
 | 
					 | 
				
			||||||
		layout = layoutPrepareInlineResult(result, (_rows.size() * MatrixRowShift) + row.items.size());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!layout) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	layout->preload();
 | 
					 | 
				
			||||||
	if (inlineRowFinalize(row, sumWidth, layout->isFullLine())) {
 | 
					 | 
				
			||||||
		layout->setPosition(_rows.size() * MatrixRowShift);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sumWidth += layout->maxWidth();
 | 
					 | 
				
			||||||
	if (!row.items.isEmpty() && row.items.back()->hasRightSkip()) {
 | 
					 | 
				
			||||||
		sumWidth += st::inlineResultsSkip;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	row.items.push_back(layout);
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool GifsListWidget::inlineRowFinalize(Row &row, int32 &sumWidth, bool force) {
 | 
					 | 
				
			||||||
	if (row.items.isEmpty()) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto full = (row.items.size() >= kInlineItemsMaxPerRow);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Currently use the same GIFs layout for all widget sizes.
 | 
					 | 
				
			||||||
//	auto big = (sumWidth >= st::roundRadiusSmall + width() - st::inlineResultsLeft);
 | 
					 | 
				
			||||||
	auto big = (sumWidth >= st::emojiPanWidth - st::inlineResultsLeft);
 | 
					 | 
				
			||||||
	if (full || big || force) {
 | 
					 | 
				
			||||||
		row.maxWidth = (full || big) ? sumWidth : 0;
 | 
					 | 
				
			||||||
		layoutInlineRow(
 | 
					 | 
				
			||||||
			row,
 | 
					 | 
				
			||||||
			width());
 | 
					 | 
				
			||||||
		_rows.push_back(row);
 | 
					 | 
				
			||||||
		row = Row();
 | 
					 | 
				
			||||||
		row.items.reserve(kInlineItemsMaxPerRow);
 | 
					 | 
				
			||||||
		sumWidth = 0;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void GifsListWidget::refreshSavedGifs() {
 | 
					void GifsListWidget::refreshSavedGifs() {
 | 
				
			||||||
	if (_section == Section::Gifs) {
 | 
						if (_section == Section::Gifs) {
 | 
				
			||||||
		clearInlineRows(false);
 | 
							clearInlineRows(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto &saved = controller()->session().data().stickers().savedGifs();
 | 
							const auto &saved = controller()->session().data().stickers().savedGifs();
 | 
				
			||||||
		if (!saved.isEmpty()) {
 | 
							if (!saved.isEmpty()) {
 | 
				
			||||||
			_rows.reserve(saved.size());
 | 
								const auto layouts = ranges::views::all(
 | 
				
			||||||
			auto row = Row();
 | 
									saved
 | 
				
			||||||
			row.items.reserve(kInlineItemsMaxPerRow);
 | 
								) | ranges::views::transform([&](not_null<DocumentData*> gif) {
 | 
				
			||||||
			auto sumWidth = 0;
 | 
									return layoutPrepareSavedGif(gif);
 | 
				
			||||||
			for (const auto &gif : saved) {
 | 
								}) | ranges::views::filter([](const LayoutItem *item) {
 | 
				
			||||||
				inlineRowsAddItem(gif, 0, row, sumWidth);
 | 
									return item != nullptr;
 | 
				
			||||||
			}
 | 
								}) | ranges::to_vector;
 | 
				
			||||||
			inlineRowFinalize(row, sumWidth, true);
 | 
					
 | 
				
			||||||
 | 
								_mosaic.addItems(layouts);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		deleteUnusedGifLayouts();
 | 
							deleteUnusedGifLayouts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -616,18 +547,12 @@ void GifsListWidget::clearInlineRows(bool resultsDeleted) {
 | 
				
			||||||
		_selected = _pressed = -1;
 | 
							_selected = _pressed = -1;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		clearSelection();
 | 
							clearSelection();
 | 
				
			||||||
		for (const auto &row : std::as_const(_rows)) {
 | 
					 | 
				
			||||||
			for (const auto &item : std::as_const(row.items)) {
 | 
					 | 
				
			||||||
				item->setPosition(-1);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		}
 | 
						_mosaic.clearRows(resultsDeleted);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_rows.clear();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(
 | 
					GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(
 | 
				
			||||||
		not_null<DocumentData*> document,
 | 
							not_null<DocumentData*> document) {
 | 
				
			||||||
		int32 position) {
 | 
					 | 
				
			||||||
	auto it = _gifLayouts.find(document);
 | 
						auto it = _gifLayouts.find(document);
 | 
				
			||||||
	if (it == _gifLayouts.cend()) {
 | 
						if (it == _gifLayouts.cend()) {
 | 
				
			||||||
		if (auto layout = LayoutItem::createLayoutGif(this, document)) {
 | 
							if (auto layout = LayoutItem::createLayoutGif(this, document)) {
 | 
				
			||||||
| 
						 | 
					@ -639,13 +564,11 @@ GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareSavedGif(
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!it->second->maxWidth()) return nullptr;
 | 
						if (!it->second->maxWidth()) return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	it->second->setPosition(position);
 | 
					 | 
				
			||||||
	return it->second.get();
 | 
						return it->second.get();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareInlineResult(
 | 
					GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareInlineResult(
 | 
				
			||||||
		not_null<InlineResult*> result,
 | 
							not_null<InlineResult*> result) {
 | 
				
			||||||
		int32 position) {
 | 
					 | 
				
			||||||
	auto it = _inlineLayouts.find(result);
 | 
						auto it = _inlineLayouts.find(result);
 | 
				
			||||||
	if (it == _inlineLayouts.cend()) {
 | 
						if (it == _inlineLayouts.cend()) {
 | 
				
			||||||
		if (auto layout = LayoutItem::createLayout(
 | 
							if (auto layout = LayoutItem::createLayout(
 | 
				
			||||||
| 
						 | 
					@ -660,12 +583,11 @@ GifsListWidget::LayoutItem *GifsListWidget::layoutPrepareInlineResult(
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!it->second->maxWidth()) return nullptr;
 | 
						if (!it->second->maxWidth()) return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	it->second->setPosition(position);
 | 
					 | 
				
			||||||
	return it->second.get();
 | 
						return it->second.get();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GifsListWidget::deleteUnusedGifLayouts() {
 | 
					void GifsListWidget::deleteUnusedGifLayouts() {
 | 
				
			||||||
	if (_rows.isEmpty() || _section != Section::Gifs) { // delete all
 | 
						if (_mosaic.empty() || _section != Section::Gifs) { // delete all
 | 
				
			||||||
		_gifLayouts.clear();
 | 
							_gifLayouts.clear();
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		for (auto i = _gifLayouts.begin(); i != _gifLayouts.cend();) {
 | 
							for (auto i = _gifLayouts.begin(); i != _gifLayouts.cend();) {
 | 
				
			||||||
| 
						 | 
					@ -679,7 +601,7 @@ void GifsListWidget::deleteUnusedGifLayouts() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GifsListWidget::deleteUnusedInlineLayouts() {
 | 
					void GifsListWidget::deleteUnusedInlineLayouts() {
 | 
				
			||||||
	if (_rows.isEmpty() || _section == Section::Gifs) { // delete all
 | 
						if (_mosaic.empty() || _section == Section::Gifs) { // delete all
 | 
				
			||||||
		_inlineLayouts.clear();
 | 
							_inlineLayouts.clear();
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		for (auto i = _inlineLayouts.begin(); i != _inlineLayouts.cend();) {
 | 
							for (auto i = _inlineLayouts.begin(); i != _inlineLayouts.cend();) {
 | 
				
			||||||
| 
						 | 
					@ -692,49 +614,8 @@ void GifsListWidget::deleteUnusedInlineLayouts() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GifsListWidget::layoutInlineRow(Row &row, int fullWidth) {
 | 
					 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
	int availw = fullWidth - (st::inlineResultsLeft - st::roundRadiusSmall);
 | 
					 | 
				
			||||||
	for (int i = 0; i < count; ++i) {
 | 
					 | 
				
			||||||
		const auto index = indices[i];
 | 
					 | 
				
			||||||
		const auto &item = row.items[index];
 | 
					 | 
				
			||||||
		const auto w = desiredWidth
 | 
					 | 
				
			||||||
			? (item->maxWidth() * availw / desiredWidth)
 | 
					 | 
				
			||||||
			: item->maxWidth();
 | 
					 | 
				
			||||||
		auto actualw = qMax(w, st::inlineResultsMinWidth);
 | 
					 | 
				
			||||||
		row.height = qMax(row.height, item->resizeGetHeight(actualw));
 | 
					 | 
				
			||||||
		if (desiredWidth) {
 | 
					 | 
				
			||||||
			availw -= actualw;
 | 
					 | 
				
			||||||
			desiredWidth -= row.items[index]->maxWidth();
 | 
					 | 
				
			||||||
			if (index > 0 && row.items[index - 1]->hasRightSkip()) {
 | 
					 | 
				
			||||||
				availw -= st::inlineResultsSkip;
 | 
					 | 
				
			||||||
				desiredWidth -= st::inlineResultsSkip;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void GifsListWidget::preloadImages() {
 | 
					void GifsListWidget::preloadImages() {
 | 
				
			||||||
	for (auto row = 0, rows = _rows.size(); row != rows; ++row) {
 | 
						_mosaic.preloadImages();
 | 
				
			||||||
		for (auto col = 0, cols = _rows[row].items.size(); col != cols; ++col) {
 | 
					 | 
				
			||||||
			_rows[row].items[col]->preload();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GifsListWidget::switchToSavedGifs() {
 | 
					void GifsListWidget::switchToSavedGifs() {
 | 
				
			||||||
| 
						 | 
					@ -757,20 +638,22 @@ int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool result
 | 
				
			||||||
	clearSelection();
 | 
						clearSelection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_section = Section::Inlines;
 | 
						_section = Section::Inlines;
 | 
				
			||||||
	auto count = int(entry->results.size());
 | 
						const auto count = int(entry->results.size());
 | 
				
			||||||
	auto from = validateExistingInlineRows(entry->results);
 | 
						const auto from = validateExistingInlineRows(entry->results);
 | 
				
			||||||
	auto added = 0;
 | 
						auto added = 0;
 | 
				
			||||||
	if (count) {
 | 
						if (count) {
 | 
				
			||||||
		_rows.reserve(count);
 | 
							const auto resultLayouts = entry->results | ranges::views::slice(
 | 
				
			||||||
		auto row = Row();
 | 
								from,
 | 
				
			||||||
		row.items.reserve(kInlineItemsMaxPerRow);
 | 
								count
 | 
				
			||||||
		auto sumWidth = 0;
 | 
							) | ranges::views::transform([&](
 | 
				
			||||||
		for (auto i = from; i != count; ++i) {
 | 
									const std::unique_ptr<InlineBots::Result> &r) {
 | 
				
			||||||
			if (inlineRowsAddItem(0, entry->results[i].get(), row, sumWidth)) {
 | 
								return layoutPrepareInlineResult(r.get());
 | 
				
			||||||
				++added;
 | 
							}) | ranges::views::filter([](const LayoutItem *item) {
 | 
				
			||||||
			}
 | 
								return item != nullptr;
 | 
				
			||||||
		}
 | 
							}) | ranges::to_vector;
 | 
				
			||||||
		inlineRowFinalize(row, sumWidth, true);
 | 
					
 | 
				
			||||||
 | 
							_mosaic.addItems(resultLayouts);
 | 
				
			||||||
 | 
							added = resultLayouts.size();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resizeToWidth(width());
 | 
						resizeToWidth(width());
 | 
				
			||||||
| 
						 | 
					@ -783,61 +666,11 @@ int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int GifsListWidget::validateExistingInlineRows(const InlineResults &results) {
 | 
					int GifsListWidget::validateExistingInlineRows(const InlineResults &results) {
 | 
				
			||||||
	int count = results.size(), until = 0, untilrow = 0, untilcol = 0;
 | 
						const auto until = _mosaic.validateExistingRows(results);
 | 
				
			||||||
	for (; until < count;) {
 | 
					 | 
				
			||||||
		if (untilrow >= _rows.size() || _rows[untilrow].items[untilcol]->getResult() != results[until].get()) {
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		++until;
 | 
					 | 
				
			||||||
		if (++untilcol == _rows[untilrow].items.size()) {
 | 
					 | 
				
			||||||
			++untilrow;
 | 
					 | 
				
			||||||
			untilcol = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (until == count) { // all items are layed out
 | 
					 | 
				
			||||||
		if (untilrow == _rows.size()) { // nothing changed
 | 
					 | 
				
			||||||
			return until;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int i = untilrow, l = _rows.size(), skip = untilcol; i < l; ++i) {
 | 
						if (_mosaic.empty()) {
 | 
				
			||||||
			for (int j = 0, s = _rows[i].items.size(); j < s; ++j) {
 | 
					 | 
				
			||||||
				if (skip) {
 | 
					 | 
				
			||||||
					--skip;
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					_rows[i].items[j]->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 = 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
 | 
					 | 
				
			||||||
		--untilrow;
 | 
					 | 
				
			||||||
		untilcol = _rows[untilrow].items.size();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	until -= untilcol;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = untilrow, l = _rows.size(); i < l; ++i) {
 | 
					 | 
				
			||||||
		for (int j = 0, s = _rows[i].items.size(); j < s; ++j) {
 | 
					 | 
				
			||||||
			_rows[i].items[j]->setPosition(-1);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_rows.resize(untilrow);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (_rows.isEmpty()) {
 | 
					 | 
				
			||||||
		_inlineWithThumb = false;
 | 
							_inlineWithThumb = false;
 | 
				
			||||||
		for (int i = until; i < count; ++i) {
 | 
							for (int i = until; i < results.size(); ++i) {
 | 
				
			||||||
			if (results.at(i)->hasThumbDisplay()) {
 | 
								if (results.at(i)->hasThumbDisplay()) {
 | 
				
			||||||
				_inlineWithThumb = true;
 | 
									_inlineWithThumb = true;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
| 
						 | 
					@ -853,8 +686,8 @@ void GifsListWidget::inlineItemLayoutChanged(const InlineBots::Layout::ItemBase
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int row = _selected / MatrixRowShift, col = _selected % MatrixRowShift;
 | 
						int row = _selected / MatrixRowShift, col = _selected % MatrixRowShift;
 | 
				
			||||||
	if (row < _rows.size() && col < _rows[row].items.size()) {
 | 
						if (const auto item = _mosaic.maybeItemAt(row, col)) {
 | 
				
			||||||
		if (layout == _rows[row].items[col]) {
 | 
							if (layout == item) {
 | 
				
			||||||
			updateSelected();
 | 
								updateSelected();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -877,14 +710,14 @@ bool GifsListWidget::inlineItemVisible(const InlineBots::Layout::ItemBase *layou
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto row = position / MatrixRowShift;
 | 
						auto row = position / MatrixRowShift;
 | 
				
			||||||
	auto col = position % MatrixRowShift;
 | 
						auto col = position % MatrixRowShift;
 | 
				
			||||||
	Assert((row < _rows.size()) && (col < _rows[row].items.size()));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto top = 0;
 | 
						auto top = 0;
 | 
				
			||||||
	for (auto i = 0; i != row; ++i) {
 | 
						for (auto i = 0; i != row; ++i) {
 | 
				
			||||||
		top += _rows[i].height;
 | 
							top += _mosaic.rowHeightAt(i);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (top < getVisibleBottom()) && (top + _rows[row].items[col]->height() > getVisibleTop());
 | 
						return (top < getVisibleBottom())
 | 
				
			||||||
 | 
							&& (top + _mosaic.itemAt(row, col)->height() > getVisibleTop());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Data::FileOrigin GifsListWidget::inlineItemFileOrigin() {
 | 
					Data::FileOrigin GifsListWidget::inlineItemFileOrigin() {
 | 
				
			||||||
| 
						 | 
					@ -1035,33 +868,36 @@ void GifsListWidget::updateSelected() {
 | 
				
			||||||
	ClickHandlerHost *lnkhost = nullptr;
 | 
						ClickHandlerHost *lnkhost = nullptr;
 | 
				
			||||||
	if (sy >= 0) {
 | 
						if (sy >= 0) {
 | 
				
			||||||
		row = 0;
 | 
							row = 0;
 | 
				
			||||||
		for (int rows = _rows.size(); row < rows; ++row) {
 | 
							for (int rows = _mosaic.rowsCount(); row < rows; ++row) {
 | 
				
			||||||
			if (sy < _rows[row].height) {
 | 
								const auto rowHeight = _mosaic.rowHeightAt(row);
 | 
				
			||||||
 | 
								if (sy < rowHeight) {
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			sy -= _rows[row].height;
 | 
								sy -= rowHeight;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (sx >= 0 && row >= 0 && row < _rows.size()) {
 | 
						if (sx >= 0 && row >= 0 && row < _mosaic.rowsCount()) {
 | 
				
			||||||
		auto &inlineItems = _rows[row].items;
 | 
							const auto columnsCount = _mosaic.columnsCountAt(row);
 | 
				
			||||||
		col = 0;
 | 
							col = 0;
 | 
				
			||||||
		for (int cols = inlineItems.size(); col < cols; ++col) {
 | 
							for (int cols = columnsCount; col < cols; ++col) {
 | 
				
			||||||
			int width = inlineItems[col]->width();
 | 
								const auto item = _mosaic.itemAt(row, col);
 | 
				
			||||||
 | 
								int width = item->width();
 | 
				
			||||||
			if (sx < width) {
 | 
								if (sx < width) {
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			sx -= width;
 | 
								sx -= width;
 | 
				
			||||||
			if (inlineItems[col]->hasRightSkip()) {
 | 
								if (item->hasRightSkip()) {
 | 
				
			||||||
				sx -= st::inlineResultsSkip;
 | 
									sx -= st::inlineResultsSkip;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (col < inlineItems.size()) {
 | 
							if (col < columnsCount) {
 | 
				
			||||||
 | 
								const auto item = _mosaic.itemAt(row, col);
 | 
				
			||||||
			sel = row * MatrixRowShift + col;
 | 
								sel = row * MatrixRowShift + col;
 | 
				
			||||||
			auto result = inlineItems[col]->getState(
 | 
								auto result = item->getState(
 | 
				
			||||||
				QPoint(sx, sy),
 | 
									QPoint(sx, sy),
 | 
				
			||||||
				HistoryView::StateRequest());
 | 
									HistoryView::StateRequest());
 | 
				
			||||||
			lnk = result.link;
 | 
								lnk = result.link;
 | 
				
			||||||
			lnkhost = inlineItems[col];
 | 
								lnkhost = item;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			row = col = -1;
 | 
								row = col = -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1072,18 +908,16 @@ void GifsListWidget::updateSelected() {
 | 
				
			||||||
	int scol = (_selected >= 0) ? (_selected % MatrixRowShift) : -1;
 | 
						int scol = (_selected >= 0) ? (_selected % MatrixRowShift) : -1;
 | 
				
			||||||
	if (_selected != sel) {
 | 
						if (_selected != sel) {
 | 
				
			||||||
		if (srow >= 0 && scol >= 0) {
 | 
							if (srow >= 0 && scol >= 0) {
 | 
				
			||||||
			Assert(srow >= 0 && srow < _rows.size() && scol >= 0 && scol < _rows[srow].items.size());
 | 
								_mosaic.itemAt(srow, scol)->update();
 | 
				
			||||||
			_rows[srow].items[scol]->update();
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		_selected = sel;
 | 
							_selected = sel;
 | 
				
			||||||
		if (row >= 0 && col >= 0) {
 | 
							if (row >= 0 && col >= 0) {
 | 
				
			||||||
			Assert(row >= 0 && row < _rows.size() && col >= 0 && col < _rows[row].items.size());
 | 
								_mosaic.itemAt(row, col)->update();
 | 
				
			||||||
			_rows[row].items[col]->update();
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (_previewShown && _selected >= 0 && _pressed != _selected) {
 | 
							if (_previewShown && _selected >= 0 && _pressed != _selected) {
 | 
				
			||||||
			_pressed = _selected;
 | 
								_pressed = _selected;
 | 
				
			||||||
			if (row >= 0 && col >= 0) {
 | 
								if (row >= 0 && col >= 0) {
 | 
				
			||||||
				auto layout = _rows[row].items[col];
 | 
									const auto layout = _mosaic.itemAt(row, col);
 | 
				
			||||||
				if (const auto previewDocument = layout->getPreviewDocument()) {
 | 
									if (const auto previewDocument = layout->getPreviewDocument()) {
 | 
				
			||||||
					controller()->widget()->showMediaPreview(
 | 
										controller()->widget()->showMediaPreview(
 | 
				
			||||||
						Data::FileOriginSavedGifs(),
 | 
											Data::FileOriginSavedGifs(),
 | 
				
			||||||
| 
						 | 
					@ -1106,8 +940,7 @@ void GifsListWidget::showPreview() {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	int row = _pressed / MatrixRowShift, col = _pressed % MatrixRowShift;
 | 
						int row = _pressed / MatrixRowShift, col = _pressed % MatrixRowShift;
 | 
				
			||||||
	if (row < _rows.size() && col < _rows[row].items.size()) {
 | 
						if (const auto layout = _mosaic.maybeItemAt(row, col)) {
 | 
				
			||||||
		auto layout = _rows[row].items[col];
 | 
					 | 
				
			||||||
		if (const auto previewDocument = layout->getPreviewDocument()) {
 | 
							if (const auto previewDocument = layout->getPreviewDocument()) {
 | 
				
			||||||
			_previewShown = controller()->widget()->showMediaPreview(
 | 
								_previewShown = controller()->widget()->showMediaPreview(
 | 
				
			||||||
				Data::FileOriginSavedGifs(),
 | 
									Data::FileOriginSavedGifs(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
				
			||||||
#include "chat_helpers/tabbed_selector.h"
 | 
					#include "chat_helpers/tabbed_selector.h"
 | 
				
			||||||
#include "base/timer.h"
 | 
					#include "base/timer.h"
 | 
				
			||||||
#include "inline_bots/inline_bot_layout_item.h"
 | 
					#include "inline_bots/inline_bot_layout_item.h"
 | 
				
			||||||
 | 
					#include "inline_bots/inline_results_mosaic_layout.h"
 | 
				
			||||||
#include "app.h"
 | 
					#include "app.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QtCore/QTimer>
 | 
					#include <QtCore/QTimer>
 | 
				
			||||||
| 
						 | 
					@ -142,32 +143,18 @@ private:
 | 
				
			||||||
	base::Timer _updateInlineItems;
 | 
						base::Timer _updateInlineItems;
 | 
				
			||||||
	bool _inlineWithThumb = false;
 | 
						bool _inlineWithThumb = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Row {
 | 
					 | 
				
			||||||
		int maxWidth = 0;
 | 
					 | 
				
			||||||
		int height = 0;
 | 
					 | 
				
			||||||
		QVector<LayoutItem*> items;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	QVector<Row> _rows;
 | 
					 | 
				
			||||||
	void clearInlineRows(bool resultsDeleted);
 | 
						void clearInlineRows(bool resultsDeleted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::map<
 | 
						std::map<
 | 
				
			||||||
		not_null<DocumentData*>,
 | 
							not_null<DocumentData*>,
 | 
				
			||||||
		std::unique_ptr<LayoutItem>> _gifLayouts;
 | 
							std::unique_ptr<LayoutItem>> _gifLayouts;
 | 
				
			||||||
	LayoutItem *layoutPrepareSavedGif(
 | 
						LayoutItem *layoutPrepareSavedGif(not_null<DocumentData*> document);
 | 
				
			||||||
		not_null<DocumentData*> document,
 | 
					 | 
				
			||||||
		int32 position);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::map<
 | 
						std::map<
 | 
				
			||||||
		not_null<InlineResult*>,
 | 
							not_null<InlineResult*>,
 | 
				
			||||||
		std::unique_ptr<LayoutItem>> _inlineLayouts;
 | 
							std::unique_ptr<LayoutItem>> _inlineLayouts;
 | 
				
			||||||
	LayoutItem *layoutPrepareInlineResult(
 | 
						LayoutItem *layoutPrepareInlineResult(not_null<InlineResult*> result);
 | 
				
			||||||
		not_null<InlineResult*> result,
 | 
					 | 
				
			||||||
		int32 position);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, Row &row, int32 &sumWidth);
 | 
					 | 
				
			||||||
	bool inlineRowFinalize(Row &row, int32 &sumWidth, bool force = false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void layoutInlineRow(Row &row, int fullWidth);
 | 
					 | 
				
			||||||
	void deleteUnusedGifLayouts();
 | 
						void deleteUnusedGifLayouts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void deleteUnusedInlineLayouts();
 | 
						void deleteUnusedInlineLayouts();
 | 
				
			||||||
| 
						 | 
					@ -182,6 +169,8 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Footer *_footer = nullptr;
 | 
						Footer *_footer = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InlineBots::Layout::MosaicLayout _mosaic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int _selected = -1;
 | 
						int _selected = -1;
 | 
				
			||||||
	int _pressed = -1;
 | 
						int _pressed = -1;
 | 
				
			||||||
	QPoint _lastMousePos;
 | 
						QPoint _lastMousePos;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue