From b4c8b307e1fd8e1d2806bef5ae567fe0b64b5ef1 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Mon, 22 Jan 2024 16:27:45 -0500 Subject: [PATCH] fix MidiEditArea combo boxes --- Source/LumatoneEditorLookAndFeel.h | 12 +- Source/MidiEditArea.cpp | 221 ++++++++++------------------- Source/MidiEditArea.h | 27 ++-- 3 files changed, 92 insertions(+), 168 deletions(-) diff --git a/Source/LumatoneEditorLookAndFeel.h b/Source/LumatoneEditorLookAndFeel.h index 2fcc537f..8f5a565b 100644 --- a/Source/LumatoneEditorLookAndFeel.h +++ b/Source/LumatoneEditorLookAndFeel.h @@ -639,7 +639,7 @@ class LumatoneEditorLookAndFeel : public LookAndFeel_V4 Label* label = new Label(sld.getName() + "_ValueLabel"); label->setText(String(sld.getValue()), dontSendNotification); label->setJustificationType(Justification::centred); - // label->setFont(getAppFont(LumatoneEditorFont::GothamNarrowMedium)); + label->setFont(getAppFont(LumatoneEditorFont::GothamNarrowMedium)); Colour textColour = (sld.isEnabled()) ? findColour(LumatoneEditorColourIDs::DescriptionText) @@ -820,8 +820,10 @@ class LumatoneEditorLookAndFeel : public LookAndFeel_V4 for (auto prop : box.getProperties()) l->getProperties().set(prop.name, prop.value); + auto name = box.getName(); + auto fontHeight = box.getHeight() * CONTROLBOXFONTHEIGHTSCALAR; l->setBounds(box.getLocalBounds()); - l->setFont(getComboBoxFont(box).withHeight(box.getHeight() * CONTROLBOXFONTHEIGHTSCALAR)); // Any style overrides should have been passed to Label + l->setFont(getComboBoxFont(box)); // Any style overrides should have been passed to Label return l; } @@ -832,8 +834,10 @@ class LumatoneEditorLookAndFeel : public LookAndFeel_V4 float fontHeight = labelToPosition.getFont().getHeight(); labelToPosition.setBounds( - margin, roundToInt((box.getHeight() - fontHeight) * 0.5f), - box.getWidth() - box.getHeight() - margin, fontHeight + margin + , (box.getHeight() - fontHeight) * 0.5 + , box.getWidth() - box.getHeight() - margin /* leave room for down arrow glyph */ + , fontHeight ); } diff --git a/Source/MidiEditArea.cpp b/Source/MidiEditArea.cpp index 449ceea4..0880695e 100644 --- a/Source/MidiEditArea.cpp +++ b/Source/MidiEditArea.cpp @@ -52,7 +52,6 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontOverride, LumatoneEditorFont::UniviaProBold); liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, editModeFontScalar); addChildComponent(liveEditorBtn.get()); - // liveEditorBtn->addListener(this); liveEditorBtn->onClick = [&]() { if (liveEditorBtn->getToggleState()) @@ -69,7 +68,6 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontOverride, LumatoneEditorFont::UniviaProBold); offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, editModeFontScalar); addChildComponent(offlineEditorBtn.get()); - // offlineEditorBtn->addListener(this); offlineEditorBtn->onClick = [&]() { if (offlineEditorBtn->getToggleState()) @@ -79,6 +77,10 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) } }; + // liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); + // offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); + + pleaseConnectLabel.reset(new juce::Label("PleaseConnectLabel", translate("PleaseConnect"))); pleaseConnectLabel->setFont(getAppFonts().getFont(LumatoneEditorFont::UniviaProBold)); pleaseConnectLabel->setColour(juce::Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ActiveText)); @@ -93,16 +95,19 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) addAndMakeVisible(logomark.get()); logomarkPath = createLogomark(); - //[/Constructor_pre] cbMidiInput.reset (new juce::ComboBox ("cbMidiInput")); addAndMakeVisible (cbMidiInput.get()); cbMidiInput->setTooltip (juce::translate("Receives answers to sent SysEx commands and the current configuration from controller ")); cbMidiInput->setEditableText (false); cbMidiInput->setJustificationType (juce::Justification::centredLeft); - cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); + // cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); + cbMidiInput->setTextWhenNothingSelected ("pick something ya dummy"); cbMidiInput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); - cbMidiInput->addListener (this); + cbMidiInput->onChange = [&]() + { + midiInputChangedCallback(); + }; cbMidiOutput.reset (new juce::ComboBox ("cbMidiOutput")); addAndMakeVisible (cbMidiOutput.get()); @@ -111,7 +116,10 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) cbMidiOutput->setJustificationType (juce::Justification::centredLeft); cbMidiOutput->setTextWhenNothingSelected (juce::translate("Select MIDI Output")); cbMidiOutput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); - cbMidiOutput->addListener (this); + cbMidiOutput->onChange = [&]() + { + midiOutputChangedCallback(); + }; lblConnectionState.reset (new juce::Label ("lblConnectionState", juce::translate("Disconnected"))); @@ -139,8 +147,14 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) { toggleAutoConnection(); }; + btnAutoConnect->setClickingTogglesState(true); + + + // Set up styles + + connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DisconnectedRed)); + connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ConnectedGreen)); - //[UserPreSize] cbMidiInput->getProperties().set(LumatoneEditorStyleIDs::popupMenuTargetWidth, 1); cbMidiInput->getProperties().set(LumatoneEditorStyleIDs::popupMenuBackgroundColour, getEditorLookAndFeel().findColour(ComboBox::ColourIds::backgroundColourId).toString()); cbMidiInput->setVisible(false); @@ -156,55 +170,34 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) lblEditMode->setFont(getAppFonts().getFont(LumatoneEditorFont::UniviaProBold)); lblEditMode->setColour(juce::Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LabelPink)); - offlineEditorBtn->setClickingTogglesState(true); - offlineEditorBtn->setRadioGroupId(10, dontSendNotification); - liveEditorBtn->setClickingTogglesState(true); - liveEditorBtn->setRadioGroupId(10, dontSendNotification); - liveEditorBtn->setToggleState(true, dontSendNotification); - liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); - offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); - - btnAutoConnect->setClickingTogglesState(true); - ioAreaFlexBox.alignContent = juce::FlexBox::AlignContent::center; ioAreaFlexBox.alignItems = juce::FlexBox::AlignItems::center; ioAreaFlexBox.justifyContent = juce::FlexBox::JustifyContent::spaceBetween; - //[/UserPreSize] - //[Constructor] You can add your own custom stuff here.. - refreshInputMenuAndSetSelected(0, dontSendNotification); - refreshOutputMenuAndSetSelected(0, dontSendNotification); + refreshInputMenuAndSetSelected(-1, dontSendNotification); + refreshOutputMenuAndSetSelected(-1, dontSendNotification); setConnectivity(false); addEditorListener(this); addStatusListener(this); btnAutoConnect->setToggleState(isAutoConnectionEnabled(), sendNotificationSync); - //[/Constructor] } MidiEditArea::~MidiEditArea() { - //[Destructor_pre]. You can add your own custom destruction code here.. liveEditorBtn = nullptr; offlineEditorBtn = nullptr; offlineMsgLabel = nullptr; pleaseConnectLabel = nullptr; logomark = nullptr; - //[/Destructor_pre] cbMidiInput = nullptr; cbMidiOutput = nullptr; lblConnectionState = nullptr; lblEditMode = nullptr; btnAutoConnect = nullptr; - - - //[Destructor]. You can add your own custom destruction code here.. - //deviceMonitor.stopThread(100); - // getLumatoneController()->removeStatusListener(this); - //[/Destructor] } bool MidiEditArea::isConnected() const @@ -215,12 +208,8 @@ bool MidiEditArea::isConnected() const //============================================================================== void MidiEditArea::paint (juce::Graphics& g) { - //[UserPrePaint] Add your own custom painting code here.. - //[/UserPrePaint] - g.fillAll (juce::Colour (0xffbad0de)); - //[UserPaint] Add your own custom painting code here.. g.fillAll(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LightBackground)); // Dark background for title and logomark @@ -237,17 +226,12 @@ void MidiEditArea::paint (juce::Graphics& g) g.setColour(connectedColours[(int)(isConnected() && liveEditorBtn->getToggleState())]); drawPathToFillBounds(g, logomarkPath, logomarkBounds); - //[/UserPaint] } void MidiEditArea::resized() { - //[UserPreResize] Add your own custom resize code here.. float w = getWidth(); float h = getHeight(); - //[/UserPreResize] - - //[UserResized] Add your own custom resize handling here.. lumatoneLabelBounds = getBounds().withRight(roundToInt(w * lumatoneLabelAreaWidth)); resizeLabelWithWidth(lumatoneLabel.get(), lumatoneLabelBounds.proportionOfWidth(lumatoneLabelWidthInArea)); @@ -301,13 +285,18 @@ void MidiEditArea::resized() ioAreaFlexBox.items.clear(); ioAreaFlexBox.items.add(juce::FlexItem(*btnAutoConnect).withFlex(0).withWidth(controlHeight * 1.6f).withHeight(controlHeight)); + int deviceBoxWidth = roundToInt(ioBounds.getWidth() * midiDeviceControlBoundsWidth); + if (btnAutoConnect->getToggleState()) { lblConnectionState->setJustificationType(juce::Justification::centredLeft); + + // Make sure these are never 0 size + cbMidiInput->setSize(deviceBoxWidth, controlHeight); + cbMidiOutput->setSize(deviceBoxWidth, controlHeight); } else { - int deviceBoxWidth = roundToInt(ioBounds.getWidth() * midiDeviceControlBoundsWidth); ioAreaFlexBox.items.add(juce::FlexItem(*cbMidiInput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); ioAreaFlexBox.items.add(juce::FlexItem(*cbMidiOutput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); @@ -334,68 +323,6 @@ void MidiEditArea::resized() offlineMsgLabel->setSize(connectivityArea.getX() - pleaseConnectLabel->getX(), roundToInt(h * connectionDirectionsHeight)); offlineMsgLabel->setFont(offlineMsgLabel->getFont().withHeight(offlineMsgLabel->getHeight())); } - //[/UserResized] -} - -void MidiEditArea::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) -{ - //[UsercomboBoxChanged_Pre] - //[/UsercomboBoxChanged_Pre] - - if (comboBoxThatHasChanged == cbMidiInput.get()) - { - //[UserComboBoxCode_cbMidiInput] -- add your combo box handling code here.. - if (cbMidiInput->getSelectedItemIndex() >= 0) - setMidiInput(cbMidiInput->getSelectedItemIndex()); - - if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) - { - setConnectivity(false); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Select both a MIDI input and output")); - } - else - { - jassert(!isConnected()); - lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); - } - //[/UserComboBoxCode_cbMidiInput] - } - else if (comboBoxThatHasChanged == cbMidiOutput.get()) - { - //[UserComboBoxCode_cbMidiOutput] -- add your combo box handling code here.. - if (cbMidiOutput->getSelectedItemIndex() >= 0) - setMidiOutput(cbMidiOutput->getSelectedItemIndex()); - - if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) - { - setConnectivity(false); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Select both a MIDI input and output")); - } - else - { - jassert(!isConnected()); - lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); - } - //[/UserComboBoxCode_cbMidiOutput] - } - - //[UsercomboBoxChanged_Post] - //[/UsercomboBoxChanged_Post] -} - -//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... - -void MidiEditArea::lookAndFeelChanged() -{ - connectedColours.clear(); - connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DisconnectedRed)); - connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ConnectedGreen)); } void MidiEditArea::setConnectivity(bool isConnectedIn, juce::String connectionStatus) @@ -457,18 +384,13 @@ void MidiEditArea::toggleAutoConnection() cbMidiOutput->setVisible(!btnAutoConnect->getToggleState()); setAutoConnectionEnabled(btnAutoConnect->getToggleState()); - + if (btnAutoConnect->getToggleState()) { lblConnectionState->setText(translate("Searching for Lumatone..."), dontSendNotification); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Waiting for response from connected devices...")); } else { - // getLumatoneController()->stopAutoConnection(); lblConnectionState->setText(translate("Disconnected"), dontSendNotification); startTimer(deviceRefreshTimeoutMs); } @@ -482,7 +404,7 @@ void MidiEditArea::editModeChangedCallback() { liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); - + if (getHasChangesToSave()) onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); } @@ -491,11 +413,43 @@ void MidiEditArea::editModeChangedCallback() offlineEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); lblConnectionState->setText("Offline", juce::NotificationType::dontSendNotification); } - + lblConnectionState->setColour(juce::Label::ColourIds::textColourId, connectedColours[(int)liveEditorBtn->getToggleState()]); repaint(); } +void MidiEditArea::midiInputChangedCallback() +{ + if (cbMidiInput->getSelectedItemIndex() >= 0) + setMidiInput(cbMidiInput->getSelectedItemIndex()); + + if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) + { + setConnectivity(false); + } + else + { + jassert(!isConnected()); + lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); + } +} + +void MidiEditArea::midiOutputChangedCallback() +{ + if (cbMidiOutput->getSelectedItemIndex() >= 0) + setMidiOutput(cbMidiOutput->getSelectedItemIndex()); + + if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) + { + setConnectivity(false); + } + else + { + jassert(!isConnected()); + lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); + } +} + void MidiEditArea::connectionFailed() { setConnectivity(false, "No answer"); @@ -506,31 +460,26 @@ void MidiEditArea::connectionFailed() // getLumatoneController()->setMidiInput(-1); // getLumatoneController()->setMidiOutput(-1); } + void MidiEditArea::connectionStateChanged(ConnectionState state) { if (state == ConnectionState::ONLINE) { - // if (inputDevice >= 0 && outputDevice >= 0) - // { - refreshInputMenuAndSetSelected(getMidiInputIndex() + 1, dontSendNotification); - refreshOutputMenuAndSetSelected(getMidiOutputIndex() + 1, dontSendNotification); - setConnectivity(true); - - onOpenConnectionToDevice(); - // } + refreshInputMenuAndSetSelected(getMidiInputIndex(), dontSendNotification); + refreshOutputMenuAndSetSelected(getMidiOutputIndex(), dontSendNotification); + setConnectivity(true); + + onOpenConnectionToDevice(); } else if (state == ConnectionState::DISCONNECTED) { - // Lost should only happen after connection is established - // jassert(isConnected); - if (!btnAutoConnect->getToggleState()) startTimer(deviceRefreshTimeoutMs); else { - refreshInputMenuAndSetSelected(0, juce::NotificationType::dontSendNotification); - refreshOutputMenuAndSetSelected(0, juce::NotificationType::sendNotificationAsync); + refreshInputMenuAndSetSelected(-1, juce::NotificationType::dontSendNotification); + refreshOutputMenuAndSetSelected(-1, juce::NotificationType::sendNotificationAsync); } setConnectivity(false); @@ -539,28 +488,6 @@ void MidiEditArea::connectionStateChanged(ConnectionState state) void MidiEditArea::editorModeChanged(EditorMode editModeIn) { - // switch (editModeIn) - // { - // case EditorMode::ONLINE: - // liveEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); - // if (getHasChangesToSave()) - // onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); - // break; - - // case EditorMode::OFFLINE: - // offlineEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); - // lblConnectionState->setText(translate("Offline"), juce::NotificationType::dontSendNotification); - // //errorVisualizer.setErrorLevel( - // // *lblConnectionState.get(), - // // HajuErrorVisualizer::ErrorLevel::noError, - // // "Offline"); - // break; - - // default: - // jassertfalse; - // break; - // } - editModeChangedCallback(); } @@ -643,12 +570,12 @@ void MidiEditArea::timerCallback() else { refreshInputMenuAndSetSelected( - getMidiInputIndex() + 1, + cbMidiInput->getSelectedId(), juce::NotificationType::dontSendNotification ); refreshOutputMenuAndSetSelected( - getMidiOutputIndex() + 1, + cbMidiOutput->getSelectedId(), juce::NotificationType::dontSendNotification ); } diff --git a/Source/MidiEditArea.h b/Source/MidiEditArea.h index e75ce663..245de5a3 100644 --- a/Source/MidiEditArea.h +++ b/Source/MidiEditArea.h @@ -45,7 +45,6 @@ class MidiEditArea : public juce::Component , private LumatoneApplicationState::DeviceController , public LumatoneEditor::StatusListener , public LumatoneEditor::EditorListener - , public juce::ComboBox::Listener , public juce::Timer { public: @@ -53,11 +52,13 @@ class MidiEditArea : public juce::Component MidiEditArea (const LumatoneEditorState& stateIn); ~MidiEditArea() override; - bool isConnected() const; +public: + + void paint (juce::Graphics& g) override; + void resized() override; //============================================================================== - //[UserMethods] -- You can add your own custom methods in this section. - void lookAndFeelChanged() override; + bool isConnected() const; void onOpenConnectionToDevice(String dialogTitle = ""); @@ -80,18 +81,11 @@ class MidiEditArea : public juce::Component void editModeChangedCallback(); -public: - //[/UserMethods] + void midiInputChangedCallback(); + void midiOutputChangedCallback(); - void paint (juce::Graphics& g) override; - void resized() override; - void comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) override; private: - - bool isWaitingForConnectionTest = false; - bool isWaitingForUserChoice = false; - std::unique_ptr lumatoneLabel; std::unique_ptr liveEditorBtn; @@ -103,13 +97,12 @@ class MidiEditArea : public juce::Component std::unique_ptr logomark; juce::Path logomarkPath; - const int deviceRefreshTimeoutMs = 500; + bool isWaitingForUserChoice = false; + const int deviceRefreshTimeoutMs = 500; //============================================================================== // Helpers - //std::unique_ptr alert; - juce::FlexBox ioAreaFlexBox; juce::Rectangle lumatoneLabelBounds; @@ -117,7 +110,7 @@ class MidiEditArea : public juce::Component juce::Rectangle logomarkBounds; juce::Rectangle ioBounds; - juce::Array connectedColours = { juce::Colour(0xffd7002a), juce::Colour(0xff84aea3) }; + juce::Array connectedColours; //============================================================================== // Position & Size constants