HelenOS sources
This source file includes following definitions.
- ui_menu_create
- ui_menu_destroy
- ui_menu_set_cb
- ui_menu_get_geom
- ui_menu_get_res
- ui_menu_open
- ui_menu_close
- ui_menu_is_open
- ui_menu_paint_bg_gfx
- ui_menu_paint_bg_text
- ui_menu_paint
- ui_menu_pos_event
- ui_menu_kbd_event
- ui_menu_up
- ui_menu_down
- ui_menu_key_press_unmod
- ui_menu_popup_close
- ui_menu_popup_kbd
- ui_menu_popup_pos
- ui_menu_left
- ui_menu_right
- ui_menu_close_req
- ui_menu_press_accel
- ui_menu_get_idev_id
#include <adt/list.h>
#include <ctype.h>
#include <errno.h>
#include <gfx/color.h>
#include <gfx/context.h>
#include <gfx/render.h>
#include <gfx/text.h>
#include <io/pos_event.h>
#include <stdlib.h>
#include <str.h>
#include <uchar.h>
#include <ui/ui.h>
#include <ui/accel.h>
#include <ui/control.h>
#include <ui/paint.h>
#include <ui/popup.h>
#include <ui/menu.h>
#include <ui/menuentry.h>
#include <ui/resource.h>
#include <ui/window.h>
#include "../private/menu.h"
#include "../private/resource.h"
enum {
menu_frame_w = 4,
menu_frame_h = 4,
menu_frame_w_text = 2,
menu_frame_h_text = 1,
menu_frame_h_margin_text = 1
};
static void ui_menu_popup_close(ui_popup_t *, void *);
static void ui_menu_popup_kbd(ui_popup_t *, void *, kbd_event_t *);
static void ui_menu_popup_pos(ui_popup_t *, void *, pos_event_t *);
static void ui_menu_key_press_unmod(ui_menu_t *, kbd_event_t *);
static ui_popup_cb_t ui_menu_popup_cb = {
.close = ui_menu_popup_close,
.kbd = ui_menu_popup_kbd,
.pos = ui_menu_popup_pos
};
errno_t ui_menu_create(ui_window_t *parent, ui_menu_t **rmenu)
{
ui_menu_t *menu;
menu = calloc(1, sizeof(ui_menu_t));
if (menu == NULL)
return ENOMEM;
menu->parent = parent;
list_initialize(&menu->entries);
*rmenu = menu;
return EOK;
}
void ui_menu_destroy(ui_menu_t *menu)
{
ui_menu_entry_t *mentry;
if (menu == NULL)
return;
mentry = ui_menu_entry_first(menu);
while (mentry != NULL) {
ui_menu_entry_destroy(mentry);
mentry = ui_menu_entry_first(menu);
}
free(menu->caption);
free(menu);
}
void ui_menu_set_cb(ui_menu_t *menu, ui_menu_cb_t *cb, void *arg)
{
menu->cb = cb;
menu->arg = arg;
}
void ui_menu_get_geom(ui_menu_t *menu, gfx_coord2_t *spos,
ui_menu_geom_t *geom)
{
gfx_coord2_t edim;
gfx_coord_t frame_w;
gfx_coord_t frame_h;
ui_resource_t *res;
res = ui_window_get_res(menu->parent);
if (res->textmode) {
frame_w = menu_frame_w_text;
frame_h = menu_frame_h_text;
} else {
frame_w = menu_frame_w;
frame_h = menu_frame_h;
}
edim.x = ui_menu_entry_calc_width(menu, menu->max_caption_w,
menu->max_shortcut_w);
edim.y = menu->total_h;
geom->outer_rect.p0 = *spos;
geom->outer_rect.p1.x = spos->x + edim.x + 2 * frame_w;
geom->outer_rect.p1.y = spos->y + edim.y + 2 * frame_h;
geom->entries_rect.p0.x = spos->x + frame_w;
geom->entries_rect.p0.y = spos->y + frame_h;
geom->entries_rect.p1.x = geom->entries_rect.p0.x + edim.x;
geom->entries_rect.p1.y = geom->entries_rect.p0.x + edim.y;
}
ui_resource_t *ui_menu_get_res(ui_menu_t *menu)
{
return ui_popup_get_res(menu->popup);
}
errno_t ui_menu_open(ui_menu_t *menu, gfx_rect_t *prect, sysarg_t idev_id)
{
ui_popup_t *popup = NULL;
ui_popup_params_t params;
ui_menu_geom_t geom;
gfx_coord2_t mpos;
errno_t rc;
menu->selected = ui_menu_entry_first(menu);
mpos.x = 0;
mpos.y = 0;
ui_menu_get_geom(menu, &mpos, &geom);
ui_popup_params_init(¶ms);
params.rect = geom.outer_rect;
params.place = *prect;
params.idev_id = idev_id;
rc = ui_popup_create(ui_window_get_ui(menu->parent), menu->parent,
¶ms, &popup);
if (rc != EOK)
return rc;
menu->popup = popup;
ui_popup_set_cb(popup, &ui_menu_popup_cb, menu);
return ui_menu_paint(menu, &mpos);
}
void ui_menu_close(ui_menu_t *menu)
{
ui_popup_destroy(menu->popup);
menu->popup = NULL;
}
bool ui_menu_is_open(ui_menu_t *menu)
{
return menu->popup != NULL;
}
errno_t ui_menu_paint_bg_gfx(ui_menu_t *menu, gfx_coord2_t *spos)
{
ui_resource_t *res;
ui_menu_geom_t geom;
gfx_rect_t bg_rect;
errno_t rc;
res = ui_menu_get_res(menu);
ui_menu_get_geom(menu, spos, &geom);
rc = gfx_set_color(res->gc, res->wnd_face_color);
if (rc != EOK)
goto error;
rc = ui_paint_outset_frame(res, &geom.outer_rect, &bg_rect);
if (rc != EOK)
goto error;
rc = gfx_set_color(res->gc, res->wnd_face_color);
if (rc != EOK)
goto error;
rc = gfx_fill_rect(res->gc, &bg_rect);
if (rc != EOK)
goto error;
return EOK;
error:
return rc;
}
errno_t ui_menu_paint_bg_text(ui_menu_t *menu, gfx_coord2_t *spos)
{
ui_resource_t *res;
ui_menu_geom_t geom;
gfx_rect_t rect;
errno_t rc;
res = ui_menu_get_res(menu);
ui_menu_get_geom(menu, spos, &geom);
rc = gfx_set_color(res->gc, res->wnd_face_color);
if (rc != EOK)
goto error;
rc = gfx_fill_rect(res->gc, &geom.outer_rect);
if (rc != EOK)
goto error;
rect = geom.outer_rect;
rect.p0.x += menu_frame_h_margin_text;
rect.p1.x -= menu_frame_h_margin_text;
rc = ui_paint_text_box(res, &rect, ui_box_single, res->wnd_face_color);
if (rc != EOK)
goto error;
return EOK;
error:
return rc;
}
errno_t ui_menu_paint(ui_menu_t *menu, gfx_coord2_t *spos)
{
ui_resource_t *res;
gfx_coord2_t pos;
ui_menu_entry_t *mentry;
ui_menu_geom_t geom;
errno_t rc;
res = ui_menu_get_res(menu);
ui_menu_get_geom(menu, spos, &geom);
if (res->textmode)
rc = ui_menu_paint_bg_text(menu, spos);
else
rc = ui_menu_paint_bg_gfx(menu, spos);
if (rc != EOK)
goto error;
pos = geom.entries_rect.p0;
mentry = ui_menu_entry_first(menu);
while (mentry != NULL) {
rc = ui_menu_entry_paint(mentry, &pos);
if (rc != EOK)
goto error;
pos.y += ui_menu_entry_height(mentry);
mentry = ui_menu_entry_next(mentry);
}
rc = gfx_update(res->gc);
if (rc != EOK)
goto error;
return EOK;
error:
return rc;
}
ui_evclaim_t ui_menu_pos_event(ui_menu_t *menu, gfx_coord2_t *spos,
pos_event_t *event)
{
ui_menu_geom_t geom;
ui_menu_entry_t *mentry;
gfx_coord2_t pos;
gfx_coord2_t epos;
ui_evclaim_t claimed;
ui_menu_get_geom(menu, spos, &geom);
epos.x = event->hpos;
epos.y = event->vpos;
pos = geom.entries_rect.p0;
mentry = ui_menu_entry_first(menu);
while (mentry != NULL) {
claimed = ui_menu_entry_pos_event(mentry, &pos, event);
if (claimed == ui_claimed)
return ui_claimed;
pos.y += ui_menu_entry_height(mentry);
mentry = ui_menu_entry_next(mentry);
}
if (gfx_pix_inside_rect(&epos, &geom.outer_rect)) {
return ui_claimed;
} else {
if (event->type == POS_PRESS)
ui_menu_close_req(menu);
}
return ui_unclaimed;
}
ui_evclaim_t ui_menu_kbd_event(ui_menu_t *menu, kbd_event_t *event)
{
if (event->type == KEY_PRESS && (event->mods &
(KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
ui_menu_key_press_unmod(menu, event);
}
if (event->type == KEY_PRESS && (event->mods & KM_ALT) != 0 &&
(event->mods & (KM_CTRL | KM_SHIFT)) == 0 && event->c != '\0')
ui_menu_press_accel(menu, event->c, event->kbd_id);
return ui_claimed;
}
void ui_menu_up(ui_menu_t *menu)
{
gfx_coord2_t mpos;
ui_menu_entry_t *nentry;
if (menu->selected == NULL)
return;
nentry = ui_menu_entry_prev(menu->selected);
if (nentry == NULL)
nentry = ui_menu_entry_last(menu);
while (!ui_menu_entry_selectable(nentry)) {
nentry = ui_menu_entry_prev(nentry);
if (nentry == NULL)
nentry = ui_menu_entry_last(menu);
if (nentry == menu->selected)
return;
}
menu->selected = nentry;
mpos.x = 0;
mpos.y = 0;
(void) ui_menu_paint(menu, &mpos);
}
void ui_menu_down(ui_menu_t *menu)
{
gfx_coord2_t mpos;
ui_menu_entry_t *nentry;
if (menu->selected == NULL)
return;
nentry = ui_menu_entry_next(menu->selected);
if (nentry == NULL)
nentry = ui_menu_entry_first(menu);
while (!ui_menu_entry_selectable(nentry)) {
nentry = ui_menu_entry_next(nentry);
if (nentry == NULL)
nentry = ui_menu_entry_first(menu);
if (nentry == menu->selected)
return;
}
menu->selected = nentry;
mpos.x = 0;
mpos.y = 0;
(void) ui_menu_paint(menu, &mpos);
}
static void ui_menu_key_press_unmod(ui_menu_t *menu, kbd_event_t *event)
{
ui_menu_entry_t *mentry;
char32_t c;
switch (event->key) {
case KC_ESCAPE:
ui_menu_close_req(menu);
break;
case KC_LEFT:
ui_menu_left(menu, event->kbd_id);
break;
case KC_RIGHT:
ui_menu_right(menu, event->kbd_id);
break;
case KC_UP:
ui_menu_up(menu);
break;
case KC_DOWN:
ui_menu_down(menu);
break;
case KC_ENTER:
if (menu->selected != NULL &&
!ui_menu_entry_is_disabled(menu->selected))
ui_menu_entry_activate(menu->selected);
break;
default:
if (event->c != '\0') {
mentry = ui_menu_entry_first(menu);
while (mentry != NULL) {
c = ui_menu_entry_get_accel(mentry);
if (c == (char32_t)tolower(event->c) &&
!ui_menu_entry_is_disabled(mentry)) {
ui_menu_entry_activate(mentry);
break;
}
mentry = ui_menu_entry_next(mentry);
}
}
break;
}
}
static void ui_menu_popup_close(ui_popup_t *popup, void *arg)
{
ui_menu_t *menu = (ui_menu_t *)arg;
ui_menu_close_req(menu);
}
static void ui_menu_popup_kbd(ui_popup_t *popup, void *arg, kbd_event_t *event)
{
ui_menu_t *menu = (ui_menu_t *)arg;
menu->idev_id = ui_popup_get_idev_id(menu->popup);
ui_menu_kbd_event(menu, event);
}
static void ui_menu_popup_pos(ui_popup_t *popup, void *arg, pos_event_t *event)
{
ui_menu_t *menu = (ui_menu_t *)arg;
gfx_coord2_t spos;
menu->idev_id = ui_popup_get_idev_id(menu->popup);
spos.x = 0;
spos.y = 0;
ui_menu_pos_event(menu, &spos, event);
}
void ui_menu_left(ui_menu_t *menu, sysarg_t idev_id)
{
if (menu->cb != NULL && menu->cb->left != NULL)
menu->cb->left(menu, menu->arg, idev_id);
}
void ui_menu_right(ui_menu_t *menu, sysarg_t idev_id)
{
if (menu->cb != NULL && menu->cb->right != NULL)
menu->cb->right(menu, menu->arg, idev_id);
}
void ui_menu_close_req(ui_menu_t *menu)
{
if (menu->cb != NULL && menu->cb->close_req != NULL)
menu->cb->close_req(menu, menu->arg);
}
void ui_menu_press_accel(ui_menu_t *menu, char32_t c, sysarg_t kbd_id)
{
if (menu->cb != NULL && menu->cb->press_accel != NULL)
menu->cb->press_accel(menu, menu->arg, c, kbd_id);
}
sysarg_t ui_menu_get_idev_id(ui_menu_t *menu)
{
return menu->idev_id;
}
HelenOS homepage, sources at GitHub