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.

422 lines
13KB

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