feat(editor): the three-dot button in the simulation too

A tap on a device in the simulation now also chooses it, so its three-dot
button shows as in the design, wherever the simulation's menu offers
something (the desktop, each card's data exchange; a switch has none).
Java's action of the tap stays (desktop, switch and NAT tables), a tap
beside lets go. The device sheet stays closed — the design is locked — and
the others see no frame. Java opens that menu only with a right click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 15:51:13 +00:00
co-authored by Claude Opus 5.5
parent fb1a467221
commit 1593726447
5 changed files with 66 additions and 9 deletions
+13 -6
View File
@@ -77,9 +77,10 @@ export interface CanvasProps {
/** A cable drawn active, as Java draws the cable of the card whose tab is open (Kabel.setAktiv). */
readonly highlightedLink?: string | null;
/**
* The simulation: a tap on a device activates it (a computer's desktop),
* a long press opens its menu; nothing moves, nothing is selected, as in
* Java's simulation mode. The documentation mode: see above.
* The simulation: a tap on a device activates it (a computer's desktop)
* and chooses it, so that its three-dot button shows as in the design; a
* long press opens its menu; nothing moves, as in Java's simulation mode.
* The documentation mode: see above.
*/
readonly mode?: 'design' | 'simulation' | 'documentation';
/**
@@ -97,6 +98,8 @@ export interface CanvasProps {
/** The cables that carry a frame now, drawn as Java draws them then (JCablePanel.farbeBlinken). */
readonly activeLinks?: ReadonlySet<string>;
readonly onActivate?: (id: string) => void;
/** In the simulation: whether the chosen device has a menu at all (a switch has none) — only then its three-dot button. */
readonly hasMenu?: (target: Selection) => boolean;
}
const NO_LINKS: ReadonlySet<string> = new Set();
@@ -274,6 +277,7 @@ export const Canvas = forwardRef<CanvasHandle, CanvasProps>(function Canvas(
chosenBy = NO_CHOICES,
activeLinks = NO_LINKS,
onActivate,
hasMenu,
onDocFrame,
renderDocText,
},
@@ -542,7 +546,7 @@ export const Canvas = forwardRef<CanvasHandle, CanvasProps>(function Canvas(
return;
}
if (now.kind === 'background') {
if (!now.moved && !simulating) {
if (!now.moved) {
onSelect?.(null);
if (cableFrom !== null) onCableStart?.(null);
}
@@ -554,7 +558,10 @@ export const Canvas = forwardRef<CanvasHandle, CanvasProps>(function Canvas(
}
if (now.longPressed) return;
if (simulating) {
if (!now.moved) onActivate?.(now.id);
if (!now.moved) {
onSelect?.({ kind: 'device', id: now.id });
onActivate?.(now.id);
}
return;
}
if (locked) {
@@ -706,7 +713,7 @@ export const Canvas = forwardRef<CanvasHandle, CanvasProps>(function Canvas(
const corner = toScreen(current, { x: item.x, y: item.y });
return renderDocText(item, { left: corner.x, top: corner.y, width: item.width * current.scale, height: item.height * current.scale, scale: current.scale });
})()}
{menuButton === null || selection === null || simulating || locked ? null : (
{menuButton === null || selection === null || (simulating ? hasMenu?.(selection) !== true : locked) ? null : (
<button
type="button"
className="device-menu-button"