mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 07:37:11 +02:00
Support two-color quote outlines.
This commit is contained in:
parent
8c28ce4c99
commit
4709e11e46
18 changed files with 290 additions and 142 deletions
|
@ -682,15 +682,19 @@ void HistoryMessageReply::paint(
|
|||
const auto hasQuote = !_fields.quote.empty();
|
||||
const auto selected = context.selected();
|
||||
const auto colorIndexPlusOne = context.outbg ? 0 : _colorIndexPlusOne;
|
||||
const auto twoColored = colorIndexPlusOne
|
||||
&& Ui::ColorIndexTwoColored(colorIndexPlusOne - 1);
|
||||
const auto cache = !inBubble
|
||||
? (hasQuote
|
||||
? st->serviceQuoteCache()
|
||||
: st->serviceReplyCache()).get()
|
||||
? st->serviceQuoteCache(twoColored)
|
||||
: st->serviceReplyCache(twoColored)).get()
|
||||
: colorIndexPlusOne
|
||||
? (hasQuote
|
||||
? st->coloredQuoteCache(selected, colorIndexPlusOne - 1)
|
||||
: st->coloredReplyCache(selected, colorIndexPlusOne - 1)).get()
|
||||
: (hasQuote ? stm->quoteCache : stm->replyCache).get();
|
||||
: (hasQuote
|
||||
? (twoColored ? stm->quoteCacheTwo : stm->quoteCache)
|
||||
: (twoColored ? stm->replyCacheTwo : stm->replyCache)).get();
|
||||
const auto "eSt = hasQuote
|
||||
? st::messageTextStyle.blockquote
|
||||
: st::messageQuoteStyle;
|
||||
|
@ -763,12 +767,10 @@ void HistoryMessageReply::paint(
|
|||
if (w > textLeft + st::historyReplyPadding.right()) {
|
||||
w -= textLeft + st::historyReplyPadding.right();
|
||||
p.setPen(!inBubble
|
||||
? st->msgImgReplyBarColor()
|
||||
? st->msgImgReplyBarColor()->c
|
||||
: colorIndexPlusOne
|
||||
? HistoryView::FromNameFg(
|
||||
context,
|
||||
colorIndexPlusOne - 1)
|
||||
: stm->msgServiceFg);
|
||||
? FromNameFg(context, colorIndexPlusOne - 1)
|
||||
: stm->msgServiceFg->c);
|
||||
_name.drawLeftElided(p, x + textLeft, y + st::historyReplyPadding.top(), w, w + 2 * x + 2 * textLeft);
|
||||
if (originalVia && w > _name.maxWidth() + st::msgServiceFont->spacew) {
|
||||
p.setFont(st::msgServiceFont);
|
||||
|
@ -802,7 +804,7 @@ void HistoryMessageReply::paint(
|
|||
auto copy = std::optional<style::TextPalette>();
|
||||
if (inBubble && _colorIndexPlusOne) {
|
||||
copy.emplace(*replyToTextPalette);
|
||||
owned.emplace(cache->outline);
|
||||
owned.emplace(cache->icon);
|
||||
copy->linkFg = owned->color();
|
||||
replyToTextPalette = &*copy;
|
||||
}
|
||||
|
@ -821,7 +823,7 @@ void HistoryMessageReply::paint(
|
|||
}
|
||||
} else {
|
||||
p.setFont(st::msgDateFont);
|
||||
p.setPen(cache->outline);
|
||||
p.setPen(cache->icon);
|
||||
p.drawTextLeft(
|
||||
x + textLeft,
|
||||
(y + (_height - st::msgDateFont->height) / 2),
|
||||
|
|
|
@ -467,6 +467,7 @@ Element::Element(
|
|||
| (IsItemScheduledUntilOnline(data)
|
||||
? Flag::ScheduledUntilOnline
|
||||
: Flag()))
|
||||
, _colorIndex(data->computeColorIndex())
|
||||
, _context(delegate->elementContext()) {
|
||||
history()->owner().registerItemView(this);
|
||||
refreshMedia(replacing);
|
||||
|
@ -490,6 +491,10 @@ not_null<History*> Element::history() const {
|
|||
return _data->history();
|
||||
}
|
||||
|
||||
uint8 Element::colorIndex() const {
|
||||
return _colorIndex;
|
||||
}
|
||||
|
||||
QDateTime Element::dateTime() const {
|
||||
return _dateTime;
|
||||
}
|
||||
|
@ -557,8 +562,8 @@ void Element::prepareCustomEmojiPaint(
|
|||
}
|
||||
clearCustomEmojiRepaint();
|
||||
p.setInactive(context.paused);
|
||||
if (!_heavyCustomEmoji) {
|
||||
_heavyCustomEmoji = true;
|
||||
if (!(_flags & Flag::HeavyCustomEmoji)) {
|
||||
_flags |= Flag::HeavyCustomEmoji;
|
||||
history()->owner().registerHeavyViewPart(const_cast<Element*>(this));
|
||||
}
|
||||
}
|
||||
|
@ -572,8 +577,8 @@ void Element::prepareCustomEmojiPaint(
|
|||
}
|
||||
clearCustomEmojiRepaint();
|
||||
p.setInactive(context.paused);
|
||||
if (!_heavyCustomEmoji) {
|
||||
_heavyCustomEmoji = true;
|
||||
if (!(_flags & Flag::HeavyCustomEmoji)) {
|
||||
_flags |= Flag::HeavyCustomEmoji;
|
||||
history()->owner().registerHeavyViewPart(const_cast<Element*>(this));
|
||||
}
|
||||
}
|
||||
|
@ -1411,7 +1416,7 @@ auto Element::verticalRepaintRange() const -> VerticalRepaintRange {
|
|||
}
|
||||
|
||||
bool Element::hasHeavyPart() const {
|
||||
return _heavyCustomEmoji;
|
||||
return (_flags & Flag::HeavyCustomEmoji);
|
||||
}
|
||||
|
||||
void Element::checkHeavyPart() {
|
||||
|
@ -1445,8 +1450,8 @@ void Element::unloadHeavyPart() {
|
|||
if (_media) {
|
||||
_media->unloadHeavyPart();
|
||||
}
|
||||
if (_heavyCustomEmoji) {
|
||||
_heavyCustomEmoji = false;
|
||||
if (_flags & Flag::HeavyCustomEmoji) {
|
||||
_flags &= ~Flag::HeavyCustomEmoji;
|
||||
_text.unloadPersistentAnimation();
|
||||
if (const auto reply = data()->Get<HistoryMessageReply>()) {
|
||||
reply->unloadPersistentAnimation();
|
||||
|
@ -1623,8 +1628,8 @@ Element::~Element() {
|
|||
// Delete media while owner still exists.
|
||||
clearSpecialOnlyEmoji();
|
||||
base::take(_media);
|
||||
if (_heavyCustomEmoji) {
|
||||
_heavyCustomEmoji = false;
|
||||
if (_flags & Flag::HeavyCustomEmoji) {
|
||||
_flags &= ~Flag::HeavyCustomEmoji;
|
||||
_text.unloadPersistentAnimation();
|
||||
checkHeavyPart();
|
||||
}
|
||||
|
|
|
@ -277,18 +277,19 @@ class Element
|
|||
, public base::has_weak_ptr {
|
||||
public:
|
||||
enum class Flag : uint16 {
|
||||
ServiceMessage = 0x0001,
|
||||
NeedsResize = 0x0002,
|
||||
AttachedToPrevious = 0x0004,
|
||||
AttachedToNext = 0x0008,
|
||||
ServiceMessage = 0x0001,
|
||||
NeedsResize = 0x0002,
|
||||
AttachedToPrevious = 0x0004,
|
||||
AttachedToNext = 0x0008,
|
||||
BubbleAttachedToPrevious = 0x0010,
|
||||
BubbleAttachedToNext = 0x0020,
|
||||
HiddenByGroup = 0x0040,
|
||||
SpecialOnlyEmoji = 0x0080,
|
||||
CustomEmojiRepainting = 0x0100,
|
||||
ScheduledUntilOnline = 0x0200,
|
||||
TopicRootReply = 0x0400,
|
||||
MediaOverriden = 0x0800,
|
||||
BubbleAttachedToNext = 0x0020,
|
||||
HiddenByGroup = 0x0040,
|
||||
SpecialOnlyEmoji = 0x0080,
|
||||
CustomEmojiRepainting = 0x0100,
|
||||
ScheduledUntilOnline = 0x0200,
|
||||
TopicRootReply = 0x0400,
|
||||
MediaOverriden = 0x0800,
|
||||
HeavyCustomEmoji = 0x1000,
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
@ -306,6 +307,7 @@ public:
|
|||
[[nodiscard]] Context context() const;
|
||||
void refreshDataId();
|
||||
|
||||
[[nodiscard]] uint8 colorIndex() const;
|
||||
[[nodiscard]] QDateTime dateTime() const;
|
||||
|
||||
[[nodiscard]] int y() const;
|
||||
|
@ -592,9 +594,11 @@ private:
|
|||
int _indexInBlock = -1;
|
||||
|
||||
mutable Flags _flags = Flag(0);
|
||||
mutable bool _heavyCustomEmoji = false;
|
||||
uint8 _colorIndex = 0;
|
||||
Context _context = Context();
|
||||
|
||||
};
|
||||
|
||||
constexpr auto size = sizeof(Element);
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -366,12 +366,6 @@ QString FastReplyText() {
|
|||
|
||||
} // namespace
|
||||
|
||||
style::color FromNameFg(
|
||||
const Ui::ChatPaintContext &context,
|
||||
uint8 colorIndex) {
|
||||
return Ui::FromNameFg(context.st, context.selected(), colorIndex);
|
||||
}
|
||||
|
||||
struct Message::CommentsButton {
|
||||
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||
std::vector<UserpicInRow> userpics;
|
||||
|
@ -1358,8 +1352,8 @@ void Message::paintFromName(
|
|||
Assert(from || info);
|
||||
const auto st = context.st;
|
||||
const auto nameFg = !context.outbg
|
||||
? FromNameFg(context, from ? from->colorIndex() : info->colorIndex)
|
||||
: stm->msgServiceFg;
|
||||
? FromNameFg(context, colorIndex())
|
||||
: stm->msgServiceFg->c;
|
||||
const auto nameText = [&] {
|
||||
if (from) {
|
||||
validateFromNameText(from);
|
||||
|
@ -1374,11 +1368,8 @@ void Message::paintFromName(
|
|||
const auto x = availableLeft
|
||||
+ std::min(availableWidth - statusWidth, nameText->maxWidth());
|
||||
const auto y = trect.top();
|
||||
const auto color = QColor(
|
||||
nameFg->c.red(),
|
||||
nameFg->c.green(),
|
||||
nameFg->c.blue(),
|
||||
nameFg->c.alpha() * 115 / 255);
|
||||
auto color = nameFg;
|
||||
color.setAlpha(115);
|
||||
const auto user = from->asUser();
|
||||
const auto id = user ? user->emojiStatusId() : 0;
|
||||
if (_fromNameStatus->id != id) {
|
||||
|
@ -1630,7 +1621,7 @@ void Message::paintText(
|
|||
.availableWidth = trect.width(),
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = stm->quoteCache.get(),
|
||||
.blockquote = context.quoteCache(colorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
|
@ -3064,14 +3055,13 @@ void Message::updateViewButtonExistence() {
|
|||
} else if (_viewButton) {
|
||||
return;
|
||||
}
|
||||
auto repainter = [=] { repaint(); };
|
||||
const auto index = item->computeColorIndex();
|
||||
_viewButton = sponsored
|
||||
? std::make_unique<ViewButton>(
|
||||
sponsored,
|
||||
index,
|
||||
std::move(repainter))
|
||||
: std::make_unique<ViewButton>(media, index, std::move(repainter));
|
||||
auto make = [=](auto &&from) {
|
||||
return std::make_unique<ViewButton>(
|
||||
std::forward<decltype(from)>(from),
|
||||
colorIndex(),
|
||||
[=] { repaint(); });
|
||||
};
|
||||
_viewButton = sponsored ? make(sponsored) : make(media);
|
||||
}
|
||||
|
||||
void Message::initLogEntryOriginal() {
|
||||
|
|
|
@ -56,10 +56,6 @@ struct BottomRippleMask {
|
|||
int shift = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] style::color FromNameFg(
|
||||
const Ui::ChatPaintContext &context,
|
||||
uint8 colorIndex);
|
||||
|
||||
class Message final : public Element {
|
||||
public:
|
||||
Message(
|
||||
|
|
|
@ -235,8 +235,9 @@ void ViewButton::draw(
|
|||
const auto stm = context.messageStyle();
|
||||
|
||||
const auto selected = context.selected();
|
||||
const auto twoColored = Ui::ColorIndexTwoColored(_inner->colorIndex);
|
||||
const auto cache = context.outbg
|
||||
? stm->replyCache.get()
|
||||
? (twoColored ? stm->replyCacheTwo : stm->replyCache).get()
|
||||
: context.st->coloredReplyCache(selected, _inner->colorIndex).get();
|
||||
const auto radius = st::historyPagePreview.radius;
|
||||
|
||||
|
@ -249,7 +250,7 @@ void ViewButton::draw(
|
|||
p.setBrush(cache->bg);
|
||||
p.drawRoundedRect(r, radius, radius);
|
||||
|
||||
p.setPen(cache->outline);
|
||||
p.setPen(cache->icon);
|
||||
_inner->text.drawElided(
|
||||
p,
|
||||
r.left(),
|
||||
|
@ -266,7 +267,7 @@ void ViewButton::draw(
|
|||
r.left() + r.width() - icon.width() - padding,
|
||||
r.top() + padding,
|
||||
r.width(),
|
||||
cache->outline);
|
||||
cache->icon);
|
||||
}
|
||||
if (_inner->lastWidth != r.width()) {
|
||||
_inner->lastWidth = r.width();
|
||||
|
|
|
@ -749,7 +749,7 @@ void Document::draw(
|
|||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = stm->quoteCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->colorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
|
|
|
@ -236,7 +236,7 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
|
|||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = stm->quoteCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->colorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
|
|
|
@ -220,15 +220,16 @@ void Game::draw(Painter &p, const PaintContext &context) const {
|
|||
auto paintw = inner.width();
|
||||
|
||||
const auto selected = context.selected();
|
||||
const auto twoColored = Ui::ColorIndexTwoColored(_colorIndex);
|
||||
const auto cache = context.outbg
|
||||
? stm->replyCache.get()
|
||||
? (twoColored ? stm->replyCacheTwo : stm->replyCache).get()
|
||||
: st->coloredReplyCache(selected, _colorIndex).get();
|
||||
Ui::Text::ValidateQuotePaintCache(*cache, _st);
|
||||
Ui::Text::FillQuotePaint(p, outer, *cache, _st);
|
||||
|
||||
auto lineHeight = UnitedLineHeight();
|
||||
if (_titleLines) {
|
||||
p.setPen(cache->outline);
|
||||
p.setPen(cache->icon);
|
||||
p.setTextPalette(context.outbg
|
||||
? stm->semiboldPalette
|
||||
: st->coloredTextPalette(selected, _colorIndex));
|
||||
|
|
|
@ -721,7 +721,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
|
|||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = stm->quoteCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->colorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
|
|
|
@ -347,8 +347,9 @@ void Giveaway::paintChannels(
|
|||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto stm = context.messageStyle();
|
||||
const auto selected = context.selected();
|
||||
const auto twoColored = Ui::ColorIndexTwoColored(_colorIndex);
|
||||
const auto cache = context.outbg
|
||||
? stm->replyCache.get()
|
||||
? (twoColored ? stm->replyCacheTwo : stm->replyCache).get()
|
||||
: context.st->coloredReplyCache(selected, _colorIndex).get();
|
||||
if (_channelCorners[0].isNull() || _channelBg != cache->bg) {
|
||||
_channelBg = cache->bg;
|
||||
|
@ -357,7 +358,7 @@ void Giveaway::paintChannels(
|
|||
style::colorizeImage(image, cache->bg, &image);
|
||||
}
|
||||
}
|
||||
p.setPen(cache->outline);
|
||||
p.setPen(cache->icon);
|
||||
const auto padding = st::chatGiveawayChannelPadding;
|
||||
for (const auto &channel : _channels) {
|
||||
const auto &thumbnail = channel.thumbnail;
|
||||
|
|
|
@ -368,7 +368,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
|
|||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = stm->quoteCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->colorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
|
|
|
@ -406,7 +406,7 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
|
|||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = stm->quoteCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->colorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
|
|
|
@ -546,8 +546,9 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
|
|||
auto attachAdditionalInfoText = _attach ? _attach->additionalInfoString() : QString();
|
||||
|
||||
const auto selected = context.selected();
|
||||
const auto twoColored = Ui::ColorIndexTwoColored(_colorIndex);
|
||||
const auto cache = context.outbg
|
||||
? stm->replyCache.get()
|
||||
? (twoColored ? stm->replyCacheTwo : stm->replyCache).get()
|
||||
: st->coloredReplyCache(selected, _colorIndex).get();
|
||||
Ui::Text::ValidateQuotePaintCache(*cache, _st);
|
||||
Ui::Text::FillQuotePaint(p, outer, *cache, _st);
|
||||
|
@ -601,7 +602,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
|
|||
paintw -= pw + st::webPagePhotoDelta;
|
||||
}
|
||||
if (_siteNameLines) {
|
||||
p.setPen(cache->outline);
|
||||
p.setPen(cache->icon);
|
||||
p.setTextPalette(context.outbg
|
||||
? stm->semiboldPalette
|
||||
: st->coloredTextPalette(selected, _colorIndex));
|
||||
|
@ -703,10 +704,10 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
|
|||
|
||||
if (_openButtonWidth) {
|
||||
p.setFont(st::semiboldFont);
|
||||
p.setPen(cache->outline);
|
||||
p.setPen(cache->icon);
|
||||
const auto end = inner.y() + inner.height() + _st.padding.bottom();
|
||||
const auto line = st::historyPageButtonLine;
|
||||
auto color = cache->outline;
|
||||
auto color = cache->icon;
|
||||
color.setAlphaF(color.alphaF() * 0.3);
|
||||
p.fillRect(inner.x(), end, inner.width(), line, color);
|
||||
const auto top = end + st::historyPageButtonPadding.top();
|
||||
|
|
|
@ -31,16 +31,16 @@ void EnsureCorners(
|
|||
|
||||
void EnsureBlockquoteCache(
|
||||
std::unique_ptr<Text::QuotePaintCache> &cache,
|
||||
const style::color &color) {
|
||||
Fn<ColorIndexValues()> values) {
|
||||
if (cache) {
|
||||
return;
|
||||
}
|
||||
cache = std::make_unique<Text::QuotePaintCache>();
|
||||
cache->bg = color->c;
|
||||
cache->bg.setAlphaF(0.12);
|
||||
cache->outline = color->c;
|
||||
cache->outline.setAlphaF(0.9);
|
||||
cache->icon = cache->outline;
|
||||
const auto &colors = values();
|
||||
cache->bg = colors.bg;
|
||||
cache->outline1 = colors.outline1;
|
||||
cache->outline2 = colors.outline2;
|
||||
cache->icon = colors.name;
|
||||
}
|
||||
|
||||
void EnsurePreCache(
|
||||
|
@ -56,11 +56,12 @@ void EnsurePreCache(
|
|||
if (!bg) {
|
||||
cache->bg.setAlphaF(0.12);
|
||||
}
|
||||
cache->outline = color->c;
|
||||
cache->outline.setAlphaF(0.9);
|
||||
cache->outline1 = color->c;
|
||||
cache->outline1.setAlphaF(0.9);
|
||||
cache->outline2 = cache->outline1;
|
||||
cache->header = color->c;
|
||||
cache->header.setAlphaF(0.25);
|
||||
cache->icon = cache->outline;
|
||||
cache->icon = cache->outline1;
|
||||
cache->icon.setAlphaF(0.6);
|
||||
}
|
||||
|
||||
|
@ -74,6 +75,15 @@ not_null<const MessageImageStyle*> ChatPaintContext::imageStyle() const {
|
|||
return &st->imageStyle(selected());
|
||||
}
|
||||
|
||||
not_null<Text::QuotePaintCache*> ChatPaintContext::quoteCache(
|
||||
uint8 colorIndex) const {
|
||||
return !outbg
|
||||
? st->coloredQuoteCache(selected(), colorIndex).get()
|
||||
: ColorIndexTwoColored(colorIndex)
|
||||
? messageStyle()->quoteCacheTwo.get()
|
||||
: messageStyle()->quoteCache.get();
|
||||
}
|
||||
|
||||
int HistoryServiceMsgRadius() {
|
||||
static const auto result = [] {
|
||||
const auto minMessageHeight = st::msgServicePadding.top()
|
||||
|
@ -99,6 +109,87 @@ int HistoryServiceMsgInvertedShrink() {
|
|||
return result;
|
||||
}
|
||||
|
||||
ColorIndexValues ComputeColorIndexValues(
|
||||
not_null<const ChatStyle*> st,
|
||||
bool selected,
|
||||
uint8 colorIndex) {
|
||||
if (colorIndex < kSimpleColorIndexCount) {
|
||||
const style::color list[] = {
|
||||
st->historyPeer1NameFg(),
|
||||
st->historyPeer2NameFg(),
|
||||
st->historyPeer3NameFg(),
|
||||
st->historyPeer4NameFg(),
|
||||
st->historyPeer5NameFg(),
|
||||
st->historyPeer6NameFg(),
|
||||
st->historyPeer7NameFg(),
|
||||
st->historyPeer8NameFg(),
|
||||
};
|
||||
const style::color listSelected[] = {
|
||||
st->historyPeer1NameFgSelected(),
|
||||
st->historyPeer2NameFgSelected(),
|
||||
st->historyPeer3NameFgSelected(),
|
||||
st->historyPeer4NameFgSelected(),
|
||||
st->historyPeer5NameFgSelected(),
|
||||
st->historyPeer6NameFgSelected(),
|
||||
st->historyPeer7NameFgSelected(),
|
||||
st->historyPeer8NameFgSelected(),
|
||||
};
|
||||
const auto paletteIndex = ColorIndexToPaletteIndex(colorIndex);
|
||||
auto result = ColorIndexValues{
|
||||
.name = (selected ? listSelected : list)[paletteIndex]->c,
|
||||
};
|
||||
result.bg = result.name;
|
||||
result.bg.setAlphaF(0.12);
|
||||
result.outline1 = result.name;
|
||||
result.outline1.setAlphaF(0.9);
|
||||
result.outline2 = result.outline1;
|
||||
return result;
|
||||
}
|
||||
struct Pair {
|
||||
QColor outline1;
|
||||
QColor outline2;
|
||||
};
|
||||
const Pair list[] = {
|
||||
{ QColor(0xE1, 0x50, 0x52), QColor(0xF9, 0xAE, 0x63) }, // Red
|
||||
{ QColor(0xE0, 0x80, 0x2B), QColor(0xFA, 0xC5, 0x34) }, // Orange
|
||||
{ QColor(0xA0, 0x5F, 0xF3), QColor(0xF4, 0x8F, 0xFF) }, // Violet
|
||||
{ QColor(0x27, 0xA9, 0x10), QColor(0xA7, 0xDC, 0x57) }, // Green
|
||||
{ QColor(0x27, 0xAC, 0xCE), QColor(0x82, 0xE8, 0xD6) }, // Cyan
|
||||
{ QColor(0x33, 0x91, 0xD4), QColor(0x7D, 0xD3, 0xF0) }, // Blue
|
||||
{ QColor(0xD1, 0x48, 0x72), QColor(0xFF, 0xBE, 0xA0) }, // Pink
|
||||
};
|
||||
const auto &pair = list[colorIndex - kSimpleColorIndexCount];
|
||||
auto bg = pair.outline1;
|
||||
bg.setAlphaF(0.12);
|
||||
return {
|
||||
.name = st->dark() ? pair.outline2 : pair.outline1,
|
||||
.bg = bg,
|
||||
.outline1 = pair.outline1,
|
||||
.outline2 = pair.outline2,
|
||||
};
|
||||
}
|
||||
|
||||
bool ColorIndexTwoColored(uint8 colorIndex) {
|
||||
return (colorIndex >= kSimpleColorIndexCount);
|
||||
}
|
||||
|
||||
ColorIndexValues SimpleColorIndexValues(QColor color, bool twoColored) {
|
||||
auto bg = color;
|
||||
bg.setAlphaF(0.12);
|
||||
auto outline1 = color;
|
||||
outline1.setAlphaF(0.9);
|
||||
auto outline2 = outline1;
|
||||
if (twoColored) {
|
||||
outline2.setAlphaF(0.3);
|
||||
}
|
||||
return {
|
||||
.name = color,
|
||||
.bg = bg,
|
||||
.outline1 = outline1,
|
||||
.outline2 = outline2,
|
||||
};
|
||||
}
|
||||
|
||||
ChatStyle::ChatStyle() {
|
||||
finalize();
|
||||
make(_historyPsaForwardPalette, st::historyPsaForwardPalette);
|
||||
|
@ -453,6 +544,8 @@ ChatStyle::ChatStyle() {
|
|||
&MessageImageStyle::historyVideoMessageMute,
|
||||
st::historyVideoMessageMute,
|
||||
st::historyVideoMessageMuteSelected);
|
||||
|
||||
updateDarkValue();
|
||||
}
|
||||
|
||||
ChatStyle::ChatStyle(not_null<const style::palette*> isolated)
|
||||
|
@ -464,6 +557,13 @@ void ChatStyle::apply(not_null<ChatTheme*> theme) {
|
|||
applyCustomPalette(theme->palette());
|
||||
}
|
||||
|
||||
void ChatStyle::updateDarkValue() {
|
||||
const auto withBg = [&](const QColor &color) {
|
||||
return CountContrast(windowBg()->c, color);
|
||||
};
|
||||
_dark = (withBg({ 0, 0, 0 }) < withBg({ 255, 255, 255 }));
|
||||
}
|
||||
|
||||
void ChatStyle::applyCustomPalette(const style::palette *palette) {
|
||||
assignPalette(palette ? palette : style::main_palette::get().get());
|
||||
if (palette) {
|
||||
|
@ -547,10 +647,13 @@ void ChatStyle::assignPalette(not_null<const style::palette*> palette) {
|
|||
= stm.semiboldPalette.linkAlwaysActive
|
||||
= (stm.textPalette.linkFg->c == stm.historyTextFg->c);
|
||||
}
|
||||
|
||||
for (auto &palette : _coloredTextPalettes) {
|
||||
palette.inited = false;
|
||||
for (auto &values : _coloredValues) {
|
||||
values.reset();
|
||||
}
|
||||
for (auto &palette : _coloredTextPalettes) {
|
||||
palette.linkFg.reset();
|
||||
}
|
||||
updateDarkValue();
|
||||
|
||||
_paletteChanged.fire({});
|
||||
}
|
||||
|
@ -584,20 +687,24 @@ const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const {
|
|||
BubbleRadiusLarge(),
|
||||
result.msgBg,
|
||||
&result.msgShadow);
|
||||
const auto &replyBar = result.msgReplyBarColor->c;
|
||||
EnsureBlockquoteCache(
|
||||
result.replyCache,
|
||||
result.msgReplyBarColor);
|
||||
[&] { return SimpleColorIndexValues(replyBar, false); });
|
||||
EnsureBlockquoteCache(
|
||||
result.replyCacheTwo,
|
||||
[&] { return SimpleColorIndexValues(replyBar, true); });
|
||||
if (!result.quoteCache) {
|
||||
result.quoteCache = std::make_unique<Text::QuotePaintCache>(
|
||||
*result.replyCache);
|
||||
}
|
||||
if (!result.quoteCacheTwo) {
|
||||
result.quoteCacheTwo = std::make_unique<Text::QuotePaintCache>(
|
||||
*result.replyCacheTwo);
|
||||
}
|
||||
|
||||
const auto preBgOverride = [&] {
|
||||
const auto withBg = [&](const QColor &color) {
|
||||
return CountContrast(windowBg()->c, color);
|
||||
};
|
||||
const auto dark = (withBg({ 0, 0, 0 }) < withBg({ 255, 255, 255 }));
|
||||
return dark ? QColor(0, 0, 0, 192) : std::optional<QColor>();
|
||||
return _dark ? QColor(0, 0, 0, 192) : std::optional<QColor>();
|
||||
};
|
||||
EnsurePreCache(
|
||||
result.preCache,
|
||||
|
@ -634,14 +741,37 @@ const MessageImageStyle &ChatStyle::imageStyle(bool selected) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
not_null<Text::QuotePaintCache*> ChatStyle::serviceQuoteCache() const {
|
||||
EnsureBlockquoteCache(_serviceQuoteCache, msgServiceFg());
|
||||
return _serviceQuoteCache.get();
|
||||
not_null<Text::QuotePaintCache*> ChatStyle::serviceQuoteCache(
|
||||
bool twoColored) const {
|
||||
const auto index = (twoColored ? 1 : 0);
|
||||
const auto &service = msgServiceFg()->c;
|
||||
EnsureBlockquoteCache(
|
||||
_serviceQuoteCache[index],
|
||||
[&] { return SimpleColorIndexValues(service, twoColored); });
|
||||
return _serviceQuoteCache[index].get();
|
||||
}
|
||||
|
||||
not_null<Text::QuotePaintCache*> ChatStyle::serviceReplyCache() const {
|
||||
EnsureBlockquoteCache(_serviceReplyCache, msgServiceFg());
|
||||
return _serviceReplyCache.get();
|
||||
not_null<Text::QuotePaintCache*> ChatStyle::serviceReplyCache(
|
||||
bool twoColored) const {
|
||||
const auto index = (twoColored ? 1 : 0);
|
||||
const auto &service = msgServiceFg()->c;
|
||||
EnsureBlockquoteCache(
|
||||
_serviceReplyCache[index],
|
||||
[&] { return SimpleColorIndexValues(service, twoColored); });
|
||||
return _serviceReplyCache[index].get();
|
||||
}
|
||||
|
||||
const ColorIndexValues &ChatStyle::coloredValues(
|
||||
bool selected,
|
||||
uint8 colorIndex) const {
|
||||
Expects(colorIndex >= 0 && colorIndex < kColorIndexCount);
|
||||
|
||||
const auto shift = (selected ? kColorIndexCount : 0);
|
||||
auto &result = _coloredValues[shift + colorIndex];
|
||||
if (!result) {
|
||||
result.emplace(ComputeColorIndexValues(this, selected, colorIndex));
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
const style::TextPalette &ChatStyle::coloredTextPalette(
|
||||
|
@ -651,14 +781,14 @@ const style::TextPalette &ChatStyle::coloredTextPalette(
|
|||
|
||||
const auto shift = (selected ? kColorIndexCount : 0);
|
||||
auto &result = _coloredTextPalettes[shift + colorIndex];
|
||||
if (!result.inited) {
|
||||
result.inited = true;
|
||||
if (!result.linkFg) {
|
||||
result.linkFg.emplace(FromNameFg(this, selected, colorIndex));
|
||||
make(
|
||||
result.data,
|
||||
(selected
|
||||
? st::inReplyTextPaletteSelected
|
||||
: st::inReplyTextPalette));
|
||||
result.data.linkFg = FromNameFg(this, selected, colorIndex);
|
||||
result.data.linkFg = result.linkFg->color();
|
||||
result.data.selectLinkFg = result.data.linkFg;
|
||||
}
|
||||
return result.data;
|
||||
|
@ -684,7 +814,9 @@ not_null<Text::QuotePaintCache*> ChatStyle::coloredCache(
|
|||
|
||||
const auto shift = (selected ? kColorIndexCount : 0);
|
||||
auto &cache = caches[shift + colorIndex];
|
||||
EnsureBlockquoteCache(cache, FromNameFg(this, selected, colorIndex));
|
||||
EnsureBlockquoteCache(cache, [&] {
|
||||
return coloredValues(selected, colorIndex);
|
||||
});
|
||||
return cache.get();
|
||||
}
|
||||
|
||||
|
@ -816,47 +948,21 @@ void ChatStyle::make(
|
|||
}
|
||||
|
||||
uint8 DecideColorIndex(uint64 id) {
|
||||
return id % kColorIndexCount;
|
||||
return id % kSimpleColorIndexCount;
|
||||
}
|
||||
|
||||
uint8 ColorIndexToPaletteIndex(uint8 colorIndex) {
|
||||
Expects(colorIndex >= 0 && colorIndex < kColorIndexCount);
|
||||
|
||||
const int8 map[] = { 0, 7, 4, 1, 6, 3, 5 };
|
||||
return map[colorIndex];
|
||||
return map[colorIndex % kSimpleColorIndexCount];
|
||||
}
|
||||
|
||||
style::color FromNameFg(
|
||||
QColor FromNameFg(
|
||||
not_null<const ChatStyle*> st,
|
||||
bool selected,
|
||||
uint8 colorIndex) {
|
||||
Expects(colorIndex >= 0 && colorIndex < kColorIndexCount);
|
||||
|
||||
if (selected) {
|
||||
const style::color colors[] = {
|
||||
st->historyPeer1NameFgSelected(),
|
||||
st->historyPeer2NameFgSelected(),
|
||||
st->historyPeer3NameFgSelected(),
|
||||
st->historyPeer4NameFgSelected(),
|
||||
st->historyPeer5NameFgSelected(),
|
||||
st->historyPeer6NameFgSelected(),
|
||||
st->historyPeer7NameFgSelected(),
|
||||
st->historyPeer8NameFgSelected(),
|
||||
};
|
||||
return colors[ColorIndexToPaletteIndex(colorIndex)];
|
||||
} else {
|
||||
const style::color colors[] = {
|
||||
st->historyPeer1NameFg(),
|
||||
st->historyPeer2NameFg(),
|
||||
st->historyPeer3NameFg(),
|
||||
st->historyPeer4NameFg(),
|
||||
st->historyPeer5NameFg(),
|
||||
st->historyPeer6NameFg(),
|
||||
st->historyPeer7NameFg(),
|
||||
st->historyPeer8NameFg(),
|
||||
};
|
||||
return colors[ColorIndexToPaletteIndex(colorIndex)];
|
||||
}
|
||||
return st->coloredValues(selected, colorIndex).name;
|
||||
}
|
||||
|
||||
void FillComplexOverlayRect(
|
||||
|
|
|
@ -27,7 +27,8 @@ class ChatTheme;
|
|||
class ChatStyle;
|
||||
struct BubblePattern;
|
||||
|
||||
inline constexpr auto kColorIndexCount = uint8(7);
|
||||
inline constexpr auto kColorIndexCount = uint8(14);
|
||||
inline constexpr auto kSimpleColorIndexCount = uint8(7);
|
||||
|
||||
struct MessageStyle {
|
||||
CornersPixmaps msgBgCornersSmall;
|
||||
|
@ -79,7 +80,9 @@ struct MessageStyle {
|
|||
style::icon historyTranscribeIcon = { Qt::Uninitialized };
|
||||
style::icon historyTranscribeHide = { Qt::Uninitialized };
|
||||
std::unique_ptr<Text::QuotePaintCache> quoteCache;
|
||||
std::unique_ptr<Text::QuotePaintCache> quoteCacheTwo;
|
||||
std::unique_ptr<Text::QuotePaintCache> replyCache;
|
||||
std::unique_ptr<Text::QuotePaintCache> replyCacheTwo;
|
||||
std::unique_ptr<Text::QuotePaintCache> preCache;
|
||||
};
|
||||
|
||||
|
@ -116,8 +119,6 @@ struct ChatPaintContext {
|
|||
QRect viewport;
|
||||
QRect clip;
|
||||
TextSelection selection;
|
||||
bool outbg = false;
|
||||
bool paused = false;
|
||||
crl::time now = 0;
|
||||
|
||||
void translate(int x, int y) {
|
||||
|
@ -133,6 +134,8 @@ struct ChatPaintContext {
|
|||
}
|
||||
[[nodiscard]] not_null<const MessageStyle*> messageStyle() const;
|
||||
[[nodiscard]] not_null<const MessageImageStyle*> imageStyle() const;
|
||||
[[nodiscard]] not_null<Text::QuotePaintCache*> quoteCache(
|
||||
uint8 colorIndex) const;
|
||||
|
||||
[[nodiscard]] ChatPaintContext translated(int x, int y) const {
|
||||
auto result = *this;
|
||||
|
@ -157,12 +160,27 @@ struct ChatPaintContext {
|
|||
};
|
||||
SkipDrawingParts skipDrawingParts = SkipDrawingParts::None;
|
||||
|
||||
bool outbg = false;
|
||||
bool paused = false;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] int HistoryServiceMsgRadius();
|
||||
[[nodiscard]] int HistoryServiceMsgInvertedRadius();
|
||||
[[nodiscard]] int HistoryServiceMsgInvertedShrink();
|
||||
|
||||
struct ColorIndexValues {
|
||||
QColor name;
|
||||
QColor bg;
|
||||
QColor outline1;
|
||||
QColor outline2;
|
||||
};
|
||||
[[nodiscard]] ColorIndexValues ComputeColorIndexValues(
|
||||
not_null<const ChatStyle*> st,
|
||||
bool selected,
|
||||
uint8 colorIndex);
|
||||
[[nodiscard]] bool ColorIndexTwoColored(uint8 colorIndex);
|
||||
|
||||
class ChatStyle final : public style::palette {
|
||||
public:
|
||||
ChatStyle();
|
||||
|
@ -172,6 +190,10 @@ public:
|
|||
void applyCustomPalette(const style::palette *palette);
|
||||
void applyAdjustedServiceBg(QColor serviceBg);
|
||||
|
||||
[[nodiscard]] bool dark() const {
|
||||
return _dark;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::span<Text::SpecialColor> highlightColors() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<> paletteChanged() const {
|
||||
|
@ -202,10 +224,13 @@ public:
|
|||
bool selected) const;
|
||||
[[nodiscard]] const MessageImageStyle &imageStyle(bool selected) const;
|
||||
|
||||
[[nodiscard]] auto serviceQuoteCache() const
|
||||
[[nodiscard]] auto serviceQuoteCache(bool twoColored) const
|
||||
-> not_null<Text::QuotePaintCache*>;
|
||||
[[nodiscard]] auto serviceReplyCache() const
|
||||
[[nodiscard]] auto serviceReplyCache(bool twoColored) const
|
||||
-> not_null<Text::QuotePaintCache*>;
|
||||
[[nodiscard]] const ColorIndexValues &coloredValues(
|
||||
bool selected,
|
||||
uint8 colorIndex) const;
|
||||
[[nodiscard]] not_null<Text::QuotePaintCache*> coloredQuoteCache(
|
||||
bool selected,
|
||||
uint8 colorIndex) const;
|
||||
|
@ -307,11 +332,12 @@ private:
|
|||
kColorIndexCount * 2>;
|
||||
|
||||
struct ColoredPalette {
|
||||
std::optional<style::owned_color> linkFg;
|
||||
style::TextPalette data;
|
||||
bool inited = false;
|
||||
};
|
||||
|
||||
void assignPalette(not_null<const style::palette*> palette);
|
||||
void updateDarkValue();
|
||||
|
||||
[[nodiscard]] not_null<Text::QuotePaintCache*> coloredCache(
|
||||
ColoredQuotePaintCaches &caches,
|
||||
|
@ -368,8 +394,15 @@ private:
|
|||
int(CachedCornerRadius::kCount)];
|
||||
|
||||
mutable std::vector<Text::SpecialColor> _highlightColors;
|
||||
mutable std::unique_ptr<Text::QuotePaintCache> _serviceQuoteCache;
|
||||
mutable std::unique_ptr<Text::QuotePaintCache> _serviceReplyCache;
|
||||
mutable std::array<
|
||||
std::unique_ptr<Text::QuotePaintCache>,
|
||||
2> _serviceQuoteCache;
|
||||
mutable std::array<
|
||||
std::unique_ptr<Text::QuotePaintCache>,
|
||||
2> _serviceReplyCache;
|
||||
mutable std::array<
|
||||
std::optional<ColorIndexValues>,
|
||||
2 * kColorIndexCount> _coloredValues;
|
||||
mutable ColoredQuotePaintCaches _coloredQuoteCaches;
|
||||
mutable ColoredQuotePaintCaches _coloredReplyCaches;
|
||||
mutable std::array<
|
||||
|
@ -403,6 +436,8 @@ private:
|
|||
style::icon _historyPollChoiceRight = { Qt::Uninitialized };
|
||||
style::icon _historyPollChoiceWrong = { Qt::Uninitialized };
|
||||
|
||||
bool _dark = false;
|
||||
|
||||
rpl::event_stream<> _paletteChanged;
|
||||
|
||||
rpl::lifetime _defaultPaletteChangeLifetime;
|
||||
|
@ -412,11 +447,17 @@ private:
|
|||
[[nodiscard]] uint8 DecideColorIndex(uint64 id);
|
||||
[[nodiscard]] uint8 ColorIndexToPaletteIndex(uint8 colorIndex);
|
||||
|
||||
[[nodiscard]] style::color FromNameFg(
|
||||
[[nodiscard]] QColor FromNameFg(
|
||||
not_null<const ChatStyle*> st,
|
||||
bool selected,
|
||||
uint8 colorIndex);
|
||||
|
||||
[[nodiscard]] inline QColor FromNameFg(
|
||||
const ChatPaintContext &context,
|
||||
uint8 colorIndex) {
|
||||
return FromNameFg(context.st, context.selected(), colorIndex);
|
||||
}
|
||||
|
||||
void FillComplexOverlayRect(
|
||||
QPainter &p,
|
||||
QRect rect,
|
||||
|
|
|
@ -489,8 +489,8 @@ ChatPaintContext ChatTheme::preparePaintContext(
|
|||
.bubblesPattern = _bubblesBackgroundPattern.get(),
|
||||
.viewport = viewport,
|
||||
.clip = clip,
|
||||
.paused = paused,
|
||||
.now = now,
|
||||
.paused = paused,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 4d1a5686a7620b163639492e1b81101b677d2472
|
||||
Subproject commit 71d24af3a840d15a6cc0a3a8a1e9cbe77a604739
|
Loading…
Add table
Reference in a new issue