diff --git a/pd/doc/5.reference/declare-help.pd b/pd/doc/5.reference/declare-help.pd index 046719bc022aaf71fbf4b7d3f2ca1880d9797be6..798c72b81b51aa47fa99181b5dfb239b5480835f 100644 --- a/pd/doc/5.reference/declare-help.pd +++ b/pd/doc/5.reference/declare-help.pd @@ -1,6 +1,10 @@ #N canvas 426 36 555 619 10; #X declare; -#X declare; +#X declare -path mylibs; +#X declare -lib mylib; +#X declare -stdpath mylibs; +#X declare -stdlib mylib; +#X declare -zoom 1; #X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0 14 -228856 -66577 0; #X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header declare 3 12 0 18 @@ -53,7 +57,6 @@ calling patch as well as the abstraction.); #X text 98 561 BUG: The name "-stdpath" is confusing \, as it has a quite different effect from "-stdpath" on the pd command line.; #X text 11 23 set environment for loading patch; -#X text 139 69 NEEDS AN EXAMPLE; #X text 165 185 - the [declare] object adds one or more directories to the search path \, and/or pre-loads one or more libraries ("extensions") to Pd in preparation for opening the patch from a file. Usage is "declare @@ -66,3 +69,33 @@ you can get it using "declare -stdpath extra/zexy".; #X text 80 185 n) symbol atom; #X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide ; +#X obj 40 52 declare -path mylibs; +#X obj 240 52 declare -lib mylib; +#X obj 40 76 declare -stdpath mylibs; +#X obj 240 76 declare -stdlib mylib; +#N canvas 480 189 445 363 Patch_local 0; +#X obj 1 1 cnv 15 437 20 empty \$0-pddp.cnv.subheading empty 3 12 0 +14 -204280 -1 0; +#X text 7 1 [declare] Patch-local options; +#X obj 10 40 declare -zoom 1; +#X text 133 40 turns on load/restore of zoom levels in a patch; +#X text 10 120 * [declare -zoom 0/1] turns save/restore of zoom levels +on or off. This overrides the corresponding global option in the GUI +preferences. Please note that this does *not* actually set the zoom +level itself \, it merely enables or disables storing and retrieving +that setting in a patch., f 69; +#X text 10 70 [declare] also offers the following special (and experimental) +patch-local option which overrides the corresponding global flag in +the current patch (including all its one-off subpatches):, f 69; +#X text 10 200 CAVEAT: This option is only available in Purr Data \, +it is NOT supported by vanilla Pd (which has no way of configuring +the zoom behavior)., f 69; +#X text 10 250 The -zoom option is intended mainly for classroom use +\, e.g. \, when projecting patches on a whiteboard. It ensures that +the patch is displayed at the preset zoom level by default \, even +if the global zoom save/load option is disabled in the preferences. +If you abuse this option to enforce unusually high or low zoom levels +\, you take away precious zoom levels from the user. So please use +this option with due skill \, care \, and diligence \, or better don't +use it at all., f 69; +#X restore 221 597 pd Patch_local; diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c index abd50f2bcc36ab516656aa2d9a096607759ac4d3..15bbca59a945d02fd6c78803c762e34910d35ba9 100644 --- a/pd/src/g_canvas.c +++ b/pd/src/g_canvas.c @@ -412,7 +412,8 @@ t_symbol *canvas_field_templatesym; /* for "canvas" data type */ t_word *canvas_field_vec; /* for "canvas" data type */ t_gpointer *canvas_field_gp; /* parent for "canvas" data type */ -static int calculate_zoom(t_float zoom_hack) +// This is also used in g_editor.c, so make sure to keep it non-static. +int calculate_zoom(t_float zoom_hack) { // This gives back the zoom level stored in the patch (cf. zoom_hack // in g_readwrite.c). Make sure to round this value to handle any rounding @@ -461,6 +462,25 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) canvas_addtolist(x); /* post("canvas %zx, owner %zx", x, owner); */ + /* This records the zoom level obtained from the patch (cf. zoom_hack in + g_readwrite.c, and the calculate_zoom() function above), so that the + actual zoom level can be calculated later in a lazy fashion if needed. + Initially zero, the actual value is extracted from the canvas arguments + below. If loading/saving zoom is enabled globally (sys_zoom != 0) then + we can apply the zoom factor right away and we are done (gl_zoom_hack + stays zero in that case). + + Otherwise, we record the value so that we can apply the zoom later when + a [declare -zoom 1] object in the patch calls for it. (In the case of a + one-off subpatch, this may actually happen much later at the time the + subpatch window is first mapped; see the comment preceding + canvas_calculate_zoom() in g_editor.c for further explanation.) + + Note that this 'declare' option is patch-local and will make sure that + the recorded zoom level is applied even if loading/saving zoom is + globally disabled (sys_zoom == 0). */ + x->gl_zoom_hack = 0; + if (argc == 5) /* toplevel: x, y, w, h, font */ { t_float zoom_hack = atom_getfloatarg(3, argc, argv); @@ -472,6 +492,9 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) zoom_hack -= height; if (sys_zoom && zoom_hack > 0) zoom = calculate_zoom(zoom_hack); + else + // record the zoom hack for later, see comment above + x->gl_zoom_hack = zoom_hack; } else if (argc == 6) /* subwindow: x, y, w, h, name, vis */ { @@ -485,6 +508,8 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) zoom_hack -= height; if (sys_zoom && zoom_hack > 0) zoom = calculate_zoom(zoom_hack); + else + x->gl_zoom_hack = zoom_hack; } /* (otherwise assume we're being created from the menu.) */ @@ -555,6 +580,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) x->gl_edit_save = 0; x->gl_font = sys_nearestfontsize(font); x->gl_zoom = zoom; + x->gl_zoomflag = sys_zoom; pd_pushsym(&x->gl_pd); x->u_queue = canvas_undo_init(x); @@ -612,6 +638,7 @@ t_glist *glist_addglist(t_glist *g, t_symbol *sym, t_float x1, t_float y1, t_float x2, t_float y2, t_float px1, t_float py1, t_float px2, t_float py2) { + extern int sys_zoom; static int gcount = 0; int zz; int menu = 0; @@ -663,6 +690,8 @@ t_glist *glist_addglist(t_glist *g, t_symbol *sym, x->gl_font = (canvas_getcurrent() ? canvas_getcurrent()->gl_font : sys_defaultfont); x->gl_zoom = 0; + x->gl_zoom_hack = 0; + x->gl_zoomflag = sys_zoom; x->gl_screenx1 = x->gl_screeny1 = 0; x->gl_screenx2 = 450; x->gl_screeny2 = 300; @@ -2907,6 +2936,21 @@ void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv) canvas_stdlib(e, atom_getsymbolarg(i+1, argc, argv)->s_name); i++; } + else if ((argc > i+1) && !strcmp(flag, "-zoom")) + { + x->gl_zoomflag = atom_getfloatarg(i+1, argc, argv) != 0; + if (x->gl_zoomflag && x->gl_zoom_hack) { + x->gl_zoom = calculate_zoom(x->gl_zoom_hack); + // we only want to calculate this once, so reset the zoom_hack + // value to ensure that we don't do it again + x->gl_zoom_hack = 0; + } else if (!x->gl_zoomflag) { + // reset the zoom level in case we already calculated it + // previously + x->gl_zoom = 0; + } + i++; + } // ag: Handle the case of an unrecognized option argument (presumably // a float). else if (!*flag) { diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h index cde9837014ad4a16ab8b7ca2eb8275062a2b1f7f..80a5840e6d6b7087b88920d79c1bf112815cef90 100644 --- a/pd/src/g_canvas.h +++ b/pd/src/g_canvas.h @@ -225,6 +225,8 @@ struct _glist t_symbol *gl_name; /* symbol bound here */ int gl_font; /* nominal font size in points, e.g., 10 */ int gl_zoom; /* current zoom level (-7..8) */ + t_float gl_zoom_hack; /* stored zoom_hack used by declare */ + int gl_zoomflag; /* canvas-local zoom flag (0/1) */ struct _glist *gl_next; /* link in list of toplevels */ t_canvasenvironment *gl_env; /* root canvases and abstractions only */ unsigned int gl_havewindow:1; /* true if we own a window */ diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index f8db767e81d8a2841cdfc9e7d315e4e99fe40bb6..e744212b79f8cee2b9eea4e8520fee44aaf762d7 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -2828,6 +2828,48 @@ void canvas_init_menu(t_canvas *x) gui_vmess("gui_menu_font_set_initial_size", "xi", x, x->gl_font); } +/* ag: Calculate the proper zoom factor for a (sub)patch. + + We may need to pick up the slack from 'declare -zoom 1' here, which + calculates zoom factors lazily from their "zoom_hack" values stored in the + (sub)patch headers. This will only be necessary if we're mapping a one-off + subpatch, because 'declare' in a subpatch always gets invoked on the + root patch or abstraction containing that subpatch. + + So in this case the zoom factor (or rather its "zoom_hack" value) will get + stored at its proper location in the subpatch canvas (which 'declare -zoom' + never sees, thus it can't update the zoom level right there), while the + zoomflag gets set by 'declare -zoom' in the root/abstraction. + + Catch 22. :) We solve this by looking up the zoomflag in the root, and + calculating the proper zoom level lazily in canvas_vis(), when the window + first gets mapped and we have both the zoomflag and zoom_hack values + readily available. */ + +static int canvas_calculate_zoom(t_canvas *x) +{ + // Check whether the zoom_hack value of canvas x is nonzero. Otherwise the + // canvas either has no zoom level, or we already calculated it previously, + // and we simply return the recorded value. + if (x->gl_zoom_hack) { + t_glist *gl = x; + // in a subpatch, look up the enclosing root or abstraction + while (!gl->gl_env && gl->gl_owner) { + gl = gl->gl_owner; + } + // If the root zoomflag is set, employ calculate_zoom() from g_canvas.c + // to calculate the zoom level from the zoom_hack value. + if (gl->gl_zoomflag) { + extern int calculate_zoom(t_float zoom_hack); + x->gl_zoom = calculate_zoom(x->gl_zoom_hack); + // Now that we've updated the value, reset the zoom_hack so that we + // don't do that calculation again. + x->gl_zoom_hack = 0; + } + } + return x->gl_zoom; +} + extern int sys_snaptogrid; /* whether we are snapping to grid or not */ extern int sys_gridsize; @@ -2903,7 +2945,7 @@ void canvas_vis(t_canvas *x, t_floatarg f) geobuf, sys_snaptogrid, sys_gridsize, - x->gl_zoom, + canvas_calculate_zoom(x), x->gl_edit, x->gl_name->s_name, canvas_getdir(x)->s_name, diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c index ae4ee02abf9c5ebf17ed69add8a053982bd7d3d8..3f477c9e4fa229c74a4e3c9296fa0431a3f62d90 100644 --- a/pd/src/g_readwrite.c +++ b/pd/src/g_readwrite.c @@ -786,7 +786,13 @@ static void canvas_saveto(t_canvas *x, t_binbuf *b) patchsym = atom_getsymbolarg(name_index, binbuf_getnatom(bz), binbuf_getvec(bz)); binbuf_free(bz); - if (sys_zoom && x->gl_zoom != 0) { + // look up the enclosing root or abstraction for the zoomflag value + // (this is where 'declare -zoom' stores it) + t_glist *gl = x; + while (!gl->gl_env && gl->gl_owner) { + gl = gl->gl_owner; + } + if (gl->gl_zoomflag && x->gl_zoom != 0) { // This uses the hack described above to store the zoom factor in // the fractional part of the windows height parameter. Note that // any of the other canvas geometry parameters would do just as @@ -818,7 +824,7 @@ static void canvas_saveto(t_canvas *x, t_binbuf *b) else { // See above. - if (sys_zoom && x->gl_zoom != 0) { + if (x->gl_zoomflag && x->gl_zoom != 0) { binbuf_addv(b, "ssiiifi;", gensym("#N"), gensym("canvas"), (int)(x->gl_screenx1), (int)(x->gl_screeny1),