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