diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index 5095921..c01a764 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -91,7 +91,6 @@ juce::RecentlyOpenedFilesList& LumatoneEditorState::getRecentFiles() const juce::Array& LumatoneEditorState::getColourPalettes() { - loadColourPalettesFromFile(); return *colourPalettes; } @@ -182,6 +181,12 @@ bool LumatoneEditorState::doSendChangesToDevice() const return LumatoneApplicationState::doSendChangesToDevice() && editorMode == EditorMode::ONLINE; } +void LumatoneEditorState::setEditMode(EditorMode editMode) +{ + editorMode = editMode; + state.setPropertyExcludingListener(this, LumatoneEditorProperty::EditorMode, (int)editorMode, nullptr); +} + juce::ValueTree LumatoneEditorState::loadStateProperties(juce::ValueTree stateIn) { juce::ValueTree newState = (stateIn.hasType(LumatoneEditorProperty::StateTree)) @@ -236,12 +241,12 @@ void LumatoneEditorState::handleStatePropertyChange(juce::ValueTree stateIn, con } } -void LumatoneEditorState::setColourPalettes(const juce::Array &palettesIn) +void LumatoneEditorStateController::setColourPalettes(const juce::Array &palettesIn) { *colourPalettes = palettesIn; } -void LumatoneEditorState::loadColourPalettesFromFile() +void LumatoneEditorStateController::loadColourPalettesFromFile() { auto directory = getUserPalettesDirectory(); auto foundPaletteFiles = directory.findChildFiles(juce::File::TypesOfFileToFind::findFiles, true, '*' + juce::String(PALETTEFILEEXTENSION)); @@ -258,14 +263,20 @@ void LumatoneEditorState::loadColourPalettesFromFile() setColourPalettes(newPalettes); } -void LumatoneEditorState::addPalette(const LumatoneEditorColourPalette &newPalette) +const juce::Array& LumatoneEditorStateController::getColourPalettes() +{ + loadColourPalettesFromFile(); + return LumatoneEditorState::getColourPalettes(); +} + +void LumatoneEditorStateController::addPalette(const LumatoneEditorColourPalette &newPalette) { colourPalettes->add(newPalette); // TODO state.setPropertyExcludingListener(this, LumatoneEditorProperty::ColourPalettes, "", nullptr); } -bool LumatoneEditorState::deletePaletteFile(juce::File pathToPalette) +bool LumatoneEditorStateController::deletePaletteFile(juce::File pathToPalette) { bool success = false; @@ -278,7 +289,7 @@ bool LumatoneEditorState::deletePaletteFile(juce::File pathToPalette) } // Open a SysEx mapping from the file specified in currentFile -bool LumatoneEditorState::resetToCurrentFile() +bool LumatoneEditorStateController::resetToCurrentFile() { if (getCurrentFile().getFullPathName().isEmpty()) { @@ -325,7 +336,7 @@ bool LumatoneEditorState::resetToCurrentFile() return false; } -bool LumatoneEditorState::setCurrentFile(File fileToOpen) +bool LumatoneEditorStateController::setCurrentFile(File fileToOpen) { currentFile = fileToOpen; state.setPropertyExcludingListener(this, LumatoneEditorProperty::CurrentFile, currentFile.getFullPathName(), nullptr); @@ -333,15 +344,48 @@ bool LumatoneEditorState::setCurrentFile(File fileToOpen) } // open a file from the "recent files" menu -bool LumatoneEditorState::openRecentFile(int recentFileIndex) +bool LumatoneEditorStateController::openRecentFile(int recentFileIndex) { jassert(recentFileIndex >= 0 && recentFileIndex < recentFiles->getNumFiles()); return setCurrentFile(recentFiles->getFile(recentFileIndex)); } +bool LumatoneEditorStateController::saveMappingToFile(juce::File fileToSave) +{ + juce::StringArray stringArray = getMappingData()->toStringArray(); + juce::String fileText = stringArray.joinIntoString("\n"); -void LumatoneEditorState::setEditMode(EditorMode editMode) + bool success = false; + + if (fileToSave.existsAsFile()) + success = fileToSave.replaceWithText(fileText, false, false); + + else if (fileToSave.create().ok) + { + success = fileToSave.appendText(fileText, false, false); + } + + if (success && getCurrentFile() != fileToSave) + { + // TODO skip certain updates? + setCurrentFile(fileToSave); + } + + return success; +} + +bool LumatoneEditorStateController::savePropertiesFile() const { - editorMode = editMode; - state.setPropertyExcludingListener(this, LumatoneEditorProperty::EditorMode, (int)editorMode, nullptr); + // TODO Save documents directories (Future: provide option to change them and save after changed by user) + //propertiesFile->setValue(LumatoneEditorProperty::UserDocumentsDirectory, getUserDocumentsDirectory().getFullPathName()); + //propertiesFile->setValue(LumatoneEditorProperty::UserMappingsDirectory, getUserMappingsDirectory().getFullPathName()); + //propertiesFile->setValue(LumatoneEditorProperty::UserPalettesDirectory, getUserPalettesDirectory().getFullPathName()); + + // Save recent files list + recentFiles->removeNonExistentFiles(); + jassert(propertiesFile != nullptr); + propertiesFile->setValue(LumatoneEditorProperty::RecentFiles, recentFiles->toString()); + + return propertiesFile->saveIfNeeded(); } + diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index 20778e7..003f717 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -21,8 +21,6 @@ class LumatoneEditorLookAndFeel; class LumatoneController; class LumatoneEditorColourPalette; -class TerpstraSysExApplication; - namespace LumatoneEditorProperty { static const juce::Identifier StateTree = juce::Identifier("LumatoneEditorState"); @@ -61,7 +59,7 @@ namespace LumatoneEditorProperty static const juce::Identifier IsomorphicMassAssign = juce::Identifier("IsomorphicMassAssign"); static const juce::Identifier LastSettingsPanel = juce::Identifier("LastSettingsPanel"); - + static const juce::Identifier LastColourWindowTab = juce::Identifier("LastColourWindowTab"); } enum class EditorMode @@ -72,13 +70,15 @@ enum class EditorMode static juce::Array GetLumatoneEditorProperties(); +class LumatoneEditorStateController; + class LumatoneEditorState : public LumatoneApplicationState { public: - - LumatoneEditorState(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager* undoManagerIn); LumatoneEditorState(juce::String name, const LumatoneEditorState& stateIn); - +protected: + LumatoneEditorState(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager* undoManagerIn); +public: ~LumatoneEditorState() override; const juce::String getApplicationName() const { return ProjectInfo::projectName; } @@ -93,14 +93,12 @@ class LumatoneEditorState : public LumatoneApplicationState LumatoneEditorLookAndFeel& getEditorLookAndFeel() { return *lookAndFeel; } - //const juce::Array& getColourPalettes() { return colourPalettes; } - const juce::Array& getColourPalettes(); + virtual const juce::Array& getColourPalettes(); const LumatoneEditorFontLibrary& getAppFonts() const { return *appFonts; } juce::String getProperty(juce::Identifier propertyId, juce::String fallbackValue=juce::String()) const; - // juce::PropertiesFile& getPropertiesFile() { return *propertiesFile; } juce::File getCurrentFile() const { return currentFile; } juce::RecentlyOpenedFilesList& getRecentFiles(); @@ -109,8 +107,6 @@ class LumatoneEditorState : public LumatoneApplicationState juce::File getUserMappingsDirectory() const; juce::File getUserPalettesDirectory() const; - // RecentlyOpenedFilesList& getRecentFileList() { return *recentFiles; } - // Font getAppFont(LumatoneEditorFont fontIdIn, float height = 12.0f) { return appFonts.getFont(fontIdIn, height); } public: bool doSendChangesToDevice() const override; @@ -119,28 +115,10 @@ class LumatoneEditorState : public LumatoneApplicationState juce::ValueTree loadStateProperties(juce::ValueTree stateIn) override; void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier& property) override; - bool resetToCurrentFile(); - bool openRecentFile(int recentFileIndex); - - void addPalette(const LumatoneEditorColourPalette& newPalette); - bool deletePaletteFile(juce::File pathToPalette); - -public: - - - -// Only main app should access these -private: - void setColourPalettes(const juce::Array& palettesIn); - void loadColourPalettesFromFile(); - - bool setCurrentFile(juce::File fileToOpen); - - void setEditMode(EditorMode editMode); - - void setHasChangesToSave(bool hasChangesToSave); - void setCalibrationMode(bool calibrationModeOn); - void setDeveloperMode(bool developerModeOn); + virtual void setHasChangesToSave(bool hasChangesToSave); + virtual void setCalibrationMode(bool calibrationModeOn); + virtual void setDeveloperMode(bool developerModeOn); + virtual void setEditMode(EditorMode editMode); protected: bool hasChangesToSave = false; @@ -161,7 +139,37 @@ class LumatoneEditorState : public LumatoneApplicationState std::shared_ptr propertiesFile; - friend class TerpstraSysExApplication; + friend class LumatoneEditorStateController; }; +class LumatoneEditorStateController : public LumatoneEditorState +{ +public: + LumatoneEditorStateController(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager* undoManagerIn) + : LumatoneEditorState(name, driverIn, undoManagerIn) {} + LumatoneEditorStateController(juce::String name, const LumatoneEditorState& stateIn) + : LumatoneEditorState(name, stateIn) {} + + const juce::Array& getColourPalettes() override; + + bool resetToCurrentFile(); + bool openRecentFile(int recentFileIndex); + + void addPalette(const LumatoneEditorColourPalette& newPalette); + bool deletePaletteFile(juce::File pathToPalette); + + void setColourPalettes(const juce::Array& palettesIn); + void loadColourPalettesFromFile(); + + bool setCurrentFile(juce::File fileToOpen); + bool saveMappingToFile(juce::File fileToSave); + + juce::PropertiesFile* getPropertiesFile() const { return propertiesFile.get(); } + bool savePropertiesFile() const; + + void setDeveloperMode(bool developerModeOn) override { LumatoneEditorState::setDeveloperMode(developerModeOn); } + void setEditMode(EditorMode editMode) override { LumatoneEditorState::setEditMode(editMode); } +}; + + #endif LUMATONE_EDITOR_STATE_H diff --git a/Source/LumatoneMenu.cpp b/Source/LumatoneMenu.cpp index eda71d0..e919f7f 100644 --- a/Source/LumatoneMenu.cpp +++ b/Source/LumatoneMenu.cpp @@ -14,8 +14,8 @@ namespace Lumatone { namespace Menu { - MainMenuModel::MainMenuModel(const LumatoneEditorState& state, ApplicationCommandManager* commandManager) - : LumatoneEditorState("MainMenu", state) + MainMenuModel::MainMenuModel(const LumatoneEditorState& state, juce::ApplicationCommandManager* commandManager) + : LumatoneEditorStateController("MainMenu", state) { theManager = commandManager; setApplicationCommandManagerToWatch(commandManager); @@ -81,7 +81,6 @@ namespace Lumatone { if (menuItemID >= recentFilesBaseID && menuItemID < recentFilesBaseID + 100) { // open a file from the "recent files" menu - // TerpstraSysExApplication::getApp().openRecentFile(menuItemID - recentFilesBaseID); openRecentFile(menuItemID - recentFilesBaseID); } } diff --git a/Source/LumatoneMenu.h b/Source/LumatoneMenu.h index d3dfe83..e089530 100644 --- a/Source/LumatoneMenu.h +++ b/Source/LumatoneMenu.h @@ -40,7 +40,7 @@ namespace Lumatone { }; class MainMenuModel : public juce::MenuBarModel - , public LumatoneEditorState + , public LumatoneEditorStateController { public: MainMenuModel(const LumatoneEditorState& stateIn, ApplicationCommandManager* commandManager); diff --git a/Source/Main.cpp b/Source/Main.cpp index 1516636..c3ac7a2 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -67,13 +67,13 @@ void TerpstraSysExApplication::initialise(const String& commandLine) // Try to open a config file if (File::isAbsolutePath(commandLineParameter)) { - state.currentFile = File(commandLineParameter); + state.setCurrentFile(juce::File(commandLineParameter)); } else { // If file name is with quotes, try removing the quotes if (commandLine.startsWithChar('"') && commandLine.endsWithChar('"')) - state.currentFile = File(commandLine.substring(1, commandLine.length() - 1)); + state.setCurrentFile(juce::File(commandLine.substring(1, commandLine.length() - 1))); //state.setCurrentFile(commandLine.substring(1, commandLine.length()-1)); } @@ -85,10 +85,8 @@ void TerpstraSysExApplication::initialise(const String& commandLine) commandManager.reset(new ApplicationCommandManager()); commandManager->registerAllCommandsForTarget(this); - boundsConstrainer = std::make_unique(); - mainWindow.reset(new MainWindow(state, commandManager.get())); - mainWindow->restoreStateFromPropertiesFile(state.propertiesFile.get()); + mainWindow->restoreStateFromPropertiesFile(state.getPropertiesFile()); if (state.getCurrentFile().existsAsFile()) @@ -97,27 +95,13 @@ void TerpstraSysExApplication::initialise(const String& commandLine) void TerpstraSysExApplication::shutdown() { - // Add your application's shutdown code here.. - - // Save documents directories (Future: provide option to change them and save after changed by user) - state.propertiesFile->setValue(LumatoneEditorProperty::UserDocumentsDirectory, state.getUserDocumentsDirectory().getFullPathName()); - state.propertiesFile->setValue(LumatoneEditorProperty::UserMappingsDirectory, state.getUserMappingsDirectory().getFullPathName()); - state.propertiesFile->setValue(LumatoneEditorProperty::UserPalettesDirectory, state.getUserPalettesDirectory().getFullPathName()); - - // Save recent files list - state.recentFiles->removeNonExistentFiles(); - jassert(state.propertiesFile != nullptr); - state.propertiesFile->setValue(LumatoneEditorProperty::RecentFiles, state.recentFiles->toString()); + LocalisedStrings::setCurrentMappings(nullptr); // Save state of main window - mainWindow->saveStateToPropertiesFile(state.propertiesFile.get()); - - state.propertiesFile->saveIfNeeded(); - state.propertiesFile = nullptr; - - LocalisedStrings::setCurrentMappings(nullptr); + //mainWindow->saveStateToPropertiesFile(state.propertiesFile.get()); + mainWindow = nullptr; - mainWindow = nullptr; + state.savePropertiesFile(); if (state.firmwareUpdateCompleted()) FirmwareTransfer::exitLibSsh2(); @@ -174,58 +158,59 @@ void TerpstraSysExApplication::anotherInstanceStarted(const String& commandLine) // this method is invoked, and the commandLine parameter tells you what // the other instance's command-line arguments were. } - -bool TerpstraSysExApplication::saveColourPalette(LumatoneEditorColourPalette& palette, File pathToFile) -{ - bool success = false; - - if (palette.hasBeenModified()) - { - ValueTree paletteNode = palette.toValueTree(); - - if (pathToFile == File()) - pathToFile = File(palette.getPathToFile()); - - // If name changed, delete the old one - if (pathToFile.exists()) - { - auto currentName = pathToFile.getFileName(); - if (currentName != palette.getName()) - { - pathToFile.deleteFile(); - } - } - - // New file - if (!pathToFile.existsAsFile()) - { - String fileName = "UnnamedPalette"; - - if (palette.getName().isNotEmpty()) - fileName = palette.getName(); - - pathToFile = state.getUserPalettesDirectory().getChildFile(fileName); - - // Make sure filename is unique since saving happens automatically - // Sorry programmers, we're using cardinal numbers here, and the original is implicitly #1 ;) - int nameId = 1; - while (pathToFile.withFileExtension(PALETTEFILEEXTENSION).existsAsFile() && nameId < 999999) - { - auto fileNameToSave = fileName + "_" + String(++nameId); - pathToFile = state.getUserPalettesDirectory().getChildFile(fileNameToSave); - } - } - - success = palette.saveToFile(pathToFile); - - // TODO error handling? - } - - // if (success) - // loadColourPalettesFromFile(); - - return success; -} +// +//bool TerpstraSysExApplication::saveColourPalette(LumatoneEditorColourPalette& palette, juce::File pathToFile) +//{ +// bool success = false; +// +// if (palette.hasBeenModified()) +// { +// ValueTree paletteNode = palette.toValueTree(); +// +// // pathToFile is optional - default to path defined in palette +// if (pathToFile == File()) +// pathToFile = File(palette.getPathToFile()); +// +// // If name changed, delete the old one +// if (pathToFile.exists()) +// { +// auto currentName = pathToFile.getFileName(); +// if (currentName != palette.getName()) +// { +// pathToFile.deleteFile(); +// } +// } +// +// // New file +// if (!pathToFile.existsAsFile()) +// { +// String fileName = "UnnamedPalette"; +// +// if (palette.getName().isNotEmpty()) +// fileName = palette.getName(); +// +// pathToFile = state.getUserPalettesDirectory().getChildFile(fileName); +// +// // Make sure filename is unique since saving happens automatically +// // Sorry programmers, we're using cardinal numbers here, and the original is implicitly #1 ;) +// int nameId = 1; +// while (pathToFile.withFileExtension(PALETTEFILEEXTENSION).existsAsFile() && nameId < 999999) +// { +// auto fileNameToSave = fileName + "_" + String(++nameId); +// pathToFile = state.getUserPalettesDirectory().getChildFile(fileNameToSave); +// } +// } +// +// success = palette.saveToFile(pathToFile); +// +// // TODO error handling? +// } +// +// // if (success) +// // loadColourPalettesFromFile(); +// +// return success; +//} void TerpstraSysExApplication::loadPropertiesFile() { @@ -406,11 +391,11 @@ bool TerpstraSysExApplication::perform(const InvocationInfo& info) bool TerpstraSysExApplication::openSysExMapping() { - fileChooser = std::make_unique("Open a Lumatone key mapping", state.recentFiles->getFile(0).getParentDirectory(), "*.ltn;*.tsx"); + fileChooser = std::make_unique("Open a Lumatone key mapping", state.getRecentFiles().getFile(0).getParentDirectory(), "*.ltn;*.tsx"); fileChooser->launchAsync(FileBrowserComponent::FileChooserFlags::canSelectFiles | FileBrowserComponent::FileChooserFlags::openMode, [&](const FileChooser& chooser) { - setCurrentFile(chooser.getResult()); + state.setCurrentFile(chooser.getResult()); state.resetToCurrentFile(); }); @@ -427,11 +412,11 @@ bool TerpstraSysExApplication::saveSysExMapping(std::function saveFileCallback) { - fileChooser = std::make_unique("Lumatone Key Mapping Files", state.recentFiles->getFile(0).getParentDirectory(), "*.ltn"); + fileChooser = std::make_unique("Lumatone Key Mapping Files", state.getRecentFiles().getFile(0).getParentDirectory(), "*.ltn"); fileChooser->launchAsync(FileBrowserComponent::FileChooserFlags::saveMode | FileBrowserComponent::FileChooserFlags::warnAboutOverwriting, [this, saveFileCallback](const FileChooser& chooser) { - state.currentFile = chooser.getResult(); + state.setCurrentFile(chooser.getResult()); bool saved = saveCurrentFile(); if (saved) { @@ -452,32 +437,12 @@ bool TerpstraSysExApplication::resetSysExMapping() return true; } -bool TerpstraSysExApplication::setCurrentFile(juce::File file) -{ - return state.setCurrentFile(file); -} - // Saves the current mapping to file, specified in state.getCurrentFile(). bool TerpstraSysExApplication::saveCurrentFile(std::function saveFileCallback) { - if (state.getCurrentFile().existsAsFile()) - state.getCurrentFile().deleteFile(); - bool retc = state.getCurrentFile().create(); - // XXX error handling - - bool appendSuccess = true; - StringArray stringArray = state.getMappingData()->toStringArray(); - for (int i = 0; i < stringArray.size(); i++) - appendSuccess = appendSuccess && state.getCurrentFile().appendText(stringArray[i] + "\n"); - - state.setHasChangesToSave(!appendSuccess); - saveFileCallback(appendSuccess); - - // ToDo undo history? - - // Add file to recent files list - or put it on top of the list - state.recentFiles->addFile(state.currentFile); - return retc; + bool success = state.saveMappingToFile(state.getCurrentFile()); + saveFileCallback(success); + return success; } bool TerpstraSysExApplication::deleteSubBoardData() @@ -696,7 +661,7 @@ bool TerpstraSysExApplication::requestConfigurationFromDevice() { // retc == 2: "No" -> no saving, overwrite DBG("Overwriting current edits"); - state.setHasChangesToSave(false); + //state.setHasChangesToSave(false); requestConfigurationFromDevice(); } }) @@ -770,7 +735,7 @@ bool TerpstraSysExApplication::aboutTerpstraSysEx() DialogWindow::LaunchOptions options; auto textDisplay = new TextEditor(); - //textDisplay->setLookAndFeel(&lookAndFeel); + //textDisplay->setLookAndFeel(&state.getEditorLookAndFeel()); state.getEditorLookAndFeel().setupTextEditor(*textDisplay); textDisplay->setMultiLine(true, true); textDisplay->setText(m, dontSendNotification); diff --git a/Source/Main.h b/Source/Main.h index 95791a1..2a754dc 100644 --- a/Source/Main.h +++ b/Source/Main.h @@ -55,10 +55,9 @@ class TerpstraSysExApplication : public JUCEApplication bool saveSysExMappingAs(std::function saveFileCallback = CHOOSE_FILE_NOOP); bool resetSysExMapping(); - bool setCurrentFile(juce::File file); bool saveCurrentFile(std::function saveFileCallback = CHOOSE_FILE_NOOP); - bool saveColourPalette(LumatoneEditorColourPalette& palette, juce::File pathToPalette=juce::File()); + //bool saveColourPalette(LumatoneEditorColourPalette& palette, juce::File pathToPalette=juce::File()); bool deleteSubBoardData(); bool copySubBoardData(); @@ -92,18 +91,16 @@ class TerpstraSysExApplication : public JUCEApplication LumatoneFirmwareDriver firmwareDriver; juce::UndoManager undoManager; - LumatoneEditorState state; + LumatoneEditorStateController state; std::unique_ptr activityMonitor; std::unique_ptr commandManager; + MainContentComponent* mainComponent; std::unique_ptr mainWindow; std::unique_ptr dialogWindow; - std::unique_ptr boundsConstrainer; - - juce::TooltipWindow tooltipWindow; std::unique_ptr fileChooser; }; diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index db61607..a805fc5 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -23,7 +23,8 @@ #include "GlobalSettingsArea.h" #include "PedalSensitivityDlg.h" -#include "./lumatone_editor_library/palettes/colour_palette_window.h" +#include "./ColourPaletteWindow.h" + #include "./lumatone_editor_library/palettes/colour_edit_textbox.h" #include "./lumatone_editor_library/ui/keyboard_component.h" #include "./lumatone_editor_library/graphics/view_constants.h" @@ -217,7 +218,7 @@ UndoableAction* MainContentComponent::createModifiedPasteCurrentSectionAction(Co if (currentSetSelectionIndex >= 0 && currentSetSelectionIndex < getNumBoards() && !copiedSubBoardData->isEmpty()) { - + auto modifiedSection = getBoard(currentSetSelectionIndex); auto octaveSize = getOctaveBoardSize(); @@ -404,7 +405,7 @@ void MainContentComponent::buttonClicked(Button* btn) // TerpstraSysExApplication::getApp().loadColourPalettesFromFile(); auto palettes = getColourPalettes(); - ColourPaletteWindow* paletteWindow = new ColourPaletteWindow(palettes); + ColourPaletteWindow* paletteWindow = new ColourPaletteWindow(*this); paletteWindow->setSize(proportionOfWidth(popupWidth), proportionOfHeight(popupHeight)); if (btn == noteEditArea->getColourViewComponent()) @@ -425,8 +426,8 @@ void MainContentComponent::buttonClicked(Button* btn) Rectangle componentArea = colourEdit->getScreenBounds().translated(-getScreenX(), -getScreenY()); - CallOutBox::launchAsynchronously( - std::unique_ptr(paletteWindow), + juce::CallOutBox::launchAsynchronously( + std::unique_ptr(paletteWindow), componentArea, this ); @@ -440,7 +441,7 @@ void MainContentComponent::buttonClicked(Button* btn) void MainContentComponent::paint (Graphics& g) { g.fillAll(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::MediumBackground)); - + g.setColour(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LightBackground)); g.fillRect(controlsArea); } diff --git a/Source/MainWindow.cpp b/Source/MainWindow.cpp index fd6a32b..98ace86 100644 --- a/Source/MainWindow.cpp +++ b/Source/MainWindow.cpp @@ -15,18 +15,17 @@ #include "./lumatone_editor_library/graphics/view_constants.h" -MainWindow::MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* cmdMgr) +MainWindow::MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* cmdManager) : juce::DocumentWindow("Lumatone Editor", juce::Colours::black, juce::DocumentWindow::minimiseButton + juce::DocumentWindow::closeButton) - , LumatoneEditorState("MainWindow", stateIn) - , commandManager(cmdMgr) + , LumatoneEditorStateController("MainWindow", stateIn) + , commandManager(cmdManager) { - // setContentOwned(new MainContentComponent(*TerpstraSysExApplication::getApp().getMappingData()), true); - setContentOwned(new MainContentComponent(stateIn, cmdMgr), true); + setContentOwned(new MainContentComponent(*this, commandManager), true); setResizable(true, true); + #if JUCE_ANDROID setFullScreen(true); #else - setLookAndFeel(&getEditorLookAndFeel()); menuModel = std::make_unique(*this, commandManager); @@ -54,9 +53,6 @@ MainWindow::MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationComm startTimer(2000); #endif - - // setLookAndFeel(stateIn.getEditorLookAndFeel()); - // setLookAndFeel(&TerpstraSysExApplication::getApp().getLookAndFeel()); } MainWindow::~MainWindow() @@ -145,6 +141,8 @@ void MainWindow::updateBounds() if (isOutOfVerticalBounds()) fixWindowPositionAndSize(); + + (LumatoneEditorProperty::MainWindowState, getWindowStateAsString()); } void MainWindow::fixWindowPositionAndSize(bool setToDefault) diff --git a/Source/MainWindow.h b/Source/MainWindow.h index 29fcc44..baa22ff 100644 --- a/Source/MainWindow.h +++ b/Source/MainWindow.h @@ -20,11 +20,11 @@ This class implements the desktop window that contains an instance of our MainContentComponent class. */ class MainWindow : public juce::DocumentWindow - , public LumatoneEditorState + , public LumatoneEditorStateController , public juce::Timer { public: - MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* cmdMgr); + MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* commandManager); virtual ~MainWindow(); diff --git a/Source/lumatone_editor_library/palettes/colour_palette_file.h b/Source/lumatone_editor_library/palettes/colour_palette_file.h index 258df3b..2954d01 100644 --- a/Source/lumatone_editor_library/palettes/colour_palette_file.h +++ b/Source/lumatone_editor_library/palettes/colour_palette_file.h @@ -97,24 +97,56 @@ class LumatoneEditorColourPalette /// /// /// - bool saveToFile(juce::File fileToSaveTo, bool deleteOldVersion = true) + bool saveToFile(juce::File fileToSaveTo, juce::File fallbackDirectory = juce::File()) { - // Make sure it has proper extension - fileToSaveTo = fileToSaveTo.withFileExtension(PALETTEFILEEXTENSION); + juce::File originalFile = pathToFile; + bool overwriteFile = originalFile.exists() && fileToSaveTo.withFileExtension(PALETTEFILEEXTENSION) == originalFile; - if (fileToSaveTo.getFullPathName() == pathToFile) - deleteOldVersion = true; + // Make sure directories exist + juce::String fileName = fileToSaveTo.getFileNameWithoutExtension(); + if (fileName.isEmpty()) + { + if (name.isNotEmpty()) + fileName = name; + else + fileName = "Unnamed Palette"; + } + + auto parentDir = fileToSaveTo.getParentDirectory(); + if (parentDir.getFullPathName().isEmpty()) + { + parentDir = fallbackDirectory; + + if (!parentDir.exists()) + { + parentDir = juce::File::getSpecialLocation(juce::File::SpecialLocationType::userDocumentsDirectory) + .getChildFile("Lumatone Editor") + .getChildFile("Palettes"); + } + } + + if (!parentDir.exists()) + parentDir.createDirectory(); - if (deleteOldVersion) + fileToSaveTo = parentDir.getChildFile(fileName).withFileExtension(PALETTEFILEEXTENSION); + + if (!overwriteFile) { - juce::File originalFile = pathToFile; + // Make sure filename is unique since saving happens automatically + int nameId = 1; + while (fileToSaveTo.existsAsFile() && nameId < 999999) + { + auto fileNameToSave = fileName + " (" + String(++nameId) + ")"; + fileToSaveTo = parentDir.getChildFile(fileNameToSave).withFileExtension(PALETTEFILEEXTENSION); + } - if (originalFile.existsAsFile()) - originalFile.deleteFile(); + fileName = fileToSaveTo.getFileNameWithoutExtension(); } if (!fileToSaveTo.existsAsFile()) + { fileToSaveTo.create(); + } if (fileToSaveTo.replaceWithText(toValueTree().toXmlString())) { @@ -126,11 +158,22 @@ class LumatoneEditorColourPalette return false; } + bool saveToFile() { return saveToFile(juce::File(pathToFile)); } + // Delete associated palette file + // Returns true if file does not exists anymore + bool deleteFile() + { + juce::File file(pathToFile); + if (file.existsAsFile()) + return file.deleteFile(); + return true; + } + juce::ValueTree toValueTree() const { juce::ValueTree node(LumatoneEditorPaletteIds::paletteId);