forked from qt-creator/qt-creator
Utils: New ThemeHelper class with icon handling tools
http://blog.qt.io/blog/author/didesous/ announced new designs/themes for Qt Creator. This patch implements the helper functions for the loading and theme-specific recoloring of icons. Change-Id: Ie6e96eeecb70dccd6b95338c653a9d3b760557cc Reviewed-by: Alessandro Portale <alessandro.portale@theqtcompany.com>
This commit is contained in:
@@ -48,6 +48,15 @@ FancyTabWidgetEnabledUnselectedTextColor=text
|
||||
FancyToolButtonHoverColor=hoverBackground
|
||||
FancyToolButtonSelectedColor=selectedBackground
|
||||
FutureProgressBackgroundColor=shadowBackground
|
||||
IconsBaseColor=ffdcdcdc
|
||||
IconsInfoColor=ff43aced
|
||||
IconsWarningColor=fff9ce1f
|
||||
IconsErrorColor=ffe8555a
|
||||
IconsRunColor=ff7fc341
|
||||
IconsStopColor=ffe7353b
|
||||
IconsDebugColor=ffb8c6ff
|
||||
IconsInterruptColor=ff7488db
|
||||
IconsNavigationArrowsColor=ffebc322
|
||||
InfoBarBackground=ff505000
|
||||
InfoBarText=text
|
||||
MenuBarEmptyAreaBackgroundColor=shadowBackground
|
||||
|
||||
@@ -42,6 +42,15 @@ FancyTabWidgetEnabledUnselectedTextColor=ffffffff
|
||||
FancyToolButtonHoverColor=28ffffff
|
||||
FancyToolButtonSelectedColor=32000000
|
||||
FutureProgressBackgroundColor=ffff0000
|
||||
IconsBaseColor=ffdcdcdc
|
||||
IconsInfoColor=ff43aced
|
||||
IconsWarningColor=fff9ce1f
|
||||
IconsErrorColor=ffe8555a
|
||||
IconsRunColor=ff7fc341
|
||||
IconsStopColor=ffe7353b
|
||||
IconsDebugColor=ffb8c6ff
|
||||
IconsInterruptColor=ff7488db
|
||||
IconsNavigationArrowsColor=ffebc322
|
||||
InfoBarBackground=ffffffe1
|
||||
InfoBarText=ff000000
|
||||
MenuBarEmptyAreaBackgroundColor=ffff0000
|
||||
|
||||
@@ -515,13 +515,31 @@ QString StyleHelper::dpiSpecificImageFile(const QString &fileName)
|
||||
{
|
||||
// See QIcon::addFile()
|
||||
if (qApp->devicePixelRatio() > 1.0) {
|
||||
const QFileInfo fi(fileName);
|
||||
const QString at2xfileName = fi.path() + QLatin1Char('/')
|
||||
+ fi.completeBaseName() + QStringLiteral("@2x.") + fi.suffix();
|
||||
if (QFile::exists(at2xfileName))
|
||||
return at2xfileName;
|
||||
const QString atDprfileName =
|
||||
imageFileWithResolution(fileName, qRound(qApp->devicePixelRatio()));
|
||||
if (QFile::exists(atDprfileName))
|
||||
return atDprfileName;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
QString StyleHelper::imageFileWithResolution(const QString &fileName, int dpr)
|
||||
{
|
||||
const QFileInfo fi(fileName);
|
||||
return dpr == 1 ? fileName :
|
||||
fi.path() + QLatin1Char('/') + fi.completeBaseName()
|
||||
+ QLatin1Char('@') + QString::number(dpr)
|
||||
+ QLatin1String("x.") + fi.suffix();
|
||||
}
|
||||
|
||||
QList<int> StyleHelper::availableImageResolutions(const QString &fileName)
|
||||
{
|
||||
QList<int> result;
|
||||
const int maxResolutions = qApp->devicePixelRatio();
|
||||
for (int i = 1; i <= maxResolutions; ++i)
|
||||
if (QFile::exists(imageFileWithResolution(fileName, i)))
|
||||
result.append(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
|
||||
@@ -95,6 +95,8 @@ public:
|
||||
static QLinearGradient statusBarGradient(const QRect &statusBarRect);
|
||||
|
||||
static QString dpiSpecificImageFile(const QString &fileName);
|
||||
static QString imageFileWithResolution(const QString &fileName, int dpr);
|
||||
static QList<int> availableImageResolutions(const QString &fileName);
|
||||
|
||||
private:
|
||||
static QColor m_baseColor;
|
||||
|
||||
@@ -130,6 +130,18 @@ public:
|
||||
TreeViewArrowColorNormal,
|
||||
TreeViewArrowColorSelected,
|
||||
|
||||
/* Icons */
|
||||
|
||||
IconsBaseColor,
|
||||
IconsInfoColor,
|
||||
IconsWarningColor,
|
||||
IconsErrorColor,
|
||||
IconsRunColor,
|
||||
IconsStopColor,
|
||||
IconsInterruptColor,
|
||||
IconsDebugColor,
|
||||
IconsNavigationArrowsColor,
|
||||
|
||||
/* Output panes */
|
||||
|
||||
OutputPanes_DebugTextColor,
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://www.qt.io/licensing
|
||||
**
|
||||
** 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 The Qt Company. For licensing terms and
|
||||
** conditions see http://www.qt.io/terms-conditions. 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, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "themehelper.h"
|
||||
#include "theme/theme.h"
|
||||
#include "stylehelper.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
#include <QMetaEnum>
|
||||
#include <QPainter>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
static QPixmap maskToColorAndAlpha(const QPixmap &mask, const QColor &color)
|
||||
{
|
||||
QImage result(mask.toImage().convertToFormat(QImage::Format_ARGB32));
|
||||
result.setDevicePixelRatio(mask.devicePixelRatio());
|
||||
QRgb *bitsStart = reinterpret_cast<QRgb*>(result.bits());
|
||||
const QRgb *bitsEnd = bitsStart + result.width() * result.height();
|
||||
const QRgb tint = color.rgb() & 0x00ffffff;
|
||||
const qreal alpha = color.alphaF();
|
||||
for (QRgb *pixel = bitsStart; pixel < bitsEnd; ++pixel) {
|
||||
QRgb pixelAlpha = ~(*pixel & 0xff) * alpha;
|
||||
*pixel = (pixelAlpha << 24) | tint;
|
||||
}
|
||||
return QPixmap::fromImage(result);
|
||||
}
|
||||
|
||||
typedef QPair<QPixmap, QColor> MaskAndColor;
|
||||
typedef QList<MaskAndColor> MasksAndColors;
|
||||
static MasksAndColors masksAndColors(const QString &mask, int dpr)
|
||||
{
|
||||
MasksAndColors result;
|
||||
const QStringList list = mask.split(QLatin1Char(','));
|
||||
for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) {
|
||||
const QStringList items = (*it).split(QLatin1Char('|'));
|
||||
const QString fileName = items.first().trimmed();
|
||||
QColor color = creatorTheme()->color(Theme::IconsBaseColor);
|
||||
if (items.count() > 1) {
|
||||
const QString colorName = items.at(1);
|
||||
static const QMetaObject &m = Theme::staticMetaObject;
|
||||
static const QMetaEnum colorEnum = m.enumerator(m.indexOfEnumerator("Color"));
|
||||
bool keyFound = false;
|
||||
const int colorEnumKey = colorEnum.keyToValue(colorName.toLatin1().constData(), &keyFound);
|
||||
if (keyFound) {
|
||||
color = creatorTheme()->color(static_cast<Theme::Color>(colorEnumKey));
|
||||
} else {
|
||||
const QColor colorFromName(colorName);
|
||||
if (colorFromName.isValid())
|
||||
color = colorFromName;
|
||||
}
|
||||
}
|
||||
const QString dprFileName = StyleHelper::availableImageResolutions(fileName).contains(dpr) ?
|
||||
StyleHelper::imageFileWithResolution(fileName, dpr) : fileName;
|
||||
result.append(qMakePair(QPixmap(dprFileName), color));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void smearPixmap(QPainter *painter, const QPixmap &pixmap)
|
||||
{
|
||||
painter->drawPixmap(QPointF(-0.501, -0.501), pixmap);
|
||||
painter->drawPixmap(QPointF(0, -0.501), pixmap);
|
||||
painter->drawPixmap(QPointF( 0.5, -0.501), pixmap);
|
||||
painter->drawPixmap(QPointF( 0.5, 0), pixmap);
|
||||
painter->drawPixmap(QPointF( 0.5, 0.5), pixmap);
|
||||
painter->drawPixmap(QPointF( 0, 0.5), pixmap);
|
||||
painter->drawPixmap(QPointF(-0.501, 0.5), pixmap);
|
||||
painter->drawPixmap(QPointF(-0.501, 0), pixmap);
|
||||
}
|
||||
|
||||
static QPixmap combinedMask(const MasksAndColors &masks)
|
||||
{
|
||||
if (masks.count() == 1)
|
||||
return masks.first().first;
|
||||
|
||||
QPixmap result(masks.first().first);
|
||||
QPainter p(&result);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Darken);
|
||||
MasksAndColors::const_iterator maskImage = masks.constBegin();
|
||||
maskImage++;
|
||||
for (;maskImage != masks.constEnd(); ++maskImage) {
|
||||
p.save();
|
||||
p.setOpacity(0.4);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Lighten);
|
||||
smearPixmap(&p, maskToColorAndAlpha((*maskImage).first, Qt::white));
|
||||
p.restore();
|
||||
p.drawPixmap(0, 0, (*maskImage).first);
|
||||
}
|
||||
p.end();
|
||||
return result;
|
||||
}
|
||||
|
||||
static QPixmap masksToIcon(const MasksAndColors &masks, const QPixmap &combinedMask)
|
||||
{
|
||||
QPixmap result(combinedMask.size());
|
||||
result.setDevicePixelRatio(combinedMask.devicePixelRatio());
|
||||
result.fill(Qt::transparent);
|
||||
QPainter p(&result);
|
||||
|
||||
for (MasksAndColors::const_iterator maskImage = masks.constBegin();
|
||||
maskImage != masks.constEnd(); ++maskImage) {
|
||||
if (maskImage != masks.constBegin()) {
|
||||
// Punch a transparent outline around an overlay.
|
||||
p.save();
|
||||
p.setOpacity(0.4);
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
|
||||
smearPixmap(&p, maskToColorAndAlpha((*maskImage).first, Qt::white));
|
||||
p.restore();
|
||||
}
|
||||
p.drawPixmap(0, 0, maskToColorAndAlpha((*maskImage).first, (*maskImage).second));
|
||||
}
|
||||
|
||||
const QPixmap shadowMask = maskToColorAndAlpha(combinedMask, Qt::black);
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
|
||||
p.setOpacity(0.05);
|
||||
p.drawPixmap(QPointF(0, -0.501), shadowMask);
|
||||
p.drawPixmap(QPointF(-0.501, 0), shadowMask);
|
||||
p.drawPixmap(QPointF(0.5, 0), shadowMask);
|
||||
p.drawPixmap(QPointF(0.5, 0.5), shadowMask);
|
||||
p.drawPixmap(QPointF(-0.501, 0.5), shadowMask);
|
||||
p.setOpacity(0.2);
|
||||
p.drawPixmap(0, 1, shadowMask);
|
||||
|
||||
p.end();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QIcon ThemeHelper::themedIcon(const QString &mask)
|
||||
{
|
||||
QIcon result;
|
||||
const MasksAndColors masks = masksAndColors(mask, qRound(qApp->devicePixelRatio()));
|
||||
const QPixmap combinedMask = Utils::combinedMask(masks);
|
||||
result.addPixmap(masksToIcon(masks, combinedMask));
|
||||
|
||||
QColor disabledColor = creatorTheme()->palette().mid().color();
|
||||
disabledColor.setAlphaF(0.6);
|
||||
result.addPixmap(maskToColorAndAlpha(combinedMask, disabledColor), QIcon::Disabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
QPixmap ThemeHelper::themedIconPixmap(const QString &mask)
|
||||
{
|
||||
const MasksAndColors masks =
|
||||
masksAndColors(mask, qRound(qApp->devicePixelRatio()));
|
||||
const QPixmap combinedMask = Utils::combinedMask(masks);
|
||||
return masksToIcon(masks, combinedMask);
|
||||
}
|
||||
|
||||
QPixmap ThemeHelper::recoloredPixmap(const QString &maskImage, const QColor &color)
|
||||
{
|
||||
return maskToColorAndAlpha(QPixmap(Utils::StyleHelper::dpiSpecificImageFile(maskImage)), color);
|
||||
}
|
||||
|
||||
QColor ThemeHelper::inputfieldIconColor()
|
||||
{
|
||||
// See QLineEdit::paintEvent
|
||||
QColor color = QApplication::palette().text().color();
|
||||
color.setAlpha(128);
|
||||
return color;
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 The Qt Company Ltd.
|
||||
** Contact: http://www.qt.io/licensing
|
||||
**
|
||||
** 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 The Qt Company. For licensing terms and
|
||||
** conditions see http://www.qt.io/terms-conditions. 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, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef THEMEHELPER_H
|
||||
#define THEMEHELPER_H
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QColor)
|
||||
QT_FORWARD_DECLARE_CLASS(QIcon)
|
||||
QT_FORWARD_DECLARE_CLASS(QPixmap)
|
||||
|
||||
namespace Utils {
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT ThemeHelper
|
||||
{
|
||||
public:
|
||||
// Returns a recolored icon with shadow and custom disabled state for a
|
||||
// grayscale mask. The mask can range from a single image filename to
|
||||
// a list of filename|color,... pairs.
|
||||
// The color can be a Theme::Color enum key name. If invalid, it is run
|
||||
// through QColor(const QString &name).
|
||||
static QIcon themedIcon(const QString &mask);
|
||||
// Same as themedIcon() but without disabled state.
|
||||
static QPixmap themedIconPixmap(const QString &mask);
|
||||
|
||||
// Simple recoloring of a mask. No shadow. maskImage is a single file.
|
||||
static QPixmap recoloredPixmap(const QString &maskImage, const QColor &color);
|
||||
|
||||
static QColor inputfieldIconColor();
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
|
||||
#endif // THEMEHELPER_H
|
||||
@@ -88,6 +88,7 @@ SOURCES += $$PWD/environment.cpp \
|
||||
$$PWD/proxycredentialsdialog.cpp \
|
||||
$$PWD/macroexpander.cpp \
|
||||
$$PWD/theme/theme.cpp \
|
||||
$$PWD/themehelper.cpp \
|
||||
$$PWD/progressindicator.cpp \
|
||||
$$PWD/fadingindicator.cpp \
|
||||
$$PWD/overridecursor.cpp \
|
||||
@@ -191,6 +192,7 @@ HEADERS += \
|
||||
$$PWD/macroexpander.h \
|
||||
$$PWD/theme/theme.h \
|
||||
$$PWD/theme/theme_p.h \
|
||||
$$PWD/themehelper.h \
|
||||
$$PWD/progressindicator.h \
|
||||
$$PWD/fadingindicator.h \
|
||||
$$PWD/executeondestruction.h \
|
||||
|
||||
@@ -195,6 +195,8 @@ QtcLibrary {
|
||||
"textfieldcombobox.h",
|
||||
"textfileformat.cpp",
|
||||
"textfileformat.h",
|
||||
"themehelper.cpp",
|
||||
"themehelper.h",
|
||||
"treemodel.cpp",
|
||||
"treemodel.h",
|
||||
"treeviewcombobox.cpp",
|
||||
|
||||
Reference in New Issue
Block a user