/src/ftk_menu_panel.c

http://ftk.googlecode.com/ · C · 336 lines · 253 code · 50 blank · 33 comment · 56 complexity · 3c62955929ddea652e502410815e21b6 MD5 · raw file

  1. /*
  2. * File: ftk_menu_panel.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: ftk menu panel
  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-10-30 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "ftk_window.h"
  31. #include "ftk_globals.h"
  32. #include "ftk_menu_item.h"
  33. typedef struct _MenuPanelPrivInfo
  34. {
  35. int changed;
  36. int items_nr;
  37. FtkWidget* items[FTK_MENU_MAX_ITEM];
  38. FtkWidgetOnEvent parent_on_event;
  39. FtkWidgetOnPaint parent_on_paint;
  40. FtkWidgetDestroy parent_destroy;
  41. }PrivInfo;
  42. static int ftk_menu_panel_count_visible_items(FtkWidget* thiz)
  43. {
  44. int i = 0;
  45. int n = 0;
  46. DECL_PRIV1(thiz, priv);
  47. for(i = 0; i < priv->items_nr; i++)
  48. {
  49. if(ftk_widget_is_visible(priv->items[i]))
  50. {
  51. n++;
  52. }
  53. }
  54. return n;
  55. }
  56. static FtkRect* ftk_menu_panel_calc_rects(FtkWidget* thiz, int* nr)
  57. {
  58. int i = 0;
  59. int n = 0;
  60. int w = 0;
  61. FtkRect* rect = NULL;
  62. DECL_PRIV1(thiz, priv);
  63. int screen_width = ftk_display_width(ftk_default_display());
  64. int max_items_per_row = screen_width/FTK_MENU_ITEM_WIDTH;
  65. return_val_if_fail(priv->items_nr > 0, NULL);
  66. n = ftk_menu_panel_count_visible_items(thiz);
  67. return_val_if_fail(n > 0, NULL);
  68. n = n <= max_items_per_row * 2 ? n : max_items_per_row * 2;
  69. rect = (FtkRect*)FTK_ALLOC(sizeof(FtkRect) * n);
  70. return_val_if_fail(rect != NULL, NULL);
  71. *nr = n;
  72. if(n <= max_items_per_row)
  73. {
  74. w = screen_width/n;
  75. for(i = 0; i < n; i++)
  76. {
  77. rect[i].x = w * i;
  78. rect[i].y = 0;
  79. rect[i].width = w;
  80. rect[i].height = FTK_MENU_ITEM_HEIGHT;
  81. }
  82. }
  83. else
  84. {
  85. int first_row_nr = n/2;
  86. int second_row_nr = (n+1)/2;
  87. w = screen_width/first_row_nr;
  88. for(i = 0; i < first_row_nr; i++)
  89. {
  90. rect[i].x = w * i;
  91. rect[i].y = 0;
  92. rect[i].width = w;
  93. rect[i].height = FTK_MENU_ITEM_HEIGHT;
  94. }
  95. w = screen_width/second_row_nr;
  96. for(i = 0; i < second_row_nr; i++)
  97. {
  98. rect[first_row_nr + i].x = w * i;
  99. rect[first_row_nr + i].y = FTK_MENU_ITEM_HEIGHT;
  100. rect[first_row_nr + i].width = w;
  101. rect[first_row_nr + i].height = FTK_MENU_ITEM_HEIGHT;
  102. }
  103. }
  104. return rect;
  105. }
  106. Ret ftk_menu_panel_relayout(FtkWidget* thiz)
  107. {
  108. int i = 0;
  109. int j = 0;
  110. int nr = 0;
  111. int h = 0;
  112. DECL_PRIV1(thiz, priv);
  113. FtkRect* rects = ftk_menu_panel_calc_rects(thiz, &nr);
  114. int screen_height = ftk_display_height(ftk_default_display());
  115. int screen_width = ftk_display_width(ftk_default_display());
  116. int max_items_per_row = screen_width/FTK_MENU_ITEM_WIDTH;
  117. return_val_if_fail(priv->items_nr > 0 && rects != NULL && nr > 0, RET_FAIL);
  118. h = nr > max_items_per_row ? FTK_MENU_ITEM_HEIGHT * 2 : FTK_MENU_ITEM_HEIGHT;
  119. ftk_widget_move_resize(thiz, 0, screen_height - h, screen_width, h);
  120. /*relayout the items*/
  121. for(i = 0, j = 0; i < nr; j++)
  122. {
  123. if(ftk_widget_is_visible(priv->items[j]))
  124. {
  125. ftk_widget_move_resize(priv->items[j], rects[i].x, rects[i].y, rects[i].width, rects[i].height);
  126. i++;
  127. }
  128. }
  129. /*hide items that there is no space for them*/
  130. for(; j < priv->items_nr; j++)
  131. {
  132. ftk_widget_move_resize(priv->items[j], 0, 0, 0, 0);
  133. }
  134. FTK_FREE(rects);
  135. return RET_OK;
  136. }
  137. static Ret ftk_menu_panel_on_event(FtkWidget* thiz, FtkEvent* event)
  138. {
  139. Ret ret = RET_OK;
  140. DECL_PRIV1(thiz, priv);
  141. if(event->type == FTK_EVT_KEY_UP && event->u.key.code == FTK_KEY_MENU)
  142. {
  143. ftk_widget_unref(thiz);
  144. return ret;
  145. }
  146. if(event->type == FTK_EVT_SHOW)
  147. {
  148. ftk_wnd_manager_grab(ftk_default_wnd_manager(), thiz);
  149. }
  150. if(event->type == FTK_EVT_HIDE)
  151. {
  152. ftk_wnd_manager_ungrab(ftk_default_wnd_manager(), thiz);
  153. }
  154. if((event->type == FTK_EVT_MOUSE_UP && ret != RET_IGNORED)
  155. || (event->type == FTK_EVT_KEY_UP && FTK_IS_ACTIVE_KEY(event->u.key.code)))
  156. {
  157. ftk_widget_show(thiz, 0);
  158. }
  159. ret = priv->parent_on_event(thiz, event);
  160. if((event->type == FTK_EVT_MOUSE_UP && ret != RET_IGNORED)
  161. || (event->type == FTK_EVT_KEY_UP && FTK_IS_ACTIVE_KEY(event->u.key.code)))
  162. {
  163. ftk_widget_unref(thiz);
  164. }
  165. return ret;
  166. }
  167. static Ret ftk_menu_panel_on_paint(FtkWidget* thiz)
  168. {
  169. int i = 0;
  170. int w = 0;
  171. int nr = 0;
  172. int first_row_nr = 0;
  173. int second_row_nr = 0;
  174. FtkGc gc = {0};
  175. DECL_PRIV1(thiz, priv);
  176. int screen_width = ftk_display_width(ftk_default_display());
  177. int max_items_per_row = screen_width/FTK_MENU_ITEM_WIDTH;
  178. FTK_BEGIN_PAINT(x, y, width, height, canvas);
  179. return_val_if_fail(priv != NULL, RET_FAIL);
  180. return_val_if_fail(ftk_widget_is_visible(thiz), RET_FAIL);
  181. /*draw border*/
  182. gc.mask = FTK_GC_FG;
  183. gc.fg = ftk_theme_get_border_color(ftk_default_theme(), FTK_MENU_PANEL, ftk_widget_state(thiz));
  184. ftk_canvas_set_gc(canvas, &gc);
  185. ftk_canvas_draw_rect(canvas, x, y, width, height, 0, 0);
  186. ftk_canvas_draw_rect(canvas, x+1, y+1, width-2, height-2, 0, 0);
  187. /*draw grid*/
  188. gc.fg = ftk_widget_get_gc(thiz)->fg;
  189. ftk_canvas_set_gc(canvas, &gc);
  190. nr = ftk_menu_panel_count_visible_items(thiz);
  191. nr = nr <= max_items_per_row * 2 ? nr : max_items_per_row * 2;
  192. if(nr > max_items_per_row)
  193. {
  194. first_row_nr = nr/2;
  195. second_row_nr = (nr+1)/2;
  196. ftk_canvas_draw_hline(canvas, x, y+FTK_MENU_ITEM_HEIGHT, screen_width);
  197. }
  198. else
  199. {
  200. first_row_nr = nr;
  201. }
  202. if(first_row_nr > 0)
  203. {
  204. w = screen_width/first_row_nr;
  205. for(i = 1; i < first_row_nr; i++)
  206. {
  207. ftk_canvas_draw_vline(canvas, x+i*w, y, FTK_MENU_ITEM_HEIGHT);
  208. }
  209. }
  210. if(second_row_nr > 0)
  211. {
  212. w = screen_width/second_row_nr;
  213. for(i = 1; i < second_row_nr; i++)
  214. {
  215. ftk_canvas_draw_vline(canvas, x+i*w, y+FTK_MENU_ITEM_HEIGHT, FTK_MENU_ITEM_HEIGHT);
  216. }
  217. }
  218. priv->parent_on_paint(thiz);
  219. return RET_OK;
  220. }
  221. static void ftk_menu_panel_destroy(FtkWidget* thiz)
  222. {
  223. DECL_PRIV1(thiz, priv);
  224. FtkWidgetDestroy parent_destroy = priv->parent_destroy;
  225. parent_destroy(thiz);
  226. FTK_ZFREE(thiz->priv_subclass[1], sizeof(PrivInfo));
  227. return;
  228. }
  229. FtkWidget* ftk_menu_panel_create(void)
  230. {
  231. FtkWidget* thiz = ftk_window_create(FTK_MENU_PANEL, 0, 0, 0, 0, 0);
  232. return_val_if_fail(thiz != NULL, NULL);
  233. thiz->priv_subclass[1] = (PrivInfo*)FTK_ZALLOC(sizeof(PrivInfo));
  234. if(thiz->priv_subclass[1] != NULL)
  235. {
  236. DECL_PRIV1(thiz, priv);
  237. priv->parent_on_event = thiz->on_event;
  238. priv->parent_on_paint = thiz->on_paint;
  239. priv->parent_destroy = thiz->destroy;
  240. thiz->on_event = ftk_menu_panel_on_event;
  241. thiz->on_paint = ftk_menu_panel_on_paint;
  242. thiz->destroy = ftk_menu_panel_destroy;
  243. }
  244. else
  245. {
  246. ftk_widget_destroy(thiz);
  247. thiz = NULL;
  248. }
  249. return thiz;
  250. }
  251. Ret ftk_menu_panel_add(FtkWidget* thiz, FtkWidget* item)
  252. {
  253. DECL_PRIV1(thiz, priv);
  254. return_val_if_fail(thiz != NULL && item != NULL, RET_FAIL);
  255. return_val_if_fail(priv->items_nr < FTK_MENU_MAX_ITEM, RET_FAIL);
  256. priv->items[priv->items_nr++] = item;
  257. priv->changed = 1;
  258. ftk_widget_append_child(thiz, item);
  259. return RET_OK;
  260. }
  261. Ret ftk_menu_panel_remove(FtkWidget* thiz, FtkWidget* item)
  262. {
  263. int i = 0;
  264. Ret ret = RET_FAIL;
  265. DECL_PRIV1(thiz, priv);
  266. return_val_if_fail(thiz != NULL && item != NULL, RET_FAIL);
  267. for(i = 0; i < priv->items_nr; i++)
  268. {
  269. if(priv->items[i] == item)
  270. {
  271. for(; i < priv->items_nr; i++)
  272. {
  273. priv->items[i] = priv->items[i+1];
  274. }
  275. priv->items_nr--;
  276. ret = RET_OK;
  277. break;
  278. }
  279. }
  280. if(ret == RET_OK)
  281. {
  282. priv->changed = 1;
  283. ftk_widget_remove_child(thiz, item);
  284. }
  285. return RET_OK;
  286. }