#include #include #include #include #include #include #define RTGUI_NOTEBOOK_TAB_DEFAULT_WIDTH 80 #define RTGUI_NOTEBOOK_TAB_DEFAULT_HEIGHT 25 struct rtgui_notebook_tab { #ifdef RTGUI_USING_NOTEBOOK_IMAGE struct rtgui_image *pressed_image; struct rtgui_image *unpressed_image; #endif struct rtgui_widget *widget; char *title; }; static void _rtgui_notebook_get_bar_rect(struct rtgui_notebook *notebook, struct rtgui_rect *rect); static void _rtgui_notebook_get_page_rect(struct rtgui_notebook *notebook, struct rtgui_rect *rect); static void _rtgui_notebook_constructor(struct rtgui_notebook *notebook) { notebook->flag = 0; notebook->childs = RT_NULL; notebook->count = 0; notebook->current = 0; notebook->tab_h = RTGUI_NOTEBOOK_TAB_DEFAULT_HEIGHT; notebook->tab_w = RTGUI_NOTEBOOK_TAB_DEFAULT_WIDTH; RTGUI_WIDGET(notebook)->gc.textalign = RTGUI_ALIGN_CENTER_HORIZONTAL | RTGUI_ALIGN_CENTER_VERTICAL; rtgui_object_set_event_handler(RTGUI_OBJECT(notebook), rtgui_notebook_event_handler); } static void _rtgui_notebook_destructor(struct rtgui_notebook *notebook) { int index; if (notebook->childs != RT_NULL) { for (index = 0; index < notebook->count; index ++) { rtgui_widget_destroy(notebook->childs[index].widget); rt_free(notebook->childs[index].title); } rtgui_free(notebook->childs); } } DEFINE_CLASS_TYPE(notebook, "notebook", RTGUI_WIDGET_TYPE, _rtgui_notebook_constructor, _rtgui_notebook_destructor, sizeof(struct rtgui_notebook)); /* Draw tab bars of @param notebook. @param dc should be initialized and * finished outside this function. Don't pass @param notebook or @param dc as * RT_NULL, it should be checked outside. */ static void _rtgui_notebook_draw_bar(struct rtgui_notebook *notebook, struct rtgui_dc *dc) { int index; struct rtgui_rect rect; struct rtgui_rect text_rect; #ifdef RTGUI_USING_NOTEBOOK_IMAGE struct rtgui_image *image = RT_NULL; struct rtgui_rect image_rect; #endif RT_ASSERT((notebook != RT_NULL) && (dc != RT_NULL)); if (notebook->flag == RTGUI_NOTEBOOK_NOTAB) return; _rtgui_notebook_get_bar_rect(notebook, &rect); rtgui_dc_fill_rect(dc, &rect); if (notebook->flag == RTGUI_NOTEBOOK_TOP || notebook->flag == RTGUI_NOTEBOOK_BOTTOM) { rect.x2 = rect.x1 + notebook->tab_w; /* draw tab bar */ for (index = 0; index < notebook->count; index++) { if (notebook->current == index) { #ifdef RTGUI_USING_NOTEBOOK_IMAGE if (notebook->childs[index].pressed_image != RT_NULL) image = notebook->childs[index].pressed_image; else #endif rtgui_dc_draw_border(dc, &rect, RTGUI_BORDER_SUNKEN); } else { #ifdef RTGUI_USING_NOTEBOOK_IMAGE if (notebook->childs[index].unpressed_image != RT_NULL) image = notebook->childs[index].unpressed_image; else #endif rtgui_dc_draw_border(dc, &rect, RTGUI_BORDER_BOX); } rtgui_font_get_metrics(RTGUI_WIDGET_FONT(notebook), notebook->childs[index].title, &text_rect); rtgui_rect_moveto_align(&rect, &text_rect, RTGUI_ALIGN_CENTER); #ifdef RTGUI_USING_NOTEBOOK_IMAGE if (image != RT_NULL) { image_rect.x1 = 0; image_rect.y1 = RTGUI_WIDGET_DEFAULT_MARGIN; image_rect.x2 = image_rect.x1 + image->w; image_rect.y2 = image_rect.y1 + image->h; rtgui_rect_moveto_align(&rect, &image_rect, RTGUI_ALIGN_CENTER_HORIZONTAL); rtgui_image_blit(image, dc, &image_rect); } if (image != RT_NULL) { int text_height = text_rect.y2 - text_rect.y1; text_rect.y1 = image_rect.y2 + RTGUI_WIDGET_DEFAULT_MARGIN; text_rect.y2 = text_rect.y1 + text_height; } image = RT_NULL; #endif rtgui_dc_draw_text(dc, notebook->childs[index].title, &text_rect); /* move to next tab */ rect.x1 = rect.x2; rect.x2 = rect.x1 + notebook->tab_w; } } else { rect.y2 = rect.y1 + notebook->tab_h; /* draw tab bar */ for (index = 0; index < notebook->count; index++) { if (notebook->current == index) { #ifdef RTGUI_USING_NOTEBOOK_IMAGE if (notebook->childs[index].pressed_image != RT_NULL) image = notebook->childs[index].pressed_image; else #endif rtgui_dc_draw_border(dc, &rect, RTGUI_BORDER_SUNKEN); } else { #ifdef RTGUI_USING_NOTEBOOK_IMAGE if (notebook->childs[index].unpressed_image != RT_NULL) image = notebook->childs[index].unpressed_image; else #endif rtgui_dc_draw_border(dc, &rect, RTGUI_BORDER_BOX); } rtgui_font_get_metrics(RTGUI_WIDGET_FONT(notebook), notebook->childs[index].title, &text_rect); rtgui_rect_moveto_align(&rect, &text_rect, RTGUI_ALIGN_CENTER); #ifdef RTGUI_USING_NOTEBOOK_IMAGE if (image != RT_NULL) { image_rect.x1 = 0; image_rect.y1 = RTGUI_WIDGET_DEFAULT_MARGIN; image_rect.x2 = image->w; image_rect.y2 = image_rect.y1 + image->h; rtgui_rect_moveto_align(&rect, &image_rect, RTGUI_ALIGN_CENTER_HORIZONTAL); rtgui_image_blit(image, dc, &image_rect); } if (image != RT_NULL) { int text_height = text_rect.y2 - text_rect.y1; text_rect.y1 = image_rect.y2 + RTGUI_WIDGET_DEFAULT_MARGIN; text_rect.y2 = text_rect.y1 + text_height; } image = RT_NULL; #endif rtgui_dc_draw_text(dc, notebook->childs[index].title, &text_rect); /* move to next tab */ rect.y1 = rect.y2; rect.y2 = rect.y1 + notebook->tab_h; } } } static void _rtgui_notebook_ondraw(struct rtgui_notebook *notebook) { struct rtgui_dc *dc; dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(notebook)); if (dc == RT_NULL) return; if (notebook->count == 0) { rtgui_rect_t rect; rtgui_widget_get_rect(RTGUI_WIDGET(notebook), &rect); rtgui_dc_fill_rect(dc, &rect); } else { if (notebook->current == RTGUI_NOT_FOUND) notebook->current = 0; _rtgui_notebook_draw_bar(notebook, dc); /* draw current tab */ rtgui_widget_update(notebook->childs[notebook->current].widget); } rtgui_dc_end_drawing(dc); } static void _rtgui_notebook_onmouse(struct rtgui_notebook *notebook, struct rtgui_event_mouse *emouse) { rtgui_rect_t rect; /* handle notebook bar */ _rtgui_notebook_get_bar_rect(notebook, &rect); rtgui_widget_rect_to_device(RTGUI_WIDGET(notebook), &rect); if (rtgui_rect_contains_point(&rect, emouse->x, emouse->y) == RT_EOK) { int index; struct rtgui_dc *dc; if (notebook->flag == RTGUI_NOTEBOOK_BOTTOM || notebook->flag == RTGUI_NOTEBOOK_TOP) { index = (emouse->x - rect.x1) / notebook->tab_w; if (index < notebook->count && index != notebook->current) { /* update tab bar */ dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(notebook)); if (dc == RT_NULL) return; rtgui_notebook_set_current_by_index(notebook, index); _rtgui_notebook_draw_bar(notebook, dc); rtgui_dc_end_drawing(dc); } } else { index = (emouse->y - rect.y1) / notebook->tab_h; if (index < notebook->count && index != notebook->current) { /* update tab bar */ dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(notebook)); if (dc == RT_NULL) return; rtgui_notebook_set_current_by_index(notebook, index); _rtgui_notebook_draw_bar(notebook, dc); rtgui_dc_end_drawing(dc); } } } else { /* handle on page */ if (RTGUI_OBJECT(notebook->childs[notebook->current].widget)->event_handler != RT_NULL) RTGUI_OBJECT(notebook->childs[notebook->current].widget)->event_handler( RTGUI_OBJECT(notebook->childs[notebook->current].widget), &(emouse->parent)); } } static void _rtgui_notebook_get_page_rect(struct rtgui_notebook *notebook, struct rtgui_rect *rect) { struct rtgui_rect tab_rect; RT_ASSERT(notebook != RT_NULL); RT_ASSERT(rect != RT_NULL); _rtgui_notebook_get_bar_rect(notebook, &tab_rect); rtgui_widget_get_rect(RTGUI_WIDGET(notebook), rect); if (notebook->flag == RTGUI_NOTEBOOK_NOTAB) return; else if (notebook->flag == RTGUI_NOTEBOOK_TOP) { rect->y1 = tab_rect.y2; } else if (notebook->flag == RTGUI_NOTEBOOK_BOTTOM) { rect->y2 = tab_rect.y1; } else if (notebook->flag == RTGUI_NOTEBOOK_LEFT) { rect->x1 = tab_rect.x2; } else if (notebook->flag == RTGUI_NOTEBOOK_RIGHT) { rect->x2 = tab_rect.x1; } } static void _rtgui_notebook_get_bar_rect(struct rtgui_notebook *notebook, struct rtgui_rect *rect) { RT_ASSERT(notebook != RT_NULL); RT_ASSERT(rect != RT_NULL); rtgui_widget_get_rect(RTGUI_WIDGET(notebook), rect); if (notebook->flag == RTGUI_NOTEBOOK_NOTAB) { rect->x1 = rect->y1 = rect->x2 = rect->y2 = 0; } else if (notebook->flag == RTGUI_NOTEBOOK_TOP) { rect->y2 = rect->y1 + notebook->tab_h; } else if (notebook->flag == RTGUI_NOTEBOOK_BOTTOM) { rect->y1 = rect->y2 - notebook->tab_h; } else if (notebook->flag == RTGUI_NOTEBOOK_LEFT) { rect->x2 = rect->x1 + notebook->tab_w; } else if (notebook->flag == RTGUI_NOTEBOOK_RIGHT) { rect->x1 = rect->x2 - notebook->tab_w; } } struct rtgui_notebook *rtgui_notebook_create(const rtgui_rect_t *rect, rt_uint8_t style) { struct rtgui_notebook *notebook; notebook = (struct rtgui_notebook *) rtgui_widget_create(RTGUI_NOTEBOOK_TYPE); if (notebook != RT_NULL) { notebook->flag = style; rtgui_widget_set_rect(RTGUI_WIDGET(notebook), rect); } return notebook; } void rtgui_notebook_destroy(struct rtgui_notebook *notebook) { rtgui_widget_destroy(RTGUI_WIDGET(notebook)); } void rtgui_notebook_add(struct rtgui_notebook *notebook, const char *label, struct rtgui_widget *child) { rtgui_rect_t rect; RT_ASSERT(notebook != RT_NULL); notebook->count += 1; notebook->childs = (struct rtgui_notebook_tab *) rtgui_realloc(notebook->childs, sizeof(struct rtgui_notebook_tab) * notebook->count); notebook->childs[notebook->count - 1].title = rt_strdup(label); notebook->childs[notebook->count - 1].widget = child; #ifdef RTGUI_USING_NOTEBOOK_IMAGE notebook->childs[notebook->count - 1].pressed_image = RT_NULL; notebook->childs[notebook->count - 1].unpressed_image = RT_NULL; #endif /* set parent */ rtgui_widget_set_parent(child, RTGUI_WIDGET(notebook)); if (notebook->count - 1 != notebook->current) rtgui_widget_hide(child); _rtgui_notebook_get_page_rect(notebook, &rect); rtgui_widget_rect_to_device(RTGUI_WIDGET(notebook), &rect); rtgui_widget_set_rect(child, &rect); if (RTGUI_WIDGET(notebook)->toplevel != RT_NULL && RTGUI_IS_WIN(RTGUI_WIDGET(notebook)->toplevel)) { struct rtgui_event_update_toplvl eup; RTGUI_EVENT_UPDATE_TOPLVL_INIT(&eup); eup.toplvl = RTGUI_WIDGET(notebook)->toplevel; if (RTGUI_OBJECT(child)->event_handler) RTGUI_OBJECT(child)->event_handler(RTGUI_OBJECT(child), (struct rtgui_event *)&eup); } } #ifdef RTGUI_USING_NOTEBOOK_IMAGE void rtgui_notebook_add_image(struct rtgui_notebook *notebook, const char *label, struct rtgui_widget *child, struct rtgui_image *pressed_image, struct rtgui_image *unpressed_image) { rtgui_rect_t rect; RT_ASSERT(notebook != RT_NULL); notebook->count += 1; notebook->childs = (struct rtgui_notebook_tab *) rtgui_realloc(notebook->childs, sizeof(struct rtgui_notebook_tab) * notebook->count); notebook->childs[notebook->count - 1].title = rt_strdup(label); notebook->childs[notebook->count - 1].widget = child; notebook->childs[notebook->count - 1].pressed_image = pressed_image; notebook->childs[notebook->count - 1].unpressed_image = unpressed_image; /* set parent */ rtgui_widget_set_parent(child, RTGUI_WIDGET(notebook)); _rtgui_notebook_get_page_rect(notebook, &rect); rtgui_widget_rect_to_device(RTGUI_WIDGET(notebook), &rect); rtgui_widget_set_rect(child, &rect); if (notebook->count - 1 != notebook->current) rtgui_widget_hide(child); if (RTGUI_WIDGET(notebook)->toplevel != RT_NULL && RTGUI_IS_WIN(RTGUI_WIDGET(notebook)->toplevel)) { struct rtgui_event_update_toplvl eup; RTGUI_EVENT_UPDATE_TOPLVL_INIT(&eup); eup.toplvl = RTGUI_WIDGET(notebook)->toplevel; if (RTGUI_OBJECT(child)->event_handler) RTGUI_OBJECT(child)->event_handler(RTGUI_OBJECT(child), (struct rtgui_event *)&eup); } return; } #endif void rtgui_notebook_remove(struct rtgui_notebook *notebook, rt_uint16_t index) { struct rtgui_notebook_tab tab; rt_bool_t need_update = RT_FALSE; RT_ASSERT(notebook != RT_NULL); if (index < notebook->count) { if (notebook->count == 1) { tab = notebook->childs[0]; rtgui_free(notebook->childs); notebook->childs = RT_NULL; notebook->count = 0; } else { if (notebook->current == index) need_update = RT_TRUE; tab = notebook->childs[index]; for (; index < notebook->count - 1; index++) { notebook->childs[index] = notebook->childs[index + 1]; } notebook->count -= 1; notebook->childs = (struct rtgui_notebook_tab *) rtgui_realloc(notebook->childs, sizeof(struct rtgui_notebook_tab) * notebook->count); } rt_free(tab.title); if (need_update) { if (notebook->current > notebook->count - 1) notebook->current = notebook->count - 1; rtgui_widget_hide(tab.widget); rtgui_widget_show(notebook->childs[notebook->current].widget); rtgui_widget_update(RTGUI_WIDGET(notebook)); rtgui_widget_set_parent(tab.widget, RT_NULL); } } } int rtgui_notebook_get_count(struct rtgui_notebook *notebook) { RT_ASSERT(notebook != RT_NULL); return notebook->count; } void rtgui_notebook_get_client_rect(struct rtgui_notebook *notebook, struct rtgui_rect *rect) { _rtgui_notebook_get_page_rect(notebook, rect); rtgui_rect_moveto(rect, 0, 0); } struct rtgui_widget *rtgui_notebook_get_current(struct rtgui_notebook *notebook) { RT_ASSERT(notebook != RT_NULL); if (notebook->current != RTGUI_NOT_FOUND) return notebook->childs[notebook->current].widget; return RT_NULL; } rt_int16_t rtgui_notebook_get_current_index(struct rtgui_notebook *notebook) { RT_ASSERT(notebook != RT_NULL); return notebook->current; } void rtgui_notebook_set_current(struct rtgui_notebook *notebook, struct rtgui_widget *widget) { rt_int16_t index; RT_ASSERT(notebook != RT_NULL); for (index = 0; index < notebook->count; index ++) { if (widget == notebook->childs[index].widget) { rtgui_notebook_set_current_by_index(notebook, index); return; } } } void rtgui_notebook_set_current_by_index(struct rtgui_notebook *notebook, rt_uint16_t index) { RT_ASSERT(notebook != RT_NULL); if ((index < notebook->count) && (notebook->current != index)) { struct rtgui_widget *widget; if (notebook->current != RTGUI_NOT_FOUND) rtgui_widget_hide(notebook->childs[notebook->current].widget); notebook->current = index; widget = notebook->childs[notebook->current].widget; rtgui_widget_show(widget); rtgui_widget_update_clip(widget); /* the whole notebook need an update */ rtgui_widget_update(RTGUI_WIDGET(notebook)); rtgui_widget_focus(widget); } } struct rtgui_widget *rtgui_notebook_get_widget_at(struct rtgui_notebook *notebook, rt_uint16_t index) { RT_ASSERT(notebook != RT_NULL); if (index < notebook->count) return notebook->childs[index].widget; return RT_NULL; } static rt_bool_t _rtgui_notebook_current_widget_handle(struct rtgui_notebook *notebook, struct rtgui_event *event) { struct rtgui_widget *widget = rtgui_notebook_get_current(notebook); if (widget && widget != RTGUI_WIDGET(notebook)) return RTGUI_OBJECT(widget)->event_handler(RTGUI_OBJECT(widget), event); else return RT_FALSE; } static void _rtgui_notebook_all_widget_handle(struct rtgui_notebook *notebook, struct rtgui_event *event) { struct rtgui_object *object; int i; for (i = 0; i < notebook->count; i++) { object = RTGUI_OBJECT(notebook->childs[i].widget); if (object->event_handler) object->event_handler(object, event); } } rt_bool_t rtgui_notebook_event_handler(struct rtgui_object *object, struct rtgui_event *event) { int page_index; rtgui_rect_t rect; struct rtgui_notebook *notebook; RT_ASSERT(object != RT_NULL); RT_ASSERT(event != RT_NULL); notebook = RTGUI_NOTEBOOK(object); switch (event->type) { case RTGUI_EVENT_PAINT: _rtgui_notebook_ondraw(notebook); break; case RTGUI_EVENT_MOUSE_BUTTON: _rtgui_notebook_onmouse(notebook, (struct rtgui_event_mouse *)event); break; case RTGUI_EVENT_SHOW: /* show myself */ rtgui_widget_onshow(object, event); /* show the tab widget */ return _rtgui_notebook_current_widget_handle(notebook, event); case RTGUI_EVENT_HIDE: /* hide myself */ rtgui_widget_onhide(object, event); /* hide the tab widget */ return _rtgui_notebook_current_widget_handle(notebook, event); case RTGUI_EVENT_KBD: return _rtgui_notebook_current_widget_handle(notebook, event); case RTGUI_EVENT_UPDATE_TOPLVL: /* update myself */ rtgui_widget_onupdate_toplvl(object, event); /* update all the widgets in myself */ _rtgui_notebook_all_widget_handle(notebook, event); return RT_FALSE; case RTGUI_EVENT_RESIZE: /* re-size page widget */ _rtgui_notebook_get_page_rect(notebook, &rect); rtgui_widget_rect_to_device(RTGUI_WIDGET(notebook), &rect); for (page_index = 0; page_index < notebook->count; page_index ++) { rtgui_widget_set_rect(notebook->childs[page_index].widget, &rect); } break; default: /* use parent event handler */ return rtgui_widget_event_handler(object, event); } return RT_FALSE; }