Changes in uspace/lib/ui/src/menu.c [ff6e91b:d92b8e8f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/menu.c
rff6e91b rd92b8e8f 1 1 /* 2 * Copyright (c) 202 1Jiri Svoboda2 * Copyright (c) 2024 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 35 35 36 36 #include <adt/list.h> 37 #include <ctype.h> 37 38 #include <errno.h> 38 39 #include <gfx/color.h> … … 43 44 #include <stdlib.h> 44 45 #include <str.h> 46 #include <uchar.h> 47 #include <ui/ui.h> 48 #include <ui/accel.h> 45 49 #include <ui/control.h> 46 50 #include <ui/paint.h> … … 50 54 #include <ui/resource.h> 51 55 #include <ui/window.h> 52 #include "../private/menubar.h"53 56 #include "../private/menu.h" 54 57 #include "../private/resource.h" … … 63 66 64 67 static void ui_menu_popup_close(ui_popup_t *, void *); 68 static void ui_menu_popup_kbd(ui_popup_t *, void *, kbd_event_t *); 65 69 static void ui_menu_popup_pos(ui_popup_t *, void *, pos_event_t *); 70 static void ui_menu_key_press_unmod(ui_menu_t *, kbd_event_t *); 66 71 67 72 static ui_popup_cb_t ui_menu_popup_cb = { 68 73 .close = ui_menu_popup_close, 74 .kbd = ui_menu_popup_kbd, 69 75 .pos = ui_menu_popup_pos 70 76 }; … … 72 78 /** Create new menu. 73 79 * 80 * @param parent Parent window 74 81 * @param mbar Menu bar 75 * @param caption Caption76 82 * @param rmenu Place to store pointer to new menu 77 83 * @return EOK on success, ENOMEM if out of memory 78 84 */ 79 errno_t ui_menu_create(ui_menu_bar_t *mbar, const char *caption, 80 ui_menu_t **rmenu) 85 errno_t ui_menu_create(ui_window_t *parent, ui_menu_t **rmenu) 81 86 { 82 87 ui_menu_t *menu; … … 86 91 return ENOMEM; 87 92 88 menu->caption = str_dup(caption); 89 if (menu->caption == NULL) { 90 free(menu); 91 return ENOMEM; 92 } 93 94 menu->mbar = mbar; 95 list_append(&menu->lmenus, &mbar->menus); 93 menu->parent = parent; 96 94 list_initialize(&menu->entries); 97 95 … … 118 116 } 119 117 120 list_remove(&menu->lmenus);121 118 free(menu->caption); 122 119 free(menu); 123 120 } 124 121 125 /** Get first menu in menu bar. 126 * 127 * @param mbar Menu bar 128 * @return First menu or @c NULL if there is none 129 */ 130 ui_menu_t *ui_menu_first(ui_menu_bar_t *mbar) 131 { 132 link_t *link; 133 134 link = list_first(&mbar->menus); 135 if (link == NULL) 136 return NULL; 137 138 return list_get_instance(link, ui_menu_t, lmenus); 139 } 140 141 /** Get next menu in menu bar. 142 * 143 * @param cur Current menu 144 * @return Next menu or @c NULL if @a cur is the last one 145 */ 146 ui_menu_t *ui_menu_next(ui_menu_t *cur) 147 { 148 link_t *link; 149 150 link = list_next(&cur->lmenus, &cur->mbar->menus); 151 if (link == NULL) 152 return NULL; 153 154 return list_get_instance(link, ui_menu_t, lmenus); 155 } 156 157 /** Get menu caption. 158 * 159 * @param menu Menu 160 * @return Caption (owned by @a menu) 161 */ 162 const char *ui_menu_caption(ui_menu_t *menu) 163 { 164 return menu->caption; 122 /** Set menu callbacks. 123 * 124 * @param menu Menu 125 * @param cb Callbacks 126 * @param arg Callback argument 127 */ 128 void ui_menu_set_cb(ui_menu_t *menu, ui_menu_cb_t *cb, void *arg) 129 { 130 menu->cb = cb; 131 menu->arg = arg; 165 132 } 166 133 … … 174 141 ui_menu_geom_t *geom) 175 142 { 176 ui_resource_t *res;177 143 gfx_coord2_t edim; 178 144 gfx_coord_t frame_w; 179 145 gfx_coord_t frame_h; 180 181 res = ui_window_get_res(menu->mbar->window); 146 ui_resource_t *res; 147 148 res = ui_window_get_res(menu->parent); 182 149 183 150 if (res->textmode) { … … 203 170 } 204 171 205 /** Get menu rectangle.206 *207 * @param menu Menu208 * @param spos Starting position (top-left corner)209 * @param rect Place to store menu rectangle210 */211 void ui_menu_get_rect(ui_menu_t *menu, gfx_coord2_t *spos, gfx_rect_t *rect)212 {213 ui_menu_geom_t geom;214 215 ui_menu_get_geom(menu, spos, &geom);216 *rect = geom.outer_rect;217 }218 219 172 /** Get UI resource from menu. 220 173 * … … 231 184 * @param menu Menu 232 185 * @param prect Parent rectangle around which the menu should be placed 233 */ 234 errno_t ui_menu_open(ui_menu_t *menu, gfx_rect_t *prect) 186 * @param idev_id Input device associated with the menu's seat 187 */ 188 errno_t ui_menu_open(ui_menu_t *menu, gfx_rect_t *prect, sysarg_t idev_id) 235 189 { 236 190 ui_popup_t *popup = NULL; … … 240 194 errno_t rc; 241 195 196 /* Select first entry */ 197 menu->selected = ui_menu_entry_first(menu); 198 242 199 /* Determine menu dimensions */ 243 200 … … 249 206 params.rect = geom.outer_rect; 250 207 params.place = *prect; 251 252 rc = ui_popup_create(menu->mbar->ui, menu->mbar->window, ¶ms, 253 &popup); 208 params.idev_id = idev_id; 209 210 rc = ui_popup_create(ui_window_get_ui(menu->parent), menu->parent, 211 ¶ms, &popup); 254 212 if (rc != EOK) 255 213 return rc; … … 269 227 ui_popup_destroy(menu->popup); 270 228 menu->popup = NULL; 229 } 230 231 /** Determine if menu is open. 232 * 233 * @param menu Menu 234 * @return @c true iff menu is open 235 */ 236 bool ui_menu_is_open(ui_menu_t *menu) 237 { 238 return menu->popup != NULL; 271 239 } 272 240 … … 439 407 /* Press outside menu - close it */ 440 408 if (event->type == POS_PRESS) 441 ui_menu_ bar_select(menu->mbar, NULL, NULL);409 ui_menu_close_req(menu); 442 410 } 443 411 444 412 return ui_unclaimed; 413 } 414 415 /** Handle keyboard event in menu. 416 * 417 * @param menu Menu 418 * @param event Keyboard event 419 * @return ui_claimed iff the event was claimed 420 */ 421 ui_evclaim_t ui_menu_kbd_event(ui_menu_t *menu, kbd_event_t *event) 422 { 423 if (event->type == KEY_PRESS && (event->mods & 424 (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) { 425 ui_menu_key_press_unmod(menu, event); 426 } 427 428 if (event->type == KEY_PRESS && (event->mods & KM_ALT) != 0 && 429 (event->mods & (KM_CTRL | KM_SHIFT)) == 0 && event->c != '\0') 430 ui_menu_press_accel(menu, event->c, event->kbd_id); 431 432 return ui_claimed; 433 } 434 435 /** Move one entry up. 436 * 437 * Non-selectable entries are skipped. If we are already at the top, 438 * we wrap around. 439 * 440 * @param menu Menu 441 */ 442 void ui_menu_up(ui_menu_t *menu) 443 { 444 gfx_coord2_t mpos; 445 ui_menu_entry_t *nentry; 446 447 if (menu->selected == NULL) 448 return; 449 450 nentry = ui_menu_entry_prev(menu->selected); 451 if (nentry == NULL) 452 nentry = ui_menu_entry_last(menu); 453 454 /* Need to find a selectable entry */ 455 while (!ui_menu_entry_selectable(nentry)) { 456 nentry = ui_menu_entry_prev(nentry); 457 if (nentry == NULL) 458 nentry = ui_menu_entry_last(menu); 459 460 /* Went completely around and found nothing? */ 461 if (nentry == menu->selected) 462 return; 463 } 464 465 menu->selected = nentry; 466 467 mpos.x = 0; 468 mpos.y = 0; 469 (void) ui_menu_paint(menu, &mpos); 470 } 471 472 /** Move one entry down. 473 * 474 * Non-selectable entries are skipped. If we are already at the bottom, 475 * we wrap around. 476 * 477 * @param menu Menu 478 */ 479 void ui_menu_down(ui_menu_t *menu) 480 { 481 gfx_coord2_t mpos; 482 ui_menu_entry_t *nentry; 483 484 if (menu->selected == NULL) 485 return; 486 487 nentry = ui_menu_entry_next(menu->selected); 488 if (nentry == NULL) 489 nentry = ui_menu_entry_first(menu); 490 491 /* Need to find a selectable entry */ 492 while (!ui_menu_entry_selectable(nentry)) { 493 nentry = ui_menu_entry_next(nentry); 494 if (nentry == NULL) 495 nentry = ui_menu_entry_first(menu); 496 497 /* Went completely around and found nothing? */ 498 if (nentry == menu->selected) 499 return; 500 } 501 502 menu->selected = nentry; 503 504 mpos.x = 0; 505 mpos.y = 0; 506 (void) ui_menu_paint(menu, &mpos); 507 } 508 509 /** Handle key press without modifiers in menu popup window. 510 * 511 * @param menu Menu 512 * @param event Keyboard event 513 */ 514 static void ui_menu_key_press_unmod(ui_menu_t *menu, kbd_event_t *event) 515 { 516 ui_menu_entry_t *mentry; 517 char32_t c; 518 519 switch (event->key) { 520 case KC_ESCAPE: 521 ui_menu_close_req(menu); 522 break; 523 case KC_LEFT: 524 ui_menu_left(menu, event->kbd_id); 525 break; 526 case KC_RIGHT: 527 ui_menu_right(menu, event->kbd_id); 528 break; 529 case KC_UP: 530 ui_menu_up(menu); 531 break; 532 case KC_DOWN: 533 ui_menu_down(menu); 534 break; 535 case KC_ENTER: 536 if (menu->selected != NULL && 537 !ui_menu_entry_is_disabled(menu->selected)) 538 ui_menu_entry_activate(menu->selected); 539 break; 540 default: 541 if (event->c != '\0') { 542 mentry = ui_menu_entry_first(menu); 543 while (mentry != NULL) { 544 c = ui_menu_entry_get_accel(mentry); 545 if (c == (char32_t)tolower(event->c) && 546 !ui_menu_entry_is_disabled(mentry)) { 547 ui_menu_entry_activate(mentry); 548 break; 549 } 550 mentry = ui_menu_entry_next(mentry); 551 } 552 } 553 break; 554 } 445 555 } 446 556 … … 454 564 ui_menu_t *menu = (ui_menu_t *)arg; 455 565 456 /* Close the menu */ 457 ui_menu_bar_select(menu->mbar, NULL, NULL); 566 /* Forward close request to caller */ 567 ui_menu_close_req(menu); 568 } 569 570 /** Handle keyboard event in menu popup window. 571 * 572 * @param popup Menu popup window 573 * @param arg Argument (ui_menu_t *) 574 * @param event Keyboard event 575 */ 576 static void ui_menu_popup_kbd(ui_popup_t *popup, void *arg, kbd_event_t *event) 577 { 578 ui_menu_t *menu = (ui_menu_t *)arg; 579 580 menu->idev_id = ui_popup_get_idev_id(menu->popup); 581 ui_menu_kbd_event(menu, event); 458 582 } 459 583 … … 469 593 gfx_coord2_t spos; 470 594 595 menu->idev_id = ui_popup_get_idev_id(menu->popup); 596 471 597 spos.x = 0; 472 598 spos.y = 0; … … 474 600 } 475 601 602 /** Send menu left event. 603 * 604 * @param menu Menu 605 * @param idev_id Input device ID 606 */ 607 void ui_menu_left(ui_menu_t *menu, sysarg_t idev_id) 608 { 609 if (menu->cb != NULL && menu->cb->left != NULL) 610 menu->cb->left(menu, menu->arg, idev_id); 611 } 612 613 /** Send menu right event. 614 * 615 * @param menu Menu 616 * @param idev_id Input device ID 617 */ 618 void ui_menu_right(ui_menu_t *menu, sysarg_t idev_id) 619 { 620 if (menu->cb != NULL && menu->cb->right != NULL) 621 menu->cb->right(menu, menu->arg, idev_id); 622 } 623 624 /** Send menu close request event. 625 * 626 * @param menu Menu 627 */ 628 void ui_menu_close_req(ui_menu_t *menu) 629 { 630 if (menu->cb != NULL && menu->cb->close_req != NULL) 631 menu->cb->close_req(menu, menu->arg); 632 } 633 634 /** Send menu accelerator key press event. 635 * 636 * @param menu Menu 637 * @param c Character 638 * @param kbd_id Keyboard ID 639 */ 640 void ui_menu_press_accel(ui_menu_t *menu, char32_t c, sysarg_t kbd_id) 641 { 642 if (menu->cb != NULL && menu->cb->press_accel != NULL) 643 menu->cb->press_accel(menu, menu->arg, c, kbd_id); 644 } 645 646 /** Get ID of last device that input event. 647 * 648 * @param menu Menu 649 * @return Input device ID 650 */ 651 sysarg_t ui_menu_get_idev_id(ui_menu_t *menu) 652 { 653 return menu->idev_id; 654 } 655 476 656 /** @} 477 657 */
Note:
See TracChangeset
for help on using the changeset viewer.