292 lines
9.6 KiB
C++
292 lines
9.6 KiB
C++
|
|
#include "APP/APP_UIWindow.h"
|
||
|
|
|
||
|
|
#include "APP/APP_KeyButton.h"
|
||
|
|
#include "APP/APP_UIWindow_Private.h"
|
||
|
|
#include <QtCore/QSignalBlocker>
|
||
|
|
#include <QtWidgets/QComboBox>
|
||
|
|
#include <QtWidgets/QLabel>
|
||
|
|
#include <QtWidgets/QLineEdit>
|
||
|
|
#include <QtWidgets/QPushButton>
|
||
|
|
#include <QtWidgets/QStackedWidget>
|
||
|
|
#include <QtWidgets/QTableWidget>
|
||
|
|
#include <QtWidgets/QTableWidgetItem>
|
||
|
|
|
||
|
|
namespace APP {
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
|
||
|
|
QString App_Func_GetDefaultKeyDescription(quint16 Usage)
|
||
|
|
{
|
||
|
|
return QStringLiteral(
|
||
|
|
"Default numpad key: %1. Left click simulates a real press/release. "
|
||
|
|
"Right click binds a function.")
|
||
|
|
.arg(Lgc_Core_GetUsageShortText(Usage));
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_RefreshKeypadState()
|
||
|
|
{
|
||
|
|
const Lgc_Core_Struct_View View = Lgc_Core_GetView(&appLgcState);
|
||
|
|
appKeypadModel.App_Func_SetNumLockOn(View.IsSystemNumLockOn);
|
||
|
|
|
||
|
|
if (View.IsPhysicalKeyStateValid)
|
||
|
|
{
|
||
|
|
appKeypadModel.App_Func_SetPressedKeysFromUsageList(View.PhysicalUsageList);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (View.IsVisibleKeyStateValid)
|
||
|
|
{
|
||
|
|
appKeypadModel.App_Func_SetPressedKeysFromUsageList(View.VisibleUsageList);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
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 int FeatureId = Lgc_Core_GetUsageFeatureId(&appLgcState, Usage);
|
||
|
|
APP_KeyButton* p_Button = It.value();
|
||
|
|
|
||
|
|
p_Button->App_Func_SetLatched(
|
||
|
|
appKeypadModel.App_Func_IsLatched(KeyId) || (FeatureId > 0));
|
||
|
|
p_Button->App_Func_SetPressed(appKeypadModel.App_Func_IsPressed(KeyId));
|
||
|
|
p_Button->App_Func_SetHintText(
|
||
|
|
FeatureId > 0
|
||
|
|
? Lgc_Core_GetFeatureNameById(&appLgcState, FeatureId)
|
||
|
|
: appKeypadModel.App_Func_GetDefaultHint(KeyId));
|
||
|
|
p_Button->setToolTip(
|
||
|
|
FeatureId > 0
|
||
|
|
? Lgc_Core_GetFeatureDescriptionById(&appLgcState, FeatureId)
|
||
|
|
: App_Func_GetDefaultKeyDescription(Usage));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_RefreshFeatureTable()
|
||
|
|
{
|
||
|
|
const QVector<int> FeatureIdList = Lgc_Core_GetFeatureIdList(&appLgcState);
|
||
|
|
const bool HasFeatures = !FeatureIdList.isEmpty();
|
||
|
|
|
||
|
|
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_Core_GetFeature(&appLgcState, FeatureId);
|
||
|
|
QTableWidgetItem* p_NameItem =
|
||
|
|
new QTableWidgetItem(Lgc_Core_GetFeatureNameById(&appLgcState, FeatureId));
|
||
|
|
p_NameItem->setData(Qt::UserRole, FeatureId);
|
||
|
|
appFeatureTable->setItem(Row, 0, p_NameItem);
|
||
|
|
appFeatureTable->setItem(
|
||
|
|
Row,
|
||
|
|
1,
|
||
|
|
new QTableWidgetItem(Lgc_Core_GetFeatureDescriptionById(&appLgcState, FeatureId)));
|
||
|
|
appFeatureTable->setItem(
|
||
|
|
Row,
|
||
|
|
2,
|
||
|
|
new QTableWidgetItem(Lgc_Core_GetFeatureTypeText(Feature.Type)));
|
||
|
|
if (FeatureId == appSelectedFeatureId)
|
||
|
|
{
|
||
|
|
TargetRow = Row;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
appSelectedFeatureId =
|
||
|
|
TargetRow >= 0 ? appSelectedFeatureId : (HasFeatures ? FeatureIdList.first() : 0);
|
||
|
|
TargetRow = TargetRow >= 0 ? TargetRow : (HasFeatures ? 0 : -1);
|
||
|
|
if (TargetRow >= 0)
|
||
|
|
{
|
||
|
|
appFeatureTable->selectRow(TargetRow);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
appFeatureTable->clearSelection();
|
||
|
|
}
|
||
|
|
|
||
|
|
App_Func_UpdateFeatureEditorState();
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_RefreshFunctionStatus()
|
||
|
|
{
|
||
|
|
const Lgc_Core_Struct_View View = Lgc_Core_GetView(&appLgcState);
|
||
|
|
appFunctionLabelStatus->setText(
|
||
|
|
View.TextFunctionStatus.isEmpty()
|
||
|
|
? QStringLiteral("Waiting for function-key activity.")
|
||
|
|
: View.TextFunctionStatus);
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_SelectFeature(int FeatureId, bool SwitchToFeaturePage)
|
||
|
|
{
|
||
|
|
if (appIsSequenceRecording && (FeatureId != appSelectedFeatureId))
|
||
|
|
{
|
||
|
|
App_Func_StopSequenceRecording();
|
||
|
|
}
|
||
|
|
|
||
|
|
appSelectedFeatureId =
|
||
|
|
Lgc_Core_GetFeature(&appLgcState, FeatureId).Id > 0 ? FeatureId : 0;
|
||
|
|
if (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->setCurrentIndex(appFeaturePageIndex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_SaveFeatureFromUi()
|
||
|
|
{
|
||
|
|
if (appSelectedFeatureId <= 0)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
Lgc_FunctionFeature_Definition Feature =
|
||
|
|
Lgc_Core_GetFeature(&appLgcState, 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_Core_UpdateFeature(&appLgcState, Feature);
|
||
|
|
|
||
|
|
appFeatureEditorStack->setCurrentIndex(App_Func_GetFeatureStackIndex(Feature.Type));
|
||
|
|
App_Func_UpdateFeatureEditorHeight();
|
||
|
|
Lgc_Core_SaveFunctionConfig(&appLgcState);
|
||
|
|
App_Func_RefreshAfterLogicChange(); // FIX: keep Device Test and status text aligned after feature edits.
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_UpdateFeatureEditorHeight()
|
||
|
|
{
|
||
|
|
if ((appFeatureEditorStack == nullptr) || (appFeatureEditorStack->currentWidget() == nullptr))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const int Height = appFeatureEditorStack->currentWidget()->sizeHint().height();
|
||
|
|
if (appFeatureEditorStack->height() != Height)
|
||
|
|
{
|
||
|
|
appFeatureEditorStack->setFixedHeight(Height);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_UpdateFeatureEditorState()
|
||
|
|
{
|
||
|
|
const Lgc_FunctionFeature_Definition Feature =
|
||
|
|
Lgc_Core_GetFeature(&appLgcState, 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);
|
||
|
|
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("No function selected yet."));
|
||
|
|
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("Example: Ctrl+C -> Ctrl+A")
|
||
|
|
: QStringLiteral("Example: Ctrl+C"));
|
||
|
|
App_Func_UpdateFeatureEditorHeight();
|
||
|
|
appFeatureBindingSummaryLabel->setText(
|
||
|
|
Lgc_Core_GetFeatureBindingSummary(&appLgcState, Feature.Id));
|
||
|
|
appIsUpdatingFeatureUi = false;
|
||
|
|
App_Func_UpdateSequenceRecordingUi();
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_AddFeature()
|
||
|
|
{
|
||
|
|
const int FeatureId = Lgc_Core_AddFeature(&appLgcState);
|
||
|
|
Lgc_Core_SaveFunctionConfig(&appLgcState);
|
||
|
|
App_Func_RefreshFeatureTable(); // FIX: the feature table must update before reselection.
|
||
|
|
App_Func_RefreshAfterLogicChange(); // FIX: refresh Device Test and current config state after add.
|
||
|
|
App_Func_SelectFeature(FeatureId, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
void App_UIWindow::App_Func_DeleteFeature()
|
||
|
|
{
|
||
|
|
if (appSelectedFeatureId <= 0)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (appIsSequenceRecording)
|
||
|
|
{
|
||
|
|
App_Func_StopSequenceRecording();
|
||
|
|
}
|
||
|
|
|
||
|
|
Lgc_Core_DeleteFeature(&appLgcState, appSelectedFeatureId);
|
||
|
|
appSelectedFeatureId = 0;
|
||
|
|
Lgc_Core_SaveFunctionConfig(&appLgcState);
|
||
|
|
App_Func_RefreshFeatureTable(); // FIX: rebuild the feature table after delete.
|
||
|
|
App_Func_RefreshAfterLogicChange(); // FIX: refresh Device Test and current config state after delete.
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace APP
|