1c4670a76f3e04dd0297bd83d4915b8662149aa8
[fanfix.git] / src / jexer / bits / ColorTheme.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 Kevin Lamonte
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer.bits;
30
31 import java.io.BufferedReader;
32 import java.io.FileReader;
33 import java.io.FileWriter;
34 import java.io.IOException;
35 import java.io.Reader;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Set;
39 import java.util.SortedMap;
40 import java.util.StringTokenizer;
41 import java.util.TreeMap;
42
43 /**
44 * ColorTheme is a collection of colors keyed by string. A default theme is
45 * also provided that matches the blue-and-white theme used by Turbo Vision.
46 */
47 public class ColorTheme {
48
49 // ------------------------------------------------------------------------
50 // Variables --------------------------------------------------------------
51 // ------------------------------------------------------------------------
52
53 /**
54 * The current theme colors.
55 */
56 private SortedMap<String, CellAttributes> colors;
57
58 // ------------------------------------------------------------------------
59 // Constructors -----------------------------------------------------------
60 // ------------------------------------------------------------------------
61
62 /**
63 * Public constructor sets the theme to the default.
64 */
65 public ColorTheme() {
66 colors = new TreeMap<String, CellAttributes>();
67 setDefaultTheme();
68 }
69
70 // ------------------------------------------------------------------------
71 // ColorTheme -------------------------------------------------------------
72 // ------------------------------------------------------------------------
73
74 /**
75 * Retrieve the CellAttributes for a named theme color.
76 *
77 * @param name theme color name, e.g. "twindow.border"
78 * @return color associated with name, e.g. bold yellow on blue
79 */
80 public CellAttributes getColor(final String name) {
81 CellAttributes attr = (CellAttributes) colors.get(name);
82 return attr;
83 }
84
85 /**
86 * Retrieve all the names in the theme.
87 *
88 * @return a list of names
89 */
90 public List<String> getColorNames() {
91 Set<String> keys = colors.keySet();
92 List<String> names = new ArrayList<String>(keys.size());
93 names.addAll(keys);
94 return names;
95 }
96
97 /**
98 * Set the color for a named theme color.
99 *
100 * @param name theme color name, e.g. "twindow.border"
101 * @param color the new color to associate with name, e.g. bold yellow on
102 * blue
103 */
104 public void setColor(final String name, final CellAttributes color) {
105 colors.put(name, color);
106 }
107
108 /**
109 * Save the color theme mappings to an ASCII file.
110 *
111 * @param filename file to write to
112 * @throws IOException if the I/O fails
113 */
114 public void save(final String filename) throws IOException {
115 FileWriter file = new FileWriter(filename);
116 for (String key: colors.keySet()) {
117 CellAttributes color = getColor(key);
118 file.write(String.format("%s = %s\n", key, color));
119 }
120 file.close();
121 }
122
123 /**
124 * Read color theme mappings from an ASCII file.
125 *
126 * @param filename file to read from
127 * @throws IOException if the I/O fails
128 */
129 public void load(final String filename) throws IOException {
130 load(new FileReader(filename));
131 }
132
133 /**
134 * Set a color based on a text string. Color text string is of the form:
135 * <code>[ bold ] [ blink ] { foreground on background }</code>
136 *
137 * @param key the color key string
138 * @param text the text string
139 */
140 public void setColorFromString(final String key, final String text) {
141 boolean bold = false;
142 boolean blink = false;
143 String foreColor;
144 String backColor;
145 String token;
146
147 StringTokenizer tokenizer = new StringTokenizer(text);
148 token = tokenizer.nextToken();
149
150 if (token.toLowerCase().equals("rgb:")) {
151 // Foreground
152 int foreColorRGB = -1;
153 try {
154 foreColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
155 } catch (NumberFormatException e) {
156 e.printStackTrace();
157 }
158
159 // "on"
160 if (!tokenizer.nextToken().toLowerCase().equals("on")) {
161 // Invalid line.
162 return;
163 }
164
165 // Background
166 int backColorRGB = -1;
167 try {
168 backColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
169 } catch (NumberFormatException e) {
170 e.printStackTrace();
171 }
172
173 CellAttributes color = new CellAttributes();
174 color.setForeColorRGB(foreColorRGB);
175 color.setBackColorRGB(backColorRGB);
176 colors.put(key, color);
177 return;
178 }
179
180 while (token.equals("bold") || token.equals("blink")) {
181 if (token.equals("bold")) {
182 bold = true;
183 token = tokenizer.nextToken();
184 }
185 if (token.equals("blink")) {
186 blink = true;
187 token = tokenizer.nextToken();
188 }
189 }
190
191 // What's left is "blah on blah"
192 foreColor = token.toLowerCase();
193
194 if (!tokenizer.nextToken().toLowerCase().equals("on")) {
195 // Invalid line.
196 return;
197 }
198 backColor = tokenizer.nextToken().toLowerCase();
199
200 CellAttributes color = new CellAttributes();
201 if (bold) {
202 color.setBold(true);
203 }
204 if (blink) {
205 color.setBlink(true);
206 }
207 color.setForeColor(Color.getColor(foreColor));
208 color.setBackColor(Color.getColor(backColor));
209 colors.put(key, color);
210 }
211
212 /**
213 * Read color theme mappings from a Reader. The reader is closed at the
214 * end.
215 *
216 * @param reader the reader to read from
217 * @throws IOException if the I/O fails
218 */
219 public void load(final Reader reader) throws IOException {
220 BufferedReader bufferedReader = new BufferedReader(reader);
221 String line = bufferedReader.readLine();
222 for (; line != null; line = bufferedReader.readLine()) {
223 // Look for lines that resemble:
224 // "key = blah on blah"
225 // "key = bold blah on blah"
226 // "key = blink bold blah on blah"
227 // "key = bold blink blah on blah"
228 // "key = blink blah on blah"
229 if (line.indexOf('=') == -1) {
230 // Invalid line.
231 continue;
232 }
233 String key = line.substring(0, line.indexOf(':')).trim();
234 String text = line.substring(line.indexOf(':') + 1);
235 setColorFromString(key, text);
236 }
237 // All done.
238 bufferedReader.close();
239 }
240
241 /**
242 * Sets to defaults that resemble the Borland IDE colors.
243 */
244 public void setDefaultTheme() {
245 CellAttributes color;
246
247 // TWindow border
248 color = new CellAttributes();
249 color.setForeColor(Color.WHITE);
250 color.setBackColor(Color.BLUE);
251 color.setBold(true);
252 colors.put("twindow.border", color);
253
254 // TWindow background
255 color = new CellAttributes();
256 color.setForeColor(Color.YELLOW);
257 color.setBackColor(Color.BLUE);
258 color.setBold(true);
259 colors.put("twindow.background", color);
260
261 // TWindow border - inactive
262 color = new CellAttributes();
263 color.setForeColor(Color.BLACK);
264 color.setBackColor(Color.BLUE);
265 color.setBold(true);
266 colors.put("twindow.border.inactive", color);
267
268 // TWindow background - inactive
269 color = new CellAttributes();
270 color.setForeColor(Color.YELLOW);
271 color.setBackColor(Color.BLUE);
272 color.setBold(true);
273 colors.put("twindow.background.inactive", color);
274
275 // TWindow border - modal
276 color = new CellAttributes();
277 color.setForeColor(Color.WHITE);
278 color.setBackColor(Color.WHITE);
279 color.setBold(true);
280 colors.put("twindow.border.modal", color);
281
282 // TWindow background - modal
283 color = new CellAttributes();
284 color.setForeColor(Color.BLACK);
285 color.setBackColor(Color.WHITE);
286 color.setBold(false);
287 colors.put("twindow.background.modal", color);
288
289 // TWindow border - modal + inactive
290 color = new CellAttributes();
291 color.setForeColor(Color.BLACK);
292 color.setBackColor(Color.WHITE);
293 color.setBold(true);
294 colors.put("twindow.border.modal.inactive", color);
295
296 // TWindow background - modal + inactive
297 color = new CellAttributes();
298 color.setForeColor(Color.BLACK);
299 color.setBackColor(Color.WHITE);
300 color.setBold(false);
301 colors.put("twindow.background.modal.inactive", color);
302
303 // TWindow border - during window movement - modal
304 color = new CellAttributes();
305 color.setForeColor(Color.GREEN);
306 color.setBackColor(Color.WHITE);
307 color.setBold(true);
308 colors.put("twindow.border.modal.windowmove", color);
309
310 // TWindow border - during window movement
311 color = new CellAttributes();
312 color.setForeColor(Color.GREEN);
313 color.setBackColor(Color.BLUE);
314 color.setBold(true);
315 colors.put("twindow.border.windowmove", color);
316
317 // TWindow background - during window movement
318 color = new CellAttributes();
319 color.setForeColor(Color.YELLOW);
320 color.setBackColor(Color.BLUE);
321 color.setBold(false);
322 colors.put("twindow.background.windowmove", color);
323
324 // TDesktop background
325 color = new CellAttributes();
326 color.setForeColor(Color.BLUE);
327 color.setBackColor(Color.WHITE);
328 color.setBold(false);
329 colors.put("tdesktop.background", color);
330
331 // TButton text
332 color = new CellAttributes();
333 color.setForeColor(Color.BLACK);
334 color.setBackColor(Color.GREEN);
335 color.setBold(false);
336 colors.put("tbutton.inactive", color);
337 color = new CellAttributes();
338 color.setForeColor(Color.CYAN);
339 color.setBackColor(Color.GREEN);
340 color.setBold(true);
341 colors.put("tbutton.active", color);
342 color = new CellAttributes();
343 color.setForeColor(Color.BLACK);
344 color.setBackColor(Color.WHITE);
345 color.setBold(true);
346 colors.put("tbutton.disabled", color);
347 color = new CellAttributes();
348 color.setForeColor(Color.YELLOW);
349 color.setBackColor(Color.GREEN);
350 color.setBold(true);
351 colors.put("tbutton.mnemonic", color);
352 color = new CellAttributes();
353 color.setForeColor(Color.YELLOW);
354 color.setBackColor(Color.GREEN);
355 color.setBold(true);
356 colors.put("tbutton.mnemonic.highlighted", color);
357
358 // TLabel text
359 color = new CellAttributes();
360 color.setForeColor(Color.WHITE);
361 color.setBackColor(Color.BLUE);
362 color.setBold(true);
363 colors.put("tlabel", color);
364
365 // TText text
366 color = new CellAttributes();
367 color.setForeColor(Color.WHITE);
368 color.setBackColor(Color.BLUE);
369 color.setBold(false);
370 colors.put("ttext", color);
371
372 // TField text
373 color = new CellAttributes();
374 color.setForeColor(Color.WHITE);
375 color.setBackColor(Color.BLUE);
376 color.setBold(false);
377 colors.put("tfield.inactive", color);
378 color = new CellAttributes();
379 color.setForeColor(Color.YELLOW);
380 color.setBackColor(Color.BLACK);
381 color.setBold(true);
382 colors.put("tfield.active", color);
383
384 // TCheckBox
385 color = new CellAttributes();
386 color.setForeColor(Color.WHITE);
387 color.setBackColor(Color.BLUE);
388 color.setBold(false);
389 colors.put("tcheckbox.inactive", color);
390 color = new CellAttributes();
391 color.setForeColor(Color.YELLOW);
392 color.setBackColor(Color.BLACK);
393 color.setBold(true);
394 colors.put("tcheckbox.active", color);
395
396 // TComboBox
397 color = new CellAttributes();
398 color.setForeColor(Color.BLACK);
399 color.setBackColor(Color.WHITE);
400 color.setBold(false);
401 colors.put("tcombobox.inactive", color);
402 color = new CellAttributes();
403 color.setForeColor(Color.BLUE);
404 color.setBackColor(Color.CYAN);
405 color.setBold(false);
406 colors.put("tcombobox.active", color);
407
408 // TSpinner
409 color = new CellAttributes();
410 color.setForeColor(Color.BLACK);
411 color.setBackColor(Color.WHITE);
412 color.setBold(false);
413 colors.put("tspinner.inactive", color);
414 color = new CellAttributes();
415 color.setForeColor(Color.BLUE);
416 color.setBackColor(Color.CYAN);
417 color.setBold(false);
418 colors.put("tspinner.active", color);
419
420 // TCalendar
421 color = new CellAttributes();
422 color.setForeColor(Color.WHITE);
423 color.setBackColor(Color.BLUE);
424 color.setBold(false);
425 colors.put("tcalendar.background", color);
426 color = new CellAttributes();
427 color.setForeColor(Color.WHITE);
428 color.setBackColor(Color.BLUE);
429 color.setBold(false);
430 colors.put("tcalendar.day", color);
431 color = new CellAttributes();
432 color.setForeColor(Color.RED);
433 color.setBackColor(Color.WHITE);
434 color.setBold(false);
435 colors.put("tcalendar.day.selected", color);
436 color = new CellAttributes();
437 color.setForeColor(Color.BLUE);
438 color.setBackColor(Color.CYAN);
439 color.setBold(false);
440 colors.put("tcalendar.arrow", color);
441 color = new CellAttributes();
442 color.setForeColor(Color.WHITE);
443 color.setBackColor(Color.BLUE);
444 color.setBold(true);
445 colors.put("tcalendar.title", color);
446
447 // TRadioButton
448 color = new CellAttributes();
449 color.setForeColor(Color.WHITE);
450 color.setBackColor(Color.BLUE);
451 color.setBold(false);
452 colors.put("tradiobutton.inactive", color);
453 color = new CellAttributes();
454 color.setForeColor(Color.YELLOW);
455 color.setBackColor(Color.BLACK);
456 color.setBold(true);
457 colors.put("tradiobutton.active", color);
458
459 // TRadioGroup
460 color = new CellAttributes();
461 color.setForeColor(Color.WHITE);
462 color.setBackColor(Color.BLUE);
463 color.setBold(false);
464 colors.put("tradiogroup.inactive", color);
465 color = new CellAttributes();
466 color.setForeColor(Color.YELLOW);
467 color.setBackColor(Color.BLUE);
468 color.setBold(true);
469 colors.put("tradiogroup.active", color);
470
471 // TMenu
472 color = new CellAttributes();
473 color.setForeColor(Color.BLACK);
474 color.setBackColor(Color.WHITE);
475 color.setBold(false);
476 colors.put("tmenu", color);
477 color = new CellAttributes();
478 color.setForeColor(Color.BLACK);
479 color.setBackColor(Color.GREEN);
480 color.setBold(false);
481 colors.put("tmenu.highlighted", color);
482 color = new CellAttributes();
483 color.setForeColor(Color.RED);
484 color.setBackColor(Color.WHITE);
485 color.setBold(false);
486 colors.put("tmenu.mnemonic", color);
487 color = new CellAttributes();
488 color.setForeColor(Color.RED);
489 color.setBackColor(Color.GREEN);
490 color.setBold(false);
491 colors.put("tmenu.mnemonic.highlighted", color);
492 color = new CellAttributes();
493 color.setForeColor(Color.BLACK);
494 color.setBackColor(Color.WHITE);
495 color.setBold(true);
496 colors.put("tmenu.disabled", color);
497
498 // TProgressBar
499 color = new CellAttributes();
500 color.setForeColor(Color.BLUE);
501 color.setBackColor(Color.BLUE);
502 color.setBold(true);
503 colors.put("tprogressbar.complete", color);
504 color = new CellAttributes();
505 color.setForeColor(Color.WHITE);
506 color.setBackColor(Color.BLUE);
507 color.setBold(false);
508 colors.put("tprogressbar.incomplete", color);
509
510 // THScroller / TVScroller
511 color = new CellAttributes();
512 color.setForeColor(Color.CYAN);
513 color.setBackColor(Color.BLUE);
514 color.setBold(false);
515 colors.put("tscroller.bar", color);
516 color = new CellAttributes();
517 color.setForeColor(Color.BLUE);
518 color.setBackColor(Color.CYAN);
519 color.setBold(false);
520 colors.put("tscroller.arrows", color);
521
522 // TTreeView
523 color = new CellAttributes();
524 color.setForeColor(Color.WHITE);
525 color.setBackColor(Color.BLUE);
526 color.setBold(false);
527 colors.put("ttreeview", color);
528 color = new CellAttributes();
529 color.setForeColor(Color.GREEN);
530 color.setBackColor(Color.BLUE);
531 color.setBold(true);
532 colors.put("ttreeview.expandbutton", color);
533 color = new CellAttributes();
534 color.setForeColor(Color.BLACK);
535 color.setBackColor(Color.CYAN);
536 color.setBold(false);
537 colors.put("ttreeview.selected", color);
538 color = new CellAttributes();
539 color.setForeColor(Color.RED);
540 color.setBackColor(Color.BLUE);
541 color.setBold(false);
542 colors.put("ttreeview.unreadable", color);
543 color = new CellAttributes();
544 // color.setForeColor(Color.BLACK);
545 // color.setBackColor(Color.BLUE);
546 // color.setBold(true);
547 color.setForeColor(Color.WHITE);
548 color.setBackColor(Color.BLUE);
549 color.setBold(false);
550 colors.put("ttreeview.inactive", color);
551 color = new CellAttributes();
552 color.setForeColor(Color.BLACK);
553 color.setBackColor(Color.WHITE);
554 color.setBold(false);
555 colors.put("ttreeview.selected.inactive", color);
556
557 // TList
558 color = new CellAttributes();
559 color.setForeColor(Color.WHITE);
560 color.setBackColor(Color.BLUE);
561 color.setBold(false);
562 colors.put("tlist", color);
563 color = new CellAttributes();
564 color.setForeColor(Color.BLACK);
565 color.setBackColor(Color.CYAN);
566 color.setBold(false);
567 colors.put("tlist.selected", color);
568 color = new CellAttributes();
569 color.setForeColor(Color.BLACK);
570 color.setBackColor(Color.CYAN);
571 color.setBold(false);
572 colors.put("tlist.unreadable", color);
573 color = new CellAttributes();
574 // color.setForeColor(Color.BLACK);
575 // color.setBackColor(Color.BLUE);
576 // color.setBold(true);
577 color.setForeColor(Color.WHITE);
578 color.setBackColor(Color.BLUE);
579 color.setBold(false);
580 colors.put("tlist.inactive", color);
581 color = new CellAttributes();
582 color.setForeColor(Color.BLACK);
583 color.setBackColor(Color.WHITE);
584 color.setBold(false);
585 colors.put("tlist.selected.inactive", color);
586
587 // TStatusBar
588 color = new CellAttributes();
589 color.setForeColor(Color.BLACK);
590 color.setBackColor(Color.WHITE);
591 color.setBold(false);
592 colors.put("tstatusbar.text", color);
593 color = new CellAttributes();
594 color.setForeColor(Color.RED);
595 color.setBackColor(Color.WHITE);
596 color.setBold(false);
597 colors.put("tstatusbar.button", color);
598 color = new CellAttributes();
599 color.setForeColor(Color.WHITE);
600 color.setBackColor(Color.BLUE);
601 color.setBold(false);
602 colors.put("tstatusbar.selected", color);
603
604 // TEditor
605 color = new CellAttributes();
606 color.setForeColor(Color.WHITE);
607 color.setBackColor(Color.BLUE);
608 color.setBold(false);
609 colors.put("teditor", color);
610
611 }
612
613 /**
614 * Make human-readable description of this Cell.
615 *
616 * @return displayable String
617 */
618 @Override
619 public String toString() {
620 return colors.toString();
621 }
622
623 }