Change build scripts
[jvcard.git] / src / com / googlecode / lanterna / gui2 / Button.java
CommitLineData
a3b510ab
NR
1/*
2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
3 *
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.
8 *
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.
13 *
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/>.
16 *
17 * Copyright (C) 2010-2015 Martin
18 */
19package com.googlecode.lanterna.gui2;
20
21import com.googlecode.lanterna.TerminalTextUtils;
22import com.googlecode.lanterna.TerminalPosition;
23import com.googlecode.lanterna.TerminalSize;
24import com.googlecode.lanterna.graphics.ThemeDefinition;
25import com.googlecode.lanterna.input.KeyStroke;
26import com.googlecode.lanterna.input.KeyType;
27
28/**
29 * Simple labeled button with an optional action attached to it, you trigger the action by pressing the Enter key on the
30 * keyboard when the component is in focus.
31 * @author Martin
32 */
33public class Button extends AbstractInteractableComponent<Button> {
34 private final Runnable action;
35 private String label;
36
37 /**
38 * Creates a new button with a specific label and no attached action. Why would you need this? I have no idea.
39 * @param label Label to put on the button
40 */
41 public Button(String label) {
42 this(label, new Runnable() {
43 @Override
44 public void run() {
45 }
46 });
47 }
48
49 /**
50 * Creates a new button with a label and an associated action to fire when triggered by the user
51 * @param label Label to put on the button
52 * @param action What action to fire when the user triggers the button by pressing the enter key
53 */
54 public Button(String label, Runnable action) {
55 this.action = action;
56 setLabel(label);
57 }
58
59 @Override
60 protected ButtonRenderer createDefaultRenderer() {
61 return new DefaultButtonRenderer();
62 }
63
64 @Override
65 public synchronized TerminalPosition getCursorLocation() {
66 return getRenderer().getCursorLocation(this);
67 }
68
69 @Override
70 public synchronized Result handleKeyStroke(KeyStroke keyStroke) {
71 if(keyStroke.getKeyType() == KeyType.Enter) {
72 action.run();
73 return Result.HANDLED;
74 }
75 return super.handleKeyStroke(keyStroke);
76 }
77
78 /**
79 * Updates the label on the button to the specified string
80 * @param label New label to use on the button
81 */
82 public final synchronized void setLabel(String label) {
83 if(label == null) {
84 throw new IllegalArgumentException("null label to a button is not allowed");
85 }
86 if(label.isEmpty()) {
87 label = " ";
88 }
89 this.label = label;
90 invalidate();
91 }
92
93 /**
94 * Returns the label current assigned to the button
95 * @return Label currently used by the button
96 */
97 public String getLabel() {
98 return label;
99 }
100
101 @Override
102 public String toString() {
103 return "Button{" + label + "}";
104 }
105
106 /**
107 * Helper interface that doesn't add any new methods but makes coding new button renderers a little bit more clear
108 */
109 public interface ButtonRenderer extends InteractableRenderer<Button> {
110 }
111
112 /**
113 * This is the default button renderer that is used if you don't override anything. With this renderer, buttons are
114 * drawn on a single line, with the label inside of "&lt;" and "&gt;".
115 */
116 public static class DefaultButtonRenderer implements ButtonRenderer {
117 @Override
118 public TerminalPosition getCursorLocation(Button button) {
119 return new TerminalPosition(1 + getLabelShift(button, button.getSize()), 0);
120 }
121
122 @Override
123 public TerminalSize getPreferredSize(Button button) {
124 return new TerminalSize(Math.max(8, TerminalTextUtils.getColumnWidth(button.getLabel()) + 2), 1);
125 }
126
127 @Override
128 public void drawComponent(TextGUIGraphics graphics, Button button) {
129 if(button.isFocused()) {
130 graphics.applyThemeStyle(getThemeDefinition(graphics).getActive());
131 }
132 else {
133 graphics.applyThemeStyle(getThemeDefinition(graphics).getInsensitive());
134 }
135 graphics.fill(' ');
136 graphics.setCharacter(0, 0, getThemeDefinition(graphics).getCharacter("LEFT_BORDER", '<'));
137 graphics.setCharacter(graphics.getSize().getColumns() - 1, 0, getThemeDefinition(graphics).getCharacter("RIGHT_BORDER", '>'));
138
139 if(button.isFocused()) {
140 graphics.applyThemeStyle(getThemeDefinition(graphics).getActive());
141 }
142 else {
143 graphics.applyThemeStyle(getThemeDefinition(graphics).getPreLight());
144 }
145 int labelShift = getLabelShift(button, graphics.getSize());
146 graphics.setCharacter(1 + labelShift, 0, button.getLabel().charAt(0));
147
148 if(TerminalTextUtils.getColumnWidth(button.getLabel()) == 1) {
149 return;
150 }
151 if(button.isFocused()) {
152 graphics.applyThemeStyle(getThemeDefinition(graphics).getSelected());
153 }
154 else {
155 graphics.applyThemeStyle(getThemeDefinition(graphics).getNormal());
156 }
157 graphics.putString(1 + labelShift + 1, 0, button.getLabel().substring(1));
158 }
159
160 private int getLabelShift(Button button, TerminalSize size) {
161 int availableSpace = size.getColumns() - 2;
162 if(availableSpace <= 0) {
163 return 0;
164 }
165 int labelShift = 0;
166 int widthInColumns = TerminalTextUtils.getColumnWidth(button.getLabel());
167 if(availableSpace > widthInColumns) {
168 labelShift = (size.getColumns() - 2 - widthInColumns) / 2;
169 }
170 return labelShift;
171 }
172 }
173
174 /**
175 * Alternative button renderer that displays buttons with just the label and minimal decoration
176 */
177 public static class FlatButtonRenderer implements ButtonRenderer {
178 @Override
179 public TerminalPosition getCursorLocation(Button component) {
180 return null;
181 }
182
183 @Override
184 public TerminalSize getPreferredSize(Button component) {
185 return new TerminalSize(TerminalTextUtils.getColumnWidth(component.getLabel()), 1);
186 }
187
188 @Override
189 public void drawComponent(TextGUIGraphics graphics, Button button) {
190 if(button.isFocused()) {
191 graphics.applyThemeStyle(getThemeDefinition(graphics).getActive());
192 }
193 else {
194 graphics.applyThemeStyle(getThemeDefinition(graphics).getInsensitive());
195 }
196 graphics.fill(' ');
197 if(button.isFocused()) {
198 graphics.applyThemeStyle(getThemeDefinition(graphics).getSelected());
199 }
200 else {
201 graphics.applyThemeStyle(getThemeDefinition(graphics).getNormal());
202 }
203 graphics.putString(0, 0, button.getLabel());
204 }
205 }
206
207 private static ThemeDefinition getThemeDefinition(TextGUIGraphics graphics) {
208 return graphics.getThemeDefinition(Button.class);
209 }
210}