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.

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