2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
4 * lanterna is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 2010-2015 Martin
19 package com
.googlecode
.lanterna
.gui2
;
21 import com
.googlecode
.lanterna
.TerminalTextUtils
;
22 import com
.googlecode
.lanterna
.TerminalPosition
;
23 import com
.googlecode
.lanterna
.TerminalSize
;
24 import com
.googlecode
.lanterna
.graphics
.ThemeDefinition
;
25 import com
.googlecode
.lanterna
.input
.KeyStroke
;
26 import com
.googlecode
.lanterna
.input
.KeyType
;
28 import java
.util
.List
;
29 import java
.util
.concurrent
.CopyOnWriteArrayList
;
32 * The checkbox component looks like a regular checkbox that you can find in modern graphics user interfaces, a label
33 * and a space that the user can toggle on and off by using enter or space keys.
37 public class CheckBox
extends AbstractInteractableComponent
<CheckBox
> {
40 * Listener interface that can be used to catch user events on the check box
42 public interface Listener
{
44 * This is fired when the user has altered the checked state of this {@code CheckBox}
45 * @param checked If the {@code CheckBox} is now toggled on, this is set to {@code true}, otherwise
48 void onStatusChanged(boolean checked
);
51 private final List
<Listener
> listeners
;
53 private boolean checked
;
56 * Creates a new checkbox with no label, initially set to un-checked
63 * Creates a new checkbox with a specific label, initially set to un-checked
64 * @param label Label to assign to the check box
66 public CheckBox(String label
) {
68 throw new IllegalArgumentException("Cannot create a CheckBox with null label");
70 else if(label
.contains("\n") || label
.contains("\r")) {
71 throw new IllegalArgumentException("Multiline checkbox labels are not supported");
73 this.listeners
= new CopyOnWriteArrayList
<Listener
>();
79 * Programmatically updated the check box to a particular checked state
80 * @param checked If {@code true}, the check box will be set to toggled on, otherwise {@code false}
83 public synchronized CheckBox
setChecked(final boolean checked
) {
84 this.checked
= checked
;
85 runOnGUIThreadIfExistsOtherwiseRunDirect(new Runnable() {
88 for(Listener listener
: listeners
) {
89 listener
.onStatusChanged(checked
);
98 * Returns the checked state of this check box
99 * @return {@code true} if the check box is toggled on, otherwise {@code false}
101 public boolean isChecked() {
106 public Result
handleKeyStroke(KeyStroke keyStroke
) {
107 if((keyStroke
.getKeyType() == KeyType
.Character
&& keyStroke
.getCharacter() == ' ') ||
108 keyStroke
.getKeyType() == KeyType
.Enter
) {
109 setChecked(!isChecked());
110 return Result
.HANDLED
;
112 return super.handleKeyStroke(keyStroke
);
116 * Updates the label of the checkbox
117 * @param label New label to assign to the check box
120 public synchronized CheckBox
setLabel(String label
) {
122 throw new IllegalArgumentException("Cannot set CheckBox label to null");
130 * Returns the label of check box
131 * @return Label currently assigned to the check box
133 public String
getLabel() {
138 * Adds a listener to this check box so that it will be notificed on certain user actions
139 * @param listener Listener to fire events on
142 public CheckBox
addListener(Listener listener
) {
143 if(listener
!= null && !listeners
.contains(listener
)) {
144 listeners
.add(listener
);
150 * Removes a listener from this check box so that, if it was previously added, it will no long receive any events
151 * @param listener Listener to remove from the check box
154 public CheckBox
removeListener(Listener listener
) {
155 listeners
.remove(listener
);
160 protected CheckBoxRenderer
createDefaultRenderer() {
161 return new DefaultCheckBoxRenderer();
165 * Helper interface that doesn't add any new methods but makes coding new check box renderers a little bit more clear
167 public static abstract class CheckBoxRenderer
implements InteractableRenderer
<CheckBox
> {
171 * The default renderer that is used unless overridden. This renderer will draw the checkbox label on the right side
172 * of a "[ ]" block which will contain a "X" inside it if the check box has toggle status on
174 public static class DefaultCheckBoxRenderer
extends CheckBoxRenderer
{
175 private static final TerminalPosition CURSOR_LOCATION
= new TerminalPosition(1, 0);
177 public TerminalPosition
getCursorLocation(CheckBox component
) {
178 return CURSOR_LOCATION
;
182 public TerminalSize
getPreferredSize(CheckBox component
) {
184 if(!component
.label
.isEmpty()) {
185 width
+= 1 + TerminalTextUtils
.getColumnWidth(component
.label
);
187 return new TerminalSize(width
, 1);
191 public void drawComponent(TextGUIGraphics graphics
, CheckBox component
) {
192 ThemeDefinition themeDefinition
= graphics
.getThemeDefinition(CheckBox
.class);
193 if(component
.isFocused()) {
194 graphics
.applyThemeStyle(themeDefinition
.getActive());
197 graphics
.applyThemeStyle(themeDefinition
.getNormal());
201 graphics
.putString(4, 0, component
.label
);
203 String head
= "[" + (component
.isChecked() ? themeDefinition
.getCharacter("MARKER", 'x') : " ") + "]";
204 if(component
.isFocused()) {
205 graphics
.applyThemeStyle(themeDefinition
.getPreLight());
208 graphics
.applyThemeStyle(themeDefinition
.getNormal());
210 graphics
.putString(0, 0, head
);