diff --git a/Source/LumatoneMenu.h b/Source/LumatoneMenu.h index ab6f117..d3dfe83 100644 --- a/Source/LumatoneMenu.h +++ b/Source/LumatoneMenu.h @@ -21,6 +21,7 @@ namespace Lumatone { saveSysExMapping = 0x200011, saveSysExMappingAs = 0x200012, resetSysExMapping = 0x200013, + importSysExMapping = 0x200014, deleteOctaveBoard = 0x200100, copyOctaveBoard = 0x200101, diff --git a/Source/Main.cpp b/Source/Main.cpp index fe2efa5..9f57e40 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -241,6 +241,7 @@ void TerpstraSysExApplication::getAllCommands(Array & commands) Lumatone::Menu::commandIDs::saveSysExMapping, Lumatone::Menu::commandIDs::saveSysExMappingAs, Lumatone::Menu::commandIDs::resetSysExMapping, + Lumatone::Menu::commandIDs::importSysExMapping, Lumatone::Menu::commandIDs::deleteOctaveBoard, Lumatone::Menu::commandIDs::copyOctaveBoard, @@ -285,6 +286,11 @@ void TerpstraSysExApplication::getCommandInfo(CommandID commandID, ApplicationCo result.addDefaultKeypress('n', ModifierKeys::commandModifier); break; + case Lumatone::Menu::commandIDs::importSysExMapping: + result.setInfo("New", "Import mapping from device.", "File", 0); + result.addDefaultKeypress('i', ModifierKeys::commandModifier); + break; + case Lumatone::Menu::commandIDs::deleteOctaveBoard: result.setInfo("Delete", "Delete section data", "Edit", 0); result.addDefaultKeypress(KeyPress::deleteKey, ModifierKeys::noModifiers); @@ -367,6 +373,8 @@ bool TerpstraSysExApplication::perform(const InvocationInfo& info) return saveSysExMappingAs(); case Lumatone::Menu::commandIDs::resetSysExMapping: return resetSysExMapping(); + case Lumatone::Menu::commandIDs::importSysExMapping: + return requestConfigurationFromDevice(); case Lumatone::Menu::commandIDs::deleteOctaveBoard: return deleteSubBoardData(); @@ -654,7 +662,7 @@ bool TerpstraSysExApplication::toggleDeveloperMode() // } -void TerpstraSysExApplication::requestConfigurationFromDevice() +bool TerpstraSysExApplication::requestConfigurationFromDevice() { // if editing operations were done that have not been saved, give the possibility to save them if (state.getHasChangesToSave()) @@ -694,7 +702,7 @@ void TerpstraSysExApplication::requestConfigurationFromDevice() }) ); - return; + return true; } resetSysExMapping(); @@ -711,6 +719,8 @@ void TerpstraSysExApplication::requestConfigurationFromDevice() state.getLumatoneController()->sendVelocityConfigRequest(); state.getLumatoneController()->sendFaderConfigRequest(); state.getLumatoneController()->sendAftertouchConfigRequest(); + + return true; } void TerpstraSysExApplication::updateMainTitle() diff --git a/Source/Main.h b/Source/Main.h index e87a675..33afe84 100644 --- a/Source/Main.h +++ b/Source/Main.h @@ -78,7 +78,7 @@ class TerpstraSysExApplication : public JUCEApplication // bool aftertouchVelocityCurveDialog(); // void sendCurrentConfigurationToDevice(); - void requestConfigurationFromDevice(); + bool requestConfigurationFromDevice(); void updateMainTitle(); diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 2cb6c07..50f6673 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -32,7 +32,7 @@ //============================================================================== -MainContentComponent::MainContentComponent(const LumatoneEditorState& stateIn) +MainContentComponent::MainContentComponent(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* commandManager) : LumatoneEditorState("MainComponent", stateIn) , copiedSubBoardData(std::make_unique()) { @@ -65,10 +65,26 @@ MainContentComponent::MainContentComponent(const LumatoneEditorState& stateIn) addAndMakeVisible(globalSettingsArea.get()); globalSettingsArea->listenToColourEditButtons(this); - // getLumatoneController()->addFirmwareListener(this); + // getLumatoneController()->addFirmwareListener(this - //lblAppName.reset(new Label("lblAppName", TerpstraSysExApplication::getApp().getApplicationName())); - lblAppName.reset(new Label("lblAppName", "lumatone editor")); + btnLoadFile.reset(new juce::TextButton("btnLoadFile")); + addAndMakeVisible(btnLoadFile.get()); + btnLoadFile->setButtonText(TRANS("LoadFile")); + btnLoadFile->setCommandToTrigger(commandManager, Lumatone::Menu::openSysExMapping, true); + + btnSaveFile.reset(new juce::TextButton("btnSaveFile")); + addAndMakeVisible(btnSaveFile.get()); + btnSaveFile->setButtonText(TRANS("SaveFile")); + btnSaveFile->setCommandToTrigger(commandManager, Lumatone::Menu::saveSysExMappingAs, true); + + btnImportFile.reset(new juce::TextButton("buttonReceive")); + addAndMakeVisible(btnImportFile.get()); + btnImportFile->setTooltip(TRANS("ImportTooltip")); + btnImportFile->setButtonText(TRANS("Import from Lumatone")); + btnImportFile->setCommandToTrigger(commandManager, Lumatone::Menu::importSysExMapping, true); + + + lblAppName.reset(new Label("lblAppName", getApplicationName())); lblAppName->setFont(getAppFonts().getFont(LumatoneEditorFont::FranklinGothic)); lblAppName->setColour(Label::ColourIds::textColourId, Colour(0xff777777)); addAndMakeVisible(lblAppName.get()); @@ -78,6 +94,9 @@ MainContentComponent::MainContentComponent(const LumatoneEditorState& stateIn) lblAppVersion->setColour(Label::ColourIds::textColourId, Colour(0xff777777)); addAndMakeVisible(lblAppVersion.get()); + + addStatusListener(this); + // Initial size setSize(DEFAULTMAINWINDOWWIDTH, DEFAULTMAINWINDOWHEIGHT); @@ -87,6 +106,14 @@ MainContentComponent::MainContentComponent(const LumatoneEditorState& stateIn) changeListenerCallback(noteEditArea->getOctaveBoardSelectorTab()); noteEditArea->changeSingleKeySelection(0); + btnLoadFile->getProperties().set(LumatoneEditorStyleIDs::textButtonIconHashCode, LumatoneEditorIcon::LoadIcon); + btnSaveFile->getProperties().set(LumatoneEditorStyleIDs::textButtonIconHashCode, LumatoneEditorIcon::SaveIcon); + btnImportFile->getProperties().set(LumatoneEditorStyleIDs::textButtonIconHashCode, LumatoneEditorIcon::ArrowUp); + btnImportFile->getProperties().set(LumatoneEditorStyleIDs::textButtonIconPlacement, LumatoneEditorStyleIDs::TextButtonIconPlacement::RightOfText); + + // Only enable when connected + btnImportFile->setEnabled(false); + // Initialize mapping structure deleteAll(); } @@ -95,6 +122,10 @@ MainContentComponent::~MainContentComponent() { //TerpstraSysExApplication::getApp().getMidiDriver().removeListener(this); + btnLoadFile = nullptr; + btnSaveFile = nullptr; + btnImportFile = nullptr; + midiEditArea = nullptr; allKeysOverview = nullptr; noteEditArea = nullptr; @@ -243,10 +274,14 @@ bool MainContentComponent::setDeveloperMode(bool developerModeOn) { curvesArea->setDeveloperMode(developerModeOn); globalSettingsArea->setDeveloperMode(developerModeOn); - // allKeysOverview->showDeveloperMode(developerModeOn); return true; } +void MainContentComponent::connectionStateChanged(ConnectionState state) +{ + btnImportFile->setEnabled(state == ConnectionState::ONLINE); +} + void MainContentComponent::octaveColourConfigReceived(int octaveIndex, uint8 rgbFlag, const int* colourData) { for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) @@ -434,10 +469,26 @@ void MainContentComponent::resized() // All keys overview/virtual keyboard playing int newKeysOverviewAreaHeight = jmax(controlsArea.getY() - midiAreaHeight, MINIMALTERPSTRAKEYSETAREAHEIGHT); - int keyboardMarginTop = newKeysOverviewAreaHeight * 0.0625f; - int keyboardHeight = newKeysOverviewAreaHeight * 0.8f; + int keyboardMarginTop = juce::roundToInt(newKeysOverviewAreaHeight * lumatoneGraphicMarginTop); + int keyboardHeight = juce::roundToInt(newKeysOverviewAreaHeight * lumatoneGraphicH); allKeysOverview->setBounds(0, midiAreaHeight + keyboardMarginTop, newWidth, keyboardHeight); + int btnHeight = roundToInt(getHeight() * fileButtonH); + int btnMargin = roundToInt(getWidth() * saveloadMarginW); + int saveLoadWidth = roundToInt(getWidth() * saveLoadW); + int btnY = allKeysOverview->getY() - roundToInt(getHeight() * btnYFromImageTop); + + int halfWidthX = roundToInt(getWidth() * 0.5f); + + btnLoadFile->setBounds(halfWidthX - btnMargin - saveLoadWidth, btnY, saveLoadWidth, btnHeight); + btnSaveFile->setBounds(halfWidthX + btnMargin, btnY, saveLoadWidth, btnHeight); + + //octaveLineY = lumatoneBounds.getBottom() + roundToInt(getHeight() * octaveLineYRatio); + + int importY = allKeysOverview->getY() - roundToInt(getHeight() * importYFromImageTop); + int importWidth = roundToInt(getWidth() * importW); + btnImportFile->setBounds(allKeysOverview->getRight() - importWidth, importY, importWidth, btnHeight); + // Edit function/single key field area noteEditArea->setSize(proportionOfWidth(assignWidth), proportionOfHeight(assignHeight)); noteEditArea->setControlsTopLeftPosition(proportionOfWidth(assignMarginX), controlsArea.getY()); diff --git a/Source/MainComponent.h b/Source/MainComponent.h index 66763fa..a615bba 100644 --- a/Source/MainComponent.h +++ b/Source/MainComponent.h @@ -13,6 +13,7 @@ #include "LumatoneEditorState.h" #include "./lumatone_editor_library/data/lumatone_layout.h" +#include "./lumatone_editor_library/listeners/status_listener.h" #include "./lumatone_editor_library/listeners/firmware_listener.h" #include "./lumatone_editor_library/lumatone_midi_driver/firmware_types.h" @@ -32,13 +33,14 @@ class PedalSensitivityDlg; */ class MainContentComponent : public juce::Component , public LumatoneEditorState + , public LumatoneEditor::StatusListener , public LumatoneEditor::FirmwareListener , public juce::ChangeListener , public juce::Button::Listener { public: //============================================================================== - MainContentComponent(const LumatoneEditorState& stateIn); + MainContentComponent(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* commandManager); ~MainContentComponent(); void restoreStateFromPropertiesFile(PropertiesFile* propertiesFile); @@ -76,6 +78,9 @@ class MainContentComponent : public juce::Component void refreshKeyDataFields(); void refreshAllFields(); + // Implementation of LumatoneEditor::StatusListener + void connectionStateChanged(ConnectionState state) override; + // Implementation of LumatoneEditor::FirmwareListener void octaveColourConfigReceived(int octaveIndex, uint8 rgbFlag, const int* colourData) override; @@ -120,6 +125,10 @@ class MainContentComponent : public juce::Component std::unique_ptr globalSettingsArea; std::unique_ptr pedalSensitivityDlg; + std::unique_ptr btnLoadFile; + std::unique_ptr btnSaveFile; + std::unique_ptr btnImportFile; + // Version signature in bottom left of window std::unique_ptr lblAppName; std::unique_ptr lblAppVersion; @@ -143,6 +152,18 @@ class MainContentComponent : public juce::Component const float footerAreaY = 0.96f; + const float lumatoneGraphicMarginTop = 0.1f; + const float lumatoneGraphicH = 0.8f; + + const float fileButtonH = 0.025f; + const float importYFromImageTop = 0.4f; + const float importW = 0.1f; + + const float btnYFromImageTop = 0.02; + const float saveLoadW = 0.08f; + const float saveloadMarginW = 0.0034f; + + const float popupWidth = 0.4f; const float popupHeight = 0.333f; diff --git a/Source/MainWindow.cpp b/Source/MainWindow.cpp index 40e913d..9e58e15 100644 --- a/Source/MainWindow.cpp +++ b/Source/MainWindow.cpp @@ -21,7 +21,7 @@ MainWindow::MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationComm , commandManager(cmdMgr) { // setContentOwned(new MainContentComponent(*TerpstraSysExApplication::getApp().getMappingData()), true); - setContentOwned(new MainContentComponent(stateIn), true); + setContentOwned(new MainContentComponent(stateIn, cmdMgr), true); setResizable(true, true); #if JUCE_ANDROID setFullScreen(true);