diff --git a/pd/nw/locales/de/translation.json b/pd/nw/locales/de/translation.json index f275b2538bafc1a5086283792b40279d3c5ad527..0dc5423ab061e1139b73bb28c72cbf5a75fc405d 100644 --- a/pd/nw/locales/de/translation.json +++ b/pd/nw/locales/de/translation.json @@ -165,6 +165,8 @@ "zoomout_tt": "Verkleinere die Anzeige des Patches", "zoomreset": "Originalgröße", "zoomreset_tt": "Setze die Anzeige des Patches auf die Originalgröße zurück", + "zoomoptimal": "Optimale Größe", + "zoomoptimal_tt": "Wählt die optimale Größe, mit der der gesamte Patch angezeigt werden kann (soweit möglich)", "fullscreen": "Vollbild", "put": "Hinzufügen", diff --git a/pd/nw/locales/en/translation.json b/pd/nw/locales/en/translation.json index e5cfb44ec8a4c4794de0fd58dacc3c5e06651ac4..7f4cf14fa6f8afc83354e79dacbcf5e1b2d10461 100644 --- a/pd/nw/locales/en/translation.json +++ b/pd/nw/locales/en/translation.json @@ -165,6 +165,8 @@ "zoomout_tt": "Make the patch visually smaller", "zoomreset": "Reset Zoom", "zoomreset_tt": "Reset the zoom to the original level", + "zoomoptimal": "Optimal Zoom", + "zoomoptimal_tt": "Change the zoom to the optimal level which makes the entire patch visible (as far as possible)", "fullscreen": "Fullscreen", "put": "Put", diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js index 2f0b2b170389d7450988006eff07ac70c4ba6041..2f697bebe94fea0e4cf7d0965f7b2b12189243b5 100644 --- a/pd/nw/pd_canvas.js +++ b/pd/nw/pd_canvas.js @@ -1352,10 +1352,18 @@ function nw_create_patch_window_menus(gui, w, name) { pdgui.gui_canvas_get_scroll(name); } }); + minit(m.view.optimalzoom, { + enabled: true, + click: function () { + pdgui.gui_canvas_optimal_zoom(name); + pdgui.gui_canvas_get_scroll(name); + } + }); minit(m.view.zoomreset, { enabled: true, click: function () { gui.Window.get().zoomLevel = 0; + pdgui.gui_canvas_get_scroll(name); } }); minit(m.view.fullscreen, { diff --git a/pd/nw/pd_menus.js b/pd/nw/pd_menus.js index 2121a94d5f371405fa7ce1745bcf4fff1ea723a3..0f87785895fff4e17c7c50265ba592ca02156187 100644 --- a/pd/nw/pd_menus.js +++ b/pd/nw/pd_menus.js @@ -325,6 +325,14 @@ function create_menu(gui, type) { modifiers: cmd_or_ctrl, tooltip: l("menu.zoomreset_tt") })); + if (canvas_menu) { + view_menu.append(m.view.optimalzoom = new gui.MenuItem({ + label: l("menu.zoomoptimal"), + key: "0", + modifiers: cmd_or_ctrl + "+alt", + tooltip: l("menu.zoomoptimal_tt") + })); + } view_menu.append(new gui.MenuItem({ type: "separator" })); view_menu.append(m.view.fullscreen = new gui.MenuItem({ label: l("menu.fullscreen"), @@ -557,11 +565,11 @@ function create_menu(gui, type) { label: l("menu.put"), submenu: put_menu }), 4); - // "Window" menu created from mac builtin above window_menu.insert(new gui.MenuItem({ label: l("menu.media"), submenu: media_menu }), 5); + // "Window" menu created from mac builtin above window_menu.append(new gui.MenuItem({ label: l("menu.help"), submenu: help_menu @@ -585,14 +593,14 @@ function create_menu(gui, type) { submenu: put_menu })); } - window_menu.append(new gui.MenuItem({ - label: l("menu.windows"), - submenu: winman_menu - })); window_menu.append(new gui.MenuItem({ label: l("menu.media"), submenu: media_menu })); + window_menu.append(new gui.MenuItem({ + label: l("menu.windows"), + submenu: winman_menu + })); window_menu.append(new gui.MenuItem({ label: l("menu.help"), submenu: help_menu diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index 09244de1fc77db09573b31da760769c28d572ce3..8b6235abce5d693058ed1d552c0863c31d9c9864 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -4371,17 +4371,11 @@ function gui_undo_menu(cid, undo_text, redo_text) { } } -function do_getscroll(cid) { - var bbox, width, height, min_width, min_height, x, y, - svg; - // Since we're throttling these getscroll calls, they can happen after - // the patch has been closed. We remove the cid from the patchwin - // object on close, so we can just check to see if our Window object has - // been set to null, and if so just return. - // This is an awfully bad pattern. The whole scroll-checking mechanism - // needs to be rethought, but in the meantime this should prevent any - // errors wrt the rendering context disappearing. - if (!patchwin[cid]) { return; } +function canvas_params(cid) +{ + // calculate the canvas parameters (svg bounding box and window geometry) + // for do_getscroll and do_optimalzoom + var bbox, width, height, min_width, min_height, x, y, svg; svg = get_item(cid, "patchsvg"); bbox = svg.getBBox(); // We try to do Pd-extended style canvas origins. That is, coord (0, 0) @@ -4419,6 +4413,21 @@ function do_getscroll(cid) { min_height |= 0; x |= 0; y |= 0; + return { svg: svg, x: x, y: y, w: width, h: height, + mw: min_width, mh: min_height }; +} + +function do_getscroll(cid) { + // Since we're throttling these getscroll calls, they can happen after + // the patch has been closed. We remove the cid from the patchwin + // object on close, so we can just check to see if our Window object has + // been set to null, and if so just return. + // This is an awfully bad pattern. The whole scroll-checking mechanism + // needs to be rethought, but in the meantime this should prevent any + // errors wrt the rendering context disappearing. + if (!patchwin[cid]) { return; } + var { svg: svg, x: x, y: y, w: width, h: height, + mw: min_width, mh: min_height } = canvas_params(cid); if (width < min_width) { width = min_width; } @@ -4458,6 +4467,46 @@ function gui_canvas_get_scroll(cid) { exports.gui_canvas_get_scroll = gui_canvas_get_scroll; +function do_optimalzoom(cid) { + // determine an optimal zoom level that makes the entire patch fit within + // the window + if (!patchwin[cid]) { return; } + var { x: x, y: y, w: width, h: height, mw: min_width, mh: min_height } = + canvas_params(cid); + // Calculate the optimal horizontal and vertical zoom values, + // using floor to always round down to the nearest integer. Note + // that these may well be negative, if the viewport is too small + // for the patch at the current zoom level. XXXREVIEW: We assume a + // zoom factor of 1.2 here; this works for me on Linux, but I'm + // not sure how portable it is. -ag + var zx = 0, zy = 0; + if (width>0) zx = Math.floor(Math.log(min_width/width)/Math.log(1.2)); + if (height>0) zy = Math.floor(Math.log(min_height/height)/Math.log(1.2)); + // Optimal zoom is the minimum of the horizontal and vertical zoom + // values. This gives us the offset to the current zoom level. We + // then need to clamp the resulting new zoom level to the valid + // zoom level range of -8..+7. + var actz = patchwin[cid].zoomLevel, z = actz+Math.min(zx, zy); + if (z < -8) z = -8; if (z > 7) z = 7; + //post("bbox: "+width+"x"+height+"+"+x+"+"+y+" window size: "+min_width+"x"+min_height+" current zoom level: "+actz+" optimal zoom level: "+z); + if (z != actz) { + patchwin[cid].zoomLevel = z; + } +} + +var optimalzoom_var = {}; + +// We use a setTimeout here as with do_getscroll above, but we have to +// use a smaller value here, so that we're done before a subsequent +// call to do_getscroll updates the viewport. XXXREVIEW: Hopefully +// 100 msec are enough for do_optimalzoom to finish. +function gui_canvas_optimal_zoom(cid) { + clearTimeout(optimalzoom_var[cid]); + optimalzoom_var[cid] = setTimeout(do_optimalzoom, 150, cid); +} + +exports.gui_canvas_optimal_zoom = gui_canvas_optimal_zoom; + // handling the selection function gui_lower(cid, tag) { var svg = patchwin[cid].window.document.getElementById("patchsvg"),