Files
0417_QT_code/APP/APP_KeyButton.cpp

178 lines
4.9 KiB
C++
Raw Normal View History

2026-03-26 10:45:29 +08:00
#include "APP/APP_KeyButton.h"
#include "APP/APP_Theme.h"
#include <QtCore/QtMath>
#include <QtGui/QPainter>
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