The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. FileSearchPathListComponent::FileSearchPathListComponent()
  21. : addButton ("+"),
  22. removeButton ("-"),
  23. changeButton (TRANS ("change...")),
  24. upButton ({}, DrawableButton::ImageOnButtonBackground),
  25. downButton ({}, DrawableButton::ImageOnButtonBackground)
  26. {
  27. listBox.setModel (this);
  28. addAndMakeVisible (listBox);
  29. listBox.setColour (ListBox::backgroundColourId, Colours::black.withAlpha (0.02f));
  30. listBox.setColour (ListBox::outlineColourId, Colours::black.withAlpha (0.1f));
  31. listBox.setOutlineThickness (1);
  32. addAndMakeVisible (addButton);
  33. addButton.onClick = [this] { addPath(); };
  34. addButton.setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight | Button::ConnectedOnBottom | Button::ConnectedOnTop);
  35. addAndMakeVisible (removeButton);
  36. removeButton.onClick = [this] { deleteSelected(); };
  37. removeButton.setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight | Button::ConnectedOnBottom | Button::ConnectedOnTop);
  38. addAndMakeVisible (changeButton);
  39. changeButton.onClick = [this] { editSelected(); };
  40. addAndMakeVisible (upButton);
  41. upButton.onClick = [this] { moveSelection (-1); };
  42. auto arrowColour = findColour (ListBox::textColourId);
  43. {
  44. Path arrowPath;
  45. arrowPath.addArrow ({ 50.0f, 100.0f, 50.0f, 0.0f }, 40.0f, 100.0f, 50.0f);
  46. DrawablePath arrowImage;
  47. arrowImage.setFill (arrowColour);
  48. arrowImage.setPath (arrowPath);
  49. upButton.setImages (&arrowImage);
  50. }
  51. addAndMakeVisible (downButton);
  52. downButton.onClick = [this] { moveSelection (1); };
  53. {
  54. Path arrowPath;
  55. arrowPath.addArrow ({ 50.0f, 0.0f, 50.0f, 100.0f }, 40.0f, 100.0f, 50.0f);
  56. DrawablePath arrowImage;
  57. arrowImage.setFill (arrowColour);
  58. arrowImage.setPath (arrowPath);
  59. downButton.setImages (&arrowImage);
  60. }
  61. updateButtons();
  62. }
  63. void FileSearchPathListComponent::updateButtons()
  64. {
  65. const bool anythingSelected = listBox.getNumSelectedRows() > 0;
  66. removeButton.setEnabled (anythingSelected);
  67. changeButton.setEnabled (anythingSelected);
  68. upButton.setEnabled (anythingSelected);
  69. downButton.setEnabled (anythingSelected);
  70. }
  71. void FileSearchPathListComponent::changed()
  72. {
  73. listBox.updateContent();
  74. listBox.repaint();
  75. updateButtons();
  76. }
  77. //==============================================================================
  78. void FileSearchPathListComponent::setPath (const FileSearchPath& newPath)
  79. {
  80. if (newPath.toString() != path.toString())
  81. {
  82. path = newPath;
  83. changed();
  84. }
  85. }
  86. void FileSearchPathListComponent::setDefaultBrowseTarget (const File& newDefaultDirectory)
  87. {
  88. defaultBrowseTarget = newDefaultDirectory;
  89. }
  90. //==============================================================================
  91. int FileSearchPathListComponent::getNumRows()
  92. {
  93. return path.getNumPaths();
  94. }
  95. void FileSearchPathListComponent::paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected)
  96. {
  97. if (rowIsSelected)
  98. g.fillAll (findColour (TextEditor::highlightColourId));
  99. g.setColour (findColour (ListBox::textColourId));
  100. Font f ((float) height * 0.7f);
  101. f.setHorizontalScale (0.9f);
  102. g.setFont (f);
  103. g.drawText (path.getRawString (rowNumber),
  104. 4, 0, width - 6, height,
  105. Justification::centredLeft, true);
  106. }
  107. void FileSearchPathListComponent::deleteKeyPressed (int row)
  108. {
  109. if (isPositiveAndBelow (row, path.getNumPaths()))
  110. {
  111. path.remove (row);
  112. changed();
  113. }
  114. }
  115. void FileSearchPathListComponent::returnKeyPressed (int row)
  116. {
  117. chooser = std::make_unique<FileChooser> (TRANS ("Change folder..."), path.getRawString (row), "*");
  118. auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
  119. chooser->launchAsync (chooserFlags, [this, row] (const FileChooser& fc)
  120. {
  121. if (fc.getResult() == File{})
  122. return;
  123. path.remove (row);
  124. path.add (fc.getResult(), row);
  125. changed();
  126. });
  127. }
  128. void FileSearchPathListComponent::listBoxItemDoubleClicked (int row, const MouseEvent&)
  129. {
  130. returnKeyPressed (row);
  131. }
  132. void FileSearchPathListComponent::selectedRowsChanged (int)
  133. {
  134. updateButtons();
  135. }
  136. void FileSearchPathListComponent::paint (Graphics& g)
  137. {
  138. g.fillAll (findColour (backgroundColourId));
  139. }
  140. void FileSearchPathListComponent::resized()
  141. {
  142. const int buttonH = 22;
  143. const int buttonY = getHeight() - buttonH - 4;
  144. listBox.setBounds (2, 2, getWidth() - 4, buttonY - 5);
  145. addButton.setBounds (2, buttonY, buttonH, buttonH);
  146. removeButton.setBounds (addButton.getRight(), buttonY, buttonH, buttonH);
  147. changeButton.changeWidthToFitText (buttonH);
  148. downButton.setSize (buttonH * 2, buttonH);
  149. upButton.setSize (buttonH * 2, buttonH);
  150. downButton.setTopRightPosition (getWidth() - 2, buttonY);
  151. upButton.setTopRightPosition (downButton.getX() - 4, buttonY);
  152. changeButton.setTopRightPosition (upButton.getX() - 8, buttonY);
  153. }
  154. bool FileSearchPathListComponent::isInterestedInFileDrag (const StringArray&)
  155. {
  156. return true;
  157. }
  158. void FileSearchPathListComponent::filesDropped (const StringArray& filenames, int, int mouseY)
  159. {
  160. for (int i = filenames.size(); --i >= 0;)
  161. {
  162. const File f (filenames[i]);
  163. if (f.isDirectory())
  164. {
  165. auto row = listBox.getRowContainingPosition (0, mouseY - listBox.getY());
  166. path.add (f, row);
  167. changed();
  168. }
  169. }
  170. }
  171. void FileSearchPathListComponent::addPath()
  172. {
  173. auto start = defaultBrowseTarget;
  174. if (start == File())
  175. start = path[0];
  176. if (start == File())
  177. start = File::getCurrentWorkingDirectory();
  178. chooser = std::make_unique<FileChooser> (TRANS ("Add a folder..."), start, "*");
  179. auto chooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
  180. chooser->launchAsync (chooserFlags, [this] (const FileChooser& fc)
  181. {
  182. if (fc.getResult() == File{})
  183. return;
  184. path.add (fc.getResult(), listBox.getSelectedRow());
  185. changed();
  186. });
  187. }
  188. void FileSearchPathListComponent::deleteSelected()
  189. {
  190. deleteKeyPressed (listBox.getSelectedRow());
  191. changed();
  192. }
  193. void FileSearchPathListComponent::editSelected()
  194. {
  195. returnKeyPressed (listBox.getSelectedRow());
  196. changed();
  197. }
  198. void FileSearchPathListComponent::moveSelection (int delta)
  199. {
  200. jassert (delta == -1 || delta == 1);
  201. auto currentRow = listBox.getSelectedRow();
  202. if (isPositiveAndBelow (currentRow, path.getNumPaths()))
  203. {
  204. auto newRow = jlimit (0, path.getNumPaths() - 1, currentRow + delta);
  205. if (currentRow != newRow)
  206. {
  207. const auto f = File::createFileWithoutCheckingPath (path.getRawString (currentRow));
  208. path.remove (currentRow);
  209. path.add (f, newRow);
  210. listBox.selectRow (newRow);
  211. changed();
  212. }
  213. }
  214. }
  215. } // namespace juce