Screenshot SF currently unsupported on Horus
[opentx.git] / companion / src / modeledit / customfunctions.cpp
blobfe5251a2cc355d9af7241f283a58ac86b6547000
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "customfunctions.h"
22 #include "helpers.h"
23 #include "appdata.h"
25 RepeatComboBox::RepeatComboBox(QWidget *parent, int & repeatParam):
26 QComboBox(parent),
27 repeatParam(repeatParam)
29 unsigned int step = IS_ARM(getCurrentBoard()) ? 1 : 10;
30 int value = repeatParam/step;
32 if (step == 1) {
33 addItem(QObject::tr("Played once, not during startup"), -1);
34 value++;
37 addItem(QObject::tr("No repeat"), 0);
39 for (unsigned int i=step; i<=60; i+=step) {
40 addItem(QObject::tr("%1s").arg(i), i);
43 setCurrentIndex(value);
45 connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onIndexChanged(int)));
48 void RepeatComboBox::onIndexChanged(int index)
50 repeatParam = itemData(index).toInt();
51 emit modified();
54 void RepeatComboBox::update()
56 unsigned int step = IS_ARM(getCurrentBoard()) ? 1 : 10;
57 int value = repeatParam/step;
58 if (step == 1) {
59 value++;
61 setCurrentIndex(value);
64 CustomFunctionsPanel::CustomFunctionsPanel(QWidget * parent, ModelData * model, GeneralSettings & generalSettings, Firmware * firmware):
65 GenericPanel(parent, model, generalSettings, firmware),
66 functions(model ? model->customFn : generalSettings.customFn),
67 mediaPlayerCurrent(-1),
68 mediaPlayer(NULL)
70 Stopwatch s1("CustomFunctionsPanel - populate");
71 lock = true;
72 int num_fsw = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
74 if (!firmware->getCapability(VoicesAsNumbers)) {
75 tracksSet = getFilesSet(getSoundsPath(generalSettings), QStringList() << "*.wav" << "*.WAV", firmware->getCapability(VoicesMaxLength));
76 for (int i=0; i<num_fsw; i++) {
77 if (functions[i].func==FuncPlayPrompt || functions[i].func==FuncBackgroundMusic) {
78 QString temp = functions[i].paramarm;
79 if (!temp.isEmpty()) {
80 tracksSet.insert(temp);
86 s1.report("get tracks");
88 if (IS_STM32(firmware->getBoard())) {
89 scriptsSet = getFilesSet(g.profile[g.id()].sdPath() + "/SCRIPTS/FUNCTIONS", QStringList() << "*.lua", firmware->getCapability(VoicesMaxLength));
90 for (int i=0; i<num_fsw; i++) {
91 if (functions[i].func==FuncPlayScript) {
92 QString temp = functions[i].paramarm;
93 if (!temp.isEmpty()) {
94 scriptsSet.insert(temp);
99 s1.report("get scripts");
101 CompanionIcon playIcon("play.png");
103 QStringList headerLabels;
104 headerLabels << "#" << tr("Switch") << tr("Action") << tr("Parameters") << tr("Enable");
105 TableLayout * tableLayout = new TableLayout(this, num_fsw, headerLabels);
107 for (int i=0; i<num_fsw; i++) {
108 // The label
109 QLabel * label = new QLabel(this);
110 label->setContextMenuPolicy(Qt::CustomContextMenu);
111 label->setMouseTracking(true);
112 label->setProperty("index", i);
113 if (model)
114 label->setText(tr("SF%1").arg(i+1));
115 else
116 label->setText(tr("GF%1").arg(i+1));
117 label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
118 connect(label, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(fsw_customContextMenuRequested(QPoint)));
119 tableLayout->addWidget(i, 0, label);
120 // s1.report("label");
122 // The switch
123 fswtchSwtch[i] = new QComboBox(this);
124 fswtchSwtch[i]->setProperty("index", i);
125 populateSwitchCB(fswtchSwtch[i], functions[i].swtch, generalSettings, model ? SpecialFunctionsContext : GlobalFunctionsContext);
126 fswtchSwtch[i]->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
127 fswtchSwtch[i]->setMaxVisibleItems(10);
128 connect(fswtchSwtch[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
129 tableLayout->addWidget(i, 1, fswtchSwtch[i]);
130 // s1.report("switch");
132 // The function
133 fswtchFunc[i] = new QComboBox(this);
134 fswtchFunc[i]->setProperty("index", i);
135 populateFuncCB(fswtchFunc[i], functions[i].func);
136 connect(fswtchFunc[i], SIGNAL(currentIndexChanged(int)), this, SLOT(functionEdited()));
137 tableLayout->addWidget(i, 2, fswtchFunc[i]);
138 // s1.report("func");
140 // The parameters
141 QHBoxLayout * paramLayout = new QHBoxLayout();
142 tableLayout->addLayout(i, 3, paramLayout);
144 fswtchGVmode[i] = new QComboBox(this);
145 fswtchGVmode[i]->setProperty("index", i);
146 populateGVmodeCB(fswtchGVmode[i], functions[i].adjustMode);
147 fswtchGVmode[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
148 connect(fswtchGVmode[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
149 paramLayout->addWidget(fswtchGVmode[i]);
151 fswtchParamGV[i] = new QCheckBox(this);
152 fswtchParamGV[i]->setProperty("index", i);
153 fswtchParamGV[i]->setText("GV");
154 fswtchParamGV[i]->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
155 connect(fswtchParamGV[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited()));
156 paramLayout->addWidget(fswtchParamGV[i]);
158 fswtchParam[i] = new QDoubleSpinBox(this);
159 fswtchParam[i]->setProperty("index", i);
160 fswtchParam[i]->setAccelerated(true);
161 fswtchParam[i]->setDecimals(0);
162 connect(fswtchParam[i], SIGNAL(editingFinished()), this, SLOT(customFunctionEdited()));
163 paramLayout->addWidget(fswtchParam[i]);
165 fswtchParamTime[i] = new QTimeEdit(this);
166 fswtchParamTime[i]->setProperty("index", i);
167 fswtchParamTime[i]->setAccelerated(true);
168 fswtchParamTime[i]->setDisplayFormat("hh:mm:ss");
169 connect(fswtchParamTime[i], SIGNAL(editingFinished()), this, SLOT(customFunctionEdited()));
170 paramLayout->addWidget(fswtchParamTime[i]);
172 fswtchParamT[i] = new QComboBox(this);
173 fswtchParamT[i]->setProperty("index", i);
174 populateFuncParamCB(fswtchParamT[i], functions[i].func, functions[i].param, functions[i].adjustMode);
175 paramLayout->addWidget(fswtchParamT[i]);
176 fswtchParamT[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
177 connect(fswtchParamT[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
179 fswtchParamArmT[i] = new QComboBox(this);
180 fswtchParamArmT[i]->setProperty("index", i);
181 fswtchParamArmT[i]->setEditable(true);
182 fswtchParamArmT[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
183 paramLayout->addWidget(fswtchParamArmT[i]);
185 connect(fswtchParamArmT[i], SIGNAL(currentIndexChanged(int)), this, SLOT(customFunctionEdited()));
186 connect(fswtchParamArmT[i], SIGNAL(editTextChanged ( const QString)), this, SLOT(customFunctionEdited()));
188 fswtchBLcolor[i] = new QSlider(this);
189 fswtchBLcolor[i]->setProperty("index", i);
190 fswtchBLcolor[i]->setMinimum(0);
191 fswtchBLcolor[i]->setMaximum(100);
192 fswtchBLcolor[i]->setSingleStep(1);
193 fswtchBLcolor[i]->setOrientation(Qt::Horizontal);
194 paramLayout->addWidget(fswtchBLcolor[i]);
195 connect(fswtchBLcolor[i], SIGNAL(sliderReleased()), this, SLOT(customFunctionEdited()));
197 playBT[i] = new QPushButton(this);
198 playBT[i]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
199 playBT[i]->setProperty("index", i);
200 playBT[i]->setIcon(playIcon);
201 paramLayout->addWidget(playBT[i]);
202 connect(playBT[i], SIGNAL(pressed()), this, SLOT(playMusic()));
204 QHBoxLayout * repeatLayout = new QHBoxLayout();
205 tableLayout->addLayout(i, 4, repeatLayout);
206 fswtchRepeat[i] = new RepeatComboBox(this, functions[i].repeatParam);
207 repeatLayout->addWidget(fswtchRepeat[i], i+1);
208 connect(fswtchRepeat[i], SIGNAL(modified()), this, SLOT(onChildModified()));
210 fswtchEnable[i] = new QCheckBox(this);
211 fswtchEnable[i]->setProperty("index", i);
212 fswtchEnable[i]->setText(tr("ON"));
213 fswtchEnable[i]->setFixedWidth(200);
214 repeatLayout->addWidget(fswtchEnable[i], i+1);
215 connect(fswtchEnable[i], SIGNAL(stateChanged(int)), this, SLOT(customFunctionEdited()));
217 s1.report("add items");
219 disableMouseScrolling();
220 s1.report("disableMouseScrolling");
222 lock = false;
224 update();
225 s1.report("update");
226 tableLayout->resizeColumnsToContents();
227 s1.report("resizeColumnsToContents");
228 tableLayout->setColumnWidth(3, 300);
229 tableLayout->pushRowsUp(num_fsw+1);
230 s1.report("end");
233 CustomFunctionsPanel::~CustomFunctionsPanel()
237 void CustomFunctionsPanel::onMediaPlayerStateChanged(QMediaPlayer::State state)
239 if (!lock) {
240 lock = true;
241 if (state==QMediaPlayer::StoppedState || state==QMediaPlayer::PausedState) {
242 mediaPlayer->stop();
243 if (mediaPlayerCurrent >= 0) {
244 playBT[mediaPlayerCurrent]->setIcon(CompanionIcon("play.png"));
245 mediaPlayerCurrent = -1;
248 lock = false;
252 void CustomFunctionsPanel::onMediaPlayerError(QMediaPlayer::Error error)
254 if (!lock) {
255 lock = true;
256 if (mediaPlayerCurrent >= 0) {
257 playBT[mediaPlayerCurrent]->setIcon(CompanionIcon("play.png"));
258 mediaPlayerCurrent = -1;
260 lock = false;
264 void CustomFunctionsPanel::playMusic()
266 if (!mediaPlayer) {
267 mediaPlayer = new QMediaPlayer(this);
268 connect(mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(onMediaPlayerStateChanged(QMediaPlayer::State)));
269 connect(mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(onMediaPlayerError(QMediaPlayer::Error)));
272 int index = sender()->property("index").toInt();
273 QString path = g.profile[g.id()].sdPath();
274 QDir qd(path);
275 QString track;
276 if (qd.exists()) {
277 if (firmware->getCapability(VoicesAsNumbers)) {
278 track = path + QString("/%1.wav").arg(int(fswtchParam[index]->value()), 4, 10, (const QChar)'0');
280 else {
281 path.append("/SOUNDS/");
282 QString lang = generalSettings.ttsLanguage;
283 if (lang.isEmpty())
284 lang = "en";
285 path.append(lang);
286 if (fswtchParamArmT[index]->currentText() != "----") {
287 track = path + "/" + fswtchParamArmT[index]->currentText() + ".wav";
290 QFile file(track);
291 if (!file.exists()) {
292 QMessageBox::critical(this, tr("Error"), tr("Unable to find sound file %1!").arg(track));
293 return;
296 if (mediaPlayerCurrent == index) {
297 mediaPlayer->stop();
298 playBT[index]->setIcon(CompanionIcon("play.png"));
299 mediaPlayerCurrent = -1;
301 else {
302 if (mediaPlayerCurrent >= 0) {
303 playBT[mediaPlayerCurrent]->setIcon(CompanionIcon("play.png"));
305 mediaPlayerCurrent = index;
306 mediaPlayer->setMedia(QUrl::fromLocalFile(track));
307 mediaPlayer->play();
308 playBT[index]->setIcon(CompanionIcon("stop.png"));
313 #define CUSTOM_FUNCTION_NUMERIC_PARAM (1<<0)
314 #define CUSTOM_FUNCTION_SOURCE_PARAM (1<<1)
315 #define CUSTOM_FUNCTION_FILE_PARAM (1<<2)
316 #define CUSTOM_FUNCTION_TIME_PARAM (1<<3)
317 #define CUSTOM_FUNCTION_GV_MODE (1<<4)
318 #define CUSTOM_FUNCTION_GV_TOOGLE (1<<5)
319 #define CUSTOM_FUNCTION_ENABLE (1<<6)
320 #define CUSTOM_FUNCTION_REPEAT (1<<7)
321 #define CUSTOM_FUNCTION_PLAY (1<<8)
322 #define CUSTOM_FUNCTION_BL_COLOR (1<<9)
324 void CustomFunctionsPanel::customFunctionEdited()
326 if (!lock) {
327 lock = true;
328 int index = sender()->property("index").toInt();
329 refreshCustomFunction(index, true);
330 emit modified();
331 lock = false;
335 void CustomFunctionsPanel::functionEdited()
337 if (!lock) {
338 lock = true;
339 int index = sender()->property("index").toInt();
340 RawSwitch swtch = functions[index].swtch;
341 functions[index].clear();
342 functions[index].swtch = swtch;
343 functions[index].func = (AssignFunc)fswtchFunc[index]->itemData(fswtchFunc[index]->currentIndex()).toInt();
344 refreshCustomFunction(index);
345 emit modified();
346 lock = false;
350 void CustomFunctionsPanel::onChildModified()
352 emit modified();
355 void CustomFunctionsPanel::refreshCustomFunction(int i, bool modified)
357 CustomFunctionData & cfn = functions[i];
358 AssignFunc func = (AssignFunc)fswtchFunc[i]->itemData(fswtchFunc[i]->currentIndex()).toInt();
360 unsigned int widgetsMask = 0;
361 if (modified) {
362 cfn.swtch = RawSwitch(fswtchSwtch[i]->itemData(fswtchSwtch[i]->currentIndex()).toInt());
363 cfn.func = func;
364 cfn.enabled = fswtchEnable[i]->isChecked();
365 cfn.adjustMode = (AssignFunc)fswtchGVmode[i]->currentIndex();
368 if (func>=FuncOverrideCH1 && func<=FuncOverrideCH32) {
369 if (model) {
370 int channelsMax = model->getChannelsMax(true);
371 fswtchParam[i]->setDecimals(0);
372 fswtchParam[i]->setSingleStep(1);
373 fswtchParam[i]->setMinimum(-channelsMax);
374 fswtchParam[i]->setMaximum(channelsMax);
375 if (modified) {
376 cfn.param = fswtchParam[i]->value();
378 fswtchParam[i]->setValue(cfn.param);
379 widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM + CUSTOM_FUNCTION_ENABLE;
382 else if (func==FuncLogs) {
383 fswtchParam[i]->setDecimals(1);
384 fswtchParam[i]->setMinimum(0);
385 fswtchParam[i]->setMaximum(25.5);
386 fswtchParam[i]->setSingleStep(0.1);
387 if (modified) cfn.param = fswtchParam[i]->value()*10.0;
388 fswtchParam[i]->setValue(cfn.param/10.0);
389 widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
391 else if (func>=FuncAdjustGV1 && func<=FuncAdjustGVLast) {
392 if (modified) cfn.adjustMode = fswtchGVmode[i]->currentIndex();
393 widgetsMask |= CUSTOM_FUNCTION_GV_MODE | CUSTOM_FUNCTION_ENABLE;
394 if (cfn.adjustMode==FUNC_ADJUST_GVAR_CONSTANT || cfn.adjustMode==FUNC_ADJUST_GVAR_INCDEC) {
395 if (modified) cfn.param = fswtchParam[i]->value();
396 fswtchParam[i]->setDecimals(0);
397 fswtchParam[i]->setSingleStep(1);
398 if (IS_ARM(getCurrentBoard())) {
399 fswtchParam[i]->setMinimum(-500);
400 fswtchParam[i]->setMaximum(500);
402 else {
403 fswtchParam[i]->setMinimum(-125);
404 fswtchParam[i]->setMaximum(125);
406 fswtchParam[i]->setValue(cfn.param);
407 widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM;
409 else {
410 if (modified) cfn.param = fswtchParamT[i]->itemData(fswtchParamT[i]->currentIndex()).toInt();
411 populateFuncParamCB(fswtchParamT[i], func, cfn.param, cfn.adjustMode);
412 widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
415 else if (func==FuncReset) {
416 if (modified) cfn.param = fswtchParamT[i]->itemData(fswtchParamT[i]->currentIndex()).toInt();
417 populateFuncParamCB(fswtchParamT[i], func, cfn.param);
418 widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM | CUSTOM_FUNCTION_ENABLE;
420 else if (func>=FuncSetTimer1 && func<=FuncSetTimer3) {
421 if (modified) cfn.param = QTimeS(fswtchParamTime[i]->time()).seconds();
422 fswtchParamTime[i]->setMinimumTime(QTime(0, 0, 0));
423 fswtchParamTime[i]->setMaximumTime(firmware->getMaxTimerStart());
424 fswtchParamTime[i]->setTime(QTimeS(cfn.param));
425 widgetsMask |= CUSTOM_FUNCTION_TIME_PARAM + CUSTOM_FUNCTION_ENABLE;
427 else if (func>=FuncSetFailsafeInternalModule && func<=FuncBindExternalModule) {
428 widgetsMask |= CUSTOM_FUNCTION_ENABLE;
430 else if (func==FuncVolume) {
431 if (modified) cfn.param = fswtchParamT[i]->itemData(fswtchParamT[i]->currentIndex()).toInt();
432 populateFuncParamCB(fswtchParamT[i], func, cfn.param);
433 widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM + CUSTOM_FUNCTION_ENABLE;
435 else if (func==FuncPlaySound || func==FuncPlayHaptic || func==FuncPlayValue || func==FuncPlayPrompt || func==FuncPlayBoth || func==FuncBackgroundMusic) {
436 if (func != FuncBackgroundMusic) {
437 widgetsMask |= CUSTOM_FUNCTION_REPEAT;
438 fswtchRepeat[i]->update();
440 if (func==FuncPlayValue) {
441 if (modified) cfn.param = fswtchParamT[i]->itemData(fswtchParamT[i]->currentIndex()).toInt();
442 populateFuncParamCB(fswtchParamT[i], func, cfn.param);
443 widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM + CUSTOM_FUNCTION_REPEAT;
445 else if (func==FuncPlayPrompt || func==FuncPlayBoth) {
446 if (firmware->getCapability(VoicesAsNumbers)) {
447 fswtchParam[i]->setDecimals(0);
448 fswtchParam[i]->setSingleStep(1);
449 fswtchParam[i]->setMinimum(0);
450 if (func==FuncPlayPrompt) {
451 widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM + CUSTOM_FUNCTION_REPEAT + CUSTOM_FUNCTION_GV_TOOGLE;
453 else {
454 widgetsMask |= CUSTOM_FUNCTION_NUMERIC_PARAM + CUSTOM_FUNCTION_REPEAT;
455 fswtchParamGV[i]->setChecked(false);
457 fswtchParam[i]->setMaximum(func==FuncPlayBoth ? 254 : 255);
458 if (modified) {
459 if (fswtchParamGV[i]->isChecked()) {
460 fswtchParam[i]->setMinimum(1);
461 cfn.param = std::min(fswtchParam[i]->value(),5.0)+(fswtchParamGV[i]->isChecked() ? 250 : 0);
463 else {
464 cfn.param = fswtchParam[i]->value();
467 if (cfn.param>250 && (func!=FuncPlayBoth)) {
468 fswtchParamGV[i]->setChecked(true);
469 fswtchParam[i]->setValue(cfn.param-250);
470 fswtchParam[i]->setMaximum(5);
472 else {
473 fswtchParamGV[i]->setChecked(false);
474 fswtchParam[i]->setValue(cfn.param);
476 if (cfn.param < 251)
477 widgetsMask |= CUSTOM_FUNCTION_PLAY;
479 else {
480 widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
481 if (modified) {
482 getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
484 populateFileComboBox(fswtchParamArmT[i], tracksSet, cfn.paramarm);
485 if (fswtchParamArmT[i]->currentText() != "----") {
486 widgetsMask |= CUSTOM_FUNCTION_PLAY;
490 else if (func==FuncBackgroundMusic) {
491 widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
492 if (modified) {
493 getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, firmware->getCapability(VoicesMaxLength));
495 populateFileComboBox(fswtchParamArmT[i], tracksSet, cfn.paramarm);
496 if (fswtchParamArmT[i]->currentText() != "----") {
497 widgetsMask |= CUSTOM_FUNCTION_PLAY;
500 else if (func==FuncPlaySound) {
501 if (modified) cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
502 populateFuncParamCB(fswtchParamT[i], func, cfn.param);
503 widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
505 else if (func==FuncPlayHaptic) {
506 if (modified) cfn.param = (uint8_t)fswtchParamT[i]->currentIndex();
507 populateFuncParamCB(fswtchParamT[i], func, cfn.param);
508 widgetsMask |= CUSTOM_FUNCTION_SOURCE_PARAM;
511 else if (func==FuncPlayScript) {
512 widgetsMask |= CUSTOM_FUNCTION_FILE_PARAM;
513 if (modified) {
514 getFileComboBoxValue(fswtchParamArmT[i], cfn.paramarm, 8);
516 populateFileComboBox(fswtchParamArmT[i], scriptsSet, cfn.paramarm);
518 else if (func==FuncBacklight && IS_TARANIS_PLUS(getCurrentBoard())) {
519 if (modified) cfn.param = (uint8_t)fswtchBLcolor[i]->value();
520 fswtchBLcolor[i]->setValue(cfn.param);
521 widgetsMask |= CUSTOM_FUNCTION_BL_COLOR;
523 else {
524 if (modified) cfn.param = fswtchParam[i]->value();
525 fswtchParam[i]->setDecimals(0);
526 fswtchParam[i]->setSingleStep(1);
527 fswtchParam[i]->setValue(cfn.param);
528 if (func <= FuncInstantTrim) {
529 widgetsMask |= CUSTOM_FUNCTION_ENABLE;
533 fswtchParam[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_NUMERIC_PARAM);
534 fswtchParamTime[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_TIME_PARAM);
535 fswtchParamGV[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_TOOGLE);
536 fswtchParamT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_SOURCE_PARAM);
537 fswtchParamArmT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_FILE_PARAM);
538 fswtchEnable[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_ENABLE);
539 if (widgetsMask & CUSTOM_FUNCTION_ENABLE)
540 fswtchEnable[i]->setChecked(cfn.enabled);
541 else
542 fswtchEnable[i]->setChecked(false);
543 fswtchRepeat[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_REPEAT);
544 fswtchGVmode[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_GV_MODE);
545 fswtchBLcolor[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_BL_COLOR);
546 playBT[i]->setVisible(widgetsMask & CUSTOM_FUNCTION_PLAY);
549 void CustomFunctionsPanel::update()
551 lock = true;
552 int num_fsw = model ? firmware->getCapability(CustomFunctions) : firmware->getCapability(GlobalFunctions);
553 for (int i=0; i<num_fsw; i++) {
554 refreshCustomFunction(i);
556 lock = false;
559 void CustomFunctionsPanel::fswPaste()
561 const QClipboard *clipboard = QApplication::clipboard();
562 const QMimeData *mimeData = clipboard->mimeData();
563 if (mimeData->hasFormat("application/x-companion-fsw")) {
564 QByteArray fswData = mimeData->data("application/x-companion-fsw");
565 CustomFunctionData *fsw = &functions[selectedFunction];
566 memcpy(fsw, fswData.constData(), sizeof(CustomFunctionData));
567 lock = true;
568 populateSwitchCB(fswtchSwtch[selectedFunction], functions[selectedFunction].swtch, generalSettings, model ? SpecialFunctionsContext : GlobalFunctionsContext);
569 populateFuncCB(fswtchFunc[selectedFunction], functions[selectedFunction].func);
570 populateGVmodeCB(fswtchGVmode[selectedFunction], functions[selectedFunction].adjustMode);
571 populateFuncParamCB(fswtchParamT[selectedFunction], functions[selectedFunction].func, functions[selectedFunction].param, functions[selectedFunction].adjustMode);
572 refreshCustomFunction(selectedFunction);
573 lock = false;
574 emit modified();
578 void CustomFunctionsPanel::fswDelete()
580 functions[selectedFunction].clear();
581 // TODO update switch and func
582 lock = true;
583 populateSwitchCB(fswtchSwtch[selectedFunction], functions[selectedFunction].swtch, generalSettings, model ? SpecialFunctionsContext : GlobalFunctionsContext);
584 populateFuncCB(fswtchFunc[selectedFunction], functions[selectedFunction].func);
585 refreshCustomFunction(selectedFunction);
586 lock = false;
587 emit modified();
590 void CustomFunctionsPanel::fswCopy()
592 QByteArray fswData;
593 fswData.append((char*)&functions[selectedFunction], sizeof(CustomFunctionData));
594 QMimeData *mimeData = new QMimeData;
595 mimeData->setData("application/x-companion-fsw", fswData);
596 QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
599 void CustomFunctionsPanel::fswCut()
601 fswCopy();
602 fswDelete();
605 void CustomFunctionsPanel::fsw_customContextMenuRequested(QPoint pos)
607 QLabel *label = (QLabel *)sender();
608 selectedFunction = label->property("index").toInt();
610 QPoint globalPos = label->mapToGlobal(pos);
612 const QClipboard *clipboard = QApplication::clipboard();
613 const QMimeData *mimeData = clipboard->mimeData();
614 bool hasData = mimeData->hasFormat("application/x-companion-fsw");
616 QMenu contextMenu;
617 contextMenu.addAction(CompanionIcon("copy.png"), tr("&Copy"),this,SLOT(fswCopy()),tr("Ctrl+C"));
618 contextMenu.addAction(CompanionIcon("cut.png"), tr("&Cut"),this,SLOT(fswCut()),tr("Ctrl+X"));
619 contextMenu.addAction(CompanionIcon("paste.png"), tr("&Paste"),this,SLOT(fswPaste()),tr("Ctrl+V"))->setEnabled(hasData);
620 contextMenu.addAction(CompanionIcon("clear.png"), tr("&Delete"),this,SLOT(fswDelete()),tr("Delete"));
622 contextMenu.exec(globalPos);
625 void CustomFunctionsPanel::populateFuncCB(QComboBox *b, unsigned int value)
627 b->clear();
628 for (unsigned int i=0; i<FuncCount; i++) {
629 if (((i>=FuncOverrideCH1 && i<=FuncOverrideCH32) && (!model || !firmware->getCapability(SafetyChannelCustomFunction))) ||
630 ((i==FuncVolume || i==FuncBackgroundMusic || i==FuncBackgroundMusicPause) && !firmware->getCapability(HasVolume)) ||
631 ((i==FuncPlayScript && !IS_HORUS_OR_TARANIS(firmware->getBoard()))) ||
632 ((i==FuncPlayHaptic) && !firmware->getCapability(Haptic)) ||
633 ((i==FuncPlayBoth) && !firmware->getCapability(HasBeeper)) ||
634 ((i==FuncLogs) && !firmware->getCapability(HasSDLogs)) ||
635 ((i==FuncSetTimer3) && firmware->getCapability(Timers) < 3) ||
636 ((i==FuncScreenshot) && IS_HORUS(firmware->getBoard())) ||
637 ((i>=FuncRangeCheckInternalModule && i<=FuncBindExternalModule) && (!model || !firmware->getCapability(DangerousFunctions))) ||
638 ((i>=FuncAdjustGV1 && i<=FuncAdjustGVLast) && !firmware->getCapability(Gvars))
640 // skipped
641 // b->addItem(CustomFunctionData(AssignFunc(i)).funcToString(), i);
642 // QModelIndex index = b->model()->index(i, 0);
643 // QVariant v(0);
644 // b->model()->setData(index, v, Qt::UserRole - 1);
646 else {
647 b->addItem(CustomFunctionData(AssignFunc(i)).funcToString(), i);
648 if (i == value) {
649 b->setCurrentIndex(b->count()-1);
655 void CustomFunctionsPanel::populateGVmodeCB(QComboBox *b, unsigned int value)
657 b->clear();
658 b->addItem(QObject::tr("Value"));
659 b->addItem(QObject::tr("Source"));
660 b->addItem(QObject::tr("GVAR"));
661 b->addItem(QObject::tr("Increment"));
662 b->setCurrentIndex(value);
665 void CustomFunctionsPanel::populateFuncParamCB(QComboBox *b, uint function, unsigned int value, unsigned int adjustmode)
667 QStringList qs;
668 b->clear();
669 if (function==FuncPlaySound) {
670 CustomFunctionData::populatePlaySoundParams(qs);
671 b->addItems(qs);
672 b->setCurrentIndex(value);
674 else if (function==FuncPlayHaptic) {
675 CustomFunctionData::populateHapticParams(qs);
676 b->addItems(qs);
677 b->setCurrentIndex(value);
679 else if (function==FuncReset) {
680 CustomFunctionData::populateResetParams(model, b, value);
682 else if (function==FuncVolume) {
683 populateSourceCB(b, RawSource(value), generalSettings, model, POPULATE_NONE|POPULATE_SOURCES|POPULATE_VIRTUAL_INPUTS|POPULATE_TRIMS|POPULATE_SWITCHES);
685 else if (function==FuncPlayValue) {
686 populateSourceCB(b, RawSource(value), generalSettings, model, POPULATE_NONE|POPULATE_SOURCES|POPULATE_VIRTUAL_INPUTS|POPULATE_SWITCHES|POPULATE_GVARS|POPULATE_TRIMS|POPULATE_TELEMETRY|POPULATE_TELEMETRYEXT|POPULATE_SCRIPT_OUTPUTS);
688 else if (function>=FuncAdjustGV1 && function<=FuncAdjustGVLast) {
689 switch (adjustmode) {
690 case 1:
691 populateSourceCB(b, RawSource(value), generalSettings, model, POPULATE_NONE|POPULATE_SOURCES|POPULATE_VIRTUAL_INPUTS|POPULATE_TRIMS|POPULATE_SWITCHES);
692 break;
693 case 2:
694 populateSourceCB(b, RawSource(value), generalSettings, model, POPULATE_GVARS);
695 break;
698 else {
699 b->hide();