Commit graph

532 commits

Author SHA1 Message Date
Admin
bb96d856dc map: typed MVT decode — no more JSON round trip
Local tiles decode the MVT protobuf straight into tile-local f32
features (MvtSink trait + MvtLocalCollector with scale-aware thinning);
the MVT -> generated-Overpass-JSON -> parse detour is gone (a ~1-3MB
binary tile inflated to ~10MB of JSON re-parsed on every restyle, most
of the ~1s per-tile rebuild). The shared feature builder now takes
tile-local ways/points; the Overpass network path projects into the
same structures. MvtTileJsonBuilder deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:46:34 +02:00
Admin
40efe563bc map: cross-fade tile generations instead of popping
New tile geometry fades in over 250ms via a tile_fade uniform
(multiplies the premultiplied output); the replaced generation's
geometry stays drawable underneath until the fade completes, so bucket
restyles and fresh tiles blend instead of flickering in. A 16ms timer
keeps frames coming while any fade is active (the paint beat idles
without input).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:37:02 +02:00
Admin
64489c622c map: labels track zoom via affine cached draw; no more vanishing
Cached label placements were redrawn shifted by the raw map-offset
delta; during a zoom the offsets change by world-scale amounts, flinging
the cache thousands of px off-screen (labels vanished just off max zoom
and stayed gone while idle because the re-place rate limit counted
frames). Now: cached glyphs draw through the exact affine screen
transform s*k + (off_new - off_old*k) with glyph size scaled, so labels
track the map mid-gesture; the re-place limit is wall-time based; and
the settle timer re-arms until a budget-truncated label pass completes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:34:57 +02:00
Admin
d0a4aa0951 map: time-based zoom settle + timer wake — restyle without wiggling
The settle window counted FRAMES, but the paint beat idles when input
stops: after a zoom gesture no frames occur, the frame delta never
reaches the threshold, and stale-bucket restyles only fired when the
user wiggled the map. Settle checks now use wall time and the zoom
gesture schedules a 150ms timeout so a wake is guaranteed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:26:02 +02:00
Admin
ec33c95f77 map: request watchdog, at-rest full label pass, bigger tile label cap
- in-flight tile requests time out after 600 frames and clear stuck
  Loading placeholders; a leaked key would otherwise choke the 12-slot
  dispatch cap (zoom-only restyles appeared to never regenerate)
- label placement budget only applies during gestures; at rest a full
  pass runs, otherwise the lowest-priority tail (house numbers) was
  permanently truncated at the same point every re-place
- per-tile label cap 32768: a city-sized overzoomed tile can exceed 16K
  labels and the priority sort dropped addresses first

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:23:40 +02:00
Admin
fd726568be map: dispatch tile rebuilds as parallel per-tile jobs
Single-batch dispatch meant one tile in flight at a time after a zoom
(requests only advance when a draw happens, draws only happen when a
tile lands) — restyles trickled sequentially. Now every missing/stale
tile dispatches its own worker job, up to 12 in flight, so a viewport
restyle overlaps across the pool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:18:25 +02:00
Admin
e4b271d294 map: 120Hz pan/zoom — rate-limited label placement, parallel restyles
Gap-distribution instrumentation on the 7680x2160@120 display showed the
renderer can hold 120fps (gap_avg 8.4ms in calm stretches) but dropped
frames wherever labels are dense: full label re-placement (5-22ms) ran
almost every other frame during pan (tile arrivals + pan distance
invalidated the cache) and EVERY frame during zoom (exact zoom equality
in the cache check).

- full re-places rate-limited to ~8/s; between them the cached placement
  draws shifted (~2ms), including during zoom gestures where labels stay
  screen-pinned briefly (pinch behavior a la Google Maps)
- each placement pass gets a hard 7ms budget; highest-scored labels
  place first, the tail defers to the next pass
- gap avg/max and >12ms counts added to the perf log
- tile restyle after zoom: one tile per worker job (10-tile batches ran
  sequentially in one closure, 2-3s per batch), settle delay 150->80ms

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:16:44 +02:00
Admin
b150f6f75d map: shrink tile geometry — the frame-gap stutter was GPU-side
Instrumentation showed draw_walk at ~1ms and CPU tile insert at ~2-3ms
while inter-frame gaps hit 200-1000ms during interaction: the stall is
GPU buffer upload/pressure from oversized tiles (a bucket-17 z14 tile
holds ~6.8K outlined buildings -> tens of MB of 19-float vertices).

- scale-aware vertex thinning: drop points closer than ~0.35 screen px
  at the styled zoom (invisible detail dominated vertex volume)
