12 template<
class Comparator>
13 void sortSelectionArray(Array<File>& selection_array) {
14 Comparator comparator;
15 selection_array.sort(comparator,
true);
18 const std::string kAddFolderName =
"Add Folder";
19 const std::string kStoreUrl =
"";
20 constexpr int kMaxRootFiles = 8000;
23 bool isAcceptableRoot(
const File& file) {
24 std::list<File> folders;
25 folders.push_back(file);
28 while (!folders.empty()) {
29 File current_file = folders.back();
32 num_files += current_file.getNumberOfChildFiles(File::findFiles);
33 if (num_files > kMaxRootFiles)
36 Array<File> sub_folders = current_file.findChildFiles(File::findDirectories,
false);
38 for (
const File& folder : sub_folders)
39 folders.push_back(folder);
46 void showAddRootWarning() {
47 String error = String(
"Folder has too many files to add to browser. Max: ") + String(kMaxRootFiles);
48 NativeMessageBox::showMessageBoxAsync(AlertWindow::WarningIcon,
"Error Adding Folder", error);
53 body_(
Shaders::kRoundedRectangleFragment),
54 border_(
Shaders::kRoundedRectangleBorderFragment) {
66 Rectangle<int> bounds = getLocalBounds();
69 body_.setBounds(bounds);
73 border_.setBounds(bounds);
78 text_.setBounds(bounds);
83 BubbleComponent::BubblePlacement placement) {
86 String textToDisplay(text.c_str());
90 lines.addLines(textToDisplay);
93 static constexpr int kBaseHeight = 24;
100 for (
auto& line : lines) {
101 maxWidth = jmax(maxWidth, font.getStringWidth(line));
105 int padding = height / 4;
106 int buffer = padding * 2 + 2;
110 int numLines = lines.size();
111 int lineHeight = height;
112 int totalHeight = lineHeight * numLines;
116 int middle_x = bounds.getX() + bounds.getWidth() / 2;
117 int middle_y = bounds.getY() + bounds.getHeight() / 2;
119 if (placement == BubbleComponent::above) {
120 setBounds(middle_x - totalWidth / 2,
121 bounds.getY() - totalHeight,
122 totalWidth, totalHeight);
123 }
else if (placement == BubbleComponent::below) {
124 setBounds(middle_x - totalWidth / 2,
126 totalWidth, totalHeight);
127 }
else if (placement == BubbleComponent::left) {
128 setBounds(bounds.getX() - totalWidth,
129 middle_y - totalHeight / 2,
130 totalWidth, totalHeight);
131 }
else if (placement == BubbleComponent::right) {
132 setBounds(bounds.getRight(),
133 middle_y - totalHeight / 2,
134 totalWidth, totalHeight);
144 selected_(-1), hovered_(-1), show_selected_(false), view_position_(0.0f),
145 highlight_(
Shaders::kColorFragment), hover_(
Shaders::kColorFragment) {
152 scroll_bar_ = std::make_unique<OpenGlScrollBar>();
153 addAndMakeVisible(scroll_bar_.get());
155 scroll_bar_->addListener(
this);
160 scroll_bar_->setColor(lighten);
164 int scroll_bar_height = getHeight();
165 scroll_bar_->setVisible(
true);
166 scroll_bar_->setBounds(getWidth() - scroll_bar_width, 0, scroll_bar_width, scroll_bar_height);
170 scroll_bar_->setVisible(
false);
176 selections_ = std::move(selections);
177 selected_ = std::min(selected_, selections_.
size() - 1);
178 hovered_ = std::min(hovered_, selections_.
size() - 1);
179 for (
int i = 0; i < selections_.
size(); ++i) {
180 if (selections_.
items[i].selected)
187 int index = floorf((mouse_position + getViewPosition()) /
getRowHeight());
188 if (index < selections_.
size() && index >= 0 && selections_.
items[index].id < 0)
194 static constexpr int kMinWidth = 150;
199 for (
int i = 0; i < selections_.
size(); ++i)
200 max_width = std::max(max_width, font.getStringWidth(selections_.
items[i].name) /
getPixelMultiple() + buffer);
207 if (row >= selections_.
size() || row < 0)
214 if (e.position.x < 0 || e.position.x > getWidth() || row >= selections_.
size() || row < 0)
224 float click_y_position = e.position.y;
226 if (row < selections_.
size() && row >= 0)
233 if (e.position.x < 0 || e.position.x > getWidth())
241 if (selection != selected_ || selection < 0)
244 for (
Listener* listener : listeners_)
245 listener->doubleClickedSelected(
this, selections_.
items[selection].id, selection);
249 if (selection < 0 || selection >= selections_.
size())
252 selected_ = selection;
253 for (
int i = 0; i < selections_.
size(); ++i)
254 selections_.
items[i].selected =
false;
255 selections_.
items[selected_].selected =
true;
257 for (
Listener* listener : listeners_)
258 listener->newSelection(
this, selections_.
items[selection].id, selection);
265 highlight_.
init(open_gl);
266 hover_.
init(open_gl);
270void PopupList::redoImage() {
271 if (getWidth() <= 0 || getHeight() <= 0)
276 int image_width = getWidth() * mult;
280 int image_height = std::max(row_height * selections_.
size(), getHeight());
281 Image rows_image(Image::ARGB, image_width, image_height,
true);
282 Graphics g(rows_image);
283 g.setColour(text_color);
287 int width = (getWidth() - 2 * padding) * mult;
288 for (
int i = 0; i < selections_.
size(); ++i) {
289 if (selections_.
items[i].id < 0) {
290 g.setColour(lighten);
291 int y = row_height * (i + 0.5f);
292 g.drawRect(padding, y, width, 1);
295 g.setColour(text_color);
296 String name = selections_.
items[i].name;
297 g.drawText(name, padding, row_height * i, width, row_height, Justification::centredLeft,
true);
303void PopupList::moveQuadToRow(
OpenGlQuad& quad,
int row) {
305 float view_height = getHeight();
306 float open_gl_row_height = 2.0f * row_height / view_height;
307 float offset = row * open_gl_row_height - 2.0f * getViewPosition() / view_height;
309 float y = 1.0f - offset;
310 quad.
setQuad(0, -1.0f, y - open_gl_row_height, 2.0f, open_gl_row_height);
314 Rectangle<int> view_bounds(getLocalBounds());
319 float width_ratio = image_width / getWidth();
321 float y_offset = 2.0f * getViewPosition() / getHeight();
324 rows_.
setTopRight(2.0f * width_ratio - 1.0f, 1.0f + y_offset);
325 rows_.
setBottomLeft(-1.0f, 1.0f + y_offset - 2.0f * height_ratio);
326 rows_.
setBottomRight(2.0f * width_ratio - 1.0f, 1.0f + y_offset - 2.0f * height_ratio);
330 moveQuadToRow(hover_, hovered_);
337 if (selected_ >= 0 && show_selected_) {
338 moveQuadToRow(highlight_, selected_);
361 view_position_ = std::max(0.0f, view_position_);
362 float scaled_height = getHeight();
364 view_position_ = std::min(view_position_, 1.0f * scrollable_range - scaled_height);
369 view_position_ = range_start;
373 static constexpr float kScrollStepRatio = 0.05f;
375 float scaled_height = getHeight();
377 scroll_bar_->setCurrentRange(getViewPosition(), scaled_height, dontSendNotification);
378 scroll_bar_->setSingleStepSize(scroll_bar_->getHeight() * kScrollStepRatio);
379 scroll_bar_->cancelPendingUpdate();
384 int selections_height = row_height *
static_cast<int>(selections_.
size());
385 return std::max(selections_height, getHeight());
389 num_view_selections_(0), hovered_(-1), x_area_(false), cache_position_(0), is_additional_(),
390 highlight_(
Shaders::kColorFragment), hover_(
Shaders::kColorFragment),
391 remove_additional_x_(
"remove_additional"), view_position_(0.0f) {
392 addAndMakeVisible(browse_area_);
393 addChildComponent(remove_additional_x_);
396 browse_area_.setInterceptsMouseClicks(
false,
false);
400 scroll_bar_ = std::make_unique<OpenGlScrollBar>();
401 addAndMakeVisible(scroll_bar_.get());
403 scroll_bar_->addListener(
this);
413 int scroll_bar_height = getHeight();
414 scroll_bar_->setBounds(getWidth() - scroll_bar_width, 0, scroll_bar_width, scroll_bar_height);
417 browse_area_.setBounds(2, 0, scroll_bar_->getX() - 3, getHeight());
419 remove_additional_x_.setBounds(0, 0, row_height, row_height);
422 loadBrowserCache(cache_position_, cache_position_ +
kNumCachedRows);
425 scroll_bar_->setColor(lighten);
428void SelectionList::sort() {
429 sortFileArray<FileNameAscendingComparator>(selections_);
435 selections_ = std::move(selections);
442 viewPositionChanged();
448 view_position_ = std::max(0.0f, view_position_);
449 float scaled_height = getHeight();
451 view_position_ = std::min(view_position_, 1.0f * scrollable_range - scaled_height);
452 viewPositionChanged();
457 return floorf((mouse_position + getViewPosition()) /
getRowHeight());
462 if (hovered_ >= filtered_selections_.size())
467 x_area_ = x >= 0 && x < row_height;
475 if (result < 0 || result >= filtered_selections_.size())
478 filtered_selections_[result].revealToUser();
482 float click_y_position = e.position.y;
485 if (row >= 0 && hovered_ >= 0) {
487 options.
addItem(hovered_,
"Open File Location");
488 showPopupSelector(
this, e.getPosition(), options, [=](
int selection) { respondToMenuCallback(selection); });
493 float click_y_position = e.position.y;
495 if (row < filtered_selections_.size() && row >= 0)
496 return filtered_selections_[row];
502 float click_x_position = e.position.x;
506 if (selection.getFileName() == String(kAddFolderName))
511 if (click_x_position < star_right)
520 if (e.mods.isPopupMenu())
527 float click_x_position = e.position.x;
530 if (!selection.exists())
533 if (click_x_position < star_right || selection != selected_)
536 for (
Listener* listener : listeners_)
537 listener->doubleClickedSelected(selection);
541 FileChooser open_box(
"Add Folder", File());
542 if (open_box.browseForDirectory()) {
543 File result = open_box.getResult();
544 if (result.exists()) {
545 if (isAcceptableRoot(result)) {
547 for (
const std::string& root : roots) {
548 if (result == File(root)) {
549 NativeMessageBox::showMessageBoxAsync(AlertWindow::WarningIcon,
"Error Adding Folder",
550 String(
"Folder already added"));
554 if (selections_.contains(File(result))) {
555 NativeMessageBox::showMessageBoxAsync(AlertWindow::WarningIcon,
"Error Adding Folder",
556 String(
"Folder already added"));
559 additional_roots_.add(result);
560 roots.push_back(result.getFullPathName().toStdString());
566 showAddRootWarning();
572 additional_roots_.removeFirstMatchingValue(folder);
574 std::string path = folder.getFullPathName().toStdString();
575 const auto& pos = std::find(roots.begin(), roots.end(), path);
576 if (pos != roots.end())
585 if (selection.exists() && selection.isDirectory() && selection == selected_) {
586 toggleOpenFolder(selection);
589 selected_ = selection;
592 for (
Listener* listener : listeners_)
593 listener->favoritesSelected();
596 for (
Listener* listener : listeners_)
597 listener->allSelected();
599 else if (selected_.exists()) {
600 for (
Listener* listener : listeners_)
601 listener->newSelection(selection);
606 if (selection.isDirectory())
609 toggleFavorite(selection);
612void SelectionList::toggleFavorite(
const File& selection) {
618 std::string path = selection.getFullPathName().toStdString();
619 if (favorites_.count(path)) {
620 favorites_.erase(path);
624 favorites_.insert(path);
630void SelectionList::toggleOpenFolder(
const File& selection) {
631 std::string path = selection.getFullPathName().toStdString();
632 Array<File> children;
633 selection.findChildFiles(children, File::findDirectories,
false);
634 if (open_folders_.count(path))
635 open_folders_.erase(path);
636 else if (!children.isEmpty())
643 view_position_ = range_start;
644 viewPositionChanged();
648 static constexpr float kScrollStepRatio = 0.05f;
650 float scaled_height = getHeight();
652 scroll_bar_->setCurrentRange(getViewPosition(), scaled_height, dontSendNotification);
653 scroll_bar_->setSingleStepSize(scroll_bar_->getHeight() * kScrollStepRatio);
654 scroll_bar_->cancelPendingUpdate();
658 if (getWidth() <= 0 || getHeight() <= 0)
661 int max =
static_cast<int>(filtered_selections_.size()) -
kNumCachedRows;
662 int position = std::max(0, std::min<int>(cache_position_, max));
667 std::string parent_string = file.getParentDirectory().getFullPathName().toStdString();
668 if (open_folders_.count(parent_string))
669 return open_folders_[parent_string] + 1;
674 Array<File> children;
675 selection.findChildFiles(children, File::findDirectories,
false);
676 for (
const File& child : children) {
677 selections.push_back(child);
678 if (open_folders_.count(child.getFullPathName().toStdString()))
684 additional_roots_name_ = name;
685 additional_roots_.clear();
688 for (
const std::string& root : roots) {
691 additional_roots_.add(file);
697 filter_string_ = filter_string.toLowerCase();
699 tokens.addTokens(filter_string_,
" ",
"");
700 filtered_selections_.clear();
701 if (favorites_option_) {
706 Array<File> all_selections = selections_;
707 all_selections.addArray(additional_roots_);
709 for (
const File& selection : all_selections) {
712 String name = selection.getFileNameWithoutExtension().toLowerCase();
714 for (
const String& token : tokens) {
715 if (!name.contains(token))
720 filtered_selections_.push_back(selection);
721 if (open_folders_.count(selection.getFullPathName().toStdString()))
726 if (!additional_roots_name_.empty())
727 filtered_selections_.push_back(File::getCurrentWorkingDirectory().getChildFile(
"_").getChildFile(kAddFolderName));
728 num_view_selections_ =
static_cast<int>(filtered_selections_.size());
730 auto found = std::find(filtered_selections_.begin(), filtered_selections_.end(), selected_);
731 if (found == filtered_selections_.end())
736 for (
int i = 0; i < filtered_selections_.size(); ++i) {
737 if (selected_ == filtered_selections_[i])
745 int presets_height = row_height *
static_cast<int>(filtered_selections_.size());
746 return std::max(presets_height, getHeight());
750 if (filtered_selections_.empty())
754 index = (index + 1) % filtered_selections_.size();
755 select(filtered_selections_[index]);
759 if (filtered_selections_.empty())
763 index = (index - 1 + filtered_selections_.size()) % filtered_selections_.size();
764 select(filtered_selections_[index]);
769 row.setScissor(
true);
771 row.setColor(Colours::white);
774 highlight_.
init(open_gl);
775 hover_.
init(open_gl);
776 remove_additional_x_.
init(open_gl);
780void SelectionList::viewPositionChanged() {
783 int last_cache_position = cache_position_;
784 cache_position_ = getViewPosition() / row_height;
785 int max =
static_cast<int>(filtered_selections_.size() -
kNumCachedRows);
786 cache_position_ = std::max(0, std::min<int>(cache_position_, max));
788 if (std::abs(cache_position_ - last_cache_position) >=
kNumCachedRows)
790 else if (last_cache_position < cache_position_)
792 else if (last_cache_position > cache_position_)
793 loadBrowserCache(cache_position_, last_cache_position);
796void SelectionList::loadBrowserCache(
int start_index,
int end_index) {
799 int image_width = getWidth() * mult;
802 int icon_x = padding;
803 int icon_width = row_height;
804 int name_x = icon_x + icon_width + padding;
805 int name_width = image_width - name_x;
807 end_index = std::min(
static_cast<int>(filtered_selections_.size()), end_index);
812 float star_draw_width = row_height * 0.8f;
813 float star_y = (row_height - star_draw_width) / 2.0f;
814 Rectangle<float> star_bounds(icon_x + (icon_width - star_draw_width) / 2.0f, star_y,
815 star_draw_width, star_draw_width);
816 star.applyTransform(star.getTransformToScaleToFit(star_bounds,
true));
818 float folder_draw_width = row_height * 0.6f;
819 float folder_y = (row_height - folder_draw_width) / 2.0f;
820 Rectangle<float> folder_bounds(icon_x + (icon_width - folder_draw_width) / 2.0f, folder_y,
821 folder_draw_width, folder_draw_width);
822 folder.applyTransform(folder.getTransformToScaleToFit(folder_bounds,
true));
823 PathStrokeType icon_stroke(1.0f, PathStrokeType::curved);
826 Colour icon_unselected = text_color.withMultipliedAlpha(0.5f);
829 for (
int i = start_index; i < end_index; ++i) {
830 Image row_image(Image::ARGB, image_width, row_height,
true);
831 Graphics g(row_image);
833 File selection = filtered_selections_[i];
834 String name = selection.getFileNameWithoutExtension();
835 if (selection.isDirectory()) {
837 g.addTransform(AffineTransform::translation(Point<int>(parents * folder_draw_width, 0)));
839 if (name == String(passthrough_name_))
840 name = selection.getParentDirectory().getFileNameWithoutExtension();
842 g.setColour(icon_unselected);
843 if (open_folders_.count(selection.getFullPathName().toStdString()))
846 g.strokePath(folder, icon_stroke);
848 else if (selection.getFileName() == String(kAddFolderName)) {
849 g.setColour(icon_unselected);
850 Path add_folder_path;
852 icon_stroke.createDashedStroke(add_folder_path, folder, dashes, 2);
853 g.fillPath(add_folder_path);
855 else if (selection.exists() || selection.getFileName() ==
"Favorites") {
856 if (favorites_.count(selection.getFullPathName().toStdString())) {
857 g.setColour(icon_selected);
861 g.setColour(icon_unselected);
863 g.strokePath(star, icon_stroke);
866 g.setColour(text_color);
868 g.drawText(name, name_x, 0, name_width - 2 * padding, row_height, Justification::centredLeft,
true);
870 is_additional_[i %
kNumCachedRows] = additional_roots_.contains(selection);
874void SelectionList::moveQuadToRow(
OpenGlQuad& quad,
int row,
float y_offset) {
876 float view_height = getHeight();
877 float open_gl_row_height = 2.0f * row_height / view_height;
878 float offset = row * open_gl_row_height;
880 float y = 1.0f + y_offset - offset;
881 quad.
setQuad(0, -1.0f, y - open_gl_row_height, 2.0f, open_gl_row_height);
885 float view_height = getHeight();
887 int num_presets = num_view_selections_;
889 int view_position = getViewPosition();
890 float y_offset = 2.0f * view_position / view_height;
892 Rectangle<int> view_bounds(getLocalBounds());
897 float width_ratio = image_width / getWidth();
898 float height_ratio = image_height / row_height;
900 float open_gl_row_height = height_ratio * 2.0f * row_height / view_height;
901 int cache_position = std::max(0, std::min(cache_position_, num_presets -
kNumCachedRows));
903 int row = cache_position + i;
905 float offset = (2.0f * row_height * row) / view_height;
906 float y = 1.0f + y_offset - offset;
908 Rectangle<int> row_bounds(0, row_height * row - view_position, getWidth(), row_height);
912 rows_[cache_index].
setTopRight(-1.0f + 2.0f * width_ratio, y);
913 rows_[cache_index].
setBottomLeft(-1.0f, y - open_gl_row_height);
914 rows_[cache_index].
setBottomRight(-1.0f + 2.0f * width_ratio, y - open_gl_row_height);
919 if (selected_index >= 0) {
920 moveQuadToRow(highlight_, selected_index, y_offset);
926 moveQuadToRow(hover_, hovered_, y_offset);
933 Rectangle<int> bounds(getWidth() - row_height - scroll_bar_width, row_height * hovered_ - view_position_,
934 row_height, row_height);
949 row.destroy(open_gl);
953 remove_additional_x_.
destroy(open_gl);
958 body_(
Shaders::kRoundedRectangleFragment),
959 border_(
Shaders::kRoundedRectangleBorderFragment) {
965 popup_list_ = std::make_unique<PopupList>();
966 popup_list_->addListener(
this);
968 popup_list_->setAlwaysOnTop(
true);
969 popup_list_->setWantsKeyboardFocus(
false);
977 Rectangle<int> bounds = getLocalBounds();
979 popup_list_->setBounds(1, rounding, getWidth() - 2, getHeight() - 2 * rounding);
981 body_.setBounds(bounds);
985 border_.setBounds(bounds);
993 int width = popup_list_->getBrowseWidth();
994 int height = popup_list_->getBrowseHeight() + 2 * rounding;
997 if (x + width > bounds.getRight())
999 if (y + height > bounds.getBottom())
1000 y = bounds.getBottom() - height;
1001 setBounds(x, y, width, height);
1005 body_(
Shaders::kRoundedRectangleFragment),
1006 border_(
Shaders::kRoundedRectangleBorderFragment),
1007 divider_(
Shaders::kColorFragment) {
1008 callback_ =
nullptr;
1014 left_list_ = std::make_unique<PopupList>();
1015 left_list_->addListener(
this);
1017 left_list_->setAlwaysOnTop(
true);
1018 left_list_->setWantsKeyboardFocus(
false);
1019 left_list_->showSelected(
true);
1021 right_list_ = std::make_unique<PopupList>();
1022 right_list_->addListener(
this);
1024 right_list_->setAlwaysOnTop(
true);
1025 right_list_->setWantsKeyboardFocus(
false);
1026 right_list_->showSelected(
true);
1034 Rectangle<int> bounds = getLocalBounds();
1036 int height = getHeight() - 2 * rounding;
1037 left_list_->setBounds(1, rounding, getWidth() / 2 - 2, height);
1038 int right_x = left_list_->getRight() + 1;
1039 right_list_->setBounds(right_x, rounding, getWidth() - right_x - 1, height);
1041 body_.setBounds(bounds);
1045 border_.setBounds(bounds);
1049 divider_.setBounds(getWidth() / 2 - 1, 1, 1, getHeight() - 2);
1058 int height = left_list_->getBrowseHeight() + 2 * rounding;
1061 if (x + width > bounds.getRight())
1063 if (y + height > bounds.getBottom())
1064 y = bounds.getBottom() - height;
1065 setBounds(x, y, width, height);
1069 if (list == left_list_.get()) {
1070 PopupItems right_items = left_list_->getSelectionItems(index);
1071 if (right_items.
size() == 0) {
1073 right_list_->setSelections(right_items);
1077 int right_selection = right_list_->getSelected();
1078 if (right_selection < 0 || right_selection >= right_items.
size() ||
1079 right_list_->getSelectionItems(right_selection).name != right_items.
items[right_selection].name) {
1080 right_selection = 0;
1083 right_list_->setSelections(right_items);
1084 right_list_->select(right_selection);
1091 body_(
Shaders::kRoundedRectangleFragment),
1092 border_(
Shaders::kRoundedRectangleBorderFragment),
1093 horizontal_divider_(
Shaders::kColorFragment),
1094 vertical_divider_(
Shaders::kColorFragment),
1096 addKeyListener(
this);
1097 setInterceptsMouseClicks(
false,
true);
1104 folder_list_ = std::make_unique<SelectionList>();
1105 folder_list_->addFavoritesOption();
1106 folder_list_->addListener(
this);
1108 folder_list_->setAlwaysOnTop(
true);
1110 selection_list_ = std::make_unique<SelectionList>();
1111 selection_list_->addListener(
this);
1113 selection_list_->setAlwaysOnTop(
true);
1115 for (
int i = 0; i < 4; ++i) {
1116 addAndMakeVisible(closing_areas_[i]);
1120 exit_button_ = std::make_unique<OpenGlShapeButton>(
"Exit");
1121 addAndMakeVisible(exit_button_.get());
1123 exit_button_->addListener(
this);
1126 store_button_ = std::make_unique<OpenGlToggleButton>(
"Store");
1127 store_button_->setUiButton(
true);
1129 store_button_->setVisible(
false);
1131 download_button_ = std::make_unique<OpenGlToggleButton>(
"Login");
1132 download_button_->setUiButton(
true);
1133 download_button_->setText(
"Download content");
1135 download_button_->setVisible(
false);
1137#if !defined(NO_TEXT_ENTRY)
1138 search_box_ = std::make_unique<OpenGlTextEditor>(
"Search");
1139 search_box_->addListener(
this);
1140 search_box_->setSelectAllWhenFocused(
true);
1141 search_box_->setMultiLine(
false,
false);
1142 search_box_->setJustification(Justification::centredLeft);
1143 addAndMakeVisible(search_box_.get());
1147 setWantsKeyboardFocus(
true);
1148 setMouseClickGrabsKeyboardFocus(
true);
1155 static constexpr float kBrowseWidthRatio = 0.5f;
1156 static constexpr float kTopHeight = 38.0f;
1160 closing_areas_[0].setBounds(0, 0, passthrough_bounds_.getX(), getHeight());
1161 closing_areas_[1].setBounds(passthrough_bounds_.getRight(), 0,
1162 getWidth() - passthrough_bounds_.getRight(), getHeight());
1163 closing_areas_[2].setBounds(0, 0, getWidth(), passthrough_bounds_.getY());
1164 closing_areas_[3].setBounds(0, passthrough_bounds_.getBottom(),
1165 getWidth(), getHeight() - passthrough_bounds_.getBottom());
1167 body_.setBounds(browser_bounds_);
1171 border_.setBounds(browser_bounds_);
1177 horizontal_divider_.
setColor(border);
1178 vertical_divider_.
setColor(border);
1181 empty_color = empty_color.withAlpha(0.5f * empty_color.getFloatAlpha());
1184 search_box_->setTextToShowWhenEmpty(TRANS(
"Search"), empty_color);
1186 search_box_->setColour(TextEditor::textColourId, findColour(
Skin::kBodyText,
true));
1187 search_box_->setColour(TextEditor::highlightedTextColourId, findColour(
Skin::kBodyText,
true));
1191 int selection_list_width = browser_bounds_.getWidth() * kBrowseWidthRatio;
1193 int folder_list_width = browser_bounds_.getWidth() - selection_list_width;
1194 int list_height = browser_bounds_.getHeight() - top_height - 2;
1195 int x = browser_bounds_.getX();
1196 int y = browser_bounds_.getY();
1198 folder_list_->setBounds(x, y + top_height + 1, folder_list_width - 1, list_height);
1199 selection_list_->setBounds(x + folder_list_width, y + top_height + 1, selection_list_width - 3, list_height);
1200 horizontal_divider_.setBounds(x + 1, y + top_height - 1, browser_bounds_.getWidth() - 2, 1);
1201 vertical_divider_.setBounds(x + folder_list_width, y + top_height, 1, list_height);
1204 int text_height = top_height - 2 * padding;
1205 download_button_->setBounds(x + padding, y + padding, selection_list_width - 2 * padding, text_height);
1207 search_box_->setBounds(download_button_->getBounds());
1208 search_box_->resized();
1211 int store_x = x + padding + selection_list_width;
1212 store_button_->setBounds(store_x, y + padding, browser_bounds_.getRight() - store_x - top_height, text_height);
1213 exit_button_->setBounds(x + browser_bounds_.getWidth() - top_height, y, top_height, top_height);
1215 Image image(Image::ARGB, 1, 1,
false);
1223 SynthSection::visibilityChanged();
1225 search_box_->setText(
"");
1227 File selected = folder_list_->selected();
1228 if (selected.exists())
1233 if (selection.exists() && selection.isDirectory()) {
1235 selection.findChildFiles(files, File::findFiles,
true, extensions_);
1236 selection_list_->setSelections(files);
1237 selection_list_->resetScrollPosition();
1249 Array<File> folders = folder_list_->getSelections();
1250 folders.addArray(folder_list_->getAdditionalFolders());
1251 for (
const File& folder : folders) {
1252 if (folder.exists() && folder.isDirectory())
1253 folder.findChildFiles(files, File::findFiles,
true, extensions_);
1256 selection_list_->setSelections(files);
1257 selection_list_->resetScrollPosition();
1262 Array<File> folders = folder_list_->getSelections();
1263 folders.addArray(folder_list_->getAdditionalFolders());
1264 for (
const File& folder : folders) {
1265 if (folder.exists() && folder.isDirectory())
1266 folder.findChildFiles(files, File::findFiles,
true, extensions_);
1268 Array<File> favorites;
1270 for (
const File& file : files) {
1271 if (favorite_lookup.count(file.getFullPathName().toStdString()))
1272 favorites.add(file);
1274 selection_list_->setSelections(favorites);
1275 selection_list_->resetScrollPosition();
1279 if (selection.exists() && !selection.isDirectory())
1285 return search_box_->hasKeyboardFocus(
true);
1287 if (key.getKeyCode() == KeyPress::escapeKey) {
1291 if (key.getKeyCode() == KeyPress::upKey || key.getKeyCode() == KeyPress::leftKey) {
1292 selection_list_->selectPrev();
1295 if (key.getKeyCode() == KeyPress::downKey || key.getKeyCode() == KeyPress::rightKey) {
1296 selection_list_->selectNext();
1299 return search_box_->hasKeyboardFocus(
true);
1304 return search_box_->hasKeyboardFocus(
true);
1309 if (!browser_bounds_.contains(e.getPosition() + closing_area->getPosition()))
1316 search_box_->setVisible(has_content);
1317 download_button_->setVisible(!has_content);
1323 String type = folder_list_->getPassthroughFolderName();
1324 store_button_->setText(
"Get more " + type.toLowerCase().toStdString() +
" by " + author);
1325 String cleaned = String(author).removeCharacters(
" _.").toLowerCase();
1326 store_button_->setVisible(more_author_presets_.count(cleaned.toStdString()));
1331 const std::string& passthrough_name,
const std::string& additional_folders_name) {
1332 extensions_ = extensions;
1334 search_box_->setText(
"");
1336 Array<File> folders;
1337 for (
const File& directory : directories)
1338 folders.add(directory);
1340 folder_list_->setPassthroughFolderName(passthrough_name);
1341 folder_list_->setAdditionalRootsName(additional_folders_name);
1342 folder_list_->setSelections(folders);
1344 if (!additional_folders_name.empty()) {
1346 for (
const std::string& path : additional)
1347 directories.emplace_back(File(path));
1350 Array<File> presets;
1351 selection_list_->setSelected(File());
1352 folder_list_->filter(
"");
1353 if (!folder_list_->selected().exists()) {
1355 selection_list_->setSelections(presets);
1357 selection_list_->filter(
"");
1361 more_author_presets_.clear();
1364 json available_packs = available[
"packs"];
1365 for (
auto& pack : available_packs) {
1366 if (pack.count(folder_list_->getPassthroughFolderName()) == 0)
1369 bool contains_files = pack[folder_list_->getPassthroughFolderName()];
1370 if (!contains_files)
1373 bool purchased =
false;
1374 if (pack.count(
"Purchased"))
1375 purchased = pack[
"Purchased"];
1379 std::string author_data = pack[
"Author"];
1380 StringArray authors;
1381 authors.addTokens(author_data,
",",
"");
1382 for (
const String& author : authors)
1383 more_author_presets_.insert(author.removeCharacters(
" ._").toLowerCase().toStdString());
1386 catch (
const json::exception& e) {
1393 selection_list_->filter(search_box_->getText());
1394 selection_list_->redoCache();
1406 if (clicked_button == exit_button_.get())
1408 else if (clicked_button == download_button_.get()) {
1409 FullInterface* parent = findParentComponentOfClass<FullInterface>();
1415 else if (clicked_button == store_button_.get() && owner_) {
1416 String encoded_author = URL::addEscapeChars(owner_->
getFileAuthor(),
true);
1417 encoded_author = encoded_author.replace(
"+",
"%2B");
1419 URL url(String(kStoreUrl) + encoded_author);
1420 url.launchInDefaultBrowser();
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
The main GUI container for the entire synthesizer interface.
Definition full_interface.h:61
void startDownload()
Starts a download of additional content if needed.
Definition full_interface.cpp:573
static void saveAdditionalFolders(const std::string &name, std::vector< std::string > folders)
Saves additional folder paths for presets, wavetables, or samples.
Definition load_save.cpp:1695
static void getAllFilesOfTypeInDirectories(Array< File > &files, const String &extensions, const std::vector< File > &directories)
Scans a set of directories for files matching certain extensions.
Definition load_save.cpp:1826
static std::vector< std::string > getAdditionalFolders(const std::string &name)
Retrieves a list of additional folder paths for a given category.
Definition load_save.cpp:1705
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 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 bool hasDataDirectory()
Checks if a data directory is properly configured (exists and has packs.json).
Definition load_save.cpp:1417
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
virtual void init(OpenGlWrapper &open_gl) override
Initializes any OpenGL resources for rendering this component.
Definition open_gl_image_component.cpp:57
virtual void destroy(OpenGlWrapper &open_gl) override
Destroys OpenGL-related resources used by this component.
Definition open_gl_image_component.cpp:69
virtual void redrawImage(bool force)
Redraws the image if necessary, creating or updating the internal Image.
Definition open_gl_image_component.cpp:16
void setColor(Colour color)
Sets a color tint for the image.
Definition open_gl_image_component.h:101
OpenGlImage & image()
Provides access to the underlying OpenGlImage.
Definition open_gl_image_component.h:107
A utility class for rendering a single image using OpenGL.
Definition open_gl_image.h:16
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
int getImageHeight()
Gets the height of the currently set image.
Definition open_gl_image.h:138
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 destroy(OpenGlWrapper &open_gl)
Releases any OpenGL resources allocated by this object.
Definition open_gl_image.cpp:128
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
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
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 setRounding(float rounding)
Sets the rounding radius of the quads.
Definition open_gl_multi_quad.h:347
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
static Path folder()
Creates a folder icon path.
Definition paths.h:133
static Path exitX()
Definition paths.h:416
static Path thickX()
Definition paths.h:431
void setShape(Path shape)
Sets the shape to be drawn.
Definition open_gl_image_component.h:441
@ kLight
Definition open_gl_image_component.h:309
void setText(String text)
Sets the displayed text and redraws the image.
Definition open_gl_image_component.h:336
void setTextSize(float size)
Sets the size of the text in points.
Definition open_gl_image_component.h:372
void setJustification(Justification justification)
Sets the text justification (e.g., centered, left, right).
Definition open_gl_image_component.h:389
void setFontType(FontType font_type)
Sets the font type (Title, Light, Regular, Mono).
Definition open_gl_image_component.h:381
Interface for receiving selection events from SelectionList.
Definition popup_browser.h:238
int getFolderDepth(const File &file)
Gets the depth of a given folder relative to open folders.
Definition popup_browser.cpp:666
int getRowFromPosition(float mouse_position)
Definition popup_browser.cpp:456
void mouseExit(const MouseEvent &e) override
Definition popup_browser.cpp:470
void scrollBarMoved(ScrollBar *scroll_bar, double range_start) override
Definition popup_browser.cpp:642
static File getAllFile()
Returns a File object representing "All" selection.
Definition popup_browser.h:275
void selectPrev()
Selects the previous item in the list.
Definition popup_browser.cpp:758
void resetScrollPosition()
Definition popup_browser.cpp:440
static constexpr float kScrollBarWidth
Scrollbar width.
Definition popup_browser.h:269
void setAdditionalRootsName(const std::string &name)
Sets the name associated with additional roots.
Definition popup_browser.cpp:683
void setScrollBarRange()
Definition popup_browser.cpp:647
void initOpenGlComponents(OpenGlWrapper &open_gl) override
Initializes all OpenGL components in this section and sub-sections.
Definition popup_browser.cpp:767
void addAdditionalFolder()
Definition popup_browser.cpp:540
static constexpr float kScrollSensitivity
Scroll sensitivity.
Definition popup_browser.h:268
void selectIcon(const File &selection)
Handles selecting the icon area (favorite toggle).
Definition popup_browser.cpp:605
File getSelection(const MouseEvent &e)
Gets the File at the mouse event position.
Definition popup_browser.cpp:492
void addSubfolderSelections(const File &selection, std::vector< File > &selections)
Adds subfolder selections if a folder is open.
Definition popup_browser.cpp:673
void mouseMove(const MouseEvent &e) override
Definition popup_browser.cpp:460
void removeAdditionalFolder(const File &folder)
Definition popup_browser.cpp:571
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Definition popup_browser.cpp:446
SelectionList()
Constructs a SelectionList.
Definition popup_browser.cpp:388
void filter(const String &filter_string)
Filters the selection list by a given string.
Definition popup_browser.cpp:696
void leftClick(const MouseEvent &e)
Definition popup_browser.cpp:501
void setSelections(Array< File > presets)
Sets the files/folders displayed in this SelectionList.
Definition popup_browser.cpp:434
void mouseDoubleClick(const MouseEvent &e) override
Definition popup_browser.cpp:526
void destroyOpenGlComponents(OpenGlWrapper &open_gl) override
Destroys all OpenGL components in this section and sub-sections.
Definition popup_browser.cpp:947
int getScrollableRange()
Gets the total scrollable range.
Definition popup_browser.cpp:743
static File getFavoritesFile()
Returns a File object representing "Favorites" selection.
Definition popup_browser.h:281
int getSelectedIndex()
Gets the index of the currently selected file.
Definition popup_browser.cpp:735
void resized() override
Called when the component is resized. Arranges layout of child components.
Definition popup_browser.cpp:411
void redoCache()
Refreshes the cached row images.
Definition popup_browser.cpp:657
void mouseDown(const MouseEvent &e) override
Definition popup_browser.cpp:519
int getIconPadding()
Gets the icon padding.
Definition popup_browser.h:330
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Renders all OpenGL components in this section and sub-sections.
Definition popup_browser.cpp:884
void respondToMenuCallback(int result)
Definition popup_browser.cpp:474
void menuClick(const MouseEvent &e)
Definition popup_browser.cpp:481
void selectNext()
Selects the next item in the list.
Definition popup_browser.cpp:749
void select(const File &selection)
Selects a given file.
Definition popup_browser.cpp:584
static constexpr int kNumCachedRows
Number of rows cached for performance.
Definition popup_browser.h:265
int getRowHeight()
Returns the scaled row height.
Definition popup_browser.h:324
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kBodyRounding
Definition skin.h:71
@ kIconButtonOff
Definition skin.h:185
@ kBorder
Definition skin.h:134
@ kWidgetPrimary1
Definition skin.h:165
@ kIconButtonOffHover
Definition skin.h:186
@ 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
@ kPopupBrowser
Definition skin.h:58
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
float getPadding()
Definition synth_section.cpp:660
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
void paintOpenGlChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all OpenGL child components.
Definition synth_section.cpp:267
virtual File getCurrentFile()
Gets the currently loaded file. Overridden by subclasses.
Definition synth_section.h:376
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
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
virtual std::string getFileAuthor()
Gets the author metadata of the currently loaded file. Overridden by subclasses.
Definition synth_section.h:388
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 loadFile(const File &file)
Loads a file (e.g., a sample or wavetable). Overridden by subclasses.
Definition synth_section.h:370
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
float getSizeRatio() const
Definition synth_section.h:765
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
nlohmann::json json
Definition line_generator.h:7
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
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174