* TextFlow: fix inline `<code>` spans sagging below the baseline
finish_row_center centered every walk by its own height, so a code run's
shorter walk got a larger downward shift than the surrounding prose under
`RowAlign.Center`. That undid TextFlow's baseline_shift: inline `<code>`
spans sat a few px below the line's baseline, and their descenders poked
out of the bottom of the code box.
* FinishedWalk now carries an optional `align_height` that text runs set
to their line style's height, so every text run on a row receives the
same centering shift and stays on the baseline. Also fixes sub- and
superscripts drifting under `RowAlign.Center`.
* The per-style metrics probe now caches descenders too, since we need
the full line height (ascender + descender) to compute `align_height`.
* Html/Markdown: make the fixed/code font size scale configurable
Replaces the hardcoded 0.85 `FIXED_FONT_SIZE_SCALE` consts with a
`fixed_font_size_scale` live property on TextFlow (default 0.85), so
apps can tune how much smaller `<code>` text renders than the prose.
* cargo_makepad: don't include `resources/android`/`ios` on every platform
Runtime asset bundling copied each crate's entire `resources/` tree into
every package, so `resources/android/` (manifest template, launcher icon
mipmaps) shipped as dead weight inside APK assets and Apple bundles, and
any `resources/ios/` content would ship on Android too. Those dirs are
platform-specific, so only their own platform should bundle them.
* Add `cp_all_skip_top()` to `makepad-shell`: like `cp_all()`, but skips
top-level entries by exact name.
* Android (APK and AAB staging): bundle `resources/android/` minus the
packaging inputs `AndroidManifest.xml.template` and `res/`, which
already reach the package via the generated manifest and the aapt
`res/` pipeline; skip `resources/ios/` entirely.
* Apple bundles: skip `resources/android/`, keep `resources/ios/`.
- bridge-dz baked for the entire Netherlands (17026 tiles, 29MB):
AHN-refined over the 8 Amsterdam sheet pairs, solver-only elsewhere.
Baked as 4 north-south strips with 2-tile overlap — the full-bbox
global solve peaked past 60GB RSS — merged with the new mbtiles-merge
subcommand (later input wins on overlaps, block-major write order).
Route app bridge_dz path ams -> nl.
- audio_unit: the new VoiceInput (VoiceProcessingIO) kind takes the input
setup/handler paths (set_input_handler panicked and aborted the app);
VPIO capture forced mono on every platform.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The junction-plaza dz field ingested road ways at the shared 6-unit
(~56 m) reach, and DzField holds full dz until radius-1.5 — so a 1 m
bridge hump raised half of Weesperplein and sheared the square over
its grounded surroundings (worst at high zoom where 1 m is ~43 px of
lift). DzField segments now carry per-source radii: plaza RING sources
keep the wide reach (quay slabs need it across their interior), while
road ways lift the plaza only across their own deck width. Diagnosed
via bake probes + an SVG dump of the paint buffers and a lift-zero
shader bisect; the dz archives themselves are clean and tapered (the
morning stairfix is not implicated).
Shadow geometry hardening from live review: facing gate widened to
0.25 (near-parallel edges swept hair-thin spikes), sliver filter
scales with the AA fringe, and deck shadows clamp their projected
height (solver outliers turned one segment into a canal-spanning
slab) and skip implausible dz outright. Probe tests document the
Weesperplein window and the dz A/B across archives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Steps shed height within the staircase (0.6 grade) instead of ramping
30m into the street grid. Surface ways under a deck clear from ground
level instead of reading back their own inherited ramp lift, which
pumped decks up every constraint round. Adds Duivendrecht probe tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the legacy flat-road fallback and A/B harness, keep patterned non-road strokes on their dedicated path, and make solid roads use the geometry/boolean mesh pipeline unconditionally. Reconcile bridge, link, and padded-tile elevation continuations generically in the tile baker and renderer.
The persistent artifacts were four distinct data bugs, found via the
dump_base_dz_at forensic test:
- Dual carriageways: two parallel ways whose ribbons merge in 2D but
solved to different heights -> a height step down the merged surface.
New solver pass: each way vertex adopts the max height of PARALLEL
ways within its own half-width (parallel_max sampler, own line
excluded); duals equalize, frontage streets are out of reach.
- Stacked grabs: a way split sitting under a parallel deck sampled the
deck overhead (no direction/distance gate can reject 2D-coincident
stacked ways). Isolated lifted runs under 25 m arc are zeroed —
measured in arc, not vertices, so short 2-vertex bridge ways survive
(zeroing those broke the Gooiseweg viaduct: fixed).
- The final coincident-vertex consensus TELEPORTED heights through
chance-coincident vertices of stacked ways; it now only reconciles
values already within 1 m (its actual job: unifying overlap copies).
- Post-consensus values had no ramps behind them (consensus ran after
blending): grade blend + hold re-runs after it, plus interior zero-run
interpolation (<120 m) for sampling holes; endpoint fallback keeps a
relaxed direction gate instead of none.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Junction consensus raised a merging way's endpoint to deck height but the
8%/m grade decay started immediately, dropping ~2 m across the visible
gore: every slip road attached below its deck with a ledge along the
merge. The grade blend now holds the junction height for the first 12 m
of the path before decaying, so merges are level through the gore and
descend after.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split ways duplicate a carriageway with an OFFSET centerline through
gores — the twin failed the direction/median gates and baked a lower
fallback height: two overlapping deck slabs at slightly different
heights, swapping mid-deck (the persistent 'road break'). Rejected
all-zero line paths now resample the field ungated with a tight cap
(2.5u, median <= 2u, 60% hit rate) — a gore twin sits within a lane of
the accepted profile and inherits it; frontage streets stay rejected.
Also: seam_probe forensic test (casing-buffer vertex dump + cross-tile
band compare) that located this; memory watchdog removed at user
request (runaway fixed and verified earlier).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Annotation now runs ONCE over every base tile in global coordinates —
junction consensus and a final exact consensus over coincident vertices
(largest |dz|) unify the overlap clip copies adjacent tiles both render.
DzField terminal cap extension skips endpoints on the tile clip bounds:
holding a cut height flat while the neighbor tile interpolates the ramp
mismatched the overlap band. Reduces (not yet eliminates) the doubled
slab at tile seams on ramping decks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-tile solves (even with 1-ring context) reached slightly different
heights for the same way on each side of a z14 seam; both tiles then
rendered their clipped copy of the deck in the overlap band at different
heights — visible steps and doubled slabs mid-deck. solve_tile is now
solve_bbox: one graph over every decoded tile (integer-grid node dedup
chains fragments across seams), one AHN pass, one constraint solve, one
global field pair; bridge_dz features bin per source tile and the
annotator samples the global field with per-tile offsets. Bonus: the
Amsterdam bake drops from ~2 min to 21 s (graph built once, not 193x).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- One continuous surface face per group ((surface − grounded cover) ∪
lifted): no more overlapping level twins micro-diverging at grazing
tilt (the lens endcaps). Tunnels stay a separate early-painted face.
- Tier-transition joints (bridge/approach style splits from the layer
rank bias) become FLUSH butt joints — but only at collinear
continuations; forks and T-junctions keep round caps. No cap discs, no
wall quads across a joint (suppressed within half_width of the joint).
- Walls/fascia unconditional again (~1.4 m band, clamped at ground): the
field-probe seam filters false-positived on every low deck through the
field's edge fade and stripped the thickness the whole look lives on.
- Baker: cross-tile boundary consensus on base_dz — every tile solves
with 1-ring context, so the same way baked slightly different heights
across a tile seam (visible mid-deck steps at z14 edges); boundary
vertices now unify to the largest-|dz| across tiles (153 paths).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Baker: tunnel sink solve (downward mirror of the lift solve): 5.5 m
clearance at every 2D crossing with a surface way, 30 m hold, grade
ramps, portals pinned to the surface at shared nodes. Tunnel ways get
their own SolvedField (never mixed with the surface field) and the
annotator runs a negative sampling pass for paths with no deck lift;
base_dz now carries signed dm values (195 tiles, +2 tunnel-only).
- Renderer: third level in the cascade — sunk parts with their own cover,
painting before ALL surface content; sunk faces displace down through
the existing signed-lift shader path. Tunnels with baked negative dz
join the union as solid sunk roads in 3D bakes (tunnel tag stripped for
styling); flat bakes keep carto dashes. Tunnel ways stay out of the
stroke/arrow corridors so surface streets above a tunnel line cannot
inherit the sink.
- Deck walls become fascia bands (~1.4 m below the deck edge, clamped at
ground): underpasses are OPEN — you can see through them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Two-cover cascade: grounded content subtracts grounded cover, lifted
subtracts lifted — a deck cuts its own casing (no more cap outlines
bleeding through on bridges) but never the road running underneath;
ramp feet still cut streets. Group parts dissolve to clean outlines
(simplify_shape) before any cross-group op.
- Depth ladder by slot (per face, per stroke rank) instead of per event:
coarser, safer separation between coplanar overlaps.
- DzField sampling gated by active-area bbox per face; corridor bbox
prefilter for interleaved strokes.
- Byte-budget tile cache eviction (1.2 GB) + pending-upload queue cap
(384 MB): 3D building bakes run 30-70 MB of fill buffer per tile and a
count-capped cache alone reached tens of GB.
- MP_TILE_PROFILE stage clock + headless union_perf_probe test with the
live theme mirrored (probe_compiled_theme): rz17 tile build 1.4s -> 0.9-1.0s.
- Revert baker lateral clearance: the constraint cascaded through solver
rounds and lifted the whole network; needs a bounded formulation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Union faces and legacy strokes merge into one rank-ordered paint sequence
(plazas, casings, centers) — cycle lanes and park paths draw above the
surfaces they ride, higher tiers still cover both; flat = buffer order,
tilt = same order via the param5 ladder.
- Joint coverage: bevel wedges at gentle bends, discs at corners/ends;
union ways get the same chaikin smoothing as legacy strokes (dz-aware).
- Per-tier DzField (nearest-way-wins, grounded ways at 0) + crack-free
midpoint face subdivision replace the narrow runtime corridors: decks
lift edge-to-edge, casings stay attached, no tents or shards.
- Lifted rings no longer subtract from lower groups: roads continue
underneath decks (paint order hides them flat, real depth when tilted).
- Lift-aware tilt depth: deck depth margin scales with lift so water and
ground at the display position can't depth-win over a bridge.
- Baker: tapered lateral clearance for elevated ways running beside
lower-layer roads (ribbon widths overlap without centerline crossings);
connected ways exempt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bridge elevation (bridge.md M1+M2): tools/map_tiles bridge-bake solves
per-vertex road/rail dz over the OSM graph (crossing clearance, grade
ramps, deck holds, junction consensus) with AHN DSM-DTM measured deck
profiles (BigTIFF reader in geodata, WGS84->RD), baked as bridge_dz +
per-base-tile base_dz (L/F/P join to exact renderer geometry). Renderer
joins dz through parse into TileWay.dz; strokes/arrows/fills lift off
their own profiles; tunnels never deck.
Road overlay unifier: painter's algorithm as geometry — per-way segment
rects + vertex discs, i_overlay top-down subtraction cascade into
DISJOINT faces (overlay_paint_groups), triangulated once; flat render is
pixel-equal to paint order (proven 0-diff on the abstract unit case) and
tilt cannot reorder it. Legacy strokes interleave by rank; plazas join
the cascade at true alpha. @roads 0/1 A/B toggle, @abtest headless
CPU-raster diff harness (1.50% vs 2D reference on the Raampoort tile),
@cam debug camera, bridge_eval.sh aerial-vs-render loop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- rain radar layer: pure-Rust KNMI HDF5 reader (superblock v0 walk,
single-chunk deflate datasets, byte-exact vs h5py), ellipsoidal polar
stereographic reprojection (20 m vs product corners), bilinear value
sampling -> smooth banded isolines, textured quad overlay through the
overlay camera, 25-frame nowcast animation; RadarSync polls at most
once per 4 min through a disk-persisted gate and caches frames on disk
- makepad-geodata + makepad-tesla crates join the workspace (overlay
builders, radar sync, NL open-data layers; transit routes now z7-14)
- Europe major-roads routing graph: nav-build --major-roads does a
ways-first scan (5.7M ways / 46M nodes / 194 s / 971 MB) and the app
falls back to it when a route leaves the regional graph — Amsterdam to
Paris routes offline (501.8 km)
- 3D flying markers: chargers/POIs/stops ride thin stalks with DYNAMIC
height (each pin clears its own building +8 m); labels, kW text,
brand and tap zones all consume the baked per-marker lift; stalks and
buildings grow together on the 2D->3D transition (per-tile flat->3D
fade heights, no replay on zoom regens)
- markers depth-honest (small bias, buildings occlude them); phong-lit
canopy/light spheres matching the buildings' NW sun; buildings tint by
BAG age in 3D; district area tints (rank 60, alpha .32); transit line
labels + stop names; follow-mode is an explicit attach/detach toggle;
rotation release schedules the label re-place (no stuck upside-down
labels after a fast spin)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Tesla-style droplet pins anchored at the tail tip (rotate around the
exact site point in tilted views); red exclusively Tesla, amber DC,
blue AC; Tesla pins show stall count, others peak kW
- in-pin text through the normal text renderer: billboard-anchored
glyphs (anchor scales with the map, glyph size constant), exempt from
label collision/repeat culling, no halo
- upright camera-delta labels: straightened labels (place names, POIs,
brands, pin text) translate with the rotation gesture but stay
horizontal — no more rotate-then-snap on regen
- per-icon zoom floors baked in vertex param4 + live icon_zoom uniform:
stale deeper-bucket tiles never flash markers on zoom-out (param4 is
lift-height only for non-icon shapes — icons stay on the ground)
- motorway exit labels (street_labels_points): carto-red name + ref
- 2D/3D mode: tilt gesture syncs app state (TiltChanged action), tilt
release near-flat settles to exact 0, mode flip re-bakes tiles
(extrusions appear/disappear without a zoom nudge)
- Simple 3D Buildings: building:part volumes with min_height bases;
outlines containing parts flatten to footprints; famous buildings
with tourism=attraction extrude instead of dying as attraction fills
- little 3D trees in tilt mode: crossed trunk quads + sphere-slice
ball canopy (architecture-model proportions)
- searchdb/mbtiles support work: reach-based distance ranking, direct
tile lookup + writer ordering
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New vision module: mmproj GGUF load (reuses the arch-agnostic loader),
exact-port preprocessing (calc_size_preserved_ratio, f64 bilinear resize to
match the reference binary's double promotion, block-major patch unfold),
and the 27-block ViT graph: patchify as two matmuls vs the flattened conv
weights, interpolated learned pos-embd (gpu bilinear+antialias, gathered to
block order), 2D vision rope, full bidirectional flash attention (f16 k/v,
f32 prec), layernorm composed as norm-mul-add, and the qwen3vl_merger
2-layer MLP into the LLM's 4096-dim space.
vlm-vision-probe validates against clip.cpp dumps: preproc bit-exact on
aligned images (1e-7), embeddings rms 3e-4..9e-4 / cosine 0.99999+ on all
three test images — inside the oracle's own flash-vs-composed spread
(rms 8.9e-4). 64-token encode 38ms, 192-token 103ms after graph compile.
Also fixes a stale DeltaNetRecurrentBlockSpec test initializer that broke
cargo test compilation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Relations reference ways randomly across the extract; the 128-group
WayStore LRU crawled Europe's pass 4 at ~260 relations/s (5+ hours).
Now: FlatWayStore decodes the whole relation-member way store into RAM
next to FlatNodeStore, assembler workers resolve and prepare features
(new prepare_point completes the set), a single writer owns the spool,
and the ordered consumer only parses members/tags. NH pass 4 3.9s ->
1.3s, per-layer feature counts identical.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Projected grid values are <= 2^26 at zoom 14, so i32 is exact; decode
hard-errors on out-of-range rather than ever truncating (no swimming
roads). NH output identical feature counts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Europe's ways arrive in creation order, i.e. spatially random: any node
cache that fits in a fraction of the store loses. The store is only
13.8GB compressed, so FlatNodeStore decodes ALL of it once (parallel,
~a minute for Europe) and resolver workers share it lock-free via Arc —
no cache, no eviction, no zlib on the hot path. NH pass 3: 5.6s -> 3.5s;
feature counts unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- NodeStore eviction was a min_by_key scan of the whole cache per miss;
with the Europe-sized cache that scan became the bottleneck (1.2k
ways/s). FIFO queue eviction is O(1) amortized
- way resolution now fans out over a resolver worker pool (each with
its own NodeStore handle and cache slice); geometry is localized on
the workers via prepare_lines/prepare_polygons and a single writer
thread owns the spool, so the on-disk format is untouched. The
id-ordered relation-way store stays on the ordered consumer thread
- Noord-Holland: pass 3 32.6s -> 5.6s, full conversion 25.7s; per-layer
feature counts identical (byte diff is record interleave order only)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two fixes to the detail converter that spent 10+ hours on Europe:
- visit_pbf: ordered parallel decode — blob reads stay serial, the
zlib+protobuf decode fans out over a worker pool, and the callback
runs in exact file order on the calling thread, so id-ordered store
builders need no changes
- NodeStore group cache: 256 groups (128MB) thrashed on Europe-scale
way resolution (~115us/way of cache-miss zlib re-decode, ~8.6k
ways/s); now MAKEPAD_NODE_CACHE_MIB (default 8GB), way resolution
~370k/s
Noord-Holland: 61s end-to-end, output byte-identical to the slow
converter (7547 tiles, same bytes).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Hella Haasseplein root cause: pedestrian squares in osm_lines arrive
as LineStrings, so `closed` was never set and the area admission
skipped them — detect implicit closure (first==last) and mark the
ring closed for the fill pass
- icon collision: doors and generic dots now yield to real symbols
(the recycling icon was losing to the building entrance beside it);
entrances gate at z18 like carto
- tools: tagprobe <pbf> <name> — dump every OSM element matching a
name, for answering "how is this actually tagged" without overpass
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
score_search_hit: settlements are near-immune to distance ("brussels"
from Amsterdam means Bruxelles, not the closest Brusselsestraat),
POIs/streets keep strong local bias, and a number token signals
address intent. nav-build --places-only scans a pbf for settlement
nodes into a compact index (Europe: 1.31M places, 67MB, 60s); the app
merges it with the regional full index, deduping same-name near hits.
Route overlay decimation now measures against the last drawn point,
bounding the error at ~1.5px — pairwise skipping compounded and
visibly reshaped the route when zoomed out.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conversion tooling (tools/map_tiles): curated Shortbread base pyramid
from a VersaTiles planet archive (bbox extract, brotli->gzip transcode
parallelized per 256x256 block), all-tag native OSM pbf detail
converter, pbf audit, and nav-build/nav-probe producing the routing
graph + search index artifacts. download_map.sh orchestrates pinned
downloads and conversions. mbtile_reader writer now skips SQLite's
lock-byte page at byte offset 1 GiB — allocating through it corrupted
every database over 1 GiB ("2nd reference to page 16385"); the 31 GB
Europe conversion passes integrity checks.
Navigation (libs/map_nav, new): region.search place/POI/street/address
index (prefix autocomplete, NL/EN category synonyms, proximity
ranking) and region.graph routing graph (CSR directed edges,
car/bike/foot speeds, oneway, turn restrictions, snap grid, A*),
maneuver generation and the NavSession map-matching state machine;
26 unit tests.
MapView interaction layer: MapViewAction, camera API + animated
fly_to, overlay.rs (route polyline with traveled dimming, markers,
position puck), per-widget mbtiles_path override, archive
minzoom/maxzoom honored for tile requests, zoom-level cross-fade over
the previous level's imagery, floating panels win hit-testing.
examples/map is the navigator app: worker-thread search, Drive/Bike/
Walk routing, simulated turn-by-turn with banner, follow camera.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
libs/tts was never tracked despite being a build dependency of the gamemaker
example. tools/download_tts.sh fetches the public upstream weights (HuggingFace
Kokoro-82M + whisper.cpp) and converts them locally with the in-repo stdlib-only
converter; model artifacts are gitignored.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* 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
* Extend support for system bar appearance to iOS too
* cargo_makepad: fix default icon behavior for iOS
Icons need to not be modified by cargo_makepad if they're already
in the proper iOS-expected format, otherwise they'll end up with
some kind of extra black border around the icon, which looks bad.
* Dock: avoid ID collisions in drag/drop; never delete dock root in unsplit_tabs
* Clean up and further harden dock logic around splitting/dragging
* cargo_makepad: Android App Bundle builds, API 26 support, stable toolchain
Overhaul the Android build pipeline. Three related build-tooling
changes that share compile.rs/sdk.rs and so are committed together.
Android App Bundle (.aab) support — required for Google Play uploads:
- New `build-aab` command: compile resources with aapt2, link a
proto-format APK, assemble the base module, run bundletool, and sign
with jarsigner.
- New `keystore-create` command wrapping keytool, with a reusable
keystore sidecar file; new `--keystore*`, `--no-sign`,
`--version-code`, `--version-name` flags.
- Version codes may be explicit or auto-generated as a monotonic
YYYYMMDDHH UTC integer.
- Read app id, version, and signing metadata from
`[package.metadata.packager]` / `[package.metadata.makepad.android]`
in Cargo.toml; support a custom AndroidManifest.xml template.
- Upgrade the bundled TOML parser for the dotted keys, inline tables,
and multi-line strings those metadata sections use.
- Download bundletool and copy jarsigner/keytool/aapt2 into the SDK.
minSdkVersion 26:
- Lower the default Android minimum SDK from 33 to 26 and track the
target SDK (35) separately, emitting minSdkVersion and
targetSdkVersion independently in the generated manifest; add a
`--min-sdk-version` override.
Stable Rust toolchain:
- Build Android and iOS on stable instead of nightly. tvOS still needs
nightly for `-Z build-std`, so the channel is resolved per target.
- Add `ensure_rust_toolchain_installed` (install only when missing).
* Android: load newer NDK symbols at runtime to support API 26
With the minimum SDK lowered to 26, NDK entry points that only exist
on newer API levels can no longer be declared with `extern "C"` —
doing so breaks `dlopen`/startup on API 26-28. Resolve them at
runtime instead:
- amidi_sys: lazily `dlopen` libamidi.so (API 29+) into a cached
vtable; the wrappers degrade to error/zero returns when the library
is absent on older devices.
- android_jni: `dlsym` the AChoreographer vsync callbacks, gated on
the running API level.
- ndk_sys: drop the `extern "C"` declarations for
`ANativeWindow_setFrameRate` and the Choreographer callbacks;
android.rs drops the now-unused frame-rate call.
- MakepadActivity: guard `setInitialSurroundingSubText` (API 30+) and
`layoutInDisplayCutoutMode` (API 28+) behind version checks.
- android_jni: the fallback render-loop thread now exits cleanly when
the app is torn down.
* Android: automatic and app-controlled system bar appearance
Add a way to control the tint of the status and navigation bar icons,
fixing white-on-white (invisible) icons when an app draws a light
background under a system dark-mode theme.
- New `Cx::set_system_bar_appearance(SystemBarAppearance)`. The default
`Auto` mode picks dark or light icons from the window background
luminance; `DarkIcons`/`LightIcons` force the choice.
- The `Window` widget resolves the setting each event cycle — for
`Auto`, the Rec.709 luma of `pass.clear_color` — and emits
`CxOsOp::SetSystemBarDarkIcons` only when the resolved value changes.
- On Android this drives `WindowInsetsController.setSystemBarsAppearance`
(API 30+) or the `SYSTEM_UI_FLAG_LIGHT_*` flags (API 26-29). The tint
is re-asserted after fullscreen toggles, since the legacy path
rewrites the whole `systemUiVisibility` bitmask.
* Android: fix soft-keyboard handling and edge-to-edge insets
Several related window-inset and IME fixes, mostly affecting devices
that are not edge-to-edge (Android versions before 15).
- Report safe-area and IME insets as the overlap with the render
surface, not the raw window-edge insets. On a non-edge-to-edge
window the surface already sits inside the system bars, so the raw
insets double-counted — leaving oversized gaps around content and
above the keyboard.
- Also drive safe-area insets from `onGlobalLayout`, so the app is
inset correctly from launch instead of drawing under the status bar
until the first keyboard show or rotation.
- While the keyboard animates, treat the `WindowInsetsAnimation`
callback as the authoritative per-frame inset source and have the
layout-driven callbacks defer to it. Read target IME visibility from
`getRootWindowInsets()` so a show animation is not misread as an
instant dismissal.
- Only reconfigure the Java IME when the `TextInputConfig` actually
changes, instead of on every show.
- `KeyboardView`: compute and apply the content shift at keyboard-show
event time, removing a one-frame lag and a tail-end jump; only
reconcile post-draw when the focused field actually redrew.
- `Modal::close()`: skip the focus revert when the modal is already
closed — it was stealing focus from a just-tapped text input and
causing a first-tap keyboard flicker.
- Hide the keyboard via `WindowInsetsController.hide(ime())` on API 30+.
* platform: don't panic posting actions during shutdown
post_action no longer unwraps the global action sender. It now
silently drops the action if the sender mutex is poisoned, no Cx
sender is installed, or the receiver has been dropped during app
teardown, and only raises the UI signal when the send succeeds.
(Also shortens an over-long field doc comment in cx.rs; no behavior
change.)
* cargo-makepad: link std statically in AAB builds (16 KB page-size fix)
`-C prefer-dynamic` ships std as a separate, 4 KB-aligned libstd.so that
fails Play's 16 KB page-size rule. AAB builds now link std statically;
APK/dev builds keep prefer-dynamic. Also documents {min_sdk_version} in help.
* 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>
* 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`.
* Fix pre-existing iOS and Android build breaks
iOS (platform/src/os/apple/ios/ios.rs): five `CxOsOp` arms had edits
that landed one match-arm late, so each block referenced bindings only
in scope on the preceding arm. Re-home them:
- `WindowGeomChange` now applies `native_window_geom_to_layout` (the
two stray lines previously sat inside the `Paint`/`prepared` arm).
- `ShowTextIME` now converts `pos` via `layout_vec2d_to_native_points`
(previously lodged inside the `SyncImeState` destructure pattern).
- `ShowClipboardActions` now converts `rect` / `keyboard_shift` to
native points (previously appended to `ShowSelectionHandles`).
- `ShowSelectionHandles` / `UpdateSelectionHandles` now convert `start`
and `end` (the `Update` arm had no conversion, and the `Show` arm's
conversion was actually the clipboard one).
- `FullscreenWindow` / `NormalizeWindow` drop the bogus `start` / `end`
conversions that didn't belong there.
Android (platform/src/ime.rs): `android_jni::to_java_configure_keyboard`
matches on `InputMode::None` and `ReturnKeyType::{Next, None, Previous,
Google, Yahoo, Join, Route, Continue, EmergencyCall}` — variants that
exist on the `ime_improvements` branch (commit 3dc039f0a) but weren't
pulled into this branch. Add them to the enum definitions so the
android target compiles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This normalizes the IME geometry calcs across iOS and Android.
The main difference is to make KeyboardView shift the content based on
the focused TExtInput instance instead of trying to shrink the viewport.
Also make sure that StackNavigation widget properly handles the
keyboard shift, even when it is drawing in full-screen mode.
* Fix portallist alignment handling so centering actually works
Now, alignment on PortalLists now only applies to the "cross-axis"
of each item, not the main axis.
So when you center a portallist itself, it won't add weird space
on the leading side of the list
* Fix text not drawing on top of a background, e.g., `<code>` tags
This worked in *most* but not all cases, e.g., if you had a ton of
inline code tags, some of them would rarely but deterministically
not show the actual text glyphs, but just an empty background.
* Avoid large margin on the left of `<code>` if it's on a new line
* Add a separate "touch" margin; use it on dock splitter and tab close
Without this, those dock UI elements are nearly impossible to grab
and press on a real touch screen device, even on my iPad.
Also, tweak cargo-makepad iOS and Android builds to use a polished
display name for the app (uppercase first character) by default.
* Don't duplicate fonts in Android/iOS app bundles
* Fix portallist alignment handling so centering actually works
Now, alignment on PortalLists now only applies to the "cross-axis"
of each item, not the main axis.
So when you center a portallist itself, it won't add weird space
on the leading side of the list
* Fix text not drawing on top of a background, e.g., `<code>` tags
This worked in *most* but not all cases, e.g., if you had a ton of
inline code tags, some of them would rarely but deterministically
not show the actual text glyphs, but just an empty background.
* Avoid large margin on the left of `<code>` if it's on a new line
* Add a separate "touch" margin; use it on dock splitter and tab close
Without this, those dock UI elements are nearly impossible to grab
and press on a real touch screen device, even on my iPad.
Also, tweak cargo-makepad iOS and Android builds to use a polished
display name for the app (uppercase first character) by default.
* Another proper fix for black screen on Android start/resume
* Fix all Android surface artifacts on pause, resume, and cold start
* cleanup: remove java-level logging in MakepadActivity
* additional cleanup/improvements for android lifecycle stuff