Companion update model references from enhanced context menus (#7325)
Companion update model references from enhanced context menus
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user