diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index 28cb36bd1a1b9479a05ce6291fe83fa820e6f6e0..48fa6fabadc4229f7cd9d50d7a6ef5c97fe95bd1 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -1440,6 +1440,51 @@ var create_editmode_background = function(grid, size) { return "url('data:image/svg+xml;utf8," + head + body + tail + "')"; } +// 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 set_grid_position(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]; + } + patchwin[cid].window.document.body.style + .setProperty("background-position", + dx + "px " + dy + "px"); +} + +function set_editmode_bg(cid, svg_elem, state) +{ + // If we're setting the bg, figure out the correct offset first + if (state) { + set_grid_position(cid, svg_elem); + } + patchwin[cid].window.document.body.style.setProperty("background-image", + state ? + create_editmode_background(showgrid[cid], gridsize[cid]) : "none"); +} + // requires nw.js API (Menuitem) function canvas_set_editmode(cid, state) { gui(cid).get_elem("patchsvg", function(patchsvg, w) { @@ -1449,14 +1494,10 @@ function canvas_set_editmode(cid, state) { // 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. - patchwin[cid].window.document.body.style - .setProperty("background-image", - create_editmode_background(showgrid[cid], gridsize[cid])); + 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); } }); } @@ -1478,17 +1519,15 @@ function update_grid(grid, grid_size_value) { // Update the grid background of all canvas windows when the corresponding // option in the gui prefs changes. 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", create_editmode_background(grid !== 0, - grid_size_value)); + set_editmode_bg(cid, patchsvg, true); } }); } - // Also update the showgrid flags. - set_grid(grid, grid_size_value); } exports.update_grid = update_grid; @@ -1761,14 +1800,6 @@ var scroll = {}, var patchwin = {}; // object filled with cid: [Window object] pairs var dialogwin = {}; // object filled with did: [Window object] pairs -var set_grid = function(grid, gridsize_value) { - var cid; - for (cid in showgrid) { - showgrid[cid] = grid; - gridsize[cid] = gridsize_value; - } -} - exports.get_patchwin = function(name) { return patchwin[name]; } @@ -6779,6 +6810,9 @@ function do_getscroll(cid, checkgeom) { width: width, height: height }); + // Now that we've updated the svg's viewBox, adjust the background + // position for the grid so it lines up properly with the patch. + set_grid_position(cid, svg_elem); }); } diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index 21cd923bb85df2df3fb37a4ad1930524979788e7..d12c47d8dc0b923af8024e2cf92490712120ee39 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -5813,13 +5813,13 @@ static void canvas_snap_to_grid(t_canvas *x, int xwas, int ywas, int xnew, int snap_dx = 0, snap_dy = 0; if (!snap_got_anchor) { - int obx = xnew, oby = ynew; + 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) / gsize) * gsize - obx; - snap_dy = ((oby + gsize / 2) / gsize) * gsize - oby; + 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;