/* * Copyright (c) 2023 Jiri Svoboda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup libui * @{ */ /** * @file Menu drop-down * * One of the drop-down menus of a menu bar. This class takes the generic * ui_menu and ties it to the menu bar. */ #include #include #include #include #include #include #include #include #include #include "../private/menubar.h" #include "../private/menudd.h" static void ui_menu_dd_left(ui_menu_t *, void *, sysarg_t); static void ui_menu_dd_right(ui_menu_t *, void *, sysarg_t); static void ui_menu_dd_close_req(ui_menu_t *, void *); static void ui_menu_dd_press_accel(ui_menu_t *, void *, char32_t, sysarg_t); static ui_menu_cb_t ui_menu_dd_menu_cb = { .left = ui_menu_dd_left, .right = ui_menu_dd_right, .close_req = ui_menu_dd_close_req, .press_accel = ui_menu_dd_press_accel }; /** Create new menu drop-down. * * @param mbar Menu bar * @param caption Caption * @param rmdd Place to store pointer to new menu drop-down or @c NULL * @param rmenu Place to store pointer to new menu or @c NULL * @return EOK on success, ENOMEM if out of memory */ errno_t ui_menu_dd_create(ui_menu_bar_t *mbar, const char *caption, ui_menu_dd_t **rmdd, ui_menu_t **rmenu) { errno_t rc; ui_menu_dd_t *mdd; mdd = calloc(1, sizeof(ui_menu_dd_t)); if (mdd == NULL) return ENOMEM; mdd->caption = str_dup(caption); if (mdd->caption == NULL) { free(mdd); return ENOMEM; } /* Create menu */ rc = ui_menu_create(mbar->window, &mdd->menu); if (rc != EOK) { free(mdd->caption); free(mdd); return rc; } mdd->mbar = mbar; list_append(&mdd->lmenudds, &mbar->menudds); ui_menu_set_cb(mdd->menu, &ui_menu_dd_menu_cb, (void *)mdd); if (rmdd != NULL) *rmdd = mdd; if (rmenu != NULL) *rmenu = mdd->menu; return EOK; } /** Destroy menu drop-down. * * @param menu Menu or @c NULL */ void ui_menu_dd_destroy(ui_menu_dd_t *mdd) { if (mdd == NULL) return; /* Destroy menu */ ui_menu_destroy(mdd->menu); list_remove(&mdd->lmenudds); free(mdd->caption); free(mdd); } /** Get first menu drop-down in menu bar. * * @param mbar Menu bar * @return First menu or @c NULL if there is none */ ui_menu_dd_t *ui_menu_dd_first(ui_menu_bar_t *mbar) { link_t *link; link = list_first(&mbar->menudds); if (link == NULL) return NULL; return list_get_instance(link, ui_menu_dd_t, lmenudds); } /** Get next menu drop-down in menu bar. * * @param cur Current menu drop-down * @return Next menu drop-down or @c NULL if @a cur is the last one */ ui_menu_dd_t *ui_menu_dd_next(ui_menu_dd_t *cur) { link_t *link; link = list_next(&cur->lmenudds, &cur->mbar->menudds); if (link == NULL) return NULL; return list_get_instance(link, ui_menu_dd_t, lmenudds); } /** Get last menu drop-down in menu bar. * * @param mbar Menu bar * @return Last menu drop-down or @c NULL if there is none */ ui_menu_dd_t *ui_menu_dd_last(ui_menu_bar_t *mbar) { link_t *link; link = list_last(&mbar->menudds); if (link == NULL) return NULL; return list_get_instance(link, ui_menu_dd_t, lmenudds); } /** Get previous menu drop-down in menu bar. * * @param cur Current menu drop-down * @return Previous menu drop-down or @c NULL if @a cur is the fist one */ ui_menu_dd_t *ui_menu_dd_prev(ui_menu_dd_t *cur) { link_t *link; link = list_prev(&cur->lmenudds, &cur->mbar->menudds); if (link == NULL) return NULL; return list_get_instance(link, ui_menu_dd_t, lmenudds); } /** Get menu drop-down caption. * * @param mdd Menu drop-down * @return Caption (owned by @a menu) */ const char *ui_menu_dd_caption(ui_menu_dd_t *mdd) { return mdd->caption; } /** Get menu drop-down accelerator character. * * @param mdd Menu drop-down * @return Accelerator character (lowercase) or the null character if * the menu has no accelerator. */ char32_t ui_menu_dd_get_accel(ui_menu_dd_t *mdd) { return ui_accel_get(mdd->caption); } /** Open menu drop-down. * * @param mdd Menu drop-down * @param prect Parent rectangle around which the drop-down should be placed * @param idev_id Input device associated with the drop-down's seat */ errno_t ui_menu_dd_open(ui_menu_dd_t *mdd, gfx_rect_t *prect, sysarg_t idev_id) { return ui_menu_open(mdd->menu, prect, idev_id); } /** Close menu drop-down. * * @param mdd Menu drop-down */ void ui_menu_dd_close(ui_menu_dd_t *mdd) { ui_menu_close(mdd->menu); } /** Determine if menu drop-down is open. * * @param mdd Menu drop-down * @return @c true iff menu drop-down is open */ bool ui_menu_dd_is_open(ui_menu_dd_t *mdd) { return ui_menu_is_open(mdd->menu); } /** Handle menu left event. * * @param menu Menu * @param arg Argument (ui_menu_dd_t *) * @param idev_id Input device ID */ static void ui_menu_dd_left(ui_menu_t *menu, void *arg, sysarg_t idev_id) { ui_menu_dd_t *mdd = (ui_menu_dd_t *)arg; (void)menu; ui_menu_bar_left(mdd->mbar, idev_id); } /** Handle menu right event. * * @param menu Menu * @param arg Argument (ui_menu_dd_t *) * @param idev_id Input device ID */ static void ui_menu_dd_right(ui_menu_t *menu, void *arg, sysarg_t idev_id) { ui_menu_dd_t *mdd = (ui_menu_dd_t *)arg; (void)menu; ui_menu_bar_right(mdd->mbar, idev_id); } /** Handle menu close request. * * @param menu Menu * @param arg Argument (ui_menu_dd_t *) */ static void ui_menu_dd_close_req(ui_menu_t *menu, void *arg) { ui_menu_dd_t *mdd = (ui_menu_dd_t *)arg; (void)menu; ui_menu_bar_deactivate(mdd->mbar); } /** Handle menu accelerator key press event. * * @param menu Menu * @param arg Argument (ui_menu_dd_t *) * @param c Character * @param kbd_id Keyboard ID */ static void ui_menu_dd_press_accel(ui_menu_t *menu, void *arg, char32_t c, sysarg_t kbd_id) { ui_menu_dd_t *mdd = (ui_menu_dd_t *)arg; (void)menu; ui_menu_bar_press_accel(mdd->mbar, c, kbd_id); } /** @} */