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.

432 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& g);
  73. void timerCallback();
  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. class FloatingLabelComponent : public Component
  109. {
  110. public:
  111. FloatingLabelComponent();
  112. void remove();
  113. void update (Component* parent, const String& text, const Colour& textColour,
  114. int x, int y, bool toRight, bool below);
  115. void paint (Graphics& g);
  116. private:
  117. Font font;
  118. Colour colour;
  119. GlyphArrangement glyphs;
  120. };
  121. //==============================================================================
  122. // A ValueSource which takes an input source, and forwards any changes in it.
  123. // This class is a handy way to create sources which re-map a value.
  124. class ValueSourceFilter : public Value::ValueSource,
  125. public Value::Listener
  126. {
  127. public:
  128. ValueSourceFilter (const Value& source) : sourceValue (source)
  129. {
  130. sourceValue.addListener (this);
  131. }
  132. void valueChanged (Value&) { sendChangeMessage (true); }
  133. protected:
  134. Value sourceValue;
  135. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSourceFilter)
  136. };
  137. //==============================================================================
  138. class FloatingToolWindow : public DialogWindow
  139. {
  140. public:
  141. FloatingToolWindow (const String& title,
  142. const String& windowPosPropertyName,
  143. Component* content,
  144. ScopedPointer<Component>& ownerPointer,
  145. int defaultW, int defaultH,
  146. int minW, int minH,
  147. int maxW, int maxH)
  148. : DialogWindow (title, Colours::darkgrey, true, true),
  149. windowPosProperty (windowPosPropertyName),
  150. owner (ownerPointer)
  151. {
  152. setUsingNativeTitleBar (true);
  153. setResizable (true, true);
  154. setResizeLimits (minW, minH, maxW, maxH);
  155. setContentOwned (content, false);
  156. const String windowState (getGlobalProperties().getValue (windowPosProperty));
  157. if (windowState.isNotEmpty())
  158. restoreWindowStateFromString (windowState);
  159. else
  160. centreAroundComponent (Component::getCurrentlyFocusedComponent(), defaultW, defaultH);
  161. setVisible (true);
  162. owner = this;
  163. }
  164. ~FloatingToolWindow()
  165. {
  166. getGlobalProperties().setValue (windowPosProperty, getWindowStateAsString());
  167. }
  168. void closeButtonPressed()
  169. {
  170. owner = nullptr;
  171. }
  172. private:
  173. String windowPosProperty;
  174. ScopedPointer<Component>& owner;
  175. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FloatingToolWindow)
  176. };
  177. //==============================================================================
  178. class PopupColourSelector : public Component,
  179. public ChangeListener,
  180. public Value::Listener,
  181. public ButtonListener
  182. {
  183. public:
  184. PopupColourSelector (const Value& colour,
  185. const Colour& defaultCol,
  186. const bool canResetToDefault)
  187. : defaultButton ("Reset to Default"),
  188. colourValue (colour),
  189. defaultColour (defaultCol)
  190. {
  191. addAndMakeVisible (&selector);
  192. selector.setName ("Colour");
  193. selector.setCurrentColour (getColour());
  194. selector.addChangeListener (this);
  195. if (canResetToDefault)
  196. {
  197. addAndMakeVisible (&defaultButton);
  198. defaultButton.addListener (this);
  199. }
  200. colourValue.addListener (this);
  201. setSize (300, 400);
  202. }
  203. void resized()
  204. {
  205. if (defaultButton.isVisible())
  206. {
  207. selector.setBounds (0, 0, getWidth(), getHeight() - 30);
  208. defaultButton.changeWidthToFitText (22);
  209. defaultButton.setTopLeftPosition (10, getHeight() - 26);
  210. }
  211. else
  212. {
  213. selector.setBounds (getLocalBounds());
  214. }
  215. }
  216. Colour getColour() const
  217. {
  218. if (colourValue.toString().isEmpty())
  219. return defaultColour;
  220. return Colour::fromString (colourValue.toString());
  221. }
  222. void setColour (const Colour& newColour)
  223. {
  224. if (getColour() != newColour)
  225. {
  226. if (newColour == defaultColour && defaultButton.isVisible())
  227. colourValue = var::null;
  228. else
  229. colourValue = newColour.toDisplayString (true);
  230. }
  231. }
  232. void buttonClicked (Button*)
  233. {
  234. setColour (defaultColour);
  235. selector.setCurrentColour (defaultColour);
  236. }
  237. void changeListenerCallback (ChangeBroadcaster*)
  238. {
  239. if (selector.getCurrentColour() != getColour())
  240. setColour (selector.getCurrentColour());
  241. }
  242. void valueChanged (Value&)
  243. {
  244. selector.setCurrentColour (getColour());
  245. }
  246. private:
  247. StoredSettings::ColourSelectorWithSwatches selector;
  248. TextButton defaultButton;
  249. Value colourValue;
  250. Colour defaultColour;
  251. };
  252. //==============================================================================
  253. /**
  254. A component that shows a colour swatch with hex ARGB value, and which pops up
  255. a colour selector when you click it.
  256. */
  257. class ColourEditorComponent : public Component,
  258. public Value::Listener
  259. {
  260. public:
  261. ColourEditorComponent (UndoManager* um, const Value& colour,
  262. const Colour& defaultCol, const bool canReset)
  263. : undoManager (um), colourValue (colour), defaultColour (defaultCol),
  264. canResetToDefault (canReset)
  265. {
  266. colourValue.addListener (this);
  267. }
  268. void paint (Graphics& g)
  269. {
  270. const Colour colour (getColour());
  271. g.fillAll (Colours::grey);
  272. g.fillCheckerBoard (getLocalBounds().reduced (2),
  273. 10, 10,
  274. Colour (0xffdddddd).overlaidWith (colour),
  275. Colour (0xffffffff).overlaidWith (colour));
  276. g.setColour (Colours::white.overlaidWith (colour).contrasting());
  277. g.setFont (Font (getHeight() * 0.6f, Font::bold));
  278. g.drawFittedText (colour.toDisplayString (true), getLocalBounds().reduced (2, 1),
  279. Justification::centred, 1);
  280. }
  281. Colour getColour() const
  282. {
  283. if (colourValue.toString().isEmpty())
  284. return defaultColour;
  285. return Colour::fromString (colourValue.toString());
  286. }
  287. void setColour (const Colour& newColour)
  288. {
  289. if (getColour() != newColour)
  290. {
  291. if (newColour == defaultColour && canResetToDefault)
  292. colourValue = var::null;
  293. else
  294. colourValue = newColour.toDisplayString (true);
  295. }
  296. }
  297. void resetToDefault()
  298. {
  299. setColour (defaultColour);
  300. }
  301. void refresh()
  302. {
  303. const Colour col (getColour());
  304. if (col != lastColour)
  305. {
  306. lastColour = col;
  307. repaint();
  308. }
  309. }
  310. void mouseDown (const MouseEvent&)
  311. {
  312. if (undoManager != nullptr)
  313. undoManager->beginNewTransaction();
  314. CallOutBox::launchAsynchronously (new PopupColourSelector (colourValue,
  315. defaultColour,
  316. canResetToDefault),
  317. getScreenBounds(), nullptr);
  318. }
  319. void valueChanged (Value&)
  320. {
  321. refresh();
  322. }
  323. private:
  324. UndoManager* undoManager;
  325. Value colourValue;
  326. Colour lastColour;
  327. const Colour defaultColour;
  328. const bool canResetToDefault;
  329. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourEditorComponent)
  330. };
  331. //==============================================================================
  332. class ColourPropertyComponent : public PropertyComponent
  333. {
  334. public:
  335. ColourPropertyComponent (UndoManager* undoManager, const String& name, const Value& colour,
  336. const Colour& defaultColour, bool canResetToDefault)
  337. : PropertyComponent (name),
  338. colourEditor (undoManager, colour, defaultColour, canResetToDefault)
  339. {
  340. addAndMakeVisible (&colourEditor);
  341. }
  342. void resized()
  343. {
  344. colourEditor.setBounds (getLookAndFeel().getPropertyComponentContentPosition (*this));
  345. }
  346. void refresh() {}
  347. protected:
  348. ColourEditorComponent colourEditor;
  349. };