textview.c 9.4 KB

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