- building outlines use miter joins (round-join bevel expansion on ~60K
  ring points per tile was the largest single buffer)
- tile GPU uploads throttled to 2 per frame via a pending queue
- resident tile cache capped at 48 (was 640) with faster idle eviction

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 17:06:03 +02:00
Admin
fb4df8ff4c map: frame-time instrumentation + label scan/draw cost fixes
- perf log: draw_walk aggregates total/geometry/label ms, max frame,
  inter-frame gap and full-placement count per 240 frames into
  local/map_perf.log
- labels precompute name_key + tile-local bbox at tile build; the
  per-frame scan does no allocation and rejects offscreen labels with
  two point transforms before any path work (an overzoomed tile holds
  ~16K labels, mostly offscreen)
- batched glyph path no longer runs update_draw_vars per call (the open
  batch already did); halo underdraw 8 -> 4 diagonal offsets, halving
  glyph volume
- fill clip overlap shrunk to ~1 screen px: the wider double-drawn
  strip let the later tile's land paint over the earlier tile's
  buildings (pale band at tile edges at high zoom)
- point local mbtiles back at noord-holland-shortbread-1.0.mbtiles

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:57:59 +02:00
Admin
15d0572849 map: label performance pass — batch, pan-cache, shape-cache
- one glyph instance batch per frame (begin/end_glyph_batch on
  DrawRotatedText): every glyph previously opened and closed its own
  aligned-instance batch, x9 with the halo underdraw
- label placement cache: pan-only frames redraw the previous placement
  shifted by the pan delta (like the tile geometry) instead of
  re-scanning up to 16K labels and re-shaping/re-colliding ~1-2K; full
  re-placement only after 48px of pan, zoom change, or tile updates
- shaped-run cache keyed by (text, quantized font_scale) so periodic
  re-placements stop re-shaping every string every time

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:47:40 +02:00
Admin
200b9d0c34 map: settle-deferred zoom restyles, full house-number coverage
- zoom-bucket restyles wait ~0.3s after the last zoom change so line
  widths scale geometrically (smooth) during the gesture and re-style
  once, instead of flickering tile-batch by tile-batch mid-zoom
- per-tile label cap 16384 and larger z16.5+ budgets: an overzoomed z14
  tile holds a whole city's addresses and lowest-priority house numbers
  were truncated before the viewport filter ever saw them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:37:56 +02:00
Admin
2d00fc3b02 map: zoom-constant vector POI symbols + green-area ranking fixes
- openstreetmap-carto symbol SVGs (CC0) tessellated once at final screen
  size and baked into a 4th tile-cached vector buffer; vertices encode
  anchor + screen-px offset, the map vertex shader (shape id 20) adds the
  offset after the map transform so symbols keep constant pixel size at
  every zoom — pure GPU vector, no raster atlas
- POI symbols colored by class (orange food, purple shops, brown culture,
  red health incl. pharmacies), labels shifted below the symbol
- symbols gated to z17+ and hidden immediately on zoom-out even while
  stale higher-bucket tiles are still displayed
- green areas (leisure/grass/forest/gardens) rank above generic landuse:
  they share the shortbread land layer with huge residential polygons and
  lost to protobuf feature order (Bellamyplein rendered gray)
- cache-only fallback when the local mbtiles source is missing (e.g.
  while a larger extract downloads)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:34:57 +02:00
Admin
868d5e1bf2 map: tile-seam overpaint fixes, label halos/colors/stability, z19
- per-end line caps (Tessellator::stroke_ends): butt at tile-clip cuts,
  round at true ends — road cap discs no longer stamp over neighbor
  tiles' tram tracks and roads at seams
- fill polygons clipped to their own tile square (Sutherland-Hodgman);
  a tile's MVT buffer fragments no longer overpaint the neighbor;
  building outlines skip segments running along the tile cut
- stroke clip padding 3px (under the generator buffer) so boundary
  cuts are detectable
- white label halos (8-offset underdraw, theme label_halo color)
- carto POI label colors (orange food, purple shops, brown culture,
  muted house numbers) from shortbread poi attributes
- label placement hysteresis across frames (no flicker while panning)
- street_polygons fill ranked below sites/parks (Bellamyplein-class
  plazas no longer cover the park inside them)
- max zoom 19 with width stops for z18/19

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 15:53:36 +02:00
Admin
98034562fb map: rebuild MapView to openstreetmap-carto quality
- semantic fill paint order (land/sites/water/buildings/street areas);
  raw MVT layer order was painting land over 6,880 buildings per tile
