tdesktop/Telegram/SourceFiles/layout/layout_mosaic.h

157 lines
4.1 KiB
C++

/*
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 "layout/abstract_layout_item.h"
#include "layout/layout_position.h"
namespace Mosaic::Layout {
struct FoundItem {
int index = -1;
bool exact = false;
QPoint relative;
};
class AbstractMosaicLayout {
public:
AbstractMosaicLayout(int bigWidth);
[[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 setRightSkip(int rightSkip);
void setPadding(QMargins padding);
void setFullWidth(int w);
[[nodiscard]] bool empty() const;
[[nodiscard]] int rowsCount() const;
void clearRows(bool resultsDeleted);
protected:
void addItems(gsl::span<const not_null<AbstractLayoutItem*>> items);
[[nodiscard]] not_null<AbstractLayoutItem*> itemAt(int row, int column) const;
[[nodiscard]] not_null<AbstractLayoutItem*> itemAt(int index) const;
[[nodiscard]] AbstractLayoutItem *maybeItemAt(int row, int column) const;
[[nodiscard]] AbstractLayoutItem *maybeItemAt(int index) const;
void forEach(Fn<void(not_null<const AbstractLayoutItem*>)> callback);
void paint(
Fn<void(not_null<AbstractLayoutItem*>, QPoint)> paintItem,
const QRect &clip) const;
int validateExistingRows(
Fn<bool(not_null<const AbstractLayoutItem*>, int)> checkItem,
int count);
private:
static constexpr auto kInlineItemsMaxPerRow = 5;
struct Row {
int maxWidth = 0;
int height = 0;
std::vector<AbstractLayoutItem*> items;
};
void addItem(not_null<AbstractLayoutItem*> 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;
QMargins _padding;
std::vector<Row> _rows;
};
template <
typename ItemBase,
typename = std::enable_if_t<
std::is_base_of_v<AbstractLayoutItem, ItemBase>>>
class MosaicLayout final : public AbstractMosaicLayout {
using Parent = AbstractMosaicLayout;
public:
using Parent::Parent;
void addItems(const std::vector<not_null<ItemBase*>> &items) {
Parent::addItems({
reinterpret_cast<const not_null<AbstractLayoutItem*>*>(
items.data()),
items.size() });
}
[[nodiscard]] not_null<ItemBase*> itemAt(int row, int column) const {
return Downcast(Parent::itemAt(row, column));
}
[[nodiscard]] not_null<ItemBase*> itemAt(int index) const {
return Downcast(Parent::itemAt(index));
}
[[nodiscard]] ItemBase *maybeItemAt(int row, int column) const {
return Downcast(Parent::maybeItemAt(row, column));
}
[[nodiscard]] ItemBase *maybeItemAt(int index) const {
return Downcast(Parent::maybeItemAt(index));
}
void forEach(Fn<void(not_null<const ItemBase*>)> callback) {
Parent::forEach([&](
not_null<const AbstractLayoutItem*> item) {
callback(Downcast(item));
});
}
void paint(
Fn<void(not_null<ItemBase*>, QPoint)> paintItem,
const QRect &clip) const {
Parent::paint([&](
not_null<AbstractLayoutItem*> item,
QPoint point) {
paintItem(Downcast(item), point);
}, clip);
}
int validateExistingRows(
Fn<bool(not_null<const ItemBase*>, int)> checkItem,
int count) {
return Parent::validateExistingRows([&](
not_null<const AbstractLayoutItem*> item,
int until) {
return checkItem(Downcast(item), until);
}, count);
}
private:
[[nodiscard]] static not_null<ItemBase*> Downcast(
not_null<AbstractLayoutItem*> item) {
return static_cast<ItemBase*>(item.get());
}
[[nodiscard]] static ItemBase *Downcast(
AbstractLayoutItem *item) {
return static_cast<ItemBase*>(item);
}
[[nodiscard]] static not_null<const ItemBase*> Downcast(
not_null<const AbstractLayoutItem*> item) {
return static_cast<const ItemBase*>(item.get());
}
[[nodiscard]] static const ItemBase *Downcast(
const AbstractLayoutItem *item) {
return static_cast<const ItemBase*>(item);
}
};
} // namespace Mosaic::Layout