Vital
Loading...
Searching...
No Matches
preset_browser.cpp
Go to the documentation of this file.
1#include "preset_browser.h"
2
3#include "skin.h"
4#include "fonts.h"
5#include "load_save.h"
6#include "paths.h"
8#include "open_gl_component.h"
9#include "open_gl_image.h"
10#include "synth_section.h"
11#include "synth_strings.h"
12#include "text_look_and_feel.h"
13
14namespace {
15 // Helper functions for sorting and filtering.
16 template<class Comparator>
17 void sortFileArray(Array<File>& file_array) {
18 Comparator comparator;
19 file_array.sort(comparator, true);
20 }
21
22 template<class Comparator>
23 void sortFileArrayWithCache(Array<File>& file_array, PresetInfoCache* cache) {
24 Comparator comparator(cache);
25 file_array.sort(comparator, true);
26 }
27
28 const std::string kPresetStoreUrl = "";
29
30 class FileNameFilter : public TextEditor::InputFilter {
31 public:
32 FileNameFilter() : TextEditor::InputFilter() { }
33
34 String filterNewText(TextEditor& editor, const String& new_input) override {
35 return new_input.removeCharacters("<>?*/|\\[]\":");
36 }
37 };
38}
39
41 num_view_presets_(0), hover_preset_(-1), click_preset_(-1), cache_position_(0),
42 highlight_(Shaders::kColorFragment), hover_(Shaders::kColorFragment),
43 view_position_(0), sort_column_(kName), sort_ascending_(true) {
44 addAndMakeVisible(browse_area_);
45 browse_area_.setInterceptsMouseClicks(false, false);
46 highlight_.setTargetComponent(&browse_area_);
47 hover_.setTargetComponent(&browse_area_);
48
49 scroll_bar_ = std::make_unique<OpenGlScrollBar>();
50 addAndMakeVisible(scroll_bar_.get());
51 addOpenGlComponent(scroll_bar_->getGlComponent());
52 scroll_bar_->addListener(this);
53
54#if !defined(NO_TEXT_ENTRY)
55 rename_editor_ = std::make_unique<OpenGlTextEditor>("Search");
56 rename_editor_->addListener(this);
57 rename_editor_->setSelectAllWhenFocused(true);
58 rename_editor_->setMultiLine(false, false);
59 rename_editor_->setJustification(Justification::centredLeft);
60 rename_editor_->setInputFilter(new FileNameFilter(), true);
61 addChildComponent(rename_editor_.get());
62 addOpenGlComponent(rename_editor_->getImageComponent());
63#endif
64
65 highlight_.setAdditive(true);
66 hover_.setAdditive(true);
67
68 favorites_ = LoadSave::getFavorites();
69}
70
71void PresetList::paintBackground(Graphics& g) {
72 int title_width = getTitleWidth();
73 g.setColour(findColour(Skin::kWidgetBackground, true));
74 g.fillRoundedRectangle(getLocalBounds().toFloat(), findValue(Skin::kBodyRounding));
75
76 int star_width = kStarWidthPercent * getWidth();
77 int name_width = kNameWidthPercent * getWidth();
78 int style_width = kStyleWidthPercent * getWidth();
79 int author_width = kAuthorWidthPercent * getWidth();
80 int date_width = kDateWidthPercent * getWidth();
81 int row_height = getRowHeight();
82 int text_padding = row_height / 2;
83
84 g.saveState();
85 g.setColour(findColour(Skin::kBody, true));
86 g.reduceClipRegion(getLocalBounds().removeFromTop(title_width));
87 Rectangle<float> top = getLocalBounds().toFloat().removeFromTop(title_width * 2.0f);
88 g.fillRoundedRectangle(top, findValue(Skin::kBodyRounding));
89 g.restoreState();
90
91 Colour lighten = findColour(Skin::kLightenScreen, true);
92 scroll_bar_->setColor(lighten);
93 g.setColour(lighten);
94 g.fillRect(star_width, 0, 1, title_width);
95 g.fillRect(star_width + name_width, 0, 1, title_width);
96 g.fillRect(star_width + name_width + style_width, 0, 1, title_width);
97 g.fillRect(getWidth() - date_width, 0, 1, title_width);
98
99 g.setColour(findColour(Skin::kTextComponentText, true));
100 g.setFont(Fonts::instance()->proportional_regular().withPointHeight(title_width * 0.5f));
101
102 Path star = Paths::star();
103 float star_draw_width = title_width * 0.8f;
104 float star_y = (title_width - star_draw_width) / 2.0f;
105 Rectangle<float> star_bounds((star_width - star_draw_width) / 2.0f, star_y, star_draw_width, star_draw_width);
106 g.fillPath(star, star.getTransformToScaleToFit(star_bounds, true));
107
108 g.drawText("Name", text_padding + star_width, 0, name_width, title_width, Justification::centredLeft);
109 int style_x = star_width + name_width + text_padding;
110 g.drawText("Style", style_x, 0, style_width, title_width, Justification::centredLeft);
111 int author_x = star_width + name_width + text_padding + style_width;
112 g.drawText("Author", author_x, 0, author_width, title_width, Justification::centredLeft);
113 g.drawText("Date", getWidth() - date_width, 0, date_width - text_padding, title_width, Justification::centredRight);
114
115 paintBorder(g);
116 setWantsKeyboardFocus(true);
117 setMouseClickGrabsKeyboardFocus(true);
118}
119
121 static constexpr float kScrollBarWidth = 15.0f;
122
123 int scroll_bar_width = kScrollBarWidth * getSizeRatio();
124 int title_width = getTitleWidth();
125 int scroll_bar_height = getHeight() - title_width;
126 scroll_bar_->setBounds(getWidth() - scroll_bar_width, title_width, scroll_bar_width, scroll_bar_height);
128
129 browse_area_.setBounds(0, title_width, getWidth(), getHeight() - title_width);
130}
131
132void PresetList::sort() {
133 if (sort_column_ == kStar && sort_ascending_)
134 sortFileArray<FavoriteAscendingComparator>(presets_);
135 else if (sort_column_ == kStar && !sort_ascending_)
136 sortFileArray<FavoriteDescendingComparator>(presets_);
137 else if (sort_column_ == kName && sort_ascending_)
138 sortFileArray<FileNameAscendingComparator>(presets_);
139 else if (sort_column_ == kName && !sort_ascending_)
140 sortFileArray<FileNameDescendingComparator>(presets_);
141 else if (sort_column_ == kAuthor && sort_ascending_)
142 sortFileArrayWithCache<AuthorAscendingComparator>(presets_, &preset_info_cache_);
143 else if (sort_column_ == kAuthor && !sort_ascending_)
144 sortFileArrayWithCache<AuthorDescendingComparator>(presets_, &preset_info_cache_);
145 else if (sort_column_ == kStyle && sort_ascending_)
146 sortFileArrayWithCache<StyleAscendingComparator>(presets_, &preset_info_cache_);
147 else if (sort_column_ == kStyle && !sort_ascending_)
148 sortFileArrayWithCache<StyleDescendingComparator>(presets_, &preset_info_cache_);
149 else if (sort_column_ == kDate && sort_ascending_)
150 sortFileArray<FileDateAscendingComparator>(presets_);
151 else if (sort_column_ == kDate && !sort_ascending_)
152 sortFileArray<FileDateDescendingComparator>(presets_);
153
154 filter(filter_string_, filter_styles_);
155}
156
157void PresetList::setPresets(Array<File> presets) {
158 presets_ = presets;
159 sort();
160 redoCache();
161}
162
163void PresetList::mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) {
164 view_position_ -= wheel.deltaY * kScrollSensitivity;
165 view_position_ = std::max(0.0f, view_position_);
166 int title_width = getTitleWidth();
167 float scaled_height = getHeight() - title_width;
168 int scrollable_range = getScrollableRange();
169 view_position_ = std::min(view_position_, 1.0f * scrollable_range - scaled_height);
170 viewPositionChanged();
172 finishRename();
173}
174
175int PresetList::getRowFromPosition(float mouse_position) {
176 int title_width = getTitleWidth();
177
178 return floorf((mouse_position + getViewPosition() - title_width) / getRowHeight());
179}
180
181void PresetList::mouseMove(const MouseEvent& e) {
182 hover_preset_ = getRowFromPosition(e.position.y);
183 if (hover_preset_ >= filtered_presets_.size())
184 hover_preset_ = -1;
185}
186
187void PresetList::mouseExit(const MouseEvent& e) {
188 hover_preset_ = -1;
189}
190
192 if (click_preset_ < 0 || click_preset_ >= filtered_presets_.size())
193 return;
194
195 File preset = filtered_presets_[click_preset_];
196 if (result == kOpenFileLocation)
197 preset.revealToUser();
198 else if (result == kRename && rename_editor_) {
199 renaming_preset_ = preset;
200 int y = getTitleWidth() + click_preset_ * getRowHeight() - getViewPosition();
201 rename_editor_->setBounds(kStarWidthPercent * getWidth(), y, kNameWidthPercent * getWidth(), getRowHeight());
202 rename_editor_->setColour(CaretComponent::caretColourId, findColour(Skin::kTextEditorCaret, true));
203 rename_editor_->setColour(TextEditor::textColourId, findColour(Skin::kBodyText, true));
204 rename_editor_->setColour(TextEditor::highlightedTextColourId, findColour(Skin::kBodyText, true));
205 rename_editor_->setColour(TextEditor::highlightColourId, findColour(Skin::kTextEditorSelection, true));
206 rename_editor_->setText(renaming_preset_.getFileNameWithoutExtension());
207 rename_editor_->setVisible(true);
208 rename_editor_->grabKeyboardFocus();
209 rename_editor_->selectAll();
210 }
211 else if (result == kDelete) {
212 for (Listener* listener : listeners_)
213 listener->deleteRequested(preset);
214 }
215}
216
217void PresetList::menuClick(const MouseEvent& e) {
218 float click_y_position = e.position.y;
219 int row = getRowFromPosition(click_y_position);
220
221 if (row >= 0 && hover_preset_ >= 0) {
222 click_preset_ = hover_preset_;
223 PopupItems options;
224 options.addItem(kOpenFileLocation, "Open File Location");
225
226 File preset = filtered_presets_[click_preset_];
227 if (preset.exists() && preset.hasWriteAccess()) {
228 options.addItem(kRename, "Rename");
229 options.addItem(kDelete, "Delete");
230 }
231
232 showPopupSelector(this, e.getPosition(), options, [=](int selection) { respondToMenuCallback(selection); });
233 }
234}
235
236void PresetList::leftClick(const MouseEvent& e) {
237 int title_width = getTitleWidth();
238 float click_y_position = e.position.y;
239 float click_x_position = e.position.x;
240 int row = getRowFromPosition(click_y_position);
241 int star_right = kStarWidthPercent * getWidth();
242
243 if (click_y_position <= title_width) {
244 int name_right = star_right + kNameWidthPercent * getWidth();
245 int style_right = name_right + kStyleWidthPercent * getWidth();
246 int author_right = style_right + kAuthorWidthPercent * getWidth();
247 Column clicked_column;
248
249 if (click_x_position < star_right)
250 clicked_column = kStar;
251 else if (click_x_position < name_right)
252 clicked_column = kName;
253 else if (click_x_position < style_right)
254 clicked_column = kStyle;
255 else if (click_x_position < author_right)
256 clicked_column = kAuthor;
257 else
258 clicked_column = kDate;
259
260 if (clicked_column == sort_column_)
261 sort_ascending_ = !sort_ascending_;
262 else
263 sort_ascending_ = true;
264 sort_column_ = clicked_column;
265 sort();
266 redoCache();
267 }
268 else if (row < filtered_presets_.size() && row >= 0) {
269 File preset = filtered_presets_[row];
270 if (click_x_position < star_right) {
271 std::string path = preset.getFullPathName().toStdString();
272 if (favorites_.count(path)) {
273 favorites_.erase(path);
275 }
276 else {
277 favorites_.insert(path);
278 LoadSave::addFavorite(preset);
279 }
280 redoCache();
281 }
282 else {
283 selected_preset_ = preset;
284
285 for (Listener* listener : listeners_)
286 listener->newPresetSelected(preset);
287 }
288 }
289}
290
291void PresetList::mouseDown(const MouseEvent& e) {
292 if (e.mods.isPopupMenu())
293 menuClick(e);
294 else
295 leftClick(e);
296}
297
298void PresetList::textEditorReturnKeyPressed(TextEditor& text_editor) {
299 if (renaming_preset_.exists())
300 finishRename();
301}
302
303void PresetList::textEditorFocusLost(TextEditor& text_editor) {
304 if (renaming_preset_.exists())
305 finishRename();
306}
307
309 rename_editor_->setVisible(false);
310}
311
312void PresetList::scrollBarMoved(ScrollBar* scroll_bar, double range_start) {
313 view_position_ = range_start;
314 viewPositionChanged();
315}
316
318 static constexpr float kScrollStepRatio = 0.05f;
319
320 int title_width = getTitleWidth();
321 float scaled_height = getHeight() - title_width;
322 scroll_bar_->setRangeLimits(0.0f, getScrollableRange());
323 scroll_bar_->setCurrentRange(getViewPosition(), scaled_height, dontSendNotification);
324 scroll_bar_->setSingleStepSize(scroll_bar_->getHeight() * kScrollStepRatio);
325 scroll_bar_->cancelPendingUpdate();
326}
327
329 String text = rename_editor_->getText();
330 rename_editor_->setVisible(false);
331 if (text.trim().isEmpty() || !renaming_preset_.exists())
332 return;
333
334 File parent = renaming_preset_.getParentDirectory();
335 File new_file = parent.getChildFile(text + renaming_preset_.getFileExtension());
336 renaming_preset_.moveFileTo(new_file);
337 renaming_preset_ = File();
338
340}
341
343 presets_.clear();
344 if (current_folder_.exists() && current_folder_.isDirectory())
345 current_folder_.findChildFiles(presets_, File::findFiles, true, "*." + vital::kPresetExtension);
346 else
347 LoadSave::getAllPresets(presets_);
348 sort();
349 redoCache();
350}
351
353 int num_presets = static_cast<int>(filtered_presets_.size());
354 if (num_presets == 0)
355 return;
356
357 int new_index = (getSelectedIndex() + num_presets + indices) % num_presets;
358 selected_preset_ = filtered_presets_[new_index];
359 for (Listener* listener : listeners_)
360 listener->newPresetSelected(selected_preset_);
361}
362
364 if (getWidth() <= 0 || getHeight() <= 0)
365 return;
366
367 int max = static_cast<int>(filtered_presets_.size()) - kNumCachedRows;
368 int position = std::max(0, std::min<int>(cache_position_, max));
369 loadBrowserCache(position, position + kNumCachedRows);
370}
371
372void PresetList::filter(String filter_string, const std::set<std::string>& styles) {
373 filter_string_ = filter_string.toLowerCase();
374 filter_styles_ = styles;
375 StringArray tokens;
376 tokens.addTokens(filter_string_, " ", "");
377 filtered_presets_.clear();
378
379 for (const File& preset : presets_) {
380 bool match = true;
381 std::string path = preset.getFullPathName().toStdString();
382 if (!styles.empty()) {
383 std::string style = preset_info_cache_.getStyle(preset);
384 if (styles.count(style) == 0)
385 match = false;
386 }
387 if (match && tokens.size()) {
388 String name = preset.getFileNameWithoutExtension().toLowerCase();
389 String author = String(preset_info_cache_.getAuthor(preset)).toLowerCase();
390
391 for (const String& token : tokens) {
392 if (!name.contains(token) && !author.contains(token))
393 match = false;
394 }
395 }
396 if (match)
397 filtered_presets_.push_back(preset);
398 }
399 num_view_presets_ = static_cast<int>(filtered_presets_.size());
400
402}
403
405 for (int i = 0; i < filtered_presets_.size(); ++i) {
406 if (selected_preset_ == filtered_presets_[i])
407 return i;
408 }
409 return -1;
410}
411
413 int row_height = getRowHeight();
414 int title_width = getTitleWidth();
415 int presets_height = row_height * static_cast<int>(filtered_presets_.size());
416 return std::max(presets_height, getHeight() - title_width);
417}
418
420 for (int i = 0; i < kNumCachedRows; ++i) {
421 rows_[i].setScissor(true);
422 rows_[i].init(open_gl);
423 rows_[i].setColor(Colours::white);
424 }
425
426 highlight_.init(open_gl);
427 hover_.init(open_gl);
429}
430
431void PresetList::viewPositionChanged() {
432 int row_height = getRowHeight();
433
434 int last_cache_position = cache_position_;
435 cache_position_ = getViewPosition() / row_height;
436 int max = static_cast<int>(filtered_presets_.size() - kNumCachedRows);
437 cache_position_ = std::max(0, std::min<int>(cache_position_, max));
438
439 if (std::abs(cache_position_ - last_cache_position) >= kNumCachedRows)
440 redoCache();
441 else if (last_cache_position < cache_position_)
442 loadBrowserCache(last_cache_position + kNumCachedRows, cache_position_ + kNumCachedRows);
443 else if (last_cache_position > cache_position_)
444 loadBrowserCache(cache_position_, last_cache_position);
445}
446
447void PresetList::loadBrowserCache(int start_index, int end_index) {
448 int mult = getPixelMultiple();
449 int row_height = getRowHeight() * mult;
450 int image_width = getWidth() * mult;
451
452 int text_padding = row_height / 2.0f;
453 int star_x = text_padding;
454 int star_width = kStarWidthPercent * image_width;
455 int name_x = star_x + star_width;
456 int name_width = kNameWidthPercent * image_width;
457 int style_x = name_x + name_width;
458 int style_width = kStyleWidthPercent * image_width;
459 int author_x = style_x + style_width;
460 int author_width = kAuthorWidthPercent * image_width;
461 int date_width = kDateWidthPercent * image_width;
462 int date_x = image_width - date_width + text_padding;
463
464 end_index = std::min(static_cast<int>(filtered_presets_.size()), end_index);
465 Font font = Fonts::instance()->proportional_light().withPointHeight(row_height * 0.5f);
466
467 Path star = Paths::star();
468 float star_draw_width = row_height * 0.8f;
469 float star_y = (row_height - star_draw_width) / 2.0f;
470 Rectangle<float> star_bounds((star_width - star_draw_width) / 2.0f, star_y, star_draw_width, star_draw_width);
471 star.applyTransform(star.getTransformToScaleToFit(star_bounds, true));
472 PathStrokeType star_stroke(1.0f, PathStrokeType::curved);
473
474 Colour text_color = findColour(Skin::kTextComponentText, true);
475 Colour star_unselected = text_color.withMultipliedAlpha(0.5f);
476 Colour star_selected = findColour(Skin::kWidgetPrimary1, true);
477
478 for (int i = start_index; i < end_index; ++i) {
479 Image row_image(Image::ARGB, image_width, row_height, true);
480 Graphics g(row_image);
481
482 File preset = filtered_presets_[i];
483 String name = preset.getFileNameWithoutExtension();
484 String author = preset_info_cache_.getAuthor(preset);
485 String style = preset_info_cache_.getStyle(preset);
486 if (!style.isEmpty())
487 style = style.substring(0, 1).toUpperCase() + style.substring(1);
488 String date = preset.getCreationTime().toString(true, false, false);
489
490 if (favorites_.count(preset.getFullPathName().toStdString())) {
491 g.setColour(star_selected);
492 g.fillPath(star);
493 }
494 else
495 g.setColour(star_unselected);
496
497 g.strokePath(star, star_stroke);
498
499 g.setColour(text_color);
500 g.setFont(font);
501 g.drawText(name, name_x, 0, name_width - 2 * text_padding, row_height, Justification::centredLeft, true);
502 g.drawText(style, style_x, 0, style_width - 2 * text_padding, row_height, Justification::centredLeft, true);
503 g.drawText(author, author_x, 0, author_width - 2 * text_padding, row_height, Justification::centredLeft, true);
504 g.drawText(date, date_x, 0, date_width - 2 * text_padding, row_height, Justification::centredRight, true);
505
506 rows_[i % kNumCachedRows].setOwnImage(row_image);
507 }
508}
509
510void PresetList::moveQuadToRow(OpenGlQuad& quad, int row, float y_offset) {
511 int row_height = getRowHeight();
512 float view_height = getHeight() - (int)getTitleWidth();
513 float open_gl_row_height = 2.0f * row_height / view_height;
514 float offset = row * open_gl_row_height;
515
516 float y = 1.0f + y_offset - offset;
517 quad.setQuad(0, -1.0f, y - open_gl_row_height, 2.0f, open_gl_row_height);
518}
519
521 int title_width = getTitleWidth();
522 float view_height = getHeight() - title_width;
523 int row_height = getRowHeight();
524 int num_presets = num_view_presets_;
525
526 int view_position = getViewPosition();
527 float y_offset = 2.0f * view_position / view_height;
528
529 Rectangle<int> view_bounds(0, title_width, getWidth(), getHeight() - title_width);
530 OpenGlComponent::setViewPort(this, view_bounds, open_gl);
531
532 float image_width = vital::utils::nextPowerOfTwo(getWidth());
533 float image_height = vital::utils::nextPowerOfTwo(row_height);
534 float width_ratio = image_width / getWidth();
535 float height_ratio = image_height / row_height;
536
537 float open_gl_row_height = height_ratio * 2.0f * row_height / view_height;
538 int cache_position = std::max(0, std::min(cache_position_, num_presets - kNumCachedRows));
539 for (int i = 0; i < kNumCachedRows && i < num_presets; ++i) {
540 int row = cache_position + i;
541 int cache_index = row % kNumCachedRows;
542 float offset = (2.0f * row_height * row) / view_height;
543 float y = 1.0f + y_offset - offset;
544
545 Rectangle<int> row_bounds(0, row_height * row - view_position + title_width, getWidth(), row_height);
546 OpenGlComponent::setScissorBounds(this, row_bounds, open_gl);
547
548 rows_[cache_index].setTopLeft(-1.0f, y);
549 rows_[cache_index].setTopRight(-1.0f + 2.0f * width_ratio, y);
550 rows_[cache_index].setBottomLeft(-1.0f, y - open_gl_row_height);
551 rows_[cache_index].setBottomRight(-1.0f + 2.0f * width_ratio, y - open_gl_row_height);
552 rows_[cache_index].drawImage(open_gl);
553 }
554
555 int selected_index = getSelectedIndex();
556 if (selected_index >= 0) {
557 moveQuadToRow(highlight_, selected_index, y_offset);
558 highlight_.setColor(findColour(Skin::kWidgetPrimary1, true).darker(0.8f));
559 highlight_.render(open_gl, animate);
560 }
561
562 if (hover_preset_ >= 0) {
563 moveQuadToRow(hover_, hover_preset_, y_offset);
564 hover_.setColor(findColour(Skin::kLightenScreen, true));
565 hover_.render(open_gl, animate);
566 }
567
569}
570
572 for (int i = 0; i < kNumCachedRows; ++i)
573 rows_[i].destroy(open_gl);
574
575 highlight_.destroy(open_gl);
576 hover_.destroy(open_gl);
578}
579
581 save_section_ = nullptr;
582 delete_section_ = nullptr;
583
584 addKeyListener(this);
585
586 preset_list_ = std::make_unique<PresetList>();
587 preset_list_->addListener(this);
588 addSubSection(preset_list_.get());
589
590 folder_list_ = std::make_unique<SelectionList>();
591 folder_list_->addFavoritesOption();
592 folder_list_->addListener(this);
593 addSubSection(folder_list_.get());
594 folder_list_->setPassthroughFolderName(LoadSave::kPresetFolderName);
595 std::vector<File> directories = LoadSave::getPresetDirectories();
596 Array<File> selections;
597 for (const File& directory : directories)
598 selections.add(directory);
599 folder_list_->setSelections(selections);
600
601 for (int i = 0; i < LoadSave::kNumPresetStyles; ++i) {
602 style_buttons_[i] = std::make_unique<OpenGlToggleButton>(strings::kPresetStyleNames[i]);
603 style_buttons_[i]->addListener(this);
604 style_buttons_[i]->setLookAndFeel(TextLookAndFeel::instance());
605 addAndMakeVisible(style_buttons_[i].get());
606 addOpenGlComponent(style_buttons_[i]->getGlComponent());
607 }
608
609 store_button_ = std::make_unique<OpenGlToggleButton>("Store");
610 addButton(store_button_.get());
611 store_button_->setUiButton(true);
612 store_button_->setVisible(false);
613
614 preset_text_ = std::make_unique<PlainTextComponent>("Preset", "Preset name");
615 addOpenGlComponent(preset_text_.get());
616 preset_text_->setFontType(PlainTextComponent::kLight);
617 preset_text_->setJustification(Justification::centredLeft);
618
619 author_text_ = std::make_unique<PlainTextComponent>("Author", "Author");
620 addOpenGlComponent(author_text_.get());
621 author_text_->setFontType(PlainTextComponent::kLight);
622 author_text_->setJustification(Justification::centredLeft);
623
624#if !defined(NO_TEXT_ENTRY)
625 search_box_ = std::make_unique<OpenGlTextEditor>("Search");
626 search_box_->addListener(this);
627 search_box_->setSelectAllWhenFocused(true);
628 search_box_->setMultiLine(false, false);
629 search_box_->setJustification(Justification::centredLeft);
630 addAndMakeVisible(search_box_.get());
631 addOpenGlComponent(search_box_->getImageComponent());
632
633 comments_ = std::make_unique<OpenGlTextEditor>("Comments");
634 comments_->setSelectAllWhenFocused(false);
635 comments_->setJustification(Justification::topLeft);
636 comments_->setReadOnly(true);
637 addAndMakeVisible(comments_.get());
638 addOpenGlComponent(comments_->getImageComponent());
639 comments_->setMultiLine(true, true);
640#endif
641
642 Array<File> presets;
644 preset_list_->setPresets(presets);
645
646 setWantsKeyboardFocus(true);
647 setMouseClickGrabsKeyboardFocus(true);
649}
650
652
654 Rectangle<int> search_rect = getSearchRect();
655 Rectangle<int> info_rect = getInfoRect();
656 paintBody(g, search_rect);
657 paintBorder(g, search_rect);
658 paintBody(g, info_rect);
659 paintBorder(g, info_rect);
660
661 int left_padding = kLeftPadding * size_ratio_;
662 int top_padding = kTopPadding * size_ratio_;
663 int middle_padding = kMiddlePadding * size_ratio_;
664
665 int text_x = info_rect.getX() + left_padding;
666 int text_width = info_rect.getWidth() - 2 * left_padding;
667 int name_y = info_rect.getY() + top_padding;
668 int name_height = kNameFontHeight * size_ratio_;
669 int author_y = name_y + name_height + middle_padding;
670 int author_height = kAuthorFontHeight * size_ratio_;
671 int comments_y = author_y + author_height + 2 * middle_padding;
672
673 g.setColour(findColour(Skin::kLightenScreen, true));
674 g.drawRect(text_x, author_y, text_width, 1);
675 g.drawRect(text_x, comments_y, text_width, 1);
676
677 g.setColour(findColour(Skin::kWidgetBackground, true));
679 Rectangle<float> folder_bounds = folder_list_->getBounds().toFloat().expanded(1);
680 g.fillRoundedRectangle(folder_bounds, rounding);
681
683}
684
689
691 static constexpr float kBrowseWidthRatio = 0.68f;
692 static constexpr float kSearchBoxRowHeightRatio = 1.3f;
693
695
696 Colour empty_color = findColour(Skin::kBodyText, true);
697 empty_color = empty_color.withAlpha(0.5f * empty_color.getFloatAlpha());
698
699 if (search_box_) {
700 search_box_->setTextToShowWhenEmpty(TRANS("Search"), empty_color);
701 search_box_->setColour(CaretComponent::caretColourId, findColour(Skin::kTextEditorCaret, true));
702 search_box_->setColour(TextEditor::textColourId, findColour(Skin::kBodyText, true));
703 search_box_->setColour(TextEditor::highlightedTextColourId, findColour(Skin::kBodyText, true));
704 search_box_->setColour(TextEditor::highlightColourId, findColour(Skin::kTextEditorSelection, true));
705 }
706 if (comments_) {
707 comments_->setColour(TextEditor::textColourId, findColour(Skin::kBodyText, true));
708 comments_->setColour(TextEditor::highlightedTextColourId, findColour(Skin::kBodyText, true));
709 comments_->setColour(TextEditor::highlightColourId, findColour(Skin::kTextEditorSelection, true));
710 }
711
712 int padding = findValue(Skin::kLargePadding);
713 int preset_list_width = getWidth() * kBrowseWidthRatio;
714 preset_list_->setBounds(getWidth() - preset_list_width - padding, 0, preset_list_width, getHeight());
715 if (isVisible())
716 preset_list_->redoCache();
717
718 Rectangle<int> search_rect = getSearchRect();
719 Rectangle<int> info_rect = getInfoRect();
720 int top_padding = kTopPadding * size_ratio_;
721 int left_padding = kLeftPadding * size_ratio_;
722 int middle_padding = kMiddlePadding * size_ratio_;
723
724 int name_y = info_rect.getY() + top_padding;
725 int name_height = kNameFontHeight * size_ratio_;
726 int author_y = name_y + name_height + middle_padding;
727 int author_height = kAuthorFontHeight * size_ratio_;
728 int text_x = info_rect.getX() + left_padding;
729 int text_width = info_rect.getWidth() - 2 * left_padding;
730 preset_text_->setTextSize(name_height);
731 preset_text_->setBounds(text_x, name_y - middle_padding, text_width, name_height + 2 * middle_padding);
732 author_text_->setTextSize(author_height);
733 author_text_->setBounds(text_x, author_y, text_width / 2, author_height + 2 * middle_padding);
734
735 int style_filter_y = search_rect.getY() + top_padding;
736 if (search_box_) {
737 int search_box_height = kSearchBoxRowHeightRatio * preset_list_->getRowHeight();
738 int search_box_x = search_rect.getX() + left_padding;
739 search_box_->setBounds(search_box_x, search_rect.getY() + top_padding, text_width, search_box_height);
740
741 style_filter_y = search_box_->getBottom() + top_padding;
742 }
743
744 int widget_margin = getWidgetMargin();
745 int style_button_height = preset_list_->getRowHeight();
746 int style_filter_x = search_rect.getX() + left_padding;
747 int style_filter_width = search_rect.getWidth() - 2 * left_padding + widget_margin;
748
749 int num_in_row = LoadSave::kNumPresetStyles / 3;
750 for (int i = 0; i < LoadSave::kNumPresetStyles; ++i) {
751 int column = i % num_in_row;
752 int x = style_filter_x + (style_filter_width * column) / num_in_row;
753 int next_x = style_filter_x + (style_filter_width * (column + 1)) / num_in_row;
754 int width = next_x - x - widget_margin;
755 int y = style_filter_y + (i / num_in_row) * (style_button_height + widget_margin);
756 style_buttons_[i]->setBounds(x, y, width, style_button_height);
757 }
758
759 int folder_y = style_filter_y + 3 * style_button_height + 2 * widget_margin + top_padding + 1;
760 folder_list_->setBounds(style_filter_x, folder_y, text_width, search_rect.getBottom() - top_padding - folder_y - 1);
761
762 setCommentsBounds();
763}
764
765void PresetBrowser::setCommentsBounds() {
766 Rectangle<int> info_rect = getInfoRect();
767 int left_padding = kLeftPadding * size_ratio_;
768 int top_padding = kTopPadding * size_ratio_;
769 int top_info_height = (kNameFontHeight + kAuthorFontHeight + kMiddlePadding * 4) * size_ratio_;
770 int width = info_rect.getWidth() - 2 * left_padding;
771
772 int comments_x = info_rect.getX() + left_padding;
773 int comments_y = info_rect.getY() + top_info_height + top_padding;
774 int comments_height = info_rect.getBottom() - comments_y - top_padding;
775 if (store_button_->isVisible()) {
776 int store_height = kStoreHeight * size_ratio_;
777 int store_y = info_rect.getBottom() - store_height - top_padding;
778 store_button_->setBounds(comments_x, store_y, width, store_height);
779 comments_height -= store_height + top_padding / 2;
780 }
781 if (comments_)
782 comments_->setBounds(comments_x, comments_y, width, comments_height);
783}
784
786 SynthSection::visibilityChanged();
787 if (search_box_)
788 search_box_->setText("");
789
790 if (isVisible()) {
791 preset_list_->redoCache();
792 folder_list_->redoCache();
793 more_author_presets_.clear();
794
795 try {
796 json available = LoadSave::getAvailablePacks();
797 json available_packs = available["packs"];
798 for (auto& pack : available_packs) {
799 if (pack.count("Presets") == 0)
800 continue;
801
802 bool purchased = false;
803 if (pack.count("Purchased"))
804 purchased = pack["Purchased"];
805 if (purchased)
806 continue;
807
808 std::string author_data = pack["Author"];
809 StringArray authors;
810 authors.addTokens(author_data, ",", "");
811 for (const String& author : authors)
812 more_author_presets_.insert(author.removeCharacters(" ._").toLowerCase().toStdString());
813 }
814 }
815 catch (const json::exception& e) {
816 }
817 }
818
819 loadPresetInfo();
820}
821
823 Rectangle<int> info_rect = getInfoRect();
824 int padding = findValue(Skin::kLargePadding);
825 int y = info_rect.getBottom() + padding;
826 return Rectangle<int>(0, y, info_rect.getWidth(), getHeight() - y);
827}
828
830 static constexpr float kInfoHeightRatio = 0.43f;
831 int width = preset_list_->getX() - findValue(Skin::kLargePadding);
832 int height = getHeight() * kInfoHeightRatio;
833 return Rectangle<int>(0, 0, width, height);
834}
835
837 if (search_box_)
838 search_box_->setText("");
839 preset_list_->reloadPresets();
840 preset_list_->filter("", std::set<std::string>());
841
842 std::vector<File> directories = LoadSave::getPresetDirectories();
843 Array<File> selections;
844 for (const File& directory : directories)
845 selections.add(directory);
846 folder_list_->setSelections(selections);
847}
848
850 std::set<std::string> styles;
851 for (int i = 0; i < LoadSave::kNumPresetStyles; ++i) {
852 if (style_buttons_[i]->getToggleState()) {
853 String name = strings::kPresetStyleNames[i];
854 styles.insert(name.toLowerCase().toStdString());
855 }
856 }
857
858 preset_list_->filter(search_box_->getText(), styles);
859 preset_list_->redoCache();
860}
861
862void PresetBrowser::textEditorTextChanged(TextEditor& editor) {
864}
865
867 editor.setText("");
868}
869
870void PresetBrowser::save(File preset) {
871 loadPresets();
872}
873
874void PresetBrowser::fileDeleted(File saved_file) {
875 loadPresets();
876}
877
878void PresetBrowser::buttonClicked(Button* clicked_button) {
879 if (clicked_button == store_button_.get()) {
880 String encoded_author = URL::addEscapeChars(author_text_->getText().toStdString(), true);
881 encoded_author = encoded_author.replace("+", "%2B");
882
883 URL url(String(kPresetStoreUrl) + encoded_author);
884 url.launchInDefaultBrowser();
885 }
886 else
888}
889
890bool PresetBrowser::keyPressed(const KeyPress &key, Component *origin) {
891 if (!isVisible())
892 return search_box_->hasKeyboardFocus(true);
893
894 if (key.getKeyCode() == KeyPress::escapeKey) {
895 for (Listener* listener : listeners_)
896 listener->hidePresetBrowser();
897 return true;
898 }
899 if (key.getKeyCode() == KeyPress::upKey || key.getKeyCode() == KeyPress::leftKey) {
901 return true;
902 }
903 if (key.getKeyCode() == KeyPress::downKey || key.getKeyCode() == KeyPress::rightKey) {
905 return true;
906 }
907 return search_box_->hasKeyboardFocus(true);
908}
909
910bool PresetBrowser::keyStateChanged(bool is_key_down, Component *origin) {
911 if (is_key_down)
912 return search_box_->hasKeyboardFocus(true);
913 return false;
914}
915
917 static const LoadSave::FileSorterAscending kFileSorter;
918
919 File parent = external_preset_.getParentDirectory();
920 if (parent.exists()) {
921 Array<File> presets;
922 parent.findChildFiles(presets, File::findFiles, false, String("*.") + vital::kPresetExtension);
923 presets.sort(kFileSorter);
924 int index = presets.indexOf(external_preset_);
925 index = (index + indices + presets.size()) % presets.size();
926
927 File new_preset = presets[index];
928 loadFromFile(new_preset);
929 externalPresetLoaded(new_preset);
930 }
931 else
932 preset_list_->shiftSelectedPreset(indices);
933}
934
938
942
944 external_preset_ = file;
945 setPresetInfo(file);
946}
947
948bool PresetBrowser::loadFromFile(File& preset) {
949 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
950 if (parent == nullptr)
951 return false;
952
953 SynthBase* synth = parent->getSynth();
954 std::string error;
955 if (synth->loadFromFile(preset, error)) {
956 setPresetInfo(preset);
957 synth->setPresetName(preset.getFileNameWithoutExtension());
958 synth->setAuthor(author_);
959
960 String comments = parent->getSynth()->getComments();
961 int comments_font_size = kCommentsFontHeight * size_ratio_;
962 if (comments_) {
963 comments_->setText(comments);
964 comments_->setFont(Fonts::instance()->proportional_light().withPointHeight(comments_font_size));
965 comments_->redoImage();
966 }
967 return true;
968 }
969 return false;
970}
971
972void PresetBrowser::loadPresetInfo() {
973 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
974 if (parent == nullptr)
975 return;
976
977 Colour background = findColour(Skin::kBody, true);
978 Colour lighten = findColour(Skin::kLightenScreen, true);
979 lighten = background.overlaidWith(lighten);
980 Colour regular_text = findColour(Skin::kBodyText, true);
981
982 String preset = parent->getSynth()->getPresetName();
983 if (preset.isEmpty()) {
984 preset_text_->setText("Preset name");
985 preset_text_->setColor(lighten);
986 }
987 else {
988 preset_text_->setText(preset);
989 preset_text_->setColor(regular_text);
990 }
991
992 String author = parent->getSynth()->getAuthor();
993 if (author.isEmpty()) {
994 author_text_->setText("Author");
995 author_text_->setColor(lighten);
996 }
997 else {
998 author_text_->setText(author);
999 author_text_->setColor(regular_text);
1000 }
1001
1002 String comments = parent->getSynth()->getComments();
1003 int comments_font_size = kCommentsFontHeight * size_ratio_;
1004 if (comments_) {
1005 comments_->setText(comments);
1006 comments_->setFont(Fonts::instance()->proportional_light().withPointHeight(comments_font_size));
1007 comments_->redoImage();
1008 }
1009}
1010
1011void PresetBrowser::setPresetInfo(File& preset) {
1012 if (preset.exists()) {
1013 try {
1014 json parsed_json_state = json::parse(preset.loadFileAsString().toStdString(), nullptr, false);
1015 author_ = LoadSave::getAuthorFromFile(preset);
1016 license_ = LoadSave::getLicense(parsed_json_state);
1017 }
1018 catch (const json::exception& e) {
1019 }
1020 }
1021}
1022
1024 listeners_.push_back(listener);
1025}
1026
1028 save_section_ = save_section;
1029 save_section_->addSaveListener(this);
1030}
1031
1033 delete_section_ = delete_section;
1034 delete_section_->addDeleteListener(this);
1035}
1036
1037void PresetBrowser::newSelection(File selection) {
1038 if (selection.exists() && selection.isDirectory())
1039 preset_list_->setCurrentFolder(selection);
1040}
1041
1043 Array<File> presets;
1044 LoadSave::getAllPresets(presets);
1045 preset_list_->setPresets(presets);
1046}
1047
1049 Array<File> presets;
1050 LoadSave::getAllPresets(presets);
1051
1052 Array<File> favorites;
1053 std::set<std::string> favorite_lookup = LoadSave::getFavorites();
1054
1055 for (const File& file : presets) {
1056 if (favorite_lookup.count(file.getFullPathName().toStdString()))
1057 favorites.add(file);
1058 }
1059 preset_list_->setPresets(favorites);
1060}
An overlay that asks the user to confirm deletion of a preset file.
Definition delete_section.h:15
void addDeleteListener(Listener *listener)
Definition delete_section.h:77
Font & proportional_light()
Returns a reference to the proportional light font.
Definition fonts.h:28
static Fonts * instance()
Gets the singleton instance of the Fonts class.
Definition fonts.h:52
A helper class for sorting files in ascending order based on their names.
Definition load_save.h:34
static const std::string kPresetFolderName
Definition load_save.h:74
static std::vector< File > getPresetDirectories()
Gets directories that should contain presets.
Definition load_save.cpp:1764
@ kNumPresetStyles
Definition load_save.h:66
static void addFavorite(const File &new_favorite)
Adds a new favorite preset or item to the favorites file.
Definition load_save.cpp:1219
static void getAllPresets(Array< File > &presets)
Retrieves all preset files from preset directories.
Definition load_save.cpp:1835
static std::string getLicense(json state)
Extracts the license information from a JSON state, if present.
Definition load_save.cpp:1107
static void removeFavorite(const File &old_favorite)
Removes a favorite item from the favorites.
Definition load_save.cpp:1225
static json getAvailablePacks()
Parses and returns JSON data about available packs.
Definition load_save.cpp:1441
static String getAuthorFromFile(const File &file)
Extracts the author's name from a given preset file.
Definition load_save.cpp:1039
static std::set< std::string > getFavorites()
Retrieves all favorites as a set of string paths.
Definition load_save.cpp:1235
static bool setViewPort(Component *component, Rectangle< int > bounds, OpenGlWrapper &open_gl)
Sets the OpenGL viewport to match a specified rectangle within a component.
Definition open_gl_component.cpp:42
static void setScissorBounds(Component *component, Rectangle< int > bounds, OpenGlWrapper &open_gl)
Sets the OpenGL scissor region to a specified rectangle within a component.
Definition open_gl_component.cpp:82
void setOwnImage(Image &image)
Sets the image from an owned copy.
Definition open_gl_image.h:69
void init(OpenGlWrapper &open_gl)
Initializes the OpenGL buffers and shader attributes needed for rendering the image.
Definition open_gl_image.cpp:33
void setBottomLeft(float x, float y)
Sets the bottom-left corner position of the image quad.
Definition open_gl_image.h:116
void drawImage(OpenGlWrapper &open_gl)
Draws the image to the current OpenGL context.
Definition open_gl_image.cpp:59
void setScissor(bool scissor)
Enables or disables scissor test when drawing the image.
Definition open_gl_image.h:156
void setBottomRight(float x, float y)
Sets the bottom-right corner position of the image quad.
Definition open_gl_image.h:121
void setTopLeft(float x, float y)
Sets the top-left corner position of the image quad.
Definition open_gl_image.h:111
void setTopRight(float x, float y)
Sets the top-right corner position of the image quad.
Definition open_gl_image.h:126
void setColor(Colour color)
Sets the color tint applied to the image.
Definition open_gl_image.h:92
virtual void init(OpenGlWrapper &open_gl) override
Initializes OpenGL buffers and shader attributes.
Definition open_gl_multi_quad.cpp:37
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
void setTargetComponent(Component *target_component)
Sets a target component to help position the quads.
Definition open_gl_multi_quad.h:358
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the quads using OpenGL.
Definition open_gl_multi_quad.cpp:92
virtual void destroy(OpenGlWrapper &open_gl) override
Releases OpenGL resources when the component is destroyed.
Definition open_gl_multi_quad.cpp:69
force_inline void setColor(Colour color)
Sets the base color for the quads.
Definition open_gl_multi_quad.h:102
void setAdditive(bool additive)
Enables or disables additive blending for rendering.
Definition open_gl_multi_quad.h:377
A convenience class for a single quad rendered via OpenGL.
Definition open_gl_multi_quad.h:447
static Path star()
Definition paths.h:446
@ kLight
Definition open_gl_image_component.h:309
Interface for events from the PresetBrowser (e.g. preset selected, deleted, or browser hidden).
Definition preset_browser.h:427
static constexpr int kLeftPadding
Definition preset_browser.h:415
PresetBrowser()
Constructs a PresetBrowser.
Definition preset_browser.cpp:580
void resized() override
Called when the component is resized. Arranges layout of child components.
Definition preset_browser.cpp:690
static constexpr int kStoreHeight
Definition preset_browser.h:420
Rectangle< int > getInfoRect()
Returns the rectangle reserved for the preset info area.
Definition preset_browser.cpp:829
static constexpr int kTopPadding
Definition preset_browser.h:416
void newSelection(File selection) override
Called when a new File is selected.
Definition preset_browser.cpp:1037
bool keyStateChanged(bool is_key_down, Component *origin) override
Definition preset_browser.cpp:910
static constexpr int kCommentsFontHeight
Definition preset_browser.h:421
void externalPresetLoaded(File file)
Loads an external preset file and sets it as the current selection.
Definition preset_browser.cpp:943
void jumpToPreset(int indices)
Jumps to a preset a certain number of steps away.
Definition preset_browser.cpp:916
static constexpr int kNameFontHeight
Definition preset_browser.h:418
~PresetBrowser()
Destructor.
Definition preset_browser.cpp:651
void setDeleteSection(DeleteSection *delete_section)
Sets the DeleteSection for handling preset deletion.
Definition preset_browser.cpp:1032
void allSelected() override
Called when "All" special selection is made.
Definition preset_browser.cpp:1042
void textEditorEscapeKeyPressed(TextEditor &editor) override
Definition preset_browser.cpp:866
void loadNextPreset()
Loads the next preset in the list.
Definition preset_browser.cpp:939
void setSaveSection(SaveSection *save_section)
Sets the SaveSection for handling preset saving.
Definition preset_browser.cpp:1027
static constexpr int kAuthorFontHeight
Definition preset_browser.h:419
void paintBackground(Graphics &g) override
Paints the background of the section. Calls paintContainer, heading, knobs, children.
Definition preset_browser.cpp:653
void addListener(Listener *listener)
Adds a listener to receive events from the PresetBrowser.
Definition preset_browser.cpp:1023
void favoritesSelected() override
Called when "Favorites" special selection is made.
Definition preset_browser.cpp:1048
void filterPresets()
Filters the displayed presets based on search text and selected styles.
Definition preset_browser.cpp:849
bool keyPressed(const KeyPress &key, Component *origin) override
Definition preset_browser.cpp:890
static constexpr int kMiddlePadding
Definition preset_browser.h:417
void buttonClicked(Button *clicked_button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition preset_browser.cpp:878
void loadPresets()
Loads all presets from known directories.
Definition preset_browser.cpp:836
void paintBackgroundShadow(Graphics &g) override
Stub for painting background shadows. Overridden by subclasses if needed.
Definition preset_browser.cpp:685
void textEditorTextChanged(TextEditor &editor) override
Definition preset_browser.cpp:862
void visibilityChanged() override
Definition preset_browser.cpp:785
void loadPrevPreset()
Loads the previous preset in the list.
Definition preset_browser.cpp:935
void fileDeleted(File deleted_file) override
Called after a file is deleted.
Definition preset_browser.cpp:874
void save(File preset) override
Called after saving a preset.
Definition preset_browser.cpp:870
Rectangle< int > getSearchRect()
Returns the rectangle reserved for the search area.
Definition preset_browser.cpp:822
A cache for preset metadata such as author and style for faster repeated lookups.
Definition preset_browser.h:21
std::string getStyle(const File &preset)
Retrieves the style of a given preset, caching the result.
Definition preset_browser.h:41
std::string getAuthor(const File &preset)
Retrieves the author of a given preset, caching the result.
Definition preset_browser.h:28
Interface for receiving preset selection and deletion requests.
Definition preset_browser.h:67
int getSelectedIndex()
Gets the index of the currently selected preset.
Definition preset_browser.cpp:404
void respondToMenuCallback(int result)
Handles actions from the preset context menu.
Definition preset_browser.cpp:191
void mouseExit(const MouseEvent &e) override
Definition preset_browser.cpp:187
void mouseDown(const MouseEvent &e) override
Definition preset_browser.cpp:291
void resized() override
Called when the component is resized. Arranges layout of child components.
Definition preset_browser.cpp:120
static constexpr float kScrollSensitivity
Definition preset_browser.h:112
static constexpr float kAuthorWidthPercent
Definition preset_browser.h:110
void leftClick(const MouseEvent &e)
Called on left-click to select, rename, or favorite a preset.
Definition preset_browser.cpp:236
void scrollBarMoved(ScrollBar *scroll_bar, double range_start) override
Definition preset_browser.cpp:312
void reloadPresets()
Reloads the currently displayed presets from disk.
Definition preset_browser.cpp:342
void menuClick(const MouseEvent &e)
Called on right-click to show a context menu.
Definition preset_browser.cpp:217
void mouseMove(const MouseEvent &e) override
Definition preset_browser.cpp:181
PresetList()
Constructs a PresetList.
Definition preset_browser.cpp:40
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Renders all OpenGL components in this section and sub-sections.
Definition preset_browser.cpp:520
void redoCache()
Updates the cached images for rows after sorting or filtering.
Definition preset_browser.cpp:363
void textEditorFocusLost(TextEditor &text_editor) override
Definition preset_browser.cpp:303
void setScrollBarRange()
Definition preset_browser.cpp:317
void destroyOpenGlComponents(OpenGlWrapper &open_gl) override
Destroys all OpenGL components in this section and sub-sections.
Definition preset_browser.cpp:571
void initOpenGlComponents(OpenGlWrapper &open_gl) override
Initializes all OpenGL components in this section and sub-sections.
Definition preset_browser.cpp:419
void finishRename()
Finalizes a preset rename operation.
Definition preset_browser.cpp:328
static constexpr float kStyleWidthPercent
Definition preset_browser.h:109
Column
Definition preset_browser.h:85
@ kAuthor
Definition preset_browser.h:90
@ kDate
Definition preset_browser.h:91
@ kName
Definition preset_browser.h:88
@ kStyle
Definition preset_browser.h:89
@ kStar
Definition preset_browser.h:87
void textEditorReturnKeyPressed(TextEditor &text_editor) override
Definition preset_browser.cpp:298
void setPresets(Array< File > presets)
Sets the array of presets to display.
Definition preset_browser.cpp:157
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Definition preset_browser.cpp:163
void paintBackground(Graphics &g) override
Paints the background of the section. Calls paintContainer, heading, knobs, children.
Definition preset_browser.cpp:71
void shiftSelectedPreset(int indices)
Moves the selected preset up or down by a number of indices.
Definition preset_browser.cpp:352
int getRowHeight()
Gets the row height in pixels.
Definition preset_browser.h:269
static constexpr float kDateWidthPercent
Definition preset_browser.h:111
static constexpr float kNameWidthPercent
Definition preset_browser.h:108
static constexpr int kNumCachedRows
Definition preset_browser.h:105
void textEditorEscapeKeyPressed(TextEditor &editor) override
Definition preset_browser.cpp:308
@ kOpenFileLocation
Definition preset_browser.h:98
@ kRename
Definition preset_browser.h:99
@ kDelete
Definition preset_browser.h:100
void filter(String filter_string, const std::set< std::string > &styles)
Filters the displayed presets by name, author, and styles.
Definition preset_browser.cpp:372
static constexpr float kStarWidthPercent
Definition preset_browser.h:107
int getRowFromPosition(float mouse_position)
Converts a mouse Y position into a row index.
Definition preset_browser.cpp:175
int getScrollableRange()
Gets the scrollable height of the presets.
Definition preset_browser.cpp:412
A UI overlay for saving presets or other files.
Definition save_section.h:21
void addSaveListener(Listener *listener)
Adds a listener to be notified when saving occurs.
Definition save_section.h:161
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kBodyRounding
Definition skin.h:71
@ kLargePadding
Definition skin.h:82
@ kWidgetRoundedCorner
Definition skin.h:104
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetBackground
Definition skin.h:173
@ kBodyText
Definition skin.h:133
@ kLightenScreen
Definition skin.h:141
@ kTextEditorSelection
Definition skin.h:203
@ kTextComponentText
Definition skin.h:148
@ kTextEditorCaret
Definition skin.h:202
@ kBody
Definition skin.h:129
@ kPresetBrowser
Definition skin.h:57
A base class providing foundational functionality for the Vital synthesizer’s engine,...
Definition synth_base.h:42
void setAuthor(const String &author)
Sets the author metadata of the current preset.
Definition synth_base.cpp:681
bool loadFromFile(File preset, std::string &error)
Attempts to load a preset from a file.
Definition synth_base.cpp:338
String getAuthor()
Gets the author of the current preset.
Definition synth_base.cpp:701
String getComments()
Gets the comments for the current preset.
Definition synth_base.cpp:705
String getPresetName()
Gets the current preset’s name.
Definition synth_base.cpp:713
void setPresetName(const String &preset_name)
Sets the preset name.
Definition synth_base.cpp:693
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 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
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
virtual void paintBody(Graphics &g, Rectangle< int > bounds)
Paints the body background within given bounds.
Definition synth_section.cpp:165
void paintChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all child sections.
Definition synth_section.cpp:274
virtual int getPixelMultiple() const
Definition synth_section.cpp:729
virtual void destroyOpenGlComponents(OpenGlWrapper &open_gl)
Destroys all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:383
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 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
virtual void paintBorder(Graphics &g, Rectangle< int > bounds)
Paints the border around given bounds.
Definition synth_section.cpp:170
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
float getSizeRatio() const
Definition synth_section.h:765
float getTitleWidth()
Definition synth_section.cpp:629
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
virtual void initOpenGlComponents(OpenGlWrapper &open_gl)
Initializes all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:349
virtual void paintTabShadow(Graphics &g)
Paints a tab-like shadow effect around the component.
Definition synth_section.cpp:188
float getWidgetMargin()
Definition synth_section.cpp:676
static TextLookAndFeel * instance()
Singleton instance access.
Definition text_look_and_feel.h:106
nlohmann::json json
Definition line_generator.h:7
const std::string kPresetStyleNames[]
Names for preset categories or styles.
Definition synth_strings.h:81
force_inline int nextPowerOfTwo(mono_float value)
Finds the next power of two greater than or equal to a float value.
Definition utils.h:370
const std::string kPresetExtension
File extension for Vital preset files.
Definition synth_constants.h:85
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