Initialize Tizen 2.3
[apps/home/ug-memo-efl.git] / src / memo_doodle_editor.c
1 /*
2 *
3 * Copyright 2012  Samsung Electronics Co., Ltd
4 *
5 * Licensed under the Flora License, Version 1.1 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *    http://floralicense.org/license/
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <appcore-efl.h>
22 #include <Elementary.h>
23 #include <dlog.h>
24 #include <gravel.h>
25 #include <extended-elm.h>
26 #include <supplement.h>
27 #include <memo-assist.h>
28 #include <memo_string.h>
29
30 typedef struct __doodle_editor_t {
31     Evas_Object *win;
32     Evas_Object *parent;
33     Memo_Component_Callback cb;
34     void *data;
35     memo_data_t *record;
36     char buf[MEMO_BUFFER_SIZE]; /* for temporarily usage only */
37     Eina_Bool savable;
38     Eina_Bool erase;    /* erase mode */
39     Eina_Bool comment;    /* edit comment mode */
40     Eina_Bool doodle_init;
41     Eina_Bool stroke_down;    /* see comment in _on_doodle_move_cb */
42     int stroke_size;
43     int stroke_color;
44
45     /* content */
46     Evas_Object *body_main;
47     Evas_Object *doodle;
48     Evas_Object *toolbar;
49     Evas_Object *btn_size;
50     void *h_ss;
51     Evas_Object *btn_color;
52     void *h_cs;
53     Evas_Object *edit_field;
54
55     /* entry */
56     Evas_Object *entry;
57     Ecore_IMF_Context *imf_context;
58 } doodle_editor_t;
59
60 static void _stroke_size_selector_del(doodle_editor_t *de);
61 static void _stroke_color_selector_del(doodle_editor_t *de);
62
63 static void _save_record(doodle_editor_t *de)
64 {
65     memo_begin_trans();
66     if (de->record->id != -1) {
67         memo_mod_data(de->record);
68     } else {
69         de->record->content = memo_get_doodle_title();
70         memo_add_data(de->record);
71     }
72     /* save doodle to file */
73     snprintf(de->buf, MEMO_BUFFER_SIZE, DOODLEDIR "/%d.png", (int)de->record->id);
74     evas_object_image_save(de->doodle, de->buf, NULL, NULL);
75     memo_end_trans();
76 }
77
78 static void _on_save_yes(void *data, Evas_Object *obj, void *event_info)
79 {
80     doodle_editor_t *de = (doodle_editor_t *)data;
81     _save_record(de);
82     de->cb(de->data, "save", NULL);
83 }
84
85 static void _on_save_no(void *data, Evas_Object *obj, void *event_info)
86 {
87     doodle_editor_t *de = (doodle_editor_t *)data;
88     de->cb(de->data, "cancel", NULL);
89 }
90
91 static Eina_Bool _launch_yes_no_popup(void *data)
92 {
93     doodle_editor_t *de = (doodle_editor_t *)data;
94     memo_create_yes_no_popup(de->win, MEMO_I18N_SAVE_MEMO, _on_save_yes, _on_save_no, de);
95     return EINA_FALSE;
96 }
97
98 static Eina_Bool _comment_savable(doodle_editor_t *de)
99 {
100     const char *text = elm_entry_entry_get(de->entry);
101     Eina_Bool savable = EINA_TRUE;
102
103     if (strcmp(text, "") == 0) {
104         savable = EINA_FALSE;
105     } else if (de->record->comment != NULL) { /* check if same as init string */
106         if (strcmp(de->record->comment, text)==0) {
107             savable = EINA_FALSE;
108         }
109     }
110     return savable;
111 }
112
113 static void _stroke_size_selector_callback(void *data, const char *msg, void *event)
114 {
115     doodle_editor_t *de = (doodle_editor_t *)data;
116     if (strcmp(msg, "layout") == 0) {
117         elm_object_part_content_set(de->body_main, "elm.swallow.tool", (Evas_Object *)event);
118     } else if (strcmp(msg, "change") == 0) {
119         de->stroke_size = (int)event;
120     } else if (strcmp(msg, "flick,down") == 0) {
121         _stroke_size_selector_del(de);
122         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "elm");
123     }
124 }
125
126 static void _stroke_size_selector_del(doodle_editor_t *de)
127 {
128     if (de->h_ss != NULL) {
129         elm_object_part_content_unset(de->body_main, "elm.swallow.tool");
130         memo_del_pencil_size_selector(de->h_ss);
131         de->h_ss = NULL;
132         memo_tool_btn_focus_set(de->btn_size, EINA_FALSE);
133     }
134 }
135
136 static void _on_stroke_size_btn_up(void *data, Evas *e, Evas_Object *evas_obj, void *event_info)
137 {
138         doodle_editor_t *de = (doodle_editor_t *)data;
139         if (de->h_ss != NULL) { /* stroke size selector already open */
140                 return;
141         }
142         if (de->h_cs != NULL) { /* destroy stroke color selector */
143                 _stroke_color_selector_del(de);
144         }
145         if (de->erase) { /* deselect eraser */
146                 de->erase = EINA_FALSE;
147                 Evas_Object *eo = (Evas_Object *)elm_object_part_content_get(de->toolbar, "elm.swallow.btn3");
148                 memo_tool_btn_focus_set(eo, de->erase);
149         }
150         /* load stroke size selector */
151         service_h service = NULL;
152         service_create(&service);
153         snprintf(de->buf, MEMO_BUFFER_SIZE, "%d", de->stroke_size);
154         service_add_extra_data(service, "current", de->buf);
155         snprintf(de->buf, MEMO_BUFFER_SIZE, "%d", 0xFFFFFFFF);
156         service_add_extra_data(service, "bg_color", de->buf);
157         de->h_ss = memo_load_pencil_size_selector(de->body_main, service, _stroke_size_selector_callback, de);
158         service_destroy(service);
159         memo_tool_btn_focus_set(de->btn_size, EINA_TRUE);
160         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "abbrev", "elm");
161 }
162
163 void _stroke_color_selector_callback(void *data, const char *msg, void *event)
164 {
165     doodle_editor_t *de = (doodle_editor_t *)data;
166     if (strcmp(msg, "layout") == 0) {
167         elm_object_part_content_set(de->body_main, "elm.swallow.tool", (Evas_Object *)event);
168     } else if (strcmp(msg, "change") == 0) {
169         de->stroke_color = (int)event;
170     } else if (strcmp(msg, "flick,down") == 0) {
171         _stroke_color_selector_del(de);
172         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "elm");
173     }
174 }
175
176 static void _stroke_color_selector_del(doodle_editor_t *de)
177 {
178     if (de->h_cs != NULL) {
179         elm_object_part_content_unset(de->body_main, "elm.swallow.tool");
180         memo_del_color_selector(de->h_cs);
181         memo_tool_btn_focus_set(de->btn_color, EINA_FALSE);
182         de->h_cs = NULL;
183     }
184 }
185
186 static void _on_stroke_color_btn_up(void *data, Evas *e, Evas_Object *evas_obj, void *event_info)
187 {
188         doodle_editor_t *de = (doodle_editor_t *)data;
189         if (de->h_cs!= NULL) { /* stroke color selector already open */
190                 return;
191         }
192         if (de->h_ss!= NULL) { /* destroy stroke  size selector */
193                 _stroke_size_selector_del(de);
194         }
195         if (de->erase) { /* deselect eraser */
196                 de->erase = EINA_FALSE;
197                 Evas_Object *eo = (Evas_Object *)elm_object_part_content_get(de->toolbar, "elm.swallow.btn3");
198                 memo_tool_btn_focus_set(eo, de->erase);
199         }
200         /* load stroke color selector */
201         service_h service = NULL;
202         service_create(&service);
203         snprintf(de->buf, MEMO_BUFFER_SIZE, "%d", de->stroke_color);
204         service_add_extra_data(service, "color", de->buf);
205         snprintf(de->buf, MEMO_BUFFER_SIZE, "%d", 0xFFFFFFFF);
206         service_add_extra_data(service, "bg_color", de->buf);
207         de->h_cs = memo_load_color_selector(de->body_main, service, _stroke_color_selector_callback, de);
208         service_destroy(service);
209         memo_tool_btn_focus_set(de->btn_color, EINA_TRUE);
210         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "abbrev", "elm");
211 }
212
213 static void _input_panel_event_callback(void *data, Ecore_IMF_Context *ctx, int value)
214 {
215     doodle_editor_t *de = (doodle_editor_t *)data;
216     if (value == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
217         if (de->comment) {
218             edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "comment");
219         }
220     } else if (value == ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
221         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "abbrev", "comment");
222         if (!de->comment) { /* first shift to comment mode */
223             if (de->record->comment == NULL) { /* remove DUMMY_COMMENT */
224                 elm_entry_entry_set(de->entry, "");
225             }
226             de->cb(de->data, "savable", (void *)0);
227         }
228         de->comment = EINA_TRUE;
229         de->cb(de->data, "title", de->record->comment == NULL ? MEMO_I18N_ADD_COMMENT : MEMO_I18N_EDIT_COMMENT);
230     }
231 }
232
233 static void _on_entry_content_change(void *data, Evas_Object *obj, void *event_info)
234 {
235     doodle_editor_t *de = (doodle_editor_t *)data;
236     if (elm_object_focus_get(de->edit_field)) {
237         if (elm_entry_is_empty(obj)) {
238             elm_object_signal_emit(de->edit_field, "elm,state,eraser,hide", "elm");
239         } else {
240             elm_object_signal_emit(de->edit_field, "elm,state,eraser,show", "elm");
241         }
242     }
243     RETIF(!de->comment);
244     Eina_Bool savable = _comment_savable(de);
245     de->cb(de->data, "savable", (void *)(savable?1:0));
246 }
247
248 // Focused callback will show X marked button and hide guidetext
249 static void _focused_cb(void *data, Evas_Object *obj, void *event_info)
250 {
251     if (!elm_entry_is_empty(obj))
252         elm_object_signal_emit(data, "elm,state,eraser,show", "elm");
253     elm_object_signal_emit(data, "elm,state,guidetext,hide", "elm");
254 }
255
256 // Unfocused callback will show guidetext and hide X marked button
257 static void _unfocused_cb(void *data, Evas_Object *obj, void *event_info)
258 {
259     if (elm_entry_is_empty(obj))
260         elm_object_signal_emit(data, "elm,state,guidetext,show", "elm");
261     elm_object_signal_emit(data, "elm,state,eraser,hide", "elm");
262 }
263
264 // When X marked button is clicked, empty entry’s contents
265 static void _eraser_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
266 {
267     elm_entry_entry_set(data, "");
268 }
269
270 static void _draw_argb32(int *img, int w, int h, int x, int y, int size, int color)
271 {
272     int cx, cy, cw, ch;
273     int i, j;
274
275     cx = x;
276     cy = y;
277     cw = size;
278     ch = size;
279     CLIP_RECT_TO_RECT(cx, cy, cw, ch, 0, 0, w, h);
280     for (i = 0; i < ch; i++) {
281         for (j = 0; j < cw; j++) {
282             memcpy(img + (i + cy) * w + (cx + j), &color, 4);
283         }
284     }
285 }
286
287 static void _on_doodle_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
288 {
289     doodle_editor_t *de = (doodle_editor_t *)data;
290     if (de->comment) {
291         return;
292     }
293     if (de->h_ss!= NULL) { /* destroy stroke  size selector */
294         _stroke_size_selector_del(de);
295     }
296     if (de->h_cs != NULL) { /* destroy stroke color selector */
297         _stroke_color_selector_del(de);
298     }
299     edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "elm");
300     de->stroke_down = EINA_TRUE;
301     de->record->has_doodle = 1;
302     if (!de->erase) {
303         de->savable = EINA_TRUE;
304     } else if (de->record->id != -1) { /* edit existing doodle with eraser */
305         de->savable = EINA_TRUE;
306     }
307     de->cb(de->data, "savable", (void *)(de->savable?1:0));
308 }
309
310 static void _on_doodle_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
311 {
312     doodle_editor_t *de = (doodle_editor_t *)data;
313     Evas_Event_Mouse_Move *event = (Evas_Event_Mouse_Move *)event_info;
314     int *img_data = NULL;
315     Evas_Coord x, y, w, h;
316     int px = 0;
317     int py = 0;
318     int i = 0;
319     int gap_max = 0;
320     int gap_x = 0;
321     int gap_y = 0;
322     int color = 0;
323
324     /* a little mouse move events will be received before mouse down event,
325        if those mouse move event is not filtered,
326        a line (from last up point to current move point) will be draw */
327     if (!de->stroke_down) {
328         return;
329     }
330
331     color = de->erase ? 0xFFFFFFFF : de->stroke_color;
332     evas_object_geometry_get(de->doodle, &x, &y, &w, &h);
333     img_data = evas_object_image_data_get(de->doodle, 1);
334     gap_x = event->cur.output.x - event->prev.output.x;
335     gap_y = event->cur.output.y - event->prev.output.y;
336     gap_max = MAX(abs(gap_x), abs(gap_y));
337
338     for (i = 0; i < gap_max; i++) {
339         px = event->prev.output.x + i * gap_x / gap_max;
340         py = event->prev.output.y + i * gap_y / gap_max;
341         /* mouse position in image */
342         px -= x;
343         py -= y;
344         _draw_argb32(img_data, w, h, px, py, de->stroke_size, color);
345     }
346     evas_object_image_data_update_add(de->doodle, 0, 0, w, h);
347 }
348
349 static void _on_doodle_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
350 {
351     doodle_editor_t *de = (doodle_editor_t *)data;
352     de->stroke_down = EINA_FALSE;
353 }
354
355 /* this function must be execute only once
356  * in resize callback we will get the actual size of doodle
357  * we need to transfer origin image data to fit the actual canvas size
358  */
359 static void _on_doodle_resize_cb(void *data, Evas_Object *obj, void *event_info)
360 {
361     doodle_editor_t *de = (doodle_editor_t *)data;
362     Evas_Coord w, h;
363     int *img_data = NULL;
364
365     if (de->doodle_init) {    /* reenter control */
366         return;
367     } else {
368         de->doodle_init = EINA_TRUE;
369         evas_object_geometry_get(de->doodle, NULL, NULL, &w, &h);
370         evas_object_image_size_set(de->doodle, w, h);
371         img_data = evas_object_image_data_get(de->doodle, 1);
372         if (img_data != NULL) { /* set background color as white */
373             memset(img_data, 0xFFFFFFFF, sizeof(int)*w*h);
374             evas_object_image_data_update_add(de->doodle, 0, 0, w, h);
375         }
376     }
377 }
378
379 static void _on_eraser_up(void *data, Evas *e, Evas_Object *evas_obj, void *event_info)
380 {
381     doodle_editor_t *de = (doodle_editor_t *)data;
382     if (de->h_ss!= NULL) { /* destroy stroke  size selector */
383         _stroke_size_selector_del(de);
384     }
385     if (de->h_cs != NULL) { /* destroy stroke color selector */
386         _stroke_color_selector_del(de);
387     }
388     de->erase = !(de->erase);
389     Evas_Object *eo = (Evas_Object *)elm_object_part_content_get(de->toolbar, "elm.swallow.btn3");
390     memo_tool_btn_focus_set(eo, de->erase);
391     edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "elm");
392 }
393
394 static void _on_yes(void *data, Evas_Object *obj, void *event_info)
395 {
396     doodle_editor_t *de = (doodle_editor_t *)data;
397     _save_record(de);
398     de->cb(de->data, "text", NULL);
399 }
400
401 static void _on_no(void *data, Evas_Object *obj, void *event_info)
402 {
403     doodle_editor_t *de = (doodle_editor_t *)data;
404     de->cb(de->data, "text", NULL);
405 }
406
407 static void _on_text_mode(void *data, Evas_Object *obj, void *event_info)
408 {
409     doodle_editor_t *de = (doodle_editor_t *)data;
410     if (de->savable) { /* modified, need user confirmation */
411         memo_create_yes_no_popup(de->parent, MEMO_I18N_SAVE_MEMO, _on_yes, _on_no, de);
412     } else {
413         de->cb(de->data, "text", NULL);
414     }
415 }
416
417 static void _create_doodle_editor_layout(doodle_editor_t *de, service_h service)
418 {
419     de->body_main = elm_layout_create(de->parent, EDJ_FILE, "doodle_editor");
420     de->cb(de->data, "layout", de->body_main);
421     /* title */
422     de->cb(de->data, "title", de->record->id==-1 ? MEMO_I18N_NEW_DRAWING : MEMO_I18N_EDIT_DRAWING);
423     /* date */
424     memo_time_format(de->buf, MEMO_BUFFER_SIZE, de->record->modi_time);
425     edje_object_part_text_set(elm_layout_edje_get(de->body_main), "elm.text.date", de->buf);
426
427     /* toolbar */
428     de->toolbar = elm_swallowed_layout(de->body_main, "elm.swallow.toolbar", EDJ_FILE, "edit_toolbar");
429     de->btn_size = elm_swallowed_layout(de->toolbar, "elm.swallow.btn1", EDJ_DIR"/black/memo.edj", "tl_stroke_size");
430     evas_object_event_callback_add(de->btn_size, EVAS_CALLBACK_MOUSE_UP, _on_stroke_size_btn_up, de);
431     de->btn_color = elm_swallowed_layout(de->toolbar, "elm.swallow.btn2", EDJ_DIR"/black/memo.edj", "tl_stroke_color");
432     evas_object_event_callback_add(de->btn_color, EVAS_CALLBACK_MOUSE_UP, _on_stroke_color_btn_up, de);
433     Evas_Object *eo = elm_swallowed_layout(de->toolbar, "elm.swallow.btn3", EDJ_DIR"/black/memo.edj", "tl_stroke_eraser");
434     evas_object_event_callback_add(eo, EVAS_CALLBACK_MOUSE_UP, _on_eraser_up, de);
435     if (!service_key_check(service, "toggle", "disable")) {
436         elm_swallowed_button(de->toolbar, "elm.swallow.btn4", MEMO_I18N_TEXT, _on_text_mode, de);
437     }
438
439     /* doodle */
440     Evas *evas = evas_object_evas_get(de->parent);
441     de->doodle = evas_object_image_filled_add(evas);
442     evas_object_image_colorspace_set(de->doodle, EVAS_COLORSPACE_ARGB8888);
443     evas_object_image_alpha_set(de->doodle, 1);
444     /* doodle data */
445     if (de->record->has_doodle == 1) {
446         snprintf(de->buf, MEMO_BUFFER_SIZE, DOODLEDIR "/%d.png", (int)de->record->id);
447         evas_object_image_file_set(de->doodle, de->buf, NULL);
448     } else {
449         evas_object_render_flush_hook(de->doodle, _on_doodle_resize_cb, de);
450     }
451     evas_object_event_callback_add(de->doodle, EVAS_CALLBACK_MOUSE_DOWN, _on_doodle_down_cb, de);
452     evas_object_event_callback_add(de->doodle, EVAS_CALLBACK_MOUSE_MOVE, _on_doodle_move_cb, de);
453     evas_object_event_callback_add(de->doodle, EVAS_CALLBACK_MOUSE_UP, _on_doodle_up_cb, de);
454     evas_object_show(de->doodle);
455     elm_object_part_content_set(de->body_main, "elm.swallow.doodle", de->doodle);
456
457     /* comment */
458     eo = elm_swallowed_layout(de->body_main, "elm.swallow.comment", EDJ_FILE, "doodle_comment");
459     //EditField
460     Evas_Object *layout = elm_layout_add(eo);
461     elm_layout_theme_set(layout, "layout", "editfield", "default");
462     elm_object_part_content_set(eo, "elm.swallow.editfield", layout);
463     Evas_Object *ef = elm_entry_add(eo);
464     elm_object_part_content_set(layout, "elm.swallow.content", ef);
465     de->edit_field = layout;
466
467     elm_object_style_set(ef, "font_color_black");
468     elm_entry_single_line_set(ef, EINA_TRUE);
469     elm_entry_scrollable_set(ef, EINA_TRUE);
470     evas_object_size_hint_weight_set(ef, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
471     evas_object_size_hint_align_set(ef, EVAS_HINT_EXPAND, 0.5);
472
473     de->entry = ef;
474     elm_entry_cnp_mode_set(de->entry, ELM_CNP_MODE_PLAINTEXT);
475     de->imf_context = elm_entry_imf_context_get(de->entry);
476     /* if not hide explicitly, seems hide event of sweep down can not be received */
477     ecore_imf_context_input_panel_hide(de->imf_context);
478     elm_entry_entry_set(de->entry, de->record->comment == NULL ? MEMO_I18N_ADD_COMMENT : de->record->comment);
479     ecore_imf_context_input_panel_event_callback_add(de->imf_context, ECORE_IMF_INPUT_PANEL_STATE_EVENT,
480         _input_panel_event_callback, de);
481     evas_object_smart_callback_add(de->entry, "changed", _on_entry_content_change, de);
482     evas_object_smart_callback_add(de->entry, "preedit,changed", _on_entry_content_change, de);
483     evas_object_smart_callback_add(de->entry, "focused", _focused_cb, layout);
484     evas_object_smart_callback_add(de->entry, "unfocused", _unfocused_cb, layout);
485     elm_object_signal_callback_add(layout, "elm,eraser,clicked", "elm", _eraser_clicked_cb, de->entry);
486
487     /* savable */
488     de->cb(de->data, "savable", (void *)(de->savable?1:0));
489 }
490
491 void memo_doodle_editor_time_format_update(void *h_de)
492 {
493     doodle_editor_t *de = (doodle_editor_t *)h_de;
494     memo_time_format(de->buf, MEMO_BUFFER_SIZE, de->record->modi_time);
495     edje_object_part_text_set(elm_layout_edje_get(de->body_main), "elm.text.date", de->buf);
496 }
497
498 void memo_doodle_editor_cancel(void *h_de)
499 {
500     doodle_editor_t *de = (doodle_editor_t *)h_de;
501     if (de->comment) {
502         de->comment = EINA_FALSE;
503         ecore_imf_context_input_panel_hide(de->imf_context);
504         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "elm");
505         if (de->record->comment == NULL) {
506             elm_entry_entry_set(de->entry, MEMO_I18N_ADD_COMMENT);
507         } else { /* recover origin comment */
508             elm_entry_entry_set(de->entry, de->record->comment);
509         }
510         de->cb(de->data, "title", de->record->id==-1 ? MEMO_I18N_NEW_DRAWING : MEMO_I18N_EDIT_DRAWING);
511         de->cb(de->data, "savable", (void *)(de->savable?1:0));
512         de->cb(de->data, "comment cancel", NULL);
513     } else {
514         if (!de->savable) { /* not modified, return directly */
515             de->cb(de->data, "cancel", NULL);
516         } else {
517             _launch_yes_no_popup(de);
518         }
519     }
520 }
521
522 void memo_doodle_editor_save(void *h_de)
523 {
524     doodle_editor_t *de = (doodle_editor_t *)h_de;
525     if (de->comment) {
526         de->comment = EINA_FALSE;
527         ecore_imf_context_input_panel_hide(de->imf_context);
528         edje_object_signal_emit(elm_layout_edje_get(de->body_main), "expand", "elm");
529         Eina_Bool savable = _comment_savable(de);
530         if (savable) {
531             de->record->comment = strdup(elm_entry_entry_get(de->entry));
532             if (de->record->id != -1) { /* when edit existing, modification of comment will make record savable */
533                 de->savable = EINA_TRUE;
534             }
535         }
536         de->cb(de->data, "title", de->record->id==-1 ? MEMO_I18N_NEW_DRAWING : MEMO_I18N_EDIT_DRAWING);
537         de->cb(de->data, "savable", (void *)(de->savable?1:0));
538         elm_object_focus_set(de->edit_field, EINA_FALSE); /* when disable done button, focus may reset to edit field */
539         de->cb(de->data, "comment done", NULL);
540     } else {
541         _save_record(de);
542         de->cb(de->data, "save", NULL);
543     }
544 }
545
546 void *memo_load_doodle_editor(Evas_Object *win, Evas_Object *parent, service_h service, Memo_Component_Callback cb, void *data)
547 {
548     doodle_editor_t *de = SMALLOC(doodle_editor_t);
549     RETVIF(de==NULL, NULL);
550     service_dump(service);
551     de->win = win;
552     de->parent = parent;
553     de->cb = (cb==NULL ? memo_com_dummy_cb : cb); /* make sure cb is not null, no need to check legitimacy of cb when call */
554     de->data = data;
555
556     /* init */
557     const char *s = NULL;
558     service_get_extra_data(service, "index", &s);
559     if (s == NULL) {
560         de->record = memo_create_data();
561         de->record->id = -1;
562         de->record->modi_time = time((time_t *) 0);
563     } else {        /* load item */
564         de->record = memo_get_data(atoi(s));
565         SFREE(s);
566     }
567     de->stroke_size = 8;
568     de->stroke_color = 0xff000000;
569
570     _create_doodle_editor_layout(de, service);
571     return (void *)de;
572 }
573
574 void memo_destroy_doodle_editor(void *h_de)
575 {
576     doodle_editor_t *de = (doodle_editor_t *)h_de;
577     if (de->h_ss!= NULL) { /* destroy stroke  size selector */
578         _stroke_size_selector_del(de);
579     }
580     if (de->h_cs != NULL) { /* destroy stroke color selector */
581         _stroke_color_selector_del(de);
582     }
583     memo_free_data(de->record);
584     evas_object_del(de->body_main);
585     SFREE(de);
586 }