2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
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
;
39 import java
.util
.SortedMap
;
40 import java
.util
.StringTokenizer
;
41 import java
.util
.TreeMap
;
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.
47 public class ColorTheme
{
49 // ------------------------------------------------------------------------
50 // Variables --------------------------------------------------------------
51 // ------------------------------------------------------------------------
54 * The current theme colors.
56 private SortedMap
<String
, CellAttributes
> colors
;
58 // ------------------------------------------------------------------------
59 // Constructors -----------------------------------------------------------
60 // ------------------------------------------------------------------------
63 * Public constructor sets the theme to the default.
66 colors
= new TreeMap
<String
, CellAttributes
>();
70 // ------------------------------------------------------------------------
71 // ColorTheme -------------------------------------------------------------
72 // ------------------------------------------------------------------------
75 * Retrieve the CellAttributes for a named theme color.
77 * @param name theme color name, e.g. "twindow.border"
78 * @return color associated with name, e.g. bold yellow on blue
80 public CellAttributes
getColor(final String name
) {
81 CellAttributes attr
= colors
.get(name
);
86 * Retrieve all the names in the theme.
88 * @return a list of names
90 public List
<String
> getColorNames() {
91 Set
<String
> keys
= colors
.keySet();
92 List
<String
> names
= new ArrayList
<String
>(keys
.size());
98 * Set the color for a named theme color.
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
104 public void setColor(final String name
, final CellAttributes color
) {
105 colors
.put(name
, color
);
109 * Save the color theme mappings to an ASCII file.
111 * @param filename file to write to
112 * @throws IOException if the I/O fails
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
));
124 * Read color theme mappings from an ASCII file.
126 * @param filename file to read from
127 * @throws IOException if the I/O fails
129 public void load(final String filename
) throws IOException
{
130 load(new FileReader(filename
));
134 * Set a color based on a text string. Color text string is of the form:
135 * <code>[ bold ] [ blink ] { foreground on background }</code>
137 * @param key the color key string
138 * @param text the text string
140 public void setColorFromString(final String key
, final String text
) {
141 boolean bold
= false;
142 boolean blink
= false;
147 StringTokenizer tokenizer
= new StringTokenizer(text
);
148 token
= tokenizer
.nextToken();
150 if (token
.toLowerCase().equals("rgb:")) {
152 int foreColorRGB
= -1;
154 foreColorRGB
= Integer
.parseInt(tokenizer
.nextToken(), 16);
155 } catch (NumberFormatException e
) {
156 // Default to white on black
157 foreColorRGB
= 0xFFFFFF;
161 if (!tokenizer
.nextToken().toLowerCase().equals("on")) {
167 int backColorRGB
= -1;
169 backColorRGB
= Integer
.parseInt(tokenizer
.nextToken(), 16);
170 } catch (NumberFormatException e
) {
174 CellAttributes color
= new CellAttributes();
175 color
.setForeColorRGB(foreColorRGB
);
176 color
.setBackColorRGB(backColorRGB
);
177 colors
.put(key
, color
);
181 while (token
.equals("bold") || token
.equals("blink")) {
182 if (token
.equals("bold")) {
184 token
= tokenizer
.nextToken();
186 if (token
.equals("blink")) {
188 token
= tokenizer
.nextToken();
192 // What's left is "blah on blah"
193 foreColor
= token
.toLowerCase();
195 if (!tokenizer
.nextToken().toLowerCase().equals("on")) {
199 backColor
= tokenizer
.nextToken().toLowerCase();
201 CellAttributes color
= new CellAttributes();
206 color
.setBlink(true);
208 color
.setForeColor(Color
.getColor(foreColor
));
209 color
.setBackColor(Color
.getColor(backColor
));
210 colors
.put(key
, color
);
214 * Read color theme mappings from a Reader. The reader is closed at the
217 * @param reader the reader to read from
218 * @throws IOException if the I/O fails
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) {
234 String key
= line
.substring(0, line
.indexOf(':')).trim();
235 String text
= line
.substring(line
.indexOf(':') + 1);
236 setColorFromString(key
, text
);
239 bufferedReader
.close();
243 * Sets to defaults that resemble the Borland IDE colors.
245 public void setDefaultTheme() {
246 CellAttributes color
;
249 color
= new CellAttributes();
250 color
.setForeColor(Color
.WHITE
);
251 color
.setBackColor(Color
.BLUE
);
253 colors
.put("twindow.border", color
);
255 // TWindow background
256 color
= new CellAttributes();
257 color
.setForeColor(Color
.YELLOW
);
258 color
.setBackColor(Color
.BLUE
);
260 colors
.put("twindow.background", color
);
262 // TWindow border - inactive
263 color
= new CellAttributes();
264 color
.setForeColor(Color
.BLACK
);
265 color
.setBackColor(Color
.BLUE
);
267 colors
.put("twindow.border.inactive", color
);
269 // TWindow background - inactive
270 color
= new CellAttributes();
271 color
.setForeColor(Color
.YELLOW
);
272 color
.setBackColor(Color
.BLUE
);
274 colors
.put("twindow.background.inactive", color
);
276 // TWindow border - modal
277 color
= new CellAttributes();
278 color
.setForeColor(Color
.WHITE
);
279 color
.setBackColor(Color
.WHITE
);
281 colors
.put("twindow.border.modal", color
);
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
);
290 // TWindow border - modal + inactive
291 color
= new CellAttributes();
292 color
.setForeColor(Color
.BLACK
);
293 color
.setBackColor(Color
.WHITE
);
295 colors
.put("twindow.border.modal.inactive", color
);
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
);
304 // TWindow border - during window movement - modal
305 color
= new CellAttributes();
306 color
.setForeColor(Color
.GREEN
);
307 color
.setBackColor(Color
.WHITE
);
309 colors
.put("twindow.border.modal.windowmove", color
);
311 // TWindow border - during window movement
312 color
= new CellAttributes();
313 color
.setForeColor(Color
.GREEN
);
314 color
.setBackColor(Color
.BLUE
);
316 colors
.put("twindow.border.windowmove", color
);
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
);
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
);
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
);
342 colors
.put("tbutton.active", color
);
343 color
= new CellAttributes();
344 color
.setForeColor(Color
.BLACK
);
345 color
.setBackColor(Color
.WHITE
);
347 colors
.put("tbutton.disabled", color
);
348 color
= new CellAttributes();
349 color
.setForeColor(Color
.YELLOW
);
350 color
.setBackColor(Color
.GREEN
);
352 colors
.put("tbutton.mnemonic", color
);
353 color
= new CellAttributes();
354 color
.setForeColor(Color
.YELLOW
);
355 color
.setBackColor(Color
.GREEN
);
357 colors
.put("tbutton.mnemonic.highlighted", color
);
360 color
= new CellAttributes();
361 color
.setForeColor(Color
.WHITE
);
362 color
.setBackColor(Color
.BLUE
);
364 colors
.put("tlabel", color
);
365 color
= new CellAttributes();
366 color
.setForeColor(Color
.YELLOW
);
367 color
.setBackColor(Color
.BLUE
);
369 colors
.put("tlabel.mnemonic", color
);
372 color
= new CellAttributes();
373 color
.setForeColor(Color
.WHITE
);
374 color
.setBackColor(Color
.BLUE
);
375 color
.setBold(false);
376 colors
.put("ttext", color
);
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
);
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
);
400 colors
.put("tcheckbox.active", color
);
401 color
= new CellAttributes();
402 color
.setForeColor(Color
.YELLOW
);
403 color
.setBackColor(Color
.BLUE
);
405 colors
.put("tcheckbox.mnemonic", color
);
406 color
= new CellAttributes();
407 color
.setForeColor(Color
.RED
);
408 color
.setBackColor(Color
.BLACK
);
410 colors
.put("tcheckbox.mnemonic.highlighted", color
);
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
);
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
);
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
);
461 colors
.put("tcalendar.title", color
);
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
);
473 colors
.put("tradiobutton.active", color
);
474 color
= new CellAttributes();
475 color
.setForeColor(Color
.YELLOW
);
476 color
.setBackColor(Color
.BLUE
);
478 colors
.put("tradiobutton.mnemonic", color
);
479 color
= new CellAttributes();
480 color
.setForeColor(Color
.RED
);
481 color
.setBackColor(Color
.BLACK
);
483 colors
.put("tradiobutton.mnemonic.highlighted", color
);
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
);
495 colors
.put("tradiogroup.active", color
);
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
);
522 colors
.put("tmenu.disabled", color
);
525 color
= new CellAttributes();
526 color
.setForeColor(Color
.BLUE
);
527 color
.setBackColor(Color
.BLUE
);
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
);
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
);
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
);
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
);
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
);
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
);
631 color
= new CellAttributes();
632 color
.setForeColor(Color
.WHITE
);
633 color
.setBackColor(Color
.BLUE
);
634 color
.setBold(false);
635 colors
.put("teditor", color
);
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
.BLUE
);
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
);
672 * Make human-readable description of this Cell.
674 * @return displayable String
677 public String
toString() {
678 return colors
.toString();