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
);
367 color
= new CellAttributes();
368 color
.setForeColor(Color
.WHITE
);
369 color
.setBackColor(Color
.BLUE
);
370 color
.setBold(false);
371 colors
.put("ttext", color
);
374 color
= new CellAttributes();
375 color
.setForeColor(Color
.BLACK
);
376 color
.setBackColor(Color
.WHITE
);
377 color
.setBold(false);
378 colors
.put("tfield.inactive", color
);
379 color
= new CellAttributes();
380 color
.setForeColor(Color
.BLACK
);
381 color
.setBackColor(Color
.CYAN
);
382 color
.setBold(false);
383 colors
.put("tfield.active", color
);
386 color
= new CellAttributes();
387 color
.setForeColor(Color
.WHITE
);
388 color
.setBackColor(Color
.BLUE
);
389 color
.setBold(false);
390 colors
.put("tcheckbox.inactive", color
);
391 color
= new CellAttributes();
392 color
.setForeColor(Color
.YELLOW
);
393 color
.setBackColor(Color
.BLACK
);
395 colors
.put("tcheckbox.active", color
);
398 color
= new CellAttributes();
399 color
.setForeColor(Color
.BLACK
);
400 color
.setBackColor(Color
.WHITE
);
401 color
.setBold(false);
402 colors
.put("tcombobox.inactive", color
);
403 color
= new CellAttributes();
404 color
.setForeColor(Color
.BLUE
);
405 color
.setBackColor(Color
.CYAN
);
406 color
.setBold(false);
407 colors
.put("tcombobox.active", color
);
410 color
= new CellAttributes();
411 color
.setForeColor(Color
.BLACK
);
412 color
.setBackColor(Color
.WHITE
);
413 color
.setBold(false);
414 colors
.put("tspinner.inactive", color
);
415 color
= new CellAttributes();
416 color
.setForeColor(Color
.BLUE
);
417 color
.setBackColor(Color
.CYAN
);
418 color
.setBold(false);
419 colors
.put("tspinner.active", color
);
422 color
= new CellAttributes();
423 color
.setForeColor(Color
.WHITE
);
424 color
.setBackColor(Color
.BLUE
);
425 color
.setBold(false);
426 colors
.put("tcalendar.background", color
);
427 color
= new CellAttributes();
428 color
.setForeColor(Color
.WHITE
);
429 color
.setBackColor(Color
.BLUE
);
430 color
.setBold(false);
431 colors
.put("tcalendar.day", color
);
432 color
= new CellAttributes();
433 color
.setForeColor(Color
.RED
);
434 color
.setBackColor(Color
.WHITE
);
435 color
.setBold(false);
436 colors
.put("tcalendar.day.selected", color
);
437 color
= new CellAttributes();
438 color
.setForeColor(Color
.BLUE
);
439 color
.setBackColor(Color
.CYAN
);
440 color
.setBold(false);
441 colors
.put("tcalendar.arrow", color
);
442 color
= new CellAttributes();
443 color
.setForeColor(Color
.WHITE
);
444 color
.setBackColor(Color
.BLUE
);
446 colors
.put("tcalendar.title", color
);
449 color
= new CellAttributes();
450 color
.setForeColor(Color
.WHITE
);
451 color
.setBackColor(Color
.BLUE
);
452 color
.setBold(false);
453 colors
.put("tradiobutton.inactive", color
);
454 color
= new CellAttributes();
455 color
.setForeColor(Color
.YELLOW
);
456 color
.setBackColor(Color
.BLACK
);
458 colors
.put("tradiobutton.active", color
);
461 color
= new CellAttributes();
462 color
.setForeColor(Color
.WHITE
);
463 color
.setBackColor(Color
.BLUE
);
464 color
.setBold(false);
465 colors
.put("tradiogroup.inactive", color
);
466 color
= new CellAttributes();
467 color
.setForeColor(Color
.YELLOW
);
468 color
.setBackColor(Color
.BLUE
);
470 colors
.put("tradiogroup.active", color
);
473 color
= new CellAttributes();
474 color
.setForeColor(Color
.BLACK
);
475 color
.setBackColor(Color
.WHITE
);
476 color
.setBold(false);
477 colors
.put("tmenu", color
);
478 color
= new CellAttributes();
479 color
.setForeColor(Color
.BLACK
);
480 color
.setBackColor(Color
.GREEN
);
481 color
.setBold(false);
482 colors
.put("tmenu.highlighted", color
);
483 color
= new CellAttributes();
484 color
.setForeColor(Color
.RED
);
485 color
.setBackColor(Color
.WHITE
);
486 color
.setBold(false);
487 colors
.put("tmenu.mnemonic", color
);
488 color
= new CellAttributes();
489 color
.setForeColor(Color
.RED
);
490 color
.setBackColor(Color
.GREEN
);
491 color
.setBold(false);
492 colors
.put("tmenu.mnemonic.highlighted", color
);
493 color
= new CellAttributes();
494 color
.setForeColor(Color
.BLACK
);
495 color
.setBackColor(Color
.WHITE
);
497 colors
.put("tmenu.disabled", color
);
500 color
= new CellAttributes();
501 color
.setForeColor(Color
.BLUE
);
502 color
.setBackColor(Color
.BLUE
);
504 colors
.put("tprogressbar.complete", color
);
505 color
= new CellAttributes();
506 color
.setForeColor(Color
.WHITE
);
507 color
.setBackColor(Color
.BLUE
);
508 color
.setBold(false);
509 colors
.put("tprogressbar.incomplete", color
);
511 // THScroller / TVScroller
512 color
= new CellAttributes();
513 color
.setForeColor(Color
.CYAN
);
514 color
.setBackColor(Color
.BLUE
);
515 color
.setBold(false);
516 colors
.put("tscroller.bar", color
);
517 color
= new CellAttributes();
518 color
.setForeColor(Color
.BLUE
);
519 color
.setBackColor(Color
.CYAN
);
520 color
.setBold(false);
521 colors
.put("tscroller.arrows", color
);
524 color
= new CellAttributes();
525 color
.setForeColor(Color
.WHITE
);
526 color
.setBackColor(Color
.BLUE
);
527 color
.setBold(false);
528 colors
.put("ttreeview", color
);
529 color
= new CellAttributes();
530 color
.setForeColor(Color
.GREEN
);
531 color
.setBackColor(Color
.BLUE
);
533 colors
.put("ttreeview.expandbutton", color
);
534 color
= new CellAttributes();
535 color
.setForeColor(Color
.BLACK
);
536 color
.setBackColor(Color
.CYAN
);
537 color
.setBold(false);
538 colors
.put("ttreeview.selected", color
);
539 color
= new CellAttributes();
540 color
.setForeColor(Color
.RED
);
541 color
.setBackColor(Color
.BLUE
);
542 color
.setBold(false);
543 colors
.put("ttreeview.unreadable", color
);
544 color
= new CellAttributes();
545 // color.setForeColor(Color.BLACK);
546 // color.setBackColor(Color.BLUE);
547 // color.setBold(true);
548 color
.setForeColor(Color
.WHITE
);
549 color
.setBackColor(Color
.BLUE
);
550 color
.setBold(false);
551 colors
.put("ttreeview.inactive", color
);
552 color
= new CellAttributes();
553 color
.setForeColor(Color
.BLACK
);
554 color
.setBackColor(Color
.WHITE
);
555 color
.setBold(false);
556 colors
.put("ttreeview.selected.inactive", color
);
559 color
= new CellAttributes();
560 color
.setForeColor(Color
.WHITE
);
561 color
.setBackColor(Color
.BLUE
);
562 color
.setBold(false);
563 colors
.put("tlist", color
);
564 color
= new CellAttributes();
565 color
.setForeColor(Color
.BLACK
);
566 color
.setBackColor(Color
.CYAN
);
567 color
.setBold(false);
568 colors
.put("tlist.selected", color
);
569 color
= new CellAttributes();
570 color
.setForeColor(Color
.BLACK
);
571 color
.setBackColor(Color
.CYAN
);
572 color
.setBold(false);
573 colors
.put("tlist.unreadable", color
);
574 color
= new CellAttributes();
575 // color.setForeColor(Color.BLACK);
576 // color.setBackColor(Color.BLUE);
577 // color.setBold(true);
578 color
.setForeColor(Color
.WHITE
);
579 color
.setBackColor(Color
.BLUE
);
580 color
.setBold(false);
581 colors
.put("tlist.inactive", color
);
582 color
= new CellAttributes();
583 color
.setForeColor(Color
.BLACK
);
584 color
.setBackColor(Color
.WHITE
);
585 color
.setBold(false);
586 colors
.put("tlist.selected.inactive", color
);
589 color
= new CellAttributes();
590 color
.setForeColor(Color
.BLACK
);
591 color
.setBackColor(Color
.WHITE
);
592 color
.setBold(false);
593 colors
.put("tstatusbar.text", color
);
594 color
= new CellAttributes();
595 color
.setForeColor(Color
.RED
);
596 color
.setBackColor(Color
.WHITE
);
597 color
.setBold(false);
598 colors
.put("tstatusbar.button", color
);
599 color
= new CellAttributes();
600 color
.setForeColor(Color
.WHITE
);
601 color
.setBackColor(Color
.BLUE
);
602 color
.setBold(false);
603 colors
.put("tstatusbar.selected", color
);
606 color
= new CellAttributes();
607 color
.setForeColor(Color
.WHITE
);
608 color
.setBackColor(Color
.BLUE
);
609 color
.setBold(false);
610 colors
.put("teditor", color
);
615 * Make human-readable description of this Cell.
617 * @return displayable String
620 public String
toString() {
621 return colors
.toString();