[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:
Max Paperno
2017-12-19 12:17:49 +01:00
committed by Bertrand Songis
parent b69f36afe4
commit 76ce186bd4
17 changed files with 741 additions and 257 deletions
+3 -6
View File
@@ -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 ####################
+77 -66
View File
@@ -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
+7 -7
View File
@@ -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) {
+2 -1
View File
@@ -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];
+135 -123
View File
@@ -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);
}
}
+9 -6
View File
@@ -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);
};
+94 -28
View File
@@ -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));
}
}
+4
View File
@@ -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
+2 -3
View File
@@ -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:
+2 -2
View File
@@ -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})
+17 -12
View File
@@ -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);
}
+1
View File
@@ -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();
};
+1 -1
View File
@@ -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