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.

281 lines
8.9KB

  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. #include "../../Application/jucer_Headers.h"
  19. #include "jucer_ResourceEditorPanel.h"
  20. //==============================================================================
  21. class ResourceListButton : public Component
  22. {
  23. public:
  24. explicit ResourceListButton (JucerDocument& doc)
  25. : document (doc), reloadButton ("Reload"), row (0)
  26. {
  27. setInterceptsMouseClicks (false, true);
  28. addAndMakeVisible (reloadButton);
  29. reloadButton.onClick = [this]
  30. {
  31. if (auto* r = document.getResources() [row])
  32. document.getResources().browseForResource ("Select a file to replace this resource", "*",
  33. File (r->originalFilename), r->name, nullptr);
  34. };
  35. }
  36. void update (int newRow)
  37. {
  38. row = newRow;
  39. reloadButton.setVisible (document.getResources() [row] != nullptr);
  40. }
  41. void resized()
  42. {
  43. reloadButton.setBoundsInset (BorderSize<int> (2));
  44. }
  45. private:
  46. JucerDocument& document;
  47. TextButton reloadButton;
  48. int row;
  49. };
  50. //==============================================================================
  51. ResourceEditorPanel::ResourceEditorPanel (JucerDocument& doc)
  52. : document (doc),
  53. addButton ("Add new resource..."),
  54. reloadAllButton ("Reload all resources"),
  55. delButton ("Delete selected resources")
  56. {
  57. addAndMakeVisible (addButton);
  58. addButton.onClick = [this]
  59. {
  60. document.getResources().browseForResource ("Select a file to add as a resource", "*", {}, {}, nullptr);
  61. };
  62. addAndMakeVisible (reloadAllButton);
  63. reloadAllButton.onClick = [this] { reloadAll(); };
  64. addAndMakeVisible (delButton);
  65. delButton.setEnabled (false);
  66. delButton.onClick = [this] { document.getResources().remove (listBox->getSelectedRow (0)); };
  67. listBox.reset (new TableListBox (String(), this));
  68. addAndMakeVisible (listBox.get());
  69. listBox->getHeader().addColumn ("name", 1, 150, 80, 400);
  70. listBox->getHeader().addColumn ("original file", 2, 350, 80, 800);
  71. listBox->getHeader().addColumn ("size", 3, 100, 40, 150);
  72. listBox->getHeader().addColumn ("reload", 4, 100, 100, 100, TableHeaderComponent::notResizableOrSortable);
  73. listBox->getHeader().setStretchToFitActive (true);
  74. listBox->setOutlineThickness (1);
  75. listBox->updateContent();
  76. document.addChangeListener (this);
  77. handleCommandMessage (1);
  78. updateLookAndFeel();
  79. }
  80. ResourceEditorPanel::~ResourceEditorPanel()
  81. {
  82. document.removeChangeListener (this);
  83. }
  84. int ResourceEditorPanel::getNumRows()
  85. {
  86. return document.getResources().size();
  87. }
  88. void ResourceEditorPanel::paintRowBackground (Graphics& g, int /*rowNumber*/,
  89. int /*width*/, int /*height*/, bool rowIsSelected)
  90. {
  91. if (rowIsSelected)
  92. g.fillAll (findColour (defaultHighlightColourId));
  93. }
  94. void ResourceEditorPanel::paintCell (Graphics& g, int rowNumber, int columnId, int width, int height,
  95. bool rowIsSelected)
  96. {
  97. if (const BinaryResources::BinaryResource* const r = document.getResources() [rowNumber])
  98. {
  99. String text;
  100. if (columnId == 1)
  101. text = r->name;
  102. else if (columnId == 2)
  103. text = r->originalFilename;
  104. else if (columnId == 3)
  105. text = File::descriptionOfSizeInBytes ((int64) r->data.getSize());
  106. if (rowIsSelected)
  107. g.setColour (findColour (defaultHighlightedTextColourId));
  108. else
  109. g.setColour (findColour (defaultTextColourId));
  110. g.setFont (13.0f);
  111. g.drawText (text, 4, 0, width - 6, height, Justification::centredLeft, true);
  112. }
  113. }
  114. Component* ResourceEditorPanel::refreshComponentForCell (int rowNumber, int columnId, bool /*isRowSelected*/,
  115. Component* existingComponentToUpdate)
  116. {
  117. if (columnId != 4)
  118. return nullptr;
  119. if (existingComponentToUpdate == nullptr)
  120. existingComponentToUpdate = new ResourceListButton (document);
  121. ((ResourceListButton*) existingComponentToUpdate)->update (rowNumber);
  122. return existingComponentToUpdate;
  123. }
  124. int ResourceEditorPanel::getColumnAutoSizeWidth (int columnId)
  125. {
  126. if (columnId == 4)
  127. return 0;
  128. Font f (13.0f);
  129. int widest = 40;
  130. for (int i = document.getResources().size(); --i >= 0;)
  131. {
  132. const BinaryResources::BinaryResource* const r = document.getResources() [i];
  133. jassert (r != nullptr);
  134. String text;
  135. if (columnId == 1)
  136. text = r->name;
  137. else if (columnId == 2)
  138. text = r->originalFilename;
  139. else if (columnId == 3)
  140. text = File::descriptionOfSizeInBytes ((int64) r->data.getSize());
  141. widest = jmax (widest, f.getStringWidth (text));
  142. }
  143. return widest + 10;
  144. }
  145. void ResourceEditorPanel::updateLookAndFeel()
  146. {
  147. listBox->setColour (ListBox::backgroundColourId, findColour (secondaryBackgroundColourId));
  148. listBox->setColour (ListBox::outlineColourId, Colours::transparentBlack);
  149. }
  150. void ResourceEditorPanel::lookAndFeelChanged()
  151. {
  152. updateLookAndFeel();
  153. }
  154. //==============================================================================
  155. class ResourceSorter
  156. {
  157. public:
  158. ResourceSorter (const int columnId_, const bool forwards)
  159. : columnId (columnId_),
  160. direction (forwards ? 1 : -1)
  161. {
  162. }
  163. int compareElements (BinaryResources::BinaryResource* first, BinaryResources::BinaryResource* second)
  164. {
  165. if (columnId == 1) return direction * first->name.compare (second->name);
  166. if (columnId == 2) return direction * first->originalFilename.compare (second->originalFilename);
  167. if (columnId == 3) return direction * (int) first->data.getSize() - (int) second->data.getSize();
  168. return 0;
  169. }
  170. private:
  171. const int columnId, direction;
  172. ResourceSorter (const ResourceSorter&);
  173. ResourceSorter& operator= (const ResourceSorter&);
  174. };
  175. void ResourceEditorPanel::sortOrderChanged (int newSortColumnId, const bool isForwards)
  176. {
  177. ResourceSorter sorter (newSortColumnId, isForwards);
  178. document.getResources().sort (sorter);
  179. }
  180. //==============================================================================
  181. void ResourceEditorPanel::selectedRowsChanged (int /*lastRowSelected*/)
  182. {
  183. delButton.setEnabled (listBox->getNumSelectedRows() > 0);
  184. }
  185. void ResourceEditorPanel::resized()
  186. {
  187. auto bounds = getLocalBounds();
  188. auto buttonSlice = bounds.removeFromBottom (40).reduced (5, 5);
  189. addButton.setBounds (buttonSlice.removeFromLeft (125));
  190. buttonSlice.removeFromLeft (10);
  191. reloadAllButton.setBounds (buttonSlice.removeFromLeft (125));
  192. delButton.setBounds (buttonSlice.removeFromRight (125));
  193. listBox->setBounds (bounds);
  194. }
  195. void ResourceEditorPanel::paint (Graphics& g)
  196. {
  197. g.fillAll (findColour (secondaryBackgroundColourId));
  198. }
  199. void ResourceEditorPanel::visibilityChanged()
  200. {
  201. if (isVisible())
  202. listBox->updateContent();
  203. }
  204. void ResourceEditorPanel::changeListenerCallback (ChangeBroadcaster*)
  205. {
  206. if (isVisible())
  207. listBox->updateContent();
  208. }
  209. void ResourceEditorPanel::reloadAll()
  210. {
  211. StringArray failed;
  212. for (int i = 0; i < document.getResources().size(); ++i)
  213. if (! document.getResources().reload (i))
  214. failed.add (document.getResources().getResourceNames() [i]);
  215. if (failed.size() > 0)
  216. {
  217. auto options = MessageBoxOptions::makeOptionsOk (MessageBoxIconType::WarningIcon,
  218. TRANS ("Reloading resources"),
  219. TRANS ("The following resources couldn't be reloaded from their original files:\n\n")
  220. + failed.joinIntoString (", "));
  221. messageBox = AlertWindow::showScopedAsync (options, nullptr);
  222. }
  223. }