Dillo v3.2.0-170-gacf511bb
Loading...
Searching...
No Matches
dialog.cc
Go to the documentation of this file.
1/*
2 * File: dialog.cc
3 *
4 * Copyright (C) 2005-2007 Jorge Arellano Cid <jcid@dillo.org>
5 * Copyright (C) 2026 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
17#include <math.h> // for rint()
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21
22#include <FL/fl_ask.H>
23#include <FL/Fl_Window.H>
24#include <FL/Fl_File_Chooser.H>
25#include <FL/Fl_Return_Button.H>
26#include <FL/Fl_Text_Display.H>
27#include <FL/Fl_Button.H>
28#include <FL/Fl_Return_Button.H>
29#include <FL/Fl_Output.H>
30#include <FL/Fl_Input.H>
31#include <FL/Fl_Secret_Input.H>
32#include <FL/Fl_Choice.H>
33#include <FL/Fl_Menu_Item.H>
34
35#include "msg.h"
36#include "dialog.hh"
37#include "misc.h"
38#include "prefs.h"
39#include "dlib/dlib.h"
40
41/*
42 * Local Data
43 */
44static int input_answer;
45static char *input_str = NULL;
46static int choice_answer;
47
48
49/*
50 * Local sub classes
51 */
52
53//----------------------------------------------------------------------------
58class CustInput3 : public Fl_Input {
59public:
60 CustInput3 (int x, int y, int w, int h, const char* l=0) :
61 Fl_Input(x,y,w,h,l) {};
62 int handle(int e);
63 int d_position();
64 void d_position(int p);
65};
66
67/* FLTK 1.4 deprecated "position()" for "insert_position()", so we make
68 * a backward compatible wrapper. */
69int CustInput3::d_position()
70{
71#if FL_API_VERSION < 10400
72 return CustInput3::position();
73#else
74 return CustInput3::insert_position();
75#endif
76}
77
78void CustInput3::d_position(int p)
79{
80#if FL_API_VERSION < 10400
81 CustInput3::position(p);
82#else
83 CustInput3::insert_position(p);
84#endif
85}
86
87int CustInput3::handle(int e)
88{
89 int k = Fl::event_key();
90
91 _MSG("CustInput3::handle event=%d\n", e);
92
93 // We're only interested in some flags
94 unsigned modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT);
95
96 if (e == FL_KEYBOARD && modifier == FL_CTRL) {
97 if (k == 'a' || k == 'e') {
98 d_position(k == 'a' ? 0 : size());
99 return 1;
100 } else if (k == 'k') {
101 cut(d_position(), size());
102 return 1;
103 } else if (k == 'd') {
104 cut(d_position(), d_position()+1);
105 return 1;
106 }
107 }
108 return Fl_Input::handle(e);
109}
110
114class CustChoice2 : public Fl_Choice {
115public:
116 CustChoice2 (int x, int y, int w, int h, const char* l=0) :
117 Fl_Choice(x,y,w,h,l) {};
118 int handle(int e) {
119 if (e == FL_KEYBOARD &&
120 (Fl::event_key() == FL_Enter || Fl::event_key() == FL_Down) &&
121 (Fl::event_state() & (FL_SHIFT|FL_CTRL|FL_ALT|FL_META)) == 0) {
122 return Fl_Choice::handle(FL_PUSH);
123 }
124 return Fl_Choice::handle(e);
125 };
126};
127
128class EnterButton : public Fl_Button {
129public:
130 EnterButton (int x,int y,int w,int h, const char* label = 0) :
131 Fl_Button (x,y,w,h,label) {};
132 int handle(int e);
133};
134
135int EnterButton::handle(int e)
136{
137 if (e == FL_KEYBOARD && Fl::focus() == this && Fl::event_key() == FL_Enter){
138 set_changed();
139 simulate_key_action();
140 do_callback();
141 return 1;
142 }
143 return Fl_Button::handle(e);
144}
145
146//----------------------------------------------------------------------------
147
148
152void a_Dialog_msg(const char *title, const char *msg)
153{
154 if (!(title && *title))
155 title = "Dillo: Message";
156 fl_message_title(title);
157 fl_message("%s", msg);
158}
159
160
164static void input_cb(Fl_Widget *button, void *number)
165{
166 input_answer = VOIDP2INT(number);
167 button->window()->hide();
168}
169
176const char *a_Dialog_input(const char *title, const char *msg)
177{
178 static Fl_Menu_Item *pm = 0;
179 int ww = 450, wh = 130, gap = 10, ih = 60, bw = 80, bh = 30;
180
181 input_answer = 0;
182
183 if (!(title && *title))
184 title = "Dillo: Input";
185
186 Fl_Window *window = new Fl_Window(ww,wh,title);
187 window->set_modal();
188 window->begin();
189 Fl_Group* ib = new Fl_Group(0,0,window->w(),window->h());
190 ib->begin();
191 window->resizable(ib);
192
193 /* '?' Icon */
194 Fl_Box* o = new Fl_Box(gap, gap, ih, ih);
195 o->box(FL_THIN_UP_BOX);
196 o->labelfont(FL_TIMES_BOLD);
197 o->labelsize(34);
198 o->label("?");
199 o->show();
200
201 Fl_Box *box = new Fl_Box(ih+2*gap,gap,ww-(ih+3*gap),ih/2, msg);
202 box->labelfont(FL_HELVETICA);
203 box->labelsize(14);
204 box->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP|FL_ALIGN_WRAP);
205
206 CustInput3 *c_inp = new CustInput3(ih+2*gap,gap+ih/2+gap,ww-(ih+3*gap),24);
207 c_inp->labelsize(14);
208 c_inp->textsize(14);
209
210 CustChoice2 *ch = new CustChoice2(1*gap,ih+3*gap,180,24);
211 if (!pm) {
212 int n_it = dList_length(prefs.search_urls);
213 pm = (Fl_Menu_Item *) calloc(n_it+1, sizeof(Fl_Menu_Item));
214 if (pm == NULL) {
215 MSG("calloc failed: %s\n", strerror(errno));
216 exit(1);
217 }
218 for (int i = 0, j = 0; i < n_it; i++) {
219 char *label, *url, *source;
220 source = (char *)dList_nth_data(prefs.search_urls, i);
221 if (!source || a_Misc_parse_search_url(source, &label, &url) < 0)
222 continue;
223 pm[j++].label(FL_NORMAL_LABEL, dStrdup(label));
224 }
225 }
226 ch->tooltip("Select search engine");
227 ch->menu(pm);
228 ch->value(prefs.search_url_idx);
229
230 int xpos = ww-2*(gap+bw), ypos = ih+3*gap;
231 Fl_Return_Button *rb = new Fl_Return_Button(xpos, ypos, bw, bh, "OK");
232 rb->align(FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
233 rb->box(FL_UP_BOX);
234 rb->callback(input_cb, INT2VOIDP(1));
235
236 xpos = ww-(gap+bw);
237 Fl_Button *b = new Fl_Button(xpos, ypos, bw, bh, "Cancel");
238 b->align(FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
239 b->box(FL_UP_BOX);
240 b->callback(input_cb, INT2VOIDP(2));
241
242 window->end();
243
244 window->show();
245 while (window->shown())
246 Fl::wait();
247 if (input_answer == 1) {
248 /* we have a string, save it */
250 input_str = dStrdup(c_inp->value());
251 prefs.search_url_idx = ch->value();
252 }
253 delete window;
254
255 return (input_answer == 1) ? input_str : NULL;
256}
257
261const char *a_Dialog_passwd(const char *title, const char *msg)
262{
263 if (!(title && *title))
264 title = "Dillo: Password";
265 fl_message_title(title);
266 return fl_password("%s", "", msg);
267}
268
274const char *a_Dialog_save_file(const char *title,
275 const char *pattern, const char *fname)
276{
277 return fl_file_chooser(title, pattern, fname);
278}
279
285const char *a_Dialog_select_file(const char *title,
286 const char *pattern, const char *fname)
287{
288 /*
289 * FileChooser::type(MULTI) appears to allow multiple files to be selected,
290 * but just follow save_file's path for now.
291 */
292 return a_Dialog_save_file(title, pattern, fname);
293}
294
300char *a_Dialog_open_file(const char *title,
301 const char *pattern, const char *fname)
302{
303 const char *fc_name;
304
305 fc_name = fl_file_chooser(title, pattern, fname);
306 return (fc_name) ? a_Misc_escape_chars(fc_name, "% #") : NULL;
307}
308
312static void text_window_close_cb(Fl_Widget *, void *vtd)
313{
314 Fl_Text_Display *td = (Fl_Text_Display *)vtd;
315 Fl_Text_Buffer *buf = td->buffer();
316
317 delete (Fl_Window*)td->window();
318 delete buf;
319}
320
324void a_Dialog_text_window(const char *title, const char *txt)
325{
326 int wh = prefs.height, ww = prefs.width, bh = 30;
327
328 if (!(title && *title))
329 title = "Dillo: Text";
330
331 Fl_Window *window = new Fl_Window(ww, wh, title);
332 Fl_Group::current(0);
333
334
335 Fl_Text_Buffer *buf = new Fl_Text_Buffer();
336 buf->text(txt);
337 Fl_Text_Display *td = new Fl_Text_Display(0,0,ww, wh-bh);
338 td->buffer(buf);
339 td->textsize((int) rint(14.0 * prefs.font_factor));
340
341 /* enable wrapping lines; text uses entire width of window */
342 td->wrap_mode(Fl_Text_Display::WRAP_AT_BOUNDS, 0);
343 window->add(td);
344
345 Fl_Return_Button *b = new Fl_Return_Button (0, wh-bh, ww, bh, "Close");
346 b->callback(text_window_close_cb, td);
347 window->add(b);
348
349 window->callback(text_window_close_cb, td);
350 window->resizable(td);
351 window->show();
352}
353
354/*--------------------------------------------------------------------------*/
355
356static void choice_cb(Fl_Widget *button, void *number)
357{
358 choice_answer = VOIDP2INT(number);
359 _MSG("choice_cb: %d\n", choice_answer);
360
361 button->window()->hide();
362}
363
370int a_Dialog_choice(const char *title, const char *msg, ...)
371{
372 va_list ap;
373 int i, n;
374
375 if (title == NULL || *title == '\0')
376 title = "Dillo: Choice";
377
378 va_start(ap, msg);
379 for (n = 0; va_arg(ap, char *) != NULL; n++);
380 va_end(ap);
381
382 if (n == 0) {
383 MSG_ERR("Dialog_choice: no alternatives.\n");
384 return 0;
385 }
386
387 int gap = 8;
388 int ww = 140 + n * 60, wh = 120;
389 int bw = (ww - gap) / n - gap, bh = 45;
390
391 Fl_Window *window = new Fl_Window(ww, wh, title);
392 window->set_modal();
393 window->begin();
394
395 Fl_Text_Buffer *buf = new Fl_Text_Buffer();
396 buf->text(msg);
397 Fl_Text_Display *td = new Fl_Text_Display(0, 0, ww, wh - bh);
398 td->buffer(buf);
399 td->textsize((int) rint(14.0 * prefs.font_factor));
400 td->wrap_mode(Fl_Text_Display::WRAP_AT_BOUNDS, 0);
401
402 window->resizable(td);
403
404 int xpos = gap;
405 va_start(ap, msg);
406 for (i = 1; i <= n; i++) {
407 Fl_Button *b = new EnterButton(xpos, wh-bh, bw, bh, va_arg(ap, char *));
408 b->align(FL_ALIGN_WRAP | FL_ALIGN_CLIP);
409 b->box(FL_UP_BOX);
410 b->callback(choice_cb, INT2VOIDP(i));
411 xpos += bw + gap;
412 /* TODO: set focus to the *-prefixed alternative */
413 }
414 va_end(ap);
415 window->end();
416
417 choice_answer = 0;
418
419 window->show();
420 while (window->shown())
421 Fl::wait();
422 _MSG("Dialog_choice answer = %d\n", answer);
423 td->buffer(NULL);
424 delete buf;
425 delete window;
426
427 return choice_answer;
428}
429
430/*--------------------------------------------------------------------------*/
431static void Dialog_user_password_cb(Fl_Widget *button, void *)
432{
433 button->window()->user_data(button);
434 button->window()->hide();
435}
436
442int a_Dialog_user_password(const char *title, const char *msg,
443 UserPasswordCB cb, void *vp)
444{
445 int ok = 0, window_h = 280, y, msg_w, msg_h;
446 const int window_w = 300, input_x = 80, input_w = 200, input_h = 30,
447 button_h = 30;
448
449 /* window is resized below */
450 if (!(title && *title))
451 title = "Dillo: User/Password";
452 Fl_Window *window = new Fl_Window(window_w,window_h,title);
453 Fl_Group::current(0);
454 window->user_data(NULL);
455
456 /* message */
457 y = 20;
458 msg_w = window_w - 40;
459 Fl_Box *msg_box = new Fl_Box(20, y, msg_w, 100); /* resized below */
460 msg_box->label(msg);
461 msg_box->labelfont(FL_HELVETICA);
462 msg_box->labelsize(14);
463 msg_box->align(FL_ALIGN_INSIDE | FL_ALIGN_TOP_LEFT | FL_ALIGN_WRAP);
464
465 fl_font(msg_box->labelfont(), msg_box->labelsize());
466 msg_w -= 6; /* The label doesn't fill the entire box. */
467 fl_measure(msg_box->label(), msg_w, msg_h, 0); // fl_measure wraps at msg_w
468 msg_box->size(msg_box->w(), msg_h);
469 window->add(msg_box);
470
471 /* inputs */
472 y += msg_h + 20;
473 Fl_Input *user_input = new Fl_Input(input_x, y, input_w, input_h, "User");
474 user_input->labelsize(14);
475 user_input->textsize(14);
476 window->add(user_input);
477 y += input_h + 10;
478 Fl_Secret_Input *password_input =
479 new Fl_Secret_Input(input_x, y, input_w, input_h, "Password");
480 password_input->labelsize(14);
481 password_input->textsize(14);
482 window->add(password_input);
483
484 /* "OK" button */
485 y += input_h + 20;
486 Fl_Button *ok_button = new EnterButton(200, y, 50, button_h, "OK");
487 ok_button->labelsize(14);
488 ok_button->callback(Dialog_user_password_cb);
489 window->add(ok_button);
490
491 /* "Cancel" button */
492 Fl_Button *cancel_button =
493 new EnterButton(50, y, 100, button_h, "Cancel");
494 cancel_button->labelsize(14);
495 cancel_button->callback(Dialog_user_password_cb);
496 window->add(cancel_button);
497
498 y += button_h + 20;
499 window_h = y;
500 window->size(window_w, window_h);
501 window->size_range(window_w, window_h, window_w, window_h);
502 window->resizable(window);
503
504 window->show();
505 while (window->shown())
506 Fl::wait();
507
508 ok = ((Fl_Widget *)window->user_data()) == ok_button ? 1 : 0;
509
510 if (ok) {
511 /* call the callback */
512 const char *user, *password;
513 user = user_input->value();
514 password = password_input->value();
515 _MSG("a_Dialog_user_passwd: ok = %d\n", ok);
516 (*cb)(user, password, vp);
517 }
518 delete window;
519
520 return ok;
521}
522
#define _MSG(...)
Definition bookmarks.c:44
#define MSG(...)
Definition bookmarks.c:45
char * a_Dialog_open_file(const char *title, const char *pattern, const char *fname)
Show the open file dialog.
Definition dialog.cc:300
static char * input_str
Definition dialog.cc:45
int a_Dialog_choice(const char *title, const char *msg,...)
Make a question-dialog with a question and alternatives.
Definition dialog.cc:370
static int input_answer
Definition dialog.cc:44
void a_Dialog_msg(const char *title, const char *msg)
Display a message in a popup window.
Definition dialog.cc:152
static void Dialog_user_password_cb(Fl_Widget *button, void *)
Definition dialog.cc:431
const char * a_Dialog_save_file(const char *title, const char *pattern, const char *fname)
Show the save file dialog.
Definition dialog.cc:274
const char * a_Dialog_passwd(const char *title, const char *msg)
Dialog for password.
Definition dialog.cc:261
static int choice_answer
Definition dialog.cc:46
static void choice_cb(Fl_Widget *button, void *number)
Definition dialog.cc:356
void a_Dialog_text_window(const char *title, const char *txt)
Show a new window with the provided text.
Definition dialog.cc:324
static void text_window_close_cb(Fl_Widget *, void *vtd)
Close text window.
Definition dialog.cc:312
static void input_cb(Fl_Widget *button, void *number)
Callback for a_Dialog_input()
Definition dialog.cc:164
const char * a_Dialog_select_file(const char *title, const char *pattern, const char *fname)
Show the select file dialog.
Definition dialog.cc:285
int a_Dialog_user_password(const char *title, const char *msg, UserPasswordCB cb, void *vp)
Make a user/password dialog.
Definition dialog.cc:442
const char * a_Dialog_input(const char *title, const char *msg)
Dialog for one line of Input with a message.
Definition dialog.cc:176
void(* UserPasswordCB)(const char *user, const char *password, void *vp)
Definition dialog.hh:8
void dFree(void *mem)
Definition dlib.c:67
char * dStrdup(const char *s)
Definition dlib.c:76
int dList_length(Dlist *lp)
For completing the ADT.
Definition dlib.c:640
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
Definition dlib.c:689
#define VOIDP2INT(p)
Definition dlib.h:72
#define INT2VOIDP(i)
Definition dlib.h:73
#define MSG_ERR(...)
Definition dpid_common.h:23
static Fl_Window * window
int a_Misc_parse_search_url(char *source, char **label, char **urlstr)
Parse dillorc's search_url string ([<label> ]<url>) Return value: -1 on error, 0 on success (and labe...
Definition misc.c:392
char * a_Misc_escape_chars(const char *str, const char *esc_set)
Escape characters as XX sequences.
Definition misc.c:27
DilloPrefs prefs
Global Data.
Definition prefs.c:33
int width
Definition prefs.h:38
Dlist * search_urls
Definition prefs.h:120
double font_factor
Definition prefs.h:75
int height
Definition prefs.h:39
bool_t search_url_idx
Definition prefs.h:119