diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 121dd0395..8c234c3e4 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -114,6 +114,7 @@ src/bin/e_focus.h \ src/bin/e_font.h \ src/bin/e_gadcon.h \ src/bin/e_gadcon_popup.h \ +src/bin/e_gadget.h \ src/bin/e_grabinput.h \ src/bin/e_grab_dialog.h \ src/bin/e.h \ @@ -276,6 +277,7 @@ src/bin/e_focus.c \ src/bin/e_font.c \ src/bin/e_gadcon.c \ src/bin/e_gadcon_popup.c \ +src/bin/e_gadget.c \ src/bin/e_grabinput.c \ src/bin/e_grab_dialog.c \ src/bin/e_hints.c \ diff --git a/src/bin/e_config.c b/src/bin/e_config.c index c56f45de5..d6d30754a 100644 --- a/src/bin/e_config.c +++ b/src/bin/e_config.c @@ -2147,11 +2147,14 @@ e_config_bindings_free(E_Config_Bindings *ecb) static void _e_config_save_cb(void *data EINA_UNUSED) { + EINTERN void e_gadget_save(void); + e_config_profile_save(); e_module_save_all(); elm_config_save(); e_config_domain_save("e", _e_config_edd, e_config); e_config_domain_save("e_bindings", _e_config_binding_edd, e_bindings); + e_gadget_save(); _e_config_save_defer = NULL; } diff --git a/src/bin/e_gadget.c b/src/bin/e_gadget.c new file mode 100644 index 000000000..a7e22f373 --- /dev/null +++ b/src/bin/e_gadget.c @@ -0,0 +1,1939 @@ +#include "e.h" + +#define SNAP_DISTANCE 5 +#define E_GADGET_TYPE 0xE31337 + +#define IS_HORIZ(orient) \ + ((orient) == E_GADGET_SITE_ORIENT_HORIZONTAL) + +#define IS_VERT(orient) \ + ((orient) == E_GADGET_SITE_ORIENT_VERTICAL) + +#define ZGS_GET(obj) \ + E_Gadget_Site *zgs; \ + zgs = evas_object_data_get((obj), "__e_gadget_site"); \ + if (!zgs) abort() + +typedef struct E_Gadget_Config E_Gadget_Config; + +typedef struct E_Gadget_Site +{ + Eina_Stringshare *name; + Eina_Bool autoadd; + E_Gadget_Site_Gravity gravity; + E_Gadget_Site_Orient orient; + E_Gadget_Site_Anchor anchor; + Eina_List *gadgets; + Eina_Inlist *gadget_list; + + Evas_Object *layout; + Evas_Object *events; + E_Gadget_Style_Cb style_cb; + int cur_size; + + E_Gadget_Config *action; + Ecore_Event_Handler *move_handler; + Ecore_Event_Handler *mouse_up_handler; +} E_Gadget_Site; + + +struct E_Gadget_Config +{ + EINA_INLIST; + int id; + Eina_Stringshare *type; + E_Object *e_obj_inherit; + Evas_Object *display; + Evas_Object *gadget; + struct + { + Evas_Object *obj; + int minw, minh; + Eina_Stringshare *name; + } style; + E_Gadget_Configure_Cb configure; + Evas_Object *cfg_object; + E_Gadget_Site *site; + E_Menu *menu; + + struct + { + Evas_Object *popup; + Evas_Smart_Cb allow; + Evas_Smart_Cb deny; + void *data; + } allow_deny; + + double x, y; //fixed % positioning + double w, h; //fixed % sizing + Evas_Point offset; //offset from mouse down + Evas_Point down; //coords from mouse down + E_Gadget_Config *orig; //gadget is a copy of the original gadget during a move + Eina_Bool moving : 1; + Eina_Bool resizing : 1; +}; + +typedef struct E_Gadget_Sites +{ + Eina_List *sites; +} E_Gadget_Sites; + +typedef struct E_Gadget_Type +{ + E_Gadget_Create_Cb cb; + E_Gadget_Wizard_Cb wizard; +} E_Gadget_Type; + +typedef struct Gadget_Item +{ + Evas_Object *editor; + Evas_Object *gadget; + Evas_Object *site; +} Gadget_Item; + +#define DESKLOCK_DEMO_LAYER (E_LAYER_CLIENT_POPUP - 100) + +static Eina_List *desklock_handlers; +static Evas_Object *desklock_rect; +static Eina_Bool added = 1; + +static Evas_Object *pointer_site; +static Eina_List *handlers; + +static Eina_Hash *gadget_types; +static E_Gadget_Sites *sites; +static Ecore_Event_Handler *comp_add_handler; + +static E_Action *move_act; +static E_Action *resize_act; +static E_Action *configure_act; +static E_Action *menu_act; + +static E_Config_DD *edd_sites; +static E_Config_DD *edd_site; +static E_Config_DD *edd_gadget; + +static void _gadget_object_finalize(E_Gadget_Config *zgc); +static void _editor_pointer_site_init(E_Gadget_Site_Orient orient, Evas_Object *site, Evas_Object *editor, Eina_Bool ); + +static void +_gadget_free(E_Gadget_Config *zgc) +{ + evas_object_del(zgc->display); + eina_stringshare_del(zgc->type); + eina_stringshare_del(zgc->style.name); + free(zgc); +} + +static E_Gadget_Config * +_gadget_at_xy(E_Gadget_Site *zgs, int x, int y, E_Gadget_Config *exclude) +{ + Eina_List *l; + E_Gadget_Config *zgc, *saved = NULL; + + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + { + int ox, oy, ow, oh; + + if (!zgc->gadget) continue; + + evas_object_geometry_get(zgc->display, &ox, &oy, &ow, &oh); + if (E_INSIDE(x, y, ox, oy, ow, oh)) + { + if (zgc == exclude) saved = zgc; + else return zgc; + } + } + return saved; +} + +static void +_gravity_apply(E_Gadget_Site *zgs, E_Gadget_Site_Gravity gravity) +{ + double ax = 0.5, ay = 0.5; + + switch (gravity) + { + case E_GADGET_SITE_GRAVITY_LEFT: + ax = 0; + break; + case E_GADGET_SITE_GRAVITY_RIGHT: + ax = 1; + break; + default: break; + } + switch (gravity) + { + case E_GADGET_SITE_GRAVITY_TOP: + ay = 0; + break; + case E_GADGET_SITE_GRAVITY_BOTTOM: + ay = 1; + break; + default: break; + } + elm_box_align_set(zgs->layout, ax, ay); + evas_object_smart_callback_call(zgs->layout, "gadget_site_gravity", NULL); +} + +static void +_gadget_reparent(E_Gadget_Site *zgs, E_Gadget_Config *zgc) +{ + Eina_Inlist *l = EINA_INLIST_GET(zgc); + E_Gadget_Config *z; + + if (!zgs->orient) + { + evas_object_layer_set(zgc->display, evas_object_layer_get(zgs->layout)); + return; + } + switch (zgs->gravity) + { + case E_GADGET_SITE_GRAVITY_NONE: + /* fake */ + break; + case E_GADGET_SITE_GRAVITY_LEFT: + case E_GADGET_SITE_GRAVITY_TOP: + for (l = l->prev; l; l = l->prev) + { + z = EINA_INLIST_CONTAINER_GET(l, E_Gadget_Config); + if (!z->display) continue; + elm_box_pack_after(zgs->layout, zgc->display, z->display); + return; + } + elm_box_pack_end(zgs->layout, zgc->display); + break; + default: + for (l = l->next; l; l = l->next) + { + z = EINA_INLIST_CONTAINER_GET(l, E_Gadget_Config); + if (!z->display) continue; + elm_box_pack_before(zgs->layout, zgc->display, z->display); + return; + } + /* right aligned: pack on left */ + elm_box_pack_start(zgs->layout, zgc->display); + } +} + +static void +_gadget_popup(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + E_Gadget_Site *zgs = data; + + if (event_info) elm_object_tree_focus_allow_set(event_info, 0); + evas_object_smart_callback_call(zgs->layout, "gadget_site_popup", event_info); +} + +static void +_gadget_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Gadget_Config *zgc = data; + + if (!e_object_is_del(zgc->e_obj_inherit)) + e_object_del(zgc->e_obj_inherit); +} + +static void +_gadget_util_allow_deny_cleanup(E_Gadget_Config *zgc) +{ + zgc->allow_deny.allow = zgc->allow_deny.deny = NULL; + zgc->allow_deny.data = NULL; + evas_object_hide(zgc->allow_deny.popup); + E_FREE_FUNC(zgc->allow_deny.popup, evas_object_del); +} + +static void +_gadget_object_free(E_Object *eobj) +{ + E_Gadget_Config *zgc; + Evas_Object *g; + + g = e_object_data_get(eobj); + zgc = evas_object_data_get(g, "__e_gadget"); + evas_object_smart_callback_call(zgc->site->layout, "gadget_destroyed", zgc->gadget); + evas_object_event_callback_del_full(zgc->gadget, EVAS_CALLBACK_DEL, _gadget_del, zgc); + if (zgc->gadget == zgc->display) + zgc->display = NULL; + else + evas_object_event_callback_del_full(zgc->display, EVAS_CALLBACK_DEL, _gadget_del, zgc); + E_FREE_FUNC(zgc->gadget, evas_object_del); + E_FREE_FUNC(zgc->cfg_object, evas_object_del); + E_FREE_FUNC(zgc->style.obj, evas_object_del); + _gadget_util_allow_deny_cleanup(zgc); + E_FREE(zgc->e_obj_inherit); + zgc->configure = NULL; +} + +static void +_gadget_wizard_end(void *data, int id) +{ + E_Gadget_Config *zgc = data; + + zgc->id = id; + _gadget_object_finalize(zgc); +} + +static Eina_Bool +_gadget_object_create(E_Gadget_Config *zgc) +{ + E_Gadget_Type *t; + Evas_Object *g; + + t = eina_hash_find(gadget_types, zgc->type); + if (!t) return EINA_TRUE; //can't create yet + + if (!zgc->id) + { + if (t->wizard) + { + t->wizard(_gadget_wizard_end, zgc); + return EINA_TRUE; + } + } + /* if id is < 0, gadget creates dummy config for demo use + * if id is 0, gadget creates new config and returns id + * otherwise, config of `id` is applied to created object + */ + g = t->cb(zgc->site->layout, &zgc->id, zgc->site->orient); + EINA_SAFETY_ON_NULL_RETURN_VAL(g, EINA_FALSE); + + zgc->e_obj_inherit = E_OBJECT_ALLOC(E_Object, E_GADGET_TYPE, _gadget_object_free); + e_object_data_set(zgc->e_obj_inherit, g); + zgc->gadget = zgc->display = g; + evas_object_smart_callback_add(g, "gadget_popup", _gadget_popup, zgc->site); + evas_object_data_set(g, "__e_gadget", zgc); + if (zgc->site->style_cb) + zgc->site->style_cb(zgc->site->layout, zgc->style.name, g); + + evas_object_event_callback_add(g, EVAS_CALLBACK_DEL, _gadget_del, zgc); + _gadget_reparent(zgc->site, zgc); + elm_object_tree_focus_allow_set(zgc->gadget, 0); + evas_object_raise(zgc->site->events); + + evas_object_smart_callback_call(zgc->site->layout, "gadget_created", g); + evas_object_show(zgc->display); + return EINA_TRUE; +} + +static void +_gadget_object_finalize(E_Gadget_Config *zgc) +{ + zgc->moving = 0; + if (_gadget_object_create(zgc)) + { + if (!zgc->display) return; + evas_object_smart_callback_call(zgc->site->layout, "gadget_added", zgc->gadget); + e_config_save_queue(); + return; + } + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + zgc->site->gadget_list = eina_inlist_remove(zgc->site->gadget_list, EINA_INLIST_GET(zgc)); + eina_stringshare_del(zgc->type); + free(zgc); +} + +static void +_site_gadget_resize(Evas_Object *g, int w, int h, Evas_Coord *ww, Evas_Coord *hh, Evas_Coord *ow, Evas_Coord *oh) +{ + Evas_Coord mnw, mnh, mxw, mxh; + E_Gadget_Config *zgc; + Evas_Aspect_Control aspect; + int ax, ay; + + zgc = evas_object_data_get(g, "__e_gadget"); + w -= zgc->style.minw; + h -= zgc->style.minh; + + evas_object_size_hint_min_get(g, &mnw, &mnh); + evas_object_size_hint_max_get(g, &mxw, &mxh); + evas_object_size_hint_aspect_get(g, &aspect, &ax, &ay); + + if (IS_HORIZ(zgc->site->orient)) + { + *ww = mnw, *hh = h; + if (!(*ww)) *ww = *hh; + } + else if (IS_VERT(zgc->site->orient)) + { + *hh = mnh, *ww = w; + if (!(*hh)) *hh = *ww; + } + else + { + *ww = mnw, *hh = mnh; + if (!(*ww)) *ww = w; + if (!(*hh)) *hh = h; + } + if (aspect && ax && ay) + { + switch (aspect) + { + case EVAS_ASPECT_CONTROL_HORIZONTAL: + *hh = (*ww * ay / ax); + break; + case EVAS_ASPECT_CONTROL_VERTICAL: + *ww = (*hh * ax / ay); + break; + default: + if (IS_HORIZ(zgc->site->orient)) + *ww = (*hh * ax / ay); + else if (IS_VERT(zgc->site->orient)) + *hh = (*ww * ay / ax); + else + { + double ar = ax / (double) ay; + + if (ar > 1.0) + *hh = (*ww * ay / ax); + else + *ww = (*hh * ax / ay); + } + } + } + *ww += zgc->style.minw; + *hh += zgc->style.minh; + *ow = *ww, *oh = *hh; + if ((!ax) && (!ay)) + { + if ((mxw >= 0) && (mxw < *ow)) *ow = mxw; + if ((mxh >= 0) && (mxh < *oh)) *oh = mxh; + } + //fprintf(stderr, "%s: %dx%d\n", zgc->type, *ow, *oh); + evas_object_resize(zgc->display, *ow, *oh); +} + +static void +_site_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + int x, y, w, h; + E_Gadget_Site *zgs = data; + + evas_object_geometry_get(obj, &x, &y, &w, &h); + evas_object_geometry_set(zgs->events, x, y, w, h); + evas_object_raise(zgs->events); + if (!zgs->orient) + evas_object_smart_need_recalculate_set(zgs->layout, 1); +} + +static void +_site_layout_orient(Evas_Object *o, E_Gadget_Site *zgs) +{ + Evas_Coord x, y, w, h, xx, yy; + Eina_List *l; + double ax, ay; + E_Gadget_Config *zgc; + + evas_object_geometry_get(o, &x, &y, &w, &h); + evas_object_geometry_set(zgs->events, x, y, w, h); + + evas_object_box_align_get(o, &ax, &ay); + + xx = x; + yy = y; + + if (zgs->gravity % 2)//left/top + { + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + { + Evas_Coord gx = xx, gy = yy; + int ww, hh, ow, oh; + + if (!zgc->display) continue; + + _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); + if (IS_HORIZ(zgs->orient)) + gx += (Evas_Coord)(((double)(ww - ow)) * 0.5), + gy += (h / 2) - (oh / 2); + else if (IS_VERT(zgs->orient)) + gy += (Evas_Coord)(((double)(hh - oh)) * 0.5), + gx += (w / 2) - (ow / 2); + evas_object_move(zgc->display, gx, gy); + if (IS_HORIZ(zgs->orient)) + xx += ow; + else + yy += oh; + } + } + else if (zgs->gravity) + { + if (IS_HORIZ(zgs->orient)) + xx += w; + else + yy += h; + + EINA_LIST_REVERSE_FOREACH(zgs->gadgets, l, zgc) + { + Evas_Coord gx = xx, gy = yy; + int ww, hh, ow, oh; + + if (!zgc->display) continue; + + _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); + if (IS_HORIZ(zgs->orient)) + gx -= (Evas_Coord)(((double)(ww - ow)) * 0.5) + ow, + gy += (h / 2) - (oh / 2); + else + gy -= (Evas_Coord)(((double)(hh - oh)) * 0.5) + oh, + gx += (w / 2) - (ow / 2); + evas_object_move(zgc->display, gx, gy); + if (IS_HORIZ(zgs->orient)) + xx -= ow; + else + yy -= oh; + } + } + + if (IS_HORIZ(zgs->orient)) + zgs->cur_size = abs(xx - x); + else if (IS_VERT(zgs->orient)) + zgs->cur_size = abs(yy - y); + + evas_object_size_hint_min_set(o, + IS_HORIZ(zgs->orient) ? zgs->cur_size : w, + IS_VERT(zgs->orient) ? zgs->cur_size : h); +} + +static void +_site_layout(Evas_Object *o, Evas_Object_Box_Data *priv EINA_UNUSED, void *data) +{ + E_Gadget_Site *zgs = data; + Evas_Coord x, y, w, h, xx, yy;//, px, py; + Eina_List *l; + double ax, ay; + E_Gadget_Config *zgc; + + evas_object_geometry_get(o, &x, &y, &w, &h); + evas_object_geometry_set(zgs->events, x, y, w, h); + + evas_object_box_align_get(o, &ax, &ay); + + xx = x; + yy = y; + if (zgs->orient) + { + _site_layout_orient(o, zgs); + return; + } + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + { + Evas_Coord gx = xx, gy = yy; + int ww, hh, ow, oh; + + if (!zgc->display) continue; + _site_gadget_resize(zgc->gadget, w * zgc->w, h * zgc->h, &ww, &hh, &ow, &oh); + if (zgc->x > -1.0) + { + gx = zgc->x * w; + gx += (Evas_Coord)(((double)(ww - ow)) * 0.5 * -ax); + } + if (zgc->y > -1.0) + { + gy = zgc->y * h; + gy += (Evas_Coord)(((double)(hh - oh)) * 0.5 * -ay); + } + if (zgs->gravity) + { +#if 0//FIXME + if (zgs->gravity % 2)//left/top + { + if (gx < px) gx = px; + } + else if ( + { + if (gx > px) gx = px; + } + + if (zgs->gravity % 2)//left/top + { + if (gy < py) gy = py; + } + else + { + if (gy > py) gy = py; + } +#endif + } + + evas_object_move(zgc->display, gx, gy); +#if 0//FIXME + if (zgs->gravity is horizontal or something) + px = gx + (-ax * ow); + else + py = gy + (-ay * oh); +#endif + if (eina_list_count(zgs->gadgets) == 1) + evas_object_size_hint_min_set(o, ow, oh); + } +} + +static Eina_Bool +_gadget_mouse_resize(E_Gadget_Config *zgc, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) +{ + int x, y, w, h;//site geom + int ox, oy, ow, oh;//gadget geom + double gw, gh; + + evas_object_geometry_get(zgc->site->layout, &x, &y, &w, &h); + evas_object_geometry_get(zgc->display, &ox, &oy, &ow, &oh); + gw = zgc->w * w; + gh = zgc->h * h; + gw += (ev->x - zgc->down.x); + gh += (ev->y - zgc->down.y); + zgc->w = gw / w; + zgc->h = gh / h; + zgc->down.x = ev->x; + zgc->down.y = ev->y; + elm_box_recalculate(zgc->site->layout); + e_config_save_queue(); + return ECORE_CALLBACK_RENEW; +} + +static void +_gadget_util_add(E_Gadget_Site *zgs, const char *type, int id) +{ + E_Gadget_Config *zgc; + + zgc = E_NEW(E_Gadget_Config, 1); + zgc->id = id; + zgc->type = eina_stringshare_add(type); + zgc->x = zgc->y = -1; + zgc->site = zgs; + if (zgc->site->orient) + zgc->w = zgc->h = -1; + else + { + int w, h; + + evas_object_geometry_get(zgc->site->layout, NULL, NULL, &w, &h); + zgc->w = (96 * e_scale) / (double)w; + zgc->h = (96 * e_scale) / (double)h; + } + zgc->site->gadgets = eina_list_append(zgc->site->gadgets, zgc); + zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(zgc)); + _gadget_object_finalize(zgc); +} + +static Eina_Bool +_gadget_act_resize_end(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + E_Gadget_Config *zgc; + Evas_Object *g; + + if (obj->type != E_GADGET_TYPE) return EINA_FALSE; + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__e_gadget"); + zgc->moving = 0; + + E_FREE_FUNC(zgc->site->move_handler, ecore_event_handler_del); + return EINA_TRUE; +} + +static Eina_Bool +_gadget_act_move(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + E_Gadget_Config *zgc, *z; + Evas_Object *g; + + if (obj->type != E_GADGET_TYPE) return EINA_FALSE; + + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__e_gadget"); + zgc->moving = 1; + evas_object_pass_events_set(zgc->site->layout, 1); + _editor_pointer_site_init(zgc->site->orient, NULL, NULL, 1); + e_gadget_site_owner_setup(pointer_site, zgc->site->anchor, NULL); + ZGS_GET(pointer_site); + _gadget_util_add(zgs, zgc->type, zgc->id); + z = eina_list_data_get(zgs->gadgets); + eina_stringshare_refplace(&z->style.name, zgc->style.name); + z->orig = zgc; + return EINA_TRUE; +} + +static Eina_Bool +_gadget_act_resize(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + E_Gadget_Config *zgc; + Evas_Object *g; + + if (obj->type != E_GADGET_TYPE) return EINA_FALSE; + + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__e_gadget"); + if (zgc->site->orient) return EINA_FALSE; + zgc->resizing = 1; + if (!zgc->site->move_handler) + zgc->site->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, (Ecore_Event_Handler_Cb)_gadget_mouse_resize, zgc); + return EINA_TRUE; +} + +static void +_gadget_act_configure_object_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Gadget_Config *zgc = data; + + zgc->cfg_object = NULL; +} + +static void +_gadget_configure(E_Gadget_Config *zgc) +{ + if (!zgc->configure) return; + if (zgc->cfg_object) + { + evas_object_raise(zgc->cfg_object); + evas_object_show(zgc->cfg_object); + return; + } + zgc->cfg_object = zgc->configure(zgc->gadget); + if (!zgc->cfg_object) return; + evas_object_event_callback_add(zgc->cfg_object, EVAS_CALLBACK_DEL, _gadget_act_configure_object_del, zgc); +} + +static Eina_Bool +_gadget_act_configure(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + E_Gadget_Config *zgc; + Evas_Object *g; + + if (obj->type != E_GADGET_TYPE) return EINA_FALSE; + + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__e_gadget"); + _gadget_configure(zgc); + return EINA_TRUE; +} + +static void +_gadget_menu_remove(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) +{ + E_Gadget_Config *zgc = data; + + evas_object_smart_callback_call(zgc->site->layout, "gadget_removed", zgc->gadget); + zgc->site->gadget_list = eina_inlist_remove(zgc->site->gadget_list, EINA_INLIST_GET(zgc)); + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + evas_object_smart_need_recalculate_set(zgc->site->layout, 1); + _gadget_free(zgc); + e_config_save_queue(); +} + +static void +_gadget_menu_configure(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) +{ + _gadget_configure(data); +} + +static void +_gadget_style_menu_item_del(void *mi) +{ + eina_stringshare_del(e_object_data_get(mi)); +} + +static void +_gadget_menu_style(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) +{ + E_Gadget_Config *zgc = data; + Eina_Stringshare *style = e_object_data_get(E_OBJECT(mi)); + + eina_stringshare_refplace(&zgc->style.name, style); + if (zgc->site->style_cb) + zgc->site->style_cb(zgc->site->layout, style, zgc->gadget); +} + +static Eina_Bool +_gadget_act_menu(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev) +{ + E_Gadget_Config *zgc; + Evas_Object *g; + E_Menu_Item *mi; + E_Menu *subm; + int x, y; + + if (obj->type != E_GADGET_TYPE) return EINA_FALSE; + + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__e_gadget"); + + zgc->menu = e_menu_new(); + evas_object_smart_callback_call(g, "gadget_menu", zgc->menu); + if (zgc->configure) + { + mi = e_menu_item_new(zgc->menu); + e_menu_item_label_set(mi, _("Settings")); + e_util_menu_item_theme_icon_set(mi, "configure"); + e_menu_item_callback_set(mi, _gadget_menu_configure, zgc); + } + if (zgc->menu->items) + { + mi = e_menu_item_new(zgc->menu); + e_menu_item_separator_set(mi, 1); + } + subm = e_menu_new(); + evas_object_smart_callback_call(zgc->site->layout, "gadget_site_style_menu", subm); + if (e_object_data_get(E_OBJECT(subm))) + { + Eina_List *styles = e_object_data_get(E_OBJECT(subm)); + Eina_Stringshare *style; + + mi = e_menu_item_new(zgc->menu); + e_menu_item_label_set(mi, _("Look")); + e_util_menu_item_theme_icon_set(mi, "preferences-look"); + e_menu_item_submenu_set(mi, subm); + e_object_unref(E_OBJECT(subm)); + + EINA_LIST_FREE(styles, style) + { + char buf[1024]; + + if (eina_streq(style, "base")) + { + eina_stringshare_del(style); + continue; + } + mi = e_menu_item_new(subm); + strncpy(buf, style, sizeof(buf) - 1); + buf[0] = toupper(buf[0]); + e_menu_item_label_set(mi, buf); + snprintf(buf, sizeof(buf), "enlightenment/%s", style); + e_util_menu_item_theme_icon_set(mi, buf); + e_menu_item_radio_group_set(mi, 1); + e_menu_item_radio_set(mi, 1); + e_menu_item_toggle_set(mi, style == zgc->style.name); + e_menu_item_disabled_set(mi, mi->toggle); + e_object_data_set(E_OBJECT(mi), style); + E_OBJECT_DEL_SET(mi, _gadget_style_menu_item_del); + e_menu_item_callback_set(mi, _gadget_menu_style, zgc); + } + } + else + e_object_del(E_OBJECT(subm)); + + + mi = e_menu_item_new(zgc->menu); + evas_object_smart_callback_call(zgc->site->layout, "gadget_site_owner_menu", mi); + if (mi->label) + { + mi = e_menu_item_new(zgc->menu); + e_menu_item_separator_set(mi, 1); + } + else + e_object_del(E_OBJECT(mi)); + + mi = e_menu_item_new(zgc->menu); + e_menu_item_label_set(mi, _("Remove")); + e_util_menu_item_theme_icon_set(mi, "list-remove"); + e_menu_item_callback_set(mi, _gadget_menu_remove, zgc); + + evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); + e_menu_activate_mouse(zgc->menu, + e_zone_current_get(), + x, y, 1, 1, + E_MENU_POP_DIRECTION_AUTO, ev->timestamp); + evas_object_smart_callback_call(zgc->site->layout, "gadget_site_popup", zgc->menu->comp_object); + return EINA_TRUE; +} + +static Eina_Bool +_site_mouse_up(E_Gadget_Site *zgs, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) +{ + if (e_bindings_mouse_up_ecore_event_handle(E_BINDING_CONTEXT_ANY, zgs->action->e_obj_inherit, ev)) + { + evas_object_pointer_mode_set(zgs->events, EVAS_OBJECT_POINTER_MODE_NOGRAB); + zgs->action = NULL; + E_FREE_FUNC(zgs->mouse_up_handler, ecore_event_handler_del); + } + return ECORE_CALLBACK_RENEW; +} + +static void +_site_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) +{ + E_Gadget_Site *zgs = data; + Evas_Event_Mouse_Down *ev = event_info; + E_Gadget_Config *zgc; + E_Action *act; + + zgc = _gadget_at_xy(zgs, ev->output.x, ev->output.y, NULL); + if (!zgc) return; + act = e_bindings_mouse_down_evas_event_handle(E_BINDING_CONTEXT_ANY, zgc->e_obj_inherit, event_info); + if (!act) return; + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + if (act->func.end_mouse) + { + int x, y; + + evas_object_pointer_mode_set(obj, EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN); + zgs->action = zgc; + if (!zgs->mouse_up_handler) + zgs->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, (Ecore_Event_Handler_Cb)_site_mouse_up, zgs); + + evas_object_geometry_get(zgc->display, &x, &y, NULL, NULL); + zgc->offset.x = ev->canvas.x - x; + zgc->offset.y = ev->canvas.y - y; + zgc->down.x = ev->canvas.x; + zgc->down.y = ev->canvas.y; + } +} + +static void +_site_drop(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + E_Gadget_Site *zgs = data, *drop; + Eina_List *l; + E_Gadget_Config *zgc, *dzgc; + int mx, my; + int x, y, w, h; + + drop = evas_object_data_get(event_info, "__e_gadget_site"); + evas_pointer_canvas_xy_get(e_comp->evas, &mx, &my); + evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); + if (!E_INSIDE(mx, my, x, y, w, h)) return; + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + { + if (!zgc->display) continue; + + evas_object_geometry_get(zgc->display, &x, &y, &w, &h); + if (E_INSIDE(mx, my, x, y, w, h)) break; + } + if (zgc) + { + Eina_Bool pre = EINA_FALSE; + if (IS_HORIZ(zgs->orient)) + { + if (mx <= x + (w / 2)) + pre = EINA_TRUE; + } + else if (IS_VERT(zgs->orient)) + { + if (my <= y + (h / 2)) + pre = EINA_TRUE; + } + else {} //FIXME + if (zgs->orient) + { + Eina_List *ll; + + if (pre) + EINA_LIST_REVERSE_FOREACH(drop->gadgets, ll, dzgc) + { + evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); + evas_object_del(dzgc->gadget); + zgs->gadget_list = eina_inlist_prepend_relative(zgs->gadget_list, + EINA_INLIST_GET(dzgc), EINA_INLIST_GET(zgc)); + zgs->gadgets = eina_list_prepend_relative_list(zgs->gadgets, dzgc, l); + dzgc->site = zgs; + if (dzgc->id == -1) dzgc->id = 0; + _gadget_object_finalize(dzgc); + } + else + EINA_LIST_REVERSE_FOREACH(drop->gadgets, ll, dzgc) + { + evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); + evas_object_del(dzgc->gadget); + zgs->gadget_list = eina_inlist_append_relative(zgs->gadget_list, + EINA_INLIST_GET(dzgc), EINA_INLIST_GET(zgc)); + zgs->gadgets = eina_list_append_relative_list(zgs->gadgets, dzgc, l); + dzgc->site = zgs; + if (dzgc->id == -1) dzgc->id = 0; + _gadget_object_finalize(dzgc); + } + } + else + { + int dx, dy, dw, dh, gx, gy, gw, gh; + + /* FIXME: this should place _(around)_ the gadget that got dropped on */ + evas_object_geometry_get(drop->layout, &dx, &dy, &dw, &dh); + evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); + EINA_LIST_FOREACH(drop->gadgets, l, dzgc) + { + /* calculate positioning offsets and normalize based on drop point */ + evas_object_geometry_get(dzgc->display, &gx, &gy, &gw, &gh); + evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->display); + evas_object_del(dzgc->gadget); + zgs->gadget_list = eina_inlist_append(zgs->gadget_list, + EINA_INLIST_GET(dzgc)); + zgs->gadgets = eina_list_append(zgs->gadgets, dzgc); + dzgc->x = ((gx - dx) / (double)dw) + ((mx - x) / (double)w); + dzgc->y = ((gy - dy) / (double)dh) + ((my - y) / (double)h); + dzgc->w = gw / (double)dw; + dzgc->h = gh / (double)dh; + dzgc->site = zgs; + if (dzgc->id == -1) dzgc->id = 0; + _gadget_object_finalize(dzgc); + } + } + } + else + { + if (zgs->orient) + { + if (mx >= x) //right of all exiting gadgets + { + EINA_LIST_FOREACH(drop->gadgets, l, dzgc) + { + evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); + evas_object_del(dzgc->gadget); + zgs->gadget_list = eina_inlist_append(zgs->gadget_list, + EINA_INLIST_GET(dzgc)); + zgs->gadgets = eina_list_append(zgs->gadgets, dzgc); + dzgc->site = zgs; + if (dzgc->id == -1) dzgc->id = 0; + _gadget_object_finalize(dzgc); + } + } + else + { + EINA_LIST_REVERSE_FOREACH(drop->gadgets, l, dzgc) + { + evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); + evas_object_del(dzgc->gadget); + zgs->gadget_list = eina_inlist_prepend(zgs->gadget_list, + EINA_INLIST_GET(dzgc)); + zgs->gadgets = eina_list_prepend(zgs->gadgets, dzgc); + dzgc->site = zgs; + if (dzgc->id == -1) dzgc->id = 0; + _gadget_object_finalize(dzgc); + } + } + } + else + { + int dx, dy, dw, dh, gx, gy, gw, gh; + + evas_object_geometry_get(drop->layout, &dx, &dy, &dw, &dh); + evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); + EINA_LIST_FOREACH(drop->gadgets, l, dzgc) + { + /* calculate positioning offsets and normalize based on drop point */ + evas_object_geometry_get(dzgc->display, &gx, &gy, &gw, &gh); + evas_object_smart_callback_call(zgs->layout, "gadget_moved", dzgc->gadget); + evas_object_del(dzgc->gadget); + zgs->gadget_list = eina_inlist_append(zgs->gadget_list, + EINA_INLIST_GET(dzgc)); + zgs->gadgets = eina_list_append(zgs->gadgets, dzgc); + dzgc->x = ((gx - dx) / (double)dw) + ((mx - x) / (double)w); + dzgc->y = ((gy - dy) / (double)dh) + ((my - y) / (double)h); + dzgc->w = gw / (double)w; + dzgc->h = gh / (double)h; + dzgc->site = zgs; + if (dzgc->id == -1) dzgc->id = 0; + _gadget_object_finalize(dzgc); + } + } + } + drop->gadget_list = NULL; + drop->gadgets = eina_list_free(drop->gadgets); + evas_object_smart_need_recalculate_set(zgs->layout, 1); + e_config_save_queue(); +} + +static void +_site_restack(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + E_Gadget_Site *zgs = data; + + if (!evas_object_smart_parent_get(zgs->layout)) + { + Eina_List *l; + E_Gadget_Config *zgc; + int layer; + + layer = evas_object_layer_get(obj); + if (!zgs->orient) + { + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + if (zgc->display) + evas_object_layer_set(zgc->display, layer); + } + evas_object_layer_set(zgs->events, layer); + } + evas_object_raise(zgs->events); +} + +static void +_site_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Gadget_Site *zgs = data; + E_Gadget_Config *zgc; + Eina_List *l; + + E_FREE_FUNC(zgs->events, evas_object_del); + zgs->layout = NULL; + zgs->cur_size = 0; + zgs->action = NULL; + zgs->style_cb = NULL; + E_FREE_FUNC(zgs->move_handler, ecore_event_handler_del); + E_FREE_FUNC(zgs->mouse_up_handler, ecore_event_handler_del); + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + evas_object_del(zgc->gadget); + if (zgs->name) return; + eina_stringshare_del(zgs->name); + free(zgs); +} + +static void +_site_style(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Gadget_Site *zgs = data; + E_Gadget_Config *zgc; + Eina_List *l; + + if (!zgs->style_cb) return; + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + if (zgc->display) + zgc->site->style_cb(zgc->site->layout, zgc->style.name, zgc->gadget); +} + +static void +_site_create(E_Gadget_Site *zgs) +{ + zgs->layout = elm_box_add(e_comp->elm); + elm_box_horizontal_set(zgs->layout, zgs->orient == E_GADGET_SITE_ORIENT_HORIZONTAL); + _gravity_apply(zgs, zgs->gravity); + if (!zgs->orient) + { + /* add dummy content to allow recalc to work */ + elm_box_pack_end(zgs->layout, elm_box_add(zgs->layout)); + } + elm_box_layout_set(zgs->layout, _site_layout, zgs, NULL); + evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_DEL, _site_del, zgs); + evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_RESTACK, _site_restack, zgs); + + zgs->events = evas_object_rectangle_add(e_comp->evas); + evas_object_name_set(zgs->events, "zgs->events"); + evas_object_event_callback_add(zgs->layout, EVAS_CALLBACK_MOVE, _site_move, zgs); + evas_object_smart_callback_add(zgs->layout, "gadget_site_dropped", _site_drop, zgs); + evas_object_smart_callback_add(zgs->layout, "gadget_site_style", _site_style, zgs); + evas_object_pointer_mode_set(zgs->events, EVAS_OBJECT_POINTER_MODE_NOGRAB); + evas_object_color_set(zgs->events, 0, 0, 0, 0); + evas_object_repeat_events_set(zgs->events, 1); + evas_object_show(zgs->events); + evas_object_event_callback_add(zgs->events, EVAS_CALLBACK_MOUSE_DOWN, _site_mouse_down, zgs); + + evas_object_data_set(zgs->layout, "__e_gadget_site", zgs); + E_LIST_FOREACH(zgs->gadgets, _gadget_object_create); + evas_object_layer_set(zgs->events, evas_object_layer_get(zgs->layout)); + evas_object_raise(zgs->events); +} + +static void +_site_auto_add(E_Gadget_Site *zgs, Evas_Object *comp_object) +{ + int x, y, w, h; + + _site_create(zgs); + e_comp_object_util_del_list_append(comp_object, zgs->layout); + evas_object_layer_set(zgs->layout, evas_object_layer_get(comp_object)); + evas_object_stack_above(zgs->layout, comp_object); + evas_object_geometry_get(comp_object, &x, &y, &w, &h); + evas_object_geometry_set(zgs->layout, x, y, w, h); +} + +static Eina_Bool +_site_auto_comp_object_handler(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Comp_Object *ev) +{ + const char *name; + Eina_List *l; + E_Gadget_Site *zgs; + + name = evas_object_name_get(ev->comp_object); + if (!name) return ECORE_CALLBACK_RENEW; + EINA_LIST_FOREACH(sites->sites, l, zgs) + if (zgs->autoadd && eina_streq(zgs->name, name)) + { + if (!zgs->layout) + _site_auto_add(zgs, ev->comp_object); + break; + } + return ECORE_CALLBACK_RENEW; +} + +static Evas_Object * +_site_util_add(E_Gadget_Site_Orient orient, const char *name, Eina_Bool autoadd) +{ + E_Gadget_Site *zgs; + Eina_List *l; + Evas_Object *parent; + + if (name) + { + EINA_LIST_FOREACH(sites->sites, l, zgs) + if (eina_streq(zgs->name, name)) + { + if (zgs->layout) return zgs->layout; + goto out; + } + } + zgs = E_NEW(E_Gadget_Site, 1); + + zgs->name = eina_stringshare_add(name); + zgs->orient = orient; + zgs->autoadd = autoadd; + switch (orient) + { + case E_GADGET_SITE_ORIENT_HORIZONTAL: + zgs->gravity = E_GADGET_SITE_GRAVITY_LEFT; + break; + case E_GADGET_SITE_ORIENT_VERTICAL: + zgs->gravity = E_GADGET_SITE_GRAVITY_TOP; + break; + default: break; + } + + if (name) + sites->sites = eina_list_append(sites->sites, zgs); +out: + if (autoadd) + { + parent = evas_object_name_find(e_comp->evas, name); + if (parent) + _site_auto_add(zgs, parent); + } + else + _site_create(zgs); + + return zgs->layout; +} + +E_API Evas_Object * +e_gadget_site_add(E_Gadget_Site_Orient orient, const char *name) +{ + return _site_util_add(orient, name, 0); +} + +E_API Evas_Object * +e_gadget_site_auto_add(E_Gadget_Site_Orient orient, const char *name) +{ + return _site_util_add(orient, name, 1); +} + +E_API void +e_gadget_site_del(Evas_Object *obj) +{ + ZGS_GET(obj); + + sites->sites = eina_list_remove(sites->sites, zgs); + evas_object_del(zgs->layout); + eina_stringshare_del(zgs->name); + free(zgs); +} + +E_API E_Gadget_Site_Anchor +e_gadget_site_anchor_get(Evas_Object *obj) +{ + ZGS_GET(obj); + + return zgs->anchor; +} + +E_API void +e_gadget_site_owner_setup(Evas_Object *obj, E_Gadget_Site_Anchor an, E_Gadget_Style_Cb cb) +{ + Evas_Object *parent; + ZGS_GET(obj); + + zgs->anchor = an; + zgs->style_cb = cb; + evas_object_smart_callback_call(zgs->layout, "gadget_site_anchor", NULL); + parent = evas_object_smart_parent_get(obj); + if (parent) + evas_object_smart_member_add(zgs->events, parent); + else + evas_object_smart_member_del(zgs->events); +} + +E_API E_Gadget_Site_Orient +e_gadget_site_orient_get(Evas_Object *obj) +{ + ZGS_GET(obj); + return zgs->orient; +} + +E_API E_Gadget_Site_Gravity +e_gadget_site_gravity_get(Evas_Object *obj) +{ + ZGS_GET(obj); + return zgs->gravity; +} + +E_API void +e_gadget_site_gravity_set(Evas_Object *obj, E_Gadget_Site_Gravity gravity) +{ + ZGS_GET(obj); + if (zgs->gravity == gravity) return; + zgs->gravity = gravity; + _gravity_apply(zgs, gravity); + evas_object_smart_need_recalculate_set(zgs->layout, 1); +} + +E_API Eina_List * +e_gadget_site_gadgets_list(Evas_Object *obj) +{ + Eina_List *l, *list = NULL; + E_Gadget_Config *zgc; + + ZGS_GET(obj); + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + if (zgc->display) + list = eina_list_append(list, zgc->gadget); + return list; +} + +E_API void +e_gadget_site_gadget_add(Evas_Object *obj, const char *type, Eina_Bool demo) +{ + int id = 0; + + demo = !!demo; + id -= demo; + EINA_SAFETY_ON_NULL_RETURN(gadget_types); + ZGS_GET(obj); + _gadget_util_add(zgs, type, id); +} + +E_API Evas_Object * +e_gadget_site_get(Evas_Object *g) +{ + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); + return zgc->site->layout; +} + +E_API void +e_gadget_configure_cb_set(Evas_Object *g, E_Gadget_Configure_Cb cb) +{ + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_NULL_RETURN(g); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN(zgc); + zgc->configure = cb; +} + +E_API void +e_gadget_configure(Evas_Object *g) +{ + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_NULL_RETURN(g); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN(zgc); + _gadget_configure(zgc); +} + +E_API Eina_Stringshare * +e_gadget_type_get(Evas_Object *g) +{ + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); + return zgc->type; +} + +E_API void +e_gadget_type_add(const char *type, E_Gadget_Create_Cb callback, E_Gadget_Wizard_Cb wizard) +{ + E_Gadget_Type *t; + Eina_List *l, *ll; + E_Gadget_Site *zgs; + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_TRUE_RETURN(!!eina_hash_find(gadget_types, type)); + t = E_NEW(E_Gadget_Type, 1); + t->cb = callback; + t->wizard = wizard; + eina_hash_add(gadget_types, type, t); + EINA_LIST_FOREACH(sites->sites, l, zgs) + EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) + if (eina_streq(type, zgc->type)) + _gadget_object_create(zgc); +} + +E_API void +e_gadget_type_del(const char *type) +{ + Eina_List *l, *ll; + E_Gadget_Site *zgs; + E_Gadget_Config *zgc; + char buf[1024]; + + strncpy(buf, type, sizeof(buf)); + + if (!gadget_types) return; + + EINA_LIST_FOREACH(sites->sites, l, zgs) + { + EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) + if (eina_streq(buf, zgc->type)) + evas_object_del(zgc->gadget); + } + eina_hash_del_by_key(gadget_types, type); +} + +E_API Eina_Iterator * +e_gadget_type_iterator_get(void) +{ + return gadget_types ? eina_hash_iterator_key_new(gadget_types) : NULL; +} + +E_API Evas_Object * +e_gadget_util_layout_style_init(Evas_Object *g, Evas_Object *style) +{ + E_Gadget_Config *zgc; + Evas_Object *prev; + const char *grp; + + EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN_VAL(zgc, NULL); + + prev = zgc->style.obj; + zgc->style.obj = style; + if (style) + { + elm_layout_file_get(style, NULL, &grp); + eina_stringshare_replace(&zgc->style.name, strrchr(grp, '/') + 1); + evas_object_event_callback_add(style, EVAS_CALLBACK_DEL, _gadget_del, zgc); + } + else + eina_stringshare_replace(&zgc->style.name, NULL); + if (prev) + evas_object_event_callback_del_full(prev, EVAS_CALLBACK_DEL, _gadget_del, zgc); + e_config_save_queue(); + zgc->display = style ?: zgc->gadget; + E_FILL(zgc->display); + E_EXPAND(zgc->display); + if (zgc->site->gravity) + { + elm_box_pack_before(zgc->site->layout, zgc->display, prev ?: zgc->gadget); + if (prev) + elm_box_unpack(zgc->site->layout, prev); + } + evas_object_raise(zgc->site->events); + if (!style) return prev; + + evas_object_data_set(style, "__e_gadget", zgc); + + elm_layout_sizing_eval(style); + evas_object_smart_calculate(style); + evas_object_size_hint_min_get(style, &zgc->style.minw, &zgc->style.minh); + evas_object_show(style); + return prev; +} + +E_API void +e_gadget_util_ctxpopup_place(Evas_Object *g, Evas_Object *ctx, Evas_Object *pos_obj) +{ + int x, y, w, h; + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_NULL_RETURN(g); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN(zgc); + + elm_ctxpopup_hover_parent_set(ctx, e_comp->elm); + evas_object_layer_set(ctx, evas_object_layer_get(pos_obj ?: g)); + + evas_object_geometry_get(pos_obj ?: g, &x, &y, &w, &h); + if (zgc->site->anchor & E_GADGET_SITE_ANCHOR_TOP) + y += h; + if (zgc->site->anchor & E_GADGET_SITE_ANCHOR_LEFT) + x += w; + if (zgc->site->orient == E_GADGET_SITE_ORIENT_HORIZONTAL) + { + x += w / 2; + elm_ctxpopup_direction_priority_set(ctx, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_DOWN, 0, 0); + } + else if (zgc->site->orient == E_GADGET_SITE_ORIENT_VERTICAL) + { + y += h / 2; + elm_ctxpopup_direction_priority_set(ctx, ELM_CTXPOPUP_DIRECTION_RIGHT, ELM_CTXPOPUP_DIRECTION_LEFT, 0, 0); + } + evas_object_move(ctx, x, y); + evas_object_smart_callback_call(zgc->site->layout, "gadget_site_popup", ctx); +} + +static void +_gadget_util_allow(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Gadget_Config *zgc = data; + + zgc->allow_deny.allow(zgc->allow_deny.data, zgc->gadget, NULL); + _gadget_util_allow_deny_cleanup(zgc); +} + +static void +_gadget_util_deny(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Gadget_Config *zgc = data; + + zgc->allow_deny.deny(zgc->allow_deny.data, zgc->gadget, NULL); + _gadget_util_allow_deny_cleanup(zgc); +} + +E_API void +e_gadget_util_allow_deny_ctxpopup(Evas_Object *g, const char *text, Evas_Smart_Cb allow_cb, Evas_Smart_Cb deny_cb, const void *data) +{ + Evas_Object *ctx, *tb, *lbl, *bt; + E_Gadget_Config *zgc; + + EINA_SAFETY_ON_NULL_RETURN(g); + zgc = evas_object_data_get(g, "__e_gadget"); + EINA_SAFETY_ON_NULL_RETURN(zgc); + + /* FIXME */ + EINA_SAFETY_ON_TRUE_RETURN(!!zgc->allow_deny.popup); + + EINA_SAFETY_ON_NULL_RETURN(allow_cb); + EINA_SAFETY_ON_NULL_RETURN(deny_cb); + EINA_SAFETY_ON_NULL_RETURN(text); + + zgc->allow_deny.allow = allow_cb; + zgc->allow_deny.deny = deny_cb; + zgc->allow_deny.data = (void*)data; + + ctx = elm_ctxpopup_add(e_comp->elm); + elm_object_style_set(ctx, "noblock"); + + tb = elm_table_add(ctx); + E_EXPAND(tb); + E_FILL(tb); + evas_object_show(tb); + lbl = elm_label_add(ctx); + E_FILL(lbl); + elm_object_text_set(lbl, text); + evas_object_show(lbl); + elm_table_pack(tb, lbl, 0, 0, 2, 2); + + bt = elm_button_add(ctx); + evas_object_show(bt); + E_EXPAND(bt); + E_FILL(bt); + elm_object_text_set(bt, _("Deny")); + evas_object_smart_callback_add(bt, "clicked", _gadget_util_deny, zgc); + elm_table_pack(tb, bt, 0, 2, 1, 1); + + bt = elm_button_add(ctx); + evas_object_show(bt); + E_EXPAND(bt); + E_FILL(bt); + elm_object_text_set(bt, _("Allow")); + evas_object_smart_callback_add(bt, "clicked", _gadget_util_allow, zgc); + elm_table_pack(tb, bt, 1, 2, 1, 1); + + elm_object_content_set(ctx, tb); + + e_gadget_util_ctxpopup_place(g, ctx, NULL); + zgc->allow_deny.popup = e_comp_object_util_add(ctx, E_COMP_OBJECT_TYPE_NONE); + evas_object_layer_set(zgc->allow_deny.popup, E_LAYER_POPUP); + evas_object_show(zgc->allow_deny.popup); +} + +EINTERN void +e_gadget_save(void) +{ + e_config_domain_save("e_gadget_sites", edd_sites, sites); +} + +EINTERN void +e_gadget_init(void) +{ + gadget_types = eina_hash_string_superfast_new(free); + edd_gadget = E_CONFIG_DD_NEW("E_Gadget_Config", E_Gadget_Config); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, id, INT); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, type, STR); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, style.name, STR); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, x, DOUBLE); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, y, DOUBLE); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, w, DOUBLE); + E_CONFIG_VAL(edd_gadget, E_Gadget_Config, h, DOUBLE); + + edd_site = E_CONFIG_DD_NEW("E_Gadget_Site", E_Gadget_Site); + E_CONFIG_VAL(edd_site, E_Gadget_Site, gravity, UINT); + E_CONFIG_VAL(edd_site, E_Gadget_Site, orient, UINT); + E_CONFIG_VAL(edd_site, E_Gadget_Site, anchor, UINT); + E_CONFIG_VAL(edd_site, E_Gadget_Site, autoadd, UCHAR); + E_CONFIG_VAL(edd_site, E_Gadget_Site, name, STR); + + E_CONFIG_LIST(edd_site, E_Gadget_Site, gadgets, edd_gadget); + + edd_sites = E_CONFIG_DD_NEW("E_Gadget_Sites", E_Gadget_Sites); + E_CONFIG_LIST(edd_sites, E_Gadget_Sites, sites, edd_site); + sites = e_config_domain_load("e_gadget_sites", edd_sites); + if (sites) + { + Eina_List *l; + E_Gadget_Site *zgs; + + EINA_LIST_FOREACH(sites->sites, l, zgs) + { + Eina_List *ll; + E_Gadget_Config *zgc; + + EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) + { + zgs->gadget_list = eina_inlist_append(zgs->gadget_list, EINA_INLIST_GET(zgc)); + zgc->site = zgs; + } + } + } + else + sites = E_NEW(E_Gadget_Sites, 1); + + move_act = e_action_add("gadget_move"); + e_action_predef_name_set(_("Gadgets"), _("Move gadget"), "gadget_move", NULL, NULL, 0); + move_act->func.go_mouse = _gadget_act_move; + + resize_act = e_action_add("gadget_resize"); + e_action_predef_name_set(_("Gadgets"), _("Resize gadget"), "gadget_resize", NULL, NULL, 0); + resize_act->func.go_mouse = _gadget_act_resize; + resize_act->func.end_mouse = _gadget_act_resize_end; + + configure_act = e_action_add("gadget_configure"); + e_action_predef_name_set(_("Gadgets"), _("Configure gadget"), "gadget_configure", NULL, NULL, 0); + configure_act->func.go_mouse = _gadget_act_configure; + + menu_act = e_action_add("gadget_menu"); + e_action_predef_name_set(_("Gadgets"), _("Gadget menu"), "gadget_menu", NULL, NULL, 0); + menu_act->func.go_mouse = _gadget_act_menu; + + comp_add_handler = ecore_event_handler_add(E_EVENT_COMP_OBJECT_ADD, (Ecore_Event_Handler_Cb)_site_auto_comp_object_handler, NULL); +} + +EINTERN void +e_gadget_shutdown(void) +{ + E_Gadget_Site *zgs; + + E_FREE_FUNC(comp_add_handler, ecore_event_handler_del); + E_CONFIG_DD_FREE(edd_gadget); + E_CONFIG_DD_FREE(edd_site); + E_CONFIG_DD_FREE(edd_sites); + EINA_LIST_FREE(sites->sites, zgs) + { + E_FREE_LIST(zgs->gadgets, _gadget_free); + evas_object_del(zgs->layout); + eina_stringshare_del(zgs->name); + free(zgs); + } + E_FREE(sites); + + e_action_del("gadget_move"); + e_action_del("gadget_resize"); + e_action_del("gadget_configure"); + e_action_del("gadget_menu"); + e_action_predef_name_del(_("Gadgets"), _("Move gadget")); + e_action_predef_name_del(_("Gadgets"), _("Resize gadget")); + e_action_predef_name_del(_("Gadgets"), _("Configure gadget")); + e_action_predef_name_del(_("Gadgets"), _("Gadget menu")); + move_act = resize_act = configure_act = menu_act = NULL; + E_FREE_FUNC(gadget_types, eina_hash_free); +} + +////////////////////////////////////////////////////// +//// EDITOR ///// +////////////////////////////////////////////////////// + +static void +_editor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_FREE_LIST(data, free); +} + +static void +_editor_pointer_site_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + e_comp_ungrab_input(1, 1); + free(data); + pointer_site = NULL; + E_FREE_LIST(handlers, ecore_event_handler_del); +} + +static void +_editor_site_hints(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + int x, y, w, h; + + evas_object_size_hint_min_get(obj, &w, &h); + evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); + evas_object_geometry_set(pointer_site, x - (w / 2), y - (h / 2), w, h); +} + +static Eina_Bool +_editor_pointer_button(Gadget_Item *active, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) +{ + int x, y, w, h; + E_Gadget_Site *zgs, *zzgs = NULL; + + if (active->site) + { + evas_object_geometry_get(active->site, &x, &y, &w, &h); + if ((ev->buttons == 1) && E_INSIDE(ev->x, ev->y, x, y, w, h)) + evas_object_smart_callback_call(active->site, "gadget_site_dropped", pointer_site); + evas_object_pass_events_set(active->site, 0); + elm_object_disabled_set(active->editor, 1); + e_comp_object_util_del_list_remove(active->editor, pointer_site); + } + else + { + E_Gadget_Config *zgc, *z; + Eina_List *l; + + if (ev->buttons == 1) + { + EINA_LIST_FOREACH(sites->sites, l, zgs) + { + if (!zgs->layout) continue; + if (!evas_object_visible_get(zgs->layout)) continue; + evas_object_geometry_get(zgs->layout, &x, &y, &w, &h); + if (!E_INSIDE(ev->x, ev->y, x, y, w, h)) continue; + /* FIXME: technically not accurate since objects on the same layer + * will have different stacking, but walking object trees sucks + */ + if ((!zzgs) || + (evas_object_layer_get(zzgs->layout) < evas_object_layer_get(zgs->layout))) + zzgs = zgs; + } + } + zgs = evas_object_data_get(pointer_site, "__e_gadget_site"); + zgc = eina_list_data_get(zgs->gadgets); + evas_object_pass_events_set(zgc->orig->site->layout, 0); + if (zzgs) + { + /* fake the moving gadget as being on the pointer site */ + z = zgc->orig; + zgc->site->gadget_list = eina_inlist_remove(zgc->site->gadget_list, EINA_INLIST_GET(zgc)); + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + _gadget_free(zgc); + z->site->gadget_list = eina_inlist_remove(z->site->gadget_list, EINA_INLIST_GET(z)); + z->site->gadgets = eina_list_remove(z->site->gadgets, z); + zgs->gadgets = eina_list_append(zgs->gadgets, z); + z->site = zgs; + evas_object_smart_callback_call(zzgs->layout, "gadget_site_dropped", pointer_site); + } + + } + E_FREE_FUNC(pointer_site, evas_object_del); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_editor_pointer_move(Gadget_Item *active EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) +{ + int w, h; + + evas_object_geometry_get(pointer_site, NULL, NULL, &w, &h); + evas_object_move(pointer_site, ev->x - (w / 2), ev->y - (h / 2)); + return ECORE_CALLBACK_RENEW; +} + +static void +_editor_pointer_site_init(E_Gadget_Site_Orient orient, Evas_Object *site, Evas_Object *editor, Eina_Bool up) +{ + Gadget_Item *active; + Evas_Object *rect; + int size; + + pointer_site = e_gadget_site_add(orient, NULL); + if (site && (orient == E_GADGET_SITE_ORIENT_HORIZONTAL)) + evas_object_geometry_get(site, NULL, NULL, NULL, &size); + else if (site && (orient == E_GADGET_SITE_ORIENT_VERTICAL)) + evas_object_geometry_get(site, NULL, NULL, &size, NULL); + else + size = 96 * e_scale; + evas_object_resize(pointer_site, size, size); + evas_object_layer_set(pointer_site, E_LAYER_MENU); + evas_object_pass_events_set(pointer_site, 1); + evas_object_show(pointer_site); + active = E_NEW(Gadget_Item, 1); + active->editor = editor; + active->site = site; + if (active->site) + evas_object_pass_events_set(active->site, 1); + evas_object_event_callback_add(pointer_site, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _editor_site_hints, active); + evas_object_event_callback_add(pointer_site, EVAS_CALLBACK_DEL, _editor_pointer_site_del, active); + E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE, _editor_pointer_move, active); + E_LIST_HANDLER_APPEND(handlers, + up ? ECORE_EVENT_MOUSE_BUTTON_UP : ECORE_EVENT_MOUSE_BUTTON_DOWN, _editor_pointer_button, active); + + rect = evas_object_rectangle_add(e_comp->evas); + evas_object_resize(rect, e_comp->w, e_comp->h); + evas_object_color_set(rect, 0, 0, 0, 0); + evas_object_layer_set(rect, E_LAYER_MENU + 1); + e_comp_object_util_del_list_append(pointer_site, rect); + evas_object_show(rect); + e_comp_grab_input(1, 1); +} + +static void +_editor_gadget_new(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + Gadget_Item *gi = data; + E_Gadget_Site_Orient orient; + + orient = e_gadget_site_orient_get(gi->site); + _editor_pointer_site_init(orient, gi->site, gi->editor, 0); + e_comp_object_util_del_list_append(gi->editor, pointer_site); + + e_gadget_site_gadget_add(pointer_site, e_gadget_type_get(gi->gadget), 1); + elm_object_disabled_set(gi->editor, 1); + elm_list_item_selected_set(event_info, 0); +} + +E_API Evas_Object * +e_gadget_editor_add(Evas_Object *parent, Evas_Object *site) +{ + Evas_Object *list, *tempsite, *g; + Eina_Iterator *it; + Eina_List *gadgets, *items = NULL; + const char *type; + + list = elm_list_add(parent); + elm_scroller_content_min_limit(list, 1, 1); + tempsite = e_gadget_site_add(E_GADGET_SITE_ORIENT_HORIZONTAL, NULL); + e_gadget_site_gravity_set(tempsite, E_GADGET_SITE_GRAVITY_NONE); + + it = e_gadget_type_iterator_get(); + /* FIXME: no types available */ + EINA_ITERATOR_FOREACH(it, type) + e_gadget_site_gadget_add(tempsite, type, 1); + eina_iterator_free(it); + + gadgets = e_gadget_site_gadgets_list(tempsite); + EINA_LIST_FREE(gadgets, g) + { + Evas_Object *box, *button = NULL; + char buf[1024]; + Gadget_Item *gi; + + gi = E_NEW(Gadget_Item, 1); + gi->editor = list; + gi->gadget = g; + gi->site = site; + items = eina_list_append(items, gi); + box = elm_box_add(list); + elm_box_horizontal_set(box, 1); + E_EXPAND(g); + E_FILL(g); + elm_box_pack_end(box, g); + evas_object_pass_events_set(g, 1); + strncpy(buf, e_gadget_type_get(g), sizeof(buf) - 1); + buf[0] = toupper(buf[0]); + elm_list_item_append(list, buf, box, button, _editor_gadget_new, gi); + elm_box_recalculate(box); + } + evas_object_data_set(list, "__gadget_items", items); + evas_object_event_callback_add(list, EVAS_CALLBACK_DEL, _editor_del, items); + elm_list_go(list); + return list; +} + +E_API Evas_Object * +e_gadget_site_edit(Evas_Object *site) +{ + Evas_Object *comp_object, *popup, *editor; + E_Zone *zone; + + zone = e_comp_object_util_zone_get(site); + if (!zone) zone = e_zone_current_get(); + + popup = elm_popup_add(e_comp->elm); + elm_popup_allow_events_set(popup, 1); + + editor = e_gadget_editor_add(e_comp->elm, site); + evas_object_show(editor); + E_FILL(editor); + elm_object_content_set(popup, editor); + comp_object = e_comp_object_util_add(popup, E_COMP_OBJECT_TYPE_NONE); + evas_object_layer_set(comp_object, E_LAYER_POPUP); + evas_object_show(comp_object); + evas_object_resize(comp_object, zone->w / 2, zone->h / 2); + e_comp_object_util_center(comp_object); + return comp_object; +} + + +static void +_gadget_desklock_del(void) +{ + e_desklock_hide(); +} + +static void +_edit_end() +{ + E_FREE_LIST(desklock_handlers, ecore_event_handler_del); + e_comp_ungrab_input(1, 1); +} + +static Eina_Bool +_gadget_key_handler(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev) +{ + if (eina_streq(ev->key, "Escape")) + _gadget_desklock_del(); + return ECORE_CALLBACK_DONE; +} + +static void +_gadget_mouse_up_handler() +{ + if (!added) + _gadget_desklock_del(); + added = 0; +} + +static void +_gadget_moved() +{ + added = 1; +} + +static Eina_Bool +_gadget_desklock_handler(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Comp_Object *ev) +{ + E_Notification_Notify n; + const char *name; + Evas_Object *site, *comp_object; + + name = evas_object_name_get(ev->comp_object); + if (!name) return ECORE_CALLBACK_RENEW; + if (strncmp(name, "desklock", 8)) return ECORE_CALLBACK_RENEW; + evas_object_layer_set(ev->comp_object, DESKLOCK_DEMO_LAYER - 1); + site = e_gadget_site_auto_add(E_GADGET_SITE_ORIENT_NONE, name); + evas_object_smart_callback_add(site, "gadget_moved", _gadget_moved, NULL); + evas_object_layer_set(site, DESKLOCK_DEMO_LAYER); + comp_object = e_gadget_site_edit(site); + e_comp_object_util_del_list_append(ev->comp_object, comp_object); + e_comp_object_util_del_list_append(ev->comp_object, desklock_rect); + + memset(&n, 0, sizeof(E_Notification_Notify)); + n.timeout = 3000; + n.summary = _("Lockscreen Gadgets"); + n.body = _("Press Escape or click the background to exit."); + n.urgency = E_NOTIFICATION_NOTIFY_URGENCY_NORMAL; + e_notification_client_send(&n, NULL, NULL); + return ECORE_CALLBACK_RENEW; +} + +E_API void +e_gadget_site_desklock_edit(void) +{ + desklock_rect = evas_object_rectangle_add(e_comp->evas); + evas_object_event_callback_add(desklock_rect, EVAS_CALLBACK_DEL, _edit_end, NULL); + evas_object_color_set(desklock_rect, 0, 0, 0, 0); + evas_object_resize(desklock_rect, e_comp->w, e_comp->h); + evas_object_layer_set(desklock_rect, DESKLOCK_DEMO_LAYER); + evas_object_show(desklock_rect); + E_LIST_HANDLER_APPEND(desklock_handlers, E_EVENT_COMP_OBJECT_ADD, _gadget_desklock_handler, NULL); + E_LIST_HANDLER_APPEND(desklock_handlers, ECORE_EVENT_KEY_DOWN, _gadget_key_handler, NULL); + E_LIST_HANDLER_APPEND(desklock_handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _gadget_mouse_up_handler, NULL); + e_desklock_demo(); + e_comp_grab_input(1, 1); +} diff --git a/src/bin/e_gadget.h b/src/bin/e_gadget.h new file mode 100644 index 000000000..f0bf2a500 --- /dev/null +++ b/src/bin/e_gadget.h @@ -0,0 +1,140 @@ +#ifndef E_TYPEDEFS +#ifndef E_GADGET_H +# define E_GADGET_H + + +/** SMART CALLBACKS: + ------------------------------- + * called by gadget site internals on gadget site object: + + * have a gadget object as event_info + * { + "gadget_added" + - a new gadget was added to the gadget site by the user + "gadget_created" + - a gadget object was created on the site + "gadget_destroyed" + - a gadget object was destroyed on the site + "gadget_moved" + - a gadget is preparing to move from its current site + "gadget_removed" + - a gadget was removed from the gadget site by the user + - the gadget should remove its config when this is triggered + * } + + * have NULL as event_info + * { + "gadget_site_anchor" + - the anchor of the gadget site changed + "gadget_site_gravity" + - the gravity of the gadget site changed + * } + + * have E_Menu as event_info + * { + "gadget_site_owner_menu" + - the owner (parent object) of the site should add any owner-specific items + in this callback (eg. settings) + "gadget_site_style_menu" + - the owner (parent object) of the site should add any style-specific items + in this callback (eg. plain, inset) + * } + + * have Evas_Object as event_info + * { + "gadget_site_popup" + - a popup has been triggered from the site; the site must remain visible until + the passed popup object has been hidden + - event_info is the Evas_Object of the popup + * } + ------------------------------- + ------------------------------- + * called externally on gadget site + "gadget_site_dropped" + - called on a target site when a gadget site is dropped on it + - event_info is the dropped site + - all gadgets on the dropped site will be moved to the target site + "gadget_site_style" + - called on a target site when its owner has executed a style change + - event_info is NULL + - triggers restyling of all contained gadgets + ------------------------------- + ------------------------------- + * called by gadget internals on gadget object: + "gadget_menu" + - called on a gadget object when the "gadget_menu" action has been triggered + - event_info is an E_Menu object + - if a configure callback has been passed with e_gadget_configure_cb_set(), + a "Settings" item will be automatically added with this callback + ------------------------------- + ------------------------------- + * called externally by gadget on gadget object: + "gadget_popup" + - called on a gadget object by the gadget when the gadget creates a popup which + requires that the gadget remain visible for the lifetime of the popup + - event_info is the Evas_Object of the popup + */ + +typedef enum +{ + E_GADGET_SITE_GRAVITY_NONE = 0, + E_GADGET_SITE_GRAVITY_LEFT, + E_GADGET_SITE_GRAVITY_RIGHT, + E_GADGET_SITE_GRAVITY_TOP, + E_GADGET_SITE_GRAVITY_BOTTOM, + E_GADGET_SITE_GRAVITY_CENTER, +} E_Gadget_Site_Gravity; + +typedef enum +{ + E_GADGET_SITE_ORIENT_NONE = 0, + E_GADGET_SITE_ORIENT_HORIZONTAL, + E_GADGET_SITE_ORIENT_VERTICAL, +} E_Gadget_Site_Orient; + +typedef enum +{ + E_GADGET_SITE_ANCHOR_NONE = 0, + E_GADGET_SITE_ANCHOR_LEFT = (1 << 0), + E_GADGET_SITE_ANCHOR_RIGHT = (1 << 1), + E_GADGET_SITE_ANCHOR_TOP = (1 << 2), + E_GADGET_SITE_ANCHOR_BOTTOM = (1 << 3), +} E_Gadget_Site_Anchor; + +typedef Evas_Object *(*E_Gadget_Create_Cb)(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient); +typedef Evas_Object *(*E_Gadget_Configure_Cb)(Evas_Object *gadget); +typedef void (*E_Gadget_Wizard_End_Cb)(void *data, int id); +typedef void (*E_Gadget_Wizard_Cb)(E_Gadget_Wizard_End_Cb cb, void *data); +typedef void (*E_Gadget_Style_Cb)(Evas_Object *owner, Eina_Stringshare *name, Evas_Object *g); + +EINTERN void e_gadget_init(void); +EINTERN void e_gadget_shutdown(void); + +E_API Evas_Object *e_gadget_site_add(E_Gadget_Site_Orient orient, const char *name); +E_API Evas_Object *e_gadget_site_auto_add(E_Gadget_Site_Orient orient, const char *name); +E_API void e_gadget_site_del(Evas_Object *obj); +E_API E_Gadget_Site_Anchor e_gadget_site_anchor_get(Evas_Object *obj); +E_API void e_gadget_site_owner_setup(Evas_Object *obj, E_Gadget_Site_Anchor an, E_Gadget_Style_Cb cb); +E_API E_Gadget_Site_Orient e_gadget_site_orient_get(Evas_Object *obj); +E_API E_Gadget_Site_Gravity e_gadget_site_gravity_get(Evas_Object *obj); +E_API void e_gadget_site_gravity_set(Evas_Object *obj, E_Gadget_Site_Gravity gravity); +E_API void e_gadget_site_gadget_add(Evas_Object *obj, const char *type, Eina_Bool demo); +E_API Eina_List *e_gadget_site_gadgets_list(Evas_Object *obj); + +E_API void e_gadget_configure_cb_set(Evas_Object *g, E_Gadget_Configure_Cb cb); +E_API void e_gadget_configure(Evas_Object *g); +E_API Evas_Object *e_gadget_site_get(Evas_Object *g); +E_API Eina_Stringshare *e_gadget_type_get(Evas_Object *g); + +E_API void e_gadget_type_add(const char *type, E_Gadget_Create_Cb callback, E_Gadget_Wizard_Cb wizard); +E_API void e_gadget_type_del(const char *type); +E_API Eina_Iterator *e_gadget_type_iterator_get(void); + +E_API Evas_Object *e_gadget_util_layout_style_init(Evas_Object *g, Evas_Object *style); +E_API void e_gadget_util_ctxpopup_place(Evas_Object *g, Evas_Object *ctx, Evas_Object *pos_obj); +E_API void e_gadget_util_allow_deny_ctxpopup(Evas_Object *g, const char *text, Evas_Smart_Cb allow_cb, Evas_Smart_Cb deny_cb, const void *data); + +E_API Evas_Object *e_gadget_editor_add(Evas_Object *parent, Evas_Object *site); +E_API Evas_Object *e_gadget_site_edit(Evas_Object *site); +#endif +#endif diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index 9bf0fc0e5..38f54846a 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -150,6 +150,7 @@ #include "e_utils.h" #include "e_hints.h" #include "e_comp_x_randr.h" +#include "e_gadget.h" #ifdef HAVE_WAYLAND # include "e_comp_wl.h" diff --git a/src/bin/e_main.c b/src/bin/e_main.c index 2781b86ec..4142bcce8 100644 --- a/src/bin/e_main.c +++ b/src/bin/e_main.c @@ -909,6 +909,14 @@ main(int argc, char **argv) TS("E_Remember Init Done"); _e_main_shutdown_push(e_remember_shutdown); + if (e_config->show_splash) + e_init_status_set(_("Setup Gadgets")); + TS("E_Gadget Init"); + e_gadget_init(); + TS("E_Gadget Init Done"); + _e_main_shutdown_push((void*)e_gadget_shutdown); + + if (e_config->show_splash) e_init_status_set(_("Setup Gadcon")); TS("E_Gadcon Init");