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.

378 lines
13KB

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