TStatusBar
[fanfix.git] / src / jexer / TStatusBar.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2016 Kevin Lamonte
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29 package jexer;
30
31 import java.util.ArrayList;
32
33 import jexer.bits.CellAttributes;
34 import jexer.bits.GraphicsChars;
35 import jexer.event.TCommandEvent;
36 import jexer.event.TKeypressEvent;
37 import jexer.event.TMouseEvent;
38
39 /**
40 * TStatusBar implements a status line with clickable buttons.
41 */
42 public final class TStatusBar extends TWidget {
43
44 /**
45 * A single shortcut key.
46 */
47 private class TStatusBarKey {
48
49 /**
50 * The keypress for this action.
51 */
52 public TKeypress key;
53
54 /**
55 * The command to issue.
56 */
57 public TCommand cmd;
58
59 /**
60 * The label text.
61 */
62 public String label;
63
64 /**
65 * If true, the mouse is on this key.
66 */
67 public boolean selected;
68
69 /**
70 * The left edge coordinate to draw this key with.
71 */
72 public int x = 0;
73
74 /**
75 * The width of this key on the screen.
76 *
77 * @return the number of columns this takes when drawn
78 */
79 public int width() {
80 return this.label.length() + this.key.toString().length() + 3;
81 }
82
83 /**
84 * Add a key to this status bar.
85 *
86 * @param key the key to trigger on
87 * @param cmd the command event to issue when key is pressed or this
88 * item is clicked
89 * @param label the label for this action
90 */
91 public TStatusBarKey(final TKeypress key, final TCommand cmd,
92 final String label) {
93
94 this.key = key;
95 this.cmd = cmd;
96 this.label = label;
97 }
98
99 }
100
101 /**
102 * Remember mouse state.
103 */
104 private TMouseEvent mouse;
105
106 /**
107 * The text to display on the right side of the shortcut keys.
108 */
109 private String text = null;
110
111 /**
112 * The shortcut keys.
113 */
114 private ArrayList<TStatusBarKey> keys = new ArrayList<TStatusBarKey>();
115
116 /**
117 * Add a key to this status bar.
118 *
119 * @param key the key to trigger on
120 * @param cmd the command event to issue when key is pressed or this item
121 * is clicked
122 * @param label the label for this action
123 */
124 public void addShortcutKeypress(final TKeypress key, final TCommand cmd,
125 final String label) {
126
127 TStatusBarKey newKey = new TStatusBarKey(key, cmd, label);
128 if (keys.size() > 0) {
129 TStatusBarKey oldKey = keys.get(keys.size() - 1);
130 newKey.x = oldKey.x + oldKey.width();
131 }
132 keys.add(newKey);
133 }
134
135 /**
136 * Set the text to display on the right side of the shortcut keys.
137 *
138 * @param text the new text
139 */
140 public void setText(final String text) {
141 this.text = text;
142 }
143
144 /**
145 * Public constructor.
146 *
147 * @param parent parent widget
148 * @param text text for the bar on the bottom row
149 */
150 public TStatusBar(final TWidget parent, final String text) {
151
152 // Set parent and window
153 super(parent, false, 0, 0, text.length(), 1);
154
155 this.text = text;
156 }
157
158 /**
159 * Public constructor.
160 *
161 * @param parent parent widget
162 */
163 public TStatusBar(final TWidget parent) {
164 this(parent, "");
165 }
166
167 /**
168 * Draw the bar.
169 */
170 @Override
171 public void draw() {
172 CellAttributes barColor = new CellAttributes();
173 barColor.setTo(getTheme().getColor("tstatusbar.text"));
174 CellAttributes keyColor = new CellAttributes();
175 keyColor.setTo(getTheme().getColor("tstatusbar.button"));
176 CellAttributes selectedColor = new CellAttributes();
177 selectedColor.setTo(getTheme().getColor("tstatusbar.selected"));
178
179 // Status bar is weird. Its draw() method is called directly by
180 // TApplication after everything is drawn, and after
181 // Screen.resetClipping(). So at this point we are drawing in
182 // absolute coordinates, not relative to our TWindow.
183 int row = getScreen().getHeight() - 1;
184 int width = getScreen().getWidth();
185
186 getScreen().hLineXY(0, row, width, ' ', barColor);
187
188 int col = 0;
189 for (TStatusBarKey key: keys) {
190 String keyStr = key.key.toString();
191 if (key.selected) {
192 getScreen().putCharXY(col++, row, ' ', selectedColor);
193 getScreen().putStringXY(col, row, keyStr, selectedColor);
194 col += keyStr.length();
195 getScreen().putCharXY(col++, row, ' ', selectedColor);
196 getScreen().putStringXY(col, row, key.label, selectedColor);
197 col += key.label.length();
198 getScreen().putCharXY(col++, row, ' ', selectedColor);
199 } else {
200 getScreen().putCharXY(col++, row, ' ', barColor);
201 getScreen().putStringXY(col, row, keyStr, keyColor);
202 col += keyStr.length() + 1;
203 getScreen().putStringXY(col, row, key.label, barColor);
204 col += key.label.length();
205 getScreen().putCharXY(col++, row, ' ', barColor);
206 }
207 }
208 if (text.length() > 0) {
209 if (keys.size() > 0) {
210 getScreen().putCharXY(col++, row, GraphicsChars.VERTICAL_BAR,
211 barColor);
212 }
213 getScreen().putCharXY(col++, row, ' ', barColor);
214 getScreen().putStringXY(col, row, text, barColor);
215 }
216 }
217
218 /**
219 * Handle keypresses.
220 *
221 * @param keypress keystroke event
222 * @return true if this keypress was consumed
223 */
224 public boolean statusBarKeypress(final TKeypressEvent keypress) {
225 for (TStatusBarKey key: keys) {
226 if (keypress.equals(key.key)) {
227 getApplication().postMenuEvent(new TCommandEvent(key.cmd));
228 return true;
229 }
230 }
231 return false;
232 }
233
234 /**
235 * Returns true if the mouse is currently on the button.
236 *
237 * @param statusBarKey the status bar item
238 * @return if true the mouse is currently on the button
239 */
240 private boolean mouseOnShortcut(final TStatusBarKey statusBarKey) {
241 if ((mouse != null)
242 && (mouse.getAbsoluteY() == getApplication().getDesktopBottom())
243 && (mouse.getAbsoluteX() >= statusBarKey.x)
244 && (mouse.getAbsoluteX() < statusBarKey.x + statusBarKey.width())
245 ) {
246 return true;
247 }
248 return false;
249 }
250
251 /**
252 * Handle mouse button presses.
253 *
254 * @param mouse mouse button event
255 * @return true if this mouse event was consumed
256 */
257 public boolean statusBarMouseDown(final TMouseEvent mouse) {
258 this.mouse = mouse;
259
260 for (TStatusBarKey key: keys) {
261 if ((mouseOnShortcut(key)) && (mouse.isMouse1())) {
262 key.selected = true;
263 return true;
264 }
265 }
266 return false;
267 }
268
269 /**
270 * Handle mouse button releases.
271 *
272 * @param mouse mouse button release event
273 * @return true if this mouse event was consumed
274 */
275 public boolean statusBarMouseUp(final TMouseEvent mouse) {
276 this.mouse = mouse;
277
278 for (TStatusBarKey key: keys) {
279 if (key.selected && mouse.isMouse1()) {
280 key.selected = false;
281
282 // Dispatch the event
283 getApplication().postMenuEvent(new TCommandEvent(key.cmd));
284 return true;
285 }
286 }
287 return false;
288 }
289
290 /**
291 * Handle mouse movements.
292 *
293 * @param mouse mouse motion event
294 */
295 public void statusBarMouseMotion(final TMouseEvent mouse) {
296 this.mouse = mouse;
297
298 for (TStatusBarKey key: keys) {
299 if (!mouseOnShortcut(key)) {
300 key.selected = false;
301 }
302 }
303 }
304
305 }