Add function to check if point is inside an object

Add evas_object_inside_get() to check if a certain (x,y) point is inside
an evas_object. This is needed because there's no simple way to
determine it outside of evas when map transformations are used.

For instance, edje uses evas_object_geometry_get() and checks if point is
whithin the rectangle. This is wrong because the object might be
rotated, scaled. Below is a test program:

/**
 * Simple Evas test
 *
 * Compile with: gcc -O0 -g  -o evas_hello_world evas_hello_world.c $(pkg-config --cflags --libs eina evas ecore ecore-evas)
 */
 #include <Eina.h>
 #include <Evas.h>
 #include <Ecore_Evas.h>
 #include <Ecore.h>
 #include <stdio.h>

 #define WIDTH (320)
 #define HEIGHT (240)

Eina_Bool main_signal_exit(void *data, int ev_type, void *ev)
{
    ecore_main_loop_quit();
    return EINA_FALSE;
}

static void
_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
    Evas_Event_Mouse_Up *ev = event_info;
    Eina_Bool b;

    b = evas_object_inside_get(obj, ev->canvas.x, ev->canvas.y);
    fprintf(stderr, "mouse_up: x=%d, y=%d inside=%d\n", ev->canvas.x,
            ev->canvas.y, b);
}

static void
_cb_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
    Evas_Event_Mouse_Move *ev = event_info;
    const char *id = data;
    Eina_Bool b;

    b = evas_object_inside_get(obj, ev->cur.canvas.x, ev->cur.canvas.y);
    fprintf(stderr, "[%s] mouse_move: x=%d, y=%d inside=%d\n", id,
            ev->cur.canvas.x, ev->cur.canvas.y, b);
}

int main(void)
{
   Evas *evas;
   Ecore_Evas *window;
   Evas_Object *bg, *r1, *r2;
   Evas_Map *m;

   evas_init();
   ecore_init();
   ecore_evas_init();

   window = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL);
   if (!evas)
     return -1;

   evas = ecore_evas_get(window);

   bg = evas_object_rectangle_add(evas);
   evas_object_color_set(bg, 255, 255, 255, 255); // white bg
   evas_object_move(bg, 0, 0);                    // at origin
   evas_object_resize(bg, WIDTH, HEIGHT);         // covers full evas
   evas_object_show(bg);

   r1 = evas_object_rectangle_add(evas);
   evas_object_color_set(r1, 255, 0, 0, 255); // 100% opaque red
   evas_object_move(r1, 50, 50);
   evas_object_resize(r1, 100, 100);

   m = evas_map_new(4);
   evas_map_util_points_populate_from_object(m, r1);
   evas_map_util_rotate(m, 45.0, 100, 100);
   evas_map_alpha_set(m, 0);
   evas_map_smooth_set(m, 1);

   evas_object_map_set(r1, m);
   evas_object_map_enable_set(r1, 1);
   evas_map_free(m);
   evas_object_show(r1);
   evas_object_event_callback_add(r1, EVAS_CALLBACK_MOUSE_UP, _cb, NULL);
   evas_object_event_callback_add(r1, EVAS_CALLBACK_MOUSE_MOVE, _cb_move, "r1");

   r2 = evas_object_rectangle_add(evas);
   evas_object_color_set(r2, 0, 255, 0, 255);
   evas_object_move(r2, 210, 150);
   evas_object_resize(r2, 50, 50);
   evas_object_show(r2);
   evas_object_event_callback_add(r2, EVAS_CALLBACK_MOUSE_MOVE, _cb_move, "r2");

   ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, evas);

   ecore_evas_show(window);
   ecore_main_loop_begin();

   ecore_evas_free(window);

   ecore_evas_shutdown();
   ecore_shutdown();
   evas_shutdown();

   return 0;
}




SVN revision: 52345
This commit is contained in:
Lucas De Marchi 2010-09-16 13:59:46 +00:00
parent 12b55be8af
commit 251a60ab09
2 changed files with 41 additions and 0 deletions

View File

@ -875,6 +875,7 @@ typedef void (*Evas_Async_Events_Put_Cb)(void *target, Evas_Callback_Type t
EAPI void evas_object_move (Evas_Object *obj, Evas_Coord x, Evas_Coord y) EINA_ARG_NONNULL(1);
EAPI void evas_object_resize (Evas_Object *obj, Evas_Coord w, Evas_Coord h) EINA_ARG_NONNULL(1);
EAPI void evas_object_geometry_get (const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) EINA_ARG_NONNULL(1);
EAPI Eina_Bool evas_object_inside_get (const Evas_Object *obj, Evas_Coord x, Evas_Coord y) EINA_ARG_NONNULL(1);
EAPI void evas_object_show (Evas_Object *obj) EINA_ARG_NONNULL(1);
EAPI void evas_object_hide (Evas_Object *obj) EINA_ARG_NONNULL(1);

View File

@ -620,6 +620,46 @@ evas_object_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, E
if (h) *h = obj->cur.geometry.h;
}
/* If an evas object does not use any transformation it's much easier to know
* if a point is within its bounds. This internal function is used by
* evas_object_inside_get() that makes the proper checks to see if the given
* evas object can use this version or a more elaborated one is needed.
*/
static inline Eina_Bool
_evas_object_unmapped_inside_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
return ((x >= obj->cur.geometry.x) && (y >= obj->cur.geometry.y) &&
(x < (obj->cur.geometry.x + obj->cur.geometry.w)) &&
(y < (obj->cur.geometry.y + obj->cur.geometry.h)));
}
/**
* Check if a certain point is inside of a rectangular evas object.
*
* This function takes into account if the given evas object suffered any
* transformation by means of evas_map_* functions.
*
* @param obj The given evas object.
* @param x X coordinate of the point to check for.
* @param y Y coordinate of the point to check for.
* @ngroup Evas_Object_Group_Basic
*/
EAPI Eina_Bool
evas_object_inside_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
return EINA_FALSE;
MAGIC_CHECK_END();
if (obj->delete_me)
return EINA_FALSE;
if ((obj->cur.map) && (obj->cur.map->count == 4) && (obj->cur.usemap))
return evas_map_inside_get(obj->cur.map, x, y);
return _evas_object_unmapped_inside_get(obj, x, y);
}
/**
* @addtogroup Evas_Object_Group_Size_Hints
* @{