2 * Jexer - Java Text User Interface
4 * License: LGPLv3 or later
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
10 * Copyright (C) 2015 Kevin Lamonte
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
33 import java
.util
.List
;
35 import jexer
.bits
.Color
;
36 import jexer
.bits
.ColorTheme
;
37 import jexer
.bits
.CellAttributes
;
38 import jexer
.bits
.GraphicsChars
;
39 import jexer
.event
.TKeypressEvent
;
40 import jexer
.event
.TMouseEvent
;
41 import static jexer
.TKeypress
.*;
44 * TEditColorThemeWindow provides an easy UI for users to alter the running
48 public final class TEditColorThemeWindow
extends TWindow
{
51 * The foreground color picker.
53 class ForegroundPicker
extends TWidget
{
68 * @param parent parent widget
69 * @param x column relative to parent
70 * @param y row relative to parent
71 * @param width width of text area
72 * @param height height of text area
74 public ForegroundPicker(final TWidget parent
, final int x
,
75 final int y
, final int width
, final int height
) {
77 super(parent
, x
, y
, width
, height
);
81 * Get the X grid coordinate for this color.
83 * @param color the Color value
84 * @return the X coordinate
86 private int getXColorPosition(final Color color
) {
87 if (color
.equals(Color
.BLACK
)) {
89 } else if (color
.equals(Color
.BLUE
)) {
91 } else if (color
.equals(Color
.GREEN
)) {
93 } else if (color
.equals(Color
.CYAN
)) {
95 } else if (color
.equals(Color
.RED
)) {
97 } else if (color
.equals(Color
.MAGENTA
)) {
99 } else if (color
.equals(Color
.YELLOW
)) {
101 } else if (color
.equals(Color
.WHITE
)) {
104 throw new IllegalArgumentException("Invalid color: " + color
);
108 * Get the Y grid coordinate for this color.
110 * @param color the Color value
111 * @param bold if true use bold color
112 * @return the Y coordinate
114 private int getYColorPosition(final Color color
, final boolean bold
) {
116 if (color
.equals(Color
.RED
)) {
118 } else if (color
.equals(Color
.MAGENTA
)) {
120 } else if (color
.equals(Color
.YELLOW
)) {
122 } else if (color
.equals(Color
.WHITE
)) {
132 * Get the bold value based on Y grid coordinate.
134 * @param dotY the Y coordinate
135 * @return the bold value
137 private boolean getBoldFromPosition(final int dotY
) {
145 * Get the color based on (X, Y) grid coordinate.
147 * @param dotX the X coordinate
148 * @param dotY the Y coordinate
149 * @return the Color value
151 private Color
getColorFromPosition(final int dotX
, final int dotY
) {
156 if ((1 <= dotX
) && (dotX
<= 3) && (y
== 1)) {
159 if ((4 <= dotX
) && (dotX
<= 6) && (y
== 1)) {
162 if ((7 <= dotX
) && (dotX
<= 9) && (y
== 1)) {
165 if ((10 <= dotX
) && (dotX
<= 12) && (y
== 1)) {
168 if ((1 <= dotX
) && (dotX
<= 3) && (y
== 2)) {
171 if ((4 <= dotX
) && (dotX
<= 6) && (y
== 2)) {
172 return Color
.MAGENTA
;
174 if ((7 <= dotX
) && (dotX
<= 9) && (y
== 2)) {
177 if ((10 <= dotX
) && (dotX
<= 12) && (y
== 2)) {
181 throw new IllegalArgumentException("Invalid coordinates: "
182 + dotX
+ ", " + dotY
);
186 * Draw the foreground colors grid.
190 CellAttributes border
= getWindow().getBorder();
191 CellAttributes background
= getWindow().getBackground();
192 CellAttributes attr
= new CellAttributes();
194 getScreen().drawBox(0, 0, getWidth(), getHeight(), border
,
195 background
, 1, false);
197 attr
.setTo(getTheme().getColor("twindow.background.modal"));
199 attr
.setForeColor(getTheme().getColor("tlabel").getForeColor());
200 attr
.setBold(getTheme().getColor("tlabel").isBold());
202 getScreen().putStringXY(1, 0, " Foreground ", attr
);
204 // Have to draw the colors manually because the int value matches
207 attr
.setReverse(true);
208 attr
.setForeColor(Color
.BLACK
);
209 putStringXY(1, 1, " ", attr
);
210 attr
.setForeColor(Color
.BLUE
);
211 putStringXY(4, 1, " ", attr
);
212 attr
.setForeColor(Color
.GREEN
);
213 putStringXY(7, 1, " ", attr
);
214 attr
.setForeColor(Color
.CYAN
);
215 putStringXY(10, 1, " ", attr
);
216 attr
.setForeColor(Color
.RED
);
217 putStringXY(1, 2, " ", attr
);
218 attr
.setForeColor(Color
.MAGENTA
);
219 putStringXY(4, 2, " ", attr
);
220 attr
.setForeColor(Color
.YELLOW
);
221 putStringXY(7, 2, " ", attr
);
222 attr
.setForeColor(Color
.WHITE
);
223 putStringXY(10, 2, " ", attr
);
226 attr
.setForeColor(Color
.BLACK
);
227 putStringXY(1, 3, " ", attr
);
228 attr
.setForeColor(Color
.BLUE
);
229 putStringXY(4, 3, " ", attr
);
230 attr
.setForeColor(Color
.GREEN
);
231 putStringXY(7, 3, " ", attr
);
232 attr
.setForeColor(Color
.CYAN
);
233 putStringXY(10, 3, " ", attr
);
234 attr
.setForeColor(Color
.RED
);
235 putStringXY(1, 4, " ", attr
);
236 attr
.setForeColor(Color
.MAGENTA
);
237 putStringXY(4, 4, " ", attr
);
238 attr
.setForeColor(Color
.YELLOW
);
239 putStringXY(7, 4, " ", attr
);
240 attr
.setForeColor(Color
.WHITE
);
241 putStringXY(10, 4, " ", attr
);
244 int dotX
= getXColorPosition(color
);
245 int dotY
= getYColorPosition(color
, bold
);
246 if (color
.equals(Color
.BLACK
) && !bold
) {
247 // Use white-on-black for black. All other colors use
248 // black-on-whatever.
250 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07],
253 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07]);
260 * @param keypress keystroke event
263 public void onKeypress(final TKeypressEvent keypress
) {
264 if (keypress
.equals(kbRight
)) {
265 int dotX
= getXColorPosition(color
);
266 int dotY
= getYColorPosition(color
, bold
);
270 color
= getColorFromPosition(dotX
, dotY
);
271 } else if (keypress
.equals(kbLeft
)) {
272 int dotX
= getXColorPosition(color
);
273 int dotY
= getYColorPosition(color
, bold
);
277 color
= getColorFromPosition(dotX
, dotY
);
278 } else if (keypress
.equals(kbUp
)) {
279 int dotX
= getXColorPosition(color
);
280 int dotY
= getYColorPosition(color
, bold
);
284 color
= getColorFromPosition(dotX
, dotY
);
285 bold
= getBoldFromPosition(dotY
);
286 } else if (keypress
.equals(kbDown
)) {
287 int dotX
= getXColorPosition(color
);
288 int dotY
= getYColorPosition(color
, bold
);
292 color
= getColorFromPosition(dotX
, dotY
);
293 bold
= getBoldFromPosition(dotY
);
296 super.onKeypress(keypress
);
300 // Save this update to the local theme.
301 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
305 * Handle mouse press events.
307 * @param mouse mouse button press event
310 public void onMouseDown(final TMouseEvent mouse
) {
311 if (mouse
.isMouseWheelUp()) {
313 int dotX
= getXColorPosition(color
);
314 int dotY
= getYColorPosition(color
, bold
);
318 color
= getColorFromPosition(dotX
, dotY
);
319 bold
= getBoldFromPosition(dotY
);
320 } else if (mouse
.isMouseWheelDown()) {
321 // Do this like kbDown
322 int dotX
= getXColorPosition(color
);
323 int dotY
= getYColorPosition(color
, bold
);
327 color
= getColorFromPosition(dotX
, dotY
);
328 bold
= getBoldFromPosition(dotY
);
329 } else if ((mouse
.getX() > 0)
330 && (mouse
.getX() < getWidth() - 1)
331 && (mouse
.getY() > 0)
332 && (mouse
.getY() < getHeight() - 1)
334 color
= getColorFromPosition(mouse
.getX(), mouse
.getY());
335 bold
= getBoldFromPosition(mouse
.getY());
337 // Let parent class handle it.
338 super.onMouseDown(mouse
);
342 // Save this update to the local theme.
343 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
349 * The background color picker.
351 class BackgroundPicker
extends TWidget
{
354 * The selected color.
359 * Public constructor.
361 * @param parent parent widget
362 * @param x column relative to parent
363 * @param y row relative to parent
364 * @param width width of text area
365 * @param height height of text area
367 public BackgroundPicker(final TWidget parent
, final int x
,
368 final int y
, final int width
, final int height
) {
370 super(parent
, x
, y
, width
, height
);
374 * Get the X grid coordinate for this color.
376 * @param color the Color value
377 * @return the X coordinate
379 private int getXColorPosition(final Color color
) {
380 if (color
.equals(Color
.BLACK
)) {
382 } else if (color
.equals(Color
.BLUE
)) {
384 } else if (color
.equals(Color
.GREEN
)) {
386 } else if (color
.equals(Color
.CYAN
)) {
388 } else if (color
.equals(Color
.RED
)) {
390 } else if (color
.equals(Color
.MAGENTA
)) {
392 } else if (color
.equals(Color
.YELLOW
)) {
394 } else if (color
.equals(Color
.WHITE
)) {
397 throw new IllegalArgumentException("Invalid color: " + color
);
401 * Get the Y grid coordinate for this color.
403 * @param color the Color value
404 * @return the Y coordinate
406 private int getYColorPosition(final Color color
) {
408 if (color
.equals(Color
.RED
)) {
410 } else if (color
.equals(Color
.MAGENTA
)) {
412 } else if (color
.equals(Color
.YELLOW
)) {
414 } else if (color
.equals(Color
.WHITE
)) {
421 * Get the color based on (X, Y) grid coordinate.
423 * @param dotX the X coordinate
424 * @param dotY the Y coordinate
425 * @return the Color value
427 private Color
getColorFromPosition(final int dotX
, final int dotY
) {
428 if ((1 <= dotX
) && (dotX
<= 3) && (dotY
== 1)) {
431 if ((4 <= dotX
) && (dotX
<= 6) && (dotY
== 1)) {
434 if ((7 <= dotX
) && (dotX
<= 9) && (dotY
== 1)) {
437 if ((10 <= dotX
) && (dotX
<= 12) && (dotY
== 1)) {
440 if ((1 <= dotX
) && (dotX
<= 3) && (dotY
== 2)) {
443 if ((4 <= dotX
) && (dotX
<= 6) && (dotY
== 2)) {
444 return Color
.MAGENTA
;
446 if ((7 <= dotX
) && (dotX
<= 9) && (dotY
== 2)) {
449 if ((10 <= dotX
) && (dotX
<= 12) && (dotY
== 2)) {
453 throw new IllegalArgumentException("Invalid coordinates: "
454 + dotX
+ ", " + dotY
);
458 * Draw the background colors grid.
462 CellAttributes border
= getWindow().getBorder();
463 CellAttributes background
= getWindow().getBackground();
464 CellAttributes attr
= new CellAttributes();
466 getScreen().drawBox(0, 0, getWidth(), getHeight(), border
,
467 background
, 1, false);
469 attr
.setTo(getTheme().getColor("twindow.background.modal"));
471 attr
.setForeColor(getTheme().getColor("tlabel").getForeColor());
472 attr
.setBold(getTheme().getColor("tlabel").isBold());
474 getScreen().putStringXY(1, 0, " Background ", attr
);
476 // Have to draw the colors manually because the int value matches
479 attr
.setReverse(true);
480 attr
.setForeColor(Color
.BLACK
);
481 putStringXY(1, 1, " ", attr
);
482 attr
.setForeColor(Color
.BLUE
);
483 putStringXY(4, 1, " ", attr
);
484 attr
.setForeColor(Color
.GREEN
);
485 putStringXY(7, 1, " ", attr
);
486 attr
.setForeColor(Color
.CYAN
);
487 putStringXY(10, 1, " ", attr
);
488 attr
.setForeColor(Color
.RED
);
489 putStringXY(1, 2, " ", attr
);
490 attr
.setForeColor(Color
.MAGENTA
);
491 putStringXY(4, 2, " ", attr
);
492 attr
.setForeColor(Color
.YELLOW
);
493 putStringXY(7, 2, " ", attr
);
494 attr
.setForeColor(Color
.WHITE
);
495 putStringXY(10, 2, " ", attr
);
498 int dotX
= getXColorPosition(color
);
499 int dotY
= getYColorPosition(color
);
500 if (color
.equals(Color
.BLACK
)) {
501 // Use white-on-black for black. All other colors use
502 // black-on-whatever.
504 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07],
507 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07]);
515 * @param keypress keystroke event
518 public void onKeypress(final TKeypressEvent keypress
) {
519 if (keypress
.equals(kbRight
)) {
520 int dotX
= getXColorPosition(color
);
521 int dotY
= getYColorPosition(color
);
525 color
= getColorFromPosition(dotX
, dotY
);
526 } else if (keypress
.equals(kbLeft
)) {
527 int dotX
= getXColorPosition(color
);
528 int dotY
= getYColorPosition(color
);
532 color
= getColorFromPosition(dotX
, dotY
);
533 } else if (keypress
.equals(kbUp
)) {
534 int dotX
= getXColorPosition(color
);
535 int dotY
= getYColorPosition(color
);
539 color
= getColorFromPosition(dotX
, dotY
);
540 } else if (keypress
.equals(kbDown
)) {
541 int dotX
= getXColorPosition(color
);
542 int dotY
= getYColorPosition(color
);
546 color
= getColorFromPosition(dotX
, dotY
);
549 super.onKeypress(keypress
);
552 // Save this update to the local theme.
553 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
557 * Handle mouse press events.
559 * @param mouse mouse button press event
562 public void onMouseDown(final TMouseEvent mouse
) {
563 if (mouse
.isMouseWheelUp()) {
565 int dotX
= getXColorPosition(color
);
566 int dotY
= getYColorPosition(color
);
570 color
= getColorFromPosition(dotX
, dotY
);
571 } else if (mouse
.isMouseWheelDown()) {
572 // Do this like kbDown
573 int dotX
= getXColorPosition(color
);
574 int dotY
= getYColorPosition(color
);
578 color
= getColorFromPosition(dotX
, dotY
);
580 } else if ((mouse
.getX() > 0)
581 && (mouse
.getX() < getWidth() - 1)
582 && (mouse
.getY() > 0)
583 && (mouse
.getY() < getHeight() - 1)
585 color
= getColorFromPosition(mouse
.getX(), mouse
.getY());
587 // Let parent class handle it.
588 super.onMouseDown(mouse
);
592 // Save this update to the local theme.
593 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
599 * The current editing theme.
601 private ColorTheme editTheme
;
604 * The left-side list of colors pane.
606 private TList colorNames
;
609 * The foreground color.
611 private ForegroundPicker foreground
;
614 * The background color.
616 private BackgroundPicker background
;
619 * Set various widgets/values to the editing theme color.
621 * @param colorName name of color from theme
623 private void refreshFromTheme(final String colorName
) {
624 CellAttributes attr
= editTheme
.getColor(colorName
);
625 foreground
.color
= attr
.getForeColor();
626 foreground
.bold
= attr
.isBold();
627 background
.color
= attr
.getBackColor();
631 * Examines foreground, background, and colorNames and sets the color in
634 private void saveToEditTheme() {
635 String colorName
= colorNames
.getSelected();
636 if (colorName
== null) {
639 CellAttributes attr
= editTheme
.getColor(colorName
);
640 attr
.setForeColor(foreground
.color
);
641 attr
.setBold(foreground
.bold
);
642 attr
.setBackColor(background
.color
);
643 editTheme
.setColor(colorName
, attr
);
647 * Public constructor. The file open box will be centered on screen.
649 * @param application the TApplication that manages this window
651 public TEditColorThemeWindow(final TApplication application
) {
653 // Register with the TApplication
654 super(application
, "Colors", 0, 0, 60, 18, MODAL
);
656 // Initialize with the first color
657 List
<String
> colors
= getTheme().getColorNames();
658 assert (colors
.size() > 0);
659 editTheme
= new ColorTheme();
660 for (String key
: colors
) {
661 CellAttributes attr
= new CellAttributes();
662 attr
.setTo(getTheme().getColor(key
));
663 editTheme
.setColor(key
, attr
);
666 colorNames
= addList(colors
, 2, 2, 38, getHeight() - 7,
668 // When the user presses Enter
670 refreshFromTheme(colorNames
.getSelected());
674 // When the user navigates with keyboard
676 refreshFromTheme(colorNames
.getSelected());
680 foreground
= new ForegroundPicker(this, 42, 1, 14, 6);
681 background
= new BackgroundPicker(this, 42, 7, 14, 4);
682 refreshFromTheme(colors
.get(0));
683 colorNames
.setSelectedIndex(0);
685 addButton(" &OK ", getWidth() - 37, getHeight() - 4,
688 ColorTheme global
= getTheme();
689 List
<String
> colors
= editTheme
.getColorNames();
690 for (String key
: colors
) {
691 CellAttributes attr
= new CellAttributes();
692 attr
.setTo(editTheme
.getColor(key
));
693 global
.setColor(key
, attr
);
695 getApplication().closeWindow(TEditColorThemeWindow
.this);
700 addButton("&Cancel", getWidth() - 25, getHeight() - 4,
703 getApplication().closeWindow(TEditColorThemeWindow
.this);
708 // Default to the color list
709 activate(colorNames
);
719 CellAttributes attr
= new CellAttributes();
721 // Draw the label on colorNames
722 attr
.setTo(getTheme().getColor("twindow.background.modal"));
723 if (colorNames
.isActive()) {
724 attr
.setForeColor(getTheme().getColor("tlabel").getForeColor());
725 attr
.setBold(getTheme().getColor("tlabel").isBold());
727 getScreen().putStringXY(3, 2, "Color Name", attr
);
729 // Draw the sample text box
731 attr
.setForeColor(foreground
.color
);
732 attr
.setBold(foreground
.bold
);
733 attr
.setBackColor(background
.color
);
734 getScreen().putStringXY(getWidth() - 17, getHeight() - 6,
735 "Text Text Text", attr
);
736 getScreen().putStringXY(getWidth() - 17, getHeight() - 5,
737 "Text Text Text", attr
);
743 * @param keypress keystroke event
746 public void onKeypress(final TKeypressEvent keypress
) {
747 // Escape - behave like cancel
748 if (keypress
.equals(kbEsc
)) {
749 getApplication().closeWindow(this);
754 super.onKeypress(keypress
);