diff --git a/win-linux/res/styles/theme-classic-light.json b/win-linux/res/styles/theme-classic-light.json new file mode 100644 index 000000000..93c928fdc --- /dev/null +++ b/win-linux/res/styles/theme-classic-light.json @@ -0,0 +1,25 @@ +{ + "id": "theme-classic-light", + "type": "light", + "values": { + "brand_word": "#446995", + "brand_slide": "#aa5252", + "brand_cell": "#40865c", + + "window_background": "#f1f1f1", + "window_border": "#888", + + "text_normal": "#444", + "text_normal_pressed": "#fff", + + "tab_active_background": "#fff", + "tab_simple_active_background": "#fff", + "tab_simple_active_text": "#444", + "tab_default_active_background": "#fff", + "tab_default_active_text": "#444", + "tab_divider": "#a5a5a5", + + "button_normal_opacity": "rgba(255,255,255,255)", + "logo_type": "dark" + } +} diff --git a/win-linux/res/styles/theme-dark.json b/win-linux/res/styles/theme-dark.json new file mode 100644 index 000000000..4643b34dc --- /dev/null +++ b/win-linux/res/styles/theme-dark.json @@ -0,0 +1,28 @@ +{ + "id": "theme-dark", + "type": "dark", + "values": { + "brand_word": "#2a2a2a", + "brand_slide": "#2a2a2a", + "brand_cell": "#2a2a2a", + + "window_background": "#404040", + "window_border": "#2a2a2a", + + "text_normal": "#d9d9d9", + "text_normal_pressed": "#d9d9d9", + + "tool_button_hover_background": "#555", + "tool_button_pressed_background": "#606060", + + "tab_active_background": "#333", + "tab_simple_active_background": "#fff", + "tab_simple_active_text": "#444", + "tab_default_active_background": "#333", + "tab_default_active_text": "#fff", + "tab_divider": "#505050", + + "button_normal_opacity": "rgba(255,255,255,200)", + "logo_type": "light" + } +} diff --git a/win-linux/res/styles/theme-light.json b/win-linux/res/styles/theme-light.json new file mode 100644 index 000000000..78fa52783 --- /dev/null +++ b/win-linux/res/styles/theme-light.json @@ -0,0 +1,25 @@ +{ + "id": "theme-light", + "type": "light", + "values": { + "brand_word": "#446995", + "brand_slide": "#aa5252", + "brand_cell": "#40865c", + + "window_background": "#f1f1f1", + "window_border": "#888", + + "text_normal": "#444", + "text_normal_pressed": "#fff", + + "tab_active_background": "#fff", + "tab_simple_active_background": "#fff", + "tab_simple_active_text": "#444", + "tab_default_active_background": "#fff", + "tab_default_active_text": "#444", + "tab_divider": "#a5a5a5", + + "button_normal_opacity": "rgba(255,255,255,255)", + "logo_type": "dark" + } +} diff --git a/win-linux/resources.qrc b/win-linux/resources.qrc index 3175eed15..17cca2cbe 100644 --- a/win-linux/resources.qrc +++ b/win-linux/resources.qrc @@ -209,4 +209,9 @@ res/styles/tabbar@2x.qss res/styles/tabbar_nix@2x.qss + + res/styles/theme-light.json + res/styles/theme-classic-light.json + res/styles/theme-dark.json + diff --git a/win-linux/src/asctabwidget.cpp b/win-linux/src/asctabwidget.cpp index a926471f9..9049a76cb 100644 --- a/win-linux/src/asctabwidget.cpp +++ b/win-linux/src/asctabwidget.cpp @@ -155,7 +155,6 @@ CAscTabWidget::CAscTabWidget(QWidget *parent) , m_widthParams({{100, 135, 9}, 68, 3, 0, WINDOW_TITLE_MIN_WIDTH, 140, 0}) , m_defWidthParams(m_widthParams) , m_isCustomStyle(true) - , m_isDarkTheme(AscAppManager::themes().isCurrentDark()) , m_tabIconSize(11, 11) { CTabBar * tabs = new CTabBar(this); @@ -555,7 +554,8 @@ void CAscTabWidget::updateTabIcon(int index) CAscTabData& data = *(panel(index)->data()); return data.isViewType(cvwtEditor) && (data.features().empty() || data.hasFeature(L"uithemes")); }; - std::wstring theme_name{m_isDarkTheme && _is_editor_supports_theme(index) ? AscAppManager::themes().current() : NSThemeLight::theme_id}; + const CTheme& ui_theme = AscAppManager::themes().current().isDark() && _is_editor_supports_theme(index) ? + AscAppManager::themes().current() : AscAppManager::themes().light(); tab_type = pEditor->GetEditorType(); switch ( tab_type ) { @@ -564,20 +564,20 @@ void CAscTabWidget::updateTabIcon(int index) } if ( !isActiveWidget() || !(index == currentIndex()) ) { - tab_theme = m_isDarkTheme ? CTabBar::DarkTab : CTabBar::LightTab; + tab_theme = AscAppManager::themes().current().isDark() ? CTabBar::DarkTab : CTabBar::LightTab; } else { switch ( tab_type ) { - case etPresentation: active_tab_color = QString::fromStdWString(AscAppManager::themes().value(theme_name, CThemes::ColorRole::ecrTabSlideActive)); break; - case etSpreadsheet: active_tab_color = QString::fromStdWString(AscAppManager::themes().value(theme_name, CThemes::ColorRole::ecrTabCellActive)); break; - case etDocument: active_tab_color = QString::fromStdWString(AscAppManager::themes().value(theme_name, CThemes::ColorRole::ecrTabWordActive)); break; + case etPresentation: active_tab_color = QString::fromStdWString(ui_theme.value(CTheme::ColorRole::ecrTabSlideActive)); break; + case etSpreadsheet: active_tab_color = QString::fromStdWString(ui_theme.value(CTheme::ColorRole::ecrTabCellActive)); break; + case etDocument: active_tab_color = QString::fromStdWString(ui_theme.value(CTheme::ColorRole::ecrTabWordActive)); break; case etNewPortal: case etPortal: - active_tab_color = QString::fromStdWString(AscAppManager::themes().value(theme_name, CThemes::ColorRole::ecrTabSimpleActiveBackground)); + active_tab_color = QString::fromStdWString(ui_theme.value(CTheme::ColorRole::ecrTabSimpleActiveBackground)); tab_theme = CTabBar::LightTab; break; default: tab_type = etUndefined; - active_tab_color = QString::fromStdWString(AscAppManager::themes().value(theme_name, CThemes::ColorRole::ecrTabDefaultActiveBackground)); + active_tab_color = QString::fromStdWString(ui_theme.value(CTheme::ColorRole::ecrTabDefaultActiveBackground)); tab_theme = AscAppManager::themes().isColorDark(active_tab_color) ? CTabBar::DarkTab : CTabBar::LightTab; break; } @@ -594,8 +594,7 @@ void CAscTabWidget::updateTabIcon(int index) // ((CTabBar *)tabBar())->setUseTabCustomPalette( !(tab_type == etPortal || tab_type == etUndefined) ); tabbar.setTabTextColor(QPalette::Active, AscAppManager::themes().isColorDark(active_tab_color) ? - AscAppManager::themes().color(theme_name, CThemes::ColorRole::ecrTextPressed) : - AscAppManager::themes().color(theme_name, CThemes::ColorRole::ecrTabSimpleActiveText)); + ui_theme.color(CTheme::ColorRole::ecrTextPressed) : ui_theme.color(CTheme::ColorRole::ecrTabSimpleActiveText)); } } @@ -620,7 +619,7 @@ void CAscTabWidget::reloadTabIcons() {etSpreadsheet, std::make_pair(":/tabbar/icons/se@2x.png", ":/tabbar/icons/se@2x.png")} }); - m_isDarkTheme ? + AscAppManager::themes().current().isDark() ? m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal_light@2x.png", ":/tabbar/icons/portal@2x.png")}, {etNewPortal, std::make_pair(":/tabbar/icons/portal_light@2x.png", ":/tabbar/icons/portal@2x.png")}}) : m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal@2x.png", ":/tabbar/icons/portal@2x.png")}, @@ -634,7 +633,7 @@ void CAscTabWidget::reloadTabIcons() {etSpreadsheet, std::make_pair(":/tabbar/icons/se@1.75x.png", ":/tabbar/icons/se@1.75x.png")} }); - m_isDarkTheme ? + AscAppManager::themes().current().isDark() ? m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal_light@1.75x.png", ":/tabbar/icons/portal@1.75x.png")}, {etNewPortal, std::make_pair(":/tabbar/icons/portal_light@1.75x.png", ":/tabbar/icons/portal@1.75x.png")}}) : m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal@1.75x.png", ":/tabbar/icons/portal@1.75x.png")}, @@ -648,7 +647,7 @@ void CAscTabWidget::reloadTabIcons() {etSpreadsheet, std::make_pair(":/tabbar/icons/se@1.5x.png", ":/tabbar/icons/se@1.5x.png")} }); - m_isDarkTheme ? + AscAppManager::themes().current().isDark() ? m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal_light@1.5x.png", ":/tabbar/icons/portal@1.5x.png")}, {etNewPortal, std::make_pair(":/tabbar/icons/portal_light@1.5x.png", ":/tabbar/icons/portal@1.5x.png")}}) : m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal@1.5x.png", ":/tabbar/icons/portal@1.5x.png")}, @@ -662,7 +661,7 @@ void CAscTabWidget::reloadTabIcons() {etSpreadsheet, std::make_pair(":/tabbar/icons/se@1.25x.png", ":/tabbar/icons/se@1.25x.png")} }); - m_isDarkTheme ? + AscAppManager::themes().current().isDark() ? m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal_light@1.25x.png", ":/tabbar/icons/portal@1.25x.png")}, {etNewPortal, std::make_pair(":/tabbar/icons/portal_light@1.25x.png", ":/tabbar/icons/portal@1.25x.png")}}) : m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal@1.25x.png", ":/tabbar/icons/portal@1.25x.png")}, @@ -675,7 +674,7 @@ void CAscTabWidget::reloadTabIcons() {etSpreadsheet, std::make_pair(":/tabbar/icons/se.png", ":/tabbar/icons/se.png")} }); - m_isDarkTheme ? + AscAppManager::themes().current().isDark() ? m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal_light.png", ":/tabbar/icons/portal.png")}, {etNewPortal, std::make_pair(":/tabbar/icons/portal_light.png", ":/tabbar/icons/portal.png")}}) : m_mapTabIcons.insert({{etPortal, std::make_pair(":/tabbar/icons/portal.png", ":/tabbar/icons/portal.png")}, @@ -1332,15 +1331,13 @@ void CAscTabWidget::setStyleSheet(const QString& stylesheet) void CAscTabWidget::applyUITheme(const std::wstring& theme) { - m_isDarkTheme = theme == NSThemeDark::theme_id; - reloadTabIcons(); updateIcons(); CTabBar & _tabbar = *(static_cast(tabBar())); // _tabbar.setTabTextColor(QPalette::Active, AscAppManager::themes().color(theme, CThemes::ColorRole::ecrTextPressed)); - _tabbar.setTabTextColor(QPalette::Inactive, AscAppManager::themes().color(theme, CThemes::ColorRole::ecrTextNormal)); - _tabbar.setUIThemeType(!m_isDarkTheme); + _tabbar.setTabTextColor(QPalette::Inactive, AscAppManager::themes().current().color(CTheme::ColorRole::ecrTextNormal)); + _tabbar.setUIThemeType(!AscAppManager::themes().current().isDark()); _tabbar.style()->polish(&_tabbar); style()->polish(this); } diff --git a/win-linux/src/asctabwidget.h b/win-linux/src/asctabwidget.h index 71463142f..6a46f2c58 100644 --- a/win-linux/src/asctabwidget.h +++ b/win-linux/src/asctabwidget.h @@ -127,7 +127,6 @@ private: size_params m_widthParams, m_defWidthParams; bool m_isCustomStyle; - bool m_isDarkTheme; CTabIconSet m_mapTabIcons; QSize m_tabIconSize; diff --git a/win-linux/src/cascapplicationmanagerwrapper.cpp b/win-linux/src/cascapplicationmanagerwrapper.cpp index ef575c12a..a8a58be30 100644 --- a/win-linux/src/cascapplicationmanagerwrapper.cpp +++ b/win-linux/src/cascapplicationmanagerwrapper.cpp @@ -992,7 +992,7 @@ void CAscApplicationManagerWrapper::initializeApp() InputArgs::set_webapps_params(wparams); AscAppManager::getInstance().InitAdditionalEditorParams(wparams); - AscAppManager::getInstance().applyTheme(themes().current(), true); + AscAppManager::getInstance().applyTheme(themes().current().id(), true); } CSingleWindow * CAscApplicationManagerWrapper::createReporterWindow(void * data, int parentid) @@ -1510,9 +1510,10 @@ void CAscApplicationManagerWrapper::applyTheme(const wstring& theme, bool force) APP_CAST(_app); if ( !_app.m_themes->isCurrent(theme) ) { - _app.m_themes->setCurrent(theme); + const std::wstring old_theme = _app.m_themes->current().id(); + _app.m_themes->setCurrentTheme(theme); - std::wstring params{InputArgs::change_webapps_param(L"&uitheme=" + _app.m_themes->current(), L"&uitheme=" + theme)}; + std::wstring params{InputArgs::change_webapps_param(L"&uitheme=" + old_theme, L"&uitheme=" + theme)}; AscAppManager::getInstance().InitAdditionalEditorParams(params); // TODO: remove diff --git a/win-linux/src/ceditorwindow.cpp b/win-linux/src/ceditorwindow.cpp index 187200c43..f5f1e9c0b 100644 --- a/win-linux/src/ceditorwindow.cpp +++ b/win-linux/src/ceditorwindow.cpp @@ -76,7 +76,7 @@ CEditorWindow::CEditorWindow(const QRect& rect, CTabPanel* panel) } #else - applyTheme(AscAppManager::themes().current()); + applyTheme(AscAppManager::themes().current().id()); m_pMainPanel = createMainPanel(m_pWinPanel); m_pWinPanel->show(); @@ -219,7 +219,7 @@ QWidget * CEditorWindow::createMainPanel(QWidget * parent, const QString& title) if ( m_dpiRatio > 1 ) mainPanel->setProperty("zoom", "1.25x"); - mainPanel->setProperty("uitheme", QString::fromStdWString(AscAppManager::themes().current())); + mainPanel->setProperty("uitheme", QString::fromStdWString(AscAppManager::themes().current().id())); mainPanel->setStyleSheet(AscAppManager::getWindowStylesheets(m_dpiRatio) + m_css); if ( isCustomWindowStyle() ) { diff --git a/win-linux/src/ceditorwindow_p.h b/win-linux/src/ceditorwindow_p.h index 3d5710ed2..eb3cfa7b7 100644 --- a/win-linux/src/ceditorwindow_p.h +++ b/win-linux/src/ceditorwindow_p.h @@ -112,13 +112,13 @@ const QString g_css = "#mainPanel[uitheme=theme-dark] #iconuser," "#mainPanel[uitheme=theme-dark] #labelTitle{color:rgba(255,255,255,80%);}"; -auto prepare_editor_css(int type, const std::wstring& theme) -> QString { +auto prepare_editor_css(int type, const CTheme& theme) -> QString { std::wstring c; switch (type) { - default: c = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrWindowBackground); break; - case etDocument: c = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrTabWordActive); break; - case etPresentation: c = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrTabSlideActive); break; - case etSpreadsheet: c = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrTabCellActive); break; + default: c = theme.value(CTheme::ColorRole::ecrWindowBackground); break; + case etDocument: c = theme.value(CTheme::ColorRole::ecrTabWordActive); break; + case etPresentation: c = theme.value(CTheme::ColorRole::ecrTabSlideActive); break; + case etSpreadsheet: c = theme.value(CTheme::ColorRole::ecrTabCellActive); break; } return g_css.arg(QString::fromStdWString(c)); @@ -126,11 +126,11 @@ auto prepare_editor_css(int type, const std::wstring& theme) -> QString { auto editor_color(int type) -> QColor { switch (type) { - case etDocument: return AscAppManager::themes().color(CThemes::ColorRole::ecrTabWordActive); - case etPresentation: return AscAppManager::themes().color(CThemes::ColorRole::ecrTabSlideActive); - case etSpreadsheet: return AscAppManager::themes().color(CThemes::ColorRole::ecrTabCellActive); + case etDocument: return AscAppManager::themes().current().color(CTheme::ColorRole::ecrTabWordActive); + case etPresentation: return AscAppManager::themes().current().color(CTheme::ColorRole::ecrTabSlideActive); + case etSpreadsheet: return AscAppManager::themes().current().color(CTheme::ColorRole::ecrTabCellActive); //#ifdef Q_OS_WIN - default: return AscAppManager::themes().color(CThemes::ColorRole::ecrWindowBackground); + default: return AscAppManager::themes().current().color(CTheme::ColorRole::ecrWindowBackground); //#else // default: return QColor(WINDOW_BACKGROUND_COLOR); //#endif @@ -207,7 +207,7 @@ public: btn->setDisabled(jsonobj["disabled"].toBool()); btn->setIconSize(QSize(20,20) * window->m_dpiRatio); btn->setMouseTracking(true); - btn->setIconOpacity(AscAppManager::themes().isCurrentDark() ? NSThemeDark::button_normal_opacity : NSThemeLight::button_normal_opacity); + btn->setIconOpacity(AscAppManager::themes().current().color(CTheme::ColorRole::ecrButtonNormalOpacity)); m_mapTitleButtons[action] = btn; @@ -242,8 +242,7 @@ public: window->m_labelTitle->setText(APP_TITLE); #ifdef Q_OS_WIN - window->setWindowBackgroundColor( - QColor(QString::fromStdWString(AscAppManager::themes().value(CThemes::ColorRole::ecrWindowBackground)))); + window->setWindowBackgroundColor(AscAppManager::themes().current().color(CTheme::ColorRole::ecrWindowBackground)); #endif } } @@ -333,14 +332,14 @@ public: if ( canExtendTitle() && window->isCustomWindowStyle() ) { window->m_pMainPanel->setProperty("window", "pretty"); - changeTheme(AscAppManager::themes().current()); + changeTheme(AscAppManager::themes().current().id()); } } void changeTheme(const std::wstring& theme) { if ( canExtendTitle() && window->isCustomWindowStyle() ) { - window->m_css = prepare_editor_css(panel()->data()->contentType(), theme); + window->m_css = prepare_editor_css(panel()->data()->contentType(), AscAppManager::themes().current()); if ( window->m_pMainPanel ) { window->m_pMainPanel->setProperty("uitheme", QString::fromStdWString(theme)); @@ -352,27 +351,27 @@ public: for ( auto c: leftboxbuttons->findChildren()) { CSVGPushButton * btn = static_cast(c); - btn->setIconOpacity(AscAppManager::themes().isThemeDark(theme) ? NSThemeDark::button_normal_opacity : NSThemeLight::button_normal_opacity); + btn->setIconOpacity(AscAppManager::themes().current().color(CTheme::ColorRole::ecrButtonNormalOpacity)); } #ifdef Q_OS_WIN std::wstring background, border; switch (panel()->data()->contentType()) { case etDocument: - background = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrTabWordActive); + background = AscAppManager::themes().current().value(CTheme::ColorRole::ecrTabWordActive); border = background; break; case etPresentation: - background = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrTabSlideActive); + background = AscAppManager::themes().current().value(CTheme::ColorRole::ecrTabSlideActive); border = background; break; case etSpreadsheet: - background = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrTabCellActive); + background = AscAppManager::themes().current().value(CTheme::ColorRole::ecrTabCellActive); border = background; break; default: - background = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrWindowBackground); - border = AscAppManager::themes().value(theme, CThemes::ColorRole::ecrWindowBorder); + background = AscAppManager::themes().current().value(CTheme::ColorRole::ecrWindowBackground); + border = AscAppManager::themes().current().value(CTheme::ColorRole::ecrWindowBorder); } window->setWindowColors(QColor(QString::fromStdWString(background)), QColor(QString::fromStdWString(border))); diff --git a/win-linux/src/cmainpanel.cpp b/win-linux/src/cmainpanel.cpp index aef3830fc..ce009b7ec 100644 --- a/win-linux/src/cmainpanel.cpp +++ b/win-linux/src/cmainpanel.cpp @@ -100,7 +100,7 @@ CMainPanel::CMainPanel(QWidget *parent, bool isCustomWindow, double dpi_ratio) , m_saveAction(0) { setObjectName("mainPanel"); - setProperty("uitheme", QString::fromStdWString(AscAppManager::themes().current())); + setProperty("uitheme", QString::fromStdWString(AscAppManager::themes().current().id())); QGridLayout *mainGridLayout = new QGridLayout(); mainGridLayout->setSpacing( 0 ); @@ -116,7 +116,7 @@ CMainPanel::CMainPanel(QWidget *parent, bool isCustomWindow, double dpi_ratio) m_pTabs = new CAscTabWidget(centralWidget); m_pTabs->setGeometry(0, 0, centralWidget->width(), centralWidget->height()); m_pTabs->activate(false); - m_pTabs->applyUITheme(AscAppManager::themes().current()); + m_pTabs->applyUITheme(AscAppManager::themes().current().id()); connect(m_pTabs, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int))); connect(m_pTabs, SIGNAL(tabBarClicked(int)), this, SLOT(onTabClicked(int))); connect(m_pTabs, SIGNAL(tabCloseRequested(int)), this, SLOT(onTabCloseRequest(int))); diff --git a/win-linux/src/cmessage.cpp b/win-linux/src/cmessage.cpp index 327fa748d..ced99aa8c 100644 --- a/win-linux/src/cmessage.cpp +++ b/win-linux/src/cmessage.cpp @@ -160,7 +160,7 @@ CMessage::CMessage(QWidget * p) layout()->setSizeConstraint(QLayout::SetFixedSize); #endif m_centralWidget->setObjectName("messageBody"); - m_centralWidget->setProperty("uitheme", AscAppManager::themes().isCurrentDark() ? "theme-dark" : "theme-light"); + m_centralWidget->setProperty("uitheme", AscAppManager::themes().current().isDark() ? "theme-dark" : "theme-light"); QVBoxLayout * _c_layout = new QVBoxLayout; QHBoxLayout * _h_layout2 = new QHBoxLayout; @@ -391,7 +391,7 @@ void CMessage::modal() if ( m_priv->defaultButton ) { _focused_handle = (HWND)m_priv->defaultButton->winId(); QTimer::singleShot(50, m_centralWidget, [&]{ - if ( !AscAppManager::themes().isCurrentDark() ) + if ( !AscAppManager::themes().current().isDark() ) for (auto * btn: m_priv->buttons) { btn->setAutoDefault(true); } diff --git a/win-linux/src/cthemes.cpp b/win-linux/src/cthemes.cpp index 5ae282c7a..5df56ba3c 100644 --- a/win-linux/src/cthemes.cpp +++ b/win-linux/src/cthemes.cpp @@ -6,26 +6,255 @@ #include #include #include +#include +#include #include #define QSTRING_FROM_WSTR(s) QString::fromStdWString(s) #define REGISTRY_THEME_KEY "UITheme" +#define THEME_DEFAULT_DARK_ID "theme-dark" +#define THEME_DEFAULT_LIGHT_ID "theme-classic-light" + +namespace NSTheme { + static const QString theme_type_dark = "dark"; + static const QString theme_type_light = "light"; + + enum class ThemeType { + ttDark, + ttLight + }; + + static const std::map map_names = { + {CTheme::ColorRole::ecrTabWordActive, "brand_word"}, + {CTheme::ColorRole::ecrTabSlideActive, "brand_slide"}, + {CTheme::ColorRole::ecrTabCellActive, "brand_cell"}, + + {CTheme::ColorRole::ecrWindowBackground, "window_background"}, + {CTheme::ColorRole::ecrWindowBorder, "window_border"}, + + {CTheme::ColorRole::ecrTextNormal, "text_normal"}, + {CTheme::ColorRole::ecrTextPressed, "text_normal_pressed"}, + + // { "tab_active_background": "#fff", + {CTheme::ColorRole::ecrTabSimpleActiveBackground, "tab_simple_active_background"}, + {CTheme::ColorRole::ecrTabSimpleActiveText, "tab_simple_active_text"}, + {CTheme::ColorRole::ecrTabDefaultActiveBackground, "tab_default_active_background"}, + {CTheme::ColorRole::ecrTabDefaultActiveText, "tab_default_active_text"}, + // { "tab_divider": "#a5a5a5", + + {CTheme::ColorRole::ecrButtonNormalOpacity, "button_normal_opacity"}, + {CTheme::ColorRole::ecrLogoColor, "logo"} + }; +} + +/* + * CThemePrivate +*/ +class CTheme::CThemePrivate { +public: + CThemePrivate() {} + + auto fromJsonObject(const QJsonObject& obj) { + id = obj.value("id").toString().toStdWString(); + type = obj.value("type").toString() == NSTheme::theme_type_dark ? + NSTheme::ThemeType::ttDark : NSTheme::ThemeType::ttLight; + jsonValues = obj.value("values").toObject(); + } + + std::wstring id; + std::wstring wstype; + NSTheme::ThemeType type; + + QJsonObject jsonValues; +}; + +/* + * CThemes private class +*/ class CThemes::CThemesPrivate { public: CThemesPrivate(CThemes * p) : parent(*p) { - support_ids = { NSThemeLight::theme_id, - NSThemeClassicLight::theme_id, - NSThemeDark::theme_id }; + rc_themes = { + {"theme-light", ":/themes/theme-light.json"}, + {"theme-classic-light", ":/themes/theme-classic-light.json"}, + {"theme-dark", ":/themes/theme-dark.json"}, + }; + + GET_REGISTRY_USER(_reg_user); + QString user_theme = _reg_user.value(REGISTRY_THEME_KEY).toString(); +#ifdef Q_OS_WIN +// if ( _reg_user.contains(REGISTRY_THEME_KEY) ) +// user_theme = _reg_user.value(REGISTRY_THEME_KEY, THEME_DEFAULT_LIGHT_ID).toString(); +// else { +// QSettings _reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat); +// user_theme = _reg.value("AppsUseLightTheme", 1).toInt() == 0 ? THEME_DEFAULT_DARK_ID : THEME_DEFAULT_LIGHT_ID; +// } + if ( user_theme.isEmpty() ) { + QSettings _reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat); + user_theme = _reg.value("AppsUseLightTheme", 1).toInt() == 0 ? THEME_DEFAULT_DARK_ID : THEME_DEFAULT_LIGHT_ID; + } +#else + if ( user_theme.isEmpty() ) { + user_theme = THEME_DEFAULT_LIGHT_ID; + } +#endif + + current = new CTheme(rc_themes.at(user_theme)); + } + + ~CThemesPrivate() + { + if ( current ) { + delete current; + current = nullptr; + } + } + + auto setCurrent(const QString& id) + { + if ( rc_themes.find(id) != rc_themes.end() ) { + return current->load(rc_themes.at(id)); + } + + return false; + } + + auto getDefault(NSTheme::ThemeType type) + { + if ( type == NSTheme::ThemeType::ttDark ) { + if ( !dark ) { + dark = new CTheme; + dark->load(rc_themes[THEME_DEFAULT_DARK_ID]); + } + + return dark; + } else { + if ( !light ) { + light = new CTheme; + light->load(rc_themes[THEME_DEFAULT_LIGHT_ID]); + } + + return light; + } } CThemes & parent; - std::wstring current = L""; - std::vector support_ids; + std::map rc_themes; + + CTheme * current = nullptr; + CTheme * dark = nullptr; + CTheme * light = nullptr; }; +/* + * CTheme +*/ + +CTheme::CTheme(const QString& path) + : m_priv(new CTheme::CThemePrivate) +{ + if ( !path.isEmpty() ) + load(path); +} + +CTheme::~CTheme() +{ + if ( m_priv ) { + delete m_priv; + m_priv = nullptr; + } +} + +auto CTheme::load(const QString& path) -> bool +{ + QFile _file(path); + if ( _file.open(QIODevice::ReadOnly) ) { + QJsonParseError jerror; + + QJsonDocument jdoc = QJsonDocument::fromJson(_file.readAll(), &jerror); + if( jerror.error == QJsonParseError::NoError ) { + m_priv->fromJsonObject(jdoc.object()); + return true; + } + } + + return false; +} + +auto CTheme::id() const -> std::wstring +{ + return m_priv->id; +} + +auto CTheme::stype() const -> QString +{ + return m_priv->type == NSTheme::ThemeType::ttDark ? + NSTheme::theme_type_dark : NSTheme::theme_type_light; +} + +auto CTheme::value(ColorRole r) const -> std::wstring +{ + if ( NSTheme::map_names.find(r) != NSTheme::map_names.end() ) { + if ( m_priv->jsonValues.contains(NSTheme::map_names.at(r)) ) + return m_priv->jsonValues.value(NSTheme::map_names.at(r)).toString().toStdWString(); + } + + return L""; +} + +auto CTheme::color(ColorRole role) const -> QColor +{ + QString v = QSTRING_FROM_WSTR(value(role)); + if ( !v.isEmpty() ) { + if ( v.startsWith("rgba") ) { + QRegularExpression re("\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3}),(\\d{1,3})"); + QRegularExpressionMatch match = re.match(v); + if ( match.hasMatch() ) { + const uint r = match.captured(1).toUInt(), + g = match.captured(2).toUInt(), + b = match.captured(3).toUInt(), + a = match.captured(4).toUInt(); + v = QString("#%1%2%3%4").arg(a, 2, 16, QLatin1Char('0')) + .arg(r, 2, 16, QLatin1Char('0')) + .arg(g, 2, 16, QLatin1Char('0')) + .arg(b, 2, 16, QLatin1Char('0')); + + // keep normalized color + m_priv->jsonValues[NSTheme::map_names.at(role)] = v; + } + } + + return QColor(v); + } + + return QColor(); +} + +#ifdef Q_OS_WIN +auto CTheme::colorRef(ColorRole role) const -> COLORREF +{ + int r, g, b; + color(role).getRgb(&r, &g, &b); + + return RGB(r,g,b); +} +#endif + +auto CTheme::isDark() const -> bool +{ + return m_priv->type == NSTheme::ThemeType::ttDark; +} + +/**/ + +CThemes::CThemes() + : m_priv(new CThemes::CThemesPrivate(this)) +{ +} + CThemes::~CThemes() { if ( m_priv ) { @@ -34,117 +263,32 @@ CThemes::~CThemes() } } -CThemes::CThemes() - : m_priv(new CThemes::CThemesPrivate(this)) +auto CThemes::current() -> const CTheme & { - GET_REGISTRY_USER(_reg_user); -#ifdef Q_OS_WIN - if ( _reg_user.contains(REGISTRY_THEME_KEY) ) - m_priv->current = _reg_user.value(REGISTRY_THEME_KEY, QString::fromStdWString(NSThemeClassicLight::theme_id)).toString().toStdWString(); - else { - QSettings _reg("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat); - m_priv->current = _reg.value("AppsUseLightTheme", 1).toInt() == 0 ? NSThemeDark::theme_id : NSThemeClassicLight::theme_id; - } -#else - m_priv->current = _reg_user.value(REGISTRY_THEME_KEY, QString::fromStdWString(NSThemeClassicLight::theme_id)).toString().toStdWString(); -#endif + return *(m_priv->current); } -auto CThemes::current() -> std::wstring +auto CThemes::dark() -> const CTheme& { - return m_priv->current; + return *m_priv->getDefault(NSTheme::ThemeType::ttDark); } -auto CThemes::setCurrent(const std::wstring& name) -> void +auto CThemes::light() -> const CTheme& { - if ( !isCurrent(name) ) { + return *m_priv->getDefault(NSTheme::ThemeType::ttLight); +} + +auto CThemes::setCurrentTheme(const std::wstring& name) -> void +{ + if ( !isCurrent(name) && m_priv->setCurrent(QString::fromStdWString(name)) ) { GET_REGISTRY_USER(_reg_user); _reg_user.setValue(REGISTRY_THEME_KEY, QString::fromStdWString(name)); - - m_priv->current = name; } } auto CThemes::isCurrent(const std::wstring& name) -> bool { - return m_priv->current == name; -} - -auto CThemes::isCurrentDark() -> bool -{ - return m_priv->current == NSThemeDark::theme_id; -} - -auto CThemes::isThemeDark(const std::wstring& name) -> bool -{ - return name == NSThemeDark::theme_id; -} - -auto CThemes::color(ColorRole r) -> QColor -{ - return color(current(), r); -} - -auto CThemes::color(const std::wstring& theme, ColorRole r) -> QColor -{ - return QColor(QSTRING_FROM_WSTR(value(theme, r))); -} - -#ifdef Q_OS_WIN -auto CThemes::colorRef(ColorRole role) -> COLORREF -{ - int r, g, b; - color(role).getRgb(&r, &g, &b); - - return RGB(r,g,b); -} -#endif - -auto CThemes::value(ColorRole r) -> std::wstring -{ - return value(m_priv->current, r); -} - -auto CThemes::value(const std::wstring& theme, ColorRole r) -> std::wstring -{ - if ( theme == NSThemeDark::theme_id ) { - switch (r) { - case ColorRole::ecrWindowBackground: return NSThemeDark::color_window_background; - case ColorRole::ecrWindowBorder: return NSThemeDark::color_window_border; - case ColorRole::ecrTextNormal: return NSThemeDark::color_text_normal; - case ColorRole::ecrTextPressed: return NSThemeDark::color_text_normal_pressed; - case ColorRole::ecrLogoColor: return NSThemeDark::color_logo; - case ColorRole::ecrTabWordActive: return NSThemeDark::color_brand_word; - case ColorRole::ecrTabCellActive: return NSThemeDark::color_brand_cell; - case ColorRole::ecrTabSlideActive: return NSThemeDark::color_brand_slide; - case ColorRole::ecrTabSimpleActiveBackground: return NSThemeDark::color_tab_simple_active_background; - case ColorRole::ecrTabSimpleActiveText: return NSThemeDark::color_tab_simple_active_text; - case ColorRole::ecrTabDefaultActiveBackground: return NSThemeDark::color_tab_default_active_background; - case ColorRole::ecrTabDefaultActiveText: return NSThemeDark::color_tab_default_active_text; - } - } else { - switch (r) { - case ColorRole::ecrWindowBackground: return NSThemeLight::color_window_background; - case ColorRole::ecrWindowBorder: return NSThemeLight::color_window_border; - case ColorRole::ecrTextNormal: return NSThemeLight::color_text_normal; - case ColorRole::ecrTextPressed: return NSThemeLight::color_text_normal_pressed; - case ColorRole::ecrLogoColor: return NSThemeLight::color_logo; - case ColorRole::ecrTabWordActive: return NSThemeLight::color_brand_word; - case ColorRole::ecrTabCellActive: return NSThemeLight::color_brand_cell; - case ColorRole::ecrTabSlideActive: return NSThemeLight::color_brand_slide; - case ColorRole::ecrTabSimpleActiveBackground: return NSThemeLight::color_tab_simple_active_background; - case ColorRole::ecrTabSimpleActiveText: return NSThemeLight::color_tab_simple_active_text; - case ColorRole::ecrTabDefaultActiveBackground: return NSThemeLight::color_tab_default_active_background; - case ColorRole::ecrTabDefaultActiveText: return NSThemeLight::color_tab_default_active_text; - } - } - - return L""; -} - -auto CThemes::isColorDark(ColorRole role) -> bool -{ - return isColorDark(value(role)); + return m_priv->current->id() == name; } auto CThemes::isColorDark(const std::wstring& color) -> bool @@ -173,7 +317,7 @@ auto CThemes::parseThemeName(const std::wstring& wjson) -> std::wstring if( jerror.error == QJsonParseError::NoError ) { QJsonObject obj = jdoc.object(); - return obj.contains("name") ? obj["name"].toString().toStdWString() : NSThemeClassicLight::theme_id; + return obj.contains("name") ? obj["name"].toString().toStdWString() : QString(THEME_DEFAULT_LIGHT_ID).toStdWString(); } } diff --git a/win-linux/src/cthemes.h b/win-linux/src/cthemes.h index 1be4f4337..71ba0c4c2 100644 --- a/win-linux/src/cthemes.h +++ b/win-linux/src/cthemes.h @@ -7,86 +7,9 @@ # include #endif -namespace NSThemeLight { - static const std::wstring theme_id = L"theme-light"; - static const std::wstring theme_type = L"light"; - static const std::wstring color_brand_word = L"#446995"; - static const std::wstring color_brand_slide = L"#aa5252"; - static const std::wstring color_brand_cell = L"#40865c"; - - static const std::wstring color_window_background = L"#f1f1f1"; - static const std::wstring color_window_border = L"#888"; - - static const std::wstring color_text_normal = L"#444"; - static const std::wstring color_text_normal_pressed = L"#fff"; - - static const std::wstring color_tab_active_background = L"#fff"; - static const std::wstring color_tab_simple_active_background = L"#fff"; - static const std::wstring color_tab_simple_active_text = L"#444"; - static const std::wstring color_tab_default_active_background = L"#fff"; - static const std::wstring color_tab_default_active_text = L"#444"; - static const std::wstring color_tab_divider = L"#a5a5a5"; - - static const QColor button_normal_opacity = QColor(255,255,255,255); - static const std::wstring color_logo = L"dark"; -} - -namespace NSThemeClassicLight { - static const std::wstring theme_id = L"theme-classic-light"; - static const std::wstring theme_type = L"light"; - - static const std::wstring color_brand_word = L"#446995"; - static const std::wstring color_brand_slide = L"#aa5252"; - static const std::wstring color_brand_cell = L"#40865c"; - - static const std::wstring color_window_background = L"#f1f1f1"; - static const std::wstring color_window_border = L"#888"; - - static const std::wstring color_text_normal = L"#444"; - static const std::wstring color_text_normal_pressed = L"#fff"; - - static const std::wstring color_tab_active_background = L"#fff"; - static const std::wstring color_tab_simple_active_background = L"#fff"; - static const std::wstring color_tab_simple_active_text = L"#444"; - static const std::wstring color_tab_default_active_background = L"#fff"; - static const std::wstring color_tab_default_active_text = L"#444"; - static const std::wstring color_tab_divider = L"#a5a5a5"; - - static const QColor button_normal_opacity = QColor(255,255,255,255); - static const std::wstring color_logo = L"dark"; -} - -namespace NSThemeDark { - static const std::wstring theme_id = L"theme-dark"; - static const std::wstring theme_type = L"dark"; - - static const std::wstring color_brand_word = L"#2a2a2a"; - static const std::wstring color_brand_slide = L"#2a2a2a"; - static const std::wstring color_brand_cell = L"#2a2a2a"; - - static const std::wstring color_window_background = L"#404040"; - static const std::wstring color_window_border = L"#2a2a2a"; - - static const std::wstring color_text_normal = L"#d9d9d9"; - static const std::wstring color_text_normal_pressed = L"#d9d9d9"; - - static const std::wstring color_tool_button_hover_background = L"#555"; - static const std::wstring color_tool_button_pressed_background = L"#606060"; - - static const std::wstring color_tab_active_background = L"#333"; - static const std::wstring color_tab_simple_active_background = L"#fff"; - static const std::wstring color_tab_simple_active_text = L"#444"; - static const std::wstring color_tab_default_active_background = L"#333"; - static const std::wstring color_tab_default_active_text = L"#fff"; - static const std::wstring color_tab_divider = L"#505050"; - - static const QColor button_normal_opacity = QColor(255,255,255,200); - static const std::wstring color_logo = L"light"; -} - -class CThemes -{ +class CThemes; +class CTheme { public: enum class ColorRole { ecrWindowBackground @@ -101,25 +24,44 @@ public: , ecrTabSimpleActiveText , ecrTabDefaultActiveBackground , ecrTabDefaultActiveText + , ecrButtonNormalOpacity }; + + auto load(const QString&) -> bool; + + auto id() const -> std::wstring; + auto stype() const -> QString; + auto color(ColorRole r) const -> QColor; +#ifdef Q_OS_WIN + auto colorRef(ColorRole r) const -> COLORREF; +#endif + auto value(ColorRole) const -> std::wstring; + auto isDark() const -> bool; + +private: + CTheme(const QString& id = QString()); + ~CTheme(); + + class CThemePrivate; + CThemePrivate * m_priv = nullptr; + + friend class CThemes; +}; + +class CThemes +{ public: CThemes(); ~CThemes(); - auto color(ColorRole r) -> QColor; - auto color(const std::wstring& theme, ColorRole r) -> QColor; -#ifdef Q_OS_WIN - auto colorRef(ColorRole r) -> COLORREF; -#endif - auto value(ColorRole) -> std::wstring; - auto value(const std::wstring&, ColorRole) -> std::wstring; - auto current() -> std::wstring; - auto setCurrent(const std::wstring&) -> void; + auto current() -> const CTheme&; + auto dark() -> const CTheme&; + auto light() -> const CTheme&; + + auto setCurrentTheme(const std::wstring&) -> void; auto isCurrent(const std::wstring& name) -> bool; - auto isCurrentDark() -> bool; auto isThemeDark(const std::wstring& name) -> bool; - auto isColorDark(ColorRole) -> bool; auto isColorDark(const std::wstring&) -> bool; auto isColorDark(const QString&) -> bool; diff --git a/win-linux/src/prop/cmainpanelimpl.cpp b/win-linux/src/prop/cmainpanelimpl.cpp index 939037a13..d3be23456 100644 --- a/win-linux/src/prop/cmainpanelimpl.cpp +++ b/win-linux/src/prop/cmainpanelimpl.cpp @@ -88,7 +88,7 @@ void CMainPanelImpl::refreshAboutVersion() else _json_obj["uiscaling"] = 0; #ifndef __OS_WIN_XP - _json_obj["uitheme"] = QString::fromStdWString(AscAppManager::themes().current()); + _json_obj["uitheme"] = QString::fromStdWString(AscAppManager::themes().current().id()); #endif GET_REGISTRY_USER(reg_user); @@ -103,7 +103,7 @@ void CMainPanelImpl::updateScaling(double dpiratio) { CMainPanel::updateScaling(dpiratio); - m_pButtonMain->setIcon(":/logo.svg", AscAppManager::themes().isCurrentDark() ? "logo-light" : "logo-dark"); + m_pButtonMain->setIcon(":/logo.svg", AscAppManager::themes().current().isDark() ? "logo-light" : "logo-dark"); m_pButtonMain->setIconSize(QSize(85,20)*dpiratio); } @@ -112,7 +112,7 @@ void CMainPanelImpl::applyTheme(const std::wstring& theme) CMainPanel::applyTheme(theme); double dpiratio = scaling(); - m_pButtonMain->setIcon(":/logo.svg", AscAppManager::themes().isCurrentDark() ? "logo-light" : "logo-dark"); + m_pButtonMain->setIcon(":/logo.svg", AscAppManager::themes().current().isDark() ? "logo-light" : "logo-dark"); m_pButtonMain->setIconSize(QSize(85,20)*dpiratio); } diff --git a/win-linux/src/win/csinglewindow.cpp b/win-linux/src/win/csinglewindow.cpp index 62ca12077..93eb5db35 100644 --- a/win-linux/src/win/csinglewindow.cpp +++ b/win-linux/src/win/csinglewindow.cpp @@ -265,9 +265,9 @@ LRESULT CALLBACK CSingleWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, PAINTSTRUCT ps; HDC hDC = ::BeginPaint(hWnd, &ps); HPEN hpenOld = static_cast(::SelectObject(hDC, ::GetStockObject(DC_PEN))); - ::SetDCPenColor(hDC, AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBorder)); + ::SetDCPenColor(hDC, AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBorder)); - HBRUSH hBrush = ::CreateSolidBrush(AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBackground)); + HBRUSH hBrush = ::CreateSolidBrush(AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBackground)); HBRUSH hbrushOld = static_cast(::SelectObject(hDC, hBrush)); ::Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom); @@ -506,7 +506,7 @@ QWidget * CSingleWindow::createMainPanel(QWidget * parent, const QString& title, { QWidget * mainPanel = new QWidget(parent); mainPanel->setObjectName("mainPanel"); - mainPanel->setProperty("uitheme", QString::fromStdWString(AscAppManager::themes().current())); + mainPanel->setProperty("uitheme", QString::fromStdWString(AscAppManager::themes().current().id())); QGridLayout * mainGridLayout = new QGridLayout(); mainGridLayout->setSpacing(0); diff --git a/win-linux/src/win/csinglewindowplatform.cpp b/win-linux/src/win/csinglewindowplatform.cpp index 21dd4717c..8fa97ef70 100644 --- a/win-linux/src/win/csinglewindowplatform.cpp +++ b/win-linux/src/win/csinglewindowplatform.cpp @@ -48,8 +48,8 @@ Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); CSingleWindowPlatform::CSingleWindowPlatform(const QRect& rect, const QString& title, QWidget * panel) : CSingleWindowBase(const_cast(rect)) - , m_bgColor(AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBackground)) - , m_borderColor(AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBorder)) + , m_bgColor(AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBackground)) + , m_borderColor(AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBorder)) { HINSTANCE hInstance = GetModuleHandle(NULL); diff --git a/win-linux/src/win/mainwindow.cpp b/win-linux/src/win/mainwindow.cpp index 2451972a2..66362f674 100644 --- a/win-linux/src/win/mainwindow.cpp +++ b/win-linux/src/win/mainwindow.cpp @@ -122,7 +122,7 @@ CMainWindow::CMainWindow(QRect& rect) : wcx.cbWndExtra = 0; wcx.lpszClassName = WINDOW_CLASS_NAME; // wcx.hbrBackground = CreateSolidBrush(WINDOW_BACKGROUND_COLOR); - wcx.hbrBackground = CreateSolidBrush(AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBackground)); + wcx.hbrBackground = CreateSolidBrush(AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBackground)); wcx.hCursor = LoadCursor( hInstance, IDC_ARROW ); QIcon icon = Utils::appIcon(); @@ -490,9 +490,9 @@ qDebug() << "WM_CLOSE"; PAINTSTRUCT ps; HDC hDC = ::BeginPaint(hWnd, &ps); HPEN hpenOld = static_cast(::SelectObject(hDC, ::GetStockObject(DC_PEN))); - ::SetDCPenColor(hDC, AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBorder)); + ::SetDCPenColor(hDC, AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBorder)); - HBRUSH hBrush = ::CreateSolidBrush(AscAppManager::themes().colorRef(CThemes::ColorRole::ecrWindowBackground)); + HBRUSH hBrush = ::CreateSolidBrush(AscAppManager::themes().current().colorRef(CTheme::ColorRole::ecrWindowBackground)); HBRUSH hbrushOld = static_cast(::SelectObject(hDC, hBrush)); ::Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);