rtgui_mv_model.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. * File : rtgui_mv_model.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2012, 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. * 2012-09-15 Grissiom first version
  13. */
  14. #include <rtgui/rtgui.h>
  15. #include <rtgui/rtgui_app.h>
  16. #include <rtgui/rtgui_object.h>
  17. #include <rtgui/rtgui_system.h>
  18. #include <rtgui/rtgui_mv_model.h>
  19. #include <rtgui/widgets/mv_view.h>
  20. #include <rtgui/widgets/window.h>
  21. static void _rtgui_mv_model_bare_remove(struct rtgui_mv_model *model, struct rtgui_mv_view *view);
  22. static void _rtgui_mv_view_bare_remove(struct rtgui_mv_view *view, struct rtgui_mv_model *model);
  23. static rt_bool_t _rtgui_mv_model_notify_view(struct rtgui_mv_model *model,
  24. struct rtgui_mv_view *view,
  25. struct rtgui_event_mv_model *emodel);
  26. static void _rtgui_mv_model_constructor(struct rtgui_mv_model *model)
  27. {
  28. model->dimension = 0;
  29. model->length = 0;
  30. model->data = RT_NULL;
  31. model->view_number = 0;
  32. model->view = RT_NULL;
  33. /* currently not interested in any event */
  34. rtgui_object_set_event_handler(RTGUI_OBJECT(model), RT_NULL);
  35. }
  36. static void _rtgui_mv_model_destructor(struct rtgui_mv_model *model)
  37. {
  38. if (model->view_number == 1)
  39. {
  40. rtgui_mv_model_remove_view(model, model->view);
  41. }
  42. else if (model->view_number > 1)
  43. {
  44. int i;
  45. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  46. for (i = 0; i < model->view_number; i++)
  47. {
  48. rtgui_mv_model_remove_view(model, view_arr[i]);
  49. }
  50. }
  51. if (model->dimension > 1)
  52. rtgui_free(model->data);
  53. }
  54. DEFINE_CLASS_TYPE(mv_model, "mv_model",
  55. RTGUI_OBJECT_TYPE,
  56. _rtgui_mv_model_constructor,
  57. _rtgui_mv_model_destructor,
  58. sizeof(struct rtgui_mv_model));
  59. struct rtgui_mv_model *rtgui_mv_model_create(rt_uint16_t dimension)
  60. {
  61. struct rtgui_mv_model *model;
  62. RT_ASSERT(dimension);
  63. model = RTGUI_MV_MODEL(rtgui_object_create(RTGUI_MV_MODEL_TYPE));
  64. if (model == RT_NULL)
  65. return RT_NULL;
  66. if (rtgui_mv_model_set_dimension(model, dimension) != RT_EOK)
  67. {
  68. rtgui_object_destroy(RTGUI_OBJECT(model));
  69. return RT_NULL;
  70. }
  71. return model;
  72. }
  73. RTM_EXPORT(rtgui_mv_model_create);
  74. rt_err_t rtgui_mv_model_set_dimension(struct rtgui_mv_model *model, rt_uint16_t dimension)
  75. {
  76. if (dimension == 1)
  77. {
  78. if (model->dimension > 1)
  79. rtgui_free(model->data);
  80. model->data = RT_NULL;
  81. }
  82. else
  83. {
  84. void *data;
  85. if (model->dimension > 1)
  86. rtgui_free(model->data);
  87. data = rtgui_malloc(sizeof(void *)*dimension);
  88. if (data == RT_NULL)
  89. {
  90. return -RT_ENOMEM;
  91. }
  92. rt_memset(data, 0, sizeof(void *)*dimension);
  93. model->data = data;
  94. }
  95. model->dimension = dimension;
  96. return RT_EOK;
  97. }
  98. RTM_EXPORT(rtgui_mv_model_set_dimension);
  99. void rtgui_mv_model_destroy(struct rtgui_mv_model *model)
  100. {
  101. rtgui_object_destroy(RTGUI_OBJECT(model));
  102. }
  103. RTM_EXPORT(rtgui_mv_model_destroy);
  104. rt_err_t rtgui_mv_model_add_view(struct rtgui_mv_model *model, struct rtgui_mv_view *view)
  105. {
  106. RT_ASSERT(model);
  107. if (view == RT_NULL)
  108. return RT_EOK;
  109. /* add view to model */
  110. if (model->view_number == 0)
  111. {
  112. model->view = view;
  113. }
  114. else if (model->view_number == 1)
  115. {
  116. /* create the array of view pointers */
  117. struct rtgui_mv_view **new_view;
  118. if (view == model->view)
  119. return RT_EOK;
  120. new_view = rtgui_malloc(2 * sizeof(struct rtgui_mv_view *));
  121. if (new_view == RT_NULL)
  122. return -RT_ENOMEM;
  123. new_view[0] = model->view;
  124. new_view[1] = view;
  125. model->view = new_view;
  126. }
  127. else
  128. {
  129. int i;
  130. struct rtgui_mv_view **new_view;
  131. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  132. for (i = 0; i < model->view_number; i++)
  133. {
  134. if (view == view_arr[i])
  135. return RT_EOK;
  136. }
  137. new_view = rtgui_realloc(model->view,
  138. (model->view_number + 1) * sizeof(struct rtgui_mv_view *));
  139. if (new_view == RT_NULL)
  140. return -RT_ENOMEM;
  141. new_view[model->view_number] = view;
  142. model->view = new_view;
  143. }
  144. model->view_number++;
  145. /* add model to view. Roll back previous action on fail. */
  146. if (view->model_number == 0)
  147. {
  148. view->model = model;
  149. }
  150. else if (view->model_number == 1)
  151. {
  152. struct rtgui_mv_model **new_arr = rtgui_malloc(2 * sizeof(struct rtgui_mv_model *));
  153. if (new_arr == RT_NULL)
  154. {
  155. _rtgui_mv_model_bare_remove(model, view);
  156. return -RT_ENOMEM;
  157. }
  158. new_arr[0] = view->model;
  159. new_arr[1] = model;
  160. view->model = new_arr;
  161. }
  162. else
  163. {
  164. struct rtgui_mv_model **new_arr = rtgui_realloc(view->model,
  165. (view->model_number + 1) * sizeof(struct rtgui_mv_model *));
  166. if (new_arr == RT_NULL)
  167. {
  168. _rtgui_mv_model_bare_remove(model, view);
  169. return -RT_ENOMEM;
  170. }
  171. new_arr[view->model_number] = model;
  172. view->model = new_arr;
  173. }
  174. view->model_number++;
  175. return RT_EOK;
  176. }
  177. RTM_EXPORT(rtgui_mv_model_add_view);
  178. static void _rtgui_mv_model_bare_remove(struct rtgui_mv_model *model, struct rtgui_mv_view *view)
  179. {
  180. int i;
  181. if (model->view_number == 1)
  182. {
  183. if (model->view == view)
  184. {
  185. model->view_number--;
  186. model->view = RT_NULL;
  187. }
  188. return;
  189. }
  190. for (i = 0; i < model->view_number; i++)
  191. {
  192. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  193. if (view == view_arr[i])
  194. break;
  195. }
  196. /* no match */
  197. if (i == model->view_number)
  198. {
  199. return;
  200. }
  201. else if (model->view_number == 2)
  202. {
  203. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  204. struct rtgui_mv_view *the_view = view_arr[(i + 1) % 2];
  205. rtgui_free(model->view);
  206. model->view = the_view;
  207. model->view_number--;
  208. return;
  209. }
  210. else
  211. {
  212. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  213. void *new_view;
  214. for (; i < model->view_number - 1; i++)
  215. {
  216. view_arr[i] = view_arr[i + 1];
  217. }
  218. new_view = rtgui_realloc(model->view,
  219. (model->view_number - 1) * sizeof(struct rtgui_mv_view *));
  220. /* no need to be panic on OOM error. The original array is still there
  221. * and we can operate it safely. So just ignore the NULL value returned
  222. * by realloc. */
  223. if (new_view != RT_NULL)
  224. model->view = new_view;
  225. model->view_number--;
  226. return;
  227. }
  228. }
  229. static void _rtgui_mv_view_bare_remove(struct rtgui_mv_view *view, struct rtgui_mv_model *model)
  230. {
  231. int i;
  232. struct rtgui_mv_model **model_arr = (struct rtgui_mv_model **)(view)->model;
  233. if (view->model_number == 1)
  234. {
  235. if (view->model == model)
  236. {
  237. view->model_number--;
  238. view->model = RT_NULL;
  239. }
  240. return;
  241. }
  242. for (i = 0; i < view->model_number; i++)
  243. {
  244. if (model == model_arr[i])
  245. break;
  246. }
  247. /* no match */
  248. if (i == view->model_number)
  249. {
  250. return;
  251. }
  252. else if (view->model_number == 2)
  253. {
  254. struct rtgui_mv_model **model_arr = (struct rtgui_mv_model **)(view)->model;
  255. struct rtgui_mv_model *the_model = model_arr[(i + 1) % 2];
  256. rtgui_free(view->model);
  257. view->model = the_model;
  258. view->model_number--;
  259. return;
  260. }
  261. else
  262. {
  263. struct rtgui_mv_model **model_arr = (struct rtgui_mv_model **)(view)->model;
  264. void *new_model;
  265. for (; i < view->model_number - 1; i++)
  266. {
  267. model_arr[i] = model_arr[i + 1];
  268. }
  269. new_model = rtgui_realloc(view->model,
  270. (view->model_number - 1) * sizeof(struct rtgui_mv_model *));
  271. /* no need to be panic on OOM error. The original array is still there
  272. * and we can operate it safely. So just ignore the NULL value returned
  273. * by realloc. */
  274. if (new_model != RT_NULL)
  275. view->model = new_model;
  276. view->model_number--;
  277. return;
  278. }
  279. }
  280. void rtgui_mv_model_remove_view(struct rtgui_mv_model *model, struct rtgui_mv_view *view)
  281. {
  282. RT_ASSERT(model);
  283. if (view == RT_NULL)
  284. return;
  285. if (model->length > 0)
  286. {
  287. struct rtgui_event_mv_model emodel;
  288. RTGUI_EVENT_MV_MODEL_DELETED_INIT(&emodel);
  289. emodel.first_data_changed_idx = 0;
  290. emodel.last_data_changed_idx = model->length;
  291. /* rtgui_mv_model_remove_view is to be called in thread context.
  292. * Besides, it is called by _rtgui_mv_view_destructor which means the
  293. * view will be invalid in the future. So we should call the event
  294. * handler immediately. */
  295. RTGUI_OBJECT(view)->event_handler(RTGUI_OBJECT(view), (struct rtgui_event *)&emodel);
  296. }
  297. _rtgui_mv_model_bare_remove(model, view);
  298. _rtgui_mv_view_bare_remove(view, model);
  299. }
  300. RTM_EXPORT(rtgui_mv_model_remove_view);
  301. rt_bool_t rtgui_mv_model_has_view(struct rtgui_mv_model *model, struct rtgui_mv_view *view)
  302. {
  303. RT_ASSERT(model);
  304. if (view == RT_NULL || model->view_number == 0)
  305. return RT_FALSE;
  306. if (model->view_number == 1)
  307. {
  308. return model->view == view;
  309. }
  310. else
  311. {
  312. int i;
  313. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  314. for (i = 0; i < model->view_number; i++)
  315. {
  316. if (view == view_arr[i])
  317. return RT_TRUE;
  318. }
  319. return RT_FALSE;
  320. }
  321. }
  322. RTM_EXPORT(rtgui_mv_model_has_view);
  323. void rtgui_mv_model_set_data(struct rtgui_mv_model *model, rt_uint16_t dim, void *p)
  324. {
  325. RT_ASSERT(model);
  326. RT_ASSERT(dim < model->dimension);
  327. if (model->dimension == 1)
  328. {
  329. model->data = p;
  330. return;
  331. }
  332. else
  333. {
  334. void **d_arr = (void **)model->data;
  335. d_arr[dim] = p;
  336. }
  337. }
  338. RTM_EXPORT(rtgui_mv_model_set_data);
  339. void *rtgui_mv_model_get_data(struct rtgui_mv_model *model, rt_uint16_t dim)
  340. {
  341. RT_ASSERT(model);
  342. RT_ASSERT(dim < model->dimension);
  343. if (model->dimension == 1)
  344. {
  345. return model->data;
  346. }
  347. else
  348. {
  349. void **d_arr = (void **)model->data;
  350. return d_arr[dim];
  351. }
  352. }
  353. RTM_EXPORT(rtgui_mv_model_get_data);
  354. static rt_bool_t _rtgui_mv_model_notify_view(struct rtgui_mv_model *model,
  355. struct rtgui_mv_view *view,
  356. struct rtgui_event_mv_model *emodel)
  357. {
  358. struct rtgui_app *target = RTGUI_WIDGET(view)->toplevel->app;
  359. emodel->model = model;
  360. emodel->view = view;
  361. return rtgui_send(target, (struct rtgui_event *)emodel, sizeof(*emodel));
  362. }
  363. void rtgui_mv_model_notify(struct rtgui_mv_model *model,
  364. struct rtgui_event_mv_model *em)
  365. {
  366. /* model and view may not be in the same thread. Actually, model may not
  367. * belong to any RTGUI thread. So we have to notify the views by sending
  368. * events to the thread directly. */
  369. if (model->view_number == 1)
  370. {
  371. struct rtgui_mv_view *view = (struct rtgui_mv_view *)model->view;
  372. _rtgui_mv_model_notify_view(model, view, em);
  373. }
  374. else
  375. {
  376. int i;
  377. struct rtgui_mv_view **view_arr = (struct rtgui_mv_view **)(model)->view;
  378. for (i = 0; i < model->view_number; i++)
  379. {
  380. _rtgui_mv_model_notify_view(model, view_arr[i], em);
  381. }
  382. }
  383. }
  384. RTM_EXPORT(rtgui_mv_model_notify);