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