From ff8969caf54050c3b89c910077a9db72ca915238 Mon Sep 17 00:00:00 2001 From: Ivica Ico Bukvic <ico@vt.edu> Date: Sun, 11 Dec 2011 13:04:52 -0500 Subject: [PATCH] preliminary addition of the infinite undo framework with debugging output --- src/g_canvas.c | 49 +++++++------------------------------ src/g_canvas.h | 9 ++++--- src/g_editor.c | 1 + src/g_undo.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ src/g_undo.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++ src/makefile.in | 2 +- 6 files changed, 142 insertions(+), 45 deletions(-) create mode 100644 src/g_undo.c create mode 100644 src/g_undo.h diff --git a/src/g_canvas.c b/src/g_canvas.c index 2589f47cb..17c2acc15 100644 --- a/src/g_canvas.c +++ b/src/g_canvas.c @@ -348,37 +348,7 @@ void glist_init(t_glist *x) tells us which.) */ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) { - /* first alloc one byte or redundant memory to prevent creation of objects with the same "name" - which leads to double-action invoked from every single action and eventually possible crashes - - we keep a list of these redundant allocations and destroy them when pd quits */ - //if (x->gl_owner && x->gl_env) { -/* - t_redundant_mem *new_rm = (t_redundant_mem *)t_getbytes(sizeof(*new_rm)); - new_rm->rm_what = (int)getbytes(1); - if (rm_start == NULL) { - //fprintf(stderr,"first allocation\n"); - rm_start = new_rm; - rm_end = new_rm; - } - else if (rm_start == rm_end) { - //fprintf(stderr,"second allocation\n"); - rm_end = new_rm; - rm_start->rm_next = rm_end; - } - else { - //fprintf(stderr,"allocation\n"); - rm_end->rm_next = new_rm; - rm_end = new_rm; - } -*/ - //} - t_canvas *x = (t_canvas *)pd_new(canvas_class); - - /* now that we've created a new canvas, add canvas info to the new_rm */ - //new_rm->rm_canvas = x; - t_canvas *owner = canvas_getcurrent(); t_symbol *s = &s_; int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT; @@ -386,15 +356,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) int font = (owner ? owner->gl_font : sys_defaultfont); glist_init(x); - // jsarlo x->gl_magic_glass = magicGlass_new(x); - // end jsarlo - - //if we are root canvas set the clock for script based destructor of the window - //if (!owner) { - // x->gl_destroy = clock_new(x, (t_method)canvas_manual_pd_free); - //} - x->gl_obj.te_type = T_OBJECT; if (!owner) canvas_addtolist(x); @@ -452,7 +414,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) if (strcmp(x->gl_name->s_name, "Pd")) pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name)); x->gl_loading = 1; - //fprintf(stderr,"loading = 1 .x%lx owner=.x%lx\n", x, x->gl_owner); + //fprintf(stderr,"loading = 1 .x%lx owner=.x%lx\n", (t_int)x, (t_int)x->gl_owner); x->gl_goprect = 0; /* no GOP rectangle unless it's turned on later */ /* cancel "vis" flag if we're a subpatch of an abstraction inside another patch. A separate mechanism prevents @@ -471,7 +433,8 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) x->gl_font = sys_nearestfontsize(font); pd_pushsym(&x->gl_pd); -/* ---------- dpsaha@vt.edu gop resize -------------------------------- */ + //dpsaha@vt.edu gop resize + //resize blob t_scalehandle *sh; char buf[64]; @@ -501,7 +464,9 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) x->move_offset_x = 0; x->move_offset_y = 0; x->move_vis = 0; -/*------------------------------------------------------------- */ + + //TODO: figure out why pd creates 2 invisible canvases at start-up + x->u_queue = canvas_undo_init(x); return(x); } @@ -912,6 +877,8 @@ void canvas_free(t_canvas *x) magicGlass_free(x->gl_magic_glass); canvas_noundo(x); + canvas_undo_free(x); + if (canvas_editing == x) canvas_editing = 0; if (canvas_whichfind == x) diff --git a/src/g_canvas.h b/src/g_canvas.h index 6344bfdbd..b7e5881ba 100644 --- a/src/g_canvas.h +++ b/src/g_canvas.h @@ -167,6 +167,8 @@ area of a window. */ +#include "g_undo.h" + struct _glist { t_object gl_obj; /* header in case we're a glist */ @@ -210,10 +212,7 @@ struct _glist unsigned int gl_isgraph:1; /* show as graph on parent */ unsigned int gl_hidetext:1; /* hide object-name + args when doing graph on parent */ unsigned int gl_gop_initialized:1; /* used for tagged moving of gop-ed objects to avoid redundant reinit */ - // jsarlo t_magicGlass *gl_magic_glass; /* magic glass object */ - // end jsarlo - //t_clock *gl_destroy; /* for script-based closing of the patch */ //dpsaha@vt.edu for the gop dynamic resizing t_pd *x_handle; @@ -226,6 +225,10 @@ struct _glist int move_offset_x; int move_offset_y; int move_vis; + + //infinite undo goodies + t_undo_action *u_queue; + t_undo_action *u_last; }; #define gl_gobj gl_obj.te_g diff --git a/src/g_editor.c b/src/g_editor.c index f8e24f44a..0c5addde9 100644 --- a/src/g_editor.c +++ b/src/g_editor.c @@ -9,6 +9,7 @@ #include "s_stuff.h" #include "g_magicglass.h" #include "g_canvas.h" +#include "g_undo.h" #include <string.h> void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, diff --git a/src/g_undo.c b/src/g_undo.c new file mode 100644 index 000000000..a634a6b55 --- /dev/null +++ b/src/g_undo.c @@ -0,0 +1,64 @@ +#include "m_pd.h" +#include "g_canvas.h" +#include <stdio.h> + +t_undo_action *canvas_undo_init(t_canvas *x) +{ + t_undo_action *a = (t_undo_action *)getbytes(sizeof(*a)); + + if (!x->u_queue) { + //this is the first init + a->type = 0; + a->x = x; + a->prev = NULL; + a->next = NULL; + x->u_queue = a; + x->u_last = a; + } + fprintf(stderr,"canvas_undo_init\n"); + return(a); +} + +t_undo_action *canvas_undo_add(t_canvas *x) +{ + t_undo_action *a; + return(a); +} + +void canvas_undo_undo(t_canvas *x) +{ + +} + +void canvas_undo_redo(t_canvas *x) +{ + +} + +void canvas_undo_rebranch(t_undo_action *u) +{ + +} + +void canvas_undo_check_canvas_pointers(t_canvas *x) +{ + +} + +void canvas_undo_purge_abstraction_actions(t_canvas *x) +{ + +} + +void canvas_undo_free(t_canvas *x) +{ + fprintf(stderr,"canvas_undo_free\n"); + if (x->u_queue) { + t_undo_action *a; + for(a = x->u_queue; a; a = a->next) { + fprintf(stderr,"freeing t_undo_action queue member\n"); + freebytes(a, sizeof(*a)); + } + } +} + diff --git a/src/g_undo.h b/src/g_undo.h new file mode 100644 index 000000000..0606c8f46 --- /dev/null +++ b/src/g_undo.h @@ -0,0 +1,62 @@ + +#ifndef __g_undo_h_ +#define __g_undo_h_ + +/* +Infinite undo by Ivica Ico Bukvic <ico@vt.edu> Dec. 2011 + +This is the home of infinite undo queue. Each root canvas has one of these. +Only canvas that is root will instantiate the pointer to t_undo_action struct. +All sub-canvases (including abstractions) will be linked to the root window. +Once the root window is destroyed, so is its undo queue. Each canvas (t_glist) +defined in g_canvas.h now also has information on t_undo_action queue and a +pointer to the last item in the doubly-linked list (queue). + +First initialized undo is never filled (it is of a type 0). First (new) action +creates another t_undo_action and saves its contents there and updates "last" +pointer inside the t_canvas (t_glist). + +t_undo_action requires canvas information in case we've deleted a canvas and +then undoed its deletion which will in effect change its pointer (memory +location). Then we need to call check_canvas_pointers to update all of the old +(stale) undo actions to corresepond with the new memory location. + +What about abstractions? Once they are recreated (e.g. after delete, followed +by an undo) all undo actions (except for its deletion in the parent window should +be purged since abstraction's state will now default to its original (saved) state. + +Types of undo data: +0 - init data (start of the queue) +1 - connect & disconnect +2 - cut, clear & typing into objects +3 - motion, inclding "tidy up" and stretching +4 - paste & duplicate +5 - apply +6 - arrange (to front/back) +7 - canvas apply +8 - create +*/ + +struct _undo_action +{ + t_canvas *x; /* canvas undo is associated with */ + int type; /* defines what kind of data container it is */ + void *data; /* each action will have a different data container */ + struct _undo_action *prev; /* previous undo action */ + struct _undo_action *next; /* next undo action */ +} t_undo_action; + +#ifndef t_undo_action +#define t_undo_action struct _undo_action +#endif + +EXTERN t_undo_action *canvas_undo_init(t_canvas *x); +EXTERN t_undo_action *canvas_undo_add(t_canvas *x); +EXTERN void canvas_undo_undo(t_canvas *x); +EXTERN void canvas_undo_redo(t_canvas *x); +EXTERN void canvas_undo_rebranch(t_undo_action *u); +EXTERN void canvas_undo_check_canvas_pointers(t_canvas *x); +EXTERN void canvas_undo_purge_abstraction_actions(t_canvas *x); +EXTERN void canvas_undo_free(t_canvas *x); + +#endif /* __g_undo_h_ */ diff --git a/src/makefile.in b/src/makefile.in index 51e141b76..36798a53d 100644 --- a/src/makefile.in +++ b/src/makefile.in @@ -61,7 +61,7 @@ TYPE_PUNNING_SRC = d_ctl.c d_array.c d_delay.c d_filter.c d_math.c d_osc.c d_sou # these are safe for full gcc 4.x optimization OPT_SAFE_SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \ g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \ - g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ + g_undo.c g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \ g_toggle.c g_vdial.c g_vslider.c g_vumeter.c g_magicglass.c \ m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \ m_conf.c m_glob.c m_sched.c \ -- GitLab