themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / fl_ask.cxx
bloba9bb1803c04fae68bece4ea04a26e54eeb67e831
1 //
2 // "$Id: fl_ask.cxx 8616 2011-04-20 14:54:42Z AlbrechtS $"
3 //
4 // Standard dialog functions for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2011 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 // Implementation of fl_message, fl_ask, fl_choice, fl_input
29 // The three-message fl_show_x functions are for forms compatibility
30 // mostly. In most cases it is easier to get a multi-line message
31 // by putting newlines in the message.
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include "flstring.h"
37 #include <FL/Fl.H>
39 #include <FL/fl_ask.H>
41 #include <FL/Fl_Box.H>
42 #include <FL/Fl_Button.H>
43 #include <FL/Fl_Return_Button.H>
44 #include <FL/Fl_Window.H>
45 #include <FL/Fl_Input.H>
46 #include <FL/Fl_Secret_Input.H>
47 #include <FL/x.H>
48 #include <FL/fl_draw.H>
50 static Fl_Window *message_form;
51 static Fl_Box *message;
52 static Fl_Box *icon;
53 static Fl_Button *button[3];
54 static Fl_Input *input;
55 static int ret_val;
56 static const char *iconlabel = "?";
57 static const char *message_title_default;
58 Fl_Font fl_message_font_ = FL_HELVETICA;
59 Fl_Fontsize fl_message_size_ = -1;
60 static int enableHotspot = 1;
61 #ifdef __APPLE__
62 extern "C" void NSBeep(void);
63 #endif
65 static char avoidRecursion = 0;
67 // Sets the global return value (ret_val) and closes the window.
68 // Note: this is used for the button callbacks and the window
69 // callback (closing the window with the close button or menu).
70 // The first argument (Fl_Widget *) can either be an Fl_Button*
71 // pointer to one of the buttons or an Fl_Window* pointer to the
72 // message window (message_form).
73 static void button_cb(Fl_Widget *, void *val) {
74 ret_val = (fl_intptr_t)val;
75 message_form->hide();
78 static Fl_Window *makeform() {
79 if (message_form) {
80 message_form->size(410,103);
81 return message_form;
83 // make sure that the dialog does not become the child of some
84 // current group
85 Fl_Group *previously_current_group = Fl_Group::current();
86 Fl_Group::current(0);
87 // create a new top level window
88 Fl_Window *w = message_form = new Fl_Window(410,103);
89 message_form->callback(button_cb,(void *)0);
90 // w->clear_border();
91 // w->box(FL_UP_BOX);
92 (message = new Fl_Box(60, 25, 340, 20))
93 ->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
94 (input = new Fl_Input(60, 37, 340, 23))->hide();
95 {Fl_Box* o = icon = new Fl_Box(10, 10, 50, 50);
96 o->box(FL_THIN_UP_BOX);
97 o->labelfont(FL_TIMES_BOLD);
98 o->labelsize(34);
99 o->color(FL_WHITE);
100 o->labelcolor(FL_BLUE);
102 w->end(); // don't add the buttons automatically
103 // create the buttons (right to left)
104 for (int b=0, x=310; b<3; b++, x -= 100) {
105 if (b==1)
106 button[b] = new Fl_Return_Button(x, 70, 90, 23);
107 else
108 button[b] = new Fl_Button(x, 70, 90, 23);
109 button[b]->align(FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
110 button[b]->callback(button_cb,(void *)b);
112 button[0]->shortcut(FL_Escape);
113 // add the buttons (left to right)
114 for (int b=2; b>=0; b--)
115 w->add(button[b]);
116 w->begin();
117 w->resizable(new Fl_Box(60,10,110-60,27));
118 w->end();
119 w->set_modal();
120 Fl_Group::current(previously_current_group);
121 return w;
125 * 'resizeform()' - Resize the form and widgets so that they hold everything
126 * that is asked of them...
129 void resizeform() {
130 int i;
131 int message_w, message_h;
132 int text_height;
133 int button_w[3], button_h[3];
134 int x, w, h, max_w, max_h;
135 const int icon_size = 50;
137 fl_font(message->labelfont(), message->labelsize());
138 message_w = message_h = 0;
139 fl_measure(message->label(), message_w, message_h);
141 message_w += 10;
142 message_h += 10;
143 if (message_w < 340)
144 message_w = 340;
145 if (message_h < 30)
146 message_h = 30;
148 fl_font(button[0]->labelfont(), button[0]->labelsize());
150 memset(button_w, 0, sizeof(button_w));
151 memset(button_h, 0, sizeof(button_h));
153 for (max_h = 25, i = 0; i < 3; i ++)
154 if (button[i]->visible())
156 fl_measure(button[i]->label(), button_w[i], button_h[i]);
158 if (i == 1)
159 button_w[1] += 20;
161 button_w[i] += 30;
162 button_h[i] += 10;
164 if (button_h[i] > max_h)
165 max_h = button_h[i];
168 if (input->visible()) text_height = message_h + 25;
169 else text_height = message_h;
171 max_w = message_w + 10 + icon_size;
172 w = button_w[0] + button_w[1] + button_w[2] - 10;
174 if (w > max_w)
175 max_w = w;
177 message_w = max_w - 10 - icon_size;
179 w = max_w + 20;
180 h = max_h + 30 + text_height;
182 message_form->size(w, h);
183 message_form->size_range(w, h, w, h);
185 message->resize(20 + icon_size, 10, message_w, message_h);
186 icon->resize(10, 10, icon_size, icon_size);
187 icon->labelsize(icon_size - 10);
188 input->resize(20 + icon_size, 10 + message_h, message_w, 25);
190 for (x = w, i = 0; i < 3; i ++)
191 if (button_w[i])
193 x -= button_w[i];
194 button[i]->resize(x, h - 10 - max_h, button_w[i] - 10, max_h);
196 // printf("button %d (%s) is %dx%d+%d,%d\n", i, button[i]->label(),
197 // button[i]->w(), button[i]->h(),
198 // button[i]->x(), button[i]->y());
202 static int innards(const char* fmt, va_list ap,
203 const char *b0,
204 const char *b1,
205 const char *b2)
207 Fl::pushed(0); // stop dragging (STR #2159)
209 avoidRecursion = 1;
211 makeform();
212 char buffer[1024];
213 if (!strcmp(fmt,"%s")) {
214 message->label(va_arg(ap, const char*));
215 } else {
216 ::vsnprintf(buffer, 1024, fmt, ap);
217 message->label(buffer);
220 message->labelfont(fl_message_font_);
221 if (fl_message_size_ == -1)
222 message->labelsize(FL_NORMAL_SIZE);
223 else
224 message->labelsize(fl_message_size_);
225 if (b0) {button[0]->show(); button[0]->label(b0); button[1]->position(210,70);}
226 else {button[0]->hide(); button[1]->position(310,70);}
227 if (b1) {button[1]->show(); button[1]->label(b1);}
228 else button[1]->hide();
229 if (b2) {button[2]->show(); button[2]->label(b2);}
230 else button[2]->hide();
231 const char* prev_icon_label = icon->label();
232 if (!prev_icon_label) icon->label(iconlabel);
234 resizeform();
236 if (button[1]->visible() && !input->visible())
237 button[1]->take_focus();
238 if (enableHotspot)
239 message_form->hotspot(button[0]);
240 if (b0 && Fl_Widget::label_shortcut(b0))
241 button[0]->shortcut(0);
242 else
243 button[0]->shortcut(FL_Escape);
245 // set default window title, if defined and a specific title is not set
246 if (!message_form->label() && message_title_default)
247 message_form->label(message_title_default);
249 // deactivate Fl::grab(), because it is incompatible with modal windows
250 Fl_Window* g = Fl::grab();
251 if (g) Fl::grab(0);
252 message_form->show();
253 while (message_form->shown()) Fl::wait();
254 if (g) // regrab the previous popup menu, if there was one
255 Fl::grab(g);
256 icon->label(prev_icon_label);
257 message_form->label(0); // reset window title
259 avoidRecursion = 0;
260 return ret_val;
263 /** \addtogroup group_comdlg
264 @{ */
266 // pointers you can use to change FLTK to another language:
267 const char* fl_no = "No"; ///< string pointer used in common dialogs, you can change it to another language
268 const char* fl_yes= "Yes"; ///< string pointer used in common dialogs, you can change it to another language
269 const char* fl_ok = "OK"; ///< string pointer used in common dialogs, you can change it to another language
270 const char* fl_cancel= "Cancel"; ///< string pointer used in common dialogs, you can change it to another language
271 const char* fl_close= "Close"; ///< string pointer used in common dialogs, you can change it to another language
273 // fltk functions:
275 Emits a system beep message.
276 \note \#include <FL/fl_ask.H>
278 void fl_beep(int type) {
279 #if 0
280 /* disable beeping until it can be made optional. */
281 #ifdef WIN32
282 switch (type) {
283 case FL_BEEP_QUESTION :
284 case FL_BEEP_PASSWORD :
285 MessageBeep(MB_ICONQUESTION);
286 break;
287 case FL_BEEP_MESSAGE :
288 MessageBeep(MB_ICONASTERISK);
289 break;
290 case FL_BEEP_NOTIFICATION :
291 MessageBeep(MB_ICONASTERISK);
292 break;
293 case FL_BEEP_ERROR :
294 MessageBeep(MB_ICONERROR);
295 break;
296 default :
297 MessageBeep(0xFFFFFFFF);
298 break;
300 #elif defined(__APPLE__)
301 switch (type) {
302 case FL_BEEP_DEFAULT :
303 case FL_BEEP_ERROR :
304 NSBeep();
305 break;
306 default :
307 break;
309 #else
310 switch (type) {
311 case FL_BEEP_DEFAULT :
312 case FL_BEEP_ERROR :
313 if (!fl_display) fl_open_display();
315 XBell(fl_display, 100);
316 break;
317 default :
318 if (!fl_display) fl_open_display();
320 XBell(fl_display, 50);
321 break;
323 #endif // WIN32
324 #endif
327 /** Shows an information message dialog box.
329 \note Common dialog boxes are application modal. No more than one common dialog box
330 can be open at any time. Requests for additional dialog boxes are ignored.
331 \note \#include <FL/fl_ask.H>
334 \param[in] fmt can be used as an sprintf-like format and variables for the message text
336 void fl_message(const char *fmt, ...) {
338 if (avoidRecursion) return;
340 va_list ap;
342 fl_beep(FL_BEEP_MESSAGE);
344 va_start(ap, fmt);
345 iconlabel = "i";
346 innards(fmt, ap, 0, fl_close, 0);
347 va_end(ap);
348 iconlabel = "?";
351 /** Shows an alert message dialog box
353 \note Common dialog boxes are application modal. No more than one common dialog box
354 can be open at any time. Requests for additional dialog boxes are ignored.
355 \note \#include <FL/fl_ask.H>
357 \param[in] fmt can be used as an sprintf-like format and variables for the message text
359 void fl_alert(const char *fmt, ...) {
361 if (avoidRecursion) return;
363 va_list ap;
365 fl_beep(FL_BEEP_ERROR);
367 va_start(ap, fmt);
368 iconlabel = "!";
369 innards(fmt, ap, 0, fl_close, 0);
370 va_end(ap);
371 iconlabel = "?";
373 /** Shows a dialog displaying the \p fmt message,
374 this dialog features 2 yes/no buttons
376 \note Common dialog boxes are application modal. No more than one common dialog box
377 can be open at any time. Requests for additional dialog boxes are ignored.
378 \note \#include <FL/fl_ask.H>
380 \param[in] fmt can be used as an sprintf-like format and variables for the message text
381 \retval 0 if the no button is selected or another dialog box is still open
382 \retval 1 if yes is selected
384 int fl_ask(const char *fmt, ...) {
386 if (avoidRecursion) return 0;
388 va_list ap;
390 fl_beep(FL_BEEP_QUESTION);
392 va_start(ap, fmt);
393 int r = innards(fmt, ap, fl_no, fl_yes, 0);
394 va_end(ap);
396 return r;
399 /** Shows a dialog displaying the \p fmt message,
400 this dialog features up to 3 customizable choice buttons
402 \note Common dialog boxes are application modal. No more than one common dialog box
403 can be open at any time. Requests for additional dialog boxes are ignored.
404 \note \#include <FL/fl_ask.H>
406 \param[in] fmt can be used as an sprintf-like format and variables for the message text
407 \param[in] b0 text label of button 0
408 \param[in] b1 text label of button 1
409 \param[in] b2 text label of button 2
410 \retval 0 if the first button with \p b0 text is selected or another dialog box is still open
411 \retval 1 if the second button with \p b1 text is selected
412 \retval 2 if the third button with \p b2 text is selected
414 int fl_choice(const char*fmt,const char *b0,const char *b1,const char *b2,...){
416 if (avoidRecursion) return 0;
418 va_list ap;
420 fl_beep(FL_BEEP_QUESTION);
422 va_start(ap, b2);
423 int r = innards(fmt, ap, b0, b1, b2);
424 va_end(ap);
425 return r;
427 /** Gets the Fl_Box icon container of the current default dialog used in
428 many common dialogs like fl_message(), fl_alert(),
429 fl_ask(), fl_choice(), fl_input(), fl_password()
430 \note \#include <FL/fl_ask.H>
432 Fl_Widget *fl_message_icon() {makeform(); return icon;}
434 static const char* input_innards(const char* fmt, va_list ap,
435 const char* defstr, uchar type) {
436 makeform();
437 message->position(60,10);
438 input->type(type);
439 input->show();
440 input->value(defstr);
441 input->take_focus();
443 int r = innards(fmt, ap, fl_cancel, fl_ok, 0);
444 input->hide();
445 message->position(60,25);
446 return r ? input->value() : 0;
449 /** Shows an input dialog displaying the \p fmt message
451 \note Common dialog boxes are application modal. No more than one common dialog box
452 can be open at any time. Requests for additional dialog boxes are ignored.
453 \note \#include <FL/fl_ask.H>
455 \param[in] fmt can be used as an sprintf-like format and variables for the message text
456 \param[in] defstr defines the default returned string if no text is entered
457 \return the user string input if OK was pushed, NULL if Cancel was pushed or another dialog box was still open
459 const char* fl_input(const char *fmt, const char *defstr, ...) {
461 if (avoidRecursion) return 0;
463 fl_beep(FL_BEEP_QUESTION);
465 va_list ap;
466 va_start(ap, defstr);
467 const char* r = input_innards(fmt, ap, defstr, FL_NORMAL_INPUT);
468 va_end(ap);
469 return r;
472 /** Shows an input dialog displaying the \p fmt message.
474 Like fl_input() except the input text is not shown,
475 '*' characters are displayed instead.
477 \note Common dialog boxes are application modal. No more than one common dialog box
478 can be open at any time. Requests for additional dialog boxes are ignored.
479 \note \#include <FL/fl_ask.H>
481 \param[in] fmt can be used as an sprintf-like format and variables for the message text
482 \param[in] defstr defines the default returned string if no text is entered
483 \return the user string input if OK was pushed, NULL if Cancel was pushed or aother dialog box was still open
485 const char *fl_password(const char *fmt, const char *defstr, ...) {
487 if (avoidRecursion) return 0;
489 fl_beep(FL_BEEP_PASSWORD);
491 va_list ap;
492 va_start(ap, defstr);
493 const char* r = input_innards(fmt, ap, defstr, FL_SECRET_INPUT);
494 va_end(ap);
495 return r;
498 /** Sets whether or not to move the common message box used in
499 many common dialogs like fl_message(), fl_alert(),
500 fl_ask(), fl_choice(), fl_input(), fl_password() to follow
501 the mouse pointer.
503 The default is \e enabled, so that the default button is the
504 hotspot and appears at the mouse position.
505 \note \#include <FL/fl_ask.H>
506 \param[in] enable non-zero enables hotspot behavior,
507 0 disables hotspot
509 void fl_message_hotspot(int enable) {
510 enableHotspot = enable ? 1 : 0;
513 /** Gets whether or not to move the common message box used in
514 many common dialogs like fl_message(), fl_alert(),
515 fl_ask(), fl_choice(), fl_input(), fl_password() to follow
516 the mouse pointer.
517 \note \#include <FL/fl_ask.H>
518 \return 0 if disable, non-zero otherwise
519 \see fl_message_hotspot(int)
521 int fl_message_hotspot(void) {
522 return enableHotspot;
525 /** Sets the title of the dialog window used in many common dialogs.
527 This window \p title will be used in the next call of one of the
528 common dialogs like fl_message(), fl_alert(), fl_ask(), fl_choice(),
529 fl_input(), fl_password().
531 The \p title string is copied internally, so that you can use a
532 local variable or free the string immediately after this call. It
533 applies only to the \b next call of one of the common dialogs and
534 will be reset to an empty title (the default for all dialogs) after
535 that call.
537 \note \#include <FL/fl_ask.H>
538 \param[in] title window label, string copied internally
540 void fl_message_title(const char *title) {
541 makeform();
542 message_form->copy_label(title);
545 /** Sets the default title of the dialog window used in many common dialogs.
547 This window \p title will be used in all subsequent calls of one of the
548 common dialogs like fl_message(), fl_alert(), fl_ask(), fl_choice(),
549 fl_input(), fl_password(), unless a specific title has been set
550 with fl_message_title(const char *title).
552 The default is no title. You can override the default title for a
553 single dialog with fl_message_title(const char *title).
555 The \p title string is copied internally, so that you can use a
556 local variable or free the string immediately after this call.
558 \note \#include <FL/fl_ask.H>
559 \param[in] title default window label, string copied internally
561 void fl_message_title_default(const char *title) {
562 if (message_title_default) {
563 free ((void *)message_title_default);
564 message_title_default = 0;
566 if (title)
567 message_title_default = strdup(title);
570 /** @} */
573 // End of "$Id: fl_ask.cxx 8616 2011-04-20 14:54:42Z AlbrechtS $".