2016-10-28 12:44:28 +00:00
/*
This file is part of Telegram Desktop ,
2018-01-03 10:23:14 +00:00
the official desktop application for the Telegram messaging service .
2016-10-28 12:44:28 +00:00
2018-01-03 10:23:14 +00:00
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
2016-10-28 12:44:28 +00:00
*/
2017-02-03 20:07:26 +00:00
# include "window/themes/window_theme.h"
2016-10-28 12:44:28 +00:00
2018-07-19 14:58:40 +00:00
# include "window/themes/window_theme_preview.h"
2016-10-28 12:44:28 +00:00
# include "mainwidget.h"
2019-01-28 13:59:49 +00:00
# include "auth_session.h"
# include "core/application.h"
# include "storage/serialize_common.h"
# include "data/data_document.h"
# include "data/data_session.h"
2017-03-04 10:23:56 +00:00
# include "storage/localstorage.h"
2017-04-06 14:38:10 +00:00
# include "base/parse_helper.h"
# include "base/zlib_help.h"
2019-01-28 13:59:49 +00:00
# include "ui/image/image.h"
# include "boxes/background_box.h"
2016-11-16 10:44:06 +00:00
# include "styles/style_widgets.h"
# include "styles/style_history.h"
2019-01-28 13:59:49 +00:00
namespace Data {
namespace {
constexpr auto FromLegacyBackgroundId ( int32 legacyId ) - > WallPaperId {
return uint64 ( 0xFFFFFFFF00000000ULL ) | uint64 ( uint32 ( legacyId ) ) ;
}
constexpr auto kUninitializedBackground = FromLegacyBackgroundId ( - 999 ) ;
constexpr auto kTestingThemeBackground = FromLegacyBackgroundId ( - 666 ) ;
constexpr auto kTestingDefaultBackground = FromLegacyBackgroundId ( - 665 ) ;
constexpr auto kTestingEditorBackground = FromLegacyBackgroundId ( - 664 ) ;
constexpr auto kThemeBackground = FromLegacyBackgroundId ( - 2 ) ;
constexpr auto kCustomBackground = FromLegacyBackgroundId ( - 1 ) ;
constexpr auto kLegacy1DefaultBackground = FromLegacyBackgroundId ( 0 ) ;
constexpr auto kDefaultBackground = FromLegacyBackgroundId ( 105 ) ;
[[nodiscard]] bool ValidateFlags ( MTPDwallPaper : : Flags flags ) {
using Flag = MTPDwallPaper : : Flag ;
const auto all = Flag ( 0 )
| Flag : : f_creator
| Flag : : f_default
| Flag : : f_pattern
| Flag : : f_settings ;
return ! ( flags & ~ all ) ;
}
[[nodiscard]] bool ValidateFlags ( MTPDwallPaperSettings : : Flags flags ) {
using Flag = MTPDwallPaperSettings : : Flag ;
const auto all = Flag ( 0 )
| Flag : : f_background_color
| Flag : : f_blur
| Flag : : f_intensity
| Flag : : f_motion ;
return ! ( flags & ~ all ) ;
}
quint32 SerializeMaybeColor ( std : : optional < QColor > color ) {
return color
? ( ( quint32 ( std : : clamp ( color - > red ( ) , 0 , 255 ) ) < < 16 )
| ( quint32 ( std : : clamp ( color - > green ( ) , 0 , 255 ) ) < < 8 )
| quint32 ( std : : clamp ( color - > blue ( ) , 0 , 255 ) ) )
: quint32 ( - 1 ) ;
}
std : : optional < QColor > MaybeColorFromSerialized ( quint32 serialized ) {
return ( serialized = = quint32 ( - 1 ) )
? std : : nullopt
: std : : make_optional ( QColor (
int ( ( serialized > > 16 ) & 0xFFU ) ,
int ( ( serialized > > 8 ) & 0xFFU ) ,
int ( serialized & 0xFFU ) ) ) ;
}
2019-01-29 07:29:38 +00:00
std : : optional < QColor > ColorFromString ( const QString & string ) {
if ( string . size ( ) ! = 6 ) {
return { } ;
} else if ( ranges : : find_if ( string , [ ] ( QChar ch ) {
return ( ch < ' a ' | | ch > ' f ' )
& & ( ch < ' A ' | | ch > ' F ' )
& & ( ch < ' 0 ' | | ch > ' 9 ' ) ;
} ) ! = string . end ( ) ) {
return { } ;
}
const auto component = [ ] ( const QString & text , int index ) {
const auto decimal = [ ] ( QChar hex ) {
const auto code = hex . unicode ( ) ;
return ( code > = ' 0 ' & & code < = ' 9 ' )
? int ( code - ' 0 ' )
: ( code > = ' a ' & & code < = ' f ' )
? int ( code - ' a ' + 0x0a )
: int ( code - ' A ' + 0x0a ) ;
} ;
index * = 2 ;
return decimal ( text [ index ] ) * 0x10 + decimal ( text [ index + 1 ] ) ;
} ;
return QColor (
component ( string , 0 ) ,
component ( string , 1 ) ,
component ( string , 2 ) ,
255 ) ;
}
QImage PreparePatternImage ( QImage image , QColor bg , QColor fg , int intensity ) {
if ( image . format ( ) ! = QImage : : Format_ARGB32_Premultiplied ) {
image = std : : move ( image ) . convertToFormat (
QImage : : Format_ARGB32_Premultiplied ) ;
}
// Similar to ColorizePattern.
// But here we set bg to all 'alpha=0' pixels and fg to opaque ones.
const auto width = image . width ( ) ;
const auto height = image . height ( ) ;
const auto alpha = anim : : interpolate (
0 ,
255 ,
fg . alphaF ( ) * std : : clamp ( intensity / 100. , 0. , 1. ) ) ;
if ( ! alpha ) {
image . fill ( bg ) ;
2019-01-29 09:39:16 +00:00
return image ;
2019-01-29 07:29:38 +00:00
}
fg . setAlpha ( 255 ) ;
const auto patternBg = anim : : shifted ( bg ) ;
const auto patternFg = anim : : shifted ( fg ) ;
const auto resultBytesPerPixel = ( image . depth ( ) > > 3 ) ;
constexpr auto resultIntsPerPixel = 1 ;
const auto resultIntsPerLine = ( image . bytesPerLine ( ) > > 2 ) ;
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel ;
auto resultInts = reinterpret_cast < uint32 * > ( image . bits ( ) ) ;
Assert ( resultIntsAdded > = 0 ) ;
Assert ( image . depth ( ) = = static_cast < int > ( ( resultIntsPerPixel * sizeof ( uint32 ) ) < < 3 ) ) ;
Assert ( image . bytesPerLine ( ) = = ( resultIntsPerLine < < 2 ) ) ;
const auto maskBytesPerPixel = ( image . depth ( ) > > 3 ) ;
const auto maskBytesPerLine = image . bytesPerLine ( ) ;
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel ;
// We want to read the last byte of four available.
// This is the difference with style::colorizeImage.
auto maskBytes = image . constBits ( ) + ( maskBytesPerPixel - 1 ) ;
Assert ( maskBytesAdded > = 0 ) ;
Assert ( image . depth ( ) = = ( maskBytesPerPixel < < 3 ) ) ;
for ( auto y = 0 ; y ! = height ; + + y ) {
for ( auto x = 0 ; x ! = width ; + + x ) {
const auto maskOpacity = static_cast < anim : : ShiftedMultiplier > (
* maskBytes ) + 1 ;
const auto fgOpacity = ( maskOpacity * alpha ) > > 8 ;
const auto bgOpacity = 256 - fgOpacity ;
* resultInts = anim : : unshifted (
patternBg * bgOpacity + patternFg * fgOpacity ) ;
maskBytes + = maskBytesPerPixel ;
resultInts + = resultIntsPerPixel ;
}
maskBytes + = maskBytesAdded ;
resultInts + = resultIntsAdded ;
}
2019-01-29 09:39:16 +00:00
return image ;
2019-01-29 07:29:38 +00:00
}
2019-01-28 13:59:49 +00:00
} // namespace
WallPaper : : WallPaper ( WallPaperId id ) : _id ( id ) {
}
void WallPaper : : setLocalImageAsThumbnail ( not_null < Image * > image ) {
Expects ( IsDefaultWallPaper ( * this )
| | IsLegacy1DefaultWallPaper ( * this )
| | IsCustomWallPaper ( * this ) ) ;
Expects ( _thumbnail = = nullptr ) ;
_thumbnail = image ;
}
WallPaperId WallPaper : : id ( ) const {
return _id ;
}
std : : optional < QColor > WallPaper : : backgroundColor ( ) const {
return _backgroundColor ;
}
DocumentData * WallPaper : : document ( ) const {
return _document ;
}
Image * WallPaper : : thumbnail ( ) const {
return _thumbnail ;
}
2019-01-29 07:29:38 +00:00
bool WallPaper : : isPattern ( ) const {
return _flags & MTPDwallPaper : : Flag : : f_pattern ;
}
bool WallPaper : : isDefault ( ) const {
return _flags & MTPDwallPaper : : Flag : : f_default ;
}
bool WallPaper : : isCreator ( ) const {
return _flags & MTPDwallPaper : : Flag : : f_creator ;
}
int WallPaper : : patternIntensity ( ) const {
return _intensity ;
}
2019-01-28 13:59:49 +00:00
bool WallPaper : : hasShareUrl ( ) const {
return ! _slug . isEmpty ( ) ;
}
QString WallPaper : : shareUrl ( ) const {
return hasShareUrl ( )
? Core : : App ( ) . createInternalLinkFull ( " bg/ " + _slug )
: QString ( ) ;
}
void WallPaper : : loadThumbnail ( ) const {
if ( _thumbnail ) {
_thumbnail - > load ( fileOrigin ( ) ) ;
}
}
void WallPaper : : loadDocument ( ) const {
if ( _document ) {
_document - > save ( fileOrigin ( ) , QString ( ) ) ;
}
}
FileOrigin WallPaper : : fileOrigin ( ) const {
return FileOriginWallpaper ( _id , _accessHash ) ;
}
2019-01-29 07:29:38 +00:00
WallPaper WallPaper : : withUrlParams (
const QMap < QString , QString > & params ) const {
using Flag = MTPDwallPaperSettings : : Flag ;
auto result = * this ;
result . _settings = Flag ( 0 ) ;
result . _backgroundColor = ColorFromString ( _slug ) ;
result . _intensity = kDefaultIntensity ;
if ( auto mode = params . value ( " mode " ) ; ! mode . isEmpty ( ) ) {
const auto list = mode . replace ( ' + ' , ' ' ) . split ( ' ' ) ;
for ( const auto & change : list ) {
if ( change = = qstr ( " blur " ) ) {
result . _settings | = Flag : : f_blur ;
} else if ( change = = qstr ( " motion " ) ) {
result . _settings | = Flag : : f_motion ;
}
}
}
if ( const auto color = ColorFromString ( params . value ( " bg_color " ) ) ) {
result . _backgroundColor = color ;
}
if ( const auto string = params . value ( " intensity " ) ; ! string . isEmpty ( ) ) {
auto ok = false ;
const auto intensity = string . toInt ( & ok ) ;
if ( ok & & base : : in_range ( intensity , 0 , 100 ) ) {
result . _intensity = intensity ;
}
}
return result ;
}
2019-01-28 13:59:49 +00:00
std : : optional < WallPaper > WallPaper : : Create ( const MTPWallPaper & data ) {
return data . match ( [ ] ( const MTPDwallPaper & data ) {
return Create ( data ) ;
} ) ;
}
std : : optional < WallPaper > WallPaper : : Create ( const MTPDwallPaper & data ) {
2019-01-29 07:29:38 +00:00
using Flag = MTPDwallPaper : : Flag ;
2019-01-28 13:59:49 +00:00
const auto document = Auth ( ) . data ( ) . processDocument (
data . vdocument ) ;
if ( ! document - > checkWallPaperProperties ( ) ) {
return std : : nullopt ;
}
auto result = WallPaper ( data . vid . v ) ;
result . _accessHash = data . vaccess_hash . v ;
result . _flags = data . vflags . v ;
result . _slug = qs ( data . vslug ) ;
result . _document = document ;
result . _thumbnail = document - > thumbnail ( ) ;
if ( data . has_settings ( ) ) {
2019-01-29 07:29:38 +00:00
const auto isPattern = ( ( result . _flags & Flag : : f_pattern ) ! = 0 ) ;
2019-01-28 13:59:49 +00:00
data . vsettings . match ( [ & ] ( const MTPDwallPaperSettings & data ) {
2019-01-29 07:29:38 +00:00
using Flag = MTPDwallPaperSettings : : Flag ;
2019-01-28 13:59:49 +00:00
result . _settings = data . vflags . v ;
2019-01-29 07:29:38 +00:00
if ( isPattern & & data . has_background_color ( ) ) {
2019-01-28 13:59:49 +00:00
result . _backgroundColor = MaybeColorFromSerialized (
data . vbackground_color . v ) ;
2019-01-29 07:29:38 +00:00
} else {
result . _settings & = ~ Flag : : f_background_color ;
2019-01-28 13:59:49 +00:00
}
2019-01-29 07:29:38 +00:00
if ( isPattern & & data . has_intensity ( ) ) {
2019-01-28 13:59:49 +00:00
result . _intensity = data . vintensity . v ;
2019-01-29 07:29:38 +00:00
} else {
result . _settings & = ~ Flag : : f_intensity ;
2019-01-28 13:59:49 +00:00
}
} ) ;
}
return result ;
}
QByteArray WallPaper : : serialize ( ) const {
auto size = sizeof ( quint64 ) // _id
+ sizeof ( quint64 ) // _accessHash
+ sizeof ( qint32 ) // _flags
+ Serialize : : stringSize ( _slug )
+ sizeof ( qint32 ) // _settings
+ sizeof ( quint32 ) // _backgroundColor
+ sizeof ( qint32 ) ; // _intensity
auto result = QByteArray ( ) ;
result . reserve ( size ) ;
{
auto stream = QDataStream ( & result , QIODevice : : WriteOnly ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
stream
< < quint64 ( _id )
< < quint64 ( _accessHash )
< < qint32 ( _flags )
< < _slug
< < qint32 ( _settings )
< < SerializeMaybeColor ( _backgroundColor )
< < qint32 ( _intensity ) ;
}
return result ;
}
std : : optional < WallPaper > WallPaper : : FromSerialized (
const QByteArray & serialized ) {
if ( serialized . isEmpty ( ) ) {
return std : : nullopt ;
}
auto id = quint64 ( ) ;
auto accessHash = quint64 ( ) ;
auto flags = qint32 ( ) ;
auto slug = QString ( ) ;
auto settings = qint32 ( ) ;
auto backgroundColor = quint32 ( ) ;
auto intensity = qint32 ( ) ;
auto stream = QDataStream ( serialized ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
stream
> > id
> > accessHash
> > flags
> > slug
> > settings
> > backgroundColor
2019-01-29 07:29:38 +00:00
> > intensity ;
2019-01-28 13:59:49 +00:00
if ( stream . status ( ) ! = QDataStream : : Ok ) {
return std : : nullopt ;
} else if ( intensity < 0 | | intensity > 100 ) {
return std : : nullopt ;
}
auto result = WallPaper ( id ) ;
result . _accessHash = accessHash ;
result . _flags = MTPDwallPaper : : Flags : : from_raw ( flags ) ;
result . _slug = slug ;
result . _settings = MTPDwallPaperSettings : : Flags : : from_raw ( settings ) ;
result . _backgroundColor = MaybeColorFromSerialized ( backgroundColor ) ;
result . _intensity = intensity ;
if ( ! ValidateFlags ( result . _flags ) | | ! ValidateFlags ( result . _settings ) ) {
return std : : nullopt ;
}
return result ;
}
std : : optional < WallPaper > WallPaper : : FromLegacySerialized (
quint64 id ,
quint64 accessHash ,
quint32 flags ,
QString slug ) {
auto result = WallPaper ( id ) ;
result . _accessHash = accessHash ;
result . _flags = MTPDwallPaper : : Flags : : from_raw ( flags ) ;
result . _slug = slug ;
2019-01-29 07:29:38 +00:00
result . _backgroundColor = ColorFromString ( slug ) ;
2019-01-28 13:59:49 +00:00
if ( ! ValidateFlags ( result . _flags ) ) {
return std : : nullopt ;
}
return result ;
}
std : : optional < WallPaper > WallPaper : : FromLegacyId ( qint32 legacyId ) {
auto result = WallPaper ( FromLegacyBackgroundId ( legacyId ) ) ;
if ( ! IsCustomWallPaper ( result ) ) {
result . _flags = MTPDwallPaper : : Flag : : f_default ;
}
return result ;
}
std : : optional < WallPaper > WallPaper : : FromColorSlug ( const QString & slug ) {
2019-01-29 07:29:38 +00:00
if ( const auto color = ColorFromString ( slug ) ) {
2019-01-28 13:59:49 +00:00
auto result = CustomWallPaper ( ) ;
result . _slug = slug ;
result . _backgroundColor = color ;
return result ;
}
return std : : nullopt ;
}
WallPaper ThemeWallPaper ( ) {
return WallPaper ( kThemeBackground ) ;
}
bool IsThemeWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kThemeBackground ) ;
}
WallPaper CustomWallPaper ( ) {
return WallPaper ( kCustomBackground ) ;
}
bool IsCustomWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kCustomBackground ) ;
}
WallPaper Legacy1DefaultWallPaper ( ) {
return WallPaper ( kLegacy1DefaultBackground ) ;
}
bool IsLegacy1DefaultWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kLegacy1DefaultBackground ) ;
}
WallPaper DefaultWallPaper ( ) {
return WallPaper ( kDefaultBackground ) ;
}
bool IsDefaultWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kDefaultBackground ) ;
}
namespace details {
WallPaper UninitializedWallPaper ( ) {
return WallPaper ( kUninitializedBackground ) ;
}
bool IsUninitializedWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kUninitializedBackground ) ;
}
WallPaper TestingThemeWallPaper ( ) {
return WallPaper ( kTestingThemeBackground ) ;
}
bool IsTestingThemeWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kTestingThemeBackground ) ;
}
WallPaper TestingDefaultWallPaper ( ) {
return WallPaper ( kTestingDefaultBackground ) ;
}
bool IsTestingDefaultWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kTestingDefaultBackground ) ;
}
WallPaper TestingEditorWallPaper ( ) {
return WallPaper ( kTestingEditorBackground ) ;
}
bool IsTestingEditorWallPaper ( const WallPaper & paper ) {
return ( paper . id ( ) = = kTestingEditorBackground ) ;
}
} // namespace details
} // namespace Data
2016-10-28 12:44:28 +00:00
namespace Window {
namespace Theme {
namespace {
2017-06-29 19:09:10 +00:00
constexpr auto kThemeFileSizeLimit = 5 * 1024 * 1024 ;
constexpr auto kThemeBackgroundSizeLimit = 4 * 1024 * 1024 ;
2018-11-01 07:10:15 +00:00
constexpr auto kBackgroundSizeLimit = 25 * 1024 * 1024 ;
2017-06-29 19:09:10 +00:00
constexpr auto kThemeSchemeSizeLimit = 1024 * 1024 ;
constexpr auto kNightThemeFile = str_const ( " :/gui/night.tdesktop-theme " ) ;
2017-01-01 16:45:20 +00:00
2019-01-16 17:26:26 +00:00
struct Applying {
QString pathRelative ;
QString pathAbsolute ;
QByteArray content ;
QByteArray paletteForRevert ;
Cached cached ;
Fn < void ( ) > overrideKeep ;
2016-10-28 12:44:28 +00:00
} ;
2019-01-16 17:26:26 +00:00
NeverFreedPointer < ChatBackground > GlobalBackground ;
Applying GlobalApplying ;
2016-10-28 12:44:28 +00:00
2017-02-03 20:07:26 +00:00
inline bool AreTestingTheme ( ) {
2019-01-16 17:26:26 +00:00
return ! GlobalApplying . paletteForRevert . isEmpty ( ) ;
2017-02-03 20:07:26 +00:00
} ;
2016-10-28 12:44:28 +00:00
QByteArray readThemeContent ( const QString & path ) {
QFile file ( path ) ;
if ( ! file . exists ( ) ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: theme file not found: %1 " ) . arg ( path ) ) ;
2016-10-28 12:44:28 +00:00
return QByteArray ( ) ;
}
if ( file . size ( ) > kThemeFileSizeLimit ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: theme file too large: %1 (should be less than 5 MB, got %2) " ) . arg ( path ) . arg ( file . size ( ) ) ) ;
2016-10-28 12:44:28 +00:00
return QByteArray ( ) ;
}
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
2017-02-03 20:07:26 +00:00
LOG ( ( " Theme Error: could not open theme file: %1 " ) . arg ( path ) ) ;
2016-10-28 12:44:28 +00:00
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 ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: Could not read name in the color scheme. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
if ( ! skipWhitespaces ( from , end ) ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: Unexpected end of the color scheme. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
if ( * from ! = ' : ' ) {
2017-02-03 20:07:26 +00:00
LOG ( ( " Theme Error: Expected ':' between each name and value in the color scheme (while reading key '%1') " ) . arg ( * outName ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
if ( ! skipWhitespaces ( + + from , end ) ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: Unexpected end of the color scheme. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
auto valueStart = from ;
if ( * from = = ' # ' ) + + from ;
2016-11-04 08:23:50 +00:00
if ( readName ( from , end ) . size ( ) = = 0 ) {
2017-02-03 20:07:26 +00:00
LOG ( ( " Theme Error: Expected a color value in #rrggbb or #rrggbbaa format in the color scheme (while reading key '%1') " ) . arg ( * outName ) ) ;
2016-10-28 12:44:28 +00:00
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 ) ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: Unexpected end of the color scheme. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
if ( * from ! = ' ; ' ) {
2017-02-03 20:07:26 +00:00
LOG ( ( " Theme Error: Expected ';' after each value in the color scheme (while reading key '%1') " ) . arg ( * outName ) ) ;
2016-10-28 12:44:28 +00:00
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 ) {
2017-02-03 20:07:26 +00:00
auto result = style : : palette : : SetResult : : Ok ;
2016-11-04 08:23:50 +00:00
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 ) {
2017-02-03 20:07:26 +00:00
LOG ( ( " Theme Warning: Skipping value '%1: %2' (expected a color value in #rrggbb or #rrggbbaa or a previously defined key in the color scheme) " ) . arg ( name ) . arg ( value ) ) ;
return SetResult : : Ok ;
2016-11-04 08:23:50 +00:00
} else if ( out ) {
2017-02-03 20:07:26 +00:00
result = out - > palette . setColor ( name , r , g , b , a ) ;
2016-11-04 08:23:50 +00:00
} else {
2017-02-03 20:07:26 +00:00
result = style : : main_palette : : setColor ( name , r , g , b , a ) ;
2016-11-04 08:23:50 +00:00
}
} else {
if ( out ) {
2017-02-03 20:07:26 +00:00
result = out - > palette . setColor ( name , value ) ;
2016-11-04 08:23:50 +00:00
} else {
2017-02-03 20:07:26 +00:00
result = style : : main_palette : : setColor ( name , value ) ;
2016-11-04 08:23:50 +00:00
}
}
2017-02-03 20:07:26 +00:00
if ( result = = style : : palette : : SetResult : : Ok ) {
return SetResult : : Ok ;
} else if ( result = = style : : palette : : SetResult : : KeyNotFound ) {
return SetResult : : NotFound ;
} else if ( result = = style : : palette : : SetResult : : ValueNotFound ) {
LOG ( ( " Theme Warning: Skipping value '%1: %2' (expected a color value in #rrggbb or #rrggbbaa or a previously defined key in the color scheme) " ) . arg ( name ) . arg ( value ) ) ;
return SetResult : : Ok ;
} else if ( result = = style : : palette : : SetResult : : Duplicate ) {
LOG ( ( " Theme Warning: Color value appears more than once in the color scheme (while applying '%1: %2') " ) . arg ( name ) . arg ( value ) ) ;
return SetResult : : Ok ;
} else {
LOG ( ( " Theme Error: Unexpected internal error. " ) ) ;
2016-10-28 12:44:28 +00:00
}
2017-02-03 20:07:26 +00:00
return SetResult : : Bad ;
}
2016-10-28 12:44:28 +00:00
2017-02-03 20:07:26 +00:00
bool loadColorScheme ( const QByteArray & content , Instance * out ) {
auto unsupported = QMap < QLatin1String , QLatin1String > ( ) ;
return ReadPaletteValues ( content , [ & unsupported , out ] ( QLatin1String name , QLatin1String value ) {
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 ) {
unsupported . insert ( name , value ) ;
2016-10-28 12:44:28 +00:00
}
2017-02-03 20:07:26 +00:00
return true ;
} ) ;
2016-10-28 12:44:28 +00:00
}
void applyBackground ( QImage & & background , bool tiled , Instance * out ) {
if ( out ) {
2017-02-21 13:45:56 +00:00
out - > background = std : : move ( background ) ;
2016-10-28 12:44:28 +00:00
out - > tiled = tiled ;
} else {
2017-02-21 13:45:56 +00:00
Background ( ) - > setThemeData ( std : : move ( background ) , tiled ) ;
2016-10-28 12:44:28 +00:00
}
}
2018-07-19 14:58:40 +00:00
bool loadThemeFromCache ( const QByteArray & content , const 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 ( ) ) {
2018-07-19 14:58:40 +00:00
QDataStream stream ( cache . background ) ;
QImageReader reader ( stream . device ( ) ) ;
2016-10-28 12:44:28 +00:00
# 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 ;
}
2018-07-21 13:54:00 +00:00
Background ( ) - > saveAdjustableColors ( ) ;
2016-10-28 12:44:28 +00:00
if ( ! background . isNull ( ) ) {
2017-02-21 13:45:56 +00:00
applyBackground ( std : : move ( background ) , cache . tiled , nullptr ) ;
2016-10-28 12:44:28 +00:00
}
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 ;
}
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: could not read '%1' in the theme file. " ) . arg ( filename ) ) ;
2016-10-28 12:44:28 +00:00
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 ) ;
2017-02-03 20:07:26 +00:00
if ( file . error ( ) = = UNZ_END_OF_LIST_OF_FILE ) {
file . clearError ( ) ;
schemeContent = file . readFileContent ( " colors.tdesktop-palette " , zlib : : kCaseInsensitive , kThemeSchemeSizeLimit ) ;
}
2016-10-28 12:44:28 +00:00
if ( file . error ( ) ! = UNZ_OK ) {
2017-02-03 20:07:26 +00:00
LOG ( ( " Theme Error: could not read 'colors.tdesktop-theme' or 'colors.tdesktop-palette' in the theme file. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
if ( ! loadColorScheme ( schemeContent , out ) ) {
return false ;
}
2018-07-21 13:54:00 +00:00
Background ( ) - > saveAdjustableColors ( ) ;
2016-10-28 12:44:28 +00:00
auto backgroundTiled = false ;
auto backgroundContent = QByteArray ( ) ;
if ( ! loadBackground ( file , & backgroundContent , & backgroundTiled ) ) {
return false ;
}
if ( ! backgroundContent . isEmpty ( ) ) {
2018-11-01 07:10:15 +00:00
auto check = QBuffer ( & backgroundContent ) ;
auto reader = QImageReader ( & check ) ;
const auto size = reader . size ( ) ;
if ( size . isEmpty ( )
| | ( size . width ( ) * size . height ( ) > kBackgroundSizeLimit ) ) {
LOG ( ( " Theme Error: bad background image size in the theme file. " ) ) ;
return false ;
}
2016-10-28 12:44:28 +00:00
auto background = App : : readImage ( backgroundContent ) ;
if ( background . isNull ( ) ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: could not read background image in the theme file. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
2018-11-01 07:10:15 +00:00
auto buffer = QBuffer ( & cache . background ) ;
2016-10-28 12:44:28 +00:00
if ( ! background . save ( & buffer , " BMP " ) ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: could not write background image as a BMP to cache. " ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
cache . tiled = backgroundTiled ;
2017-02-21 13:45:56 +00:00
applyBackground ( std : : move ( background ) , cache . tiled , out ) ;
2016-10-28 12:44:28 +00:00
}
} else {
// Looks like it is not a .zip theme.
if ( ! loadColorScheme ( content , out ) ) {
return false ;
}
2018-07-21 13:54:00 +00:00
Background ( ) - > saveAdjustableColors ( ) ;
2016-10-28 12:44:28 +00:00
}
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 ) {
2019-01-17 08:18:23 +00:00
if ( image . format ( ) ! = QImage : : Format_ARGB32_Premultiplied ) {
image = std : : move ( image ) . convertToFormat (
QImage : : Format_ARGB32_Premultiplied ) ;
2016-10-28 12:44:28 +00:00
}
image . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-02-21 13:45:56 +00:00
return std : : move ( image ) ;
2016-10-28 12:44:28 +00:00
}
2017-02-03 20:07:26 +00:00
void adjustColor ( style : : color color , float64 hue , float64 saturation ) {
2016-12-21 15:05:58 +00:00
auto original = color - > c ;
original . setHslF ( hue , saturation , original . lightnessF ( ) , original . alphaF ( ) ) ;
color . set ( original . red ( ) , original . green ( ) , original . blue ( ) , original . alpha ( ) ) ;
}
2018-08-02 12:47:50 +00:00
void WriteAppliedTheme ( ) {
auto saved = Saved ( ) ;
2019-01-16 17:26:26 +00:00
saved . pathRelative = GlobalApplying . pathRelative ;
saved . pathAbsolute = GlobalApplying . pathAbsolute ;
saved . content = std : : move ( GlobalApplying . content ) ;
saved . cache = std : : move ( GlobalApplying . cached ) ;
2018-08-02 12:47:50 +00:00
Local : : writeTheme ( saved ) ;
}
void ClearApplying ( ) {
2019-01-16 17:26:26 +00:00
GlobalApplying = Applying ( ) ;
2018-08-02 12:47:50 +00:00
}
2016-10-28 12:44:28 +00:00
} // namespace
2018-07-21 13:54:00 +00:00
ChatBackground : : AdjustableColor : : AdjustableColor ( style : : color data )
: item ( data )
, original ( data - > c ) {
}
ChatBackground : : ChatBackground ( ) : _adjustableColors ( {
st : : msgServiceBg ,
st : : msgServiceBgSelected ,
st : : historyScrollBg ,
st : : historyScrollBgOver ,
st : : historyScrollBarBg ,
st : : historyScrollBarBgOver } ) {
saveAdjustableColors ( ) ;
}
2016-10-28 12:44:28 +00:00
void ChatBackground : : setThemeData ( QImage & & themeImage , bool themeTile ) {
2017-02-21 13:45:56 +00:00
_themeImage = prepareBackgroundImage ( std : : move ( themeImage ) ) ;
2016-10-28 12:44:28 +00:00
_themeTile = themeTile ;
}
void ChatBackground : : start ( ) {
2019-01-28 13:59:49 +00:00
if ( Data : : details : : IsUninitializedWallPaper ( _paper ) ) {
2016-11-04 19:50:35 +00:00
if ( ! Local : : readBackground ( ) ) {
2019-01-28 13:59:49 +00:00
setImage ( Data : : ThemeWallPaper ( ) ) ;
2016-11-04 19:50:35 +00:00
}
2016-10-28 12:44:28 +00:00
}
}
2019-01-16 17:26:26 +00:00
void ChatBackground : : setImage (
const Data : : WallPaper & paper ,
QImage & & image ) {
2019-01-29 07:29:38 +00:00
if ( image . format ( ) ! = QImage : : Format_ARGB32_Premultiplied ) {
image = std : : move ( image ) . convertToFormat (
QImage : : Format_ARGB32_Premultiplied ) ;
}
2019-01-28 13:59:49 +00:00
const auto needResetAdjustable = Data : : IsDefaultWallPaper ( paper )
& & ! Data : : IsDefaultWallPaper ( _paper )
2018-07-19 14:58:40 +00:00
& & ! nightMode ( )
& & _themeAbsolutePath . isEmpty ( ) ;
2019-01-28 13:59:49 +00:00
if ( Data : : IsThemeWallPaper ( paper ) & & _themeImage . isNull ( ) ) {
setPaper ( Data : : DefaultWallPaper ( ) ) ;
2019-01-16 17:26:26 +00:00
} else {
2019-01-17 08:18:23 +00:00
setPaper ( paper ) ;
2019-01-16 17:26:26 +00:00
if ( needResetAdjustable ) {
// If we had a default color theme with non-default background,
// and we switch to default background we must somehow switch from
// adjusted service colors to default (non-adjusted) service colors.
// The only way to do that right now is through full palette reset.
restoreAdjustableColors ( ) ;
}
2016-10-28 12:44:28 +00:00
}
2019-01-28 13:59:49 +00:00
if ( Data : : IsThemeWallPaper ( _paper ) ) {
2018-07-19 14:58:40 +00:00
( nightMode ( ) ? _tileNightValue : _tileDayValue ) = _themeTile ;
2016-10-28 12:44:28 +00:00
setPreparedImage ( QImage ( _themeImage ) ) ;
2019-01-28 13:59:49 +00:00
} else if ( Data : : details : : IsTestingThemeWallPaper ( _paper )
| | Data : : details : : IsTestingDefaultWallPaper ( _paper )
| | Data : : details : : IsTestingEditorWallPaper ( _paper ) ) {
if ( Data : : details : : IsTestingDefaultWallPaper ( _paper ) | | image . isNull ( ) ) {
2016-11-02 14:44:33 +00:00
image . load ( qsl ( " :/gui/art/bg.jpg " ) ) ;
2019-01-28 13:59:49 +00:00
setPaper ( Data : : details : : TestingDefaultWallPaper ( ) ) ;
2016-11-02 14:44:33 +00:00
}
2019-01-17 08:18:23 +00:00
setPreparedImage ( prepareBackgroundImage ( std : : move ( image ) ) ) ;
2016-10-28 12:44:28 +00:00
} else {
2019-01-28 13:59:49 +00:00
if ( Data : : IsLegacy1DefaultWallPaper ( _paper ) ) {
2017-01-17 08:50:22 +00:00
image . load ( qsl ( " :/gui/art/bg_initial.jpg " ) ) ;
2018-10-15 19:42:10 +00:00
const auto scale = cScale ( ) * cIntRetinaFactor ( ) ;
if ( scale ! = 100 ) {
2019-01-17 08:18:23 +00:00
image = image . scaledToWidth (
ConvertScale ( image . width ( ) , scale ) ,
Qt : : SmoothTransformation ) ;
2016-10-28 12:44:28 +00:00
}
2019-01-28 13:59:49 +00:00
} else if ( Data : : IsDefaultWallPaper ( _paper )
2019-01-29 07:29:38 +00:00
| | ( ! _paper . backgroundColor ( ) & & image . isNull ( ) ) ) {
2019-01-28 13:59:49 +00:00
setPaper ( Data : : DefaultWallPaper ( ) ) ;
2016-11-07 15:24:28 +00:00
image . load ( qsl ( " :/gui/art/bg.jpg " ) ) ;
2016-10-28 12:44:28 +00:00
}
2019-01-16 17:26:26 +00:00
Local : : writeBackground (
_paper ,
2019-01-28 13:59:49 +00:00
( ( Data : : IsDefaultWallPaper ( _paper )
| | Data : : IsLegacy1DefaultWallPaper ( _paper ) )
2019-01-16 17:26:26 +00:00
? QImage ( )
: image ) ) ;
2019-01-29 07:29:38 +00:00
if ( const auto fill = _paper . backgroundColor ( ) ) {
if ( _paper . isPattern ( ) & & ! image . isNull ( ) ) {
setPreparedImage ( Data : : PreparePatternImage (
std : : move ( image ) ,
* fill ,
PatternColor ( * fill ) ,
_paper . patternIntensity ( ) ) ) ;
} else {
_pixmap = QPixmap ( ) ;
_pixmapForTiled = QPixmap ( ) ;
if ( adjustPaletteRequired ( ) ) {
adjustPaletteUsingColor ( * fill ) ;
}
2019-01-17 08:18:23 +00:00
}
} else {
setPreparedImage ( prepareBackgroundImage ( std : : move ( image ) ) ) ;
}
2016-10-28 12:44:28 +00:00
}
2019-01-29 07:29:38 +00:00
Assert ( ( ! _pixmap . isNull ( ) & & ! _pixmapForTiled . isNull ( ) )
| | colorForFill ( ) ) ;
2019-01-17 08:18:23 +00:00
2018-07-19 14:58:40 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : New , tile ( ) ) ) ;
2018-07-21 13:54:00 +00:00
if ( needResetAdjustable ) {
2018-07-19 14:58:40 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : TestingTheme , tile ( ) ) , true ) ;
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : ApplyingTheme , tile ( ) ) , true ) ;
2017-06-29 19:09:10 +00:00
}
2016-10-28 12:44:28 +00:00
}
void ChatBackground : : setPreparedImage ( QImage & & image ) {
2019-01-17 08:18:23 +00:00
Expects ( image . format ( ) = = QImage : : Format_ARGB32_Premultiplied ) ;
2017-02-03 20:07:26 +00:00
2019-01-17 08:18:23 +00:00
image . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-02-03 20:07:26 +00:00
2019-01-17 08:18:23 +00:00
if ( adjustPaletteRequired ( ) ) {
2018-07-21 13:54:00 +00:00
adjustPaletteUsingBackground ( image ) ;
2016-12-21 15:05:58 +00:00
}
2017-01-01 16:45:20 +00:00
auto width = image . width ( ) ;
auto height = image . height ( ) ;
2017-08-17 09:06:26 +00:00
Assert ( width > 0 & & height > 0 ) ;
2017-01-01 16:45:20 +00:00
auto isSmallForTiled = ( width < kMinimumTiledSize | | height < kMinimumTiledSize ) ;
if ( isSmallForTiled ) {
auto repeatTimesX = qCeil ( kMinimumTiledSize / float64 ( width ) ) ;
auto repeatTimesY = qCeil ( kMinimumTiledSize / float64 ( height ) ) ;
auto imageForTiled = QImage ( width * repeatTimesX , height * repeatTimesY , QImage : : Format_ARGB32_Premultiplied ) ;
imageForTiled . setDevicePixelRatio ( image . devicePixelRatio ( ) ) ;
auto imageForTiledBytes = imageForTiled . bits ( ) ;
auto bytesInLine = width * sizeof ( uint32 ) ;
for ( auto timesY = 0 ; timesY ! = repeatTimesY ; + + timesY ) {
auto imageBytes = image . constBits ( ) ;
for ( auto y = 0 ; y ! = height ; + + y ) {
for ( auto timesX = 0 ; timesX ! = repeatTimesX ; + + timesX ) {
memcpy ( imageForTiledBytes , imageBytes , bytesInLine ) ;
imageForTiledBytes + = bytesInLine ;
}
imageBytes + = image . bytesPerLine ( ) ;
imageForTiledBytes + = imageForTiled . bytesPerLine ( ) - ( repeatTimesX * bytesInLine ) ;
}
}
2017-02-21 13:45:56 +00:00
_pixmapForTiled = App : : pixmapFromImageInPlace ( std : : move ( imageForTiled ) ) ;
2017-01-01 16:45:20 +00:00
}
2017-02-21 13:45:56 +00:00
_pixmap = App : : pixmapFromImageInPlace ( std : : move ( image ) ) ;
2017-01-01 16:45:20 +00:00
if ( ! isSmallForTiled ) {
_pixmapForTiled = _pixmap ;
}
2016-10-28 12:44:28 +00:00
}
2019-01-17 08:18:23 +00:00
void ChatBackground : : setPaper ( const Data : : WallPaper & paper ) {
_paper = paper ;
}
bool ChatBackground : : adjustPaletteRequired ( ) {
const auto usingThemeBackground = [ & ] {
2019-01-28 13:59:49 +00:00
return Data : : IsThemeWallPaper ( _paper )
| | Data : : details : : IsTestingThemeWallPaper ( _paper ) ;
2019-01-17 08:18:23 +00:00
} ;
const auto usingDefaultBackground = [ & ] {
2019-01-28 13:59:49 +00:00
return Data : : IsDefaultWallPaper ( _paper )
| | Data : : details : : IsTestingDefaultWallPaper ( _paper ) ;
2019-01-17 08:18:23 +00:00
} ;
const auto testingPalette = [ & ] {
const auto path = AreTestingTheme ( )
? GlobalApplying . pathAbsolute
: _themeAbsolutePath ;
return IsPaletteTestingPath ( path ) ;
} ;
if ( testingPalette ( ) ) {
return false ;
} else if ( isNonDefaultThemeOrBackground ( ) | | nightMode ( ) ) {
return ! usingThemeBackground ( ) ;
}
return ! usingDefaultBackground ( ) ;
}
2018-07-21 13:54:00 +00:00
void ChatBackground : : adjustPaletteUsingBackground ( const QImage & img ) {
Assert ( img . format ( ) = = QImage : : Format_ARGB32_Premultiplied ) ;
uint64 components [ 3 ] = { 0 } ;
uint64 componentsScroll [ 3 ] = { 0 } ;
auto w = img . width ( ) ;
auto h = img . height ( ) ;
auto size = w * h ;
if ( auto pix = img . constBits ( ) ) {
for ( auto 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 ( auto i = 0 ; i ! = 3 ; + + i ) {
components [ i ] / = size ;
}
}
2019-01-17 08:18:23 +00:00
adjustPaletteUsingColor (
QColor ( components [ 0 ] , components [ 1 ] , components [ 2 ] ) ) ;
}
void ChatBackground : : adjustPaletteUsingColor ( QColor color ) {
2019-01-29 07:29:38 +00:00
const auto hue = color . hslHueF ( ) ;
const auto saturation = color . hslSaturationF ( ) ;
2018-07-21 13:54:00 +00:00
for ( const auto & color : _adjustableColors ) {
adjustColor ( color . item , hue , saturation ) ;
}
}
2019-01-29 07:29:38 +00:00
std : : optional < QColor > ChatBackground : : colorForFill ( ) const {
return _pixmap . isNull ( ) ? _paper . backgroundColor ( ) : std : : nullopt ;
}
2019-01-17 08:18:23 +00:00
QImage ChatBackground : : createCurrentImage ( ) const {
2019-01-29 07:29:38 +00:00
if ( const auto fill = colorForFill ( ) ) {
2019-01-17 08:18:23 +00:00
auto result = QImage (
kMinimumTiledSize ,
kMinimumTiledSize ,
QImage : : Format_ARGB32_Premultiplied ) ;
result . fill ( * fill ) ;
return result ;
}
2019-01-29 07:29:38 +00:00
return pixmap ( ) . toImage ( ) ; // #TODO patterns
2019-01-17 08:18:23 +00:00
}
2016-10-28 12:44:28 +00:00
bool ChatBackground : : tile ( ) const {
2018-07-19 14:58:40 +00:00
return nightMode ( ) ? _tileNightValue : _tileDayValue ;
}
bool ChatBackground : : tileDay ( ) const {
2019-01-28 13:59:49 +00:00
if ( Data : : details : : IsTestingThemeWallPaper ( _paper ) | |
Data : : details : : IsTestingDefaultWallPaper ( _paper ) ) {
2018-07-19 14:58:40 +00:00
if ( ! nightMode ( ) ) {
return _tileForRevert ;
}
}
return _tileDayValue ;
2016-10-28 12:44:28 +00:00
}
2018-07-19 14:58:40 +00:00
bool ChatBackground : : tileNight ( ) const {
2019-01-28 13:59:49 +00:00
if ( Data : : details : : IsTestingThemeWallPaper ( _paper ) | |
Data : : details : : IsTestingDefaultWallPaper ( _paper ) ) {
2018-07-19 14:58:40 +00:00
if ( nightMode ( ) ) {
return _tileForRevert ;
}
2016-11-02 14:44:33 +00:00
}
2018-07-19 14:58:40 +00:00
return _tileNightValue ;
2016-11-02 14:44:33 +00:00
}
void ChatBackground : : ensureStarted ( ) {
2019-01-29 07:29:38 +00:00
if ( _pixmap . isNull ( ) & & ! _paper . backgroundColor ( ) ) {
2016-10-28 12:44:28 +00:00
// 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 ( ) ;
2018-07-19 14:58:40 +00:00
const auto old = this - > tile ( ) ;
if ( nightMode ( ) ) {
setTileNightValue ( tile ) ;
} else {
setTileDayValue ( tile ) ;
}
if ( this - > tile ( ) ! = old ) {
2019-01-28 13:59:49 +00:00
if ( ! Data : : details : : IsTestingThemeWallPaper ( _paper )
& & ! Data : : details : : IsTestingDefaultWallPaper ( _paper ) ) {
2016-11-02 14:44:33 +00:00
Local : : writeUserSettings ( ) ;
}
2018-07-19 14:58:40 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : Changed , tile ) ) ;
2016-10-28 12:44:28 +00:00
}
}
2018-07-19 14:58:40 +00:00
void ChatBackground : : setTileDayValue ( bool tile ) {
ensureStarted ( ) ;
_tileDayValue = tile ;
}
void ChatBackground : : setTileNightValue ( bool tile ) {
ensureStarted ( ) ;
_tileNightValue = tile ;
}
void ChatBackground : : setThemeAbsolutePath ( const QString & path ) {
_themeAbsolutePath = path ;
}
QString ChatBackground : : themeAbsolutePath ( ) const {
return _themeAbsolutePath ;
}
2016-11-02 14:44:33 +00:00
void ChatBackground : : reset ( ) {
2019-01-28 13:59:49 +00:00
if ( Data : : details : : IsTestingThemeWallPaper ( _paper )
| | Data : : details : : IsTestingDefaultWallPaper ( _paper ) ) {
2016-11-02 14:44:33 +00:00
if ( _themeImage . isNull ( ) ) {
2019-01-28 13:59:49 +00:00
_paperForRevert = Data : : DefaultWallPaper ( ) ;
2016-11-02 14:44:33 +00:00
_imageForRevert = QImage ( ) ;
_tileForRevert = false ;
} else {
2019-01-28 13:59:49 +00:00
_paperForRevert = Data : : ThemeWallPaper ( ) ;
2016-11-02 14:44:33 +00:00
_imageForRevert = _themeImage ;
_tileForRevert = _themeTile ;
}
} else {
2019-01-28 13:59:49 +00:00
setImage ( Data : : ThemeWallPaper ( ) ) ;
2018-07-21 13:54:00 +00:00
restoreAdjustableColors ( ) ;
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : TestingTheme , tile ( ) ) , true ) ;
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : ApplyingTheme , tile ( ) ) , true ) ;
2016-11-02 14:44:33 +00:00
}
}
void ChatBackground : : saveForRevert ( ) {
ensureStarted ( ) ;
2019-01-28 13:59:49 +00:00
if ( ! Data : : details : : IsTestingThemeWallPaper ( _paper )
& & ! Data : : details : : IsTestingDefaultWallPaper ( _paper ) ) {
2019-01-16 17:26:26 +00:00
_paperForRevert = _paper ;
2017-02-21 13:45:56 +00:00
_imageForRevert = std : : move ( _pixmap ) . toImage ( ) ;
2018-07-19 14:58:40 +00:00
_tileForRevert = tile ( ) ;
2016-11-02 14:44:33 +00:00
}
}
2018-07-21 13:54:00 +00:00
void ChatBackground : : saveAdjustableColors ( ) {
for ( auto & color : _adjustableColors ) {
color . original = color . item - > c ;
}
}
void ChatBackground : : restoreAdjustableColors ( ) {
for ( const auto & color : _adjustableColors ) {
const auto value = color . original ;
color . item . set ( value . red ( ) , value . green ( ) , value . blue ( ) , value . alpha ( ) ) ;
}
}
void ChatBackground : : setTestingTheme ( Instance & & theme ) {
2016-11-02 14:44:33 +00:00
style : : main_palette : : apply ( theme . palette ) ;
2018-07-21 13:54:00 +00:00
saveAdjustableColors ( ) ;
auto switchToThemeBackground = ! theme . background . isNull ( )
2019-01-28 13:59:49 +00:00
| | Data : : IsThemeWallPaper ( _paper )
| | ( Data : : IsDefaultWallPaper ( _paper )
2018-07-19 14:58:40 +00:00
& & ! nightMode ( )
& & _themeAbsolutePath . isEmpty ( ) ) ;
2019-01-16 17:26:26 +00:00
if ( AreTestingTheme ( ) & & IsPaletteTestingPath ( GlobalApplying . pathAbsolute ) ) {
2017-02-03 20:07:26 +00:00
// Grab current background image if it is not already custom
2019-01-28 13:59:49 +00:00
if ( ! Data : : IsCustomWallPaper ( _paper ) ) {
2017-02-03 20:07:26 +00:00
saveForRevert ( ) ;
2019-01-28 13:59:49 +00:00
setImage (
Data : : details : : TestingEditorWallPaper ( ) ,
std : : move ( _pixmap ) . toImage ( ) ) ;
2017-02-03 20:07:26 +00:00
}
2017-06-30 12:03:51 +00:00
} else if ( switchToThemeBackground ) {
2016-11-02 14:44:33 +00:00
saveForRevert ( ) ;
2019-01-28 13:59:49 +00:00
setImage (
Data : : details : : TestingThemeWallPaper ( ) ,
std : : move ( theme . background ) ) ;
2016-11-02 14:44:33 +00:00
setTile ( theme . tiled ) ;
2017-01-11 08:16:44 +00:00
} else {
// Apply current background image so that service bg colors are recounted.
2019-01-29 07:29:38 +00:00
// #TODO patterns
2019-01-16 17:26:26 +00:00
setImage ( _paper , std : : move ( _pixmap ) . toImage ( ) ) ;
2016-11-02 14:44:33 +00:00
}
2018-07-19 14:58:40 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : TestingTheme , tile ( ) ) , true ) ;
2016-11-02 14:44:33 +00:00
}
2016-12-20 13:03:51 +00:00
void ChatBackground : : setTestingDefaultTheme ( ) {
style : : main_palette : : reset ( ) ;
2018-07-21 13:54:00 +00:00
saveAdjustableColors ( ) ;
2018-07-19 14:58:40 +00:00
saveForRevert ( ) ;
2019-01-28 13:59:49 +00:00
setImage ( Data : : details : : TestingDefaultWallPaper ( ) ) ;
2018-07-19 14:58:40 +00:00
setTile ( false ) ;
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : TestingTheme , tile ( ) ) , true ) ;
2016-12-20 13:03:51 +00:00
}
2018-07-19 14:58:40 +00:00
void ChatBackground : : keepApplied ( const QString & path , bool write ) {
setThemeAbsolutePath ( path ) ;
2019-01-28 13:59:49 +00:00
if ( Data : : details : : IsTestingEditorWallPaper ( _paper ) ) {
setPaper ( Data : : CustomWallPaper ( ) ) ;
2017-02-03 20:07:26 +00:00
_themeImage = QImage ( ) ;
_themeTile = false ;
2018-07-19 14:58:40 +00:00
if ( write ) {
writeNewBackgroundSettings ( ) ;
}
2019-01-28 13:59:49 +00:00
} else if ( Data : : details : : IsTestingThemeWallPaper ( _paper ) ) {
setPaper ( Data : : ThemeWallPaper ( ) ) ;
2019-01-17 08:18:23 +00:00
_themeImage = prepareBackgroundImage ( _pixmap . toImage ( ) ) ;
2018-07-19 14:58:40 +00:00
_themeTile = tile ( ) ;
if ( write ) {
writeNewBackgroundSettings ( ) ;
}
2019-01-28 13:59:49 +00:00
} else if ( Data : : details : : IsTestingDefaultWallPaper ( _paper ) ) {
setPaper ( Data : : DefaultWallPaper ( ) ) ;
2016-11-02 14:44:33 +00:00
_themeImage = QImage ( ) ;
_themeTile = false ;
2018-07-19 14:58:40 +00:00
if ( write ) {
writeNewBackgroundSettings ( ) ;
}
2016-11-02 14:44:33 +00:00
}
2018-07-19 14:58:40 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : ApplyingTheme , tile ( ) ) , true ) ;
}
2018-07-21 13:54:00 +00:00
bool ChatBackground : : isNonDefaultThemeOrBackground ( ) {
start ( ) ;
2018-07-19 14:58:40 +00:00
return nightMode ( )
? ( _themeAbsolutePath ! = NightThemePath ( )
2019-01-28 13:59:49 +00:00
| | ! Data : : IsThemeWallPaper ( _paper ) )
2018-07-19 14:58:40 +00:00
: ( ! _themeAbsolutePath . isEmpty ( )
2019-01-28 13:59:49 +00:00
| | ! Data : : IsDefaultWallPaper ( _paper ) ) ;
2016-11-02 14:44:33 +00:00
}
2018-09-26 11:28:16 +00:00
bool ChatBackground : : isNonDefaultBackground ( ) {
start ( ) ;
return _themeAbsolutePath . isEmpty ( )
2019-01-28 13:59:49 +00:00
? ! Data : : IsDefaultWallPaper ( _paper )
: ! Data : : IsThemeWallPaper ( _paper ) ;
2018-09-26 11:28:16 +00:00
}
2016-11-02 14:44:33 +00:00
void ChatBackground : : writeNewBackgroundSettings ( ) {
2018-07-19 14:58:40 +00:00
if ( tile ( ) ! = _tileForRevert ) {
2016-11-02 14:44:33 +00:00
Local : : writeUserSettings ( ) ;
}
2018-07-19 14:58:40 +00:00
Local : : writeBackground (
2019-01-16 17:26:26 +00:00
_paper ,
2019-01-28 13:59:49 +00:00
( ( Data : : IsThemeWallPaper ( _paper )
| | Data : : IsDefaultWallPaper ( _paper ) )
2018-07-19 14:58:40 +00:00
? QImage ( )
2019-01-29 07:29:38 +00:00
: _pixmap . toImage ( ) ) ) ; // #TODO patterns
2016-11-02 14:44:33 +00:00
}
void ChatBackground : : revert ( ) {
2019-01-28 13:59:49 +00:00
if ( Data : : details : : IsTestingThemeWallPaper ( _paper )
| | Data : : details : : IsTestingDefaultWallPaper ( _paper )
| | Data : : details : : IsTestingEditorWallPaper ( _paper ) ) {
2016-11-02 14:44:33 +00:00
setTile ( _tileForRevert ) ;
2019-01-16 17:26:26 +00:00
setImage ( _paperForRevert , std : : move ( _imageForRevert ) ) ;
2017-01-11 08:16:44 +00:00
} else {
// Apply current background image so that service bg colors are recounted.
2019-01-29 07:29:38 +00:00
// #TODO patterns
2019-01-16 17:26:26 +00:00
setImage ( _paper , std : : move ( _pixmap ) . toImage ( ) ) ;
2016-11-02 14:44:33 +00:00
}
2018-07-19 14:58:40 +00:00
notify ( BackgroundUpdate ( BackgroundUpdate : : Type : : RevertingTheme , tile ( ) ) , true ) ;
2016-11-02 14:44:33 +00:00
}
2018-07-19 14:58:40 +00:00
void ChatBackground : : setNightModeValue ( bool nightMode ) {
_nightMode = nightMode ;
}
bool ChatBackground : : nightMode ( ) const {
return _nightMode ;
}
2018-09-26 11:28:16 +00:00
void ChatBackground : : toggleNightMode ( std : : optional < QString > themePath ) {
const auto settingDefault = themePath . has_value ( ) ;
2018-07-19 14:58:40 +00:00
const auto oldNightMode = _nightMode ;
const auto newNightMode = ! _nightMode ;
_nightMode = newNightMode ;
2018-09-26 11:28:16 +00:00
auto read = settingDefault ? Saved ( ) : Local : : readThemeAfterSwitch ( ) ;
2018-07-19 14:58:40 +00:00
auto path = read . pathAbsolute ;
_nightMode = oldNightMode ;
auto oldTileValue = ( _nightMode ? _tileNightValue : _tileDayValue ) ;
2018-08-02 12:47:50 +00:00
const auto alreadyOnDisk = [ & ] {
2018-07-19 14:58:40 +00:00
if ( read . content . isEmpty ( ) ) {
return false ;
}
auto preview = std : : make_unique < Preview > ( ) ;
preview - > pathAbsolute = std : : move ( read . pathAbsolute ) ;
preview - > pathRelative = std : : move ( read . pathRelative ) ;
preview - > content = std : : move ( read . content ) ;
preview - > instance . cached = std : : move ( read . cache ) ;
const auto loaded = loadTheme (
preview - > content ,
preview - > instance . cached ,
& preview - > instance ) ;
if ( ! loaded ) {
return false ;
}
Apply ( std : : move ( preview ) ) ;
return true ;
} ( ) ;
2018-08-02 12:47:50 +00:00
if ( ! alreadyOnDisk ) {
2018-09-26 11:28:16 +00:00
path = themePath
? * themePath
: ( newNightMode ? NightThemePath ( ) : QString ( ) ) ;
ApplyDefaultWithPath ( path ) ;
2018-07-19 14:58:40 +00:00
}
// Theme editor could have already reverted the testing of this toggle.
if ( AreTestingTheme ( ) ) {
2019-01-16 17:26:26 +00:00
GlobalApplying . overrideKeep = [ = ] {
2018-09-26 11:28:16 +00:00
_nightMode = newNightMode ;
2018-07-24 19:49:37 +00:00
2018-09-26 11:28:16 +00:00
// Restore the value, it was set inside theme testing.
( oldNightMode ? _tileNightValue : _tileDayValue ) = oldTileValue ;
2018-07-19 14:58:40 +00:00
2018-09-26 11:28:16 +00:00
if ( ! alreadyOnDisk ) {
// First-time switch to default night mode should write it.
WriteAppliedTheme ( ) ;
}
ClearApplying ( ) ;
keepApplied ( path , settingDefault ) ;
if ( tile ( ) ! = _tileForRevert ) {
Local : : writeUserSettings ( ) ;
}
Local : : writeSettings ( ) ;
if ( ! settingDefault & & ! Local : : readBackground ( ) ) {
2019-01-28 13:59:49 +00:00
setImage ( Data : : ThemeWallPaper ( ) ) ;
2018-09-26 11:28:16 +00:00
}
} ;
2018-07-19 14:58:40 +00:00
}
}
2016-11-02 14:44:33 +00:00
2016-10-28 12:44:28 +00:00
ChatBackground * Background ( ) {
2019-01-16 17:26:26 +00:00
GlobalBackground . createIfNull ( ) ;
return GlobalBackground . data ( ) ;
2016-10-28 12:44:28 +00:00
}
2018-07-19 14:58:40 +00:00
bool Load ( Saved & & saved ) {
if ( saved . content . size ( ) < 4 ) {
LOG ( ( " Theme Error: Could not load theme from '%1' (%2) "
) . arg ( saved . pathRelative
) . arg ( saved . pathAbsolute ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
2019-01-16 17:26:26 +00:00
GlobalBackground . createIfNull ( ) ;
2018-07-19 14:58:40 +00:00
if ( loadThemeFromCache ( saved . content , saved . cache ) ) {
Background ( ) - > setThemeAbsolutePath ( saved . pathAbsolute ) ;
2016-10-28 12:44:28 +00:00
return true ;
}
2018-07-19 14:58:40 +00:00
if ( ! loadTheme ( saved . content , saved . cache ) ) {
2016-10-28 12:44:28 +00:00
return false ;
}
2018-07-19 14:58:40 +00:00
Local : : writeTheme ( saved ) ;
Background ( ) - > setThemeAbsolutePath ( saved . pathAbsolute ) ;
2016-10-28 12:44:28 +00:00
return true ;
}
void Unload ( ) {
2019-01-16 17:26:26 +00:00
GlobalBackground . clear ( ) ;
GlobalApplying = Applying ( ) ;
2016-10-28 12:44:28 +00:00
}
2016-11-02 14:44:33 +00:00
bool Apply ( const QString & filepath ) {
2018-07-19 14:58:40 +00:00
if ( auto preview = PreviewFromFile ( filepath ) ) {
return Apply ( std : : move ( preview ) ) ;
2016-11-02 14:44:33 +00:00
}
2018-07-19 14:58:40 +00:00
return false ;
2017-06-29 19:09:10 +00:00
}
2017-02-21 13:45:56 +00:00
bool Apply ( std : : unique_ptr < Preview > preview ) {
2019-01-16 17:26:26 +00:00
GlobalApplying . pathRelative = std : : move ( preview - > pathRelative ) ;
GlobalApplying . pathAbsolute = std : : move ( preview - > pathAbsolute ) ;
GlobalApplying . content = std : : move ( preview - > content ) ;
GlobalApplying . cached = std : : move ( preview - > instance . cached ) ;
if ( GlobalApplying . paletteForRevert . isEmpty ( ) ) {
GlobalApplying . paletteForRevert = style : : main_palette : : save ( ) ;
2016-11-02 14:44:33 +00:00
}
2017-02-21 13:45:56 +00:00
Background ( ) - > setTestingTheme ( std : : move ( preview - > instance ) ) ;
2016-11-02 14:44:33 +00:00
return true ;
}
2018-09-26 11:28:16 +00:00
void ApplyDefaultWithPath ( const QString & themePath ) {
if ( ! themePath . isEmpty ( ) ) {
if ( auto preview = PreviewFromFile ( themePath ) ) {
Apply ( std : : move ( preview ) ) ;
}
} else {
2019-01-16 17:26:26 +00:00
GlobalApplying . pathRelative = QString ( ) ;
GlobalApplying . pathAbsolute = QString ( ) ;
GlobalApplying . content = QByteArray ( ) ;
GlobalApplying . cached = Cached ( ) ;
if ( GlobalApplying . paletteForRevert . isEmpty ( ) ) {
GlobalApplying . paletteForRevert = style : : main_palette : : save ( ) ;
2018-09-26 11:28:16 +00:00
}
Background ( ) - > setTestingDefaultTheme ( ) ;
}
2016-12-20 13:03:51 +00:00
}
2017-02-03 20:07:26 +00:00
bool ApplyEditedPalette ( const QString & path , const QByteArray & content ) {
Instance out ;
if ( ! loadColorScheme ( content , & out ) ) {
return false ;
}
out . cached . colors = out . palette . save ( ) ;
out . cached . paletteChecksum = style : : palette : : Checksum ( ) ;
out . cached . contentChecksum = hashCrc32 ( content . constData ( ) , content . size ( ) ) ;
2019-01-16 17:26:26 +00:00
GlobalApplying . pathRelative = path . isEmpty ( )
2018-07-19 14:58:40 +00:00
? QString ( )
: QDir ( ) . relativeFilePath ( path ) ;
2019-01-16 17:26:26 +00:00
GlobalApplying . pathAbsolute = path . isEmpty ( )
2018-07-19 14:58:40 +00:00
? QString ( )
: QFileInfo ( path ) . absoluteFilePath ( ) ;
2019-01-16 17:26:26 +00:00
GlobalApplying . content = content ;
GlobalApplying . cached = out . cached ;
if ( GlobalApplying . paletteForRevert . isEmpty ( ) ) {
GlobalApplying . paletteForRevert = style : : main_palette : : save ( ) ;
2017-02-03 20:07:26 +00:00
}
2017-02-21 13:45:56 +00:00
Background ( ) - > setTestingTheme ( std : : move ( out ) ) ;
2017-02-03 20:07:26 +00:00
KeepApplied ( ) ;
return true ;
}
2016-11-02 14:44:33 +00:00
void KeepApplied ( ) {
2018-07-19 14:58:40 +00:00
if ( ! AreTestingTheme ( ) ) {
2016-11-02 14:44:33 +00:00
return ;
2019-01-16 17:26:26 +00:00
} else if ( GlobalApplying . overrideKeep ) {
2018-09-26 13:06:30 +00:00
// This callback will be destroyed while running.
// And it won't be able to safely access captures after that.
// So we save it on stack for the time while it is running.
2019-01-16 17:26:26 +00:00
const auto onstack = base : : take ( GlobalApplying . overrideKeep ) ;
onstack ( ) ;
2018-09-26 11:28:16 +00:00
return ;
2016-11-02 14:44:33 +00:00
}
2019-01-16 17:26:26 +00:00
const auto path = GlobalApplying . pathAbsolute ;
2018-08-02 12:47:50 +00:00
WriteAppliedTheme ( ) ;
ClearApplying ( ) ;
Background ( ) - > keepApplied ( path , true ) ;
2016-11-02 14:44:33 +00:00
}
void Revert ( ) {
2018-07-19 14:58:40 +00:00
if ( ! AreTestingTheme ( ) ) {
return ;
2016-11-02 14:44:33 +00:00
}
2019-01-16 17:26:26 +00:00
style : : main_palette : : load ( GlobalApplying . paletteForRevert ) ;
2018-07-21 13:54:00 +00:00
Background ( ) - > saveAdjustableColors ( ) ;
2018-08-02 12:47:50 +00:00
ClearApplying ( ) ;
2016-11-02 14:44:33 +00:00
Background ( ) - > revert ( ) ;
}
2018-07-19 14:58:40 +00:00
QString NightThemePath ( ) {
return str_const_toString ( kNightThemeFile ) ;
}
2018-09-26 11:28:16 +00:00
bool IsNonDefaultBackground ( ) {
return Background ( ) - > isNonDefaultBackground ( ) ;
}
2018-07-19 14:58:40 +00:00
bool IsNightMode ( ) {
2019-01-16 17:26:26 +00:00
return GlobalBackground ? Background ( ) - > nightMode ( ) : false ;
2018-07-19 14:58:40 +00:00
}
void SetNightModeValue ( bool nightMode ) {
2019-01-16 17:26:26 +00:00
if ( GlobalBackground | | nightMode ) {
2018-07-19 14:58:40 +00:00
Background ( ) - > setNightModeValue ( nightMode ) ;
}
}
void ToggleNightMode ( ) {
2018-09-26 11:28:16 +00:00
Background ( ) - > toggleNightMode ( std : : nullopt ) ;
}
void ToggleNightMode ( const QString & path ) {
Background ( ) - > toggleNightMode ( path ) ;
2017-06-29 19:09:10 +00:00
}
2016-10-28 12:44:28 +00:00
bool LoadFromFile ( const QString & path , Instance * out , QByteArray * outContent ) {
* outContent = readThemeContent ( path ) ;
if ( outContent - > size ( ) < 4 ) {
2017-02-02 16:29:36 +00:00
LOG ( ( " Theme Error: Could not load theme from %1 " ) . arg ( path ) ) ;
2016-10-28 12:44:28 +00:00
return false ;
}
return loadTheme ( * outContent , out - > cached , out ) ;
}
2017-02-03 20:07:26 +00:00
bool IsPaletteTestingPath ( const QString & path ) {
if ( path . endsWith ( qstr ( " .tdesktop-palette " ) , Qt : : CaseInsensitive ) ) {
return QFileInfo ( path ) . exists ( ) ;
}
return false ;
}
2016-12-23 13:21:01 +00:00
void ComputeBackgroundRects ( QRect wholeFill , QSize imageSize , QRect & to , QRect & from ) {
if ( uint64 ( imageSize . width ( ) ) * wholeFill . height ( ) > uint64 ( imageSize . height ( ) ) * wholeFill . width ( ) ) {
float64 pxsize = wholeFill . height ( ) / float64 ( imageSize . height ( ) ) ;
int takewidth = qCeil ( wholeFill . width ( ) / pxsize ) ;
if ( takewidth > imageSize . width ( ) ) {
takewidth = imageSize . width ( ) ;
} else if ( ( imageSize . width ( ) % 2 ) ! = ( takewidth % 2 ) ) {
+ + takewidth ;
}
to = QRect ( int ( ( wholeFill . width ( ) - takewidth * pxsize ) / 2. ) , 0 , qCeil ( takewidth * pxsize ) , wholeFill . height ( ) ) ;
from = QRect ( ( imageSize . width ( ) - takewidth ) / 2 , 0 , takewidth , imageSize . height ( ) ) ;
} else {
float64 pxsize = wholeFill . width ( ) / float64 ( imageSize . width ( ) ) ;
int takeheight = qCeil ( wholeFill . height ( ) / pxsize ) ;
if ( takeheight > imageSize . height ( ) ) {
takeheight = imageSize . height ( ) ;
} else if ( ( imageSize . height ( ) % 2 ) ! = ( takeheight % 2 ) ) {
+ + takeheight ;
}
to = QRect ( 0 , int ( ( wholeFill . height ( ) - takeheight * pxsize ) / 2. ) , wholeFill . width ( ) , qCeil ( takeheight * pxsize ) ) ;
from = QRect ( 0 , ( imageSize . height ( ) - takeheight ) / 2 , imageSize . width ( ) , takeheight ) ;
}
}
2017-02-03 20:07:26 +00:00
bool CopyColorsToPalette ( const QString & path , const QByteArray & themeContent ) {
auto paletteContent = themeContent ;
zlib : : FileToRead file ( themeContent ) ;
unz_global_info globalInfo = { 0 } ;
file . getGlobalInfo ( & globalInfo ) ;
if ( file . error ( ) = = UNZ_OK ) {
paletteContent = file . readFileContent ( " colors.tdesktop-theme " , zlib : : kCaseInsensitive , kThemeSchemeSizeLimit ) ;
if ( file . error ( ) = = UNZ_END_OF_LIST_OF_FILE ) {
file . clearError ( ) ;
paletteContent = file . readFileContent ( " colors.tdesktop-palette " , zlib : : kCaseInsensitive , kThemeSchemeSizeLimit ) ;
}
if ( file . error ( ) ! = UNZ_OK ) {
LOG ( ( " Theme Error: could not read 'colors.tdesktop-theme' or 'colors.tdesktop-palette' in the theme file, while copying to '%1'. " ) . arg ( path ) ) ;
return false ;
}
}
QFile f ( path ) ;
if ( ! f . open ( QIODevice : : WriteOnly ) ) {
LOG ( ( " Theme Error: could not open file for write '%1' " ) . arg ( path ) ) ;
return false ;
}
if ( f . write ( paletteContent ) ! = paletteContent . size ( ) ) {
LOG ( ( " Theme Error: could not write palette to '%1' " ) . arg ( path ) ) ;
return false ;
}
return true ;
}
2018-06-04 15:35:11 +00:00
bool ReadPaletteValues ( const QByteArray & content , Fn < bool ( QLatin1String name , QLatin1String value ) > callback ) {
2017-02-03 20:07:26 +00:00
if ( content . size ( ) > kThemeSchemeSizeLimit ) {
LOG ( ( " Theme Error: color scheme file too large (should be less than 1 MB, got %2) " ) . arg ( content . size ( ) ) ) ;
return false ;
}
auto data = base : : parse : : stripComments ( content ) ;
auto from = data . constData ( ) , end = from + data . size ( ) ;
while ( from ! = end ) {
auto name = QLatin1String ( " " ) ;
auto value = QLatin1String ( " " ) ;
if ( ! readNameAndValue ( from , end , & name , & value ) ) {
return false ;
}
if ( name . size ( ) = = 0 ) { // End of content reached.
return true ;
}
if ( ! callback ( name , value ) ) {
return false ;
}
}
return true ;
}
2019-01-29 07:29:38 +00:00
QColor PatternColor ( QColor background ) {
const auto hue = background . hueF ( ) ;
const auto saturation = background . saturationF ( ) ;
const auto value = background . valueF ( ) ;
return QColor : : fromHsvF (
hue ,
std : : min ( 1.0 , saturation + 0.05 + 0.1 * ( 1. - saturation ) ) ,
( value > 0.5
? std : : max ( 0. , value * 0.65 )
: std : : max ( 0. , std : : min ( 1. , 1. - value * 0.65 ) ) ) ,
0.4
) . toRgb ( ) ;
}
2016-10-28 12:44:28 +00:00
} // namespace Theme
} // namespace Window