aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThorben Kroeger <thorbenkroeger@gmail.com>2014-10-14 19:09:48 +0200
committerhjk <hjk121@nokiamail.com>2014-10-15 17:21:10 +0200
commit84f5585b5d958c3cdad4cce93244d43a360352c2 (patch)
treebeee12b956afd5cb86ad0cc03d73e3144a426f61 /src
parentfd8fcd29a1d70a10864fc5a6e5c6dc5cf1c96ecf (diff)
Implement theming for QtCreator
Adds a 'Theme' tab to the environment settings and a '-theme' command line option. A theme is a combination of colors, gradients, flags and style information. There are two themes: - 'default': preserves the current default look - 'dark': uses a more flat for many widgets, dark color theme for everything This does not use a stylesheet (too limited), but rather sets the palette via C++ and modifies drawing behavior. Overall, the look is more flat (removed some gradients and bevels). Tested on Ubuntu 14.04 using Qt 5.4 and running on a KDE Desktop (Oxygen base style). For a screenshot, see https://gist.github.com/thorbenk/5ab06bea726de0aa7473 Changes: - Introduce class Theme, defining the interface how to access theme specific settings. The class reads a .creatortheme file (INI file, via QSettings) - Define named colors in the [Palette] section (see dark.creatortheme for example usage) - Use either named colors of AARRGGBB (hex) in the [Colors] section - A file ending with .creatortheme may be supplied to the '-theme' command line option - A global Theme instance can be accessed via creatorTheme() - Query colors, gradients, icons and flags from the theme were possible (TODO: use this in more places...) - There are very many color roles. It seems better to me to describe the role clearly, and then to consolidate later in the actual theme by assigning the same color. For example, one can set the text color of the output pane button individualy. - Many elements are also drawn differently. For the dark theme, I wanted to have a flatter look. - Introduce Theme::WidgetStyle enum, for now {Original, Flat}. - The theme specifies which kind of widget style it wants. - The drawing code queries the theme's style flag and switches between the original, gradient based look and the new, flat look. - Create some custom icons which look better on dark background (wip, currently folder/file icons) - Let ManhattanStyle draw some elements for non-panelwidgets, too (open/close arrows in QTreeView, custom folder/file icons) - For the welcomescreen, pass the WelcomeTheme class. WelcomeTheme exposes theme colors as Q_PROPERTY accessible from .qml - Themes can be modified via the 'Themes' tab in the environment settings. TODO: * Unify image handling * Avoid style name references * Fix gradients Change-Id: I92c2050ab0fb327649ea1eff4adec973d2073944 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com> Reviewed-by: hjk <hjk121@nokiamail.com>
Diffstat (limited to 'src')
-rw-r--r--src/libs/utils/detailsbutton.cpp54
-rw-r--r--src/libs/utils/detailswidget.cpp32
-rw-r--r--src/libs/utils/outputformatter.cpp21
-rw-r--r--src/libs/utils/outputformatter.h2
-rw-r--r--src/libs/utils/theme/theme.cpp356
-rw-r--r--src/libs/utils/theme/theme.h217
-rw-r--r--src/libs/utils/theme/theme_p.cpp47
-rw-r--r--src/libs/utils/theme/theme_p.h59
-rw-r--r--src/libs/utils/theme/welcometheme.cpp87
-rw-r--r--src/libs/utils/theme/welcometheme.h87
-rw-r--r--src/libs/utils/utils-lib.pri10
-rw-r--r--src/libs/utils/utils.qbs13
-rw-r--r--src/plugins/coreplugin/Core.json.in5
-rw-r--r--src/plugins/coreplugin/core.qrc4
-rw-r--r--src/plugins/coreplugin/coreconstants.h3
-rw-r--r--src/plugins/coreplugin/coreplugin.cpp59
-rw-r--r--src/plugins/coreplugin/coreplugin.pro26
-rw-r--r--src/plugins/coreplugin/coreplugin.qbs24
-rw-r--r--src/plugins/coreplugin/editormanager/editorview.cpp19
-rw-r--r--src/plugins/coreplugin/fancyactionbar.cpp62
-rw-r--r--src/plugins/coreplugin/fancytabwidget.cpp100
-rw-r--r--src/plugins/coreplugin/find/searchresultwidget.cpp21
-rw-r--r--src/plugins/coreplugin/images/dark_fileicon.pngbin0 -> 288 bytes
-rw-r--r--src/plugins/coreplugin/images/dark_foldericon.pngbin0 -> 265 bytes
-rw-r--r--src/plugins/coreplugin/images/dark_magnifier.pngbin0 -> 488 bytes
-rw-r--r--src/plugins/coreplugin/images/dark_magnifier@2x.pngbin0 -> 589 bytes
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp8
-rw-r--r--src/plugins/coreplugin/mainwindow.h3
-rw-r--r--src/plugins/coreplugin/manhattanstyle.cpp114
-rw-r--r--src/plugins/coreplugin/manhattanstyle.h4
-rw-r--r--src/plugins/coreplugin/outputpanemanager.cpp59
-rw-r--r--src/plugins/coreplugin/progressmanager/futureprogress.cpp11
-rw-r--r--src/plugins/coreplugin/progressmanager/progressbar.cpp33
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanager.cpp7
-rw-r--r--src/plugins/coreplugin/themeeditor/colorrole.cpp58
-rw-r--r--src/plugins/coreplugin/themeeditor/colorrole.h67
-rw-r--r--src/plugins/coreplugin/themeeditor/colorvariable.cpp73
-rw-r--r--src/plugins/coreplugin/themeeditor/colorvariable.h77
-rw-r--r--src/plugins/coreplugin/themeeditor/sectionedtablemodel.cpp124
-rw-r--r--src/plugins/coreplugin/themeeditor/sectionedtablemodel.h69
-rw-r--r--src/plugins/coreplugin/themeeditor/themecolors.cpp76
-rw-r--r--src/plugins/coreplugin/themeeditor/themecolors.h71
-rw-r--r--src/plugins/coreplugin/themeeditor/themecolorstableview.cpp62
-rw-r--r--src/plugins/coreplugin/themeeditor/themecolorstableview.h55
-rw-r--r--src/plugins/coreplugin/themeeditor/themeeditorwidget.cpp142
-rw-r--r--src/plugins/coreplugin/themeeditor/themeeditorwidget.h78
-rw-r--r--src/plugins/coreplugin/themeeditor/themeeditorwidget.ui45
-rw-r--r--src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.cpp227
-rw-r--r--src/plugins/coreplugin/themeeditor/themesettingsitemdelegate.h78
-rw-r--r--src/plugins/coreplugin/themeeditor/themesettingstablemodel.cpp297
-rw-r--r--src/plugins/coreplugin/themeeditor/themesettingstablemodel.h94
-rw-r--r--src/plugins/coreplugin/themesettings.cpp465
-rw-r--r--src/plugins/coreplugin/themesettings.h72
-rw-r--r--src/plugins/coreplugin/themesettings.ui73
-rw-r--r--src/plugins/cppeditor/cppeditor.qrc3
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.cpp9
-rw-r--r--src/plugins/cppeditor/images/dark_qt_c.pngbin0 -> 341 bytes
-rw-r--r--src/plugins/cppeditor/images/dark_qt_cpp.pngbin0 -> 266 bytes
-rw-r--r--src/plugins/cppeditor/images/dark_qt_h.pngbin0 -> 502 bytes
-rw-r--r--src/plugins/help/helpplugin.cpp11
-rw-r--r--src/plugins/projectexplorer/doubletabwidget.cpp146
-rw-r--r--src/plugins/projectexplorer/miniprojecttargetselector.cpp48
-rw-r--r--src/plugins/projectexplorer/panelswidget.cpp29
-rw-r--r--src/plugins/qmakeprojectmanager/images/dark_headers.pngbin0 -> 502 bytes
-rw-r--r--src/plugins/qmakeprojectmanager/images/dark_sources.pngbin0 -> 266 bytes
-rw-r--r--src/plugins/qmakeprojectmanager/images/dark_unknown.pngbin0 -> 356 bytes
-rw-r--r--src/plugins/qmakeprojectmanager/profileeditor.cpp8
-rw-r--r--src/plugins/qmakeprojectmanager/qmakenodes.cpp10
-rw-r--r--src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc3
-rw-r--r--src/plugins/qtsupport/images/dark_forms.pngbin0 -> 565 bytes
-rw-r--r--src/plugins/qtsupport/images/dark_qml.pngbin0 -> 287 bytes
-rw-r--r--src/plugins/qtsupport/images/dark_qt_project.pngbin0 -> 186 bytes
-rw-r--r--src/plugins/qtsupport/images/dark_qt_qrc.pngbin0 -> 424 bytes
-rw-r--r--src/plugins/qtsupport/qtoutputformatter.cpp5
-rw-r--r--src/plugins/qtsupport/qtsupport.qrc4
-rw-r--r--src/plugins/qtsupport/qtsupportconstants.h1
-rw-r--r--src/plugins/texteditor/texteditor.cpp8
-rw-r--r--src/plugins/todo/todoitemsmodel.cpp8
-rw-r--r--src/plugins/welcome/welcomeplugin.cpp25
79 files changed, 3853 insertions, 315 deletions
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
new file mode 100644
index 0000000000..3581d3331f
--- /dev/null
+++ b/src/plugins/coreplugin/images/dark_fileicon.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/dark_foldericon.png b/src/plugins/coreplugin/images/dark_foldericon.png
new file mode 100644
index 0000000000..dc7a50431e
--- /dev/null
+++ b/src/plugins/coreplugin/images/dark_foldericon.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/dark_magnifier.png b/src/plugins/coreplugin/images/dark_magnifier.png
new file mode 100644
index 0000000000..322a542a0e
--- /dev/null
+++ b/src/plugins/coreplugin/images/dark_magnifier.png
Binary files differ
diff --git a/src/plugins/coreplugin/images/dark_magnifier@2x.png b/src/plugins/coreplugin/images/dark_magnifier@2x.png
new file mode 100644
index 0000000000..ed82c37dd0
--- /dev/null
+++ b/src/plugins/coreplugin/images/dark_magnifier@2x.png
Binary files differ
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 0cfebe0951..dbff065a40 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -37,6 +37,7 @@
#include "fancytabwidget.h"
#include "documentmanager.h"
#include "generalsettings.h"
+#include "themesettings.h"
#include "helpmanager.h"
#include "idocumentfactory.h"
#include "messagemanager.h"
@@ -78,6 +79,7 @@
#include <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/src/plugins/coreplugin/themeeditor/themecolorstableview.h b/src/plugins/coreplugin/themeeditor/themecolorstableview.h
new file mode 100644
index 0000000000..346caf250d
--- /dev/null
+++ b/src/plugins/coreplugin/themeeditor/themecolorstableview.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Thorben Kroeger <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 THEMECOLORSTABLEVIEW_H
+#define THEMECOLORSTABLEVIEW_H
+
+#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
new file mode 100644
index 0000000000..269b5e3938
--- /dev/null
+++ b/src/plugins/cppeditor/images/dark_qt_c.png
Binary files differ
diff --git a/src/plugins/cppeditor/images/dark_qt_cpp.png b/src/plugins/cppeditor/images/dark_qt_cpp.png
new file mode 100644
index 0000000000..c809be82ab
--- /dev/null
+++ b/src/plugins/cppeditor/images/dark_qt_cpp.png
Binary files differ
diff --git a/src/plugins/cppeditor/images/dark_qt_h.png b/src/plugins/cppeditor/images/dark_qt_h.png
new file mode 100644
index 0000000000..1cf8eab6f9
--- /dev/null
+++ b/src/plugins/cppeditor/images/dark_qt_h.png
Binary files differ
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index b58557dff3..c686f7eec7 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -76,6 +76,7 @@
#include <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
new file mode 100644
index 0000000000..1cf8eab6f9
--- /dev/null
+++ b/src/plugins/qmakeprojectmanager/images/dark_headers.png
Binary files differ
diff --git a/src/plugins/qmakeprojectmanager/images/dark_sources.png b/src/plugins/qmakeprojectmanager/images/dark_sources.png
new file mode 100644
index 0000000000..c809be82ab
--- /dev/null
+++ b/src/plugins/qmakeprojectmanager/images/dark_sources.png
Binary files differ
diff --git a/src/plugins/qmakeprojectmanager/images/dark_unknown.png b/src/plugins/qmakeprojectmanager/images/dark_unknown.png
new file mode 100644
index 0000000000..8bfd1fa3dc
--- /dev/null
+++ b/src/plugins/qmakeprojectmanager/images/dark_unknown.png
Binary files differ
diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp
index 89cf2600da..0b5ae42613 100644
--- a/src/plugins/qmakeprojectmanager/profileeditor.cpp
+++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp
@@ -42,6 +42,7 @@
#include <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
new file mode 100644
index 0000000000..c6c54c082f
--- /dev/null
+++ b/src/plugins/qtsupport/images/dark_forms.png
Binary files differ
diff --git a/src/plugins/qtsupport/images/dark_qml.png b/src/plugins/qtsupport/images/dark_qml.png
new file mode 100644
index 0000000000..65f445a873
--- /dev/null
+++ b/src/plugins/qtsupport/images/dark_qml.png
Binary files differ
diff --git a/src/plugins/qtsupport/images/dark_qt_project.png b/src/plugins/qtsupport/images/dark_qt_project.png
new file mode 100644
index 0000000000..5f4df3aa35
--- /dev/null
+++ b/src/plugins/qtsupport/images/dark_qt_project.png
Binary files differ
diff --git a/src/plugins/qtsupport/images/dark_qt_qrc.png b/src/plugins/qtsupport/images/dark_qt_qrc.png
new file mode 100644
index 0000000000..81b68ba39f
--- /dev/null
+++ b/src/plugins/qtsupport/images/dark_qt_qrc.png
Binary files differ
diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp
index 68983363bc..0e337590f5 100644
--- a/src/plugins/qtsupport/qtoutputformatter.cpp
+++ b/src/plugins/qtsupport/qtoutputformatter.cpp
@@ -32,6 +32,7 @@
#include <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