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.

379 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. //==============================================================================
  18. String hexString8Digits (int value);
  19. String createAlphaNumericUID();
  20. String createGUID (const String& seed); // Turns a seed into a windows GUID
  21. String escapeSpaces (const String& text); // replaces spaces with blackslash-space
  22. String addQuotesIfContainsSpaces (const String& text);
  23. StringPairArray parsePreprocessorDefs (const String& defs);
  24. StringPairArray mergePreprocessorDefs (StringPairArray inheritedDefs, const StringPairArray& overridingDefs);
  25. String createGCCPreprocessorFlags (const StringPairArray& defs);
  26. String replacePreprocessorDefs (const StringPairArray& definitions, String sourceString);
  27. StringArray getSearchPathsFromString (const String& searchPath);
  28. void setValueIfVoid (Value value, const var& defaultValue);
  29. void addPlistDictionaryKey (XmlElement* xml, const String& key, const String& value);
  30. void addPlistDictionaryKeyBool (XmlElement* xml, const String& key, bool value);
  31. void addPlistDictionaryKeyInt (XmlElement* xml, const String& key, int value);
  32. //==============================================================================
  33. int indexOfLineStartingWith (const StringArray& lines, const String& text, int startIndex);
  34. void autoScrollForMouseEvent (const MouseEvent& e, bool scrollX = true, bool scrollY = true);
  35. void showUTF8ToolWindow (ScopedPointer<Component>& ownerPointer);
  36. bool cancelAnyModalComponents();
  37. bool reinvokeCommandAfterCancellingModalComps (const ApplicationCommandTarget::InvocationInfo&);
  38. //==============================================================================
  39. class RolloverHelpComp : public Component,
  40. private Timer
  41. {
  42. public:
  43. RolloverHelpComp();
  44. void paint (Graphics&) override;
  45. void timerCallback() override;
  46. private:
  47. Component* lastComp;
  48. String lastTip;
  49. static String findTip (Component*);
  50. };
  51. //==============================================================================
  52. class PropertyListBuilder
  53. {
  54. public:
  55. PropertyListBuilder() {}
  56. void add (PropertyComponent* propertyComp)
  57. {
  58. components.add (propertyComp);
  59. }
  60. void add (PropertyComponent* propertyComp, const String& tooltip)
  61. {
  62. propertyComp->setTooltip (tooltip);
  63. add (propertyComp);
  64. }
  65. void addSearchPathProperty (const Value& value, const String& name, const String& mainHelpText)
  66. {
  67. add (new TextPropertyComponent (value, name, 16384, true),
  68. mainHelpText + " Use semi-colons or new-lines to separate multiple paths.");
  69. }
  70. void setPreferredHeight (int height)
  71. {
  72. for (int j = components.size(); --j >= 0;)
  73. components.getUnchecked(j)->setPreferredHeight (height);
  74. }
  75. Array <PropertyComponent*> components;
  76. private:
  77. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyListBuilder)
  78. };
  79. //==============================================================================
  80. // A ValueSource which takes an input source, and forwards any changes in it.
  81. // This class is a handy way to create sources which re-map a value.
  82. class ValueSourceFilter : public Value::ValueSource,
  83. public Value::Listener
  84. {
  85. public:
  86. ValueSourceFilter (const Value& source) : sourceValue (source)
  87. {
  88. sourceValue.addListener (this);
  89. }
  90. void valueChanged (Value&) { sendChangeMessage (true); }
  91. protected:
  92. Value sourceValue;
  93. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSourceFilter)
  94. };
  95. //==============================================================================
  96. class FloatingToolWindow : public DialogWindow
  97. {
  98. public:
  99. FloatingToolWindow (const String& title,
  100. const String& windowPosPropertyName,
  101. Component* content,
  102. ScopedPointer<Component>& ownerPointer,
  103. int defaultW, int defaultH,
  104. int minW, int minH,
  105. int maxW, int maxH)
  106. : DialogWindow (title, Colours::darkgrey, true, true),
  107. windowPosProperty (windowPosPropertyName),
  108. owner (ownerPointer)
  109. {
  110. setUsingNativeTitleBar (true);
  111. setResizable (true, true);
  112. setResizeLimits (minW, minH, maxW, maxH);
  113. setContentOwned (content, false);
  114. const String windowState (getGlobalProperties().getValue (windowPosProperty));
  115. if (windowState.isNotEmpty())
  116. restoreWindowStateFromString (windowState);
  117. else
  118. centreAroundComponent (Component::getCurrentlyFocusedComponent(), defaultW, defaultH);
  119. setVisible (true);
  120. owner = this;
  121. }
  122. ~FloatingToolWindow()
  123. {
  124. getGlobalProperties().setValue (windowPosProperty, getWindowStateAsString());
  125. }
  126. void closeButtonPressed()
  127. {
  128. owner = nullptr;
  129. }
  130. private:
  131. String windowPosProperty;
  132. ScopedPointer<Component>& owner;
  133. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FloatingToolWindow)
  134. };
  135. //==============================================================================
  136. class PopupColourSelector : public Component,
  137. public ChangeListener,
  138. public Value::Listener,
  139. public ButtonListener
  140. {
  141. public:
  142. PopupColourSelector (const Value& colour,
  143. Colour defaultCol,
  144. const bool canResetToDefault)
  145. : defaultButton ("Reset to Default"),
  146. colourValue (colour),
  147. defaultColour (defaultCol)
  148. {
  149. addAndMakeVisible (&selector);
  150. selector.setName ("Colour");
  151. selector.setCurrentColour (getColour());
  152. selector.addChangeListener (this);
  153. if (canResetToDefault)
  154. {
  155. addAndMakeVisible (&defaultButton);
  156. defaultButton.addListener (this);
  157. }
  158. colourValue.addListener (this);
  159. setSize (300, 400);
  160. }
  161. void resized()
  162. {
  163. if (defaultButton.isVisible())
  164. {
  165. selector.setBounds (0, 0, getWidth(), getHeight() - 30);
  166. defaultButton.changeWidthToFitText (22);
  167. defaultButton.setTopLeftPosition (10, getHeight() - 26);
  168. }
  169. else
  170. {
  171. selector.setBounds (getLocalBounds());
  172. }
  173. }
  174. Colour getColour() const
  175. {
  176. if (colourValue.toString().isEmpty())
  177. return defaultColour;
  178. return Colour::fromString (colourValue.toString());
  179. }
  180. void setColour (Colour newColour)
  181. {
  182. if (getColour() != newColour)
  183. {
  184. if (newColour == defaultColour && defaultButton.isVisible())
  185. colourValue = var::null;
  186. else
  187. colourValue = newColour.toDisplayString (true);
  188. }
  189. }
  190. void buttonClicked (Button*)
  191. {
  192. setColour (defaultColour);
  193. selector.setCurrentColour (defaultColour);
  194. }
  195. void changeListenerCallback (ChangeBroadcaster*)
  196. {
  197. if (selector.getCurrentColour() != getColour())
  198. setColour (selector.getCurrentColour());
  199. }
  200. void valueChanged (Value&)
  201. {
  202. selector.setCurrentColour (getColour());
  203. }
  204. private:
  205. StoredSettings::ColourSelectorWithSwatches selector;
  206. TextButton defaultButton;
  207. Value colourValue;
  208. Colour defaultColour;
  209. };
  210. //==============================================================================
  211. /**
  212. A component that shows a colour swatch with hex ARGB value, and which pops up
  213. a colour selector when you click it.
  214. */
  215. class ColourEditorComponent : public Component,
  216. public Value::Listener
  217. {
  218. public:
  219. ColourEditorComponent (UndoManager* um, const Value& colour,
  220. Colour defaultCol, const bool canReset)
  221. : undoManager (um), colourValue (colour), defaultColour (defaultCol),
  222. canResetToDefault (canReset)
  223. {
  224. colourValue.addListener (this);
  225. }
  226. void paint (Graphics& g)
  227. {
  228. const Colour colour (getColour());
  229. g.fillAll (Colours::grey);
  230. g.fillCheckerBoard (getLocalBounds().reduced (2),
  231. 10, 10,
  232. Colour (0xffdddddd).overlaidWith (colour),
  233. Colour (0xffffffff).overlaidWith (colour));
  234. g.setColour (Colours::white.overlaidWith (colour).contrasting());
  235. g.setFont (Font (getHeight() * 0.6f, Font::bold));
  236. g.drawFittedText (colour.toDisplayString (true), getLocalBounds().reduced (2, 1),
  237. Justification::centred, 1);
  238. }
  239. Colour getColour() const
  240. {
  241. if (colourValue.toString().isEmpty())
  242. return defaultColour;
  243. return Colour::fromString (colourValue.toString());
  244. }
  245. void setColour (Colour newColour)
  246. {
  247. if (getColour() != newColour)
  248. {
  249. if (newColour == defaultColour && canResetToDefault)
  250. colourValue = var::null;
  251. else
  252. colourValue = newColour.toDisplayString (true);
  253. }
  254. }
  255. void resetToDefault()
  256. {
  257. setColour (defaultColour);
  258. }
  259. void refresh()
  260. {
  261. const Colour col (getColour());
  262. if (col != lastColour)
  263. {
  264. lastColour = col;
  265. repaint();
  266. }
  267. }
  268. void mouseDown (const MouseEvent&)
  269. {
  270. if (undoManager != nullptr)
  271. undoManager->beginNewTransaction();
  272. CallOutBox::launchAsynchronously (new PopupColourSelector (colourValue,
  273. defaultColour,
  274. canResetToDefault),
  275. getScreenBounds(), nullptr);
  276. }
  277. void valueChanged (Value&)
  278. {
  279. refresh();
  280. }
  281. private:
  282. UndoManager* undoManager;
  283. Value colourValue;
  284. Colour lastColour;
  285. const Colour defaultColour;
  286. const bool canResetToDefault;
  287. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourEditorComponent)
  288. };
  289. //==============================================================================
  290. class ColourPropertyComponent : public PropertyComponent
  291. {
  292. public:
  293. ColourPropertyComponent (UndoManager* undoManager, const String& name, const Value& colour,
  294. Colour defaultColour, bool canResetToDefault)
  295. : PropertyComponent (name),
  296. colourEditor (undoManager, colour, defaultColour, canResetToDefault)
  297. {
  298. addAndMakeVisible (&colourEditor);
  299. }
  300. void resized()
  301. {
  302. colourEditor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
  303. }
  304. void refresh() {}
  305. protected:
  306. ColourEditorComponent colourEditor;
  307. };