Returning coords with Clickable event. Usinsg them to position cursor when clicking in a textfield
This commit is contained in:
parent
787e071fbd
commit
9f078aaeef
5 changed files with 68 additions and 15 deletions
|
|
@ -8,7 +8,7 @@ view = count \
|
||||||
children = [
|
children = [
|
||||||
Text({ content = str(count), x = 0, y = 20 }),
|
Text({ content = str(count), x = 0, y = 20 }),
|
||||||
Clickable {
|
Clickable {
|
||||||
event = "increment",
|
event = Increment,
|
||||||
child = Rect { w = 100, h = 40, color = "blue" }
|
child = Rect { w = 100, h = 40, color = "blue" }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,27 @@ export function runApp(app: App, canvas: HTMLCanvasElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const event = hitTest(x, y);
|
const hitResult = hitTest(x, y);
|
||||||
if (event) {
|
if (hitResult) {
|
||||||
|
const { event, relativeX, relativeY } = hitResult;
|
||||||
|
|
||||||
|
if (event.kind === 'constructor') {
|
||||||
|
const eventWithCoords: Value = {
|
||||||
|
kind: 'constructor',
|
||||||
|
name: event.name,
|
||||||
|
args: [{
|
||||||
|
kind: 'record',
|
||||||
|
fields: {
|
||||||
|
x: { kind: 'int', value: Math.floor(relativeX) },
|
||||||
|
y: { kind: 'int', value: Math.floor(relativeY) },
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
handleEvent(eventWithCoords);
|
||||||
|
} else {
|
||||||
handleEvent(event);
|
handleEvent(event);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('keydown', (e) => {
|
window.addEventListener('keydown', (e) => {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,31 @@
|
||||||
routeKeyToFocused = state event \
|
routeKeyToFocused = state event \
|
||||||
(state.focusedInput == "email"
|
(state.focusedInput == "email"
|
||||||
| True \
|
| True \
|
||||||
newInputState = textInput2.update state.email event;
|
newInputState = textInput.update state.email event;
|
||||||
state.{ email = newInputState }
|
state.{ email = newInputState }
|
||||||
| False \
|
| False \
|
||||||
newInputState = textInput2.update state.password event;
|
newInputState = textInput.update state.password event;
|
||||||
state.{ password = newInputState });
|
state.{ password = newInputState });
|
||||||
|
|
||||||
init = {
|
init = {
|
||||||
focusedInput = "email",
|
focusedInput = "email",
|
||||||
email = textInput2.init "",
|
email = textInput.init "",
|
||||||
password = textInput2.init ""
|
password = textInput.init ""
|
||||||
};
|
};
|
||||||
|
|
||||||
update = state event \ event
|
update = state event \ event
|
||||||
| FocusEmail \ state.{ focusedInput = "email" }
|
| FocusEmail coords \ (
|
||||||
| FocusPassword \ state.{ focusedInput = "password" }
|
newState = state.{ focusedInput = "email" };
|
||||||
|
newInputState = textInput.update state.email (Clicked coords);
|
||||||
|
newState.{ email = newInputState }
|
||||||
|
)
|
||||||
|
|
||||||
|
| FocusPassword coords \ (
|
||||||
|
newState = state.{ focusedInput = "password" };
|
||||||
|
newInputState = textInput.update state.password (Clicked coords);
|
||||||
|
newState.{ password = newInputState }
|
||||||
|
)
|
||||||
|
|
||||||
| ArrowLeft \ routeKeyToFocused state ArrowLeft
|
| ArrowLeft \ routeKeyToFocused state ArrowLeft
|
||||||
| ArrowRight \ routeKeyToFocused state ArrowRight
|
| ArrowRight \ routeKeyToFocused state ArrowRight
|
||||||
| Backspace \ routeKeyToFocused state Backspace
|
| Backspace \ routeKeyToFocused state Backspace
|
||||||
|
|
@ -29,13 +39,13 @@ view = state viewport \
|
||||||
child = Column {
|
child = Column {
|
||||||
gap = 10,
|
gap = 10,
|
||||||
children = [
|
children = [
|
||||||
textInput2.view state.email {
|
textInput.view state.email {
|
||||||
focused = state.focusedInput == "email",
|
focused = state.focusedInput == "email",
|
||||||
onFocus = FocusEmail,
|
onFocus = FocusEmail,
|
||||||
w = 300,
|
w = 300,
|
||||||
h = 40
|
h = 40
|
||||||
},
|
},
|
||||||
textInput2.view state.password {
|
textInput.view state.password {
|
||||||
focused = state.focusedInput == "password",
|
focused = state.focusedInput == "password",
|
||||||
onFocus = FocusPassword,
|
onFocus = FocusPassword,
|
||||||
w = 300,
|
w = 300,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,23 @@ calcScrollOffset = text cursorPos scrollOffset inputWidth \
|
||||||
| True \ cursorX - inputWidth + 20
|
| True \ cursorX - inputWidth + 20
|
||||||
| False \ scrollOffset));
|
| False \ scrollOffset));
|
||||||
|
|
||||||
textInput2 = {
|
findPosHelper = text targetX index \
|
||||||
|
(index >= len text)
|
||||||
|
| True \ len text
|
||||||
|
| False \ (
|
||||||
|
widthSoFar = measureText (slice text 0 index);
|
||||||
|
widthNext = measureText (slice text 0 (index + 1));
|
||||||
|
midpoint = (widthSoFar + widthNext) / 2;
|
||||||
|
(targetX < midpoint
|
||||||
|
| True \ index
|
||||||
|
| False \ findPosHelper text targetX (index + 1))
|
||||||
|
);
|
||||||
|
|
||||||
|
findCursorPos = text clickX scrollOffset inputPadding \
|
||||||
|
adjustedX = clickX + scrollOffset - inputPadding;
|
||||||
|
findPosHelper text adjustedX 0;
|
||||||
|
|
||||||
|
textInput = {
|
||||||
# init : String \ State
|
# init : String \ State
|
||||||
init = text \ { text = text, cursorPos = 0, scrollOffset = 0 },
|
init = text \ { text = text, cursorPos = 0, scrollOffset = 0 },
|
||||||
|
|
||||||
|
|
@ -65,6 +81,12 @@ textInput2 = {
|
||||||
{ text = newText, cursorPos = newCursorPos, scrollOffset = newScroll }
|
{ text = newText, cursorPos = newCursorPos, scrollOffset = newScroll }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
| Clicked coords \ (
|
||||||
|
newCursorPos = findCursorPos state.text coords.x state.scrollOffset 8;
|
||||||
|
newScroll = calcScrollOffset state.text newCursorPos state.scrollOffset 284;
|
||||||
|
{ text = state.text, cursorPos = newCursorPos, scrollOffset = newScroll }
|
||||||
|
)
|
||||||
|
|
||||||
| _ \ state,
|
| _ \ state,
|
||||||
|
|
||||||
view = state config \
|
view = state config \
|
||||||
|
|
|
||||||
|
|
@ -228,11 +228,15 @@ function measure(ui: UIValue): { width: number, height: number } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hitTest(x: number, y: number): Value | null {
|
export function hitTest(x: number, y: number): { event: Value, relativeX: number, relativeY: number } | null {
|
||||||
for (const region of clickRegions) {
|
for (const region of clickRegions) {
|
||||||
if (x >= region.x && x < region.x + region.width &&
|
if (x >= region.x && x < region.x + region.width &&
|
||||||
y >= region.y && y < region.y + region.height) {
|
y >= region.y && y < region.y + region.height) {
|
||||||
return region.event;
|
return {
|
||||||
|
event: region.event,
|
||||||
|
relativeX: x - region.x,
|
||||||
|
relativeY: y - region.y,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue