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.

336 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #pragma once
  14. //==============================================================================
  15. class FileGroupInformationComponent : public Component,
  16. private ListBoxModel,
  17. private ValueTree::Listener
  18. {
  19. public:
  20. FileGroupInformationComponent (const Project::Item& group)
  21. : item (group),
  22. header (item.getName(), { getIcons().openFolder, Colours::transparentBlack })
  23. {
  24. list.setHeaderComponent (std::make_unique<ListBoxHeader> (Array<String> { "File", "Binary Resource", "Xcode Resource", "Compile", "Compiler Flag Scheme" },
  25. Array<float> { 0.3f, 0.15f, 0.15f, 0.15f, 0.25f }));
  26. list.setModel (this);
  27. list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
  28. addAndMakeVisible (list);
  29. list.updateContent();
  30. list.setRowHeight (30);
  31. item.state.addListener (this);
  32. lookAndFeelChanged();
  33. addAndMakeVisible (header);
  34. }
  35. ~FileGroupInformationComponent() override
  36. {
  37. item.state.removeListener (this);
  38. }
  39. //==============================================================================
  40. void paint (Graphics& g) override
  41. {
  42. g.setColour (findColour (secondaryBackgroundColourId));
  43. g.fillRect (getLocalBounds().reduced (12, 0));
  44. }
  45. void resized() override
  46. {
  47. auto bounds = getLocalBounds().reduced (12, 0);
  48. header.setBounds (bounds.removeFromTop (40));
  49. list.setBounds (bounds.reduced (10, 4));
  50. }
  51. void parentSizeChanged() override
  52. {
  53. setSize (jmax (550, getParentWidth()), getParentHeight());
  54. }
  55. int getNumRows() override
  56. {
  57. return item.getNumChildren();
  58. }
  59. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool /*rowIsSelected*/) override
  60. {
  61. g.setColour (findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
  62. : secondaryWidgetBackgroundColourId));
  63. g.fillRect (0, 0, width, height - 1);
  64. }
  65. Component* refreshComponentForRow (int rowNumber, bool /*isRowSelected*/, Component* existingComponentToUpdate) override
  66. {
  67. std::unique_ptr<Component> existing (existingComponentToUpdate);
  68. if (rowNumber < getNumRows())
  69. {
  70. auto child = item.getChild (rowNumber);
  71. if (existingComponentToUpdate == nullptr
  72. || dynamic_cast<FileOptionComponent*> (existing.get())->item != child)
  73. {
  74. existing.reset();
  75. existing.reset (new FileOptionComponent (child, dynamic_cast<ListBoxHeader*> (list.getHeaderComponent())));
  76. }
  77. }
  78. return existing.release();
  79. }
  80. String getGroupPath() const { return item.getFile().getFullPathName(); }
  81. //==============================================================================
  82. void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
  83. void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
  84. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
  85. void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
  86. void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
  87. private:
  88. Project::Item item;
  89. ListBox list;
  90. ContentViewHeader header;
  91. void itemChanged()
  92. {
  93. list.updateContent();
  94. repaint();
  95. }
  96. //==============================================================================
  97. class FileOptionComponent : public Component
  98. {
  99. public:
  100. FileOptionComponent (const Project::Item& fileItem, ListBoxHeader* listBoxHeader)
  101. : item (fileItem),
  102. header (listBoxHeader),
  103. compilerFlagSchemeSelector (item)
  104. {
  105. if (item.isFile())
  106. {
  107. addAndMakeVisible (compileButton);
  108. compileButton.getToggleStateValue().referTo (item.getShouldCompileValue());
  109. compileButton.onStateChange = [this] { compilerFlagSchemeSelector.setVisible (compileButton.getToggleState()); };
  110. addAndMakeVisible (binaryResourceButton);
  111. binaryResourceButton.getToggleStateValue().referTo (item.getShouldAddToBinaryResourcesValue());
  112. addAndMakeVisible (xcodeResourceButton);
  113. xcodeResourceButton.getToggleStateValue().referTo (item.getShouldAddToXcodeResourcesValue());
  114. addChildComponent (compilerFlagSchemeSelector);
  115. compilerFlagSchemeSelector.setVisible (compileButton.getToggleState());
  116. }
  117. }
  118. void paint (Graphics& g) override
  119. {
  120. if (header != nullptr)
  121. {
  122. auto textBounds = getLocalBounds().removeFromLeft (roundToInt (header->getProportionAtIndex (0) * getWidth()));
  123. auto iconBounds = textBounds.removeFromLeft (25);
  124. if (item.isImageFile())
  125. iconBounds.reduce (5, 5);
  126. item.getIcon().withColour (findColour (treeIconColourId)).draw (g, iconBounds.toFloat(), item.isIconCrossedOut());
  127. g.setColour (findColour (widgetTextColourId));
  128. g.drawText (item.getName(), textBounds, Justification::centredLeft);
  129. }
  130. }
  131. void resized() override
  132. {
  133. if (header != nullptr)
  134. {
  135. auto bounds = getLocalBounds();
  136. auto width = getWidth();
  137. bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (0) * width));
  138. binaryResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (1) * width)));
  139. xcodeResourceButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (2) * width)));
  140. compileButton.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (3) * width)));
  141. compilerFlagSchemeSelector.setBounds (bounds.removeFromLeft (roundToInt (header->getProportionAtIndex (4) * width)));
  142. }
  143. }
  144. Project::Item item;
  145. private:
  146. //==============================================================================
  147. class CompilerFlagSchemeSelector : public Component,
  148. private Value::Listener
  149. {
  150. public:
  151. CompilerFlagSchemeSelector (Project::Item& it)
  152. : item (it)
  153. {
  154. schemeBox.setTextWhenNothingSelected ("None");
  155. updateCompilerFlagSchemeComboBox();
  156. schemeBox.onChange = [this] { handleComboBoxSelection(); };
  157. addAndMakeVisible (schemeBox);
  158. addChildComponent (newSchemeLabel);
  159. newSchemeLabel.setEditable (true);
  160. newSchemeLabel.setJustificationType (Justification::centredLeft);
  161. newSchemeLabel.onEditorHide = [this]
  162. {
  163. newSchemeLabel.setVisible (false);
  164. schemeBox.setVisible (true);
  165. auto newScheme = newSchemeLabel.getText();
  166. item.project.addCompilerFlagScheme (newScheme);
  167. if (item.getCompilerFlagSchemeString().isEmpty())
  168. item.setCompilerFlagScheme (newScheme);
  169. updateCompilerFlagSchemeComboBox();
  170. };
  171. selectScheme (item.getCompilerFlagSchemeString());
  172. projectCompilerFlagSchemesValue = item.project.getProjectValue (Ids::compilerFlagSchemes);
  173. projectCompilerFlagSchemesValue.addListener (this);
  174. lookAndFeelChanged();
  175. }
  176. void resized() override
  177. {
  178. auto b = getLocalBounds();
  179. schemeBox.setBounds (b);
  180. newSchemeLabel.setBounds (b);
  181. }
  182. private:
  183. void valueChanged (Value&) override { updateCompilerFlagSchemeComboBox(); }
  184. void lookAndFeelChanged() override
  185. {
  186. schemeBox.setColour (ComboBox::outlineColourId, Colours::transparentBlack);
  187. schemeBox.setColour (ComboBox::textColourId, findColour (defaultTextColourId));
  188. }
  189. void updateCompilerFlagSchemeComboBox()
  190. {
  191. auto itemScheme = item.getCompilerFlagSchemeString();
  192. auto allSchemes = item.project.getCompilerFlagSchemes();
  193. if (itemScheme.isNotEmpty() && ! allSchemes.contains (itemScheme))
  194. {
  195. item.clearCurrentCompilerFlagScheme();
  196. itemScheme = {};
  197. }
  198. schemeBox.clear();
  199. schemeBox.addItemList (allSchemes, 1);
  200. schemeBox.addSeparator();
  201. schemeBox.addItem ("Add a new scheme...", -1);
  202. schemeBox.addItem ("Delete selected scheme", -2);
  203. schemeBox.addItem ("Clear", -3);
  204. selectScheme (itemScheme);
  205. }
  206. void handleComboBoxSelection()
  207. {
  208. auto selectedID = schemeBox.getSelectedId();
  209. if (selectedID > 0)
  210. {
  211. item.setCompilerFlagScheme (schemeBox.getItemText (selectedID - 1));
  212. }
  213. else if (selectedID == -1)
  214. {
  215. newSchemeLabel.setText ("NewScheme", dontSendNotification);
  216. schemeBox.setVisible (false);
  217. newSchemeLabel.setVisible (true);
  218. newSchemeLabel.showEditor();
  219. if (auto* ed = newSchemeLabel.getCurrentTextEditor())
  220. ed->setInputRestrictions (64, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_");
  221. }
  222. else if (selectedID == -2)
  223. {
  224. auto currentScheme = item.getCompilerFlagSchemeString();
  225. if (currentScheme.isNotEmpty())
  226. {
  227. item.project.removeCompilerFlagScheme (currentScheme);
  228. item.clearCurrentCompilerFlagScheme();
  229. }
  230. updateCompilerFlagSchemeComboBox();
  231. }
  232. else if (selectedID == -3)
  233. {
  234. schemeBox.setSelectedId (0);
  235. item.clearCurrentCompilerFlagScheme();
  236. }
  237. }
  238. void selectScheme (const String& schemeToSelect)
  239. {
  240. if (schemeToSelect.isNotEmpty())
  241. {
  242. for (int i = 0; i < schemeBox.getNumItems(); ++i)
  243. {
  244. if (schemeBox.getItemText (i) == schemeToSelect)
  245. {
  246. schemeBox.setSelectedItemIndex (i);
  247. return;
  248. }
  249. }
  250. }
  251. schemeBox.setSelectedId (0);
  252. }
  253. Project::Item& item;
  254. Value projectCompilerFlagSchemesValue;
  255. ComboBox schemeBox;
  256. Label newSchemeLabel;
  257. };
  258. //==============================================================================
  259. ListBoxHeader* header;
  260. ToggleButton compileButton, binaryResourceButton, xcodeResourceButton;
  261. CompilerFlagSchemeSelector compilerFlagSchemeSelector;
  262. };
  263. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileGroupInformationComponent)
  264. };