first push
This commit is contained in:
40
APP/APP_GlassCard.cpp
Normal file
40
APP/APP_GlassCard.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "APP/APP_GlassCard.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
namespace APP {
|
||||
|
||||
APP_GlassCard::APP_GlassCard(QWidget* parent)
|
||||
: QFrame(parent)
|
||||
{
|
||||
// 交给我们自己统一绘制卡片外观,不使用 QFrame 默认边框。
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
// 背景由 paintEvent 自绘,这里不走样式表背景。
|
||||
setAttribute(Qt::WA_StyledBackground, false);
|
||||
}
|
||||
|
||||
void APP_GlassCard::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
/*
|
||||
* 卡片外观刻意保持简单,方便教学时理解自绘流程:
|
||||
* 1. 先画一个带圆角的深色底板
|
||||
* 2. 再画一圈细边框
|
||||
*/
|
||||
const QRectF BodyRect = rect().adjusted(1.0, 1.0, -1.0, -1.0);
|
||||
const qreal Radius = 22.0;
|
||||
const QColor FillColor(30, 35, 43);
|
||||
const QColor BorderColor(82, 92, 104);
|
||||
|
||||
QPainter Painter(this);
|
||||
Painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// 先画卡片主体。
|
||||
Painter.setPen(QPen(BorderColor, 1.0));
|
||||
Painter.setBrush(FillColor);
|
||||
Painter.drawRoundedRect(BodyRect, Radius, Radius);
|
||||
|
||||
}
|
||||
|
||||
} // namespace APP
|
||||
27
APP/APP_GlassCard.h
Normal file
27
APP/APP_GlassCard.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QFrame>
|
||||
|
||||
namespace APP {
|
||||
|
||||
/*
|
||||
* 这是项目里所有“卡片容器”的基础控件。
|
||||
*
|
||||
* 它只负责统一外观,不负责任何业务逻辑:
|
||||
* 1. 统一圆角卡片风格
|
||||
* 2. 统一边框和暗色底板
|
||||
*
|
||||
* 上层像主页卡片、调试卡片都直接继承它。
|
||||
*/
|
||||
class APP_GlassCard : public QFrame
|
||||
{
|
||||
public:
|
||||
// 构造一个带统一外观的卡片容器。
|
||||
explicit APP_GlassCard(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
// 卡片背景和圆角边框都在这里自绘。
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
};
|
||||
|
||||
} // namespace APP
|
||||
171
APP/APP_KeyButton.cpp
Normal file
171
APP/APP_KeyButton.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#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)
|
||||
{
|
||||
appHintText = appKeyInfo.hint;
|
||||
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::App_Func_SetHintText(const QString& HintText)
|
||||
{
|
||||
if (appHintText == HintText)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
appHintText = HintText;
|
||||
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);
|
||||
|
||||
if (!appHintText.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,
|
||||
appHintText.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
|
||||
{
|
||||
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
|
||||
33
APP/APP_KeyButton.h
Normal file
33
APP/APP_KeyButton.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "APP/APP_KeypadModel.h"
|
||||
#include <QtGui/QColor>
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
namespace APP {
|
||||
|
||||
class APP_KeyButton : public QPushButton
|
||||
{
|
||||
public:
|
||||
explicit APP_KeyButton(const APP_KeyInfo& KeyInfo, QWidget* parent = nullptr);
|
||||
|
||||
void App_Func_SetLatched(bool IsLatched);
|
||||
void App_Func_SetPressed(bool IsPressed);
|
||||
void App_Func_SetHintText(const QString& HintText);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
private:
|
||||
QColor App_Func_GetAccentColor() const;
|
||||
QColor App_Func_GetBackgroundColor() const;
|
||||
QColor App_Func_GetBorderColor() const;
|
||||
QColor App_Func_GetTextColor() const;
|
||||
|
||||
APP_KeyInfo appKeyInfo;
|
||||
QString appHintText;
|
||||
bool appIsLatched = false;
|
||||
bool appIsPressed = false;
|
||||
};
|
||||
|
||||
} // namespace APP
|
||||
119
APP/APP_KeypadModel.cpp
Normal file
119
APP/APP_KeypadModel.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "APP/APP_KeypadModel.h"
|
||||
|
||||
namespace APP {
|
||||
|
||||
APP_KeypadModel::APP_KeypadModel()
|
||||
{
|
||||
appKeyList = {
|
||||
{QStringLiteral("num"), QStringLiteral("Num"), QString(), 0x0053, 0, 0, 1, 1, APP_KeyTone::Aqua},
|
||||
{QStringLiteral("divide"), QStringLiteral("/"), QString(), 0x0054, 0, 1, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("multiply"), QStringLiteral("*"), QString(), 0x0055, 0, 2, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("minus"), QStringLiteral("-"), QString(), 0x0056, 0, 3, 1, 1, APP_KeyTone::Amber},
|
||||
{QStringLiteral("7"), QStringLiteral("7"), QStringLiteral("Home"), 0x005F, 1, 0, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("8"), QStringLiteral("8"), QStringLiteral("Up"), 0x0060, 1, 1, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("9"), QStringLiteral("9"), QStringLiteral("PgUp"), 0x0061, 1, 2, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("plus"), QStringLiteral("+"), QString(), 0x0057, 1, 3, 2, 1, APP_KeyTone::Aqua},
|
||||
{QStringLiteral("4"), QStringLiteral("4"), QStringLiteral("Left"), 0x005C, 2, 0, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("5"), QStringLiteral("5"), QString(), 0x005D, 2, 1, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("6"), QStringLiteral("6"), QStringLiteral("Right"), 0x005E, 2, 2, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("1"), QStringLiteral("1"), QStringLiteral("End"), 0x0059, 3, 0, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("2"), QStringLiteral("2"), QStringLiteral("Down"), 0x005A, 3, 1, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("3"), QStringLiteral("3"), QStringLiteral("PgDn"), 0x005B, 3, 2, 1, 1, APP_KeyTone::Normal},
|
||||
{QStringLiteral("enter"), QStringLiteral("Enter"), QString(), 0x0058, 3, 3, 2, 1, APP_KeyTone::Blue},
|
||||
{QStringLiteral("0"), QStringLiteral("0"), QStringLiteral("Ins"), 0x0062, 4, 0, 1, 2, APP_KeyTone::Normal},
|
||||
{QStringLiteral("dot"), QStringLiteral("."), QStringLiteral("Del"), 0x0063, 4, 2, 1, 1, APP_KeyTone::Normal}
|
||||
};
|
||||
}
|
||||
|
||||
const QVector<APP_KeyInfo>& APP_KeypadModel::App_Func_GetKeyList() const
|
||||
{
|
||||
return appKeyList;
|
||||
}
|
||||
|
||||
bool APP_KeypadModel::App_Func_IsLatched(const QString& KeyId) const
|
||||
{
|
||||
return (KeyId == QStringLiteral("num")) && appNumLockOn;
|
||||
}
|
||||
|
||||
bool APP_KeypadModel::App_Func_IsPressed(const QString& KeyId) const
|
||||
{
|
||||
return appPressedKeyIdList.contains(KeyId);
|
||||
}
|
||||
|
||||
quint16 APP_KeypadModel::App_Func_GetUsageFromKeyId(const QString& KeyId) const
|
||||
{
|
||||
for (const APP_KeyInfo& KeyInfo : appKeyList)
|
||||
{
|
||||
if (KeyInfo.id == KeyId)
|
||||
{
|
||||
return KeyInfo.usage;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString APP_KeypadModel::App_Func_GetKeyIdFromUsage(quint16 Usage) const
|
||||
{
|
||||
for (const APP_KeyInfo& KeyInfo : appKeyList)
|
||||
{
|
||||
if (KeyInfo.usage == Usage)
|
||||
{
|
||||
return KeyInfo.id;
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString APP_KeypadModel::App_Func_GetLabelFromUsage(quint16 Usage) const
|
||||
{
|
||||
for (const APP_KeyInfo& KeyInfo : appKeyList)
|
||||
{
|
||||
if (KeyInfo.usage == Usage)
|
||||
{
|
||||
return KeyInfo.label;
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString APP_KeypadModel::App_Func_GetDefaultHint(const QString& KeyId) const
|
||||
{
|
||||
for (const APP_KeyInfo& KeyInfo : appKeyList)
|
||||
{
|
||||
if (KeyInfo.id == KeyId)
|
||||
{
|
||||
return KeyInfo.hint;
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void APP_KeypadModel::App_Func_SetNumLockOn(bool IsOn)
|
||||
{
|
||||
appNumLockOn = IsOn;
|
||||
}
|
||||
|
||||
void APP_KeypadModel::App_Func_ClearPressedKeys()
|
||||
{
|
||||
appPressedKeyIdList.clear();
|
||||
}
|
||||
|
||||
void APP_KeypadModel::App_Func_SetPressedKeysFromUsageList(const QVector<quint16>& UsageList)
|
||||
{
|
||||
appPressedKeyIdList.clear();
|
||||
|
||||
for (quint16 Usage : UsageList)
|
||||
{
|
||||
const QString KeyId = App_Func_GetKeyIdFromUsage(Usage);
|
||||
if (!KeyId.isEmpty() && !appPressedKeyIdList.contains(KeyId))
|
||||
{
|
||||
appPressedKeyIdList.append(KeyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace APP
|
||||
52
APP/APP_KeypadModel.h
Normal file
52
APP/APP_KeypadModel.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace APP {
|
||||
|
||||
enum class APP_KeyTone
|
||||
{
|
||||
Normal,
|
||||
Aqua,
|
||||
Amber,
|
||||
Blue
|
||||
};
|
||||
|
||||
struct APP_KeyInfo
|
||||
{
|
||||
QString id;
|
||||
QString label;
|
||||
QString hint;
|
||||
quint16 usage = 0;
|
||||
int row = 0;
|
||||
int column = 0;
|
||||
int rowSpan = 1;
|
||||
int columnSpan = 1;
|
||||
APP_KeyTone tone = APP_KeyTone::Normal;
|
||||
};
|
||||
|
||||
class APP_KeypadModel
|
||||
{
|
||||
public:
|
||||
APP_KeypadModel();
|
||||
|
||||
const QVector<APP_KeyInfo>& App_Func_GetKeyList() const;
|
||||
bool App_Func_IsLatched(const QString& KeyId) const;
|
||||
bool App_Func_IsPressed(const QString& KeyId) const;
|
||||
quint16 App_Func_GetUsageFromKeyId(const QString& KeyId) const;
|
||||
QString App_Func_GetKeyIdFromUsage(quint16 Usage) const;
|
||||
QString App_Func_GetLabelFromUsage(quint16 Usage) const;
|
||||
QString App_Func_GetDefaultHint(const QString& KeyId) const;
|
||||
void App_Func_SetNumLockOn(bool IsOn);
|
||||
void App_Func_ClearPressedKeys();
|
||||
void App_Func_SetPressedKeysFromUsageList(const QVector<quint16>& UsageList);
|
||||
|
||||
private:
|
||||
QVector<APP_KeyInfo> appKeyList;
|
||||
QStringList appPressedKeyIdList;
|
||||
bool appNumLockOn = false;
|
||||
};
|
||||
|
||||
} // namespace APP
|
||||
131
APP/APP_Theme.cpp
Normal file
131
APP/APP_Theme.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "APP/APP_Theme.h"
|
||||
|
||||
#include <QtGui/QFontDatabase>
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
namespace APP {
|
||||
|
||||
QPalette APP_Theme::App_Func_GetPalette()
|
||||
{
|
||||
/*
|
||||
* 不用样式表时,Qt 最稳妥的统一美化方式就是调色板:
|
||||
* 1. 先选 Fusion 风格
|
||||
* 2. 再给标准控件一组统一颜色
|
||||
*/
|
||||
QPalette Palette;
|
||||
|
||||
const QColor WindowColor(20, 25, 33);
|
||||
const QColor BaseColor(28, 34, 42);
|
||||
const QColor AltBaseColor(34, 40, 49);
|
||||
const QColor ButtonColor(38, 44, 54);
|
||||
const QColor BorderHintColor(86, 96, 108);
|
||||
const QColor HighlightColor(72, 184, 162);
|
||||
const QColor TextColor(238, 242, 247);
|
||||
const QColor DimTextColor(162, 170, 182);
|
||||
|
||||
Palette.setColor(QPalette::Window, WindowColor);
|
||||
Palette.setColor(QPalette::WindowText, TextColor);
|
||||
Palette.setColor(QPalette::Base, BaseColor);
|
||||
Palette.setColor(QPalette::AlternateBase, AltBaseColor);
|
||||
Palette.setColor(QPalette::Text, TextColor);
|
||||
Palette.setColor(QPalette::Button, ButtonColor);
|
||||
Palette.setColor(QPalette::ButtonText, TextColor);
|
||||
Palette.setColor(QPalette::BrightText, QColor(255, 255, 255));
|
||||
Palette.setColor(QPalette::Light, BorderHintColor.lighter(120));
|
||||
Palette.setColor(QPalette::Midlight, BorderHintColor);
|
||||
Palette.setColor(QPalette::Mid, BorderHintColor.darker(120));
|
||||
Palette.setColor(QPalette::Dark, WindowColor.darker(140));
|
||||
Palette.setColor(QPalette::Shadow, QColor(0, 0, 0, 140));
|
||||
Palette.setColor(QPalette::Highlight, HighlightColor);
|
||||
Palette.setColor(QPalette::HighlightedText, TextColor);
|
||||
Palette.setColor(QPalette::ToolTipBase, BaseColor);
|
||||
Palette.setColor(QPalette::ToolTipText, TextColor);
|
||||
Palette.setColor(QPalette::Link, QColor(103, 146, 224));
|
||||
Palette.setColor(QPalette::PlaceholderText, QColor(170, 178, 188, 170));
|
||||
Palette.setColor(QPalette::Disabled, QPalette::WindowText, DimTextColor);
|
||||
Palette.setColor(QPalette::Disabled, QPalette::Text, DimTextColor);
|
||||
Palette.setColor(QPalette::Disabled, QPalette::ButtonText, DimTextColor);
|
||||
|
||||
return Palette;
|
||||
}
|
||||
|
||||
QFont APP_Theme::App_Func_GetBodyFont()
|
||||
{
|
||||
// 正文用相对稳妥、系统常见的字体候选。
|
||||
QFont Font(App_Func_PickFontFamily(QStringList()
|
||||
<< QStringLiteral("Segoe UI Variable Text")
|
||||
<< QStringLiteral("Microsoft YaHei UI")
|
||||
<< QStringLiteral("Segoe UI")
|
||||
<< QStringLiteral("Bahnschrift")));
|
||||
Font.setPointSize(10);
|
||||
Font.setWeight(QFont::Medium);
|
||||
return Font;
|
||||
}
|
||||
|
||||
QFont APP_Theme::App_Func_GetTitleFont()
|
||||
{
|
||||
// 页面标题字号更大、字重更高。
|
||||
QFont Font(App_Func_PickFontFamily(QStringList()
|
||||
<< QStringLiteral("Segoe UI Variable Display Semibold")
|
||||
<< QStringLiteral("Microsoft YaHei UI")
|
||||
<< QStringLiteral("Bahnschrift SemiBold")));
|
||||
Font.setPointSize(21);
|
||||
Font.setWeight(QFont::DemiBold);
|
||||
return Font;
|
||||
}
|
||||
|
||||
QFont APP_Theme::App_Func_GetMetricFont()
|
||||
{
|
||||
// 指标类标题用比正文更有力度的字重。
|
||||
QFont Font(App_Func_PickFontFamily(QStringList()
|
||||
<< QStringLiteral("Bahnschrift SemiBold")
|
||||
<< QStringLiteral("Segoe UI Semibold")
|
||||
<< QStringLiteral("Microsoft YaHei UI")));
|
||||
Font.setPointSize(12);
|
||||
Font.setWeight(QFont::DemiBold);
|
||||
return Font;
|
||||
}
|
||||
|
||||
QFont APP_Theme::App_Func_GetKeyLabelFont()
|
||||
{
|
||||
// 按键主文字字号较大,保证小键盘一眼能看清。
|
||||
QFont Font(App_Func_PickFontFamily(QStringList()
|
||||
<< QStringLiteral("Bahnschrift SemiBold")
|
||||
<< QStringLiteral("Segoe UI Semibold")
|
||||
<< QStringLiteral("Microsoft YaHei UI")));
|
||||
Font.setPointSize(22);
|
||||
return Font;
|
||||
}
|
||||
|
||||
QFont APP_Theme::App_Func_GetKeyHintFont()
|
||||
{
|
||||
// 按键 hint 放左上角,所以字号更小。
|
||||
QFont Font(App_Func_PickFontFamily(QStringList()
|
||||
<< QStringLiteral("Segoe UI Semibold")
|
||||
<< QStringLiteral("Bahnschrift SemiBold")
|
||||
<< QStringLiteral("Microsoft YaHei UI")));
|
||||
Font.setPointSize(8);
|
||||
Font.setLetterSpacing(QFont::AbsoluteSpacing, 1.0);
|
||||
return Font;
|
||||
}
|
||||
|
||||
QString APP_Theme::App_Func_PickFontFamily(const QStringList& FamilyList)
|
||||
{
|
||||
// 从候选字体里依次挑选系统真实存在的字体。
|
||||
const QFontDatabase Database;
|
||||
const QStringList AvailableFamilyList = Database.families();
|
||||
|
||||
for (int Index = 0; Index < FamilyList.size(); ++Index)
|
||||
{
|
||||
const QString& Family = FamilyList.at(Index);
|
||||
if (AvailableFamilyList.contains(Family))
|
||||
{
|
||||
return Family;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果都不存在,就退回 Qt 当前默认字体。
|
||||
return QApplication::font().family();
|
||||
}
|
||||
|
||||
} // namespace APP
|
||||
38
APP/APP_Theme.h
Normal file
38
APP/APP_Theme.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtGui/QFont>
|
||||
#include <QtGui/QPalette>
|
||||
|
||||
namespace APP {
|
||||
|
||||
/*
|
||||
* 主题模块现在只保留一套固定暗色风格。
|
||||
*
|
||||
* - 不参与 DRI 枚举
|
||||
* - 不参与协议解析
|
||||
* - 不参与业务判断
|
||||
*/
|
||||
class APP_Theme
|
||||
{
|
||||
public:
|
||||
// 返回标准控件使用的统一调色板。
|
||||
static QPalette App_Func_GetPalette();
|
||||
|
||||
// 正文说明文字的默认字体。
|
||||
static QFont App_Func_GetBodyFont();
|
||||
// 页面标题字体。
|
||||
static QFont App_Func_GetTitleFont();
|
||||
// 指标、卡片主标题使用的强调字体。
|
||||
static QFont App_Func_GetMetricFont();
|
||||
// 键帽中央主文字字体。
|
||||
static QFont App_Func_GetKeyLabelFont();
|
||||
// 键帽角落提示文字字体。
|
||||
static QFont App_Func_GetKeyHintFont();
|
||||
|
||||
private:
|
||||
// 从候选字体列表中挑出当前系统真实存在的一项。
|
||||
static QString App_Func_PickFontFamily(const QStringList& FamilyList);
|
||||
};
|
||||
|
||||
} // namespace APP
|
||||
420
APP/APP_UIWindow.cpp
Normal file
420
APP/APP_UIWindow.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
#include "APP/APP_UIWindow.h"
|
||||
|
||||
#include "APP/APP_GlassCard.h"
|
||||
#include "APP/APP_KeyButton.h"
|
||||
#include "APP/APP_Theme.h"
|
||||
#include "APP/APP_UIWindow_Private.h"
|
||||
#include "LOGIC/Lgc_Func_Button.h"
|
||||
#include <QtCore/QSignalBlocker>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QFormLayout>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QSizePolicy>
|
||||
#include <QtWidgets/QStackedWidget>
|
||||
#include <QtWidgets/QTabWidget>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
#include <QtWidgets/QTableWidgetItem>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
|
||||
namespace APP {
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
QLabel* App_Func_CreateLabel(
|
||||
QWidget* parent,
|
||||
const QString& Text,
|
||||
const QFont& Font,
|
||||
bool WordWrap = false)
|
||||
{
|
||||
QLabel* p_Label = new QLabel(Text, parent);
|
||||
p_Label->setFont(Font);
|
||||
p_Label->setAttribute(Qt::WA_TranslucentBackground, true);
|
||||
p_Label->setWordWrap(WordWrap);
|
||||
return p_Label;
|
||||
}
|
||||
|
||||
APP_GlassCard* App_Func_CreateCard(QWidget* parent, QVBoxLayout** pp_Layout)
|
||||
{
|
||||
APP_GlassCard* p_Card = new APP_GlassCard(parent);
|
||||
QVBoxLayout* p_Layout = new QVBoxLayout(p_Card);
|
||||
p_Layout->setContentsMargins(20, 20, 20, 20);
|
||||
p_Layout->setSpacing(14);
|
||||
*pp_Layout = p_Layout;
|
||||
return p_Card;
|
||||
}
|
||||
|
||||
void App_Func_SetGridStretch(QGridLayout* p_Grid, int ColumnCount, int RowCount)
|
||||
{
|
||||
for (int Column = 0; Column < ColumnCount; ++Column)
|
||||
{
|
||||
p_Grid->setColumnStretch(Column, 1);
|
||||
}
|
||||
for (int Row = 0; Row < RowCount; ++Row)
|
||||
{
|
||||
p_Grid->setRowStretch(Row, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int App_Func_GetFeatureStackIndex(Lgc_FunctionFeature_Type Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case Lgc_FunctionFeature_Type::KeyCombination:
|
||||
case Lgc_FunctionFeature_Type::KeySequence:
|
||||
return 0;
|
||||
|
||||
case Lgc_FunctionFeature_Type::Website:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool App_Func_IsKeyRecordFeatureType(Lgc_FunctionFeature_Type Type)
|
||||
{
|
||||
return (Type == Lgc_FunctionFeature_Type::KeyCombination) ||
|
||||
(Type == Lgc_FunctionFeature_Type::KeySequence);
|
||||
}
|
||||
|
||||
QString App_Func_GetWebsiteEditText(const QString& UrlText)
|
||||
{
|
||||
const QString DisplayText = UrlText.trimmed();
|
||||
return DisplayText.isEmpty() ? QStringLiteral("https://") : DisplayText;
|
||||
}
|
||||
|
||||
App_UIWindow::App_UIWindow(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
App_Func_InitWindow();
|
||||
App_Func_InitUi();
|
||||
App_Func_InitConnect();
|
||||
App_Func_InitLogic();
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
App_UIWindow::~App_UIWindow()
|
||||
{
|
||||
Lgc_Core_Close(&appLgcState);
|
||||
}
|
||||
|
||||
void App_UIWindow::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
QPainter Painter(this);
|
||||
Painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
Painter.fillRect(rect(), palette().color(QPalette::Window));
|
||||
}
|
||||
|
||||
void App_UIWindow::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
App_Func_UpdateFeatureEditorHeight();
|
||||
}
|
||||
|
||||
bool App_UIWindow::nativeEvent(const QByteArray& EventType, void* p_Message, long* p_Result)
|
||||
{
|
||||
Q_UNUSED(EventType);
|
||||
App_Func_HandleSequenceRecordMessage(p_Message);
|
||||
Lgc_Core_HandleNativeMessage(&appLgcState, p_Message);
|
||||
return QWidget::nativeEvent(EventType, p_Message, p_Result);
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_InitWindow()
|
||||
{
|
||||
setWindowTitle(QStringLiteral("数字键盘上位机"));
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
setMinimumSize(820, 960);
|
||||
resize(900, 1040);
|
||||
#else
|
||||
setMinimumSize(760, 820);
|
||||
resize(820, 900);
|
||||
#endif
|
||||
setAttribute(Qt::WA_StyledBackground, true);
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_InitUi()
|
||||
{
|
||||
QVBoxLayout* p_RootLayout = new QVBoxLayout(this);
|
||||
p_RootLayout->setContentsMargins(26, 22, 26, 24);
|
||||
p_RootLayout->setSpacing(14);
|
||||
|
||||
appPageTab = new QTabWidget(this);
|
||||
appPageTab->setDocumentMode(true);
|
||||
appPageTab->setMovable(false);
|
||||
|
||||
appPageTab->addTab(App_Func_CreatePadCard(), QStringLiteral("按键映射"));
|
||||
appFeaturePageIndex = appPageTab->addTab(App_Func_CreateFunctionConfigCard(), QStringLiteral("功能表"));
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
appPageTab->addTab(App_Func_CreateDebugCard(), QStringLiteral("调试"));
|
||||
#endif
|
||||
|
||||
p_RootLayout->addWidget(appPageTab, 1);
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_InitConnect()
|
||||
{
|
||||
connect(&appTimerPoll, &QTimer::timeout, this, &App_UIWindow::App_Func_OnPollTimer);
|
||||
connect(&appTimerAutoRefreshDevice, &QTimer::timeout, this, [this]()
|
||||
{
|
||||
if (appLgcState.IsConnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QString OldTextLog = appLgcState.TextLog;
|
||||
Lgc_Core_RefreshDevice(&appLgcState);
|
||||
if (!appLgcState.IsConnected)
|
||||
{
|
||||
appLgcState.TextLog = OldTextLog;
|
||||
}
|
||||
App_Func_RefreshAfterLogicChange();
|
||||
});
|
||||
|
||||
connect(appFeatureAddButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_AddFeature);
|
||||
connect(appFeatureDeleteButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_DeleteFeature);
|
||||
|
||||
connect(appFeatureTable, &QTableWidget::itemSelectionChanged, this, [this]()
|
||||
{
|
||||
const QModelIndexList IndexList = appFeatureTable->selectionModel()->selectedRows();
|
||||
if (IndexList.isEmpty())
|
||||
{
|
||||
App_Func_SelectFeature(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const int Row = IndexList.first().row();
|
||||
const QTableWidgetItem* p_Item = appFeatureTable->item(Row, 0);
|
||||
App_Func_SelectFeature(p_Item == nullptr ? 0 : p_Item->data(Qt::UserRole).toInt());
|
||||
});
|
||||
|
||||
const auto ConnectSaveSignal = [this](auto Sender, auto Signal)
|
||||
{
|
||||
connect(Sender, Signal, this, [this]()
|
||||
{
|
||||
if (!appIsUpdatingFeatureUi)
|
||||
{
|
||||
App_Func_SaveFeatureFromUi();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ConnectSaveSignal(appFeatureNameEdit, &QLineEdit::textChanged);
|
||||
ConnectSaveSignal(appFeatureDescriptionEdit, &QLineEdit::textChanged);
|
||||
ConnectSaveSignal(appFeatureTypeCombo, qOverload<int>(&QComboBox::currentIndexChanged));
|
||||
ConnectSaveSignal(appFeatureSequenceEdit, &QLineEdit::textChanged);
|
||||
ConnectSaveSignal(appFeatureWebsiteEdit, &QLineEdit::textChanged);
|
||||
|
||||
connect(appFeatureSequenceRecordStartButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_StartSequenceRecording);
|
||||
connect(appFeatureSequenceRecordStopButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_StopSequenceRecording);
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
connect(appDebugPanel->Debug_Func_GetRefreshButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnRefreshDeviceClicked);
|
||||
connect(appDebugPanel->Debug_Func_GetClearButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnClearLogClicked);
|
||||
connect(appDebugPanel->Debug_Func_GetApplyConfigButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnApplyDeviceConfigClicked);
|
||||
connect(appDebugPanel->Debug_Func_GetSyncTimeButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnSyncTimeClicked);
|
||||
connect(appDebugPanel->Debug_Func_GetModeSwitchButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnModeSwitchClicked);
|
||||
#endif
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_InitLogic()
|
||||
{
|
||||
Lgc_Core_Init(&appLgcState);
|
||||
Lgc_Core_SetWindowHandle(&appLgcState, reinterpret_cast<void*>(winId()));
|
||||
|
||||
App_Func_RefreshFeatureTable();
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
App_Func_RefreshDeviceConfigFromState();
|
||||
#endif
|
||||
Lgc_Core_Start(&appLgcState);
|
||||
appTimerPoll.setInterval(30);
|
||||
appTimerPoll.start();
|
||||
appTimerAutoRefreshDevice.setInterval(1500);
|
||||
appTimerAutoRefreshDevice.start();
|
||||
App_Func_RefreshAfterLogicChange();
|
||||
}
|
||||
|
||||
QWidget* App_UIWindow::App_Func_CreatePadCard()
|
||||
{
|
||||
QVBoxLayout* p_Layout = nullptr;
|
||||
APP_GlassCard* p_Card = App_Func_CreateCard(this, &p_Layout);
|
||||
p_Layout->addWidget(App_Func_CreateLabel(
|
||||
p_Card,
|
||||
QStringLiteral("按键映射"),
|
||||
APP_Theme::App_Func_GetMetricFont()));
|
||||
p_Layout->addWidget(App_Func_CreateLabel(
|
||||
p_Card,
|
||||
QStringLiteral("左键直接模拟真实小键盘按下/抬起;右键把当前按键绑定到某个功能。绑定后,键帽左上角会显示功能名,悬停会显示功能简介。"),
|
||||
APP_Theme::App_Func_GetBodyFont(),
|
||||
true));
|
||||
|
||||
QGridLayout* p_Grid = new QGridLayout();
|
||||
p_Grid->setSpacing(14);
|
||||
|
||||
for (const APP_KeyInfo& Key : appKeypadModel.App_Func_GetKeyList())
|
||||
{
|
||||
APP_KeyButton* p_Button = new APP_KeyButton(Key, p_Card);
|
||||
p_Button->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(p_Button, &QPushButton::pressed, this, [this, Key]() { App_Func_HandleUiKeyPressed(Key.usage); });
|
||||
connect(p_Button, &QPushButton::released, this, [this, Key]() { App_Func_HandleUiKeyReleased(Key.usage); });
|
||||
connect(p_Button, &QWidget::customContextMenuRequested, this, [this, p_Button, Key](const QPoint&)
|
||||
{
|
||||
App_Func_ShowKeyMenu(
|
||||
Key.usage,
|
||||
p_Button->mapToGlobal(QPoint(p_Button->width() / 2, p_Button->height() / 2)));
|
||||
});
|
||||
|
||||
appKeypadButtonMap.insert(Key.id, p_Button);
|
||||
p_Grid->addWidget(p_Button, Key.row, Key.column, Key.rowSpan, Key.columnSpan);
|
||||
}
|
||||
|
||||
App_Func_SetGridStretch(p_Grid, 4, 5);
|
||||
p_Layout->addLayout(p_Grid, 1);
|
||||
return p_Card;
|
||||
}
|
||||
|
||||
QWidget* App_UIWindow::App_Func_CreateFunctionConfigCard()
|
||||
{
|
||||
QVBoxLayout* p_Layout = nullptr;
|
||||
APP_GlassCard* p_Card = App_Func_CreateCard(this, &p_Layout);
|
||||
const auto AddRow = [p_Card](QFormLayout* p_Form, const QString& LabelText, QWidget* p_Field)
|
||||
{
|
||||
p_Form->addRow(App_Func_CreateLabel(p_Card, LabelText, APP_Theme::App_Func_GetBodyFont()), p_Field);
|
||||
};
|
||||
|
||||
p_Layout->addWidget(App_Func_CreateLabel(
|
||||
p_Card,
|
||||
QStringLiteral("功能表"),
|
||||
APP_Theme::App_Func_GetMetricFont()));
|
||||
p_Layout->addWidget(App_Func_CreateLabel(
|
||||
p_Card,
|
||||
QStringLiteral("功能表默认为空,请先添加功能,再把按钮绑定到某个功能。当前支持“快捷键”“快捷键序列”和“打开网址”三种功能类型。"),
|
||||
APP_Theme::App_Func_GetBodyFont(),
|
||||
true));
|
||||
|
||||
QHBoxLayout* p_TopRow = new QHBoxLayout();
|
||||
p_TopRow->setContentsMargins(0, 0, 0, 0);
|
||||
p_TopRow->setSpacing(10);
|
||||
appFeatureAddButton = new QPushButton(QStringLiteral("添加功能"), p_Card);
|
||||
appFeatureDeleteButton = new QPushButton(QStringLiteral("删除功能"), p_Card);
|
||||
appFeatureDeleteButton->setEnabled(false);
|
||||
p_TopRow->addWidget(appFeatureAddButton);
|
||||
p_TopRow->addWidget(appFeatureDeleteButton);
|
||||
p_TopRow->addStretch(1);
|
||||
p_Layout->addLayout(p_TopRow);
|
||||
|
||||
appFeatureTable = new QTableWidget(p_Card);
|
||||
appFeatureTable->setColumnCount(3);
|
||||
appFeatureTable->setHorizontalHeaderLabels({ QStringLiteral("功能名"), QStringLiteral("功能简介"), QStringLiteral("类型") });
|
||||
appFeatureTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
appFeatureTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
appFeatureTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
appFeatureTable->setAlternatingRowColors(true);
|
||||
appFeatureTable->verticalHeader()->setVisible(false);
|
||||
appFeatureTable->horizontalHeader()->setStretchLastSection(false);
|
||||
appFeatureTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
appFeatureTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
appFeatureTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
||||
appFeatureTable->setMinimumHeight(220);
|
||||
p_Layout->addWidget(appFeatureTable);
|
||||
|
||||
QFormLayout* p_Form = new QFormLayout();
|
||||
p_Form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
p_Form->setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
p_Form->setHorizontalSpacing(10);
|
||||
p_Form->setVerticalSpacing(10);
|
||||
|
||||
appFeatureNameEdit = new QLineEdit(p_Card);
|
||||
appFeatureNameEdit->setPlaceholderText(QStringLiteral("例如:功能1 / 打开4399 / 前缀补码"));
|
||||
AddRow(p_Form, QStringLiteral("功能名"), appFeatureNameEdit);
|
||||
|
||||
appFeatureDescriptionEdit = new QLineEdit(p_Card);
|
||||
appFeatureDescriptionEdit->setPlaceholderText(QStringLiteral("例如:打开 4399 首页"));
|
||||
AddRow(p_Form, QStringLiteral("功能简介"), appFeatureDescriptionEdit);
|
||||
|
||||
appFeatureTypeCombo = new QComboBox(p_Card);
|
||||
appFeatureTypeCombo->addItem(
|
||||
Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::KeyCombination),
|
||||
static_cast<int>(Lgc_FunctionFeature_Type::KeyCombination));
|
||||
appFeatureTypeCombo->addItem(
|
||||
Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::KeySequence),
|
||||
static_cast<int>(Lgc_FunctionFeature_Type::KeySequence));
|
||||
appFeatureTypeCombo->addItem(
|
||||
Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::Website),
|
||||
static_cast<int>(Lgc_FunctionFeature_Type::Website));
|
||||
AddRow(p_Form, QStringLiteral("功能类型"), appFeatureTypeCombo);
|
||||
|
||||
appFeatureEditorStack = new QStackedWidget(p_Card);
|
||||
appFeatureEditorStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
QWidget* p_SequencePage = new QWidget(appFeatureEditorStack);
|
||||
QFormLayout* p_SequenceForm = new QFormLayout(p_SequencePage);
|
||||
p_SequenceForm->setContentsMargins(0, 0, 0, 0);
|
||||
p_SequenceForm->setHorizontalSpacing(10);
|
||||
p_SequenceForm->setVerticalSpacing(10);
|
||||
|
||||
QWidget* p_SequenceEditor = new QWidget(p_SequencePage);
|
||||
QHBoxLayout* p_SequenceEditorLayout = new QHBoxLayout(p_SequenceEditor);
|
||||
p_SequenceEditorLayout->setContentsMargins(0, 0, 0, 0);
|
||||
p_SequenceEditorLayout->setSpacing(8);
|
||||
appFeatureSequenceEdit = new QLineEdit(p_SequenceEditor);
|
||||
appFeatureSequenceEdit->setPlaceholderText(QStringLiteral("例如:Ctrl+C"));
|
||||
appFeatureSequenceRecordStartButton = new QPushButton(QStringLiteral("开始录入"), p_SequenceEditor);
|
||||
appFeatureSequenceRecordStopButton = new QPushButton(QStringLiteral("退出录入"), p_SequenceEditor);
|
||||
appFeatureSequenceRecordStopButton->setEnabled(false);
|
||||
p_SequenceEditorLayout->addWidget(appFeatureSequenceEdit, 1);
|
||||
p_SequenceEditorLayout->addWidget(appFeatureSequenceRecordStartButton);
|
||||
p_SequenceEditorLayout->addWidget(appFeatureSequenceRecordStopButton);
|
||||
p_SequenceForm->addRow(QStringLiteral("快捷键"), p_SequenceEditor);
|
||||
|
||||
QWidget* p_WebsitePage = new QWidget(appFeatureEditorStack);
|
||||
QVBoxLayout* p_WebsiteLayout = new QVBoxLayout(p_WebsitePage);
|
||||
p_WebsiteLayout->setContentsMargins(0, 0, 0, 0);
|
||||
p_WebsiteLayout->setSpacing(0);
|
||||
appFeatureWebsiteEdit = new QLineEdit(p_WebsitePage);
|
||||
appFeatureWebsiteEdit->setPlaceholderText(QStringLiteral("例如直接输入 4399.com 或 www.4399.com"));
|
||||
p_WebsiteLayout->addWidget(appFeatureWebsiteEdit);
|
||||
|
||||
appFeatureEditorStack->addWidget(p_SequencePage);
|
||||
appFeatureEditorStack->addWidget(p_WebsitePage);
|
||||
AddRow(p_Form, QStringLiteral("功能参数"), appFeatureEditorStack);
|
||||
|
||||
appFeatureBindingSummaryLabel = App_Func_CreateLabel(
|
||||
p_Card,
|
||||
QStringLiteral("当前还没有功能,请点击“添加功能”。"),
|
||||
APP_Theme::App_Func_GetBodyFont(),
|
||||
true);
|
||||
AddRow(p_Form, QStringLiteral("绑定情况"), appFeatureBindingSummaryLabel);
|
||||
|
||||
appFunctionLabelStatus = App_Func_CreateLabel(
|
||||
p_Card,
|
||||
QStringLiteral("等待按键动作。"),
|
||||
APP_Theme::App_Func_GetBodyFont(),
|
||||
true);
|
||||
AddRow(p_Form, QStringLiteral("最近一次动作"), appFunctionLabelStatus);
|
||||
|
||||
p_Layout->addLayout(p_Form);
|
||||
p_Layout->addStretch(1);
|
||||
return p_Card;
|
||||
}
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
QWidget* App_UIWindow::App_Func_CreateDebugCard()
|
||||
{
|
||||
appDebugPanel = new DEBUG::Debug_Panel(this);
|
||||
appDebugPanel->Debug_Func_SetConnectionText(QStringLiteral("未连接,等待枚举设备。"), false);
|
||||
appDebugPanel->Debug_Func_SetLogText(QStringLiteral("等待收到输入包。"));
|
||||
return appDebugPanel;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace APP
|
||||
125
APP/APP_UIWindow.h
Normal file
125
APP/APP_UIWindow.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include "APP/APP_KeypadModel.h"
|
||||
#include "DEBUG/Debug_Config.h"
|
||||
#include "LOGIC/Lgc_Core.h"
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
#include "DEBUG/Debug_Panel.h"
|
||||
#endif
|
||||
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QResizeEvent;
|
||||
class QStackedWidget;
|
||||
class QTabWidget;
|
||||
class QTableWidget;
|
||||
|
||||
namespace APP {
|
||||
|
||||
class APP_KeyButton;
|
||||
|
||||
class App_UIWindow : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit App_UIWindow(QWidget* parent = nullptr);
|
||||
~App_UIWindow() override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
bool nativeEvent(const QByteArray& EventType, void* p_Message, long* p_Result) override;
|
||||
|
||||
private:
|
||||
void App_Func_InitWindow();
|
||||
void App_Func_InitUi();
|
||||
void App_Func_InitConnect();
|
||||
void App_Func_InitLogic();
|
||||
void App_Func_RefreshUi();
|
||||
void App_Func_RefreshKeypadState();
|
||||
void App_Func_RefreshKeypadButtons();
|
||||
void App_Func_RefreshFeatureTable();
|
||||
void App_Func_RefreshFunctionStatus();
|
||||
void App_Func_RefreshDebugView();
|
||||
void App_Func_RefreshAfterLogicChange();
|
||||
void App_Func_SelectFeature(int FeatureId, bool SwitchToFeaturePage = false);
|
||||
void App_Func_SaveFeatureFromUi();
|
||||
void App_Func_UpdateFeatureEditorState();
|
||||
void App_Func_UpdateFeatureEditorHeight();
|
||||
void App_Func_AddFeature();
|
||||
void App_Func_DeleteFeature();
|
||||
void App_Func_AssignFeatureToUsage(quint16 Usage, int FeatureId);
|
||||
void App_Func_HandleUiKeyPressed(quint16 Usage);
|
||||
void App_Func_HandleUiKeyReleased(quint16 Usage);
|
||||
void App_Func_ShowKeyMenu(quint16 Usage, const QPoint& GlobalPos);
|
||||
void App_Func_StartSequenceRecording();
|
||||
void App_Func_StopSequenceRecording();
|
||||
void App_Func_UpdateSequenceRecordingUi();
|
||||
bool App_Func_HandleSequenceRecordMessage(void* p_Message);
|
||||
void App_Func_AppendRecordedSequenceToken(const QString& Token);
|
||||
QString App_Func_GetKeyHintText(const QString& KeyId) const;
|
||||
QString App_Func_GetFeatureNameById(int FeatureId) const;
|
||||
QString App_Func_GetFeatureDescriptionById(int FeatureId) const;
|
||||
QString App_Func_GetFeatureDescriptionForUsage(quint16 Usage) const;
|
||||
QString App_Func_GetDefaultKeyDescription(quint16 Usage) const;
|
||||
QString App_Func_GetFeatureBindingSummary(int FeatureId) const;
|
||||
void App_Func_OnPollTimer();
|
||||
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
void App_Func_OnApplyDeviceConfigClicked();
|
||||
void App_Func_OnRefreshDeviceClicked();
|
||||
void App_Func_OnClearLogClicked();
|
||||
void App_Func_OnSyncTimeClicked();
|
||||
void App_Func_OnModeSwitchClicked();
|
||||
void App_Func_RefreshDeviceConfigFromState();
|
||||
#endif
|
||||
|
||||
QWidget* App_Func_CreatePadCard();
|
||||
QWidget* App_Func_CreateFunctionConfigCard();
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
QWidget* App_Func_CreateDebugCard();
|
||||
#endif
|
||||
|
||||
APP_KeypadModel appKeypadModel;
|
||||
QHash<QString, APP_KeyButton*> appKeypadButtonMap;
|
||||
QTabWidget* appPageTab = nullptr;
|
||||
int appFeaturePageIndex = 0;
|
||||
|
||||
QLabel* appFunctionLabelStatus = nullptr;
|
||||
QTableWidget* appFeatureTable = nullptr;
|
||||
QPushButton* appFeatureAddButton = nullptr;
|
||||
QPushButton* appFeatureDeleteButton = nullptr;
|
||||
QLabel* appFeatureParameterHintLabel = nullptr;
|
||||
QLabel* appFeatureBindingSummaryLabel = nullptr;
|
||||
QLineEdit* appFeatureNameEdit = nullptr;
|
||||
QLineEdit* appFeatureDescriptionEdit = nullptr;
|
||||
QComboBox* appFeatureTypeCombo = nullptr;
|
||||
QStackedWidget* appFeatureEditorStack = nullptr;
|
||||
QLineEdit* appFeatureSequenceEdit = nullptr;
|
||||
QLineEdit* appFeatureWebsiteEdit = nullptr;
|
||||
QPushButton* appFeatureSequenceRecordStartButton = nullptr;
|
||||
QPushButton* appFeatureSequenceRecordStopButton = nullptr;
|
||||
bool appIsUpdatingFeatureUi = false;
|
||||
bool appIsSequenceRecording = false;
|
||||
int appSelectedFeatureId = 0;
|
||||
QSet<quint16> appUiPressedUsageSet;
|
||||
QSet<QString> appSequenceRecordingPressedKeySet;
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
DEBUG::Debug_Panel* appDebugPanel = nullptr;
|
||||
#endif
|
||||
|
||||
QTimer appTimerPoll;
|
||||
QTimer appTimerAutoRefreshDevice;
|
||||
Lgc_Core_Struct_State appLgcState;
|
||||
};
|
||||
|
||||
} // namespace APP
|
||||
519
APP/APP_UIWindow_Feature.cpp
Normal file
519
APP/APP_UIWindow_Feature.cpp
Normal file
@@ -0,0 +1,519 @@
|
||||
#include "APP/APP_UIWindow.h"
|
||||
|
||||
#include "APP/APP_KeyButton.h"
|
||||
#include "APP/APP_UIWindow_Private.h"
|
||||
#include "DEBUG/Debug_Panel.h"
|
||||
#include <QtCore/QSignalBlocker>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QLayout>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QStackedWidget>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
#include <QtWidgets/QTableWidgetItem>
|
||||
|
||||
namespace APP {
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool App_Func_HasDebugSendRoute(const Lgc_Core_Struct_State& State)
|
||||
{
|
||||
return State.DriVendorPort.ReadPort.IsOpened || State.DriBlePort.IsConnected;
|
||||
}
|
||||
|
||||
QString App_Func_GetDebugSendModeText(const Lgc_Core_Struct_State& State)
|
||||
{
|
||||
if (State.DriBlePort.IsConnected || State.DriVendorPort.IsBluetoothTransport)
|
||||
{
|
||||
return QStringLiteral("蓝牙模式");
|
||||
}
|
||||
|
||||
if (State.DriVendorPort.ReadPort.IsOpened)
|
||||
{
|
||||
return QStringLiteral("USB 模式");
|
||||
}
|
||||
|
||||
return QStringLiteral("未连接");
|
||||
}
|
||||
|
||||
QString App_Func_GetDebugConfigStatusText(const Lgc_Core_Struct_State& State)
|
||||
{
|
||||
return QStringLiteral("目标 USB 0x%1:0x%2 / 当前发包模式:%3")
|
||||
.arg(State.DeviceConfig.VendorId, 4, 16, QLatin1Char('0'))
|
||||
.arg(State.DeviceConfig.ProductId, 4, 16, QLatin1Char('0'))
|
||||
.arg(App_Func_GetDebugSendModeText(State))
|
||||
.toUpper();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void App_UIWindow::App_Func_RefreshUi()
|
||||
{
|
||||
App_Func_RefreshKeypadButtons();
|
||||
App_Func_RefreshFunctionStatus();
|
||||
update();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_RefreshKeypadState()
|
||||
{
|
||||
appKeypadModel.App_Func_SetNumLockOn(appLgcState.IsSystemNumLockOn);
|
||||
|
||||
const QVector<quint16>* p_UsageList = appLgcState.IsPhysicalKeyStateValid
|
||||
? &appLgcState.PhysicalUsageList
|
||||
: (appLgcState.IsVisibleKeyStateValid ? &appLgcState.VisibleUsageList : nullptr);
|
||||
if (p_UsageList != nullptr)
|
||||
{
|
||||
appKeypadModel.App_Func_SetPressedKeysFromUsageList(*p_UsageList);
|
||||
}
|
||||
else
|
||||
{
|
||||
appKeypadModel.App_Func_ClearPressedKeys();
|
||||
}
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_RefreshKeypadButtons()
|
||||
{
|
||||
for (auto It = appKeypadButtonMap.begin(); It != appKeypadButtonMap.end(); ++It)
|
||||
{
|
||||
const QString KeyId = It.key();
|
||||
const quint16 Usage = appKeypadModel.App_Func_GetUsageFromKeyId(KeyId);
|
||||
const bool HasFeature =
|
||||
Lgc_FunctionButton_HasUsageFeature(appLgcState.FunctionButtonConfig, Usage);
|
||||
APP_KeyButton* p_Button = It.value();
|
||||
p_Button->App_Func_SetLatched(appKeypadModel.App_Func_IsLatched(KeyId) || HasFeature);
|
||||
p_Button->App_Func_SetPressed(appKeypadModel.App_Func_IsPressed(KeyId));
|
||||
p_Button->App_Func_SetHintText(App_Func_GetKeyHintText(KeyId));
|
||||
p_Button->setToolTip(App_Func_GetFeatureDescriptionForUsage(Usage));
|
||||
}
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_RefreshFeatureTable()
|
||||
{
|
||||
if (appFeatureTable == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QVector<int> FeatureIdList = Lgc_FunctionButton_GetFeatureIdList(appLgcState.FunctionButtonConfig);
|
||||
QSignalBlocker Blocker(appFeatureTable);
|
||||
appFeatureTable->clearContents();
|
||||
appFeatureTable->setRowCount(FeatureIdList.size());
|
||||
|
||||
int TargetRow = -1;
|
||||
for (int Row = 0; Row < FeatureIdList.size(); ++Row)
|
||||
{
|
||||
const int FeatureId = FeatureIdList.at(Row);
|
||||
const Lgc_FunctionFeature_Definition Feature = Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, FeatureId);
|
||||
QTableWidgetItem* p_NameItem = new QTableWidgetItem(Lgc_FunctionButton_GetFeatureName(Feature));
|
||||
p_NameItem->setData(Qt::UserRole, FeatureId);
|
||||
appFeatureTable->setItem(Row, 0, p_NameItem);
|
||||
appFeatureTable->setItem(Row, 1, new QTableWidgetItem(App_Func_GetFeatureDescriptionById(FeatureId)));
|
||||
appFeatureTable->setItem(Row, 2, new QTableWidgetItem(Lgc_FunctionButton_GetFeatureTypeText(Feature.Type)));
|
||||
if (FeatureId == appSelectedFeatureId)
|
||||
{
|
||||
TargetRow = Row;
|
||||
}
|
||||
}
|
||||
|
||||
appSelectedFeatureId =
|
||||
TargetRow >= 0 ? appSelectedFeatureId : (FeatureIdList.isEmpty() ? 0 : FeatureIdList.first());
|
||||
TargetRow = TargetRow >= 0 ? TargetRow : (FeatureIdList.isEmpty() ? -1 : 0);
|
||||
if (TargetRow >= 0)
|
||||
{
|
||||
appFeatureTable->selectRow(TargetRow);
|
||||
}
|
||||
else
|
||||
{
|
||||
appFeatureTable->clearSelection();
|
||||
}
|
||||
App_Func_UpdateFeatureEditorState();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_RefreshFunctionStatus()
|
||||
{
|
||||
if (appFunctionLabelStatus != nullptr)
|
||||
{
|
||||
appFunctionLabelStatus->setText(
|
||||
appLgcState.TextFunctionStatus.isEmpty()
|
||||
? QStringLiteral("等待按键动作。")
|
||||
: appLgcState.TextFunctionStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_RefreshDebugView()
|
||||
{
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
appDebugPanel->Debug_Func_SetConfigStatusText(
|
||||
App_Func_GetDebugConfigStatusText(appLgcState),
|
||||
App_Func_HasDebugSendRoute(appLgcState));
|
||||
appDebugPanel->Debug_Func_SetConnectionText(
|
||||
appLgcState.IsConnected ? QStringLiteral("连接成功") : QStringLiteral("连接失败"),
|
||||
appLgcState.IsConnected);
|
||||
appDebugPanel->Debug_Func_SetLogText(appLgcState.TextLog);
|
||||
#endif
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_RefreshAfterLogicChange()
|
||||
{
|
||||
App_Func_RefreshKeypadState();
|
||||
App_Func_RefreshDebugView();
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_SelectFeature(int FeatureId, bool SwitchToFeaturePage)
|
||||
{
|
||||
if (appIsSequenceRecording && (FeatureId != appSelectedFeatureId))
|
||||
{
|
||||
App_Func_StopSequenceRecording();
|
||||
}
|
||||
|
||||
appSelectedFeatureId =
|
||||
appLgcState.FunctionButtonConfig.FeatureMap.contains(FeatureId) ? FeatureId : 0;
|
||||
|
||||
if ((appFeatureTable != nullptr) && (appSelectedFeatureId > 0))
|
||||
{
|
||||
for (int Row = 0; Row < appFeatureTable->rowCount(); ++Row)
|
||||
{
|
||||
QTableWidgetItem* p_Item = appFeatureTable->item(Row, 0);
|
||||
if ((p_Item != nullptr) && (p_Item->data(Qt::UserRole).toInt() == appSelectedFeatureId))
|
||||
{
|
||||
QSignalBlocker Blocker(appFeatureTable);
|
||||
appFeatureTable->selectRow(Row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
App_Func_UpdateFeatureEditorState();
|
||||
if (SwitchToFeaturePage && (appPageTab != nullptr))
|
||||
{
|
||||
appPageTab->setCurrentIndex(appFeaturePageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_SaveFeatureFromUi()
|
||||
{
|
||||
if (appSelectedFeatureId <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
|
||||
if (Feature.Id <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Feature.Name = appFeatureNameEdit->text();
|
||||
Feature.Description = appFeatureDescriptionEdit->text();
|
||||
Feature.Type = static_cast<Lgc_FunctionFeature_Type>(appFeatureTypeCombo->currentData().toInt());
|
||||
Feature.SequenceText = appFeatureSequenceEdit->text();
|
||||
Feature.WebsiteUrl = appFeatureWebsiteEdit->text();
|
||||
if ((Feature.Type == Lgc_FunctionFeature_Type::Website) &&
|
||||
Feature.WebsiteUrl.trimmed().isEmpty())
|
||||
{
|
||||
Feature.WebsiteUrl = QStringLiteral("https://");
|
||||
QSignalBlocker Blocker(appFeatureWebsiteEdit);
|
||||
appFeatureWebsiteEdit->setText(Feature.WebsiteUrl);
|
||||
}
|
||||
|
||||
Lgc_FunctionButton_SetFeature(&appLgcState.FunctionButtonConfig, Feature);
|
||||
|
||||
appFeatureEditorStack->setCurrentIndex(App_Func_GetFeatureStackIndex(Feature.Type));
|
||||
App_Func_UpdateFeatureEditorHeight();
|
||||
App_Func_RefreshFeatureTable();
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_UpdateFeatureEditorHeight()
|
||||
{
|
||||
if (appFeatureEditorStack == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget* p_CurrentPage = appFeatureEditorStack->currentWidget();
|
||||
if (p_CurrentPage == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int AvailableWidth = qMax(
|
||||
p_CurrentPage->contentsRect().width(),
|
||||
appFeatureEditorStack->contentsRect().width());
|
||||
int Height = p_CurrentPage->minimumSizeHint().height();
|
||||
if (QLayout* p_Layout = p_CurrentPage->layout())
|
||||
{
|
||||
if ((AvailableWidth > 0) && p_Layout->hasHeightForWidth())
|
||||
{
|
||||
Height = qMax(Height, p_Layout->totalHeightForWidth(AvailableWidth));
|
||||
}
|
||||
Height = qMax(Height, p_Layout->sizeHint().height());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((AvailableWidth > 0) && p_CurrentPage->hasHeightForWidth())
|
||||
{
|
||||
Height = qMax(Height, p_CurrentPage->heightForWidth(AvailableWidth));
|
||||
}
|
||||
Height = qMax(Height, p_CurrentPage->sizeHint().height());
|
||||
}
|
||||
|
||||
if (appFeatureEditorStack->height() != Height)
|
||||
{
|
||||
appFeatureEditorStack->setFixedHeight(Height);
|
||||
}
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_UpdateFeatureEditorState()
|
||||
{
|
||||
const Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
|
||||
const bool HasFeature = Feature.Id > 0;
|
||||
|
||||
if (appIsSequenceRecording && (!HasFeature || !App_Func_IsKeyRecordFeatureType(Feature.Type)))
|
||||
{
|
||||
App_Func_StopSequenceRecording();
|
||||
}
|
||||
|
||||
appFeatureNameEdit->setEnabled(HasFeature);
|
||||
appFeatureDescriptionEdit->setEnabled(HasFeature);
|
||||
appFeatureTypeCombo->setEnabled(HasFeature);
|
||||
appFeatureEditorStack->setEnabled(HasFeature);
|
||||
if (appFeatureDeleteButton != nullptr)
|
||||
{
|
||||
appFeatureDeleteButton->setEnabled(HasFeature);
|
||||
}
|
||||
|
||||
appIsUpdatingFeatureUi = true;
|
||||
if (!HasFeature)
|
||||
{
|
||||
appFeatureNameEdit->clear();
|
||||
appFeatureDescriptionEdit->clear();
|
||||
appFeatureSequenceEdit->clear();
|
||||
appFeatureWebsiteEdit->clear();
|
||||
appFeatureTypeCombo->setCurrentIndex(0);
|
||||
appFeatureEditorStack->setCurrentIndex(0);
|
||||
App_Func_UpdateFeatureEditorHeight();
|
||||
appFeatureBindingSummaryLabel->setText(QStringLiteral("当前还没有功能,请点击“添加功能”。"));
|
||||
appIsUpdatingFeatureUi = false;
|
||||
App_Func_UpdateSequenceRecordingUi();
|
||||
return;
|
||||
}
|
||||
|
||||
appFeatureNameEdit->setText(Feature.Name);
|
||||
appFeatureDescriptionEdit->setText(Feature.Description);
|
||||
const int TypeIndex = appFeatureTypeCombo->findData(static_cast<int>(Feature.Type));
|
||||
if (TypeIndex >= 0)
|
||||
{
|
||||
appFeatureTypeCombo->setCurrentIndex(TypeIndex);
|
||||
}
|
||||
appFeatureSequenceEdit->setText(Feature.SequenceText);
|
||||
appFeatureWebsiteEdit->setText(App_Func_GetWebsiteEditText(Feature.WebsiteUrl));
|
||||
appFeatureEditorStack->setCurrentIndex(App_Func_GetFeatureStackIndex(Feature.Type));
|
||||
appFeatureSequenceEdit->setPlaceholderText(
|
||||
Feature.Type == Lgc_FunctionFeature_Type::KeySequence
|
||||
? QStringLiteral("例如:Ctrl+C -> Ctrl+A")
|
||||
: QStringLiteral("例如:Ctrl+C"));
|
||||
App_Func_UpdateFeatureEditorHeight();
|
||||
appFeatureBindingSummaryLabel->setText(App_Func_GetFeatureBindingSummary(Feature.Id));
|
||||
appIsUpdatingFeatureUi = false;
|
||||
App_Func_UpdateSequenceRecordingUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_AddFeature()
|
||||
{
|
||||
const int FeatureId = Lgc_FunctionButton_AddFeature(&appLgcState.FunctionButtonConfig);
|
||||
App_Func_RefreshFeatureTable();
|
||||
App_Func_SelectFeature(FeatureId, true);
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_DeleteFeature()
|
||||
{
|
||||
if (appSelectedFeatureId <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (appIsSequenceRecording)
|
||||
{
|
||||
App_Func_StopSequenceRecording();
|
||||
}
|
||||
|
||||
const QString FeatureName = App_Func_GetFeatureNameById(appSelectedFeatureId);
|
||||
Lgc_FunctionButton_RemoveFeature(&appLgcState.FunctionButtonConfig, appSelectedFeatureId);
|
||||
appSelectedFeatureId = 0;
|
||||
Lgc_Core_ApplyFunctionConfig(&appLgcState);
|
||||
appLgcState.TextFunctionStatus = QStringLiteral("已删除功能:%1").arg(FeatureName);
|
||||
App_Func_RefreshFeatureTable();
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_AssignFeatureToUsage(quint16 Usage, int FeatureId)
|
||||
{
|
||||
if (FeatureId > 0 && !appLgcState.FunctionButtonConfig.FeatureMap.contains(FeatureId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Lgc_FunctionButton_SetUsageFeatureId(&appLgcState.FunctionButtonConfig, Usage, FeatureId);
|
||||
Lgc_Core_ApplyFunctionConfig(&appLgcState);
|
||||
appLgcState.TextFunctionStatus = FeatureId > 0
|
||||
? QStringLiteral("已将按键 %1 绑定到 %2。")
|
||||
.arg(Lgc_FunctionButton_GetUsageShortText(Usage), App_Func_GetFeatureNameById(FeatureId))
|
||||
: QStringLiteral("已清除按键 %1 的功能绑定。")
|
||||
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
App_Func_RefreshFeatureTable();
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
QString App_UIWindow::App_Func_GetKeyHintText(const QString& KeyId) const
|
||||
{
|
||||
const quint16 Usage = appKeypadModel.App_Func_GetUsageFromKeyId(KeyId);
|
||||
const int FeatureId = Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage);
|
||||
return FeatureId > 0 ? App_Func_GetFeatureNameById(FeatureId) : appKeypadModel.App_Func_GetDefaultHint(KeyId);
|
||||
}
|
||||
|
||||
QString App_UIWindow::App_Func_GetFeatureNameById(int FeatureId) const
|
||||
{
|
||||
const Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, FeatureId);
|
||||
return Feature.Id > 0 ? Lgc_FunctionButton_GetFeatureName(Feature) : QStringLiteral("无功能");
|
||||
}
|
||||
|
||||
QString App_UIWindow::App_Func_GetFeatureDescriptionById(int FeatureId) const
|
||||
{
|
||||
const Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, FeatureId);
|
||||
if (Feature.Id <= 0)
|
||||
{
|
||||
return QStringLiteral("未绑定功能。");
|
||||
}
|
||||
|
||||
if (!Feature.Description.trimmed().isEmpty())
|
||||
{
|
||||
return Feature.Description.trimmed();
|
||||
}
|
||||
|
||||
switch (Feature.Type)
|
||||
{
|
||||
case Lgc_FunctionFeature_Type::KeyCombination:
|
||||
return Feature.SequenceText.trimmed().isEmpty()
|
||||
? QStringLiteral("输出一次快捷键,当前还没有配置快捷键。")
|
||||
: QStringLiteral("输出快捷键:%1").arg(Feature.SequenceText.trimmed());
|
||||
|
||||
case Lgc_FunctionFeature_Type::KeySequence:
|
||||
return Feature.SequenceText.trimmed().isEmpty()
|
||||
? QStringLiteral("按顺序输出多组快捷键,当前还没有配置序列。")
|
||||
: QStringLiteral("输出快捷键序列:%1").arg(Feature.SequenceText.trimmed());
|
||||
|
||||
case Lgc_FunctionFeature_Type::Website:
|
||||
return Feature.WebsiteUrl.trimmed().isEmpty()
|
||||
? QStringLiteral("打开网址,当前还没有配置链接。")
|
||||
: QStringLiteral("打开网址:%1").arg(Feature.WebsiteUrl.trimmed());
|
||||
|
||||
default:
|
||||
return QStringLiteral("未知功能。");
|
||||
}
|
||||
}
|
||||
|
||||
QString App_UIWindow::App_Func_GetFeatureDescriptionForUsage(quint16 Usage) const
|
||||
{
|
||||
const int FeatureId = Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage);
|
||||
return FeatureId > 0 ? App_Func_GetFeatureDescriptionById(FeatureId) : App_Func_GetDefaultKeyDescription(Usage);
|
||||
}
|
||||
|
||||
QString App_UIWindow::App_Func_GetDefaultKeyDescription(quint16 Usage) const
|
||||
{
|
||||
return QStringLiteral("默认小键盘按键:%1。左键模拟真实按下,右键可以绑定功能。")
|
||||
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
}
|
||||
|
||||
QString App_UIWindow::App_Func_GetFeatureBindingSummary(int FeatureId) const
|
||||
{
|
||||
if (FeatureId <= 0)
|
||||
{
|
||||
return QStringLiteral("当前未绑定任何按键。");
|
||||
}
|
||||
|
||||
QStringList KeyList;
|
||||
for (quint16 Usage : Lgc_FunctionButton_GetConfigurableUsages())
|
||||
{
|
||||
if (Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage) == FeatureId)
|
||||
{
|
||||
KeyList.append(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
}
|
||||
}
|
||||
|
||||
return KeyList.isEmpty()
|
||||
? QStringLiteral("当前未绑定任何按键。")
|
||||
: QStringLiteral("当前绑定按键:%1").arg(KeyList.join(QStringLiteral(", ")));
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_OnPollTimer()
|
||||
{
|
||||
if (Lgc_Core_Poll(&appLgcState))
|
||||
{
|
||||
App_Func_RefreshAfterLogicChange();
|
||||
}
|
||||
}
|
||||
|
||||
#if APP_ENABLE_DEBUG_WINDOW
|
||||
void App_UIWindow::App_Func_RefreshDeviceConfigFromState()
|
||||
{
|
||||
appDebugPanel->Debug_Func_SetDeviceConfigText(
|
||||
appLgcState.DeviceConfig.VendorId,
|
||||
appLgcState.DeviceConfig.ProductId);
|
||||
appDebugPanel->Debug_Func_SetConfigStatusText(
|
||||
App_Func_GetDebugConfigStatusText(appLgcState),
|
||||
App_Func_HasDebugSendRoute(appLgcState));
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_OnApplyDeviceConfigClicked()
|
||||
{
|
||||
quint16 VendorId = 0;
|
||||
quint16 ProductId = 0;
|
||||
if (!appDebugPanel->Debug_Func_TryGetDeviceConfig(&VendorId, &ProductId))
|
||||
{
|
||||
appDebugPanel->Debug_Func_SetConfigStatusText(
|
||||
QStringLiteral("VID / PID 输入无效。请使用十六进制。"),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
|
||||
appLgcState.DeviceConfig.VendorId = VendorId;
|
||||
appLgcState.DeviceConfig.ProductId = ProductId;
|
||||
App_Func_OnRefreshDeviceClicked();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_OnRefreshDeviceClicked()
|
||||
{
|
||||
Lgc_Core_RefreshDevice(&appLgcState);
|
||||
App_Func_RefreshDeviceConfigFromState();
|
||||
App_Func_RefreshAfterLogicChange();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_OnClearLogClicked()
|
||||
{
|
||||
Lgc_Core_ClearLog(&appLgcState);
|
||||
App_Func_RefreshDebugView();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_OnSyncTimeClicked()
|
||||
{
|
||||
Lgc_Core_SendTimeSync(&appLgcState);
|
||||
App_Func_RefreshAfterLogicChange();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_OnModeSwitchClicked()
|
||||
{
|
||||
Lgc_Core_SendThemeSwitch(&appLgcState);
|
||||
App_Func_RefreshAfterLogicChange();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace APP
|
||||
12
APP/APP_UIWindow_Private.h
Normal file
12
APP/APP_UIWindow_Private.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "LOGIC/Lgc_Func_Button.h"
|
||||
#include <QtCore/QString>
|
||||
|
||||
namespace APP {
|
||||
|
||||
int App_Func_GetFeatureStackIndex(Lgc_FunctionFeature_Type Type);
|
||||
bool App_Func_IsKeyRecordFeatureType(Lgc_FunctionFeature_Type Type);
|
||||
QString App_Func_GetWebsiteEditText(const QString& UrlText);
|
||||
|
||||
} // namespace APP
|
||||
558
APP/APP_UIWindow_Record.cpp
Normal file
558
APP/APP_UIWindow_Record.cpp
Normal file
@@ -0,0 +1,558 @@
|
||||
#include "APP/APP_UIWindow.h"
|
||||
|
||||
#include "APP/APP_UIWindow_Private.h"
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QSignalBlocker>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace APP {
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool App_Func_IsModifierRecordToken(const QString& Token)
|
||||
{
|
||||
return (Token == QStringLiteral("Ctrl")) ||
|
||||
(Token == QStringLiteral("Shift")) ||
|
||||
(Token == QStringLiteral("Alt")) ||
|
||||
(Token == QStringLiteral("Win"));
|
||||
}
|
||||
|
||||
QStringList App_Func_GetOrderedRecordedModifierTokens(const QSet<QString>& PressedKeySet)
|
||||
{
|
||||
const QStringList ModifierOrder = {
|
||||
QStringLiteral("Ctrl"),
|
||||
QStringLiteral("Shift"),
|
||||
QStringLiteral("Alt"),
|
||||
QStringLiteral("Win")
|
||||
};
|
||||
|
||||
QStringList Result;
|
||||
for (const QString& ModifierToken : ModifierOrder)
|
||||
{
|
||||
if (PressedKeySet.contains(ModifierToken))
|
||||
{
|
||||
Result.append(ModifierToken);
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
QString App_Func_GetRecordedCombinationText(
|
||||
const QSet<QString>& PressedKeySet,
|
||||
const QString& TriggerToken)
|
||||
{
|
||||
QStringList TokenList = App_Func_GetOrderedRecordedModifierTokens(PressedKeySet);
|
||||
if (!TriggerToken.isEmpty() && !App_Func_IsModifierRecordToken(TriggerToken))
|
||||
{
|
||||
TokenList.append(TriggerToken);
|
||||
}
|
||||
return TokenList.join(QStringLiteral("+"));
|
||||
}
|
||||
|
||||
bool App_Func_TryGetRawKeyboard(void* p_Message, RAWKEYBOARD* p_Keyboard)
|
||||
{
|
||||
if ((p_Message == nullptr) || (p_Keyboard == nullptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MSG* p_Msg = reinterpret_cast<MSG*>(p_Message);
|
||||
if (p_Msg->message != WM_INPUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT NeedSize = 0;
|
||||
GetRawInputData(
|
||||
reinterpret_cast<HRAWINPUT>(p_Msg->lParam),
|
||||
RID_INPUT,
|
||||
nullptr,
|
||||
&NeedSize,
|
||||
sizeof(RAWINPUTHEADER));
|
||||
if (NeedSize == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray Buffer(static_cast<int>(NeedSize), 0);
|
||||
if (GetRawInputData(
|
||||
reinterpret_cast<HRAWINPUT>(p_Msg->lParam),
|
||||
RID_INPUT,
|
||||
Buffer.data(),
|
||||
&NeedSize,
|
||||
sizeof(RAWINPUTHEADER)) == static_cast<UINT>(-1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const RAWINPUT* p_Input = reinterpret_cast<const RAWINPUT*>(Buffer.constData());
|
||||
if (p_Input->header.dwType != RIM_TYPEKEYBOARD)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*p_Keyboard = p_Input->data.keyboard;
|
||||
return true;
|
||||
}
|
||||
|
||||
QString App_Func_GetRecordedKeyToken(const RAWKEYBOARD& Keyboard)
|
||||
{
|
||||
const bool IsE0 = (Keyboard.Flags & RI_KEY_E0) != 0;
|
||||
const USHORT VirtualKey = Keyboard.VKey;
|
||||
|
||||
if ((VirtualKey >= 'A') && (VirtualKey <= 'Z'))
|
||||
{
|
||||
return QString(QChar(static_cast<char16_t>(VirtualKey)));
|
||||
}
|
||||
if ((VirtualKey >= '0') && (VirtualKey <= '9'))
|
||||
{
|
||||
return QString(QChar(static_cast<char16_t>(VirtualKey)));
|
||||
}
|
||||
if ((VirtualKey >= VK_F1) && (VirtualKey <= VK_F24))
|
||||
{
|
||||
return QStringLiteral("F%1").arg(VirtualKey - VK_F1 + 1);
|
||||
}
|
||||
|
||||
switch (VirtualKey)
|
||||
{
|
||||
case VK_CONTROL:
|
||||
case VK_LCONTROL:
|
||||
case VK_RCONTROL:
|
||||
return QStringLiteral("Ctrl");
|
||||
|
||||
case VK_SHIFT:
|
||||
case VK_LSHIFT:
|
||||
case VK_RSHIFT:
|
||||
return QStringLiteral("Shift");
|
||||
|
||||
case VK_MENU:
|
||||
case VK_LMENU:
|
||||
case VK_RMENU:
|
||||
return QStringLiteral("Alt");
|
||||
|
||||
case VK_LWIN:
|
||||
case VK_RWIN:
|
||||
return QStringLiteral("Win");
|
||||
|
||||
case VK_RETURN:
|
||||
return IsE0 ? QStringLiteral("NumEnter") : QStringLiteral("Enter");
|
||||
|
||||
case VK_SPACE:
|
||||
return QStringLiteral("Space");
|
||||
|
||||
case VK_TAB:
|
||||
return QStringLiteral("Tab");
|
||||
|
||||
case VK_ESCAPE:
|
||||
return QStringLiteral("Esc");
|
||||
|
||||
case VK_BACK:
|
||||
return QStringLiteral("Backspace");
|
||||
|
||||
case VK_DELETE:
|
||||
return QStringLiteral("Delete");
|
||||
|
||||
case VK_INSERT:
|
||||
return QStringLiteral("Insert");
|
||||
|
||||
case VK_HOME:
|
||||
return QStringLiteral("Home");
|
||||
|
||||
case VK_END:
|
||||
return QStringLiteral("End");
|
||||
|
||||
case VK_PRIOR:
|
||||
return QStringLiteral("PageUp");
|
||||
|
||||
case VK_NEXT:
|
||||
return QStringLiteral("PageDown");
|
||||
|
||||
case VK_LEFT:
|
||||
return QStringLiteral("Left");
|
||||
|
||||
case VK_RIGHT:
|
||||
return QStringLiteral("Right");
|
||||
|
||||
case VK_UP:
|
||||
return QStringLiteral("Up");
|
||||
|
||||
case VK_DOWN:
|
||||
return QStringLiteral("Down");
|
||||
|
||||
case VK_CAPITAL:
|
||||
return QStringLiteral("CapsLock");
|
||||
|
||||
case VK_SNAPSHOT:
|
||||
return QStringLiteral("PrintScreen");
|
||||
|
||||
case VK_SCROLL:
|
||||
return QStringLiteral("ScrollLock");
|
||||
|
||||
case VK_PAUSE:
|
||||
return QStringLiteral("Pause");
|
||||
|
||||
case VK_NUMPAD0:
|
||||
return QStringLiteral("Num0");
|
||||
|
||||
case VK_NUMPAD1:
|
||||
return QStringLiteral("Num1");
|
||||
|
||||
case VK_NUMPAD2:
|
||||
return QStringLiteral("Num2");
|
||||
|
||||
case VK_NUMPAD3:
|
||||
return QStringLiteral("Num3");
|
||||
|
||||
case VK_NUMPAD4:
|
||||
return QStringLiteral("Num4");
|
||||
|
||||
case VK_NUMPAD5:
|
||||
return QStringLiteral("Num5");
|
||||
|
||||
case VK_NUMPAD6:
|
||||
return QStringLiteral("Num6");
|
||||
|
||||
case VK_NUMPAD7:
|
||||
return QStringLiteral("Num7");
|
||||
|
||||
case VK_NUMPAD8:
|
||||
return QStringLiteral("Num8");
|
||||
|
||||
case VK_NUMPAD9:
|
||||
return QStringLiteral("Num9");
|
||||
|
||||
case VK_DIVIDE:
|
||||
return QStringLiteral("Num/");
|
||||
|
||||
case VK_MULTIPLY:
|
||||
return QStringLiteral("Num*");
|
||||
|
||||
case VK_SUBTRACT:
|
||||
return QStringLiteral("Num-");
|
||||
|
||||
case VK_ADD:
|
||||
return QStringLiteral("Num+");
|
||||
|
||||
case VK_DECIMAL:
|
||||
return QStringLiteral("Num.");
|
||||
|
||||
case VK_OEM_COMMA:
|
||||
return QStringLiteral("Comma");
|
||||
|
||||
case VK_OEM_PERIOD:
|
||||
return QStringLiteral("Period");
|
||||
|
||||
case VK_OEM_1:
|
||||
return QStringLiteral("Semicolon");
|
||||
|
||||
case VK_OEM_2:
|
||||
return QStringLiteral("Slash");
|
||||
|
||||
case VK_OEM_3:
|
||||
return QStringLiteral("Grave");
|
||||
|
||||
case VK_OEM_4:
|
||||
return QStringLiteral("LeftBracket");
|
||||
|
||||
case VK_OEM_5:
|
||||
return QStringLiteral("Backslash");
|
||||
|
||||
case VK_OEM_6:
|
||||
return QStringLiteral("RightBracket");
|
||||
|
||||
case VK_OEM_7:
|
||||
return QStringLiteral("Quote");
|
||||
|
||||
case VK_OEM_MINUS:
|
||||
return QStringLiteral("Minus");
|
||||
|
||||
case VK_OEM_PLUS:
|
||||
return QStringLiteral("Equal");
|
||||
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void App_UIWindow::App_Func_StartSequenceRecording()
|
||||
{
|
||||
const Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
|
||||
if (Feature.Id <= 0 || !App_Func_IsKeyRecordFeatureType(Feature.Type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
appIsSequenceRecording = true;
|
||||
appSequenceRecordingPressedKeySet.clear();
|
||||
appLgcState.IsFunctionSequenceRecording = true;
|
||||
{
|
||||
QSignalBlocker Blocker(appFeatureSequenceEdit);
|
||||
appFeatureSequenceEdit->setText(QString());
|
||||
}
|
||||
App_Func_SaveFeatureFromUi();
|
||||
appLgcState.TextFunctionStatus =
|
||||
Feature.Type == Lgc_FunctionFeature_Type::KeySequence
|
||||
? QStringLiteral("已开始录入快捷键序列,接下来按下任意键盘按键即可按组追加。")
|
||||
: QStringLiteral("已开始录入快捷键,请按下目标组合键。");
|
||||
App_Func_UpdateSequenceRecordingUi();
|
||||
if (appFeatureSequenceEdit != nullptr)
|
||||
{
|
||||
appFeatureSequenceEdit->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_StopSequenceRecording()
|
||||
{
|
||||
appIsSequenceRecording = false;
|
||||
appSequenceRecordingPressedKeySet.clear();
|
||||
appLgcState.IsFunctionSequenceRecording = false;
|
||||
appLgcState.TextFunctionStatus = QStringLiteral("已退出录入,当前功能键配置已保存。");
|
||||
App_Func_UpdateSequenceRecordingUi();
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_UpdateSequenceRecordingUi()
|
||||
{
|
||||
const Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
|
||||
const bool HasFeature = Feature.Id > 0;
|
||||
const bool CanRecord =
|
||||
HasFeature && App_Func_IsKeyRecordFeatureType(Feature.Type);
|
||||
const bool IsLocked = appIsSequenceRecording;
|
||||
|
||||
if (appFeatureTable != nullptr)
|
||||
{
|
||||
appFeatureTable->setEnabled(!IsLocked);
|
||||
}
|
||||
if (appFeatureAddButton != nullptr)
|
||||
{
|
||||
appFeatureAddButton->setEnabled(!IsLocked);
|
||||
}
|
||||
if (appFeatureDeleteButton != nullptr)
|
||||
{
|
||||
appFeatureDeleteButton->setEnabled(HasFeature && !IsLocked);
|
||||
}
|
||||
if (appFeatureNameEdit != nullptr)
|
||||
{
|
||||
appFeatureNameEdit->setEnabled(HasFeature && !IsLocked);
|
||||
}
|
||||
if (appFeatureDescriptionEdit != nullptr)
|
||||
{
|
||||
appFeatureDescriptionEdit->setEnabled(HasFeature && !IsLocked);
|
||||
}
|
||||
if (appFeatureTypeCombo != nullptr)
|
||||
{
|
||||
appFeatureTypeCombo->setEnabled(HasFeature && !IsLocked);
|
||||
}
|
||||
if (appFeatureWebsiteEdit != nullptr)
|
||||
{
|
||||
appFeatureWebsiteEdit->setEnabled(HasFeature && !IsLocked);
|
||||
}
|
||||
if (appFeatureSequenceEdit != nullptr)
|
||||
{
|
||||
appFeatureSequenceEdit->setReadOnly(appIsSequenceRecording);
|
||||
}
|
||||
if (appFeatureSequenceRecordStartButton != nullptr)
|
||||
{
|
||||
appFeatureSequenceRecordStartButton->setEnabled(CanRecord && !appIsSequenceRecording);
|
||||
}
|
||||
if (appFeatureSequenceRecordStopButton != nullptr)
|
||||
{
|
||||
appFeatureSequenceRecordStopButton->setEnabled(CanRecord && appIsSequenceRecording);
|
||||
}
|
||||
}
|
||||
|
||||
bool App_UIWindow::App_Func_HandleSequenceRecordMessage(void* p_Message)
|
||||
{
|
||||
if (!appIsSequenceRecording)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RAWKEYBOARD Keyboard = {};
|
||||
if (!App_Func_TryGetRawKeyboard(p_Message, &Keyboard))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString Token = App_Func_GetRecordedKeyToken(Keyboard);
|
||||
if (Token.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool IsPressed = (Keyboard.Flags & RI_KEY_BREAK) == 0;
|
||||
if (IsPressed)
|
||||
{
|
||||
if (appSequenceRecordingPressedKeySet.contains(Token))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
appSequenceRecordingPressedKeySet.insert(Token);
|
||||
if (!App_Func_IsModifierRecordToken(Token))
|
||||
{
|
||||
App_Func_AppendRecordedSequenceToken(Token);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
appSequenceRecordingPressedKeySet.remove(Token);
|
||||
return false;
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_AppendRecordedSequenceToken(const QString& Token)
|
||||
{
|
||||
if (Token.isEmpty() || appFeatureSequenceEdit == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const Lgc_FunctionFeature_Definition Feature =
|
||||
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
|
||||
if (Feature.Id <= 0 || !App_Func_IsKeyRecordFeatureType(Feature.Type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QString CombinationText =
|
||||
App_Func_GetRecordedCombinationText(appSequenceRecordingPressedKeySet, Token);
|
||||
if (CombinationText.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QString OldText = appFeatureSequenceEdit->text().trimmed();
|
||||
const QString NewText =
|
||||
Feature.Type == Lgc_FunctionFeature_Type::KeySequence
|
||||
? (OldText.isEmpty()
|
||||
? CombinationText
|
||||
: QStringLiteral("%1 -> %2").arg(OldText, CombinationText))
|
||||
: CombinationText;
|
||||
{
|
||||
QSignalBlocker Blocker(appFeatureSequenceEdit);
|
||||
appFeatureSequenceEdit->setText(NewText);
|
||||
appFeatureSequenceEdit->setCursorPosition(NewText.size());
|
||||
}
|
||||
|
||||
App_Func_SaveFeatureFromUi();
|
||||
appLgcState.TextFunctionStatus = QStringLiteral("录入中:%1").arg(NewText);
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_HandleUiKeyPressed(quint16 Usage)
|
||||
{
|
||||
QString TextStatus;
|
||||
if (Lgc_FunctionButton_HasUsageFeature(appLgcState.FunctionButtonConfig, Usage))
|
||||
{
|
||||
if (!Lgc_FunctionButton_RunBinding(&appLgcState, Usage, &TextStatus))
|
||||
{
|
||||
TextStatus = QStringLiteral("%1 当前没有可执行功能。")
|
||||
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Lgc_FunctionButton_SendUsageToWindows(Usage, true))
|
||||
{
|
||||
appUiPressedUsageSet.insert(Usage);
|
||||
TextStatus = QStringLiteral("已模拟按下 %1。")
|
||||
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
}
|
||||
else
|
||||
{
|
||||
TextStatus = QStringLiteral("模拟按下 %1 失败。")
|
||||
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
}
|
||||
}
|
||||
|
||||
if (!TextStatus.isEmpty())
|
||||
{
|
||||
appLgcState.TextFunctionStatus = TextStatus;
|
||||
}
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_HandleUiKeyReleased(quint16 Usage)
|
||||
{
|
||||
if (!appUiPressedUsageSet.remove(Usage))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
appLgcState.TextFunctionStatus =
|
||||
Lgc_FunctionButton_SendUsageToWindows(Usage, false)
|
||||
? QStringLiteral("已模拟抬起 %1。").arg(Lgc_FunctionButton_GetUsageShortText(Usage))
|
||||
: QStringLiteral("模拟抬起 %1 失败。").arg(Lgc_FunctionButton_GetUsageShortText(Usage));
|
||||
App_Func_RefreshUi();
|
||||
}
|
||||
|
||||
void App_UIWindow::App_Func_ShowKeyMenu(quint16 Usage, const QPoint& GlobalPos)
|
||||
{
|
||||
const int CurrentFeatureId =
|
||||
Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage);
|
||||
|
||||
QMenu Menu(this);
|
||||
|
||||
QAction* p_NoneAction = Menu.addAction(QStringLiteral("无功能"));
|
||||
p_NoneAction->setCheckable(true);
|
||||
p_NoneAction->setChecked(CurrentFeatureId <= 0);
|
||||
p_NoneAction->setData(0);
|
||||
|
||||
const QVector<int> FeatureIdList =
|
||||
Lgc_FunctionButton_GetFeatureIdList(appLgcState.FunctionButtonConfig);
|
||||
if (!FeatureIdList.isEmpty())
|
||||
{
|
||||
Menu.addSeparator();
|
||||
for (int FeatureId : FeatureIdList)
|
||||
{
|
||||
QAction* p_Action = Menu.addAction(QStringLiteral("绑定到 %1").arg(App_Func_GetFeatureNameById(FeatureId)));
|
||||
p_Action->setCheckable(true);
|
||||
p_Action->setChecked(FeatureId == CurrentFeatureId);
|
||||
p_Action->setData(FeatureId);
|
||||
p_Action->setToolTip(App_Func_GetFeatureDescriptionById(FeatureId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.addSeparator();
|
||||
QAction* p_EmptyAction = Menu.addAction(QStringLiteral("暂无功能,请先到功能表添加"));
|
||||
p_EmptyAction->setEnabled(false);
|
||||
}
|
||||
|
||||
Menu.addSeparator();
|
||||
QAction* p_OpenFeaturePageAction = Menu.addAction(QStringLiteral("打开功能表"));
|
||||
p_OpenFeaturePageAction->setData(-1);
|
||||
|
||||
QAction* p_SelectedAction = Menu.exec(GlobalPos);
|
||||
if (p_SelectedAction == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int ActionData = p_SelectedAction->data().toInt();
|
||||
if (ActionData == -1)
|
||||
{
|
||||
App_Func_SelectFeature(CurrentFeatureId, true);
|
||||
return;
|
||||
}
|
||||
|
||||
App_Func_AssignFeatureToUsage(Usage, ActionData);
|
||||
if (ActionData > 0)
|
||||
{
|
||||
App_Func_SelectFeature(ActionData);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace APP
|
||||
Reference in New Issue
Block a user