Commit graph

65 commits

Author SHA1 Message Date
Kevin Boos
e0a5a23f2f
Splash improvements for running untrusted mini-apps (#1139)
* fix a pile of splash script-vm bugs: newline statements, short-circuit args, tail calls

went through the script VM and parser and fixed a batch of correctness bugs
that were biting the launcher's mini-apps:

- newline-delimited statements: a `(` or `[` at the start of the next line no
  longer greedily glues onto the previous value as a call/index. leading infix
  operators and `.` still continue the expression (the shader DSL needs that),
  and the divert is suppressed inside ()/[] groupings.
- short-circuit `&&`/`||` used as a call argument no longer loses its value to
  nil when the jump skips a multi-op right-hand side.
- a call as the very last statement of a script actually executes now, in both
  end-of-parse unwind loops (also patched a zero-offset ShortCircuitEnd).
- custom widgets that deref to a base with a #[source] field now forward
  script_source, so script_apply_eval works on them instead of silently no-op'ing.

plus regression tests for the newline and short-circuit cases.

* harden splash isolates: scoped timers, net gating, effective-visibility snapshots

isolate-safety work so mini-apps can't reach outside their sandbox:

- isolate-safe script-timer dispatch hook + gc for stale timers
- gate net.socket_stream on the net runtime being present
- widget-tree snapshot reports effective visibility (a widget counts as hidden
  if any ancestor is hidden)
- macos_activate_app (plus a headless no-op) so the launcher can focus itself

* widen the host->splash surface: splash setters, view/glassbutton script calls

everything the host needs to poke into a running mini-app's script:

- Splash: call_script_fn, set_script_global, set_allow_net, and a cached body id
  so host->script calls don't rescan for the body every time
- View.set_visible and GlassButton set_text/text are callable from script now
- makepad_test learned right-click (secondary button) so the headless tests can
  exercise long-press / context menus

* fix small-size glass lens + sdf box degeneration, warn on missing glyphs

visual correctness fixes we kept tripping over:

- cap the gauss lens band at 35% of the surface's smaller side so tiny discs
  degrade gracefully instead of smearing
- clamp the Sdf2d.box (and box_x/box_y/box_all) radius so an oversized radius
  saturates at a circle instead of collapsing into a rotated diamond
- log once per codepoint when no loaded font can render it (was silently
  drawing .notdef boxes)

* guard stale rect areas in clipped_rect/abs_to_rel/set_rect against out-of-bounds panics

* add switch_finger_capture to hand a live finger capture between widgets mid-drag

* add promote_finger_capture_over: hand a child-grabbed finger up to a co-capturing container

* splash: add validate_splash_body, a dry-run eval for externally-sourced scripts

evaluates a body in a throwaway isolate with the exact prefix/limits the
Splash widget uses and returns the captured script errors instead of logging
them. lets hosts that install source from outside (downloads, AI generation,
user input) reject bad scripts with real errors to show or feed back, where
the widget's own eval silently keeps the old view.

* strip mod.res from splash isolates; document validate_splash_body caveats

the res module's handles reach both the filesystem (abs_path loads) and the
network (web_url / http resources) without going through the gated net
runtime, so a 'no-net' isolate could still fetch and exfiltrate. found by an
adversarial review of AI-generated app installs, but it applies to any
untrusted splash source.

also note on validate_splash_body that the instruction limit bounds compute,
not heap growth, and that top-level timers live until isolate reclamation --
same exposure as actually installing the source, so validation adds nothing
new.

* splash: jailed per-app file storage (mod.fs inside isolates)

mini-apps get an OS-style private data directory, like an android app's
internal storage or an iOS container: the app sees a filesystem rooted at
"/", and that root IS its host-assigned sandbox directory
(Splash::set_sandbox_dir / SplashRef forwarder). registered as mod.fs in
isolates -- deliberately shadowing the stripped real fs module, so inside
an app "the filesystem" simply is the jail:

  fs.read fs.write fs.append fs.exists fs.remove fs.mkdir fs.list

containment lives entirely in the host layer:
- lexical path resolution against the root; `..` above the root, NUL, deep
  or overlong paths are errors before any I/O
- the per-VM root is rust state keyed by the isolate's heap -- script code
  can neither read nor retarget it
- symlink defense in depth: nothing here can create links, and every
  existing component under the root is verified non-symlink before use
- quotas: 1MB/file, 16MB/jail, 256 entries
- no root assigned (previews) -> every call errors cleanly

validate_splash_body gives dry runs a throwaway jail (temp dir, removed
after) so top-level fs.read boot loads validate instead of erroring. roots
are dropped with their isolates in the gc.

unit tests cover the containment: traversal/absolute/backslash escapes,
depth/name caps, and the symlink block.

* splash: put the jailed fs module in scope as a bare name

app scripts say fs.read("/x"), but the eval prefix only used the widgets
prelude, so bare fs resolved to a not-found error value and every storage
call failed silently. bind it in the prefix (let fs = mod.fs) for both the
plain and net variants; a script reassigning fs only shadows its own name,
the jail stays host-side.

* splash storage: quota + boundary hardening from adversarial review

three confirmed jail findings:
- mkdir bypassed every quota (target + create_dir_all, no jail_usage check)
  -> unbounded inode/dir-metadata exhaustion on the shared host volume.
  now charges new dirs against MAX_ENTRIES via missing_entries(); write's
  entry check does the same so a deep write can't overshoot the cap either.
- write/append/mkdir lacked remove's root guard: fs.write("/", data)
  resolved real == root and reached create_dir_all(root.parent()) -- one
  dir above the jail (the shared app_data/). now rejected like remove does.
- validate_splash_body's scratch jail used a predictable temp name created
  with create_dir_all (would follow a planted symlink out of temp). now an
  exclusive create_dir on a per-process+vm name (EEXIST-safe against a
  planted entry), reclaimed via gc before the dir is removed so a top-level
  timer can't resurrect it.

unit tests added for missing_entries; the containment tests still pass.

* splash: empty set_text tears down the isolate instead of no-oping

set_text("") was a silent no-op (eval_body early-returns on an empty body),
so a reused Splash that goes back to empty -- the widget-gallery live preview
on Back -- left its old isolate running its timers (and holding a storage-jail
binding) behind a blank view. now an empty body reclaims the isolate: the
isolate-minted view is replaced with a fresh empty one built in the main vm
BEFORE the isolate heap is freed, then the isolate is gc'd (stopping its
timers, dropping its jail root); vm_id resets to MAIN so a later non-empty
set_text allocs a fresh isolate as before. the existing host_launcher
teardown call sites (widget picker back()/reset()) become correct unchanged.

* overlay: composite glass in draw order, not creation order

every gauss/glass surface opens its own draw list and registers it in the
window's single Overlay via store_sub_list, which hands out the first free
slot and keeps it for the life of the process. renderers walk that table in
index order, so the paint order of all glass in an app was the order the
surfaces were first *created* — permanently, with freed slots reused by
whatever registered next. draw order never came into it, so a widget rebuilt
after a layout change, or a panel opened later, could land on top of anything
drawn after it. the only workarounds available to apps were "don't draw the
thing that's winning", which looks like a bug.

