Add 'src/jexer/' from commit 'cf01c92f5809a0732409e280fb0f32f27393618d'
[fanfix.git] / src / jexer / bits / ColorTheme.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 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 = 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 // Default to white on black
157 foreColorRGB = 0xFFFFFF;
158 }
159
160 // "on"
161 if (!tokenizer.nextToken().toLowerCase().equals("on")) {
162 // Invalid line.
163 return;
164 }
165
166 // Background
167 int backColorRGB = -1;
168 try {
169 backColorRGB = Integer.parseInt(tokenizer.nextToken(), 16);
170 } catch (NumberFormatException e) {
171 backColorRGB = 0;
172 }
173
174 CellAttributes color = new CellAttributes();
175 color.setForeColorRGB(foreColorRGB);
176 color.setBackColorRGB(backColorRGB);
177 colors.put(key, color);
178 return;
179 }
180
181 while (token.equals("bold") || token.equals("blink")) {
182 if (token.equals("bold")) {
183 bold = true;
184 token = tokenizer.nextToken();
185 }
186 if (token.equals("blink")) {
187 blink = true;
188 token = tokenizer.nextToken();
189 }
190 }
191
192 // What's left is "blah on blah"
193 foreColor = token.toLowerCase();
194
195 if (!tokenizer.nextToken().toLowerCase().equals("on")) {
196 // Invalid line.
197 return;
198 }
199 backColor = tokenizer.nextToken().toLowerCase();
200
201 CellAttributes color = new CellAttributes();
202 if (bold) {
203 color.setBold(true);
204 }
205 if (blink) {
206 color.setBlink(true);
207 }
208 color.setForeColor(Color.getColor(foreColor));
209 color.setBackColor(Color.getColor(backColor));
210 colors.put(key, color);
211 }
212
213 /**
214 * Read color theme mappings from a Reader. The reader is closed at the
215 * end.
216 *
217 * @param reader the reader to read from
218 * @throws IOException if the I/O fails
219 */
220 public void load(final Reader reader) throws IOException {
221 BufferedReader bufferedReader = new BufferedReader(reader);
222 String line = bufferedReader.readLine();
223 for (; line != null; line = bufferedReader.readLine()) {
224 // Look for lines that resemble:
225 // "key = blah on blah"
226 // "key = bold blah on blah"
227 // "key = blink bold blah on blah"
228 // "key = bold blink blah on blah"
229 // "key = blink blah on blah"
230 if (line.indexOf('=') == -1) {
231 // Invalid line.
232 continue;
233 }
234 String key = line.substring(0, line.indexOf(':')).trim();
235 String text = line.substring(line.indexOf(':') + 1);
236 setColorFromString(key, text);
237 }
238 // All done.
239 bufferedReader.close();
240 }
241
242 /**
243 * Sets to defaults that resemble the Borland IDE colors.
244 */
245 public void setDefaultTheme() {
246 CellAttributes color;
247
248 // TWindow border
249 color = new CellAttributes();
250 color.setForeColor(Color.WHITE);
251 color.setBackColor(Color.BLUE);
252 color.setBold(true);
253 colors.put("twindow.border", color);
254
255 // TWindow background
256 color = new CellAttributes();
257 color.setForeColor(Color.YELLOW);
258 color.setBackColor(Color.BLUE);
259 color.setBold(true);
260 colors.put("twindow.background", color);
261
262 // TWindow border - inactive
263 color = new CellAttributes();
264 color.setForeColor(Color.BLACK);
265 color.setBackColor(Color.BLUE);
266 color.setBold(true);
267 colors.put("twindow.border.inactive", color);
268
269 // TWindow background - inactive
270 color = new CellAttributes();
271 color.setForeColor(Color.YELLOW);
272 color.setBackColor(Color.BLUE);
273 color.setBold(true);
274 colors.put("twindow.background.inactive", color);
275
276 // TWindow border - modal
277 color = new CellAttributes();
278 color.setForeColor(Color.WHITE);
279 color.setBackColor(Color.WHITE);
280 color.setBold(true);
281 colors.put("twindow.border.modal", color);
282
283 // TWindow background - modal
284 color = new CellAttributes();
285 color.setForeColor(Color.BLACK);
286 color.setBackColor(Color.WHITE);
287 color.setBold(false);
288 colors.put("twindow.background.modal", color);
289
290 // TWindow border - modal + inactive
291 color = new CellAttributes();
292 color.setForeColor(Color.BLACK);
293 color.setBackColor(Color.WHITE);
294 color.setBold(true);
295 colors.put("twindow.border.modal.inactive", color);
296
297 // TWindow background - modal + inactive
298 color = new CellAttributes();
299 color.setForeColor(Color.BLACK);
300 color.setBackColor(Color.WHITE);
301 color.setBold(false);
302 colors.put("twindow.background.modal.inactive", color);
303
304 // TWindow border - during window movement - modal
305 color = new CellAttributes();
306 color.setForeColor(Color.GREEN);
307 color.setBackColor(Color.WHITE);
308 color.setBold(true);
309 colors.put("twindow.border.modal.windowmove", color);
310
311 // TWindow border - during window movement
312 color = new CellAttributes();
313 color.setForeColor(Color.GREEN);
314 color.setBackColor(Color.BLUE);
315 color.setBold(true);
316 colors.put("twindow.border.windowmove", color);
317
318 // TWindow background - during window movement
319 color = new CellAttributes();
320 color.setForeColor(Color.YELLOW);
321 color.setBackColor(Color.BLUE);
322 color.setBold(false);
323 colors.put("twindow.background.windowmove", color);
324
325 // TDesktop background
326 color = new CellAttributes();
327 color.setForeColor(Color.BLUE);
328 color.setBackColor(Color.WHITE);
329 color.setBold(false);
330 colors.put("tdesktop.background", color);
331
332 // TButton text
333 color = new CellAttributes();
334 color.setForeColor(Color.BLACK);
335 color.setBackColor(Color.GREEN);
336 color.setBold(false);
337 colors.put("tbutton.inactive", color);
338 color = new CellAttributes();
339 color.setForeColor(Color.CYAN);
340 color.setBackColor(Color.GREEN);
341 color.setBold(true);
342 colors.put("tbutton.active", color);
343 color = new CellAttributes();
344 color.setForeColor(Color.BLACK);
345 color.setBackColor(Color.WHITE);
346 color.setBold(true);
347 colors.put("tbutton.disabled", color);
348 color = new CellAttributes();
349 color.setForeColor(Color.YELLOW);
350 color.setBackColor(Color.GREEN);
351 color.setBold(true);
352 colors.put("tbutton.mnemonic", color);
353 color = new CellAttributes();
354 color.setForeColor(Color.YELLOW);
355 color.setBackColor(Color.GREEN);
356 color.setBold(true);
357 colors.put("tbutton.mnemonic.highlighted", color);
358
359 // TLabel text
360 color = new CellAttributes();
361 color.setForeColor(Color.WHITE);
362 color.setBackColor(Color.BLUE);
363 color.setBold(true);
364 colors.put("tlabel", color);
365 color = new CellAttributes();
366 color.setForeColor(Color.YELLOW);
367 color.setBackColor(Color.BLUE);
368 color.setBold(true);
369 colors.put("tlabel.mnemonic", color);
370
371 // TText text
372 color = new CellAttributes();
373 color.setForeColor(Color.WHITE);
374 color.setBackColor(Color.BLUE);
375 color.setBold(false);
376 colors.put("ttext", color);
377
378 // TField text
379 color = new CellAttributes();
380 color.setForeColor(Color.BLACK);
381 color.setBackColor(Color.WHITE);
382 color.setBold(false);
383 colors.put("tfield.inactive", color);
384 color = new CellAttributes();
385 color.setForeColor(Color.BLACK);
386 color.setBackColor(Color.CYAN);
387 color.setBold(false);
388 colors.put("tfield.active", color);
389
390 // TCheckBox
391 color = new CellAttributes();
392 color.setForeColor(Color.WHITE);
393 color.setBackColor(Color.BLUE);
394 color.setBold(false);
395 colors.put("tcheckbox.inactive", color);
396 color = new CellAttributes();
397 color.setForeColor(Color.YELLOW);
398 color.setBackColor(Color.BLACK);
399 color.setBold(true);
400 colors.put("tcheckbox.active", color);
401 color = new CellAttributes();
402 color.setForeColor(Color.YELLOW);
403 color.setBackColor(Color.BLUE);
404 color.setBold(true);
405 colors.put("tcheckbox.mnemonic", color);
406 color = new CellAttributes();
407 color.setForeColor(Color.RED);
408 color.setBackColor(Color.BLACK);
409 color.setBold(true);
410 colors.put("tcheckbox.mnemonic.highlighted", color);
411
412 // TComboBox
413 color = new CellAttributes();
414 color.setForeColor(Color.BLACK);
415 color.setBackColor(Color.WHITE);
416 color.setBold(false);
417 colors.put("tcombobox.inactive", color);
418 color = new CellAttributes();
419 color.setForeColor(Color.BLUE);
420 color.setBackColor(Color.CYAN);
421 color.setBold(false);
422 colors.put("tcombobox.active", color);
423
424 // TSpinner
425 color = new CellAttributes();
426 color.setForeColor(Color.BLACK);
427 color.setBackColor(Color.WHITE);
428 color.setBold(false);
429 colors.put("tspinner.inactive", color);
430 color = new CellAttributes();
431 color.setForeColor(Color.BLUE);
432 color.setBackColor(Color.CYAN);
433 color.setBold(false);
434 colors.put("tspinner.active", color);
435
436 // TCalendar
437 color = new CellAttributes();
438 color.setForeColor(Color.WHITE);
439 color.setBackColor(Color.BLUE);
440 color.setBold(false);
441 colors.put("tcalendar.background", color);
442 color = new CellAttributes();
443 color.setForeColor(Color.WHITE);
444 color.setBackColor(Color.BLUE);
445 color.setBold(false);
446 colors.put("tcalendar.day", color);
447 color = new CellAttributes();
448 color.setForeColor(Color.RED);
449 color.setBackColor(Color.WHITE);
450 color.setBold(false);
451 colors.put("tcalendar.day.selected", color);
452 color = new CellAttributes();
453 color.setForeColor(Color.BLUE);
454 color.setBackColor(Color.CYAN);
455 color.setBold(false);
456 colors.put("tcalendar.arrow", color);
457 color = new CellAttributes();
458 color.setForeColor(Color.WHITE);
459 color.setBackColor(Color.BLUE);
460 color.setBold(true);
461 colors.put("tcalendar.title", color);
462
463 // TRadioButton
464 color = new CellAttributes();
465 color.setForeColor(Color.WHITE);
466 color.setBackColor(Color.BLUE);
467 color.setBold(false);
468 colors.put("tradiobutton.inactive", color);
469 color = new CellAttributes();
470 color.setForeColor(Color.YELLOW);
471 color.setBackColor(Color.BLACK);
472 color.setBold(true);
473 colors.put("tradiobutton.active", color);
474 color = new CellAttributes();
475 color.setForeColor(Color.YELLOW);
476 color.setBackColor(Color.BLUE);
477 color.setBold(true);
478 colors.put("tradiobutton.mnemonic", color);
479 color = new CellAttributes();
480 color.setForeColor(Color.RED);
481 color.setBackColor(Color.BLACK);
482 color.setBold(true);
483 colors.put("tradiobutton.mnemonic.highlighted", color);
484
485 // TRadioGroup
486 color = new CellAttributes();
487 color.setForeColor(Color.WHITE);
488 color.setBackColor(Color.BLUE);
489 color.setBold(false);
490 colors.put("tradiogroup.inactive", color);
491 color = new CellAttributes();
492 color.setForeColor(Color.YELLOW);
493 color.setBackColor(Color.BLUE);
494 color.setBold(true);
495 colors.put("tradiogroup.active", color);
496
497 // TMenu
498 color = new CellAttributes();
499 color.setForeColor(Color.BLACK);
500 color.setBackColor(Color.WHITE);
501 color.setBold(false);
502 colors.put("tmenu", color);
503 color = new CellAttributes();
504 color.setForeColor(Color.BLACK);
505 color.setBackColor(Color.GREEN);
506 color.setBold(false);
507 colors.put("tmenu.highlighted", color);
508 color = new CellAttributes();
509 color.setForeColor(Color.RED);
510 color.setBackColor(Color.WHITE);
511 color.setBold(false);
512 colors.put("tmenu.mnemonic", color);
513 color = new CellAttributes();
514 color.setForeColor(Color.RED);
515 color.setBackColor(Color.GREEN);
516 color.setBold(false);
517 colors.put("tmenu.mnemonic.highlighted", color);
518 color = new CellAttributes();
519 color.setForeColor(Color.BLACK);
520 color.setBackColor(Color.WHITE);
521 color.setBold(true);
522 colors.put("tmenu.disabled", color);
523
524 // TProgressBar
525 color = new CellAttributes();
526 color.setForeColor(Color.BLUE);
527 color.setBackColor(Color.BLUE);
528 color.setBold(true);
529 colors.put("tprogressbar.complete", color);
530 color = new CellAttributes();
531 color.setForeColor(Color.WHITE);
532 color.setBackColor(Color.BLUE);
533 color.setBold(false);
534 colors.put("tprogressbar.incomplete", color);
535
536 // THScroller / TVScroller
537 color = new CellAttributes();
538 color.setForeColor(Color.CYAN);
539 color.setBackColor(Color.BLUE);
540 color.setBold(false);
541 colors.put("tscroller.bar", color);
542 color = new CellAttributes();
543 color.setForeColor(Color.BLUE);
544 color.setBackColor(Color.CYAN);
545 color.setBold(false);
546 colors.put("tscroller.arrows", color);
547
548 // TTreeView
549 color = new CellAttributes();
550 color.setForeColor(Color.WHITE);
551 color.setBackColor(Color.BLUE);
552 color.setBold(false);
553 colors.put("ttreeview", color);
554 color = new CellAttributes();
555 color.setForeColor(Color.GREEN);
556 color.setBackColor(Color.BLUE);
557 color.setBold(true);
558 colors.put("ttreeview.expandbutton", color);
559 color = new CellAttributes();
560 color.setForeColor(Color.BLACK);
561 color.setBackColor(Color.CYAN);
562 color.setBold(false);
563 colors.put("ttreeview.selected", color);
564 color = new CellAttributes();
565 color.setForeColor(Color.RED);
566 color.setBackColor(Color.BLUE);
567 color.setBold(false);
568 colors.put("ttreeview.unreadable", color);
569 color = new CellAttributes();
570 // color.setForeColor(Color.BLACK);
571 // color.setBackColor(Color.BLUE);
572 // color.setBold(true);
573 color.setForeColor(Color.WHITE);
574 color.setBackColor(Color.BLUE);
575 color.setBold(false);
576 colors.put("ttreeview.inactive", color);
577 color = new CellAttributes();
578 color.setForeColor(Color.BLACK);
579 color.setBackColor(Color.WHITE);
580 color.setBold(false);
581 colors.put("ttreeview.selected.inactive", color);
582
583 // TList
584 color = new CellAttributes();
585 color.setForeColor(Color.WHITE);
586 color.setBackColor(Color.BLUE);
587 color.setBold(false);
588 colors.put("tlist", color);
589 color = new CellAttributes();
590 color.setForeColor(Color.BLACK);
591 color.setBackColor(Color.CYAN);
592 color.setBold(false);
593 colors.put("tlist.selected", color);
594 color = new CellAttributes();
595 color.setForeColor(Color.BLACK);
596 color.setBackColor(Color.CYAN);
597 color.setBold(false);
598 colors.put("tlist.unreadable", color);
599 color = new CellAttributes();
600 // color.setForeColor(Color.BLACK);
601 // color.setBackColor(Color.BLUE);
602 // color.setBold(true);
603 color.setForeColor(Color.WHITE);
604 color.setBackColor(Color.BLUE);
605 color.setBold(false);
606 colors.put("tlist.inactive", color);
607 color = new CellAttributes();
608 color.setForeColor(Color.BLACK);
609 color.setBackColor(Color.WHITE);
610 color.setBold(false);
611 colors.put("tlist.selected.inactive", color);
612
613 // TStatusBar
614 color = new CellAttributes();
615 color.setForeColor(Color.BLACK);
616 color.setBackColor(Color.WHITE);
617 color.setBold(false);
618 colors.put("tstatusbar.text", color);
619 color = new CellAttributes();
620 color.setForeColor(Color.RED);
621 color.setBackColor(Color.WHITE);
622 color.setBold(false);
623 colors.put("tstatusbar.button", color);
624 color = new CellAttributes();
625 color.setForeColor(Color.WHITE);
626 color.setBackColor(Color.BLUE);
627 color.setBold(false);
628 colors.put("tstatusbar.selected", color);
629
630 // TEditor
631 color = new CellAttributes();
632 color.setForeColor(Color.WHITE);
633 color.setBackColor(Color.BLUE);
634 color.setBold(false);
635 colors.put("teditor", color);
636
637 // TTable
638 color = new CellAttributes();
639 color.setForeColor(Color.WHITE);
640 color.setBackColor(Color.BLUE);
641 color.setBold(false);
642 colors.put("ttable.inactive", color);
643 color = new CellAttributes();
644 color.setForeColor(Color.BLACK);
645 color.setBackColor(Color.CYAN);
646 color.setBold(false);
647 colors.put("ttable.active", color);
648 color = new CellAttributes();
649 color.setForeColor(Color.YELLOW);
650 color.setBackColor(Color.CYAN);
651 color.setBold(true);
652 colors.put("ttable.selected", color);
653 color = new CellAttributes();
654 color.setForeColor(Color.BLACK);
655 color.setBackColor(Color.WHITE);
656 color.setBold(false);
657 colors.put("ttable.label", color);
658 color = new CellAttributes();
659 color.setForeColor(Color.BLUE);
660 color.setBackColor(Color.WHITE);
661 color.setBold(false);
662 colors.put("ttable.label.selected", color);
663 color = new CellAttributes();
664 color.setForeColor(Color.WHITE);
665 color.setBackColor(Color.BLUE);
666 color.setBold(false);
667 colors.put("ttable.border", color);
668
669 // TSplitPane
670 color = new CellAttributes();
671 color.setForeColor(Color.WHITE);
672 color.setBackColor(Color.BLUE);
673 color.setBold(false);
674 colors.put("tsplitpane", color);
675
676 }
677
678 /**
679 * Make human-readable description of this Cell.
680 *
681 * @return displayable String
682 */
683 @Override
684 public String toString() {
685 return colors.toString();
686 }
687
688 }