Qt Creator源码分析系列——UI界面:StyleHelper类

该篇文章内容主要集中Qt Creator软件界面部分代码的分析。从分析插件中的utils-lib中的StyleHelper模块开始,项目文件在路径\qt-creator-master\qt-creator-master\src\libs\utils\utils-lib下。

StyleHelper

StyleHelper类没有继承其他类,且成员都是静态的。除了依赖theme/theme.hhostosinfo.h,还依赖于QPixmapCache、QPainter、QApplication、QFileInfo、QCommonStyle、QStyleOption、QWindow、qmath.h。

// Helper class holding all custom color values StyleHelper中保存了所有自定义颜色
class QTCREATOR_UTILS_EXPORT StyleHelper
{
public:
    static const unsigned int DEFAULT_BASE_COLOR = 0x666666;
    static const int progressFadeAnimationDuration = 600;
    // Height of the project explorer navigation bar
    static int navigationWidgetHeight() { return 24; }
    static qreal sidebarFontSize() { return HostOsInfo::isMacHost() ? 10 : 7.5; }
    static QPalette sidebarFontPalette(const QPalette &original);
    // This is our color table, all colors derive from baseColor
    // 自定义的颜色表,源自baseColor
    static QColor requestedBaseColor() { return m_requestedBaseColor; }
    static QColor baseColor(bool lightColored = false);
    static QColor panelTextColor(bool lightColored = false) {
    	if (!lightColored)
        	return Qt::white;
    	else
        	return Qt::black;
	}
    static QColor highlightColor(bool lightColored = false);
    static QColor shadowColor(bool lightColored = false);
    static QColor borderColor(bool lightColored = false);
    static QColor toolBarBorderColor();
    static QColor buttonTextColor() { return QColor(0x4c4c4c); }
    static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50);
    static QColor alphaBlendedColors(const QColor &colorA, const QColor &colorB);
    static QColor sidebarHighlight() { return QColor(255, 255, 255, 40); }
    static QColor sidebarShadow() { return QColor(0, 0, 0, 40); }
    static QColor toolBarDropShadowColor() { return QColor(0, 0, 0, 70); }
    static QColor notTooBrightHighlightColor();
    // Sets the base color and makes sure all top level widgets are updated
    static void setBaseColor(const QColor &color);
    // Draws a shaded anti-aliased arrow
    static void drawArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option);
    // Gradients used for panels
    static void horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false);
    static void verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false);
    static void menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect);
    static bool usePixmapCache() { return true; }
    static QPixmap disabledSideBarIcon(const QPixmap &enabledicon);
    static void drawIconWithShadow(const QIcon &icon, const QRect &rect, QPainter *p, QIcon::Mode iconMode,
                                   int dipRadius = 3, const QColor &color = QColor(0, 0, 0, 130),
                                   const QPoint &dipOffset = QPoint(1, -2));
    static void drawCornerImage(const QImage &img, QPainter *painter, const QRect &rect,
                         int left = 0, int top = 0, int right = 0, int bottom = 0);
    static void tintImage(QImage &img, const QColor &tintColor);
    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);
    static double luminance(const QColor &color);
    static bool isReadableOn(const QColor &background, const QColor &foreground);
private:
    static QColor m_baseColor;
    static QColor m_requestedBaseColor;
};

先介绍针对静态成员m_baseColor和m_requestedBaseColor的函数。依赖于Theme类。

