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.

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