Vital
Loading...
Searching...
No Matches
drag_drop_effect_order.cpp
Go to the documentation of this file.
2
3#include "skin.h"
4#include "fonts.h"
5#include "paths.h"
6#include "synth_button.h"
8#include "synth_strings.h"
10#include "utils.h"
11
12namespace {
13 Path getPathForEffect(String effect) {
14 if (effect == "compressor")
15 return Paths::compressor();
16 if (effect == "chorus")
17 return Paths::chorus();
18 if (effect == "delay")
19 return Paths::delay();
20 if (effect == "distortion")
21 return Paths::distortion();
22 if (effect == "eq")
23 return Paths::equalizer();
24 if (effect == "filter")
25 return Paths::effectsFilter();
26 if (effect == "flanger")
27 return Paths::flanger();
28 if (effect == "phaser")
29 return Paths::phaser();
30 if (effect == "reverb")
31 return Paths::reverb();
32
33 return Path();
34 }
35}
36
37DraggableEffect::DraggableEffect(const String& name, int order) : SynthSection(name), order_(order), hover_(false) {
38 setInterceptsMouseClicks(false, true);
39
40 StringArray tokens;
41 tokens.addTokens(getName(), "_", "");
42 icon_ = getPathForEffect(tokens[0].toLowerCase());
43
44 background_ = std::make_unique<OpenGlImageComponent>("background");
45 addOpenGlComponent(background_.get());
46 background_->setComponent(this);
47 background_->paintEntireComponent(false);
48
49 enable_ = std::make_unique<SynthButton>(name + "_on");
50 enable_->setPowerButton();
51 addButton(enable_.get());
52 enable_->setButtonText("");
53 enable_->getGlComponent()->setAlwaysOnTop(true);
54}
55
56void DraggableEffect::paint(Graphics& g) {
57 static constexpr float kLeftPadding = 0.07f;
58 static constexpr float kIconSize = 0.6f;
59 static constexpr int kTextureRows = 2;
60 static constexpr int kTextureColumns = 3;
61 static constexpr float kTextureYStart = 0.13f;
62 static constexpr float kTexturePadding = 0.45f;
63 static constexpr float kTextureCircleRadiusPercent = 0.25f;
64
65 g.setColour(getParentComponent()->findColour(Skin::kBody, true));
66 int round_amount = findValue(Skin::kBodyRounding);
67 g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), round_amount);
68
69 if (enable_->getToggleState())
70 g.setColour(findColour(Skin::kPowerButtonOn, true));
71 else
72 g.setColour(findColour(Skin::kPowerButtonOff, true));
73 g.drawRoundedRectangle(0.5f, 0.5f, getWidth() - 1.0f, getHeight() - 1.0f, round_amount, 1.0f);
74
75 g.setFont(Fonts::instance()->proportional_regular().withPointHeight(size_ratio_ * 12.0f));
76 float text_x = getWidth() * kLeftPadding;
77 StringArray tokens;
78 tokens.addTokens(getName(), "_", "");
79 String text = tokens[0];
80 text = text.substring(0, 1).toUpperCase() + text.substring(1);
81 g.drawText(text, text_x, 0, getWidth() - text_x, getHeight(), Justification::centredLeft, true);
82
83 float icon_width = kIconSize * getHeight();
84 float icon_x = getWidth() / 2.0f + (getWidth() / 2.0f - icon_width) / 2.0f;
85 float icon_y = (getHeight() - icon_width) / 2.0f;
86 Rectangle<float> icon_bounds(icon_x, icon_y, icon_width, icon_width);
87 g.fillPath(icon_, icon_.getTransformToScaleToFit(icon_bounds, true));
88
89 if (hover_) {
90 g.setColour(findColour(Skin::kLightenScreen, true).withMultipliedAlpha(1.5f));
91
92 int width = getWidth();
93 int height = getHeight();
94 float spacing = width * (1.0f - 2.0f * kTexturePadding) / (kTextureColumns - 1.0f);
95 float radius = spacing * kTextureCircleRadiusPercent;
96 float x = width * kTexturePadding;
97 float y = height * kTextureYStart;
98 for (int c = 0; c < kTextureColumns; ++c) {
99 for (int r = 0; r < kTextureRows; ++r) {
100 g.fillEllipse(x + spacing * c - radius, y + spacing * r - radius, 2.0f * radius, 2.0f * radius);
101 g.fillEllipse(x + spacing * c - radius, height - y - spacing * r - radius, 2.0f * radius, 2.0f * radius);
102 }
103 }
104 }
105}
106
108 int width = getTitleWidth();
109 enable_->setBounds(0, 0, width, width);
110 background_->redrawImage(true);
111}
112
113void DraggableEffect::buttonClicked(Button* clicked_button) {
114 for (Listener* listener : listeners_)
115 listener->effectEnabledChanged(this, clicked_button->getToggleState());
116
117 background_->redrawImage(true);
118 SynthSection::buttonClicked(clicked_button);
119}
120
121void DraggableEffect::hover(bool hover) {
122 if (hover_ != hover) {
123 hover_ = hover;
124 background_->redrawImage(true);
125 }
126}
127
129 currently_dragged_ = nullptr;
130 currently_hovered_ = nullptr;
131 last_dragged_index_ = 0;
132 mouse_down_y_ = 0;
133 dragged_starting_y_ = 0;
134 for (int i = 0; i < vital::constants::kNumEffects; ++i) {
135 effect_order_[i] = i;
136 effect_list_.push_back(std::make_unique<DraggableEffect>(strings::kEffectOrder[i], i));
137 addSubSection(effect_list_[i].get());
138 effect_list_[i]->addListener(this);
139 effect_list_[i]->setSkinOverride(static_cast<Skin::SectionOverride>(Skin::kAllEffects + 1 + i));
140 }
141}
142
144
146 float padding = size_ratio_ * kEffectPadding;
147
148 for (int i = 0; i < vital::constants::kNumEffects; ++i) {
149 Component* effect = getEffect(i);
150 int from_y = getEffectY(i);
151 int to_y = getEffectY(i + 1);
152 effect->setBounds(0, from_y, getWidth(), to_y - from_y - padding);
153 }
154}
155
157 static constexpr float kConnectionWidth = 0.1f;
158 g.setColour(findColour(Skin::kLightenScreen, true));
159 int width = getWidth() * kConnectionWidth;
160 int center = getWidth() / 2.0f + findValue(Skin::kWidgetRoundedCorner);
161 g.fillRect(center - width / 2, 0, width, getHeight());
162}
163
166
167 DraggableEffect* current = currently_dragged_;
168 if (current)
169 current->renderOpenGlComponents(open_gl, animate);
170}
171
172void DragDropEffectOrder::mouseMove(const MouseEvent& e) {
173 int current_index = getEffectIndexFromY(e.y);
174 DraggableEffect* hover = effect_list_[effect_order_[current_index]].get();
175 if (hover != currently_hovered_) {
176 if (currently_hovered_)
177 currently_hovered_->hover(false);
178 if (hover)
179 hover->hover(true);
180 currently_hovered_ = hover;
181 }
182}
183
184void DragDropEffectOrder::mouseDown(const MouseEvent& e) {
185 mouse_down_y_ = e.y;
186 last_dragged_index_ = getEffectIndexFromY(e.y);
187 currently_dragged_ = effect_list_[effect_order_[last_dragged_index_]].get();
188 dragged_starting_y_ = currently_dragged_->getY();
189
190 currently_dragged_->setAlwaysOnTop(true);
191}
192
193void DragDropEffectOrder::mouseDrag(const MouseEvent& e) {
194 if (currently_dragged_ == nullptr)
195 return;
196
197 int delta_y = e.y - mouse_down_y_;
198 int clamped_y = vital::utils::iclamp(dragged_starting_y_ + delta_y, 0,
199 getHeight() - currently_dragged_->getHeight());
200 currently_dragged_->setTopLeftPosition(currently_dragged_->getX(), clamped_y);
201
202 int next_index = getEffectIndexFromY(e.y);
203 if (next_index != last_dragged_index_) {
204 moveEffect(last_dragged_index_, next_index);
205 last_dragged_index_ = next_index;
206 }
207}
208
209void DragDropEffectOrder::mouseUp(const MouseEvent& e) {
210 if (currently_dragged_)
211 currently_dragged_->setAlwaysOnTop(false);
212
213 currently_dragged_ = nullptr;
214 setStationaryEffectPosition(last_dragged_index_);
215}
216
217void DragDropEffectOrder::mouseExit(const MouseEvent& e) {
218 if (currently_hovered_) {
219 currently_hovered_->hover(false);
220 currently_hovered_ = nullptr;
221 }
222}
223
225 for (Listener* listener : listeners_)
226 listener->effectEnabledChanged(effect->order(), enabled);
227}
228
231 float order = controls[getName().toStdString()]->value();
233
234 for (int i = 0; i < vital::constants::kNumEffects; ++i)
236
237 for (Listener* listener : listeners_)
238 listener->orderChanged(this);
239}
240
241void DragDropEffectOrder::moveEffect(int start_index, int end_index) {
242 int delta_index = end_index - start_index;
243 if (delta_index == 0)
244 return;
245
246 int moving = effect_order_[start_index];
247
248 int direction = delta_index / abs(delta_index);
249 for (int i = start_index; i != end_index; i += direction) {
250 effect_order_[i] = effect_order_[i + direction];
252 }
253
254 effect_order_[end_index] = moving;
255
257 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
258 if (parent)
259 parent->getSynth()->valueChangedInternal(getName().toStdString(), order);
260
261 for (Listener* listener : listeners_)
262 listener->orderChanged(this);
263}
264
266 float padding = size_ratio_ * kEffectPadding;
267 Component* effect = getEffect(index);
268 int from_y = getEffectY(index);
269 int to_y = getEffectY(index + 1);
270 effect->setBounds(0, from_y, getWidth(), to_y - from_y - padding);
271}
272
275 return effect_order_[i];
276}
277
278Component* DragDropEffectOrder::getEffect(int index) const {
279 return effect_list_[getEffectIndex(index)].get();
280}
281
283 return effect_list_[getEffectIndex(index)]->enabled();
284}
285
287 float padding = size_ratio_ * kEffectPadding;
288 int index = vital::constants::kNumEffects * (y + padding / 2.0f) / (getHeight() + padding);
290}
291
292int DragDropEffectOrder::getEffectY(int index) const {
293 int padding = size_ratio_ * kEffectPadding;
294 return std::round((1.0f * index * (getHeight() + padding)) / vital::constants::kNumEffects);
295}
Listener interface for responding to changes in the drag/drop order or effect states.
Definition drag_drop_effect_order.h:129
void resized() override
Positions the DraggableEffect components based on the current order.
Definition drag_drop_effect_order.cpp:145
void setAllValues(vital::control_map &controls) override
Sets all values from a control map (e.g., restoring order from saved state).
Definition drag_drop_effect_order.cpp:229
virtual ~DragDropEffectOrder()
Destructor.
Definition drag_drop_effect_order.cpp:143
int getEffectIndexFromY(float y) const
Converts a vertical mouse position (y) to an ordered effect index.
Definition drag_drop_effect_order.cpp:286
void effectEnabledChanged(DraggableEffect *effect, bool enabled) override
Responds to enable state changes from a DraggableEffect.
Definition drag_drop_effect_order.cpp:224
int getEffectIndex(int index) const
Gets the effect’s internal index from an ordered position.
Definition drag_drop_effect_order.cpp:273
void moveEffect(int start_index, int end_index)
Moves an effect from one position to another, adjusting the order of all affected effects.
Definition drag_drop_effect_order.cpp:241
Component * getEffect(int index) const
Gets the effect component at a given ordered position.
Definition drag_drop_effect_order.cpp:278
void mouseUp(const MouseEvent &e) override
Handles mouse up events to finalize the dragged effect’s position.
Definition drag_drop_effect_order.cpp:209
void mouseDrag(const MouseEvent &e) override
Handles mouse drag events to reorder the effects dynamically.
Definition drag_drop_effect_order.cpp:193
bool effectEnabled(int index) const
Checks if the effect at a given ordered position is enabled.
Definition drag_drop_effect_order.cpp:282
void mouseExit(const MouseEvent &e) override
Resets hover states when the mouse exits the component.
Definition drag_drop_effect_order.cpp:217
static constexpr int kEffectPadding
Padding between individual effects.
Definition drag_drop_effect_order.h:123
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Renders all nested OpenGL components, including dragged effects.
Definition drag_drop_effect_order.cpp:164
void mouseDown(const MouseEvent &e) override
Handles mouse down events to initiate dragging.
Definition drag_drop_effect_order.cpp:184
DragDropEffectOrder(String name)
Constructs a DragDropEffectOrder component.
Definition drag_drop_effect_order.cpp:128
void mouseMove(const MouseEvent &e) override
Handles mouse movement to update hover states.
Definition drag_drop_effect_order.cpp:172
void setStationaryEffectPosition(int index)
Repositions the effect at the given index to its stationary position (no dragging).
Definition drag_drop_effect_order.cpp:265
void paintBackground(Graphics &g) override
Paints the background behind the effects.
Definition drag_drop_effect_order.cpp:156
Listener interface for responding to changes in the DraggableEffect’s enabled state.
Definition drag_drop_effect_order.h:24
A UI component representing an individual effect that can be enabled, disabled, and rearranged.
Definition drag_drop_effect_order.h:18
int order() const
Gets the current order (position) of this effect.
Definition drag_drop_effect_order.h:93
void hover(bool hover)
Updates the hover state visually.
Definition drag_drop_effect_order.cpp:121
void resized() override
Positions the subcomponents (like enable button) within the DraggableEffect.
Definition drag_drop_effect_order.cpp:107
void buttonClicked(Button *clicked_button) override
Handles button clicks, primarily the enable button.
Definition drag_drop_effect_order.cpp:113
DraggableEffect(const String &name, int order)
Constructs a DraggableEffect.
Definition drag_drop_effect_order.cpp:37
void paint(Graphics &g) override
Paints the DraggableEffect’s background and icon.
Definition drag_drop_effect_order.cpp:56
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Renders all nested OpenGL components.
Definition drag_drop_effect_order.h:62
static Fonts * instance()
Gets the singleton instance of the Fonts class.
Definition fonts.h:52
static Path delay()
Creates a delay effect icon path from embedded SVG data.
Definition paths.h:93
static Path phaser()
Creates a phaser effect icon path.
Definition paths.h:141
static Path equalizer()
Creates an equalizer icon path.
Definition paths.h:109
static Path chorus()
Creates a chorus icon path from embedded SVG data.
Definition paths.h:77
static Path compressor()
Creates a compressor icon path from embedded SVG data.
Definition paths.h:85
static Path reverb()
Creates a reverb effect icon path.
Definition paths.h:149
static Path distortion()
Creates a distortion effect icon path.
Definition paths.h:101
static Path flanger()
Creates a flanger effect icon path.
Definition paths.h:125
static Path effectsFilter()
Creates an effects filter icon path.
Definition paths.h:117
@ kBodyRounding
Definition skin.h:71
@ kWidgetRoundedCorner
Definition skin.h:104
@ kPowerButtonOff
Definition skin.h:138
@ kPowerButtonOn
Definition skin.h:137
@ kLightenScreen
Definition skin.h:141
@ kBody
Definition skin.h:129
SectionOverride
Identifiers for different UI sections that can have color or value overrides.
Definition skin.h:30
@ kAllEffects
Definition skin.h:45
void valueChangedInternal(const std::string &name, vital::mono_float value)
Handles internal value changes, updating the parameter and optionally notifying the host.
Definition synth_base.cpp:54
An interface class linking the Vital synthesizer backend (SynthBase) with a GUI.
Definition synth_gui_interface.h:56
SynthBase * getSynth()
Returns the SynthBase instance this interface is managing.
Definition synth_gui_interface.h:85
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
virtual void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate)
Renders all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:357
virtual void animate(bool animate)
Triggers animation state change in sub-sections if needed.
Definition synth_section.cpp:822
void addSubSection(SynthSection *section, bool show=true)
Adds a subsection (another SynthSection) as a child.
Definition synth_section.cpp:457
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
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
virtual void setAllValues(vital::control_map &controls)
Sets values for all known parameters from a control map.
Definition synth_section.cpp:827
float getTitleWidth()
Definition synth_section.cpp:629
const std::string kEffectOrder[]
Defines the processing order of various effects.
Definition synth_strings.h:225
@ kNumEffects
Definition synth_constants.h:187
force_inline int iclamp(int value, int min_val, int max_val)
Clamps an integer between [min_val, max_val].
Definition utils.h:250
void decodeFloatToOrder(int *order, mono_float float_code, int size)
Decodes a float-encoded permutation back into order.
Definition utils.cpp:55
mono_float encodeOrderToFloat(int *order, int size)
Encodes a permutation (stored in order) into a single float.
Definition utils.cpp:32
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174
Declares classes for OpenGL-based buttons used in the Vital synth UI.
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...