// 尝试根据用户请求确保使用的实际颜色在生成实际基础颜色时的合理范围
void StyleHelper::setBaseColor(const QColor &newcolor)
{
	// 将m_requestedBaseColor设置为newcolor
    m_requestedBaseColor = newcolor;
    // 提取theme中默认颜色和本类的默认颜色
    const QColor themeBaseColor = creatorTheme()->color(Theme::PanelStatusBarBackgroundColor);
    const QColor defaultBaseColor = QColor(DEFAULT_BASE_COLOR);
    QColor color;
    if (defaultBaseColor == newcolor) {
        color = themeBaseColor;
    } else {
        const int valueDelta = (newcolor.value() - defaultBaseColor.value()) / 3;
        const int value = qBound(0, themeBaseColor.value() + valueDelta, 255);
        color.setHsv(newcolor.hue(), newcolor.saturation() * 0.7, value);
    }

    if (color.isValid() && color != m_baseColor) {
        m_baseColor = color;  // m_baseColor设置为color
        foreach (QWidget *w, QApplication::topLevelWidgets())
        	w->update();
    }
}

sidebarFontPalette函数传入QPalette调色盘,通过Theme类取出Theme::ProgressBarTitleColor的QColor,设置到新建的palette中返回。

QPalette StyleHelper::sidebarFontPalette(const QPalette &original)
{
    QPalette palette = original;
    const QColor textColor = creatorTheme()->color(Theme::ProgressBarTitleColor);
    palette.setColor(QPalette::WindowText, textColor);
    palette.setColor(QPalette::Text, textColor);
    return palette;
}

返回基础颜色,如果lightColored和Theme::WindowColorAsBase有一个为真,就使用QPalette::Window的颜色,否则使用m_baseColor。

QColor StyleHelper::baseColor(bool lightColored)
{
    static const QColor windowColor = QApplication::palette().color(QPalette::Window);
    static const bool windowColorAsBase = creatorTheme()->flag(Theme::WindowColorAsBase);
    return (lightColored || windowColorAsBase) ? windowColor : m_baseColor;
}

highlightColor、shadowColor、borderColor、toolBarBorderColor函数用于基于baseColor颜色的调整HSV值定制颜色。

QColor StyleHelper::highlightColor(bool lightColored)
{
    QColor result = baseColor(lightColored);
    if (!lightColored)
        result.setHsv(result.hue(), clamp(result.saturation()), clamp(result.value() * 1.16));
    else
        result.setHsv(result.hue(), clamp(result.saturation()), clamp(result.value() * 1.06));
    return result;
}
QColor StyleHelper::shadowColor(bool lightColored)
{
    QColor result = baseColor(lightColored);
    result.setHsv(result.hue(), clamp(result.saturation() * 1.1), clamp(result.value() * 0.70));
    return result;
}
QColor StyleHelper::borderColor(bool lightColored)
{
    QColor result = baseColor(lightColored);
    result.setHsv(result.hue(), result.saturation(), result.value() / 2);
    return result;
}
QColor StyleHelper::toolBarBorderColor()
{
    const QColor base = baseColor();
    return QColor::fromHsv(base.hue(), base.saturation(), clamp(base.value() * 0.80f));
}

根据比例因子factor合成colorA和colorB。占比(factor、100-factor)

QColor StyleHelper::mergedColors(const QColor &colorA, const QColor &colorB, int factor)
{
    const int maxFactor = 100;
    QColor tmp = colorA;
    tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
    tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
    tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
    return tmp;
}

colorA和colorB的另外一种合成函数

QColor StyleHelper::alphaBlendedColors(const QColor &colorA, const QColor &colorB)
{
    const int alpha = colorB.alpha();
    const int antiAlpha = 255 - alpha;
    return QColor((colorA.red() * antiAlpha + colorB.red() * alpha) / 255, (colorA.green() * antiAlpha + colorB.green() * alpha) / 255, (colorA.blue() * antiAlpha + colorB.blue() * alpha) / 255);
}

不是那么亮的高亮颜色

