textbox.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /*
  2. * File : textbox.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2009, 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. * 2009-10-16 Bernard first version
  13. */
  14. #include <rtgui/rtgui.h>
  15. #include <rtgui/dc.h>
  16. #include <rtgui/rtgui_theme.h>
  17. #include <rtgui/rtgui_system.h>
  18. #include <rtgui/widgets/textbox.h>
  19. #include <rtgui/widgets/widget.h>
  20. #include <ctype.h>
  21. static void rtgui_textbox_timeout(rtgui_timer_t* timer, void* parameter);
  22. static rt_bool_t rtgui_textbox_onkey(PVOID wdt, rtgui_event_t* event);
  23. static rt_bool_t rtgui_textbox_onfocus(PVOID wdt, rtgui_event_t* event);
  24. static rt_bool_t rtgui_textbox_onunfocus(PVOID wdt, rtgui_event_t* event);
  25. void _rtgui_textbox_constructor(rtgui_textbox_t *box)
  26. {
  27. rtgui_rect_t rect;
  28. RTGUI_WIDGET_FLAG(box) |= RTGUI_WIDGET_FLAG_FOCUSABLE;
  29. rtgui_widget_set_event_handler(box, rtgui_textbox_event_handler);
  30. rtgui_widget_set_onfocus(box, rtgui_textbox_onfocus);
  31. rtgui_widget_set_onunfocus(box, rtgui_textbox_onunfocus);
  32. rtgui_widget_set_onkey(box,rtgui_textbox_onkey);
  33. RTGUI_WIDGET_BACKGROUND(box) = white;
  34. /* set default text align */
  35. RTGUI_WIDGET_TEXTALIGN(box) = RTGUI_ALIGN_CENTER_VERTICAL;
  36. rtgui_widget_set_style(box, RTGUI_BORDER_SUNKEN);
  37. /* set proper of control 创建一个周期型的控制定时器*/
  38. box->caret_timer = rtgui_timer_create(100, RT_TIMER_FLAG_PERIODIC,rtgui_textbox_timeout, box);
  39. //初始化...当前行,开始行,在当前行中的位置
  40. box->line = box->line_begin = box->position = 0;
  41. box->flag = RTGUI_TEXTBOX_NONE; //单行(默认)
  42. box->isedit = RT_TRUE;//默认是可以编辑的
  43. /* allocate default line buffer 分配默认的行缓存 */
  44. box->text = RT_NULL;
  45. rtgui_font_get_string_rect(RTGUI_WIDGET_FONT(box), "h", &rect);
  46. box->font_width = rtgui_rect_width(rect);
  47. box->on_change = RT_NULL;
  48. box->on_enter = RT_NULL;
  49. }
  50. void _rtgui_textbox_deconstructor(rtgui_textbox_t *textbox)
  51. {
  52. if(textbox->text != RT_NULL)
  53. {
  54. rt_free(textbox->text);
  55. textbox->text = RT_NULL;
  56. }
  57. if(textbox->caret_timer != RT_NULL)
  58. rtgui_timer_destory(textbox->caret_timer);
  59. textbox->caret_timer = RT_NULL;
  60. }
  61. rtgui_type_t *rtgui_textbox_type_get(void)
  62. {
  63. static rtgui_type_t *textbox_type = RT_NULL;
  64. if(!textbox_type)
  65. {
  66. textbox_type = rtgui_type_create("textbox", RTGUI_WIDGET_TYPE,
  67. sizeof(rtgui_textbox_t),
  68. RTGUI_CONSTRUCTOR(_rtgui_textbox_constructor),
  69. RTGUI_DESTRUCTOR(_rtgui_textbox_deconstructor));
  70. }
  71. return textbox_type;
  72. }
  73. //#include <rthw.h>
  74. //绘制编辑块光标
  75. void rtgui_textbox_draw_caret(rtgui_textbox_t* box, rt_uint16_t position)
  76. {
  77. int x,y;
  78. // rtgui_color_t color;
  79. rtgui_rect_t rect;
  80. int font_h,box_h;
  81. rtgui_dc_t *dc;
  82. RT_ASSERT(box != RT_NULL);
  83. dc = rtgui_dc_begin_drawing(box);
  84. if(dc == RT_NULL)return;
  85. rtgui_widget_get_rect(box, &rect);
  86. font_h = rtgui_font_get_font_height(RTGUI_WIDGET_FONT(box));
  87. box_h = rtgui_rect_height(rect);
  88. rect.x1 += position * box->font_width+2;
  89. rect.x2 = rect.x1+2;
  90. rect.y1 += (box_h-font_h)/2;
  91. rect.y2 = rect.y1 + font_h;
  92. for(x=rect.x1;x<rect.x2;x++)
  93. {
  94. for(y=rect.y1;y<rect.y2;y++)
  95. {
  96. // rt_hw_lcd_get_pixel(color,x,y);
  97. // color ^= white;
  98. // rtgui_dc_draw_point(box, color,x,y);
  99. if(box->flag & RTGUI_TEXTBOX_CARET_SHOW)
  100. {
  101. RTGUI_DC_FC(dc) = black;
  102. rtgui_dc_draw_point(dc, x,y);
  103. }
  104. else
  105. {
  106. RTGUI_DC_FC(dc) = white;
  107. rtgui_dc_draw_point(dc, x,y);
  108. }
  109. }
  110. }
  111. rtgui_dc_end_drawing(dc);
  112. }
  113. static void rtgui_textbox_timeout(rtgui_timer_t* timer, void* parameter)
  114. {
  115. rtgui_textbox_t* box;
  116. box = (rtgui_textbox_t*)parameter;
  117. /* set caret flag */
  118. if(box->flag & RTGUI_TEXTBOX_CARET_SHOW)
  119. box->flag &= ~RTGUI_TEXTBOX_CARET_SHOW;
  120. else
  121. box->flag |= RTGUI_TEXTBOX_CARET_SHOW;
  122. rtgui_textbox_draw_caret(box,box->position);
  123. return ;
  124. }
  125. static void rtgui_textbox_onmouse(rtgui_textbox_t* box, rtgui_event_mouse_t* event)
  126. {
  127. rt_size_t length;
  128. rt_uint16_t posbak = box->position;
  129. RT_ASSERT(box != RT_NULL);
  130. RT_ASSERT(event != RT_NULL);
  131. if(box->isedit == RT_FALSE)return;
  132. length = rt_strlen(box->text);
  133. if(event->button & RTGUI_MOUSE_BUTTON_LEFT && event->button & RTGUI_MOUSE_BUTTON_DOWN)
  134. {
  135. rt_int32_t x;
  136. if(!box->isedit)return;
  137. if(box->flag & RTGUI_TEXTBOX_MULTI)
  138. {//多行文本
  139. /* set widget focus */
  140. rtgui_widget_focus(box);
  141. //add codes at here.
  142. //...
  143. box->position = 0;
  144. box->flag |= RTGUI_TEXTBOX_CARET_SHOW;
  145. rtgui_textbox_draw_caret(box,box->position);
  146. }
  147. else
  148. {//单行文本
  149. /* set caret position */
  150. x = event->x - RTGUI_WIDGET(box)->extent.x1;
  151. if(x < 0)
  152. {
  153. box->position = 0;
  154. }
  155. else if(x > length * box->font_width)
  156. {
  157. box->position = length;
  158. }
  159. else
  160. {
  161. box->position = x / box->font_width;
  162. }
  163. //改变了位置,如果上一个位置显示了编辑框光标,则清除之.
  164. if(box->flag & RTGUI_TEXTBOX_CARET_SHOW)
  165. {
  166. rtgui_timer_stop(box->caret_timer);
  167. box->flag &= ~RTGUI_TEXTBOX_CARET_SHOW;
  168. rtgui_textbox_draw_caret(box, posbak);//先刷新以下编辑块光标,如果是显示状态
  169. rtgui_timer_start(box->caret_timer);
  170. }
  171. /* set widget focus */
  172. rtgui_widget_focus(box);
  173. /* draw caret 绘制编辑块光标 */
  174. rtgui_textbox_draw_caret(box,box->position);
  175. }
  176. }
  177. }
  178. static rt_bool_t rtgui_textbox_onkey(PVOID wdt, rtgui_event_t* event)
  179. {
  180. rtgui_textbox_t* box = (rtgui_textbox_t*)wdt;
  181. rtgui_event_kbd_t* ekbd = (rtgui_event_kbd_t*)event;
  182. rt_size_t length;
  183. rt_uint16_t posbak = box->position;
  184. RT_ASSERT(box != RT_NULL);
  185. RT_ASSERT(ekbd != RT_NULL);
  186. length = rt_strlen(box->text);
  187. if(ekbd->key == RTGUIK_DELETE)
  188. {//删除光标后面的字符
  189. if(box->position == length - 1)
  190. {
  191. box->text[box->position] = '\0';
  192. }
  193. else
  194. {
  195. char *c;
  196. /* remove character */
  197. for(c = &box->text[box->position]; c[1] != '\0'; c++)
  198. *c = c[1];
  199. *c = '\0';
  200. }
  201. if(box->on_change)box->on_change(box,RT_NULL);
  202. }
  203. else if(ekbd->key == RTGUIK_BACKSPACE)
  204. {//删除光标前面的字符
  205. if(box->position == length - 1)
  206. {
  207. box->text[box->position] = '\0';
  208. box->position --;
  209. }
  210. else if(box->position != 0)
  211. {
  212. /* remove current character */
  213. if(box->position != 0)
  214. {
  215. char *c;
  216. /* remove character */
  217. for(c = &box->text[box->position - 1]; c[1] != '\0'; c++)
  218. *c = c[1];
  219. *c = '\0';
  220. }
  221. box->position --;
  222. }
  223. if(box->on_change)box->on_change(box,RT_NULL);
  224. }
  225. else if(ekbd->key == RTGUIK_LEFT)
  226. {//光标向左移动一个字符位
  227. if(box->position > 0)
  228. {
  229. box->position --;
  230. }
  231. }
  232. else if(ekbd->key == RTGUIK_RIGHT)
  233. {//光标向右移动一个字符位
  234. if(box->position < length)
  235. {
  236. box->position ++;
  237. }
  238. }
  239. else if(ekbd->key == RTGUIK_HOME)
  240. {//光标移动到串首
  241. box->position = 0;
  242. }
  243. else if(ekbd->key == RTGUIK_END)
  244. {//光标移动到串尾
  245. box->position = length;
  246. }
  247. else if(ekbd->key == RTGUIK_RETURN)
  248. {
  249. if(box->on_enter != RT_NULL)
  250. {
  251. box->on_enter(box, RT_NULL);
  252. }
  253. }
  254. else if(ekbd->key == RTGUIK_NUMLOCK)//数字键有效
  255. {
  256. /* change numlock state */
  257. }
  258. else
  259. {
  260. if(isprint(ekbd->key))
  261. {//是可打印字符或数字
  262. /* no buffer on this line */
  263. if(box->flag & RTGUI_TEXTBOX_DIGIT)
  264. {//输入限制为数字
  265. if(!isdigit(ekbd->key))
  266. {//允许'.'和'-'
  267. if(ekbd->key != '.' && ekbd->key !='-')return RT_FALSE;
  268. if(ekbd->key == '.' && strchr(box->text,'.'))return RT_FALSE;
  269. if(ekbd->key == '-')
  270. {//在数字模式下,单独处理符号
  271. if(length+1 > box->line_length) return RT_FALSE;
  272. if(length+1 > box->dis_length) return RT_FALSE;
  273. if(strchr(box->text,'-'))
  274. {//当前已经置为负号
  275. char* c;
  276. for(c = &box->text[0]; c != &box->text[length]; c++)
  277. *c = *(c+1);
  278. box->text[length] = '\0';
  279. box->position --;
  280. goto _exit;
  281. }
  282. else
  283. {
  284. char* c;
  285. for(c = &box->text[length]; c != &box->text[0]; c--)
  286. *c = *(c-1);
  287. box->text[0] = '-';
  288. box->text[length+1] = '\0';
  289. box->position ++;
  290. goto _exit;
  291. }
  292. }
  293. }
  294. //rt_kprintf("%c ",ekbd->key);//debug printf
  295. }
  296. if(length+1 > box->line_length) return RT_FALSE;
  297. if(length+1 > box->dis_length) return RT_FALSE;
  298. if(box->position <= length-1)
  299. {
  300. char* c;
  301. for(c = &box->text[length]; c != &box->text[box->position]; c--)
  302. *c = *(c-1);
  303. box->text[length+1] = '\0';
  304. }
  305. box->text[box->position] = ekbd->key;
  306. box->position ++;
  307. if(box->on_change)box->on_change(box,RT_NULL);
  308. }
  309. }
  310. _exit:
  311. //改变了位置,如果上一个位置显示了编辑框光标,则清除之.
  312. if(box->flag & RTGUI_TEXTBOX_CARET_SHOW)
  313. {
  314. rtgui_timer_stop(box->caret_timer);
  315. box->flag &= ~RTGUI_TEXTBOX_CARET_SHOW;
  316. rtgui_textbox_draw_caret(box, posbak);//先刷新一下编辑块光标,如果是显示状态
  317. rtgui_timer_start(box->caret_timer);
  318. }
  319. /* set widget focus */
  320. rtgui_widget_focus(box);
  321. /* set caret to show */
  322. box->flag |= RTGUI_TEXTBOX_CARET_SHOW;
  323. /* re-draw text box */
  324. rtgui_theme_draw_textbox(box);
  325. /* draw caret 绘制编辑块光标 */
  326. rtgui_textbox_draw_caret(box,box->position);
  327. return RT_TRUE;
  328. }
  329. static rt_bool_t rtgui_textbox_onfocus(PVOID wdt, rtgui_event_t* event)
  330. {
  331. rtgui_widget_t *widget = (rtgui_widget_t*)wdt;
  332. rtgui_textbox_t* box = (rtgui_textbox_t*)widget;
  333. /* set caret to show */
  334. box->flag |= RTGUI_TEXTBOX_CARET_SHOW;//编辑块光标
  335. /* start caret timer */
  336. rtgui_timer_start(box->caret_timer);
  337. return RT_TRUE;
  338. }
  339. static rt_bool_t rtgui_textbox_onunfocus(PVOID wdt, rtgui_event_t* event)
  340. {
  341. rtgui_widget_t *widget = (rtgui_widget_t*)wdt;
  342. rtgui_textbox_t* box = (rtgui_textbox_t*)widget;
  343. /* stop caret timer */
  344. rtgui_timer_stop(box->caret_timer);
  345. /* set caret to hide */
  346. box->flag &= ~RTGUI_TEXTBOX_CARET_SHOW;
  347. rtgui_textbox_draw_caret(box,box->position);
  348. if(box->on_enter)box->on_enter(box,event);
  349. rtgui_theme_draw_textbox(box);
  350. return RT_TRUE;
  351. }
  352. rt_bool_t rtgui_textbox_event_handler(PVOID wdt, rtgui_event_t* event)
  353. {
  354. rtgui_widget_t *widget = (rtgui_widget_t*)wdt;
  355. rtgui_textbox_t* box = (rtgui_textbox_t*)widget;
  356. switch (event->type)
  357. {
  358. case RTGUI_EVENT_PAINT:
  359. if(widget->on_draw != RT_NULL) widget->on_draw(widget, event);
  360. else
  361. rtgui_theme_draw_textbox(box);
  362. break;
  363. case RTGUI_EVENT_MOUSE_BUTTON:
  364. if(widget->on_mouseclick != RT_NULL) widget->on_mouseclick(widget, event);
  365. else
  366. rtgui_textbox_onmouse(box, (rtgui_event_mouse_t*)event);
  367. return RT_TRUE;
  368. case RTGUI_EVENT_KBD:
  369. if(widget->on_key != RT_NULL)
  370. widget->on_key(widget, event);
  371. return RT_TRUE;
  372. default:
  373. return rtgui_widget_event_handler(widget,event);
  374. }
  375. return RT_FALSE;
  376. }
  377. rtgui_textbox_t* rtgui_textbox_create(PVOID parent,const char* text,int left,int top,int w,int h, rt_uint32_t flag)
  378. {
  379. rtgui_textbox_t* box;
  380. RT_ASSERT(parent != RT_NULL);
  381. box = rtgui_widget_create(RTGUI_TEXTBOX_TYPE);
  382. if(box != RT_NULL)
  383. {
  384. rtgui_rect_t rect;
  385. rtgui_widget_get_rect(parent, &rect);
  386. rtgui_widget_rect_to_device(parent,&rect);
  387. rect.x1 += left;
  388. rect.y1 += top;
  389. rect.x2 = rect.x1+w;
  390. rect.y2 = rect.y1+h;
  391. rtgui_widget_set_rect(box,&rect);
  392. /* allocate default line buffer */
  393. rtgui_textbox_set_value(box, text);
  394. box->flag = flag;
  395. //设定可显示字符数量
  396. box->dis_length = (w-5)/rtgui_font_get_font_width(RTGUI_WIDGET_FONT(box));
  397. rtgui_container_add_child(parent, box);
  398. }
  399. return box;
  400. }
  401. void rtgui_textbox_destroy(rtgui_textbox_t* box)
  402. {
  403. rtgui_widget_destroy(box);
  404. }
  405. //将一个文本串关联到一个textbox控件
  406. void rtgui_textbox_set_value(rtgui_textbox_t* box, const char* text)
  407. {
  408. if(box->text != RT_NULL)
  409. {//已经有内容
  410. /* free the old text */
  411. rt_free(box->text);
  412. box->text = RT_NULL;
  413. }
  414. //原先没有内容
  415. box->line_length = ((rt_strlen(text)+1)/RTGUI_TEXTBOX_LINE_MAX+1)*RTGUI_TEXTBOX_LINE_MAX;
  416. /* allocate line buffer */
  417. box->text = rt_malloc(box->line_length);
  418. rt_memset(box->text, 0, box->line_length);
  419. /* copy text */
  420. rt_memcpy(box->text, text, rt_strlen(text) + 1);
  421. /* set current position */
  422. box->position = rt_strlen(text);
  423. }
  424. const char* rtgui_textbox_get_value(rtgui_textbox_t* box)
  425. {
  426. return (const char*)box->text;
  427. }
  428. void rtgui_textbox_set_line_length(rtgui_textbox_t* box, rt_size_t length)
  429. {
  430. rt_uint8_t* new_line;
  431. RT_ASSERT(box != RT_NULL);
  432. /* invalid length */
  433. if(length <= 0) return;
  434. new_line = rt_malloc(length);
  435. if(length < box->line_length)
  436. {
  437. rt_memcpy(new_line, box->text, length - 1);
  438. new_line[length] = '\0';
  439. }
  440. else
  441. {
  442. rt_memcpy(new_line, (const char*)box->text, rt_strlen((const char*)box->text));
  443. }
  444. /* set line length */
  445. box->line_length = length;
  446. }
  447. //取得textbox控件的文本显示区域
  448. void rtgui_textbox_get_edit_rect(rtgui_textbox_t *box,rtgui_rect_t *rect)
  449. {
  450. rtgui_widget_get_rect(box, rect);
  451. rtgui_rect_inflate(rect,-1);
  452. }