The source code moved from the SPIN with license changed to Flora 1.1
[apps/native/home/homescreen-efl.git] / src / dynamic_index.c
1 /*
2  * Copyright 2012  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 "dynamic_index.h"
18
19 #include <stdbool.h>
20 #include <Elementary.h>
21
22 #include "homescreen-efl.h"
23 #include "util.h"
24 #include "livebox/livebox_panel.h"
25 #include "layout.h"
26
27 static Evas_Object *__dynamic_index_create_indice(Evas_Object *box);
28 static Eina_Bool __dynamic_index_fill_box(dynamic_index_t *dynamic_index);
29
30 static void __dynamic_index_page_count_changed_cb(void *data, Evas_Object *obj, const char *emission, const char *source);
31 static void __dynamic_index_page_area_changed_cb(void *data, Evas_Object *obj, void *event_info);
32
33 static void __dynamic_index_current_page_changed_start_cb(void *data, Evas_Object *obj, void *event_info);
34 static void __dynamic_index_current_page_changed_stop_cb(void *data, Evas_Object *obj, void *event_info);
35 static void __dynamic_index_set_properties(Evas_Object *index, double percent);
36 static Evas_Object *__dynamic_index_box_create(void);
37 static void __dynamic_index_rotate(Evas_Object *element, double angle, double alpha);
38
39 HAPI dynamic_index_t *dynamic_index_new(Evas_Object *page_scroller)
40 {
41         dynamic_index_t *dynamic_index = NULL;
42         Evas_Object *box = NULL;
43
44         if (!page_scroller) {
45                 LOGD("Invalid parameter : page_scroller is NULL");
46                 return NULL;
47         }
48
49         dynamic_index = (dynamic_index_t *) malloc (sizeof(dynamic_index_t));
50         if (!dynamic_index)
51                 return NULL;
52
53         box = __dynamic_index_box_create();
54
55         dynamic_index->scroller = page_scroller;
56         dynamic_index->box = box;
57         dynamic_index->page_count = page_scroller_get_page_count(page_scroller);
58         dynamic_index->page_current = page_scroller_get_current_page(page_scroller);
59
60         elm_scroller_page_size_get(page_scroller, &dynamic_index->page_width, NULL);
61         elm_scroller_region_get(page_scroller, &dynamic_index->x_current, NULL, NULL, NULL);
62
63         if (!__dynamic_index_fill_box(dynamic_index)) {
64                 LOGD("Box fill failed");
65                 evas_object_del(box);
66                 free(dynamic_index);
67                 return NULL;
68         }
69
70         elm_object_signal_callback_add(page_scroller, "scroller,count,changed", "*", __dynamic_index_page_count_changed_cb, dynamic_index);
71         evas_object_smart_callback_add(page_scroller, "scroll", __dynamic_index_page_area_changed_cb, dynamic_index);
72
73         evas_object_smart_callback_add(page_scroller, "scroll,drag,start", __dynamic_index_current_page_changed_start_cb, dynamic_index);
74         evas_object_smart_callback_add(page_scroller, "scroll,anim,stop", __dynamic_index_current_page_changed_stop_cb, dynamic_index);
75
76         evas_object_data_set(page_scroller, KEY_INDEX, dynamic_index);
77
78         return dynamic_index;
79 }
80
81 HAPI void dynamic_index_clear(dynamic_index_t *dynamic_index)
82 {
83         int i = 0;
84
85         if (!dynamic_index) {
86                 LOGE("Invalid parameter");
87                 return;
88         }
89
90         for (i = 0; i < dynamic_index->page_count; i++) {
91                 if (dynamic_index->indices[i]) {
92                         evas_object_del(dynamic_index->indices[i]);
93                         dynamic_index->indices[i] = NULL;
94                 }
95         }
96
97         elm_box_clear(dynamic_index->box);
98 }
99
100 HAPI void dynamic_index_del(dynamic_index_t *dynamic_index)
101 {
102         if (!dynamic_index) {
103                 LOGE("[INVALID_PARAM][dynamic_index='%p']", dynamic_index);
104                 return;
105         }
106
107         elm_object_signal_callback_del(dynamic_index->scroller, "scroller,count,changed", "*", __dynamic_index_page_count_changed_cb);
108
109         evas_object_smart_callback_del(dynamic_index->scroller, "scroll", __dynamic_index_page_area_changed_cb);
110         evas_object_smart_callback_del(dynamic_index->scroller, "scroll,drag,start", __dynamic_index_current_page_changed_start_cb);
111         evas_object_smart_callback_del(dynamic_index->scroller, "scroll,anim,stop", __dynamic_index_current_page_changed_stop_cb);
112
113         dynamic_index_clear(dynamic_index);
114         free(dynamic_index);
115 }
116
117 HAPI void dynamic_index_reload(dynamic_index_t *dynamic_index, int idx, int page_count)
118 {
119         if (!dynamic_index) {
120                 LOGE("[INVALID_PARAMS]");
121                 return;
122         }
123
124         dynamic_index_clear(dynamic_index);
125         dynamic_index->page_current = idx;
126         dynamic_index->page_count = page_count;
127
128         __dynamic_index_fill_box(dynamic_index);
129 }
130
131 static Evas_Object *__dynamic_index_create_indice(Evas_Object *box)
132 {
133         Evas_Object *layout = NULL;
134         Evas_Object *size_setter_rect = NULL;
135
136         int idx_width = (INDEX_ELEMENT_CONTAINER_WIDTH / ROOT_WIN_W) * home_screen_get_root_width();
137         int idx_height = (INDEX_ELEMENT_CONTAINER_HEIGHT / ROOT_WIN_H) * home_screen_get_root_height();
138
139
140         if (!box) {
141                 LOGD("Invalid argument : box is NULL");
142                 return NULL;
143         }
144
145         layout = elm_layout_add(box);
146         if (!layout) {
147                 LOGD("Layout creation failed");
148                 return NULL;
149         }
150
151         if (!elm_layout_file_set(layout, INDEX_EDJE, GROUP_INDEX_ELEMENT)) {
152                 evas_object_del(layout);
153                 return NULL;
154         }
155
156         size_setter_rect = evas_object_rectangle_add(evas_object_evas_get(home_screen_get_win()));
157         if (!size_setter_rect) {
158                 LOGE("Failed to create size setter rectangle");
159                 return NULL;
160         }
161
162         elm_object_part_content_set(layout, INDICE_SIZE_SETTER, size_setter_rect);
163
164         evas_object_color_set(size_setter_rect, 0, 0, 0, 0);
165         evas_object_size_hint_min_set(size_setter_rect, idx_width, idx_height);
166         evas_object_size_hint_max_set(size_setter_rect, idx_width, idx_height);
167         evas_object_resize(size_setter_rect, idx_width, idx_height);
168
169         evas_object_show(layout);
170         elm_box_pack_end(box, layout);
171
172         return layout;
173 }
174
175 static void __dynamic_index_set_properties(Evas_Object *index, double percent)
176 {
177         double size = (percent*INDEX_CURRENT_SIZE+(1.0-percent)*INDEX_NORMAL_SIZE)*home_screen_get_root_width();
178         evas_object_size_hint_min_set(index, size, size);
179         evas_object_size_hint_max_set(index, size, size);
180         evas_object_color_set(index, 255, 255, 255, percent*INDEX_CURRENT_ALPHA+(1.0-percent)*INDEX_NORMAL_ALPHA);
181 }
182
183 static Eina_Bool __dynamic_index_fill_box(dynamic_index_t *dynamic_index)
184 {
185         int i = 0, c_page = -1;
186
187         Evas_Object *layout = NULL;
188
189         if (!dynamic_index)
190                 return EINA_FALSE;
191
192         if (!dynamic_index->box || dynamic_index->page_count < 1) {
193                 LOGD("Invalid parameters : box is NULL or elements_count is < 1");
194                 return EINA_FALSE;
195         }
196
197         c_page = dynamic_index->page_current;
198         if(c_page < 0 || c_page > dynamic_index->page_count)
199         {
200                 LOGE("Failed to get current_page ");
201                 return EINA_FALSE;
202         }
203
204         for (i = 0 ; i < dynamic_index->page_count; i++) {
205                 layout = __dynamic_index_create_indice(dynamic_index->box);
206                 if (!layout) {
207                         LOGE("Failed to append index element into the box");
208                         dynamic_index_clear(dynamic_index);
209                         return EINA_FALSE;
210                 }
211
212                 dynamic_index->indices[i] = layout;
213         }
214
215         elm_layout_signal_emit(dynamic_index->indices[c_page], SIGNAL_SET_CURRENT, SIGNAL_SOURCE);
216         __dynamic_index_set_properties(dynamic_index->indices[dynamic_index->page_current], 1.0);
217
218         return EINA_TRUE;
219 }
220
221 static void __dynamic_index_page_count_changed_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
222 {
223         LOGD("The page count has changed");
224         dynamic_index_t *dynamic_index = (dynamic_index_t *)data;
225         dynamic_index_clear(dynamic_index);
226         dynamic_index->page_count = page_scroller_get_page_count(dynamic_index->scroller);
227
228         LOGD("page count : %d ", dynamic_index->page_count);
229
230         if (!dynamic_index->page_count)
231                 return;
232
233         dynamic_index->page_current = page_scroller_get_current_page(dynamic_index->scroller);
234
235         if (!__dynamic_index_fill_box(dynamic_index)) {
236                 elm_object_signal_callback_del(dynamic_index->scroller, "scroller,count,changed", "*", __dynamic_index_page_count_changed_cb);
237                 evas_object_smart_callback_del(dynamic_index->scroller, "scroll", __dynamic_index_page_area_changed_cb);
238                 evas_object_smart_callback_del(dynamic_index->scroller, "scroll,drag,start", __dynamic_index_current_page_changed_start_cb);
239                 evas_object_smart_callback_del(dynamic_index->scroller, "scroll,anim,stop", __dynamic_index_current_page_changed_stop_cb);
240         }
241 }
242
243 HAPI double _dist(int current, int page_x, int page_width)
244 {
245         return 1.0-((double)fabs(page_x-current))/page_width;
246 }
247
248 static void __dynamic_index_page_area_changed_cb(void *data, Evas_Object *obj, void *event_info)
249 {
250         int x = 0;
251         double angle = 0.0;
252         double color = 0.0;
253         int next_page = -1;
254
255         dynamic_index_t *dynamic_index = (dynamic_index_t*) data;
256         if(!dynamic_index)
257         {
258                 LOGE("Invalid dynamic_index");
259                 return;
260         }
261         elm_scroller_region_get(obj, &x, NULL, NULL, NULL);
262
263         angle = (double)(x - dynamic_index->x_current)/dynamic_index->page_width * 90.0;
264
265         if(fabs(x - dynamic_index->x_current) <= dynamic_index->page_width)
266         {
267                 next_page = x > dynamic_index->x_current ? (dynamic_index->page_current+1) % dynamic_index->page_count : dynamic_index->page_current-1;
268                 color = fabs(angle) * 2;
269         }
270         else
271         {
272                 if(x > dynamic_index->x_current)
273                 {
274                         next_page = dynamic_index->page_count-1;
275                         color = (double)(dynamic_index->page_width*dynamic_index->page_count - x)/dynamic_index->page_width * 180.0;
276                 }
277                 else
278                 {
279                         next_page = 0;
280                         color = 180.0;
281                 }
282         }
283
284         if (next_page == dynamic_index->page_count - 1 && dynamic_index->page_current == 0 && dynamic_index->page_count % 2 == 1)
285                 angle = angle - 270.0;
286
287         __dynamic_index_rotate(dynamic_index->indices[dynamic_index->page_current], 90.0 + angle, 255.0 - color);
288         __dynamic_index_rotate(dynamic_index->indices[next_page], angle, 75.0 + color);
289 }
290
291 static Evas_Object *__dynamic_index_box_create(void)
292 {
293         Evas_Object *box = NULL;
294
295         box = elm_box_add(home_screen_get_win());
296         if (!box) {
297                 LOGD("Box creation failed");
298                 return NULL;
299         }
300
301         elm_box_homogeneous_set(box, EINA_TRUE);
302         elm_box_horizontal_set(box, EINA_TRUE);
303
304         evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
305
306         elm_box_align_set(box, 0.5, 0.5);
307         evas_object_show(box);
308
309         return box;
310 }
311
312 static void __dynamic_index_current_page_changed_start_cb(void *data, Evas_Object *obj, void *event_info)
313 {
314         dynamic_index_t *dynamic_index = (dynamic_index_t*) data;
315         if(!dynamic_index)
316         {
317                 LOGE("Invalid data");
318                 return;
319         }
320
321         elm_scroller_current_page_get(obj, &dynamic_index->page_current, NULL);
322         elm_scroller_region_get(obj, &dynamic_index->x_current, NULL, NULL, NULL);
323 }
324
325 static void __dynamic_index_current_page_changed_stop_cb(void *data, Evas_Object *obj, void *event_info)
326 {
327         dynamic_index_t *dynamic_index = (dynamic_index_t*)data;
328         int i;
329
330         if(!dynamic_index)
331         {
332                 LOGE("Invalid data");
333                 return;
334         }
335
336         elm_scroller_current_page_get(obj, &dynamic_index->page_current, NULL);
337         for(i = 0; i<dynamic_index->page_current; i++)
338         {
339                 elm_object_signal_emit(dynamic_index->indices[i], SIGNAL_SET_DEFAULT, SIGNAL_SOURCE);
340         }
341         elm_object_signal_emit(dynamic_index->indices[dynamic_index->page_current], SIGNAL_SET_CURRENT, SIGNAL_SOURCE);
342         for(i = dynamic_index->page_current+1; i<dynamic_index->page_count; i++)
343         {
344                 elm_object_signal_emit(dynamic_index->indices[i], SIGNAL_SET_DEFAULT, SIGNAL_SOURCE);
345         }
346 }
347
348 static void __dynamic_index_rotate(Evas_Object *element, double angle, double alpha)
349 {
350         Evas_Object *edje = NULL;
351
352         if(!element)
353         {
354                 LOGE("Invalid argument : element is NULL");
355                 return;
356         }
357
358         edje = elm_layout_edje_get(element);
359         if(!edje)
360         {
361                 LOGE("Failed to get edje from layout");
362                 return;
363         }
364
365         Edje_Message_Float_Set *msg = malloc(sizeof(*msg) + sizeof(double));
366         msg->count = 2;
367         msg->val[0] = angle;
368         msg->val[1] = alpha;
369
370         edje_object_message_send(edje, EDJE_MESSAGE_FLOAT_SET, 1, msg);
371         edje_object_signal_emit(edje, "rot_changed", "ly");
372
373         free(msg);
374 }
375