aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/canvas/evas_object_polygon.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/lib/canvas/evas_object_polygon.c')
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_polygon.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_object_polygon.c b/libraries/evas/src/lib/canvas/evas_object_polygon.c
new file mode 100644
index 0000000..cbc1802
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_polygon.c
@@ -0,0 +1,554 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4/* private magic number for polygon objects */
5static const char o_type[] = "polygon";
6
7/* private struct for line object internal data */
8typedef struct _Evas_Object_Polygon Evas_Object_Polygon;
9typedef struct _Evas_Polygon_Point Evas_Polygon_Point;
10
11struct _Evas_Object_Polygon
12{
13 DATA32 magic;
14 Eina_List *points;
15 void *engine_data;
16 struct {
17 int x, y;
18 } offset;
19 Evas_Coord_Rectangle geometry;
20 char changed : 1;
21};
22
23struct _Evas_Polygon_Point
24{
25 Evas_Coord x, y;
26};
27
28/* private methods for polygon objects */
29static void evas_object_polygon_init(Evas_Object *obj);
30static void *evas_object_polygon_new(void);
31static void evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
32static void evas_object_polygon_free(Evas_Object *obj);
33static void evas_object_polygon_render_pre(Evas_Object *obj);
34static void evas_object_polygon_render_post(Evas_Object *obj);
35
36static unsigned int evas_object_polygon_id_get(Evas_Object *obj);
37static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj);
38static void *evas_object_polygon_engine_data_get(Evas_Object *obj);
39
40static int evas_object_polygon_is_opaque(Evas_Object *obj);
41static int evas_object_polygon_was_opaque(Evas_Object *obj);
42static int evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
43static int evas_object_polygon_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
44
45static const Evas_Object_Func object_func =
46{
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 */
56 NULL,
57 NULL,
58 NULL,
59 NULL,
60 evas_object_polygon_is_opaque,
61 evas_object_polygon_was_opaque,
62 evas_object_polygon_is_inside,
63 evas_object_polygon_was_inside,
64 NULL,
65 NULL,
66 NULL,
67 NULL,
68 NULL
69};
70
71/* the actual api call to add a rect */
72/* it has no other api calls as all properties are standard */
73
74EVAS_MEMPOOL(_mp_obj);
75
76EAPI Evas_Object *
77evas_object_polygon_add(Evas *e)
78{
79 Evas_Object *obj;
80
81 MAGIC_CHECK(e, Evas, MAGIC_EVAS);
82 return NULL;
83 MAGIC_CHECK_END();
84 obj = evas_object_new(e);
85 evas_object_polygon_init(obj);
86 evas_object_inject(obj, e);
87 return obj;
88}
89
90EAPI void
91evas_object_polygon_point_add(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
92{
93 Evas_Object_Polygon *o;
94 Evas_Polygon_Point *p;
95 Evas_Coord min_x, max_x, min_y, max_y;
96 int is, was = 0;
97
98 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
99 return;
100 MAGIC_CHECK_END();
101 o = (Evas_Object_Polygon *)(obj->object_data);
102 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
103 return;
104 MAGIC_CHECK_END();
105
106 if (obj->layer->evas->events_frozen <= 0)
107 {
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,
113 1, 1);
114 }
115 if (!o->points)
116 {
117 o->offset.x = obj->cur.geometry.x;
118 o->offset.y = obj->cur.geometry.y;
119 }
120 else
121 {
122 /* Update all points and take offset into account. */
123 Eina_List *over;
124
125 EINA_LIST_FOREACH(o->points, over, p)
126 {
127 p->x += o->offset.x;
128 p->y += o->offset.y;
129 }
130 }
131
132 p = malloc(sizeof(Evas_Polygon_Point));
133 if (!p) return;
134 p->x = x + o->offset.x;
135 p->y = y + o->offset.y;
136
137 if (!o->points)
138 {
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;
143 }
144 else
145 {
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))
149 max_x = p->x;
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))
154 max_y = p->y;
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;
160 }
161 o->points = eina_list_append(o->points, p);
162
163 o->geometry = obj->cur.geometry;
164 o->offset.x = 0;
165 o->offset.y = 0;
166
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)
173 {
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) )
179 {
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,
185 NULL);
186 }
187 }
188 evas_object_inform_call_move(obj);
189 evas_object_inform_call_resize(obj);
190}
191
192EAPI void
193evas_object_polygon_points_clear(Evas_Object *obj)
194{
195 Evas_Object_Polygon *o;
196 int is, was;
197
198 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
199 return;
200 MAGIC_CHECK_END();
201 o = (Evas_Object_Polygon *)(obj->object_data);
202 MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON);
203 return;
204 MAGIC_CHECK_END();
205 was = evas_object_is_in_output_rect(obj,
206 obj->layer->evas->pointer.x,
207 obj->layer->evas->pointer.y, 1, 1);
208 while (o->points)
209 {
210 free(o->points->data);
211 o->points = eina_list_remove(o->points, o->points->data);
212 }
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,
230 NULL);
231 evas_object_inform_call_move(obj);
232 evas_object_inform_call_resize(obj);
233}
234
235/* all nice and private */
236static void
237evas_object_polygon_init(Evas_Object *obj)
238{
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;
250 obj->cur.layer = 0;
251 /* set up object-specific settings */
252 obj->prev = obj->cur;
253 /* set up methods (compulsory) */
254 obj->func = &object_func;
255 obj->type = o_type;
256}
257
258static void *
259evas_object_polygon_new(void)
260{
261 Evas_Object_Polygon *o;
262
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);
266 if (!o) return NULL;
267 EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Polygon);
268 o->magic = MAGIC_OBJ_POLYGON;
269 return o;
270}
271
272static void
273evas_object_polygon_free(Evas_Object *obj)
274{
275 Evas_Object_Polygon *o;
276
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);
280 return;
281 MAGIC_CHECK_END();
282 /* free obj */
283 while (o->points)
284 {
285 free(o->points->data);
286 o->points = eina_list_remove(o->points, o->points->data);
287 }
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,
290 o->engine_data);
291 o->magic = 0;
292 EVAS_MEMPOOL_FREE(_mp_obj, o);
293}
294
295static void
296evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
297{
298 Evas_Object_Polygon *o;
299 Eina_List *l;
300 Evas_Polygon_Point *p;
301
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,
305 context,
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,
311 context);
312 obj->layer->evas->engine.func->context_render_op_set(output, context,
313 obj->cur.render_op);
314 if (o->changed)
315 {
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,
318 o->engine_data);
319 EINA_LIST_FOREACH(o->points, l, p)
320 {
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,
325 o->engine_data,
326 p->x, p->y);
327 }
328 }
329
330 if (o->engine_data)
331 obj->layer->evas->engine.func->polygon_draw(output,
332 context,
333 surface,
334 o->engine_data,
335 o->offset.x + x, o->offset.y + y);
336}
337
338static void
339evas_object_polygon_render_pre(Evas_Object *obj)
340{
341 Evas_Object_Polygon *o;
342 int is_v, was_v;
343
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)
355 {
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);
359 }
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);
364 if (is_v != was_v)
365 {
366 evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
367 goto done;
368 }
369 if ((obj->cur.map != obj->prev.map) ||
370 (obj->cur.usemap != obj->prev.usemap))
371 {
372 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
373 goto done;
374 }
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) */
380 if (obj->restack)
381 {
382 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
383 goto done;
384 }
385 /* if it changed render op */
386 if (obj->cur.render_op != obj->prev.render_op)
387 {
388 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
389 goto done;
390 }
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))
396 {
397 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
398 goto done;
399 }
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) ||
407 (o->changed))
408 {
409 evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
410 goto done;
411 }
412 done:
413 if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
414 (obj->cur.geometry.y != obj->prev.geometry.y))
415 {
416 if (!o->changed)
417 {
418 o->offset.x += obj->cur.geometry.x - obj->prev.geometry.x;
419 o->offset.y += obj->cur.geometry.y - obj->prev.geometry.y;
420 }
421 else
422 {
423 o->offset.x += obj->cur.geometry.x - o->geometry.x;
424 o->offset.y += obj->cur.geometry.y - o->geometry.y;
425 }
426 }
427 evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
428}
429
430static void
431evas_object_polygon_render_post(Evas_Object *obj)
432{
433 Evas_Object_Polygon *o;
434
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;
443 o->changed = 0;
444}
445
446static unsigned int evas_object_polygon_id_get(Evas_Object *obj)
447{
448 Evas_Object_Polygon *o;
449
450 o = (Evas_Object_Polygon *)(obj->object_data);
451 if (!o) return 0;
452 return MAGIC_OBJ_POLYGON;
453}
454
455static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj)
456{
457 Evas_Object_Polygon *o;
458
459 o = (Evas_Object_Polygon *)(obj->object_data);
460 if (!o) return 0;
461 return MAGIC_OBJ_SHAPE;
462}
463
464static void *evas_object_polygon_engine_data_get(Evas_Object *obj)
465{
466 Evas_Object_Polygon *o;
467
468 o = (Evas_Object_Polygon *)(obj->object_data);
469 if (!o) return NULL;
470 return o->engine_data;
471}
472
473static int
474evas_object_polygon_is_opaque(Evas_Object *obj __UNUSED__)
475{
476 /* this returns 1 if the internal object data implies that the object is */
477 /* currently fully opaque over the entire line it occupies */
478 return 0;
479}
480
481static int
482evas_object_polygon_was_opaque(Evas_Object *obj __UNUSED__)
483{
484 /* this returns 1 if the internal object data implies that the object was */
485 /* previously fully opaque over the entire line it occupies */
486 return 0;
487}
488
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. */
492static int
493evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
494{
495 Evas_Object_Polygon *o;
496 int num_edges = 0; /* Number of edges we crossed */
497 Eina_List *itr;
498 Evas_Polygon_Point *p;
499
500 o = (Evas_Object_Polygon *)(obj->object_data);
501 if (!o) return 0;
502 if (!o->points) return 0;
503
504 /* Adjust X and Y according to current geometry */
505 x -= o->offset.x;
506 y -= o->offset.y;
507
508 if (eina_list_count(o->points) == 1)
509 {
510 p = eina_list_data_get(o->points);
511 return ((p->x == x) && (p->y == y));
512 }
513
514 EINA_LIST_FOREACH(o->points, itr, p)
515 {
516 Evas_Coord line_y;
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 */
520 if (next)
521 {
522 p_next = eina_list_data_get(next);
523 }
524 else
525 {
526 p_next = eina_list_data_get(o->points);
527 }
528
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)))
533 {
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 */
538 if (line_y < y)
539 num_edges++;
540 }
541 }
542
543 /* Return true if num_edges is odd */
544 return ((num_edges % 2) == 1);
545}
546
547static int
548evas_object_polygon_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
549{
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 */
553 return 1;
554}