diff --git a/Makefile b/Makefile index c3ae0d7..bb2c6ad 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ # (at your option) any later version. # -OBJS = fped.o expr.o coord.o obj.o inst.o util.o error.o \ +OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \ unparse.o \ cpp.o lex.yy.o y.tab.o \ gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \ diff --git a/README b/README index b2c4987..7075423 100644 --- a/README +++ b/README @@ -348,9 +348,11 @@ GUI Keys: -space reset user coordinates +Space reset user coordinates +, = zoom in (like mouse wheel forward) - zoom out (like mouse wheel backward) . cursor position to screen center (like middle click) * zoom and center to extents # zoom and center to currently active frame instance +Delete delete the currently selected object +U undelete the previously deleted object diff --git a/TODO b/TODO index 4edddba..505a048 100644 --- a/TODO +++ b/TODO @@ -19,6 +19,7 @@ Style: Bugs: - default silk width has no business being hard-coded in obj.c - after moving, arc sometimes wrap the wrong way +- undelete only works if not much has changed since the deletion Code cleanup: - merge edit_unique with edit_name @@ -26,7 +27,6 @@ Code cleanup: - add regression tests Open decisions: -- decide on table presentation (merge frame and vars into single entity ?) - Q: should loop be (start, last) or (start, iterations) ? or start ... last ? - change vector circle color ? (also, highlight on hover ?) - Q: allow reassignment of vector names ? diff --git a/delete.c b/delete.c new file mode 100644 index 0000000..4c8b93b --- /dev/null +++ b/delete.c @@ -0,0 +1,286 @@ +/* + * delete.c - Object deletion + * + * Written 2009 by Werner Almesberger + * Copyright 2009 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 "util.h" +#include "error.h" +#include "expr.h" +#include "obj.h" +#include "delete.h" + + +static struct deletion { + enum del_type { + dt_vec, + dt_obj, + } type; + union { + struct { + struct vec *ref; + struct vec *prev; + } vec; + struct { + struct obj *ref; + struct obj *prev; + } obj; + } u; + struct deletion *next; +} *deletions = NULL; + + +static struct deletion *new_deletion(enum del_type type) +{ + struct deletion *del; + + del = alloc_type(struct deletion); + del->type = type; + del->next = deletions; + deletions = del; + return del; +} + + +/* ----- vectors ----------------------------------------------------------- */ + + +static void dereference_vec(struct vec *vec) +{ + assert(!vec->n_refs); + put_vec(vec->base); +} + + +static void destroy_vec(struct vec *vec) +{ + assert(!vec->n_refs); + free_expr(vec->x); + free_expr(vec->y); + free(vec); +} + + +static void rereference_vec(struct vec *vec) +{ + get_vec(vec->base); +} + + +int delete_vec(struct vec *vec) +{ + struct vec *walk, *prev; + struct deletion *del; + + if (vec->n_refs) { + fail("vector has %d reference%s", vec->n_refs, + vec->n_refs == 1 ? "" : "s"); + return 0; + } + prev = NULL; + for (walk = vec->frame->vecs; walk != vec; walk = walk->next) + prev = walk; + if (prev) + prev->next = vec->next; + else + vec->frame->vecs = vec->next; + dereference_vec(vec); + del = new_deletion(dt_vec); + del->u.vec.ref = vec; + del->u.vec.prev = prev; + return 1; +} + + +static void undelete_vec(struct vec *vec, struct vec *prev) +{ + if (prev) { + assert(vec->next == prev->next); + prev->next = vec; + } else { + assert(vec->next == vec->frame->vecs); + vec->frame->vecs = vec; + } + rereference_vec(vec); +} + + +/* ----- objects ----------------------------------------------------------- */ + + +static void dereference_obj(struct obj *obj) +{ + switch (obj->type) { + case ot_frame: + /* nothing */ + break; + case ot_pad: + put_vec(obj->u.pad.other); + break; + case ot_line: + put_vec(obj->u.line.other); + break; + case ot_rect: + put_vec(obj->u.rect.other); + break; + case ot_arc: + put_vec(obj->u.arc.start); + put_vec(obj->u.arc.end); + break; + case ot_meas: + put_vec(obj->u.meas.other); + break; + default: + abort(); + } + put_vec(obj->base); +} + + +static void destroy_obj(struct obj *obj) +{ + switch (obj->type) { + case ot_frame: + /* nothing */ + break; + case ot_pad: + free(obj->u.pad.name); + break; + case ot_line: + free_expr(obj->u.line.width); + break; + case ot_rect: + free_expr(obj->u.rect.width); + break; + case ot_arc: + free_expr(obj->u.arc.width); + break; + case ot_meas: + free_expr(obj->u.meas.offset); + break; + default: + abort(); + } + free(obj); +} + + +static void rereference_obj(struct obj *obj) +{ + switch (obj->type) { + case ot_frame: + /* nothing */ + break; + case ot_pad: + get_vec(obj->u.pad.other); + break; + case ot_line: + get_vec(obj->u.line.other); + break; + case ot_rect: + get_vec(obj->u.rect.other); + break; + case ot_arc: + get_vec(obj->u.arc.start); + get_vec(obj->u.arc.end); + break; + case ot_meas: + get_vec(obj->u.meas.other); + break; + default: + abort(); + } + get_vec(obj->base); +} + + +int delete_obj(struct obj *obj) +{ + struct obj *walk, *prev; + struct deletion *del; + + prev = NULL; + for (walk = obj->frame->objs; walk != obj; walk = walk->next) + prev = walk; + if (prev) + prev->next = obj->next; + else + obj->frame->objs = obj->next; + dereference_obj(obj); + del = new_deletion(dt_obj); + del->u.obj.ref = obj; + del->u.obj.prev = prev; + return 1; +} + + +static void undelete_obj(struct obj *obj, struct obj *prev) +{ + if (prev) { + assert(obj->next == prev->next); + prev->next = obj; + } else { + assert(obj->next == obj->frame->objs); + obj->frame->objs = obj; + } + rereference_obj(obj); +} + + +/* ----- destroy/undelete interface ---------------------------------------- */ + + +int destroy(void) +{ + struct deletion *del; + + if (!deletions) + return 0; + del = deletions; + switch (del->type) { + case dt_vec: + destroy_vec(del->u.vec.ref); + break; + case dt_obj: + destroy_obj(del->u.obj.ref); + break; + default: + abort(); + } + deletions = del->next; + free(del); + return 1; +} + + +int undelete(void) +{ + struct deletion *del; + + if (!deletions) + return 0; + del = deletions; + switch (del->type) { + case dt_vec: + undelete_vec(del->u.vec.ref, del->u.vec.prev); + break; + case dt_obj: + undelete_obj(del->u.obj.ref, del->u.obj.prev); + break; + default: + abort(); + } + deletions = del->next; + free(del); + return 1; +} diff --git a/delete.h b/delete.h new file mode 100644 index 0000000..993a664 --- /dev/null +++ b/delete.h @@ -0,0 +1,26 @@ +/* + * delete.h - Object deletion + * + * Written 2009 by Werner Almesberger + * Copyright 2009 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 DELETE_H +#define DELETE_H + + +#include "obj.h" + + +int delete_vec(struct vec *vec); +int delete_obj(struct obj *obj); +int destroy(void); +int undelete(void); + +#endif /* !OBJ_H */ diff --git a/fpd.y b/fpd.y index 84e5b2a..cdc2338 100644 --- a/fpd.y +++ b/fpd.y @@ -117,6 +117,7 @@ static struct obj *new_obj(enum obj_type type) obj = alloc_type(struct obj); obj->type = type; + obj->frame = curr_frame; obj->next = NULL; return obj; } diff --git a/gui_canvas.c b/gui_canvas.c index 3736ffd..07c5605 100644 --- a/gui_canvas.c +++ b/gui_canvas.c @@ -13,8 +13,10 @@ #include #include +#include #include "obj.h" +#include "delete.h" #include "inst.h" #include "gui_inst.h" #include "gui_style.h" @@ -29,6 +31,7 @@ static struct coord curr_pos; static struct coord user_origin = { 0, 0 }; static int dragging = 0; +static int drag_escaped = 0; /* 1 once we've made is out of the drag radius */ static struct coord drag_start; @@ -111,9 +114,11 @@ static void drag_left(struct coord pos) { if (!dragging) return; - if (hypot(pos.x-drag_start.x, pos.y-drag_start.y)/ctx.scale < + if (!drag_escaped && + hypot(pos.x-drag_start.x, pos.y-drag_start.y)/ctx.scale < DRAG_MIN_R) return; + drag_escaped = 1; tool_drag(&ctx, pos); } @@ -159,6 +164,7 @@ static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, } if (tool_consider_drag(&ctx, pos)) { dragging = 1; + drag_escaped = 0; drag_start = pos; break; } @@ -283,6 +289,16 @@ static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, ctx.center = pos; redraw(); break; + case GDK_BackSpace: + case GDK_Delete: + case GDK_KP_Delete: + if (selected_inst && inst_delete(selected_inst)) + change_world(); + break; + case 'u': + if (undelete()) + change_world(); + break; } return TRUE; } diff --git a/inst.c b/inst.c index 10bfd2a..a62b196 100644 --- a/inst.c +++ b/inst.c @@ -19,6 +19,7 @@ #include "coord.h" #include "expr.h" #include "obj.h" +#include "delete.h" #include "gui_status.h" #include "gui_tools.h" #include "gui_inst.h" @@ -740,12 +741,13 @@ static struct inst_ops frame_ops = { }; -void inst_begin_frame(const struct frame *frame, struct coord base, - int active, int is_active_frame) +void inst_begin_frame(struct obj *obj, const struct frame *frame, + struct coord base, int active, int is_active_frame) { struct inst *inst; inst = add_inst(&frame_ops, ip_frame, base); + inst->obj = obj; inst->u.frame.ref = frame; inst->u.frame.active = is_active_frame; inst->active = active; @@ -865,6 +867,13 @@ void inst_hover(struct inst *inst, struct draw_ctx *ctx, int on) } +int inst_delete(struct inst *inst) +{ + return inst->ops == &vec_ops ? + delete_vec(inst->vec) : delete_obj(inst->obj); +} + + void inst_debug(void) { enum inst_prio prio; diff --git a/inst.h b/inst.h index 4b98077..0c1a006 100644 --- a/inst.h +++ b/inst.h @@ -102,8 +102,8 @@ int inst_meas(struct obj *obj, struct coord from, struct coord to, void inst_begin_active(int active); void inst_end_active(void); -void inst_begin_frame(const struct frame *frame, struct coord base, - int active, int is_active_frame); +void inst_begin_frame(struct obj *obj, const struct frame *frame, + struct coord base, int active, int is_active_frame); void inst_end_frame(const struct frame *frame); struct bbox inst_get_bbox(void); @@ -117,6 +117,7 @@ struct pix_buf *inst_draw_move(struct inst *inst, struct draw_ctx *ctx, struct coord pos, int i); int inst_do_move_to(struct inst *inst, struct vec *vec, int i); void inst_hover(struct inst *inst, struct draw_ctx *ctx, int on); +int inst_delete(struct inst *inst); void inst_debug(void); #endif /* !INST_H */ diff --git a/obj.c b/obj.c index a4ce533..069cfde 100644 --- a/obj.c +++ b/obj.c @@ -33,7 +33,7 @@ struct frame *active_frame = NULL; static int generate_frame(struct frame *frame, struct coord base, - const struct frame *parent, int active); + const struct frame *parent, struct obj *frame_ref, int active); static struct num eval_unit(const struct expr *expr, const struct frame *frame) @@ -93,7 +93,7 @@ static int generate_objs(struct frame *frame, struct coord base, int active) switch (obj->type) { case ot_frame: if (!generate_frame(obj->u.frame.ref, - obj->base ? obj->base->pos : base, frame, + obj->base ? obj->base->pos : base, frame, obj, active && obj->u.frame.ref->active_ref == obj)) return 0; break; @@ -237,14 +237,14 @@ static int iterate_tables(struct frame *frame, struct table *table, static int generate_frame(struct frame *frame, struct coord base, - const struct frame *parent, int active) + const struct frame *parent, struct obj *frame_ref, int active) { int ok; /* * We ensure during construction that frames can never recurse. */ - inst_begin_frame(frame, base, + inst_begin_frame(frame_ref, frame, base, active && parent == active_frame, active && frame == active_frame); frame->curr_parent = parent; @@ -260,7 +260,7 @@ int instantiate(void) int ok; inst_start(); - ok = generate_frame(root_frame, zero, NULL, 1); + ok = generate_frame(root_frame, zero, NULL, NULL, 1); if (ok) inst_commit(); else diff --git a/obj.h b/obj.h index 0e30b58..19461d7 100644 --- a/obj.h +++ b/obj.h @@ -14,6 +14,7 @@ #ifndef OBJ_H #define OBJ_H +#include #include #include "expr.h" @@ -161,6 +162,7 @@ struct obj { struct arc arc; struct meas meas; } u; + struct frame *frame; struct vec *base; struct obj *next; int lineno; @@ -180,6 +182,15 @@ static inline struct vec *get_vec(struct vec *vec) } +static inline void put_vec(struct vec *vec) +{ + if (vec) { + assert(vec->n_refs); + vec->n_refs--; + } +} + + int instantiate(void); #endif /* !OBJ_H */