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
;
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.
33 public class Button
extends AbstractInteractableComponent
<Button
> {
34 private final Runnable action
;
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
41 public Button(String label
) {
42 this(label
, new Runnable() {
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
54 public Button(String label
, Runnable action
) {
60 protected ButtonRenderer
createDefaultRenderer() {
61 return new DefaultButtonRenderer();
65 public synchronized TerminalPosition
getCursorLocation() {
66 return getRenderer().getCursorLocation(this);
70 public synchronized Result
handleKeyStroke(KeyStroke keyStroke
) {
71 if(keyStroke
.getKeyType() == KeyType
.Enter
) {
73 return Result
.HANDLED
;
75 return super.handleKeyStroke(keyStroke
);
79 * Updates the label on the button to the specified string
80 * @param label New label to use on the button
82 public final synchronized void setLabel(String label
) {
84 throw new IllegalArgumentException("null label to a button is not allowed");
94 * Returns the label current assigned to the button
95 * @return Label currently used by the button
97 public String
getLabel() {
102 public String
toString() {
103 return "Button{" + label
+ "}";
107 * Helper interface that doesn't add any new methods but makes coding new button renderers a little bit more clear
109 public interface ButtonRenderer
extends InteractableRenderer
<Button
> {
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 "<" and ">".
116 public static class DefaultButtonRenderer
implements ButtonRenderer
{
118 public TerminalPosition
getCursorLocation(Button button
) {
119 return new TerminalPosition(1 + getLabelShift(button
, button
.getSize()), 0);
123 public TerminalSize
getPreferredSize(Button button
) {
124 return new TerminalSize(Math
.max(8, TerminalTextUtils
.getColumnWidth(button
.getLabel()) + 2), 1);
128 public void drawComponent(TextGUIGraphics graphics
, Button button
) {
129 if(button
.isFocused()) {
130 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getActive());
133 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getInsensitive());
136 graphics
.setCharacter(0, 0, getThemeDefinition(graphics
).getCharacter("LEFT_BORDER", '<'));
137 graphics
.setCharacter(graphics
.getSize().getColumns() - 1, 0, getThemeDefinition(graphics
).getCharacter("RIGHT_BORDER", '>'));
139 if(button
.isFocused()) {
140 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getActive());
143 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getPreLight());
145 int labelShift
= getLabelShift(button
, graphics
.getSize());
146 graphics
.setCharacter(1 + labelShift
, 0, button
.getLabel().charAt(0));
148 if(TerminalTextUtils
.getColumnWidth(button
.getLabel()) == 1) {
151 if(button
.isFocused()) {
152 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getSelected());
155 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getNormal());
157 graphics
.putString(1 + labelShift
+ 1, 0, button
.getLabel().substring(1));
160 private int getLabelShift(Button button
, TerminalSize size
) {
161 int availableSpace
= size
.getColumns() - 2;
162 if(availableSpace
<= 0) {
166 int widthInColumns
= TerminalTextUtils
.getColumnWidth(button
.getLabel());
167 if(availableSpace
> widthInColumns
) {
168 labelShift
= (size
.getColumns() - 2 - widthInColumns
) / 2;
175 * Alternative button renderer that displays buttons with just the label and minimal decoration
177 public static class FlatButtonRenderer
implements ButtonRenderer
{
179 public TerminalPosition
getCursorLocation(Button component
) {
184 public TerminalSize
getPreferredSize(Button component
) {
185 return new TerminalSize(TerminalTextUtils
.getColumnWidth(component
.getLabel()), 1);
189 public void drawComponent(TextGUIGraphics graphics
, Button button
) {
190 if(button
.isFocused()) {
191 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getActive());
194 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getInsensitive());
197 if(button
.isFocused()) {
198 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getSelected());
201 graphics
.applyThemeStyle(getThemeDefinition(graphics
).getNormal());
203 graphics
.putString(0, 0, button
.getLabel());
207 private static ThemeDefinition
getThemeDefinition(TextGUIGraphics graphics
) {
208 return graphics
.getThemeDefinition(Button
.class);