Keep colorized theme in editor.

This commit is contained in:
John Preston 2019-08-26 19:36:23 +03:00
parent 04d5158ae3
commit a3e993253c
9 changed files with 158 additions and 44 deletions

View File

@ -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;

View File

@ -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() {

View File

@ -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();

View File

@ -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()));

View File

@ -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);

View File

@ -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);
};

View File

@ -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);

View File

@ -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{

View File

@ -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);