widget-common.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  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)
  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) && hotkey_cmp (hotkey1.end, hotkey2.end);
  199. /* *INDENT-ON* */
  200. }
  201. /* --------------------------------------------------------------------------------------------- */
  202. void
  203. hotkey_draw (const Widget *w, const hotkey_t hotkey, gboolean focused)
  204. {
  205. if (hotkey.start[0] != '\0')
  206. {
  207. widget_selectcolor (w, focused, FALSE);
  208. tty_print_string (hotkey.start);
  209. }
  210. if (hotkey.hotkey != NULL)
  211. {
  212. widget_selectcolor (w, focused, TRUE);
  213. tty_print_string (hotkey.hotkey);
  214. }
  215. if (hotkey.end != NULL)
  216. {
  217. widget_selectcolor (w, focused, FALSE);
  218. tty_print_string (hotkey.end);
  219. }
  220. }
  221. /* --------------------------------------------------------------------------------------------- */
  222. char *
  223. hotkey_get_text (const hotkey_t hotkey)
  224. {
  225. GString *text;
  226. text = g_string_new (hotkey.start);
  227. if (hotkey.hotkey != NULL)
  228. {
  229. g_string_append_c (text, '&');
  230. g_string_append (text, hotkey.hotkey);
  231. }
  232. if (hotkey.end != NULL)
  233. g_string_append (text, hotkey.end);
  234. return g_string_free (text, FALSE);
  235. }
  236. /* --------------------------------------------------------------------------------------------- */
  237. void
  238. widget_init (Widget *w, const WRect *r, widget_cb_fn callback, widget_mouse_cb_fn mouse_callback)
  239. {
  240. w->id = widget_set_id ();
  241. w->rect = *r;
  242. w->pos_flags = WPOS_KEEP_DEFAULT;
  243. w->callback = callback;
  244. w->keymap = NULL;
  245. w->ext_keymap = NULL;
  246. w->ext_mode = FALSE;
  247. w->mouse_callback = mouse_callback != NULL ? mouse_callback : widget_default_mouse_callback;
  248. w->owner = NULL;
  249. w->mouse_handler = mouse_handle_event;
  250. w->mouse.forced_capture = FALSE;
  251. w->mouse.capture = FALSE;
  252. w->mouse.last_msg = MSG_MOUSE_NONE;
  253. w->mouse.last_buttons_down = 0;
  254. w->options = WOP_DEFAULT;
  255. w->state = WST_CONSTRUCT | WST_VISIBLE;
  256. w->make_global = widget_default_make_global;
  257. w->make_local = widget_default_make_local;
  258. w->find = widget_default_find;
  259. w->find_by_type = widget_default_find_by_type;
  260. w->find_by_id = widget_default_find_by_id;
  261. w->set_state = widget_default_set_state;
  262. w->destroy = widget_default_destroy;
  263. w->get_colors = widget_default_get_colors;
  264. }
  265. /* --------------------------------------------------------------------------------------------- */
  266. /* Default callback for widgets */
  267. cb_ret_t
  268. widget_default_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
  269. {
  270. (void) sender;
  271. (void) parm;
  272. switch (msg)
  273. {
  274. case MSG_INIT:
  275. case MSG_FOCUS:
  276. case MSG_UNFOCUS:
  277. case MSG_ENABLE:
  278. case MSG_DISABLE:
  279. case MSG_DRAW:
  280. case MSG_DESTROY:
  281. case MSG_CURSOR:
  282. case MSG_IDLE:
  283. return MSG_HANDLED;
  284. case MSG_RESIZE:
  285. return widget_default_resize (w, CONST_RECT (data));
  286. default:
  287. return MSG_NOT_HANDLED;
  288. }
  289. }
  290. /* --------------------------------------------------------------------------------------------- */
  291. /**
  292. * Apply new options to widget.
  293. *
  294. * @param w widget
  295. * @param options widget option flags to modify. Several flags per call can be modified.
  296. * @param enable TRUE if specified options should be added, FALSE if options should be removed
  297. */
  298. void
  299. widget_set_options (Widget *w, widget_options_t options, gboolean enable)
  300. {
  301. if (enable)
  302. w->options |= options;
  303. else
  304. w->options &= ~options;
  305. }
  306. /* --------------------------------------------------------------------------------------------- */
  307. void
  308. widget_adjust_position (widget_pos_flags_t pos_flags, WRect *r)
  309. {
  310. if ((pos_flags & WPOS_FULLSCREEN) != 0)
  311. {
  312. r->y = 0;
  313. r->x = 0;
  314. r->lines = LINES;
  315. r->cols = COLS;
  316. }
  317. else
  318. {
  319. if ((pos_flags & WPOS_CENTER_HORZ) != 0)
  320. r->x = (COLS - r->cols) / 2;
  321. if ((pos_flags & WPOS_CENTER_VERT) != 0)
  322. r->y = (LINES - r->lines) / 2;
  323. if ((pos_flags & WPOS_TRYUP) != 0)
  324. {
  325. if (r->y > 3)
  326. r->y -= 2;
  327. else if (r->y == 3)
  328. r->y = 2;
  329. }
  330. }
  331. }
  332. /* --------------------------------------------------------------------------------------------- */
  333. /**
  334. * Change widget position and size.
  335. *
  336. * @param w widget
  337. * @param y y coordinate of top-left corner
  338. * @param x x coordinate of top-left corner
  339. * @param lines width
  340. * @param cols height
  341. */
  342. void
  343. widget_set_size (Widget *w, int y, int x, int lines, int cols)
  344. {
  345. WRect r = { y, x, lines, cols };
  346. send_message (w, NULL, MSG_RESIZE, 0, &r);
  347. widget_draw (w);
  348. }
  349. /* --------------------------------------------------------------------------------------------- */
  350. /**
  351. * Change widget position and size.
  352. *
  353. * @param w widget
  354. * @param r WRect object that holds position and size
  355. */
  356. void
  357. widget_set_size_rect (Widget *w, WRect *r)
  358. {
  359. send_message (w, NULL, MSG_RESIZE, 0, r);
  360. widget_draw (w);
  361. }
  362. /* --------------------------------------------------------------------------------------------- */
  363. void
  364. widget_selectcolor (const Widget *w, gboolean focused, gboolean hotkey)
  365. {
  366. int color;
  367. const int *colors;
  368. colors = widget_get_colors (w);
  369. if (widget_get_state (w, WST_DISABLED))
  370. color = DISABLED_COLOR;
  371. else if (hotkey)
  372. color = colors[focused ? DLG_COLOR_HOT_FOCUS : DLG_COLOR_HOT_NORMAL];
  373. else
  374. color = colors[focused ? DLG_COLOR_FOCUS : DLG_COLOR_NORMAL];
  375. tty_setcolor (color);
  376. }
  377. /* --------------------------------------------------------------------------------------------- */
  378. void
  379. widget_erase (Widget *w)
  380. {
  381. if (w != NULL)
  382. tty_fill_region (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, ' ');
  383. }
  384. /* --------------------------------------------------------------------------------------------- */
  385. void
  386. widget_set_visibility (Widget *w, gboolean make_visible)
  387. {
  388. if (widget_get_state (w, WST_VISIBLE) != make_visible)
  389. widget_set_state (w, WST_VISIBLE, make_visible);
  390. }
  391. /* --------------------------------------------------------------------------------------------- */
  392. /**
  393. * Check whether widget is active or not.
  394. * Widget is active if it's current in the its owner and each owner in the chain is current too.
  395. *
  396. * @param w the widget
  397. *
  398. * @return TRUE if the widget is active, FALSE otherwise
  399. */
  400. gboolean
  401. widget_is_active (const void *w)
  402. {
  403. const WGroup *owner;
  404. /* Is group top? */
  405. if (w == top_dlg->data)
  406. return TRUE;
  407. owner = CONST_WIDGET (w)->owner;
  408. /* Is widget in any group? */
  409. if (owner == NULL)
  410. return FALSE;
  411. if (w != owner->current->data)
  412. return FALSE;
  413. return widget_is_active (owner);
  414. }
  415. /* --------------------------------------------------------------------------------------------- */
  416. cb_ret_t
  417. widget_draw (Widget *w)
  418. {
  419. cb_ret_t ret = MSG_NOT_HANDLED;
  420. if (w != NULL && widget_get_state (w, WST_VISIBLE))
  421. {
  422. WGroup *g = w->owner;
  423. if (g != NULL && widget_get_state (WIDGET (g), WST_ACTIVE))
  424. ret = w->callback (w, NULL, MSG_DRAW, 0, NULL);
  425. }
  426. return ret;
  427. }
  428. /* --------------------------------------------------------------------------------------------- */
  429. /**
  430. * Replace widget in the dialog.
  431. *
  432. * @param old_w old widget that need to be replaced
  433. * @param new_w new widget that will replace @old_w
  434. */
  435. void
  436. widget_replace (Widget *old_w, Widget *new_w)
  437. {
  438. WGroup *g = old_w->owner;
  439. gboolean should_focus = FALSE;
  440. GList *holder;
  441. if (g->widgets == NULL)
  442. return;
  443. if (g->current == NULL)
  444. g->current = g->widgets;
  445. /* locate widget position in the list */
  446. if (old_w == g->current->data)
  447. holder = g->current;
  448. else
  449. holder = g_list_find (g->widgets, old_w);
  450. /* if old widget is focused, we should focus the new one... */
  451. if (widget_get_state (old_w, WST_FOCUSED))
  452. should_focus = TRUE;
  453. /* ...but if new widget isn't selectable, we cannot focus it */
  454. if (!widget_get_options (new_w, WOP_SELECTABLE))
  455. should_focus = FALSE;
  456. /* if new widget isn't selectable, select other widget before replace */
  457. if (!should_focus)
  458. {
  459. GList *l;
  460. for (l = group_get_widget_next_of (holder);
  461. !widget_is_focusable (WIDGET (l->data)) && l != holder;
  462. l = group_get_widget_next_of (l))
  463. ;
  464. widget_select (WIDGET (l->data));
  465. }
  466. /* replace widget */
  467. new_w->owner = g;
  468. new_w->id = old_w->id;
  469. holder->data = new_w;
  470. send_message (old_w, NULL, MSG_DESTROY, 0, NULL);
  471. send_message (new_w, NULL, MSG_INIT, 0, NULL);
  472. if (should_focus)
  473. widget_select (new_w);
  474. else
  475. widget_draw (new_w);
  476. }
  477. /* --------------------------------------------------------------------------------------------- */
  478. gboolean
  479. widget_is_focusable (const Widget *w)
  480. {
  481. return (widget_get_options (w, WOP_SELECTABLE) && widget_get_state (w, WST_VISIBLE)
  482. && !widget_get_state (w, WST_DISABLED));
  483. }
  484. /* --------------------------------------------------------------------------------------------- */
  485. /**
  486. * Select specified widget in it's owner.
  487. *
  488. * Note: this function (and widget_focus(), which it calls) is a no-op
  489. * if the widget is already selected.
  490. *
  491. * @param w widget to be selected
  492. */
  493. void
  494. widget_select (Widget *w)
  495. {
  496. WGroup *g;
  497. if (!widget_get_options (w, WOP_SELECTABLE))
  498. return;
  499. g = GROUP (w->owner);
  500. if (g != NULL)
  501. {
  502. if (widget_get_options (w, WOP_TOP_SELECT))
  503. {
  504. GList *l;
  505. l = widget_find (WIDGET (g), w);
  506. widget_reorder (l, TRUE);
  507. }
  508. widget_focus (w);
  509. }
  510. }
  511. /* --------------------------------------------------------------------------------------------- */
  512. /**
  513. * Set widget at bottom of widget list.
  514. */
  515. void
  516. widget_set_bottom (Widget *w)
  517. {
  518. widget_reorder (widget_find (WIDGET (w->owner), w), FALSE);
  519. }
  520. /* --------------------------------------------------------------------------------------------- */
  521. /**
  522. * Look up key event of widget and translate it to command ID.
  523. * @param w widget
  524. * @param key key event
  525. *
  526. * @return command ID binded with @key.
  527. */
  528. long
  529. widget_lookup_key (Widget *w, int key)
  530. {
  531. if (w->ext_mode)
  532. {
  533. w->ext_mode = FALSE;
  534. return keybind_lookup_keymap_command (w->ext_keymap, key);
  535. }
  536. return keybind_lookup_keymap_command (w->keymap, key);
  537. }
  538. /* --------------------------------------------------------------------------------------------- */
  539. /**
  540. * Default widget callback to convert widget coordinates from local (relative to owner) to global
  541. * (relative to screen).
  542. *
  543. * @param w widget
  544. * @delta offset for top-left corner coordinates. Used for child widgets of WGroup
  545. */
  546. void
  547. widget_default_make_global (Widget *w, const WRect *delta)
  548. {
  549. if (delta != NULL)
  550. rect_move (&w->rect, delta->y, delta->x);
  551. else if (w->owner != NULL)
  552. rect_move (&w->rect, WIDGET (w->owner)->rect.y, WIDGET (w->owner)->rect.x);
  553. }
  554. /* --------------------------------------------------------------------------------------------- */
  555. /**
  556. * Default widget callback to convert widget coordinates from global (relative to screen) to local
  557. * (relative to owner).
  558. *
  559. * @param w widget
  560. * @delta offset for top-left corner coordinates. Used for child widgets of WGroup
  561. */
  562. void
  563. widget_default_make_local (Widget *w, const WRect *delta)
  564. {
  565. if (delta != NULL)
  566. rect_move (&w->rect, -delta->y, -delta->x);
  567. else if (w->owner != NULL)
  568. rect_move (&w->rect, -WIDGET (w->owner)->rect.y, -WIDGET (w->owner)->rect.x);
  569. }
  570. /* --------------------------------------------------------------------------------------------- */
  571. /**
  572. * Default callback function to find widget.
  573. *
  574. * @param w widget
  575. * @param what widget to find
  576. *
  577. * @return holder of @what if widget is @what, NULL otherwise
  578. */
  579. GList *
  580. widget_default_find (const Widget *w, const Widget *what)
  581. {
  582. return (w != what || w->owner == NULL) ? NULL
  583. : g_list_find (CONST_GROUP (w->owner)->widgets, what);
  584. }
  585. /* --------------------------------------------------------------------------------------------- */
  586. /**
  587. * Default callback function to find widget by widget type using widget callback.
  588. *
  589. * @param w widget
  590. * @param cb widget callback
  591. *
  592. * @return @w if widget callback is @cb, NULL otherwise
  593. */
  594. Widget *
  595. widget_default_find_by_type (const Widget *w, widget_cb_fn cb)
  596. {
  597. return (w->callback == cb ? WIDGET (w) : NULL);
  598. }
  599. /* --------------------------------------------------------------------------------------------- */
  600. /**
  601. * Default callback function to find widget by widget ID.
  602. *
  603. * @param w widget
  604. * @param id widget ID
  605. *
  606. * @return @w if widget id is equal to @id, NULL otherwise
  607. */
  608. Widget *
  609. widget_default_find_by_id (const Widget *w, unsigned long id)
  610. {
  611. return (w->id == id ? WIDGET (w) : NULL);
  612. }
  613. /* --------------------------------------------------------------------------------------------- */
  614. /**
  615. * Default callback function to modify state of widget.
  616. *
  617. * @param w widget
  618. * @param state widget state flag to modify
  619. * @param enable specifies whether to turn the flag on (TRUE) or off (FALSE).
  620. * Only one flag per call can be modified.
  621. * @return MSG_HANDLED if set was handled successfully, MSG_NOT_HANDLED otherwise.
  622. */
  623. cb_ret_t
  624. widget_default_set_state (Widget *w, widget_state_t state, gboolean enable)
  625. {
  626. gboolean ret = MSG_HANDLED;
  627. Widget *owner = WIDGET (GROUP (w->owner));
  628. if (enable)
  629. w->state |= state;
  630. else
  631. w->state &= ~state;
  632. if (enable)
  633. {
  634. /* exclusive bits */
  635. switch (state)
  636. {
  637. case WST_CONSTRUCT:
  638. w->state &= ~(WST_ACTIVE | WST_SUSPENDED | WST_CLOSED);
  639. break;
  640. case WST_ACTIVE:
  641. w->state &= ~(WST_CONSTRUCT | WST_SUSPENDED | WST_CLOSED);
  642. break;
  643. case WST_SUSPENDED:
  644. w->state &= ~(WST_CONSTRUCT | WST_ACTIVE | WST_CLOSED);
  645. break;
  646. case WST_CLOSED:
  647. w->state &= ~(WST_CONSTRUCT | WST_ACTIVE | WST_SUSPENDED);
  648. break;
  649. default:
  650. break;
  651. }
  652. }
  653. if (owner == NULL)
  654. return MSG_NOT_HANDLED;
  655. switch (state)
  656. {
  657. case WST_VISIBLE:
  658. if (widget_get_state (owner, WST_ACTIVE))
  659. {
  660. /* redraw owner to show/hide widget */
  661. widget_draw (owner);
  662. if (!enable)
  663. {
  664. /* try select another widget if current one got hidden */
  665. if (w == GROUP (owner)->current->data)
  666. group_select_next_widget (GROUP (owner));
  667. widget_update_cursor (owner); /* FIXME: unneeded? */
  668. }
  669. }
  670. break;
  671. case WST_DISABLED:
  672. ret = send_message (w, NULL, enable ? MSG_DISABLE : MSG_ENABLE, 0, NULL);
  673. if (ret == MSG_HANDLED && widget_get_state (owner, WST_ACTIVE))
  674. ret = widget_draw (w);
  675. break;
  676. case WST_FOCUSED:
  677. {
  678. widget_msg_t msg;
  679. msg = enable ? MSG_FOCUS : MSG_UNFOCUS;
  680. ret = send_message (w, NULL, msg, 0, NULL);
  681. if (ret == MSG_HANDLED && widget_get_state (owner, WST_ACTIVE))
  682. {
  683. widget_draw (w);
  684. /* Notify owner that focus was moved from one widget to another */
  685. send_message (owner, w, MSG_CHANGED_FOCUS, 0, NULL);
  686. }
  687. }
  688. break;
  689. default:
  690. break;
  691. }
  692. return ret;
  693. }
  694. /* --------------------------------------------------------------------------------------------- */
  695. /**
  696. * Default callback function to destroy widget.
  697. *
  698. * @param w widget
  699. */
  700. void
  701. widget_default_destroy (Widget *w)
  702. {
  703. send_message (w, NULL, MSG_DESTROY, 0, NULL);
  704. g_free (w);
  705. }
  706. /* --------------------------------------------------------------------------------------------- */
  707. /* get mouse pointer location within widget */
  708. Gpm_Event
  709. mouse_get_local (const Gpm_Event *global, const Widget *w)
  710. {
  711. Gpm_Event local;
  712. memset (&local, 0, sizeof (local));
  713. local.buttons = global->buttons;
  714. local.x = global->x - w->rect.x;
  715. local.y = global->y - w->rect.y;
  716. local.type = global->type;
  717. return local;
  718. }
  719. /* --------------------------------------------------------------------------------------------- */
  720. gboolean
  721. mouse_global_in_widget (const Gpm_Event *event, const Widget *w)
  722. {
  723. const WRect *r = &w->rect;
  724. return (event->x > r->x) && (event->y > r->y) && (event->x <= r->x + r->cols)
  725. && (event->y <= r->y + r->lines);
  726. }
  727. /* --------------------------------------------------------------------------------------------- */