diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index e00198726..39bc72618 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -43,6 +43,58 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_boxes.h" namespace Settings { +namespace { + +const auto kColorizeIgnoredKeys = base::flat_set{ { + qstr("boxTextFgGood"), + qstr("boxTextFgError"), + qstr("historyPeer1NameFg"), + qstr("historyPeer1NameFgSelected"), + qstr("historyPeer1UserpicBg"), + qstr("historyPeer2NameFg"), + qstr("historyPeer2NameFgSelected"), + qstr("historyPeer2UserpicBg"), + qstr("historyPeer3NameFg"), + qstr("historyPeer3NameFgSelected"), + qstr("historyPeer3UserpicBg"), + qstr("historyPeer4NameFg"), + qstr("historyPeer4NameFgSelected"), + qstr("historyPeer4UserpicBg"), + qstr("historyPeer5NameFg"), + qstr("historyPeer5NameFgSelected"), + qstr("historyPeer5UserpicBg"), + qstr("historyPeer6NameFg"), + qstr("historyPeer6NameFgSelected"), + qstr("historyPeer6UserpicBg"), + qstr("historyPeer7NameFg"), + qstr("historyPeer7NameFgSelected"), + qstr("historyPeer7UserpicBg"), + qstr("historyPeer8NameFg"), + qstr("historyPeer8NameFgSelected"), + qstr("historyPeer8UserpicBg"), + qstr("msgFile1Bg"), + qstr("msgFile1BgDark"), + qstr("msgFile1BgOver"), + qstr("msgFile1BgSelected"), + qstr("msgFile2Bg"), + qstr("msgFile2BgDark"), + qstr("msgFile2BgOver"), + qstr("msgFile2BgSelected"), + qstr("msgFile3Bg"), + qstr("msgFile3BgDark"), + qstr("msgFile3BgOver"), + qstr("msgFile3BgSelected"), + qstr("msgFile4Bg"), + qstr("msgFile4BgDark"), + qstr("msgFile4BgOver"), + qstr("msgFile4BgSelected"), + qstr("mediaviewFileRedCornerFg"), + qstr("mediaviewFileYellowCornerFg"), + qstr("mediaviewFileGreenCornerFg"), + qstr("mediaviewFileBlueCornerFg"), +} }; + +} // namespace class BackgroundRow : public Ui::RpWidget { public: @@ -876,10 +928,16 @@ void SetupDefaultThemes(not_null container) { scheme.accentColor)); box->setSaveCallback([=](QColor result) { auto colorizer = Window::Theme::Colorizer(); + colorizer.ignoreKeys = kColorizeIgnoredKeys; colorizer.hueThreshold = 10; - colorizer.saturationThreshold = 10; - colorizer.wasHue = scheme.accentColor.hue(); - colorizer.nowHue = result.hue(); + scheme.accentColor.getHsv( + &colorizer.wasHue, + &colorizer.wasSaturation, + &colorizer.wasValue); + result.getHsv( + &colorizer.nowHue, + &colorizer.nowSaturation, + &colorizer.nowValue); apply(scheme, &colorizer); }); }; diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp index 36bf523b6..89fad322f 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme.cpp @@ -153,24 +153,65 @@ void Colorize( auto saturation = 0; auto value = 0; color.getHsv(&hue, &saturation, &value); - if ((saturation < colorizer->saturationThreshold) - || (std::abs(hue - colorizer->wasHue) > colorizer->hueThreshold)) { - return; - } - const auto changed = hue + (colorizer->nowHue - colorizer->wasHue); + const auto changeColor = std::abs(hue - colorizer->wasHue) + <= colorizer->hueThreshold; + const auto nowHue = hue + (colorizer->nowHue - colorizer->wasHue); + const auto nowSaturation = ((saturation > colorizer->wasSaturation) + && (colorizer->nowSaturation > colorizer->wasSaturation)) + ? (((colorizer->nowSaturation * (255 - colorizer->wasSaturation)) + + ((saturation - colorizer->wasSaturation) + * (255 - colorizer->nowSaturation))) + / (255 - colorizer->wasSaturation)) + : ((saturation != colorizer->wasSaturation) + && (colorizer->wasSaturation != 0)) + ? ((saturation * colorizer->nowSaturation) + / colorizer->wasSaturation) + : colorizer->nowSaturation; + const auto nowValue = (value > colorizer->wasValue) + ? (((colorizer->nowValue * (255 - colorizer->wasValue)) + + ((value - colorizer->wasValue) + * (255 - colorizer->nowValue))) + / (255 - colorizer->wasValue)) + : (value < colorizer->wasValue) + ? ((value * colorizer->nowValue) + / colorizer->wasValue) + : colorizer->nowValue; auto nowR = 0; auto nowG = 0; auto nowB = 0; QColor::fromHsv( - (changed + 360) % 360, - saturation, - value + changeColor ? ((nowHue + 360) % 360) : hue, + changeColor ? nowSaturation : saturation, + nowValue ).getRgb(&nowR, &nowG, &nowB); r = uchar(nowR); g = uchar(nowG); b = uchar(nowB); } +void Colorize(uint32 &pixel, not_null colorizer) { + const auto chars = reinterpret_cast(&pixel); + Colorize( + chars[2], + chars[1], + chars[0], + colorizer); +} + +void Colorize(QImage &image, not_null colorizer) { + image = std::move(image).convertToFormat(QImage::Format_ARGB32); + const auto bytes = image.bits(); + const auto bytesPerLine = image.bytesPerLine(); + for (auto line = 0; line != image.height(); ++line) { + const auto ints = reinterpret_cast( + bytes + line * bytesPerLine); + const auto end = ints + image.width(); + for (auto p = ints; p != end; ++p) { + Colorize(*p, colorizer); + } + } +} + enum class SetResult { Ok, Bad, @@ -190,7 +231,7 @@ SetResult setColorSchemeValue( 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 (colorizer) { + if (colorizer && !colorizer->ignoreKeys.contains(name)) { Colorize(r, g, b, colorizer); } if (error) { @@ -362,6 +403,9 @@ bool loadTheme( LOG(("Theme Error: could not read background image in the theme file.")); return false; } + if (colorizer) { + Colorize(background, colorizer); + } auto buffer = QBuffer(&cache.background); if (!background.save(&buffer, "BMP")) { LOG(("Theme Error: could not write background image as a BMP to cache.")); diff --git a/Telegram/SourceFiles/window/themes/window_theme.h b/Telegram/SourceFiles/window/themes/window_theme.h index 61a6e662c..ee3e3a8c3 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.h +++ b/Telegram/SourceFiles/window/themes/window_theme.h @@ -51,9 +51,13 @@ struct Preview { struct Colorizer { int wasHue = 0; + int wasSaturation = 0; + int wasValue = 0; int nowHue = 0; + int nowSaturation = 0; + int nowValue = 0; int hueThreshold = 0; - int saturationThreshold = 0; + base::flat_set ignoreKeys; }; bool Apply(const QString &filepath);