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.

377 lines
14KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. #include "../jucer_Headers.h"
  18. #include "jucer_GlobalPreferences.h"
  19. #include "../Utility/jucer_FloatingToolWindow.h"
  20. #include "../Utility/jucer_ColourPropertyComponent.h"
  21. //==============================================================================
  22. PathSettingsTab::PathSettingsTab (DependencyPathOS os)
  23. {
  24. const int maxChars = 1024;
  25. StoredSettings& settings = getAppSettings();
  26. vst2PathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::vst2Path, os), "VST SDK", maxChars, false));
  27. vst3PathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::vst3Path, os), "VST3 SDK", maxChars, false));
  28. #if ! JUCE_LINUX
  29. rtasPathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::rtasPath, os), "RTAS SDK", maxChars, false));
  30. aaxPathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::aaxPath, os), "AAX SDK", maxChars, false));
  31. #endif
  32. androidSdkPathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::androidSDKPath, os), "Android SDK", maxChars, false));
  33. androidNdkPathComponent = pathComponents.add (new TextPropertyComponent (settings.getGlobalPath (Ids::androidNDKPath, os), "Android NDK", maxChars, false));
  34. for (TextPropertyComponent** component = pathComponents.begin(); component != pathComponents.end(); ++component)
  35. {
  36. addAndMakeVisible (**component);
  37. (*component)->addListener (this);
  38. textPropertyComponentChanged (*component);
  39. }
  40. }
  41. PathSettingsTab::~PathSettingsTab()
  42. {
  43. }
  44. void PathSettingsTab::textPropertyComponentChanged (TextPropertyComponent* textPropertyComponent)
  45. {
  46. Identifier keyName = getKeyForPropertyComponent (textPropertyComponent);
  47. Colour textColour = getAppSettings().isGlobalPathValid (keyName, textPropertyComponent->getText())
  48. ? Colours::black
  49. : Colours::red;
  50. textPropertyComponent->setColour (TextPropertyComponent::textColourId, textColour);
  51. }
  52. Identifier PathSettingsTab::getKeyForPropertyComponent (TextPropertyComponent* component) const
  53. {
  54. if (component == vst2PathComponent) return Ids::vst2Path;
  55. if (component == vst3PathComponent) return Ids::vst3Path;
  56. if (component == rtasPathComponent) return Ids::rtasPath;
  57. if (component == aaxPathComponent) return Ids::aaxPath;
  58. if (component == androidSdkPathComponent) return Ids::androidSDKPath;
  59. if (component == androidNdkPathComponent) return Ids::androidNDKPath;
  60. // this property component does not have a key associated to it!
  61. jassertfalse;
  62. return String::empty;
  63. }
  64. Component* PathSettingsTab::getContent()
  65. {
  66. return this;
  67. }
  68. String PathSettingsTab::getName() const noexcept
  69. {
  70. return "Paths";
  71. }
  72. void PathSettingsTab::resized()
  73. {
  74. const int componentHeight = 25;
  75. for (TextPropertyComponent** component = pathComponents.begin(); component != pathComponents.end(); ++component)
  76. {
  77. const int elementNumber = pathComponents.indexOf (*component);
  78. (*component)->setBounds (0, componentHeight * elementNumber, getWidth(), componentHeight);
  79. }
  80. }
  81. //==============================================================================
  82. struct AppearanceEditor
  83. {
  84. struct FontScanPanel : public Component,
  85. private Timer
  86. {
  87. FontScanPanel()
  88. {
  89. fontsToScan = Font::findAllTypefaceNames();
  90. startTimer (1);
  91. }
  92. void paint (Graphics& g) override
  93. {
  94. g.fillAll (Colours::darkgrey);
  95. g.setFont (14.0f);
  96. g.setColour (Colours::white);
  97. g.drawFittedText ("Scanning for fonts..", getLocalBounds(), Justification::centred, 2);
  98. const int size = 30;
  99. getLookAndFeel().drawSpinningWaitAnimation (g, Colours::white, (getWidth() - size) / 2, getHeight() / 2 - 50, size, size);
  100. }
  101. void timerCallback() override
  102. {
  103. repaint();
  104. if (fontsToScan.size() == 0)
  105. {
  106. getAppSettings().monospacedFontNames = fontsFound;
  107. if (AppearanceSettingsTab* tab = findParentComponentOfClass<AppearanceSettingsTab>())
  108. tab->changeContent (new EditorPanel());
  109. }
  110. else
  111. {
  112. if (isMonospacedTypeface (fontsToScan[0]))
  113. fontsFound.add (fontsToScan[0]);
  114. fontsToScan.remove (0);
  115. }
  116. }
  117. // A rather hacky trick to select only the fixed-pitch fonts..
  118. // This is unfortunately a bit slow, but will work on all platforms.
  119. static bool isMonospacedTypeface (const String& name)
  120. {
  121. const Font font (name, 20.0f, Font::plain);
  122. const int width = font.getStringWidth ("....");
  123. return width == font.getStringWidth ("WWWW")
  124. && width == font.getStringWidth ("0000")
  125. && width == font.getStringWidth ("1111")
  126. && width == font.getStringWidth ("iiii");
  127. }
  128. StringArray fontsToScan, fontsFound;
  129. };
  130. //==============================================================================
  131. struct EditorPanel : public Component,
  132. private ButtonListener
  133. {
  134. EditorPanel()
  135. : loadButton ("Load Scheme..."),
  136. saveButton ("Save Scheme...")
  137. {
  138. rebuildProperties();
  139. addAndMakeVisible (panel);
  140. loadButton.setColour (TextButton::buttonColourId, Colours::lightgrey.withAlpha (0.5f));
  141. saveButton.setColour (TextButton::buttonColourId, Colours::lightgrey.withAlpha (0.5f));
  142. loadButton.setColour (TextButton::textColourOffId, Colours::white);
  143. saveButton.setColour (TextButton::textColourOffId, Colours::white);
  144. addAndMakeVisible (loadButton);
  145. addAndMakeVisible (saveButton);
  146. loadButton.addListener (this);
  147. saveButton.addListener (this);
  148. }
  149. void rebuildProperties()
  150. {
  151. AppearanceSettings& scheme = getAppSettings().appearance;
  152. Array<PropertyComponent*> props;
  153. Value fontValue (scheme.getCodeFontValue());
  154. props.add (FontNameValueSource::createProperty ("Code Editor Font", fontValue));
  155. props.add (FontSizeValueSource::createProperty ("Font Size", fontValue));
  156. const StringArray colourNames (scheme.getColourNames());
  157. for (int i = 0; i < colourNames.size(); ++i)
  158. props.add (new ColourPropertyComponent (nullptr, colourNames[i],
  159. scheme.getColourValue (colourNames[i]),
  160. Colours::white, false));
  161. panel.clear();
  162. panel.addProperties (props);
  163. }
  164. void resized() override
  165. {
  166. Rectangle<int> r (getLocalBounds());
  167. panel.setBounds (r.removeFromTop (getHeight() - 28).reduced (4, 2));
  168. loadButton.setBounds (r.removeFromLeft (getWidth() / 2).reduced (10, 4));
  169. saveButton.setBounds (r.reduced (10, 3));
  170. }
  171. private:
  172. PropertyPanel panel;
  173. TextButton loadButton, saveButton;
  174. void buttonClicked (Button* b) override
  175. {
  176. if (b == &loadButton)
  177. loadScheme();
  178. else
  179. saveScheme();
  180. }
  181. void saveScheme()
  182. {
  183. FileChooser fc ("Select a file in which to save this colour-scheme...",
  184. getAppSettings().appearance.getSchemesFolder()
  185. .getNonexistentChildFile ("Scheme", AppearanceSettings::getSchemeFileSuffix()),
  186. AppearanceSettings::getSchemeFileWildCard());
  187. if (fc.browseForFileToSave (true))
  188. {
  189. File file (fc.getResult().withFileExtension (AppearanceSettings::getSchemeFileSuffix()));
  190. getAppSettings().appearance.writeToFile (file);
  191. getAppSettings().appearance.refreshPresetSchemeList();
  192. }
  193. }
  194. void loadScheme()
  195. {
  196. FileChooser fc ("Please select a colour-scheme file to load...",
  197. getAppSettings().appearance.getSchemesFolder(),
  198. AppearanceSettings::getSchemeFileWildCard());
  199. if (fc.browseForFileToOpen())
  200. if (getAppSettings().appearance.readFromFile (fc.getResult()))
  201. rebuildProperties();
  202. }
  203. JUCE_DECLARE_NON_COPYABLE (EditorPanel)
  204. };
  205. //==============================================================================
  206. struct FontNameValueSource : public ValueSourceFilter
  207. {
  208. FontNameValueSource (const Value& source) : ValueSourceFilter (source) {}
  209. var getValue() const override
  210. {
  211. return Font::fromString (sourceValue.toString()).getTypefaceName();
  212. }
  213. void setValue (const var& newValue) override
  214. {
  215. Font font (Font::fromString (sourceValue.toString()));
  216. font.setTypefaceName (newValue.toString().isEmpty() ? Font::getDefaultMonospacedFontName()
  217. : newValue.toString());
  218. sourceValue = font.toString();
  219. }
  220. static ChoicePropertyComponent* createProperty (const String& title, const Value& value)
  221. {
  222. StringArray fontNames = getAppSettings().monospacedFontNames;
  223. Array<var> values;
  224. values.add (Font::getDefaultMonospacedFontName());
  225. values.add (var());
  226. for (int i = 0; i < fontNames.size(); ++i)
  227. values.add (fontNames[i]);
  228. StringArray names;
  229. names.add ("<Default Monospaced>");
  230. names.add (String::empty);
  231. names.addArray (getAppSettings().monospacedFontNames);
  232. return new ChoicePropertyComponent (Value (new FontNameValueSource (value)),
  233. title, names, values);
  234. }
  235. };
  236. //==============================================================================
  237. struct FontSizeValueSource : public ValueSourceFilter
  238. {
  239. FontSizeValueSource (const Value& source) : ValueSourceFilter (source) {}
  240. var getValue() const override
  241. {
  242. return Font::fromString (sourceValue.toString()).getHeight();
  243. }
  244. void setValue (const var& newValue) override
  245. {
  246. sourceValue = Font::fromString (sourceValue.toString()).withHeight (newValue).toString();
  247. }
  248. static PropertyComponent* createProperty (const String& title, const Value& value)
  249. {
  250. return new SliderPropertyComponent (Value (new FontSizeValueSource (value)),
  251. title, 5.0, 40.0, 0.1, 0.5);
  252. }
  253. };
  254. };
  255. void AppearanceSettings::showGlobalPreferences (ScopedPointer<Component>& ownerPointer)
  256. {
  257. if (ownerPointer != nullptr)
  258. ownerPointer->toFront (true);
  259. else
  260. new FloatingToolWindow ("Global Preferences",
  261. "globalPreferencesEditorPos",
  262. new GlobalPreferencesComponent,
  263. ownerPointer,
  264. 500, 500, 500, 500, 500, 500);
  265. }
  266. //==============================================================================
  267. AppearanceSettingsTab::AppearanceSettingsTab()
  268. {
  269. if (getAppSettings().monospacedFontNames.size() == 0)
  270. content = new AppearanceEditor::FontScanPanel();
  271. else
  272. content = new AppearanceEditor::EditorPanel();
  273. changeContent (content);
  274. }
  275. Component* AppearanceSettingsTab::getContent()
  276. {
  277. return this;
  278. }
  279. void AppearanceSettingsTab::changeContent (Component* newContent)
  280. {
  281. content = newContent;
  282. addAndMakeVisible (content);
  283. content->setBounds (getLocalBounds());
  284. }
  285. String AppearanceSettingsTab::getName() const noexcept
  286. {
  287. return "Code Editor";
  288. }
  289. void AppearanceSettingsTab::resized()
  290. {
  291. content->setBounds (getLocalBounds());
  292. }
  293. //==============================================================================
  294. GlobalPreferencesComponent::GlobalPreferencesComponent()
  295. : TabbedComponent (TabbedButtonBar::TabsAtTop)
  296. {
  297. preferenceTabs.add (new PathSettingsTab (TargetOS::getThisOS()));
  298. preferenceTabs.add (new AppearanceSettingsTab);
  299. for (GlobalPreferencesTab** tab = preferenceTabs.begin(); tab != preferenceTabs.end(); ++tab)
  300. addTab ((*tab)->getName(), findColour(mainBackgroundColourId, true), (*tab)->getContent(), true);
  301. }