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 = [
|
||||
Text({ content = str(count), x = 0, y = 20 }),
|
||||
Clickable {
|
||||
event = "increment",
|
||||
event = Increment,
|
||||
child = Rect { w = 100, h = 40, color = "blue" }
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -74,9 +74,26 @@ export function runApp(app: App, canvas: HTMLCanvasElement) {
|
|||
}
|
||||
|
||||
|
||||
const event = hitTest(x, y);
|
||||
if (event) {
|
||||
handleEvent(event);
|
||||
const hitResult = hitTest(x, y);
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,31 @@
|
|||
routeKeyToFocused = state event \
|
||||
(state.focusedInput == "email"
|
||||
| True \
|
||||
newInputState = textInput2.update state.email event;
|
||||
newInputState = textInput.update state.email event;
|
||||
state.{ email = newInputState }
|
||||
| False \
|
||||
newInputState = textInput2.update state.password event;
|
||||
newInputState = textInput.update state.password event;
|
||||
state.{ password = newInputState });
|
||||
|
||||
init = {
|
||||
focusedInput = "email",
|
||||
email = textInput2.init "",
|
||||
password = textInput2.init ""
|
||||
email = textInput.init "",
|
||||
password = textInput.init ""
|
||||
};
|
||||
|
||||
update = state event \ event
|
||||
| FocusEmail \ state.{ focusedInput = "email" }
|
||||
| FocusPassword \ state.{ focusedInput = "password" }
|
||||
| FocusEmail coords \ (
|
||||
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
|
||||
| ArrowRight \ routeKeyToFocused state ArrowRight
|
||||
| Backspace \ routeKeyToFocused state Backspace
|
||||
|
|
@ -29,13 +39,13 @@ view = state viewport \
|
|||
child = Column {
|
||||
gap = 10,
|
||||
children = [
|
||||
textInput2.view state.email {
|
||||
textInput.view state.email {
|
||||
focused = state.focusedInput == "email",
|
||||
onFocus = FocusEmail,
|
||||
w = 300,
|
||||
h = 40
|
||||
},
|
||||
textInput2.view state.password {
|
||||
textInput.view state.password {
|
||||
focused = state.focusedInput == "password",
|
||||
onFocus = FocusPassword,
|
||||
w = 300,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,23 @@ calcScrollOffset = text cursorPos scrollOffset inputWidth \
|
|||
| True \ cursorX - inputWidth + 20
|
||||
| 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 = text \ { text = text, cursorPos = 0, scrollOffset = 0 },
|
||||
|
||||
|
|
@ -65,6 +81,12 @@ textInput2 = {
|
|||
{ 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,
|
||||
|
||||
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) {
|
||||
if (x >= region.x && x < region.x + region.width &&
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue