#include #include #include #include "line.h" static Evas_Smart *get_smart(); static void _line_object_add(Evas_Object *o); static void _line_object_del(Evas_Object *o); static void _line_object_move(Evas_Object *o, Evas_Coord x, Evas_Coord y); static void _line_object_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h); static void _line_object_show(Evas_Object *o); static void _line_object_hide(Evas_Object *o); static void _line_object_color_set(Evas_Object *o, int r, int g, int b, int a); static void _line_object_clip_set(Evas_Object *o, Evas_Object *clip); static void _line_object_clip_unset(Evas_Object *o); #define SMART_LINE_NAME "e_smart_line" struct polyline *polyline_empty() { struct polyline *pl; pl = (struct polyline *)malloc(sizeof(struct polyline)); if (pl == NULL) return NULL; pl->w = 0; pl->a = 255; pl->r = 0; pl->g = 0; pl->b = 0; pl->points = NULL; pl->count = 0; pl->mode = 0; return pl; } void polyline_delete(struct polyline *pl) { free(pl->points); free(pl); } void polyline_set_color(struct polyline *pl, int r, int g, int b, int a) { pl->a = a; pl->r = r; pl->g = g; pl->b = b; } void polyline_set_width(struct polyline *pl, int w) { pl->w = w; } void polyline_add_point(struct polyline *pl, struct point p) { pl->points = realloc(pl->points, (pl->count + 1) * sizeof(struct point)); pl->points[pl->count] = p; pl->count++; } struct smart_line { Evas_Object *obj; Evas_Coord x, y, w, h; Evas_Object *clip; Evas_Object *poly; struct point *points; struct polyline *pl; int pcount; }; Evas_Object *e_smart_line_add(Evas *e) { Evas_Object *o; struct smart_line *smart; o = evas_object_smart_add(e, get_smart()); smart = evas_object_smart_data_get(o); if(smart == NULL) { evas_object_del(o); return NULL; } smart->points = NULL; smart->pcount = 0; smart->pl = NULL; return o; } static inline int line_cut(struct line l0, struct line l1, struct point *p) { Evas_Coord c1, c2, det, a1, a2, b1, b2; b1 = l0.p0.x - l0.p1.x; // b1 = x1 - x2 a1 = l0.p1.y - l0.p0.y; // a1 = y2 - y1 c1 = l0.p1.x * l0.p0.y - l0.p0.x * l0.p1.y; // c = x2*y1 - x1*y2; b2 = l1.p0.x - l1.p1.x; // b2 = x3 - x4 a2 = l1.p1.y - l1.p0.y; // a2 = y4 - y3 c2 = l1.p1.x * l1.p0.y - l1.p0.x * l1.p1.y; det = a1 * b2 - a2 * b1; if(det == 0) return -1; p->x = (b1*c2 - b2*c1)/det; p->y = (a2*c1 - a1*c2)/det; return 0; } static inline struct line new_line(struct point p0, struct point p1) { struct line l; l.p0 = p0; l.p1 = p1; return l; } static inline void wide_line(Evas_Coord w, struct line l, struct line *l0, struct line *l1) { Evas_Coord dX, dY, dx, dy; double scale, len, ddx, ddy; dX = l.p1.x - l.p0.x; dY = l.p1.y - l.p0.y; len = sqrt(dX * dX + dY * dY); scale = (double)(w) / (2 * len); ddx = -scale * (double)dY; ddy = scale * (double)dX; ddx += (ddx > 0) ? 0.5 : -0.5; ddy += (ddy > 0) ? 0.5 : -0.5; dx = (Evas_Coord)ddx; dy = (Evas_Coord)ddy; l0->p0.x = l.p0.x + dx; l0->p0.y = l.p0.y + dy; l1->p0.x = l.p0.x - dx; l1->p0.y = l.p0.y - dy; l0->p1.x = l.p1.x + dx; l0->p1.y = l.p1.y + dy; l1->p1.x = l.p1.x - dx; l1->p1.y = l.p1.y - dy; } static int _is_line_valid(struct line *l, int w) { int dx = abs(l->p1.x - l->p0.x); int dy = abs(l->p1.y - l->p0.y); if(dx < w && dy < w) return 0; return 1; } static void _line_update(struct smart_line *smart, int dx, int dy) { int i; evas_object_polygon_points_clear(smart->poly); for(i = 0; i < smart->pcount; i++) { // printf("p[%i]: %i,%i\n", i, poly[i].x, poly[i].y); evas_object_polygon_point_add(smart->poly, smart->points[i].x - dx, smart->points[i].y - dy); } evas_object_show(smart->poly); } struct polyline *e_smart_line_get(Evas_Object *o) { struct smart_line *smart; smart = evas_object_smart_data_get(o); return smart->pl; } void e_smart_line_set(Evas_Object *o, struct polyline *pl) { int i; struct smart_line *smart; struct line l0_0 = {{0}}; struct line l0_1 = {{0}}; struct point fwd[pl->count]; struct point bwd[pl->count]; int pcount = 0; struct point last; if(pl->count < 1) return; smart = evas_object_smart_data_get(o); last = pl->points[0]; for(i = 1; i < pl->count; i++) { struct point tmp; struct line l = new_line(last, pl->points[i]); if(!_is_line_valid(&l, pl->w)) continue; if(pcount == 0) { wide_line(pl->w, l, &l0_0, &l0_1); fwd[pcount] = l0_0.p0; bwd[pcount] = l0_1.p0; last = pl->points[i]; pcount++; continue; } if(i >= pl->count - 1) { fwd[pcount] = l0_0.p1; bwd[pcount] = l0_1.p1; pcount++; break; } struct line l1_0, l1_1; wide_line(pl->w, l, &l1_0, &l1_1); if(line_cut(l0_0, l1_0, &tmp) < 0) continue; fwd[pcount] = tmp; if(line_cut(l0_1, l1_1, &tmp) < 0) continue; bwd[pcount] = tmp; last = pl->points[i]; l0_0 = l1_0; l0_1 = l1_1; pcount++; } if(smart->points != NULL) free(smart->points); smart->points = (struct point *)malloc(sizeof(struct point) * pcount * 2); smart->pcount = pcount * 2; for(i = 0; i < pcount; i++) { smart->points[i] = fwd[i]; smart->points[2 * pcount - i - 1] = bwd[i]; } evas_object_color_set(smart->poly, pl->r, pl->g, pl->b, pl->a); _line_update(smart, smart->x, smart->y); smart->pl = pl; } static void _line_object_add(Evas_Object *o) { struct smart_line *smart; smart = calloc(1, sizeof(struct smart_line)); if (smart == NULL) return; smart->obj = o; smart->x = 0; smart->y = 0; smart->w = 0; smart->h = 0; smart->clip = evas_object_rectangle_add(evas_object_evas_get(o)); evas_object_smart_member_add(smart->clip, o); evas_object_color_set(smart->clip, 255, 255, 255, 255); evas_object_move(smart->clip, smart->x, smart->y); evas_object_resize(smart->clip, smart->w, smart->h); smart->poly = evas_object_polygon_add(evas_object_evas_get(o)); evas_object_smart_member_add(smart->poly, o); evas_object_color_set(smart->poly, 255, 255, 255, 255); evas_object_move(smart->poly, smart->x, smart->y); evas_object_resize(smart->poly, smart->w, smart->h); evas_object_show(smart->poly); evas_object_smart_data_set(o, smart); } static void _line_object_del(Evas_Object *o) { struct smart_line *smart; smart = evas_object_smart_data_get(o); evas_object_del(smart->clip); evas_object_del(smart->poly); free(smart); } static void _line_object_move(Evas_Object *o, Evas_Coord x, Evas_Coord y) { struct smart_line *smart; smart = evas_object_smart_data_get(o); smart->x = x; smart->y = y; _line_update(smart, smart->x, smart->y); } static void _line_object_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h) { struct smart_line *smart; smart = evas_object_smart_data_get(o); smart->w = w; smart->h = h; evas_object_resize(smart->clip, smart->w, smart->h); evas_object_resize(smart->poly, smart->w, smart->h); } static void _line_object_show(Evas_Object *o) { struct smart_line *smart; smart = evas_object_smart_data_get(o); evas_object_show(smart->clip); } static void _line_object_hide(Evas_Object *o) { struct smart_line *smart; smart = evas_object_smart_data_get(o); evas_object_hide(smart->clip); } static void _line_object_color_set(Evas_Object *o, int r, int g, int b, int a) { struct smart_line *smart; smart = evas_object_smart_data_get(o); evas_object_color_set(smart->poly, r, g, b, a); } static void _line_object_clip_set(Evas_Object *o, Evas_Object *clip) { struct smart_line *smart; smart = evas_object_smart_data_get(o); evas_object_clip_set(smart->clip, clip); } static void _line_object_clip_unset(Evas_Object *o) { struct smart_line *smart; smart = evas_object_smart_data_get(o); evas_object_clip_unset(smart->clip); } static Evas_Smart *get_smart() { static Evas_Smart *e_smart_line = NULL; if(e_smart_line != NULL) return e_smart_line; e_smart_line = evas_smart_new(SMART_LINE_NAME, _line_object_add, _line_object_del, NULL, NULL, NULL, NULL, NULL, _line_object_move, _line_object_resize, _line_object_show, _line_object_hide, _line_object_color_set, _line_object_clip_set, _line_object_clip_unset, NULL); return e_smart_line; }