the hook for fixing it was already there and unused: CxDrawList's
draw_item_reorder, honoured by every backend (metal, d3d11, opengl, vulkan,
web_gl, headless raster). so stamp each overlay sub-list with the position it
was begun in this frame (Cx2d::overlay_seq, reset in Overlay::begin) and have
Overlay::end stable-sort the table by that stamp.

this also gets parent-then-child right without special cases, which matters
because glass.GlassButton / glass.GlassSegmented call begin_overlay_reuse
unconditionally instead of checking is_drawing_overlay(), so they hold their
own slots rather than riding their parent's.

* glass.GlassSegmented: size segments to their labels, add set_selected

three things, all of them things that looked broken to a user:

- segments were width/count, so "Max" got the same room as "Default": the long
  word crowded, the short one floated. each segment is now measured (DrawText
  layout size_in_lpxs) and gets its text plus padding, with leftover width
  shared equally so every label keeps the same margin. if the labels don't fit,
  the padding shrinks (never the text) to a floor. the pill's x/width are
  computed in rust and passed as uniforms since they can't come from a segment
  count any more, and hit-testing is a boundary lookup rather than a division.

- `selected` was public but the pill is drawn from a private sel_pos that only
  followed it via the click animation, so restoring a saved value from code
  left the control showing one segment while reporting another — and a click on
  the segment it really held was then ignored as "already selected". that reads
  as the control eating your clicks. set_selected keeps both in step.

- the travel easing was 0.30, which arrived before the eye could follow it.
  0.16.

* text_input: re-layout when max_lines changes

the laidout text was cached on width alone, so flipping draw_text.max_lines
at runtime (collapsing a composer to one line) kept the old multi-row layout
and the field never shrank. make max_lines part of the cache key.

* text_input: add set_max_lines instead of making callers script it

applying script to a TextInput re-applies its #[live] fields, and text is
one of them, so toggling max_lines through script_apply_eval! silently
wiped whatever the user had typed. give it a typed setter.

* text_input: don't drop the layout in set_max_lines

clearing laidout_text there leaves the field with no layout for the rest
of the event batch, so every cursor op in that window bails out with
"can't move cursor because layout was invalidated by an earlier event".
since set_max_lines gets called from focus/blur handling, that window is
exactly when you're clicking into the field — so the click placed no
caret at all. max_lines is already part of the layout cache key, so the
next draw re-lays out on its own.

* text_input: add scroll_to_top

for a field that folds to a fixed height when it loses focus: the scroll
offset survives the blur, so a draft last edited near its end folds
showing whichever line the caret had scrolled to rather than its first.
leaves laidout_text alone — scrolling doesn't change the layout, and
dropping it would break every cursor op for the rest of the event batch,
same trap as set_max_lines.

* text_input: add set_height

for a composer that folds to one line when it loses focus. pinning the
height is the safe way to fold — unlike clamping max_lines it leaves the
laid-out text alone, and the laid-out text is what maps a click to a
caret position. fold by re-layout and the press that re-focuses the
field resolves against the folded layout while the expanded one is on
screen, so the caret and any drag-selection land on the wrong text.

* text_input: add take_key_focus, which actually shows the caret

the caret draws as (1.0 - blink) * focus, and both come from animators
that only move when the widget is dealt a Hit::KeyFocus. setting key
focus on a field that ALREADY holds it dispatches no hit — so a field
that was focused, then hidden (hiding doesn't clear Cx's key focus) and
shown again comes back typable but with no caret and no selection
highlight, animators still parked where the last focus-lost left them.

plays focus.on unconditionally rather than only when focus changed:
repairing the case where it did NOT change is the entire point.

* splash: name scripts in errors, and stop using line as an identity slot

a runtime error from a Splash app logged `:1804943384:12 - widget has
no uid`: empty file, and a "line" that is really a pointer address.
the format is {file}:{line}:{col}, and both fields were casualties of
the same hack — ScriptMod.line carried self_id so the body could be
found again (m.line == self_id && m.file.is_empty()), while ip_to_loc
adds that same field to the script's real line when reporting. so every
location came out as real_line + a pointer, and nothing said WHICH app.

identity moves to module_path, which nothing else reads for these
bodies, freeing line to be a line. file gets a real name via a new
set_debug_name the host calls with the mini-app's id.

the validator's ScriptMod gets the same treatment — its errors are
shown to the user AND fed back to the agent as repair input, so a
location offset by a vm id was actively misleading there.

* splash: document the constant offset in reported script lines

the host prefix is two lines, so a reported line is two ahead of the
app's own file. it can't be zero — a zero-line prefix would share line 1
with the app's first line, and that line is always the // name: header,
which would comment the prefix out.

* script: stop silently losing widgets emitted from branches and loops

Splash mini-apps kept rendering nothing from on_render closures with zero
errors logged. Bisected live and in pure-VM probes, this was a pile of
separate bugs in the same corner:

- an if/else whose branch emits a widget lost the taken true branch: the
  statement's POP_TO_ME got fused onto the else tail, which the IF_ELSE
  jump skips. Generalized last_short_circuit_target into last_jump_target
  and record every branch join (if/elif/else, match, try/err), so the
  commit lands standalone AT the join and every path runs it. Same disease
  as the short-circuit-argument bug, new jump sites.
- elif never patched its arm's IF_ELSE jump (relative 0), so a taken arm
  spun the interpreter until the instruction limit killed the whole entry.
  elif now desugars into else { if ... } via IfElseExpr, which also gives
  its arms the join treatment.
- for x in <non-iterable> silently skipped the body where the equivalent
  while errored; now raises "for loop source is not iterable" (nil and
  empty sources stay silent). for k v in <number> passed key/index swapped
  and lost k after the first iteration (the advance only rebound v).
