From 84f5585b5d958c3cdad4cce93244d43a360352c2 Mon Sep 17 00:00:00 2001 From: Thorben Kroeger Date: Tue, 14 Oct 2014 19:09:48 +0200 Subject: Implement theming for QtCreator Adds a 'Theme' tab to the environment settings and a '-theme' command line option. A theme is a combination of colors, gradients, flags and style information. There are two themes: - 'default': preserves the current default look - 'dark': uses a more flat for many widgets, dark color theme for everything This does not use a stylesheet (too limited), but rather sets the palette via C++ and modifies drawing behavior. Overall, the look is more flat (removed some gradients and bevels). Tested on Ubuntu 14.04 using Qt 5.4 and running on a KDE Desktop (Oxygen base style). For a screenshot, see https://gist.github.com/thorbenk/5ab06bea726de0aa7473 Changes: - Introduce class Theme, defining the interface how to access theme specific settings. The class reads a .creatortheme file (INI file, via QSettings) - Define named colors in the [Palette] section (see dark.creatortheme for example usage) - Use either named colors of AARRGGBB (hex) in the [Colors] section - A file ending with .creatortheme may be supplied to the '-theme' command line option - A global Theme instance can be accessed via creatorTheme() - Query colors, gradients, icons and flags from the theme were possible (TODO: use this in more places...) - There are very many color roles. It seems better to me to describe the role clearly, and then to consolidate later in the actual theme by assigning the same color. For example, one can set the text color of the output pane button individualy. - Many elements are also drawn differently. For the dark theme, I wanted to have a flatter look. - Introduce Theme::WidgetStyle enum, for now {Original, Flat}. - The theme specifies which kind of widget style it wants. - The drawing code queries the theme's style flag and switches between the original, gradient based look and the new, flat look. - Create some custom icons which look better on dark background (wip, currently folder/file icons) - Let ManhattanStyle draw some elements for non-panelwidgets, too (open/close arrows in QTreeView, custom folder/file icons) - For the welcomescreen, pass the WelcomeTheme class. WelcomeTheme exposes theme colors as Q_PROPERTY accessible from .qml - Themes can be modified via the 'Themes' tab in the environment settings. TODO: * Unify image handling * Avoid style name references * Fix gradients Change-Id: I92c2050ab0fb327649ea1eff4adec973d2073944 Reviewed-by: Thomas Hartmann Reviewed-by: hjk --- share/qtcreator/static.pro | 1 + share/qtcreator/themes/dark.creatortheme | 129 ++++++ share/qtcreator/themes/default.creatortheme | 118 ++++++ share/qtcreator/welcomescreen/develop.qml | 4 +- share/qtcreator/welcomescreen/welcomescreen.qml | 3 +- share/qtcreator/welcomescreen/widgets/Button.qml | 29 +- .../welcomescreen/widgets/CustomColors.qml | 38 -- share/qtcreator/welcomescreen/widgets/Delegate.qml | 6 +- .../welcomescreen/widgets/IconAndLink.qml | 2 +- .../qtcreator/welcomescreen/widgets/LinkedText.qml | 7 +- .../welcomescreen/widgets/ProjectItem.qml | 6 +- .../welcomescreen/widgets/RecentProjects.qml | 1 + .../qtcreator/welcomescreen/widgets/SearchBar.qml | 6 +- .../welcomescreen/widgets/SessionItem.qml | 13 +- share/qtcreator/welcomescreen/widgets/SideBar.qml | 30 +- share/share.qbs | 1 + src/libs/utils/detailsbutton.cpp | 54 ++- src/libs/utils/detailswidget.cpp | 32 +- src/libs/utils/outputformatter.cpp | 21 +- src/libs/utils/outputformatter.h | 2 - src/libs/utils/theme/theme.cpp | 356 ++++++++++++++++ src/libs/utils/theme/theme.h | 217 ++++++++++ src/libs/utils/theme/theme_p.cpp | 47 +++ src/libs/utils/theme/theme_p.h | 59 +++ src/libs/utils/theme/welcometheme.cpp | 87 ++++ src/libs/utils/theme/welcometheme.h | 87 ++++ src/libs/utils/utils-lib.pri | 10 +- src/libs/utils/utils.qbs | 13 + src/plugins/coreplugin/Core.json.in | 5 + src/plugins/coreplugin/core.qrc | 4 + src/plugins/coreplugin/coreconstants.h | 3 + src/plugins/coreplugin/coreplugin.cpp | 59 ++- src/plugins/coreplugin/coreplugin.pro | 26 +- src/plugins/coreplugin/coreplugin.qbs | 24 ++ .../coreplugin/editormanager/editorview.cpp | 19 +- src/plugins/coreplugin/fancyactionbar.cpp | 62 ++- src/plugins/coreplugin/fancytabwidget.cpp | 100 +++-- src/plugins/coreplugin/find/searchresultwidget.cpp | 21 +- src/plugins/coreplugin/images/dark_fileicon.png | Bin 0 -> 288 bytes src/plugins/coreplugin/images/dark_foldericon.png | Bin 0 -> 265 bytes src/plugins/coreplugin/images/dark_magnifier.png | Bin 0 -> 488 bytes .../coreplugin/images/dark_magnifier@2x.png | Bin 0 -> 589 bytes src/plugins/coreplugin/mainwindow.cpp | 8 + src/plugins/coreplugin/mainwindow.h | 3 + src/plugins/coreplugin/manhattanstyle.cpp | 114 +++-- src/plugins/coreplugin/manhattanstyle.h | 4 +- src/plugins/coreplugin/outputpanemanager.cpp | 59 ++- .../coreplugin/progressmanager/futureprogress.cpp | 11 +- .../coreplugin/progressmanager/progressbar.cpp | 33 +- .../coreplugin/progressmanager/progressmanager.cpp | 7 + src/plugins/coreplugin/themeeditor/colorrole.cpp | 58 +++ src/plugins/coreplugin/themeeditor/colorrole.h | 67 +++ .../coreplugin/themeeditor/colorvariable.cpp | 73 ++++ src/plugins/coreplugin/themeeditor/colorvariable.h | 77 ++++ .../coreplugin/themeeditor/sectionedtablemodel.cpp | 124 ++++++ .../coreplugin/themeeditor/sectionedtablemodel.h | 69 +++ src/plugins/coreplugin/themeeditor/themecolors.cpp | 76 ++++ src/plugins/coreplugin/themeeditor/themecolors.h | 71 ++++ .../themeeditor/themecolorstableview.cpp | 62 +++ .../coreplugin/themeeditor/themecolorstableview.h | 55 +++ .../coreplugin/themeeditor/themeeditorwidget.cpp | 142 +++++++ .../coreplugin/themeeditor/themeeditorwidget.h | 78 ++++ .../coreplugin/themeeditor/themeeditorwidget.ui | 45 ++ .../themeeditor/themesettingsitemdelegate.cpp | 227 ++++++++++ .../themeeditor/themesettingsitemdelegate.h | 78 ++++ .../themeeditor/themesettingstablemodel.cpp | 297 +++++++++++++ .../themeeditor/themesettingstablemodel.h | 94 +++++ src/plugins/coreplugin/themesettings.cpp | 465 +++++++++++++++++++++ src/plugins/coreplugin/themesettings.h | 72 ++++ src/plugins/coreplugin/themesettings.ui | 73 ++++ src/plugins/cppeditor/cppeditor.qrc | 3 + src/plugins/cppeditor/cppeditorplugin.cpp | 9 +- src/plugins/cppeditor/images/dark_qt_c.png | Bin 0 -> 341 bytes src/plugins/cppeditor/images/dark_qt_cpp.png | Bin 0 -> 266 bytes src/plugins/cppeditor/images/dark_qt_h.png | Bin 0 -> 502 bytes src/plugins/help/helpplugin.cpp | 11 +- src/plugins/projectexplorer/doubletabwidget.cpp | 146 ++++--- .../projectexplorer/miniprojecttargetselector.cpp | 48 ++- src/plugins/projectexplorer/panelswidget.cpp | 29 +- .../qmakeprojectmanager/images/dark_headers.png | Bin 0 -> 502 bytes .../qmakeprojectmanager/images/dark_sources.png | Bin 0 -> 266 bytes .../qmakeprojectmanager/images/dark_unknown.png | Bin 0 -> 356 bytes src/plugins/qmakeprojectmanager/profileeditor.cpp | 8 +- src/plugins/qmakeprojectmanager/qmakenodes.cpp | 10 +- .../qmakeprojectmanager/qmakeprojectmanager.qrc | 3 + src/plugins/qtsupport/images/dark_forms.png | Bin 0 -> 565 bytes src/plugins/qtsupport/images/dark_qml.png | Bin 0 -> 287 bytes src/plugins/qtsupport/images/dark_qt_project.png | Bin 0 -> 186 bytes src/plugins/qtsupport/images/dark_qt_qrc.png | Bin 0 -> 424 bytes src/plugins/qtsupport/qtoutputformatter.cpp | 5 +- src/plugins/qtsupport/qtsupport.qrc | 4 + src/plugins/qtsupport/qtsupportconstants.h | 1 + src/plugins/texteditor/texteditor.cpp | 8 +- src/plugins/todo/todoitemsmodel.cpp | 8 + src/plugins/welcome/welcomeplugin.cpp | 25 +- 95 files changed, 4169 insertions(+), 393 deletions(-) create mode 100644 share/qtcreator/themes/dark.creatortheme create mode 100644 share/qtcreator/themes/default.creatortheme delete mode 100644 share/qtcreator/welcomescreen/widgets/CustomColors.qml create mode 100644 src/libs/utils/theme/theme.cpp create mode 100644 src/libs/utils/theme/theme.h create mode 100644 src/libs/utils/theme/theme_p.cpp create mode 100644 src/libs/utils/theme/theme_p.h create mode 100644 src/libs/utils/theme/welcometheme.cpp create mode 100644 src/libs/utils/theme/welcometheme.h create mode 100644 src/plugins/coreplugin/images/dark_fileicon.png create mode 100644 src/plugins/coreplugin/images/dark_foldericon.png create mode 100644 src/plugins/coreplugin/images/dark_magnifier.png create mode 100644 src/plugins/coreplugin/images/dark_magnifier@2x.png create mode 100644 src/plugins/coreplugin/themeeditor/colorrole.cpp create mode 100644 src/plugins/coreplugin/themeeditor/colorrole.h create mode 100644 src/plugins/coreplugin/themeeditor/colorvariable.cpp create mode 100644 src/plugins/coreplugin/themeeditor/colorvariable.h create mode 100644 src/plugins/coreplugin/themeeditor/sectionedtablemodel.cpp create mode 100644 src/plugins/coreplugin/themeeditor/sectionedtablemodel.h create mode 100644 src/plugins/coreplugin/themeeditor/themecolors.cpp create mode 100644 src/plugins/coreplugin/themeeditor/themecolors.h create mode 100644 src/plugins/coreplugin/themeeditor/themecolorstableview.cpp create mode 100644 src/plugins/coreplugin/themeeditor/themecolorstableview.h create mode 100644 src/plugins/coreplugin/themeeditor/themeeditorwidget.cpp create mode 100644 src/plugins/coreplugin/themeeditor/themeeditorwidget.h create mode 100644 src/plugins/coreplugin/themeeditor/themeeditorwidget.ui create mode 100644 src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.cpp create mode 100644 src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.h create mode 100644 src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp create mode 100644 src/plugins/coreplugin/themeeditor/themesettingstablemodel.h create mode 100644 src/plugins/coreplugin/themesettings.cpp create mode 100644 src/plugins/coreplugin/themesettings.h create mode 100644 src/plugins/coreplugin/themesettings.ui create mode 100644 src/plugins/cppeditor/images/dark_qt_c.png create mode 100644 src/plugins/cppeditor/images/dark_qt_cpp.png create mode 100644 src/plugins/cppeditor/images/dark_qt_h.png create mode 100644 src/plugins/qmakeprojectmanager/images/dark_headers.png create mode 100644 src/plugins/qmakeprojectmanager/images/dark_sources.png create mode 100644 src/plugins/qmakeprojectmanager/images/dark_unknown.png create mode 100644 src/plugins/qtsupport/images/dark_forms.png create mode 100644 src/plugins/qtsupport/images/dark_qml.png create mode 100644 src/plugins/qtsupport/images/dark_qt_project.png create mode 100644 src/plugins/qtsupport/images/dark_qt_qrc.png diff --git a/share/qtcreator/static.pro b/share/qtcreator/static.pro index 6b4d50fd52..360fbf39cb 100644 --- a/share/qtcreator/static.pro +++ b/share/qtcreator/static.pro @@ -28,6 +28,7 @@ DATA_DIRS = \ examplebrowser \ snippets \ templates \ + themes \ designer \ schemes \ styles \ diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme new file mode 100644 index 0000000000..4223600e39 --- /dev/null +++ b/share/qtcreator/themes/dark.creatortheme @@ -0,0 +1,129 @@ +[General] +ThemeName=dark + +[Palette] +shadowBackground=ff232323 +text=ffe7e7e7 +textDisabled=ffa0a0a4 +hoverBackground=ff515151 +selectedBackground=ff151515 +normalBackground=ff333333 +alternateBackground=ff515151 +error=ffff0000 + +[Colors] +BackgroundColorAlternate=alternateBackground +BackgroundColorDark=shadowBackground +BackgroundColorHover=hoverBackground +BackgroundColorNormal=normalBackground +BackgroundColorSelected=selectedBackground +BadgeLabelBackgroundColorChecked=normalBackground +BadgeLabelBackgroundColorUnchecked=selectedBackground +BadgeLabelTextColorChecked=text +BadgeLabelTextColorUnchecked=text +CanceledSearchTextColor=ff0000 +ComboBoxArrowColor=text +ComboBoxArrowColorDisabled=text +ComboBoxTextColor=text +DetailsButtonBackgroundColorHover=hoverBackground +DetailsWidgetBackgroundColor=ff4a4a4a +DockWidgetResizeHandleColor=shadowBackground +DoubleTabWidget1stEmptyAreaBackgroundColor=normalBackground +DoubleTabWidget1stSeparatorColor=hoverBackground +DoubleTabWidget1stTabActiveTextColor=text +DoubleTabWidget1stTabBackgroundColor=ff4a4a4a +DoubleTabWidget1stTabInactiveTextColor=textDisabled +DoubleTabWidget2ndSeparatorColor=hoverBackground +DoubleTabWidget2ndTabActiveTextColor=text +DoubleTabWidget2ndTabBackgroundColor=ff434343 +DoubleTabWidget2ndTabInactiveTextColor=textDisabled +EditorPlaceholderColor=normalBackground +FancyTabBarBackgroundColor=shadowBackground +FancyTabWidgetDisabledSelectedTextColor=textDisabled +FancyTabWidgetDisabledUnselectedTextColor=textDisabled +FancyTabWidgetEnabledSelectedTextColor=text +FancyTabWidgetEnabledUnselectedTextColor=text +FancyToolButtonHoverColor=hoverBackground +FancyToolButtonSelectedColor=selectedBackground +FutureProgressBackgroundColor=shadowBackground +MenuBarEmptyAreaBackgroundColor=shadowBackground +MenuBarItemBackgroundColor=shadowBackground +MenuBarItemTextColorDisabled=textDisabled +MenuBarItemTextColorNormal=text +MiniProjectTargetSelectorBackgroundColor=shadowBackground +MiniProjectTargetSelectorBorderColor=shadowBackground +MiniProjectTargetSelectorSummaryBackgroundColor=shadowBackground +MiniProjectTargetSelectorTextColor=text +OutputFormatter_DebugTextColor=text +OutputFormatter_ErrorMessageTextColor=error +OutputFormatter_NormalMessageTextColor=text +OutputFormatter_StdErrTextColor=error +OutputFormatter_StdOutTextColor=text +OutputPaneButtonFlashColor=error +OutputPaneToggleButtonTextColorChecked=text +OutputPaneToggleButtonTextColorUnchecked=text +PanelButtonToolBackgroundColorHover=hoverBackground +PanelStatusBarBackgroundColor=shadowBackground +PanelTextColor=text +PanelsWidgetSeparatorLineColor=0 +ProgressBarColorError=error +ProgressBarColorFinished=ff5aaa3c +ProgressBarColorNormal=hoverBackground +ProgressBarTitleColor=text +QtOutputFormatter_LinkTextColor=ff0000ff +SearchResultWidgetBackgroundColor=shadowBackground +SearchResultWidgetTextColor=text +TextColorDisabled=textDisabled +TextColorHighlight=ffff0000 +TextColorNormal=text +TodoItemTextColor=ff000000 +ToggleButtonBackgroundColor=shadowBackground +ToolBarBackgroundColor=shadowBackground +TreeViewArrowColorNormal=hoverBackground +TreeViewArrowColorSelected=text +Welcome_BackgroundColorNormal=normalBackground +Welcome_Button_BorderColor=0 +Welcome_Button_TextColorNormal=ffe7e7e7 +Welcome_Button_TextColorPressed=ffffffff +Welcome_Caption_TextColorNormal=ff4acb47 +Welcome_DividerColor=ff232323 +Welcome_Link_BackgroundColor=ff333333 +Welcome_Link_TextColorActive=fff0f0f0 +Welcome_Link_TextColorNormal=text +Welcome_ProjectItem_BackgroundColorHover=0 +Welcome_ProjectItem_TextColorFilepath=textDisabled +Welcome_SessionItemExpanded_BackgroundColor=selectedBackground +Welcome_SessionItem_BackgroundColorHover=hoverBackground +Welcome_SessionItem_BackgroundColorNormal=0 +Welcome_SideBar_BackgroundColor=ff434343 +Welcome_TextColorHeading=text +Welcome_TextColorNormal=text + +[Flags] +ComboBoxDrawTextShadow=false +DerivePaletteFromTheme=true +DrawIndicatorBranch=true +DrawProgressBarSunken=false +DrawSearchResultWidgetFrame=false +DrawTargetSelectorBottom=false + +[Gradients] +DetailsWidgetHeaderGradient\1\color=0 +DetailsWidgetHeaderGradient\1\pos=1 +DetailsWidgetHeaderGradient\size=1 + +[IconOverlay] +CSourceMimetype=:/cppeditor/images/dark_qt_c.png +CppHeaderMimetype=:/cppeditor/images/dark_qt_h.png +CppSourceMimetype=:/cppeditor/images/dark_qt_cpp.png +PrfMimetype=:/qtsupport/images/dark_qt_project.png +PriMimetype=:/qtsupport/images/dark_qt_project.png +ProMimetype=:/qtsupport/images/dark_qt_project.png + +#TODO: needs to be ported to new ini format! +[StandardIcons] +SP_FileIcon=:/core/images/dark_fileicon.png +SP_DirIcon=:/core/images/dark_foldericon.png + +[Style] +WidgetStyle=StyleFlat diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme new file mode 100644 index 0000000000..b16dd8dbd6 --- /dev/null +++ b/share/qtcreator/themes/default.creatortheme @@ -0,0 +1,118 @@ +[General] +ThemeName=default + +[Palette] +brightText = ffffffff +darkText = ff000000 + +[Colors] +BackgroundColorAlternate=ff3d3d3d +BackgroundColorDark=ff232323 +BackgroundColorHover=ff515151 +BackgroundColorNormal=ffffffff +BackgroundColorSelected=ff151515 +BadgeLabelBackgroundColorChecked=ffe0e0e0 +BadgeLabelBackgroundColorUnchecked=ff808080 +BadgeLabelTextColorChecked=ff606060 +BadgeLabelTextColorUnchecked=ffffffff +CanceledSearchTextColor=ffff0000 +ComboBoxArrowColor=ffb8b5b2 +ComboBoxArrowColorDisabled=ffdcdcdc +ComboBoxTextColor=ffffffff +DetailsButtonBackgroundColorHover=b4ffffff +DetailsWidgetBackgroundColor=28ffffff +DockWidgetResizeHandleColor=ff000000 +DoubleTabWidget1stEmptyAreaBackgroundColor=ffff0000 +DoubleTabWidget1stSeparatorColor=ffff0000 +DoubleTabWidget1stTabActiveTextColor=ff000000 +DoubleTabWidget1stTabBackgroundColor=ffff0000 +DoubleTabWidget1stTabInactiveTextColor=ff000000 +DoubleTabWidget2ndSeparatorColor=ffff0000 +DoubleTabWidget2ndTabActiveTextColor=ffffffff +DoubleTabWidget2ndTabBackgroundColor=ffff0000 +DoubleTabWidget2ndTabInactiveTextColor=ff000000 +EditorPlaceholderColor=ffe0dcd8 +FancyTabBarBackgroundColor=ffff0000 +FancyTabWidgetDisabledSelectedTextColor=ffffffff +FancyTabWidgetDisabledUnselectedTextColor=78ffffff +FancyTabWidgetEnabledSelectedTextColor=ff3c3c3c +FancyTabWidgetEnabledUnselectedTextColor=ffffffff +FancyToolButtonHoverColor=28ffffff +FancyToolButtonSelectedColor=32000000 +FutureProgressBackgroundColor=ffff0000 +MenuBarEmptyAreaBackgroundColor=ffff0000 +MenuBarItemBackgroundColor=ffff0000 +MenuBarItemTextColorDisabled=ffa0a0a4 +MenuBarItemTextColorNormal=ff000000 +MiniProjectTargetSelectorBackgroundColor=ffa0a0a0 +MiniProjectTargetSelectorBorderColor=ff000000 +MiniProjectTargetSelectorSummaryBackgroundColor=ff464646 +MiniProjectTargetSelectorTextColor=a0ffffff +OutputFormatter_DebugTextColor=ffaa00aa +OutputFormatter_ErrorMessageTextColor=ffaa0000 +OutputFormatter_NormalMessageTextColor=ff0000aa +OutputFormatter_StdErrTextColor=ffaa0000 +OutputFormatter_StdOutTextColor=ff000000 +OutputPaneButtonFlashColor=ffff0000 +OutputPaneToggleButtonTextColorChecked=ffffffff +OutputPaneToggleButtonTextColorUnchecked=ff000000 +PanelTextColor=brightText +PanelButtonToolBackgroundColorHover=25ffffff +PanelStatusBarBackgroundColor=ffff0000 +PanelsWidgetSeparatorLineColor=ffbfbcb8 +ProgressBarColorError=d2ff3c00 +ProgressBarColorFinished=ff5aaa3c +ProgressBarColorNormal=b4ffffff +ProgressBarTitleColor=ffffffff +QtOutputFormatter_LinkTextColor=ff0000aa +SearchResultWidgetBackgroundColor=ffffffff +SearchResultWidgetTextColor=ff000000 +TextColorDisabled=ff000000 +TextColorHighlight=ffa0a0a4 +TextColorNormal=ff000000 +TodoItemTextColor=ff000000 +ToggleButtonBackgroundColor=ffff0000 +ToolBarBackgroundColor=ffff0000 +TreeViewArrowColorNormal=ffff0000 +TreeViewArrowColorSelected=ffff0000 +Welcome_BackgroundColorNormal=ffffffff +Welcome_Button_BorderColor=ff737373 +Welcome_Button_TextColorNormal=ff000000 +Welcome_Button_TextColorPressed=ffc0c0c0 +Welcome_Caption_TextColorNormal=ff328930 +Welcome_DividerColor=ff737373 +Welcome_Link_BackgroundColor=ff909090 +Welcome_Link_TextColorActive=fff0f0f0 +Welcome_Link_TextColorNormal=ff328930 +Welcome_ProjectItem_BackgroundColorHover=fff9f9f9 +Welcome_ProjectItem_TextColorFilepath=ff6b6b6b +Welcome_SessionItemExpanded_BackgroundColor=fff1f1f1 +Welcome_SessionItem_BackgroundColorHover=fff9f9f9 +Welcome_SessionItem_BackgroundColorNormal=19f9f9f9 +Welcome_SideBar_BackgroundColor=ffebebeb +Welcome_TextColorHeading=ff535353 +Welcome_TextColorNormal=ff000000 + +[Flags] +ComboBoxDrawTextShadow=true +DerivePaletteFromTheme=false +DrawIndicatorBranch=false +DrawProgressBarSunken=true +DrawSearchResultWidgetFrame=true +DrawTargetSelectorBottom=true + +[Gradients] +DetailsWidgetHeaderGradient\1\color=ffffff +DetailsWidgetHeaderGradient\1\pos=1 +DetailsWidgetHeaderGradient\size=1 + +[IconOverlay] +CSourceMimetype=:/cppeditor/images/qt_c.png +CppHeaderMimetype=:/cppeditor/images/qt_h.png +CppSourceMimetype=:/cppeditor/images/qt_cpp.png +PrfMimetype=:/qtsupport/images/qt_project.png +PriMimetype=:/qtsupport/images/qt_project.png +ProMimetype=:/qtsupport/images/qt_project.png + +[Style] +WidgetStyle=StyleDefault diff --git a/share/qtcreator/welcomescreen/develop.qml b/share/qtcreator/welcomescreen/develop.qml index 4681e2f3a0..dc0f9dc658 100644 --- a/share/qtcreator/welcomescreen/develop.qml +++ b/share/qtcreator/welcomescreen/develop.qml @@ -66,7 +66,7 @@ Controls.ScrollView { x: 32 y: screenDependHeightDistance + 77 - color: "#535353" + color: creatorTheme.textColorHeading text: qsTr("Sessions") font.pixelSize: 16 font.family: "Helvetica" @@ -78,7 +78,7 @@ Controls.ScrollView { x: 406 y: screenDependHeightDistance + 77 - color: "#535353" + color: creatorTheme.textColorHeading text: qsTr("Recent Projects") anchors.left: sessionsTitle.right anchors.leftMargin: 280 diff --git a/share/qtcreator/welcomescreen/welcomescreen.qml b/share/qtcreator/welcomescreen/welcomescreen.qml index 91174ede31..67c5bab9e5 100644 --- a/share/qtcreator/welcomescreen/welcomescreen.qml +++ b/share/qtcreator/welcomescreen/welcomescreen.qml @@ -35,7 +35,6 @@ Item { id: root property var fonts: CustomFonts {} - property var colors: CustomColors { } property int screenDependHeightDistance: Math.min(50, Math.max(16, height / 30)) @@ -48,7 +47,7 @@ Item { Rectangle { id: splitter - color: "#737373" + color: creatorTheme.dividerColor; // divider between left and right pane width: 1 anchors.top: parent.top anchors.bottom: parent.bottom diff --git a/share/qtcreator/welcomescreen/widgets/Button.qml b/share/qtcreator/welcomescreen/widgets/Button.qml index ec048f3f3a..9e860d7c8e 100644 --- a/share/qtcreator/welcomescreen/widgets/Button.qml +++ b/share/qtcreator/welcomescreen/widgets/Button.qml @@ -61,61 +61,60 @@ Button { Rectangle { anchors.fill: parent antialiasing: true - radius: 3 + radius: (creatorTheme.widgetStyle === 'flat') ? 0 : 3 visible: !(button.pressed || button.checked) gradient: Gradient { GradientStop { position: 0 - color: "#f9f9f9" + color: (theme==='dark') ? "#232323" : "#f9f9f9" } GradientStop { position: 0.49 - color: "#f9f9f9" + color: (theme === 'dark') ? "#232323" : "#f9f9f9" } GradientStop { position: 0.5 - color: "#eeeeee" + color: (theme === 'dark') ? "#232323" : "#eeeeee" } GradientStop { position: 1 - color: "#eeeeee" + color: (theme === 'dark') ? "#232323" : "#eeeeee" } } - border.color: "#737373" - + border.color: creatorTheme.button_BorderColor } Rectangle { anchors.fill: parent antialiasing: true - radius: 3 + radius: (creatorTheme.widgetStyle === 'flat') ? 0 : 3 visible: button.pressed || button.checked gradient: Gradient { GradientStop { position: 0.00; - color: "#4c4c4c"; + color: (theme === "dark") ? "#151515" : "#4c4c4c" } GradientStop { position: 0.49; - color: "#4c4c4c"; + color: (theme === "dark") ? "#151515" : "#4c4c4c" } GradientStop { position: 0.50; - color: "#424242"; + color: (theme === "dark") ? "#151515" : "#424242" } GradientStop { position: 1.00; - color: "#424242"; + color: (theme === "dark") ? "#151515" : "#424242" } } - border.color: "#333333" + border.color: creatorTheme.button_BorderColor } } @@ -124,7 +123,9 @@ Button { renderType: Text.NativeRendering verticalAlignment: Text.AlignVCenter text: button.text - color: button.pressed || button.checked ? "lightGray" : "black" + color: button.pressed || button.checked + ? creatorTheme.button_TextColorPressed + : creatorTheme.button_TextColorNormal font.pixelSize: 15 font.bold: false smooth: true diff --git a/share/qtcreator/welcomescreen/widgets/CustomColors.qml b/share/qtcreator/welcomescreen/widgets/CustomColors.qml deleted file mode 100644 index 5ee98e6f13..0000000000 --- a/share/qtcreator/welcomescreen/widgets/CustomColors.qml +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://www.qt.io/licensing. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -import QtQuick 2.1 - -QtObject { - property color linkColor: "#328930" - //property color linkColor: "#70b332" - //property color strongForegroundColor: "#58595b" - property color strongForegroundColor: "#328930" -} diff --git a/share/qtcreator/welcomescreen/widgets/Delegate.qml b/share/qtcreator/welcomescreen/widgets/Delegate.qml index 10dbd2298f..f7fcbfa059 100644 --- a/share/qtcreator/welcomescreen/widgets/Delegate.qml +++ b/share/qtcreator/welcomescreen/widgets/Delegate.qml @@ -34,6 +34,7 @@ Rectangle { id: delegate height: 240 width: 216 + color: creatorTheme.backgroundColorNormal property alias caption: captionItem.text property alias imageSource: imageItem.source @@ -106,7 +107,7 @@ Rectangle { y: 161 width: 200 height: 69 - color: "#ffffff" + color: creatorTheme.backgroundColorNormal anchors.bottom: parent.bottom anchors.right: parent.right anchors.left: parent.left @@ -116,7 +117,7 @@ Rectangle { id: captionItem x: 16 y: 170 - color: colors.strongForegroundColor + color: creatorTheme.caption_TextColorNormal text: qsTr("2D PAINTING EXAMPLE long description") elide: Text.ElideRight anchors.right: parent.right @@ -163,6 +164,7 @@ Rectangle { x: 16 y: 198 text: qsTr("Tags:") + color: creatorTheme.textColorNormal smooth: true font.italic: false font.pixelSize: 11 diff --git a/share/qtcreator/welcomescreen/widgets/IconAndLink.qml b/share/qtcreator/welcomescreen/widgets/IconAndLink.qml index 0e8aec6c91..3621653fda 100644 --- a/share/qtcreator/welcomescreen/widgets/IconAndLink.qml +++ b/share/qtcreator/welcomescreen/widgets/IconAndLink.qml @@ -44,7 +44,7 @@ Row { LinkedText { text: title font.pixelSize: 11 - color: "black" + color: creatorTheme.textColorNormal // 'Qt Account' .. 'User Guide' on lower left onClicked: { if (openUrl) gettingStarted.openUrl(openUrl); diff --git a/share/qtcreator/welcomescreen/widgets/LinkedText.qml b/share/qtcreator/welcomescreen/widgets/LinkedText.qml index 5c878538c4..c8c061a9d9 100644 --- a/share/qtcreator/welcomescreen/widgets/LinkedText.qml +++ b/share/qtcreator/welcomescreen/widgets/LinkedText.qml @@ -33,7 +33,8 @@ import QtQuick 2.1 NativeText { id: root height: 16 - color: active ? "#f0f0f0" : colors.linkColor + color: active ? creatorTheme.link_TextColorActive + : creatorTheme.link_TextColorNormal verticalAlignment: Text.AlignVCenter font: fonts.linkFont @@ -53,7 +54,7 @@ NativeText { property bool enlargeMouseArea: true Rectangle { - color: "#909090" + color: "#909090" // FIXME: theming: Where is this ever visible? radius: 6 opacity: root.active z: -1 @@ -65,7 +66,7 @@ NativeText { } Rectangle { - color: "#909090" + color: "#909090" // FIXME: theming: Where is this ever visible? opacity: root.active z: -1 anchors.rightMargin: -6 diff --git a/share/qtcreator/welcomescreen/widgets/ProjectItem.qml b/share/qtcreator/welcomescreen/widgets/ProjectItem.qml index 1216ac10f2..922eef5065 100644 --- a/share/qtcreator/welcomescreen/widgets/ProjectItem.qml +++ b/share/qtcreator/welcomescreen/widgets/ProjectItem.qml @@ -35,9 +35,9 @@ Item { width: row.width + 8 height: text.height - Rectangle { + Rectangle { // background shown on hover over project item anchors.fill: parent - color: "#f9f9f9" + color: creatorTheme.projectItem_BackgroundColorHover visible: mouseArea.containsMouse } @@ -67,7 +67,7 @@ Item { NativeText { id: pathText height: 20 - color: "#6b6b6b" + color: creatorTheme.projectItem_TextColorFilepath font: fonts.smallPath } } diff --git a/share/qtcreator/welcomescreen/widgets/RecentProjects.qml b/share/qtcreator/welcomescreen/widgets/RecentProjects.qml index bd59444e23..e6f1c6ee01 100644 --- a/share/qtcreator/welcomescreen/widgets/RecentProjects.qml +++ b/share/qtcreator/welcomescreen/widgets/RecentProjects.qml @@ -34,6 +34,7 @@ import QtQuick.Controls 1.0 Rectangle { id: projectList height: column.height + 200 + color: creatorTheme.backgroundColorNormal property alias model: repeater.model // Behavior on verticalScrollBar.opacity { diff --git a/share/qtcreator/welcomescreen/widgets/SearchBar.qml b/share/qtcreator/welcomescreen/widgets/SearchBar.qml index 9d4ce68536..1578445f59 100644 --- a/share/qtcreator/welcomescreen/widgets/SearchBar.qml +++ b/share/qtcreator/welcomescreen/widgets/SearchBar.qml @@ -37,9 +37,9 @@ Rectangle { width: 930 height: 27 - color: "#ffffff" + color: creatorTheme.backgroundColorNormal radius: 6 - border.color: "#cccccc" + border.color: "#cccccc" // FIXME: make themable property alias placeholderText: lineEdit.placeholderText property alias text: lineEdit.text @@ -56,6 +56,8 @@ Rectangle { font.pixelSize: 14 placeholderText: qsTr("Search...") style: TextFieldStyle { + placeholderTextColor: creatorTheme.textColorNormal + textColor: creatorTheme.textColorNormal background: Item { } } diff --git a/share/qtcreator/welcomescreen/widgets/SessionItem.qml b/share/qtcreator/welcomescreen/widgets/SessionItem.qml index 2d2f5ceaf6..3f8bfbf451 100644 --- a/share/qtcreator/welcomescreen/widgets/SessionItem.qml +++ b/share/qtcreator/welcomescreen/widgets/SessionItem.qml @@ -67,7 +67,10 @@ Item { Rectangle { z: -4 - color: "#f9f9f9" + // background of session item + color: (iArea.hovered || text.hovered || area2.hovered) + ? creatorTheme.sessionItem_BackgroundColorHover + : creatorTheme.sessionItem_BackgroundColorNormal anchors.fill: parent visible: iArea.containsMouse || text.hovered anchors.topMargin: 1 @@ -115,6 +118,7 @@ Item { NativeText { text: projectsName[index] font: fonts.boldDescription + color: creatorTheme.textColorNormal } NativeText { x: 4 @@ -139,7 +143,7 @@ Item { maximumLineCount: 2 elide: Text.ElideRight height: lineCount == 2 ? font.pixelSize * 2 + 4 : font.pixelSize + 2 - color: "#6b6b6b" + color: creatorTheme.projectItem_TextColorFilepath width: delegate.ListView.view.width - 48 MouseArea { anchors.fill: parent @@ -222,7 +226,8 @@ Item { id: collapseButton visible: text.hovered || iArea.containsMouse || delegate.expanded - property color color: iArea.containsMouse ? "#E9E9E9" : "#f1f1f1" + property color color: iArea.containsMouse ? creatorTheme.sessionItem_BackgroundColorHover + : creatorTheme.sessionItemExpanded_BackgroundColor anchors.fill: parent Image { @@ -238,7 +243,7 @@ Item { Rectangle { color: collapseButton.color z: -1 - radius: 6 + radius: creatorTheme.widgetStyle === 'flat' ? 0 : 6 anchors.fill: parent anchors.topMargin: 1 anchors.bottomMargin: 1 diff --git a/share/qtcreator/welcomescreen/widgets/SideBar.qml b/share/qtcreator/welcomescreen/widgets/SideBar.qml index 8c1931099c..9c92901f09 100644 --- a/share/qtcreator/welcomescreen/widgets/SideBar.qml +++ b/share/qtcreator/welcomescreen/widgets/SideBar.qml @@ -48,10 +48,24 @@ ColumnLayout { Layout.preferredWidth: tabs.width + 16 * 2 Layout.preferredHeight: tabs.height + screenDependHeightDistance * 2 - Image { - fillMode: Image.Tile - source: "images/background.png" + Component { + id: imageBackground + Image { + fillMode: Image.Tile + source: "images/background.png" + anchors.fill: parent + } + } + Component { + id: flatBackground + Rectangle { + color: creatorTheme.sideBar_BackgroundColor + } + } + Loader { + id: topLeftLoader anchors.fill: parent + sourceComponent: creatorTheme.widgetStyle === 'flat' ? flatBackground : imageBackground; } Tabs { @@ -64,7 +78,7 @@ ColumnLayout { } Rectangle { - color: "#737373" + color: creatorTheme.widgetStyle === 'flat' ? creatorTheme.sideBar_BackgroundColor : creatorTheme.dividerColor anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -73,7 +87,7 @@ ColumnLayout { } Rectangle { - color: "#737373" + color: creatorTheme.widgetStyle === 'flat' ? creatorTheme.sideBar_BackgroundColor : creatorTheme.dividerColor anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -83,7 +97,7 @@ ColumnLayout { } Rectangle { - color: "#737373" + color: creatorTheme.widgetStyle === 'flat' ? creatorTheme.sideBar_BackgroundColor : creatorTheme.dividerColor anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -94,7 +108,7 @@ ColumnLayout { } Rectangle { - color: "#ebebeb" + color: creatorTheme.sideBar_BackgroundColor Layout.fillWidth: true Layout.preferredWidth: innerColumn.width + 20 @@ -115,6 +129,7 @@ ColumnLayout { NativeText { text: qsTr("New to Qt?") + color: creatorTheme.textColorNormal font.pixelSize: 18 } @@ -124,6 +139,7 @@ ColumnLayout { Layout.preferredWidth: innerColumn.width text: qsTr("Learn how to develop your own applications and explore Qt Creator.") + color: creatorTheme.textColorNormal font.pixelSize: 12 wrapMode: Text.WrapAtWordBoundaryOrAnywhere } diff --git a/share/share.qbs b/share/share.qbs index f048f5d98d..354844a62d 100644 --- a/share/share.qbs +++ b/share/share.qbs @@ -21,6 +21,7 @@ Product { "snippets", "styles", "templates", + "themes", "welcomescreen" ] } diff --git a/src/libs/utils/detailsbutton.cpp b/src/libs/utils/detailsbutton.cpp index cfbfc1044f..3e36c12cb4 100644 --- a/src/libs/utils/detailsbutton.cpp +++ b/src/libs/utils/detailsbutton.cpp @@ -29,8 +29,8 @@ ****************************************************************************/ #include "detailsbutton.h" - -#include +#include "hostosinfo.h" +#include "theme/theme.h" #include #include @@ -122,8 +122,15 @@ void DetailsButton::paintEvent(QPaintEvent *e) QPainter p(this); // draw hover animation - if (!HostOsInfo::isMacHost() && !isDown() && m_fader > 0) - p.fillRect(rect().adjusted(1, 1, -2, -2), QColor(255, 255, 255, int(m_fader*180))); + if (!HostOsInfo::isMacHost() && !isDown() && m_fader > 0) { + QColor c = creatorTheme()->color(Theme::DetailsButtonBackgroundColorHover); + c.setAlpha (int(m_fader * c.alpha())); + + QRect r = rect(); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) + r.adjust(1, 1, -2, -2); + p.fillRect(r, c); + } if (isChecked()) { if (m_checkedPixmap.isNull() || m_checkedPixmap.size() / m_checkedPixmap.devicePixelRatio() != contentsRect().size()) @@ -148,10 +155,6 @@ void DetailsButton::paintEvent(QPaintEvent *e) QPixmap DetailsButton::cacheRendering(const QSize &size, bool checked) { - QLinearGradient lg; - lg.setCoordinateMode(QGradient::ObjectBoundingMode); - lg.setFinalStop(0, 1); - const qreal pixelRatio = devicePixelRatio(); QPixmap pixmap(size * pixelRatio); pixmap.setDevicePixelRatio(pixelRatio); @@ -159,23 +162,30 @@ QPixmap DetailsButton::cacheRendering(const QSize &size, bool checked) QPainter p(&pixmap); p.setRenderHint(QPainter::Antialiasing, true); p.translate(0.5, 0.5); - p.setPen(Qt::NoPen); - if (!checked) { - lg.setColorAt(0, QColor(0, 0, 0, 10)); - lg.setColorAt(1, QColor(0, 0, 0, 16)); + + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + QLinearGradient lg; + lg.setCoordinateMode(QGradient::ObjectBoundingMode); + lg.setFinalStop(0, 1); + if (!checked) { + lg.setColorAt(0, QColor(0, 0, 0, 10)); + lg.setColorAt(1, QColor(0, 0, 0, 16)); + } else { + lg.setColorAt(0, QColor(255, 255, 255, 0)); + lg.setColorAt(1, QColor(255, 255, 255, 50)); + } + p.setBrush(lg); + p.setPen(QColor(255,255,255,140)); + p.drawRoundedRect(1, 1, size.width()-3, size.height()-3, 1, 1); + p.setPen(QPen(QColor(0, 0, 0, 40))); + p.drawLine(0, 1, 0, size.height() - 2); + if (checked) + p.drawLine(1, size.height() - 1, size.width() - 1, size.height() - 1); } else { - lg.setColorAt(0, QColor(255, 255, 255, 0)); - lg.setColorAt(1, QColor(255, 255, 255, 50)); + p.setPen(Qt::NoPen); + p.drawRoundedRect(0, 0, size.width(), size.height(), 1, 1); } - p.setBrush(lg); - p.setPen(QColor(255,255,255,140)); - p.drawRoundedRect(1, 1, size.width()-3, size.height()-3, 1, 1); - p.setPen(QPen(QColor(0, 0, 0, 40))); - p.drawLine(0, 1, 0, size.height() - 2); - if (checked) - p.drawLine(1, size.height() - 1, size.width() - 1, size.height() - 1); - p.setPen(palette().color(QPalette::Text)); QRect textRect = p.fontMetrics().boundingRect(text()); diff --git a/src/libs/utils/detailswidget.cpp b/src/libs/utils/detailswidget.cpp index 68320d76c5..5218916cf7 100644 --- a/src/libs/utils/detailswidget.cpp +++ b/src/libs/utils/detailswidget.cpp @@ -31,6 +31,7 @@ #include "detailswidget.h" #include "detailsbutton.h" #include "hostosinfo.h" +#include "theme/theme.h" #include #include @@ -148,21 +149,22 @@ QPixmap DetailsWidget::createBackground(const QSize &size, int topHeight, QWidge if (HostOsInfo::isMacHost()) p.fillRect(fullRect, qApp->palette().window().color()); else - p.fillRect(fullRect, QColor(255, 255, 255, 40)); - - QLinearGradient lg(topRect.topLeft(), topRect.bottomLeft()); - lg.setColorAt(0, QColor(255, 255, 255, 130)); - lg.setColorAt(1, QColor(255, 255, 255, 0)); - p.fillRect(topRect, lg); - p.setRenderHint(QPainter::Antialiasing, true); - p.translate(0.5, 0.5); - p.setPen(QColor(0, 0, 0, 40)); - p.setBrush(Qt::NoBrush); - p.drawRoundedRect(fullRect.adjusted(0, 0, -1, -1), 2, 2); - p.setBrush(Qt::NoBrush); - p.setPen(QColor(255,255,255,140)); - p.drawRoundedRect(fullRect.adjusted(1, 1, -2, -2), 2, 2); - p.setPen(QPen(widget->palette().color(QPalette::Mid))); + p.fillRect(fullRect, creatorTheme()->color(Theme::DetailsWidgetBackgroundColor)); + + if (creatorTheme()->widgetStyle () == Theme::StyleDefault) { + QLinearGradient lg(topRect.topLeft(), topRect.bottomLeft()); + lg.setStops(creatorTheme()->gradient(Theme::DetailsWidgetHeaderGradient)); + p.fillRect(topRect, lg); + p.setRenderHint(QPainter::Antialiasing, true); + p.translate(0.5, 0.5); + p.setPen(QColor(0, 0, 0, 40)); + p.setBrush(Qt::NoBrush); + p.drawRoundedRect(fullRect.adjusted(0, 0, -1, -1), 2, 2); + p.setBrush(Qt::NoBrush); + p.setPen(QColor(255,255,255,140)); + p.drawRoundedRect(fullRect.adjusted(1, 1, -2, -2), 2, 2); + p.setPen(QPen(widget->palette().color(QPalette::Mid))); + } return pixmap; } diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index 5d952d2ed9..ca745e3f8a 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -28,10 +28,11 @@ ** ****************************************************************************/ +#include "ansiescapecodehandler.h" #include "outputformatter.h" +#include "theme/theme.h" #include -#include using namespace Utils; @@ -110,12 +111,6 @@ void OutputFormatter::clearLastLine() cursor.removeSelectedText(); } -QColor OutputFormatter::mixColors(const QColor &a, const QColor &b) -{ - return QColor((a.red() + 2 * b.red()) / 3, (a.green() + 2 * b.green()) / 3, - (a.blue() + 2* b.blue()) / 3, (a.alpha() + 2 * b.alpha()) / 3); -} - void OutputFormatter::initFormats() { if (!plainTextEdit()) @@ -127,26 +122,28 @@ void OutputFormatter::initFormats() m_formats = new QTextCharFormat[NumberOfFormats]; + Theme *theme = creatorTheme(); + // NormalMessageFormat m_formats[NormalMessageFormat].setFont(boldFont); - m_formats[NormalMessageFormat].setForeground(mixColors(p.color(QPalette::Text), QColor(Qt::blue))); + m_formats[NormalMessageFormat].setForeground(theme->color(Theme::OutputFormatter_NormalMessageTextColor)); // ErrorMessageFormat m_formats[ErrorMessageFormat].setFont(boldFont); - m_formats[ErrorMessageFormat].setForeground(mixColors(p.color(QPalette::Text), QColor(Qt::red))); + m_formats[ErrorMessageFormat].setForeground(theme->color(Theme::OutputFormatter_ErrorMessageTextColor)); // StdOutFormat m_formats[StdOutFormat].setFont(m_font); - m_formats[StdOutFormat].setForeground(p.color(QPalette::Text)); + m_formats[StdOutFormat].setForeground(theme->color(Theme::OutputFormatter_StdOutTextColor)); m_formats[StdOutFormatSameLine] = m_formats[StdOutFormat]; // StdErrFormat m_formats[StdErrFormat].setFont(m_font); - m_formats[StdErrFormat].setForeground(mixColors(p.color(QPalette::Text), QColor(Qt::red))); + m_formats[StdErrFormat].setForeground(theme->color(Theme::OutputFormatter_StdErrTextColor)); m_formats[StdErrFormatSameLine] = m_formats[StdErrFormat]; m_formats[DebugFormat].setFont(m_font); - m_formats[DebugFormat].setForeground(mixColors(p.color(QPalette::Text), QColor(Qt::magenta))); + m_formats[DebugFormat].setForeground(theme->color(Theme::OutputFormatter_DebugTextColor)); } void OutputFormatter::handleLink(const QString &href) diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h index 2f29a195bf..6dba8e5f10 100644 --- a/src/libs/utils/outputformatter.h +++ b/src/libs/utils/outputformatter.h @@ -73,8 +73,6 @@ protected: QTextCharFormat charFormat(OutputFormat format) const; void append(QTextCursor &cursor, const QString &text, const QTextCharFormat &format); - static QColor mixColors(const QColor &a, const QColor &b); - private: QPlainTextEdit *m_plainTextEdit; QTextCharFormat *m_formats; diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp new file mode 100644 index 0000000000..97d1627115 --- /dev/null +++ b/src/libs/utils/theme/theme.cpp @@ -0,0 +1,356 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "theme.h" +#include "theme_p.h" +#include "qtcassert.h" + +#include +#include +#include +#include + +namespace Utils { + +static Theme *m_creatorTheme = 0; + +Theme *creatorTheme() +{ + return m_creatorTheme; +} + +void setCreatorTheme(Theme *theme) +{ + // TODO: memory management of theme object + m_creatorTheme = theme; +} + +Theme::Theme(QObject *parent) + : QObject(parent) + , d(new ThemePrivate) +{ +} + +Theme::~Theme() +{ + delete d; +} + +void Theme::drawIndicatorBranch(QPainter *painter, const QRect &rect, QStyle::State state) const +{ + Q_UNUSED(painter); + Q_UNUSED(rect); + Q_UNUSED(state); +} + +Theme::WidgetStyle Theme::widgetStyle() const +{ + return d->widgetStyle; +} + +bool Theme::flag(Theme::Flag f) const +{ + return d->flags[f]; +} + +QColor Theme::color(Theme::ColorRole role) const +{ + return d->colors[role].first; +} + +QGradientStops Theme::gradient(Theme::GradientRole role) const +{ + return d->gradientStops[role]; +} + +QString Theme::iconOverlay(Theme::MimeType mimetype) const +{ + return d->iconOverlays[mimetype]; +} + +QString Theme::dpiSpecificImageFile(const QString &fileName) const +{ + return dpiSpecificImageFile(fileName, QLatin1String("")); +} + +QString Theme::dpiSpecificImageFile(const QString &fileName, const QString &themePrefix) const +{ + // See QIcon::addFile() + const QFileInfo fi(fileName); + + bool at2x = (qApp->devicePixelRatio() > 1.0); + + const QString at2xFileName = fi.path() + QStringLiteral("/") + + fi.completeBaseName() + QStringLiteral("@2x.") + fi.suffix(); + const QString themedAt2xFileName = fi.path() + QStringLiteral("/") + themePrefix + + fi.completeBaseName() + QStringLiteral("@2x.") + fi.suffix(); + const QString themedFileName = fi.path() + QStringLiteral("/") + themePrefix + + fi.completeBaseName() + QStringLiteral(".") + fi.suffix(); + + if (at2x) { + if (QFile::exists(themedAt2xFileName)) + return themedAt2xFileName; + else if (QFile::exists(themedFileName)) + return themedFileName; + else if (QFile::exists(at2xFileName)) + return at2xFileName; + return fileName; + } else { + if (QFile::exists(themedFileName)) + return themedFileName; + return fileName; + } +} + +QPair Theme::readNamedColor(const QString &color) const +{ + if (d->palette.contains(color)) + return qMakePair(d->palette[color], color); + + bool ok = true; + const QRgb rgba = color.toLongLong(&ok, 16); + if (!ok) { + qWarning("Color '%s' is neither a named color nor a valid color", qPrintable(color)); + return qMakePair(Qt::black, QString()); + } + return qMakePair(QColor::fromRgba(rgba), QString()); +} + +QString Theme::imageFile(const QString &fileName) const +{ + return fileName; +} + +QString Theme::fileName() const +{ + return d->fileName; +} + +void Theme::setName(const QString &name) +{ + d->name = name; +} + +static QColor readColor(const QString &color) +{ + bool ok = true; + const QRgb rgba = color.toLongLong(&ok, 16); + return QColor::fromRgba(rgba); +} + +static QString writeColor(const QColor &color) +{ + return QString::number(color.rgba(), 16); +} + +// reading, writing of .creatortheme ini file //////////////////////////////// +void Theme::writeSettings(const QString &filename) const +{ + QSettings settings(filename, QSettings::IniFormat); + + const QMetaObject &m = *metaObject(); + { + settings.setValue(QLatin1String("ThemeName"), d->name); + } + { + settings.beginGroup(QLatin1String("Palette")); + for (int i = 0, total = d->colors.size(); i < total; ++i) { + const QPair var = d->colors[i]; + if (var.second.isEmpty()) + continue; + settings.setValue(var.second, writeColor(var.first)); + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Colors")); + const QMetaEnum e = m.enumerator(m.indexOfEnumerator("ColorRole")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + const QPair var = d->colors[i]; + if (!var.second.isEmpty()) + settings.setValue(key, var.second); // named color + else + settings.setValue(key, writeColor(var.first)); + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Gradients")); + const QMetaEnum e = m.enumerator(m.indexOfEnumerator("GradientRole")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QGradientStops stops = gradient(static_cast(i)); + settings.beginWriteArray(key); + int k = 0; + foreach (const QGradientStop stop, stops) { + settings.setArrayIndex(k); + settings.setValue(QLatin1String("pos"), stop.first); + settings.setValue(QLatin1String("color"), writeColor(stop.second)); + ++k; + } + settings.endArray(); + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("IconOverlay")); + const QMetaEnum e = m.enumerator(m.indexOfEnumerator("MimeType")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + settings.setValue(key, iconOverlay(static_cast(i))); + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Flags")); + const QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + settings.setValue(key, flag(static_cast(i))); + } + settings.endGroup(); + } + + { + settings.beginGroup(QLatin1String("Style")); + const QMetaEnum e = m.enumerator(m.indexOfEnumerator("WidgetStyle")); + settings.setValue(QLatin1String("WidgetStyle"), QLatin1String(e.valueToKey(widgetStyle ()))); + settings.endGroup(); + } +} + +void Theme::readSettings(QSettings &settings) +{ + d->fileName = settings.fileName(); + const QMetaObject &m = *metaObject(); + + { + d->name = settings.value(QLatin1String("ThemeName"), QLatin1String("unnamed")).toString(); + } + { + settings.beginGroup(QLatin1String("Palette")); + foreach (const QString &key, settings.allKeys()) { + QColor c = readColor(settings.value(key).toString()); + d->palette[key] = c; + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Style")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("WidgetStyle")); + QString val = settings.value(QLatin1String("WidgetStyle")).toString(); + d->widgetStyle = static_cast(e.keysToValue (val.toLatin1().data())); + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Colors")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("ColorRole")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QTC_ASSERT(settings.contains(key), return);; + d->colors[i] = readNamedColor(settings.value(key).toString()); + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Gradients")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("GradientRole")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QGradientStops stops; + int size = settings.beginReadArray(key); + for (int j = 0; j < size; ++j) { + settings.setArrayIndex(j); + QTC_ASSERT(settings.contains(QLatin1String("pos")), return);; + double pos = settings.value(QLatin1String("pos")).toDouble(); + QTC_ASSERT(settings.contains(QLatin1String("color")), return);; + QColor c = readColor(settings.value(QLatin1String("color")).toString()); + stops.append(qMakePair(pos, c)); + } + settings.endArray(); + d->gradientStops[i] = stops; + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("IconOverlay")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("MimeType")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QTC_ASSERT(settings.contains(key), return);; + d->iconOverlays[i] = settings.value(key).toString(); + } + settings.endGroup(); + } + { + settings.beginGroup(QLatin1String("Flags")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QTC_ASSERT(settings.contains(key), return);; + d->flags[i] = settings.value(key).toBool(); + } + settings.endGroup(); + } +} + +QIcon Theme::standardIcon(QStyle::StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const +{ + Q_UNUSED(standardPixmap); + Q_UNUSED(opt); + Q_UNUSED(widget); + return QIcon(); +} + +QPalette Theme::palette(const QPalette &base) const +{ + if (!flag(DerivePaletteFromTheme)) + return base; + + // FIXME: introduce some more color roles for this + + QPalette pal = base; + pal.setColor(QPalette::All, QPalette::Window, color(Theme::BackgroundColorNormal)); + pal.setBrush(QPalette::All, QPalette::WindowText, color(Theme::TextColorNormal)); + pal.setColor(QPalette::All, QPalette::Base, color(Theme::BackgroundColorNormal)); + pal.setColor(QPalette::All, QPalette::AlternateBase, color(Theme::BackgroundColorAlternate)); + pal.setColor(QPalette::All, QPalette::Button, color(Theme::BackgroundColorDark)); + pal.setColor(QPalette::All, QPalette::BrightText, Qt::red); + pal.setBrush(QPalette::All, QPalette::Text, color(Theme::TextColorNormal)); + pal.setBrush(QPalette::All, QPalette::ButtonText, color(Theme::TextColorNormal)); + pal.setBrush(QPalette::All, QPalette::ToolTipBase, color(Theme::BackgroundColorSelected)); + pal.setColor(QPalette::Highlight, color(Theme::BackgroundColorSelected)); + pal.setColor(QPalette::HighlightedText, Qt::white); + pal.setColor(QPalette::ToolTipText, color(Theme::TextColorNormal)); + return pal; +} + +} // namespace Utils diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h new file mode 100644 index 0000000000..4a55bdc409 --- /dev/null +++ b/src/libs/utils/theme/theme.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEME_H +#define THEME_H + +#include "../utils_global.h" + +#include +#include + +QT_FORWARD_DECLARE_CLASS(QSettings) + +namespace Utils { + +class ThemePrivate; + +class QTCREATOR_UTILS_EXPORT Theme : public QObject +{ + Q_OBJECT + + Q_ENUMS(ColorRole) + Q_ENUMS(GradientRole) + Q_ENUMS(MimeType) + Q_ENUMS(Flag) + Q_ENUMS(WidgetStyle) + +public: + Theme(QObject *parent = 0); + ~Theme(); + + enum ColorRole { + BackgroundColorAlternate, + BackgroundColorDark, + BackgroundColorHover, + BackgroundColorNormal, + BackgroundColorSelected, + BadgeLabelBackgroundColorChecked, + BadgeLabelBackgroundColorUnchecked, + BadgeLabelTextColorChecked, + BadgeLabelTextColorUnchecked, + CanceledSearchTextColor, + ComboBoxArrowColor, + ComboBoxArrowColorDisabled, + ComboBoxTextColor, + DetailsWidgetBackgroundColor, + DetailsButtonBackgroundColorHover, + DockWidgetResizeHandleColor, + DoubleTabWidget1stEmptyAreaBackgroundColor, + DoubleTabWidget1stSeparatorColor, + DoubleTabWidget2ndSeparatorColor, + DoubleTabWidget1stTabBackgroundColor, + DoubleTabWidget2ndTabBackgroundColor, + DoubleTabWidget1stTabActiveTextColor, + DoubleTabWidget1stTabInactiveTextColor, + DoubleTabWidget2ndTabActiveTextColor, + DoubleTabWidget2ndTabInactiveTextColor, + EditorPlaceholderColor, + FancyTabBarBackgroundColor, + FancyTabWidgetEnabledSelectedTextColor, + FancyTabWidgetEnabledUnselectedTextColor, + FancyTabWidgetDisabledSelectedTextColor, + FancyTabWidgetDisabledUnselectedTextColor, + FancyToolButtonHoverColor, + FancyToolButtonSelectedColor, + FutureProgressBackgroundColor, + MenuBarEmptyAreaBackgroundColor, + MenuBarItemBackgroundColor, + MenuBarItemTextColorDisabled, + MenuBarItemTextColorNormal, + MiniProjectTargetSelectorBackgroundColor, + MiniProjectTargetSelectorBorderColor, + MiniProjectTargetSelectorSummaryBackgroundColor, + MiniProjectTargetSelectorTextColor, + OutputPaneButtonFlashColor, + OutputPaneToggleButtonTextColorChecked, + OutputPaneToggleButtonTextColorUnchecked, + PanelButtonToolBackgroundColorHover, + PanelTextColor, + PanelsWidgetSeparatorLineColor, + PanelStatusBarBackgroundColor, + ProgressBarTitleColor, + ProgressBarColorError, + ProgressBarColorFinished, + ProgressBarColorNormal, + SearchResultWidgetBackgroundColor, + SearchResultWidgetTextColor, + TextColorDisabled, + TextColorHighlight, + TextColorNormal, + TodoItemTextColor, + ToggleButtonBackgroundColor, + ToolBarBackgroundColor, + TreeViewArrowColorNormal, + TreeViewArrowColorSelected, + + OutputFormatter_NormalMessageTextColor, + OutputFormatter_ErrorMessageTextColor, + OutputFormatter_StdOutTextColor, + OutputFormatter_StdErrTextColor, + OutputFormatter_DebugTextColor, + + QtOutputFormatter_LinkTextColor, + + /* Welcome Plugin */ + + Welcome_TextColorNormal, + Welcome_TextColorHeading, // #535353 // Sessions, Recent Projects + Welcome_BackgroundColorNormal, // #ffffff + Welcome_DividerColor, // #737373 + Welcome_Button_BorderColor, + Welcome_Button_TextColorNormal, + Welcome_Button_TextColorPressed, + Welcome_Link_TextColorNormal, + Welcome_Link_TextColorActive, + Welcome_Link_BackgroundColor, + Welcome_Caption_TextColorNormal, + Welcome_SideBar_BackgroundColor, + + Welcome_ProjectItem_TextColorFilepath, + Welcome_ProjectItem_BackgroundColorHover, + + Welcome_SessionItem_BackgroundColorNormal, + Welcome_SessionItem_BackgroundColorHover, + Welcome_SessionItemExpanded_BackgroundColor + }; + + enum GradientRole { + DetailsWidgetHeaderGradient, + Welcome_Button_GradientNormal, + Welcome_Button_GradientPressed + }; + + enum MimeType { + CppSourceMimetype, + CSourceMimetype, + CppHeaderMimetype, + ProMimetype, + PriMimetype, + PrfMimetype + }; + + enum Flag { + DrawTargetSelectorBottom, + DrawSearchResultWidgetFrame, + DrawProgressBarSunken, + DrawIndicatorBranch, + ComboBoxDrawTextShadow, + DerivePaletteFromTheme + }; + + enum WidgetStyle { + StyleDefault, + StyleFlat + }; + + WidgetStyle widgetStyle() const; + bool flag(Flag f) const; + QColor color(ColorRole role) const; + QGradientStops gradient(GradientRole role) const; + QString iconOverlay(MimeType mimetype) const; + QPalette palette(const QPalette &base) const; + QString dpiSpecificImageFile(const QString &fileName) const; + void drawIndicatorBranch(QPainter *painter, const QRect &rect, QStyle::State state) const; + QIcon standardIcon(QStyle::StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const; + QString imageFile(const QString &fileName) const; + + QString fileName() const; + void setName(const QString &name); + + void writeSettings(const QString &filename) const; + void readSettings(QSettings &settings); + ThemePrivate *d; + +signals: + void changed(); + +protected: + QString dpiSpecificImageFile(const QString &fileName, const QString &themePrefix) const; + +private: + QPair readNamedColor(const QString &color) const; +}; + +QTCREATOR_UTILS_EXPORT Theme *creatorTheme(); +QTCREATOR_UTILS_EXPORT void setCreatorTheme(Theme *theme); + +} // namespace Utils + +#endif // THEME_H diff --git a/src/libs/utils/theme/theme_p.cpp b/src/libs/utils/theme/theme_p.cpp new file mode 100644 index 0000000000..05c7916722 --- /dev/null +++ b/src/libs/utils/theme/theme_p.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "theme_p.h" + +#include + +namespace Utils { + +ThemePrivate::ThemePrivate() + : widgetStyle(Theme::StyleDefault) +{ + const QMetaObject &m = Theme::staticMetaObject; + colors.resize (m.enumerator(m.indexOfEnumerator("ColorRole")).keyCount()); + gradientStops.resize (m.enumerator(m.indexOfEnumerator("GradientRole")).keyCount()); + iconOverlays.resize (m.enumerator(m.indexOfEnumerator("MimeType")).keyCount()); + flags.resize (m.enumerator(m.indexOfEnumerator("Flag")).keyCount()); +} + +} // namespace Utils diff --git a/src/libs/utils/theme/theme_p.h b/src/libs/utils/theme/theme_p.h new file mode 100644 index 0000000000..d507becafc --- /dev/null +++ b/src/libs/utils/theme/theme_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEME_P_H +#define THEME_P_H + +#include "theme.h" +#include "../utils_global.h" + +#include +#include + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT ThemePrivate +{ +public: + ThemePrivate(); + + QString fileName; + QString name; + QVector > colors; + QVector iconOverlays; + QVector gradientStops; + QVector flags; + Theme::WidgetStyle widgetStyle; + QMap palette; +}; + +} // namespace Utils + +#endif // THEME_P_H diff --git a/src/libs/utils/theme/welcometheme.cpp b/src/libs/utils/theme/welcometheme.cpp new file mode 100644 index 0000000000..e8581a7d7d --- /dev/null +++ b/src/libs/utils/theme/welcometheme.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "welcometheme.h" + +#include "theme.h" + +using namespace Utils; + +#define IMPL_COLOR_PROPERTY(propName, enumName) \ + QColor WelcomeTheme::propName () const { \ + return creatorTheme()->color(Theme::enumName); \ + } + +#define GRADIENT(x) \ + QGradient grad; \ + grad.setStops(creatorTheme()->gradient(Theme::x)); \ + return grad; + +WelcomeTheme::WelcomeTheme(QObject *parent) + : QObject(parent) +{ +} + +QString WelcomeTheme::widgetStyle() const +{ + switch (creatorTheme()->widgetStyle()) { + case Theme::StyleDefault: + return QLatin1String("default"); + case Theme::StyleFlat: + return QLatin1String("flat"); + } + return QString::null; +} + +void WelcomeTheme::notifyThemeChanged() +{ + emit themeChanged(); +} + +IMPL_COLOR_PROPERTY(textColorNormal , Welcome_TextColorNormal ) +IMPL_COLOR_PROPERTY(textColorHeading , Welcome_TextColorHeading ) +IMPL_COLOR_PROPERTY(backgroundColorNormal , Welcome_BackgroundColorNormal ) +IMPL_COLOR_PROPERTY(dividerColor , Welcome_DividerColor ) +IMPL_COLOR_PROPERTY(button_BorderColor , Welcome_Button_BorderColor ) +IMPL_COLOR_PROPERTY(button_TextColorNormal , Welcome_Button_TextColorNormal ) +IMPL_COLOR_PROPERTY(button_TextColorPressed, Welcome_Button_TextColorPressed) +IMPL_COLOR_PROPERTY(link_TextColorNormal , Welcome_Link_TextColorNormal ) +IMPL_COLOR_PROPERTY(link_TextColorActive , Welcome_Link_TextColorActive ) +IMPL_COLOR_PROPERTY(link_BackgroundColor , Welcome_Link_BackgroundColor ) +IMPL_COLOR_PROPERTY(caption_TextColorNormal, Welcome_Caption_TextColorNormal) +IMPL_COLOR_PROPERTY(sideBar_BackgroundColor, Welcome_SideBar_BackgroundColor) +IMPL_COLOR_PROPERTY(projectItem_TextColorFilepath, Welcome_ProjectItem_TextColorFilepath) +IMPL_COLOR_PROPERTY(projectItem_BackgroundColorHover, Welcome_ProjectItem_BackgroundColorHover) +IMPL_COLOR_PROPERTY(sessionItem_BackgroundColorNormal, Welcome_SessionItem_BackgroundColorNormal) +IMPL_COLOR_PROPERTY(sessionItemExpanded_BackgroundColor, Welcome_SessionItemExpanded_BackgroundColor) +IMPL_COLOR_PROPERTY(sessionItem_BackgroundColorHover, Welcome_SessionItem_BackgroundColorHover) + +QGradient WelcomeTheme::button_GradientNormal () const { GRADIENT(Welcome_Button_GradientNormal); } +QGradient WelcomeTheme::button_GradientPressed () const { GRADIENT(Welcome_Button_GradientPressed); } diff --git a/src/libs/utils/theme/welcometheme.h b/src/libs/utils/theme/welcometheme.h new file mode 100644 index 0000000000..ec9f36c844 --- /dev/null +++ b/src/libs/utils/theme/welcometheme.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef WELCOMETHEME_H +#define WELCOMETHEME_H + +#include "../utils_global.h" + +#include + +#define DECLARE_COLOR_PROPERTY(propName) \ + Q_PROPERTY(QColor propName READ propName NOTIFY themeChanged) \ + QColor propName () const; + +/*! + * Expose theme properties to QML (for welcomeplugin) + */ +class QTCREATOR_UTILS_EXPORT WelcomeTheme : public QObject +{ + Q_OBJECT + +public: + WelcomeTheme(QObject *parent); + + DECLARE_COLOR_PROPERTY(textColorNormal) + DECLARE_COLOR_PROPERTY(textColorHeading) + DECLARE_COLOR_PROPERTY(backgroundColorNormal) + DECLARE_COLOR_PROPERTY(dividerColor) + DECLARE_COLOR_PROPERTY(button_BorderColor) + DECLARE_COLOR_PROPERTY(button_TextColorNormal) + DECLARE_COLOR_PROPERTY(button_TextColorPressed) + DECLARE_COLOR_PROPERTY(link_TextColorNormal) + DECLARE_COLOR_PROPERTY(link_TextColorActive) + DECLARE_COLOR_PROPERTY(link_BackgroundColor) + DECLARE_COLOR_PROPERTY(sideBar_BackgroundColor) + DECLARE_COLOR_PROPERTY(caption_TextColorNormal) + DECLARE_COLOR_PROPERTY(projectItem_TextColorFilepath) + DECLARE_COLOR_PROPERTY(projectItem_BackgroundColorHover) + DECLARE_COLOR_PROPERTY(sessionItem_BackgroundColorNormal) + DECLARE_COLOR_PROPERTY(sessionItemExpanded_BackgroundColor) + DECLARE_COLOR_PROPERTY(sessionItem_BackgroundColorHover) + + Q_PROPERTY(QGradient button_GradientNormal READ button_GradientNormal NOTIFY themeChanged) + Q_PROPERTY(QGradient button_GradientPressed READ button_GradientPressed NOTIFY themeChanged) + + Q_PROPERTY(QString widgetStyle READ widgetStyle CONSTANT) + + QString widgetStyle() const; + + QGradient button_GradientNormal () const; + QGradient button_GradientPressed () const; + +public slots: + void notifyThemeChanged(); + +signals: + void themeChanged(); +}; + +#endif // WELCOMETHEME_H diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 8b0257ba6e..087bcba89e 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -92,7 +92,10 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/treemodel.cpp \ $$PWD/treeviewcombobox.cpp \ $$PWD/proxycredentialsdialog.cpp \ - $$PWD/macroexpander.cpp + $$PWD/macroexpander.cpp \ + $$PWD/theme/theme.cpp \ + $$PWD/theme/theme_p.cpp \ + $$PWD/theme/welcometheme.cpp win32:SOURCES += $$PWD/consoleprocess_win.cpp else:SOURCES += $$PWD/consoleprocess_unix.cpp @@ -189,7 +192,10 @@ HEADERS += \ $$PWD/algorithm.h \ $$PWD/QtConcurrentTools \ $$PWD/proxycredentialsdialog.h \ - $$PWD/macroexpander.h + $$PWD/macroexpander.h \ + $$PWD/theme/theme.h \ + $$PWD/theme/theme_p.h \ + $$PWD/theme/welcometheme.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index a665cfc3ba..a5a92af87a 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -204,6 +204,19 @@ QtcLibrary { "images/triangle_vert.png", ] + Group { + name: "Theme" + prefix: "theme/" + files: [ + "theme.cpp", + "theme.h", + "theme_p.cpp", + "theme_p.h", + "welcometheme.cpp", + "welcometheme.h", + ] + } + Group { name: "Tooltip" prefix: "tooltip/" diff --git a/src/plugins/coreplugin/Core.json.in b/src/plugins/coreplugin/Core.json.in index 25d8507502..8e792dfa28 100644 --- a/src/plugins/coreplugin/Core.json.in +++ b/src/plugins/coreplugin/Core.json.in @@ -22,6 +22,11 @@ \"Parameter\" : \"color\", \"Description\" : \"Override selected UI color\" }, + { + \"Name\" : \"-theme\", + \"Parameter\" : \"default|dark\", + \"Description\" : \"Choose a built-in theme or pass a .creatortheme file\" + }, { \"Name\" : \"-presentationMode\", \"Description\" : \"Enable presentation mode with pop-ups for key combos\" diff --git a/src/plugins/coreplugin/core.qrc b/src/plugins/coreplugin/core.qrc index db87f15a30..35ae643470 100644 --- a/src/plugins/coreplugin/core.qrc +++ b/src/plugins/coreplugin/core.qrc @@ -26,6 +26,8 @@ images/locked@2x.png images/magnifier.png images/magnifier@2x.png + images/dark_magnifier.png + images/dark_magnifier@2x.png images/minus.png images/next.png images/panel_button.png @@ -103,5 +105,7 @@ images/warning@2x.png images/info.png images/info@2x.png + images/dark_fileicon.png + images/dark_foldericon.png diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index b2e716097f..d4bf58227a 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -101,6 +101,7 @@ const char OPTIONS[] = "QtCreator.Options"; const char TOGGLE_SIDEBAR[] = "QtCreator.ToggleSidebar"; const char TOGGLE_MODE_SELECTOR[] = "QtCreator.ToggleModeSelector"; const char TOGGLE_FULLSCREEN[] = "QtCreator.ToggleFullScreen"; +const char THEMEOPTIONS[] = "QtCreator.ThemeOptions"; const char TR_SHOW_SIDEBAR[] = QT_TRANSLATE_NOOP("Core", "Show Sidebar"); const char TR_HIDE_SIDEBAR[] = QT_TRANSLATE_NOOP("Core", "Hide Sidebar"); @@ -241,6 +242,8 @@ const char SETTINGS_ID_MIMETYPES[] = "D.MimeTypes"; const char SETTINGS_DEFAULTTEXTENCODING[] = "General/DefaultFileEncoding"; +const char SETTINGS_THEME[] = "Core/CreatorTheme"; + const char ALL_FILES_FILTER[] = QT_TRANSLATE_NOOP("Core", "All Files (*)"); const char TR_CLEAR_MENU[] = QT_TRANSLATE_NOOP("Core", "Clear Menu"); diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index a63d533e05..63739045ef 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -42,23 +42,30 @@ #include #include #include +#include #include #include +#include +#include #include #include #include +#include using namespace Core; using namespace Core::Internal; - -CorePlugin::CorePlugin() : m_editMode(0), m_designMode(0) +using namespace Utils; + +CorePlugin::CorePlugin() + : m_mainWindow(0) + , m_editMode(0) + , m_designMode(0) + , m_findPlugin(0) + , m_locator(0) { qRegisterMetaType(); - m_mainWindow = new MainWindow; - m_findPlugin = new FindPlugin; - m_locator = new Locator; } CorePlugin::~CorePlugin() @@ -84,15 +91,55 @@ CorePlugin::~CorePlugin() void CorePlugin::parseArguments(const QStringList &arguments) { + QString themeName = QLatin1String("default"); + QColor overrideColor; + bool overrideTheme = false; + for (int i = 0; i < arguments.size(); ++i) { if (arguments.at(i) == QLatin1String("-color")) { const QString colorcode(arguments.at(i + 1)); - m_mainWindow->setOverrideColor(QColor(colorcode)); + overrideColor = QColor(colorcode); i++; // skip the argument } if (arguments.at(i) == QLatin1String("-presentationMode")) ActionManager::setPresentationModeEnabled(true); + if (arguments.at(i) == QLatin1String("-theme")) { + overrideTheme = true; + themeName = arguments.at(i + 1); + i++; + } } + + QSettings *settings = Core::ICore::settings(); + QString themeURI = settings->value(QLatin1String(Core::Constants::SETTINGS_THEME)).toString(); + + if (!QFileInfo::exists(themeURI) || overrideTheme) { + const QString builtInTheme = QStringLiteral("%1/themes/%2.creatortheme") + .arg(ICore::resourcePath()).arg(themeName); + if (QFile::exists(builtInTheme)) { + themeURI = builtInTheme; + } else if (themeName.endsWith(QLatin1String(".creatortheme"))) { + themeURI = themeName; + } else { // TODO: Fallback to default theme + qCritical("%s", qPrintable(QCoreApplication::translate("Application", "No valid theme '%1'") + .arg(themeName))); + } + } + + QSettings themeSettings(themeURI, QSettings::IniFormat); + Theme *theme = new Theme(qApp); + theme->readSettings(themeSettings); + setCreatorTheme(theme); + qApp->setPalette(creatorTheme()->palette(qApp->palette())); + + // defer creation of these widgets until here, + // because they need a valid theme set + m_mainWindow = new MainWindow; + m_findPlugin = new FindPlugin; + m_locator = new Locator; + + if (overrideColor.isValid()) + m_mainWindow->setOverrideColor(overrideColor); } bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index e9f5ef867b..e822521e6a 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -16,6 +16,7 @@ SOURCES += corejsextensions.cpp \ fancyactionbar.cpp \ fancytabwidget.cpp \ generalsettings.cpp \ + themesettings.cpp \ id.cpp \ icontext.cpp \ jsexpander.cpp \ @@ -101,7 +102,15 @@ SOURCES += corejsextensions.cpp \ ioutputpane.cpp \ patchtool.cpp \ windowsupport.cpp \ - opendocumentstreeview.cpp + opendocumentstreeview.cpp \ + themeeditor/themecolors.cpp \ + themeeditor/themecolorstableview.cpp \ + themeeditor/colorvariable.cpp \ + themeeditor/themeeditorwidget.cpp \ + themeeditor/colorrole.cpp \ + themeeditor/themesettingstablemodel.cpp \ + themeeditor/sectionedtablemodel.cpp \ + themeeditor/themesettingsitemdelegate.cpp HEADERS += corejsextensions.h \ mainwindow.h \ @@ -111,6 +120,7 @@ HEADERS += corejsextensions.h \ fancyactionbar.h \ fancytabwidget.h \ generalsettings.h \ + themesettings.h \ id.h \ jsexpander.h \ messagemanager.h \ @@ -206,18 +216,28 @@ HEADERS += corejsextensions.h \ dialogs/addtovcsdialog.h \ patchtool.h \ windowsupport.h \ - opendocumentstreeview.h + opendocumentstreeview.h \ + themeeditor/themecolors.h \ + themeeditor/themecolorstableview.h \ + themeeditor/colorvariable.h \ + themeeditor/themeeditorwidget.h \ + themeeditor/colorrole.h \ + themeeditor/themesettingstablemodel.h \ + themeeditor/sectionedtablemodel.h \ + themeeditor/themesettingsitemdelegate.h \ FORMS += dialogs/newdialog.ui \ dialogs/saveitemsdialog.ui \ dialogs/readonlyfilesdialog.ui \ dialogs/openwithdialog.ui \ generalsettings.ui \ + themesettings.ui \ dialogs/externaltoolconfig.ui \ mimetypesettingspage.ui \ mimetypemagicdialog.ui \ removefiledialog.ui \ - dialogs/addtovcsdialog.ui + dialogs/addtovcsdialog.ui \ + themeeditor/themeeditorwidget.ui RESOURCES += core.qrc \ fancyactionbar.qrc diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 33cf4ff513..0e3773bfc7 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -285,6 +285,30 @@ QtcPlugin { ] } + Group { + name: "ThemeEditor" + prefix: "themeeditor/" + files: [ + "colorrole.cpp", + "colorrole.h", + "colorvariable.cpp", + "colorvariable.h", + "sectionedtablemodel.cpp", + "sectionedtablemodel.h", + "themecolors.cpp", + "themecolors.h", + "themecolorstableview.cpp", + "themecolorstableview.h", + "themeeditorwidget.cpp", + "themeeditorwidget.h", + "themeeditorwidget.ui", + "themesettingsitemdelegate.cpp", + "themesettingsitemdelegate.h", + "themesettingstablemodel.cpp", + "themesettingstablemodel.h", + ] + } + Export { Depends { name: "Aggregation" } Depends { name: "Utils" } diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp index 01df7f5657..044d72cdfa 100644 --- a/src/plugins/coreplugin/editormanager/editorview.cpp +++ b/src/plugins/coreplugin/editormanager/editorview.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -56,7 +57,7 @@ using namespace Core; using namespace Core::Internal; - +using namespace Utils; // ================EditorView==================== @@ -244,11 +245,17 @@ void EditorView::paintEvent(QPaintEvent *) // Discreet indication where an editor would be if there is none QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - painter.setPen(Qt::NoPen); - painter.setBrush(palette().color(QPalette::Background).darker(107)); - const int r = 3; - painter.drawRoundedRect(m_container->geometry().adjusted(r , r, -r, -r), r * 2, r * 2); + + QRect rect = m_container->geometry(); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setPen(Qt::NoPen); + painter.setBrush(creatorTheme()->color(Theme::EditorPlaceholderColor)); + const int r = 3; + painter.drawRoundedRect(rect.adjusted(r , r, -r, -r), r * 2, r * 2); + } else { + painter.fillRect(rect, creatorTheme()->color(Theme::EditorPlaceholderColor)); + } } void EditorView::mousePressEvent(QMouseEvent *e) diff --git a/src/plugins/coreplugin/fancyactionbar.cpp b/src/plugins/coreplugin/fancyactionbar.cpp index 926fa088c4..a411ef7d97 100644 --- a/src/plugins/coreplugin/fancyactionbar.cpp +++ b/src/plugins/coreplugin/fancyactionbar.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -145,30 +146,41 @@ void FancyToolButton::paintEvent(QPaintEvent *event) if (!Utils::HostOsInfo::isMacHost() // Mac UIs usually don't hover && m_fader > 0 && isEnabled() && !isDown() && !isChecked()) { painter.save(); - int fader = int(40 * m_fader); - QLinearGradient grad(rect().topLeft(), rect().topRight()); - grad.setColorAt(0, Qt::transparent); - grad.setColorAt(0.5, QColor(255, 255, 255, fader)); - grad.setColorAt(1, Qt::transparent); - painter.fillRect(rect(), grad); - painter.setPen(QPen(grad, 1.0)); - painter.drawLine(rect().topLeft(), rect().topRight()); - painter.drawLine(rect().bottomLeft(), rect().bottomRight()); + const QColor hoverColor = creatorTheme()->color(Theme::FancyToolButtonHoverColor); + QColor fadedHoverColor = hoverColor; + fadedHoverColor.setAlpha(int(m_fader * hoverColor.alpha())); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + QLinearGradient grad(rect().topLeft(), rect().topRight()); + grad.setColorAt(0, Qt::transparent); + grad.setColorAt(0.5, fadedHoverColor); + grad.setColorAt(1, Qt::transparent); + painter.fillRect(rect(), grad); + painter.setPen(QPen(grad, 1.0)); + painter.drawLine(rect().topLeft(), rect().topRight()); + painter.drawLine(rect().bottomLeft(), rect().bottomRight()); + } else { + painter.fillRect(rect(), fadedHoverColor); + } painter.restore(); } else if (isDown() || isChecked()) { painter.save(); - QLinearGradient grad(rect().topLeft(), rect().topRight()); - grad.setColorAt(0, Qt::transparent); - grad.setColorAt(0.5, QColor(0, 0, 0, 50)); - grad.setColorAt(1, Qt::transparent); - painter.fillRect(rect(), grad); - painter.setPen(QPen(grad, 1.0)); - painter.drawLine(rect().topLeft(), rect().topRight()); - painter.drawLine(rect().topLeft(), rect().topRight()); - painter.drawLine(rect().topLeft() + QPoint(0,1), rect().topRight() + QPoint(0,1)); - painter.drawLine(rect().bottomLeft(), rect().bottomRight()); - painter.drawLine(rect().bottomLeft(), rect().bottomRight()); - painter.drawLine(rect().topLeft() - QPoint(0,1), rect().topRight() - QPoint(0,1)); + const QColor selectedColor = creatorTheme()->color(Theme::FancyToolButtonSelectedColor); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + QLinearGradient grad(rect().topLeft(), rect().topRight()); + grad.setColorAt(0, Qt::transparent); + grad.setColorAt(0.5, selectedColor); + grad.setColorAt(1, Qt::transparent); + painter.fillRect(rect(), grad); + painter.setPen(QPen(grad, 1.0)); + painter.drawLine(rect().topLeft(), rect().topRight()); + painter.drawLine(rect().topLeft(), rect().topRight()); + painter.drawLine(rect().topLeft() + QPoint(0,1), rect().topRight() + QPoint(0,1)); + painter.drawLine(rect().bottomLeft(), rect().bottomRight()); + painter.drawLine(rect().bottomLeft(), rect().bottomRight()); + painter.drawLine(rect().topLeft() - QPoint(0,1), rect().topRight() - QPoint(0,1)); + } else { + painter.fillRect(rect(), selectedColor); + } painter.restore(); } @@ -261,7 +273,13 @@ void FancyToolButton::paintEvent(QPaintEvent *event) void FancyActionBar::paintEvent(QPaintEvent *event) { QPainter painter(this); - Q_UNUSED(event) + + if (creatorTheme()->widgetStyle () == Theme::StyleFlat) { + // this paints the background of the bottom portion of the + // left tab bar + painter.fillRect(event->rect(), creatorTheme()->color(Theme::FancyTabBarBackgroundColor)); + } + QColor light = Utils::StyleHelper::sidebarHighlight(); QColor dark = Utils::StyleHelper::sidebarShadow(); painter.setPen(dark); diff --git a/src/plugins/coreplugin/fancytabwidget.cpp b/src/plugins/coreplugin/fancytabwidget.cpp index ebf73bf69a..b4095138fd 100644 --- a/src/plugins/coreplugin/fancytabwidget.cpp +++ b/src/plugins/coreplugin/fancytabwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -47,6 +48,7 @@ using namespace Core; using namespace Internal; +using namespace Utils; const int FancyTabBar::m_rounding = 22; const int FancyTabBar::m_textPadding = 4; @@ -115,8 +117,12 @@ QSize FancyTabBar::tabSizeHint(bool minimum) const void FancyTabBar::paintEvent(QPaintEvent *event) { - Q_UNUSED(event) QPainter p(this); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + // draw background of upper part of left tab widget + // (Welcome, ... Help) + p.fillRect (event->rect(), creatorTheme()->color(Theme::FancyTabBarBackgroundColor)); + } for (int i = 0; i < count(); ++i) if (i != currentIndex()) @@ -245,29 +251,35 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const bool enabled = isTabEnabled(tabIndex); if (selected) { - //background - painter->save(); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, QColor(255, 255, 255, 140)); - grad.setColorAt(1, QColor(255, 255, 255, 210)); - painter->fillRect(rect.adjusted(0, 0, 0, -1), grad); - painter->restore(); - - //shadows - painter->setPen(QColor(0, 0, 0, 110)); - painter->drawLine(rect.topLeft() + QPoint(1,-1), rect.topRight() - QPoint(0,1)); - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - painter->setPen(QColor(0, 0, 0, 40)); - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - - //highlights - painter->setPen(QColor(255, 255, 255, 50)); - painter->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0,2)); - painter->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0,1)); - painter->setPen(QColor(255, 255, 255, 40)); - painter->drawLine(rect.topLeft() + QPoint(0, 0), rect.topRight()); - painter->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1)); - painter->drawLine(rect.bottomLeft() + QPoint(0,-1), rect.bottomRight()-QPoint(0,1)); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + // background color of a fancy tab that is active + painter->fillRect(rect.adjusted(0, 0, 0, -1), + creatorTheme()->color(Theme::BackgroundColorSelected)); + } else { + //background + painter->save(); + QLinearGradient grad(rect.topLeft(), rect.topRight()); + grad.setColorAt(0, QColor(255, 255, 255, 140)); + grad.setColorAt(1, QColor(255, 255, 255, 210)); + painter->fillRect(rect.adjusted(0, 0, 0, -1), grad); + painter->restore(); + + //shadows + painter->setPen(QColor(0, 0, 0, 110)); + painter->drawLine(rect.topLeft() + QPoint(1,-1), rect.topRight() - QPoint(0,1)); + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + painter->setPen(QColor(0, 0, 0, 40)); + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + + //highlights + painter->setPen(QColor(255, 255, 255, 50)); + painter->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0,2)); + painter->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0,1)); + painter->setPen(QColor(255, 255, 255, 40)); + painter->drawLine(rect.topLeft() + QPoint(0, 0), rect.topRight()); + painter->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1)); + painter->drawLine(rect.bottomLeft() + QPoint(0,-1), rect.bottomRight()-QPoint(0,1)); + } } QString tabText(this->tabText(tabIndex)); @@ -281,23 +293,24 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const painter->setFont(boldFont); painter->setPen(selected ? QColor(255, 255, 255, 160) : QColor(0, 0, 0, 110)); const int textFlags = Qt::AlignCenter | (drawIcon ? Qt::AlignBottom : Qt::AlignVCenter) | Qt::TextWordWrap; - if (enabled) { - painter->drawText(tabTextRect, textFlags, tabText); - painter->setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); - } else { - painter->setPen(selected ? Utils::StyleHelper::panelTextColor() : QColor(255, 255, 255, 120)); - } + if (!Utils::HostOsInfo::isMacHost() && !selected && enabled) { painter->save(); int fader = int(m_tabs[tabIndex]->fader()); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, Qt::transparent); - grad.setColorAt(0.5, QColor(255, 255, 255, fader)); - grad.setColorAt(1, Qt::transparent); - painter->fillRect(rect, grad); - painter->setPen(QPen(grad, 1.0)); - painter->drawLine(rect.topLeft(), rect.topRight()); - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + QColor c = creatorTheme()->color(Theme::BackgroundColorHover); + c.setAlpha(int(255 * fader/40.0)); // FIXME: hardcoded end value 40 + painter->fillRect(rect, c); + } else { + QLinearGradient grad(rect.topLeft(), rect.topRight()); + grad.setColorAt(0, Qt::transparent); + grad.setColorAt(0.5, QColor(255, 255, 255, fader)); + grad.setColorAt(1, Qt::transparent); + painter->fillRect(rect, grad); + painter->setPen(QPen(grad, 1.0)); + painter->drawLine(rect.topLeft(), rect.topRight()); + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + } painter->restore(); } @@ -310,8 +323,19 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const Utils::StyleHelper::drawIconWithShadow(tabIcon(tabIndex), tabIconRect, painter, enabled ? QIcon::Normal : QIcon::Disabled); } + painter->setOpacity(1.0); //FIXME: was 0.7 before? + if (enabled) { + painter->setPen(selected + ? creatorTheme()->color(Theme::FancyTabWidgetEnabledSelectedTextColor) + : creatorTheme()->color(Theme::FancyTabWidgetEnabledUnselectedTextColor)); + } else { + painter->setPen(selected + ? creatorTheme()->color(Theme::FancyTabWidgetDisabledSelectedTextColor) + : creatorTheme()->color(Theme::FancyTabWidgetDisabledUnselectedTextColor)); + } painter->translate(0, -1); painter->drawText(tabTextRect, textFlags, tabText); + painter->restore(); } diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp index 683af3b374..a484699ac9 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.cpp +++ b/src/plugins/coreplugin/find/searchresultwidget.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -52,6 +53,8 @@ static const int SEARCHRESULT_WARNING_LIMIT = 200000; static const char SIZE_WARNING_ID[] = "sizeWarningLabel"; +using namespace Utils; + namespace Core { namespace Internal { @@ -93,11 +96,13 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : QFrame *topWidget = new QFrame; QPalette pal; - pal.setColor(QPalette::Window, QColor(255, 255, 225)); - pal.setColor(QPalette::WindowText, Qt::black); + pal.setColor(QPalette::Window, creatorTheme()->color(Theme::SearchResultWidgetBackgroundColor)); + pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::SearchResultWidgetTextColor)); topWidget->setPalette(pal); - topWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); - topWidget->setLineWidth(1); + if (creatorTheme()->flag(Theme::DrawSearchResultWidgetFrame)) { + topWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); + topWidget->setLineWidth(1); + } topWidget->setAutoFillBackground(true); QHBoxLayout *topLayout = new QHBoxLayout(topWidget); topLayout->setMargin(2); @@ -105,10 +110,12 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : layout->addWidget(topWidget); m_messageWidget = new QFrame; - pal.setColor(QPalette::WindowText, Qt::red); + pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::CanceledSearchTextColor)); m_messageWidget->setPalette(pal); - m_messageWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); - m_messageWidget->setLineWidth(1); + if (creatorTheme()->flag(Theme::DrawSearchResultWidgetFrame)) { + m_messageWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); + m_messageWidget->setLineWidth(1); + } m_messageWidget->setAutoFillBackground(true); QHBoxLayout *messageLayout = new QHBoxLayout(m_messageWidget); messageLayout->setMargin(2); diff --git a/src/plugins/coreplugin/images/dark_fileicon.png b/src/plugins/coreplugin/images/dark_fileicon.png new file mode 100644 index 0000000000..3581d3331f Binary files /dev/null and b/src/plugins/coreplugin/images/dark_fileicon.png differ diff --git a/src/plugins/coreplugin/images/dark_foldericon.png b/src/plugins/coreplugin/images/dark_foldericon.png new file mode 100644 index 0000000000..dc7a50431e Binary files /dev/null and b/src/plugins/coreplugin/images/dark_foldericon.png differ diff --git a/src/plugins/coreplugin/images/dark_magnifier.png b/src/plugins/coreplugin/images/dark_magnifier.png new file mode 100644 index 0000000000..322a542a0e Binary files /dev/null and b/src/plugins/coreplugin/images/dark_magnifier.png differ diff --git a/src/plugins/coreplugin/images/dark_magnifier@2x.png b/src/plugins/coreplugin/images/dark_magnifier@2x.png new file mode 100644 index 0000000000..ed82c37dd0 Binary files /dev/null and b/src/plugins/coreplugin/images/dark_magnifier@2x.png differ diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 0cfebe0951..dbff065a40 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -37,6 +37,7 @@ #include "fancytabwidget.h" #include "documentmanager.h" #include "generalsettings.h" +#include "themesettings.h" #include "helpmanager.h" #include "idocumentfactory.h" #include "messagemanager.h" @@ -78,6 +79,7 @@ #include #include #include +#include #include #include @@ -130,6 +132,7 @@ MainWindow::MainWindow() : m_rightPaneWidget(0), m_versionDialog(0), m_generalSettings(new GeneralSettings), + m_themeSettings(new ThemeSettings), m_shortcutSettings(new ShortcutSettings), m_toolSettings(new ToolSettings), m_mimeTypeSettings(new MimeTypeSettings), @@ -252,6 +255,7 @@ MainWindow::~MainWindow() ExtensionSystem::PluginManager::removeObject(m_shortcutSettings); ExtensionSystem::PluginManager::removeObject(m_generalSettings); + ExtensionSystem::PluginManager::removeObject(m_themeSettings); ExtensionSystem::PluginManager::removeObject(m_toolSettings); ExtensionSystem::PluginManager::removeObject(m_mimeTypeSettings); ExtensionSystem::PluginManager::removeObject(m_systemEditor); @@ -263,6 +267,8 @@ MainWindow::~MainWindow() m_shortcutSettings = 0; delete m_generalSettings; m_generalSettings = 0; + delete m_themeSettings; + m_themeSettings = 0; delete m_toolSettings; m_toolSettings = 0; delete m_mimeTypeSettings; @@ -320,6 +326,7 @@ bool MainWindow::init(QString *errorMessage) m_progressManager->init(); // needs the status bar manager ExtensionSystem::PluginManager::addObject(m_generalSettings); + ExtensionSystem::PluginManager::addObject(m_themeSettings); ExtensionSystem::PluginManager::addObject(m_shortcutSettings); ExtensionSystem::PluginManager::addObject(m_toolSettings); ExtensionSystem::PluginManager::addObject(m_mimeTypeSettings); @@ -628,6 +635,7 @@ void MainWindow::registerDefaultActions() // Options Action mtools->appendGroup(Constants::G_TOOLS_OPTIONS); mtools->addSeparator(globalContext, Constants::G_TOOLS_OPTIONS); + m_optionsAction = new QAction(tr("&Options..."), this); cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS, globalContext); if (UseMacShortcuts) { diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index 267ca3413a..da6ec54016 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -72,6 +72,7 @@ namespace Internal { class ActionManagerPrivate; class FancyTabWidget; class GeneralSettings; +class ThemeSettings; class ProgressManagerPrivate; class ShortcutSettings; class ToolSettings; @@ -191,6 +192,7 @@ private: QMap m_contextWidgets; GeneralSettings *m_generalSettings; + ThemeSettings *m_themeSettings; ShortcutSettings *m_shortcutSettings; ToolSettings *m_toolSettings; MimeTypeSettings *m_mimeTypeSettings; @@ -206,6 +208,7 @@ private: QAction *m_optionsAction; QAction *m_toggleSideBarAction; QAction *m_toggleModeSelectorAction; + QAction *m_themeAction; QToolButton *m_toggleSideBarButton; QColor m_overrideColor; diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 889e18d265..0722e31110 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -53,6 +54,8 @@ #include #include +using namespace Utils; + // We define a currently unused state for indicating animations const QStyle::State State_Animating = QStyle::State(0x00000040); @@ -242,7 +245,8 @@ void ManhattanStyle::unpolish(QApplication *app) QPalette panelPalette(const QPalette &oldPalette, bool lightColored = false) { - QColor color = Utils::StyleHelper::panelTextColor(lightColored); + Q_UNUSED(lightColored); + QColor color = creatorTheme()->color(Theme::PanelTextColor); QPalette pal = oldPalette; pal.setBrush(QPalette::All, QPalette::WindowText, color); pal.setBrush(QPalette::All, QPalette::ButtonText, color); @@ -310,17 +314,12 @@ void ManhattanStyle::polish(QPalette &pal) QProxyStyle::polish(pal); } -QIcon ManhattanStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +QIcon ManhattanStyle::standardIcon(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const { - QIcon icon; - switch (standardIcon) { - case QStyle::SP_TitleBarCloseButton: - case QStyle::SP_ToolBarHorizontalExtensionButton: - return QIcon(standardPixmap(standardIcon, option, widget)); - default: - icon = baseStyle()->standardIcon(standardIcon, option, widget); - } - return icon; + QIcon ico = creatorTheme()->standardIcon(standardPixmap, opt, widget); + if (!ico.isNull()) + return ico; + return QProxyStyle::standardIcon(standardPixmap, opt, widget); } QPixmap ManhattanStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, @@ -377,8 +376,13 @@ int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { - if (!panelWidget(widget)) + if (!panelWidget(widget)) { + if (creatorTheme()->flag(Theme::DrawIndicatorBranch) && element == PE_IndicatorBranch) { + creatorTheme()->drawIndicatorBranch(painter, option->rect, option->state); + return; + } return QProxyStyle::drawPrimitive(element, option, painter, widget); + } bool animating = (option->state & State_Animating); int state = option->state; @@ -437,7 +441,7 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption switch (element) { case PE_IndicatorDockWidgetResizeHandle: - painter->fillRect(option->rect, Utils::StyleHelper::borderColor()); + painter->fillRect(option->rect, creatorTheme()->color(Theme::DockWidgetResizeHandleColor)); break; case PE_FrameDockWidget: QCommonStyle::drawPrimitive(element, option, painter, widget); @@ -491,8 +495,7 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption QColor highlight(255, 255, 255, 30); painter->setPen(highlight); } else if (option->state & State_Enabled && option->state & State_MouseOver) { - QColor lighter(255, 255, 255, 37); - painter->fillRect(rect, lighter); + painter->fillRect(rect, creatorTheme()->color(Theme::PanelButtonToolBackgroundColorHover)); } else if (widget && widget->property("highlightWidget").toBool()) { QColor shade(0, 0, 0, 128); painter->fillRect(rect, shade); @@ -513,15 +516,19 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption case PE_PanelStatusBar: { - painter->save(); - QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect); - painter->fillRect(rect, grad); - painter->setPen(QColor(255, 255, 255, 60)); - painter->drawLine(rect.topLeft() + QPoint(0,1), - rect.topRight()+ QPoint(0,1)); - painter->setPen(Utils::StyleHelper::borderColor().darker(110)); - painter->drawLine(rect.topLeft(), rect.topRight()); - painter->restore(); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + painter->save(); + QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect); + painter->fillRect(rect, grad); + painter->setPen(QColor(255, 255, 255, 60)); + painter->drawLine(rect.topLeft() + QPoint(0,1), + rect.topRight()+ QPoint(0,1)); + painter->setPen(Utils::StyleHelper::borderColor().darker(110)); //TODO: make themable + painter->drawLine(rect.topLeft(), rect.topRight()); + painter->restore(); + } else { + painter->fillRect(rect, creatorTheme()->color(Theme::PanelStatusBarBackgroundColor)); + } } break; @@ -639,13 +646,20 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt painter->save(); if (const QStyleOptionMenuItem *mbi = qstyleoption_cast(option)) { QColor highlightOutline = Utils::StyleHelper::borderColor().lighter(120); - bool act = mbi->state & (State_Sunken | State_Selected); - bool dis = !(mbi->state & State_Enabled); - Utils::StyleHelper::menuGradient(painter, option->rect, option->rect); + const bool act = mbi->state & (State_Sunken | State_Selected); + const bool dis = !(mbi->state & State_Enabled); + + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) + painter->fillRect(option->rect, creatorTheme()->color(Theme::MenuBarItemBackgroundColor)); + else + Utils::StyleHelper::menuGradient(painter, option->rect, option->rect); + QStyleOptionMenuItem item = *mbi; item.rect = mbi->rect; QPalette pal = mbi->palette; - pal.setBrush(QPalette::ButtonText, dis ? Qt::gray : Qt::black); + pal.setBrush(QPalette::ButtonText, dis + ? creatorTheme()->color(Theme::MenuBarItemTextColorDisabled) + : creatorTheme()->color(Theme::MenuBarItemTextColorNormal)); item.palette = pal; QCommonStyle::drawControl(element, &item, painter, widget); @@ -725,13 +739,15 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt } text.prepend(option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, elideWidth)); - if ((option->state & State_Enabled)) { + if (creatorTheme()->flag(Theme::ComboBoxDrawTextShadow) + && (option->state & State_Enabled)) + { painter->setPen(QColor(0, 0, 0, 70)); painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text); - } else { - painter->setOpacity(0.8); } - painter->setPen(Utils::StyleHelper::panelTextColor()); + if (option->state & State_Enabled) + painter->setOpacity(0.8); + painter->setPen(creatorTheme()->color(Theme::ComboBoxTextColor)); painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text); painter->restore(); @@ -775,12 +791,16 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt break; case CE_MenuBarEmptyArea: { - Utils::StyleHelper::menuGradient(painter, option->rect, option->rect); - painter->save(); - painter->setPen(Utils::StyleHelper::borderColor()); - painter->drawLine(option->rect.bottomLeft() + QPointF(0.5, 0.5), - option->rect.bottomRight() + QPointF(0.5, 0.5)); - painter->restore(); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + Utils::StyleHelper::menuGradient(painter, option->rect, option->rect); + painter->save(); + painter->setPen(Utils::StyleHelper::borderColor()); + painter->drawLine(option->rect.bottomLeft() + QPointF(0.5, 0.5), + option->rect.bottomRight() + QPointF(0.5, 0.5)); + painter->restore(); + } else { + painter->fillRect(option->rect, creatorTheme()->color(Theme::MenuBarEmptyAreaBackgroundColor)); + } } break; @@ -799,12 +819,22 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt bool drawLightColored = lightColored(widget); if (horizontal) - Utils::StyleHelper::horizontalGradient(painter, gradientSpan, rect, drawLightColored); - else - Utils::StyleHelper::verticalGradient(painter, gradientSpan, rect, drawLightColored); + { + // draws the background of the 'Type hierarchy', 'Projects' headers + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) + painter->fillRect (rect, creatorTheme()->color(Theme::ToolBarBackgroundColor)); + else + Utils::StyleHelper::horizontalGradient(painter, gradientSpan, rect, drawLightColored); + } else { + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) + painter->fillRect (rect, creatorTheme()->color(Theme::ToolBarBackgroundColor)); + else + Utils::StyleHelper::verticalGradient(painter, gradientSpan, rect, drawLightColored); + } - if (!drawLightColored) + if (!drawLightColored) { painter->setPen(Utils::StyleHelper::borderColor()); + } else painter->setPen(QColor(0x888888)); diff --git a/src/plugins/coreplugin/manhattanstyle.h b/src/plugins/coreplugin/manhattanstyle.h index c4b9571227..e67ea49c09 100644 --- a/src/plugins/coreplugin/manhattanstyle.h +++ b/src/plugins/coreplugin/manhattanstyle.h @@ -56,6 +56,7 @@ public: SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget = 0) const; QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = 0) const; + QIcon standardIcon(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = 0) const; int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const; QRect itemRect(QPainter *p, const QRect &r, int flags, bool enabled, const QPixmap *pixmap, const QString &text, int len = -1) const; QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const; @@ -71,9 +72,6 @@ public: void unpolish(QWidget *widget); void unpolish(QApplication *app); -protected slots: - QIcon standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; - private: void drawButtonSeparator(QPainter *painter, const QRect &rect, bool reverse) const; diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 4b02e079f8..c8a60c0c60 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -65,6 +66,8 @@ #include #include +using namespace Utils; + namespace Core { namespace Internal { @@ -675,24 +678,44 @@ void OutputPaneToggleButton::paintEvent(QPaintEvent*) styleOption.initFrom(this); const bool hovered = !Utils::HostOsInfo::isMacHost() && (styleOption.state & QStyle::State_MouseOver); - QImage const* image = 0; - if (isDown()) - image = &panelButtonPressed; - else if (isChecked()) - image = hovered ? &panelButtonCheckedHover : &panelButtonChecked; - else - image = hovered ? &panelButtonHover : &panelButton; - if (image) - Utils::StyleHelper::drawCornerImage(*image, &p, rect(), numberAreaWidth, buttonBorderWidth, buttonBorderWidth, buttonBorderWidth); + const QImage *image = 0; + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + if (isDown()) + image = &panelButtonPressed; + else if (isChecked()) + image = hovered ? &panelButtonCheckedHover : &panelButtonChecked; + else + image = hovered ? &panelButtonHover : &panelButton; + if (image) + Utils::StyleHelper::drawCornerImage(*image, &p, rect(), numberAreaWidth, buttonBorderWidth, buttonBorderWidth, buttonBorderWidth); + } else { + QColor c; + if (isChecked()) { + c = creatorTheme()->color(hovered ? Theme::BackgroundColorHover + : Theme::BackgroundColorSelected); + } else if (isDown()) { + c = creatorTheme()->color(Theme::BackgroundColorSelected); + } else { + c = creatorTheme()->color(hovered ? Theme::BackgroundColorHover + : Theme::BackgroundColorDark); + } + p.fillRect(rect(), c); + } if (m_flashTimer->state() == QTimeLine::Running) - p.fillRect(rect().adjusted(numberAreaWidth, 1, -1, -1), QBrush(QColor(255, 0, 0, m_flashTimer->currentFrame()))); + { + QColor c = creatorTheme()->color(Theme::OutputPaneButtonFlashColor); + c.setAlpha (m_flashTimer->currentFrame()); + QRect r = (creatorTheme()->widgetStyle() == Theme::StyleFlat) + ? rect() : rect().adjusted(numberAreaWidth, 1, -1, -1); + p.fillRect(r, c); + } p.setFont(font()); - p.setPen(Qt::white); + p.setPen(creatorTheme()->color(Theme::OutputPaneToggleButtonTextColorChecked)); p.drawText((numberAreaWidth - numberWidth) / 2, baseLine, m_number); if (!isChecked()) - p.setPen(Qt::black); + p.setPen(creatorTheme()->color(Theme::OutputPaneToggleButtonTextColorUnchecked)); int leftPart = numberAreaWidth + buttonBorderWidth; int labelWidth = 0; if (!m_badgeNumberLabel.text().isEmpty()) { @@ -751,8 +774,10 @@ QSize OutputPaneManageButton::sizeHint() const void OutputPaneManageButton::paintEvent(QPaintEvent*) { QPainter p(this); - static const QImage button(Utils::StyleHelper::dpiSpecificImageFile(QStringLiteral(":/core/images/panel_manage_button.png"))); - Utils::StyleHelper::drawCornerImage(button, &p, rect(), buttonBorderWidth, buttonBorderWidth, buttonBorderWidth, buttonBorderWidth); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + static const QImage button(Utils::StyleHelper::dpiSpecificImageFile(QStringLiteral(":/core/images/panel_manage_button.png"))); + Utils::StyleHelper::drawCornerImage(button, &p, rect(), buttonBorderWidth, buttonBorderWidth, buttonBorderWidth, buttonBorderWidth); + } QStyle *s = style(); QStyleOption arrowOpt; arrowOpt.initFrom(this); @@ -775,13 +800,15 @@ void BadgeLabel::paint(QPainter *p, int x, int y, bool isChecked) const QRectF rect(QRect(QPoint(x, y), m_size)); p->save(); - p->setBrush(isChecked ? QColor(0xe0, 0xe0, 0xe0) : Qt::darkGray); + p->setBrush(creatorTheme()->color(isChecked? Theme::BadgeLabelBackgroundColorChecked + : Theme::BadgeLabelBackgroundColorUnchecked)); p->setPen(Qt::NoPen); p->setRenderHint(QPainter::Antialiasing, true); p->drawRoundedRect(rect, m_padding, m_padding, Qt::AbsoluteSize); p->setFont(m_font); - p->setPen(isChecked ? QColor(0x60, 0x60, 0x60) : Qt::white); + p->setPen(creatorTheme()->color(isChecked ? Theme::BadgeLabelTextColorChecked + : Theme::BadgeLabelTextColorUnchecked)); p->drawText(rect, Qt::AlignCenter, m_text); p->restore(); diff --git a/src/plugins/coreplugin/progressmanager/futureprogress.cpp b/src/plugins/coreplugin/progressmanager/futureprogress.cpp index fec6376eab..eb61772d89 100644 --- a/src/plugins/coreplugin/progressmanager/futureprogress.cpp +++ b/src/plugins/coreplugin/progressmanager/futureprogress.cpp @@ -32,6 +32,7 @@ #include "progressbar.h" #include +#include #include #include @@ -48,6 +49,8 @@ const int notificationTimeout = 8000; const int shortNotificationTimeout = 1000; +using namespace Utils; + namespace Core { class FutureProgressPrivate : public QObject @@ -295,8 +298,12 @@ void FutureProgress::mousePressEvent(QMouseEvent *event) void FutureProgress::paintEvent(QPaintEvent *) { QPainter p(this); - QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect()); - p.fillRect(rect(), grad); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + p.fillRect(rect(), creatorTheme()->color(Theme::FutureProgressBackgroundColor)); + } else { + QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect()); + p.fillRect(rect(), grad); + } } /*! diff --git a/src/plugins/coreplugin/progressmanager/progressbar.cpp b/src/plugins/coreplugin/progressmanager/progressbar.cpp index 682a4f6e65..d5366e05d3 100644 --- a/src/plugins/coreplugin/progressmanager/progressbar.cpp +++ b/src/plugins/coreplugin/progressmanager/progressbar.cpp @@ -31,6 +31,7 @@ #include "progressbar.h" #include +#include #include #include @@ -40,6 +41,7 @@ using namespace Core; using namespace Core::Internal; +using namespace Utils; static const int PROGRESSBAR_HEIGHT = 13; static const int CANCELBUTTON_WIDTH = 16; @@ -277,7 +279,7 @@ void ProgressBar::paintEvent(QPaintEvent *) p.setPen(QColor(0, 0, 0, 120)); p.drawText(textRect, alignment | Qt::AlignBottom, elidedtitle); p.translate(0, -1); - p.setPen(Utils::StyleHelper::panelTextColor()); + p.setPen(creatorTheme()->color(Theme::ProgressBarTitleColor)); p.drawText(textRect, alignment | Qt::AlignBottom, elidedtitle); p.translate(0, 1); } @@ -287,23 +289,23 @@ void ProgressBar::paintEvent(QPaintEvent *) // draw outer rect const QRect rect(INDENT - 1, titleHeight + separatorHeight + (m_titleVisible ? 4 : 3), size().width() - 2 * INDENT + 1, m_progressHeight); - Utils::StyleHelper::drawCornerImage(bar, &p, rect, 3, 3, 3, 3); + + if (creatorTheme()->flag(Theme::DrawProgressBarSunken)) + Utils::StyleHelper::drawCornerImage(bar, &p, rect, 3, 3, 3, 3); // draw inner rect - QColor c = Utils::StyleHelper::panelTextColor(); - c.setAlpha(180); + QColor c = creatorTheme()->color(Theme::ProgressBarColorNormal); p.setPen(Qt::NoPen); QRectF inner = rect.adjusted(2, 2, -2, -2); inner.adjust(0, 0, qRound((percent - 1) * inner.width()), 0); if (m_error) { - QColor red(255, 60, 0, 210); - c = red; + c = creatorTheme()->color(Theme::ProgressBarColorError); // avoid too small red bar if (inner.width() < 10) inner.adjust(0, 0, 10 - inner.width(), 0); } else if (m_finished) { - c = QColor(90, 170, 60); + c = creatorTheme()->color(Theme::ProgressBarColorFinished); } // Draw line and shadow after the gradient fill @@ -311,13 +313,18 @@ void ProgressBar::paintEvent(QPaintEvent *) p.fillRect(QRect(inner.right(), inner.top(), 2, inner.height()), QColor(0, 0, 0, 20)); p.fillRect(QRect(inner.right(), inner.top(), 1, inner.height()), QColor(0, 0, 0, 60)); } - QLinearGradient grad(inner.topLeft(), inner.bottomLeft()); - grad.setColorAt(0, c.lighter(130)); - grad.setColorAt(0.4, c.lighter(106)); - grad.setColorAt(0.41, c.darker(106)); - grad.setColorAt(1, c.darker(130)); p.setPen(Qt::NoPen); - p.setBrush(grad); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + //draw the progress bar + p.setBrush (c); + } else { + QLinearGradient grad(inner.topLeft(), inner.bottomLeft()); + grad.setColorAt(0, c.lighter(130)); + grad.setColorAt(0.4, c.lighter(106)); + grad.setColorAt(0.41, c.darker(106)); + grad.setColorAt(1, c.darker(130)); + p.setBrush(grad); + } p.drawRect(inner); p.setBrush(Qt::NoBrush); p.setPen(QPen(QColor(0, 0, 0, 30), 1)); diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp index caed00017f..14a9600f97 100644 --- a/src/plugins/coreplugin/progressmanager/progressmanager.cpp +++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ static const char kDetailsPinned[] = "DetailsPinned"; using namespace Core; using namespace Core::Internal; +using namespace Utils; /*! \mainclass @@ -703,6 +705,11 @@ ToggleButton::ToggleButton(QWidget *parent) : QToolButton(parent) { setToolButtonStyle(Qt::ToolButtonIconOnly); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + QPalette p = palette(); + p.setBrush(QPalette::Base, creatorTheme()->color(Theme::ToggleButtonBackgroundColor)); + setPalette(p); + } } QSize ToggleButton::sizeHint() const diff --git a/src/plugins/coreplugin/themeeditor/colorrole.cpp b/src/plugins/coreplugin/themeeditor/colorrole.cpp new file mode 100644 index 0000000000..1fe016226e --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/colorrole.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "colorrole.h" +#include "colorvariable.h" + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +ColorRole::ColorRole(const QString &roleName, QSharedPointer colorVariable) + : m_roleName(roleName), + m_roleVariable(colorVariable) +{ + m_roleVariable->addReference(this); +} + +QSharedPointer ColorRole::colorVariable() const +{ + return m_roleVariable; +} + +void ColorRole::assignColorVariable(ColorVariable::Ptr namedColor) +{ + namedColor->addReference(this); + m_roleVariable = namedColor; +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/colorrole.h b/src/plugins/coreplugin/themeeditor/colorrole.h new file mode 100644 index 0000000000..bf7704b8f6 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/colorrole.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef COLORROLE_H +#define COLORROLE_H + +#include +#include +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ColorVariable; +class ThemeColors; + +class ColorRole +{ +public: + friend class ThemeColors; + + typedef QSharedPointer Ptr; + + QString roleName() const { return m_roleName; } + QSharedPointer colorVariable() const; + void assignColorVariable(QSharedPointer colorVariable); + +private: + explicit ColorRole(const QString &roleName, QSharedPointer colorVariable); + QString m_roleName; + QString m_roleDescription; + QSharedPointer m_roleVariable; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // COLORROLE_H diff --git a/src/plugins/coreplugin/themeeditor/colorvariable.cpp b/src/plugins/coreplugin/themeeditor/colorvariable.cpp new file mode 100644 index 0000000000..40294691ec --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/colorvariable.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "colorvariable.h" +#include "colorrole.h" +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +ColorVariable::ColorVariable(const QColor &color, const QString &name) + : m_variableValue(color) + , m_variableName(name) +{ +} + +ColorVariable::~ColorVariable() +{ +} + +void ColorVariable::setColor(const QColor &newColor) +{ + m_variableValue = newColor; +} + +void ColorVariable::addReference(ColorRole *t) +{ + m_references.insert(t); +} + +void ColorVariable::removeReference(ColorRole *t) +{ + QTC_ASSERT(m_references.contains(t), return); + m_references.remove(t); +} + + +QSet ColorVariable::references() const +{ + return m_references; +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/colorvariable.h b/src/plugins/coreplugin/themeeditor/colorvariable.h new file mode 100644 index 0000000000..1c2b1e3bd2 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/colorvariable.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef COLORVARIABLE_H +#define COLORVARIABLE_H + +#include +#include +#include +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ColorRole; +class ThemeColors; + +class ColorVariable +{ +public: + friend class ThemeColors; + typedef QSharedPointer Ptr; + + ~ColorVariable(); + + // name of this variable + QString variableName() const { return m_variableName; } + + // value of this variable + QColor color() const { return m_variableValue; } + void setColor(const QColor &color); + + // which theme colors are referencing this variable? + void addReference(ColorRole *t); + void removeReference(ColorRole *t); + QSet references() const; + +private: + explicit ColorVariable(const QColor &color, const QString &variableName = QString()); + QColor m_variableValue; + QString m_variableName; + QSet m_references; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // COLORVARIABLE_H diff --git a/src/plugins/coreplugin/themeeditor/sectionedtablemodel.cpp b/src/plugins/coreplugin/themeeditor/sectionedtablemodel.cpp new file mode 100644 index 0000000000..8808dc428e --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/sectionedtablemodel.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "sectionedtablemodel.h" + +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +SectionedTableModel::SectionedTableModel(QObject *parent) : + QAbstractTableModel(parent) +{ +} + +int SectionedTableModel::sectionHeader(int row) const +{ + int currRow = 0; + int i = 0; + do { + if (row == currRow) + return i; + currRow += sectionRowCount(i) + 1; //account for next header + ++i; + } while (i < sectionCount()); + return -1; +} + +int SectionedTableModel::inSectionBody(int row) const +{ + int currRow = 0; + int i = 0; + do { + ++currRow; + if (row >= currRow && row < currRow + sectionRowCount(i)) + return i; + currRow += sectionRowCount(i); + ++i; + } while (i < sectionCount()); + return -1; +} + +int SectionedTableModel::modelToSectionRow(int row) const +{ + int currRow = 0; + for (int i = 0; i < sectionCount(); ++i) { + ++currRow; + if (row >= currRow && row < currRow + sectionRowCount(i)) + return row-currRow; + currRow += sectionRowCount(i); + } + return row; +} + +QSize SectionedTableModel::span(const QModelIndex &index) const +{ + if (sectionHeader(index.row()) >= 0 && index.column() == 0) + return QSize(1, columnCount(index)); + return QSize(1, 1); +} + +int SectionedTableModel::rowCount(const QModelIndex &index) const +{ + if (index.isValid()) + return 0; + + int r = 0; + for (int i = 0; i < sectionCount(); ++i) + r += sectionRowCount(i) + 1; + return r; +} + +QVariant SectionedTableModel::data(const QModelIndex &index, int role) const +{ + int header = sectionHeader(index.row()); + if (header >= 0) + return (index.column() == 0) ? sectionHeaderData(header, role) + : QVariant(QString()); + return sectionBodyData(inSectionBody(index.row()), + modelToSectionRow(index.row()), + index.column(), + role); +} + +Qt::ItemFlags SectionedTableModel::flags(const QModelIndex &index) const +{ + if (int h = sectionHeader(index.row()) >= 0) + return sectionHeaderFlags(h); + return sectionBodyFlags(inSectionBody(index.row()), + modelToSectionRow(index.row()), + index.column()); +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/sectionedtablemodel.h b/src/plugins/coreplugin/themeeditor/sectionedtablemodel.h new file mode 100644 index 0000000000..5706f3c775 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/sectionedtablemodel.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef SECTIONEDTABLEMODEL_H +#define SECTIONEDTABLEMODEL_H + +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class SectionedTableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit SectionedTableModel(QObject *parent = 0); + + virtual int sectionRowCount(int section) const = 0; + virtual QVariant sectionBodyData(int section, int row, int column, int role) const = 0; + virtual QVariant sectionHeaderData(int section, int role) const = 0; + virtual Qt::ItemFlags sectionBodyFlags(int section, int row, int column) const = 0; + virtual Qt::ItemFlags sectionHeaderFlags(int section) const = 0; + virtual int sectionCount() const = 0; + QSize span(const QModelIndex &index) const Q_DECL_OVERRIDE; + + int inSectionBody(int row) const; + int modelToSectionRow(int row) const; + int sectionHeader(int row) const; + +protected: + int rowCount(const QModelIndex &index) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // SECTIONEDTABLEMODEL_H diff --git a/src/plugins/coreplugin/themeeditor/themecolors.cpp b/src/plugins/coreplugin/themeeditor/themecolors.cpp new file mode 100644 index 0000000000..2549d3e0cb --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themecolors.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "themecolors.h" +#include "colorvariable.h" +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +QSharedPointer ThemeColors::createVariable(const QColor &variableColor, const QString &variableName) +{ + ColorVariable::Ptr var(new ColorVariable(variableColor, variableName)); + insert(var); + return var; +} + +ColorRole::Ptr ThemeColors::createRole(const QString &roleName, QSharedPointer colorVariable) +{ + ColorRole::Ptr role(new ColorRole(roleName, colorVariable)); + insert(role); + return role; +} + +void ThemeColors::insert(ColorRole::Ptr color) +{ + m_colorRoles.append(color); +} + +void ThemeColors::insert(ColorVariable::Ptr color) +{ + m_colorVariables.insert(color); +} + +QSet > ThemeColors::colorVariables() +{ + return m_colorVariables; +} + +void ThemeColors::removeVariable(QSharedPointer variable) +{ + QTC_ASSERT(m_colorVariables.contains(variable), return); + m_colorVariables.remove(variable); +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/themecolors.h b/src/plugins/coreplugin/themeeditor/themecolors.h new file mode 100644 index 0000000000..da47d6b213 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themecolors.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEMECOLORS_H +#define THEMECOLORS_H + +#include "colorrole.h" + +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ColorVariable; + +class ThemeColors +{ +public: + typedef QSharedPointer Ptr; + + int numColorRoles() const { return m_colorRoles.size(); } + ColorRole::Ptr const colorRole(int index) { return m_colorRoles.at(index); } + + QSharedPointer createVariable(const QColor &variableColor, const QString &variableName = QString()); + ColorRole::Ptr createRole(const QString &roleName, QSharedPointer colorVariable); + + QSet > colorVariables(); + + void removeVariable(QSharedPointer variable); + +private: + void insert(ColorRole::Ptr color); + void insert(QSharedPointer color); + + QList m_colorRoles; + QSet > m_colorVariables; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // THEMECOLORS_H diff --git a/src/plugins/coreplugin/themeeditor/themecolorstableview.cpp b/src/plugins/coreplugin/themeeditor/themecolorstableview.cpp new file mode 100644 index 0000000000..07274b2062 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themecolorstableview.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "themecolorstableview.h" +#include "themesettingsitemdelegate.h" +#include "themesettingstablemodel.h" + +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +ThemeColorsTableView::ThemeColorsTableView(QWidget *parent) + : QTreeView(parent) +{ +} + +void ThemeColorsTableView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + QModelIndex index = indexAt(event->pos()); + if (model()->flags(index) & Qt::ItemIsEditable && index.column() == 1) { + setCurrentIndex(index); + edit(index); + // TODO: only applies to editing colors + static_cast(itemDelegate())->popupMenu(); + } + } + QTreeView::mousePressEvent(event); +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/themecolorstableview.h b/src/plugins/coreplugin/themeeditor/themecolorstableview.h new file mode 100644 index 0000000000..346caf250d --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themecolorstableview.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEMECOLORSTABLEVIEW_H +#define THEMECOLORSTABLEVIEW_H + +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ThemeColorsTableView : public QTreeView +{ + Q_OBJECT + +public: + ThemeColorsTableView(QWidget *parent = 0); + +protected: + void mousePressEvent(QMouseEvent *event); +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // THEMECOLORSTABLEVIEW_H diff --git a/src/plugins/coreplugin/themeeditor/themeeditorwidget.cpp b/src/plugins/coreplugin/themeeditor/themeeditorwidget.cpp new file mode 100644 index 0000000000..4b7abdcb42 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themeeditorwidget.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "themeeditorwidget.h" +#include "ui_themeeditorwidget.h" + +#include "colorvariable.h" +#include "colorrole.h" +#include "themecolors.h" +#include "themesettingstablemodel.h" +#include "themesettingsitemdelegate.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +ThemeEditorWidget::ThemeEditorWidget(QWidget *parent) : + QWidget(parent), + m_ui(new Ui::ThemeEditorWidget), + m_readOnly(false), + m_model(0) +{ + m_ui->setupUi(this); + + m_proxyModel = new QSortFilterProxyModel(this); + m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_proxyModel->setFilterKeyColumn(0); + + m_ui->tableView->setModel(m_proxyModel); + ThemeSettingsItemDelegate *cbid = new ThemeSettingsItemDelegate(this); + m_ui->tableView->setItemDelegate(cbid); + connect(m_ui->filter, &QLineEdit::textChanged, m_proxyModel, + static_cast(&QSortFilterProxyModel::setFilterRegExp)); + connect(m_ui->tableView, &QAbstractItemView::doubleClicked, this, &ThemeEditorWidget::changeColor); +} + +ThemeEditorWidget::~ThemeEditorWidget() +{ + delete m_ui; +} + +void ThemeEditorWidget::changeColor(const QModelIndex &index) +{ + if (m_model->inSectionBody(index.row()) != ThemeSettingsTableModel::SectionColors) + return; + if (index.column() == 1) + return; + + int row = m_model->modelToSectionRow(index.row()); + ColorRole::Ptr themeColor = m_model->colors()->colorRole(row); + + QColor currentColor = themeColor->colorVariable()->color(); + + // FIXME: 'currentColor' is correct, but QColorDialog won't show + // it as the correct initial color. Why? + + QColorDialog dlg(this); + dlg.setOption(QColorDialog::ShowAlphaChannel); + dlg.setCurrentColor(currentColor); + + const int customCount = QColorDialog::customCount(); + for (int i = 0; i < customCount; ++i) + QColorDialog::setCustomColor(i, Qt::transparent); // invalid + + int i = 0; + foreach (ColorVariable::Ptr namedColor, m_model->colors()->colorVariables()) + QColorDialog::setCustomColor(i++, namedColor->color().toRgb()); + + int ret = dlg.exec(); + if (ret == QDialog::Accepted) { + themeColor->colorVariable()->setColor(dlg.currentColor()); + m_model->markEverythingChanged(); + } +} + +void ThemeEditorWidget::setReadOnly(bool readOnly) +{ + m_readOnly = readOnly; + m_ui->tableView->setEnabled(!readOnly); + m_ui->filter->setEnabled(!readOnly); +} + +void ThemeEditorWidget::initFrom(Utils::Theme *theme) +{ + if (m_model) { + m_model->setParent(0); + delete m_model; + } + m_model = new ThemeSettingsTableModel(this); + m_model->initFrom(theme); + m_proxyModel->setSourceModel(m_model); + + m_ui->tableView->setColumnWidth(0, 400); + m_ui->tableView->setColumnWidth(1, 300); +} + +ThemeSettingsTableModel *ThemeEditorWidget::model() +{ + return m_model; +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/themeeditorwidget.h b/src/plugins/coreplugin/themeeditor/themeeditorwidget.h new file mode 100644 index 0000000000..ea759882fc --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themeeditorwidget.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEMEEDITORWIDGET_H +#define THEMEEDITORWIDGET_H + +#include + +QT_BEGIN_NAMESPACE +class QSortFilterProxyModel; +QT_END_NAMESPACE + +namespace Utils { class Theme; } + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +namespace Ui { class ThemeEditorWidget; } + +class ThemeSettingsTableModel; + +class ThemeEditorWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ThemeEditorWidget(QWidget *parent = 0); + ~ThemeEditorWidget(); + + void initFrom(Utils::Theme *theme); + + ThemeSettingsTableModel *model(); + + void setReadOnly(bool readOnly); + +private slots: + void changeColor(const QModelIndex &index); + +private: + Ui::ThemeEditorWidget *m_ui; + bool m_readOnly; + ThemeSettingsTableModel *m_model; + QSortFilterProxyModel *m_proxyModel; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // THEMEEDITORWIDGET_H diff --git a/src/plugins/coreplugin/themeeditor/themeeditorwidget.ui b/src/plugins/coreplugin/themeeditor/themeeditorwidget.ui new file mode 100644 index 0000000000..41022847f5 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themeeditorwidget.ui @@ -0,0 +1,45 @@ + + + Core::Internal::ThemeEditor::ThemeEditorWidget + + + + 0 + 0 + 400 + 300 + + + + Theme Editor + + + + + + + + Filter: + + + + + + + + + + + + + + + + Core::Internal::ThemeEditor::ThemeColorsTableView + QTableView +
coreplugin/themeeditor/themecolorstableview.h
+
+
+ + +
diff --git a/src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.cpp b/src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.cpp new file mode 100644 index 0000000000..c21766d989 --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "themesettingsitemdelegate.h" + +#include "colorvariable.h" +#include "themesettingstablemodel.h" +#include +#include + +#include +#include +#include +#include +#include + +using namespace Utils; + +static QAbstractItemModel *sourceModel(QAbstractItemModel *model) +{ + if (QAbstractProxyModel *m = qobject_cast(model)) + return m->sourceModel(); + return model; +} + +static const QAbstractItemModel *sourceModel(const QAbstractItemModel *model) +{ + if (const QAbstractProxyModel *m = qobject_cast(model)) + return m->sourceModel(); + return model; +} + +static QIcon makeIcon(const QColor &color) +{ + QImage img(QSize(24,24), QImage::Format_ARGB32); + img.fill(color.rgba()); + QIcon ico = QIcon(QPixmap::fromImage(img)); + return ico; +} + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +ThemeSettingsItemDelegate::ThemeSettingsItemDelegate(QObject *parent) + : QStyledItemDelegate(parent), + m_comboBox(0) +{ +} + +QWidget *ThemeSettingsItemDelegate::createColorEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + const ThemeSettingsTableModel *model = qobject_cast(sourceModel(index.model())); + + Q_UNUSED(option); + const int row = model->modelToSectionRow(index.row()); + QComboBox *cb = new QComboBox(parent); + ColorRole::Ptr colorRole = model->m_colors->colorRole(row); + + const bool isUnnamed = colorRole->colorVariable()->variableName().isEmpty(); + const QColor currentColor = colorRole->colorVariable()->color(); + + int k = 0; + if (isUnnamed) { + cb->addItem(makeIcon(currentColor), tr(" (current)")); + ++k; + } else { + cb->addItem(makeIcon(currentColor), + colorRole->colorVariable()->variableName()+QString(tr(" (current)"))); + ++k; + } + + foreach (ColorVariable::Ptr namedColor, model->m_colors->colorVariables()) { + if (namedColor->variableName().isEmpty()) + continue; + if (colorRole->colorVariable() == namedColor) { + continue; + } else { + cb->addItem(makeIcon(namedColor->color()), namedColor->variableName()); + m_actions[k++] = qMakePair(Action_ChooseNamedColor, namedColor); + } + } + + if (!isUnnamed) { + cb->addItem(tr("Make unnamed")); + m_actions[k++] = qMakePair(Action_MakeUnnamed, QSharedPointer(0)); + } + cb->addItem(tr("Create new name...")); + m_actions[k++] = qMakePair(Action_CreateNew, QSharedPointer(0)); + + connect(cb, static_cast(&QComboBox::activated), + this, [this, cb]() { + ThemeSettingsItemDelegate *me = const_cast(this); + emit me->commitData(cb); + emit me->closeEditor(cb); + }); + + m_comboBox = cb; + return cb; +} + +QWidget *ThemeSettingsItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + const ThemeSettingsTableModel *model = qobject_cast(sourceModel(index.model())); + + const int section = model->inSectionBody(index.row()); + QTC_ASSERT(section >= 0, return 0); + + switch (section) { + case ThemeSettingsTableModel::SectionWidgetStyle: { + QComboBox *cb = new QComboBox(parent); + QMetaEnum e = Theme::staticMetaObject.enumerator(Theme::staticMetaObject.indexOfEnumerator("WidgetStyle")); + for (int i = 0, total = e.keyCount(); i < total; ++i) + cb->addItem(QLatin1String(e.key(i))); + connect(cb, static_cast(&QComboBox::activated), + this, [this, cb]() { + ThemeSettingsItemDelegate *me = const_cast(this); + emit me->commitData(cb); + emit me->closeEditor(cb); + }); + m_comboBox = cb; + return cb; + } + case ThemeSettingsTableModel::SectionColors: { + return createColorEditor(parent, option, index); + } + case ThemeSettingsTableModel::SectionFlags: { + return QStyledItemDelegate::createEditor(parent, option, index); + } + default: { + qWarning("unhandled section"); + return 0; + } + } // switch +} + +void ThemeSettingsItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QStyledItemDelegate::setEditorData(editor, index); +} + +void ThemeSettingsItemDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const +{ + ThemeSettingsTableModel *themeSettingsModel = qobject_cast(sourceModel(model)); + + const int row = themeSettingsModel->modelToSectionRow(index.row()); + const int section = themeSettingsModel->inSectionBody(index.row()); + + switch (section) { + case ThemeSettingsTableModel::SectionWidgetStyle: + if (QComboBox *cb = qobject_cast(editor)) + themeSettingsModel->m_widgetStyle = static_cast(cb->currentIndex()); + return; + case ThemeSettingsTableModel::SectionColors: { + if (QComboBox *cb = qobject_cast(editor)) { + ColorRole::Ptr themeColor = themeSettingsModel->m_colors->colorRole(row); + + Action act = m_actions[cb->currentIndex()].first; + ColorVariable::Ptr previousVariable = themeColor->colorVariable(); + ColorVariable::Ptr newVariable = m_actions[cb->currentIndex()].second; + + if (act == Action_NoAction) { + return; + } else if (act == Action_ChooseNamedColor) { + previousVariable->removeReference(themeColor.data()); + QTC_ASSERT(newVariable, return); + themeColor->assignColorVariable(newVariable); + } else if (act == Action_MakeUnnamed) { + previousVariable->removeReference(themeColor.data()); + if (previousVariable->references().size() == 0) + themeSettingsModel->m_colors->removeVariable(previousVariable); + ColorVariable::Ptr anonymousColor = themeSettingsModel->m_colors->createVariable(previousVariable->color()); + themeColor->assignColorVariable(anonymousColor); + } else if (act == Action_CreateNew) { + QString name = QInputDialog::getText(editor, tr("New variable name"), tr("Variable name:")); + if (!name.isEmpty()) { + previousVariable->removeReference(themeColor.data()); + + // TODO: check for name collision + ColorVariable::Ptr newVariable = themeSettingsModel->m_colors->createVariable(previousVariable->color(), name); + + themeColor->assignColorVariable(newVariable); + } + } + } + return; + } + default: + return QStyledItemDelegate::setModelData(editor, model, index); + } +} + +void ThemeSettingsItemDelegate::popupMenu() +{ + m_comboBox->showPopup(); +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.h b/src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.h new file mode 100644 index 0000000000..02023284ba --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEMESETTINGSITEMDELEGATE_H +#define THEMESETTINGSITEMDELEGATE_H + +#include "themecolors.h" +#include "colorvariable.h" + +#include + +QT_BEGIN_NAMESPACE +class QComboBox; +QT_END_NAMESPACE + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ThemeSettingsItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + + enum Action { + Action_NoAction, + Action_ChooseNamedColor, + Action_MakeUnnamed, + Action_CreateNew + }; + +public: + ThemeSettingsItemDelegate(QObject *parent); + + QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; + void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; + + void popupMenu(); + +private: + QWidget *createColorEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; + + mutable QMap > m_actions; + mutable QComboBox *m_comboBox; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // THEMESETTINGSITEMDELEGATE_H diff --git a/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp b/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp new file mode 100644 index 0000000000..e3eebce56e --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "themesettingstablemodel.h" +#include "colorvariable.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace Utils; + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +ThemeSettingsTableModel::ThemeSettingsTableModel(QObject *parent) + : SectionedTableModel(parent), + m_colors(new ThemeColors), + m_hasChanges(false) +{ +} + +int ThemeSettingsTableModel::columnCount(const QModelIndex &index) const +{ + Q_UNUSED(index); + return 2; +} + +int ThemeSettingsTableModel::sectionRowCount(int section) const +{ + switch (static_cast
(section)) { + case SectionWidgetStyle: return 1; + case SectionColors: return m_colors->numColorRoles(); + case SectionFlags: return m_flags.size(); + case SectionIconOverlays: return m_iconOverlays.size(); + default: return 0; + } +} + +QVariant ThemeSettingsTableModel::sectionBodyData(int section, int row, int column, int role) const +{ + auto makeDecoration = [](const QColor &c) -> QImage { + QImage img(QSize(32,32), QImage::Format_ARGB32); + img.fill(Qt::transparent); + QPainter p(&img); + p.fillRect(QRect(4,4,24,24), c); + return img; + }; + + switch (static_cast
(section)) { + case SectionWidgetStyle: { + if (role != Qt::DisplayRole) + return QVariant(); + if (column == 0) + return QLatin1String("WidgetStyle"); + else + return m_widgetStyle == Theme::StyleFlat ? QLatin1String("StyleFlat") : QLatin1String("StyleDefault"); + } + case SectionColors: { + ColorRole::Ptr colorRole = m_colors->colorRole(row); + if (column == 0 && role == Qt::DecorationRole) + return QVariant::fromValue(makeDecoration(colorRole->colorVariable()->color())); + if (role == Qt::DisplayRole) { + if (column == 0) + return colorRole->roleName(); + else + return colorRole->colorVariable()->variableName(); + } + return QVariant(); + } + case SectionFlags: { + if (column == 0 && role == Qt::DisplayRole) + return m_flags[row].first; + else if (column == 1 && role == Qt::CheckStateRole) + return m_flags[row].second ? Qt::Checked : Qt::Unchecked; + else if (column == 0 && role == Qt::DecorationRole) + return QVariant::fromValue(makeDecoration(Qt::transparent)); + return QVariant(); + } + case SectionIconOverlays: { + if (column == 0 && role == Qt::DisplayRole) + return m_iconOverlays[row].first; + else if (column == 1 && role == Qt::DisplayRole) + return m_iconOverlays[row].second; + else if (column == 0 && role == Qt::DecorationRole) + return QVariant::fromValue(makeDecoration(Qt::transparent)); + return QVariant(); + } + default: + return QVariant(); + } +} + +QVariant ThemeSettingsTableModel::sectionHeaderData(int section, int role) const +{ + if (role == Qt::DisplayRole) { + switch (static_cast
(section)) { + case SectionWidgetStyle: return tr("Widget Style"); + case SectionColors: return tr("Colors"); + case SectionFlags: return tr("Flags"); + case SectionIconOverlays: return tr("Icon Overlays"); + default: return QString(); + } + } + if (role == Qt::FontRole) { + QFont font; + font.setPointSizeF(font.pointSizeF() * 1.25); + font.setBold(true); + return font; + } + if (role == Qt::SizeHintRole) + return QSize(50, 50); + return QVariant(); +} + +Qt::ItemFlags ThemeSettingsTableModel::sectionBodyFlags(int section, int row, int column) const +{ + Q_UNUSED(row); + switch (static_cast
(section)) { + case SectionWidgetStyle: + return (column == 0) ? Qt::ItemIsEnabled + : Qt::ItemIsEnabled | Qt::ItemIsEditable; + case SectionColors: + return (column == 0) ? Qt::ItemIsEnabled + : Qt::ItemIsEnabled | Qt::ItemIsEditable; + case SectionFlags: + return (column == 0) ? Qt::ItemIsEnabled + : Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; + case SectionIconOverlays: + return Qt::ItemIsEnabled; + default: return Qt::ItemIsEnabled; + } +} + +bool ThemeSettingsTableModel::setData(const QModelIndex &idx, const QVariant &value, int role) +{ + m_hasChanges = true; + Q_UNUSED(role); + + int section = inSectionBody(idx.row()); + int row = modelToSectionRow(idx.row()); + switch (static_cast
(section)) { + case SectionFlags: { + Qt::CheckState checkState = static_cast(value.toInt()); + bool checked = checkState == Qt::Checked; + m_flags[row].second = checked; + emit dataChanged(idx, idx); + return true; + } + default: { + // don't bother tracking changes, just mark the whole table as changed + markEverythingChanged(); + return true; + } + } // switch +} + +void ThemeSettingsTableModel::markEverythingChanged() +{ + m_hasChanges = true; + QModelIndex i; + emit dataChanged(index(0, 0, i), index(rowCount(i), columnCount(i), i)); +} + +void ThemeSettingsTableModel::initFrom(Theme *theme) +{ + const QMetaObject &metaObject = Theme::staticMetaObject; + // Colors + { + QMetaEnum e = metaObject.enumerator(metaObject.indexOfEnumerator("ColorRole")); + QMap varLookup; + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QPair c = theme->d->colors[static_cast(i)]; + if (c.second.isEmpty()) { + ColorVariable::Ptr v = colors()->createVariable(c.first); + colors()->createRole(key, v); + } else if (varLookup.contains(c.second)) { + colors()->createRole(key, varLookup[c.second]); + } else { + ColorVariable::Ptr v = colors()->createVariable(c.first, c.second); + colors()->createRole(key, v); + varLookup[c.second] = v; + } + } + } + // Flags + { + QMetaEnum e = metaObject.enumerator(metaObject.indexOfEnumerator("Flag")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + m_flags.append(qMakePair(key, theme->flag(static_cast(i)))); + } + } + // IconOverlays + { + QMetaEnum e = metaObject.enumerator(metaObject.indexOfEnumerator("MimeType")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + m_iconOverlays.append(qMakePair(key, theme->iconOverlay(static_cast(i)))); + } + } + + m_widgetStyle = theme->widgetStyle(); + m_name = theme->d->name; +} + +void ThemeSettingsTableModel::toTheme(Theme *t) const +{ + ThemePrivate *theme = t->d; + // Colors + { + QMetaEnum e = Theme::staticMetaObject.enumerator(Theme::staticMetaObject.indexOfEnumerator("ColorRole")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + ColorRole::Ptr role = colors()->colorRole(i); + ColorVariable::Ptr var = role->colorVariable(); + theme->colors[i] = qMakePair(var->color(), var->variableName()); + } + } + // Flags + { + QTC_ASSERT(theme->flags.size() == m_flags.size(), return); + for (int i = 0; i < theme->flags.size(); ++i) + theme->flags[i] = m_flags[i].second; + } + // IconOveralys + { + const int nOverlays = theme->iconOverlays.size(); + QTC_ASSERT(nOverlays == m_iconOverlays.size(), return); + for (int i = 0; i < nOverlays; ++i) + theme->iconOverlays[i] = m_iconOverlays[i].second; + } + + theme->widgetStyle = m_widgetStyle; + theme->name = m_name; + emit t->changed(); +} + +Qt::ItemFlags ThemeSettingsTableModel::sectionHeaderFlags(int section) const +{ + Q_UNUSED(section); + return Qt::ItemIsEnabled; +} + +int ThemeSettingsTableModel::sectionCount() const +{ + return SectionInvalid; +} + +QVariant ThemeSettingsTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole) { + if (orientation == Qt::Horizontal) { + if (section == 0) + return tr("Role"); + return tr("Value"); + } + } + return QVariant(); +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themeeditor/themesettingstablemodel.h b/src/plugins/coreplugin/themeeditor/themesettingstablemodel.h new file mode 100644 index 0000000000..7af96458cc --- /dev/null +++ b/src/plugins/coreplugin/themeeditor/themesettingstablemodel.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEMESETTINGSTABLEMODEL_H +#define THEMESETTINGSTABLEMODEL_H + +#include + +#include "themecolors.h" +#include "sectionedtablemodel.h" +#include + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ThemeSettingsTableModel : public SectionedTableModel +{ + Q_OBJECT + +public: + friend class ThemeSettingsItemDelegate; + + enum Section { + SectionWidgetStyle, + SectionColors, + SectionFlags, + SectionIconOverlays, + SectionInvalid // end + }; + + ThemeSettingsTableModel(QObject *parent = 0); + + bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &index) const Q_DECL_OVERRIDE; + int sectionRowCount(int section) const Q_DECL_OVERRIDE; + QVariant sectionBodyData(int section, int row, int column, int role) const Q_DECL_OVERRIDE; + QVariant sectionHeaderData(int section, int role) const Q_DECL_OVERRIDE; + Qt::ItemFlags sectionBodyFlags(int section, int row, int column) const Q_DECL_OVERRIDE; + Qt::ItemFlags sectionHeaderFlags(int section) const Q_DECL_OVERRIDE; + int sectionCount() const Q_DECL_OVERRIDE; + + ThemeColors::Ptr colors() const { return m_colors; } + + bool hasChanges() const { return m_hasChanges; } + + void markEverythingChanged(); + + void initFrom(Utils::Theme *theme); + void toTheme(Utils::Theme *theme) const; + + QString m_name; + +public: + ThemeColors::Ptr m_colors; + QList > m_flags; + QList > m_iconOverlays; + Utils::Theme::WidgetStyle m_widgetStyle; + bool m_hasChanges; +}; + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core + +#endif // THEMESETTINGSTABLEMODEL_H diff --git a/src/plugins/coreplugin/themesettings.cpp b/src/plugins/coreplugin/themesettings.cpp new file mode 100644 index 0000000000..c21dc4ad44 --- /dev/null +++ b/src/plugins/coreplugin/themesettings.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "themesettings.h" +#include "coreconstants.h" +#include "icore.h" +#include "editormanager/editormanager_p.h" +#include "themeeditor/themesettingstablemodel.h" + +#include + +#include +#include +#include +#include +#include + +#include "ui_themesettings.h" + +using namespace Utils; + +namespace Core { +namespace Internal { + +const char themeNameKey[] = "ThemeName"; + +static QString customThemesPath() +{ + QString path = Core::ICore::userResourcePath(); + path.append(QLatin1String("/themes/")); + return path; +} + +static QString createThemeFileName(const QString &pattern) +{ + const QString stylesPath = customThemesPath(); + QString baseFileName = stylesPath; + baseFileName += pattern; + + // Find an available file name + int i = 1; + QString fileName; + do { + fileName = baseFileName.arg((i == 1) ? QString() : QString::number(i)); + ++i; + } while (QFile::exists(fileName)); + + // Create the base directory when it doesn't exist + if (!QFile::exists(stylesPath) && !QDir().mkpath(stylesPath)) { + qWarning() << "Failed to create theme directory:" << stylesPath; + return QString(); + } + return fileName; +} + + +struct ThemeEntry +{ + ThemeEntry() {} + ThemeEntry(const QString &fileName, bool readOnly): + m_fileName(fileName), + m_readOnly(readOnly) + { } + + QString fileName() const { return m_fileName; } + QString name() const; + bool readOnly() const { return m_readOnly; } + +private: + QString m_fileName; + bool m_readOnly; +}; + +QString ThemeEntry::name() const +{ + QSettings settings(m_fileName, QSettings::IniFormat); + QString n = settings.value(QLatin1String(themeNameKey), QCoreApplication::tr("unnamed")).toString(); + return m_readOnly ? QCoreApplication::tr("%1 (built-in)").arg(n) : n; +} + + +class ThemeListModel : public QAbstractListModel +{ +public: + ThemeListModel(QObject *parent = 0): + QAbstractListModel(parent) + { + } + + int rowCount(const QModelIndex &parent) const + { + return parent.isValid() ? 0 : m_themes.size(); + } + + QVariant data(const QModelIndex &index, int role) const + { + if (role == Qt::DisplayRole) + return m_themes.at(index.row()).name(); + return QVariant(); + } + + void removeTheme(int index) + { + beginRemoveRows(QModelIndex(), index, index); + m_themes.removeAt(index); + endRemoveRows(); + } + + void setThemes(const QList &themes) + { + beginResetModel(); + m_themes = themes; + endResetModel(); + } + + const ThemeEntry &themeAt(int index) const + { + return m_themes.at(index); + } + +private: + QList m_themes; +}; + + +class ThemeSettingsPrivate +{ +public: + ThemeSettingsPrivate(); + ~ThemeSettingsPrivate(); + +public: + ThemeListModel *m_themeListModel; + bool m_refreshingThemeList; + Ui::ThemeSettings *m_ui; + QPointer m_widget; + ThemeEntry m_currentTheme; +}; + +ThemeSettingsPrivate::ThemeSettingsPrivate() + : m_themeListModel(new ThemeListModel) + , m_refreshingThemeList(false) + , m_ui(0) +{ + m_currentTheme = ThemeEntry(creatorTheme()->fileName(), true); +} + +ThemeSettingsPrivate::~ThemeSettingsPrivate() +{ + delete m_themeListModel; +} + +ThemeSettings::ThemeSettings() +{ + setId(Core::Constants::SETTINGS_ID_ENVIRONMENT); + setDisplayName(tr("Theme")); + setCategory(Core::Constants::SETTINGS_CATEGORY_CORE); + setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE)); + setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON)); + + d = new ThemeSettingsPrivate(); +} + +ThemeSettings::~ThemeSettings() +{ + delete d; +} + +void ThemeSettings::refreshThemeList() +{ + QList themes; + + QString resourcePath = Core::ICore::resourcePath(); + QDir themeDir(resourcePath + QLatin1String("/themes")); + themeDir.setNameFilters(QStringList() << QLatin1String("*.creatortheme")); + themeDir.setFilter(QDir::Files); + + int selected = 0; + + QStringList themeList = themeDir.entryList(); + QString defaultTheme = QFileInfo(defaultThemeFileName()).fileName(); + if (themeList.removeAll(defaultTheme)) + themeList.prepend(defaultTheme); + foreach (const QString &file, themeList) { + const QString fileName = themeDir.absoluteFilePath(file); + if (d->m_currentTheme.fileName() == fileName) + selected = themes.size(); + themes.append(ThemeEntry(fileName, true)); + } + + if (themes.isEmpty()) + qWarning() << "Warning: no themes found in path:" << themeDir.path(); + + themeDir.setPath(customThemesPath()); + foreach (const QString &file, themeDir.entryList()) { + const QString fileName = themeDir.absoluteFilePath(file); + if (d->m_currentTheme.fileName() == fileName) + selected = themes.size(); + themes.append(ThemeEntry(fileName, false)); + } + + d->m_currentTheme = themes[selected]; + + d->m_refreshingThemeList = true; + d->m_themeListModel->setThemes(themes); + d->m_ui->themeComboBox->setCurrentIndex(selected); + d->m_refreshingThemeList = false; +} + +QString ThemeSettings::defaultThemeFileName(const QString &fileName) +{ + QString defaultScheme = Core::ICore::resourcePath(); + defaultScheme += QLatin1String("/themes/"); + + if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName)) + defaultScheme += fileName; + else + defaultScheme += QLatin1String("default.creatortheme"); + + return defaultScheme; +} + +void ThemeSettings::themeSelected(int index) +{ + bool readOnly = true; + if (index != -1) { + // Check whether we're switching away from a changed theme + if (!d->m_refreshingThemeList) + maybeSaveTheme(); + + const ThemeEntry &entry = d->m_themeListModel->themeAt(index); + readOnly = entry.readOnly(); + d->m_currentTheme = entry; + + QSettings settings(entry.fileName(), QSettings::IniFormat); + Theme theme; + theme.readSettings(settings); + d->m_ui->editor->initFrom(&theme); + } + d->m_ui->copyButton->setEnabled(index != -1); + d->m_ui->deleteButton->setEnabled(!readOnly); + d->m_ui->renameButton->setEnabled(!readOnly); + d->m_ui->editor->setReadOnly(readOnly); +} + +QWidget *ThemeSettings::widget() +{ + if (!d->m_widget) { + d->m_widget = new QWidget; + d->m_ui = new Ui::ThemeSettings(); + d->m_ui->setupUi(d->m_widget); + d->m_ui->themeComboBox->setModel(d->m_themeListModel); + + connect(d->m_ui->themeComboBox, static_cast(&QComboBox::currentIndexChanged), + this, &ThemeSettings::themeSelected); + connect(d->m_ui->copyButton, &QAbstractButton::clicked, this, &ThemeSettings::copyTheme); + connect(d->m_ui->renameButton, &QAbstractButton::clicked, this, &ThemeSettings::renameTheme); + connect(d->m_ui->deleteButton, &QAbstractButton::clicked, this, &ThemeSettings::confirmDeleteTheme); + + refreshThemeList(); + } + return d->m_widget; +} + +void ThemeSettings::confirmDeleteTheme() +{ + const int index = d->m_ui->themeComboBox->currentIndex(); + if (index == -1) + return; + + const ThemeEntry &entry = d->m_themeListModel->themeAt(index); + if (entry.readOnly()) + return; + + QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning, + tr("Delete Theme"), + tr("Are you sure you want to delete the theme '%1' permanently?").arg(entry.name()), + QMessageBox::Discard | QMessageBox::Cancel, + d->m_ui->deleteButton->window()); + + // Change the text and role of the discard button + QPushButton *deleteButton = static_cast(messageBox->button(QMessageBox::Discard)); + deleteButton->setText(tr("Delete")); + messageBox->addButton(deleteButton, QMessageBox::AcceptRole); + messageBox->setDefaultButton(deleteButton); + + connect(deleteButton, &QAbstractButton::clicked, messageBox, &QDialog::accept); + connect(messageBox, &QDialog::accepted, this, &ThemeSettings::deleteTheme); + messageBox->setAttribute(Qt::WA_DeleteOnClose); + messageBox->open(); +} + +void ThemeSettings::deleteTheme() +{ + const int index = d->m_ui->themeComboBox->currentIndex(); + QTC_ASSERT(index != -1, return); + + const ThemeEntry &entry = d->m_themeListModel->themeAt(index); + QTC_ASSERT(!entry.readOnly(), return); + + if (QFile::remove(entry.fileName())) + d->m_themeListModel->removeTheme(index); +} + +void ThemeSettings::copyTheme() +{ + QInputDialog *dialog = new QInputDialog(d->m_ui->copyButton->window()); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setInputMode(QInputDialog::TextInput); + dialog->setWindowTitle(tr("Copy Theme")); + dialog->setLabelText(tr("Theme name:")); + + //TODO + //dialog->setTextValue(tr("%1 (copy)").arg(d_ptr->m_value.colorScheme().displayName())); + + connect(dialog, &QInputDialog::textValueSelected, this, &ThemeSettings::copyThemeByName); + dialog->open(); +} + +void ThemeSettings::maybeSaveTheme() +{ + if (!d->m_ui->editor->model()->hasChanges()) + return; + + QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning, + tr("Theme Changed"), + tr("The theme \"%1\" was modified, do you want to save the changes?") + .arg(d->m_currentTheme.name()), + QMessageBox::Discard | QMessageBox::Save, + d->m_ui->themeComboBox->window()); + + // Change the text of the discard button + QPushButton *discardButton = static_cast(messageBox->button(QMessageBox::Discard)); + discardButton->setText(tr("Discard")); + messageBox->addButton(discardButton, QMessageBox::DestructiveRole); + messageBox->setDefaultButton(QMessageBox::Save); + + if (messageBox->exec() == QMessageBox::Save) { + Theme newTheme; + d->m_ui->editor->model()->toTheme(&newTheme); + newTheme.writeSettings(d->m_currentTheme.fileName()); + } +} + +void ThemeSettings::renameTheme() +{ + int index = d->m_ui->themeComboBox->currentIndex(); + if (index == -1) + return; + const ThemeEntry &entry = d->m_themeListModel->themeAt(index); + + maybeSaveTheme(); + + QInputDialog *dialog = new QInputDialog(d->m_ui->renameButton->window()); + dialog->setInputMode(QInputDialog::TextInput); + dialog->setWindowTitle(tr("Rename Theme")); + dialog->setLabelText(tr("Theme name:")); + dialog->setTextValue(d->m_ui->editor->model()->m_name); + int ret = dialog->exec(); + QString newName = dialog->textValue(); + delete dialog; + + if (ret != QDialog::Accepted || newName.isEmpty()) + return; + + // overwrite file with new name + Theme newTheme; + d->m_ui->editor->model()->toTheme(&newTheme); + newTheme.setName(newName); + newTheme.writeSettings(entry.fileName()); + + refreshThemeList(); +} + +void ThemeSettings::copyThemeByName(const QString &name) +{ + int index = d->m_ui->themeComboBox->currentIndex(); + if (index == -1) + return; + + const ThemeEntry &entry = d->m_themeListModel->themeAt(index); + + QString baseFileName = QFileInfo(entry.fileName()).completeBaseName(); + baseFileName += QLatin1String("_copy%1.creatortheme"); + QString fileName = createThemeFileName(baseFileName); + + if (fileName.isEmpty()) + return; + + // Ask about saving any existing modifactions + maybeSaveTheme(); + + Theme newTheme; + d->m_ui->editor->model()->toTheme(&newTheme); + newTheme.setName(name); + newTheme.writeSettings(fileName); + + d->m_currentTheme = ThemeEntry(fileName, true); + + refreshThemeList(); +} + +void ThemeSettings::apply() +{ + if (!d->m_ui) // wasn't shown, can't be changed + return; + + { + d->m_ui->editor->model()->toTheme(creatorTheme()); + QPalette newPalette = creatorTheme()->palette(qApp->palette()); + qApp->setPalette(newPalette); + foreach (QWidget *w, QApplication::topLevelWidgets()) + w->update(); + } + + // save definition of theme + if (!d->m_currentTheme.readOnly()) { + Theme newTheme; + d->m_ui->editor->model()->toTheme(&newTheme); + newTheme.writeSettings(d->m_currentTheme.fileName()); + } + + // save filename of selected theme in global config + QSettings *settings = Core::ICore::settings(); + settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), d->m_currentTheme.fileName()); +} + +void ThemeSettings::finish() +{ + delete d->m_widget; + if (!d->m_ui) // page was never shown + return + delete d->m_ui; + d->m_ui = 0; +} + +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/themesettings.h b/src/plugins/coreplugin/themesettings.h new file mode 100644 index 0000000000..a204acd7a1 --- /dev/null +++ b/src/plugins/coreplugin/themesettings.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Thorben Kroeger . +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://www.qt.io/licensing. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef THEMESETTINGS_H +#define THEMESETTINGS_H + +#include + +namespace Core { +namespace Internal { + +class ThemeSettingsPrivate; + +class ThemeSettings : public IOptionsPage +{ + Q_OBJECT + +public: + ThemeSettings(); + ~ThemeSettings(); + + QWidget *widget(); + void apply(); + void finish(); + + static QString defaultThemeFileName(const QString &fileName = QString()); + +private slots: + void themeSelected(int index); + void copyTheme(); + void renameTheme(); + void copyThemeByName(const QString &); + void confirmDeleteTheme(); + void deleteTheme(); + void maybeSaveTheme(); + +private: + void refreshThemeList(); + ThemeSettingsPrivate *d; +}; + +} // namespace Internal +} // namespace Core + +#endif // THEMESETTINGS_H diff --git a/src/plugins/coreplugin/themesettings.ui b/src/plugins/coreplugin/themesettings.ui new file mode 100644 index 0000000000..80fce6544d --- /dev/null +++ b/src/plugins/coreplugin/themesettings.ui @@ -0,0 +1,73 @@ + + + Core::Internal::ThemeSettings + + + + 0 + 0 + 527 + 359 + + + + + + + + + + 0 + 0 + + + + + + + + Rename... + + + + + + + Copy... + + + + + + + Delete + + + + + + + + + + 0 + 0 + + + + + + + + + Core::Internal::ThemeEditor::ThemeEditorWidget + QWidget +
coreplugin/themeeditor/themeeditorwidget.h
+ 1 +
+
+ + + + +
diff --git a/src/plugins/cppeditor/cppeditor.qrc b/src/plugins/cppeditor/cppeditor.qrc index 6e5f83fba6..e3091a0d9b 100644 --- a/src/plugins/cppeditor/cppeditor.qrc +++ b/src/plugins/cppeditor/cppeditor.qrc @@ -4,5 +4,8 @@ images/qt_h.png CppEditor.mimetypes.xml images/qt_c.png + images/dark_qt_cpp.png + images/dark_qt_h.png + images/dark_qt_c.png diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index c02327802d..577ec4949a 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -59,11 +59,14 @@ #include +#include + #include #include using namespace Core; using namespace TextEditor; +using namespace Utils; namespace CppEditor { namespace Internal { @@ -103,9 +106,9 @@ public: addHoverHandler(new CppHoverHandler); if (!Utils::HostOsInfo::isMacHost() && !Utils::HostOsInfo::isWindowsHost()) { - FileIconProvider::registerIconOverlayForMimeType(":/cppeditor/images/qt_cpp.png", Constants::CPP_SOURCE_MIMETYPE); - FileIconProvider::registerIconOverlayForMimeType(":/cppeditor/images/qt_c.png", Constants::C_SOURCE_MIMETYPE); - FileIconProvider::registerIconOverlayForMimeType(":/cppeditor/images/qt_h.png", Constants::CPP_HEADER_MIMETYPE); + FileIconProvider::registerIconOverlayForMimeType(creatorTheme()->iconOverlay(Theme::CppSourceMimetype).toLatin1().data(), Constants::CPP_SOURCE_MIMETYPE); + FileIconProvider::registerIconOverlayForMimeType(creatorTheme()->iconOverlay(Theme::CSourceMimetype).toLatin1().data(), Constants::C_SOURCE_MIMETYPE); + FileIconProvider::registerIconOverlayForMimeType(creatorTheme()->iconOverlay(Theme::CppHeaderMimetype).toLatin1().data(), Constants::CPP_HEADER_MIMETYPE); } } }; diff --git a/src/plugins/cppeditor/images/dark_qt_c.png b/src/plugins/cppeditor/images/dark_qt_c.png new file mode 100644 index 0000000000..269b5e3938 Binary files /dev/null and b/src/plugins/cppeditor/images/dark_qt_c.png differ diff --git a/src/plugins/cppeditor/images/dark_qt_cpp.png b/src/plugins/cppeditor/images/dark_qt_cpp.png new file mode 100644 index 0000000000..c809be82ab Binary files /dev/null and b/src/plugins/cppeditor/images/dark_qt_cpp.png differ diff --git a/src/plugins/cppeditor/images/dark_qt_h.png b/src/plugins/cppeditor/images/dark_qt_h.png new file mode 100644 index 0000000000..1cf8eab6f9 Binary files /dev/null and b/src/plugins/cppeditor/images/dark_qt_h.png differ diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index b58557dff3..c686f7eec7 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -76,6 +76,7 @@ #include #include #include +#include #include #include @@ -101,6 +102,7 @@ static const char kExternalWindowStateKey[] = "Help/ExternalWindowState"; #define IMAGEPATH ":/help/images/" using namespace Core; +using namespace Utils; HelpPlugin::HelpPlugin() : m_mode(0), @@ -565,8 +567,13 @@ void HelpPlugin::showContextHelp() // No link found or no context object viewer->setSource(QUrl(Help::Constants::AboutBlank)); viewer->setHtml(tr("No Documentation" - "
%1
No documentation " - "available.
").arg(idFromContext)); + "
" + "%2
" + "No documentation available." + "
") + .arg(creatorTheme()->color(Theme::TextColorNormal).name()) + .arg(idFromContext) + .arg(creatorTheme()->color(Theme::TextColorNormal).name())); } else { const QUrl &oldSource = viewer->source(); if (source != oldSource) { diff --git a/src/plugins/projectexplorer/doubletabwidget.cpp b/src/plugins/projectexplorer/doubletabwidget.cpp index c6e360f459..8c00a81ef7 100644 --- a/src/plugins/projectexplorer/doubletabwidget.cpp +++ b/src/plugins/projectexplorer/doubletabwidget.cpp @@ -32,6 +32,7 @@ #include "ui_doubletabwidget.h" #include +#include #include #include @@ -42,6 +43,7 @@ #include using namespace ProjectExplorer::Internal; +using namespace Utils; static const int MIN_LEFT_MARGIN = 50; static const int MARGIN = 12; @@ -53,35 +55,45 @@ static const int OVERFLOW_DROPDOWN_WIDTH = Utils::StyleHelper::navigationWidgetH static void drawFirstLevelSeparator(QPainter *painter, QPoint top, QPoint bottom) { QLinearGradient grad(top, bottom); - grad.setColorAt(0, QColor(255, 255, 255, 20)); - grad.setColorAt(0.4, QColor(255, 255, 255, 60)); - grad.setColorAt(0.7, QColor(255, 255, 255, 50)); - grad.setColorAt(1, QColor(255, 255, 255, 40)); - painter->setPen(QPen(grad, 0)); - painter->drawLine(top, bottom); - grad.setColorAt(0, QColor(0, 0, 0, 30)); - grad.setColorAt(0.4, QColor(0, 0, 0, 70)); - grad.setColorAt(0.7, QColor(0, 0, 0, 70)); - grad.setColorAt(1, QColor(0, 0, 0, 40)); - painter->setPen(QPen(grad, 0)); - painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0)); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + grad.setColorAt(0, QColor(255, 0, 255, 20)); + grad.setColorAt(0.4, QColor(255, 0, 255, 60)); + grad.setColorAt(0.7, QColor(255, 0, 255, 50)); + grad.setColorAt(1, QColor(255, 0, 255, 40)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top, bottom); + grad.setColorAt(0, QColor(0, 0, 0, 30)); + grad.setColorAt(0.4, QColor(0, 0, 0, 70)); + grad.setColorAt(0.7, QColor(0, 0, 0, 70)); + grad.setColorAt(1, QColor(0, 0, 0, 40)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0)); + } else { + painter->setPen(QPen(creatorTheme()->color(Theme::DoubleTabWidget1stSeparatorColor), 0)); + painter->drawLine(top, bottom); + } } static void drawSecondLevelSeparator(QPainter *painter, QPoint top, QPoint bottom) { QLinearGradient grad(top, bottom); - grad.setColorAt(0, QColor(255, 255, 255, 0)); - grad.setColorAt(0.4, QColor(255, 255, 255, 100)); - grad.setColorAt(0.7, QColor(255, 255, 255, 100)); - grad.setColorAt(1, QColor(255, 255, 255, 0)); - painter->setPen(QPen(grad, 0)); - painter->drawLine(top, bottom); - grad.setColorAt(0, QColor(0, 0, 0, 0)); - grad.setColorAt(0.4, QColor(0, 0, 0, 100)); - grad.setColorAt(0.7, QColor(0, 0, 0, 100)); - grad.setColorAt(1, QColor(0, 0, 0, 0)); - painter->setPen(QPen(grad, 0)); - painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0)); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + grad.setColorAt(0, QColor(255, 255, 255, 20)); + grad.setColorAt(0.4, QColor(255, 255, 255, 60)); + grad.setColorAt(0.7, QColor(255, 255, 255, 50)); + grad.setColorAt(1, QColor(255, 255, 255, 40)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top, bottom); + grad.setColorAt(0, QColor(0, 0, 0, 0)); + grad.setColorAt(0.4, QColor(0, 0, 0, 100)); + grad.setColorAt(0.7, QColor(0, 0, 0, 100)); + grad.setColorAt(1, QColor(0, 0, 0, 0)); + painter->setPen(QPen(grad, 0)); + painter->drawLine(top - QPoint(1,0), bottom - QPoint(1,0)); + } else { + painter->setPen(QPen(creatorTheme()->color(Theme::DoubleTabWidget2ndSeparatorColor), 0)); + painter->drawLine(top, bottom); + } } DoubleTabWidget::DoubleTabWidget(QWidget *parent) : @@ -352,16 +364,18 @@ void DoubleTabWidget::paintEvent(QPaintEvent *event) // draw top level tab bar r.setHeight(Utils::StyleHelper::navigationWidgetHeight()); - QPoint offset = window()->mapToGlobal(QPoint(0, 0)) - mapToGlobal(r.topLeft()); - QRect gradientSpan = QRect(offset, window()->size()); - Utils::StyleHelper::horizontalGradient(&painter, gradientSpan, r); - - painter.setPen(Utils::StyleHelper::borderColor()); - - QColor lighter(255, 255, 255, 40); - painter.drawLine(r.bottomLeft(), r.bottomRight()); - painter.setPen(lighter); - painter.drawLine(r.topLeft(), r.topRight()); + if (creatorTheme()->widgetStyle () == Theme::StyleDefault) { + QPoint offset = window()->mapToGlobal(QPoint(0, 0)) - mapToGlobal(r.topLeft()); + QRect gradientSpan = QRect(offset, window()->size()); + Utils::StyleHelper::horizontalGradient(&painter, gradientSpan, r); + painter.setPen(Utils::StyleHelper::borderColor()); + QColor lighter(255, 255, 255, 40); + painter.drawLine(r.bottomLeft(), r.bottomRight()); + painter.setPen(lighter); + painter.drawLine(r.topLeft(), r.topRight()); + } else { + painter.fillRect(r, creatorTheme()->color(Theme::DoubleTabWidget1stEmptyAreaBackgroundColor)); + } QFontMetrics fm(font()); int baseline = (r.height() + fm.ascent()) / 2 - 1; @@ -373,17 +387,23 @@ void DoubleTabWidget::paintEvent(QPaintEvent *event) } QLinearGradient grad(QPoint(0, 0), QPoint(0, r.height() + OTHER_HEIGHT - 1)); - grad.setColorAt(0, QColor(247, 247, 247)); - grad.setColorAt(1, QColor(205, 205, 205)); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + grad.setColorAt(0, creatorTheme()->color(Theme::DoubleTabWidget1stTabBackgroundColor)); + } else { + grad.setColorAt(0, QColor(247, 247, 247)); + grad.setColorAt(1, QColor(205, 205, 205)); + } // draw background of second bar painter.fillRect(QRect(0, r.height(), r.width(), OTHER_HEIGHT), grad); - painter.setPen(QColor(0x505050)); - painter.drawLine(0, r.height() + OTHER_HEIGHT, - r.width(), r.height() + OTHER_HEIGHT); - painter.setPen(Qt::white); - painter.drawLine(0, r.height(), - r.width(), r.height()); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + painter.setPen(QColor(0x505050)); + painter.drawLine(0, r.height() + OTHER_HEIGHT, + r.width(), r.height() + OTHER_HEIGHT); + painter.setPen(Qt::white); + painter.drawLine(0, r.height(), + r.width(), r.height()); + } // top level tabs int x = m_title.isEmpty() ? 0 : @@ -464,26 +484,28 @@ void DoubleTabWidget::paintEvent(QPaintEvent *event) r.height() + 1), grad); - if (actualIndex != 0) { + if (actualIndex != 0 && creatorTheme()->widgetStyle() == Theme::StyleDefault) { painter.setPen(QColor(255, 255, 255, 170)); painter.drawLine(x, 0, x, r.height()); } x += MARGIN; - painter.setPen(Qt::black); + painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget1stTabActiveTextColor)); painter.drawText(x, baseline, tab.displayName()); x += nameWidth.at(actualIndex); x += MARGIN; - painter.setPen(Utils::StyleHelper::borderColor()); - painter.drawLine(x, 0, x, r.height() - 1); - painter.setPen(QColor(0, 0, 0, 20)); - painter.drawLine(x + 1, 0, x + 1, r.height() - 1); - painter.setPen(QColor(255, 255, 255, 170)); - painter.drawLine(x - 1, 0, x - 1, r.height()); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + painter.setPen(Utils::StyleHelper::borderColor()); + painter.drawLine(x, 0, x, r.height() - 1); + painter.setPen(QColor(0, 0, 0, 20)); + painter.drawLine(x + 1, 0, x + 1, r.height() - 1); + painter.setPen(QColor(255, 255, 255, 170)); + painter.drawLine(x - 1, 0, x - 1, r.height()); + } } else { - if (i == 0) + if (i == 0 && creatorTheme()->widgetStyle() == Theme::StyleDefault) drawFirstLevelSeparator(&painter, QPoint(x, 0), QPoint(x, r.height()-1)); x += MARGIN; - painter.setPen(Utils::StyleHelper::panelTextColor()); + painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget1stTabInactiveTextColor)); painter.drawText(x + 1, baseline, tab.displayName()); x += nameWidth.at(actualIndex); x += MARGIN; @@ -512,14 +534,20 @@ void DoubleTabWidget::paintEvent(QPaintEvent *event) x += MARGIN; int textWidth = fm.width(subTabs.at(i)); if (currentTab.currentSubTab == i) { - painter.setPen(Qt::white); - painter.drawPixmap(x, y, m_left); - painter.drawPixmap(QRect(x + SELECTION_IMAGE_WIDTH, y, - textWidth, imageHeight), - m_mid, QRect(0, 0, m_mid.width(), m_mid.height())); - painter.drawPixmap(x + SELECTION_IMAGE_WIDTH + textWidth, y, m_right); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + painter.drawPixmap(x, y, m_left); + painter.drawPixmap(QRect(x + SELECTION_IMAGE_WIDTH, y, + textWidth, imageHeight), + m_mid, QRect(0, 0, m_mid.width(), m_mid.height())); + painter.drawPixmap(x + SELECTION_IMAGE_WIDTH + textWidth, y, m_right); + } else { + painter.setBrush(creatorTheme()->color(Theme::DoubleTabWidget2ndTabBackgroundColor)); + painter.setPen(Qt::NoPen); + painter.drawRoundedRect(QRect(x,y,2*SELECTION_IMAGE_WIDTH+textWidth, m_mid.height()), 5,5); + } + painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget2ndTabActiveTextColor)); } else { - painter.setPen(Qt::black); + painter.setPen(creatorTheme()->color(Theme::DoubleTabWidget2ndTabInactiveTextColor)); } x += SELECTION_IMAGE_WIDTH; painter.drawText(x, y + (imageHeight + fm.ascent()) / 2. - 1, diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 600e768d50..ba78e46eb0 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,7 @@ static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay) using namespace ProjectExplorer; using namespace ProjectExplorer::Internal; +using namespace Utils; static bool projectLesserThan(Project *p1, Project *p2) { @@ -133,17 +135,21 @@ void TargetSelectorDelegate::paint(QPainter *painter, selectionGradient.load(QLatin1String(":/projectexplorer/images/targetpanel_gradient.png")); if (option.state & QStyle::State_Selected) { - QColor color =(option.state & QStyle::State_HasFocus) ? - option.palette.highlight().color() : - option.palette.dark().color(); - painter->fillRect(option.rect, color.darker(140)); - Utils::StyleHelper::drawCornerImage(selectionGradient, painter, option.rect.adjusted(0, 0, 0, -1), 5, 5, 5, 5); - painter->setPen(QColor(255, 255, 255, 60)); - painter->drawLine(option.rect.topLeft(), option.rect.topRight()); - painter->setPen(QColor(255, 255, 255, 30)); - painter->drawLine(option.rect.bottomLeft() - QPoint(0,1), option.rect.bottomRight() - QPoint(0,1)); - painter->setPen(QColor(0, 0, 0, 80)); - painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight()); + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) { + painter->fillRect(option.rect, creatorTheme()->color(Theme::BackgroundColorSelected)); + } else { + QColor color =(option.state & QStyle::State_HasFocus) ? + option.palette.highlight().color() : + option.palette.dark().color(); + painter->fillRect(option.rect, color.darker(140)); + Utils::StyleHelper::drawCornerImage(selectionGradient, painter, option.rect.adjusted(0, 0, 0, -1), 5, 5, 5, 5); + painter->setPen(QColor(255, 255, 255, 60)); + painter->drawLine(option.rect.topLeft(), option.rect.topRight()); + painter->setPen(QColor(255, 255, 255, 30)); + painter->drawLine(option.rect.bottomLeft() - QPoint(0,1), option.rect.bottomRight() - QPoint(0,1)); + painter->setPen(QColor(0, 0, 0, 80)); + painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight()); + } } QFontMetrics fm(option.font); @@ -640,7 +646,7 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi m_hideOnRelease(false) { QPalette p; - p.setColor(QPalette::Text, QColor(255, 255, 255, 160)); + p.setColor(QPalette::Text, creatorTheme()->color(Theme::MiniProjectTargetSelectorTextColor)); setPalette(p); setProperty("panelwidget", true); setContentsMargins(QMargins(0, 1, 1, 8)); @@ -654,7 +660,8 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi m_summaryLabel = new QLabel(this); m_summaryLabel->setMargin(3); m_summaryLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); - m_summaryLabel->setStyleSheet(QString::fromLatin1("background: #464646;")); + m_summaryLabel->setStyleSheet(QString::fromLatin1("background: %1;") + .arg(creatorTheme()->color(Theme::MiniProjectTargetSelectorSummaryBackgroundColor).name())); m_summaryLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_summaryLabel->setTextInteractionFlags(m_summaryLabel->textInteractionFlags() | Qt::LinksAccessibleByMouse); @@ -1575,15 +1582,18 @@ void MiniProjectTargetSelector::updateSummary() void MiniProjectTargetSelector::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.setBrush(QBrush(QColor(160, 160, 160, 255))); + painter.setBrush(creatorTheme()->color(Theme::MiniProjectTargetSelectorBackgroundColor)); painter.drawRect(rect()); - painter.setPen(Utils::StyleHelper::borderColor()); + painter.setPen(creatorTheme()->color(Theme::MiniProjectTargetSelectorBackgroundColor)); + // draw border on top and right painter.drawLine(rect().topLeft(), rect().topRight()); painter.drawLine(rect().topRight(), rect().bottomRight()); - - QRect bottomRect(0, rect().height() - 8, rect().width(), 8); - static QImage image(QLatin1String(":/projectexplorer/images/targetpanel_bottom.png")); - Utils::StyleHelper::drawCornerImage(image, &painter, bottomRect, 1, 1, 1, 1); + if (creatorTheme()->flag(Theme::DrawTargetSelectorBottom)) { + // draw thicker border on the bottom + QRect bottomRect(0, rect().height() - 8, rect().width(), 8); + static QImage image(QLatin1String(":/projectexplorer/images/targetpanel_bottom.png")); + Utils::StyleHelper::drawCornerImage(image, &painter, bottomRect, 1, 1, 1, 1); + } } void MiniProjectTargetSelector::switchToProjectsMode() diff --git a/src/plugins/projectexplorer/panelswidget.cpp b/src/plugins/projectexplorer/panelswidget.cpp index 85506bb1d7..c379ad5986 100644 --- a/src/plugins/projectexplorer/panelswidget.cpp +++ b/src/plugins/projectexplorer/panelswidget.cpp @@ -36,6 +36,7 @@ #include #include +#include #include namespace { @@ -53,6 +54,7 @@ const int PANEL_LEFT_MARGIN = 70; /// \brief The OnePixelBlackLine class using namespace ProjectExplorer; +using namespace Utils; namespace { class OnePixelBlackLine : public QWidget @@ -69,8 +71,7 @@ public: { Q_UNUSED(e); QPainter p(this); - QColor fillColor = Utils::StyleHelper::mergedColors( - palette().button().color(), Qt::black, 80); + QColor fillColor = creatorTheme()->color(Theme::PanelsWidgetSeparatorLineColor); p.fillRect(contentsRect(), fillColor); } }; @@ -88,16 +89,19 @@ void RootWidget::paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); - QPainter painter(this); - QColor light = Utils::StyleHelper::mergedColors( - palette().button().color(), Qt::white, 30); - QColor dark = Utils::StyleHelper::mergedColors( - palette().button().color(), Qt::black, 85); - - painter.setPen(light); - painter.drawLine(rect().topRight(), rect().bottomRight()); - painter.setPen(dark); - painter.drawLine(rect().topRight() - QPoint(1,0), rect().bottomRight() - QPoint(1,0)); + if (creatorTheme()->widgetStyle() == Theme::StyleDefault) { + // draw separator line to the right of the settings panel + QPainter painter(this); + QColor light = Utils::StyleHelper::mergedColors( + palette().button().color(), Qt::white, 30); + QColor dark = Utils::StyleHelper::mergedColors( + palette().button().color(), Qt::black, 85); + + painter.setPen(light); + painter.drawLine(rect().topRight(), rect().bottomRight()); + painter.setPen(dark); + painter.drawLine(rect().topRight() - QPoint(1,0), rect().bottomRight() - QPoint(1,0)); + } } } @@ -176,6 +180,7 @@ void PanelsWidget::addPropertiesPanel(PropertiesPanel *panel) nameLabel->setText(panel->displayName()); QPalette palette = nameLabel->palette(); for (int i = QPalette::Active; i < QPalette::NColorGroups; ++i ) { + // FIXME: theming QColor foregroundColor = palette.color(QPalette::ColorGroup(i), QPalette::Foreground); foregroundColor.setAlpha(110); palette.setBrush(QPalette::ColorGroup(i), QPalette::Foreground, foregroundColor); diff --git a/src/plugins/qmakeprojectmanager/images/dark_headers.png b/src/plugins/qmakeprojectmanager/images/dark_headers.png new file mode 100644 index 0000000000..1cf8eab6f9 Binary files /dev/null and b/src/plugins/qmakeprojectmanager/images/dark_headers.png differ diff --git a/src/plugins/qmakeprojectmanager/images/dark_sources.png b/src/plugins/qmakeprojectmanager/images/dark_sources.png new file mode 100644 index 0000000000..c809be82ab Binary files /dev/null and b/src/plugins/qmakeprojectmanager/images/dark_sources.png differ diff --git a/src/plugins/qmakeprojectmanager/images/dark_unknown.png b/src/plugins/qmakeprojectmanager/images/dark_unknown.png new file mode 100644 index 0000000000..8bfd1fa3dc Binary files /dev/null and b/src/plugins/qmakeprojectmanager/images/dark_unknown.png differ diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp index 89cf2600da..0b5ae42613 100644 --- a/src/plugins/qmakeprojectmanager/profileeditor.cpp +++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ #include using namespace TextEditor; +using namespace Utils; namespace QmakeProjectManager { namespace Internal { @@ -222,9 +224,9 @@ ProFileEditorFactory::ProFileEditorFactory() addHoverHandler(new ProFileHoverHandler(keywords)); setSyntaxHighlighterCreator([keywords]() { return new ProFileHighlighter(keywords); }); - Core::FileIconProvider::registerIconOverlayForSuffix(QtSupport::Constants::ICON_QT_PROJECT, "pro"); - Core::FileIconProvider::registerIconOverlayForSuffix(QtSupport::Constants::ICON_QT_PROJECT, "pri"); - Core::FileIconProvider::registerIconOverlayForSuffix(QtSupport::Constants::ICON_QT_PROJECT, "prf"); + Core::FileIconProvider::registerIconOverlayForSuffix(creatorTheme()->iconOverlay(Theme::ProMimetype).toLatin1().data(), "pro"); + Core::FileIconProvider::registerIconOverlayForSuffix(creatorTheme()->iconOverlay(Theme::PriMimetype).toLatin1().data(), "pri"); + Core::FileIconProvider::registerIconOverlayForSuffix(creatorTheme()->iconOverlay(Theme::PrfMimetype).toLatin1().data(), "prf"); } } // namespace Internal diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index dc8efe1b11..085ce968d4 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,7 @@ #include using namespace Core; +using namespace Utils; // Static cached data in struct QmakeNodeStaticData providing information and icons // for file types and the project. Do some magic via qAddPostRoutine() @@ -150,7 +152,10 @@ QmakeNodeStaticData::QmakeNodeStaticData() const QSize desiredSize = QSize(16, 16); for (unsigned i = 0 ; i < count; ++i) { - const QIcon overlayIcon = QIcon(QLatin1String(fileTypeDataStorage[i].icon)); + QIcon overlayIcon; + QString iconFile = QString::fromLatin1(fileTypeDataStorage[i].icon); + iconFile = creatorTheme()->imageFile(iconFile); + overlayIcon = QIcon(iconFile); const QPixmap folderPixmap = Core::FileIconProvider::overlayIcon(QStyle::SP_DirIcon, overlayIcon, desiredSize); @@ -161,7 +166,8 @@ QmakeNodeStaticData::QmakeNodeStaticData() desc, folderIcon)); } // Project icon - const QIcon projectBaseIcon(QLatin1String(":/qtsupport/images/qt_project.png")); + const QLatin1String fname(":/qtsupport/images/qt_project.png"); + const QIcon projectBaseIcon(creatorTheme()->imageFile(fname)); const QPixmap projectPixmap = Core::FileIconProvider::overlayIcon(QStyle::SP_DirIcon, projectBaseIcon, desiredSize); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc index 6c6e8857d6..af8684afce 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc @@ -6,5 +6,8 @@ images/headers.png images/sources.png images/unknown.png + images/dark_headers.png + images/dark_sources.png + images/dark_unknown.png diff --git a/src/plugins/qtsupport/images/dark_forms.png b/src/plugins/qtsupport/images/dark_forms.png new file mode 100644 index 0000000000..c6c54c082f Binary files /dev/null and b/src/plugins/qtsupport/images/dark_forms.png differ diff --git a/src/plugins/qtsupport/images/dark_qml.png b/src/plugins/qtsupport/images/dark_qml.png new file mode 100644 index 0000000000..65f445a873 Binary files /dev/null and b/src/plugins/qtsupport/images/dark_qml.png differ diff --git a/src/plugins/qtsupport/images/dark_qt_project.png b/src/plugins/qtsupport/images/dark_qt_project.png new file mode 100644 index 0000000000..5f4df3aa35 Binary files /dev/null and b/src/plugins/qtsupport/images/dark_qt_project.png differ diff --git a/src/plugins/qtsupport/images/dark_qt_qrc.png b/src/plugins/qtsupport/images/dark_qt_qrc.png new file mode 100644 index 0000000000..81b68ba39f Binary files /dev/null and b/src/plugins/qtsupport/images/dark_qt_qrc.png differ diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp index 68983363bc..0e337590f5 100644 --- a/src/plugins/qtsupport/qtoutputformatter.cpp +++ b/src/plugins/qtsupport/qtoutputformatter.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ using namespace ProjectExplorer; using namespace QtSupport; +using namespace Utils; // "file" or "qrc", colon, optional '//', '/' and further characters #define QML_URL_REGEXP \ @@ -181,8 +183,7 @@ void QtOutputFormatter::appendLine(QTextCursor &cursor, const LinkResult &lr, cursor.insertText(line.left(lr.start), normalFormat); QTextCharFormat linkFormat = normalFormat; - const QColor textColor = plainTextEdit()->palette().color(QPalette::Text); - linkFormat.setForeground(mixColors(textColor, QColor(Qt::blue))); + linkFormat.setForeground(creatorTheme()->color(Theme::QtOutputFormatter_LinkTextColor)); linkFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); linkFormat.setAnchor(true); linkFormat.setAnchorHref(lr.href); diff --git a/src/plugins/qtsupport/qtsupport.qrc b/src/plugins/qtsupport/qtsupport.qrc index 351b129134..e97078e35b 100644 --- a/src/plugins/qtsupport/qtsupport.qrc +++ b/src/plugins/qtsupport/qtsupport.qrc @@ -4,6 +4,10 @@ images/qml.png images/qt_project.png images/qt_qrc.png + images/dark_forms.png + images/dark_qml.png + images/dark_qt_project.png + images/dark_qt_qrc.png QtSupport.mimetypes.xml diff --git a/src/plugins/qtsupport/qtsupportconstants.h b/src/plugins/qtsupport/qtsupportconstants.h index 343d6865aa..dae80d1012 100644 --- a/src/plugins/qtsupport/qtsupportconstants.h +++ b/src/plugins/qtsupport/qtsupportconstants.h @@ -100,6 +100,7 @@ const char IOS_PLATFORM_TR[] = QT_TRANSLATE_NOOP("QtSupport", "iOS"); const char QML_WIZARD_ICON[] = ":/qmlproject/images/qml_wizard.png"; const char ICON_QT_PROJECT[] = ":/qtsupport/images/qt_project.png"; +const char DARK_ICON_QT_PROJECT[] = ":/qtsupport/images/dark_qt_project.png"; } // namepsace Constants } // namepsace QtSupport diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index c7512b961b..82bddcaac5 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -2509,7 +2509,13 @@ bool TextEditorWidget::event(QEvent *e) e->ignore(); // we are a really nice citizen d->m_maybeFakeTooltipEvent = false; return true; - break; + case QEvent::ApplicationPaletteChange: { + // slight hack: ignore palette changes + // at this point the palette has changed already, + // so undo it by re-setting the palette: + applyFontSettings(); + return true; + } default: break; } diff --git a/src/plugins/todo/todoitemsmodel.cpp b/src/plugins/todo/todoitemsmodel.cpp index 4822928d05..183f1d927e 100644 --- a/src/plugins/todo/todoitemsmodel.cpp +++ b/src/plugins/todo/todoitemsmodel.cpp @@ -34,8 +34,12 @@ #include +#include + #include +using namespace Utils; + namespace Todo { namespace Internal { @@ -83,6 +87,10 @@ QVariant TodoItemsModel::data(const QModelIndex &index, int role) const if (role == Qt::BackgroundColorRole) return item.color; + if (role == Qt::TextColorRole) + return creatorTheme()->color(Theme::TodoItemTextColor); + if (role == Qt::ForegroundRole) + return creatorTheme()->color(Theme::TodoItemTextColor); switch (index.column()) { diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index e84fcd233b..e1e0b1595c 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -44,6 +44,9 @@ #include #include +#include +#include + #include #include @@ -86,6 +89,8 @@ public: // bool eventFilter(QObject *, QEvent *); public slots: + void onThemeChanged(); + void setActivePlugin(int pos) { if (m_activePlugin != pos) { @@ -108,11 +113,13 @@ private: QuickContainer *m_welcomePage; QList m_pluginList; int m_activePlugin; + WelcomeTheme *m_welcomeTheme; }; // --- WelcomeMode WelcomeMode::WelcomeMode() : - m_activePlugin(0) + m_activePlugin(0), + m_welcomeTheme(new WelcomeTheme(this)) { setDisplayName(tr("Welcome")); setIcon(QIcon(QLatin1String(":/welcome/images/mode_welcome.png"))); @@ -128,6 +135,7 @@ WelcomeMode::WelcomeMode() : layout->setSpacing(0); m_welcomePage = new QuickContainer(); + onThemeChanged(); //initialize background color m_welcomePage->setResizeMode(QuickContainer::SizeRootObjectToView); m_welcomePage->setObjectName(QLatin1String("WelcomePage")); @@ -154,6 +162,12 @@ WelcomeMode::WelcomeMode() : setWidget(m_modeWidget); } +void WelcomeMode::onThemeChanged() +{ + m_welcomePage->setColor(creatorTheme()->color(Theme::BackgroundColorNormal)); + m_welcomeTheme->notifyThemeChanged(); +} + WelcomeMode::~WelcomeMode() { QSettings *settings = Core::ICore::settings(); @@ -243,6 +257,15 @@ void WelcomeMode::initPlugins() ctx->setContextProperty(QLatin1String("pagesModel"), QVariant::fromValue(m_pluginList)); + connect(creatorTheme(), &Theme::changed, this, &WelcomeMode::onThemeChanged); + ctx->setContextProperty(QLatin1String("creatorTheme"), m_welcomeTheme); + + // FIXME: pass theme class to QML somehow + if (creatorTheme()->widgetStyle() == Theme::StyleFlat) + ctx->setContextProperty(QLatin1String("theme"), QLatin1String("dark")); + else + ctx->setContextProperty(QLatin1String("theme"), QLatin1String("default")); + QString path = resourcePath() + QLatin1String("/welcomescreen/welcomescreen.qml"); // finally, load the root page -- cgit v1.2.1