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.

372 lines
12KB

  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 drawRecessedShadows (Graphics& g, int w, int h, int shadowSize);
  35. void showUTF8ToolWindow();
  36. // Start a callout modally, which will delete the content comp when it's dismissed.
  37. void launchAsyncCallOutBox (Component& attachTo, Component* content);
  38. bool cancelAnyModalComponents();
  39. bool reinvokeCommandAfterCancellingModalComps (const ApplicationCommandTarget::InvocationInfo&);
  40. //==============================================================================
  41. struct Icon
  42. {
  43. Icon() : path (nullptr) {}
  44. Icon (const Path& p, const Colour& c) : path (&p), colour (c) {}
  45. void draw (Graphics& g, const Rectangle<float>& area) const
  46. {
  47. if (path != nullptr)
  48. {
  49. g.setColour (colour);
  50. const RectanglePlacement placement (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize);
  51. g.fillPath (*path, placement.getTransformToFit (path->getBounds(), area));
  52. }
  53. }
  54. const Path* path;
  55. Colour colour;
  56. };
  57. //==============================================================================
  58. class RolloverHelpComp : public Component,
  59. private Timer
  60. {
  61. public:
  62. RolloverHelpComp();
  63. void paint (Graphics& g);
  64. void timerCallback();
  65. private:
  66. Component* lastComp;
  67. String lastTip;
  68. static String findTip (Component*);
  69. };
  70. //==============================================================================
  71. class PropertyListBuilder
  72. {
  73. public:
  74. PropertyListBuilder() {}
  75. void add (PropertyComponent* propertyComp)
  76. {
  77. components.add (propertyComp);
  78. }
  79. void add (PropertyComponent* propertyComp, const String& tooltip)
  80. {
  81. propertyComp->setTooltip (tooltip);
  82. add (propertyComp);
  83. }
  84. void addSearchPathProperty (const Value& value, const String& name, const String& mainHelpText)
  85. {
  86. add (new TextPropertyComponent (value, name, 16384, true),
  87. mainHelpText + " Use semi-colons or new-lines to separate multiple paths.");
  88. }
  89. void setPreferredHeight (int height)
  90. {
  91. for (int j = components.size(); --j >= 0;)
  92. components.getUnchecked(j)->setPreferredHeight (height);
  93. }
  94. Array <PropertyComponent*> components;
  95. private:
  96. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyListBuilder);
  97. };
  98. //==============================================================================
  99. class FloatingLabelComponent : public Component
  100. {
  101. public:
  102. FloatingLabelComponent();
  103. void remove();
  104. void update (Component* parent, const String& text, const Colour& textColour,
  105. int x, int y, bool toRight, bool below);
  106. void paint (Graphics& g);
  107. private:
  108. Font font;
  109. Colour colour;
  110. GlyphArrangement glyphs;
  111. };
  112. //==============================================================================
  113. // A ValueSource which takes an input source, and forwards any changes in it.
  114. // This class is a handy way to create sources which re-map a value.
  115. class ValueSourceFilter : public Value::ValueSource,
  116. public Value::Listener
  117. {
  118. public:
  119. ValueSourceFilter (const Value& source) : sourceValue (source)
  120. {
  121. sourceValue.addListener (this);
  122. }
  123. void valueChanged (Value&) { sendChangeMessage (true); }
  124. protected:
  125. Value sourceValue;
  126. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSourceFilter);
  127. };
  128. //==============================================================================
  129. class PopupColourSelector : public Component,
  130. public ChangeListener,
  131. public Value::Listener,
  132. public ButtonListener
  133. {
  134. public:
  135. PopupColourSelector (const Value& colourValue_,
  136. const Colour& defaultColour_,
  137. const bool canResetToDefault)
  138. : defaultButton ("Reset to Default"),
  139. colourValue (colourValue_),
  140. defaultColour (defaultColour_)
  141. {
  142. addAndMakeVisible (&selector);
  143. selector.setName ("Colour");
  144. selector.setCurrentColour (getColour());
  145. selector.addChangeListener (this);
  146. if (canResetToDefault)
  147. {
  148. addAndMakeVisible (&defaultButton);
  149. defaultButton.addListener (this);
  150. }
  151. colourValue.addListener (this);
  152. setSize (300, 400);
  153. }
  154. void resized()
  155. {
  156. if (defaultButton.isVisible())
  157. {
  158. selector.setBounds (0, 0, getWidth(), getHeight() - 30);
  159. defaultButton.changeWidthToFitText (22);
  160. defaultButton.setTopLeftPosition (10, getHeight() - 26);
  161. }
  162. else
  163. {
  164. selector.setBounds (0, 0, getWidth(), getHeight());
  165. }
  166. }
  167. Colour getColour() const
  168. {
  169. if (colourValue.toString().isEmpty())
  170. return defaultColour;
  171. return Colour::fromString (colourValue.toString());
  172. }
  173. void setColour (const Colour& newColour)
  174. {
  175. if (getColour() != newColour)
  176. {
  177. if (newColour == defaultColour && defaultButton.isVisible())
  178. colourValue = var::null;
  179. else
  180. colourValue = newColour.toDisplayString (true);
  181. }
  182. }
  183. void buttonClicked (Button*)
  184. {
  185. setColour (defaultColour);
  186. selector.setCurrentColour (defaultColour);
  187. }
  188. void changeListenerCallback (ChangeBroadcaster*)
  189. {
  190. if (selector.getCurrentColour() != getColour())
  191. setColour (selector.getCurrentColour());
  192. }
  193. void valueChanged (Value&)
  194. {
  195. selector.setCurrentColour (getColour());
  196. }
  197. private:
  198. StoredSettings::ColourSelectorWithSwatches selector;
  199. TextButton defaultButton;
  200. Value colourValue;
  201. Colour defaultColour;
  202. };
  203. //==============================================================================
  204. /**
  205. A component that shows a colour swatch with hex ARGB value, and which pops up
  206. a colour selector when you click it.
  207. */
  208. class ColourEditorComponent : public Component,
  209. public Value::Listener
  210. {
  211. public:
  212. ColourEditorComponent (UndoManager* undoManager_, const Value& colourValue_,
  213. const Colour& defaultColour_, const bool canResetToDefault_)
  214. : undoManager (undoManager_), colourValue (colourValue_), defaultColour (defaultColour_),
  215. canResetToDefault (canResetToDefault_)
  216. {
  217. colourValue.addListener (this);
  218. }
  219. void paint (Graphics& g)
  220. {
  221. const Colour colour (getColour());
  222. g.fillAll (Colours::grey);
  223. g.fillCheckerBoard (getLocalBounds().reduced (2, 2),
  224. 10, 10,
  225. Colour (0xffdddddd).overlaidWith (colour),
  226. Colour (0xffffffff).overlaidWith (colour));
  227. g.setColour (Colours::white.overlaidWith (colour).contrasting());
  228. g.setFont (Font (getHeight() * 0.6f, Font::bold));
  229. g.drawFittedText (colour.toDisplayString (true),
  230. 2, 1, getWidth() - 4, getHeight() - 1,
  231. Justification::centred, 1);
  232. }
  233. Colour getColour() const
  234. {
  235. if (colourValue.toString().isEmpty())
  236. return defaultColour;
  237. return Colour::fromString (colourValue.toString());
  238. }
  239. void setColour (const Colour& newColour)
  240. {
  241. if (getColour() != newColour)
  242. {
  243. if (newColour == defaultColour && canResetToDefault)
  244. colourValue = var::null;
  245. else
  246. colourValue = newColour.toDisplayString (true);
  247. }
  248. }
  249. void resetToDefault()
  250. {
  251. setColour (defaultColour);
  252. }
  253. void refresh()
  254. {
  255. const Colour col (getColour());
  256. if (col != lastColour)
  257. {
  258. lastColour = col;
  259. repaint();
  260. }
  261. }
  262. void mouseDown (const MouseEvent&)
  263. {
  264. if (undoManager != nullptr)
  265. undoManager->beginNewTransaction();
  266. launchAsyncCallOutBox (*this, new PopupColourSelector (colourValue, defaultColour, canResetToDefault));
  267. }
  268. void valueChanged (Value&)
  269. {
  270. refresh();
  271. }
  272. private:
  273. UndoManager* undoManager;
  274. Value colourValue;
  275. Colour lastColour;
  276. const Colour defaultColour;
  277. const bool canResetToDefault;
  278. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourEditorComponent);
  279. };
  280. //==============================================================================
  281. class ColourPropertyComponent : public PropertyComponent
  282. {
  283. public:
  284. ColourPropertyComponent (UndoManager* undoManager, const String& name, const Value& colour,
  285. const Colour& defaultColour, bool canResetToDefault)
  286. : PropertyComponent (name),
  287. colourEditor (undoManager, colour, defaultColour, canResetToDefault)
  288. {
  289. addAndMakeVisible (&colourEditor);
  290. }
  291. void resized()
  292. {
  293. colourEditor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
  294. }
  295. void refresh() {}
  296. protected:
  297. ColourEditorComponent colourEditor;
  298. };