mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-25 16:54:25 +00:00
Keep colorized theme in editor.
This commit is contained in:
parent
04d5158ae3
commit
a3e993253c
@ -67,8 +67,12 @@ T *SharedMemoryLocation() {
|
||||
// see https://github.com/boostcon/cppnow_presentations_2012/blob/master/wed/schurr_cpp11_tools_for_class_authors.pdf
|
||||
class str_const { // constexpr string
|
||||
public:
|
||||
template<std::size_t N>
|
||||
constexpr str_const(const char(&a)[N]) : _str(a), _size(N - 1) {
|
||||
constexpr str_const(const char *str, std::size_t size)
|
||||
: _str(str)
|
||||
, _size(size) {
|
||||
}
|
||||
template <std::size_t N>
|
||||
constexpr str_const(const char(&a)[N]) : str_const(a, N - 1) {
|
||||
}
|
||||
constexpr char operator[](std::size_t n) const {
|
||||
return (n < _size) ? _str[n] :
|
||||
@ -79,7 +83,7 @@ public:
|
||||
#endif // OS_MAC_OLD
|
||||
}
|
||||
constexpr std::size_t size() const { return _size; }
|
||||
const char *c_str() const { return _str; }
|
||||
constexpr const char *c_str() const { return _str; }
|
||||
|
||||
private:
|
||||
const char* const _str;
|
||||
|
@ -15,7 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_drafts.h"
|
||||
#include "data/data_user.h"
|
||||
#include "boxes/send_files_box.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "export/export_settings.h"
|
||||
@ -33,7 +32,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
#include "apiwrap.h"
|
||||
#include "main/main_session.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/themes/window_theme_editor.h"
|
||||
#include "base/flags.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
@ -4424,7 +4425,7 @@ std::vector<Lang::Language> readRecentLanguages() {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool copyThemeColorsToPalette(const QString &path) {
|
||||
bool copyThemeColorsToPalette(const QString &destination) {
|
||||
auto &themeKey = Window::Theme::IsNightMode()
|
||||
? _themeKeyNight
|
||||
: _themeKeyDay;
|
||||
@ -4438,12 +4439,16 @@ bool copyThemeColorsToPalette(const QString &path) {
|
||||
}
|
||||
|
||||
QByteArray themeContent;
|
||||
theme.stream >> themeContent;
|
||||
QString pathRelative, pathAbsolute;
|
||||
theme.stream >> themeContent >> pathRelative >> pathAbsolute;
|
||||
if (theme.stream.status() != QDataStream::Ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Window::Theme::CopyColorsToPalette(path, themeContent);
|
||||
return Window::Theme::CopyColorsToPalette(
|
||||
destination,
|
||||
pathAbsolute,
|
||||
themeContent);
|
||||
}
|
||||
|
||||
void writeRecentHashtagsAndBots() {
|
||||
|
@ -152,7 +152,7 @@ bool readBackground();
|
||||
|
||||
void writeTheme(const Window::Theme::Saved &saved);
|
||||
void clearTheme();
|
||||
bool copyThemeColorsToPalette(const QString &file);
|
||||
bool copyThemeColorsToPalette(const QString &destination);
|
||||
Window::Theme::Saved readThemeAfterSwitch();
|
||||
|
||||
void writeLangPack();
|
||||
|
@ -32,7 +32,6 @@ namespace {
|
||||
constexpr auto kThemeFileSizeLimit = 5 * 1024 * 1024;
|
||||
constexpr auto kThemeBackgroundSizeLimit = 4 * 1024 * 1024;
|
||||
constexpr auto kBackgroundSizeLimit = 25 * 1024 * 1024;
|
||||
constexpr auto kThemeSchemeSizeLimit = 1024 * 1024;
|
||||
constexpr auto kNightThemeFile = str_const(":/gui/night.tdesktop-theme");
|
||||
constexpr auto kMinimumTiledSize = 512;
|
||||
|
||||
@ -1229,38 +1228,6 @@ void ComputeBackgroundRects(QRect wholeFill, QSize imageSize, QRect &to, QRect &
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool ReadPaletteValues(const QByteArray &content, Fn<bool(QLatin1String name, QLatin1String value)> callback) {
|
||||
if (content.size() > kThemeSchemeSizeLimit) {
|
||||
LOG(("Theme Error: color scheme file too large (should be less than 1 MB, got %2)").arg(content.size()));
|
||||
|
@ -16,6 +16,8 @@ class Session;
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
|
||||
constexpr auto kThemeSchemeSizeLimit = 1024 * 1024;
|
||||
|
||||
struct Colorizer;
|
||||
|
||||
struct Cached {
|
||||
@ -212,7 +214,10 @@ ChatBackground *Background();
|
||||
|
||||
void ComputeBackgroundRects(QRect wholeFill, QSize imageSize, QRect &to, QRect &from);
|
||||
|
||||
bool CopyColorsToPalette(const QString &path, const QByteArray &themeContent);
|
||||
bool CopyColorsToPalette(
|
||||
const QString &destination,
|
||||
const QString &themePath,
|
||||
const QByteArray &themeContent);
|
||||
|
||||
bool ReadPaletteValues(const QByteArray &content, Fn<bool(QLatin1String name, QLatin1String value)> callback);
|
||||
|
||||
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/themes/window_theme_editor_block.h"
|
||||
#include "window/themes/window_themes_embedded.h"
|
||||
#include "mainwindow.h"
|
||||
#include "layout.h"
|
||||
#include "storage/localstorage.h"
|
||||
@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/parse_helper.h"
|
||||
#include "base/zlib_help.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/application.h"
|
||||
#include "boxes/edit_color_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
||||
@ -184,6 +186,46 @@ QByteArray replaceValueInContent(const QByteArray &content, const QByteArray &na
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray ColorizeInContent(
|
||||
QByteArray content,
|
||||
not_null<const Colorizer*> colorizer) {
|
||||
auto validNames = OrderedSet<QLatin1String>();
|
||||
content.detach();
|
||||
auto start = content.constBegin(), data = start, end = data + content.size();
|
||||
while (data != end) {
|
||||
skipWhitespacesAndComments(data, end);
|
||||
if (data == end) break;
|
||||
|
||||
auto foundName = base::parse::readName(data, end);
|
||||
skipWhitespacesAndComments(data, end);
|
||||
if (data == end || *data != ':') {
|
||||
return "error";
|
||||
}
|
||||
++data;
|
||||
skipWhitespacesAndComments(data, end);
|
||||
auto valueStart = data;
|
||||
auto value = readValue(data, end);
|
||||
auto valueEnd = data;
|
||||
if (value.size() == 0) {
|
||||
return "error";
|
||||
}
|
||||
if (isValidColorValue(value)) {
|
||||
const auto colorized = Colorize(value, colorizer);
|
||||
Assert(colorized.size() == value.size());
|
||||
memcpy(
|
||||
content.data() + (data - start) - value.size(),
|
||||
colorized.data(),
|
||||
value.size());
|
||||
}
|
||||
skipWhitespacesAndComments(data, end);
|
||||
if (data == end || *data != ';') {
|
||||
return "error";
|
||||
}
|
||||
++data;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
QString bytesToUtf8(QLatin1String bytes) {
|
||||
return QString::fromUtf8(bytes.data(), bytes.size());
|
||||
}
|
||||
@ -279,6 +321,57 @@ private:
|
||||
|
||||
};
|
||||
|
||||
bool CopyColorsToPalette(
|
||||
const QString &destination,
|
||||
const QString &themePath,
|
||||
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(destination));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QFile f(destination);
|
||||
if (!f.open(QIODevice::WriteOnly)) {
|
||||
LOG(("Theme Error: could not open file for write '%1'").arg(destination));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (themePath.startsWith(qstr(":/gui"))) {
|
||||
const auto schemes = EmbeddedThemes();
|
||||
const auto i = ranges::find(
|
||||
schemes,
|
||||
themePath,
|
||||
&EmbeddedScheme::path);
|
||||
if (i != end(schemes)) {
|
||||
const auto &colors = Core::App().settings().themesAccentColors();
|
||||
if (const auto accent = colors.get(i->type)) {
|
||||
const auto colorizer = ColorizerFrom(*i, *accent);
|
||||
paletteContent = ColorizeInContent(
|
||||
std::move(paletteContent),
|
||||
&colorizer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f.write(paletteContent) != paletteContent.size()) {
|
||||
LOG(("Theme Error: could not write palette to '%1'").arg(destination));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Editor::Inner::Inner(QWidget *parent, const QString &path) : TWidget(parent)
|
||||
, _path(path)
|
||||
, _existingRows(this, EditorBlock::Type::Existing, &_context)
|
||||
@ -497,14 +590,14 @@ QString colorString(QColor color) {
|
||||
auto result = QString();
|
||||
result.reserve(9);
|
||||
result.append('#');
|
||||
auto addHex = [&result](int code) {
|
||||
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));
|
||||
}
|
||||
};
|
||||
auto addValue = [addHex](int code) {
|
||||
const auto addValue = [&](int code) {
|
||||
addHex(code / 16);
|
||||
addHex(code % 16);
|
||||
};
|
||||
|
@ -18,6 +18,11 @@ class PlainShadow;
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
|
||||
bool CopyColorsToPalette(
|
||||
const QString &destination,
|
||||
const QString &themePath,
|
||||
const QByteArray &themeContent);
|
||||
|
||||
class Editor : public TWidget {
|
||||
public:
|
||||
Editor(QWidget*, const QString &path);
|
||||
|
@ -215,6 +215,38 @@ void Colorize(EmbeddedScheme &scheme, not_null<const Colorizer*> colorizer) {
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray Colorize(
|
||||
QLatin1String hexColor,
|
||||
not_null<const Colorizer*> colorizer) {
|
||||
Expects(hexColor.size() == 7 || hexColor.size() == 9);
|
||||
|
||||
auto color = qColor(str_const(hexColor.data() + 1, 6));
|
||||
Colorize(color, colorizer);
|
||||
|
||||
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(color.red());
|
||||
addValue(color.green());
|
||||
addValue(color.blue());
|
||||
if (hexColor.size() == 9) {
|
||||
result.append(hexColor.data()[7]);
|
||||
result.append(hexColor.data()[8]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<EmbeddedScheme> EmbeddedThemes() {
|
||||
return {
|
||||
EmbeddedScheme{
|
||||
|
@ -71,6 +71,9 @@ void Colorize(
|
||||
not_null<const Colorizer*> colorizer);
|
||||
void Colorize(QImage &image, not_null<const Colorizer*> colorizer);
|
||||
void Colorize(EmbeddedScheme &scheme, not_null<const Colorizer*> colorizer);
|
||||
[[nodiscard]] QByteArray Colorize(
|
||||
QLatin1String hexColor,
|
||||
not_null<const Colorizer*> colorizer);
|
||||
|
||||
[[nodiscard]] std::vector<EmbeddedScheme> EmbeddedThemes();
|
||||
[[nodiscard]] std::vector<QColor> DefaultAccentColors(EmbeddedType type);
|
||||
|
Loading…
Reference in New Issue
Block a user