diff --git a/pd/nw/dialog_prefs.html b/pd/nw/dialog_prefs.html index 07a857749594c6722cde64de2092bf787ecd773b..8308b66de68e7e468aaca4a9b2c98675cfdc218c 100644 --- a/pd/nw/dialog_prefs.html +++ b/pd/nw/dialog_prefs.html @@ -415,9 +415,16 @@ select { </select> <br/> <label data-i18n="[title]prefs.gui.grid.show_grid_tt"> - <input type="checkbox" id="show_grid" name="show_grid"> + <input type="checkbox" id="show_grid" name="show_grid" + onchange="grid_toggle(this.checked)"> <span data-i18n="prefs.gui.grid.show_grid"></span> </label> + <select id="grid_size"> + <option value="5">5</option> + <option value="10">10</option> + <option value="20">20</option> + <option value="25">25</option> + </select> <br/> <label data-i18n="[title]prefs.gui.zoom.save_zoom_tt"> <input type="checkbox" id="save_zoom" name="save_zoom"> @@ -783,6 +790,7 @@ function apply(save_prefs) { pdgui.pdsend("pd gui-prefs", get_gui_preset(), get_bool_elem("show_grid"), + document.getElementById("grid_size").value, get_bool_elem("save_zoom"), get_bool_elem("browser_doc"), get_bool_elem("browser_path"), @@ -796,7 +804,8 @@ function apply(save_prefs) { get_bool_elem("browser_path") ); // Update the grid on all open windows. - pdgui.update_grid(get_bool_elem("show_grid")); + pdgui.update_grid(get_bool_elem("show_grid"), + document.getElementById("grid_size").value); // Send the startup config data to Pd pdgui.pdsend.apply(null, ["pd path-dialog", startup_use_stdpath, startup_verbose].concat(get_path_array())); @@ -1035,13 +1044,18 @@ function midi_prefs_callback(attrs) { pdgui.resize_window(pd_object_callback); } +function grid_toggle(checked) { + document.getElementById("grid_size").disabled = !checked; + document.getElementById("show_grid").checked = checked; +} + function autopatch_yoffset_toggle(checked) { document.getElementById("autopatch_yoffset_value").disabled = !checked; document.getElementById("autopatch_yoffset").checked = checked; } -function gui_prefs_callback(name, show_grid, save_zoom, browser_doc, browser_path, - browser_init, autopatch_yoffset) { +function gui_prefs_callback(name, show_grid, grid_size, save_zoom, browser_doc, + browser_path, browser_init, autopatch_yoffset) { var s = document.getElementById("gui_preset"); // ag: scan the css subdir for user-defined styles @@ -1071,6 +1085,8 @@ function gui_prefs_callback(name, show_grid, save_zoom, browser_doc, browser_pat } } document.getElementById("show_grid").checked = !!show_grid; + document.getElementById("grid_size").value = grid_size; + grid_toggle(!!show_grid); document.getElementById("save_zoom").checked = !!save_zoom; document.getElementById("browser_doc").checked = !!browser_doc; document.getElementById("browser_path").checked = !!browser_path; diff --git a/pd/nw/locales/de/translation.json b/pd/nw/locales/de/translation.json index 73ccfc8b2cad4fb9d7911edb1f2ac4d748a75394..c2b72f7e3c0479f87ec9297a2cd5601c938582c7 100644 --- a/pd/nw/locales/de/translation.json +++ b/pd/nw/locales/de/translation.json @@ -432,8 +432,8 @@ "footgun": "Fusspistole" }, "grid": { - "show_grid": "Gitter-Hintergrund im Edit-Modus", - "show_grid_tt": "Gitter-Hintergrund im Edit-Modus anzeigen" + "show_grid": "Am Gitter ausrichten (experimentell)", + "show_grid_tt": "Ausrichten am Gitter im Edit-Modus" }, "zoom": { "save_zoom": "Speichern/Laden der Vergrößerung im Patch", diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json index ee65f1aa393cb47133587fdb9a875daddab2284d..7c9ac0e47444773d8cd7601a63a37e4819d527dd 100644 --- a/pd/nw/locales/en/translation.json +++ b/pd/nw/locales/en/translation.json @@ -432,8 +432,8 @@ "footgun": "Footgun" }, "grid": { - "show_grid": "grid background in edit mode", - "show_grid_tt": "Show the grid background in edit mode" + "show_grid": "snap to grid (experimental)", + "show_grid_tt": "Snap to the grid in edit mode" }, "zoom": { "save_zoom": "save/load zoom level with patch", diff --git a/pd/nw/locales/fr/translation.json b/pd/nw/locales/fr/translation.json index ccdc3bc4b7524cabb3a5cd4a4a2b8ac2f9b74667..b397705d8a46942e62e67caa8732c8c2b9954162 100644 --- a/pd/nw/locales/fr/translation.json +++ b/pd/nw/locales/fr/translation.json @@ -432,8 +432,8 @@ "footgun": "Footgun" }, "grid": { - "show_grid": "Fond de grille en mode Édition", - "show_grid_tt": "Afficher l'arrière-plan de la grille en mode Édition" + "show_grid": "Aligner sur la grille (expérimental)", + "show_grid_tt": "Accrocher à la grille en mode Édition" }, "zoom": { "save_zoom": "Sauver/Charger niveau zoom avec patch", diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index dd8d0bb349d523196f6e5797decdad137e47a87d..367550ee2e98c437510eabcd2e949b88f643f8f6 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -1374,36 +1374,146 @@ function menu_send(name) { } } -/* -ico@vt.edu 20200907: added svg tiled background to reflect edit mode and -integrated it into the canvas_set_editmode below. +// Set the grid background position to adjust for the viewBox of the svg. +// We do this separately and before setting the background so we can call this +// when the scroll view needs to be adjusted. +function get_grid_coords(cid, svg_elem) { + var vbox = svg_elem.getAttribute("viewBox").split(" "), + dx = 0, dy = 0; + // First two values of viewBox are x-origin and y-origin. Pd allows + // negative coordinates-- for example, the user can drag an object at + // (0, 0) 12 pixels to the left to arrive at (-12, 0). To accommodate this + // with the svg backend, we would adjust the x-origin to be -12 so that + // the user can view it (possibly by scrolling). These adjustments are + // all handled with gui_canvas_get_scroll. + // + // For the background image css property, everything is based on + // CSS DOM positioning. CSS doesn't really know anything about the SVG + // viewport-- it only knows that an SVG element is of a certain size and + // (in our case) has its top-left corner at the top-left corner of the + // window. So when we change the viewBox to have negative origin indices, + // we have to adjust the origin of the grid in the opposite direction + // For example, if our new x-origin for the svg viewBox is -12, we make + // the x-origin for the background image "12px". This adjustment positions + // the grid *as if* if extended 12 more pixels to the left of its + // container. + if (vbox[0] < 0) { + dx = 0 - vbox[0]; + } + if (vbox[1] < 0) { + dy = 0 - vbox[1]; + } + return { x: dx, y: dy }; +} + +function create_svg_lock(cid) { + var zoom = patchwin[cid].zoomLevel, + size; + // adjust for zoom level + size = 1 / Math.pow(1.2, zoom) * 24; + return "url('data:image/svg+xml;utf8," + + encodeURIComponent(['<svg xmlns="http://www.w3.org/2000/svg"', + ['width="', size, 'px"'].join(""), + ['height="', size, 'px"'].join(""), + 'viewBox="0 0 486.866 486.866"', + '>', + '<path fill="#bbb" d="', + 'M393.904,214.852h-8.891v-72.198c0-76.962-61.075-141.253', + '-137.411-142.625c-2.084-0.038-6.254-0.038-8.338,0', + 'C162.927,1.4,101.853,65.691,101.853,142.653v1.603c0,16.182,', + '13.118,29.3,29.3,29.3c16.182,0,29.299-13.118,29.299-29.3', + 'v-1.603', + 'c0-45.845,37.257-83.752,82.98-83.752s82.981,37.907,82.981,', + '83.752v72.198H92.963c-13.702,0-24.878,14.139-24.878,', + '31.602v208.701', + 'c0,17.44,11.176,31.712,24.878,31.712h300.941c13.703,0,', + '24.878-14.271,24.878-31.712V246.452', + 'C418.783,228.989,407.607,214.852,393.904,214.852z M271.627,', + '350.591v63.062c0,7.222-6.046,13.332-13.273,13.332h-29.841', + 'c-7.228,0-13.273-6.11-13.273-13.332v-63.062c-7.009-6.9-11.09', + '-16.44-11.09-26.993c0-19.999,15.459-37.185,35.115-37.977', + 'c2.083-0.085,6.255-0.085,8.337,0c19.656,0.792,35.115,17.978,', + '35.115,37.977C282.717,334.149,278.637,343.69,271.627,350.591z', + '"/>', + '</svg>', + "')", + ].join(" ")); +} + +// Background for edit mode. Currently, we use a grid if snap-to-grid +// functionality is turned on in the GUI preferences. If not, we just use +// the same grid with a lower opacity. That way the edit mode is always +// visually distinct from run mode. +var create_editmode_bg = function(cid, svg_elem) { + var data, cell_data_str, opacity_str, grid, size, pos; + grid = showgrid[cid]; + size = gridsize[cid]; + pos = get_grid_coords(cid, svg_elem); + // if snap-to-grid isn't turned on, just use cell size of 10 and make the + // grid partially transparent + size = grid ? size : 10; + opacity_str = '"' + (grid ? 1 : 0.4) + '"'; + cell_data_str = ['"', "M", size, 0, "L", 0, 0, 0, size, '"'].join(" "); + + data = ['<svg xmlns="http://www.w3.org/2000/svg" ', + 'width="1000" height="1000" ', + 'opacity=', opacity_str, '>', + '<defs>', + '<pattern id="cell" patternUnits="userSpaceOnUse" ', + 'width="', size, '" height="', size, '">', + '<path fill="none" stroke="#ddd" stroke-width="1" ', + 'd=', cell_data_str,'/>', + '</pattern>', + '<pattern id="grid" patternUnits="userSpaceOnUse" ', + 'width="100" height="100" x="', pos.x, '" y="', pos.y, '">', + '<rect width="500" height="500" fill="url(#cell)" />', + '<path fill="none" stroke="#bbb" stroke-width="1" ', + 'd="M 500 0 L 0 0 0 500"/>', + '</pattern>', + '</defs>', + '<rect width="1000" height="1000" fill="url(#grid)" />', + '</svg>' + ].join(" "); + // make sure to encode the data so we obey all the rules with our data URL + return "url('data:image/svg+xml;utf8," + encodeURIComponent(data) + "')"; +} -LATER: consider adding an interim version that reflects only the ctrl button press -*/ -var gui_editmode_svg_background = "url(\"data:image/svg+xml,%3Csvg " + - "xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 " + - " 100 100'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%239C92AC' fill-opacity" + - "='0.4'%3E%3Cpath opacity='.5' d='M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1" + - "v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-" + - "1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9" + - "H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9" + - "V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v" + - "1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h" + - "9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-1" + - "0 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9" + - "h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-" + - "10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9" + - "h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9" + - "v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h" + - "9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h" + - "9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-1" + - "0 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-" + - "9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm1" + - "0 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9" + - "h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9" + - "h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0" + - "h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z'/%3E%3Cpath d" + - "='M6 5V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E\")"; +function set_bg(cid, data_url, bg_pos, repeat) { + var style = patchwin[cid].window.document.body.style; + style.setProperty("background-image", data_url); + style.setProperty("background-position", bg_pos); + style.setProperty("background-repeat", repeat); +} + +function set_editmode_bg(cid, svg_elem, state) +{ + var offset, zoom; + if (!state) { + set_bg(cid, "none", "0% 0%", "repeat"); + } else if (showgrid[cid]) { + // Show a grid in editmode if we're snapping to grid + set_bg(cid, create_editmode_bg(cid, svg_elem), "0% 0%", "repeat"); + } else { + // Otherwise show a little lock in the top right corner of the patch + // adjusting for zoom level + zoom = patchwin[cid].zoomLevel; + offset = 1 / Math.pow(1.2, zoom) * 5; + offset = offset + "px"; + set_bg(cid, create_svg_lock(cid), + ["right", offset, "top", offset].join(" "), + "no-repeat"); + } +} + +function update_svg_background(cid, svg_elem) { + var bg = patchwin[cid].window.document.body.style + .getPropertyValue("background-image"); + // Quick hack-- we just check whether the background has been drawn. If + // it has we assume we're in editmode. + if (bg !== "none") { + set_editmode_bg(cid, svg_elem, 1); + } +} // requires nw.js API (Menuitem) function canvas_set_editmode(cid, state) { @@ -1411,15 +1521,13 @@ function canvas_set_editmode(cid, state) { w.set_editmode_checkbox(state !== 0 ? true : false); if (state !== 0) { patchsvg.classList.add("editmode"); - if (showgrid[cid]) { - //post("editmode:" + gui_editmode_svg_background); - patchwin[cid].window.document.body.style.setProperty - ("background-image", gui_editmode_svg_background); - } + // For now, we just change the opacity of the background grid + // depending on whether snap-to-grid is turned on. This way + // edit mode is always visually distinct. + set_editmode_bg(cid, patchsvg, true); } else { patchsvg.classList.remove("editmode"); - patchwin[cid].window.document.body.style.setProperty("background-image", - "none"); + set_editmode_bg(cid, patchsvg, false); } }); } @@ -1437,21 +1545,19 @@ function canvas_query_editmode(cid) { exports.canvas_query_editmode = canvas_query_editmode; -function update_grid(grid) { +function update_grid(grid, grid_size_value) { // Update the grid background of all canvas windows when the corresponding // option in the gui prefs changes. - var bg = grid != 0 ? gui_editmode_svg_background : "none"; for (var cid in patchwin) { + showgrid[cid] = grid !== 0; + gridsize[cid] = grid_size_value; gui(cid).get_elem("patchsvg", function(patchsvg, w) { var editmode = patchsvg.classList.contains("editmode"); if (editmode) { - patchwin[cid].window.document.body.style.setProperty - ("background-image", bg); + set_editmode_bg(cid, patchsvg, true); } }); } - // Also update the showgrid flags. - set_showgrid(grid); } exports.update_grid = update_grid; @@ -1713,6 +1819,7 @@ var scroll = {}, font = {}, doscroll = {}, showgrid = {}, + gridsize = {}, last_loaded, // last loaded canvas last_focused, // last focused canvas (doesn't include Pd window or dialogs) loading = {}, @@ -1723,12 +1830,6 @@ var scroll = {}, var patchwin = {}; // object filled with cid: [Window object] pairs var dialogwin = {}; // object filled with did: [Window object] pairs -var set_showgrid = function(grid) { - for (var cid in showgrid) { - showgrid[cid] = grid; - } -} - exports.get_patchwin = function(name) { return patchwin[name]; } @@ -1888,7 +1989,9 @@ 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, warid, hide_scroll, hide_menu, has_toplevel_scalars, cargs) { +function gui_canvas_new(cid, width, height, geometry, grid, grid_size_value, + 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 @@ -1916,6 +2019,7 @@ function gui_canvas_new(cid, width, height, geometry, grid, zoom, editmode, name font[cid] = 10; doscroll[cid] = 0; showgrid[cid] = grid != 0; + gridsize[cid] = grid_size_value; toplevel_scalars[cid] = has_toplevel_scalars; // geometry is just the x/y screen offset "+xoff+yoff" geometry = geometry.slice(1); // remove the leading "+" @@ -6162,10 +6266,10 @@ function gui_midi_properties(gfxstub, sys_indevs, sys_outdevs, } } -function gui_gui_properties(dummy, name, show_grid, save_zoom, browser_doc, browser_path, +function gui_gui_properties(dummy, name, show_grid, grid_size, save_zoom, browser_doc, browser_path, browser_init, autopatch_yoffset) { if (dialogwin["prefs"] !== null) { - dialogwin["prefs"].window.gui_prefs_callback(name, show_grid, save_zoom, + dialogwin["prefs"].window.gui_prefs_callback(name, show_grid, grid_size, save_zoom, browser_doc, browser_path, browser_init, autopatch_yoffset); } } @@ -6739,6 +6843,11 @@ function do_getscroll(cid, checkgeom) { width: width, height: height }); + // Now update the svg's background if we're in edit mode. This adds + // a new background image to the body of the document each time. + // So if there is a performance regression with do_getscroll when + // in editmode, this could be the culprit. + update_svg_background(cid, svg_elem); }); } diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index ef71817264cea7a3ee78a7b194252418b37c434b..d12c47d8dc0b923af8024e2cf92490712120ee39 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -2799,6 +2799,9 @@ void canvas_init_menu(t_canvas *x) gui_vmess("gui_menu_font_set_initial_size", "xi", x, x->gl_font); } +extern int sys_snaptogrid; /* whether we are snapping to grid or not */ +extern int sys_gridsize; + void canvas_vis(t_canvas *x, t_floatarg f) { //fprintf(stderr,"canvas_vis .x%zx %f\n", (t_int)x, f); @@ -2809,7 +2812,6 @@ void canvas_vis(t_canvas *x, t_floatarg f) t_gobj *g; t_int properties; - extern int sys_grid; int flag = (f != 0); if (flag) @@ -2865,12 +2867,13 @@ 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", "xiisiiissiiiiis", + gui_vmess("gui_canvas_new", "xiisiiiissiiiiis", x, (int)(x->gl_screenx2 - x->gl_screenx1), (int)(x->gl_screeny2 - x->gl_screeny1), geobuf, - sys_grid, + sys_snaptogrid, + sys_gridsize, x->gl_zoom, x->gl_edit, x->gl_name->s_name, @@ -3637,6 +3640,8 @@ static int canvas_upx, canvas_upy; static int ctrl_runmode_warned; +static int snap_got_anchor; + /* mouse click */ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which, int mod, int doit) @@ -3646,6 +3651,10 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which, to array_motion so that we can update corresponding send when the array has been changed */ array_garray = NULL; + + /* reset the snap_got_anchor variable so the the snap_to_grid feature + can find its anchor object before it starts to displace a selection */ + snap_got_anchor = 0; //post("canvas_doclick %d", doit); t_gobj *y; @@ -5767,15 +5776,77 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av) extern void graph_checkgop_rect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2); + /* We get the bbox for the object under the mouse the first time around, + then cache its offset from the mouse for future motion messages. + Since there are cases where snapping to a grid can move the object + relative to the mouse pointer, we can't rely on our "anchor" object to + always be directly under the mouse coordinates. */ +static void snap_get_anchor_xy(t_canvas *x, int *gobj_x, int *gobj_y) +{ + t_selection *s = x->gl_editor->e_selection; + int x1, y1, x2, y2; + while (s) + { + if (canvas_hitbox(x, s->sel_what, x->gl_editor->e_xwas, + x->gl_editor->e_ywas, &x1, &y1, &x2, &y2)) + { + *gobj_x = x1; + *gobj_y = y1; + return; + } + s = s->sel_next; + } + bug("canvas_get_snap_offset"); +} +int anchor_xoff; +int anchor_yoff; + +static void canvas_snap_to_grid(t_canvas *x, int xwas, int ywas, int xnew, + int ynew, int *dx, int *dy) +{ + int gsize = sys_gridsize; + /* If we're snapping to grid, we need an initial delta to align + the object under the mouse to the given gridlines. We keep + that in the variables below, which will have no affect after + our initial grid adjustment. */ + int snap_dx = 0, snap_dy = 0; + if (!snap_got_anchor) + { + int obx = xnew, oby = ynew, xsign, ysign; + snap_get_anchor_xy(x, &obx, &oby); + /* First, get the distance the selection should be displaced + in order to align the anchor object with a grid line. */ + + snap_dx = ((obx + gsize / 2 * (obx < 0 ? -1 : 1)) / gsize) * gsize - obx; + snap_dy = ((oby + gsize / 2 * (oby < 0 ? -1 : 1)) / gsize) * gsize - oby; + obx = obx / gsize * gsize; + oby = oby / gsize * gsize; + anchor_xoff = xnew - obx; + anchor_yoff = ynew - oby; + snap_got_anchor = 1; + } + *dx = ((xnew - anchor_xoff + gsize / 2) / gsize) * gsize - + ((xwas - anchor_xoff + gsize / 2) / gsize) * gsize + snap_dx; + *dy = ((ynew - anchor_yoff + gsize / 2) / gsize) * gsize - + ((ywas - anchor_yoff + gsize / 2) / gsize) * gsize + snap_dy; +} static void delay_move(t_canvas *x) { - canvas_displaceselection(x, - x->gl_editor->e_xnew - x->gl_editor->e_xwas, - x->gl_editor->e_ynew - x->gl_editor->e_ywas); - x->gl_editor->e_xwas = x->gl_editor->e_xnew; - x->gl_editor->e_ywas = x->gl_editor->e_ynew; + int dx, dy; + int xwas = x->gl_editor->e_xwas, ywas = x->gl_editor->e_ywas, + xnew = x->gl_editor->e_xnew, ynew = x->gl_editor->e_ynew; + if (sys_snaptogrid) + canvas_snap_to_grid(x, xwas, ywas, xnew, ynew, &dx, &dy); + else + { + dx = xnew - xwas; + dy = ynew - ywas; + } + canvas_displaceselection(x, dx, dy); + x->gl_editor->e_xwas = xnew; + x->gl_editor->e_ywas = ynew; } void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos, diff --git a/pd/src/m_glob.c b/pd/src/m_glob.c index 6fca411ca59a08070c0c2b2fd9ee2a0da4f41eb7..db3b842cf9959e36dd41d02028bf5c50109a2937 100644 --- a/pd/src/m_glob.c +++ b/pd/src/m_glob.c @@ -79,13 +79,14 @@ static void glob_perf(t_pd *dummy, float f) sys_perf = (f != 0); } -extern int sys_grid, sys_zoom, sys_browser_doc, sys_browser_path, sys_browser_init, +extern int sys_snaptogrid, sys_gridsize, sys_zoom, sys_browser_doc, sys_browser_path, sys_browser_init, sys_autopatch_yoffset; extern t_symbol *sys_gui_preset; static void glob_gui_prefs(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { sys_gui_preset = atom_getsymbolarg(0, argc--, argv++); - sys_grid = !!atom_getintarg(0, argc--, argv++); + sys_snaptogrid = !!atom_getintarg(0, argc--, argv++); + sys_gridsize = atom_getintarg(0, argc--, argv++); sys_zoom = !!atom_getintarg(0, argc--, argv++); sys_browser_doc = !!atom_getintarg(0, argc--, argv++); sys_browser_path = !!atom_getintarg(0, argc--, argv++); @@ -96,10 +97,11 @@ static void glob_gui_prefs(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) /* just the gui-preset, the save-zoom toggle and various help browser options for now */ static void glob_gui_properties(t_pd *dummy) { - gui_vmess("gui_gui_properties", "xsiiiiii", + gui_vmess("gui_gui_properties", "xsiiiiiii", dummy, sys_gui_preset->s_name, - sys_grid, + sys_snaptogrid, + sys_gridsize, sys_zoom, sys_browser_doc, sys_browser_path, diff --git a/pd/src/s_file.c b/pd/src/s_file.c index 0f0b18f258c23d9ad266a71eb86638fcb0ccd320..e78cabcc4ff0ae6ec6db62c4c6765ab6d7548de7 100644 --- a/pd/src/s_file.c +++ b/pd/src/s_file.c @@ -42,7 +42,7 @@ #define snprintf sprintf_s #endif -int sys_defeatrt, sys_autopatch_yoffset, sys_grid = 1, sys_zoom, sys_browser_doc = 1, +int sys_defeatrt, sys_autopatch_yoffset, sys_snaptogrid = 1, sys_gridsize = 10, sys_zoom, sys_browser_doc = 1, sys_browser_path, sys_browser_init; t_symbol *sys_flags = &s_; void sys_doflags( void); @@ -671,7 +671,9 @@ void sys_loadpreferences( void) if (sys_getpreference("defeatrt", prefbuf, MAXPDSTRING)) sscanf(prefbuf, "%d", &sys_defeatrt); if (sys_getpreference("showgrid", prefbuf, MAXPDSTRING)) - sscanf(prefbuf, "%d", &sys_grid); + sscanf(prefbuf, "%d", &sys_snaptogrid); + if (sys_getpreference("gridsize", prefbuf, MAXPDSTRING)) + sscanf(prefbuf, "%d", &sys_gridsize); if (sys_getpreference("savezoom", prefbuf, MAXPDSTRING)) sscanf(prefbuf, "%d", &sys_zoom); if (sys_getpreference("browser_doc", prefbuf, MAXPDSTRING)) @@ -819,8 +821,10 @@ void glob_savepreferences(t_pd *dummy) sys_putpreference("nloadlib", buf1); sprintf(buf1, "%d", sys_defeatrt); sys_putpreference("defeatrt", buf1); - sprintf(buf1, "%d", sys_grid); + sprintf(buf1, "%d", sys_snaptogrid); sys_putpreference("showgrid", buf1); + sprintf(buf1, "%d", sys_gridsize); + sys_putpreference("gridsize", buf1); sprintf(buf1, "%d", sys_zoom); sys_putpreference("savezoom", buf1); sprintf(buf1, "%d", sys_browser_doc);