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.

361 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. #include "jucer_Application.h"
  19. #include "jucer_AppearanceSettings.h"
  20. //==============================================================================
  21. AppearanceSettings::AppearanceSettings (const CodeEditorComponent& editor)
  22. : settings ("COLOUR_SCHEME")
  23. {
  24. getColourValue ("Background") = editor.findColour (CodeEditorComponent::backgroundColourId).toString();
  25. getColourValue ("Plain Text") = editor.findColour (CodeEditorComponent::defaultTextColourId).toString();
  26. getColourValue ("Selected Background") = editor.findColour (CodeEditorComponent::highlightColourId).toString();
  27. const CodeEditorComponent::ColourScheme cs (editor.getColourScheme());
  28. for (int i = cs.types.size(); --i >= 0;)
  29. {
  30. CodeEditorComponent::ColourScheme::TokenType& t = cs.types.getReference(i);
  31. getColourValue (t.name) = t.colour.toString();
  32. }
  33. Font f (editor.getFont());
  34. f.setTypefaceName (f.getTypeface()->getName());
  35. getCodeFontValue() = f.toString();
  36. }
  37. bool AppearanceSettings::readFromFile (const File& file)
  38. {
  39. const ScopedPointer<XmlElement> xml (XmlDocument::parse (file));
  40. if (xml != nullptr && xml->hasTagName (settings.getType().toString()))
  41. {
  42. settings = ValueTree::fromXml (*xml);
  43. return true;
  44. }
  45. return false;
  46. }
  47. bool AppearanceSettings::writeToFile (const File& file) const
  48. {
  49. const ScopedPointer<XmlElement> xml (settings.createXml());
  50. return xml != nullptr && xml->writeToFile (file, String::empty);
  51. }
  52. StringArray AppearanceSettings::getColourNames() const
  53. {
  54. StringArray s;
  55. for (int i = 0; i < settings.getNumChildren(); ++i)
  56. {
  57. const ValueTree c (settings.getChild(i));
  58. if (c.hasType ("COLOUR"))
  59. s.add (c [Ids::name]);
  60. }
  61. return s;
  62. }
  63. void AppearanceSettings::applyToCodeEditor (CodeEditorComponent& editor) const
  64. {
  65. CodeEditorComponent::ColourScheme cs (editor.getColourScheme());
  66. for (int i = cs.types.size(); --i >= 0;)
  67. {
  68. CodeEditorComponent::ColourScheme::TokenType& t = cs.types.getReference(i);
  69. getColour (t.name, t.colour);
  70. }
  71. editor.setColourScheme (cs);
  72. Colour col;
  73. if (getColour ("Plain Text", col)) editor.setColour (CodeEditorComponent::defaultTextColourId, col);
  74. if (getColour ("Selected Background", col)) editor.setColour (CodeEditorComponent::highlightColourId, col);
  75. if (getColour ("Background", col))
  76. {
  77. col = Colours::white.overlaidWith (col);
  78. editor.setColour (CodeEditorComponent::backgroundColourId, col);
  79. editor.setColour (CaretComponent::caretColourId, col.contrasting());
  80. }
  81. editor.setFont (getCodeFont());
  82. }
  83. Font AppearanceSettings::getCodeFont() const
  84. {
  85. const String fontString (settings [Ids::font].toString());
  86. if (fontString.isEmpty())
  87. {
  88. #if JUCE_MAC
  89. Font font (13.0f);
  90. font.setTypefaceName ("Menlo");
  91. #else
  92. Font font (10.0f);
  93. font.setTypefaceName (Font::getDefaultMonospacedFontName());
  94. #endif
  95. return font;
  96. }
  97. return Font::fromString (fontString);
  98. }
  99. Value AppearanceSettings::getCodeFontValue()
  100. {
  101. return settings.getPropertyAsValue (Ids::font, nullptr);
  102. }
  103. Value AppearanceSettings::getColourValue (const String& colourName)
  104. {
  105. ValueTree c (settings.getChildWithProperty (Ids::name, colourName));
  106. if (! c.isValid())
  107. {
  108. c = ValueTree ("COLOUR");
  109. c.setProperty (Ids::name, colourName, nullptr);
  110. settings.addChild (c, -1, nullptr);
  111. }
  112. return c.getPropertyAsValue (Ids::colour, nullptr);
  113. }
  114. bool AppearanceSettings::getColour (const String& name, Colour& result) const
  115. {
  116. const ValueTree colour (settings.getChildWithProperty (Ids::name, name));
  117. if (colour.isValid())
  118. {
  119. result = Colour::fromString (colour [Ids::colour].toString());
  120. return true;
  121. }
  122. return false;
  123. }
  124. //==============================================================================
  125. struct AppearanceEditor
  126. {
  127. class Window : public DialogWindow
  128. {
  129. public:
  130. Window() : DialogWindow ("Appearance Settings", Colours::black, true, true)
  131. {
  132. setUsingNativeTitleBar (true);
  133. setContentOwned (new EditorPanel(), false);
  134. setResizable (true, true);
  135. const int width = 350;
  136. setResizeLimits (width, 200, width, 1000);
  137. String windowState (getAppProperties().getValue (getWindowPosName()));
  138. if (windowState.isNotEmpty())
  139. restoreWindowStateFromString (windowState);
  140. else
  141. centreAroundComponent (Component::getCurrentlyFocusedComponent(), width, 500);
  142. setVisible (true);
  143. }
  144. ~Window()
  145. {
  146. getAppProperties().setValue (getWindowPosName(), getWindowStateAsString());
  147. }
  148. void closeButtonPressed()
  149. {
  150. JucerApplication::getApp()->appearanceEditorWindow = nullptr;
  151. }
  152. private:
  153. static const char* getWindowPosName() { return "colourSchemeEditorPos"; }
  154. JUCE_DECLARE_NON_COPYABLE (Window);
  155. };
  156. //==============================================================================
  157. class EditorPanel : public Component,
  158. private Button::Listener
  159. {
  160. public:
  161. EditorPanel()
  162. : loadButton ("Load Scheme..."),
  163. saveButton ("Save Scheme...")
  164. {
  165. setOpaque (true);
  166. rebuildProperties();
  167. addAndMakeVisible (&panel);
  168. loadButton.setColour (TextButton::buttonColourId, Colours::grey);
  169. saveButton.setColour (TextButton::buttonColourId, Colours::grey);
  170. addAndMakeVisible (&loadButton);
  171. addAndMakeVisible (&saveButton);
  172. loadButton.addListener (this);
  173. saveButton.addListener (this);
  174. }
  175. void rebuildProperties()
  176. {
  177. AppearanceSettings& scheme = getAppSettings().appearance;
  178. Array <PropertyComponent*> props;
  179. Value fontValue (scheme.getCodeFontValue());
  180. props.add (FontNameValueSource::createProperty ("Code Editor Font", fontValue));
  181. props.add (FontSizeValueSource::createProperty ("Font Size", fontValue));
  182. const StringArray colourNames (scheme.getColourNames());
  183. for (int i = 0; i < colourNames.size(); ++i)
  184. props.add (new ColourPropertyComponent (nullptr, colourNames[i],
  185. scheme.getColourValue (colourNames[i]),
  186. Colours::white, false));
  187. panel.clear();
  188. panel.addProperties (props);
  189. }
  190. void paint (Graphics& g)
  191. {
  192. g.fillAll (Colours::black);
  193. }
  194. void resized()
  195. {
  196. Rectangle<int> r (getLocalBounds());
  197. panel.setBounds (r.removeFromTop (getHeight() - 26).reduced (4, 3));
  198. loadButton.setBounds (r.removeFromLeft (getWidth() / 2).reduced (10, 3));
  199. saveButton.setBounds (r.reduced (10, 3));
  200. }
  201. private:
  202. PropertyPanel panel;
  203. TextButton loadButton, saveButton;
  204. void buttonClicked (Button* b)
  205. {
  206. if (b == &loadButton)
  207. loadScheme();
  208. else
  209. saveScheme();
  210. }
  211. void saveScheme()
  212. {
  213. FileChooser fc ("Select a file in which to save this colour-scheme...",
  214. getAppSettings().getSchemesFolder().getNonexistentChildFile ("Scheme", ".editorscheme"),
  215. "*.editorscheme");
  216. if (fc.browseForFileToSave (true))
  217. {
  218. File file (fc.getResult().withFileExtension (".editorscheme"));
  219. getAppSettings().appearance.writeToFile (file);
  220. }
  221. }
  222. void loadScheme()
  223. {
  224. FileChooser fc ("Please select a colour-scheme file to load...",
  225. getAppSettings().getSchemesFolder(),
  226. "*.editorscheme");
  227. if (fc.browseForFileToOpen())
  228. {
  229. if (getAppSettings().appearance.readFromFile (fc.getResult()))
  230. rebuildProperties();
  231. }
  232. }
  233. JUCE_DECLARE_NON_COPYABLE (EditorPanel);
  234. };
  235. //==============================================================================
  236. class FontNameValueSource : public ValueSourceFilter
  237. {
  238. public:
  239. FontNameValueSource (const Value& source) : ValueSourceFilter (source) {}
  240. var getValue() const
  241. {
  242. return Font::fromString (sourceValue.toString()).getTypefaceName();
  243. }
  244. void setValue (const var& newValue)
  245. {
  246. Font font (Font::fromString (sourceValue.toString()));
  247. font.setTypefaceName (newValue.toString());
  248. sourceValue = font.toString();
  249. }
  250. static ChoicePropertyComponent* createProperty (const String& title, const Value& value)
  251. {
  252. const StringArray& fontNames = getAppSettings().getFontNames();
  253. Array<var> values;
  254. for (int i = 0; i < fontNames.size(); ++i)
  255. values.add (fontNames[i]);
  256. return new ChoicePropertyComponent (Value (new FontNameValueSource (value)),
  257. title, fontNames, values);
  258. }
  259. };
  260. //==============================================================================
  261. class FontSizeValueSource : public ValueSourceFilter
  262. {
  263. public:
  264. FontSizeValueSource (const Value& source) : ValueSourceFilter (source) {}
  265. var getValue() const
  266. {
  267. return Font::fromString (sourceValue.toString()).getHeight();
  268. }
  269. void setValue (const var& newValue)
  270. {
  271. sourceValue = Font::fromString (sourceValue.toString()).withHeight (newValue).toString();
  272. }
  273. static PropertyComponent* createProperty (const String& title, const Value& value)
  274. {
  275. return new SliderPropertyComponent (Value (new FontSizeValueSource (value)),
  276. title, 5.0, 40.0, 0.1, 0.5);
  277. }
  278. };
  279. };
  280. Component* AppearanceSettings::createEditorWindow()
  281. {
  282. return new AppearanceEditor::Window();
  283. }