important progress

This commit is contained in:
Joeri Exelmans 2025-10-04 23:42:48 +02:00
parent a72653fcce
commit 9bb5157d5d
3 changed files with 26 additions and 87 deletions

View file

@ -1,21 +1,5 @@
# bun-react-template ![logo](./logo.png)
To install dependencies: # StateBuddy
```bash dependencies, bla, bla
bun install
```
To start a development server:
```bash
bun dev
```
To run for production:
```bash
bun start
```
This project was created using `bun init` in bun v1.2.14. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View file

@ -47,10 +47,6 @@ type DraggingState = {
lastMousePos: Vec2D; lastMousePos: Vec2D;
} | null; // null means: not dragging } | null; // null means: not dragging
type ResizingState = {
lastMousePos: Vec2D;
} | null; // null means: not resizing
type SelectingState = Rect2D | null; type SelectingState = Rect2D | null;
@ -76,7 +72,6 @@ const minStateSize = {x: 40, y: 40};
export function VisualEditor() { export function VisualEditor() {
const [state, setState] = useState<VisualEditorState>(onOffStateMachine); const [state, setState] = useState<VisualEditorState>(onOffStateMachine);
const [dragging, setDragging] = useState<DraggingState>(null); const [dragging, setDragging] = useState<DraggingState>(null);
const [resizing, setResizing] = useState<ResizingState>(null);
const [mode, setMode] = useState<"state"|"transition"|"text">("state"); const [mode, setMode] = useState<"state"|"transition"|"text">("state");
@ -107,10 +102,13 @@ export function VisualEditor() {
const currentPointer = {x: e.clientX, y: e.clientY}; const currentPointer = {x: e.clientX, y: e.clientY};
if (e.button === 1) { if (e.button === 1) {
// ignore selection, always insert rountangle // ignore selection, middle mouse button always inserts
setState(state => { setState(state => {
const newID = state.nextID.toString(); const newID = state.nextID.toString();
setSelection([newID]); setSelection([{uid: newID, parts: ["bottom", "right"]}]);
setDragging({
lastMousePos: currentPointer,
});
return { return {
...state, ...state,
rountangles: [...state.rountangles, { rountangles: [...state.rountangles, {
@ -122,9 +120,11 @@ export function VisualEditor() {
nextID: state.nextID+1, nextID: state.nextID+1,
}; };
}); });
setResizing({lastMousePos: currentPointer}); return;
} }
else if (e.button === 0) {
if (e.button === 0) {
// left mouse button on a shape will drag that shape (and everything else that's selected). if the shape under the pointer was not in the selection then the selection is reset to contain only that shape.
const uid = e.target?.dataset.uid; const uid = e.target?.dataset.uid;
const parts: string[] = e.target?.dataset.parts?.split(' ') || []; const parts: string[] = e.target?.dataset.parts?.split(' ') || [];
if (uid) { if (uid) {
@ -138,28 +138,20 @@ export function VisualEditor() {
if (!allPartsInSelection) { if (!allPartsInSelection) {
setSelection([{uid, parts, kind: "dontcare"}]); setSelection([{uid, parts, kind: "dontcare"}]);
} }
// left mouse button: select and drag
setDragging({ setDragging({
lastMousePos: currentPointer, lastMousePos: currentPointer,
}); });
// // right mouse button: select and resize return;
// else if (e.button === 2) {
// setResizing({
// lastMousePos: currentPointer,
// });
// }
} }
else { }
// otherwise, just start making a selection
setDragging(null); setDragging(null);
setResizing(null);
setSelectingState({ setSelectingState({
topLeft: currentPointer, topLeft: currentPointer,
size: {x: 0, y: 0}, size: {x: 0, y: 0},
}); });
setSelection([]); setSelection([]);
}
}
}; };
const onMouseMove = (e: MouseEvent) => { const onMouseMove = (e: MouseEvent) => {
@ -195,31 +187,6 @@ export function VisualEditor() {
return {lastMousePos: currentPointer}; return {lastMousePos: currentPointer};
}); });
} }
else if (resizing) {
setResizing(prevResizeState => {
const pointerDelta = subtractV2D(currentPointer, prevResizeState!.lastMousePos);
const halfPointerDelta = scaleV2D(pointerDelta, 0.5);
setState(state => ({
...state,
rountangles: state.rountangles.map(r => {
if (selection.includes(r.uid)) {
const newSize = addV2D(r.size, halfPointerDelta);
return {
...r,
size: {
x: Math.max(newSize.x, minStateSize.x),
y: Math.max(newSize.y, minStateSize.y),
},
};
}
else {
return r; // no change
}
}),
}));
return {lastMousePos: currentPointer};
});
}
else if (selectingState) { else if (selectingState) {
setSelectingState(ss => { setSelectingState(ss => {
const selectionSize = subtractV2D(currentPointer, ss!.topLeft); const selectionSize = subtractV2D(currentPointer, ss!.topLeft);
@ -233,7 +200,6 @@ export function VisualEditor() {
const onMouseUp = (e: MouseEvent) => { const onMouseUp = (e: MouseEvent) => {
setDragging(null); setDragging(null);
setResizing(null);
setSelectingState(ss => { setSelectingState(ss => {
if (ss) { if (ss) {
// we were making a selection // we were making a selection
@ -263,17 +229,6 @@ export function VisualEditor() {
uid, uid,
parts: [...parts], parts: [...parts],
}))); })));
// const selected = [
// ...state.rountangles.filter(rountangle =>
// isEntirelyWithin(rountangle, normalizedSS)),
// ...state.arrows.filter(arrow => isEntirelyWithin({
// topLeft: arrow.start,
// size: subtractV2D(arrow.end, arrow.start),
// }, normalizedSS)),
// ];
// setSelection(selected.map(r => r.uid));
} }
return null; // no longer selecting return null; // no longer selecting
}); });
@ -290,7 +245,7 @@ export function VisualEditor() {
setSelection(selection => { setSelection(selection => {
setState(state => ({ setState(state => ({
...state, ...state,
rountangles: state.rountangles.filter(r => !selection.includes(r.uid)), rountangles: state.rountangles.filter(r => !selection.some(rs => rs.uid === r.uid)),
})); }));
return []; return [];
}); });
@ -340,7 +295,7 @@ export function VisualEditor() {
window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("mouseup", onMouseUp); window.removeEventListener("mouseup", onMouseUp);
}; };
}, [selectingState, dragging, resizing]); }, [selectingState, dragging]);
return <svg width="100%" height="100%" return <svg width="100%" height="100%"
className="svgCanvas" className="svgCanvas"
@ -383,7 +338,7 @@ export function VisualEditor() {
Left mouse button: Select/Drag. Left mouse button: Select/Drag.
</text> </text>
<text x={5} y={40}> <text x={5} y={40}>
Right mouse button: Resize. Right mouse button: Select only.
</text> </text>
<text x={5} y={60}> <text x={5} y={60}>
Middle mouse button: Insert [S]tates / [T]ransitions / Te[X]t (current mode: {mode})</text> Middle mouse button: Insert [S]tates / [T]ransitions / Te[X]t (current mode: {mode})</text>