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.

289 lines
9.0KB

  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_Application.h"
  19. #include "jucer_AppearanceSettings.h"
  20. #include "jucer_GlobalPreferences.h"
  21. namespace AppearanceColours
  22. {
  23. struct ColourInfo
  24. {
  25. const char* name;
  26. int colourID;
  27. bool mustBeOpaque;
  28. bool applyToEditorOnly;
  29. };
  30. static const ColourInfo colours[] =
  31. {
  32. { "Main Window Bkgd", mainBackgroundColourId, true, false },
  33. { "Treeview Highlight", TreeView::selectedItemBackgroundColourId, false, false },
  34. { "Code Background", CodeEditorComponent::backgroundColourId, true, false },
  35. { "Line Number Bkgd", CodeEditorComponent::lineNumberBackgroundId, false, false },
  36. { "Line Numbers", CodeEditorComponent::lineNumberTextId, false, false },
  37. { "Plain Text", CodeEditorComponent::defaultTextColourId, false, false },
  38. { "Selected Text Bkgd", CodeEditorComponent::highlightColourId, false, false },
  39. { "Caret", CaretComponent::caretColourId, false, true }
  40. };
  41. enum
  42. {
  43. numColours = sizeof (AppearanceColours::colours) / sizeof (AppearanceColours::colours[0])
  44. };
  45. }
  46. //==============================================================================
  47. AppearanceSettings::AppearanceSettings (bool updateAppWhenChanged)
  48. : settings ("COLOUR_SCHEME")
  49. {
  50. if (! ProjucerApplication::getApp().isRunningCommandLine)
  51. {
  52. ProjucerLookAndFeel lf;
  53. for (int i = 0; i < AppearanceColours::numColours; ++i)
  54. getColourValue (AppearanceColours::colours[i].name) = lf.findColour (AppearanceColours::colours[i].colourID).toString();
  55. CodeDocument doc;
  56. CPlusPlusCodeTokeniser tokeniser;
  57. CodeEditorComponent editor (doc, &tokeniser);
  58. const CodeEditorComponent::ColourScheme cs (editor.getColourScheme());
  59. for (int i = cs.types.size(); --i >= 0;)
  60. {
  61. CodeEditorComponent::ColourScheme::TokenType& t = cs.types.getReference(i);
  62. getColourValue (t.name) = t.colour.toString();
  63. }
  64. getCodeFontValue() = getDefaultCodeFont().toString();
  65. if (updateAppWhenChanged)
  66. settings.addListener (this);
  67. }
  68. }
  69. File AppearanceSettings::getSchemesFolder()
  70. {
  71. File f (getGlobalProperties().getFile().getSiblingFile ("Schemes"));
  72. f.createDirectory();
  73. return f;
  74. }
  75. void AppearanceSettings::writeDefaultSchemeFile (const String& xmlString, const String& name)
  76. {
  77. const File file (getSchemesFolder().getChildFile (name).withFileExtension (getSchemeFileSuffix()));
  78. AppearanceSettings settings (false);
  79. ScopedPointer<XmlElement> xml (XmlDocument::parse (xmlString));
  80. if (xml != nullptr)
  81. settings.readFromXML (*xml);
  82. settings.writeToFile (file);
  83. }
  84. void AppearanceSettings::refreshPresetSchemeList()
  85. {
  86. writeDefaultSchemeFile (BinaryData::colourscheme_dark_xml, "Default (Dark)");
  87. writeDefaultSchemeFile (BinaryData::colourscheme_light_xml, "Default (Light)");
  88. Array<File> newSchemes;
  89. getSchemesFolder().findChildFiles (newSchemes, File::findFiles, false, String ("*") + getSchemeFileSuffix());
  90. if (newSchemes != presetSchemeFiles)
  91. {
  92. presetSchemeFiles.swapWith (newSchemes);
  93. ProjucerApplication::getCommandManager().commandStatusChanged();
  94. }
  95. }
  96. StringArray AppearanceSettings::getPresetSchemes()
  97. {
  98. StringArray s;
  99. for (int i = 0; i < presetSchemeFiles.size(); ++i)
  100. s.add (presetSchemeFiles.getReference(i).getFileNameWithoutExtension());
  101. return s;
  102. }
  103. void AppearanceSettings::selectPresetScheme (int index)
  104. {
  105. readFromFile (presetSchemeFiles [index]);
  106. }
  107. bool AppearanceSettings::readFromXML (const XmlElement& xml)
  108. {
  109. if (xml.hasTagName (settings.getType().toString()))
  110. {
  111. const ValueTree newSettings (ValueTree::fromXml (xml));
  112. // we'll manually copy across the new properties to the existing tree so that
  113. // any open editors will be kept up to date..
  114. settings.copyPropertiesFrom (newSettings, nullptr);
  115. for (int i = settings.getNumChildren(); --i >= 0;)
  116. {
  117. ValueTree c (settings.getChild (i));
  118. const ValueTree newValue (newSettings.getChildWithProperty (Ids::name, c.getProperty (Ids::name)));
  119. if (newValue.isValid())
  120. c.copyPropertiesFrom (newValue, nullptr);
  121. }
  122. return true;
  123. }
  124. return false;
  125. }
  126. bool AppearanceSettings::readFromFile (const File& file)
  127. {
  128. const ScopedPointer<XmlElement> xml (XmlDocument::parse (file));
  129. return xml != nullptr && readFromXML (*xml);
  130. }
  131. bool AppearanceSettings::writeToFile (const File& file) const
  132. {
  133. const ScopedPointer<XmlElement> xml (settings.createXml());
  134. return xml != nullptr && xml->writeToFile (file, String());
  135. }
  136. Font AppearanceSettings::getDefaultCodeFont()
  137. {
  138. return Font (Font::getDefaultMonospacedFontName(), Font::getDefaultStyle(), 13.0f);
  139. }
  140. StringArray AppearanceSettings::getColourNames() const
  141. {
  142. StringArray s;
  143. for (int i = 0; i < settings.getNumChildren(); ++i)
  144. {
  145. const ValueTree c (settings.getChild(i));
  146. if (c.hasType ("COLOUR"))
  147. s.add (c [Ids::name]);
  148. }
  149. return s;
  150. }
  151. void AppearanceSettings::updateColourScheme()
  152. {
  153. applyToLookAndFeel (LookAndFeel::getDefaultLookAndFeel());
  154. ProjucerApplication::getApp().mainWindowList.sendLookAndFeelChange();
  155. }
  156. void AppearanceSettings::applyToLookAndFeel (LookAndFeel& lf) const
  157. {
  158. for (int i = 0; i < AppearanceColours::numColours; ++i)
  159. {
  160. Colour col;
  161. if (getColour (AppearanceColours::colours[i].name, col))
  162. {
  163. if (AppearanceColours::colours[i].mustBeOpaque)
  164. col = Colours::white.overlaidWith (col);
  165. if (! AppearanceColours::colours[i].applyToEditorOnly)
  166. lf.setColour (AppearanceColours::colours[i].colourID, col);
  167. }
  168. }
  169. lf.setColour (ScrollBar::thumbColourId, lf.findColour (mainBackgroundColourId).contrasting().withAlpha (0.13f));
  170. }
  171. void AppearanceSettings::applyToCodeEditor (CodeEditorComponent& editor) const
  172. {
  173. CodeEditorComponent::ColourScheme cs (editor.getColourScheme());
  174. for (int i = cs.types.size(); --i >= 0;)
  175. {
  176. CodeEditorComponent::ColourScheme::TokenType& t = cs.types.getReference(i);
  177. getColour (t.name, t.colour);
  178. }
  179. editor.setColourScheme (cs);
  180. editor.setFont (getCodeFont());
  181. for (int i = 0; i < AppearanceColours::numColours; ++i)
  182. {
  183. if (AppearanceColours::colours[i].applyToEditorOnly)
  184. {
  185. Colour col;
  186. if (getColour (AppearanceColours::colours[i].name, col))
  187. editor.setColour (AppearanceColours::colours[i].colourID, col);
  188. }
  189. }
  190. editor.setColour (ScrollBar::thumbColourId, editor.findColour (CodeEditorComponent::backgroundColourId)
  191. .contrasting()
  192. .withAlpha (0.13f));
  193. }
  194. Font AppearanceSettings::getCodeFont() const
  195. {
  196. const String fontString (settings [Ids::font].toString());
  197. if (fontString.isEmpty())
  198. return getDefaultCodeFont();
  199. return Font::fromString (fontString);
  200. }
  201. Value AppearanceSettings::getCodeFontValue()
  202. {
  203. return settings.getPropertyAsValue (Ids::font, nullptr);
  204. }
  205. Value AppearanceSettings::getColourValue (const String& colourName)
  206. {
  207. ValueTree c (settings.getChildWithProperty (Ids::name, colourName));
  208. if (! c.isValid())
  209. {
  210. c = ValueTree ("COLOUR");
  211. c.setProperty (Ids::name, colourName, nullptr);
  212. settings.addChild (c, -1, nullptr);
  213. }
  214. return c.getPropertyAsValue (Ids::colour, nullptr);
  215. }
  216. bool AppearanceSettings::getColour (const String& name, Colour& result) const
  217. {
  218. const ValueTree colour (settings.getChildWithProperty (Ids::name, name));
  219. if (colour.isValid())
  220. {
  221. result = Colour::fromString (colour [Ids::colour].toString());
  222. return true;
  223. }
  224. return false;
  225. }