view_stack.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*
  2. * Copyright (c) 2019 Actions Semiconductor Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @file view stack interface
  8. */
  9. #define LOG_MODULE_CUSTOMER
  10. #include <os_common_api.h>
  11. #include <ui_manager.h>
  12. #include <string.h>
  13. #include <assert.h>
  14. #include <view_stack.h>
  15. LOG_MODULE_REGISTER(view_stack, LOG_LEVEL_INF);
  16. typedef struct {
  17. /* view cache descripter */
  18. const view_cache_dsc_t *cache;
  19. /* view group descripter */
  20. const view_group_dsc_t *group;
  21. /* presenter of the view, used only when cache == NULL */
  22. const void *presenter;
  23. /* init focused view id */
  24. uint16_t id;
  25. /* init focused main view id for view cache */
  26. uint16_t main_id;
  27. } view_stack_data_t;
  28. typedef struct {
  29. view_stack_data_t data[CONFIG_VIEW_STACK_LEVEL];
  30. uint8_t num;
  31. uint8_t inited : 1;
  32. } view_stack_ctx_t;
  33. static view_stack_ctx_t view_stack;
  34. static OS_MUTEX_DEFINE(mutex);
  35. static int _view_stack_update(const view_stack_data_t *data, bool push_stack);
  36. static int _view_stack_jump(view_stack_data_t *old_data,
  37. const view_stack_data_t *new_data);
  38. int view_stack_init(void)
  39. {
  40. int res = 0;
  41. os_mutex_lock(&mutex, OS_FOREVER);
  42. if (view_stack.inited) {
  43. res = -EALREADY;
  44. goto out_unlock;
  45. }
  46. view_stack.inited = 1;
  47. out_unlock:
  48. os_mutex_unlock(&mutex);
  49. return res;
  50. }
  51. void view_stack_deinit(void)
  52. {
  53. os_mutex_lock(&mutex, OS_FOREVER);
  54. view_stack.inited = 0;
  55. os_mutex_unlock(&mutex);
  56. view_stack_clean();
  57. }
  58. uint8_t view_stack_get_num(void)
  59. {
  60. return view_stack.num;
  61. }
  62. uint16_t view_stack_get_top(void)
  63. {
  64. view_stack_data_t * top;
  65. uint16_t focused = VIEW_INVALID_ID;
  66. os_mutex_lock(&mutex, OS_FOREVER);
  67. if (view_stack.num == 0) {
  68. goto out_unlock;
  69. }
  70. top = &view_stack.data[view_stack.num - 1];
  71. if (top->cache) {
  72. focused = view_cache_get_focus_view();
  73. } else {
  74. focused = top->id;
  75. }
  76. out_unlock:
  77. os_mutex_unlock(&mutex);
  78. return focused;
  79. }
  80. const view_cache_dsc_t * view_stack_get_top_cache(void)
  81. {
  82. view_stack_data_t * top;
  83. const view_cache_dsc_t *dsc = NULL;
  84. os_mutex_lock(&mutex, OS_FOREVER);
  85. if (view_stack.num > 0) {
  86. top = &view_stack.data[view_stack.num - 1];
  87. dsc = top->cache;
  88. }
  89. os_mutex_unlock(&mutex);
  90. return dsc;
  91. }
  92. uint16_t view_stack_level_get_view_id(uint16_t level_id)
  93. {
  94. uint16_t focused = VIEW_INVALID_ID;
  95. os_mutex_lock(&mutex, OS_FOREVER);
  96. if(level_id < view_stack.num)
  97. focused = view_stack.data[level_id].id;
  98. os_mutex_unlock(&mutex);
  99. return focused;
  100. }
  101. void view_stack_clean(void)
  102. {
  103. os_mutex_lock(&mutex, OS_FOREVER);
  104. if (view_stack.num > 0) {
  105. _view_stack_jump(&view_stack.data[view_stack.num - 1], NULL);
  106. view_stack.num = 0;
  107. }
  108. os_mutex_unlock(&mutex);
  109. }
  110. int view_stack_pop_home(void)
  111. {
  112. int res = -ENODATA;
  113. os_mutex_lock(&mutex, OS_FOREVER);
  114. if (view_stack.num <= 1) {
  115. goto out_unlock;
  116. }
  117. res = _view_stack_jump(&view_stack.data[view_stack.num - 1], &view_stack.data[0]);
  118. view_stack.num = 1;
  119. out_unlock:
  120. os_mutex_unlock(&mutex);
  121. return res;
  122. }
  123. int view_stack_pop(void)
  124. {
  125. int res = -ENODATA;
  126. os_mutex_lock(&mutex, OS_FOREVER);
  127. if (view_stack.num <= 1) {
  128. goto out_unlock;
  129. }
  130. res = _view_stack_jump(&view_stack.data[view_stack.num - 1],
  131. &view_stack.data[view_stack.num - 2]);
  132. view_stack.num--;
  133. out_unlock:
  134. os_mutex_unlock(&mutex);
  135. return res;
  136. }
  137. int view_stack_push_cache(const view_cache_dsc_t *dsc, uint16_t view_id)
  138. {
  139. return view_stack_push_cache2(dsc, view_id, VIEW_INVALID_ID);
  140. }
  141. int view_stack_push_cache2(const view_cache_dsc_t *dsc,
  142. uint16_t focus_view_id, uint16_t main_view_id)
  143. {
  144. view_stack_data_t data = {
  145. .cache = dsc,
  146. .group = NULL,
  147. .presenter = NULL,
  148. .id = focus_view_id,
  149. .main_id = main_view_id,
  150. };
  151. return _view_stack_update(&data, true);
  152. }
  153. int view_stack_push_group(const view_group_dsc_t *dsc)
  154. {
  155. view_stack_data_t data = {
  156. .cache = NULL,
  157. .group = dsc,
  158. .presenter = NULL,
  159. .id = dsc->vlist[dsc->idx],
  160. };
  161. return _view_stack_update(&data, true);
  162. }
  163. int view_stack_push_view(uint16_t view_id, const void *presenter)
  164. {
  165. view_stack_data_t data = {
  166. .cache = NULL,
  167. .group = NULL,
  168. .presenter = presenter,
  169. .id = view_id,
  170. };
  171. return _view_stack_update(&data, true);
  172. }
  173. int view_stack_jump_cache(const view_cache_dsc_t *dsc, uint16_t view_id)
  174. {
  175. return view_stack_jump_cache2(dsc, view_id, VIEW_INVALID_ID);
  176. }
  177. int view_stack_jump_cache2(const view_cache_dsc_t *dsc,
  178. uint16_t focus_view_id, uint16_t main_view_id)
  179. {
  180. view_stack_data_t data = {
  181. .cache = dsc,
  182. .group = NULL,
  183. .presenter = NULL,
  184. .id = focus_view_id,
  185. .main_id = main_view_id,
  186. };
  187. return _view_stack_update(&data, false);
  188. }
  189. int view_stack_jump_group(const view_group_dsc_t *dsc)
  190. {
  191. view_stack_data_t data = {
  192. .cache = NULL,
  193. .group = dsc,
  194. .presenter = NULL,
  195. .id = dsc->vlist[dsc->idx],
  196. };
  197. return _view_stack_update(&data, false);
  198. }
  199. int view_stack_jump_view(uint16_t view_id, const void *presenter)
  200. {
  201. view_stack_data_t data = {
  202. .cache = NULL,
  203. .group = NULL,
  204. .presenter = presenter,
  205. .id = view_id,
  206. };
  207. return _view_stack_update(&data, false);
  208. }
  209. void view_stack_dump(void)
  210. {
  211. uint8_t i;
  212. int8_t idx;
  213. os_mutex_lock(&mutex, OS_FOREVER);
  214. os_printk("view stack:\n", view_stack.num);
  215. for (idx = view_stack.num - 1; idx >= 0; idx--) {
  216. if (view_stack.data[idx].cache) {
  217. os_printk("[%d] cache:\n", idx);
  218. os_printk("\t main(%u):", view_stack.data[idx].cache->num);
  219. for (i = 0; i < view_stack.data[idx].cache->num; i++) {
  220. os_printk(" %u", view_stack.data[idx].cache->vlist[i]);
  221. }
  222. os_printk("\n\t cross: %u %u\n", view_stack.data[idx].cache->cross_vlist[0],
  223. view_stack.data[idx].cache->cross_vlist[1]);
  224. } else if (view_stack.data[idx].group) {
  225. os_printk("[%d] group:", idx, view_stack.data[idx].group->num);
  226. for (i = 0; i < view_stack.data[idx].group->num; i++) {
  227. os_printk(" %u", i, view_stack.data[idx].group->vlist[i]);
  228. }
  229. os_printk("\n");
  230. } else {
  231. os_printk("[%d] view: %u\n", idx, view_stack.data[idx].id);
  232. }
  233. }
  234. os_printk("\n");
  235. os_mutex_unlock(&mutex);
  236. }
  237. static int _view_stack_update(const view_stack_data_t *data, bool push_stack)
  238. {
  239. view_stack_data_t *old_data = NULL;
  240. int res = 0;
  241. int new_idx;
  242. os_mutex_lock(&mutex, OS_FOREVER);
  243. if (view_stack.inited == 0) {
  244. res = -ESRCH;
  245. goto out_unlock;
  246. }
  247. if ((view_stack.num >= ARRAY_SIZE(view_stack.data)) && push_stack) {
  248. res = -ENOSPC;
  249. goto out_unlock;
  250. }
  251. if (view_stack.num > 0) {
  252. old_data = &view_stack.data[view_stack.num - 1];
  253. } else {
  254. push_stack = true;
  255. }
  256. res = _view_stack_jump(old_data, data);
  257. if (!res) {
  258. if (push_stack) {
  259. new_idx = view_stack.num ++;
  260. } else {
  261. new_idx = view_stack.num - 1;
  262. }
  263. memcpy(&view_stack.data[new_idx], data, sizeof(*data));
  264. }
  265. assert(res == 0);
  266. out_unlock:
  267. os_mutex_unlock(&mutex);
  268. return res;
  269. }
  270. static bool _view_group_has_view(const view_group_dsc_t *group, uint8_t view_id)
  271. {
  272. int i;
  273. for (i = group->num - 1; i >= 0; i--) {
  274. if (view_id == group->vlist[i])
  275. return true;
  276. }
  277. return false;
  278. }
  279. static void _view_group_scroll_cb(uint16_t view_id, uint8_t msg_id)
  280. {
  281. view_stack_data_t * data;
  282. if (msg_id != MSG_VIEW_SCROLL_END) {
  283. return;
  284. }
  285. os_mutex_lock(&mutex, OS_FOREVER);
  286. data = &view_stack.data[view_stack.num - 1];
  287. if (view_stack.num < 1 || data->group == NULL) {
  288. goto out_unlock;
  289. }
  290. if (data->group->scroll_cb)
  291. data->group->scroll_cb(view_id);
  292. out_unlock:
  293. os_mutex_unlock(&mutex);
  294. }
  295. static void _view_group_monitor_cb(uint16_t view_id, uint8_t msg_id, void *msg_data)
  296. {
  297. view_stack_data_t * data;
  298. os_mutex_lock(&mutex, OS_FOREVER);
  299. data = &view_stack.data[view_stack.num - 1];
  300. if (view_stack.num < 1 || data->group == NULL) {
  301. goto out_unlock;
  302. }
  303. if (_view_group_has_view(data->group, view_id) == false) {
  304. goto out_unlock;
  305. }
  306. if (msg_id == MSG_VIEW_FOCUS || msg_id == MSG_VIEW_DEFOCUS) {
  307. bool focused = (msg_id == MSG_VIEW_FOCUS);
  308. if (data->group->focus_cb)
  309. data->group->focus_cb(view_id, focused);
  310. if (focused)
  311. data->id = view_id;
  312. }
  313. out_unlock:
  314. os_mutex_unlock(&mutex);
  315. }
  316. static int _view_stack_jump(view_stack_data_t *old_data,
  317. const view_stack_data_t *new_data)
  318. {
  319. uint16_t old_view = VIEW_INVALID_ID;
  320. uint16_t new_view = VIEW_INVALID_ID;
  321. int8_t i;
  322. int res = 0;
  323. if (old_data) {
  324. if (old_data->cache) {
  325. old_view = view_cache_get_focus_view();
  326. old_data->id = old_view;
  327. old_data->main_id = view_cache_get_focus_main_view();
  328. if(!view_cache_deinit())
  329. {
  330. os_mutex_unlock(&mutex);
  331. view_cache_wait_last_focus_cb();
  332. os_mutex_lock(&mutex, OS_FOREVER);
  333. }
  334. } else if (old_data->group) {
  335. ui_manager_set_monitor_callback(NULL);
  336. if (old_data->group->scroll_cb)
  337. ui_manager_set_scroll_callback(NULL);
  338. old_view = old_data->id;
  339. for (i = old_data->group->num - 1; i >= 0; i--) {
  340. if (old_data->group->vlist[i] != old_view)
  341. ui_view_delete(old_data->group->vlist[i]);
  342. }
  343. /* delete the focused view at last to avoid unexpected focus changes */
  344. ui_view_delete(old_view);
  345. } else {
  346. old_view = old_data->id;
  347. ui_view_delete(old_data->id);
  348. }
  349. }
  350. if (new_data) {
  351. if (new_data->cache) {
  352. res = view_cache_init2(new_data->cache, new_data->id, new_data->main_id);
  353. } else if (new_data->group) {
  354. uint8_t idx = new_data->group->idx;
  355. ui_manager_set_monitor_callback(_view_group_monitor_cb);
  356. if (new_data->group->scroll_cb)
  357. ui_manager_set_scroll_callback(_view_group_scroll_cb);
  358. for (i = new_data->group->num - 1; i >= 0; i--) {
  359. if (new_data->group->vlist[i] == new_data->id) {
  360. idx = i;
  361. break;
  362. }
  363. }
  364. ui_view_create(new_data->group->vlist[idx],
  365. new_data->group->plist ? new_data->group->plist[idx] : NULL,
  366. UI_CREATE_FLAG_SHOW);
  367. for (i = new_data->group->num - 1; i >= 0; i--) {
  368. if (i != idx) {
  369. ui_view_create(new_data->group->vlist[i],
  370. new_data->group->plist ? new_data->group->plist[i] : NULL,
  371. 0);
  372. }
  373. }
  374. /* trigger first scroll_cb to notify app */
  375. if (new_data->group->scroll_cb)
  376. new_data->group->scroll_cb(new_data->group->vlist[idx]);
  377. } else {
  378. res = ui_view_create(new_data->id, new_data->presenter, UI_CREATE_FLAG_SHOW);
  379. }
  380. new_view = new_data->id;
  381. }
  382. SYS_LOG_INF("view_stack: jump %d -> %d (res=%d)", old_view, new_view, res);
  383. return res;
  384. }