root/lib/widget/widget-common.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. widget_set_id
  2. widget_default_resize
  3. widget_do_focus
  4. widget_focus
  5. widget_reorder
  6. hotkey_cmp
  7. widget_default_mouse_callback
  8. widget_default_get_colors
  9. hotkey_new
  10. hotkey_free
  11. hotkey_width
  12. hotkey_equal
  13. hotkey_draw
  14. hotkey_get_text
  15. widget_init
  16. widget_destroy
  17. widget_default_callback
  18. widget_set_options
  19. widget_adjust_position
  20. widget_set_size
  21. widget_selectcolor
  22. widget_erase
  23. widget_set_visibility
  24. widget_is_active
  25. widget_draw
  26. widget_replace
  27. widget_is_focusable
  28. widget_select
  29. widget_set_bottom
  30. widget_overlapped
  31. widget_lookup_key
  32. widget_default_find
  33. widget_default_find_by_type
  34. widget_default_find_by_id
  35. widget_default_set_state
  36. mouse_get_local
  37. mouse_global_in_widget

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

/* [previous][next][first][last][top][bottom][index][help]  */