From af9edc17d2ec685257309d07439fbb1f249dd126 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 1 Nov 2016 23:59:51 +0300 Subject: [PATCH] Applying color theme without restarting the application. --- Telegram/Resources/basic.style | 1 - Telegram/Resources/colors.palette | 6 + Telegram/Resources/sample.tdesktop-theme | 4 + Telegram/SourceFiles/app.cpp | 39 +----- Telegram/SourceFiles/app.h | 1 - .../SourceFiles/codegen/style/generator.cpp | 113 ++++++++++++----- Telegram/SourceFiles/facades.cpp | 4 - Telegram/SourceFiles/facades.h | 2 - Telegram/SourceFiles/localstorage.cpp | 33 ++--- Telegram/SourceFiles/mainwidget.cpp | 1 - Telegram/SourceFiles/overviewwidget.cpp | 9 +- Telegram/SourceFiles/overviewwidget.h | 2 - .../settings/settings_background_widget.cpp | 2 +- .../SourceFiles/ui/style/style_core_color.cpp | 36 +++--- .../SourceFiles/ui/style/style_core_color.h | 25 ++-- .../SourceFiles/ui/style/style_core_icon.cpp | 59 ++++++--- .../SourceFiles/ui/style/style_core_icon.h | 115 ++++++++++++++---- 17 files changed, 275 insertions(+), 177 deletions(-) diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style index 8c925db16..4da47a1fb 100644 --- a/Telegram/Resources/basic.style +++ b/Telegram/Resources/basic.style @@ -277,7 +277,6 @@ boxScroll: flatScroll(solidScroll) { boxScrollSkip: 6px; boxScrollShadowBg: #00000012; -titleBg: #6389a8; titleHeight: 39px; titleFont: font(17px); titlePos: point(44px, 29px); diff --git a/Telegram/Resources/colors.palette b/Telegram/Resources/colors.palette index cd38d6629..ddc62dd09 100644 --- a/Telegram/Resources/colors.palette +++ b/Telegram/Resources/colors.palette @@ -29,6 +29,8 @@ windowSubTextFgOver: #7c99b2; // gray over light blue: fallback for subtext over windowActiveTextFg: #1485c2; // online blue: fallback for active color windowShadowFg: #000000; // black: fallback for shadow color +titleBg: #6389a8; + imageBg: #000000; imageBgTransparent: #ffffff; @@ -124,6 +126,10 @@ historyCaptionOutFg: historyTextOutFg; historyFileNameInFg: historyTextInFg; historyFileNameOutFg: historyTextOutFg; +historySystemBg: #89a0b47f; +historySystemBgSelected: #bbc8d4a2; +historySystemFg: #ffffff; + // mediaview mediaviewFileBg: windowBg; mediaviewFileNameFg: windowTextFg; diff --git a/Telegram/Resources/sample.tdesktop-theme b/Telegram/Resources/sample.tdesktop-theme index b38bf9404..bd97b03b8 100644 --- a/Telegram/Resources/sample.tdesktop-theme +++ b/Telegram/Resources/sample.tdesktop-theme @@ -29,6 +29,7 @@ windowOverBg: #edf2f5; windowSubTextFgOver: #7c99b2; windowActiveTextFg: #1485c2; windowShadowFg: #000000; +titleBg: #6389a8; imageBg: #000000; imageBgTransparent: #ffffff; trayCounterBg: #f23c34; @@ -97,6 +98,9 @@ historyCaptionInFg: historyTextInFg; historyCaptionOutFg: historyTextOutFg; historyFileNameInFg: historyTextInFg; historyFileNameOutFg: historyTextOutFg; +historySystemBg: #89a0b47f; +historySystemBgSelected: #bbc8d4a2; +historySystemFg: #ffffff; mediaviewFileBg: windowBg; mediaviewFileNameFg: windowTextFg; mediaviewFileSizeFg: windowSubTextFg; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index fb54feaa0..b4e26531a 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2774,37 +2774,6 @@ namespace { roundRect(p, x, y, w, h, bg, i.value(), 0); } - void initBackground(int32 id, const QImage &p, bool nowrite) { - if (Local::readBackground()) return; - - QImage img(p); - bool remove = (id == Window::Theme::kThemeBackground); - if (p.isNull()) { - if (id == Window::Theme::kDefaultBackground) { - img.load(qsl(":/gui/art/bg.jpg")); - } else { - img.load(qsl(":/gui/art/bg_old.png")); - if (cRetina()) { - img = img.scaledToWidth(img.width() * 2, Qt::SmoothTransformation); - } else if (cScale() != dbisOne) { - img = img.scaledToWidth(convertScale(img.width()), Qt::SmoothTransformation); - } - id = Window::Theme::kOldBackground; - } - remove = true; - } - if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied && img.format() != QImage::Format_RGB32) { - img = img.convertToFormat(QImage::Format_RGB32); - } - img.setDevicePixelRatio(cRetinaFactor()); - - if (!nowrite) { - Local::writeBackground(id, remove ? QImage() : img); - } - - initColorsFromBackground(img); - } - void initColorsFromBackground(const QImage &img) { uint64 components[3] = { 0 }, componentsScroll[3] = { 0 }; auto w = img.width(); @@ -2889,10 +2858,10 @@ namespace { prepareCorners(StickerSelectedCorners, st::dateRadius, _msgServiceSelectBg); uchar rScroll = uchar(componentsScroll[0]), gScroll = uchar(componentsScroll[1]), bScroll = uchar(componentsScroll[2]); - _historyScrollBarColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.barColor->c.alphaF() * 0xFF)); - _historyScrollBgColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.bgColor->c.alphaF() * 0xFF)); - _historyScrollBarOverColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.barOverColor->c.alphaF() * 0xFF)); - _historyScrollBgOverColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.bgOverColor->c.alphaF() * 0xFF)); + _historyScrollBarColor = style::color(rScroll, gScroll, bScroll, st::historyScroll.barColor->c.alpha()); + _historyScrollBgColor = style::color(rScroll, gScroll, bScroll, st::historyScroll.bgColor->c.alpha()); + _historyScrollBarOverColor = style::color(rScroll, gScroll, bScroll, st::historyScroll.barOverColor->c.alpha()); + _historyScrollBgOverColor = style::color(rScroll, gScroll, bScroll, st::historyScroll.bgOverColor->c.alpha()); if (App::main()) { App::main()->updateScrollColors(); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index e7b9fd858..4dceffcc3 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -294,7 +294,6 @@ namespace App { } void initColorsFromBackground(const QImage &image); - void initBackground(int32 id, const QImage &p = QImage(), bool nowrite = false); const style::color &msgServiceBg(); const style::color &msgServiceSelectBg(); diff --git a/Telegram/SourceFiles/codegen/style/generator.cpp b/Telegram/SourceFiles/codegen/style/generator.cpp index a475920de..9a199fd02 100644 --- a/Telegram/SourceFiles/codegen/style/generator.cpp +++ b/Telegram/SourceFiles/codegen/style/generator.cpp @@ -435,6 +435,9 @@ bool Generator::writePaletteDefinition() { header_->stream() << "\ class palette {\n\ public:\n\ + palette() = default;\n\ + palette(const palette &other) = delete;\n\ +\n\ QByteArray save() const;\n\ bool load(const QByteArray &cache);\n\ bool setColor(QLatin1String name, uchar r, uchar g, uchar b, uchar a);\n\ @@ -451,29 +454,90 @@ public:\n\ return false; } - auto type = typeToString(variable.value.type()); auto index = (indexInPalette++); - header_->stream() << "\tinline const " << type << " &" << name << "() const { return _colors[" << index << "]; };\n"; + header_->stream() << "\tinline const color &" << name << "() const { return _colors[" << index << "]; };\n"; return true; })) return false; auto count = indexInPalette; - auto type = typeToString({ structure::TypeTag::Color }); header_->stream() << "\ +\n\ + palette &operator=(const palette &other) {\n\ + auto wasReady = _ready;\n\ + for (int i = 0; i != " << count << "; ++i) {\n\ + if (other._status[i] == Status::Loaded) {\n\ + if (_status[i] == Status::Initial) {\n\ + new (data(i)) internal::ColorData(*other.data(i));\n\ + } else {\n\ + *data(i) = *other.data(i);\n\ + }\n\ + } else if (_status[i] != Status::Initial) {\n\ + data(i)->~ColorData();\n\ + _status[i] = Status::Initial;\n\ + _ready = false;\n\ + }\n\ + }\n\ + if (wasReady && !_ready) {\n\ + finalize();\n\ + }\n\ + return *this;\n\ + }\n\ \n\ static int32 Checksum();\n\ +\n\ + ~palette() {\n\ + for (int i = 0; i != " << count << "; ++i) {\n\ + if (_status[i] != Status::Initial) {\n\ + data(i)->~ColorData();\n\ + }\n\ + }\n\ + }\n\ \n\ private:\n\ struct TempColorData { uchar r, g, b, a; };\n\ - void compute(int index, int fallbackIndex, TempColorData data);\n\ + void compute(int index, int fallbackIndex, TempColorData value) {\n\ + if (_status[index] == Status::Initial) {\n\ + if (fallbackIndex >= 0 && _status[fallbackIndex] != Status::Initial) {\n\ + _status[index] = Status::Loaded;\n\ + new (data(index)) internal::ColorData(*data(fallbackIndex));\n\ + } else {\n\ + _status[index] = Status::Created;\n\ + new (data(index)) internal::ColorData(value.r, value.g, value.b, value.a);\n\ + }\n\ + }\n\ + }\n\ +\n\ + internal::ColorData *data(int index) {\n\ + return reinterpret_cast(_data) + index;\n\ + }\n\ +\n\ + const internal::ColorData *data(int index) const {\n\ + return reinterpret_cast(_data) + index;\n\ + }\n\ +\n\ + void setData(int index, const internal::ColorData &value) {\n\ + if (_status[index] == Status::Initial) {\n\ + new (data(index)) internal::ColorData(value);\n\ + } else {\n\ + *data(index) = value;\n\ + }\n\ + _status[index] = Status::Loaded;\n\ + }\n\ \n\ enum class Status {\n\ Initial,\n\ + Created,\n\ Loaded,\n\ - Fallback,\n\ };\n\ \n\ - " << type << " _colors[" << count << "] = { Qt::Uninitialized };\n\ + alignas(alignof(internal::ColorData)) char _data[sizeof(internal::ColorData) * " << count << "];\n\ +\n\ + color _colors[" << count << "] = {\n"; + for (int i = 0; i != count; ++i) { + header_->stream() << "\t\tdata(" << i << "),\n"; + } + header_->stream() << "\ + };\n\ Status _status[" << count << "] = { Status::Initial };\n\ bool _ready = false;\n\ \n\ @@ -485,9 +549,9 @@ QByteArray save();\n\ bool load(const QByteArray &cache);\n\ bool setColor(QLatin1String name, uchar r, uchar g, uchar b, uchar a);\n\ bool setColor(QLatin1String name, QLatin1String from);\n\ +void apply(const palette &other);\n\ \n\ -} // namespace main_palette\n\ -\n"; +} // namespace main_palette\n"; header_->newline(); @@ -648,17 +712,6 @@ void palette::finalize() {\n\ \n\ int32 palette::Checksum() {\n\ return " << checksum << ";\n\ -}\n\ -\n\ -void palette::compute(int index, int fallbackIndex, TempColorData data) {\n\ - if (_status[index] == Status::Initial) {\n\ - if (fallbackIndex >= 0 && _status[fallbackIndex] != Status::Initial) {\n\ - _status[index] = Status::Fallback;\n\ - _colors[index] = _colors[fallbackIndex];\n\ - } else {\n\ - _colors[index] = { data.r, data.g, data.b, data.a };\n\ - }\n\ - }\n\ }\n"; source_->newline().pushNamespace().newline(); @@ -731,10 +784,10 @@ QByteArray palette::save() const {\n\ \n\ auto result = QByteArray(" << (count * 4) << ", Qt::Uninitialized);\n\ for (auto i = 0, index = 0; i != " << count << "; ++i) {\n\ - result[index++] = static_cast(_colors[i]->c.red());\n\ - result[index++] = static_cast(_colors[i]->c.green());\n\ - result[index++] = static_cast(_colors[i]->c.blue());\n\ - result[index++] = static_cast(_colors[i]->c.alpha());\n\ + result[index++] = static_cast(data(i)->c.red());\n\ + result[index++] = static_cast(data(i)->c.green());\n\ + result[index++] = static_cast(data(i)->c.blue());\n\ + result[index++] = static_cast(data(i)->c.alpha());\n\ }\n\ return result;\n\ }\n\ @@ -744,8 +797,7 @@ bool palette::load(const QByteArray &cache) {\n\ \n\ auto p = reinterpret_cast(cache.constData());\n\ for (auto i = 0; i != " << count << "; ++i) {\n\ - _colors[i] = { p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3] };\n\ - _status[i] = Status::Loaded;\n\ + setData(i, { p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3] });\n\ }\n\ return true;\n\ }\n\ @@ -753,8 +805,7 @@ bool palette::load(const QByteArray &cache) {\n\ bool palette::setColor(QLatin1String name, uchar r, uchar g, uchar b, uchar a) {\n\ auto index = getPaletteIndex(name);\n\ if (index >= 0) {\n\ - _colors[index] = { r, g, b, a };\n\ - _status[index] = Status::Loaded;\n\ + setData(index, { r, g, b, a });\n\ return true;\n\ }\n\ return false;\n\ @@ -764,8 +815,7 @@ bool palette::setColor(QLatin1String name, QLatin1String from) {\n\ auto nameIndex = getPaletteIndex(name);\n\ auto fromIndex = getPaletteIndex(from);\n\ if (nameIndex >= 0 && fromIndex >= 0 && _status[fromIndex] == Status::Loaded) {\n\ - _colors[nameIndex] = _colors[fromIndex];\n\ - _status[nameIndex] = Status::Loaded;\n\ + setData(nameIndex, *data(fromIndex));\n\ return true;\n\ }\n\ return false;\n\ @@ -789,6 +839,11 @@ bool setColor(QLatin1String name, QLatin1String from) {\n\ return _palette.setColor(name, from);\n\ }\n\ \n\ +void apply(const palette &other) {\n\ + _palette = other;\n\ + style::internal::resetIcons();\n\ +}\n\ +\n\ } // namespace main_palette\n\ \n"; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 17493cb6f..8457a0775 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -667,8 +667,6 @@ struct Data { base::Observable ItemRemoved; - bool ApplyingTheme = false; - }; } // namespace internal @@ -784,6 +782,4 @@ DefineRefVar(Global, base::Observable, LocalPasscodeChanged); DefineRefVar(Global, base::Observable, ItemRemoved); -DefineVar(Global, bool, ApplyingTheme); - } // namespace Global diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index d049c6a9f..dc3eaed73 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -356,8 +356,6 @@ DeclareRefVar(base::Observable, LocalPasscodeChanged); DeclareRefVar(base::Observable, ItemRemoved); -DeclareVar(bool, ApplyingTheme); - } // namespace Global namespace Adaptive { diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 690c4ca6e..5e17abe53 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -598,7 +598,7 @@ FileKey _backgroundKey = 0; bool _backgroundWasRead = false; bool _backgroundCanWrite = true; -FileKey _themeKey = 0, _applyingThemeKey = 0; +FileKey _themeKey = 0; bool _readingUserSettings = false; FileKey _userSettingsKey = 0; @@ -1066,12 +1066,11 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) { } break; case dbiTheme: { - quint64 themeKey = 0, applyingThemeKey = 0; - stream >> themeKey >> applyingThemeKey; + quint64 themeKey = 0; + stream >> themeKey; if (!_checkStreamStatus(stream)) return false; _themeKey = themeKey; - _applyingThemeKey = applyingThemeKey; } break; case dbiTryIPv6: { @@ -2232,7 +2231,7 @@ void writeSettings() { auto &proxy = Global::ConnectionProxy(); size += Serialize::stringSize(proxy.host) + sizeof(qint32) + Serialize::stringSize(proxy.user) + Serialize::stringSize(proxy.password); } - if (_themeKey || _applyingThemeKey) { + if (_themeKey) { size += sizeof(quint32) + 2 * sizeof(quint64); } size += sizeof(quint32) + sizeof(qint32) * 7; @@ -2264,8 +2263,8 @@ void writeSettings() { data.stream << proxy.host << qint32(proxy.port) << proxy.user << proxy.password; } data.stream << quint32(dbiTryIPv6) << qint32(Global::TryIPv6()); - if (_themeKey || _applyingThemeKey) { - data.stream << quint32(dbiTheme) << quint64(_themeKey) << quint64(_applyingThemeKey); + if (_themeKey) { + data.stream << quint32(dbiTheme) << quint64(_themeKey); } TWindowPos pos(cWindowPos()); @@ -3639,7 +3638,7 @@ void writeBackground(int32 id, const QImage &img) { } bool readBackground() { - if (_backgroundWasRead || Global::ApplyingTheme()) { + if (_backgroundWasRead) { return false; } _backgroundWasRead = true; @@ -3729,9 +3728,8 @@ bool readThemeUsingKey(FileKey key) { } void writeTheme(const QString &pathRelative, const QString &pathAbsolute, const QByteArray &content, const Window::Theme::Cached &cache) { - auto key = _applyingThemeKey ? _applyingThemeKey : _themeKey; - if (!key) { - key = _themeKey = genKey(); + if (!_themeKey) { + _themeKey = genKey(); writeSettings(); } @@ -3744,21 +3742,12 @@ void writeTheme(const QString &pathRelative, const QString &pathAbsolute, const data.stream << pathRelative << pathAbsolute; data.stream << cache.paletteChecksum << cache.contentChecksum << cache.colors << cache.background << backgroundTiled; - FileWriteDescriptor file(key, FileOption::Safe); + FileWriteDescriptor file(_themeKey, FileOption::Safe); file.writeEncrypted(data, _settingsKey); } void readTheme() { - if (_applyingThemeKey) { - if (readThemeUsingKey(_applyingThemeKey)) { - Global::SetApplyingTheme(true); - } else { - clearKey(_applyingThemeKey); - _applyingThemeKey = 0; - writeSettings(); - readTheme(); - } - } else if (_themeKey && !readThemeUsingKey(_themeKey)) { + if (_themeKey && !readThemeUsingKey(_themeKey)) { clearKey(_themeKey); _themeKey = 0; writeSettings(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index ad4fdd15f..b2a776fd1 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1905,7 +1905,6 @@ void MainWidget::backgroundParams(const QRect &forRect, QRect &to, QRect &from) void MainWidget::updateScrollColors() { _history->updateScrollColors(); - if (_overview) _overview->updateScrollColors(); } void MainWidget::setChatBackground(const App::WallPaper &wp) { diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 05c3498f6..063357479 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -1874,7 +1874,7 @@ OverviewInner::~OverviewInner() { } OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent) -, _scroll(this, st::historyScroll, false) +, _scroll(this, st::setScroll, false) , _inner(this, &_scroll, peer, type) , _a_show(animation(this, &OverviewWidget::step_show)) , _topShadow(this, st::shadowColor) { @@ -1883,8 +1883,6 @@ OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewTyp _scroll.move(0, 0); _inner.move(0, 0); - updateScrollColors(); - _scroll.show(); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); @@ -2195,11 +2193,6 @@ void OverviewWidget::fillSelectedItems(SelectedItemSet &sel, bool forDelete) { _inner.fillSelectedItems(sel, forDelete); } -void OverviewWidget::updateScrollColors() { - if (!App::historyScrollBarColor()) return; - _scroll.updateColors(App::historyScrollBarColor(), App::historyScrollBgColor(), App::historyScrollBarOverColor(), App::historyScrollBgOverColor()); -} - void OverviewWidget::updateAfterDrag() { _inner.dragActionUpdate(QCursor::pos()); } diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 32a7c7e47..9b81e2ee7 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -315,8 +315,6 @@ public: void fillSelectedItems(SelectedItemSet &sel, bool forDelete); - void updateScrollColors(); - void updateAfterDrag(); void grabStart() override { diff --git a/Telegram/SourceFiles/settings/settings_background_widget.cpp b/Telegram/SourceFiles/settings/settings_background_widget.cpp index 83a68e2c5..f9f5008c9 100644 --- a/Telegram/SourceFiles/settings/settings_background_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_background_widget.cpp @@ -239,7 +239,7 @@ void BackgroundWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &upd if (!theme.cached.background.isEmpty()) { Local::writeBackground(Window::Theme::kThemeBackground, QImage()); } - App::restart(); + style::main_palette::apply(theme.palette); } return; } diff --git a/Telegram/SourceFiles/ui/style/style_core_color.cpp b/Telegram/SourceFiles/ui/style/style_core_color.cpp index c70d5e29a..aa8b92a0d 100644 --- a/Telegram/SourceFiles/ui/style/style_core_color.cpp +++ b/Telegram/SourceFiles/ui/style/style_core_color.cpp @@ -41,30 +41,25 @@ void destroyColors() { colorsMap.clear(); } -Color::Color(const Color &c) : ptr(c.owner ? new ColorData(*c.ptr) : c.ptr), owner(c.owner) { +Color::Color(const Color &c) : ptr(c.ptr) { } -Color::Color(QColor c) : owner(false) { - init(c.red(), c.green(), c.blue(), c.alpha()); +Color::Color(ColorData *data) : ptr(data) { } -Color::Color(uchar r, uchar g, uchar b, uchar a) : owner(false) { +Color::Color(uchar r, uchar g, uchar b, uchar a) { init(r, g, b, a); } -Color &Color::operator=(const Color &c) { - if (this != &c) { - if (owner) { - delete ptr; - } - ptr = c.owner ? new ColorData(*c.ptr) : c.ptr; - owner = c.owner; - } - return *this; +void Color::set(uchar r, uchar g, uchar b, uchar a) const { + ptr->set(r, g, b, a); } void Color::init(uchar r, uchar g, uchar b, uchar a) { - uint32 key = colorKey(r, g, b, a); + if (ptr) { + return set(r, g, b, a); + } + auto key = colorKey(r, g, b, a); auto i = colorsMap.constFind(key); if (i == colorsMap.cend()) { i = colorsMap.insert(key, new ColorData(r, g, b, a)); @@ -72,19 +67,16 @@ void Color::init(uchar r, uchar g, uchar b, uchar a) { ptr = i.value(); } -Color::~Color() { - if (owner) { - delete ptr; - } +ColorData::ColorData() : p(Qt::NoPen), b(Qt::NoBrush) { } ColorData::ColorData(uchar r, uchar g, uchar b, uchar a) : c(int(r), int(g), int(b), int(a)), p(c), b(c) { } -void ColorData::set(QColor color) { - c = color; - p = QPen(color); - b = QBrush(color); +void ColorData::set(uchar r, uchar g, uchar b, uchar a) { + this->c = QColor(r, g, b, a); + this->p = QPen(c); + this->b = QBrush(c); } } // namespace internal diff --git a/Telegram/SourceFiles/ui/style/style_core_color.h b/Telegram/SourceFiles/ui/style/style_core_color.h index 175805255..a52f62652 100644 --- a/Telegram/SourceFiles/ui/style/style_core_color.h +++ b/Telegram/SourceFiles/ui/style/style_core_color.h @@ -21,6 +21,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once namespace style { + +class palette; + namespace internal { void destroyColors(); @@ -31,13 +34,9 @@ public: Color(Qt::Initialization = Qt::Uninitialized) { } Color(const Color &c); - explicit Color(QColor c); - Color(uchar r, uchar g, uchar b, uchar a = 255); - Color &operator=(const Color &c); - ~Color(); + Color(uchar r, uchar g, uchar b, uchar a); - void set(QColor newv); - void set(uchar r, uchar g, uchar b, uchar a = 255); + void set(uchar r, uchar g, uchar b, uchar a) const; operator const QBrush &() const; operator const QPen &() const; @@ -54,16 +53,12 @@ public: } private: - ColorData *ptr = nullptr; - bool owner = false; - + Color(ColorData *data); void init(uchar r, uchar g, uchar b, uchar a); - friend void startManager(); + ColorData *ptr = nullptr; - Color(ColorData *p) : ptr(p) { - } - friend class ColorData; + friend class style::palette; }; @@ -78,10 +73,12 @@ public: } private: + ColorData(); ColorData(uchar r, uchar g, uchar b, uchar a); - void set(QColor c); + void set(uchar r, uchar g, uchar b, uchar a); friend class Color; + friend class style::palette; }; diff --git a/Telegram/SourceFiles/ui/style/style_core_icon.cpp b/Telegram/SourceFiles/ui/style/style_core_icon.cpp index 0fe70595d..21759927b 100644 --- a/Telegram/SourceFiles/ui/style/style_core_icon.cpp +++ b/Telegram/SourceFiles/ui/style/style_core_icon.cpp @@ -31,8 +31,10 @@ uint32 colorKey(QColor c) { using IconMasks = QMap; using IconPixmaps = QMap, QPixmap>; +using IconDatas = OrderedSet; NeverFreedPointer iconMasks; NeverFreedPointer iconPixmaps; +NeverFreedPointer iconData; inline int pxAdjust(int value, int scale) { if (value < 0) { @@ -82,6 +84,11 @@ MonoIcon::MonoIcon(const IconMask *mask, const Color &color, QPoint offset) , _offset(offset) { } +void MonoIcon::reset() const { + _pixmap = QPixmap(); + _size = QSize(); +} + int MonoIcon::width() const { ensureLoaded(); return _size.width(); @@ -151,8 +158,13 @@ void MonoIcon::ensureLoaded() const { if (_size.isValid()) { return; } - const uchar *data = _mask->data(); - int size = _mask->size(); + if (!_maskImage.isNull()) { + createCachedPixmap(); + return; + } + + auto data = _mask->data(); + auto size = _mask->size(); auto generateTag = qstr("GENERATE:"); if (size > generateTag.size() && !memcmp(data, generateTag.data(), generateTag.size())) { @@ -190,18 +202,27 @@ void MonoIcon::ensureLoaded() const { } _maskImage = i.value(); - iconPixmaps.createIfNull(); - auto key = qMakePair(_mask, colorKey(_color->c)); - auto j = iconPixmaps->constFind(key); - if (j == iconPixmaps->cend()) { - j = iconPixmaps->insert(key, App::pixmapFromImageInPlace(createIconImage(_maskImage, _color->c))); - } - _pixmap = j.value(); - _size = _pixmap.size() / cIntRetinaFactor(); + createCachedPixmap(); } } -void Icon::fill(QPainter &p, const QRect &rect) const { +void MonoIcon::createCachedPixmap() const { + iconPixmaps.createIfNull(); + auto key = qMakePair(_mask, colorKey(_color->c)); + auto j = iconPixmaps->constFind(key); + if (j == iconPixmaps->cend()) { + j = iconPixmaps->insert(key, App::pixmapFromImageInPlace(createIconImage(_maskImage, _color->c))); + } + _pixmap = j.value(); + _size = _pixmap.size() / cIntRetinaFactor(); +} + +void IconData::created() { + iconData.createIfNull(); + iconData->insert(this); +} + +void IconData::fill(QPainter &p, const QRect &rect) const { if (_parts.isEmpty()) return; auto partSize = _parts.at(0).size(); @@ -212,7 +233,7 @@ void Icon::fill(QPainter &p, const QRect &rect) const { } } -void Icon::fill(QPainter &p, const QRect &rect, QColor colorOverride) const { +void IconData::fill(QPainter &p, const QRect &rect, QColor colorOverride) const { if (_parts.isEmpty()) return; auto partSize = _parts.at(0).size(); @@ -223,7 +244,7 @@ void Icon::fill(QPainter &p, const QRect &rect, QColor colorOverride) const { } } -int Icon::width() const { +int IconData::width() const { if (_width < 0) { _width = 0; for_const (auto &part, _parts) { @@ -233,7 +254,7 @@ int Icon::width() const { return _width; } -int Icon::height() const { +int IconData::height() const { if (_height < 0) { _height = 0; for_const (auto &part, _parts) { @@ -243,7 +264,17 @@ int Icon::height() const { return _height; } +void resetIcons() { + iconPixmaps.clear(); + if (iconData) { + for (auto data : *iconData) { + data->reset(); + } + } +} + void destroyIcons() { + iconData.clear(); iconPixmaps.clear(); iconMasks.clear(); } diff --git a/Telegram/SourceFiles/ui/style/style_core_icon.h b/Telegram/SourceFiles/ui/style/style_core_icon.h index 5fada3cd5..0877f2ba0 100644 --- a/Telegram/SourceFiles/ui/style/style_core_icon.h +++ b/Telegram/SourceFiles/ui/style/style_core_icon.h @@ -50,6 +50,7 @@ public: MonoIcon() = default; MonoIcon(const IconMask *mask, const Color &color, QPoint offset); + void reset() const; int width() const; int height() const; QSize size() const; @@ -66,6 +67,7 @@ public: private: void ensureLoaded() const; + void createCachedPixmap() const; const IconMask *_mask = nullptr; Color _color; @@ -76,17 +78,20 @@ private: }; -class Icon { +class IconData { public: - Icon(Qt::Initialization) { - } - - template - Icon(const MonoIcons&... icons) { + template + IconData(const MonoIcons &...icons) { + created(); _parts.reserve(sizeof...(MonoIcons)); addIcons(icons...); } + void reset() { + for_const (auto &part, _parts) { + part.reset(); + } + } bool empty() const { return _parts.empty(); } @@ -96,12 +101,6 @@ public: part.paint(p, pos, outerw); } } - void paint(QPainter &p, int x, int y, int outerw) const { - paint(p, QPoint(x, y), outerw); - } - void paintInCenter(QPainter &p, const QRect &outer) const { - paint(p, outer.x() + (outer.width() - width()) / 2, outer.y() + (outer.height() - height()) / 2, outer.x() * 2 + outer.width()); - } void fill(QPainter &p, const QRect &rect) const; void paint(QPainter &p, const QPoint &pos, int outerw, QColor colorOverride) const { @@ -109,24 +108,18 @@ public: part.paint(p, pos, outerw, colorOverride); } } - void paint(QPainter &p, int x, int y, int outerw, QColor colorOverride) const { - paint(p, QPoint(x, y), outerw, colorOverride); - } - void paintInCenter(QPainter &p, const QRect &outer, QColor colorOverride) const { - paint(p, outer.x() + (outer.width() - width()) / 2, outer.y() + (outer.height() - height()) / 2, outer.x() * 2 + outer.width(), colorOverride); - } void fill(QPainter &p, const QRect &rect, QColor colorOverride) const; int width() const; int height() const; - QSize size() const { - return QSize(width(), height()); - } private: + void created(); + template void addIcons() { } + template void addIcons(const MonoIcon &icon, const MonoIcons&... icons) { _parts.push_back(icon); @@ -139,6 +132,86 @@ private: }; +class Icon { +public: + Icon(Qt::Initialization) { + } + + template + Icon(const MonoIcons&... icons) : _data(new IconData(icons...)), _owner(true) { + } + Icon(const Icon &other) : _data(other._data) { + } + Icon(Icon &&other) : _data(base::take(other._data)), _owner(base::take(_owner)) { + } + Icon &operator=(const Icon &other) { + t_assert(!_owner); + _data = other._data; + _owner = false; + return *this; + } + Icon &operator=(Icon &&other) { + t_assert(!_owner); + _data = base::take(other._data); + _owner = base::take(other._owner); + return *this; + } + + bool empty() const { + return _data->empty(); + } + + void paint(QPainter &p, const QPoint &pos, int outerw) const { + return _data->paint(p, pos, outerw); + } + void paint(QPainter &p, int x, int y, int outerw) const { + return _data->paint(p, QPoint(x, y), outerw); + } + void paintInCenter(QPainter &p, const QRect &outer) const { + return _data->paint(p, QPoint(outer.x() + (outer.width() - width()) / 2, outer.y() + (outer.height() - height()) / 2), outer.x() * 2 + outer.width()); + } + void fill(QPainter &p, const QRect &rect) const { + return _data->fill(p, rect); + } + + void paint(QPainter &p, const QPoint &pos, int outerw, QColor colorOverride) const { + return _data->paint(p, pos, outerw, colorOverride); + } + void paint(QPainter &p, int x, int y, int outerw, QColor colorOverride) const { + return _data->paint(p, QPoint(x, y), outerw, colorOverride); + } + void paintInCenter(QPainter &p, const QRect &outer, QColor colorOverride) const { + return _data->paint(p, QPoint(outer.x() + (outer.width() - width()) / 2, outer.y() + (outer.height() - height()) / 2), outer.x() * 2 + outer.width(), colorOverride); + } + void fill(QPainter &p, const QRect &rect, QColor colorOverride) const { + return _data->fill(p, rect, colorOverride); + } + + int width() const { + return _data->width(); + } + int height() const { + return _data->height(); + } + QSize size() const { + return QSize(width(), height()); + } + + ~Icon() { + if (auto data = base::take(_data)) { + if (_owner) { + delete data; + } + } + } + +private: + IconData *_data = nullptr; + bool _owner = false; + +}; + +void resetIcons(); void destroyIcons(); } // namespace internal