QColor StyleHelper::notTooBrightHighlightColor()
{
    QColor highlightColor = QApplication::palette().highlight().color();
    if (0.5 * highlightColor.saturationF() + 0.75 - highlightColor.valueF() < 0)
        highlightColor.setHsvF(highlightColor.hsvHueF(), 0.1 + highlightColor.saturationF() * 2.0, highlightColor.valueF());
    return highlightColor;
}
void StyleHelper::drawArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option)
{
    if (option->rect.width() <= 1 || option->rect.height() <= 1)
        return;

    const qreal devicePixelRatio = painter->device()->devicePixelRatio();
    const bool enabled = option->state & QStyle::State_Enabled;
    QRect r = option->rect;
    int size = qMin(r.height(), r.width());
    QPixmap pixmap;
    const QString pixmapName = QString::asprintf("StyleHelper::drawArrow-%d-%d-%d-%f",
                       element, size, enabled, devicePixelRatio);
    if (!QPixmapCache::find(pixmapName, &pixmap)) {
        QImage image(size * devicePixelRatio, size * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
        image.fill(Qt::transparent);
        QPainter painter(&image);

        QStyleOption tweakedOption(*option);
        tweakedOption.state = QStyle::State_Enabled;

        auto drawCommonStyleArrow = [&tweakedOption, element, &painter](const QRect &rect, const QColor &color) -> void
        {
            static const QCommonStyle* const style = qobject_cast<QCommonStyle*>(QApplication::style());
            if (!style)
                return;
            tweakedOption.palette.setColor(QPalette::ButtonText, color.rgb());
            tweakedOption.rect = rect;
            painter.setOpacity(color.alphaF());
            style->QCommonStyle::drawPrimitive(element, &tweakedOption, &painter);
        };

        if (!enabled) {
            drawCommonStyleArrow(image.rect(), creatorTheme()->color(Theme::IconsDisabledColor));
        } else {
            if (creatorTheme()->flag(Theme::ToolBarIconShadow))
                drawCommonStyleArrow(image.rect().translated(0, devicePixelRatio), toolBarDropShadowColor());
            drawCommonStyleArrow(image.rect(), creatorTheme()->color(Theme::IconsBaseColor));
        }
        painter.end();
        pixmap = QPixmap::fromImage(image);
        pixmap.setDevicePixelRatio(devicePixelRatio);
        QPixmapCache::insert(pixmapName, pixmap);
    }
    int xOffset = r.x() + (r.width() - size)/2;
    int yOffset = r.y() + (r.height() - size)/2;
    painter->drawPixmap(xOffset, yOffset, pixmap);
}

三个**Gradient函数和辅助函数

static void verticalGradientHelper(QPainter *p, const QRect &spanRect, const QRect &rect, bool lightColored)
{
    QColor highlight = StyleHelper::highlightColor(lightColored);
    QColor shadow = StyleHelper::shadowColor(lightColored);
    QLinearGradient grad(spanRect.topRight(), spanRect.topLeft());
    grad.setColorAt(0, highlight.lighter(117));
    grad.setColorAt(1, shadow.darker(109));
    p->fillRect(rect, grad);
    QColor light(255, 255, 255, 80);
    p->setPen(light);
    p->drawLine(rect.topRight() - QPoint(1, 0), rect.bottomRight() - QPoint(1, 0));
    QColor dark(0, 0, 0, 90);
    p->setPen(dark);
    p->drawLine(rect.topLeft(), rect.bottomLeft());
}
void StyleHelper::verticalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored)
{
    if (StyleHelper::usePixmapCache()) {

        QColor keyColor = baseColor(lightColored);
        const QString key = QString::asprintf("mh_vertical %d %d %d %d %d",
            spanRect.width(), spanRect.height(), clipRect.width(),
            clipRect.height(), keyColor.rgb());

        QPixmap pixmap;
        if (!QPixmapCache::find(key, &pixmap)) {
            pixmap = QPixmap(clipRect.size());
            QPainter p(&pixmap);
            QRect rect(0, 0, clipRect.width(), clipRect.height());
            verticalGradientHelper(&p, spanRect, rect, lightColored);
            p.end();
            QPixmapCache::insert(key, pixmap);
        }

        painter->drawPixmap(clipRect.topLeft(), pixmap);
    } else {
        verticalGradientHelper(painter, spanRect, clipRect, lightColored);
    }
}
static void horizontalGradientHelper(QPainter *p, const QRect &spanRect, const
QRect &rect, bool lightColored)
{
    if (lightColored) {
        QLinearGradient shadowGradient(rect.topLeft(), rect.bottomLeft());
        shadowGradient.setColorAt(0, 0xf0f0f0);
        shadowGradient.setColorAt(1, 0xcfcfcf);
        p->fillRect(rect, shadowGradient);
        return;
    }

    QColor base = StyleHelper::baseColor(lightColored);
    QColor highlight = StyleHelper::highlightColor(lightColored);
    QColor shadow = StyleHelper::shadowColor(lightColored);
    QLinearGradient grad(rect.topLeft(), rect.bottomLeft());
    grad.setColorAt(0, highlight.lighter(120));
    if (rect.height() == StyleHelper::navigationWidgetHeight()) {
        grad.setColorAt(0.4, highlight);
        grad.setColorAt(0.401, base);
    }
    grad.setColorAt(1, shadow);
    p->fillRect(rect, grad);

    QLinearGradient shadowGradient(spanRect.topLeft(), spanRect.topRight());
        shadowGradient.setColorAt(0, QColor(0, 0, 0, 30));
    QColor lighterHighlight;
    lighterHighlight = highlight.lighter(130);
    lighterHighlight.setAlpha(100);
    shadowGradient.setColorAt(0.7, lighterHighlight);
        shadowGradient.setColorAt(1, QColor(0, 0, 0, 40));
    p->fillRect(rect, shadowGradient);
}

