.
1 /*
2 Copyright (C) 2015 Johan Mattsson
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 3 of the
7 License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13 */
14
15 using Bird;
16 using Cairo;
17
18 namespace BirdFont {
19
20 public class Theme : GLib.Object {
21
22 static Gee.HashMap<string, Color> colors;
23 public static Gee.ArrayList<string> color_list;
24 public static Gee.ArrayList<string> themes;
25 public static string current_theme;
26
27 public static void text_color (Text text, string name) {
28 Color c;
29
30 if (unlikely (!colors.has_key (name))) {
31 warning (@"Theme does not have a color for $name");
32 return;
33 }
34
35 c = colors.get (name);
36 text.set_source_rgba (c.r, c.g, c.b, c.a);
37 }
38
39 public static void color (Context cr, string name) {
40 Color c;
41
42 if (unlikely (!colors.has_key (name))) {
43 warning (@"Theme does not have a color for $name");
44 return;
45 }
46
47 c = colors.get (name);
48 cr.set_source_rgba (c.r, c.g, c.b, c.a);
49 }
50
51 public static void color_opacity (Context cr, string name, double opacity) {
52 Color c;
53
54 if (unlikely (!colors.has_key (name))) {
55 warning (@"Theme does not have a color for $name");
56 return;
57 }
58
59 c = colors.get (name);
60 cr.set_source_rgba (c.r, c.g, c.b, opacity);
61 }
62
63 public static void text_color_opacity (Text text, string name, double opacity) {
64 Color c;
65
66 if (unlikely (!colors.has_key (name))) {
67 warning (@"Theme does not have a color for $name");
68 return;
69 }
70
71 c = colors.get (name);
72 text.set_source_rgba (c.r, c.g, c.b, opacity);
73 }
74
75 public static Color get_color (string name) {
76 Color c;
77
78 if (unlikely (!colors.has_key (name))) {
79 warning (@"Theme does not have a color for $name");
80 return new Color (0, 0, 0, 1);
81 }
82
83 return colors.get (name);
84 }
85
86 public static void set_default_colors () {
87 current_theme = "";
88
89 color_list = new Gee.ArrayList<string> ();
90 colors = new Gee.HashMap<string, Color> ();
91 themes = new Gee.ArrayList<string> ();
92
93 Theme.set_default_color ("Stroke Color", 0, 0, 0, 1);
94 Theme.set_default_color ("Handle Color", 0, 0, 0, 1);
95 Theme.set_default_color ("Fill Color", 0.5, 0.5, 0.5, 1);
96
97 Theme.set_default_color ("Background 1", 1, 1, 1, 1);
98 Theme.set_default_color ("Background 2", 101 / 255.0, 108 / 255.0, 116 / 255.0, 1);
99 Theme.set_default_color ("Background 3", 38 / 255.0, 39 / 255.0, 43 / 255.0, 1);
100 Theme.set_default_color ("Background 4", 51 / 255.0, 54 / 255.0, 59 / 255.0, 1);
101 Theme.set_default_color ("Background 5", 0.3, 0.3, 0.3, 1);
102 Theme.set_default_color ("Background 6", 224/255.0, 224/255.0, 224/255.0, 1);
103 Theme.set_default_color ("Background 7", 56 / 255.0, 59 / 255.0, 65 / 255.0, 1);
104 Theme.set_default_color ("Background 8", 55/255.0, 55/255.0, 55/255.0, 1);
105 Theme.set_default_color ("Background 9", 72/255.0, 72/255.0, 72/255.0, 1);
106
107 Theme.set_default_color ("Foreground 1", 0, 0, 0, 1);
108 Theme.set_default_color ("Foreground 2", 101 / 255.0, 108 / 255.0, 116 / 255.0, 1);
109 Theme.set_default_color ("Foreground 3", 26 / 255.0, 30 / 255.0, 32 / 255.0, 1);
110 Theme.set_default_color ("Foreground 4", 40 / 255.0, 57 / 255.0, 65 / 255.0, 1);
111 Theme.set_default_color ("Foreground 5", 70 / 255.0, 77 / 255.0, 83 / 255.0, 1);
112 Theme.set_default_color ("Foreground Inverted", 1, 1, 1, 1);
113
114 Theme.set_default_color ("Highlighted 1", 234 / 255.0, 77 / 255.0, 26 / 255.0, 1);
115
116 Theme.set_default_color ("Highlighted Guide", 0, 0, 0.3, 1);
117 Theme.set_default_color ("Guide 1", 0.7, 0.7, 0.8, 1);
118 Theme.set_default_color ("Guide 2", 0.7, 0, 0, 0.5);
119 Theme.set_default_color ("Guide 3", 120 / 255.0, 68 / 255.0, 120 / 255.0, 120 / 255.0);
120
121 Theme.set_default_color ("Grid",0.2, 0.6, 0.2, 0.2);
122
123 Theme.set_default_color ("Background Glyph", 0.2, 0.2, 0.2, 0.5);
124
125 Theme.set_default_color ("Tool Border 1", 38 / 255.0, 39 / 255.0, 43 / 255.0, 1);
126 Theme.set_default_color ("Tool Background 1", 14 / 255.0, 16 / 255.0, 17 / 255.0, 1);
127
128 Theme.set_default_color ("Tool Border 2", 38 / 255.0, 39 / 255.0, 43 / 255.0, 1);
129 Theme.set_default_color ("Tool Background 2", 26 / 255.0, 30 / 255.0, 32 / 255.0, 1);
130
131 Theme.set_default_color ("Tool Border 3", 38 / 255.0, 39 / 255.0, 43 / 255.0, 1);
132 Theme.set_default_color ("Tool Background 3", 44 / 255.0, 47 / 255.0, 51 / 255.0, 1);
133
134 Theme.set_default_color ("Tool Border 4", 38 / 255.0, 39 / 255.0, 43 / 255.0, 1);
135 Theme.set_default_color ("Tool Background 4", 33 / 255.0, 36 / 255.0, 39 / 255.0, 1);
136
137 Theme.set_default_color ("Button Foreground", 101 / 255.0, 108 / 255.0, 116 / 255.0, 1);
138
139 N_("Stroke Color");
140 N_("Handle Color");
141 N_("Fill Color");
142
143 N_("Background 1");
144 N_("Background 2");
145 N_("Background 3");
146 N_("Background 4");
147 N_("Background 5");
148 N_("Background 6");
149 N_("Background 7");
150 N_("Background 8");
151 N_("Background 9");
152
153 N_("Foreground 1");
154 N_("Foreground 2");
155 N_("Foreground 3");
156 N_("Foreground 4");
157 N_("Foreground 5");
158 N_("Foreground Inverted");
159
160 N_("Highlighted 1");
161 N_("Highlighted Guide");
162
163 N_("Grid");
164
165 N_("Guide 1");
166 N_("Guide 2");
167 N_("Guide 3");
168
169 N_("Tool Border 1");
170 N_("Tool Background 1");
171 N_("Tool Border 2");
172 N_("Tool Background 2");
173 N_("Tool Border 3");
174 N_("Tool Background 3");
175 N_("Tool Border 4");
176 N_("Tool Background 4");
177
178 N_("Button Foreground");
179
180 add_theme_files ();
181 }
182
183 static void add_theme_files () {
184 FileEnumerator enumerator;
185 FileInfo? file_info;
186 string file_name;
187 File dir;
188
189 dir = BirdFont.get_settings_directory ();
190
191 themes.clear ();
192 themes.add ("default.theme");
193 themes.add ("high_contrast.theme");
194
195 try {
196 enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
197 while ((file_info = enumerator.next_file ()) != null) {
198 file_name = ((!) file_info).get_name ();
199
200 if (file_name.has_suffix (".theme")) {
201 themes.add (file_name);
202 }
203 }
204 } catch (Error e) {
205 warning (e.message);
206 }
207 }
208
209 public static void set_default_color (string name, double r, double g, double b, double a) {
210 color_list.add (name);
211 colors.set (name, new Color (r, g, b, a));
212 write_theme (); // FIXME: don't overwrite color
213 }
214
215 public static void save_color (string name, double r, double g, double b, double a) {
216 colors.set (name, new Color (r, g, b, a));
217 write_theme ();
218 }
219
220 public static void load_theme (string theme_file) {
221 File default_theme;
222 File user_theme;
223
224 user_theme = get_child (BirdFont.get_settings_directory (), theme_file);
225 if (user_theme.query_exists ()) {
226 current_theme = theme_file;
227 parse_theme (user_theme);
228 return;
229 }
230
231 default_theme = SearchPaths.find_file (null, theme_file);
232 if (default_theme.query_exists ()) {
233 current_theme = theme_file;
234 parse_theme (default_theme);
235 return;
236 }
237
238 warning (@"Theme not found: $theme_file");
239 }
240
241 public static void write_theme () {
242 DataOutputStream os;
243 File file;
244 int i;
245 string base_name;
246
247 if (current_theme == "") {
248 warning ("No name for theme.");
249 return;
250 }
251
252 if (current_theme == "default.theme" || current_theme == "high_contrast.theme") {
253 current_theme = "custom.theme";
254
255 file = get_child (BirdFont.get_settings_directory (), current_theme);
256 i = 2;
257 base_name = "custom";
258 while (file.query_exists ()) {
259 current_theme = @"$(base_name)_theme_$(i).theme";
260 file = get_child (BirdFont.get_settings_directory (), current_theme);
261 i++;
262 }
263 }
264
265 file = get_child (BirdFont.get_settings_directory (), current_theme);
266
267 try {
268 if (file.query_exists ()) {
269 file.delete ();
270 }
271 } catch (GLib.Error e) {
272 warning (e.message);
273 }
274
275 try {
276 os = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION));
277 os.put_string ("""<?xml version="1.0" encoding="utf-8" standalone="yes"?>""");
278 os.put_string ("\n");
279
280 os.put_string ("<theme>\n");
281 foreach (string name in colors.keys) {
282 Color color = colors.get (name);
283
284 os.put_string ("\t<color ");
285
286 os.put_string (@"name=\"$(Markup.escape_text (name))\" ");
287 os.put_string (@"red=\"$(color.r)\" ");
288 os.put_string (@"green=\"$(color.g)\" ");
289 os.put_string (@"blue=\"$(color.b)\" ");
290 os.put_string (@"alpha=\"$(color.a)\"");
291
292 os.put_string ("/>\n");
293 }
294 os.put_string ("</theme>\n");
295
296 os.close ();
297 } catch (GLib.Error e) {
298 warning (e.message);
299 }
300
301 add_theme_files ();
302 }
303
304 static void parse_theme (File f) {
305 string xml_data;
306 XmlParser parser;
307
308 try {
309 FileUtils.get_contents((!) f.get_path (), out xml_data);
310 parser = new XmlParser (xml_data);
311 parse_colors (parser.get_root_tag ());
312 } catch (GLib.Error e) {
313 warning (e.message);
314 }
315 }
316
317 static void parse_colors (Tag tag) {
318 foreach (Tag t in tag) {
319 if (t.get_name () == "color") {
320 parse_color (t.get_attributes ());
321 }
322 }
323 }
324
325 static void parse_color (Attributes attributes) {
326 string name = "";
327 double r = 0;
328 double g = 0;
329 double b = 0;
330 double a = 1;
331
332 foreach (Attribute attr in attributes) {
333 if (attr.get_name () == "name") {
334 name = attr.get_content ();
335 }
336
337 if (attr.get_name () == "red") {
338 r = double.parse (attr.get_content ());
339 }
340
341 if (attr.get_name () == "green") {
342 g = double.parse (attr.get_content ());
343 }
344
345 if (attr.get_name () == "blue") {
346 b = double.parse (attr.get_content ());
347 }
348
349 if (attr.get_name () == "alpha") {
350 a = double.parse (attr.get_content ());
351 }
352 }
353
354 colors.set (name, new Color (r, g, b, a));
355 }
356
357 public static void add_new_theme (SettingsDisplay d) {
358 TextListener listener;
359
360 listener = new TextListener (t_("New theme"), "", t_("Set"));
361
362 listener.signal_text_input.connect ((text) => {
363 if (text != "") {
364 current_theme = text + ".theme";
365 themes.add (current_theme);
366 }
367 });
368
369 listener.signal_submit.connect (() => {
370 TabContent.hide_text_input ();
371 write_theme ();
372 d.create_setting_items ();
373 });
374
375 TabContent.show_text_input (listener);
376 }
377 }
378
379 }
380