Merge with latest 2.3
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ['PayPal.Me/opentx']
|
|
@ -6,7 +6,7 @@ set(VERSION_REVISION "0")
|
|||
set(VERSION_SUFFIX $ENV{OPENTX_VERSION_SUFFIX})
|
||||
set(VERSION_FAMILY ${VERSION_MAJOR}.${VERSION_MINOR})
|
||||
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION}${VERSION_SUFFIX})
|
||||
set(SDCARD_REVISION "0026")
|
||||
set(SDCARD_REVISION "0028")
|
||||
set(SDCARD_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}V${SDCARD_REVISION})
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
|
30
CREDITS.txt
|
@ -11,6 +11,7 @@ Arne Schwabe (schwabe)
|
|||
|
||||
[Translators]
|
||||
[fr] Sebastien Charpentier (LapinFou)
|
||||
[es] Daniel Gorbea (dgatf)
|
||||
|
||||
[Other contributors]
|
||||
Rob Thomson
|
||||
|
@ -422,7 +423,6 @@ Pablo Gomez Martinez
|
|||
Alan Thoren
|
||||
Jack Clodfelter
|
||||
William Simon
|
||||
James Houck
|
||||
Peter Fithern
|
||||
Thomas Svedman
|
||||
TechFixPros
|
||||
|
@ -687,7 +687,6 @@ Shaun Currier
|
|||
Danilo Schiara
|
||||
John Hennig
|
||||
RK Custom Homes
|
||||
James Houck
|
||||
Piet Teekens
|
||||
Tommy Widenflycht
|
||||
Johan Petrus Theophilus
|
||||
|
@ -1707,3 +1706,30 @@ Fabrice Debonnet
|
|||
James Laver
|
||||
Kevin Bowens
|
||||
David Frech
|
||||
Udo Kastenholz
|
||||
Julio Margarido
|
||||
Uwe Muendelein
|
||||
James Jewitt
|
||||
Daniel Ferreira
|
||||
Michael Charlston
|
||||
Leopoldo Cicero
|
||||
Tom Van Driel
|
||||
Karl Vetter
|
||||
Johannes Janssen
|
||||
François Blondé
|
||||
Precision Aero
|
||||
Thomas Håkansson
|
||||
Gordon Evans
|
||||
Benny Simonsen
|
||||
George Kennedy
|
||||
Stefano Boggia
|
||||
Maksym Arshynkin
|
||||
Tomas Sodergren
|
||||
Jörg Lemnitz
|
||||
TMac FPV
|
||||
Josef Schaeffler
|
||||
Mike Frizell
|
||||
MeCodeGoodSomeday
|
||||
Timothy Fry
|
||||
John Beech
|
||||
Wojciech Winiarski
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## OpenTX 2.3 Branch
|
||||
|
||||
[](https://travis-ci.org/opentx/opentx)
|
||||
[](https://discord.gg/pAmmCp2)
|
||||
[](https://discord.gg/CZCwVx2)
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DJ9MASSKVW8WN)
|
||||
|
||||
The ongoing development on 2.3.x is done in this branch.
|
||||
|
|
|
@ -250,6 +250,7 @@ set(companion_SRCS
|
|||
wizarddialog.cpp
|
||||
styleeditdialog.cpp
|
||||
dialogs/filesyncdialog.cpp # TODO move to own lib with other dialogs
|
||||
profilechooser.cpp
|
||||
)
|
||||
|
||||
set(companion_MOC_HDRS
|
||||
|
@ -284,6 +285,7 @@ set(companion_MOC_HDRS
|
|||
styleeditdialog.h
|
||||
helpers_html.h
|
||||
dialogs/filesyncdialog.h
|
||||
profilechooser.h
|
||||
)
|
||||
|
||||
set(companion_UIS
|
||||
|
@ -305,6 +307,7 @@ set(companion_UIS
|
|||
flasheepromdialog.ui
|
||||
radionotfound.ui
|
||||
styleeditdialog.ui
|
||||
profilechooser.ui
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
|
|
@ -73,6 +73,7 @@ void AppPreferencesDialog::accept()
|
|||
g.OpenTxBranch(AppData::DownloadBranchType(ui->OpenTxBranch->currentIndex()));
|
||||
g.autoCheckFw(ui->autoCheckFirmware->isChecked());
|
||||
g.showSplash(ui->showSplash->isChecked());
|
||||
g.promptProfile(ui->chkPromptProfile->isChecked());
|
||||
g.simuSW(ui->simuSW->isChecked());
|
||||
g.removeModelSlots(ui->opt_removeBlankSlots->isChecked());
|
||||
g.newModelAction(ui->opt_newMdl_useWizard->isChecked() ? AppData::MODEL_ACT_WIZARD : ui->opt_newMdl_useEditor->isChecked() ? AppData::MODEL_ACT_EDITOR : AppData::MODEL_ACT_NONE);
|
||||
|
@ -185,6 +186,7 @@ void AppPreferencesDialog::initSettings()
|
|||
ui->autoCheckCompanion->setChecked(g.autoCheckApp());
|
||||
ui->autoCheckFirmware->setChecked(g.autoCheckFw());
|
||||
ui->showSplash->setChecked(g.showSplash());
|
||||
ui->chkPromptProfile->setChecked(g.promptProfile());
|
||||
ui->historySize->setValue(g.historySize());
|
||||
ui->backLightColor->setCurrentIndex(g.backLight());
|
||||
ui->volumeGain->setValue(profile.volumeGain() / 10.0);
|
||||
|
@ -352,6 +354,13 @@ void AppPreferencesDialog::on_ge_pathButton_clicked()
|
|||
}
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_btnClearPos_clicked()
|
||||
{
|
||||
SimulatorOptions opts = g.profile[g.sessionId()].simulatorOptions();
|
||||
opts.controlsState.clear();
|
||||
g.profile[g.sessionId()].simulatorOptions(opts);
|
||||
}
|
||||
|
||||
#if defined(JOYSTICKS)
|
||||
void AppPreferencesDialog::on_joystickChkB_clicked() {
|
||||
if (ui->joystickChkB->isChecked()) {
|
||||
|
|
|
@ -66,6 +66,7 @@ class AppPreferencesDialog : public QDialog
|
|||
void on_SplashSelect_clicked();
|
||||
void on_clearImageButton_clicked();
|
||||
void on_btn_appLogsDir_clicked();
|
||||
void on_btnClearPos_clicked();
|
||||
|
||||
#if defined(JOYSTICKS)
|
||||
void on_joystickChkB_clicked();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>741</width>
|
||||
<width>864</width>
|
||||
<height>668</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -45,7 +45,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="profileTab">
|
||||
<attribute name="title">
|
||||
|
@ -61,22 +61,40 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="optionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="4">
|
||||
<widget class="QWidget" name="widget_splashImage" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
|
@ -704,29 +722,90 @@ Mode 4:
|
|||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="7" column="1">
|
||||
<layout class="QVBoxLayout" name="updatesLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckFirmware">
|
||||
<property name="text">
|
||||
<string>Automatic check for OpenTX firmware updates</string>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="backupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<property name="text">
|
||||
<string>Enable automatic backup before writing firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckCompanion">
|
||||
<property name="text">
|
||||
<string>Automatic check for Companion updates</string>
|
||||
<item row="22" column="0">
|
||||
<widget class="QLabel" name="ge_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<property name="text">
|
||||
<string>Google Earth Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="OpenTxBranch">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Releases (stable)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Release candidates (testing)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nightly builds (unstable)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<widget class="QComboBox" name="splashincludeCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Only show user splash images</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Show user and companion splash images</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="0,1">
|
||||
|
@ -764,120 +843,27 @@ Mode 4:
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Startup Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="0">
|
||||
<widget class="QLabel" name="ge_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Google Earth Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="showSplash">
|
||||
<property name="text">
|
||||
<string>Show splash screen when Companion starts</string>
|
||||
<string>Show splash screen</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Automatic Backup Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remember</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item row="22" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="backupPath">
|
||||
<widget class="QLineEdit" name="ge_lineedit">
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="backupPathButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="libraryPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="libraryPathButton">
|
||||
<widget class="QPushButton" name="ge_pathButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -885,49 +871,13 @@ Mode 4:
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
<string>Select Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="opt_removeBlankSlots">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove empty model slots when deleting models (only applies for radios w/out categories)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="24" column="0">
|
||||
<widget class="QLabel" name="lbl_appLogsDir">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output Logs Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="23" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug Output Logging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="opt_newMdl_useWizard">
|
||||
|
@ -962,90 +912,22 @@ Mode 4:
|
|||
</layout>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QCheckBox" name="backupEnable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable automatic backup before writing firmware</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<widget class="QComboBox" name="splashincludeCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Only show user splash images</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Show user and companion splash images</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="ge_lineedit">
|
||||
<widget class="QLineEdit" name="backupPath">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ge_pathButton">
|
||||
<widget class="QPushButton" name="backupPathButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Executable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="24" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="appLogsDir">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_appLogsDir">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
|
@ -1053,14 +935,56 @@ Mode 4:
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="22" column="0" colspan="2">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remember</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<item row="25" column="0">
|
||||
<widget class="QLabel" name="lbl_appLogsDir">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output Logs Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" rowspan="3">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Startup Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="opt_removeBlankSlots">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>This option maintains the behaviour from older OpenTx versions where empty model slots are preserved when a model is deleted or moved. </p><p>When this option is de-selected, the other models may be re-arranged to fill the gap left by the removed model.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove empty model slots when deleting models (only applies for radios w/out categories)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
|
@ -1073,33 +997,7 @@ Mode 4:
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash Screen Library</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Action on New Model</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="23" column="1">
|
||||
<item row="24" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="opt_appDebugLog">
|
||||
|
@ -1123,36 +1021,163 @@ Mode 4:
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="25" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="appLogsDir">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_appLogsDir">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Action on New Model</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="libraryPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="libraryPathButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash Screen Library</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Release channel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QComboBox" name="OpenTxBranch">
|
||||
<item row="4" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="24" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Releases (stable)</string>
|
||||
<string>Debug Output Logging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="23" column="0" colspan="2">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Automatic Backup Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<layout class="QVBoxLayout" name="updatesLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckFirmware">
|
||||
<property name="text">
|
||||
<string>Automatic check for OpenTX firmware updates</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCheckCompanion">
|
||||
<property name="text">
|
||||
<string>Release candidates (testing)</string>
|
||||
<string>Automatic check for Companion updates</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="20" column="0" rowspan="2" colspan="2">
|
||||
<widget class="Line" name="line_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="chkPromptProfile">
|
||||
<property name="text">
|
||||
<string>Nightly builds (unstable)</string>
|
||||
<string>Prompt for radio profile</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -1180,7 +1205,38 @@ Mode 4:
|
|||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="5" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QDoubleSpinBox" name="volumeGain">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>3.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="joystickCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
|
@ -1193,14 +1249,20 @@ Mode 4:
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QPushButton" name="joystickcalButton">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Calibrate</string>
|
||||
<string>Screenshot capture folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="backLightColor">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -1235,31 +1297,22 @@ Mode 4:
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="9" column="3">
|
||||
<widget class="QPushButton" name="joystickcalButton">
|
||||
<property name="text">
|
||||
<string>Screenshot capture folder</string>
|
||||
<string>Calibrate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="snapshotPathButton">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="snapshotClipboardCKB">
|
||||
|
@ -1274,7 +1327,7 @@ Mode 4:
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<item row="9" column="2">
|
||||
<widget class="QCheckBox" name="joystickChkB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -1287,17 +1340,20 @@ Mode 4:
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="snapshotPathButton">
|
||||
<property name="text">
|
||||
<string>Select Folder</string>
|
||||
<item row="12" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
|
@ -1310,7 +1366,20 @@ Mode 4:
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_volumeGain">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Simulator Volume Gain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
|
@ -1348,60 +1417,30 @@ Mode 4:
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="3">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Simulator controls</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="simuSW">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remember simulator switch values</string>
|
||||
<string>Save switch/pot positions on simulator exit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_volumeGain">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="2" column="3">
|
||||
<widget class="QPushButton" name="btnClearPos">
|
||||
<property name="text">
|
||||
<string>Simulator Volume Gain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QDoubleSpinBox" name="volumeGain">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>3.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
<string>Clear saved positions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
set(firmwares_SRCS
|
||||
adjustmentreference.cpp
|
||||
boards.cpp
|
||||
curvereference.cpp
|
||||
customfunctiondata.cpp
|
||||
|
|
81
companion/src/firmwares/adjustmentreference.cpp
Normal file
|
@ -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;
|
||||
}
|
69
companion/src/firmwares/adjustmentreference.h
Normal file
|
@ -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
|
||||
|
|
|
@ -123,6 +123,12 @@ GeneralSettings::GeneralSettings()
|
|||
strcpy(bluetoothName, "taranis");
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
trainer.mix[i].mode = 2; // replace (:=)
|
||||
trainer.mix[i].src = i;
|
||||
trainer.mix[i].weight = 100;
|
||||
}
|
||||
|
||||
templateSetup = g.profile[g.sessionId()].channelOrder();
|
||||
stickMode = g.profile[g.sessionId()].defaultMode();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "macros.h"
|
||||
#include "radiodataconversionstate.h"
|
||||
#include "helpers.h"
|
||||
#include "adjustmentreference.h"
|
||||
|
||||
/*
|
||||
* TimerData
|
||||
|
@ -37,6 +38,10 @@ void TimerData::convert(RadioDataConversionState & cstate)
|
|||
mode.convert(cstate);
|
||||
}
|
||||
|
||||
bool TimerData::isEmpty()
|
||||
{
|
||||
return (mode == RawSwitch(SWITCH_TYPE_TIMER_MODE, 0) && name[0] == '\0' && minuteBeep == 0 && countdownBeep == COUNTDOWN_SILENT && val == 0 && persistent == 0 /*&& pvalue == 0*/);
|
||||
}
|
||||
|
||||
/*
|
||||
* ModelData
|
||||
|
@ -69,7 +74,7 @@ bool ModelData::isInputValid(const unsigned int idx) const
|
|||
{
|
||||
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData * expo = &expoData[i];
|
||||
if (expo->mode == 0) break;
|
||||
if (expo->mode == INPUT_MODE_NONE) break;
|
||||
if (expo->chn == idx)
|
||||
return true;
|
||||
}
|
||||
|
@ -80,7 +85,7 @@ bool ModelData::hasExpos(uint8_t inputIdx) const
|
|||
{
|
||||
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData & expo = expoData[i];
|
||||
if (expo.chn==inputIdx && expo.mode!=0) {
|
||||
if (expo.chn == inputIdx && expo.mode != INPUT_MODE_NONE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +108,7 @@ QVector<const ExpoData *> ModelData::expos(int input) const
|
|||
QVector<const ExpoData *> result;
|
||||
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
|
||||
const ExpoData * ed = &expoData[i];
|
||||
if ((int)ed->chn==input && ed->mode!=0) {
|
||||
if ((int)ed->chn == input && ed->mode != INPUT_MODE_NONE) {
|
||||
result << ed;
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +187,7 @@ void ModelData::clear()
|
|||
for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++)
|
||||
customFn[i].clear();
|
||||
for (int i = 0; i < CPN_MAX_CURVES; i++)
|
||||
curves[i].clear(5);
|
||||
curves[i].clear();
|
||||
for (int i = 0; i < CPN_MAX_TIMERS; i++)
|
||||
timers[i].clear();
|
||||
swashRingData.clear();
|
||||
|
@ -270,19 +275,68 @@ int ModelData::getTrimValue(int phaseIdx, int trimIdx)
|
|||
|
||||
bool ModelData::isGVarLinked(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
return flightModeData[phaseIdx].gvars[gvarIdx] > 1024;
|
||||
return flightModeData[phaseIdx].gvars[gvarIdx] > GVAR_MAX_VALUE;
|
||||
}
|
||||
|
||||
int ModelData::getGVarFieldValue(int phaseIdx, int gvarIdx)
|
||||
bool ModelData::isGVarLinkedCircular(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
int idx = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
for (int i=0; idx>GVAR_MAX_VALUE && i<CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int nextPhase = idx - GVAR_MAX_VALUE - 1;
|
||||
if (nextPhase >= phaseIdx) nextPhase += 1;
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int val = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
if (phaseIdx == 0 || val <= GVAR_MAX_VALUE)
|
||||
return false;
|
||||
int nextPhase = val - (GVAR_MAX_VALUE + 1);
|
||||
if (nextPhase >= phaseIdx)
|
||||
nextPhase += 1;
|
||||
phaseIdx = nextPhase;
|
||||
idx = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
}
|
||||
return idx;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ModelData::getGVarValue(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int val = flightModeData[phaseIdx].gvars[gvarIdx];
|
||||
if (phaseIdx == 0 || val <= GVAR_MAX_VALUE)
|
||||
return val;
|
||||
int nextPhase = val - (GVAR_MAX_VALUE + 1);
|
||||
if (nextPhase >= phaseIdx)
|
||||
nextPhase += 1;
|
||||
phaseIdx = nextPhase;
|
||||
}
|
||||
return flightModeData[0].gvars[gvarIdx]; // circular linked so return FM0 value
|
||||
}
|
||||
|
||||
bool ModelData::isREncLinked(int phaseIdx, int reIdx)
|
||||
{
|
||||
return flightModeData[phaseIdx].rotaryEncoders[reIdx] > RENC_MAX_VALUE;
|
||||
}
|
||||
|
||||
bool ModelData::isREncLinkedCircular(int phaseIdx, int reIdx)
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int val = flightModeData[phaseIdx].rotaryEncoders[reIdx];
|
||||
if (phaseIdx == 0 || val <= RENC_MAX_VALUE)
|
||||
return false;
|
||||
int nextPhase = val - (RENC_MAX_VALUE + 1);
|
||||
if (nextPhase >= phaseIdx)
|
||||
nextPhase += 1;
|
||||
phaseIdx = nextPhase;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int ModelData::getREncValue(int phaseIdx, int reIdx)
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
int val = flightModeData[phaseIdx].rotaryEncoders[reIdx];
|
||||
if (phaseIdx == 0 || val <= RENC_MAX_VALUE)
|
||||
return val;
|
||||
int nextPhase = val - (RENC_MAX_VALUE + 1);
|
||||
if (nextPhase >= phaseIdx)
|
||||
nextPhase += 1;
|
||||
phaseIdx = nextPhase;
|
||||
}
|
||||
return flightModeData[0].rotaryEncoders[reIdx]; // circular linked so return FM0 value
|
||||
}
|
||||
|
||||
void ModelData::setTrimValue(int phaseIdx, int trimIdx, int value)
|
||||
|
@ -364,9 +418,9 @@ bool ModelData::isAvailable(const RawSwitch & swtch) const
|
|||
}
|
||||
}
|
||||
|
||||
float ModelData::getGVarFieldValuePrec(int phaseIdx, int gvarIdx)
|
||||
float ModelData::getGVarValuePrec(int phaseIdx, int gvarIdx)
|
||||
{
|
||||
return getGVarFieldValue(phaseIdx, gvarIdx) * gvarData[gvarIdx].multiplierGet();
|
||||
return getGVarValue(phaseIdx, gvarIdx) * gvarData[gvarIdx].multiplierGet();
|
||||
}
|
||||
|
||||
void ModelData::convert(RadioDataConversionState & cstate)
|
||||
|
@ -412,3 +466,837 @@ void ModelData::convert(RadioDataConversionState & cstate)
|
|||
moduleData[i].convert(cstate.withComponentIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_REF_UPDATES 100
|
||||
|
||||
void ModelData::appendUpdateReferenceParams(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2, const int shift)
|
||||
{
|
||||
if (updRefList) {
|
||||
//qDebug() << "Append parameters - type:" << type << " action:" << action << " index1:" << index1 << " index2:" << index2 << " shift:" << shift;
|
||||
if (updRefList->size() <= MAX_REF_UPDATES)
|
||||
updRefList->append(UpdateReferenceParams(type, action, index1, index2, shift));
|
||||
else
|
||||
qDebug() << "Warning: Update ignored as the list of updates exceeds " << MAX_REF_UPDATES;
|
||||
}
|
||||
}
|
||||
|
||||
int ModelData::updateAllReferences(const ReferenceUpdateType type, const ReferenceUpdateAction action, const int index1, const int index2, const int shift)
|
||||
{
|
||||
//Stopwatch s1("ModelData::updateAllReferences");
|
||||
//s1.report("Start");
|
||||
|
||||
int loopcnt = 0;
|
||||
int updcnt = 0;
|
||||
updRefList = nullptr;
|
||||
QVector<UpdateReferenceParams> updRefParams; // declaring this variable in ModelData class crashes program on opening model file
|
||||
updRefList = &updRefParams; // so declare pointer variable in ModelData class and pass it the address of the local array
|
||||
|
||||
if (updRefList) {
|
||||
appendUpdateReferenceParams(type, action, index1, index2, shift);
|
||||
|
||||
while (!updRefList->isEmpty())
|
||||
{
|
||||
if (++loopcnt > MAX_REF_UPDATES) {
|
||||
qDebug() << "Warning: Update iterations terminated early as the list exceeded " << MAX_REF_UPDATES;
|
||||
break;
|
||||
}
|
||||
//qDebug() << "Start of iteration:" << loopcnt;
|
||||
updcnt += updateReference();
|
||||
updRefList->removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Iterations:" << loopcnt << " References updated:" << updcnt;
|
||||
//s1.report("Finish");
|
||||
|
||||
return updcnt;
|
||||
}
|
||||
|
||||
int ModelData::updateReference()
|
||||
{
|
||||
UpdateReferenceParams p = updRefList->first();
|
||||
|
||||
if (p.action < REF_UPD_ACT_CLEAR || p.action > REF_UPD_ACT_SWAP || p.type < REF_UPD_TYPE_CHANNEL || p.type > REF_UPD_TYPE_TIMER) {
|
||||
qDebug() << "Error - invalid parameters" << " > type:" << p.type << " action:" << p.action << " index1:" << p.index1 << " index2:" << p.index2 << " shift:" << p.shift;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&updRefInfo, 0, sizeof(updRefInfo));
|
||||
updRefInfo.type = p.type;
|
||||
updRefInfo.action = p.action;
|
||||
updRefInfo.index1 = abs(p.index1);
|
||||
updRefInfo.index2 = abs(p.index2);
|
||||
updRefInfo.shift = p.shift;
|
||||
|
||||
if ((updRefInfo.action == REF_UPD_ACT_SWAP && updRefInfo.index1 == updRefInfo.index2) || (updRefInfo.action == REF_UPD_ACT_SHIFT && updRefInfo.shift == 0)) {
|
||||
qDebug() << "Warning - nothing to do" << " > type:" << updRefInfo.type << " action:" << updRefInfo.action << " index1:" << updRefInfo.index1 << " index2:" << updRefInfo.index2 << " shift:" << updRefInfo.shift;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Stopwatch s1("ModelData::updateReference");
|
||||
//s1.report("Start");
|
||||
|
||||
Firmware *fw = getCurrentFirmware();
|
||||
|
||||
switch (updRefInfo.type)
|
||||
{
|
||||
case REF_UPD_TYPE_CHANNEL:
|
||||
updRefInfo.srcType = SOURCE_TYPE_CH;
|
||||
updRefInfo.maxindex = fw->getCapability(Outputs);
|
||||
break;
|
||||
case REF_UPD_TYPE_CURVE:
|
||||
updRefInfo.maxindex = fw->getCapability(NumCurves);
|
||||
break;
|
||||
case REF_UPD_TYPE_FLIGHT_MODE:
|
||||
updRefInfo.swtchType = SWITCH_TYPE_FLIGHT_MODE;
|
||||
updRefInfo.maxindex = fw->getCapability(FlightModes);
|
||||
break;
|
||||
case REF_UPD_TYPE_GLOBAL_VARIABLE:
|
||||
updRefInfo.srcType = SOURCE_TYPE_GVAR;
|
||||
updRefInfo.maxindex = fw->getCapability(Gvars);
|
||||
break;
|
||||
case REF_UPD_TYPE_INPUT:
|
||||
updRefInfo.srcType = SOURCE_TYPE_VIRTUAL_INPUT;
|
||||
updRefInfo.maxindex = fw->getCapability(VirtualInputs);
|
||||
break;
|
||||
case REF_UPD_TYPE_LOGICAL_SWITCH:
|
||||
updRefInfo.srcType = SOURCE_TYPE_CUSTOM_SWITCH;
|
||||
updRefInfo.swtchType = SWITCH_TYPE_VIRTUAL;
|
||||
updRefInfo.maxindex = fw->getCapability(LogicalSwitches);
|
||||
break;
|
||||
case REF_UPD_TYPE_SCRIPT:
|
||||
updRefInfo.srcType = SOURCE_TYPE_LUA_OUTPUT;
|
||||
updRefInfo.maxindex = fw->getCapability(LuaScripts);
|
||||
break;
|
||||
case REF_UPD_TYPE_SENSOR:
|
||||
updRefInfo.srcType = SOURCE_TYPE_TELEMETRY;
|
||||
updRefInfo.swtchType = SWITCH_TYPE_SENSOR;
|
||||
updRefInfo.maxindex = fw->getCapability(Sensors);
|
||||
break;
|
||||
case REF_UPD_TYPE_TIMER:
|
||||
updRefInfo.srcType = SOURCE_TYPE_SPECIAL;
|
||||
updRefInfo.maxindex = fw->getCapability(Timers);
|
||||
// rawsource index offset TODO refactor timers so be own category
|
||||
updRefInfo.index1 += 2;
|
||||
updRefInfo.index2 += 2;
|
||||
updRefInfo.maxindex += 2;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled reference type:" << updRefInfo.type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
updRefInfo.maxindex--; // getCapabilities and constants are 1 based
|
||||
|
||||
//qDebug() << "updRefInfo - type:" << updRefInfo.type << " action:" << updRefInfo.action << " index1:" << updRefInfo.index1 << " index2:" << updRefInfo.index2 << " shift:" << updRefInfo.shift;
|
||||
//qDebug() << "maxindex:" << updRefInfo.maxindex << "updRefInfo - srcType:" << updRefInfo.srcType << " swtchType:" << updRefInfo.swtchType;
|
||||
|
||||
//s1.report("Initialise");
|
||||
|
||||
for (int i = fw->getCapability(NumFirstUsableModule); i < fw->getCapability(NumModules); i++) {
|
||||
ModuleData *md = &moduleData[i];
|
||||
if (md->protocol != PULSES_OFF && md->failsafeMode == FAILSAFE_CUSTOM && md->hasFailsafes(fw))
|
||||
updateModuleFailsafes(md);
|
||||
}
|
||||
//s1.report("Modules");
|
||||
|
||||
for (int i = 0; i < CPN_MAX_TIMERS; i++) {
|
||||
TimerData *td = &timers[i];
|
||||
if (!td->isModeOff()) {
|
||||
updateTimerMode(td->mode);
|
||||
if (td->isModeOff())
|
||||
appendUpdateReferenceParams(REF_UPD_TYPE_TIMER, REF_UPD_ACT_CLEAR, i);
|
||||
}
|
||||
}
|
||||
//s1.report("Timers");
|
||||
|
||||
for (int i = 1; i < CPN_MAX_FLIGHT_MODES; i++) { // skip FM0 as switch not used
|
||||
FlightModeData *fmd = &flightModeData[i];
|
||||
if (fmd->swtch.isSet()) {
|
||||
updateSwitchRef(fmd->swtch);
|
||||
if(!fmd->swtch.isSet())
|
||||
appendUpdateReferenceParams(REF_UPD_TYPE_FLIGHT_MODE, REF_UPD_ACT_CLEAR, i);
|
||||
}
|
||||
}
|
||||
//s1.report("Flight Modes");
|
||||
|
||||
for (int i = 0; i < CPN_MAX_EXPOS; i++) {
|
||||
ExpoData *ed = &expoData[i];
|
||||
if (!ed->isEmpty()) {
|
||||
updateSourceRef(ed->srcRaw);
|
||||
if (ed->srcRaw.isSet()) {
|
||||
updateSwitchRef(ed->swtch);
|
||||
updateCurveRef(ed->curve);
|
||||
updateAdjustRef(ed->weight);
|
||||
updateAdjustRef(ed->offset);
|
||||
updateFlightModeFlags(ed->flightModes);
|
||||
}
|
||||
else {
|
||||
unsigned int chnsave = ed->chn;
|
||||
removeInput(i);
|
||||
i--;
|
||||
if (!hasExpos(chnsave))
|
||||
appendUpdateReferenceParams(REF_UPD_TYPE_INPUT, REF_UPD_ACT_CLEAR, chnsave);
|
||||
}
|
||||
}
|
||||
}
|
||||
//s1.report("Inputs");
|
||||
|
||||
for (int i = 0; i < CPN_MAX_MIXERS; i++) {
|
||||
MixData *md = &mixData[i];
|
||||
if (!md->isEmpty()) {
|
||||
updateDestCh(md);
|
||||
if (!md->isEmpty()) {
|
||||
updateSourceRef(md->srcRaw);
|
||||
if (md->srcRaw.isSet()) {
|
||||
updateSwitchRef(md->swtch);
|
||||
updateCurveRef(md->curve);
|
||||
updateAdjustRef(md->weight);
|
||||
updateAdjustRef(md->sOffset);
|
||||
updateFlightModeFlags(md->flightModes);
|
||||
}
|
||||
else {
|
||||
removeMix(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//s1.report("Mixes");
|
||||
|
||||
for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
|
||||
LimitData *ld = &limitData[i];
|
||||
if (!ld->isEmpty()) {
|
||||
updateAdjustRef(ld->min);
|
||||
updateAdjustRef(ld->max);
|
||||
updateAdjustRef(ld->offset);
|
||||
updateLimitCurveRef(ld->curve);
|
||||
}
|
||||
}
|
||||
//s1.report("Outputs");
|
||||
|
||||
for (int i = 0; i < CPN_MAX_LOGICAL_SWITCHES; i++) {
|
||||
LogicalSwitchData *lsd = &logicalSw[i];
|
||||
if (!lsd->isEmpty()) {
|
||||
bool clearlsd = false;
|
||||
CSFunctionFamily family = lsd->getFunctionFamily();
|
||||
switch(family) {
|
||||
case LS_FAMILY_VOFS:
|
||||
updateSourceIntRef(lsd->val1);
|
||||
if (lsd->val1 == 0)
|
||||
clearlsd = true;
|
||||
break;
|
||||
case LS_FAMILY_STICKY:
|
||||
case LS_FAMILY_VBOOL:
|
||||
updateSwitchIntRef(lsd->val1);
|
||||
updateSwitchIntRef(lsd->val2);
|
||||
if (lsd->val1 == 0 && lsd->val2 == 0)
|
||||
clearlsd = true;
|
||||
break;
|
||||
case LS_FAMILY_EDGE:
|
||||
updateSwitchIntRef(lsd->val1);
|
||||
if (lsd->val1 == 0)
|
||||
clearlsd = true;
|
||||
break;
|
||||
case LS_FAMILY_VCOMP:
|
||||
updateSourceIntRef(lsd->val1);
|
||||
updateSourceIntRef(lsd->val2);
|
||||
if (lsd->val1 == 0 && lsd->val2 == 0)
|
||||
clearlsd = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (clearlsd) {
|
||||
lsd->clear();
|
||||
appendUpdateReferenceParams(REF_UPD_TYPE_LOGICAL_SWITCH, REF_UPD_ACT_CLEAR, i);
|
||||
}
|
||||
else {
|
||||
updateSwitchIntRef(lsd->andsw);
|
||||
}
|
||||
}
|
||||
}
|
||||
//s1.report("Logical Switches");
|
||||
|
||||
for (int i = 0; i < CPN_MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
CustomFunctionData *cfd = &customFn[i];
|
||||
if (!cfd->isEmpty()) {
|
||||
updateAssignFunc(cfd);
|
||||
if (!cfd->isEmpty()) {
|
||||
updateSwitchRef(cfd->swtch);
|
||||
if (cfd->func == FuncVolume || cfd->func == FuncPlayValue || (cfd->func >= FuncAdjustGV1 && cfd->func <= FuncAdjustGVLast && (cfd->adjustMode == FUNC_ADJUST_GVAR_GVAR || cfd->adjustMode == FUNC_ADJUST_GVAR_SOURCE))) {
|
||||
updateSourceIntRef(cfd->param);
|
||||
if (cfd->param == 0)
|
||||
cfd->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//s1.report("Special Functions");
|
||||
|
||||
if (fw->getCapability(Heli)) {
|
||||
updateSourceRef(swashRingData.aileronSource);
|
||||
updateSourceRef(swashRingData.collectiveSource);
|
||||
updateSourceRef(swashRingData.elevatorSource);
|
||||
//s1.report("Heli");
|
||||
}
|
||||
|
||||
if (fw->getCapability(Telemetry)) {
|
||||
updateTelemetryRef(frsky.voltsSource);
|
||||
updateTelemetryRef(frsky.altitudeSource);
|
||||
updateTelemetryRef(frsky.currentSource);
|
||||
updateTelemetryRef(frsky.varioSource);
|
||||
for (int i = 0; i < fw->getCapability(TelemetryCustomScreens); i++) {
|
||||
switch(frsky.screens[i].type) {
|
||||
case TELEMETRY_SCREEN_BARS:
|
||||
for (int j = 0; j < fw->getCapability(TelemetryCustomScreensBars); j++) {
|
||||
FrSkyBarData *fbd = &frsky.screens[i].body.bars[j];
|
||||
updateSourceRef(fbd->source);
|
||||
if (!fbd->source.isSet()) {
|
||||
fbd->barMin = 0;
|
||||
fbd->barMax = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TELEMETRY_SCREEN_NUMBERS:
|
||||
for (int j = 0; j < fw->getCapability(TelemetryCustomScreensLines); j++) {
|
||||
FrSkyLineData *fld = &frsky.screens[i].body.lines[j];
|
||||
for (int k = 0; k < fw->getCapability(TelemetryCustomScreensFieldsPerLine); k++) {
|
||||
updateSourceRef(fld->source[k]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//s1.report("Telemetry");
|
||||
}
|
||||
|
||||
// TODO maybe less risk to leave it up to the user??
|
||||
/*
|
||||
for (int i = 0; i < CPN_MAX_SENSORS; i++) {
|
||||
SensorData *sd = &sensorData[i];
|
||||
if (sd->isAvailable() && sd->type == SensorData::TELEM_TYPE_CALCULATED) {
|
||||
}
|
||||
}
|
||||
s1.report("Telemetry Sensors");
|
||||
*/
|
||||
|
||||
// TODO needs lua incorporated into Companion as script needs to be parsed to determine if input field is source or value
|
||||
/*
|
||||
for (int i=0; i < CPN_MAX_SCRIPTS; i++) {
|
||||
ScriptData *sd = &scriptData[i];
|
||||
if (sd->filename[0] != '\0') {
|
||||
for (int j = 0; j < CPN_MAX_SCRIPT_INPUTS; j++) {
|
||||
// get input parameters and for each one where type is SOURCE
|
||||
if(inputtype = "SOURCE")
|
||||
updateSourceIntRef(sd->inputs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
s1.report("Custom Scripts");
|
||||
*/
|
||||
|
||||
// TODO Horus CustomScreenData and TopBarData will need checking for updates but Companion does not current handle ie just data blobs refer modeldata.h
|
||||
|
||||
qDebug() << "References updated this iteration:" << updRefInfo.updcnt;
|
||||
//s1.report("Finish");
|
||||
|
||||
return updRefInfo.updcnt;
|
||||
}
|
||||
|
||||
template <class R, typename T>
|
||||
void ModelData::updateTypeIndexRef(R & curRef, const T type, const int idxAdj, const bool defClear, const int defType, const int defIndex)
|
||||
{
|
||||
//qDebug() << "Raw value: " << curRef.toValue() << " String:" << curRef.toString() << " Type: " << curRef.type << " Index:" << curRef.index << " idxAdj:" << idxAdj << " defClear:" << defClear << " defType:" << defType << " defIndex:" << defIndex;
|
||||
if (!curRef.isSet() || curRef.type != type)
|
||||
return;
|
||||
|
||||
R newRef;
|
||||
newRef.type = curRef.type;
|
||||
newRef.index = abs(curRef.index);
|
||||
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
if (newRef.index != (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
if (defClear)
|
||||
newRef.clear();
|
||||
else {
|
||||
newRef.type = (T)defType;
|
||||
newRef.index = defIndex;
|
||||
}
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if (newRef.index < (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
|
||||
newRef.index += updRefInfo.shift;
|
||||
|
||||
if (newRef.index < (updRefInfo.index1 + idxAdj) || newRef.index > (updRefInfo.maxindex + idxAdj)) {
|
||||
if (defClear)
|
||||
newRef.clear();
|
||||
else {
|
||||
newRef.type = (T)defType;
|
||||
newRef.index = defIndex;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
if (newRef.index == updRefInfo.index1 + idxAdj)
|
||||
newRef.index = updRefInfo.index2 + idxAdj;
|
||||
else if (newRef.index == updRefInfo.index2 + idxAdj)
|
||||
newRef.index = updRefInfo.index1 + idxAdj;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
if (curRef.type != newRef.type || abs(curRef.index) != newRef.index) {
|
||||
newRef.index = curRef.index < 0 ? -newRef.index : newRef.index;
|
||||
//qDebug() << "Updated reference: " << curRef.toString() << " -> " << newRef.toString();
|
||||
curRef = newRef;
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class R, typename T>
|
||||
void ModelData::updateTypeValueRef(R & curRef, const T type, const int idxAdj, const bool defClear, const int defType, const int defValue)
|
||||
{
|
||||
//qDebug() << " String:" << curRef.toString() << " Type: " << curRef.type << " Value:" << curRef.value;
|
||||
if (!curRef.isSet() || curRef.type != type)
|
||||
return;
|
||||
|
||||
R newRef;
|
||||
newRef.type = curRef.type;
|
||||
newRef.value = abs(curRef.value);
|
||||
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
if (newRef.value != (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
if (defClear)
|
||||
newRef.clear();
|
||||
else {
|
||||
newRef.type = (T)defType;
|
||||
newRef.value = defValue;
|
||||
}
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if (newRef.value < (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
|
||||
newRef.value += updRefInfo.shift;
|
||||
|
||||
if (newRef.value < (updRefInfo.index1 + idxAdj) || newRef.value > (updRefInfo.maxindex + idxAdj)) {
|
||||
if (defClear)
|
||||
newRef.clear();
|
||||
else {
|
||||
newRef.type = (T)defType;
|
||||
newRef.value = defValue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
if (newRef.value == updRefInfo.index1 + idxAdj)
|
||||
newRef.value = updRefInfo.index2 + idxAdj;
|
||||
else if (newRef.value == updRefInfo.index2 + idxAdj)
|
||||
newRef.value = updRefInfo.index1 + idxAdj;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
if (curRef.type != newRef.type || abs(curRef.value) != newRef.value) {
|
||||
newRef.value = curRef.value < 0 ? -newRef.value : newRef.value;
|
||||
//qDebug() << "Updated reference: " << curRef.toString() << " -> " << newRef.toString();
|
||||
curRef = newRef;
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::updateCurveRef(CurveReference & crv)
|
||||
{
|
||||
if (updRefInfo.type == REF_UPD_TYPE_GLOBAL_VARIABLE && (crv.type == CurveReference::CURVE_REF_DIFF || crv.type == CurveReference::CURVE_REF_EXPO))
|
||||
updateAdjustRef(crv.value);
|
||||
else if (updRefInfo.type == REF_UPD_TYPE_CURVE && crv.type == CurveReference::CURVE_REF_CUSTOM)
|
||||
updateTypeValueRef<CurveReference, CurveReference::CurveRefType>(crv, CurveReference::CURVE_REF_CUSTOM, 1);
|
||||
}
|
||||
|
||||
void ModelData::updateLimitCurveRef(CurveReference & crv)
|
||||
{
|
||||
CurveReference src = CurveReference(CurveReference::CURVE_REF_CUSTOM, crv.value);
|
||||
updateCurveRef(src);
|
||||
if (crv.value != src.value)
|
||||
crv.value = src.value;
|
||||
}
|
||||
|
||||
void ModelData::updateAdjustRef(int & value)
|
||||
{
|
||||
if (updRefInfo.type != REF_UPD_TYPE_GLOBAL_VARIABLE)
|
||||
return;
|
||||
|
||||
AdjustmentReference adj = AdjustmentReference(value);
|
||||
updateTypeValueRef<AdjustmentReference, AdjustmentReference::AdjustRefType>(adj, AdjustmentReference::ADJUST_REF_GVAR, 1);
|
||||
if (value != adj.toValue())
|
||||
value = adj.toValue();
|
||||
}
|
||||
|
||||
void ModelData::updateAssignFunc(CustomFunctionData * cfd)
|
||||
{
|
||||
const int invalidateRef = -1;
|
||||
int newRef = (int)cfd->func;
|
||||
int idxAdj;
|
||||
|
||||
switch (updRefInfo.type)
|
||||
{
|
||||
case REF_UPD_TYPE_CHANNEL:
|
||||
if(cfd->func < FuncOverrideCH1 || cfd->func > FuncOverrideCH32) // TODO refactor to FuncOverrideCHLast
|
||||
return;
|
||||
idxAdj = FuncOverrideCH1;
|
||||
break;
|
||||
case REF_UPD_TYPE_GLOBAL_VARIABLE:
|
||||
if (cfd->func < FuncAdjustGV1 || cfd->func > FuncAdjustGVLast)
|
||||
return;
|
||||
idxAdj = FuncAdjustGV1;
|
||||
break;
|
||||
case REF_UPD_TYPE_TIMER:
|
||||
if (cfd->func < FuncSetTimer1 || cfd->func > FuncSetTimer3) // TODO refactor to FuncSetTimerLast
|
||||
return;
|
||||
idxAdj = FuncSetTimer1 - 2; // reverse earlier offset requiured for rawsource
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
if (newRef != (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
newRef = invalidateRef;
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if (newRef < (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
|
||||
newRef += updRefInfo.shift;
|
||||
|
||||
if (newRef < (updRefInfo.index1 + idxAdj) || newRef > (updRefInfo.maxindex + idxAdj))
|
||||
newRef = invalidateRef;
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
if (newRef == updRefInfo.index1 + idxAdj)
|
||||
newRef = updRefInfo.index2 + idxAdj;
|
||||
else if (newRef == updRefInfo.index2 + idxAdj)
|
||||
newRef = updRefInfo.index1 + idxAdj;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
if (newRef == invalidateRef) {
|
||||
cfd->clear();
|
||||
//qDebug() << "Function cleared";
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
else if (cfd->func != (AssignFunc)newRef) {
|
||||
//qDebug() << "Updated reference:" << cfd->func << " -> " << newRef;
|
||||
cfd->func = (AssignFunc)newRef;
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::updateDestCh(MixData * md)
|
||||
{
|
||||
if (updRefInfo.type != REF_UPD_TYPE_CHANNEL)
|
||||
return;
|
||||
|
||||
const int invalidateRef = -1;
|
||||
const int idxAdj = 1;
|
||||
int newRef = md->destCh;
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
if (newRef != (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
newRef = invalidateRef;
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if (newRef < (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
|
||||
newRef += updRefInfo.shift;
|
||||
|
||||
if (newRef < (updRefInfo.index1 + idxAdj) || newRef > (updRefInfo.maxindex + idxAdj))
|
||||
newRef = invalidateRef;
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
if (newRef == updRefInfo.index1 + idxAdj)
|
||||
newRef = updRefInfo.index2 + idxAdj;
|
||||
else if (newRef == updRefInfo.index2 + idxAdj)
|
||||
newRef = updRefInfo.index1 + idxAdj;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
if (newRef == invalidateRef) {
|
||||
md->clear();
|
||||
//qDebug() << "Mix cleared";
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
else if (md->destCh != static_cast<unsigned int>(newRef)) {
|
||||
//qDebug() << "Updated reference:" << md->destCh << " -> " << newRef;
|
||||
md->destCh = newRef;
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::updateFlightModeFlags(unsigned int & curRef)
|
||||
{
|
||||
if (updRefInfo.type != REF_UPD_TYPE_FLIGHT_MODE || curRef == 0 /*all selected*/ || curRef == 511 /*all deselected*/)
|
||||
return;
|
||||
|
||||
if (updRefInfo.index1 > CPN_MAX_FLIGHT_MODES || updRefInfo.index2 > CPN_MAX_FLIGHT_MODES)
|
||||
return;
|
||||
|
||||
unsigned int newRef = curRef;
|
||||
bool flag[CPN_MAX_FLIGHT_MODES];
|
||||
bool f;
|
||||
|
||||
int mask = 1;
|
||||
for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
flag[i] = curRef & mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
flag[updRefInfo.index1] = false;
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if(updRefInfo.shift < 0) {
|
||||
for (int i = updRefInfo.index1; i < CPN_MAX_FLIGHT_MODES; i++) {
|
||||
if (i - updRefInfo.shift <= updRefInfo.maxindex)
|
||||
flag[i] = flag[i - updRefInfo.shift];
|
||||
else
|
||||
flag[i] = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= updRefInfo.index1; i--) {
|
||||
if (i - updRefInfo.shift >= updRefInfo.index1)
|
||||
flag[i] = flag[i - updRefInfo.shift];
|
||||
else
|
||||
flag[i] = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
f = flag[updRefInfo.index1];
|
||||
flag[updRefInfo.index1] = flag[updRefInfo.index2];
|
||||
flag[updRefInfo.index2] = f;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
newRef = 0;
|
||||
for (int i = CPN_MAX_FLIGHT_MODES - 1; i >= 0 ; i--) {
|
||||
if (flag[i])
|
||||
newRef++;
|
||||
newRef <<= 1;
|
||||
}
|
||||
newRef >>= 1;
|
||||
|
||||
if (curRef != newRef) {
|
||||
//qDebug() << "Updated reference:" << curRef << " -> " << newRef;
|
||||
curRef = newRef;
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::updateTelemetryRef(unsigned int & curRef)
|
||||
{
|
||||
if (updRefInfo.type != REF_UPD_TYPE_SENSOR)
|
||||
return;
|
||||
|
||||
const int idxAdj = 1;
|
||||
int newRef = curRef;
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
if (newRef != (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
newRef = 0;
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if (newRef < (updRefInfo.index1 + idxAdj))
|
||||
return;
|
||||
|
||||
newRef += updRefInfo.shift;
|
||||
|
||||
if (newRef < (updRefInfo.index1 + idxAdj) || newRef > (updRefInfo.maxindex + idxAdj))
|
||||
newRef = 0;
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
if (newRef == updRefInfo.index1 + idxAdj)
|
||||
newRef = updRefInfo.index2 + idxAdj;
|
||||
else if (newRef == updRefInfo.index2 + idxAdj)
|
||||
newRef = updRefInfo.index1 + idxAdj;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
if (curRef != static_cast<unsigned int>(newRef)) {
|
||||
//qDebug() << "Updated reference:" << curRef << " -> " << newRef;
|
||||
curRef = newRef;
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelData::updateModuleFailsafes(ModuleData * md)
|
||||
{
|
||||
if (updRefInfo.type != REF_UPD_TYPE_CHANNEL)
|
||||
return;
|
||||
|
||||
bool updated = false;
|
||||
|
||||
switch (updRefInfo.action)
|
||||
{
|
||||
case REF_UPD_ACT_CLEAR:
|
||||
break;
|
||||
case REF_UPD_ACT_SHIFT:
|
||||
if (updRefInfo.shift == 0 || updRefInfo.index1 < 0 || updRefInfo.index1 > CPN_MAX_CHNOUT - 1)
|
||||
return;
|
||||
|
||||
if (updRefInfo.shift > 0) {
|
||||
for (int i = (CPN_MAX_CHNOUT - 1); i > updRefInfo.index1; i--) {
|
||||
md->failsafeChannels[i] = md->failsafeChannels[i - 1];
|
||||
}
|
||||
md->failsafeChannels[updRefInfo.index1] = 0;
|
||||
}
|
||||
else {
|
||||
for (int i = (updRefInfo.index1 + 1); i < (CPN_MAX_CHNOUT - 1); i++) {
|
||||
md->failsafeChannels[i - 1] = md->failsafeChannels[i];
|
||||
}
|
||||
md->failsafeChannels[CPN_MAX_CHNOUT - 1] = 0;
|
||||
}
|
||||
updated = true;
|
||||
break;
|
||||
case REF_UPD_ACT_SWAP:
|
||||
int tmp;
|
||||
if (updRefInfo.index1 >= 0 && updRefInfo.index1 < CPN_MAX_CHNOUT) {
|
||||
updated = true;
|
||||
tmp = md->failsafeChannels[updRefInfo.index1];
|
||||
if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT)
|
||||
md->failsafeChannels[updRefInfo.index1] = md->failsafeChannels[updRefInfo.index2];
|
||||
else
|
||||
md->failsafeChannels[updRefInfo.index1] = 0;
|
||||
}
|
||||
else
|
||||
tmp = 0;
|
||||
if (updRefInfo.index2 >= 0 && updRefInfo.index2 < CPN_MAX_CHNOUT)
|
||||
updated = true;
|
||||
md->failsafeChannels[updRefInfo.index2] = tmp;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Error - unhandled action:" << updRefInfo.action;
|
||||
return;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
//qDebug() << "Updated module failsafes";
|
||||
updRefInfo.updcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
int ModelData::linkedFlightModeIndexToValue(const int phaseIdx, const int useFmIdx, const int maxOwnValue)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (phaseIdx == useFmIdx || phaseIdx < 0 || phaseIdx > (CPN_MAX_FLIGHT_MODES - 1) || useFmIdx < 0 || useFmIdx > (CPN_MAX_FLIGHT_MODES - 1))
|
||||
val = flightModeData[phaseIdx].linkedFlightModeZero(phaseIdx, maxOwnValue);
|
||||
else
|
||||
val = maxOwnValue + useFmIdx + (useFmIdx >= phaseIdx ? 0 : 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int ModelData::linkedFlightModeValueToIndex(const int phaseIdx, const int val, const int maxOwnValue)
|
||||
{
|
||||
int idx = val - maxOwnValue - 1;
|
||||
if (idx >= phaseIdx)
|
||||
idx += 1;
|
||||
return idx;
|
||||
}
|
||||
|
||||
int ModelData::getGVarFlightModeIndex(const int phaseIdx, const int gvarIdx)
|
||||
{
|
||||
if (!isGVarLinked(phaseIdx, gvarIdx))
|
||||
return -1;
|
||||
return (linkedFlightModeValueToIndex(phaseIdx, flightModeData[phaseIdx].gvars[gvarIdx], GVAR_MAX_VALUE));
|
||||
}
|
||||
|
||||
void ModelData::setGVarFlightModeIndexToValue(const int phaseIdx, const int gvarIdx, const int useFmIdx)
|
||||
{
|
||||
flightModeData[phaseIdx].gvars[gvarIdx] = linkedFlightModeIndexToValue(phaseIdx, useFmIdx, GVAR_MAX_VALUE);
|
||||
}
|
||||
|
||||
int ModelData::getREncFlightModeIndex(const int phaseIdx, const int reIdx)
|
||||
{
|
||||
if (!isREncLinked(phaseIdx, reIdx))
|
||||
return -1;
|
||||
return (linkedFlightModeValueToIndex(phaseIdx, flightModeData[phaseIdx].rotaryEncoders[reIdx], RENC_MAX_VALUE));
|
||||
}
|
||||
|
||||
void ModelData::setREncFlightModeIndexToValue(const int phaseIdx, const int reIdx, const int useFmIdx)
|
||||
{
|
||||
flightModeData[phaseIdx].rotaryEncoders[reIdx] = linkedFlightModeIndexToValue(phaseIdx, useFmIdx, RENC_MAX_VALUE);
|
||||
}
|
||||
|
||||
bool ModelData::isExpoParent(const int index)
|
||||
{
|
||||
const ExpoData &ed = expoData[index];
|
||||
const QVector<const ExpoData *> chexpos = expos(ed.chn);
|
||||
return chexpos.constFirst() == &ed;
|
||||
}
|
||||
|
||||
bool ModelData::isExpoChild(const int index)
|
||||
{
|
||||
const ExpoData &ed = expoData[index];
|
||||
const QVector<const ExpoData *> chexpos = expos(ed.chn);
|
||||
return chexpos.constFirst() != &ed;
|
||||
}
|
||||
|
||||
bool ModelData::hasExpoChildren(const int index)
|
||||
{
|
||||
const ExpoData &ed = expoData[index];
|
||||
const QVector<const ExpoData *> chexpos = expos(ed.chn);
|
||||
return chexpos.constFirst() == &ed && chexpos.constLast() != &ed;
|
||||
}
|
||||
|
||||
bool ModelData::hasExpoSiblings(const int index)
|
||||
{
|
||||
const ExpoData &ed = expoData[index];
|
||||
const QVector<const ExpoData *> chexpos = expos(ed.chn);
|
||||
return !isExpoParent(index) && chexpos.size() > 2;
|
||||
}
|
||||
|
||||
void ModelData::removeMix(const int idx)
|
||||
{
|
||||
memmove(&mixData[idx], &mixData[idx + 1], (CPN_MAX_MIXERS - (idx + 1)) * sizeof(MixData));
|
||||
mixData[CPN_MAX_MIXERS - 1].clear();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -119,7 +119,20 @@ enum MultiModuleRFProtocols {
|
|||
MODULE_SUBTYPE_MULTI_AFHDS2A_RX,
|
||||
MODULE_SUBTYPE_MULTI_HOTT,
|
||||
MODULE_SUBTYPE_MULTI_FX816,
|
||||
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_FX816
|
||||
MODULE_SUBTYPE_MULTI_BAYANG_RX,
|
||||
MODULE_SUBTYPE_MULTI_PELIKAN,
|
||||
MODULE_SUBTYPE_MULTI_TIGER,
|
||||
MODULE_SUBTYPE_MULTI_XK,
|
||||
MODULE_SUBTYPE_MULTI_XN297DUMP,
|
||||
MODULE_SUBTYPE_MULTI_FRSKYX2,
|
||||
MODULE_SUBTYPE_MULTI_FRSKY_R9,
|
||||
MODULE_SUBTYPE_MULTI_PROPEL,
|
||||
MODULE_SUBTYPE_MULTI_FRSKYL,
|
||||
MODULE_SUBTYPE_MULTI_SKYARTEC,
|
||||
MODULE_SUBTYPE_MULTI_ESKY150V2,
|
||||
MODULE_SUBTYPE_MULTI_DSM_RX,
|
||||
MODULE_SUBTYPE_MULTI_JJRC345,
|
||||
MODULE_SUBTYPE_MULTI_LAST = MODULE_SUBTYPE_MULTI_JJRC345
|
||||
};
|
||||
|
||||
enum TrainerProtocol {
|
||||
|
@ -197,6 +210,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
|
||||
|
|
|
@ -39,7 +39,7 @@ static const QStringList STR_SUBTYPE_CUSTOM ({
|
|||
});
|
||||
static const QStringList STR_SUBTYPE_FLYSKY {"Standard", "V9x9", "V6x6", "V912", "CX20"};
|
||||
static const QStringList STR_SUBTYPE_HUBSAN {"H107", "H301", "H501"};
|
||||
static const QStringList STR_SUBTYPE_FRSKY {"D16", "D8", "D16 8ch", "V8", "D16 EU-LBT", "D16 EU-LBT 8ch"};
|
||||
static const QStringList STR_SUBTYPE_FRSKY {"D16", "D8", "D16 8ch", "V8", "D16 EU-LBT", "D16 EU-LBT 8ch", "D8 Cloned", "D16 Cloned"};
|
||||
static const QStringList STR_SUBTYPE_HISKY {"Standard", "HK310"};
|
||||
static const QStringList STR_SUBTYPE_V2X2 {"Standard", "JXD506"};
|
||||
static const QStringList STR_SUBTYPE_DSM {"DSM2 22ms", "DSM2 11ms", "DSMX 22ms", "DSMX 11ms"};
|
||||
|
@ -51,6 +51,7 @@ static const QStringList STR_SUBTYPE_SLT {"V1 (6 Channel)", "V2 (8 Channel
|
|||
static const QStringList STR_SUBTYPE_CX10 {"Green", "Blue", "DM007", "-", "JC3015a", "JC3015b", "MK33041"};
|
||||
static const QStringList STR_SUBTYPE_CG023 {"Standard", "YD829"};
|
||||
static const QStringList STR_SUBTYPE_BAYANG {"Standard", "H8S3D", "X16 AH", "IRDRONE", "DHD D4"};
|
||||
static const QStringList STR_SUBTYPE_ESky {"Standard", "ET4"};
|
||||
static const QStringList STR_SUBTYPE_MT99 {"MT99", "H7", "YZ", "LS", "FY805"};
|
||||
static const QStringList STR_SUBTYPE_MJXQ {"WLH08", "X600", "X800", "H26D", "E010", "H26WH", "Phoenix"};
|
||||
static const QStringList STR_SUBTYPE_FY326 {"Standard", "FY319"};
|
||||
|
@ -60,20 +61,29 @@ static const QStringList STR_SUBTYPE_Q2X2 {"Q222", "Q242", "Q282"};
|
|||
static const QStringList STR_SUBTYPE_WK2x01 {"WK2801", "WK2401", "W6_5_1", "W6_6_1", "W6_HEL", "W6_HEL_I"};
|
||||
static const QStringList STR_SUBTYPE_Q303 {"Standard", "CX35", "CX10D", "CX10WD"};
|
||||
static const QStringList STR_SUBTYPE_CABELL {"Cabell V3", "Cab V3 Telem", "-", "-", "-", "-", "Set FailSafe", "Unbind"};
|
||||
static const QStringList STR_SUBTYPE_ESKY150 {"4 Channel", "7 Channel"};
|
||||
static const QStringList STR_SUBTYPE_H83D {"H8 Mini 3D", "H20H", "H20 Mini", "H30 Mini"};
|
||||
static const QStringList STR_SUBTYPE_CORONA {"Corona V1", "Corona V2", "Flydream V3"};
|
||||
static const QStringList STR_SUBTYPE_HITEC {"Optima", "Optima Hub Telem", "Minima"};
|
||||
static const QStringList STR_SUBTYPE_TRAXXAS {"6519 RX"};
|
||||
static const QStringList STR_SUBTYPE_WFLY {"WFR0xS"};
|
||||
static const QStringList STR_SUBTYPE_BUGS_MINI {"Standard", "Bugs 3H"};
|
||||
static const QStringList STR_SUBTYPE_TRAXXAS {"6519 RX"};
|
||||
static const QStringList STR_SUBTYPE_E01X {"E012", "E015", "E016H"};
|
||||
static const QStringList STR_SUBTYPE_V911S {"Standard", "E119"};
|
||||
static const QStringList STR_SUBTYPE_GD00X {"GD V1", "GD V2"};
|
||||
static const QStringList STR_SUBTYPE_REDPINE {"Fast", "Slow"};
|
||||
static const QStringList STR_SUBTYPE_POTENSIC {"A20 Firefly"};
|
||||
static const QStringList STR_SUBTYPE_ZSX {"JJRC ZSX-280"};
|
||||
static const QStringList STR_SUBTYPE_FLYZONE {"FZ-410 TX"};
|
||||
static const QStringList STR_SUBTYPE_FRSKYX_RX {"D16 FCC", "D16 LBT"};
|
||||
static const QStringList STR_SUBTYPE_FRSKYX_RX {"RX", "Clone TX"};
|
||||
static const QStringList STR_SUBTYPE_FX816 {"P38"};
|
||||
static const QStringList STR_SUBTYPE_ESKY150 {"4CH", "7CH"};
|
||||
static const QStringList STR_SUBTYPE_XK {"X450", "X420"};
|
||||
static const QStringList STR_SUBTYPE_XN297DUMP {"250K", "1M", "2M", "AUTO"};
|
||||
static const QStringList STR_SUBTYPE_FRSKYX2 {"D16", "D16 8ch", "D16 EU-LBT", "D16 EU-LBT 8ch", "D16 Cloned"};
|
||||
static const QStringList STR_SUBTYPE_FRSKYR9 {"915 MHz", "868 MHz", "915 MHz 8-Channel", "868 MHz 8-Channel"};
|
||||
static const QStringList STR_SUBTYPE_PROPEL {"74-Z"};
|
||||
static const QStringList STR_SUBTYPE_FRSKYL {"LR12", "LR12 6-Channel"};
|
||||
static const QStringList STR_SUBTYPE_ESKY150V2 {"150 V2"};
|
||||
|
||||
static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT};
|
||||
|
||||
|
@ -83,7 +93,7 @@ static const QStringList NO_SUBTYPE {STR_MULTI_DEFAULT};
|
|||
const Multiprotocols multiProtocols {
|
||||
{MODULE_SUBTYPE_MULTI_FLYSKY, 4, false, STR_SUBTYPE_FLYSKY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_HUBSAN, 2, false, STR_SUBTYPE_HUBSAN, STR_MULTI_VIDFREQ},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKY, 5, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKY, 7, false, STR_SUBTYPE_FRSKY, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HISKY, 1, false, STR_SUBTYPE_HISKY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_V2X2, 1, false, STR_SUBTYPE_V2X2, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_DSM2, 3, false, STR_SUBTYPE_DSM, nullptr},
|
||||
|
@ -91,14 +101,16 @@ const Multiprotocols multiProtocols {
|
|||
{MODULE_SUBTYPE_MULTI_YD717, 4, false, STR_SUBTYPE_YD717, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_KN, 1, false, STR_SUBTYPE_KN, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SYMAX, 1, false, STR_SUBTYPE_SYMAX, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SLT, 4, false, STR_SUBTYPE_SLT, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SLT, 4, false, STR_SUBTYPE_SLT, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_CX10, 6, false, STR_SUBTYPE_CX10, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CG023, 1, false, STR_SUBTYPE_CG023, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_BAYANG, 4, false, STR_SUBTYPE_BAYANG, STR_MULTI_TELEMETRY},
|
||||
{MODULE_SUBTYPE_MULTI_ESky, 1, false, STR_SUBTYPE_ESky, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_MT99XX, 4, false, STR_SUBTYPE_MT99, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_MJXQ, 6, false, STR_SUBTYPE_MJXQ, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_FY326, 1, false, STR_SUBTYPE_FY326, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_SFHSS, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, NO_SUBTYPE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_HONTAI, 3, false, STR_SUBTYPE_HONTAI, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_OLRS, 0, false, NO_SUBTYPE, STR_MULTI_RFPOWER},
|
||||
{MODULE_SUBTYPE_MULTI_FS_AFHDS2A, 3, true, STR_SUBTYPE_AFHDS2A, STR_MULTI_SERVOFREQ},
|
||||
|
@ -106,25 +118,32 @@ const Multiprotocols multiProtocols {
|
|||
{MODULE_SUBTYPE_MULTI_WK_2X01, 5, false, STR_SUBTYPE_WK2x01, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_Q303, 3, false, STR_SUBTYPE_Q303, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CABELL, 7, false, STR_SUBTYPE_CABELL, STR_MULTI_OPTION},
|
||||
{MODULE_SUBTYPE_MULTI_ESKY150, 1, false, STR_SUBTYPE_ESKY150, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_H83D, 3, false, STR_SUBTYPE_H83D, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_CORONA, 2, false, STR_SUBTYPE_CORONA, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_HITEC, 2, false, STR_SUBTYPE_HITEC, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_WFLY, 0, false, STR_SUBTYPE_WFLY, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_BUGS_MINI, 1, false, STR_SUBTYPE_BUGS_MINI, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_TRAXXAS, 0, false, STR_SUBTYPE_TRAXXAS, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_E01X, 2, false, STR_SUBTYPE_E01X, STR_MULTI_OPTION},
|
||||
{MODULE_SUBTYPE_MULTI_V911S, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_V911S, 1, false, STR_SUBTYPE_V911S, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_GD00X, 1, false, STR_SUBTYPE_GD00X, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_KF606, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_REDPINE, 1, false, STR_SUBTYPE_REDPINE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_POTENSIC, 0, false, STR_SUBTYPE_POTENSIC, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_ZSX, 0, false, STR_SUBTYPE_ZSX, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FLYZONE, 0, false, STR_SUBTYPE_FLYZONE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKYX_RX, 1, false, STR_SUBTYPE_FRSKYX_RX, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_ESky, 0, false, NO_SUBTYPE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_J6PRO, 0, false, NO_SUBTYPE, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_ESKY150, 1, false, STR_SUBTYPE_ESKY150, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_HOTT, 0, true, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_FX816, 0, false, STR_SUBTYPE_FX816, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_XK, 1, false, STR_SUBTYPE_XK, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_XN297DUMP, 3, false, STR_SUBTYPE_XN297DUMP, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKYX2, 4, true, STR_SUBTYPE_FRSKYX2, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKY_R9, 3, true, STR_SUBTYPE_FRSKYR9, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_PROPEL, 0, false, STR_SUBTYPE_PROPEL, nullptr},
|
||||
{MODULE_SUBTYPE_MULTI_FRSKYL, 1, false, STR_SUBTYPE_FRSKYL, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_SKYARTEC, 0, false, NO_SUBTYPE, STR_MULTI_RFTUNE},
|
||||
{MODULE_SUBTYPE_MULTI_ESKY150V2, 0, false, STR_SUBTYPE_ESKY150V2, STR_MULTI_RFTUNE},
|
||||
{MM_RF_CUSTOM_SELECTED, 7, true, STR_SUBTYPE_CUSTOM, STR_MULTI_OPTION},
|
||||
|
||||
// Sentinel and default for protocols not listed above (MM_RF_CUSTOM is 0xff)
|
||||
|
@ -165,14 +184,13 @@ QString Multiprotocols::protocolToString(int protocol, bool custom)
|
|||
static const QStringList strings({
|
||||
"FlySky", "Hubsan", "FrSky", "Hisky", "V2x2", "DSM", "Devo", "YD717", "KN", "SymaX", "SLT", "CX10", "CG023",
|
||||
"Bayang", "ESky", "MT99XX", "MJXQ", "Shenqi", "FY326", "SFHSS", "J6 PRO","FQ777","Assan","Hontai","Open LRS",
|
||||
"FlySky AFHDS2A", "Q2x2", "Walkera", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie",
|
||||
"FlySky AFHDS2A", "Q2x2", "WK2x01", "Q303", "GW008", "DM002", "Cabell", "ESky 150", "H8 3D", "Corona", "CFlie",
|
||||
"Hitec", "Wfly", "Bugs", "Bugs Mini", "Traxxas", "NCC-1701-A", "E01X", "WL Heli V911S", "GD00X", "Volantex V761",
|
||||
"KFPlan KF606", "Redpine", "Potensic", "ZXS", "FlyZone", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816"
|
||||
"KFPlan KF606", "Redpine", "Potensic", "ZSX", "FlyZone", "Scanner", "FrSky RX", "FlySky AFHDS2A RX", "HoTT", "Fx816",
|
||||
"Bayang RX", "Pelikan", "Tiger", "XK", "XN297 Dump", "FrSky X 2.1", "FrSky R9", "Propel", "FrSky L", "Skyartec",
|
||||
"ESky 150v2", "DSM RX", "JJRC345"
|
||||
});
|
||||
|
||||
if (protocol == MM_RF_CUSTOM_SELECTED || custom)
|
||||
return tr("Custom - proto %1)").arg(protocol);
|
||||
else
|
||||
return strings.value(protocol, CPN_STR_UNKNOWN_ITEM);
|
||||
}
|
||||
|
||||
|
|
|
@ -693,9 +693,11 @@ class FlightModeField: public TransformedField {
|
|||
internalField.Append(new UnsignedField<8>(this, phase.fadeIn));
|
||||
internalField.Append(new UnsignedField<8>(this, phase.fadeOut));
|
||||
|
||||
if (version < 219) {
|
||||
for (int i = 0; i < rotencCount; i++) {
|
||||
internalField.Append(new SignedField<16>(this, phase.rotaryEncoders[i]));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_GVARS(board, version); i++) {
|
||||
internalField.Append(new SignedField<16>(this, phase.gvars[i]));
|
||||
|
@ -1914,7 +1916,7 @@ class SensorField: public TransformedField {
|
|||
internalField.Append(new UnsignedField<32>(this, _param, "param"));
|
||||
}
|
||||
|
||||
virtual void beforeExport()
|
||||
void beforeExport() override
|
||||
{
|
||||
if (sensor.type == SensorData::TELEM_TYPE_CUSTOM) {
|
||||
_id = sensor.id;
|
||||
|
@ -2054,17 +2056,12 @@ class ModuleUnionField: public UnionField<unsigned int> {
|
|||
|
||||
void beforeExport() override
|
||||
{
|
||||
if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
|
||||
module.multi.rfProtocol += 3;
|
||||
rfProtExtra = (module.multi.rfProtocol & 0x70) >> 4;
|
||||
module.multi.rfProtocol &= 0x0f;
|
||||
}
|
||||
|
||||
void afterImport() override
|
||||
{
|
||||
module.multi.rfProtocol = (rfProtExtra << 4) + (module.rfProtocol & 0xf);
|
||||
if (module.multi.rfProtocol > MODULE_SUBTYPE_MULTI_LAST)
|
||||
module.multi.rfProtocol -= 3;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -2133,7 +2130,8 @@ class ModuleUnionField: public UnionField<unsigned int> {
|
|||
memset(receiverName, 0, sizeof(receiverName));
|
||||
}
|
||||
|
||||
bool select(const unsigned int& attr) const override {
|
||||
bool select(const unsigned int& attr) const override
|
||||
{
|
||||
return attr >= PULSES_ACCESS_ISRM && attr <= PULSES_ACCESS_R9M_LITE_PRO;
|
||||
}
|
||||
|
||||
|
@ -2141,7 +2139,6 @@ class ModuleUnionField: public UnionField<unsigned int> {
|
|||
{
|
||||
for (int i=0; i<PXX2_MAX_RECEIVERS_PER_MODULE; i++) {
|
||||
for (int pos=0; pos<PXX2_LEN_RX_NAME+1; pos++) {
|
||||
|
||||
if (pos == PXX2_LEN_RX_NAME || module.access.receiverName[i][pos] == '\0') {
|
||||
memset(module.access.receiverName[i]+pos,'\0',PXX2_LEN_RX_NAME-pos);
|
||||
break;
|
||||
|
@ -2222,7 +2219,7 @@ class ModuleField: public TransformedField {
|
|||
module.subType = module.protocol - PULSES_PXX_XJT_X16;
|
||||
}
|
||||
else if (module.protocol == PULSES_MULTIMODULE) {
|
||||
module.rfProtocol = module.multi.rfProtocol & 0xf;
|
||||
module.rfProtocol = module.multi.rfProtocol & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -564,7 +564,7 @@ int OpenTxFirmware::getCapability(::Capability capability)
|
|||
case SoundPitch:
|
||||
return 1;
|
||||
case Haptic:
|
||||
return (IS_2560(board) || IS_SKY9X(board) || IS_TARANIS_PLUS(board) || IS_TARANIS_SMALL(board) || IS_TARANIS_X9E(board) || IS_FAMILY_HORUS_OR_T16(board) || IS_JUMPER_T12(board) || id.contains("haptic"));
|
||||
return board != Board::BOARD_TARANIS_X9D || id.contains("haptic");
|
||||
case ModelTrainerEnable:
|
||||
if (IS_HORUS_OR_TARANIS(board) && board!=Board::BOARD_TARANIS_XLITE)
|
||||
return 1;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -793,7 +802,7 @@ bool OpenTxFirmware::isAvailable(PulsesProtocol proto, int port)
|
|||
case PULSES_ACCST_ISRM_D16:
|
||||
return IS_ACCESS_RADIO(board, id);
|
||||
case PULSES_MULTIMODULE:
|
||||
return id.contains("internalmulti");
|
||||
return id.contains("internalmulti") || IS_RADIOMASTER_TX16S(board);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -1252,6 +1261,7 @@ void registerOpenTxFirmwares()
|
|||
|
||||
/* FrSky Taranis X9D board */
|
||||
firmware = new OpenTxFirmware("opentx-x9d", Firmware::tr("FrSky Taranis X9D"), BOARD_TARANIS_X9D);
|
||||
firmware->addOption("noras", Firmware::tr("Disable RAS (SWR)"));
|
||||
firmware->addOption("haptic", Firmware::tr("Haptic module installed"));
|
||||
addOpenTxTaranisOptions(firmware);
|
||||
addPPMInternalModuleHack(firmware);
|
||||
|
@ -1331,7 +1341,6 @@ void registerOpenTxFirmwares()
|
|||
firmware->addOption("noheli", Firmware::tr("Disable HELI menu and cyclic mix support"));
|
||||
firmware->addOption("nogvars", Firmware::tr("Disable Global variables"));
|
||||
firmware->addOption("lua", Firmware::tr("Enable Lua custom scripts screen"));
|
||||
firmware->addOption("flexr9m", Firmware::tr("Enable non certified R9M firmwares"));
|
||||
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
|
||||
addOpenTxFontOptions(firmware);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
@ -1342,15 +1351,17 @@ void registerOpenTxFirmwares()
|
|||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("internalmulti", Firmware::tr("Support for MULTI internal module"));
|
||||
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
registerOpenTxFirmware(firmware);
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
// TX16S is unavailable until finalized
|
||||
/* Radiomaster TX16S board
|
||||
/* Radiomaster TX16S board */
|
||||
firmware = new OpenTxFirmware("opentx-tx16s", Firmware::tr("Radiomaster TX16s / TX16s Hall / TX16s Masterfire"), BOARD_RADIOMASTER_TX16S);
|
||||
addOpenTxFrskyOptions(firmware);
|
||||
firmware->addOption("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
registerOpenTxFirmware(firmware);*/
|
||||
addOpenTxRfOptions(firmware, FLEX);
|
||||
static const Firmware::Option opt_bt("bluetooth", Firmware::tr("Support for bluetooth module"));
|
||||
static const Firmware::Option opt_internal_gps("internalgps", Firmware::tr("Support internal GPS"));
|
||||
firmware->addOptionsGroup({opt_bt, opt_internal_gps});
|
||||
registerOpenTxFirmware(firmware);
|
||||
|
||||
/* 9XR-Pro */
|
||||
firmware = new OpenTxFirmware("opentx-9xrpro", Firmware::tr("Turnigy 9XR-PRO"), BOARD_9XRPRO);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -82,6 +82,8 @@ QString SensorData::unitString() const
|
|||
return tr("seconds");
|
||||
case UNIT_CELLS:
|
||||
return tr("V");
|
||||
case UNIT_MILLILITERS_PER_MINUTE:
|
||||
return tr("ml/minute");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ class SensorData {
|
|||
UNIT_RADIANS,
|
||||
UNIT_MILLILITERS,
|
||||
UNIT_FLOZ,
|
||||
UNIT_MILLILITERS_PER_MINUTE,
|
||||
UNIT_HOURS,
|
||||
UNIT_MINUTES,
|
||||
UNIT_SECONDS,
|
||||
|
|
|
@ -1124,7 +1124,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item row="19" column="1">
|
||||
<widget class="QLineEdit" name="registrationId">
|
||||
<property name="inputMask">
|
||||
<string>aaaaaaAA</string>
|
||||
<string>nnnnnnNN</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>8</number>
|
||||
|
|
0
companion/src/images/simulator/TX16S/bottom.png
Executable file → Normal file
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
BIN
companion/src/images/simulator/TX16S/left.png
Executable file → Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 31 KiB |
BIN
companion/src/images/simulator/TX16S/left_page.png
Executable file → Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 31 KiB |
BIN
companion/src/images/simulator/TX16S/left_page2.png
Executable file → Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 31 KiB |
BIN
companion/src/images/simulator/TX16S/left_rtn.png
Executable file → Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 31 KiB |
BIN
companion/src/images/simulator/TX16S/left_sys.png
Executable file → Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 31 KiB |
BIN
companion/src/images/simulator/TX16S/left_tele.png
Executable file → Normal file
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 31 KiB |
0
companion/src/images/simulator/TX16S/right.png
Executable file → Normal file
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
0
companion/src/images/simulator/TX16S/right_ent.png
Executable file → Normal file
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
0
companion/src/images/simulator/TX16S/right_mdl.png
Executable file → Normal file
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
0
companion/src/images/simulator/TX16S/top.png
Executable file → Normal file
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 439 B |
|
@ -1,500 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>preferencesDialog</class>
|
||||
<widget class="QDialog" name="preferencesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>685</width>
|
||||
<height>432</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>685</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="snapshotPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Simu BackLight</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Simulator capture folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Joystick</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Remember simulator switches</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="simuSW">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QComboBox" name="joystickCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="joystickChkB">
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="snapshotClipboardCKB">
|
||||
<property name="text">
|
||||
<string>Use clipboard only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="joystickcalButton">
|
||||
<property name="text">
|
||||
<string>Calibrate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="backLightColor">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Blue</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Green</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Red</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Orange</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Yellow</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="snapshotPathButton">
|
||||
<property name="text">
|
||||
<string>Open Folder</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Personal splash library</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="libraryPath">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="libraryPathButton">
|
||||
<property name="text">
|
||||
<string>Open Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QComboBox" name="splashincludeCB">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Include companion splashes</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Only user defined splashes</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Splash library behaviour</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Custom TX splash screen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="SplashFileName">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="SplashSelect">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QToolButton" name="SplashLibraryDialogButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clearImageButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="InvertPixels">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Invert Pixels</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="imageLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>backLightColor</tabstop>
|
||||
<tabstop>joystickCB</tabstop>
|
||||
<tabstop>joystickChkB</tabstop>
|
||||
<tabstop>joystickcalButton</tabstop>
|
||||
<tabstop>simuSW</tabstop>
|
||||
<tabstop>snapshotPath</tabstop>
|
||||
<tabstop>snapshotPathButton</tabstop>
|
||||
<tabstop>snapshotClipboardCKB</tabstop>
|
||||
<tabstop>libraryPath</tabstop>
|
||||
<tabstop>libraryPathButton</tabstop>
|
||||
<tabstop>splashincludeCB</tabstop>
|
||||
<tabstop>SplashFileName</tabstop>
|
||||
<tabstop>SplashSelect</tabstop>
|
||||
<tabstop>SplashLibraryDialogButton</tabstop>
|
||||
<tabstop>clearImageButton</tabstop>
|
||||
<tabstop>InvertPixels</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>preferencesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>370</x>
|
||||
<y>49</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>preferencesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>390</x>
|
||||
<y>55</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -49,6 +49,7 @@
|
|||
#include "translations.h"
|
||||
|
||||
#include "dialogs/filesyncdialog.h"
|
||||
#include "profilechooser.h"
|
||||
|
||||
#include <QtGui>
|
||||
#include <QFileInfo>
|
||||
|
@ -130,11 +131,17 @@ MainWindow::MainWindow():
|
|||
else {
|
||||
if (!g.previousVersion().isEmpty())
|
||||
g.warningId(g.warningId() | AppMessages::MSG_UPGRADED);
|
||||
if (g.promptProfile()) {
|
||||
QTimer::singleShot(updateDelay, this, SLOT(chooseProfile())); // add an extra second to give mainwindow time to load
|
||||
updateDelay += 5000; // give user time to select profile before warnings
|
||||
}
|
||||
else {
|
||||
if (checkProfileRadioExists(g.sessionId()))
|
||||
QTimer::singleShot(updateDelay, this, SLOT(doAutoUpdates()));
|
||||
else
|
||||
g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE);
|
||||
}
|
||||
}
|
||||
QTimer::singleShot(updateDelay, this, SLOT(displayWarnings()));
|
||||
|
||||
QStringList strl = QApplication::arguments();
|
||||
|
@ -916,14 +923,15 @@ void MainWindow::changelog()
|
|||
|
||||
void MainWindow::customizeSplash()
|
||||
{
|
||||
CustomizeSplashDialog * dialog = new CustomizeSplashDialog(this);
|
||||
auto * dialog = new CustomizeSplashDialog(this);
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::writeEeprom()
|
||||
{
|
||||
if (activeMdiChild()) activeMdiChild()->writeEeprom();
|
||||
if (activeMdiChild())
|
||||
activeMdiChild()->writeEeprom();
|
||||
}
|
||||
|
||||
void MainWindow::readEeprom()
|
||||
|
@ -1806,3 +1814,20 @@ void MainWindow::autoClose()
|
|||
{
|
||||
this->close();
|
||||
}
|
||||
|
||||
void MainWindow::chooseProfile()
|
||||
{
|
||||
QMap<int, QString> active;
|
||||
active = g.getActiveProfiles();
|
||||
if (active.size() > 1) {
|
||||
ProfileChooserDialog *pcd = new ProfileChooserDialog(this);
|
||||
connect(pcd, &ProfileChooserDialog::profileChanged, this, &MainWindow::loadProfileId);
|
||||
pcd->exec();
|
||||
delete pcd;
|
||||
// doi here as need to wait until dialog dismissed and current radio type is set
|
||||
if (checkProfileRadioExists(g.sessionId()))
|
||||
doAutoUpdates();
|
||||
else
|
||||
g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ class MainWindow : public QMainWindow
|
|||
void exportSettings();
|
||||
void importSettings();
|
||||
void autoClose();
|
||||
void chooseProfile();
|
||||
|
||||
void openUpdatesWaitDialog();
|
||||
void closeUpdatesWaitDialog();
|
||||
|
|
|
@ -1490,18 +1490,18 @@ bool MdiChild::convertStorage(Board::Type from, Board::Type to, bool newFile)
|
|||
isUntitled = true;
|
||||
|
||||
if (cstate.hasLogEntries(RadioDataConversionState::EVT_INF)) {
|
||||
QDialog * msgBox = new QDialog(Q_NULLPTR, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||
auto * msgBox = new QDialog(Q_NULLPTR, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||
|
||||
ExportableTableView * tv = new ExportableTableView(msgBox);
|
||||
auto * tv = new ExportableTableView(msgBox);
|
||||
tv->setSortingEnabled(true);
|
||||
tv->verticalHeader()->hide();
|
||||
tv->setModel(cstate.getLogModel(RadioDataConversionState::EVT_INF, tv));
|
||||
tv->resizeColumnsToContents();
|
||||
tv->resizeRowsToContents();
|
||||
|
||||
QDialogButtonBox * btnBox = new QDialogButtonBox(QDialogButtonBox::Ok, this);
|
||||
auto * btnBox = new QDialogButtonBox(QDialogButtonBox::Ok, this);
|
||||
|
||||
QVBoxLayout * lo = new QVBoxLayout(msgBox);
|
||||
auto * lo = new QVBoxLayout(msgBox);
|
||||
lo->addWidget(new QLabel(tr("<b>The conversion generated some important messages, please review them below.</b>")));
|
||||
lo->addWidget(tv);
|
||||
lo->addWidget(btnBox);
|
||||
|
|
|
@ -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
|
||||
|
@ -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));
|
||||
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()
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -154,7 +159,7 @@ Curves::Curves(QWidget * parent, ModelData & model, GeneralSettings & generalSet
|
|||
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) {
|
||||
ui->curvesLayout->addWidget(edit, i, 1, 1, 1);
|
||||
|
@ -176,7 +181,7 @@ 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) {
|
||||
if (limit != maxCurves) {
|
||||
QSpacerItem * item2 = new QSpacerItem(1,1, QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
ui->curvesLayout2->addItem(item2,limit + 1, 1, 1, 1, 0);
|
||||
}
|
||||
|
@ -199,7 +204,7 @@ 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 {
|
||||
|
@ -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 {
|
||||
|
@ -318,8 +323,7 @@ void Curves::updateCurve()
|
|||
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]) {
|
||||
int numpoints = model->curves[k].count;
|
||||
|
@ -360,7 +364,8 @@ void Curves::updateCurve()
|
|||
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;
|
||||
|
@ -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++) {
|
||||
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;
|
||||
}
|
||||
|
@ -491,6 +493,7 @@ 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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -699,7 +640,7 @@ void Curves::onSceneNewPoint(int x, int y)
|
|||
}
|
||||
numpoints++;
|
||||
model->curves[currentCurve].count = numpoints;
|
||||
for (int idx=(numpoints-1); idx>(newidx); idx--) {
|
||||
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;
|
||||
|
@ -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));
|
||||
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));
|
||||
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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
@ -151,7 +150,7 @@ 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!"));
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("Not enough available Inputs!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -172,19 +171,20 @@ 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;
|
||||
if (firmware->getCapability(VirtualInputs))
|
||||
inputName = model->inputNames[mixd.chn];
|
||||
inputName = model->inputNames[ed.chn];
|
||||
|
||||
ExpoDialog *g = new ExpoDialog(this, *model, &mixd, generalSettings, firmware, inputName);
|
||||
ExpoDialog *g = new ExpoDialog(this, *model, &ed, generalSettings, firmware, inputName);
|
||||
if (g->exec()) {
|
||||
model->expoData[index] = mixd;
|
||||
model->expoData[index] = ed;
|
||||
if (firmware->getCapability(VirtualInputs))
|
||||
strncpy(model->inputNames[mixd.chn], inputName.toLatin1().data(), 4);
|
||||
strncpy(model->inputNames[ed.chn], inputName.toLatin1().data(), INPUT_NAME_LEN);
|
||||
emit modified();
|
||||
update();
|
||||
}
|
||||
|
@ -200,23 +200,24 @@ void InputsPanel::gm_openExpo(int index)
|
|||
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;
|
||||
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;
|
||||
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++) {
|
||||
|
@ -229,15 +230,13 @@ void InputsPanel::setSelectedByExpoList(QList<int> list)
|
|||
void InputsPanel::exposDelete(bool ask)
|
||||
{
|
||||
QList<int> list = createExpoListFromSelected();
|
||||
if(list.isEmpty()) return;
|
||||
if (list.isEmpty())
|
||||
return;
|
||||
|
||||
QMessageBox::StandardButton ret = QMessageBox::No;
|
||||
|
||||
if (ask)
|
||||
ret = QMessageBox::warning(this, "companion",
|
||||
tr("Delete Selected Inputs?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
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);
|
||||
|
@ -256,13 +255,13 @@ void InputsPanel::exposCopy()
|
|||
{
|
||||
QList<int> list = createExpoListFromSelected();
|
||||
|
||||
QByteArray mxData;
|
||||
QByteArray exData;
|
||||
foreach (int idx, list) {
|
||||
mxData.append((char*)&model->expoData[idx], sizeof(ExpoData));
|
||||
exData.append((char*)&model->expoData[idx], sizeof(ExpoData));
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData("application/x-companion-expo", mxData);
|
||||
mimeData->setData(MIMETYPE_EXPO, exData);
|
||||
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
|
@ -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,7 +334,6 @@ void InputsPanel::exposDuplicate()
|
|||
exposPaste();
|
||||
}
|
||||
|
||||
|
||||
void InputsPanel::expoOpen(QListWidgetItem *item)
|
||||
{
|
||||
if (!item)
|
||||
|
@ -348,7 +347,8 @@ void InputsPanel::expoOpen(QListWidgetItem *item)
|
|||
return;
|
||||
model->expoData[idx].chn = ch;
|
||||
expoInserted = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
expoInserted = false;
|
||||
}
|
||||
gm_openExpo(idx);
|
||||
|
@ -360,7 +360,8 @@ void InputsPanel::expoAdd()
|
|||
|
||||
if (index < 0) { // if empty then return relevant index
|
||||
expoOpen();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
index++;
|
||||
if (!gm_insertExpo(index))
|
||||
return;
|
||||
|
@ -376,37 +377,57 @@ void InputsPanel::expolistWidget_customContextMenuRequested(QPoint pos)
|
|||
|
||||
const QClipboard *clipboard = QApplication::clipboard();
|
||||
const QMimeData *mimeData = clipboard->mimeData();
|
||||
bool hasData = mimeData->hasFormat("application/x-companion-expo");
|
||||
bool hasData = mimeData->hasFormat(MIMETYPE_EXPO);
|
||||
|
||||
selectedIdx = getIndexFromSelected();
|
||||
inputIdx = getInputIndexFromSelected();
|
||||
|
||||
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"));
|
||||
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("&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.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->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))
|
||||
|
@ -494,8 +515,11 @@ void InputsPanel::exposDeleteList(QList<int> list, bool clearName)
|
|||
|
||||
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()
|
||||
{
|
||||
QByteArray data;
|
||||
if (hasClipboardData(&data)) {
|
||||
memcpy(&model->logicalSw[selectedIndex], data.constData(), sizeof(LogicalSwitchData));
|
||||
updateDataModels();
|
||||
updateLine(selectedIndex);
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::cmDelete()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::cmCopy()
|
||||
{
|
||||
QByteArray data;
|
||||
data.append((char*)&model->logicalSw[selectedIndex], sizeof(LogicalSwitchData));
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData(MIMETYPE_LOGICAL_SWITCH, data);
|
||||
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::cmCut()
|
||||
{
|
||||
cmCopy();
|
||||
cmClear();
|
||||
}
|
||||
|
||||
// TODO make something generic here!
|
||||
void LogicalSwitchesPanel::onCustomContextMenuRequested(QPoint pos)
|
||||
{
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedIndex = label->property("index").toInt();
|
||||
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()));
|
||||
|
||||
contextMenu.exec(globalPos);
|
||||
}
|
||||
|
||||
bool LogicalSwitchesPanel::hasClipboardData(QByteArray * data) const
|
||||
{
|
||||
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));
|
||||
if (mimeData->hasFormat(MIMETYPE_LOGICAL_SWITCH)) {
|
||||
if (data)
|
||||
data->append(mimeData->data(MIMETYPE_LOGICAL_SWITCH));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::cswDelete()
|
||||
{
|
||||
model->logicalSw[selectedSwitch].clear();
|
||||
emit modified();
|
||||
updateLine(selectedSwitch);
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::cswCopy()
|
||||
{
|
||||
QByteArray cswData;
|
||||
cswData.append((char*)&model->logicalSw[selectedSwitch],sizeof(LogicalSwitchData));
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData("application/x-companion-csw", cswData);
|
||||
QApplication::clipboard()->setMimeData(mimeData,QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
void LogicalSwitchesPanel::cswCut()
|
||||
{
|
||||
cswCopy();
|
||||
cswDelete();
|
||||
}
|
||||
|
||||
// TODO make something generic here!
|
||||
void LogicalSwitchesPanel::csw_customContextMenuRequested(QPoint pos)
|
||||
{
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedSwitch = label->property("index").toInt();
|
||||
|
||||
QPoint globalPos = label->mapToGlobal(pos);
|
||||
|
||||
const QClipboard * clipboard = QApplication::clipboard();
|
||||
const QMimeData * mimeData = clipboard->mimeData();
|
||||
bool hasData = mimeData->hasFormat("application/x-companion-csw");
|
||||
|
||||
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()));
|
||||
|
||||
contextMenu.exec(globalPos);
|
||||
}
|
||||
|
|
|
@ -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,18 +133,18 @@ QWidget * TimerPanel::getLastFocus()
|
|||
|
||||
void TimerPanel::on_value_editingFinished()
|
||||
{
|
||||
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;
|
||||
|
||||
if (!lock) {
|
||||
bool ok;
|
||||
const RawSwitch rs(ui->mode->itemData(index).toInt(&ok));
|
||||
if (ok && timer.mode.toValue() != rs.toValue()) {
|
||||
|
@ -145,21 +152,26 @@ void TimerPanel::onModeChanged(int index)
|
|||
emit modified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimerPanel::on_minuteBeep_toggled(bool checked)
|
||||
{
|
||||
if (!lock) {
|
||||
timer.minuteBeep = checked;
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void TimerPanel::on_name_editingFinished()
|
||||
{
|
||||
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);
|
||||
|
||||
timersCount = firmware->getCapability(Timers);
|
||||
|
||||
for (int i = 0; i < CPN_MAX_TIMERS; i++) {
|
||||
if (i<firmware->getCapability(Timers)) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1082,7 +1049,7 @@ 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)) {
|
||||
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>
|
||||
|
|
|
@ -592,13 +592,28 @@ void TelemetryCustomScreen::barTimeChanged()
|
|||
}
|
||||
}
|
||||
|
||||
TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
/******************************************************/
|
||||
|
||||
TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
ModelPanel(parent, model, generalSettings, firmware),
|
||||
ui(new Ui::TelemetrySensor),
|
||||
sensor(sensor),
|
||||
lock(false)
|
||||
lock(false),
|
||||
sensorIndex(sensorIndex),
|
||||
selectedIndex(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->numLabel->setText(tr("TELE%1").arg(sensorIndex + 1));
|
||||
ui->numLabel->setProperty("index", sensorIndex);
|
||||
ui->numLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
QFontMetrics *f = new QFontMetrics(QFont());
|
||||
QSize sz;
|
||||
sz = f->size(Qt::TextSingleLine, "TELE00");
|
||||
ui->numLabel->setMinimumWidth(sz.width());
|
||||
ui->numLabel->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->numLabel->setToolTip(tr("Popup menu available"));
|
||||
ui->numLabel->setMouseTracking(true);
|
||||
connect(ui->numLabel, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(on_customContextMenuRequested(QPoint)));
|
||||
ui->id->setField(sensor.id, this);
|
||||
ui->instance->setField(sensor.instance, this);
|
||||
ui->ratio->setField(sensor.ratio, this);
|
||||
|
@ -622,6 +637,7 @@ TelemetrySensorPanel::TelemetrySensorPanel(QWidget *parent, SensorData & sensor,
|
|||
ui->source2->setField(sensor.sources[1], this);
|
||||
ui->source3->setField(sensor.sources[2], this);
|
||||
ui->source4->setField(sensor.sources[3], this);
|
||||
ui->prec->setField(sensor.prec, 0, 2, false, "", this);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -645,7 +661,21 @@ void TelemetrySensorPanel::update()
|
|||
ui->name->setText(sensor.label);
|
||||
ui->type->setCurrentIndex(sensor.type);
|
||||
ui->unit->setCurrentIndex(sensor.unit);
|
||||
ui->prec->setValue(sensor.prec);
|
||||
ui->id->updateValue();
|
||||
ui->instance->updateValue();
|
||||
ui->ratio->updateValue();
|
||||
ui->offset->updateValue();
|
||||
ui->autoOffset->updateValue();
|
||||
ui->filter->updateValue();
|
||||
ui->logs->updateValue();
|
||||
ui->persistent->updateValue();
|
||||
ui->onlyPositive->updateValue();
|
||||
ui->gpsSensor->updateValue();
|
||||
ui->altSensor->updateValue();
|
||||
ui->ampsSensor->updateValue();
|
||||
ui->cellsSensor->updateValue();
|
||||
ui->cellsIndex->updateValue();
|
||||
ui->prec->updateValue();
|
||||
|
||||
if (sensor.type == SensorData::TELEM_TYPE_CALCULATED) {
|
||||
sensor.updateUnit();
|
||||
|
@ -825,15 +855,85 @@ void TelemetrySensorPanel::on_unit_currentIndexChanged(int index)
|
|||
}
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::on_prec_valueChanged(double value)
|
||||
void TelemetrySensorPanel::on_prec_valueChanged()
|
||||
{
|
||||
if (!lock) {
|
||||
sensor.prec = value;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::on_customContextMenuRequested(QPoint pos)
|
||||
{
|
||||
QLabel *label = (QLabel *)sender();
|
||||
selectedIndex = label->property("index").toInt();
|
||||
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("clear.png"), tr("Clear All"),this,SLOT(cmClearAll()));
|
||||
|
||||
contextMenu.exec(globalPos);
|
||||
}
|
||||
|
||||
bool TelemetrySensorPanel::hasClipboardData(QByteArray * data) const
|
||||
{
|
||||
const QClipboard * clipboard = QApplication::clipboard();
|
||||
const QMimeData * mimeData = clipboard->mimeData();
|
||||
if (mimeData->hasFormat(MIMETYPE_TELE_SENSOR)) {
|
||||
if (data)
|
||||
data->append(mimeData->data(MIMETYPE_TELE_SENSOR));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::cmCopy()
|
||||
{
|
||||
QByteArray data;
|
||||
data.append((char*)&sensor, sizeof(SensorData));
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData(MIMETYPE_TELE_SENSOR, data);
|
||||
QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::cmCut()
|
||||
{
|
||||
cmCopy();
|
||||
cmClear();
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::cmPaste()
|
||||
{
|
||||
QByteArray data;
|
||||
if (hasClipboardData(&data)) {
|
||||
memcpy(&sensor, data.constData(), sizeof(SensorData));
|
||||
emit dataModified();
|
||||
emit modified();
|
||||
}
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::cmClear()
|
||||
{
|
||||
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear Telemetry Sensor. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
|
||||
return;
|
||||
|
||||
sensor.clear();
|
||||
emit dataModified();
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TelemetrySensorPanel::cmClearAll()
|
||||
{
|
||||
if (QMessageBox::question(this, CPN_STR_APP_NAME, tr("Clear all Telemetry Sensors. Are you sure?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
|
||||
return;
|
||||
|
||||
emit clearAllSensors();
|
||||
}
|
||||
|
||||
/******************************************************/
|
||||
|
||||
TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware):
|
||||
|
@ -852,11 +952,12 @@ TelemetryPanel::TelemetryPanel(QWidget *parent, ModelData & model, GeneralSettin
|
|||
ui->A1GB->hide();
|
||||
ui->A2GB->hide();
|
||||
for (unsigned i= 0; i < CPN_MAX_SENSORS; ++i) {
|
||||
TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], model, generalSettings, firmware);
|
||||
TelemetrySensorPanel * panel = new TelemetrySensorPanel(this, model.sensorData[i], i, model, generalSettings, firmware);
|
||||
ui->sensorsLayout->addWidget(panel);
|
||||
sensorPanels[i] = panel;
|
||||
connect(panel, SIGNAL(dataModified()), this, SLOT(update()));
|
||||
connect(panel, SIGNAL(modified()), this, SLOT(onModified()));
|
||||
connect(panel, SIGNAL(clearAllSensors()), this, SLOT(on_clearAllSensors()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1198,3 +1299,13 @@ void TelemetryPanel::on_mahCount_ChkB_toggled(bool checked)
|
|||
ui->mahCount_SB->setDisabled(!checked);
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void TelemetryPanel::on_clearAllSensors()
|
||||
{
|
||||
for (int i = 0; i < CPN_MAX_SENSORS; i++) {
|
||||
model->sensorData[i].clear();
|
||||
}
|
||||
|
||||
update();
|
||||
emit modified();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "modeledit.h"
|
||||
#include "eeprominterface.h"
|
||||
|
||||
constexpr char MIMETYPE_TELE_SENSOR[] = "application/x-companion-tele-sensor";
|
||||
|
||||
class AutoComboBox;
|
||||
class RawSourceFilterItemModel;
|
||||
class TimerEdit;
|
||||
|
@ -103,19 +105,27 @@ class TelemetrySensorPanel: public ModelPanel
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TelemetrySensorPanel(QWidget *parent, SensorData & sensor, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
TelemetrySensorPanel(QWidget *parent, SensorData & sensor, int sensorIndex, ModelData & model, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
~TelemetrySensorPanel();
|
||||
void update();
|
||||
|
||||
signals:
|
||||
void dataModified();
|
||||
void clearAllSensors();
|
||||
|
||||
protected slots:
|
||||
void on_name_editingFinished();
|
||||
void on_type_currentIndexChanged(int index);
|
||||
void on_formula_currentIndexChanged(int index);
|
||||
void on_unit_currentIndexChanged(int index);
|
||||
void on_prec_valueChanged(double value);
|
||||
void on_prec_valueChanged();
|
||||
void on_customContextMenuRequested(QPoint pos);
|
||||
bool hasClipboardData(QByteArray * data = nullptr) const;
|
||||
void cmCopy();
|
||||
void cmCut();
|
||||
void cmPaste();
|
||||
void cmClear();
|
||||
void cmClearAll();
|
||||
|
||||
protected:
|
||||
void updateSourcesComboBox(AutoComboBox * cb, bool negative);
|
||||
|
@ -123,7 +133,9 @@ class TelemetrySensorPanel: public ModelPanel
|
|||
private:
|
||||
Ui::TelemetrySensor * ui;
|
||||
SensorData & sensor;
|
||||
bool lock;
|
||||
bool lock = false;
|
||||
int sensorIndex = 0;
|
||||
int selectedIndex = 0;
|
||||
};
|
||||
|
||||
class TelemetryPanel : public ModelPanel
|
||||
|
@ -154,6 +166,7 @@ class TelemetryPanel : public ModelPanel
|
|||
void on_fasOffset_DSB_editingFinished();
|
||||
void on_mahCount_SB_editingFinished();
|
||||
void on_mahCount_ChkB_toggled(bool checked);
|
||||
void on_clearAllSensors();
|
||||
|
||||
private:
|
||||
Ui::Telemetry *ui;
|
||||
|
|
|
@ -13,13 +13,32 @@
|
|||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,1,0,0,0,1,0,0,1,1,1,0,0,1,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="numLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TELE##</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="name">
|
||||
<property name="sizePolicy">
|
||||
|
@ -520,6 +539,11 @@
|
|||
<string>US fl.Oz.</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ml/min</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -536,23 +560,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="prec">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="AutoPrecisionComboBox" name="prec"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="ratioLabel">
|
||||
|
@ -711,6 +719,11 @@
|
|||
<extends>QSpinBox</extends>
|
||||
<header>autohexspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AutoPrecisionComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>autoprecisioncombobox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
62
companion/src/profilechooser.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 "profilechooser.h"
|
||||
#include "ui_profilechooser.h"
|
||||
#include "appdata.h"
|
||||
|
||||
ProfileChooserDialog::ProfileChooserDialog(QWidget * parent):
|
||||
QDialog(parent),
|
||||
ui(new Ui::ProfileChooserDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(QIcon(":/icon.png"));
|
||||
QComboBox *prof = ui->cboProfiles;
|
||||
prof->clear();
|
||||
|
||||
QMap<int, QString> active;
|
||||
active = g.getActiveProfiles();
|
||||
QMapIterator<int, QString> i(active);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
prof->addItem(i.value(), i.key());
|
||||
}
|
||||
|
||||
prof->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
prof->setCurrentIndex(prof->findData(g.id()));
|
||||
connect(prof, SIGNAL(currentIndexChanged(int)), this, SLOT(on_cboProfilesCurrentIndexChanged(int)));
|
||||
}
|
||||
|
||||
ProfileChooserDialog::~ProfileChooserDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ProfileChooserDialog::on_cboProfilesCurrentIndexChanged(int index)
|
||||
{
|
||||
QComboBox *prof = ui->cboProfiles;
|
||||
|
||||
if ((prof->currentIndex() > -1)) {
|
||||
int oldid = g.id();
|
||||
int newid = prof->currentData().toInt();
|
||||
if (oldid != newid)
|
||||
emit profileChanged(newid);
|
||||
}
|
||||
}
|
47
companion/src/profilechooser.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 _PROFILECHOOSER_H_
|
||||
#define _PROFILECHOOSER_H_
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
namespace Ui {
|
||||
class ProfileChooserDialog;
|
||||
}
|
||||
|
||||
class ProfileChooserDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ProfileChooserDialog(QWidget * parent = 0);
|
||||
~ProfileChooserDialog();
|
||||
signals:
|
||||
void profileChanged(int newid);
|
||||
|
||||
private slots:
|
||||
void on_cboProfilesCurrentIndexChanged(int index);
|
||||
|
||||
private:
|
||||
Ui::ProfileChooserDialog *ui;
|
||||
};
|
||||
|
||||
#endif // _PROFILECHOOSER_H_
|
110
companion/src/profilechooser.ui
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProfileChooserDialog</class>
|
||||
<widget class="QDialog" name="ProfileChooserDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>352</width>
|
||||
<height>102</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select Profile</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
<width>311</width>
|
||||
<height>66</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cboProfiles">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ProfileChooserDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ProfileChooserDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -15,6 +15,7 @@ set(shared_HDRS
|
|||
autolineedit.h
|
||||
genericpanel.h
|
||||
hexspinbox.h
|
||||
autoprecisioncombobox.h
|
||||
)
|
||||
|
||||
qt5_wrap_cpp(shared_SRCS ${shared_HDRS})
|
||||
|
|
257
companion/src/shared/autoprecisioncombobox.h
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* 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 _AUTOPRECISIONCOMBOBOX_H_
|
||||
#define _AUTOPRECISIONCOMBOBOX_H_
|
||||
|
||||
#include "genericpanel.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QString>
|
||||
|
||||
class AutoPrecisionComboBox: public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
//! \property minDecimals Determines the first list item
|
||||
Q_PROPERTY(unsigned int minDecimals READ minDecimals WRITE setMinDecimals)
|
||||
//! \property maxDecimals Determines the last list item
|
||||
Q_PROPERTY(unsigned int maxDecimals READ maxDecimals WRITE setMaxDecimals)
|
||||
//! \property padding If true, add trailing underscore placeholders to each list item
|
||||
Q_PROPERTY(bool padding READ padding WRITE setPadding)
|
||||
//! \property suffix Optional text suffix to each list value
|
||||
Q_PROPERTY(QString suffix READ suffix WRITE setSuffix)
|
||||
|
||||
public:
|
||||
explicit AutoPrecisionComboBox(QWidget * parent = nullptr):
|
||||
QComboBox(parent)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
explicit AutoPrecisionComboBox(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr):
|
||||
QComboBox(parent)
|
||||
{
|
||||
setField(field, minDecimals, maxDecimals, padding, suffix, panel);
|
||||
init();
|
||||
}
|
||||
|
||||
explicit AutoPrecisionComboBox(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", QWidget * parent = nullptr, GenericPanel * panel = nullptr):
|
||||
QComboBox(parent)
|
||||
{
|
||||
setField(field, minDecimals, maxDecimals, padding, suffix, panel);
|
||||
init();
|
||||
}
|
||||
|
||||
inline int minDecimals() const { return m_minDecimals; }
|
||||
inline int maxDecimals() const { return m_maxDecimals; }
|
||||
inline bool padding() const { return m_padding; }
|
||||
inline QString suffix() const { return m_suffix; }
|
||||
|
||||
public slots:
|
||||
void setField(int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr)
|
||||
{
|
||||
m_field = reinterpret_cast<unsigned int *>(&field);
|
||||
initField(minDecimals, maxDecimals, padding, suffix);
|
||||
setPanel(panel);
|
||||
}
|
||||
|
||||
void setField(unsigned int & field, unsigned int minDecimals = 0, unsigned int maxDecimals = 1, bool padding = false, QString suffix = "", GenericPanel * panel = nullptr)
|
||||
{
|
||||
m_field = &field;
|
||||
initField(minDecimals, maxDecimals, padding, suffix);
|
||||
setPanel(panel);
|
||||
}
|
||||
|
||||
void setMinDecimals(unsigned int minDecimals)
|
||||
{
|
||||
m_minDecimals = rangecheckDecimals(minDecimals);
|
||||
if (m_minDecimals > m_maxDecimals)
|
||||
m_minDecimals = m_maxDecimals;
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setMaxDecimals(unsigned int maxDecimals)
|
||||
{
|
||||
m_maxDecimals = rangecheckDecimals(maxDecimals);
|
||||
if (m_maxDecimals < m_minDecimals)
|
||||
m_maxDecimals = m_minDecimals;
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setPadding(bool padding)
|
||||
{
|
||||
m_padding = padding;
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setSuffix(QString suffix)
|
||||
{
|
||||
m_suffix = suffix.trimmed();
|
||||
if (!m_lock)
|
||||
updateList();
|
||||
}
|
||||
|
||||
void setPanel(GenericPanel * panel)
|
||||
{
|
||||
m_panel = panel;
|
||||
}
|
||||
|
||||
void setValue(int value)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
const unsigned int val = (unsigned int)value;
|
||||
if (*m_field != val) {
|
||||
*m_field = rangecheckDecimals(val);
|
||||
updateValue();
|
||||
emit valueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void setValue(unsigned int value)
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
if (*m_field != value) {
|
||||
*m_field = rangecheckDecimals(value);
|
||||
updateValue();
|
||||
emit valueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void updateValue()
|
||||
{
|
||||
if (!m_field)
|
||||
return;
|
||||
if (!isValidDecimals(*m_field))
|
||||
return;
|
||||
if (*m_field > m_maxDecimals) {
|
||||
setMaxDecimals(*m_field);
|
||||
}
|
||||
const bool savedlock = setLocked(true);
|
||||
setCurrentIndex(findData(*m_field));
|
||||
setLocked(savedlock);
|
||||
}
|
||||
|
||||
void setAutoIndexes()
|
||||
{
|
||||
for (int i = 0; i < count(); ++i)
|
||||
setItemData(i, i);
|
||||
updateValue();
|
||||
}
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
protected slots:
|
||||
void init()
|
||||
{
|
||||
connect(this, QOverload<int>::of(&AutoPrecisionComboBox::currentIndexChanged), this, &AutoPrecisionComboBox::onCurrentIndexChanged);
|
||||
}
|
||||
|
||||
void initField(unsigned int minDecimals, unsigned int maxDecimals, bool padding, QString suffix)
|
||||
{
|
||||
const bool savedlock = setLocked(true);
|
||||
setMinDecimals(minDecimals);
|
||||
setMaxDecimals(maxDecimals);
|
||||
setPadding(padding);
|
||||
setSuffix(suffix);
|
||||
setLocked(savedlock);
|
||||
updateList();
|
||||
}
|
||||
|
||||
void updateList()
|
||||
{
|
||||
const bool savedlock = setLocked(true);
|
||||
unsigned int i;
|
||||
int j;
|
||||
clear();
|
||||
|
||||
for (i = APCB_DECIMALS_MIN, j = (int)m_maxDecimals; j >= 0; i++, j--) {
|
||||
if (i >= m_minDecimals) {
|
||||
QString str = QString("0.%1").arg(QString(i, '0'));
|
||||
if (m_padding)
|
||||
str.append(QString(j, '_'));
|
||||
if (m_suffix != "")
|
||||
str.append(QString(" %1").arg(m_suffix));
|
||||
addItem(str, i);
|
||||
}
|
||||
}
|
||||
|
||||
setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
setLocked(savedlock);
|
||||
}
|
||||
|
||||
void onCurrentIndexChanged(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return;
|
||||
if (m_field && !m_lock) {
|
||||
*m_field = itemData(index).toUInt();
|
||||
if (m_panel)
|
||||
emit m_panel->modified();
|
||||
emit valueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int rangecheckDecimals(unsigned int decimals)
|
||||
{
|
||||
unsigned int ret;
|
||||
if (decimals < APCB_DECIMALS_MIN)
|
||||
ret = APCB_DECIMALS_MIN;
|
||||
else if (decimals > APCB_DECIMALS_MAX)
|
||||
ret = APCB_DECIMALS_MAX;
|
||||
else
|
||||
ret = decimals;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool isValidDecimals(unsigned int value)
|
||||
{
|
||||
if (value >= APCB_DECIMALS_MIN && value <= APCB_DECIMALS_MAX)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool setLocked(bool lock)
|
||||
{
|
||||
const bool ret = m_lock;
|
||||
m_lock = lock;
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
constexpr static unsigned int APCB_DECIMALS_MIN = {0};
|
||||
constexpr static unsigned int APCB_DECIMALS_MAX = {6};
|
||||
|
||||
unsigned int * m_field = nullptr;
|
||||
GenericPanel * m_panel = nullptr;
|
||||
unsigned int m_minDecimals = 0;
|
||||
unsigned int m_maxDecimals = 0;
|
||||
bool m_padding = false;
|
||||
QString m_suffix = "";
|
||||
bool m_lock = false;
|
||||
};
|
||||
|
||||
#endif // _AUTOPRECISIONCOMBOBOX_H_
|
|
@ -39,6 +39,7 @@ class GenericPanel : public QWidget
|
|||
friend class AutoHexSpinBox;
|
||||
friend class AutoLineEdit;
|
||||
friend class GVarGroup;
|
||||
friend class AutoPrecisionComboBox;
|
||||
|
||||
public:
|
||||
GenericPanel(QWidget *parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware);
|
||||
|
|
|
@ -99,9 +99,10 @@ void Joystick::processEvents()
|
|||
axes[i] = moved;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
axisRepeatTimers[i].restart();
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit axisValueChanged(i, 0);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ SimulatedUIWidgetTX16S::SimulatedUIWidgetTX16S(SimulatorInterface *simulator, QW
|
|||
// add actions in order of appearance on the help menu
|
||||
|
||||
act = new RadioUiAction(3, QList<int>() << Qt::Key_Up, SIMU_STR_HLP_KEY_UP, SIMU_STR_HLP_ACT_MDL);
|
||||
addRadioWidget(ui->rightbuttons->addArea(QRect(10, 0, 80, 35), "TX16S/right_mdl.png", act));
|
||||
addRadioWidget(ui->rightbuttons->addArea(QRect(40, 0, 110, 35), "TX16S/right_mdl.png", act));
|
||||
|
||||
m_mouseMidClickAction = new RadioUiAction(2, QList<int>() << Qt::Key_Enter << Qt::Key_Return, SIMU_STR_HLP_KEYS_ACTIVATE, SIMU_STR_HLP_ACT_ROT_DN);
|
||||
addRadioWidget(ui->rightbuttons->addArea(QRect(45, 70, 100, 160), "TX16S/right_ent.png", m_mouseMidClickAction));
|
||||
|
@ -59,7 +59,7 @@ SimulatedUIWidgetTX16S::SimulatedUIWidgetTX16S(SimulatorInterface *simulator, QW
|
|||
m_scrollDnAction = new RadioUiAction(-1, QList<int>() << Qt::Key_Plus << Qt::Key_Equal, SIMU_STR_HLP_KEY_PLS % "|" % SIMU_STR_HLP_MOUSE_DN, SIMU_STR_HLP_ACT_ROT_RGT);
|
||||
connectScrollActions();
|
||||
|
||||
addRadioWidget(ui->leftbuttons->addArea(QRect(10, 252, 30, 30), "TX16S/left_scrnsht.png", m_screenshotAction));
|
||||
addRadioWidget(ui->leftbuttons->addArea(QRect(10, 245, 30, 30), "TX16S/left_scrnsht.png", m_screenshotAction));
|
||||
|
||||
m_backlightColors << QColor(47, 123, 227);
|
||||
|
||||
|
|
|
@ -699,11 +699,13 @@ void SimulatorWidget::restoreRadioWidgetsState()
|
|||
void SimulatorWidget::saveRadioWidgetsState(QList<QByteArray> & state)
|
||||
{
|
||||
if (m_radioWidgets.size()) {
|
||||
if (g.simuSW()) {
|
||||
state.clear();
|
||||
foreach (RadioWidget * rw, m_radioWidgets)
|
||||
state.append(rw->getStateData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -575,6 +575,7 @@ class AppData: public CompStoreObj
|
|||
PROPERTY4(bool, snapToClpbrd, "snapshot_to_clipboard", false)
|
||||
PROPERTY4(bool, autoCheckApp, "startup_check_companion", true)
|
||||
PROPERTY4(bool, autoCheckFw, "startup_check_fw", true)
|
||||
PROPERTY4(bool, promptProfile, "startup_prompt_profile", false)
|
||||
|
||||
PROPERTY(bool, enableBackup, false)
|
||||
PROPERTY(bool, backupOnFlash, true)
|
||||
|
|
|
@ -10184,7 +10184,7 @@ We recommend you view the release notes using the button below to learn about an
|
|||
<message>
|
||||
<location filename="../mainwindow.cpp" line="1491"/>
|
||||
<source>Set Menu Language</source>
|
||||
<translation>Inposta Menu Lingua</translation>
|
||||
<translation>Menù Impostazione Lingua</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="1230"/>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
;Include Modern UI
|
||||
|
||||
!include "MUI2.nsh"
|
||||
!include "nsDialogs.nsh"
|
||||
!include "@CMAKE_CURRENT_SOURCE_DIR@\..\targets\windows\FileAssociation.nsh"
|
||||
|
||||
;--------------------------------
|
||||
|
@ -32,6 +33,10 @@
|
|||
;Variables
|
||||
|
||||
Var StartMenuFolder
|
||||
Var StartMenuLocationDialog
|
||||
Var StartMenuLocationRadioCurrent
|
||||
Var StartMenuLocationRadioAll
|
||||
Var StartMenuLocationValue ; "current_user" or "all_users"
|
||||
|
||||
;--------------------------------
|
||||
;Interface Settings
|
||||
|
@ -68,9 +73,11 @@
|
|||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\OpenTX\Companion @VERSION_FAMILY@"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
|
||||
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
|
||||
|
||||
;Start Menu Folder for current user or all users?
|
||||
Page custom StartMenuLocationCreator StartMenuLocationLeave
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
# These indented statements modify settings for MUI_PAGE_FINISH
|
||||
|
@ -117,6 +124,7 @@ Section "OpenTX Companion @VERSION_FAMILY@" SecDummy
|
|||
|
||||
;Registry information for add/remove programs
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "DisplayName" "OpenTX Companion @VERSION_FAMILY@"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "DisplayVersion" "@VERSION@"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "DisplayIcon" "$\"$INSTDIR\companion.exe$\""
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTX Companion @VERSION_FAMILY@" "Publisher" "OpenTX"
|
||||
|
@ -126,10 +134,14 @@ Section "OpenTX Companion @VERSION_FAMILY@" SecDummy
|
|||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
|
||||
;Create shortcuts
|
||||
${If} $StartMenuLocationValue == "all_users"
|
||||
SetShellVarContext all
|
||||
${Endif}
|
||||
CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Companion @VERSION_FAMILY@.lnk" "$INSTDIR\companion.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Firmware Simulator @VERSION_FAMILY@.lnk" "$INSTDIR\simulator.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall Companion @VERSION_FAMILY@.lnk" "$INSTDIR\Uninstall.exe"
|
||||
SetShellVarContext current
|
||||
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
|
||||
|
@ -141,6 +153,14 @@ SectionEnd
|
|||
;Language strings
|
||||
LangString DESC_SecDummy ${LANG_ENGLISH} "Models and settings editor for OpenTX"
|
||||
LangString DESC_SecDummy ${LANG_FRENCH} "Editeur de r<>glages et mod<6F>les pour OpenTX"
|
||||
LangString SML_SubTitle ${LANG_ENGLISH} "Choose a location for the Start Menu shortcuts"
|
||||
LangString SML_SubTitle ${LANG_FRENCH} "Choisissez un emplacement pour les raccourcis de l'application"
|
||||
LangString SML_MainLabel ${LANG_ENGLISH} "Create start menu shortcuts for:"
|
||||
LangString SML_MainLabel ${LANG_FRENCH} "Emplacement pour les raccourcis de l'application:"
|
||||
LangString SML_RadioCurrent ${LANG_ENGLISH} "Current user only"
|
||||
LangString SML_RadioCurrent ${LANG_FRENCH} "Utilisateur actuel"
|
||||
LangString SML_RadioAll ${LANG_ENGLISH} "All users"
|
||||
LangString SML_RadioAll ${LANG_FRENCH} "Tous les utilisateurs"
|
||||
|
||||
;Assign language strings to sections
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
|
@ -203,6 +223,13 @@ Section "un.OpenTX Companion @VERSION_FAMILY@"
|
|||
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder
|
||||
|
||||
; Always remove start menu folder for both locations: current user and all users
|
||||
SetShellVarContext all
|
||||
Delete "$SMPROGRAMS\$StartMenuFolder\Companion @VERSION_FAMILY@.lnk"
|
||||
Delete "$SMPROGRAMS\$StartMenuFolder\Firmware Simulator @VERSION_FAMILY@.lnk"
|
||||
Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall Companion @VERSION_FAMILY@.lnk"
|
||||
RMDir "$SMPROGRAMS\$StartMenuFolder"
|
||||
SetShellVarContext current
|
||||
Delete "$SMPROGRAMS\$StartMenuFolder\Companion @VERSION_FAMILY@.lnk"
|
||||
Delete "$SMPROGRAMS\$StartMenuFolder\Firmware Simulator @VERSION_FAMILY@.lnk"
|
||||
Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall Companion @VERSION_FAMILY@.lnk"
|
||||
|
@ -218,3 +245,58 @@ SectionEnd
|
|||
Function LaunchLink
|
||||
ExecShell "" "$INSTDIR\companion.exe"
|
||||
FunctionEnd
|
||||
|
||||
|
||||
; Custom page with radio buttons, if the start menu entries shall be created
|
||||
; for the current user or for all users.
|
||||
Function StartMenuLocationCreator
|
||||
; Set default value if not already set. Do this before we might "abort" this page.
|
||||
${If} $StartMenuLocationValue == ""
|
||||
StrCpy $StartMenuLocationValue "current_user"
|
||||
${EndIf}
|
||||
|
||||
; If the folder starts with >, the user has chosen not to create a shortcut (see NSIS/StartMenu.nsh)
|
||||
StrCpy $R0 $StartMenuFolder 1
|
||||
${If} $R0 == ">"
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
!insertmacro MUI_HEADER_TEXT_PAGE $(MUI_TEXT_STARTMENU_TITLE) $(SML_SubTitle)
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $StartMenuLocationDialog
|
||||
|
||||
${If} $StartMenuLocationDialog == error
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${NSD_CreateLabel} 0u 0u 100% 12u $(SML_MainLabel)
|
||||
Pop $R0
|
||||
|
||||
${NSD_CreateRadioButton} 8u 20u 100% 12u $(SML_RadioCurrent)
|
||||
Pop $StartMenuLocationRadioCurrent
|
||||
${NSD_AddStyle} $StartMenuLocationRadioCurrent ${WS_GROUP}
|
||||
|
||||
${NSD_CreateRadioButton} 8u 40u 100% 12u $(SML_RadioAll)
|
||||
Pop $StartMenuLocationRadioAll
|
||||
|
||||
${If} $StartMenuLocationValue == "all_users"
|
||||
${NSD_SetState} $StartMenuLocationRadioAll ${BST_CHECKED}
|
||||
${Else}
|
||||
${NSD_SetState} $StartMenuLocationRadioCurrent ${BST_CHECKED}
|
||||
${EndIf}
|
||||
|
||||
${NSD_OnBack} StartMenuLocationLeave
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
; Converts the radio button state back into a value for "StartMenuLocationValue"
|
||||
Function StartMenuLocationLeave
|
||||
${NSD_GetState} $StartMenuLocationRadioAll $R0
|
||||
${If} $R0 == ${BST_CHECKED}
|
||||
StrCpy $StartMenuLocationValue "all_users"
|
||||
${Else}
|
||||
StrCpy $StartMenuLocationValue "current_user"
|
||||
${Endif}
|
||||
FunctionEnd
|
||||
|
|
|
@ -489,7 +489,7 @@ end
|
|||
local function runPopupPage(event)
|
||||
local result
|
||||
if fieldPopup.status == 3 then
|
||||
result = popupConfirmation(fieldPopup.info, event)
|
||||
result = popupConfirmation("Confirmation", fieldPopup.info, event)
|
||||
else
|
||||
result = popupWarning(fieldPopup.info, event)
|
||||
end
|
||||
|
|
157
radio/sdcard/horus/SCRIPTS/TOOLS/MultiChan.txt
Normal file
|
@ -0,0 +1,157 @@
|
|||
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
|
||||
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
|
||||
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
|
||||
1,3,Flysky,V912,1,BtmBtn,TopBtn
|
||||
1,4,Flysky,CX20,0,CH5,CH6,CH7
|
||||
28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Flyzone,FZ-410,0
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
|
||||
37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
|
||||
37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
|
||||
67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
67,1,FrSkyL,LR12_6CH,0,CH5,CH6
|
||||
15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
|
||||
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
|
||||
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
|
||||
57,0,HoTT,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
|
||||
7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
7,3,Devo,6CH,0,CH5,CH6
|
||||
7,4,Devo,7CH,0,CH5,CH6,CH7
|
||||
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
|
||||
30,1,WK2x01,WK2401,0
|
||||
30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
|
||||
30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
|
||||
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
||||
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
|
||||
6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
|
||||
24,0,Assan,Std,0,CH5,CH6,CH7,CH8
|
||||
14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
|
||||
14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
|
||||
14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
|
||||
14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
|
||||
13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
|
||||
12,0,CX10,Green,1,Flip,Rate
|
||||
12,1,CX10,Blue,1,Flip,Rate,Pict,Video
|
||||
12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
|
||||
12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
|
||||
12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
|
||||
12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
|
||||
33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
|
||||
32,0,GW008,FY326,1,Flip
|
||||
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
|
||||
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
|
||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
|
||||
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
|
||||
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
|
||||
29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal
|
||||
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
|
||||
31,2,Q303,CX10D,1,Arm,Flip
|
||||
31,3,Q303,CX10WD,1,Arm,Flip
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
|
||||
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
|
||||
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
|
||||
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
|
||||
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
|
||||
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
|
||||
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
61,0,Tiger,Std,1,Flip,Light
|
||||
46,0,V911s,Std,1,Calib
|
||||
46,1,E119,Std,1,Calib
|
||||
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
||||
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
||||
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
19,0,Shenqi,Cycle,1
|
||||
4,1,Hisky,HK310,0,Aux
|
||||
43,0,Traxxas,6519,0
|
||||
52,0,ZSX,280,1,Light
|
||||
48,0,V761,Std,1,Gyro
|
||||
49,0,KF606,Std,1,Trim
|
||||
47,0,GD00x,V1,1,Trim,LED,Rate
|
||||
47,1,GD00x,V2,1,Trim,LED,Rate
|
||||
58,0,FX816,P38,1
|
302
radio/sdcard/horus/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
Normal file
|
@ -0,0 +1,302 @@
|
|||
|
||||
local toolName = "TNS|Multi chan namer|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # 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. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local protocol_name = ""
|
||||
local sub_protocol_name = ""
|
||||
local bind_ch = 0
|
||||
local module_conf = {}
|
||||
local module_pos = "Internal"
|
||||
local file_ok = 0
|
||||
local done = 0
|
||||
local protocol = 0
|
||||
local sub_protocol = 0
|
||||
local f_seek = 0
|
||||
local channel_names={}
|
||||
local num_search = "Searching"
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Multi_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
drawScreenTitle("Multi channels namer")
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
x_pos = 10
|
||||
y_pos = 32
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 0
|
||||
y_pos = 9
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if module_conf["Type"] ~= 6 then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"No Multi module configured...", BLINK)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"No Multi module configured...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Channel order
|
||||
if (ch_order == -1) then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Can't open file MultiChan.txt
|
||||
if file_ok == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt)
|
||||
return
|
||||
end
|
||||
|
||||
if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt)
|
||||
num_search = num_search .. "."
|
||||
if #num_search > 15 then
|
||||
num_search = string.sub(num_search,1,9)
|
||||
end
|
||||
local proto = 0
|
||||
local sub_proto = 0
|
||||
local proto_name = ""
|
||||
local sub_proto_name = ""
|
||||
local channels = ""
|
||||
local nbr_try = 0
|
||||
local nbr_car = 0
|
||||
repeat
|
||||
io.seek(f, f_seek)
|
||||
local data = io.read(f, 100) -- read 100 characters
|
||||
if #data ==0 then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)')
|
||||
if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then
|
||||
if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then
|
||||
protocol_name = proto_name
|
||||
sub_protocol_name = sub_proto_name
|
||||
bind_ch = tonumber(bind_ch)
|
||||
if channels ~= nil then
|
||||
--extract channel names
|
||||
nbr_car = string.find(channels, "\r")
|
||||
if nbr_car == nil then nbr_car = string.find(channels, "\n") end
|
||||
if nbr_car ~= nil then
|
||||
channels = string.sub(channels,1,nbr_car-1)
|
||||
end
|
||||
local i = 5
|
||||
for k in string.gmatch(channels, ",([%w-_ ]+)") do
|
||||
channel_names[i] = k
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
f_seek = -1 -- protocol found
|
||||
break
|
||||
end
|
||||
end
|
||||
if f_seek ~= -1 then
|
||||
nbr_car = string.find(data, "\n")
|
||||
if nbr_car == nil then nbr_car = string.find(data, "\r") end
|
||||
if nbr_car == nil then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
f_seek = f_seek + nbr_car -- seek to next line
|
||||
nbr_try = nbr_try + 1
|
||||
end
|
||||
until nbr_try > 20 or f_seek == -1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
if f_seek ~= -1 then
|
||||
return -- continue searching...
|
||||
end
|
||||
|
||||
--Protocol & Sub_protocol
|
||||
if protocol_name == "" or sub_protocol_name == "" then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt)
|
||||
return
|
||||
elseif LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
text1=""
|
||||
text2=""
|
||||
for i,v in ipairs(channel_names) do
|
||||
if i<=8 then
|
||||
if i==1 then
|
||||
text1 = v
|
||||
else
|
||||
text1=text1 .. "," .. v
|
||||
end
|
||||
else
|
||||
if i==9 then
|
||||
text2 = v
|
||||
else
|
||||
text2=text2 .. "," .. v
|
||||
end
|
||||
end
|
||||
end
|
||||
if LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt)
|
||||
line = line + 1
|
||||
if text2 ~= "" then
|
||||
lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
if event ~= EVT_VIRTUAL_ENTER and done == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"<ENT> Save", lcd_opt + INVERS + BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt)
|
||||
line = line + 1
|
||||
local output, nbr
|
||||
if done == 0 then
|
||||
for i,v in ipairs(channel_names) do
|
||||
output = model.getOutput(i-1)
|
||||
output["name"] = v
|
||||
model.setOutput(i-1,output)
|
||||
nbr = i
|
||||
end
|
||||
for i = nbr, 15 do
|
||||
output = model.getOutput(i)
|
||||
output["name"] = "n-a"
|
||||
model.setOutput(i,output)
|
||||
end
|
||||
if bind_ch == 1 then
|
||||
output = model.getOutput(15)
|
||||
output["name"] = "BindCH"
|
||||
model.setOutput(15,output)
|
||||
end
|
||||
done = 1
|
||||
end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Multi_Init()
|
||||
module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
module_pos = "External"
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
protocol = module_conf["protocol"]
|
||||
sub_protocol = module_conf["subProtocol"]
|
||||
|
||||
--Exceptions on first 4 channels...
|
||||
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
|
||||
if ( protocol == 4 and sub_protocol ==1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
|
||||
stick_names[2] = "n-a"
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 43 then -- Traxxas
|
||||
stick_names[2] = "Aux4"
|
||||
stick_names[4] = "Aux3"
|
||||
elseif protocol == 48 then -- V761
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
|
||||
stick_names[1] = "n-a"
|
||||
stick_names[2] = "n-a"
|
||||
end
|
||||
|
||||
--Determine fist 4 channels order
|
||||
local ch_order=module_conf["channelsOrder"]
|
||||
if (ch_order == -1) then
|
||||
channel_names[1] = stick_names[defaultChannel(0)+1]
|
||||
channel_names[2] = stick_names[defaultChannel(1)+1]
|
||||
channel_names[3] = stick_names[defaultChannel(2)+1]
|
||||
channel_names[4] = stick_names[defaultChannel(3)+1]
|
||||
else
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[4]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[2]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[3]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[1]
|
||||
end
|
||||
--Check MultiChan.txt
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
file_ok = 1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Multi_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
Multi_Draw_LCD(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
return { init=Multi_Init, run=Multi_Run }
|
BIN
radio/sdcard/horus/THEMES/Darkblue/tx16s.bmp
Executable file → Normal file
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 161 KiB |
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 161 KiB |
|
@ -19,7 +19,8 @@
|
|||
-- Horus Widget to display the levels of lipo battery with per cell indication
|
||||
-- 3djc & Offer Shmuely
|
||||
-- Date: 2020
|
||||
-- ver: 0.4
|
||||
-- ver: 0.5
|
||||
local version = "v0.5"
|
||||
|
||||
local _options = {
|
||||
{ "Sensor", SOURCE, 0 }, -- default to 'Cels'
|
||||
|
@ -28,6 +29,40 @@ local _options = {
|
|||
{ "LowestCell", BOOL, 1 } -- 0=main voltage display shows all-cell-voltage, 1=main voltage display shows lowest-cell
|
||||
}
|
||||
|
||||
-- Data gathered from commercial lipo sensors
|
||||
|
||||
local _lipoPercentListSplit = {
|
||||
{ { 3, 0 }, { 3.093, 1 }, { 3.196, 2 }, { 3.301, 3 }, { 3.401, 4 }, { 3.477, 5 }, { 3.544, 6 }, { 3.601, 7 }, { 3.637, 8 }, { 3.664, 9 }, { 3.679, 10 }, { 3.683, 11 }, { 3.689, 12 }, { 3.692, 13 } },
|
||||
{ { 3.705, 14 }, { 3.71, 15 }, { 3.713, 16 }, { 3.715, 17 }, { 3.72, 18 }, { 3.731, 19 }, { 3.735, 20 }, { 3.744, 21 }, { 3.753, 22 }, { 3.756, 23 }, { 3.758, 24 }, { 3.762, 25 }, { 3.767, 26 } },
|
||||
{ { 3.774, 27 }, { 3.78, 28 }, { 3.783, 29 }, { 3.786, 30 }, { 3.789, 31 }, { 3.794, 32 }, { 3.797, 33 }, { 3.8, 34 }, { 3.802, 35 }, { 3.805, 36 }, { 3.808, 37 }, { 3.811, 38 }, { 3.815, 39 } },
|
||||
{ { 3.818, 40 }, { 3.822, 41 }, { 3.825, 42 }, { 3.829, 43 }, { 3.833, 44 }, { 3.836, 45 }, { 3.84, 46 }, { 3.843, 47 }, { 3.847, 48 }, { 3.85, 49 }, { 3.854, 50 }, { 3.857, 51 }, { 3.86, 52 } },
|
||||
{ { 3.863, 53 }, { 3.866, 54 }, { 3.87, 55 }, { 3.874, 56 }, { 3.879, 57 }, { 3.888, 58 }, { 3.893, 59 }, { 3.897, 60 }, { 3.902, 61 }, { 3.906, 62 }, { 3.911, 63 }, { 3.918, 64 } },
|
||||
{ { 3.923, 65 }, { 3.928, 66 }, { 3.939, 67 }, { 3.943, 68 }, { 3.949, 69 }, { 3.955, 70 }, { 3.961, 71 }, { 3.968, 72 }, { 3.974, 73 }, { 3.981, 74 }, { 3.987, 75 }, { 3.994, 76 } },
|
||||
{ { 4.001, 77 }, { 4.007, 78 }, { 4.014, 79 }, { 4.021, 80 }, { 4.029, 81 }, { 4.036, 82 }, { 4.044, 83 }, { 4.052, 84 }, { 4.062, 85 }, { 4.074, 86 }, { 4.085, 87 }, { 4.095, 88 } },
|
||||
{ { 4.105, 89 }, { 4.111, 90 }, { 4.116, 91 }, { 4.12, 92 }, { 4.125, 93 }, { 4.129, 94 }, { 4.135, 95 }, { 4.145, 96 }, { 4.176, 97 }, { 4.179, 98 }, { 4.193, 99 }, { 4.2, 100 } },
|
||||
}
|
||||
|
||||
local function periodicInit(t, durationMili)
|
||||
t.startTime = getTime();
|
||||
t.durationMili = durationMili;
|
||||
end
|
||||
local function periodicReset(t)
|
||||
t.startTime = getTime();
|
||||
end
|
||||
local function periodicHasPassed(t)
|
||||
local elapsed = getTime() - t.startTime;
|
||||
local elapsedMili = elapsed * 10;
|
||||
if (elapsedMili < t.durationMili) then
|
||||
return false;
|
||||
end
|
||||
return true;
|
||||
end
|
||||
local function periodicGetElapsedTime(t)
|
||||
local elapsed = getTime() - t.startTime;
|
||||
local elapsedMili = elapsed * 10;
|
||||
return elapsedMili;
|
||||
end
|
||||
|
||||
-- This function is run once at the creation of the widget
|
||||
local function create(zone, options)
|
||||
local wgt = {
|
||||
|
@ -50,7 +85,10 @@ local function create(zone, options)
|
|||
cellCount = 0,
|
||||
cellSum = 0,
|
||||
mainValue = 0,
|
||||
secondaryValue = 0
|
||||
secondaryValue = 0,
|
||||
periodic1 = { startTime = getTime(), durationMili = 1000 },
|
||||
periodicProfiler = { startTime = getTime(), durationMili = 5000 },
|
||||
profTimes = {},
|
||||
}
|
||||
|
||||
-- use default if user did not set, So widget is operational on "select widget"
|
||||
|
@ -65,7 +103,9 @@ end
|
|||
|
||||
-- This function allow updates when you change widgets settings
|
||||
local function update(wgt, options)
|
||||
if (wgt == nil) then return end
|
||||
if (wgt == nil) then
|
||||
return
|
||||
end
|
||||
|
||||
wgt.options = options
|
||||
|
||||
|
@ -99,9 +139,12 @@ end
|
|||
local function detectResetEvent(wgt)
|
||||
|
||||
local currMinRSSI = getValue('RSSI-')
|
||||
if (currMinRSSI == nil) then return
|
||||
if (currMinRSSI == nil) then
|
||||
return
|
||||
end
|
||||
if (currMinRSSI == wgt.telemResetLowestMinRSSI) then
|
||||
return
|
||||
end
|
||||
if (currMinRSSI == wgt.telemResetLowestMinRSSI) then return end
|
||||
|
||||
if (currMinRSSI < wgt.telemResetLowestMinRSSI) then
|
||||
-- rssi just got lower, record it
|
||||
|
@ -118,29 +161,29 @@ local function detectResetEvent(wgt)
|
|||
|
||||
end
|
||||
|
||||
|
||||
--- This function return the percentage remaining in a single Lipo cel
|
||||
local function getCellPercent(cellValue)
|
||||
--- since running on long array found to be very intensive to hrous cpu, we are splitting the list to small lists
|
||||
local function getCellPercent(wgt, cellValue)
|
||||
if cellValue == nil then
|
||||
return 0
|
||||
end
|
||||
local result = 0;
|
||||
|
||||
-- in case somehow voltage is higher, don't return nil
|
||||
if (cellValue > 4.2) then
|
||||
return 100
|
||||
end
|
||||
|
||||
-- Data gathered from commercial lipo sensors
|
||||
local myArrayPercentList = { {3,0},{3.093,1},{3.196,2},{3.301,3},{3.401,4},{3.477,5},{3.544,6},{3.601,7},{3.637,8},{3.664,9},{3.679,10},{3.683,11},{3.689,12},{3.692,13},{3.705,14},{3.71,15},{3.713,16},{3.715,17},{3.72,18},{3.731,19},{3.735,20},{3.744,21},{3.753,22},{3.756,23},{3.758,24},{3.762,25},{3.767,26},{3.774,27},{3.78,28},{3.783,29},{3.786,30},{3.789,31},{3.794,32},{3.797,33},{3.8,34},{3.802,35},{3.805,36},{3.808,37},{3.811,38},{3.815,39},{3.818,40},{3.822,41},{3.825,42},{3.829,43},{3.833,44},{3.836,45},{3.84,46},{3.843,47},{3.847,48},{3.85,49},{3.854,50},{3.857,51},{3.86,52},{3.863,53},{3.866,54},{3.87,55},{3.874,56},{3.879,57},{3.888,58},{3.893,59},{3.897,60},{3.902,61},{3.906,62},{3.911,63},{3.918,64},{3.923,65},{3.928,66},{3.939,67},{3.943,68},{3.949,69},{3.955,70},{3.961,71},{3.968,72},{3.974,73},{3.981,74},{3.987,75},{3.994,76},{4.001,77},{4.007,78},{4.014,79},{4.021,80},{4.029,81},{4.036,82},{4.044,83},{4.052,84},{4.062,85},{4.074,86},{4.085,87},{4.095,88},{4.105,89},{4.111,90},{4.116,91},{4.12,92},{4.125,93},{4.129,94},{4.135,95},{4.145,96},{4.176,97},{4.179,98},{4.193,99},{4.2,100} }
|
||||
|
||||
for i, v in ipairs(myArrayPercentList) do
|
||||
if v[1] >= cellValue then
|
||||
result = v[2]
|
||||
break
|
||||
end
|
||||
end
|
||||
for i1, v1 in ipairs(_lipoPercentListSplit) do
|
||||
--is the cellVal < last-value-on-sub-list? (first-val:v1[1], last-val:v1[#v1])
|
||||
if (cellValue <= v1[#v1][1]) then
|
||||
-- cellVal is in this sub-list, find the exact value
|
||||
for i2, v2 in ipairs(v1) do
|
||||
if v2[1] >= cellValue then
|
||||
result = v2[2]
|
||||
return result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- in case somehow voltage is too high (>4.2), don't return nil
|
||||
return 100
|
||||
end
|
||||
|
||||
--- This function returns a table with cels values
|
||||
local function calculateBatteryData(wgt)
|
||||
|
@ -152,20 +195,13 @@ local function calculateBatteryData(wgt)
|
|||
return
|
||||
end
|
||||
|
||||
-- this is necessary for simu where cell-count can change
|
||||
if #wgt.cellDataHistoryLowest ~= #newCellData then
|
||||
wgt.cellDataHistoryLowest = {}
|
||||
for k, v in pairs(newCellData) do
|
||||
wgt.cellDataHistoryLowest[k] = 5 -- invalid reading, set high value so the min() will update it soon
|
||||
end
|
||||
end
|
||||
|
||||
local cellMax = 0
|
||||
local cellMin = 5
|
||||
local cellSum = 0
|
||||
for k, v in pairs(newCellData) do
|
||||
-- stores the lowest cell values in historical table
|
||||
if v > 1 and v < wgt.cellDataHistoryLowest[k] then -- min 1v to consider a valid reading
|
||||
if v > 1 and v < wgt.cellDataHistoryLowest[k] then
|
||||
-- min 1v to consider a valid reading
|
||||
wgt.cellDataHistoryLowest[k] = v
|
||||
|
||||
--- calc history lowest of all cells
|
||||
|
@ -181,7 +217,8 @@ local function calculateBatteryData(wgt)
|
|||
end
|
||||
|
||||
--- calc lowest of all cells
|
||||
if v < cellMin and v > 1 then -- min 1v to consider a valid reading
|
||||
if v < cellMin and v > 1 then
|
||||
-- min 1v to consider a valid reading
|
||||
cellMin = v
|
||||
end
|
||||
--- sum of all cells
|
||||
|
@ -197,7 +234,6 @@ local function calculateBatteryData(wgt)
|
|||
|
||||
--- average of all cells
|
||||
wgt.cellAvg = wgt.cellSum / wgt.cellCount
|
||||
wgt.cellPercent = getCellPercent(wgt.cellMin)
|
||||
|
||||
wgt.cellDataLive = newCellData
|
||||
|
||||
|
@ -219,12 +255,18 @@ local function calculateBatteryData(wgt)
|
|||
wgt.secondaryValue = "-2"
|
||||
end
|
||||
|
||||
|
||||
wgt.isDataAvailable = true
|
||||
|
||||
-- calculate intensive CPU data
|
||||
if (periodicHasPassed(wgt.periodic1) or wgt.cellPercent == 0) then
|
||||
|
||||
--wgt.cellPercent = getCellPercent(wgt, wgt.cellMin) -- use batt percentage by lowest cell voltage
|
||||
wgt.cellPercent = getCellPercent(wgt, wgt.cellAvg) -- use batt percentage by average cell voltage
|
||||
|
||||
periodicReset(wgt.periodic1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- color for battery
|
||||
-- This function returns green at 100%, red bellow 30% and graduate in between
|
||||
|
@ -242,24 +284,36 @@ end
|
|||
-- This function returns green at gvalue, red at rvalue and graduate in between
|
||||
local function getRangeColor(value, green_value, red_value)
|
||||
local range = math.abs(green_value - red_value)
|
||||
if range==0 then return lcd.RGB(0, 0xdf, 0) end
|
||||
if range == 0 then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value == nil then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
|
||||
if green_value > red_value then
|
||||
if value > green_value then return lcd.RGB(0, 0xdf, 0) end
|
||||
if value < red_value then return lcd.RGB(0xdf, 0, 0) end
|
||||
if value > green_value then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value < red_value then
|
||||
return lcd.RGB(0xdf, 0, 0)
|
||||
end
|
||||
g = math.floor(0xdf * (value - red_value) / range)
|
||||
r = 0xdf - g
|
||||
return lcd.RGB(r, g, 0)
|
||||
else
|
||||
if value > green_value then return lcd.RGB(0, 0xdf, 0) end
|
||||
if value < red_value then return lcd.RGB(0xdf, 0, 0) end
|
||||
if value > green_value then
|
||||
return lcd.RGB(0, 0xdf, 0)
|
||||
end
|
||||
if value < red_value then
|
||||
return lcd.RGB(0xdf, 0, 0)
|
||||
end
|
||||
r = math.floor(0xdf * (value - green_value) / range)
|
||||
g = 0xdf - r
|
||||
return lcd.RGB(r, g, 0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Zone size: 70x39 1/8th top bar
|
||||
local function refreshZoneTiny(wgt)
|
||||
local myString = string.format("%2.1fV", wgt.mainValue)
|
||||
|
@ -307,12 +361,12 @@ local function refreshZoneMedium(wgt)
|
|||
end
|
||||
|
||||
-- draw values
|
||||
lcd.drawText(wgt.zone.x, wgt.zone.y + 35, string.format("%2.1fV", wgt.mainValue), DBLSIZE + CUSTOM_COLOR + wgt.shadowed + wgt.no_telem_blink)
|
||||
lcd.drawText(wgt.zone.x + wgt.zone.w, wgt.zone.y, string.format("%2.1fV", wgt.mainValue), DBLSIZE + CUSTOM_COLOR + RIGHT + wgt.shadowed + wgt.no_telem_blink)
|
||||
|
||||
-- more info if 1/4 is high enough (without trim & slider)
|
||||
if wgt.zone.h > 80 then
|
||||
lcd.drawText(wgt.zone.x , wgt.zone.y + 70, string.format("%2.2fV" , wgt.secondaryValue), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink)
|
||||
lcd.drawText(wgt.zone.x + 50, wgt.zone.y + 70, string.format("dV %2.2fV", wgt.cellMax - wgt.cellMin), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink)
|
||||
--lcd.drawText(wgt.zone.x + 50 , wgt.zone.y + 70, string.format("%2.2fV" , wgt.secondaryValue), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink)
|
||||
lcd.drawText(wgt.zone.x, wgt.zone.y + 70, string.format("dV %2.2fV", wgt.cellMax - wgt.cellMin), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink)
|
||||
lcd.drawText(wgt.zone.x, wgt.zone.y + 84, string.format("Min %2.2fV", wgt.cellDataHistoryCellLowest), SMLSIZE + CUSTOM_COLOR + wgt.no_telem_blink)
|
||||
end
|
||||
|
||||
|
@ -321,28 +375,21 @@ local function refreshZoneMedium(wgt)
|
|||
lcd.drawGauge(wgt.zone.x + myBatt.x, wgt.zone.y + myBatt.y, myBatt.w, myBatt.h, wgt.cellPercent, 100, CUSTOM_COLOR)
|
||||
|
||||
-- draw cells
|
||||
local cellH = wgt.zone.h / wgt.cellCount
|
||||
if cellH > 20 then cellH =20 end
|
||||
local cellH = 19
|
||||
local cellX = 118
|
||||
local cellW = 58
|
||||
local cellW = wgt.zone.w / 3
|
||||
|
||||
local pos = { { x = 0, y = 38 }, { x = cellW, y = 38 }, { x = 2 * cellW, y = 38 }, { x = 0, y = 57 }, { x = cellW, y = 57 }, { x = 2 * cellW, y = 57 } }
|
||||
for i = 1, wgt.cellCount, 1 do
|
||||
local cellY = wgt.zone.y + (i - 1) * (cellH - 1)
|
||||
|
||||
-- fill current cell
|
||||
lcd.setColor(CUSTOM_COLOR, getRangeColor(wgt.cellDataLive[i], wgt.cellMax, wgt.cellMax - 0.2))
|
||||
--lcd.drawFilledRectangle(wgt.zone.x + cellX , cellY, 58, cellH, CUSTOM_COLOR)
|
||||
local percentCurrent = getCellPercent(wgt.cellDataLive[i])
|
||||
local percentMin = getCellPercent(wgt.cellDataHistoryLowest[i])
|
||||
|
||||
lcd.drawFilledRectangle(wgt.zone.x + cellX , cellY, cellW * percentCurrent / 100, cellH, CUSTOM_COLOR)
|
||||
|
||||
-- fill min
|
||||
lcd.setColor(CUSTOM_COLOR, getRangeColor(wgt.cellDataHistoryLowest[i], wgt.cellMax, wgt.cellMax - 0.2))
|
||||
lcd.drawFilledRectangle(wgt.zone.x + cellX + ((percentCurrent - percentMin) / 100) , cellY, cellW - (cellW * (percentCurrent - percentMin) / 100), cellH, CUSTOM_COLOR)
|
||||
|
||||
lcd.setColor(CUSTOM_COLOR, getRangeColor(wgt.cellDataLive[i], wgt.cellMax, wgt.cellMax - 0.2))
|
||||
lcd.drawFilledRectangle(wgt.zone.x + pos[i].x, wgt.zone.y + pos[i].y, cellW - 1, 20, CUSTOM_COLOR)
|
||||
lcd.setColor(CUSTOM_COLOR, WHITE)
|
||||
lcd.drawText (wgt.zone.x + cellX + 10, cellY, string.format("%.2f", wgt.cellDataLive[i]), SMLSIZE + CUSTOM_COLOR + wgt.shadowed + wgt.no_telem_blink)
|
||||
lcd.drawRectangle (wgt.zone.x + cellX , cellY, 59, cellH, CUSTOM_COLOR , 1)
|
||||
lcd.drawText(wgt.zone.x + pos[i].x + 10, wgt.zone.y + pos[i].y, string.format("%.2f", wgt.cellDataLive[i]), CUSTOM_COLOR + wgt.shadowed)
|
||||
lcd.drawRectangle(wgt.zone.x + pos[i].x, wgt.zone.y + pos[i].y, cellW, 20, CUSTOM_COLOR, 1)
|
||||
end
|
||||
|
||||
-- draws bat
|
||||
|
@ -447,7 +494,9 @@ end
|
|||
|
||||
-- This function allow recording of lowest cells when widget is in background
|
||||
local function background(wgt)
|
||||
if (wgt == nil) then return end
|
||||
if (wgt == nil) then
|
||||
return
|
||||
end
|
||||
|
||||
detectResetEvent(wgt)
|
||||
|
||||
|
@ -456,11 +505,21 @@ local function background(wgt)
|
|||
end
|
||||
|
||||
local function refresh(wgt)
|
||||
|
||||
if (wgt == nil) then return end
|
||||
if (wgt.options == nil) then return end
|
||||
if (wgt.zone == nil) then return end
|
||||
if (wgt.options.LowestCell == nil) then return end
|
||||
if (wgt == nil) then
|
||||
return
|
||||
end
|
||||
if type(wgt) ~= "table" then
|
||||
return
|
||||
end
|
||||
if (wgt.options == nil) then
|
||||
return
|
||||
end
|
||||
if (wgt.zone == nil) then
|
||||
return
|
||||
end
|
||||
if (wgt.options.LowestCell == nil) then
|
||||
return
|
||||
end
|
||||
|
||||
if wgt.options.Shadow == 1 then
|
||||
wgt.shadowed = SHADOWED
|
||||
|
@ -478,14 +537,17 @@ local function refresh(wgt)
|
|||
wgt.no_telem_blink = INVERS + BLINK
|
||||
end
|
||||
|
||||
|
||||
if wgt.zone.w > 380 and wgt.zone.h > 165 then refreshZoneXLarge(wgt)
|
||||
elseif wgt.zone.w > 180 and wgt.zone.h > 145 then refreshZoneLarge(wgt)
|
||||
elseif wgt.zone.w > 170 and wgt.zone.h > 65 then refreshZoneMedium(wgt)
|
||||
elseif wgt.zone.w > 150 and wgt.zone.h > 28 then refreshZoneSmall(wgt)
|
||||
elseif wgt.zone.w > 65 and wgt.zone.h > 35 then refreshZoneTiny(wgt)
|
||||
if wgt.zone.w > 380 and wgt.zone.h > 165 then
|
||||
refreshZoneXLarge(wgt)
|
||||
elseif wgt.zone.w > 180 and wgt.zone.h > 145 then
|
||||
refreshZoneLarge(wgt)
|
||||
elseif wgt.zone.w > 170 and wgt.zone.h > 65 then
|
||||
refreshZoneMedium(wgt)
|
||||
elseif wgt.zone.w > 150 and wgt.zone.h > 28 then
|
||||
refreshZoneSmall(wgt)
|
||||
elseif wgt.zone.w > 65 and wgt.zone.h > 35 then
|
||||
refreshZoneTiny(wgt)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return { name = "BattCheck", options = _options, create = create, update = update, background = background, refresh = refresh }
|
157
radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChan.txt
Normal file
|
@ -0,0 +1,157 @@
|
|||
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
|
||||
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
|
||||
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
|
||||
1,3,Flysky,V912,1,BtmBtn,TopBtn
|
||||
1,4,Flysky,CX20,0,CH5,CH6,CH7
|
||||
28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Flyzone,FZ-410,0
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
|
||||
37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
|
||||
37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
|
||||
67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
67,1,FrSkyL,LR12_6CH,0,CH5,CH6
|
||||
15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
|
||||
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
|
||||
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
|
||||
57,0,HoTT,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
|
||||
7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
7,3,Devo,6CH,0,CH5,CH6
|
||||
7,4,Devo,7CH,0,CH5,CH6,CH7
|
||||
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
|
||||
30,1,WK2x01,WK2401,0
|
||||
30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
|
||||
30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
|
||||
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
||||
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
|
||||
6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
|
||||
24,0,Assan,Std,0,CH5,CH6,CH7,CH8
|
||||
14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
|
||||
14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
|
||||
14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
|
||||
14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
|
||||
13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
|
||||
12,0,CX10,Green,1,Flip,Rate
|
||||
12,1,CX10,Blue,1,Flip,Rate,Pict,Video
|
||||
12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
|
||||
12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
|
||||
12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
|
||||
12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
|
||||
33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
|
||||
32,0,GW008,FY326,1,Flip
|
||||
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
|
||||
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
|
||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
|
||||
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
|
||||
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
|
||||
29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal
|
||||
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
|
||||
31,2,Q303,CX10D,1,Arm,Flip
|
||||
31,3,Q303,CX10WD,1,Arm,Flip
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
|
||||
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
|
||||
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
|
||||
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
|
||||
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
|
||||
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
|
||||
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
61,0,Tiger,Std,1,Flip,Light
|
||||
46,0,V911s,Std,1,Calib
|
||||
46,1,E119,Std,1,Calib
|
||||
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
||||
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
||||
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
19,0,Shenqi,Cycle,1
|
||||
4,1,Hisky,HK310,0,Aux
|
||||
43,0,Traxxas,6519,0
|
||||
52,0,ZSX,280,1,Light
|
||||
48,0,V761,Std,1,Gyro
|
||||
49,0,KF606,Std,1,Trim
|
||||
47,0,GD00x,V1,1,Trim,LED,Rate
|
||||
47,1,GD00x,V2,1,Trim,LED,Rate
|
||||
58,0,FX816,P38,1
|
302
radio/sdcard/taranis-x7/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
Normal file
|
@ -0,0 +1,302 @@
|
|||
|
||||
local toolName = "TNS|Multi chan namer|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # 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. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local protocol_name = ""
|
||||
local sub_protocol_name = ""
|
||||
local bind_ch = 0
|
||||
local module_conf = {}
|
||||
local module_pos = "Internal"
|
||||
local file_ok = 0
|
||||
local done = 0
|
||||
local protocol = 0
|
||||
local sub_protocol = 0
|
||||
local f_seek = 0
|
||||
local channel_names={}
|
||||
local num_search = "Searching"
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Multi_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
drawScreenTitle("Multi channels namer")
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
x_pos = 10
|
||||
y_pos = 32
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 0
|
||||
y_pos = 9
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if module_conf["Type"] ~= 6 then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"No Multi module configured...", BLINK)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"No Multi module configured...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Channel order
|
||||
if (ch_order == -1) then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Can't open file MultiChan.txt
|
||||
if file_ok == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt)
|
||||
return
|
||||
end
|
||||
|
||||
if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt)
|
||||
num_search = num_search .. "."
|
||||
if #num_search > 15 then
|
||||
num_search = string.sub(num_search,1,9)
|
||||
end
|
||||
local proto = 0
|
||||
local sub_proto = 0
|
||||
local proto_name = ""
|
||||
local sub_proto_name = ""
|
||||
local channels = ""
|
||||
local nbr_try = 0
|
||||
local nbr_car = 0
|
||||
repeat
|
||||
io.seek(f, f_seek)
|
||||
local data = io.read(f, 100) -- read 100 characters
|
||||
if #data ==0 then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)')
|
||||
if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then
|
||||
if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then
|
||||
protocol_name = proto_name
|
||||
sub_protocol_name = sub_proto_name
|
||||
bind_ch = tonumber(bind_ch)
|
||||
if channels ~= nil then
|
||||
--extract channel names
|
||||
nbr_car = string.find(channels, "\r")
|
||||
if nbr_car == nil then nbr_car = string.find(channels, "\n") end
|
||||
if nbr_car ~= nil then
|
||||
channels = string.sub(channels,1,nbr_car-1)
|
||||
end
|
||||
local i = 5
|
||||
for k in string.gmatch(channels, ",([%w-_ ]+)") do
|
||||
channel_names[i] = k
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
f_seek = -1 -- protocol found
|
||||
break
|
||||
end
|
||||
end
|
||||
if f_seek ~= -1 then
|
||||
nbr_car = string.find(data, "\n")
|
||||
if nbr_car == nil then nbr_car = string.find(data, "\r") end
|
||||
if nbr_car == nil then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
f_seek = f_seek + nbr_car -- seek to next line
|
||||
nbr_try = nbr_try + 1
|
||||
end
|
||||
until nbr_try > 20 or f_seek == -1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
if f_seek ~= -1 then
|
||||
return -- continue searching...
|
||||
end
|
||||
|
||||
--Protocol & Sub_protocol
|
||||
if protocol_name == "" or sub_protocol_name == "" then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt)
|
||||
return
|
||||
elseif LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
text1=""
|
||||
text2=""
|
||||
for i,v in ipairs(channel_names) do
|
||||
if i<=8 then
|
||||
if i==1 then
|
||||
text1 = v
|
||||
else
|
||||
text1=text1 .. "," .. v
|
||||
end
|
||||
else
|
||||
if i==9 then
|
||||
text2 = v
|
||||
else
|
||||
text2=text2 .. "," .. v
|
||||
end
|
||||
end
|
||||
end
|
||||
if LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt)
|
||||
line = line + 1
|
||||
if text2 ~= "" then
|
||||
lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
if event ~= EVT_VIRTUAL_ENTER and done == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"<ENT> Save", lcd_opt + INVERS + BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt)
|
||||
line = line + 1
|
||||
local output, nbr
|
||||
if done == 0 then
|
||||
for i,v in ipairs(channel_names) do
|
||||
output = model.getOutput(i-1)
|
||||
output["name"] = v
|
||||
model.setOutput(i-1,output)
|
||||
nbr = i
|
||||
end
|
||||
for i = nbr, 15 do
|
||||
output = model.getOutput(i)
|
||||
output["name"] = "n-a"
|
||||
model.setOutput(i,output)
|
||||
end
|
||||
if bind_ch == 1 then
|
||||
output = model.getOutput(15)
|
||||
output["name"] = "BindCH"
|
||||
model.setOutput(15,output)
|
||||
end
|
||||
done = 1
|
||||
end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Multi_Init()
|
||||
module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
module_pos = "External"
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
protocol = module_conf["protocol"]
|
||||
sub_protocol = module_conf["subProtocol"]
|
||||
|
||||
--Exceptions on first 4 channels...
|
||||
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
|
||||
if ( protocol == 4 and sub_protocol ==1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
|
||||
stick_names[2] = "n-a"
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 43 then -- Traxxas
|
||||
stick_names[2] = "Aux4"
|
||||
stick_names[4] = "Aux3"
|
||||
elseif protocol == 48 then -- V761
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
|
||||
stick_names[1] = "n-a"
|
||||
stick_names[2] = "n-a"
|
||||
end
|
||||
|
||||
--Determine fist 4 channels order
|
||||
local ch_order=module_conf["channelsOrder"]
|
||||
if (ch_order == -1) then
|
||||
channel_names[1] = stick_names[defaultChannel(0)+1]
|
||||
channel_names[2] = stick_names[defaultChannel(1)+1]
|
||||
channel_names[3] = stick_names[defaultChannel(2)+1]
|
||||
channel_names[4] = stick_names[defaultChannel(3)+1]
|
||||
else
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[4]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[2]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[3]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[1]
|
||||
end
|
||||
--Check MultiChan.txt
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
file_ok = 1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Multi_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
Multi_Draw_LCD(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
return { init=Multi_Init, run=Multi_Run }
|
157
radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChan.txt
Normal file
|
@ -0,0 +1,157 @@
|
|||
1,0,Flysky,Flysky,0,CH5,CH6,CH7,CH8
|
||||
1,1,Flysky,V9x9,1,Flip,Light,Pict,Video
|
||||
1,2,Flysky,V6x6,1,Flip,Light,Pict,Video,HLess,RTH,XCAL,YCAL
|
||||
1,3,Flysky,V912,1,BtmBtn,TopBtn
|
||||
1,4,Flysky,CX20,0,CH5,CH6,CH7
|
||||
28,0,Flysky_AFHDS2A,PWM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,1,Flysky_AFHDS2A,PPM_IBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,2,Flysky_AFHDS2A,PWM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
28,3,Flysky_AFHDS2A,PPM_SBUS,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
53,0,Flyzone,FZ-410,0
|
||||
2,0,Hubsan,H107,1,Flip,Light,Pict,Video,HLess
|
||||
2,1,Hubsan,H301,0,RTH,Light,Stab,Video
|
||||
2,2,Hubsan,H501,0,RTH,Light,Pict,Video,HLess,GPS_H,ALT_H,Flip,FModes
|
||||
41,0,Bugs,3-6-8,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
60,0,Pelikan,PRO_V4,0,CH5,CH6,CH7,CH8
|
||||
37,0,Corona,COR_V1,0,CH5,CH6,CH7,CH8
|
||||
37,1,Corona,COR_V2,0,CH5,CH6,CH7,CH8
|
||||
37,2,Corona,FD_V3,0,CH5,CH6,CH7,CH8
|
||||
25,0,FrSkyV,V8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8,0,CH5,CH6,CH7,CH8
|
||||
3,0,FrSkyD,D8Cloned,0,CH5,CH6,CH7,CH8
|
||||
67,0,FrSkyL,LR12,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
67,1,FrSkyL,LR12_6CH,0,CH5,CH6
|
||||
15,0,FrSkyX,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,1,FrSkyX,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
15,2,FrSkyX,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
15,3,FrSkyX,D16_8CH_LBT,0,CH5,CH6,CH7,CH8
|
||||
15,4,FrSkyX,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,0,FrSkyX2,D16_FCC,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,1,FrSkyX2,D16_8CH_FCC,0,CH5,CH6,CH7,CH8
|
||||
64,2,FrSkyX2,D16_LBT,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
64,3,FrSkyX2,D16_8CH_LBT,1,CH5,CH6,CH7,CH8
|
||||
64,4,FrSkyX2,D16Cloned,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,0,FrSkyRX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
55,1,FrSkyRX,CloneTX,0
|
||||
39,0,Hitec,Opt_Fw,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,1,Hitec,Opt_Hub,0,CH5,CH6,CH7,CH8,CH9
|
||||
39,2,Hitec,Minima,0,CH5,CH6,CH7,CH8,CH9
|
||||
57,0,HoTT,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
21,0,SFHSS,Std,0,CH5,CH6,CH7,CH8
|
||||
68,0,Skyartec,Std,0,CH5,CH6,CH7
|
||||
7,0,Devo,8CH,0,CH5,CH6,CH7,CH8
|
||||
7,1,Devo,10CH,0,CH5,CH6,CH7,CH8,CH9,CH10
|
||||
7,2,Devo,12CH,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
7,3,Devo,6CH,0,CH5,CH6
|
||||
7,4,Devo,7CH,0,CH5,CH6,CH7
|
||||
30,0,WK2x01,WK2801,0,CH5,CH6,CH7,CH8
|
||||
30,1,WK2x01,WK2401,0
|
||||
30,2,WK2x01,W6_5_1,0,Gear,Dis,Gyro
|
||||
30,3,WK2x01,W6_6_1,0,Gear,Col,Gyro
|
||||
30,4,WK2x01,W6HEL,0,Gear,Col,Gyro
|
||||
30,5,WK2x01,W6HEL_I,0,Gear,Col,Gyro
|
||||
6,0,DSM,2_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,1,DSM,2_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,2,DSM,X_22,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
6,3,DSM,X_11,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,n-a,ThKill
|
||||
22,0,J6Pro,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12
|
||||
22,0,WFLY,WFR0xS,0,CH5,CH6,CH7,CH8,CH9
|
||||
24,0,Assan,Std,0,CH5,CH6,CH7,CH8
|
||||
14,0,Bayang,Std,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,n-a,n-a,AnAux1,AnAux2
|
||||
14,1,Bayang,H8S3D,1,Flip,RTH,Pict,Video,HLess,Invert,Rates
|
||||
14,2,Bayang,X16_AH,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf
|
||||
14,3,Bayang,IRDRONE,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
14,4,Bayang,DHD_D4,1,Flip,RTH,Pict,Video,HLess,Invert,Rates,TakeOf,EmStop
|
||||
59,0,BayangRX,RX,1,AnAux1,AnAux2,Flip,RTH,Pict,Video
|
||||
42,0,BugsMini,Mini,0,Arm,Angle,Flip,Pict,Video,LED
|
||||
42,1,BugsMini,3H,0,Arm,Angle,Flip,Pict,Video,LED,AltHol
|
||||
34,0,Cabell,V3,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
34,1,Cabell,V3Telem,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
13,0,CG023,Std,1,Flip,Light,Pict,Video,HLess
|
||||
13,1,CG023,YD829,1,Flip,n-a,Pict,Video,HLess
|
||||
12,0,CX10,Green,1,Flip,Rate
|
||||
12,1,CX10,Blue,1,Flip,Rate,Pict,Video
|
||||
12,2,CX10,DM007,1,Flip,Mode,Pict,Video,HLess
|
||||
12,4,CX10,JC3015_1,1,Flip,Mode,Pict,Video
|
||||
12,5,CX10,JC3015_2,1,Flip,Mode,LED,DFlip
|
||||
12,6,CX10,MK33041,1,Flip,Mode,Pict,Video,HLess,RTH
|
||||
33,0,DM022,Std,1,Flip,LED,Cam1,Cam2,HLess,RTH,RLow
|
||||
45,0,E01X,E012,1,n-a,Flip,n-a,HLess,RTH
|
||||
45,1,E01X,E015,1,Arm,Flip,LED,HLess,RTH
|
||||
45,2,E01X,E016H,1,Stop,Flip,n-a,HLess,RTH
|
||||
16,0,ESKY,Std,0,Gyro,Pitch
|
||||
16,1,ESKY,ET4,0,Gyro,Pitch
|
||||
35,0,ESKY150,4CH,0
|
||||
35,1,ESKY150,7CH,0,FMode,Aux6,Aux7
|
||||
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
|
||||
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
|
||||
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
|
||||
32,0,GW008,FY326,1,Flip
|
||||
36,0,H8_3D,Std,1,Flip,Light,Pict,Video,RTH,FlMode,Cal1
|
||||
36,1,H8_3D,H20H,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,2,H8_3D,H20,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
36,3,H8_3D,H30,1,Flip,Light,Pict,Video,Opt1,Opt2,Cal1,Cal2,Gimbal
|
||||
4,0,Hisky,Std,0,Gear,Pitch,Gyro,CH8
|
||||
9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim
|
||||
26,0,Hontai,Std,1,Flip,LED,Pict,Video,HLess,RTH,Calib
|
||||
26,1,Hontai,JJRCX1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,2,Hontai,X5C1,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
26,3,Hontai,FQ777_951,1,Flip,Arm,Pict,Video,HLess,RTH,Calib
|
||||
18,0,MJXQ,WHL08,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,1,MJXQ,X600,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,2,MJXQ,X800,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,3,MJXQ,H26D,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,4,MJXQ,E010,1,Flip,LED,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,5,MJXQ,H26WH,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
18,6,MJXQ,Phoenix,1,Flip,Arm,Pict,Video,HLess,RTH,AuFlip,Pan,Tilt,Rate
|
||||
17,0,MT99XX,Std,1,Flip,LED,Pict,Video,HLess
|
||||
17,1,MT99XX,H7,1,Flip,LED,Pict,Video,HLess
|
||||
17,2,MT99XX,YZ,1,Flip,LED,Pict,Video,HLess
|
||||
17,3,MT99XX,LS,1,Flip,Invert,Pict,Video,HLess
|
||||
17,4,MT99XX,FY805,1,Flip,n-a,n-a,n-a,HLess
|
||||
44,0,NCC1701,Std,1,Warp
|
||||
51,0,Potensic,A20,1,TakLan,Emerg,Mode,HLess
|
||||
66,0,Propel,74-Z,1,LEDs,RollCW,RolCCW,Fire,Weapon,Calib,AltHol,TakeOf,Land,Train
|
||||
29,0,Q2x2,Q222,1,Flip,LED,Mod2,Mod1,HLess,RTH,XCal,YCal
|
||||
29,1,Q2x2,Q242,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
29,2,Q2x2,Q282,1,Flip,LED,Pict,Video,HLess,RTH,XCal,YCal
|
||||
31,0,Q303,Q303,1,AltHol,Flip,Pict,Video,HLess,RTH,Gimbal
|
||||
31,1,Q303,C35,1,Arm,VTX,Pict,Video,n-a,RTH,Gimbal
|
||||
31,2,Q303,CX10D,1,Arm,Flip
|
||||
31,3,Q303,CX10WD,1,Arm,Flip
|
||||
50,0,Redpine,Fast,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
50,1,Redpine,Slow,0,sCH5,sCH6,sCH7,sCH8,sCH9,sCH10,sCH11,sCH12,sCH13,sCH14,sCH15,sCH16
|
||||
11,0,SLT,V1,0,Gear,Pitch
|
||||
11,1,SLT,V2,0,CH5,CH6,CH7,CH8
|
||||
11,2,SLT,Q100,0,Rates,n-a,CH7,CH8,Mode,Flip,n-a,n-a,Calib
|
||||
11,3,SLT,Q200,0,Rates,n-a,CH7,CH8,Mode,VidOn,VidOff,Calib
|
||||
11,4,SLT,MR100,0,Rates,n-a,CH7,CH8,Mode,Flip,Video,Pict
|
||||
10,0,Symax,Std,1,Flip,Rates,Pict,Video,HLess
|
||||
10,1,Symax,X5C,1,Flip,Rates,Pict,Video,HLess
|
||||
5,0,V2x2,Std,1,Flip,Light,Pict,Video,HLess,CalX,CalY
|
||||
5,1,V2x2,JXD506,1,Flip,Light,Pict,Video,HLess,StaSto,Emerg,Cam_UD
|
||||
61,0,Tiger,Std,1,Flip,Light
|
||||
46,0,V911s,Std,1,Calib
|
||||
46,1,E119,Std,1,Calib
|
||||
62,0,XK,X450,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
62,1,XK,X420,1,FMode,TakeOf,Emerg,3D_6G,Pict,Video
|
||||
8,0,YD717,Std,1,Flip,Light,Pict,Video,HLess
|
||||
8,1,YD717,SkyWlkr,1,Flip,Light,Pict,Video,HLess
|
||||
8,2,YD717,Simax4,1,Flip,Light,Pict,Video,HLess
|
||||
8,3,YD717,XinXun,1,Flip,Light,Pict,Video,HLess
|
||||
8,4,YD717,NiHui,1,Flip,Light,Pict,Video,HLess
|
||||
65,0,FrSkyR9,R9_915,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,1,FrSkyR9,R9_868,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
|
||||
65,2,FrSkyR9,R9_915_8CH,0,CH5,CH6,CH7,CH8
|
||||
65,3,FrSkyR9,R9_968_8CH,0,CH5,CH6,CH7,CH8
|
||||
56,0,Flysky2A_RX,RX,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14
|
||||
19,0,Shenqi,Cycle,1
|
||||
4,1,Hisky,HK310,0,Aux
|
||||
43,0,Traxxas,6519,0
|
||||
52,0,ZSX,280,1,Light
|
||||
48,0,V761,Std,1,Gyro
|
||||
49,0,KF606,Std,1,Trim
|
||||
47,0,GD00x,V1,1,Trim,LED,Rate
|
||||
47,1,GD00x,V2,1,Trim,LED,Rate
|
||||
58,0,FX816,P38,1
|
302
radio/sdcard/taranis-x9/SCRIPTS/TOOLS/MultiChannelsUpdater.lua
Normal file
|
@ -0,0 +1,302 @@
|
|||
|
||||
local toolName = "TNS|Multi chan namer|TNE"
|
||||
|
||||
---- #########################################################################
|
||||
---- # #
|
||||
---- # Copyright (C) OpenTX #
|
||||
-----# #
|
||||
---- # 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. #
|
||||
---- # #
|
||||
---- #########################################################################
|
||||
|
||||
local protocol_name = ""
|
||||
local sub_protocol_name = ""
|
||||
local bind_ch = 0
|
||||
local module_conf = {}
|
||||
local module_pos = "Internal"
|
||||
local file_ok = 0
|
||||
local done = 0
|
||||
local protocol = 0
|
||||
local sub_protocol = 0
|
||||
local f_seek = 0
|
||||
local channel_names={}
|
||||
local num_search = "Searching"
|
||||
|
||||
local function drawScreenTitle(title)
|
||||
if LCD_W == 480 then
|
||||
lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR)
|
||||
lcd.drawText(1, 5, title, MENU_TITLE_COLOR)
|
||||
else
|
||||
lcd.drawScreenTitle(title, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function bitand(a, b)
|
||||
local result = 0
|
||||
local bitval = 1
|
||||
while a > 0 and b > 0 do
|
||||
if a % 2 == 1 and b % 2 == 1 then -- test the rightmost bits
|
||||
result = result + bitval -- set the current bit
|
||||
end
|
||||
bitval = bitval * 2 -- shift left
|
||||
a = math.floor(a/2) -- shift right
|
||||
b = math.floor(b/2)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function Multi_Draw_LCD(event)
|
||||
local line = 0
|
||||
|
||||
lcd.clear()
|
||||
drawScreenTitle("Multi channels namer")
|
||||
|
||||
--Display settings
|
||||
local lcd_opt = 0
|
||||
if LCD_W == 480 then
|
||||
x_pos = 10
|
||||
y_pos = 32
|
||||
y_inc = 20
|
||||
else
|
||||
x_pos = 0
|
||||
y_pos = 9
|
||||
y_inc = 8
|
||||
lcd_opt = SMLSIZE
|
||||
end
|
||||
|
||||
--Multi Module detection
|
||||
if module_conf["Type"] ~= 6 then
|
||||
if LCD_W == 480 then
|
||||
lcd.drawText(10,50,"No Multi module configured...", BLINK)
|
||||
else
|
||||
--Draw on LCD_W=128
|
||||
lcd.drawText(2,17,"No Multi module configured...",SMLSIZE)
|
||||
end
|
||||
return
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,module_pos .. " Multi detected.", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Channel order
|
||||
if (ch_order == -1) then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels order can't be read from Multi...", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
--Can't open file MultiChan.txt
|
||||
if file_ok == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Can't read MultiChan.txt file...", lcd_opt)
|
||||
return
|
||||
end
|
||||
|
||||
if ( protocol_name == "" or sub_protocol_name == "" ) and f_seek ~=-1 then
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,num_search, lcd_opt)
|
||||
num_search = num_search .. "."
|
||||
if #num_search > 15 then
|
||||
num_search = string.sub(num_search,1,9)
|
||||
end
|
||||
local proto = 0
|
||||
local sub_proto = 0
|
||||
local proto_name = ""
|
||||
local sub_proto_name = ""
|
||||
local channels = ""
|
||||
local nbr_try = 0
|
||||
local nbr_car = 0
|
||||
repeat
|
||||
io.seek(f, f_seek)
|
||||
local data = io.read(f, 100) -- read 100 characters
|
||||
if #data ==0 then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
proto, sub_proto, proto_name, sub_proto_name, bind_ch, channels = string.match(data,'(%d+),(%d),([%w-_ ]+),([%w-_ ]+),(%d)(.+)')
|
||||
if proto ~= nil and sub_proto ~= nil and protocol_name ~= nil and sub_protocol_name ~= nil and bind_ch ~= nil then
|
||||
if tonumber(proto) == protocol and tonumber(sub_proto) == sub_protocol then
|
||||
protocol_name = proto_name
|
||||
sub_protocol_name = sub_proto_name
|
||||
bind_ch = tonumber(bind_ch)
|
||||
if channels ~= nil then
|
||||
--extract channel names
|
||||
nbr_car = string.find(channels, "\r")
|
||||
if nbr_car == nil then nbr_car = string.find(channels, "\n") end
|
||||
if nbr_car ~= nil then
|
||||
channels = string.sub(channels,1,nbr_car-1)
|
||||
end
|
||||
local i = 5
|
||||
for k in string.gmatch(channels, ",([%w-_ ]+)") do
|
||||
channel_names[i] = k
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
f_seek = -1 -- protocol found
|
||||
break
|
||||
end
|
||||
end
|
||||
if f_seek ~= -1 then
|
||||
nbr_car = string.find(data, "\n")
|
||||
if nbr_car == nil then nbr_car = string.find(data, "\r") end
|
||||
if nbr_car == nil then
|
||||
f_seek = -1 -- end of file
|
||||
break
|
||||
end
|
||||
f_seek = f_seek + nbr_car -- seek to next line
|
||||
nbr_try = nbr_try + 1
|
||||
end
|
||||
until nbr_try > 20 or f_seek == -1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
if f_seek ~= -1 then
|
||||
return -- continue searching...
|
||||
end
|
||||
|
||||
--Protocol & Sub_protocol
|
||||
if protocol_name == "" or sub_protocol_name == "" then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Unknown protocol "..tostring(protocol).."/"..tostring(sub_protocol).." ...", lcd_opt)
|
||||
return
|
||||
elseif LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name .. " / SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
else
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Protocol: " .. protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"SubProtocol: " .. sub_protocol_name, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
text1=""
|
||||
text2=""
|
||||
for i,v in ipairs(channel_names) do
|
||||
if i<=8 then
|
||||
if i==1 then
|
||||
text1 = v
|
||||
else
|
||||
text1=text1 .. "," .. v
|
||||
end
|
||||
else
|
||||
if i==9 then
|
||||
text2 = v
|
||||
else
|
||||
text2=text2 .. "," .. v
|
||||
end
|
||||
end
|
||||
end
|
||||
if LCD_W > 128 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Channels: " .. text1, lcd_opt)
|
||||
line = line + 1
|
||||
if text2 ~= "" then
|
||||
lcd.drawText(x_pos*9, y_pos+y_inc*line,text2, lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
end
|
||||
|
||||
if event ~= EVT_VIRTUAL_ENTER and done == 0 then
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"<ENT> Save", lcd_opt + INVERS + BLINK)
|
||||
return
|
||||
end
|
||||
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Setting channel names.", lcd_opt)
|
||||
line = line + 1
|
||||
local output, nbr
|
||||
if done == 0 then
|
||||
for i,v in ipairs(channel_names) do
|
||||
output = model.getOutput(i-1)
|
||||
output["name"] = v
|
||||
model.setOutput(i-1,output)
|
||||
nbr = i
|
||||
end
|
||||
for i = nbr, 15 do
|
||||
output = model.getOutput(i)
|
||||
output["name"] = "n-a"
|
||||
model.setOutput(i,output)
|
||||
end
|
||||
if bind_ch == 1 then
|
||||
output = model.getOutput(15)
|
||||
output["name"] = "BindCH"
|
||||
model.setOutput(15,output)
|
||||
end
|
||||
done = 1
|
||||
end
|
||||
lcd.drawText(x_pos, y_pos+y_inc*line,"Done!", lcd_opt)
|
||||
line = line + 1
|
||||
end
|
||||
|
||||
-- Init
|
||||
local function Multi_Init()
|
||||
module_conf = model.getModule(0)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
module_pos = "External"
|
||||
module_conf = model.getModule(1)
|
||||
if module_conf["Type"] ~= 6 then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
protocol = module_conf["protocol"]
|
||||
sub_protocol = module_conf["subProtocol"]
|
||||
|
||||
--Exceptions on first 4 channels...
|
||||
local stick_names = { "Rud", "Ele", "Thr", "Ail" }
|
||||
if ( protocol == 4 and sub_protocol ==1 ) or protocol == 19 or protocol == 52 then -- Hisky/HK310, Shenqi, ZSX
|
||||
stick_names[2] = "n-a"
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 43 then -- Traxxas
|
||||
stick_names[2] = "Aux4"
|
||||
stick_names[4] = "Aux3"
|
||||
elseif protocol == 48 then -- V761
|
||||
stick_names[4] = "n-a"
|
||||
elseif protocol == 47 or protocol == 49 or protocol == 58 then -- GD00x, KF606, FX816
|
||||
stick_names[1] = "n-a"
|
||||
stick_names[2] = "n-a"
|
||||
end
|
||||
|
||||
--Determine fist 4 channels order
|
||||
local ch_order=module_conf["channelsOrder"]
|
||||
if (ch_order == -1) then
|
||||
channel_names[1] = stick_names[defaultChannel(0)+1]
|
||||
channel_names[2] = stick_names[defaultChannel(1)+1]
|
||||
channel_names[3] = stick_names[defaultChannel(2)+1]
|
||||
channel_names[4] = stick_names[defaultChannel(3)+1]
|
||||
else
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[4]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[2]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[3]
|
||||
ch_order = math.floor(ch_order/4)
|
||||
channel_names[bitand(ch_order,3)+1] = stick_names[1]
|
||||
end
|
||||
--Check MultiChan.txt
|
||||
local f = io.open("/SCRIPTS/TOOLS/MultiChan.txt", "r")
|
||||
if f == nil then return end
|
||||
file_ok = 1
|
||||
io.close(f)
|
||||
end
|
||||
|
||||
-- Main
|
||||
local function Multi_Run(event)
|
||||
if event == nil then
|
||||
error("Cannot be run as a model script!")
|
||||
return 2
|
||||
else
|
||||
Multi_Draw_LCD(event)
|
||||
if event == EVT_VIRTUAL_EXIT then
|
||||
return 2
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
return { init=Multi_Init, run=Multi_Run }
|
|
@ -381,9 +381,12 @@ endif()
|
|||
|
||||
add_definitions(-DPOPUP_LEVEL=${POPUP_LEVEL})
|
||||
|
||||
if(BOOTLOADER)
|
||||
add_definitions(-DBOOTLOADER)
|
||||
endif(BOOTLOADER)
|
||||
if(INTERNAL_MODULE_MULTI)
|
||||
set(DEFAULT_TEMPLATE_SETUP 21 CACHE STRING "")
|
||||
else()
|
||||
set(DEFAULT_TEMPLATE_SETUP 0 CACHE STRING "")
|
||||
endif()
|
||||
add_definitions(-DDEFAULT_TEMPLATE_SETUP=${DEFAULT_TEMPLATE_SETUP})
|
||||
|
||||
set(SRC
|
||||
${SRC}
|
||||
|
@ -444,7 +447,6 @@ endif()
|
|||
|
||||
set(SRC ${SRC} ${FIRMWARE_SRC})
|
||||
|
||||
|
||||
##### firmware target #####
|
||||
|
||||
option(FIRMWARE_TARGET "Configure Firmware target (can be turned of for compiling Companion only)" ON)
|
||||
|
|
Before Width: | Height: | Size: 601 B After Width: | Height: | Size: 310 B |
BIN
radio/src/bitmaps/480x272/mask_txbat_charging.png
Executable file → Normal file
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 553 B |
|
@ -315,7 +315,7 @@ void Bluetooth::wakeup(void)
|
|||
uint8_t len = ZLEN(g_eeGeneral.bluetoothName);
|
||||
if (len > 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
*cur++ = char2lower(zchar2char(g_eeGeneral.bluetoothName[i]));
|
||||
*cur++ = char2lower(g_eeGeneral.bluetoothName[i]);
|
||||
}
|
||||
*cur = '\0';
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ void Bluetooth::wakeup()
|
|||
uint8_t len = ZLEN(g_eeGeneral.bluetoothName);
|
||||
if (len > 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
*cur++ = char2lower(zchar2char(g_eeGeneral.bluetoothName[i]));
|
||||
*cur++ = char2lower(g_eeGeneral.bluetoothName[i]);
|
||||
}
|
||||
*cur = '\0';
|
||||
}
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
#define _BUZZER_H_
|
||||
|
||||
#if defined(BUZZER)
|
||||
extern uint8_t g_beepCnt;
|
||||
extern uint8_t beepAgain;
|
||||
extern uint8_t beepAgainOrig;
|
||||
extern uint8_t beepOn;
|
||||
extern bool warble;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include "opentx.h"
|
||||
|
||||
uint8_t s_curveChan;
|
||||
int8_t * curveEnd[MAX_CURVES];
|
||||
|
||||
void loadCurves()
|
||||
|
@ -120,7 +119,7 @@ bool isCurveUsed(uint8_t index)
|
|||
}
|
||||
|
||||
#define CUSTOM_POINT_X(points, count, idx) ((idx)==0 ? -100 : (((idx)==(count)-1) ? 100 : points[(count)+(idx)-1]))
|
||||
int32_t compute_tangent(CurveHeader * crv, int8_t * points, int i)
|
||||
int32_t compute_tangent(CurveHeader * crv, const int8_t * points, int i)
|
||||
{
|
||||
int32_t m=0;
|
||||
uint8_t num_points = crv->points + 5;
|
||||
|
@ -240,7 +239,7 @@ int intpol(int x, uint8_t idx) // -100, -75, -50, -25, 0 ,25 ,50, 75, 100
|
|||
int8_t * points = curveAddress(idx);
|
||||
uint8_t count = crv.points+5;
|
||||
bool custom = (crv.type == CURVE_TYPE_CUSTOM);
|
||||
int16_t erg = 0;
|
||||
int16_t erg;
|
||||
|
||||
x += RESXu;
|
||||
|
||||
|
@ -339,11 +338,6 @@ int applyCustomCurve(int x, uint8_t idx)
|
|||
return intpol(x, idx);
|
||||
}
|
||||
|
||||
point_t getPoint(uint8_t index)
|
||||
{
|
||||
return getPoint(s_curveChan, index);
|
||||
}
|
||||
|
||||
point_t getPoint(uint8_t curveIndex, uint8_t index)
|
||||
{
|
||||
point_t result = {0, 0};
|
||||
|
@ -363,7 +357,14 @@ point_t getPoint(uint8_t curveIndex, uint8_t index)
|
|||
return result;
|
||||
}
|
||||
|
||||
#if !defined(COLORLCD)
|
||||
point_t getPoint(uint8_t index)
|
||||
{
|
||||
return getPoint(s_currIdxSubMenu, index);
|
||||
}
|
||||
|
||||
int applyCurrentCurve(int x)
|
||||
{
|
||||
return applyCustomCurve(x, s_curveChan);
|
||||
return applyCustomCurve(x, s_currIdxSubMenu);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -208,6 +208,16 @@ enum TrainerMode {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if defined(RADIO_FAMILY_T16) || (defined(RADIO_T12) && defined(INTERNAL_MODULE_MULTI)) || defined(ALLOW_TRAINER_MULTI)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_MULTI
|
||||
#elif defined(BLUETOOTH)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_SLAVE_BLUETOOTH
|
||||
#elif defined(PCBX7) || defined(PCBXLITE)
|
||||
#define TRAINER_MODE_MAX() TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
|
||||
#else
|
||||
#define TRAINER_MODE_MAX() HAS_WIRELESS_TRAINER_HARDWARE() ? TRAINER_MODE_MASTER_BATTERY_COMPARTMENT : TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
#define IS_INTERNAL_MODULE_ENABLED() (g_model.moduleData[INTERNAL_MODULE].type != MODULE_TYPE_NONE)
|
||||
#else
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "dataconstants.h"
|
||||
#include "definitions.h"
|
||||
#include "opentx_types.h"
|
||||
#include "globals.h"
|
||||
|
||||
#if defined(PCBTARANIS)
|
||||
#define N_TARANIS_FIELD(x)
|
||||
|
@ -331,10 +332,10 @@ PACK(struct TelemetrySensor {
|
|||
NOBACKUP(uint16_t persistentValue);
|
||||
} NAME(id1) FUNC(select_id1);
|
||||
union {
|
||||
PACK(struct {
|
||||
NOBACKUP(PACK(struct {
|
||||
uint8_t physID:5;
|
||||
uint8_t rxIndex:3; // 1 bit for module index, 2 bits for receiver index
|
||||
}) frskyInstance;
|
||||
}) frskyInstance);
|
||||
uint8_t instance;
|
||||
NOBACKUP(uint8_t formula);
|
||||
} NAME(id2) FUNC(select_id2);
|
||||
|
@ -513,8 +514,6 @@ PACK(struct ModuleData {
|
|||
* Model structure
|
||||
*/
|
||||
|
||||
typedef uint16_t BeepANACenter;
|
||||
|
||||
#if LEN_BITMAP_NAME > 0
|
||||
#define MODEL_HEADER_BITMAP_FIELD NOBACKUP(char bitmap[LEN_BITMAP_NAME]);
|
||||
#else
|
||||
|
@ -697,7 +696,8 @@ PACK(struct TrainerData {
|
|||
|
||||
#if defined(PCBHORUS) || defined(PCBNV14)
|
||||
#define EXTRA_GENERAL_FIELDS \
|
||||
NOBACKUP(uint8_t auxSerialMode); \
|
||||
NOBACKUP(uint8_t auxSerialMode:4); \
|
||||
NOBACKUP(uint8_t aux2SerialMode:4); \
|
||||
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
|
||||
uint16_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */ \
|
||||
uint8_t slidersConfig ARRAY(1,struct_sliderConfig,nullptr); /* 1 bit per slider */ \
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
extern volatile uint32_t g_tmr10ms;
|
||||
|
||||
uint8_t auxSerialTracesEnabled();
|
||||
uint8_t aux2SerialTracesEnabled();
|
||||
|
||||
#if defined(SIMU)
|
||||
typedef void (*traceCallbackFunc)(const char * text);
|
||||
|
|
Before Width: | Height: | Size: 155 B After Width: | Height: | Size: 143 B |
Before Width: | Height: | Size: 155 B After Width: | Height: | Size: 150 B |
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 190 B |
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 250 B |