1 #include "evas_common.h"
2 #include "evas_private.h"
4 /* private magic number for polygon objects */
5 static const char o_type[] = "polygon";
7 /* private struct for line object internal data */
8 typedef struct _Evas_Object_Polygon Evas_Object_Polygon;
9 typedef struct _Evas_Polygon_Point Evas_Polygon_Point;
11 struct _Evas_Object_Polygon
19 Evas_Coord_Rectangle geometry;
23 struct _Evas_Polygon_Point
28 /* private methods for polygon objects */
29 static void evas_object_polygon_init(Evas_Object *obj);
30 static void *evas_object_polygon_new(void);
31 static void evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
32 static void evas_object_polygon_free(Evas_Object *obj);
33 static void evas_object_polygon_render_pre(Evas_Object *obj);
34 static void evas_object_polygon_render_post(Evas_Object *obj);
36 static unsigned int evas_object_polygon_id_get(Evas_Object *obj);
37 static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj);
38 static void *evas_object_polygon_engine_data_get(Evas_Object *obj);
40 static int evas_object_polygon_is_opaque(Evas_Object *obj);
41 static int evas_object_polygon_was_opaque(Evas_Object *obj);
42 static int evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
43 static int evas_object_polygon_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
45 static const Evas_Object_Func object_func =
47 /* methods (compulsory) */
48 evas_object_polygon_free,
49 evas_object_polygon_render,
50 evas_object_polygon_render_pre,
51 evas_object_polygon_render_post,
52 evas_object_polygon_id_get,
53 evas_object_polygon_visual_id_get,
54 evas_object_polygon_engine_data_get,
55 /* these are optional. NULL = nothing */
60 evas_object_polygon_is_opaque,
61 evas_object_polygon_was_opaque,
62 evas_object_polygon_is_inside,
63 evas_object_polygon_was_inside,
71 /* the actual api call to add a rect */
72 /* it has no other api calls as all properties are standard */
74 EVAS_MEMPOOL(_mp_obj);
77 evas_object_polygon_add(Evas *e)
81 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
84 obj = evas_object_new(e);
85 evas_object_polygon_init(obj);
86 evas_object_inject(obj, e);
91 evas_object_polygon_point_add(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
93 Evas_Object_Polygon *o;
94 Evas_Polygon_Point *p;
95 Evas_Coord min_x, max_x, min_y, max_y;
98 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
101 o = (Evas_Object_Polygon *)(obj->object_data);
102 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
106 if (obj->layer->evas->events_frozen <= 0)
108 if (!evas_event_passes_through(obj) &&
109 !evas_event_freezes_through(obj))
110 was = evas_object_is_in_output_rect(obj,
111 obj->layer->evas->pointer.x,
112 obj->layer->evas->pointer.y,
117 o->offset.x = obj->cur.geometry.x;
118 o->offset.y = obj->cur.geometry.y;
122 /* Update all points and take offset into account. */
125 EINA_LIST_FOREACH(o->points, over, p)
132 p = malloc(sizeof(Evas_Polygon_Point));
134 p->x = x + o->offset.x;
135 p->y = y + o->offset.y;
139 obj->cur.geometry.x = p->x;
140 obj->cur.geometry.y = p->y;
141 obj->cur.geometry.w = 2;
142 obj->cur.geometry.h = 2;
146 if (p->x < obj->cur.geometry.x) min_x = p->x;
147 else min_x = obj->cur.geometry.x;
148 if (p->x > (obj->cur.geometry.x + obj->cur.geometry.w - 2))
150 else max_x = obj->cur.geometry.x + obj->cur.geometry.w - 2;
151 if (p->y < obj->cur.geometry.y) min_y = p->y;
152 else min_y = obj->cur.geometry.y;
153 if (p->y > (obj->cur.geometry.y + obj->cur.geometry.h - 2))
155 else max_y = obj->cur.geometry.y + obj->cur.geometry.h - 2;
156 obj->cur.geometry.x = min_x;
157 obj->cur.geometry.y = min_y;
158 obj->cur.geometry.w = max_x - min_x + 2;
159 obj->cur.geometry.h = max_y - min_y + 2;
161 o->points = eina_list_append(o->points, p);
163 o->geometry = obj->cur.geometry;
167 //// obj->cur.cache.geometry.validity = 0;
168 o->changed = EINA_TRUE;
169 evas_object_change(obj);
170 evas_object_clip_dirty(obj);
171 evas_object_coords_recalc(obj);
172 if (obj->layer->evas->events_frozen <= 0)
174 is = evas_object_is_in_output_rect(obj,
175 obj->layer->evas->pointer.x,
176 obj->layer->evas->pointer.y, 1, 1);
177 if (!evas_event_passes_through(obj) &&
178 !evas_event_freezes_through(obj) )
180 if ((is ^ was) && obj->cur.visible)
181 evas_event_feed_mouse_move(obj->layer->evas,
182 obj->layer->evas->pointer.x,
183 obj->layer->evas->pointer.y,
184 obj->layer->evas->last_timestamp,
188 evas_object_inform_call_move(obj);
189 evas_object_inform_call_resize(obj);
193 evas_object_polygon_points_clear(Evas_Object *obj)
195 Evas_Object_Polygon *o;
198 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
201 o = (Evas_Object_Polygon *)(obj->object_data);
202 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
205 was = evas_object_is_in_output_rect(obj,
206 obj->layer->evas->pointer.x,
207 obj->layer->evas->pointer.y, 1, 1);
210 free(o->points->data);
211 o->points = eina_list_remove(o->points, o->points->data);
213 obj->cur.geometry.x = 0;
214 obj->cur.geometry.y = 0;
215 obj->cur.geometry.w = 0;
216 obj->cur.geometry.h = 0;
217 //// obj->cur.cache.geometry.validity = 0;
218 o->changed = EINA_TRUE;
219 evas_object_change(obj);
220 evas_object_clip_dirty(obj);
221 evas_object_coords_recalc(obj);
222 is = evas_object_is_in_output_rect(obj,
223 obj->layer->evas->pointer.x,
224 obj->layer->evas->pointer.y, 1, 1);
225 if ((is || was) && obj->cur.visible)
226 evas_event_feed_mouse_move(obj->layer->evas,
227 obj->layer->evas->pointer.x,
228 obj->layer->evas->pointer.y,
229 obj->layer->evas->last_timestamp,
231 evas_object_inform_call_move(obj);
232 evas_object_inform_call_resize(obj);
235 /* all nice and private */
237 evas_object_polygon_init(Evas_Object *obj)
239 /* alloc image ob, setup methods and default values */
240 obj->object_data = evas_object_polygon_new();
241 /* set up default settings for this kind of object */
242 obj->cur.color.r = 255;
243 obj->cur.color.g = 255;
244 obj->cur.color.b = 255;
245 obj->cur.color.a = 255;
246 obj->cur.geometry.x = 0;
247 obj->cur.geometry.y = 0;
248 obj->cur.geometry.w = 0;
249 obj->cur.geometry.h = 0;
251 /* set up object-specific settings */
252 obj->prev = obj->cur;
253 /* set up methods (compulsory) */
254 obj->func = &object_func;
259 evas_object_polygon_new(void)
261 Evas_Object_Polygon *o;
263 /* alloc obj private data */
264 EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_polygon", Evas_Object_Polygon, 32, NULL);
265 o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Polygon);
267 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Polygon);
268 o->magic = MAGIC_OBJ_POLYGON;
273 evas_object_polygon_free(Evas_Object *obj)
275 Evas_Object_Polygon *o;
277 /* frees private object data. very simple here */
278 o = (Evas_Object_Polygon *)(obj->object_data);
279 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
285 free(o->points->data);
286 o->points = eina_list_remove(o->points, o->points->data);
288 o->engine_data = obj->layer->evas->engine.func->polygon_points_clear(obj->layer->evas->engine.data.output,
289 obj->layer->evas->engine.data.context,
292 EVAS_MEMPOOL_FREE(_mp_obj, o);
296 evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
298 Evas_Object_Polygon *o;
300 Evas_Polygon_Point *p;
302 /* render object to surface with context, and offxet by x,y */
303 o = (Evas_Object_Polygon *)(obj->object_data);
304 obj->layer->evas->engine.func->context_color_set(output,
306 obj->cur.cache.clip.r,
307 obj->cur.cache.clip.g,
308 obj->cur.cache.clip.b,
309 obj->cur.cache.clip.a);
310 obj->layer->evas->engine.func->context_multiplier_unset(output,
312 obj->layer->evas->engine.func->context_render_op_set(output, context,
316 o->engine_data = obj->layer->evas->engine.func->polygon_points_clear(obj->layer->evas->engine.data.output,
317 obj->layer->evas->engine.data.context,
319 EINA_LIST_FOREACH(o->points, l, p)
321 //px = evas_coord_world_x_to_screen(obj->layer->evas, p->x);
322 //py = evas_coord_world_y_to_screen(obj->layer->evas, p->y);
323 o->engine_data = obj->layer->evas->engine.func->polygon_point_add(obj->layer->evas->engine.data.output,
324 obj->layer->evas->engine.data.context,
331 obj->layer->evas->engine.func->polygon_draw(output,
335 o->offset.x + x, o->offset.y + y);
339 evas_object_polygon_render_pre(Evas_Object *obj)
341 Evas_Object_Polygon *o;
344 /* dont pre-render the obj twice! */
345 if (obj->pre_render_done) return;
346 obj->pre_render_done = 1;
347 /* pre-render phase. this does anything an object needs to do just before */
348 /* rendering. this could mean loading the image data, retrieving it from */
349 /* elsewhere, decoding video etc. */
350 /* then when this is done the object needs to figure if it changed and */
351 /* if so what and where and add the appropriate redraw lines */
352 o = (Evas_Object_Polygon *)(obj->object_data);
353 /* if someone is clipping this obj - go calculate the clipper */
354 if (obj->cur.clipper)
356 if (obj->cur.cache.clip.dirty)
357 evas_object_clip_recalc(obj->cur.clipper);
358 obj->cur.clipper->func->render_pre(obj->cur.clipper);
360 /* now figure what changed and add draw rects */
361 /* if it just became visible or invisible */
362 is_v = evas_object_is_visible(obj);
363 was_v = evas_object_was_visible(obj);
366 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
369 if (obj->changed_map)
371 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes,
375 /* it's not visible - we accounted for it appearing or not so just abort */
376 if (!is_v) goto done;
377 /* clipper changed this is in addition to anything else for obj */
378 evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
379 /* if we restacked (layer or just within a layer) */
382 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
385 /* if it changed render op */
386 if (obj->cur.render_op != obj->prev.render_op)
388 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
391 /* if it changed color */
392 if ((obj->cur.color.r != obj->prev.color.r) ||
393 (obj->cur.color.g != obj->prev.color.g) ||
394 (obj->cur.color.b != obj->prev.color.b) ||
395 (obj->cur.color.a != obj->prev.color.a))
397 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
400 /* if it changed geometry - and obviously not visibility or color */
401 /* calculate differences since we have a constant color fill */
402 /* we really only need to update the differences */
403 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
404 (obj->cur.geometry.y != obj->prev.geometry.y) ||
405 (obj->cur.geometry.w != obj->prev.geometry.w) ||
406 (obj->cur.geometry.h != obj->prev.geometry.h) ||
409 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
413 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
414 (obj->cur.geometry.y != obj->prev.geometry.y))
418 o->offset.x += obj->cur.geometry.x - obj->prev.geometry.x;
419 o->offset.y += obj->cur.geometry.y - obj->prev.geometry.y;
423 o->offset.x += obj->cur.geometry.x - o->geometry.x;
424 o->offset.y += obj->cur.geometry.y - o->geometry.y;
427 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
431 evas_object_polygon_render_post(Evas_Object *obj)
433 Evas_Object_Polygon *o;
435 /* this moves the current data to the previous state parts of the object */
436 /* in whatever way is safest for the object. also if we don't need object */
437 /* data anymore we can free it if the object deems this is a good idea */
438 o = (Evas_Object_Polygon *)(obj->object_data);
439 /* remove those pesky changes */
440 evas_object_clip_changes_clean(obj);
441 /* move cur to prev safely for object data */
442 obj->prev = obj->cur;
446 static unsigned int evas_object_polygon_id_get(Evas_Object *obj)
448 Evas_Object_Polygon *o;
450 o = (Evas_Object_Polygon *)(obj->object_data);
452 return MAGIC_OBJ_POLYGON;
455 static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj)
457 Evas_Object_Polygon *o;
459 o = (Evas_Object_Polygon *)(obj->object_data);
461 return MAGIC_OBJ_SHAPE;
464 static void *evas_object_polygon_engine_data_get(Evas_Object *obj)
466 Evas_Object_Polygon *o;
468 o = (Evas_Object_Polygon *)(obj->object_data);
470 return o->engine_data;
474 evas_object_polygon_is_opaque(Evas_Object *obj __UNUSED__)
476 /* this returns 1 if the internal object data implies that the object is */
477 /* currently fully opaque over the entire line it occupies */
482 evas_object_polygon_was_opaque(Evas_Object *obj __UNUSED__)
484 /* this returns 1 if the internal object data implies that the object was */
485 /* previously fully opaque over the entire line it occupies */
489 /* We count the number of edges a "ray" 90 degs upwards from our point
490 * intersects with. If it's even, we are outside of the polygon, if it's odd,
491 * we are inside of it. */
493 evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
495 Evas_Object_Polygon *o;
496 int num_edges = 0; /* Number of edges we crossed */
498 Evas_Polygon_Point *p;
500 o = (Evas_Object_Polygon *)(obj->object_data);
502 if (!o->points) return 0;
504 /* Adjust X and Y according to current geometry */
508 if (eina_list_count(o->points) == 1)
510 p = eina_list_data_get(o->points);
511 return ((p->x == x) && (p->y == y));
514 EINA_LIST_FOREACH(o->points, itr, p)
517 Eina_List *next = eina_list_next(itr);
518 Evas_Polygon_Point *p_next;
519 /* Get the next, or if there's no next, take the first */
522 p_next = eina_list_data_get(next);
526 p_next = eina_list_data_get(o->points);
529 /* Make sure that we are directly below the edge,
530 * and that p->x != p_next->x */
531 if (((p->x < p_next->x) && (p->x <= x) && (x < p_next->x)) ||
532 ((p->x > p_next->x) && (p_next->x < x) && (x <= p->x)))
534 line_y = ((double) (p->y - p_next->y) /
535 (double) (p->x - p_next->x)) *
536 (x - p_next->x) + p_next->y;
537 /* We crossed that edge if the line is directly above us */
543 /* Return true if num_edges is odd */
544 return ((num_edges % 2) == 1);
548 evas_object_polygon_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
550 /* this returns 1 if the canvas co-ordinates were inside the object based */
551 /* on object private data. not much use for rects, but for polys, images */
552 /* and other complex objects it might be */