migrate to Tizen 3.0 SDK
[apps/core/preloaded/taskmanager.git] / src / scroller.c
1 /*
2  *  Task Manager
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20  #include <Elementary.h>
21
22  #include "conf.h"
23  #include "item.h"
24  #include "list.h"
25  #include "log.h"
26  #include "main.h"
27  #include "scroller.h"
28  #include "util.h"
29
30 #define PRIVATE_DATA_KEY_DRAG "pri_drag"
31 #define PRIVATE_DATA_KEY_MOUSE_DOWN "pri_m_dw"
32 #define PRIVATE_DATA_KEY_POP_ALL_TIMER "pri_pop_tm"
33 #define PRIVATE_DATA_KEY_REVERSE_LIST "pri_re_li"
34 #define PRIVATE_DATA_KEY_TERMINATE "pri_tm"
35
36
37
38 task_mgr_error_e scroller_push_item(Evas_Object *scroller, Evas_Object *item)
39 {
40         _D("");
41         retv_if(!scroller, TASK_MGR_ERROR_INVALID_PARAMETER);
42         retv_if(!item, TASK_MGR_ERROR_INVALID_PARAMETER);
43
44         Evas_Object *box_layout = NULL;
45         Evas_Object *box = NULL;
46
47         box_layout = elm_object_content_get(scroller);
48         retv_if(!box_layout, TASK_MGR_ERROR_FAIL);
49
50         box = elm_object_part_content_get(box_layout, BOX_GROUP_NAME);
51         retv_if(!box, TASK_MGR_ERROR_FAIL);
52
53         elm_box_pack_end(box, item);
54
55         return TASK_MGR_ERROR_NONE;
56 }
57
58
59
60 void scroller_pop_item(Evas_Object *scroller, Evas_Object *item, int terminate)
61 {
62         ret_if(!scroller);
63         ret_if(!item);
64
65         Evas_Object *box_layout = NULL;
66         Evas_Object *box = NULL;
67         Evas_Object *tmp_item = NULL;
68
69         Eina_List *list = NULL;
70         const Eina_List *l = NULL;
71         const Eina_List *ln = NULL;
72
73         box_layout = elm_object_content_get(scroller);
74         ret_if(!box_layout);
75
76         box = elm_object_part_content_get(box_layout, BOX_GROUP_NAME);
77         ret_if(!box);
78
79         list = elm_box_children_get(box);
80         ret_if(!list);
81
82         EINA_LIST_FOREACH_SAFE(list, l, ln, tmp_item) {
83                 if (item != tmp_item) continue;
84                 if (terminate) item_terminate(item);
85
86                 elm_box_unpack(box, item);
87                 item_destroy(item);
88                 break;
89         }
90         eina_list_free(list);
91 }
92
93
94
95 task_mgr_error_e scroller_push_all_item(Evas_Object *scroller, Eina_List *list)
96 {
97         const Eina_List *l = NULL;
98         const Eina_List *ln = NULL;
99         list_type_default_s *info = NULL;
100         Evas_Object *item = NULL;
101
102         if (!list) {
103                 _D("No app in the history list");
104                 return TASK_MGR_ERROR_NONE;
105         }
106
107         EINA_LIST_FOREACH_SAFE(list, l, ln, info) {
108                 if (!info) continue;
109                 item = item_create(scroller, info);
110                 continue_if(!item);
111                 scroller_push_item(scroller, item);
112         }
113
114         return TASK_MGR_ERROR_NONE;
115 }
116
117
118
119 static Eina_Bool _pop_all_item_cb(void *data)
120 {
121         Evas_Object *scroller = data;
122         Evas_Object *item = NULL;
123         Eina_List *list = NULL;
124         static int i = 0;
125         int count = 0;
126         int terminate = (int) evas_object_data_get(scroller, PRIVATE_DATA_KEY_TERMINATE);
127
128         list = evas_object_data_get(scroller, PRIVATE_DATA_KEY_REVERSE_LIST);
129         goto_if(!list, END);
130
131         count = eina_list_count(list);
132         _D("remove list count(include clear button) : %d", count);
133         if (i >= count-1) goto END;
134
135         item = eina_list_nth(list, i);
136         i++;
137         goto_if(!item, END);
138
139         scroller_pop_item(scroller, item, terminate);
140         return ECORE_CALLBACK_RENEW;
141
142 END:
143         i = 0;
144         eina_list_free(list);
145         evas_object_data_del(scroller, PRIVATE_DATA_KEY_REVERSE_LIST);
146         evas_object_data_del(scroller, PRIVATE_DATA_KEY_TERMINATE);
147         evas_object_data_del(scroller, PRIVATE_DATA_KEY_POP_ALL_TIMER);
148         item_clear_set_disable(scroller);
149
150         return ECORE_CALLBACK_CANCEL;
151 }
152
153
154
155 void scroller_pop_all_item(Evas_Object *scroller, int terminate)
156 {
157         Evas_Object *box_layout = NULL;
158         Evas_Object *box = NULL;
159         Eina_List *list = NULL;
160         Eina_List *reverse_list = NULL;
161         Ecore_Timer *timer = NULL;
162
163         ret_if(!scroller);
164
165         timer = evas_object_data_del(scroller, PRIVATE_DATA_KEY_POP_ALL_TIMER);
166         if (timer) {
167                 _D("There is already a timer for popping all items.");
168                 ecore_timer_del(timer);
169         }
170
171         /* An user tap the end all button, all items have to be terminated even if paused. */
172         if (!evas_object_data_get(scroller, PRIVATE_DATA_KEY_TERMINATE)) {
173                 evas_object_data_set(scroller, PRIVATE_DATA_KEY_TERMINATE, (void *) terminate);
174         }
175
176         box_layout = elm_object_content_get(scroller);
177         ret_if(!box_layout);
178
179         box = elm_object_part_content_get(box_layout, BOX_GROUP_NAME);
180         ret_if(!box);
181
182         list = elm_box_children_get(box);
183         if (!list) return;
184
185         /* This reverse list should be freed in the timer */
186         reverse_list = eina_list_reverse_clone(list);
187         eina_list_free(list);
188         ret_if(!reverse_list);
189         evas_object_data_set(scroller, PRIVATE_DATA_KEY_REVERSE_LIST, reverse_list);
190
191         timer = ecore_timer_add(0.01f, _pop_all_item_cb, scroller);
192         if (!timer) {
193                 _E("Cannot add a timer");
194                 evas_object_data_del(scroller, PRIVATE_DATA_KEY_REVERSE_LIST);
195                 evas_object_data_del(scroller, PRIVATE_DATA_KEY_TERMINATE);
196                 eina_list_free(reverse_list);
197                 return;
198         }
199
200         evas_object_data_set(scroller, PRIVATE_DATA_KEY_POP_ALL_TIMER, timer);
201 }
202
203
204
205 int scroller_count(Evas_Object *scroller)
206 {
207         Evas_Object *box_layout = NULL;
208         Evas_Object *box = NULL;
209         Eina_List *list = NULL;
210
211         retv_if(!scroller, 0);
212
213         box_layout = elm_object_content_get(scroller);
214         retv_if(!box_layout, 0);
215
216         box = elm_object_part_content_get(box_layout, BOX_GROUP_NAME);
217         retv_if(!box, 0);
218
219         list = elm_box_children_get(box);
220         if (!list) {
221                 _D("list is null");
222                 return 0;
223         }
224
225         return eina_list_count(list);
226 }
227
228
229
230 Eina_Bool scroller_is_scrolling(Evas_Object *scroller)
231 {
232         return evas_object_data_get(scroller, DATA_KEY_IS_SCROLLING)? EINA_TRUE:EINA_FALSE;
233 }
234
235
236
237 void scroller_freeze(Evas_Object *scroller)
238 {
239         Evas_Object *box_layout = NULL;
240         Evas_Object *box = NULL;
241
242         ret_if(!scroller);
243
244         box_layout = elm_object_content_get(scroller);
245         ret_if(!box_layout);
246
247         box = elm_object_part_content_get(box_layout, BOX_GROUP_NAME);
248         ret_if(!box);
249
250         elm_object_scroll_freeze_push(box);
251 }
252
253
254
255 void scroller_unfreeze(Evas_Object *scroller)
256 {
257         Evas_Object *box_layout = NULL;
258         Evas_Object *box = NULL;
259
260         ret_if(!scroller);
261
262         box_layout = elm_object_content_get(scroller);
263         ret_if(!box_layout);
264
265         box = elm_object_part_content_get(box_layout, BOX_GROUP_NAME);
266         ret_if(!box);
267
268         while (elm_object_scroll_freeze_get(box)) {
269                 elm_object_scroll_freeze_pop(box);
270         }
271 }
272
273
274
275 static void _mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
276 {
277         _D("Mouse is down");
278         evas_object_data_set(obj, PRIVATE_DATA_KEY_MOUSE_DOWN, (void *) 1);
279 }
280
281
282
283 static void _mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
284 {
285         _D("Mouse is up");
286         evas_object_data_del(obj, PRIVATE_DATA_KEY_MOUSE_DOWN);
287         if (evas_object_data_get(obj, PRIVATE_DATA_KEY_DRAG)) return;
288         evas_object_data_del(obj, DATA_KEY_IS_SCROLLING);
289 }
290
291
292
293 static void _anim_start_cb(void *data, Evas_Object *scroller, void *event_info)
294 {
295         _D("start the scroller animation");
296         evas_object_data_set(scroller, DATA_KEY_IS_SCROLLING, (void *) 1);
297 }
298
299
300
301 static void _anim_stop_cb(void *data, Evas_Object *scroller, void *event_info)
302 {
303         _D("stop the scroller animation");
304         if (evas_object_data_get(scroller, PRIVATE_DATA_KEY_MOUSE_DOWN)) return;
305         evas_object_data_del(scroller, DATA_KEY_IS_SCROLLING);
306 }
307
308
309
310 static void _drag_start_cb(void *data, Evas_Object *scroller, void *event_info)
311 {
312         _D("start to drag the scroller animation");
313         evas_object_data_set(scroller, PRIVATE_DATA_KEY_DRAG, (void *) 1);
314 }
315
316
317
318 static void _drag_stop_cb(void *data, Evas_Object *scroller, void *event_info)
319 {
320         _D("stop to drag the scroller animation");
321         evas_object_data_del(scroller, PRIVATE_DATA_KEY_DRAG);
322 }
323
324
325
326 static void _scroll_cb(void *data, Evas_Object *scroller, void *event_info)
327 {
328         evas_object_data_set(scroller, DATA_KEY_IS_SCROLLING, (void *) 1);
329 }
330
331
332
333 Evas_Object *scroller_create(Evas_Object *layout)
334 {
335         retv_if(!layout, NULL);
336
337         Evas_Object *box = NULL;
338         Evas_Object *box_layout = NULL;
339         Evas_Object *scroller = NULL;
340
341         scroller = elm_scroller_add(layout);
342         retv_if(!scroller, NULL);
343
344         elm_scroller_bounce_set(scroller, EINA_FALSE, EINA_FALSE);
345         elm_scroller_policy_set(scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
346         //elm_object_style_set(scroller, "list_effect");
347         elm_object_focus_allow_set(scroller, EINA_FALSE);
348         elm_object_part_content_set(layout, "scroller", scroller);
349         evas_object_show(scroller);
350
351         evas_object_event_callback_add(scroller, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, NULL);
352         evas_object_event_callback_add(scroller, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, NULL);
353         evas_object_smart_callback_add(scroller, "scroll,anim,start", _anim_start_cb, NULL);
354         evas_object_smart_callback_add(scroller, "scroll,anim,stop", _anim_stop_cb, NULL);
355         evas_object_smart_callback_add(scroller, "scroll,drag,start", _drag_start_cb, NULL);
356         evas_object_smart_callback_add(scroller, "scroll,drag,stop", _drag_stop_cb, NULL);
357         evas_object_smart_callback_add(scroller, "scroll", _scroll_cb, NULL);
358         /* Because change an align in box, use the layout betweein box and scroller. */
359
360         box_layout = elm_layout_add(scroller);
361         if (!box_layout) {
362                 _E("Fail to create box layout");
363                 evas_object_del(scroller);
364                 return NULL;
365         }
366         elm_layout_file_set(box_layout, util_get_file_path(APP_DIR_RESOURCE, BOX_LAYOUT_EDJ), BOX_GROUP_NAME);
367         evas_object_size_hint_align_set(box_layout, 0.5, 1.0);
368         evas_object_size_hint_weight_set(box_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
369         evas_object_show(box_layout);
370         elm_object_content_set(scroller, box_layout);
371
372         box = elm_box_add(scroller);
373         if (!box) {
374                 _E("Fail to create box");
375                 evas_object_del(box_layout);
376                 evas_object_del(scroller);
377                 return NULL;
378         }
379         elm_box_horizontal_set(box, EINA_FALSE);
380         evas_object_size_hint_align_set(box, 0.5, 1.0);
381         evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
382         elm_object_part_content_set(box_layout, BOX_GROUP_NAME, box);
383         evas_object_show(box);
384         main_get_info()->box = box;
385
386         return scroller;
387 }
388
389
390
391 void scroller_destroy(Evas_Object *scroller)
392 {
393         ret_if(!scroller);
394
395         Evas_Object *item = NULL;
396         Evas_Object *box_layout = NULL;
397         Evas_Object *box = NULL;
398         Eina_List *list = NULL;
399
400         ret_if(!scroller);
401         scroller_pop_all_item(scroller, 0);
402
403         box_layout = elm_object_content_unset(scroller);
404         ret_if(!box_layout);
405
406         box = elm_object_part_content_unset(box_layout, BOX_GROUP_NAME);
407         ret_if(!box);
408
409         list = elm_box_children_get(box);
410         if (!list) {
411                 _D("list is empty");
412                 return;
413         }
414
415         EINA_LIST_FREE(list, item) {
416                 if (!item) break;
417                 item_destroy(item);
418         }
419         free(list);
420
421         evas_object_del(box);
422         evas_object_del(box_layout);
423
424         evas_object_event_callback_del(scroller, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb);
425         evas_object_event_callback_del(scroller, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb);
426         evas_object_smart_callback_del(scroller, "scroll,anim,start", _anim_start_cb);
427         evas_object_smart_callback_del(scroller, "scroll,anim,stop", _anim_stop_cb);
428         evas_object_smart_callback_del(scroller, "scroll,drag,start", _drag_start_cb);
429         evas_object_smart_callback_del(scroller, "scroll,drag,stop", _drag_stop_cb);
430         evas_object_smart_callback_del(scroller, "scroll", _scroll_cb);
431
432         evas_object_del(scroller);
433 }
434
435
436
437 /* End of the file */