Vital
Loading...
Searching...
No Matches
header_section.cpp
Go to the documentation of this file.
1#include "header_section.h"
2
3#include "fonts.h"
4#include "preset_selector.h"
5#include "load_save.h"
6#include "oscilloscope.h"
7#include "tab_selector.h"
8#include "volume_section.h"
9
10class LogoButton : public Button {
11 public:
12 LogoButton(const String& name) : Button(name) {
13 image_component_.setComponent(this);
14 }
15
16 void setPaths(const Path& letter, const Path& ring) {
17 letter_ = letter;
18 ring_ = ring;
19 }
20
21 void resized() override {
22 const DropShadow shadow(Colours::white, 5, Point<int>(0, 0));
23
24 if (shadow_.getWidth() == getWidth() && shadow_.getHeight() == getHeight())
25 return;
26
27 Rectangle<float> bounds = getLocalBounds().toFloat();
28 letter_.applyTransform(letter_.getTransformToScaleToFit(bounds, true));
29 ring_.applyTransform(ring_.getTransformToScaleToFit(bounds, true));
30
31 shadow_ = Image(Image::SingleChannel, getWidth(), getHeight(), true);
32
33 Graphics shadow_g(shadow_);
34 shadow.drawForPath(shadow_g, letter_);
35 shadow.drawForPath(shadow_g, ring_);
36
37 redoImage();
38 }
39
40 void paintButton(Graphics& g, bool hover, bool down) override {
41 Rectangle<float> bounds = getLocalBounds().toFloat();
42 letter_.applyTransform(letter_.getTransformToScaleToFit(bounds, true));
43 ring_.applyTransform(ring_.getTransformToScaleToFit(bounds, true));
44
45 g.setColour(findColour(Skin::kShadow, true));
46 g.drawImageAt(shadow_, 0, 0, true);
47
48 ColourGradient letter_gradient(letter_top_color_, 0.0f, 0.0f, letter_bottom_color_, 0.0f, getHeight(), false);
49 ColourGradient ring_gradient(ring_top_color_, 0.0f, 0.0f, ring_bottom_color_, 0.0f, getHeight(), false);
50 g.setGradientFill(letter_gradient);
51 g.fillPath(letter_);
52
53 g.setGradientFill(ring_gradient);
54 g.fillPath(ring_);
55
56 if (hover) {
57 g.setColour(findColour(Skin::kLightenScreen, true));
58 g.fillEllipse(getLocalBounds().toFloat());
59 }
60 else if (down) {
61 g.setColour(findColour(Skin::kOverlayScreen, true));
62 g.fillEllipse(getLocalBounds().toFloat());
63 }
64 }
65
66 void setLetterColors(Colour top, Colour bottom) {
67 letter_top_color_ = top;
68 letter_bottom_color_ = bottom;
69 redoImage();
70 }
71
72 void setRingColors(Colour top, Colour bottom) {
73 ring_top_color_ = top;
74 ring_bottom_color_ = bottom;
75 redoImage();
76 }
77
78 void mouseEnter(const MouseEvent& e) override {
79 Button::mouseEnter(e);
80 image_component_.setColor(Colour(0xffdddddd));
81 }
82
83 void mouseExit(const MouseEvent& e) override {
84 Button::mouseExit(e);
85 image_component_.setColor(Colours::white);
86 }
87
88 OpenGlImageComponent* getImageComponent() { return &image_component_; }
89 void redoImage() { image_component_.redrawImage(true); }
90
91 private:
92 OpenGlImageComponent image_component_;
93
94 Path letter_;
95 Path ring_;
96
97 Image shadow_;
98
99 Colour letter_top_color_;
100 Colour letter_bottom_color_;
101
102 Colour ring_top_color_;
103 Colour ring_bottom_color_;
104};
105
107#if !defined(NO_TEXT_ENTRY)
108 logo_button_ = std::make_unique<LogoButton>("logo");
109 logo_button_->setPaths(Paths::vitalV(), Paths::vitalRing());
110 addAndMakeVisible(logo_button_.get());
111 addOpenGlComponent(logo_button_->getImageComponent());
112 logo_button_->addListener(this);
113#endif
114
116}
117
119 int logo_padding_y = kLogoPaddingY * size_ratio_;
120 int logo_height = getHeight() - 2 * logo_padding_y;
121 int logo_padding_x = (getWidth() - logo_height) / 2;
122 if (logo_button_)
123 logo_button_->setBounds(logo_padding_x, logo_padding_y, logo_height, logo_height);
124}
125
127 if (logo_button_) {
128 logo_button_->setRingColors(findColour(Skin::kWidgetPrimary1, true), findColour(Skin::kWidgetPrimary2, true));
129 logo_button_->setLetterColors(findColour(Skin::kWidgetSecondary1, true), findColour(Skin::kWidgetSecondary2, true));
130 }
131}
132
133void LogoSection::buttonClicked(Button* clicked_button) {
134 for (Listener* listener : listeners_)
135 listener->showAboutSection();
136}
137
138HeaderSection::HeaderSection() : SynthSection("header_section"), tab_offset_(0) {
139 logo_section_ = std::make_unique<LogoSection>();
140 addSubSection(logo_section_.get());
141 logo_section_->addListener(this);
142
143 tab_selector_ = std::make_unique<TabSelector>("tab_selector");
144 addAndMakeVisible(tab_selector_.get());
145 addOpenGlComponent(tab_selector_->getImageComponent());
146 tab_selector_->setSliderStyle(Slider::LinearBar);
147 tab_selector_->setRange(0, 3);
148 tab_selector_->addListener(this);
149 tab_selector_->setNames({"VOICE", "EFFECTS", "MATRIX", "ADVANCED"});
150 tab_selector_->setScrollWheelEnabled(false);
151
152 synth_preset_selector_ = std::make_unique<SynthPresetSelector>();
153 addSubSection(synth_preset_selector_.get());
154 synth_preset_selector_->addListener(this);
155
156
157 volume_section_ = std::make_unique<VolumeSection>("VOLUME");
158 addSubSection(volume_section_.get());
159
160 oscilloscope_ = std::make_unique<Oscilloscope>();
161 addOpenGlComponent(oscilloscope_.get());
162
163 spectrogram_ = std::make_unique<Spectrogram>();
164 addOpenGlComponent(spectrogram_.get());
165 spectrogram_->setVisible(false);
166 spectrogram_->paintBackgroundLines(false);
167 spectrogram_->setMinDb(-40.0f);
168 spectrogram_->setMaxDb(0.0f);
169
170 view_spectrogram_ = std::make_unique<SynthButton>("view_spectrogram");
171 addButton(view_spectrogram_.get());
172 view_spectrogram_->getGlComponent()->setVisible(false);
173
174 exit_temporary_button_ = std::make_unique<OpenGlShapeButton>("Exit");
175 addChildComponent(exit_temporary_button_.get());
176 addOpenGlComponent(exit_temporary_button_->getGlComponent());
177 exit_temporary_button_->addListener(this);
178 exit_temporary_button_->setShape(Paths::exitX());
179
180 temporary_tab_ = std::make_unique<PlainTextComponent>("Temporary", "");
181 addOpenGlComponent(temporary_tab_.get());
182 temporary_tab_->setFontType(PlainTextComponent::kLight);
183 temporary_tab_->setJustification(Justification::centredLeft);
184
186}
187
190
191 g.setColour(findColour(Skin::kBody, true));
192 int logo_section_width = getStandardKnobSize() + getPadding();
193 g.fillRect(0, 0, logo_section_width, getHeight());
194
197
198 g.saveState();
199 Rectangle<int> bounds = getLocalArea(synth_preset_selector_.get(), synth_preset_selector_->getLocalBounds());
200 g.reduceClipRegion(bounds);
201 g.setOrigin(bounds.getTopLeft());
202 synth_preset_selector_->paintBackground(g);
203 g.restoreState();
204
205 if (LoadSave::doesExpire()) {
206 String countdown = "Beta expires in: " + String(LoadSave::getDaysToExpire()) + " days";
207 int countdown_height = volume_section_->getY() + volume_section_->getBuffer();
208 g.setFont(Fonts::instance()->proportional_regular().withPointHeight(countdown_height / 2.0f));
209 g.setColour(findColour(Skin::kTextComponentText, true));
210 g.drawText(countdown, volume_section_->getX(), 0,
211 volume_section_->getWidth(), countdown_height, Justification::centred);
212 }
213}
214
216 static constexpr float kTextHeightRatio = 0.3f;
217 static constexpr float kPaddingLeft = 0.25f;
218
219 oscilloscope_->setColour(Skin::kBody, findColour(Skin::kBackground, true));
220 spectrogram_->setColour(Skin::kBody, findColour(Skin::kBackground, true));
221 int height = getHeight();
222 int width = getWidth();
223 int widget_margin = findValue(Skin::kWidgetMargin);
224 int large_padding = findValue(Skin::kLargePadding);
225 int logo_width = findValue(Skin::kModulationButtonWidth);
226 logo_section_->setBounds(large_padding, 0, logo_width, height);
227
228 int preset_selector_width = width / 3;
229 int preset_selector_height = height * 0.6f;
230 int preset_selector_buffer = (height - preset_selector_height) * 0.5f;
231 int preset_selector_x = (getWidth() - preset_selector_width + 2 * preset_selector_height) / 2;
232 synth_preset_selector_->setBounds(preset_selector_x, preset_selector_buffer,
233 preset_selector_width, preset_selector_height);
234
235 int component_padding = 12 * size_ratio_;
236 int volume_width = (width - synth_preset_selector_->getRight() - 2 * component_padding) / 2;
237 int oscilloscope_width = volume_width - widget_margin;
238 int oscilloscope_x = width - oscilloscope_width - large_padding;
239 volume_section_->setBounds(synth_preset_selector_->getRight() + component_padding, 0, volume_width, height);
240 oscilloscope_->setBounds(oscilloscope_x, widget_margin, oscilloscope_width, height - 2 * widget_margin);
241 view_spectrogram_->setBounds(oscilloscope_->getBounds());
242 spectrogram_->setBounds(oscilloscope_->getBounds());
243
244 int tabs_width = preset_selector_x - component_padding - tab_offset_;
245 tab_selector_->setBounds(tab_offset_, 0, tabs_width, height);
246 exit_temporary_button_->setBounds(tab_offset_, 0, height, height);
247
248 float temporary_height = getHeight() * kTextHeightRatio;
249 temporary_tab_->setTextSize(temporary_height);
250
251 int temporary_x = exit_temporary_button_->getRight() + getHeight() * kPaddingLeft;
252 int temporary_width = synth_preset_selector_->getX() - temporary_x;
253 temporary_tab_->setBounds(temporary_x, 0, temporary_width, getHeight());
254
256}
257
260 synth_preset_selector_->resetText();
261}
262
265 bool view_spectrogram = view_spectrogram_->getToggleState();
266 oscilloscope_->setVisible(!view_spectrogram);
267 spectrogram_->setVisible(view_spectrogram);
268}
269
270void HeaderSection::buttonClicked(Button* clicked_button) {
271 if (clicked_button == exit_temporary_button_.get()) {
272 for (Listener* listener : listeners_)
273 listener->clearTemporaryTab(tab_selector_->getValue());
274 setTemporaryTab("");
275 }
276 else if (clicked_button == view_spectrogram_.get()) {
277 bool view_spectrogram = view_spectrogram_->getToggleState();
278 oscilloscope_->setVisible(!view_spectrogram);
279 spectrogram_->setVisible(view_spectrogram);
280 SynthSection::buttonClicked(clicked_button);
281 }
282 else
283 SynthSection::buttonClicked(clicked_button);
284}
285
287 if (slider == tab_selector_.get()) {
288 int index = tab_selector_->getValue();
289 for (Listener* listener : listeners_)
290 listener->tabSelected(index);
291 }
292 else
294}
295
297 for (Listener* listener : listeners_)
298 listener->setPresetBrowserVisibility(visible, tab_selector_->getValue());
299}
300
302 for (Listener* listener : listeners_)
303 listener->setBankExporterVisibility(visible, tab_selector_->getValue());
304}
305
307 for (Listener* listener : listeners_)
308 listener->deleteRequested(preset);
309}
310
312 for (Listener* listener : listeners_)
313 listener->bankImported();
314}
315
316void HeaderSection::save(File preset) {
317 synth_preset_selector_->resetText();
318 synth_preset_selector_->setModified(false);
319}
320
322 temporary_tab_->setText(name);
323 tab_selector_->setVisible(name.isEmpty());
324 exit_temporary_button_->setVisible(!name.isEmpty());
325 repaint();
327}
328
330 oscilloscope_->setOscilloscopeMemory(memory);
331}
332
334 spectrogram_->setAudioMemory(memory);
335}
336
338 synth_preset_selector_->setModified(true);
339}
340
342 synth_preset_selector_->resetText();
343 synth_preset_selector_->setModified(false);
344}
static Fonts * instance()
Gets the singleton instance of the Fonts class.
Definition fonts.h:52
Interface for objects that need to be notified of events from the HeaderSection.
Definition header_section.h:96
void notifyFresh()
Marks the interface as having no unsaved changes.
Definition header_section.cpp:341
void reset() override
Resets the header, typically after loading a preset or making other state changes.
Definition header_section.cpp:258
void bankImported() override
Called when a bank of presets has been imported.
Definition header_section.cpp:311
void setAudioMemory(const vital::StereoMemory *memory)
Sets the memory used by the spectrogram for visualization.
Definition header_section.cpp:333
void save(File preset) override
Called after saving a preset, allowing the header to update its state (e.g., mark as unmodified).
Definition header_section.cpp:316
void paintBackground(Graphics &g) override
Paints the background of the header, including tab areas, preset areas, and optional expiration count...
Definition header_section.cpp:188
void sliderValueChanged(Slider *slider) override
Handles slider value changes (e.g., when the tab selector moves to a different tab).
Definition header_section.cpp:286
void setPresetBrowserVisibility(bool visible) override
Called to show or hide the preset browser.
Definition header_section.cpp:296
HeaderSection()
Constructs the HeaderSection.
Definition header_section.cpp:138
void setOscilloscopeMemory(const vital::poly_float *memory)
Sets the memory used by the oscilloscope for visualization.
Definition header_section.cpp:329
void notifyChange()
Marks the interface as having unsaved changes.
Definition header_section.cpp:337
void setAllValues(vital::control_map &controls) override
Sets parameter values for the header section.
Definition header_section.cpp:263
void resized() override
Resizes and rearranges child components within the header.
Definition header_section.cpp:215
void buttonClicked(Button *clicked_button) override
Handles button clicks within the header (e.g., toggling spectrogram, exiting temporary tabs).
Definition header_section.cpp:270
void deleteRequested(File preset) override
Handles the request to delete a given preset.
Definition header_section.cpp:306
void setBankExporterVisibility(bool visible) override
Called to show or hide the bank exporter.
Definition header_section.cpp:301
void setTemporaryTab(String name)
Sets a temporary tab name, typically when overlaying the preset browser or bank exporter.
Definition header_section.cpp:321
static bool doesExpire()
Checks if this build of Vital includes an expiration mechanism.
Definition load_save.cpp:1533
static int getDaysToExpire()
Returns the number of days remaining until expiration.
Definition load_save.cpp:1541
Definition header_section.cpp:10
void paintButton(Graphics &g, bool hover, bool down) override
Definition header_section.cpp:40
OpenGlImageComponent * getImageComponent()
Definition header_section.cpp:88
LogoButton(const String &name)
Definition header_section.cpp:12
void setRingColors(Colour top, Colour bottom)
Definition header_section.cpp:72
void setPaths(const Path &letter, const Path &ring)
Definition header_section.cpp:16
void redoImage()
Definition header_section.cpp:89
void mouseExit(const MouseEvent &e) override
Definition header_section.cpp:83
void mouseEnter(const MouseEvent &e) override
Definition header_section.cpp:78
void resized() override
Definition header_section.cpp:21
void setLetterColors(Colour top, Colour bottom)
Definition header_section.cpp:66
Interface for objects that need to respond to logo interactions.
Definition header_section.h:33
static constexpr float kLogoPaddingY
The vertical padding applied to the logo within its section.
Definition header_section.h:27
void resized() override
Positions the logo button within the section.
Definition header_section.cpp:118
void paintBackground(Graphics &g) override
Paints the background of the logo section.
Definition header_section.cpp:126
LogoSection()
Constructs the LogoSection.
Definition header_section.cpp:106
void buttonClicked(Button *clicked_button) override
Handles button click events. In this case, clicking the logo button.
Definition header_section.cpp:133
A component that uses OpenGL to render a cached image of a JUCE component or custom drawing.
Definition open_gl_image_component.h:18
void setComponent(Component *component)
Sets the component to be drawn into the OpenGL image. If not set, uses this component.
Definition open_gl_image_component.h:83
virtual void redrawImage(bool force)
Redraws the image if necessary, creating or updating the internal Image.
Definition open_gl_image_component.cpp:16
void setColor(Colour color)
Sets a color tint for the image.
Definition open_gl_image_component.h:101
static Path vitalV()
Creates the Vital 'V' logo path.
Definition paths.h:50
static Path exitX()
Definition paths.h:416
static Path vitalRing()
Creates the Vital ring logo path.
Definition paths.h:39
@ kLight
Definition open_gl_image_component.h:309
@ kWidgetMargin
Definition skin.h:103
@ kModulationButtonWidth
Definition skin.h:101
@ kLargePadding
Definition skin.h:82
@ kBackground
Definition skin.h:128
@ kWidgetPrimary2
Definition skin.h:166
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetSecondary1
Definition skin.h:168
@ kLightenScreen
Definition skin.h:141
@ kOverlayScreen
Definition skin.h:140
@ kShadow
Definition skin.h:142
@ kTextComponentText
Definition skin.h:148
@ kWidgetSecondary2
Definition skin.h:169
@ kBody
Definition skin.h:129
@ kHeader
Definition skin.h:33
@ kLogo
Definition skin.h:32
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
virtual void buttonClicked(Button *clicked_button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition synth_section.cpp:398
float getPadding()
Definition synth_section.cpp:660
PresetSelector * preset_selector_
Definition synth_section.h:816
void addSubSection(SynthSection *section, bool show=true)
Adds a subsection (another SynthSection) as a child.
Definition synth_section.cpp:457
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
void paintChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all child sections.
Definition synth_section.cpp:274
void paintKnobShadows(Graphics &g)
Paints knob shadows for all sliders.
Definition synth_section.cpp:253
float size_ratio_
Definition synth_section.h:821
void addButton(OpenGlToggleButton *button, bool show=true)
Definition synth_section.cpp:428
float findValue(Skin::ValueId value_id) const
Finds a value in the skin overrides or from the parent if not found locally.
Definition synth_section.cpp:18
float getStandardKnobSize()
Definition synth_section.cpp:656
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
virtual void sliderValueChanged(Slider *moved_slider) override
Called when a slider value changes. Updates the synth parameter accordingly.
Definition synth_section.cpp:391
virtual void setAllValues(vital::control_map &controls)
Sets values for all known parameters from a control map.
Definition synth_section.cpp:827
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
virtual void repaintBackground()
Requests a repaint of the background.
Definition synth_section.cpp:96
virtual void paintContainer(Graphics &g)
Paints the container background, body, heading, etc.
Definition synth_section.cpp:146
A specialized MemoryTemplate for two-channel (stereo) audio.
Definition memory.h:216
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
Declares the PresetSelector class which provides a UI component for selecting presets.
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
Declares the TabSelector class, a slider-based UI component for selecting tabs.