From 35e8b61b7d34b960e47990cd541e6009d12e7ee5 Mon Sep 17 00:00:00 2001 From: Neil Horne <15316949+elecpower@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:49:34 +1100 Subject: [PATCH] feat(cpn): read and write to/from radio profile SD path, menu reorganisation (#5753) --- companion/releasenotes.txt | 484 ----------------- companion/src/companion.qrc | 41 +- .../originals/folder-tree-read-classic.svg | 162 ++++++ .../originals/folder-tree-read-monochrome.svg | 66 +++ .../originals/folder-tree-read-outline.svg | 110 ++++ .../originals/folder-tree-read-yerico.svg | 111 ++++ .../originals/folder-tree-write-classic.svg | 162 ++++++ .../folder-tree-write-monochrome.svg | 66 +++ .../originals/folder-tree-write-outline.svg | 108 ++++ .../originals/folder-tree-write-yerico.svg | 111 ++++ companion/src/mainwindow.cpp | 514 ++++++++++++------ companion/src/mainwindow.h | 67 ++- companion/src/mdichild.cpp | 72 ++- companion/src/mdichild.h | 19 +- companion/src/radiointerface.cpp | 28 +- companion/src/radiointerface.h | 7 +- companion/src/storage/appdata.h | 7 + .../themes/classic/16/folder-tree-read.png | Bin 0 -> 569 bytes .../themes/classic/16/folder-tree-write.png | Bin 0 -> 586 bytes .../themes/classic/24/folder-tree-read.png | Bin 0 -> 803 bytes .../themes/classic/24/folder-tree-write.png | Bin 0 -> 789 bytes .../themes/classic/32/folder-tree-read.png | Bin 0 -> 1055 bytes .../themes/classic/32/folder-tree-write.png | Bin 0 -> 1078 bytes .../themes/classic/48/folder-tree-read.png | Bin 0 -> 1560 bytes .../themes/classic/48/folder-tree-write.png | Bin 0 -> 1586 bytes .../themes/monoblue/16/folder-tree-read.png | Bin 0 -> 424 bytes .../themes/monoblue/16/folder-tree-write.png | Bin 0 -> 418 bytes .../themes/monoblue/24/folder-tree-read.png | Bin 0 -> 435 bytes .../themes/monoblue/24/folder-tree-write.png | Bin 0 -> 432 bytes .../themes/monoblue/32/folder-tree-read.png | Bin 0 -> 452 bytes .../themes/monoblue/32/folder-tree-write.png | Bin 0 -> 450 bytes .../themes/monoblue/48/folder-tree-read.png | Bin 0 -> 480 bytes .../themes/monoblue/48/folder-tree-write.png | Bin 0 -> 479 bytes .../themes/monochrome/16/folder-tree-read.png | Bin 0 -> 436 bytes .../monochrome/16/folder-tree-write.png | Bin 0 -> 434 bytes .../themes/monochrome/24/folder-tree-read.png | Bin 0 -> 573 bytes .../monochrome/24/folder-tree-write.png | Bin 0 -> 568 bytes .../themes/monochrome/32/folder-tree-read.png | Bin 0 -> 711 bytes .../monochrome/32/folder-tree-write.png | Bin 0 -> 715 bytes .../themes/monochrome/48/folder-tree-read.png | Bin 0 -> 983 bytes .../monochrome/48/folder-tree-write.png | Bin 0 -> 1013 bytes .../themes/monowhite/16/folder-tree-read.png | Bin 0 -> 440 bytes .../themes/monowhite/16/folder-tree-write.png | Bin 0 -> 434 bytes .../themes/monowhite/24/folder-tree-read.png | Bin 0 -> 625 bytes .../themes/monowhite/24/folder-tree-write.png | Bin 0 -> 612 bytes .../themes/monowhite/32/folder-tree-read.png | Bin 0 -> 798 bytes .../themes/monowhite/32/folder-tree-write.png | Bin 0 -> 794 bytes .../themes/monowhite/48/folder-tree-read.png | Bin 0 -> 1238 bytes .../themes/monowhite/48/folder-tree-write.png | Bin 0 -> 1241 bytes .../src/themes/yerico/16/folder-tree-read.png | Bin 0 -> 812 bytes .../themes/yerico/16/folder-tree-write.png | Bin 0 -> 812 bytes .../src/themes/yerico/24/folder-tree-read.png | Bin 0 -> 1241 bytes .../themes/yerico/24/folder-tree-write.png | Bin 0 -> 1240 bytes .../src/themes/yerico/32/folder-tree-read.png | Bin 0 -> 1721 bytes .../themes/yerico/32/folder-tree-write.png | Bin 0 -> 1725 bytes .../src/themes/yerico/48/folder-tree-read.png | Bin 0 -> 2652 bytes .../themes/yerico/48/folder-tree-write.png | Bin 0 -> 2659 bytes 57 files changed, 1403 insertions(+), 732 deletions(-) delete mode 100644 companion/releasenotes.txt create mode 100644 companion/src/images/originals/folder-tree-read-classic.svg create mode 100644 companion/src/images/originals/folder-tree-read-monochrome.svg create mode 100644 companion/src/images/originals/folder-tree-read-outline.svg create mode 100644 companion/src/images/originals/folder-tree-read-yerico.svg create mode 100644 companion/src/images/originals/folder-tree-write-classic.svg create mode 100644 companion/src/images/originals/folder-tree-write-monochrome.svg create mode 100644 companion/src/images/originals/folder-tree-write-outline.svg create mode 100644 companion/src/images/originals/folder-tree-write-yerico.svg create mode 100644 companion/src/themes/classic/16/folder-tree-read.png create mode 100644 companion/src/themes/classic/16/folder-tree-write.png create mode 100644 companion/src/themes/classic/24/folder-tree-read.png create mode 100644 companion/src/themes/classic/24/folder-tree-write.png create mode 100644 companion/src/themes/classic/32/folder-tree-read.png create mode 100644 companion/src/themes/classic/32/folder-tree-write.png create mode 100644 companion/src/themes/classic/48/folder-tree-read.png create mode 100644 companion/src/themes/classic/48/folder-tree-write.png create mode 100644 companion/src/themes/monoblue/16/folder-tree-read.png create mode 100644 companion/src/themes/monoblue/16/folder-tree-write.png create mode 100644 companion/src/themes/monoblue/24/folder-tree-read.png create mode 100644 companion/src/themes/monoblue/24/folder-tree-write.png create mode 100644 companion/src/themes/monoblue/32/folder-tree-read.png create mode 100644 companion/src/themes/monoblue/32/folder-tree-write.png create mode 100644 companion/src/themes/monoblue/48/folder-tree-read.png create mode 100644 companion/src/themes/monoblue/48/folder-tree-write.png create mode 100644 companion/src/themes/monochrome/16/folder-tree-read.png create mode 100644 companion/src/themes/monochrome/16/folder-tree-write.png create mode 100644 companion/src/themes/monochrome/24/folder-tree-read.png create mode 100644 companion/src/themes/monochrome/24/folder-tree-write.png create mode 100644 companion/src/themes/monochrome/32/folder-tree-read.png create mode 100644 companion/src/themes/monochrome/32/folder-tree-write.png create mode 100644 companion/src/themes/monochrome/48/folder-tree-read.png create mode 100644 companion/src/themes/monochrome/48/folder-tree-write.png create mode 100644 companion/src/themes/monowhite/16/folder-tree-read.png create mode 100644 companion/src/themes/monowhite/16/folder-tree-write.png create mode 100644 companion/src/themes/monowhite/24/folder-tree-read.png create mode 100644 companion/src/themes/monowhite/24/folder-tree-write.png create mode 100644 companion/src/themes/monowhite/32/folder-tree-read.png create mode 100644 companion/src/themes/monowhite/32/folder-tree-write.png create mode 100644 companion/src/themes/monowhite/48/folder-tree-read.png create mode 100644 companion/src/themes/monowhite/48/folder-tree-write.png create mode 100644 companion/src/themes/yerico/16/folder-tree-read.png create mode 100644 companion/src/themes/yerico/16/folder-tree-write.png create mode 100644 companion/src/themes/yerico/24/folder-tree-read.png create mode 100644 companion/src/themes/yerico/24/folder-tree-write.png create mode 100644 companion/src/themes/yerico/32/folder-tree-read.png create mode 100644 companion/src/themes/yerico/32/folder-tree-write.png create mode 100644 companion/src/themes/yerico/48/folder-tree-read.png create mode 100644 companion/src/themes/yerico/48/folder-tree-write.png diff --git a/companion/releasenotes.txt b/companion/releasenotes.txt deleted file mode 100644 index 58ef7c750..000000000 --- a/companion/releasenotes.txt +++ /dev/null @@ -1,484 +0,0 @@ -

Version 2.2.1 / 2017-12-17

- -Please see this page for details. - -

Version 2.2.0 / 2017-05-30

- -Major release! Please see this page for details. - -

Version 2.1.9 / 2016-09-14

- - - - -

Version 2.1.8 / 2016-04-14

- - - - -

Version 2.1.7 / 2016-01-04

- - - - -

Version 2.1.6 / 2015-11-11

- - - - -

Version 2.1.5 / 2015-11-05

- -Notice: version 2.1.4 was skipped by the OpenTX team to avoid confusion with FrSky's release of OpenTX 2.1.4 - - - - -

Version 2.1.3 / 2015-09-09

- - - - -

Version 2.1.2 / 2015-09-07

- - - - -

Version 2.1.1 / 2015-08-06

- - - -

Version 2.1.0 / 2015-07-16

- - - -

Version 2.0.17 / 2015-05-04

- - - -

Version 2.0.16 / 2015-05-03

- - - -

Version 2.0.15 / 2015-01-13

- - -

Version 2.0.14 / 2015-01-12

- - -

Version 2.0.13 / 2014-11-20

- - -

Version 2.0.12 / 2014-09-15

- - -

Version 2.0.11 / 2014-09-10

- - -

Version 2.0.10 / 2014-09-08

- - -

Version 2.0.8 / 2014-07-23

- - -

Version 2.0.7

- - -

Version 2.0.6

- - -

Version 2.0.5

- - -

Version 2.0.4

- - -

Version 2.0.3

- - -

Version 2.0.2

- - -

Version 2.0.1

- - -

Version 2.0.0

- - -

Version 1.52

- - -

Version 1.51

- - -

Version 1.50

- - -

Version 1.49

- - -

Version 1.48

- - -

Version 1.47

- - -

Version 1.46

- - -

Version 1.45

- - -

Version 1.44

- - -

Version 1.43

- - -

Version 1.42

- - -

Version 1.41

- - -

Version 1.40

- - -

Version 1.39

- - -

Version 1.38

- - -

Version 1.37

- - -

Version 1.36

- - -

Version 1.35

- diff --git a/companion/src/companion.qrc b/companion/src/companion.qrc index b78cf3506..bd395a443 100644 --- a/companion/src/companion.qrc +++ b/companion/src/companion.qrc @@ -2,7 +2,6 @@ images/customize.png images/icon.png - ../releasenotes.txt images/screenshot.png images/splash.png images/companion-title.png @@ -191,6 +190,8 @@ themes/monochrome/16/stop.png themes/monochrome/16/write_eeprom.png themes/monochrome/16/sdsync.png + themes/monochrome/16/folder-tree-read.png + themes/monochrome/16/folder-tree-write.png themes/monochrome/24/paintbrush.png themes/monochrome/24/open.png themes/monochrome/24/edit.png @@ -235,6 +236,8 @@ themes/monochrome/24/stop.png themes/monochrome/24/write_eeprom.png themes/monochrome/24/sdsync.png + themes/monochrome/24/folder-tree-read.png + themes/monochrome/24/folder-tree-write.png themes/monochrome/32/paintbrush.png themes/monochrome/32/open.png themes/monochrome/32/edit.png @@ -279,6 +282,8 @@ themes/monochrome/32/stop.png themes/monochrome/32/write_eeprom.png themes/monochrome/32/sdsync.png + themes/monochrome/32/folder-tree-read.png + themes/monochrome/32/folder-tree-write.png themes/monochrome/48/paintbrush.png themes/monochrome/48/open.png themes/monochrome/48/edit.png @@ -323,6 +328,8 @@ themes/monochrome/48/stop.png themes/monochrome/48/write_eeprom.png themes/monochrome/48/sdsync.png + themes/monochrome/48/folder-tree-read.png + themes/monochrome/48/folder-tree-write.png themes/classic/16/paintbrush.png themes/classic/16/open.png themes/classic/16/edit.png @@ -367,6 +374,8 @@ themes/classic/16/stop.png themes/classic/16/write_eeprom.png themes/classic/16/sdsync.png + themes/classic/16/folder-tree-read.png + themes/classic/16/folder-tree-write.png themes/classic/24/paintbrush.png themes/classic/24/open.png themes/classic/24/edit.png @@ -411,6 +420,8 @@ themes/classic/24/stop.png themes/classic/24/write_eeprom.png themes/classic/24/sdsync.png + themes/classic/24/folder-tree-read.png + themes/classic/24/folder-tree-write.png themes/classic/32/paintbrush.png themes/classic/32/open.png themes/classic/32/edit.png @@ -455,6 +466,8 @@ themes/classic/32/stop.png themes/classic/32/write_eeprom.png themes/classic/32/sdsync.png + themes/classic/32/folder-tree-read.png + themes/classic/32/folder-tree-write.png themes/classic/48/paintbrush.png themes/classic/48/open.png themes/classic/48/edit.png @@ -499,6 +512,8 @@ themes/classic/48/stop.png themes/classic/48/write_eeprom.png themes/classic/48/sdsync.png + themes/classic/48/folder-tree-read.png + themes/classic/48/folder-tree-write.png themes/monoblue/16/paintbrush.png themes/monoblue/16/open.png themes/monoblue/16/edit.png @@ -543,6 +558,8 @@ themes/monoblue/16/stop.png themes/monoblue/16/write_eeprom.png themes/monoblue/16/sdsync.png + themes/monoblue/16/folder-tree-read.png + themes/monoblue/16/folder-tree-write.png themes/monoblue/24/paintbrush.png themes/monoblue/24/open.png themes/monoblue/24/edit.png @@ -587,6 +604,8 @@ themes/monoblue/24/stop.png themes/monoblue/24/write_eeprom.png themes/monoblue/24/sdsync.png + themes/monoblue/24/folder-tree-read.png + themes/monoblue/24/folder-tree-write.png themes/monoblue/32/paintbrush.png themes/monoblue/32/open.png themes/monoblue/32/edit.png @@ -631,6 +650,8 @@ themes/monoblue/32/stop.png themes/monoblue/32/write_eeprom.png themes/monoblue/32/sdsync.png + themes/monoblue/32/folder-tree-read.png + themes/monoblue/32/folder-tree-write.png themes/monoblue/48/paintbrush.png themes/monoblue/48/open.png themes/monoblue/48/edit.png @@ -675,6 +696,8 @@ themes/monoblue/48/stop.png themes/monoblue/48/write_eeprom.png themes/monoblue/48/sdsync.png + themes/monoblue/48/folder-tree-read.png + themes/monoblue/48/folder-tree-write.png themes/monowhite/16/paintbrush.png themes/monowhite/16/open.png themes/monowhite/16/edit.png @@ -719,6 +742,8 @@ themes/monowhite/16/stop.png themes/monowhite/16/write_eeprom.png themes/monowhite/16/sdsync.png + themes/monowhite/16/folder-tree-read.png + themes/monowhite/16/folder-tree-write.png themes/monowhite/24/paintbrush.png themes/monowhite/24/open.png themes/monowhite/24/edit.png @@ -763,6 +788,8 @@ themes/monowhite/24/stop.png themes/monowhite/24/write_eeprom.png themes/monowhite/24/sdsync.png + themes/monowhite/24/folder-tree-read.png + themes/monowhite/24/folder-tree-write.png themes/monowhite/32/paintbrush.png themes/monowhite/32/open.png themes/monowhite/32/edit.png @@ -807,6 +834,8 @@ themes/monowhite/32/stop.png themes/monowhite/32/write_eeprom.png themes/monowhite/32/sdsync.png + themes/monowhite/32/folder-tree-read.png + themes/monowhite/32/folder-tree-write.png themes/monowhite/48/paintbrush.png themes/monowhite/48/open.png themes/monowhite/48/edit.png @@ -851,6 +880,8 @@ themes/monowhite/48/stop.png themes/monowhite/48/write_eeprom.png themes/monowhite/48/sdsync.png + themes/monowhite/48/folder-tree-read.png + themes/monowhite/48/folder-tree-write.png themes/yerico/16/paintbrush.png themes/yerico/16/open.png themes/yerico/16/edit.png @@ -895,6 +926,8 @@ themes/yerico/16/stop.png themes/yerico/16/write_eeprom.png themes/yerico/16/sdsync.png + themes/yerico/16/folder-tree-read.png + themes/yerico/16/folder-tree-write.png themes/yerico/24/paintbrush.png themes/yerico/24/open.png themes/yerico/24/edit.png @@ -939,6 +972,8 @@ themes/yerico/24/stop.png themes/yerico/24/write_eeprom.png themes/yerico/24/sdsync.png + themes/yerico/24/folder-tree-read.png + themes/yerico/24/folder-tree-write.png themes/yerico/32/paintbrush.png themes/yerico/32/open.png themes/yerico/32/edit.png @@ -983,6 +1018,8 @@ themes/yerico/32/stop.png themes/yerico/32/write_eeprom.png themes/yerico/32/sdsync.png + themes/yerico/32/folder-tree-read.png + themes/yerico/32/folder-tree-write.png themes/yerico/48/paintbrush.png themes/yerico/48/open.png themes/yerico/48/edit.png @@ -1027,6 +1064,8 @@ themes/yerico/48/stop.png themes/yerico/48/write_eeprom.png themes/yerico/48/sdsync.png + themes/yerico/48/folder-tree-read.png + themes/yerico/48/folder-tree-write.png sounds/0.wav sounds/1.wav sounds/2.wav diff --git a/companion/src/images/originals/folder-tree-read-classic.svg b/companion/src/images/originals/folder-tree-read-classic.svg new file mode 100644 index 000000000..99bdf8f32 --- /dev/null +++ b/companion/src/images/originals/folder-tree-read-classic.svg @@ -0,0 +1,162 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-read-monochrome.svg b/companion/src/images/originals/folder-tree-read-monochrome.svg new file mode 100644 index 000000000..61bbd4967 --- /dev/null +++ b/companion/src/images/originals/folder-tree-read-monochrome.svg @@ -0,0 +1,66 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-read-outline.svg b/companion/src/images/originals/folder-tree-read-outline.svg new file mode 100644 index 000000000..4411f60e4 --- /dev/null +++ b/companion/src/images/originals/folder-tree-read-outline.svg @@ -0,0 +1,110 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-read-yerico.svg b/companion/src/images/originals/folder-tree-read-yerico.svg new file mode 100644 index 000000000..9128da187 --- /dev/null +++ b/companion/src/images/originals/folder-tree-read-yerico.svg @@ -0,0 +1,111 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-write-classic.svg b/companion/src/images/originals/folder-tree-write-classic.svg new file mode 100644 index 000000000..c1fcb7a5a --- /dev/null +++ b/companion/src/images/originals/folder-tree-write-classic.svg @@ -0,0 +1,162 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-write-monochrome.svg b/companion/src/images/originals/folder-tree-write-monochrome.svg new file mode 100644 index 000000000..1ef1dac65 --- /dev/null +++ b/companion/src/images/originals/folder-tree-write-monochrome.svg @@ -0,0 +1,66 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-write-outline.svg b/companion/src/images/originals/folder-tree-write-outline.svg new file mode 100644 index 000000000..e9a703d9d --- /dev/null +++ b/companion/src/images/originals/folder-tree-write-outline.svg @@ -0,0 +1,108 @@ + + + + diff --git a/companion/src/images/originals/folder-tree-write-yerico.svg b/companion/src/images/originals/folder-tree-write-yerico.svg new file mode 100644 index 000000000..4318c5ea2 --- /dev/null +++ b/companion/src/images/originals/folder-tree-write-yerico.svg @@ -0,0 +1,111 @@ + + + + diff --git a/companion/src/mainwindow.cpp b/companion/src/mainwindow.cpp index 542b15d73..362bed837 100644 --- a/companion/src/mainwindow.cpp +++ b/companion/src/mainwindow.cpp @@ -90,7 +90,7 @@ MainWindow::MainWindow(): if (g.isFirstUse()) { g.warningId(g.warningId() | AppMessages::MSG_WELCOME); - QTimer::singleShot(updateDelay-500, this, SLOT(appPrefs())); // must be shown before warnings dialog but after splash + QTimer::singleShot(updateDelay-500, this, SLOT(editAppSettings())); // must be shown before warnings dialog but after splash } else { if (!g.previousVersion().isEmpty()) @@ -205,7 +205,7 @@ void MainWindow::closeEvent(QCloseEvent *event) #endif g.mainWinGeo(saveGeometry()); g.mainWinState(saveState()); - g.tabbedMdi(actTabbedWindows->isChecked()); + g.tabbedMdi(tabbedWindowsAct->isChecked()); QApplication::closeAllWindows(); mdiArea->closeAllSubWindows(); if (mdiArea->currentSubWindow()) { @@ -255,7 +255,7 @@ void MainWindow::manualCheckForUpdates() statusBar()->clearMessage(); } -void MainWindow::downloads() +void MainWindow::updates() { doUpdates(false); } @@ -325,13 +325,13 @@ void MainWindow::onIconSizeChanged(QAction * act) void MainWindow::setTabbedWindows(bool on) { mdiArea->setViewMode(on ? QMdiArea::TabbedView : QMdiArea::SubWindowView); - if (actTileWindows) - actTileWindows->setDisabled(on); - if (actCascadeWindows) - actCascadeWindows->setDisabled(on); + if (tileWindowsAct) + tileWindowsAct->setDisabled(on); + if (cascadeWindowsAct) + cascadeWindowsAct->setDisabled(on); - if (actTabbedWindows->isChecked() != on) - actTabbedWindows->setChecked(on); + if (tabbedWindowsAct->isChecked() != on) + tabbedWindowsAct->setChecked(on); } void MainWindow::newFile() @@ -452,7 +452,7 @@ void MainWindow::loadProfile() } } -void MainWindow::appPrefs() +void MainWindow::editAppSettings() { AppPreferencesDialog * dialog = new AppPreferencesDialog(this, updateFactories); dialog->setMainWinHasDirtyChild(anyChildrenDirty()); @@ -460,6 +460,7 @@ void MainWindow::appPrefs() connect(dialog, &AppPreferencesDialog::firmwareProfileChanged, this, &MainWindow::onCurrentProfileChanged); dialog->exec(); dialog->deleteLater(); + updateMenus(); } void MainWindow::sdsync(bool postUpdate) @@ -677,9 +678,11 @@ void MainWindow::updateMenus() compareAct->setEnabled(activeChild); writeSettingsAct->setEnabled(activeChild); readSettingsAct->setEnabled(true); + writeSettingsSDPathAct->setEnabled(activeChild && isSDPathValid()); + readSettingsSDPathAct->setEnabled(isSDPathValid()); writeBUToRadioAct->setEnabled(false); readBUToFileAct->setEnabled(false); - editSplashAct->setDisabled(IS_FAMILY_HORUS_OR_T16(getCurrentBoard())); + editSplashAct->setDisabled(Boards::getBoardCapability(getCurrentBoard(), Board::HasColorLcd)); foreach (QAction * act, fileWindowActions) { if (!act) @@ -692,34 +695,39 @@ void MainWindow::updateMenus() if (act->isSeparator() && act->parent() == this) delete act; } - fileWindowActions.clear(); - if (activeChild) { - editMenu->clear(); - editMenu->addActions(activeMdiChild()->getEditActions()); - editMenu->addSeparator(); - editMenu->addActions(activeMdiChild()->getModelActions()); // maybe separate menu/toolbar? - editMenu->setEnabled(true); - editToolBar->clear(); - editToolBar->addActions(activeMdiChild()->getEditActions()); - editToolBar->setEnabled(true); + fileWindowActions.clear(); + + if (activeChild) { + modelsMenu->clear(); + modelsMenu->addActions(activeMdiChild()->getEditActions()); + modelsMenu->addSeparator(); + modelsMenu->addActions(activeMdiChild()->getModelActions()); // maybe separate menu/toolbar? + modelsMenu->addAction(compareAct); + modelsMenu->setEnabled(true); + + modelsToolBar->clear(); + modelsToolBar->addActions(activeMdiChild()->getEditActions()); + modelsToolBar->addAction(compareAct); + modelsToolBar->setEnabled(true); + if (activeMdiChild()->getAction(MdiChild::ACT_MDL_MOV)) { // workaround for default split button appearance of action with menu :-/ QToolButton * btn; - if ((btn = qobject_cast(editToolBar->widgetForAction(activeMdiChild()->getAction(MdiChild::ACT_MDL_MOV))))) + if ((btn = qobject_cast(modelsToolBar->widgetForAction(activeMdiChild()->getAction(MdiChild::ACT_MDL_MOV))))) btn->setPopupMode(QToolButton::InstantPopup); } fileWindowActions = activeMdiChild()->getGeneralActions(); QAction *sep = new QAction(this); sep->setSeparator(true); - fileWindowActions.append(sep); - fileMenu->insertActions(logsAct, fileWindowActions); - fileToolBar->insertActions(logsAct, fileWindowActions); + fileWindowActions.insert(0, sep); + radioMenu->addActions(fileWindowActions); + modelsToolBar->addActions(fileWindowActions); // do not put these in radio toolbar } else { - editToolBar->setDisabled(true); - editMenu->setDisabled(true); + modelsToolBar->setDisabled(true); + modelsMenu->setDisabled(true); } foreach (QAction * act, windowsListActions->actions()) { @@ -732,7 +740,7 @@ void MainWindow::updateMenus() updateRecentFileActions(); updateProfilesActions(); - setWindowTitle(tr("EdgeTX Companion %1 - Radio: %2 - Profile: %3").arg(VERSION).arg(getCurrentFirmware()->getName()).arg(g.profile[g.id()].name())); + setWindowTitle(tr("%1 %2 - Radio: %3 - Profile: %4").arg(CPN_STR_APP_NAME).arg(VERSION).arg(getCurrentFirmware()->getName()).arg(g.profile[g.id()].name())); } MdiChild * MainWindow::createMdiChild() @@ -801,59 +809,70 @@ void MainWindow::trAct(QAction * act, const QString & text, const QString & desc void MainWindow::retranslateUi(bool showMsg) { - trAct(newAct, tr("New"), tr("Create a new Models and Settings file")); - trAct(openAct, tr("Open..."), tr("Open Models and Settings file")); - trAct(saveAct, tr("Save"), tr("Save Models and Settings file")); - trAct(saveAsAct, tr("Save As..."), tr("Save Models and Settings file")); - trAct(closeAct, tr("Close"), tr("Close Models and Settings file")); - trAct(exitAct, tr("Exit"), tr("Exit the application")); - trAct(aboutAct, tr("About Companion..."), tr("Show the application's About box")); + trAct(newAct, tr("New"), tr("Create a new Models and Settings file")); + trAct(openAct, tr("Open..."), tr("Open an existing Models and Settings file")); + trAct(saveAct, tr("Save"), tr("Save to Models and Settings file")); + trAct(saveAsAct, tr("Save As..."), tr("Save Models and Settings to another file name")); + trAct(closeAct, tr("Close"), tr("Close Models and Settings file")); + trAct(recentFilesAct, tr("Recent Files"), tr("List of recently used files")); + trAct(writeSettingsSDPathAct, tr("Write Models and Settings to SD Path"), tr("Write Models and Settings to SD Path")); + trAct(readSettingsSDPathAct, tr("Read Models and Settings from SD Path"), tr("Read Models and Settings from SD Path")); + trAct(exitAct, tr("Exit"), tr("Exit the application")); - trAct(recentFilesAct, tr("Recent Files"), tr("List of recently used files")); - trAct(profilesMenuAct, tr("Radio Profiles"), tr("Create or Select Radio Profiles")); - trAct(logsAct, tr("View Log File..."), tr("Open and view log file")); - trAct(appPrefsAct, tr("Settings..."), tr("Edit Settings")); - trAct(downloadsAct, tr("Download components..."), tr("Download EdgeTX components and supporting resources")); - trAct(manualChkForUpdAct, tr("Check for updates..."), tr("Check for updates to EdgeTX and supporting resources")); - trAct(changelogAct, tr("Release notes..."), tr("Show release notes")); - trAct(compareAct, tr("Compare Models..."), tr("Compare models")); - trAct(editSplashAct, tr("Edit Radio Splash Image..."), tr("Edit the splash image of your Radio")); - trAct(readFlashAct, tr("Read Firmware from Radio"), tr("Read firmware from Radio")); - trAct(writeFlashAct, tr("Write Firmware to Radio"), tr("Write firmware to Radio")); - trAct(sdsyncAct, tr("Synchronize SD"), tr("SD card synchronization")); + trAct(editAppSettingsAct, tr("Edit Settings..."), tr("Edit %1 and Simulator settings (including radio profiles) settings").arg(CPN_STR_APP_NAME)); + trAct(exportAppSettingsAct, tr("Export Settings..."), tr("Save all the current %1 and Simulator settings (including radio profiles) to a file.").arg(CPN_STR_APP_NAME)); + trAct(importAppSettingsAct, tr("Import Settings..."), tr("Load %1 and Simulator settings from a prevously exported settings file.").arg(CPN_STR_APP_NAME)); - //trAct(openDocURLAct, tr("Manuals and other Documents"), tr("Open the EdgeTX document page in a web browser")); - trAct(writeSettingsAct, tr("Write Models and Settings To Radio"), tr("Write Models and Settings to Radio")); - trAct(readSettingsAct, tr("Read Models and Settings From Radio"), tr("Read Models and Settings from Radio")); - trAct(burnConfigAct, tr("Configure Communications..."), tr("Configure software for communicating with the Radio")); + trAct(burnConfigAct, tr("Configure Radio Communications..."), tr("Configure Companion for communicating with the Radio")); + trAct(editSplashAct, tr("Edit Radio Splash Image..."), tr("Edit the splash image of your Radio")); + trAct(readFlashAct, tr("Read Firmware from Radio"), tr("Read firmware from Radio")); + trAct(writeFlashAct, tr("Write Firmware to Radio"), tr("Write firmware to Radio")); + trAct(writeSettingsAct, tr("Write Models and Settings to Radio"), tr("Write Models and Settings to Radio")); + trAct(readSettingsAct, tr("Read Models and Settings from Radio"), tr("Read Models and Settings from Radio")); trAct(writeBUToRadioAct, tr("Write Backup to Radio"), tr("Write Backup from file to Radio")); trAct(readBUToFileAct, tr("Backup Radio to File"), tr("Save a complete backup file of all settings and model data in the Radio")); + trAct(compareAct, tr("Compare Models"), tr("Compare models")); + trAct(updatesAct, tr("Update components..."), tr("Download and update EdgeTX components and supporting resources")); + trAct(sdsyncAct, tr("Synchronize SD card..."), tr("SD card synchronization")); + trAct(logsAct, tr("View Log File..."), tr("Open and view log file")); + + trAct(profilesMenuAct, tr("Radio Profiles"), tr("Create or Select Radio Profiles")); trAct(createProfileAct, tr("Add Radio Profile"), tr("Create a new Radio Settings Profile")); trAct(copyProfileAct, tr("Copy Current Radio Profile"), tr("Duplicate current Radio Settings Profile")); trAct(deleteProfileAct, tr("Delete Current Radio Profile..."), tr("Delete the current Radio Settings Profile")); - trAct(exportSettingsAct, tr("Export Application Settings.."), tr("Save all the current %1 and Simulator settings (including radio profiles) to a file.").arg(CPN_STR_APP_NAME)); - trAct(importSettingsAct, tr("Import Application Settings.."), tr("Load %1 and Simulator settings from a prevously exported settings file.").arg(CPN_STR_APP_NAME)); + trAct(viewFileToolbarAct, tr("File Toolbar"), tr("Configure File toolbar visibility")); + trAct(viewModelsToolbarAct, tr("Models Toolbar"), tr("Configure Models toolbar visibility")); + trAct(viewRadioToolbarAct, tr("Radio Toolbar"), tr("Configure Radio toolbar visibility")); + trAct(viewSettingsToolbarAct, tr("Settings Toolbar"), tr("Configure Settings toolbar visibility")); + trAct(viewToolsToolbarAct, tr("Tools Toolbar"), tr("Configure Tools toolbar visibility")); - trAct(actTabbedWindows, tr("Tabbed Windows"), tr("Use tabs to arrange open windows.")); - trAct(actTileWindows, tr("Tile Windows"), tr("Arrange open windows across all the available space.")); - trAct(actCascadeWindows, tr("Cascade Windows"), tr("Arrange all open windows in a stack.")); - trAct(actCloseAllWindows, tr("Close All Windows"), tr("Closes all open files (prompts to save if necessary.")); + trAct(tabbedWindowsAct, tr("Tabbed Windows"), tr("Use tabs to arrange open windows.")); + trAct(tileWindowsAct, tr("Tile Windows"), tr("Arrange open windows across all the available space.")); + trAct(cascadeWindowsAct, tr("Cascade Windows"), tr("Arrange all open windows in a stack.")); + trAct(closeAllWindowsAct, tr("Close All Windows"), tr("Closes all open files (prompts to save if necessary.")); + + trAct(manualChkForUpdAct, tr("Check for updates..."), tr("Check for updates to EdgeTX and supporting resources")); + trAct(changelogAct, tr("Release notes..."), tr("Show release notes")); + trAct(aboutAct, tr("About"), tr("Show the application's About box")); - editMenu->setTitle(tr("Edit")); fileMenu->setTitle(tr("File")); + viewMenu->setTitle(tr("View")); + modelsMenu->setTitle(tr("Models")); settingsMenu->setTitle(tr("Settings")); themeMenu->setTitle(tr("Set Icon Theme")); iconThemeSizeMenu->setTitle(tr("Set Icon Size")); - burnMenu->setTitle(tr("Read/Write")); + radioMenu->setTitle(tr("Radio")); + toolsMenu->setTitle(tr("Tools")); windowMenu->setTitle(tr("Window")); helpMenu->setTitle(tr("Help")); fileToolBar->setWindowTitle(tr("File")); - editToolBar->setWindowTitle(tr("Edit")); - burnToolBar->setWindowTitle(tr("Write")); - helpToolBar->setWindowTitle(tr("Help")); + modelsToolBar->setWindowTitle(tr("Models")); + radioToolBar->setWindowTitle(tr("Radio")); + settingsToolBar->setWindowTitle(tr("Settings")); + toolsToolBar->setWindowTitle(tr("Tools")); showReadyStatus(); @@ -863,60 +882,71 @@ void MainWindow::retranslateUi(bool showMsg) void MainWindow::createActions() { - newAct = addAct("new.png", SLOT(newFile()), QKeySequence::New); - openAct = addAct("open.png", SLOT(openFile()), QKeySequence::Open); - saveAct = addAct("save.png", SLOT(save()), QKeySequence::Save); - saveAsAct = addAct("saveas.png", SLOT(saveAs()), tr("Ctrl+Shift+S")); // Windows doesn't have "native" save-as key, Lin/OSX both use this one anyway - closeAct = addAct("clear.png", SLOT(closeFile()) /*, QKeySequence::Close*/); // setting/showing this shortcut interferes with the system one (Ctrl+W/Ctrl-F4) - exitAct = addAct("exit.png", SLOT(closeAllWindows()), QKeySequence::Quit, qApp); + newAct = addAct("new.png", SLOT(newFile()), QKeySequence::New); + openAct = addAct("open.png", SLOT(openFile()), QKeySequence::Open); + saveAct = addAct("save.png", SLOT(save()), QKeySequence::Save); + saveAsAct = addAct("saveas.png", SLOT(saveAs()), tr("Ctrl+Shift+S")); // Windows doesn't have "native" save-as key, Lin/OSX both use this one anyway + // assigned menus in createMenus() + recentFilesAct = addAct("recentdocument.png"); + closeAct = addAct("clear.png", SLOT(closeFile()) /*, QKeySequence::Close*/); // setting/showing this shortcut interferes with the system one (Ctrl+W/Ctrl-F4) + // TODO change to more appropriate icon sets and uncomment toolbar actions + writeSettingsSDPathAct = addAct("folder-tree-write.png", SLOT(writeSettingsSDPath())); + readSettingsSDPathAct = addAct("folder-tree-read.png", SLOT(readSettingsSDPath())); + // end TODO + exitAct = addAct("exit.png", SLOT(closeAllWindows()), QKeySequence::Quit, qApp); - logsAct = addAct("logs.png", SLOT(logFile()), tr("Ctrl+Alt+L")); - appPrefsAct = addAct("apppreferences.png", SLOT(appPrefs()), QKeySequence::Preferences); - downloadsAct = addAct("download.png", SLOT(downloads()), tr("Ctrl+Alt+D")); - compareAct = addAct("compare.png", SLOT(compare()), tr("Ctrl+Alt+R")); - sdsyncAct = addAct("sdsync.png", SLOT(sdsync())); + editAppSettingsAct = addAct("apppreferences.png", SLOT(editAppSettings()), QKeySequence::Preferences); + exportAppSettingsAct = addAct("saveas.png", SLOT(exportAppSettings())); + importAppSettingsAct = addAct("open.png", SLOT(importAppSettings())); + burnConfigAct = addAct("configure.png", SLOT(burnConfig())); - editSplashAct = addAct("paintbrush.png", SLOT(customizeSplash())); - burnListAct = addAct("list.png", SLOT(burnList())); - readFlashAct = addAct("read_flash.png", SLOT(readFlash())); - writeFlashAct = addAct("write_flash.png", SLOT(writeFlash())); - writeSettingsAct = addAct("write_eeprom.png", SLOT(writeSettings())); - readSettingsAct = addAct("read_eeprom.png", SLOT(readSettings())); - burnConfigAct = addAct("configure.png", SLOT(burnConfig())); + compareAct = addAct("compare.png", SLOT(compare()), tr("Ctrl+Alt+R")); + updatesAct = addAct("download.png", SLOT(updates()), tr("Ctrl+Alt+D")); + editSplashAct = addAct("paintbrush.png", SLOT(customizeSplash())); + // assigned menus in createMenus() + profilesMenuAct = addAct("profiles.png"); + createProfileAct = addAct("new.png", SLOT(createProfile())); + copyProfileAct = addAct("copy.png", SLOT(copyProfile())); + deleteProfileAct = addAct("clear.png", SLOT(deleteCurrentProfile())); + sdsyncAct = addAct("sdsync.png", SLOT(sdsync())); + logsAct = addAct("logs.png", SLOT(logFile()), tr("Ctrl+Alt+L")); - writeBUToRadioAct = addAct("write_eeprom_file.png", SLOT(writeBackup())); - readBUToFileAct = addAct("read_eeprom_file.png", SLOT(readBackup())); + burnListAct = addAct("list.png", SLOT(burnList())); + readFlashAct = addAct("read_flash.png", SLOT(readFlash())); + writeFlashAct = addAct("write_flash.png", SLOT(writeFlash())); + writeSettingsAct = addAct("write_eeprom.png", SLOT(writeSettings())); + readSettingsAct = addAct("read_eeprom.png", SLOT(readSettings())); + writeBUToRadioAct = addAct("write_eeprom_file.png", SLOT(writeBackup())); + readBUToFileAct = addAct("read_eeprom_file.png", SLOT(readBackup())); - createProfileAct = addAct("new.png", SLOT(createProfile())); - copyProfileAct = addAct("copy.png", SLOT(copyProfile())); - deleteProfileAct = addAct("clear.png", SLOT(deleteCurrentProfile())); + viewFileToolbarAct = addAct("", SLOT(viewFileToolbar())); + viewModelsToolbarAct = addAct("", SLOT(viewModelsToolbar())); + viewRadioToolbarAct = addAct("", SLOT(viewRadioToolbar())); + viewSettingsToolbarAct = addAct("", SLOT(viewSettingsToolbar())); + viewToolsToolbarAct = addAct("", SLOT(viewToolsToolbar())); - exportSettingsAct = addAct("saveas.png", SLOT(exportSettings())); - importSettingsAct = addAct("open.png", SLOT(importSettings())); + tabbedWindowsAct = addAct("", SLOT(setTabbedWindows(bool)), 0, this, SIGNAL(triggered(bool))); + tileWindowsAct = addAct("", SLOT(tileSubWindows()), 0, mdiArea); + cascadeWindowsAct = addAct("", SLOT(cascadeSubWindows()), 0, mdiArea); + closeAllWindowsAct = addAct("", SLOT(closeAllSubWindows()), 0, mdiArea); - actTabbedWindows = addAct("", SLOT(setTabbedWindows(bool)), 0, this, SIGNAL(triggered(bool))); - actTileWindows = addAct("", SLOT(tileSubWindows()), 0, mdiArea); - actCascadeWindows = addAct("", SLOT(cascadeSubWindows()), 0, mdiArea); - actCloseAllWindows = addAct("", SLOT(closeAllSubWindows()), 0, mdiArea); - - manualChkForUpdAct = addAct("update.png", SLOT(manualCheckForUpdates())); - aboutAct = addAct("information.png", SLOT(about())); - //openDocURLAct = addAct("changelog.png", SLOT(openDocURL())); - changelogAct = addAct("changelog.png", SLOT(changelog())); - - // these two get assigned menus in createMenus() - recentFilesAct = addAct("recentdocument.png"); - profilesMenuAct = addAct("profiles.png"); + manualChkForUpdAct = addAct("update.png", SLOT(manualCheckForUpdates())); + changelogAct = addAct("changelog.png", SLOT(changelog())); + aboutAct = addAct("information.png", SLOT(about())); exitAct->setMenuRole(QAction::QuitRole); aboutAct->setMenuRole(QAction::AboutRole); - appPrefsAct->setMenuRole(QAction::PreferencesRole); - //openDocURLAct->setMenuRole(QAction::ApplicationSpecificRole); - //manualChkForUpdAct->setMenuRole(QAction::ApplicationSpecificRole); + editAppSettingsAct->setMenuRole(QAction::PreferencesRole); changelogAct->setMenuRole(QAction::ApplicationSpecificRole); - actTabbedWindows->setCheckable(true); compareAct->setEnabled(false); + + setActCheckability(tabbedWindowsAct, false); + setActCheckability(viewFileToolbarAct, g.fileToolbarVisible()); + setActCheckability(viewModelsToolbarAct, g.modelsToolbarVisible()); + setActCheckability(viewRadioToolbarAct, g.radioToolbarVisible()); + setActCheckability(viewSettingsToolbarAct, g.settingsToolbarVisible()); + setActCheckability(viewToolsToolbarAct, g.toolsToolbarVisible()); } void MainWindow::createMenus() @@ -929,19 +959,23 @@ void MainWindow::createMenus() fileMenu->addAction(closeAct); fileMenu->addAction(recentFilesAct); fileMenu->addSeparator(); - fileMenu->addAction(logsAct); - fileMenu->addAction(downloadsAct); - fileMenu->addAction(compareAct); - fileMenu->addAction(sdsyncAct); + fileMenu->addAction(readSettingsSDPathAct); + fileMenu->addAction(writeSettingsSDPathAct); fileMenu->addSeparator(); fileMenu->addAction(exitAct); - editMenu = menuBar()->addMenu(""); + viewMenu = menuBar()->addMenu(""); + viewMenu->addAction(viewFileToolbarAct); + viewMenu->addAction(viewModelsToolbarAct); + viewMenu->addAction(viewRadioToolbarAct); + viewMenu->addAction(viewSettingsToolbarAct); + viewMenu->addAction(viewToolsToolbarAct); + viewMenu->addSeparator(); + viewMenu->addMenu(createLanguageMenu(viewMenu)); - settingsMenu = menuBar()->addMenu(""); - settingsMenu->addMenu(createLanguageMenu(settingsMenu)); + modelsMenu = menuBar()->addMenu(""); - themeMenu = settingsMenu->addMenu(""); + themeMenu = viewMenu->addMenu(""); QActionGroup * themeGroup = new QActionGroup(themeMenu); addActToGroup(themeGroup, tr("Classical"), tr("The classic companion9x icon theme"), "themeId", 0, g.theme()); addActToGroup(themeGroup, tr("Yerico"), tr("Yellow round honey sweet icon theme"), "themeId", 1, g.theme()); @@ -951,7 +985,7 @@ void MainWindow::createMenus() connect(themeGroup, &QActionGroup::triggered, this, &MainWindow::onThemeChanged); themeMenu->addActions(themeGroup->actions()); - iconThemeSizeMenu = settingsMenu->addMenu(""); + iconThemeSizeMenu = viewMenu->addMenu(""); QActionGroup * szGroup = new QActionGroup(iconThemeSizeMenu); addActToGroup(szGroup, tr("Small"), tr("Use small toolbar icons"), "sizeId", 0, g.iconSize()); addActToGroup(szGroup, tr("Normal"), tr("Use normal size toolbar icons"), "sizeId", 1, g.iconSize()); @@ -960,41 +994,42 @@ void MainWindow::createMenus() connect(szGroup, &QActionGroup::triggered, this, &MainWindow::onIconSizeChanged); iconThemeSizeMenu->addActions(szGroup->actions()); - settingsMenu->addSeparator(); - settingsMenu->addAction(appPrefsAct); - settingsMenu->addAction(profilesMenuAct); - settingsMenu->addAction(editSplashAct); - settingsMenu->addAction(burnConfigAct); - settingsMenu->addSeparator(); - settingsMenu->addAction(exportSettingsAct); - settingsMenu->addAction(importSettingsAct); + radioMenu = menuBar()->addMenu(""); + radioMenu->addAction(writeSettingsAct); + radioMenu->addAction(readSettingsAct); + radioMenu->addSeparator(); + radioMenu->addAction(writeBUToRadioAct); + radioMenu->addAction(readBUToFileAct); + radioMenu->addSeparator(); + radioMenu->addAction(writeFlashAct); + radioMenu->addAction(readFlashAct); + radioMenu->addSeparator(); + radioMenu->addAction(burnConfigAct); + radioMenu->addAction(editSplashAct); - burnMenu = menuBar()->addMenu(""); - burnMenu->addAction(writeSettingsAct); - burnMenu->addAction(readSettingsAct); - burnMenu->addSeparator(); - burnMenu->addAction(writeBUToRadioAct); - burnMenu->addAction(readBUToFileAct); - burnMenu->addSeparator(); - burnMenu->addAction(writeFlashAct); - burnMenu->addAction(readFlashAct); - burnMenu->addSeparator(); - burnMenu->addSeparator(); + settingsMenu = menuBar()->addMenu(""); + settingsMenu->addAction(editAppSettingsAct); + settingsMenu->addAction(exportAppSettingsAct); + settingsMenu->addAction(importAppSettingsAct); + settingsMenu->addSeparator(); + settingsMenu->addAction(profilesMenuAct); + + toolsMenu = menuBar()->addMenu(""); + toolsMenu->addAction(updatesAct); + toolsMenu->addAction(sdsyncAct); + toolsMenu->addAction(logsAct); + toolsMenu->addSeparator(); windowMenu = menuBar()->addMenu(""); - windowMenu->addAction(actTabbedWindows); - windowMenu->addAction(actTileWindows); - windowMenu->addAction(actCascadeWindows); - windowMenu->addAction(actCloseAllWindows); + windowMenu->addAction(tabbedWindowsAct); + windowMenu->addAction(tileWindowsAct); + windowMenu->addAction(cascadeWindowsAct); + windowMenu->addAction(closeAllWindowsAct); windowMenu->addSeparator(); helpMenu = menuBar()->addMenu(""); helpMenu->addAction(manualChkForUpdAct); - //helpMenu->addSeparator(); - //helpMenu->addAction(openDocURLAct); - //helpMenu->addSeparator(); helpMenu->addAction(changelogAct); - //helpMenu->addSeparator(); helpMenu->addAction(aboutAct); recentFilesMenu = new QMenu(this); @@ -1008,7 +1043,7 @@ void MainWindow::createMenus() profilesMenu = new QMenu(this); QActionGroup *profilesGroup = new QActionGroup(this); - for (int i=0; i < MAX_PROFILES; i++) { + for (int i = 0; i < MAX_PROFILES; i++) { profileActs.append(profilesMenu->addAction("")); profileActs[i]->setVisible(false); profileActs[i]->setCheckable(true); @@ -1032,46 +1067,81 @@ void MainWindow::createToolBars() fileToolBar->addAction(saveAct); fileToolBar->addAction(closeAct); fileToolBar->addSeparator(); - fileToolBar->addAction(logsAct); - fileToolBar->addAction(downloadsAct); - fileToolBar->addSeparator(); - fileToolBar->addAction(appPrefsAct); - fileToolBar->addAction(profilesMenuAct); - fileToolBar->addAction(editSplashAct); - fileToolBar->addAction(editSplashAct); - fileToolBar->addSeparator(); - fileToolBar->addAction(compareAct); - fileToolBar->addAction(sdsyncAct); + fileToolBar->addAction(readSettingsSDPathAct); + fileToolBar->addAction(writeSettingsSDPathAct); // workaround for default split button appearance of action with menu :-/ QToolButton * btn; if ((btn = qobject_cast(fileToolBar->widgetForAction(recentFilesAct)))) btn->setPopupMode(QToolButton::InstantPopup); - if ((btn = qobject_cast(fileToolBar->widgetForAction(profilesMenuAct)))) - btn->setPopupMode(QToolButton::InstantPopup); // gets populated later - editToolBar = addToolBar(""); - editToolBar->setObjectName("Edit"); + modelsToolBar = addToolBar(""); + modelsToolBar->setObjectName("Models"); - burnToolBar = new QToolBar(this); - addToolBar( Qt::LeftToolBarArea, burnToolBar ); - burnToolBar->setObjectName("Write"); - burnToolBar->addAction(writeSettingsAct); - burnToolBar->addAction(readSettingsAct); - burnToolBar->addSeparator(); - burnToolBar->addAction(writeBUToRadioAct); - burnToolBar->addAction(readBUToFileAct); - burnToolBar->addSeparator(); - burnToolBar->addAction(writeFlashAct); - burnToolBar->addAction(readFlashAct); - burnToolBar->addSeparator(); - burnToolBar->addAction(burnConfigAct); + radioToolBar = new QToolBar(this); + addToolBar(Qt::LeftToolBarArea, radioToolBar); + radioToolBar->setObjectName("Radio"); + radioToolBar->addAction(writeSettingsAct); + radioToolBar->addAction(readSettingsAct); + radioToolBar->addSeparator(); + radioToolBar->addAction(writeBUToRadioAct); + radioToolBar->addAction(readBUToFileAct); + radioToolBar->addSeparator(); + radioToolBar->addAction(writeFlashAct); + radioToolBar->addAction(readFlashAct); + radioToolBar->addSeparator(); + radioToolBar->addAction(burnConfigAct); + + settingsToolBar = addToolBar(""); + settingsToolBar->setObjectName("Settings"); + settingsToolBar->addAction(editAppSettingsAct); + settingsToolBar->addAction(profilesMenuAct); + + if ((btn = qobject_cast(settingsToolBar->widgetForAction(profilesMenuAct)))) + btn->setPopupMode(QToolButton::InstantPopup); + + toolsToolBar = addToolBar(""); + toolsToolBar->setObjectName("Tools"); + toolsToolBar->addAction(updatesAct); + toolsToolBar->addAction(sdsyncAct); + toolsToolBar->addAction(logsAct); + + connect(fileToolBar, &QToolBar::visibilityChanged, [=](bool visible) + { + g.fileToolbarVisible(visible); + const QSignalBlocker blocker(viewFileToolbarAct); + viewFileToolbarAct->setChecked(g.fileToolbarVisible()); + }); + + connect(modelsToolBar, &QToolBar::visibilityChanged, [=](bool visible) + { + g.modelsToolbarVisible(visible); + const QSignalBlocker blocker(viewModelsToolbarAct); + viewModelsToolbarAct->setChecked(g.modelsToolbarVisible()); + }); + + connect(radioToolBar, &QToolBar::visibilityChanged, [=](bool visible) + { + g.radioToolbarVisible(visible); + const QSignalBlocker blocker(viewRadioToolbarAct); + viewRadioToolbarAct->setChecked(g.radioToolbarVisible()); + }); + + connect(settingsToolBar, &QToolBar::visibilityChanged, [=](bool visible) + { + g.settingsToolbarVisible(visible); + const QSignalBlocker blocker(viewSettingsToolbarAct); + viewSettingsToolbarAct->setChecked(g.settingsToolbarVisible()); + }); + + connect(toolsToolBar, &QToolBar::visibilityChanged, [=](bool visible) + { + g.toolsToolbarVisible(visible); + const QSignalBlocker blocker(viewToolsToolbarAct); + viewToolsToolbarAct->setChecked(g.toolsToolbarVisible()); + }); - helpToolBar = addToolBar(""); - helpToolBar->setObjectName("Help"); - helpToolBar->addAction(manualChkForUpdAct); - helpToolBar->addAction(aboutAct); } QMenu * MainWindow::createLanguageMenu(QWidget * parent) @@ -1262,7 +1332,7 @@ int MainWindow::newProfile(bool loadProfile) if (loadProfile) { if (loadProfileId(i)) - appPrefs(); + editAppSettings(); } return i; @@ -1281,7 +1351,7 @@ void MainWindow::copyProfile() g.profile[newId] = g.profile[g.id()]; g.profile[newId].name(g.profile[newId].name() + tr(" - Copy")); if (loadProfileId(newId)) - appPrefs(); + editAppSettings(); } } @@ -1316,12 +1386,12 @@ void MainWindow::deleteCurrentProfile() deleteProfile(g.id()); } -void MainWindow::exportSettings() +void MainWindow::exportAppSettings() { Helpers::exportAppSettings(); } -void MainWindow::importSettings() +void MainWindow::importAppSettings() { if (anyChildrenDirty()) { QMessageBox::warning(this, CPN_STR_APP_NAME, tr("Please save or close all modified files before importing settings")); @@ -1416,3 +1486,95 @@ void MainWindow::chooseProfile() g.warningId(g.warningId() | AppMessages::MSG_NO_RADIO_TYPE); } } + +void MainWindow::readSettingsSDPath() +{ + QString tempFile; + tempFile = generateProcessUniqueTempFileName("temp.etx"); + qDebug() << "Reading models and settings from SD path into temp file: " << tempFile; + + if (readSettingsFromSDPath(tempFile)) { + MdiChild * child = createMdiChild(); + child->newFile(false); + child->loadFile(tempFile, false); + child->show(); + qunlink(tempFile); + } +} + +bool MainWindow::readSettingsFromSDPath(const QString & filename) +{ + ProgressDialog progressDialog(this, tr("Read Models and Settings from SD path"), CompanionIcon("read_eeprom.png")); + bool result = ::readSettingsSDCard(filename, progressDialog.progress(), false); + if (!result) { + if (!progressDialog.isEmpty()) { + progressDialog.exec(); + } + } + else { + statusBar()->showMessage(tr("Models and Settings read"), 2000); + } + return result; +} + +void MainWindow::writeSettingsSDPath() +{ + StatusDialog *status = new StatusDialog(this, tr("Writing models and settings to SD path"), tr("In progress..."), 400); + + if (activeMdiChild()) + activeMdiChild()->writeSettings(status, false); + + delete status; +} + +bool MainWindow::isSDPathValid() +{ + bool ret = false; + const QString sdPath = g.currentProfile().sdPath(); + if (!sdPath.isEmpty()) { + if (QFile::exists(sdPath)) + ret = true; + } + return ret; +} + +void MainWindow::setActCheckability(QAction * act, bool checked) +{ + act->setCheckable(true); + act->setChecked(checked); +} + +void MainWindow::viewFileToolbar() +{ + g.fileToolbarVisible(viewFileToolbarAct->isChecked()); + const QSignalBlocker blocker(fileToolBar); + fileToolBar->setVisible(viewFileToolbarAct->isChecked()); +} + +void MainWindow::viewModelsToolbar() +{ + g.modelsToolbarVisible(viewModelsToolbarAct->isChecked()); + const QSignalBlocker blocker(modelsToolBar); + modelsToolBar->setVisible(viewModelsToolbarAct->isChecked()); +} + +void MainWindow::viewRadioToolbar() +{ + g.radioToolbarVisible(viewRadioToolbarAct->isChecked()); + const QSignalBlocker blocker(radioToolBar); + radioToolBar->setVisible(viewRadioToolbarAct->isChecked()); +} + +void MainWindow::viewSettingsToolbar() +{ + g.settingsToolbarVisible(viewSettingsToolbarAct->isChecked()); + const QSignalBlocker blocker(settingsToolBar); + settingsToolBar->setVisible(viewSettingsToolbarAct->isChecked()); +} + +void MainWindow::viewToolsToolbar() +{ + g.toolsToolbarVisible(viewToolsToolbarAct->isChecked()); + const QSignalBlocker blocker(toolsToolBar); + toolsToolBar->setVisible(viewToolsToolbarAct->isChecked()); +} diff --git a/companion/src/mainwindow.h b/companion/src/mainwindow.h index 6014fe759..f90b9ad03 100644 --- a/companion/src/mainwindow.h +++ b/companion/src/mainwindow.h @@ -101,23 +101,32 @@ class MainWindow : public QMainWindow void customizeSplash(); void about(); void compare(); - void appPrefs(); void updateMenus(); void createProfile(); void copyProfile(); void deleteProfile(const int pid); void deleteCurrentProfile(); - void exportSettings(); - void importSettings(); + void editAppSettings(); + void exportAppSettings(); + void importAppSettings(); void autoClose(); void chooseProfile(); void autoCheckForUpdates(); void manualCheckForUpdates(); - void downloads(); + void updates(); void doUpdates(bool check, bool interactive = true); void openFile(const QString & fileName); + void readSettingsSDPath(); + void writeSettingsSDPath(); + + void viewFileToolbar(); + void viewModelsToolbar(); + void viewRadioToolbar(); + void viewSettingsToolbar(); + void viewToolsToolbar(); + private: QAction * addAct(const QString & icon, const char * slot = NULL, const QKeySequence & shortcut = 0, QObject * slotObj = NULL, const char * signal = NULL); QAction * addActToGroup(QActionGroup * aGroup, const QString & sName, const QString & lName, const char * propName = 0, @@ -126,6 +135,8 @@ class MainWindow : public QMainWindow QMenu * createLanguageMenu(QWidget * parent = Q_NULLPTR); + void setActCheckability(QAction * act, bool checked); + void createActions(); void createMenus(); void createToolBars(); @@ -143,9 +154,12 @@ class MainWindow : public QMainWindow bool readSettingsFromRadio(const QString & filename); bool readFirmwareFromRadio(const QString & filename); + bool readSettingsFromSDPath(const QString & filename); bool checkProfileRadioExists(int profId); + bool isSDPathValid(); + QMdiArea *mdiArea; QString installer_fileName; @@ -155,21 +169,30 @@ class MainWindow : public QMainWindow QVector profileActs; QList fileWindowActions; + // top level menus QMenu *fileMenu; - QMenu *editMenu; + QMenu *modelsMenu; + QMenu *viewMenu; QMenu *settingsMenu; - QMenu *burnMenu; - QMenu *helpMenu; + QMenu *radioMenu; + QMenu *toolsMenu; QMenu *windowMenu; + QMenu *helpMenu; + + // sub menus QMenu *iconThemeSizeMenu; QMenu *themeMenu; QMenu *recentFilesMenu; QMenu *profilesMenu; + QActionGroup * windowsListActions; + QToolBar *fileToolBar; - QToolBar *editToolBar; - QToolBar *burnToolBar; - QToolBar *helpToolBar; + QToolBar *modelsToolBar; + QToolBar *radioToolBar; + QToolBar *settingsToolBar; + QToolBar *toolsToolBar; + QAction *newAct; QAction *openAct; QAction *saveAct; @@ -177,8 +200,8 @@ class MainWindow : public QMainWindow QAction *closeAct; QAction *recentFilesAct; QAction *exitAct; - QAction *appPrefsAct; - QAction *downloadsAct; + QAction *editAppSettingsAct; + QAction *updatesAct; QAction *manualChkForUpdAct; QAction *sdsyncAct; QAction *changelogAct; @@ -198,11 +221,17 @@ class MainWindow : public QMainWindow QAction *createProfileAct; QAction *copyProfileAct; QAction *deleteProfileAct; - QAction *exportSettingsAct; - QAction *importSettingsAct; - //QAction *openDocURLAct; - QAction *actTabbedWindows; - QAction *actTileWindows; - QAction *actCascadeWindows; - QAction *actCloseAllWindows; + QAction *exportAppSettingsAct; + QAction *importAppSettingsAct; + QAction *tabbedWindowsAct; + QAction *tileWindowsAct; + QAction *cascadeWindowsAct; + QAction *closeAllWindowsAct; + QAction *writeSettingsSDPathAct; + QAction *readSettingsSDPathAct; + QAction *viewFileToolbarAct; + QAction *viewModelsToolbarAct; + QAction *viewRadioToolbarAct; + QAction *viewSettingsToolbarAct; + QAction *viewToolsToolbarAct; }; diff --git a/companion/src/mdichild.cpp b/companion/src/mdichild.cpp index 2fe03a3d1..ab13be5d3 100644 --- a/companion/src/mdichild.cpp +++ b/companion/src/mdichild.cpp @@ -216,19 +216,12 @@ void MdiChild::setupNavigation() addAct(ACT_GEN_PST, "paste.png", SLOT(pasteGeneralSettings()), tr("Ctrl+Alt+V")); addAct(ACT_GEN_SIM, "simulate.png", SLOT(radioSimulate()), tr("Alt+Shift+S")); - addAct(ACT_ITM_EDT, "edit.png", SLOT(edit()), Qt::Key_Enter); - addAct(ACT_ITM_DEL, "clear.png", SLOT(confirmDelete()), QKeySequence::Delete); - + addAct(ACT_MDL_EDT, "edit.png", SLOT(edit()), Qt::Key_Enter); + addAct(ACT_MDL_DEL, "clear.png", SLOT(confirmDelete()), QKeySequence::Delete); addAct(ACT_MDL_ADD, "add.png", SLOT(modelAdd()), tr("Alt+A")); addAct(ACT_MDL_RTR, "open.png", SLOT(loadBackup()), tr("Alt+R")); addAct(ACT_MDL_WIZ, "wizard.png", SLOT(wizardEdit()), tr("Alt+W")); - addAct(ACT_LBL_ADD, "add.png", SLOT(labelAdd()), tr("Alt-L")); - addAct(ACT_LBL_DEL, "clear.png", SLOT(labelDelete()), tr("Alt-L")); - addAct(ACT_LBL_REN, "edit.png", SLOT(labelRename()), tr("Alt-R")); - addAct(ACT_LBL_MVU, "moveup.png", SLOT(labelMoveUp()), tr("Alt-+")); - addAct(ACT_LBL_MVD, "movedown.png", SLOT(labelMoveDown()), tr("Alt--")); - addAct(ACT_MDL_DFT, "currentmodel.png", SLOT(setDefault()), tr("Alt+U")); addAct(ACT_MDL_PRT, "print.png", SLOT(print()), QKeySequence::Print); addAct(ACT_MDL_SIM, "simulate.png", SLOT(modelSimulate()), tr("Alt+S")); @@ -244,6 +237,12 @@ void MdiChild::setupNavigation() QMenu * catsMenu = new QMenu(this); action[ACT_MDL_MOV]->setMenu(catsMenu); + addAct(ACT_LBL_ADD, "add.png", SLOT(labelAdd()), tr("Alt-L")); + addAct(ACT_LBL_DEL, "clear.png", SLOT(labelDelete()), tr("Alt-L")); + addAct(ACT_LBL_REN, "edit.png", SLOT(labelRename()), tr("Alt-R")); + addAct(ACT_LBL_MVU, "moveup.png", SLOT(labelMoveUp()), tr("Alt-+")); + addAct(ACT_LBL_MVD, "movedown.png", SLOT(labelMoveDown()), tr("Alt--")); + // set up the toolbars QToolButton * btn; @@ -352,6 +351,8 @@ void MdiChild::updateNavigation() } action[ACT_GEN_SRT]->setVisible(hasLabels); + action[ACT_MDL_DEL]->setEnabled(modelsSelected); + action[ACT_MDL_DEL]->setText(tr("Delete") % (modelsSelected ? sp % modelsRemvTxt : ns)); action[ACT_MDL_CUT]->setEnabled(modelsSelected); action[ACT_MDL_CUT]->setText(tr("Cut") % (modelsSelected ? sp % modelsRemvTxt : ns)); action[ACT_MDL_CPY]->setEnabled(modelsSelected); @@ -379,8 +380,8 @@ void MdiChild::retranslateUi() action[ACT_GEN_SIM]->setText(tr("Simulate Radio")); cboModelSortOrder->setToolTip(tr("Radio Models Order")); - action[ACT_ITM_EDT]->setText(tr("Edit Model")); - action[ACT_ITM_DEL]->setText(tr("Delete")); + action[ACT_MDL_EDT]->setText(tr("Edit Model")); + action[ACT_MDL_DEL]->setText(tr("Delete Model")); action[ACT_LBL_ADD]->setText(tr("Add")); action[ACT_LBL_DEL]->setText(tr("Delete")); @@ -408,6 +409,7 @@ QList MdiChild::getGeneralActions() { QList actGrp; actGrp.append(getAction(ACT_GEN_SIM)); + actGrp.append(actionsSeparator()); actGrp.append(getAction(ACT_GEN_EDT)); actGrp.append(getAction(ACT_GEN_CPY)); actGrp.append(getAction(ACT_GEN_PST)); @@ -418,27 +420,28 @@ QList MdiChild::getEditActions() { QList actGrp; actGrp.append(action[ACT_MDL_ADD]); - QAction * sep2 = new QAction(this); - sep2->setSeparator(true); - actGrp.append(sep2); - actGrp.append(getAction(ACT_ITM_EDT)); - actGrp.append(getAction(ACT_ITM_DEL)); + actGrp.append(actionsSeparator()); + actGrp.append(getAction(ACT_MDL_EDT)); + actGrp.append(getAction(ACT_MDL_DEL)); actGrp.append(getAction(ACT_MDL_CUT)); actGrp.append(getAction(ACT_MDL_CPY)); actGrp.append(getAction(ACT_MDL_PST)); actGrp.append(getAction(ACT_MDL_INS)); actGrp.append(getAction(ACT_MDL_DUP)); - actGrp.append(getAction(ACT_MDL_MOV)); actGrp.append(getAction(ACT_MDL_EXP)); + actGrp.append(getAction(ACT_MDL_MOV)); return actGrp; } QList MdiChild::getModelActions() { QList actGrp; - actGrp.append(getAction(ACT_MDL_RTR)); actGrp.append(getAction(ACT_MDL_WIZ)); actGrp.append(getAction(ACT_MDL_DFT)); + // TODO remove + // the function has been hobbled as expects eeprom binary backup so do not list + // can just open another etx so use case doubtful + //actGrp.append(getAction(ACT_MDL_RTR)); actGrp.append(getAction(ACT_MDL_PRT)); actGrp.append(getAction(ACT_MDL_SIM)); return actGrp; @@ -1481,12 +1484,12 @@ int MdiChild::askQuestion(const QString & msg, QMessageBox::StandardButtons butt return QMessageBox::question(this, CPN_STR_APP_NAME, msg, buttons, defaultButton); } -void MdiChild::writeSettings(StatusDialog * status) // write to Tx +void MdiChild::writeSettings(StatusDialog * status, bool toRadio) // write to Tx { if (g.confirmWriteModelsAndSettings()) { QMessageBox msgbox; - msgbox.setText(tr("You are about to overwrite ALL models on the Radio.")); - msgbox.setInformativeText(tr("Do you want to continue?")); + msgbox.setText(tr("You are about to overwrite ALL models.")); + msgbox.setInformativeText(tr("Continue?")); msgbox.setIcon(QMessageBox::Icon::Question); msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::Abort); msgbox.setDefaultButton(QMessageBox::Abort); @@ -1499,21 +1502,31 @@ void MdiChild::writeSettings(StatusDialog * status) // write to Tx return; } - QString radioPath = findMassstoragePath("RADIO", true); - qDebug() << "Searching for SD card, found" << radioPath; + QString radioPath; + + if (toRadio) { + radioPath = findMassstoragePath("RADIO", true); + qDebug() << "Searching for SD card, found" << radioPath; + } + else { + radioPath = g.currentProfile().sdPath(); + if (!QFile(radioPath % "/RADIO").exists()) + radioPath.clear(); + } + if (radioPath.isEmpty()) { qDebug() << "Radio SD card not found"; - QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Unable to find radio SD card!")); + QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Unable to find SD card!")); return; } if (saveFile(radioPath, false)) { status->hide(); - QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Models and settings written to radio")); + QMessageBox::information(this, CPN_STR_TTL_INFO, tr("Models and settings written")); } else { status->hide(); - QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error writing models and settings to radio!")); + QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Error writing models and settings!")); } } @@ -1834,3 +1847,10 @@ void MdiChild::setModelModified(const int modelIndex, bool cascade) setModified(); } } + +QAction * MdiChild::actionsSeparator() +{ + QAction * act = new QAction(this); + act->setSeparator(true); + return act; +} diff --git a/companion/src/mdichild.h b/companion/src/mdichild.h index fa3fbcd69..49f4cbc34 100644 --- a/companion/src/mdichild.h +++ b/companion/src/mdichild.h @@ -55,14 +55,9 @@ class MdiChild : public QWidget ACT_GEN_PST, ACT_GEN_SIM, ACT_GEN_SRT, // model sort order - ACT_ITM_EDT, - ACT_ITM_DEL, - ACT_LBL_ADD, - ACT_LBL_DEL, - ACT_LBL_MVU, // Move up - ACT_LBL_MVD, // Move down - ACT_LBL_REN, // Move down - ACT_MDL_ADD, // model actions... + ACT_MDL_EDT, // model actions... + ACT_MDL_DEL, + ACT_MDL_ADD, ACT_MDL_CPY, ACT_MDL_CUT, ACT_MDL_PST, @@ -75,6 +70,11 @@ class MdiChild : public QWidget ACT_MDL_DFT, // set as DeFaulT ACT_MDL_PRT, // print ACT_MDL_SIM, + ACT_LBL_ADD, // label actions.. + ACT_LBL_DEL, + ACT_LBL_MVU, // Move up + ACT_LBL_MVD, // Move down + ACT_LBL_REN, // Move down ACT_ENUM_END }; @@ -97,7 +97,7 @@ class MdiChild : public QWidget bool saveAs(bool isNew=false); bool saveFile(const QString & fileName, bool setCurrent=true); void closeFile(bool force = false); - void writeSettings(StatusDialog * status); + void writeSettings(StatusDialog * status, bool toRadio = true); void print(int model=-1, const QString & filename=""); void onFirmwareChanged(); @@ -231,6 +231,7 @@ class MdiChild : public QWidget AbstractStaticItemModel* modelSortOrderItemModel; QComboBox* cboModelSortOrder; void setModelModified(const int modelIndex, bool cascade = true); + QAction * actionsSeparator(); }; // This will draw the drop indicator across all columns of a model View (vs. in just one column), and lets us make the indicator more obvious. diff --git a/companion/src/radiointerface.cpp b/companion/src/radiointerface.cpp index 37265cf62..afe08f836 100644 --- a/companion/src/radiointerface.cpp +++ b/companion/src/radiointerface.cpp @@ -189,21 +189,25 @@ bool readSettings(const QString & filename, ProgressWidget * progress) return readSettingsEeprom(filename, progress); } -bool readSettingsSDCard(const QString & filename, ProgressWidget * progress) +bool readSettingsSDCard(const QString & filename, ProgressWidget * progress, bool fromRadio) { - QString radioPath = findMassstoragePath("RADIO", true, progress); - qDebug() << "Searching for SD card, found" << radioPath; - if (radioPath.isEmpty()) { - QMessageBox::critical(progress, CPN_STR_TTL_ERROR, - QCoreApplication::translate("RadioInterface", "Unable to find radio SD card!")); - return false; + QString radioPath; + + if (fromRadio) { + radioPath = findMassstoragePath("RADIO", true, progress); + qDebug() << "Searching for SD card, found" << radioPath; + } + else { + radioPath = g.currentProfile().sdPath(); + if (!QFile::exists(radioPath % "/RADIO")) + radioPath.clear(); } - // if radio.yml it is a converted radio - // if radio.bin unconverted pre 2.6 - // if neither then unconverted eeprom or empty - if (!QFile::exists(radioPath % "/RADIO/radio.yml") && !QFile::exists(radioPath % "/RADIO/radio.bin")) - return readSettingsEeprom(filename, progress); + if (radioPath.isEmpty()) { + QMessageBox::critical(progress, CPN_STR_TTL_ERROR, + QCoreApplication::translate("RadioInterface", "Unable to find SD card!")); + return false; + } RadioData radioData; Storage inputStorage(radioPath); diff --git a/companion/src/radiointerface.h b/companion/src/radiointerface.h index d97bcd983..4b930df9c 100644 --- a/companion/src/radiointerface.h +++ b/companion/src/radiointerface.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef _RADIOINTERFACE_H_ -#define _RADIOINTERFACE_H_ +#pragma once #include #include @@ -42,8 +41,6 @@ QStringList getWriteFirmwareArgs(const QString &filename); bool readFirmware(const QString &filename, ProgressWidget *progress); bool writeFirmware(const QString &filename, ProgressWidget *progress); bool readSettings(const QString &filename, ProgressWidget *progress); -bool readSettingsSDCard(const QString &filename, ProgressWidget *progress); +bool readSettingsSDCard(const QString &filename, ProgressWidget *progress, bool fromRadio = true); bool readSettingsEeprom(const QString &filename, ProgressWidget *progress); bool writeSettings(const QString &filename, ProgressWidget *progress); - -#endif // _RADIOINTERFACE_H_ diff --git a/companion/src/storage/appdata.h b/companion/src/storage/appdata.h index 1b57c77f0..119dd8169 100644 --- a/companion/src/storage/appdata.h +++ b/companion/src/storage/appdata.h @@ -835,6 +835,13 @@ class AppData: public CompStoreObj // Message box confirmations PROPERTY(bool, confirmWriteModelsAndSettings, true) + // Toolbars visibility + PROPERTY(bool, fileToolbarVisible, true) + PROPERTY(bool, modelsToolbarVisible, true) + PROPERTY(bool, radioToolbarVisible, true) + PROPERTY(bool, settingsToolbarVisible, true) + PROPERTY(bool, toolsToolbarVisible, true) + bool firstUse; QString upgradeFromVersion; diff --git a/companion/src/themes/classic/16/folder-tree-read.png b/companion/src/themes/classic/16/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..c6c4cecdcdbb106289e4df30ecc095d03d57e592 GIT binary patch literal 569 zcmV-90>=G`P)A4FCWD8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10mey0 zK~y-6rISBsQ&AYjfA^)vMrgE(T~rLw$;l9*E?xXnEwqjuDxyONBMA-;b?GDy(y@@C zvr`2@l1a4XHP{fUpw=R-ytdXPBu#k~QZ+5U_c=64)4XRCJn(V3hwmP~bI-j>MED=H z0Vt&|i^%IL*9DwwapoORuJ5W742cNUx>>1I#4rpgl}h4*3k|)y6Eq{4OcDqLNT<_y zz1}(>4u=T_gH8+0$ZeQ>`EFrb9@wz}@OU)JGpT2evbb5P{{nr z0=W&71$_?7-h1ZjdX`@EG!tXf_ZVZY)g3Tj*o3ASub%JYK#Lf)h8QpAx7EHFYv^?O zcWnS7^0bi~8hI4UuPi&7kJwHHR|`*~chGg+!QU9U@8Es|A4FCWD8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10oO@H zK~y-6rISBMTTv9ozx(oxMlc$wI%sJKSj31B5@@%Aii@q37Hm<34pj_9%%WMGq81!F z1-A|ky10lWt4ItsNN^Bi>A$pTqfaIJ42eQg%sURg#Ha5?gnn@0-j8#CoWpl7BO?5d zcmQCGbrR94?9~Hkz2nXnfK2fuchFBnkk>#qo26JRM#*H7G~`g!UUhI=fj|Ievl-!V z7<#?F=-cgfSS%Lx2)DI=EaJy`9#UQh{L2FXbUF^1_0atQJBKN-=Y1-FZ^ftb3V=Gs zSRVj5oz5phjzd-ULRDNV2gVqyd~CHge~U)93xFgMEy??`w-escqxdfsphlAL-ZlKn z{lW9;=a=sh07F_MRL_hIVr}E|4KuO#2VzAUEd$TSADA2XZC7+tIf7E$!=^^O=EM5#zy%4|Cq>ud|qb z$r!6q0yssCPlX)QjM1d{cSMvb0*GiqQOEatrbdO|S~04BuI31{u6GCqgDSt*Gp6z` Y0aCZm)bV1i1^@s607*qoM6N<$f*F_nEC2ui literal 0 HcmV?d00001 diff --git a/companion/src/themes/classic/24/folder-tree-read.png b/companion/src/themes/classic/24/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..307a0c3c08315306091b828064374c88f6741ba4 GIT binary patch literal 803 zcmV+;1Kj+HP)0cec_P#P})fX>cN91aHn>FMc|mzT%E z+ycOEw^LhN3qV_28&<1zgYWfvsjI8QU@&YCpePDYUw7b_6)^55B|US4Z}hmCoSY;h zBV&7jPxc|4r%KT!s;3ThedcVTSF=7QAds{NV_K%BpPY4!#l^)f0kR}XdJqZ{6B84v ztE*XXPp~QnBP)eq_Gce*Ao@cM2Mh@z>ciqB;BHsN4OZnqL}5@~W2~i~CrQ#HAw>A7*b6K~gO}XCDCOTP*>E=U zb-?$b?zv<7$L}(q&o>zD27W-AnVG?6vjJc>n@LMcTTfWQFkL4vF{cn0^eX{?H z-|ruXEqtP;rY4GuivehCY^0!|VBMQuo+Ck?LIee#mjm8kE#LZI1l&Et002ovPDHLkV1n1AY-Rue literal 0 HcmV?d00001 diff --git a/companion/src/themes/classic/24/folder-tree-write.png b/companion/src/themes/classic/24/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..0b61387dce0b3194558b847b1730509f055bf01c GIT binary patch literal 789 zcmV+w1M2*VP)QN-F!7cR>n3QVXdSn5zOiZJs+ zM1<}XqHYSk@FGDZih?dAMzkAg+-V_A3R0RMG3=A+fHU>aWP7Zdv zJq2eH0=L^ub8|BQeSLkjx3|afP$)!8OABVRd2<3y(|G!#pKwG2WgEM5^5VEMt>X9l z$<58(oZyw)!{-tkhV=D6^$fk?^r?{U{tX4uj4TvOo-W^>Uqmn%OiGY1gt)iZq^GBw z91aJ+)G6j7G2H=?=-P`agfK}dwbcTTl(Kb2p8+%t)m&#T5=|gjmJ1;=i;53*<{q#f z0ZLa3)~)bth#B7(T^{sLl9hFwx|{W9j#Zv$yVL0`=(_u8bdhf;Xsf%((C~9zp0>-t z{mwQHo;`f^R(rJ)1;S!MBqK-zWMxG;l@;Y{psK1kAGV5x{b?L+Jcq$#RJ__Z0A}U< zQpP0`gaHu<1aP@r02CG$VzF2N7@zRs4NQ`4D`rA|hsg5AIhouE0O;xIp{lA1fR2t1 z%F4=?*tM!!-VVQK^w}Vp^#x??-2uQ~=93pFib82=Deymwd_G?s_jo+?Uhc-;bYO?$Ml?-}dnd#4<9Y(a%BV1#&Blg?27aoOiK8N> z&*B79%Enbp0h}){)FnK@f|jH}ul5+DsE?hxT>CvkaYL>C04b&3qsY|Cw%(k7>=Z+A TXVl2w00000NkvXXu0mjf+?!+W literal 0 HcmV?d00001 diff --git a/companion/src/themes/classic/32/folder-tree-read.png b/companion/src/themes/classic/32/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..b97aaaf8316c931f94629e2d2948aa5e22e7aeb1 GIT binary patch literal 1055 zcmV+)1mOFLP)8>RKGq zQVK$gGAkR*{Sig$$2O$058Rv`#kx(gmOii8l){NDoW7hM+tHNdy4aP>fGj(eO0e$gY4 zDP93;a}@C9LjZv3>1mu!XKG$iQ9(gLL5^OxBC8^7ZEYnO3=#|mnVg)YySw|gHis+7Sjv2j(tu&|Kc-roEPM59qmCKFRrQ>dy6fWzUy;c%>A&1N%g zZEd>p>J~^QlYDvlEI$SoSbvW(BRe^}a+ihF+N4UV-O_5JDc4TQac{Zh&Z=&u1?Z%PP(DmDCSV8y^@;-#Eo;t18!i8%jIHZWF)m%Q&WS*Vp#&JX!x`M%TEE{useDAz`#uWuh=0a z9PPuA-HL~i4U!6I}#fSk6>(X+w z<1-ZZ-_HiiChA|_wPs%30)D?A^X77F4J{ctTm3!&&cA-Ax}kPwyWvJ5#M8^6{{H?V zkH>=&o!8xtbLoaYzzICG9GaMzFonZm77`1(1@!*$r39puA)qr2=NK9q+IsfGVI7e@$Q(K!GB002ovPDHLkV1o2p{JsDH literal 0 HcmV?d00001 diff --git a/companion/src/themes/classic/32/folder-tree-write.png b/companion/src/themes/classic/32/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..85810d684a0d56740e75a28fc9e601d73ae57864 GIT binary patch literal 1078 zcmV-61j+k}P)hp@4+5wF*a*XzaQa?#%2epAIEfey^g z%~4cTL~U(tY_Ge!oBI0tb@{BUEIKD@bUJZ5ooiUL*-UeD zvr=AV0mCpj`CUIhEk;O9Gi}ITyE;eE_50=uxZQ3tx9#Sh7n+p#frckGS3uWwq?STR zH`HDbA}N7ALWt9=A&0}UOV@S$<^p8_Lvh5c7Pug#e0v@4+~DBgz9T(n2rCM#H{^s6 z_gQnS$2<$3=cJT@^#nGIs38gIYF{m$5<+C<7v^`BKDKB7lK;BE-@7+>-_q%T#YsoJ=P@dNGWWyXk|8oH<3zU?U@Jh|2T)Fg> z5?}Z7K^!#|Y$>xn-8I}}N=;8=KDtOGB?^#|sKA{7M_X?E6P%fu;jN=hoWAf42R?og zb8eQ&!xCJ-yNGB}An^_;aVI`MLDy#=@_6U7lstGB0Sp3B?+PZY=^{R#s=y?$ePUvQ zk&%(uW@Tk1+1c5#b@?OZoILY2znr>AxG%k?fHB@ zIyySmuu@9)?kvM*-9~$LhcB;rmpR+9H3c9jbU_k_kmcoNOePbfqoV|aK>+M_J9fK$ z4QsVpX=`ia_4?PSaa6y*qkQK>sawrecN{Ox3u<9OG954sgHz|ub8$%nEoDPC;#=U_ zZ!Q3AHd`P(8#p9{*fI6Y`5vOic9QA9{QNxT`*%}RcSMOFcy;A8lv0iY4~sNW1;l1` z;?ppCbJI{pWPkj6wLqZ|qH6U^y}i9Tv$L~=0)PFd)6fl!0r#$k#>dAq{C+=?a70-^ z^&ekMKuYNY-uoBMIW#o%K>w$GgcYZuff}cL1_}xa@J^0ly8MHhKq$1i0ydkCcj}(v w$4h5#$O-`;d~{qbv6NEfIV+QohK+Ln4I%H_G*{t41ONa407*qoM6N<$f(9}A*8l(j literal 0 HcmV?d00001 diff --git a/companion/src/themes/classic/48/folder-tree-read.png b/companion/src/themes/classic/48/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..3e7cbcddde3ed5d1f28b8aaf3b7bbaa1c8199d64 GIT binary patch literal 1560 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 literal 0 HcmV?d00001 diff --git a/companion/src/themes/monoblue/16/folder-tree-read.png b/companion/src/themes/monoblue/16/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..fd4a1b479cf4fbbe734e576b19267f63302b47d1 GIT binary patch literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFvNcITwWnidMV_;}#VPNEq&<7~;px-&&!2zXwT$U4P>M0h z+uensgH_f8$l)yTh%5%uH6Y9=%K!EWkilN!>Fdh=l2KSlO|3`C;SEs8!qdeugyVX0 z0t1tqBcmFdfq+Phfy6-`M*&@imBol%>cmxuX4B8lk85GvC z2CaK|)f{MsYKdz^NlIc#s#S7PDv)9@GB7gLH89jQv9Zfmi~x#{!~9 z##-PXP>&=?PjG%(NqJ&XDnogBxn5>oc5!lIL8@MUQTpt6Hc~)E44$rjF6*2UngAfK Bbv6J1 literal 0 HcmV?d00001 diff --git a/companion/src/themes/monoblue/16/folder-tree-write.png b/companion/src/themes/monoblue/16/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..0fa6d2f48c9354bf93648426b7556323428abaab GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFvNcITwWnidMV_;}#VPNEq&<7~;px-&&!2zXwT$U4P>M0h z+uensgH_f8$l)yTh%5%uH6Y9=%K!EWkilN!>Fdh=l2KSlO|3`C;SEs8$kW9!gyVX0 z0t2I?qng24j${WH7DuKPJdTcx7R`+9QYuHAR&+@w1bOfXBqSNMF$gm#DzOHiZscYM z>Q*grjVMV;EJ?LWE=mPb3`Pbfc98G^vGBX`~&Kd v1nCLRPb(=;EJ|f4FE7{2%*!rLPAo{(%P&fw{mw=TsEEPS)z4*}Q$iB}3Z8Pz literal 0 HcmV?d00001 diff --git a/companion/src/themes/monoblue/24/folder-tree-read.png b/companion/src/themes/monoblue/24/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..5852ebb38d49699e0ed0001af14231369d22652e GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaP3?%1DUd;wl3dtTpz6=aiY77hwEes65fI9x9$j#HmF@)oKasm*D zCMGciE==e$6gkM9P%6q8ypTzNOGQHJ71u(U2tkn$zPVh92LyO{OI6# z$Ac^N0zcRpR^J!%FH5r20-C5=;u=wsl30>zm0Xkxq!^40j7)V640R1HLkumfjLof# z&9n^+tPBihyRQWL8A(HKeoAIqB|?Kmh>@X{iG`J+2}Hvtp6{GM4H|G8N-}d(i%Sx7 z3lMrBmH_RsfasC27WfC$BMH(IoS#-wo>-L1P+nfHmzkGcoSayYs+V7sKKq@G6i^X^ Mr>mdKI;Vst0D=T~;{X5v literal 0 HcmV?d00001 diff --git a/companion/src/themes/monoblue/24/folder-tree-write.png b/companion/src/themes/monoblue/24/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..711cdb5897dbead7ccd6e91cd266e86853f92a10 GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaP3?%1DUd;wl3dtTpz6=aiY77hwEes65fI9x9$l24yF@)oKasoq> zgPOoe39e-k&VqXw!q_=PwKx_!?70vS&hhj>*MbE_FG4t&+Y&NXC{HS53)5ho)*R@- zu>4>10egnGo?-{yguJW<8mC&~8c~vxSdwa$T$Bo=7>o>zOmz(mbqy^;3@xmT&8>{h zv<(cb3=C$wuLOD+NkeXaN@iLmLW4z!k)f4|nU#?RM8nfpt8{@HG~hOrWag$8mn7yE zAoM^i0onuABV#S_52!~Hq$fB(t)x7$D3zhSyj(9cFS|H7u^?41zbJk7I~ysWA_h-a KKbLh*2~7Zm6MT38 literal 0 HcmV?d00001 diff --git a/companion/src/themes/monoblue/32/folder-tree-read.png b/companion/src/themes/monoblue/32/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc3b30c9f0c43ef388857aea498ffcdaac86dc0 GIT binary patch literal 452 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZ&To$sR$z3=CCj3=9n|3=F@3LJcn% z7)lKo7+xhXFj&oCU=S~uvn$XBD8U)v6XN>+|9=LCv}eygRJ`JT1{7pW@^*J&=wOxg z0I4YOh%5%uKR}rA{K03bKn8n>r>`sfOGaTKHMJfkhc`f>C{Gv15Q)pBXHWAs81OI$ zG+*IOnE&L0wa3{>KA!f4Dj}~f2T#7@aCX^^i-o5d-W18S>bF|wmMG2aa(?i_TGT2* zjj^Utq+>Ow?&_{H^GgF6!y3ZtKXh^SKW9w~l+|9=LCv}eygRJ`JT1{7pW@^*J&=wOxg z0I4YOh%5%uKR}rA{K03bKn8n>r>`sfOGaTKHMJfkhc`f>2u~Ns5Q)pBXC3((6nIz; zTs^`6!M@-@U+3Q?>s5~CHak`&GUbS0uzYmS|Hy2Cq}{9TUio;wQ^9trheC`0&sLA3 z2iz>}%hg`2(dx=Q*Uc5ds`HgS%%{SFcN3r7rT?sJihy>gmbgZgq$HN4S|t~y0x1R~ z10z#i14CUy%Me2gD`RsjV>4|711kfA+3qWWL4c$oH$NpatrDTZBE-nh%EZjd&>W&+ zuI^oRpau=N4JDbmsl_FUxdjM45KDmeSU~j1SPT3E>X8KL3C>R|DNig)WhgH%*UQYy dE>2D?NY%?PN}v7CMhd8i!PC{xWt~$(698KliIe~U literal 0 HcmV?d00001 diff --git a/companion/src/themes/monoblue/48/folder-tree-read.png b/companion/src/themes/monoblue/48/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..ffa75386d240764dc0eac47869c30b9a057f003b GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDD3?#L31Vw<9Lb6AYF9SoB8UsT^3j@P1pisjL z28L3g!dD3l3|2E37{m+a>&pI;QCLV#tw+h>4N$1e)5S4FcUglCQy+t>Sv4EAPXHGaZh)AHBA8 z_R`fmt<;@g@f%%YGNoH&pI;QCLV#tw+h>4N$1m)5S4Frj_;KV_~*9knzu4% z9pF@~b?$ZDDYX;m0M!!Lh?11Vl2ohYqEsNoU}Ruqs%v1VYiJo_Xkle+Ze?tyZD3$! zU@+T#B`|!DH00)|WTsUjG+2Zf8Csc`Ss7SDG%)U1_5`Rw18ze}W^QV6Nn&mRLJ!0e zpgk54Ju=n;|A2ZVL3)Do(@M${i&7cN%ggmL^RkPR6AM!H@{7`Ezq647Dq`?-^>bP0 Hl+XkK1Co?h literal 0 HcmV?d00001 diff --git a/companion/src/themes/monochrome/16/folder-tree-read.png b/companion/src/themes/monochrome/16/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..db62ca731b811c0c81d8d1bcd26863a57cff0d9a GIT binary patch literal 436 zcmV;l0ZaagP)0}_-((pV@7c8V5OMr`~MlEzhB8d?{P$4iD>%!%AblRUtgzfP8C3BVR^H2>E)fU4TZev-YmpcM#yRn^C4 z2L~7?X>WZTPY-j@#d)(Y^?my2JL5ZSn~ZV|^WB85gZU&Yo%jVT;XclqEbu0tbp?K7 z5ic9=6uwl|5Z58e!OEH5V3KWIO!BRvm;N_G7q756ga33SfvQ^XX<%+N8g29? e9frYRaODrIMOpmM1BEaE000046(41kR}fyX?y}3s}#n@LP_Z}q(~DIkdVeU zcIgt>R1qTVf+z~v!ob2K3^8f&%Y&+r~ywD1{6 zSia)`iPebsT5yl>DKjr3;t-42ulPFxDytjC{{+2i4_CN~h|98|6bRg8=Fh)GL=UGC zQQrCiKHTS^jupc%)g3%Wo$)))^hbHFf5LxIcQ6?d%eD9u%;61|^cT2^k9C1Rc!=YI zo5yu#p5g^W#M_|`GP8wd8H|WCJdKFo1wHq_5$gDYogw`BSOS^(azq0Y?RNXssHFSQ cXf)Pu0R#_J@#-}XI{*Lx07*qoM6N<$g4B<>$^ZZW literal 0 HcmV?d00001 diff --git a/companion/src/themes/monochrome/24/folder-tree-read.png b/companion/src/themes/monochrome/24/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..04d42a07dfd34f8a50030cd342cf39ea9a0ec946 GIT binary patch literal 573 zcmV-D0>b@?P)g%ii;Be0Uo#&kIz0bYpxiV8b4TmsPj*p3FY{L>jRf=BLrJ|~BZ*nd!<7cZW zdWNeF-eKHq65mu+fWTa4zFlHQ43xt&5%H~J-GNpCE9urUbHCOCn6y|DR;ASd25|}t zn8kEvzF2R-75qRaHbul8Okf7zAv3?$FKVY24O=WH7jYi1@dj=k85<2ca@;0=Z>7Pflzl>MK7Mp?3-LqzOq36Pl=Dxe}_1mjh6%c-4n z@H8UkEByYo0zP7Ng_wm#Bg#UxA*$7CYx?Q8q^_bUo@~_S5wYhlf*mYNF}N5Q00000 LNkvXXu0mjfcS`rL literal 0 HcmV?d00001 diff --git a/companion/src/themes/monochrome/24/folder-tree-write.png b/companion/src/themes/monochrome/24/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..b19006030b4b5dcd2f9abadcd92c92e0a9d294ab GIT binary patch literal 568 zcmV-80>}M{P)SbQahu(euvFAmpzb3Q>SORXBokO*^Sy+H>4#&<~+h?MLO?Q03-T{i6CMce;ag(BW#e>yvn$WCUYL zCMxi;spd|Afh5~%+WM-$SxR}AWXSK5?7$ifVtF0VRHA48l%lDv=z3;2ThSdiozhB1oIP)hkYb<$kkqMcZRGdP78c#Cng>*h`;*qLOwrme2}52cjv zxRK;8wqPj^;9xg^m)L~Y@5C(QdbU`{{QReXUmO{{LD$$>v|ItNzZmg>0000n)d^a0yf#%&f-=m;ep|4}e#| zM_|_3&A8yK43s1tOz>@S?PmZp`yy!sI15yOJ-}w7ZMZLSgpA`jkCihnDOJZCD{>sq z5#8(3Pyu$hm$!^q0cJJ@Or-@%syP8|!N)E*DQO|a-?z~MuC)`~j(~f>lLGvAaS!EI tY9|ncVYue|zhPl?TtEcitP!j4}+E z2=&(k2U<84&+}{@B|y>zVAAy~z+K>A6t_~s;OBt};Hab?U>aBjrXm9hPWxV<2@JaH zYru1$CxTz`Jg=0wp9J0ky}(Z31EKX$x&SBQ98h!pexL!2MhS>q1CsUtW56pjdlthv z3G4v=0N;VHK;6uKo7r_qKim|5l5`9h$-D-D(|`e&6W+4!IANOyj%3VKdYcspw8eBvfUNo~e0FuTC%I>hUFzx`k1&m7C8si&q?ZVm( zGkYYd4;TjefX%=Va5ip$I01iMJM1h8tKkbXTOyc}8i1r~I|A0`{vL2UhI11bOc9rg zGy!vF_9T)Z{pxh^BmsFaBWXFozoi`kS;}t>yK`_e3&?`wIpbFf6<}ry>8y0LeISuk zmt@YCBsC=6khCGsbBb7mE5IVbhv^J(NYYi{3&E$j>3EA~_N_Izh$Gp!nQeChW`O+! zN3a*bdxEXF0bGd+PRl^Aq>jEmi@Bi$kfPYvuSnhh|?U4Wg002ovPDHLkV1j4hHKPCk literal 0 HcmV?d00001 diff --git a/companion/src/themes/monochrome/48/folder-tree-read.png b/companion/src/themes/monochrome/48/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..6f1a5e6b0c947dff05b488213a1c46db70753ee3 GIT binary patch literal 983 zcmV;|11S87P)fB$vMFG4U=2tmn62tv#Y1ydnWi=wY3sGAHyyV0u<5v3cE)Js3` zq7)IlRU@$SB5#5)f>OFDq%VY76%qVcMc3WG7jxET-+i4qv-{4B!T#aEne(3KKhOVt zo-^k>2iw%$fH#4zma%7n$*~+slI%>9#9cIl4}n9HvhRNZ_)5~`GDJ-YI0bwJe322+ z3oHXpN}3c))QAAv$AI;~$H148x@`XeybUZTjYO1)rXqmt!=xhC5+Y&yG$lneCLrJh z@GtN#Fb5!r*a@r#wiOX{SLt0IBuxXp1*QY5ZT}s{UjeoNKLERncp8a7aQ-wfpVaxE z!uV3)8{i!9y6sy1kkEc)Vo$c7)9=U~0?oJ>ZJ% zd!fH($oYU-z3tOK>aDy z4J-nVO4^g%iEUpl>--R5)#wAx0s>wFW`yz0K#!yo!0*8IHn#n?Pv()=Az-WReE^as z03QH*Nk5;@0iWjB-r&FW*A{i8(D|W`?SXKNSOWak3G%WL=#lhd#Ju^L{+-qzZC{YI z09XMm1ZK8O*#u09aVSQBGySzOq%FALmed{u&V)7$lGYI^ASQ(dV~BF#;whs?*%UfJ zCZ}`o3Gi}xcgiD1fHM8>Y=2#7Ag!V%0Wm40;wjCcj(y;uq_R6~?zcaSvMDqgEFPnM zE}E{$#*C^`Xd`J=HC7aU!YdJA`*Ib$?NEsTNmGF*Geb9Rx80G)imKMY5#U;;^-Hp( zi;|9q!o4G?dlAnjy+S!7X=5h{>(~bdNz284U|x73I&7$rm%>~Lee~H5-@%mjlgzES4-MF6+5vG0q<2wKAu94z!qRv2Y6b~Mk7#F zLGxD?yzTJ6PoZ%EO{2TFw|7I+PK*)@0hA<3rH8Gm@ce~)ctN<^+&f;VOq2olysL6T@hbz!V+AKn#0db3gxA$`!DDBT2# z2t^S=kOsOCT^Qwd7e%CmL?l=c%-=+eQnOrlpDt#s<1{;SX7@ic1^d8(^MB{O&pFSY z_k6sEm2J9)q$R)-+h6DG%WVHp11Xz}{KMcHH<=?3QNjC$Z z0fWGiz`h*MAYdi1 zFtfh^3`;r)d#SODAtJYVAb8~?1oLbMS=-(0TP zp0NEMa1U^-ALMmsU|7)lFrujDc$=+)D5BO;O-gvm!k7miJ79Q5E=ot^?|2y3vWb#?Vp?A zEkYv#B+Un|2~1~g7oNy7MN@0w9pFq*#wA(OPm&HuTHUXX+Fry-9EwJ&0*y j6@Zc?>Hhz1W`Mr{$%bFkEjBl)00000NkvXXu0mjfTOzmj literal 0 HcmV?d00001 diff --git a/companion/src/themes/monowhite/16/folder-tree-read.png b/companion/src/themes/monowhite/16/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..bb46e259fc360c95089cdb6824161261bfe81aae GIT binary patch literal 440 zcmV;p0Z0CcP)b9k0y7v}T%-O<|D9iHMQK4Pb; z&O(y${|X#KVS?cO@?z51yn@q79`xriw(%C1@C1i&FUhyR1aKIinsebD&R`Eed;V%w zN%C+g0DFC4OT5PSB+skrA~t##za0!SINyAaaRCcR@-oSz_VK?Q>?e8LXE4ESYz|z_ zu(e8{#iF-7(XH=C&u`$>su5a@bwPf`5o}^QEE+nPR@LQ3V2-1@xu<>iFS=|#37O9$p83C6wKE+hQqH$ng$VZ7fh=?Z<@uI4`5%DS_p5r0*F@x8o9&ymaVeK5Bu!>uSe1theq#B12 zu~F4uaGIGPB4Qm&Sk`7S;sEYf^DZ7>J|b?T!2t%791Jq^4Mao_TgCdLs;9xqIDr~h zIKw4=;I!I%KaD^ai};Cq_>E(nYcu%uFM-)A#4f&Jp%7+@U|*Zf_hEt5K2wb&EN14x z^+H5EE7$w`3Yqz~W|j~)u~NSBjY|`ru|{GIUx(HQ^}%C9%*-q7O*o(xXqsl{e@)}i c>2x0d0iecCbbbgvPyhe`07*qoM6N<$f*ByR*#H0l literal 0 HcmV?d00001 diff --git a/companion/src/themes/monowhite/24/folder-tree-read.png b/companion/src/themes/monowhite/24/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..3e7a66cf8d636e8c8d7c02e112891437f6bce6c2 GIT binary patch literal 625 zcmV-%0*?KOP)6j2n#e@C-MiAoX#K~Y2$B!mPkQtP50K~PXw5NvD|{SJbK_z@zAg?5RR zU}Cp6DQvU|X2s}$_%En2>MnaM=0zss%k0jG7lwJ zv$%msU>#Vq-OTxq0Ea@t_dp$}0XKmgK-2cUe7=~1qN;(7V3uLV#0)SyjmvX)_Nu$6^+cT1m0;hoQz;@sx z@HDIo6=3^z%r9v#X%Dcy2rOpy8bs8`2rTJJsBD7*(q@*j7=eHl+tVAIX@zZILekDi z+)%#+n^_GQ1|Ae(CV?+i3Fd*rJuqK^*HsCQk)GJC;r$c1Z@W_zREA)W?P*Elf#eNv zS<(vd30MobrtQ`Bpi;9)(jagm6m}kXWcv=#Bt7N3Nas^e1gwO^!)yXy|ya~XAwSfzgv*uEYEZkC{zm1#1h|M-E(=L2{f z3n<_>pz?t-$u(62<(nf4TJgvVkN?X8%`mNn^hO1>DgytR#_{00000 LNkvXXu0mjf7*7h4 literal 0 HcmV?d00001 diff --git a/companion/src/themes/monowhite/24/folder-tree-write.png b/companion/src/themes/monowhite/24/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..a14749b3914ef7af47cbd7e857571610230e3153 GIT binary patch literal 612 zcmV-q0-ODbP)I$)wSBqU5o{Q(9WNhb?~!T;c2z(itb(y^lfF_=Uo zL?S6g+(be&s)#l{hUdL+i2XQ+pZI~Vc#e%LMIbY8)riL znK{|&X+(@FDO!X&f{ci3l~=7eh#PedbwV9MU^+AJED{zE=Wrw6vnifr z=4?}`r&$yco0N%38FcqE^DZ9YX(b=*CV~&u&1}U2w&6`?KEtz!I2{qk(XXWMVY{I^ zf+5T*VYlM95^**KnfcdX)y7M(gdj7o*BxBWz)I+)$dn%6Ta!NcSf|iSk>{1?aXIW! yhTozWt?LM?dEYbE^yqhkzDA=l@xP2m#KAu!JG+(@gr|o90000Vibxu5tgICR+SrJqrJ{|XqQtCVNJKCR5i}q+ zijAF(AQqzAs$gjd2nq_i;~z*Qt4Y?~}sEbEyPFL4v^#-?8X#M;N6wQtLpr^0g^n2 zJMm9dy*c3h6wc!B)^t^q_WSWYj$scTz>{5zcLHFhs*WZ((eZv9zf{#*eNba~qlKBq zBA%+Mb6txM16a3`9MPowx+dj&@bZc+$-}Md{;GOqqyS0wVyUW5C)thH@HI|X)zT{8 zf!XW=Nc(vy$)KN4@QtS67NDvYFq`B-O*6Wwo&Qi(J=(R2p&6*Ew}-t?a!`}{{+Kz; z_4#zw(NKVDgU{l(j<|pE>9EPyqqS<_VpW}5ZEVx~VmsWKWZ#fEc5DS;EnU=fyJv^^ z{Iy*G`*15hS<5lWU7CU&8Nh$|PSg3;tGPkO%>tAr{VTeF-_fh~HnLuA_Bfu#6Mf^` z@d(~Ya^FTK+DZ-lR8?OkxfgfiOMHkIl02q41^?7sNZ@i+eLhM6Nha|$KEPqj;AB-@ zNwNd`G1Ss1jyS^zKg?O?U8 zv;fO1hN_y!EF_u6PR;$WQ(XX49Xnr9@GXAsa;U0BEGD_SVSuWd9TwEriaP<;tF5-; zWgJd&&k&zO+XhfozvA(&%&}R3>o~ARovhZbLB?#bbB}`0R-n3i3(5Ew*UYD07*qoM6N<$g5A=AIsgCw literal 0 HcmV?d00001 diff --git a/companion/src/themes/monowhite/32/folder-tree-write.png b/companion/src/themes/monowhite/32/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..76cea1acb87c267c5566d0ca7a03092e7aa62d4f GIT binary patch literal 794 zcmV+#1LgdQP)OlF7tVR-M|d(J)od(OG%+)-7g z@xvpyxqaV)rv_wZdc9sLyN5~!-rG_L*)uWP(;7522D`5!t%kmPAx z+b(*nV}4eXSU)3}!wSBxs!x*y`*9Oq#+$eWpLenDIzmU*KRf2PljX)gh^h&m8}Qf!*@8)dSy@REx4{reoRMo!&vPZ@t zkoMV2^5T&BZ*c|ALRI~VSCZU^=i36bjJvDq$zhw=&;wQV?nd)TZpG?=&H@(J$#m{~ z6oG1$Kfo_T^iJcGjTXNUjLLx@tLpIJV3O^4w*8!Ib72^^O+sK4PGd=PR5j*ez-cEAY zI15dZ1HGy`p5#tVtzW>0IGE%yO_+YQRwvF@)yJDj;CxrykN0tZ`~F5%{gq@ZZm@O? z4`6HpyM~nFt(uF+4xFs26F8CNMol?h(ln=KoU5w0lKjzSU=)GpT4P=K8#`M=psMXh^nx!n7tc;q)e@GH{4+Lzs_Jt4n)S6(Je0tNV$xE)f(MiA z-azJ#sS&8EpYX&aYg{aWRop%zPX;m9HJJ9&cquT`@AsFd^51YATyg?4{eJ(k literal 0 HcmV?d00001 diff --git a/companion/src/themes/monowhite/48/folder-tree-read.png b/companion/src/themes/monowhite/48/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..f87930d4f5a81177872c7e44abf560fca213ceaa GIT binary patch literal 1238 zcmV;{1S$K8P)$W1Iq@ffPSO`H&R0KgE8nqNfEtXhBVOaeURzzP|mRneV z#6pqeM@G3(tEL%kM5&ekNkJ+RrbvY{L$YSE+q$i~Pk)@dwqG-I#+^HZ&;ys5d(L~G z^FDLVdFOr4#Wt0^fDEt-m@usURiG)BCzs1D%Vx8G*HC$6fIES9NfQRO&j40Px;ci# zb}dj}4FUZ?7Wjl9qBd#o23mn9V?_W|T!8J9z$-vAuo>8t%*4~cJ-}+<2}!ra@Qq8$ z(L%7jL6Qg#Zvr*~^MN~nEx=k}i6m@y6ymCi007(Vl4b$d0^b5FZ7-6v5ZDXM1GY(O zwEcTNo@(p?03^-ezh%@6tduk!cpG>DXaQa<{;wgSt6=YdCT@0Rp3unV{j_`>$O7^0#ABs~TU#OwXGw-m9j1s)%zs~T^#lB83%we;TRp0ZC23?SvF! z573_c59|b-|K;%Atd$*;Nc|KX_a(t($$xIjwfv9_hX!j5il+p_$Y8;4Cx?b2+?H(k{oA5 zo+Ig2U{34+F{wmWCF*9HQNmGIEfP+QsGr$qs3&!YM6ru$H0)DXFT*z3` zB;dobIu?sc59{51gdP$SZF<4rgIA?ofzD`MVfeuNFZT~cufhtkZTnRK0W_vI2x$W(e z4goEaW&*zvju!u7WbV{v`^S9zX%{pC-XI*EoCK~0zLwOIWTST{HZuuJtacd10^nkx zIs$<6fdjU8B=4{=`x_zb`K%ekBIk@t|>M^sRFK&w4nsf2Ex)f4cpz4<^zj> z&yuLsLs&ioXtVukj62yVK z)<>cL1ymd3a=F~%YCCa;XarC;n;q@7&RK(h0eTDIzi0gU761SM07*qoM6N<$f{0`m A8UO$Q literal 0 HcmV?d00001 diff --git a/companion/src/themes/monowhite/48/folder-tree-write.png b/companion/src/themes/monowhite/48/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..86c96905f0ac76de65d3001a26e3c34a7f6de0bd GIT binary patch literal 1241 zcmV;~1Sb25P)|yqDr$@f4c~@{vW&0~iW)Q%%!CptlAa=p41!2PsfQwZ zkV#Wsz8fEHj?h4$Nk^DB)h6bkDKg@UKiU`T2Px`BJj+HVE61FcEp8%iJ= z|0eJWppy2Rfv17prR|l_Fapu|t-wdXHNe}keIf7+@Cq;;IGm)XAp|5f0iD3d!1cf$ z+ntgY0BeDlfX9HPwnvh5O*w&R{1)I-;5wk+_6A8e0qY3HKMpLi{cA0KjaY#u!qymx z@8hxk3gBnp!uUR#Mp<(X1}4Jxn55;vTfk0Wu_WRa5^x952XsqXVS6G;-;@&ousts6 zKA@N2Dwjx_u)R4R?uEdIz*b53Cy}U0K+>~>r3M(Z-Bm;W48lPy$1v~#sBsUZ*+R!{4@jDoLbiw_wg;;8y&-8H&?9L*f!s1e*zgykXBq~6 zN}4G5Ga%`1!pcnpz682#eMa!A=r;tfkc1}S2iqN!F)S_85OB%& z2ey|c2}?Q~=$VvN888*G(7BSboSloZD9@X~FfapnKI6E=c&ik-60m)M5GLe?ya>#S zetxo;0~|~e$b-Nr@D6Zw9dvyU3?>QGoq+8z;DvhYt%kZ2kkkUKs?aq8{0Mw*J26Dg zf;@t`>4YfqaLMyqY`+%RB&kQzdG(kquR}Z(BhQM6C6xChJ!1Qd$xJjA3C(=qPC{xp z2)t{1x1;=h2EF6-u4bcqJyMMfSJHK zWh#~fb4l<-d9OelA)(n5fA>pz4d|5A4!mglsO>_f!Lihsh^zz_q)cdvNz7T4RoHAF zi-oO~z;;Qc)wv=z+U`wbP!mTsAs0Rcwoej@yPW`%S_xYS;CA5hv__>S z;P978VyU|VQYAF;@*4w?l&U6LL>dAYOWK=3r+|I7AIf6L>7ph9+jFugoa%(8;s23M z7J0kT-+_54JXbk3rWMRPq1jJa&9mOfi@=PGd2lscKm!t*aYFfJO`Y_8m(-a@LNh`L zr>6w}c`x)ofkvZwXlUr+MjLUOXa`WCP;f2De>46BcFXj?ga~Wl00000NkvXXu0mjf DIBYc6 literal 0 HcmV?d00001 diff --git a/companion/src/themes/yerico/16/folder-tree-read.png b/companion/src/themes/yerico/16/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..5d5e602ea1e484c99e8924b992f84e2adff49bd1 GIT binary patch literal 812 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 DLbp>Z literal 0 HcmV?d00001 diff --git a/companion/src/themes/yerico/24/folder-tree-write.png b/companion/src/themes/yerico/24/folder-tree-write.png new file mode 100644 index 0000000000000000000000000000000000000000..dffadcb9913d393ec2026c18af4feacdb4f5f49c GIT binary patch literal 1240 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 TZV=@B00000NkvXXu0mjfv|UQ; literal 0 HcmV?d00001 diff --git a/companion/src/themes/yerico/48/folder-tree-read.png b/companion/src/themes/yerico/48/folder-tree-read.png new file mode 100644 index 0000000000000000000000000000000000000000..92e850066e2ae9e15bcdac6e7c6945a2a4ea5816 GIT binary patch literal 2652 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 RknaEh002ovPDHLkV1g!l8?yia literal 0 HcmV?d00001