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.

381 lines
12KB

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