void StyleHelper::horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored)
{
    if (StyleHelper::usePixmapCache()) {

        QColor keyColor = baseColor(lightColored);
        const QString key = QString::asprintf("mh_horizontal %d %d %d %d %d %d",
            spanRect.width(), spanRect.height(), clipRect.width(),
            clipRect.height(), keyColor.rgb(), spanRect.x());

        QPixmap pixmap;
        if (!QPixmapCache::find(key, &pixmap)) {
            pixmap = QPixmap(clipRect.size());
            QPainter p(&pixmap);
            QRect rect = QRect(0, 0, clipRect.width(), clipRect.height());
            horizontalGradientHelper(&p, spanRect, rect, lightColored);
            p.end();
            QPixmapCache::insert(key, pixmap);
        }

        painter->drawPixmap(clipRect.topLeft(), pixmap);

    } else {
        horizontalGradientHelper(painter, spanRect, clipRect, lightColored);
    }
}
static void menuGradientHelper(QPainter *p, const QRect &spanRect, const QRect &rect)
{
    QLinearGradient grad(spanRect.topLeft(), spanRect.bottomLeft());
    QColor menuColor = StyleHelper::mergedColors(StyleHelper::baseColor(), QColor(244, 244, 244), 25);
    grad.setColorAt(0, menuColor.lighter(112));
    grad.setColorAt(1, menuColor);
    p->fillRect(rect, grad);
}
void StyleHelper::menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect)
{
    if (StyleHelper::usePixmapCache()) {
        const QString key = QString::asprintf("mh_menu %d %d %d %d %d",
            spanRect.width(), spanRect.height(), clipRect.width(),
            clipRect.height(), StyleHelper::baseColor().rgb());

        QPixmap pixmap;
        if (!QPixmapCache::find(key, &pixmap)) {
            pixmap = QPixmap(clipRect.size());
            QPainter p(&pixmap);
            QRect rect = QRect(0, 0, clipRect.width(), clipRect.height());
            menuGradientHelper(&p, spanRect, rect);
            p.end();
            QPixmapCache::insert(key, pixmap);
        }

        painter->drawPixmap(clipRect.topLeft(), pixmap);
    } else {
        menuGradientHelper(painter, spanRect, clipRect);
    }
}
发布了134 篇原创文章 · 获赞 141 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/asmartkiller/article/details/104385172