diff --git a/eeshow/Makefile b/eeshow/Makefile
index b3122c6..a86dc2c 100644
--- a/eeshow/Makefile
+++ b/eeshow/Makefile
@@ -15,7 +15,7 @@ OBJS = main.o \
kicad/sch-parse.o kicad/sch-render.o kicad/lib-parse.o \
kicad/lib-render.o kicad/dwg.o kicad/delta.o \
gui/gui.o gui/over.o gui/style.o gui/aoi.o gui/fmt-pango.o gui/input.o \
- gui/progress.o gui/glabel.o \
+ gui/progress.o gui/glabel.o gui/sheet.o \
file/file.o file/git-util.o file/git-file.o file/git-hist.o \
gfx/style.o gfx/fig.o gfx/record.o gfx/cro.o gfx/diff.o gfx/gfx.o \
gfx/text.o gfx/misc.o \
diff --git a/eeshow/gui/common.h b/eeshow/gui/common.h
index 789f527..f326289 100644
--- a/eeshow/gui/common.h
+++ b/eeshow/gui/common.h
@@ -111,10 +111,27 @@ void progress_update(struct gui_ctx *ctx);
void dehover_glabel(struct gui_ctx *ctx);
void add_glabel_aoi(struct gui_sheet *sheet, const struct sch_obj *obj);
+/* sheet.c */
+
+bool sheet_click(void *user, int x, int y);
+bool sheet_hover_update(void *user, int x, int y);
+void sheet_key(void *user, int x, int y, int keyval);
+
+void go_to_sheet(struct gui_ctx *ctx, struct gui_sheet *sheet);
+void do_revision_overlays(struct gui_ctx *ctx);
+void sheet_setup(struct gui_ctx *ctx);
+
/* gui.c */
void redraw(const struct gui_ctx *ctx);
void eeschema_coord(const struct gui_ctx *ctx, int x, int y, int *rx, int *ry);
-void go_to_sheet(struct gui_ctx *ctx, struct gui_sheet *sheet);
+struct gui_sheet *find_corresponding_sheet(struct gui_sheet *pick_from,
+ struct gui_sheet *ref_in, const struct gui_sheet *ref);
+void render_sheet(struct gui_sheet *sheet);
+void render_delta(struct gui_ctx *ctx);
+void hide_history(struct gui_ctx *ctx);
+void show_history(struct gui_ctx *ctx, enum selecting sel);
+void mark_aois(struct gui_ctx *ctx, struct gui_sheet *sheet);
+
#endif /* !GUI_COMMON_H */
diff --git a/eeshow/gui/gui.c b/eeshow/gui/gui.c
index b2aa26f..585dd2c 100644
--- a/eeshow/gui/gui.c
+++ b/eeshow/gui/gui.c
@@ -57,7 +57,7 @@ void redraw(const struct gui_ctx *ctx)
}
-static struct gui_sheet *find_corresponding_sheet(struct gui_sheet *pick_from,
+struct gui_sheet *find_corresponding_sheet(struct gui_sheet *pick_from,
struct gui_sheet *ref_in, const struct gui_sheet *ref)
{
struct gui_sheet *sheet, *plan_b;
@@ -144,7 +144,7 @@ static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
}
-static void render_sheet(struct gui_sheet *sheet)
+void render_sheet(struct gui_sheet *sheet)
{
char *argv[] = { "gui", NULL };
@@ -158,11 +158,7 @@ static void render_sheet(struct gui_sheet *sheet)
}
-/* @@@ not nice to have this so far out */
-static void mark_aois(struct gui_ctx *ctx, struct gui_sheet *sheet);
-
-
-static void render_delta(struct gui_ctx *ctx)
+void render_delta(struct gui_ctx *ctx)
{
#if 0
/* @@@ needs updating for curr/last vs. new/old */
@@ -203,20 +199,6 @@ static void render_delta(struct gui_ctx *ctx)
/* ----- Tools ------------------------------------------------------------- */
-static void canvas_coord(const struct gui_ctx *ctx,
- int ex, int ey, int *x, int *y)
-{
- GtkAllocation alloc;
- int sx, sy;
-
- 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;
-}
-
-
void eeschema_coord(const struct gui_ctx *ctx, int x, int y, int *rx, int *ry)
{
GtkAllocation alloc;
@@ -227,86 +209,10 @@ void eeschema_coord(const struct gui_ctx *ctx, int x, int y, int *rx, int *ry)
}
-/* ----- 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;
- redraw(ctx);
-}
-
-
-static void zoom_out(struct gui_ctx *ctx, int x, int y)
-{
- if (ctx->curr_sheet->w >> ctx->zoom <= 16)
- return;
- ctx->zoom++;
- ctx->x = 2 * ctx->x - x;
- ctx->y = 2 * ctx->y - y;
- redraw(ctx);
-}
-
-
-static void curr_sheet_size(struct gui_ctx *ctx, int *w, int *h)
-{
- const struct gui_sheet *sheet = ctx->curr_sheet;
- int ax1, ay1, bx1, by1;
-
- if (!ctx->old_hist) {
- *w = sheet->w;
- *h = sheet->h;
- } else {
- const struct gui_sheet *old =
- find_corresponding_sheet(ctx->old_hist->sheets,
- ctx->new_hist->sheets, sheet);
-
- /*
- * We're only interested in differences here, so no need for
- * the usual "-1" in x1 = x0 + w - 1
- */
- ax1 = sheet->xmin + sheet->w;
- ay1 = sheet->ymin + sheet->h;
- bx1 = old->xmin + old->w;
- by1 = old->ymin + old->h;
- *w = (ax1 > bx1 ? ax1 : bx1) -
- (sheet->xmin < old->xmin ? sheet->xmin : old->xmin);
- *h = (ay1 > by1 ? ay1 : by1) -
- (sheet->ymin < old->ymin ? sheet->ymin : old->ymin);
- }
-}
-
-
-static void zoom_to_extents(struct gui_ctx *ctx)
-{
- GtkAllocation alloc;
- int w, h;
-
- curr_sheet_size(ctx, &w, &h);
- ctx->x = w / 2;
- ctx->y = h / 2;
-
- gtk_widget_get_allocation(ctx->da, &alloc);
- ctx->zoom = 0;
- while (w >> ctx->zoom > alloc.width || h >> ctx->zoom > alloc.height)
- ctx->zoom++;
-
- redraw(ctx);
-}
-
-
/* ----- Revision history -------------------------------------------------- */
-static void do_revision_overlays(struct gui_ctx *ctx);
-
-
-static void hide_history(struct gui_ctx *ctx)
+void hide_history(struct gui_ctx *ctx)
{
input_pop();
@@ -473,7 +379,7 @@ static struct gui_hist *skip_history(struct gui_ctx *ctx, struct gui_hist *h)
static const struct input_ops history_input_ops;
-static void show_history(struct gui_ctx *ctx, enum selecting sel)
+void show_history(struct gui_ctx *ctx, enum selecting sel)
{
struct gui_hist *h = ctx->hist;
@@ -494,336 +400,6 @@ static void show_history(struct gui_ctx *ctx, enum selecting sel)
}
-static void show_history_cb(void *user)
-{
- struct gui_hist *h = user;
- struct gui_ctx *ctx = h->ctx;
- enum selecting sel = sel_only;
-
- if (ctx->old_hist)
- sel = h == ctx->new_hist ? sel_new : sel_old;
- show_history(ctx, sel);
-}
-
-
-/* ----- Navigate sheets --------------------------------------------------- */
-
-
-/* @@@ find a better place for this forward declaration */
-static void mark_aois(struct gui_ctx *ctx, struct gui_sheet *sheet);
-
-
-static void close_subsheet(void *user)
-{
- struct gui_sheet *sheet = user;
- struct gui_ctx *ctx = sheet->ctx;
-
- go_to_sheet(ctx, sheet);
-}
-
-
-static bool hover_sheet(void *user, bool on)
-{
- struct gui_sheet *sheet = user;
- struct gui_ctx *ctx = sheet->ctx;
- const char *title = sheet->sch->title;
-
- if (!title)
- title = "(unnamed)";
- if (on) {
- const struct gui_sheet *s;
- int n = 0, this = -1;
-
- for (s = ctx->new_hist->sheets; s; s = s->next) {
- n++;
- if (s == sheet)
- this = n;
- }
- overlay_text(sheet->over, "%s\n%d / %d",
- title, this, n);
- } else {
- overlay_text(sheet->over, "%s", title);
- }
- redraw(ctx);
- return 1;
-}
-
-
-static bool show_history_details(void *user, bool on)
-{
- struct gui_hist *h = user;
- struct gui_ctx *ctx = h->ctx;
- char *s;
-
- if (on) {
- s = vcs_git_long_for_pango(h->vcs_hist, fmt_pango);
- overlay_text_raw(h->over, s);
- free(s);
- } else {
- overlay_text(h->over, "%.40s", vcs_git_summary(h->vcs_hist));
- }
- redraw(ctx);
- return 1;
-}
-
-
-static void revision_overlays_diff(struct gui_ctx *ctx)
-{
- struct gui_hist *new = ctx->new_hist;
- struct gui_hist *old = ctx->old_hist;
-
- new->over = overlay_add(&ctx->hist_overlays, &ctx->aois,
- show_history_details, show_history_cb, new);
- overlay_style(new->over, &overlay_style_diff_new);
- show_history_details(new, 0);
-
- old->over = overlay_add(&ctx->hist_overlays, &ctx->aois,
- show_history_details, show_history_cb, old);
- overlay_style(old->over, &overlay_style_diff_old);
- show_history_details(old, 0);
-}
-
-
-static void do_revision_overlays(struct gui_ctx *ctx)
-{
- overlay_remove_all(&ctx->hist_overlays);
-
- if (ctx->old_hist) {
- revision_overlays_diff(ctx);
- } else {
- ctx->new_hist->over = overlay_add(&ctx->hist_overlays,
- &ctx->aois, show_history_details, show_history_cb,
- ctx->new_hist);
- overlay_style(ctx->new_hist->over, &overlay_style_default);
- show_history_details(ctx->new_hist, 0);
- }
-}
-
-
-static struct gui_sheet *find_parent_sheet(struct gui_sheet *sheets,
- const struct gui_sheet *ref)
-{
- struct gui_sheet *parent;
- const struct sch_obj *obj;
-
- for (parent = sheets; parent; parent = parent->next)
- for (obj = parent->sch->objs; obj; obj = obj->next)
- if (obj->type == sch_obj_sheet &&
- obj->u.sheet.sheet == ref->sch)
- return parent;
- return NULL;
-}
-
-
-static void sheet_selector_recurse(struct gui_ctx *ctx, struct gui_sheet *sheet)
-{
- struct gui_sheet *parent;
-
- parent = find_parent_sheet(ctx->new_hist->sheets, sheet);
- if (parent)
- sheet_selector_recurse(ctx, parent);
- sheet->over = overlay_add(&ctx->sheet_overlays, &ctx->aois,
- hover_sheet, close_subsheet, sheet);
- hover_sheet(sheet, 0);
-}
-
-
-static void do_sheet_overlays(struct gui_ctx *ctx)
-{
- overlay_remove_all(&ctx->sheet_overlays);
- sheet_selector_recurse(ctx, ctx->curr_sheet);
-}
-
-
-void go_to_sheet(struct gui_ctx *ctx, struct gui_sheet *sheet)
-{
- aoi_dehover();
- overlay_remove_all(&ctx->pop_overlays);
- if (!sheet->rendered) {
- render_sheet(sheet);
- mark_aois(ctx, sheet);
- }
- ctx->curr_sheet = sheet;
- if (ctx->old_hist)
- render_delta(ctx);
- if (ctx->vcs_hist)
- do_revision_overlays(ctx);
- do_sheet_overlays(ctx);
- zoom_to_extents(ctx);
-}
-
-
-static bool go_up_sheet(struct gui_ctx *ctx)
-{
- struct gui_sheet *parent;
-
- parent = find_parent_sheet(ctx->new_hist->sheets, ctx->curr_sheet);
- if (!parent)
- return 0;
- go_to_sheet(ctx, parent);
- return 1;
-}
-
-
-static bool go_prev_sheet(struct gui_ctx *ctx)
-{
- struct gui_sheet *sheet;
-
- for (sheet = ctx->new_hist->sheets; sheet; sheet = sheet->next)
- if (sheet->next && sheet->next == ctx->curr_sheet) {
- go_to_sheet(ctx, sheet);
- return 1;
- }
- return 0;
-}
-
-
-static bool go_next_sheet(struct gui_ctx *ctx)
-{
- if (!ctx->curr_sheet->next)
- return 0;
- go_to_sheet(ctx, ctx->curr_sheet->next);
- return 1;
-}
-
-
-/* ----- Input: sheet ------------------------------------------------------ */
-
-
-static bool sheet_click(void *user, int x, int y)
-{
- struct gui_ctx *ctx = user;
- const struct gui_sheet *curr_sheet = ctx->curr_sheet;
- int ex, ey;
-
- canvas_coord(ctx, x, y, &ex, &ey);
-
- if (aoi_click(ctx->aois, x, y))
- return 1;
- if (aoi_click(curr_sheet->aois,
- ex + curr_sheet->xmin, ey + curr_sheet->ymin))
- return 1;
-
- if (ctx->showing_history)
- hide_history(ctx);
- overlay_remove_all(&ctx->pop_overlays);
- redraw(ctx);
- return 1;
-}
-
-
-static bool sheet_hover_update(void *user, int x, int y)
-{
- struct gui_ctx *ctx = user;
- const struct gui_sheet *curr_sheet = ctx->curr_sheet;
- int ex, ey;
-
- canvas_coord(ctx, x, y, &ex, &ey);
-
- if (aoi_hover(ctx->aois, x, y))
- return 1;
- return aoi_hover(curr_sheet->aois,
- ex + curr_sheet->xmin, ey + curr_sheet->ymin);
-}
-
-
-static void sheet_hover_end(void *user)
-{
-}
-
-
-static bool sheet_drag_begin(void *user, int x, int y)
-{
- dehover_glabel(user);
- return 1;
-}
-
-
-static void sheet_drag_move(void *user, int dx, int dy)
-{
- struct gui_ctx *ctx = user;
-
- ctx->x -= dx << ctx->zoom;
- ctx->y -= dy << ctx->zoom;
- redraw(ctx);
-}
-
-
-static void sheet_scroll(void *user, int x, int y, int dy)
-{
- struct gui_ctx *ctx = user;
- int ex, ey;
-
- canvas_coord(ctx, x, y, &ex, &ey);
- if (dy < 0)
- zoom_in(ctx, ex, ey);
- else
- zoom_out(ctx, ex, ey);
-}
-
-
-static void sheet_key(void *user, int x, int y, int keyval)
-{
- struct gui_ctx *ctx = user;
- struct gui_sheet *sheet = ctx->curr_sheet;
- int ex, ey;
-
- canvas_coord(ctx, x, y, &ex, &ey);
-
- switch (keyval) {
- case '+':
- case '=':
- zoom_in(ctx, x, y);
- break;
- case '-':
- zoom_out(ctx, x, y);
- break;
- case '*':
- zoom_to_extents(ctx);
- break;
- case GDK_KEY_Home:
- if (sheet != ctx->new_hist->sheets)
- go_to_sheet(ctx, ctx->new_hist->sheets);
- break;
- case GDK_KEY_BackSpace:
- case GDK_KEY_Delete:
- go_up_sheet(ctx);
- break;
- case GDK_KEY_Page_Up:
- case GDK_KEY_KP_Page_Up:
- go_prev_sheet(ctx);
- break;
- case GDK_KEY_Page_Down:
- case GDK_KEY_KP_Page_Down:
- go_next_sheet(ctx);
- break;
- case GDK_KEY_Up:
- case GDK_KEY_KP_Up:
- show_history(ctx, sel_new);
- break;
- case GDK_KEY_Down:
- case GDK_KEY_KP_Down:
- show_history(ctx, sel_old);
- break;
- case GDK_KEY_q:
- gtk_main_quit();
- }
-}
-
-
-static const struct input_ops sheet_input_ops = {
- .click = sheet_click,
- .hover_begin = sheet_hover_update,
- .hover_update = sheet_hover_update,
- .hover_click = sheet_click,
- .hover_end = sheet_hover_end,
- .scroll = sheet_scroll,
- .drag_begin = sheet_drag_begin,
- .drag_move = sheet_drag_move,
- .key = sheet_key,
-};
-
-
/* ----- Input: history ---------------------------------------------------- */
@@ -844,26 +420,12 @@ static const struct input_ops history_input_ops = {
.hover_begin = sheet_hover_update,
.hover_update = sheet_hover_update,
.hover_click = sheet_click,
- .hover_end = sheet_hover_end,
- .scroll = sheet_scroll,
.drag_begin = input_accept,
.drag_move = history_drag_move,
.key = sheet_key,
};
-/* ----- Event handlers ---------------------------------------------------- */
-
-
-static void size_allocate_event(GtkWidget *widget, GdkRectangle *allocation,
- gpointer data)
-{
- struct gui_ctx *ctx = data;
-
- zoom_to_extents(ctx);
-}
-
-
/* ----- AoI callbacks ----------------------------------------------------- */
@@ -915,7 +477,7 @@ static void add_sheet_aoi(struct gui_ctx *ctx, struct gui_sheet *parent,
}
-static void mark_aois(struct gui_ctx *ctx, struct gui_sheet *sheet)
+void mark_aois(struct gui_ctx *ctx, struct gui_sheet *sheet)
{
const struct sch_obj *obj;
@@ -1197,19 +759,17 @@ int gui(unsigned n_args, char **args, bool recurse, int limit)
g_signal_connect(G_OBJECT(ctx.da), "draw",
G_CALLBACK(on_draw_event), &ctx);
- g_signal_connect(G_OBJECT(ctx.da), "size_allocate",
- G_CALLBACK(size_allocate_event), &ctx);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
+ sheet_setup(&ctx);
+
// gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
go_to_sheet(&ctx, ctx.new_hist->sheets);
gtk_widget_show_all(window);
- input_push(&sheet_input_ops, &ctx);
-
/* for performance testing, use -N-depth */
if (limit >= 0)
gtk_main();
diff --git a/eeshow/gui/sheet.c b/eeshow/gui/sheet.c
new file mode 100644
index 0000000..ca21cc0
--- /dev/null
+++ b/eeshow/gui/sheet.c
@@ -0,0 +1,459 @@
+/*
+ * gui/sheet.c - Sheet navigation
+ *
+ * Written 2016 by Werner Almesberger
+ * Copyright 2016 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
+
+#include
+
+#include "file/git-hist.h"
+#include "kicad/sch.h"
+#include "kicad/delta.h"
+#include "gui/fmt-pango.h"
+#include "gui/style.h"
+#include "gui/aoi.h"
+#include "gui/over.h"
+#include "gui/input.h"
+#include "gui/common.h"
+
+
+/* ----- Tools ------------------------------------------------------------- */
+
+
+static void canvas_coord(const struct gui_ctx *ctx,
+ int ex, int ey, int *x, int *y)
+{
+ GtkAllocation alloc;
+ int sx, sy;
+
+ 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;
+}
+
+
+/* ----- 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;
+ redraw(ctx);
+}
+
+
+static void zoom_out(struct gui_ctx *ctx, int x, int y)
+{
+ if (ctx->curr_sheet->w >> ctx->zoom <= 16)
+ return;
+ ctx->zoom++;
+ ctx->x = 2 * ctx->x - x;
+ ctx->y = 2 * ctx->y - y;
+ redraw(ctx);
+}
+
+
+static void curr_sheet_size(struct gui_ctx *ctx, int *w, int *h)
+{
+ const struct gui_sheet *sheet = ctx->curr_sheet;
+ int ax1, ay1, bx1, by1;
+
+ if (!ctx->old_hist) {
+ *w = sheet->w;
+ *h = sheet->h;
+ } else {
+ const struct gui_sheet *old =
+ find_corresponding_sheet(ctx->old_hist->sheets,
+ ctx->new_hist->sheets, sheet);
+
+ /*
+ * We're only interested in differences here, so no need for
+ * the usual "-1" in x1 = x0 + w - 1
+ */
+ ax1 = sheet->xmin + sheet->w;
+ ay1 = sheet->ymin + sheet->h;
+ bx1 = old->xmin + old->w;
+ by1 = old->ymin + old->h;
+ *w = (ax1 > bx1 ? ax1 : bx1) -
+ (sheet->xmin < old->xmin ? sheet->xmin : old->xmin);
+ *h = (ay1 > by1 ? ay1 : by1) -
+ (sheet->ymin < old->ymin ? sheet->ymin : old->ymin);
+ }
+}
+
+
+static void zoom_to_extents(struct gui_ctx *ctx)
+{
+ GtkAllocation alloc;
+ int w, h;
+
+ curr_sheet_size(ctx, &w, &h);
+ ctx->x = w / 2;
+ ctx->y = h / 2;
+
+ gtk_widget_get_allocation(ctx->da, &alloc);
+ ctx->zoom = 0;
+ while (w >> ctx->zoom > alloc.width || h >> ctx->zoom > alloc.height)
+ ctx->zoom++;
+
+ redraw(ctx);
+}
+
+
+/* ----- Navigate sheets --------------------------------------------------- */
+
+
+static void close_subsheet(void *user)
+{
+ struct gui_sheet *sheet = user;
+ struct gui_ctx *ctx = sheet->ctx;
+
+ go_to_sheet(ctx, sheet);
+}
+
+
+static bool hover_sheet(void *user, bool on)
+{
+ struct gui_sheet *sheet = user;
+ struct gui_ctx *ctx = sheet->ctx;
+ const char *title = sheet->sch->title;
+
+ if (!title)
+ title = "(unnamed)";
+ if (on) {
+ const struct gui_sheet *s;
+ int n = 0, this = -1;
+
+ for (s = ctx->new_hist->sheets; s; s = s->next) {
+ n++;
+ if (s == sheet)
+ this = n;
+ }
+ overlay_text(sheet->over, "%s\n%d / %d",
+ title, this, n);
+ } else {
+ overlay_text(sheet->over, "%s", title);
+ }
+ redraw(ctx);
+ return 1;
+}
+
+
+static bool show_history_details(void *user, bool on)
+{
+ struct gui_hist *h = user;
+ struct gui_ctx *ctx = h->ctx;
+ char *s;
+
+ if (on) {
+ s = vcs_git_long_for_pango(h->vcs_hist, fmt_pango);
+ overlay_text_raw(h->over, s);
+ free(s);
+ } else {
+ overlay_text(h->over, "%.40s", vcs_git_summary(h->vcs_hist));
+ }
+ redraw(ctx);
+ return 1;
+}
+
+
+static void show_history_cb(void *user)
+{
+ struct gui_hist *h = user;
+ struct gui_ctx *ctx = h->ctx;
+ enum selecting sel = sel_only;
+
+ if (ctx->old_hist)
+ sel = h == ctx->new_hist ? sel_new : sel_old;
+ show_history(ctx, sel);
+}
+
+
+static void revision_overlays_diff(struct gui_ctx *ctx)
+{
+ struct gui_hist *new = ctx->new_hist;
+ struct gui_hist *old = ctx->old_hist;
+
+ new->over = overlay_add(&ctx->hist_overlays, &ctx->aois,
+ show_history_details, show_history_cb, new);
+ overlay_style(new->over, &overlay_style_diff_new);
+ show_history_details(new, 0);
+
+ old->over = overlay_add(&ctx->hist_overlays, &ctx->aois,
+ show_history_details, show_history_cb, old);
+ overlay_style(old->over, &overlay_style_diff_old);
+ show_history_details(old, 0);
+}
+
+
+void do_revision_overlays(struct gui_ctx *ctx)
+{
+ overlay_remove_all(&ctx->hist_overlays);
+
+ if (ctx->old_hist) {
+ revision_overlays_diff(ctx);
+ } else {
+ ctx->new_hist->over = overlay_add(&ctx->hist_overlays,
+ &ctx->aois, show_history_details, show_history_cb,
+ ctx->new_hist);
+ overlay_style(ctx->new_hist->over, &overlay_style_default);
+ show_history_details(ctx->new_hist, 0);
+ }
+}
+
+
+static struct gui_sheet *find_parent_sheet(struct gui_sheet *sheets,
+ const struct gui_sheet *ref)
+{
+ struct gui_sheet *parent;
+ const struct sch_obj *obj;
+
+ for (parent = sheets; parent; parent = parent->next)
+ for (obj = parent->sch->objs; obj; obj = obj->next)
+ if (obj->type == sch_obj_sheet &&
+ obj->u.sheet.sheet == ref->sch)
+ return parent;
+ return NULL;
+}
+
+
+static void sheet_selector_recurse(struct gui_ctx *ctx, struct gui_sheet *sheet)
+{
+ struct gui_sheet *parent;
+
+ parent = find_parent_sheet(ctx->new_hist->sheets, sheet);
+ if (parent)
+ sheet_selector_recurse(ctx, parent);
+ sheet->over = overlay_add(&ctx->sheet_overlays, &ctx->aois,
+ hover_sheet, close_subsheet, sheet);
+ hover_sheet(sheet, 0);
+}
+
+
+static void do_sheet_overlays(struct gui_ctx *ctx)
+{
+ overlay_remove_all(&ctx->sheet_overlays);
+ sheet_selector_recurse(ctx, ctx->curr_sheet);
+}
+
+
+void go_to_sheet(struct gui_ctx *ctx, struct gui_sheet *sheet)
+{
+ aoi_dehover();
+ overlay_remove_all(&ctx->pop_overlays);
+ if (!sheet->rendered) {
+ render_sheet(sheet);
+ mark_aois(ctx, sheet);
+ }
+ ctx->curr_sheet = sheet;
+ if (ctx->old_hist)
+ render_delta(ctx);
+ if (ctx->vcs_hist)
+ do_revision_overlays(ctx);
+ do_sheet_overlays(ctx);
+ zoom_to_extents(ctx);
+}
+
+
+static bool go_up_sheet(struct gui_ctx *ctx)
+{
+ struct gui_sheet *parent;
+
+ parent = find_parent_sheet(ctx->new_hist->sheets, ctx->curr_sheet);
+ if (!parent)
+ return 0;
+ go_to_sheet(ctx, parent);
+ return 1;
+}
+
+
+static bool go_prev_sheet(struct gui_ctx *ctx)
+{
+ struct gui_sheet *sheet;
+
+ for (sheet = ctx->new_hist->sheets; sheet; sheet = sheet->next)
+ if (sheet->next && sheet->next == ctx->curr_sheet) {
+ go_to_sheet(ctx, sheet);
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool go_next_sheet(struct gui_ctx *ctx)
+{
+ if (!ctx->curr_sheet->next)
+ return 0;
+ go_to_sheet(ctx, ctx->curr_sheet->next);
+ return 1;
+}
+
+
+/* ----- Input ------------------------------------------------------------- */
+
+
+bool sheet_click(void *user, int x, int y)
+{
+ struct gui_ctx *ctx = user;
+ const struct gui_sheet *curr_sheet = ctx->curr_sheet;
+ int ex, ey;
+
+ canvas_coord(ctx, x, y, &ex, &ey);
+
+ if (aoi_click(ctx->aois, x, y))
+ return 1;
+ if (aoi_click(curr_sheet->aois,
+ ex + curr_sheet->xmin, ey + curr_sheet->ymin))
+ return 1;
+
+ if (ctx->showing_history)
+ hide_history(ctx);
+ overlay_remove_all(&ctx->pop_overlays);
+ redraw(ctx);
+ return 1;
+}
+
+
+bool sheet_hover_update(void *user, int x, int y)
+{
+ struct gui_ctx *ctx = user;
+ const struct gui_sheet *curr_sheet = ctx->curr_sheet;
+ int ex, ey;
+
+ canvas_coord(ctx, x, y, &ex, &ey);
+
+ if (aoi_hover(ctx->aois, x, y))
+ return 1;
+ return aoi_hover(curr_sheet->aois,
+ ex + curr_sheet->xmin, ey + curr_sheet->ymin);
+}
+
+
+static bool sheet_drag_begin(void *user, int x, int y)
+{
+ dehover_glabel(user);
+ return 1;
+}
+
+
+static void sheet_drag_move(void *user, int dx, int dy)
+{
+ struct gui_ctx *ctx = user;
+
+ ctx->x -= dx << ctx->zoom;
+ ctx->y -= dy << ctx->zoom;
+ redraw(ctx);
+}
+
+
+static void sheet_scroll(void *user, int x, int y, int dy)
+{
+ struct gui_ctx *ctx = user;
+ int ex, ey;
+
+ canvas_coord(ctx, x, y, &ex, &ey);
+ if (dy < 0)
+ zoom_in(ctx, ex, ey);
+ else
+ zoom_out(ctx, ex, ey);
+}
+
+
+void sheet_key(void *user, int x, int y, int keyval)
+{
+ struct gui_ctx *ctx = user;
+ struct gui_sheet *sheet = ctx->curr_sheet;
+ int ex, ey;
+
+ canvas_coord(ctx, x, y, &ex, &ey);
+
+ switch (keyval) {
+ case '+':
+ case '=':
+ zoom_in(ctx, x, y);
+ break;
+ case '-':
+ zoom_out(ctx, x, y);
+ break;
+ case '*':
+ zoom_to_extents(ctx);
+ break;
+ case GDK_KEY_Home:
+ if (sheet != ctx->new_hist->sheets)
+ go_to_sheet(ctx, ctx->new_hist->sheets);
+ break;
+ case GDK_KEY_BackSpace:
+ case GDK_KEY_Delete:
+ go_up_sheet(ctx);
+ break;
+ case GDK_KEY_Page_Up:
+ case GDK_KEY_KP_Page_Up:
+ go_prev_sheet(ctx);
+ break;
+ case GDK_KEY_Page_Down:
+ case GDK_KEY_KP_Page_Down:
+ go_next_sheet(ctx);
+ break;
+ case GDK_KEY_Up:
+ case GDK_KEY_KP_Up:
+ show_history(ctx, sel_new);
+ break;
+ case GDK_KEY_Down:
+ case GDK_KEY_KP_Down:
+ show_history(ctx, sel_old);
+ break;
+ case GDK_KEY_q:
+ gtk_main_quit();
+ }
+}
+
+
+static const struct input_ops sheet_input_ops = {
+ .click = sheet_click,
+ .hover_begin = sheet_hover_update,
+ .hover_update = sheet_hover_update,
+ .hover_click = sheet_click,
+ .scroll = sheet_scroll,
+ .drag_begin = sheet_drag_begin,
+ .drag_move = sheet_drag_move,
+ .key = sheet_key,
+};
+
+
+/* ----- Event handlers ---------------------------------------------------- */
+
+
+static void size_allocate_event(GtkWidget *widget, GdkRectangle *allocation,
+ gpointer data)
+{
+ struct gui_ctx *ctx = data;
+
+ zoom_to_extents(ctx);
+}
+
+
+/* ----- Initialization ---------------------------------------------------- */
+
+
+void sheet_setup(struct gui_ctx *ctx)
+{
+ g_signal_connect(G_OBJECT(ctx->da), "size_allocate",
+ G_CALLBACK(size_allocate_event), &ctx);
+ input_push(&sheet_input_ops, ctx);
+}