mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Colorize bubbles according to a custom chat theme.
This commit is contained in:
parent
5de83ef30c
commit
beff635e45
38 changed files with 479 additions and 165 deletions
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
|
@ -365,6 +366,7 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||||
const Data::WallPaper &paper)
|
const Data::WallPaper &paper)
|
||||||
: SimpleElementDelegate(controller, [=] { update(); })
|
: SimpleElementDelegate(controller, [=] { update(); })
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
|
, _chatStyle(std::make_unique<Ui::ChatStyle>())
|
||||||
, _text1(GenerateTextItem(
|
, _text1(GenerateTextItem(
|
||||||
delegate(),
|
delegate(),
|
||||||
_controller->session().data().history(PeerData::kServiceNotificationsId),
|
_controller->session().data().history(PeerData::kServiceNotificationsId),
|
||||||
|
@ -378,6 +380,8 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||||
, _paper(paper)
|
, _paper(paper)
|
||||||
, _media(_paper.document() ? _paper.document()->createMediaView() : nullptr)
|
, _media(_paper.document() ? _paper.document()->createMediaView() : nullptr)
|
||||||
, _radial([=](crl::time now) { radialAnimationCallback(now); }) {
|
, _radial([=](crl::time now) { radialAnimationCallback(now); }) {
|
||||||
|
_chatStyle->apply(controller->defaultChatTheme().get());
|
||||||
|
|
||||||
if (_media) {
|
if (_media) {
|
||||||
_media->thumbnailWanted(_paper.fileOrigin());
|
_media->thumbnailWanted(_paper.fileOrigin());
|
||||||
}
|
}
|
||||||
|
@ -590,14 +594,10 @@ QRect BackgroundPreviewBox::radialRect() const {
|
||||||
void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) {
|
void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) {
|
||||||
const auto height1 = _text1->height();
|
const auto height1 = _text1->height();
|
||||||
const auto height2 = _text2->height();
|
const auto height2 = _text2->height();
|
||||||
const auto context = HistoryView::PaintContext{
|
const auto context = _controller->defaultChatTheme()->preparePaintContext(
|
||||||
.st = style::main_palette::get(),
|
_chatStyle.get(),
|
||||||
.bubblesPattern = nullptr, // #TODO bubbles
|
rect(),
|
||||||
.viewport = rect(),
|
rect());
|
||||||
.clip = rect(),
|
|
||||||
.selection = TextSelection(),
|
|
||||||
.now = ms,
|
|
||||||
};
|
|
||||||
p.translate(0, textsTop());
|
p.translate(0, textsTop());
|
||||||
paintDate(p);
|
paintDate(p);
|
||||||
_text1->draw(p, context);
|
_text1->draw(p, context);
|
||||||
|
|
|
@ -25,6 +25,7 @@ class SessionController;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class Checkbox;
|
class Checkbox;
|
||||||
|
class ChatStyle;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class BackgroundPreviewBox
|
class BackgroundPreviewBox
|
||||||
|
@ -71,6 +72,7 @@ private:
|
||||||
void checkBlurAnimationStart();
|
void checkBlurAnimationStart();
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
||||||
AdminLog::OwnedItem _text1;
|
AdminLog::OwnedItem _text1;
|
||||||
AdminLog::OwnedItem _text2;
|
AdminLog::OwnedItem _text2;
|
||||||
Data::WallPaper _paper;
|
Data::WallPaper _paper;
|
||||||
|
|
|
@ -242,6 +242,14 @@ InnerWidget::InnerWidget(
|
||||||
st::historyAdminLogEmptyWidth
|
st::historyAdminLogEmptyWidth
|
||||||
- st::historyAdminLogEmptyPadding.left()
|
- st::historyAdminLogEmptyPadding.left()
|
||||||
- st::historyAdminLogEmptyPadding.left()) {
|
- st::historyAdminLogEmptyPadding.left()) {
|
||||||
|
Window::ChatThemeValueFromPeer(
|
||||||
|
controller,
|
||||||
|
channel
|
||||||
|
) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> &&theme) {
|
||||||
|
_theme = std::move(theme);
|
||||||
|
controller->setChatStyleTheme(_theme);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
_scrollDateHideTimer.setCallback([=] { scrollDateHideByTimer(); });
|
_scrollDateHideTimer.setCallback([=] { scrollDateHideByTimer(); });
|
||||||
session().data().viewRepaintRequest(
|
session().data().viewRepaintRequest(
|
||||||
|
@ -915,13 +923,12 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
if (from != end) {
|
if (from != end) {
|
||||||
auto viewport = QRect(); // #TODO bubbles
|
auto viewport = QRect(); // #TODO bubbles
|
||||||
auto top = itemTop(from->get());
|
auto top = itemTop(from->get());
|
||||||
auto context = HistoryView::PaintContext{
|
auto context = _controller->preparePaintContext({
|
||||||
.st = style::main_palette::get(),
|
.theme = _theme.get(),
|
||||||
.bubblesPattern = nullptr,
|
.visibleAreaTop = _visibleTop,
|
||||||
.viewport = viewport.translated(0, -top),
|
.visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(),
|
||||||
.clip = clip.translated(0, -top),
|
.clip = clip,
|
||||||
.now = crl::now(),
|
}).translated(0, -top);
|
||||||
};
|
|
||||||
p.translate(0, top);
|
p.translate(0, top);
|
||||||
for (auto i = from; i != to; ++i) {
|
for (auto i = from; i != to; ++i) {
|
||||||
const auto view = i->get();
|
const auto view = i->get();
|
||||||
|
|
|
@ -58,6 +58,9 @@ public:
|
||||||
not_null<ChannelData*> channel);
|
not_null<ChannelData*> channel);
|
||||||
|
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
[[nodiscard]] not_null<Ui::ChatTheme*> theme() const {
|
||||||
|
return _theme.get();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> showSearchSignal() const;
|
[[nodiscard]] rpl::producer<> showSearchSignal() const;
|
||||||
[[nodiscard]] rpl::producer<int> scrollToSignal() const;
|
[[nodiscard]] rpl::producer<int> scrollToSignal() const;
|
||||||
|
@ -253,6 +256,7 @@ private:
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
|
|
||||||
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||||
|
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||||
|
|
||||||
std::vector<OwnedItem> _items;
|
std::vector<OwnedItem> _items;
|
||||||
std::set<uint64> _eventIds;
|
std::set<uint64> _eventIds;
|
||||||
|
|
|
@ -470,11 +470,8 @@ void Widget::paintEvent(QPaintEvent *e) {
|
||||||
//auto ms = crl::now();
|
//auto ms = crl::now();
|
||||||
//_historyDownShown.step(ms);
|
//_historyDownShown.step(ms);
|
||||||
|
|
||||||
SectionWidget::PaintBackground(
|
const auto clip = e->rect();
|
||||||
controller(),
|
SectionWidget::PaintBackground(controller(), _inner->theme(), this, clip);
|
||||||
controller()->defaultChatTheme().get(), // #TODO themes
|
|
||||||
this,
|
|
||||||
e->rect());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onScroll() {
|
void Widget::onScroll() {
|
||||||
|
|
|
@ -163,6 +163,14 @@ HistoryInner::HistoryInner(
|
||||||
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
|
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
|
Window::ChatThemeValueFromPeer(
|
||||||
|
controller,
|
||||||
|
_peer
|
||||||
|
) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> &&theme) {
|
||||||
|
_theme = std::move(theme);
|
||||||
|
controller->setChatStyleTheme(_theme);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_touchSelectTimer.setSingleShot(true);
|
_touchSelectTimer.setSingleShot(true);
|
||||||
connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect()));
|
connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect()));
|
||||||
|
|
||||||
|
@ -617,7 +625,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
auto top = mtop + block->y() + view->y();
|
auto top = mtop + block->y() + view->y();
|
||||||
auto context = _controller->preparePaintContext({
|
auto context = _controller->preparePaintContext({
|
||||||
.theme = _controller->defaultChatTheme().get(), // #TODO themes
|
.theme = _theme.get(),
|
||||||
.visibleAreaTop = _visibleAreaTop,
|
.visibleAreaTop = _visibleAreaTop,
|
||||||
.visibleAreaTopGlobal = visibleAreaTopGlobal,
|
.visibleAreaTopGlobal = visibleAreaTopGlobal,
|
||||||
.clip = clip,
|
.clip = clip,
|
||||||
|
@ -666,7 +674,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
auto readTill = (HistoryItem*)nullptr;
|
auto readTill = (HistoryItem*)nullptr;
|
||||||
auto top = htop + block->y() + view->y();
|
auto top = htop + block->y() + view->y();
|
||||||
auto context = _controller->preparePaintContext({
|
auto context = _controller->preparePaintContext({
|
||||||
.theme = _controller->defaultChatTheme().get(), // #TODO themes
|
.theme = _theme.get(),
|
||||||
.visibleAreaTop = _visibleAreaTop,
|
.visibleAreaTop = _visibleAreaTop,
|
||||||
.visibleAreaTopGlobal = visibleAreaTopGlobal,
|
.visibleAreaTopGlobal = visibleAreaTopGlobal,
|
||||||
.visibleAreaWidth = width(),
|
.visibleAreaWidth = width(),
|
||||||
|
|
|
@ -34,6 +34,7 @@ class SessionController;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
class ChatTheme;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
enum class ReportReason;
|
enum class ReportReason;
|
||||||
class PathShiftGradient;
|
class PathShiftGradient;
|
||||||
|
@ -55,7 +56,10 @@ public:
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<History*> history);
|
not_null<History*> history);
|
||||||
|
|
||||||
Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
[[nodiscard]] not_null<Ui::ChatTheme*> theme() const {
|
||||||
|
return _theme.get();
|
||||||
|
}
|
||||||
|
|
||||||
void messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages);
|
void messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages);
|
||||||
void messagesReceivedDown(PeerData *peer, const QVector<MTPMessage> &messages);
|
void messagesReceivedDown(PeerData *peer, const QVector<MTPMessage> &messages);
|
||||||
|
@ -344,6 +348,7 @@ private:
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
const not_null<PeerData*> _peer;
|
const not_null<PeerData*> _peer;
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||||
|
|
||||||
History *_migrated = nullptr;
|
History *_migrated = nullptr;
|
||||||
int _contentWidth = 0;
|
int _contentWidth = 0;
|
||||||
|
|
|
@ -4942,7 +4942,7 @@ void HistoryWidget::startItemRevealAnimations() {
|
||||||
HistoryView::ListWidget::kItemRevealDuration,
|
HistoryView::ListWidget::kItemRevealDuration,
|
||||||
anim::easeOutCirc);
|
anim::easeOutCirc);
|
||||||
if (item->out() || _history->peer->isSelf()) {
|
if (item->out() || _history->peer->isSelf()) {
|
||||||
controller()->defaultChatTheme()->rotateComplexGradientBackground(); // #TODO themes
|
_list->theme()->rotateComplexGradientBackground();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6888,7 +6888,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
Window::SectionWidget::PaintBackground(
|
Window::SectionWidget::PaintBackground(
|
||||||
controller(),
|
controller(),
|
||||||
controller()->defaultChatTheme().get(), // #TODO themes
|
_list ? _list->theme().get() : controller()->defaultChatTheme().get(),
|
||||||
this,
|
this,
|
||||||
e->rect());
|
e->rect());
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,11 @@ public:
|
||||||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||||
void elementReplyTo(const FullMsgId &to) override;
|
void elementReplyTo(const FullMsgId &to) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] not_null<Window::SessionController*> controller() const {
|
||||||
|
return _controller;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||||
|
|
|
@ -1446,7 +1446,7 @@ void ListWidget::startItemRevealAnimations() {
|
||||||
kItemRevealDuration,
|
kItemRevealDuration,
|
||||||
anim::easeOutCirc);
|
anim::easeOutCirc);
|
||||||
if (view->data()->out()) {
|
if (view->data()->out()) {
|
||||||
controller()->defaultChatTheme()->rotateComplexGradientBackground(); // #TODO themes
|
_delegate->listChatTheme()->rotateComplexGradientBackground();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1611,16 +1611,16 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
||||||
auto to = std::lower_bound(begin(_items), end(_items), clip.top() + clip.height(), [this](auto &elem, int bottom) {
|
auto to = std::lower_bound(begin(_items), end(_items), clip.top() + clip.height(), [this](auto &elem, int bottom) {
|
||||||
return this->itemTop(elem) < bottom;
|
return this->itemTop(elem) < bottom;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (from != end(_items)) {
|
if (from != end(_items)) {
|
||||||
auto viewport = QRect(); // #TODO bubbles
|
auto viewport = QRect(); // #TODO bubbles
|
||||||
auto top = itemTop(from->get());
|
auto top = itemTop(from->get());
|
||||||
auto context = HistoryView::PaintContext{
|
auto context = controller()->preparePaintContext({
|
||||||
.st = style::main_palette::get(),
|
.theme = _delegate->listChatTheme(),
|
||||||
.bubblesPattern = nullptr,
|
.visibleAreaTop = _visibleTop,
|
||||||
.viewport = viewport.translated(0, -top),
|
.visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(),
|
||||||
.clip = clip.translated(0, -top),
|
.clip = clip,
|
||||||
.now = crl::now(),
|
}).translated(0, -top);
|
||||||
};
|
|
||||||
p.translate(0, top);
|
p.translate(0, top);
|
||||||
for (auto i = from; i != to; ++i) {
|
for (auto i = from; i != to; ++i) {
|
||||||
const auto view = *i;
|
const auto view = *i;
|
||||||
|
|
|
@ -21,6 +21,7 @@ class Session;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
class ChatTheme;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -91,6 +92,7 @@ public:
|
||||||
const QString &command,
|
const QString &command,
|
||||||
const FullMsgId &context) = 0;
|
const FullMsgId &context) = 0;
|
||||||
virtual void listHandleViaClick(not_null<UserData*> bot) = 0;
|
virtual void listHandleViaClick(not_null<UserData*> bot) = 0;
|
||||||
|
virtual not_null<Ui::ChatTheme*> listChatTheme() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -559,6 +559,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
p,
|
p,
|
||||||
Ui::ComplexBubble{
|
Ui::ComplexBubble{
|
||||||
.simple = Ui::SimpleBubble{
|
.simple = Ui::SimpleBubble{
|
||||||
|
.st = context.st,
|
||||||
.geometry = g,
|
.geometry = g,
|
||||||
.pattern = context.bubblesPattern,
|
.pattern = context.bubblesPattern,
|
||||||
.patternViewport = context.viewport,
|
.patternViewport = context.viewport,
|
||||||
|
|
|
@ -101,6 +101,14 @@ PinnedWidget::PinnedWidget(
|
||||||
QString(),
|
QString(),
|
||||||
st::historyComposeButton))
|
st::historyComposeButton))
|
||||||
, _scrollDown(_scroll.get(), st::historyToDown) {
|
, _scrollDown(_scroll.get(), st::historyToDown) {
|
||||||
|
Window::ChatThemeValueFromPeer(
|
||||||
|
controller,
|
||||||
|
history->peer
|
||||||
|
) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> &&theme) {
|
||||||
|
_theme = std::move(theme);
|
||||||
|
controller->setChatStyleTheme(_theme);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
_topBar->setActiveChat(
|
_topBar->setActiveChat(
|
||||||
TopBarWidget::ActiveChat{
|
TopBarWidget::ActiveChat{
|
||||||
.key = _history,
|
.key = _history,
|
||||||
|
@ -457,11 +465,7 @@ void PinnedWidget::paintEvent(QPaintEvent *e) {
|
||||||
const auto aboveHeight = _topBar->height();
|
const auto aboveHeight = _topBar->height();
|
||||||
const auto bg = e->rect().intersected(
|
const auto bg = e->rect().intersected(
|
||||||
QRect(0, aboveHeight, width(), height() - aboveHeight));
|
QRect(0, aboveHeight, width(), height() - aboveHeight));
|
||||||
SectionWidget::PaintBackground(
|
SectionWidget::PaintBackground(controller(), _theme.get(), this, bg);
|
||||||
controller(),
|
|
||||||
controller()->defaultChatTheme().get(), // #TODO themes
|
|
||||||
this,
|
|
||||||
bg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PinnedWidget::onScroll() {
|
void PinnedWidget::onScroll() {
|
||||||
|
@ -654,6 +658,10 @@ void PinnedWidget::listSendBotCommand(
|
||||||
void PinnedWidget::listHandleViaClick(not_null<UserData*> bot) {
|
void PinnedWidget::listHandleViaClick(not_null<UserData*> bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<Ui::ChatTheme*> PinnedWidget::listChatTheme() {
|
||||||
|
return _theme.get();
|
||||||
|
}
|
||||||
|
|
||||||
void PinnedWidget::confirmDeleteSelected() {
|
void PinnedWidget::confirmDeleteSelected() {
|
||||||
ConfirmDeleteSelectedItems(_inner);
|
ConfirmDeleteSelectedItems(_inner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,7 @@ public:
|
||||||
const QString &command,
|
const QString &command,
|
||||||
const FullMsgId &context) override;
|
const FullMsgId &context) override;
|
||||||
void listHandleViaClick(not_null<UserData*> bot) override;
|
void listHandleViaClick(not_null<UserData*> bot) override;
|
||||||
|
not_null<Ui::ChatTheme*> listChatTheme() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
@ -145,6 +146,7 @@ private:
|
||||||
void refreshClearButtonText();
|
void refreshClearButtonText();
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||||
PeerData *_migratedPeer = nullptr;
|
PeerData *_migratedPeer = nullptr;
|
||||||
QPointer<ListWidget> _inner;
|
QPointer<ListWidget> _inner;
|
||||||
object_ptr<TopBarWidget> _topBar;
|
object_ptr<TopBarWidget> _topBar;
|
||||||
|
|
|
@ -162,6 +162,14 @@ RepliesWidget::RepliesWidget(
|
||||||
, _scroll(std::make_unique<Ui::ScrollArea>(this, st::historyScroll, false))
|
, _scroll(std::make_unique<Ui::ScrollArea>(this, st::historyScroll, false))
|
||||||
, _scrollDown(_scroll.get(), st::historyToDown)
|
, _scrollDown(_scroll.get(), st::historyToDown)
|
||||||
, _readRequestTimer([=] { sendReadTillRequest(); }) {
|
, _readRequestTimer([=] { sendReadTillRequest(); }) {
|
||||||
|
Window::ChatThemeValueFromPeer(
|
||||||
|
controller,
|
||||||
|
history->peer
|
||||||
|
) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> &&theme) {
|
||||||
|
_theme = std::move(theme);
|
||||||
|
controller->setChatStyleTheme(_theme);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
setupRoot();
|
setupRoot();
|
||||||
setupRootView();
|
setupRootView();
|
||||||
|
|
||||||
|
@ -1511,11 +1519,7 @@ void RepliesWidget::paintEvent(QPaintEvent *e) {
|
||||||
const auto aboveHeight = _topBar->height();
|
const auto aboveHeight = _topBar->height();
|
||||||
const auto bg = e->rect().intersected(
|
const auto bg = e->rect().intersected(
|
||||||
QRect(0, aboveHeight, width(), height() - aboveHeight));
|
QRect(0, aboveHeight, width(), height() - aboveHeight));
|
||||||
SectionWidget::PaintBackground(
|
SectionWidget::PaintBackground(controller(), _theme.get(), this, bg);
|
||||||
controller(),
|
|
||||||
controller()->defaultChatTheme().get(), // #TODO themes
|
|
||||||
this,
|
|
||||||
bg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RepliesWidget::onScroll() {
|
void RepliesWidget::onScroll() {
|
||||||
|
@ -1786,6 +1790,10 @@ void RepliesWidget::listHandleViaClick(not_null<UserData*> bot) {
|
||||||
_composeControls->setText({ '@' + bot->username + ' ' });
|
_composeControls->setText({ '@' + bot->username + ' ' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<Ui::ChatTheme*> RepliesWidget::listChatTheme() {
|
||||||
|
return _theme.get();
|
||||||
|
}
|
||||||
|
|
||||||
void RepliesWidget::confirmDeleteSelected() {
|
void RepliesWidget::confirmDeleteSelected() {
|
||||||
ConfirmDeleteSelectedItems(_inner);
|
ConfirmDeleteSelectedItems(_inner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ public:
|
||||||
const QString &command,
|
const QString &command,
|
||||||
const FullMsgId &context) override;
|
const FullMsgId &context) override;
|
||||||
void listHandleViaClick(not_null<UserData*> bot) override;
|
void listHandleViaClick(not_null<UserData*> bot) override;
|
||||||
|
not_null<Ui::ChatTheme*> listChatTheme() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
@ -250,6 +251,7 @@ private:
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
const MsgId _rootId = 0;
|
const MsgId _rootId = 0;
|
||||||
|
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||||
HistoryItem *_root = nullptr;
|
HistoryItem *_root = nullptr;
|
||||||
std::shared_ptr<Data::RepliesList> _replies;
|
std::shared_ptr<Data::RepliesList> _replies;
|
||||||
rpl::variable<bool> _areComments = false;
|
rpl::variable<bool> _areComments = false;
|
||||||
|
|
|
@ -42,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
|
||||||
#include "data/data_scheduled_messages.h"
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "storage/storage_media_prepare.h"
|
#include "storage/storage_media_prepare.h"
|
||||||
|
@ -101,6 +100,14 @@ ScheduledWidget::ScheduledWidget(
|
||||||
ComposeControls::Mode::Scheduled,
|
ComposeControls::Mode::Scheduled,
|
||||||
SendMenu::Type::Disabled))
|
SendMenu::Type::Disabled))
|
||||||
, _scrollDown(_scroll, st::historyToDown) {
|
, _scrollDown(_scroll, st::historyToDown) {
|
||||||
|
Window::ChatThemeValueFromPeer(
|
||||||
|
controller,
|
||||||
|
history->peer
|
||||||
|
) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> &&theme) {
|
||||||
|
_theme = std::move(theme);
|
||||||
|
controller->setChatStyleTheme(_theme);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
const auto state = Dialogs::EntryState{
|
const auto state = Dialogs::EntryState{
|
||||||
.key = _history,
|
.key = _history,
|
||||||
.section = Dialogs::EntryState::Section::Scheduled,
|
.section = Dialogs::EntryState::Section::Scheduled,
|
||||||
|
@ -996,11 +1003,8 @@ void ScheduledWidget::paintEvent(QPaintEvent *e) {
|
||||||
//auto ms = crl::now();
|
//auto ms = crl::now();
|
||||||
//_historyDownShown.step(ms);
|
//_historyDownShown.step(ms);
|
||||||
|
|
||||||
SectionWidget::PaintBackground(
|
const auto clip = e->rect();
|
||||||
controller(),
|
SectionWidget::PaintBackground(controller(), _theme.get(), this, clip);
|
||||||
controller()->defaultChatTheme().get(), // #TODO themes
|
|
||||||
this,
|
|
||||||
e->rect());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledWidget::onScroll() {
|
void ScheduledWidget::onScroll() {
|
||||||
|
@ -1204,6 +1208,10 @@ void ScheduledWidget::listHandleViaClick(not_null<UserData*> bot) {
|
||||||
_composeControls->setText({ '@' + bot->username + ' ' });
|
_composeControls->setText({ '@' + bot->username + ' ' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<Ui::ChatTheme*> ScheduledWidget::listChatTheme() {
|
||||||
|
return _theme.get();
|
||||||
|
}
|
||||||
|
|
||||||
void ScheduledWidget::confirmSendNowSelected() {
|
void ScheduledWidget::confirmSendNowSelected() {
|
||||||
ConfirmSendNowSelectedItems(_inner);
|
ConfirmSendNowSelectedItems(_inner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,7 @@ public:
|
||||||
const QString &command,
|
const QString &command,
|
||||||
const FullMsgId &context) override;
|
const FullMsgId &context) override;
|
||||||
void listHandleViaClick(not_null<UserData*> bot) override;
|
void listHandleViaClick(not_null<UserData*> bot) override;
|
||||||
|
not_null<Ui::ChatTheme*> listChatTheme() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
@ -206,6 +207,7 @@ private:
|
||||||
Api::SendOptions options);
|
Api::SendOptions options);
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||||
object_ptr<Ui::ScrollArea> _scroll;
|
object_ptr<Ui::ScrollArea> _scroll;
|
||||||
QPointer<ListWidget> _inner;
|
QPointer<ListWidget> _inner;
|
||||||
object_ptr<TopBarWidget> _topBar;
|
object_ptr<TopBarWidget> _topBar;
|
||||||
|
|
|
@ -78,12 +78,12 @@ static_assert(kDisplaySkipped != kTimeUnknown);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const auto errors = std::fetestexcept(FE_ALL_EXCEPT);
|
const auto errors = std::fetestexcept(FE_ALL_EXCEPT);
|
||||||
LOG(("Streaming Error: Got NAN in std::round(%1), fe: %2."
|
|
||||||
).arg(value
|
|
||||||
).arg(errors));
|
|
||||||
if (const auto result = std::round(value); !std::isnan(result)) {
|
if (const auto result = std::round(value); !std::isnan(result)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
LOG(("Streaming Error: Got second NAN in std::round(%1), fe: %2."
|
||||||
|
).arg(value
|
||||||
|
).arg(errors));
|
||||||
std::feclearexcept(FE_ALL_EXCEPT);
|
std::feclearexcept(FE_ALL_EXCEPT);
|
||||||
if (const auto result = std::round(value); !std::isnan(result)) {
|
if (const auto result = std::round(value); !std::isnan(result)) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/wrap/padding_wrap.h"
|
#include "ui/wrap/padding_wrap.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
@ -633,7 +634,9 @@ rpl::producer<QString> CallsPeer2PeerPrivacyController::exceptionsDescription()
|
||||||
ForwardsPrivacyController::ForwardsPrivacyController(
|
ForwardsPrivacyController::ForwardsPrivacyController(
|
||||||
not_null<Window::SessionController*> controller)
|
not_null<Window::SessionController*> controller)
|
||||||
: SimpleElementDelegate(controller, [] {})
|
: SimpleElementDelegate(controller, [] {})
|
||||||
, _controller(controller) {
|
, _controller(controller)
|
||||||
|
, _chatStyle(std::make_unique<Ui::ChatStyle>()) {
|
||||||
|
_chatStyle->apply(controller->defaultChatTheme().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
UserPrivacy::Key ForwardsPrivacyController::key() {
|
UserPrivacy::Key ForwardsPrivacyController::key() {
|
||||||
|
@ -715,13 +718,11 @@ object_ptr<Ui::RpWidget> ForwardsPrivacyController::setupAboveWidget(
|
||||||
rect);
|
rect);
|
||||||
|
|
||||||
Painter p(widget);
|
Painter p(widget);
|
||||||
const auto context = HistoryView::PaintContext{
|
const auto theme = _controller->defaultChatTheme().get();
|
||||||
.st = style::main_palette::get(),
|
const auto context = theme->preparePaintContext(
|
||||||
.bubblesPattern = nullptr,
|
_chatStyle.get(),
|
||||||
.viewport = widget->rect(),
|
widget->rect(),
|
||||||
.clip = widget->rect(),
|
widget->rect());
|
||||||
.now = crl::now(),
|
|
||||||
};
|
|
||||||
p.translate(0, padding + view->marginBottom());
|
p.translate(0, padding + view->marginBottom());
|
||||||
view->draw(p, context);
|
view->draw(p, context);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,10 @@ namespace Window {
|
||||||
class SessionController;
|
class SessionController;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ChatStyle;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
class BlockedBoxController : public PeerListController {
|
class BlockedBoxController : public PeerListController {
|
||||||
|
@ -193,6 +197,7 @@ private:
|
||||||
Option value);
|
Option value);
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
const std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "support/support_autocomplete.h"
|
#include "support/support_autocomplete.h"
|
||||||
|
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
@ -502,9 +504,11 @@ ConfirmContactBox::ConfirmContactBox(
|
||||||
const Contact &data,
|
const Contact &data,
|
||||||
Fn<void(Qt::KeyboardModifiers)> submit)
|
Fn<void(Qt::KeyboardModifiers)> submit)
|
||||||
: SimpleElementDelegate(controller, [=] { update(); })
|
: SimpleElementDelegate(controller, [=] { update(); })
|
||||||
|
, _chatStyle(std::make_unique<Ui::ChatStyle>())
|
||||||
, _comment(GenerateCommentItem(this, history, data))
|
, _comment(GenerateCommentItem(this, history, data))
|
||||||
, _contact(GenerateContactItem(this, history, data))
|
, _contact(GenerateContactItem(this, history, data))
|
||||||
, _submit(submit) {
|
, _submit(submit) {
|
||||||
|
_chatStyle->apply(controller->defaultChatTheme().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfirmContactBox::prepare() {
|
void ConfirmContactBox::prepare() {
|
||||||
|
@ -565,13 +569,11 @@ void ConfirmContactBox::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
p.fillRect(e->rect(), st::boxBg);
|
p.fillRect(e->rect(), st::boxBg);
|
||||||
|
|
||||||
const auto context = HistoryView::PaintContext{
|
const auto theme = controller()->defaultChatTheme().get();
|
||||||
.st = style::main_palette::get(),
|
const auto context = theme->preparePaintContext(
|
||||||
.bubblesPattern = nullptr, // #TODO bubbles
|
_chatStyle.get(),
|
||||||
.viewport = rect(),
|
rect(),
|
||||||
.clip = rect(),
|
rect());
|
||||||
.now = crl::now(),
|
|
||||||
};
|
|
||||||
p.translate(st::boxPadding.left(), 0);
|
p.translate(st::boxPadding.left(), 0);
|
||||||
if (_comment) {
|
if (_comment) {
|
||||||
_comment->draw(p, context);
|
_comment->draw(p, context);
|
||||||
|
|
|
@ -24,6 +24,7 @@ class SessionController;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
class InputField;
|
class InputField;
|
||||||
|
class ChatStyle;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Support {
|
namespace Support {
|
||||||
|
@ -83,6 +84,7 @@ protected:
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
||||||
AdminLog::OwnedItem _comment;
|
AdminLog::OwnedItem _comment;
|
||||||
AdminLog::OwnedItem _contact;
|
AdminLog::OwnedItem _contact;
|
||||||
Fn<void(Qt::KeyboardModifiers)> _submit;
|
Fn<void(Qt::KeyboardModifiers)> _submit;
|
||||||
|
|
|
@ -18,19 +18,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct CornersPixmaps {
|
|
||||||
QPixmap p[4];
|
|
||||||
};
|
|
||||||
std::vector<CornersPixmaps> Corners;
|
std::vector<CornersPixmaps> Corners;
|
||||||
base::flat_map<uint32, CornersPixmaps> CornersMap;
|
base::flat_map<uint32, CornersPixmaps> CornersMap;
|
||||||
QImage CornersMaskLarge[4], CornersMaskSmall[4];
|
QImage CornersMaskLarge[4], CornersMaskSmall[4];
|
||||||
rpl::lifetime PaletteChangedLifetime;
|
rpl::lifetime PaletteChangedLifetime;
|
||||||
|
|
||||||
void PrepareCorners(CachedRoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr, QImage *cors = nullptr) {
|
[[nodiscard]] std::array<QImage, 4> PrepareCorners(int32 radius, const QBrush &brush, const style::color *shadow = nullptr) {
|
||||||
Expects(Corners.size() > index);
|
|
||||||
|
|
||||||
int32 r = radius * style::DevicePixelRatio(), s = st::msgShadow * style::DevicePixelRatio();
|
int32 r = radius * style::DevicePixelRatio(), s = st::msgShadow * style::DevicePixelRatio();
|
||||||
QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied), localCors[4];
|
QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied);
|
||||||
{
|
{
|
||||||
Painter p(&rect);
|
Painter p(&rect);
|
||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
|
@ -46,27 +41,31 @@ void PrepareCorners(CachedRoundCorners index, int32 radius, const QBrush &brush,
|
||||||
p.setBrush(brush);
|
p.setBrush(brush);
|
||||||
p.drawRoundedRect(0, 0, r * 3, r * 3, r, r);
|
p.drawRoundedRect(0, 0, r * 3, r * 3, r, r);
|
||||||
}
|
}
|
||||||
if (!cors) cors = localCors;
|
auto result = std::array<QImage, 4>();
|
||||||
cors[0] = rect.copy(0, 0, r, r);
|
result[0] = rect.copy(0, 0, r, r);
|
||||||
cors[1] = rect.copy(r * 2, 0, r, r);
|
result[1] = rect.copy(r * 2, 0, r, r);
|
||||||
cors[2] = rect.copy(0, r * 2, r, r + (shadow ? s : 0));
|
result[2] = rect.copy(0, r * 2, r, r + (shadow ? s : 0));
|
||||||
cors[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0));
|
result[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0));
|
||||||
if (index != SmallMaskCorners && index != LargeMaskCorners) {
|
return result;
|
||||||
for (int i = 0; i < 4; ++i) {
|
}
|
||||||
Corners[index].p[i] = PixmapFromImage(std::move(cors[i]));
|
|
||||||
Corners[index].p[i].setDevicePixelRatio(style::DevicePixelRatio());
|
void PrepareCorners(CachedRoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr) {
|
||||||
}
|
Expects(index < Corners.size());
|
||||||
|
|
||||||
|
auto images = PrepareCorners(radius, brush, shadow);
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
Corners[index].p[i] = PixmapFromImage(std::move(images[i]));
|
||||||
|
Corners[index].p[i].setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateMaskCorners() {
|
void CreateMaskCorners() {
|
||||||
QImage mask[4];
|
auto mask = PrepareCorners(st::roundRadiusSmall, QColor(255, 255, 255), nullptr);
|
||||||
PrepareCorners(SmallMaskCorners, st::roundRadiusSmall, QColor(255, 255, 255), nullptr, mask);
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
CornersMaskSmall[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
CornersMaskSmall[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||||
CornersMaskSmall[i].setDevicePixelRatio(style::DevicePixelRatio());
|
CornersMaskSmall[i].setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
}
|
}
|
||||||
PrepareCorners(LargeMaskCorners, st::historyMessageRadius, QColor(255, 255, 255), nullptr, mask);
|
mask = PrepareCorners(st::historyMessageRadius, QColor(255, 255, 255), nullptr);
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
CornersMaskLarge[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
CornersMaskLarge[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||||
CornersMaskLarge[i].setDevicePixelRatio(style::DevicePixelRatio());
|
CornersMaskLarge[i].setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
@ -231,23 +230,40 @@ void FillRoundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, style::colo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillRoundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts) {
|
CornersPixmaps PrepareCornerPixmaps(int32 radius, style::color bg, const style::color *sh) {
|
||||||
auto colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24) | ((uint32(bg->c.red()) & 0xFF) << 16) | ((uint32(bg->c.green()) & 0xFF) << 8) | ((uint32(bg->c.blue()) & 0xFF) << 24);
|
auto images = PrepareCorners(radius, bg, sh);
|
||||||
auto i = CornersMap.find(colorKey);
|
auto result = CornersPixmaps();
|
||||||
if (i == CornersMap.cend()) {
|
for (int j = 0; j < 4; ++j) {
|
||||||
QImage images[4];
|
result.p[j] = PixmapFromImage(std::move(images[j]));
|
||||||
switch (radius) {
|
result.p[j].setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
case ImageRoundRadius::Small: PrepareCorners(SmallMaskCorners, st::roundRadiusSmall, bg, nullptr, images); break;
|
}
|
||||||
case ImageRoundRadius::Large: PrepareCorners(LargeMaskCorners, st::historyMessageRadius, bg, nullptr, images); break;
|
return result;
|
||||||
default: p.fillRect(x, y, w, h, bg); return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CornersPixmaps pixmaps;
|
CornersPixmaps PrepareCornerPixmaps(ImageRoundRadius radius, style::color bg, const style::color *sh) {
|
||||||
for (int j = 0; j < 4; ++j) {
|
switch (radius) {
|
||||||
pixmaps.p[j] = PixmapFromImage(std::move(images[j]));
|
case ImageRoundRadius::Small:
|
||||||
pixmaps.p[j].setDevicePixelRatio(style::DevicePixelRatio());
|
return PrepareCornerPixmaps(st::roundRadiusSmall, bg, sh);
|
||||||
}
|
case ImageRoundRadius::Large:
|
||||||
i = CornersMap.emplace(colorKey, pixmaps).first;
|
return PrepareCornerPixmaps(st::historyMessageRadius, bg, sh);
|
||||||
|
}
|
||||||
|
Unexpected("Image round radius in PrepareCornerPixmaps.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillRoundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts) {
|
||||||
|
if (radius == ImageRoundRadius::None) {
|
||||||
|
p.fillRect(x, y, w, h, bg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24)
|
||||||
|
| ((uint32(bg->c.red()) & 0xFF) << 16)
|
||||||
|
| ((uint32(bg->c.green()) & 0xFF) << 8)
|
||||||
|
| ((uint32(bg->c.blue()) & 0xFF));
|
||||||
|
auto i = CornersMap.find(colorKey);
|
||||||
|
if (i == end(CornersMap)) {
|
||||||
|
i = CornersMap.emplace(
|
||||||
|
colorKey,
|
||||||
|
PrepareCornerPixmaps(radius, bg, nullptr)).first;
|
||||||
}
|
}
|
||||||
FillRoundRect(p, x, y, w, h, bg, i->second, nullptr, parts);
|
FillRoundRect(p, x, y, w, h, bg, i->second, nullptr, parts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@ enum class ImageRoundRadius;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
enum CachedRoundCorners : int {
|
struct CornersPixmaps {
|
||||||
SmallMaskCorners = 0x00, // for images
|
QPixmap p[4];
|
||||||
LargeMaskCorners,
|
};
|
||||||
|
|
||||||
|
enum CachedRoundCorners : int {
|
||||||
BoxCorners,
|
BoxCorners,
|
||||||
MenuCorners,
|
MenuCorners,
|
||||||
BotKbOverCorners,
|
BotKbOverCorners,
|
||||||
|
@ -69,6 +70,16 @@ inline void FillRoundRect(Painter &p, const QRect &rect, style::color bg, ImageR
|
||||||
return FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts);
|
return FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] CornersPixmaps PrepareCornerPixmaps(
|
||||||
|
int32 radius,
|
||||||
|
style::color bg,
|
||||||
|
const style::color *sh);
|
||||||
|
[[nodiscard]] CornersPixmaps PrepareCornerPixmaps(
|
||||||
|
ImageRoundRadius radius,
|
||||||
|
style::color bg,
|
||||||
|
const style::color *sh);
|
||||||
|
void FillRoundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, const CornersPixmaps &corner, const style::color *shadow = nullptr, RectParts parts = RectPart::Full);
|
||||||
|
|
||||||
void StartCachedCorners();
|
void StartCachedCorners();
|
||||||
void FinishCachedCorners();
|
void FinishCachedCorners();
|
||||||
|
|
||||||
|
|
125
Telegram/SourceFiles/ui/chat/chat_style.cpp
Normal file
125
Telegram/SourceFiles/ui/chat/chat_style.cpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
|
|
||||||
|
#include "ui/chat/chat_theme.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
ChatStyle::ChatStyle() {
|
||||||
|
finalize();
|
||||||
|
messageIcon(
|
||||||
|
&MessageStyle::tailLeft,
|
||||||
|
st::historyBubbleTailInLeft,
|
||||||
|
st::historyBubbleTailInLeftSelected,
|
||||||
|
st::historyBubbleTailOutLeft,
|
||||||
|
st::historyBubbleTailOutLeftSelected);
|
||||||
|
messageIcon(
|
||||||
|
&MessageStyle::tailRight,
|
||||||
|
st::historyBubbleTailInRight,
|
||||||
|
st::historyBubbleTailInRightSelected,
|
||||||
|
st::historyBubbleTailOutRight,
|
||||||
|
st::historyBubbleTailOutRightSelected);
|
||||||
|
messageColor(
|
||||||
|
&MessageStyle::msgBg,
|
||||||
|
msgInBg(),
|
||||||
|
msgInBgSelected(),
|
||||||
|
msgOutBg(),
|
||||||
|
msgOutBgSelected());
|
||||||
|
messageColor(
|
||||||
|
&MessageStyle::msgShadow,
|
||||||
|
msgInShadow(),
|
||||||
|
msgInShadowSelected(),
|
||||||
|
msgOutShadow(),
|
||||||
|
msgOutShadowSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatStyle::apply(not_null<ChatTheme*> theme) {
|
||||||
|
const auto themePalette = theme->palette();
|
||||||
|
assignPalette(themePalette
|
||||||
|
? themePalette
|
||||||
|
: style::main_palette::get().get());
|
||||||
|
if (themePalette) {
|
||||||
|
_defaultPaletteChangeLifetime.destroy();
|
||||||
|
} else {
|
||||||
|
style::PaletteChanged(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
assignPalette(style::main_palette::get());
|
||||||
|
}, _defaultPaletteChangeLifetime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatStyle::assignPalette(not_null<const style::palette*> palette) {
|
||||||
|
*static_cast<style::palette*>(this) = *palette;
|
||||||
|
style::internal::resetIcons();
|
||||||
|
for (auto &style : _messageStyles) {
|
||||||
|
style.corners = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const {
|
||||||
|
auto &result = messageStyleRaw(outbg, selected);
|
||||||
|
if (result.corners.p[0].isNull()) {
|
||||||
|
result.corners = Ui::PrepareCornerPixmaps(
|
||||||
|
st::historyMessageRadius,
|
||||||
|
result.msgBg,
|
||||||
|
&result.msgShadow);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageStyle &ChatStyle::messageStyleRaw(bool outbg, bool selected) const {
|
||||||
|
return _messageStyles[(outbg ? 2 : 0) + (selected ? 1 : 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatStyle::icon(style::icon &my, const style::icon &original) {
|
||||||
|
my = original.withPalette(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageStyle &ChatStyle::messageIn() {
|
||||||
|
return messageStyleRaw(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageStyle &ChatStyle::messageInSelected() {
|
||||||
|
return messageStyleRaw(false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageStyle &ChatStyle::messageOut() {
|
||||||
|
return messageStyleRaw(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageStyle &ChatStyle::messageOutSelected() {
|
||||||
|
return messageStyleRaw(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatStyle::messageIcon(
|
||||||
|
style::icon MessageStyle::*my,
|
||||||
|
const style::icon &originalIn,
|
||||||
|
const style::icon &originalInSelected,
|
||||||
|
const style::icon &originalOut,
|
||||||
|
const style::icon &originalOutSelected) {
|
||||||
|
icon(messageIn().*my, originalIn);
|
||||||
|
icon(messageInSelected().*my, originalInSelected);
|
||||||
|
icon(messageOut().*my, originalOut);
|
||||||
|
icon(messageOutSelected().*my, originalOutSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatStyle::messageColor(
|
||||||
|
style::color MessageStyle::*my,
|
||||||
|
const style::color &originalIn,
|
||||||
|
const style::color &originalInSelected,
|
||||||
|
const style::color &originalOut,
|
||||||
|
const style::color &originalOutSelected) {
|
||||||
|
messageIn().*my = originalIn;
|
||||||
|
messageInSelected().*my = originalInSelected;
|
||||||
|
messageOut().*my = originalOut;
|
||||||
|
messageOutSelected().*my = originalOutSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
65
Telegram/SourceFiles/ui/chat/chat_style.h
Normal file
65
Telegram/SourceFiles/ui/chat/chat_style.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
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 "ui/cached_round_corners.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class ChatTheme;
|
||||||
|
|
||||||
|
struct MessageStyle {
|
||||||
|
CornersPixmaps corners;
|
||||||
|
style::icon tailLeft = { Qt::Uninitialized };
|
||||||
|
style::icon tailRight = { Qt::Uninitialized };
|
||||||
|
style::color msgBg;
|
||||||
|
style::color msgShadow;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChatStyle final : public style::palette {
|
||||||
|
public:
|
||||||
|
ChatStyle();
|
||||||
|
|
||||||
|
void apply(not_null<ChatTheme*> theme);
|
||||||
|
|
||||||
|
[[nodiscard]] const MessageStyle &messageStyle(
|
||||||
|
bool outbg,
|
||||||
|
bool selected) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void assignPalette(not_null<const style::palette*> palette);
|
||||||
|
|
||||||
|
void icon(style::icon &my, const style::icon &original);
|
||||||
|
|
||||||
|
[[nodiscard]] MessageStyle &messageStyleRaw(
|
||||||
|
bool outbg,
|
||||||
|
bool selected) const;
|
||||||
|
[[nodiscard]] MessageStyle &messageIn();
|
||||||
|
[[nodiscard]] MessageStyle &messageInSelected();
|
||||||
|
[[nodiscard]] MessageStyle &messageOut();
|
||||||
|
[[nodiscard]] MessageStyle &messageOutSelected();
|
||||||
|
void messageIcon(
|
||||||
|
style::icon MessageStyle::*my,
|
||||||
|
const style::icon &originalIn,
|
||||||
|
const style::icon &originalInSelected,
|
||||||
|
const style::icon &originalOut,
|
||||||
|
const style::icon &originalOutSelected);
|
||||||
|
void messageColor(
|
||||||
|
style::color MessageStyle::*my,
|
||||||
|
const style::color &originalIn,
|
||||||
|
const style::color &originalInSelected,
|
||||||
|
const style::color &originalOut,
|
||||||
|
const style::color &originalOutSelected);
|
||||||
|
|
||||||
|
mutable std::array<MessageStyle, 4> _messageStyles;
|
||||||
|
|
||||||
|
rpl::lifetime _defaultPaletteChangeLifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -30,6 +30,8 @@ constexpr auto kMaxSize = 2960;
|
||||||
|
|
||||||
[[nodiscard]] CacheBackgroundResult CacheBackground(
|
[[nodiscard]] CacheBackgroundResult CacheBackground(
|
||||||
const CacheBackgroundRequest &request) {
|
const CacheBackgroundRequest &request) {
|
||||||
|
Expects(!request.area.isEmpty());
|
||||||
|
|
||||||
const auto gradient = request.background.gradientForFill.isNull()
|
const auto gradient = request.background.gradientForFill.isNull()
|
||||||
? QImage()
|
? QImage()
|
||||||
: (request.gradientRotationAdd != 0)
|
: (request.gradientRotationAdd != 0)
|
||||||
|
@ -69,12 +71,14 @@ constexpr auto kMaxSize = 2960;
|
||||||
Qt::KeepAspectRatio,
|
Qt::KeepAspectRatio,
|
||||||
Qt::SmoothTransformation)
|
Qt::SmoothTransformation)
|
||||||
: request.background.preparedForTiled;
|
: request.background.preparedForTiled;
|
||||||
const auto w = tiled.width() / style::DevicePixelRatio();
|
const auto w = tiled.width() / float(style::DevicePixelRatio());
|
||||||
const auto h = tiled.height() / style::DevicePixelRatio();
|
const auto h = tiled.height() / float(style::DevicePixelRatio());
|
||||||
const auto cx = int(std::ceil(request.area.width() / w));
|
const auto cx = int(std::ceil(request.area.width() / w));
|
||||||
const auto cy = int(std::ceil(request.area.height() / h));
|
const auto cy = int(std::ceil(request.area.height() / h));
|
||||||
const auto rows = cy;
|
const auto rows = cy;
|
||||||
const auto cols = request.background.isPattern ? (((cx / 2) * 2) + 1) : cx;
|
const auto cols = request.background.isPattern
|
||||||
|
? (((cx / 2) * 2) + 1)
|
||||||
|
: cx;
|
||||||
const auto xshift = request.background.isPattern
|
const auto xshift = request.background.isPattern
|
||||||
? (request.area.width() - cols * w) / 2
|
? (request.area.width() - cols * w) / 2
|
||||||
: 0;
|
: 0;
|
||||||
|
@ -202,13 +206,14 @@ void ChatTheme::setBubblesBackground(QImage image) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!_bubblesBackgroundPattern) {
|
if (!_bubblesBackgroundPattern) {
|
||||||
_bubblesBackgroundPattern = PrepareBubblePattern();
|
_bubblesBackgroundPattern = PrepareBubblePattern(palette());
|
||||||
}
|
}
|
||||||
_bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap;
|
_bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap;
|
||||||
_repaintBackgroundRequests.fire({});
|
_repaintBackgroundRequests.fire({});
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatPaintContext ChatTheme::preparePaintContext(
|
ChatPaintContext ChatTheme::preparePaintContext(
|
||||||
|
not_null<const ChatStyle*> st,
|
||||||
QRect viewport,
|
QRect viewport,
|
||||||
QRect clip) {
|
QRect clip) {
|
||||||
_bubblesBackground.area = viewport.size();
|
_bubblesBackground.area = viewport.size();
|
||||||
|
@ -223,7 +228,7 @@ ChatPaintContext ChatTheme::preparePaintContext(
|
||||||
// _bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap;
|
// _bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap;
|
||||||
//}
|
//}
|
||||||
return {
|
return {
|
||||||
.st = _palette ? _palette.get() : style::main_palette::get(),
|
.st = st,
|
||||||
.bubblesPattern = _bubblesBackgroundPattern.get(),
|
.bubblesPattern = _bubblesBackgroundPattern.get(),
|
||||||
.viewport = viewport,
|
.viewport = viewport,
|
||||||
.clip = clip,
|
.clip = clip,
|
||||||
|
@ -240,6 +245,7 @@ const BackgroundState &ChatTheme::backgroundState(QSize area) {
|
||||||
&& !background().gradientForFill.isNull()) {
|
&& !background().gradientForFill.isNull()) {
|
||||||
// We don't support direct painting of patterned gradients.
|
// We don't support direct painting of patterned gradients.
|
||||||
// So we need to sync-generate cache image here.
|
// So we need to sync-generate cache image here.
|
||||||
|
_willCacheForArea = area;
|
||||||
setCachedBackground(CacheBackground(currentCacheRequest(area)));
|
setCachedBackground(CacheBackground(currentCacheRequest(area)));
|
||||||
_cacheBackgroundTimer->cancel();
|
_cacheBackgroundTimer->cancel();
|
||||||
} else if (_backgroundState.now.area != area) {
|
} else if (_backgroundState.now.area != area) {
|
||||||
|
|
|
@ -13,10 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
class ChatStyle;
|
||||||
struct BubblePattern;
|
struct BubblePattern;
|
||||||
|
|
||||||
struct ChatPaintContext {
|
struct ChatPaintContext {
|
||||||
not_null<const style::palette*> st;
|
not_null<const ChatStyle*> st;
|
||||||
const BubblePattern *bubblesPattern = nullptr;
|
const BubblePattern *bubblesPattern = nullptr;
|
||||||
QRect viewport;
|
QRect viewport;
|
||||||
QRect clip;
|
QRect clip;
|
||||||
|
@ -112,22 +113,23 @@ public:
|
||||||
ChatTheme(ChatThemeDescriptor &&descriptor);
|
ChatTheme(ChatThemeDescriptor &&descriptor);
|
||||||
|
|
||||||
[[nodiscard]] uint64 key() const;
|
[[nodiscard]] uint64 key() const;
|
||||||
[[nodiscard]] not_null<const style::palette*> palette() const {
|
[[nodiscard]] const style::palette *palette() const {
|
||||||
return _palette.get();
|
return _palette.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBackground(ChatThemeBackground &&background);
|
void setBackground(ChatThemeBackground &&background);
|
||||||
void updateBackgroundImageFrom(ChatThemeBackground &&background);
|
void updateBackgroundImageFrom(ChatThemeBackground &&background);
|
||||||
const ChatThemeBackground &background() const {
|
[[nodiscard]] const ChatThemeBackground &background() const {
|
||||||
return _mutableBackground;
|
return _mutableBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBubblesBackground(QImage image);
|
void setBubblesBackground(QImage image);
|
||||||
const BubblePattern *bubblesBackgroundPattern() const {
|
[[nodiscard]] const BubblePattern *bubblesBackgroundPattern() const {
|
||||||
return _bubblesBackgroundPattern.get();
|
return _bubblesBackgroundPattern.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] ChatPaintContext preparePaintContext(
|
[[nodiscard]] ChatPaintContext preparePaintContext(
|
||||||
|
not_null<const ChatStyle*> st,
|
||||||
QRect viewport,
|
QRect viewport,
|
||||||
QRect clip);
|
QRect clip);
|
||||||
[[nodiscard]] const BackgroundState &backgroundState(QSize area);
|
[[nodiscard]] const BackgroundState &backgroundState(QSize area);
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/cached_round_corners.h"
|
#include "ui/cached_round_corners.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -79,12 +80,10 @@ void PaintBubbleGeneric(
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintPatternBubble(Painter &p, const SimpleBubble &args) {
|
void PaintPatternBubble(Painter &p, const SimpleBubble &args) {
|
||||||
const auto opacity = st::msgOutBg->c.alphaF();
|
const auto opacity = args.st->msgOutBg()->c.alphaF();
|
||||||
const auto shadowOpacity = opacity * st::msgOutShadow->c.alphaF();
|
const auto shadowOpacity = opacity * args.st->msgOutShadow()->c.alphaF();
|
||||||
const auto pattern = args.pattern;
|
const auto pattern = args.pattern;
|
||||||
const auto sh = (args.skip & RectPart::Bottom)
|
const auto sh = !(args.skip & RectPart::Bottom);
|
||||||
? nullptr
|
|
||||||
: &st::msgOutShadow;
|
|
||||||
const auto &tail = (args.tailSide == RectPart::Right)
|
const auto &tail = (args.tailSide == RectPart::Right)
|
||||||
? pattern->tailRight
|
? pattern->tailRight
|
||||||
: pattern->tailLeft;
|
: pattern->tailLeft;
|
||||||
|
@ -221,30 +220,14 @@ void PaintPatternBubble(Painter &p, const SimpleBubble &args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintSolidBubble(Painter &p, const SimpleBubble &args) {
|
void PaintSolidBubble(Painter &p, const SimpleBubble &args) {
|
||||||
const auto &bg = args.selected
|
const auto &st = args.st->messageStyle(args.outbg, args.selected);
|
||||||
? (args.outbg ? st::msgOutBgSelected : st::msgInBgSelected)
|
const auto &bg = st.msgBg;
|
||||||
: (args.outbg ? st::msgOutBg : st::msgInBg);
|
|
||||||
const auto sh = (args.skip & RectPart::Bottom)
|
const auto sh = (args.skip & RectPart::Bottom)
|
||||||
? nullptr
|
? nullptr
|
||||||
: args.selected
|
: &st.msgShadow;
|
||||||
? &(args.outbg ? st::msgOutShadowSelected : st::msgInShadowSelected)
|
|
||||||
: &(args.outbg ? st::msgOutShadow : st::msgInShadow);
|
|
||||||
const auto corners = args.selected
|
|
||||||
? (args.outbg
|
|
||||||
? MessageOutSelectedCorners
|
|
||||||
: MessageInSelectedCorners)
|
|
||||||
: (args.outbg ? MessageOutCorners : MessageInCorners);
|
|
||||||
const auto &tail = (args.tailSide == RectPart::Right)
|
const auto &tail = (args.tailSide == RectPart::Right)
|
||||||
? (args.selected
|
? st.tailRight
|
||||||
? st::historyBubbleTailOutRightSelected
|
: st.tailLeft;
|
||||||
: st::historyBubbleTailOutRight)
|
|
||||||
: args.selected
|
|
||||||
? (args.outbg
|
|
||||||
? st::historyBubbleTailOutLeftSelected
|
|
||||||
: st::historyBubbleTailInLeftSelected)
|
|
||||||
: (args.outbg
|
|
||||||
? st::historyBubbleTailOutLeft
|
|
||||||
: st::historyBubbleTailInLeft);
|
|
||||||
const auto tailShift = (args.tailSide == RectPart::Right)
|
const auto tailShift = (args.tailSide == RectPart::Right)
|
||||||
? QPoint(0, tail.height())
|
? QPoint(0, tail.height())
|
||||||
: QPoint(tail.width(), tail.height());
|
: QPoint(tail.width(), tail.height());
|
||||||
|
@ -253,7 +236,7 @@ void PaintSolidBubble(Painter &p, const SimpleBubble &args) {
|
||||||
}, [&](const QRect &rect) {
|
}, [&](const QRect &rect) {
|
||||||
p.fillRect(rect, *sh);
|
p.fillRect(rect, *sh);
|
||||||
}, [&](const QRect &rect, RectParts parts) {
|
}, [&](const QRect &rect, RectParts parts) {
|
||||||
Ui::FillRoundRect(p, rect, bg, corners, sh, parts);
|
Ui::FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, st.corners, sh, parts);
|
||||||
}, [&](const QPoint &bottomPosition) {
|
}, [&](const QPoint &bottomPosition) {
|
||||||
tail.paint(p, bottomPosition - tailShift, args.outerWidth);
|
tail.paint(p, bottomPosition - tailShift, args.outerWidth);
|
||||||
return tail.width();
|
return tail.width();
|
||||||
|
@ -262,7 +245,8 @@ void PaintSolidBubble(Painter &p, const SimpleBubble &args) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<BubblePattern> PrepareBubblePattern() {
|
std::unique_ptr<BubblePattern> PrepareBubblePattern(
|
||||||
|
not_null<const style::palette*> st) {
|
||||||
auto result = std::make_unique<Ui::BubblePattern>();
|
auto result = std::make_unique<Ui::BubblePattern>();
|
||||||
result->corners = Images::CornersMask(st::historyMessageRadius);
|
result->corners = Images::CornersMask(st::historyMessageRadius);
|
||||||
const auto addShadow = [&](QImage &bottomCorner) {
|
const auto addShadow = [&](QImage &bottomCorner) {
|
||||||
|
@ -274,7 +258,7 @@ std::unique_ptr<BubblePattern> PrepareBubblePattern() {
|
||||||
result.fill(Qt::transparent);
|
result.fill(Qt::transparent);
|
||||||
result.setDevicePixelRatio(bottomCorner.devicePixelRatio());
|
result.setDevicePixelRatio(bottomCorner.devicePixelRatio());
|
||||||
auto p = QPainter(&result);
|
auto p = QPainter(&result);
|
||||||
p.setOpacity(st::msgInShadow->c.alphaF());
|
p.setOpacity(st->msgInShadow()->c.alphaF());
|
||||||
p.drawImage(0, st::msgShadow, bottomCorner);
|
p.drawImage(0, st::msgShadow, bottomCorner);
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
p.drawImage(0, 0, bottomCorner);
|
p.drawImage(0, 0, bottomCorner);
|
||||||
|
|
|
@ -13,6 +13,9 @@ class Painter;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
class ChatTheme;
|
||||||
|
class ChatStyle;
|
||||||
|
|
||||||
struct BubbleSelectionInterval {
|
struct BubbleSelectionInterval {
|
||||||
int top = 0;
|
int top = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
@ -28,9 +31,11 @@ struct BubblePattern {
|
||||||
mutable QImage tailCache;
|
mutable QImage tailCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<BubblePattern> PrepareBubblePattern();
|
[[nodiscard]] std::unique_ptr<BubblePattern> PrepareBubblePattern(
|
||||||
|
not_null<const style::palette*> st);
|
||||||
|
|
||||||
struct SimpleBubble {
|
struct SimpleBubble {
|
||||||
|
not_null<const ChatStyle*> st;
|
||||||
QRect geometry;
|
QRect geometry;
|
||||||
const BubblePattern *pattern = nullptr;
|
const BubblePattern *pattern = nullptr;
|
||||||
QRect patternViewport;
|
QRect patternViewport;
|
||||||
|
|
|
@ -61,22 +61,6 @@ namespace {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto ChatThemeValueFromPeer(
|
|
||||||
not_null<SessionController*> controller,
|
|
||||||
not_null<PeerData*> peer)
|
|
||||||
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
|
||||||
return MaybeCloudThemeValueFromPeer(
|
|
||||||
peer
|
|
||||||
) | rpl::map([=](std::optional<Data::CloudTheme> theme)
|
|
||||||
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
|
||||||
if (!theme) {
|
|
||||||
return rpl::single(controller->defaultChatTheme());
|
|
||||||
}
|
|
||||||
return controller->cachedChatThemeValue(*theme);
|
|
||||||
}) | rpl::flatten_latest(
|
|
||||||
) | rpl::distinct_until_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AbstractSectionWidget::AbstractSectionWidget(
|
AbstractSectionWidget::AbstractSectionWidget(
|
||||||
|
@ -298,4 +282,20 @@ rpl::producer<int> SectionWidget::desiredHeight() const {
|
||||||
|
|
||||||
SectionWidget::~SectionWidget() = default;
|
SectionWidget::~SectionWidget() = default;
|
||||||
|
|
||||||
|
auto ChatThemeValueFromPeer(
|
||||||
|
not_null<SessionController*> controller,
|
||||||
|
not_null<PeerData*> peer)
|
||||||
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
||||||
|
return MaybeCloudThemeValueFromPeer(
|
||||||
|
peer
|
||||||
|
) | rpl::map([=](std::optional<Data::CloudTheme> theme)
|
||||||
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>> {
|
||||||
|
if (!theme) {
|
||||||
|
return rpl::single(controller->defaultChatTheme());
|
||||||
|
}
|
||||||
|
return controller->cachedChatThemeValue(*theme);
|
||||||
|
}) | rpl::flatten_latest(
|
||||||
|
) | rpl::distinct_until_changed();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -203,4 +203,9 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] auto ChatThemeValueFromPeer(
|
||||||
|
not_null<SessionController*> controller,
|
||||||
|
not_null<PeerData*> peer)
|
||||||
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>>;
|
||||||
|
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/delayed_activation.h"
|
#include "ui/delayed_activation.h"
|
||||||
#include "ui/chat/message_bubble.h"
|
#include "ui/chat/message_bubble.h"
|
||||||
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/chat/chat_theme.h"
|
#include "ui/chat/chat_theme.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/toasts/common_toasts.h"
|
#include "ui/toasts/common_toasts.h"
|
||||||
|
@ -79,6 +80,7 @@ constexpr auto kMaxChatEntryHistorySize = 50;
|
||||||
std::optional<QColor> accent) {
|
std::optional<QColor> accent) {
|
||||||
return [=](style::palette &palette) {
|
return [=](style::palette &palette) {
|
||||||
using namespace Theme;
|
using namespace Theme;
|
||||||
|
palette.finalize();
|
||||||
if (dark) {
|
if (dark) {
|
||||||
const auto &embedded = EmbeddedThemes();
|
const auto &embedded = EmbeddedThemes();
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
|
@ -506,9 +508,13 @@ SessionController::SessionController(
|
||||||
_window->widget(),
|
_window->widget(),
|
||||||
this))
|
this))
|
||||||
, _invitePeekTimer([=] { checkInvitePeek(); })
|
, _invitePeekTimer([=] { checkInvitePeek(); })
|
||||||
, _defaultChatTheme(std::make_shared<Ui::ChatTheme>()) {
|
, _defaultChatTheme(std::make_shared<Ui::ChatTheme>())
|
||||||
|
, _chatStyle(std::make_unique<Ui::ChatStyle>()) {
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
_chatStyleTheme = _defaultChatTheme;
|
||||||
|
_chatStyle->apply(_defaultChatTheme.get());
|
||||||
|
|
||||||
pushDefaultChatBackground();
|
pushDefaultChatBackground();
|
||||||
Theme::Background()->updates(
|
Theme::Background()->updates(
|
||||||
) | rpl::start_with_next([=](const Theme::BackgroundUpdate &update) {
|
) | rpl::start_with_next([=](const Theme::BackgroundUpdate &update) {
|
||||||
|
@ -1378,6 +1384,15 @@ auto SessionController::cachedChatThemeValue(
|
||||||
}) | rpl::take(1));
|
}) | rpl::take(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionController::setChatStyleTheme(
|
||||||
|
const std::shared_ptr<Ui::ChatTheme> &theme) {
|
||||||
|
if (_chatStyleTheme.lock() == theme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_chatStyleTheme = theme;
|
||||||
|
_chatStyle->apply(theme.get());
|
||||||
|
}
|
||||||
|
|
||||||
void SessionController::pushDefaultChatBackground() {
|
void SessionController::pushDefaultChatBackground() {
|
||||||
const auto background = Theme::Background();
|
const auto background = Theme::Background();
|
||||||
const auto &paper = background->paper();
|
const auto &paper = background->paper();
|
||||||
|
@ -1520,7 +1535,10 @@ HistoryView::PaintContext SessionController::preparePaintContext(
|
||||||
args.visibleAreaTop - visibleAreaTopLocal,
|
args.visibleAreaTop - visibleAreaTopLocal,
|
||||||
args.visibleAreaWidth,
|
args.visibleAreaWidth,
|
||||||
content()->height());
|
content()->height());
|
||||||
return args.theme->preparePaintContext(viewport, args.clip);
|
return args.theme->preparePaintContext(
|
||||||
|
_chatStyle.get(),
|
||||||
|
viewport,
|
||||||
|
args.clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionController::~SessionController() {
|
SessionController::~SessionController() {
|
||||||
|
|
|
@ -45,6 +45,7 @@ class FormController;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class LayerWidget;
|
class LayerWidget;
|
||||||
enum class ReportReason;
|
enum class ReportReason;
|
||||||
|
class ChatStyle;
|
||||||
class ChatTheme;
|
class ChatTheme;
|
||||||
struct ChatPaintContext;
|
struct ChatPaintContext;
|
||||||
struct ChatThemeBackground;
|
struct ChatThemeBackground;
|
||||||
|
@ -404,6 +405,7 @@ public:
|
||||||
[[nodiscard]] auto cachedChatThemeValue(
|
[[nodiscard]] auto cachedChatThemeValue(
|
||||||
const Data::CloudTheme &data)
|
const Data::CloudTheme &data)
|
||||||
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>>;
|
-> rpl::producer<std::shared_ptr<Ui::ChatTheme>>;
|
||||||
|
void setChatStyleTheme(const std::shared_ptr<Ui::ChatTheme> &theme);
|
||||||
|
|
||||||
struct PaintContextArgs {
|
struct PaintContextArgs {
|
||||||
not_null<Ui::ChatTheme*> theme;
|
not_null<Ui::ChatTheme*> theme;
|
||||||
|
@ -484,6 +486,8 @@ private:
|
||||||
std::shared_ptr<Ui::ChatTheme> _defaultChatTheme;
|
std::shared_ptr<Ui::ChatTheme> _defaultChatTheme;
|
||||||
base::flat_map<uint64, CachedTheme> _customChatThemes;
|
base::flat_map<uint64, CachedTheme> _customChatThemes;
|
||||||
rpl::event_stream<std::shared_ptr<Ui::ChatTheme>> _cachedThemesStream;
|
rpl::event_stream<std::shared_ptr<Ui::ChatTheme>> _cachedThemesStream;
|
||||||
|
std::unique_ptr<Ui::ChatStyle> _chatStyle;
|
||||||
|
std::weak_ptr<Ui::ChatTheme> _chatStyleTheme;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,8 @@ PRIVATE
|
||||||
ui/chat/attach/attach_single_file_preview.h
|
ui/chat/attach/attach_single_file_preview.h
|
||||||
ui/chat/attach/attach_single_media_preview.cpp
|
ui/chat/attach/attach_single_media_preview.cpp
|
||||||
ui/chat/attach/attach_single_media_preview.h
|
ui/chat/attach/attach_single_media_preview.h
|
||||||
|
ui/chat/chat_style.cpp
|
||||||
|
ui/chat/chat_style.h
|
||||||
ui/chat/chat_theme.cpp
|
ui/chat/chat_theme.cpp
|
||||||
ui/chat/chat_theme.h
|
ui/chat/chat_theme.h
|
||||||
ui/chat/group_call_bar.cpp
|
ui/chat/group_call_bar.cpp
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 13117d03e5683af00f898a330aa319fd17efe8f7
|
Subproject commit 62158ed7955af3f7eabb1156075c1a41c4fff6b3
|
|
@ -1 +1 @@
|
||||||
Subproject commit 15ffd051d605be310051645412c54c2b9f87ff01
|
Subproject commit 3c95a9187194c07fda409f1ad1e142232bb82cbc
|
Loading…
Add table
Reference in a new issue