2016-10-28 12:44:28 +00:00
/*
This file is part of Telegram Desktop ,
the official desktop version of Telegram messaging app , see https : //telegram.org
Telegram Desktop is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
It is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright ( c ) 2014 - 2016 John Preston , https : //desktop.telegram.org
*/
# include "stdafx.h"
# include "window/window_theme.h"
# include "mainwidget.h"
# include "localstorage.h"
# include "core/parse_helper.h"
# include "core/zlib_help.h"
namespace Window {
namespace Theme {
namespace {
constexpr int kThemeFileSizeLimit = 5 * 1024 * 1024 ;
constexpr int kThemeBackgroundSizeLimit = 4 * 1024 * 1024 ;
constexpr int kThemeSchemeSizeLimit = 1024 * 1024 ;
struct Data {
2016-11-02 14:44:33 +00:00
struct Applying {
QString path ;
QByteArray content ;
QByteArray paletteForRevert ;
Cached cached ;
} ;
2016-10-28 12:44:28 +00:00
ChatBackground background ;
2016-11-02 14:44:33 +00:00
Applying applying ;
2016-10-28 12:44:28 +00:00
} ;
NeverFreedPointer < Data > instance ;
QByteArray readThemeContent ( const QString & path ) {
QFile file ( path ) ;
if ( ! file . exists ( ) ) {
LOG ( ( " Error: theme file not found: %1 " ) . arg ( path ) ) ;
return QByteArray ( ) ;
}
if ( file . size ( ) > kThemeFileSizeLimit ) {
LOG ( ( " Error: theme file too large: %1 (should be less than 5 MB, got %2) " ) . arg ( path ) . arg ( file . size ( ) ) ) ;
return QByteArray ( ) ;
}
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
LOG ( ( " Warning: could not open theme file: %1 " ) . arg ( path ) ) ;
return QByteArray ( ) ;
}
return file . readAll ( ) ;
}
inline uchar readHexUchar ( char code , bool & error ) {
if ( code > = ' 0 ' & & code < = ' 9 ' ) {
return ( ( code - ' 0 ' ) & 0xFF ) ;
} else if ( code > = ' a ' & & code < = ' f ' ) {
return ( ( code + 10 - ' a ' ) & 0xFF ) ;
} else if ( code > = ' A ' & & code < = ' F ' ) {
return ( ( code + 10 - ' A ' ) & 0xFF ) ;
}
error = true ;
return 0xFF ;
}
inline uchar readHexUchar ( char char1 , char char2 , bool & error ) {
return ( ( readHexUchar ( char1 , error ) & 0x0F ) < < 4 ) | ( readHexUchar ( char2 , error ) & 0x0F ) ;
}
2016-11-04 08:23:50 +00:00
bool readNameAndValue ( const char * & from , const char * end , QLatin1String * outName , QLatin1String * outValue ) {
2016-10-28 12:44:28 +00:00
using base : : parse : : skipWhitespaces ;
using base : : parse : : readName ;
if ( ! skipWhitespaces ( from , end ) ) return true ;
* outName = readName ( from , end ) ;
2016-11-04 08:23:50 +00:00
if ( outName - > size ( ) = = 0 ) {
2016-10-28 12:44:28 +00:00
LOG ( ( " Error: Could not read name in the color scheme. " ) ) ;
return false ;
}
if ( ! skipWhitespaces ( from , end ) ) {
LOG ( ( " Error: Unexpected end of the color scheme. " ) ) ;
return false ;
}
if ( * from ! = ' : ' ) {
LOG ( ( " Error: Expected ':' between each name and value in the color scheme. " ) ) ;
return false ;
}
if ( ! skipWhitespaces ( + + from , end ) ) {
LOG ( ( " Error: Unexpected end of the color scheme. " ) ) ;
return false ;
}
auto valueStart = from ;
if ( * from = = ' # ' ) + + from ;
2016-11-04 08:23:50 +00:00
if ( readName ( from , end ) . size ( ) = = 0 ) {
2016-10-28 12:44:28 +00:00
LOG ( ( " Error: Expected a color value in #rrggbb or #rrggbbaa format in the color scheme. " ) ) ;
return false ;
}
2016-11-04 08:23:50 +00:00
* outValue = QLatin1String ( valueStart , from - valueStart ) ;
2016-10-28 12:44:28 +00:00
if ( ! skipWhitespaces ( from , end ) ) {
LOG ( ( " Error: Unexpected end of the color scheme. " ) ) ;
return false ;
}
if ( * from ! = ' ; ' ) {
LOG ( ( " Error: Expected ';' after each value in the color scheme. " ) ) ;
return false ;
}
+ + from ;
return true ;
}
2016-11-04 08:23:50 +00:00
enum class SetResult {
Ok ,
Bad ,
NotFound ,
} ;
SetResult setColorSchemeValue ( QLatin1String name , QLatin1String value , Instance * out ) {
auto found = false ;
auto size = value . size ( ) ;
auto data = value . data ( ) ;
if ( data [ 0 ] = = ' # ' & & ( size = = 7 | | size = = 9 ) ) {
auto error = false ;
auto r = readHexUchar ( data [ 1 ] , data [ 2 ] , error ) ;
auto g = readHexUchar ( data [ 3 ] , data [ 4 ] , error ) ;
auto b = readHexUchar ( data [ 5 ] , data [ 6 ] , error ) ;
auto a = ( size = = 9 ) ? readHexUchar ( data [ 7 ] , data [ 8 ] , error ) : uchar ( 255 ) ;
if ( error ) {
LOG ( ( " Error: Expected a color value in #rrggbb or #rrggbbaa format in the color scheme (while applying '%1: %2') " ) . arg ( QLatin1String ( name ) ) . arg ( QLatin1String ( value ) ) ) ;
return SetResult : : Bad ;
} else if ( out ) {
found = out - > palette . setColor ( name , r , g , b , a ) ;
} else {
found = style : : main_palette : : setColor ( name , r , g , b , a ) ;
}
} else {
if ( out ) {
found = out - > palette . setColor ( name , value ) ;
} else {
found = style : : main_palette : : setColor ( name , value ) ;
}
}
return found ? SetResult : : Ok : SetResult : : NotFound ;
}
2016-10-28 12:44:28 +00:00
bool loadColorScheme ( const QByteArray & content , Instance * out = nullptr ) {
if ( content . size ( ) > kThemeSchemeSizeLimit ) {
LOG ( ( " Error: color scheme file too large (should be less than 1 MB, got %2) " ) . arg ( content . size ( ) ) ) ;
return false ;
}
2016-11-04 08:23:50 +00:00
QMap < QLatin1String , QLatin1String > unsupported ;
2016-10-28 12:44:28 +00:00
auto data = base : : parse : : stripComments ( content ) ;
auto from = data . constData ( ) , end = from + data . size ( ) ;
while ( from ! = end ) {
2016-11-04 08:23:50 +00:00
QLatin1String name , value ;
2016-10-28 12:44:28 +00:00
if ( ! readNameAndValue ( from , end , & name , & value ) ) {
return false ;
}
2016-11-04 08:23:50 +00:00
if ( name . size ( ) = = 0 ) { // End of content reached.
2016-10-28 12:44:28 +00:00
return true ;
}
2016-11-04 08:23:50 +00:00
// Find the named value in the already read unsupported list.
value = unsupported . value ( value , value ) ;
auto result = setColorSchemeValue ( name , value , out ) ;
if ( result = = SetResult : : Bad ) {
2016-10-28 12:44:28 +00:00
return false ;
2016-11-04 08:23:50 +00:00
} else if ( result = = SetResult : : NotFound ) {
LOG ( ( " Warning: unexpected name or value in the color scheme (while applying '%1: %2') " ) . arg ( name ) . arg ( value ) ) ;
unsupported . insert ( name , value ) ;
2016-10-28 12:44:28 +00:00
}
}
return true ;
}
void applyBackground ( QImage & & background , bool tiled , Instance * out ) {
if ( out ) {
out - > background = std_ : : move ( background ) ;
out - > tiled = tiled ;
} else {
Background ( ) - > setThemeData ( std_ : : move ( background ) , tiled ) ;
}
}
bool loadThemeFromCache ( const QByteArray & content , Cached & cache ) {
2016-10-31 12:29:26 +00:00
if ( cache . paletteChecksum ! = style : : palette : : Checksum ( ) ) {
2016-10-28 12:44:28 +00:00
return false ;
}
if ( cache . contentChecksum ! = hashCrc32 ( content . constData ( ) , content . size ( ) ) ) {
return false ;
}
QImage background ;
if ( ! cache . background . isEmpty ( ) ) {
QBuffer buffer ( & cache . background ) ;
QImageReader reader ( & buffer ) ;
# ifndef OS_MAC_OLD
reader . setAutoTransform ( true ) ;
# endif // OS_MAC_OLD
if ( ! reader . read ( & background ) | | background . isNull ( ) ) {
return false ;
}
}
if ( ! style : : main_palette : : load ( cache . colors ) ) {
return false ;
}
if ( ! background . isNull ( ) ) {
applyBackground ( std_ : : move ( background ) , cache . tiled , nullptr ) ;
}
return true ;
}
enum class LoadResult {
Loaded ,
Failed ,
NotFound ,
} ;
LoadResult loadBackgroundFromFile ( zlib : : FileToRead & file , const char * filename , QByteArray * outBackground ) {
* outBackground = file . readFileContent ( filename , zlib : : kCaseInsensitive , kThemeBackgroundSizeLimit ) ;
if ( file . error ( ) = = UNZ_OK ) {
return LoadResult : : Loaded ;
} else if ( file . error ( ) = = UNZ_END_OF_LIST_OF_FILE ) {
file . clearError ( ) ;
return LoadResult : : NotFound ;
}
LOG ( ( " Error: could not read '%1' in the theme file. " ) . arg ( filename ) ) ;
return LoadResult : : Failed ;
}
bool loadBackground ( zlib : : FileToRead & file , QByteArray * outBackground , bool * outTiled ) {
auto result = loadBackgroundFromFile ( file , " background.jpg " , outBackground ) ;
if ( result ! = LoadResult : : NotFound ) return ( result = = LoadResult : : Loaded ) ;
result = loadBackgroundFromFile ( file , " background.png " , outBackground ) ;
if ( result ! = LoadResult : : NotFound ) return ( result = = LoadResult : : Loaded ) ;
* outTiled = true ;
result = loadBackgroundFromFile ( file , " tiled.jpg " , outBackground ) ;
if ( result ! = LoadResult : : NotFound ) return ( result = = LoadResult : : Loaded ) ;
result = loadBackgroundFromFile ( file , " tiled.png " , outBackground ) ;
if ( result ! = LoadResult : : NotFound ) return ( result = = LoadResult : : Loaded ) ;
return true ;
}
bool loadTheme ( const QByteArray & content , Cached & cache , Instance * out = nullptr ) {
cache = Cached ( ) ;
zlib : : FileToRead file ( content ) ;
unz_global_info globalInfo = { 0 } ;
file . getGlobalInfo ( & globalInfo ) ;
if ( file . error ( ) = = UNZ_OK ) {
auto schemeContent = file . readFileContent ( " colors.tdesktop-theme " , zlib : : kCaseInsensitive , kThemeSchemeSizeLimit ) ;
if ( file . error ( ) ! = UNZ_OK ) {
LOG ( ( " Error: could not read 'colors.tdesktop-theme' in the theme file. " ) ) ;
return false ;
}
if ( ! loadColorScheme ( schemeContent , out ) ) {
return false ;
}
auto backgroundTiled = false ;
auto backgroundContent = QByteArray ( ) ;
if ( ! loadBackground ( file , & backgroundContent , & backgroundTiled ) ) {
return false ;
}
if ( ! backgroundContent . isEmpty ( ) ) {
auto background = App : : readImage ( backgroundContent ) ;
if ( background . isNull ( ) ) {
LOG ( ( " Error: could not read background image in the theme file. " ) ) ;
return false ;
}
QBuffer buffer ( & cache . background ) ;
if ( ! background . save ( & buffer , " BMP " ) ) {
LOG ( ( " Error: could not write background image as a BMP to cache. " ) ) ;
return false ;
}
cache . tiled = backgroundTiled ;
applyBackground ( std_ : : move ( background ) , cache . tiled , out ) ;
}
} else {
// Looks like it is not a .zip theme.
if ( ! loadColorScheme ( content , out ) ) {
return false ;
}
}
if ( out ) {
cache . colors = out - > palette . save ( ) ;
} else {
cache . colors = style : : main_palette : : save ( ) ;
}
2016-10-31 12:29:26 +00:00
cache . paletteChecksum = style : : palette : : Checksum ( ) ;
2016-10-28 12:44:28 +00:00
cache . contentChecksum = hashCrc32 ( content . constData ( ) , content . size ( ) ) ;
return true ;
}
QImage prepareBackgroundImage ( QImage & & image ) {
if ( image . format ( ) ! = QImage : : Format_ARGB32 & & image . format ( ) ! = QImage : : Format_ARGB32_Premultiplied & & image . format ( ) ! = QImage : : Format_RGB32 ) {
image = std_ : : move ( image ) . convertToFormat ( QImage : : Format_RGB32 ) ;
}
image . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
return std_ : : move ( image ) ;
}
2016-11-03 10:33:57 +00:00
void initColorsFromBackground ( const QImage & img ) {
uint64 components [ 3 ] = { 0 } , componentsScroll [ 3 ] = { 0 } ;
auto w = img . width ( ) ;
auto h = img . height ( ) ;
auto size = w * h ;
if ( auto pix = img . constBits ( ) ) {
for ( int i = 0 , l = size * 4 ; i ! = l ; i + = 4 ) {
components [ 2 ] + = pix [ i + 0 ] ;
components [ 1 ] + = pix [ i + 1 ] ;
components [ 0 ] + = pix [ i + 2 ] ;
}
}
if ( size ) {
for ( int i = 0 ; i ! = 3 ; + + i ) {
components [ i ] / = size ;
}
}
int maxtomin [ 3 ] = { 0 , 1 , 2 } ;
if ( components [ maxtomin [ 0 ] ] < components [ maxtomin [ 1 ] ] ) {
qSwap ( maxtomin [ 0 ] , maxtomin [ 1 ] ) ;
}
if ( components [ maxtomin [ 1 ] ] < components [ maxtomin [ 2 ] ] ) {
qSwap ( maxtomin [ 1 ] , maxtomin [ 2 ] ) ;
if ( components [ maxtomin [ 0 ] ] < components [ maxtomin [ 1 ] ] ) {
qSwap ( maxtomin [ 0 ] , maxtomin [ 1 ] ) ;
}
}
uint64 max = qMax ( 1ULL , components [ maxtomin [ 0 ] ] ) , mid = qMax ( 1ULL , components [ maxtomin [ 1 ] ] ) , min = qMax ( 1ULL , components [ maxtomin [ 2 ] ] ) ;
memcpy ( componentsScroll , components , sizeof ( components ) ) ;
if ( max ! = min ) {
if ( min > uint64 ( qRound ( 0.77 * max ) ) ) {
uint64 newmin = qRound ( 0.77 * max ) ; // min saturation 23%
uint64 newmid = max - ( ( max - mid ) * ( max - newmin ) ) / ( max - min ) ;
components [ maxtomin [ 1 ] ] = newmid ;
components [ maxtomin [ 2 ] ] = newmin ;
}
uint64 newmin = qRound ( 0.77 * max ) ; // saturation 23% for scroll
uint64 newmid = max - ( ( max - mid ) * ( max - newmin ) ) / ( max - min ) ;
componentsScroll [ maxtomin [ 1 ] ] = newmid ;
componentsScroll [ maxtomin [ 2 ] ] = newmin ;
}
float64 luminance = 0.299 * componentsScroll [ 0 ] + 0.587 * componentsScroll [ 1 ] + 0.114 * componentsScroll [ 2 ] ;
uint64 maxScroll = max ;
if ( luminance < 0.5 * 0xFF ) {
maxScroll + = qRound ( 0.2 * 0xFF ) ;
} else {
maxScroll - = qRound ( 0.2 * 0xFF ) ;
}
componentsScroll [ maxtomin [ 2 ] ] = qMin ( uint64 ( float64 ( componentsScroll [ maxtomin [ 2 ] ] ) * maxScroll / float64 ( componentsScroll [ maxtomin [ 0 ] ] ) ) , 0xFFULL ) ;
componentsScroll [ maxtomin [ 1 ] ] = qMin ( uint64 ( float64 ( componentsScroll [ maxtomin [ 1 ] ] ) * maxScroll / float64 ( componentsScroll [ maxtomin [ 0 ] ] ) ) , 0xFFULL ) ;
componentsScroll [ maxtomin [ 0 ] ] = qMin ( maxScroll , 0xFFULL ) ;
if ( max > uint64 ( qRound ( 0.2 * 0xFF ) ) ) { // brightness greater than 20%
max - = qRound ( 0.2 * 0xFF ) ;
} else {
max = 0 ;
}
components [ maxtomin [ 2 ] ] = uint64 ( float64 ( components [ maxtomin [ 2 ] ] ) * max / float64 ( components [ maxtomin [ 0 ] ] ) ) ;
components [ maxtomin [ 1 ] ] = uint64 ( float64 ( components [ maxtomin [ 1 ] ] ) * max / float64 ( components [ maxtomin [ 0 ] ] ) ) ;
components [ maxtomin [ 0 ] ] = max ;
uchar r = uchar ( components [ 0 ] ) ;
uchar g = uchar ( components [ 1 ] ) ;
uchar b = uchar ( components [ 2 ] ) ;
st : : msgServiceBg . set ( r , g , b , st : : msgServiceBg - > c . alpha ( ) ) ;
float64 alphaSel = st : : msgServiceSelectBg - > c . alphaF ( ) , addSel = ( 1. - ( ( 1. - alphaSel ) / ( 1. - st : : msgServiceBg - > c . alphaF ( ) ) ) ) * 0xFF ;
uchar rsel = snap ( qRound ( ( ( 1. - alphaSel ) * r + addSel ) / alphaSel ) , 0 , 0xFF ) ;
uchar gsel = snap ( qRound ( ( ( 1. - alphaSel ) * g + addSel ) / alphaSel ) , 0 , 0xFF ) ;
uchar bsel = snap ( qRound ( ( ( 1. - alphaSel ) * b + addSel ) / alphaSel ) , 0 , 0xFF ) ;
st : : msgServiceSelectBg . set ( r , g , b , qRound ( alphaSel * 0xFF ) ) ;
uchar rScroll = uchar ( componentsScroll [ 0 ] ) , gScroll = uchar ( componentsScroll [ 1 ] ) , bScroll = uchar ( componentsScroll [ 2 ] ) ;
st : : historyScroll . barColor . set ( rScroll , gScroll , bScroll , st : : historyScroll . barColor - > c . alpha ( ) ) ;
st : : historyScroll . bgColor . set ( rScroll , gScroll , bScroll , st : : historyScroll . bgColor - > c . alpha ( ) ) ;
st : : historyScroll . barOverColor . set ( rScroll , gScroll , bScroll , st : : historyScroll . barOverColor - > c . alpha ( ) ) ;
st : : historyScroll . bgOverColor . set ( rScroll , gScroll , bScroll , st : : historyScroll . bgOverColor - > c . alpha ( ) ) ;
}
2016-10-28 12:44:28 +00:00
} // namespace
void ChatBackground : : setThemeData ( QImage & & themeImage , bool themeTile ) {
_themeImage = prepareBackgroundImage ( std_ : : move ( themeImage ) ) ;
_themeTile = themeTile ;
}
void ChatBackground : : start ( ) {
if ( _id = = internal : : kUninitializedBackground ) {
2016-11-04 19:50:35 +00:00
if ( ! Local : : readBackground ( ) ) {
setImage ( kThemeBackground ) ;
}
2016-10-28 12:44:28 +00:00
}
}
void ChatBackground : : setImage ( int32 id , QImage & & image ) {
if ( id = = kThemeBackground & & _themeImage . isNull ( ) ) {
id = kDefaultBackground ;
}
_id = id ;
if ( _id = = kThemeBackground ) {
_tile = _themeTile ;
setPreparedImage ( QImage ( _themeImage ) ) ;
2016-11-02 14:44:33 +00:00
} else if ( _id = = internal : : kTestingThemeBackground | | _id = = internal : : kTestingDefaultBackground ) {
if ( _id = = internal : : kTestingDefaultBackground | | image . isNull ( ) ) {
image . load ( qsl ( " :/gui/art/bg.jpg " ) ) ;
_id = internal : : kTestingDefaultBackground ;
}
setPreparedImage ( std_ : : move ( image ) ) ;
2016-10-28 12:44:28 +00:00
} else {
2016-11-07 15:24:28 +00:00
if ( _id = = kInitialBackground ) {
image . load ( qsl ( " :/gui/art/bg_initial.png " ) ) ;
2016-10-28 12:44:28 +00:00
if ( cRetina ( ) ) {
image = image . scaledToWidth ( image . width ( ) * 2 , Qt : : SmoothTransformation ) ;
} else if ( cScale ( ) ! = dbisOne ) {
image = image . scaledToWidth ( convertScale ( image . width ( ) ) , Qt : : SmoothTransformation ) ;
}
2016-11-07 15:24:28 +00:00
} else if ( _id = = kDefaultBackground | | image . isNull ( ) ) {
_id = kDefaultBackground ;
image . load ( qsl ( " :/gui/art/bg.jpg " ) ) ;
2016-10-28 12:44:28 +00:00
}
2016-11-07 15:24:28 +00:00
Local : : writeBackground ( _id , ( _id = = kDefaultBackground | | _id = = kInitialBackground ) ? QImage ( ) : image ) ;
2016-10-28 12:44:28 +00:00
setPreparedImage ( prepareBackgroundImage ( std_ : : move ( image ) ) ) ;
}
t_assert ( ! _image . isNull ( ) ) ;
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : New , _tile ) ) ;
}
void ChatBackground : : setPreparedImage ( QImage & & image ) {
2016-11-03 10:33:57 +00:00
initColorsFromBackground ( image ) ;
2016-10-28 12:44:28 +00:00
_image = App : : pixmapFromImageInPlace ( std_ : : move ( image ) ) ;
}
int32 ChatBackground : : id ( ) const {
return _id ;
}
const QPixmap & ChatBackground : : image ( ) const {
return _image ;
}
bool ChatBackground : : tile ( ) const {
return _tile ;
}
2016-11-02 14:44:33 +00:00
bool ChatBackground : : tileForSave ( ) const {
if ( _id = = internal : : kTestingThemeBackground | |
_id = = internal : : kTestingDefaultBackground ) {
return _tileForRevert ;
}
return tile ( ) ;
}
void ChatBackground : : ensureStarted ( ) {
2016-10-28 12:44:28 +00:00
if ( _image . isNull ( ) ) {
// We should start first, otherwise the default call
// to start() will reset this value to _themeTile.
start ( ) ;
}
2016-11-02 14:44:33 +00:00
}
void ChatBackground : : setTile ( bool tile ) {
ensureStarted ( ) ;
2016-10-28 12:44:28 +00:00
if ( _tile ! = tile ) {
_tile = tile ;
2016-11-02 14:44:33 +00:00
if ( _id ! = internal : : kTestingThemeBackground & & _id ! = internal : : kTestingDefaultBackground ) {
Local : : writeUserSettings ( ) ;
}
2016-10-28 12:44:28 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : Changed , _tile ) ) ;
}
}
2016-11-02 14:44:33 +00:00
void ChatBackground : : reset ( ) {
if ( _id = = internal : : kTestingThemeBackground | | _id = = internal : : kTestingDefaultBackground ) {
if ( _themeImage . isNull ( ) ) {
_idForRevert = kDefaultBackground ;
_imageForRevert = QImage ( ) ;
_tileForRevert = false ;
} else {
_idForRevert = kThemeBackground ;
_imageForRevert = _themeImage ;
_tileForRevert = _themeTile ;
}
} else {
setImage ( kThemeBackground ) ;
}
}
void ChatBackground : : saveForRevert ( ) {
ensureStarted ( ) ;
if ( _id ! = internal : : kTestingThemeBackground & & _id ! = internal : : kTestingDefaultBackground ) {
_idForRevert = _id ;
_imageForRevert = std_ : : move ( _image ) . toImage ( ) ;
_tileForRevert = _tile ;
}
}
void ChatBackground : : setTestingTheme ( Instance & & theme ) {
style : : main_palette : : apply ( theme . palette ) ;
if ( ! theme . background . isNull ( ) | | _id = = kThemeBackground ) {
saveForRevert ( ) ;
setImage ( internal : : kTestingThemeBackground , std_ : : move ( theme . background ) ) ;
setTile ( theme . tiled ) ;
}
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : TestingTheme , _tile ) , true ) ;
}
void ChatBackground : : keepApplied ( ) {
if ( _id = = internal : : kTestingThemeBackground ) {
_id = kThemeBackground ;
_themeImage = _image . toImage ( ) ;
_themeTile = _tile ;
} else if ( _id = = internal : : kTestingDefaultBackground ) {
_id = kDefaultBackground ;
_themeImage = QImage ( ) ;
_themeTile = false ;
writeNewBackgroundSettings ( ) ;
}
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : ApplyingTheme , _tile ) , true ) ;
}
void ChatBackground : : writeNewBackgroundSettings ( ) {
if ( _tile ! = _tileForRevert ) {
Local : : writeUserSettings ( ) ;
}
Local : : writeBackground ( _id , QImage ( ) ) ;
}
void ChatBackground : : revert ( ) {
if ( _id = = internal : : kTestingThemeBackground | | _id = = internal : : kTestingDefaultBackground ) {
setTile ( _tileForRevert ) ;
setImage ( _idForRevert , std_ : : move ( _imageForRevert ) ) ;
}
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : RevertingTheme , _tile ) , true ) ;
}
2016-10-28 12:44:28 +00:00
ChatBackground * Background ( ) {
instance . createIfNull ( ) ;
return & instance - > background ;
}
bool Load ( const QString & pathRelative , const QString & pathAbsolute , const QByteArray & content , Cached & cache ) {
if ( content . size ( ) < 4 ) {
LOG ( ( " Error: Could not load theme from '%1' (%2) " ) . arg ( pathRelative ) . arg ( pathAbsolute ) ) ;
return false ;
}
instance . createIfNull ( ) ;
if ( loadThemeFromCache ( content , cache ) ) {
return true ;
}
if ( ! loadTheme ( content , cache ) ) {
return false ;
}
Local : : writeTheme ( pathRelative , pathAbsolute , content , cache ) ;
return true ;
}
void Unload ( ) {
instance . clear ( ) ;
}
2016-11-02 14:44:33 +00:00
bool Apply ( const QString & filepath ) {
QByteArray content ;
Instance theme ;
if ( ! LoadFromFile ( filepath , & theme , & content ) ) {
return false ;
}
instance . createIfNull ( ) ;
instance - > applying . path = filepath ;
instance - > applying . content = content ;
instance - > applying . cached = theme . cached ;
if ( instance - > applying . paletteForRevert . isEmpty ( ) ) {
instance - > applying . paletteForRevert = style : : main_palette : : save ( ) ;
}
Background ( ) - > setTestingTheme ( std_ : : move ( theme ) ) ;
return true ;
}
void KeepApplied ( ) {
auto filepath = instance ? instance - > applying . path : QString ( ) ;
if ( filepath . isEmpty ( ) ) {
return ;
}
auto pathRelative = QDir ( ) . relativeFilePath ( filepath ) ;
auto pathAbsolute = QFileInfo ( filepath ) . absoluteFilePath ( ) ;
Local : : writeTheme ( pathRelative , pathAbsolute , instance - > applying . content , instance - > applying . cached ) ;
instance - > applying = Data : : Applying ( ) ;
Background ( ) - > keepApplied ( ) ;
}
void Revert ( ) {
if ( ! instance - > applying . paletteForRevert . isEmpty ( ) ) {
style : : main_palette : : load ( instance - > applying . paletteForRevert ) ;
}
instance - > applying = Data : : Applying ( ) ;
Background ( ) - > revert ( ) ;
}
2016-10-28 12:44:28 +00:00
bool LoadFromFile ( const QString & path , Instance * out , QByteArray * outContent ) {
* outContent = readThemeContent ( path ) ;
if ( outContent - > size ( ) < 4 ) {
LOG ( ( " Error: Could not load theme from %1 " ) . arg ( path ) ) ;
return false ;
}
return loadTheme ( * outContent , out - > cached , out ) ;
}
} // namespace Theme
} // namespace Window