A press with the middle (or any other non-left) mouse button never reaches the Studio's drag, place or select handlers: dragging pans the view even on a selected object or while placing, and a click selects nothing. A middle click no longer starts the browser's autoscroll. check_studio covers a middle-drag on the selected truck (it stays put, the view moves), a middle click on another object (the selection is kept), and a middle-drag while placing (nothing is placed).
This commit is contained in:
1 parent
95ea4a8512
commit
7962249191
3 files changed
+48
-4
No files matched your search
+1
-1
@@ -70,7 +70,7 @@ document.documentElement.setAttribute("data-theme",t);})();
|
|||||||
<tr><th>Turn</th><td>R / Shift+R, or the ⟲ ⟳ buttons</td></tr>
|
<tr><th>Turn</th><td>R / Shift+R, or the ⟲ ⟳ buttons</td></tr>
|
||||||
<tr><th>Copy / delete</th><td>Ctrl+D / Delete</td></tr>
|
<tr><th>Copy / delete</th><td>Ctrl+D / Delete</td></tr>
|
||||||
<tr><th>Undo / redo</th><td>Ctrl+Z / Ctrl+Y</td></tr>
|
<tr><th>Undo / redo</th><td>Ctrl+Z / Ctrl+Y</td></tr>
|
||||||
<tr><th>View</th><td>drag the ground to pan, Ctrl + wheel or pinch to zoom, ↺ ↻ to rotate, levels to look inside</td></tr>
|
<tr><th>View</th><td>drag the ground to pan, or drag with the middle mouse button anywhere (it never moves an object); Ctrl + wheel or pinch to zoom, ↺ ↻ to rotate, levels to look inside</td></tr>
|
||||||
<tr><th>Agent</th><td>✦ Agent opens a chat with a language model that edits the scene for you; Undo takes its steps back. Drag the window by its title, resize it at the top-left corner</td></tr>
|
<tr><th>Agent</th><td>✦ Agent opens a chat with a language model that edits the scene for you; Undo takes its steps back. Drag the window by its title, resize it at the top-left corner</td></tr>
|
||||||
<tr><th>MCP</th><td>connect an AI agent over MCP; its edits appear here live (see the panel when nothing is selected)</td></tr>
|
<tr><th>MCP</th><td>connect an AI agent over MCP; its edits appear here live (see the panel when nothing is selected)</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -198,6 +198,43 @@ with sync_playwright() as p:
|
|||||||
pg.evaluate("__studio.select(null)")
|
pg.evaluate("__studio.select(null)")
|
||||||
pg.wait_for_timeout(400)
|
pg.wait_for_timeout(400)
|
||||||
|
|
||||||
|
# the middle mouse button only moves the camera: it never drags, selects or places anything
|
||||||
|
pg.locator('#objects li[data-id="truck"]').click()
|
||||||
|
pg.evaluate("__studio.view.focus('truck', 3)")
|
||||||
|
pg.wait_for_timeout(400)
|
||||||
|
t0 = obj("truck")
|
||||||
|
p0 = at(t0["x"], t0["y"])
|
||||||
|
tb = pg.locator('.iso-svg g[data-obj="truck"] path.iso-t').first.bounding_box()
|
||||||
|
mx, my = tb["x"] + tb["width"] / 2, tb["y"] + tb["height"] / 2
|
||||||
|
pg.mouse.move(mx, my)
|
||||||
|
pg.mouse.down(button="middle")
|
||||||
|
for i in range(1, 11):
|
||||||
|
pg.mouse.move(mx + 8 * i, my + 5 * i)
|
||||||
|
pg.wait_for_timeout(15)
|
||||||
|
pg.mouse.up(button="middle")
|
||||||
|
pg.wait_for_timeout(600)
|
||||||
|
t1, p1 = obj("truck"), at(t0["x"], t0["y"])
|
||||||
|
check((t1["x"], t1["y"]) == (t0["x"], t0["y"]) and abs(p1[0] - p0[0] - 80) < 3 and abs(p1[1] - p0[1] - 50) < 3,
|
||||||
|
f"a middle-drag on the selected truck pans the view and leaves the truck where it was (moved {p1[0] - p0[0]:.0f}, {p1[1] - p0[1]:.0f} px)")
|
||||||
|
gb = pg.locator('.iso-svg g[data-obj="genset"] path.iso-t').first.bounding_box()
|
||||||
|
pg.mouse.click(gb["x"] + gb["width"] / 2, gb["y"] + gb["height"] / 2, button="middle")
|
||||||
|
pg.wait_for_timeout(400)
|
||||||
|
check(pg.evaluate("__studio.S.sel") == "truck", "a middle click on another object does not select it")
|
||||||
|
n2 = len(doc()["objects"])
|
||||||
|
pg.locator('.st-tile[data-type="tree"]').click()
|
||||||
|
pg.mouse.move(mx, my)
|
||||||
|
pg.mouse.down(button="middle")
|
||||||
|
for i in range(1, 11):
|
||||||
|
pg.mouse.move(mx - 8 * i, my - 5 * i)
|
||||||
|
pg.wait_for_timeout(15)
|
||||||
|
pg.mouse.up(button="middle")
|
||||||
|
pg.wait_for_timeout(600)
|
||||||
|
check(len(doc()["objects"]) == n2 and pg.evaluate("__studio.S.placing") == "tree",
|
||||||
|
"while placing, a middle-drag pans and places nothing")
|
||||||
|
pg.keyboard.press("Escape")
|
||||||
|
pg.evaluate("__studio.select(null)")
|
||||||
|
pg.wait_for_timeout(300)
|
||||||
|
|
||||||
# an agent edits over MCP: the open Studio follows
|
# an agent edits over MCP: the open Studio follows
|
||||||
init = mcp({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "test", "version": "0"}}})
|
init = mcp({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "test", "version": "0"}}})
|
||||||
check(init["result"]["serverInfo"]["name"] == "isokit", "MCP initialize")
|
check(init["result"]["serverInfo"]["name"] == "isokit", "MCP initialize")
|
||||||
|
|||||||
+10
-3
@@ -286,10 +286,14 @@
|
|||||||
var ptrs = {}, down = null, moved = false, pinch = null, hoverId = null, claimed = false;
|
var ptrs = {}, down = null, moved = false, pinch = null, hoverId = null, claimed = false;
|
||||||
function npt() { return Object.keys(ptrs).length; }
|
function npt() { return Object.keys(ptrs).length; }
|
||||||
svg.addEventListener("pointerdown", function (e) {
|
svg.addEventListener("pointerdown", function (e) {
|
||||||
|
// the middle (or any other non-left) mouse button only moves the camera: it never
|
||||||
|
// drags, places or selects an object, whatever is under the pointer
|
||||||
|
var cam = e.pointerType === "mouse" && e.button !== 0;
|
||||||
|
if (cam && e.button === 1) e.preventDefault();
|
||||||
ptrs[e.pointerId] = { x: e.clientX, y: e.clientY };
|
ptrs[e.pointerId] = { x: e.clientX, y: e.clientY };
|
||||||
if (npt() === 1) {
|
if (npt() === 1) {
|
||||||
down = { x: e.clientX, y: e.clientY, id: e.pointerId, t: e.target }; moved = false;
|
down = { x: e.clientX, y: e.clientY, id: e.pointerId, t: e.target, cam: cam }; moved = false;
|
||||||
claimed = !!(opts.interact && call(opts.interact.down, e, { obj: targetObj(e.target), id: targetId(e.target), world: toWorld(e.clientX, e.clientY, 0) }));
|
claimed = !cam && !!(opts.interact && call(opts.interact.down, e, { obj: targetObj(e.target), id: targetId(e.target), world: toWorld(e.clientX, e.clientY, 0) }));
|
||||||
if (claimed) { try { svg.setPointerCapture(e.pointerId); } catch (er) { /* ignore */ } }
|
if (claimed) { try { svg.setPointerCapture(e.pointerId); } catch (er) { /* ignore */ } }
|
||||||
}
|
}
|
||||||
if (npt() === 2) {
|
if (npt() === 2) {
|
||||||
@@ -336,12 +340,15 @@
|
|||||||
if (npt() < 2) pinch = null;
|
if (npt() < 2) pinch = null;
|
||||||
if (wasDown) {
|
if (wasDown) {
|
||||||
if (claimed) call(opts.interact.up, e, { moved: moved, world: toWorld(e.clientX, e.clientY, 0), cancel: e.type !== "pointerup" });
|
if (claimed) call(opts.interact.up, e, { moved: moved, world: toWorld(e.clientX, e.clientY, 0), cancel: e.type !== "pointerup" });
|
||||||
else if (!moved && e.type === "pointerup") pick(e.target, e.clientX, e.clientY);
|
else if (!moved && !down.cam && e.type === "pointerup") pick(e.target, e.clientX, e.clientY);
|
||||||
}
|
}
|
||||||
if (npt() === 0) { down = null; claimed = false; wrap.classList.remove("iso-dragging"); }
|
if (npt() === 0) { down = null; claimed = false; wrap.classList.remove("iso-dragging"); }
|
||||||
}
|
}
|
||||||
svg.addEventListener("pointerup", up);
|
svg.addEventListener("pointerup", up);
|
||||||
svg.addEventListener("pointercancel", up);
|
svg.addEventListener("pointercancel", up);
|
||||||
|
// no browser autoscroll or paste on a middle click
|
||||||
|
svg.addEventListener("mousedown", function (e) { if (e.button === 1) e.preventDefault(); });
|
||||||
|
svg.addEventListener("auxclick", function (e) { if (e.button === 1) e.preventDefault(); });
|
||||||
svg.addEventListener("pointerleave", function (e) { if (e.pointerType === "mouse" && hoverId) { setHover(hoverId, false); hoverId = null; if (!st.sel) hideTip(); } });
|
svg.addEventListener("pointerleave", function (e) { if (e.pointerType === "mouse" && hoverId) { setHover(hoverId, false); hoverId = null; if (!st.sel) hideTip(); } });
|
||||||
svg.addEventListener("wheel", function (e) {
|
svg.addEventListener("wheel", function (e) {
|
||||||
if (!(e.ctrlKey || e.metaKey || opts.wheelZoom)) return;
|
if (!(e.ctrlKey || e.metaKey || opts.wheelZoom)) return;
|
||||||
|
|||||||
Reference in new issue
Block a user