From e2ff07457c7ef098b15ec4e22a4604f8dcaebfe0 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 3 Aug 2016 09:33:16 -0300 Subject: [PATCH] eeshow/: scroll wheel zooms --- eeshow/cro.c | 38 +++++---- eeshow/cro.h | 5 +- eeshow/gui.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 236 insertions(+), 27 deletions(-) diff --git a/eeshow/cro.c b/eeshow/cro.c index 4b7f66a..bd70aed 100644 --- a/eeshow/cro.c +++ b/eeshow/cro.c @@ -303,21 +303,25 @@ static void *cr_pdf_init(int argc, char *const *argv) } -static void end_common(struct cro_ctx *cc, int *w, int *h) +static void end_common(struct cro_ctx *cc, int *w, int *h, int *x, int *y) { - int x, y; + int xmin, ymin; cairo_surface_destroy(cc->s); cairo_destroy(cc->cr); - record_bbox(&cc->record, &x, &y, w, h); + record_bbox(&cc->record, &xmin, &ymin, w, h); -// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, x, y); - cc->xo = -cd(cc, x); - cc->yo = -cd(cc, y); +// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, xmin, ymin); + cc->xo = -cd(cc, xmin); + cc->yo = -cd(cc, ymin); + if (x) + *x = xmin; + if (y) + *y = ymin; *w = cd(cc, *w); *h = cd(cc, *h); -// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, x, y); +// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, xmin, ymin); } @@ -339,7 +343,7 @@ static void cr_png_end(void *ctx) struct cro_ctx *cc = ctx; int w, h; - end_common(cc, &w, &h); + end_common(cc, &w, &h, NULL, NULL); cc->s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h); cc->cr = cairo_create(cc->s); @@ -380,7 +384,7 @@ static void cr_pdf_end(void *ctx) int w, h; unsigned i; - end_common(cc, &w, &h); + end_common(cc, &w, &h, NULL, NULL); if (cc->output_name) cc->s = cairo_pdf_surface_create(cc->output_name, w, h); @@ -419,7 +423,7 @@ uint32_t *cro_img_end(struct cro_ctx *cc, int *w, int *h, int *stride) { uint32_t *data; - end_common(cc, w, h); + end_common(cc, w, h, NULL, NULL); *stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, *w); data = alloc_size(*stride * *h); @@ -453,15 +457,16 @@ void cro_img_write(struct cro_ctx *cc, const char *name) } -void cro_canvas_end(struct cro_ctx *cc) +void cro_canvas_end(struct cro_ctx *cc, int *w, int *h, int *xmin, int *ymin) { - int w, h; - - end_common(cc, &w, &h); + end_common(cc, w, h, xmin, ymin); + *w /= cc->scale; + *h /= cc->scale; } -void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr) +void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr, int xo, int yo, + float scale) { set_color(cr, COLOR_WHITE); cairo_paint(cr); @@ -473,6 +478,9 @@ void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr) cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cc->cr = cr; + cc->scale = scale; + cc->xo = xo; + cc->yo = yo; record_replay(&cc->record); } diff --git a/eeshow/cro.h b/eeshow/cro.h index a050ad8..4429891 100644 --- a/eeshow/cro.h +++ b/eeshow/cro.h @@ -34,7 +34,8 @@ extern const struct gfx_ops cro_pdf_ops; uint32_t *cro_img_end(struct cro_ctx *cc, int *w, int *h, int *stride); void cro_img_write(struct cro_ctx *cc, const char *name); -void cro_canvas_end(struct cro_ctx *cc); -void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr); +void cro_canvas_end(struct cro_ctx *cc, int *w, int *h, int *xmin, int *ymin); +void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr, int x, int y, + float scale); #endif /* !CRO_H */ diff --git a/eeshow/gui.c b/eeshow/gui.c index ec36c2e..f6c094a 100644 --- a/eeshow/gui.c +++ b/eeshow/gui.c @@ -17,6 +17,8 @@ * https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html */ +#include + #include #include "cro.h" @@ -26,17 +28,39 @@ struct gui_ctx { + GtkWidget *da; const struct sch_ctx *sch; + struct cro_ctx *gfx_ctx; + int w, h; + int xmin, ymin; + + unsigned zoom; /* scale by 1.0 / (1 << zoom) */ + int x, y; /* center, in eeschema coordinates */ + + bool panning; + int pan_x, pan_y; } gui_ctx; +/* ----- Rendering --------------------------------------------------------- */ + + static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) { const struct gui_ctx *ctx = user_data; + GtkAllocation alloc; - cro_canvas_draw(ctx->gfx_ctx, cr); + float f = 1.0 / (1 << ctx->zoom); + int x, y; + + gtk_widget_get_allocation(ctx->da, &alloc); +// x = -(ctx->xo - ctx->w / 2) * f - (ctx->x - alloc.width / 2); +// y = -(ctx->yo - ctx->h / 2) * f - (ctx->y - alloc.height / 2); + x = -(ctx->xmin + ctx->x) * f + alloc.width / 2; + y = -(ctx->ymin + ctx->y) * f + alloc.height / 2; + cro_canvas_draw(ctx->gfx_ctx, cr, x, y, f); return FALSE; } @@ -48,35 +72,211 @@ static void render(struct gui_ctx *ctx) gfx_init(&cro_canvas_ops, 1, argv); sch_render(ctx->sch->sheets); - cro_canvas_end(gfx_ctx); + cro_canvas_end(gfx_ctx, &ctx->w, &ctx->h, &ctx->xmin, &ctx->ymin); ctx->gfx_ctx = gfx_ctx; + + ctx->x = ctx->w >> 1; + ctx->y = ctx->h >> 1; // gfx_end(); } +/* ----- Tools ------------------------------------------------------------- */ + + +static void canvas_coord(const struct gui_ctx *ctx, + int ex, int ey, int *x, int *y) +{ + int sx, sy; + GtkAllocation alloc; + + gtk_widget_get_allocation(ctx->da, &alloc); + sx = ex - alloc.width / 2; + sy = ey - alloc.height / 2; + *x = (sx << ctx->zoom) + ctx->x; + *y = (sy << ctx->zoom) + ctx->y; +} + + +/* ----- Panning ----------------------------------------------------------- */ + + +static void pan_begin(struct gui_ctx *ctx, int x, int y) +{ +} + + +static void pan_update(struct gui_ctx *ctx, int x, int y) +{ +} + + +static void pan_end(struct gui_ctx *ctx, int x, int y) +{ +} + + +/* ----- Zoom -------------------------------------------------------------- */ + + + +static void zoom_in(struct gui_ctx *ctx, int x, int y) +{ + if (ctx->zoom == 0) + return; + ctx->zoom--; + ctx->x = (ctx->x + x) / 2; + ctx->y = (ctx->y + y) / 2; + gtk_widget_queue_draw(ctx->da); +} + + +static void zoom_out(struct gui_ctx *ctx, int x, int y) +{ + if (ctx->w >> ctx->zoom <= 16) + return; + ctx->zoom++; + ctx->x = 2 * ctx->x - x; + ctx->y = 2 * ctx->y - y; + gtk_widget_queue_draw(ctx->da); +} + + +/* ----- Event handlers ---------------------------------------------------- */ + + +static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, + gpointer data) +{ + struct gui_ctx *ctx = data; + int x, y; + + canvas_coord(ctx, event->x, event->y, &x, &y); +// fprintf(stderr, "motion\n"); + pan_update(ctx, x, y); + return TRUE; +} + + +static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, + gpointer data) +{ + struct gui_ctx *ctx = data; + int x, y; + + canvas_coord(ctx, event->x, event->y, &x, &y); + fprintf(stderr, "button press\n"); + switch (event->button) { + case 1: + case 2: + pan_begin(ctx, x, y); + break; + case 3: + ; + } + return TRUE; +} + + +static gboolean button_release_event(GtkWidget *widget, GdkEventButton *event, + gpointer data) +{ + struct gui_ctx *ctx = data; + int x, y; + + canvas_coord(ctx, event->x, event->y, &x, &y); + fprintf(stderr, "button release\n"); + switch (event->button) { + case 1: + case 2: + pan_end(ctx, x, y); + break; + case 3: + ; + } + return TRUE; +} + + +static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ +fprintf(stderr, "key %d\n", event->keyval); + switch (event->keyval) { + case GDK_KEY_q: + gtk_main_quit(); + } + return TRUE; +} + + +static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, + gpointer data) +{ + struct gui_ctx *ctx = data; + int x, y; + + canvas_coord(ctx, event->x, event->y, &x, &y); + switch (event->direction) { + case GDK_SCROLL_UP: + zoom_in(ctx, x, y); + break; + case GDK_SCROLL_DOWN: + zoom_out(ctx, x, y); + break; + default: + /* ignore */; + } + return TRUE; +} + + +/* ----- Initialization ---------------------------------------------------- */ + + int gui(struct sch_ctx *sch) { GtkWidget *window; - GtkWidget *da; struct gui_ctx ctx = { - .sch = sch, + .sch = sch, + .zoom = 4, /* scale by 1 / 16 */ + .panning = 0, }; render(&ctx); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - da = gtk_drawing_area_new(); - gtk_container_add(GTK_CONTAINER(window), da); + ctx.da = gtk_drawing_area_new(); + gtk_container_add(GTK_CONTAINER(window), ctx.da); - g_signal_connect(G_OBJECT(da), "draw", + g_signal_connect(G_OBJECT(ctx.da), "draw", G_CALLBACK(on_draw_event), &ctx); + g_signal_connect(G_OBJECT(ctx.da), "motion_notify_event", + G_CALLBACK(motion_notify_event), &ctx); + g_signal_connect(G_OBJECT(ctx.da), "button_press_event", + G_CALLBACK(button_press_event), &ctx); + g_signal_connect(G_OBJECT(ctx.da), "button_release_event", + G_CALLBACK(button_release_event), &ctx); + g_signal_connect(G_OBJECT(ctx.da), "scroll_event", + G_CALLBACK(scroll_event), &ctx); + g_signal_connect(G_OBJECT(ctx.da), "key_press_event", + G_CALLBACK(key_press_event), &ctx); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); - gtk_window_set_default_size(GTK_WINDOW(window), 400, 90); - gtk_window_set_title(GTK_WINDOW(window), "GTK window"); + gtk_widget_set_can_focus(ctx.da, TRUE); + + gtk_widget_set_events(ctx.da, + GDK_EXPOSE | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_PRESS_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_SCROLL_MASK | + GDK_POINTER_MOTION_MASK); + +// gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); +// gtk_window_set_default_size(GTK_WINDOW(window), 400, 90); + gtk_window_set_title(GTK_WINDOW(window), "eeshow"); gtk_widget_show_all(window);