1 // samplv1widget_config.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2012-2020, rncbc aka Rui Nuno Capela. All rights reserved.
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 *****************************************************************************/
21
22 #include "samplv1widget_config.h"
23 #include "samplv1widget_param.h"
24
25 #include "samplv1widget_palette.h"
26
27 #include "samplv1_ui.h"
28
29 #include "samplv1_pshifter.h"
30
31 #include "samplv1_controls.h"
32 #include "samplv1_programs.h"
33
34 #include "ui_samplv1widget_config.h"
35
36 #include <QPushButton>
37 #include <QComboBox>
38
39 #include <QMessageBox>
40 #include <QFileDialog>
41 #include <QFileInfo>
42 #include <QUrl>
43
44 #include <QMenu>
45
46 #include <QStyleFactory>
47
48
49 // Default (empty/blank) name.
50 static const char *g_pszDefName = QT_TRANSLATE_NOOP("samplv1widget_config", "(default)");
51
52
53 //----------------------------------------------------------------------------
54 // samplv1widget_config -- UI wrapper form.
55
56 // ctor.
samplv1widget_config(samplv1_ui * pSamplUi,QWidget * pParent)57 samplv1widget_config::samplv1widget_config (
58 samplv1_ui *pSamplUi, QWidget *pParent )
59 : QDialog(pParent), p_ui(new Ui::samplv1widget_config), m_ui(*p_ui),
60 m_pSamplUi(pSamplUi)
61 {
62 // Setup UI struct...
63 m_ui.setupUi(this);
64
65 // Pitch-shift types.
66 m_ui.PitchShiftTypeComboBox->addItem(tr("(default)"));
67 m_ui.PitchShiftTypeComboBox->addItem(tr("S.M.Bernsee"));
68 #ifdef CONFIG_LIBRUBBERBAND
69 m_ui.PitchShiftTypeComboBox->addItem(tr("RubberBand"));
70 #endif
71
72 // Note names.
73 QStringList notes;
74 for (int note = 0; note < 128; ++note)
75 notes << samplv1_ui::noteName(note);
76 m_ui.TuningRefNoteComboBox->insertItems(0, notes);
77
78 // Tuning specifics setup...
79 m_ui.TuningTabBar->addTab(tr("&Global"));
80 m_ui.TuningTabBar->addTab(tr("&Instance"));
81
82 // Dialog dirty flags.
83 m_iDirtyTuning = 0;
84 m_iDirtyControls = 0;
85 m_iDirtyPrograms = 0;
86 m_iDirtyOptions = 0;
87
88 // Setup options...
89 samplv1_config *pConfig = samplv1_config::getInstance();
90 if (pConfig && m_pSamplUi) {
91 const bool bPlugin = m_pSamplUi->isPlugin();
92 m_ui.ProgramsPreviewCheckBox->setChecked(pConfig->bProgramsPreview);
93 m_ui.UseNativeDialogsCheckBox->setChecked(pConfig->bUseNativeDialogs);
94 m_ui.KnobDialModeComboBox->setCurrentIndex(pConfig->iKnobDialMode);
95 m_ui.KnobEditModeComboBox->setCurrentIndex(pConfig->iKnobEditMode);
96 m_ui.FrameTimeFormatComboBox->setCurrentIndex(pConfig->iFrameTimeFormat);
97 m_ui.RandomizePercentSpinBox->setValue(pConfig->fRandomizePercent);
98 m_ui.PitchShiftTypeComboBox->setCurrentIndex(pConfig->iPitchShiftType);
99 // Custom display options (only for no-plugin forms)...
100 resetCustomColorThemes(pConfig->sCustomColorTheme);
101 resetCustomStyleThemes(pConfig->sCustomStyleTheme);
102 // Load controllers database...
103 samplv1_controls *pControls = m_pSamplUi->controls();
104 if (pControls) {
105 m_ui.ControlsTreeWidget->loadControls(pControls);
106 m_ui.ControlsEnabledCheckBox->setEnabled(bPlugin);
107 m_ui.ControlsEnabledCheckBox->setChecked(pControls->enabled());
108 }
109 // Load programs database...
110 samplv1_programs *pPrograms = m_pSamplUi->programs();
111 if (pPrograms) {
112 m_ui.ProgramsTreeWidget->loadPrograms(pPrograms);
113 m_ui.ProgramsEnabledCheckBox->setEnabled(bPlugin);
114 m_ui.ProgramsPreviewCheckBox->setEnabled(!bPlugin);
115 m_ui.ProgramsEnabledCheckBox->setChecked(pPrograms->enabled());
116 }
117 // Initialize conveniency options...
118 loadComboBoxHistory(m_ui.TuningScaleFileComboBox);
119 loadComboBoxHistory(m_ui.TuningKeyMapFileComboBox);
120 // Micro-tonal tuning settings...
121 const int iTuningTab = (m_pSamplUi->isTuningEnabled() ? 1 : 0);
122 m_ui.TuningTabBar->setCurrentIndex(iTuningTab);
123 tuningTabChanged(iTuningTab);
124 }
125
126 // Signal/slots connections...
127 QObject::connect(m_ui.ControlsAddItemToolButton,
128 SIGNAL(clicked()),
129 SLOT(controlsAddItem()));
130 QObject::connect(m_ui.ControlsEditToolButton,
131 SIGNAL(clicked()),
132 SLOT(controlsEditItem()));
133 QObject::connect(m_ui.ControlsDeleteToolButton,
134 SIGNAL(clicked()),
135 SLOT(controlsDeleteItem()));
136
137 QObject::connect(m_ui.ControlsTreeWidget,
138 SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
139 SLOT(controlsCurrentChanged()));
140 QObject::connect(m_ui.ControlsTreeWidget,
141 SIGNAL(itemChanged(QTreeWidgetItem *, int)),
142 SLOT(controlsChanged()));
143
144 QObject::connect(m_ui.ControlsEnabledCheckBox,
145 SIGNAL(toggled(bool)),
146 SLOT(controlsEnabled(bool)));
147
148 QObject::connect(m_ui.ProgramsAddBankToolButton,
149 SIGNAL(clicked()),
150 SLOT(programsAddBankItem()));
151 QObject::connect(m_ui.ProgramsAddItemToolButton,
152 SIGNAL(clicked()),
153 SLOT(programsAddItem()));
154 QObject::connect(m_ui.ProgramsEditToolButton,
155 SIGNAL(clicked()),
156 SLOT(programsEditItem()));
157 QObject::connect(m_ui.ProgramsDeleteToolButton,
158 SIGNAL(clicked()),
159 SLOT(programsDeleteItem()));
160
161 QObject::connect(m_ui.ProgramsTreeWidget,
162 SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
163 SLOT(programsCurrentChanged()));
164 QObject::connect(m_ui.ProgramsTreeWidget,
165 SIGNAL(itemChanged(QTreeWidgetItem *, int)),
166 SLOT(programsChanged()));
167 QObject::connect(m_ui.ProgramsTreeWidget,
168 SIGNAL(itemActivated(QTreeWidgetItem *, int)),
169 SLOT(programsActivated()));
170
171 QObject::connect(m_ui.ProgramsEnabledCheckBox,
172 SIGNAL(toggled(bool)),
173 SLOT(programsEnabled(bool)));
174
175 // Custom context menu...
176 m_ui.ControlsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
177 m_ui.ProgramsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
178
179 QObject::connect(m_ui.ControlsTreeWidget,
180 SIGNAL(customContextMenuRequested(const QPoint&)),
181 SLOT(controlsContextMenuRequested(const QPoint&)));
182 QObject::connect(m_ui.ProgramsTreeWidget,
183 SIGNAL(customContextMenuRequested(const QPoint&)),
184 SLOT(programsContextMenuRequested(const QPoint&)));
185
186 // Tuning slots...
187 QObject::connect(m_ui.TuningTabBar,
188 SIGNAL(currentChanged(int)),
189 SLOT(tuningTabChanged(int)));
190 QObject::connect(m_ui.TuningEnabledCheckBox,
191 SIGNAL(toggled(bool)),
192 SLOT(tuningChanged()));
193 QObject::connect(m_ui.TuningRefNoteComboBox,
194 SIGNAL(activated(int)),
195 SLOT(tuningChanged()));
196 QObject::connect(m_ui.TuningRefPitchSpinBox,
197 SIGNAL(valueChanged(double)),
198 SLOT(tuningChanged()));
199 QObject::connect(m_ui.TuningRefNotePushButton,
200 SIGNAL(clicked()),
201 SLOT(tuningRefNoteClicked()));
202 QObject::connect(m_ui.TuningScaleFileComboBox,
203 SIGNAL(activated(int)),
204 SLOT(tuningChanged()));
205 QObject::connect(m_ui.TuningScaleFileToolButton,
206 SIGNAL(clicked()),
207 SLOT(tuningScaleFileClicked()));
208 QObject::connect(m_ui.TuningKeyMapFileToolButton,
209 SIGNAL(clicked()),
210 SLOT(tuningKeyMapFileClicked()));
211 QObject::connect(m_ui.TuningKeyMapFileComboBox,
212 SIGNAL(activated(int)),
213 SLOT(tuningChanged()));
214
215 // Options slots...
216 QObject::connect(m_ui.ProgramsPreviewCheckBox,
217 SIGNAL(toggled(bool)),
218 SLOT(optionsChanged()));
219 QObject::connect(m_ui.UseNativeDialogsCheckBox,
220 SIGNAL(toggled(bool)),
221 SLOT(optionsChanged()));
222 QObject::connect(m_ui.KnobDialModeComboBox,
223 SIGNAL(activated(int)),
224 SLOT(optionsChanged()));
225 QObject::connect(m_ui.KnobEditModeComboBox,
226 SIGNAL(activated(int)),
227 SLOT(optionsChanged()));
228 QObject::connect(m_ui.CustomColorThemeComboBox,
229 SIGNAL(activated(int)),
230 SLOT(optionsChanged()));
231 QObject::connect(m_ui.CustomColorThemeToolButton,
232 SIGNAL(clicked()),
233 SLOT(editCustomColorThemes()));
234 QObject::connect(m_ui.CustomStyleThemeComboBox,
235 SIGNAL(activated(int)),
236 SLOT(optionsChanged()));
237 QObject::connect(m_ui.FrameTimeFormatComboBox,
238 SIGNAL(activated(int)),
239 SLOT(optionsChanged()));
240 QObject::connect(m_ui.RandomizePercentSpinBox,
241 SIGNAL(valueChanged(double)),
242 SLOT(optionsChanged()));
243 QObject::connect(m_ui.PitchShiftTypeComboBox,
244 SIGNAL(activated(int)),
245 SLOT(optionsChanged()));
246
247 // Dialog commands...
248 QObject::connect(m_ui.DialogButtonBox,
249 SIGNAL(accepted()),
250 SLOT(accept()));
251 QObject::connect(m_ui.DialogButtonBox,
252 SIGNAL(rejected()),
253 SLOT(reject()));
254
255 // Done.
256 stabilize();
257 }
258
259
260 // dtor.
~samplv1widget_config(void)261 samplv1widget_config::~samplv1widget_config (void)
262 {
263 delete p_ui;
264 }
265
266
ui_instance(void) const267 samplv1_ui *samplv1widget_config::ui_instance (void) const
268 {
269 return m_pSamplUi;
270 }
271
272
273 // controllers command slots.
controlsAddItem(void)274 void samplv1widget_config::controlsAddItem (void)
275 {
276 m_ui.ControlsTreeWidget->addControlItem();
277
278 controlsChanged();
279 }
280
281
controlsEditItem(void)282 void samplv1widget_config::controlsEditItem (void)
283 {
284 QTreeWidgetItem *pItem = m_ui.ControlsTreeWidget->currentItem();
285 if (pItem)
286 m_ui.ControlsTreeWidget->editItem(pItem, 0);
287
288 controlsChanged();
289 }
290
291
controlsDeleteItem(void)292 void samplv1widget_config::controlsDeleteItem (void)
293 {
294 QTreeWidgetItem *pItem = m_ui.ControlsTreeWidget->currentItem();
295 if (pItem)
296 delete pItem;
297
298 controlsChanged();
299 }
300
301
302 // controllers janitorial slots.
controlsCurrentChanged(void)303 void samplv1widget_config::controlsCurrentChanged (void)
304 {
305 stabilize();
306 }
307
308
controlsContextMenuRequested(const QPoint & pos)309 void samplv1widget_config::controlsContextMenuRequested ( const QPoint& pos )
310 {
311 QTreeWidgetItem *pItem = m_ui.ControlsTreeWidget->currentItem();
312
313 QMenu menu(this);
314 QAction *pAction;
315
316 bool bEnabled = (m_pSamplUi && m_pSamplUi->controls() != nullptr);
317
318 pAction = menu.addAction(QIcon(":/images/samplv1_preset.png"),
319 tr("&Add Controller"), this, SLOT(controlsAddItem()));
320 pAction->setEnabled(bEnabled);
321
322 menu.addSeparator();
323
324 bEnabled = bEnabled && (pItem != nullptr);
325
326 pAction = menu.addAction(QIcon(":/images/presetEdit.png"),
327 tr("&Edit"), this, SLOT(controlsEditItem()));
328 pAction->setEnabled(bEnabled);
329
330 menu.addSeparator();
331
332 pAction = menu.addAction(QIcon(":/images/presetDelete.png"),
333 tr("&Delete"), this, SLOT(controlsDeleteItem()));
334 pAction->setEnabled(bEnabled);
335
336 menu.exec(m_ui.ControlsTreeWidget->mapToGlobal(pos));
337 }
338
339
controlsEnabled(bool bOn)340 void samplv1widget_config::controlsEnabled ( bool bOn )
341 {
342 if (m_pSamplUi) {
343 samplv1_controls *pControls = m_pSamplUi->controls();
344 if (pControls && m_pSamplUi->isPlugin())
345 pControls->enabled(bOn);
346 }
347
348 controlsChanged();
349 }
350
351
controlsChanged(void)352 void samplv1widget_config::controlsChanged (void)
353 {
354 ++m_iDirtyControls;
355
356 stabilize();
357 }
358
359
360 // programs command slots.
programsAddBankItem(void)361 void samplv1widget_config::programsAddBankItem (void)
362 {
363 m_ui.ProgramsTreeWidget->addBankItem();
364
365 programsChanged();
366 }
367
368
programsAddItem(void)369 void samplv1widget_config::programsAddItem (void)
370 {
371 m_ui.ProgramsTreeWidget->addProgramItem();
372
373 programsChanged();
374 }
375
376
programsEditItem(void)377 void samplv1widget_config::programsEditItem (void)
378 {
379 QTreeWidgetItem *pItem = m_ui.ProgramsTreeWidget->currentItem();
380 if (pItem)
381 m_ui.ProgramsTreeWidget->editItem(pItem, 1);
382
383 programsChanged();
384 }
385
386
programsDeleteItem(void)387 void samplv1widget_config::programsDeleteItem (void)
388 {
389 QTreeWidgetItem *pItem = m_ui.ProgramsTreeWidget->currentItem();
390 if (pItem)
391 delete pItem;
392
393 programsChanged();
394 }
395
396
397 // programs janitor slots.
programsCurrentChanged(void)398 void samplv1widget_config::programsCurrentChanged (void)
399 {
400 stabilize();
401 }
402
403
programsContextMenuRequested(const QPoint & pos)404 void samplv1widget_config::programsContextMenuRequested ( const QPoint& pos )
405 {
406 QTreeWidgetItem *pItem = m_ui.ProgramsTreeWidget->currentItem();
407
408 QMenu menu(this);
409 QAction *pAction;
410
411 bool bEnabled = (m_pSamplUi && m_pSamplUi->programs() != nullptr);
412
413 pAction = menu.addAction(QIcon(":/images/presetBank.png"),
414 tr("Add &Bank"), this, SLOT(programsAddBankItem()));
415 pAction->setEnabled(bEnabled);
416
417 pAction = menu.addAction(QIcon(":/images/samplv1_preset.png"),
418 tr("&Add Program"), this, SLOT(programsAddItem()));
419 pAction->setEnabled(bEnabled);
420
421 menu.addSeparator();
422
423 bEnabled = bEnabled && (pItem != nullptr);
424
425 pAction = menu.addAction(QIcon(":/images/presetEdit.png"),
426 tr("&Edit"), this, SLOT(programsEditItem()));
427 pAction->setEnabled(bEnabled);
428
429 menu.addSeparator();
430
431 pAction = menu.addAction(QIcon(":/images/presetDelete.png"),
432 tr("&Delete"), this, SLOT(programsDeleteItem()));
433 pAction->setEnabled(bEnabled);
434
435 menu.exec(m_ui.ProgramsTreeWidget->mapToGlobal(pos));
436 }
437
438
programsEnabled(bool bOn)439 void samplv1widget_config::programsEnabled ( bool bOn )
440 {
441 if (m_pSamplUi) {
442 samplv1_programs *pPrograms = m_pSamplUi->programs();
443 if (pPrograms && m_pSamplUi->isPlugin())
444 pPrograms->enabled(bOn);
445 }
446
447 programsChanged();
448 }
449
450
programsChanged(void)451 void samplv1widget_config::programsChanged (void)
452 {
453 ++m_iDirtyPrograms;
454
455 stabilize();
456 }
457
458
programsActivated(void)459 void samplv1widget_config::programsActivated (void)
460 {
461 if (m_pSamplUi) {
462 samplv1_programs *pPrograms = m_pSamplUi->programs();
463 if (m_ui.ProgramsPreviewCheckBox->isChecked() && pPrograms)
464 m_ui.ProgramsTreeWidget->selectProgram(pPrograms);
465 }
466
467 stabilize();
468 }
469
470
471 // tuning command slots
tuningTabChanged(int iTuningTab)472 void samplv1widget_config::tuningTabChanged ( int iTuningTab )
473 {
474 // Prevent loss of some tuning changes here...
475 if (m_iDirtyTuning > 0 &&
476 QMessageBox::warning(this,
477 tr("Warning"),
478 tr("%1 tuning settings have been changed.\n\n"
479 "Do you want to discard the changes?")
480 .arg(m_ui.TuningTabBar->tabText(1 - iTuningTab).remove('&')),
481 QMessageBox::Discard | QMessageBox::Cancel)
482 == QMessageBox::Cancel) {
483 const bool bBlockSignals = m_ui.TuningTabBar->blockSignals(true);
484 m_ui.TuningTabBar->setCurrentIndex(1 - iTuningTab);
485 m_ui.TuningTabBar->blockSignals(bBlockSignals);
486 return;
487 }
488
489 if (iTuningTab == 0) {
490 // Global (default) scope...
491 samplv1_config *pConfig = samplv1_config::getInstance();
492 if (pConfig) {
493 m_ui.TuningEnabledCheckBox->setChecked(pConfig->bTuningEnabled);
494 m_ui.TuningRefNoteComboBox->setCurrentIndex(pConfig->iTuningRefNote);
495 m_ui.TuningRefPitchSpinBox->setValue(double(pConfig->fTuningRefPitch));
496 setComboBoxCurrentItem(
497 m_ui.TuningScaleFileComboBox,
498 QFileInfo(pConfig->sTuningScaleFile));
499 setComboBoxCurrentItem(
500 m_ui.TuningKeyMapFileComboBox,
501 QFileInfo(pConfig->sTuningKeyMapFile));
502 }
503 }
504 else
505 if (m_pSamplUi) {
506 // Instance scope...
507 m_ui.TuningEnabledCheckBox->setChecked(m_pSamplUi->isTuningEnabled());
508 m_ui.TuningRefNoteComboBox->setCurrentIndex(m_pSamplUi->tuningRefNote());
509 m_ui.TuningRefPitchSpinBox->setValue(double(m_pSamplUi->tuningRefPitch()));
510 setComboBoxCurrentItem(
511 m_ui.TuningScaleFileComboBox,
512 QFileInfo(QString::fromUtf8(m_pSamplUi->tuningScaleFile())));
513 setComboBoxCurrentItem(
514 m_ui.TuningKeyMapFileComboBox,
515 QFileInfo(QString::fromUtf8(m_pSamplUi->tuningKeyMapFile())));
516 }
517
518 // Reset tuning dirty flag...
519 m_iDirtyTuning = 0;
520 }
521
522
tuningRefNoteClicked(void)523 void samplv1widget_config::tuningRefNoteClicked (void)
524 {
525 m_ui.TuningRefNoteComboBox->setCurrentIndex(69);
526 m_ui.TuningRefPitchSpinBox->setValue(double(440.0f));
527
528 tuningChanged();
529 }
530
531
tuningScaleFileClicked(void)532 void samplv1widget_config::tuningScaleFileClicked (void)
533 {
534 samplv1_config *pConfig = samplv1_config::getInstance();
535 if (pConfig == nullptr)
536 return;
537
538 QString sTuningScaleFile = m_ui.TuningScaleFileComboBox->currentText();
539
540 const QString sExt("scl");
541 const QString& sTitle = tr("Open Scale File");
542
543 QStringList filters;
544 filters.append(tr("Scale files (*.%1)").arg(sExt));
545 filters.append(tr("All files (*.*)"));
546 const QString& sFilter = filters.join(";;");
547
548 QWidget *pParentWidget = nullptr;
549 QFileDialog::Options options;
550 if (pConfig->bDontUseNativeDialogs) {
551 options |= QFileDialog::DontUseNativeDialog;
552 pParentWidget = QWidget::window();
553 }
554 #if 1//QT_VERSION < QT_VERSION_CHECK(4, 4, 0)
555 sTuningScaleFile = QFileDialog::getOpenFileName(pParentWidget,
556 sTitle, pConfig->sTuningScaleDir, sFilter, nullptr, options);
557 #else
558 QFileDialog fileDialog(pParentWidget,
559 sTitle, sTuningScaleFile, sFilter);
560 fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
561 fileDialog.setFileMode(QFileDialog::ExistingFiles);
562 fileDialog.setDefaultSuffix(sExt);
563 QList<QUrl> urls(fileDialog.sidebarUrls());
564 urls.append(QUrl::fromLocalFile(pConfig->sTuningScaleDir));
565 fileDialog.setSidebarUrls(urls);
566 fileDialog.setOptions(options);
567 if (fileDialog.exec())
568 sTuningScaleFile = fileDialog.selectedFiles().first();
569 #endif
570
571 if (!sTuningScaleFile.isEmpty()) {
572 const QFileInfo info(sTuningScaleFile);
573 if (setComboBoxCurrentItem(m_ui.TuningScaleFileComboBox, info)) {
574 pConfig->sTuningScaleDir = info.absolutePath();
575 tuningChanged();
576 }
577 }
578 }
579
580
tuningKeyMapFileClicked(void)581 void samplv1widget_config::tuningKeyMapFileClicked (void)
582 {
583 samplv1_config *pConfig = samplv1_config::getInstance();
584 if (pConfig == nullptr)
585 return;
586
587 QString sTuningKeyMapFile = m_ui.TuningKeyMapFileComboBox->currentText();
588
589 const QString sExt("kbm");
590 const QString& sTitle = tr("Open Key Map File");
591
592 QStringList filters;
593 filters.append(tr("Key Map files (*.%1)").arg(sExt));
594 filters.append(tr("All files (*.*)"));
595 const QString& sFilter = filters.join(";;");
596
597 QWidget *pParentWidget = nullptr;
598 QFileDialog::Options options;
599 if (pConfig->bDontUseNativeDialogs) {
600 options |= QFileDialog::DontUseNativeDialog;
601 pParentWidget = QWidget::window();
602 }
603 #if 1//QT_VERSION < QT_VERSION_CHECK(4, 4, 0)
604 sTuningKeyMapFile = QFileDialog::getOpenFileName(pParentWidget,
605 sTitle, pConfig->sTuningKeyMapDir, sFilter, nullptr, options);
606 #else
607 QFileDialog fileDialog(pParentWidget,
608 sTitle, sTuningScaleFile, sFilter);
609 fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
610 fileDialog.setFileMode(QFileDialog::ExistingFiles);
611 fileDialog.setDefaultSuffix(sExt);
612 QList<QUrl> urls(fileDialog.sidebarUrls());
613 urls.append(QUrl::fromLocalFile(pConfig->sTuningKeyMapDir));
614 fileDialog.setSidebarUrls(urls);
615 fileDialog.setOptions(options);
616 if (fileDialog.exec())
617 sTuningKeyMapFile = fileDialog.selectedFiles().first();
618 #endif
619
620 if (!sTuningKeyMapFile.isEmpty()) {
621 const QFileInfo info(sTuningKeyMapFile);
622 if (setComboBoxCurrentItem(m_ui.TuningKeyMapFileComboBox, info)) {
623 pConfig->sTuningKeyMapDir = info.absolutePath();
624 tuningChanged();
625 }
626 }
627 }
628
629
tuningChanged(void)630 void samplv1widget_config::tuningChanged (void)
631 {
632 ++m_iDirtyTuning;
633
634 stabilize();
635 }
636
637
638 // options slot.
optionsChanged(void)639 void samplv1widget_config::optionsChanged (void)
640 {
641 ++m_iDirtyOptions;
642
643 stabilize();
644 }
645
646
647 // stabilizer.
stabilize(void)648 void samplv1widget_config::stabilize (void)
649 {
650 QTreeWidgetItem *pItem = m_ui.ControlsTreeWidget->currentItem();
651 bool bEnabled = (m_pSamplUi && m_pSamplUi->controls() != nullptr);
652 m_ui.ControlsAddItemToolButton->setEnabled(bEnabled);
653 bEnabled = bEnabled && (pItem != nullptr);
654 m_ui.ControlsEditToolButton->setEnabled(bEnabled);
655 m_ui.ControlsDeleteToolButton->setEnabled(bEnabled);
656
657 pItem = m_ui.ProgramsTreeWidget->currentItem();
658 bEnabled = (m_pSamplUi && m_pSamplUi->programs() != nullptr);
659 m_ui.ProgramsPreviewCheckBox->setEnabled(
660 bEnabled && m_ui.ProgramsEnabledCheckBox->isChecked());
661 m_ui.ProgramsAddBankToolButton->setEnabled(bEnabled);
662 m_ui.ProgramsAddItemToolButton->setEnabled(bEnabled);
663 bEnabled = bEnabled && (pItem != nullptr);
664 m_ui.ProgramsEditToolButton->setEnabled(bEnabled);
665 m_ui.ProgramsDeleteToolButton->setEnabled(bEnabled);
666
667 bEnabled = m_ui.TuningEnabledCheckBox->isChecked();
668 const bool bTuningRefEnabled = bEnabled
669 && comboBoxCurrentItem(m_ui.TuningKeyMapFileComboBox).isEmpty();
670 m_ui.TuningRefNoteTextLabel->setEnabled(bTuningRefEnabled);
671 m_ui.TuningRefNoteComboBox->setEnabled(bTuningRefEnabled);
672 m_ui.TuningRefPitchSpinBox->setEnabled(bTuningRefEnabled);
673 m_ui.TuningRefNotePushButton->setEnabled(bTuningRefEnabled);
674 m_ui.TuningScaleFileTextLabel->setEnabled(bEnabled);
675 m_ui.TuningScaleFileComboBox->setEnabled(bEnabled);
676 m_ui.TuningScaleFileToolButton->setEnabled(bEnabled);
677 m_ui.TuningKeyMapFileTextLabel->setEnabled(bEnabled);
678 m_ui.TuningKeyMapFileComboBox->setEnabled(bEnabled);
679 m_ui.TuningKeyMapFileToolButton->setEnabled(bEnabled);
680
681 const bool bValid
682 = (m_iDirtyTuning > 0
683 || m_iDirtyControls > 0
684 || m_iDirtyPrograms > 0
685 || m_iDirtyOptions > 0);
686 m_ui.DialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(bValid);
687 }
688
689
690 // dialog slots.
accept(void)691 void samplv1widget_config::accept (void)
692 {
693 samplv1_config *pConfig = samplv1_config::getInstance();
694
695 if (m_iDirtyTuning > 0 && pConfig && m_pSamplUi) {
696 // Micro-tonal tuning settings...
697 if (m_ui.TuningTabBar->currentIndex() == 0) {
698 // Global (default) scope...
699 pConfig->bTuningEnabled = m_ui.TuningEnabledCheckBox->isChecked();
700 pConfig->iTuningRefNote = m_ui.TuningRefNoteComboBox->currentIndex();
701 pConfig->fTuningRefPitch = float(m_ui.TuningRefPitchSpinBox->value());
702 pConfig->sTuningScaleFile = comboBoxCurrentItem(m_ui.TuningScaleFileComboBox);
703 pConfig->sTuningKeyMapFile = comboBoxCurrentItem(m_ui.TuningKeyMapFileComboBox);
704 } else {
705 m_pSamplUi->setTuningEnabled(
706 m_ui.TuningEnabledCheckBox->isChecked());
707 m_pSamplUi->setTuningRefNote(
708 m_ui.TuningRefNoteComboBox->currentIndex());
709 m_pSamplUi->setTuningRefPitch(
710 float(m_ui.TuningRefPitchSpinBox->value()));
711 m_pSamplUi->setTuningScaleFile(comboBoxCurrentItem(
712 m_ui.TuningScaleFileComboBox).toUtf8().constData());
713 m_pSamplUi->setTuningKeyMapFile(comboBoxCurrentItem(
714 m_ui.TuningKeyMapFileComboBox).toUtf8().constData());
715 }
716 // Reset/update micro-tonal tuning...
717 m_pSamplUi->resetTuning();
718 // Save other conveniency options...
719 saveComboBoxHistory(m_ui.TuningScaleFileComboBox);
720 saveComboBoxHistory(m_ui.TuningKeyMapFileComboBox);
721 // Reset dirty flag.
722 m_iDirtyTuning = 0;
723 }
724
725 if (m_iDirtyControls > 0 && pConfig && m_pSamplUi) {
726 // Save controls...
727 samplv1_controls *pControls = m_pSamplUi->controls();
728 if (pControls) {
729 m_ui.ControlsTreeWidget->saveControls(pControls);
730 pConfig->saveControls(pControls);
731 // Reset dirty flag.
732 m_iDirtyControls = 0;
733 }
734 }
735
736 if (m_iDirtyPrograms > 0 && pConfig && m_pSamplUi) {
737 // Save programs...
738 samplv1_programs *pPrograms = m_pSamplUi->programs();
739 if (pPrograms) {
740 m_ui.ProgramsTreeWidget->savePrograms(pPrograms);
741 pConfig->savePrograms(pPrograms);
742 // Reset dirty flag.
743 m_iDirtyPrograms = 0;
744 }
745 }
746
747 if (m_iDirtyOptions > 0 && pConfig) {
748 // Save options...
749 pConfig->bProgramsPreview = m_ui.ProgramsPreviewCheckBox->isChecked();
750 pConfig->bUseNativeDialogs = m_ui.UseNativeDialogsCheckBox->isChecked();
751 pConfig->bDontUseNativeDialogs = !pConfig->bUseNativeDialogs;
752 pConfig->iKnobDialMode = m_ui.KnobDialModeComboBox->currentIndex();
753 samplv1widget_dial::setDialMode(
754 samplv1widget_dial::DialMode(pConfig->iKnobDialMode));
755 pConfig->iKnobEditMode = m_ui.KnobEditModeComboBox->currentIndex();
756 samplv1widget_edit::setEditMode(
757 samplv1widget_edit::EditMode(pConfig->iKnobEditMode));
758 const QString sOldCustomColorTheme = pConfig->sCustomColorTheme;
759 if (m_ui.CustomColorThemeComboBox->currentIndex() > 0)
760 pConfig->sCustomColorTheme = m_ui.CustomColorThemeComboBox->currentText();
761 else
762 pConfig->sCustomColorTheme.clear();
763 const QString sOldCustomStyleTheme = pConfig->sCustomStyleTheme;
764 if (m_ui.CustomStyleThemeComboBox->currentIndex() > 0)
765 pConfig->sCustomStyleTheme = m_ui.CustomStyleThemeComboBox->currentText();
766 else
767 pConfig->sCustomStyleTheme.clear();
768 const int iOldFrameTimeFormat = pConfig->iFrameTimeFormat;
769 const int iOldPitchShiftType = pConfig->iPitchShiftType;
770 pConfig->iFrameTimeFormat = m_ui.FrameTimeFormatComboBox->currentIndex();
771 pConfig->fRandomizePercent = float(m_ui.RandomizePercentSpinBox->value());
772 pConfig->iPitchShiftType = m_ui.PitchShiftTypeComboBox->currentIndex();
773 int iNeedRestart = 0;
774 if (pConfig->sCustomStyleTheme != sOldCustomStyleTheme) {
775 if (pConfig->sCustomStyleTheme.isEmpty()) {
776 ++iNeedRestart;
777 } else {
778 QApplication::setStyle(
779 QStyleFactory::create(pConfig->sCustomStyleTheme));
780 }
781 }
782 if (pConfig->sCustomColorTheme != sOldCustomColorTheme) {
783 if (pConfig->sCustomColorTheme.isEmpty()) {
784 ++iNeedRestart;
785 } else {
786 QPalette pal;
787 if (samplv1widget_palette::namedPalette(
788 pConfig, pConfig->sCustomColorTheme, pal))
789 QApplication::setPalette(pal);
790 }
791 }
792 if (pConfig->iFrameTimeFormat != iOldFrameTimeFormat)
793 ++iNeedRestart;
794 if (pConfig->iPitchShiftType != iOldPitchShiftType) {
795 ++iNeedRestart;
796 samplv1_pshifter::setDefaultType(
797 samplv1_pshifter::Type(pConfig->iPitchShiftType));
798 }
799 // Show restart message if needed...
800 if (iNeedRestart > 0) {
801 QMessageBox::information(this,
802 tr("Information"),
803 tr("Some settings may be only effective\n"
804 "next time you start this application."));
805 }
806 // Reset dirty flag.
807 m_iDirtyOptions = 0;
808 }
809
810 // Just go with dialog acceptance.
811 QDialog::accept();
812 }
813
814
reject(void)815 void samplv1widget_config::reject (void)
816 {
817 bool bReject = true;
818
819 // Check if there's any pending changes...
820 if (m_iDirtyTuning > 0 ||
821 m_iDirtyControls > 0 ||
822 m_iDirtyPrograms > 0 ||
823 m_iDirtyOptions > 0) {
824 QMessageBox::StandardButtons buttons
825 = QMessageBox::Discard | QMessageBox::Cancel;
826 if (m_ui.DialogButtonBox->button(QDialogButtonBox::Ok)->isEnabled())
827 buttons |= QMessageBox::Apply;
828 switch (QMessageBox::warning(this,
829 tr("Warning"),
830 tr("Some settings have been changed.\n\n"
831 "Do you want to apply the changes?"),
832 buttons)) {
833 case QMessageBox::Apply:
834 accept();
835 return;
836 case QMessageBox::Discard:
837 break;
838 default: // Cancel.
839 bReject = false;
840 }
841 }
842
843 if (bReject)
844 QDialog::reject();
845 }
846
847
848 // Custom color palette theme manager.
editCustomColorThemes(void)849 void samplv1widget_config::editCustomColorThemes (void)
850 {
851 samplv1_config *pConfig = samplv1_config::getInstance();
852 if (pConfig == nullptr)
853 return;
854
855 samplv1widget_palette form(this);
856 form.setSettings(pConfig);
857
858 QString sCustomColorTheme;
859 int iDirtyCustomColorTheme = 0;
860
861 const int iCustomColorTheme
862 = m_ui.CustomColorThemeComboBox->currentIndex();
863 if (iCustomColorTheme > 0) {
864 sCustomColorTheme = m_ui.CustomColorThemeComboBox->itemText(iCustomColorTheme);
865 form.setPaletteName(sCustomColorTheme);
866 }
867
868 if (form.exec() == QDialog::Accepted) {
869 sCustomColorTheme = form.paletteName();
870 ++iDirtyCustomColorTheme;
871 }
872
873 if (iDirtyCustomColorTheme > 0 || form.isDirty()) {
874 resetCustomColorThemes(sCustomColorTheme);
875 optionsChanged();
876 }
877 }
878
879
880 // Custom color palette themes settler.
resetCustomColorThemes(const QString & sCustomColorTheme)881 void samplv1widget_config::resetCustomColorThemes (
882 const QString& sCustomColorTheme )
883 {
884 m_ui.CustomColorThemeComboBox->clear();
885 m_ui.CustomColorThemeComboBox->addItem(
886 tr(g_pszDefName));
887 samplv1_config *pConfig = samplv1_config::getInstance();
888 if (pConfig) m_ui.CustomColorThemeComboBox->addItems(
889 samplv1widget_palette::namedPaletteList(pConfig));
890
891 int iCustomColorTheme = 0;
892 if (!sCustomColorTheme.isEmpty()) {
893 iCustomColorTheme = m_ui.CustomColorThemeComboBox->findText(
894 sCustomColorTheme);
895 if (iCustomColorTheme < 0)
896 iCustomColorTheme = 0;
897 }
898 m_ui.CustomColorThemeComboBox->setCurrentIndex(iCustomColorTheme);
899 }
900
901
902 // Custom widget style themes settler.
resetCustomStyleThemes(const QString & sCustomStyleTheme)903 void samplv1widget_config::resetCustomStyleThemes (
904 const QString& sCustomStyleTheme )
905 {
906 m_ui.CustomStyleThemeComboBox->clear();
907 m_ui.CustomStyleThemeComboBox->addItem(
908 tr(g_pszDefName));
909 m_ui.CustomStyleThemeComboBox->addItems(
910 QStyleFactory::keys());
911
912 int iCustomStyleTheme = 0;
913 if (!sCustomStyleTheme.isEmpty()) {
914 iCustomStyleTheme = m_ui.CustomStyleThemeComboBox->findText(
915 sCustomStyleTheme);
916 if (iCustomStyleTheme < 0)
917 iCustomStyleTheme = 0;
918 }
919 m_ui.CustomStyleThemeComboBox->setCurrentIndex(iCustomStyleTheme);
920 }
921
922
923 // Combo box history persistence helper implementation.
loadComboBoxHistory(QComboBox * pComboBox)924 void samplv1widget_config::loadComboBoxHistory ( QComboBox *pComboBox )
925 {
926 samplv1_config *pConfig = samplv1_config::getInstance();
927 if (pConfig == nullptr)
928 return;
929
930 // Load combobox list from configuration settings file...
931 const bool bBlockSignals = pComboBox->blockSignals(true);
932 pConfig->beginGroup("/History");
933 const QStringList& history
934 = pConfig->value('/' + pComboBox->objectName()).toStringList();
935 QStringListIterator iter(history);
936 while (iter.hasNext()) {
937 const QFileInfo info(iter.next());
938 if (info.exists() && info.isReadable()) {
939 const QString& sPath = info.canonicalFilePath();
940 pComboBox->insertItem(0, info.fileName(), sPath);
941 }
942 }
943 pConfig->endGroup();
944 pComboBox->blockSignals(bBlockSignals);
945 }
946
947
saveComboBoxHistory(QComboBox * pComboBox)948 void samplv1widget_config::saveComboBoxHistory ( QComboBox *pComboBox )
949 {
950 samplv1_config *pConfig = samplv1_config::getInstance();
951 if (pConfig == nullptr)
952 return;
953
954 // Save combobox list to configuration settings file...
955 const bool bBlockSignals = pComboBox->blockSignals(true);
956 pConfig->beginGroup("/History");
957 QStringList history;
958 const int iCount = pComboBox->count();
959 for (int i = 0; i < iCount; ++i) {
960 const QString& sData = pComboBox->itemData(i).toString();
961 if (!sData.isEmpty())
962 history.prepend(sData);
963 }
964 pConfig->setValue('/' + pComboBox->objectName(), history);
965 pConfig->endGroup();
966 pComboBox->blockSignals(bBlockSignals);
967 }
968
969
970 // Combo box settter/gettter helper prototypes.
setComboBoxCurrentItem(QComboBox * pComboBox,const QFileInfo & info)971 bool samplv1widget_config::setComboBoxCurrentItem (
972 QComboBox *pComboBox, const QFileInfo& info )
973 {
974 const bool bBlockSignals = pComboBox->blockSignals(true);
975 const bool bResult = info.exists() && info.isReadable();
976 if (bResult) {
977 const QString& sData = info.canonicalFilePath();
978 int iIndex = pComboBox->findData(sData);
979 if (iIndex < 0) {
980 pComboBox->insertItem(0, info.fileName(), sData);
981 iIndex = 0;
982 }
983 pComboBox->setCurrentIndex(iIndex);
984 pComboBox->setToolTip(sData);
985 } else {
986 pComboBox->setCurrentIndex(pComboBox->count() - 1);
987 pComboBox->setToolTip(pComboBox->currentText());
988 }
989 pComboBox->blockSignals(bBlockSignals);
990
991 return bResult;
992 }
993
994
comboBoxCurrentItem(QComboBox * pComboBox)995 QString samplv1widget_config::comboBoxCurrentItem ( QComboBox *pComboBox )
996 {
997 QString sData;
998
999 const int iIndex = pComboBox->currentIndex();
1000 if (iIndex >= 0)
1001 sData = pComboBox->itemData(iIndex).toString();
1002
1003 return sData;
1004 }
1005
1006
1007 // end of samplv1widget_config.cpp
1008