textview.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * File : textview.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2011-03-05 Bernard first version
  13. */
  14. #include <rtgui/dc.h>
  15. #include <rtgui/rtgui_system.h>
  16. #include <rtgui/widgets/textview.h>
  17. rt_inline char* _get_line_text(rtgui_textview_t *textview, rt_uint16_t index)
  18. {
  19. char* line;
  20. if (index < textview->line_count)
  21. {
  22. line = textview->lines + (index * textview->line_width);
  23. return line;
  24. }
  25. return RT_NULL;
  26. }
  27. static void _calc_line(rtgui_textview_t *textview, const char* text)
  28. {
  29. char* line;
  30. const unsigned char* ptr;
  31. rt_ubase_t line_index, line_position;
  32. if (textview->lines != RT_NULL)
  33. {
  34. rt_free(textview->lines);
  35. textview->lines = RT_NULL;
  36. textview->line_count = 0;
  37. }
  38. /* get line count */
  39. line_index = 0; line_position = 0;
  40. ptr = (const unsigned char*)text;
  41. if (*ptr == 0) return;
  42. while (*ptr != '\0')
  43. {
  44. if (*ptr == '\n')
  45. {
  46. line_index ++;
  47. line_position = 0;
  48. }
  49. else if (*ptr == '\r')
  50. {
  51. ptr ++;
  52. continue;
  53. }
  54. else if (*ptr == '\t')
  55. {
  56. line_position += 4;
  57. if (line_position >= textview->line_width - 1)
  58. {
  59. line_index ++;
  60. line_position = 0;
  61. }
  62. }
  63. else
  64. {
  65. if ((*ptr) >= 0x80)
  66. {
  67. /* fill cjk character */
  68. if (line_position + 1 >= (textview->line_width - 1))
  69. {
  70. /* split to next line */
  71. line_index ++;
  72. line_position = 0;
  73. }
  74. line_position ++;
  75. line_position ++;
  76. }
  77. else
  78. {
  79. line_position ++;
  80. }
  81. if (line_position >= textview->line_width - 1)
  82. {
  83. line_index ++;
  84. line_position = 0;
  85. }
  86. }
  87. ptr ++;
  88. }
  89. /* set line count */
  90. textview->line_count = line_index + 1;
  91. /* allocate lines */
  92. textview->lines = rt_malloc(textview->line_count * textview->line_width);
  93. rt_memset(textview->lines, 0, (textview->line_count * textview->line_width));
  94. /* fill lines */
  95. line_index = 0; line_position = 0;
  96. ptr = (const unsigned char*)text;
  97. line = _get_line_text(textview, line_index);
  98. while (*ptr)
  99. {
  100. if (*ptr == '\n')
  101. {
  102. line_index ++;
  103. line_position = 0;
  104. line = _get_line_text(textview, line_index);
  105. }
  106. else if (*ptr == '\r')
  107. {
  108. /* ignore '\r' */
  109. ptr ++;
  110. continue;
  111. }
  112. else if (*ptr == '\t')
  113. {
  114. line[line_position++] = ' ';
  115. line[line_position++] = ' ';
  116. line[line_position++] = ' ';
  117. line[line_position++] = ' ';
  118. if (line_position >= textview->line_width - 1)
  119. {
  120. line_index ++;
  121. line_position = 0;
  122. line = _get_line_text(textview, line_index);
  123. }
  124. }
  125. else
  126. {
  127. if ((*ptr) >= 0x80)
  128. {
  129. /* fill cjk character */
  130. if (line_position + 1 >= (textview->line_width - 1))
  131. {
  132. /* split to next line */
  133. line_index ++;
  134. line_position = 0;
  135. line = _get_line_text(textview, line_index);
  136. }
  137. line[line_position ++] = *ptr ++;
  138. line[line_position ++] = *ptr;
  139. }
  140. else
  141. {
  142. line[line_position ++] = *ptr;
  143. }
  144. if (line_position >= textview->line_width - 1)
  145. {
  146. line_index ++;
  147. line_position = 0;
  148. line = _get_line_text(textview, line_index);
  149. }
  150. }
  151. ptr ++;
  152. }
  153. textview->line_current = 0;
  154. }
  155. static void _calc_width(rtgui_textview_t *textview)
  156. {
  157. rtgui_rect_t rect;
  158. rt_uint16_t width, height;
  159. width = rtgui_rect_width(RTGUI_WIDGET(textview)->extent) - 6;
  160. height = rtgui_rect_height(RTGUI_WIDGET(textview)->extent);
  161. rtgui_font_get_metrics(RTGUI_WIDGET_FONT(RTGUI_WIDGET(textview)), "W", &rect);
  162. textview->line_width = width / rtgui_rect_width(rect) + 1;
  163. textview->line_page_count = height / (rtgui_rect_height(rect) + 3);
  164. /* set minimal value */
  165. if (textview->line_page_count == 0) textview->line_page_count = 1;
  166. }
  167. static void _draw_textview(rtgui_textview_t *textview)
  168. {
  169. struct rtgui_dc* dc;
  170. struct rtgui_rect rect, font_rect;
  171. char* line;
  172. rt_ubase_t line_index, item_height;
  173. rtgui_font_get_metrics(RTGUI_WIDGET_FONT(RTGUI_WIDGET(textview)), "W", &font_rect);
  174. item_height = rtgui_rect_height(font_rect) + 3;
  175. dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(textview));
  176. if (dc == RT_NULL) return ;
  177. /* fill rect */
  178. rtgui_widget_get_rect(RTGUI_WIDGET(textview), &rect);
  179. rtgui_dc_fill_rect(dc, &rect);
  180. rect.x1 += 3;
  181. rect.x2 -= 3;
  182. for (line_index = textview->line_current;
  183. (line_index < textview->line_current + textview->line_page_count) &&
  184. (line_index < textview->line_count);
  185. line_index ++)
  186. {
  187. line = (char* )_get_line_text(textview, line_index);
  188. rtgui_dc_draw_text(dc, line, &rect);
  189. rect.y1 += item_height;
  190. }
  191. rtgui_dc_end_drawing(dc);
  192. }
  193. static void _rtgui_textview_constructor(rtgui_textview_t *textview)
  194. {
  195. /* init widget and set event handler */
  196. rtgui_widget_set_event_handler(RTGUI_WIDGET(textview), rtgui_textview_event_handler);
  197. RTGUI_WIDGET(textview)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
  198. /* set field */
  199. textview->line_count = 0;
  200. textview->lines = RT_NULL;
  201. textview->line_current = -1;
  202. textview->line_page_count = 1;
  203. }
  204. static void _rtgui_textview_destructor(rtgui_textview_t *textview)
  205. {
  206. /* release line memory */
  207. rt_free(textview->lines);
  208. textview->lines = RT_NULL;
  209. }
  210. DEFINE_CLASS_TYPE(textview, "textview",
  211. RTGUI_WIDGET_TYPE,
  212. _rtgui_textview_constructor,
  213. _rtgui_textview_destructor,
  214. sizeof(struct rtgui_textview));
  215. rt_bool_t rtgui_textview_event_handler(struct rtgui_widget* widget, struct rtgui_event* event)
  216. {
  217. struct rtgui_textview* textview;
  218. RT_ASSERT(widget != RT_NULL);
  219. textview = (struct rtgui_textview*) widget;
  220. switch (event->type)
  221. {
  222. case RTGUI_EVENT_PAINT:
  223. _draw_textview(textview);
  224. break;
  225. case RTGUI_EVENT_KBD:
  226. {
  227. struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
  228. if (ekbd->type == RTGUI_KEYDOWN)
  229. {
  230. rt_int16_t line_current_update;
  231. line_current_update = textview->line_current;
  232. if (ekbd->key == RTGUIK_LEFT)
  233. {
  234. if (textview->line_current > textview->line_page_count)
  235. {
  236. line_current_update -= textview->line_page_count;
  237. }
  238. else if (textview->line_current > 0)
  239. {
  240. line_current_update = 0;
  241. }
  242. }
  243. else if (ekbd->key == RTGUIK_RIGHT)
  244. {
  245. if (textview->line_current + textview->line_page_count < textview->line_count - 1)
  246. {
  247. line_current_update += textview->line_page_count;
  248. }
  249. }
  250. else if (ekbd->key == RTGUIK_UP)
  251. {
  252. if (textview->line_current > 0)
  253. {
  254. line_current_update --;
  255. }
  256. }
  257. else if (ekbd->key == RTGUIK_DOWN)
  258. {
  259. if (textview->line_current + textview->line_page_count < textview->line_count - 1)
  260. {
  261. line_current_update ++;
  262. }
  263. }
  264. if (textview->line_current != line_current_update)
  265. {
  266. textview->line_current = line_current_update;
  267. rtgui_widget_update(widget);
  268. return RT_TRUE;
  269. }
  270. }
  271. break;
  272. }
  273. }
  274. return RT_FALSE;
  275. }
  276. rtgui_textview_t* rtgui_textview_create(const char* text, const rtgui_rect_t *rect)
  277. {
  278. struct rtgui_textview* textview;
  279. textview = (struct rtgui_textview*) rtgui_widget_create(RTGUI_TEXTVIEW_TYPE);
  280. if (textview != RT_NULL)
  281. {
  282. rtgui_widget_set_rect(RTGUI_WIDGET(textview), rect);
  283. /* calculate line width and line page count */
  284. _calc_width(textview);
  285. /* set text */
  286. _calc_line(textview, text);
  287. }
  288. return textview;
  289. }
  290. void rtgui_textview_destroy(rtgui_textview_t* textview)
  291. {
  292. rtgui_widget_destroy(RTGUI_WIDGET(textview));
  293. }
  294. void rtgui_textview_set_text(rtgui_textview_t* textview, const char* text)
  295. {
  296. RT_ASSERT(textview != RT_NULL);
  297. /* calculate line width and line page count */
  298. _calc_width(textview);
  299. /* set text */
  300. _calc_line(textview, text);
  301. /* update widget */
  302. rtgui_widget_update(RTGUI_WIDGET(textview));
  303. }