[Companion] Adjust source value ranges and editors in LS/CF/Telemetry (#5437)
* [Companion] RawSourceRange: Fix for timers and RTC; Remove unused "single precision" flag and logic; Add logic for "short" timer handling. * [Companion] Add TimerEdit class for editing negative times; Implement TimerEdit in LS, CF, and Telemetry (bars) editors; * [Companion] Refactor LogicalSwitchesPanel for fewer & more efficient updates; Fix newly-added LS not being available in source lists; Fix bug with timer/rtc comparison values getting reset to value of spin box instead of time editor. * Add forgotten #include. * [Companion] LogicalSwitchesPanel: Update raw sources list upon screen refresh (fixes #5374); Improve data entry in spin boxes (fixes #5375). * Make gcc happy. * [Companion] Set proper RawSourceRange for GVars, trims, mixer scripts, and sticks/switches/cyclic/MAX. * [Companion] Fix backwards precision/range logic on telemetry sensors offset spinbox; Fix other minor range issues with ratio & offset. * [Companion] Remove short limit on min/max timer values for LS & telem. bars. * Switch to TimerEdit in maxLibQt. * Fix gcc build. * Remove unused files. * Caps fix.
This commit is contained in:
committed by
Bertrand Songis
parent
b69f36afe4
commit
76ce186bd4
@@ -191,12 +191,9 @@ set(common_RESOURCES
|
||||
|
||||
qt5_wrap_cpp(common_SRCS ${common_MOC_HDRS})
|
||||
qt5_add_resources(common_RCC ${common_RESOURCES})
|
||||
#add_custom_target(gen_qrc DEPENDS ${common_RCC} ${companion_QM})
|
||||
|
||||
add_library(common ${common_SRCS} ${common_RCC})
|
||||
qt5_use_modules(common Core Xml Widgets)
|
||||
target_link_libraries(common PRIVATE simulation)
|
||||
#add_dependencies(common gen_qrc)
|
||||
target_link_libraries(common simulation maxLibQtWidgets Qt5::Core Qt5::Xml Qt5::Widgets)
|
||||
|
||||
set(CPN_COMMON_LIB common)
|
||||
|
||||
@@ -307,7 +304,7 @@ qt5_wrap_cpp(companion_SRCS ${companion_MOC_HDRS})
|
||||
|
||||
add_executable(${COMPANION_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${companion_SRCS} ${icon_RC})
|
||||
qt5_use_modules(${COMPANION_NAME} Core Widgets Network)
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit simulation ${CPN_COMMON_LIB} maxLibQtWidgets qcustomplot shared storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
target_link_libraries(${COMPANION_NAME} PRIVATE generaledit modeledit ${CPN_COMMON_LIB} qcustomplot shared storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
|
||||
PrintTargetReport("${COMPANION_NAME}")
|
||||
|
||||
@@ -316,7 +313,7 @@ PrintTargetReport("${COMPANION_NAME}")
|
||||
set(simu_SRCS simulator.cpp )
|
||||
|
||||
add_executable(${SIMULATOR_NAME} MACOSX_BUNDLE ${WIN_EXECUTABLE_TYPE} ${simu_SRCS} ${icon_RC})
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE simulation ${CPN_COMMON_LIB} storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
target_link_libraries(${SIMULATOR_NAME} PRIVATE ${CPN_COMMON_LIB} storage ${PTHREAD_LIBRARY} ${SDL_LIBRARY} ${WIN_LINK_LIBRARIES})
|
||||
|
||||
############# Install ####################
|
||||
|
||||
|
||||
@@ -244,11 +244,6 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
|
||||
Firmware * firmware = Firmware::getCurrentVariant();
|
||||
int board = firmware->getBoard();
|
||||
bool singleprec = (flags & RANGE_SINGLE_PRECISION);
|
||||
|
||||
if (!singleprec && !IS_ARM(board)) {
|
||||
singleprec = true;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SOURCE_TYPE_TELEMETRY:
|
||||
@@ -267,9 +262,7 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
result.unit = sensor.unitString();
|
||||
}
|
||||
else {
|
||||
if (singleprec) {
|
||||
result.offset = -DBL_MAX;
|
||||
}
|
||||
result.offset = -DBL_MAX;
|
||||
|
||||
switch (index) {
|
||||
case TELEMETRY_SOURCE_TX_BATT:
|
||||
@@ -279,20 +272,21 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
result.unit = QObject::tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_TX_TIME:
|
||||
result.step = 1;
|
||||
result.max = 24*60 - 1;
|
||||
result.step = 60;
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = QObject::tr("s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_TIMER1:
|
||||
case TELEMETRY_SOURCE_TIMER2:
|
||||
case TELEMETRY_SOURCE_TIMER3:
|
||||
result.step = singleprec ? 5 : 1;
|
||||
result.max = singleprec ? 255*5 : 60*60;
|
||||
result.step = 5;
|
||||
result.max = 255 * result.step;
|
||||
result.unit = QObject::tr("s");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_RSSI_TX:
|
||||
case TELEMETRY_SOURCE_RSSI_RX:
|
||||
result.max = 100;
|
||||
if (singleprec) result.offset = 128;
|
||||
result.offset = 128;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_A1_MIN:
|
||||
case TELEMETRY_SOURCE_A2_MIN:
|
||||
@@ -310,9 +304,9 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
case TELEMETRY_SOURCE_ALT_MIN:
|
||||
case TELEMETRY_SOURCE_ALT_MAX:
|
||||
case TELEMETRY_SOURCE_GPS_ALT:
|
||||
result.step = singleprec ? 8 : 1;
|
||||
result.step = 8;
|
||||
result.min = -500;
|
||||
result.max = singleprec ? 1540 : 3000;
|
||||
result.max = 1540;
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step = (result.step * 105) / 32;
|
||||
result.min = (result.min * 105) / 32;
|
||||
@@ -332,15 +326,15 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
result.unit = QObject::trUtf8("°C");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_HDG:
|
||||
result.step = singleprec ? 2 : 1;
|
||||
result.step = 2;
|
||||
result.max = 360;
|
||||
if (singleprec) result.offset = 256;
|
||||
result.offset = 256;
|
||||
result.unit = QObject::trUtf8("°");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_RPM:
|
||||
case TELEMETRY_SOURCE_RPM_MAX:
|
||||
result.step = singleprec ? 50 : 1;
|
||||
result.max = singleprec ? 12750 : 30000;
|
||||
result.step = 50;
|
||||
result.max = 12750;
|
||||
break;
|
||||
case TELEMETRY_SOURCE_FUEL:
|
||||
result.max = 100;
|
||||
@@ -349,8 +343,8 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
case TELEMETRY_SOURCE_ASPEED:
|
||||
case TELEMETRY_SOURCE_ASPEED_MAX:
|
||||
result.decimals = 1;
|
||||
result.step = singleprec ? 2.0 : 0.1;
|
||||
result.max = singleprec ? (2*255) : 2000;
|
||||
result.step = 2.0;
|
||||
result.max = (2*255);
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step *= 1.150779;
|
||||
result.max *= 1.150779;
|
||||
@@ -364,8 +358,8 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
break;
|
||||
case TELEMETRY_SOURCE_SPEED:
|
||||
case TELEMETRY_SOURCE_SPEED_MAX:
|
||||
result.step = singleprec ? 2 : 1;
|
||||
result.max = singleprec ? (2*255) : 2000;
|
||||
result.step = 2;
|
||||
result.max = (2*255);
|
||||
if (firmware->getCapability(Imperial) || settings.imperial) {
|
||||
result.step *= 1.150779;
|
||||
result.max *= 1.150779;
|
||||
@@ -379,8 +373,8 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
break;
|
||||
case TELEMETRY_SOURCE_VERTICAL_SPEED:
|
||||
result.step = 0.1;
|
||||
result.min = singleprec ? -12.5 : -300.0;
|
||||
result.max = singleprec ? 13.0 : 300.0;
|
||||
result.min = -12.5;
|
||||
result.max = 13.0;
|
||||
result.decimals = 1;
|
||||
result.unit = QObject::tr("m/s");
|
||||
break;
|
||||
@@ -389,13 +383,13 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
break;
|
||||
case TELEMETRY_SOURCE_DIST:
|
||||
case TELEMETRY_SOURCE_DIST_MAX:
|
||||
result.step = singleprec ? 8 : 1;
|
||||
result.max = singleprec ? 2040 : 10000;
|
||||
result.step = 8;
|
||||
result.max = 2040;
|
||||
result.unit = QObject::tr("m");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CELL:
|
||||
case TELEMETRY_SOURCE_CELL_MIN:
|
||||
result.step = singleprec ? 0.02 : 0.01;
|
||||
result.step = 0.02;
|
||||
result.max = 5.1;
|
||||
result.decimals = 2;
|
||||
result.unit = QObject::tr("V");
|
||||
@@ -405,26 +399,26 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
case TELEMETRY_SOURCE_VFAS:
|
||||
case TELEMETRY_SOURCE_VFAS_MIN:
|
||||
result.step = 0.1;
|
||||
result.max = singleprec ? 25.5 : 100.0;
|
||||
result.max = 25.5;
|
||||
result.decimals = 1;
|
||||
result.unit = QObject::tr("V");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CURRENT:
|
||||
case TELEMETRY_SOURCE_CURRENT_MAX:
|
||||
result.step = singleprec ? 0.5 : 0.1;
|
||||
result.max = singleprec ? 127.5 : 200.0;
|
||||
result.step = 0.5;
|
||||
result.max = 127.5;
|
||||
result.decimals = 1;
|
||||
result.unit = QObject::tr("A");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_CONSUMPTION:
|
||||
result.step = singleprec ? 100 : 1;
|
||||
result.max = singleprec ? 25500 : 30000;
|
||||
result.step = 100;
|
||||
result.max = 25500;
|
||||
result.unit = QObject::tr("mAh");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_POWER:
|
||||
case TELEMETRY_SOURCE_POWER_MAX:
|
||||
result.step = singleprec ? 5 : 1;
|
||||
result.max = singleprec ? 1275 : 2000;
|
||||
result.step = 5;
|
||||
result.max = 1275;
|
||||
result.unit = QObject::tr("W");
|
||||
break;
|
||||
case TELEMETRY_SOURCE_ACCX:
|
||||
@@ -432,8 +426,8 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
case TELEMETRY_SOURCE_ACCZ:
|
||||
result.step = 0.01;
|
||||
result.decimals = 2;
|
||||
result.max = singleprec ? 2.55 : 10.00;
|
||||
result.min = singleprec ? 0 : -10.00;
|
||||
result.max = 2.55;
|
||||
result.min = 0;
|
||||
result.unit = QObject::tr("g");
|
||||
break;
|
||||
default:
|
||||
@@ -441,28 +435,38 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
break;
|
||||
}
|
||||
|
||||
if (singleprec && result.offset==-DBL_MAX) {
|
||||
if (result.offset == -DBL_MAX) {
|
||||
result.offset = result.max - (127*result.step);
|
||||
}
|
||||
|
||||
if (flags & (RANGE_DELTA_FUNCTION|RANGE_DELTA_ABS_FUNCTION)) {
|
||||
if (singleprec) {
|
||||
result.offset = 0;
|
||||
result.min = result.step * -127;
|
||||
result.max = result.step * 127;
|
||||
}
|
||||
else {
|
||||
result.min = -result.max;
|
||||
}
|
||||
if (flags & (RANGE_DELTA_FUNCTION | RANGE_ABS_FUNCTION)) {
|
||||
result.offset = 0;
|
||||
result.min = result.step * -127;
|
||||
result.max = result.step * 127;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_GVAR:
|
||||
result.max = 1024;
|
||||
case SOURCE_TYPE_LUA_OUTPUT:
|
||||
result.max = 30000;
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_TRIM:
|
||||
result.max = (model && model->extendedTrims ? firmware->getCapability(ExtendedTrimsRange) : firmware->getCapability(TrimsRange));
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_GVAR: {
|
||||
GVarData gv = model->gvarData[index];
|
||||
result.step = gv.multiplierGet();
|
||||
result.decimals = gv.prec;
|
||||
result.max = gv.getMaxPrec();
|
||||
result.min = gv.getMinPrec();
|
||||
result.unit = gv.unitToString();
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_TYPE_SPECIAL:
|
||||
if (index == 0) { //Batt
|
||||
result.step = 0.1;
|
||||
@@ -471,26 +475,30 @@ RawSourceRange RawSource::getRange(const ModelData * model, const GeneralSetting
|
||||
result.unit = QObject::tr("V");
|
||||
}
|
||||
else if (index == 1) { //Time
|
||||
result.step = 1;
|
||||
result.max = 24*60 - 1;
|
||||
result.unit = QObject::tr("h:m");
|
||||
result.step = 60;
|
||||
result.max = 24 * 60 * result.step - 60; // 23:59:00 with 1-minute resolution
|
||||
result.unit = QObject::tr("s");
|
||||
}
|
||||
else { // Timers 1 - 3
|
||||
result.step = singleprec ? 5 : 1;
|
||||
result.max = singleprec ? 255*5 : 60*60;
|
||||
result.unit = singleprec ? QObject::tr("m:s") : QObject::tr("h:m:s");
|
||||
result.step = 1;
|
||||
result.max = 9 * 60 * 60 - 1; // 8:59:59 (to match firmware)
|
||||
result.min = -result.max;
|
||||
result.unit = QObject::tr("s");
|
||||
}
|
||||
break;
|
||||
|
||||
case SOURCE_TYPE_CH:
|
||||
result.max = model->getChannelsMax(false);
|
||||
result.min = -result.max;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (model) {
|
||||
result.max = model->getChannelsMax(true);
|
||||
result.min = -result.max;
|
||||
}
|
||||
result.max = 100;
|
||||
result.min = -result.max;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & RANGE_DELTA_ABS_FUNCTION) {
|
||||
if (flags & RANGE_ABS_FUNCTION) {
|
||||
result.min = 0;
|
||||
}
|
||||
|
||||
@@ -936,12 +944,15 @@ CSFunctionFamily LogicalSwitchData::getFunctionFamily() const
|
||||
|
||||
unsigned int LogicalSwitchData::getRangeFlags() const
|
||||
{
|
||||
if (func == LS_FN_DPOS)
|
||||
return RANGE_DELTA_FUNCTION;
|
||||
else if (func == LS_FN_DAPOS)
|
||||
return RANGE_DELTA_ABS_FUNCTION;
|
||||
else
|
||||
return 0;
|
||||
int f = 0;
|
||||
|
||||
if (func == LS_FN_DPOS || func == LS_FN_DAPOS)
|
||||
f |= RANGE_DELTA_FUNCTION;
|
||||
|
||||
if (func == LS_FN_DAPOS || func == LS_FN_APOS || func == LS_FN_ANEG)
|
||||
f |= RANGE_ABS_FUNCTION;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
QString LogicalSwitchData::funcToString() const
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
|
||||
#include <TimerEdit>
|
||||
|
||||
RepeatComboBox::RepeatComboBox(QWidget *parent, int & repeatParam):
|
||||
QComboBox(parent),
|
||||
repeatParam(repeatParam)
|
||||
@@ -178,10 +180,8 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
|
||||
connect(fswtchParam[i], SIGNAL(editingFinished()), this, SLOT(customFunctionEdited()));
|
||||
paramLayout->addWidget(fswtchParam[i]);
|
||||
|
||||
fswtchParamTime[i] = new QTimeEdit(this);
|
||||
fswtchParamTime[i] = new TimerEdit(this);
|
||||
fswtchParamTime[i]->setProperty("index", i);
|
||||
fswtchParamTime[i]->setAccelerated(true);
|
||||
fswtchParamTime[i]->setDisplayFormat("hh:mm:ss");
|
||||
connect(fswtchParamTime[i], SIGNAL(editingFinished()), this, SLOT(customFunctionEdited()));
|
||||
paramLayout->addWidget(fswtchParamTime[i]);
|
||||
|
||||
@@ -450,10 +450,10 @@ void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
|
||||
}
|
||||
else if (func>=FuncSetTimer1 && func<=FuncSetTimer3) {
|
||||
if (modified)
|
||||
cfn.param = QTimeS(fswtchParamTime[i]->time()).seconds();
|
||||
fswtchParamTime[i]->setMinimumTime(QTime(0, 0, 0));
|
||||
fswtchParamTime[i]->setMaximumTime(firmware->getMaxTimerStart());
|
||||
fswtchParamTime[i]->setTime(QTimeS(cfn.param));
|
||||
cfn.param = fswtchParamTime[i]->timeInSeconds();
|
||||
RawSourceRange range = RawSource(SOURCE_TYPE_SPECIAL, func - FuncSetTimer1 + 2).getRange(model, generalSettings);
|
||||
fswtchParamTime[i]->setTimeRange((int)range.min, (int)range.max);
|
||||
fswtchParamTime[i]->setTime(cfn.param);
|
||||
widgetsMask |= CUSTOM_FUNCTION_TIME_PARAM | CUSTOM_FUNCTION_ENABLE;
|
||||
}
|
||||
else if (func>=FuncSetFailsafeInternalModule && func<=FuncBindExternalModule) {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "eeprominterface.h"
|
||||
|
||||
class RawSwitchFilterItemModel;
|
||||
class TimerEdit;
|
||||
|
||||
class RepeatComboBox: public QComboBox
|
||||
{
|
||||
@@ -87,7 +88,7 @@ class CustomFunctionsPanel : public GenericPanel
|
||||
QComboBox * fswtchFunc[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
QCheckBox * fswtchParamGV[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
QDoubleSpinBox * fswtchParam[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
QTimeEdit * fswtchParamTime[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
TimerEdit * fswtchParamTime[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
QPushButton * playBT[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
QComboBox * fswtchParamT[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
QComboBox * fswtchParamArmT[CPN_MAX_SPECIAL_FUNCTIONS];
|
||||
|
||||
@@ -22,17 +22,19 @@
|
||||
#include "switchitemmodel.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <TimerEdit>
|
||||
|
||||
LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
ModelPanel(parent, model, generalSettings, firmware),
|
||||
rawSourceItemModel(NULL),
|
||||
selectedSwitch(0)
|
||||
{
|
||||
Stopwatch s1("LogicalSwitchesPanel");
|
||||
|
||||
int channelsMax = model.getChannelsMax(true);
|
||||
rawSwitchItemModel = new RawSwitchFilterItemModel(&generalSettings, &model, LogicalSwitchesContext);
|
||||
int srcFlags = POPULATE_NONE | POPULATE_SOURCES | POPULATE_SCRIPT_OUTPUTS | POPULATE_VIRTUAL_INPUTS | POPULATE_TRIMS | POPULATE_SWITCHES | POPULATE_TELEMETRY | (firmware->getCapability(GvarsInCS) ? POPULATE_GVARS : 0);
|
||||
rawSourceItemModel = Helpers::getRawSourceItemModel(&generalSettings, &model, srcFlags);
|
||||
rawSourceItemModel->setParent(this);
|
||||
|
||||
setDataModels();
|
||||
|
||||
QStringList headerLabels;
|
||||
headerLabels << "#" << tr("Function") << tr("V1") << tr("V2") << tr("AND Switch");
|
||||
@@ -58,7 +60,8 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
|
||||
// The function
|
||||
csw[i] = new QComboBox(this);
|
||||
csw[i]->setProperty("index", i);
|
||||
connect(csw[i], SIGNAL(currentIndexChanged(int)), this, SLOT(edited()));
|
||||
populateCSWCB(csw[i]);
|
||||
connect(csw[i], SIGNAL(currentIndexChanged(int)), this, SLOT(functionChanged()));
|
||||
tableLayout->addWidget(i, 1, csw[i]);
|
||||
|
||||
// V1
|
||||
@@ -74,7 +77,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
|
||||
cswitchValue[i]->setAccelerated(true);
|
||||
cswitchValue[i]->setDecimals(0);
|
||||
cswitchValue[i]->setProperty("index", i);
|
||||
connect(cswitchValue[i], SIGNAL(valueChanged(double)), this, SLOT(edited()));
|
||||
connect(cswitchValue[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited()));
|
||||
v1Layout->addWidget(cswitchValue[i]);
|
||||
cswitchValue[i]->setVisible(false);
|
||||
tableLayout->addLayout(i, 2, v1Layout);
|
||||
@@ -92,7 +95,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
|
||||
cswitchOffset[i]->setMinimum(-channelsMax);
|
||||
cswitchOffset[i]->setAccelerated(true);
|
||||
cswitchOffset[i]->setDecimals(0);
|
||||
connect(cswitchOffset[i], SIGNAL(valueChanged(double)), this, SLOT(edited()));
|
||||
connect(cswitchOffset[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited()));
|
||||
cswitchOffset[i]->setVisible(false);
|
||||
v2Layout->addWidget(cswitchOffset[i]);
|
||||
cswitchOffset2[i] = new QDoubleSpinBox(this);
|
||||
@@ -101,13 +104,13 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
|
||||
cswitchOffset2[i]->setMinimum(-channelsMax);
|
||||
cswitchOffset2[i]->setAccelerated(true);
|
||||
cswitchOffset2[i]->setDecimals(0);
|
||||
connect(cswitchOffset2[i], SIGNAL(valueChanged(double)), this, SLOT(edited()));
|
||||
cswitchOffset2[i]->setSpecialValueText(" " + tr("(instant)"));
|
||||
connect(cswitchOffset2[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited()));
|
||||
cswitchOffset2[i]->setVisible(false);
|
||||
v2Layout->addWidget(cswitchOffset2[i]);
|
||||
cswitchTOffset[i] = new QTimeEdit(this);
|
||||
cswitchTOffset[i] = new TimerEdit(this);
|
||||
cswitchTOffset[i]->setProperty("index",i);
|
||||
cswitchTOffset[i]->setAccelerated(true);
|
||||
connect(cswitchTOffset[i],SIGNAL(editingFinished()),this,SLOT(edited()));
|
||||
connect(cswitchTOffset[i],SIGNAL(editingFinished()),this,SLOT(offsetEdited()));
|
||||
v2Layout->addWidget(cswitchTOffset[i]);
|
||||
cswitchTOffset[i]->setVisible(false);
|
||||
tableLayout->addLayout(i, 3, v2Layout);
|
||||
@@ -115,6 +118,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
|
||||
// AND
|
||||
cswitchAnd[i] = new QComboBox(this);
|
||||
cswitchAnd[i]->setProperty("index", i);
|
||||
populateAndSwitchCB(cswitchAnd[i]);
|
||||
connect(cswitchAnd[i], SIGNAL(currentIndexChanged(int)), this, SLOT(andEdited(int)));
|
||||
tableLayout->addWidget(i, 4, cswitchAnd[i]);
|
||||
|
||||
@@ -157,18 +161,55 @@ LogicalSwitchesPanel::~LogicalSwitchesPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::setDataModels()
|
||||
{
|
||||
if (rawSourceItemModel)
|
||||
rawSourceItemModel->deleteLater();
|
||||
|
||||
int srcFlags = POPULATE_NONE | POPULATE_SOURCES | POPULATE_SCRIPT_OUTPUTS | POPULATE_VIRTUAL_INPUTS | POPULATE_TRIMS | POPULATE_SWITCHES | POPULATE_TELEMETRY | (firmware->getCapability(GvarsInCS) ? POPULATE_GVARS : 0);
|
||||
rawSourceItemModel = Helpers::getRawSourceItemModel(&generalSettings, model, srcFlags);
|
||||
rawSourceItemModel->setParent(this);
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::functionChanged()
|
||||
{
|
||||
int i = sender()->property("index").toInt();
|
||||
unsigned newFunc = csw[i]->currentData().toUInt();
|
||||
|
||||
if (model->logicalSw[i].func == newFunc)
|
||||
return;
|
||||
|
||||
CSFunctionFamily oldFuncFamily = model->logicalSw[i].getFunctionFamily();
|
||||
model->logicalSw[i].func = newFunc;
|
||||
CSFunctionFamily newFuncFamily = model->logicalSw[i].getFunctionFamily();
|
||||
|
||||
if (oldFuncFamily != newFuncFamily) {
|
||||
model->logicalSw[i].clear();
|
||||
model->logicalSw[i].func = newFunc;
|
||||
if (newFuncFamily == LS_FAMILY_TIMER) {
|
||||
model->logicalSw[i].val1 = -119;
|
||||
model->logicalSw[i].val2 = -119;
|
||||
}
|
||||
else if (newFuncFamily == LS_FAMILY_EDGE) {
|
||||
model->logicalSw[i].val2 = -129;
|
||||
}
|
||||
}
|
||||
updateLine(i);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::v1Edited(int value)
|
||||
{
|
||||
if (!lock) {
|
||||
int i = sender()->property("index").toInt();
|
||||
model->logicalSw[i].val1 = cswitchSource1[i]->itemData(value).toInt();
|
||||
if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) {
|
||||
RawSource source = RawSource(model->logicalSw[i].val1);
|
||||
RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[i].getRangeFlags());
|
||||
model->logicalSw[i].val2 = (cswitchOffset[i]->value() - range.offset) / range.step;
|
||||
setSwitchWidgetVisibility(i);
|
||||
if (!offsetEditedAt(i))
|
||||
updateLine(i);
|
||||
}
|
||||
else {
|
||||
emit modified();
|
||||
}
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,75 +249,65 @@ void LogicalSwitchesPanel::delayEdited(double delay)
|
||||
}
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::edited()
|
||||
void LogicalSwitchesPanel::offsetEdited()
|
||||
{
|
||||
if (!lock) {
|
||||
lock = true;
|
||||
int i = sender()->property("index").toInt();
|
||||
CSFunctionFamily oldFuncFamily = model->logicalSw[i].getFunctionFamily();
|
||||
model->logicalSw[i].func = csw[i]->itemData(csw[i]->currentIndex()).toInt();
|
||||
CSFunctionFamily newFuncFamily = model->logicalSw[i].getFunctionFamily();
|
||||
offsetEditedAt(sender()->property("index").toInt());
|
||||
}
|
||||
|
||||
if (oldFuncFamily != newFuncFamily) {
|
||||
model->logicalSw[i].clear();
|
||||
model->logicalSw[i].func = csw[i]->currentData().toInt();
|
||||
if (newFuncFamily == LS_FAMILY_TIMER) {
|
||||
model->logicalSw[i].val1 = -119;
|
||||
model->logicalSw[i].val2 = -119;
|
||||
}
|
||||
else if (newFuncFamily == LS_FAMILY_EDGE) {
|
||||
model->logicalSw[i].val2 = -129;
|
||||
}
|
||||
setSwitchWidgetVisibility(i);
|
||||
}
|
||||
bool LogicalSwitchesPanel::offsetEditedAt(int index)
|
||||
{
|
||||
if (lock)
|
||||
return false;
|
||||
|
||||
RawSource source;
|
||||
lock = true;
|
||||
bool mod = false;
|
||||
int value;
|
||||
|
||||
switch (newFuncFamily)
|
||||
switch (model->logicalSw[index].getFunctionFamily())
|
||||
{
|
||||
case LS_FAMILY_VOFS:
|
||||
{
|
||||
case LS_FAMILY_VOFS:
|
||||
{
|
||||
source = RawSource(model->logicalSw[i].val1);
|
||||
RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[i].getRangeFlags());
|
||||
double value = source.isTimeBased() ? QTimeS(cswitchTOffset[i]->time()).seconds() : cswitchOffset[i]->value();
|
||||
model->logicalSw[i].val2 = round((value-range.offset)/range.step);;
|
||||
value = model->logicalSw[i].val2*range.step + range.offset;
|
||||
if (source.isTimeBased())
|
||||
cswitchTOffset[i]->setTime(QTimeS(round(value)));
|
||||
else
|
||||
cswitchOffset[i]->setValue(value);
|
||||
break;
|
||||
}
|
||||
case LS_FAMILY_TIMER:
|
||||
model->logicalSw[i].val1 = TimToVal(cswitchValue[i]->value());
|
||||
model->logicalSw[i].val2 = TimToVal(cswitchOffset[i]->value());
|
||||
updateTimerParam(cswitchValue[i], model->logicalSw[i].val1, 0.1);
|
||||
updateTimerParam(cswitchOffset[i], model->logicalSw[i].val2, 0.1);
|
||||
break;
|
||||
case LS_FAMILY_EDGE:
|
||||
cswitchOffset2[i]->setSpecialValueText(" " + tr("(instant)"));
|
||||
if (sender() == cswitchOffset[i]) {
|
||||
model->logicalSw[i].val2 = TimToVal(cswitchOffset[i]->value());
|
||||
updateTimerParam(cswitchOffset[i], model->logicalSw[i].val2, 0.0);
|
||||
}
|
||||
else {
|
||||
model->logicalSw[i].val3 = TimToVal(cswitchOffset2[i]->value()) - model->logicalSw[i].val2;
|
||||
}
|
||||
updateTimerParam(cswitchOffset2[i], model->logicalSw[i].val2+model->logicalSw[i].val3, ValToTim(TimToVal(cswitchOffset[i]->value())-1));
|
||||
if (model->logicalSw[i].val3 == 0) {
|
||||
cswitchOffset2[i]->setSuffix(" " + tr("(infinite)"));
|
||||
}
|
||||
else {
|
||||
cswitchOffset2[i]->setSuffix("");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
RawSource source = RawSource(model->logicalSw[index].val1);
|
||||
RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[index].getRangeFlags());
|
||||
double currVal = source.isTimeBased() ? cswitchTOffset[index]->timeInSeconds() : cswitchOffset[index]->value();
|
||||
value = round((currVal - range.offset) / range.step);
|
||||
mod = (mod || value != model->logicalSw[index].val2);
|
||||
model->logicalSw[index].val2 = value;
|
||||
break;
|
||||
}
|
||||
emit modified();
|
||||
lock = false;
|
||||
updateLine(i);
|
||||
|
||||
case LS_FAMILY_TIMER:
|
||||
value = TimToVal(cswitchValue[index]->value());
|
||||
mod = (mod || value != model->logicalSw[index].val1);
|
||||
model->logicalSw[index].val1 = value;
|
||||
value = TimToVal(cswitchOffset[index]->value());
|
||||
mod = (mod || value != model->logicalSw[index].val2);
|
||||
model->logicalSw[index].val2 = value;
|
||||
break;
|
||||
|
||||
case LS_FAMILY_EDGE:
|
||||
if (sender() == cswitchOffset[index]) {
|
||||
value = TimToVal(cswitchOffset[index]->value());
|
||||
mod = (mod || value != model->logicalSw[index].val2);
|
||||
model->logicalSw[index].val2 = value;
|
||||
}
|
||||
else {
|
||||
value = TimToVal(cswitchOffset2[index]->value()) - model->logicalSw[index].val2;
|
||||
mod = (mod || value != model->logicalSw[index].val3);
|
||||
model->logicalSw[index].val3 = value;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
lock = false;
|
||||
|
||||
if (mod) {
|
||||
updateLine(index);
|
||||
emit modified();
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum)
|
||||
@@ -303,17 +334,22 @@ void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, doubl
|
||||
#define VALUE_TO_VISIBLE 0x20
|
||||
#define DELAY_ENABLED 0x40
|
||||
#define DURATION_ENABLED 0x80
|
||||
#define LINE_ENABLED 0x100
|
||||
|
||||
void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
void LogicalSwitchesPanel::updateLine(int i)
|
||||
{
|
||||
lock = true;
|
||||
unsigned int mask;
|
||||
|
||||
csw[i]->setCurrentIndex(csw[i]->findData(model->logicalSw[i].func));
|
||||
cswitchAnd[i]->setCurrentIndex(cswitchAnd[i]->findData(RawSwitch(model->logicalSw[i].andsw).toValue()));
|
||||
|
||||
if (!model->logicalSw[i].func) {
|
||||
mask = 0;
|
||||
}
|
||||
else {
|
||||
mask = DELAY_ENABLED | DURATION_ENABLED;
|
||||
mask = LINE_ENABLED | DELAY_ENABLED | DURATION_ENABLED;
|
||||
|
||||
switch (model->logicalSw[i].getFunctionFamily())
|
||||
{
|
||||
case LS_FAMILY_VOFS:
|
||||
@@ -321,20 +357,16 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
mask |= SOURCE1_VISIBLE;
|
||||
RawSource source = RawSource(model->logicalSw[i].val1);
|
||||
RawSourceRange range = source.getRange(model, generalSettings, model->logicalSw[i].getRangeFlags());
|
||||
double value = range.step * model->logicalSw[i].val2 + range.offset; /* TODO+source.getRawOffset(model)*/
|
||||
cswitchSource1[i]->setModel(rawSourceItemModel);
|
||||
cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(source.toValue()));
|
||||
cswitchOffset[i]->setDecimals(range.decimals);
|
||||
cswitchOffset[i]->setSingleStep(range.step);
|
||||
if (source.isTimeBased()) {
|
||||
mask |= VALUE_TO_VISIBLE;
|
||||
int maxTime = round(range.max);
|
||||
int value = round(range.step*model->logicalSw[i].val2 + range.offset);
|
||||
cswitchTOffset[i]->setMaximumTime(QTimeS(maxTime));
|
||||
QString format = (maxTime>=3600) ? "hh:mm:ss" : "mm:ss";
|
||||
if (!range.unit.isEmpty())
|
||||
format += QString("' [%1]'").arg(range.unit);
|
||||
cswitchTOffset[i]->setDisplayFormat(format);
|
||||
cswitchTOffset[i]->setTime(QTimeS(value));
|
||||
cswitchTOffset[i]->setTimeRange(range.min, range.max);
|
||||
cswitchTOffset[i]->setSingleStep(range.step);
|
||||
cswitchTOffset[i]->setPageStep(range.step * 60);
|
||||
cswitchTOffset[i]->setShowSeconds(range.step != 60);
|
||||
cswitchTOffset[i]->setTime((int)value);
|
||||
}
|
||||
else {
|
||||
mask |= VALUE2_VISIBLE;
|
||||
@@ -342,13 +374,16 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
cswitchOffset[i]->setSuffix("");
|
||||
else
|
||||
cswitchOffset[i]->setSuffix(" " + range.unit);
|
||||
cswitchOffset[i]->setDecimals(range.decimals);
|
||||
cswitchOffset[i]->setMinimum(range.min);
|
||||
cswitchOffset[i]->setMaximum(range.max);
|
||||
cswitchOffset[i]->setValue(range.step*(model->logicalSw[i].val2/* TODO+source.getRawOffset(model)*/)+range.offset);
|
||||
cswitchOffset[i]->setSingleStep(range.step);
|
||||
cswitchOffset[i]->setValue(value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LS_FAMILY_STICKY: // no break
|
||||
case LS_FAMILY_VBOOL:
|
||||
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
|
||||
@@ -357,6 +392,7 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
cswitchSource2[i]->setModel(rawSwitchItemModel);
|
||||
cswitchSource2[i]->setCurrentIndex(cswitchSource2[i]->findData(model->logicalSw[i].val2));
|
||||
break;
|
||||
|
||||
case LS_FAMILY_EDGE:
|
||||
mask |= SOURCE1_VISIBLE | VALUE2_VISIBLE | VALUE3_VISIBLE;
|
||||
mask &= ~DELAY_ENABLED;
|
||||
@@ -364,14 +400,9 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(model->logicalSw[i].val1));
|
||||
updateTimerParam(cswitchOffset[i], model->logicalSw[i].val2, 0.0);
|
||||
updateTimerParam(cswitchOffset2[i], model->logicalSw[i].val2+model->logicalSw[i].val3, ValToTim(TimToVal(cswitchOffset[i]->value())-1));
|
||||
cswitchOffset2[i]->setSpecialValueText(tr("(instant)"));
|
||||
if (model->logicalSw[i].val3 == 0) {
|
||||
cswitchOffset2[i]->setSuffix(tr("(infinite)"));
|
||||
}
|
||||
else {
|
||||
cswitchOffset2[i]->setSuffix("");
|
||||
}
|
||||
cswitchOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)"));
|
||||
break;
|
||||
|
||||
case LS_FAMILY_VCOMP:
|
||||
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
|
||||
cswitchSource1[i]->setModel(rawSourceItemModel);
|
||||
@@ -379,6 +410,7 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
cswitchSource2[i]->setModel(rawSourceItemModel);
|
||||
cswitchSource2[i]->setCurrentIndex(cswitchSource2[i]->findData(model->logicalSw[i].val2));
|
||||
break;
|
||||
|
||||
case LS_FAMILY_TIMER:
|
||||
mask |= VALUE1_VISIBLE | VALUE2_VISIBLE;
|
||||
updateTimerParam(cswitchValue[i], model->logicalSw[i].val1, 0.1);
|
||||
@@ -393,6 +425,7 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
cswitchOffset[i]->setVisible(mask & VALUE2_VISIBLE);
|
||||
cswitchOffset2[i]->setVisible(mask & VALUE3_VISIBLE);
|
||||
cswitchTOffset[i]->setVisible(mask & VALUE_TO_VISIBLE);
|
||||
cswitchAnd[i]->setVisible(mask & LINE_ENABLED);
|
||||
if (firmware->getCapability(LogicalSwitchesExt)) {
|
||||
cswitchDuration[i]->setVisible(mask & DURATION_ENABLED);
|
||||
cswitchDelay[i]->setVisible(mask & DELAY_ENABLED);
|
||||
@@ -401,10 +434,12 @@ void LogicalSwitchesPanel::setSwitchWidgetVisibility(int i)
|
||||
if (mask & DELAY_ENABLED)
|
||||
cswitchDelay[i]->setValue(model->logicalSw[i].delay/10.0);
|
||||
}
|
||||
|
||||
rawSwitchItemModel->update();
|
||||
lock = false;
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::populateCSWCB(QComboBox *b, int value)
|
||||
void LogicalSwitchesPanel::populateCSWCB(QComboBox *b)
|
||||
{
|
||||
int order[] = {
|
||||
LS_FN_OFF,
|
||||
@@ -441,23 +476,14 @@ void LogicalSwitchesPanel::populateCSWCB(QComboBox *b, int value)
|
||||
continue;
|
||||
}
|
||||
b->addItem(LogicalSwitchData(func).funcToString(), func);
|
||||
if (value == func) {
|
||||
b->setCurrentIndex(b->count()-1);
|
||||
}
|
||||
}
|
||||
b->setMaxVisibleItems(10);
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b, const RawSwitch & value, const int idx)
|
||||
void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b)
|
||||
{
|
||||
if (!model->logicalSw[idx].func) {
|
||||
b->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ARM(firmware->getBoard())) {
|
||||
b->setModel(rawSwitchItemModel);
|
||||
b->setCurrentIndex(b->findData(value.toValue()));
|
||||
}
|
||||
else {
|
||||
RawSwitch item;
|
||||
@@ -466,36 +492,23 @@ void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b, const RawSwitch & v
|
||||
|
||||
item = RawSwitch(SWITCH_TYPE_NONE);
|
||||
b->addItem(item.toString(), item.toValue());
|
||||
if (item == value) b->setCurrentIndex(b->count()-1);
|
||||
|
||||
for (int i=1; i <= Boards::getCapability(firmware->getBoard(), Board::SwitchPositions); i++) {
|
||||
item = RawSwitch(SWITCH_TYPE_SWITCH, i);
|
||||
b->addItem(item.toString(), item.toValue());
|
||||
if (item == value) b->setCurrentIndex(b->count()-1);
|
||||
}
|
||||
|
||||
for (int i=1; i<=6; i++) {
|
||||
item = RawSwitch(SWITCH_TYPE_VIRTUAL, i);
|
||||
b->addItem(item.toString(), item.toValue());
|
||||
if (item == value) b->setCurrentIndex(b->count()-1);
|
||||
}
|
||||
}
|
||||
b->setVisible(true);
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::updateLine(int i)
|
||||
{
|
||||
lock = true;
|
||||
populateCSWCB(csw[i], model->logicalSw[i].func);
|
||||
lock = true;
|
||||
setSwitchWidgetVisibility(i);
|
||||
lock = true;
|
||||
populateAndSwitchCB(cswitchAnd[i], RawSwitch(model->logicalSw[i].andsw), i);
|
||||
lock = false;
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::update()
|
||||
{
|
||||
setDataModels();
|
||||
for (int i=0; i<firmware->getCapability(LogicalSwitches); i++) {
|
||||
updateLine(i);
|
||||
}
|
||||
@@ -510,7 +523,6 @@ void LogicalSwitchesPanel::cswPaste()
|
||||
LogicalSwitchData *csw = &model->logicalSw[selectedSwitch];
|
||||
memcpy(csw, cswData.constData(), sizeof(LogicalSwitchData));
|
||||
emit modified();
|
||||
rawSwitchItemModel->update();
|
||||
updateLine(selectedSwitch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "radiodata.h"
|
||||
|
||||
class RawSwitchFilterItemModel;
|
||||
class TimerEdit;
|
||||
|
||||
class LogicalSwitchesPanel : public ModelPanel
|
||||
{
|
||||
@@ -37,12 +38,16 @@ class LogicalSwitchesPanel : public ModelPanel
|
||||
virtual void update();
|
||||
|
||||
private slots:
|
||||
void edited();
|
||||
void setDataModels();
|
||||
void functionChanged();
|
||||
void v1Edited(int value);
|
||||
void v2Edited(int value);
|
||||
void andEdited(int value);
|
||||
void durationEdited(double duration);
|
||||
void delayEdited(double delay);
|
||||
void offsetEdited();
|
||||
bool offsetEditedAt(int index);
|
||||
void updateLine(int index);
|
||||
void csw_customContextMenuRequested(QPoint pos);
|
||||
void cswDelete();
|
||||
void cswCopy();
|
||||
@@ -54,7 +59,7 @@ class LogicalSwitchesPanel : public ModelPanel
|
||||
QDoubleSpinBox * cswitchValue[CPN_MAX_LOGICAL_SWITCHES];
|
||||
QDoubleSpinBox * cswitchOffset[CPN_MAX_LOGICAL_SWITCHES];
|
||||
QDoubleSpinBox * cswitchOffset2[CPN_MAX_LOGICAL_SWITCHES];
|
||||
QTimeEdit * cswitchTOffset[CPN_MAX_LOGICAL_SWITCHES];
|
||||
TimerEdit * cswitchTOffset[CPN_MAX_LOGICAL_SWITCHES];
|
||||
QComboBox * cswitchAnd[CPN_MAX_LOGICAL_SWITCHES];
|
||||
QDoubleSpinBox * cswitchDuration[CPN_MAX_LOGICAL_SWITCHES];
|
||||
QDoubleSpinBox * cswitchDelay[CPN_MAX_LOGICAL_SWITCHES];
|
||||
@@ -62,12 +67,10 @@ class LogicalSwitchesPanel : public ModelPanel
|
||||
QComboBox * cswitchSource2[CPN_MAX_LOGICAL_SWITCHES];
|
||||
RawSwitchFilterItemModel * rawSwitchItemModel;
|
||||
QStandardItemModel * rawSourceItemModel;
|
||||
void setSwitchWidgetVisibility(int i);
|
||||
int selectedSwitch;
|
||||
|
||||
void populateCSWCB(QComboBox *b, int value);
|
||||
void populateAndSwitchCB(QComboBox *b, const RawSwitch & value, const int idx);
|
||||
void updateLine(int index);
|
||||
void populateCSWCB(QComboBox *b);
|
||||
void populateAndSwitchCB(QComboBox *b);
|
||||
void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0);
|
||||
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
|
||||
#include <TimerEdit>
|
||||
|
||||
TelemetryAnalog::TelemetryAnalog(QWidget *parent, FrSkyChannelData & analog, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
ModelPanel(parent, model, generalSettings, firmware),
|
||||
ui(new Ui::TelemetryAnalog),
|
||||
@@ -324,6 +326,13 @@ TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model,
|
||||
connect(minSB[l], SIGNAL(valueChanged(double)), this, SLOT(barMinChanged(double)));
|
||||
ui->screenBarsLayout->addWidget(minSB[l], l, 1, 1, 1);
|
||||
|
||||
minTime[l] = new TimerEdit(this);
|
||||
minTime[l]->setProperty("index", l);
|
||||
minTime[l]->setProperty("type", "min");
|
||||
connect(minTime[l], SIGNAL(editingFinished()), this, SLOT(barTimeChanged()));
|
||||
ui->screenBarsLayout->addWidget(minTime[l], l, 1, 1, 1);
|
||||
minTime[l]->hide();
|
||||
|
||||
QLabel * label = new QLabel(this);
|
||||
label->setAutoFillBackground(false);
|
||||
label->setStyleSheet(QString::fromUtf8("Background:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 128, 255), stop:0.339795 rgba(0, 0, 128, 255), stop:0.339799 rgba(255, 255, 255, 255), stop:0.662444 rgba(255, 255, 255, 255),)\n"""));
|
||||
@@ -336,6 +345,13 @@ TelemetryCustomScreen::TelemetryCustomScreen(QWidget *parent, ModelData & model,
|
||||
maxSB[l]->setProperty("index", l);
|
||||
connect(maxSB[l], SIGNAL(valueChanged(double)), this, SLOT(barMaxChanged(double)));
|
||||
ui->screenBarsLayout->addWidget(maxSB[l], l, 3, 1, 1);
|
||||
|
||||
maxTime[l] = new TimerEdit(this);
|
||||
maxTime[l]->setProperty("index", l);
|
||||
maxTime[l]->setProperty("type", "max");
|
||||
connect(maxTime[l], SIGNAL(editingFinished()), this, SLOT(barTimeChanged()));
|
||||
ui->screenBarsLayout->addWidget(maxTime[l], l, 3, 1, 1);
|
||||
maxTime[l]->hide();
|
||||
}
|
||||
|
||||
disableMouseScrolling();
|
||||
@@ -410,30 +426,58 @@ void TelemetryCustomScreen::updateBar(int line)
|
||||
lock = true;
|
||||
|
||||
RawSource source = screen.body.bars[line].source;
|
||||
|
||||
minTime[line]->setVisible(false);
|
||||
maxTime[line]->setVisible(false);
|
||||
|
||||
if (source.type != SOURCE_TYPE_NONE) {
|
||||
RawSourceRange range = source.getRange(model, generalSettings, RANGE_SINGLE_PRECISION);
|
||||
RawSourceRange range = source.getRange(model, generalSettings);
|
||||
if (!IS_ARM(getCurrentBoard())) {
|
||||
int max = round((range.max - range.min) / range.step);
|
||||
if (int(255-screen.body.bars[line].barMax) > max) {
|
||||
screen.body.bars[line].barMax = 255 - max;
|
||||
}
|
||||
}
|
||||
minSB[line]->setEnabled(true);
|
||||
minSB[line]->setDecimals(range.decimals);
|
||||
minSB[line]->setMinimum(range.min);
|
||||
minSB[line]->setMaximum(range.max);
|
||||
minSB[line]->setSingleStep(range.step);
|
||||
minSB[line]->setValue(range.getValue(screen.body.bars[line].barMin));
|
||||
maxSB[line]->setEnabled(true);
|
||||
maxSB[line]->setDecimals(range.decimals);
|
||||
maxSB[line]->setMinimum(range.min);
|
||||
maxSB[line]->setMaximum(range.max);
|
||||
maxSB[line]->setSingleStep(range.step);
|
||||
if (IS_ARM(getCurrentBoard())) {
|
||||
maxSB[line]->setValue(range.getValue(screen.body.bars[line].barMax));
|
||||
float minVal = range.getValue(screen.body.bars[line].barMin);
|
||||
float maxVal = IS_ARM(getCurrentBoard()) ? screen.body.bars[line].barMax : 255 - screen.body.bars[line].barMax;
|
||||
maxVal = range.getValue(maxVal);
|
||||
|
||||
if (source.isTimeBased()) {
|
||||
minTime[line]->setVisible(true);
|
||||
minTime[line]->setTimeRange(range.min, range.max);
|
||||
minTime[line]->setSingleStep(range.step);
|
||||
minTime[line]->setPageStep(range.step * 60);
|
||||
minTime[line]->setShowSeconds(range.step != 60);
|
||||
minTime[line]->setTime((int)minVal);
|
||||
|
||||
maxTime[line]->setVisible(true);
|
||||
maxTime[line]->setTimeRange(range.min, range.max);
|
||||
maxTime[line]->setSingleStep(range.step);
|
||||
maxTime[line]->setPageStep(range.step * 60);
|
||||
maxTime[line]->setShowSeconds(range.step != 60);
|
||||
maxTime[line]->setTime((int)maxVal);
|
||||
|
||||
minSB[line]->setVisible(false);
|
||||
maxSB[line]->setVisible(false);
|
||||
}
|
||||
else {
|
||||
maxSB[line]->setValue(range.getValue(255 - screen.body.bars[line].barMax));
|
||||
minSB[line]->setVisible(true);
|
||||
minSB[line]->setEnabled(true);
|
||||
minSB[line]->setDecimals(range.decimals);
|
||||
minSB[line]->setMinimum(range.min);
|
||||
minSB[line]->setMaximum(range.max);
|
||||
minSB[line]->setSingleStep(range.step);
|
||||
minSB[line]->setSuffix(" " + range.unit);
|
||||
minSB[line]->setValue(minVal);
|
||||
|
||||
maxSB[line]->setVisible(true);
|
||||
maxSB[line]->setEnabled(true);
|
||||
maxSB[line]->setDecimals(range.decimals);
|
||||
maxSB[line]->setMinimum(range.min);
|
||||
maxSB[line]->setMaximum(range.max);
|
||||
maxSB[line]->setSingleStep(range.step);
|
||||
maxSB[line]->setSuffix(" " + range.unit);
|
||||
maxSB[line]->setValue(maxVal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -511,6 +555,24 @@ void TelemetryCustomScreen::barMaxChanged(double value)
|
||||
}
|
||||
}
|
||||
|
||||
void TelemetryCustomScreen::barTimeChanged()
|
||||
{
|
||||
if (!lock) {
|
||||
int line = sender()->property("index").toInt();
|
||||
int & valRef = (sender()->property("type").toString() == "min" ? screen.body.bars[line].barMin : screen.body.bars[line].barMax);
|
||||
TimerEdit * te = qobject_cast<TimerEdit *>(sender());
|
||||
if (!te)
|
||||
return;
|
||||
|
||||
if (IS_ARM(getCurrentBoard()))
|
||||
valRef = round(te->timeInSeconds() / te->singleStep());
|
||||
else
|
||||
valRef = round((te->timeInSeconds() - te->minimumTime()) / te->singleStep());
|
||||
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
ModelPanel(parent, model, generalSettings, firmware),
|
||||
ui(new Ui::TelemetrySensor),
|
||||
@@ -598,23 +660,27 @@ void TelemetrySensorPanel::update()
|
||||
ui->formula->hide();
|
||||
isConfigurable = sensor.unit < SensorData::UNIT_FIRST_VIRTUAL;
|
||||
ratioFieldsDisplayed = (sensor.unit < SensorData::UNIT_FIRST_VIRTUAL);
|
||||
ui->offset->setMaximum((sensor.prec > 0 ? sensor.prec == 2 ? 30000 : 3000 : 300));
|
||||
ui->offset->setMinimum((sensor.prec > 0 ? sensor.prec == 2 ? -30000 : -3000 : -300));
|
||||
|
||||
if (sensor.unit == SensorData::UNIT_RPMS) {
|
||||
ui->offset->setDecimals(0);
|
||||
ui->offset->setSingleStep(1);
|
||||
ui->ratio->setDecimals(0);
|
||||
ui->ratio->setSingleStep(1);
|
||||
ui->autoOffset->hide();
|
||||
ui->ratio->setMinimum(1);
|
||||
ui->offset->setMinimum(1);
|
||||
if (ui->ratio->decimals()) {
|
||||
ui->ratio->setMaximum(30000);
|
||||
ui->ratio->setMinimum(1);
|
||||
ui->ratio->setDecimals(0);
|
||||
ui->ratio->setSingleStep(1);
|
||||
ui->offset->setMaximum(30000);
|
||||
ui->offset->setMinimum(1);
|
||||
ui->offset->setDecimals(0);
|
||||
ui->offset->setSingleStep(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui->offset->setDecimals(sensor.prec);
|
||||
ui->offset->setSingleStep(pow(0.1, (int)sensor.prec));
|
||||
else if (ui->ratio->decimals() != 1) {
|
||||
ui->ratio->setMaximum(3000);
|
||||
ui->ratio->setMinimum(0);
|
||||
ui->ratio->setDecimals(1);
|
||||
ui->ratio->setSingleStep(0.1);
|
||||
ui->offset->setMaximum(30000.0f / powf(10.0f, sensor.prec));
|
||||
ui->offset->setMinimum(-ui->offset->maximum());
|
||||
ui->offset->setDecimals(sensor.prec);
|
||||
ui->offset->setSingleStep(pow(0.1, sensor.prec));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "eeprominterface.h"
|
||||
|
||||
class AutoComboBox;
|
||||
class TimerEdit;
|
||||
|
||||
namespace Ui {
|
||||
class TelemetryAnalog;
|
||||
@@ -82,6 +83,7 @@ class TelemetryCustomScreen: public ModelPanel
|
||||
void barSourceChanged(int index);
|
||||
void barMinChanged(double value);
|
||||
void barMaxChanged(double value);
|
||||
void barTimeChanged();
|
||||
|
||||
protected:
|
||||
void populateTelemetrySourceCB(QComboBox * b, RawSource & source, bool last=false);
|
||||
@@ -94,6 +96,8 @@ class TelemetryCustomScreen: public ModelPanel
|
||||
QComboBox * barsCB[4];
|
||||
QDoubleSpinBox * minSB[4];
|
||||
QDoubleSpinBox * maxSB[4];
|
||||
TimerEdit * minTime[4];
|
||||
TimerEdit * maxTime[4];
|
||||
};
|
||||
|
||||
class TelemetrySensorPanel: public ModelPanel
|
||||
|
||||
@@ -187,9 +187,8 @@ class RawSourceRange
|
||||
QString unit;
|
||||
};
|
||||
|
||||
#define RANGE_SINGLE_PRECISION 1
|
||||
#define RANGE_DELTA_FUNCTION 2
|
||||
#define RANGE_DELTA_ABS_FUNCTION 4
|
||||
#define RANGE_DELTA_FUNCTION 1
|
||||
#define RANGE_ABS_FUNCTION 2
|
||||
|
||||
class RawSource {
|
||||
public:
|
||||
|
||||
@@ -15,8 +15,8 @@ set(shared_HDRS
|
||||
genericpanel.h
|
||||
hexspinbox.h
|
||||
)
|
||||
|
||||
|
||||
qt5_wrap_cpp(shared_SRCS ${shared_HDRS})
|
||||
|
||||
add_library(shared ${shared_SRCS})
|
||||
qt5_use_modules(shared Widgets)
|
||||
target_link_libraries(shared PRIVATE Qt5::Widgets ${CPN_COMMON_LIB})
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "genericpanel.h"
|
||||
|
||||
#include <TimerEdit>
|
||||
#include <QComboBox>
|
||||
#include <QEvent>
|
||||
#include <QLabel>
|
||||
@@ -105,20 +107,23 @@ bool GenericPanel::eventFilter(QObject *object, QEvent * event)
|
||||
return QWidget::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void GenericPanel::setFocusFilter(QWidget * w)
|
||||
{
|
||||
w->installEventFilter(this);
|
||||
w->setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
|
||||
void GenericPanel::disableMouseScrolling()
|
||||
{
|
||||
Q_FOREACH(QComboBox * cb, findChildren<QComboBox*>()) {
|
||||
cb->installEventFilter(this);
|
||||
cb->setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
foreach(QWidget * cb, findChildren<QComboBox*>())
|
||||
setFocusFilter(cb);
|
||||
|
||||
Q_FOREACH(QAbstractSpinBox * sb, findChildren<QAbstractSpinBox*>()) {
|
||||
sb->installEventFilter(this);
|
||||
sb->setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
foreach(QWidget * sb, findChildren<QAbstractSpinBox*>())
|
||||
setFocusFilter(sb);
|
||||
|
||||
Q_FOREACH(QSlider * slider, findChildren<QSlider*>()) {
|
||||
slider->installEventFilter(this);
|
||||
slider->setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
foreach(QWidget * slider, findChildren<QSlider*>())
|
||||
setFocusFilter(slider);
|
||||
|
||||
foreach(QWidget * te, findChildren<TimerEdit*>())
|
||||
setFocusFilter(te);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ class GenericPanel : public QWidget
|
||||
void addVSpring(QGridLayout *, int col, int row);
|
||||
void addDoubleSpring(QGridLayout *, int col, int row);
|
||||
virtual bool eventFilter(QObject *obj, QEvent *event);
|
||||
void setFocusFilter(QWidget * w);
|
||||
void disableMouseScrolling();
|
||||
};
|
||||
|
||||
|
||||
@@ -92,4 +92,4 @@ qt5_wrap_ui(simulation_SRCS ${simulation_UIS})
|
||||
qt5_wrap_cpp(simulation_SRCS ${simulation_HDRS})
|
||||
|
||||
add_library(simulation ${simulation_SRCS} ${simulation_HDRS})
|
||||
qt5_use_modules(simulation Core Widgets Svg)
|
||||
target_link_libraries(simulation PRIVATE ${CPN_COMMON_LIB} Qt5::Core Qt5::Widgets Qt5::Svg)
|
||||
|
||||
@@ -13,14 +13,14 @@ project(maxLibQtWidgets)
|
||||
set(SRCS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ExportableTableView.cpp"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/ScrollableMessageBox.cpp"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/TimerEdit.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/TimerEdit.cpp"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/TreeComboBox.cpp"
|
||||
)
|
||||
|
||||
set(HDRS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ExportableTableView.h"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/ScrollableMessageBox.h"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/TimerEdit.h"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/TimerEdit.h"
|
||||
# "${CMAKE_CURRENT_LIST_DIR}/TreeComboBox.h"
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "TimerEdit.h"
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
TimerEdit
|
||||
|
||||
COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
|
||||
Contact: http://www.WorldDesign.com/contact
|
||||
|
||||
LICENSE:
|
||||
|
||||
Commercial License Usage
|
||||
Licensees holding valid commercial licenses may use this file in
|
||||
accordance with the terms contained in a written agreement between
|
||||
you and the copyright holder.
|
||||
|
||||
GNU General Public License Usage
|
||||
Alternatively, this file may be used under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TimerEdit.h"
|
||||
#include <cmath>
|
||||
|
||||
TimerEdit::TimerEdit(QWidget *parent) :
|
||||
QLineEdit(parent),
|
||||
m_showSeconds(true),
|
||||
m_minTime(0),
|
||||
m_maxTime(24 * 3600 - 1),
|
||||
m_singleStep(1),
|
||||
m_pageStep(60),
|
||||
m_hourDigits(2),
|
||||
m_validator(new QRegularExpressionValidator(this))
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
setupFormat();
|
||||
setToolTip(tr("Use mouse scroll or UP/DOWN arrow keys to change time in small steps.\nCTRL + scroll or PAGE UP/DOWN keys to change time in larger steps."));
|
||||
connect(this, &TimerEdit::textEdited, this, &TimerEdit::textEditedHandler);
|
||||
}
|
||||
|
||||
int TimerEdit::timeInSeconds() const
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret += timepart(text(), TimeParts::Hours) * 3600;
|
||||
ret += timepart(text(), TimeParts::Minutes) * 60;
|
||||
ret += timepart(text(), TimeParts::Seconds);
|
||||
ret *= timepart(text(), TimeParts::Polarity);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TimerEdit::timepart(const QString &input, TimerEdit::TimeParts part) const
|
||||
{
|
||||
int ret = 0;
|
||||
QRegularExpressionMatch match = m_validator->regularExpression().match(input, 0, QRegularExpression::NormalMatch);
|
||||
|
||||
if (match.hasMatch()) {
|
||||
switch (part) {
|
||||
case Hours:
|
||||
if (!match.captured("hrs").isEmpty())
|
||||
ret = match.captured("hrs").toInt();
|
||||
break;
|
||||
|
||||
case Minutes:
|
||||
if (!match.captured("mins").isEmpty())
|
||||
ret = match.captured("mins").toInt();
|
||||
break;
|
||||
|
||||
case Seconds:
|
||||
if (!match.captured("secs").isEmpty())
|
||||
ret = match.captured("secs").toInt();
|
||||
break;
|
||||
|
||||
case Polarity:
|
||||
if (!match.captured("pol").isEmpty() && !match.captured("pol").compare("-"))
|
||||
ret = -1;
|
||||
else
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//// Slots ////
|
||||
|
||||
void TimerEdit::setTime(int seconds)
|
||||
{
|
||||
if (seconds > m_maxTime)
|
||||
seconds = m_maxTime;
|
||||
else if (seconds < m_minTime)
|
||||
seconds = m_minTime;
|
||||
|
||||
div_t qrM = div(abs(seconds), 60);
|
||||
div_t qrH = div(qrM.quot, 60);
|
||||
|
||||
QString val = QString("%1").arg(qrH.rem, 2, 10, QChar('0'));
|
||||
|
||||
if (m_hourDigits)
|
||||
val.prepend(QString("%1:").arg(qrH.quot, m_hourDigits, 10, QChar('0')));
|
||||
|
||||
if (m_showSeconds)
|
||||
val.append(QString(":%1").arg(qrM.rem, 2, 10, QChar('0')));
|
||||
|
||||
if (m_minTime < 0) {
|
||||
if (seconds < 0)
|
||||
val.prepend("-");
|
||||
else
|
||||
val.prepend(" ");
|
||||
}
|
||||
|
||||
if (text().compare(val)) {
|
||||
setText(val);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::incrDecr(int seconds)
|
||||
{
|
||||
if (!seconds)
|
||||
return;
|
||||
|
||||
const int cs = timeInSeconds();
|
||||
int s = seconds + cs;
|
||||
if (s < m_minTime)
|
||||
s = m_minTime;
|
||||
if (s > m_maxTime)
|
||||
s = m_maxTime;
|
||||
if (s != cs) {
|
||||
setTime(s);
|
||||
emitValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::setTimeRange(int minSeconds, int maxSeconds)
|
||||
{
|
||||
if (minSeconds <= maxSeconds && (m_minTime != minSeconds || m_maxTime != maxSeconds)) {
|
||||
int digits = 0;
|
||||
if (maxSeconds >= 3600)
|
||||
digits = floorf(logf(round(maxSeconds / 3600)) / logf(10.0f)) + 1;
|
||||
|
||||
bool mod = (m_hourDigits != digits || std::signbit((float)m_minTime) != std::signbit((float)minSeconds));
|
||||
|
||||
m_minTime = minSeconds;
|
||||
m_maxTime = maxSeconds;
|
||||
m_hourDigits = digits;
|
||||
|
||||
if (mod)
|
||||
setupFormat();
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::setMinimumTime(int minSeconds)
|
||||
{
|
||||
setTimeRange(minSeconds, (m_maxTime > minSeconds ? m_maxTime : minSeconds));
|
||||
}
|
||||
|
||||
void TimerEdit::setMaximumTime(int maxSeconds)
|
||||
{
|
||||
setTimeRange((m_minTime < maxSeconds ? m_minTime : maxSeconds), maxSeconds);
|
||||
}
|
||||
|
||||
void TimerEdit::setShowSeconds(bool showSeconds)
|
||||
{
|
||||
if (m_showSeconds != showSeconds) {
|
||||
m_showSeconds = showSeconds;
|
||||
setupFormat();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// Protected ////
|
||||
|
||||
void TimerEdit::textEditedHandler()
|
||||
{
|
||||
int sec = timeInSeconds();
|
||||
if (sec < m_minTime)
|
||||
setTime(m_minTime);
|
||||
else if (sec > m_maxTime)
|
||||
setTime(m_maxTime);
|
||||
else
|
||||
return;
|
||||
|
||||
emitValueChanged();
|
||||
}
|
||||
|
||||
void TimerEdit::setupFormat()
|
||||
{
|
||||
QString inputRe = "(?<mins>[0-5][0-9])";
|
||||
QString inputMsk = "99";
|
||||
QString suffx = "\\" % tr("m") % "\\" % tr("m");
|
||||
|
||||
if (m_hourDigits) {
|
||||
inputRe.prepend("(?<hrs>[0-9]*[0-9]):");
|
||||
inputMsk.prepend(":");
|
||||
suffx.prepend(":");
|
||||
for (int i=0; i < m_hourDigits; ++i) {
|
||||
inputMsk.prepend("9");
|
||||
suffx.prepend("\\" % tr("h"));
|
||||
}
|
||||
}
|
||||
if (m_showSeconds) {
|
||||
inputRe.append(":(?<secs>[0-5][0-9])");
|
||||
inputMsk.append(":99");
|
||||
suffx.append(":\\" % tr("s") % "\\" % tr("s"));
|
||||
}
|
||||
if (m_minTime < 0) {
|
||||
inputRe.prepend("(?<pol>-|\\+|\\s)?");
|
||||
inputMsk.prepend("#");
|
||||
}
|
||||
|
||||
inputRe.prepend("^");
|
||||
inputRe.append("\\s?\\[[^\\]]+\\]$");
|
||||
inputMsk.append(" \\[" % suffx % "\\]");
|
||||
|
||||
m_validator->setRegularExpression(QRegularExpression(inputRe));
|
||||
|
||||
setInputMask(inputMsk);
|
||||
setValidator(m_validator);
|
||||
}
|
||||
|
||||
void TimerEdit::emitValueChanged()
|
||||
{
|
||||
emit QLineEdit::textEdited(text());
|
||||
}
|
||||
|
||||
void TimerEdit::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Up:
|
||||
incrDecr(m_singleStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
incrDecr(-(int)m_singleStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_PageUp:
|
||||
incrDecr(m_pageStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_PageDown:
|
||||
incrDecr(-(int)m_pageStep);
|
||||
break;
|
||||
|
||||
case Qt::Key_Plus:
|
||||
case Qt::Key_Equal:
|
||||
case Qt::Key_Minus:
|
||||
if (m_minTime < 0) {
|
||||
setTime(-timeInSeconds());
|
||||
emitValueChanged();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
QLineEdit::keyPressEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerEdit::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
if (event->angleDelta().isNull()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
int numSteps = -event->angleDelta().y() / 8 / 15 * -1; // one step per 15deg
|
||||
numSteps *= (event->modifiers() & Qt::ControlModifier) ? m_pageStep : m_singleStep;
|
||||
incrDecr(numSteps);
|
||||
event->accept();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
TimerEdit
|
||||
https://github.com/mpaperno/maxLibQt
|
||||
|
||||
COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
|
||||
Contact: http://www.WorldDesign.com/contact
|
||||
|
||||
LICENSE:
|
||||
|
||||
Commercial License Usage
|
||||
Licensees holding valid commercial licenses may use this file in
|
||||
accordance with the terms contained in a written agreement between
|
||||
you and the copyright holder.
|
||||
|
||||
GNU General Public License Usage
|
||||
Alternatively, this file may be used under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TIMEREDIT_H
|
||||
#define TIMEREDIT_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QKeyEvent>
|
||||
#include <QWheelEvent>
|
||||
|
||||
/**
|
||||
\class TimerEdit
|
||||
\version 1.0.0
|
||||
|
||||
\brief A time value line editor which accepts negative and large times (> 23:59:59), suitable for a timer, etc.
|
||||
|
||||
Qt's \c QTimeEdit has a limitation in that it can only accept "valid" times, in the range of 0:00:00 to 23:59:59.
|
||||
The TimerEdit control aims to address that. It allows any amount of time to be entered, as well as negative times.
|
||||
It provides a mask for data entry, a validator with settable min/max times, and increment/decrement via keyboard
|
||||
or mouse wheel in configurable steps.
|
||||
|
||||
Data I/O is in seconds only, that is you set the time value in total seconds and also read it back in seconds
|
||||
(there is no conversion from/to a \e QTime object).
|
||||
|
||||
*/
|
||||
class TimerEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int minimumTime READ minimumTime WRITE setMinimumTime)
|
||||
Q_PROPERTY(int maximumTime READ maximumTime WRITE setMaximumTime)
|
||||
Q_PROPERTY(bool showSeconds READ showSeconds WRITE setShowSeconds)
|
||||
Q_PROPERTY(unsigned int singleStep READ singleStep WRITE setSingleStep)
|
||||
Q_PROPERTY(unsigned int pageStep READ pageStep WRITE setPageStep)
|
||||
|
||||
|
||||
public:
|
||||
enum TimeParts {Whole, Polarity, Hours, Minutes, Seconds};
|
||||
|
||||
TimerEdit(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
int timeInSeconds() const;
|
||||
int timepart(const QString &input, TimeParts part) const;
|
||||
|
||||
bool showSeconds() const { return m_showSeconds; }
|
||||
int minimumTime() const { return m_minTime; }
|
||||
int maximumTime() const { return m_maxTime; }
|
||||
unsigned int singleStep() const { return m_singleStep; }
|
||||
unsigned int pageStep() const { return m_pageStep; }
|
||||
|
||||
public slots:
|
||||
void setTime(int seconds);
|
||||
void incrDecr(int seconds);
|
||||
void setTimeRange(int minSeconds, int maxSeconds);
|
||||
void setMinimumTime(int minSeconds);
|
||||
void setMaximumTime(int maxSeconds);
|
||||
void setShowSeconds(bool showSeconds);
|
||||
|
||||
void setSingleStep(unsigned int step) { m_singleStep = step; }
|
||||
void setPageStep(unsigned int pageStep) { m_pageStep = pageStep; }
|
||||
|
||||
protected:
|
||||
void textEditedHandler();
|
||||
void setupFormat();
|
||||
void emitValueChanged();
|
||||
void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
|
||||
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
|
||||
|
||||
bool m_showSeconds;
|
||||
int m_minTime; // seconds
|
||||
int m_maxTime; // seconds
|
||||
unsigned m_singleStep; // seconds
|
||||
unsigned m_pageStep; // seconds
|
||||
short m_hourDigits;
|
||||
QRegularExpressionValidator * m_validator;
|
||||
};
|
||||
|
||||
#endif // TIMEREDIT_H
|
||||
Reference in New Issue
Block a user