Vital
Loading...
Searching...
No Matches
synth_slider.cpp
Go to the documentation of this file.
1
3
4#include "synth_slider.h"
5
6#include <cmath>
7
8#include "skin.h"
9#include "fonts.h"
10#include "curve_look_and_feel.h"
11#include "full_interface.h"
12#include "modulation_matrix.h"
13#include "synth_gui_interface.h"
14#include "synth_section.h"
15
28
30 slider_->redoImage(false);
31}
32
34 int total_width = isHorizontal() ? getHeight() : getWidth();
35 int extra = total_width % 2;
36 return std::floor(SynthSlider::kLinearWidthPercent * total_width * 0.5f) * 2.0f + extra;
37}
38
40 if (isModulationKnob()) {
41 float radius = 1.0f - 1.0f / getWidth();
42 slider_quad_.setQuad(0, -radius, -radius, 2.0f * radius, 2.0f * radius);
43 }
44 else if (isRotaryQuad()) {
45 float thickness = findValue(Skin::kKnobArcThickness);
46 float size = findValue(Skin::kKnobArcSize) * getKnobSizeScale() + thickness;
47 float offset = findValue(Skin::kKnobOffset);
48 float radius_x = (size + 0.5f) / getWidth();
49 float center_y = 2.0f * offset / getHeight();
50 float radius_y = (size + 0.5f) / getHeight();
51 slider_quad_.setQuad(0, -radius_x, -center_y - radius_y, 2.0f * radius_x, 2.0f * radius_y);
53 }
54 else if (isHorizontalQuad()) {
55 float margin = 2.0f * (findValue(Skin::kWidgetMargin) - 0.5f) / getWidth();
56 slider_quad_.setQuad(0, -1.0f + margin, -1.0f, 2.0f - 2.0f * margin, 2.0f);
57 }
58 else if (isVerticalQuad()) {
59 float margin = 2.0f * (findValue(Skin::kWidgetMargin) - 0.5f) / getHeight();
60 slider_quad_.setQuad(0, -1.0f, -1.0f + margin, 2.0f, 2.0f - 2.0f * margin);
61 }
62}
63
64void OpenGlSlider::redoImage(bool skip_image) {
65 static constexpr float kRoundingMult = 0.4f;
66 static constexpr float kRotaryHoverBoost = 1.4f;
67 if (getWidth() <= 0 || getHeight() <= 0)
68 return;
69
70 bool horizontal = isHorizontalQuad();
71 bool vertical = isVerticalQuad();
72 if (modulation_amount_) {
73 slider_quad_.setModColor(mod_color_);
74 slider_quad_.setBackgroundColor(background_color_);
75 }
76 else {
77 slider_quad_.setModColor(Colours::transparentBlack);
78 slider_quad_.setBackgroundColor(Colours::transparentBlack);
79 }
80
81 if (isModulationKnob()) {
82 slider_quad_.setActive(true);
83 float t = getValue();
84 slider_quad_.setThumbColor(thumb_color_);
85
86 if (t > 0.0f) {
88 slider_quad_.setColor(unselected_color_);
89 slider_quad_.setAltColor(selected_color_);
90 }
91 else {
93 slider_quad_.setColor(selected_color_);
94 slider_quad_.setAltColor(unselected_color_);
95 }
96
97 if (isMouseOverOrDragging())
98 slider_quad_.setThickness(1.8f);
99 else
100 slider_quad_.setThickness(1.0f);
101 }
102 else if (isRotaryQuad()) {
103 slider_quad_.setActive(true);
104 float arc = slider_quad_.getMaxArc();
105 float t = valueToProportionOfLength(getValue());
106 slider_quad_.setShaderValue(0, vital::utils::interpolate(-arc, arc, t));
107 slider_quad_.setColor(selected_color_);
108 slider_quad_.setAltColor(unselected_color_);
109 slider_quad_.setThumbColor(thumb_color_);
110 slider_quad_.setStartPos(bipolar_ ? 0.0f : -vital::kPi);
111
112 float thickness = findValue(Skin::kKnobArcThickness);
113 if (isMouseOverOrDragging())
114 thickness *= kRotaryHoverBoost;
115 slider_quad_.setThickness(thickness);
116 }
117 else if (horizontal || vertical) {
118 slider_quad_.setActive(true);
119 float t = valueToProportionOfLength(getValue());
120 slider_quad_.setShaderValue(0, t);
121 slider_quad_.setColor(selected_color_);
122 slider_quad_.setAltColor(unselected_color_);
123 slider_quad_.setThumbColor(thumb_color_);
124 slider_quad_.setStartPos(bipolar_ ? 0.0f : -1.0f);
125
126 int total_width = horizontal ? getHeight() : getWidth();
127 float slider_width = getLinearSliderWidth();
128 float handle_width = SynthSlider::kLinearHandlePercent * total_width;
129 if (isMouseOverOrDragging()) {
130 int boost = std::round(slider_width / 8.0f) + 1.0f;
131 slider_quad_.setThickness(slider_width + 2 * boost);
132 }
133 else
134 slider_quad_.setThickness(slider_width);
135 slider_quad_.setRounding(slider_width * kRoundingMult);
136 slider_quad_.setThumbAmount(handle_width);
137 }
138 else if (!skip_image) {
139 image_component_.setActive(true);
140 image_component_.redrawImage(true);
141 }
142}
143
145 if (getWidth() <= 0)
146 return;
147
148 thumb_color_ = getThumbColor();
149 selected_color_ = getSelectedColor();
150 unselected_color_ = getUnselectedColor();
151 background_color_ = getBackgroundColor();
152 mod_color_ = getModColor();
153}
154
155SynthSlider::SynthSlider(String name) : OpenGlSlider(name), show_popup_on_hover_(true), scroll_enabled_(true),
156 bipolar_modulation_(false), stereo_modulation_(false),
157 bypass_modulation_(false), modulation_bar_right_(true),
158 snap_to_value_(false), hovering_(false),
159 has_parameter_assignment_(false),
160 use_suffix_(true), snap_value_(0.0),
161 text_height_percentage_(0.0f), knob_size_scale_(1.0f),
162 sensitivity_(kDefaultSensitivity),
163 popup_placement_(BubbleComponent::below),
164 modulation_control_placement_(BubbleComponent::below),
165 max_display_characters_(kDefaultFormatLength),
166 max_decimal_places_(kDefaultFormatDecimalPlaces), shift_index_amount_(0),
167 shift_is_multiplicative_(false), mouse_wheel_index_movement_(1.0),
168 text_entry_width_percent_(kDefaultTextEntryWidthPercent),
169 text_entry_height_percent_(kDefaultTextEntryHeightPercent),
170 display_multiply_(0.0f), display_exponential_base_(2.0f),
171 string_lookup_(nullptr), extra_modulation_target_(nullptr),
172 synth_interface_(nullptr) {
173 text_entry_ = std::make_unique<OpenGlTextEditor>("text_entry");
174 text_entry_->setMonospace();
175 text_entry_->setMultiLine(false);
176 text_entry_->setScrollToShowCursor(false);
177 text_entry_->addListener(this);
178 text_entry_->setSelectAllWhenFocused(true);
179 text_entry_->setKeyboardType(TextEditor::numericKeyboard);
180 text_entry_->setJustification(Justification::centred);
181 text_entry_->setAlwaysOnTop(true);
182 text_entry_->getImageComponent()->setAlwaysOnTop(true);
183 addChildComponent(text_entry_.get());
184
185 setWantsKeyboardFocus(true);
186 setTextBoxStyle(Slider::NoTextBox, true, 0, 0);
187
190 return;
191
192 setRotaryParameters(2.0f * vital::kPi - kRotaryAngle, 2.0f * vital::kPi + kRotaryAngle, true);
193
194 details_ = vital::Parameters::getDetails(name.toStdString());
196
199 setDoubleClickReturnValue(true, details_.default_value);
200 setVelocityBasedMode(false);
201 setVelocityModeParameters(1.0, 0, 0.0, false, ModifierKeys::ctrlAltCommandModifiers);
202}
203
205 PopupItems options;
206
207 if (isDoubleClickReturnEnabled())
208 options.addItem(kDefaultValue, "Set to Default Value");
209
211 options.addItem(kArmMidiLearn, "Learn MIDI Assignment");
212
213 if (has_parameter_assignment_ && synth_interface_->getSynth()->isMidiMapped(getName().toStdString()))
214 options.addItem(kClearMidiLearn, "Clear MIDI Assignment");
215
216 options.addItem(kManualEntry, "Enter Value");
217
218 std::vector<vital::ModulationConnection*> connections = getConnections();
219 if (!connections.empty())
220 options.addItem(-1, "");
221
222 std::string disconnect = "Disconnect from ";
223 for (int i = 0; i < connections.size(); ++i) {
224 std::string name = ModulationMatrix::getMenuSourceDisplayName(connections[i]->source_name).toStdString();
225 options.addItem(kModulationList + i, disconnect + name);
226 }
227
228 if (connections.size() > 1)
229 options.addItem(kClearModulations, "Disconnect all modulations");
230
231 return options;
232}
233
234void SynthSlider::mouseDown(const MouseEvent& e) {
236
237 if (e.mods.isAltDown()) {
239 return;
240 }
241
242 if (e.mods.isPopupMenu()) {
243 PopupItems options = createPopupMenu();
244 parent_->showPopupSelector(this, e.getPosition(), options, [=](int selection) { handlePopupResult(selection); });
245 }
246 else {
247 if (isRotary())
248 setMouseDragSensitivity(kDefaultRotaryDragLength / sensitivity_);
249 else {
250 setSliderSnapsToMousePosition(false);
251 setMouseDragSensitivity(std::max(getWidth(), getHeight()) / sensitivity_);
252 }
253
254 OpenGlSlider::mouseDown(e);
255 synth->beginChangeGesture(getName().toStdString());
256
257 for (SliderListener* listener : slider_listeners_)
258 listener->mouseDown(this);
259
260 showPopup(true);
261 }
262}
263
264void SynthSlider::mouseDrag(const MouseEvent& e) {
265 if (e.mods.isAltDown())
266 return;
267
268 float multiply = 1.0f;
269 if (e.mods.isShiftDown() && shift_index_amount_) {
270 double value = getValue();
271 int value_from_min = value - details_.min;
272 int shift = value_from_min % shift_index_amount_;
273 int min = details_.min + shift;
274 double max = details_.max;
275 if (shift)
276 max = std::max<double>(details_.max + shift - shift_index_amount_, value);
277 if (value < min || value > max)
278 setValue(vital::utils::clamp(value, min, max));
279 setRange(min, max, shift_index_amount_);
280 multiply = std::max(1, shift_index_amount_ / 2);
281 }
282 else
284
285 sensitive_mode_ = e.mods.isCommandDown();
286 if (sensitive_mode_)
287 multiply *= kSlowDragMultiplier;
288
289 if (isRotary())
290 setMouseDragSensitivity(kDefaultRotaryDragLength / (sensitivity_ * multiply));
291 else {
292 setSliderSnapsToMousePosition(false);
293 setMouseDragSensitivity(std::max(getWidth(), getHeight()) / (sensitivity_ * multiply));
294 }
295
296 OpenGlSlider::mouseDrag(e);
297
298 if (!e.mods.isPopupMenu())
299 showPopup(true);
300}
301
302void SynthSlider::mouseUp(const MouseEvent& e) {
303 if (e.mods.isPopupMenu() || e.mods.isAltDown())
304 return;
305
307 OpenGlSlider::mouseUp(e);
308
309 for (SliderListener* listener : slider_listeners_)
310 listener->mouseUp(this);
311
312 synth_interface_->getSynth()->endChangeGesture(getName().toStdString());
313}
314
315void SynthSlider::mouseEnter(const MouseEvent &e) {
316 OpenGlSlider::mouseEnter(e);
318 listener->hoverStarted(this);
319
321 showPopup(true);
322
323 hovering_ = true;
324 redoImage();
325}
326
327void SynthSlider::mouseExit(const MouseEvent &e) {
328 OpenGlSlider::mouseExit(e);
330 listener->hoverEnded(this);
331
332 hidePopup(true);
333 hovering_ = false;
334 redoImage();
335}
336
337void SynthSlider::mouseDoubleClick(const MouseEvent& e) {
338 OpenGlSlider::mouseDoubleClick(e);
339 if (!e.mods.isPopupMenu()) {
340 for (SliderListener* listener : slider_listeners_)
341 listener->doubleClick(this);
342 }
343 showPopup(true);
344}
345
346void SynthSlider::mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) {
347 double interval = getInterval();
348 if (scroll_enabled_ && !wheel.isSmooth && getInterval() > 0) {
349 if (shift_index_amount_ && e.mods.isShiftDown()) {
350 interval = shift_index_amount_;
352 if (wheel.deltaY > 0.0f)
353 setValue(getValue() * interval * mouse_wheel_index_movement_);
354 else
355 setValue(getValue() / std::max(1.0, (interval * mouse_wheel_index_movement_)));
356 }
357 }
358
359 if (wheel.deltaY > 0.0f)
360 setValue(getValue() + interval * mouse_wheel_index_movement_);
361 else
362 setValue(getValue() - interval * mouse_wheel_index_movement_);
363 }
364 else
365 OpenGlSlider::mouseWheelMove(e, wheel);
366
367 showPopup(true);
368}
369
370void SynthSlider::focusLost(FocusChangeType cause) {
372 listener->focusLost(this);
373}
374
379
382 return OpenGlSlider::getTextFromValue(value);
383
384 return String(getAdjustedValue(value));
385}
386
388 if (string_lookup_) {
389 int lookup = vital::utils::iclamp(value, 0, getMaximum());
390 return string_lookup_[lookup];
391 }
392
394 return OpenGlSlider::getTextFromValue(value);
395
396 double adjusted_value = getAdjustedValue(value);
397 if (popupSuffix_.isEmpty()) {
398 return popup_prefix_ + formatValue(adjusted_value);
399 } else {
400 return popup_prefix_ + formatValue(adjusted_value) + popupSuffix_;
401 }
402}
403
404String SynthSlider::getTextFromValue(double value) {
405 if (isText() && has_parameter_assignment_ && popup_prefix_.isEmpty()) {
406 if (details_.local_description.empty())
407 return details_.display_name;
409 }
410 if (isText() && !popup_prefix_.isEmpty())
411 return popup_prefix_;
412 return getSliderTextFromValue(value);
413}
414
415double SynthSlider::getValueFromText(const String& text) {
416 String cleaned = text.removeCharacters(" ").toLowerCase();
417 if (string_lookup_) {
418 for (int i = 0; i <= getMaximum(); ++i) {
419 if (cleaned == String(string_lookup_[i]).toLowerCase())
420 return i;
421 }
422 }
423 if (text.endsWithChar('%') && getDisplayDetails()->display_units != "%") {
424 float t = 0.01f * cleaned.removeCharacters("%").getDoubleValue();
425 return (getMaximum() - getMinimum()) * t + getMinimum();
426 }
427 return getValueFromAdjusted(Slider::getValueFromText(text));
428}
429
430double SynthSlider::getAdjustedValue(double value) {
432
433 double adjusted_value = value;
434 switch (details->value_scale) {
436 adjusted_value *= adjusted_value;
437 break;
439 adjusted_value *= adjusted_value * adjusted_value;
440 break;
442 adjusted_value *= adjusted_value;
443 adjusted_value *= adjusted_value;
444 break;
446 adjusted_value = powf(display_exponential_base_, adjusted_value);
447 break;
449 adjusted_value = sqrtf(std::max(adjusted_value, 0.0));
450 break;
451 default:
452 break;
453 }
454
455 adjusted_value += details->post_offset;
456 if (details->display_invert)
457 adjusted_value = 1.0 / adjusted_value;
459 adjusted_value *= display_multiply_;
460 else
461 adjusted_value *= details->display_multiply;
462
463 return adjusted_value;
464}
465
468
469 double readjusted_value = value;
471 readjusted_value /= display_multiply_;
472 else
473 readjusted_value /= details->display_multiply;
474
475 if (details->display_invert)
476 readjusted_value = 1.0 / readjusted_value;
477 readjusted_value -= details->post_offset;
478
479 switch (details->value_scale) {
481 return sqrtf(std::max(readjusted_value, 0.0));
483 return powf(std::max(readjusted_value, 0.0), 1.0f / 3.0f);
485 return sqrtf(sqrtf(std::max(readjusted_value, 0.0)));
487 return log(readjusted_value) / std::log(display_exponential_base_);
489 return readjusted_value * readjusted_value;
490 default:
491 return readjusted_value;
492 }
493}
494
496 setValue(getValueFromAdjusted(value));
497}
498
500 synth_interface_ = findParentComponentOfClass<SynthGuiInterface>();
502}
503
504double SynthSlider::snapValue(double attempted_value, DragMode drag_mode) {
505 const double percent = 0.05;
506 if (!snap_to_value_ || sensitive_mode_ || drag_mode != DragMode::absoluteDrag)
507 return attempted_value;
508
509 double range = getMaximum() - getMinimum();
510 double radius = percent * range;
512 return snap_value_;
513 return attempted_value;
514}
515
519
520void SynthSlider::textEditorFocusLost(TextEditor& editor) {
522}
523
525 if (text_entry_ && !text_entry_->getText().isEmpty())
526 setValue(getValueFromText(text_entry_->getText()));
527 text_entry_->setVisible(false);
528
529 for (SliderListener* listener : slider_listeners_)
530 listener->menuFinished(this);
531}
532
534#if !defined(NO_TEXT_ENTRY)
535 text_entry_->setColour(CaretComponent::caretColourId, findColour(Skin::kTextEditorCaret, true));
536 text_entry_->setColour(TextEditor::textColourId, findColour(Skin::kBodyText, true));
537 text_entry_->setColour(TextEditor::highlightedTextColourId, findColour(Skin::kBodyText, true));
538 text_entry_->setColour(TextEditor::highlightColourId, findColour(Skin::kTextEditorSelection, true));
539 if (isRotary())
541 else
543 text_entry_->setVisible(true);
544
545 text_entry_->redoImage();
546 text_entry_->setText(getRawTextFromValue(getValue()));
547 text_entry_->selectAll();
548 if (text_entry_->isShowing())
549 text_entry_->grabKeyboardFocus();
550#endif
551}
552
553void SynthSlider::drawShadow(Graphics &g) {
554 if (isRotary() && !isTextOrCurve())
556 else if (&getLookAndFeel() == CurveLookAndFeel::instance()) {
557 g.setColour(findColour(Skin::kWidgetBackground, true));
558 float rounding = findValue(Skin::kWidgetRoundedCorner);
559 g.fillRoundedRectangle(getBounds().toFloat(), rounding);
560 }
561}
562
564 Colour shadow_color = findColour(Skin::kShadow, true);
565
566 float center_x = getWidth() / 2.0f;
567 float center_y = getHeight() / 2.0f;
568 float stroke_width = findValue(Skin::kKnobArcThickness);
569 float radius = knob_size_scale_ * findValue(Skin::kKnobArcSize) / 2.0f;
570 center_y += findValue(Skin::kKnobOffset);
571 float shadow_width = findValue(Skin::kKnobShadowWidth);
572 float shadow_offset = findValue(Skin::kKnobShadowOffset);
573
574 PathStrokeType outer_stroke(stroke_width, PathStrokeType::beveled, PathStrokeType::rounded);
575 PathStrokeType shadow_stroke(stroke_width + 1, PathStrokeType::beveled, PathStrokeType::rounded);
576
577 g.saveState();
578 g.setOrigin(getX(), getY());
579
580 Colour body = findColour(Skin::kRotaryBody, true);
581 float body_radius = knob_size_scale_ * findValue(Skin::kKnobBodySize) / 2.0f;
582 if (body_radius >= 0.0f && body_radius < getWidth()) {
583
584 if (shadow_width > 0.0f) {
585 Colour transparent_shadow = shadow_color.withAlpha(0.0f);
586 float shadow_radius = body_radius + shadow_width;
587 ColourGradient shadow_gradient(shadow_color, center_x, center_y + shadow_offset,
588 transparent_shadow, center_x - shadow_radius, center_y + shadow_offset, true);
589 float shadow_start = std::max(0.0f, (body_radius - std::abs(shadow_offset))) / shadow_radius;
590 shadow_gradient.addColour(shadow_start, shadow_color);
591 shadow_gradient.addColour(1.0f - (1.0f - shadow_start) * 0.75f, shadow_color.withMultipliedAlpha(0.5625f));
592 shadow_gradient.addColour(1.0f - (1.0f - shadow_start) * 0.5f, shadow_color.withMultipliedAlpha(0.25f));
593 shadow_gradient.addColour(1.0f - (1.0f - shadow_start) * 0.25f, shadow_color.withMultipliedAlpha(0.0625f));
594 g.setGradientFill(shadow_gradient);
595 g.fillRect(getLocalBounds());
596 }
597
598 g.setColour(body);
599 Rectangle<float> ellipse(center_x - body_radius, center_y - body_radius, 2.0f * body_radius, 2.0f * body_radius);
600 g.fillEllipse(ellipse);
601
602 g.setColour(findColour(Skin::kRotaryBodyBorder, true));
603 g.drawEllipse(ellipse.reduced(0.5f), 1.0f);
604 }
605
606 Path shadow_outline;
607 Path shadow_path;
608
609 shadow_outline.addCentredArc(center_x, center_y, radius, radius,
610 0, -kRotaryAngle, kRotaryAngle, true);
611 shadow_stroke.createStrokedPath(shadow_path, shadow_outline);
612 if ((!findColour(Skin::kRotaryArcUnselected, true).isTransparent() && isActive()) ||
613 (!findColour(Skin::kRotaryArcUnselectedDisabled, true).isTransparent() && !isActive())) {
614 g.setColour(shadow_color);
615 g.fillPath(shadow_path);
616 }
617
618 g.restoreState();
619}
620
623 return;
624
626 setRange(details_.min, details_.max, 1.0f);
627 else
628 setRange(details_.min, details_.max);
629}
630
634
635void SynthSlider::showPopup(bool primary) {
636 if (shouldShowPopup())
637 parent_->showPopupDisplay(this, getTextFromValue(getValue()).toStdString(), popup_placement_, primary);
638}
639
640void SynthSlider::hidePopup(bool primary) {
641 parent_->hidePopupDisplay(primary);
642}
643
644String SynthSlider::formatValue(float value) {
645 String format;
647 format = String(value);
648 else {
649 if (max_decimal_places_ == 0)
650 format = String(std::roundf(value));
651 else
652 format = String(value, max_decimal_places_);
653
654 int display_characters = max_display_characters_;
655 if (format[0] == '-')
656 display_characters += 1;
657
658 format = format.substring(0, display_characters);
659 if (format.getLastCharacter() == '.')
660 format = format.removeCharacters(".");
661 }
662
663 if (use_suffix_)
664 return format + getDisplayDetails()->display_units;
665 return format;
666}
667
670 listener->guiChanged(this);
671}
672
674 static constexpr int kTextBarSize = 2;
675
676 Rectangle<int> mod_bounds = getModulationArea();
677 if (isTextOrCurve()) {
679 return mod_bounds.removeFromRight(kTextBarSize);
680
681 return mod_bounds.removeFromLeft(kTextBarSize);
682 }
683 else if (isRotary())
684 return getLocalBounds();
685
686 int buffer = findValue(Skin::kWidgetMargin);
687 if (getSliderStyle() == LinearBar) {
688 return Rectangle<int>(mod_bounds.getX() + buffer, mod_bounds.getY(),
689 mod_bounds.getWidth() - 2 * buffer, mod_bounds.getHeight());
690 }
691 return Rectangle<int>(mod_bounds.getX(), mod_bounds.getY() + buffer,
692 mod_bounds.getWidth(), mod_bounds.getHeight() - 2 * buffer);
693}
694
695std::vector<vital::ModulationConnection*> SynthSlider::getConnections() {
696 if (synth_interface_ == nullptr)
697 return std::vector<vital::ModulationConnection*>();
698
700 return synth->getDestinationConnections(getName().toStdString());
701}
702
705 std::vector<vital::ModulationConnection*> connections = getConnections();
706
707 if (result == kArmMidiLearn)
708 synth->armMidiLearn(getName().toStdString());
709 else if (result == kClearMidiLearn)
710 synth->clearMidiLearn(getName().toStdString());
711 else if (result == kDefaultValue)
712 setValue(getDoubleClickReturnValue());
713 else if (result == kManualEntry)
715 else if (result == kClearModulations) {
716 for (vital::ModulationConnection* connection : connections) {
717 std::string source = connection->source_name;
719 }
721 }
722 else if (result >= kModulationList) {
723 int connection_index = result - kModulationList;
724 std::string source = connections[connection_index]->source_name;
725 synth_interface_->disconnectModulation(connections[connection_index]);
727 }
728}
729
731 int text_width = getWidth() * text_entry_width_percent_;
732 float font_size = findValue(Skin::kTextComponentFontSize);
733 int text_height = font_size / kTextEntryHeightPercent;
734 float y_offset = 0.0f;
735 if (isText())
737
738 text_entry_->setBounds((getWidth() - text_width) / 2, (getHeight() - text_height + 1) / 2 + y_offset,
739 text_width, text_height);
740}
741
743 static constexpr float kTextEntryWidthRatio = 3.0f;
744
745 float font_size = findValue(Skin::kTextComponentFontSize);
746 int text_height = font_size / kTextEntryHeightPercent;
747 int text_width = text_height * kTextEntryWidthRatio;
748
749 text_entry_->setBounds((getWidth() - text_width) / 2, (getHeight() - text_height) / 2, text_width, text_height);
750}
751
754 listener->modulationAmountChanged(this);
755}
756
759 listener->modulationRemoved(this);
760}
761
764 listener->modulationsChanged(getName().toStdString());
765}
766
static CurveLookAndFeel * instance()
Gets the singleton instance of CurveLookAndFeel.
Definition curve_look_and_feel.h:52
static String getMenuSourceDisplayName(const String &original)
Returns a user-friendly display name for a given source string in menu context.
Definition modulation_matrix.cpp:513
void setBackgroundColor(const Colour &color)
Sets the background color of the component for painting operations.
Definition open_gl_component.h:242
virtual void init(OpenGlWrapper &open_gl)
Initializes any OpenGL-specific resources needed by the component.
Definition open_gl_component.cpp:148
void setActive(bool active)
Sets whether this component is active (rendered) or not.
Definition open_gl_image_component.h:113
virtual void redrawImage(bool force)
Redraws the image if necessary, creating or updating the internal Image.
Definition open_gl_image_component.cpp:16
void setThickness(float thickness, bool reset=false)
Sets the thickness used by some shaders and can reset to this thickness.
Definition open_gl_multi_quad.h:338
void setActive(bool active)
Activates or deactivates rendering of this component.
Definition open_gl_multi_quad.h:331
void setShaderValue(int i, float shader_value, int value_index=0)
Sets a shader value for all four vertices of a quad.
Definition open_gl_multi_quad.h:254
void setQuad(int i, float x, float y, float w, float h)
Sets the position and size of a quad in normalized device space.
Definition open_gl_multi_quad.h:313
force_inline void setAltColor(Colour color)
Sets an alternate color, often used by custom shaders.
Definition open_gl_multi_quad.h:118
void setFragmentShader(Shaders::FragmentShader shader)
Sets the fragment shader used to render the quads.
Definition open_gl_multi_quad.h:86
force_inline void setColor(Colour color)
Sets the base color for the quads.
Definition open_gl_multi_quad.h:102
force_inline void setStartPos(float pos)
Sets a starting position used by some shaders (e.g., arc start).
Definition open_gl_multi_quad.h:150
force_inline void setThumbAmount(float amount)
Sets the amount of thumb exposure (used in certain shader effects).
Definition open_gl_multi_quad.h:142
force_inline float getMaxArc()
Gets the current maximum arc value.
Definition open_gl_multi_quad.h:166
force_inline void setThumbColor(Colour color)
Sets a "thumb" color, potentially for scroll bars or similar widgets.
Definition open_gl_multi_quad.h:134
void setRounding(float rounding)
Sets the rounding radius of the quads.
Definition open_gl_multi_quad.h:347
force_inline void setModColor(Colour color)
Sets a modulation color for custom effects in the shader.
Definition open_gl_multi_quad.h:126
An extended JUCE Slider that leverages OpenGL for rendering.
Definition synth_slider.h:52
bool isRotaryQuad() const
Definition synth_slider.h:117
bool isText() const
Definition synth_slider.h:99
virtual Colour getUnselectedColor() const
Definition synth_slider.h:209
virtual float findValue(Skin::ValueId value_id) const
Definition synth_slider.h:269
virtual float getKnobSizeScale() const
Definition synth_slider.h:164
virtual Colour getModColor() const
Definition synth_slider.h:197
bool isHorizontalQuad() const
Definition synth_slider.h:123
bool isTextOrCurve() const
Definition synth_slider.h:105
virtual Colour getBackgroundColor() const
Definition synth_slider.h:203
virtual void valueChanged() override
Called when the slider value changes. Redraws the image to reflect the new value.
Definition synth_slider.h:80
virtual Colour getThumbColor() const
Definition synth_slider.h:242
void parentHierarchyChanged() override
Called when the parent hierarchy changes. Used for retrieving parent sections.
Definition synth_slider.h:86
void setColors()
Updates internal colors based on the current skin and state.
Definition synth_slider.cpp:144
int getLinearSliderWidth()
Definition synth_slider.cpp:33
void setSliderDisplayValues()
Sets the slider display values (positions, sizes) based on current style.
Definition synth_slider.cpp:39
void redoImage(bool skip_image=false)
Definition synth_slider.cpp:64
virtual Colour getSelectedColor() const
Definition synth_slider.h:223
static constexpr float kRotaryAngle
The default rotary arc angle used for rotary sliders.
Definition synth_slider.h:55
bool isVerticalQuad() const
Definition synth_slider.h:129
bool isModulationKnob() const
Definition synth_slider.h:111
SynthSection * parent_
The parent SynthSection.
Definition synth_slider.h:289
bool isActive() const
Definition synth_slider.h:172
virtual void init(OpenGlWrapper &open_gl) override
Definition synth_slider.cpp:16
void paintBackground(Graphics &g) override
Definition synth_slider.cpp:29
@ kHorizontalSliderFragment
Definition shaders.h:73
@ kRotarySliderFragment
Definition shaders.h:71
@ kModulationKnobFragment
Definition shaders.h:76
@ kVerticalSliderFragment
Definition shaders.h:74
@ kWidgetMargin
Definition skin.h:103
@ kKnobBodySize
Definition skin.h:91
@ kTextComponentFontSize
Definition skin.h:86
@ kKnobArcSize
Definition skin.h:89
@ kTextComponentOffset
Definition skin.h:85
@ kKnobOffset
Definition skin.h:97
@ kKnobHandleLength
Definition skin.h:92
@ kKnobShadowOffset
Definition skin.h:100
@ kWidgetRoundedCorner
Definition skin.h:104
@ kKnobArcThickness
Definition skin.h:90
@ kKnobShadowWidth
Definition skin.h:99
@ kRotaryArcUnselectedDisabled
Definition skin.h:153
@ kRotaryBody
Definition skin.h:155
@ kRotaryBodyBorder
Definition skin.h:156
@ kWidgetBackground
Definition skin.h:173
@ kBodyText
Definition skin.h:133
@ kRotaryArcUnselected
Definition skin.h:152
@ kShadow
Definition skin.h:142
@ kTextEditorSelection
Definition skin.h:203
@ kTextEditorCaret
Definition skin.h:202
A base class providing foundational functionality for the Vital synthesizer’s engine,...
Definition synth_base.h:42
virtual void beginChangeGesture(const std::string &name)
Called when a parameter change gesture begins. Typically not implemented in this base class.
Definition synth_base.h:356
bool isMidiMapped(const std::string &name)
Checks if a given parameter name is MIDI mapped.
Definition synth_base.cpp:677
virtual void endChangeGesture(const std::string &name)
Called when a parameter change gesture ends. Typically not implemented in this base class.
Definition synth_base.h:363
void clearMidiLearn(const std::string &name)
Clears the MIDI mapping for a given parameter name.
Definition synth_base.cpp:673
std::vector< vital::ModulationConnection * > getDestinationConnections(const std::string &destination)
Returns all modulation connections targeting a given destination parameter.
Definition synth_base.cpp:253
void armMidiLearn(const std::string &name)
Arms the given parameter name for MIDI learn, associating the next received MIDI control with it.
Definition synth_base.cpp:665
SynthBase * getSynth()
Returns the SynthBase instance this interface is managing.
Definition synth_gui_interface.h:85
void disconnectModulation(std::string source, std::string destination)
Disconnects a modulation from the GUI layer.
Definition synth_gui_interface.cpp:146
void hidePopupDisplay(bool primary)
Hides the currently shown popup display.
Definition synth_section.cpp:140
void showPopupSelector(Component *source, Point< int > position, const PopupItems &options, std::function< void(int)> callback, std::function< void()> cancel={ })
Shows a popup selector with options.
Definition synth_section.cpp:119
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 showPopupDisplay(Component *source, const std::string &text, BubbleComponent::BubblePlacement placement, bool primary)
Shows a brief popup display (like a tooltip).
Definition synth_section.cpp:133
Listener interface for receiving slider events such as mouse interactions, modulation changes,...
Definition synth_slider.h:347
float snap_value_
Definition synth_slider.h:738
float knob_size_scale_
Definition synth_slider.h:740
double getAdjustedValue(double value)
Definition synth_slider.cpp:430
void textEditorReturnKeyPressed(TextEditor &editor) override
Definition synth_slider.cpp:516
int shift_index_amount_
Definition synth_slider.h:746
virtual bool shouldShowPopup()
Definition synth_slider.h:440
double getValueFromAdjusted(double value)
Definition synth_slider.cpp:466
virtual void parentHierarchyChanged() override
Called when the parent hierarchy changes, updates references to synthesizer.
Definition synth_slider.cpp:499
void setStringLookup(const std::string *lookup)
Definition synth_slider.h:470
BubbleComponent::BubblePlacement popup_placement_
Definition synth_slider.h:742
bool has_parameter_assignment_
Definition synth_slider.h:736
virtual void focusLost(FocusChangeType cause) override
Definition synth_slider.cpp:370
void setLinearTextEntryBounds()
Sets bounds for text entry in linear mode.
Definition synth_slider.cpp:742
virtual void valueChanged() override
Called when the slider value changes. Notifies GUIs.
Definition synth_slider.cpp:375
virtual void mouseDrag(const MouseEvent &e) override
Definition synth_slider.cpp:264
String formatValue(float value)
Definition synth_slider.cpp:644
Rectangle< int > getModulationArea() const
Definition synth_slider.h:560
vital::ValueDetails * getDisplayDetails()
Definition synth_slider.cpp:767
String popup_prefix_
Definition synth_slider.h:725
PopupItems createPopupMenu()
Definition synth_slider.cpp:204
int max_display_characters_
Definition synth_slider.h:744
vital::ValueDetails alternate_details_
Definition synth_slider.h:761
String getRawTextFromValue(double value)
Definition synth_slider.cpp:380
void setRotaryTextEntryBounds()
Sets bounds for text entry in rotary mode.
Definition synth_slider.cpp:730
virtual void mouseDown(const MouseEvent &e) override
Mouse event overrides for custom behavior.
Definition synth_slider.cpp:234
bool shift_is_multiplicative_
Definition synth_slider.h:747
static constexpr float kSlowDragMultiplier
Definition synth_slider.h:334
void setDefaultRange()
Sets the default parameter range based on the parameter details.
Definition synth_slider.cpp:621
SynthSlider(String name)
Definition synth_slider.cpp:155
void textEditorFocusLost(TextEditor &editor) override
Definition synth_slider.cpp:520
float findValue(Skin::ValueId value_id) const override
Definition synth_slider.h:681
String getTextFromValue(double value) override
Definition synth_slider.cpp:404
Rectangle< int > getModulationMeterBounds() const
Definition synth_slider.cpp:673
std::vector< vital::ModulationConnection * > getConnections()
Definition synth_slider.cpp:695
void notifyModulationAmountChanged()
Notifies listeners that modulation amount has changed.
Definition synth_slider.cpp:752
static constexpr float kLinearWidthPercent
Definition synth_slider.h:341
String getSliderTextFromValue(double value)
Definition synth_slider.cpp:387
double mouse_wheel_index_movement_
Definition synth_slider.h:748
bool show_popup_on_hover_
Definition synth_slider.h:724
float text_entry_width_percent_
Definition synth_slider.h:749
void addSliderListener(SliderListener *listener)
Definition synth_slider.cpp:631
void notifyModulationRemoved()
Notifies listeners that a modulation was removed.
Definition synth_slider.cpp:757
float display_exponential_base_
Definition synth_slider.h:758
void hidePopup(bool primary)
Definition synth_slider.cpp:640
virtual void mouseExit(const MouseEvent &e) override
Definition synth_slider.cpp:327
void handlePopupResult(int result)
Definition synth_slider.cpp:703
double sensitivity_
Definition synth_slider.h:741
int max_decimal_places_
Definition synth_slider.h:745
virtual double snapValue(double attemptedValue, DragMode dragMode) override
Definition synth_slider.cpp:504
void showPopup(bool primary)
Definition synth_slider.cpp:635
virtual void mouseUp(const MouseEvent &e) override
Definition synth_slider.cpp:302
std::unique_ptr< OpenGlTextEditor > text_entry_
Definition synth_slider.h:767
static constexpr float kDefaultRotaryDragLength
Definition synth_slider.h:338
SynthGuiInterface * synth_interface_
Definition synth_slider.h:766
bool snap_to_value_
Definition synth_slider.h:734
bool scroll_enabled_
Definition synth_slider.h:727
virtual void mouseEnter(const MouseEvent &e) override
Definition synth_slider.cpp:315
virtual void mouseDoubleClick(const MouseEvent &e) override
Definition synth_slider.cpp:337
bool modulation_bar_right_
Definition synth_slider.h:731
float display_multiply_
Definition synth_slider.h:757
void showTextEntry()
Shows the text entry box for manual value entry.
Definition synth_slider.cpp:533
void notifyGuis()
Notifies GUI listeners of a value change.
Definition synth_slider.cpp:668
virtual void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Definition synth_slider.cpp:346
String popupSuffix_
Definition synth_slider.h:726
bool hovering_
Definition synth_slider.h:735
void setSliderPositionFromText()
Sets the slider position from the current text in the text editor.
Definition synth_slider.cpp:524
std::vector< SliderListener * > slider_listeners_
Definition synth_slider.h:769
static constexpr float kTextEntryHeightPercent
Definition synth_slider.h:332
bool use_suffix_
Definition synth_slider.h:737
std::pair< Skin::ValueId, float > alternate_display_setting_
Definition synth_slider.h:760
@ kDefaultValue
Definition synth_slider.h:321
@ kClearModulations
Definition synth_slider.h:323
@ kModulationList
Definition synth_slider.h:324
@ kClearMidiLearn
Definition synth_slider.h:320
@ kManualEntry
Definition synth_slider.h:322
@ kArmMidiLearn
Definition synth_slider.h:319
void notifyModulationsChanged()
Notifies listeners that modulations changed.
Definition synth_slider.cpp:762
double getValueFromText(const String &text) override
Definition synth_slider.cpp:415
vital::ValueDetails details_
Definition synth_slider.h:756
bool sensitive_mode_
Definition synth_slider.h:733
virtual void drawShadow(Graphics &g)
Definition synth_slider.cpp:553
void setValueFromAdjusted(double value)
Definition synth_slider.cpp:495
void drawRotaryShadow(Graphics &g)
Definition synth_slider.cpp:563
const std::string * string_lookup_
Definition synth_slider.h:763
static constexpr float kLinearHandlePercent
Definition synth_slider.h:342
static const bool isParameter(const std::string &name)
Definition synth_parameters.h:220
static const ValueDetails & getDetails(const std::string &name)
Definition synth_parameters.h:200
#define VITAL_ASSERT(x)
Definition common.h:11
force_inline int iclamp(int value, int min_val, int max_val)
Clamps an integer between [min_val, max_val].
Definition utils.h:250
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182
constexpr mono_float kPi
Pi constant.
Definition common.h:36
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174
A hierarchical structure of popup menu items for a selector component.
Definition synth_section.h:29
void addItem(int sub_id, const std::string &sub_name, bool sub_selected=false)
Adds a new item as a submenu entry.
Definition synth_section.h:51
A structure representing a single modulation connection between a modulation source and a destination...
Definition synth_types.h:30
Holds metadata about a single parameter (control) in the Vital synthesizer.
Definition synth_parameters.h:23
mono_float max
Maximum parameter value.
Definition synth_parameters.h:41
mono_float display_multiply
Multiplier for converting internal values to display units.
Definition synth_parameters.h:44
bool display_invert
If true, invert the displayed value range.
Definition synth_parameters.h:46
mono_float post_offset
Offset applied after scaling (for certain scale types).
Definition synth_parameters.h:43
@ kQuartic
Parameter value transformed by a quartic curve.
Definition synth_parameters.h:33
@ kSquareRoot
Parameter value transformed by a square root function.
Definition synth_parameters.h:34
@ kCubic
Parameter value transformed by a cubic curve.
Definition synth_parameters.h:32
@ kExponential
Parameter value transformed by an exponential function.
Definition synth_parameters.h:35
@ kIndexed
Parameter steps through discrete indexed values.
Definition synth_parameters.h:29
@ kQuadratic
Parameter value transformed by a quadratic curve.
Definition synth_parameters.h:31
mono_float min
Minimum parameter value.
Definition synth_parameters.h:40
std::string display_name
Human-readable name for display in UI.
Definition synth_parameters.h:48
std::string local_description
Local description or additional metadata.
Definition synth_parameters.h:50
const std::string * string_lookup
Optional lookup table for indexed parameter names.
Definition synth_parameters.h:49
mono_float default_value
Default value for the parameter.
Definition synth_parameters.h:42
ValueScale value_scale
The scaling mode of the parameter value.
Definition synth_parameters.h:45
std::string display_units
Units to display next to the parameter (e.g., "Hz", "dB").
Definition synth_parameters.h:47
Declares the SynthSlider and related classes, providing various slider styles and functionality in th...