@@ -62,7 +62,7 @@ RipplerXAudioProcessorEditor::RipplerXAudioProcessorEditor (RipplerXAudioProcess
6262 sunImage, 1 .0f , juce::Colours::transparentBlack,
6363 sunImage, 1 .0f , juce::Colours::transparentBlack);
6464 }
65- sun.setBounds (col+138 , row+3 , 20 , 20 );
65+ sun.setBounds (col+128 , row+3 , 20 , 20 );
6666 sun.onClick = [this ] {
6767 audioProcessor.toggleTheme ();
6868 loadTheme ();
@@ -80,39 +80,14 @@ RipplerXAudioProcessorEditor::RipplerXAudioProcessorEditor (RipplerXAudioProcess
8080 moonImage, 1 .0f , juce::Colours::transparentBlack,
8181 moonImage, 1 .0f , juce::Colours::transparentBlack);
8282 }
83- moon.setBounds (col+138 , row+3 , 20 , 20 );
83+ moon.setBounds (col+128 , row+3 , 20 , 20 );
8484 moon.onClick = [this ] {
8585 audioProcessor.toggleTheme ();
8686 loadTheme ();
8787 repaint ();
8888 };
8989
90- col += 160 ;
91- addAndMakeVisible (sizeLabel);
92- sizeLabel.setColour (juce::Label::ColourIds::textColourId, Colour (globals::COLOR_NEUTRAL_LIGHT ));
93- sizeLabel.setFont (FontOptions (16 .0f ));
94- sizeLabel.setText (" UI" , NotificationType::dontSendNotification);
95- sizeLabel.setBounds (col, row, 30 , 25 );
96-
97- addAndMakeVisible (sizeMenu);
98- sizeMenu.addItem (" 100%" , 1 );
99- sizeMenu.addItem (" 125%" , 2 );
100- sizeMenu.addItem (" 150%" , 3 );
101- sizeMenu.addItem (" 175%" , 4 );
102- sizeMenu.addItem (" 200%" , 5 );
103- sizeMenu.setSelectedId (audioProcessor.scale == 1 .0f ? 1
104- : audioProcessor.scale == 1 .25f ? 2
105- : audioProcessor.scale == 1 .5f ? 3
106- : audioProcessor.scale == 1 .75f ? 4
107- : 5 );
108- sizeMenu.onChange = [this ]()
109- {
110- const int value = sizeMenu.getSelectedId ();
111- auto scale = value == 1 ? 1 .0f : value == 2 ? 1 .25f : value == 3 ? 1 .5f : value == 4 ? 1 .75f : 2 .0f ;
112- audioProcessor.setScale (scale);
113- setScaleFactor (audioProcessor.scale );
114- };
115- sizeMenu.setBounds (col+25 ,row,80 ,25 );
90+ col += 215 ;
11691
11792 addAndMakeVisible (velButton);
11893 velButton.setTooltip (" Toggle velocity mapping, can also be set by holding Shift+Drag on knobs" );
@@ -127,13 +102,13 @@ RipplerXAudioProcessorEditor::RipplerXAudioProcessorEditor (RipplerXAudioProcess
127102 repaintVelSliders ();
128103 };
129104 velButton.setButtonText (" Vel Map" );
130- velButton.setBounds (col+ 115 , row, 80 , 25 );
105+ velButton.setBounds (col, row, 80 , 25 );
131106
132107 addAndMakeVisible (polyLabel);
133108 polyLabel.setColour (juce::Label::ColourIds::textColourId, Colour (globals::COLOR_NEUTRAL_LIGHT ));
134109 polyLabel.setFont (FontOptions (16 .0f ));
135110 polyLabel.setText (" Voices" , NotificationType::dontSendNotification);
136- polyLabel.setBounds (col+115 + 80 +5 , row, 50 , 25 );
111+ polyLabel.setBounds (col+80 +5 , row, 50 , 25 );
137112
138113 addAndMakeVisible (polyMenu);
139114 polyMenu.addItem (" 1" , 1 );
@@ -150,18 +125,7 @@ RipplerXAudioProcessorEditor::RipplerXAudioProcessorEditor (RipplerXAudioProcess
150125 audioProcessor.setPolyphony (poly);
151126 });
152127 };
153- polyMenu.setBounds (col+115 +80 +50 +5 ,row,55 ,25 );
154-
155- addAndMakeVisible (stereoizerBtn);
156- stereoizerBtn.setBounds (Rectangle<int >(50 , 25 ).withPosition (polyMenu.getBounds ().getTopRight ().translated (6 , 0 )));
157- stereoizerBtn.setAlpha (0 .0f );
158- stereoizerBtn.setTooltip (" Toggle stereoizer FX" );
159- stereoizerBtn.onClick = [this ]()
160- {
161- bool stereo = (bool )audioProcessor.params .getRawParameterValue (" stereoizer" )->load ();
162- audioProcessor.params .getParameter (" stereoizer" )->setValueNotifyingHost (stereo ? 0 .0f : 1 .0f );
163- repaint ();
164- };
128+ polyMenu.setBounds (col+80 +50 +5 ,row,55 ,25 );
165129
166130 addAndMakeVisible (presetMenu);
167131 presetMenu.setText (" Patch" );
@@ -256,6 +220,11 @@ RipplerXAudioProcessorEditor::RipplerXAudioProcessorEditor (RipplerXAudioProcess
256220 };
257221 presetMenu.setBounds (getWidth () - 110 , row, 100 , 25 );
258222
223+ addAndMakeVisible (settingsBtn);
224+ settingsBtn.setBounds (Rectangle<int >(25 , 25 ).withPosition (presetMenu.getBounds ().getTopLeft ().translated (-25 - 10 +3 , 0 )));
225+ settingsBtn.setAlpha (0 .f );
226+ settingsBtn.onClick = [this ]() { showSettingsMenu (); };
227+
259228 // NOISE SLIDERS
260229 col = 10 ; row += 35 ;
261230
@@ -869,7 +838,6 @@ void RipplerXAudioProcessorEditor::loadTheme()
869838 malletLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL_LIGHT ));
870839 malletSubLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL_LIGHT ));
871840 envelopeLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL_LIGHT ));
872- sizeLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL_LIGHT ));
873841 pitchLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL ));
874842 polyLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL_LIGHT ));
875843 aLabel.setColour (juce::Label::ColourIds::textColourId, Colour (COLOR_NEUTRAL_LIGHT ));
@@ -910,12 +878,31 @@ void RipplerXAudioProcessorEditor::paint (Graphics& g)
910878 path.lineTo ((float )bounds.getRight () - 3 .0f , (float )bounds.getCentreY () - 2 .0f );
911879 g.strokePath (path, PathStrokeType (2 .0f ));
912880
913- // draw stereoizer button
914- bounds = stereoizerBtn.getBounds ();
915- bool stereo = audioProcessor.params .getRawParameterValue (" stereoizer" )->load ();
916- g.setColour (Colour (stereo ? COLOR_ACTIVE : COLOR_NEUTRAL_LIGHT ));
917- g.setFont (14 .f );
918- g.drawText (stereo ? " Stereo" : " Mono" , bounds, Justification::centred, false );
881+ // draw settings button
882+ drawGear (g, settingsBtn.getBounds (), 10 , 6 , Colour (COLOR_ACTIVE ), Colour (COLOR_BACKGROUND ));
883+ }
884+
885+ void RipplerXAudioProcessorEditor::drawGear (Graphics& g, Rectangle<int > bounds, float radius, int segs, Colour color, Colour background)
886+ {
887+ float x = bounds.toFloat ().getCentreX ();
888+ float y = bounds.toFloat ().getCentreY ();
889+ float oradius = radius;
890+ float iradius = radius / 3 .f ;
891+ float cradius = iradius / 1 .5f ;
892+ float coffset = MathConstants<float >::twoPi;
893+ float inc = MathConstants<float >::twoPi / segs;
894+
895+ g.setColour (color);
896+ g.fillEllipse (x - oradius, y - oradius, oradius * 2 .f , oradius * 2 .f );
897+
898+ g.setColour (background);
899+ for (int i = 0 ; i < segs; i++) {
900+ float angle = coffset + i * inc;
901+ float cx = x + std::cos (angle) * oradius;
902+ float cy = y + std::sin (angle) * oradius;
903+ g.fillEllipse (cx - cradius, cy - cradius, cradius * 2 , cradius * 2 );
904+ }
905+ g.fillEllipse (x - iradius, y - iradius, iradius * 2 .f , iradius * 2 .f );
919906}
920907
921908void RipplerXAudioProcessorEditor::repaintVelSliders ()
@@ -947,6 +934,51 @@ void RipplerXAudioProcessorEditor::resized()
947934{
948935}
949936
937+ void RipplerXAudioProcessorEditor::showSettingsMenu ()
938+ {
939+ bool stereoizer = (bool )audioProcessor.params .getRawParameterValue (" stereoizer" )->load ();
940+ bool reuseVoices = (bool )audioProcessor.params .getRawParameterValue (" reuse_voices" )->load ();
941+
942+ PopupMenu menu;
943+ PopupMenu scaleMenu;
944+ scaleMenu.addItem (1 , " 100%" , true , audioProcessor.scale == 1 .0f );
945+ scaleMenu.addItem (2 , " 125%" , true , audioProcessor.scale == 1 .25f );
946+ scaleMenu.addItem (3 , " 150%" , true , audioProcessor.scale == 1 .5f );
947+ scaleMenu.addItem (4 , " 175%" , true , audioProcessor.scale == 1 .75f );
948+ scaleMenu.addItem (5 , " 200%" , true , audioProcessor.scale == 2 .0f );
949+
950+ PopupMenu polyphonyMenu;
951+ polyphonyMenu.addItem (10 , " Reuse voices on repeated notes" , true , reuseVoices);
952+
953+ menu.addSubMenu (" UI Scale" , scaleMenu);
954+ menu.addSubMenu (" Polyphony" , polyphonyMenu);
955+ menu.addItem (11 , " Stereoizer" , true , stereoizer);
956+
957+ auto menuPos = localPointToGlobal (settingsBtn.getBounds ().getBottomRight ());
958+ menu.showMenuAsync (PopupMenu::Options ()
959+ .withTargetScreenArea ({ menuPos.getX () - 125 , menuPos.getY (), 1 , 1 }),
960+ [this , stereoizer, reuseVoices](int result) {
961+ if (result == 0 ) return ;
962+ if (result == 1 ) audioProcessor.setScale (1 .f );
963+ if (result == 2 ) audioProcessor.setScale (1 .25f );
964+ if (result == 3 ) audioProcessor.setScale (1 .5f );
965+ if (result == 4 ) audioProcessor.setScale (1 .75f );
966+ if (result == 5 ) audioProcessor.setScale (2 .f );
967+ if (result >= 1 && result <= 5 ) {
968+ setScaleFactor (audioProcessor.scale );
969+ }
970+
971+ if (result == 10 ) {
972+ auto param = audioProcessor.params .getParameter (" reuse_voices" );
973+ param->setValueNotifyingHost (reuseVoices ? 0 .f : 1 .f );
974+ }
975+ if (result == 11 ) {
976+ auto param = audioProcessor.params .getParameter (" stereoizer" );
977+ param->setValueNotifyingHost (stereoizer ? 0 .f : 1 .f );
978+ }
979+ });
980+ }
981+
950982void RipplerXAudioProcessorEditor::showMalletMenu ()
951983{
952984 auto malletType = (int )audioProcessor.params .getRawParameterValue (" mallet_type" )->load () + 1 ;
0 commit comments