#include "APP/APP_KeyButton.h" #include "APP/APP_Theme.h" #include #include namespace { /* * 这个小工具函数用来把两种颜色按比例混合。 * 当前项目里主要用它来根据按键状态生成不同深浅的背景色和边框色。 */ QColor App_Func_MixColor(const QColor& Left, const QColor& Right, qreal Value) { const qreal Rate = qBound(0.0, Value, 1.0); return QColor( qRound(Left.red() + (Right.red() - Left.red()) * Rate), qRound(Left.green() + (Right.green() - Left.green()) * Rate), qRound(Left.blue() + (Right.blue() - Left.blue()) * Rate), qRound(Left.alpha() + (Right.alpha() - Left.alpha()) * Rate)); } } // namespace namespace APP { APP_KeyButton::APP_KeyButton(const APP_KeyInfo& KeyInfo, QWidget* parent) : QPushButton(parent), appKeyInfo(KeyInfo) { // 这里把按钮本身的交互属性定下来,后面就主要交给 paintEvent 自绘。 setCursor(Qt::PointingHandCursor); setFlat(true); setMinimumSize(78, 78); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } void APP_KeyButton::App_Func_SetLatched(bool IsLatched) { // 状态没变时不重复刷新,避免无意义重绘。 if (appIsLatched == IsLatched) { return; } appIsLatched = IsLatched; update(); } void APP_KeyButton::App_Func_SetPressed(bool IsPressed) { // 状态没变时同样直接返回。 if (appIsPressed == IsPressed) { return; } appIsPressed = IsPressed; update(); } void APP_KeyButton::paintEvent(QPaintEvent* event) { Q_UNUSED(event); // 留一点内边距,让卡片式按键看起来不那么“顶满”。 const QRectF ButtonRect = rect().adjusted(6.0, 6.0, -6.0, -6.0); const qreal Radius = 14.0; QColor FillColor = App_Func_GetBackgroundColor(); QColor OutlineColor = App_Func_GetBorderColor(); // 鼠标按下时再做一层轻微压暗,形成“压下去”的感觉。 if (isDown()) { FillColor = FillColor.darker(108); OutlineColor = OutlineColor.darker(112); } QPainter Painter(this); Painter.setRenderHint(QPainter::Antialiasing, true); Painter.setRenderHint(QPainter::TextAntialiasing, true); // 先画背景和边框。 Painter.setPen(QPen(OutlineColor, 1.2)); Painter.setBrush(FillColor); Painter.drawRoundedRect(ButtonRect, Radius, Radius); // hint 一般显示在左上角,比如 Num、Fn 这类短提示。 if (!appKeyInfo.hint.isEmpty()) { Painter.setFont(APP_Theme::App_Func_GetKeyHintFont()); Painter.setPen(App_Func_GetTextColor().lighter(115)); Painter.drawText( ButtonRect.adjusted(10.0, 8.0, -10.0, -8.0), Qt::AlignLeft | Qt::AlignTop, appKeyInfo.hint.toUpper()); } // 主文字放中间。文字长度不同就稍微缩一下字号,避免挤出按钮。 QFont LabelFont = APP_Theme::App_Func_GetKeyLabelFont(); if (appKeyInfo.label.size() > 2) { LabelFont.setPointSize(LabelFont.pointSize() - 4); } else if (appKeyInfo.label.size() == 2) { LabelFont.setPointSize(LabelFont.pointSize() - 2); } Painter.setFont(LabelFont); Painter.setPen(App_Func_GetTextColor()); Painter.drawText(ButtonRect, Qt::AlignCenter, appKeyInfo.label); } QColor APP_KeyButton::App_Func_GetAccentColor() const { // 每个 tone 对应一组强调色,用来让不同类别的键略有区分。 switch (appKeyInfo.tone) { case APP_KeyTone::Aqua: return QColor(72, 184, 162); case APP_KeyTone::Amber: return QColor(224, 172, 76); case APP_KeyTone::Blue: return QColor(103, 146, 224); case APP_KeyTone::Normal: default: return QColor(150, 168, 196); } } QColor APP_KeyButton::App_Func_GetBackgroundColor() const { // 先以统一暗色为底,再按状态叠加强调色。 const QColor BaseColor(55, 61, 70); // 按下态最强。 if (appIsPressed) { return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), 0.56); } // 锁定态次之。 if (appKeyInfo.tone != APP_KeyTone::Normal || appIsLatched) { return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), appIsLatched ? 0.35 : 0.18); } return BaseColor; } QColor APP_KeyButton::App_Func_GetBorderColor() const { const QColor BaseColor(104, 114, 126); if (appIsPressed) { return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), 0.72); } if (appKeyInfo.tone != APP_KeyTone::Normal || appIsLatched) { return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), appIsLatched ? 0.45 : 0.25); } return BaseColor; } QColor APP_KeyButton::App_Func_GetTextColor() const { // 当前项目固定用高亮浅色字,保证暗底上阅读清晰。 return QColor(238, 242, 247); } } // namespace APP