Commit fdf163ad authored by Guillem Bartrina's avatar Guillem Bartrina
Browse files

add an alert system that notifies the user of the existence of unsaved edited...

add an alert system that notifies the user of the existence of unsaved edited instances of the abstraction he is editing or about to edit
parent ffea3cd5
......@@ -297,6 +297,10 @@
"none": "Keinen",
"none_tt": "Ersetze keinen der Subpatches"
},
"warning": {
"unsaved_tt": "There is an unsaved edited instance of this abstraction",
"multipleunsaved_tt": "There is another unsaved edited instance of this abstraction"
},
"find": {
"placeholder": "Suche im Patch",
"search": "Suche",
......
......@@ -297,6 +297,10 @@
"none": "None",
"none_tt": "Do not replace any subpatch"
},
"warning": {
"unsaved_tt": "There is an unsaved edited instance of this abstraction",
"multipleunsaved_tt": "There is another unsaved edited instance of this abstraction"
},
"find": {
"placeholder": "Search in Canvas",
"search": "Search",
......
......@@ -297,6 +297,10 @@
"none": "Aucun",
"none_tt": "Ne remplacer aucun sous-patch"
},
"warning": {
"unsaved_tt": "There is an unsaved edited instance of this abstraction",
"multipleunsaved_tt": "There is another unsaved edited instance of this abstraction"
},
"find": {
"placeholder": "Chercher dans le Canevas",
"search": "Chercher",
......
......@@ -102,6 +102,9 @@
</button>
</div>
</dialog>
<div style="position: fixed; right: 2%; top: 2%; ">
<strong id="canvas_warning" style="display: none; text-align: right; -webkit-user-select: none;">!</strong>
</div>
<div id="hscroll" style="position: fixed; left: 0px; bottom: 0px; border-radius: 0px; width: 10px; height: 5px; visibility: hidden;"></div>
<div id="vscroll" style="position: fixed; right: 0px; top: 0px; border-radius: 0px; width: 5px; height: 10px; visibility: hidden;"></div>
<script type="text/javascript" src="./pd_canvas.js"></script>
......
......@@ -1336,6 +1336,9 @@ function register_window_id(cid, attr_array) {
// we check the title_queue to see if our title now contains an asterisk
// (which is the visual cue for "dirty")
// Enable/disable the warning for multiple dirty instances
pdgui.gui_canvas_warning(cid, attr_array.warid);
// Two possibilities for handling this better:
// have a representation of canvas attys in pdgui.js (editmode, dirty, etc.)
// or
......
......@@ -1760,7 +1760,7 @@ function create_window(cid, type, width, height, xpos, ypos, attr_array) {
}
// create a new canvas
function gui_canvas_new(cid, width, height, geometry, grid, zoom, editmode, name, dir, dirty_flag, hide_scroll, hide_menu, has_toplevel_scalars, cargs) {
function gui_canvas_new(cid, width, height, geometry, grid, zoom, editmode, name, dir, dirty_flag, warid, hide_scroll, hide_menu, has_toplevel_scalars, cargs) {
// hack for buggy tcl popups... should go away for node-webkit
//reset_ctrl_on_popup_window
......@@ -1817,6 +1817,7 @@ function gui_canvas_new(cid, width, height, geometry, grid, zoom, editmode, name
name: name,
dir: dir,
dirty: dirty_flag,
warid: warid,
args: cargs,
zoom: zoom,
editmode: editmode,
......@@ -2860,6 +2861,35 @@ function gui_gobj_dirty(cid, tag, state) {
});
}
function gui_canvas_warning(cid, warid) {
var warning = get_item(cid, "canvas_warning");
switch(warid)
{
case 0:
warning.style.setProperty("display", "none");
break;
case 1:
warning.title = lang.get_local_string("canvas.warning.unsaved_tt");
warning.onclick = function(){ pdsend(cid, "showdirty"); }
warning.style.setProperty("color", "coral");
warning.style.setProperty("font-size", "x-large");
warning.style.setProperty("display", "inline");
break;
case 2:
warning.title = lang.get_local_string("canvas.warning.multipleunsaved_tt");
warning.onclick = function(){ pdsend(cid, "showdirty"); }
warning.style.setProperty("color", "red");
warning.style.setProperty("font-size", "xx-large");
warning.style.setProperty("display", "inline");
break;
default:
break;
}
}
exports.gui_canvas_warning = gui_canvas_warning;
function gui_canvas_emphasize(cid) {
gui(cid).get_elem("patchsvg", function(e) {
// raise the window
......
......@@ -396,6 +396,8 @@ static int calculate_zoom(t_float zoom_hack)
return zoom;
}
int canvas_dirty_broadcast_all(t_symbol *name, t_symbol *dir, int mess);
/* make a new glist. It will either be a "root" canvas or else
it appears as a "text" object in another window (canvas_getcurrent()
tells us which.) */
......@@ -472,6 +474,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
else x->gl_env = 0;
x->gl_subdirties = 0;
x->gl_dirties = 0;
if (yloc < GLIST_DEFCANVASYLOC)
yloc = GLIST_DEFCANVASYLOC;
......@@ -522,6 +525,14 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
canvas_field_vec = NULL;
canvas_field_gp = NULL;
/* in the case it is an abstraction (gl_env is not null)
get the number of dirty instances of this same abstraction */
if(x->gl_env)
{
x->gl_dirties = canvas_dirty_broadcast_all(x->gl_name,
canvas_getdir(x), 0);
}
return(x);
}
......@@ -792,6 +803,100 @@ void canvas_dirtyclimb(t_canvas *x, int n)
}
}
/* the following functions are used to broadcast messages to all instances of
a specific abstraction (either file-based or ab).
the state of these instances change accoring to the message sent. */
void clone_iterate(t_pd *z, t_canvas_iterator it, void* data);
int clone_match(t_pd *z, t_symbol *name, t_symbol *dir);
static void canvas_dirty_common(t_canvas *x, int mess)
{
if(mess == 2)
{
if(x->gl_dirty)
{
if(!x->gl_havewindow) canvas_vis(x, 1);
gui_vmess("gui_canvas_emphasize", "x", x);
}
}
else
{
x->gl_dirties += mess;
if(x->gl_havewindow)
canvas_warning(x, (x->gl_dirties > 1 ?
(x->gl_dirty ? 2 : 1)
: (x->gl_dirties ? !x->gl_dirty : 0)));
}
}
/* packed data passing structure for canvas_dirty_broadcast */
typedef struct _dirty_broadcast_data
{
t_symbol *name;
t_symbol *dir;
int mess;
int *res; /* return value */
} t_dirty_broadcast_data;
static void canvas_dirty_deliver_packed(t_canvas *x, t_dirty_broadcast_data *data)
{
*data->res += (x->gl_dirty > 0);
canvas_dirty_common(x, data->mess);
}
static int canvas_dirty_broadcast_packed(t_canvas *x, t_dirty_broadcast_data *data);
static int canvas_dirty_broadcast(t_canvas *x, t_symbol *name, t_symbol *dir, int mess)
{
int res = 0;
t_gobj *g;
for (g = x->gl_list; g; g = g->g_next)
{
if(pd_class(&g->g_pd) == canvas_class)
{
if(canvas_isabstraction((t_canvas *)g)
&& ((t_canvas *)g)->gl_name == name
&& canvas_getdir((t_canvas *)g) == dir)
{
res += (((t_canvas *)g)->gl_dirty > 0);
canvas_dirty_common((t_canvas *)g, mess);
}
else
res += canvas_dirty_broadcast((t_canvas *)g, name, dir, mess);
}
else if(pd_class(&g->g_pd) == clone_class)
{
int cres = 0;
t_dirty_broadcast_data data;
data.name = name; data.dir = dir; data.mess = mess; data.res = &cres;
if(clone_match(&g->g_pd, name, dir))
{
clone_iterate(&g->g_pd, canvas_dirty_deliver_packed, &data);
}
else
{
clone_iterate(&g->g_pd, canvas_dirty_broadcast_packed, &data);
}
res += cres;
}
}
return (res);
}
static int canvas_dirty_broadcast_packed(t_canvas *x, t_dirty_broadcast_data *data)
{
*data->res = canvas_dirty_broadcast(x, data->name, data->dir, data->mess);
}
int canvas_dirty_broadcast_all(t_symbol *name, t_symbol *dir, int mess)
{
int res = 0;
t_canvas *x;
for (x = pd_this->pd_canvaslist; x; x = x->gl_next)
res += canvas_dirty_broadcast(x, name, dir, mess);
return (res);
}
/* mark a glist dirty or clean */
void canvas_dirty(t_canvas *x, t_floatarg n)
{
......@@ -806,6 +911,15 @@ void canvas_dirty(t_canvas *x, t_floatarg n)
/* set dirtiness visual markings */
canvas_dirtyclimb(x2, (unsigned)n);
/* in the case it is an abstraction, we tell all other
instances that there is eiher one more dirty instance or
one less dirty instance */
if(canvas_isabstraction(x2)
&& (x2->gl_owner || x2->gl_isclone))
{
canvas_dirty_broadcast_all(x2->gl_name, canvas_getdir(x2),
(x2->gl_dirty ? 1 : -1));
}
}
}
......@@ -1034,6 +1148,15 @@ extern void canvas_group_free(t_pd *x);
void canvas_free(t_canvas *x)
{
//fprintf(stderr,"canvas_free %zx\n", (t_uint)x);
/* in the case it is a dirty abstraction, we tell all other
instances that there is one less dirty instance */
if(canvas_isabstraction(x) && x->gl_dirty
&& (x->gl_owner || x->gl_isclone))
{
canvas_dirty_broadcast_all(x->gl_name, canvas_getdir(x), -1);
}
t_gobj *y;
int dspstate = canvas_suspend_dsp();
......@@ -1893,6 +2016,13 @@ void canvas_redrawallfortemplatecanvas(t_canvas *x, int action)
canvas_redrawallfortemplate(0, action);
}
/* --------- */
static void canvas_showdirty(t_canvas *x)
{
canvas_dirty_broadcast_all(x->gl_name, canvas_getdir(x), 2);
}
/* ------------------------------- declare ------------------------ */
/* put "declare" objects in a patch to tell it about the environment in
......@@ -2765,6 +2895,8 @@ void g_canvas_setup(void)
class_addcreator((t_newmethod)table_new, gensym("table"),
A_DEFSYM, A_DEFFLOAT, 0);
class_addmethod(canvas_class, (t_method)canvas_showdirty,
gensym("showdirty"), 0);
/*---------------------------- declare ------------------- */
declare_class = class_new(gensym("declare"), (t_newmethod)declare_new,
(t_method)declare_free, sizeof(t_declare), CLASS_NOINLET, A_GIMME, 0);
......
......@@ -235,6 +235,7 @@ struct _glist
t_gpointer gl_gp; /* parent for "canvas" data type */
int gl_subdirties; /* number of descending dirty abstractions */
int gl_dirties; /* number of diry instances, for multiple dirty warning */
};
#define gl_gobj gl_obj.te_g
......@@ -581,6 +582,7 @@ EXTERN int canvas_setdeleting(t_canvas *x, int flag);
EXTERN int canvas_hasarray(t_canvas *x);
EXTERN int canvas_has_scalars_only(t_canvas *x);
EXTERN void canvas_warning(t_canvas *x, int warid);
#define LB_LOAD 0 /* "loadbang" actions - 0 for original meaning */
#define LB_INIT 1 /* loaded but not yet connected to parent patch */
......
......@@ -2752,7 +2752,7 @@ void canvas_vis(t_canvas *x, t_floatarg f)
We may need to expand this to include scalars, as well. */
canvas_create_editor(x);
canvas_args_to_string(argsbuf, x);
gui_vmess("gui_canvas_new", "xiisiiissiiiis",
gui_vmess("gui_canvas_new", "xiisiiissiiiiis",
x,
(int)(x->gl_screenx2 - x->gl_screenx1),
(int)(x->gl_screeny2 - x->gl_screeny1),
......@@ -2763,6 +2763,9 @@ void canvas_vis(t_canvas *x, t_floatarg f)
x->gl_name->s_name,
canvas_getdir(x)->s_name,
x->gl_dirty,
(x->gl_dirties > 1 ?
(x->gl_dirty ? 2 : 1)
: (x->gl_dirties ? !x->gl_dirty : 0)),
x->gl_noscroll,
x->gl_nomenu,
canvas_hasarray(x),
......@@ -6171,6 +6174,12 @@ void gobj_dirty(t_gobj *x, t_glist *g, int state)
t_rtext *y = glist_findrtext(g, (t_text *)x);
gui_vmess("gui_gobj_dirty", "xsi", g, rtext_gettag(y), state);
}
/* tell the gui to display a specific message in the
top right corner */
void canvas_warning(t_canvas *x, int warid)
{
gui_vmess("gui_canvas_warning", "xi", x, warid);
}
static int glist_dofinderror(t_glist *gl, void *error_object)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment