diff --git a/solidify/Makefile b/solidify/Makefile index 46cd807..2a6f7b8 100644 --- a/solidify/Makefile +++ b/solidify/Makefile @@ -12,7 +12,7 @@ SHELL = /bin/bash -OBJS = array.o face.o histo.o level.o overlap.o solidify.o +OBJS = array.o face.o histo.o level.o overlap.o solidify.o style.o util.o CFLAGS_WARN = -Wall -Wshadow -Wmissing-prototypes \ -Wmissing-declarations -Wno-format-zero-length diff --git a/solidify/level.c b/solidify/level.c index 20ea52b..882253b 100644 --- a/solidify/level.c +++ b/solidify/level.c @@ -16,15 +16,26 @@ #include #include +#include "util.h" #include "array.h" #include "face.h" +#include "style.h" #include "level.h" #define NEAR 1 -static void draw_image(GtkWidget *widget, struct face *f) +static int has_osd; + + +static double r_center(const struct face *f) +{ + return hypot(f->sx, f->sy)/LEVEL_CENTER_DIV; +} + + +static void draw_map(GtkWidget *widget, struct face *f) { int x, y, z; double z0; @@ -70,7 +81,17 @@ static void draw_image(GtkWidget *widget, struct face *f) } -static void scroll_z(GtkWidget *da, struct face *f, int up) +static void draw_image(GtkWidget *widget, struct face *f, int osd) +{ + draw_map(widget, f); + has_osd = osd; + if (osd) + draw_circle(widget->window, gc_osd, + f->sx/2, f->sy/2, r_center(f)); +} + + +static void scroll_z(GtkWidget *darea, struct face *f, int up, int osd) { if (up) { if (f->z_ref < f->a->max_z) @@ -79,42 +100,46 @@ static void scroll_z(GtkWidget *da, struct face *f, int up) if (f->z_ref > f->a->min_z) f->z_ref--; } - draw_image(da, f); + draw_image(darea, f, osd); } -static void scroll_xy(GtkWidget *da, struct face *f, int dx, int dy, int up) +static void scroll_xy(GtkWidget *darea, struct face *f, int dx, int dy, int up, + int osd) { double d; d = (double) (up ? 1 : -1)/(dx*dx+dy*dy)/2.0; f->fx += d*dx; f->fy += d*dy; - draw_image(da, f); + draw_image(darea, f, osd); } static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { - GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget)); + GtkWidget *darea = gtk_bin_get_child(GTK_BIN(widget)); struct face *f = data; int dx = event->x-f->sx/2; int dy = event->y-f->sy/2; - int center = hypot(dx, dy)/hypot(f->sx, f->sy) < 0.25; + double r = hypot(dx, dy); + double rc = r_center(f); + int center = r < rc; + int osd = fabs(r-rc) < OSD_PROXIMITY; switch (event->direction) { case GDK_SCROLL_UP: if (center) - scroll_z(da, f, 0); + scroll_z(darea, f, 0, osd); else - scroll_xy(da, f, dx, dy, 1); + scroll_xy(darea, f, dx, dy, 1, osd); break; case GDK_SCROLL_DOWN: if (center) - scroll_z(da, f, 1); + scroll_z(darea, f, 1, osd); else - scroll_xy(da, f, dx, dy, 0); + scroll_xy(darea, f, dx, dy, 0, osd); break; default: /* ignore */; @@ -126,25 +151,50 @@ 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 face *f = data; + int dx = event->x-f->sx/2; + int dy = event->y-f->sy/2; + double r = hypot(dx, dy); + double rc = r_center(f); + int osd = fabs(r-rc) < OSD_PROXIMITY; + + if (osd != has_osd) + draw_image(widget, f, osd); + return FALSE; +} + + void level(GtkWidget *canvas, struct face *f) { - GtkWidget *evbox, *da; + GtkWidget *evbox, *darea; evbox = gtk_event_box_new(); - da = gtk_drawing_area_new(); - gtk_widget_set_size_request(da, f->sx, f->sy); - gtk_container_add(GTK_CONTAINER(canvas), evbox); - gtk_container_add(GTK_CONTAINER(evbox), da); + darea = gtk_drawing_area_new(); - draw_image(da, f); + 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, f->sx, f->sy); + gtk_container_add(GTK_CONTAINER(canvas), evbox); + gtk_container_add(GTK_CONTAINER(evbox), darea); + + draw_image(darea, f, 0); g_signal_connect(G_OBJECT(evbox), "scroll-event", G_CALLBACK(scroll_event), f); - g_signal_connect(G_OBJECT(da), "expose-event", + g_signal_connect(G_OBJECT(darea), "expose-event", G_CALLBACK(expose_event), f); + g_signal_connect(G_OBJECT(darea), "motion-notify-event", + G_CALLBACK(motion_notify_event), f); } diff --git a/solidify/overlap.c b/solidify/overlap.c index c2f045b..c69bae4 100644 --- a/solidify/overlap.c +++ b/solidify/overlap.c @@ -203,7 +203,7 @@ static void shift(struct matrix *m, int dx, int dy, int dir) static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { - GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget)); + GtkWidget *darea = gtk_bin_get_child(GTK_BIN(widget)); struct solid *s = data; int dx = event->x-sx(s)/2; int dy = event->y-sy(s)/2; @@ -218,14 +218,14 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, shift(&s->a->m, dx, dy, 1); else rotate(&s->a->m, r); - draw_image(da, s); + draw_image(darea, s); break; case GDK_SCROLL_DOWN: if (center) shift(&s->a->m, dx, dy, -1); else rotate(&s->a->m, -r); - draw_image(da, s); + draw_image(darea, s); break; default: /* ignore */; @@ -245,18 +245,18 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, void overlap(GtkWidget *canvas, struct solid *s) { - GtkWidget *evbox, *da; + GtkWidget *evbox, *darea; evbox = gtk_event_box_new(); - da = gtk_drawing_area_new(); - gtk_widget_set_size_request(da, sx(s), sy(s)); + darea = gtk_drawing_area_new(); + gtk_widget_set_size_request(darea, sx(s), sy(s)); gtk_container_add(GTK_CONTAINER(canvas), evbox); - gtk_container_add(GTK_CONTAINER(evbox), da); + gtk_container_add(GTK_CONTAINER(evbox), darea); - draw_image(da, s); + draw_image(darea, s); g_signal_connect(G_OBJECT(evbox), "scroll-event", G_CALLBACK(scroll_event), s); - g_signal_connect(G_OBJECT(da), "expose-event", + g_signal_connect(G_OBJECT(darea), "expose-event", G_CALLBACK(expose_event), s); } diff --git a/solidify/solidify.c b/solidify/solidify.c index b306c1b..60f79a0 100644 --- a/solidify/solidify.c +++ b/solidify/solidify.c @@ -18,6 +18,7 @@ #include "face.h" #include "solid.h" +#include "style.h" #include "level.h" #include "overlap.h" @@ -102,6 +103,8 @@ static void gui(void) level(canvas, solid.a); active = solid.a; + init_style(root->window); + gtk_widget_show_all(root); g_signal_connect(G_OBJECT(root), "key-press-event", diff --git a/solidify/style.c b/solidify/style.c new file mode 100644 index 0000000..6b260a8 --- /dev/null +++ b/solidify/style.c @@ -0,0 +1,53 @@ +/* + * style.c - GUI style parameters and items + * + * Written 2010 by Werner Almesberger + * Copyright 2010 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include +#include + +#include "style.h" + + +GdkGC *gc_osd; + + +static GdkColor get_color(GdkDrawable *da, const char *spec) +{ + GdkColormap *cmap; + GdkColor color; + + cmap = gdk_drawable_get_colormap(da); + if (!gdk_color_parse(spec, &color)) + abort(); + if (!gdk_colormap_alloc_color(cmap, &color, FALSE, TRUE)) + abort(); + return color; +} + + +static GdkGC *gc(GdkDrawable *da, const char *spec, int width) +{ + GdkGCValues gc_values = { + .background = get_color(da, "black"), + .foreground = get_color(da, spec), + .line_width = width, + }; + + return gdk_gc_new_with_values(da, &gc_values, + GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_LINE_WIDTH); +} + + +void init_style(GdkDrawable *da) +{ + gc_osd = gc(da, "#ffff00", 4); +} diff --git a/solidify/style.h b/solidify/style.h new file mode 100644 index 0000000..aff1c42 --- /dev/null +++ b/solidify/style.h @@ -0,0 +1,28 @@ +/* + * style.h - GUI style parameters and items + * + * Written 2010 by Werner Almesberger + * Copyright 2010 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef STYLE_H +#define STYLE_H + +#include + + +extern GdkGC *gc_osd; + + +#define OSD_PROXIMITY 20 +#define LEVEL_CENTER_DIV 5 + + +void init_style(GdkDrawable *da); + +#endif /* !STYLE_H */ diff --git a/solidify/util.c b/solidify/util.c new file mode 100644 index 0000000..40206d1 --- /dev/null +++ b/solidify/util.c @@ -0,0 +1,22 @@ +/* + * util.c - Common utility functions + * + * Written 2010 by Werner Almesberger + * Copyright 2010 by Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include + +#include "util.h" + + +void draw_circle(GdkDrawable *da, GdkGC *gc, int x, int y, int r) +{ + gdk_draw_arc(da, gc, FALSE, x-r, y-r, 2*r, 2*r, 0, 360*64); +} diff --git a/solidify/util.h b/solidify/util.h index 4b71771..8bcd292 100644 --- a/solidify/util.h +++ b/solidify/util.h @@ -14,6 +14,7 @@ #define UTIL_H #include +#include #define alloc_size(s) \ @@ -24,4 +25,7 @@ #define alloc_type(t) ((t *) alloc_size(sizeof(t))) + +void draw_circle(GdkDrawable *da, GdkGC *gc, int x, int y, int r); + #endif /* UTIL_H */