Companion update model references from enhanced context menus (#7325)

Companion update model references from enhanced context menus
This commit is contained in:
Neil Horne
2020-05-15 15:25:50 +02:00
committed by GitHub
parent f7fc15d7b5
commit 40f9b05ce2
31 changed files with 3472 additions and 984 deletions
+1
View File
@@ -1,5 +1,6 @@
set(firmwares_SRCS
adjustmentreference.cpp
boards.cpp
curvereference.cpp
customfunctiondata.cpp
@@ -0,0 +1,81 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include "adjustmentreference.h"
#include "radiodata.h" // for ModelData
AdjustmentReference::AdjustmentReference(int value)
{
int val = value;
if (abs(val) > ADJUST_REF_GVAR_BASE && abs(val) <= ADJUST_REF_GVAR_BASE + CPN_MAX_GVARS) {
type = ADJUST_REF_GVAR;
val = val >= 0 ? val - ADJUST_REF_GVAR_BASE : val + ADJUST_REF_GVAR_BASE;
}
else
this->type = ADJUST_REF_VALUE;
this->value = val;
}
AdjustmentReference::AdjustmentReference(AdjustRefType type, int value)
{
this->type = type;
if (isValid(value))
this->value = value;
else
clear();
}
bool AdjustmentReference::isValid(const int value) const
{
switch(type) {
case ADJUST_REF_VALUE:
if (abs(value) < ADJUST_REF_GVAR_BASE)
return true;
break;
case ADJUST_REF_GVAR:
if (abs(value) > 0 && abs(value) <= CPN_MAX_GVARS);
return true;
break;
}
return false;
}
QString AdjustmentReference::toString(const ModelData * model, const bool sign) const
{
QString ret;
switch(type) {
case ADJUST_REF_GVAR:
ret = RawSource(SOURCE_TYPE_GVAR, abs(value) - 1).toString(model);
if (value < 0)
ret.prepend("-");
else if (sign)
ret.prepend("+");
break;
default:
ret = "%1%";
if (sign && value > 0)
ret.prepend("+");
ret = ret.arg(value);
break;
}
return ret;
}
@@ -0,0 +1,69 @@
/*
* Copyright (C) OpenTX
*
* Based on code named
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#ifndef ADJUSTMENTREFERENCE_H
#define ADJUSTMENTREFERENCE_H
#include <QtCore>
class ModelData;
constexpr int ADJUST_REF_GVAR_BASE { 10000 };
class AdjustmentReference {
Q_DECLARE_TR_FUNCTIONS(AdjustmentReference)
public:
enum AdjustRefType {
ADJUST_REF_VALUE,
ADJUST_REF_GVAR,
};
AdjustmentReference() { clear(); }
explicit AdjustmentReference(int value);
AdjustmentReference(const AdjustRefType type, const int value);
void clear() { memset(this, 0, sizeof(AdjustmentReference)); }
bool isSet() const { return type != ADJUST_REF_VALUE || value != 0; }
bool isValid(const int value) const;
QString toString(const ModelData * model = nullptr, const bool sign = false) const;
inline const int toValue() const
{
if (type == ADJUST_REF_GVAR)
return value >= 0 ? value + ADJUST_REF_GVAR_BASE : value - ADJUST_REF_GVAR_BASE;
else
return value;
}
bool operator== ( const AdjustmentReference & other) const {
return (this->type == other.type) && (this->value == other.value);
}
bool operator!= ( const AdjustmentReference & other) const {
return (this->type != other.type) || (this->value != other.value);
}
AdjustRefType type;
int value;
};
#endif // ADJUSTMENTREFERENCE_H
+1
View File
@@ -50,6 +50,7 @@ class CurveReference {
int value;
QString toString(const ModelData * model = NULL, bool verbose = true) const;
bool isSet() const { return type != CURVE_REF_DIFF || value != 0; }
};
#endif // CURVEREFERENCE_H
+4 -1
View File
@@ -100,6 +100,8 @@ enum Capability {
GvarsName,
NoTelemetryProtocol,
TelemetryCustomScreens,
TelemetryCustomScreensBars,
TelemetryCustomScreensLines,
TelemetryCustomScreensFieldsPerLine,
TelemetryMaxMultiplier,
HasVario,
@@ -149,7 +151,8 @@ enum Capability {
DangerousFunctions,
HasModelCategories,
HasSwitchableJack,
PwrButtonPress
PwrButtonPress,
Sensors
};
class EEPROMInterface
+5
View File
@@ -90,3 +90,8 @@ float GVarData::getMaxPrec() const
{
return getMax() * multiplierGet();
}
bool GVarData::isEmpty() const
{
return (name[0] == '\0' && min == 0 && max == 0 && (!popup) && prec == 0 && unit == 0);
}
+2 -1
View File
@@ -43,7 +43,7 @@ class GVarData {
GVAR_PREC_MUL1
};
char name[GVAR_NAME_LEN+1];
char name[GVAR_NAME_LEN + 1];
int min;
int max;
bool popup;
@@ -62,6 +62,7 @@ class GVarData {
int getMax() const;
float getMinPrec() const;
float getMaxPrec() const;
bool isEmpty() const;
};
+68 -13
View File
@@ -35,6 +35,10 @@ void ExpoData::convert(RadioDataConversionState & cstate)
swtch.convert(cstate);
}
bool ExpoData::isEmpty() const
{
return (chn == 0 && mode == INPUT_MODE_NONE);
}
/*
* MixData
@@ -48,6 +52,10 @@ void MixData::convert(RadioDataConversionState & cstate)
swtch.convert(cstate);
}
bool MixData::isEmpty() const
{
return (destCh == 0);
}
/*
* LimitData
@@ -87,17 +95,16 @@ void LimitData::clear()
bool LimitData::isEmpty() const
{
return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0');
return (min == -1000 && max == 1000 && !revert && !offset && !ppmCenter && !symetrical && name[0] == '\0' && !curve.isSet());
}
/*
* CurveData
*/
CurveData::CurveData()
{
clear(5);
clear();
}
void CurveData::clear(int count)
@@ -126,22 +133,20 @@ QString CurveData::nameToString(const int idx) const
* FlightModeData
*/
void FlightModeData::clear(const int phase)
void FlightModeData::clear(const int phaseIdx)
{
memset(reinterpret_cast<void *>(this), 0, sizeof(FlightModeData));
if (phase != 0) {
for (int idx=0; idx<CPN_MAX_GVARS; idx++) {
gvars[idx] = 1025;
}
for (int idx=0; idx<CPN_MAX_ENCODERS; idx++) {
rotaryEncoders[idx] = 1025;
}
for (int i = 0; i < CPN_MAX_GVARS; i++) {
gvars[i] = linkedGVarFlightModeZero(phaseIdx);
}
for (int i = 0; i < CPN_MAX_ENCODERS; i++) {
rotaryEncoders[i] = linkedREncFlightModeZero(phaseIdx);
}
}
QString FlightModeData::nameToString(int index) const
QString FlightModeData::nameToString(int phaseIdx) const
{
return RadioData::getElementName(tr("FM"), index, name); // names are zero-based, FM0, FM1, etc
return RadioData::getElementName(tr("FM"), phaseIdx, name); // names are zero-based, FM0, FM1, etc
}
void FlightModeData::convert(RadioDataConversionState & cstate)
@@ -150,3 +155,53 @@ void FlightModeData::convert(RadioDataConversionState & cstate)
cstate.setSubComp(nameToString(cstate.subCompIdx));
swtch.convert(cstate);
}
bool FlightModeData::isEmpty(int phaseIdx) const
{
if (name[0] != '\0' || swtch.isSet() || fadeIn != 0 || fadeOut != 0)
return false;
for (int i = 0; i < CPN_MAX_TRIMS; i++) {
if (trim[i] != 0 || trimRef[i] != 0 || trimMode[i] != 0)
return false;
}
for (int i = 0; i < CPN_MAX_GVARS; i++) {
if (!isGVarEmpty(phaseIdx, i))
return false;
}
for (int i = 0; i < CPN_MAX_ENCODERS; i++) {
if (!isREncEmpty(phaseIdx, i))
return false;
}
return true;
}
bool FlightModeData::isGVarEmpty(int phaseIdx, int gvIdx) const
{
if ((phaseIdx == 0 && gvars[gvIdx] == 0) || (phaseIdx != 0 && gvars[gvIdx] == linkedGVarFlightModeZero(phaseIdx)))
return true;
return false;
}
bool FlightModeData::isREncEmpty(int phaseIdx, int reIdx) const
{
if ((phaseIdx == 0 && rotaryEncoders[reIdx] == 0) || (phaseIdx != 0 && rotaryEncoders[reIdx] == linkedREncFlightModeZero(phaseIdx)))
return true;
return false;
}
int FlightModeData::linkedFlightModeZero(int phaseIdx, int maxOwnValue) const
{
if (phaseIdx == 0)
return 0;
return maxOwnValue + 1;
}
int FlightModeData::linkedGVarFlightModeZero(int phaseIdx) const
{
return linkedFlightModeZero(phaseIdx, GVAR_MAX_VALUE);
}
int FlightModeData::linkedREncFlightModeZero(int phaseIdx) const
{
return linkedFlightModeZero(phaseIdx, RENC_MAX_VALUE);
}
+25 -7
View File
@@ -37,6 +37,8 @@ enum InputMode {
INPUT_MODE_BOTH
};
#define EXPODATA_NAME_LEN 10
class ExpoData {
Q_DECLARE_TR_FUNCTIONS(ExpoData)
@@ -52,9 +54,10 @@ class ExpoData {
int offset;
CurveReference curve;
int carryTrim;
char name[10+1];
char name[EXPODATA_NAME_LEN+1];
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(ExpoData)); }
void convert(RadioDataConversionState & cstate);
bool isEmpty() const;
};
enum MltpxValue {
@@ -90,8 +93,11 @@ class MixData {
char name[MIXDATA_NAME_LEN+1];
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(MixData)); }
bool isEmpty() const;
};
#define LIMITDATA_NAME_LEN 6
class LimitData {
Q_DECLARE_TR_FUNCTIONS(LimitData)
@@ -103,7 +109,7 @@ class LimitData {
int offset;
int ppmCenter;
bool symetrical;
char name[6+1];
char name[LIMITDATA_NAME_LEN+1];
CurveReference curve;
QString minToString() const;
QString maxToString() const;
@@ -120,6 +126,8 @@ class CurvePoint {
int8_t y;
};
#define CURVEDATA_NAME_LEN 6
class CurveData {
Q_DECLARE_TR_FUNCTIONS(CurveData)
@@ -131,7 +139,7 @@ class CurveData {
};
CurveData();
void clear(int count);
void clear(int count = 5);
bool isEmpty() const;
QString nameToString(const int idx) const;
@@ -139,9 +147,13 @@ class CurveData {
bool smooth;
int count;
CurvePoint points[CPN_MAX_POINTS];
char name[6+1];
char name[CURVEDATA_NAME_LEN+1];
};
#define FLIGHTMODE_NAME_LEN 10
#define RENC_MAX_VALUE 1024
#define RENC_MIN_VALUE -RENC_MAX_VALUE
class FlightModeData {
Q_DECLARE_TR_FUNCTIONS(FlightModeData)
@@ -151,14 +163,20 @@ class FlightModeData {
int trimRef[CPN_MAX_TRIMS];
int trim[CPN_MAX_TRIMS];
RawSwitch swtch;
char name[10+1];
char name[FLIGHTMODE_NAME_LEN+1];
unsigned int fadeIn;
unsigned int fadeOut;
int rotaryEncoders[CPN_MAX_ENCODERS];
int gvars[CPN_MAX_GVARS];
void clear(const int phase);
QString nameToString(int index) const;
void clear(const int phaseIdx);
QString nameToString(int phaseIdx) const;
void convert(RadioDataConversionState & cstate);
bool isEmpty(int phaseIdx) const;
bool isGVarEmpty(int phaseIdx, int gvIdx) const;
bool isREncEmpty(int phaseIdx, int reIdx) const;
int linkedFlightModeZero(int phaseIdx, int maxOwnValue) const;
int linkedGVarFlightModeZero(int phaseIdx) const;
int linkedREncFlightModeZero(int phaseIdx) const;
};
class SwashRingData {
File diff suppressed because it is too large Load Diff
+106 -3
View File
@@ -76,6 +76,8 @@ class TimerData {
int pvalue;
void clear() { memset(reinterpret_cast<void *>(this), 0, sizeof(TimerData)); mode = RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); }
void convert(RadioDataConversionState & cstate);
bool isEmpty();
bool isModeOff() { return mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0); }
};
#define CPN_MAX_SCRIPTS 9
@@ -128,6 +130,8 @@ enum TrainerMode {
TRAINER_MODE_MULTI
};
#define INPUT_NAME_LEN 4
class ModelData {
Q_DECLARE_TR_FUNCTIONS(ModelData)
@@ -170,7 +174,7 @@ class ModelData {
MixData mixData[CPN_MAX_MIXERS];
LimitData limitData[CPN_MAX_CHNOUT];
char inputNames[CPN_MAX_INPUTS][4+1];
char inputNames[CPN_MAX_INPUTS][INPUT_NAME_LEN+1];
ExpoData expoData[CPN_MAX_EXPOS];
CurveData curves[CPN_MAX_CURVES];
@@ -219,11 +223,23 @@ class ModelData {
void setTrimValue(int phaseIdx, int trimIdx, int value);
bool isGVarLinked(int phaseIdx, int gvarIdx);
int getGVarFieldValue(int phaseIdx, int gvarIdx);
float getGVarFieldValuePrec(int phaseIdx, int gvarIdx);
bool isGVarLinkedCircular(int phaseIdx, int gvarIdx);
int getGVarValue(int phaseIdx, int gvarIdx);
float getGVarValuePrec(int phaseIdx, int gvarIdx);
int getGVarFlightModeIndex(const int phaseIdx, const int gvarIdx);
void setGVarFlightModeIndexToValue(const int phaseIdx, const int gvarIdx, const int useFmIdx);
bool isREncLinked(int phaseIdx, int reIdx);
bool isREncLinkedCircular(int phaseIdx, int reIdx);
int getREncValue(int phaseIdx, int reIdx);
int getREncFlightModeIndex(const int phaseIdx, const int reIdx);
void setREncFlightModeIndexToValue(const int phaseIdx, const int reIdx, const int useFmIdx);
ModelData removeGlobalVars();
int linkedFlightModeIndexToValue(const int phaseIdx, const int useFmIdx, const int maxOwnValue);
int linkedFlightModeValueToIndex(const int phaseIdx, const int val, const int maxOwnValue);
void clearMixes();
void clearInputs();
@@ -231,8 +247,95 @@ class ModelData {
bool isAvailable(const RawSwitch & swtch) const;
enum ReferenceUpdateAction {
REF_UPD_ACT_CLEAR,
REF_UPD_ACT_SHIFT,
REF_UPD_ACT_SWAP,
};
enum ReferenceUpdateType {
REF_UPD_TYPE_CHANNEL,
REF_UPD_TYPE_CURVE,
REF_UPD_TYPE_FLIGHT_MODE,
REF_UPD_TYPE_GLOBAL_VARIABLE,
REF_UPD_TYPE_INPUT,
REF_UPD_TYPE_LOGICAL_SWITCH,
REF_UPD_TYPE_SCRIPT,
REF_UPD_TYPE_SENSOR,
REF_UPD_TYPE_TIMER,
};
struct UpdateReferenceParams
{
ReferenceUpdateType type;
ReferenceUpdateAction action;
int index1;
int index2;
int shift;
UpdateReferenceParams() {}
UpdateReferenceParams(ReferenceUpdateType t, ReferenceUpdateAction a, int i1, int i2 = 0, int s = 0) :
type(t), action(a), index1(i1), index2(i2), shift(s) {}
};
int updateAllReferences(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2 = 0, const int shift = 0);
bool isExpoParent(const int index);
bool isExpoChild(const int index);
bool hasExpoChildren(const int index);
bool hasExpoSiblings(const int index);
void removeMix(const int idx);
protected:
void removeGlobalVar(int & var);
private:
QVector<UpdateReferenceParams> *updRefList = nullptr;
struct UpdateReferenceInfo
{
ReferenceUpdateType type;
ReferenceUpdateAction action;
int index1;
int index2;
int shift;
int updcnt;
int maxindex;
RawSourceType srcType;
RawSwitchType swtchType;
};
UpdateReferenceInfo updRefInfo;
int updateReference();
void appendUpdateReferenceParams(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2 = 0, const int shift = 0);
template <class R, typename T>
void updateTypeIndexRef(R & curref, const T type, const int idxAdj = 0, const bool defClear = true, const int defType = 0, const int defIndex = 0);
template <class R, typename T>
void updateTypeValueRef(R & curref, const T type, const int idxAdj = 0, const bool defClear = true, const int defType = 0, const int defValue = 0);
void updateAdjustRef(int & adj);
void updateAssignFunc(CustomFunctionData * cfd);
void updateCurveRef(CurveReference & crv);
void updateDestCh(MixData * md);
void updateLimitCurveRef(CurveReference & crv);
void updateFlightModeFlags(unsigned int & flags);
void updateTelemetryRef(unsigned int & idx);
void updateModuleFailsafes(ModuleData * md);
inline void updateSourceRef(RawSource & src) { updateTypeIndexRef<RawSource, RawSourceType>(src, updRefInfo.srcType); }
inline void updateSwitchRef(RawSwitch & swtch) { updateTypeIndexRef<RawSwitch, RawSwitchType>(swtch, updRefInfo.swtchType, 1); }
inline void updateTimerMode(RawSwitch & swtch) { updateTypeIndexRef<RawSwitch, RawSwitchType>(swtch, updRefInfo.swtchType, 1, false, (int)SWITCH_TYPE_TIMER_MODE, 0); }
inline void updateSourceIntRef(int & value)
{
RawSource src = RawSource(value);
updateTypeIndexRef<RawSource, RawSourceType>(src, updRefInfo.srcType);
if (value != src.toValue())
value = src.toValue();
}
inline void updateSwitchIntRef(int & value)
{
RawSwitch swtch = RawSwitch(value);
updateTypeIndexRef<RawSwitch, RawSwitchType>(swtch, updRefInfo.swtchType, 1);
if (value != swtch.toValue())
value = swtch.toValue();
}
};
#endif // MODELDATA_H
+56
View File
@@ -181,3 +181,59 @@ QStringList ModuleData::powerValueStrings(int subType, Firmware * fw)
strIdx += 2;
return strings[strIdx];
}
bool ModuleData::hasFailsafes(Firmware * fw) const
{
return fw->getCapability(HasFailsafe) && (
protocol == PULSES_ACCESS_ISRM ||
protocol == PULSES_ACCST_ISRM_D16 ||
protocol == PULSES_PXX_XJT_X16 ||
protocol == PULSES_PXX_R9M ||
protocol == PULSES_ACCESS_R9M ||
protocol == PULSES_ACCESS_R9M_LITE ||
protocol == PULSES_ACCESS_R9M_LITE_PRO ||
protocol == PULSES_XJT_LITE_X16 ||
protocol == PULSES_MULTIMODULE
);
}
int ModuleData::getMaxChannelCount()
{
switch (protocol) {
case PULSES_ACCESS_ISRM:
return 24;
case PULSES_PXX_R9M:
case PULSES_ACCESS_R9M:
case PULSES_ACCESS_R9M_LITE:
case PULSES_ACCESS_R9M_LITE_PRO:
case PULSES_ACCST_ISRM_D16:
case PULSES_XJT_LITE_X16:
case PULSES_PXX_XJT_X16:
case PULSES_CROSSFIRE:
case PULSES_SBUS:
case PULSES_PPM:
return 16;
case PULSES_XJT_LITE_LR12:
case PULSES_PXX_XJT_LR12:
return 12;
case PULSES_PXX_DJT:
case PULSES_XJT_LITE_D8:
case PULSES_PXX_XJT_D8:
return 8;
case PULSES_LP45:
case PULSES_DSM2:
case PULSES_DSMX:
return 6;
case PULSES_MULTIMODULE:
if (multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2)
return 12;
else
return 16;
break;
case PULSES_OFF:
break;
default:
break;
}
return 8;
}
+3 -1
View File
@@ -159,7 +159,7 @@ class ModuleData {
unsigned int modelId;
unsigned int protocol; // type in datastructs.h
int rfProtocol; // rfProtocol in datastructs.h
unsigned int subType;
bool invertedSerial;
unsigned int channelsStart;
@@ -207,6 +207,8 @@ class ModuleData {
static QString indexToString(int index, Firmware * fw);
static QString protocolToString(unsigned protocol);
static QStringList powerValueStrings(int subType, Firmware * fw);
bool hasFailsafes(Firmware * fw) const;
int getMaxChannelCount();
};
#endif // MODULEDATA_H
@@ -616,6 +616,10 @@ int OpenTxFirmware::getCapability(::Capability capability)
return 0;
else
return IS_ARM(board) ? 4 : 2;
case TelemetryCustomScreensBars:
return (getCapability(TelemetryCustomScreens) ? 4 : 0);
case TelemetryCustomScreensLines:
return (getCapability(TelemetryCustomScreens) ? 4 : 0);
case TelemetryCustomScreensFieldsPerLine:
return HAS_LARGE_LCD(board) ? 3 : 2;
case NoTelemetryProtocol:
@@ -754,6 +758,11 @@ int OpenTxFirmware::getCapability(::Capability capability)
return IS_TARANIS_XLITES(board);
case PwrButtonPress:
return IS_HORUS_OR_TARANIS(board) && (board!=Board::BOARD_TARANIS_X9D) && (board!=Board::BOARD_TARANIS_X9DP);
case Sensors:
if (IS_FAMILY_HORUS_OR_T16(board) || IS_TARANIS_X9(board))
return 60;
else
return 40;
default:
return 0;
}
+3 -5
View File
@@ -227,11 +227,7 @@ class RawSource {
AllSourceGroups = InputSourceGroups | GVarsGroup | TelemGroup | ScriptsGroup
};
RawSource():
type(SOURCE_TYPE_NONE),
index(0)
{
}
RawSource() { clear(); }
explicit RawSource(int value):
type(RawSourceType(abs(value)/65536)),
@@ -258,6 +254,8 @@ class RawSource {
bool isSlider(int * sliderIndex = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
bool isTimeBased(Board::Type board = Board::BOARD_UNKNOWN) const;
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
bool isSet() const { return type != SOURCE_TYPE_NONE || index != 0; }
void clear() { type = SOURCE_TYPE_NONE; index = 0; }
bool operator == ( const RawSource & other) const {
return (this->type == other.type) && (this->index == other.index);
+3 -6
View File
@@ -65,11 +65,7 @@ class RawSwitch {
AllSwitchContexts = AllModelContexts | GlobalFunctionsContext
};
RawSwitch():
type(SWITCH_TYPE_NONE),
index(0)
{
}
RawSwitch() { clear(); }
explicit RawSwitch(int value):
type(RawSwitchType(abs(value)/256)),
@@ -91,6 +87,8 @@ class RawSwitch {
RawSwitch convert(RadioDataConversionState & cstate);
QString toString(Board::Type board = Board::BOARD_UNKNOWN, const GeneralSettings * const generalSettings = NULL, const ModelData * const modelData = NULL) const;
bool isAvailable(const ModelData * const model = NULL, const GeneralSettings * const gs = NULL, Board::Type board = Board::BOARD_UNKNOWN) const;
bool isSet() const { return type != SWITCH_TYPE_NONE || index != 0; }
void clear() { type = SWITCH_TYPE_NONE; index = 0; }
bool operator== ( const RawSwitch& other) const {
return (this->type == other.type) && (this->index == other.index);
@@ -100,7 +98,6 @@ class RawSwitch {
return (this->type != other.type) || (this->index != other.index);
}
RawSwitchType type;
int index;
};
+92 -69
View File
@@ -120,7 +120,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
s1.report("header");
for (int i=0; i<chnCapability; i++) {
for (int i = 0; i < chnCapability; i++) {
int col = 0;
// Channel label
@@ -131,7 +131,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
label->setContextMenuPolicy(Qt::CustomContextMenu);
label->setToolTip(tr("Popup menu available"));
label->setMouseTracking(true);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(chn_customContextMenuRequested(QPoint)));
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint)));
tableLayout->addWidget(i, col++, label);
// Channel name
@@ -204,7 +204,7 @@ Channels::Channels(QWidget * parent, ModelData & model, GeneralSettings & genera
Channels::~Channels()
{
// compiler warning if delete[]
for (int i=0; i<CPN_MAX_CHNOUT;i++) {
for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
delete name[i];
delete chnOffset[i];
delete chnMin[i];
@@ -240,7 +240,7 @@ void Channels::refreshExtendedLimits()
{
int channelMax = model->getChannelsMax();
for (int i=0 ; i<CPN_MAX_CHNOUT; i++) {
for (int i = 0 ; i < CPN_MAX_CHNOUT; i++) {
chnOffset[i]->updateMinMax(10 * channelMax);
chnMin[i]->updateMinMax(10 * channelMax);
chnMax[i]->updateMinMax(10 * channelMax);
@@ -280,7 +280,7 @@ void Channels::ppmcenterEdited()
void Channels::update()
{
for (int i=0; i<chnCapability; i++) {
for (int i = 0; i < chnCapability; i++) {
updateLine(i);
}
}
@@ -298,7 +298,7 @@ void Channels::updateLine(int i)
if (IS_HORUS_OR_TARANIS(firmware->getBoard())) {
int numcurves = firmware->getCapability(NumCurves);
curveCB[i]->clear();
for (int j=-numcurves; j<=numcurves; j++) {
for (int j = -numcurves; j <= numcurves; j++) {
curveCB[i]->addItem(CurveReference(CurveReference::CURVE_REF_CUSTOM, j).toString(model, false), j);
}
curveCB[i]->setCurrentIndex(model->limitData[i].curve.value + numcurves);
@@ -312,118 +312,140 @@ void Channels::updateLine(int i)
lock = false;
}
void Channels::chnPaste()
void Channels::cmPaste()
{
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_CHN)) {
QByteArray chnData = mimeData->data(MIMETYPE_CHN);
LimitData *chn = &model->limitData[selectedChannel];
memcpy(chn, chnData.constData(), sizeof(LimitData));
updateLine(selectedChannel);
QByteArray data;
if (hasClipboardData(&data)) {
memcpy(&model->limitData[selectedIndex], data.constData(), sizeof(LimitData));
updateLine(selectedIndex);
emit modified();
}
}
void Channels::chnDelete()
void Channels::cmDelete()
{
int maxidx = chnCapability - 1;
for (int i=selectedChannel; i<maxidx; i++) {
if (!model->limitData[i].isEmpty() || !model->limitData[i+1].isEmpty()) {
LimitData *chn1 = &model->limitData[i];
LimitData *chn2 = &model->limitData[i+1];
memcpy(chn1, chn2, sizeof(LimitData));
updateLine(i);
}
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
memmove(&model->limitData[selectedIndex], &model->limitData[selectedIndex + 1], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData));
model->limitData[chnCapability - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
for (int i = selectedIndex; i < chnCapability; i++) {
updateLine(i);
}
model->limitData[maxidx].clear();
updateLine(maxidx);
emit modified();
}
void Channels::chnCopy()
void Channels::cmCopy()
{
QByteArray chnData;
chnData.append((char*)&model->limitData[selectedChannel],sizeof(LimitData));
QByteArray data;
data.append((char*)&model->limitData[selectedIndex], sizeof(LimitData));
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_CHN, chnData);
mimeData->setData(MIMETYPE_CHANNEL, data);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
}
void Channels::chnCut()
void Channels::cmCut()
{
chnCopy();
chnClear();
cmCopy();
cmClear();
}
void Channels::chn_customContextMenuRequested(QPoint pos)
void Channels::onCustomContextMenuRequested(QPoint pos)
{
QLabel *label = (QLabel *)sender();
selectedChannel = label->property("index").toInt();
selectedIndex = label->property("index").toInt();
QPoint globalPos = label->mapToGlobal(pos);
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat(MIMETYPE_CHN);
bool moveUpAllowed = (selectedChannel > 0);
bool moveDownAllowed = (selectedChannel < (chnCapability - 1));
bool insertAllowed = (selectedChannel < (chnCapability - 1)) && (model->limitData[chnCapability - 1].isEmpty());
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(chnCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(chnCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(chnPaste()))->setEnabled(hasData);
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(chnClear()));
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(cmPaste()))->setEnabled(hasClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(cmClear()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(chnInsert()))->setEnabled(insertAllowed);
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(chnDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(chnMoveUp()))->setEnabled(moveUpAllowed);
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(chnMoveDown()))->setEnabled(moveDownAllowed);
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(cmInsert()))->setEnabled(insertAllowed());
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(cmDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(cmMoveUp()))->setEnabled(moveUpAllowed());
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(cmMoveDown()))->setEnabled(moveDownAllowed());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(chnClearAll()));
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(cmClearAll()));
contextMenu.exec(globalPos);
}
void Channels::chnMoveUp()
bool Channels::hasClipboardData(QByteArray * data) const
{
swapChnData(selectedChannel, selectedChannel - 1);
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_CHANNEL)) {
if (data)
data->append(mimeData->data(MIMETYPE_CHANNEL));
return true;
}
return false;
}
void Channels::chnMoveDown()
bool Channels::insertAllowed() const
{
swapChnData(selectedChannel, selectedChannel + 1);
return ((selectedIndex < chnCapability - 1) && (model->limitData[chnCapability - 1].isEmpty()));
}
void Channels::chnClear()
bool Channels::moveDownAllowed() const
{
model->limitData[selectedChannel].clear();
updateLine(selectedChannel);
return selectedIndex < chnCapability - 1;
}
bool Channels::moveUpAllowed() const
{
return selectedIndex > 0;
}
void Channels::cmMoveUp()
{
swapData(selectedIndex, selectedIndex - 1);
}
void Channels::cmMoveDown()
{
swapData(selectedIndex, selectedIndex + 1);
}
void Channels::cmClear()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Channel. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
model->limitData[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
updateLine(selectedIndex);
emit modified();
}
void Channels::chnClearAll()
void Channels::cmClearAll()
{
for (int i=0; i<chnCapability; i++) {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Channels. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = 0; i < chnCapability; i++) {
model->limitData[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_CLEAR, i);
updateLine(i);
}
emit modified();
}
void Channels::chnInsert()
void Channels::cmInsert()
{
for (int i=(chnCapability - 1); i>selectedChannel; i--) {
if (!model->limitData[i].isEmpty() || !model->limitData[i-1].isEmpty()) {
memcpy(&model->limitData[i], &model->limitData[i-1], sizeof(LimitData));
updateLine(i);
}
}
chnClear();
memmove(&model->limitData[selectedIndex + 1], &model->limitData[selectedIndex], (CPN_MAX_CHNOUT - (selectedIndex + 1)) * sizeof(LimitData));
model->limitData[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
emit modified();
}
void Channels::swapChnData(int idx1, int idx2)
void Channels::swapData(int idx1, int idx2)
{
if ((idx1 != idx2) && (!model->limitData[idx1].isEmpty() || !model->limitData[idx2].isEmpty())) {
LimitData chntmp = model->limitData[idx2];
@@ -431,6 +453,7 @@ void Channels::swapChnData(int idx1, int idx2)
LimitData *chn2 = &model->limitData[idx2];
memcpy(chn2, chn1, sizeof(LimitData));
memcpy(chn1, &chntmp, sizeof(LimitData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_CHANNEL, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
updateLine(idx1);
updateLine(idx2);
emit modified();
+17 -13
View File
@@ -26,7 +26,7 @@
#include <QtCore>
constexpr char MIMETYPE_CHN[] = "application/x-companion-chn";
constexpr char MIMETYPE_CHANNEL[] = "application/x-companion-channel";
class GVarGroup;
@@ -68,19 +68,23 @@ class Channels : public ModelPanel
void ppmcenterEdited();
void update();
void updateLine(int index);
void chnDelete();
void chnCopy();
void chnPaste();
void chnCut();
void chnMoveUp();
void chnMoveDown();
void chnInsert();
void chnClear();
void chnClearAll();
void chn_customContextMenuRequested(QPoint pos);
void cmDelete();
void cmCopy();
void cmPaste();
void cmCut();
void cmMoveUp();
void cmMoveDown();
void cmInsert();
void cmClear();
void cmClearAll();
void onCustomContextMenuRequested(QPoint pos);
private:
void swapChnData(int idx1, int idx2);
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
QLineEdit *name[CPN_MAX_CHNOUT];
LimitsGroup *chnOffset[CPN_MAX_CHNOUT];
LimitsGroup *chnMin[CPN_MAX_CHNOUT];
@@ -89,7 +93,7 @@ class Channels : public ModelPanel
QComboBox *curveCB[CPN_MAX_CHNOUT];
QSpinBox *centerSB[CPN_MAX_CHNOUT];
QCheckBox *symlimitsChk[CPN_MAX_CHNOUT];
int selectedChannel;
int selectedIndex;
int chnCapability;
};
+213 -128
View File
@@ -117,7 +117,12 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
lock = true;
if (!firmware->getCapability(HasCvNames)) {
maxCurves = firmware->getCapability(NumCurves);
hasNames = firmware->getCapability(HasCvNames);
hasEnhanced = firmware->getCapability(EnhancedCurves);
maxPoints = firmware->getCapability(NumCurvePoints);
if (!hasNames) {
ui->curveName->hide();
ui->curveNameLabel->hide();
}
@@ -127,14 +132,14 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
connect(scene, SIGNAL(newPoint(int, int)), this, SLOT(onSceneNewPoint(int, int)));
ui->curvePreview->setScene(scene);
int numcurves=firmware->getCapability(NumCurves);
int limit;
if (numcurves>16) {
limit=numcurves/2;
if (maxCurves > 16) {
limit = maxCurves / 2;
} else {
limit=numcurves;
limit = maxCurves;
}
for (int i=0; i<numcurves; i++) {
for (int i = 0; i < maxCurves; i++) {
visibleCurves[i] = false;
// The edit curve button
@@ -151,15 +156,15 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
edit->setStyleSheet(QString("background-color: %1; color: white; padding: 2px 3px; border-style: outset; border-width: 1px; border-radius: 2px; border-color: inherit;").arg(colors[i].name()));
#endif
edit->setPalette(palette);
edit->setText(tr("Curve %1").arg(i+1));
edit->setText(tr("Curve %1").arg(i + 1));
edit->setContextMenuPolicy(Qt::CustomContextMenu);
edit->setToolTip(tr("Popup menu available"));
connect(edit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&)));
connect(edit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onCustomContextMenuRequested(const QPoint&)));
connect(edit, SIGNAL(clicked()), this, SLOT(editCurve()));
if (i<limit) {
if (i < limit) {
ui->curvesLayout->addWidget(edit, i, 1, 1, 1);
} else {
ui->curvesLayout2->addWidget(edit, i-limit, 2, 1, 1);
ui->curvesLayout2->addWidget(edit, i - limit, 2, 1, 1);
}
// The curve plot checkbox
@@ -167,7 +172,7 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
plot->setProperty("index", i);
plot->setPalette(palette);
connect(plot, SIGNAL(toggled(bool)), this, SLOT(plotCurve(bool)));
if (i<limit) {
if (i < limit) {
ui->curvesLayout->addWidget(plot, i, 2, 1, 1);
} else {
ui->curvesLayout2->addWidget(plot, i-limit, 1, 1, 1);
@@ -175,13 +180,13 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
}
QSpacerItem * item = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding);
ui->curvesLayout->addItem(item,limit+1,1,1,1,0);
if (limit!=numcurves) {
ui->curvesLayout->addItem(item,limit + 1, 1, 1, 1, 0);
if (limit != maxCurves) {
QSpacerItem * item2 = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding);
ui->curvesLayout2->addItem(item2,limit+1,1,1,1,0);
ui->curvesLayout2->addItem(item2,limit + 1, 1, 1, 1, 0);
}
for (int i=0; i<CPN_MAX_POINTS; i++) {
for (int i = 0; i < CPN_MAX_POINTS; i++) {
spnx[i] = new QSpinBox(this);
spnx[i]->setProperty("index", i);
spnx[i]->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
@@ -199,14 +204,14 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
ui->pointsLayout->addWidget(spny[i], i, 1, 1, 1);
bool insert;
if (firmware->getCapability(EnhancedCurves)) {
if (hasEnhanced) {
insert = (i >= 1);
}
else {
insert = (i==2 || i==4 || i==8 || i==16);
insert = (i == 2 || i == 4 || i ==8 || i == 16);
}
if (insert) {
ui->curvePoints->addItem(tr("%1 points").arg(i+1), i+1);
ui->curvePoints->addItem(tr("%1 points").arg(i + 1), i + 1);
}
}
@@ -250,7 +255,7 @@ void Curves::update()
{
lock = true;
if (firmware->getCapability(HasCvNames)) {
if (hasNames) {
ui->curveName->setText(model->curves[currentCurve].name);
}
@@ -272,7 +277,7 @@ void Curves::updateCurveType()
int index = 0;
if (firmware->getCapability(EnhancedCurves)) {
if (hasEnhanced) {
index = model->curves[currentCurve].count - 2;
}
else {
@@ -305,35 +310,34 @@ void Curves::updateCurve()
qreal width = scene->sceneRect().width();
qreal height = scene->sceneRect().height();
qreal centerX = scene->sceneRect().left() + width/2;
qreal centerY = scene->sceneRect().top() + height/2;
qreal centerX = scene->sceneRect().left() + width / 2;
qreal centerY = scene->sceneRect().top() + height / 2;
QGraphicsSimpleTextItem *ti = scene->addSimpleText(tr("Editing curve %1").arg(currentCurve+1));
QGraphicsSimpleTextItem *ti = scene->addSimpleText(tr("Editing curve %1").arg(currentCurve + 1));
ti->setPos(3, 3);
scene->addLine(centerX, GFX_MARGIN, centerX, height+GFX_MARGIN);
scene->addLine(GFX_MARGIN, centerY, width+GFX_MARGIN, centerY);
scene->addLine(centerX, GFX_MARGIN, centerX, height + GFX_MARGIN);
scene->addLine(GFX_MARGIN, centerY, width + GFX_MARGIN, centerY);
QPen pen;
pen.setWidth(1);
pen.setStyle(Qt::SolidLine);
int numcurves = firmware->getCapability(NumCurves);
for (int k=0; k<numcurves; k++) {
for (int k = 0; k < maxCurves; k++) {
pen.setColor(colors[k]);
if (currentCurve!=k && visibleCurves[k]) {
if (currentCurve != k && visibleCurves[k]) {
int numpoints = model->curves[k].count;
for (int i=0; i<numpoints-1; i++) {
for (int i = 0; i < numpoints - 1; i++) {
if (model->curves[k].type == CurveData::CURVE_TYPE_CUSTOM)
scene->addLine(centerX + (qreal)model->curves[k].points[i].x*width/200,centerY - (qreal)model->curves[k].points[i].y*height/200,centerX + (qreal)model->curves[k].points[i+1].x*width/200,centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen);
scene->addLine(centerX + (qreal)model->curves[k].points[i].x*width/200, centerY - (qreal)model->curves[k].points[i].y*height/200,centerX + (qreal)model->curves[k].points[i+1].x*width/200,centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen);
else
scene->addLine(GFX_MARGIN + i*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i].y*height/200,GFX_MARGIN + (i+1)*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen);
scene->addLine(GFX_MARGIN + i*width/(numpoints-1), centerY - (qreal)model->curves[k].points[i].y*height/200,GFX_MARGIN + (i+1)*width/(numpoints-1),centerY - (qreal)model->curves[k].points[i+1].y*height/200, pen);
}
}
}
int numpoints = model->curves[currentCurve].count;
for (int i=0; i<numpoints; i++) {
for (int i = 0; i < numpoints; i++) {
nodel = nodex;
nodex = new Node();
nodex->setProperty("index", i);
@@ -341,26 +345,27 @@ void Curves::updateCurve()
nodex->setBallSize(ui->pointSize->value());
nodex->setBallHeight(0);
if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) {
if (i>0 && i<numpoints-1) {
if (i > 0 && i < numpoints - 1) {
nodex->setFixedX(false);
nodex->setMinX(model->curves[currentCurve].points[i-1].x);
nodex->setMaxX(model->curves[currentCurve].points[i+1].x);
nodex->setMinX(model->curves[currentCurve].points[i - 1].x);
nodex->setMaxX(model->curves[currentCurve].points[i + 1].x);
}
else {
nodex->setFixedX(true);
}
nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x*width/200,centerY - (qreal)model->curves[currentCurve].points[i].y*height/200);
nodex->setPos(centerX + (qreal)model->curves[currentCurve].points[i].x * width / 200, centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
}
else {
nodex->setFixedX(true);
nodex->setPos(GFX_MARGIN + i*width/(numpoints-1), centerY - (qreal)model->curves[currentCurve].points[i].y*height/200);
nodex->setPos(GFX_MARGIN + i * width / (numpoints - 1), centerY - (qreal)model->curves[currentCurve].points[i].y * height / 200);
}
connect(nodex, SIGNAL(moved(int, int)), this, SLOT(onNodeMoved(int, int)));
connect(nodex, SIGNAL(focus()), this, SLOT(onNodeFocus()));
connect(nodex, SIGNAL(unfocus()), this, SLOT(onNodeUnfocus()));
connect(nodex, SIGNAL(deleteMe()), this, SLOT(onNodeDelete()));
scene->addItem(nodex);
if (i>0) scene->addItem(new Edge(nodel, nodex));
if (i > 0)
scene->addItem(new Edge(nodel, nodex));
}
lock = false;
@@ -371,20 +376,20 @@ void Curves::updateCurvePoints()
lock = true;
int count = model->curves[currentCurve].count;
for (int i=0; i<count; i++) {
for (int i = 0; i < count; i++) {
spny[i]->show();
spny[i]->setValue(model->curves[currentCurve].points[i].y);
if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM) {
spnx[i]->show();
if (i==0 || i==model->curves[currentCurve].count-1) {
if (i == 0 || i == model->curves[currentCurve].count - 1) {
spnx[i]->setDisabled(true);
spnx[i]->setMaximum(+100);
spnx[i]->setMinimum(-100);
}
else {
spnx[i]->setDisabled(false);
spnx[i]->setMaximum(model->curves[currentCurve].points[i+1].x);
spnx[i]->setMinimum(model->curves[currentCurve].points[i-1].x);
spnx[i]->setMaximum(model->curves[currentCurve].points[i + 1].x);
spnx[i]->setMinimum(model->curves[currentCurve].points[i - 1].x);
}
spnx[i]->setValue(model->curves[currentCurve].points[i].x);
}
@@ -392,7 +397,7 @@ void Curves::updateCurvePoints()
spnx[i]->hide();
}
}
for (int i=count; i<CPN_MAX_POINTS; i++) {
for (int i = count; i < CPN_MAX_POINTS; i++) {
spny[i]->hide();
spnx[i]->hide();
}
@@ -421,9 +426,9 @@ void Curves::onNodeMoved(int x, int y)
spnx[index]->setValue(x);
spny[index]->setValue(y);
if (index > 0)
spnx[index-1]->setMaximum(x);
if (index < model->curves[currentCurve].count-1)
spnx[index+1]->setMinimum(x);
spnx[index - 1]->setMaximum(x);
if (index < model->curves[currentCurve].count - 1)
spnx[index + 1]->setMinimum(x);
emit modified();
lock = false;
}
@@ -444,17 +449,14 @@ void Curves::onNodeUnfocus()
bool Curves::allowCurveType(int points, CurveData::CurveType type)
{
int numcurves = firmware->getCapability(NumCurves);
int totalpoints = 0;
for (int i=0; i<numcurves; i++) {
int cvPoints = (i==currentCurve ? points : model->curves[i].count);
CurveData::CurveType cvType = (i==currentCurve ? type : model->curves[i].type);
totalpoints += cvPoints + (cvType==CurveData::CURVE_TYPE_CUSTOM ? cvPoints-2 : 0);
for (int i = 0; i < maxCurves; i++) {
int cvPoints = (i == currentCurve ? points : model->curves[i].count);
CurveData::CurveType cvType = (i == currentCurve ? type : model->curves[i].type);
totalpoints += cvPoints + (cvType == CurveData::CURVE_TYPE_CUSTOM ? cvPoints - 2 : 0);
}
int fwpoints = firmware->getCapability(NumCurvePoints);
if (totalpoints > fwpoints) {
if (totalpoints > maxPoints) {
QMessageBox::warning(this, "companion", tr("Not enough free points in EEPROM to store the curve."));
return false;
}
@@ -472,8 +474,8 @@ void Curves::on_curvePoints_currentIndexChanged(int index)
model->curves[currentCurve].count = numpoints;
// TODO something better + reuse!
for (int i=0; i<CPN_MAX_POINTS; i++) {
model->curves[currentCurve].points[i].x = (i >= numpoints-1 ? +100 : -100 + (200*i)/(numpoints-1));
for (int i = 0; i < CPN_MAX_POINTS; i++) {
model->curves[currentCurve].points[i].x = (i >= numpoints - 1 ? +100 : -100 + (200 * i) / (numpoints - 1));
model->curves[currentCurve].points[i].y = 0;
}
@@ -491,12 +493,13 @@ void Curves::on_curveCustom_currentIndexChanged(int index)
if (!lock) {
CurveData::CurveType type = (CurveData::CurveType)index;
int numpoints = ui->curvePoints->itemData(ui->curvePoints->currentIndex()).toInt();
if (allowCurveType(model->curves[currentCurve].count, type)) {
model->curves[currentCurve].type = type;
// TODO something better + reuse!
for (int i=0; i<CPN_MAX_POINTS; i++) {
model->curves[currentCurve].points[i].x = (i >= numpoints-1 ? +100 : -100 + (200*i)/(numpoints-1));
for (int i = 0; i < CPN_MAX_POINTS; i++) {
model->curves[currentCurve].points[i].x = (i >= numpoints - 1 ? +100 : -100 + (200 * i) / (numpoints - 1));
model->curves[currentCurve].points[i].y = 0;
}
@@ -525,7 +528,7 @@ void Curves::on_curveName_editingFinished()
void Curves::resizeEvent(QResizeEvent *event)
{
QRect qr = ui->curvePreview->contentsRect();
ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width()-GFX_MARGIN*2, qr.height()-GFX_MARGIN*2);
ui->curvePreview->scene()->setSceneRect(GFX_MARGIN, GFX_MARGIN, qr.width() - GFX_MARGIN * 2, qr.height() - GFX_MARGIN * 2);
updateCurve();
ModelPanel::resizeEvent(event);
}
@@ -559,12 +562,12 @@ void Curves::on_curveApply_clicked()
int index = ui->curveType->currentIndex();
int numpoints = model->curves[currentCurve].count;
for (int i=0; i<numpoints; i++) {
for (int i = 0; i < numpoints; i++) {
float x;
if (model->curves[currentCurve].type == CurveData::CURVE_TYPE_CUSTOM)
x = model->curves[currentCurve].points[i].x;
else
x = -100.0 + (200.0/(numpoints-1))*i;
x = -100.0 + (200.0 / (numpoints - 1)) * i;
bool apply = false;
switch (ui->curveSide->currentIndex()) {
@@ -572,11 +575,11 @@ void Curves::on_curveApply_clicked()
apply = true;
break;
case 1:
if (x>=0)
if (x >= 0)
apply = true;
break;
case 2:
if (x<0)
if (x < 0)
apply = true;
break;
}
@@ -591,68 +594,6 @@ void Curves::on_curveApply_clicked()
emit modified();
}
void Curves::ShowContextMenu(const QPoint& pos) // this is a slot
{
QPushButton *button = (QPushButton *)sender();
int index = button->property("index").toInt();
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
QPoint globalPos = button->mapToGlobal(pos);
QMenu myMenu;
QAction *action;
action = myMenu.addAction(CompanionIcon("copy.png"),tr("Copy"));
action->setProperty("index", CURVE_COPY);
action = myMenu.addAction(CompanionIcon("paste.png"),tr("Paste"));
if (!mimeData->hasFormat("application/x-companion-curve-item")) {
action->setEnabled(false);
}
action->setProperty("index", CURVE_PASTE);
action = myMenu.addAction(CompanionIcon("clear.png"),tr("Clear"));
action->setProperty("index", CURVE_RESET);
action = myMenu.addAction(CompanionIcon("clear.png"),tr("Clear all curves"));
action->setProperty("index", CURVE_RESETALL);
QAction* selectedItem = myMenu.exec(globalPos);
if (selectedItem) {
int action=selectedItem->property("index").toInt();
if (action==CURVE_COPY) {
QByteArray curveData;
QMimeData *mimeData2 = new QMimeData;
curveData.append((char*)&model->curves[index], sizeof(CurveData));
mimeData2->setData("application/x-companion-curve-item", curveData);
QApplication::clipboard()->setMimeData(mimeData2, QClipboard::Clipboard);
}
else if (action==CURVE_PASTE) {
QByteArray curveData = mimeData->data("application/x-companion-curve-item");
CurveData *curve = &model->curves[index];
memcpy(curve, curveData.constData(), sizeof(CurveData));
update();
emit modified();
}
else if (action==CURVE_RESET) {
int res = QMessageBox::question(this, "companion", tr("Are you sure you want to reset curve %1?").arg(index+1), QMessageBox::Yes | QMessageBox::No);
if (res == QMessageBox::Yes) {
model->curves[index].clear(5);
update();
emit modified();
}
}
else if (action==CURVE_RESETALL) {
int res = QMessageBox::question(this, "companion", tr("Are you sure you want to reset all curves?"), QMessageBox::Yes | QMessageBox::No);
if (res == QMessageBox::Yes) {
int numcurves = firmware->getCapability(NumCurves);
for (int i=0; i<numcurves; i++) {
model->curves[i].clear(5);
}
update();
emit modified();
}
}
}
}
void Curves::onPointSizeEdited()
{
if (!lock) {
@@ -690,7 +631,7 @@ void Curves::onSceneNewPoint(int x, int y)
newidx = numpoints;
}
else {
for (int i=0; i<numpoints; i++) {
for (int i = 0; i < numpoints; i++) {
if (x < model->curves[currentCurve].points[i].x) {
newidx = i;
break;
@@ -699,8 +640,8 @@ void Curves::onSceneNewPoint(int x, int y)
}
numpoints++;
model->curves[currentCurve].count = numpoints;
for (int idx=(numpoints-1); idx>(newidx); idx--) {
model->curves[currentCurve].points[idx] = model->curves[currentCurve].points[idx-1];
for (int idx = (numpoints - 1); idx > newidx; idx--) {
model->curves[currentCurve].points[idx] = model->curves[currentCurve].points[idx - 1];
}
model->curves[currentCurve].points[newidx].x = x;
model->curves[currentCurve].points[newidx].y = y;
@@ -709,6 +650,150 @@ void Curves::onSceneNewPoint(int x, int y)
}
}
void Curves::onCustomContextMenuRequested(QPoint pos)
{
QPushButton *button = (QPushButton *)sender();
selectedIndex = button->property("index").toInt();
QPoint globalPos = button->mapToGlobal(pos);
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"), this, SLOT(cmPaste()))->setEnabled(hasClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmClear()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(cmInsert()))->setEnabled(insertAllowed());
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(cmDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(cmMoveUp()))->setEnabled(moveUpAllowed());
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(cmMoveDown()))->setEnabled(moveDownAllowed());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"), this, SLOT(cmClearAll()));
contextMenu.exec(globalPos);
}
bool Curves::hasClipboardData(QByteArray * data) const
{
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_CURVE)) {
if (data)
data->append(mimeData->data(MIMETYPE_CURVE));
return true;
}
return false;
}
bool Curves::insertAllowed() const
{
return ((selectedIndex < maxCurves - 1) && (model->curves[maxCurves - 1].isEmpty()));
}
bool Curves::moveDownAllowed() const
{
return selectedIndex < maxCurves - 1;
}
bool Curves::moveUpAllowed() const
{
return selectedIndex > 0;
}
void Curves::cmClear()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
update();
emit modified();
}
void Curves::cmClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Curves. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = 0; i < maxCurves; i++) {
model->curves[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_CLEAR, i);
}
update();
emit modified();
}
void Curves::cmCopy()
{
QByteArray data;
data.append((char*)&model->curves[selectedIndex], sizeof(CurveData));
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_CURVE, data);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
}
void Curves::cmCut()
{
cmCopy();
cmClear();
}
void Curves::cmDelete()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Curve. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
memmove(&model->curves[selectedIndex], &model->curves[selectedIndex + 1], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData));
model->curves[maxCurves - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update();
emit modified();
}
void Curves::cmInsert()
{
memmove(&model->curves[selectedIndex + 1], &model->curves[selectedIndex], (CPN_MAX_CURVES - (selectedIndex + 1)) * sizeof(CurveData));
model->curves[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
emit modified();
}
void Curves::cmMoveDown()
{
swapData(selectedIndex, selectedIndex + 1);
}
void Curves::cmMoveUp()
{
swapData(selectedIndex, selectedIndex - 1);
}
void Curves::cmPaste()
{
QByteArray data;
if (hasClipboardData(&data)) {
CurveData *cd = &model->curves[selectedIndex];
memcpy(cd, data.constData(), sizeof(CurveData));
update();
emit modified();
}
}
void Curves::swapData(int idx1, int idx2)
{
if ((idx1 != idx2) && (!model->curves[idx1].isEmpty() || !model->curves[idx2].isEmpty())) {
CurveData cdtmp = model->curves[idx2];
CurveData *cd1 = &model->curves[idx1];
CurveData *cd2 = &model->curves[idx2];
memcpy(cd2, cd1, sizeof(CurveData));
memcpy(cd1, &cdtmp, sizeof(CurveData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_CURVE, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update();
emit modified();
}
}
CustomScene::CustomScene(QGraphicsView * view) :
QGraphicsScene(view)
{
+21 -7
View File
@@ -26,12 +26,7 @@
#include <QGraphicsScene>
#include <QGraphicsView>
enum CopyAction {
CURVE_COPY,
CURVE_PASTE,
CURVE_RESET,
CURVE_RESETALL
};
constexpr char MIMETYPE_CURVE[] = "application/x-companion-curve";
namespace Ui {
class Curves;
@@ -71,7 +66,6 @@ class Curves : public ModelPanel
private slots:
void editCurve();
void ShowContextMenu(const QPoint& pos);
void plotCurve(bool checked);
void on_curveName_editingFinished();
void on_curvePoints_currentIndexChanged(int index);
@@ -86,6 +80,16 @@ class Curves : public ModelPanel
void onSceneNewPoint(int x, int y);
void onPointSizeEdited();
void onNodeDelete();
void onCustomContextMenuRequested(QPoint pos);
void cmClear();
void cmClearAll();
void cmCopy();
void cmCut();
void cmDelete();
void cmInsert();
void cmPaste();
void cmMoveDown();
void cmMoveUp();
protected:
virtual void resizeEvent(QResizeEvent *event);
@@ -105,6 +109,16 @@ class Curves : public ModelPanel
bool allowCurveType(int points, CurveData::CurveType type);
void setPointY(int i, int x, int y);
CustomScene * scene;
int maxCurves;
int hasNames;
int hasEnhanced;
int maxPoints;
int selectedIndex;
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
};
#endif // _CURVES_H_
+81 -62
View File
@@ -127,7 +127,7 @@ CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model,
else
label->setText(tr("GF%1").arg(i+1));
label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(fsw_customContextMenuRequested(QPoint)));
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint)));
tableLayout->addWidget(i, 0, label);
// s1.report("label");
@@ -608,76 +608,63 @@ void CustomFunctionsPanel::update()
lock = false;
}
void CustomFunctionsPanel::fswPaste()
void CustomFunctionsPanel::cmPaste()
{
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_FSW)) {
QByteArray fswData = mimeData->data(MIMETYPE_FSW);
CustomFunctionData *fsw = &functions[selectedFunction];
memcpy(fsw, fswData.constData(), sizeof(CustomFunctionData));
resetCBsAndRefresh(selectedFunction);
QByteArray data;
if (hasClipboardData(&data)) {
memcpy(&functions[selectedIndex], data.constData(), sizeof(CustomFunctionData));
resetCBsAndRefresh(selectedIndex);
emit modified();
}
}
void CustomFunctionsPanel::fswDelete()
void CustomFunctionsPanel::cmDelete()
{
int maxidx = fswCapability - 1;
for (int i=selectedFunction; i<maxidx; i++) {
if (!functions[i].isEmpty() || !functions[i+1].isEmpty()) {
CustomFunctionData *fsw1 = &functions[i];
CustomFunctionData *fsw2 = &functions[i+1];
memcpy(fsw1, fsw2, sizeof(CustomFunctionData));
resetCBsAndRefresh(i);
}
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Special Function. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
memmove(&functions[selectedIndex], &functions[selectedIndex + 1], (CPN_MAX_SPECIAL_FUNCTIONS - (selectedIndex + 1)) * sizeof(CustomFunctionData));
functions[fswCapability - 1].clear();
for (int i = selectedIndex; i < (fswCapability - 1); i++) {
resetCBsAndRefresh(i);
}
functions[maxidx].clear();
resetCBsAndRefresh(maxidx);
emit modified();
}
void CustomFunctionsPanel::fswCopy()
void CustomFunctionsPanel::cmCopy()
{
QByteArray fswData;
fswData.append((char*)&functions[selectedFunction], sizeof(CustomFunctionData));
QByteArray data;
data.append((char*)&functions[selectedIndex], sizeof(CustomFunctionData));
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_FSW, fswData);
mimeData->setData(MIMETYPE_CUSTOM_FUNCTION, data);
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
void CustomFunctionsPanel::fswCut()
void CustomFunctionsPanel::cmCut()
{
fswCopy();
fswClear();
cmCopy();
cmClear();
}
void CustomFunctionsPanel::fsw_customContextMenuRequested(QPoint pos)
void CustomFunctionsPanel::onCustomContextMenuRequested(QPoint pos)
{
QLabel *label = (QLabel *)sender();
selectedFunction = label->property("index").toInt();
selectedIndex = label->property("index").toInt();
QPoint globalPos = label->mapToGlobal(pos);
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat(MIMETYPE_FSW);
bool moveUpAllowed = (selectedFunction > 0);
bool moveDownAllowed = (selectedFunction < (fswCapability - 1));
bool insertAllowed = (selectedFunction < (fswCapability - 1)) && (functions[fswCapability - 1].isEmpty());
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(fswCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(fswCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(fswPaste()))->setEnabled(hasData);
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(fswClear()));
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(cmPaste()))->setEnabled(hasClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(cmClear()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(fswInsert()))->setEnabled(insertAllowed);
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(fswDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(fswMoveUp()))->setEnabled(moveUpAllowed);
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(fswMoveDown()))->setEnabled(moveDownAllowed);
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(cmInsert()))->setEnabled(insertAllowed());
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(cmDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(cmMoveUp()))->setEnabled(moveUpAllowed());
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(cmMoveDown()))->setEnabled(moveDownAllowed());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(fswClearAll()));
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(cmClearAll()));
contextMenu.exec(globalPos);
}
@@ -762,25 +749,31 @@ void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsi
}
}
void CustomFunctionsPanel::fswMoveUp()
void CustomFunctionsPanel::cmMoveUp()
{
swapFuncData(selectedFunction, selectedFunction - 1);
swapData(selectedIndex, selectedIndex - 1);
}
void CustomFunctionsPanel::fswMoveDown()
void CustomFunctionsPanel::cmMoveDown()
{
swapFuncData(selectedFunction, selectedFunction + 1);
swapData(selectedIndex, selectedIndex + 1);
}
void CustomFunctionsPanel::fswClear()
void CustomFunctionsPanel::cmClear()
{
functions[selectedFunction].clear();
resetCBsAndRefresh(selectedFunction);
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Special Function. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
functions[selectedIndex].clear();
resetCBsAndRefresh(selectedIndex);
emit modified();
}
void CustomFunctionsPanel::fswClearAll()
void CustomFunctionsPanel::cmClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Special Functions. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i=0; i<fswCapability; i++) {
functions[i].clear();
resetCBsAndRefresh(i);
@@ -788,18 +781,17 @@ void CustomFunctionsPanel::fswClearAll()
emit modified();
}
void CustomFunctionsPanel::fswInsert()
void CustomFunctionsPanel::cmInsert()
{
for (int i=(fswCapability - 1); i>selectedFunction; i--) {
if (!functions[i].isEmpty() || !functions[i-1].isEmpty()) {
memcpy(&functions[i], &functions[i-1], sizeof(CustomFunctionData));
resetCBsAndRefresh(i);
}
memmove(&functions[selectedIndex + 1], &functions[selectedIndex], (CPN_MAX_SPECIAL_FUNCTIONS - (selectedIndex + 1)) * sizeof(CustomFunctionData));
functions[selectedIndex].clear();
for (int i = selectedIndex; i < (fswCapability - 1); i++) {
resetCBsAndRefresh(i);
}
fswClear();
}
void CustomFunctionsPanel::swapFuncData(int idx1, int idx2)
void CustomFunctionsPanel::swapData(int idx1, int idx2)
{
if ((idx1 != idx2) && (!functions[idx1].isEmpty() || !functions[idx2].isEmpty())) {
CustomFunctionData fswtmp = functions[idx2];
@@ -823,3 +815,30 @@ void CustomFunctionsPanel::resetCBsAndRefresh(int idx)
refreshCustomFunction(idx);
lock = false;
}
bool CustomFunctionsPanel::hasClipboardData(QByteArray * data) const
{
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_CUSTOM_FUNCTION)) {
if (data)
data->append(mimeData->data(MIMETYPE_CUSTOM_FUNCTION));
return true;
}
return false;
}
bool CustomFunctionsPanel::insertAllowed() const
{
return ((selectedIndex < fswCapability - 1) && (model->curves[fswCapability - 1].isEmpty()));
}
bool CustomFunctionsPanel::moveDownAllowed() const
{
return selectedIndex < fswCapability - 1;
}
bool CustomFunctionsPanel::moveUpAllowed() const
{
return selectedIndex > 0;
}
+17 -13
View File
@@ -30,7 +30,7 @@ class RawSourceFilterItemModel;
class RawSwitchFilterItemModel;
class TimerEdit;
constexpr char MIMETYPE_FSW[] = "application/x-companion-fsw";
constexpr char MIMETYPE_CUSTOM_FUNCTION[] = "application/x-companion-custom-function";
class RepeatComboBox: public QComboBox
{
@@ -67,7 +67,7 @@ class CustomFunctionsPanel : public GenericPanel
void updateDataModels();
void customFunctionEdited();
void functionEdited();
void fsw_customContextMenuRequested(QPoint pos);
void onCustomContextMenuRequested(QPoint pos);
void refreshCustomFunction(int index, bool modified=false);
void onChildModified();
bool playSound(int index);
@@ -75,21 +75,25 @@ class CustomFunctionsPanel : public GenericPanel
void toggleSound(bool play);
void onMediaPlayerStateChanged(QMediaPlayer::State state);
void onMediaPlayerError(QMediaPlayer::Error error);
void fswDelete();
void fswCopy();
void fswPaste();
void fswCut();
void fswMoveUp();
void fswMoveDown();
void fswInsert();
void fswClear();
void fswClearAll();
void cmDelete();
void cmCopy();
void cmPaste();
void cmCut();
void cmMoveUp();
void cmMoveDown();
void cmInsert();
void cmClear();
void cmClearAll();
private:
void populateFuncCB(QComboBox *b, unsigned int value);
void populateGVmodeCB(QComboBox *b, unsigned int value);
void populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode=0);
void swapFuncData(int idx1, int idx2);
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
void resetCBsAndRefresh(int idx);
RawSwitchFilterItemModel * rawSwitchItemModel;
RawSourceFilterItemModel * rawSrcAllItemModel;
@@ -113,7 +117,7 @@ class CustomFunctionsPanel : public GenericPanel
QSlider * fswtchBLcolor[CPN_MAX_SPECIAL_FUNCTIONS];
QMediaPlayer * mediaPlayer;
int selectedFunction;
int selectedIndex;
int fswCapability;
};
File diff suppressed because it is too large Load Diff
+42 -4
View File
@@ -26,6 +26,10 @@
class RawSwitchFilterItemModel;
constexpr char MIMETYPE_FLIGHTMODE[] = "application/x-companion-flightmode";
constexpr char MIMETYPE_GVAR_PARAMS[] = "application/x-companion-gvar-params";
constexpr char MIMETYPE_GVAR_VALUE[] = "application/x-companion-gvar-value";
namespace Ui {
class FlightMode;
}
@@ -42,6 +46,7 @@ class FlightModePanel : public ModelPanel
signals:
void nameModified();
void datachanged();
private slots:
void phaseName_editingFinished();
@@ -61,18 +66,36 @@ class FlightModePanel : public ModelPanel
void phaseGVMax_editingFinished();
void phaseREValue_editingFinished();
void phaseREUse_currentIndexChanged(int index);
void name_customContextMenuRequested(const QPoint & pos);
void fmClear();
void gvLabel_customContextMenuRequested(const QPoint & pos);
void gvClear();
void onCustomContextMenuRequested(QPoint pos);
void cmClear();
void cmClearAll();
void cmCopy();
void cmCut();
void cmDelete();
void cmInsert();
void cmPaste();
void cmMoveDown();
void cmMoveUp();
void gvOnCustomContextMenuRequested(QPoint pos);
void gvCmClear();
void gvCmClearAll();
void gvCmCopy();
void gvCmCut();
void gvCmDelete();
void gvCmInsert();
void gvCmPaste();
void gvCmMoveDown();
void gvCmMoveUp();
private:
Ui::FlightMode *ui;
int phaseIdx;
FlightModeData & phase;
int fmCount;
int reCount;
int gvCount;
int gvIdx;
int trimCount;
QVector<QLabel *> trimsLabel;
QLineEdit * gvNames[CPN_MAX_GVARS];
QDoubleSpinBox * gvValues[CPN_MAX_GVARS];
@@ -88,12 +111,27 @@ class FlightModePanel : public ModelPanel
QVector<QSpinBox *> trimsValue;
QVector<QSlider *> trimsSlider;
RawSwitchFilterItemModel * rawSwitchItemModel;
Board::Type board;
void trimUpdate(unsigned int trim);
void updateGVar(int index);
void updateRotaryEncoder(int index);
void setGVSB(QDoubleSpinBox * spinBox, int min, int max, int val);
void populateGvarUnitCB(QComboBox * cb);
void populateGvarPrecCB(QComboBox * cb);
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
void swapData(int idx1, int idx2);
bool gvHasClipboardData() const;
bool gvHasDefnClipboardData(QByteArray * data = nullptr) const;
bool gvHasValueClipboardData(QByteArray * data = nullptr) const;
bool gvDeleteAllowed() const;
bool gvInsertAllowed() const;
bool gvMoveDownAllowed() const;
bool gvMoveUpAllowed() const;
void gvSwapData(int idx1, int idx2);
};
class FlightModesPanel : public ModelPanel
+346 -158
View File
@@ -47,18 +47,18 @@ InputsPanel::InputsPanel(QWidget *parent, ModelData & model, GeneralSettings & g
qbClear->setText(tr("Clear All Inputs"));
qbClear->setIcon(CompanionIcon("clear.png"));
exposLayout->addWidget(ExposlistWidget,1,1,1,3);
exposLayout->addWidget(qbUp,2,1);
exposLayout->addWidget(qbClear,2,2);
exposLayout->addWidget(qbDown,2,3);
exposLayout->addWidget(ExposlistWidget, 1, 1, 1, 3);
exposLayout->addWidget(qbUp, 2, 1);
exposLayout->addWidget(qbClear, 2, 2);
exposLayout->addWidget(qbDown, 2, 3);
connect(ExposlistWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(expolistWidget_customContextMenuRequested(QPoint)));
connect(ExposlistWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(expolistWidget_doubleClicked(QModelIndex)));
connect(ExposlistWidget, SIGNAL(mimeDropped(int,const QMimeData*,Qt::DropAction)), this, SLOT(mimeExpoDropped(int, const QMimeData*, Qt::DropAction)));
connect(ExposlistWidget, SIGNAL(mimeDropped(int, const QMimeData*,Qt::DropAction)), this, SLOT(mimeExpoDropped(int, const QMimeData*, Qt::DropAction)));
connect(qbUp, SIGNAL(pressed()),SLOT(moveExpoUp()));
connect(qbDown, SIGNAL(pressed()),SLOT(moveExpoDown()));
connect(qbClear, SIGNAL(pressed()),SLOT(clearExpos()));
connect(qbUp, SIGNAL(pressed()), SLOT(moveExpoUp()));
connect(qbDown, SIGNAL(pressed()), SLOT(moveExpoDown()));
connect(qbClear, SIGNAL(pressed()), SLOT(clearExpos()));
connect(ExposlistWidget, SIGNAL(keyWasPressed(QKeyEvent*)), this, SLOT(expolistWidget_KeyPress(QKeyEvent*)));
}
@@ -71,9 +71,9 @@ void InputsPanel::update()
{
lock = true;
ExposlistWidget->clear();
for (int i=0; i < inputsCount; ++i) {
for (int i = 0; i < inputsCount; ++i) {
bool filled = false;
for (uint j=0; j < CPN_MAX_EXPOS; ++j) {
for (uint j = 0; j < CPN_MAX_EXPOS; ++j) {
const ExpoData & ed = model->expoData[j];
if ((int)ed.chn == i && ed.mode) {
AddInputLine(j);
@@ -81,7 +81,7 @@ void InputsPanel::update()
}
}
if (!filled) {
AddInputLine(-i-1);
AddInputLine(-i - 1);
}
}
lock = false;
@@ -108,9 +108,8 @@ void InputsPanel::AddInputLine(int dest)
const ExpoData &md = model->expoData[dest];
qba.append((const char*)&md, sizeof(ExpoData));
destId = md.chn + 1;
const QVector<const ExpoData *> expos = model->expos(md.chn);
newChan = (expos.constFirst() == &md);
hasSibs = (expos.constLast() != &md);
newChan = model->isExpoParent(dest);
hasSibs = (model->hasExpoChildren(dest) || model->hasExpoSiblings(dest));
}
QListWidgetItem *itm = new QListWidgetItem(getInputText(dest, newChan));
itm->setData(Qt::UserRole, qba);
@@ -133,10 +132,10 @@ QString InputsPanel::getInputText(int dest, bool newChan)
{
QString str;
if (dest < 0) {
str = modelPrinter.printInputName(-dest-1);
str = modelPrinter.printInputName(-dest - 1);
}
else {
const ExpoData & input = model->expoData[dest];
const ExpoData &input = model->expoData[dest];
const int nameChars = (firmware->getCapability(VirtualInputs) ? 10 : 4);
if (newChan)
str = QString("%1").arg(modelPrinter.printInputName(input.chn), -nameChars, QChar(' '));
@@ -150,14 +149,14 @@ QString InputsPanel::getInputText(int dest, bool newChan)
bool InputsPanel::gm_insertExpo(int idx)
{
if (idx<0 || idx>=CPN_MAX_EXPOS || model->expoData[CPN_MAX_EXPOS-1].mode > 0) {
QMessageBox::information(this, CPN_STR_APP_NAME, tr("Not enough available inputs!"));
if (idx < 0 || idx >= CPN_MAX_EXPOS || model->expoData[CPN_MAX_EXPOS-1].mode > 0) {
QMessageBox::information(this, CPN_STR_APP_NAME, tr("Not enough available Inputs!"));
return false;
}
int chn = model->expoData[idx].chn;
ExpoData * newExpo = model->insertInput(idx);
ExpoData *newExpo = model->insertInput(idx);
newExpo->chn = chn;
newExpo->weight = 100;
newExpo->mode = INPUT_MODE_BOTH;
@@ -172,107 +171,107 @@ void InputsPanel::gm_deleteExpo(int index, bool clearName)
void InputsPanel::gm_openExpo(int index)
{
if(index<0 || index>=CPN_MAX_EXPOS) return;
if (index < 0 || index >= CPN_MAX_EXPOS)
return;
ExpoData mixd(model->expoData[index]);
ExpoData ed(model->expoData[index]);
QString inputName;
QString inputName;
if (firmware->getCapability(VirtualInputs))
inputName = model->inputNames[ed.chn];
ExpoDialog *g = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName);
if (g->exec()) {
model->expoData[index] = ed;
if (firmware->getCapability(VirtualInputs))
inputName = model->inputNames[mixd.chn];
ExpoDialog *g = new ExpoDialog(this, *model, &mixd, generalSettings, firmware, inputName);
if (g->exec()) {
model->expoData[index] = mixd;
if (firmware->getCapability(VirtualInputs))
strncpy(model->inputNames[mixd.chn], inputName.toLatin1().data(), 4);
emit modified();
update();
}
else {
if (expoInserted) {
gm_deleteExpo(index);
}
expoInserted=false;
update();
strncpy(model->inputNames[ed.chn], inputName.toLatin1().data(), INPUT_NAME_LEN);
emit modified();
update();
}
else {
if (expoInserted) {
gm_deleteExpo(index);
}
expoInserted=false;
update();
}
}
int InputsPanel::getExpoIndex(unsigned int dch)
{
unsigned int i = 0;
while (model->expoData[i].chn<=dch && model->expoData[i].mode && i<CPN_MAX_EXPOS) i++;
if(i==CPN_MAX_EXPOS) return -1;
return i;
unsigned int i = 0;
while (model->expoData[i].chn <= dch && model->expoData[i].mode && i < CPN_MAX_EXPOS)
i++;
if (i == CPN_MAX_EXPOS)
return -1;
return i;
}
QList<int> InputsPanel::createExpoListFromSelected()
{
QList<int> list;
foreach(QListWidgetItem *item, ExposlistWidget->selectedItems()) {
int idx= item->data(Qt::UserRole).toByteArray().at(0);
if(idx>=0 && idx<CPN_MAX_EXPOS) list << idx;
}
return list;
QList<int> list;
foreach (QListWidgetItem *item, ExposlistWidget->selectedItems()) {
int idx = item->data(Qt::UserRole).toByteArray().at(0);
if (idx >= 0 && idx < CPN_MAX_EXPOS)
list << idx;
}
return list;
}
void InputsPanel::setSelectedByExpoList(QList<int> list)
{
for(int i=0; i<ExposlistWidget->count(); i++) {
int t = ExposlistWidget->item(i)->data(Qt::UserRole).toByteArray().at(0);
if(list.contains(t))
ExposlistWidget->item(i)->setSelected(true);
}
for (int i = 0; i < ExposlistWidget->count(); i++) {
int t = ExposlistWidget->item(i)->data(Qt::UserRole).toByteArray().at(0);
if (list.contains(t))
ExposlistWidget->item(i)->setSelected(true);
}
}
void InputsPanel::exposDelete(bool ask)
{
QList<int> list = createExpoListFromSelected();
if(list.isEmpty()) return;
QList<int> list = createExpoListFromSelected();
if (list.isEmpty())
return;
QMessageBox::StandardButton ret = QMessageBox::No;
QMessageBox::StandardButton ret = QMessageBox::No;
if(ask)
ret = QMessageBox::warning(this, "companion",
tr("Delete Selected Inputs?"),
QMessageBox::Yes | QMessageBox::No);
if (ask)
ret = QMessageBox::warning(this, CPN_STR_APP_NAME, tr("Delete selected Inputs. Are you sure?"), QMessageBox::Yes | QMessageBox::No);
if ((ret == QMessageBox::Yes) || (!ask)) {
exposDeleteList(list, ask);
emit modified();
update();
}
if ((ret == QMessageBox::Yes) || (!ask)) {
exposDeleteList(list, ask);
emit modified();
update();
}
}
void InputsPanel::exposCut()
{
exposCopy();
exposDelete(false);
exposCopy();
exposDelete(false);
}
void InputsPanel::exposCopy()
{
QList<int> list = createExpoListFromSelected();
QList<int> list = createExpoListFromSelected();
QByteArray mxData;
foreach(int idx, list) {
mxData.append((char*)&model->expoData[idx], sizeof(ExpoData));
}
QByteArray exData;
foreach (int idx, list) {
exData.append((char*)&model->expoData[idx], sizeof(ExpoData));
}
QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-companion-expo", mxData);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_EXPO, exData);
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
}
void InputsPanel::mimeExpoDropped(int index, const QMimeData *data, Qt::DropAction action)
{
int idx = ExposlistWidget->item(index)->data(Qt::UserRole).toByteArray().at(0);
if (action==Qt::CopyAction) {
if (action == Qt::CopyAction) {
pasteExpoMimeData(data, idx);
}
else if (action==Qt::MoveAction) {
else if (action == Qt::MoveAction) {
QList<int> list = createExpoListFromSelected();
exposDeleteList(list, false);
foreach (const int del, list) {
@@ -285,30 +284,31 @@ void InputsPanel::mimeExpoDropped(int index, const QMimeData *data, Qt::DropActi
void InputsPanel::pasteExpoMimeData(const QMimeData * mimeData, int destIdx)
{
if (mimeData->hasFormat("application/x-companion-expo")) {
int idx; // mixer index
if (mimeData->hasFormat(MIMETYPE_EXPO)) {
int idx; // expo index
int dch;
if (destIdx < 0) {
dch = -destIdx - 1;
idx = getExpoIndex(dch) - 1; //get expo index to insert
} else {
}
else {
idx = destIdx;
dch = model->expoData[idx].chn;
}
QByteArray mxData = mimeData->data("application/x-companion-expo");
QByteArray exData = mimeData->data(MIMETYPE_EXPO);
int i = 0;
while (i < mxData.size()) {
while (i < exData.size()) {
idx++;
if (!gm_insertExpo(idx))
break;
ExpoData *md = &model->expoData[idx];
memcpy(md, mxData.mid(i, sizeof(ExpoData)).constData(), sizeof(ExpoData));
const int oldChan = md->chn;
md->chn = dch;
maybeCopyInputName(oldChan, md->chn);
ExpoData *ed = &model->expoData[idx];
memcpy(ed, exData.mid(i, sizeof(ExpoData)).constData(), sizeof(ExpoData));
const int oldChan = ed->chn;
ed->chn = dch;
maybeCopyInputName(oldChan, ed->chn);
i += sizeof(ExpoData);
}
@@ -334,83 +334,104 @@ void InputsPanel::exposDuplicate()
exposPaste();
}
void InputsPanel::expoOpen(QListWidgetItem *item)
{
if (!item)
item = ExposlistWidget->currentItem();
if (!item)
item = ExposlistWidget->currentItem();
int idx = item->data(Qt::UserRole).toByteArray().at(0);
if (idx<0) {
int ch = -idx-1;
idx = getExpoIndex(ch); // get expo index to insert
if (!gm_insertExpo(idx))
return;
model->expoData[idx].chn = ch;
expoInserted=true;
} else {
expoInserted=false;
}
gm_openExpo(idx);
int idx = item->data(Qt::UserRole).toByteArray().at(0);
if (idx < 0) {
int ch = -idx - 1;
idx = getExpoIndex(ch); // get expo index to insert
if (!gm_insertExpo(idx))
return;
model->expoData[idx].chn = ch;
expoInserted = true;
}
else {
expoInserted = false;
}
gm_openExpo(idx);
}
void InputsPanel::expoAdd()
{
int index = ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0);
int index = ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0);
if(index<0) { // if empty then return relevant index
expoOpen();
} else {
index++;
if (!gm_insertExpo(index))
return;
model->expoData[index].chn = model->expoData[index-1].chn;
expoInserted=true;
}
gm_openExpo(index);
if (index < 0) { // if empty then return relevant index
expoOpen();
}
else {
index++;
if (!gm_insertExpo(index))
return;
model->expoData[index].chn = model->expoData[index-1].chn;
expoInserted = true;
}
gm_openExpo(index);
}
void InputsPanel::expolistWidget_customContextMenuRequested(QPoint pos)
{
QPoint globalPos = ExposlistWidget->mapToGlobal(pos);
QPoint globalPos = ExposlistWidget->mapToGlobal(pos);
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat("application/x-companion-expo");
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat(MIMETYPE_EXPO);
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("add.png"), tr("&Add"),this,SLOT(expoAdd()),tr("Ctrl+A"));
contextMenu.addAction(CompanionIcon("edit.png"), tr("&Edit"),this,SLOT(expoOpen()),tr("Enter"));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(exposDelete()),tr("Delete"));
contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(exposCopy()),tr("Ctrl+C"));
contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(exposCut()),tr("Ctrl+X"));
contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(exposPaste()),tr("Ctrl+V"))->setEnabled(hasData);
contextMenu.addAction(CompanionIcon("duplicate.png"), tr("Du&plicate"),this,SLOT(exposDuplicate()),tr("Ctrl+U"));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(moveExpoUp()),tr("Ctrl+Up"));
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(moveExpoDown()),tr("Ctrl+Down"));
contextMenu.addSeparator();
contextMenu.addActions(ExposlistWidget->actions());
selectedIdx = getIndexFromSelected();
inputIdx = getInputIndexFromSelected();
contextMenu.exec(globalPos);
QMenu contextMenu;
QMenu *contextMenuLines = contextMenu.addMenu(tr("Lines"));
contextMenuLines->addAction(CompanionIcon("add.png"), tr("&Add"), this, SLOT(expoAdd()), tr("Ctrl+A"));
contextMenuLines->addAction(CompanionIcon("edit.png"), tr("&Edit"), this, SLOT(expoOpen()), tr("Enter"));
contextMenuLines->addSeparator();
contextMenuLines->addAction(CompanionIcon("clear.png"), tr("&Delete"), this, SLOT(exposDelete()), tr("Delete"));
contextMenuLines->addAction(CompanionIcon("copy.png"), tr("&Copy"), this, SLOT(exposCopy()), tr("Ctrl+C"));
contextMenuLines->addAction(CompanionIcon("cut.png"), tr("&Cut"), this, SLOT(exposCut()), tr("Ctrl+X"));
contextMenuLines->addAction(CompanionIcon("paste.png"), tr("&Paste"), this, SLOT(exposPaste()), tr("Ctrl+V"))->setEnabled(hasData);
contextMenuLines->addAction(CompanionIcon("duplicate.png"), tr("Du&plicate"), this, SLOT(exposDuplicate()), tr("Ctrl+U"));
contextMenuLines->addSeparator();
contextMenuLines->addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(moveExpoUp()), tr("Ctrl+Up"));
contextMenuLines->addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(moveExpoDown()), tr("Ctrl+Down"));
QMenu *contextMenuInputs = contextMenu.addMenu(tr("Input"));
contextMenuInputs->addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(cmInputInsert()))->setEnabled(cmInputInsertAllowed());
contextMenuInputs->addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(cmInputDelete()));
contextMenuInputs->addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(cmInputMoveUp()))->setEnabled(cmInputMoveUpAllowed());
contextMenuInputs->addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(cmInputMoveDown()))->setEnabled(cmInputMoveDownAllowed());
contextMenuInputs->addSeparator();
contextMenuInputs->addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmInputClear()))->setEnabled(isExpoIndex(selectedIdx));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"), this, SLOT(clearExpos()));
contextMenu.addSeparator();
contextMenu.addActions(ExposlistWidget->actions());
contextMenu.exec(globalPos);
}
void InputsPanel::expolistWidget_KeyPress(QKeyEvent *event)
{
if(event->matches(QKeySequence::SelectAll)) expoAdd(); //Ctrl A
if(event->matches(QKeySequence::Delete)) exposDelete();
if(event->matches(QKeySequence::Copy)) exposCopy();
if(event->matches(QKeySequence::Cut)) exposCut();
if(event->matches(QKeySequence::Paste)) exposPaste();
if(event->matches(QKeySequence::Underline)) exposDuplicate();
if (event->matches(QKeySequence::SelectAll))
expoAdd(); //Ctrl A
if (event->matches(QKeySequence::Delete))
exposDelete();
if (event->matches(QKeySequence::Copy))
exposCopy();
if (event->matches(QKeySequence::Cut))
exposCut();
if (event->matches(QKeySequence::Paste))
exposPaste();
if (event->matches(QKeySequence::Underline))
exposDuplicate();
if(event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter) expoOpen();
if(event->matches(QKeySequence::MoveToNextLine))
ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow()+1);
if(event->matches(QKeySequence::MoveToPreviousLine))
ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow()-1);
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
expoOpen();
if (event->matches(QKeySequence::MoveToNextLine))
ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow() + 1);
if (event->matches(QKeySequence::MoveToPreviousLine))
ExposlistWidget->setCurrentRow(ExposlistWidget->currentRow() - 1);
}
int InputsPanel::gm_moveExpo(int idx, bool dir) //true=inc=down false=dec=up
@@ -418,7 +439,7 @@ int InputsPanel::gm_moveExpo(int idx, bool dir) //true=inc=down false=dec=up
if (idx >= CPN_MAX_EXPOS || idx < 0 || (dir && idx >= CPN_MAX_EXPOS - 1) || (!dir && !idx))
return -1;
const int tdx = dir ? idx+1 : idx-1;
const int tdx = dir ? idx + 1 : idx-1;
ExpoData temp;
ExpoData &src = model->expoData[idx];
ExpoData &tgt = model->expoData[tdx];
@@ -432,7 +453,7 @@ int InputsPanel::gm_moveExpo(int idx, bool dir) //true=inc=down false=dec=up
if (tgt.chn != src.chn || tgtempty) {
const int oldChan = src.chn;
if (dir && src.chn < unsigned(inputsCount-1))
if (dir && src.chn < unsigned(inputsCount - 1))
src.chn++;
else if (!dir && src.chn > 0)
src.chn--;
@@ -452,7 +473,7 @@ void InputsPanel::moveExpoList(bool down)
QList<int> list = createExpoListFromSelected();
QList<int> highlightList;
bool mod = false;
foreach(int idx, list) {
foreach (int idx, list) {
const int newIdx = gm_moveExpo(idx, down);
if (newIdx > -1) {
highlightList << newIdx;
@@ -483,19 +504,22 @@ void InputsPanel::expolistWidget_doubleClicked(QModelIndex index)
void InputsPanel::exposDeleteList(QList<int> list, bool clearName)
{
std::sort(list.begin(), list.end());
std::sort(list.begin(), list.end());
int iDec = 0;
foreach(int idx, list) {
gm_deleteExpo(idx-iDec, clearName);
iDec++;
}
int iDec = 0;
foreach (int idx, list) {
gm_deleteExpo(idx-iDec, clearName);
iDec++;
}
}
void InputsPanel::clearExpos()
{
if (QMessageBox::question(this, tr("Clear Inputs?"), tr("Really clear all the inputs?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Inputs. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
model->clearInputs();
for (int i = 0; i < inputsCount; i++) {
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, i);
}
emit modified();
update();
}
@@ -512,8 +536,172 @@ void InputsPanel::maybeCopyInputName(int srcChan, int destChan)
if (srcEmpty) {
// if destination input name is empty, copy it from source expo input
if (!strlen(model->inputNames[destChan]))
strncpy(model->inputNames[destChan], model->inputNames[srcChan], 5);
strncpy(model->inputNames[destChan], model->inputNames[srcChan], INPUT_NAME_LEN);
// clear the emptry source channel name
model->inputNames[srcChan][0] = 0;
}
}
bool InputsPanel::cmInputInsertAllowed() const
{
return ((!model->hasExpos(inputsCount - 1)) && (inputIdx < inputsCount - 1));
}
bool InputsPanel::cmInputMoveDownAllowed() const
{
return (inputIdx >= 0 && (inputIdx < inputsCount - 1));
}
bool InputsPanel::cmInputMoveUpAllowed() const
{
return inputIdx > 0;
}
void InputsPanel::cmInputClear()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = CPN_MAX_EXPOS - 1; i >= 0; i--) {
ExpoData *ed = &model->expoData[i];
if ((int)ed->chn == inputIdx)
model->removeInput(i);
}
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_CLEAR, inputIdx);
update();
emit modified();
}
void InputsPanel::cmInputDelete()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Input. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
ExpoData *ed = &model->expoData[i];
if ((int)ed->chn == inputIdx)
model->removeInput(i);
else if ((int)ed->chn > inputIdx)
ed->chn--;
}
for (int i = inputIdx; i < inputsCount; i++) {
strncpy(model->inputNames[i], model->inputNames[i + 1], sizeof(model->inputNames[i]) - 1);
}
model->inputNames[inputsCount - 1][0] = 0;
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, -1);
update();
emit modified();
}
void InputsPanel::cmInputInsert()
{
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
ExpoData *ed = &model->expoData[i];
if ((int)ed->chn >= inputIdx)
ed->chn++;
}
for (int i = inputsCount - 1; i > inputIdx; i--) {
strncpy(model->inputNames[i], model->inputNames[i - 1], sizeof(model->inputNames[i]) - 1);
}
model->inputNames[inputIdx][0] = 0;
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SHIFT, inputIdx, 0, 1);
update();
emit modified();
}
void InputsPanel::cmInputMoveDown()
{
cmInputSwapData(inputIdx, inputIdx + 1);
}
void InputsPanel::cmInputMoveUp()
{
cmInputSwapData(inputIdx - 1, inputIdx);
}
void InputsPanel::cmInputSwapData(int idx1, int idx2)
{
if (idx1 >= idx2 || (!model->hasExpos(idx1) && !model->hasExpos(idx2)))
return;
// save expos
int expoidx = -1;
QVector<ExpoData> edtmp;
int i;
for (i = 0; i < CPN_MAX_EXPOS; i++) {
ExpoData *ed = &model->expoData[i];
if ((int)ed->chn == idx1) {
edtmp << model->expoData[i];
if (expoidx < 0)
expoidx = i;
}
else if ((int)ed->chn > idx1)
break;
}
// move expos up
const int offset = i - expoidx;
int expocnt;
for (int j = i; j < CPN_MAX_EXPOS; j++) {
ExpoData *ed = &model->expoData[j];
if ((int)ed->chn == idx2) {
ExpoData *dest = &model->expoData[j - offset];
memcpy(dest, &model->expoData[j], sizeof(ExpoData));
dest->chn = idx1;
expocnt++;
}
else if ((int)ed->chn > idx2)
break;
}
// copy back saved expos
int cnt = 0;
foreach (ExpoData ed, edtmp) {
ExpoData *dest = &model->expoData[expoidx + expocnt + cnt];
memcpy(dest, &ed, sizeof(ExpoData));
dest->chn = idx2;
cnt++;
}
// swap names
QByteArray *tname = new QByteArray(model->inputNames[idx2]);
strncpy(model->inputNames[idx2], model->inputNames[idx1], sizeof(model->inputNames[idx2]) - 1);
strncpy(model->inputNames[idx1], tname->data(), sizeof(model->inputNames[idx1]) - 1);
model->updateAllReferences(ModelData::REF_UPD_TYPE_INPUT, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update();
emit modified();
}
bool InputsPanel::isInputIndex(const int index)
{
if (index < 0)
return true;
else
return false;
}
bool InputsPanel::isExpoIndex(const int index)
{
return !isInputIndex(index);
}
int InputsPanel::getIndexFromSelected()
{
return ExposlistWidget->currentItem()->data(Qt::UserRole).toByteArray().at(0);
}
int InputsPanel::getInputIndexFromSelected()
{
const int selidx = getIndexFromSelected();
int idx;
if (isInputIndex(selidx))
idx = -selidx - 1;
else {
const ExpoData *ed = &model->expoData[selidx];
idx = ed->chn;
}
return idx;
}
+17 -1
View File
@@ -25,6 +25,8 @@
#include "mixerslistwidget.h"
#include "modelprinter.h"
constexpr char MIMETYPE_EXPO[] = "application/x-companion-expo";
class InputsPanel : public ModelPanel
{
Q_OBJECT
@@ -52,12 +54,19 @@ class InputsPanel : public ModelPanel
void expoOpen(QListWidgetItem *item = NULL);
void expoAdd();
void maybeCopyInputName(int srcChan, int destChan);
void cmInputClear();
void cmInputDelete();
void cmInputInsert();
void cmInputMoveDown();
void cmInputMoveUp();
private:
bool expoInserted;
MixersListWidget *ExposlistWidget;
int inputsCount;
ModelPrinter modelPrinter;
int selectedIdx;
int inputIdx;
int getExpoIndex(unsigned int dch);
bool gm_insertExpo(int idx);
@@ -70,7 +79,14 @@ class InputsPanel : public ModelPanel
void pasteExpoMimeData(const QMimeData * mimeData, int destIdx);
void AddInputLine(int dest);
QString getInputText(int dest, bool newChan);
bool cmInputInsertAllowed() const;
bool cmInputMoveDownAllowed() const;
bool cmInputMoveUpAllowed() const;
void cmInputSwapData(int idx1, int idx2);
bool isInputIndex(const int index);
bool isExpoIndex(const int index);
int getIndexFromSelected();
int getInputIndexFromSelected();
};
#endif // _INPUTS_H_
+264 -174
View File
@@ -26,7 +26,7 @@
LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
ModelPanel(parent, model, generalSettings, firmware),
selectedSwitch(0)
selectedIndex(0)
{
Stopwatch s1("LogicalSwitchesPanel");
@@ -35,19 +35,22 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
const int srcGroups = firmware->getCapability(GvarsInCS) ? 0 : (RawSource::AllSourceGroups & ~RawSource::GVarsGroup);
rawSourceItemModel = new RawSourceFilterItemModel(&generalSettings, &model, srcGroups, this);
lsCapability = firmware->getCapability(LogicalSwitches);
lsCapabilityExt = firmware->getCapability(LogicalSwitchesExt);
QStringList headerLabels;
headerLabels << "#" << tr("Function") << tr("V1") << tr("V2") << tr("AND Switch");
if (firmware->getCapability(LogicalSwitchesExt)) {
if (lsCapabilityExt) {
headerLabels << tr("Duration") << tr("Delay");
}
TableLayout * tableLayout = new TableLayout(this, firmware->getCapability(LogicalSwitches), headerLabels);
TableLayout * tableLayout = new TableLayout(this, lsCapability, headerLabels);
s1.report("header");
const int channelsMax = model.getChannelsMax(true);
lock = true;
for (int i=0; i<firmware->getCapability(LogicalSwitches); i++) {
for (int i=0; i<lsCapability; i++) {
// The label
QLabel * label = new QLabel(this);
label->setProperty("index", i);
@@ -56,96 +59,96 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
label->setToolTip(tr("Popup menu available"));
label->setMouseTracking(true);
label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(csw_customContextMenuRequested(QPoint)));
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomContextMenuRequested(QPoint)));
tableLayout->addWidget(i, 0, label);
// The function
csw[i] = new QComboBox(this);
csw[i]->setProperty("index", i);
populateCSWCB(csw[i]);
connect(csw[i], SIGNAL(currentIndexChanged(int)), this, SLOT(functionChanged()));
tableLayout->addWidget(i, 1, csw[i]);
cbFunction[i] = new QComboBox(this);
cbFunction[i]->setProperty("index", i);
populateFunctionCB(cbFunction[i]);
connect(cbFunction[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onFunctionChanged()));
tableLayout->addWidget(i, 1, cbFunction[i]);
// V1
QHBoxLayout *v1Layout = new QHBoxLayout();
cswitchSource1[i] = new QComboBox(this);
cswitchSource1[i]->setProperty("index",i);
connect(cswitchSource1[i], SIGNAL(currentIndexChanged(int)), this, SLOT(v1Edited(int)));
v1Layout->addWidget(cswitchSource1[i]);
cswitchSource1[i]->setVisible(false);
cswitchValue[i] = new QDoubleSpinBox(this);
cswitchValue[i]->setMaximum(channelsMax);
cswitchValue[i]->setMinimum(-channelsMax);
cswitchValue[i]->setAccelerated(true);
cswitchValue[i]->setDecimals(0);
cswitchValue[i]->setProperty("index", i);
connect(cswitchValue[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited()));
v1Layout->addWidget(cswitchValue[i]);
cswitchValue[i]->setVisible(false);
cbSource1[i] = new QComboBox(this);
cbSource1[i]->setProperty("index",i);
connect(cbSource1[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onV1Changed(int)));
v1Layout->addWidget(cbSource1[i]);
cbSource1[i]->setVisible(false);
dsbValue[i] = new QDoubleSpinBox(this);
dsbValue[i]->setMaximum(channelsMax);
dsbValue[i]->setMinimum(-channelsMax);
dsbValue[i]->setAccelerated(true);
dsbValue[i]->setDecimals(0);
dsbValue[i]->setProperty("index", i);
connect(dsbValue[i], SIGNAL(editingFinished()), this, SLOT(onOffsetChanged()));
v1Layout->addWidget(dsbValue[i]);
dsbValue[i]->setVisible(false);
tableLayout->addLayout(i, 2, v1Layout);
// V2
QHBoxLayout *v2Layout = new QHBoxLayout();
cswitchSource2[i] = new QComboBox(this);
cswitchSource2[i]->setProperty("index", i);
connect(cswitchSource2[i], SIGNAL(currentIndexChanged(int)), this, SLOT(v2Edited(int)));
v2Layout->addWidget(cswitchSource2[i]);
cswitchSource2[i]->setVisible(false);
cswitchOffset[i] = new QDoubleSpinBox(this);
cswitchOffset[i]->setProperty("index",i);
cswitchOffset[i]->setMaximum(channelsMax);
cswitchOffset[i]->setMinimum(-channelsMax);
cswitchOffset[i]->setAccelerated(true);
cswitchOffset[i]->setDecimals(0);
connect(cswitchOffset[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited()));
cswitchOffset[i]->setVisible(false);
v2Layout->addWidget(cswitchOffset[i]);
cswitchOffset2[i] = new QDoubleSpinBox(this);
cswitchOffset2[i]->setProperty("index",i);
cswitchOffset2[i]->setMaximum(channelsMax);
cswitchOffset2[i]->setMinimum(-channelsMax);
cswitchOffset2[i]->setAccelerated(true);
cswitchOffset2[i]->setDecimals(0);
cswitchOffset2[i]->setSpecialValueText(" " + tr("(instant)"));
connect(cswitchOffset2[i], SIGNAL(editingFinished()), this, SLOT(offsetEdited()));
cswitchOffset2[i]->setVisible(false);
v2Layout->addWidget(cswitchOffset2[i]);
cswitchTOffset[i] = new TimerEdit(this);
cswitchTOffset[i]->setProperty("index",i);
connect(cswitchTOffset[i],SIGNAL(editingFinished()),this,SLOT(offsetEdited()));
v2Layout->addWidget(cswitchTOffset[i]);
cswitchTOffset[i]->setVisible(false);
cbSource2[i] = new QComboBox(this);
cbSource2[i]->setProperty("index", i);
connect(cbSource2[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onV2Changed(int)));
v2Layout->addWidget(cbSource2[i]);
cbSource2[i]->setVisible(false);
dsbOffset[i] = new QDoubleSpinBox(this);
dsbOffset[i]->setProperty("index",i);
dsbOffset[i]->setMaximum(channelsMax);
dsbOffset[i]->setMinimum(-channelsMax);
dsbOffset[i]->setAccelerated(true);
dsbOffset[i]->setDecimals(0);
connect(dsbOffset[i], SIGNAL(editingFinished()), this, SLOT(onOffsetChanged()));
dsbOffset[i]->setVisible(false);
v2Layout->addWidget(dsbOffset[i]);
dsbOffset2[i] = new QDoubleSpinBox(this);
dsbOffset2[i]->setProperty("index",i);
dsbOffset2[i]->setMaximum(channelsMax);
dsbOffset2[i]->setMinimum(-channelsMax);
dsbOffset2[i]->setAccelerated(true);
dsbOffset2[i]->setDecimals(0);
dsbOffset2[i]->setSpecialValueText(" " + tr("(instant)"));
connect(dsbOffset2[i], SIGNAL(editingFinished()), this, SLOT(onOffsetChanged()));
dsbOffset2[i]->setVisible(false);
v2Layout->addWidget(dsbOffset2[i]);
teOffset[i] = new TimerEdit(this);
teOffset[i]->setProperty("index",i);
connect(teOffset[i],SIGNAL(editingFinished()),this,SLOT(onOffsetChanged()));
v2Layout->addWidget(teOffset[i]);
teOffset[i]->setVisible(false);
tableLayout->addLayout(i, 3, v2Layout);
// 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]);
cbAndSwitch[i] = new QComboBox(this);
cbAndSwitch[i]->setProperty("index", i);
populateAndSwitchCB(cbAndSwitch[i]);
connect(cbAndSwitch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(onAndSwitchChanged(int)));
tableLayout->addWidget(i, 4, cbAndSwitch[i]);
if (firmware->getCapability(LogicalSwitchesExt)) {
if (lsCapabilityExt) {
// Duration
cswitchDuration[i] = new QDoubleSpinBox(this);
cswitchDuration[i]->setProperty("index", i);
cswitchDuration[i]->setSingleStep(0.1);
cswitchDuration[i]->setMaximum(25);
cswitchDuration[i]->setMinimum(0);
cswitchDuration[i]->setAccelerated(true);
cswitchDuration[i]->setDecimals(1);
connect(cswitchDuration[i], SIGNAL(valueChanged(double)), this, SLOT(durationEdited(double)));
tableLayout->addWidget(i, 5, cswitchDuration[i]);
dsbDuration[i] = new QDoubleSpinBox(this);
dsbDuration[i]->setProperty("index", i);
dsbDuration[i]->setSingleStep(0.1);
dsbDuration[i]->setMaximum(25);
dsbDuration[i]->setMinimum(0);
dsbDuration[i]->setAccelerated(true);
dsbDuration[i]->setDecimals(1);
connect(dsbDuration[i], SIGNAL(valueChanged(double)), this, SLOT(onDurationChanged(double)));
tableLayout->addWidget(i, 5, dsbDuration[i]);
// Delay
cswitchDelay[i] = new QDoubleSpinBox(this);
cswitchDelay[i]->setProperty("index", i);
cswitchDelay[i]->setSingleStep(0.1);
cswitchDelay[i]->setMaximum(25);
cswitchDelay[i]->setMinimum(0);
cswitchDelay[i]->setAccelerated(true);
cswitchDelay[i]->setDecimals(1);
connect(cswitchDelay[i], SIGNAL(valueChanged(double)), this, SLOT(delayEdited(double)));
tableLayout->addWidget(i, 6, cswitchDelay[i]);
dsbDelay[i] = new QDoubleSpinBox(this);
dsbDelay[i]->setProperty("index", i);
dsbDelay[i]->setSingleStep(0.1);
dsbDelay[i]->setMaximum(25);
dsbDelay[i]->setMinimum(0);
dsbDelay[i]->setAccelerated(true);
dsbDelay[i]->setDecimals(1);
connect(dsbDelay[i], SIGNAL(valueChanged(double)), this, SLOT(onDelayChanged(double)));
tableLayout->addWidget(i, 6, dsbDelay[i]);
}
}
@@ -155,7 +158,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
lock = false;
update();
tableLayout->resizeColumnsToContents();
tableLayout->pushRowsUp(firmware->getCapability(LogicalSwitches)+1);
tableLayout->pushRowsUp(lsCapability+1);
s1.report("end");
}
@@ -172,10 +175,10 @@ void LogicalSwitchesPanel::updateDataModels()
lock = oldLock;
}
void LogicalSwitchesPanel::functionChanged()
void LogicalSwitchesPanel::onFunctionChanged()
{
int i = sender()->property("index").toInt();
unsigned newFunc = csw[i]->currentData().toUInt();
unsigned newFunc = cbFunction[i]->currentData().toUInt();
if (model->logicalSw[i].func == newFunc)
return;
@@ -204,13 +207,13 @@ void LogicalSwitchesPanel::functionChanged()
emit modified();
}
void LogicalSwitchesPanel::v1Edited(int value)
void LogicalSwitchesPanel::onV1Changed(int value)
{
if (!lock) {
int i = sender()->property("index").toInt();
model->logicalSw[i].val1 = cswitchSource1[i]->itemData(value).toInt();
model->logicalSw[i].val1 = cbSource1[i]->itemData(value).toInt();
if (model->logicalSw[i].getFunctionFamily() == LS_FAMILY_VOFS) {
if (!offsetEditedAt(i))
if (!offsetChangedAt(i))
updateLine(i);
}
else {
@@ -219,25 +222,25 @@ void LogicalSwitchesPanel::v1Edited(int value)
}
}
void LogicalSwitchesPanel::v2Edited(int value)
void LogicalSwitchesPanel::onV2Changed(int value)
{
if (!lock) {
int i = sender()->property("index").toInt();
model->logicalSw[i].val2 = cswitchSource2[i]->itemData(value).toInt();
model->logicalSw[i].val2 = cbSource2[i]->itemData(value).toInt();
emit modified();
}
}
void LogicalSwitchesPanel::andEdited(int value)
void LogicalSwitchesPanel::onAndSwitchChanged(int value)
{
if (!lock) {
int index = sender()->property("index").toInt();
model->logicalSw[index].andsw = cswitchAnd[index]->itemData(value).toInt();
model->logicalSw[index].andsw = cbAndSwitch[index]->itemData(value).toInt();
emit modified();
}
}
void LogicalSwitchesPanel::durationEdited(double duration)
void LogicalSwitchesPanel::onDurationChanged(double duration)
{
if (!lock) {
int index = sender()->property("index").toInt();
@@ -246,7 +249,7 @@ void LogicalSwitchesPanel::durationEdited(double duration)
}
}
void LogicalSwitchesPanel::delayEdited(double delay)
void LogicalSwitchesPanel::onDelayChanged(double delay)
{
if (!lock) {
int index = sender()->property("index").toInt();
@@ -255,12 +258,12 @@ void LogicalSwitchesPanel::delayEdited(double delay)
}
}
void LogicalSwitchesPanel::offsetEdited()
void LogicalSwitchesPanel::onOffsetChanged()
{
offsetEditedAt(sender()->property("index").toInt());
offsetChangedAt(sender()->property("index").toInt());
}
bool LogicalSwitchesPanel::offsetEditedAt(int index)
bool LogicalSwitchesPanel::offsetChangedAt(int index)
{
if (lock)
return false;
@@ -275,7 +278,7 @@ bool LogicalSwitchesPanel::offsetEditedAt(int index)
{
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();
double currVal = source.isTimeBased() ? teOffset[index]->timeInSeconds() : dsbOffset[index]->value();
value = round((currVal - range.offset) / range.step);
mod = (mod || value != model->logicalSw[index].val2);
model->logicalSw[index].val2 = value;
@@ -283,22 +286,22 @@ bool LogicalSwitchesPanel::offsetEditedAt(int index)
}
case LS_FAMILY_TIMER:
value = TimToVal(cswitchValue[index]->value());
value = TimToVal(dsbValue[index]->value());
mod = (mod || value != model->logicalSw[index].val1);
model->logicalSw[index].val1 = value;
value = TimToVal(cswitchOffset[index]->value());
value = TimToVal(dsbOffset[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());
if (sender() == dsbOffset[index]) {
value = TimToVal(dsbOffset[index]->value());
mod = (mod || value != model->logicalSw[index].val2);
model->logicalSw[index].val2 = value;
}
else {
value = TimToVal(cswitchOffset2[index]->value()) - model->logicalSw[index].val2;
value = TimToVal(dsbOffset2[index]->value()) - model->logicalSw[index].val2;
mod = (mod || value != model->logicalSw[index].val3);
model->logicalSw[index].val3 = value;
}
@@ -347,8 +350,8 @@ 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()));
cbFunction[i]->setCurrentIndex(cbFunction[i]->findData(model->logicalSw[i].func));
cbAndSwitch[i]->setCurrentIndex(cbAndSwitch[i]->findData(RawSwitch(model->logicalSw[i].andsw).toValue()));
if (!model->logicalSw[i].func) {
mask = 0;
@@ -364,27 +367,27 @@ void LogicalSwitchesPanel::updateLine(int i)
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()));
cbSource1[i]->setModel(rawSourceItemModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(source.toValue()));
if (source.isTimeBased()) {
mask |= VALUE_TO_VISIBLE;
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);
teOffset[i]->setTimeRange(range.min, range.max);
teOffset[i]->setSingleStep(range.step);
teOffset[i]->setPageStep(range.step * 60);
teOffset[i]->setShowSeconds(range.step != 60);
teOffset[i]->setTime((int)value);
}
else {
mask |= VALUE2_VISIBLE;
if (range.unit.isEmpty())
cswitchOffset[i]->setSuffix("");
dsbOffset[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]->setSingleStep(range.step);
cswitchOffset[i]->setValue(value);
dsbOffset[i]->setSuffix(" " + range.unit);
dsbOffset[i]->setDecimals(range.decimals);
dsbOffset[i]->setMinimum(range.min);
dsbOffset[i]->setMaximum(range.max);
dsbOffset[i]->setSingleStep(range.step);
dsbOffset[i]->setValue(value);
}
break;
@@ -393,58 +396,58 @@ void LogicalSwitchesPanel::updateLine(int i)
case LS_FAMILY_STICKY: // no break
case LS_FAMILY_VBOOL:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
cswitchSource1[i]->setModel(rawSwitchItemModel);
cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(model->logicalSw[i].val1));
cswitchSource2[i]->setModel(rawSwitchItemModel);
cswitchSource2[i]->setCurrentIndex(cswitchSource2[i]->findData(model->logicalSw[i].val2));
cbSource1[i]->setModel(rawSwitchItemModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
cbSource2[i]->setModel(rawSwitchItemModel);
cbSource2[i]->setCurrentIndex(cbSource2[i]->findData(model->logicalSw[i].val2));
break;
case LS_FAMILY_EDGE:
mask |= SOURCE1_VISIBLE | VALUE2_VISIBLE | VALUE3_VISIBLE;
mask &= ~DELAY_ENABLED;
cswitchSource1[i]->setModel(rawSwitchItemModel);
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]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)"));
cbSource1[i]->setModel(rawSwitchItemModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
updateTimerParam(dsbOffset[i], model->logicalSw[i].val2, 0.0);
updateTimerParam(dsbOffset2[i], model->logicalSw[i].val2+model->logicalSw[i].val3, ValToTim(TimToVal(dsbOffset[i]->value())-1));
dsbOffset2[i]->setSuffix((model->logicalSw[i].val3) ? "" : tr(" (infinite)"));
break;
case LS_FAMILY_VCOMP:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
cswitchSource1[i]->setModel(rawSourceItemModel);
cswitchSource1[i]->setCurrentIndex(cswitchSource1[i]->findData(model->logicalSw[i].val1));
cswitchSource2[i]->setModel(rawSourceItemModel);
cswitchSource2[i]->setCurrentIndex(cswitchSource2[i]->findData(model->logicalSw[i].val2));
cbSource1[i]->setModel(rawSourceItemModel);
cbSource1[i]->setCurrentIndex(cbSource1[i]->findData(model->logicalSw[i].val1));
cbSource2[i]->setModel(rawSourceItemModel);
cbSource2[i]->setCurrentIndex(cbSource2[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);
updateTimerParam(cswitchOffset[i], model->logicalSw[i].val2, 0.1);
updateTimerParam(dsbValue[i], model->logicalSw[i].val1, 0.1);
updateTimerParam(dsbOffset[i], model->logicalSw[i].val2, 0.1);
break;
}
}
cswitchSource1[i]->setVisible(mask & SOURCE1_VISIBLE);
cswitchSource2[i]->setVisible(mask & SOURCE2_VISIBLE);
cswitchValue[i]->setVisible(mask & VALUE1_VISIBLE);
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);
cbSource1[i]->setVisible(mask & SOURCE1_VISIBLE);
cbSource2[i]->setVisible(mask & SOURCE2_VISIBLE);
dsbValue[i]->setVisible(mask & VALUE1_VISIBLE);
dsbOffset[i]->setVisible(mask & VALUE2_VISIBLE);
dsbOffset2[i]->setVisible(mask & VALUE3_VISIBLE);
teOffset[i]->setVisible(mask & VALUE_TO_VISIBLE);
cbAndSwitch[i]->setVisible(mask & LINE_ENABLED);
if (lsCapabilityExt) {
dsbDuration[i]->setVisible(mask & DURATION_ENABLED);
dsbDelay[i]->setVisible(mask & DELAY_ENABLED);
if (mask & DURATION_ENABLED)
cswitchDuration[i]->setValue(model->logicalSw[i].duration/10.0);
dsbDuration[i]->setValue(model->logicalSw[i].duration/10.0);
if (mask & DELAY_ENABLED)
cswitchDelay[i]->setValue(model->logicalSw[i].delay/10.0);
dsbDelay[i]->setValue(model->logicalSw[i].delay/10.0);
}
lock = false;
}
void LogicalSwitchesPanel::populateCSWCB(QComboBox *b)
void LogicalSwitchesPanel::populateFunctionCB(QComboBox *b)
{
int order[] = {
LS_FN_OFF,
@@ -514,63 +517,150 @@ void LogicalSwitchesPanel::populateAndSwitchCB(QComboBox *b)
void LogicalSwitchesPanel::update()
{
updateDataModels();
for (int i=0; i<firmware->getCapability(LogicalSwitches); i++) {
for (int i=0; i<lsCapability; i++) {
updateLine(i);
}
}
void LogicalSwitchesPanel::cswPaste()
void LogicalSwitchesPanel::cmPaste()
{
const QClipboard *clipboard = QApplication::clipboard();
const QMimeData *mimeData = clipboard->mimeData();
if (mimeData->hasFormat("application/x-companion-csw")) {
QByteArray cswData = mimeData->data("application/x-companion-csw");
LogicalSwitchData *csw = &model->logicalSw[selectedSwitch];
memcpy(csw, cswData.constData(), sizeof(LogicalSwitchData));
update();
QByteArray data;
if (hasClipboardData(&data)) {
memcpy(&model->logicalSw[selectedIndex], data.constData(), sizeof(LogicalSwitchData));
updateDataModels();
updateLine(selectedIndex);
emit modified();
}
}
void LogicalSwitchesPanel::cswDelete()
void LogicalSwitchesPanel::cmDelete()
{
model->logicalSw[selectedSwitch].clear();
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Logical Switch. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
memmove(&model->logicalSw[selectedIndex], &model->logicalSw[selectedIndex + 1], (CPN_MAX_LOGICAL_SWITCHES - (selectedIndex + 1)) * sizeof(LogicalSwitchData));
model->logicalSw[lsCapability - 1].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, -1);
update();
emit modified();
updateLine(selectedSwitch);
}
void LogicalSwitchesPanel::cswCopy()
void LogicalSwitchesPanel::cmCopy()
{
QByteArray cswData;
cswData.append((char*)&model->logicalSw[selectedSwitch],sizeof(LogicalSwitchData));
QByteArray data;
data.append((char*)&model->logicalSw[selectedIndex], sizeof(LogicalSwitchData));
QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-companion-csw", cswData);
mimeData->setData(MIMETYPE_LOGICAL_SWITCH, data);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
}
void LogicalSwitchesPanel::cswCut()
void LogicalSwitchesPanel::cmCut()
{
cswCopy();
cswDelete();
cmCopy();
cmClear();
}
// TODO make something generic here!
void LogicalSwitchesPanel::csw_customContextMenuRequested(QPoint pos)
void LogicalSwitchesPanel::onCustomContextMenuRequested(QPoint pos)
{
QLabel *label = (QLabel *)sender();
selectedSwitch = label->property("index").toInt();
QLabel *label = (QLabel *)sender();
selectedIndex = label->property("index").toInt();
QPoint globalPos = label->mapToGlobal(pos);
QPoint globalPos = label->mapToGlobal(pos);
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"),this,SLOT(cmCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"),this,SLOT(cmCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"),this,SLOT(cmPaste()))->setEnabled(hasClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"),this,SLOT(cmClear()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"),this,SLOT(cmInsert()))->setEnabled(insertAllowed());
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"),this,SLOT(cmDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"),this,SLOT(cmMoveUp()))->setEnabled(moveUpAllowed());
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"),this,SLOT(cmMoveDown()))->setEnabled(moveDownAllowed());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"),this,SLOT(cmClearAll()));
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
bool hasData = mimeData->hasFormat("application/x-companion-csw");
contextMenu.exec(globalPos);
}
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(cswCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(cswCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(cswPaste()))->setEnabled(hasData);
contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(cswDelete()));
bool LogicalSwitchesPanel::hasClipboardData(QByteArray * data) const
{
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_LOGICAL_SWITCH)) {
if (data)
data->append(mimeData->data(MIMETYPE_LOGICAL_SWITCH));
return true;
}
return false;
}
contextMenu.exec(globalPos);
bool LogicalSwitchesPanel::insertAllowed() const
{
return ((selectedIndex < lsCapability - 1) && (model->logicalSw[lsCapability - 1].isEmpty()));
}
bool LogicalSwitchesPanel::moveDownAllowed() const
{
return selectedIndex < lsCapability - 1;
}
bool LogicalSwitchesPanel::moveUpAllowed() const
{
return selectedIndex > 0;
}
void LogicalSwitchesPanel::cmMoveUp()
{
swapData(selectedIndex, selectedIndex - 1);
}
void LogicalSwitchesPanel::cmMoveDown()
{
swapData(selectedIndex, selectedIndex + 1);
}
void LogicalSwitchesPanel::cmClear()
{
model->logicalSw[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, selectedIndex);
update();
emit modified();
}
void LogicalSwitchesPanel::cmClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Logical Switches. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i=0; i<lsCapability; i++) {
model->logicalSw[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_CLEAR, i);
}
update();
emit modified();
}
void LogicalSwitchesPanel::cmInsert()
{
memmove(&model->logicalSw[selectedIndex + 1], &model->logicalSw[selectedIndex], (CPN_MAX_LOGICAL_SWITCHES - (selectedIndex + 1)) * sizeof(LogicalSwitchData));
model->logicalSw[selectedIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SHIFT, selectedIndex, 0, 1);
update();
emit modified();
}
void LogicalSwitchesPanel::swapData(int idx1, int idx2)
{
if ((idx1 != idx2) && (!model->logicalSw[idx1].isEmpty() || !model->logicalSw[idx2].isEmpty())) {
LogicalSwitchData lstmp = model->logicalSw[idx2];
LogicalSwitchData *lsw1 = &model->logicalSw[idx1];
LogicalSwitchData *lsw2 = &model->logicalSw[idx2];
memcpy(lsw2, lsw1, sizeof(LogicalSwitchData));
memcpy(lsw1, &lstmp, sizeof(LogicalSwitchData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_LOGICAL_SWITCH, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
update();
emit modified();
}
}
+39 -27
View File
@@ -28,6 +28,8 @@ class RawSwitchFilterItemModel;
class RawSourceFilterItemModel;
class TimerEdit;
constexpr char MIMETYPE_LOGICAL_SWITCH[] = "application/x-companion-logical-switch";
class LogicalSwitchesPanel : public ModelPanel
{
Q_OBJECT
@@ -40,40 +42,50 @@ class LogicalSwitchesPanel : public ModelPanel
private slots:
void updateDataModels();
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 onFunctionChanged();
void onV1Changed(int value);
void onV2Changed(int value);
void onAndSwitchChanged(int value);
void onDurationChanged(double duration);
void onDelayChanged(double delay);
void onOffsetChanged();
bool offsetChangedAt(int index);
void updateLine(int index);
void csw_customContextMenuRequested(QPoint pos);
void cswDelete();
void cswCopy();
void cswPaste();
void cswCut();
void onCustomContextMenuRequested(QPoint pos);
void cmDelete();
void cmCopy();
void cmPaste();
void cmCut();
void cmMoveUp();
void cmMoveDown();
void cmInsert();
void cmClear();
void cmClearAll();
private:
QComboBox * csw[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * cswitchValue[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * cswitchOffset[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * cswitchOffset2[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];
QComboBox * cswitchSource1[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cswitchSource2[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbFunction[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * dsbValue[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * dsbOffset[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * dsbOffset2[CPN_MAX_LOGICAL_SWITCHES];
TimerEdit * teOffset[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbAndSwitch[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * dsbDuration[CPN_MAX_LOGICAL_SWITCHES];
QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES];
RawSwitchFilterItemModel * rawSwitchItemModel;
RawSourceFilterItemModel * rawSourceItemModel;
int selectedSwitch;
void populateCSWCB(QComboBox *b);
int selectedIndex;
void populateFunctionCB(QComboBox *b);
void populateAndSwitchCB(QComboBox *b);
void updateTimerParam(QDoubleSpinBox *sb, int timer, double minimum=0);
int lsCapability;
int lsCapabilityExt;
void swapData(int idx1, int idx2);
bool hasClipboardData(QByteArray * data = nullptr) const;
bool insertAllowed() const;
bool moveDownAllowed() const;
bool moveUpAllowed() const;
};
#endif // _LOGICALSWITCHES_H_
+206 -87
View File
@@ -49,7 +49,7 @@ TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, Ge
}
else {
ui->name->setMaxLength(length);
ui->name->setText(timer.name);
//ui->name->setText(timer.name);
}
// Mode
@@ -85,6 +85,7 @@ TimerPanel::TimerPanel(QWidget *parent, ModelData & model, TimerData & timer, Ge
QWidget::setTabOrder(ui->countdownBeep, ui->minuteBeep);
QWidget::setTabOrder(ui->minuteBeep, ui->persistent);
update();
lock = false;
}
@@ -95,6 +96,9 @@ TimerPanel::~TimerPanel()
void TimerPanel::update()
{
lock = true;
ui->name->setText(timer.name);
int hour = timer.val / 3600;
int min = (timer.val - (hour * 3600)) / 60;
int sec = (timer.val - (hour * 3600)) % 60;
@@ -116,7 +120,10 @@ void TimerPanel::update()
ui->persistentValue->setText(QString(" %1(%2:%3:%4)").arg(sign<0 ? "-" :" ").arg(hours, 2, 10, QLatin1Char('0')).arg(minutes, 2, 10, QLatin1Char('0')).arg(seconds, 2, 10, QLatin1Char('0')));
}
ui->countdownBeep->updateValue();
ui->minuteBeep->setChecked(timer.minuteBeep);
ui->persistent->updateValue();
lock = false;
}
QWidget * TimerPanel::getLastFocus()
@@ -126,38 +133,43 @@ QWidget * TimerPanel::getLastFocus()
void TimerPanel::on_value_editingFinished()
{
unsigned val = ui->value->time().hour()*3600 + ui->value->time().minute()*60 + ui->value->time().second();
if (timer.val != val) {
timer.val = val;
emit modified();
if (!lock) {
unsigned val = ui->value->time().hour()*3600 + ui->value->time().minute()*60 + ui->value->time().second();
if (timer.val != val) {
timer.val = val;
emit modified();
}
}
}
void TimerPanel::onModeChanged(int index)
{
if (lock)
return;
bool ok;
const RawSwitch rs(ui->mode->itemData(index).toInt(&ok));
if (ok && timer.mode.toValue() != rs.toValue()) {
timer.mode = rs;
emit modified();
if (!lock) {
bool ok;
const RawSwitch rs(ui->mode->itemData(index).toInt(&ok));
if (ok && timer.mode.toValue() != rs.toValue()) {
timer.mode = rs;
emit modified();
}
}
}
void TimerPanel::on_minuteBeep_toggled(bool checked)
{
timer.minuteBeep = checked;
emit modified();
if (!lock) {
timer.minuteBeep = checked;
emit modified();
}
}
void TimerPanel::on_name_editingFinished()
{
if (QString(timer.name) != ui->name->text()) {
int length = ui->name->maxLength();
strncpy(timer.name, ui->name->text().toLatin1(), length);
emit modified();
if (!lock) {
if (QString(timer.name) != ui->name->text()) {
int length = ui->name->maxLength();
strncpy(timer.name, ui->name->text().toLatin1(), length);
emit modified();
}
}
}
@@ -273,27 +285,12 @@ ModulePanel::~ModulePanel()
delete ui;
}
bool ModulePanel::moduleHasFailsafes()
{
return firmware->getCapability(HasFailsafe) && (
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_ISRM ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCST_ISRM_D16 ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_PXX_XJT_X16 ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_PXX_R9M ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M_LITE ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_ACCESS_R9M_LITE_PRO ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_XJT_LITE_X16 ||
(PulsesProtocol)module.protocol == PulsesProtocol::PULSES_MULTIMODULE
);
}
void ModulePanel::setupFailsafes()
{
ChannelFailsafeWidgetsGroup grp;
const int start = module.channelsStart;
const int end = start + module.channelsCount;
const bool hasFailsafe = moduleHasFailsafes();
const bool hasFailsafe = module.hasFailsafes(firmware);
lock = true;
@@ -382,48 +379,6 @@ void ModulePanel::setupFailsafes()
lock = false;
}
int ModulePanel::getMaxChannelCount()
{
const PulsesProtocol protocol = (PulsesProtocol)module.protocol;
switch (protocol) {
case PULSES_ACCESS_ISRM:
return 24;
case PULSES_PXX_R9M:
case PULSES_ACCESS_R9M:
case PULSES_ACCESS_R9M_LITE:
case PULSES_ACCESS_R9M_LITE_PRO:
case PULSES_ACCST_ISRM_D16:
case PULSES_XJT_LITE_X16:
case PULSES_PXX_XJT_X16:
case PULSES_CROSSFIRE:
case PULSES_SBUS:
case PULSES_PPM:
return 16;
case PULSES_XJT_LITE_LR12:
case PULSES_PXX_XJT_LR12:
return 12;
case PULSES_PXX_DJT:
case PULSES_XJT_LITE_D8:
case PULSES_PXX_XJT_D8:
return 8;
case PULSES_LP45:
case PULSES_DSM2:
case PULSES_DSMX:
return 6;
case PULSES_MULTIMODULE:
if (module.multi.rfProtocol == MODULE_SUBTYPE_MULTI_DSM2)
return 12;
else
return 16;
break;
case PULSES_OFF:
break;
default:
break;
}
return 8;
}
void ModulePanel::update()
{
const PulsesProtocol protocol = (PulsesProtocol)module.protocol;
@@ -510,7 +465,7 @@ void ModulePanel::update()
mask |= MASK_PPM_FIELDS | MASK_CHANNELS_RANGE | MASK_CHANNELS_COUNT;
}
if (moduleHasFailsafes()) {
if (module.hasFailsafes(firmware)) {
mask |= MASK_FAILSAFES;
}
@@ -527,7 +482,7 @@ void ModulePanel::update()
ui->label_channelsCount->setVisible(mask & MASK_CHANNELS_RANGE);
ui->channelsCount->setVisible(mask & MASK_CHANNELS_RANGE);
ui->channelsCount->setEnabled(mask & MASK_CHANNELS_COUNT);
ui->channelsCount->setMaximum(getMaxChannelCount());
ui->channelsCount->setMaximum(module.getMaxChannelCount());
ui->channelsCount->setValue(module.channelsCount);
ui->channelsCount->setSingleStep(firmware->getCapability(HasPPMStart) ? 1 : 2);
@@ -695,7 +650,7 @@ void ModulePanel::onProtocolChanged(int index)
{
if (!lock && module.protocol != ui->protocol->itemData(index).toUInt()) {
module.protocol = ui->protocol->itemData(index).toInt();
module.channelsCount = getMaxChannelCount();
module.channelsCount = module.getMaxChannelCount();
update();
emit modified();
}
@@ -790,7 +745,7 @@ void ModulePanel::onMultiProtocolChanged(int index)
if (rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
maxSubTypes=8;
module.subType = std::min(module.subType, maxSubTypes -1);
module.channelsCount = getMaxChannelCount();
module.channelsCount = module.getMaxChannelCount();
update();
emit modified();
lock = false;
@@ -1064,16 +1019,28 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
RawSwitchFilterItemModel * swModel = new RawSwitchFilterItemModel(&generalSettings, &model, RawSwitch::TimersContext, this);
connect(this, &SetupPanel::updated, swModel, &RawSwitchFilterItemModel::update);
for (int i=0; i<CPN_MAX_TIMERS; i++) {
if (i<firmware->getCapability(Timers)) {
timersCount = firmware->getCapability(Timers);
for (int i = 0; i < CPN_MAX_TIMERS; i++) {
if (i < timersCount) {
timers[i] = new TimerPanel(this, model, model.timers[i], generalSettings, firmware, prevFocus, swModel);
ui->gridLayout->addWidget(timers[i], 1+i, 1);
connect(timers[i], &TimerPanel::modified, this, &SetupPanel::modified);
connect(this, &SetupPanel::updated, timers[i], &TimerPanel::update);
connect(this, &SetupPanel::timerUpdated, timers[i], &TimerPanel::update);
prevFocus = timers[i]->getLastFocus();
// TODO more reliable method required
QLabel *label = findChild<QLabel *>(QString("label_timer%1").arg(i + 1));
if (label) { // to stop crashing if not found
label->setProperty("index", i);
label->setContextMenuPolicy(Qt::CustomContextMenu);
label->setToolTip(tr("Popup menu available"));
label->setMouseTracking(true);
connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onTimerCustomContextMenuRequested(QPoint)));
}
}
else {
foreach(QLabel *label, findChildren<QLabel *>(QRegularExpression(QString("label_timer%1").arg(i+1)))) {
foreach(QLabel *label, findChildren<QLabel *>(QRegularExpression(QString("label_timer%1").arg(i + 1 )))) { //TODO more reliable method required
label->hide();
}
}
@@ -1081,9 +1048,9 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
if (firmware->getCapability(HasTopLcd)) {
ui->toplcdTimer->setField(model.toplcdTimer, this);
for (int i=0; i<CPN_MAX_TIMERS; i++) {
if (i<firmware->getCapability(Timers)) {
ui->toplcdTimer->addItem(tr("Timer %1").arg(i+1), i);
for (int i = 0; i < CPN_MAX_TIMERS; i++) {
if (i<timersCount) {
ui->toplcdTimer->addItem(tr("Timer %1").arg(i + 1), i);
}
}
}
@@ -1528,3 +1495,155 @@ void SetupPanel::on_editText_clicked()
}
}
void SetupPanel::onTimerCustomContextMenuRequested(QPoint pos)
{
QLabel *label = (QLabel *)sender();
selectedTimerIndex = label->property("index").toInt();
QPoint globalPos = label->mapToGlobal(pos);
QMenu contextMenu;
contextMenu.addAction(CompanionIcon("copy.png"), tr("Copy"), this, SLOT(cmTimerCopy()));
contextMenu.addAction(CompanionIcon("cut.png"), tr("Cut"), this, SLOT(cmTimerCut()));
contextMenu.addAction(CompanionIcon("paste.png"), tr("Paste"), this, SLOT(cmTimerPaste()))->setEnabled(hasTimerClipboardData());
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear"), this, SLOT(cmTimerClear()));
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("arrow-right.png"), tr("Insert"), this, SLOT(cmTimerInsert()))->setEnabled(insertTimerAllowed());
contextMenu.addAction(CompanionIcon("arrow-left.png"), tr("Delete"), this, SLOT(cmTimerDelete()));
contextMenu.addAction(CompanionIcon("moveup.png"), tr("Move Up"), this, SLOT(cmTimerMoveUp()))->setEnabled(moveTimerUpAllowed());
contextMenu.addAction(CompanionIcon("movedown.png"), tr("Move Down"), this, SLOT(cmTimerMoveDown()))->setEnabled(moveTimerDownAllowed());
contextMenu.addSeparator();
contextMenu.addAction(CompanionIcon("clear.png"), tr("Clear All"), this, SLOT(cmTimerClearAll()));
contextMenu.exec(globalPos);
}
bool SetupPanel::hasTimerClipboardData(QByteArray * data) const
{
const QClipboard * clipboard = QApplication::clipboard();
const QMimeData * mimeData = clipboard->mimeData();
if (mimeData->hasFormat(MIMETYPE_TIMER)) {
if (data)
data->append(mimeData->data(MIMETYPE_TIMER));
return true;
}
return false;
}
bool SetupPanel::insertTimerAllowed() const
{
return ((selectedTimerIndex < timersCount - 1) && (model->timers[timersCount - 1].isEmpty()));
}
bool SetupPanel::moveTimerDownAllowed() const
{
return selectedTimerIndex < timersCount - 1;
}
bool SetupPanel::moveTimerUpAllowed() const
{
return selectedTimerIndex > 0;
}
void SetupPanel::cmTimerClear()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Timer. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
model->timers[selectedTimerIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, selectedTimerIndex);
emit timerUpdated();
emit modified();
}
void SetupPanel::cmTimerClearAll()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Timers. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
for (int i = 0; i < timersCount; i++) {
model->timers[i].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_CLEAR, i);
}
emit timerUpdated();
emit modified();
}
void SetupPanel::cmTimerCopy()
{
QByteArray data;
data.append((char*)&model->timers[selectedTimerIndex], sizeof(TimerData));
QMimeData *mimeData = new QMimeData;
mimeData->setData(MIMETYPE_TIMER, data);
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
}
void SetupPanel::cmTimerCut()
{
cmTimerCopy();
cmTimerClear();
}
void SetupPanel::cmTimerDelete()
{
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Delete Timer. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
return;
int maxidx = timersCount - 1;
for (int i = selectedTimerIndex; i < maxidx; i++) {
if (!model->timers[i].isEmpty() || !model->timers[i + 1].isEmpty()) {
memcpy(&model->timers[i], &model->timers[i+1], sizeof(TimerData));
}
}
model->timers[maxidx].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, -1);
emit timerUpdated();
emit modified();
}
void SetupPanel::cmTimerInsert()
{
for (int i = (timersCount - 1); i > selectedTimerIndex; i--) {
if (!model->timers[i].isEmpty() || !model->timers[i-1].isEmpty()) {
memcpy(&model->timers[i], &model->timers[i-1], sizeof(TimerData));
}
}
model->timers[selectedTimerIndex].clear();
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SHIFT, selectedTimerIndex, 0, 1);
emit timerUpdated();
emit modified();
}
void SetupPanel::cmTimerMoveDown()
{
swapTimerData(selectedTimerIndex, selectedTimerIndex + 1);
}
void SetupPanel::cmTimerMoveUp()
{
swapTimerData(selectedTimerIndex, selectedTimerIndex - 1);
}
void SetupPanel::cmTimerPaste()
{
QByteArray data;
if (hasTimerClipboardData(&data)) {
TimerData *td = &model->timers[selectedTimerIndex];
memcpy(td, data.constData(), sizeof(TimerData));
emit timerUpdated();
emit modified();
}
}
void SetupPanel::swapTimerData(int idx1, int idx2)
{
if ((idx1 != idx2) && (!model->timers[idx1].isEmpty() || !model->timers[idx2].isEmpty())) {
TimerData tdtmp = model->timers[idx2];
TimerData *td1 = &model->timers[idx1];
TimerData *td2 = &model->timers[idx2];
memcpy(td2, td1, sizeof(TimerData));
memcpy(td1, &tdtmp, sizeof(TimerData));
model->updateAllReferences(ModelData::REF_UPD_TYPE_TIMER, ModelData::REF_UPD_ACT_SWAP, idx1, idx2);
emit timerUpdated();
emit modified();
}
}
+20 -2
View File
@@ -24,6 +24,8 @@
#include "modeledit.h"
#include "eeprominterface.h"
constexpr char MIMETYPE_TIMER[] = "application/x-companion-timer";
class RawSwitchFilterItemModel;
namespace Ui {
@@ -62,7 +64,6 @@ class ModulePanel : public ModelPanel
ModulePanel(QWidget *parent, ModelData & model, ModuleData & module, GeneralSettings & generalSettings, Firmware * firmware, int moduleIdx);
virtual ~ModulePanel();
virtual void update();
bool moduleHasFailsafes();
public slots:
void onExtendedLimitsToggled();
@@ -71,7 +72,6 @@ class ModulePanel : public ModelPanel
void channelsRangeChanged();
private slots:
int getMaxChannelCount();
void setupFailsafes();
void on_trainerMode_currentIndexChanged(int index);
void onProtocolChanged(int index);
@@ -129,6 +129,7 @@ class SetupPanel : public ModelPanel
signals:
void extendedLimitsToggled();
void updated();
void timerUpdated();
private slots:
void on_name_editingFinished();
@@ -148,6 +149,16 @@ class SetupPanel : public ModelPanel
void potWarningToggled(bool checked);
void on_potWarningMode_currentIndexChanged(int index);
void on_editText_clicked();
void onTimerCustomContextMenuRequested(QPoint pos);
void cmTimerClear();
void cmTimerClearAll();
void cmTimerCopy();
void cmTimerCut();
void cmTimerDelete();
void cmTimerInsert();
void cmTimerPaste();
void cmTimerMoveDown();
void cmTimerMoveUp();
private:
Ui::Setup *ui;
@@ -161,6 +172,13 @@ class SetupPanel : public ModelPanel
void updatePotWarnings();
void updateBeepCenter();
void populateThrottleSourceCB();
int timersCount;
int selectedTimerIndex;
bool hasTimerClipboardData(QByteArray * data = nullptr) const;
bool insertTimerAllowed() const;
bool moveTimerDownAllowed() const;
bool moveTimerUpAllowed() const;
void swapTimerData(int idx1, int idx2);
};
#endif // _SETUP_H_
+1 -1
View File
@@ -590,7 +590,7 @@ If this is checked the throttle will be reversed. Idle will be forward, trim wi
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_timer3_2">
<widget class="QLabel" name="label_timer3">
<property name="font">
<font>
<weight>50</weight>