- a line-leading { after a value-ending line glued onto the previous
  expression as a proto instantiation; it now starts a new statement,
  same divert rule the ( and [ newline fix added.
- int literals were second-class numbers: U40/I32/F32/F16/U32 didn't
  collapse to the number bucket in to_redux, so 6 .is_number() missed
  method dispatch entirely and an int arg against a float default failed
  with "expected number, got number". They're all just numbers now.

Regression tests in tests/on_render_emission.rs cover each shape, incl.
the exact calendar/weather patterns that were blank in the launcher.

* splash: keep an on_render closure's final widget, and say when a render fails

Two host-side halves of the emission-loss story:

- the parser turns a closure's last statement into its return value, so a
  render closure that ENDS with a widget literal built it and then threw it
  away (this is why wrapping a whole render in one extra View{} produced
  nothing). script_result now pushes a returned widget object into me as
  the last child; non-widget returns still get skipped downstream.
- a render closure that errors mid-run used to have its output discarded
  with no diagnostics at all, which is what made this whole bug family
  cost days to find. Now it logs the error before dropping the result.

* script: auto-close still-open fn and let states at end of source

Both parse drivers dropped EndFnExpr/EndFnBlock/EmitLetDyn through their
auto-close catch-all when the source ended with them still open. A module
whose FINAL statement was let c = <lambda> got a body whose jump-over
stayed 0 — FN_BODY_DYN re-ran, found its me already popped, logged
"me stack is empty" and fell straight INTO the body, running it inline
at definition time and ending the module eval early — and the let itself
never emitted, so the binding silently didn't exist (same for
let c = <call>). Now those states close the way the live handlers do:
return + jump patch for the body, LET_DYN/LET_TYPED for the binding, and
the let's own EndStmt no longer marks a statement value (LET consumed
it; the final RETURN would pop an empty stack).

Fun consequence: the old test idiom of reading a result via
  let out = r
  out
only ever worked BECAUSE the trailing let was dropped — RETURN popped
the naked value off the stack. With the let actually binding, scripts
must end on a call (echo(r)); the emission tests are updated to do that.

Regression tests in tests/auto_close_eof.rs, including the exact
deferred-boot-timer closure shape the launcher apps use (which was
already fine — it just LOOKED guilty, see the splash commit).

* splash: probe optional script hooks without spamming the error log

call_script_fn checks whether the fn exists and bails quietly — but it
probed with a trapping scope_value, which had already queued a NotFound
by the time the miss was handled. Every host broadcast of an optional
hook (on_app_resize, on_widget_resize) against a script that doesn't
define it logged
  variable 00001e93e419c77c not found in scope
— maximally misleading: the hex is just id!(on_app_resize) (Rust-side
ids aren't in the reverse-lookup table so they print raw), and the
line:col is the stale ip from the end of that script's eval, which
pointed at whatever closure happened to be compiled last. In the
launcher that was the boot-timer line of every generated app, sending
the investigation down a deferred-closure rabbit hole the pure-VM tests
then cleared. Probe with NoTrap.

* script derive: don't name the eval values vec 'v'

script_apply_eval!'s generated values block bound 'let mut v' and then
spliced #(expr) interpolations in verbatim — so a caller interpolating a
variable that happened to be called v got the macro's own half-built Vec
(borrow errors if you were lucky, the wrong value if not). Obscure name
instead.

* headless: don't compile the Apple video path

Upstream's zero-copy video work put CoreVideo/Metal code in
gpu_texture.rs (plus two consumers) behind cfg(target_os = "macos")
alone. Under cfg(headless) the apple backend isn't built at all, so
every one of those symbols — ObjcId, msg_send!, CVPixelBufferRef,
CVMetalTextureCache* — is missing and makepad-platform fails to
compile with 94 errors. That takes the headless harness down with it,
which is what host_launcher's UI tests run on.

Gate the Apple blocks on not(headless) too. Nothing is lost: headless
has no Metal device to import a CVPixelBuffer into, so the whole path
is inapplicable there.

Not caused by the rebase — pristine dev has it: its headless
CxOsTexture is an empty struct while gpu_texture.rs reads .os.texture.
2026-08-12 01:55:46 +02:00
Admin
59b7d2712f gamemaker: full engine round — chase camera rig, racing-game APIs, script stdlib math, real error line numbers
Engine (examples/gamemaker): chase camera rig (camera({chase}) — ease-behind
with mouse-wins/recenter authority), writable camera + look deltas, spatial
queries (raycast/overlap_sphere/ground_normal), save/load, sustained tones,
rot_y + collide:false spawnables, HUD slots/bars, terrain noise shaping +
height bands, per-shape instanced render batching with static slabs (3.2x),
error push-loop into the agent chat, unknown-verb/option diagnostics with
game.splash:line:col positions, streaming tail-statement finalization, quiet
toolbar UI, Shh voice hush, fable voice.

Platform: runtime vector methods (.length/.normalized/.dot/.cross), scalar+
vector lerp, TAU; ScriptVm error capture sink; window frame capture API; four
headless-JIT fixes (scalar casts, mat4 mul, Id-arg expansion, commuted
scalar-vec ops) with regression test stages. Widgets: single-line TextInput
baseline centering, TextFlow inline-code baseline alignment, glass button
corner_radius uniform. Voice/ggml Metal backends: debug logs behind
GGML_METAL_TRACE. splashgame.md: the runtime-loaded game API contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 14:20:03 +02:00
Kevin Boos
ca684774f7 TextInput: expose the location of the caret/cursor (#1132)
in absolute window-relative coordinates.

THis allows, for ex, a widget to be placed relative to the
current location of the text being inputted by the user.
2026-07-02 08:34:04 +02:00
Admin
ef0514a9aa hypothetical heap access fix 2026-07-01 14:04:23 +02:00
Kevin Boos
95535b25f7 TextInput: infer soft-keyboard input_mode from content_type if its unset (#1125)
* Support standard keyboard navg shortcuts/keys in TextInput

Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys

* Add `CropToFill` image fit variant, improve ImageFit docs

This allows you to easily achieve the "centered cropped fit" that most apps
want for things like avatars or small thubmnails that get masked.

* Detect and support hardware keyboards, distinguish from soft/virtual kbd

Mimic desktop behavior on mobile systems as much as possible.
This is esp important for tablets like iPad OS where you're more likely
to have a real physical keyboard attached.

For iOS:
* Arrow keys and Home/End/PageUp/PageDown navigate and auto-repeat
  at the system-defined rate (connected via `UIKeyCommand`)
* Cmd+Enter to submit a `TextInput` and Cmd+C/X/V clipboard shortcuts now work.
* Ensure the pop-up diacritic/accent menu is properly placed using a hidden
  `UITextInput` native widget, which acts as a sort of "proxy"
* Proactively drain `ShowTextIME` after each draw so the IME position will be
  properly updated after each keystroke.
* Importnatly, don't mark the IME dismissed when a hardware keyboard is attached.

For both iOS & Android:
* Add a `has_physical_keyboard()` detection mechanism across both backends,
  and fix platform-specific key repeat behavior

For Android:
* Ensure clipboard cut/copy works using the same Ctrl shortcuts (API 26+)

Soft/virtual keyboard/IME changes:
* For multiline TExtInputs, a soft keyboard Enter/Return key will always just
  insert a new line, to avoid complexity with keyboard shortcut cfgs.
* CJK keyboard character selection should also be properly positioned now

* minor optimization to avoid re-setting IME pos if it didn't change

* Ensure inline composition is still shown in TextInput on all platforms

This is mostly relevant when using CJK and other similar IMEs.
Previously Makepad didn't shown any "echoes" of the single latin chars
that the user would type, but it would correctly input the selected CJK
glyph. So if you typed `nihao` and then selected `你哈`, then you would
see the proper chinese characters but not the latin "nihao".
Tha't s a bit confusing while typing.

Summary of the fixes per platform:

macOS:
- `set_marked_text` now forwards the marked (composition) text to the
  focused TextInput with `replace_last = true`; previously it only stored
  it in an ivar. `unmark_text` clears the preview, and both it and
  `insert_text` share a new `clear_marked_text_ivar` helper so a commit
  doesn't emit a second, destructive text-input event.

Windows:
- Add `WM_IME_COMPOSITION` handling: commit `GCS_RESULTSTR`
  (`replace_last = false`) and show `GCS_COMPSTR` inline
  (`replace_last = true`), and clear on `WM_IME_ENDCOMPOSITION`. The
  message is consumed so DefWindowProc neither draws its own composition
  window nor synthesizes a duplicate WM_CHAR for the result.
- Extend the vendored `windows` binding with `ImmGetCompositionStringW`,
  `GCS_COMPSTR`/`GCS_RESULTSTR`, and `WM_IME_COMPOSITION`/
  `WM_IME_ENDCOMPOSITION`, which it didn't previously generate.

Linux (Wayland):
- Handle the `zwp_text_input_v3` `PreeditString` event (previously empty)
  and apply the double-buffered preedit/commit state on `Done`, in the
  protocol-mandated order (commit, then preedit), clearing the preview
  when a cycle carries no preedit.

Linux (X11):
- Create the input context with XIM on-the-spot (`XIMPreeditCallbacks`)
  and forward the preedit string from the draw/start/done callbacks,
  falling back to `XIMPreeditNothing` if the IM server doesn't support
  callbacks. Callbacks run inside `XFilterEvent`, so they only mutate a
  thread-local that the event loop drains into the widget afterward,
  avoiding re-entrant access to the app.

Android:
- Don't mark the IME dismissed when a physical keyboard is attached
  (mirrors the iOS guard). Android was unconditionally calling
  `text_ime_was_dismissed()` on soft-keyboard hide, which tore down the
  IME connection that hardware-key composition relies on.

* iOS: replace custom `UITextInput` with a native `UITextView`

`UITextView` is a full system-native keyboard client, so we get all the
major features for free: language HUD pill and the complete globe/Ctrl+Space
shortcut to cycle between IMEs/languages.

Makepad basically just mirrors the state of the system native text view,
via the `full_state_sync`, but the actual native text view is kept invisible
so it doesn't interfere with what we render in Makepad's TextInput.
Notably, the Full Keyboard Accessibility setting now does work properly,
whereas it did not before with our UITextInput-based approach.

We also make sure that arrow keys, nav keys, auto-repeat, and modifiers
are properly hanlded so we can retain the expected kbd shortcuts,
like other desktop platforms.

* iOS: remove the old `UITextInput` connection with the Makepad TextInput

We've now switched to the native UITextview, so we don't need this any more.

* iOS: fix desync during fast typing

Ensure there's no race between the native UITextView and
Makepad's TextInput, as the Enter/REturn key needs special handling
w.r.t. how `pressesBegan` gets it (From a real hardware kbd).

* TextInput: more iOS integration, and text input types

more native integration for things like username/password,
new password fields, email, address, URLs, etc.
These tell iOS to change the keyboard layout/type for the text input.

* iOS: don't let Full Keyboard Access focus on our hidden native cursor

* cleanup

* iOS/TextInput: fix perf issues

* iOS TextInput: more fixes for read-only efficiency, and filtered input

Also port some of these fixes to Android's IME integration layer

* iOS/TextInput: hide the native caret iOS draws during autocorrect

but still allow the "decline autocorrect" bubble to popup where that
hidden caret is located (and the CJK candidate window in the same spot)

* Avoid script VM re-entrant panic: defer animator_cut/play if script VM is held

`animator_cut` / `animator_play` call `cx.with_vm`, which panics
(*"Script VM swapped off"*) when invoked during an apply walk — e.g. a
widget's `on_after_apply` on `ScriptReapply` / `Reload` — because the VM
is already taken for the duration of that walk's enclosing `cx.with_vm`.

- The derive macro's `animator_cut_scoped` / `animator_play_scoped` now
  check `cx.is_script_vm_held()`; when held, they queue the op
  (`defer_cut` / `defer_play`) and return instead of re-entering the VM.
- `animator_handle_event_scoped` replays the queue via `flush_deferred`
  on the next frame, once the VM is free.

The defer path runs **only** in the formerly-panicking case, so VM-free
animations are byte-for-byte unchanged.

Also adds a re-entrancy-naming panic (`VmHolderGuard`) plus
`Cx::try_with_vm` / `Cx::is_script_vm_held` for diagnosing and handling
this class of bug.

* Better spacing/positioning for IME popups like the CJK candidate menu

applied to all platforms, but primarily an issue on macOS/iOS.

The candidate/conversion window (e.g. CJK pinyin) was covering the line of
text being composed. Carry the caret-line rect (not just a point) through
ShowTextIME and feed each backend its native "keep clear of this line" API,
so the OS places the candidate directly above/below the line with a small gap:

- macOS: firstRectForCharacterRange returns the line rect via AppKit
  convertRect:toView:nil + convertRectToScreen (drops the hand-rolled
  screen-coord math + fudge offsets); invalidate on caret move.
- Windows: ImmSetCandidateWindow with a CFS_EXCLUDE line rect.
- Wayland: set_cursor_rectangle with the real line rect.
- X11: XNSpotLocation/XNArea at the line.
- iOS: return the true composing-line box from firstRectForRange so iOS flips
  around the real edges (consistent at any screen position) instead of a
  degenerate point; only while marked text is active, to avoid an oversized
  autocorrect highlight when typing normally.

* Fix Linux X11 behavior: Ctrl-based kbd shortcuts didn't work in TextInput

also trying to fix X11 behavior for positioning the CJK candidate window,
turns out there was an X11 bug for Ubuntu 22 and older so it's not always
possible, but we can attempt a workaround if errors occur (based on that,
we try to auto-detect the version of X11)

* fix X11 event loop latency by draining only a max of 64 events before redrawing

still working on X11 CJK candidate window positioning...

* add logs to X11 ime to figure out wtf is going on

* more robust fallbacks for X11 CJK candidate window positioning... grr

* maybe try to set the XFontSet attribute? for CJK candidate positioning

* positioning works now but there is a bit of overlap still

* now that X11 CJK candidate positioning works in some cases,
we need to pass the full rectangle containing the current line of text
to the X11 library so that it can position the window both on top
and beneath the current line of text, if needed.

* tweaking X11 CJK candidate positioning

* abandon the screen-positioning heuristic

Instead, we just send the bounding rect of the current text character
and hopefully let the X11 platform libs decide where to put the
CJK candidate popup

* add more spacing to the bounding rect on X11

* tweak for a bit more space between CJK candidate window

* more tweaks, rect height isn't being respected for some reason...

* attempting to add more instrumentation to figure out wtf is going on with X11 CJK positioning

* remove bad instrumentation that was causing freezes. ugh

* different approach for IME placement on X11

* previous positioning attempts for X11 didn't work.

New strategy: let it be positioned, and then try to move it

* still trying to fix X11 CJK candidate window positoining...

* trying to find CJK candidate window with X11 queries (To move it)

* abandon window scanning approach

* better approach, now just tweaking it

* fix one case where the candidate window was flipped but it pointing too low

* tweaking more

* trying to fix above-text line positioning

* still trying to tweak CJK candidates ABOVE the text line

* be more conservative when guessing whether X11 will show the CJK candidate above or below

* improve size heuristic for CJK candidate height

* calling X11 as complete now. jfc. Cleanup, remove debug logs, etc

* TextInput: infer soft-keyboard `input_mode` from `content_type` if its unset

New functon: `effective_input_mode()` will now derive a keyboard layout
from the `content_type`, if one was provided and if it makes sense to infer.

Explicitly setting the `input_mode` will always take precendence.
2026-06-16 09:08:10 +02:00
Kevin Boos
1f1c9178a7 Ensure inline composition is still shown in TextInput on all platforms (#1109)
* Support standard keyboard navg shortcuts/keys in TextInput

Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys

* Add `CropToFill` image fit variant, improve ImageFit docs

This allows you to easily achieve the "centered cropped fit" that most apps
want for things like avatars or small thubmnails that get masked.

* Detect and support hardware keyboards, distinguish from soft/virtual kbd

Mimic desktop behavior on mobile systems as much as possible.
This is esp important for tablets like iPad OS where you're more likely
to have a real physical keyboard attached.

For iOS:
* Arrow keys and Home/End/PageUp/PageDown navigate and auto-repeat
  at the system-defined rate (connected via `UIKeyCommand`)
* Cmd+Enter to submit a `TextInput` and Cmd+C/X/V clipboard shortcuts now work.
* Ensure the pop-up diacritic/accent menu is properly placed using a hidden
  `UITextInput` native widget, which acts as a sort of "proxy"
* Proactively drain `ShowTextIME` after each draw so the IME position will be
  properly updated after each keystroke.
* Importnatly, don't mark the IME dismissed when a hardware keyboard is attached.

For both iOS & Android:
* Add a `has_physical_keyboard()` detection mechanism across both backends,
  and fix platform-specific key repeat behavior

For Android:
* Ensure clipboard cut/copy works using the same Ctrl shortcuts (API 26+)

Soft/virtual keyboard/IME changes:
* For multiline TExtInputs, a soft keyboard Enter/Return key will always just
  insert a new line, to avoid complexity with keyboard shortcut cfgs.
* CJK keyboard character selection should also be properly positioned now

* minor optimization to avoid re-setting IME pos if it didn't change

* Ensure inline composition is still shown in TextInput on all platforms

This is mostly relevant when using CJK and other similar IMEs.
Previously Makepad didn't shown any "echoes" of the single latin chars
that the user would type, but it would correctly input the selected CJK
glyph. So if you typed `nihao` and then selected `你哈`, then you would
see the proper chinese characters but not the latin "nihao".
Tha't s a bit confusing while typing.

Summary of the fixes per platform:

macOS:
- `set_marked_text` now forwards the marked (composition) text to the
  focused TextInput with `replace_last = true`; previously it only stored
  it in an ivar. `unmark_text` clears the preview, and both it and
  `insert_text` share a new `clear_marked_text_ivar` helper so a commit
  doesn't emit a second, destructive text-input event.

Windows:
- Add `WM_IME_COMPOSITION` handling: commit `GCS_RESULTSTR`
  (`replace_last = false`) and show `GCS_COMPSTR` inline
  (`replace_last = true`), and clear on `WM_IME_ENDCOMPOSITION`. The
  message is consumed so DefWindowProc neither draws its own composition
  window nor synthesizes a duplicate WM_CHAR for the result.
- Extend the vendored `windows` binding with `ImmGetCompositionStringW`,
  `GCS_COMPSTR`/`GCS_RESULTSTR`, and `WM_IME_COMPOSITION`/
  `WM_IME_ENDCOMPOSITION`, which it didn't previously generate.

Linux (Wayland):
- Handle the `zwp_text_input_v3` `PreeditString` event (previously empty)
  and apply the double-buffered preedit/commit state on `Done`, in the
  protocol-mandated order (commit, then preedit), clearing the preview
  when a cycle carries no preedit.

Linux (X11):
- Create the input context with XIM on-the-spot (`XIMPreeditCallbacks`)
  and forward the preedit string from the draw/start/done callbacks,
  falling back to `XIMPreeditNothing` if the IM server doesn't support
  callbacks. Callbacks run inside `XFilterEvent`, so they only mutate a
  thread-local that the event loop drains into the widget afterward,
  avoiding re-entrant access to the app.

Android:
- Don't mark the IME dismissed when a physical keyboard is attached
  (mirrors the iOS guard). Android was unconditionally calling
  `text_ime_was_dismissed()` on soft-keyboard hide, which tore down the
  IME connection that hardware-key composition relies on.

* iOS: replace custom `UITextInput` with a native `UITextView`

`UITextView` is a full system-native keyboard client, so we get all the
major features for free: language HUD pill and the complete globe/Ctrl+Space
shortcut to cycle between IMEs/languages.

Makepad basically just mirrors the state of the system native text view,
via the `full_state_sync`, but the actual native text view is kept invisible
so it doesn't interfere with what we render in Makepad's TextInput.
Notably, the Full Keyboard Accessibility setting now does work properly,
whereas it did not before with our UITextInput-based approach.

We also make sure that arrow keys, nav keys, auto-repeat, and modifiers
are properly hanlded so we can retain the expected kbd shortcuts,
like other desktop platforms.

* iOS: remove the old `UITextInput` connection with the Makepad TextInput

We've now switched to the native UITextview, so we don't need this any more.

* iOS: fix desync during fast typing

Ensure there's no race between the native UITextView and
Makepad's TextInput, as the Enter/REturn key needs special handling
w.r.t. how `pressesBegan` gets it (From a real hardware kbd).

* TextInput: more iOS integration, and text input types

more native integration for things like username/password,
new password fields, email, address, URLs, etc.
These tell iOS to change the keyboard layout/type for the text input.

* iOS: don't let Full Keyboard Access focus on our hidden native cursor

* cleanup

* iOS/TextInput: fix perf issues

* iOS TextInput: more fixes for read-only efficiency, and filtered input

Also port some of these fixes to Android's IME integration layer

* iOS/TextInput: hide the native caret iOS draws during autocorrect

but still allow the "decline autocorrect" bubble to popup where that
hidden caret is located (and the CJK candidate window in the same spot)

* Avoid script VM re-entrant panic: defer animator_cut/play if script VM is held

`animator_cut` / `animator_play` call `cx.with_vm`, which panics
(*"Script VM swapped off"*) when invoked during an apply walk — e.g. a
widget's `on_after_apply` on `ScriptReapply` / `Reload` — because the VM
is already taken for the duration of that walk's enclosing `cx.with_vm`.

- The derive macro's `animator_cut_scoped` / `animator_play_scoped` now
  check `cx.is_script_vm_held()`; when held, they queue the op
  (`defer_cut` / `defer_play`) and return instead of re-entering the VM.
- `animator_handle_event_scoped` replays the queue via `flush_deferred`
  on the next frame, once the VM is free.

The defer path runs **only** in the formerly-panicking case, so VM-free
animations are byte-for-byte unchanged.

Also adds a re-entrancy-naming panic (`VmHolderGuard`) plus
`Cx::try_with_vm` / `Cx::is_script_vm_held` for diagnosing and handling
this class of bug.

* Better spacing/positioning for IME popups like the CJK candidate menu

applied to all platforms, but primarily an issue on macOS/iOS.

The candidate/conversion window (e.g. CJK pinyin) was covering the line of
text being composed. Carry the caret-line rect (not just a point) through
ShowTextIME and feed each backend its native "keep clear of this line" API,
so the OS places the candidate directly above/below the line with a small gap:

- macOS: firstRectForCharacterRange returns the line rect via AppKit
  convertRect:toView:nil + convertRectToScreen (drops the hand-rolled
  screen-coord math + fudge offsets); invalidate on caret move.
- Windows: ImmSetCandidateWindow with a CFS_EXCLUDE line rect.
- Wayland: set_cursor_rectangle with the real line rect.
- X11: XNSpotLocation/XNArea at the line.
- iOS: return the true composing-line box from firstRectForRange so iOS flips
  around the real edges (consistent at any screen position) instead of a
  degenerate point; only while marked text is active, to avoid an oversized
  autocorrect highlight when typing normally.

* Fix Linux X11 behavior: Ctrl-based kbd shortcuts didn't work in TextInput

also trying to fix X11 behavior for positioning the CJK candidate window,
turns out there was an X11 bug for Ubuntu 22 and older so it's not always
possible, but we can attempt a workaround if errors occur (based on that,
we try to auto-detect the version of X11)

* fix X11 event loop latency by draining only a max of 64 events before redrawing

still working on X11 CJK candidate window positioning...

* add logs to X11 ime to figure out wtf is going on

* more robust fallbacks for X11 CJK candidate window positioning... grr

* maybe try to set the XFontSet attribute? for CJK candidate positioning

* positioning works now but there is a bit of overlap still

* now that X11 CJK candidate positioning works in some cases,
we need to pass the full rectangle containing the current line of text
to the X11 library so that it can position the window both on top
and beneath the current line of text, if needed.

* tweaking X11 CJK candidate positioning

* abandon the screen-positioning heuristic

Instead, we just send the bounding rect of the current text character
and hopefully let the X11 platform libs decide where to put the
CJK candidate popup

* add more spacing to the bounding rect on X11

* tweak for a bit more space between CJK candidate window

* more tweaks, rect height isn't being respected for some reason...

* attempting to add more instrumentation to figure out wtf is going on with X11 CJK positioning

* remove bad instrumentation that was causing freezes. ugh

* different approach for IME placement on X11

* previous positioning attempts for X11 didn't work.

New strategy: let it be positioned, and then try to move it

* still trying to fix X11 CJK candidate window positoining...

* trying to find CJK candidate window with X11 queries (To move it)

* abandon window scanning approach

* better approach, now just tweaking it

* fix one case where the candidate window was flipped but it pointing too low

* tweaking more

* trying to fix above-text line positioning

* still trying to tweak CJK candidates ABOVE the text line

* be more conservative when guessing whether X11 will show the CJK candidate above or below

* improve size heuristic for CJK candidate height

* calling X11 as complete now. jfc. Cleanup, remove debug logs, etc
2026-06-16 09:07:32 +02:00
Kevin Boos
e93aba1161 iOS: replace custom UITextInput with a native UITextView (#1121)
* iOS: replace custom `UITextInput` with a native `UITextView`

`UITextView` is a full system-native keyboard client, so we get all the
major features for free: language HUD pill and the complete globe/Ctrl+Space
shortcut to cycle between IMEs/languages.

Makepad basically just mirrors the state of the system native text view,
via the `full_state_sync`, but the actual native text view is kept invisible
so it doesn't interfere with what we render in Makepad's TextInput.
Notably, the Full Keyboard Accessibility setting now does work properly,
whereas it did not before with our UITextInput-based approach.

We also make sure that arrow keys, nav keys, auto-repeat, and modifiers
are properly hanlded so we can retain the expected kbd shortcuts,
like other desktop platforms.

* iOS: remove the old `UITextInput` connection with the Makepad TextInput

We've now switched to the native UITextview, so we don't need this any more.

* iOS: fix desync during fast typing

Ensure there's no race between the native UITextView and
Makepad's TextInput, as the Enter/REturn key needs special handling
w.r.t. how `pressesBegan` gets it (From a real hardware kbd).

* TextInput: more iOS integration, and text input types

more native integration for things like username/password,
new password fields, email, address, URLs, etc.
These tell iOS to change the keyboard layout/type for the text input.

* iOS: don't let Full Keyboard Access focus on our hidden native cursor

* cleanup

* iOS/TextInput: fix perf issues

* iOS TextInput: more fixes for read-only efficiency, and filtered input

Also port some of these fixes to Android's IME integration layer

* iOS/TextInput: hide the native caret iOS draws during autocorrect

but still allow the "decline autocorrect" bubble to popup where that
hidden caret is located (and the CJK candidate window in the same spot)
2026-06-12 09:12:26 +02:00
Kevin Boos
7c7003774c Detect and support hardware keyboards, distinguish from soft/virtual kbd (#1106)
* Support standard keyboard navg shortcuts/keys in TextInput

Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys

* Add `CropToFill` image fit variant, improve ImageFit docs

This allows you to easily achieve the "centered cropped fit" that most apps
want for things like avatars or small thubmnails that get masked.

* Detect and support hardware keyboards, distinguish from soft/virtual kbd

Mimic desktop behavior on mobile systems as much as possible.
This is esp important for tablets like iPad OS where you're more likely
to have a real physical keyboard attached.

For iOS:
* Arrow keys and Home/End/PageUp/PageDown navigate and auto-repeat
  at the system-defined rate (connected via `UIKeyCommand`)
* Cmd+Enter to submit a `TextInput` and Cmd+C/X/V clipboard shortcuts now work.
* Ensure the pop-up diacritic/accent menu is properly placed using a hidden
  `UITextInput` native widget, which acts as a sort of "proxy"
* Proactively drain `ShowTextIME` after each draw so the IME position will be
  properly updated after each keystroke.
* Importnatly, don't mark the IME dismissed when a hardware keyboard is attached.

For both iOS & Android:
* Add a `has_physical_keyboard()` detection mechanism across both backends,
  and fix platform-specific key repeat behavior

For Android:
* Ensure clipboard cut/copy works using the same Ctrl shortcuts (API 26+)

Soft/virtual keyboard/IME changes:
* For multiline TExtInputs, a soft keyboard Enter/Return key will always just
  insert a new line, to avoid complexity with keyboard shortcut cfgs.
* CJK keyboard character selection should also be properly positioned now

* minor optimization to avoid re-setting IME pos if it didn't change
2026-06-09 00:09:14 +02:00
Kevin Boos
904f09a6a0 Support standard keyboard navg shortcuts/keys in TextInput (#1101)
Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys
2026-06-03 20:53:07 +02:00
Admin
f91eec1b7f isolates 2026-06-02 18:51:17 +02:00
admin
b94ab6e985 splash md for calculator 2026-05-27 07:39:41 +02:00
Kevin Boos
30342e4234 Improve mobile IME and soft keyboard handling (#1085)
* Support overriding the dpi factor at runtime, on all platforms

Add `Cx::set_window_dpi_override` for runtime UI zoom, but dispatch it
in a deferred manner so it's safe to call in an event handler.

For each platform, we connect the dpi override to the click/tap
coordinates to remap it properly, which was done on some platforms
but not most.

* Fix and restyle todo example

* cad

* Fix todo input styling and studio build env

* fix slides

* Don't apply UI scaling (dpi override) to safe inset areas / IME areas

Scaling those areas doesn't make sense, as it can lead to empty space
(extra unnecessary padding) on the border of the IME or the device inset area,
which looks bad and is basically objectively wrong

-------------

Centralize native/physical/layout DPI conversion on `CxWindow`, and use it at platform boundaries for window geometry, safe-area insets, input coordinates, soft keyboard spacing, clipboard and selection overlays, and camera preview rects.

Add runtime `set_window_dpi_override` support that rescales all window-local metrics and emits `WindowGeomChange`.

* Improve mobile IME and soft keyboard handling

- Add broader soft keyboard configuration for input modes, autocorrect, autocapitalization, return key types, multiline, and secure text entry.
- Improve iOS text input state handling, composition ranges, selection sync, and native/layout coordinate conversion.
- Improve Android InputConnection handling for composing text, selection updates, batch edits, editor actions, surrounding text, and programmatic text sync.
- Wire TextInput through the expanded IME configuration surface.
- Cover newer iOS and Android IME APIs while preserving fallbacks for older keyboard behavior.

* Fix iOS IME area DPI override scaling

* Remove Android-specific IME hack

* Further fix Android IME to avoid stale composition ranges being underlined

espeically after you tap elsewhere in the TextInput widget

---------

Co-authored-by: admin <info@makepad.nl>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:14:21 +02:00
Admin
4a106111b8 ai manager otw 2026-04-28 12:24:40 +02:00
Kevin Boos
c52b353c52 Support runtime changes to script-level heap objects (#1063)
* Support runtime-reassigned module templates and app-wide events

- Dock/PortalList: add `refresh_widgets_mod_template()` so callers can
  re-capture a content template from `mod.widgets.*` after reassigning
  it at runtime via `script_eval!`. Dock's variant takes a separate
  template_key and mod_widgets_name since local DSL names (e.g.
  `room_screen`) don't always match the module entry (`RoomScreen`).
- PortalList: add `all_items_and_pool()` iterator so callers can walk
  every live and pooled item (e.g. to push a new property across the
  whole list on a preference change).
- StackNavigation: forward non-visibility events (`Event::Actions`) to
  all child stack views, not just visible ones. Inactive views need
  global state updates too; `View::handle_event` still gates on each
  child's own `visible` flag for events that require visibility.
- TextInput: add `submit_on_enter` so callers can opt into Cmd/Ctrl+
  Enter submit semantics, plus a `key_focus_lost` helper for commit-
  on-blur inputs.
- Image: honor `Size::Fit { max }` when `peek_walk_turtle` returns NaN
  so `Fit{max: Abs(..)}` caps image height without clipping.
- FlatList: derive `Default` on the shared `WidgetItem` struct.
- draw: re-export `Base` and `FitBound` from turtle.

* Add Event::ScriptReapply + preserve Dock state on reload

- `Event::ScriptReapply`: new event signalling a widget-tree Apply::Reload
  that does NOT re-run `script_mod!`. Fires from `run_live_edit_if_needed`
  when `Cx::pending_script_reapply` is set (previously the flag was never
  observed on desktop). The AppMain macro caches the app's script root as
  a rooted `ScriptObjectRef` and re-applies the tree with it — so runtime
  heap mutations (e.g. `script_eval!` overriding a user preference) stay
  intact. If a file-driven `LiveEdit` handler then sets the flag again, a
  bounded follow-up `ScriptReapply` pass runs in the same tick.

- Dock: on `Apply::Reload`, preserve existing runtime `dock_items` (open
  tabs, selected indices, splitter positions). Only insert DSL-defined
  items for IDs that don't already exist — so a source hot-reload no
  longer wipes the user's opened tabs.

* cleanup, remove unnecessary crap from prior approaches

the whole `refresh_widgets_mod_template` was a misguided approach,
and now that we have script reload/re-apply working and we have fixed
LiveEdit for most widgets, we just don't need it

* cleanup, remove more unused functions
2026-04-22 23:36:56 +02:00
Admin
69aa615947 mlx 5x->2x 2026-04-10 14:46:22 +02:00
Kevin Boos
f36f2e58ad TextInput: support single-line horizontal scrolling when text overflows (#1012)
* TextInput: support single-line horizontal scrolling when text overflows

When a single-line TextInput's text content is wider than its visible area
(due to Fill, Fixed, or parent-constrained Fit width), the text now
automatically scrolls horizontally to keep the cursor visible.

- Add `scroll_x` tracking with auto-scroll-to-cursor logic
- Push a clip rect for all TextInput modes (not just multiline) to prevent
  text from bleeding outside widget bounds
- Layout single-line text without max_width constraint so overflow is
  detectable via `size_in_lpxs.width`
- Handle mouse wheel/trackpad scroll events for single-line horizontal
  scrolling (maps both axes to horizontal)
- Account for `scroll_x` in IME position and selection rect calculations
- Add `Turtle::set_width()` and `Cx2d::compute_max_width_from_ancestors()`
  (width counterparts to existing height methods)
- Add UIZoo examples: Fill width, Fixed width, and Fit-in-container

* a bit more cleanup, no need for clip size to be an option
2026-04-06 16:28:35 +02:00
Kevin Boos
99bcff6dbf TextInput: explicitly support multiline mode with parent-relative max height (#1011)
* TextInput: support multiline mode with proper scrolling

* ScrollBar integration with mouse wheel, scrollbar handle drag,
  and the correct way of dealing with `handled_y` propagation,
  which basically means that scrolling can be handled by the TextInput
  as a child, or not and left to the parent.
* Only auto-scroll to the cursor when it actually moves, not on every redraw
* `is_multiline` controls wrapping too, which makes more sense.
   Now a single-line mode TextINput shouldn't wrap the text
* Allow setting `text` in the Splash DSL (make it `#[live]`)

Also added some examples to the uizoo demo: empty, pre-filled, read-only, toggle
between multi and single line.

* minor cleanup for TextInput multiline/scrolling

* Explicitly support multiline TextInput with Relative max height bounds

* more cleanup

* TextInput: support cascading parent-relative max height bounds

This was needed in Robrix, specifically a fairly common case in which
a TextInput should expand to Fit its content, but should not exceed
a certain percentage of the height of its parent.

This builds on the initial relative min/max Fit bounds that Eddy added
a while back, but weren't directly handled by TextInput, whcih itself
has special demands because it has to start internally
wrapping/scrolling.

* fix merge artifacts
2026-04-03 19:17:15 +02:00
Kevin Boos
0c5d39e2bc TextInput: support multiline mode with proper scrolling (#1010)
* TextInput: support multiline mode with proper scrolling

* ScrollBar integration with mouse wheel, scrollbar handle drag,
  and the correct way of dealing with `handled_y` propagation,
  which basically means that scrolling can be handled by the TextInput
  as a child, or not and left to the parent.
* Only auto-scroll to the cursor when it actually moves, not on every redraw
* `is_multiline` controls wrapping too, which makes more sense.
   Now a single-line mode TextINput shouldn't wrap the text
* Allow setting `text` in the Splash DSL (make it `#[live]`)

Also added some examples to the uizoo demo: empty, pre-filled, read-only, toggle
between multi and single line.

* minor cleanup for TextInput multiline/scrolling

* Explicitly support multiline TextInput with Relative max height bounds

* more cleanup
2026-04-03 19:09:48 +02:00
Kevin Boos
9379d01e21 TextInput: reflow text upon widget resize (width changes) (#1009)
Fixes a minor bug in which the entered text within a TextInput widget
would not get its layout recalculated if the width changed, meaning
that text could get cutoff on the right side of the widget.

Now we ensure that the text layout gets re-done (and the cached value
is not incorrectly used) if the width has changed since the last layout.
2026-04-03 11:30:25 +02:00
offline-ant
dd83d4b759 platform: small fixes and quality improvements (#928)
- Android log levels: map log! macro levels to Android log priorities
  (ERROR=6, WARN=5, INFO=4). Some devices suppress DEBUG by default.
- cargo-makepad android: show help text instead of panicking on missing
  or invalid subcommand.
- Android build: discover .class files dynamically instead of hardcoding
  ~25 individual paths. Add Java 8 source/target flags.
- Remove deprecated AsyncTask import from MakepadNetwork.java.
- Studio stdout: add newline after JSON messages for JSON-lines parsing.
- Studio stdout: skip profiler timing in stdout mode to avoid overhead.
- Script thread: fix panic on empty call stack in call_has_me/call_has_try.
- Cursor: reset to Default on FingerHoverOut in TextFlow and TextInput.

Co-authored-by: ant <ant@offline.click>
2026-03-08 11:24:18 +01:00
Kevin Boos
97bb42e439 TextInput: actually use color_empty_hover/focus in draw_text shader (#927) 2026-03-07 09:46:44 +01:00
Admin
78a4a416fb override play 2026-02-27 10:28:00 +01:00
Admin
4586f861d9 text cast in set_text 2026-02-24 17:12:54 +01:00
Admin
582af4b271 splice out a makepad-network crate 2026-02-23 23:21:31 +01:00
Julián Montes de Oca
40cad5dd37 Restore IME support (#860)
* Restore IME support

* Remove unused voice handling methods from Window
2026-02-20 14:06:02 +01:00
Admin
81db1516d9 todo app 2026-02-12 19:58:49 +01:00
Admin
8e6702c56b First 2.0 2026-02-12 14:52:33 +01:00
Admin
a271bd0027 compile 2026-02-10 18:26:51 +01:00
Eddy Bruel
986eb8218f Clear layout cache in text input if turtle width changes. 2026-02-06 15:38:00 +01:00
Julián Montes de Oca
0dd31cb6c8 IME: Support on Android and Input Configuration (#839)
* WIP

* Improvements for cursor control

* Enhance text selection and key event handling for Samsung keyboard compatibility

* Default to multine inputtype in android

* WIP Input configurations

* Enhance iOS text input handling

* Cleanup

* Comment out 'Next' variant across platforms for future implementation.

* Rename IME Config API to match web APIs

* Fix Android emoji deletion by implementing UTF-16 code unit index conversion

* Proper ASCII-only input and improve iOS keyboard handling

* Replace 'is_numeric_only' with 'input_mode'

* Prevent pasting invalid characters

* Cleanup

* Cleanup

* Hide clipboard actions on text change

* Cleanup

* Unify keyboard event types and fix iOS text input regressions

Unified TextInputEvent with new fields for better IME support across platforms:
- Added `composition` field for IME preview ranges (CJKinput)
- Added `full_state_sync` for complete buffer state (Android approach)
- Added `replace_range` for autocorrect/suggestion replacements (iOS approach)

All platforms: Standardized on CharOffset for character position handling

* Prevent text synchronization with the platform during active composition

* Add UITextInputCurrentInputModeDidChangeNotification support

* Add underline for active IME composition in TextInput

* Improve editor action handling for multiline inputs on Android

* Enhance IME composition tracking and clipboard action handling in TextInput

* Simplify IME state handling on Android

* Cleanup IME handling on iOS

* Cleanup

* Cleanup IME handling on iOS

* Improve docs/comments

* Improve docs/comments

* Add floating cursor support for keyboard trackpad in iOS

* Refine IME handling in TextInput to prevent iOS buffer loss during composition updates

* Move UITextInput protocol implementation into its own module

* Move MakepadInputConnection into its own file

* Cleanup

* Improve general IME handling in TextInput. Improve docs and comments

* Refactor text input configuration to separate soft keyboard settings for mobile platforms.
2026-02-02 11:48:21 +01:00
Eddy Bruel
b88eb5ed1d Whitespace should never be wrapped 2026-01-20 20:40:17 +01:00
Jason Yau
01c48991b7 fixed IME composition popup position for Windows (#841)
Co-authored-by: jasonqiu <jasonqiuchen@outlook.com>
2026-01-17 17:57:36 +01:00
Julián Montes de Oca
900bc6276b iOS: Add UITextInput protocol implementation for IME support (#838)
- MakepadTextInputView with marked text (composition) for CJK input
- UTF-16 ↔ char index conversion for emoji/Unicode handling
- TextRangeReplaceEvent for autocorrect/autocomplete
2026-01-12 14:10:44 +01:00
Julián Montes de Oca
e07406460d Add clipboard actions support for iOS (#833)
Implemented UIEditMenuInteraction for clipboard actions, allowing copy, cut, paste, and select all functionalities.
2026-01-06 17:00:02 +01:00
Kevin Boos
eb6396b5eb Add optional serde derives for Serialization/Deserialization on select public types (#831)
Can be activated by setting the "serde" feature on `makepad-widgets`
(or other internal crates).
2025-12-18 08:38:58 +01:00
Admin
0a1e93a89e align mathtypes to WGSL 2025-12-02 11:43:12 +01:00
Julián Montes de Oca
7ff2574dfc Android: Implement ShowClipboardActions with native ActionMode (#821)
Cx API:
- Implement existing ShowClipboardActions
- Add HideClipboardActions
- Cross-platform API ready for iOS implementation

Android Implementation:
- Native ActionMode integration with floating toolbar (API 23+)
- JNI bindings for showing/hiding menu and handling clipboard actions
- Event system for Copy/Cut/Paste/Select All actions
- Smart menu state management based on selection and clipboard

TextInput Integration:
- Long press selects word and shows menu
- Double tap and long press selects word and shows menu
- Selection preservation when tapping selected text
2025-11-22 10:06:05 +01:00
Eddy Bruel
de1c50317d Implement per-row alignment for rightward flowing turtles 2025-10-30 12:43:18 +01:00
Eddy Bruel
cdcae82792 Unify Size::Right and Size::RightWrap 2025-10-28 09:20:57 +01:00
Eddy Bruel
5ae24ac81a Fix 2025-10-27 11:19:22 +01:00
Eddy Bruel
090aa10932 Remove spurious printlns 2025-10-27 11:13:50 +01:00
Admin
76cce72dc9 Fused Id and LiveId 2025-10-25 20:53:30 +02:00
Julián Montes de Oca
c85f72f00d Add focus loss detection to TextInput, for keyboard dismissal (#802)
TextInput now self-detects when user taps outside its area and dismisses the keyboard.
The tap event is not consumed.

Fixes keyboard staying open when tapping widgets that don't grab focus.
2025-10-25 19:42:32 +02:00
Eddy Bruel
07fbece97f Rethink selection drag scrolling as a post-op during draw 2025-10-24 11:40:36 +02:00
Eddy Bruel
3634a1c9e1 Implement vertical selection drag scrolling for TextInput 2025-10-23 10:48:02 +02:00
Eddy Bruel
9af5173fae Add ascender to selection rects 2025-10-21 12:24:33 +02:00
okapii
f8e511fec1 Fixes 2025-07-10 14:48:34 +02:00
okapii
48433b8708 Consistent theme application and rotary focus state optimizations 2025-07-10 13:56:13 +02:00
okapii
532453f4bb Further complete dither support 2025-07-10 12:24:32 +02:00
okapii
9478bf7b41 Complete gradient dither support 2025-07-10 12:04:09 +02:00