Changes in uspace/lib/ui/src/menu.c [d92b8e8f:d7f82635] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/menu.c
rd92b8e8f rd7f82635 1 1 /* 2 * Copyright (c) 202 4Jiri Svoboda2 * Copyright (c) 2021 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 35 35 36 36 #include <adt/list.h> 37 #include <ctype.h>38 37 #include <errno.h> 39 38 #include <gfx/color.h> … … 44 43 #include <stdlib.h> 45 44 #include <str.h> 46 #include <uchar.h>47 #include <ui/ui.h>48 #include <ui/accel.h>49 45 #include <ui/control.h> 50 46 #include <ui/paint.h> … … 54 50 #include <ui/resource.h> 55 51 #include <ui/window.h> 52 #include "../private/menubar.h" 56 53 #include "../private/menu.h" 57 54 #include "../private/resource.h" … … 61 58 menu_frame_h = 4, 62 59 menu_frame_w_text = 2, 63 menu_frame_h_text = 1, 64 menu_frame_h_margin_text = 1 60 menu_frame_h_text = 1 65 61 }; 66 62 67 63 static void ui_menu_popup_close(ui_popup_t *, void *); 68 static void ui_menu_popup_kbd(ui_popup_t *, void *, kbd_event_t *);69 64 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 *);71 65 72 66 static ui_popup_cb_t ui_menu_popup_cb = { 73 67 .close = ui_menu_popup_close, 74 .kbd = ui_menu_popup_kbd,75 68 .pos = ui_menu_popup_pos 76 69 }; … … 78 71 /** Create new menu. 79 72 * 80 * @param parent Parent window81 73 * @param mbar Menu bar 74 * @param caption Caption 82 75 * @param rmenu Place to store pointer to new menu 83 76 * @return EOK on success, ENOMEM if out of memory 84 77 */ 85 errno_t ui_menu_create(ui_window_t *parent, ui_menu_t **rmenu) 78 errno_t ui_menu_create(ui_menu_bar_t *mbar, const char *caption, 79 ui_menu_t **rmenu) 86 80 { 87 81 ui_menu_t *menu; … … 91 85 return ENOMEM; 92 86 93 menu->parent = parent; 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); 94 95 list_initialize(&menu->entries); 95 96 … … 116 117 } 117 118 119 list_remove(&menu->lmenus); 118 120 free(menu->caption); 119 121 free(menu); 120 122 } 121 123 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; 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; 132 164 } 133 165 … … 141 173 ui_menu_geom_t *geom) 142 174 { 175 ui_resource_t *res; 143 176 gfx_coord2_t edim; 144 177 gfx_coord_t frame_w; 145 178 gfx_coord_t frame_h; 146 ui_resource_t *res; 147 148 res = ui_window_get_res(menu->parent); 179 180 res = ui_window_get_res(menu->mbar->window); 149 181 150 182 if (res->textmode) { … … 170 202 } 171 203 204 /** Get menu rectangle. 205 * 206 * @param menu Menu 207 * @param spos Starting position (top-left corner) 208 * @param rect Place to store menu rectangle 209 */ 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 172 218 /** Get UI resource from menu. 173 219 * … … 184 230 * @param menu Menu 185 231 * @param prect Parent rectangle around which the menu should be placed 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) 232 */ 233 errno_t ui_menu_open(ui_menu_t *menu, gfx_rect_t *prect) 189 234 { 190 235 ui_popup_t *popup = NULL; … … 194 239 errno_t rc; 195 240 196 /* Select first entry */197 menu->selected = ui_menu_entry_first(menu);198 199 241 /* Determine menu dimensions */ 200 242 … … 206 248 params.rect = geom.outer_rect; 207 249 params.place = *prect; 208 params.idev_id = idev_id; 209 210 rc = ui_popup_create(ui_window_get_ui(menu->parent), menu->parent, 211 ¶ms, &popup); 250 251 rc = ui_popup_create(menu->mbar->ui, menu->mbar->window, ¶ms, 252 &popup); 212 253 if (rc != EOK) 213 254 return rc; … … 227 268 ui_popup_destroy(menu->popup); 228 269 menu->popup = NULL; 229 }230 231 /** Determine if menu is open.232 *233 * @param menu Menu234 * @return @c true iff menu is open235 */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 Menu244 * @param spos Starting position (top-left corner)245 * @return EOK on success or an error code246 */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 Menu285 * @param spos Starting position (top-left corner)286 * @return EOK on success or an error code287 */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;321 270 } 322 271 … … 333 282 ui_menu_entry_t *mentry; 334 283 ui_menu_geom_t geom; 284 gfx_rect_t bg_rect; 335 285 errno_t rc; 336 286 … … 338 288 ui_menu_get_geom(menu, spos, &geom); 339 289 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); 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); 345 307 if (rc != EOK) 346 308 goto error; … … 407 369 /* Press outside menu - close it */ 408 370 if (event->type == POS_PRESS) 409 ui_menu_ close_req(menu);371 ui_menu_bar_select(menu->mbar, NULL, NULL); 410 372 } 411 373 412 374 return ui_unclaimed; 413 }414 415 /** Handle keyboard event in menu.416 *417 * @param menu Menu418 * @param event Keyboard event419 * @return ui_claimed iff the event was claimed420 */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 Menu441 */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 Menu478 */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 Menu512 * @param event Keyboard event513 */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 }555 375 } 556 376 … … 564 384 ui_menu_t *menu = (ui_menu_t *)arg; 565 385 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); 386 /* Close the menu */ 387 ui_menu_bar_select(menu->mbar, NULL, NULL); 582 388 } 583 389 … … 593 399 gfx_coord2_t spos; 594 400 595 menu->idev_id = ui_popup_get_idev_id(menu->popup);596 597 401 spos.x = 0; 598 402 spos.y = 0; … … 600 404 } 601 405 602 /** Send menu left event.603 *604 * @param menu Menu605 * @param idev_id Input device ID606 */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 Menu616 * @param idev_id Input device ID617 */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 Menu627 */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 Menu637 * @param c Character638 * @param kbd_id Keyboard ID639 */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 Menu649 * @return Input device ID650 */651 sysarg_t ui_menu_get_idev_id(ui_menu_t *menu)652 {653 return menu->idev_id;654 }655 656 406 /** @} 657 407 */
Note:
See TracChangeset
for help on using the changeset viewer.