Commit 4f9cc742 authored by Ivica Bukvic's avatar Ivica Bukvic
Browse files

added first version of the global/universal preset system using objects preset_hub and preset_node

parent 043e7a11
......@@ -31,7 +31,6 @@ void bng_draw_select(t_bng* x, t_glist* glist);
/* --------------- bng gui-bang ------------------------- */
t_widgetbehavior bng_widgetbehavior;
static t_class *bng_class;
/* widget helper functions */
......
......@@ -920,11 +920,12 @@ static void canvas_drawlines(t_canvas *x)
while (oc = linetraverser_next(&t))
{
issignal = (outlet_getsymbol(t.tr_outlet) == &s_signal ? 1 : 0);
sys_vgui(".x%lx.c create line %d %d %d %d -width %s -fill %s \
-tags {l%lx all_cords}\n",
glist_getcanvas(x), t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2,
(issignal ? "$signal_cord_width" : "$msg_cord_width"), (issignal ? "$signal_cord" : "$msg_cord"),
oc);
if (!(pd_class(&t.tr_ob2->ob_g.g_pd) == preset_node_class && pd_class(&t.tr_ob->ob_g.g_pd) != message_class))
sys_vgui(".x%lx.c create line %d %d %d %d -width %s -fill %s \
-tags {l%lx all_cords}\n",
glist_getcanvas(x), t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2,
(issignal ? "$signal_cord_width" : "$msg_cord_width"), (issignal ? "$signal_cord" : "$msg_cord"),
oc);
}
}
......@@ -1047,29 +1048,29 @@ void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
}
}
static void canvas_loadbangabstractions(t_canvas *x)
static void canvas_loadbangabstractions(t_canvas *x, t_symbol *s)
{
t_gobj *y;
t_symbol *s = gensym("loadbang");
//t_symbol *s = gensym("loadbang");
for (y = x->gl_list; y; y = y->g_next)
if (pd_class(&y->g_pd) == canvas_class)
{
if (canvas_isabstraction((t_canvas *)y))
canvas_loadbang((t_canvas *)y);
else
canvas_loadbangabstractions((t_canvas *)y);
canvas_loadbangabstractions((t_canvas *)y, s);
}
}
void canvas_loadbangsubpatches(t_canvas *x)
void canvas_loadbangsubpatches(t_canvas *x, t_symbol *s)
{
t_gobj *y;
t_symbol *s = gensym("loadbang");
//t_symbol *s = gensym("loadbang");
for (y = x->gl_list; y; y = y->g_next)
if (pd_class(&y->g_pd) == canvas_class)
{
if (!canvas_isabstraction((t_canvas *)y))
canvas_loadbangsubpatches((t_canvas *)y);
canvas_loadbangsubpatches((t_canvas *)y, s);
}
for (y = x->gl_list; y; y = y->g_next)
if ((pd_class(&y->g_pd) != canvas_class) &&
......@@ -1079,9 +1080,14 @@ void canvas_loadbangsubpatches(t_canvas *x)
void canvas_loadbang(t_canvas *x)
{
t_gobj *y;
canvas_loadbangabstractions(x);
canvas_loadbangsubpatches(x);
//t_gobj *y;
// first loadbang preset hubs and nodes
canvas_loadbangabstractions(x, gensym("pre-loadbang"));
canvas_loadbangsubpatches(x, gensym("pre-loadbang"));
// then do the regular loadbang
canvas_loadbangabstractions(x, gensym("loadbang"));
canvas_loadbangsubpatches(x, gensym("loadbang"));
}
/* JMZ:
* initbang is emitted after the canvas is done, but before the parent canvas is done
......
......@@ -39,23 +39,6 @@ in future releases. The public (stable) API is in m_pd.h. */
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
extern "C" {
#endif
/* redundant struct queue for maintaining a list of redundantly
allocated memory chunks to avoid double-entry bug. these are
instantiated inside canvas_new since the bug only affects new
canvases/abstractions rather than individual objects. the queue
is destructed in m_glob.c quit call (when pd exits) */
/*
typedef struct _redundant_mem
{
//int rm_what;
t_canvas *rm_canvas;
struct _redundant_mem *rm_next;
} t_redundant_mem;
t_redundant_mem *rm_start;
t_redundant_mem *rm_end;
*/
/* --------------------- geometry ---------------------------- */
#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
......@@ -98,6 +81,14 @@ EXTERN_STRUCT _magicGlass;
#define t_magicGlass struct _magicGlass
// end jsarlo
// undo stuff
EXTERN_STRUCT _undo_action;
#define t_undo_action struct _undo_action
// preset hub stuff
EXTERN_STRUCT _preset_hub;
#define t_preset_hub struct _preset_hub
typedef struct _selection
{
t_gobj *sel_what;
......@@ -166,7 +157,7 @@ area of a window.
*/
#include "g_undo.h"
//#include "g_undo.h"
struct _glist
{
......@@ -228,11 +219,43 @@ struct _glist
//infinite undo goodies
t_undo_action *u_queue;
t_undo_action *u_last;
//global preset array pointer
t_preset_hub *gl_phub;
};
#define gl_gobj gl_obj.te_g
#define gl_pd gl_gobj.g_pd
/*-------------------universal preset stuff---------------------*/
// for the universal preset_node ability (see g_editor.c doconnect/disconnect functions)
// this is where all the classes capable of being controlled via preset should be defined
// preset objects
t_class *preset_hub_class;
t_class *preset_node_class;
// core gui
t_class *gatom_class;
t_class *message_class;
// core text
extern t_class *pdint_class;
extern t_class *pdfloat_class;
extern t_class *pdsymbol_class;
// iemgui
t_class *bng_class;
t_class *hradio_class, *hradio_old_class;
t_class *hslider_class;
t_class *my_canvas_class;
t_class *my_numbox_class;
t_class *toggle_class;
t_class *vradio_class, *vradio_old_class;
t_class *vslider_class;
t_class *vu_class;
/*-----------------end universal preset stuff-------------------*/
/* a data structure to describe a field in a pure datum */
#define DT_FLOAT 0
......@@ -654,7 +677,6 @@ EXTERN void fielddesc_setcoord(t_fielddesc *f, t_template *tmpl,
EXTERN t_float fielddesc_cvttocoord(t_fielddesc *f, t_float val);
EXTERN t_float fielddesc_cvtfromcoord(t_fielddesc *f, t_float coord);
/* ----------------------- guiconnects, g_guiconnect.c --------- */
EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym);
EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
......@@ -663,6 +685,78 @@ EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s);
EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s);
/* ---------- infinite undo/redo routines found in g_undo.c ------------ */
EXTERN t_undo_action *canvas_undo_init(t_canvas *x);
EXTERN t_undo_action *canvas_undo_add(t_canvas *x,
int type, const char *name, void *data);
EXTERN void canvas_undo_undo(t_canvas *x);
EXTERN void canvas_undo_redo(t_canvas *x);
EXTERN void canvas_undo_rebranch(t_canvas *x);
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);
/* --------- 1. connect ---------- */
EXTERN void *canvas_undo_set_connect(t_canvas *x,
int index1, int outno, int index2, int inno);
EXTERN void canvas_undo_connect(t_canvas *x, void *z, int action);
/* --------- 2. disconnect ------- */
EXTERN void *canvas_undo_set_disconnect(t_canvas *x,
int index1, int outno, int index2, int inno);
EXTERN void canvas_undo_disconnect(t_canvas *x, void *z, int action);
/* --------- 3. cut -------------- */
EXTERN void *canvas_undo_set_cut(t_canvas *x, int mode);
EXTERN void canvas_undo_cut(t_canvas *x, void *z, int action);
/* --------- 4. move ------------- */
EXTERN void *canvas_undo_set_move(t_canvas *x, int selected);
EXTERN void canvas_undo_move(t_canvas *x, void *z, int action);
/* --------- 5. paste ------------ */
EXTERN void *canvas_undo_set_paste(t_canvas *x, int offset);
EXTERN void canvas_undo_paste(t_canvas *x, void *z, int action);
/* --------- 6. apply ------------ */
EXTERN void *canvas_undo_set_apply(t_canvas *x, int n);
EXTERN void canvas_undo_apply(t_canvas *x, void *z, int action);
/* --------- 7. arrange ---------- */
EXTERN void *canvas_undo_set_arrange(t_canvas *x, t_gobj *obj, int newindex);
EXTERN void canvas_undo_arrange(t_canvas *x, void *z, int action);
/* --------- 8. canvas apply ----- */
EXTERN void *canvas_undo_set_canvas(t_canvas *x);
EXTERN void canvas_undo_canvas_apply(t_canvas *x, void *z, int action);
/* --------- 9. create ----------- */
EXTERN void canvas_undo_create(t_canvas *x, void *z, int action);
EXTERN void *canvas_undo_set_create(t_canvas *x);
/* --------- 10. recreate -------- */
EXTERN void canvas_undo_recreate(t_canvas *x, void *z, int action);
EXTERN void *canvas_undo_set_recreate(t_canvas *x, t_gobj *y, int old_pos);
/* --------- 11. font ------------ */
EXTERN void canvas_undo_font(t_canvas *x, void *z, int action);
EXTERN void *canvas_undo_set_font(t_canvas *x, int font);
/* ------------------------------- */
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
}
#endif
......@@ -576,6 +576,7 @@ void *canvas_undo_set_disconnect(t_canvas *x,
void canvas_disconnect(t_canvas *x,
t_float index1, t_float outno, t_float index2, t_float inno)
{
//fprintf(stderr,"canvas_disconnect\n");
t_linetraverser t;
t_outconnect *oc;
linetraverser_start(&t, x);
......@@ -594,6 +595,14 @@ void canvas_disconnect(t_canvas *x,
}
// end jsarlo
obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
// if we are dealing with a preset_node, make sure to also disconnect its invisible return node
// we trust here that the object has been already connected to a valid object so we blindly
// disconnect first outlet with the first inlet
if (pd_class(&t.tr_ob->ob_g.g_pd) == preset_node_class) {
//fprintf(stderr,"gotta disconnect hidden one too...\n");
obj_disconnect(t.tr_ob2, 0, t.tr_ob, 0);
}
break;
}
}
......@@ -2914,6 +2923,7 @@ int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
{
//fprintf(stderr,"canvas_doconnect\n");
int x11=0, y11=0, x12=0, y12=0;
t_gobj *y1;
int x21=0, y21=0, x22=0, y22=0;
......@@ -2988,6 +2998,36 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
}
if (doit)
{
// if the first object is preset_node, check if the object we are connecting to
// is supported. If not, disallow connection
if (pd_class(&y1->g_pd) == preset_node_class) {
if (pd_class(&y2->g_pd) != gatom_class &&
pd_class(&y2->g_pd) != bng_class &&
pd_class(&y2->g_pd) != hradio_class &&
pd_class(&y2->g_pd) != hradio_old_class &&
pd_class(&y2->g_pd) != hslider_class &&
pd_class(&y2->g_pd) != my_canvas_class &&
pd_class(&y2->g_pd) != my_numbox_class &&
pd_class(&y2->g_pd) != toggle_class &&
pd_class(&y2->g_pd) != vradio_class &&
pd_class(&y2->g_pd) != vradio_old_class &&
pd_class(&y2->g_pd) != vslider_class &&
pd_class(&y2->g_pd) != vu_class &&
pd_class(&y2->g_pd) != pdint_class &&
pd_class(&y2->g_pd) != pdfloat_class &&
pd_class(&y2->g_pd) != pdsymbol_class) {
error("preset node currently works only with gui objects, ints, floats, and symbols...\n");
return;
}
}
// now check if explicit user-made connection into preset_node if kind other than message
// messages may be used to change node's operation
if (pd_class(&y2->g_pd) == preset_node_class && pd_class(&y1->g_pd) != message_class) {
error("preset node only accepts messages as input to set its destination preset_hub...\n");
return;
}
int issignal = obj_issignaloutlet(ob1, closest1);
oc = obj_connect(ob1, closest1, ob2, closest2);
lx1 = x11 + (noutlet1 > 1 ?
......@@ -3038,6 +3078,16 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
canvas_undo_add(x, 1, "connect", canvas_undo_set_connect(x,
canvas_getindex(x, &ob1->ob_g), closest1,
canvas_getindex(x, &ob2->ob_g), closest2));
// add auto-connect back to preset_node object
// (by this time we know we are connecting only to legal objects who have at least one outlet)
if (pd_class(&y1->g_pd) == preset_node_class) {
//fprintf(stderr,"gotta do auto-connect back to preset_node\n");
if (!canvas_isconnected(x, ob2, 0, ob1, 0))
obj_connect(ob2, 0, ob1, 0);
//else
// fprintf(stderr,"error: already connected (this happens when loading from file and is ok)\n");
}
}
else
// jsarlo
......@@ -4505,6 +4555,7 @@ extern t_class *text_class;
void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
t_floatarg fwhoin, t_floatarg finno)
{
//fprintf(stderr,"canvas_connect\n");
if (!x->gl_list) {
post("paste error: no objects to connect, probably incomplete clipboard copy from an external source (e.g. from a text editor)");
return;
......@@ -4534,15 +4585,25 @@ void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
while (inno >= obj_ninlets(objsink))
inlet_new(objsink, &objsink->ob_pd, 0, 0);
if (!(oc = obj_connect(objsrc, outno, objsink, inno))) goto bad;
if (glist_isvisible(x))
{
sys_vgui(".x%lx.c create line %d %d %d %d -width %s -fill %s -tags {l%lx all_cords}\n",
glist_getcanvas(x), 0, 0, 0, 0,
(obj_issignaloutlet(objsrc, outno) ? "$signal_cord_width" : "$msg_cord_width"),
(obj_issignaloutlet(objsrc, outno) ? "$signal_cord" : "$msg_cord"), oc);
canvas_fixlinesfor(x, objsrc);
}
if (!canvas_isconnected(x, objsrc, outno, objsink, inno)) {
if (!(oc = obj_connect(objsrc, outno, objsink, inno))) goto bad;
// add auto-connect back to preset_node object
// (by this time we know we are connecting only to legal objects who have at least one outlet)
if (pd_class(&objsrc->ob_pd) == preset_node_class) {
//fprintf(stderr,"canvas_connect: gotta do auto-connect back to preset_node\n");
if (!canvas_isconnected(x, objsink, 0, objsrc, 0))
obj_connect(objsink, 0, objsrc, 0);
}
if (glist_isvisible(x) && (pd_class(&sink->g_pd) != preset_node_class || (pd_class(&sink->g_pd) == preset_node_class && pd_class(&src->g_pd) == message_class)))
{
//fprintf(stderr,"draw line\n");
sys_vgui(".x%lx.c create line %d %d %d %d -width %s -fill %s -tags {l%lx all_cords}\n",
glist_getcanvas(x), 0, 0, 0, 0,
(obj_issignaloutlet(objsrc, outno) ? "$signal_cord_width" : "$msg_cord_width"),
(obj_issignaloutlet(objsrc, outno) ? "$signal_cord" : "$msg_cord"), oc);
canvas_fixlinesfor(x, objsrc);
}
}
return;
bad:
......
......@@ -34,7 +34,6 @@ void hradio_draw_select(t_hradio* x, t_glist* glist);
/* ------------- hdl gui-horicontal dial ---------------------- */
t_widgetbehavior hradio_widgetbehavior;
static t_class *hradio_class, *hradio_old_class;
/* widget helper functions */
......
......@@ -31,7 +31,6 @@ static void hslider_draw_select(t_hslider* x,t_glist* glist);
/* ------------ hsl gui-horicontal slider ----------------------- */
t_widgetbehavior hslider_widgetbehavior;
static t_class *hslider_class;
static double last;
static int is_last_float = 0;
......
......@@ -31,7 +31,6 @@ void my_canvas_draw_select(t_my_canvas* x, t_glist* glist);
/* ---------- cnv my gui-canvas for a window ---------------- */
t_widgetbehavior my_canvas_widgetbehavior;
static t_class *my_canvas_class;
/* widget helper functions */
......
......@@ -38,7 +38,6 @@ static void my_numbox_draw_update(t_gobj *client, t_glist *glist);
/* ------------ nmx gui-my number box ----------------------- */
t_widgetbehavior my_numbox_widgetbehavior;
static t_class *my_numbox_class;
/* widget helper functions */
......
......@@ -15,10 +15,10 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "g_undo.h"
#include "x_preset.h"
t_class *text_class;
static t_class *message_class;
static t_class *gatom_class;
static void text_vis(t_gobj *z, t_glist *glist, int vis);
static void text_displace(t_gobj *z, t_glist *glist,
int dx, int dy);
......@@ -100,6 +100,12 @@ static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
t_text *x;
int argc;
t_atom *argv;
// for hiding arguments
t_atom *vec;
int len, i, hidden;
t_binbuf *hide;
newest = 0;
canvas_setcurrent((t_canvas *)gl);
canvas_getargs(&argc, &argv);
......@@ -125,12 +131,34 @@ static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
//fprintf(stderr,"creating blank object\n");
x = (t_text *)pd_new(text_class);
}
/* special case: an object, like preset_hub, hides its arguments beyond the first n, so
we modify its binbuf here */
vec = binbuf_getvec(b);
len = binbuf_getnatom(b);
hidden = 0;
for (i = 0; i < len; i++) {
if (!strcmp("%hidden%", atom_getsymbol(&vec[i])->s_name)) {
//fprintf(stderr,"found hidden %d %s\n", i, atom_getsymbol(&vec[i])->s_name);
hidden = i;
break;
}
}
if (hidden) {
hide = binbuf_new();
binbuf_add(hide, hidden, vec);
binbuf_free(b);
b = hide;
}
/* done special case */
x->te_binbuf = b;
x->te_xpix = xpix;
x->te_ypix = ypix;
x->te_width = 0;
x->te_type = T_OBJECT;
glist_add(gl, &x->te_g);
if (selected)
{
/* this is called if we've been created from the menu. */
......@@ -407,7 +435,7 @@ typedef struct _message
t_clock *m_clock;
} t_message;
static t_class *message_class, *messresponder_class;
static t_class *messresponder_class;
static void messresponder_bang(t_messresponder *x)
{
......@@ -1337,28 +1365,46 @@ static void text_delete(t_gobj *z, t_glist *glist)
static void text_vis(t_gobj *z, t_glist *glist, int vis)
{
//fprintf(stderr,"text_vis\n");
t_text *x = (t_text *)z;
if (vis)
{
if (gobj_shouldvis(&x->te_g, glist))
{
t_rtext *y = glist_findrtext(glist, x);
if (x->te_type == T_ATOM)
glist_retext(glist, x);
text_drawborder(x, glist, rtext_gettag(y),
rtext_width(y), rtext_height(y), 1);
rtext_draw(y);
}
}
else
{
t_rtext *y = glist_findrtext(glist, x);
if (gobj_shouldvis(&x->te_g, glist))
{
text_eraseborder(x, glist, rtext_gettag(y));
rtext_erase(y);
}
}
#ifdef PDL2ORK
//if we are in k12 mode and this is hub with level 1 (global) don't draw it and make its width/height 0
int exception = 0;
if (pd_class(&x->te_pd) == preset_hub_class && sys_k12_mode) {
fprintf(stderr,"text_vis reports preset_hub_class detected\n");
t_preset_hub *h = (t_preset_hub *)z;
if (h->ph_invis) {
exception = 1;
x->te_width = 0;
}
}
if (!exception) {
#endif
if (vis)
{
if (gobj_shouldvis(&x->te_g, glist))
{
t_rtext *y = glist_findrtext(glist, x);
if (x->te_type == T_ATOM)
glist_retext(glist, x);
text_drawborder(x, glist, rtext_gettag(y),
rtext_width(y), rtext_height(y), 1);
rtext_draw(y);
}
}
else
{
t_rtext *y = glist_findrtext(glist, x);
if (gobj_shouldvis(&x->te_g, glist))
{
text_eraseborder(x, glist, rtext_gettag(y));
rtext_erase(y);
}
}
#ifdef PDL2ORK
}
#endif
}
static int text_click(t_gobj *z, struct _glist *glist,
......@@ -1841,6 +1887,7 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
char *c1, *c2;
int i1, i2;
if (x->te_type == T_OBJECT)
{
t_binbuf *b = binbuf_new();
......@@ -1851,16 +1898,18 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
vec1 = binbuf_getvec(x->te_binbuf);
natom2 = binbuf_getnatom(b);
vec2 = binbuf_getvec(b);
/* special case: if pd args change just pass the message on. */
if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
/* special case: if pd subpatch is valid and its args change, and its new name is valid, just pass the message on. */
if (x->te_pd == canvas_class && (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
&& !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") &&
vec2[0].a_type == A_SYMBOL
&& !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
&& !strcmp(vec2[0].a_w.w_symbol->s_name, "pd") && vec2[1].a_type == A_SYMBOL))
{
//fprintf(stderr,"setto canvas\n");
//first check if the contents have changed to see if there is any point of recreating the object
binbuf_gettext(x->te_binbuf, &c1, &i1);
binbuf_gettext(b, &c2, &i2);
if (strcmp(c1, c2)) {
//fprintf(stderr,"string differs\n");
canvas_undo_add(glist_getcanvas(glist), 10, "recreate",
(void *)canvas_undo_set_recreate(glist_getcanvas(glist), &x->te_g, pos));
typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
......@@ -1872,6 +1921,7 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
else /* normally, just destroy the old one and make a new one. */
{
//first check if the contents have changed to see if there is any point of recreating the object
//fprintf(stderr,"setto not canvas\n");
binbuf_gettext(x->te_binbuf, &c1, &i1);
binbuf_gettext(b, &c2, &i2);
if (strcmp(c1, c2)) {
......
......@@ -32,7 +32,6 @@ void toggle_draw_select(t_toggle* x, t_glist* glist);
/* --------------- tgl gui-toggle ------------------------- */
t_widgetbehavior toggle_widgetbehavior;
static t_class *toggle_class;
/* widget helper functions */
......
#include "m_pd.h"
#include "g_canvas.h"
#include <stdio.h>
#include "g_undo.h"
//used for canvas_objtext to differentiate between objects being created by user
//vs. those (re)created by the undo/redo actions
int we_are_undoing = 0;
extern const char *canvas_undo_name;
extern void glob_preset_node_list_seek_hub(void);
t_undo_action *canvas_undo_init(t_canvas *x)
{
......@@ -75,6 +77,10 @@ void canvas_undo_undo(t_canvas *x)
char *undo_action = x->u_last->name;
char *redo_action = x->u_last->next->name;
we_are_undoing = 0;
// here we call updating of all unpaired hubs and nodes since their regular call
// will fail in case their position needed to be updated by undo/redo first to