Changes in uspace/lib/ui/src/menu.c [d7f82635:d92b8e8f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/menu.c
rd7f82635 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" … … 58 61 menu_frame_h = 4, 59 62 menu_frame_w_text = 2, 60 menu_frame_h_text = 1 63 menu_frame_h_text = 1, 64 menu_frame_h_margin_text = 1 61 65 }; 62 66 63 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 *); 64 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 *); 65 71 66 72 static ui_popup_cb_t ui_menu_popup_cb = { 67 73 .close = ui_menu_popup_close, 74 .kbd = ui_menu_popup_kbd, 68 75 .pos = ui_menu_popup_pos 69 76 }; … … 71 78 /** Create new menu. 72 79 * 80 * @param parent Parent window 73 81 * @param mbar Menu bar 74 * @param caption Caption75 82 * @param rmenu Place to store pointer to new menu 76 83 * @return EOK on success, ENOMEM if out of memory 77 84 */ 78 errno_t ui_menu_create(ui_menu_bar_t *mbar, const char *caption, 79 ui_menu_t **rmenu) 85 errno_t ui_menu_create(ui_window_t *parent, ui_menu_t **rmenu) 80 86 { 81 87 ui_menu_t *menu; … … 85 91 return ENOMEM; 86 92 87 menu->caption = str_dup(caption); 88 if (menu->caption == NULL) { 89 free(menu); 90 return ENOMEM; 91 } 92 93 menu->mbar = mbar; 94 list_append(&menu->lmenus, &mbar->menus); 93 menu->parent = parent; 95 94 list_initialize(&menu->entries); 96 95 … … 117 116 } 118 117 119 list_remove(&menu->lmenus);120 118 free(menu->caption); 121 119 free(menu); 122 120 } 123 121 124 /** Get first menu in menu bar. 125 * 126 * @param mbar Menu bar 127 * @return First menu or @c NULL if there is none 128 */ 129 ui_menu_t *ui_menu_first(ui_menu_bar_t *mbar) 130 { 131 link_t *link; 132 133 link = list_first(&mbar->menus); 134 if (link == NULL) 135 return NULL; 136 137 return list_get_instance(link, ui_menu_t, lmenus); 138 } 139 140 /** Get next menu in menu bar. 141 * 142 * @param cur Current menu 143 * @return Next menu or @c NULL if @a cur is the last one 144 */ 145 ui_menu_t *ui_menu_next(ui_menu_t *cur) 146 { 147 link_t *link; 148 149 link = list_next(&cur->lmenus, &cur->mbar->menus); 150 if (link == NULL) 151 return NULL; 152 153 return list_get_instance(link, ui_menu_t, lmenus); 154 } 155 156 /** Get menu caption. 157 * 158 * @param menu Menu 159 * @return Caption (owned by @a menu) 160 */ 161 const char *ui_menu_caption(ui_menu_t *menu) 162 { 163 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; 164 132 } 165 133 … … 173 141 ui_menu_geom_t *geom) 174 142 { 175 ui_resource_t *res;176 143 gfx_coord2_t edim; 177 144 gfx_coord_t frame_w; 178 145 gfx_coord_t frame_h; 179 180 res = ui_window_get_res(menu->mbar->window); 146 ui_resource_t *res; 147 148 res = ui_window_get_res(menu->parent); 181 149 182 150 if (res->textmode) { … … 202 170 } 203 171 204 /** Get menu rectangle.205 *206 * @param menu Menu207 * @param spos Starting position (top-left corner)208 * @param rect Place to store menu rectangle209 */210 void ui_menu_get_rect(ui_menu_t *menu, gfx_coord2_t *spos, gfx_rect_t *rect)211 {212 ui_menu_geom_t geom;213 214 ui_menu_get_geom(menu, spos, &geom);215 *rect = geom.outer_rect;216 }217 218 172 /** Get UI resource from menu. 219 173 * … … 230 184 * @param menu Menu 231 185 * @param prect Parent rectangle around which the menu should be placed 232 */ 233 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) 234 189 { 235 190 ui_popup_t *popup = NULL; … … 239 194 errno_t rc; 240 195 196 /* Select first entry */ 197 menu->selected = ui_menu_entry_first(menu); 198 241 199 /* Determine menu dimensions */ 242 200 … … 248 206 params.rect = geom.outer_rect; 249 207 params.place = *prect; 250 251 rc = ui_popup_create(menu->mbar->ui, menu->mbar->window, ¶ms, 252 &popup); 208 params.idev_id = idev_id; 209 210 rc = ui_popup_create(ui_window_get_ui(menu->parent), menu->parent, 211 ¶ms, &popup); 253 212 if (rc != EOK) 254 213 return rc; … … 268 227 ui_popup_destroy(menu->popup); 269 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; 239 } 240 241 /** Paint menu. 242 * 243 * @param menu Menu 244 * @param spos Starting position (top-left corner) 245 * @return EOK on success or an error code 246 */ 247 errno_t ui_menu_paint_bg_gfx(ui_menu_t *menu, gfx_coord2_t *spos) 248 { 249 ui_resource_t *res; 250 ui_menu_geom_t geom; 251 gfx_rect_t bg_rect; 252 errno_t rc; 253 254 res = ui_menu_get_res(menu); 255 ui_menu_get_geom(menu, spos, &geom); 256 257 /* Paint menu frame */ 258 259 rc = gfx_set_color(res->gc, res->wnd_face_color); 260 if (rc != EOK) 261 goto error; 262 263 rc = ui_paint_outset_frame(res, &geom.outer_rect, &bg_rect); 264 if (rc != EOK) 265 goto error; 266 267 /* Paint menu background */ 268 269 rc = gfx_set_color(res->gc, res->wnd_face_color); 270 if (rc != EOK) 271 goto error; 272 273 rc = gfx_fill_rect(res->gc, &bg_rect); 274 if (rc != EOK) 275 goto error; 276 277 return EOK; 278 error: 279 return rc; 280 } 281 282 /** Paint menu. 283 * 284 * @param menu Menu 285 * @param spos Starting position (top-left corner) 286 * @return EOK on success or an error code 287 */ 288 errno_t ui_menu_paint_bg_text(ui_menu_t *menu, gfx_coord2_t *spos) 289 { 290 ui_resource_t *res; 291 ui_menu_geom_t geom; 292 gfx_rect_t rect; 293 errno_t rc; 294 295 res = ui_menu_get_res(menu); 296 ui_menu_get_geom(menu, spos, &geom); 297 298 /* Paint menu background */ 299 300 rc = gfx_set_color(res->gc, res->wnd_face_color); 301 if (rc != EOK) 302 goto error; 303 304 rc = gfx_fill_rect(res->gc, &geom.outer_rect); 305 if (rc != EOK) 306 goto error; 307 308 /* Paint menu box */ 309 310 rect = geom.outer_rect; 311 rect.p0.x += menu_frame_h_margin_text; 312 rect.p1.x -= menu_frame_h_margin_text; 313 314 rc = ui_paint_text_box(res, &rect, ui_box_single, res->wnd_face_color); 315 if (rc != EOK) 316 goto error; 317 318 return EOK; 319 error: 320 return rc; 270 321 } 271 322 … … 282 333 ui_menu_entry_t *mentry; 283 334 ui_menu_geom_t geom; 284 gfx_rect_t bg_rect;285 335 errno_t rc; 286 336 … … 288 338 ui_menu_get_geom(menu, spos, &geom); 289 339 290 /* Paint menu frame */ 291 292 rc = gfx_set_color(res->gc, res->wnd_face_color); 293 if (rc != EOK) 294 goto error; 295 296 rc = ui_paint_outset_frame(res, &geom.outer_rect, &bg_rect); 297 if (rc != EOK) 298 goto error; 299 300 /* Paint menu background */ 301 302 rc = gfx_set_color(res->gc, res->wnd_face_color); 303 if (rc != EOK) 304 goto error; 305 306 rc = gfx_fill_rect(res->gc, &bg_rect); 340 /* Paint menu frame and background */ 341 if (res->textmode) 342 rc = ui_menu_paint_bg_text(menu, spos); 343 else 344 rc = ui_menu_paint_bg_gfx(menu, spos); 307 345 if (rc != EOK) 308 346 goto error; … … 369 407 /* Press outside menu - close it */ 370 408 if (event->type == POS_PRESS) 371 ui_menu_ bar_select(menu->mbar, NULL, NULL);409 ui_menu_close_req(menu); 372 410 } 373 411 374 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 } 375 555 } 376 556 … … 384 564 ui_menu_t *menu = (ui_menu_t *)arg; 385 565 386 /* Close the menu */ 387 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); 388 582 } 389 583 … … 399 593 gfx_coord2_t spos; 400 594 595 menu->idev_id = ui_popup_get_idev_id(menu->popup); 596 401 597 spos.x = 0; 402 598 spos.y = 0; … … 404 600 } 405 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 406 656 /** @} 407 657 */
Note:
See TracChangeset
for help on using the changeset viewer.