Change elm_exit to ui_app_exit
[platform/core/uifw/inputdelegator.git] / src / w-input-emoticon.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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 <app.h>
18 #include <app_preference.h>
19 #include <Elementary.h>
20 #include <string>
21 #include <vector>
22 #include <stdint.h>
23
24 #include <vconf.h>
25 #include <vconf-keys.h>
26
27 #include "Debug.h"
28 #include "w-input-selector.h"
29
30 #define RECENT_EMOJI_LIST "recent_emoji_list"
31
32 #define EMOTICON_CNT 180
33 #define RECENT_CNT 9
34
35 extern App_Data* app_data;
36
37 static int is_content_reuse_on = 0;
38
39
40 using namespace std;
41
42 vector <int> recent_emoji_list;
43
44 typedef struct {
45     int code;
46     const char* name;
47 }Emoticon;
48
49 static Elm_Object_Item *it_emoticon_empty = NULL;
50 static Elm_Object_Item *it_emoticon_recent_group = NULL;
51 static Elm_Object_Item *it_emoticon_emoji_group = NULL;
52 static Elm_Object_Item *it_last = NULL;
53
54 static Elm_Genlist_Item_Class *itc_emoticon = NULL;
55
56 #define INITAL_ITEM_UNIT 24
57 #define LOADING_ITEM_UNIT 27
58 static int loading_done_for_item = 0;
59 Ecore_Timer *lazy_loading_timer_for_items = NULL;
60
61 #define INITAL_CONTENT_UNIT 51
62 #define LOADING_CONTENT_UNIT 9
63 static int loading_done_for_contents = 0;
64 Ecore_Timer *lazy_loading_timer_for_contents = NULL;
65
66
67 typedef struct emoticon_content
68 {
69     int index;
70     Evas_Object *content;
71     int used;
72 } emoticon_content_s;
73
74 static emoticon_content_s emoticon_contents_pool[EMOTICON_CNT] = { 0, };
75 static emoticon_content_s emoticon_recents_pool[RECENT_CNT] = { 0, };
76
77
78 Emoticon emoticon_info[EMOTICON_CNT] = {
79     {0x1f600, ""},
80     {0x1f601, ""},
81     {0x1f602, ""},
82     {0x1f603, ""},
83     {0x1f604, ""},
84     {0x1f605, ""},
85     {0x1f606, ""},
86     {0x1f609, ""},
87     {0x1f60a, ""},
88     {0x1f60b, ""},
89     {0x1f60e, ""},
90     {0x1f60d, ""},
91     {0x1f618, ""},
92     {0x1f617, ""},
93     {0x1f619, ""},
94     {0x1f61a, ""},
95     {0x263a, ""},
96     {0x1f642, ""},
97     {0x1f917, ""},
98     {0x1f607, ""},
99     {0x1f914, ""},
100     {0x1f610, ""},
101     {0x1f611, ""},
102     {0x1f636, ""},
103     {0x1f644, ""},
104     {0x1f60f, ""},
105     {0x1f623, ""},
106     {0x1f625, ""},
107     {0x1f62e, ""},
108     {0x1f910, ""},
109     {0x1f62f, ""},
110     {0x1f634, ""},
111     {0x1f62a, ""},
112     {0x1f62b, ""},
113     {0x1f60c, ""},
114     {0x1f913, ""},
115     {0x1f61b, ""},
116     {0x1f61c, ""},
117     {0x1f61d, ""},
118     {0x1f641, ""},
119     {0x1f612, ""},
120     {0x1f613, ""},
121     {0x1f614, ""},
122     {0x1f615, ""},
123     {0x1f616, ""},
124     {0x1f643, ""},
125     {0x1f637, ""},
126     {0x1f912, ""},
127     {0x1f915, ""},
128     {0x1f911, ""},
129     {0x1f632, ""},
130     {0x1f61e, ""},
131     {0x1f61f, ""},
132     {0x1f624, ""},
133     {0x1f622, ""},
134     {0x1f62d, ""},
135     {0x1f626, ""},
136     {0x1f627, ""},
137     {0x1f628, ""},
138     {0x1f629, ""},
139     {0x1f62c, ""},
140     {0x1f630, ""},
141     {0x1f631, ""},
142     {0x1f633, ""},
143     {0x1f635, ""},
144     {0x1f621, ""},
145     {0x1f620, ""},
146     {0x1f608, ""},
147     {0x1f648, ""},
148     {0x1f649, ""},
149     {0x1f64a, ""},
150     {0x1f448, ""},
151     {0x1f449, ""},
152     {0x261d, ""},
153     {0x1f446, ""},
154     {0x1f595, ""},
155     {0x1f447, ""},
156     {0x270c, ""},
157     {0x1f596, ""},
158     {0x1f918, ""},
159     {0x1f591, ""},
160     {0x1f590, ""},
161     {0x270a, ""},
162     {0x270b, ""},
163     {0x1f44a, ""},
164     {0x1f44c, ""},
165     {0x1f44d, ""},
166     {0x1f44e, ""},
167     {0x1f592, ""},
168     {0x1f593, ""},
169     {0x1f44b, ""},
170     {0x1f44f, ""},
171     {0x1f450, ""},
172     {0x1f493, ""},
173     {0x1f494, ""},
174     {0x1f495, ""},
175     {0x1f496, ""},
176     {0x1f497, ""},
177     {0x1f49d, ""},
178     {0x1f49e, ""},
179     {0x1f49f, ""},
180     {0x2763, ""},
181     {0x1f35e, ""},
182     {0x1f9c0, ""},
183     {0x1f356, ""},
184     {0x1f357, ""},
185     {0x1f354, ""},
186     {0x1f35f, ""},
187     {0x1f355, ""},
188     {0x1f32d, ""},
189     {0x1f32e, ""},
190     {0x1f32f, ""},
191     {0x1f37f, ""},
192     {0x1f372, ""},
193     {0x1f371, ""},
194     {0x1f358, ""},
195     {0x1f359, ""},
196     {0x1f35a, ""},
197     {0x1f35c, ""},
198     {0x1f35b, ""},
199     {0x1f35d, ""},
200     {0x1f360, ""},
201     {0x1f362, ""},
202     {0x1f363, ""},
203     {0x1f364, ""},
204     {0x1f365, ""},
205     {0x1f361, ""},
206     {0x1f366, ""},
207     {0x1f368, ""},
208     {0x1f367, ""},
209     {0x1f369, ""},
210     {0x1f36a, ""},
211     {0x1f382, ""},
212     {0x1f370, ""},
213     {0x1f36b, ""},
214     {0x1f36c, ""},
215     {0x1f36d, ""},
216     {0x1f36e, ""},
217     {0x1f36f, ""},
218     {0x1f37c, ""},
219     {0x2615, ""},
220     {0x1f375, ""},
221     {0x1f376, ""},
222     {0x1f37e, ""},
223     {0x1f377, ""},
224     {0x1f378, ""},
225     {0x1f379, ""},
226     {0x1f37a, ""},
227     {0x1f37b, ""},
228     {0x1f383, ""},
229     {0x1f384, ""},
230     {0x1f388, ""},
231     {0x1f389, ""},
232     {0x1f38a, ""},
233     {0x26bd, ""},
234     {0x26be, ""},
235     {0x1f3c0, ""},
236     {0x1f3c8, ""},
237     {0x1f3c9, ""},
238     {0x1f3be, ""},
239     {0x1f3b1, ""},
240     {0x1f3b3, ""},
241     {0x26f3, ""},
242     {0x26f8, ""},
243     {0x1f3a3, ""},
244     {0x1f3bf, ""},
245     {0x1f3cf, ""},
246     {0x1f3d0, ""},
247     {0x1f3d1, ""},
248     {0x1f3d2, ""},
249     {0x1f3d3, ""},
250     {0x1f3f8, ""},
251     {0x1f3af, ""},
252     {0x1f3b2, ""},
253     {0x1f3df, ""},
254     {0x1f3db, ""},
255     {0x1f3e0, ""},
256     {0x1f3e2, ""},
257     {0x1f3e5, ""},
258     {0x1f3eb, ""},
259 };
260
261
262 //---------------------------------------------------------------------------------------//
263
264 static Eina_Bool _custom_back_cb2(void *data, Elm_Object_Item *it)
265 {
266     PRINTFUNC(DLOG_DEBUG, "");
267
268     if (is_content_reuse_on) {
269         int i;
270
271         if (lazy_loading_timer_for_items != NULL) {
272             ecore_timer_del(lazy_loading_timer_for_items);
273             lazy_loading_timer_for_items = NULL;
274         }
275
276         if (lazy_loading_timer_for_contents != NULL) {
277             ecore_timer_del(lazy_loading_timer_for_contents);
278             lazy_loading_timer_for_contents = NULL;
279         }
280
281         //Recent EMOTICONS : the recent emoiton need to be updated whenever emoticon view is generated, so deleted here.
282         for (i=0;i< RECENT_CNT;i++)
283         {
284             if (emoticon_recents_pool[i].used == 0 && emoticon_recents_pool[i].content) {
285                 evas_object_del(emoticon_recents_pool[i].content);
286             }
287             emoticon_recents_pool[i].content = NULL;
288         }
289     }
290
291     _back_to_genlist_for_selector();
292     return EINA_TRUE;
293 }
294
295
296 void get_recent_emoticons(vector <int> &emoticon_list)
297 {
298     int ret = PREFERENCE_ERROR_NONE;
299     char *str = NULL;
300
301     ret = preference_get_string(RECENT_EMOJI_LIST, &str);
302     if (PREFERENCE_ERROR_NONE != ret) {
303         PRINTFUNC(DLOG_ERROR, "preference_get_string error!(%d)", ret);
304     }
305
306     emoticon_list.clear();
307
308     PRINTFUNC(DLOG_DEBUG, "str = %s", str);
309
310     if (str != NULL) {
311         char *tok, *ptr;
312         tok = strtok_r(str, ",", &ptr);
313         while (tok != NULL) {
314             PRINTFUNC(DLOG_DEBUG, "tok = %s", tok);
315             emoticon_list.push_back(strtol(tok, (char **)NULL, 10));
316             tok = strtok_r(NULL, ",", &ptr);
317         }
318     }
319
320     if (str)
321         free(str);
322
323     return;
324 }
325
326 void set_recent_emoticons(vector <int> &emoticon_list, int val)
327 {
328     unsigned int i;
329     int ret = PREFERENCE_ERROR_NONE;
330
331     if (emoticon_list.size() > 0) {
332         for (i = 0; i < emoticon_list.size(); i++) {
333             PRINTFUNC(DLOG_DEBUG, "%d == %d", emoticon_list.at(i), val);
334
335             if (emoticon_list.at(i) == val) {
336                 emoticon_list.erase(emoticon_list.begin()+i);
337                 break;
338             }
339         }
340
341         if (emoticon_list.size() >= RECENT_CNT) {
342             emoticon_list.erase(emoticon_list.end());
343         }
344     }
345
346     emoticon_list.insert(emoticon_list.begin(), val);
347
348     string stored;
349     char str[10] = {0, };
350
351     for (i = 0; i < emoticon_list.size(); i++) {
352         snprintf(str, sizeof(str), "%d", emoticon_list.at(i));
353         stored += str;
354         if (i+1 != emoticon_list.size())
355             stored += ",";
356     }
357
358     PRINTFUNC(DLOG_DEBUG, "%s", stored.c_str());
359
360     ret = preference_set_string(RECENT_EMOJI_LIST, stored.c_str());
361     if (PREFERENCE_ERROR_NONE != ret) {
362         PRINTFUNC(DLOG_ERROR, "preference_set_string error!(%d)", ret);
363     }
364 }
365
366 static void _emoticon_item_clicked_cb(void *data, Evas_Object * obj, void *event_info)
367 {
368     int index = (uintptr_t)data;
369
370     PRINTFUNC(DLOG_DEBUG, "index = %d", index);
371
372     // store in recents list
373     set_recent_emoticons(recent_emoji_list, index);
374
375     int length;
376     const Eina_Unicode unicode_event[2] = { (Eina_Unicode)emoticon_info[index].code, 0 };
377     char* utf_8 = eina_unicode_unicode_to_utf8(unicode_event, &length);
378
379     reply_to_sender_by_callback((const char*)utf_8, "emoticon");
380
381     PRINTFUNC(SECURE_DEBUG, "[%d]%s", index, utf_8);
382     if (utf_8)
383         free(utf_8);
384
385     ui_app_exit();
386 }
387
388 Evas_Object* get_emoticon_button(Evas_Object* parent, int index){
389     if (parent == NULL)
390         return NULL;
391
392      Evas_Object* btn = elm_button_add(parent);
393      elm_object_style_set(btn, "emoticon");
394      evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
395      evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
396
397      int length;
398      const Eina_Unicode unicode_event[2] = { (Eina_Unicode)emoticon_info[index].code, 0 };
399      char* utf_8 = eina_unicode_unicode_to_utf8(unicode_event, &length);
400      elm_object_part_text_set(btn, "elm.text", utf_8);
401
402      if (utf_8)
403          free(utf_8);
404
405      evas_object_layer_set(btn, 32000);
406
407      evas_object_smart_callback_add(btn, "clicked", _emoticon_item_clicked_cb, (void *)(uintptr_t)index);
408
409      return btn;
410 }
411
412 Evas_Object* get_recent_emoticon_button(Evas_Object* parent, int index){
413     if (parent == NULL)
414         return NULL;
415
416      Evas_Object* btn = elm_button_add(parent);
417      elm_object_style_set(btn, "emoticon");
418      evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
419      evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
420
421      int length;
422      const Eina_Unicode unicode_event[2] = { (Eina_Unicode)emoticon_info[recent_emoji_list.at(index)].code, 0 };
423      char* utf_8 = eina_unicode_unicode_to_utf8(unicode_event, &length);
424      elm_object_part_text_set(btn, "elm.text", utf_8);
425
426      evas_object_data_set(btn, "index", (void*)(uintptr_t) recent_emoji_list.at(index));
427
428      if (utf_8)
429          free(utf_8);
430
431      evas_object_layer_set(btn, 32000);
432      evas_object_smart_callback_add(btn, "clicked", _emoticon_item_clicked_cb, (void*)(uintptr_t) recent_emoji_list.at(index));
433
434      return btn;
435 }
436
437 static void _emoticon_gl_lang_changed(void *data, Evas_Object *obj, void *event_info)
438 {
439     elm_genlist_realized_items_update(obj);
440 }
441
442 static char * __emoticon_gl_text_get(void *data, Evas_Object *obj, const char *part)
443 {
444     //PRINTFUNC(DLOG_DEBUG,"part = %s", part);
445
446     const char* str = (const char*) data;
447     if (!str)
448         return NULL;
449
450     if (!strcmp(part, "elm.text")) {
451         //PRINTFUNC(DLOG_DEBUG,"str = %s", str);
452         return strdup(gettext(str));
453     }
454     return NULL;
455 }
456
457 static void _emoticon_gl_content_unswallowed_cb(void *data, Evas_Object *obj, void *event_info)
458 {
459     Elm_Object_Item *it = (Elm_Object_Item *)event_info;
460
461     const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(it);
462
463 //      PRINTFUNC(DLOG_DEBUG,"%s - stype[%s]", __func__, itc->item_style);
464     if (!strcmp(itc->item_style, "3button_flat")) {
465         int index = (uintptr_t)elm_object_item_data_get(it);
466         //PRINTFUNC(DLOG_DEBUG,"it = %p", it);
467         PRINTFUNC(DLOG_DEBUG, "index = %d %d %d", index, index+1, index+2);
468
469         if (index < EMOTICON_CNT) {
470             emoticon_contents_pool[index].used = 0;
471         }
472         if (index + 1 < EMOTICON_CNT) {
473             emoticon_contents_pool[index+1].used = 0;
474         }
475         if (index + 2 < EMOTICON_CNT) {
476             emoticon_contents_pool[index+2].used = 0;
477         }
478     } else if (!strcmp(itc->item_style, "3button_flat_recent")) {
479         unsigned int index = (uintptr_t)elm_object_item_data_get(it);
480         //PRINTFUNC(DLOG_DEBUG,"index = %d",index);
481
482         if (index < recent_emoji_list.size()) {
483             emoticon_recents_pool[index].used = 0;
484         }
485         if (index + 1 < recent_emoji_list.size()) {
486             emoticon_recents_pool[index+1].used = 0;
487         }
488         if (index + 2 < recent_emoji_list.size()) {
489             emoticon_recents_pool[index+2].used = 0;
490         }
491     }
492 }
493
494 static Evas_Object * __emoticon_gl_recent_content_get(void *data, Evas_Object *obj, const char *part)
495 {
496     if (is_content_reuse_on) {
497         unsigned int index = (uintptr_t)data;
498         int new_index = 0;
499
500     //PRINTFUNC(DLOG_DEBUG,"%s %d", part, index);
501         if (!strcmp(part, "elm.icon.1") || (!strcmp(part, "elm.icon.2")) || (!strcmp(part, "elm.icon.3"))) {
502             if (!strcmp(part, "elm.icon.1")) {
503                 if (index >= recent_emoji_list.size()) return NULL;
504                 new_index = index;
505             } else if (!strcmp(part, "elm.icon.2")) {
506                 if (index + 1 >= recent_emoji_list.size()) return NULL;
507                 new_index = index + 1;
508             } else if (!strcmp(part, "elm.icon.3")) {
509                 if (index + 2 >= recent_emoji_list.size()) return NULL;
510                 new_index = index + 2;
511             }
512
513             Evas_Object* btn = NULL;
514             btn = (Evas_Object*)emoticon_recents_pool[new_index].content;
515             emoticon_recents_pool[new_index].used = 1;
516             return btn;
517         } else if (!strcmp(part, "base")) {
518             Evas_Object* btn = elm_button_add(obj);
519             elm_object_style_set(btn, "ime/transparent");
520             return btn;
521         }
522     } else {
523         unsigned int index = (uintptr_t)data;
524         int new_index = 0;
525
526     //    PRINTFUNC(DLOG_DEBUG,"%s %d", part, index);
527         if (!strcmp(part, "elm.icon.1") || (!strcmp(part, "elm.icon.2")) || (!strcmp(part, "elm.icon.3"))) {
528             if (!strcmp(part, "elm.icon.1")) {
529                 if (index >= recent_emoji_list.size()) return NULL;
530                 new_index = index;
531             } else if (!strcmp(part, "elm.icon.2")) {
532                 if (index + 1 >= recent_emoji_list.size()) return NULL;
533                 new_index = index + 1;
534             } else if (!strcmp(part, "elm.icon.3")) {
535                 if (index + 2 >= recent_emoji_list.size()) return NULL;
536                 new_index = index + 2;
537             }
538             return get_recent_emoticon_button(obj, new_index);
539         } else if (!strcmp(part, "base")) {
540             Evas_Object* btn = elm_button_add(obj);
541             elm_object_style_set(btn, "ime/transparent");
542             return btn;
543         }
544     }
545     return NULL;
546 }
547
548 static Evas_Object * __emoticon_gl_emoticon_content_get(void *data, Evas_Object *obj, const char *part)
549 {
550     //PRINTFUNC(DLOG_DEBUG,"%s", __func__);
551
552     if (is_content_reuse_on) {
553         int index = (uintptr_t)data;
554         int new_index = 0;
555
556         if (!strcmp(part, "elm.icon.1") || (!strcmp(part, "elm.icon.2")) || (!strcmp(part, "elm.icon.3"))) {
557             if (!strcmp(part, "elm.icon.1")) {
558                 if (index >= EMOTICON_CNT) return NULL;
559                 new_index = index;
560             } else if (!strcmp(part, "elm.icon.2")) {
561                 if (index + 1 >= EMOTICON_CNT) return NULL;
562                 new_index = index + 1;
563             } else if (!strcmp(part, "elm.icon.3")) {
564                 if (index + 2 >= EMOTICON_CNT) return NULL;
565                 new_index = index + 2;
566             }
567
568             Evas_Object* btn = NULL;
569             btn = (Evas_Object*)emoticon_contents_pool[new_index].content;
570             emoticon_contents_pool[new_index].used = 1;
571 #if 0
572             char utf_8[10] = {0, };
573             snprintf(utf_8, sizeof(utf_8), "%d", new_index);
574             elm_object_part_text_set(btn, "elm.text", strdup(utf_8));
575 #else
576             int length;
577             const Eina_Unicode unicode_event[2] = { (Eina_Unicode)emoticon_info[new_index].code, 0 };
578             char* utf_8 = eina_unicode_unicode_to_utf8(unicode_event, &length);
579             elm_object_part_text_set(btn, "elm.text", utf_8);
580             evas_object_data_set(btn, "index", (void*)(uintptr_t)new_index);
581
582             if (utf_8)
583                 free(utf_8);
584 #endif
585             return btn;
586
587         } else if (!strcmp(part, "base")) {
588             Evas_Object* btn = elm_button_add(obj);
589             elm_object_style_set(btn, "ime/transparent");
590             return btn;
591         }
592     } else {
593         int index = (uintptr_t)data;
594         int new_index = 0;
595
596         if (!strcmp(part, "elm.icon.1") ||  (!strcmp(part, "elm.icon.2")) ||  (!strcmp(part, "elm.icon.3"))) {
597             if (!strcmp(part, "elm.icon.1")) {
598                 if (index >= EMOTICON_CNT) return NULL;
599                 new_index = index;
600             } else if (!strcmp(part, "elm.icon.2")) {
601                 if (index + 1 >= EMOTICON_CNT) return NULL;
602                 new_index = index + 1;
603             } else if (!strcmp(part, "elm.icon.3")) {
604                 if (index + 2 >= EMOTICON_CNT) return NULL;
605                 new_index = index + 2;
606             }
607             return get_emoticon_button(obj, new_index);
608         } else if (!strcmp(part, "base")) {
609             Evas_Object* btn = elm_button_add(obj);
610             elm_object_style_set(btn, "ime/transparent");
611             return btn;
612         }
613     }
614     return NULL;
615 }
616
617
618 void _create_reusable_recents(Evas_Object *parent)
619 {
620     if (!parent) {
621         PRINTFUNC(DLOG_ERROR, "parent is null");
622         return;
623     }
624
625     unsigned int i;
626     for (i = 0; i < recent_emoji_list.size(); i++ ) {
627         emoticon_recents_pool[i].index = i;
628         emoticon_recents_pool[i].content = get_recent_emoticon_button(parent, i);
629         emoticon_recents_pool[i].used = 0;
630     }
631 }
632
633 static Eina_Bool _lazy_loader_cb_for_contents(void *data)
634 {
635     Evas_Object *gl = (Evas_Object *)data;
636     if (!gl) {
637         PRINTFUNC(DLOG_ERROR, "gl is null");
638         lazy_loading_timer_for_contents = NULL;
639         return ECORE_CALLBACK_CANCEL;
640     }
641
642     if (loading_done_for_contents == EMOTICON_CNT) {
643         PRINTFUNC(DLOG_DEBUG, "lazy loading contents done");
644         lazy_loading_timer_for_contents = NULL;
645         return ECORE_CALLBACK_CANCEL;
646     }
647
648     int loading_top = 0;
649     if (loading_done_for_contents + LOADING_CONTENT_UNIT > EMOTICON_CNT) {
650         loading_top = EMOTICON_CNT;
651     } else {
652         loading_top = loading_done_for_contents + LOADING_CONTENT_UNIT;
653     }
654
655     PRINTFUNC(DLOG_DEBUG, "_lazy_loader_cb_for_contents loading_done = %d", loading_done_for_contents);
656
657     int i;
658     for (i = loading_done_for_contents; i < loading_top; i++) {
659         emoticon_contents_pool[i].index = i;
660         emoticon_contents_pool[i].used = 0;
661
662         if (emoticon_contents_pool[i].content == NULL) { // reusable
663             emoticon_contents_pool[i].content = get_emoticon_button(gl, i);
664         }
665     }
666
667     loading_done_for_contents = loading_top;
668
669     return ECORE_CALLBACK_RENEW;
670 }
671
672 void create_reusable_button(Evas_Object *parent)
673 {
674     if (!parent) {
675         PRINTFUNC(DLOG_ERROR, "parent is null");
676         return;
677     }
678     loading_done_for_contents = INITAL_CONTENT_UNIT;
679
680     int i;
681     for (i = 0; i < INITAL_CONTENT_UNIT; i++ ) {
682         emoticon_contents_pool[i].index = i;
683         emoticon_contents_pool[i].used = 0;
684
685         if (emoticon_contents_pool[i].content == NULL) { // reusable
686             emoticon_contents_pool[i].content = get_emoticon_button(parent, i);
687         }
688     }
689
690     lazy_loading_timer_for_contents = ecore_timer_add(0.25, _lazy_loader_cb_for_contents, (void *)parent);
691 }
692
693 static Eina_Bool _lazy_loader_cb_for_items(void *data)
694 {
695     Evas_Object *gl = (Evas_Object *)data;
696     if (!gl) {
697         PRINTFUNC(DLOG_ERROR, "gl is null");
698         lazy_loading_timer_for_items = NULL;
699         return ECORE_CALLBACK_CANCEL;
700     }
701
702     if (loading_done_for_item == EMOTICON_CNT) {
703         PRINTFUNC(DLOG_DEBUG, "lazy loading item done");
704         //elm_genlist_realized_items_update(gl);
705         elm_genlist_item_class_free(itc_emoticon);
706         lazy_loading_timer_for_items = NULL;
707
708         return ECORE_CALLBACK_CANCEL;
709     }
710
711     int loading_top = 0;
712     if (loading_done_for_item + LOADING_ITEM_UNIT > EMOTICON_CNT) {
713         loading_top = EMOTICON_CNT;
714     } else {
715         loading_top = loading_done_for_item + LOADING_ITEM_UNIT;
716     }
717
718     if (loading_top > loading_done_for_contents) {
719         PRINTFUNC(DLOG_DEBUG, "Wait for content loading");
720         return ECORE_CALLBACK_RENEW;
721     }
722     PRINTFUNC(DLOG_DEBUG, "_lazy_loader_cb_for_items loading_done_for_item = %d", loading_done_for_item);
723
724     int i;
725     for (i = loading_done_for_item; i < loading_top; i++ ) {
726         if (i%3 == 0)
727             elm_genlist_item_append(gl, itc_emoticon, (void*)(uintptr_t)i, NULL, ELM_GENLIST_ITEM_NONE, NULL, (void *)(uintptr_t)i);
728     }
729
730     loading_done_for_item = loading_top;
731     return ECORE_CALLBACK_RENEW;
732 }
733
734 void _create_reusable_contents(Evas_Object *gl){
735     if (!gl) {
736         PRINTFUNC(DLOG_ERROR, "gl is null");
737         return;
738     }
739     int i;
740     loading_done_for_item = INITAL_ITEM_UNIT;
741
742     for (i = 0; i < INITAL_ITEM_UNIT; i++ ) {
743         if (i%3 == 0)
744             elm_genlist_item_append(gl, itc_emoticon, (void*)(uintptr_t)i, NULL, ELM_GENLIST_ITEM_NONE, NULL, (void *)(uintptr_t)i);
745     }
746
747     lazy_loading_timer_for_items = ecore_timer_add(0.1, _lazy_loader_cb_for_items, (void *)gl);
748 }
749
750 Evas_Object* _create_emoticon_genlist(void* data)
751 {
752     PRINTFUNC(DLOG_DEBUG, "%s", __func__);
753     App_Data* ad = (App_Data*) data;
754     if (!ad)
755         return NULL;
756
757     Evas_Object* genlist = elm_genlist_add(ad->naviframe);
758     if (NULL == genlist)
759         return NULL;
760
761     if (_WEARABLE) {
762         Evas_Object* circle_object_genlist = eext_circle_object_genlist_add(genlist, ad->circle_surface);
763         eext_circle_object_genlist_scroller_policy_set(circle_object_genlist, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
764         evas_object_data_set(genlist, "circle", (void *) circle_object_genlist);
765         eext_rotary_object_event_activated_set(circle_object_genlist, EINA_TRUE);
766     }
767     evas_object_size_hint_weight_set(genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
768     evas_object_size_hint_align_set(genlist, EVAS_HINT_FILL, EVAS_HINT_FILL);
769     evas_object_show(genlist);
770
771     const char *item_style = NULL;
772     if (_WEARABLE)
773         item_style = "empty";
774     Elm_Object_Item *nf_emoticon_item = elm_naviframe_item_push(ad->naviframe, NULL, NULL, NULL, genlist, item_style);
775
776     elm_naviframe_item_pop_cb_set(nf_emoticon_item, _custom_back_cb2, ad);
777
778     evas_object_smart_callback_add(genlist, "language,changed", _emoticon_gl_lang_changed, genlist);
779
780     if (is_content_reuse_on) {
781         evas_object_smart_callback_add(genlist, "content,unswallowed", _emoticon_gl_content_unswallowed_cb, NULL);
782     }
783
784     return genlist;
785 }
786
787 void _update_emoticon_items(void *data)
788 {
789     PRINTFUNC(DLOG_DEBUG, "%s", __func__);
790     Evas_Object* gl = (Evas_Object*) data;
791     if (!gl)
792         return;
793
794     unsigned int i;
795     Elm_Object_Item *it = NULL;
796     Elm_Object_Item *first_it = NULL;
797
798     Elm_Genlist_Item_Class * itc_dummy = elm_genlist_item_class_new();
799     itc_dummy->item_style = "title";
800     itc_dummy->func.text_get = NULL;
801     itc_dummy->func.content_get = NULL;
802     itc_dummy->func.state_get = NULL;
803     itc_dummy->func.del = NULL;
804
805     Elm_Genlist_Item_Class *itc_group = elm_genlist_item_class_new();
806
807     itc_group->item_style = "groupindex";
808     itc_group->func.text_get = __emoticon_gl_text_get;
809     itc_group->func.content_get = NULL;
810     itc_group->func.state_get = NULL;
811     itc_group->func.del = NULL;
812
813     Elm_Genlist_Item_Class *itc_recent = elm_genlist_item_class_new();
814     if (is_content_reuse_on) {
815 //        itc_recent->content_reusable = EINA_TRUE;
816     }
817     itc_recent->item_style = "3button_flat_recent";
818     itc_recent->func.text_get = NULL;
819     itc_recent->func.content_get = __emoticon_gl_recent_content_get;
820     itc_recent->func.state_get = NULL;
821     itc_recent->func.del = NULL;
822
823     itc_emoticon = elm_genlist_item_class_new();
824     if (is_content_reuse_on) {
825 //        itc_emoticon->content_reusable = EINA_TRUE;
826     }
827     itc_emoticon->item_style = "3button_flat";
828     itc_emoticon->func.text_get = NULL;
829     itc_emoticon->func.content_get = __emoticon_gl_emoticon_content_get;
830     itc_emoticon->func.state_get = NULL;
831     itc_emoticon->func.del = NULL;
832
833     // dummy title for empty space
834     it_emoticon_empty = elm_genlist_item_append(gl, itc_dummy, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
835
836     if (recent_emoji_list.size() > 0) {
837         if (is_content_reuse_on) {
838             _create_reusable_recents(gl);
839         }
840
841         // Group Recents
842         it_emoticon_recent_group = elm_genlist_item_append(gl, itc_group, (void*)"IDS_IME_HEADER_RECENT_M_RECETLY_SENT_EMOJIS_ABB", NULL, ELM_GENLIST_ITEM_NONE, NULL, (void *)2);
843         elm_genlist_item_select_mode_set(it, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
844         if (first_it == NULL)
845             first_it = it_emoticon_recent_group;
846
847         PRINTFUNC(DLOG_DEBUG, "size = %d", recent_emoji_list.size());
848
849         for (i=0;i < recent_emoji_list.size();i=i+3)
850         {
851             it = elm_genlist_item_append(gl, itc_recent, (void*)(uintptr_t)i, NULL, ELM_GENLIST_ITEM_NONE, NULL, (void *)(uintptr_t)i);
852         }
853     }
854
855     // Group Emoticons
856     it_emoticon_emoji_group = elm_genlist_item_append(gl, itc_group, (void*)"IDS_IME_HEADER_EMOJIS_ABB", NULL, ELM_GENLIST_ITEM_NONE, NULL, (void *)2);
857     elm_genlist_item_select_mode_set(it, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
858     if (first_it == NULL)
859         first_it = it_emoticon_emoji_group;
860
861     if (is_content_reuse_on) {
862         _create_reusable_contents(gl);
863     } else {
864         // Emoticons
865         for (i=0;i< EMOTICON_CNT;i=i+3) {
866             it = elm_genlist_item_append(gl, itc_emoticon, (void*)(uintptr_t)i, NULL, ELM_GENLIST_ITEM_NONE, NULL, (void *)(uintptr_t)i);
867             it_last = it;
868         }
869         elm_genlist_item_class_free(itc_emoticon);
870     }
871     it = elm_genlist_item_next_get(first_it);
872     const Elm_Genlist_Item_Class *itc_temp = elm_genlist_item_item_class_get(it);
873     if (itc_temp == itc_group) {
874         it = elm_genlist_item_next_get(it);
875     }
876     elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
877
878     elm_genlist_item_class_free(itc_recent);
879     elm_genlist_item_class_free(itc_group);
880     elm_genlist_item_class_free(itc_dummy);
881 }
882
883 void ise_show_emoticon_list(void *data)
884 {
885     App_Data* ad = (App_Data*) data;
886     if (!ad)
887         return;
888
889     it_emoticon_empty = NULL;
890     it_emoticon_recent_group = NULL;
891     it_emoticon_emoji_group = NULL;
892     it_last = NULL;
893
894     get_recent_emoticons(recent_emoji_list);
895
896     Evas_Object* emoticon_list = NULL;
897
898     emoticon_list = _create_emoticon_genlist(ad);
899
900     if (is_content_reuse_on) {
901         create_reusable_button(ad->naviframe); // button object need to survive even if genlist is deleted.
902     }
903     _update_emoticon_items(emoticon_list);
904 }