浏览代码

add multi-text view widget.

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1455 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong@gmail.com 14 年之前
父节点
当前提交
db9e590b90

+ 10 - 0
components/rtgui/common/image.c

@@ -295,3 +295,13 @@ struct rtgui_image_palette* rtgui_image_palette_create(rt_uint32_t ncolors)
 
 	return palette;
 }
+
+void rtgui_image_get_rect(struct rtgui_image* image, struct rtgui_rect* rect)
+{
+	RT_ASSERT(image != RT_NULL);
+	RT_ASSERT(rect  != RT_NULL);
+
+	rect->x1 = 0; rect->y1 = 0;
+	rect->x2 = image->w; rect->y2 = image->h;
+}
+

+ 4 - 0
components/rtgui/include/rtgui/image.h

@@ -66,6 +66,9 @@ struct rtgui_image* rtgui_image_create(const char* filename, rt_bool_t load);
 struct rtgui_image* rtgui_image_create_from_mem(const char* type, const rt_uint8_t* data, rt_size_t length, rt_bool_t load);
 void rtgui_image_destroy(struct rtgui_image* image);
 
+/* get image's rect */
+void rtgui_image_get_rect(struct rtgui_image* image, struct rtgui_rect* rect);
+
 /* register an image engine */
 void rtgui_image_register_engine(struct rtgui_image_engine* engine);
 
