widget-common.c 23 KB

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