Many changes:
[fanfix.git] / src / jexer / TStatusBar.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 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 getScreen().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 getScreen().putCharXY(col++, row, ' ', selectedColor);
269 getScreen().putStringXY(col, row, keyStr, selectedColor);
270 col += keyStr.length();
271 getScreen().putCharXY(col++, row, ' ', selectedColor);
272 getScreen().putStringXY(col, row, key.label, selectedColor);
273 col += key.label.length();
274 getScreen().putCharXY(col++, row, ' ', selectedColor);
275 } else {
276 getScreen().putCharXY(col++, row, ' ', barColor);
277 getScreen().putStringXY(col, row, keyStr, keyColor);
278 col += keyStr.length() + 1;
279 getScreen().putStringXY(col, row, key.label, barColor);
280 col += key.label.length();
281 getScreen().putCharXY(col++, row, ' ', barColor);
282 }
283 }
284 if (text.length() > 0) {
285 if (keys.size() > 0) {
286 getScreen().putCharXY(col++, row, GraphicsChars.VERTICAL_BAR,
287 barColor);
288 }
289 getScreen().putCharXY(col++, row, ' ', barColor);
290 getScreen().putStringXY(col, row, text, barColor);
291 }
292 }
293
294 // ------------------------------------------------------------------------
295 // TStatusBar -------------------------------------------------------------
296 // ------------------------------------------------------------------------
297
298 /**
299 * Add a key to this status bar.
300 *
301 * @param key the key to trigger on
302 * @param cmd the command event to issue when key is pressed or this item
303 * is clicked
304 * @param label the label for this action
305 */
306 public void addShortcutKeypress(final TKeypress key, final TCommand cmd,
307 final String label) {
308
309 TStatusBarKey newKey = new TStatusBarKey(key, cmd, label);
310 if (keys.size() > 0) {
311 TStatusBarKey oldKey = keys.get(keys.size() - 1);
312 newKey.x = oldKey.x + oldKey.width();
313 }
314 keys.add(newKey);
315 }
316
317 /**
318 * Set the text to display on the right side of the shortcut keys.
319 *
320 * @param text the new text
321 */
322 public void setText(final String text) {
323 this.text = text;
324 }
325
326 }