/src/ftk_combo_box.c

http://ftk.googlecode.com/ · C · 362 lines · 261 code · 72 blank · 29 comment · 33 complexity · b0d320d4b3aae38210d379593c965d60 MD5 · raw file

  1. /*
  2. * File: ftk_combo_box.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: combo_box control.
  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. * 2010-01-28 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "ftk_globals.h"
  31. #include "ftk_theme.h"
  32. #include "ftk_entry.h"
  33. #include "ftk_dialog.h"
  34. #include "ftk_button.h"
  35. #include "ftk_combo_box.h"
  36. #include "ftk_list_view.h"
  37. #include "ftk_list_model_default.h"
  38. #include "ftk_list_render_default.h"
  39. typedef struct _ComboBoxPrivInfo
  40. {
  41. FtkWidget* entry;
  42. FtkWidget* button;
  43. FtkListModel* model;
  44. int selected;
  45. FtkListener listener;
  46. void* listener_ctx;
  47. }PrivInfo;
  48. static Ret ftk_combo_box_on_event(FtkWidget* thiz, FtkEvent* event)
  49. {
  50. return RET_OK;
  51. }
  52. static Ret ftk_combo_box_on_paint(FtkWidget* thiz)
  53. {
  54. return RET_OK;
  55. }
  56. static void ftk_combo_box_destroy(FtkWidget* thiz)
  57. {
  58. DECL_PRIV0(thiz, priv);
  59. if(priv != NULL)
  60. {
  61. ftk_list_model_unref(priv->model);
  62. priv->model = NULL;
  63. FTK_ZFREE(thiz->priv_subclass[0], sizeof(PrivInfo));
  64. }
  65. return;
  66. }
  67. static Ret ftk_popup_on_item_clicked(void* ctx, void* list)
  68. {
  69. FtkListItemInfo* info = NULL;
  70. int i = ftk_list_view_get_selected((FtkWidget*)list);
  71. FtkListModel* model = ftk_list_view_get_model((FtkWidget*)list);
  72. Ret ret = RET_OK;
  73. ftk_list_model_get_data(model, i, (void**)&info);
  74. if(info != NULL)
  75. {
  76. FtkWidget* thiz = (FtkWidget*)info->user_data;
  77. DECL_PRIV0(thiz, priv);
  78. ftk_combo_box_set_text(thiz, info->text);
  79. priv->selected = i;
  80. ret = FTK_CALL_LISTENER(priv->listener, priv->listener_ctx, thiz);
  81. priv->model->listener_ctx = NULL;
  82. }
  83. ftk_widget_unref((FtkWidget*)ctx);
  84. return ret;
  85. }
  86. static Ret ftk_combo_box_popup_rect(FtkWidget* thiz, int* x, int* y, int* w, int* h)
  87. {
  88. int ox = 0;
  89. int oy = 0;
  90. int nr = 0;
  91. int width = 0;
  92. int height = 0;
  93. DECL_PRIV0(thiz, priv);
  94. FtkWidget* win = ftk_widget_toplevel(thiz);
  95. int win_heigth = ftk_widget_height(win);
  96. int margin = (FTK_H_MARGIN + FTK_DIALOG_BORDER)*2;
  97. ox = ftk_widget_left_abs(thiz);
  98. width = ftk_widget_width(thiz);
  99. oy = ftk_widget_top_in_window(priv->entry) + ftk_widget_height(priv->entry);
  100. height = ftk_list_model_get_total(priv->model) * FTK_POPUP_MENU_ITEM_HEIGHT + margin;
  101. if((height + oy) > win_heigth)
  102. {
  103. if(oy < (win_heigth)/2)
  104. {
  105. height = win_heigth - oy;
  106. nr = (height - margin)/FTK_POPUP_MENU_ITEM_HEIGHT;
  107. height = nr * FTK_POPUP_MENU_ITEM_HEIGHT + margin;
  108. }
  109. else
  110. {
  111. height = FTK_MIN(height, oy - ftk_widget_height(priv->entry));
  112. nr = (height - margin)/FTK_POPUP_MENU_ITEM_HEIGHT;
  113. height = nr * FTK_POPUP_MENU_ITEM_HEIGHT + margin;
  114. oy = oy - height - ftk_widget_height(priv->entry);
  115. }
  116. }
  117. oy += ftk_widget_top_abs(win);
  118. *x = ox;
  119. *y = oy;
  120. *w = width;
  121. *h = height;
  122. return RET_OK;
  123. }
  124. static Ret button_drop_down_clicked(void* ctx, void* obj)
  125. {
  126. int x = 0;
  127. int y = 0;
  128. int w = 200;
  129. int h = 100;
  130. FtkWidget* thiz = (FtkWidget*)ctx;
  131. DECL_PRIV0(thiz, priv);
  132. FtkWidget* popup = NULL;
  133. FtkWidget* list = NULL;
  134. FtkListRender* render = NULL;
  135. ftk_combo_box_popup_rect(thiz, &x, &y, &w, &h);
  136. popup = ftk_dialog_create_ex(FTK_ATTR_POPUP, x, y, w, h);
  137. if(y < ftk_widget_top_abs(thiz))
  138. {
  139. ftk_window_set_animation_hint(popup, "combobox_up");
  140. }
  141. else
  142. {
  143. ftk_window_set_animation_hint(popup, "combobox_down");
  144. }
  145. ftk_dialog_hide_title(popup);
  146. w = ftk_widget_width(popup) - FTK_DIALOG_BORDER * 2;
  147. h = ftk_widget_height(popup) - FTK_DIALOG_BORDER * 2;
  148. list = ftk_list_view_create(popup, 0, 0, w, h);
  149. ftk_widget_show(list, 1);
  150. render = ftk_list_render_default_create();
  151. ftk_list_view_init(list, priv->model, render, FTK_POPUP_MENU_ITEM_HEIGHT);
  152. ftk_list_view_set_clicked_listener(list, ftk_popup_on_item_clicked, popup);
  153. ftk_widget_show_all(popup, 1);
  154. return RET_OK;
  155. }
  156. FtkWidget* ftk_combo_box_create(FtkWidget* parent, int x, int y, int width, int height)
  157. {
  158. FtkWidget* thiz = (FtkWidget*)FTK_ZALLOC(sizeof(FtkWidget));
  159. return_val_if_fail(thiz != NULL, NULL);
  160. width = width < height ? (height << 1) : width;
  161. thiz->priv_subclass[0] = (PrivInfo*)FTK_ZALLOC(sizeof(PrivInfo));
  162. if(thiz->priv_subclass[0] != NULL)
  163. {
  164. int h = 0;
  165. int w = 0;
  166. FtkGc gc = {0};
  167. DECL_PRIV0(thiz, priv);
  168. thiz->on_event = ftk_combo_box_on_event;
  169. thiz->on_paint = ftk_combo_box_on_paint;
  170. thiz->destroy = ftk_combo_box_destroy;
  171. ftk_widget_init(thiz, FTK_COMBO_BOX, 0, x, y, width, height, FTK_ATTR_TRANSPARENT);
  172. ftk_widget_append_child(parent, thiz);
  173. priv->entry = ftk_entry_create(thiz, 0, 0, width-height, height);
  174. h = ftk_widget_height(priv->entry);
  175. w = ftk_widget_width(priv->entry);
  176. ftk_widget_move_resize(priv->entry, 0, FTK_HALF(height-h), width - h, h);
  177. ftk_widget_show(priv->entry, 1);
  178. priv->button = ftk_button_create(thiz, width - h, FTK_HALF(height-h), h, h);
  179. ftk_button_set_clicked_listener(priv->button, button_drop_down_clicked, thiz);
  180. ftk_widget_set_attr(priv->button, FTK_ATTR_BG_CENTER);
  181. gc.mask = FTK_GC_BITMAP;
  182. gc.bitmap = ftk_theme_load_image(ftk_default_theme(), "drop_down_normal"FTK_STOCK_IMG_SUFFIX);
  183. ftk_widget_set_gc(priv->button, FTK_WIDGET_NORMAL, &gc);
  184. ftk_gc_reset(&gc);
  185. gc.mask = FTK_GC_BITMAP;
  186. gc.bitmap = ftk_theme_load_image(ftk_default_theme(), "drop_down_selected"FTK_STOCK_IMG_SUFFIX);
  187. ftk_widget_set_gc(priv->button, FTK_WIDGET_FOCUSED, &gc);
  188. ftk_gc_reset(&gc);
  189. gc.mask = FTK_GC_BITMAP;
  190. gc.bitmap = ftk_theme_load_image(ftk_default_theme(), "drop_down_pressed"FTK_STOCK_IMG_SUFFIX);
  191. ftk_widget_set_gc(priv->button, FTK_WIDGET_ACTIVE, &gc);
  192. ftk_gc_reset(&gc);
  193. ftk_widget_show(priv->button, 1);
  194. ftk_widget_resize(thiz, width, h + (FTK_V_MARGIN << 1));
  195. priv->model = ftk_list_model_default_create(10);
  196. priv->selected = -1;
  197. }
  198. else
  199. {
  200. FTK_FREE(thiz);
  201. }
  202. return thiz;
  203. }
  204. const char* ftk_combo_box_get_text(FtkWidget* thiz)
  205. {
  206. DECL_PRIV0(thiz, priv);
  207. return_val_if_fail(thiz != NULL, NULL);
  208. return ftk_entry_get_text(priv->entry);
  209. }
  210. Ret ftk_combo_box_set_text(FtkWidget* thiz, const char* text)
  211. {
  212. DECL_PRIV0(thiz, priv);
  213. return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
  214. return ftk_entry_set_text(priv->entry, text);
  215. }
  216. FtkWidget* ftk_combo_box_get_entry(FtkWidget* thiz)
  217. {
  218. DECL_PRIV0(thiz, priv);
  219. return_val_if_fail(thiz != NULL, NULL);
  220. return priv->entry;
  221. }
  222. int ftk_combo_box_get_selected(FtkWidget* thiz)
  223. {
  224. DECL_PRIV0(thiz, priv);
  225. return_val_if_fail(thiz != NULL, -1);
  226. return priv->selected;
  227. }
  228. Ret ftk_combo_box_append(FtkWidget* thiz, FtkBitmap* icon, const char* text)
  229. {
  230. DECL_PRIV0(thiz, priv);
  231. FtkListItemInfo info = {0};
  232. return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
  233. info.type = FTK_LIST_ITEM_NORMAL;
  234. info.text = (char *)text;
  235. info.left_icon = icon;
  236. info.user_data = thiz;
  237. return ftk_list_model_add(priv->model, &info);
  238. }
  239. Ret ftk_combo_box_reset(FtkWidget* thiz)
  240. {
  241. DECL_PRIV0(thiz, priv);
  242. return_val_if_fail(thiz != NULL, RET_FAIL);
  243. ftk_combo_box_set_text(thiz, " ");
  244. priv->selected = -1;
  245. return ftk_list_model_reset(priv->model);
  246. }
  247. Ret ftk_combo_box_remove(FtkWidget* thiz, size_t index)
  248. {
  249. DECL_PRIV0(thiz, priv);
  250. return_val_if_fail(thiz != NULL, RET_FAIL);
  251. if(priv->selected == index)
  252. {
  253. ftk_combo_box_set_text(thiz, " ");
  254. priv->selected = -1;
  255. }
  256. return ftk_list_model_remove(priv->model, index);
  257. }
  258. Ret ftk_combo_box_set_clicked_listener(FtkWidget* thiz, FtkListener listener, void* ctx)
  259. {
  260. DECL_PRIV0(thiz, priv);
  261. return_val_if_fail(thiz != NULL, RET_FAIL);
  262. priv->listener_ctx = ctx;
  263. priv->listener = listener;
  264. return RET_OK;
  265. }
  266. int ftk_combo_box_get_item_nr(FtkWidget* thiz)
  267. {
  268. DECL_PRIV0(thiz, priv);
  269. return_val_if_fail(thiz != NULL, 0);
  270. return ftk_list_model_get_total(priv->model);
  271. }
  272. Ret ftk_combo_box_get_item(FtkWidget* thiz, size_t index, const FtkBitmap** icon, const char** text)
  273. {
  274. DECL_PRIV0(thiz, priv);
  275. FtkListItemInfo* info = NULL;
  276. return_val_if_fail(thiz != NULL, 0);
  277. ftk_list_model_get_data(priv->model, index, (void**)&info);
  278. if(info != NULL)
  279. {
  280. if(icon != NULL)
  281. {
  282. *icon = info->left_icon;
  283. }
  284. if(text != NULL)
  285. {
  286. *text = info->text;
  287. }
  288. }
  289. return info != NULL ? RET_OK : RET_FAIL;
  290. }