Files
Qt_keyboard/APP/APP_UIWindow_Feature.cpp
2026-04-03 09:26:10 +08:00

520 lines
17 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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