mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Implement new bubble rounding.
This commit is contained in:
parent
405d8c327d
commit
ba2f92906b
20 changed files with 308 additions and 223 deletions
|
@ -319,6 +319,11 @@ InnerWidget::InnerWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
controller->adaptive().chatWideValue(
|
||||||
|
) | rpl::start_with_next([=](bool wide) {
|
||||||
|
_isChatWide = wide;
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
updateEmptyText();
|
updateEmptyText();
|
||||||
|
|
||||||
requestAdmins();
|
requestAdmins();
|
||||||
|
@ -661,7 +666,7 @@ void InnerWidget::elementHandleViaClick(not_null<UserData*> bot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InnerWidget::elementIsChatWide() {
|
bool InnerWidget::elementIsChatWide() {
|
||||||
return _controller->adaptive().isChatWide();
|
return _isChatWide;
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::PathShiftGradient*> InnerWidget::elementPathShiftGradient() {
|
not_null<Ui::PathShiftGradient*> InnerWidget::elementPathShiftGradient() {
|
||||||
|
@ -1029,10 +1034,8 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
p.setOpacity(opacity);
|
p.setOpacity(opacity);
|
||||||
const auto dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top());
|
const auto dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top());
|
||||||
const auto width = view->width();
|
const auto width = view->width();
|
||||||
const auto chatWide =
|
|
||||||
_controller->adaptive().isChatWide();
|
|
||||||
if (const auto date = view->Get<HistoryView::DateBadge>()) {
|
if (const auto date = view->Get<HistoryView::DateBadge>()) {
|
||||||
date->paint(p, context.st, dateY, width, chatWide);
|
date->paint(p, context.st, dateY, width, _isChatWide);
|
||||||
} else {
|
} else {
|
||||||
HistoryView::ServiceMessagePainter::PaintDate(
|
HistoryView::ServiceMessagePainter::PaintDate(
|
||||||
p,
|
p,
|
||||||
|
@ -1040,7 +1043,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
view->dateTime(),
|
view->dateTime(),
|
||||||
dateY,
|
dateY,
|
||||||
width,
|
width,
|
||||||
chatWide);
|
_isChatWide);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,6 +288,7 @@ private:
|
||||||
Element *_visibleTopItem = nullptr;
|
Element *_visibleTopItem = nullptr;
|
||||||
int _visibleTopFromItem = 0;
|
int _visibleTopFromItem = 0;
|
||||||
|
|
||||||
|
bool _isChatWide = false;
|
||||||
bool _scrollDateShown = false;
|
bool _scrollDateShown = false;
|
||||||
Ui::Animations::Simple _scrollDateOpacity;
|
Ui::Animations::Simple _scrollDateOpacity;
|
||||||
SingleQueuedInvokation _scrollDateCheck;
|
SingleQueuedInvokation _scrollDateCheck;
|
||||||
|
|
|
@ -922,7 +922,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
const auto stm = &st->messageStyle(false, false);
|
const auto stm = &st->messageStyle(false, false);
|
||||||
if (clip.y() < _botAbout->rect.y() + _botAbout->rect.height() && clip.y() + clip.height() > _botAbout->rect.y()) {
|
if (clip.y() < _botAbout->rect.y() + _botAbout->rect.height() && clip.y() + clip.height() > _botAbout->rect.y()) {
|
||||||
p.setTextPalette(stm->textPalette);
|
p.setTextPalette(stm->textPalette);
|
||||||
Ui::FillRoundRect(p, _botAbout->rect, stm->msgBg, stm->msgBgCorners, &stm->msgShadow);
|
Ui::FillRoundRect(p, _botAbout->rect, stm->msgBg, stm->msgBgCornersLarge, &stm->msgShadow);
|
||||||
|
|
||||||
auto top = _botAbout->rect.top() + st::msgPadding.top();
|
auto top = _botAbout->rect.top() + st::msgPadding.top();
|
||||||
if (!_history->peer->isRepliesChat()) {
|
if (!_history->peer->isRepliesChat()) {
|
||||||
|
|
|
@ -761,17 +761,6 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
&& (_fromNameVersion < item->displayFrom()->nameVersion())) {
|
&& (_fromNameVersion < item->displayFrom()->nameVersion())) {
|
||||||
fromNameUpdated(g.width());
|
fromNameUpdated(g.width());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto skipTail = isAttachedToNext()
|
|
||||||
|| (media && media->skipBubbleTail())
|
|
||||||
|| (keyboard != nullptr)
|
|
||||||
|| (this->context() == Context::Replies
|
|
||||||
&& data()->isDiscussionPost());
|
|
||||||
const auto displayTail = skipTail
|
|
||||||
? RectPart::None
|
|
||||||
: (context.outbg && !delegate()->elementIsChatWide())
|
|
||||||
? RectPart::Right
|
|
||||||
: RectPart::Left;
|
|
||||||
Ui::PaintBubble(
|
Ui::PaintBubble(
|
||||||
p,
|
p,
|
||||||
Ui::ComplexBubble{
|
Ui::ComplexBubble{
|
||||||
|
@ -783,7 +772,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
.outerWidth = width(),
|
.outerWidth = width(),
|
||||||
.selected = context.selected(),
|
.selected = context.selected(),
|
||||||
.outbg = context.outbg,
|
.outbg = context.outbg,
|
||||||
.tailSide = displayTail,
|
.rounding = countBubbleRounding(),
|
||||||
},
|
},
|
||||||
.selection = mediaSelectionIntervals,
|
.selection = mediaSelectionIntervals,
|
||||||
});
|
});
|
||||||
|
@ -1408,7 +1397,8 @@ void Message::toggleCommentsButtonRipple(bool pressed) {
|
||||||
const auto linkHeight = st::historyCommentsButtonHeight;
|
const auto linkHeight = st::historyCommentsButtonHeight;
|
||||||
if (!_comments->ripple) {
|
if (!_comments->ripple) {
|
||||||
const auto drawMask = [&](QPainter &p) {
|
const auto drawMask = [&](QPainter &p) {
|
||||||
const auto radius = st::historyMessageRadius;
|
// #TODO rounding
|
||||||
|
const auto radius = st::bubbleRadiusSmall;
|
||||||
p.drawRoundedRect(
|
p.drawRoundedRect(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -2992,6 +2982,33 @@ QRect Message::countGeometry() const {
|
||||||
height() - contentTop - marginBottom());
|
height() - contentTop - marginBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ui::BubbleRounding Message::countBubbleRounding() const {
|
||||||
|
const auto smallTop = isAttachedToPrevious();
|
||||||
|
const auto smallBottom = isAttachedToNext();
|
||||||
|
const auto media = this->media();
|
||||||
|
const auto keyboard = data()->inlineReplyKeyboard();
|
||||||
|
const auto skipTail = smallBottom
|
||||||
|
|| (media && media->skipBubbleTail())
|
||||||
|
|| (keyboard != nullptr)
|
||||||
|
|| (context() == Context::Replies && data()->isDiscussionPost());
|
||||||
|
const auto right = !delegate()->elementIsChatWide() && hasOutLayout();
|
||||||
|
using Corner = Ui::BubbleCornerRounding;
|
||||||
|
return {
|
||||||
|
.topLeft = (smallTop && !right) ? Corner::Small : Corner::Large,
|
||||||
|
.topRight = (smallTop && right) ? Corner::Small : Corner::Large,
|
||||||
|
.bottomLeft = ((smallBottom && !right)
|
||||||
|
? Corner::Small
|
||||||
|
: (!skipTail && !right)
|
||||||
|
? Corner::Tail
|
||||||
|
: Corner::Large),
|
||||||
|
.bottomRight = ((smallBottom && right)
|
||||||
|
? Corner::Small
|
||||||
|
: (!skipTail && right)
|
||||||
|
? Corner::Tail
|
||||||
|
: Corner::Large),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
int Message::resizeContentGetHeight(int newWidth) {
|
int Message::resizeContentGetHeight(int newWidth) {
|
||||||
if (isHidden()) {
|
if (isHidden()) {
|
||||||
return marginTop() + marginBottom();
|
return marginTop() + marginBottom();
|
||||||
|
|
|
@ -19,6 +19,10 @@ namespace Data {
|
||||||
struct ReactionId;
|
struct ReactionId;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
struct BubbleRounding;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
class ViewButton;
|
class ViewButton;
|
||||||
|
@ -221,6 +225,7 @@ private:
|
||||||
|
|
||||||
void updateMediaInBubbleState();
|
void updateMediaInBubbleState();
|
||||||
QRect countGeometry() const;
|
QRect countGeometry() const;
|
||||||
|
[[nodiscard]] Ui::BubbleRounding countBubbleRounding() const;
|
||||||
|
|
||||||
int resizeContentGetHeight(int newWidth);
|
int resizeContentGetHeight(int newWidth);
|
||||||
QSize performCountOptimalSize() override;
|
QSize performCountOptimalSize() override;
|
||||||
|
|
|
@ -211,7 +211,8 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
|
||||||
rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCorners);
|
// #TODO rounding
|
||||||
|
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCornersSmall);
|
||||||
}
|
}
|
||||||
const auto inWebPage = (_parent->media() != this);
|
const auto inWebPage = (_parent->media() != this);
|
||||||
const auto roundRadius = inWebPage
|
const auto roundRadius = inWebPage
|
||||||
|
|
|
@ -357,7 +357,8 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!unwrapped) {
|
} else if (!unwrapped) {
|
||||||
Ui::FillRoundShadow(p, 0, 0, paintw, height(), sti->msgShadow, sti->msgShadowCorners);
|
// #TODO rounding
|
||||||
|
Ui::FillRoundShadow(p, 0, 0, paintw, height(), sti->msgShadow, sti->msgShadowCornersSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto usex = 0, usew = paintw;
|
auto usex = 0, usew = paintw;
|
||||||
|
|
|
@ -186,7 +186,8 @@ void Location::draw(Painter &p, const PaintContext &context) const {
|
||||||
}
|
}
|
||||||
painth -= painty;
|
painth -= painty;
|
||||||
} else {
|
} else {
|
||||||
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCorners);
|
// #TODO rounding
|
||||||
|
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCornersSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto roundRadius = ImageRoundRadius::Large;
|
auto roundRadius = ImageRoundRadius::Large;
|
||||||
|
|
|
@ -267,7 +267,8 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
|
||||||
rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCorners);
|
// #TODO rounding
|
||||||
|
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCornersSmall);
|
||||||
}
|
}
|
||||||
const auto inWebPage = (_parent->media() != this);
|
const auto inWebPage = (_parent->media() != this);
|
||||||
const auto roundRadius = inWebPage
|
const auto roundRadius = inWebPage
|
||||||
|
|
|
@ -1569,7 +1569,8 @@ void Poll::toggleLinkRipple(bool pressed) {
|
||||||
const auto linkHeight = bottomButtonHeight();
|
const auto linkHeight = bottomButtonHeight();
|
||||||
if (!_linkRipple) {
|
if (!_linkRipple) {
|
||||||
const auto drawMask = [&](QPainter &p) {
|
const auto drawMask = [&](QPainter &p) {
|
||||||
const auto radius = st::historyMessageRadius;
|
// #TODO rounding
|
||||||
|
const auto radius = st::bubbleRadiusSmall;
|
||||||
p.drawRoundedRect(
|
p.drawRoundedRect(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -66,7 +66,7 @@ void CreateMaskCorners() {
|
||||||
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());
|
||||||
}
|
}
|
||||||
mask = PrepareCorners(st::historyMessageRadius, QColor(255, 255, 255), nullptr);
|
mask = PrepareCorners(st::roundRadiusLarge, 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());
|
||||||
|
@ -79,7 +79,7 @@ void CreatePaletteCorners() {
|
||||||
PrepareCorners(DateCorners, st::dateRadius, st::msgDateImgBg);
|
PrepareCorners(DateCorners, st::dateRadius, st::msgDateImgBg);
|
||||||
PrepareCorners(OverviewVideoCorners, st::overviewVideoStatusRadius, st::msgDateImgBg);
|
PrepareCorners(OverviewVideoCorners, st::overviewVideoStatusRadius, st::msgDateImgBg);
|
||||||
PrepareCorners(OverviewVideoSelectedCorners, st::overviewVideoStatusRadius, st::msgDateImgBgSelected);
|
PrepareCorners(OverviewVideoSelectedCorners, st::overviewVideoStatusRadius, st::msgDateImgBgSelected);
|
||||||
PrepareCorners(ForwardCorners, st::historyMessageRadius, st::historyForwardChooseBg);
|
PrepareCorners(ForwardCorners, st::roundRadiusLarge, st::historyForwardChooseBg);
|
||||||
PrepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg);
|
PrepareCorners(MediaviewSaveCorners, st::mediaviewControllerRadius, st::mediaviewSaveMsgBg);
|
||||||
PrepareCorners(StickerHoverCorners, st::roundRadiusSmall, st::emojiPanHover);
|
PrepareCorners(StickerHoverCorners, st::roundRadiusSmall, st::emojiPanHover);
|
||||||
PrepareCorners(BotKeyboardCorners, st::roundRadiusSmall, st::botKbBg);
|
PrepareCorners(BotKeyboardCorners, st::roundRadiusSmall, st::botKbBg);
|
||||||
|
@ -192,7 +192,7 @@ CornersPixmaps PrepareCornerPixmaps(ImageRoundRadius radius, style::color bg, co
|
||||||
case ImageRoundRadius::Small:
|
case ImageRoundRadius::Small:
|
||||||
return PrepareCornerPixmaps(st::roundRadiusSmall, bg, sh);
|
return PrepareCornerPixmaps(st::roundRadiusSmall, bg, sh);
|
||||||
case ImageRoundRadius::Large:
|
case ImageRoundRadius::Large:
|
||||||
return PrepareCornerPixmaps(st::historyMessageRadius, bg, sh);
|
return PrepareCornerPixmaps(st::roundRadiusLarge, bg, sh);
|
||||||
}
|
}
|
||||||
Unexpected("Image round radius in PrepareCornerPixmaps.");
|
Unexpected("Image round radius in PrepareCornerPixmaps.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ AlbumThumbnail::AlbumThumbnail(
|
||||||
Fn<void()> deleteCallback)
|
Fn<void()> deleteCallback)
|
||||||
: _layout(layout)
|
: _layout(layout)
|
||||||
, _fullPreview(file.preview)
|
, _fullPreview(file.preview)
|
||||||
, _shrinkSize(int(std::ceil(st::historyMessageRadius / 1.4)))
|
, _shrinkSize(int(std::ceil(st::roundRadiusLarge / 1.4)))
|
||||||
, _isPhoto(file.type == PreparedFile::Type::Photo)
|
, _isPhoto(file.type == PreparedFile::Type::Photo)
|
||||||
, _isVideo(file.type == PreparedFile::Type::Video) {
|
, _isVideo(file.type == PreparedFile::Type::Video) {
|
||||||
Expects(!_fullPreview.isNull());
|
Expects(!_fullPreview.isNull());
|
||||||
|
|
|
@ -562,9 +562,11 @@ historyInfoToast: Toast(defaultToast) {
|
||||||
iconPosition: point(13px, 13px);
|
iconPosition: point(13px, 13px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bubbleRadiusSmall: roundRadiusLarge;
|
||||||
|
bubbleRadiusLarge: 16px;
|
||||||
|
|
||||||
historyPhotoLeft: 14px;
|
historyPhotoLeft: 14px;
|
||||||
historyPhotoBubbleMinWidth: 200px;
|
historyPhotoBubbleMinWidth: 200px;
|
||||||
historyMessageRadius: roundRadiusLarge;
|
|
||||||
historyBubbleTailInLeft: icon {{ "bubble_tail", msgInBg }};
|
historyBubbleTailInLeft: icon {{ "bubble_tail", msgInBg }};
|
||||||
historyBubbleTailInLeftSelected: icon {{ "bubble_tail", msgInBgSelected }};
|
historyBubbleTailInLeftSelected: icon {{ "bubble_tail", msgInBgSelected }};
|
||||||
historyBubbleTailOutLeft: icon {{ "bubble_tail", msgOutBg }};
|
historyBubbleTailOutLeft: icon {{ "bubble_tail", msgOutBg }};
|
||||||
|
|
|
@ -480,12 +480,14 @@ void ChatStyle::assignPalette(not_null<const style::palette*> palette) {
|
||||||
*static_cast<style::palette*>(this) = *palette;
|
*static_cast<style::palette*>(this) = *palette;
|
||||||
style::internal::resetIcons();
|
style::internal::resetIcons();
|
||||||
for (auto &style : _messageStyles) {
|
for (auto &style : _messageStyles) {
|
||||||
style.msgBgCorners = {};
|
style.msgBgCornersSmall = {};
|
||||||
|
style.msgBgCornersLarge = {};
|
||||||
}
|
}
|
||||||
for (auto &style : _imageStyles) {
|
for (auto &style : _imageStyles) {
|
||||||
style.msgDateImgBgCorners = {};
|
style.msgDateImgBgCorners = {};
|
||||||
style.msgServiceBgCorners = {};
|
style.msgServiceBgCorners = {};
|
||||||
style.msgShadowCorners = {};
|
style.msgShadowCornersSmall = {};
|
||||||
|
style.msgShadowCornersLarge = {};
|
||||||
}
|
}
|
||||||
_serviceBgCornersNormal = {};
|
_serviceBgCornersNormal = {};
|
||||||
_serviceBgCornersInverted = {};
|
_serviceBgCornersInverted = {};
|
||||||
|
@ -533,8 +535,13 @@ const CornersPixmaps &ChatStyle::serviceBgCornersInverted() const {
|
||||||
const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const {
|
const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const {
|
||||||
auto &result = messageStyleRaw(outbg, selected);
|
auto &result = messageStyleRaw(outbg, selected);
|
||||||
EnsureCorners(
|
EnsureCorners(
|
||||||
result.msgBgCorners,
|
result.msgBgCornersSmall,
|
||||||
st::historyMessageRadius,
|
st::bubbleRadiusSmall,
|
||||||
|
result.msgBg,
|
||||||
|
&result.msgShadow);
|
||||||
|
EnsureCorners(
|
||||||
|
result.msgBgCornersLarge,
|
||||||
|
st::bubbleRadiusLarge,
|
||||||
result.msgBg,
|
result.msgBg,
|
||||||
&result.msgShadow);
|
&result.msgShadow);
|
||||||
return result;
|
return result;
|
||||||
|
@ -551,8 +558,12 @@ const MessageImageStyle &ChatStyle::imageStyle(bool selected) const {
|
||||||
st::dateRadius,
|
st::dateRadius,
|
||||||
result.msgServiceBg);
|
result.msgServiceBg);
|
||||||
EnsureCorners(
|
EnsureCorners(
|
||||||
result.msgShadowCorners,
|
result.msgShadowCornersSmall,
|
||||||
st::historyMessageRadius,
|
st::bubbleRadiusSmall,
|
||||||
|
result.msgShadow);
|
||||||
|
EnsureCorners(
|
||||||
|
result.msgShadowCornersLarge,
|
||||||
|
st::bubbleRadiusLarge,
|
||||||
result.msgShadow);
|
result.msgShadow);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +587,7 @@ const CornersPixmaps &ChatStyle::msgSelectOverlayCornersSmall() const {
|
||||||
const CornersPixmaps &ChatStyle::msgSelectOverlayCornersLarge() const {
|
const CornersPixmaps &ChatStyle::msgSelectOverlayCornersLarge() const {
|
||||||
EnsureCorners(
|
EnsureCorners(
|
||||||
_msgSelectOverlayCornersLarge,
|
_msgSelectOverlayCornersLarge,
|
||||||
st::historyMessageRadius,
|
st::roundRadiusLarge,
|
||||||
msgSelectOverlay());
|
msgSelectOverlay());
|
||||||
return _msgSelectOverlayCornersLarge;
|
return _msgSelectOverlayCornersLarge;
|
||||||
}
|
}
|
||||||
|
@ -707,7 +718,8 @@ void FillComplexLocationRect(
|
||||||
ImageRoundRadius radius,
|
ImageRoundRadius radius,
|
||||||
RectParts roundCorners) {
|
RectParts roundCorners) {
|
||||||
const auto stm = &st->messageStyle(false, false);
|
const auto stm = &st->messageStyle(false, false);
|
||||||
RectWithCorners(p, rect, stm->msgBg, stm->msgBgCorners, roundCorners);
|
// #TODO rounding
|
||||||
|
RectWithCorners(p, rect, stm->msgBg, stm->msgBgCornersSmall, roundCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -26,7 +26,8 @@ class ChatStyle;
|
||||||
struct BubblePattern;
|
struct BubblePattern;
|
||||||
|
|
||||||
struct MessageStyle {
|
struct MessageStyle {
|
||||||
CornersPixmaps msgBgCorners;
|
CornersPixmaps msgBgCornersSmall;
|
||||||
|
CornersPixmaps msgBgCornersLarge;
|
||||||
style::color msgBg;
|
style::color msgBg;
|
||||||
style::color msgShadow;
|
style::color msgShadow;
|
||||||
style::color msgServiceFg;
|
style::color msgServiceFg;
|
||||||
|
@ -79,7 +80,8 @@ struct MessageStyle {
|
||||||
struct MessageImageStyle {
|
struct MessageImageStyle {
|
||||||
CornersPixmaps msgDateImgBgCorners;
|
CornersPixmaps msgDateImgBgCorners;
|
||||||
CornersPixmaps msgServiceBgCorners;
|
CornersPixmaps msgServiceBgCorners;
|
||||||
CornersPixmaps msgShadowCorners;
|
CornersPixmaps msgShadowCornersSmall;
|
||||||
|
CornersPixmaps msgShadowCornersLarge;
|
||||||
style::color msgServiceBg;
|
style::color msgServiceBg;
|
||||||
style::color msgDateImgBg;
|
style::color msgDateImgBg;
|
||||||
style::color msgShadow;
|
style::color msgShadow;
|
||||||
|
|
|
@ -15,79 +15,152 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using Corner = BubbleCornerRounding;
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename FillBg, // fillBg(QRect rect)
|
typename FillBg, // fillBg(QRect rect)
|
||||||
typename FillSh, // fillSh(QRect rect)
|
typename FillSh, // fillSh(QRect rect)
|
||||||
typename FillRounded, // fillRounded(QRect rect, RectParts parts)
|
typename FillCorner, // fillCorner(int x, int y, int index, Corner size)
|
||||||
typename PaintTail> // paintTail(QPoint bottomPosition) -> tailWidth
|
typename PaintTail> // paintTail(QPoint bottomPosition) -> tailWidth
|
||||||
void PaintBubbleGeneric(
|
void PaintBubbleGeneric(
|
||||||
const SimpleBubble &args,
|
const SimpleBubble &args,
|
||||||
FillBg &&fillBg,
|
FillBg &&fillBg,
|
||||||
FillSh &&fillSh,
|
FillSh &&fillSh,
|
||||||
FillRounded &&fillRounded,
|
FillCorner &&fillCorner,
|
||||||
PaintTail &&paintTail) {
|
PaintTail &&paintTail) {
|
||||||
auto parts = RectPart::None | RectPart::NoTopBottom;
|
const auto topLeft = args.rounding.topLeft;
|
||||||
auto rect = args.geometry;
|
const auto topRight = args.rounding.topRight;
|
||||||
if (args.skip & RectPart::Top) {
|
const auto bottomWithTailLeft = args.rounding.bottomLeft;
|
||||||
if (args.skip & RectPart::Bottom) {
|
const auto bottomWithTailRight = args.rounding.bottomRight;
|
||||||
fillBg(rect);
|
if (topLeft == Corner::None
|
||||||
return;
|
&& topRight == Corner::None
|
||||||
|
&& bottomWithTailLeft == Corner::None
|
||||||
|
&& bottomWithTailRight == Corner::None) {
|
||||||
|
fillBg(args.geometry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto bottomLeft = (bottomWithTailLeft == Corner::Tail)
|
||||||
|
? Corner::None
|
||||||
|
: bottomWithTailLeft;
|
||||||
|
const auto bottomRight = (bottomWithTailRight == Corner::Tail)
|
||||||
|
? Corner::None
|
||||||
|
: bottomWithTailRight;
|
||||||
|
const auto rect = args.geometry;
|
||||||
|
const auto small = st::bubbleRadiusSmall;
|
||||||
|
const auto large = st::bubbleRadiusLarge;
|
||||||
|
const auto cornerSize = [&](Corner corner) {
|
||||||
|
return (corner == Corner::Large)
|
||||||
|
? large
|
||||||
|
: (corner == Corner::Small)
|
||||||
|
? small
|
||||||
|
: 0;
|
||||||
|
};
|
||||||
|
const auto verticalSkip = [&](Corner left, Corner right) {
|
||||||
|
return std::max(cornerSize(left), cornerSize(right));
|
||||||
|
};
|
||||||
|
const auto top = verticalSkip(topLeft, topRight);
|
||||||
|
const auto bottom = verticalSkip(bottomLeft, bottomRight);
|
||||||
|
if (top) {
|
||||||
|
const auto left = cornerSize(topLeft);
|
||||||
|
const auto right = cornerSize(topRight);
|
||||||
|
if (left) {
|
||||||
|
fillCorner(rect.left(), rect.top(), 0, topLeft);
|
||||||
|
if (const auto add = top - left) {
|
||||||
|
fillBg({ rect.left(), rect.top() + left, left, add });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (const auto fill = rect.width() - left - right; fill > 0) {
|
||||||
|
fillBg({ rect.left() + left, rect.top(), fill, top });
|
||||||
|
}
|
||||||
|
if (right) {
|
||||||
|
fillCorner(
|
||||||
|
rect.left() + rect.width() - right,
|
||||||
|
rect.top(),
|
||||||
|
1,
|
||||||
|
topRight);
|
||||||
|
if (const auto add = top - right) {
|
||||||
|
fillBg({
|
||||||
|
rect.left() + rect.width() - right,
|
||||||
|
rect.top() + right,
|
||||||
|
right,
|
||||||
|
add,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rect.setTop(rect.y() - st::historyMessageRadius);
|
|
||||||
} else {
|
|
||||||
parts |= RectPart::FullTop;
|
|
||||||
}
|
}
|
||||||
const auto skipBottom = (args.skip & RectPart::Bottom);
|
if (const auto h = rect.height() - top - bottom; h > 0) {
|
||||||
if (skipBottom) {
|
fillBg({ rect.left(), rect.top() + top, rect.width(), h });
|
||||||
rect.setHeight(rect.height() + st::historyMessageRadius);
|
|
||||||
} else {
|
|
||||||
parts |= RectPart::Bottom;
|
|
||||||
}
|
}
|
||||||
if (!skipBottom && args.tailSide == RectPart::Right) {
|
if (bottom) {
|
||||||
parts |= RectPart::BottomLeft;
|
const auto left = cornerSize(bottomLeft);
|
||||||
fillBg({
|
const auto right = cornerSize(bottomRight);
|
||||||
rect.x() + rect.width() - st::historyMessageRadius,
|
if (left) {
|
||||||
rect.y() + rect.height() - st::historyMessageRadius,
|
fillCorner(
|
||||||
st::historyMessageRadius,
|
rect.left(),
|
||||||
st::historyMessageRadius });
|
rect.top() + rect.height() - left,
|
||||||
const auto tailWidth = paintTail({
|
2,
|
||||||
rect.x() + rect.width(),
|
bottomLeft);
|
||||||
rect.y() + rect.height() });
|
if (const auto add = bottom - left) {
|
||||||
fillSh({
|
fillBg({
|
||||||
rect.x() + rect.width() - st::historyMessageRadius,
|
rect.left(),
|
||||||
rect.y() + rect.height(),
|
rect.top() + rect.height() - bottom,
|
||||||
st::historyMessageRadius + tailWidth,
|
left,
|
||||||
st::msgShadow });
|
add,
|
||||||
} else if (!skipBottom && args.tailSide == RectPart::Left) {
|
});
|
||||||
parts |= RectPart::BottomRight;
|
}
|
||||||
fillBg({
|
}
|
||||||
rect.x(),
|
if (const auto fill = rect.width() - left - right; fill > 0) {
|
||||||
rect.y() + rect.height() - st::historyMessageRadius,
|
fillBg({
|
||||||
st::historyMessageRadius,
|
rect.left() + left,
|
||||||
st::historyMessageRadius });
|
rect.top() + rect.height() - bottom,
|
||||||
const auto tailWidth = paintTail({
|
fill,
|
||||||
rect.x(),
|
bottom,
|
||||||
rect.y() + rect.height() });
|
});
|
||||||
fillSh({
|
}
|
||||||
rect.x() - tailWidth,
|
if (right) {
|
||||||
rect.y() + rect.height(),
|
fillCorner(
|
||||||
st::historyMessageRadius + tailWidth,
|
rect.left() + rect.width() - right,
|
||||||
st::msgShadow });
|
rect.top() + rect.height() - right,
|
||||||
} else if (!skipBottom) {
|
3,
|
||||||
parts |= RectPart::FullBottom;
|
bottomRight);
|
||||||
|
if (const auto add = bottom - right) {
|
||||||
|
fillBg({
|
||||||
|
rect.left() + rect.width() - right,
|
||||||
|
rect.top() + rect.height() - bottom,
|
||||||
|
right,
|
||||||
|
add,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto leftTail = (bottomWithTailLeft == Corner::Tail)
|
||||||
|
? paintTail({ rect.x(), rect.y() + rect.height() })
|
||||||
|
: 0;
|
||||||
|
const auto rightTail = (bottomWithTailRight == Corner::Tail)
|
||||||
|
? paintTail({ rect.x() + rect.width(), rect.y() + rect.height() })
|
||||||
|
: 0;
|
||||||
|
if (!args.shadowed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto shLeft = rect.x() + cornerSize(bottomLeft) - leftTail;
|
||||||
|
const auto shWidth = rect.x()
|
||||||
|
+ rect.width()
|
||||||
|
- cornerSize(bottomRight)
|
||||||
|
+ rightTail
|
||||||
|
- shLeft;
|
||||||
|
if (shWidth > 0) {
|
||||||
|
fillSh({ shLeft, rect.y() + rect.height(), shWidth, st::msgShadow });
|
||||||
}
|
}
|
||||||
fillRounded(rect, parts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintPatternBubble(QPainter &p, const SimpleBubble &args) {
|
void PaintPatternBubble(QPainter &p, const SimpleBubble &args) {
|
||||||
const auto opacity = args.st->msgOutBg()->c.alphaF();
|
const auto opacity = args.st->msgOutBg()->c.alphaF();
|
||||||
const auto shadowOpacity = opacity * args.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 &tail = (args.rounding.bottomRight == Corner::Tail)
|
||||||
const auto &tail = (args.tailSide == RectPart::Right)
|
|
||||||
? pattern->tailRight
|
? pattern->tailRight
|
||||||
: pattern->tailLeft;
|
: pattern->tailLeft;
|
||||||
const auto tailShift = (args.tailSide == RectPart::Right
|
const auto tailShift = (args.rounding.bottomRight == Corner::Tail
|
||||||
? QPoint(0, tail.height())
|
? QPoint(0, tail.height())
|
||||||
: QPoint(tail.width(), tail.height())) / int(tail.devicePixelRatio());
|
: QPoint(tail.width(), tail.height())) / int(tail.devicePixelRatio());
|
||||||
const auto fillBg = [&](const QRect &rect) {
|
const auto fillBg = [&](const QRect &rect) {
|
||||||
|
@ -101,11 +174,9 @@ void PaintPatternBubble(QPainter &p, const SimpleBubble &args) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto fillSh = [&](const QRect &rect) {
|
const auto fillSh = [&](const QRect &rect) {
|
||||||
if (!(args.skip & RectPart::Bottom)) {
|
p.setOpacity(shadowOpacity);
|
||||||
p.setOpacity(shadowOpacity);
|
fillBg(rect);
|
||||||
fillBg(rect);
|
p.setOpacity(opacity);
|
||||||
p.setOpacity(opacity);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const auto fillPattern = [&](
|
const auto fillPattern = [&](
|
||||||
int x,
|
int x,
|
||||||
|
@ -120,121 +191,53 @@ void PaintPatternBubble(QPainter &p, const SimpleBubble &args) {
|
||||||
mask,
|
mask,
|
||||||
cache);
|
cache);
|
||||||
};
|
};
|
||||||
const auto fillCorner = [&](int x, int y, int index) {
|
const auto fillCorner = [&](int x, int y, int index, Corner size) {
|
||||||
fillPattern(
|
auto &corner = (size == Corner::Large)
|
||||||
x,
|
? pattern->cornersLarge[index]
|
||||||
y,
|
: pattern->cornersSmall[index];
|
||||||
pattern->corners[index],
|
auto &cache = (size == Corner::Large)
|
||||||
(index < 2) ? pattern->cornerTopCache : pattern->cornerBottomCache);
|
? (index < 2
|
||||||
};
|
? pattern->cornerTopLargeCache
|
||||||
const auto fillRounded = [&](const QRect &rect, RectParts parts) {
|
: pattern->cornerBottomLargeCache)
|
||||||
const auto x = rect.x();
|
: (index < 2
|
||||||
const auto y = rect.y();
|
? pattern->cornerTopSmallCache
|
||||||
const auto w = rect.width();
|
: pattern->cornerBottomSmallCache);
|
||||||
const auto h = rect.height();
|
fillPattern(x, y, corner, cache);
|
||||||
|
|
||||||
const auto cornerWidth = pattern->corners[0].width()
|
|
||||||
/ style::DevicePixelRatio();
|
|
||||||
const auto cornerHeight = pattern->corners[0].height()
|
|
||||||
/ style::DevicePixelRatio();
|
|
||||||
if (w < 2 * cornerWidth || h < 2 * cornerHeight) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (w > 2 * cornerWidth) {
|
|
||||||
if (parts & RectPart::Top) {
|
|
||||||
fillBg({
|
|
||||||
x + cornerWidth,
|
|
||||||
y,
|
|
||||||
w - 2 * cornerWidth,
|
|
||||||
cornerHeight });
|
|
||||||
}
|
|
||||||
if (parts & RectPart::Bottom) {
|
|
||||||
fillBg({
|
|
||||||
x + cornerWidth,
|
|
||||||
y + h - cornerHeight,
|
|
||||||
w - 2 * cornerWidth,
|
|
||||||
cornerHeight });
|
|
||||||
if (sh) {
|
|
||||||
fillSh({
|
|
||||||
x + cornerWidth,
|
|
||||||
y + h,
|
|
||||||
w - 2 * cornerWidth,
|
|
||||||
st::msgShadow });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (h > 2 * cornerHeight) {
|
|
||||||
if ((parts & RectPart::NoTopBottom) == RectPart::NoTopBottom) {
|
|
||||||
fillBg({
|
|
||||||
x,
|
|
||||||
y + cornerHeight,
|
|
||||||
w,
|
|
||||||
h - 2 * cornerHeight });
|
|
||||||
} else {
|
|
||||||
if (parts & RectPart::Left) {
|
|
||||||
fillBg({
|
|
||||||
x,
|
|
||||||
y + cornerHeight,
|
|
||||||
cornerWidth,
|
|
||||||
h - 2 * cornerHeight });
|
|
||||||
}
|
|
||||||
if ((parts & RectPart::Center) && w > 2 * cornerWidth) {
|
|
||||||
fillBg({
|
|
||||||
x + cornerWidth,
|
|
||||||
y + cornerHeight,
|
|
||||||
w - 2 * cornerWidth,
|
|
||||||
h - 2 * cornerHeight });
|
|
||||||
}
|
|
||||||
if (parts & RectPart::Right) {
|
|
||||||
fillBg({
|
|
||||||
x + w - cornerWidth,
|
|
||||||
y + cornerHeight,
|
|
||||||
cornerWidth,
|
|
||||||
h - 2 * cornerHeight });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parts & RectPart::TopLeft) {
|
|
||||||
fillCorner(x, y, 0);
|
|
||||||
}
|
|
||||||
if (parts & RectPart::TopRight) {
|
|
||||||
fillCorner(x + w - cornerWidth, y, 1);
|
|
||||||
}
|
|
||||||
if (parts & RectPart::BottomLeft) {
|
|
||||||
fillCorner(x, y + h - cornerHeight, 2);
|
|
||||||
}
|
|
||||||
if (parts & RectPart::BottomRight) {
|
|
||||||
fillCorner(x + w - cornerWidth, y + h - cornerHeight, 3);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const auto paintTail = [&](QPoint bottomPosition) {
|
const auto paintTail = [&](QPoint bottomPosition) {
|
||||||
const auto position = bottomPosition - tailShift;
|
const auto position = bottomPosition - tailShift;
|
||||||
fillPattern(position.x(), position.y(), tail, pattern->tailCache);
|
fillPattern(position.x(), position.y(), tail, pattern->tailCache);
|
||||||
return tail.width() / int(tail.devicePixelRatio());
|
return tail.width() / int(tail.devicePixelRatio());
|
||||||
};
|
};
|
||||||
|
|
||||||
p.setOpacity(opacity);
|
p.setOpacity(opacity);
|
||||||
PaintBubbleGeneric(args, fillBg, fillSh, fillRounded, paintTail);
|
PaintBubbleGeneric(args, fillBg, fillSh, fillCorner, paintTail);
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintSolidBubble(QPainter &p, const SimpleBubble &args) {
|
void PaintSolidBubble(QPainter &p, const SimpleBubble &args) {
|
||||||
const auto &st = args.st->messageStyle(args.outbg, args.selected);
|
const auto &st = args.st->messageStyle(args.outbg, args.selected);
|
||||||
const auto &bg = st.msgBg;
|
const auto &bg = st.msgBg;
|
||||||
const auto sh = (args.skip & RectPart::Bottom)
|
const auto sh = (args.rounding.bottomRight == Corner::None)
|
||||||
? nullptr
|
? nullptr
|
||||||
: &st.msgShadow;
|
: &st.msgShadow;
|
||||||
const auto &tail = (args.tailSide == RectPart::Right)
|
const auto &tail = (args.rounding.bottomRight == Corner::Tail)
|
||||||
? st.tailRight
|
? st.tailRight
|
||||||
: st.tailLeft;
|
: st.tailLeft;
|
||||||
const auto tailShift = (args.tailSide == RectPart::Right)
|
const auto tailShift = (args.rounding.bottomRight == Corner::Tail)
|
||||||
? QPoint(0, tail.height())
|
? QPoint(0, tail.height())
|
||||||
: QPoint(tail.width(), tail.height());
|
: QPoint(tail.width(), tail.height());
|
||||||
|
|
||||||
PaintBubbleGeneric(args, [&](const QRect &rect) {
|
PaintBubbleGeneric(args, [&](const QRect &rect) {
|
||||||
p.fillRect(rect, bg);
|
p.fillRect(rect, bg);
|
||||||
}, [&](const QRect &rect) {
|
}, [&](const QRect &rect) {
|
||||||
p.fillRect(rect, *sh);
|
p.fillRect(rect, *sh);
|
||||||
}, [&](const QRect &rect, RectParts parts) {
|
}, [&](int x, int y, int index, Corner size) {
|
||||||
Ui::FillRoundRect(p, rect, bg, st.msgBgCorners, sh, parts);
|
auto &corners = (size == Corner::Large)
|
||||||
|
? st.msgBgCornersLarge
|
||||||
|
: st.msgBgCornersSmall;
|
||||||
|
const auto &corner = corners.p[index];
|
||||||
|
p.drawPixmap(x, y, corners.p[index]);
|
||||||
}, [&](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();
|
||||||
|
@ -246,7 +249,8 @@ void PaintSolidBubble(QPainter &p, const SimpleBubble &args) {
|
||||||
std::unique_ptr<BubblePattern> PrepareBubblePattern(
|
std::unique_ptr<BubblePattern> PrepareBubblePattern(
|
||||||
not_null<const style::palette*> st) {
|
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->cornersSmall = Images::CornersMask(st::bubbleRadiusSmall);
|
||||||
|
result->cornersLarge = Images::CornersMask(st::bubbleRadiusLarge);
|
||||||
const auto addShadow = [&](QImage &bottomCorner) {
|
const auto addShadow = [&](QImage &bottomCorner) {
|
||||||
auto result = QImage(
|
auto result = QImage(
|
||||||
bottomCorner.width(),
|
bottomCorner.width(),
|
||||||
|
@ -264,13 +268,19 @@ std::unique_ptr<BubblePattern> PrepareBubblePattern(
|
||||||
|
|
||||||
bottomCorner = std::move(result);
|
bottomCorner = std::move(result);
|
||||||
};
|
};
|
||||||
addShadow(result->corners[2]);
|
addShadow(result->cornersSmall[2]);
|
||||||
addShadow(result->corners[3]);
|
addShadow(result->cornersSmall[3]);
|
||||||
result->cornerTopCache = QImage(
|
result->cornerTopSmallCache = QImage(
|
||||||
result->corners[0].size(),
|
result->cornersSmall[0].size(),
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
result->cornerBottomCache = QImage(
|
result->cornerTopLargeCache = QImage(
|
||||||
result->corners[2].size(),
|
result->cornersLarge[0].size(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result->cornerBottomSmallCache = QImage(
|
||||||
|
result->cornersSmall[2].size(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result->cornerBottomLargeCache = QImage(
|
||||||
|
result->cornersLarge[2].size(),
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -305,40 +315,52 @@ void PaintBubble(QPainter &p, const ComplexBubble &args) {
|
||||||
const auto width = rect.width();
|
const auto width = rect.width();
|
||||||
const auto top = rect.y();
|
const auto top = rect.y();
|
||||||
const auto bottom = top + rect.height();
|
const auto bottom = top + rect.height();
|
||||||
const auto paintOne = [&](QRect geometry, bool selected, RectParts skip) {
|
const auto paintOne = [&](
|
||||||
|
QRect geometry,
|
||||||
|
bool selected,
|
||||||
|
bool fromTop,
|
||||||
|
bool tillBottom) {
|
||||||
auto simple = args.simple;
|
auto simple = args.simple;
|
||||||
simple.geometry = geometry;
|
simple.geometry = geometry;
|
||||||
simple.selected = selected;
|
simple.selected = selected;
|
||||||
simple.skip = skip;
|
if (!fromTop) {
|
||||||
|
simple.rounding.topLeft
|
||||||
|
= simple.rounding.topRight
|
||||||
|
= Corner::None;
|
||||||
|
}
|
||||||
|
if (!tillBottom) {
|
||||||
|
simple.rounding.bottomLeft
|
||||||
|
= simple.rounding.bottomRight
|
||||||
|
= Corner::None;
|
||||||
|
simple.shadowed = false;
|
||||||
|
}
|
||||||
PaintBubble(p, simple);
|
PaintBubble(p, simple);
|
||||||
};
|
};
|
||||||
auto from = top;
|
auto from = top;
|
||||||
for (const auto &selected : args.selection) {
|
for (const auto &selected : args.selection) {
|
||||||
if (selected.top > from) {
|
if (selected.top > from) {
|
||||||
const auto skip = RectPart::Bottom
|
const auto fromTop = (from <= top);
|
||||||
| (from > top ? RectPart::Top : RectPart::None);
|
|
||||||
paintOne(
|
paintOne(
|
||||||
QRect(left, from, width, selected.top - from),
|
QRect(left, from, width, selected.top - from),
|
||||||
false,
|
false,
|
||||||
skip);
|
(from <= top),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
const auto skip = ((selected.top > top)
|
const auto fromTop = (selected.top <= top);
|
||||||
? RectPart::Top
|
const auto tillBottom = (selected.top + selected.height >= bottom);
|
||||||
: RectPart::None)
|
|
||||||
| ((selected.top + selected.height < bottom)
|
|
||||||
? RectPart::Bottom
|
|
||||||
: RectPart::None);
|
|
||||||
paintOne(
|
paintOne(
|
||||||
QRect(left, selected.top, width, selected.height),
|
QRect(left, selected.top, width, selected.height),
|
||||||
true,
|
true,
|
||||||
skip);
|
(selected.top <= top),
|
||||||
|
(selected.top + selected.height >= bottom));
|
||||||
from = selected.top + selected.height;
|
from = selected.top + selected.height;
|
||||||
}
|
}
|
||||||
if (from < bottom) {
|
if (from < bottom) {
|
||||||
paintOne(
|
paintOne(
|
||||||
QRect(left, from, width, bottom - from),
|
QRect(left, from, width, bottom - from),
|
||||||
false,
|
false,
|
||||||
RectPart::Top);
|
false,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,20 @@ namespace Ui {
|
||||||
class ChatTheme;
|
class ChatTheme;
|
||||||
class ChatStyle;
|
class ChatStyle;
|
||||||
|
|
||||||
|
enum class BubbleCornerRounding : uchar {
|
||||||
|
Large,
|
||||||
|
Small,
|
||||||
|
None,
|
||||||
|
Tail,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BubbleRounding {
|
||||||
|
BubbleCornerRounding topLeft = BubbleCornerRounding();
|
||||||
|
BubbleCornerRounding topRight = BubbleCornerRounding();
|
||||||
|
BubbleCornerRounding bottomLeft = BubbleCornerRounding();
|
||||||
|
BubbleCornerRounding bottomRight = BubbleCornerRounding();
|
||||||
|
};
|
||||||
|
|
||||||
struct BubbleSelectionInterval {
|
struct BubbleSelectionInterval {
|
||||||
int top = 0;
|
int top = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
@ -23,11 +37,14 @@ struct BubbleSelectionInterval {
|
||||||
|
|
||||||
struct BubblePattern {
|
struct BubblePattern {
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
std::array<QImage, 4> corners;
|
std::array<QImage, 4> cornersSmall;
|
||||||
|
std::array<QImage, 4> cornersLarge;
|
||||||
QImage tailLeft;
|
QImage tailLeft;
|
||||||
QImage tailRight;
|
QImage tailRight;
|
||||||
mutable QImage cornerTopCache;
|
mutable QImage cornerTopSmallCache;
|
||||||
mutable QImage cornerBottomCache;
|
mutable QImage cornerTopLargeCache;
|
||||||
|
mutable QImage cornerBottomSmallCache;
|
||||||
|
mutable QImage cornerBottomLargeCache;
|
||||||
mutable QImage tailCache;
|
mutable QImage tailCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,9 +59,9 @@ struct SimpleBubble {
|
||||||
QRect patternViewport;
|
QRect patternViewport;
|
||||||
int outerWidth = 0;
|
int outerWidth = 0;
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
bool shadowed = true;
|
||||||
bool outbg = false;
|
bool outbg = false;
|
||||||
RectPart tailSide = RectPart::None;
|
BubbleRounding rounding;
|
||||||
RectParts skip = RectPart::None;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ComplexBubble {
|
struct ComplexBubble {
|
||||||
|
|
|
@ -771,9 +771,9 @@ void Generator::paintBubble(const Bubble &bubble) {
|
||||||
auto y = _historyBottom - st::msgMargin.bottom() - height;
|
auto y = _historyBottom - st::msgMargin.bottom() - height;
|
||||||
auto bubbleTop = y;
|
auto bubbleTop = y;
|
||||||
auto bubbleHeight = height;
|
auto bubbleHeight = height;
|
||||||
if (isPhoto) {
|
if (isPhoto) { // #TODO rounding
|
||||||
bubbleTop -= st::historyMessageRadius + 1;
|
bubbleTop -= st::bubbleRadiusSmall + 1;
|
||||||
bubbleHeight += st::historyMessageRadius + 1;
|
bubbleHeight += st::bubbleRadiusSmall + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto left = bubble.outbg ? st::msgMargin.right() : st::msgMargin.left();
|
auto left = bubble.outbg ? st::msgMargin.right() : st::msgMargin.left();
|
||||||
|
@ -783,20 +783,20 @@ void Generator::paintBubble(const Bubble &bubble) {
|
||||||
x += left;
|
x += left;
|
||||||
|
|
||||||
_p->setPen(Qt::NoPen);
|
_p->setPen(Qt::NoPen);
|
||||||
auto tailclip = st::historyMessageRadius + 1;
|
auto tailclip = st::bubbleRadiusSmall +1;
|
||||||
if (bubble.tail) {
|
if (bubble.tail) {
|
||||||
if (bubble.outbg) {
|
if (bubble.outbg) {
|
||||||
_p->setClipRegion(QRegion(_history) - QRect(x + bubble.width - tailclip, bubbleTop + bubbleHeight - tailclip, tailclip + st::historyMessageRadius, tailclip + st::historyMessageRadius));
|
_p->setClipRegion(QRegion(_history) - QRect(x + bubble.width - tailclip, bubbleTop + bubbleHeight - tailclip, tailclip + st::bubbleRadiusSmall, tailclip + st::bubbleRadiusSmall));
|
||||||
} else {
|
} else {
|
||||||
_p->setClipRegion(QRegion(_history) - QRect(x - st::historyMessageRadius, bubbleTop + bubbleHeight - tailclip, tailclip + st::historyMessageRadius, tailclip + st::historyMessageRadius));
|
_p->setClipRegion(QRegion(_history) - QRect(x - st::bubbleRadiusSmall, bubbleTop + bubbleHeight - tailclip, tailclip + st::bubbleRadiusSmall, tailclip + st::bubbleRadiusSmall));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto sh = bubble.outbg ? st::msgOutShadow[_palette] : st::msgInShadow[_palette];
|
auto sh = bubble.outbg ? st::msgOutShadow[_palette] : st::msgInShadow[_palette];
|
||||||
_p->setBrush(sh);
|
_p->setBrush(sh);
|
||||||
_p->drawRoundedRect(x, bubbleTop + st::msgShadow, bubble.width, bubbleHeight, st::historyMessageRadius, st::historyMessageRadius);
|
_p->drawRoundedRect(x, bubbleTop + st::msgShadow, bubble.width, bubbleHeight, st::bubbleRadiusSmall, st::bubbleRadiusSmall);
|
||||||
auto bg = bubble.outbg ? st::msgOutBg[_palette] : st::msgInBg[_palette];
|
auto bg = bubble.outbg ? st::msgOutBg[_palette] : st::msgInBg[_palette];
|
||||||
_p->setBrush(bg);
|
_p->setBrush(bg);
|
||||||
_p->drawRoundedRect(x, bubbleTop, bubble.width, bubbleHeight, st::historyMessageRadius, st::historyMessageRadius);
|
_p->drawRoundedRect(x, bubbleTop, bubble.width, bubbleHeight, st::bubbleRadiusSmall, st::bubbleRadiusSmall);
|
||||||
if (bubble.tail) {
|
if (bubble.tail) {
|
||||||
_p->setClipRect(_history);
|
_p->setClipRect(_history);
|
||||||
if (bubble.outbg) {
|
if (bubble.outbg) {
|
||||||
|
|
|
@ -242,7 +242,7 @@ void CloudListCheck::paintNotSupported(
|
||||||
|
|
||||||
const auto height = st::settingsThemePreviewSize.height();
|
const auto height = st::settingsThemePreviewSize.height();
|
||||||
const auto rect = QRect(0, 0, outerWidth, height);
|
const auto rect = QRect(0, 0, outerWidth, height);
|
||||||
const auto radius = st::historyMessageRadius;
|
const auto radius = st::roundRadiusLarge;
|
||||||
p.drawRoundedRect(rect, radius, radius);
|
p.drawRoundedRect(rect, radius, radius);
|
||||||
st::settingsThemeNotSupportedIcon.paintInCenter(p, rect);
|
st::settingsThemeNotSupportedIcon.paintInCenter(p, rect);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_layers.h" // st::boxLabel
|
#include "styles/style_layers.h" // st::boxLabel
|
||||||
#include "styles/style_chat.h" // st::historyMessageRadius
|
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
Loading…
Add table
Reference in a new issue