/src/ftk_list_render_default.c

http://ftk.googlecode.com/ · C · 356 lines · 278 code · 44 blank · 34 comment · 59 complexity · 3cc8fb4928adecd22fdcc70a0616a8b0 MD5 · raw file

  1. /*
  2. * File: ftk_list_render_default.h
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: default list render
  5. *
  6. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  7. *
  8. * Licensed under the Academic Free License version 2.1
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. /*
  25. * History:
  26. * ================================================================
  27. * 2009-11-28 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "ftk_log.h"
  31. #include "ftk_util.h"
  32. #include "ftk_globals.h"
  33. #include "ftk_icon_cache.h"
  34. #include "ftk_source_timer.h"
  35. #include "ftk_list_model_default.h"
  36. #include "ftk_list_render_default.h"
  37. #define MARQUEE_MOVE_INTERVAL 200
  38. #define MARQUEE_PAUSE_INTERVAL 2000
  39. typedef enum _RenderMarqueeState
  40. {
  41. MARQUEE_NONE,
  42. MARQUEE_BEGIN,
  43. MARQUEE_MOVE,
  44. MARQUEE_PAUSE,
  45. MARQUEE_END
  46. }RenderMarqueeState;
  47. typedef struct _ListRenderDefaultPrivInfo
  48. {
  49. FtkBitmap* more;
  50. FtkBitmap* radio_off;
  51. FtkBitmap* radio_on;
  52. FtkBitmap* check_off;
  53. FtkBitmap* check_on;
  54. FtkBitmap* bg_disable;
  55. FtkListModel* model;
  56. FtkWidget* list_view;
  57. int focus_item;
  58. int times_to_move;
  59. int visible_start;
  60. int marquee_width;
  61. int marquee_paint_times;
  62. int marquee_cycle_times;
  63. FtkMarqueeAttr marquee_attr;
  64. FtkSource* marquee_timer;
  65. RenderMarqueeState marquee_state;
  66. }PrivInfo;
  67. static Ret ftk_list_render_default_init(FtkListRender* thiz, FtkListModel* model, FtkWidget* list_view)
  68. {
  69. DECL_PRIV(thiz, priv);
  70. return_val_if_fail(priv != NULL && model != NULL, RET_FAIL);
  71. priv->model = model;
  72. priv->list_view = list_view;
  73. return RET_OK;
  74. }
  75. static Ret marquee_timer_func(void* ctx)
  76. {
  77. FtkListRender* thiz = (FtkListRender*)ctx;
  78. DECL_PRIV(thiz, priv);
  79. FtkWidget* list_view = priv->list_view;
  80. if(priv->marquee_state == MARQUEE_NONE)
  81. {
  82. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_PAUSE_INTERVAL);
  83. return RET_OK;
  84. }
  85. priv->visible_start++;
  86. switch(priv->marquee_state)
  87. {
  88. case MARQUEE_BEGIN:
  89. {
  90. priv->visible_start = 0;
  91. priv->marquee_paint_times = 0;
  92. priv->marquee_state = MARQUEE_MOVE;
  93. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_PAUSE_INTERVAL);
  94. break;
  95. }
  96. case MARQUEE_MOVE:
  97. {
  98. if(priv->marquee_paint_times == 0)
  99. {
  100. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_MOVE_INTERVAL);
  101. }
  102. if(priv->marquee_paint_times < priv->times_to_move)
  103. {
  104. priv->marquee_paint_times++;
  105. }
  106. else
  107. {
  108. priv->marquee_state = MARQUEE_PAUSE;
  109. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_PAUSE_INTERVAL);
  110. }
  111. break;
  112. }
  113. case MARQUEE_PAUSE:
  114. {
  115. priv->marquee_paint_times = 0;
  116. priv->marquee_state = MARQUEE_MOVE;
  117. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_MOVE_INTERVAL);
  118. break;
  119. }
  120. case MARQUEE_END:
  121. {
  122. priv->visible_start = 0;
  123. priv->marquee_cycle_times++;
  124. priv->marquee_paint_times = 0;
  125. priv->marquee_state = MARQUEE_BEGIN;
  126. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_PAUSE_INTERVAL);
  127. break;
  128. }
  129. default:break;
  130. }
  131. //ftk_logd("%s: state=%d paint_times=%d cycle_times=%d vstart=%d\n", __func__,
  132. // priv->marquee_state, priv->marquee_paint_times, priv->marquee_cycle_times,
  133. // priv->visible_start);
  134. ftk_list_view_repaint_focus_item(list_view);
  135. return RET_OK;
  136. }
  137. static Ret ftk_list_render_default_focus_check(FtkListRender* thiz)
  138. {
  139. DECL_PRIV(thiz, priv);
  140. int focus_item = ftk_list_view_get_selected(priv->list_view);
  141. if(focus_item != priv->focus_item && priv->marquee_timer != 0)
  142. {
  143. priv->visible_start = 0;
  144. priv->focus_item = focus_item;
  145. priv->marquee_paint_times = 0;
  146. priv->marquee_cycle_times = 0;
  147. priv->times_to_move = priv->marquee_width/16;
  148. priv->marquee_state = MARQUEE_BEGIN;
  149. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_PAUSE_INTERVAL);
  150. }
  151. return RET_OK;
  152. }
  153. static Ret ftk_list_render_default_paint(FtkListRender* thiz, FtkCanvas* canvas, int pos, int x, int y, int w, int h)
  154. {
  155. int dx = 0;
  156. int dy = 0;
  157. DECL_PRIV(thiz, priv);
  158. FtkBitmap* right_icon = NULL;
  159. FtkListItemInfo* info = NULL;
  160. return_val_if_fail(thiz != NULL && canvas != NULL && w > 0 && h > 0, RET_FAIL);
  161. ftk_list_model_get_data(priv->model, pos, (void**)&info);
  162. return_val_if_fail(info != NULL, RET_FAIL);
  163. if(info->disable)
  164. {
  165. ftk_canvas_draw_bg_image(canvas, priv->bg_disable, FTK_BG_FOUR_CORNER, x, y, w, h);
  166. }
  167. if(info->left_icon != NULL)
  168. {
  169. ftk_canvas_draw_bg_image(canvas, info->left_icon, FTK_BG_CENTER, x, y, h, h);
  170. }
  171. switch(info->type)
  172. {
  173. case FTK_LIST_ITEM_RADIO:
  174. {
  175. right_icon = info->state ? priv->radio_on : priv->radio_off;
  176. break;
  177. }
  178. case FTK_LIST_ITEM_CHECK:
  179. {
  180. right_icon = info->state ? priv->check_on : priv->check_off;
  181. break;
  182. }
  183. case FTK_LIST_ITEM_MORE:
  184. {
  185. right_icon = priv->more;
  186. break;
  187. }
  188. default:
  189. {
  190. right_icon = info->right_icon;
  191. break;
  192. }
  193. }
  194. if(right_icon != NULL)
  195. {
  196. ftk_canvas_draw_bg_image(canvas, right_icon, FTK_BG_CENTER, x+w-h, y, h, h);
  197. }
  198. if(info->text != NULL)
  199. {
  200. int text_width = w;
  201. int visible_start = 0;
  202. FtkTextLine line = {0};
  203. const char* text = NULL;
  204. FtkTextLayout* text_layout = ftk_default_text_layout();
  205. text_width = info->left_icon != NULL ? text_width - h : text_width;
  206. text_width = right_icon != NULL ? text_width - h : text_width;
  207. dy = y + FTK_HALF(h);
  208. dx = FTK_H_MARGIN + (info->left_icon != NULL ? x + h : x);
  209. priv->marquee_width = text_width;
  210. ftk_list_render_default_focus_check(thiz);
  211. ftk_text_layout_init(text_layout, info->text, -1, canvas, text_width);
  212. ftk_text_layout_get_visual_line(text_layout, &line);
  213. do
  214. {
  215. visible_start = 0;
  216. if(priv->marquee_attr == 0 || pos != priv->focus_item)
  217. {
  218. break;
  219. }
  220. else if(!(priv->marquee_attr & FTK_MARQUEE_RIGHT2LEFT))
  221. {
  222. /*NOT support down to up scroll yet.*/
  223. break;
  224. }
  225. else if(!(priv->marquee_attr & FTK_MARQUEE_AUTO))
  226. {
  227. /*IF text is short dont scroll it.*/
  228. break;
  229. }
  230. else if((priv->marquee_attr & FTK_MARQUEE_ONCE) && (priv->marquee_cycle_times) > 0)
  231. {
  232. break;
  233. }
  234. else if((priv->marquee_attr & FTK_MARQUEE_AUTO) && (line.len == strlen(info->text)))
  235. {
  236. priv->marquee_state = MARQUEE_NONE;
  237. break;
  238. }
  239. if(priv->marquee_state == MARQUEE_NONE)
  240. {
  241. priv->marquee_state = MARQUEE_BEGIN;
  242. }
  243. visible_start = priv->visible_start;
  244. ftk_text_layout_init(text_layout, utf8_move_forward(info->text, visible_start),
  245. -1, canvas, text_width);
  246. ftk_text_layout_get_visual_line(text_layout, &line);
  247. if((line.extent + 20) < text_width)
  248. {
  249. priv->marquee_state = MARQUEE_END;
  250. ftk_source_timer_modify(priv->marquee_timer, MARQUEE_PAUSE_INTERVAL);
  251. }
  252. }while(0);
  253. text = utf8_move_forward(info->text, visible_start);
  254. ftk_text_layout_init(text_layout, text, -1, canvas, text_width);
  255. if(ftk_text_layout_get_visual_line(text_layout, &line) == RET_OK)
  256. {
  257. ftk_canvas_draw_string(canvas, dx + line.xoffset, dy, line.text, line.len, 1);
  258. }
  259. }
  260. return RET_OK;
  261. }
  262. static void ftk_list_render_default_destroy(FtkListRender* thiz)
  263. {
  264. if(thiz != NULL)
  265. {
  266. DECL_PRIV(thiz, priv);
  267. ftk_bitmap_unref(priv->radio_on);
  268. ftk_bitmap_unref(priv->radio_off);
  269. ftk_bitmap_unref(priv->check_on);
  270. ftk_bitmap_unref(priv->check_off);
  271. ftk_bitmap_unref(priv->more);
  272. ftk_bitmap_unref(priv->bg_disable);
  273. if(priv->marquee_timer != NULL)
  274. {
  275. ftk_source_disable(priv->marquee_timer);
  276. ftk_main_loop_remove_source(ftk_default_main_loop(), priv->marquee_timer);
  277. }
  278. FTK_ZFREE(thiz, sizeof(FtkListRender) + sizeof(PrivInfo));
  279. }
  280. return;
  281. }
  282. FtkListRender* ftk_list_render_default_create(void)
  283. {
  284. FtkListRender* thiz = FTK_NEW_PRIV(FtkListRender);
  285. if(thiz != NULL)
  286. {
  287. DECL_PRIV(thiz, priv);
  288. thiz->init = ftk_list_render_default_init;
  289. thiz->paint = ftk_list_render_default_paint;
  290. thiz->destroy = ftk_list_render_default_destroy;
  291. priv->focus_item = -1;
  292. priv->radio_off = ftk_theme_load_image(ftk_default_theme(), "btn_radio_off"FTK_STOCK_IMG_SUFFIX);
  293. priv->radio_on = ftk_theme_load_image(ftk_default_theme(), "btn_radio_on"FTK_STOCK_IMG_SUFFIX);
  294. priv->check_off = ftk_theme_load_image(ftk_default_theme(), "btn_check_off"FTK_STOCK_IMG_SUFFIX);
  295. priv->check_on = ftk_theme_load_image(ftk_default_theme(), "btn_check_on"FTK_STOCK_IMG_SUFFIX);
  296. priv->more = ftk_theme_load_image(ftk_default_theme(), "more"FTK_STOCK_IMG_SUFFIX);
  297. priv->bg_disable = ftk_theme_load_image(ftk_default_theme(), "list_selector_background_disabled"FTK_STOCK_IMG_SUFFIX);
  298. }
  299. return thiz;
  300. }
  301. Ret ftk_list_render_default_set_marquee_attr(FtkListRender* thiz, FtkMarqueeAttr marquee_attr)
  302. {
  303. DECL_PRIV(thiz, priv);
  304. return_val_if_fail(thiz != NULL, RET_FAIL);
  305. priv->marquee_attr = marquee_attr;
  306. if(priv->marquee_timer == NULL)
  307. {
  308. priv->marquee_timer = ftk_source_timer_create(MARQUEE_MOVE_INTERVAL, marquee_timer_func, thiz);
  309. ftk_main_loop_add_source(ftk_default_main_loop(), priv->marquee_timer);
  310. }
  311. return RET_OK;
  312. }