Taskmanager / src /

view.c

  1. /*
  2. * Copyright (c) 2016 Samsung Electronics Co., Ltd
  3. *
  4. * Licensed under the Flora License, Version 1.1 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://floralicense.org/license/
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16.  
  17. #include <efl_extension.h>
  18. #include "view.h"
  19. #include "item.h"
  20. #include "$(appName).h"
  21. #include "defines.h"
  22.  
  23. static struct view_info {
  24. Evas_Object *win;
  25. Evas_Object *layout;
  26. Evas_Object *conform;
  27. Evas_Object *genlist;
  28. Elm_Genlist_Item_Class *item_class;
  29. view_item_callback_t item_clicked_callback;
  30. view_item_callback_t item_deleted_callback;
  31. } s_info = {
  32. .win = NULL,
  33. .layout = NULL,
  34. .conform = NULL,
  35. .genlist = NULL,
  36. .item_class = NULL,
  37. .item_clicked_callback = NULL,
  38. .item_deleted_callback = NULL,
  39. };
  40.  
  41. static void _delete_win_request_cb(void *data, Evas_Object *obj, void *event_info);
  42. static void _layout_back_cb(void *data, Evas_Object *obj, void *event_info);
  43. static void _get_app_resource(const char *edj_file_in, char *edj_path_out);
  44. static Evas_Object *_create_icon(Evas_Object *parent, char *image_path);
  45. static void _item_layout_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
  46. static Evas_Object *_create_item_layout(Evas_Object *parent, char *app_id, char *icon_path);
  47. static Evas_Object *_get_item_content(void *data, Evas_Object *obj, const char *part);
  48. static Evas_Object *_create_genlist(void);
  49. static void _delete_item(Elm_Object_Item *genlist_item);
  50. static void _view_display_no_applications(void);
  51. static Eina_Bool _view_display_application_list(Eina_List *app_list);
  52.  
  53. /**
  54. * @brief Creates essential objects: window, conformant and layout.
  55. */
  56. Eina_Bool view_create(void *user_data)
  57. {
  58. char edj_path[PATH_MAX] = {0, };
  59.  
  60. /* Create the window */
  61. s_info.win = view_create_win(PACKAGE);
  62. if (s_info.win == NULL) {
  63. dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a window.");
  64. return EINA_FALSE;
  65. }
  66.  
  67. /* Create the conformant */
  68. s_info.conform = view_create_conformant_without_indicator(s_info.win);
  69. if (s_info.conform == NULL) {
  70. dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a conformant");
  71. return EINA_FALSE;
  72. }
  73.  
  74. /* Base Layout */
  75. _get_app_resource(MAIN_EDJ, edj_path);
  76. s_info.layout = view_create_layout(s_info.win, edj_path, TASKMGR_MAIN_GROUP);
  77. if (!s_info.layout) {
  78. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create layout");
  79. evas_object_del(s_info.win);
  80. return EINA_FALSE;
  81. }
  82. elm_object_content_set(s_info.conform, s_info.layout);
  83.  
  84. /* Genlist */
  85. s_info.genlist = _create_genlist();
  86. if (!s_info.genlist) {
  87. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create genlist");
  88. evas_object_del(s_info.win);
  89. return EINA_FALSE;
  90. }
  91.  
  92. /* Show window after base gui is set up */
  93. evas_object_show(s_info.win);
  94.  
  95. return EINA_TRUE;
  96. }
  97.  
  98. /**
  99. * @brief Creates a basic window named package.
  100. * @param[in] pkg_name Name of the window
  101. */
  102. Evas_Object *view_create_win(const char *pkg_name)
  103. {
  104. Evas_Object *win = NULL;
  105.  
  106. /*
  107. * Window
  108. * Create and initialize elm_win.
  109. * elm_win is mandatory to manipulate the window.
  110. */
  111. win = elm_win_util_standard_add(pkg_name, pkg_name);
  112. elm_win_conformant_set(win, EINA_TRUE);
  113. elm_win_autodel_set(win, EINA_TRUE);
  114. elm_win_indicator_mode_set(win, ELM_WIN_INDICATOR_SHOW);
  115. elm_win_indicator_opacity_set(win, ELM_WIN_INDICATOR_OPAQUE);
  116.  
  117. evas_object_smart_callback_add(win, "delete,request", _delete_win_request_cb, NULL);
  118.  
  119. return win;
  120. }
  121.  
  122. /**
  123. * @brief Creates a layout to target parent object with edje file
  124. * @param[in] parent The object to which you want to add this layout
  125. * @param[in] file_path File path of EDJ file will be used
  126. * @param[in] group_name Name of group in EDJ you want to set to
  127. * @param[in] cb_function The function will be called when back event is detected
  128. * @param[in] user_data The user data to be passed to the callback functions
  129. */
  130. Evas_Object *view_create_layout(Evas_Object *parent, const char *file_path, const char *group_name)
  131. {
  132. Evas_Object *layout = NULL;
  133.  
  134. if (parent == NULL) {
  135. dlog_print(DLOG_ERROR, LOG_TAG, "parent is NULL.");
  136. return NULL;
  137. }
  138.  
  139. /* Create layout using EDC(an edje file) */
  140. layout = elm_layout_add(parent);
  141. elm_layout_file_set(layout, file_path, group_name);
  142.  
  143. /* Layout size setting */
  144. evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
  145.  
  146. eext_object_event_callback_add(layout, EEXT_CALLBACK_BACK, _layout_back_cb, NULL);
  147.  
  148. evas_object_show(layout);
  149.  
  150. return layout;
  151. }
  152.  
  153. /**
  154. * @brief Creates a conformant without indicator for wearable app.
  155. * @param[in] win The object to which you want to set this conformant
  156. * Conformant is mandatory for base GUI to have proper size
  157. */
  158. Evas_Object *view_create_conformant_without_indicator(Evas_Object *win)
  159. {
  160. /*
  161. * Conformant
  162. * Create and initialize elm_conformant.
  163. * elm_conformant is mandatory for base GUI to have proper size
  164. * when indicator or virtual keypad is visible.
  165. */
  166. Evas_Object *conform = NULL;
  167.  
  168. if (win == NULL) {
  169. dlog_print(DLOG_ERROR, LOG_TAG, "window is NULL.");
  170. return NULL;
  171. }
  172.  
  173. conform = elm_conformant_add(win);
  174. evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
  175. elm_win_resize_object_add(win, conform);
  176.  
  177. evas_object_show(conform);
  178.  
  179. return conform;
  180. }
  181.  
  182. /**
  183. * @brief The applications list is displayed or 'No applications' label if the
  184. * provided list is empty.
  185. * @param[in] app_list The list of application ids and paths to its icons.
  186. */
  187. void view_update_application_list(Eina_List *app_list)
  188. {
  189. if (!app_list) {
  190. dlog_print(DLOG_ERROR, LOG_TAG, "No running applications");
  191. _view_display_no_applications();
  192. } else {
  193. _view_display_application_list(app_list);
  194. }
  195. }
  196.  
  197. /**
  198. * @brief The view callback functions are set.
  199. * @param[in] item_clicked_callback The callback function to be invoked on application's icon click.
  200. * @param[in] item_deleted_callback The callback function to be invoked on application's icon removal.
  201. */
  202. void view_set_callbacks(view_item_callback_t item_clicked_callback, view_item_callback_t item_deleted_callback)
  203. {
  204. s_info.item_clicked_callback = item_clicked_callback;
  205. s_info.item_deleted_callback = item_deleted_callback;
  206. }
  207.  
  208. /**
  209. * @brief Destroys window and frees its resources.
  210. */
  211. void view_destroy(void)
  212. {
  213. if (s_info.win == NULL)
  214. return;
  215.  
  216. evas_object_del(s_info.win);
  217. }
  218.  
  219. /**
  220. * @brief Internal function which displays the 'No applications' label in place
  221. * of application icons.
  222. */
  223. static void _view_display_no_applications(void)
  224. {
  225. if (s_info.layout)
  226. elm_layout_signal_emit(s_info.layout, TASKMGR_PROGRAM_NO_APPS_SHOW_SIGNAL, TASKMGR_PROGRAM_NO_APPS_SHOW_SOURCE);
  227.  
  228. if (s_info.genlist)
  229. elm_genlist_clear(s_info.genlist);
  230. }
  231.  
  232. /**
  233. * @brief Internal function responsible for application's list display.
  234. * @param[in] app_list The list of application ids and paths to its icons.
  235. * @return Function returns 'EINA_TRUE' if the applications list was displayed
  236. * successfully, otherwise 'EINA_FALSE' is returned.
  237. */
  238. static Eina_Bool _view_display_application_list(Eina_List *app_list)
  239. {
  240. Eina_List *it = NULL;
  241. app_item_t *item = NULL;
  242.  
  243. if (!app_list) {
  244. dlog_print(DLOG_ERROR, LOG_TAG, "Invalid argument");
  245. return false;
  246. }
  247.  
  248. if (s_info.layout)
  249. elm_layout_signal_emit(s_info.layout, TASKMGR_PROGRAM_NO_APPS_HIDE_SIGNAL, TASKMGR_PROGRAM_NO_APPS_HIDE_SOURCE);
  250.  
  251. if (elm_genlist_items_count(s_info.genlist) != 0)
  252. elm_genlist_clear(s_info.genlist);
  253.  
  254. EINA_LIST_FOREACH(app_list, it, item)
  255. elm_genlist_item_append(s_info.genlist, s_info.item_class, (void *)item, NULL,
  256. ELM_GENLIST_ITEM_NONE, NULL, NULL);
  257.  
  258. return true;
  259. }
  260.  
  261. /**
  262. * @brief Internal callback function invoked when the main window needs to be destroyed.
  263. * @param[in] data The user data passed to the evas_object_smart_callback_add() function.
  264. * @param[in] obj The object invoking this callback function.
  265. * @param[in] event_info The structure containing the information on this event.
  266. */
  267. static void _delete_win_request_cb(void *data, Evas_Object *obj, void *event_info)
  268. {
  269. ui_app_exit();
  270. }
  271.  
  272. /**
  273. * @brief Internal callback function invoked on HW Back button press.
  274. * @param[in] data The user data passed to the eext_object_event_callback_add() function.
  275. * @param[in] obj The object invoking this callback function.
  276. * @param[in] event_info The structure containing the information on this event.
  277. */
  278. static void _layout_back_cb(void *data, Evas_Object *obj, void *event_info)
  279. {
  280. /* Let window go to hide state. */
  281. elm_win_lower(s_info.win);
  282. }
  283.  
  284. /**
  285. * @brief Internal function which creates fully qualified path to the provided resource file.
  286. * @param[in] edj_file_in The file name.
  287. * @param[out] edj_path_out The fully qualified path to the edj_file_in file.
  288. */
  289. static void _get_app_resource(const char *edj_file_in, char *edj_path_out)
  290. {
  291. char *res_path = app_get_resource_path();
  292. if (res_path) {
  293. snprintf(edj_path_out, PATH_MAX, "%s%s", res_path, edj_file_in);
  294. free(res_path);
  295. }
  296. }
  297.  
  298. /**
  299. * @brief Internal function creates an application's icons based on provided icon's path.
  300. * @param[in] parent The parent object for an icon to be created.
  301. * @param[in] image_path The fully qualified path to the application's icon to be displayed.
  302. * @return This function returns an icon if it was successfully created,
  303. * otherwise NULL is returned.
  304. */
  305. static Evas_Object *_create_icon(Evas_Object *parent, char *image_path)
  306. {
  307. Evas_Object *icon = elm_image_add(parent);
  308. if (!icon) {
  309. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create an image");
  310. return NULL;
  311. }
  312.  
  313. elm_image_file_set(icon, image_path, NULL);
  314. evas_object_show(icon);
  315.  
  316. return icon;
  317. }
  318.  
  319. /**
  320. * @brief Internal function handling user gestures over an applications icon.
  321. * The following gestures are supported:
  322. * - tap - item clicked callback function is invoked.
  323. * - swipe left/right - removes the swiped application form the list.
  324. * @param[in] data The user data passed to the callback attachment function evas_object_event_callback_add().
  325. * @param[in] e The evas surface where the event took place.
  326. * @param[in] obj The object invoking this callback function.
  327. * @param[in] event_info The structure containing the information on this event.
  328. */
  329. static void _item_layout_mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
  330. {
  331. Evas_Object *edje = NULL;
  332. Elm_Object_Item *genlist_item = NULL;
  333. double dx = 0;
  334. Evas_Event_Mouse_Up *mouse_up_ev = (Evas_Event_Mouse_Up *)event_info;
  335.  
  336. edje = elm_layout_edje_get(obj);
  337. edje_object_part_drag_value_get(edje, ITEM_PART_BASE, &dx, NULL);
  338.  
  339. if ((int)dx == 0) {
  340. /* Item was not dragged left/right - item was clicked, resume application */
  341. genlist_item = elm_genlist_at_xy_item_get(s_info.genlist, mouse_up_ev->canvas.x, mouse_up_ev->canvas.y, NULL);
  342. if (!genlist_item) {
  343. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get item at %d, %d", mouse_up_ev->canvas.x, mouse_up_ev->canvas.y);
  344. return;
  345. }
  346.  
  347. app_item_t *item = (app_item_t *)elm_object_item_data_get(genlist_item);
  348. if (!item) {
  349. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get item data");
  350. return;
  351. }
  352. if (s_info.item_clicked_callback)
  353. s_info.item_clicked_callback(item->app_id);
  354.  
  355. } else if (dx < ITEM_DRAG_OUTSIDE_VAL && dx > -ITEM_DRAG_OUTSIDE_VAL) {
  356. /* Item was dragged, but not far enough to terminate application */
  357. elm_layout_signal_emit(obj, ITEM_PROGRAM_RESET_POSITION_SIGNAL, ITEM_PROGRAM_RESET_POSITION_SOURCE);
  358. } else {
  359. /* Item was dragged to left/right edge of the screen - terminate application */
  360. elm_layout_signal_emit(obj, ITEM_PROGRAM_HIDE_SIGNAL, ITEM_PROGRAM_HIDE_SOURCE);
  361.  
  362. genlist_item = elm_genlist_at_xy_item_get(s_info.genlist, mouse_up_ev->canvas.x, mouse_up_ev->canvas.y, NULL);
  363. if (!genlist_item) {
  364. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get item at %d, %d", mouse_up_ev->canvas.x, mouse_up_ev->canvas.y);
  365. return;
  366. }
  367.  
  368. _delete_item(genlist_item);
  369.  
  370. if (elm_genlist_items_count(s_info.genlist) == 0)
  371. _view_display_no_applications();
  372. }
  373. }
  374.  
  375. /**
  376. * @brief Internal function which creates the list item's layout where the
  377. * information is displayed (application's icon and identifier).
  378. * @param[in] parent The parent object for a layout to be created.
  379. * @param[in] app_id The application identifier to be displayed.
  380. * @param[in] icon_path The application's icon to be displayed.
  381. * @return This function returns a layout object if it was successfully created,
  382. * otherwise NULL is returned.
  383. */
  384. static Evas_Object *_create_item_layout(Evas_Object *parent, char *app_id, char *icon_path)
  385. {
  386. Evas_Object *icon = NULL;
  387. Evas_Object *layout = NULL;
  388. char edj_path[PATH_MAX] = {0, };
  389.  
  390. _get_app_resource(ITEM_EDJ, edj_path);
  391.  
  392. layout = elm_layout_add(parent);
  393. if (!layout) {
  394. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create layout");
  395. return NULL;
  396. }
  397.  
  398. elm_layout_file_set(layout, edj_path, GENLIST_CUSTOM_ITEM_GROUP);
  399. evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
  400. evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
  401.  
  402. evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_UP, _item_layout_mouse_up_cb, NULL);
  403.  
  404. icon = _create_icon(parent, icon_path);
  405. elm_object_part_content_set(layout, ITEM_PART_CONTENT, icon);
  406. elm_object_part_text_set(layout, ITEM_PART_TEXT, app_id);
  407.  
  408. evas_object_show(layout);
  409.  
  410. return layout;
  411. }
  412.  
  413. /**
  414. * @brief Internal callback function invoked on list's item display.
  415. * This function is responsible for non-text objects handling and it is assigned
  416. * to the func.content_get handler of genlist item's class structure.
  417. * In the content area of an genlist item, the application's icon is displayed.
  418. * @param[in] data The user data passed to the elm_genlist_item_append() function.
  419. * @param[in] obj The object invoking this callback function.
  420. * @param[in] part The name of the item's part being rendered.
  421. * @return The list's item layout is returned if it was successfully created,
  422. * otherwise NULL is returned.
  423. */
  424. static Evas_Object *_get_item_content(void *data, Evas_Object *obj, const char *part)
  425. {
  426. if (!data)
  427. return NULL;
  428.  
  429. app_item_t *item = (app_item_t *)data;
  430.  
  431. return _create_item_layout(obj, item->app_id, item->icon_path);
  432. }
  433.  
  434. /**
  435. * @brief Internal function which creates a genlist object and related item class.
  436. * The newly created genlist is set to the window object.
  437. * @return The function returns genlist object if it was created successfully,
  438. * otherwise 'NULL' is returned.
  439. */
  440. static Evas_Object *_create_genlist(void)
  441. {
  442. Evas_Object *genlist = elm_genlist_add(s_info.win);
  443. if (!genlist) {
  444. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create genlist");
  445. return NULL;
  446. }
  447.  
  448. s_info.item_class = elm_genlist_item_class_new();
  449. if (!s_info.item_class) {
  450. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to create item class");
  451. evas_object_del(genlist);
  452. return NULL;
  453. }
  454.  
  455. s_info.item_class->item_style = "full";
  456. s_info.item_class->func.text_get = NULL;
  457. s_info.item_class->func.content_get = _get_item_content;
  458. s_info.item_class->func.state_get = NULL;
  459. s_info.item_class->func.del = NULL;
  460.  
  461. elm_genlist_mode_set(genlist, ELM_LIST_SCROLL);
  462. elm_genlist_select_mode_set(genlist, ELM_OBJECT_SELECT_MODE_NONE);
  463.  
  464. elm_object_part_content_set(s_info.layout, TASKMGR_PART_CONTENT, genlist);
  465.  
  466. return genlist;
  467. }
  468.  
  469. /**
  470. * @brief Internal function responsible for list's item removal and item
  471. * delete callback invocation.
  472. */
  473. static void _delete_item(Elm_Object_Item *genlist_item)
  474. {
  475. app_item_t *item = (app_item_t *)elm_object_item_data_get(genlist_item);
  476. if (!item) {
  477. dlog_print(DLOG_ERROR, LOG_TAG, "Failed to get item data");
  478. return;
  479. }
  480.  
  481. if (s_info.item_deleted_callback)
  482. s_info.item_deleted_callback(item->app_id);
  483.  
  484. elm_object_item_del(genlist_item);
  485. }