diff --git a/components/rtgui/include/rtgui/widgets/combobox.h b/components/rtgui/include/rtgui/widgets/combobox.h index e524358834..517b125d06 100644 --- a/components/rtgui/include/rtgui/widgets/combobox.h +++ b/components/rtgui/include/rtgui/widgets/combobox.h @@ -32,6 +32,8 @@ struct rtgui_combobox /* pull down window */ struct rtgui_win* pd_win; rt_bool_t pd_pressed; + rt_uint16_t pd_win_width; + rt_uint16_t pd_win_height; /* combobox items */ struct rtgui_combobox_item* items; @@ -48,6 +50,6 @@ rtgui_combobox_t *rtgui_combobox_create(); void rtgui_combobox_destroy(rtgui_combobox_t* box); rt_bool_t rtgui_combobox_event_handler(struct rtgui_widget* widget, struct rtgui_event* event); -struct rtgui_item* rtgui_combox_get_select(struct rtgui_combobox* box); +struct rtgui_combobox_item* rtgui_combox_get_select(struct rtgui_combobox* box); #endif diff --git a/components/rtgui/include/rtgui/widgets/menu.h b/components/rtgui/include/rtgui/widgets/menu.h new file mode 100644 index 0000000000..1d98f32e51 --- /dev/null +++ b/components/rtgui/include/rtgui/widgets/menu.h @@ -0,0 +1,79 @@ +#ifndef __RTGUI_MENU_H__ +#define __RTGUI_MENU_H__ + +#include +#include +#include + +/* rtgui menu item */ +enum rtgui_menu_item_type +{ + RTGUI_ITEM_NORMAL, + RTGUI_ITEM_CHECK, + RTGUI_ITEM_SUBMENU, + RTGUI_ITEM_SEPARATOR +}; +typedef enum rtgui_menu_item_type rtgui_menu_item_type_t; + +struct rtgui_menu_item +{ + rtgui_menu_item_type_t type; + + /* menu text label */ + const char* label; + /* menu image */ + rtgui_image_t *image; + /* parent menu */ + struct rtgui_menu *parent_menu, *sub_menu; + + /* menu action */ + rt_bool_t (*on_menuaction)(rtgui_widget_t* widget, rtgui_event_t* event); +}; +typedef struct rtgui_menu_item rtgui_menu_item_t; + +/** Gets the type of a menu */ +#define RTGUI_MENU_TYPE (rtgui_menu_type_get()) +/** Casts the object to an rtgui_menu */ +#define RTGUI_MENU(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_MENU_TYPE, rtgui_menu_t)) +/** Checks if the object is an rtgui_menu */ +#define RTGUI_IS_MENU(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_MENU_TYPE)) + +#define RTGUI_MENU_DEFAULT_WIDTH 100 + +struct rtgui_menu_item; + +struct rtgui_menu +{ + /* inherited from window */ + struct rtgui_win parent; + + /* menu items */ + const struct rtgui_menu_item *items; + rt_uint16_t items_count; + rt_uint16_t current_item; + + /* parent item */ + struct rtgui_menu_item *parent_item; + + /* pop event handle */ + rt_bool_t (*on_menupop)(rtgui_widget_t* widget, rtgui_event_t* event); + rt_bool_t (*on_menuhide)(rtgui_widget_t* widget, rtgui_event_t* event); +}; +typedef struct rtgui_menu rtgui_menu_t; + +rtgui_type_t *rtgui_menu_type_get(void); + +struct rtgui_menu* rtgui_menu_create(const char* title); +void rtgui_menu_destroy(struct rtgui_menu* menu); + +void rtgui_menu_set_onmenupop(struct rtgui_menu* menu, rtgui_event_handler_ptr handler); +void rtgui_menu_set_onmenuhide(struct rtgui_menu* menu, rtgui_event_handler_ptr handler); + +void rtgui_menu_pop(struct rtgui_menu* menu, int x, int y); +rtgui_menu_item_t* rtgui_menu_item_new(struct rtgui_menu* menu, char* text, int type, + rt_bool_t (*on_menu)(rtgui_widget_t* widget, rtgui_event_t* event)); +rtgui_menu_item_t* rtgui_menu_item_new_separator(struct rtgui_menu* menu); +void rtgui_menu_item_add(struct rtgui_menu* menu, struct rtgui_menu_item* item); +struct rtgui_menu_item* rtgui_menu_get_first_item(struct rtgui_menu* menu); + +#endif diff --git a/components/rtgui/widgets/combobox.c b/components/rtgui/widgets/combobox.c index 7d17429bb8..fabc9404c5 100644 --- a/components/rtgui/widgets/combobox.c +++ b/components/rtgui/widgets/combobox.c @@ -2,6 +2,8 @@ #include static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_widget* widget, struct rtgui_event* event); +const static rt_uint8_t down_arrow[] = {0xff, 0x7e, 0x3c, 0x18}; +const static rt_uint8_t right_arrow[] = {0x80, 0xc0, 0xe0, 0xf0, 0xe0, 0xc0, 0x80}; static void _rtgui_combobox_constructor(rtgui_combobox_t *box) { @@ -88,7 +90,7 @@ static void rtgui_combobox_ondraw(struct rtgui_combobox* box) rtgui_rect_inflate(&rect, -1); if (box->pd_pressed == RT_TRUE) rtgui_dc_draw_border(dc, &rect, RTGUI_BORDER_SUNKEN); else rtgui_dc_draw_border(dc, &rect, RTGUI_BORDER_RAISE); - rtgui_dc_draw_arraw(dc, &rect, RTGUI_ARRAW_DOWN); + rtgui_dc_draw_byte(dc, rect.x1, rect.y1, rect.y2, down_arrow); /* end drawing */ rtgui_dc_end_drawing(dc); @@ -123,7 +125,6 @@ static rt_bool_t rtgui_combobox_onmouse_button(struct rtgui_combobox* box, struc if (box->pd_win != RT_NULL) { struct rtgui_rect r; - rtgui_box_t* pd_win_box; r.x1 = RTGUI_WIDGET(box)->extent.x1; r.y1 = RTGUI_WIDGET(box)->extent.y2 + 2; @@ -131,12 +132,6 @@ static rt_bool_t rtgui_combobox_onmouse_button(struct rtgui_combobox* box, struc r.y2 = r.y1 + box->pd_win_height; rtgui_win_set_rect(RTGUI_WIN(box->pd_win), &r); - pd_win_box = (rtgui_box_t*) rtgui_container_get_first_child(RTGUI_CONTAINER(box->pd_win)); - if (pd_win_box != RT_NULL) - { - RTGUI_WIDGET(pd_win_box)->extent = RTGUI_WIDGET(box->pd_win)->extent; - rtgui_box_layout(pd_win_box); - } /* show combo box pull down window */ rtgui_win_show(RTGUI_WIN(box->pd_win), RT_FALSE); @@ -178,18 +173,6 @@ rt_bool_t rtgui_combobox_event_handler(struct rtgui_widget* widget, struct rtgui item = (struct rtgui_item*) (focused->widget); if (item != RT_NULL) { - if (box->pd_select != RT_NULL) - { - /* un-select old item */ - rtgui_item_selected(box->pd_select, RT_FALSE); - } - - box->pd_select = item; - if (box->on_selected != RT_NULL) - { - box->on_selected(RTGUI_WIDGET(box), RT_NULL); - } - /* hide pull down window */ rtgui_win_hiden(RTGUI_WIN(box->pd_win)); rtgui_combobox_ondraw(box); @@ -210,12 +193,6 @@ static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_widget* widget, struc box = (struct rtgui_combobox*) (((struct rtgui_win*)widget)->user_data); if (box == RT_NULL) return RT_TRUE; - /* clear select item */ - if (box->pd_select != RT_NULL) - { - rtgui_item_selected(box->pd_select, RT_FALSE); - } - /* hide pull down window */ rtgui_win_hiden(RTGUI_WIN(box->pd_win)); @@ -226,7 +203,7 @@ static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_widget* widget, struc return RT_TRUE; } -struct rtgui_item* rtgui_combox_get_select(struct rtgui_combobox* box) +struct rtgui_combobox_item* rtgui_combox_get_select(struct rtgui_combobox* box) { if ((box != RT_NULL) && (box->current_item < box->items_count)) { diff --git a/components/rtgui/widgets/menu.c b/components/rtgui/widgets/menu.c new file mode 100644 index 0000000000..fcf52253d0 --- /dev/null +++ b/components/rtgui/widgets/menu.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include + +#define RTGUI_MENU_IMAGE_MAGIN 18 +#define RTGUI_MENU_SUBMENU_MAGIN 16 + +static void rtgui_menu_item_unselect(struct rtgui_menu_item* item); +static rt_bool_t rtgui_menu_on_deactivate(rtgui_widget_t* widget, rtgui_event_t* event); + +static void _rtgui_menu_constructor(rtgui_menu_t *menu) +{ + rtgui_box_t* box; + rtgui_rect_t rect = {0, 0, RTGUI_MENU_DEFAULT_WIDTH, RTGUI_BORDER_DEFAULT_WIDTH << 1}; + + /* set default rect */ + menu->width = RTGUI_MENU_DEFAULT_WIDTH; + menu->height = (RTGUI_BORDER_DEFAULT_WIDTH << 1); + rtgui_widget_set_rect(RTGUI_WIDGET(menu), &rect); + /* set window style */ + RTGUI_WIN(menu)->style = RTGUI_WIN_STYLE_NO_TITLE; + + /* set deactivate handler */ + rtgui_win_set_ondeactivate(RTGUI_WIN(menu), rtgui_menu_on_deactivate); + + /* set proper of control */ + menu->parent_item = RT_NULL; + menu->select_item = RT_NULL; + menu->on_menupop = RT_NULL; + menu->on_menuhide = RT_NULL; + + /* create box */ + box = rtgui_box_create(RTGUI_VERTICAL, &rect); + rtgui_container_add_child(RTGUI_CONTAINER(menu), RTGUI_WIDGET(box)); +} + +rtgui_type_t *rtgui_menu_type_get(void) +{ + static rtgui_type_t *menu_type = RT_NULL; + + if (!menu_type) + { + menu_type = rtgui_type_create("menu", RTGUI_WIN_TYPE, + sizeof(rtgui_menu_t), RTGUI_CONSTRUCTOR(_rtgui_menu_constructor), RT_NULL); + } + + return menu_type; +} + +static rt_bool_t rtgui_menu_on_deactivate(rtgui_widget_t* widget, rtgui_event_t* event) +{ + rtgui_menu_t* menu = (rtgui_menu_t*) widget; + + if (menu->select_item != RT_NULL) + { + /* try to wake through to find sub menu activated */ + if (menu->select_item->type == RTGUI_ITEM_SUBMENU) + { + /* if sub menu activated, not hide menu */ + if (menu->select_item->sub_menu != RT_NULL && + rtgui_win_is_activated(RTGUI_WIN(menu->select_item->sub_menu))) + { + return RT_TRUE; + } + } + } + + rtgui_win_hiden(RTGUI_WIN(menu)); + if (menu->on_menuhide != RT_NULL) + { + menu->on_menuhide(RTGUI_WIDGET(menu), RT_NULL); + } + + /* if it's a submenu, try to hide parent menu */ + if (menu->parent_item != RT_NULL && + !rtgui_win_is_activated(RTGUI_WIN(menu->parent_item->parent_menu))) + { + rtgui_menu_on_deactivate(RTGUI_WIDGET(menu->parent_item->parent_menu), event); + } + + /* unselected all items */ + if (menu->select_item != RT_NULL) + { + // rtgui_menu_item_unselect(menu->select_item); + } + + return RT_TRUE; +} + +struct rtgui_menu* rtgui_menu_create(const char* title) +{ + struct rtgui_menu* menu; + + menu = (struct rtgui_menu*) rtgui_widget_create ( RTGUI_MENU_TYPE ); + if (menu != RT_NULL) + { + rtgui_win_set_title(RTGUI_WIN(menu), title); + } + + return menu; +} + +void rtgui_menu_destroy(struct rtgui_menu* menu) +{ + rtgui_widget_destroy (RTGUI_WIDGET(menu)); +} + +void rtgui_menu_set_onmenupop(struct rtgui_menu* menu, rtgui_event_handler_ptr handler) +{ + if (menu == RT_NULL) return; + + menu->on_menupop = handler; +} + +void rtgui_menu_set_onmenuhide(struct rtgui_menu* menu, rtgui_event_handler_ptr handler) +{ + if (menu == RT_NULL) return; + + menu->on_menuhide = handler; +} + +void rtgui_menu_pop(struct rtgui_menu* menu, int x, int y) +{ + rtgui_rect_t rect; + rtgui_box_t* box; + + if (menu == RT_NULL) return; + + /* set window extent */ + rect.x1 = x; + rect.y1 = y; + rect.x2 = x + menu->width; + rect.y2 = y + menu->height; + rtgui_win_set_rect(RTGUI_WIN(menu), &rect); + + /* layout box */ + box = (rtgui_box_t*) rtgui_container_get_first_child(RTGUI_CONTAINER(menu)); + RTGUI_WIDGET(box)->extent = rect; + rtgui_box_layout(box); + + /* on menu pop handler */ + if (menu->on_menupop != RT_NULL) + { + menu->on_menupop(RTGUI_WIDGET(menu), RT_NULL); + } + + /* show menu window */ + rtgui_win_show(RTGUI_WIN(menu), RT_FALSE); +} + +rtgui_menu_item_t* rtgui_menu_item_new(struct rtgui_menu* menu, char* text, int type, + rt_bool_t (*on_menu)(rtgui_widget_t* widget, rtgui_event_t* event)) +{ + rtgui_menu_item_t* item; + + if (menu == RT_NULL) return RT_NULL; + item = rtgui_menu_item_create(text); + if (item == RT_NULL) return RT_NULL; + + item->type = type; + item->image = RT_NULL; + item->on_menuaction = on_menu; + + rtgui_menu_item_add(menu, item); + + return item; +} + +rtgui_menu_item_t* rtgui_menu_item_new_separator(struct rtgui_menu* menu) +{ + rtgui_menu_item_t* item; + + if (menu == RT_NULL) return RT_NULL; + + item = rtgui_menu_item_create("--"); + if (item == RT_NULL) return RT_NULL; + + item->type = RTGUI_ITEM_SEPARATOR; + item->image = RT_NULL; + item->on_menuaction = RT_NULL; + + /* resize item extent */ + rtgui_widget_set_miniheight(RTGUI_WIDGET(item), 2); + RTGUI_WIDGET(item)->extent.y2 = RTGUI_WIDGET(item)->extent.y1 + 2; + + rtgui_menu_item_add(menu, item); + + return item; +} + +void rtgui_menu_item_add(struct rtgui_menu* menu, struct rtgui_menu_item* item) +{ + rtgui_box_t* box; + + if (menu == RT_NULL || item == RT_NULL) return; + + box = (rtgui_box_t*) rtgui_container_get_first_child(RTGUI_CONTAINER(menu)); + + menu->height += rtgui_rect_height(RTGUI_WIDGET(item)->extent); + if (menu->width < rtgui_rect_width(RTGUI_WIDGET(item)->extent) + RTGUI_MENU_IMAGE_MAGIN + RTGUI_MENU_SUBMENU_MAGIN) + { + menu->width = rtgui_rect_width(RTGUI_WIDGET(item)->extent) + RTGUI_MENU_IMAGE_MAGIN + RTGUI_MENU_SUBMENU_MAGIN; + } + + item->parent_menu = menu; + if (item->type == RTGUI_ITEM_SUBMENU) + { + item->sub_menu->parent_item = item; + } + + rtgui_box_append(box, RTGUI_WIDGET(item)); +} + +struct rtgui_menu_item* rtgui_menu_get_first_item(struct rtgui_menu* menu) +{ + rtgui_box_t* box; + rtgui_menu_item_t* item; + + if (menu == RT_NULL) return RT_NULL; + + box = (rtgui_box_t*) rtgui_container_get_first_child(RTGUI_CONTAINER(menu)); + if (box == RT_NULL) return RT_NULL; + + item = (rtgui_menu_item_t*) rtgui_container_get_first_child(RTGUI_CONTAINER(box)); + + return item; +}