#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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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(&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(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(Lgc_FunctionFeature_Type::KeyCombination)); appFeatureTypeCombo->addItem( Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::KeySequence), static_cast(Lgc_FunctionFeature_Type::KeySequence)); appFeatureTypeCombo->addItem( Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::Website), static_cast(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