2016-12-23 16:21:01 +03:00
/*
This file is part of Telegram Desktop ,
2018-01-03 13:23:14 +03:00
the official desktop application for the Telegram messaging service .
2016-12-23 16:21:01 +03:00
2018-01-03 13:23:14 +03:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2016-12-23 16:21:01 +03:00
*/
2017-02-03 23:07:26 +03:00
# include "window/themes/window_theme_preview.h"
2016-12-23 16:21:01 +03:00
2023-08-30 05:25:34 +03:00
# include "dialogs/dialogs_three_state_icon.h"
2017-04-13 11:27:10 +03:00
# include "lang/lang_keys.h"
2016-12-23 16:21:01 +03:00
# include "platform/platform_window_title.h"
2020-10-10 12:15:37 +03:00
# include "ui/text/text_options.h"
2022-01-05 01:06:03 +03:00
# include "ui/text/text_utilities.h"
2022-12-03 20:59:48 +03:00
# include "ui/empty_userpic.h"
2018-10-23 13:44:42 +04:00
# include "ui/emoji_config.h"
2022-09-17 00:23:27 +04:00
# include "ui/painter.h"
2024-03-24 01:04:33 +03:00
# include "ui/rect.h"
2021-08-26 18:02:21 +03:00
# include "ui/chat/chat_theme.h"
2022-10-04 10:11:15 +04:00
# include "ui/chat/chat_style.h"
# include "ui/chat/message_bubble.h"
2016-12-23 16:21:01 +03:00
# include "styles/style_widgets.h"
# include "styles/style_window.h"
2020-02-03 13:26:37 +04:00
# include "styles/style_media_view.h"
2020-10-10 12:15:37 +03:00
# include "styles/style_chat.h"
2023-05-16 19:48:49 +04:00
# include "styles/style_chat_helpers.h"
2016-12-23 16:21:01 +03:00
# include "styles/style_dialogs.h"
2017-12-07 19:01:41 +04:00
# include "styles/style_info.h"
2016-12-23 16:21:01 +03:00
namespace Window {
namespace Theme {
namespace {
2023-09-06 14:24:32 +03:00
[[nodiscard]] QString FillLetters ( const QString & name ) {
2016-12-29 13:03:51 +04:00
QList < QString > letters ;
QList < int > levels ;
auto level = 0 ;
auto letterFound = false ;
auto ch = name . constData ( ) , end = ch + name . size ( ) ;
while ( ch ! = end ) {
auto emojiLength = 0 ;
2021-07-14 02:16:03 +04:00
if ( Ui : : Emoji : : Find ( ch , end , & emojiLength ) ) {
2016-12-29 13:03:51 +04:00
ch + = emojiLength ;
} else if ( ch - > isHighSurrogate ( ) ) {
+ + ch ;
if ( ch ! = end & & ch - > isLowSurrogate ( ) ) {
+ + ch ;
}
} else if ( ! letterFound & & ch - > isLetterOrNumber ( ) ) {
letterFound = true ;
2023-10-03 17:50:33 +04:00
if ( ch + 1 ! = end & & Ui : : Text : : IsDiacritic ( * ( ch + 1 ) ) ) {
2016-12-29 13:03:51 +04:00
letters . push_back ( QString ( ch , 2 ) ) ;
levels . push_back ( level ) ;
+ + ch ;
} else {
letters . push_back ( QString ( ch , 1 ) ) ;
levels . push_back ( level ) ;
}
+ + ch ;
} else {
if ( * ch = = ' ' ) {
level = 0 ;
letterFound = false ;
} else if ( letterFound & & * ch = = ' - ' ) {
level = 1 ;
letterFound = true ;
}
+ + ch ;
}
}
// We prefer the second letter to be after ' ', but it can also be after '-'.
auto result = QString ( ) ;
if ( ! letters . isEmpty ( ) ) {
result + = letters . front ( ) ;
auto bestIndex = 0 ;
auto bestLevel = 2 ;
for ( auto i = letters . size ( ) ; i ! = 1 ; ) {
if ( levels [ - - i ] < bestLevel ) {
bestIndex = i ;
bestLevel = levels [ i ] ;
}
}
if ( bestIndex > 0 ) {
result + = letters [ bestIndex ] ;
}
}
return result . toUpper ( ) ;
}
2016-12-23 16:21:01 +03:00
class Generator {
public :
2019-09-09 14:56:05 +03:00
Generator (
const Instance & theme ,
CurrentData & & current ,
PreviewType type ) ;
2016-12-23 16:21:01 +03:00
2019-09-09 14:56:05 +03:00
[[nodiscard]] QImage generate ( ) ;
2016-12-23 16:21:01 +03:00
private :
enum class Status {
None ,
Sent ,
Received
} ;
struct Row {
2019-06-12 15:26:04 +02:00
Ui : : Text : : String name ;
2016-12-29 13:03:51 +04:00
QString letters ;
2016-12-23 16:21:01 +03:00
enum class Type {
User ,
Group ,
Channel
} ;
Type type = Type : : User ;
int peerIndex = 0 ;
int unreadCounter = 0 ;
bool muted = false ;
bool pinned = false ;
QString date ;
2019-06-12 15:26:04 +02:00
Ui : : Text : : String text ;
2016-12-23 16:21:01 +03:00
Status status = Status : : None ;
bool selected = false ;
bool active = false ;
} ;
struct Bubble {
int width = 0 ;
int height = 0 ;
bool outbg = false ;
Status status = Status : : None ;
QString date ;
2022-10-04 10:11:15 +04:00
bool attachToTop = false ;
bool attachToBottom = false ;
2016-12-23 16:21:01 +03:00
bool tail = true ;
2019-06-12 15:26:04 +02:00
Ui : : Text : : String text = { st : : msgMinWidth } ;
2016-12-23 16:21:01 +03:00
QVector < int > waveform ;
int waveactive = 0 ;
QString wavestatus ;
QImage photo ;
int photoWidth = 0 ;
int photoHeight = 0 ;
2019-06-12 15:26:04 +02:00
Ui : : Text : : String replyName = { st : : msgMinWidth } ;
Ui : : Text : : String replyText = { st : : msgMinWidth } ;
2016-12-23 16:21:01 +03:00
} ;
2019-09-09 14:56:05 +03:00
[[nodiscard]] bool extended ( ) const ;
2016-12-23 16:21:01 +03:00
void prepare ( ) ;
2022-01-05 01:06:03 +03:00
void addRow (
QString name ,
int peerIndex ,
QString date ,
const TextWithEntities & text ) ;
2016-12-23 16:21:01 +03:00
void addBubble ( Bubble bubble , int width , int height , QString date , Status status ) ;
void addAudioBubble ( QVector < int > waveform , int waveactive , QString wavestatus , QString date , Status status ) ;
void addTextBubble ( QString text , QString date , Status status ) ;
void addDateBubble ( QString date ) ;
void addPhotoBubble ( QString image , QString caption , QString date , Status status ) ;
QSize computeSkipBlock ( Status status , QString date ) ;
int computeInfoWidth ( Status status , QString date ) ;
void generateData ( ) ;
void paintHistoryList ( ) ;
void paintHistoryBackground ( ) ;
void paintTopBar ( ) ;
void paintComposeArea ( ) ;
void paintDialogs ( ) ;
void paintDialogsList ( ) ;
void paintHistoryShadows ( ) ;
void paintRow ( const Row & row ) ;
void paintBubble ( const Bubble & bubble ) ;
void paintService ( QString text ) ;
2016-12-29 13:03:51 +04:00
void paintUserpic ( int x , int y , Row : : Type type , int index , QString letters ) ;
2016-12-23 16:21:01 +03:00
void setTextPalette ( const style : : TextPalette & st ) ;
void restoreTextPalette ( ) ;
const Instance & _theme ;
const style : : palette & _palette ;
2019-09-09 14:56:05 +03:00
const CurrentData _current ;
const PreviewType _type ;
2022-10-04 10:11:15 +04:00
Ui : : ChatStyle _st ;
2016-12-23 16:21:01 +03:00
Painter * _p = nullptr ;
QRect _rect ;
QRect _inner ;
QRect _body ;
QRect _dialogs ;
QRect _dialogsList ;
QRect _topBar ;
QRect _composeArea ;
QRect _history ;
int _rowsTop = 0 ;
2017-02-21 16:45:56 +03:00
std : : vector < Row > _rows ;
2016-12-23 16:21:01 +03:00
2019-06-12 15:26:04 +02:00
Ui : : Text : : String _topBarName ;
2016-12-23 16:21:01 +03:00
QString _topBarStatus ;
bool _topBarStatusActive = false ;
int _historyBottom = 0 ;
2017-02-21 16:45:56 +03:00
std : : vector < Bubble > _bubbles ;
2016-12-23 16:21:01 +03:00
style : : TextPalette _textPalette ;
} ;
2019-09-09 14:56:05 +03:00
bool Generator : : extended ( ) const {
return ( _type = = PreviewType : : Extended ) ;
}
2016-12-23 16:21:01 +03:00
void Generator : : prepare ( ) {
2019-09-09 14:56:05 +03:00
const auto size = extended ( )
? QRect (
QPoint ( ) ,
st : : themePreviewSize ) . marginsAdded ( st : : themePreviewMargin ) . size ( )
: st : : themePreviewSize ;
_rect = QRect ( QPoint ( ) , size ) ;
_inner = extended ( ) ? _rect . marginsRemoved ( st : : themePreviewMargin ) : _rect ;
_body = extended ( ) ? _inner . marginsRemoved ( QMargins ( 0 , Platform : : PreviewTitleHeight ( ) , 0 , 0 ) ) : _inner ;
2016-12-23 16:21:01 +03:00
_dialogs = QRect ( _body . x ( ) , _body . y ( ) , st : : themePreviewDialogsWidth , _body . height ( ) ) ;
2022-09-29 14:33:17 +04:00
_dialogsList = _dialogs . marginsRemoved ( QMargins ( 0 , st : : dialogsFilterPadding . y ( ) + st : : dialogsMenuToggle . height + st : : dialogsFilterPadding . y ( ) , 0 , st : : defaultDialogRow . padding . bottom ( ) ) ) ;
2016-12-23 16:21:01 +03:00
_topBar = QRect ( _dialogs . x ( ) + _dialogs . width ( ) , _dialogs . y ( ) , _body . width ( ) - _dialogs . width ( ) , st : : topBarHeight ) ;
2016-12-27 02:46:36 +04:00
_composeArea = QRect ( _topBar . x ( ) , _body . y ( ) + _body . height ( ) - st : : historySendSize . height ( ) , _topBar . width ( ) , st : : historySendSize . height ( ) ) ;
2016-12-23 16:21:01 +03:00
_history = QRect ( _topBar . x ( ) , _topBar . y ( ) + _topBar . height ( ) , _topBar . width ( ) , _body . height ( ) - _topBar . height ( ) - _composeArea . height ( ) ) ;
generateData ( ) ;
}
2022-01-05 01:06:03 +03:00
void Generator : : addRow (
QString name ,
int peerIndex ,
QString date ,
const TextWithEntities & text ) {
2016-12-23 16:21:01 +03:00
Row row ;
2017-12-28 16:06:06 +03:00
row . name . setText ( st : : msgNameStyle , name , Ui : : NameTextOptions ( ) ) ;
2016-12-29 13:03:51 +04:00
2023-09-06 14:24:32 +03:00
row . letters = FillLetters ( name ) ;
2016-12-29 13:03:51 +04:00
2016-12-23 16:21:01 +03:00
row . peerIndex = peerIndex ;
row . date = date ;
2022-01-05 01:06:03 +03:00
row . text . setMarkedText (
st : : dialogsTextStyle ,
text ,
Ui : : DialogTextOptions ( ) ) ;
2017-02-21 16:45:56 +03:00
_rows . push_back ( std : : move ( row ) ) ;
2016-12-23 16:21:01 +03:00
}
void Generator : : addBubble ( Bubble bubble , int width , int height , QString date , Status status ) {
bubble . width = width ;
bubble . height = height ;
bubble . date = date ;
bubble . status = status ;
2017-02-21 16:45:56 +03:00
_bubbles . push_back ( std : : move ( bubble ) ) ;
2016-12-23 16:21:01 +03:00
}
void Generator : : addAudioBubble ( QVector < int > waveform , int waveactive , QString wavestatus , QString date , Status status ) {
Bubble bubble ;
bubble . waveform = waveform ;
bubble . waveactive = waveactive ;
bubble . wavestatus = wavestatus ;
auto skipBlock = computeSkipBlock ( status , date ) ;
auto width = st : : msgFileMinWidth ;
2020-10-19 18:37:59 +03:00
const auto & st = st : : msgFileLayout ;
2022-09-30 11:23:32 +04:00
auto tleft = st . padding . left ( ) + st . thumbSize + st . thumbSkip ;
2016-12-23 16:21:01 +03:00
accumulate_max ( width , tleft + st : : normalFont - > width ( wavestatus ) + skipBlock . width ( ) + st : : msgPadding . right ( ) ) ;
accumulate_min ( width , st : : msgMaxWidth ) ;
2020-10-19 18:37:59 +03:00
auto height = st . padding . top ( ) + st . thumbSize + st . padding . bottom ( ) ;
2017-02-21 16:45:56 +03:00
addBubble ( std : : move ( bubble ) , width , height , date , status ) ;
2016-12-23 16:21:01 +03:00
}
QSize Generator : : computeSkipBlock ( Status status , QString date ) {
auto infoWidth = computeInfoWidth ( status , date ) ;
auto width = st : : msgDateSpace + infoWidth - st : : msgDateDelta . x ( ) ;
auto height = st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ;
return QSize ( width , height ) ;
}
int Generator : : computeInfoWidth ( Status status , QString date ) {
auto result = st : : msgDateFont - > width ( date ) ;
if ( status ! = Status : : None ) {
result + = st : : historySendStateSpace ;
}
return result ;
}
void Generator : : addTextBubble ( QString text , QString date , Status status ) {
Bubble bubble ;
auto skipBlock = computeSkipBlock ( status , date ) ;
2022-01-05 03:18:36 +03:00
auto marked = TextWithEntities { std : : move ( text ) } ;
bubble . text . setMarkedText (
st : : messageTextStyle ,
std : : move ( marked ) ,
Ui : : ItemTextDefaultOptions ( ) ) ;
bubble . text . updateSkipBlock ( skipBlock . width ( ) , skipBlock . height ( ) ) ;
2016-12-23 16:21:01 +03:00
auto width = _history . width ( ) - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
accumulate_min ( width , st : : msgPadding . left ( ) + bubble . text . maxWidth ( ) + st : : msgPadding . right ( ) ) ;
accumulate_min ( width , st : : msgMaxWidth ) ;
auto textWidth = qMax ( width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , 1 ) ;
auto textHeight = bubble . text . countHeight ( textWidth ) ;
auto height = st : : msgPadding . top ( ) + textHeight + st : : msgPadding . bottom ( ) ;
2017-02-21 16:45:56 +03:00
addBubble ( std : : move ( bubble ) , width , height , date , status ) ;
2016-12-23 16:21:01 +03:00
}
void Generator : : addDateBubble ( QString date ) {
Bubble bubble ;
2017-02-21 16:45:56 +03:00
addBubble ( std : : move ( bubble ) , 0 , 0 , date , Status : : None ) ;
2016-12-23 16:21:01 +03:00
}
void Generator : : addPhotoBubble ( QString image , QString caption , QString date , Status status ) {
Bubble bubble ;
bubble . photo . load ( image ) ;
2019-09-13 13:24:06 +03:00
bubble . photoWidth = style : : ConvertScale ( bubble . photo . width ( ) / 2 ) ;
bubble . photoHeight = style : : ConvertScale ( bubble . photo . height ( ) / 2 ) ;
2016-12-23 16:21:01 +03:00
auto skipBlock = computeSkipBlock ( status , date ) ;
2022-01-05 03:18:36 +03:00
auto marked = TextWithEntities { std : : move ( caption ) } ;
bubble . text . setMarkedText (
st : : messageTextStyle ,
std : : move ( marked ) ,
Ui : : ItemTextDefaultOptions ( ) ) ;
bubble . text . updateSkipBlock ( skipBlock . width ( ) , skipBlock . height ( ) ) ;
2016-12-23 16:21:01 +03:00
auto width = _history . width ( ) - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
accumulate_min ( width , bubble . photoWidth ) ;
accumulate_min ( width , st : : msgMaxWidth ) ;
auto textWidth = qMax ( width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , 1 ) ;
auto textHeight = bubble . text . countHeight ( textWidth ) ;
auto height = st : : mediaCaptionSkip + textHeight + st : : msgPadding . bottom ( ) ;
2017-02-21 16:45:56 +03:00
addBubble ( std : : move ( bubble ) , width , height , date , status ) ;
2016-12-23 16:21:01 +03:00
}
void Generator : : generateData ( ) {
_rows . reserve ( 9 ) ;
2022-01-05 01:06:03 +03:00
addRow (
" Eva Summer " ,
0 ,
" 11:00 " ,
{ . text = " We are too smart for this world. "
+ QString : : fromUtf8 ( " \xf0 \x9f \xa4 \xa3 \xf0 \x9f \x98 \x82 " ) } ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . active = true ;
_rows . back ( ) . pinned = true ;
2022-01-05 01:06:03 +03:00
addRow ( " Alexandra Smith " , 7 , " 10:00 " , { . text = " This is amazing! " } ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . unreadCounter = 2 ;
2022-01-05 01:06:03 +03:00
addRow (
" Mike Apple " ,
2 ,
" 9:00 " ,
2023-10-03 17:50:33 +04:00
Ui : : Text : : Colorized ( QChar ( 55357 )
2022-01-05 01:06:03 +03:00
+ QString ( )
+ QChar ( 56836 )
+ " Sticker " ) ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . unreadCounter = 2 ;
_rows . back ( ) . muted = true ;
2023-10-03 17:50:33 +04:00
addRow ( " Evening Club " , 1 , " 8:00 " , Ui : : Text : : Colorized ( " Eva: Photo " ) ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . type = Row : : Type : : Group ;
2022-01-05 01:06:03 +03:00
addRow (
" Old Pirates " ,
6 ,
" 7:00 " ,
2023-10-03 17:50:33 +04:00
Ui : : Text : : Colorized ( " Max: " ) . append ( " Yo-ho-ho! " ) ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . type = Row : : Type : : Group ;
2022-01-05 01:06:03 +03:00
addRow ( " Max Bright " , 3 , " 6:00 " , { . text = " How about some coffee? " } ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . status = Status : : Received ;
2022-01-05 01:06:03 +03:00
addRow ( " Natalie Parker " , 4 , " 5:00 " , { . text = " OK, great) " } ) ;
2016-12-23 16:21:01 +03:00
_rows . back ( ) . status = Status : : Received ;
2023-10-03 17:50:33 +04:00
addRow ( " Davy Jones " , 5 , " 4:00 " , Ui : : Text : : Colorized ( " Keynote.pdf " ) ) ;
2016-12-23 16:21:01 +03:00
2017-12-28 16:06:06 +03:00
_topBarName . setText ( st : : msgNameStyle , " Eva Summer " , Ui : : NameTextOptions ( ) ) ;
2016-12-23 16:21:01 +03:00
_topBarStatus = " online " ;
_topBarStatusActive = true ;
2021-09-17 13:20:15 +03:00
addPhotoBubble ( " :/gui/art/themeimage.jpg " , " To reach a port, we must sail. " + QString : : fromUtf8 ( " \xf0 \x9f \xa5 \xb8 " ) , " 7:00 " , Status : : None ) ;
2016-12-23 16:21:01 +03:00
int wavedata [ ] = { 0 , 0 , 0 , 0 , 27 , 31 , 4 , 1 , 0 , 0 , 23 , 30 , 18 , 9 , 7 , 19 , 4 , 2 , 2 , 2 , 0 , 0 , 15 , 15 , 15 , 15 , 3 , 15 , 19 , 3 , 2 , 0 , 0 , 0 , 0 , 0 , 3 , 12 , 16 , 6 , 4 , 6 , 14 , 12 , 2 , 12 , 12 , 11 , 3 , 0 , 7 , 5 , 7 , 4 , 7 , 5 , 2 , 4 , 0 , 9 , 5 , 7 , 6 , 2 , 2 , 0 , 0 } ;
auto waveform = QVector < int > ( base : : array_size ( wavedata ) ) ;
memcpy ( waveform . data ( ) , wavedata , sizeof ( wavedata ) ) ;
addAudioBubble ( waveform , 33 , " 0:07 " , " 8:00 " , Status : : None ) ;
_bubbles . back ( ) . outbg = true ;
_bubbles . back ( ) . status = Status : : Received ;
addDateBubble ( " December 26 " ) ;
2021-09-17 13:20:15 +03:00
addTextBubble ( " Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. " + QString : : fromUtf8 ( " \xf0 \x9f \xa7 \x90 " ) , " 10:00 " , Status : : Received ) ;
2016-12-23 16:21:01 +03:00
_bubbles . back ( ) . tail = false ;
_bubbles . back ( ) . outbg = true ;
2022-10-04 10:11:15 +04:00
_bubbles . back ( ) . attachToBottom = true ;
2021-09-17 13:20:15 +03:00
addTextBubble ( " Mark Twain said that " + QString : : fromUtf8 ( " \xe2 \x98 \x9d \xef \xb8 \x8f " ) , " 10:00 " , Status : : Received ) ;
2016-12-23 16:21:01 +03:00
_bubbles . back ( ) . outbg = true ;
2022-10-04 10:11:15 +04:00
_bubbles . back ( ) . attachToTop = true ;
2016-12-23 16:21:01 +03:00
_bubbles . back ( ) . tail = true ;
2021-09-17 13:20:15 +03:00
addTextBubble ( " We are too smart for this world. " + QString : : fromUtf8 ( " \xf0 \x9f \xa4 \xa3 \xf0 \x9f \x98 \x82 " ) , " 11:00 " , Status : : None ) ;
2017-12-28 16:06:06 +03:00
_bubbles . back ( ) . replyName . setText ( st : : msgNameStyle , " Alex Cassio " , Ui : : NameTextOptions ( ) ) ;
2021-09-17 13:20:15 +03:00
_bubbles . back ( ) . replyText . setText ( st : : messageTextStyle , " Mark Twain said that " + QString : : fromUtf8 ( " \xe2 \x98 \x9d \xef \xb8 \x8f " ) , Ui : : DialogTextOptions ( ) ) ;
2016-12-23 16:21:01 +03:00
}
2019-09-09 14:56:05 +03:00
Generator : : Generator (
const Instance & theme ,
CurrentData & & current ,
PreviewType type )
2016-12-23 16:21:01 +03:00
: _theme ( theme )
, _palette ( _theme . palette )
2019-09-09 14:56:05 +03:00
, _current ( std : : move ( current ) )
2022-10-04 10:11:15 +04:00
, _type ( type )
, _st ( & _palette ) {
2016-12-23 16:21:01 +03:00
}
2018-01-02 22:10:49 +03:00
QImage Generator : : generate ( ) {
2016-12-23 16:21:01 +03:00
prepare ( ) ;
2018-01-02 22:10:49 +03:00
auto result = QImage (
2024-03-24 01:04:33 +03:00
_rect . size ( ) * style : : DevicePixelRatio ( ) ,
2018-01-02 22:10:49 +03:00
QImage : : Format_ARGB32_Premultiplied ) ;
2024-03-24 01:04:33 +03:00
result . setDevicePixelRatio ( style : : DevicePixelRatio ( ) ) ;
2016-12-23 16:21:01 +03:00
result . fill ( st : : themePreviewBg - > c ) ;
{
Painter p ( & result ) ;
PainterHighQualityEnabler hq ( p ) ;
_p = & p ;
_p - > fillRect ( _body , QColor ( 0 , 0 , 0 ) ) ;
_p - > fillRect ( _body , st : : windowBg [ _palette ] ) ;
paintHistoryList ( ) ;
paintTopBar ( ) ;
paintComposeArea ( ) ;
paintDialogs ( ) ;
paintHistoryShadows ( ) ;
}
2019-09-09 14:56:05 +03:00
if ( extended ( ) ) {
Platform : : PreviewWindowFramePaint ( result , _palette , _body , _rect . width ( ) ) ;
}
2016-12-23 16:21:01 +03:00
2018-01-02 22:10:49 +03:00
return result ;
2016-12-23 16:21:01 +03:00
}
void Generator : : paintHistoryList ( ) {
paintHistoryBackground ( ) ;
_historyBottom = _history . y ( ) + _history . height ( ) ;
_historyBottom - = st : : historyPaddingBottom ;
2019-09-10 05:56:20 +03:00
_p - > setClipping ( true ) ;
2016-12-23 16:21:01 +03:00
for ( auto i = _bubbles . size ( ) ; i ! = 0 ; ) {
auto & bubble = _bubbles [ - - i ] ;
if ( bubble . width > 0 ) {
paintBubble ( bubble ) ;
} else {
paintService ( bubble . date ) ;
}
}
_p - > setClipping ( false ) ;
}
void Generator : : paintHistoryBackground ( ) {
auto fromy = ( - st : : topBarHeight ) ;
auto background = _theme . background ;
auto tiled = _theme . tiled ;
if ( background . isNull ( ) ) {
2019-01-28 16:59:49 +03:00
const auto fakePaper = Data : : WallPaper ( _current . backgroundId ) ;
if ( Data : : IsThemeWallPaper ( fakePaper ) ) {
2021-08-31 22:10:39 +03:00
background = Ui : : ReadBackgroundImage (
u " :/gui/art/background.tgv " _q ,
QByteArray ( ) ,
true ) ;
const auto paper = Data : : DefaultWallPaper ( ) ;
background = Ui : : PreparePatternImage (
std : : move ( background ) ,
paper . backgroundColors ( ) ,
paper . gradientRotation ( ) ,
paper . patternOpacity ( ) ) ;
2016-12-23 16:21:01 +03:00
tiled = false ;
} else {
2018-01-02 22:10:49 +03:00
background = std : : move ( _current . backgroundImage ) ;
2016-12-23 16:21:01 +03:00
tiled = _current . backgroundTiled ;
}
}
2018-01-02 22:10:49 +03:00
background = std : : move ( background ) . convertToFormat (
QImage : : Format_ARGB32_Premultiplied ) ;
2024-03-24 01:04:33 +03:00
background . setDevicePixelRatio ( style : : DevicePixelRatio ( ) ) ;
2016-12-23 16:21:01 +03:00
_p - > setClipRect ( _history ) ;
if ( tiled ) {
2017-01-01 20:45:20 +04:00
auto width = background . width ( ) ;
auto height = background . height ( ) ;
2024-03-24 01:04:33 +03:00
auto repeatTimesX = qCeil ( _history . width ( )
* style : : DevicePixelRatio ( )
/ float64 ( width ) ) ;
auto repeatTimesY = qCeil ( ( _history . height ( ) - fromy )
* style : : DevicePixelRatio ( )
/ float64 ( height ) ) ;
2018-01-02 22:10:49 +03:00
auto imageForTiled = QImage (
width * repeatTimesX ,
height * repeatTimesY ,
QImage : : Format_ARGB32_Premultiplied ) ;
2017-01-01 20:45:20 +04:00
imageForTiled . setDevicePixelRatio ( background . devicePixelRatio ( ) ) ;
auto imageForTiledBytes = imageForTiled . bits ( ) ;
auto bytesInLine = width * sizeof ( uint32 ) ;
for ( auto timesY = 0 ; timesY ! = repeatTimesY ; + + timesY ) {
auto imageBytes = background . constBits ( ) ;
for ( auto y = 0 ; y ! = height ; + + y ) {
for ( auto timesX = 0 ; timesX ! = repeatTimesX ; + + timesX ) {
memcpy ( imageForTiledBytes , imageBytes , bytesInLine ) ;
imageForTiledBytes + = bytesInLine ;
}
imageBytes + = background . bytesPerLine ( ) ;
2018-01-02 22:10:49 +03:00
imageForTiledBytes + = imageForTiled . bytesPerLine ( )
- ( repeatTimesX * bytesInLine ) ;
2016-12-23 16:21:01 +03:00
}
}
2017-01-01 20:45:20 +04:00
_p - > drawImage ( _history . x ( ) , _history . y ( ) + fromy , imageForTiled ) ;
2016-12-23 16:21:01 +03:00
} else {
PainterHighQualityEnabler hq ( * _p ) ;
2021-08-13 20:19:06 +03:00
auto fill = QSize ( _topBar . width ( ) , _body . height ( ) ) ;
2021-08-26 18:02:21 +03:00
const auto rects = Ui : : ComputeChatBackgroundRects (
fill ,
background . size ( ) ) ;
2021-08-13 20:19:06 +03:00
auto to = rects . to ;
2016-12-23 16:21:01 +03:00
to . moveTop ( to . top ( ) + fromy ) ;
to . moveTopLeft ( to . topLeft ( ) + _history . topLeft ( ) ) ;
2021-08-13 20:19:06 +03:00
_p - > drawImage ( to , background , rects . from ) ;
2016-12-23 16:21:01 +03:00
}
_p - > setClipping ( false ) ;
}
void Generator : : paintTopBar ( ) {
_p - > fillRect ( _topBar , st : : topBarBg [ _palette ] ) ;
auto right = st : : topBarMenuToggle . width ;
st : : topBarMenuToggle . icon [ _palette ] . paint ( * _p , _topBar . x ( ) + _topBar . width ( ) - right + st : : topBarMenuToggle . iconPosition . x ( ) , _topBar . y ( ) + st : : topBarMenuToggle . iconPosition . y ( ) , _rect . width ( ) ) ;
2020-12-14 19:56:01 +04:00
right + = st : : topBarSkip + st : : topBarCall . width ;
st : : topBarCall . icon [ _palette ] . paint ( * _p , _topBar . x ( ) + _topBar . width ( ) - right + st : : topBarCall . iconPosition . x ( ) , _topBar . y ( ) + st : : topBarCall . iconPosition . y ( ) , _rect . width ( ) ) ;
2016-12-23 16:21:01 +03:00
right + = st : : topBarSearch . width ;
st : : topBarSearch . icon [ _palette ] . paint ( * _p , _topBar . x ( ) + _topBar . width ( ) - right + st : : topBarSearch . iconPosition . x ( ) , _topBar . y ( ) + st : : topBarSearch . iconPosition . y ( ) , _rect . width ( ) ) ;
2017-07-05 16:11:08 +03:00
auto decreaseWidth = st : : topBarCall . width + st : : topBarCallSkip + st : : topBarSearch . width + st : : topBarMenuToggle . width ;
2016-12-23 16:21:01 +03:00
auto nameleft = _topBar . x ( ) + st : : topBarArrowPadding . right ( ) ;
auto nametop = _topBar . y ( ) + st : : topBarArrowPadding . top ( ) ;
auto statustop = _topBar . y ( ) + st : : topBarHeight - st : : topBarArrowPadding . bottom ( ) - st : : dialogsTextFont - > height ;
auto namewidth = _topBar . x ( ) + _topBar . width ( ) - decreaseWidth - nameleft - st : : topBarArrowPadding . right ( ) ;
_p - > setFont ( st : : dialogsTextFont ) ;
_p - > setPen ( _topBarStatusActive ? st : : historyStatusFgActive [ _palette ] : st : : historyStatusFg [ _palette ] ) ;
_p - > drawText ( nameleft , statustop + st : : dialogsTextFont - > ascent , _topBarStatus ) ;
_p - > setPen ( st : : dialogsNameFg [ _palette ] ) ;
_topBarName . drawElided ( * _p , nameleft , nametop , namewidth ) ;
}
void Generator : : paintComposeArea ( ) {
_p - > fillRect ( _composeArea , st : : historyReplyBg [ _palette ] ) ;
2016-12-27 02:46:36 +04:00
auto controlsTop = _composeArea . y ( ) + _composeArea . height ( ) - st : : historySendSize . height ( ) ;
2021-09-28 12:18:14 +04:00
const auto attachIconLeft = ( st : : historyAttach . iconPosition . x ( ) < 0 )
? ( ( st : : historyAttach . width - st : : historyAttach . icon . width ( ) ) / 2 )
: st : : historyAttach . iconPosition . x ( ) ;
const auto attachIconTop = ( st : : historyAttach . iconPosition . y ( ) < 0 )
? ( ( st : : historyAttach . height - st : : historyAttach . icon . height ( ) ) / 2 )
: st : : historyAttach . iconPosition . y ( ) ;
st : : historyAttach . icon [ _palette ] . paint ( * _p , _composeArea . x ( ) + attachIconLeft , controlsTop + attachIconTop , _rect . width ( ) ) ;
2016-12-27 02:46:36 +04:00
auto right = st : : historySendRight + st : : historySendSize . width ( ) ;
st : : historyRecordVoice [ _palette ] . paintInCenter ( * _p , QRect ( _composeArea . x ( ) + _composeArea . width ( ) - right , controlsTop , st : : historySendSize . width ( ) , st : : historySendSize . height ( ) ) ) ;
2016-12-23 16:21:01 +03:00
2023-05-16 19:48:49 +04:00
const auto & emojiButton = st : : historyAttachEmoji . inner ;
const auto emojiIconLeft = ( emojiButton . iconPosition . x ( ) < 0 )
? ( ( emojiButton . width - emojiButton . icon . width ( ) ) / 2 )
: emojiButton . iconPosition . x ( ) ;
const auto emojiIconTop = ( emojiButton . iconPosition . y ( ) < 0 )
? ( ( emojiButton . height - emojiButton . icon . height ( ) ) / 2 )
: emojiButton . iconPosition . y ( ) ;
const auto & emojiIcon = emojiButton . icon [ _palette ] ;
right + = emojiButton . width ;
2016-12-23 16:21:01 +03:00
auto attachEmojiLeft = _composeArea . x ( ) + _composeArea . width ( ) - right ;
2023-05-16 19:48:49 +04:00
_p - > fillRect ( attachEmojiLeft , controlsTop , emojiButton . width , emojiButton . height , st : : historyComposeAreaBg [ _palette ] ) ;
2021-03-22 19:40:56 +04:00
emojiIcon . paint ( * _p , attachEmojiLeft + emojiIconLeft , controlsTop + emojiIconTop , _rect . width ( ) ) ;
2016-12-23 16:21:01 +03:00
auto pen = st : : historyEmojiCircleFg [ _palette ] - > p ;
2022-02-25 16:11:49 +03:00
pen . setWidthF ( style : : ConvertScaleExact ( st : : historyEmojiCircleLine ) ) ;
2016-12-23 16:21:01 +03:00
pen . setCapStyle ( Qt : : RoundCap ) ;
_p - > setPen ( pen ) ;
_p - > setBrush ( Qt : : NoBrush ) ;
PainterHighQualityEnabler hq ( * _p ) ;
2021-03-22 19:40:56 +04:00
const auto skipx = emojiIcon . width ( ) / 4 ;
const auto skipy = emojiIcon . height ( ) / 4 ;
const auto inner = QRect (
attachEmojiLeft + emojiIconLeft + skipx ,
controlsTop + emojiIconTop + skipy ,
emojiIcon . width ( ) - 2 * skipx ,
emojiIcon . height ( ) - 2 * skipy ) ;
2016-12-23 16:21:01 +03:00
_p - > drawEllipse ( inner ) ;
2019-06-05 18:42:46 +03:00
auto fieldLeft = _composeArea . x ( ) + st : : historyAttach . width ;
auto fieldTop = _composeArea . y ( ) + _composeArea . height ( ) - st : : historyAttach . height + st : : historySendPadding ;
2023-05-16 19:48:49 +04:00
auto fieldWidth = _composeArea . width ( ) - st : : historyAttach . width - st : : historySendSize . width ( ) - st : : historySendRight - emojiButton . width ;
2019-06-05 18:42:46 +03:00
auto fieldHeight = st : : historySendSize . height ( ) - 2 * st : : historySendPadding ;
2016-12-23 16:21:01 +03:00
auto field = QRect ( fieldLeft , fieldTop , fieldWidth , fieldHeight ) ;
2018-05-22 00:31:46 +03:00
_p - > fillRect ( field , st : : historyComposeField . textBg [ _palette ] ) ;
2016-12-23 16:21:01 +03:00
_p - > setClipRect ( field ) ;
2022-10-04 10:11:15 +04:00
_p - > save ( ) ;
2024-06-06 20:57:09 +04:00
_p - > setFont ( st : : historyComposeField . style . font ) ;
2018-05-22 00:31:46 +03:00
_p - > setPen ( st : : historyComposeField . placeholderFg [ _palette ] ) ;
auto placeholderRect = QRect (
2019-06-05 18:42:46 +03:00
field . x ( ) + st : : historyComposeField . textMargins . left ( ) + st : : historyComposeField . placeholderMargins . left ( ) ,
field . y ( ) + st : : historyComposeField . textMargins . top ( ) + st : : historyComposeField . placeholderMargins . top ( ) ,
2018-05-22 00:31:46 +03:00
field . width ( ) - st : : historyComposeField . textMargins . left ( ) - st : : historyComposeField . textMargins . right ( ) ,
field . height ( ) - st : : historyComposeField . textMargins . top ( ) - st : : historyComposeField . textMargins . bottom ( ) ) ;
2019-06-19 17:09:03 +02:00
_p - > drawText ( placeholderRect , tr : : lng_message_ph ( tr : : now ) , QTextOption ( st : : historyComposeField . placeholderAlign ) ) ;
2016-12-23 16:21:01 +03:00
_p - > restore ( ) ;
_p - > setClipping ( false ) ;
}
void Generator : : paintDialogs ( ) {
_p - > fillRect ( _dialogs , st : : dialogsBg [ _palette ] ) ;
2021-09-17 13:20:15 +03:00
const auto iconLeft = ( st : : dialogsMenuToggle . iconPosition . x ( ) < 0 )
? ( st : : dialogsMenuToggle . width - st : : dialogsMenuToggle . icon . width ( ) ) / 2
: st : : dialogsMenuToggle . iconPosition . x ( ) ;
const auto iconTop = ( st : : dialogsMenuToggle . iconPosition . y ( ) < 0 )
? ( st : : dialogsMenuToggle . height - st : : dialogsMenuToggle . icon . height ( ) ) / 2
: st : : dialogsMenuToggle . iconPosition . y ( ) ;
st : : dialogsMenuToggle . icon [ _palette ] . paint ( * _p , _dialogs . x ( ) + st : : dialogsFilterPadding . x ( ) + iconLeft , _dialogs . y ( ) + st : : dialogsFilterPadding . y ( ) + iconTop , _rect . width ( ) ) ;
2016-12-23 16:21:01 +03:00
auto filterLeft = _dialogs . x ( ) + st : : dialogsFilterPadding . x ( ) + st : : dialogsMenuToggle . width + st : : dialogsFilterPadding . x ( ) ;
auto filterRight = st : : dialogsFilterSkip + st : : dialogsFilterPadding . x ( ) ;
2017-06-29 22:09:10 +03:00
auto filterWidth = _dialogs . x ( ) + _dialogs . width ( ) - filterLeft - filterRight ;
2019-04-26 18:07:44 +04:00
auto filterAreaHeight = st : : topBarHeight ;
2022-10-20 17:42:50 +04:00
auto filterTop = _dialogs . y ( ) + ( filterAreaHeight - st : : dialogsFilter . heightMin ) / 2 ;
auto filter = QRect ( filterLeft , filterTop , filterWidth , st : : dialogsFilter . heightMin ) ;
2016-12-23 16:21:01 +03:00
2022-10-20 17:42:50 +04:00
auto pen = st : : dialogsFilter . borderFg [ _palette ] - > p ;
pen . setWidth ( st : : dialogsFilter . border ) ;
2016-12-23 16:21:01 +03:00
_p - > setPen ( pen ) ;
2022-10-20 17:42:50 +04:00
_p - > setBrush ( st : : dialogsFilter . textBg [ _palette ] ) ;
2016-12-23 16:21:01 +03:00
{
PainterHighQualityEnabler hq ( * _p ) ;
2022-10-20 17:42:50 +04:00
const auto radius = st : : dialogsFilter . borderRadius
- ( st : : dialogsFilter . border / 2. ) ;
_p - > drawRoundedRect (
QRectF ( filter ) . marginsRemoved (
QMarginsF (
st : : dialogsFilter . border / 2. ,
st : : dialogsFilter . border / 2. ,
st : : dialogsFilter . border / 2. ,
st : : dialogsFilter . border / 2. ) ) ,
radius ,
radius ) ;
2016-12-23 16:21:01 +03:00
}
_p - > save ( ) ;
_p - > setClipRect ( filter ) ;
2022-10-20 17:42:50 +04:00
auto phRect = QRect ( filter . x ( ) + st : : dialogsFilter . textMargins . left ( ) + st : : dialogsFilter . placeholderMargins . left ( ) , filter . y ( ) + st : : dialogsFilter . textMargins . top ( ) + st : : dialogsFilter . placeholderMargins . top ( ) , filter . width ( ) - st : : dialogsFilter . textMargins . left ( ) - st : : dialogsFilter . textMargins . right ( ) , filter . height ( ) - st : : dialogsFilter . textMargins . top ( ) - st : : dialogsFilter . textMargins . bottom ( ) ) ;
2024-06-06 20:57:09 +04:00
_p - > setFont ( st : : dialogsFilter . style . font ) ;
2022-10-20 17:42:50 +04:00
_p - > setPen ( st : : dialogsFilter . placeholderFg [ _palette ] ) ;
_p - > drawText ( phRect , tr : : lng_dlg_filter ( tr : : now ) , QTextOption ( st : : dialogsFilter . placeholderAlign ) ) ;
2016-12-23 16:21:01 +03:00
_p - > restore ( ) ;
_p - > setClipping ( false ) ;
paintDialogsList ( ) ;
}
void Generator : : paintDialogsList ( ) {
_p - > setClipRect ( _dialogsList ) ;
_rowsTop = _dialogsList . y ( ) ;
for ( auto & row : _rows ) {
paintRow ( row ) ;
_rowsTop + = st : : dialogsRowHeight ;
}
_p - > setClipping ( false ) ;
}
void Generator : : paintRow ( const Row & row ) {
auto x = _dialogsList . x ( ) ;
auto y = _rowsTop ;
auto fullWidth = _dialogsList . width ( ) ;
auto fullRect = QRect ( x , y , fullWidth , st : : dialogsRowHeight ) ;
if ( row . active | | row . selected ) {
_p - > fillRect ( fullRect , row . active ? st : : dialogsBgActive [ _palette ] : st : : dialogsBgOver [ _palette ] ) ;
}
2022-09-29 14:33:17 +04:00
const auto & st = st : : defaultDialogRow ;
paintUserpic (
x + st . padding . left ( ) ,
y + st . padding . top ( ) ,
row . type ,
row . peerIndex ,
row . letters ) ;
auto nameleft = x + st . nameLeft ;
auto namewidth = x + fullWidth - nameleft - st . padding . right ( ) ;
auto rectForName = QRect ( nameleft , y + st . nameTop , namewidth , st : : msgNameFont - > height ) ;
2016-12-23 16:21:01 +03:00
auto chatTypeIcon = ( [ & row ] ( ) - > const style : : icon * {
if ( row . type = = Row : : Type : : Group ) {
2023-08-30 05:25:34 +03:00
return & Dialogs : : ThreeStateIcon (
st : : dialogsChatIcon ,
row . active ,
row . selected ) ;
2016-12-23 16:21:01 +03:00
} else if ( row . type = = Row : : Type : : Channel ) {
2023-08-30 05:25:34 +03:00
return & Dialogs : : ThreeStateIcon (
st : : dialogsChannelIcon ,
row . active ,
row . selected ) ;
2016-12-23 16:21:01 +03:00
}
return nullptr ;
} ) ( ) ;
if ( chatTypeIcon ) {
( * chatTypeIcon ) [ _palette ] . paint ( * _p , rectForName . topLeft ( ) , fullWidth ) ;
2022-10-25 16:40:54 +04:00
rectForName . setLeft ( rectForName . left ( )
+ chatTypeIcon - > width ( )
+ st : : dialogsChatTypeSkip ) ;
2016-12-23 16:21:01 +03:00
}
2022-10-04 10:11:15 +04:00
auto texttop = y + st . textTop ;
2016-12-23 16:21:01 +03:00
auto dateWidth = st : : dialogsDateFont - > width ( row . date ) ;
rectForName . setWidth ( rectForName . width ( ) - dateWidth - st : : dialogsDateSkip ) ;
_p - > setFont ( st : : dialogsDateFont ) ;
_p - > setPen ( row . active ? st : : dialogsDateFgActive [ _palette ] : ( row . selected ? st : : dialogsDateFgOver [ _palette ] : st : : dialogsDateFg [ _palette ] ) ) ;
_p - > drawText ( rectForName . left ( ) + rectForName . width ( ) + st : : dialogsDateSkip , rectForName . top ( ) + st : : msgNameFont - > height - st : : msgDateFont - > descent , row . date ) ;
auto availableWidth = namewidth ;
if ( row . unreadCounter ) {
auto counter = QString : : number ( row . unreadCounter ) ;
2022-09-29 14:33:17 +04:00
auto unreadRight = x + fullWidth - st . padding . right ( ) ;
2016-12-23 16:21:01 +03:00
auto unreadTop = texttop + st : : dialogsTextFont - > ascent - st : : dialogsUnreadFont - > ascent - ( st : : dialogsUnreadHeight - st : : dialogsUnreadFont - > height ) / 2 ;
auto unreadWidth = st : : dialogsUnreadFont - > width ( counter ) ;
auto unreadRectWidth = unreadWidth + 2 * st : : dialogsUnreadPadding ;
auto unreadRectHeight = st : : dialogsUnreadHeight ;
accumulate_max ( unreadRectWidth , unreadRectHeight ) ;
auto unreadRectLeft = unreadRight - unreadRectWidth ;
auto unreadRectTop = unreadTop ;
availableWidth - = unreadRectWidth + st : : dialogsUnreadPadding ;
style : : color bg [ ] = {
st : : dialogsUnreadBg ,
st : : dialogsUnreadBgOver ,
st : : dialogsUnreadBgActive ,
st : : dialogsUnreadBgMuted ,
st : : dialogsUnreadBgMutedOver ,
st : : dialogsUnreadBgMutedActive
} ;
auto index = ( row . active ? 2 : row . selected ? 1 : 0 ) + ( row . muted ? 3 : 0 ) ;
_p - > setPen ( Qt : : NoPen ) ;
_p - > setBrush ( bg [ index ] [ _palette ] ) ;
_p - > drawRoundedRect ( QRectF ( unreadRectLeft , unreadRectTop , unreadRectWidth , unreadRectHeight ) , unreadRectHeight / 2. , unreadRectHeight / 2. ) ;
auto textTop = ( unreadRectHeight - st : : dialogsUnreadFont - > height ) / 2 ;
_p - > setFont ( st : : dialogsUnreadFont ) ;
_p - > setPen ( row . active ? st : : dialogsUnreadFgActive [ _palette ] : ( row . selected ? st : : dialogsUnreadFgOver [ _palette ] : st : : dialogsUnreadFg [ _palette ] ) ) ;
_p - > drawText ( unreadRectLeft + ( unreadRectWidth - unreadWidth ) / 2 , unreadRectTop + textTop + st : : dialogsUnreadFont - > ascent , counter ) ;
} else if ( row . pinned ) {
2023-08-30 05:25:34 +03:00
auto icon = Dialogs : : ThreeStateIcon (
st : : dialogsPinnedIcon ,
row . active ,
row . selected ) [ _palette ] ;
2022-09-29 14:33:17 +04:00
icon . paint ( * _p , x + fullWidth - st . padding . right ( ) - icon . width ( ) , texttop , fullWidth ) ;
2016-12-23 16:21:01 +03:00
availableWidth - = icon . width ( ) + st : : dialogsUnreadPadding ;
}
auto textRect = QRect ( nameleft , texttop , availableWidth , st : : dialogsTextFont - > height ) ;
setTextPalette ( row . active ? st : : dialogsTextPaletteActive : ( row . selected ? st : : dialogsTextPaletteOver : st : : dialogsTextPalette ) ) ;
_p - > setFont ( st : : dialogsTextFont ) ;
_p - > setPen ( row . active ? st : : dialogsTextFgActive [ _palette ] : ( row . selected ? st : : dialogsTextFgOver [ _palette ] : st : : dialogsTextFg [ _palette ] ) ) ;
row . text . drawElided ( * _p , textRect . left ( ) , textRect . top ( ) , textRect . width ( ) , textRect . height ( ) / st : : dialogsTextFont - > height ) ;
restoreTextPalette ( ) ;
auto sendStateIcon = ( [ & row ] ( ) - > const style : : icon * {
if ( row . status = = Status : : Sent ) {
2023-08-30 05:25:34 +03:00
return & Dialogs : : ThreeStateIcon (
st : : dialogsSentIcon ,
row . active ,
row . selected ) ;
2016-12-23 16:21:01 +03:00
} else if ( row . status = = Status : : Received ) {
2023-08-30 05:25:34 +03:00
return & Dialogs : : ThreeStateIcon (
st : : dialogsReceivedIcon ,
row . active ,
row . selected ) ;
2016-12-23 16:21:01 +03:00
}
return nullptr ;
} ) ( ) ;
if ( sendStateIcon ) {
rectForName . setWidth ( rectForName . width ( ) - st : : dialogsSendStateSkip ) ;
( * sendStateIcon ) [ _palette ] . paint ( * _p , rectForName . topLeft ( ) + QPoint ( rectForName . width ( ) , 0 ) , fullWidth ) ;
}
_p - > setPen ( row . active ? st : : dialogsNameFgActive [ _palette ] : ( row . selected ? st : : dialogsNameFgOver [ _palette ] : st : : dialogsNameFg [ _palette ] ) ) ;
row . name . drawElided ( * _p , rectForName . left ( ) , rectForName . top ( ) , rectForName . width ( ) ) ;
}
void Generator : : paintBubble ( const Bubble & bubble ) {
auto height = bubble . height ;
if ( ! bubble . replyName . isEmpty ( ) ) {
2023-10-28 23:10:06 +04:00
height + = st : : historyReplyTop
+ st : : historyReplyPadding . top ( )
+ st : : msgServiceNameFont - > height
+ st : : normalFont - > height
+ st : : historyReplyPadding . bottom ( )
+ st : : historyReplyBottom ;
2016-12-23 16:21:01 +03:00
}
auto isPhoto = ! bubble . photo . isNull ( ) ;
auto x = _history . x ( ) ;
auto y = _historyBottom - st : : msgMargin . bottom ( ) - height ;
auto bubbleTop = y ;
auto bubbleHeight = height ;
2022-10-04 10:11:15 +04:00
if ( isPhoto ) {
2022-11-08 11:19:17 +01:00
bubbleTop - = Ui : : BubbleRadiusLarge ( ) + 1 ;
bubbleHeight + = Ui : : BubbleRadiusLarge ( ) + 1 ;
2016-12-23 16:21:01 +03:00
}
auto left = bubble . outbg ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) ;
if ( bubble . outbg ) {
left + = _history . width ( ) - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) - bubble . width ;
}
x + = left ;
2022-10-04 10:11:15 +04:00
using Corner = Ui : : BubbleCornerRounding ;
auto rounding = Ui : : BubbleRounding {
Corner : : Large ,
Corner : : Large ,
Corner : : Large ,
Corner : : Large ,
} ;
if ( bubble . outbg ) {
if ( bubble . attachToTop ) {
rounding . topRight = Corner : : Small ;
2016-12-23 16:21:01 +03:00
}
2022-10-04 10:11:15 +04:00
if ( bubble . attachToBottom ) {
rounding . bottomRight = Corner : : Small ;
} else if ( bubble . tail ) {
rounding . bottomRight = Corner : : Tail ;
}
} else {
if ( bubble . attachToTop ) {
rounding . topLeft = Corner : : Small ;
}
if ( bubble . attachToBottom ) {
rounding . bottomLeft = Corner : : Small ;
} else if ( bubble . tail ) {
rounding . bottomLeft = Corner : : Tail ;
2016-12-23 16:21:01 +03:00
}
}
2022-10-04 10:11:15 +04:00
Ui : : PaintBubble ( * _p , Ui : : SimpleBubble {
. st = & _st ,
. geometry = QRect ( x , bubbleTop , bubble . width , bubbleHeight ) ,
. outerWidth = _rect . width ( ) ,
. outbg = bubble . outbg ,
. rounding = rounding ,
} ) ;
2016-12-23 16:21:01 +03:00
auto trect = QRect ( x , y , bubble . width , bubble . height ) ;
if ( isPhoto ) {
trect = trect . marginsRemoved ( QMargins ( st : : msgPadding . left ( ) , st : : mediaCaptionSkip , st : : msgPadding . right ( ) , st : : msgPadding . bottom ( ) ) ) ;
} else {
trect = trect . marginsRemoved ( st : : msgPadding ) ;
}
if ( ! bubble . replyName . isEmpty ( ) ) {
2023-10-28 23:10:06 +04:00
trect . setY ( trect . y ( ) + st : : historyReplyTop ) ;
2016-12-23 16:21:01 +03:00
auto bar = ( bubble . outbg ? st : : msgOutReplyBarColor [ _palette ] : st : : msgInReplyBarColor [ _palette ] ) ;
2023-10-28 23:10:06 +04:00
auto rbar = style : : rtlrect (
trect . x ( ) ,
trect . y ( ) ,
trect . width ( ) ,
( st : : historyReplyPadding . top ( )
+ st : : msgServiceNameFont - > height
+ st : : normalFont - > height
+ st : : historyReplyPadding . bottom ( ) ) ,
_rect . width ( ) ) ;
{
auto hq = PainterHighQualityEnabler ( * _p ) ;
_p - > setPen ( Qt : : NoPen ) ;
_p - > setBrush ( bar ) ;
const auto outline = st : : messageTextStyle . blockquote . outline ;
const auto radius = st : : messageTextStyle . blockquote . radius ;
_p - > setOpacity ( Ui : : kDefaultOutline1Opacity ) ;
_p - > setClipRect ( rbar . x ( ) , rbar . y ( ) , outline , rbar . height ( ) ) ;
_p - > drawRoundedRect ( rbar , radius , radius ) ;
_p - > setOpacity ( Ui : : kDefaultBgOpacity ) ;
_p - > setClipRect (
rbar . x ( ) + outline ,
rbar . y ( ) ,
rbar . width ( ) - outline ,
rbar . height ( ) ) ;
_p - > drawRoundedRect ( rbar , radius , radius ) ;
}
_p - > setOpacity ( 1. ) ;
_p - > setClipping ( false ) ;
2016-12-23 16:21:01 +03:00
_p - > setPen ( bubble . outbg ? st : : msgOutServiceFg [ _palette ] : st : : msgInServiceFg [ _palette ] ) ;
2023-10-28 23:10:06 +04:00
bubble . replyName . drawLeftElided ( * _p , trect . x ( ) + st : : historyReplyPadding . left ( ) , trect . y ( ) + st : : historyReplyPadding . top ( ) , bubble . width - st : : historyReplyPadding . left ( ) - st : : historyReplyPadding . right ( ) , _rect . width ( ) ) ;
2016-12-23 16:21:01 +03:00
_p - > setPen ( bubble . outbg ? st : : historyTextOutFg [ _palette ] : st : : historyTextInFg [ _palette ] ) ;
2023-10-28 23:10:06 +04:00
bubble . replyText . drawLeftElided ( * _p , trect . x ( ) + st : : historyReplyPadding . left ( ) , trect . y ( ) + st : : historyReplyPadding . top ( ) + st : : msgServiceNameFont - > height , bubble . width - st : : historyReplyPadding . left ( ) - st : : historyReplyPadding . right ( ) , _rect . width ( ) ) ;
2016-12-23 16:21:01 +03:00
2023-10-28 23:10:06 +04:00
trect . setY ( trect . y ( ) + rbar . height ( ) + st : : historyReplyBottom ) ;
2016-12-23 16:21:01 +03:00
}
if ( ! bubble . text . isEmpty ( ) ) {
setTextPalette ( bubble . outbg ? st : : outTextPalette : st : : inTextPalette ) ;
_p - > setPen ( bubble . outbg ? st : : historyTextOutFg [ _palette ] : st : : historyTextInFg [ _palette ] ) ;
_p - > setFont ( st : : msgFont ) ;
bubble . text . draw ( * _p , trect . x ( ) , trect . y ( ) , trect . width ( ) ) ;
} else if ( ! bubble . waveform . isEmpty ( ) ) {
2020-10-19 18:37:59 +03:00
const auto & st = st : : msgFileLayout ;
2022-09-30 11:23:32 +04:00
auto nameleft = x + st . padding . left ( ) + st . thumbSize + st . thumbSkip ;
auto nameright = st . padding . right ( ) ;
2020-10-19 18:37:59 +03:00
auto statustop = y + st . statusTop ;
auto inner = style : : rtlrect ( x + st . padding . left ( ) , y + st . padding . top ( ) , st . thumbSize , st . thumbSize , _rect . width ( ) ) ;
2016-12-23 16:21:01 +03:00
_p - > setPen ( Qt : : NoPen ) ;
_p - > setBrush ( bubble . outbg ? st : : msgFileOutBg [ _palette ] : st : : msgFileInBg [ _palette ] ) ;
_p - > drawEllipse ( inner ) ;
auto icon = ( [ & bubble ] {
return & ( bubble . outbg ? st : : historyFileOutPlay : st : : historyFileInPlay ) ;
} ) ( ) ;
( * icon ) [ _palette ] . paintInCenter ( * _p , inner ) ;
auto namewidth = x + bubble . width - nameleft - nameright ;
// rescale waveform by going in waveform.size * bar_count 1D grid
auto active = bubble . outbg ? st : : msgWaveformOutActive [ _palette ] : st : : msgWaveformInActive [ _palette ] ;
auto inactive = bubble . outbg ? st : : msgWaveformOutInactive [ _palette ] : st : : msgWaveformInInactive [ _palette ] ;
2019-06-05 18:42:46 +03:00
auto wf_size = bubble . waveform . size ( ) ;
auto availw = namewidth + st : : msgWaveformSkip ;
auto bar_count = qMin ( availw / ( st : : msgWaveformBar + st : : msgWaveformSkip ) , wf_size ) ;
auto max_value = 0 ;
auto max_delta = st : : msgWaveformMax - st : : msgWaveformMin ;
2020-10-19 18:37:59 +03:00
auto wave_bottom = y + st : : msgFileLayout . padding . top ( ) + st : : msgWaveformMax ;
2016-12-23 16:21:01 +03:00
_p - > setPen ( Qt : : NoPen ) ;
auto norm_value = uchar ( 31 ) ;
2019-06-05 18:42:46 +03:00
for ( auto i = 0 , bar_x = 0 , sum_i = 0 ; i < wf_size ; + + i ) {
auto value = bubble . waveform [ i ] ;
if ( sum_i + bar_count > = wf_size ) { // draw bar
sum_i = sum_i + bar_count - wf_size ;
if ( sum_i < ( bar_count + 1 ) / 2 ) {
if ( max_value < value ) max_value = value ;
}
auto bar_value = ( ( max_value * max_delta ) + ( ( norm_value + 1 ) / 2 ) ) / ( norm_value + 1 ) ;
if ( i > = bubble . waveactive ) {
_p - > fillRect ( nameleft + bar_x , wave_bottom - bar_value , st : : msgWaveformBar , st : : msgWaveformMin + bar_value , inactive ) ;
} else {
_p - > fillRect ( nameleft + bar_x , wave_bottom - bar_value , st : : msgWaveformBar , st : : msgWaveformMin + bar_value , active ) ;
}
bar_x + = st : : msgWaveformBar + st : : msgWaveformSkip ;
2016-12-23 16:21:01 +03:00
2019-06-05 18:42:46 +03:00
if ( sum_i < ( bar_count + 1 ) / 2 ) {
max_value = 0 ;
} else {
max_value = value ;
}
2016-12-23 16:21:01 +03:00
} else {
2019-06-05 18:42:46 +03:00
if ( max_value < value ) max_value = value ;
sum_i + = bar_count ;
2016-12-23 16:21:01 +03:00
}
}
auto status = bubble . outbg ? st : : mediaOutFg [ _palette ] : st : : mediaInFg [ _palette ] ;
_p - > setFont ( st : : normalFont ) ;
_p - > setPen ( status ) ;
_p - > drawTextLeft ( nameleft , statustop , _rect . width ( ) , bubble . wavestatus ) ;
}
_p - > setFont ( st : : msgDateFont ) ;
auto infoRight = x + bubble . width - st : : msgPadding . right ( ) + st : : msgDateDelta . x ( ) ;
auto infoBottom = y + height - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) ;
_p - > setPen ( bubble . outbg ? st : : msgOutDateFg [ _palette ] : st : : msgInDateFg [ _palette ] ) ;
auto infoWidth = computeInfoWidth ( bubble . status , bubble . date ) ;
auto dateX = infoRight - infoWidth ;
auto dateY = infoBottom - st : : msgDateFont - > height ;
_p - > drawText ( dateX , dateY + st : : msgDateFont - > ascent , bubble . date ) ;
auto icon = ( [ & bubble ] ( ) - > const style : : icon * {
if ( bubble . status = = Status : : Sent ) {
return & st : : historySentIcon ;
} else if ( bubble . status = = Status : : Received ) {
return & st : : historyReceivedIcon ;
}
return nullptr ;
} ) ( ) ;
if ( icon ) {
( * icon ) [ _palette ] . paint ( * _p , QPoint ( infoRight , infoBottom ) + st : : historySendStatePosition , _rect . width ( ) ) ;
}
2022-10-04 10:11:15 +04:00
_historyBottom = y - ( bubble . attachToTop ? st : : msgMarginTopAttached : st : : msgMargin . top ( ) ) ;
2016-12-23 16:21:01 +03:00
if ( isPhoto ) {
2024-03-24 01:04:33 +03:00
auto image = bubble . photo . scaled (
QSize ( bubble . photoWidth , bubble . photoHeight )
* style : : DevicePixelRatio ( ) ,
Qt : : IgnoreAspectRatio ,
Qt : : SmoothTransformation ) ;
image . setDevicePixelRatio ( style : : DevicePixelRatio ( ) ) ;
2016-12-23 16:21:01 +03:00
_p - > drawImage ( x , y - bubble . photoHeight , image ) ;
_historyBottom - = bubble . photoHeight ;
}
}
void Generator : : paintService ( QString text ) {
auto bubbleHeight = st : : msgServicePadding . top ( ) + st : : msgServiceFont - > height + st : : msgServicePadding . bottom ( ) ;
auto bubbleTop = _historyBottom - st : : msgServiceMargin . bottom ( ) - bubbleHeight ;
auto textWidth = st : : msgServiceFont - > width ( text ) ;
auto bubbleWidth = st : : msgServicePadding . left ( ) + textWidth + st : : msgServicePadding . right ( ) ;
auto radius = bubbleHeight / 2 ;
_p - > setPen ( Qt : : NoPen ) ;
_p - > setBrush ( st : : msgServiceBg [ _palette ] ) ;
auto bubbleLeft = _history . x ( ) + ( _history . width ( ) - bubbleWidth ) / 2 ;
_p - > drawRoundedRect ( bubbleLeft , bubbleTop , bubbleWidth , bubbleHeight , radius , radius ) ;
_p - > setPen ( st : : msgServiceFg [ _palette ] ) ;
2017-01-11 12:16:44 +04:00
_p - > setFont ( st : : msgServiceFont ) ;
2016-12-23 16:21:01 +03:00
_p - > drawText ( bubbleLeft + st : : msgServicePadding . left ( ) , bubbleTop + st : : msgServicePadding . top ( ) + st : : msgServiceFont - > ascent , text ) ;
_historyBottom = bubbleTop - st : : msgServiceMargin . top ( ) ;
}
2016-12-29 13:03:51 +04:00
void Generator : : paintUserpic ( int x , int y , Row : : Type type , int index , QString letters ) {
2023-10-16 13:52:08 +04:00
const auto colorIndex = Ui : : DecideColorIndex ( index ) ;
2022-12-03 20:59:48 +03:00
const auto colors = Ui : : EmptyUserpic : : UserpicColor ( colorIndex ) ;
auto userpic = Ui : : EmptyUserpic ( colors , letters ) ;
2016-12-23 16:21:01 +03:00
2022-09-29 14:33:17 +04:00
const auto size = st : : defaultDialogRow . photoSize ;
auto image = QImage (
2022-12-03 20:59:48 +03:00
QSize ( size , size ) * style : : DevicePixelRatio ( ) ,
2022-09-29 14:33:17 +04:00
QImage : : Format_ARGB32_Premultiplied ) ;
2024-03-24 01:04:33 +03:00
image . setDevicePixelRatio ( style : : DevicePixelRatio ( ) ) ;
2022-12-03 20:59:48 +03:00
image . fill ( Qt : : transparent ) ;
2016-12-23 16:21:01 +03:00
{
Painter p ( & image ) ;
2022-12-05 16:18:10 +04:00
userpic . paintCircle ( p , 0 , 0 , size , size ) ;
2016-12-23 16:21:01 +03:00
}
2022-09-29 14:33:17 +04:00
_p - > drawImage ( rtl ( ) ? ( _rect . width ( ) - x - size ) : x , y , image ) ;
2016-12-23 16:21:01 +03:00
}
void Generator : : paintHistoryShadows ( ) {
_p - > fillRect ( _history . x ( ) + st : : lineWidth , _history . y ( ) , _history . width ( ) - st : : lineWidth , st : : lineWidth , st : : shadowFg [ _palette ] ) ;
_p - > fillRect ( _history . x ( ) + st : : lineWidth , _history . y ( ) + _history . height ( ) - st : : lineWidth , _history . width ( ) - st : : lineWidth , st : : lineWidth , st : : shadowFg [ _palette ] ) ;
_p - > fillRect ( _history . x ( ) , _body . y ( ) , st : : lineWidth , _body . height ( ) , st : : shadowFg [ _palette ] ) ;
}
void Generator : : setTextPalette ( const style : : TextPalette & st ) {
_textPalette . linkFg = st . linkFg [ _palette ] . clone ( ) ;
_textPalette . monoFg = st . monoFg [ _palette ] . clone ( ) ;
2022-09-18 15:17:49 +04:00
_textPalette . spoilerFg = st . spoilerFg [ _palette ] . clone ( ) ;
2016-12-23 16:21:01 +03:00
_textPalette . selectBg = st . selectBg [ _palette ] . clone ( ) ;
2017-02-17 15:57:56 +03:00
_textPalette . selectFg = st . selectFg [ _palette ] . clone ( ) ;
_textPalette . selectLinkFg = st . selectLinkFg [ _palette ] . clone ( ) ;
_textPalette . selectMonoFg = st . selectMonoFg [ _palette ] . clone ( ) ;
2022-09-18 15:17:49 +04:00
_textPalette . selectSpoilerFg = st . selectSpoilerFg [ _palette ] . clone ( ) ;
2016-12-23 16:21:01 +03:00
_textPalette . selectOverlay = st . selectOverlay [ _palette ] . clone ( ) ;
_p - > setTextPalette ( _textPalette ) ;
}
void Generator : : restoreTextPalette ( ) {
_p - > restoreTextPalette ( ) ;
}
2019-09-08 19:29:43 +03:00
} // namespace
QString CachedThemePath ( uint64 documentId ) {
2019-09-06 14:33:51 +03:00
return QString : : fromLatin1 ( " special://cached-%1 " ) . arg ( documentId ) ;
}
2019-09-03 21:04:38 +03:00
std : : unique_ptr < Preview > PreviewFromFile (
const QByteArray & bytes ,
2019-09-05 10:42:06 +03:00
const QString & filepath ,
2019-09-03 21:04:38 +03:00
const Data : : CloudTheme & cloud ) {
2018-07-19 17:58:40 +03:00
auto result = std : : make_unique < Preview > ( ) ;
2019-09-03 21:04:38 +03:00
auto & object = result - > object ;
object . cloud = cloud ;
2019-09-05 08:18:21 +03:00
object . pathAbsolute = filepath . isEmpty ( )
2019-09-06 14:33:51 +03:00
? CachedThemePath ( cloud . documentId )
2019-09-05 08:18:21 +03:00
: QFileInfo ( filepath ) . absoluteFilePath ( ) ;
2019-09-06 14:33:51 +03:00
object . pathRelative = filepath . isEmpty ( )
? object . pathAbsolute
: QDir ( ) . relativeFilePath ( filepath ) ;
2019-09-09 09:59:57 +03:00
const auto instance = & result - > instance ;
const auto cache = & result - > instance . cached ;
2019-09-03 21:04:38 +03:00
if ( bytes . isEmpty ( ) ) {
2019-09-09 09:59:57 +03:00
if ( ! LoadFromFile ( filepath , instance , cache , & object . content ) ) {
2019-09-03 21:04:38 +03:00
return nullptr ;
}
} else {
2019-09-05 09:51:46 +03:00
object . content = bytes ;
2019-09-09 09:59:57 +03:00
if ( ! LoadFromContent ( bytes , instance , cache ) ) {
2019-09-03 21:04:38 +03:00
return nullptr ;
}
2018-07-19 17:58:40 +03:00
}
return result ;
}
2018-01-02 22:10:49 +03:00
std : : unique_ptr < Preview > GeneratePreview (
2019-09-03 21:04:38 +03:00
const QByteArray & bytes ,
2019-09-05 10:42:06 +03:00
const QString & filepath ,
2019-09-03 21:04:38 +03:00
const Data : : CloudTheme & cloud ,
2019-09-09 14:56:05 +03:00
CurrentData & & data ,
PreviewType type ) {
2019-09-05 10:42:06 +03:00
auto result = PreviewFromFile ( bytes , filepath , cloud ) ;
2018-07-19 17:58:40 +03:00
if ( ! result ) {
2017-08-13 19:14:00 +03:00
return nullptr ;
2016-12-23 16:21:01 +03:00
}
2018-01-02 22:10:49 +03:00
result - > preview = Generator (
result - > instance ,
2019-09-09 14:56:05 +03:00
std : : move ( data ) ,
type
2018-01-02 22:10:49 +03:00
) . generate ( ) ;
2017-02-21 17:37:53 +03:00
return result ;
2016-12-23 16:21:01 +03:00
}
2019-09-09 14:56:05 +03:00
QImage GeneratePreview (
const QByteArray & bytes ,
const QString & filepath ) {
const auto preview = GeneratePreview (
bytes ,
filepath ,
Data : : CloudTheme ( ) ,
CurrentData { Data : : ThemeWallPaper ( ) . id ( ) } ,
PreviewType : : Normal ) ;
return preview ? preview - > preview : QImage ( ) ;
}
2016-12-23 16:21:01 +03:00
int DefaultPreviewTitleHeight ( ) {
2019-10-20 15:24:09 +04:00
return st : : defaultWindowTitle . height ;
2016-12-23 16:21:01 +03:00
}
void DefaultPreviewWindowTitle ( Painter & p , const style : : palette & palette , QRect body , int outerWidth ) {
2019-10-20 15:24:09 +04:00
auto titleRect = QRect ( body . x ( ) , body . y ( ) - st : : defaultWindowTitle . height , body . width ( ) , st : : defaultWindowTitle . height ) ;
2016-12-23 16:21:01 +03:00
p . fillRect ( titleRect , QColor ( 0 , 0 , 0 ) ) ;
2017-01-16 16:27:11 +03:00
p . fillRect ( titleRect , st : : titleBgActive [ palette ] ) ;
2021-03-22 19:40:12 +04:00
auto right = st : : defaultWindowTitle . close . width ;
st : : defaultWindowTitle . close . icon [ palette ] . paint ( p , titleRect . x ( ) + titleRect . width ( ) - right + st : : defaultWindowTitle . close . iconPosition . x ( ) , titleRect . y ( ) + st : : windowTitleButtonClose . iconPosition . y ( ) , outerWidth ) ;
2019-10-20 15:24:09 +04:00
right + = st : : defaultWindowTitle . maximize . width ;
st : : defaultWindowTitle . maximize . icon [ palette ] . paint ( p , titleRect . x ( ) + titleRect . width ( ) - right + st : : defaultWindowTitle . maximize . iconPosition . x ( ) , titleRect . y ( ) + st : : defaultWindowTitle . maximize . iconPosition . y ( ) , outerWidth ) ;
right + = st : : defaultWindowTitle . minimize . width ;
st : : defaultWindowTitle . minimize . icon [ palette ] . paint ( p , titleRect . x ( ) + titleRect . width ( ) - right + st : : defaultWindowTitle . minimize . iconPosition . x ( ) , titleRect . y ( ) + st : : defaultWindowTitle . minimize . iconPosition . y ( ) , outerWidth ) ;
2016-12-23 16:21:01 +03:00
p . fillRect ( titleRect . x ( ) , titleRect . y ( ) + titleRect . height ( ) - st : : lineWidth , titleRect . width ( ) , st : : lineWidth , st : : titleShadow [ palette ] ) ;
}
void DefaultPreviewWindowFramePaint ( QImage & preview , const style : : palette & palette , QRect body , int outerWidth ) {
2024-03-24 01:04:33 +03:00
auto mask = QImage (
st : : windowShadow . size ( ) * style : : DevicePixelRatio ( ) ,
QImage : : Format_ARGB32_Premultiplied ) ;
mask . setDevicePixelRatio ( style : : DevicePixelRatio ( ) ) ;
2016-12-23 16:21:01 +03:00
{
Painter p ( & mask ) ;
p . setCompositionMode ( QPainter : : CompositionMode_Source ) ;
st : : windowShadow . paint ( p , 0 , 0 , st : : windowShadow . width ( ) , QColor ( 0 , 0 , 0 ) ) ;
}
auto maxSize = 0 ;
auto currentInt = static_cast < uint32 > ( 0 ) ;
auto lastLineInts = reinterpret_cast < const uint32 * > ( mask . constBits ( ) + ( mask . height ( ) - 1 ) * mask . bytesPerLine ( ) ) ;
for ( auto end = lastLineInts + mask . width ( ) ; lastLineInts ! = end ; + + lastLineInts ) {
if ( * lastLineInts < currentInt ) {
break ;
}
currentInt = * lastLineInts ;
+ + maxSize ;
}
2024-03-24 01:04:33 +03:00
if ( maxSize % style : : DevicePixelRatio ( ) ) {
maxSize - = ( maxSize % style : : DevicePixelRatio ( ) ) ;
2016-12-23 16:21:01 +03:00
}
2024-03-24 01:04:33 +03:00
auto size = maxSize / style : : DevicePixelRatio ( ) ;
2016-12-23 16:21:01 +03:00
auto bottom = size ;
auto left = size - st : : windowShadowShift ;
auto right = left ;
auto top = size - 2 * st : : windowShadowShift ;
auto sprite = st : : windowShadow [ palette ] ;
2024-03-24 01:04:33 +03:00
auto topLeft = QImage (
sprite . size ( ) * style : : DevicePixelRatio ( ) ,
QImage : : Format_ARGB32_Premultiplied ) ;
topLeft . setDevicePixelRatio ( style : : DevicePixelRatio ( ) ) ;
2016-12-23 16:21:01 +03:00
{
Painter p ( & topLeft ) ;
p . setCompositionMode ( QPainter : : CompositionMode_Source ) ;
sprite . paint ( p , 0 , 0 , sprite . width ( ) ) ;
}
auto width = sprite . width ( ) ;
auto height = sprite . height ( ) ;
auto topRight = topLeft . mirrored ( true , false ) ;
auto bottomRight = topLeft . mirrored ( true , true ) ;
auto bottomLeft = topLeft . mirrored ( false , true ) ;
Painter p ( & preview ) ;
DefaultPreviewWindowTitle ( p , palette , body , outerWidth ) ;
2024-03-24 01:04:33 +03:00
auto inner = QRect (
body . x ( ) ,
body . y ( ) - st : : defaultWindowTitle . height ,
body . width ( ) ,
body . height ( ) + st : : defaultWindowTitle . height ) ;
p . setClipRegion ( QRegion ( inner + Margins ( size ) ) - inner ) ;
2016-12-23 16:21:01 +03:00
p . drawImage ( inner . x ( ) - left , inner . y ( ) - top , topLeft ) ;
2024-03-24 01:04:33 +03:00
p . drawImage (
inner . x ( ) + inner . width ( ) + right - width ,
inner . y ( ) - top ,
topRight ) ;
p . drawImage (
inner . x ( ) + inner . width ( ) + right - width ,
inner . y ( ) + inner . height ( ) + bottom - height ,
bottomRight ) ;
p . drawImage (
inner . x ( ) - left ,
inner . y ( ) + inner . height ( ) + bottom - height ,
bottomLeft ) ;
p . drawImage (
QRect (
inner . x ( ) - left ,
inner . y ( ) - top + height ,
left ,
top + inner . height ( ) + bottom - 2 * height ) ,
topLeft ,
QRect (
0 ,
topLeft . height ( ) - style : : DevicePixelRatio ( ) ,
left * style : : DevicePixelRatio ( ) ,
style : : DevicePixelRatio ( ) ) ) ;
p . drawImage (
QRect (
inner . x ( ) - left + width ,
inner . y ( ) - top ,
left + inner . width ( ) + right - 2 * width ,
top ) ,
topLeft ,
QRect (
topLeft . width ( ) - style : : DevicePixelRatio ( ) ,
0 ,
style : : DevicePixelRatio ( ) ,
top * style : : DevicePixelRatio ( ) ) ) ;
p . drawImage (
QRect (
inner . x ( ) + inner . width ( ) ,
inner . y ( ) - top + height ,
right ,
top + inner . height ( ) + bottom - 2 * height ) ,
topRight ,
QRect (
topRight . width ( ) - right * style : : DevicePixelRatio ( ) ,
topRight . height ( ) - style : : DevicePixelRatio ( ) ,
right * style : : DevicePixelRatio ( ) ,
style : : DevicePixelRatio ( ) ) ) ;
p . drawImage (
QRect (
inner . x ( ) - left + width ,
inner . y ( ) + inner . height ( ) ,
left + inner . width ( ) + right - 2 * width ,
bottom ) ,
bottomRight ,
QRect (
0 ,
bottomRight . height ( ) - bottom * style : : DevicePixelRatio ( ) ,
style : : DevicePixelRatio ( ) ,
bottom * style : : DevicePixelRatio ( ) ) ) ;
2016-12-23 16:21:01 +03:00
}
} // namespace Theme
} // namespace Window