Vital
Loading...
Searching...
No Matches
bank_exporter.cpp
Go to the documentation of this file.
1
3
4#include "bank_exporter.h"
5
6#include "skin.h"
7#include "fonts.h"
8#include "load_save.h"
9#include "paths.h"
10#include "open_gl_component.h"
11#include "open_gl_image.h"
12#include "synth_section.h"
13
14namespace {
15 template<class Comparator>
16 void sortFiles(Array<File>& file_array) {
17 Comparator comparator;
18 file_array.sort(comparator, true);
19 }
20
21 String getRelativePath(const File& file, const String& folder) {
22 File parent = file;
23 while (parent.exists() && !parent.isRoot()) {
24 parent = parent.getParentDirectory();
25 if (parent.getFileName() == folder)
26 return file.getRelativePathFrom(parent).replaceCharacter(File::getSeparatorChar(), '/');
27 }
28
29 return file.getFileName();
30 }
31}
32
33ContentList::ContentList(const std::string& name) :
34 SynthSection(name), num_contents_(0), last_selected_index_(-1), hover_index_(-1),
35 cache_position_(0), view_position_(0), sort_column_(kDate), sort_ascending_(true), selected_(),
36 highlight_(kNumCachedRows, Shaders::kColorFragment), hover_(Shaders::kColorFragment) {
37 addAndMakeVisible(browse_area_);
38 browse_area_.setInterceptsMouseClicks(false, false);
39 highlight_.setTargetComponent(&browse_area_);
40 hover_.setTargetComponent(&browse_area_);
41 highlight_.setAdditive(true);
42 hover_.setAdditive(true);
43
44 scroll_bar_ = std::make_unique<OpenGlScrollBar>();
45 addAndMakeVisible(scroll_bar_.get());
46 addOpenGlComponent(scroll_bar_->getGlComponent());
47 scroll_bar_->addListener(this);
48}
49
51 int title_width = getTitleWidth();
52 g.setColour(findColour(Skin::kWidgetBackground, true));
53 g.fillRoundedRectangle(getLocalBounds().toFloat(), findValue(Skin::kBodyRounding));
54
55 int selected_width = kAddWidthRatio * getWidth();
56 int name_width = kNameWidthRatio * getWidth();
57 int date_width = getWidth() - name_width;
58 int row_height = getRowHeight();
59 int text_padding = row_height / 2;
60
61 g.saveState();
62 g.setColour(findColour(Skin::kBody, true));
63 g.reduceClipRegion(getLocalBounds().removeFromTop(title_width));
64 Rectangle<float> top = getLocalBounds().toFloat().removeFromTop(title_width * 2.0f);
65 g.fillRoundedRectangle(top, findValue(Skin::kBodyRounding));
66 g.restoreState();
67
68 Colour lighten = findColour(Skin::kLightenScreen, true);
69 scroll_bar_->setColor(lighten);
70
71 g.setColour(lighten);
72 g.fillRect(selected_width, 0, 1, title_width);
73 g.fillRect(selected_width + name_width, 0, 1, title_width);
74
75 g.setColour(findColour(Skin::kTextComponentText, true));
76 g.setFont(Fonts::instance()->proportional_regular().withPointHeight(title_width * 0.5f));
77
78 String name = getName() + " Name";
79 g.drawText(name, selected_width + text_padding, 0, name_width, title_width, Justification::centredLeft);
80 g.drawText("Date", getWidth() - date_width, 0,
81 date_width - text_padding, title_width, Justification::centredRight);
82
83 setWantsKeyboardFocus(true);
84 setMouseClickGrabsKeyboardFocus(true);
85}
86
88 static constexpr float kScrollBarWidth = 15.0f;
89
90 int scroll_bar_width = kScrollBarWidth * getSizeRatio();
91 int title_width = getTitleWidth();
92 int scroll_bar_height = getHeight() - title_width;
93 scroll_bar_->setBounds(getWidth() - scroll_bar_width, title_width, scroll_bar_width, scroll_bar_height);
95
96 browse_area_.setBounds(0, title_width, getWidth(), getHeight() - title_width);
97 loadBrowserCache(cache_position_, cache_position_ + kNumCachedRows);
98}
99
100void ContentList::sort() {
101 if (sort_column_ == kName && sort_ascending_)
102 sortFiles<FileNameAscendingComparator>(contents_);
103 else if (sort_column_ == kName && !sort_ascending_)
104 sortFiles<FileNameDescendingComparator>(contents_);
105 else if (sort_column_ == kDate && sort_ascending_)
106 sortFiles<FileDateAscendingComparator>(contents_);
107 else if (sort_column_ == kDate && !sort_ascending_)
108 sortFiles<FileDateDescendingComparator>(contents_);
109 else if (sort_column_ == kAdded) {
110 SelectedComparator comparator(selected_files_, sort_ascending_);
111 contents_.sort(comparator, true);
112 }
113}
114
115void ContentList::setContent(Array<File> contents) {
116 contents_ = std::move(contents);
117 num_contents_ = contents_.size();
118 redoCache();
120}
121
122void ContentList::mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) {
123 view_position_ -= wheel.deltaY * kScrollSensitivity;
124 view_position_ = std::max(0.0f, view_position_);
125 int title_width = getTitleWidth();
126 float scaled_height = getHeight() - title_width;
127 int scrollable_range = getScrollableRange();
128 view_position_ = std::min(view_position_, 1.0f * scrollable_range - scaled_height);
129 viewPositionChanged();
131}
132
133int ContentList::getRowFromPosition(float mouse_position) {
134 int title_width = getTitleWidth();
135
136 return floorf((mouse_position + getViewPosition() - title_width) / getRowHeight());
137}
138
139void ContentList::mouseMove(const MouseEvent& e) {
140 hover_index_ = getRowFromPosition(e.position.y);
141 if (hover_index_ >= contents_.size())
142 hover_index_ = -1;
143}
144
145void ContentList::mouseExit(const MouseEvent& e) {
146 hover_index_ = -1;
147}
148
149void ContentList::mouseDown(const MouseEvent& e) {
150 int title_width = getTitleWidth();
151 float click_y_position = e.position.y;
152 float click_x_position = e.position.x;
153 int row = getRowFromPosition(click_y_position);
154
155 if (click_y_position <= title_width) {
156 int selected_right = kAddWidthRatio * getWidth();
157 int name_right = selected_right + kNameWidthRatio * getWidth();
158 Column clicked_column;
159
160 if (click_x_position < selected_right)
161 clicked_column = kAdded;
162 else if (click_x_position < name_right)
163 clicked_column = kName;
164 else
165 clicked_column = kDate;
166
167 if (clicked_column == sort_column_)
168 sort_ascending_ = !sort_ascending_;
169 else
170 sort_ascending_ = true;
171 sort_column_ = clicked_column;
172 sort();
173 repaint();
174 redoCache();
175 }
176 else if (row < contents_.size() && row >= 0) {
177 if (click_x_position < kAddWidthRatio * getWidth()) {
178 if (highlighted_files_.count(contents_[row].getFullPathName().toStdString()) == 0)
179 highlightClick(e, row);
180 selectHighlighted(row);
181 }
182 else
183 highlightClick(e, row);
184
185 redoCache();
186 repaint();
187 }
188}
189
190void ContentList::scrollBarMoved(ScrollBar* scroll_bar, double range_start) {
191 view_position_ = range_start;
192 viewPositionChanged();
193}
194
196 static constexpr float kScrollStepRatio = 0.05f;
197
198 int title_width = getTitleWidth();
199 float scaled_height = getHeight() - title_width;
200 scroll_bar_->setRangeLimits(0.0f, getScrollableRange());
201 scroll_bar_->setCurrentRange(view_position_, scaled_height, dontSendNotification);
202 scroll_bar_->setSingleStepSize(scroll_bar_->getHeight() * kScrollStepRatio);
203 scroll_bar_->cancelPendingUpdate();
204}
205
206void ContentList::selectHighlighted(int clicked_index) {
207 std::string path = contents_[clicked_index].getFullPathName().toStdString();
208 if (selected_files_.count(path)) {
209 for (const std::string& highlighted : highlighted_files_)
210 selected_files_.erase(highlighted);
211 }
212 else {
213 for (const std::string& highlighted : highlighted_files_)
214 selected_files_.insert(highlighted);
215 }
216}
217
218void ContentList::highlightClick(const MouseEvent& e, int clicked_index) {
219 int cache_index = clicked_index - cache_position_;
220 if (e.mods.isShiftDown())
221 selectRange(clicked_index);
222 else if (e.mods.isCommandDown()) {
223 std::string path = contents_[clicked_index].getFullPathName().toStdString();
224 bool selected = highlighted_files_.count(path);
225 if (selected)
226 highlighted_files_.erase(path);
227 else
228 highlighted_files_.insert(path);
229 if (cache_index >= 0 && cache_index < kNumCachedRows)
230 selected_[cache_index] = !selected;
231 }
232 else {
233 highlighted_files_.clear();
234 for (int i = 0; i < kNumCachedRows; ++i)
235 selected_[i] = i == cache_index;
236 highlighted_files_.insert(contents_[clicked_index].getFullPathName().toStdString());
237 }
238
239 last_selected_index_ = clicked_index;
240}
241
242void ContentList::selectRange(int clicked_index) {
243 if (last_selected_index_ < 0)
244 last_selected_index_ = clicked_index;
245
246 int start = std::min(std::min(clicked_index, last_selected_index_), contents_.size());
247 int end = std::min(std::max(clicked_index, last_selected_index_), contents_.size());
248
249 for (int i = start; i <= end; ++i) {
250 int cache_index = i - cache_position_;
251 if (cache_index >= 0 && cache_index < kNumCachedRows)
252 selected_[cache_index] = true;
253 highlighted_files_.insert(contents_[i].getFullPathName().toStdString());
254 }
255}
256
258 if (getWidth() <= 0 || getHeight() <= 0)
259 return;
260
261 int max = static_cast<int>(contents_.size()) - kNumCachedRows;
262 int position = std::max(0, std::min<int>(cache_position_, max));
263 loadBrowserCache(position, position + kNumCachedRows);
264}
265
267 int row_height = getRowHeight();
268 int title_width = getTitleWidth();
269 int presets_height = row_height * static_cast<int>(contents_.size());
270 return std::max(presets_height, getHeight() - title_width);
271}
272
274 for (int i = 0; i < kNumCachedRows; ++i) {
275 rows_[i].setScissor(true);
276 rows_[i].init(open_gl);
277 rows_[i].setColor(Colours::white);
278 }
279
280 highlight_.init(open_gl);
281 hover_.init(open_gl);
283}
284
285void ContentList::viewPositionChanged() {
286 int row_height = getRowHeight();
287
288 int last_cache_position = cache_position_;
289 cache_position_ = getViewPosition() / row_height;
290 int max = static_cast<int>(contents_.size() - kNumCachedRows);
291 cache_position_ = std::max(0, std::min<int>(cache_position_, max));
292
293 if (std::abs(cache_position_ - last_cache_position) >= kNumCachedRows)
294 redoCache();
295 else if (last_cache_position < cache_position_)
296 loadBrowserCache(last_cache_position + kNumCachedRows, cache_position_ + kNumCachedRows);
297 else if (last_cache_position > cache_position_)
298 loadBrowserCache(cache_position_, last_cache_position);
299}
300
301void ContentList::loadBrowserCache(int start_index, int end_index) {
302 int mult = getPixelMultiple();
303 int row_height = getRowHeight() * mult;
304 int image_width = getWidth() * mult;
305
306 int text_padding = row_height / 2.0f;
307 int add_x = text_padding;
308 int add_width = kAddWidthRatio * image_width;
309 int name_x = add_x + add_width;
310 int name_width = kNameWidthRatio * image_width;
311 int date_width = kDateWidthRatio * image_width;
312 int date_x = image_width - date_width + text_padding;
313
314 end_index = std::min(static_cast<int>(contents_.size()), end_index);
315 Font font = Fonts::instance()->proportional_light().withPointHeight(row_height * 0.5f);
316
317 Path icon;
318 icon.addRoundedRectangle(0.0f, 0.0f, 1.0f, 1.0f, 0.1f, 0.1f);
319 icon.addPath(Paths::plusOutline());
320 float add_draw_width = row_height * 0.8f;
321 float add_y = (row_height - add_draw_width) / 2.0f;
322 Rectangle<float> add_bounds((add_width - add_draw_width) / 2.0f, add_y, add_draw_width, add_draw_width);
323 icon.applyTransform(icon.getTransformToScaleToFit(add_bounds, true));
324 PathStrokeType add_stroke(1.0f, PathStrokeType::curved);
325
326 Colour text_color = findColour(Skin::kTextComponentText, true);
327 Colour add_unselected = findColour(Skin::kLightenScreen, true);
328 Colour add_selected = findColour(Skin::kWidgetPrimary1, true);
329
330 for (int i = start_index; i < end_index; ++i) {
331 Image row_image(Image::ARGB, image_width, row_height, true);
332 Graphics g(row_image);
333
334 File content = contents_[i];
335 String name = content.getFileNameWithoutExtension();
336 String date = content.getCreationTime().toString(true, false, false);
337
338 if (selected_files_.count(content.getFullPathName().toStdString()))
339 g.setColour(add_selected);
340 else
341 g.setColour(add_unselected);
342
343 g.fillPath(icon);
344
345 g.setColour(text_color);
346 g.setFont(font);
347 g.drawText(name, name_x, 0, name_width - 2 * text_padding, row_height, Justification::centredLeft, true);
348 g.drawText(date, date_x, 0, date_width - 2 * text_padding, row_height, Justification::centredRight, true);
349
350 rows_[i % kNumCachedRows].setOwnImage(row_image);
351 selected_[i % kNumCachedRows] = highlighted_files_.count(content.getFullPathName().toStdString());
352 }
353}
354
355void ContentList::moveQuadToRow(OpenGlMultiQuad* quad, int index, int row, float y_offset) {
356 int row_height = getRowHeight();
357 float view_height = getHeight() - (int)getTitleWidth();
358 float open_gl_row_height = 2.0f * row_height / view_height;
359 float offset = row * open_gl_row_height;
360
361 float y = 1.0f + y_offset - offset;
362 quad->setQuad(index, -1.0f, y - open_gl_row_height, 2.0f, open_gl_row_height);
363}
364
366 int title_width = getTitleWidth();
367 float view_height = getHeight() - title_width;
368 int row_height = getRowHeight();
369 int num_contents = num_contents_;
370
371 int view_position = getViewPosition();
372 float y_offset = 2.0f * view_position / view_height;
373
374 Rectangle<int> view_bounds(0, title_width, getWidth(), getHeight() - title_width);
375 OpenGlComponent::setViewPort(this, view_bounds, open_gl);
376
377 float image_width = vital::utils::nextPowerOfTwo(getWidth());
378 float image_height = vital::utils::nextPowerOfTwo(row_height);
379 float width_ratio = image_width / getWidth();
380 float height_ratio = image_height / row_height;
381
382 float open_gl_row_height = 2.0f * row_height / view_height;
383 float open_gl_image_height = height_ratio * open_gl_row_height;
384 int cache_position = std::max(0, std::min(cache_position_, num_contents - kNumCachedRows));
385 int num_selected = 0;
386 for (int i = 0; i < kNumCachedRows && i < num_contents; ++i) {
387 int row = cache_position + i;
388 int cache_index = row % kNumCachedRows;
389 float offset = (2.0f * row_height * row) / view_height;
390 float y = 1.0f + y_offset - offset;
391
392 Rectangle<int> row_bounds(0, row_height * row - view_position + title_width, getWidth(), row_height);
393 OpenGlComponent::setScissorBounds(this, row_bounds, open_gl);
394
395 rows_[cache_index].setTopLeft(-1.0f, y);
396 rows_[cache_index].setTopRight(-1.0f + 2.0f * width_ratio, y);
397 rows_[cache_index].setBottomLeft(-1.0f, y - open_gl_image_height);
398 rows_[cache_index].setBottomRight(-1.0f + 2.0f * width_ratio, y - open_gl_image_height);
399 rows_[cache_index].drawImage(open_gl);
400
401 if (selected_[cache_index]) {
402 highlight_.setQuad(num_selected, -1.0f, y - open_gl_row_height, 2.0f, open_gl_row_height);
403 num_selected++;
404 }
405 }
406
407 highlight_.setNumQuads(num_selected);
408 highlight_.setColor(findColour(Skin::kWidgetSecondary1, true).darker(0.8f));
409 highlight_.render(open_gl, animate);
410
411 if (hover_index_ >= 0) {
412 moveQuadToRow(&hover_, 0, hover_index_, y_offset);
413 hover_.setColor(findColour(Skin::kLightenScreen, true));
414 hover_.render(open_gl, animate);
415 }
416
418}
419
421 for (int i = 0; i < kNumCachedRows; ++i)
422 rows_[i].destroy(open_gl);
423
424 highlight_.destroy(open_gl);
425 hover_.destroy(open_gl);
427}
428
430 export_bank_button_ = std::make_unique<OpenGlToggleButton>("Export Bank");
431 export_bank_button_->setEnabled(false);
432 export_bank_button_->addListener(this);
433 export_bank_button_->setUiButton(true);
434 addAndMakeVisible(export_bank_button_.get());
435 addOpenGlComponent(export_bank_button_->getGlComponent());
436
437 addKeyListener(this);
438
439 preset_list_ = std::make_unique<ContentList>("Preset");
440 addSubSection(preset_list_.get());
441 wavetable_list_ = std::make_unique<ContentList>("Wavetable");
442 addSubSection(wavetable_list_.get());
443 lfo_list_ = std::make_unique<ContentList>("LFO");
444 addSubSection(lfo_list_.get());
445 sample_list_ = std::make_unique<ContentList>("Sample");
446 addSubSection(sample_list_.get());
447
448#if !defined(NO_TEXT_ENTRY)
449 bank_name_box_ = std::make_unique<OpenGlTextEditor>("Bank Name");
450 bank_name_box_->addListener(this);
451 bank_name_box_->setSelectAllWhenFocused(true);
452 bank_name_box_->setMultiLine(false, false);
453 bank_name_box_->setJustification(Justification::centredLeft);
454 addAndMakeVisible(bank_name_box_.get());
455 addOpenGlComponent(bank_name_box_->getImageComponent());
456#endif
457
458 setWantsKeyboardFocus(true);
459 setMouseClickGrabsKeyboardFocus(true);
461}
462
464
467 Rectangle<int> export_bounds = wavetable_list_->getBounds();
468 export_bounds.setY(0);
469 export_bounds.setHeight(wavetable_list_->getY() - findValue(Skin::kLargePadding));
470 paintBody(g, export_bounds);
471
472 Colour empty_color = findColour(Skin::kBodyText, true);
473 empty_color = empty_color.withAlpha(0.5f * empty_color.getFloatAlpha());
474 setButtonColors();
475
476 if (bank_name_box_) {
477 bank_name_box_->setTextToShowWhenEmpty(TRANS("Bank Name"), empty_color);
478 bank_name_box_->setColour(CaretComponent::caretColourId, findColour(Skin::kTextEditorCaret, true));
479 bank_name_box_->setColour(TextEditor::textColourId, findColour(Skin::kBodyText, true));
480 bank_name_box_->setColour(TextEditor::highlightedTextColourId, findColour(Skin::kBodyText, true));
481 bank_name_box_->setColour(TextEditor::highlightColourId, findColour(Skin::kTextEditorSelection, true));
482 bank_name_box_->redoImage();
483 }
484}
485
487 paintTabShadow(g, preset_list_->getBounds());
488 paintTabShadow(g, wavetable_list_->getBounds());
489 paintTabShadow(g, lfo_list_->getBounds());
490 paintTabShadow(g, sample_list_->getBounds());
491
492 Rectangle<int> export_bounds = wavetable_list_->getBounds();
493 export_bounds.setY(0);
494 export_bounds.setHeight(wavetable_list_->getY() - findValue(Skin::kLargePadding));
495 paintTabShadow(g, export_bounds);
496}
497
499 static constexpr float kOptionsHeight = 0.08f;
500
501 int padding_width = findValue(Skin::kLargePadding);
502 int browse_width = getWidth() / 2 - padding_width;
503 preset_list_->setBounds(0, 0, browse_width, getHeight());
504
505 int options_height = kOptionsHeight * getHeight();
506 int other_browse_x = getWidth() - browse_width - padding_width;
507 int other_browse_height = (getHeight() - options_height - 2.0f * padding_width) / 3.0f;
508
509 wavetable_list_->setBounds(other_browse_x, options_height, browse_width, other_browse_height);
510
511 Rectangle<int> export_bounds = wavetable_list_->getBounds();
512 export_bounds.setY(0);
513 export_bounds.setHeight(wavetable_list_->getY() - findValue(Skin::kLargePadding));
514
515 int lfo_y = wavetable_list_->getBottom() + padding_width;
516 lfo_list_->setBounds(other_browse_x, lfo_y, browse_width, other_browse_height);
517
518 int sample_y = getHeight() - other_browse_height;
519 sample_list_->setBounds(other_browse_x, sample_y, browse_width, other_browse_height);
520
521 int widget_margin = findValue(Skin::kWidgetMargin);
522 int active_export_width = export_bounds.getWidth() - 3 * widget_margin;
523 int bank_name_width = active_export_width / 2;
524 int export_button_width = active_export_width - bank_name_width;
525 int options_y = export_bounds.getY() + widget_margin;
526 int option_component_height = export_bounds.getHeight() - 2 * widget_margin;
527
528 int name_x = export_bounds.getX() + widget_margin;
529 int export_button_x = name_x + bank_name_width + widget_margin;
530 export_bank_button_->setBounds(export_button_x, options_y, export_button_width, option_component_height);
531
532 if (bank_name_box_) {
533 bank_name_box_->setBounds(name_x, options_y, bank_name_width, option_component_height);
534 bank_name_box_->resized();
535 }
536}
537
539 SynthSection::visibilityChanged();
540 if (isShowing())
541 loadFiles();
542}
543
544void BankExporter::textEditorTextChanged(TextEditor& editor) {
545 bool enabled = bank_name_box_ && bank_name_box_->getText().trim() != "";
546 if (enabled == export_bank_button_->isEnabled())
547 return;
548
549 export_bank_button_->setEnabled(enabled);
550 setButtonColors();
551}
552
553void BankExporter::setButtonColors() {
554 if (export_bank_button_->isEnabled())
555 export_bank_button_->setColour(Skin::kUiButton, findColour(Skin::kUiActionButton, true));
556 else
557 export_bank_button_->setColour(Skin::kUiButton, findColour(Skin::kUiButtonPressed, true));
558
559 export_bank_button_->setColour(Skin::kUiButtonHover, findColour(Skin::kUiActionButtonHover, true));
560 export_bank_button_->setColour(Skin::kUiButtonPressed, findColour(Skin::kUiActionButtonPressed, true));
561}
562
563void BankExporter::exportBank() {
564 ZipFile::Builder bank_zip;
565 String bank_name = bank_name_box_->getText().trim();
566 if (bank_name.isEmpty())
567 return;
568
569 std::set<std::string> presets = preset_list_->selectedFiles();
570 std::set<std::string> wavetables = wavetable_list_->selectedFiles();
571 std::set<std::string> lfos = lfo_list_->selectedFiles();
572 std::set<std::string> samples = sample_list_->selectedFiles();
573
574 if (presets.empty() && wavetables.empty() && lfos.empty() && samples.empty())
575 return;
576
577 String preset_path = bank_name + "/" + LoadSave::kPresetFolderName + "/";
578 for (const std::string& path : presets) {
579 File preset(path);
580 if (preset.exists())
581 bank_zip.addFile(preset, 9, preset_path + getRelativePath(preset, LoadSave::kPresetFolderName));
582 }
583
584 String wavetable_path = bank_name + "/" + LoadSave::kWavetableFolderName + "/";
585 for (const std::string& path : wavetables) {
586 File wavetable(path);
587 if (wavetable.exists())
588 bank_zip.addFile(wavetable, 9, wavetable_path + getRelativePath(wavetable, LoadSave::kWavetableFolderName));
589 }
590
591 String lfo_path = bank_name + "/" + LoadSave::kLfoFolderName + "/";
592 for (const std::string& path : lfos) {
593 File lfo(path);
594 if (lfo.exists())
595 bank_zip.addFile(lfo, 9, lfo_path + getRelativePath(lfo, LoadSave::kLfoFolderName));
596 }
597
598 String sample_path = bank_name + "/" + LoadSave::kSampleFolderName + "/";
599 for (const std::string& path : samples) {
600 File sample(path);
601 if (sample.exists())
602 bank_zip.addFile(sample, 9, sample_path + getRelativePath(sample, LoadSave::kSampleFolderName));
603 }
604
605 File file = File::getCurrentWorkingDirectory().getChildFile(bank_name + "." + vital::kBankExtension);
606 FileChooser export_box("Export Bank", file, String("*.") + vital::kBankExtension);
607 if (export_box.browseForFileToSave(true)) {
608 File destination = export_box.getResult().withFileExtension(vital::kBankExtension);
609 if (destination.hasWriteAccess()) {
610 FileOutputStream output_stream(destination);
611 if (output_stream.openedOk())
612 bank_zip.writeToStream(output_stream, nullptr);
613 }
614 }
615}
616
617void BankExporter::loadFiles() {
618 Array<File> presets;
620 preset_list_->setContent(presets);
621
622 Array<File> wavetables;
624 wavetable_list_->setContent(wavetables);
625
626 Array<File> lfos;
628 lfo_list_->setContent(lfos);
629
630 Array<File> samples;
632 sample_list_->setContent(samples);
633}
634
635void BankExporter::buttonClicked(Button* clicked_button) {
636 if (clicked_button == export_bank_button_.get())
637 exportBank();
638}
639
640bool BankExporter::keyPressed(const KeyPress &key, Component *origin) {
641 if (key.getKeyCode() == KeyPress::escapeKey && isVisible()) {
642 setVisible(false);
643 return true;
644 }
645 return bank_name_box_->hasKeyboardFocus(true);
646}
647
648bool BankExporter::keyStateChanged(bool is_key_down, Component *origin) {
649 if (is_key_down)
650 return bank_name_box_->hasKeyboardFocus(true);
651 return false;
652}
Declares the ContentList and BankExporter classes for exporting banks of presets, wavetables,...
void visibilityChanged() override
Called when visibility changes, loads files if becoming visible.
Definition bank_exporter.cpp:538
bool keyPressed(const KeyPress &key, Component *origin) override
Definition bank_exporter.cpp:640
bool keyStateChanged(bool is_key_down, Component *origin) override
Definition bank_exporter.cpp:648
void textEditorTextChanged(TextEditor &editor) override
Definition bank_exporter.cpp:544
~BankExporter()
Destructor.
void paintBackgroundShadow(Graphics &g) override
Definition bank_exporter.cpp:486
void paintBackground(Graphics &g) override
Definition bank_exporter.cpp:465
void resized() override
Resizes and lays out child components.
Definition bank_exporter.cpp:498
void buttonClicked(Button *clicked_button) override
Definition bank_exporter.cpp:635
BankExporter()
Constructor.
Definition bank_exporter.cpp:429
static constexpr float kScrollSensitivity
Scroll sensitivity factor.
Definition bank_exporter.h:51
void scrollBarMoved(ScrollBar *scroll_bar, double range_start) override
Definition bank_exporter.cpp:190
ContentList(const std::string &name)
Definition bank_exporter.cpp:33
void setContent(Array< File > presets)
Definition bank_exporter.cpp:115
static constexpr float kDateWidthRatio
Width ratio allocated to the date column.
Definition bank_exporter.h:49
static constexpr float kNameWidthRatio
Width ratio allocated to the name column.
Definition bank_exporter.h:47
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Handles mouse wheel events for scrolling.
Definition bank_exporter.cpp:122
int getScrollableRange()
Definition bank_exporter.cpp:266
int getRowFromPosition(float mouse_position)
Definition bank_exporter.cpp:133
void setScrollBarRange()
Updates the scrollbar range based on content size and view position.
Definition bank_exporter.cpp:195
void resized() override
Resizes and lays out child components.
Definition bank_exporter.cpp:87
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Definition bank_exporter.cpp:365
void destroyOpenGlComponents(OpenGlWrapper &open_gl) override
Definition bank_exporter.cpp:420
int getRowHeight()
Definition bank_exporter.h:142
void mouseMove(const MouseEvent &e) override
Handles mouse move events for hover effects.
Definition bank_exporter.cpp:139
void mouseDown(const MouseEvent &e) override
Handles mouse down events for selection and sorting actions.
Definition bank_exporter.cpp:149
void redoCache()
Reloads cached rows after content changes.
Definition bank_exporter.cpp:257
void mouseExit(const MouseEvent &e) override
Handles mouse exit events to clear hover state.
Definition bank_exporter.cpp:145
void paintBackground(Graphics &g) override
Definition bank_exporter.cpp:50
static constexpr float kAddWidthRatio
Width ratio allocated to the "add" (selection) column.
Definition bank_exporter.h:45
void initOpenGlComponents(OpenGlWrapper &open_gl) override
Definition bank_exporter.cpp:273
static constexpr int kNumCachedRows
Number of rows to keep cached.
Definition bank_exporter.h:41
Column
Columns used in the list for sorting and display.
Definition bank_exporter.h:32
@ kDate
Column representing file date.
Definition bank_exporter.h:36
@ kAdded
Column representing selection status.
Definition bank_exporter.h:34
@ kName
Column representing file name.
Definition bank_exporter.h:35
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
static const std::string kPresetFolderName
Definition load_save.h:74
static void getAllUserLfos(Array< File > &lfos)
Retrieves all user LFO shapes (from data and user directories).
Definition load_save.cpp:1871
static const std::string kSampleFolderName
Definition load_save.h:77
static void getAllUserPresets(Array< File > &presets)
Retrieves all user presets (from data and user directories).
Definition load_save.cpp:1855
static const std::string kLfoFolderName
Definition load_save.h:78
static void getAllUserWavetables(Array< File > &wavetables)
Retrieves all user wavetables (from data and user directories).
Definition load_save.cpp:1863
static const std::string kWavetableFolderName
Definition load_save.h:75
static void getAllUserSamples(Array< File > &samples)
Retrieves all user samples (from data and user directories).
Definition load_save.cpp:1879
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
A component for rendering multiple quads using OpenGL, with customizable colors, rounding,...
Definition open_gl_multi_quad.h:16
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
void setNumQuads(int num_quads)
Sets how many quads will actually be drawn (up to max_quads).
Definition open_gl_multi_quad.h:92
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
static Path plusOutline()
Definition paths.h:322
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kWidgetMargin
Definition skin.h:103
@ kBodyRounding
Definition skin.h:71
@ kLargePadding
Definition skin.h:82
@ kUiButtonPressed
Definition skin.h:195
@ kUiActionButton
Definition skin.h:196
@ kUiButtonHover
Definition skin.h:194
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetBackground
Definition skin.h:173
@ kBodyText
Definition skin.h:133
@ kWidgetSecondary1
Definition skin.h:168
@ kLightenScreen
Definition skin.h:141
@ kUiActionButtonHover
Definition skin.h:197
@ kUiActionButtonPressed
Definition skin.h:198
@ kUiButton
Definition skin.h:192
@ 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
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 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
float findValue(Skin::ValueId value_id) const
Finds a value in the skin overrides or from the parent if not found locally.
Definition synth_section.cpp:18
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
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
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 kBankExtension
File extension for Vital bank files, which group multiple presets.
Definition synth_constants.h:103
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174