- tile-local f64 coordinates + per-tile offsets; fixes f32 web-mercator
  quantization (0.25px vertex, 2px shader ULP at z17)
- casing/center stroke buffers split; fills -> all casings -> all centers
  across tiles (carto roads-casing/roads-fill order)
- per-view-zoom-bucket restyling with carto width stops; stale buckets
  stay drawable during rebuild; screen-space AA/tolerance
- carto palette, building outlines z15+, bridge decks, tram/rail from
  streets layer above road centers, thin-path slow width growth
- house numbers (addresses) and shop names (pois) as point labels z16+
- MVT-correct absolute ring winding for multipolygon classification
- visible_tile_keys divides viewport by overzoom (was 64x over-request)
- text: prepare_single_line_run scales glyph size+raster with font_scale;
  draw_path_glyphs pins ambient font_scale (letter-spaced labels bug)
- script derive: cast numeric field defaults instead of .into() fallback

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 15:34:44 +02:00
Athan
b41e7404b6
feat : add advance vide player example (#1138)
Co-authored-by: Athan Xiao <Athan.Xiao@one.nz>
2026-07-23 12:16:19 +02:00
Kevin Boos
b01e35faca
Avoid redrawing for simple text-based widgets (#1141)
redrawing is significantly more expensive than text comparisons,
and doing this outside of each widget is difficult and less efficient.

this helped avoid a bunch of redraw cycles in robrix,
so it's probably worth doing for all widgets, especially since
setting text or another basic property now does an auto-redraw
(it didn't used to be like that)
2026-07-23 12:13:44 +02:00
Kevin Boos
a4fea8e259
New unified kinetic scrolling. Vastly improve draw shaprness on low-res screens. Fix rendering and text perf issues on CPU+GPU (#1127)
* Fix rendering, gradient, sampling, etc issues on older GPUs

* Fix bug in `box_y` sdf function, which caused gradients to be split
  into two bands incorrectly. Mostly a problem on lower-res screens.
* Use per-texture filtering instead of GL sampler objects on Linux,
  especially for Mesa drivers that ignore min filter samplers.

This should help prevent blocky/pixellated things like emoji/avatars

* Improve rendering sharpness on low-DPI screens (icons, emoji, images)

On 1.0-DPI screens, emoji/SVG-icons/avatars were minified without
adequate sampling and SVG AA was sub-pixel, producing blocky/aliased
output. This reworks each path and adds optional full-window SSAA.

SVG icons (device-aware AA + round caps):
- draw_svg.rs/draw_vector.rs/render.rs: size the fill & stroke AA
  fringe and the curve-flatten tolerance in DEVICE pixels (≈constant
  regardless of icon size), so edges resolve via the analytic
  d/fwidth coverage and curves stay smooth at any scale; re-tessellate
  on scale change.
- triangulate.rs: thread the flatten tolerance through path fill/stroke.
- tessellate.rs: emit round caps as a solid disc (u=0.5) instead of a
  radial fade that collapsed to a square at small sizes.
- widgets/icon.rs: don't clip the Icon to its Fit bounds, so round
  caps that extend past the box render fully instead of being sheared.

Emoji:
- glyph_raster_image.rs/rasterizer.rs: rasterize color emoji near the
  on-screen size with an alpha-weighted box downscale (geometric-mean
  scale factor) instead of the font's native PNG strike.

Images / avatars (mipmaps):
- image_cache.rs/texture.rs/draw_list.rs/lib.rs: optionally emit a CPU
  mipmap chain (VecMipBGRAu8_32) for non-animated images so minified
  avatars/thumbnails sample cleanly. Env-gated MAKEPAD_IMAGE_MIPMAPS;
  default on for GL on Linux.
- metal.rs: real per-level mip upload. d3d11.rs/vulkan.rs/web_gl.rs:
  safe single-level fallback (no crash; real mips TODO).

Full-window supersampling (optional):
- window.rs: render the whole UI into an offscreen target at
  MAKEPAD_SUPERSAMPLE× device resolution and downscale-resolve into the
  window. Default 2×, env-tunable, 1× disables. Modeled on the existing
  GaussStack render-to-texture path.

* don't unconditionally enable supersampling SSAA of 2x by default

it's too expensive and too slow for most older devices

* cleanup, reduce comment verbosity

* improve SVG anti aliasing

* Windows: fix laggy/juddery scroll performance

- Pace the render loop to the display refresh using a DXGI frame-latency
  waitable object and present with vsync, replacing the free-spinning,
  uncapped Poll loop that caused uneven scroll cadence.
- Coalesce consecutive WM_MOUSEMOVE messages and paint once per loop pass
  to stop the judder when moving the mouse during fling deceleration.
- Cache get_dpi_factor() and the WM_NCHITTEST WindowDragQuery result to
  avoid per-mouse-move GetDeviceCaps syscalls and widget-tree hit-tests.
- Throttle XInput/DirectInput polling of empty/disconnected controller
  slots, which was stalling the UI thread.
- Rework the momentum fling to a native exponential model with a
  frame-interval EMA, and stop the tail auto-scroll from fighting an
  active fling/drag.
- D3D11: update the glyph atlas and image textures in place via
  UpdateSubresource instead of recreating them on every change, and
  spread D3D11 shader-object creation across frames.
- Slug atlas: only force a full re-layout on a width change; append rows
  on height growth.

* Windows: correctness fixes from review (off the scroll hot path)

- d3d11: close the DXGI frame-latency waitable HANDLE in Drop (it was
  leaked once per main-window lifecycle and the field comment was wrong);
  keep popup swap chains at frame-latency 1; track the waitable-swapchain
  flag for ResizeBuffers instead of inferring it from the handle; present
  without the vsync interval during a live resize.
- windows.rs: poll game input on the idle signal tick so a gamepad button
  can be serviced while the app is otherwise idle.
- win32_window / window: invalidate the WM_NCHITTEST / WindowDragQuery
  caches on window move and on a caption relayout, with a generation
  counter guarding against a reentrant invalidation being clobbered.
- windows_game_input: detect a controller already plugged in at launch via
  a one-shot full scan on the first poll, probe slot 0 (Player 1) first,
  and offset the DirectInput enumeration so it never stacks with the
  XInput probe.
- comment/doc corrections.

* Image cache: accept any Arc<D: AsRef<[u8]> + ?Sized> for async image data

The load_image_from_data_async family required Arc<Vec<u8>>, forcing callers
that already hold the bytes as Arc<[u8]> (e.g. a content-addressed media cache)
to copy the whole buffer via .to_vec() just to satisfy the type. Generalize the
data parameter to Arc<D> where D: AsRef<[u8]> + ?Sized, so those callers can pass
their existing Arc by refcount-clone with no byte copy. The decode path only ever
borrowed the bytes (&[u8]), so this is purely a signature relaxation; existing
Arc<Vec<u8>> callers are unaffected (D = Vec<u8>).

* Linux: GL glyph-atlas in-place texture update + X11/Wayland mouse-move coalescing

* Scroll: unified fling model + native trackpad momentum deceleration

Share one kinetic-scroll model between PortalList and ScrollBar (and thus
ScrollXView/ScrollYView/ScrollXYView) via a new widgets/src/scroll_motion.rs:

- Touch-drag flicks use an iOS-style exponential self-decay, frame-rate
  independent via a per-frame integrator with dt smoothing.
- Trackpad scrolling applies the OS momentum directly while fast (responsive,
  full native speed), then hands off to a gentler self-decaying tail once it
  slows past a threshold, so the deceleration is longer and smoother than the
  OS's short, choppy tail. Handoff is seeded at the current speed for a
  continuous transition; the seed is clamped against degenerate event timing.
- Add ScrollPhase to scroll events, mapped from NSEventPhase/momentumPhase on
  macOS and wl_pointer AxisStop on Wayland; None elsewhere (wheels/X11/Windows
  behave as before). MAKEPAD_RAW_TRACKPAD_MOMENTUM=1 bypasses the smoothed tail.
- A press catches an in-progress fling (stops the scroll, consumes the press so
  it doesn't also activate a child), matching iOS/Android/macOS.

* Shader codegen: prefix Metal/WGSL locals to avoid reserved-word collisions

The Metal/WGSL backends emitted user-declared shader locals verbatim, so a
local named after a reserved type keyword (e.g. `half`) produced invalid
shader source and failed to compile at runtime. Prefix them with `l_` like the
HLSL/GLSL backends already do.

* TextFlow: don't panic on unbalanced HTML close tags

end_code/end_quote unwrapped the area stack, so a stray `</pre>` or
`</blockquote>` in untrusted content (e.g. a chat message) panicked. Return
early instead, and drop a vestigial per-list-item area-stack push that leaked
an entry and could hand a stray close tag the wrong block's area.

* Scroll: expose fling decel, handoff threshold, & tail-decel as `#[live]` fields

This allows app devs to override the scroll feel per-widget in the DSL,
or globally by overriding the base widget's defaults — verified that a DSL
override takes effect.

* Windows: fix frame pacing, paste crash, and wheel input backlog

- Wait on the frame-latency waitable right before each window's vsync
  present instead of on every Paint, so input no longer stalls behind
  waits that have no matching present. Drain leftover credits after a
  live resize.
- Pasting when the clipboard has no text no longer panics.
- The poll loop now handles up to 32 messages (2 ms) per frame and
  merges consecutive mouse-wheel messages, so fast wheels can't build a
  backlog that keeps scrolling after the gesture ends. Sleep 1 ms when a
  frame presents nothing so animation polling doesn't spin a core.

* Image: don't build unused mip chains; fix stale images in recycled widgets

- Only build the CPU mip chain when a backend actually uploads it
  (Metal, behind its env var), and build it on the decode thread instead
  of the UI thread. Linux GL still gets its mipmaps via glGenerateMipmap
  and now retains less CPU memory per image.
- Recycled Image widgets no longer show the previous item's image or
  apply an old decode result. Placeholder textures set via set_texture
  (like blurhashes) stay visible while the real image decodes, and a
  failed load clears the widget instead of leaving old content up.

* Widgets: avoid needless caption redraws; cheaper PortalList height tracking

- Label::set_text does nothing when the text hasn't changed, and the
  window caption title is only synced when it actually changes, so mouse
  moves and animation ticks no longer redraw the whole window every
  event. The caption centering padding requests its own redraw now.
- PortalList records item heights only when new or changed, and only
  re-applies the default height after it drifts by half a pixel, so big
  lists don't walk every unmeasured item on every scroll frame.

* Text: cache layouts of long texts; stop cloning glyph outlines every frame

- The layout cache now accepts texts of any length (long messages and
  code blocks used to re-layout on every scroll frame). It is a real LRU
  with a byte budget on top of the entry cap, and texts drawn in the
  current frame are never evicted, so one heavy frame can't thrash the
  cache into a permanent miss cycle. The shaper cache is LRU now too.
- Glyph outlines are shared via Rc, so drawing a cached glyph no longer
  copies its command list, and outline complexity is computed once when
  the outline is built instead of every frame.

* Html: fix stale links/spans in recycled widgets and <details> renumbering

- set_text only rebuilds when the content actually changed, so a
  recycled link can't open the previous message's URL, and re-setting
  identical content keeps the user's <details> open/closed state.
- Custom widgets and <details> are keyed by their node index instead of
  a visit-order counter, so toggling a collapsed <details> can't
  renumber the widgets after it and rebind them to the wrong nodes.
  item_with_scope also recreates its widget when the template changes.

* Linux: fixed-distance wheel scrolling; Wayland frame-callback pacing

- Wheel scrolling moves a fixed 60 px per detent on X11 and Wayland
  instead of a timing-based guess that flipped between 12 px and 240 px
  depending on how events batched. Wayland reads real detent counts via
  AxisValue120 (wl_seat v9, with AxisDiscrete as the older fallback) and
  maps keymaps MAP_PRIVATE as v7+ requires. Touchpads are unchanged.
- Wayland frames are paced with wl_surface frame callbacks and swap
  interval 0, so redrawing a hidden or minimized window can no longer
  hang the whole app inside eglSwapBuffers (compositors withhold frame
  callbacks for hidden windows). Windows with a callback in flight skip
  presenting and stay dirty; X11 keeps vsync exactly as before.

* Text: bigger layout cache budget, reclaimed at the end of each frame

A maximal ~60 KB message lays out to roughly 4 MB of glyphs, so the 4 MB
budget couldn't hold even one alongside a normal screen. Raise it to
16 MB, and run eviction at the end of every frame so memory over the
budget is freed one frame after its content leaves the screen, instead
of lingering until some later layout happens to insert a new entry.

* Fix oversized uniform slices: the array lengths were in bytes, not f32 elements

* Wayland: flush buffered mouse motion before scroll events, and drop motion for closed windows

* GL: fall back to non-mipmapped filtering when glGenerateMipmap fails on strict GLES3 drivers

* Text: bucket emoji raster scales so zooming reuses atlas slots instead of re-decoding every step

* Image: add has_content() and record texture provenance on cache-hit loads too

* Scroll: native trackpad momentum, Chrome-model bounce; presses catch motion, never click children

* Dock: redraw the newly selected tab immediately when the active tab is closed

* Html: standard link colors with pressed precedence; skip re-parsing unchanged text; color setters

* Image: don't redraw on cache-hit loads of the already-bound image (per-draw reloaders looped forever)

* Scroll: log macOS momentum-end phase bits to check Cancelled (touch-cut) vs Ended (natural fade)

* Scroll: momentum state machine; flicks survive pagination; edge sentinels & once-per-frame actions

* Scroll: remove the MAKEPAD_SCROLL_DEBUG diagnostics

* Scroll: time-based fling velocity window; pointer fan-out guard; parked flings survive pagination

* PortalList: optional reached-start/end margins (Some(0) default); repositioning re-announces the edges

* Linux/Wayland: honor UI zoom across window resizes; scale caption bar with zoom

Keep the wayland-side window geom in native units so the zoomed dpi isn't
read back as "native" on the next Configure — UI zoom no longer resets or
flickers on maximize/tile. Also let the caption bar height scale with the
zoom (pin to native only on macOS, where the buttons are OS traffic lights).

* Windows: D3D11 fixes for drawlist mgmt

trying to help with the `new_batch` bugs

* draw_list.rs — `set_zbias` now returns whether it changed
* d3d11.rs — uploads draw_call_uniforms on the given condition:
  `uniforms_dirty || zbias_changed || buffer.is_none()`
  and the zbias advance is hoisted above the early-continues

* Scroll: hard flicks carry farther and boost on re-flick; iOS-style touch rubber band with per-edge bounce gating; Android fling spline behind a flag

* Splitter: redraw both pane subtrees on drag; cached views keep fresh fixed sizes in the dirty check

* iOS: re-deliver window-geometry changes dropped by re-entrant UIKit callbacks; Init only ever from the first draw

* final cleanup fixes. Ensure all examples, experiments, `studio` all work

* Image: skip re-parsing an SVG that is already shown, keyed on the caller's shared bytes

* CachedView: fix upside-down offscreen texture on GL/GL-ES

GL/GL-ES store offscreen FBOs bottom-up, unlike Metal/D3D/WGSL.
The DSL->script-shader migration switched the CachedView composite to plain
.sample() (non-flipping sample2d on GL), so cached views rendered
vertically mirrored on GL/GL-ES; Metal was fine on macOS.

Add a `sample_rt` script sampler (emits the V-flipping sample2d_rt on
GLSL, plain no-flip sample elsewhere) and use it in the CachedView and
CachedRoundedView composites.

* Fix `AdaptiveView::redraw()` to actually do something
2026-07-21 09:59:12 +02:00
Admin
221b6a4a72 gamemaker: Escape as push-to-talk alongside F1
VoiceWave grows an opt-in ptt_use_escape flag (Escape doubles as cancel/
dismiss elsewhere, so hosts choose); both keys drive the same logical talk
button. Gamemaker opts in via the caption_bar's hidden voice_wave and the
hints now read 'hold Esc' — the big friendly key for kids. Verified the
nested named-child merge lands on the live widget.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:05:45 +02:00
Admin
eb4165d5a0 macos: A/B diagnostics — MAKEPAD_NO_VSYNC, MAKEPAD_TIMER_TRACE, MAKEPAD_NO_GAUSS
Verdict on the gamemaker judder (measured, 25s A/B runs, same window size):
  gauss OFF        -> unchanged (25-33ms gaps)   [pyramid exonerated]
  empty game world -> unchanged                  [game exonerated]
  vsync OFF        -> FIXED (119.8fps steady, worst 9ms; slow callbacks 124->2)

The stall is CAMetalLayer display-sync throttling: the compositor (hardware-
mirrored + SwitchResX-scaled 7680x2160) returns drawables unevenly, and
nextDrawable blocks the main thread 10-25ms in phases. The durable fix is
present-gated pacing: track in-flight presents via addPresentedHandler and
skip the paint when the pool is busy instead of blocking the event loop.

MAKEPAD_TIMER_TRACE=1 logs paint-clock fire-to-fire gaps >20ms and slow
callbacks >10ms with a per-step breakdown (live_edit/net/pad/paint/gc).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:45:59 +02:00
Admin
e7a7cad092 perf 2026-07-10 15:34:38 +02:00
Admin
77e7d65fb7 macos: pace paint timer to display refresh; PerfGraph gpu channel + pass trace
The fixed 8ms timer0 presented ~125Hz into a 120Hz vsync queue: the drawable
pool drifted full and nextDrawable blocked the main thread in a ~25-frame
sawtooth (PerfGraph 'wait' ramps). Timer now arms at 1.002/max_fps across
attached NSScreens — the +0.2% makes NSTimer lateness drain the queue instead
of accumulating. Sawtooth verified gone.

perf_monitor: 'gpu' channel — presented-frame GPU interval tapped from the
existing command-buffer completion aggregation (atomic hand-off, folded at
frame_boundary; concurrent with CPU channels, plotted violet).

metal: MAKEPAD_GPU_PASS_TRACE=1 logs per-pass GPU time ([gpu-pass] name ms)
for frame-budget hunts.

Measured (gamemaker, empty world vs full racing game — identical ~4.7ms GPU):
the frame cost is the UI glass pipeline, not the game — scene capture +
6 mip downsamples + 3 smooth upsamples re-run every frame at 120Hz because
the game pane dirties the window; at low GPU clocks the 11-pass chain's
latency swings past the 8.3ms budget in phases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:30:08 +02:00
Admin
4cfb51877c PerfGraph: generic frame profiler widget + Cx perf monitor channels
platform: Cx.perf_monitor — per-frame ring (240) of paint-to-paint gap +
per-channel CPU us. Built-in channels: event dispatch (outermost, minus
app-attributed time), script exec, GC, pass encode, nextDrawable wait.
Apps register custom channels: cx.perf_monitor.channel("physics", rgb).
Off until enabled; hooks in event dispatch, macos repaint, metal draw_pass.

widgets: PerfGraph — corner-pinned live panel (DrawVector strips): frame-gap
bars colored against 120/60Hz budgets with guide lines, stacked per-channel
CPU, legend with averages. Self-positions bottom-right (DrawVector geometry
+ deferred turtle alignment don't mix — no aligning parent).

gamemaker: PerfGraph hovers the game pane (F3 toggles), engine feeds script
+ physics channels (incl. hot-reload evals); engine text overlay moved to
F4; per-phase engine window kept for ag perf / AIGAME_PERF=1; new 'ag perf'
harness verb + template guidance (template CLAUDE.md force-added: runtime
resource, blanket CLAUDE.md gitignore had kept it untracked).

Measured on my-game-5: engine frame CPU ~0.3ms; the hiccup is frame pacing —
the 8ms NSTimer paint clock beats against the 120Hz display, the drawable
pool drifts full and nextDrawable blocks the main thread in a ~25-frame
sawtooth (avg 2-3.4ms, spikes 20-30ms). The graph shows it as red ramps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:10:27 +02:00
Admin
fbd4972450 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
30eeae75ca
View: add fn for toggling optimize and force texture caching (#1136)
* TextInput: expose the location of the caret/cursor

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.

* View: add fn for toggling `optimize` and force texture caching

Add CachedView fns that make it easier to control its parameters:
* set_optimize(cx, ViewOptimize): switch optimize mode at runtime and
  allocate the draw_list on demand. Previously `optimize` was set once from
  `texture_caching` and never reset, so a view couldn't toggle between direct
  and texture-cached rendering per frame.
* set_texture_max_height(Option<f64>): cap the Texture-mode render turtle's
  height so a tall Fit-height cached view can't allocate a render target past
  the GPU's max texture size (was a hard MTLTextureDescriptor abort once
  content exceeded 16384px). None (default) leaves it uncapped; content past
  the cap is clipped. Only affects Texture mode.
* redraw_texture_cache() / force_texture_redraw: force one offscreen
  re-render after a content repopulate or an optimize-mode flip. The
  rect-based will_redraw check can't see a content change on a recycled or
  toggled view, so without this it would composite a stale texture.
* view_size is now updated in every optimize mode, not just draw-list modes.
  The None (direct-render) path previously left it stale, so a view toggled
  None<->Texture sized its next offscreen turtle from an old height and
  clipped/mis-positioned its content.
2026-07-02 08:34:19 +02:00
Kevin Boos
c65b72efad
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
3a82d26045 hypothetical heap access fix 2026-07-01 14:04:23 +02:00
Admin
a4c87a64dd animating buttons 2026-06-26 16:46:24 +02:00
Admin
e7939c8f14 animating bg 2026-06-26 15:49:25 +02:00
Admin
a6c7a22ba8 glass centering 2026-06-26 13:07:21 +02:00
Admin
cba6d6ff7e aichat 2026-06-25 16:11:42 +02:00
Admin
ac10a82c34 aichat otw 2026-06-25 16:11:42 +02:00
Admin
3ad65e8bd3 glass kit more 2026-06-25 16:11:42 +02:00
Admin
725a726e3d glass kit more 2026-06-25 16:11:42 +02:00
Admin
374fa0c285 gloop glass radio 2026-06-25 16:11:42 +02:00
Admin
f91b0fa0bd gloop glass radio 2026-06-25 16:11:42 +02:00
Admin
70062ed86b gloop glass radio 2026-06-25 16:11:42 +02:00
Admin
ba0306d4ee Add glass_panel widget example; restore rustfmt guard
- New GlassPanel widget (widgets/src/glass_panel.rs) + lib export
- gauss_view: honor surface_alpha for translucent glass surfaces
- examples/glass: standalone demo (wired into Cargo workspace + makepad.splash)
- rustfmt.toml: re-enable disable_all_formatting to stop rustfmt from
  reformatting the whole tree on save

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:11:42 +02:00
Kevin Boos
e4e1585b05
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
529f7d7720
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
bc13b891e5
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
585475d02a
Fix modal behavior: prevent scroll behind it, make Fit{max} scrollable (#1117)
* Ensure that a view that specifies Fit with a max value can be scrolled.
* Turtle: include a view's outer maring in the size calc for a `Fit{max}` bound.
* Modal: dismiss on Escape KeyUp (not KeyDown) so the release can't leak to a
  background widget behind the modal.
* Modal: allow scrolling, and reset the scroll to the top when showing it.
* Touch-baased dragging for views (ScrollBar) and PortalList now respect
  the blocked scrolling areas, not just the mouse wheel / trackpad scroll.
* Forward the `set_scroll_pos()` through the widget derive traits so that
  we don't have to hook it up for each specific widget.
2026-06-11 22:12:09 +02:00
Kevin Boos
8b03b0b2ad
Audit and harden image decoding stuff against huge inputs (DoS) (#1110)
* Image support: add bmp/qoi,ico, webp, SVG in `Image` widget, 16-bit png

Generally, this commit makes improvements to image decoding and rendering.

Added a bunch of functions for image discovery / metadata gathering:
`decode_image_from_data()`, `image_size_by_data()`, `looks_like_svg()`

Added more `Image[Ref]` functions for other image formats:
`ImageRef::load_{bmp,qoi,ico,gif,webp,svg}_from_data()`, plus a nice
convenience fn for auto-detec+load: `load_image_from_data()`.

Added cheap, lazily-init'd support for SVGs within the `Image` widget.

Fixed some issues with aspect ratio being clobbered during image rotation.

* Audit and harden image decoding stuff against huge inputs (DoS)

Bound the size of the decoded image, pixel count, frame counts (for animated),
range of SVG sniffing, and encoded file size.
Only once we run those checks do we actually alloc a buffer for the decoded image. before allocating decode buffers. Validate

Add various other checks within the vendored image decoding libraries too.
2026-06-09 00:31:36 +02:00
Kevin Boos
850edc8ca6
Image support: add bmp/qoi,ico, webp, SVG in Image widget, 16-bit png (#1108)
Generally, this commit makes improvements to image decoding and rendering.

Added a bunch of functions for image discovery / metadata gathering:
`decode_image_from_data()`, `image_size_by_data()`, `looks_like_svg()`

Added more `Image[Ref]` functions for other image formats:
`ImageRef::load_{bmp,qoi,ico,gif,webp,svg}_from_data()`, plus a nice
convenience fn for auto-detec+load: `load_image_from_data()`.

Added cheap, lazily-init'd support for SVGs within the `Image` widget.

Fixed some issues with aspect ratio being clobbered during image rotation.
2026-06-09 00:09:29 +02:00
Kevin Boos
221cd7a1d5
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
alanpoon
ad73981737
Play and Pause fix in Video (#1096)
* video_debug

* Fix video pause being overridden by stall-recovery force-play on macOS

The native AVPlayer poll loop nudged a rate-0 player back into playing
whenever `autoplay` was true, intended as stall recovery but firing every
frame after a user-initiated pause. Once `begin_playback` latched
`autoplay = true` on first start, subsequent pauses were undone on the
next frame poll.

Split user playback intent into a `should_play` field that toggles on
play/pause/resume, and gate the force-play check on that instead of
`autoplay` (which is now a one-shot consumed in `check_prepared`).

Also restore the `Apply::Animate` early return in `Video::on_after_apply`
(needed so hover transitions don't re-decode the PNG/JPG thumbnail every
frame) and drop the redundant `Texture::new(cx)` allocation in
`apply_thumbnail_settings` that load_thumbnail_image immediately
overwrote anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 07:19:21 +02:00
Kevin Boos
7fff61c7a5
Add CropToFill image fit variant, improve ImageFit docs (#1102)
* 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.
2026-06-05 07:18:35 +02:00
Kevin Boos
f497a9fc14
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
a86f6e3bda isolates 2026-06-02 18:51:17 +02:00
Kevin Boos
eba743032d
Extend support for system bar appearance to iOS too (#1098) 2026-06-02 10:26:11 +02:00
admin
3d18a137ca splash md for calculator 2026-05-27 07:39:41 +02:00