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.

414 lines
13KB

  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. struct Icon
  40. {
  41. Icon() : path (nullptr) {}
  42. Icon (const Path& p, const Colour& c) : path (&p), colour (c) {}
  43. Icon (const Path* p, const Colour& c) : path (p), colour (c) {}
  44. void draw (Graphics& g, const Rectangle<float>& area, bool isCrossedOut) const
  45. {
  46. if (path != nullptr)
  47. {
  48. g.setColour (colour);
  49. const RectanglePlacement placement (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize);
  50. g.fillPath (*path, placement.getTransformToFit (path->getBounds(), area));
  51. if (isCrossedOut)
  52. {
  53. g.setColour (Colours::red.withAlpha (0.8f));
  54. g.drawLine ((float) area.getX(), area.getY() + area.getHeight() * 0.2f,
  55. (float) area.getRight(), area.getY() + area.getHeight() * 0.8f, 3.0f);
  56. }
  57. }
  58. }
  59. Icon withContrastingColourTo (const Colour& background) const
  60. {
  61. return Icon (path, background.contrasting (colour, 0.6f));
  62. }
  63. const Path* path;
  64. Colour colour;
  65. };
  66. //==============================================================================
  67. class RolloverHelpComp : public Component,
  68. private Timer
  69. {
  70. public:
  71. RolloverHelpComp();
  72. void paint (Graphics&) override;
  73. void timerCallback() override;
  74. private:
  75. Component* lastComp;
  76. String lastTip;
  77. static String findTip (Component*);
  78. };
  79. //==============================================================================
  80. class PropertyListBuilder
  81. {
  82. public:
  83. PropertyListBuilder() {}
  84. void add (PropertyComponent* propertyComp)
  85. {
  86. components.add (propertyComp);
  87. }
  88. void add (PropertyComponent* propertyComp, const String& tooltip)
  89. {
  90. propertyComp->setTooltip (tooltip);
  91. add (propertyComp);
  92. }
  93. void addSearchPathProperty (const Value& value, const String& name, const String& mainHelpText)
  94. {
  95. add (new TextPropertyComponent (value, name, 16384, true),
  96. mainHelpText + " Use semi-colons or new-lines to separate multiple paths.");
  97. }
  98. void setPreferredHeight (int height)
  99. {
  100. for (int j = components.size(); --j >= 0;)
  101. components.getUnchecked(j)->setPreferredHeight (height);
  102. }
  103. Array <PropertyComponent*> components;
  104. private:
  105. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyListBuilder)
  106. };
  107. //==============================================================================
  108. // A ValueSource which takes an input source, and forwards any changes in it.
  109. // This class is a handy way to create sources which re-map a value.
  110. class ValueSourceFilter : public Value::ValueSource,
  111. public Value::Listener
  112. {
  113. public:
  114. ValueSourceFilter (const Value& source) : sourceValue (source)
  115. {
  116. sourceValue.addListener (this);
  117. }
  118. void valueChanged (Value&) { sendChangeMessage (true); }
  119. protected:
  120. Value sourceValue;
  121. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSourceFilter)
  122. };
  123. //==============================================================================
  124. class FloatingToolWindow : public DialogWindow
  125. {
  126. public:
  127. FloatingToolWindow (const String& title,
  128. const String& windowPosPropertyName,
  129. Component* content,
  130. ScopedPointer<Component>& ownerPointer,
  131. int defaultW, int defaultH,
  132. int minW, int minH,
  133. int maxW, int maxH)
  134. : DialogWindow (title, Colours::darkgrey, true, true),
  135. windowPosProperty (windowPosPropertyName),
  136. owner (ownerPointer)
  137. {
  138. setUsingNativeTitleBar (true);
  139. setResizable (true, true);
  140. setResizeLimits (minW, minH, maxW, maxH);
  141. setContentOwned (content, false);
  142. const String windowState (getGlobalProperties().getValue (windowPosProperty));
  143. if (windowState.isNotEmpty())
  144. restoreWindowStateFromString (windowState);
  145. else
  146. centreAroundComponent (Component::getCurrentlyFocusedComponent(), defaultW, defaultH);
  147. setVisible (true);
  148. owner = this;
  149. }
  150. ~FloatingToolWindow()
  151. {
  152. getGlobalProperties().setValue (windowPosProperty, getWindowStateAsString());
  153. }
  154. void closeButtonPressed()
  155. {
  156. owner = nullptr;
  157. }
  158. private:
  159. String windowPosProperty;
  160. ScopedPointer<Component>& owner;
  161. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FloatingToolWindow)
  162. };
  163. //==============================================================================
  164. class PopupColourSelector : public Component,
  165. public ChangeListener,
  166. public Value::Listener,
  167. public ButtonListener
  168. {
  169. public:
  170. PopupColourSelector (const Value& colour,
  171. const Colour& defaultCol,
  172. const bool canResetToDefault)
  173. : defaultButton ("Reset to Default"),
  174. colourValue (colour),
  175. defaultColour (defaultCol)
  176. {
  177. addAndMakeVisible (&selector);
  178. selector.setName ("Colour");
  179. selector.setCurrentColour (getColour());
  180. selector.addChangeListener (this);
  181. if (canResetToDefault)
  182. {
  183. addAndMakeVisible (&defaultButton);
  184. defaultButton.addListener (this);
  185. }
  186. colourValue.addListener (this);
  187. setSize (300, 400);
  188. }
  189. void resized()
  190. {
  191. if (defaultButton.isVisible())
  192. {
  193. selector.setBounds (0, 0, getWidth(), getHeight() - 30);
  194. defaultButton.changeWidthToFitText (22);
  195. defaultButton.setTopLeftPosition (10, getHeight() - 26);
  196. }
  197. else
  198. {
  199. selector.setBounds (getLocalBounds());
  200. }
  201. }
  202. Colour getColour() const
  203. {
  204. if (colourValue.toString().isEmpty())
  205. return defaultColour;
  206. return Colour::fromString (colourValue.toString());
  207. }
  208. void setColour (const Colour& newColour)
  209. {
  210. if (getColour() != newColour)
  211. {
  212. if (newColour == defaultColour && defaultButton.isVisible())
  213. colourValue = var::null;
  214. else
  215. colourValue = newColour.toDisplayString (true);
  216. }
  217. }
  218. void buttonClicked (Button*)
  219. {
  220. setColour (defaultColour);
  221. selector.setCurrentColour (defaultColour);
  222. }
  223. void changeListenerCallback (ChangeBroadcaster*)
  224. {
  225. if (selector.getCurrentColour() != getColour())
  226. setColour (selector.getCurrentColour());
  227. }
  228. void valueChanged (Value&)
  229. {
  230. selector.setCurrentColour (getColour());
  231. }
  232. private:
  233. StoredSettings::ColourSelectorWithSwatches selector;
  234. TextButton defaultButton;
  235. Value colourValue;
  236. Colour defaultColour;
  237. };
  238. //==============================================================================
  239. /**
  240. A component that shows a colour swatch with hex ARGB value, and which pops up
  241. a colour selector when you click it.
  242. */
  243. class ColourEditorComponent : public Component,
  244. public Value::Listener
  245. {
  246. public:
  247. ColourEditorComponent (UndoManager* um, const Value& colour,
  248. const Colour& defaultCol, const bool canReset)
  249. : undoManager (um), colourValue (colour), defaultColour (defaultCol),
  250. canResetToDefault (canReset)
  251. {
  252. colourValue.addListener (this);
  253. }
  254. void paint (Graphics& g)
  255. {
  256. const Colour colour (getColour());
  257. g.fillAll (Colours::grey);
  258. g.fillCheckerBoard (getLocalBounds().reduced (2),
  259. 10, 10,
  260. Colour (0xffdddddd).overlaidWith (colour),
  261. Colour (0xffffffff).overlaidWith (colour));
  262. g.setColour (Colours::white.overlaidWith (colour).contrasting());
  263. g.setFont (Font (getHeight() * 0.6f, Font::bold));
  264. g.drawFittedText (colour.toDisplayString (true), getLocalBounds().reduced (2, 1),
  265. Justification::centred, 1);
  266. }
  267. Colour getColour() const
  268. {
  269. if (colourValue.toString().isEmpty())
  270. return defaultColour;
  271. return Colour::fromString (colourValue.toString());
  272. }
  273. void setColour (const Colour& newColour)
  274. {
  275. if (getColour() != newColour)
  276. {
  277. if (newColour == defaultColour && canResetToDefault)
  278. colourValue = var::null;
  279. else
  280. colourValue = newColour.toDisplayString (true);
  281. }
  282. }
  283. void resetToDefault()
  284. {
  285. setColour (defaultColour);
  286. }
  287. void refresh()
  288. {
  289. const Colour col (getColour());
  290. if (col != lastColour)
  291. {
  292. lastColour = col;
  293. repaint();
  294. }
  295. }
  296. void mouseDown (const MouseEvent&)
  297. {
  298. if (undoManager != nullptr)
  299. undoManager->beginNewTransaction();
  300. CallOutBox::launchAsynchronously (new PopupColourSelector (colourValue,
  301. defaultColour,
  302. canResetToDefault),
  303. getScreenBounds(), nullptr);
  304. }
  305. void valueChanged (Value&)
  306. {
  307. refresh();
  308. }
  309. private:
  310. UndoManager* undoManager;
  311. Value colourValue;
  312. Colour lastColour;
  313. const Colour defaultColour;
  314. const bool canResetToDefault;
  315. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourEditorComponent)
  316. };
  317. //==============================================================================
  318. class ColourPropertyComponent : public PropertyComponent
  319. {
  320. public:
  321. ColourPropertyComponent (UndoManager* undoManager, const String& name, const Value& colour,
  322. const Colour& defaultColour, bool canResetToDefault)
  323. : PropertyComponent (name),
  324. colourEditor (undoManager, colour, defaultColour, canResetToDefault)
  325. {
  326. addAndMakeVisible (&colourEditor);
  327. }
  328. void resized()
  329. {
  330. colourEditor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
  331. }
  332. void refresh() {}
  333. protected:
  334. ColourEditorComponent colourEditor;
  335. };