Move Window::Theme::Colorizer to style::colorizer.

This commit is contained in:
John Preston 2021-09-02 19:58:04 +03:00
parent c4982711db
commit 2554aaf3c0
12 changed files with 71 additions and 256 deletions

View file

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/attach/attach_extensions.h"
#include "ui/layers/generic_box.h"
#include "ui/effects/radial_animation.h"
#include "ui/style/style_palette_colorizer.h"
#include "ui/toast/toast.h"
#include "ui/image/image.h"
#include "ui/ui_utility.h"

View file

@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_domain.h" // Domain::activeSessionValue.
#include "ui/chat/chat_theme.h"
#include "ui/image/image.h"
#include "ui/style/style_palette_colorizer.h"
#include "ui/ui_utility.h"
#include "boxes/confirm_box.h"
#include "boxes/background_box.h"
@ -159,7 +160,7 @@ enum class SetResult {
SetResult setColorSchemeValue(
QLatin1String name,
QLatin1String value,
const Colorizer &colorizer,
const style::colorizer &colorizer,
Instance *out) {
auto result = style::palette::SetResult::Ok;
auto size = value.size();
@ -171,7 +172,7 @@ SetResult setColorSchemeValue(
auto b = readHexUchar(data[5], data[6], error);
auto a = (size == 9) ? readHexUchar(data[7], data[8], error) : uchar(255);
if (colorizer) {
Colorize(name, r, g, b, colorizer);
style::colorize(name, r, g, b, colorizer);
}
if (error) {
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));
@ -206,7 +207,7 @@ SetResult setColorSchemeValue(
bool loadColorScheme(
const QByteArray &content,
const Colorizer &colorizer,
const style::colorizer &colorizer,
Instance *out) {
auto unsupported = QMap<QLatin1String, QLatin1String>();
return ReadPaletteValues(content, [&](QLatin1String name, QLatin1String value) {
@ -268,7 +269,7 @@ bool loadBackground(zlib::FileToRead &file, QByteArray *outBackground, bool *out
bool LoadTheme(
const QByteArray &content,
const Colorizer &colorizer,
const style::colorizer &colorizer,
const std::optional<QByteArray> &editedPalette,
Cached *cache = nullptr,
Instance *out = nullptr) {
@ -282,7 +283,7 @@ bool LoadTheme(
}
zlib::FileToRead file(content);
const auto emptyColorizer = Colorizer();
const auto emptyColorizer = style::colorizer();
const auto &paletteColorizer = editedPalette ? emptyColorizer : colorizer;
unz_global_info globalInfo = { 0 };
@ -331,7 +332,7 @@ bool LoadTheme(
return false;
}
if (colorizer) {
Colorize(background, colorizer);
style::colorize(background, colorizer);
}
if (cache) {
auto buffer = QBuffer(&cache->background);
@ -353,7 +354,7 @@ bool LoadTheme(
}
}
if (out) {
out->palette.finalize();
out->palette.finalize(paletteColorizer);
}
if (cache) {
if (out) {
@ -1270,7 +1271,7 @@ void ApplyDefaultWithPath(const QString &themePath) {
bool ApplyEditedPalette(const QByteArray &content) {
auto out = Instance();
if (!loadColorScheme(content, Colorizer(), &out)) {
if (!loadColorScheme(content, style::colorizer(), &out)) {
return false;
}
style::main_palette::apply(out.palette);
@ -1420,7 +1421,7 @@ bool LoadFromFile(
not_null<Instance*> out,
Cached *outCache,
QByteArray *outContent,
const Colorizer &colorizer) {
const style::colorizer &colorizer) {
const auto content = readThemeContent(path);
if (outContent) {
*outContent = content;
@ -1432,7 +1433,12 @@ bool LoadFromContent(
const QByteArray &content,
not_null<Instance*> out,
Cached *outCache) {
return LoadTheme(content, Colorizer(), std::nullopt, outCache, out);
return LoadTheme(
content,
style::colorizer(),
std::nullopt,
outCache,
out);
}
QString EditingPalettePath() {

View file

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_cloud_themes.h"
#include "ui/style/style_core_palette.h"
namespace style {
struct colorizer;
} // namespace style
namespace Main {
class Session;
} // namespace Main
@ -30,7 +34,6 @@ inline constexpr auto kThemeSchemeSizeLimit = 1024 * 1024;
inline constexpr auto kThemeBackgroundSizeLimit = 4 * 1024 * 1024;
struct ParsedTheme;
struct Colorizer;
[[nodiscard]] bool IsEmbeddedTheme(const QString &path);
@ -107,7 +110,7 @@ bool LoadFromFile(
not_null<Instance*> out,
Cached *outCache,
QByteArray *outContent,
const Colorizer &colorizer);
const style::colorizer &colorizer);
bool LoadFromContent(
const QByteArray &content,
not_null<Instance*> out,

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/multi_select.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/toast/toast.h"
#include "ui/style/style_palette_colorizer.h"
#include "ui/image/image_prepare.h"
#include "ui/ui_utility.h"
#include "base/parse_helper.h"
@ -156,7 +157,7 @@ bool isValidColorValue(QLatin1String value) {
[[nodiscard]] QByteArray ColorizeInContent(
QByteArray content,
const Colorizer &colorizer) {
const style::colorizer &colorizer) {
auto validNames = OrderedSet<QLatin1String>();
content.detach();
auto start = content.constBegin(), data = start, end = data + content.size();
@ -176,7 +177,7 @@ bool isValidColorValue(QLatin1String value) {
return "error";
}
if (isValidColorValue(value)) {
const auto colorized = Colorize(value, colorizer);
const auto colorized = style::colorize(value, colorizer);
Assert(colorized.size() == value.size());
memcpy(
content.data() + (data - start) - value.size(),
@ -809,7 +810,7 @@ void Editor::importTheme() {
QByteArray Editor::ColorizeInContent(
QByteArray content,
const Colorizer &colorizer) {
const style::colorizer &colorizer) {
return Window::Theme::ColorizeInContent(content, colorizer);
}

View file

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h"
#include "base/object_ptr.h"
namespace style {
struct colorizer;
} // namespace style
namespace Ui {
class FlatButton;
class ScrollArea;
@ -27,8 +31,6 @@ class Controller;
namespace Theme {
struct Colorizer;
struct ParsedTheme {
QByteArray palette;
QByteArray background;
@ -54,7 +56,7 @@ public:
[[nodiscard]] static QByteArray ColorizeInContent(
QByteArray content,
const Colorizer &colorizer);
const style::colorizer &colorizer);
protected:
void paintEvent(QPaintEvent *e) override;

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_prepare.h"
#include "ui/toast/toast.h"
#include "ui/text/format_values.h"
#include "ui/style/style_palette_colorizer.h"
#include "ui/special_fields.h"
#include "ui/ui_utility.h"
#include "main/main_account.h"

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_prepare.h"
#include "ui/widgets/popup_menu.h"
#include "ui/toast/toast.h"
#include "ui/style/style_palette_colorizer.h"
#include "boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
@ -135,7 +136,7 @@ CloudListColors ColorsFromScheme(const EmbeddedScheme &scheme) {
CloudListColors ColorsFromScheme(
const EmbeddedScheme &scheme,
const Colorizer &colorizer) {
const style::colorizer &colorizer) {
if (!colorizer) {
return ColorsFromScheme(scheme);
}

View file

@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unique_qptr.h"
#include "base/binary_guard.h"
namespace style {
struct colorizer;
} // namespace style
namespace Ui {
class PopupMenu;
} // namespace Ui
@ -24,7 +28,6 @@ class SessionController;
namespace Theme {
struct EmbeddedScheme;
struct Colorizer;
struct CloudListColors {
QImage background;
@ -37,7 +40,7 @@ struct CloudListColors {
[[nodiscard]] CloudListColors ColorsFromScheme(const EmbeddedScheme &scheme);
[[nodiscard]] CloudListColors ColorsFromScheme(
const EmbeddedScheme &scheme,
const Colorizer &colorizer);
const style::colorizer &colorizer);
class CloudListCheck final : public Ui::AbstractCheckView {
public:

View file

@ -11,13 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/serialize_common.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "ui/style/style_palette_colorizer.h"
namespace Window {
namespace Theme {
namespace {
constexpr auto kMaxAccentColors = 3;
constexpr auto kEnoughLightnessForContrast = 64;
const auto kColorizeIgnoredKeys = base::flat_set<QLatin1String>{ {
qstr("boxTextFgGood"),
@ -69,44 +69,24 @@ const auto kColorizeIgnoredKeys = base::flat_set<QLatin1String>{ {
qstr("mediaviewFileBlueCornerFg"),
} };
QColor qColor(std::string_view hex) {
Expects(hex.size() == 6);
const auto component = [](char a, char b) {
const auto convert = [](char ch) {
Expects((ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'F')
|| (ch >= 'a' && ch <= 'f'));
return (ch >= '0' && ch <= '9')
? int(ch - '0')
: int(ch - ((ch >= 'A' && ch <= 'F') ? 'A' : 'a') + 10);
};
return convert(a) * 16 + convert(b);
};
return QColor(
component(hex[0], hex[1]),
component(hex[2], hex[3]),
component(hex[4], hex[5]));
};
Colorizer::Color cColor(std::string_view hex) {
const auto q = qColor(hex);
style::colorizer::Color cColor(std::string_view hex) {
const auto q = style::ColorFromHex(hex);
auto hue = int();
auto saturation = int();
auto value = int();
q.getHsv(&hue, &saturation, &value);
return Colorizer::Color{ hue, saturation, value };
return style::colorizer::Color{ hue, saturation, value };
}
} // namespace
Colorizer ColorizerFrom(const EmbeddedScheme &scheme, const QColor &color) {
using Color = Colorizer::Color;
style::colorizer ColorizerFrom(
const EmbeddedScheme &scheme,
const QColor &color) {
using Color = style::colorizer::Color;
using Pair = std::pair<Color, Color>;
auto result = Colorizer();
auto result = style::colorizer();
result.ignoreKeys = kColorizeIgnoredKeys;
result.hueThreshold = 15;
scheme.accentColor.getHsv(
@ -168,9 +148,9 @@ Colorizer ColorizerFrom(const EmbeddedScheme &scheme, const QColor &color) {
return result;
}
Colorizer ColorizerForTheme(const QString &absolutePath) {
style::colorizer ColorizerForTheme(const QString &absolutePath) {
if (absolutePath.isEmpty() || !IsEmbeddedTheme(absolutePath)) {
return Colorizer();
return {};
}
const auto schemes = EmbeddedThemes();
const auto i = ranges::find(
@ -178,150 +158,16 @@ Colorizer ColorizerForTheme(const QString &absolutePath) {
absolutePath,
&EmbeddedScheme::path);
if (i == end(schemes)) {
return Colorizer();
return {};
}
const auto &colors = Core::App().settings().themesAccentColors();
if (const auto accent = colors.get(i->type)) {
return ColorizerFrom(*i, *accent);
}
return Colorizer();
return {};
}
[[nodiscard]] std::optional<Colorizer::Color> Colorize(
const Colorizer::Color &color,
const Colorizer &colorizer) {
const auto changeColor = std::abs(color.hue - colorizer.was.hue)
< colorizer.hueThreshold;
if (!changeColor) {
return std::nullopt;
}
const auto nowHue = color.hue + (colorizer.now.hue - colorizer.was.hue);
const auto nowSaturation = ((color.saturation > colorizer.was.saturation)
&& (colorizer.now.saturation > colorizer.was.saturation))
? (((colorizer.now.saturation * (255 - colorizer.was.saturation))
+ ((color.saturation - colorizer.was.saturation)
* (255 - colorizer.now.saturation)))
/ (255 - colorizer.was.saturation))
: ((color.saturation != colorizer.was.saturation)
&& (colorizer.was.saturation != 0))
? ((color.saturation * colorizer.now.saturation)
/ colorizer.was.saturation)
: colorizer.now.saturation;
const auto nowValue = (color.value > colorizer.was.value)
? (((colorizer.now.value * (255 - colorizer.was.value))
+ ((color.value - colorizer.was.value)
* (255 - colorizer.now.value)))
/ (255 - colorizer.was.value))
: (color.value < colorizer.was.value)
? ((color.value * colorizer.now.value)
/ colorizer.was.value)
: colorizer.now.value;
return Colorizer::Color{
((nowHue + 360) % 360),
nowSaturation,
nowValue
};
}
[[nodiscard]] std::optional<QColor> Colorize(
const QColor &color,
const Colorizer &colorizer) {
auto hue = 0;
auto saturation = 0;
auto lightness = 0;
color.getHsv(&hue, &saturation, &lightness);
const auto result = Colorize(
Colorizer::Color{ hue, saturation, lightness },
colorizer);
if (!result) {
return std::nullopt;
}
const auto &fields = *result;
return QColor::fromHsv(fields.hue, fields.saturation, fields.value);
}
void FillColorizeResult(uchar &r, uchar &g, uchar &b, const QColor &color) {
auto nowR = 0;
auto nowG = 0;
auto nowB = 0;
color.getRgb(&nowR, &nowG, &nowB);
r = uchar(nowR);
g = uchar(nowG);
b = uchar(nowB);
}
void Colorize(uchar &r, uchar &g, uchar &b, const Colorizer &colorizer) {
const auto changed = Colorize(QColor(int(r), int(g), int(b)), colorizer);
if (changed) {
FillColorizeResult(r, g, b, *changed);
}
}
void Colorize(
QLatin1String name,
uchar &r,
uchar &g,
uchar &b,
const Colorizer &colorizer) {
if (colorizer.ignoreKeys.contains(name)) {
return;
}
const auto i = colorizer.keepContrast.find(name);
if (i == end(colorizer.keepContrast)) {
Colorize(r, g, b, colorizer);
return;
}
const auto check = i->second.first;
const auto rgb = QColor(int(r), int(g), int(b));
const auto changed = Colorize(rgb, colorizer);
const auto checked = Colorize(check, colorizer).value_or(check);
const auto lightness = [](QColor hsv) {
return hsv.value() - (hsv.value() * hsv.saturation()) / 511;
};
const auto changedLightness = lightness(changed.value_or(rgb).toHsv());
const auto checkedLightness = lightness(
QColor::fromHsv(checked.hue, checked.saturation, checked.value));
const auto delta = std::abs(changedLightness - checkedLightness);
if (delta >= kEnoughLightnessForContrast) {
if (changed) {
FillColorizeResult(r, g, b, *changed);
}
return;
}
const auto replace = i->second.second;
const auto result = Colorize(replace, colorizer).value_or(replace);
FillColorizeResult(
r,
g,
b,
QColor::fromHsv(result.hue, result.saturation, result.value));
}
void Colorize(uint32 &pixel, const Colorizer &colorizer) {
const auto chars = reinterpret_cast<uchar*>(&pixel);
Colorize(
chars[2],
chars[1],
chars[0],
colorizer);
}
void Colorize(QImage &image, const Colorizer &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<uint32*>(
bytes + line * bytesPerLine);
const auto end = ints + image.width();
for (auto p = ints; p != end; ++p) {
Colorize(*p, colorizer);
}
}
}
void Colorize(EmbeddedScheme &scheme, const Colorizer &colorizer) {
void Colorize(EmbeddedScheme &scheme, const style::colorizer &colorizer) {
const auto colors = {
&EmbeddedScheme::background,
&EmbeddedScheme::sent,
@ -330,45 +176,16 @@ void Colorize(EmbeddedScheme &scheme, const Colorizer &colorizer) {
&EmbeddedScheme::radiobuttonInactive
};
for (const auto color : colors) {
if (const auto changed = Colorize(scheme.*color, colorizer)) {
if (const auto changed = style::colorize(scheme.*color, colorizer)) {
scheme.*color = changed->toRgb();
}
}
}
QByteArray Colorize(
QLatin1String hexColor,
const Colorizer &colorizer) {
Expects(hexColor.size() == 7 || hexColor.size() == 9);
auto color = qColor(std::string_view(hexColor.data() + 1, 6));
const auto changed = Colorize(color, colorizer).value_or(color).toRgb();
auto result = QByteArray();
result.reserve(hexColor.size());
result.append(hexColor.data()[0]);
const auto addHex = [&](int code) {
if (code >= 0 && code < 10) {
result.append('0' + code);
} else if (code >= 10 && code < 16) {
result.append('a' + (code - 10));
}
};
const auto addValue = [&](int code) {
addHex(code / 16);
addHex(code % 16);
};
addValue(changed.red());
addValue(changed.green());
addValue(changed.blue());
if (hexColor.size() == 9) {
result.append(hexColor.data()[7]);
result.append(hexColor.data()[8]);
}
return result;
}
std::vector<EmbeddedScheme> EmbeddedThemes() {
const auto qColor = [](auto hex) {
return style::ColorFromHex(hex);
};
return {
EmbeddedScheme{
EmbeddedType::Default,
@ -417,6 +234,9 @@ std::vector<EmbeddedScheme> EmbeddedThemes() {
}
std::vector<QColor> DefaultAccentColors(EmbeddedType type) {
const auto qColor = [](auto hex) {
return style::ColorFromHex(hex);
};
switch (type) {
case EmbeddedType::DayBlue:
return {

View file

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class QImage;
namespace style {
struct colorizer;
} // namespace style
namespace Window {
namespace Theme {
@ -47,42 +51,14 @@ private:
};
struct Colorizer {
struct Color {
int hue = 0;
int saturation = 0;
int value = 0;
};
int hueThreshold = 0;
int lightnessMin = 0;
int lightnessMax = 255;
Color was;
Color now;
base::flat_set<QLatin1String> ignoreKeys;
base::flat_map<QLatin1String, std::pair<Color, Color>> keepContrast;
explicit operator bool() const {
return (hueThreshold > 0);
}
};
[[nodiscard]] Colorizer ColorizerFrom(
[[nodiscard]] style::colorizer ColorizerFrom(
const EmbeddedScheme &scheme,
const QColor &color);
[[nodiscard]] Colorizer ColorizerForTheme(const QString &absolutePath);
[[nodiscard]] style::colorizer ColorizerForTheme(const QString &absolutePath);
void Colorize(uchar &r, uchar &g, uchar &b, const Colorizer &colorizer);
void Colorize(
QLatin1String name,
uchar &r,
uchar &g,
uchar &b,
const Colorizer &colorizer);
void Colorize(QImage &image, const Colorizer &colorizer);
void Colorize(EmbeddedScheme &scheme, const Colorizer &colorizer);
[[nodiscard]] QByteArray Colorize(
QLatin1String hexColor,
const Colorizer &colorizer);
EmbeddedScheme &scheme,
const style::colorizer &colorizer);
[[nodiscard]] std::vector<EmbeddedScheme> EmbeddedThemes();
[[nodiscard]] std::vector<QColor> DefaultAccentColors(EmbeddedType type);

View file

@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/message_bubble.h"
#include "ui/chat/chat_style.h"
#include "ui/chat/chat_theme.h"
#include "ui/style/style_palette_colorizer.h"
#include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h"
#include "calls/calls_instance.h" // Core::App().calls().inCall().
@ -95,7 +96,7 @@ constexpr auto kMaxChatEntryHistorySize = 50;
&instance,
nullptr,
nullptr,
accent ? ColorizerFrom(*i, *accent) : Colorizer());
accent ? ColorizerFrom(*i, *accent) : style::colorizer());
Assert(loaded);
palette = instance.palette;
} else {

@ -1 +1 @@
Subproject commit c88762d0eb860064927bacaa784acd9a4f23c39b
Subproject commit cc5ebf21e747802e60941083da0e0d7d1bfbb2aa