@@ -74,3 +77,4 @@ void rtgui_image_blit(struct rtgui_image* image, struct rtgui_dc* dc, struct rtg
 struct rtgui_image_palette* rtgui_image_palette_create(rt_uint32_t ncolors);
 
 #endif
+

+ 65 - 65
components/rtgui/include/rtgui/list.h

@@ -1,66 +1,66 @@
-/*
- * File      : list.h
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2009, 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
- * 2009-10-16     Bernard      first version
- */
-#ifndef __RTGUI_LIST_H__
-#define __RTGUI_LIST_H__
-
-#include <rtgui/rtgui.h>
-
-struct rtgui_list_node
-{
-	struct rtgui_list_node* next;
-};
-typedef struct rtgui_list_node rtgui_list_t;
-
-rt_inline void rtgui_list_init(rtgui_list_t *l)
-{
-	l->next = (struct rtgui_list_node *)0;
-}
+/*
+ * File      : list.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2009, 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
+ * 2009-10-16     Bernard      first version
+ */
+#ifndef __RTGUI_LIST_H__
+#define __RTGUI_LIST_H__
 
-rt_inline void rtgui_list_append(rtgui_list_t *l, rtgui_list_t *n)
-{
-	struct rtgui_list_node* node;
-
-	node = l;
-	while (node->next) node = node->next;
-
-	/* append the node to the tail */
-	node->next = n;
-	n->next = (struct rtgui_list_node*) 0;
-}
-
-rt_inline void rtgui_list_insert(rtgui_list_t *l, rtgui_list_t *n)
-{
-	n->next = l->next;
-	l->next = n;
-}
-
-rt_inline rtgui_list_t* rtgui_list_remove(rtgui_list_t *l, rtgui_list_t *n)
-{
-	/* remove slist head */
-	struct rtgui_list_node* node = l;
-	while (node->next && node->next != n) node = node->next;
-
-	/* remove node */
-	if (node->next != (rtgui_list_t *)0) node->next = node->next->next;
-
-	return l;
-}
-
-#define rtgui_list_entry(node, type, member)	\
-	((type *)((char*)(node)-(unsigned long)(&((type *)0)->member)))
-
-#define rtgui_list_foreach(node, list)	\
-	for ((node) = (list)->next; (node) != RT_NULL; (node) = (node)->next)
-
-#endif
+#include <rtgui/rtgui.h>
+
+struct rtgui_list_node
+{
+	struct rtgui_list_node* next;
+};
+typedef struct rtgui_list_node rtgui_list_t;
+
+rt_inline void rtgui_list_init(rtgui_list_t *l)
+{
+	l->next = (struct rtgui_list_node *)0;
+}
+
+rt_inline void rtgui_list_append(rtgui_list_t *l, rtgui_list_t *n)
+{
+	struct rtgui_list_node* node;
+
+	node = l;
+	while (node->next) node = node->next;
+
+	/* append the node to the tail */
+	node->next = n;
+	n->next = (struct rtgui_list_node*) 0;
+}
+
+rt_inline void rtgui_list_insert(rtgui_list_t *l, rtgui_list_t *n)
+{
+	n->next = l->next;
+	l->next = n;
+}
+
+rt_inline rtgui_list_t* rtgui_list_remove(rtgui_list_t *l, rtgui_list_t *n)
+{
+	/* remove slist head */
+	struct rtgui_list_node* node = l;
+	while (node->next && node->next != n) node = node->next;
+
+	/* remove node */
+	if (node->next != (rtgui_list_t *)0) node->next = node->next->next;
+
+	return l;
+}
+
+#define rtgui_list_entry(node, type, member)	\
+	((type *)((char*)(node)-(unsigned long)(&((type *)0)->member)))
+
+#define rtgui_list_foreach(node, list)	\
+	for ((node) = (list)->next; (node) != RT_NULL; (node) = (node)->next)
+
+#endif

+ 67 - 0
components/rtgui/include/rtgui/widgets/textview.h

@@ -0,0 +1,67 @@
+/*
+ * File      : textview.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, 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
+ * 2011-03-05     Bernard      first version
+ */
+#ifndef __RTGUI_TEXTVIEW_H__
+#define __RTGUI_TEXTVIEW_H__
+
+#include <rtgui/widgets/widget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup rtgui_textview
+ * @{
+ */
+
+DECLARE_CLASS_TYPE(textview);
+
+/** Gets the type of a textview */
+#define RTGUI_TEXTVIEW_TYPE       (RTGUI_TYPE(textview))
+/** Casts the object to an rtgui_textview */
+#define RTGUI_TEXTVIEW(obj)       (RTGUI_OBJECT_CAST((obj), RTGUI_TEXTVIEW_TYPE, rtgui_textview_t))
+/** Checks if the object is an rtgui_textview */
+#define RTGUI_IS_TEXTVIEW(obj)    (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_TEXTVIEW_TYPE))
+
+/*
+ * the textview widget
+ */
+struct rtgui_textview
+{
+	/* inherit from widget */
+	struct rtgui_widget parent;
+
+	rt_uint16_t line_width;
+	rt_uint16_t line_count;
+
+	char* lines;
+
+	rt_int16_t line_current;
+	rt_uint16_t line_page_count;
+};
+typedef struct rtgui_textview rtgui_textview_t;
+
+rtgui_textview_t* rtgui_textview_create(const char* text, const rtgui_rect_t *rect);
+void rtgui_textview_destroy(rtgui_textview_t* textview);
+
+rt_bool_t rtgui_textview_event_handler(struct rtgui_widget* widget, struct rtgui_event* event);
+void rtgui_textview_set_text(rtgui_textview_t* textview, const char* text);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 5
components/rtgui/widgets/button.c

@@ -66,11 +66,7 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_widget* widget, struct rtgui_e
 	switch (event->type)
 	{
 	case RTGUI_EVENT_PAINT:
-#ifndef RTGUI_USING_SMALL_SIZE		
-		if (widget->on_draw != RT_NULL ) widget->on_draw(widget, event);
-		else
-#endif			
-			rtgui_theme_draw_button(btn);
+		rtgui_theme_draw_button(btn);
 		break;
 
 	case RTGUI_EVENT_KBD:

+ 4 - 0
components/rtgui/widgets/label.c

@@ -95,6 +95,9 @@ void rtgui_label_set_text(rtgui_label_t* label, const char* text)
 
 	if (label->text != RT_NULL)
 	{
+		/* it's a same text string */
+		if (rt_strncmp(text, label->text, rt_strlen(text)) == 0) return;
+		
 		/* release old text memory */
 		rt_free(label->text);
 	}
@@ -105,3 +108,4 @@ void rtgui_label_set_text(rtgui_label_t* label, const char* text)
 	/* update widget */
 	rtgui_theme_draw_label(label);
 }
+

+ 14 - 5
components/rtgui/widgets/listbox.c

@@ -41,10 +41,10 @@ DEFINE_CLASS_TYPE(listbox, "listbox",
 
 void rtgui_listbox_ondraw(struct rtgui_listbox* box)
 {
-	struct rtgui_rect rect, item_rect;
 	struct rtgui_dc* dc;
 	rt_uint16_t page_index, index;
 	const struct rtgui_listbox_item* item;
+	struct rtgui_rect rect, item_rect, image_rect;
 
 	dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(box));
 	if (dc == RT_NULL) return;
@@ -83,7 +83,10 @@ void rtgui_listbox_ondraw(struct rtgui_listbox* box)
 
 		if (item->image != RT_NULL)
 		{
-			rtgui_image_blit(item->image, dc, &item_rect);
+			rtgui_image_get_rect(item->image, &image_rect);
+			rtgui_rect_moveto_align(&item_rect, &image_rect, RTGUI_ALIGN_CENTER_VERTICAL);
+
+			rtgui_image_blit(item->image, dc, &image_rect);
 			item_rect.x1 += item->image->w + 2;
 		}
         /* draw text */
@@ -104,7 +107,7 @@ static void rtgui_listbox_update_current(struct rtgui_listbox* box, rt_int16_t o
 {
 	struct rtgui_dc* dc;
 	const struct rtgui_listbox_item* item;
-	rtgui_rect_t rect, item_rect;
+	rtgui_rect_t rect, item_rect, image_rect;
 
 	if ((old_item == -1) || (old_item/box->page_items != box->current_item/box->page_items))
 	{
@@ -134,7 +137,10 @@ static void rtgui_listbox_update_current(struct rtgui_listbox* box, rt_int16_t o
 	item = &(box->items[old_item]);
 	if (item->image != RT_NULL)
 	{
-		rtgui_image_blit(item->image, dc, &item_rect);
+		rtgui_image_get_rect(item->image, &image_rect);
+		rtgui_rect_moveto_align(&item_rect, &image_rect, RTGUI_ALIGN_CENTER_VERTICAL);
+		
+		rtgui_image_blit(item->image, dc, &image_rect);
 		item_rect.x1 += item->image->w + 2;
 	}
 	rtgui_dc_draw_text(dc, item->name, &item_rect);
@@ -155,7 +161,10 @@ static void rtgui_listbox_update_current(struct rtgui_listbox* box, rt_int16_t o
 	item = &(box->items[box->current_item]);
 	if (item->image != RT_NULL)
 	{
-		rtgui_image_blit(item->image, dc, &item_rect);
+		rtgui_image_get_rect(item->image, &image_rect);
+		rtgui_rect_moveto_align(&item_rect, &image_rect, RTGUI_ALIGN_CENTER_VERTICAL);
+
+		rtgui_image_blit(item->image, dc, &image_rect);
         item_rect.x1 += (item->image->w + 2);
 	}
 	rtgui_dc_draw_text(dc, item->name, &item_rect);

+ 15 - 1
components/rtgui/widgets/menu.c

@@ -81,10 +81,18 @@ static void _rtgui_menu_onitem(struct rtgui_widget* widget, struct rtgui_event*
 	}
 	else /* other menu item */
 	{
+		rt_ubase_t index;
+		
 		/* invoke action */
 		if (menu->items[menu->items_list->current_item].on_menuaction != RT_NULL)
 			menu->items[menu->items_list->current_item].on_menuaction(RTGUI_WIDGET(menu), RT_NULL);
 
+		/* hide all of sub-menu */
+		for (index = 0; index < menu->items_count; index ++)
+		{
+			if (menu->items[index].submenu != RT_NULL)
+				rtgui_menu_hiden(menu->items[index].submenu);
+		}
 		rtgui_menu_hiden(menu);
 	}
 }
@@ -138,7 +146,7 @@ static void _rtgui_menu_item_ondraw(struct rtgui_listctrl *list, struct rtgui_dc
 }
 
 DEFINE_CLASS_TYPE(menu, "menu", 
-	RTGUI_WIDGET_TYPE,
+	RTGUI_WIN_TYPE,
 	_rtgui_menu_constructor,
 	_rtgui_menu_destructor,
 	sizeof(struct rtgui_menu));
@@ -170,6 +178,9 @@ static rt_bool_t rtgui_menu_on_deactivate(rtgui_widget_t* widget, rtgui_event_t*
 		menu->on_menuhide(RTGUI_WIDGET(menu), RT_NULL);
 	}
 
+	/* un-select item */
+	menu->items_list->current_item = -1;
+
 	/* if it's a submenu, try to hide parent menu */
 	if (menu->parent_menu != RT_NULL &&
 		rtgui_win_is_activated(RTGUI_WIN(menu->parent_menu)) == RT_FALSE)
@@ -258,7 +269,10 @@ void rtgui_menu_pop(struct rtgui_menu* menu, int x, int y)
 void rtgui_menu_hiden(struct rtgui_menu* menu)
 {
 	rtgui_win_hiden(RTGUI_WIN(menu));
+	/* un-select item */
+	menu->items_list->current_item = -1;
 
 	if (menu->parent_menu != RT_NULL)
 		rtgui_menu_hiden(menu->parent_menu);
 }
+

+ 2 - 2
components/rtgui/widgets/scrollbar.c

@@ -72,7 +72,7 @@ void rtgui_scrollbar_get_thumb_rect(rtgui_scrollbar_t *bar, rtgui_rect_t *rect)
 
 		/* vertical scroll bar */
 		rect->x1 = scrollbar_rect.x1;
-		rect->x2 = scrollbar_rect.x2;
+		rect->x2 = scrollbar_rect.x2 - 1;
 		rect->y1 = scrollbar_rect.y1 + btn_width + _rtgui_scrollbar_get_thumb_position(bar);
 		rect->y2 = rect->y1 + btn_width;
 	}
@@ -85,7 +85,7 @@ void rtgui_scrollbar_get_thumb_rect(rtgui_scrollbar_t *bar, rtgui_rect_t *rect)
 		rect->x2 = rect->x1 + btn_height;
 
 		rect->y1 = scrollbar_rect.y1;
-		rect->y2 = scrollbar_rect.y2;
+		rect->y2 = scrollbar_rect.y2 - 1;
 	}
 }
 

+ 352 - 0
components/rtgui/widgets/textview.c

@@ -0,0 +1,352 @@
+/*
+ * File      : textview.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2011, 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
+ * 2011-03-05     Bernard      first version
+ */
+#include <rtgui/dc.h>
+#include <rtgui/rtgui_system.h>
+#include <rtgui/widgets/textview.h>
+
+rt_inline unsigned char* _get_line_text(rtgui_textview_t *textview, rt_uint16_t index)
+{
+	unsigned char* line;
+	if (index < textview->line_count)
+	{
+		line = textview->lines + (index * textview->line_width);
+		return line;
+	}
+
+	return RT_NULL;
+}
+
+static void _calc_line(rtgui_textview_t *textview, const char* text)
+{
+	unsigned char* line;
+	const unsigned char* ptr;
+	rt_ubase_t line_index, line_position;
+
+	if (textview->lines != RT_NULL)
+	{
+		rt_free(textview->lines);
+		textview->lines = RT_NULL;
+		textview->line_count = 0;
+	}
+
+	/* get line count */
+	line_index = 0; line_position = 0;
+	ptr = (const unsigned char*)text;
+	if (*ptr == 0) return;
+
+	while (*ptr != '\0')
+	{
+		if (*ptr == '\n') 
+		{
+			line_index ++;
+			line_position = 0;
+		}
+		else if (*ptr == '\r')
+		{
+			ptr ++;
+			continue;
+		}
+		else if (*ptr == '\t')
+		{
+			line_position += 4;
+			if (line_position >= textview->line_width - 1)
+			{
+				line_index ++;
+				line_position = 0;
+			}
+		}
+		else 
+		{
+			if ((*ptr) >= 0x80)
+			{
+				/* fill cjk character */
+				if (line_position + 1 >= (textview->line_width - 1))
+				{
+					/* split to next line */
+					line_index ++;
+					line_position = 0;
+				}
+
+				line_position ++;
+				line_position ++;
+			}
+			else 
+			{
+				line_position ++;
+			}
+
+			if (line_position >= textview->line_width - 1)
+			{
+				line_index ++;
+				line_position = 0;
+			}
+		}
+
+		ptr ++;
+	}
+
+	/* set line count */
+	textview->line_count = line_index + 1;
+
+	/* allocate lines */
+	textview->lines = rt_malloc(textview->line_count * textview->line_width);
+	rt_memset(textview->lines, 0, (textview->line_count * textview->line_width));
+
+	/* fill lines */
+	line_index = 0; line_position = 0;
+	ptr = (const unsigned char*)text;
+	line = _get_line_text(textview, line_index);
+	while (*ptr)
+	{
+		if (*ptr == '\n') 
+		{
+			line_index ++;
+			line_position = 0;
+			line = _get_line_text(textview, line_index);
+		}
+		else if (*ptr == '\r')
+		{
+			/* ignore '\r' */
+			ptr ++;
+			continue;
+		}
+		else if (*ptr == '\t')
+		{
+			line[line_position++] = ' ';
+			line[line_position++] = ' ';
+			line[line_position++] = ' ';
+			line[line_position++] = ' ';
+			if (line_position >= textview->line_width - 1)
+			{
+				line_index ++;
+				line_position = 0;
+				line = _get_line_text(textview, line_index);
+			}
+		}
+		else 
+		{
+			if ((*ptr) >= 0x80)
+			{
+				/* fill cjk character */
+				if (line_position + 1 >= (textview->line_width - 1))
+				{
+					/* split to next line */
+					line_index ++;
+					line_position = 0;
+					line = _get_line_text(textview, line_index);
+				}
+
+				line[line_position ++] = *ptr ++;
+				line[line_position ++] = *ptr;
+			}
+			else 
+			{
+				line[line_position ++] = *ptr;
+			}
+
+			if (line_position >= textview->line_width - 1)
+			{
+				line_index ++;
+				line_position = 0;
+				line = _get_line_text(textview, line_index);
+			}
+		}
+
+		ptr ++;
+	}
+
+	textview->line_current = 0;
+}
+
+static void _calc_width(rtgui_textview_t *textview)
+{
+	rtgui_rect_t rect;
+	rt_uint16_t width, height;
+
+	width = rtgui_rect_width(RTGUI_WIDGET(textview)->extent) - 6;
+	height = rtgui_rect_height(RTGUI_WIDGET(textview)->extent);
+
+	rtgui_font_get_metrics(RTGUI_WIDGET_FONT(RTGUI_WIDGET(textview)), "W", &rect);
+	textview->line_width = width / rtgui_rect_width(rect) + 1;
+	textview->line_page_count = height / (rtgui_rect_height(rect) + 3);
+
+	/* set minimal value */
+	if (textview->line_page_count == 0) textview->line_page_count = 1;
+}
+
+static void _draw_textview(rtgui_textview_t *textview)
+{
+	struct rtgui_dc* dc;
+	struct rtgui_rect rect, font_rect;
+	char* line;
+	rt_ubase_t line_index, item_height;
+
+	rtgui_font_get_metrics(RTGUI_WIDGET_FONT(RTGUI_WIDGET(textview)), "W", &font_rect);
+	item_height = rtgui_rect_height(font_rect) + 3;
+
+	dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(textview));
+	if (dc == RT_NULL) return ;
+
+	/* fill rect */
+	rtgui_widget_get_rect(RTGUI_WIDGET(textview), &rect);
+	rtgui_dc_fill_rect(dc, &rect);
+
+	rect.x1 += 3;
+	rect.x2 -= 3;
+
+	for (line_index = textview->line_current; 
+		(line_index < textview->line_current + textview->line_page_count) &&
+		(line_index < textview->line_count); 
+		line_index ++)
+	{
+		line = (char* )_get_line_text(textview, line_index);
+		rtgui_dc_draw_text(dc, line, &rect);
+
+		rect.y1 += item_height;
+	}
+
+	rtgui_dc_end_drawing(dc);
+}
+
+static void _rtgui_textview_constructor(rtgui_textview_t *textview)
+{
+	/* init widget and set event handler */
+	rtgui_widget_set_event_handler(RTGUI_WIDGET(textview), rtgui_textview_event_handler);
+	RTGUI_WIDGET(textview)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
+
+	/* set field */
+	textview->line_count = 0;
+	textview->lines = RT_NULL;
+
+	textview->line_current = -1;
+	textview->line_page_count = 1;
+}
+
+static void _rtgui_textview_destructor(rtgui_textview_t *textview)
+{
+	/* release line memory */
+	rt_free(textview->lines);
+	textview->lines = RT_NULL;
+}
+
+DEFINE_CLASS_TYPE(textview, "textview", 
+	RTGUI_WIDGET_TYPE,
+	_rtgui_textview_constructor,
+	_rtgui_textview_destructor,
+	sizeof(struct rtgui_textview));
+
+rt_bool_t rtgui_textview_event_handler(struct rtgui_widget* widget, struct rtgui_event* event)
+{
+	struct rtgui_textview* textview;
+
+	RT_ASSERT(widget != RT_NULL);
+
+	textview = (struct rtgui_textview*) widget;
+	switch (event->type)
+	{
+	case RTGUI_EVENT_PAINT:
+		_draw_textview(textview);
+		break;
+	
+	case RTGUI_EVENT_KBD:
+		{
+		struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
+		if (ekbd->type == RTGUI_KEYDOWN)
+		{
+			rt_int16_t line_current_update;
+			line_current_update = textview->line_current;
+			if (ekbd->key == RTGUIK_LEFT)
+			{
+				if (textview->line_current > textview->line_page_count)
+				{
+					line_current_update -= textview->line_page_count;
+				}
+				else if (textview->line_current > 0)
+				{
+					line_current_update = 0;
+				}
+			}
+			else if (ekbd->key == RTGUIK_RIGHT)
+			{
+				if (textview->line_current + textview->line_page_count < textview->line_count - 1)
+				{
+					line_current_update += textview->line_page_count;
+				}
+			}
+			else if (ekbd->key == RTGUIK_UP)
+			{
+				if (textview->line_current > 0)
+				{
+					line_current_update --;
+				}
+			}
+			else if (ekbd->key == RTGUIK_DOWN)
+			{
+				if (textview->line_current + textview->line_page_count < textview->line_count - 1)
+				{
+					line_current_update ++;
+				}
+			}
+
+			if (textview->line_current != line_current_update)
+			{
+				textview->line_current = line_current_update;
+				rtgui_widget_update(widget);
+				return RT_TRUE;
+			}
+		}
+		break;
+		}
+	}
+
+	return RT_FALSE;
+}
+
+rtgui_textview_t* rtgui_textview_create(const char* text, const rtgui_rect_t *rect)
+{
+    struct rtgui_textview* textview;
+
+    textview = (struct rtgui_textview*) rtgui_widget_create(RTGUI_TEXTVIEW_TYPE);
+    if (textview != RT_NULL)
+    {
+		rtgui_widget_set_rect(RTGUI_WIDGET(textview), rect);
+
+		/* calculate line width and line page count */
+		_calc_width(textview);
+
+		/* set text */
+		_calc_line(textview, text);
+    }
+
+    return textview;
+}
+
+void rtgui_textview_destroy(rtgui_textview_t* textview)
+{
+	rtgui_widget_destroy(RTGUI_WIDGET(textview));
+}
+
+void rtgui_textview_set_text(rtgui_textview_t* textview, const char* text)
+{
+	RT_ASSERT(textview != RT_NULL);
+
+	/* calculate line width and line page count */
+	_calc_width(textview);
+
+	/* set text */
+	_calc_line(textview, text);
+
+	/* update widget */
+	rtgui_widget_update(RTGUI_WIDGET(textview));
+}