Custom colors in history_view_service_message module.

This commit is contained in:
John Preston 2021-09-03 13:17:07 +03:00
parent 1a4a9319f3
commit 2a2607d026
24 changed files with 520 additions and 367 deletions

View File

@ -237,7 +237,10 @@ InnerWidget::InnerWidget(
, _channel(channel)
, _history(channel->owner().history(channel))
, _api(&_channel->session().mtp())
, _pathGradient(HistoryView::MakePathShiftGradient([=] { update(); }))
, _pathGradient(
HistoryView::MakePathShiftGradient(
controller->chatStyle(),
[=] { update(); }))
, _scrollDateCheck([=] { scrollDateCheck(); })
, _emptyText(
st::historyAdminLogEmptyWidth
@ -906,8 +909,14 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
auto clip = e->rect();
auto context = _controller->preparePaintContext({
.theme = _theme.get(),
.visibleAreaTop = _visibleTop,
.visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(),
.clip = clip,
});
if (_items.empty() && _upLoaded && _downLoaded) {
paintEmpty(p);
paintEmpty(p, context.st);
} else {
_pathGradient->startFrame(
0,
@ -923,12 +932,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
});
if (from != end) {
auto top = itemTop(from->get());
auto context = _controller->preparePaintContext({
.theme = _theme.get(),
.visibleAreaTop = _visibleTop,
.visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(),
.clip = clip,
}).translated(0, -top);
context.translate(0, -top);
p.translate(0, top);
for (auto i = from; i != to; ++i) {
const auto view = i->get();
@ -1000,10 +1004,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
const auto chatWide =
_controller->adaptive().isChatWide();
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, dateY, width, chatWide);
date->paint(p, context.st, dateY, width, chatWide);
} else {
HistoryView::ServiceMessagePainter::paintDate(
HistoryView::ServiceMessagePainter::PaintDate(
p,
context.st,
view->dateTime(),
dateY,
width,
@ -1043,19 +1048,14 @@ auto InnerWidget::viewForItem(const HistoryItem *item) -> Element* {
return nullptr;
}
void InnerWidget::paintEmpty(Painter &p) {
void InnerWidget::paintEmpty(Painter &p, not_null<const Ui::ChatStyle*> st) {
auto rectWidth = st::historyAdminLogEmptyWidth;
auto innerWidth = rectWidth - st::historyAdminLogEmptyPadding.left() - st::historyAdminLogEmptyPadding.right();
auto rectHeight = st::historyAdminLogEmptyPadding.top() + _emptyText.countHeight(innerWidth) + st::historyAdminLogEmptyPadding.bottom();
auto rect = QRect((width() - rectWidth) / 2, (height() - rectHeight) / 3, rectWidth, rectHeight);
HistoryView::ServiceMessagePainter::paintBubble(
p,
rect.x(),
rect.y(),
rect.width(),
rect.height());
HistoryView::ServiceMessagePainter::PaintBubble(p, st, rect);
p.setPen(st::msgServiceFg);
p.setPen(st->msgServiceFg());
_emptyText.draw(p, rect.x() + st::historyAdminLogEmptyPadding.left(), rect.y() + st::historyAdminLogEmptyPadding.top(), innerWidth, style::al_top);
}

View File

@ -36,6 +36,7 @@ enum class PointState : char;
namespace Ui {
class PopupMenu;
class ChatStyle;
} // namespace Ui
namespace Window {
@ -213,7 +214,7 @@ private:
void updateSize();
void updateMinMaxIds();
void updateEmptyText();
void paintEmpty(Painter &p);
void paintEmpty(Painter &p, not_null<const Ui::ChatStyle*> st);
void clearAfterFilterChange();
void clearAndRequestLog();
void addEvents(Direction direction, const QVector<MTPChannelAdminLogEvent> &events);

View File

@ -159,7 +159,10 @@ HistoryInner::HistoryInner(
, _peer(history->peer)
, _history(history)
, _migrated(history->migrateFrom())
, _pathGradient(HistoryView::MakePathShiftGradient([=] { update(); }))
, _pathGradient(
HistoryView::MakePathShiftGradient(
controller->chatStyle(),
[=] { update(); }))
, _scrollDateCheck([this] { scrollDateCheck(); })
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
Instance = this;
@ -543,12 +546,16 @@ TextSelection HistoryInner::itemRenderSelection(
return TextSelection();
}
void HistoryInner::paintEmpty(Painter &p, int width, int height) {
void HistoryInner::paintEmpty(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int width,
int height) {
if (!_emptyPainter) {
_emptyPainter = std::make_unique<HistoryView::EmptyPainter>(
_history);
}
_emptyPainter->paint(p, width, height);
_emptyPainter->paint(p, st, width, height);
}
void HistoryInner::paintEvent(QPaintEvent *e) {
@ -563,37 +570,47 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
_userpicsCache.clear();
});
Painter p(this);
auto clip = e->rect();
const auto visibleAreaTopGlobal = mapToGlobal(
QPoint(0, _visibleAreaTop)).y();
auto context = _controller->preparePaintContext({
.theme = _theme.get(),
.visibleAreaTop = _visibleAreaTop,
.visibleAreaTopGlobal = visibleAreaTopGlobal,
.clip = clip,
});
_pathGradient->startFrame(
0,
width(),
std::min(st::msgMaxWidth / 2, width() / 2));
Painter p(this);
auto clip = e->rect();
const auto historyDisplayedEmpty = _history->isDisplayedEmpty()
&& (!_migrated || _migrated->isDisplayedEmpty());
bool noHistoryDisplayed = _firstLoading || historyDisplayedEmpty;
if (!_firstLoading && _botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) {
const auto st = context.st;
const auto stm = &st->messageStyle(false, false);
if (clip.y() < _botAbout->rect.y() + _botAbout->rect.height() && clip.y() + clip.height() > _botAbout->rect.y()) {
p.setTextPalette(st::inTextPalette);
Ui::FillRoundRect(p, _botAbout->rect, st::msgInBg, Ui::MessageInCorners, &st::msgInShadow);
p.setTextPalette(stm->textPalette);
Ui::FillRoundRect(p, _botAbout->rect, stm->msgBg, stm->corners, &stm->msgShadow);
auto top = _botAbout->rect.top() + st::msgPadding.top();
if (!_history->peer->isRepliesChat()) {
p.setFont(st::msgNameFont);
p.setPen(st::dialogsNameFg);
p.setPen(st->dialogsNameFg());
p.drawText(_botAbout->rect.left() + st::msgPadding.left(), top + st::msgNameFont->ascent, tr::lng_bot_description(tr::now));
top += +st::msgNameFont->height + st::botDescSkip;
}
p.setPen(st::historyTextInFg);
p.setPen(stm->historyTextFg);
_botAbout->info->text.draw(p, _botAbout->rect.left() + st::msgPadding.left(), top, _botAbout->width);
p.restoreTextPalette();
}
} else if (historyDisplayedEmpty) {
paintEmpty(p, width(), height());
paintEmpty(p, context.st, width(), height());
} else {
_emptyPainter = nullptr;
}
@ -611,8 +628,6 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
} else {
seltoy += _dragSelTo->height();
}
const auto visibleAreaTopGlobal = mapToGlobal(
QPoint(0, _visibleAreaTop)).y();
auto mtop = migratedTop();
auto htop = historyTop();
@ -625,12 +640,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
auto item = view->data();
auto top = mtop + block->y() + view->y();
auto context = _controller->preparePaintContext({
.theme = _theme.get(),
.visibleAreaTop = _visibleAreaTop,
.visibleAreaTopGlobal = visibleAreaTopGlobal,
.clip = clip,
}).translated(0, -top);
context.translate(0, -top);
p.translate(0, top);
if (context.clip.y() < view->height()) while (top < drawToY) {
context.outbg = view->hasOutLayout();
@ -666,6 +676,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
item = view->data();
}
p.translate(0, -top);
context.translate(0, top);
}
if (htop >= 0) {
auto iBlock = (_curHistory == _history ? _curBlock : 0);
@ -675,15 +686,9 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
auto item = view->data();
auto readTill = (HistoryItem*)nullptr;
auto top = htop + block->y() + view->y();
auto context = _controller->preparePaintContext({
.theme = _theme.get(),
.visibleAreaTop = _visibleAreaTop,
.visibleAreaTopGlobal = visibleAreaTopGlobal,
.visibleAreaWidth = width(),
.clip = clip.intersected(
QRect(0, hdrawtop, width(), clip.top() + clip.height())
),
}).translated(0, -top);
context.clip = clip.intersected(
QRect(0, hdrawtop, width(), clip.top() + clip.height()));
context.translate(0, -top);
p.translate(0, top);
while (top < drawToY) {
const auto height = view->height();
@ -812,10 +817,11 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
? itemtop
: (dateTop - st::msgServiceMargin.top());
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, dateY, _contentWidth, _isChatWide);
date->paint(p, context.st, dateY, _contentWidth, _isChatWide);
} else {
HistoryView::ServiceMessagePainter::paintDate(
HistoryView::ServiceMessagePainter::PaintDate(
p,
context.st,
view->dateTime(),
dateY,
_contentWidth,

View File

@ -35,6 +35,7 @@ class SessionController;
namespace Ui {
class ChatTheme;
class ChatStyle;
class PopupMenu;
enum class ReportReason;
class PathShiftGradient;
@ -246,7 +247,11 @@ private:
std::unique_ptr<QMimeData> prepareDrag();
void performDrag();
void paintEmpty(Painter &p, int width, int height);
void paintEmpty(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int width,
int height);
QPoint mapPointToItem(QPoint p, const Element *view) const;
QPoint mapPointToItem(QPoint p, const HistoryItem *item) const;

View File

@ -107,6 +107,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/pinned_bar.h"
#include "ui/chat/group_call_bar.h"
#include "ui/chat/chat_theme.h"
#include "ui/chat/chat_style.h"
#include "ui/widgets/popup_menu.h"
#include "ui/item_text_options.h"
#include "ui/unread_badge.h"
@ -7058,9 +7059,10 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
- st::msgServiceMargin.bottom()) / 2,
w,
h);
HistoryView::ServiceMessagePainter::paintBubble(p, tr.x(), tr.y(), tr.width(), tr.height());
const auto st = controller()->chatStyle();
HistoryView::ServiceMessagePainter::PaintBubble(p, st, tr);
p.setPen(st::msgServiceFg);
p.setPen(st->msgServiceFg());
p.setFont(st::msgServiceFont->f);
p.drawTextLeft(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top(), width(), tr::lng_willbe_history(tr::now));

View File

@ -23,13 +23,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/stickers_emoji_pack.h"
#include "window/window_session_controller.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/chat/chat_style.h"
#include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h"
#include "data/data_session.h"
#include "data/data_groups.h"
#include "data/data_media_types.h"
#include "lang/lang_keys.h"
#include "layout/layout_selection.h"
#include "app.h"
#include "styles/style_chat.h"
@ -62,10 +62,11 @@ bool IsAttachedToPreviousInSavedMessages(
} // namespace
std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient(
not_null<const Ui::ChatStyle*> st,
Fn<void()> update) {
return std::make_unique<Ui::PathShiftGradient>(
st::msgServiceBg,
st::msgServiceBgSelected,
st->msgServiceBg(),
st->msgServiceBgSelected(),
std::move(update));
}
@ -73,7 +74,10 @@ SimpleElementDelegate::SimpleElementDelegate(
not_null<Window::SessionController*> controller,
Fn<void()> update)
: _controller(controller)
, _pathGradient(MakePathShiftGradient(std::move(update))) {
, _pathGradient(
MakePathShiftGradient(
controller->chatStyle(),
std::move(update))) {
}
SimpleElementDelegate::~SimpleElementDelegate() = default;
@ -259,7 +263,13 @@ int UnreadBar::marginTop() {
return st::lineWidth + st::historyUnreadBarMargin;
}
void UnreadBar::paint(Painter &p, int y, int w, bool chatWide) const {
void UnreadBar::paint(
Painter &p,
const PaintContext &context,
int y,
int w,
bool chatWide) const {
const auto st = context.st;
const auto bottom = y + height();
y += marginTop();
p.fillRect(
@ -267,15 +277,15 @@ void UnreadBar::paint(Painter &p, int y, int w, bool chatWide) const {
y,
w,
height() - marginTop() - st::lineWidth,
st::historyUnreadBarBg);
st->historyUnreadBarBg());
p.fillRect(
0,
bottom - st::lineWidth,
w,
st::lineWidth,
st::historyUnreadBarBorder);
st->historyUnreadBarBorder());
p.setFont(st::historyUnreadBarFont);
p.setPen(st::historyUnreadBarFg);
p.setPen(st->historyUnreadBarFg());
int maxwidth = w;
if (chatWide) {
@ -310,8 +320,13 @@ int DateBadge::height() const {
+ st::msgServiceMargin.bottom();
}
void DateBadge::paint(Painter &p, int y, int w, bool chatWide) const {
ServiceMessagePainter::paintDate(p, text, width, y, w, chatWide);
void DateBadge::paint(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int y,
int w,
bool chatWide) const {
ServiceMessagePainter::PaintDate(p, st, text, width, y, w, chatWide);
}
Element::Element(
@ -367,6 +382,7 @@ void Element::refreshDataIdHook() {
void Element::paintHighlight(
Painter &p,
const PaintContext &context,
int geometryHeight) const {
const auto top = marginTop();
const auto bottom = marginBottom();
@ -374,7 +390,7 @@ void Element::paintHighlight(
const auto skiptop = top - fill;
const auto fillheight = fill + geometryHeight + fill;
paintCustomHighlight(p, skiptop, fillheight, data());
paintCustomHighlight(p, context, skiptop, fillheight, data());
}
float64 Element::highlightOpacity(not_null<const HistoryItem*> item) const {
@ -392,6 +408,7 @@ float64 Element::highlightOpacity(not_null<const HistoryItem*> item) const {
void Element::paintCustomHighlight(
Painter &p,
const PaintContext &context,
int y,
int height,
not_null<const HistoryItem*> item) const {
@ -406,7 +423,7 @@ void Element::paintCustomHighlight(
y,
width(),
height,
st::defaultTextPalette.selectOverlay);
context.st->msgSelectOverlay());
p.setOpacity(o);
}

View File

@ -26,6 +26,7 @@ namespace Ui {
class PathShiftGradient;
struct BubblePattern;
struct ChatPaintContext;
class ChatStyle;
} // namespace Ui
namespace HistoryView {
@ -36,6 +37,8 @@ struct StateRequest;
struct TextState;
class Media;
using PaintContext = Ui::ChatPaintContext;
enum class Context : char {
History,
Replies,
@ -94,6 +97,7 @@ public:
};
[[nodiscard]] std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient(
not_null<const Ui::ChatStyle*> st,
Fn<void()> update);
class SimpleElementDelegate : public ElementDelegate {
@ -177,7 +181,12 @@ struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
static int height();
static int marginTop();
void paint(Painter &p, int y, int w, bool chatWide) const;
void paint(
Painter &p,
const PaintContext &context,
int y,
int w,
bool chatWide) const;
QString text;
int width = 0;
@ -191,15 +200,18 @@ struct DateBadge : public RuntimeComponent<DateBadge, Element> {
void init(const QString &date);
int height() const;
void paint(Painter &p, int y, int w, bool chatWide) const;
void paint(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int y,
int w,
bool chatWide) const;
QString text;
int width = 0;
};
using PaintContext = Ui::ChatPaintContext;
class Element
: public Object
, public RuntimeComposer<Element>
@ -347,6 +359,7 @@ public:
void paintCustomHighlight(
Painter &p,
const PaintContext &context,
int y,
int height,
not_null<const HistoryItem*> item) const;
@ -376,6 +389,7 @@ public:
protected:
void paintHighlight(
Painter &p,
const PaintContext &context,
int geometryHeight) const;
[[nodiscard]] ClickHandlerPtr fromLink() const;

View File

@ -7,17 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_empty_list_bubble.h"
#include "history/view/history_view_list_widget.h"
#include "ui/chat/chat_style.h"
#include "history/view/history_view_service_message.h"
namespace HistoryView {
EmptyListBubbleWidget::EmptyListBubbleWidget(
not_null<ListWidget*> parent,
not_null<Ui::RpWidget*> parent,
not_null<const Ui::ChatStyle*> st,
const style::margins &padding)
: RpWidget(parent)
, _padding(padding) {
, _padding(padding)
, _st(st) {
parent->sizeValue(
) | rpl::start_with_next([=](const QSize &s) {
updateGeometry(s);
@ -42,14 +43,9 @@ void EmptyListBubbleWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto r = rect();
HistoryView::ServiceMessagePainter::paintBubble(
p,
r.x(),
r.y(),
r.width(),
r.height());
HistoryView::ServiceMessagePainter::PaintBubble(p, _st, r);
p.setPen(st::msgServiceFg);
p.setPen(_st->msgServiceFg());
_text.draw(
p,
r.x() + _padding.left(),

View File

@ -9,14 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h"
namespace HistoryView {
namespace Ui {
class ChatStyle;
} // namespace Ui
class ListWidget;
namespace HistoryView {
class EmptyListBubbleWidget : public Ui::RpWidget {
public:
EmptyListBubbleWidget(
not_null<ListWidget*> parent,
not_null<Ui::RpWidget*> parent,
not_null<const Ui::ChatStyle*> st,
const style::margins &padding);
void setText(const TextWithEntities &textWithEntities);
@ -29,6 +32,7 @@ private:
void updateGeometry(const QSize &size);
const style::margins &_padding;
const not_null<const Ui::ChatStyle*> _st;
Ui::Text::String _text;
int _innerWidth = 0;
int _forceWidth = 0;

View File

@ -256,7 +256,10 @@ ListWidget::ListWidget(
, _controller(controller)
, _context(_delegate->listContext())
, _itemAverageHeight(itemMinimalHeight())
, _pathGradient(MakePathShiftGradient([=] { update(); }))
, _pathGradient(
MakePathShiftGradient(
controller->chatStyle(),
[=] { update(); }))
, _scrollDateCheck([this] { scrollDateCheck(); })
, _applyUpdatedScrollState([this] { applyUpdatedScrollState(); })
, _selectEnabled(_delegate->listAllowsMultiSelect())
@ -1700,11 +1703,14 @@ void ListWidget::paintEvent(QPaintEvent *e) {
int dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top());
int width = view->width();
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, dateY, width, _isChatWide);
date->paint(p, context.st, dateY, width, _isChatWide);
} else {
ServiceMessagePainter::paintDate(
ServiceMessagePainter::PaintDate(
p,
ItemDateText(view->data(), IsItemScheduledUntilOnline(view->data())),
context.st,
ItemDateText(
view->data(),
IsItemScheduledUntilOnline(view->data())),
dateY,
width,
_isChatWide);

View File

@ -498,7 +498,12 @@ void Message::draw(Painter &p, const PaintContext &context) const {
auto unreadbarh = bar->height();
if (context.clip.intersects(QRect(0, dateh, width(), unreadbarh))) {
p.translate(0, dateh);
bar->paint(p, 0, width(), delegate()->elementIsChatWide());
bar->paint(
p,
context,
0,
width(),
delegate()->elementIsChatWide());
p.translate(0, -dateh);
}
}
@ -537,9 +542,9 @@ void Message::draw(Painter &p, const PaintContext &context) const {
}
if (customHighlight) {
media->drawHighlight(p, localMediaTop);
media->drawHighlight(p, context, localMediaTop);
} else {
paintHighlight(p, g.height());
paintHighlight(p, context, g.height());
}
const auto roll = media ? media->bubbleRoll() : Media::BubbleRoll();

View File

@ -163,6 +163,7 @@ ScheduledWidget::ScheduledWidget(
{
auto emptyInfo = base::make_unique_q<EmptyListBubbleWidget>(
_inner,
controller->chatStyle(),
st::msgServicePadding);
const auto emptyText = Ui::Text::Semibold(
tr::lng_scheduled_messages_empty(tr::now));

View File

@ -41,98 +41,6 @@ enum CornerHorizontalSide {
CornerRight = 0x01,
};
class ServiceMessageStyleData : public Data::AbstractStructure {
public:
ServiceMessageStyleData() {
style::PaletteChanged(
) | rpl::start_with_next([=] {
for (auto &corner : corners) {
corner = QPixmap();
}
}, _lifetime);
}
// circle[CircleMask value]
QImage circle[2];
// corners[(CircleMask value) * MaskMultiplier | (CornerVerticalSide value) | (CornerHorizontalSide value)]
QPixmap corners[8];
base::flat_map<std::pair<int, uint32>, QPixmap> overridenCorners;
private:
rpl::lifetime _lifetime;
};
Data::GlobalStructurePointer<ServiceMessageStyleData> serviceMessageStyle;
int historyServiceMsgRadius() {
static int HistoryServiceMsgRadius = ([]() {
auto minMsgHeight = (st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom());
return minMsgHeight / 2;
})();
return HistoryServiceMsgRadius;
}
int historyServiceMsgInvertedRadius() {
static int HistoryServiceMsgInvertedRadius = ([]() {
auto minRowHeight = st::msgServiceFont->height;
return minRowHeight - historyServiceMsgRadius();
})();
return HistoryServiceMsgInvertedRadius;
}
int historyServiceMsgInvertedShrink() {
static int HistoryServiceMsgInvertedShrink = ([]() {
return (historyServiceMsgInvertedRadius() * 2) / 3;
})();
return HistoryServiceMsgInvertedShrink;
}
void createCircleMasks() {
serviceMessageStyle.createIfNull();
if (!serviceMessageStyle->circle[NormalMask].isNull()) return;
int size = historyServiceMsgRadius() * 2;
serviceMessageStyle->circle[NormalMask] = style::createCircleMask(size);
int sizeInverted = historyServiceMsgInvertedRadius() * 2;
serviceMessageStyle->circle[InvertedMask] = style::createInvertedCircleMask(sizeInverted);
}
uint32 ColorToUint(const style::color &bg) {
const auto &c = bg->c;
return c.red() << 24 | c.green() << 16 | c.blue() << 8 | c.alpha();
}
QPixmap circleCorner(int corner, const style::color &bg) {
auto &currentCorner = (bg == st::msgServiceBg)
? serviceMessageStyle->corners[corner]
: serviceMessageStyle->overridenCorners[{ corner, ColorToUint(bg) }];
if (currentCorner.isNull()) {
int maskType = corner / MaskMultiplier;
int radius = (maskType == NormalMask
? historyServiceMsgRadius()
: historyServiceMsgInvertedRadius());
int size = radius * cIntRetinaFactor();
int xoffset = 0, yoffset = 0;
if (corner & CornerRight) {
xoffset = size;
}
if (corner & CornerBottom) {
yoffset = size;
}
auto part = QRect(xoffset, yoffset, size, size);
auto result = style::colorizeImage(
serviceMessageStyle->circle[maskType],
bg,
part);
result.setDevicePixelRatio(cRetinaFactor());
currentCorner = Ui::PixmapFromImage(std::move(result));
}
return currentCorner;
}
enum class SideStyle {
Rounded,
Plain,
@ -140,96 +48,97 @@ enum class SideStyle {
};
// Returns amount of pixels already painted vertically (so you can skip them in the complex rect shape).
int paintBubbleSide(
int PaintBubbleSide(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int x,
int y,
int width,
SideStyle style,
CornerVerticalSide side,
const style::color &bg) {
CornerVerticalSide side) {
if (style == SideStyle::Rounded) {
const auto corner = (int(NormalMask) * MaskMultiplier) | side;
auto left = circleCorner(corner | CornerLeft, bg);
int leftWidth = left.width() / cIntRetinaFactor();
const auto &corners = st->serviceBgCornersNormal();
const auto left = corners.p[(side == CornerTop) ? 0 : 2];
const auto leftWidth = left.width() / cIntRetinaFactor();
p.drawPixmap(x, y, left);
auto right = circleCorner(corner | CornerRight, bg);
int rightWidth = right.width() / cIntRetinaFactor();
const auto right = corners.p[(side == CornerTop) ? 1 : 3];
const auto rightWidth = right.width() / cIntRetinaFactor();
p.drawPixmap(x + width - rightWidth, y, right);
int cornerHeight = left.height() / cIntRetinaFactor();
const auto cornerHeight = left.height() / cIntRetinaFactor();
p.fillRect(
x + leftWidth,
y,
width - leftWidth - rightWidth,
cornerHeight,
bg);
st->msgServiceBg());
return cornerHeight;
} else if (style == SideStyle::Inverted) {
// CornerLeft and CornerRight are inverted for SideStyle::Inverted sprites.
const auto corner = (int(InvertedMask) * MaskMultiplier) | side;
auto left = circleCorner(corner | CornerRight, bg);
int leftWidth = left.width() / cIntRetinaFactor();
// CornerLeft and CornerRight are inverted in the top part.
const auto &corners = st->serviceBgCornersInverted();
const auto left = corners.p[(side == CornerTop) ? 1 : 2];
const auto leftWidth = left.width() / cIntRetinaFactor();
p.drawPixmap(x - leftWidth, y, left);
auto right = circleCorner(corner | CornerLeft, bg);
const auto right = corners.p[(side == CornerTop) ? 0 : 3];
p.drawPixmap(x + width, y, right);
}
return 0;
}
void paintBubblePart(
void PaintBubblePart(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int x,
int y,
int width,
int height,
SideStyle topStyle,
SideStyle bottomStyle,
const style::color &bg,
bool forceShrink = false) {
if ((topStyle == SideStyle::Inverted)
|| (bottomStyle == SideStyle::Inverted)
|| forceShrink) {
width -= historyServiceMsgInvertedShrink() * 2;
x += historyServiceMsgInvertedShrink();
width -= Ui::HistoryServiceMsgInvertedShrink() * 2;
x += Ui::HistoryServiceMsgInvertedShrink();
}
if (int skip = paintBubbleSide(p, x, y, width, topStyle, CornerTop, bg)) {
if (int skip = PaintBubbleSide(p, st, x, y, width, topStyle, CornerTop)) {
y += skip;
height -= skip;
}
int bottomSize = 0;
if (bottomStyle == SideStyle::Rounded) {
bottomSize = historyServiceMsgRadius();
bottomSize = Ui::HistoryServiceMsgRadius();
} else if (bottomStyle == SideStyle::Inverted) {
bottomSize = historyServiceMsgInvertedRadius();
bottomSize = Ui::HistoryServiceMsgInvertedRadius();
}
const auto skip = paintBubbleSide(
const auto skip = PaintBubbleSide(
p,
st,
x,
y + height - bottomSize,
width,
bottomStyle,
CornerBottom,
bg);
CornerBottom);
if (skip) {
height -= skip;
}
p.fillRect(x, y, width, height, bg);
p.fillRect(x, y, width, height, st->msgServiceBg());
}
void paintPreparedDate(
void PaintPreparedDate(
Painter &p,
const style::color &bg,
const Ui::CornersPixmaps &corners,
const style::color &fg,
const QString &dateText,
int dateTextWidth,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
bool chatWide) {
int left = st::msgServiceMargin.left();
const auto maxwidth = chatWide
? std::min(w, WideChatWidth())
@ -238,19 +147,27 @@ void paintPreparedDate(
left += (w - dateTextWidth - st::msgServicePadding.left() - st::msgServicePadding.right()) / 2;
int height = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom();
ServiceMessagePainter::paintBubble(
ServiceMessagePainter::PaintBubble(
p,
left,
y + st::msgServiceMargin.top(),
dateTextWidth
+ st::msgServicePadding.left()
+ st::msgServicePadding.left(),
height,
bg);
bg,
corners,
QRect(
left,
y + st::msgServiceMargin.top(),
dateTextWidth
+ st::msgServicePadding.left()
+ st::msgServicePadding.left(),
height));
p.setFont(st::msgServiceFont);
p.setPen(fg);
p.drawText(left + st::msgServicePadding.left(), y + st::msgServiceMargin.top() + st::msgServicePadding.top() + st::msgServiceFont->ascent, dateText);
p.drawText(
left + st::msgServicePadding.left(),
(y
+ st::msgServiceMargin.top()
+ st::msgServicePadding.top()
+ st::msgServiceFont->ascent),
dateText);
}
bool NeedAboutGroup(not_null<History*> history) {
@ -268,88 +185,112 @@ int WideChatWidth() {
return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left();
}
void ServiceMessagePainter::paintDate(
void ServiceMessagePainter::PaintDate(
Painter &p,
not_null<const Ui::ChatStyle*> st,
const QDateTime &date,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
const auto dateText = langDayOfMonthFull(date.date());
const auto dateTextWidth = st::msgServiceFont->width(dateText);
paintPreparedDate(p, dateText, dateTextWidth, y, w, chatWide, bg, fg);
bool chatWide) {
PaintDate(
p,
st,
langDayOfMonthFull(date.date()),
y,
w,
chatWide);
}
void ServiceMessagePainter::paintDate(
void ServiceMessagePainter::PaintDate(
Painter &p,
not_null<const Ui::ChatStyle*> st,
const QString &dateText,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
paintPreparedDate(
bool chatWide) {
PaintDate(
p,
st,
dateText,
st::msgServiceFont->width(dateText),
y,
w,
chatWide,
bg,
fg);
chatWide);
}
void ServiceMessagePainter::paintDate(
void ServiceMessagePainter::PaintDate(
Painter &p,
not_null<const Ui::ChatStyle*> st,
const QString &dateText,
int dateTextWidth,
int y,
int w,
bool chatWide,
const style::color &bg,
const style::color &fg) {
paintPreparedDate(p, dateText, dateTextWidth, y, w, chatWide, bg, fg);
}
void ServiceMessagePainter::paintBubble(
Painter &p,
int x,
int y,
int w,
int h,
const style::color &bg) {
createCircleMasks();
paintBubblePart(
bool chatWide) {
PaintPreparedDate(
p,
x,
st->msgServiceBg(),
st->serviceBgCornersNormal(),
st->msgServiceFg(),
dateText,
dateTextWidth,
y,
w,
h,
SideStyle::Rounded,
SideStyle::Rounded,
bg);
chatWide);
}
void ServiceMessagePainter::paintComplexBubble(
void ServiceMessagePainter::PaintDate(
Painter &p,
const style::color &bg,
const Ui::CornersPixmaps &corners,
const style::color &fg,
const QString &dateText,
int dateTextWidth,
int y,
int w,
bool chatWide) {
PaintPreparedDate(
p,
bg,
corners,
fg,
dateText,
dateTextWidth,
y,
w,
chatWide);
}
void ServiceMessagePainter::PaintBubble(
Painter &p,
not_null<const Ui::ChatStyle*> st,
QRect rect) {
PaintBubble(p, st->msgServiceBg(), st->serviceBgCornersNormal(), rect);
}
void ServiceMessagePainter::PaintBubble(
Painter &p,
const style::color &bg,
const Ui::CornersPixmaps &corners,
QRect rect) {
Ui::FillRoundRect(p, rect, bg, corners);
}
void ServiceMessagePainter::PaintComplexBubble(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int left,
int width,
const Ui::Text::String &text,
const QRect &textRect,
const style::color &bg) {
createCircleMasks();
auto lineWidths = countLineWidths(text, textRect);
const QRect &textRect) {
const auto lineWidths = CountLineWidths(text, textRect);
int y = st::msgServiceMargin.top(), previousRichWidth = 0;
bool previousShrink = false, forceShrink = false;
SideStyle topStyle = SideStyle::Rounded, bottomStyle;
for (int i = 0, count = lineWidths.size(); i < count; ++i) {
auto lineWidth = lineWidths.at(i);
const auto lineWidth = lineWidths[i];
if (i + 1 < count) {
auto nextLineWidth = lineWidths.at(i + 1);
const auto nextLineWidth = lineWidths[i + 1];
if (nextLineWidth > lineWidth) {
bottomStyle = SideStyle::Inverted;
} else if (nextLineWidth < lineWidth) {
@ -374,15 +315,15 @@ void ServiceMessagePainter::paintComplexBubble(
richHeight -= st::msgServicePadding.top();
}
forceShrink = previousShrink && (richWidth == previousRichWidth);
paintBubblePart(
PaintBubblePart(
p,
st,
left + ((width - richWidth) / 2),
y,
richWidth,
richHeight,
topStyle,
bottomStyle,
bg,
forceShrink);
y += richHeight;
@ -399,38 +340,46 @@ void ServiceMessagePainter::paintComplexBubble(
}
}
QVector<int> ServiceMessagePainter::countLineWidths(const Ui::Text::String &text, const QRect &textRect) {
int linesCount = qMax(textRect.height() / st::msgServiceFont->height, 1);
QVector<int> lineWidths;
lineWidths.reserve(linesCount);
text.countLineWidths(textRect.width(), &lineWidths);
QVector<int> ServiceMessagePainter::CountLineWidths(
const Ui::Text::String &text,
const QRect &textRect) {
const auto linesCount = qMax(
textRect.height() / st::msgServiceFont->height,
1);
auto result = QVector<int>();
result.reserve(linesCount);
text.countLineWidths(textRect.width(), &result);
int minDelta = 2 * (historyServiceMsgRadius() + historyServiceMsgInvertedRadius() - historyServiceMsgInvertedShrink());
for (int i = 0, count = lineWidths.size(); i < count; ++i) {
int width = qMax(lineWidths.at(i), 0);
const auto minDelta = 2 * (Ui::HistoryServiceMsgRadius()
+ Ui::HistoryServiceMsgInvertedRadius()
- Ui::HistoryServiceMsgInvertedShrink());
for (int i = 0, count = result.size(); i != count; ++i) {
auto width = qMax(result[i], 0);
if (i > 0) {
int widthBefore = lineWidths.at(i - 1);
const auto widthBefore = result[i - 1];
if (width < widthBefore && width + minDelta > widthBefore) {
width = widthBefore;
}
}
if (i + 1 < count) {
int widthAfter = lineWidths.at(i + 1);
const auto widthAfter = result[i + 1];
if (width < widthAfter && width + minDelta > widthAfter) {
width = widthAfter;
}
}
if (width > lineWidths.at(i)) {
lineWidths[i] = width;
if (width > result[i]) {
result[i] = width;
if (i > 0) {
int widthBefore = lineWidths.at(i - 1);
if (widthBefore != width && widthBefore < width + minDelta && widthBefore + minDelta > width) {
int widthBefore = result[i - 1];
if (widthBefore != width
&& widthBefore < width + minDelta
&& widthBefore + minDelta > width) {
i -= 2;
}
}
}
}
return lineWidths;
return result;
}
Service::Service(
@ -527,7 +476,10 @@ void Service::draw(Painter &p, const PaintContext &context) const {
return;
}
auto height = this->height() - st::msgServiceMargin.top() - st::msgServiceMargin.bottom();
const auto st = context.st;
auto height = this->height()
- st::msgServiceMargin.top()
- st::msgServiceMargin.bottom();
auto dateh = 0;
auto unreadbarh = 0;
auto clip = context.clip;
@ -540,7 +492,12 @@ void Service::draw(Painter &p, const PaintContext &context) const {
if (const auto bar = Get<UnreadBar>()) {
unreadbarh = bar->height();
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
bar->paint(p, 0, width(), delegate()->elementIsChatWide());
bar->paint(
p,
context,
0,
width(),
delegate()->elementIsChatWide());
}
p.translate(0, unreadbarh);
clip.translate(0, -unreadbarh);
@ -554,9 +511,9 @@ void Service::draw(Painter &p, const PaintContext &context) const {
return;
}
paintHighlight(p, height);
paintHighlight(p, context, height);
p.setTextPalette(st::serviceTextPalette);
p.setTextPalette(st->serviceTextPalette());
if (auto media = this->media()) {
height -= st::msgServiceMargin.top() + media->height();
@ -568,10 +525,16 @@ void Service::draw(Painter &p, const PaintContext &context) const {
auto trect = QRect(g.left(), st::msgServiceMargin.top(), g.width(), height).marginsAdded(-st::msgServicePadding);
ServiceMessagePainter::paintComplexBubble(p, g.left(), g.width(), item->_text, trect);
ServiceMessagePainter::PaintComplexBubble(
p,
context.st,
g.left(),
g.width(),
item->_text,
trect);
p.setBrush(Qt::NoBrush);
p.setPen(st::msgServiceFg);
p.setPen(st->msgServiceFg());
p.setFont(st::msgServiceFont);
item->_text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignCenter, 0, -1, context.selection, false);
@ -694,7 +657,11 @@ void EmptyPainter::fillAboutGroup() {
}
}
void EmptyPainter::paint(Painter &p, int width, int height) {
void EmptyPainter::paint(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int width,
int height) {
if (_phrases.empty()) {
return;
}
@ -731,15 +698,14 @@ void EmptyPainter::paint(Painter &p, int width, int height) {
const auto bubbleLeft = (width - bubbleWidth) / 2;
const auto bubbleTop = (height - bubbleHeight) / 2;
ServiceMessagePainter::paintBubble(
ServiceMessagePainter::PaintBubble(
p,
bubbleLeft,
bubbleTop,
bubbleWidth,
bubbleHeight);
st->msgServiceBg(),
st->serviceBgCornersNormal(),
QRect(bubbleLeft, bubbleTop, bubbleWidth, bubbleHeight));
p.setPen(st::msgServiceFg);
p.setBrush(st::msgServiceFg);
p.setPen(st->msgServiceFg());
p.setBrush(st->msgServiceFg());
const auto left = bubbleLeft + padding.left();
auto top = bubbleTop + padding.top();
@ -762,7 +728,7 @@ void EmptyPainter::paint(Painter &p, int width, int height) {
top += textHeight(_text) + st::historyGroupAboutTextSkip;
for (const auto &text : _phrases) {
p.setPen(st::msgServiceFg);
p.setPen(st->msgServiceFg());
text.drawElided(
p,
left + st::historyGroupAboutBulletSkip,

View File

@ -11,6 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class HistoryService;
namespace Ui {
class ChatStyle;
struct CornersPixmaps;
} // namespace Ui
namespace HistoryView {
class Service : public Element {
@ -48,50 +53,61 @@ int WideChatWidth();
class ServiceMessagePainter {
public:
static void paintDate(
static void PaintDate(
Painter &p,
not_null<const Ui::ChatStyle*> st,
const QDateTime &date,
int y,
int w,
bool chatWide,
const style::color &bg = st::msgServiceBg,
const style::color &fg = st::msgServiceFg);
static void paintDate(
bool chatWide);
static void PaintDate(
Painter &p,
not_null<const Ui::ChatStyle*> st,
const QString &dateText,
int y,
int w,
bool chatWide,
const style::color &bg = st::msgServiceBg,
const style::color &fg = st::msgServiceFg);
static void paintDate(
bool chatWide);
static void PaintDate(
Painter &p,
not_null<const Ui::ChatStyle*> st,
const QString &dateText,
int dateTextWidth,
int y,
int w,
bool chatWide,
const style::color &bg = st::msgServiceBg,
const style::color &fg = st::msgServiceFg);
static void paintBubble(
bool chatWide);
static void PaintDate(
Painter &p,
int x,
const style::color &bg,
const Ui::CornersPixmaps &corners,
const style::color &fg,
const QString &dateText,
int dateTextWidth,
int y,
int w,
int h,
const style::color &bg = st::msgServiceBg);
bool chatWide);
static void paintComplexBubble(
static void PaintBubble(
Painter &p,
not_null<const Ui::ChatStyle*> st,
QRect rect);
static void PaintBubble(
Painter &p,
const style::color &bg,
const Ui::CornersPixmaps &corners,
QRect rect);
static void PaintComplexBubble(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int left,
int width,
const Ui::Text::String &text,
const QRect &textRect,
const style::color &bg = st::msgServiceBg);
const QRect &textRect);
private:
static QVector<int> countLineWidths(const Ui::Text::String &text, const QRect &textRect);
static QVector<int> CountLineWidths(
const Ui::Text::String &text,
const QRect &textRect);
};
@ -99,7 +115,11 @@ class EmptyPainter {
public:
explicit EmptyPainter(not_null<History*> history);
void paint(Painter &p, int width, int height);
void paint(
Painter &p,
not_null<const Ui::ChatStyle*> st,
int width,
int height);
private:
void fillAboutGroup();

View File

@ -86,7 +86,10 @@ public:
}
virtual void refreshParentId(not_null<HistoryItem*> realParent) {
}
virtual void drawHighlight(Painter &p, int top) const {
virtual void drawHighlight(
Painter &p,
const PaintContext &context,
int top) const {
}
virtual void draw(Painter &p, const PaintContext &context) const = 0;
[[nodiscard]] virtual PointState pointState(QPoint point) const;

View File

@ -270,7 +270,10 @@ QMargins GroupedMedia::groupedPadding() const {
(normal.bottom() - grouped.bottom()) + addToBottom);
}
void GroupedMedia::drawHighlight(Painter &p, int top) const {
void GroupedMedia::drawHighlight(
Painter &p,
const PaintContext &context,
int top) const {
if (_mode != Mode::Column) {
return;
}
@ -278,7 +281,12 @@ void GroupedMedia::drawHighlight(Painter &p, int top) const {
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
const auto &part = _parts[i];
const auto rect = part.geometry.translated(0, skip);
_parent->paintCustomHighlight(p, rect.y(), rect.height(), part.item);
_parent->paintCustomHighlight(
p,
context,
rect.y(),
rect.height(),
part.item);
}
}

View File

@ -31,7 +31,10 @@ public:
void refreshParentId(not_null<HistoryItem*> realParent) override;
void drawHighlight(Painter &p, int top) const override;
void drawHighlight(
Painter &p,
const PaintContext &context,
int top) const override;
void draw(Painter &p, const PaintContext &context) const override;
PointState pointState(QPoint point) const override;
TextState textState(

View File

@ -25,6 +25,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h"
#include "ui/widgets/popup_menu.h"
#include "ui/controls/delete_message_context_action.h"
#include "ui/chat/chat_style.h"
#include "ui/cached_round_corners.h"
#include "ui/ui_utility.h"
#include "ui/inactive_press.h"
#include "lang/lang_keys.h"
@ -94,6 +96,20 @@ struct ListWidget::Context {
DragSelectAction dragSelectAction;
};
struct ListWidget::DateBadge {
DateBadge(Type type, Fn<void()> checkCallback, Fn<void()> hideCallback);
SingleQueuedInvokation check;
base::Timer hideTimer;
Ui::Animations::Simple opacity;
Ui::CornersPixmaps corners;
bool goodType = false;
bool shown = false;
QString text;
int textWidth = 0;
QRect rect;
};
class ListWidget::Section {
public:
Section(Type type)
@ -228,6 +244,17 @@ ListWidget::CachedItem &ListWidget::CachedItem::operator=(
ListWidget::CachedItem::~CachedItem() = default;
ListWidget::DateBadge::DateBadge(
Type type,
Fn<void()> checkCallback,
Fn<void()> hideCallback)
: check(std::move(checkCallback))
, hideTimer(std::move(hideCallback))
, goodType(type == Type::Photo
|| type == Type::Video
|| type == Type::GIF) {
}
bool ListWidget::Section::addItem(not_null<BaseLayout*> item) {
if (_items.empty() || belongsHere(item)) {
if (_items.empty()) setHeader(item);
@ -664,13 +691,10 @@ ListWidget::ListWidget(
, _migrated(_controller->migrated())
, _type(_controller->section().mediaType())
, _slice(sliceKey(_universalAroundId))
, _dateBadge(DateBadge{
.check = SingleQueuedInvokation([=] { scrollDateCheck(); }),
.hideTimer = base::Timer([=] { scrollDateHide(); }),
.goodType = (_type == Type::Photo
|| _type == Type::Video
|| _type == Type::GIF),
}) {
, _dateBadge(std::make_unique<DateBadge>(
_type,
[=] { scrollDateCheck(); },
[=] { scrollDateHide(); })) {
setMouseTracking(true);
start();
}
@ -1204,16 +1228,16 @@ void ListWidget::visibleTopBottomUpdated(
checkMoveToOtherViewer();
clearHeavyItems();
if (_dateBadge.goodType) {
if (_dateBadge->goodType) {
updateDateBadgeFor(_visibleTop);
if (!_visibleTop) {
if (_dateBadge.shown) {
if (_dateBadge->shown) {
scrollDateHide();
} else {
update(_dateBadge.rect);
update(_dateBadge->rect);
}
} else {
_dateBadge.check.call();
_dateBadge->check.call();
}
}
}
@ -1228,29 +1252,30 @@ void ListWidget::updateDateBadgeFor(int top) {
+ st::msgServiceFont->height
+ st::msgServicePadding.bottom();
_dateBadge.text = ItemDateText(layout->getItem(), false);
_dateBadge.rect = QRect(0, top, width(), rectHeight);
_dateBadge->text = ItemDateText(layout->getItem(), false);
_dateBadge->textWidth = st::msgServiceFont->width(_dateBadge->text);
_dateBadge->rect = QRect(0, top, width(), rectHeight);
}
void ListWidget::scrollDateCheck() {
if (!_dateBadge.shown) {
if (!_dateBadge->shown) {
toggleScrollDateShown();
}
_dateBadge.hideTimer.callOnce(st::infoScrollDateHideTimeout);
_dateBadge->hideTimer.callOnce(st::infoScrollDateHideTimeout);
}
void ListWidget::scrollDateHide() {
if (_dateBadge.shown) {
if (_dateBadge->shown) {
toggleScrollDateShown();
}
}
void ListWidget::toggleScrollDateShown() {
_dateBadge.shown = !_dateBadge.shown;
_dateBadge.opacity.start(
[=] { update(_dateBadge.rect); },
_dateBadge.shown ? 0. : 1.,
_dateBadge.shown ? 1. : 0.,
_dateBadge->shown = !_dateBadge->shown;
_dateBadge->opacity.start(
[=] { update(_dateBadge->rect); },
_dateBadge->shown ? 0. : 1.,
_dateBadge->shown ? 1. : 0.,
st::infoDateFadeDuration);
}
@ -1403,19 +1428,27 @@ void ListWidget::paintEvent(QPaintEvent *e) {
fromSectionIt->paintFloatingHeader(p, _visibleTop, outerWidth);
}
if (_dateBadge.goodType && clip.intersects(_dateBadge.rect)) {
if (_dateBadge->goodType && clip.intersects(_dateBadge->rect)) {
const auto scrollDateOpacity =
_dateBadge.opacity.value(_dateBadge.shown ? 1. : 0.);
_dateBadge->opacity.value(_dateBadge->shown ? 1. : 0.);
if (scrollDateOpacity > 0.) {
p.setOpacity(scrollDateOpacity);
HistoryView::ServiceMessagePainter::paintDate(
if (_dateBadge->corners.p[0].isNull()) {
_dateBadge->corners = Ui::PrepareCornerPixmaps(
Ui::HistoryServiceMsgRadius(),
st::roundedBg,
nullptr);
}
HistoryView::ServiceMessagePainter::PaintDate(
p,
_dateBadge.text,
st::roundedBg,
_dateBadge->corners,
st::roundedFg,
_dateBadge->text,
_dateBadge->textWidth,
_visibleTop,
outerWidth,
false,
st::roundedBg,
st::roundedFg);
false);
}
}
}

View File

@ -90,6 +90,7 @@ public:
private:
struct Context;
struct DateBadge;
class Section;
using CursorState = HistoryView::CursorState;
using TextState = HistoryView::TextState;
@ -331,15 +332,7 @@ private:
DragSelectAction _dragSelectAction = DragSelectAction::None;
bool _wasSelectedText = false; // was some text selected in current drag action
struct DateBadge {
SingleQueuedInvokation check;
base::Timer hideTimer;
Ui::Animations::Simple opacity;
bool goodType = false;
bool shown = false;
QString text;
QRect rect;
} _dateBadge;
const std::unique_ptr<DateBadge> _dateBadge;
base::unique_qptr<Ui::PopupMenu> _contextMenu;
rpl::event_stream<> _checkForHide;

View File

@ -95,9 +95,6 @@ void CreatePaletteCorners() {
PrepareCorners(Doc4Corners, st::roundRadiusSmall, st::msgFile4Bg);
PrepareCorners(MessageInCorners, st::historyMessageRadius, st::msgInBg, &st::msgInShadow);
PrepareCorners(MessageInSelectedCorners, st::historyMessageRadius, st::msgInBgSelected, &st::msgInShadowSelected);
PrepareCorners(MessageOutCorners, st::historyMessageRadius, st::msgOutBg, &st::msgOutShadow);
PrepareCorners(MessageOutSelectedCorners, st::historyMessageRadius, st::msgOutBgSelected, &st::msgOutShadowSelected);
}
} // namespace

View File

@ -43,9 +43,6 @@ enum CachedRoundCorners : int {
InSelectedShadowCorners,
MessageInCorners, // with shadow
MessageInSelectedCorners,
MessageOutCorners,
MessageOutSelectedCorners,
RoundCornersCount
};

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/chat_style.h"
#include "ui/chat/chat_theme.h"
#include "ui/ui_utility.h"
#include "styles/style_chat.h"
#include "styles/style_dialogs.h"
@ -30,10 +31,36 @@ not_null<const MessageStyle*> ChatPaintContext::messageStyle() const {
return &st->messageStyle(outbg, selected());
}
int HistoryServiceMsgRadius() {
static const auto result = [] {
const auto minMessageHeight = st::msgServicePadding.top()
+ st::msgServiceFont->height
+ st::msgServicePadding.bottom();
return minMessageHeight / 2;
}();
return result;
}
int HistoryServiceMsgInvertedRadius() {
static const auto result = [] {
const auto minRowHeight = st::msgServiceFont->height;
return minRowHeight - HistoryServiceMsgRadius();
}();
return result;
}
int HistoryServiceMsgInvertedShrink() {
static const auto result = [] {
return (HistoryServiceMsgInvertedRadius() * 2) / 3;
}();
return result;
}
ChatStyle::ChatStyle() {
finalize();
make(_historyPsaForwardPalette, st::historyPsaForwardPalette);
make(_imgReplyTextPalette, st::imgReplyTextPalette);
make(_serviceTextPalette, st::serviceTextPalette);
make(_historyRepliesInvertedIcon, st::historyRepliesInvertedIcon);
make(_historyViewsInvertedIcon, st::historyViewsInvertedIcon);
make(_historyViewsSendingIcon, st::historyViewsSendingIcon);
@ -212,9 +239,41 @@ void ChatStyle::assignPalette(not_null<const style::palette*> palette) {
for (auto &style : _messageStyles) {
style.corners = {};
}
_serviceBgCornersNormal = {};
_serviceBgCornersInverted = {};
_msgServiceBgCorners = {};
_msgServiceBgSelectedCorners = {};
_msgBotKbOverBgAddCorners = {};
_msgDateImgBgCorners = {};
_msgDateImgBgSelectedCorners = {};
}
const CornersPixmaps &ChatStyle::serviceBgCornersNormal() const {
EnsureCorners(
_serviceBgCornersNormal,
HistoryServiceMsgRadius(),
msgServiceBg());
return _serviceBgCornersNormal;
}
const CornersPixmaps &ChatStyle::serviceBgCornersInverted() const {
if (_serviceBgCornersInverted.p[0].isNull()) {
const auto radius = HistoryServiceMsgInvertedRadius();
const auto size = radius * style::DevicePixelRatio();
auto circle = style::colorizeImage(
style::createInvertedCircleMask(radius * 2),
msgServiceBg());
circle.setDevicePixelRatio(style::DevicePixelRatio());
const auto fill = [&](int index, int xoffset, int yoffset) {
_serviceBgCornersInverted.p[index] = PixmapFromImage(
circle.copy(QRect(xoffset, yoffset, size, size)));
};
fill(0, 0, 0);
fill(1, size, 0);
fill(2, size, size);
fill(3, 0, size);
}
return _serviceBgCornersInverted;
}
const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const {

View File

@ -83,12 +83,19 @@ struct ChatPaintContext {
};
[[nodiscard]] int HistoryServiceMsgRadius();
[[nodiscard]] int HistoryServiceMsgInvertedRadius();
[[nodiscard]] int HistoryServiceMsgInvertedShrink();
class ChatStyle final : public style::palette {
public:
ChatStyle();
void apply(not_null<ChatTheme*> theme);
[[nodiscard]] const CornersPixmaps &serviceBgCornersNormal() const;
[[nodiscard]] const CornersPixmaps &serviceBgCornersInverted() const;
[[nodiscard]] const MessageStyle &messageStyle(
bool outbg,
bool selected) const;
@ -105,6 +112,9 @@ public:
[[nodiscard]] const style::TextPalette &imgReplyTextPalette() const {
return _imgReplyTextPalette;
}
[[nodiscard]] const style::TextPalette &serviceTextPalette() const {
return _serviceTextPalette;
}
[[nodiscard]] const style::icon &historyRepliesInvertedIcon() const {
return _historyRepliesInvertedIcon;
}
@ -174,6 +184,9 @@ private:
const Type &originalOut,
const Type &originalOutSelected);
mutable CornersPixmaps _serviceBgCornersNormal;
mutable CornersPixmaps _serviceBgCornersInverted;
mutable std::array<MessageStyle, 4> _messageStyles;
mutable CornersPixmaps _msgServiceBgCorners;
@ -184,6 +197,7 @@ private:
style::TextPalette _historyPsaForwardPalette;
style::TextPalette _imgReplyTextPalette;
style::TextPalette _serviceTextPalette;
style::icon _historyRepliesInvertedIcon = { Qt::Uninitialized };
style::icon _historyViewsInvertedIcon = { Qt::Uninitialized };
style::icon _historyViewsSendingIcon = { Qt::Uninitialized };

View File

@ -416,6 +416,9 @@ public:
};
[[nodiscard]] Ui::ChatPaintContext preparePaintContext(
PaintContextArgs &&args);
[[nodiscard]] not_null<const Ui::ChatStyle*> chatStyle() const {
return _chatStyle.get();
}
rpl::lifetime &lifetime() {
return _lifetime;
@ -486,7 +489,7 @@ private:
std::shared_ptr<Ui::ChatTheme> _defaultChatTheme;
base::flat_map<uint64, CachedTheme> _customChatThemes;
rpl::event_stream<std::shared_ptr<Ui::ChatTheme>> _cachedThemesStream;
std::unique_ptr<Ui::ChatStyle> _chatStyle;
const std::unique_ptr<Ui::ChatStyle> _chatStyle;
std::weak_ptr<Ui::ChatTheme> _chatStyleTheme;
rpl::lifetime _lifetime;