diff options
94 files changed, 4139 insertions, 363 deletions
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/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 <utils/hostosinfo.h> +#include "hostosinfo.h" +#include "theme/theme.h" #include <QGraphicsOpacityEffect> #include <QGuiApplication> @@ -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 <QGridLayout> #include <QLabel> @@ -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 <QPlainTextEdit> -#include <utils/ansiescapecodehandler.h> 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 <thorbenkroeger@gmail.com>. +** 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 <QApplication> +#include <QFileInfo> +#include <QMetaEnum> +#include <QSettings> + +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<QColor, QString> 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<QColor, QString> 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<QColor, QString> 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<Theme::GradientRole>(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<Theme::MimeType>(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<Theme::Flag>(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<Theme::WidgetStyle>(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 <thorbenkroeger@gmail.com>. +** 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 <QStyle> +#include <QFlags> + +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<QColor, QString> 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 <thorbenkroeger@gmail.com>. +** 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 <QMetaEnum> + +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 <thorbenkroeger@gmail.com>. +** 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 <QColor> +#include <QMap> + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT ThemePrivate +{ +public: + ThemePrivate(); + + QString fileName; + QString name; + QVector<QPair<QColor, QString> > colors; + QVector<QString> iconOverlays; + QVector<QGradientStops> gradientStops; + QVector<bool> flags; + Theme::WidgetStyle widgetStyle; + QMap<QString, QColor> 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 <thorbenkroeger@gmail.com>. +** 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 <thorbenkroeger@gmail.com>. +** 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 <QStyle> + +#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 @@ -205,6 +205,19 @@ QtcLibrary { ] 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/" files: [ 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 @@ -23,6 +23,11 @@ \"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 @@ <file>images/locked@2x.png</file> <file>images/magnifier.png</file> <file>images/magnifier@2x.png</file> + <file>images/dark_magnifier.png</file> + <file>images/dark_magnifier@2x.png</file> <file>images/minus.png</file> <file>images/next.png</file> <file>images/panel_button.png</file> @@ -103,5 +105,7 @@ <file>images/warning@2x.png</file> <file>images/info.png</file> <file>images/info@2x.png</file> + <file>images/dark_fileicon.png</file> + <file>images/dark_foldericon.png</file> </qresource> </RCC> 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 <coreplugin/editormanager/editormanager.h> #include <coreplugin/find/findplugin.h> #include <coreplugin/locator/locator.h> +#include <coreplugin/coreconstants.h> #include <utils/macroexpander.h> #include <utils/savefile.h> +#include <utils/stringutils.h> +#include <utils/theme/theme.h> #include <QtPlugin> #include <QDebug> #include <QDateTime> +#include <QDir> 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<Core::Id>(); - 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 <coreplugin/editormanager/ieditor.h> #include <coreplugin/findplaceholder.h> #include <utils/qtcassert.h> +#include <utils/theme/theme.h> #include <QDebug> @@ -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 <utils/stringutils.h> #include <utils/tooltip/tooltip.h> #include <utils/tooltip/tipcontents.h> +#include <utils/theme/theme.h> #include <QPainter> #include <QVBoxLayout> @@ -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 <utils/hostosinfo.h> #include <utils/stylehelper.h> #include <utils/styledbar.h> +#include <utils/theme/theme.h> #include <QDebug> @@ -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 <aggregation/aggregate.h> #include <coreplugin/coreplugin.h> +#include <utils/theme/theme.h> #include <QDir> #include <QFrame> @@ -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 Binary files differnew file mode 100644 index 0000000000..3581d3331f --- /dev/null +++ b/src/plugins/coreplugin/images/dark_fileicon.png diff --git a/src/plugins/coreplugin/images/dark_foldericon.png b/src/plugins/coreplugin/images/dark_foldericon.png Binary files differnew file mode 100644 index 0000000000..dc7a50431e --- /dev/null +++ b/src/plugins/coreplugin/images/dark_foldericon.png diff --git a/src/plugins/coreplugin/images/dark_magnifier.png b/src/plugins/coreplugin/images/dark_magnifier.png Binary files differnew file mode 100644 index 0000000000..322a542a0e --- /dev/null +++ b/src/plugins/coreplugin/images/dark_magnifier.png diff --git a/src/plugins/coreplugin/images/dark_magnifier@2x.png b/src/plugins/coreplugin/images/dark_magnifier@2x.png Binary files differnew file mode 100644 index 0000000000..ed82c37dd0 --- /dev/null +++ b/src/plugins/coreplugin/images/dark_magnifier@2x.png 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 <utils/hostosinfo.h> #include <utils/qtcassert.h> #include <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <utils/stringutils.h> #include <extensionsystem/pluginmanager.h> @@ -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<QWidget *, IContext *> 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 <utils/stylehelper.h> #include <utils/fancymainwindow.h> +#include <utils/theme/theme.h> #include <QApplication> #include <QComboBox> @@ -53,6 +54,8 @@ #include <QToolBar> #include <QToolButton> +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<const QStyleOptionMenuItem *>(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 <utils/styledbar.h> #include <utils/stylehelper.h> #include <utils/qtcassert.h> +#include <utils/theme/theme.h> #include <QDebug> @@ -65,6 +66,8 @@ #include <QToolButton> #include <QTimeLine> +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 <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <QCoreApplication> #include <QFutureWatcher> @@ -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 <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <QPropertyAnimation> #include <QPainter> @@ -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 <utils/hostosinfo.h> #include <utils/qtcassert.h> #include <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <QAction> #include <QEvent> @@ -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 <thorbenkroeger@gmail.com>. +** 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> colorVariable) + : m_roleName(roleName), + m_roleVariable(colorVariable) +{ + m_roleVariable->addReference(this); +} + +QSharedPointer<ColorVariable> 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 <thorbenkroeger@gmail.com>. +** 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 <QString> +#include <QColor> +#include <QSharedPointer> + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ColorVariable; +class ThemeColors; + +class ColorRole +{ +public: + friend class ThemeColors; + + typedef QSharedPointer<ColorRole> Ptr; + + QString roleName() const { return m_roleName; } + QSharedPointer<ColorVariable> colorVariable() const; + void assignColorVariable(QSharedPointer<ColorVariable> colorVariable); + +private: + explicit ColorRole(const QString &roleName, QSharedPointer<ColorVariable> colorVariable); + QString m_roleName; + QString m_roleDescription; + QSharedPointer<ColorVariable> 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 <thorbenkroeger@gmail.com>. +** 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 <utils/qtcassert.h> + +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<ColorRole *> 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 <thorbenkroeger@gmail.com>. +** 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 <QSharedPointer> +#include <QColor> +#include <QString> +#include <QSet> + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ColorRole; +class ThemeColors; + +class ColorVariable +{ +public: + friend class ThemeColors; + typedef QSharedPointer<ColorVariable> 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<ColorRole *> references() const; + +private: + explicit ColorVariable(const QColor &color, const QString &variableName = QString()); + QColor m_variableValue; + QString m_variableName; + QSet<ColorRole *> 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 <thorbenkroeger@gmail.com>. +** 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 <QSize> + +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 <thorbenkroeger@gmail.com>. +** 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 <QAbstractTableModel> + +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 <thorbenkroeger@gmail.com>. +** 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 <utils/qtcassert.h> + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +QSharedPointer<ColorVariable> 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> 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<QSharedPointer<ColorVariable> > ThemeColors::colorVariables() +{ + return m_colorVariables; +} + +void ThemeColors::removeVariable(QSharedPointer<ColorVariable> 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 <thorbenkroeger@gmail.com>. +** 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 <QSet> + +namespace Core { +namespace Internal { +namespace ThemeEditor { + +class ColorVariable; + +class ThemeColors +{ +public: + typedef QSharedPointer<ThemeColors> Ptr; + + int numColorRoles() const { return m_colorRoles.size(); } + ColorRole::Ptr const colorRole(int index) { return m_colorRoles.at(index); } + + QSharedPointer<ColorVariable> createVariable(const QColor &variableColor, const QString &variableName = QString()); + ColorRole::Ptr createRole(const QString &roleName, QSharedPointer<ColorVariable> colorVariable); + + QSet<QSharedPointer<ColorVariable> > colorVariables(); + + void removeVariable(QSharedPointer<ColorVariable> variable); + +private: + void insert(ColorRole::Ptr color); + void insert(QSharedPointer<ColorVariable> color); + + QList<ColorRole::Ptr> m_colorRoles; + QSet<QSharedPointer<ColorVariable> > 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 <thorbenkroeger@gmail.com>. +** 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 <QMouseEvent> + +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<ThemeSettingsItemDelegate *>(itemDelegate())->popupMenu(); + } + } + QTreeView::mousePressEvent(event); +} + +} // namespace ThemeEditor +} // namespace Internal +} // namespace Core diff --git a/share/qtcreator/welcomescreen/widgets/CustomColors.qml b/src/plugins/coreplugin/themeeditor/themecolorstableview.h index 5ee98e6f13..346caf250d 100644 --- a/share/qtcreator/welcomescreen/widgets/CustomColors.qml +++ b/src/plugins/coreplugin/themeeditor/themecolorstableview.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Thorben Kroeger <thorbenkroeger@gmail.com>. ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. @@ -28,11 +28,28 @@ ** ****************************************************************************/ -import QtQuick 2.1 +#ifndef THEMECOLORSTABLEVIEW_H +#define THEMECOLORSTABLEVIEW_H -QtObject { - property color linkColor: "#328930" - //property color linkColor: "#70b332" - //property color strongForegroundColor: "#58595b" - property color strongForegroundColor: "#328930" -} +#include <QTreeView> + +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 <thorbenkroeger@gmail.com>. +** 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 <QAbstractButton> +#include <QAbstractItemModel> +#include <QColorDialog> +#include <QDir> +#include <QFileInfo> +#include <QMetaEnum> +#include <QSortFilterProxyModel> +#include <QTimer> +#include <QSharedPointer> +#include <QWeakPointer> + +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<void (QSortFilterProxyModel:: *)(const QString &)>(&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 <thorbenkroeger@gmail.com>. +** 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 <QWidget> + +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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Core::Internal::ThemeEditor::ThemeEditorWidget</class> + <widget class="QWidget" name="Core::Internal::ThemeEditor::ThemeEditorWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Theme Editor</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="filter"/> + </item> + </layout> + </item> + <item> + <widget class="Core::Internal::ThemeEditor::ThemeColorsTableView" name="tableView"/> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Core::Internal::ThemeEditor::ThemeColorsTableView</class> + <extends>QTableView</extends> + <header location="global">coreplugin/themeeditor/themecolorstableview.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> 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 <thorbenkroeger@gmail.com>. +** 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 <utils/qtcassert.h> +#include <utils/theme/theme.h> + +#include <QAbstractProxyModel> +#include <QComboBox> +#include <QEvent> +#include <QInputDialog> +#include <QMetaEnum> + +using namespace Utils; + +static QAbstractItemModel *sourceModel(QAbstractItemModel *model) +{ + if (QAbstractProxyModel *m = qobject_cast<QAbstractProxyModel *>(model)) + return m->sourceModel(); + return model; +} + +static const QAbstractItemModel *sourceModel(const QAbstractItemModel *model) +{ + if (const QAbstractProxyModel *m = qobject_cast<const QAbstractProxyModel *>(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<const ThemeSettingsTableModel*>(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("<unnamed> (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<ColorVariable>(0)); + } + cb->addItem(tr("Create new name...")); + m_actions[k++] = qMakePair(Action_CreateNew, QSharedPointer<ColorVariable>(0)); + + connect(cb, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), + this, [this, cb]() { + ThemeSettingsItemDelegate *me = const_cast<ThemeSettingsItemDelegate *>(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<const ThemeSettingsTableModel*>(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<void (QComboBox::*)(int)>(&QComboBox::activated), + this, [this, cb]() { + ThemeSettingsItemDelegate *me = const_cast<ThemeSettingsItemDelegate *>(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<ThemeSettingsTableModel *>(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<QComboBox *>(editor)) + themeSettingsModel->m_widgetStyle = static_cast<Theme::WidgetStyle>(cb->currentIndex()); + return; + case ThemeSettingsTableModel::SectionColors: { + if (QComboBox *cb = qobject_cast<QComboBox *>(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 <thorbenkroeger@gmail.com>. +** 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 <QStyledItemDelegate> + +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<int, QPair<Action, ColorVariable::Ptr> > 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 <thorbenkroeger@gmail.com>. +** 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 <utils/qtcassert.h> +#include <utils/theme/theme.h> +#include <utils/theme/theme_p.h> + +#include <QApplication> +#include <QImage> +#include <QMetaEnum> +#include <QPainter> +#include <QPalette> + +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>(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>(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>(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>(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>(section)) { + case SectionFlags: { + Qt::CheckState checkState = static_cast<Qt::CheckState>(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<QString, ColorVariable::Ptr> varLookup; + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QPair<QColor, QString> c = theme->d->colors[static_cast<Theme::ColorRole>(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<Theme::Flag>(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<Theme::MimeType>(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 <thorbenkroeger@gmail.com>. +** 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 <QAbstractTableModel> + +#include "themecolors.h" +#include "sectionedtablemodel.h" +#include <utils/theme/theme.h> + +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<QPair<QString, bool> > m_flags; + QList<QPair<QString, QString> > 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 <thorbenkroeger@gmail.com>. +** 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 <utils/qtcassert.h> + +#include <QDebug> +#include <QDir> +#include <QInputDialog> +#include <QMessageBox> +#include <QSettings> + +#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<ThemeEntry> &themes) + { + beginResetModel(); + m_themes = themes; + endResetModel(); + } + + const ThemeEntry &themeAt(int index) const + { + return m_themes.at(index); + } + +private: + QList<ThemeEntry> m_themes; +}; + + +class ThemeSettingsPrivate +{ +public: + ThemeSettingsPrivate(); + ~ThemeSettingsPrivate(); + +public: + ThemeListModel *m_themeListModel; + bool m_refreshingThemeList; + Ui::ThemeSettings *m_ui; + QPointer<QWidget> 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<ThemeEntry> 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<void(QComboBox::*)(int)>(&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<QPushButton*>(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<QPushButton*>(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 <thorbenkroeger@gmail.com>. +** 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 <coreplugin/dialogs/ioptionspage.h> + +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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Core::Internal::ThemeSettings</class> + <widget class="QWidget" name="Core::Internal::ThemeSettings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>527</width> + <height>359</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QComboBox" name="themeComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="renameButton"> + <property name="text"> + <string>Rename...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="copyButton"> + <property name="text"> + <string>Copy...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="deleteButton"> + <property name="text"> + <string>Delete</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Core::Internal::ThemeEditor::ThemeEditorWidget" name="editor" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Core::Internal::ThemeEditor::ThemeEditorWidget</class> + <extends>QWidget</extends> + <header location="global">coreplugin/themeeditor/themeeditorwidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources> + <include location="core.qrc"/> + </resources> + <connections/> +</ui> 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 @@ <file>images/qt_h.png</file> <file>CppEditor.mimetypes.xml</file> <file>images/qt_c.png</file> + <file>images/dark_qt_cpp.png</file> + <file>images/dark_qt_h.png</file> + <file>images/dark_qt_c.png</file> </qresource> </RCC> 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 <utils/hostosinfo.h> +#include <utils/theme/theme.h> + #include <QCoreApplication> #include <QStringList> 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 Binary files differnew file mode 100644 index 0000000000..269b5e3938 --- /dev/null +++ b/src/plugins/cppeditor/images/dark_qt_c.png diff --git a/src/plugins/cppeditor/images/dark_qt_cpp.png b/src/plugins/cppeditor/images/dark_qt_cpp.png Binary files differnew file mode 100644 index 0000000000..c809be82ab --- /dev/null +++ b/src/plugins/cppeditor/images/dark_qt_cpp.png diff --git a/src/plugins/cppeditor/images/dark_qt_h.png b/src/plugins/cppeditor/images/dark_qt_h.png Binary files differnew file mode 100644 index 0000000000..1cf8eab6f9 --- /dev/null +++ b/src/plugins/cppeditor/images/dark_qt_h.png 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 <utils/hostosinfo.h> #include <utils/qtcassert.h> #include <utils/styledbar.h> +#include <utils/theme/theme.h> #include <QDir> #include <QFileInfo> @@ -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("<html><head><title>No Documentation</title>" - "</head><body><br/><center><b>%1</b><br/>No documentation " - "available.</center></body></html>").arg(idFromContext)); + "</head><body><br/><center>" + "<font color=\"%1\"><b>%2</b></font><br/>" + "<font color=\"%3\">No documentation available.</font>" + "</center></body></html>") + .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 <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <QRect> #include <QPainter> @@ -42,6 +43,7 @@ #include <QDebug> 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 <utils/algorithm.h> #include <utils/styledbar.h> #include <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> @@ -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 <QLabel> #include <utils/stylehelper.h> +#include <utils/theme/theme.h> #include <utils/qtcassert.h> 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 Binary files differnew file mode 100644 index 0000000000..1cf8eab6f9 --- /dev/null +++ b/src/plugins/qmakeprojectmanager/images/dark_headers.png diff --git a/src/plugins/qmakeprojectmanager/images/dark_sources.png b/src/plugins/qmakeprojectmanager/images/dark_sources.png Binary files differnew file mode 100644 index 0000000000..c809be82ab --- /dev/null +++ b/src/plugins/qmakeprojectmanager/images/dark_sources.png diff --git a/src/plugins/qmakeprojectmanager/images/dark_unknown.png b/src/plugins/qmakeprojectmanager/images/dark_unknown.png Binary files differnew file mode 100644 index 0000000000..8bfd1fa3dc --- /dev/null +++ b/src/plugins/qmakeprojectmanager/images/dark_unknown.png 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 <qtsupport/qtsupportconstants.h> #include <texteditor/texteditoractionhandler.h> #include <utils/qtcassert.h> +#include <utils/theme/theme.h> #include <QCoreApplication> #include <QFileInfo> @@ -49,6 +50,7 @@ #include <QTextBlock> 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 <utils/algorithm.h> #include <utils/hostosinfo.h> #include <utils/stringutils.h> +#include <utils/theme/theme.h> #include <proparser/prowriter.h> #include <proparser/qmakevfs.h> @@ -73,6 +74,7 @@ #include <utils/QtConcurrentTools> 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 @@ <file>images/headers.png</file> <file>images/sources.png</file> <file>images/unknown.png</file> + <file>images/dark_headers.png</file> + <file>images/dark_sources.png</file> + <file>images/dark_unknown.png</file> </qresource> </RCC> diff --git a/src/plugins/qtsupport/images/dark_forms.png b/src/plugins/qtsupport/images/dark_forms.png Binary files differnew file mode 100644 index 0000000000..c6c54c082f --- /dev/null +++ b/src/plugins/qtsupport/images/dark_forms.png diff --git a/src/plugins/qtsupport/images/dark_qml.png b/src/plugins/qtsupport/images/dark_qml.png Binary files differnew file mode 100644 index 0000000000..65f445a873 --- /dev/null +++ b/src/plugins/qtsupport/images/dark_qml.png diff --git a/src/plugins/qtsupport/images/dark_qt_project.png b/src/plugins/qtsupport/images/dark_qt_project.png Binary files differnew file mode 100644 index 0000000000..5f4df3aa35 --- /dev/null +++ b/src/plugins/qtsupport/images/dark_qt_project.png diff --git a/src/plugins/qtsupport/images/dark_qt_qrc.png b/src/plugins/qtsupport/images/dark_qt_qrc.png Binary files differnew file mode 100644 index 0000000000..81b68ba39f --- /dev/null +++ b/src/plugins/qtsupport/images/dark_qt_qrc.png 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 <coreplugin/editormanager/editormanager.h> #include <projectexplorer/project.h> +#include <utils/theme/theme.h> #include <QPlainTextEdit> #include <QTextCursor> @@ -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 @@ <file>images/qml.png</file> <file>images/qt_project.png</file> <file>images/qt_qrc.png</file> + <file>images/dark_forms.png</file> + <file>images/dark_qml.png</file> + <file>images/dark_qt_project.png</file> + <file>images/dark_qt_qrc.png</file> <file>QtSupport.mimetypes.xml</file> </qresource> </RCC> 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 <utils/algorithm.h> +#include <utils/theme/theme.h> + #include <QIcon> +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 <utils/styledbar.h> #include <utils/iwelcomepage.h> +#include <utils/theme/theme.h> +#include <utils/theme/welcometheme.h> + #include <QVBoxLayout> #include <QMessageBox> @@ -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<QObject*> 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 |