efl/legacy/elementary/src/lib/elm_mapbuf.c

606 lines
17 KiB
C

#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_widget_mapbuf.h"
#include "elm_widget_container.h"
EAPI Eo_Op ELM_OBJ_MAPBUF_BASE_ID = EO_NOOP;
#define MY_CLASS ELM_OBJ_MAPBUF_CLASS
#define MY_CLASS_NAME "elm_mapbuf"
static void
_sizing_eval(Evas_Object *obj)
{
Evas_Coord minw = -1, minh = -1;
Evas_Coord maxw = -1, maxh = -1;
ELM_MAPBUF_DATA_GET(obj, sd);
if (sd->content)
{
evas_object_size_hint_min_get(sd->content, &minw, &minh);
evas_object_size_hint_max_get(sd->content, &maxw, &maxh);
}
evas_object_size_hint_min_set(obj, minw, minh);
evas_object_size_hint_max_set(obj, maxw, maxh);
}
static void
_elm_mapbuf_smart_theme(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
{
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
if (ret) *ret = EINA_FALSE;
Eina_Bool int_ret = EINA_FALSE;
eo_do_super(obj, MY_CLASS, elm_wdg_theme(&int_ret));
if (!int_ret) return;
_sizing_eval(obj);
if (ret) *ret = EINA_TRUE;
}
static void
_changed_size_hints_cb(void *data,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
void *event_info __UNUSED__)
{
_sizing_eval(data);
}
static void
_elm_mapbuf_smart_sub_object_del(Eo *obj, void *_pd, va_list *list)
{
Elm_Mapbuf_Smart_Data *sd = _pd;
Evas_Object *sobj = va_arg(*list, Evas_Object *);
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
if (ret) *ret = EINA_FALSE;
Eina_Bool int_ret = EINA_FALSE;
eo_do_super(obj, MY_CLASS, elm_wdg_sub_object_del(sobj, &int_ret));
if (!int_ret) return;
if (sobj == sd->content)
{
evas_object_data_del(sobj, "_elm_leaveme");
evas_object_smart_member_del(sobj);
evas_object_clip_unset(sobj);
evas_object_event_callback_del_full
(sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints_cb,
obj);
sd->content = NULL;
_sizing_eval(obj);
}
if (ret) *ret = EINA_TRUE;
}
static void
_mapbuf(Evas_Object *obj)
{
Evas_Coord x, y, w, h;
ELM_MAPBUF_DATA_GET(obj, sd);
Elm_Widget_Smart_Data *wd = eo_data_scope_get(obj, ELM_OBJ_WIDGET_CLASS);
evas_object_geometry_get(wd->resize_obj, &x, &y, &w, &h);
evas_object_resize(sd->content, w, h);
if (sd->enabled)
{
static Evas_Map *m = NULL;
if (!m) m = evas_map_new(4);
evas_map_util_points_populate_from_geometry(m, x, y, w, h, 0);
evas_map_smooth_set(m, sd->smooth);
evas_map_alpha_set(m, sd->alpha);
evas_object_map_set(sd->content, m);
evas_object_map_enable_set(sd->content, EINA_TRUE);
}
else
{
evas_object_map_set(sd->content, NULL);
evas_object_map_enable_set(sd->content, EINA_FALSE);
evas_object_move(sd->content, x, y);
}
}
static void
_configure(Evas_Object *obj, Eina_Bool update_force)
{
ELM_MAPBUF_DATA_GET(obj, sd);
Elm_Widget_Smart_Data *wd = eo_data_scope_get(obj, ELM_OBJ_WIDGET_CLASS);
if (!sd->content) return;
Eina_Bool inside_all = EINA_FALSE;
Evas_Coord x, y, w, h, x2, y2, w2, h2, vx, vy, vw, vh;
evas_object_geometry_get(wd->resize_obj, &x, &y, &w, &h);
evas_object_geometry_get(sd->content, &x2, &y2, &w2, &h2);
if ((update_force) || ((x != x2) || (y != y2) || (w != w2) || (h != h2)))
{
Evas *e = evas_object_evas_get(obj);
evas_output_viewport_get(e, &vx, &vy, &vw, &vh);
/* Apply no changes once the content is rendered fully one time. We
aren't sure that the content is updated correctly if the content was
outside of the viewport, especially it has many child members. Some
type of children will do the lazy updated (ie, textblock) on right
before the rendering. It means they lose the update time cause
of the mapbuf since the mapbuf tries nochange forcefully. */
if (!sd->inside_view[0] && ((x >= vx) && (x <= (vx + vw))))
sd->inside_view[0] = EINA_TRUE;
if (!sd->inside_view[1] && ((y >= vy) && (y <= (vy + vh))))
sd->inside_view[1] = EINA_TRUE;
if (!sd->inside_view[2] && (((x + w) >= vx) && ((x + w) <= (vx + vw))))
sd->inside_view[2] = EINA_TRUE;
if (!sd->inside_view[3] && (((y + h) >= vy) && ((y + h) <= (vy + vh))))
sd->inside_view[3] = EINA_TRUE;
if (sd->inside_view[0] && sd->inside_view[1] && sd->inside_view[2] &&
sd->inside_view[3])
inside_all = EINA_TRUE;
if (!sd->enabled || !inside_all)
evas_object_move(sd->content, x, y);
else
{
/* This causes many side effects in calculating mapbuf objects.
But it doesn't affect to the mapbuf it's own special feature, performance. */
// evas_smart_objects_calculate(e);
evas_nochange_push(e);
evas_object_move(sd->content, x, y);
// evas_smart_objects_calculate(e);
evas_nochange_pop(e);
}
_mapbuf(obj);
}
}
static void
_mapbuf_auto_eval(Evas_Object *obj, Elm_Mapbuf_Smart_Data *sd)
{
Eina_Bool vis;
Evas_Coord x, y, w, h;
Evas_Coord vx, vy, vw, vh;
Eina_Bool on = EINA_FALSE;
if (!sd->automode) return ;
vis = evas_object_visible_get(obj);
evas_object_geometry_get(obj, &x, &y, &w, &h);
evas_output_viewport_get(evas_object_evas_get(obj), &vx, &vy, &vw, &vh);
if ((vis) && (ELM_RECTS_INTERSECT(x, y, w, h, vx, vy, vw, vh)))
on = EINA_TRUE;
elm_mapbuf_enabled_set(obj, on);
}
static Eina_Bool
_mapbuf_move_end(void *data)
{
Elm_Mapbuf_Smart_Data *sd = data;
elm_mapbuf_smooth_set(sd->self, sd->smooth_saved);
sd->idler = NULL;
return EINA_FALSE;
}
static void
_mapbuf_auto_smooth(Evas_Object *obj EINA_UNUSED, Elm_Mapbuf_Smart_Data *sd)
{
if (!sd->automode) return ;
if (!sd->idler) sd->idler = ecore_idler_add(_mapbuf_move_end, sd);
sd->smooth = EINA_FALSE;
}
static void
_elm_mapbuf_smart_move(Eo *obj, void *_pd, va_list *list)
{
Evas_Coord x = va_arg(*list, Evas_Coord);
Evas_Coord y = va_arg(*list, Evas_Coord);
eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
_mapbuf_auto_eval(obj, _pd);
_mapbuf_auto_smooth(obj, _pd);
_configure(obj, EINA_FALSE);
}
static void
_elm_mapbuf_smart_resize(Eo *obj, void *_pd, va_list *list)
{
Evas_Coord w = va_arg(*list, Evas_Coord);
Evas_Coord h = va_arg(*list, Evas_Coord);
eo_do_super(obj, MY_CLASS, evas_obj_smart_resize(w, h));
_mapbuf_auto_eval(obj, _pd);
_configure(obj, EINA_FALSE);
}
static void
_elm_mapbuf_smart_show(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
{
eo_do_super(obj, MY_CLASS, evas_obj_smart_show());
_mapbuf_auto_eval(obj, _pd);
_configure(obj, EINA_FALSE);
}
static void
_elm_mapbuf_smart_hide(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
{
eo_do_super(obj, MY_CLASS, evas_obj_smart_hide());
_mapbuf_auto_eval(obj, _pd);
_configure(obj, EINA_FALSE);
}
static void
_elm_mapbuf_inside_view_reset(Evas_Object *obj)
{
ELM_MAPBUF_DATA_GET(obj, sd);
sd->inside_view[0] = EINA_FALSE;
sd->inside_view[1] = EINA_FALSE;
sd->inside_view[2] = EINA_FALSE;
sd->inside_view[3] = EINA_FALSE;
}
static void
_elm_mapbuf_smart_content_set(Eo *obj, void *_pd, va_list *list)
{
Elm_Mapbuf_Smart_Data *sd = _pd;
Elm_Widget_Smart_Data *wd = eo_data_scope_get(obj, ELM_OBJ_WIDGET_CLASS);
const char *part = va_arg(*list, const char *);
Evas_Object *content = va_arg(*list, Evas_Object *);
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
if (ret) *ret = EINA_FALSE;
if (part && strcmp(part, "default")) return;
if (sd->content == content)
{
if (ret) *ret = EINA_TRUE;
return;
}
if (sd->content) evas_object_del(sd->content);
sd->content = content;
if (content)
{
evas_object_data_set(content, "_elm_leaveme", (void *)1);
elm_widget_sub_object_add(obj, content);
evas_object_smart_member_add(content, obj);
evas_object_clip_set(content, wd->resize_obj);
evas_object_color_set
(wd->resize_obj, 255, 255, 255, 255);
evas_object_event_callback_add
(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
_changed_size_hints_cb, obj);
}
else
evas_object_color_set(wd->resize_obj, 0, 0, 0, 0);
_elm_mapbuf_inside_view_reset(obj);
_sizing_eval(obj);
_configure(obj, EINA_TRUE);
if (ret) *ret = EINA_TRUE;
}
static void
_elm_mapbuf_smart_content_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
Elm_Mapbuf_Smart_Data *sd = _pd;
const char *part = va_arg(*list, const char *);
Evas_Object **ret = va_arg(*list, Evas_Object **);
*ret = NULL;
if (part && strcmp(part, "default")) return;
*ret = sd->content;
}
static void
_elm_mapbuf_smart_content_unset(Eo *obj, void *_pd, va_list *list)
{
Evas_Object *content;
const char *part = va_arg(*list, const char *);
Evas_Object **ret = va_arg(*list, Evas_Object **);
if (ret) *ret = NULL;
Elm_Mapbuf_Smart_Data *sd = _pd;
Elm_Widget_Smart_Data *wd = eo_data_scope_get(obj, ELM_OBJ_WIDGET_CLASS);
if (part && strcmp(part, "default")) return;
if (!sd->content) return;
content = sd->content;
elm_widget_sub_object_del(obj, content);
evas_object_smart_member_del(content);
evas_object_data_del(content, "_elm_leaveme");
evas_object_color_set(wd->resize_obj, 0, 0, 0, 0);
if (ret) *ret = content;
ELM_SAFE_FREE(sd->idler, ecore_idler_del);
}
static void
_elm_mapbuf_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
{
Elm_Mapbuf_Smart_Data *priv = _pd;
Evas_Object *rect = evas_object_rectangle_add(evas_object_evas_get(obj));
elm_widget_resize_object_set(obj, rect);
eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
evas_object_static_clip_set(rect, EINA_TRUE);
evas_object_pass_events_set(rect, EINA_TRUE);
evas_object_color_set(rect, 0, 0, 0, 0);
priv->self = obj;
priv->alpha = EINA_TRUE;
priv->smooth = EINA_TRUE;
elm_widget_can_focus_set(obj, EINA_FALSE);
_sizing_eval(obj);
}
EAPI Evas_Object *
elm_mapbuf_add(Evas_Object *parent)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
Evas_Object *obj = eo_add(MY_CLASS, parent);
eo_unref(obj);
return obj;
}
static void
_constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
{
eo_do_super(obj, MY_CLASS, eo_constructor());
eo_do(obj,
evas_obj_type_set(MY_CLASS_NAME));
elm_widget_sub_object_add(eo_parent_get(obj), obj);
}
static void
_destructor(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
{
Elm_Mapbuf_Smart_Data *priv = _pd;
if (priv->idler) ecore_idler_del(priv->idler);
priv->idler = NULL;
eo_do_super(obj, MY_CLASS, eo_destructor());
}
EAPI void
elm_mapbuf_enabled_set(Evas_Object *obj,
Eina_Bool enabled)
{
ELM_MAPBUF_CHECK(obj);
eo_do(obj, elm_obj_mapbuf_enabled_set(enabled));
}
static void
_internal_enable_set(Eo *obj, Elm_Mapbuf_Smart_Data *sd, Eina_Bool enabled)
{
if (sd->enabled == enabled) return;
sd->enabled = enabled;
_elm_mapbuf_inside_view_reset(obj);
if (sd->content) evas_object_static_clip_set(sd->content, sd->enabled);
_configure(obj, EINA_TRUE);
}
static void
_enabled_set(Eo *obj, void *_pd, va_list *list)
{
Eina_Bool enabled = va_arg(*list, int);
Elm_Mapbuf_Smart_Data *sd = _pd;
_internal_enable_set(obj, sd, enabled);
}
EAPI Eina_Bool
elm_mapbuf_enabled_get(const Evas_Object *obj)
{
ELM_MAPBUF_CHECK(obj) EINA_FALSE;
Eina_Bool ret = EINA_FALSE;
eo_do((Eo *) obj, elm_obj_mapbuf_enabled_get(&ret));
return ret;
}
static void
_enabled_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
Elm_Mapbuf_Smart_Data *sd = _pd;
*ret = sd->enabled;
}
EAPI void
elm_mapbuf_smooth_set(Evas_Object *obj,
Eina_Bool smooth)
{
ELM_MAPBUF_CHECK(obj);
eo_do(obj, elm_obj_mapbuf_smooth_set(smooth));
}
static void
_smooth_set(Eo *obj, void *_pd, va_list *list)
{
Eina_Bool smooth = va_arg(*list, int);
Elm_Mapbuf_Smart_Data *sd = _pd;
if (sd->smooth == smooth) return;
sd->smooth = smooth;
sd->smooth_saved = smooth;
_configure(obj, EINA_TRUE);
}
EAPI Eina_Bool
elm_mapbuf_smooth_get(const Evas_Object *obj)
{
ELM_MAPBUF_CHECK(obj) EINA_FALSE;
Eina_Bool ret = EINA_FALSE;
eo_do((Eo *) obj, elm_obj_mapbuf_smooth_get(&ret));
return ret;
}
static void
_smooth_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
Elm_Mapbuf_Smart_Data *sd = _pd;
*ret = sd->smooth;
}
EAPI void
elm_mapbuf_alpha_set(Evas_Object *obj,
Eina_Bool alpha)
{
ELM_MAPBUF_CHECK(obj);
eo_do(obj, elm_obj_mapbuf_alpha_set(alpha));
}
static void
_alpha_set(Eo *obj, void *_pd, va_list *list)
{
Eina_Bool alpha = va_arg(*list, int);
Elm_Mapbuf_Smart_Data *sd = _pd;
if (sd->alpha == alpha) return;
sd->alpha = alpha;
_configure(obj, EINA_TRUE);
}
EAPI Eina_Bool
elm_mapbuf_alpha_get(const Evas_Object *obj)
{
ELM_MAPBUF_CHECK(obj) EINA_FALSE;
Eina_Bool ret = EINA_FALSE;
eo_do((Eo *) obj, elm_obj_mapbuf_alpha_get(&ret));
return ret;
}
static void
_alpha_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
Elm_Mapbuf_Smart_Data *sd = _pd;
*ret = sd->alpha;
}
EAPI void
elm_mapbuf_auto_set(Evas_Object *obj,
Eina_Bool on)
{
ELM_MAPBUF_CHECK(obj);
eo_do(obj, elm_obj_mapbuf_auto_set(on));
}
static void
_auto_set(Eo *obj, void *_pd, va_list *list)
{
Eina_Bool on = va_arg(*list, int);
Elm_Mapbuf_Smart_Data *sd = _pd;
if (sd->automode == on) return;
sd->automode = on;
if (on)
{
_mapbuf_auto_eval(obj, sd);
}
else
{
ELM_SAFE_FREE(sd->idler, ecore_idler_del);
_internal_enable_set(obj, _pd, EINA_FALSE);
}
_configure(obj, EINA_TRUE);
}
EAPI Eina_Bool
elm_mapbuf_auto_get(const Evas_Object *obj)
{
ELM_MAPBUF_CHECK(obj) EINA_FALSE;
Eina_Bool ret = EINA_FALSE;
eo_do((Eo *) obj, elm_obj_mapbuf_auto_get(&ret));
return ret;
}
static void
_auto_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
{
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
Elm_Mapbuf_Smart_Data *sd = _pd;
*ret = sd->automode;
}
static void
_class_constructor(Eo_Class *klass)
{
const Eo_Op_Func_Description func_desc[] = {
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_ADD), _elm_mapbuf_smart_add),
EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_RESIZE), _elm_mapbuf_smart_resize),
EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_MOVE), _elm_mapbuf_smart_move),
EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_SHOW), _elm_mapbuf_smart_show),
EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_HIDE), _elm_mapbuf_smart_hide),
EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_THEME), _elm_mapbuf_smart_theme),
EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_SUB_OBJECT_DEL), _elm_mapbuf_smart_sub_object_del),
EO_OP_FUNC(ELM_OBJ_CONTAINER_ID(ELM_OBJ_CONTAINER_SUB_ID_CONTENT_SET), _elm_mapbuf_smart_content_set),
EO_OP_FUNC(ELM_OBJ_CONTAINER_ID(ELM_OBJ_CONTAINER_SUB_ID_CONTENT_GET), _elm_mapbuf_smart_content_get),
EO_OP_FUNC(ELM_OBJ_CONTAINER_ID(ELM_OBJ_CONTAINER_SUB_ID_CONTENT_UNSET), _elm_mapbuf_smart_content_unset),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_ENABLED_SET), _enabled_set),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_ENABLED_GET), _enabled_get),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_SMOOTH_SET), _smooth_set),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_SMOOTH_GET), _smooth_get),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_ALPHA_SET), _alpha_set),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_ALPHA_GET), _alpha_get),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_AUTO_SET), _auto_set),
EO_OP_FUNC(ELM_OBJ_MAPBUF_ID(ELM_OBJ_MAPBUF_SUB_ID_AUTO_GET), _auto_get),
EO_OP_FUNC_SENTINEL
};
eo_class_funcs_set(klass, func_desc);
evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
}
static const Eo_Op_Description op_desc[] = {
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_ENABLED_SET, "Enable or disable the map."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_ENABLED_GET, "Get a value whether map is enabled or not."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_SMOOTH_SET, "Enable or disable smooth map rendering."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_SMOOTH_GET, "Get a value whether smooth map rendering is enabled or not."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_ALPHA_SET, "Set or unset alpha flag for map rendering."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_ALPHA_GET, "Get a value whether alpha blending is enabled or not."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_AUTO_SET, "Turn map on or off automatically based on object visibility."),
EO_OP_DESCRIPTION(ELM_OBJ_MAPBUF_SUB_ID_AUTO_GET, "Get automatic mode state."),
EO_OP_DESCRIPTION_SENTINEL
};
static const Eo_Class_Description class_desc = {
EO_VERSION,
MY_CLASS_NAME,
EO_CLASS_TYPE_REGULAR,
EO_CLASS_DESCRIPTION_OPS(&ELM_OBJ_MAPBUF_BASE_ID, op_desc, ELM_OBJ_MAPBUF_SUB_ID_LAST),
NULL,
sizeof(Elm_Mapbuf_Smart_Data),
_class_constructor,
NULL
};
EO_DEFINE_CLASS(elm_obj_mapbuf_class_get, &class_desc, ELM_OBJ_CONTAINER_CLASS, NULL);