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