dialog.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. /* Dialog box features module for the Midnight Commander
  2. Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  3. 2005, 2007 Free Software Foundation, Inc.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. */
  16. /** \file dialog.c
  17. * \brief Source: dialog box features module
  18. */
  19. #include <config.h>
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include "global.h"
  26. #include "../src/tty/tty.h"
  27. #include "../src/skin/skin.h"
  28. #include "../src/tty/mouse.h"
  29. #include "../src/tty/key.h"
  30. #include "help.h" /* interactive_display() */
  31. #include "dialog.h"
  32. #include "layout.h"
  33. #include "execute.h" /* suspend_cmd() */
  34. #include "main.h" /* fast_refresh */
  35. #include "strutil.h"
  36. #include "setup.h" /* mouse_close_dialog */
  37. /* Color styles for normal and error dialogs */
  38. int dialog_colors [4];
  39. int alarm_colors [4];
  40. /* Primitive way to check if the the current dialog is our dialog */
  41. /* This is needed by async routines like load_prompt */
  42. Dlg_head *current_dlg = 0;
  43. /* A hook list for idle events */
  44. Hook *idle_hook = 0;
  45. /* left click outside of dialog closes it */
  46. int mouse_close_dialog = 0;
  47. static void dlg_broadcast_msg_to (Dlg_head * h, widget_msg_t message,
  48. int reverse, int flags);
  49. /* draw box in window */
  50. void
  51. draw_box (Dlg_head *h, int y, int x, int ys, int xs)
  52. {
  53. tty_draw_box (h->y + y, h->x + x, ys, xs);
  54. }
  55. void
  56. widget_erase (Widget *w)
  57. {
  58. tty_fill_region (w->y, w->x, w->lines, w->cols, ' ');
  59. }
  60. void
  61. dlg_erase (Dlg_head *h)
  62. {
  63. if (h != NULL)
  64. tty_fill_region (h->y, h->x, h->lines, h->cols, ' ');
  65. }
  66. void
  67. init_widget (Widget *w, int y, int x, int lines, int cols,
  68. callback_fn callback, mouse_h mouse_handler)
  69. {
  70. w->x = x;
  71. w->y = y;
  72. w->cols = cols;
  73. w->lines = lines;
  74. w->callback = callback;
  75. w->mouse = mouse_handler;
  76. w->parent = 0;
  77. /* Almost all widgets want to put the cursor in a suitable place */
  78. w->options = W_WANT_CURSOR;
  79. }
  80. /* Clean the dialog area, draw the frame and the title */
  81. void
  82. common_dialog_repaint (struct Dlg_head *h)
  83. {
  84. int space;
  85. space = (h->flags & DLG_COMPACT) ? 0 : 1;
  86. tty_setcolor (DLG_NORMALC (h));
  87. dlg_erase (h);
  88. draw_box (h, space, space, h->lines - 2 * space, h->cols - 2 * space);
  89. if (h->title) {
  90. tty_setcolor (DLG_HOT_NORMALC (h));
  91. dlg_move (h, space, (h->cols - str_term_width1 (h->title)) / 2);
  92. tty_print_string (h->title);
  93. }
  94. }
  95. /* this function allows to set dialog position */
  96. void
  97. dlg_set_position (Dlg_head *h, int y1, int x1, int y2, int x2)
  98. {
  99. /* save old positions, will be used to reposition childs */
  100. int ox, oy, oc, ol;
  101. int shift_x, shift_y, scale_x, scale_y;
  102. /* save old positions, will be used to reposition childs */
  103. ox = h->x;
  104. oy = h->y;
  105. oc = h->cols;
  106. ol = h->lines;
  107. h->x = x1;
  108. h->y = y1;
  109. h->lines = y2 - y1;
  110. h->cols = x2 - x1;
  111. /* values by which controls should be moved */
  112. shift_x = h->x - ox;
  113. shift_y = h->y - oy;
  114. scale_x = h->cols - oc;
  115. scale_y = h->lines - ol;
  116. if (h->current == NULL)
  117. return;
  118. if ((shift_x != 0) || (shift_y != 0) || (scale_x != 0) || (scale_y != 0)) {
  119. Widget *c = h->current;
  120. do {
  121. /* there are, mainly, 2 generally possible
  122. situations:
  123. 1. control sticks to one side - it
  124. should be moved
  125. 2. control sticks to two sides of
  126. one direction - it should be sized */
  127. int x = c->x;
  128. int y = c->y;
  129. int cols = c->cols;
  130. int lines = c->lines;
  131. if ((c->pos_flags & WPOS_KEEP_LEFT) && (c->pos_flags & WPOS_KEEP_RIGHT)) {
  132. x += shift_x;
  133. cols += scale_x;
  134. } else if (c->pos_flags & WPOS_KEEP_LEFT)
  135. x += shift_x;
  136. else if (c->pos_flags & WPOS_KEEP_RIGHT)
  137. x += shift_x + scale_x;
  138. if ((c->pos_flags & WPOS_KEEP_TOP) && (c->pos_flags & WPOS_KEEP_BOTTOM)) {
  139. y += shift_y;
  140. lines += scale_y;
  141. } else if (c->pos_flags & WPOS_KEEP_TOP)
  142. y += shift_y;
  143. else if (c->pos_flags & WPOS_KEEP_BOTTOM)
  144. y += shift_y + scale_y;
  145. widget_set_size (c, y, x, lines, cols);
  146. c = c->next;
  147. } while (h->current != c);
  148. }
  149. }
  150. /* this function sets only size, leaving positioning to automatic methods */
  151. void
  152. dlg_set_size (Dlg_head *h, int lines, int cols)
  153. {
  154. int x = h->x;
  155. int y = h->y;
  156. if (h->flags & DLG_CENTER) {
  157. y = (LINES - lines) / 2;
  158. x = (COLS - cols) / 2;
  159. }
  160. if ((h->flags & DLG_TRYUP) && (y > 3))
  161. y -= 2;
  162. dlg_set_position (h, y, x, y + lines, x + cols);
  163. }
  164. /* Default dialog callback */
  165. cb_ret_t
  166. default_dlg_callback (Dlg_head *h, Widget *sender,
  167. dlg_msg_t msg, int parm, void *data)
  168. {
  169. (void) sender;
  170. (void) parm;
  171. (void) data;
  172. switch (msg) {
  173. case DLG_DRAW:
  174. if (h->color != NULL) {
  175. common_dialog_repaint (h);
  176. return MSG_HANDLED;
  177. }
  178. return MSG_NOT_HANDLED;
  179. case DLG_IDLE:
  180. dlg_broadcast_msg_to (h, WIDGET_IDLE, 0, W_WANT_IDLE);
  181. return MSG_HANDLED;
  182. case DLG_RESIZE:
  183. /* this is default resizing mechanism */
  184. /* the main idea of this code is to resize dialog
  185. according to flags (if any of flags require automatic
  186. resizing, like DLG_CENTER, end after that reposition
  187. controls in dialog according to flags of widget) */
  188. dlg_set_size (h, h->lines, h->cols);
  189. return MSG_HANDLED;
  190. default:
  191. break;
  192. }
  193. return MSG_NOT_HANDLED;
  194. }
  195. Dlg_head *
  196. create_dlg (int y1, int x1, int lines, int cols, const int *color_set,
  197. dlg_cb_fn callback, const char *help_ctx, const char *title,
  198. int flags)
  199. {
  200. Dlg_head *new_d;
  201. new_d = g_new0 (Dlg_head, 1);
  202. if (color_set != NULL) {
  203. new_d->color = g_new (int, DLG_COLOR_NUM);
  204. memmove (new_d->color, color_set, sizeof (int) * DLG_COLOR_NUM);
  205. }
  206. new_d->help_ctx = help_ctx;
  207. new_d->callback = (callback != NULL) ? callback : default_dlg_callback;
  208. new_d->x = x1;
  209. new_d->y = y1;
  210. new_d->flags = flags;
  211. new_d->data = NULL;
  212. dlg_set_size (new_d, lines, cols);
  213. /* Strip existing spaces, add one space before and after the title */
  214. if (title) {
  215. char *t;
  216. t = g_strstrip (g_strdup (title));
  217. if (*t != '\0')
  218. new_d->title = g_strdup_printf (" %s ", t);
  219. g_free (t);
  220. }
  221. return new_d;
  222. }
  223. void
  224. dlg_set_default_colors (void)
  225. {
  226. dialog_colors [0] = COLOR_NORMAL;
  227. dialog_colors [1] = COLOR_FOCUS;
  228. dialog_colors [2] = COLOR_HOT_NORMAL;
  229. dialog_colors [3] = COLOR_HOT_FOCUS;
  230. alarm_colors [0] = ERROR_COLOR;
  231. alarm_colors [1] = REVERSE_COLOR;
  232. alarm_colors [2] = ERROR_HOT_NORMAL;
  233. alarm_colors [3] = ERROR_HOT_FOCUS;
  234. }
  235. void
  236. set_idle_proc (Dlg_head *d, int enable)
  237. {
  238. if (enable)
  239. d->flags |= DLG_WANT_IDLE;
  240. else
  241. d->flags &= ~DLG_WANT_IDLE;
  242. }
  243. /*
  244. * Insert widget to dialog before current widget. For dialogs populated
  245. * from the bottom, make the widget current. Return widget number.
  246. */
  247. int
  248. add_widget_autopos (Dlg_head *h, void *w, widget_pos_flags_t pos_flags)
  249. {
  250. Widget *widget = (Widget *) w;
  251. /* Don't accept 0 widgets, and running dialogs */
  252. if (!widget || h->running)
  253. abort ();
  254. widget->x += h->x;
  255. widget->y += h->y;
  256. widget->parent = h;
  257. widget->dlg_id = h->count++;
  258. widget->pos_flags = pos_flags;
  259. if (h->current) {
  260. widget->next = h->current;
  261. widget->prev = h->current->prev;
  262. h->current->prev->next = widget;
  263. h->current->prev = widget;
  264. } else {
  265. widget->prev = widget;
  266. widget->next = widget;
  267. }
  268. if ((h->flags & DLG_REVERSE) || !h->current)
  269. h->current = widget;
  270. return widget->dlg_id;
  271. }
  272. /* wrapper to simply add lefttop positioned controls */
  273. int
  274. add_widget (Dlg_head *h, void *w)
  275. {
  276. return add_widget_autopos (h, w, WPOS_KEEP_LEFT | WPOS_KEEP_TOP);
  277. }
  278. static void
  279. do_complete_refresh (Dlg_head *dlg)
  280. {
  281. if (!dlg->fullscreen && dlg->parent)
  282. do_complete_refresh (dlg->parent);
  283. dlg_redraw (dlg);
  284. }
  285. void
  286. do_refresh (void)
  287. {
  288. if (!current_dlg)
  289. return;
  290. if (fast_refresh)
  291. dlg_redraw (current_dlg);
  292. else {
  293. do_complete_refresh (current_dlg);
  294. }
  295. }
  296. /* broadcast a message to all the widgets in a dialog that have
  297. * the options set to flags. If flags is zero, the message is sent
  298. * to all widgets.
  299. */
  300. static void
  301. dlg_broadcast_msg_to (Dlg_head *h, widget_msg_t message, int reverse,
  302. int flags)
  303. {
  304. Widget *p, *first, *wi;
  305. if (!h->current)
  306. return;
  307. if (reverse)
  308. first = p = h->current->prev;
  309. else
  310. first = p = h->current->next;
  311. do {
  312. wi = p;
  313. if (reverse)
  314. p = p->prev;
  315. else
  316. p = p->next;
  317. if (flags == 0 || (flags & wi->options))
  318. send_message (wi, message, 0);
  319. } while (first != p);
  320. }
  321. /* broadcast a message to all the widgets in a dialog */
  322. void
  323. dlg_broadcast_msg (Dlg_head *h, widget_msg_t message, int reverse)
  324. {
  325. dlg_broadcast_msg_to (h, message, reverse, 0);
  326. }
  327. int
  328. dlg_focus (Dlg_head *h)
  329. {
  330. if ((h->current != NULL)
  331. && (send_message (h->current, WIDGET_FOCUS, 0) == MSG_HANDLED)) {
  332. h->callback (h, h->current, DLG_FOCUS, 0, NULL);
  333. return 1;
  334. }
  335. return 0;
  336. }
  337. static int
  338. dlg_unfocus (Dlg_head *h)
  339. {
  340. if ((h->current != NULL)
  341. && (send_message (h->current, WIDGET_UNFOCUS, 0) == MSG_HANDLED)) {
  342. h->callback (h, h->current, DLG_UNFOCUS, 0, NULL);
  343. return 1;
  344. }
  345. return 0;
  346. }
  347. /* Return true if the windows overlap */
  348. int dlg_overlap (Widget *a, Widget *b)
  349. {
  350. if ((b->x >= a->x + a->cols)
  351. || (a->x >= b->x + b->cols)
  352. || (b->y >= a->y + a->lines)
  353. || (a->y >= b->y + b->lines))
  354. return 0;
  355. return 1;
  356. }
  357. /* Find the widget with the given callback in the dialog h */
  358. Widget *
  359. find_widget_type (const Dlg_head *h, callback_fn callback)
  360. {
  361. Widget *w = NULL;
  362. if ((h != NULL) && (h->current != NULL)) {
  363. int i;
  364. Widget *item;
  365. for (i = 0, item = h->current; i < h->count; i++, item = item->next) {
  366. if (item->callback == callback) {
  367. w = item;
  368. break;
  369. }
  370. }
  371. }
  372. return w;
  373. }
  374. /* Find the widget with the given dialog id in the dialog h and select it */
  375. void
  376. dlg_select_by_id (const Dlg_head *h, int id)
  377. {
  378. Widget *w, *w_found;
  379. if (!h->current)
  380. return;
  381. w = h->current;
  382. w_found = NULL;
  383. do {
  384. if (w->dlg_id == id) {
  385. w_found = w;
  386. break;
  387. }
  388. w = w->next;
  389. } while (w != h->current);
  390. if (w_found)
  391. dlg_select_widget(w_found);
  392. }
  393. /* What to do if the requested widget doesn't take focus */
  394. typedef enum {
  395. SELECT_NEXT, /* go the the next widget */
  396. SELECT_PREV, /* go the the previous widget */
  397. SELECT_EXACT /* use current widget */
  398. } select_dir_t;
  399. /*
  400. * Try to select another widget. If forward is set, follow tab order.
  401. * Otherwise go to the previous widget.
  402. */
  403. static void
  404. do_select_widget (Dlg_head *h, Widget *w, select_dir_t dir)
  405. {
  406. Widget *w0 = h->current;
  407. if (!dlg_unfocus (h))
  408. return;
  409. h->current = w;
  410. do {
  411. if (dlg_focus (h))
  412. break;
  413. switch (dir) {
  414. case SELECT_NEXT:
  415. h->current = h->current->next;
  416. break;
  417. case SELECT_PREV:
  418. h->current = h->current->prev;
  419. break;
  420. case SELECT_EXACT:
  421. h->current = w0;
  422. dlg_focus (h);
  423. return;
  424. }
  425. } while (h->current != w);
  426. if (dlg_overlap (w0, h->current)) {
  427. send_message (h->current, WIDGET_DRAW, 0);
  428. send_message (h->current, WIDGET_FOCUS, 0);
  429. }
  430. }
  431. /*
  432. * Try to select widget in the dialog.
  433. */
  434. void
  435. dlg_select_widget (void *w)
  436. {
  437. do_select_widget (((Widget *) w)->parent, w, SELECT_NEXT);
  438. }
  439. /* Try to select previous widget in the tab order */
  440. void
  441. dlg_one_up (Dlg_head *h)
  442. {
  443. if (h->current)
  444. do_select_widget (h, h->current->prev, SELECT_PREV);
  445. }
  446. /* Try to select next widget in the tab order */
  447. void
  448. dlg_one_down (Dlg_head *h)
  449. {
  450. if (h->current)
  451. do_select_widget (h, h->current->next, SELECT_NEXT);
  452. }
  453. void update_cursor (Dlg_head *h)
  454. {
  455. Widget *p = h->current;
  456. if (p != NULL) {
  457. if (p->options & W_WANT_CURSOR)
  458. send_message (p, WIDGET_CURSOR, 0);
  459. else
  460. while ((p = p->next) != h->current)
  461. if (p->options & W_WANT_CURSOR)
  462. if (send_message (p, WIDGET_CURSOR, 0) == MSG_HANDLED)
  463. break;
  464. }
  465. }
  466. /* Redraw the widgets in reverse order, leaving the current widget
  467. * as the last one
  468. */
  469. void
  470. dlg_redraw (Dlg_head *h)
  471. {
  472. h->callback (h, NULL, DLG_DRAW, 0, NULL);
  473. dlg_broadcast_msg (h, WIDGET_DRAW, 1);
  474. update_cursor (h);
  475. }
  476. void
  477. dlg_stop (Dlg_head *h)
  478. {
  479. h->running = 0;
  480. }
  481. static void
  482. dialog_handle_key (Dlg_head *h, int d_key)
  483. {
  484. if (is_abort_char (d_key)) {
  485. h->ret_value = B_CANCEL;
  486. dlg_stop (h);
  487. return;
  488. }
  489. switch (d_key) {
  490. case '\n':
  491. case KEY_ENTER:
  492. h->ret_value = B_ENTER;
  493. dlg_stop (h);
  494. break;
  495. case KEY_LEFT:
  496. case KEY_UP:
  497. dlg_one_up (h);
  498. break;
  499. case KEY_RIGHT:
  500. case KEY_DOWN:
  501. dlg_one_down (h);
  502. break;
  503. case KEY_F(1):
  504. interactive_display (NULL, h->help_ctx);
  505. do_refresh ();
  506. break;
  507. case XCTRL('z'):
  508. suspend_cmd ();
  509. /* Fall through */
  510. case XCTRL('l'):
  511. #ifdef HAVE_SLANG
  512. tty_touch_screen ();
  513. mc_refresh ();
  514. #else
  515. /* Use this if the refreshes fail */
  516. clr_scr ();
  517. repaint_screen ();
  518. #endif /* HAVE_SLANG */
  519. break;
  520. default:
  521. break;
  522. }
  523. }
  524. static cb_ret_t
  525. dlg_try_hotkey (Dlg_head *h, int d_key)
  526. {
  527. Widget *hot_cur;
  528. cb_ret_t handled;
  529. int c;
  530. if (h->current == NULL)
  531. return MSG_NOT_HANDLED;
  532. /*
  533. * Explanation: we don't send letter hotkeys to other widgets if
  534. * the currently selected widget is an input line
  535. */
  536. if (h->current->options & W_IS_INPUT) {
  537. /* skip ascii control characters, anything else can valid character in
  538. * some encoding */
  539. if (d_key >= 32 && d_key < 256)
  540. return MSG_NOT_HANDLED;
  541. }
  542. /* If it's an alt key, send the message */
  543. c = d_key & ~ALT (0);
  544. if (d_key & ALT (0) && g_ascii_isalpha (c))
  545. d_key = g_ascii_tolower (c);
  546. handled = MSG_NOT_HANDLED;
  547. if (h->current->options & W_WANT_HOTKEY)
  548. handled = send_message (h->current, WIDGET_HOTKEY, d_key);
  549. /* If not used, send hotkey to other widgets */
  550. if (handled == MSG_HANDLED)
  551. return MSG_HANDLED;
  552. hot_cur = h->current->next;
  553. /* send it to all widgets */
  554. while (h->current != hot_cur && handled == MSG_NOT_HANDLED) {
  555. if (hot_cur->options & W_WANT_HOTKEY)
  556. handled = send_message (hot_cur, WIDGET_HOTKEY, d_key);
  557. if (handled == MSG_NOT_HANDLED)
  558. hot_cur = hot_cur->next;
  559. }
  560. if (handled == MSG_HANDLED)
  561. do_select_widget (h, hot_cur, SELECT_EXACT);
  562. return handled;
  563. }
  564. static void
  565. dlg_key_event (Dlg_head *h, int d_key)
  566. {
  567. cb_ret_t handled;
  568. if (h->current == NULL)
  569. return;
  570. /* TAB used to cycle */
  571. if (!(h->flags & DLG_WANT_TAB)) {
  572. if (d_key == '\t') {
  573. dlg_one_down (h);
  574. return;
  575. } else if (d_key == KEY_BTAB) {
  576. dlg_one_up (h);
  577. return;
  578. }
  579. }
  580. /* first can dlg_callback handle the key */
  581. handled = h->callback (h, NULL, DLG_KEY, d_key, NULL);
  582. /* next try the hotkey */
  583. if (handled == MSG_NOT_HANDLED)
  584. handled = dlg_try_hotkey (h, d_key);
  585. if (handled == MSG_HANDLED)
  586. h->callback (h, NULL, DLG_HOTKEY_HANDLED, 0, NULL);
  587. else
  588. /* not used - then try widget_callback */
  589. handled = send_message (h->current, WIDGET_KEY, d_key);
  590. /* not used- try to use the unhandled case */
  591. if (handled == MSG_NOT_HANDLED)
  592. handled = h->callback (h, NULL, DLG_UNHANDLED_KEY, d_key, NULL);
  593. if (handled == MSG_NOT_HANDLED)
  594. dialog_handle_key (h, d_key);
  595. h->callback (h, NULL, DLG_POST_KEY, d_key, NULL);
  596. }
  597. static int
  598. dlg_mouse_event (Dlg_head * h, Gpm_Event * event)
  599. {
  600. Widget *item;
  601. Widget *starting_widget = h->current;
  602. Gpm_Event new_event;
  603. int x = event->x;
  604. int y = event->y;
  605. /* close the dialog by mouse click out of dialog area */
  606. if (mouse_close_dialog && !h->fullscreen
  607. && ((event->buttons & GPM_B_LEFT) != 0) && ((event->type & GPM_DOWN) != 0) /* left click */
  608. && !((x > h->x) && (x <= h->x + h->cols) && (y > h->y) && (y <= h->y + h->lines))) {
  609. h->ret_value = B_CANCEL;
  610. dlg_stop (h);
  611. return MOU_NORMAL;
  612. }
  613. item = starting_widget;
  614. do {
  615. Widget *widget;
  616. widget = item;
  617. item = item->next;
  618. if ((x > widget->x) && (x <= widget->x + widget->cols)
  619. && (y > widget->y) && (y <= widget->y + widget->lines)) {
  620. new_event = *event;
  621. new_event.x -= widget->x;
  622. new_event.y -= widget->y;
  623. if (widget->mouse != NULL)
  624. return widget->mouse (&new_event, widget);
  625. }
  626. } while (item != starting_widget);
  627. return MOU_NORMAL;
  628. }
  629. /* Run dialog routines */
  630. /* Init the process */
  631. void
  632. init_dlg (Dlg_head *h)
  633. {
  634. /* Initialize dialog manager and widgets */
  635. h->callback (h, NULL, DLG_INIT, 0, NULL);
  636. dlg_broadcast_msg (h, WIDGET_INIT, 0);
  637. if (h->x == 0 && h->y == 0 && h->cols == COLS && h->lines == LINES)
  638. h->fullscreen = 1;
  639. h->parent = current_dlg;
  640. current_dlg = h;
  641. /* Initialize the mouse status */
  642. h->mouse_status = MOU_NORMAL;
  643. /* Select the first widget that takes focus */
  644. while (!dlg_focus (h) && h->current)
  645. h->current = h->current->next;
  646. /* Redraw the screen */
  647. dlg_redraw (h);
  648. h->ret_value = 0;
  649. h->running = 1;
  650. }
  651. /* Shutdown the run_dlg */
  652. void
  653. dlg_run_done (Dlg_head *h)
  654. {
  655. if (h->current != NULL)
  656. h->callback (h, h->current, DLG_END, 0, NULL);
  657. current_dlg = h->parent;
  658. }
  659. void
  660. dlg_process_event (Dlg_head *h, int key, Gpm_Event *event)
  661. {
  662. if (key == EV_NONE){
  663. if (tty_got_interrupt ())
  664. key = XCTRL('g');
  665. else
  666. return;
  667. }
  668. if (key == EV_MOUSE)
  669. h->mouse_status = dlg_mouse_event (h, event);
  670. else
  671. dlg_key_event (h, key);
  672. }
  673. static void
  674. frontend_run_dlg (Dlg_head *h)
  675. {
  676. int d_key;
  677. Gpm_Event event;
  678. event.x = -1;
  679. while (h->running) {
  680. if (winch_flag)
  681. change_screen_size ();
  682. if (is_idle ()) {
  683. if (idle_hook)
  684. execute_hooks (idle_hook);
  685. while ((h->flags & DLG_WANT_IDLE) && is_idle ())
  686. h->callback (h, NULL, DLG_IDLE, 0, NULL);
  687. /* Allow terminating the dialog from the idle handler */
  688. if (!h->running)
  689. break;
  690. }
  691. update_cursor (h);
  692. /* Clear interrupt flag */
  693. tty_got_interrupt ();
  694. d_key = tty_get_event (&event, h->mouse_status == MOU_REPEAT, TRUE);
  695. dlg_process_event (h, d_key, &event);
  696. if (!h->running)
  697. h->callback (h, NULL, DLG_VALIDATE, 0, NULL);
  698. }
  699. }
  700. /* Standard run dialog routine
  701. * We have to keep this routine small so that we can duplicate it's
  702. * behavior on complex routines like the file routines, this way,
  703. * they can call the dlg_process_event without rewriting all the code
  704. */
  705. int run_dlg (Dlg_head *h)
  706. {
  707. init_dlg (h);
  708. frontend_run_dlg (h);
  709. dlg_run_done (h);
  710. return h->ret_value;
  711. }
  712. void
  713. destroy_dlg (Dlg_head *h)
  714. {
  715. int i;
  716. Widget *c;
  717. dlg_broadcast_msg (h, WIDGET_DESTROY, 0);
  718. c = h->current;
  719. for (i = 0; i < h->count; i++) {
  720. c = c->next;
  721. g_free (h->current);
  722. h->current = c;
  723. }
  724. g_free (h->color);
  725. g_free (h->title);
  726. g_free (h);
  727. do_refresh ();
  728. }
  729. void widget_set_size (Widget *widget, int y, int x, int lines, int cols)
  730. {
  731. widget->x = x;
  732. widget->y = y;
  733. widget->cols = cols;
  734. widget->lines = lines;
  735. send_message (widget, WIDGET_RESIZED, 0 /* unused */);
  736. }
  737. /* Replace widget old_w for widget new_w in the dialog */
  738. void
  739. dlg_replace_widget (Widget *old_w, Widget *new_w)
  740. {
  741. Dlg_head *h = old_w->parent;
  742. int should_focus = 0;
  743. if (!h->current)
  744. return;
  745. if (old_w == h->current)
  746. should_focus = 1;
  747. new_w->parent = h;
  748. new_w->dlg_id = old_w->dlg_id;
  749. if (old_w == old_w->next) {
  750. /* just one widget */
  751. new_w->prev = new_w;
  752. new_w->next = new_w;
  753. } else {
  754. new_w->prev = old_w->prev;
  755. new_w->next = old_w->next;
  756. old_w->prev->next = new_w;
  757. old_w->next->prev = new_w;
  758. }
  759. if (should_focus)
  760. h->current = new_w;
  761. send_message (old_w, WIDGET_DESTROY, 0);
  762. send_message (new_w, WIDGET_INIT, 0);
  763. if (should_focus)
  764. dlg_select_widget (new_w);
  765. send_message (new_w, WIDGET_DRAW, 0);
  766. }