diff --git a/examples/gui/demo_fnview.c b/examples/gui/demo_fnview.c index c0fd55ea84..d1a126874e 100644 --- a/examples/gui/demo_fnview.c +++ b/examples/gui/demo_fnview.c @@ -7,6 +7,9 @@ static rtgui_label_t* label; void open_btn_onbutton(rtgui_widget_t* widget, struct rtgui_event* event) { /* create a fn view */ + rtgui_view_t *view; + + view = rtgui_filelist_view_create(workbench, "/", "*.*"); } rtgui_view_t* demo_fn_view(rtgui_workbench_t* workbench) diff --git a/rtgui/include/rtgui/widgets/about_view.h b/rtgui/include/rtgui/widgets/about_view.h new file mode 100644 index 0000000000..52f6ca23a0 --- /dev/null +++ b/rtgui/include/rtgui/widgets/about_view.h @@ -0,0 +1,45 @@ +/* + * File : list_view.h + * This file is part of RTGUI in RT-Thread RTOS + * COPYRIGHT (C) 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-01-06 Bernard first version + */ + +#ifndef __RTGUI_ABOUT_VIEW_H__ +#define __RTGUI_ABOUT_VIEW_H__ + +#include +#include +#include +#include + +/** Gets the type of a about view */ +#define RTGUI_ABOUT_VIEW_TYPE (rtgui_about_view_type_get()) +/** Casts the object to a about view */ +#define RTGUI_ABOUT_VIEW(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_ABOUT_VIEW_TYPE, rtgui_about_view_t)) +/** Checks if the object is a about view */ +#define RTGUI_IS_ABOUT_VIEW(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_ABOUT_VIEW_TYPE)) + +struct rtgui_about_view +{ + struct rtgui_view parent; + + /* widget private data */ + rtgui_image_t* logo; + const char* description; +}; +typedef struct rtgui_about_view rtgui_about_view_t; + +rtgui_type_t *rtgui_about_view_type_get(void); + +rtgui_about_view_t* rtgui_about_view_create(rtgui_image_t *logo, const char* description); +rt_bool_t rtgui_about_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event); + +#endif diff --git a/rtgui/include/rtgui/widgets/filelist_view.h b/rtgui/include/rtgui/widgets/filelist_view.h new file mode 100644 index 0000000000..c34b1e2032 --- /dev/null +++ b/rtgui/include/rtgui/widgets/filelist_view.h @@ -0,0 +1,56 @@ +#ifndef __RTGUI_FILELIST_VIEW_H__ +#define __RTGUI_FILELIST_VIEW_H__ + +#include + +#define RTGUI_FITEM_FILE 0x0 +#define RTGUI_FITEM_DIR 0x1 +struct rtgui_file_item +{ + rt_uint8_t* name; + + rt_uint32_t type; + rt_uint32_t size; +}; + +/** Gets the type of a filelist view */ +#define RTGUI_FILELIST_VIEW_TYPE (rtgui_filelist_view_type_get()) +/** Casts the object to a filelist */ +#define RTGUI_FILELIST_VIEW(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_FILELIST_VIEW_TYPE, rtgui_filelist_view_t)) +/** Checks if the object is a filelist view */ +#define RTGUI_IS_FILELIST_VIEW(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_FILELIST_VIEW_TYPE)) + +struct rtgui_filelist_view +{ + struct rtgui_view parent; + + /* widget private data */ + + /* current directory */ + rt_uint8_t* current_directory; + rt_uint8_t* pattern; + + /* the number of item in a page */ + rt_uint16_t page_items; + rt_uint16_t items_count; + + /* the selected item */ + rt_uint16_t current_item; + + /* items array */ + struct rtgui_file_item *items; +}; +typedef struct rtgui_filelist_view rtgui_filelist_view_t; + +rtgui_type_t *rtgui_filelist_view_type_get(void); + +rtgui_filelist_view_t* rtgui_filelist_view_create(rtgui_workbench_t* workbench, + const char* directory, const char* pattern, const rtgui_rect_t* rect); +void rtgui_filelist_view_destroy(rtgui_filelist_view_t* view); + +void rtgui_filelist_view_clear(rtgui_filelist_view_t* view); + +rt_bool_t rtgui_filelist_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event); +void rtgui_filelist_view_set_directory(rtgui_filelist_view_t* view, const char* directory); + +#endif diff --git a/rtgui/include/rtgui/widgets/list_view.h b/rtgui/include/rtgui/widgets/list_view.h new file mode 100644 index 0000000000..69463eb98b --- /dev/null +++ b/rtgui/include/rtgui/widgets/list_view.h @@ -0,0 +1,66 @@ +/* + * File : list_view.h + * This file is part of RTGUI in RT-Thread RTOS + * COPYRIGHT (C) 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-01-06 Bernard first version + */ + +#ifndef __RTGUI_LIST_VIEW_H__ +#define __RTGUI_LIST_VIEW_H__ + +#include +#include +#include + +#include + +typedef void (*item_action)(void* parameter); +struct rtgui_list_item +{ + char* name; + rtgui_image_t *image; + + item_action action; + void *parameter; +}; + +/** Gets the type of a list view */ +#define RTGUI_LIST_VIEW_TYPE (rtgui_list_view_type_get()) +/** Casts the object to a filelist */ +#define RTGUI_LIST_VIEW(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_LIST_VIEW_TYPE, rtgui_list_view_t)) +/** Checks if the object is a filelist view */ +#define RTGUI_IS_LIST_VIEW(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_LIST_VIEW_TYPE)) + +struct rtgui_list_view +{ + struct rtgui_view parent; + + /* widget private data */ + /* list item */ + struct rtgui_list_item* items; + + /* total number of items */ + rt_uint16_t items_count; + /* the number of item in a page */ + rt_uint16_t page_items; + /* current item */ + rt_uint16_t current_item; +}; +typedef struct rtgui_list_view rtgui_list_view_t; + +rtgui_type_t *rtgui_list_view_type_get(void); + +rtgui_list_view_t* rtgui_list_view_create(struct rtgui_list_item* items, rt_uint16_t count, + rtgui_rect_t *rect); +void rtgui_list_view_clear(rtgui_list_view_t* view); + +rt_bool_t rtgui_list_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event); + +#endif diff --git a/rtgui/widgets/about_view.c b/rtgui/widgets/about_view.c new file mode 100644 index 0000000000..f12baa4333 --- /dev/null +++ b/rtgui/widgets/about_view.c @@ -0,0 +1,108 @@ +/* + * File : about_view.c + * This file is part of RTGUI in RT-Thread RTOS + * COPYRIGHT (C) 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-01-06 Bernard first version + */ + +#include +#include + +static void _rtgui_about_view_constructor(struct rtgui_about_view *view) +{ + /* default rect */ + struct rtgui_rect rect = {0, 0, 200, 200}; + + /* set default widget rect and set event handler */ + rtgui_widget_set_event_handler(RTGUI_WIDGET(view),rtgui_about_view_event_handler); + rtgui_widget_set_rect(RTGUI_WIDGET(view), &rect); + + RTGUI_WIDGET(view)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE; + + view->logo = RT_NULL; + view->description = RT_NULL; + + RTGUI_WIDGET_TEXTALIGN(RTGUI_WIDGET(view)) = RTGUI_ALIGN_CENTER_VERTICAL; +} + +rtgui_type_t *rtgui_about_view_type_get(void) +{ + static rtgui_type_t *list_view_type = RT_NULL; + + if (!list_view_type) + { + list_view_type = rtgui_type_create("aboutview", RTGUI_VIEW_TYPE, + sizeof(rtgui_about_view_t), RTGUI_CONSTRUCTOR(_rtgui_about_view_constructor), RT_NULL); + } + + return list_view_type; +} + +void rtgui_about_view_ondraw(struct rtgui_about_view* view) +{ + struct rtgui_rect rect; + struct rtgui_dc* dc; + + dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(view)); + if (dc == RT_NULL) return; + + rtgui_widget_get_rect(RTGUI_WIDGET(view), &rect); + rtgui_dc_fill_rect(dc, &rect); + + if (view->logo != RT_NULL) + rtgui_image_blit(view->logo, dc, &rect); + + rect.y1 += view->logo->h + 5; + if (view->description != RT_NULL) + rtgui_dc_draw_text(dc, view->description, &rect); + + rect.y1 += rtgui_dc_get_font(dc)->height; + rtgui_dc_draw_hline(dc, rect.x1 + 3, rect.x2 - 3, rect.y1); + rtgui_dc_set_color(dc, white); + rtgui_dc_draw_hline(dc, rect.x1 + 4, rect.x2 - 2, rect.y1 + 1); + + rtgui_dc_end_drawing(dc); +} + +rt_bool_t rtgui_about_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + struct rtgui_about_view* view = RT_NULL; + + view = RTGUI_ABOUT_VIEW(widget); + switch (event->type) + { + case RTGUI_EVENT_PAINT: + rtgui_about_view_ondraw(view); + return RT_FALSE; + } + + /* use view event handler */ + return rtgui_view_event_handler(widget, event); +} + +rtgui_about_view_t* rtgui_about_view_create(rtgui_image_t *logo, const char* description) +{ + struct rtgui_about_view* view = RT_NULL; + + view = (struct rtgui_about_view*) rtgui_widget_create(RTGUI_ABOUT_VIEW_TYPE); + if (view != RT_NULL) + { + view->logo = logo; + view->description = description; + } + + return view; +} + +void rtgui_about_view_destroy(rtgui_about_view_t* view) +{ + /* destroy view */ + rtgui_widget_destroy(RTGUI_WIDGET(view)); +} diff --git a/rtgui/widgets/filelist_view.c b/rtgui/widgets/filelist_view.c index 23a05cb592..eeba921d9f 100644 --- a/rtgui/widgets/filelist_view.c +++ b/rtgui/widgets/filelist_view.c @@ -11,3 +11,675 @@ * Date Author Notes * 2010-01-06 Bernard first version */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#define PATH_SEPARATOR '\\' +#define stat _stat +#else +#include +#define PATH_SEPARATOR '/' +#endif + +#include + +#define RTGUI_FILELIST_MARGIN 5 + +const static char * file_xpm[] = { +"16 16 21 1", +" c None", +". c #999999", +"+ c #818181", +"@ c #FFFFFF", +"# c #ECECEC", +"$ c #EAEAEA", +"% c #EBEBEB", +"& c #EDEDED", +"* c #F0F0F0", +"= c #C4C4C4", +"- c #C5C5C5", +"; c #C6C6C6", +"> c #C7C7C7", +", c #EEEEEE", +"' c #EDEDE5", +") c #EDEDE6", +"! c #EFEFEF", +"~ c #C8C8C8", +"{ c #F1F1F1", +"] c #F2F2F2", +"^ c #959595", +".++++++++++++ ", +"+@@@@@@@@@@@@+ ", +"+@#$$%%%##&*@+ ", +"+@$=--;;;;>*@+ ", +"+@$%%###&&,*@+ ", +"+@%-;;;;;;>*@+ ", +"+@%%##&&'#,*@+ ", +"+@%;;;;,,),*@+ ", +"+@##&&,,!!!*@+ ", +"+@#;;;>>~~~*@+ ", +"+@#&,,!!*{{{@+ ", +"+@&;>>~~~{{]@+ ", +"+@&&,!!**{]]@+ ", +"+@@@@@@@@@@@@+ ", +"^++++++++++++^ ", +" "}; + +const static char * folder_xpm[] = { +"16 16 121 2", +" c None", +". c #D9B434", +"+ c #E1C25E", +"@ c #E2C360", +"# c #E2C35F", +"$ c #DBB63C", +"% c #DAB336", +"& c #FEFEFD", +"* c #FFFFFE", +"= c #FFFEFE", +"- c #FFFEFD", +"; c #FBF7EA", +"> c #E4C76B", +", c #E3C76B", +"' c #E6CD79", +") c #E5CA74", +"! c #DAAF35", +"~ c #FEFCF7", +"{ c #F8E48E", +"] c #F5DE91", +"^ c #F5E09F", +"/ c #F6E1AC", +"( c #FEFBEF", +"_ c #FEFDF4", +": c #FEFCF3", +"< c #FEFCF1", +"[ c #FEFBEE", +"} c #FFFDFA", +"| c #DAAF36", +"1 c #DAAA36", +"2 c #FDFAF1", +"3 c #F5DE94", +"4 c #F4DC93", +"5 c #F2D581", +"6 c #EDCA6A", +"7 c #EACB6C", +"8 c #EFD385", +"9 c #EFD280", +"0 c #EFD07A", +"a c #EECF76", +"b c #EECF72", +"c c #FBF7E9", +"d c #DAAE34", +"e c #DAAB35", +"f c #FBF6E8", +"g c #EFD494", +"h c #EECE88", +"i c #E9C173", +"j c #F6E9C9", +"k c #FEFCF2", +"l c #FEFCF0", +"m c #DAAB36", +"n c #DAA637", +"o c #FFFDF8", +"p c #FFFDF6", +"q c #FFFCF5", +"r c #FCF6D8", +"s c #F8E694", +"t c #F7E385", +"u c #F6DF76", +"v c #F5DB68", +"w c #F4D85C", +"x c #FCF4D7", +"y c #DAA435", +"z c #DAA136", +"A c #FEFCF6", +"B c #FCF2C8", +"C c #FBEFB9", +"D c #FAECAC", +"E c #F9E89C", +"F c #F7E38B", +"G c #F6E07C", +"H c #F6DC6C", +"I c #F5D95D", +"J c #F4D64F", +"K c #F3D344", +"L c #FCF3D0", +"M c #DA9F35", +"N c #DA9A36", +"O c #FDFAF2", +"P c #FAEDB3", +"Q c #F9E9A4", +"R c #F8E695", +"S c #F7E285", +"T c #F6DE76", +"U c #F5DB65", +"V c #F4D757", +"W c #F3D449", +"X c #F2D13B", +"Y c #F1CE30", +"Z c #FBF2CC", +"` c #DA9835", +" . c #DA9435", +".. c #FEFAEF", +"+. c #F9E9A1", +"@. c #F8E591", +"#. c #F7E181", +"$. c #F6DE72", +"%. c #F5DA63", +"&. c #F4D754", +"*. c #F3D347", +"=. c #F2D039", +"-. c #F1CD2E", +";. c #F0CB26", +">. c #FBF2CA", +",. c #D98E33", +"'. c #FAF0DC", +"). c #F4DDA7", +"!. c #F4DB9E", +"~. c #F3DA96", +"{. c #F3D88E", +"]. c #F3D786", +"^. c #F2D47F", +"/. c #F2D379", +"(. c #F1D272", +"_. c #F1D06C", +":. c #F1CF69", +"<. c #F8EAC2", +"[. c #D8882D", +"}. c #D8872D", +"|. c #D8862C", +" ", +" ", +" ", +" . + @ @ @ # $ ", +" % & * = - * ; > , , , ' ) ", +" ! ~ { ] ^ / ( _ : < ( [ } | ", +" 1 2 3 4 5 6 7 8 9 0 a b c d ", +" e f g h i j k : k l ( [ * m ", +" n * o p q : r s t u v w x y ", +" z A B C D E F G H I J K L M ", +" N O P Q R S T U V W X Y Z ` ", +" ...+.@.#.$.%.&.*.=.-.;.>. . ", +" ,.'.).!.~.{.].^./.(._.:.<.,. ", +" [.}.[.[.[.[.[.[.[.[.}.[.|. ", +" ", +" "}; + +/* image for file and folder */ +static rtgui_image_t *file_image, *folder_image; +static struct rtgui_filelist_view *filelist_view = RT_NULL; /* only one view in global */ + +static void _rtgui_filelist_view_constructor(struct rtgui_filelist_view *view) +{ + /* default rect */ + struct rtgui_rect rect = {0, 0, 200, 200}; + + /* set default widget rect and set event handler */ + rtgui_widget_set_event_handler(RTGUI_WIDGET(view), rtgui_filelist_view_event_handler); + rtgui_widget_set_rect(RTGUI_WIDGET(view), &rect); + + RTGUI_WIDGET(view)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE; + + view->current_item = 0; + view->items_count = 0; + view->page_items = 0; + + view->current_directory = RT_NULL; + view->pattern = RT_NULL; + RTGUI_WIDGET_BACKGROUND(RTGUI_WIDGET(view)) = white; + RTGUI_WIDGET_TEXTALIGN(RTGUI_WIDGET(view)) = RTGUI_ALIGN_CENTER_VERTICAL; + + file_image = rtgui_image_create_from_mem("xpm", + (rt_uint8_t*)file_xpm, sizeof(file_xpm), RT_TRUE); + folder_image = rtgui_image_create_from_mem("xpm", + (rt_uint8_t*)folder_xpm, sizeof(folder_xpm), RT_TRUE); +} + +rtgui_type_t *rtgui_filelist_view_type_get(void) +{ + static rtgui_type_t *filelist_view_type = RT_NULL; + + if (!filelist_view_type) + { + filelist_view_type = rtgui_type_create("flview", RTGUI_VIEW_TYPE, + sizeof(rtgui_filelist_view_t), RTGUI_CONSTRUCTOR(_rtgui_filelist_view_constructor), RT_NULL); + } + + return filelist_view_type; +} + +void rtgui_filelist_view_ondraw(struct rtgui_filelist_view* view) +{ + struct rtgui_dc* dc; + rt_uint16_t page_index, index; + struct rtgui_file_item* item; + struct rtgui_rect rect, item_rect, image_rect; + + dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(view)); + if (dc == RT_NULL) return; + + rtgui_widget_get_rect(RTGUI_WIDGET(view), &rect); + rtgui_dc_fill_rect(dc, &rect); + + /* get item base rect */ + item_rect = rect; + item_rect.y1 += 1; + item_rect.y2 = item_rect.y1 + (1 + rtgui_theme_get_selected_height()); + + /* get image base rect */ + image_rect.x1 = RTGUI_FILELIST_MARGIN; image_rect.y1 = 0; + image_rect.x2 = RTGUI_FILELIST_MARGIN + file_image->w; image_rect.y2 = file_image->h; + rtgui_rect_moveto_align(&item_rect, &image_rect, RTGUI_ALIGN_CENTER_VERTICAL); + + /* get current page */ + page_index = (view->current_item / view->page_items) * view->page_items; + for (index = 0; index < view->page_items; index ++) + { + if (page_index + index >= view->items_count) break; + + item = &(view->items[page_index + index]); + + if (page_index + index == view->current_item) + { + rtgui_theme_draw_selected(dc, &item_rect); + } + else + { + /* draw background */ + rtgui_dc_fill_rect(dc, &item_rect); + } + + /* draw item */ + + if (item->type == RTGUI_FITEM_FILE) + rtgui_image_blit(file_image, dc, &image_rect); + else + rtgui_image_blit(folder_image, dc, &image_rect); + + /* draw text */ + item_rect.x1 += RTGUI_FILELIST_MARGIN + file_image->w + 2; + rtgui_dc_draw_text(dc, item->name, &item_rect); + item_rect.x1 -= RTGUI_FILELIST_MARGIN + file_image->w + 2; + + /* move to next item position */ + item_rect.y1 += (rtgui_theme_get_selected_height() + 1); + item_rect.y2 += (rtgui_theme_get_selected_height() + 1); + + image_rect.y1 += (rtgui_theme_get_selected_height() + 1); + image_rect.y2 += (rtgui_theme_get_selected_height() + 1); + } + + rtgui_dc_end_drawing(dc); +} + +void rtgui_filelist_view_update_current(struct rtgui_filelist_view* view, rt_uint16_t old_item) +{ + struct rtgui_dc* dc; + struct rtgui_file_item* item; + rtgui_rect_t rect, item_rect, image_rect; + + if (old_item/view->page_items != view->current_item/view->page_items) + { + /* it's not a same page, update all */ + rtgui_widget_update(RTGUI_WIDGET(view)); + return; + } + + dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(view)); + if (dc == RT_NULL) return; + + rtgui_widget_get_rect(RTGUI_WIDGET(view), &rect); + + /* get old item rect */ + item_rect = rect; + item_rect.y1 += 1; + item_rect.y1 += (old_item % view->page_items) * (1 + rtgui_theme_get_selected_height()); + item_rect.y2 = item_rect.y1 + (1 + rtgui_theme_get_selected_height()); + + /* get image rect */ + image_rect.x1 = RTGUI_FILELIST_MARGIN; image_rect.y1 = 0; + image_rect.x2 = RTGUI_FILELIST_MARGIN + file_image->w; image_rect.y2 = file_image->h; + rtgui_rect_moveto_align(&item_rect, &image_rect, RTGUI_ALIGN_CENTER_VERTICAL); + + /* draw old item */ + rtgui_dc_fill_rect(dc, &item_rect); + + item = &(view->items[old_item]); + if (item->type == RTGUI_FITEM_FILE) /* draw item image */ + rtgui_image_blit(file_image, dc, &image_rect); + else + rtgui_image_blit(folder_image, dc, &image_rect); + + item_rect.x1 += RTGUI_FILELIST_MARGIN + file_image->w + 2; + rtgui_dc_draw_text(dc, item->name, &item_rect); + + /* draw current item */ + item_rect = rect; + item_rect.y1 += 1; + item_rect.y1 += (view->current_item % view->page_items) * (1 + rtgui_theme_get_selected_height()); + item_rect.y2 = item_rect.y1 + (1 + rtgui_theme_get_selected_height()); + + rtgui_theme_draw_selected(dc, &item_rect); + + /* get image base rect */ + image_rect.x1 = RTGUI_FILELIST_MARGIN; image_rect.y1 = 0; + image_rect.x2 = RTGUI_FILELIST_MARGIN + file_image->w; image_rect.y2 = file_image->h; + rtgui_rect_moveto_align(&item_rect, &image_rect, RTGUI_ALIGN_CENTER_VERTICAL); + + item = &(view->items[view->current_item]); + if (item->type == RTGUI_FITEM_FILE) /* draw item image */ + rtgui_image_blit(file_image, dc, &image_rect); + else + rtgui_image_blit(folder_image, dc, &image_rect); + + item_rect.x1 += RTGUI_FILELIST_MARGIN + file_image->w + 2; + rtgui_dc_draw_text(dc, item->name, &item_rect); + + rtgui_dc_end_drawing(dc); +} + +rt_bool_t rtgui_filelist_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + struct rtgui_filelist_view* view = RT_NULL; + + view = RTGUI_FILELIST_VIEW(widget); + switch (event->type) + { + case RTGUI_EVENT_PAINT: + rtgui_filelist_view_ondraw(view); + return RT_FALSE; + + case RTGUI_EVENT_RESIZE: + { + struct rtgui_event_resize* resize; + + resize = (struct rtgui_event_resize*)event; + + /* recalculate page items */ + if (file_image != RT_NULL) + view->page_items = resize->h / (1 + rtgui_theme_get_selected_height()); + else + view->page_items = resize->h / (2 + 14); + } + break; + + case RTGUI_EVENT_KBD: + { + struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event; + if (ekbd->type == RTGUI_KEYDOWN) + { + rt_uint16_t old_item; + + old_item = view->current_item; + switch (ekbd->key) + { + case RTGUIK_UP: + if (view->current_item > 0) + view->current_item --; + rtgui_filelist_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_DOWN: + if (view->current_item < view->items_count - 1) + view->current_item ++; + rtgui_filelist_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_LEFT: + if (view->current_item - view->page_items >= 0) + view->current_item -= view->page_items; + rtgui_filelist_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_RIGHT: + if (view->current_item + view->page_items < view->items_count - 1) + view->current_item += view->page_items; + rtgui_filelist_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_RETURN: + if (view->items[view->current_item].type == RTGUI_FITEM_DIR) + { + char new_path[64]; + + if (strcmp(view->items[view->current_item].name, ".") == 0) return RT_FALSE; + if (strcmp(view->items[view->current_item].name, "..") == 0) + { + char *ptr; + ptr = strrchr(view->current_directory, PATH_SEPARATOR); + + if (ptr == RT_NULL) return RT_FALSE; + if (ptr == &(view->current_directory[0])) + { + /* it's root directory */ + new_path[0] = PATH_SEPARATOR; + new_path[1] = '\0'; + } + else + { + strncpy(new_path, view->current_directory, ptr - view->current_directory + 1); + new_path[ptr - view->current_directory] = '\0'; + } + } + else if (view->current_item == 0 && + (view->current_directory[0] == '/') && (view->current_directory[1] == '\0')) + { + if (RTGUI_VIEW(view)->modal_show == RT_TRUE) + { + rtgui_view_end_modal(RTGUI_VIEW(view), RTGUI_MODAL_CANCEL); + } + else + { + rtgui_filelist_view_destroy(view); + } + + return RT_FALSE; + } + else + { + if (view->current_directory[strlen(view->current_directory) - 1] != PATH_SEPARATOR) + sprintf(new_path, "%s%c%s",view->current_directory, PATH_SEPARATOR, + view->items[view->current_item].name); + else + sprintf(new_path, "%s%s",view->current_directory, + view->items[view->current_item].name); + } + rtgui_filelist_view_set_directory(view, new_path); + } + else + { + if (RTGUI_VIEW(view)->modal_show == RT_TRUE) + { + rtgui_view_end_modal(RTGUI_VIEW(view), RTGUI_MODAL_OK); + } + } + return RT_FALSE; + + default: + break; + } + } + } + return RT_FALSE; + } + + /* use view event handler */ + return rtgui_view_event_handler(widget, event); +} + +rtgui_filelist_view_t* rtgui_filelist_view_create(rtgui_workbench_t* workbench, + const char* directory, const char* pattern, const rtgui_rect_t* rect) +{ + struct rtgui_filelist_view* view = RT_NULL; + + /* create a new view */ + view = (struct rtgui_filelist_view*) rtgui_widget_create(RTGUI_FILELIST_VIEW_TYPE); + if (view != RT_NULL) + { + view->items = RT_NULL; + view->pattern = rt_strdup(pattern); + view->page_items = rtgui_rect_height(*rect) / (1 + rtgui_theme_get_selected_height()); + rtgui_filelist_view_set_directory(view, directory); + + rtgui_workbench_add_view(workbench, RTGUI_VIEW(view)); + } + + return view; +} + +void rtgui_filelist_view_destroy(rtgui_filelist_view_t* view) +{ + /* delete all file items */ + rtgui_filelist_view_clear(view); + /* delete current directory and pattern */ + rtgui_free(view->current_directory); view->current_directory = RT_NULL; + rtgui_free(view->pattern); view->pattern = RT_NULL; + + /* delete image */ + rtgui_image_destroy(file_image); + rtgui_image_destroy(folder_image); + + /* destroy view */ + rtgui_widget_destroy(RTGUI_WIDGET(view)); +} + +/* clear all file items */ +void rtgui_filelist_view_clear(rtgui_filelist_view_t* view) +{ + rt_uint32_t index; + struct rtgui_file_item* item; + + for (index = 0; index < view->items_count; index ++) + { + item = &(view->items[index]); + + /* release item name */ + rt_free(item->name); + item->name = RT_NULL; + } + + /* release items */ + rtgui_free(view->items); + view->items = RT_NULL; + + view->items_count = 0; + view->current_item = 0; +} + +void rtgui_filelist_view_set_directory(rtgui_filelist_view_t* view, const char* directory) +{ + rt_uint8_t fullpath[256]; + struct rtgui_file_item *item; + + RT_ASSERT(view != RT_NULL); + + /* clear file items firstly */ + rtgui_filelist_view_clear(view); + if (directory != RT_NULL) + { + DIR* dir; + struct stat s; + rt_uint32_t index; + struct dirent* dirent; + + view->items_count = 0; + dir = opendir(directory); + if (dir == RT_NULL) goto __return; + + /* current directory exists, set it */ + if (view->current_directory != RT_NULL) rt_free(view->current_directory); + view->current_directory = rt_strdup(directory); + + do + { + dirent = readdir(dir); + if (dirent == RT_NULL) break; + + if (strcmp(dirent->d_name, ".") == 0) continue; + if (strcmp(dirent->d_name, "..") == 0) continue; + + view->items_count ++; + } while (dirent != RT_NULL); + closedir(dir); + + view->items_count ++; /* root directory for [x] exit, others for .. */ + + view->items = (struct rtgui_file_item*) rtgui_malloc(sizeof(struct rtgui_file_item) * view->items_count); + if (view->items == RT_NULL) return; /* no memory */ + + index = 0; + if (directory[0] == '/' && directory[1] != '\0') + { + item = &(view->items[0]); + + /* add .. directory */ + item->name = rt_strdup(".."); + item->type = RTGUI_FITEM_DIR; + item->size = 0; + + index ++; + } + else + { + item = &(view->items[0]); + + /* add .. directory */ + item->name = rt_strdup("Í˳öÎļþä¯ÀÀ"); + item->type = RTGUI_FITEM_DIR; + item->size = 0; + + index ++; + } + + /* reopen directory */ + dir = opendir(directory); + for (; index < view->items_count; index ++) + { + dirent = readdir(dir); + if (dirent == RT_NULL) break; + + item = &(view->items[index]); + item->name = rt_strdup(dirent->d_name); + + rt_memset(&s, 0, sizeof(struct stat)); + + /* build full path for the file */ + if (directory[strlen(directory) - 1] != PATH_SEPARATOR) + sprintf(fullpath, "%s%c%s", directory, PATH_SEPARATOR, dirent->d_name); + else + sprintf(fullpath, "%s%s", directory, dirent->d_name); + + stat(fullpath, &s); + if ( s.st_mode & S_IFDIR ) + { + item->type = RTGUI_FITEM_DIR; + item->size = 0; + } + else + { + item->type = RTGUI_FITEM_FILE; + item->size = s.st_size; + } + } + + closedir(dir); + } + + view->current_item = 0; + +__return: + /* update view */ + rtgui_widget_update(RTGUI_WIDGET(view)); +} diff --git a/rtgui/widgets/list_view.c b/rtgui/widgets/list_view.c index 853bbe6d4d..91ff21970b 100644 --- a/rtgui/widgets/list_view.c +++ b/rtgui/widgets/list_view.c @@ -11,3 +11,248 @@ * Date Author Notes * 2010-01-06 Bernard first version */ + +#include +#include + +#define LIST_MARGIN 5 + +static void _rtgui_list_view_constructor(struct rtgui_list_view *view) +{ + /* default rect */ + struct rtgui_rect rect = {0, 0, 200, 200}; + + /* set default widget rect and set event handler */ + rtgui_widget_set_event_handler(RTGUI_WIDGET(view),rtgui_list_view_event_handler); + rtgui_widget_set_rect(RTGUI_WIDGET(view), &rect); + + RTGUI_WIDGET(view)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE; + + view->current_item = 0; + view->items_count = 0; + view->page_items = 0; + + RTGUI_WIDGET_BACKGROUND(RTGUI_WIDGET(view)) = white; + RTGUI_WIDGET_TEXTALIGN(RTGUI_WIDGET(view)) = RTGUI_ALIGN_CENTER_VERTICAL; +} + +rtgui_type_t *rtgui_list_view_type_get(void) +{ + static rtgui_type_t *list_view_type = RT_NULL; + + if (!list_view_type) + { + list_view_type = rtgui_type_create("listview", RTGUI_VIEW_TYPE, + sizeof(rtgui_list_view_t), RTGUI_CONSTRUCTOR(_rtgui_list_view_constructor), RT_NULL); + } + + return list_view_type; +} + +void rtgui_list_view_ondraw(struct rtgui_list_view* view) +{ + struct rtgui_rect rect, item_rect; + struct rtgui_dc* dc; + rt_uint16_t page_index, index; + struct rtgui_list_item* item; + + dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(view)); + if (dc == RT_NULL) return; + + rtgui_widget_get_rect(RTGUI_WIDGET(view), &rect); + rtgui_dc_fill_rect(dc, &rect); + + /* get item base rect */ + item_rect = rect; + item_rect.y1 += 2; + item_rect.y2 = item_rect.y1 + (2 + rtgui_theme_get_selected_height()); + + /* get current page */ + page_index = (view->current_item / view->page_items) * view->page_items; + for (index = 0; index < view->page_items; index ++) + { + if (page_index + index >= view->items_count) break; + + item = &(view->items[page_index + index]); + + if (page_index + index == view->current_item) + { + rtgui_theme_draw_selected(dc, &item_rect); + } + item_rect.x1 += LIST_MARGIN; + + if (item->image != RT_NULL) + { + rtgui_image_blit(item->image, dc, &item_rect); + item_rect.x1 += item->image->w + 2; + } + /* draw text */ + rtgui_dc_draw_text(dc, item->name, &item_rect); + + if (item->image != RT_NULL) + item_rect.x1 -= (item->image->w + 2); + item_rect.x1 -= LIST_MARGIN; + + /* move to next item position */ + item_rect.y1 += (rtgui_theme_get_selected_height() + 2); + item_rect.y2 += (rtgui_theme_get_selected_height() + 2); + } + rtgui_dc_end_drawing(dc); +} + +void rtgui_list_view_update_current(struct rtgui_list_view* view, rt_uint16_t old_item) +{ + struct rtgui_dc* dc; + struct rtgui_list_item* item; + rtgui_rect_t rect, item_rect; + + if (old_item/view->page_items != view->current_item/view->page_items) + { + /* it's not a same page, update all */ + rtgui_widget_update(RTGUI_WIDGET(view)); + return; + } + + dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(view)); + if (dc == RT_NULL) return; + + rtgui_widget_get_rect(RTGUI_WIDGET(view), &rect); + + item_rect = rect; + /* get old item's rect */ + item_rect.y1 += 2; + item_rect.y1 += (old_item % view->page_items) * (2 + rtgui_theme_get_selected_height()); + item_rect.y2 = item_rect.y1 + (2 + rtgui_theme_get_selected_height()); + + /* draw old item */ + rtgui_dc_fill_rect(dc, &item_rect); + + item_rect.x1 += LIST_MARGIN; + + item = &(view->items[old_item]); + if (item->image != RT_NULL) + { + rtgui_image_blit(item->image, dc, &item_rect); + item_rect.x1 += item->image->w + 2; + } + rtgui_dc_draw_text(dc, item->name, &item_rect); + + /* draw current item */ + item_rect = rect; + /* get current item's rect */ + item_rect.y1 += 2; + item_rect.y1 += (view->current_item % view->page_items) * (2 + rtgui_theme_get_selected_height()); + item_rect.y2 = item_rect.y1 + (2 + rtgui_theme_get_selected_height()); + + /* draw current item */ + rtgui_theme_draw_selected(dc, &item_rect); + + item_rect.x1 += LIST_MARGIN; + + item = &(view->items[view->current_item]); + if (item->image != RT_NULL) + { + rtgui_image_blit(item->image, dc, &item_rect); + item_rect.x1 += (item->image->w + 2); + } + rtgui_dc_draw_text(dc, item->name, &item_rect); + + rtgui_dc_end_drawing(dc); +} + +rt_bool_t rtgui_list_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + struct rtgui_list_view* view = RT_NULL; + + view = RTGUI_LIST_VIEW(widget); + switch (event->type) + { + case RTGUI_EVENT_PAINT: + rtgui_list_view_ondraw(view); + return RT_FALSE; + + case RTGUI_EVENT_RESIZE: + { + struct rtgui_event_resize* resize; + + resize = (struct rtgui_event_resize*)event; + + /* recalculate page items */ + view->page_items = resize->h / (2 + rtgui_theme_get_selected_height()); + } + break; + + case RTGUI_EVENT_KBD: + { + struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event; + if (ekbd->type == RTGUI_KEYDOWN) + { + rt_uint16_t old_item; + + old_item = view->current_item; + switch (ekbd->key) + { + case RTGUIK_LEFT: + if (view->current_item - view->page_items >= 0) + view->current_item -= view->page_items; + rtgui_list_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_UP: + if (view->current_item > 0) + view->current_item --; + rtgui_list_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_RIGHT: + if (view->current_item + view->page_items < view->items_count - 1) + view->current_item += view->page_items; + rtgui_list_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_DOWN: + if (view->current_item < view->items_count - 1) + view->current_item ++; + rtgui_list_view_update_current(view, old_item); + return RT_FALSE; + + case RTGUIK_RETURN: + if (view->items[view->current_item].action != RT_NULL) + { + view->items[view->current_item].action(view->items[view->current_item].parameter); + } + return RT_FALSE; + + default: + break; + } + } + } + return RT_FALSE; + } + + /* use view event handler */ + return rtgui_view_event_handler(widget, event); +} + +rtgui_list_view_t* rtgui_list_view_create(struct rtgui_list_item* items, rt_uint16_t count, rtgui_rect_t *rect) +{ + struct rtgui_list_view* view = RT_NULL; + + view = (struct rtgui_list_view*) rtgui_widget_create(RTGUI_LIST_VIEW_TYPE); + if (view != RT_NULL) + { + view->items = items; + view->items_count = count; + + view->page_items = rtgui_rect_height(*rect) / (2 + rtgui_theme_get_selected_height()); + } + + return view; +} + +void rtgui_list_view_destroy(rtgui_list_view_t* view) +{ + /* destroy view */ + rtgui_widget_destroy(RTGUI_WIDGET(view)); +}