AnalogTapeModel

Physical modelling signal processing for analog tape recording
Log | Files | Refs | Submodules | README | LICENSE

commit 1aad314727d1c40e3f7894564e2ef46a47273d9d
parent fe5257a71bba1ea956c09de718d19f9e1f145291
Author: jatinchowdhury18 <[email protected]>
Date:   Fri, 24 Jul 2020 08:59:06 -0700

Update GUI to new design (#59)

* Start work on new GUI

* GUI updates: combo boxes, tabbed components

* Update tooltips and slider colors, add Hysteresis Mode ComboBox

Co-authored-by: jatinchowdhury18 <[email protected]>
Diffstat:
MPlugin/CHOWTapeModel.jucer | 25+++++++++++++++++++++----
APlugin/Source/GUI/Assets/Background.svg | 9+++++++++
APlugin/Source/GUI/Assets/RobotoCondensed-Bold.ttf | 0
APlugin/Source/GUI/Assets/RobotoCondensed-Regular.ttf | 0
APlugin/Source/GUI/Assets/gui.xml | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/Assets/knob.svg | 13+++++++++++++
APlugin/Source/GUI/Assets/pointer.svg | 4++++
RPlugin/Source/GUI/preset_save_gui.xml -> Plugin/Source/GUI/Assets/preset_save_gui.xml | 0
APlugin/Source/GUI/InfoComp.cpp | 44++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/InfoComp.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/MyLNF.cpp | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/MyLNF.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/TitleComp.cpp | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/TitleComp.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/TooltipComp.cpp | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/TooltipComp.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DPlugin/Source/GUI/gui.xml | 100-------------------------------------------------------------------------------
MPlugin/Source/PluginProcessor.cpp | 13+++++++++++++
MPlugin/Source/PluginProcessor.h | 2++
MPlugin/Source/Presets/PresetComp.cpp | 21++++++---------------
MPlugin/Source/Presets/PresetComp.h | 36++----------------------------------
21 files changed, 899 insertions(+), 153 deletions(-)

diff --git a/Plugin/CHOWTapeModel.jucer b/Plugin/CHOWTapeModel.jucer @@ -7,9 +7,26 @@ <MAINGROUP id="pXbPvR" name="CHOWTapeModel"> <GROUP id="{0178B10A-4A61-796A-5AB2-915D32AF6EEE}" name="Source"> <GROUP id="{8D673967-9B5D-8254-9062-4C4B14D4EAD9}" name="GUI"> - <FILE id="KmBito" name="gui.xml" compile="0" resource="1" file="Source/GUI/gui.xml"/> - <FILE id="kmORjM" name="preset_save_gui.xml" compile="0" resource="1" - file="Source/GUI/preset_save_gui.xml"/> + <GROUP id="{1765C43E-7671-A0DE-6CE7-A10A24110269}" name="Assets"> + <FILE id="rW7Fbv" name="Background.svg" compile="0" resource="1" file="Source/GUI/Assets/Background.svg"/> + <FILE id="DzcyPN" name="gui.xml" compile="0" resource="1" file="Source/GUI/Assets/gui.xml"/> + <FILE id="xzpwn3" name="knob.svg" compile="0" resource="1" file="Source/GUI/Assets/knob.svg"/> + <FILE id="VVaf9c" name="pointer.svg" compile="0" resource="1" file="Source/GUI/Assets/pointer.svg"/> + <FILE id="LbfXKZ" name="preset_save_gui.xml" compile="0" resource="1" + file="Source/GUI/Assets/preset_save_gui.xml"/> + <FILE id="th5YSa" name="RobotoCondensed-Bold.ttf" compile="0" resource="1" + file="Source/GUI/Assets/RobotoCondensed-Bold.ttf"/> + <FILE id="bQP3yl" name="RobotoCondensed-Regular.ttf" compile="0" resource="1" + file="Source/GUI/Assets/RobotoCondensed-Regular.ttf"/> + </GROUP> + <FILE id="rOj90C" name="InfoComp.cpp" compile="1" resource="0" file="Source/GUI/InfoComp.cpp"/> + <FILE id="FxvDV3" name="InfoComp.h" compile="0" resource="0" file="Source/GUI/InfoComp.h"/> + <FILE id="IgOtsG" name="MyLNF.cpp" compile="1" resource="0" file="Source/GUI/MyLNF.cpp"/> + <FILE id="pj6eEc" name="MyLNF.h" compile="0" resource="0" file="Source/GUI/MyLNF.h"/> + <FILE id="WfCYvA" name="TitleComp.cpp" compile="1" resource="0" file="Source/GUI/TitleComp.cpp"/> + <FILE id="aoz8GN" name="TitleComp.h" compile="0" resource="0" file="Source/GUI/TitleComp.h"/> + <FILE id="oFI05X" name="TooltipComp.cpp" compile="1" resource="0" file="Source/GUI/TooltipComp.cpp"/> + <FILE id="BpGwTA" name="TooltipComp.h" compile="0" resource="0" file="Source/GUI/TooltipComp.h"/> </GROUP> <GROUP id="{71C1FCA8-E7B0-3B66-1340-F140C452FF6F}" name="Presets"> <GROUP id="{AB6F221D-98B5-9782-2241-321BA5DFB83C}" name="PresetConfigs"> @@ -169,5 +186,5 @@ <LINUX/> </LIVE_SETTINGS> <JUCEOPTIONS JUCE_JACK="1" JUCE_VST3_CAN_REPLACE_VST2="0" JUCE_STRICT_REFCOUNTEDPOINTER="1" - FOLEYS_SHOW_GUI_EDITOR_PALLETTE="0" JUCE_WEB_BROWSER="0"/> + FOLEYS_SHOW_GUI_EDITOR_PALLETTE="0" JUCE_WEB_BROWSER="0" FOLEYS_ENABLE_BINARY_DATA="1"/> </JUCERPROJECT> diff --git a/Plugin/Source/GUI/Assets/Background.svg b/Plugin/Source/GUI/Assets/Background.svg @@ -0,0 +1,9 @@ +<svg width="615" height="661" viewBox="0 0 615 661" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect width="615" height="661" fill="url(#paint0_linear)"/> +<defs> +<linearGradient id="paint0_linear" x1="0" y1="0" x2="678.229" y2="588.079" gradientUnits="userSpaceOnUse"> +<stop stop-color="#8B3232"/> +<stop offset="1" stop-color="#7D2424"/> +</linearGradient> +</defs> +</svg> diff --git a/Plugin/Source/GUI/Assets/RobotoCondensed-Bold.ttf b/Plugin/Source/GUI/Assets/RobotoCondensed-Bold.ttf Binary files differ. diff --git a/Plugin/Source/GUI/Assets/RobotoCondensed-Regular.ttf b/Plugin/Source/GUI/Assets/RobotoCondensed-Regular.ttf Binary files differ. diff --git a/Plugin/Source/GUI/Assets/gui.xml b/Plugin/Source/GUI/Assets/gui.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<magic> + <Styles> + <Style name="default"> + <Nodes/> + <Classes> + <plot-view border="2" background-color="black" border-color="silver" display="contents"/> + <nomargin margin="0" padding="0" border="0"/> + <group margin="5" padding="5" border="2" flex-direction="column"/> + <Slider background-color="00000000" caption-color="FFFFFFFF" slider-text-outline="00000000" + slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below" + lookAndFeel="MyLNF" slider-background="ff595c6b" slider-track="ff9cbcbd"> + <media/> + </Slider> + </Classes> + <Types> + <Slider border="0" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below"/> + <ToggleButton border="0" max-height="50" caption-size="0" text="Active"/> + <TextButton border="0" max-height="50" caption-size="0"/> + <ComboBox border="0" max-height="50" caption-size="0"/> + <Plot border="0" margin="0" padding="0" background-color="00000000" + radius="0"/> + <XYDragComponent border="0" margin="0" padding="0" background-color="00000000" + radius="0"/> + </Types> + </Style> + </Styles> + <View id="root" resizable="1" resize-corner="1" flex-direction="column" + padding="0" width="580" height="580" background-color="FF8B3232" + background-image="Background_svg" image-placement="stretch"> + <View max-height="100" padding="0" margin="0" background-color=""> + <View margin="2" padding="" background-color="00000000" flex-direction="column" + flex-grow="0.75"> + <TitleComp background-color="00000000" title="Chow Tape Model" font="40" + padding="0"/> + <InfoComp background-color="00000000" text1="FFEAA92C" flex-grow="0.7" + padding="0" margin="5"/> + </View> + <Plot source="scope" plot-color="FFEAA92C" padding="0" background-color="33000000" + plot-decay="0.0" plot-fill-color="00000000"/> + </View> + <View padding="0" margin="" background-color="" lookAndFeel=""> + <View flex-direction="column" margin="5" padding="" background-color="FF31323A"> + <Slider caption="Input Gain [dB]" parameter="ingain" class="Slider" name="Input Gain" + tooltip="Sets the input gain to the tape model in Decibels."/> + <Slider caption="Dry/Wet" parameter="drywet" class="Slider" tooltip="Sets dry/wet mix of the entire plugin." + name="Dry/Wet" slider-track="FF0BBDC2"/> + <Slider caption="Output Gain [dB]" parameter="outgain" class="Slider" name="Output Gain" + tooltip="Sets the output gain from the tape model in Decibels."/> + </View> + <View flex-direction="column" tab-color="" background-color="FF31323A"> + <Slider caption="Bias" parameter="width" class="Slider" name="Bias" + tooltip="Controls the amount of bias used by the tape recorder. Turning down the bias can create &quot;deadzone&quot; distortion."/> + <Slider caption="Saturation" parameter="sat" class="Slider" name="Saturation" + tooltip="Controls the amount of tape saturation applied to the signal."/> + <Slider caption="Drive" parameter="drive" class="Slider" name="Drive" + tooltip="Controls the amount of amplification done during the tape magnetisation process. Note that unlike the &quot;Input Gain&quot;, this amplification is highly nonlinear."/> + </View> + <View display="tabbed" padding="0" background-color="FF31323A" flex-grow="1.5" + lookAndFeel="MyLNF"> + <View flex-direction="column" tab-caption="Loss" tab-color="" background-color="FF31323A" + padding="0" margin="0"> + <View flex-grow="0.1" background-color="00000000"/> + <Slider caption="Gap [mm]" parameter="gap" slider-type="linear-horizontal" + class="Slider" padding="0" slider-background="ff595c6b" slider-track="ff9cbcbd" + name="Gap" tooltip="Sets the width of the playhead gap. Certain frequencies that resonate with the gap width will be emphasized."/> + <View flex-grow="0.2" background-color="00000000"/> + <Slider caption="Thickness [mm]" parameter="thick" class="Slider" slider-type="linear-horizontal" + padding="0" slider-background="ff595c6b" slider-track="ff9cbcbd" + name="Thickness" tooltip="Sets the thickness of the tape. Thicker tape has a more muted high-frequency response."/> + <View flex-grow="0.2" background-color="00000000"/> + <Slider caption="Spacing [mm]" parameter="spacing" slider-type="linear-horizontal" + class="Slider" padding="0" slider-background="ff595c6b" slider-track="ff9cbcbd" + name="Spacing" tooltip="Sets the spacing between the tape and the playhead. A larger spacing means more high frequency signal is lost during playback."/> + <View flex-grow="0.2" background-color="00000000"/> + <Slider caption="Speed [ips]" parameter="speed" slider-type="linear-horizontal" + class="Slider" padding="0" slider-background="ff595c6b" slider-track="ff9cbcbd" + name="Speed" tooltip="Sets the speed of the tape as it affects the playhead loss effects. Note that this control does not affect the wow/flutter processing."/> + <View flex-grow="0.2" background-color="00000000"/> + </View> + <View tab-caption="Degrade" padding="0" flex-direction="column" background-color="FF31323A"> + <Slider parameter="deg_depth" caption="Depth" class="Slider" name="Depth" + tooltip="Sets the depth of the tape degradation." padding="0" + margin="0"/> + <Slider caption="Amount" parameter="deg_amt" class="Slider" name="Amount" padding="0" margin="0" + tooltip="Sets the amount of the tape that is degraded. At large values all of the tape will be affected, at small values only some sections will be affected."/> + <Slider parameter="deg_var" caption="Variance" class="Slider" name="Variance" padding="0" margin="0" + tooltip="Sets the variance of the tape degradation. Use lower values for uniform degradation, or higher values for variation across different sections of tape."/> + </View> + <View tab-caption="CHEW" padding="0" flex-direction="column" background-color="FF31323A"> + <Slider parameter="chew_depth" caption="Depth" max-height="150" class="Slider" + name="Chew Depth" tooltip="Controls how intensely the tape has been chewed up."/> + <Slider caption="Frequency" parameter="chew_freq" max-height="150" class="Slider" + name="Chew Frequency" tooltip="Controls the amount of time in between chewed-up sections of tape."/> + </View> + </View> + <View display="tabbed" padding="0" background-color="FF31323A" lookAndFeel="MyLNF"> + <View tab-caption="Flutter" flex-direction="column" background-color="FF31323A"> + <Slider caption="Depth" parameter="depth" max-height="150" class="Slider" + name="Flutter Depth" tooltip="Sets depth of the tape flutter."/> + <Slider caption="Rate" parameter="rate" class="Slider" max-height="150" + name="Flutter Rate" tooltip="Sets the rate of the tape flutter."/> + </View> + <View tab-caption="Wow" flex-direction="column" background-color="FF31323A"> + <Slider caption="Depth" parameter="wow_depth" max-height="150" class="Slider" + name="Wow Depth" tooltip="Sets the depth of the tape wow."/> + <Slider caption="Rate" parameter="wow_rate" class="Slider" max-height="150" + name="Wow Rate" tooltip="Sets the rate of the tape wow."/> + </View> + </View> + </View> + <TooltipComp flex-grow="0.15" background-color="00000000" tooltip-name="FFEAA92C" + tooltip-text="FFFFFFFF"/> + <View max-height="35" margin="0" padding="0" background-color="FF31323A" + flex-grow="0.1"> + <ComboBox caption="Oversampling" parameter="os" class="Slider" caption-size="0" + padding="0" combo-text="FFEAA92C" combo-background="00000000" max-height="100" margin="" + lookAndFeel="ComboBoxLNF" name="Oversampling" + tooltip="Sets the amount of oversampling used for the hysteresis processing. More oversampling will reduce aliasing artifacts, but requires more CPU resources."/> + <ComboBox lookAndFeel="ComboBoxLNF" padding="0" border="0" background-color="00000000" + name="Hysteresis Mode" caption="Hysteresis Mode" caption-size="0" combo-text="FFEAA92C" + caption-color="FFFFFFFF" max-height="100" margin="" parameter="mode" combo-background="00000000" + tooltip="Selects the mode to use for hysteresis processing. Choose between 2nd/4th order Runge-Kutta method, 5 or 10 Newton-Raphson iterations, or revert to version 1.0."/> + <presets margin="5" padding="0" background-color="00000000" border-color="595C6B" + radius="" border="" lookAndFeel="ComboBoxLNF" tooltip="Selects a preset for the plugin." + flex-grow="1.8" max-height="100"/> + </View> + </View> +</magic> + +\ No newline at end of file diff --git a/Plugin/Source/GUI/Assets/knob.svg b/Plugin/Source/GUI/Assets/knob.svg @@ -0,0 +1,13 @@ +<svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="40.2539" cy="40.7441" r="27.248" transform="rotate(45 40.2539 40.7441)" fill="url(#paint0_linear)" stroke="url(#paint1_linear)" stroke-opacity="0.5" stroke-width="1.75794"/> +<defs> +<linearGradient id="paint0_linear" x1="13.0059" y1="13.4961" x2="67.502" y2="67.9921" gradientUnits="userSpaceOnUse"> +<stop stop-color="#B5B5BF"/> +<stop offset="1" stop-color="#606068"/> +</linearGradient> +<linearGradient id="paint1_linear" x1="13.0059" y1="13.4961" x2="67.502" y2="67.9921" gradientUnits="userSpaceOnUse"> +<stop stop-color="white"/> +<stop offset="1" stop-color="#383844"/> +</linearGradient> +</defs> +</svg> diff --git a/Plugin/Source/GUI/Assets/pointer.svg b/Plugin/Source/GUI/Assets/pointer.svg @@ -0,0 +1,4 @@ +<svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="40.2539" cy="40.7441" r="27.248" transform="rotate(45 40.2539 40.7441)" fill="white" fill-opacity="0.0"/> +<path d="M38.496 12.964H42.0119V41.3092C42.0119 42.2801 41.2248 43.0672 40.2539 43.0672C39.2831 43.0672 38.496 42.2801 38.496 41.3092V12.964Z" fill="white"/> +</svg> diff --git a/Plugin/Source/GUI/preset_save_gui.xml b/Plugin/Source/GUI/Assets/preset_save_gui.xml diff --git a/Plugin/Source/GUI/InfoComp.cpp b/Plugin/Source/GUI/InfoComp.cpp @@ -0,0 +1,44 @@ +#include "InfoComp.h" + +InfoComp::InfoComp (const AudioProcessor::WrapperType wrapperType) : + wrapperType (wrapperType) +{ + setColour (text1ColourID, Colours::grey); + setColour (text2ColourID, Colours::white); + + addAndMakeVisible (linkButton); + linkButton.setFont (Font (17.0f).boldened(), false, Justification::left); +} + +void InfoComp::paint (Graphics& g) +{ + g.setFont (17.0f); + auto font = g.getCurrentFont(); + auto b = getLocalBounds(); + + auto drawText = [=, &g, &b] (const String& text) + { + auto width = font.getStringWidth (text); + g.drawFittedText (text, b.removeFromLeft (width), Justification::left, 1); + }; + + auto typeStr = String (AudioProcessor::getWrapperTypeDescription (wrapperType)); + g.setColour (findColour (text1ColourID)); + drawText (typeStr + ", "); + + g.setColour (findColour (text2ColourID)); + drawText ("v" + String (JucePlugin_VersionString) + " "); + + g.setColour (findColour (text1ColourID)); + drawText (String ("~ DSP by ")); + + linkX = b.getX() - 2; + linkButton.setColour (HyperlinkButton::ColourIds::textColourId, findColour (text2ColourID)); + resized(); +} + +void InfoComp::resized() +{ + auto b = getLocalBounds(); + linkButton.setBounds (linkX, 0, 100, getHeight()); +} diff --git a/Plugin/Source/GUI/InfoComp.h b/Plugin/Source/GUI/InfoComp.h @@ -0,0 +1,61 @@ +#ifndef INFOCOMP_H_INCLUDED +#define INFOCOMP_H_INCLUDED + +#include <JuceHeader.h> + +class InfoComp : public Component +{ +public: + InfoComp (const AudioProcessor::WrapperType wrapperType); + + enum ColourIDs + { + text1ColourID, + text2ColourID, + }; + + void paint (Graphics& g) override; + void resized() override; + +private: + const AudioProcessor::WrapperType wrapperType; + HyperlinkButton linkButton { JucePlugin_Manufacturer, URL ("https://ccrma.stanford.edu/~jatin/chowdsp") }; + + int linkX = 0; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InfoComp) +}; + +class InfoItem : public foleys::GuiItem +{ +public: + FOLEYS_DECLARE_GUI_FACTORY (InfoItem) + + InfoItem (foleys::MagicGUIBuilder& builder, const ValueTree& node) : + foleys::GuiItem (builder, node) + { + setColourTranslation ({ + {"text1", InfoComp::text1ColourID}, + {"text2", InfoComp::text2ColourID}, + }); + + infoComp = std::make_unique<InfoComp> (builder.getMagicState().getProcessor()->wrapperType); + addAndMakeVisible (infoComp.get()); + } + + void update() override + { + } + + Component* getWrappedComponent() override + { + return infoComp.get(); + } + +private: + std::unique_ptr<InfoComp> infoComp; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InfoItem) +}; + +#endif // INFOCOMP_H_INCLUDED diff --git a/Plugin/Source/GUI/MyLNF.cpp b/Plugin/Source/GUI/MyLNF.cpp @@ -0,0 +1,257 @@ +#include "MyLNF.h" + +MyLNF::MyLNF() +{ + roboto = Typeface::createSystemTypefaceFor (BinaryData::RobotoCondensedRegular_ttf, + BinaryData::RobotoCondensedRegular_ttfSize); + + robotoBold = Typeface::createSystemTypefaceFor (BinaryData::RobotoCondensedBold_ttf, + BinaryData::RobotoCondensedBold_ttfSize); + + setColour (TabbedButtonBar::tabOutlineColourId, Colour (0xFF595C6B)); +} + +Typeface::Ptr MyLNF::getTypefaceForFont (const Font& font) +{ + return font.isBold() ? robotoBold : roboto; +} + +void MyLNF::drawRotarySlider (juce::Graphics& g, int x, int y, int width, int height, + float sliderPos, float rotaryStartAngle, + float rotaryEndAngle, juce::Slider& slider) +{ + int diameter = (width > height)? height : width; + if (diameter < 16) return; + + juce::Point<float> centre (x + std::floor (width * 0.5f + 0.5f), y + std::floor (height * 0.5f + 0.5f)); + diameter -= (diameter % 2)? 9 : 8; + float radius = diameter * 0.5f; + x = int (centre.x - radius); + y = int (centre.y - radius); + + const auto bounds = juce::Rectangle<int> (x, y, diameter, diameter).toFloat(); + + auto b = pointer->getBounds().toFloat(); + auto b2 = knob->getBounds().toFloat(); + pointer->setTransform (AffineTransform::rotation (MathConstants<float>::twoPi * ((sliderPos - 0.5f) * 300.0f / 360.0f), + b.getCentreX(), b.getCentreY())); + + auto knobBounds = (bounds * 0.75f).withCentre (centre); + knob->drawWithin (g, knobBounds, RectanglePlacement::stretchToFit, 1.0f); + pointer->drawWithin (g, knobBounds, RectanglePlacement::stretchToFit, 1.0f); + + const auto toAngle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle); + const juce::Colour fill = slider.findColour (juce::Slider::rotarySliderFillColourId); + constexpr float arcFactor = 0.9f; + + Path valueArc; + valueArc.addPieSegment (bounds, rotaryStartAngle, rotaryEndAngle, arcFactor); + g.setColour (Colour (0xff595c6b)); + g.fillPath (valueArc); + valueArc.clear(); + + valueArc.addPieSegment (bounds, rotaryStartAngle, toAngle, arcFactor); + g.setColour (Colour (0xff9cbcbd)); + g.fillPath (valueArc); +} + +void MyLNF::drawToggleButton (Graphics& g, ToggleButton& button, + bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) +{ + auto fontSize = jmin (15.0f, (float) button.getHeight() * 0.75f); + auto tickWidth = fontSize * 1.1f; + + drawTickBox (g, button, 4.0f, ((float) button.getHeight() - tickWidth) * 0.5f, + tickWidth, tickWidth, + button.getToggleState(), + button.isEnabled(), + shouldDrawButtonAsHighlighted, + shouldDrawButtonAsDown); + + g.setColour (button.findColour (ToggleButton::textColourId)); + g.setFont (Font (fontSize).boldened()); + + if (! button.isEnabled()) + g.setOpacity (0.5f); + + g.drawFittedText (button.getButtonText(), + button.getLocalBounds().withTrimmedLeft (roundToInt (tickWidth) + 10) + .withTrimmedRight (2), + Justification::centredLeft, 10); +} + +void MyLNF::createTabTextLayout (const TabBarButton& button, float length, float depth, + Colour colour, TextLayout& textLayout) +{ + Font font (depth * 0.45f, Font::bold); + font.setUnderline (button.hasKeyboardFocus (false)); + + AttributedString s; + s.setJustification (Justification::centred); + s.append (button.getButtonText().trim(), font, colour); + + textLayout.createLayout (s, length); +} + +void MyLNF::drawTabButton (TabBarButton& button, Graphics& g, bool /*isMouseOver*/, bool /*isMouseDown*/) +{ + const Rectangle<int> activeArea (button.getActiveArea()); + + const TabbedButtonBar::Orientation o = button.getTabbedButtonBar().getOrientation(); + + const Colour bkg (button.getTabBackgroundColour()); + + if (button.getToggleState()) + { + g.setColour (bkg); + } + else + { + Point<int> p1, p2; + + switch (o) + { + case TabbedButtonBar::TabsAtBottom: p1 = activeArea.getBottomLeft(); p2 = activeArea.getTopLeft(); break; + case TabbedButtonBar::TabsAtTop: p1 = activeArea.getTopLeft(); p2 = activeArea.getBottomLeft(); break; + case TabbedButtonBar::TabsAtRight: p1 = activeArea.getTopRight(); p2 = activeArea.getTopLeft(); break; + case TabbedButtonBar::TabsAtLeft: p1 = activeArea.getTopLeft(); p2 = activeArea.getTopRight(); break; + default: jassertfalse; break; + } + + g.setGradientFill (ColourGradient (bkg.brighter (0.2f), p1.toFloat(), + bkg.darker (0.1f), p2.toFloat(), false)); + } + + g.fillRect (activeArea); + + g.setColour (button.findColour (TabbedButtonBar::tabOutlineColourId)); + + Rectangle<int> r (activeArea); + g.fillRect (r.removeFromBottom (1)); + + const float alpha = 0.6f; + Colour col (bkg.contrasting().withMultipliedAlpha (alpha)); + + if (button.isFrontTab()) + col = Colours::white; + + const Rectangle<float> area (button.getTextArea().toFloat()); + + float length = area.getWidth(); + float depth = area.getHeight(); + + if (button.getTabbedButtonBar().isVertical()) + std::swap (length, depth); + + TextLayout textLayout; + createTabTextLayout (button, length, depth, col, textLayout); + + AffineTransform t; + + switch (o) + { + case TabbedButtonBar::TabsAtLeft: t = t.rotated (MathConstants<float>::pi * -0.5f).translated (area.getX(), area.getBottom()); break; + case TabbedButtonBar::TabsAtRight: t = t.rotated (MathConstants<float>::pi * 0.5f).translated (area.getRight(), area.getY()); break; + case TabbedButtonBar::TabsAtTop: + case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break; + default: jassertfalse; break; + } + + g.addTransform (t); + textLayout.draw (g, Rectangle<float> (length, depth)); +} + +void MyLNF::drawLinearSlider (Graphics& g, int x, int y, int width, int height, + float sliderPos, float /*minSliderPos*/, float /*maxSliderPos*/, + const Slider::SliderStyle, Slider& slider) +{ + auto trackWidth = jmin (6.0f, slider.isHorizontal() ? (float) height * 0.25f : (float) width * 0.25f); + + Point<float> startPoint (slider.isHorizontal() ? (float) x : (float) x + (float) width * 0.5f, + slider.isHorizontal() ? (float) y + (float) height * 0.5f : (float) (height + y)); + + Point<float> endPoint (slider.isHorizontal() ? (float) (width + x) : startPoint.x, + slider.isHorizontal() ? startPoint.y : (float) y); + + Path backgroundTrack; + backgroundTrack.startNewSubPath (startPoint); + backgroundTrack.lineTo (endPoint); + g.setColour (slider.findColour (Slider::backgroundColourId)); + g.strokePath (backgroundTrack, { trackWidth, PathStrokeType::curved, PathStrokeType::rounded }); + + Path valueTrack; + Point<float> minPoint, maxPoint, thumbPoint; + + { + auto kx = slider.isHorizontal() ? sliderPos : ((float) x + (float) width * 0.5f); + auto ky = slider.isHorizontal() ? ((float) y + (float) height * 0.5f) : sliderPos; + + minPoint = startPoint; + maxPoint = { kx, ky }; + } + + auto thumbWidth = getSliderThumbRadius (slider); + + valueTrack.startNewSubPath (minPoint); + valueTrack.lineTo (maxPoint); + g.setColour (slider.findColour (Slider::trackColourId)); + g.strokePath (valueTrack, { trackWidth, PathStrokeType::curved, PathStrokeType::rounded }); + + auto thumbRect = Rectangle<float> (static_cast<float> (thumbWidth), + static_cast<float> (thumbWidth)).withCentre (maxPoint); + knob->drawWithin (g, thumbRect, RectanglePlacement::stretchToFit, 1.0f); +} + +Slider::SliderLayout MyLNF::getSliderLayout (Slider& slider) +{ + auto layout = LookAndFeel_V4::getSliderLayout (slider); + + auto style = slider.getSliderStyle(); + if (style == Slider::LinearHorizontal) + layout.textBoxBounds = layout.textBoxBounds.withX (layout.sliderBounds.getX()); + + return layout; +} + +Label* MyLNF::createSliderTextBox (Slider& slider) +{ + auto l = LookAndFeel_V4::createSliderTextBox (slider); + + auto style = slider.getSliderStyle(); + if (style == Slider::LinearHorizontal) + l->setJustificationType (Justification::left); + + return l; +} + +void ComboBoxLNF::drawComboBox (Graphics& g, int width, int height, bool, int, int, int, int, ComboBox& box) +{ + auto cornerSize = 5.0f; + Rectangle<int> boxBounds (0, 0, width, height); + + g.setColour (box.findColour (ComboBox::backgroundColourId)); + g.fillRoundedRectangle (boxBounds.toFloat(), cornerSize); + + if (box.getName().isNotEmpty()) + { + g.setColour (Colours::white); + g.setFont (getComboBoxFont (box).boldened()); + auto nameBox = boxBounds.withWidth (boxBounds.proportionOfWidth (0.7f)); + g.drawFittedText (box.getName() + ": ", nameBox, Justification::right, 1); + } +} + +void ComboBoxLNF::positionComboBoxText (ComboBox& box, Label& label) +{ + auto b = box.getBounds(); + + if (box.getName().isNotEmpty()) + { + auto width = b.proportionOfWidth (0.3f); + auto x = b.proportionOfWidth (0.7f); + b = b.withX (x).withWidth (width); + } + + label.setBounds (b); + label.setFont (getComboBoxFont (box).boldened()); +} diff --git a/Plugin/Source/GUI/MyLNF.h b/Plugin/Source/GUI/MyLNF.h @@ -0,0 +1,68 @@ +#ifndef MYLNF_H_INCLUDED +#define MYLNF_H_INCLUDED + +#include <JuceHeader.h> + +class MyLNF : public LookAndFeel_V4 +{ +public: + MyLNF(); + + Typeface::Ptr getTypefaceForFont(const Font&) override; + + void drawRotarySlider (juce::Graphics& g, int x, int y, int width, int height, + float sliderPos, float rotaryStartAngle, + float rotaryEndAngle, juce::Slider& slider) override; + + void drawToggleButton (Graphics& g, ToggleButton& button, + bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override; + + void createTabTextLayout (const TabBarButton& button, float length, float depth, + Colour colour, TextLayout& textLayout); + void drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown) override; + + void drawLinearSlider (Graphics& g, int x, int y, int width, int height, + float sliderPos, float minSliderPos, float maxSliderPos, + const Slider::SliderStyle style, Slider& slider) override; + + Slider::SliderLayout getSliderLayout (Slider& slider) override; + Label* createSliderTextBox (Slider& slider) override; + +private: + std::unique_ptr<Drawable> knob = Drawable::createFromImageData (BinaryData::knob_svg, BinaryData::knob_svgSize); + std::unique_ptr<Drawable> pointer = Drawable::createFromImageData (BinaryData::pointer_svg, BinaryData::pointer_svgSize); + + Typeface::Ptr roboto; + Typeface::Ptr robotoBold; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyLNF) +}; + + +class ComboBoxLNF : public MyLNF +{ +public: + ComboBoxLNF() {} + + void drawComboBox (Graphics& g, int width, int height, bool, int, int, int, int, ComboBox& box) override; + void positionComboBoxText (ComboBox& box, Label& label) override; + + void drawPopupMenuItem (Graphics& g, const Rectangle<int>& area, + const bool isSeparator, const bool isActive, + const bool isHighlighted, const bool /*isTicked*/, + const bool hasSubMenu, const String& text, + const String& shortcutKeyText, + const Drawable* icon, const Colour* const textColourToUse) override + { + LookAndFeel_V4::drawPopupMenuItem (g, area, isSeparator, isActive, + isHighlighted, false /*isTicked*/, hasSubMenu, text, + shortcutKeyText, icon, textColourToUse); + } + +private: + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComboBoxLNF) +}; + + +#endif // MYLNF_H_INCLUDED diff --git a/Plugin/Source/GUI/TitleComp.cpp b/Plugin/Source/GUI/TitleComp.cpp @@ -0,0 +1,69 @@ +#include "TitleComp.h" + +TitleComp::TitleComp() +{ + setColour (text1ColourID, Colours::white); + setColour (text2ColourID, Colours::grey); +} + +void TitleComp::paint (Graphics& g) +{ + g.setFont (Font (font).boldened()); + auto font = g.getCurrentFont(); + auto b = getLocalBounds(); + + auto drawText = [=, &g, &b] (const String& text) + { + auto width = font.getStringWidth (text); + g.drawFittedText (text, b.removeFromLeft (width), Justification::left, 1); + }; + + g.setColour (findColour (text1ColourID)); + drawText (title + " "); + + g.setColour (findColour (text2ColourID)); + drawText (subtitle); +} + +void TitleComp::setStrings (String newTitle, String newSubtitle, float newFont) +{ + font = newFont == 0.0f ? (float) getHeight() : newFont; + + title = newTitle; + subtitle = newSubtitle; + repaint(); +} + +//====================================================================== +TitleItem::TitleItem (foleys::MagicGUIBuilder& builder, const ValueTree& node) : + foleys::GuiItem (builder, node) +{ + setColourTranslation ({ + {"text1", TitleComp::text1ColourID}, + {"text2", TitleComp::text2ColourID}, + }); + + addAndMakeVisible (comp); +} + +void TitleItem::update() +{ + auto titleString = magicBuilder.getStyleProperty (title, configNode).toString(); + auto subtitleString = magicBuilder.getStyleProperty (subtitle, configNode).toString(); + auto fontVal = (float) magicBuilder.getStyleProperty (font, configNode); + + comp.setStrings (titleString, subtitleString, fontVal); +} + +std::vector<foleys::SettableProperty> TitleItem::getSettableProperties() const +{ + std::vector<foleys::SettableProperty> properties; + properties.push_back ({ configNode, title, foleys::SettableProperty::Text, {}, {} }); + properties.push_back ({ configNode, subtitle, foleys::SettableProperty::Text, {}, {} }); + properties.push_back ({ configNode, font, foleys::SettableProperty::Number, 0.0f, {} }); + return properties; +} + +const Identifier TitleItem::title { "title" }; +const Identifier TitleItem::subtitle { "subtitle" }; +const Identifier TitleItem::font { "font" }; diff --git a/Plugin/Source/GUI/TitleComp.h b/Plugin/Source/GUI/TitleComp.h @@ -0,0 +1,51 @@ +#ifndef TITLECOMP_H_INCLUDED +#define TITLECOMP_H_INCLUDED + +#include <JuceHeader.h> + +class TitleComp : public Component, + public SettableTooltipClient +{ +public: + TitleComp(); + + enum ColourIDs + { + text1ColourID, + text2ColourID, + }; + + void paint (Graphics& g) override; + void setStrings (String newTitle, String newSubtitle, float font); + +private: + String title; + String subtitle; + float font = 0.0f; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TitleComp) +}; + +class TitleItem : public foleys::GuiItem +{ +public: + FOLEYS_DECLARE_GUI_FACTORY (TitleItem) + + static const Identifier title; + static const Identifier subtitle; + static const Identifier font; + + TitleItem (foleys::MagicGUIBuilder& builder, const ValueTree& node); + + void update() override; + std::vector<foleys::SettableProperty> getSettableProperties() const override; + + Component* getWrappedComponent() override { return &comp; } + +private: + TitleComp comp; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TitleItem) +}; + +#endif // TITLECOMP_H_INCLUDED diff --git a/Plugin/Source/GUI/TooltipComp.cpp b/Plugin/Source/GUI/TooltipComp.cpp @@ -0,0 +1,85 @@ +#include "TooltipComp.h" + +TooltipComponent::TooltipComponent() +{ + setColour (backgroundColourID, Colours::transparentBlack); + setColour (textColourID, Colours::lightgrey); + setColour (nameColourID, Colours::white); + + showTip.store (false); + startTimer (123); +} + +void TooltipComponent::paint (Graphics& g) +{ + g.fillAll (findColour (backgroundColourID)); + + if (showTip.load()) + { + auto b = getLocalBounds(); + + g.setFont (Font (17.0f).boldened()); + if (name.isNotEmpty()) + { + g.setColour (findColour (nameColourID)); + g.drawFittedText (name + ":", b, Justification::topLeft, 1); + } + + auto whitespace = String(); + auto font = g.getCurrentFont(); + while (font.getStringWidth(whitespace) < font.getStringWidth (name + ": ")) + whitespace += " "; + + g.setColour (findColour (textColourID)); + g.drawMultiLineText (whitespace + tip, b.getX(), + b.getY() + (int) font.getHeight() - 3, b.getWidth(), Justification::topLeft); + } +} + +String TooltipComponent::getTipFor (Component& c) +{ + if (Process::isForegroundProcess() + && ! ModifierKeys::currentModifiers.isAnyMouseButtonDown()) + { + if (auto* ttc = dynamic_cast<TooltipClient*> (&c)) + if (! c.isCurrentlyBlockedByAnotherModalComponent()) + return ttc->getTooltip(); + } + + return {}; +} + +void TooltipComponent::timerCallback() +{ + auto& desktop = Desktop::getInstance(); + auto mouseSource = desktop.getMainMouseSource(); + + auto* newComp = mouseSource.isTouch() ? nullptr : mouseSource.getComponentUnderMouse(); + + bool needsRepaint = false; + if (newComp != nullptr) + { + auto newTip = getTipFor (*newComp); + needsRepaint = newTip != tip; + + tip = newTip; + name = newComp->getName(); + + if (! showTip.load()) + { + showTip.store (true); + needsRepaint = true; + } + } + else + { + if (showTip.load()) + { + showTip.store (false); + needsRepaint = true; + } + } + + if (needsRepaint) + repaint(); +} diff --git a/Plugin/Source/GUI/TooltipComp.h b/Plugin/Source/GUI/TooltipComp.h @@ -0,0 +1,62 @@ +#ifndef TOOLTIPCOMP_H_INCLUDED +#define TOOLTIPCOMP_H_INCLUDED + +#include <JuceHeader.h> + +class TooltipComponent : public Component, + private Timer +{ +public: + TooltipComponent(); + + enum ColourIDs + { + backgroundColourID, + textColourID, + nameColourID, + }; + + void paint (Graphics& g) override; + void timerCallback() override; + String getTipFor (Component& c); + +private: + String name, tip; + std::atomic_bool showTip; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TooltipComponent) +}; + +class TooltipItem : public foleys::GuiItem +{ +public: + FOLEYS_DECLARE_GUI_FACTORY (TooltipItem) + + TooltipItem (foleys::MagicGUIBuilder& builder, const ValueTree& node) : + foleys::GuiItem (builder, node) + { + setColourTranslation ({ + {"tooltip-background", TooltipComponent::backgroundColourID}, + {"tooltip-text", TooltipComponent::textColourID}, + {"tooltip-name", TooltipComponent::nameColourID}, + }); + + addAndMakeVisible (tooltipComp); + } + + void update() override + { + } + + Component* getWrappedComponent() override + { + return &tooltipComp; + } + +private: + TooltipComponent tooltipComp; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TooltipItem) +}; + +#endif // TOOLTIPCOMP_H_INCLUDED diff --git a/Plugin/Source/GUI/gui.xml b/Plugin/Source/GUI/gui.xml @@ -1,100 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<magic> - <Styles> - <Style name="default"> - <Nodes/> - <Classes> - <plot-view border="2" background-color="black" border-color="silver" display="contents"/> - <nomargin margin="0" padding="0" border="0"/> - <group margin="5" padding="5" border="2" flex-direction="column"/> - </Classes> - <Types> - <Slider border="0" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below"/> - <ToggleButton border="0" max-height="50" caption-size="0" text="Active"/> - <TextButton border="0" max-height="50" caption-size="0"/> - <ComboBox border="0" max-height="50" caption-size="0"/> - <Plot border="0" margin="0" padding="0" background-color="00000000" - radius="0"/> - <XYDragComponent border="0" margin="0" padding="0" background-color="00000000" - radius="0"/> - </Types> - </Style> - </Styles> - <View id="root" resizable="1" resize-corner="1" flex-direction="column" - background-color="FF7D2C2C" padding="0" width="600" height="650"> - <View max-height="100" padding="0" background-color="FF7D2C2C" margin="0"> - <Label text="CHOW Tape Model" font-size="20" padding="0" background-color="FF7D2C2C" - border="" max-width="180"/> - <Plot source="scope" plot-fill-color="FF000000" plot-color="FFCC7D12" - padding="0" background-color="FF000000" plot-decay="0.0"/> - </View> - <View background-color="FF7D2C2C" padding="0" margin=""> - <View flex-direction="column" margin="5" padding=""> - <Label max-height="5"/> - <Slider caption="Input Gain [dB]" parameter="ingain" slider-textbox="textbox-below" - slider-type="rotary-horizontal-vertical" max-height="160"/> - <ComboBox caption="Oversampling" parameter="os" max-height="70"/> - <Slider caption="Dry/Wet" parameter="drywet" slider-textbox="textbox-below" - slider-type="rotary-horizontal-vertical" max-height="170"/> - <Slider caption="Output Gain [dB]" parameter="outgain" slider-textbox="textbox-below" - slider-type="rotary-horizontal-vertical" max-height="170"/> - </View> - <View flex-direction="column" tab-color=""> - <Label max-height="40" text="Hysteresis" font-size="18" justification="centred"/> - <Slider caption="Bias" parameter="width" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below"/> - <Slider caption="Saturation" parameter="sat" slider-textbox="textbox-below" - slider-type="rotary-horizontal-vertical"/> - <Slider caption="Drive" parameter="drive" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below"/> - <ComboBox caption="Mode" parameter="mode" max-height="70"/> - </View> - <View display="tabbed" padding="0"> - <View flex-direction="column" tab-caption="Loss" tab-color="" background-color="" - padding="0" margin="0"> - <Label max-height="40" text="Loss" justification="centred" font-size="18" - padding="0" margin="0"/> - <Slider caption="Gap [mm]" parameter="gap" slider-type="linear-horizontal" - slider-textbox="textbox-below" background-color="" padding="0"/> - <Slider caption="Thickness [mm]" parameter="thick" slider-textbox="textbox-below" - slider-type="linear-horizontal" padding="0"/> - <Slider caption="Spacing [mm]" parameter="spacing" slider-type="linear-horizontal" - slider-textbox="textbox-below" lookAndFeel="LookAndFeel_V4" padding="0"/> - <Slider caption="Speed [ips]" parameter="speed" slider-type="linear-horizontal" - slider-textbox="textbox-below" padding="0"/> - </View> - <View tab-caption="Degr." padding="0" flex-direction="column"> - <Label text="Degrade" justification="centred" font-size="18" max-height="40"/> - <Slider parameter="deg_depth" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below" - caption="Depth"/> - <Slider caption="Amount" parameter="deg_amt" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below"/> - <Slider parameter="deg_var" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below" - caption="Variance"/> - </View> - <View tab-caption="CHEW" padding="0" flex-direction="column"> - <Label text="CHEW" justification="centred" font-size="18" max-height="40"/> - <Slider parameter="chew_depth" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below" - caption="Depth" max-height="180"/> - <Slider caption="Frequency" parameter="chew_freq" slider-type="rotary-horizontal-vertical" - slider-textbox="textbox-below" max-height="200"/> - </View> - </View> - <View display="tabbed" padding="0"> - <View tab-caption="Flutter" flex-direction="column"> - <Label max-height="40" text="Flutter" justification="centred" font-size="18"/> - <Slider caption="Depth" parameter="depth" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below" - max-height="200"/> - <Slider caption="Rate" parameter="rate" slider-textbox="textbox-below" - slider-type="rotary-horizontal-vertical" max-height="200"/> - </View> - <View tab-caption="Wow" flex-direction="column"> - <Label max-height="40" text="Wow" justification="centred" font-size="18"/> - <Slider caption="Depth" parameter="wow_depth" slider-type="rotary-horizontal-vertical" slider-textbox="textbox-below" - max-height="200"/> - <Slider caption="Rate" parameter="wow_rate" slider-textbox="textbox-below" - slider-type="rotary-horizontal-vertical" max-height="200"/> - </View> - </View> - </View> - <presets max-height="30" margin="0" padding="0"/> - </View> -</magic> diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp @@ -9,6 +9,10 @@ */ #include "PluginProcessor.h" +#include "GUI/InfoComp.h" +#include "GUI/TitleComp.h" +#include "GUI/TooltipComp.h" +#include "GUI/MyLNF.h" //============================================================================== ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor() @@ -32,6 +36,8 @@ ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor() lossFilter[ch].reset (new LossFilter (vts)); scope = magicState.createAndAddObject<foleys::MagicOscilloscope> ("scope"); + + LookAndFeel::setDefaultLookAndFeel (&myLNF); } ChowtapeModelAudioProcessor::~ChowtapeModelAudioProcessor() @@ -248,6 +254,13 @@ AudioProcessorEditor* ChowtapeModelAudioProcessor::createEditor() auto builder = std::make_unique<foleys::MagicGUIBuilder> (magicState); builder->registerJUCEFactories(); presetManager.registerPresetsComponent (*builder); + builder->registerFactory ("TooltipComp", &TooltipItem::factory); + builder->registerFactory ("InfoComp", &InfoItem::factory); + builder->registerFactory ("TitleComp", &TitleItem::factory); + + builder->registerJUCELookAndFeels(); + builder->registerLookAndFeel ("MyLNF", std::make_unique<MyLNF>()); + builder->registerLookAndFeel ("ComboBoxLNF", std::make_unique<ComboBoxLNF>()); #if SAVE_PRESETS // Add button to save new presets magicState.addTrigger ("savepreset", [=] diff --git a/Plugin/Source/PluginProcessor.h b/Plugin/Source/PluginProcessor.h @@ -20,6 +20,7 @@ #include "Processors/DryWetProcessor.h" #include "Processors/Timing_Effects/DelayProcessor.h" #include "Presets/PresetManager.h" +#include "GUI/MyLNF.h" //============================================================================== /** @@ -89,6 +90,7 @@ private: foleys::MagicPlotSource* scope = nullptr; PresetManager presetManager; + MyLNF myLNF; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChowtapeModelAudioProcessor) diff --git a/Plugin/Source/Presets/PresetComp.cpp b/Plugin/Source/Presets/PresetComp.cpp @@ -6,7 +6,7 @@ PresetComp::PresetComp (ChowtapeModelAudioProcessor& proc, PresetManager& manage { manager.addListener (this); - setColour (backgroundColourId, Colour (0xFF434352)); + setColour (backgroundColourId, Colour (0xFF595C6B)); setColour (textColourId, Colours::white); addAndMakeVisible (presetBox); @@ -25,25 +25,16 @@ PresetComp::~PresetComp() void PresetComp::paint (Graphics& g) { + const auto cornerSize = 5.0f; + presetBox.setColour (PopupMenu::ColourIds::backgroundColourId, findColour (backgroundColourId)); - g.fillAll (findColour (backgroundColourId)); - - g.setColour (findColour (textColourId)); - g.setFont (getHeight() * 0.6f); - auto presetBounds = presetBox.getBounds(); - presetBounds.setWidth (100); - presetBounds.translate (-110, 0); - g.drawFittedText ("Presets:", presetBounds, Justification::centredRight, 1); - - g.setFont (getHeight() * 0.4f); - auto versionBounds = getLocalBounds().removeFromRight (50); - g.drawFittedText ("v" + String (JucePlugin_VersionString), versionBounds, Justification::centred, 1); + g.setColour (findColour (backgroundColourId)); + g.fillRoundedRectangle (getLocalBounds().toFloat(), cornerSize); } void PresetComp::resized() { - auto boxWidth = jmin (getWidth() / 3, 200); - presetBox.setBounds ((getWidth() - boxWidth) / 2, 2, boxWidth, getHeight() - 4); + presetBox.setBounds (getLocalBounds()); repaint(); } diff --git a/Plugin/Source/Presets/PresetComp.h b/Plugin/Source/Presets/PresetComp.h @@ -5,6 +5,7 @@ #include "../PluginProcessor.h" class PresetComp : public Component, + public SettableTooltipClient, private PresetManager::Listener { public: @@ -22,42 +23,9 @@ public: void presetUpdated() override; private: - class CustomComboBox : public ComboBox - { - public: - CustomComboBox (const String& name = {}) : - ComboBox (name) - { - setLookAndFeel (&comboLNF); - } - - ~CustomComboBox() - { - setLookAndFeel (nullptr); - } - - private: - class ComboLNF : public LookAndFeel_V4 - { - void drawPopupMenuItem (Graphics& g, const Rectangle<int>& area, - const bool isSeparator, const bool isActive, - const bool isHighlighted, const bool /*isTicked*/, - const bool hasSubMenu, const String& text, - const String& shortcutKeyText, - const Drawable* icon, const Colour* const textColourToUse) override - { - LookAndFeel_V4::drawPopupMenuItem (g, area, isSeparator, isActive, - isHighlighted, false /*isTicked*/, hasSubMenu, text, - shortcutKeyText, icon, textColourToUse); - } - }; - - ComboLNF comboLNF; - }; - ChowtapeModelAudioProcessor& proc; PresetManager& manager; - CustomComboBox presetBox; + ComboBox presetBox; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PresetComp) };