0baab9e0ec927177f8a40bc8f62849676b7aeea0
[framework/uifw/evas.git] / src / lib / canvas / evas_object_line.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 /* private magic number for line objects */
5 static const char o_type[] = "line";
6
7 /* private struct for line object internal data */
8 typedef struct _Evas_Object_Line      Evas_Object_Line;
9
10 struct _Evas_Object_Line
11 {
12    DATA32            magic;
13    struct {
14       struct {
15          int         x1, y1, x2, y2;
16          struct {
17             Evas_Coord w, h;
18          } object;
19       } cache;
20       Evas_Coord         x1, y1, x2, y2;
21    } cur, prev;
22
23    void             *engine_data;
24
25    char              changed : 1;
26 };
27
28 /* private methods for line objects */
29 static void evas_object_line_init(Evas_Object *obj);
30 static void *evas_object_line_new(void);
31 static void evas_object_line_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
32 static void evas_object_line_free(Evas_Object *obj);
33 static void evas_object_line_render_pre(Evas_Object *obj);
34 static void evas_object_line_render_post(Evas_Object *obj);
35
36 static unsigned int evas_object_line_id_get(Evas_Object *obj);
37 static unsigned int evas_object_line_visual_id_get(Evas_Object *obj);
38 static void *evas_object_line_engine_data_get(Evas_Object *obj);
39
40 static int evas_object_line_is_opaque(Evas_Object *obj);
41 static int evas_object_line_was_opaque(Evas_Object *obj);
42 static int evas_object_line_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
43 static int evas_object_line_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
44 static void evas_object_line_coords_recalc(Evas_Object *obj);
45
46 static const Evas_Object_Func object_func =
47 {
48    /* methods (compulsory) */
49    evas_object_line_free,
50      evas_object_line_render,
51      evas_object_line_render_pre,
52      evas_object_line_render_post,
53      evas_object_line_id_get,
54      evas_object_line_visual_id_get,
55      evas_object_line_engine_data_get,
56    /* these are optional. NULL = nothing */
57      NULL,
58      NULL,
59      NULL,
60      NULL,
61      evas_object_line_is_opaque,
62      evas_object_line_was_opaque,
63      evas_object_line_is_inside,
64      evas_object_line_was_inside,
65      evas_object_line_coords_recalc,
66      NULL,
67      NULL,
68      NULL,
69      NULL
70 };
71
72 /* the actual api call to add a rect */
73 /* it has no other api calls as all properties are standard */
74
75
76 /**
77  * @addtogroup Evas_Line_Group
78  * @{
79  */
80
81 EVAS_MEMPOOL(_mp_obj);
82
83 /**
84  * Adds a new evas line object to the given evas.
85  * @param   e The given evas.
86  * @return  The new evas line object.
87  */
88 EAPI Evas_Object *
89 evas_object_line_add(Evas *e)
90 {
91    Evas_Object *obj;
92
93    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
94    return NULL;
95    MAGIC_CHECK_END();
96    obj = evas_object_new(e);
97    evas_object_line_init(obj);
98    evas_object_inject(obj, e);
99    return obj;
100 }
101
102 /**
103  * Sets the coordinates of the end points of the given evas line object.
104  * @param   obj The given evas line object.
105  * @param   x1  The X coordinate of the first point.
106  * @param   y1  The Y coordinate of the first point.
107  * @param   x2  The X coordinate of the second point.
108  * @param   y2  The Y coordinate of the second point.
109  */
110 EAPI void
111 evas_object_line_xy_set(Evas_Object *obj, Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2)
112 {
113    Evas_Object_Line *o;
114    Evas_Coord min_x, max_x, min_y, max_y;
115    int is, was = 0;
116
117    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
118    return;
119    MAGIC_CHECK_END();
120    o = (Evas_Object_Line *)(obj->object_data);
121    MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE);
122    return;
123    MAGIC_CHECK_END();
124    if ((x1 == o->cur.x1) && (y1 == o->cur.y1) &&
125        (x2 == o->cur.x2) && (y2 == o->cur.y2)) return;
126    if (obj->layer->evas->events_frozen <= 0)
127      {
128         if (!evas_event_passes_through(obj))
129           was = evas_object_is_in_output_rect(obj,
130                                               obj->layer->evas->pointer.x,
131                                               obj->layer->evas->pointer.y, 1, 1);
132      }
133    if (x1 < x2)
134      {
135         min_x = x1;
136         max_x = x2;
137      }
138    else
139      {
140         min_x = x2;
141         max_x = x1;
142      }
143    if (y1 < y2)
144      {
145         min_y = y1;
146         max_y = y2;
147      }
148    else
149      {
150         min_y = y2;
151         max_y = y1;
152      }
153    obj->cur.geometry.x = min_x;
154    obj->cur.geometry.y = min_y;
155    obj->cur.geometry.w = max_x - min_x + 2;
156    obj->cur.geometry.h = max_y - min_y + 2;
157 ////   obj->cur.cache.geometry.validity = 0;
158    o->cur.x1 = x1 - min_x;
159    o->cur.y1 = y1 - min_y;
160    o->cur.x2 = x2 - min_x;
161    o->cur.y2 = y2 - min_y;
162    o->changed = 1;
163    evas_object_change(obj);
164    evas_object_coords_recalc(obj);
165    evas_object_clip_dirty(obj);
166    if (obj->layer->evas->events_frozen <= 0)
167      {
168         is = evas_object_is_in_output_rect(obj,
169                                            obj->layer->evas->pointer.x,
170                                            obj->layer->evas->pointer.y, 1, 1);
171         if (!evas_event_passes_through(obj))
172           {
173              if ((is ^ was) && obj->cur.visible)
174                evas_event_feed_mouse_move(obj->layer->evas,
175                                           obj->layer->evas->pointer.x,
176                                           obj->layer->evas->pointer.y,
177                                           obj->layer->evas->last_timestamp,
178                                           NULL);
179           }
180      }
181    evas_object_inform_call_move(obj);
182    evas_object_inform_call_resize(obj);
183 }
184
185 /**
186  * Retrieves the coordinates of the end points of the given evas line object.
187  * @param obj The given line object.
188  * @param x1  Pointer to an integer in which to store the X coordinate of the
189  *            first end point.
190  * @param y1  Pointer to an integer in which to store the Y coordinate of the
191  *            first end point.
192  * @param x2  Pointer to an integer in which to store the X coordinate of the
193  *            second end point.
194  * @param y2  Pointer to an integer in which to store the Y coordinate of the
195  *            second end point.
196  */
197 EAPI void
198 evas_object_line_xy_get(const Evas_Object *obj, Evas_Coord *x1, Evas_Coord *y1, Evas_Coord *x2, Evas_Coord *y2)
199 {
200    Evas_Object_Line *o;
201
202    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
203    if (x1) *x1 = 0;
204    if (y1) *y1 = 0;
205    if (x2) *x2 = 0;
206    if (y2) *y2 = 0;
207    return;
208    MAGIC_CHECK_END();
209    o = (Evas_Object_Line *)(obj->object_data);
210    MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE);
211    if (x1) *x1 = 0;
212    if (y1) *y1 = 0;
213    if (x2) *x2 = 0;
214    if (y2) *y2 = 0;
215    return;
216    MAGIC_CHECK_END();
217    if (x1) *x1 = obj->cur.geometry.x + o->cur.x1;
218    if (y1) *y1 = obj->cur.geometry.y + o->cur.y1;
219    if (x2) *x2 = obj->cur.geometry.x + o->cur.x2;
220    if (y2) *y2 = obj->cur.geometry.y + o->cur.y2;
221 }
222
223 /**
224  * @}
225  */
226
227 /* all nice and private */
228 static void
229 evas_object_line_init(Evas_Object *obj)
230 {
231    /* alloc image ob, setup methods and default values */
232    obj->object_data = evas_object_line_new();
233    /* set up default settings for this kind of object */
234    obj->cur.color.r = 255;
235    obj->cur.color.g = 255;
236    obj->cur.color.b = 255;
237    obj->cur.color.a = 255;
238    obj->cur.geometry.x = 0;
239    obj->cur.geometry.y = 0;
240    obj->cur.geometry.w = 0;
241    obj->cur.geometry.h = 0;
242    obj->cur.layer = 0;
243    obj->cur.anti_alias = 1;
244    obj->cur.render_op = EVAS_RENDER_BLEND;
245    /* set up object-specific settings */
246    obj->prev = obj->cur;
247    /* set up methods (compulsory) */
248    obj->func = &object_func;
249    obj->type = o_type;
250 }
251
252 static void *
253 evas_object_line_new(void)
254 {
255    Evas_Object_Line *o;
256
257    /* alloc obj private data */
258    EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_line", Evas_Object_Line, 16, NULL);
259    o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Line);
260    if (!o) return NULL;
261    EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Line);
262    o->magic = MAGIC_OBJ_LINE;
263    o->cur.x1 = 0;
264    o->cur.y1 = 0;
265    o->cur.x2 = 31;
266    o->cur.y2 = 31;
267    o->prev = o->cur;
268    return o;
269 }
270
271 static void
272 evas_object_line_free(Evas_Object *obj)
273 {
274    Evas_Object_Line *o;
275
276    /* frees private object data. very simple here */
277    o = (Evas_Object_Line *)(obj->object_data);
278    MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE);
279    return;
280    MAGIC_CHECK_END();
281    /* free obj */
282    o->magic = 0;
283    free(o);
284 }
285
286 static void
287 evas_object_line_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y)
288 {
289    Evas_Object_Line *o;
290
291    /* render object to surface with context, and offxet by x,y */
292    o = (Evas_Object_Line *)(obj->object_data);
293    obj->layer->evas->engine.func->context_color_set(output,
294                                                     context,
295                                                     obj->cur.cache.clip.r,
296                                                     obj->cur.cache.clip.g,
297                                                     obj->cur.cache.clip.b,
298                                                     obj->cur.cache.clip.a);
299    obj->layer->evas->engine.func->context_multiplier_unset(output,
300                                                            context);
301    obj->layer->evas->engine.func->context_anti_alias_set(output, context,
302                                                          obj->cur.anti_alias);
303    obj->layer->evas->engine.func->context_render_op_set(output, context,
304                                                         obj->cur.render_op);
305    obj->layer->evas->engine.func->line_draw(output,
306                                             context,
307                                             surface,
308                                             o->cur.cache.x1 + x,
309                                             o->cur.cache.y1 + y,
310                                             o->cur.cache.x2 + x,
311                                             o->cur.cache.y2 + y);
312 }
313
314 static void
315 evas_object_line_render_pre(Evas_Object *obj)
316 {
317    Evas_Object_Line *o;
318    int is_v, was_v;
319
320    /* dont pre-render the obj twice! */
321    if (obj->pre_render_done) return;
322    obj->pre_render_done = 1;
323    /* pre-render phase. this does anything an object needs to do just before */
324    /* rendering. this could mean loading the image data, retrieving it from */
325    /* elsewhere, decoding video etc. */
326    /* then when this is done the object needs to figure if it changed and */
327    /* if so what and where and add the appropriate redraw lines */
328    o = (Evas_Object_Line *)(obj->object_data);
329    /* if someone is clipping this obj - go calculate the clipper */
330    if (obj->cur.clipper)
331      {
332         if (obj->cur.cache.clip.dirty)
333           evas_object_clip_recalc(obj->cur.clipper);
334         obj->cur.clipper->func->render_pre(obj->cur.clipper);
335      }
336    /* now figure what changed and add draw rects */
337    /* if it just became visible or invisible */
338    is_v = evas_object_is_visible(obj);
339    was_v = evas_object_was_visible(obj);
340    if (is_v != was_v)
341      {
342         evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v);
343         goto done;
344      }
345    if ((obj->cur.map != obj->prev.map) ||
346        (obj->cur.usemap != obj->prev.usemap))
347      {
348         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
349         goto done;
350      }
351    /* it's not visible - we accounted for it appearing or not so just abort */
352    if (!is_v) goto done;
353    /* clipper changed this is in addition to anything else for obj */
354    evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj);
355    /* if we restacked (layer or just within a layer) */
356    if (obj->restack)
357      {
358         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
359         goto done;
360      }
361    /* if it changed anti_alias */
362    if (obj->cur.anti_alias != obj->prev.anti_alias)
363      {
364         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
365         goto done;
366      }
367    /* if it changed render op */
368    if (obj->cur.render_op != obj->prev.render_op)
369      {
370         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
371         goto done;
372      }
373    /* if it changed color */
374    if ((obj->cur.color.r != obj->prev.color.r) ||
375        (obj->cur.color.g != obj->prev.color.g) ||
376        (obj->cur.color.b != obj->prev.color.b) ||
377        (obj->cur.color.a != obj->prev.color.a))
378      {
379         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
380         goto done;
381      }
382    /* if it changed geometry - and obviously not visibility or color */
383    /* calculate differences since we have a constant color fill */
384    /* we really only need to update the differences */
385    if ((obj->cur.geometry.x != obj->prev.geometry.x) ||
386        (obj->cur.geometry.y != obj->prev.geometry.y) ||
387        (obj->cur.geometry.w != obj->prev.geometry.w) ||
388        (obj->cur.geometry.h != obj->prev.geometry.h) ||
389        ((o->changed) &&
390         ((o->cur.x1 != o->prev.x1) ||
391          (o->cur.y1 != o->prev.y1) ||
392          (o->cur.x2 != o->prev.x2) ||
393          (o->cur.y2 != o->prev.y2)))
394        )
395      {
396         evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj);
397         goto done;
398      }
399    done:
400    evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v);
401 }
402
403 static void
404 evas_object_line_render_post(Evas_Object *obj)
405 {
406    Evas_Object_Line *o;
407
408    /* this moves the current data to the previous state parts of the object */
409    /* in whatever way is safest for the object. also if we don't need object */
410    /* data anymore we can free it if the object deems this is a good idea */
411    o = (Evas_Object_Line *)(obj->object_data);
412    /* remove those pesky changes */
413    evas_object_clip_changes_clean(obj);
414    /* move cur to prev safely for object data */
415    obj->prev = obj->cur;
416    o->prev = o->cur;
417    o->changed = 0;
418 }
419
420 static unsigned int evas_object_line_id_get(Evas_Object *obj)
421 {
422    Evas_Object_Line *o;
423
424    o = (Evas_Object_Line *)(obj->object_data);
425    if (!o) return 0;
426    return MAGIC_OBJ_LINE;
427 }
428
429 static unsigned int evas_object_line_visual_id_get(Evas_Object *obj)
430 {
431    Evas_Object_Line *o;
432
433    o = (Evas_Object_Line *)(obj->object_data);
434    if (!o) return 0;
435    return MAGIC_OBJ_SHAPE;
436 }
437
438 static void *evas_object_line_engine_data_get(Evas_Object *obj)
439 {
440    Evas_Object_Line *o;
441
442    o = (Evas_Object_Line *)(obj->object_data);
443    if (!o) return NULL;
444    return o->engine_data;
445 }
446
447 static int
448 evas_object_line_is_opaque(Evas_Object *obj __UNUSED__)
449 {
450    /* this returns 1 if the internal object data implies that the object is */
451    /* currently fully opaque over the entire line it occupies */
452    return 0;
453 }
454
455 static int
456 evas_object_line_was_opaque(Evas_Object *obj __UNUSED__)
457 {
458    /* this returns 1 if the internal object data implies that the object was */
459    /* previously fully opaque over the entire line it occupies */
460    return 0;
461 }
462
463 static int
464 evas_object_line_is_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
465 {
466    /* this returns 1 if the canvas co-ordinates are inside the object based */
467    /* on object private data. not much use for rects, but for polys, images */
468    /* and other complex objects it might be */
469    return 1;
470 }
471
472 static int
473 evas_object_line_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__)
474 {
475    /* this returns 1 if the canvas co-ordinates were inside the object based */
476    /* on object private data. not much use for rects, but for polys, images */
477    /* and other complex objects it might be */
478    return 1;
479 }
480
481 static void
482 evas_object_line_coords_recalc(Evas_Object *obj)
483 {
484    Evas_Object_Line *o;
485
486    o = (Evas_Object_Line *)(obj->object_data);
487    o->cur.cache.x1 = obj->cur.geometry.x + o->cur.x1;
488    o->cur.cache.y1 = obj->cur.geometry.y + o->cur.y1;
489    o->cur.cache.x2 = obj->cur.geometry.x + o->cur.x2;
490    o->cur.cache.y2 = obj->cur.geometry.y + o->cur.y2;
491    o->cur.cache.object.w = obj->cur.geometry.w;
492    o->cur.cache.object.h = obj->cur.geometry.h;
493 }