widget-common.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. /*
  2. Widgets for the Midnight Commander
  3. Copyright (C) 1994-2024
  4. Free Software Foundation, Inc.
  5. Authors:
  6. Radek Doulik, 1994, 1995
  7. Miguel de Icaza, 1994, 1995
  8. Jakub Jelinek, 1995
  9. Andrej Borsenkow, 1996
  10. Norbert Warmuth, 1997
  11. Andrew Borodin <aborodin@vmail.ru>, 2009-2022
  12. This file is part of the Midnight Commander.
  13. The Midnight Commander is free software: you can redistribute it
  14. and/or modify it under the terms of the GNU General Public License as
  15. published by the Free Software Foundation, either version 3 of the License,
  16. or (at your option) any later version.
  17. The Midnight Commander is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU General Public License for more details.
  21. You should have received a copy of the GNU General Public License
  22. along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. /** \file widget-common.c
  25. * \brief Source: shared stuff of widgets
  26. */
  27. #include <config.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include "lib/global.h"
  31. #include "lib/tty/tty.h"
  32. #include "lib/tty/color.h"
  33. #include "lib/skin.h"
  34. #include "lib/strutil.h"
  35. #include "lib/widget.h"
  36. /*** global variables ****************************************************************************/
  37. /*** file scope macro definitions ****************************************************************/
  38. /*** file scope type declarations ****************************************************************/
  39. /*** forward declarations (file scope functions) *************************************************/
  40. /*** file scope variables ************************************************************************/
  41. /* maximum value of used widget ID */
  42. static unsigned long widget_id = 0;
  43. /* --------------------------------------------------------------------------------------------- */
  44. /*** file scope functions ************************************************************************/
  45. /* --------------------------------------------------------------------------------------------- */
  46. /**
  47. * Calc widget ID,
  48. * Widget ID is uniq for each widget created during MC session (like PID in OS).
  49. *
  50. * @return widget ID.
  51. */
  52. static unsigned long
  53. widget_set_id (void)
  54. {
  55. unsigned long id;
  56. id = widget_id++;
  57. /* TODO IF NEEDED: if id is already used, find next free id. */
  58. return id;
  59. }
  60. /* --------------------------------------------------------------------------------------------- */
  61. static cb_ret_t
  62. widget_default_resize (Widget *w, const WRect *r)
  63. {
  64. if (r == NULL)
  65. return MSG_NOT_HANDLED;
  66. w->rect = *r;
  67. return MSG_HANDLED;
  68. }
  69. /* --------------------------------------------------------------------------------------------- */
  70. static void
  71. widget_do_focus (Widget *w, gboolean enable)
  72. {
  73. if (w != NULL && widget_get_state (WIDGET (w->owner), WST_VISIBLE | WST_FOCUSED))
  74. widget_set_state (w, WST_FOCUSED, enable);
  75. }
  76. /* --------------------------------------------------------------------------------------------- */
  77. /**
  78. * Focus specified widget in it's owner.
  79. *
  80. * @param w widget to be focused.
  81. */
  82. static void
  83. widget_focus (Widget *w)
  84. {
  85. WGroup *g = w->owner;
  86. if (g == NULL || g->current == NULL)
  87. return;
  88. if (WIDGET (g->current->data) != w)
  89. {
  90. widget_do_focus (WIDGET (g->current->data), FALSE);
  91. /* Test if focus lost was allowed and focus has really been loose */
  92. if (g->current == NULL || !widget_get_state (WIDGET (g->current->data), WST_FOCUSED))
  93. {
  94. widget_do_focus (w, TRUE);
  95. g->current = widget_find (WIDGET (g), w);
  96. }
  97. }
  98. else if (!widget_get_state (w, WST_FOCUSED))
  99. widget_do_focus (w, TRUE);
  100. }
  101. /* --------------------------------------------------------------------------------------------- */
  102. /**
  103. * Put widget on top or bottom of Z-order.
  104. */
  105. static void
  106. widget_reorder (GList *l, gboolean set_top)
  107. {
  108. WGroup *g = WIDGET (l->data)->owner;
  109. g->widgets = g_list_remove_link (g->widgets, l);
  110. if (set_top)
  111. g->widgets = g_list_concat (g->widgets, l);
  112. else
  113. g->widgets = g_list_concat (l, g->widgets);
  114. }
  115. /* --------------------------------------------------------------------------------------------- */
  116. static gboolean
  117. hotkey_cmp (const char *s1, const char *s2)
  118. {
  119. gboolean n1, n2;
  120. n1 = s1 != NULL;
  121. n2 = s2 != NULL;
  122. if (n1 != n2)
  123. return FALSE;
  124. if (n1 && n2 && strcmp (s1, s2) != 0)
  125. return FALSE;
  126. return TRUE;
  127. }
  128. /* --------------------------------------------------------------------------------------------- */
  129. static void
  130. widget_default_mouse_callback (Widget *w, mouse_msg_t msg, mouse_event_t *event)
  131. {
  132. /* do nothing */
  133. (void) w;
  134. (void) msg;
  135. (void) event;
  136. }
  137. /* --------------------------------------------------------------------------------------------- */
  138. static const int *
  139. widget_default_get_colors (const Widget *w)
  140. {
  141. const Widget *owner = CONST_WIDGET (w->owner);
  142. return (owner == NULL ? NULL : widget_get_colors (owner));
  143. }
  144. /* --------------------------------------------------------------------------------------------- */
  145. /*** public functions ****************************************************************************/
  146. /* --------------------------------------------------------------------------------------------- */
  147. struct hotkey_t
  148. hotkey_new (const char *text)
  149. {
  150. hotkey_t result;
  151. const char *cp, *p;
  152. if (text == NULL)
  153. text = "";
  154. /* search for '&', that is not on the of text */
  155. cp = strchr (text, '&');
  156. if (cp != NULL && cp[1] != '\0')
  157. {
  158. result.start = g_strndup (text, cp - text);
  159. /* skip '&' */
  160. cp++;
  161. p = str_cget_next_char (cp);
  162. result.hotkey = g_strndup (cp, p - cp);
  163. cp = p;
  164. result.end = g_strdup (cp);
  165. }
  166. else
  167. {
  168. result.start = g_strdup (text);
  169. result.hotkey = NULL;
  170. result.end = NULL;
  171. }
  172. return result;
  173. }
  174. /* --------------------------------------------------------------------------------------------- */
  175. void
  176. hotkey_free (const hotkey_t hotkey)
  177. {
  178. g_free (hotkey.start);
  179. g_free (hotkey.hotkey);
  180. g_free (hotkey.end);
  181. }
  182. /* --------------------------------------------------------------------------------------------- */
  183. int
  184. hotkey_width (const hotkey_t hotkey)
  185. {
  186. int result;
  187. result = str_term_width1 (hotkey.start);
  188. result += (hotkey.hotkey != NULL) ? str_term_width1 (hotkey.hotkey) : 0;
  189. result += (hotkey.end != NULL) ? str_term_width1 (hotkey.end) : 0;
  190. return result;
  191. }
  192. /* --------------------------------------------------------------------------------------------- */
  193. gboolean
  194. hotkey_equal (const hotkey_t hotkey1, const hotkey_t hotkey2)
  195. {
  196. /* *INDENT-OFF* */
  197. return (strcmp (hotkey1.start, hotkey2.start) == 0) &&
  198. hotkey_cmp (hotkey1.hotkey, hotkey2.hotkey) &&
  199. hotkey_cmp (hotkey1.end, hotkey2.end);
  200. /* *INDENT-ON* */
  201. }
  202. /* --------------------------------------------------------------------------------------------- */
  203. void
  204. hotkey_draw (const Widget *w, const hotkey_t hotkey, gboolean focused)
  205. {
  206. if (hotkey.start[0] != '\0')
  207. {
  208. widget_selectcolor (w, focused, FALSE);
  209. tty_print_string (hotkey.start);
  210. }
  211. if (hotkey.hotkey != NULL)
  212. {
  213. widget_selectcolor (w, focused, TRUE);
  214. tty_print_string (hotkey.hotkey);
  215. }
  216. if (hotkey.end != NULL)
  217. {
  218. widget_selectcolor (w, focused, FALSE);
  219. tty_print_string (hotkey.end);
  220. }
  221. }
  222. /* --------------------------------------------------------------------------------------------- */
  223. char *
  224. hotkey_get_text (const hotkey_t hotkey)
  225. {
  226. GString *text;
  227. text = g_string_new (hotkey.start);
  228. if (hotkey.hotkey != NULL)
  229. {
  230. g_string_append_c (text, '&');
  231. g_string_append (text, hotkey.hotkey);
  232. }
  233. if (hotkey.end != NULL)
  234. g_string_append (text, hotkey.end);
  235. return g_string_free (text, FALSE);
  236. }
  237. /* --------------------------------------------------------------------------------------------- */
  238. void
  239. widget_init (Widget *w, const WRect *r, widget_cb_fn callback, widget_mouse_cb_fn mouse_callback)
  240. {
  241. w->id = widget_set_id ();
  242. w->rect = *r;
  243. w->pos_flags = WPOS_KEEP_DEFAULT;
  244. w->callback = callback;
  245. w->keymap = NULL;
  246. w->ext_keymap = NULL;
  247. w->ext_mode = FALSE;
  248. w->mouse_callback = mouse_callback != NULL ? mouse_callback : widget_default_mouse_callback;
  249. w->owner = NULL;
  250. w->mouse_handler = mouse_handle_event;
  251. w->mouse.forced_capture = FALSE;
  252. w->mouse.capture = FALSE;
  253. w->mouse.last_msg = MSG_MOUSE_NONE;
  254. w->mouse.last_buttons_down = 0;
  255. w->options = WOP_DEFAULT;
  256. w->state = WST_CONSTRUCT | WST_VISIBLE;
  257. w->make_global = widget_default_make_global;
  258. w->make_local = widget_default_make_local;
  259. w->find = widget_default_find;
  260. w->find_by_type = widget_default_find_by_type;
  261. w->find_by_id = widget_default_find_by_id;
  262. w->set_state = widget_default_set_state;
  263. w->destroy = widget_default_destroy;
  264. w->get_colors = widget_default_get_colors;
  265. }
  266. /* --------------------------------------------------------------------------------------------- */
  267. /* Default callback for widgets */
  268. cb_ret_t
  269. widget_default_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
  270. {
  271. (void) sender;
  272. (void) parm;
  273. switch (msg)
  274. {
  275. case MSG_INIT:
  276. case MSG_FOCUS:
  277. case MSG_UNFOCUS:
  278. case MSG_ENABLE:
  279. case MSG_DISABLE:
  280. case MSG_DRAW:
  281. case MSG_DESTROY:
  282. case MSG_CURSOR:
  283. case MSG_IDLE:
  284. return MSG_HANDLED;
  285. case MSG_RESIZE:
  286. return widget_default_resize (w, CONST_RECT (data));
  287. default:
  288. return MSG_NOT_HANDLED;
  289. }
  290. }
  291. /* --------------------------------------------------------------------------------------------- */
  292. /**
  293. * Apply new options to widget.
  294. *
  295. * @param w widget
  296. * @param options widget option flags to modify. Several flags per call can be modified.
  297. * @param enable TRUE if specified options should be added, FALSE if options should be removed
  298. */
  299. void
  300. widget_set_options (Widget *w, widget_options_t options, gboolean enable)
  301. {
  302. if (enable)
  303. w->options |= options;
  304. else
  305. w->options &= ~options;
  306. }
  307. /* --------------------------------------------------------------------------------------------- */
  308. void
  309. widget_adjust_position (widget_pos_flags_t pos_flags, WRect *r)
  310. {
  311. if ((pos_flags & WPOS_FULLSCREEN) != 0)
  312. {
  313. r->y = 0;
  314. r->x = 0;
  315. r->lines = LINES;
  316. r->cols = COLS;
  317. }
  318. else
  319. {
  320. if ((pos_flags & WPOS_CENTER_HORZ) != 0)
  321. r->x = (COLS - r->cols) / 2;
  322. if ((pos_flags & WPOS_CENTER_VERT) != 0)
  323. r->y = (LINES - r->lines) / 2;
  324. if ((pos_flags & WPOS_TRYUP) != 0)
  325. {
  326. if (r->y > 3)
  327. r->y -= 2;
  328. else if (r->y == 3)
  329. r->y = 2;
  330. }
  331. }
  332. }
  333. /* --------------------------------------------------------------------------------------------- */
  334. /**
  335. * Change widget position and size.
  336. *
  337. * @param w widget
  338. * @param y y coordinate of top-left corner
  339. * @param x x coordinate of top-left corner
  340. * @param lines width
  341. * @param cols height
  342. */
  343. void
  344. widget_set_size (Widget *w, int y, int x, int lines, int cols)
  345. {
  346. WRect r = { y, x, lines, cols };
  347. send_message (w, NULL, MSG_RESIZE, 0, &r);
  348. widget_draw (w);
  349. }
  350. /* --------------------------------------------------------------------------------------------- */
  351. /**
  352. * Change widget position and size.
  353. *
  354. * @param w widget
  355. * @param r WRect object that holds position and size
  356. */
  357. void
  358. widget_set_size_rect (Widget *w, WRect *r)
  359. {
  360. send_message (w, NULL, MSG_RESIZE, 0, r);
  361. widget_draw (w);
  362. }
  363. /* --------------------------------------------------------------------------------------------- */
  364. void
  365. widget_selectcolor (const Widget *w, gboolean focused, gboolean hotkey)
  366. {
  367. int color;
  368. const int *colors;
  369. colors = widget_get_colors (w);
  370. if (widget_get_state (w, WST_DISABLED))
  371. color = DISABLED_COLOR;
  372. else if (hotkey)
  373. color = colors[focused ? DLG_COLOR_HOT_FOCUS : DLG_COLOR_HOT_NORMAL];
  374. else
  375. color = colors[focused ? DLG_COLOR_FOCUS : DLG_COLOR_NORMAL];
  376. tty_setcolor (color);
  377. }
  378. /* --------------------------------------------------------------------------------------------- */
  379. void
  380. widget_erase (Widget *w)
  381. {
  382. if (w != NULL)
  383. tty_fill_region (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, ' ');
  384. }
  385. /* --------------------------------------------------------------------------------------------- */
  386. void
  387. widget_set_visibility (Widget *w, gboolean make_visible)
  388. {
  389. if (widget_get_state (w, WST_VISIBLE) != make_visible)
  390. widget_set_state (w, WST_VISIBLE, make_visible);
  391. }
  392. /* --------------------------------------------------------------------------------------------- */
  393. /**
  394. * Check whether widget is active or not.
  395. * Widget is active if it's current in the its owner and each owner in the chain is current too.
  396. *
  397. * @param w the widget
  398. *
  399. * @return TRUE if the widget is active, FALSE otherwise
  400. */
  401. gboolean
  402. widget_is_active (const void *w)
  403. {
  404. const WGroup *owner;
  405. /* Is group top? */
  406. if (w == top_dlg->data)
  407. return TRUE;
  408. owner = CONST_WIDGET (w)->owner;
  409. /* Is widget in any group? */
  410. if (owner == NULL)
  411. return FALSE;
  412. if (w != owner->current->data)
  413. return FALSE;
  414. return widget_is_active (owner);
  415. }
  416. /* --------------------------------------------------------------------------------------------- */
  417. cb_ret_t
  418. widget_draw (Widget *w)
  419. {
  420. cb_ret_t ret = MSG_NOT_HANDLED;
  421. if (w != NULL && widget_get_state (w, WST_VISIBLE))
  422. {
  423. WGroup *g = w->owner;
  424. if (g != NULL && widget_get_state (WIDGET (g), WST_ACTIVE))
  425. ret = w->callback (w, NULL, MSG_DRAW, 0, NULL);
  426. }
  427. return ret;
  428. }
  429. /* --------------------------------------------------------------------------------------------- */
  430. /**
  431. * Replace widget in the dialog.
  432. *
  433. * @param old_w old widget that need to be replaced
  434. * @param new_w new widget that will replace @old_w
  435. */
  436. void
  437. widget_replace (Widget *old_w, Widget *new_w)
  438. {
  439. WGroup *g = old_w->owner;
  440. gboolean should_focus = FALSE;
  441. GList *holder;
  442. if (g->widgets == NULL)
  443. return;
  444. if (g->current == NULL)
  445. g->current = g->widgets;
  446. /* locate widget position in the list */
  447. if (old_w == g->current->data)
  448. holder = g->current;
  449. else
  450. holder = g_list_find (g->widgets, old_w);
  451. /* if old widget is focused, we should focus the new one... */
  452. if (widget_get_state (old_w, WST_FOCUSED))
  453. should_focus = TRUE;
  454. /* ...but if new widget isn't selectable, we cannot focus it */
  455. if (!widget_get_options (new_w, WOP_SELECTABLE))
  456. should_focus = FALSE;
  457. /* if new widget isn't selectable, select other widget before replace */
  458. if (!should_focus)
  459. {
  460. GList *l;
  461. for (l = group_get_widget_next_of (holder);
  462. !widget_is_focusable (WIDGET (l->data)) && l != holder;
  463. l = group_get_widget_next_of (l))
  464. ;
  465. widget_select (WIDGET (l->data));
  466. }
  467. /* replace widget */
  468. new_w->owner = g;
  469. new_w->id = old_w->id;
  470. holder->data = new_w;
  471. send_message (old_w, NULL, MSG_DESTROY, 0, NULL);
  472. send_message (new_w, NULL, MSG_INIT, 0, NULL);
  473. if (should_focus)
  474. widget_select (new_w);
  475. else
  476. widget_draw (new_w);
  477. }
  478. /* --------------------------------------------------------------------------------------------- */
  479. gboolean
  480. widget_is_focusable (const Widget *w)
  481. {
  482. return (widget_get_options (w, WOP_SELECTABLE) && widget_get_state (w, WST_VISIBLE) &&
  483. !widget_get_state (w, WST_DISABLED));
  484. }
  485. /* --------------------------------------------------------------------------------------------- */
  486. /**
  487. * Select specified widget in it's owner.
  488. *
  489. * Note: this function (and widget_focus(), which it calls) is a no-op
  490. * if the widget is already selected.
  491. *
  492. * @param w widget to be selected
  493. */
  494. void
  495. widget_select (Widget *w)
  496. {
  497. WGroup *g;
  498. if (!widget_get_options (w, WOP_SELECTABLE))
  499. return;
  500. g = GROUP (w->owner);
  501. if (g != NULL)
  502. {
  503. if (widget_get_options (w, WOP_TOP_SELECT))
  504. {
  505. GList *l;
  506. l = widget_find (WIDGET (g), w);
  507. widget_reorder (l, TRUE);
  508. }
  509. widget_focus (w);
  510. }
  511. }
  512. /* --------------------------------------------------------------------------------------------- */
  513. /**
  514. * Set widget at bottom of widget list.
  515. */
  516. void
  517. widget_set_bottom (Widget *w)
  518. {
  519. widget_reorder (widget_find (WIDGET (w->owner), w), FALSE);
  520. }
  521. /* --------------------------------------------------------------------------------------------- */
  522. /**
  523. * Look up key event of widget and translate it to command ID.
  524. * @param w widget
  525. * @param key key event
  526. *
  527. * @return command ID binded with @key.
  528. */
  529. long
  530. widget_lookup_key (Widget *w, int key)
  531. {
  532. if (w->ext_mode)
  533. {
  534. w->ext_mode = FALSE;
  535. return keybind_lookup_keymap_command (w->ext_keymap, key);
  536. }
  537. return keybind_lookup_keymap_command (w->keymap, key);
  538. }
  539. /* --------------------------------------------------------------------------------------------- */
  540. /**
  541. * Default widget callback to convert widget coordinates from local (relative to owner) to global
  542. * (relative to screen).
  543. *
  544. * @param w widget
  545. * @delta offset for top-left corner coordinates. Used for child widgets of WGroup
  546. */
  547. void
  548. widget_default_make_global (Widget *w, const WRect *delta)
  549. {
  550. if (delta != NULL)
  551. rect_move (&w->rect, delta->y, delta->x);
  552. else if (w->owner != NULL)
  553. rect_move (&w->rect, WIDGET (w->owner)->rect.y, WIDGET (w->owner)->rect.x);
  554. }
  555. /* --------------------------------------------------------------------------------------------- */
  556. /**
  557. * Default widget callback to convert widget coordinates from global (relative to screen) to local
  558. * (relative to owner).
  559. *
  560. * @param w widget
  561. * @delta offset for top-left corner coordinates. Used for child widgets of WGroup
  562. */
  563. void
  564. widget_default_make_local (Widget *w, const WRect *delta)
  565. {
  566. if (delta != NULL)
  567. rect_move (&w->rect, -delta->y, -delta->x);
  568. else if (w->owner != NULL)
  569. rect_move (&w->rect, -WIDGET (w->owner)->rect.y, -WIDGET (w->owner)->rect.x);
  570. }
  571. /* --------------------------------------------------------------------------------------------- */
  572. /**
  573. * Default callback function to find widget.
  574. *
  575. * @param w widget
  576. * @param what widget to find
  577. *
  578. * @return holder of @what if widget is @what, NULL otherwise
  579. */
  580. GList *
  581. widget_default_find (const Widget *w, const Widget *what)
  582. {
  583. return (w != what
  584. || w->owner == NULL) ? NULL : g_list_find (CONST_GROUP (w->owner)->widgets, what);
  585. }
  586. /* --------------------------------------------------------------------------------------------- */
  587. /**
  588. * Default callback function to find widget by widget type using widget callback.
  589. *
  590. * @param w widget
  591. * @param cb widget callback
  592. *
  593. * @return @w if widget callback is @cb, NULL otherwise
  594. */
  595. Widget *
  596. widget_default_find_by_type (const Widget *w, widget_cb_fn cb)
  597. {
  598. return (w->callback == cb ? WIDGET (w) : NULL);
  599. }
  600. /* --------------------------------------------------------------------------------------------- */
  601. /**
  602. * Default callback function to find widget by widget ID.
  603. *
  604. * @param w widget
  605. * @param id widget ID
  606. *
  607. * @return @w if widget id is equal to @id, NULL otherwise
  608. */
  609. Widget *
  610. widget_default_find_by_id (const Widget *w, unsigned long id)
  611. {
  612. return (w->id == id ? WIDGET (w) : NULL);
  613. }
  614. /* --------------------------------------------------------------------------------------------- */
  615. /**
  616. * Default callback function to modify state of widget.
  617. *
  618. * @param w widget
  619. * @param state widget state flag to modify
  620. * @param enable specifies whether to turn the flag on (TRUE) or off (FALSE).
  621. * Only one flag per call can be modified.
  622. * @return MSG_HANDLED if set was handled successfully, MSG_NOT_HANDLED otherwise.
  623. */
  624. cb_ret_t
  625. widget_default_set_state (Widget *w, widget_state_t state, gboolean enable)
  626. {
  627. gboolean ret = MSG_HANDLED;
  628. Widget *owner = WIDGET (GROUP (w->owner));
  629. if (enable)
  630. w->state |= state;
  631. else
  632. w->state &= ~state;
  633. if (enable)
  634. {
  635. /* exclusive bits */
  636. switch (state)
  637. {
  638. case WST_CONSTRUCT:
  639. w->state &= ~(WST_ACTIVE | WST_SUSPENDED | WST_CLOSED);
  640. break;
  641. case WST_ACTIVE:
  642. w->state &= ~(WST_CONSTRUCT | WST_SUSPENDED | WST_CLOSED);
  643. break;
  644. case WST_SUSPENDED:
  645. w->state &= ~(WST_CONSTRUCT | WST_ACTIVE | WST_CLOSED);
  646. break;
  647. case WST_CLOSED:
  648. w->state &= ~(WST_CONSTRUCT | WST_ACTIVE | WST_SUSPENDED);
  649. break;
  650. default:
  651. break;
  652. }
  653. }
  654. if (owner == NULL)
  655. return MSG_NOT_HANDLED;
  656. switch (state)
  657. {
  658. case WST_VISIBLE:
  659. if (widget_get_state (owner, WST_ACTIVE))
  660. {
  661. /* redraw owner to show/hide widget */
  662. widget_draw (owner);
  663. if (!enable)
  664. {
  665. /* try select another widget if current one got hidden */
  666. if (w == GROUP (owner)->current->data)
  667. group_select_next_widget (GROUP (owner));
  668. widget_update_cursor (owner); /* FIXME: unneeded? */
  669. }
  670. }
  671. break;
  672. case WST_DISABLED:
  673. ret = send_message (w, NULL, enable ? MSG_DISABLE : MSG_ENABLE, 0, NULL);
  674. if (ret == MSG_HANDLED && widget_get_state (owner, WST_ACTIVE))
  675. ret = widget_draw (w);
  676. break;
  677. case WST_FOCUSED:
  678. {
  679. widget_msg_t msg;
  680. msg = enable ? MSG_FOCUS : MSG_UNFOCUS;
  681. ret = send_message (w, NULL, msg, 0, NULL);
  682. if (ret == MSG_HANDLED && widget_get_state (owner, WST_ACTIVE))
  683. {
  684. widget_draw (w);
  685. /* Notify owner that focus was moved from one widget to another */
  686. send_message (owner, w, MSG_CHANGED_FOCUS, 0, NULL);
  687. }
  688. }
  689. break;
  690. default:
  691. break;
  692. }
  693. return ret;
  694. }
  695. /* --------------------------------------------------------------------------------------------- */
  696. /**
  697. * Default callback function to destroy widget.
  698. *
  699. * @param w widget
  700. */
  701. void
  702. widget_default_destroy (Widget *w)
  703. {
  704. send_message (w, NULL, MSG_DESTROY, 0, NULL);
  705. g_free (w);
  706. }
  707. /* --------------------------------------------------------------------------------------------- */
  708. /* get mouse pointer location within widget */
  709. Gpm_Event
  710. mouse_get_local (const Gpm_Event *global, const Widget *w)
  711. {
  712. Gpm_Event local;
  713. memset (&local, 0, sizeof (local));
  714. local.buttons = global->buttons;
  715. local.x = global->x - w->rect.x;
  716. local.y = global->y - w->rect.y;
  717. local.type = global->type;
  718. return local;
  719. }
  720. /* --------------------------------------------------------------------------------------------- */
  721. gboolean
  722. mouse_global_in_widget (const Gpm_Event *event, const Widget *w)
  723. {
  724. const WRect *r = &w->rect;
  725. return (event->x > r->x) && (event->y > r->y) && (event->x <= r->x + r->cols)
  726. && (event->y <= r->y + r->lines);
  727. }
  728. /* --------------------------------------------------------------------------------------------- */