window focus events and enable/disable menu items
[nikiroo-utils.git] / src / jexer / menu / TMenuItem.java
1 /*
2 * Jexer - Java Text User Interface
3 *
4 * License: LGPLv3 or later
5 *
6 * This module is licensed under the GNU Lesser General Public License
7 * Version 3. Please see the file "COPYING" in this directory for more
8 * information about the GNU Lesser General Public License Version 3.
9 *
10 * Copyright (C) 2015 Kevin Lamonte
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 3 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, see
24 * http://www.gnu.org/licenses/, or write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * 02110-1301 USA
27 *
28 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 * @version 1
30 */
31 package jexer.menu;
32
33 import jexer.TKeypress;
34 import jexer.TWidget;
35 import jexer.bits.CellAttributes;
36 import jexer.bits.GraphicsChars;
37 import jexer.bits.MnemonicString;
38 import jexer.event.TKeypressEvent;
39 import jexer.event.TMouseEvent;
40 import jexer.event.TMenuEvent;
41 import static jexer.TKeypress.*;
42
43 /**
44 * TMenuItem implements a menu item.
45 */
46 public class TMenuItem extends TWidget {
47
48 /**
49 * Label for this menu item.
50 */
51 private String label;
52
53 /**
54 * Menu ID. IDs less than 1024 are reserved for common system
55 * functions. Existing ones are defined in TMenu, i.e. TMenu.MID_EXIT.
56 */
57 private int id = TMenu.MID_UNUSED;
58
59 /**
60 * Get the menu item ID.
61 *
62 * @return the id
63 */
64 public final int getId() {
65 return id;
66 }
67
68 /**
69 * When true, this item can be checked or unchecked.
70 */
71 private boolean checkable = false;
72
73 /**
74 * Set checkable flag.
75 *
76 * @param checkable if true, this menu item can be checked/unchecked
77 */
78 public final void setCheckable(final boolean checkable) {
79 this.checkable = checkable;
80 }
81
82 /**
83 * When true, this item is checked.
84 */
85 private boolean checked = false;
86
87 /**
88 * Global shortcut key.
89 */
90 private TKeypress key;
91
92 /**
93 * The title string. Use '&' to specify a mnemonic, i.e. "&File" will
94 * highlight the 'F' and allow 'f' or 'F' to select it.
95 */
96 private MnemonicString mnemonic;
97
98 /**
99 * Get the mnemonic string for this menu item.
100 *
101 * @return mnemonic string
102 */
103 public final MnemonicString getMnemonic() {
104 return mnemonic;
105 }
106
107 /**
108 * Get a global accelerator key for this menu item.
109 *
110 * @return global keyboard accelerator, or null if no key is associated
111 * with this item
112 */
113 public final TKeypress getKey() {
114 return key;
115 }
116
117 /**
118 * Set a global accelerator key for this menu item.
119 *
120 * @param key global keyboard accelerator
121 */
122 public final void setKey(final TKeypress key) {
123 this.key = key;
124
125 if (key != null) {
126 int newWidth = (label.length() + 4 + key.toString().length() + 2);
127 if (newWidth > getWidth()) {
128 setWidth(newWidth);
129 }
130 }
131 }
132
133 /**
134 * Package private constructor.
135 *
136 * @param parent parent widget
137 * @param id menu id
138 * @param x column relative to parent
139 * @param y row relative to parent
140 * @param label menu item title
141 */
142 TMenuItem(final TMenu parent, final int id, final int x, final int y,
143 final String label) {
144
145 // Set parent and window
146 super(parent);
147
148 mnemonic = new MnemonicString(label);
149
150 setX(x);
151 setY(y);
152 setHeight(1);
153 this.label = mnemonic.getRawLabel();
154 setWidth(label.length() + 4);
155 this.id = id;
156
157 // Default state for some known menu items
158 switch (id) {
159
160 case TMenu.MID_CUT:
161 setEnabled(false);
162 break;
163 case TMenu.MID_COPY:
164 setEnabled(false);
165 break;
166 case TMenu.MID_PASTE:
167 setEnabled(false);
168 break;
169 case TMenu.MID_CLEAR:
170 setEnabled(false);
171 break;
172
173 case TMenu.MID_TILE:
174 break;
175 case TMenu.MID_CASCADE:
176 break;
177 case TMenu.MID_CLOSE_ALL:
178 break;
179 case TMenu.MID_WINDOW_MOVE:
180 break;
181 case TMenu.MID_WINDOW_ZOOM:
182 break;
183 case TMenu.MID_WINDOW_NEXT:
184 break;
185 case TMenu.MID_WINDOW_PREVIOUS:
186 break;
187 case TMenu.MID_WINDOW_CLOSE:
188 break;
189 default:
190 break;
191 }
192
193 }
194
195 /**
196 * Returns true if the mouse is currently on the menu item.
197 *
198 * @param mouse mouse event
199 */
200 private boolean mouseOnMenuItem(final TMouseEvent mouse) {
201 if ((mouse.getY() == 0)
202 && (mouse.getX() >= 0)
203 && (mouse.getX() < getWidth())
204 ) {
205 return true;
206 }
207 return false;
208 }
209
210 /**
211 * Draw a menu item with label.
212 */
213 @Override
214 public void draw() {
215 CellAttributes background = getTheme().getColor("tmenu");
216 CellAttributes menuColor;
217 CellAttributes menuMnemonicColor;
218 if (isAbsoluteActive()) {
219 menuColor = getTheme().getColor("tmenu.highlighted");
220 menuMnemonicColor = getTheme().getColor("tmenu.mnemonic.highlighted");
221 } else {
222 if (isEnabled()) {
223 menuColor = getTheme().getColor("tmenu");
224 menuMnemonicColor = getTheme().getColor("tmenu.mnemonic");
225 } else {
226 menuColor = getTheme().getColor("tmenu.disabled");
227 menuMnemonicColor = getTheme().getColor("tmenu.disabled");
228 }
229 }
230
231 char cVSide = GraphicsChars.WINDOW_SIDE;
232 getScreen().vLineXY(0, 0, 1, cVSide, background);
233 getScreen().vLineXY(getWidth() - 1, 0, 1, cVSide, background);
234
235 getScreen().hLineXY(1, 0, getWidth() - 2, ' ', menuColor);
236 getScreen().putStringXY(2, 0, mnemonic.getRawLabel(), menuColor);
237 if (key != null) {
238 String keyLabel = key.toString();
239 getScreen().putStringXY((getWidth() - keyLabel.length() - 2), 0,
240 keyLabel, menuColor);
241 }
242 if (mnemonic.getShortcutIdx() >= 0) {
243 getScreen().putCharXY(2 + mnemonic.getShortcutIdx(), 0,
244 mnemonic.getShortcut(), menuMnemonicColor);
245 }
246 if (checked) {
247 assert (checkable);
248 getScreen().putCharXY(1, 0, GraphicsChars.CHECK, menuColor);
249 }
250
251 }
252
253 /**
254 * Dispatch event(s) due to selection or click.
255 */
256 public void dispatch() {
257 assert (isEnabled());
258
259 getApplication().addMenuEvent(new TMenuEvent(id));
260 if (checkable) {
261 checked = !checked;
262 }
263 }
264
265 /**
266 * Handle mouse button presses.
267 *
268 * @param event mouse button press event
269 */
270 /* TODO: this was commented out in d-tui, why?
271 @Override
272 public void onMouseDown(final TMouseEvent event) {
273 if ((mouseOnMenuItem(event)) && (event.mouse1)) {
274 dispatch();
275 return;
276 }
277 }
278 */
279
280 /**
281 * Handle mouse button releases.
282 *
283 * @param mouse mouse button release event
284 */
285 @Override
286 public void onMouseUp(final TMouseEvent mouse) {
287 if ((mouseOnMenuItem(mouse)) && (mouse.isMouse1())) {
288 dispatch();
289 return;
290 }
291 }
292
293 /**
294 * Handle keystrokes.
295 *
296 * @param keypress keystroke event
297 */
298 @Override
299 public void onKeypress(final TKeypressEvent keypress) {
300 if (keypress.equals(kbEnter)) {
301 dispatch();
302 return;
303 }
304
305 // Pass to parent for the things we don't care about.
306 super.onKeypress(keypress);
307 }
308 }