#include #include #include static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_object *object, struct rtgui_event *event); const static rt_uint8_t down_arrow[] = {0xff, 0x7e, 0x3c, 0x18}; static void _rtgui_combobox_constructor(rtgui_combobox_t *box) { rtgui_rect_t rect = {0, 0, RTGUI_COMBOBOX_WIDTH, RTGUI_COMBOBOX_HEIGHT}; /* init widget and set event handler */ rtgui_object_set_event_handler(RTGUI_OBJECT(box), rtgui_combobox_event_handler); rtgui_widget_set_rect(RTGUI_WIDGET(box), &rect); RTGUI_WIDGET_TEXTALIGN(box) = RTGUI_ALIGN_CENTER_VERTICAL; box->pd_pressed = RT_FALSE; box->current_item = 0; box->on_selected = RT_NULL; box->pd_win = RT_NULL; } static void _rtgui_combobox_destructor(rtgui_combobox_t *box) { /* destroy pull down window */ rtgui_win_destroy(box->pd_win); /* reset box field */ box->pd_win = RT_NULL; } rt_bool_t rtgui_combobox_pdwin_onitem(struct rtgui_object *object, struct rtgui_event *event) { struct rtgui_widget *widget; rtgui_win_t *pd_win; rtgui_combobox_t *combo; rtgui_listbox_t *list; RT_ASSERT(object != RT_NULL); widget = RTGUI_WIDGET(object); list = RTGUI_LISTBOX(widget); pd_win = RTGUI_WIN(rtgui_widget_get_toplevel(widget)); combo = RTGUI_COMBOBOX(pd_win->user_data); combo->current_item = list->current_item; if (combo->on_selected != RT_NULL) combo->on_selected(RTGUI_OBJECT(combo), RT_NULL); rtgui_win_hide(pd_win); rtgui_widget_update(RTGUI_WIDGET(combo)); return RT_FALSE; } rt_bool_t rtgui_combobox_pdwin_ondeactive(struct rtgui_object *object, struct rtgui_event *event) { rtgui_win_hide(RTGUI_WIN(object)); return RT_TRUE; } DEFINE_CLASS_TYPE(combobox, "combobox", RTGUI_WIDGET_TYPE, _rtgui_combobox_constructor, _rtgui_combobox_destructor, sizeof(struct rtgui_combobox)); rtgui_combobox_t *rtgui_combobox_create(struct rtgui_listbox_item *items, rt_uint16_t count, struct rtgui_rect *rect) { rtgui_combobox_t *box; box = (rtgui_combobox_t *)rtgui_widget_create(RTGUI_COMBOBOX_TYPE); box->items_count = count; box->items = items; rtgui_widget_set_rect(RTGUI_WIDGET(box), rect); box->pd_win = RT_NULL; return box; } void rtgui_combobox_destroy(rtgui_combobox_t *box) { rtgui_widget_destroy(RTGUI_WIDGET(box)); } static void rtgui_combobox_ondraw(struct rtgui_combobox *box) { /* draw button */ rtgui_color_t bc; struct rtgui_dc *dc; struct rtgui_rect rect, r; /* begin drawing */ dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(box)); if (dc == RT_NULL) return; bc = RTGUI_WIDGET_BACKGROUND(box); /* get widget rect */ rtgui_widget_get_rect(RTGUI_WIDGET(box), &rect); RTGUI_WIDGET_BACKGROUND(box) = white; /* fill widget rect with background color */ rtgui_dc_fill_rect(dc, &rect); rtgui_dc_draw_rect(dc, &rect); /* draw current item */ if (box->current_item < box->items_count) { rect.x1 += 5; rtgui_dc_draw_text(dc, box->items[box->current_item].name, &rect); } /* restore background color */ RTGUI_WIDGET_BACKGROUND(box) = bc; /* draw pull down button */ rect.x1 = rect.x2 - RTGUI_COMBOBOX_BUTTON_WIDTH; rtgui_rect_inflate(&rect, -1); rtgui_dc_fill_rect(dc, &rect); 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); r.x1 = 0; r.y1 = 0; r.x2 = 8; r.y2 = 4; rtgui_rect_moveto_align(&rect, &r, RTGUI_ALIGN_CENTER_HORIZONTAL | RTGUI_ALIGN_CENTER_VERTICAL); rtgui_dc_draw_byte(dc, r.x1, r.y1, 4, down_arrow); /* end drawing */ rtgui_dc_end_drawing(dc); return; } static rt_bool_t rtgui_combobox_onmouse_button(struct rtgui_combobox *box, struct rtgui_event_mouse *event) { struct rtgui_rect rect; /* get widget rect */ rect = RTGUI_WIDGET(box)->extent; /* move to the pull down button */ rect.x1 = rect.x2 - RTGUI_COMBOBOX_BUTTON_WIDTH; if (rtgui_rect_contains_point(&rect, event->x, event->y) == RT_EOK) { /* handle mouse button on pull down button */ if (event->button & RTGUI_MOUSE_BUTTON_LEFT && event->button & RTGUI_MOUSE_BUTTON_DOWN) { box->pd_pressed = RT_TRUE; rtgui_widget_update(RTGUI_WIDGET(box)); } else if (event->button & RTGUI_MOUSE_BUTTON_LEFT && event->button & RTGUI_MOUSE_BUTTON_UP) { box->pd_pressed = RT_FALSE; rtgui_widget_update(RTGUI_WIDGET(box)); /* pop pull down window */ if (box->pd_win == RT_NULL) { rtgui_listbox_t *list; /* create pull down window */ rect = RTGUI_WIDGET(box)->extent; rect.y1 = rect.y2; /* give it 5 pixels margin, or the last item won't get shown */ rect.y2 = rect.y1 + box->items_count * (2 + rtgui_theme_get_selected_height()) + 5; box->pd_win = rtgui_win_create(RT_NULL, "combo", &rect, RTGUI_WIN_STYLE_NO_TITLE); rtgui_win_set_ondeactivate(RTGUI_WIN(box->pd_win), rtgui_combobox_pulldown_hide); /* set user data to parent combobox */ box->pd_win->user_data = (rt_uint32_t)box; /* create list box */ rtgui_rect_inflate(&rect, -1); list = rtgui_listbox_create(box->items, box->items_count, &rect); rtgui_container_add_child(RTGUI_CONTAINER(box->pd_win), RTGUI_WIDGET(list)); rtgui_widget_focus(RTGUI_WIDGET(list)); rtgui_listbox_set_onitem(list, rtgui_combobox_pdwin_onitem); rtgui_win_set_ondeactivate(box->pd_win, rtgui_combobox_pdwin_ondeactive); } /* show combo box pull down window */ rtgui_win_show(RTGUI_WIN(box->pd_win), RT_FALSE); } return RT_TRUE; } return RT_FALSE; } rt_bool_t rtgui_combobox_event_handler(struct rtgui_object *object, struct rtgui_event *event) { struct rtgui_combobox *box; RTGUI_WIDGET_EVENT_HANDLER_PREPARE box = RTGUI_COMBOBOX(object); switch (event->type) { case RTGUI_EVENT_PAINT: #ifndef RTGUI_USING_SMALL_SIZE if (widget->on_draw != RT_NULL) widget->on_draw(RTGUI_OBJECT(widget), event); else #endif rtgui_combobox_ondraw(box); break; case RTGUI_EVENT_MOUSE_BUTTON: return rtgui_combobox_onmouse_button(box, (struct rtgui_event_mouse *)event); case RTGUI_EVENT_FOCUSED: { /* item focused */ struct rtgui_event_focused *focused; focused = (struct rtgui_event_focused *) event; if (focused->widget != RT_NULL) { /* hide pull down window */ rtgui_win_hide(RTGUI_WIN(box->pd_win)); rtgui_combobox_ondraw(box); } } break; default: return rtgui_widget_event_handler(object, event); } return RT_FALSE; } static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_object *object, struct rtgui_event *event) { struct rtgui_widget *widget; struct rtgui_combobox *box; RT_ASSERT(object != RT_NULL); RT_ASSERT(event != RT_NULL); widget = RTGUI_WIDGET(object); box = RTGUI_COMBOBOX(object); if (widget == RT_NULL) return RT_TRUE; box = (struct rtgui_combobox *)(((struct rtgui_win *)widget)->user_data); if (box == RT_NULL) return RT_TRUE; /* hide pull down window */ rtgui_win_hide(RTGUI_WIN(box->pd_win)); /* clear pull down button state */ box->pd_pressed = RT_FALSE; rtgui_widget_update(RTGUI_WIDGET(box)); return RT_TRUE; } struct rtgui_listbox_item *rtgui_combox_get_select(struct rtgui_combobox *box) { if ((box != RT_NULL) && (box->current_item < box->items_count)) { return &(box->items[box->current_item]); } return RT_NULL; } void rtgui_combobox_set_onselected(struct rtgui_combobox *box, rtgui_event_handler_ptr func) { box->on_selected = func; }