mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Animated transition on pattern-on-gradient resize.
This commit is contained in:
parent
b9a9520ef5
commit
3dadcd9352
17 changed files with 213 additions and 135 deletions
|
@ -26,7 +26,7 @@ object_ptr<Window::SectionWidget> TabbedMemento::createWidget(
|
|||
TabbedSection::TabbedSection(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: Window::SectionWidget(parent, controller)
|
||||
: Window::SectionWidget(parent, controller, PaintedBackground::Custom)
|
||||
, _selector(controller->tabbedSelector()) {
|
||||
_selector->setParent(this);
|
||||
_selector->setRoundRadius(0);
|
||||
|
|
|
@ -164,7 +164,7 @@ void Widget::BottomButton::paintEvent(QPaintEvent *e) {
|
|||
Widget::Widget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: Window::AbstractSectionWidget(parent, controller)
|
||||
: Window::AbstractSectionWidget(parent, controller, PaintedBackground::Custom)
|
||||
, _api(&controller->session().mtp())
|
||||
, _searchControls(this)
|
||||
, _mainMenuToggle(_searchControls, st::dialogsMenuToggle)
|
||||
|
|
|
@ -275,11 +275,14 @@ Widget::Widget(
|
|||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<ChannelData*> channel)
|
||||
: Window::SectionWidget(parent, controller)
|
||||
: Window::SectionWidget(parent, controller, PaintedBackground::Section)
|
||||
, _scroll(this, st::historyScroll, false)
|
||||
, _fixedBar(this, controller, channel)
|
||||
, _fixedBarShadow(this)
|
||||
, _whatIsThis(this, tr::lng_admin_log_about(tr::now).toUpper(), st::historyComposeButton) {
|
||||
, _whatIsThis(
|
||||
this,
|
||||
tr::lng_admin_log_about(tr::now).toUpper(),
|
||||
st::historyComposeButton) {
|
||||
_fixedBar->move(0, 0);
|
||||
_fixedBar->resizeToWidth(width());
|
||||
_fixedBar->showFilterRequests(
|
||||
|
@ -303,6 +306,11 @@ Widget::Widget(
|
|||
updateAdaptiveLayout();
|
||||
}, lifetime());
|
||||
|
||||
controller->repaintBackgroundRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
_inner = _scroll->setOwnedWidget(object_ptr<InnerWidget>(this, controller, channel));
|
||||
_inner->showSearchSignal(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
|
|
@ -171,7 +171,7 @@ const auto kPsaAboutPrefix = "cloud_lng_about_psa_";
|
|||
HistoryWidget::HistoryWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: Window::AbstractSectionWidget(parent, controller)
|
||||
: Window::AbstractSectionWidget(parent, controller, PaintedBackground::Section)
|
||||
, _api(&controller->session().mtp())
|
||||
, _updateEditTimeLeftDisplay([=] { updateField(); })
|
||||
, _fieldBarCancel(this, st::historyReplyCancel)
|
||||
|
@ -432,6 +432,11 @@ HistoryWidget::HistoryWidget(
|
|||
}
|
||||
}, lifetime());
|
||||
|
||||
controller->repaintBackgroundRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, lifetime());
|
||||
|
||||
session().data().newItemAdded(
|
||||
) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
|
||||
newItemAdded(item);
|
||||
|
|
|
@ -90,7 +90,7 @@ PinnedWidget::PinnedWidget(
|
|||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<History*> history)
|
||||
: Window::SectionWidget(parent, controller)
|
||||
: Window::SectionWidget(parent, controller, PaintedBackground::Section)
|
||||
, _history(history->migrateToOrMe())
|
||||
, _migratedPeer(_history->peer->migrateFrom())
|
||||
, _topBar(this, controller)
|
||||
|
|
|
@ -146,7 +146,7 @@ RepliesWidget::RepliesWidget(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<History*> history,
|
||||
MsgId rootId)
|
||||
: Window::SectionWidget(parent, controller)
|
||||
: Window::SectionWidget(parent, controller, PaintedBackground::Section)
|
||||
, _history(history)
|
||||
, _rootId(rootId)
|
||||
, _root(lookupRoot())
|
||||
|
|
|
@ -90,7 +90,7 @@ ScheduledWidget::ScheduledWidget(
|
|||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<History*> history)
|
||||
: Window::SectionWidget(parent, controller)
|
||||
: Window::SectionWidget(parent, controller, PaintedBackground::Section)
|
||||
, _history(history)
|
||||
, _scroll(this, st::historyScroll, false)
|
||||
, _topBar(this, controller)
|
||||
|
|
|
@ -24,7 +24,7 @@ SectionWidget::SectionWidget(
|
|||
not_null<Window::SessionController*> window,
|
||||
Wrap wrap,
|
||||
not_null<Memento*> memento)
|
||||
: Window::SectionWidget(parent, window)
|
||||
: Window::SectionWidget(parent, window, PaintedBackground::Custom)
|
||||
, _content(this, window, wrap, memento) {
|
||||
init();
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ SectionWidget::SectionWidget(
|
|||
not_null<Window::SessionController*> window,
|
||||
Wrap wrap,
|
||||
not_null<MoveMemento*> memento)
|
||||
: Window::SectionWidget(parent, window)
|
||||
: Window::SectionWidget(parent, window, PaintedBackground::Custom)
|
||||
, _content(memento->takeContent(this, wrap)) {
|
||||
init();
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ WrapWidget::WrapWidget(
|
|||
not_null<Window::SessionController*> window,
|
||||
Wrap wrap,
|
||||
not_null<Memento*> memento)
|
||||
: SectionWidget(parent, window)
|
||||
: SectionWidget(parent, window, PaintedBackground::Custom)
|
||||
, _wrap(wrap)
|
||||
, _controller(createController(window, memento->content()))
|
||||
, _topShadow(this) {
|
||||
|
|
|
@ -571,18 +571,21 @@ void BackgroundRow::updateImage() {
|
|||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
p.setOpacity(patternOpacity);
|
||||
}
|
||||
const auto &pix = background->pixmap();
|
||||
if (!pix.isNull()) {
|
||||
const auto sx = (pix.width() > pix.height())
|
||||
? ((pix.width() - pix.height()) / 2)
|
||||
const auto &prepared = background->prepared();
|
||||
if (!prepared.isNull()) {
|
||||
const auto sx = (prepared.width() > prepared.height())
|
||||
? ((prepared.width() - prepared.height()) / 2)
|
||||
: 0;
|
||||
const auto sy = (pix.height() > pix.width())
|
||||
? ((pix.height() - pix.width()) / 2)
|
||||
const auto sy = (prepared.height() > prepared.width())
|
||||
? ((prepared.height() - prepared.width()) / 2)
|
||||
: 0;
|
||||
const auto s = (pix.width() > pix.height())
|
||||
? pix.height()
|
||||
: pix.width();
|
||||
p.drawPixmap(0, 0, size, size, pix, sx, sy, s, s);
|
||||
const auto s = (prepared.width() > prepared.height())
|
||||
? prepared.height()
|
||||
: prepared.width();
|
||||
p.drawImage(
|
||||
QRect(0, 0, size, size),
|
||||
prepared,
|
||||
QRect(sx, sy, s, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Window {
|
||||
|
||||
AbstractSectionWidget::AbstractSectionWidget(
|
||||
QWidget *parent,
|
||||
not_null<SessionController*> controller,
|
||||
PaintedBackground paintedBackground)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller) {
|
||||
if (paintedBackground == PaintedBackground::Section) {
|
||||
controller->repaintBackgroundRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, lifetime());
|
||||
}
|
||||
}
|
||||
|
||||
Main::Session &AbstractSectionWidget::session() const {
|
||||
return _controller->session();
|
||||
}
|
||||
|
||||
SectionWidget::SectionWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
: AbstractSectionWidget(parent, controller) {
|
||||
not_null<Window::SessionController*> controller,
|
||||
PaintedBackground paintedBackground)
|
||||
: AbstractSectionWidget(parent, controller, paintedBackground) {
|
||||
}
|
||||
|
||||
void SectionWidget::setGeometryWithTopMoved(
|
||||
|
@ -99,18 +114,16 @@ void SectionWidget::PaintBackground(
|
|||
const auto gradient = background->gradientForFill();
|
||||
const auto fill = QSize(widget->width(), fullHeight);
|
||||
auto fromy = controller->content()->backgroundFromY();
|
||||
auto cached = controller->cachedBackground(fill);
|
||||
const auto goodCache = (cached.area == fill);
|
||||
const auto useCached = goodCache || !gradient.isNull();
|
||||
if (!cached.pixmap.isNull()) {
|
||||
auto state = controller->backgroundState(fill);
|
||||
const auto paintCache = [&](const CachedBackground &cache) {
|
||||
const auto to = QRect(
|
||||
QPoint(cached.x, fromy + cached.y),
|
||||
cached.pixmap.size() / cIntRetinaFactor());
|
||||
if (goodCache) {
|
||||
p.drawPixmap(to, cached.pixmap);
|
||||
QPoint(cache.x, fromy + cache.y),
|
||||
cache.pixmap.size() / cIntRetinaFactor());
|
||||
if (cache.area == fill) {
|
||||
p.drawPixmap(to, cache.pixmap);
|
||||
} else {
|
||||
const auto sx = fill.width() / float64(cached.area.width());
|
||||
const auto sy = fill.height() / float64(cached.area.height());
|
||||
const auto sx = fill.width() / float64(cache.area.width());
|
||||
const auto sy = fill.height() / float64(cache.area.height());
|
||||
const auto round = [](float64 value) -> int {
|
||||
return (value >= 0.)
|
||||
? int(std::ceil(value))
|
||||
|
@ -122,17 +135,27 @@ void SectionWidget::PaintBackground(
|
|||
sto.y(),
|
||||
round((to.x() + to.width()) * sx) - sto.x(),
|
||||
round((to.y() + to.height()) * sy) - sto.y(),
|
||||
cached.pixmap);
|
||||
cache.pixmap);
|
||||
}
|
||||
};
|
||||
const auto goodNow = !state.now.pixmap.isNull()
|
||||
&& (state.now.area == fill);
|
||||
const auto useCache = goodNow || !gradient.isNull();
|
||||
if (useCache) {
|
||||
if (state.shown < 1. && !gradient.isNull()) {
|
||||
paintCache(state.was);
|
||||
p.setOpacity(state.shown);
|
||||
}
|
||||
paintCache(state.now);
|
||||
return;
|
||||
}
|
||||
const auto patternOpacity = background->paper().patternOpacity();
|
||||
const auto &bg = background->pixmap();
|
||||
if (!bg.isNull() && !background->tile()) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto &prepared = background->prepared();
|
||||
if (!prepared.isNull() && !background->tile()) {
|
||||
const auto hq = PainterHighQualityEnabler(p);
|
||||
const auto rects = Window::Theme::ComputeBackgroundRects(
|
||||
fill,
|
||||
bg.size());
|
||||
prepared.size());
|
||||
if (!gradient.isNull()) {
|
||||
p.drawImage(rects.to, gradient);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
|
@ -140,17 +163,17 @@ void SectionWidget::PaintBackground(
|
|||
}
|
||||
auto to = rects.to;
|
||||
to.moveTop(to.top() + fromy);
|
||||
p.drawPixmap(to, bg, rects.from);
|
||||
p.drawImage(to, prepared, rects.from);
|
||||
return;
|
||||
}
|
||||
if (!gradient.isNull()) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto hq = PainterHighQualityEnabler(p);
|
||||
p.drawImage(QRect(QPoint(0, fromy), fill), gradient);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
p.setOpacity(patternOpacity);
|
||||
}
|
||||
if (!bg.isNull()) {
|
||||
auto &tiled = background->pixmapForTiled();
|
||||
if (!prepared.isNull()) {
|
||||
const auto &tiled = background->preparedForTiled();
|
||||
auto left = clip.left();
|
||||
auto top = clip.top();
|
||||
auto right = clip.left() + clip.width();
|
||||
|
@ -163,7 +186,7 @@ void SectionWidget::PaintBackground(
|
|||
auto cy = qCeil((bottom - fromy) / h);
|
||||
for (auto i = sx; i < cx; ++i) {
|
||||
for (auto j = sy; j < cy; ++j) {
|
||||
p.drawPixmap(QPointF(i * w, fromy + j * h), tiled);
|
||||
p.drawImage(QPointF(i * w, fromy + j * h), tiled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,14 @@ class AbstractSectionWidget
|
|||
, public Media::Player::FloatSectionDelegate
|
||||
, protected base::Subscriber {
|
||||
public:
|
||||
enum class PaintedBackground {
|
||||
Section,
|
||||
Custom,
|
||||
};
|
||||
AbstractSectionWidget(
|
||||
QWidget *parent,
|
||||
not_null<SessionController*> controller)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller) {
|
||||
}
|
||||
not_null<SessionController*> controller,
|
||||
PaintedBackground paintedBackground);
|
||||
|
||||
[[nodiscard]] Main::Session &session() const;
|
||||
[[nodiscard]] not_null<SessionController*> controller() const {
|
||||
|
@ -84,7 +86,8 @@ class SectionWidget : public AbstractSectionWidget {
|
|||
public:
|
||||
SectionWidget(
|
||||
QWidget *parent,
|
||||
not_null<SessionController*> controller);
|
||||
not_null<SessionController*> controller,
|
||||
PaintedBackground paintedBackground);
|
||||
|
||||
virtual Dialogs::RowDescriptor activeChat() const {
|
||||
return {};
|
||||
|
|
|
@ -730,8 +730,8 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
|||
Assert(colorForFill()
|
||||
|| !_gradient.isNull()
|
||||
|| (!_original.isNull()
|
||||
&& !_pixmap.isNull()
|
||||
&& !_pixmapForTiled.isNull()));
|
||||
&& !_prepared.isNull()
|
||||
&& !_preparedForTiled.isNull()));
|
||||
|
||||
_updates.fire({ BackgroundUpdate::Type::New, tile() }); // delayed?
|
||||
if (needResetAdjustable) {
|
||||
|
@ -763,46 +763,42 @@ void ChatBackground::setPrepared(
|
|||
}
|
||||
|
||||
_original = std::move(original);
|
||||
_prepared = std::move(prepared);
|
||||
_gradient = std::move(gradient);
|
||||
preparePixmaps(std::move(prepared));
|
||||
_imageMonoColor = _gradient.isNull()
|
||||
? CalculateImageMonoColor(_prepared)
|
||||
: std::nullopt;
|
||||
prepareImageForTiled();
|
||||
}
|
||||
|
||||
void ChatBackground::preparePixmaps(QImage image) {
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
void ChatBackground::prepareImageForTiled() {
|
||||
const auto width = _prepared.width();
|
||||
const auto height = _prepared.height();
|
||||
const auto isSmallForTiled = (width > 0 && height > 0)
|
||||
&& (width < kMinimumTiledSize || height < kMinimumTiledSize);
|
||||
if (isSmallForTiled) {
|
||||
const auto repeatTimesX = qCeil(kMinimumTiledSize / (1. * width));
|
||||
const auto repeatTimesY = qCeil(kMinimumTiledSize / (1. * height));
|
||||
auto imageForTiled = QImage(
|
||||
width * repeatTimesX,
|
||||
height * repeatTimesY,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
imageForTiled.setDevicePixelRatio(image.devicePixelRatio());
|
||||
auto imageForTiledBytes = imageForTiled.bits();
|
||||
auto bytesInLine = width * sizeof(uint32);
|
||||
for (auto timesY = 0; timesY != repeatTimesY; ++timesY) {
|
||||
auto imageBytes = image.constBits();
|
||||
for (auto y = 0; y != height; ++y) {
|
||||
for (auto timesX = 0; timesX != repeatTimesX; ++timesX) {
|
||||
memcpy(imageForTiledBytes, imageBytes, bytesInLine);
|
||||
imageForTiledBytes += bytesInLine;
|
||||
}
|
||||
imageBytes += image.bytesPerLine();
|
||||
imageForTiledBytes += imageForTiled.bytesPerLine() - (repeatTimesX * bytesInLine);
|
||||
}
|
||||
}
|
||||
_pixmapForTiled = Ui::PixmapFromImage(std::move(imageForTiled));
|
||||
}
|
||||
_imageMonoColor = _gradient.isNull()
|
||||
? CalculateImageMonoColor(image)
|
||||
: std::nullopt;
|
||||
_pixmap = image.isNull()
|
||||
? QPixmap()
|
||||
: Ui::PixmapFromImage(std::move(image));
|
||||
if (!isSmallForTiled) {
|
||||
_pixmapForTiled = _pixmap;
|
||||
_preparedForTiled = _prepared;
|
||||
return;
|
||||
}
|
||||
const auto repeatTimesX = qCeil(kMinimumTiledSize / (1. * width));
|
||||
const auto repeatTimesY = qCeil(kMinimumTiledSize / (1. * height));
|
||||
_preparedForTiled = QImage(
|
||||
width * repeatTimesX,
|
||||
height * repeatTimesY,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_preparedForTiled.setDevicePixelRatio(_prepared.devicePixelRatio());
|
||||
auto imageForTiledBytes = _preparedForTiled.bits();
|
||||
auto bytesInLine = width * sizeof(uint32);
|
||||
for (auto timesY = 0; timesY != repeatTimesY; ++timesY) {
|
||||
auto imageBytes = _prepared.constBits();
|
||||
for (auto y = 0; y != height; ++y) {
|
||||
for (auto timesX = 0; timesX != repeatTimesX; ++timesX) {
|
||||
memcpy(imageForTiledBytes, imageBytes, bytesInLine);
|
||||
imageForTiledBytes += bytesInLine;
|
||||
}
|
||||
imageBytes += _prepared.bytesPerLine();
|
||||
imageForTiledBytes += _preparedForTiled.bytesPerLine() - (repeatTimesX * bytesInLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -868,7 +864,7 @@ void ChatBackground::adjustPaletteUsingColor(QColor color) {
|
|||
}
|
||||
|
||||
std::optional<QColor> ChatBackground::colorForFill() const {
|
||||
return !_pixmap.isNull()
|
||||
return !_prepared.isNull()
|
||||
? imageMonoColor()
|
||||
: !_gradient.isNull()
|
||||
? std::nullopt
|
||||
|
@ -888,13 +884,12 @@ QImage ChatBackground::createCurrentImage() const {
|
|||
result.fill(*fill);
|
||||
return result;
|
||||
} else if (_gradient.isNull()) {
|
||||
return pixmap().toImage();
|
||||
} else if (pixmap().isNull()) {
|
||||
return _prepared;
|
||||
} else if (_prepared.isNull()) {
|
||||
return _gradient;
|
||||
}
|
||||
const auto &pattern = pixmap();
|
||||
auto result = _gradient.scaled(
|
||||
pattern.size(),
|
||||
_prepared.size(),
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
result.setDevicePixelRatio(1.);
|
||||
|
@ -902,7 +897,7 @@ QImage ChatBackground::createCurrentImage() const {
|
|||
auto p = QPainter(&result);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
p.setOpacity(paper().patternOpacity());
|
||||
p.drawPixmap(QRect(QPoint(), pattern.size()), pattern);
|
||||
p.drawImage(QRect(QPoint(), _prepared.size()), _prepared);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1044,7 +1039,7 @@ void ChatBackground::setTestingTheme(Instance &&theme) {
|
|||
saveForRevert();
|
||||
set(
|
||||
Data::details::TestingEditorWallPaper(),
|
||||
std::move(_pixmap).toImage());
|
||||
base::take(_prepared));
|
||||
}
|
||||
} else if (switchToThemeBackground) {
|
||||
saveForRevert();
|
||||
|
|
|
@ -170,11 +170,11 @@ public:
|
|||
[[nodiscard]] WallPaperId id() const {
|
||||
return _paper.id();
|
||||
}
|
||||
[[nodiscard]] const QPixmap &pixmap() const {
|
||||
return _pixmap;
|
||||
[[nodiscard]] const QImage &prepared() const {
|
||||
return _prepared;
|
||||
}
|
||||
[[nodiscard]] const QPixmap &pixmapForTiled() const {
|
||||
return _pixmapForTiled;
|
||||
[[nodiscard]] const QImage &preparedForTiled() const {
|
||||
return _preparedForTiled;
|
||||
}
|
||||
[[nodiscard]] std::optional<QColor> colorForFill() const;
|
||||
[[nodiscard]] QImage gradientForFill() const;
|
||||
|
@ -197,7 +197,7 @@ private:
|
|||
void initialRead();
|
||||
void saveForRevert();
|
||||
void setPrepared(QImage original, QImage prepared, QImage gradient);
|
||||
void preparePixmaps(QImage image);
|
||||
void prepareImageForTiled();
|
||||
void writeNewBackgroundSettings();
|
||||
void setPaper(const Data::WallPaper &paper);
|
||||
|
||||
|
@ -239,8 +239,8 @@ private:
|
|||
std::optional<QColor> _paperColor;
|
||||
QImage _gradient;
|
||||
QImage _original;
|
||||
QPixmap _pixmap;
|
||||
QPixmap _pixmapForTiled;
|
||||
QImage _prepared;
|
||||
QImage _preparedForTiled;
|
||||
bool _nightMode = false;
|
||||
bool _tileDayValue = false;
|
||||
bool _tileNightValue = true;
|
||||
|
|
|
@ -988,10 +988,11 @@ void MainMenu::refreshBackground() {
|
|||
const auto intensityText = IntensityOfColor(st::mainMenuCoverFg->c);
|
||||
const auto background = Window::Theme::Background();
|
||||
const auto &paper = background->paper();
|
||||
const auto &pixmap = background->pixmap();
|
||||
const auto &prepared = background->prepared();
|
||||
|
||||
QRect to, from;
|
||||
const auto rects = Window::Theme::ComputeBackgroundRects(fill, pixmap.size());
|
||||
const auto rects = Window::Theme::ComputeBackgroundRects(
|
||||
fill,
|
||||
prepared.size());
|
||||
|
||||
auto backgroundImage = !paper.backgroundColors().empty()
|
||||
? Data::GenerateWallPaper(
|
||||
|
@ -999,7 +1000,7 @@ void MainMenu::refreshBackground() {
|
|||
paper.backgroundColors(),
|
||||
paper.gradientRotation(),
|
||||
paper.patternOpacity(),
|
||||
[&](QPainter &p) { p.drawPixmap(to, pixmap, from); })
|
||||
[&](QPainter &p) { p.drawImage(rects.to, prepared, rects.from); })
|
||||
: QImage(
|
||||
fill * cIntRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
|
@ -1029,7 +1030,7 @@ void MainMenu::refreshBackground() {
|
|||
|
||||
// Background image.
|
||||
if (!paper.isPattern()) {
|
||||
p.drawPixmap(to, pixmap, from);
|
||||
p.drawImage(rects.to, prepared, rects.from);
|
||||
}
|
||||
|
||||
// Cut off the part of the background that is under text.
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace {
|
|||
constexpr auto kMaxChatEntryHistorySize = 50;
|
||||
constexpr auto kCacheBackgroundTimeout = 3 * crl::time(1000);
|
||||
constexpr auto kCacheBackgroundFastTimeout = crl::time(200);
|
||||
constexpr auto kBackgroundFadeDuration = crl::time(200);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -1318,15 +1319,16 @@ void SessionController::openDocument(
|
|||
session().data().message(contextId));
|
||||
}
|
||||
|
||||
CachedBackground SessionController::cachedBackground(QSize area) {
|
||||
if (_cachedBackground.area != area) {
|
||||
const BackgroundState &SessionController::backgroundState(QSize area) {
|
||||
_backgroundState.shown = _backgroundFade.value(1.);
|
||||
if (_backgroundState.now.area != area) {
|
||||
if (_willCacheForArea != area || !_cacheBackgroundTimer.isActive()) {
|
||||
_willCacheForArea = area;
|
||||
_lastAreaChangeTime = crl::now();
|
||||
_cacheBackgroundTimer.callOnce(kCacheBackgroundFastTimeout);
|
||||
}
|
||||
}
|
||||
return _cachedBackground;
|
||||
return _backgroundState;
|
||||
}
|
||||
|
||||
void SessionController::cacheBackground() {
|
||||
|
@ -1342,8 +1344,8 @@ void SessionController::cacheBackground() {
|
|||
}
|
||||
const auto gradient = background->gradientForFill();
|
||||
const auto patternOpacity = background->paper().patternOpacity();
|
||||
const auto &bg = background->pixmap();
|
||||
if (background->tile() || bg.isNull()) {
|
||||
const auto &prepared = background->prepared();
|
||||
if (background->tile() || prepared.isNull()) {
|
||||
auto result = gradient.isNull()
|
||||
? QImage(
|
||||
_willCacheForArea * cIntRetinaFactor(),
|
||||
|
@ -1353,34 +1355,34 @@ void SessionController::cacheBackground() {
|
|||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
if (!bg.isNull()) {
|
||||
if (!prepared.isNull()) {
|
||||
QPainter p(&result);
|
||||
if (!gradient.isNull()) {
|
||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
p.setOpacity(patternOpacity);
|
||||
}
|
||||
const auto &tiled = background->pixmapForTiled();
|
||||
auto w = tiled.width() / cRetinaFactor();
|
||||
auto h = tiled.height() / cRetinaFactor();
|
||||
const auto &tiled = background->preparedForTiled();
|
||||
const auto w = tiled.width() / cRetinaFactor();
|
||||
const auto h = tiled.height() / cRetinaFactor();
|
||||
auto sx = 0;
|
||||
auto sy = 0;
|
||||
auto cx = qCeil(_willCacheForArea.width() / w);
|
||||
auto cy = qCeil(_willCacheForArea.height() / h);
|
||||
const auto cx = qCeil(_willCacheForArea.width() / w);
|
||||
const auto cy = qCeil(_willCacheForArea.height() / h);
|
||||
for (int i = sx; i < cx; ++i) {
|
||||
for (int j = sy; j < cy; ++j) {
|
||||
p.drawPixmap(QPointF(i * w, j * h), tiled);
|
||||
p.drawImage(QPointF(i * w, j * h), tiled);
|
||||
}
|
||||
}
|
||||
}
|
||||
_cachedBackground = CachedBackground{
|
||||
setCachedBackground({
|
||||
.pixmap = Ui::PixmapFromImage(std::move(result)),
|
||||
.area = _willCacheForArea,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
const auto rects = Window::Theme::ComputeBackgroundRects(
|
||||
_willCacheForArea,
|
||||
bg.size());
|
||||
auto image = bg.toImage().copy(rects.from).scaled(
|
||||
prepared.size());
|
||||
auto image = prepared.copy(rects.from).scaled(
|
||||
rects.to.width() * cIntRetinaFactor(),
|
||||
rects.to.height() * cIntRetinaFactor(),
|
||||
Qt::IgnoreAspectRatio,
|
||||
|
@ -1399,21 +1401,51 @@ void SessionController::cacheBackground() {
|
|||
p.drawImage(QRect(QPoint(), rects.to.size()), image);
|
||||
}
|
||||
image = QImage();
|
||||
_cachedBackground = {
|
||||
setCachedBackground({
|
||||
.pixmap = Ui::PixmapFromImage(std::move(result)),
|
||||
.area = _willCacheForArea,
|
||||
.x = rects.to.x(),
|
||||
.y = rects.to.y(),
|
||||
};
|
||||
}
|
||||
if (!gradient.isNull()) {
|
||||
content()->update();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void SessionController::setCachedBackground(CachedBackground &&cached) {
|
||||
const auto background = Window::Theme::Background();
|
||||
if (background->gradientForFill().isNull()
|
||||
|| _backgroundState.now.pixmap.isNull()) {
|
||||
_backgroundFade.stop();
|
||||
_backgroundState.shown = 1.;
|
||||
_backgroundState.now = std::move(cached);
|
||||
return;
|
||||
}
|
||||
// #TODO themes compose several transitions.
|
||||
_backgroundState.was = std::move(_backgroundState.now);
|
||||
_backgroundState.now = std::move(cached);
|
||||
_backgroundState.shown = 0.;
|
||||
const auto callback = [=] {
|
||||
if (!_backgroundFade.animating()) {
|
||||
_backgroundState.was = {};
|
||||
_backgroundState.shown = 1.;
|
||||
}
|
||||
_repaintBackgroundRequests.fire({});
|
||||
};
|
||||
_backgroundFade.start(
|
||||
callback,
|
||||
0.,
|
||||
1.,
|
||||
kBackgroundFadeDuration);
|
||||
}
|
||||
|
||||
void SessionController::clearCachedBackground() {
|
||||
_cachedBackground = {};
|
||||
_backgroundState = {};
|
||||
_backgroundFade.stop();
|
||||
_cacheBackgroundTimer.cancel();
|
||||
_repaintBackgroundRequests.fire({});
|
||||
}
|
||||
|
||||
rpl::producer<> SessionController::repaintBackgroundRequests() const {
|
||||
return _repaintBackgroundRequests.events();
|
||||
}
|
||||
|
||||
SessionController::~SessionController() {
|
||||
|
|
|
@ -7,13 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <rpl/variable.h>
|
||||
#include "base/flags.h"
|
||||
#include "base/object_ptr.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "base/timer.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/layers/layer_widget.h"
|
||||
#include "window/window_adaptive.h"
|
||||
|
||||
|
@ -63,6 +62,12 @@ struct CachedBackground {
|
|||
int y = 0;
|
||||
};
|
||||
|
||||
struct BackgroundState {
|
||||
CachedBackground was;
|
||||
CachedBackground now;
|
||||
float64 shown = 1.;
|
||||
};
|
||||
|
||||
enum class GifPauseReason {
|
||||
Any = 0,
|
||||
InlineResults = (1 << 0),
|
||||
|
@ -232,7 +237,6 @@ private:
|
|||
MsgId _showingRepliesRootId = 0;
|
||||
mtpRequestId _showingRepliesRequestId = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class SessionController : public SessionNavigation {
|
||||
|
@ -296,11 +300,11 @@ public:
|
|||
void floatPlayerAreaUpdated();
|
||||
|
||||
struct ColumnLayout {
|
||||
int bodyWidth;
|
||||
int dialogsWidth;
|
||||
int chatWidth;
|
||||
int thirdWidth;
|
||||
Adaptive::WindowLayout windowLayout;
|
||||
int bodyWidth = 0;
|
||||
int dialogsWidth = 0;
|
||||
int chatWidth = 0;
|
||||
int thirdWidth = 0;
|
||||
Adaptive::WindowLayout windowLayout = Adaptive::WindowLayout();
|
||||
};
|
||||
[[nodiscard]] ColumnLayout computeColumnLayout() const;
|
||||
int dialogsSmallColumnWidth() const;
|
||||
|
@ -400,7 +404,8 @@ public:
|
|||
void toggleFiltersMenu(bool enabled);
|
||||
[[nodiscard]] rpl::producer<> filtersMenuChanged() const;
|
||||
|
||||
[[nodiscard]] CachedBackground cachedBackground(QSize area);
|
||||
[[nodiscard]] const BackgroundState &backgroundState(QSize area);
|
||||
[[nodiscard]] rpl::producer<> repaintBackgroundRequests() const;
|
||||
|
||||
rpl::lifetime &lifetime() {
|
||||
return _lifetime;
|
||||
|
@ -433,6 +438,7 @@ private:
|
|||
|
||||
void cacheBackground();
|
||||
void clearCachedBackground();
|
||||
void setCachedBackground(CachedBackground &&cached);
|
||||
|
||||
const not_null<Controller*> _window;
|
||||
|
||||
|
@ -461,10 +467,12 @@ private:
|
|||
|
||||
rpl::event_stream<> _filtersMenuChanged;
|
||||
|
||||
CachedBackground _cachedBackground;
|
||||
BackgroundState _backgroundState;
|
||||
Ui::Animations::Simple _backgroundFade;
|
||||
QSize _willCacheForArea;
|
||||
crl::time _lastAreaChangeTime = 0;
|
||||
base::Timer _cacheBackgroundTimer;
|
||||
rpl::event_stream<> _repaintBackgroundRequests;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue