Make mouse behavior better

This commit is contained in:
dylan 2023-05-08 23:14:01 -07:00
parent 7f9e873323
commit b248a016a9
2 changed files with 72 additions and 6 deletions

View File

@ -177,6 +177,7 @@ const transformForPaste = (text: string) => {
} }
const state = { const state = {
doubleClickTimer: 0,
history: [] as Array<{code: string, anchor: number, focus: number}>, history: [] as Array<{code: string, anchor: number, focus: number}>,
historyDebounce: 0, historyDebounce: 0,
historyIndex: 0, historyIndex: 0,
@ -222,6 +223,7 @@ const state = {
} }
this.historyDebounce = historyDebounceFrames; this.historyDebounce = historyDebounceFrames;
}, },
wordMode: false,
scrollX: 0, scrollX: 0,
scrollY: 0, scrollY: 0,
anchor: 0, anchor: 0,
@ -240,6 +242,34 @@ const state = {
clampInRange(n: number) { clampInRange(n: number) {
return Math.max(0, Math.min(n, this.code.length)) return Math.max(0, Math.min(n, this.code.length))
}, },
findNearestWordBoundaryLeft(index: number) {
if (index === this.code.length-1) {
return index;
}
const words1 = this.code.slice(0, index+1).split(/\b/g);
if (words1[words1.length-1].length === 1) {
return index;
}
const words = this.code.slice(0, index).split(/\b/g);
if (!words.length) {
return 0;
}
return index-words[words.length-1].length;
},
findNearestWordBoundaryRight(index: number) {
if (index === 0) {
return index;
}
const words1 = this.code.slice(index-1).split(/\b/g);
if (words1[0].length === 1) {
return index;
}
const words = this.code.slice(index).split(/\b/g);
if (!words.length) {
return this.code.length;
}
return index+words[0].length;
},
setSelection(anchor: number | {x: number, y: number}, focus?: number | {x: number, y: number}) { setSelection(anchor: number | {x: number, y: number}, focus?: number | {x: number, y: number}) {
if (typeof anchor !== "number") { if (typeof anchor !== "number") {
anchor = gridToIndex(this.code, anchor.x, anchor.y); anchor = gridToIndex(this.code, anchor.x, anchor.y);
@ -248,14 +278,36 @@ const state = {
if (typeof focus !== "number") { if (typeof focus !== "number") {
focus = gridToIndex(this.code, focus.x, focus.y); focus = gridToIndex(this.code, focus.x, focus.y);
} }
this.anchor = this.clampInRange(anchor), this.anchor = this.clampInRange(anchor);
this.focus = this.clampInRange(focus); this.focus = this.clampInRange(focus);
if (this.wordMode) {
console.log('word mode', this.anchor, this.focus, this.findNearestWordBoundaryLeft(this.anchor), this.findNearestWordBoundaryRight(this.focus));
if (this.anchor <= this.focus) {
this.anchor = this.findNearestWordBoundaryLeft(this.anchor);
this.focus = this.findNearestWordBoundaryRight(this.focus);
} else {
this.anchor = this.findNearestWordBoundaryRight(this.anchor);
this.focus = this.findNearestWordBoundaryLeft(this.focus);
}
}
this.anchor = this.clampInRange(this.anchor);
this.focus = this.clampInRange(this.focus);
}, },
setFocus(focus: number | {x: number, y: number}) { setFocus(focus: number | {x: number, y: number}) {
if (typeof focus !== "number") { if (typeof focus !== "number") {
focus = gridToIndex(this.code, focus.x, focus.y); focus = gridToIndex(this.code, focus.x, focus.y);
} }
this.focus = this.clampInRange(focus); this.focus = this.clampInRange(focus);
if (this.wordMode) {
if (this.anchor <= this.focus) {
this.anchor = this.findNearestWordBoundaryLeft(this.anchor);
this.focus = this.findNearestWordBoundaryRight(this.focus);
} else {
this.anchor = this.findNearestWordBoundaryRight(this.anchor);
this.focus = this.findNearestWordBoundaryLeft(this.focus);
}
}
this.focus = this.clampInRange(this.focus);
}, },
insertText(text: string) { insertText(text: string) {
const {code, anchor, focus} = this; const {code, anchor, focus} = this;
@ -453,13 +505,23 @@ const update = async () => {
state.snapshot(); state.snapshot();
} }
} }
if (state.doubleClickTimer > 0) {
state.doubleClickTimer -= 1;
}
if (mouseDown()) { if (mouseDown() && !shiftKeyDown()) {
if (state.doubleClickTimer > 0) {
state.wordMode = true;
} else {
state.doubleClickTimer = 10;
}
const {x, y} = mousePos(); const {x, y} = mousePos();
state.setSelection(pixelToIndex(state.code, x, y-8)); state.setSelection(pixelToIndex(state.code, x, y-8));
} else if (mouseHeld()) { } else if (mouseHeld()) {
const {x, y} = mousePos(); const {x, y} = mousePos();
state.setFocus(pixelToIndex(state.code, x, y-8)); state.setFocus(pixelToIndex(state.code, x, y-8));
} else {
state.wordMode = false;
} }
const keyboardString = getKeyboardString(); const keyboardString = getKeyboardString();

View File

@ -14,7 +14,7 @@ const mouseButtonsDown = {
[M.MIDDLE]: false, [M.MIDDLE]: false,
}; };
const mouseEvents: Array<{ const mouseEvents: Array<{
type: "click" | "down" | "up" | "move", type: "click" | "down" | "up" | "move" | "dblclick",
button: typeof M[keyof typeof M], button: typeof M[keyof typeof M],
x: number, x: number,
y: number, y: number,
@ -35,9 +35,9 @@ const eventPixelCoords = (evt: WindowMouseEvent) => {
} }
} }
// addEventListener("dblclick", (evt) => { addEventListener("dblclick", (evt) => {
// console.log("dblclick", evt.button, evt.clientX, evt.clientY); mouseEvents.push({type: "dblclick", button: evt.button, ...eventPixelCoords(evt)});
// }); });
addEventListener("click", (evt) => { addEventListener("click", (evt) => {
mouseEvents.push({type: "click", button: evt.button, ...eventPixelCoords(evt)}); mouseEvents.push({type: "click", button: evt.button, ...eventPixelCoords(evt)});
@ -87,6 +87,10 @@ export const mouseClick = (button: number = M.LEFT) => {
return mouseEvents.some(ev => ev.button === button && ev.type === "click"); return mouseEvents.some(ev => ev.button === button && ev.type === "click");
} }
export const mouseDoubleClick = (button: number = M.LEFT) => {
return mouseEvents.some(ev => ev.button === button && ev.type === "dblclick");
}
export const mouseHeld = (button: number = M.LEFT) => { export const mouseHeld = (button: number = M.LEFT) => {
return mouseButtonsDown[button]; return mouseButtonsDown[button];
} }