diff --git a/solidify/overlap.c b/solidify/overlap.c index c69bae4..2a66f3f 100644 --- a/solidify/overlap.c +++ b/solidify/overlap.c @@ -17,24 +17,34 @@ #include #include +#include "util.h" #include "face.h" #include "solid.h" +#include "style.h" #include "overlap.h" #define UNDEF_F HUGE_VAL -#define BORDER 10 /* pixels around the minimum drawing area */ + + +static int has_osd; static int sx(const struct solid *s) { - return (s->a->sx > s->b->sx ? s->a->sx : s->b->sx)+2*BORDER; + return (s->a->sx > s->b->sx ? s->a->sx : s->b->sx)+2*OVERLAP_BORDER; } static int sy(const struct solid *s) { - return (s->a->sy > s->b->sy ? s->a->sy : s->b->sy)+2*BORDER; + return (s->a->sy > s->b->sy ? s->a->sy : s->b->sy)+2*OVERLAP_BORDER; +} + + +static double r_center(const struct solid *s) +{ + return hypot(sx(s), sy(s))/OVERLAP_CENTER_DIV; } @@ -136,7 +146,7 @@ static void point(const struct solid *s, int x, int y, guchar *p) } -static void draw_image(GtkWidget *widget, struct solid *s) +static void draw_map(GtkWidget *widget, struct solid *s) { guchar *rgbbuf, *p; int x, y; @@ -158,6 +168,23 @@ static void draw_image(GtkWidget *widget, struct solid *s) } +static void draw_image(GtkWidget *widget, struct solid *s, int osd) +{ + int cx = sx(s)/2; + int cy = sy(s)/2; + int p; + + draw_map(widget, s); + has_osd = osd; + if (!osd) + return; + draw_circle(widget->window, gc_osd, cx, cy, r_center(s)); + p = r_center(s)/sqrt(2); + gdk_draw_line(widget->window, gc_osd, cx-p, cy-p, cx+p, cy+p); + gdk_draw_line(widget->window, gc_osd, cx-p, cy+p, cx+p, cy-p); +} + + /* * Rotate such that a point at distance "r" moves one unit. Rotate * counter-clockwise for r > 1, clockwise for r < 0. @@ -200,6 +227,21 @@ static void shift(struct matrix *m, int dx, int dy, int dir) } +static int osd_proximity(const struct solid *s, int dx, int dy) +{ + double r = hypot(dx, dy); + double rc = r_center(s); + + if (fabs(r-rc) < OSD_PROXIMITY) + return 1; + if (r > rc) + return 0; + if (abs(abs(dx)-abs(dy)) < OSD_PROXIMITY) + return 1; + return 0; +} + + static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { @@ -208,7 +250,9 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, int dx = event->x-sx(s)/2; int dy = event->y-sy(s)/2; double r = hypot(dx, dy); - int center = r/hypot(sx(s), sy(s)) < 0.25; + double rc = r_center(s); + int center = r < rc; + int osd = osd_proximity(s, dx, dy); if (r < 1) return TRUE; @@ -217,15 +261,15 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, if (center) shift(&s->a->m, dx, dy, 1); else - rotate(&s->a->m, r); - draw_image(darea, s); + rotate(&s->a->m, -r); + draw_image(darea, s, osd); break; case GDK_SCROLL_DOWN: if (center) shift(&s->a->m, dx, dy, -1); else - rotate(&s->a->m, -r); - draw_image(darea, s); + rotate(&s->a->m, r); + draw_image(darea, s, osd); break; default: /* ignore */; @@ -237,11 +281,24 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { - draw_image(widget, user_data); + draw_image(widget, user_data, has_osd); return TRUE; } +static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, + gpointer data) +{ + struct solid *s = data; + int dx = event->x-sx(s)/2; + int dy = event->y-sy(s)/2; + int osd = osd_proximity(s, dx, dy); + + if (osd != has_osd) + draw_image(widget, s, osd); + return FALSE; +} + void overlap(GtkWidget *canvas, struct solid *s) { @@ -249,14 +306,24 @@ void overlap(GtkWidget *canvas, struct solid *s) evbox = gtk_event_box_new(); darea = gtk_drawing_area_new(); + + gtk_widget_set_events(darea, + GDK_EXPOSE | GDK_KEY_PRESS_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL | + GDK_POINTER_MOTION_MASK); + gtk_widget_set_size_request(darea, sx(s), sy(s)); gtk_container_add(GTK_CONTAINER(canvas), evbox); gtk_container_add(GTK_CONTAINER(evbox), darea); - draw_image(darea, s); + draw_image(darea, s, 0); g_signal_connect(G_OBJECT(evbox), "scroll-event", G_CALLBACK(scroll_event), s); g_signal_connect(G_OBJECT(darea), "expose-event", G_CALLBACK(expose_event), s); + g_signal_connect(G_OBJECT(darea), "motion-notify-event", + G_CALLBACK(motion_notify_event), s); + } diff --git a/solidify/style.h b/solidify/style.h index aff1c42..14bb978 100644 --- a/solidify/style.h +++ b/solidify/style.h @@ -19,8 +19,10 @@ extern GdkGC *gc_osd; -#define OSD_PROXIMITY 20 -#define LEVEL_CENTER_DIV 5 +#define OSD_PROXIMITY 20 /* pixels */ +#define LEVEL_CENTER_DIV 5 /* fraction of diagonal */ +#define OVERLAP_BORDER 10 /* pixels around min. drawing area */ +#define OVERLAP_CENTER_DIV 5 /* fraction of diagonal */ void init_style(GdkDrawable *da);