#34 call onResize() when window size is changed
[fanfix.git] / src / jexer / TMessageBox.java
CommitLineData
daa4106c 1/*
c6940ed9
KL
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
c6940ed9 5 *
a2018e99 6 * Copyright (C) 2017 Kevin Lamonte
c6940ed9 7 *
e16dda65
KL
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:
c6940ed9 14 *
e16dda65
KL
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
c6940ed9 17 *
e16dda65
KL
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.
c6940ed9
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
31import java.util.ArrayList;
32import java.util.List;
339652cc 33import java.util.ResourceBundle;
c6940ed9 34
91c9a837
KL
35import jexer.event.TKeypressEvent;
36import static jexer.TKeypress.*;
37
c6940ed9
KL
38/**
39 * TMessageBox is a system-modal dialog with buttons for OK, Cancel, Yes, or
40 * No. Call it like:
41 *
c6940ed9
KL
42 * <pre>
43 * {@code
44 * box = application.messageBox(title, caption,
45 * TMessageBox.Type.OK | TMessageBox.Type.CANCEL);
46 *
47 * if (box.getResult() == TMessageBox.OK) {
48 * ... the user pressed OK, do stuff ...
49 * }
50 * }
51 * </pre>
52 *
53 */
54public class TMessageBox extends TWindow {
55
339652cc
KL
56 /**
57 * Translated strings.
58 */
59 private static final ResourceBundle i18n = ResourceBundle.getBundle(TMessageBox.class.getName());
60
c6940ed9
KL
61 /**
62 * Message boxes have these supported types.
63 */
64 public enum Type {
65 /**
66 * Show an OK button.
67 */
68 OK,
69
70 /**
71 * Show both OK and Cancel buttons.
72 */
73 OKCANCEL,
74
75 /**
76 * Show both Yes and No buttons.
77 */
78 YESNO,
79
80 /**
81 * Show Yes, No, and Cancel buttons.
82 */
83 YESNOCANCEL
84 };
85
91c9a837
KL
86 /**
87 * The type of this message box.
88 */
89 private Type type;
90
91 /**
92 * My buttons.
93 */
329fd62e 94 private List<TButton> buttons;
91c9a837 95
c6940ed9
KL
96 /**
97 * Message boxes have these possible results.
98 */
99 public enum Result {
100 /**
101 * User clicked "OK".
102 */
103 OK,
104
105 /**
106 * User clicked "Cancel".
107 */
108 CANCEL,
109
110 /**
111 * User clicked "Yes".
112 */
113 YES,
114
115 /**
116 * User clicked "No".
117 */
118 NO
119 };
120
c6940ed9
KL
121 /**
122 * Which button was clicked: OK, CANCEL, YES, or NO.
123 */
124 private Result result = Result.OK;
125
126 /**
127 * Get the result.
128 *
129 * @return the result: OK, CANCEL, YES, or NO.
130 */
131 public final Result getResult() {
132 return result;
133 }
134
135 /**
136 * Public constructor. The message box will be centered on screen.
137 *
138 * @param application TApplication that manages this window
139 * @param title window title, will be centered along the top border
140 * @param caption message to display. Use embedded newlines to get a
141 * multi-line box.
142 */
143 public TMessageBox(final TApplication application, final String title,
144 final String caption) {
145
146 this(application, title, caption, Type.OK, true);
147 }
148
149 /**
150 * Public constructor. The message box will be centered on screen.
151 *
152 * @param application TApplication that manages this window
153 * @param title window title, will be centered along the top border
154 * @param caption message to display. Use embedded newlines to get a
155 * multi-line box.
156 * @param type one of the Type constants. Default is Type.OK.
157 */
158 public TMessageBox(final TApplication application, final String title,
159 final String caption, final Type type) {
160
161 this(application, title, caption, type, true);
162 }
163
164 /**
165 * Public constructor. The message box will be centered on screen.
166 *
167 * @param application TApplication that manages this window
168 * @param title window title, will be centered along the top border
169 * @param caption message to display. Use embedded newlines to get a
170 * multi-line box.
171 * @param type one of the Type constants. Default is Type.OK.
172 * @param yield if true, yield this Thread. Subclasses need to set this
173 * to false and yield at their end of their constructor intead.
174 */
175 protected TMessageBox(final TApplication application, final String title,
176 final String caption, final Type type, final boolean yield) {
177
178 // Start as 50x50 at (1, 1). These will be changed later.
179 super(application, title, 1, 1, 100, 100, CENTERED | MODAL);
180
91c9a837
KL
181 // Hang onto type so that we can provide more convenience in
182 // onKeypress().
183 this.type = type;
184
c6940ed9
KL
185 // Determine width and height
186 String [] lines = caption.split("\n");
187 int width = title.length() + 12;
188 setHeight(6 + lines.length);
189 for (String line: lines) {
190 if (line.length() + 4 > width) {
191 width = line.length() + 4;
192 }
193 }
194 setWidth(width);
195 if (getWidth() > getScreen().getWidth()) {
196 setWidth(getScreen().getWidth());
197 }
198 // Re-center window to get an appropriate (x, y)
199 center();
200
201 // Now add my elements
202 int lineI = 1;
203 for (String line: lines) {
204 addLabel(line, 1, lineI, "twindow.background.modal");
205 lineI++;
206 }
207
208 // The button line
209 lineI++;
91c9a837 210 buttons = new ArrayList<TButton>();
c6940ed9
KL
211
212 int buttonX = 0;
213
214 // Setup button actions
215 switch (type) {
216
217 case OK:
218 result = Result.OK;
219 if (getWidth() < 15) {
220 setWidth(15);
221 }
222 buttonX = (getWidth() - 11) / 2;
339652cc 223 buttons.add(addButton(i18n.getString("okButton"), buttonX, lineI,
c6940ed9
KL
224 new TAction() {
225 public void DO() {
226 result = Result.OK;
227 getApplication().closeWindow(TMessageBox.this);
228 }
229 }
230 )
231 );
232 break;
233
234 case OKCANCEL:
235 result = Result.CANCEL;
236 if (getWidth() < 26) {
237 setWidth(26);
238 }
239 buttonX = (getWidth() - 22) / 2;
339652cc 240 buttons.add(addButton(i18n.getString("okButton"), buttonX, lineI,
c6940ed9
KL
241 new TAction() {
242 public void DO() {
243 result = Result.OK;
244 getApplication().closeWindow(TMessageBox.this);
245 }
246 }
247 )
248 );
249 buttonX += 8 + 4;
339652cc 250 buttons.add(addButton(i18n.getString("cancelButton"), buttonX, lineI,
c6940ed9
KL
251 new TAction() {
252 public void DO() {
253 result = Result.CANCEL;
254 getApplication().closeWindow(TMessageBox.this);
255 }
256 }
257 )
258 );
259 break;
260
261 case YESNO:
262 result = Result.NO;
263 if (getWidth() < 20) {
264 setWidth(20);
265 }
266 buttonX = (getWidth() - 16) / 2;
339652cc 267 buttons.add(addButton(i18n.getString("yesButton"), buttonX, lineI,
c6940ed9
KL
268 new TAction() {
269 public void DO() {
270 result = Result.YES;
271 getApplication().closeWindow(TMessageBox.this);
272 }
273 }
274 )
275 );
276 buttonX += 5 + 4;
339652cc 277 buttons.add(addButton(i18n.getString("noButton"), buttonX, lineI,
c6940ed9
KL
278 new TAction() {
279 public void DO() {
280 result = Result.NO;
281 getApplication().closeWindow(TMessageBox.this);
282 }
283 }
284 )
285 );
286 break;
287
288 case YESNOCANCEL:
289 result = Result.CANCEL;
290 if (getWidth() < 31) {
291 setWidth(31);
292 }
293 buttonX = (getWidth() - 27) / 2;
339652cc 294 buttons.add(addButton(i18n.getString("yesButton"), buttonX, lineI,
c6940ed9
KL
295 new TAction() {
296 public void DO() {
297 result = Result.YES;
298 getApplication().closeWindow(TMessageBox.this);
299 }
300 }
301 )
302 );
303 buttonX += 5 + 4;
339652cc 304 buttons.add(addButton(i18n.getString("noButton"), buttonX, lineI,
c6940ed9
KL
305 new TAction() {
306 public void DO() {
307 result = Result.NO;
308 getApplication().closeWindow(TMessageBox.this);
309 }
310 }
311 )
312 );
313 buttonX += 4 + 4;
339652cc
KL
314 buttons.add(addButton(i18n.getString("cancelButton"), buttonX,
315 lineI,
c6940ed9
KL
316 new TAction() {
317 public void DO() {
318 result = Result.CANCEL;
319 getApplication().closeWindow(TMessageBox.this);
320 }
321 }
322 )
323 );
324 break;
325
326 default:
327 throw new IllegalArgumentException("Invalid message box type: " + type);
328 }
329
330 // Set the secondaryThread to run me
331 getApplication().enableSecondaryEventReceiver(this);
332
333 if (yield) {
334 // Yield to the secondary thread. When I come back from the
335 // constructor response will already be set.
336 getApplication().yield();
337 }
338 }
339
91c9a837
KL
340 /**
341 * Handle keystrokes.
342 *
343 * @param keypress keystroke event
344 */
345 @Override
346 public void onKeypress(final TKeypressEvent keypress) {
347
348 if (this instanceof TInputBox) {
349 super.onKeypress(keypress);
350 return;
351 }
352
353 // Some convenience for message boxes: Alt won't be needed for the
354 // buttons.
355 switch (type) {
356
357 case OK:
358 if (keypress.equals(kbO)) {
359 buttons.get(0).dispatch();
360 return;
361 }
362 break;
363
364 case OKCANCEL:
365 if (keypress.equals(kbO)) {
366 buttons.get(0).dispatch();
367 return;
368 } else if (keypress.equals(kbC)) {
369 buttons.get(1).dispatch();
370 return;
371 }
372 break;
373
374 case YESNO:
375 if (keypress.equals(kbY)) {
376 buttons.get(0).dispatch();
377 return;
378 } else if (keypress.equals(kbN)) {
379 buttons.get(1).dispatch();
380 return;
381 }
382 break;
383
384 case YESNOCANCEL:
385 if (keypress.equals(kbY)) {
386 buttons.get(0).dispatch();
387 return;
388 } else if (keypress.equals(kbN)) {
389 buttons.get(1).dispatch();
390 return;
391 } else if (keypress.equals(kbC)) {
392 buttons.get(2).dispatch();
393 return;
394 }
395 break;
396
397 default:
398 throw new IllegalArgumentException("Invalid message box type: " + type);
399 }
400
401 super.onKeypress(keypress);
402 }
403
c6940ed9 404}