2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2016 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
.util
.List
;
33 import jexer
.bits
.Color
;
34 import jexer
.bits
.ColorTheme
;
35 import jexer
.bits
.CellAttributes
;
36 import jexer
.bits
.GraphicsChars
;
37 import jexer
.event
.TKeypressEvent
;
38 import jexer
.event
.TMouseEvent
;
39 import static jexer
.TKeypress
.*;
42 * TEditColorThemeWindow provides an easy UI for users to alter the running
46 public final class TEditColorThemeWindow
extends TWindow
{
49 * The foreground color picker.
51 class ForegroundPicker
extends TWidget
{
66 * @param parent parent widget
67 * @param x column relative to parent
68 * @param y row relative to parent
69 * @param width width of text area
70 * @param height height of text area
72 public ForegroundPicker(final TWidget parent
, final int x
,
73 final int y
, final int width
, final int height
) {
75 super(parent
, x
, y
, width
, height
);
79 * Get the X grid coordinate for this color.
81 * @param color the Color value
82 * @return the X coordinate
84 private int getXColorPosition(final Color color
) {
85 if (color
.equals(Color
.BLACK
)) {
87 } else if (color
.equals(Color
.BLUE
)) {
89 } else if (color
.equals(Color
.GREEN
)) {
91 } else if (color
.equals(Color
.CYAN
)) {
93 } else if (color
.equals(Color
.RED
)) {
95 } else if (color
.equals(Color
.MAGENTA
)) {
97 } else if (color
.equals(Color
.YELLOW
)) {
99 } else if (color
.equals(Color
.WHITE
)) {
102 throw new IllegalArgumentException("Invalid color: " + color
);
106 * Get the Y grid coordinate for this color.
108 * @param color the Color value
109 * @param bold if true use bold color
110 * @return the Y coordinate
112 private int getYColorPosition(final Color color
, final boolean bold
) {
114 if (color
.equals(Color
.RED
)) {
116 } else if (color
.equals(Color
.MAGENTA
)) {
118 } else if (color
.equals(Color
.YELLOW
)) {
120 } else if (color
.equals(Color
.WHITE
)) {
130 * Get the bold value based on Y grid coordinate.
132 * @param dotY the Y coordinate
133 * @return the bold value
135 private boolean getBoldFromPosition(final int dotY
) {
143 * Get the color based on (X, Y) grid coordinate.
145 * @param dotX the X coordinate
146 * @param dotY the Y coordinate
147 * @return the Color value
149 private Color
getColorFromPosition(final int dotX
, final int dotY
) {
154 if ((1 <= dotX
) && (dotX
<= 3) && (y
== 1)) {
157 if ((4 <= dotX
) && (dotX
<= 6) && (y
== 1)) {
160 if ((7 <= dotX
) && (dotX
<= 9) && (y
== 1)) {
163 if ((10 <= dotX
) && (dotX
<= 12) && (y
== 1)) {
166 if ((1 <= dotX
) && (dotX
<= 3) && (y
== 2)) {
169 if ((4 <= dotX
) && (dotX
<= 6) && (y
== 2)) {
170 return Color
.MAGENTA
;
172 if ((7 <= dotX
) && (dotX
<= 9) && (y
== 2)) {
175 if ((10 <= dotX
) && (dotX
<= 12) && (y
== 2)) {
179 throw new IllegalArgumentException("Invalid coordinates: "
180 + dotX
+ ", " + dotY
);
184 * Draw the foreground colors grid.
188 CellAttributes border
= getWindow().getBorder();
189 CellAttributes background
= getWindow().getBackground();
190 CellAttributes attr
= new CellAttributes();
192 getScreen().drawBox(0, 0, getWidth(), getHeight(), border
,
193 background
, 1, false);
195 attr
.setTo(getTheme().getColor("twindow.background.modal"));
197 attr
.setForeColor(getTheme().getColor("tlabel").getForeColor());
198 attr
.setBold(getTheme().getColor("tlabel").isBold());
200 getScreen().putStringXY(1, 0, " Foreground ", attr
);
202 // Have to draw the colors manually because the int value matches
205 attr
.setReverse(true);
206 attr
.setForeColor(Color
.BLACK
);
207 putStringXY(1, 1, " ", attr
);
208 attr
.setForeColor(Color
.BLUE
);
209 putStringXY(4, 1, " ", attr
);
210 attr
.setForeColor(Color
.GREEN
);
211 putStringXY(7, 1, " ", attr
);
212 attr
.setForeColor(Color
.CYAN
);
213 putStringXY(10, 1, " ", attr
);
214 attr
.setForeColor(Color
.RED
);
215 putStringXY(1, 2, " ", attr
);
216 attr
.setForeColor(Color
.MAGENTA
);
217 putStringXY(4, 2, " ", attr
);
218 attr
.setForeColor(Color
.YELLOW
);
219 putStringXY(7, 2, " ", attr
);
220 attr
.setForeColor(Color
.WHITE
);
221 putStringXY(10, 2, " ", attr
);
224 attr
.setForeColor(Color
.BLACK
);
225 putStringXY(1, 3, " ", attr
);
226 attr
.setForeColor(Color
.BLUE
);
227 putStringXY(4, 3, " ", attr
);
228 attr
.setForeColor(Color
.GREEN
);
229 putStringXY(7, 3, " ", attr
);
230 attr
.setForeColor(Color
.CYAN
);
231 putStringXY(10, 3, " ", attr
);
232 attr
.setForeColor(Color
.RED
);
233 putStringXY(1, 4, " ", attr
);
234 attr
.setForeColor(Color
.MAGENTA
);
235 putStringXY(4, 4, " ", attr
);
236 attr
.setForeColor(Color
.YELLOW
);
237 putStringXY(7, 4, " ", attr
);
238 attr
.setForeColor(Color
.WHITE
);
239 putStringXY(10, 4, " ", attr
);
242 int dotX
= getXColorPosition(color
);
243 int dotY
= getYColorPosition(color
, bold
);
244 if (color
.equals(Color
.BLACK
) && !bold
) {
245 // Use white-on-black for black. All other colors use
246 // black-on-whatever.
248 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07],
251 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07]);
258 * @param keypress keystroke event
261 public void onKeypress(final TKeypressEvent keypress
) {
262 if (keypress
.equals(kbRight
)) {
263 int dotX
= getXColorPosition(color
);
264 int dotY
= getYColorPosition(color
, bold
);
268 color
= getColorFromPosition(dotX
, dotY
);
269 } else if (keypress
.equals(kbLeft
)) {
270 int dotX
= getXColorPosition(color
);
271 int dotY
= getYColorPosition(color
, bold
);
275 color
= getColorFromPosition(dotX
, dotY
);
276 } else if (keypress
.equals(kbUp
)) {
277 int dotX
= getXColorPosition(color
);
278 int dotY
= getYColorPosition(color
, bold
);
282 color
= getColorFromPosition(dotX
, dotY
);
283 bold
= getBoldFromPosition(dotY
);
284 } else if (keypress
.equals(kbDown
)) {
285 int dotX
= getXColorPosition(color
);
286 int dotY
= getYColorPosition(color
, bold
);
290 color
= getColorFromPosition(dotX
, dotY
);
291 bold
= getBoldFromPosition(dotY
);
294 super.onKeypress(keypress
);
298 // Save this update to the local theme.
299 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
303 * Handle mouse press events.
305 * @param mouse mouse button press event
308 public void onMouseDown(final TMouseEvent mouse
) {
309 if (mouse
.isMouseWheelUp()) {
311 int dotX
= getXColorPosition(color
);
312 int dotY
= getYColorPosition(color
, bold
);
316 color
= getColorFromPosition(dotX
, dotY
);
317 bold
= getBoldFromPosition(dotY
);
318 } else if (mouse
.isMouseWheelDown()) {
319 // Do this like kbDown
320 int dotX
= getXColorPosition(color
);
321 int dotY
= getYColorPosition(color
, bold
);
325 color
= getColorFromPosition(dotX
, dotY
);
326 bold
= getBoldFromPosition(dotY
);
327 } else if ((mouse
.getX() > 0)
328 && (mouse
.getX() < getWidth() - 1)
329 && (mouse
.getY() > 0)
330 && (mouse
.getY() < getHeight() - 1)
332 color
= getColorFromPosition(mouse
.getX(), mouse
.getY());
333 bold
= getBoldFromPosition(mouse
.getY());
335 // Let parent class handle it.
336 super.onMouseDown(mouse
);
340 // Save this update to the local theme.
341 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
347 * The background color picker.
349 class BackgroundPicker
extends TWidget
{
352 * The selected color.
357 * Public constructor.
359 * @param parent parent widget
360 * @param x column relative to parent
361 * @param y row relative to parent
362 * @param width width of text area
363 * @param height height of text area
365 public BackgroundPicker(final TWidget parent
, final int x
,
366 final int y
, final int width
, final int height
) {
368 super(parent
, x
, y
, width
, height
);
372 * Get the X grid coordinate for this color.
374 * @param color the Color value
375 * @return the X coordinate
377 private int getXColorPosition(final Color color
) {
378 if (color
.equals(Color
.BLACK
)) {
380 } else if (color
.equals(Color
.BLUE
)) {
382 } else if (color
.equals(Color
.GREEN
)) {
384 } else if (color
.equals(Color
.CYAN
)) {
386 } else if (color
.equals(Color
.RED
)) {
388 } else if (color
.equals(Color
.MAGENTA
)) {
390 } else if (color
.equals(Color
.YELLOW
)) {
392 } else if (color
.equals(Color
.WHITE
)) {
395 throw new IllegalArgumentException("Invalid color: " + color
);
399 * Get the Y grid coordinate for this color.
401 * @param color the Color value
402 * @return the Y coordinate
404 private int getYColorPosition(final Color color
) {
406 if (color
.equals(Color
.RED
)) {
408 } else if (color
.equals(Color
.MAGENTA
)) {
410 } else if (color
.equals(Color
.YELLOW
)) {
412 } else if (color
.equals(Color
.WHITE
)) {
419 * Get the color based on (X, Y) grid coordinate.
421 * @param dotX the X coordinate
422 * @param dotY the Y coordinate
423 * @return the Color value
425 private Color
getColorFromPosition(final int dotX
, final int dotY
) {
426 if ((1 <= dotX
) && (dotX
<= 3) && (dotY
== 1)) {
429 if ((4 <= dotX
) && (dotX
<= 6) && (dotY
== 1)) {
432 if ((7 <= dotX
) && (dotX
<= 9) && (dotY
== 1)) {
435 if ((10 <= dotX
) && (dotX
<= 12) && (dotY
== 1)) {
438 if ((1 <= dotX
) && (dotX
<= 3) && (dotY
== 2)) {
441 if ((4 <= dotX
) && (dotX
<= 6) && (dotY
== 2)) {
442 return Color
.MAGENTA
;
444 if ((7 <= dotX
) && (dotX
<= 9) && (dotY
== 2)) {
447 if ((10 <= dotX
) && (dotX
<= 12) && (dotY
== 2)) {
451 throw new IllegalArgumentException("Invalid coordinates: "
452 + dotX
+ ", " + dotY
);
456 * Draw the background colors grid.
460 CellAttributes border
= getWindow().getBorder();
461 CellAttributes background
= getWindow().getBackground();
462 CellAttributes attr
= new CellAttributes();
464 getScreen().drawBox(0, 0, getWidth(), getHeight(), border
,
465 background
, 1, false);
467 attr
.setTo(getTheme().getColor("twindow.background.modal"));
469 attr
.setForeColor(getTheme().getColor("tlabel").getForeColor());
470 attr
.setBold(getTheme().getColor("tlabel").isBold());
472 getScreen().putStringXY(1, 0, " Background ", attr
);
474 // Have to draw the colors manually because the int value matches
477 attr
.setReverse(true);
478 attr
.setForeColor(Color
.BLACK
);
479 putStringXY(1, 1, " ", attr
);
480 attr
.setForeColor(Color
.BLUE
);
481 putStringXY(4, 1, " ", attr
);
482 attr
.setForeColor(Color
.GREEN
);
483 putStringXY(7, 1, " ", attr
);
484 attr
.setForeColor(Color
.CYAN
);
485 putStringXY(10, 1, " ", attr
);
486 attr
.setForeColor(Color
.RED
);
487 putStringXY(1, 2, " ", attr
);
488 attr
.setForeColor(Color
.MAGENTA
);
489 putStringXY(4, 2, " ", attr
);
490 attr
.setForeColor(Color
.YELLOW
);
491 putStringXY(7, 2, " ", attr
);
492 attr
.setForeColor(Color
.WHITE
);
493 putStringXY(10, 2, " ", attr
);
496 int dotX
= getXColorPosition(color
);
497 int dotY
= getYColorPosition(color
);
498 if (color
.equals(Color
.BLACK
)) {
499 // Use white-on-black for black. All other colors use
500 // black-on-whatever.
502 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07],
505 getScreen().putCharXY(dotX
, dotY
, GraphicsChars
.CP437
[0x07]);
513 * @param keypress keystroke event
516 public void onKeypress(final TKeypressEvent keypress
) {
517 if (keypress
.equals(kbRight
)) {
518 int dotX
= getXColorPosition(color
);
519 int dotY
= getYColorPosition(color
);
523 color
= getColorFromPosition(dotX
, dotY
);
524 } else if (keypress
.equals(kbLeft
)) {
525 int dotX
= getXColorPosition(color
);
526 int dotY
= getYColorPosition(color
);
530 color
= getColorFromPosition(dotX
, dotY
);
531 } else if (keypress
.equals(kbUp
)) {
532 int dotX
= getXColorPosition(color
);
533 int dotY
= getYColorPosition(color
);
537 color
= getColorFromPosition(dotX
, dotY
);
538 } else if (keypress
.equals(kbDown
)) {
539 int dotX
= getXColorPosition(color
);
540 int dotY
= getYColorPosition(color
);
544 color
= getColorFromPosition(dotX
, dotY
);
547 super.onKeypress(keypress
);
550 // Save this update to the local theme.
551 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
555 * Handle mouse press events.
557 * @param mouse mouse button press event
560 public void onMouseDown(final TMouseEvent mouse
) {
561 if (mouse
.isMouseWheelUp()) {
563 int dotX
= getXColorPosition(color
);
564 int dotY
= getYColorPosition(color
);
568 color
= getColorFromPosition(dotX
, dotY
);
569 } else if (mouse
.isMouseWheelDown()) {
570 // Do this like kbDown
571 int dotX
= getXColorPosition(color
);
572 int dotY
= getYColorPosition(color
);
576 color
= getColorFromPosition(dotX
, dotY
);
578 } else if ((mouse
.getX() > 0)
579 && (mouse
.getX() < getWidth() - 1)
580 && (mouse
.getY() > 0)
581 && (mouse
.getY() < getHeight() - 1)
583 color
= getColorFromPosition(mouse
.getX(), mouse
.getY());
585 // Let parent class handle it.
586 super.onMouseDown(mouse
);
590 // Save this update to the local theme.
591 ((TEditColorThemeWindow
) getWindow()).saveToEditTheme();
597 * The current editing theme.
599 private ColorTheme editTheme
;
602 * The left-side list of colors pane.
604 private TList colorNames
;
607 * The foreground color.
609 private ForegroundPicker foreground
;
612 * The background color.
614 private BackgroundPicker background
;
617 * Set various widgets/values to the editing theme color.
619 * @param colorName name of color from theme
621 private void refreshFromTheme(final String colorName
) {
622 CellAttributes attr
= editTheme
.getColor(colorName
);
623 foreground
.color
= attr
.getForeColor();
624 foreground
.bold
= attr
.isBold();
625 background
.color
= attr
.getBackColor();
629 * Examines foreground, background, and colorNames and sets the color in
632 private void saveToEditTheme() {
633 String colorName
= colorNames
.getSelected();
634 if (colorName
== null) {
637 CellAttributes attr
= editTheme
.getColor(colorName
);
638 attr
.setForeColor(foreground
.color
);
639 attr
.setBold(foreground
.bold
);
640 attr
.setBackColor(background
.color
);
641 editTheme
.setColor(colorName
, attr
);
645 * Public constructor. The file open box will be centered on screen.
647 * @param application the TApplication that manages this window
649 public TEditColorThemeWindow(final TApplication application
) {
651 // Register with the TApplication
652 super(application
, "Colors", 0, 0, 60, 18, MODAL
);
654 // Initialize with the first color
655 List
<String
> colors
= getTheme().getColorNames();
656 assert (colors
.size() > 0);
657 editTheme
= new ColorTheme();
658 for (String key
: colors
) {
659 CellAttributes attr
= new CellAttributes();
660 attr
.setTo(getTheme().getColor(key
));
661 editTheme
.setColor(key
, attr
);
664 colorNames
= addList(colors
, 2, 2, 38, getHeight() - 7,
666 // When the user presses Enter
668 refreshFromTheme(colorNames
.getSelected());
672 // When the user navigates with keyboard
674 refreshFromTheme(colorNames
.getSelected());
678 foreground
= new ForegroundPicker(this, 42, 1, 14, 6);
679 background
= new BackgroundPicker(this, 42, 7, 14, 4);
680 refreshFromTheme(colors
.get(0));
681 colorNames
.setSelectedIndex(0);
683 addButton(" &OK ", getWidth() - 37, getHeight() - 4,
686 ColorTheme global
= getTheme();
687 List
<String
> colors
= editTheme
.getColorNames();
688 for (String key
: colors
) {
689 CellAttributes attr
= new CellAttributes();
690 attr
.setTo(editTheme
.getColor(key
));
691 global
.setColor(key
, attr
);
693 getApplication().closeWindow(TEditColorThemeWindow
.this);
698 addButton("&Cancel", getWidth() - 25, getHeight() - 4,
701 getApplication().closeWindow(TEditColorThemeWindow
.this);
706 // Default to the color list
707 activate(colorNames
);
717 CellAttributes attr
= new CellAttributes();
719 // Draw the label on colorNames
720 attr
.setTo(getTheme().getColor("twindow.background.modal"));
721 if (colorNames
.isActive()) {
722 attr
.setForeColor(getTheme().getColor("tlabel").getForeColor());
723 attr
.setBold(getTheme().getColor("tlabel").isBold());
725 getScreen().putStringXY(3, 2, "Color Name", attr
);
727 // Draw the sample text box
729 attr
.setForeColor(foreground
.color
);
730 attr
.setBold(foreground
.bold
);
731 attr
.setBackColor(background
.color
);
732 getScreen().putStringXY(getWidth() - 17, getHeight() - 6,
733 "Text Text Text", attr
);
734 getScreen().putStringXY(getWidth() - 17, getHeight() - 5,
735 "Text Text Text", attr
);
741 * @param keypress keystroke event
744 public void onKeypress(final TKeypressEvent keypress
) {
745 // Escape - behave like cancel
746 if (keypress
.equals(kbEsc
)) {
747 getApplication().closeWindow(this);
752 super.onKeypress(keypress
);