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_default_callback
  17. widget_set_options
  18. widget_adjust_position
  19. widget_set_size
  20. widget_set_size_rect
  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_lookup_key
  31. widget_default_make_global
  32. widget_default_make_local
  33. widget_default_find
  34. widget_default_find_by_type
  35. widget_default_find_by_id
  36. widget_default_set_state
  37. widget_default_destroy
  38. mouse_get_local
  39. mouse_global_in_widget

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

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