2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "clipdrawer.h"
20 #include "item_manager.h"
21 #include "xconverter.h"
23 #define EDJ_PATH "/usr/share/edje"
24 #define APP_EDJ_FILE EDJ_PATH"/cbhmdrawer.edj"
25 #define GRP_MAIN "cbhmdrawer"
27 #define ANIM_DURATION 30 // 1 seconds
28 #define ANIM_FLOPS (0.5/30)
29 #define CLIPDRAWER_HEIGHT 360
30 #define CLIPDRAWER_HEIGHT_LANDSCAPE 228
31 #define DEFAULT_WIDTH 720
32 #define GRID_ITEM_SPACE_W 6
33 #define GRID_ITEM_SINGLE_W 185
34 #define GRID_ITEM_SINGLE_H 161
35 #define GRID_ITEM_W (GRID_ITEM_SINGLE_W+(GRID_ITEM_SPACE_W*2))
36 #define GRID_ITEM_H (GRID_ITEM_SINGLE_H)
37 #define GRID_IMAGE_LIMIT_W 91
38 #define GRID_IMAGE_LIMIT_H 113
39 #define GRID_IMAGE_INNER 10
40 #define GRID_IMAGE_REAL_W (GRID_ITEM_SINGLE_W - (2*GRID_IMAGE_INNER))
41 #define GRID_IMAGE_REAL_H (GRID_ITEM_SINGLE_H - (2*GRID_IMAGE_INNER))
43 static Evas_Object *create_win(ClipdrawerData *cd, const char *name);
44 static Evas_Object *_grid_content_get(void *data, Evas_Object *obj, const char *part);
45 static void _grid_del(void *data, Evas_Object *obj);
46 static Eina_Bool clipdrawer_add_item(AppData *ad, CNP_ITEM *item);
47 static Eina_Bool clipdrawer_del_item(AppData *ad, CNP_ITEM *item);
48 static void clipdrawer_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
49 static void _grid_item_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
50 static void setting_win(Ecore_X_Display *x_disp, Ecore_X_Window x_main_win);
51 static void set_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win);
52 static void unset_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win);
54 static void _change_gengrid_paste_textonly_mode(ClipdrawerData *cd)
56 CNP_ITEM *item = NULL;
58 Elm_Object_Item *gitem = elm_gengrid_first_item_get(cd->gengrid);
62 item = elm_object_item_data_get(gitem);
63 if ((item->type_index == ATOM_INDEX_IMAGE) && (item->layout))
65 if (cd->paste_text_only)
66 edje_object_signal_emit(elm_layout_edje_get(item->layout), "elm,state,show,dim", "elm");
68 edje_object_signal_emit(elm_layout_edje_get(item->layout), "elm,state,hide,dim", "elm");
70 gitem = elm_gengrid_item_next_get(gitem);
74 void clipdrawer_paste_textonly_set(AppData *ad, Eina_Bool textonly)
76 ClipdrawerData *cd = ad->clipdrawer;
77 if (cd->paste_text_only != textonly)
78 cd->paste_text_only = textonly;
79 DTRACE("paste textonly mode = %d\n", textonly);
81 _change_gengrid_paste_textonly_mode(cd);
84 Eina_Bool clipdrawer_paste_textonly_get(AppData *ad)
86 ClipdrawerData *cd = ad->clipdrawer;
87 return cd->paste_text_only;
90 static Evas_Object *_load_edj(Evas_Object* win, const char *file, const char *group)
92 Evas_Object *layout = elm_layout_add(win);
95 DMSG("ERROR: elm_layout_add return NULL\n");
99 if (!elm_layout_file_set(layout, file, group))
101 DMSG("ERROR: elm_layout_file_set return FALSE\n");
102 evas_object_del(layout);
106 evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
107 elm_win_resize_object_add(win, layout);
109 evas_object_show(layout);
113 static Eina_Bool keydown_cb(void *data, int type, void *event)
116 Ecore_Event_Key *ev = event;
117 if (!strcmp(ev->keyname, KEY_END))
118 clipdrawer_lower_view(ad);
120 return ECORE_CALLBACK_PASS_ON;
123 ClipdrawerData* init_clipdrawer(AppData *ad)
125 ClipdrawerData *cd = calloc(1, sizeof(ClipdrawerData));
127 /* create and setting window */
130 if (!(cd->main_win = create_win(cd, APPNAME)))
135 cd->x_main_win = elm_win_xwindow_get(cd->main_win);
136 setting_win(ad->x_disp, cd->x_main_win);
139 if (!(cd->main_layout = _load_edj(cd->main_win, APP_EDJ_FILE, GRP_MAIN)))
141 evas_object_del(cd->main_win);
146 /* create and setting gengrid */
147 elm_theme_extension_add(NULL, APP_EDJ_FILE);
148 edje_object_signal_callback_add(elm_layout_edje_get(cd->main_layout),
149 "mouse,up,1", "*", clipdrawer_ly_clicked, ad);
151 cd->gengrid = elm_gengrid_add(cd->main_win);
152 elm_object_part_content_set(cd->main_layout, "historyitems", cd->gengrid);
153 elm_gengrid_item_size_set(cd->gengrid, GRID_ITEM_W+2, GRID_ITEM_H);
154 elm_gengrid_align_set(cd->gengrid, 0.5, 0.0);
155 elm_gengrid_horizontal_set(cd->gengrid, EINA_TRUE);
156 elm_gengrid_bounce_set(cd->gengrid, EINA_TRUE, EINA_FALSE);
157 elm_gengrid_multi_select_set(cd->gengrid, EINA_FALSE);
158 // evas_object_smart_callback_add(cd->gengrid, "selected", _grid_click_paste, ad);
159 evas_object_size_hint_weight_set(cd->gengrid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
161 elm_gengrid_clear(cd->gengrid);
163 cd->gic.item_style = "default_grid";
164 cd->gic.func.text_get = NULL;
165 cd->gic.func.content_get = _grid_content_get;
166 cd->gic.func.state_get = NULL;
167 cd->gic.func.del = _grid_del;
169 evas_object_show(cd->gengrid);
171 ad->draw_item_add = clipdrawer_add_item;
172 ad->draw_item_del = clipdrawer_del_item;
173 // ad->x_main_win = cd->x_main_win;
175 cd->keydown_handler = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keydown_cb, ad);
176 cd->evas = evas_object_evas_get(cd->main_win);
181 void depose_clipdrawer(ClipdrawerData *cd)
183 evas_object_del(cd->main_win);
185 ecore_timer_del(cd->anim_timer);
186 if (cd->keydown_handler)
187 ecore_event_handler_del(cd->keydown_handler);
191 static Eina_Bool clipdrawer_add_item(AppData *ad, CNP_ITEM *item)
193 ClipdrawerData *cd = ad->clipdrawer;
194 if (item->type_index == ATOM_INDEX_IMAGE)
196 Elm_Object_Item *gitem = elm_gengrid_first_item_get(cd->gengrid);
199 CNP_ITEM *gitem_data = elm_object_item_data_get(gitem);
200 gitem = elm_gengrid_item_next_get(gitem);
201 if ((gitem_data->type_index == item->type_index) && (!strcmp(item->data, gitem_data->data)))
203 DMSG("duplicated file path = %s\n", item->data);
204 item_delete_by_CNP_ITEM(ad, gitem_data);
207 cd->gic.item_style = "clipboard_photo_style";
211 cd->gic.item_style = "default_grid";
214 item->gitem = elm_gengrid_item_prepend(cd->gengrid, &cd->gic, item, NULL, NULL);
219 static Eina_Bool clipdrawer_del_item(AppData *ad, CNP_ITEM *item)
222 elm_object_item_del(item->gitem);
226 static void _grid_del(void *data, Evas_Object *obj)
228 CNP_ITEM *item = data;
233 static Evas_Object *_grid_content_get(void *data, Evas_Object *obj, const char *part)
235 CNP_ITEM *item = data;
236 AppData *ad = item->ad;
237 ClipdrawerData *cd = ad->clipdrawer;
239 if (strcmp(part, "elm.swallow.icon"))
241 if (item->type_index == ATOM_INDEX_IMAGE) /* text/uri */
245 Evas_Object *layout = elm_layout_add(obj);
246 elm_layout_theme_set(layout, "gengrid", "item", "clipboard_style");
247 edje_object_signal_callback_add(elm_layout_edje_get(layout),
248 "mouse,up,1", "*", _grid_item_ly_clicked, data);
252 sicon = evas_object_image_add(evas_object_evas_get(obj));
253 evas_object_image_load_size_set(sicon, GRID_IMAGE_REAL_W, GRID_IMAGE_REAL_H);
254 evas_object_image_file_set(sicon, item->data, NULL);
255 evas_object_image_size_get(sicon, &w, &h);
257 if (w > GRID_IMAGE_REAL_W || h > GRID_IMAGE_REAL_H)
261 iw = GRID_IMAGE_REAL_W;
262 ih = (float)GRID_IMAGE_REAL_W / w * h;
266 iw = (float)GRID_IMAGE_REAL_H / h * w;
267 ih = GRID_IMAGE_REAL_H;
276 evas_object_image_fill_set(sicon, 0, 0, iw, ih);
277 evas_object_resize(sicon, iw, ih);
278 evas_object_size_hint_min_set(sicon, iw, ih);
279 elm_object_part_content_set(layout, "elm.swallow.icon", sicon);
281 if (cd->paste_text_only)
282 edje_object_signal_emit(elm_layout_edje_get(layout), "elm,state,show,dim", "elm");
284 edje_object_signal_emit(elm_layout_edje_get(layout), "elm,state,hide,dim", "elm");
286 item->layout = layout;
290 Evas_Object *layout = elm_layout_add(obj);
291 elm_layout_theme_set(layout, "gengrid", "widestyle", "horizontal_layout");
292 edje_object_signal_callback_add(elm_layout_edje_get(layout),
293 "mouse,up,1", "*", _grid_item_ly_clicked, data);
294 Evas_Object *rect = evas_object_rectangle_add(evas_object_evas_get(obj));
295 evas_object_resize(rect, GRID_ITEM_W, GRID_ITEM_H);
296 evas_object_color_set(rect, 242, 233, 183, 255);
297 evas_object_show(rect);
298 elm_object_part_content_set(layout, "elm.swallow.icon", rect);
300 Evas_Object *ientry = elm_entry_add(obj);
301 evas_object_size_hint_weight_set(ientry, 0, 0);
302 elm_entry_scrollable_set(ientry, EINA_TRUE);
304 char *entry_text = string_for_entry_get(ad, item->type_index, item->data);
307 elm_object_part_text_set(ientry, NULL, entry_text);
312 elm_object_part_text_set(ientry, NULL, item->data);
314 elm_entry_editable_set(ientry, EINA_FALSE);
315 elm_entry_context_menu_disabled_set(ientry, EINA_TRUE);
316 evas_object_show(ientry);
317 elm_object_part_content_set(layout, "elm.swallow.inner", ientry);
319 item->layout = layout;
325 static void clipdrawer_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source)
329 if (ad->clipdrawer->anim_status != STATUS_NONE)
332 #define EDJE_CLOSE_PART_PREFIX "background/close"
333 if (!strncmp(source, EDJE_CLOSE_PART_PREFIX, strlen(EDJE_CLOSE_PART_PREFIX)))
335 clipdrawer_lower_view(ad);
339 static void _grid_del_response_cb(void *data, Evas_Object *obj, void *event_info)
341 CNP_ITEM *item = data;
342 AppData *ad = item->ad;
343 ClipdrawerData *cd = ad->clipdrawer;
344 const char *label = elm_object_item_text_get(event_info);
347 evas_object_del(obj);
349 if (!strcmp(label, "Yes"))
351 item_delete_by_CNP_ITEM(ad, item);
355 static void _grid_item_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source)
357 CNP_ITEM *item = data;
358 AppData *ad = item->ad;
359 ClipdrawerData *cd = ad->clipdrawer;
361 if (cd->anim_status != STATUS_NONE)
364 Elm_Object_Item *sgobj = NULL;
365 sgobj = elm_gengrid_selected_item_get(cd->gengrid);
366 item = elm_object_item_data_get(sgobj);
370 DTRACE("ERR: cbhm can't get the selected item\n");
374 #define EDJE_DELBTN_PART_PREFIX "delbtn"
375 if (strncmp(source, EDJE_DELBTN_PART_PREFIX, strlen(EDJE_DELBTN_PART_PREFIX)))
377 elm_gengrid_item_selected_set(sgobj, EINA_FALSE);
379 if (item->type_index != ATOM_INDEX_IMAGE || !cd->paste_text_only)
381 set_selection_owner(ad, ECORE_X_SELECTION_SECONDARY, item);
386 elm_gengrid_item_selected_set(sgobj, EINA_FALSE);
388 Evas_Object *popup = elm_popup_add(cd->main_win);
389 elm_popup_timeout_set(popup, 5);
390 evas_object_size_hint_weight_set(popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
391 elm_object_text_set(popup, "Are you sure delete this?");
392 elm_popup_item_append(popup, "Yes", NULL, _grid_del_response_cb, item);
393 elm_popup_item_append(popup, "No", NULL, _grid_del_response_cb, item);
394 evas_object_show(popup);
398 void set_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win)
400 ecore_x_icccm_transient_for_set(x_main_win, x_active_win);
401 ecore_x_event_mask_set(x_active_win,
402 ECORE_X_EVENT_MASK_WINDOW_PROPERTY | ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
405 void unset_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win)
407 ecore_x_event_mask_unset(x_active_win,
408 ECORE_X_EVENT_MASK_WINDOW_PROPERTY | ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
409 ecore_x_icccm_transient_for_unset(x_main_win);
412 static void set_focus_for_app_window(Ecore_X_Window x_main_win, Eina_Bool enable)
415 Eina_Bool accepts_focus;
416 Ecore_X_Window_State_Hint initial_state;
417 Ecore_X_Pixmap icon_pixmap;
418 Ecore_X_Pixmap icon_mask;
419 Ecore_X_Window icon_window;
420 Ecore_X_Window window_group;
423 ecore_x_icccm_hints_get (x_main_win,
424 &accepts_focus, &initial_state, &icon_pixmap, &icon_mask, &icon_window, &window_group, &is_urgent);
425 ecore_x_icccm_hints_set (x_main_win,
426 enable, initial_state, icon_pixmap, icon_mask, icon_window, window_group, is_urgent);
427 DMSG("set focus mode = %d\n", enable);
430 void setting_win(Ecore_X_Display *x_disp, Ecore_X_Window x_main_win)
433 // disable window effect
434 utilx_set_window_effect_state(x_disp, x_main_win, 0);
436 ecore_x_icccm_name_class_set(x_main_win, "NORMAL_WINDOW", "NORMAL_WINDOW");
438 set_focus_for_app_window(x_main_win, EINA_FALSE);
442 Evas_Object *create_win(ClipdrawerData *cd, const char *name)
446 Evas_Object *win = elm_win_add(NULL, name, ELM_WIN_BASIC);
449 DMSG("ERROR: elm_win_add return NULL\n");
452 elm_win_title_set(win, name);
453 elm_win_borderless_set(win, EINA_TRUE);
454 ecore_x_window_size_get(ecore_x_window_root_first_get(), &cd->root_w, &cd->root_h);
455 DMSG("root_w: %d, root_h: %d\n", cd->root_w, cd->root_h);
456 evas_object_resize(win, cd->root_w, cd->root_h);
458 elm_scale_set((double)cd->root_w/DEFAULT_WIDTH);
462 static void set_sliding_win_geometry(ClipdrawerData *cd)
466 Evas_Coord x, y, w, h;
467 zone = ecore_x_e_illume_zone_get(cd->x_main_win);
468 DTRACE(" zone:%x\n", zone);
470 if (cd->o_degree == 90 || cd->o_degree == 270)
472 h = cd->anim_count * CLIPDRAWER_HEIGHT_LANDSCAPE / ANIM_DURATION;
479 h = cd->anim_count * CLIPDRAWER_HEIGHT / ANIM_DURATION;
488 DTRACE("[CBHM] change degree geometry... (%d, %d, %d x %d)\n", x, y, w, h);
489 ecore_x_e_illume_sliding_win_geometry_set(zone, x, y, w, h);
490 ecore_x_e_illume_sliding_win_state_set(zone, cd->anim_count != 0);
493 void set_rotation_to_clipdrawer(ClipdrawerData *cd)
496 int angle = cd->o_degree;
499 if (angle == 180) // reverse
501 h = CLIPDRAWER_HEIGHT;
506 else if (angle == 90) // right rotate
508 h = CLIPDRAWER_HEIGHT_LANDSCAPE;
513 else if (angle == 270) // left rotate
515 h = CLIPDRAWER_HEIGHT_LANDSCAPE;
522 h = CLIPDRAWER_HEIGHT;
528 evas_object_resize(cd->main_win, w, h);
529 evas_object_move(cd->main_win, x, y);
530 if (cd->anim_count == ANIM_DURATION)
531 set_sliding_win_geometry(cd);
534 static Eina_Bool _get_anim_pos(ClipdrawerData *cd, int *sp, int *ep)
539 int angle = cd->o_degree;
540 int anim_start, anim_end;
542 if (angle == 180) // reverse
544 anim_start = -(cd->root_h - CLIPDRAWER_HEIGHT);
547 else if (angle == 90) // right rotate
549 anim_start = cd->root_w;
550 anim_end = anim_start - CLIPDRAWER_HEIGHT_LANDSCAPE;
552 else if (angle == 270) // left rotate
554 anim_start = -(cd->root_w - CLIPDRAWER_HEIGHT_LANDSCAPE);
559 anim_start = cd->root_h;
560 anim_end = anim_start - CLIPDRAWER_HEIGHT;
568 static Eina_Bool _do_anim_delta_pos(ClipdrawerData *cd, int sp, int ep, int ac, int *dp)
573 int angle = cd->o_degree;
576 posprop = 1.0*ac/ANIM_DURATION;
578 if (angle == 180) // reverse
580 delta = (int)((ep-sp)*posprop);
581 evas_object_move(cd->main_win, 0, sp+delta);
583 else if (angle == 90) // right rotate
585 delta = (int)((ep-sp)*posprop);
586 evas_object_move(cd->main_win, sp+delta, 0);
588 else if (angle == 270) // left rotate
590 delta = (int)((ep-sp)*posprop);
591 evas_object_move(cd->main_win, sp+delta, 0);
595 delta = (int)((sp-ep)*posprop);
596 evas_object_move(cd->main_win, 0, sp-delta);
604 static void stop_animation(AppData *ad)
607 ClipdrawerData *cd = ad->clipdrawer;
608 cd->anim_status = STATUS_NONE;
611 ecore_timer_del(cd->anim_timer);
612 cd->anim_timer = NULL;
615 set_sliding_win_geometry(cd);
618 static Eina_Bool anim_pos_calc_cb(void *data)
621 ClipdrawerData *cd = ad->clipdrawer;
622 int anim_start, anim_end, delta;
624 _get_anim_pos(cd, &anim_start, &anim_end);
626 if (cd->anim_status == SHOW_ANIM)
628 if (cd->anim_count > ANIM_DURATION)
630 cd->anim_count = ANIM_DURATION;
634 _do_anim_delta_pos(cd, anim_start, anim_end, cd->anim_count, &delta);
635 if (cd->anim_count == 1)
636 evas_object_show(cd->main_win);
639 else if (cd->anim_status == HIDE_ANIM)
641 if (cd->anim_count < 0)
644 evas_object_hide(cd->main_win);
645 elm_win_lower(cd->main_win);
646 unset_transient_for(cd->x_main_win, ad->x_active_win);
650 _do_anim_delta_pos(cd, anim_start, anim_end, cd->anim_count, &delta);
662 static Eina_Bool clipdrawer_anim_effect(AppData *ad, AnimStatus atype)
665 ClipdrawerData *cd = ad->clipdrawer;
666 if (atype == cd->anim_status)
668 DTRACE("Warning: Animation effect is already in progress. \n");
672 cd->anim_status = atype;
675 ecore_timer_del(cd->anim_timer);
676 cd->anim_timer = ecore_timer_add(ANIM_FLOPS, anim_pos_calc_cb, ad);
681 void clipdrawer_activate_view(AppData* ad)
684 ClipdrawerData *cd = ad->clipdrawer;
687 set_focus_for_app_window(cd->x_main_win, EINA_TRUE);
688 set_transient_for(cd->x_main_win, ad->x_active_win);
689 cd->o_degree = get_active_window_degree(ad->x_active_win);
690 elm_win_rotation_set(cd->main_win, cd->o_degree);
691 set_rotation_to_clipdrawer(cd);
692 // evas_object_show(cd->main_win);
693 elm_win_activate(cd->main_win);
694 // if (clipdrawer_anim_effect(ad, SHOW_ANIM))
695 clipdrawer_anim_effect(ad, SHOW_ANIM);
699 void clipdrawer_lower_view(AppData* ad)
702 ClipdrawerData *cd = ad->clipdrawer;
703 if (cd->main_win && cd->anim_count)
705 set_focus_for_app_window(cd->x_main_win, EINA_FALSE);
706 // if (clipdrawer_anim_effect(ad, HIDE_ANIM))
707 // ad->windowshow = EINA_FALSE;
708 clipdrawer_anim_effect(ad, HIDE_ANIM);