mirror of
https://github.com/bitsycore/compose-desktop-native.git
synced 2026-10-05 10:47:26 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9527ee8c2 | ||
|
|
6040816cf7 | ||
|
|
6f3bc915b2 | ||
|
|
1ba84a3a2c | ||
|
|
e807ecf973 | ||
|
|
dc35f5bd37 | ||
|
|
4888fdcda0 | ||
|
|
85e0179590 |
@@ -31,9 +31,13 @@ jobs:
|
||||
host: macos
|
||||
target: MacosArm64
|
||||
exe_ext: kexe
|
||||
# jvm publication: only :material-symbols declares a jvm() target
|
||||
# (its common API renders via upstream Compose on JVM) — publish
|
||||
# its host-independent jar from the same host as the metadata.
|
||||
tasks: >-
|
||||
publishKotlinMultiplatformPublicationToGitHubPackagesRepository
|
||||
publishMacosArm64PublicationToGitHubPackagesRepository
|
||||
publishJvmPublicationToGitHubPackagesRepository
|
||||
- runner: ubuntu-22.04
|
||||
host: linux
|
||||
target: LinuxX64
|
||||
@@ -95,23 +99,33 @@ jobs:
|
||||
# intrinsic K/N's LLD can't resolve is aliased to msvcrt's _setjmpex at
|
||||
# link time via --defsym in sdl3.def.
|
||||
|
||||
# Build static SDL3 / SDL3_ttf / SDL3_image / FreeType from
|
||||
# scripts/build-sdl/build-sdl.properties. Cached against the manifest +
|
||||
# scripts so version bumps invalidate cleanly.
|
||||
# `cache_version` is a manual bump for when the toolchain (runner OS,
|
||||
# compiler flavour, K/N sysroot expectations) changes without any
|
||||
# scripts/build-sdl/ file changing. Increment to force a rebuild.
|
||||
# Build the static native deps from scripts/build-sdl/build-sdl.properties.
|
||||
# Only Windows ships the SDL3 renderer (no Skiko on mingw), so only it needs
|
||||
# SDL3_ttf / SDL3_image / FreeType (SDL3_ttf text, SDL3_image decode, FreeType
|
||||
# icon-axis rasterisation). macOS / Linux publish the Skia renderer — Skiko
|
||||
# handles text / images / icons — so they only need base SDL3 for the main
|
||||
# loop (windowing / input / audio / filesystem). Matches the cinterop guard
|
||||
# in compose/ui/ui/build.gradle.kts, which skips those three cinterops on the
|
||||
# Skia targets. Cached against the manifest + scripts so version bumps
|
||||
# invalidate cleanly; bump the `v3` key when the toolchain (runner OS,
|
||||
# compiler flavour, K/N sysroot) changes without a scripts/build-sdl/ edit.
|
||||
- name: Cache libs/
|
||||
id: cache-libs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: libs
|
||||
key: sdl-libs-v2-${{ matrix.host }}-${{ hashFiles('scripts/build-sdl/**') }}
|
||||
key: sdl-libs-v3-${{ matrix.host }}-${{ hashFiles('scripts/build-sdl/**') }}
|
||||
|
||||
- name: Build static SDL / TTF / image / FreeType
|
||||
# Windows: full SDL3 renderer stack. macOS / Linux (Skia): base SDL3 only.
|
||||
- name: Build static native deps
|
||||
if: steps.cache-libs.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: bash scripts/build-sdl/build-all.sh
|
||||
run: |
|
||||
if [ "${{ matrix.host }}" = "windows" ]; then
|
||||
python3 scripts/build-sdl/build-all.py
|
||||
else
|
||||
python3 scripts/build-sdl/build-all.py sdl3
|
||||
fi
|
||||
|
||||
# src/vendor/ trees are gitignored — a fresh checkout has zero vendored
|
||||
# androidx.compose.* files. Sync copies them in from the upstream refs
|
||||
@@ -167,15 +181,11 @@ jobs:
|
||||
target_dir=$(echo "${{ matrix.target }}" | awk '{print tolower(substr($0,1,1)) substr($0,2)}')
|
||||
version="${GITHUB_REF_NAME#v}"
|
||||
mkdir -p dist
|
||||
# Windows Git Bash has no `zip`; every runner has JDK 21 → use `jar cf`
|
||||
# which writes a valid ZIP file. `-C dir file` = enter dir then add
|
||||
# `file` at the archive root, so the archive stays flat like `zip -j`.
|
||||
for app in demo apidemo; do
|
||||
src="$app/build/bin/$target_dir/releaseExecutable"
|
||||
zip_path="$(pwd)/dist/$app-$version-$target_dir.zip"
|
||||
jar --create --no-manifest --file "$zip_path" \
|
||||
-C "$src" "$app.${{ matrix.exe_ext }}" \
|
||||
-C "$src" "data.kres"
|
||||
python3 -c 'import sys,os,zipfile; z=zipfile.ZipFile(sys.argv[1],"w",zipfile.ZIP_DEFLATED,compresslevel=9); [z.write(f,os.path.basename(f)) for f in sys.argv[2:]]; z.close()' \
|
||||
"$zip_path" "$src/$app.${{ matrix.exe_ext }}" "$src/data.kres"
|
||||
done
|
||||
ls -la dist/
|
||||
|
||||
|
||||
@@ -60,8 +60,18 @@ compose/
|
||||
|
||||
utils/
|
||||
└── material-symbols/ → :material-symbols — codepoints + all three style objects
|
||||
(Outlined / Rounded / Sharp). Apps get one dep;
|
||||
the consumer Zip task bundles only the fonts used.
|
||||
(Outlined / Rounded / Sharp). COMMON API (usable from
|
||||
shared app code) + per-stack actuals: native renders
|
||||
via :foundation IconFontIcon (IconFont handles the
|
||||
SDL3/Skia split), jvm() via Skiko directly
|
||||
(Typeface.makeClone per axes — upstream's FontCache
|
||||
drops variationSettings from its key). Its commonMain
|
||||
declares official Maven compose coords — the root
|
||||
build's FULL-COMMONIZATION BRIDGE substitutes ui /
|
||||
foundation / material3 to project modules on native
|
||||
configs. Apps get one dep; the consumer Zip task
|
||||
bundles only the fonts used (native) and
|
||||
jvmProcessResources stages the same fonts (jvm).
|
||||
|
||||
components/
|
||||
└── resources/library/ → :components-resources — the OFFICIAL Compose resources
|
||||
@@ -94,11 +104,12 @@ demo/ → :demo — flagship showcase app (30+ screens) + th
|
||||
screens on stock JVM Compose Desktop (`./gradlew :demo:run`,
|
||||
MainJvmKt) — the parity reference; differences vs native = port bugs
|
||||
apidemo/ → :apidemo — Postman-style REST API manager
|
||||
scripts/ → vendor-sync + python helper scripts (compose-fidelity/coverage,
|
||||
material-symbols generate/subset) + compose-fork/;
|
||||
scripts/build-sdl/ = Windows static-lib build scripts (bash)
|
||||
scripts/ → vendor-sync + python helper scripts (compose-coverage = API
|
||||
coverage/fidelity vs upstream, material-symbols generate/subset)
|
||||
+ compose-fork/;
|
||||
scripts/build-sdl/ = static-lib build script (python)
|
||||
libs/ → gitignored per-host static SDL3 / SDL3_ttf / SDL3_image / FreeType
|
||||
output of scripts/build-sdl/build-*.sh on Windows
|
||||
output of scripts/build-sdl/build-all.py on Windows
|
||||
```
|
||||
|
||||
Module PATHS stay short (`:ui`, `:foundation`, `:window`, …) —
|
||||
@@ -313,20 +324,21 @@ gradlew.bat :apidemo:runDebugExecutableMingwX64
|
||||
|
||||
### System dependencies
|
||||
|
||||
**macOS (default Skia build):** `brew install sdl3`. Only need `sdl3_ttf`
|
||||
if you set `-Prenderer=sdl3`. Skiko klibs come from Maven.
|
||||
SDL3 + SDL3_ttf + SDL3_image + FreeType (+ image codecs) are **built from
|
||||
source as static libraries on every OS** and linked straight into the
|
||||
executable — no brew/apt SDL packages, no runtime .dll/.so/.dylib;
|
||||
a distributable is `<app>` + `data.kres`. One script does it all:
|
||||
`python scripts/build-sdl/build-all.py` (plain Python 3, no Git Bash needed)
|
||||
builds into the gitignored, in-repo `libs/` folder. Versions/URLs pinned in
|
||||
`scripts/build-sdl/build-sdl.properties`. Steps run in order freetype → sdl3
|
||||
→ sdl3-image → sdl3-ttf; pass step names to rebuild a subset
|
||||
(`python scripts/build-sdl/build-all.py sdl3-ttf`).
|
||||
|
||||
**Linux (default Skia build):** `sudo apt install libsdl3-dev`. Same caveat
|
||||
for SDL3_ttf.
|
||||
|
||||
**Windows (mingwX64 — always uses SDL3 + SDL3_ttf + SDL3_image + FreeType):**
|
||||
these four libraries + image codecs are **linked statically into the
|
||||
executable** — no runtime DLLs, distributable is just `<app>.exe` +
|
||||
`data.kres`. They're not downloaded — `scripts/build-sdl/build-all.sh` (from Git
|
||||
Bash) builds them from source as static libs into a gitignored, in-repo `libs/`
|
||||
folder. Needs: git, cmake, mingw-w64 gcc/g++ on PATH, plus curl + python for
|
||||
ninja fetch. `scripts/build-sdl/build-all.sh` = `build-freetype.sh` → `build-sdl3.sh` →
|
||||
`build-sdl3-image.sh` → `build-sdl3-ttf.sh`.
|
||||
Needs everywhere: git, cmake, python 3 (ninja fetched automatically). Per
|
||||
host: macOS = Xcode CLT (Skia default; Skiko klibs from Maven); Linux =
|
||||
gcc/g++ + the X11/Wayland/audio dev headers SDL3's configure detects (apt
|
||||
list in .github/workflows/publish.yml); Windows = mingw-w64 g++ on PATH
|
||||
(C compiles with K/N's bundled mingw).
|
||||
|
||||
## Runtime bundling — data.kres
|
||||
|
||||
|
||||
@@ -47,7 +47,11 @@ compose/
|
||||
per-window Lifecycle/ViewModelStore/SavedState owners)
|
||||
|
||||
utils/
|
||||
└── material-symbols/ → :material-symbols (codepoints + Outlined/Rounded/Sharp icon fonts)
|
||||
└── material-symbols/ → :material-symbols (Material Symbols: 4200+ codepoints + Outlined/Rounded/
|
||||
Sharp composables with the variable-font axes as
|
||||
parameters (FILL/wght/GRAD/opsz). Common API — native
|
||||
draws via the port's icon-font engine, the jvm target
|
||||
via Skiko, so shared app code uses it on both stacks)
|
||||
|
||||
components/
|
||||
└── resources/library/ → :components-resources (vendored official compose resources runtime —
|
||||
@@ -133,13 +137,31 @@ implementation(project(":material-symbols")) // icon-font composables (optional
|
||||
|
||||
## Building
|
||||
|
||||
- **macOS:** `brew install sdl3` (Skia is the default; Skiko klibs come from
|
||||
Maven).
|
||||
- **Linux:** `sudo apt install libsdl3-dev`.
|
||||
- **Windows:** SDL3, SDL3_ttf, SDL3_image and FreeType are built from source
|
||||
as **static** libraries by `scripts/build-sdl/build-all.sh` into the gitignored
|
||||
in-repo `libs/`, then linked into the executable — the Windows
|
||||
distributable is just `<app>.exe` + `data.kres`, no runtime DLLs.
|
||||
All four native dependencies — **SDL3**, **SDL3_ttf** (the in-house
|
||||
variable-font-axes fork), **SDL3_image** (+ vendored PNG/WEBP codecs) and
|
||||
**FreeType** — are built from source as **static** libraries by one script,
|
||||
on every OS, and linked straight into the executable. No `brew install`, no
|
||||
`apt install libsdl3-dev`, no runtime `.dll` / `.so` / `.dylib` next to the
|
||||
binary — a distributable is just `<app>` + `data.kres`.
|
||||
|
||||
```bash
|
||||
python3 scripts/build-sdl/build-all.py # freetype → sdl3 → sdl3-image → sdl3-ttf
|
||||
python3 scripts/build-sdl/build-all.py sdl3-ttf # rebuild a subset
|
||||
```
|
||||
|
||||
Library versions / URLs are pinned in `scripts/build-sdl/build-sdl.properties`;
|
||||
output lands in the gitignored in-repo `libs/`. Required on every host: `git`,
|
||||
`cmake`, Python 3 (`ninja` is fetched automatically when absent). Per host:
|
||||
|
||||
- **macOS** — Xcode command line tools. Skia is the default renderer; Skiko
|
||||
klibs come from Maven.
|
||||
- **Linux** — gcc/g++ plus the X11 / Wayland / audio dev headers SDL3's
|
||||
configure detects (the exact apt list is in
|
||||
`.github/workflows/publish.yml`).
|
||||
- **Windows** — a mingw-w64 g++ on PATH (the C side compiles with
|
||||
Kotlin/Native's bundled mingw).
|
||||
|
||||
Then build any app target — see the demo / apidemo commands above.
|
||||
|
||||
## Vendoring
|
||||
|
||||
@@ -158,6 +180,15 @@ Upstream ref pinned in `scripts/compose-fork/compose.properties`; manifests can
|
||||
pin additional upstream repos inline (`SET_REPO=<url>@<ref>` — the resources
|
||||
runtime vendors from the compose-multiplatform umbrella repo this way).
|
||||
|
||||
How much of upstream's public API the port actually covers is measured, not
|
||||
guessed — `scripts/compose-coverage.py` diffs this repo's klib ABI dumps
|
||||
against upstream's, per vendored module:
|
||||
|
||||
```bash
|
||||
./gradlew apiDump && python3 scripts/compose-coverage.py # per-module coverage tables
|
||||
python3 scripts/compose-coverage.py --missing ui-text # list the exact uncovered decls
|
||||
```
|
||||
|
||||
See [CLAUDE.md](CLAUDE.md) for the full architecture, source-set hierarchy,
|
||||
vendoring rules, density flow (physical-pixel Option B), and per-area file
|
||||
map.
|
||||
|
||||
+23
-3
@@ -8,8 +8,8 @@ plugins {
|
||||
alias(libs.plugins.kotlin.plugin.compose) apply false
|
||||
alias(libs.plugins.kotlin.plugin.serialization) apply false
|
||||
alias(libs.plugins.compose.multiplatform) apply false
|
||||
// Public-ABI dumps (api/<module>.klib.api). Used by scripts/compose-fidelity-check.py
|
||||
// to diff our androidx.compose.* surface against the official Compose klib ABI.
|
||||
// Public-ABI dumps (api/<module>.klib.api). Used by scripts/compose-coverage.py
|
||||
// to diff our mirrored API surface against the official upstream klib ABI dumps.
|
||||
alias(libs.plugins.binary.compatibility.validator)
|
||||
}
|
||||
|
||||
@@ -108,10 +108,30 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
// FULL-COMMONIZATION BRIDGE (repo-wide): a module may declare the OFFICIAL
|
||||
// Maven Compose artifacts in its commonMain so metadata + jvm resolve them
|
||||
// (e.g. :material-symbols' common API); every NATIVE target configuration
|
||||
// swaps those modules for the port's project equivalents — the Maven
|
||||
// artifacts ship no mingwX64/linux klibs. org.jetbrains.compose.runtime is
|
||||
// deliberately NOT here: the port uses the official runtime klibs everywhere.
|
||||
// (:demo carries the same pattern locally for components-resources.)
|
||||
val vNativeTargetTokens = listOf("mingwX64", "linuxX64", "linuxArm64", "macosArm64")
|
||||
allprojects {
|
||||
configurations.configureEach {
|
||||
if (vNativeTargetTokens.any { name.contains(it, ignoreCase = true) }) {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
substitute(module("org.jetbrains.compose.ui:ui")).using(project(":ui"))
|
||||
substitute(module("org.jetbrains.compose.foundation:foundation")).using(project(":foundation"))
|
||||
substitute(module("org.jetbrains.compose.material3:material3")).using(project(":material3"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the current host can build the mingwX64 target. Kotlin/Native can
|
||||
// only cross-compile mingwX64 cinterops from a Windows host — the sdl3_ttf /
|
||||
// sdl3_image cinterops need Windows SDL3 headers under libs/ (produced by
|
||||
// scripts/build-sdl/build-*.sh, which only runs on Windows). Declaring `mingwX64()` on
|
||||
// scripts/build-sdl/build-all.py run on a Windows host). Declaring `mingwX64()` on
|
||||
// a non-Windows host is safe for pure-Kotlin modules but blows up the moment
|
||||
// a `depends = sdl3` cinterop tries to include SDL3_ttf/SDL_ttf.h.
|
||||
// Override with `-PforceMingw=true` if you actually have the headers wired.
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// Klib ABI Dump
|
||||
// Targets: [linuxArm64, linuxX64, macosArm64, mingwX64]
|
||||
// Rendering settings:
|
||||
// - Signature version: 2
|
||||
// - Show manifest properties: true
|
||||
// - Show declarations: true
|
||||
|
||||
// Library unique name: <com.bitsycore.compose.sdl:components-resources>
|
||||
open annotation class org.jetbrains.compose.resources/ExperimentalResourceApi : kotlin/Annotation { // org.jetbrains.compose.resources/ExperimentalResourceApi|null[0]
|
||||
constructor <init>() // org.jetbrains.compose.resources/ExperimentalResourceApi.<init>|<init>(){}[0]
|
||||
}
|
||||
|
||||
open annotation class org.jetbrains.compose.resources/InternalResourceApi : kotlin/Annotation { // org.jetbrains.compose.resources/InternalResourceApi|null[0]
|
||||
constructor <init>() // org.jetbrains.compose.resources/InternalResourceApi.<init>|<init>(){}[0]
|
||||
}
|
||||
|
||||
open annotation class org.jetbrains.compose.resources/ResourceContentHash : kotlin/Annotation { // org.jetbrains.compose.resources/ResourceContentHash|null[0]
|
||||
constructor <init>(kotlin/Int) // org.jetbrains.compose.resources/ResourceContentHash.<init>|<init>(kotlin.Int){}[0]
|
||||
|
||||
final val hash // org.jetbrains.compose.resources/ResourceContentHash.hash|{}hash[0]
|
||||
final fun <get-hash>(): kotlin/Int // org.jetbrains.compose.resources/ResourceContentHash.hash.<get-hash>|<get-hash>(){}[0]
|
||||
}
|
||||
|
||||
final enum class org.jetbrains.compose.resources/DensityQualifier : kotlin/Enum<org.jetbrains.compose.resources/DensityQualifier>, org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/DensityQualifier|null[0]
|
||||
enum entry HDPI // org.jetbrains.compose.resources/DensityQualifier.HDPI|null[0]
|
||||
enum entry LDPI // org.jetbrains.compose.resources/DensityQualifier.LDPI|null[0]
|
||||
enum entry MDPI // org.jetbrains.compose.resources/DensityQualifier.MDPI|null[0]
|
||||
enum entry XHDPI // org.jetbrains.compose.resources/DensityQualifier.XHDPI|null[0]
|
||||
enum entry XXHDPI // org.jetbrains.compose.resources/DensityQualifier.XXHDPI|null[0]
|
||||
enum entry XXXHDPI // org.jetbrains.compose.resources/DensityQualifier.XXXHDPI|null[0]
|
||||
|
||||
final val dpi // org.jetbrains.compose.resources/DensityQualifier.dpi|{}dpi[0]
|
||||
final fun <get-dpi>(): kotlin/Int // org.jetbrains.compose.resources/DensityQualifier.dpi.<get-dpi>|<get-dpi>(){}[0]
|
||||
final val entries // org.jetbrains.compose.resources/DensityQualifier.entries|#static{}entries[0]
|
||||
final fun <get-entries>(): kotlin.enums/EnumEntries<org.jetbrains.compose.resources/DensityQualifier> // org.jetbrains.compose.resources/DensityQualifier.entries.<get-entries>|<get-entries>#static(){}[0]
|
||||
|
||||
final fun valueOf(kotlin/String): org.jetbrains.compose.resources/DensityQualifier // org.jetbrains.compose.resources/DensityQualifier.valueOf|valueOf#static(kotlin.String){}[0]
|
||||
final fun values(): kotlin/Array<org.jetbrains.compose.resources/DensityQualifier> // org.jetbrains.compose.resources/DensityQualifier.values|values#static(){}[0]
|
||||
|
||||
final object Companion { // org.jetbrains.compose.resources/DensityQualifier.Companion|null[0]
|
||||
final fun selectByDensity(kotlin/Float): org.jetbrains.compose.resources/DensityQualifier // org.jetbrains.compose.resources/DensityQualifier.Companion.selectByDensity|selectByDensity(kotlin.Float){}[0]
|
||||
final fun selectByValue(kotlin/Int): org.jetbrains.compose.resources/DensityQualifier // org.jetbrains.compose.resources/DensityQualifier.Companion.selectByValue|selectByValue(kotlin.Int){}[0]
|
||||
}
|
||||
}
|
||||
|
||||
final enum class org.jetbrains.compose.resources/ThemeQualifier : kotlin/Enum<org.jetbrains.compose.resources/ThemeQualifier>, org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/ThemeQualifier|null[0]
|
||||
enum entry DARK // org.jetbrains.compose.resources/ThemeQualifier.DARK|null[0]
|
||||
enum entry LIGHT // org.jetbrains.compose.resources/ThemeQualifier.LIGHT|null[0]
|
||||
|
||||
final val entries // org.jetbrains.compose.resources/ThemeQualifier.entries|#static{}entries[0]
|
||||
final fun <get-entries>(): kotlin.enums/EnumEntries<org.jetbrains.compose.resources/ThemeQualifier> // org.jetbrains.compose.resources/ThemeQualifier.entries.<get-entries>|<get-entries>#static(){}[0]
|
||||
|
||||
final fun valueOf(kotlin/String): org.jetbrains.compose.resources/ThemeQualifier // org.jetbrains.compose.resources/ThemeQualifier.valueOf|valueOf#static(kotlin.String){}[0]
|
||||
final fun values(): kotlin/Array<org.jetbrains.compose.resources/ThemeQualifier> // org.jetbrains.compose.resources/ThemeQualifier.values|values#static(){}[0]
|
||||
|
||||
final object Companion { // org.jetbrains.compose.resources/ThemeQualifier.Companion|null[0]
|
||||
final fun selectByValue(kotlin/Boolean): org.jetbrains.compose.resources/ThemeQualifier // org.jetbrains.compose.resources/ThemeQualifier.Companion.selectByValue|selectByValue(kotlin.Boolean){}[0]
|
||||
}
|
||||
}
|
||||
|
||||
abstract interface org.jetbrains.compose.resources/Qualifier // org.jetbrains.compose.resources/Qualifier|null[0]
|
||||
|
||||
abstract interface org.jetbrains.compose.resources/ResourceReader { // org.jetbrains.compose.resources/ResourceReader|null[0]
|
||||
abstract fun getUri(kotlin/String): kotlin/String // org.jetbrains.compose.resources/ResourceReader.getUri|getUri(kotlin.String){}[0]
|
||||
abstract suspend fun read(kotlin/String): kotlin/ByteArray // org.jetbrains.compose.resources/ResourceReader.read|read(kotlin.String){}[0]
|
||||
abstract suspend fun readPart(kotlin/String, kotlin/Long, kotlin/Long): kotlin/ByteArray // org.jetbrains.compose.resources/ResourceReader.readPart|readPart(kotlin.String;kotlin.Long;kotlin.Long){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources.vector.xmldom/MalformedXMLException : kotlin/Exception { // org.jetbrains.compose.resources.vector.xmldom/MalformedXMLException|null[0]
|
||||
constructor <init>(kotlin/String?) // org.jetbrains.compose.resources.vector.xmldom/MalformedXMLException.<init>|<init>(kotlin.String?){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/DrawableResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/DrawableResource|null[0]
|
||||
constructor <init>(kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/DrawableResource.<init>|<init>(kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/FontResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/FontResource|null[0]
|
||||
constructor <init>(kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/FontResource.<init>|<init>(kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/LanguageQualifier : org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/LanguageQualifier|null[0]
|
||||
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/LanguageQualifier.<init>|<init>(kotlin.String){}[0]
|
||||
|
||||
final val language // org.jetbrains.compose.resources/LanguageQualifier.language|{}language[0]
|
||||
final fun <get-language>(): kotlin/String // org.jetbrains.compose.resources/LanguageQualifier.language.<get-language>|<get-language>(){}[0]
|
||||
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/LanguageQualifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/LanguageQualifier.hashCode|hashCode(){}[0]
|
||||
final fun toString(): kotlin/String // org.jetbrains.compose.resources/LanguageQualifier.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/MissingResourceException : kotlin/Exception { // org.jetbrains.compose.resources/MissingResourceException|null[0]
|
||||
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/MissingResourceException.<init>|<init>(kotlin.String){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/PluralStringResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/PluralStringResource|null[0]
|
||||
constructor <init>(kotlin/String, kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/PluralStringResource.<init>|<init>(kotlin.String;kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
|
||||
|
||||
final val key // org.jetbrains.compose.resources/PluralStringResource.key|{}key[0]
|
||||
final fun <get-key>(): kotlin/String // org.jetbrains.compose.resources/PluralStringResource.key.<get-key>|<get-key>(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/RegionQualifier : org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/RegionQualifier|null[0]
|
||||
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/RegionQualifier.<init>|<init>(kotlin.String){}[0]
|
||||
|
||||
final val region // org.jetbrains.compose.resources/RegionQualifier.region|{}region[0]
|
||||
final fun <get-region>(): kotlin/String // org.jetbrains.compose.resources/RegionQualifier.region.<get-region>|<get-region>(){}[0]
|
||||
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/RegionQualifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/RegionQualifier.hashCode|hashCode(){}[0]
|
||||
final fun toString(): kotlin/String // org.jetbrains.compose.resources/RegionQualifier.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/ResourceEnvironment { // org.jetbrains.compose.resources/ResourceEnvironment|null[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/ResourceEnvironment.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/ResourceEnvironment.hashCode|hashCode(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/ResourceItem { // org.jetbrains.compose.resources/ResourceItem|null[0]
|
||||
constructor <init>(kotlin.collections/Set<org.jetbrains.compose.resources/Qualifier>, kotlin/String, kotlin/Long, kotlin/Long) // org.jetbrains.compose.resources/ResourceItem.<init>|<init>(kotlin.collections.Set<org.jetbrains.compose.resources.Qualifier>;kotlin.String;kotlin.Long;kotlin.Long){}[0]
|
||||
|
||||
final fun copy(kotlin.collections/Set<org.jetbrains.compose.resources/Qualifier> = ..., kotlin/String = ..., kotlin/Long = ..., kotlin/Long = ...): org.jetbrains.compose.resources/ResourceItem // org.jetbrains.compose.resources/ResourceItem.copy|copy(kotlin.collections.Set<org.jetbrains.compose.resources.Qualifier>;kotlin.String;kotlin.Long;kotlin.Long){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/ResourceItem.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/ResourceItem.hashCode|hashCode(){}[0]
|
||||
final fun toString(): kotlin/String // org.jetbrains.compose.resources/ResourceItem.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/ScriptQualifier : org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/ScriptQualifier|null[0]
|
||||
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/ScriptQualifier.<init>|<init>(kotlin.String){}[0]
|
||||
|
||||
final val script // org.jetbrains.compose.resources/ScriptQualifier.script|{}script[0]
|
||||
final fun <get-script>(): kotlin/String // org.jetbrains.compose.resources/ScriptQualifier.script.<get-script>|<get-script>(){}[0]
|
||||
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/ScriptQualifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/ScriptQualifier.hashCode|hashCode(){}[0]
|
||||
final fun isEmpty(): kotlin/Boolean // org.jetbrains.compose.resources/ScriptQualifier.isEmpty|isEmpty(){}[0]
|
||||
final fun toString(): kotlin/String // org.jetbrains.compose.resources/ScriptQualifier.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/StringArrayResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/StringArrayResource|null[0]
|
||||
constructor <init>(kotlin/String, kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/StringArrayResource.<init>|<init>(kotlin.String;kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
|
||||
|
||||
final val key // org.jetbrains.compose.resources/StringArrayResource.key|{}key[0]
|
||||
final fun <get-key>(): kotlin/String // org.jetbrains.compose.resources/StringArrayResource.key.<get-key>|<get-key>(){}[0]
|
||||
}
|
||||
|
||||
final class org.jetbrains.compose.resources/StringResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/StringResource|null[0]
|
||||
constructor <init>(kotlin/String, kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/StringResource.<init>|<init>(kotlin.String;kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
|
||||
|
||||
final val key // org.jetbrains.compose.resources/StringResource.key|{}key[0]
|
||||
final fun <get-key>(): kotlin/String // org.jetbrains.compose.resources/StringResource.key.<get-key>|<get-key>(){}[0]
|
||||
}
|
||||
|
||||
sealed class org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/Resource|null[0]
|
||||
open fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/Resource.equals|equals(kotlin.Any?){}[0]
|
||||
open fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/Resource.hashCode|hashCode(){}[0]
|
||||
}
|
||||
|
||||
final object org.jetbrains.compose.resources/ResourceCaches // org.jetbrains.compose.resources/ResourceCaches|null[0]
|
||||
|
||||
final val org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop|#static{}org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop[0]
|
||||
final val org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop|#static{}org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop[0]
|
||||
final val org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop|#static{}org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop[0]
|
||||
final val org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop // org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop|#static{}org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/LocalResourceReader // org.jetbrains.compose.resources/LocalResourceReader|{}LocalResourceReader[0]
|
||||
final fun <get-LocalResourceReader>(): androidx.compose.runtime/ProvidableCompositionLocal<org.jetbrains.compose.resources/ResourceReader> // org.jetbrains.compose.resources/LocalResourceReader.<get-LocalResourceReader>|<get-LocalResourceReader>(){}[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop|#static{}org_jetbrains_compose_resources_DrawableResource$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop|#static{}org_jetbrains_compose_resources_FontResource$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop|#static{}org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop|#static{}org_jetbrains_compose_resources_ImageCache_Svg$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop|#static{}org_jetbrains_compose_resources_ImageCache_Vector$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop|#static{}org_jetbrains_compose_resources_LanguageQualifier$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop|#static{}org_jetbrains_compose_resources_MissingResourceException$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop|#static{}org_jetbrains_compose_resources_PluralStringResource$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop|#static{}org_jetbrains_compose_resources_RegionQualifier$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop|#static{}org_jetbrains_compose_resources_Resource$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop|#static{}org_jetbrains_compose_resources_ResourceCaches$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop|#static{}org_jetbrains_compose_resources_ResourceEnvironment$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop|#static{}org_jetbrains_compose_resources_ResourceItem$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop|#static{}org_jetbrains_compose_resources_ScriptQualifier$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop|#static{}org_jetbrains_compose_resources_StringArrayResource$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop|#static{}org_jetbrains_compose_resources_StringItem_Array$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop|#static{}org_jetbrains_compose_resources_StringItem_Plurals$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop|#static{}org_jetbrains_compose_resources_StringItem_Value$stableprop[0]
|
||||
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop|#static{}org_jetbrains_compose_resources_StringResource$stableprop[0]
|
||||
|
||||
final fun (kotlin/ByteArray).org.jetbrains.compose.resources/decodeToImageBitmap(): androidx.compose.ui.graphics/ImageBitmap // org.jetbrains.compose.resources/decodeToImageBitmap|decodeToImageBitmap@kotlin.ByteArray(){}[0]
|
||||
final fun (kotlin/ByteArray).org.jetbrains.compose.resources/decodeToImageVector(androidx.compose.ui.unit/Density): androidx.compose.ui.graphics.vector/ImageVector // org.jetbrains.compose.resources/decodeToImageVector|decodeToImageVector@kotlin.ByteArray(androidx.compose.ui.unit.Density){}[0]
|
||||
final fun (kotlin/ByteArray).org.jetbrains.compose.resources/decodeToSvgPainter(androidx.compose.ui.unit/Density): androidx.compose.ui.graphics.painter/Painter // org.jetbrains.compose.resources/decodeToSvgPainter|decodeToSvgPainter@kotlin.ByteArray(androidx.compose.ui.unit.Density){}[0]
|
||||
final fun org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop_getter|org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop_getter|org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop_getter|org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop_getter|org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/Font(org.jetbrains.compose.resources/FontResource, androidx.compose.ui.text.font/FontWeight?, androidx.compose.ui.text.font/FontStyle, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.ui.text.font/Font // org.jetbrains.compose.resources/Font|Font(org.jetbrains.compose.resources.FontResource;androidx.compose.ui.text.font.FontWeight?;androidx.compose.ui.text.font.FontStyle;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/Font(org.jetbrains.compose.resources/FontResource, androidx.compose.ui.text.font/FontWeight?, androidx.compose.ui.text.font/FontStyle, androidx.compose.ui.text.font/FontVariation.Settings?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.ui.text.font/Font // org.jetbrains.compose.resources/Font|Font(org.jetbrains.compose.resources.FontResource;androidx.compose.ui.text.font.FontWeight?;androidx.compose.ui.text.font.FontStyle;androidx.compose.ui.text.font.FontVariation.Settings?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/getResourceUri(kotlin/String): kotlin/String // org.jetbrains.compose.resources/getResourceUri|getResourceUri(kotlin.String){}[0]
|
||||
final fun org.jetbrains.compose.resources/getSystemResourceEnvironment(): org.jetbrains.compose.resources/ResourceEnvironment // org.jetbrains.compose.resources/getSystemResourceEnvironment|getSystemResourceEnvironment(){}[0]
|
||||
final fun org.jetbrains.compose.resources/imageResource(org.jetbrains.compose.resources/DrawableResource, androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics/ImageBitmap // org.jetbrains.compose.resources/imageResource|imageResource(org.jetbrains.compose.resources.DrawableResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop_getter|org_jetbrains_compose_resources_DrawableResource$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop_getter|org_jetbrains_compose_resources_FontResource$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop_getter|org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop_getter|org_jetbrains_compose_resources_ImageCache_Svg$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop_getter|org_jetbrains_compose_resources_ImageCache_Vector$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop_getter|org_jetbrains_compose_resources_LanguageQualifier$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop_getter|org_jetbrains_compose_resources_MissingResourceException$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop_getter|org_jetbrains_compose_resources_PluralStringResource$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop_getter|org_jetbrains_compose_resources_RegionQualifier$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop_getter|org_jetbrains_compose_resources_Resource$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop_getter|org_jetbrains_compose_resources_ResourceCaches$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop_getter|org_jetbrains_compose_resources_ResourceEnvironment$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop_getter|org_jetbrains_compose_resources_ResourceItem$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop_getter|org_jetbrains_compose_resources_ScriptQualifier$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop_getter|org_jetbrains_compose_resources_StringArrayResource$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop_getter|org_jetbrains_compose_resources_StringItem_Array$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop_getter|org_jetbrains_compose_resources_StringItem_Plurals$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop_getter|org_jetbrains_compose_resources_StringItem_Value$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop_getter|org_jetbrains_compose_resources_StringResource$stableprop_getter(){}[0]
|
||||
final fun org.jetbrains.compose.resources/painterResource(org.jetbrains.compose.resources/DrawableResource, androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics.painter/Painter // org.jetbrains.compose.resources/painterResource|painterResource(org.jetbrains.compose.resources.DrawableResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/pluralStringResource(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/pluralStringResource|pluralStringResource(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/pluralStringResource(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, kotlin/Array<out kotlin/Any>..., androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/pluralStringResource|pluralStringResource(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;kotlin.Array<out|kotlin.Any>...;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/rememberResourceEnvironment(androidx.compose.runtime/Composer?, kotlin/Int): org.jetbrains.compose.resources/ResourceEnvironment // org.jetbrains.compose.resources/rememberResourceEnvironment|rememberResourceEnvironment(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/stringArrayResource(org.jetbrains.compose.resources/StringArrayResource, androidx.compose.runtime/Composer?, kotlin/Int): kotlin.collections/List<kotlin/String> // org.jetbrains.compose.resources/stringArrayResource|stringArrayResource(org.jetbrains.compose.resources.StringArrayResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/stringResource(org.jetbrains.compose.resources/StringResource, androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/stringResource|stringResource(org.jetbrains.compose.resources.StringResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/stringResource(org.jetbrains.compose.resources/StringResource, kotlin/Array<out kotlin/Any>..., androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/stringResource|stringResource(org.jetbrains.compose.resources.StringResource;kotlin.Array<out|kotlin.Any>...;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun org.jetbrains.compose.resources/vectorResource(org.jetbrains.compose.resources/DrawableResource, androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics.vector/ImageVector // org.jetbrains.compose.resources/vectorResource|vectorResource(org.jetbrains.compose.resources.DrawableResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getDrawableResourceBytes(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/DrawableResource): kotlin/ByteArray // org.jetbrains.compose.resources/getDrawableResourceBytes|getDrawableResourceBytes(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.DrawableResource){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getFontResourceBytes(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/FontResource): kotlin/ByteArray // org.jetbrains.compose.resources/getFontResourceBytes|getFontResourceBytes(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.FontResource){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;kotlin.Array<out|kotlin.Any>...){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/PluralStringResource, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.PluralStringResource;kotlin.Int){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;kotlin.Array<out|kotlin.Any>...){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/StringResource): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.StringResource){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/StringResource, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.StringResource;kotlin.Array<out|kotlin.Any>...){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/StringResource): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.StringResource){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/StringResource, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.StringResource;kotlin.Array<out|kotlin.Any>...){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getStringArray(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/StringArrayResource): kotlin.collections/List<kotlin/String> // org.jetbrains.compose.resources/getStringArray|getStringArray(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.StringArrayResource){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/getStringArray(org.jetbrains.compose.resources/StringArrayResource): kotlin.collections/List<kotlin/String> // org.jetbrains.compose.resources/getStringArray|getStringArray(org.jetbrains.compose.resources.StringArrayResource){}[0]
|
||||
final suspend fun org.jetbrains.compose.resources/readResourceBytes(kotlin/String): kotlin/ByteArray // org.jetbrains.compose.resources/readResourceBytes|readResourceBytes(kotlin.String){}[0]
|
||||
@@ -2078,17 +2078,6 @@ final object com.compose.sdl.icons/IconDefaults { // com.compose.sdl.icons/IconD
|
||||
final fun <get-LocalContentColor>(): androidx.compose.ui.graphics/Color // com.compose.sdl.icons/IconDefaults.LocalContentColor.<get-LocalContentColor>|<get-LocalContentColor>(){}[0]
|
||||
}
|
||||
|
||||
final object com.compose.sdl.icons/MaterialIconAxisDefaults { // com.compose.sdl.icons/MaterialIconAxisDefaults|null[0]
|
||||
final const val Fill // com.compose.sdl.icons/MaterialIconAxisDefaults.Fill|{}Fill[0]
|
||||
final fun <get-Fill>(): kotlin/Float // com.compose.sdl.icons/MaterialIconAxisDefaults.Fill.<get-Fill>|<get-Fill>(){}[0]
|
||||
final const val Grade // com.compose.sdl.icons/MaterialIconAxisDefaults.Grade|{}Grade[0]
|
||||
final fun <get-Grade>(): kotlin/Int // com.compose.sdl.icons/MaterialIconAxisDefaults.Grade.<get-Grade>|<get-Grade>(){}[0]
|
||||
final const val OpticalSize // com.compose.sdl.icons/MaterialIconAxisDefaults.OpticalSize|{}OpticalSize[0]
|
||||
final fun <get-OpticalSize>(): kotlin/Int // com.compose.sdl.icons/MaterialIconAxisDefaults.OpticalSize.<get-OpticalSize>|<get-OpticalSize>(){}[0]
|
||||
final const val Weight // com.compose.sdl.icons/MaterialIconAxisDefaults.Weight|{}Weight[0]
|
||||
final fun <get-Weight>(): kotlin/Int // com.compose.sdl.icons/MaterialIconAxisDefaults.Weight.<get-Weight>|<get-Weight>(){}[0]
|
||||
}
|
||||
|
||||
final object com.compose.sdl.widgets/SplitPaneDefaults { // com.compose.sdl.widgets/SplitPaneDefaults|null[0]
|
||||
final val DividerThickness // com.compose.sdl.widgets/SplitPaneDefaults.DividerThickness|{}DividerThickness[0]
|
||||
final fun <get-DividerThickness>(): androidx.compose.ui.unit/Dp // com.compose.sdl.widgets/SplitPaneDefaults.DividerThickness.<get-DividerThickness>|<get-DividerThickness>(){}[0]
|
||||
@@ -2220,7 +2209,6 @@ final val androidx.compose.foundation/androidx_compose_foundation_MarqueeDefault
|
||||
final val androidx.compose.foundation/androidx_compose_foundation_MutatorMutex$stableprop // androidx.compose.foundation/androidx_compose_foundation_MutatorMutex$stableprop|#static{}androidx_compose_foundation_MutatorMutex$stableprop[0]
|
||||
final val androidx.compose.foundation/androidx_compose_foundation_ScrollState$stableprop // androidx.compose.foundation/androidx_compose_foundation_ScrollState$stableprop|#static{}androidx_compose_foundation_ScrollState$stableprop[0]
|
||||
final val com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop // com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop|#static{}com_compose_sdl_icons_IconDefaults$stableprop[0]
|
||||
final val com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop // com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop|#static{}com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop[0]
|
||||
final val com.compose.sdl.scrollbar/LocalScrollbarStyle // com.compose.sdl.scrollbar/LocalScrollbarStyle|{}LocalScrollbarStyle[0]
|
||||
final fun <get-LocalScrollbarStyle>(): androidx.compose.runtime/ProvidableCompositionLocal<com.compose.sdl.scrollbar/ScrollbarStyle> // com.compose.sdl.scrollbar/LocalScrollbarStyle.<get-LocalScrollbarStyle>|<get-LocalScrollbarStyle>(){}[0]
|
||||
final val com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop // com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop|#static{}com_compose_sdl_scrollbar_ScrollbarStyle$stableprop[0]
|
||||
@@ -2294,6 +2282,8 @@ final fun (androidx.compose.ui.input.pointer/PointerEvent).androidx.compose.foun
|
||||
final fun (androidx.compose.ui.input.pointer/PointerEvent).androidx.compose.foundation.gestures/calculateZoom(): kotlin/Float // androidx.compose.foundation.gestures/calculateZoom|calculateZoom@androidx.compose.ui.input.pointer.PointerEvent(){}[0]
|
||||
final fun (androidx.compose.ui.text/AnnotatedString.Builder).androidx.compose.foundation.text/appendInlineContent(kotlin/String, kotlin/String = ...) // androidx.compose.foundation.text/appendInlineContent|appendInlineContent@androidx.compose.ui.text.AnnotatedString.Builder(kotlin.String;kotlin.String){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.content/contentReceiver(androidx.compose.foundation.content/ReceiveContentListener): androidx.compose.ui/Modifier // androidx.compose.foundation.content/contentReceiver|contentReceiver@androidx.compose.ui.Modifier(androidx.compose.foundation.content.ReceiveContentListener){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.draganddrop/dragAndDropSource(kotlin/Function1<androidx.compose.ui.geometry/Offset, androidx.compose.ui.draganddrop/DragAndDropTransferData?>): androidx.compose.ui/Modifier // androidx.compose.foundation.draganddrop/dragAndDropSource|dragAndDropSource@androidx.compose.ui.Modifier(kotlin.Function1<androidx.compose.ui.geometry.Offset,androidx.compose.ui.draganddrop.DragAndDropTransferData?>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.draganddrop/dragAndDropSource(kotlin/Function1<androidx.compose.ui.graphics.drawscope/DrawScope, kotlin/Unit>, kotlin/Function1<androidx.compose.ui.geometry/Offset, androidx.compose.ui.draganddrop/DragAndDropTransferData?>): androidx.compose.ui/Modifier // androidx.compose.foundation.draganddrop/dragAndDropSource|dragAndDropSource@androidx.compose.ui.Modifier(kotlin.Function1<androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit>;kotlin.Function1<androidx.compose.ui.geometry.Offset,androidx.compose.ui.draganddrop.DragAndDropTransferData?>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.draganddrop/dragAndDropTarget(kotlin/Function1<androidx.compose.ui.draganddrop/DragAndDropEvent, kotlin/Boolean>, androidx.compose.ui.draganddrop/DragAndDropTarget): androidx.compose.ui/Modifier // androidx.compose.foundation.draganddrop/dragAndDropTarget|dragAndDropTarget@androidx.compose.ui.Modifier(kotlin.Function1<androidx.compose.ui.draganddrop.DragAndDropEvent,kotlin.Boolean>;androidx.compose.ui.draganddrop.DragAndDropTarget){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.gestures/draggable(androidx.compose.foundation.gestures/DraggableState, androidx.compose.foundation.gestures/Orientation, kotlin/Boolean = ..., androidx.compose.foundation.interaction/MutableInteractionSource? = ..., kotlin/Boolean = ..., kotlin.coroutines/SuspendFunction2<kotlinx.coroutines/CoroutineScope, androidx.compose.ui.geometry/Offset, kotlin/Unit> = ..., kotlin.coroutines/SuspendFunction2<kotlinx.coroutines/CoroutineScope, kotlin/Float, kotlin/Unit> = ..., kotlin/Boolean = ...): androidx.compose.ui/Modifier // androidx.compose.foundation.gestures/draggable|draggable@androidx.compose.ui.Modifier(androidx.compose.foundation.gestures.DraggableState;androidx.compose.foundation.gestures.Orientation;kotlin.Boolean;androidx.compose.foundation.interaction.MutableInteractionSource?;kotlin.Boolean;kotlin.coroutines.SuspendFunction2<kotlinx.coroutines.CoroutineScope,androidx.compose.ui.geometry.Offset,kotlin.Unit>;kotlin.coroutines.SuspendFunction2<kotlinx.coroutines.CoroutineScope,kotlin.Float,kotlin.Unit>;kotlin.Boolean){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.gestures/draggable2D(androidx.compose.foundation.gestures/Draggable2DState, kotlin/Boolean = ..., androidx.compose.foundation.interaction/MutableInteractionSource? = ..., kotlin/Boolean = ..., kotlin/Function1<androidx.compose.ui.geometry/Offset, kotlin/Unit> = ..., kotlin/Function1<androidx.compose.ui.unit/Velocity, kotlin/Unit> = ..., kotlin/Boolean = ...): androidx.compose.ui/Modifier // androidx.compose.foundation.gestures/draggable2D|draggable2D@androidx.compose.ui.Modifier(androidx.compose.foundation.gestures.Draggable2DState;kotlin.Boolean;androidx.compose.foundation.interaction.MutableInteractionSource?;kotlin.Boolean;kotlin.Function1<androidx.compose.ui.geometry.Offset,kotlin.Unit>;kotlin.Function1<androidx.compose.ui.unit.Velocity,kotlin.Unit>;kotlin.Boolean){}[0]
|
||||
@@ -2620,14 +2610,13 @@ final fun androidx.compose.foundation/rememberBasicTooltipState(kotlin/Boolean,
|
||||
final fun androidx.compose.foundation/rememberOverscrollEffect(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.foundation/OverscrollEffect? // androidx.compose.foundation/rememberOverscrollEffect|rememberOverscrollEffect(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun androidx.compose.foundation/rememberScrollState(kotlin/Int, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.foundation/ScrollState // androidx.compose.foundation/rememberScrollState|rememberScrollState(kotlin.Int;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.icons/IconFontIcon(kotlin/Int, kotlin/String, kotlin/String?, androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Color, androidx.compose.ui.unit/Dp, kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.icons/IconFontIcon|IconFontIcon(kotlin.Int;kotlin.String;kotlin.String?;androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Color;androidx.compose.ui.unit.Dp;kotlin.collections.List<androidx.compose.ui.text.font.FontVariation.Setting>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.icons/MaterialIconAxes(kotlin/Float = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ...): kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting> // com.compose.sdl.icons/MaterialIconAxes|MaterialIconAxes(kotlin.Float;kotlin.Int;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop_getter(): kotlin/Int // com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop_getter|com_compose_sdl_icons_IconDefaults$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop_getter(): kotlin/Int // com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop_getter|com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.modifier/rememberMutableInteractionSource(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.foundation.interaction/MutableInteractionSource // com.compose.sdl.modifier/rememberMutableInteractionSource|rememberMutableInteractionSource(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.scrollbar/HorizontalScrollbar(com.compose.sdl.scrollbar/ScrollbarAdapter, androidx.compose.ui/Modifier?, kotlin/Boolean, com.compose.sdl.scrollbar/ScrollbarStyle?, androidx.compose.foundation.interaction/MutableInteractionSource?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.scrollbar/HorizontalScrollbar|HorizontalScrollbar(com.compose.sdl.scrollbar.ScrollbarAdapter;androidx.compose.ui.Modifier?;kotlin.Boolean;com.compose.sdl.scrollbar.ScrollbarStyle?;androidx.compose.foundation.interaction.MutableInteractionSource?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.scrollbar/VerticalScrollbar(com.compose.sdl.scrollbar/ScrollbarAdapter, androidx.compose.ui/Modifier?, kotlin/Boolean, com.compose.sdl.scrollbar/ScrollbarStyle?, androidx.compose.foundation.interaction/MutableInteractionSource?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.scrollbar/VerticalScrollbar|VerticalScrollbar(com.compose.sdl.scrollbar.ScrollbarAdapter;androidx.compose.ui.Modifier?;kotlin.Boolean;com.compose.sdl.scrollbar.ScrollbarStyle?;androidx.compose.foundation.interaction.MutableInteractionSource?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop_getter(): kotlin/Int // com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop_getter|com_compose_sdl_scrollbar_ScrollbarStyle$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.scrollbar/defaultScrollbarStyle(): com.compose.sdl.scrollbar/ScrollbarStyle // com.compose.sdl.scrollbar/defaultScrollbarStyle|defaultScrollbarStyle(){}[0]
|
||||
final fun com.compose.sdl.scrollbar/rememberScrollbarAdapter(androidx.compose.foundation.lazy/LazyListState, androidx.compose.runtime/Composer?, kotlin/Int): com.compose.sdl.scrollbar/ScrollbarAdapter // com.compose.sdl.scrollbar/rememberScrollbarAdapter|rememberScrollbarAdapter(androidx.compose.foundation.lazy.LazyListState;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.scrollbar/rememberScrollbarAdapter(androidx.compose.foundation/ScrollState, androidx.compose.runtime/Composer?, kotlin/Int): com.compose.sdl.scrollbar/ScrollbarAdapter // com.compose.sdl.scrollbar/rememberScrollbarAdapter|rememberScrollbarAdapter(androidx.compose.foundation.ScrollState;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.text/IconText(kotlin/String, kotlin/String, androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Color, androidx.compose.ui.unit/TextUnit, androidx.compose.ui.text.style/TextAlign, kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.text/IconText|IconText(kotlin.String;kotlin.String;androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Color;androidx.compose.ui.unit.TextUnit;androidx.compose.ui.text.style.TextAlign;kotlin.collections.List<androidx.compose.ui.text.font.FontVariation.Setting>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun com.compose.sdl.text/IconText(kotlin/String, kotlin/String, androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Color, androidx.compose.ui.unit/TextUnit, androidx.compose.ui.text.style/TextAlign?, kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.text/IconText|IconText(kotlin.String;kotlin.String;androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Color;androidx.compose.ui.unit.TextUnit;androidx.compose.ui.text.style.TextAlign?;kotlin.collections.List<androidx.compose.ui.text.font.FontVariation.Setting>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
|
||||
+83
-32
@@ -30,9 +30,12 @@ import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.scrollBy
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
// ==================
|
||||
@@ -141,6 +144,19 @@ private class LazyListScrollbarAdapter(private val state: LazyListState) : Scrol
|
||||
get() = (state.layoutInfo.viewportEndOffset - state.layoutInfo.viewportStartOffset).toDouble()
|
||||
|
||||
override suspend fun scrollTo(scrollOffset: Double) {
|
||||
val vDistance = scrollOffset - this.scrollOffset
|
||||
// Within a viewport, scroll by EXACT pixels so a drag stays smooth. A lazy
|
||||
// list's pixel geometry is only ESTIMATED (average visible item size), and
|
||||
// that estimate drifts as differently-sized items scroll through the
|
||||
// viewport — so index-snapping every frame makes the thumb jump. scrollBy
|
||||
// sidesteps the estimate entirely. This is what Compose Desktop's own
|
||||
// LazyListScrollbarAdapter does, and for the same reason.
|
||||
if (abs(vDistance) <= viewportSize) {
|
||||
state.scrollBy(vDistance.toFloat())
|
||||
return
|
||||
}
|
||||
// Far jump (track-click paging past a viewport): no exact geometry to lean
|
||||
// on, so estimate an index/offset from the average and snap to it.
|
||||
val vAvg = averageItemSize()
|
||||
if (vAvg <= 0.0) return
|
||||
val vTarget = scrollOffset.coerceAtLeast(0.0)
|
||||
@@ -193,7 +209,6 @@ private fun Scrollbar(
|
||||
val vHoverSource = remember { MutableInteractionSource() }
|
||||
val vHovered by vHoverSource.collectIsHoveredAsState()
|
||||
var vDraggingThumb by remember { mutableStateOf(false) }
|
||||
var vGrab by remember { mutableStateOf(0) }
|
||||
// onSizeChanged reports PHYSICAL pixels (Option-B density flow), so every
|
||||
// int/px carried through here — vTrackPx, vThumbLen, vThumbPos — is in
|
||||
// physical pixels. Passing them into `.dp` doubles again through
|
||||
@@ -230,15 +245,6 @@ private fun Scrollbar(
|
||||
val vRawPos = if (vTravel <= 0) 0 else (vTravel * (vOffset / vMaxScroll)).roundToInt()
|
||||
val vThumbPos = (if (reverseLayout) vTravel - vRawPos else vRawPos).coerceIn(0, vTravel)
|
||||
|
||||
// ============
|
||||
// Map a track-relative position to a scroll offset and apply it.
|
||||
fun scrollToTrackPos(inThumbTop: Int) {
|
||||
if (vTravel <= 0) return
|
||||
val vPos = inThumbTop.coerceIn(0, vTravel)
|
||||
val vFrac = (if (reverseLayout) vTravel - vPos else vPos).toDouble() / vTravel
|
||||
vScope.launch { adapter.scrollTo(vFrac * vMaxScroll) }
|
||||
}
|
||||
|
||||
val vThumbLenDp = with(vDensity) { vThumbLen.toDp() }
|
||||
val vThumbMod = (
|
||||
if (isVertical) Modifier.offset { IntOffset(0, vThumbPos) }.width(style.thickness).height(vThumbLenDp)
|
||||
@@ -251,33 +257,78 @@ private fun Scrollbar(
|
||||
|
||||
// ============
|
||||
// Drag the thumb / page on track click — handled on the track so the
|
||||
// coordinates have a stable (non-moving) origin.
|
||||
// coordinates have a stable (non-moving) origin. The press is CONSUMED:
|
||||
// a scrollbar owns the pointer input it handles, so content sharing this
|
||||
// region (the scrollable beneath, or a parent that also reads pointer
|
||||
// input) never reacts to the same press. Geometry is read LIVE from the
|
||||
// adapter at press time — not from the captured render metrics above,
|
||||
// which go stale between pointerInput relaunches — so a grab after a
|
||||
// wheel-scroll still hit-tests against the thumb's current position.
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchTrackSize(isVertical, with(vDensity) { vTrackPx.toDp() }, style.thickness)
|
||||
.pointerInput(isVertical, adapter, vTrackPx) {
|
||||
detectDragGestures(
|
||||
onDragStart = { offset ->
|
||||
val vPress = (if (isVertical) offset.y else offset.x).toInt()
|
||||
if (vPress in vThumbPos..(vThumbPos + vThumbLen)) {
|
||||
vDraggingThumb = true
|
||||
vGrab = vPress - vThumbPos
|
||||
} else {
|
||||
// Page toward the click by one viewport.
|
||||
vDraggingThumb = false
|
||||
val vDir = if (vPress < vThumbPos) -1.0 else 1.0
|
||||
vScope.launch { adapter.scrollTo(vOffset + vDir * vViewport) }
|
||||
}
|
||||
},
|
||||
onDrag = { change, _ ->
|
||||
.pointerInput(isVertical, adapter, vTrackPx, reverseLayout) {
|
||||
awaitEachGesture {
|
||||
val vDown = awaitFirstDown(requireUnconsumed = false)
|
||||
vDown.consume()
|
||||
|
||||
// Live geometry — stable for the drag's duration (content /
|
||||
// viewport / track sizes don't change mid-drag).
|
||||
val vContentPx = adapter.contentSize
|
||||
val vViewportPx = adapter.viewportSize
|
||||
val vMaxScrollPx = vContentPx - vViewportPx
|
||||
if (vMaxScrollPx <= 0.0 || vTrackPx <= 0) return@awaitEachGesture
|
||||
val vMinLen = style.minimalHeight.value.toInt()
|
||||
val vLen = (vTrackPx * (vViewportPx / vContentPx)).roundToInt()
|
||||
.coerceIn(vMinLen.coerceAtMost(vTrackPx), vTrackPx)
|
||||
val vTravelPx = vTrackPx - vLen
|
||||
val vRaw = if (vTravelPx <= 0) 0
|
||||
else (vTravelPx * (adapter.scrollOffset / vMaxScrollPx)).roundToInt()
|
||||
val vPos = (if (reverseLayout) vTravelPx - vRaw else vRaw).coerceIn(0, vTravelPx)
|
||||
|
||||
// Map a track-relative thumb-top to a scroll offset. The
|
||||
// target uses the LIVE max scroll (read fresh each move),
|
||||
// not the press-time value — the adapter compares it against
|
||||
// its live scrollOffset, and mixing a stale scale with a live
|
||||
// one makes the delta run away (grab at the bottom, drag up,
|
||||
// and the list overshoots to the middle).
|
||||
fun scrollToTrackPos(inThumbTop: Int) {
|
||||
if (vTravelPx <= 0) return
|
||||
val vLiveMax = adapter.contentSize - adapter.viewportSize
|
||||
if (vLiveMax <= 0.0) return
|
||||
val vClamped = inThumbTop.coerceIn(0, vTravelPx)
|
||||
val vFrac = (if (reverseLayout) vTravelPx - vClamped else vClamped).toDouble() / vTravelPx
|
||||
vScope.launch { adapter.scrollTo(vFrac * vLiveMax) }
|
||||
}
|
||||
|
||||
val vPress = (if (isVertical) vDown.position.y else vDown.position.x).toInt()
|
||||
val vGrab: Int
|
||||
if (vPress in vPos..(vPos + vLen)) {
|
||||
vDraggingThumb = true
|
||||
vGrab = vPress - vPos
|
||||
} else {
|
||||
// Page toward the click by one viewport.
|
||||
vDraggingThumb = false
|
||||
vGrab = 0
|
||||
val vDir = if (vPress < vPos) -1.0 else 1.0
|
||||
vScope.launch { adapter.scrollTo(adapter.scrollOffset + vDir * vViewportPx) }
|
||||
}
|
||||
|
||||
// Follow the pressed pointer to release, consuming every
|
||||
// change so the interaction can't leak. Only a thumb grab
|
||||
// drags-to-scroll; a track press just consumes.
|
||||
do {
|
||||
val vEvent = awaitPointerEvent()
|
||||
val vChange = vEvent.changes.firstOrNull { it.id == vDown.id } ?: break
|
||||
if (vDraggingThumb) {
|
||||
val vCur = (if (isVertical) change.position.y else change.position.x).toInt()
|
||||
val vCur = (if (isVertical) vChange.position.y else vChange.position.x).toInt()
|
||||
scrollToTrackPos(vCur - vGrab)
|
||||
}
|
||||
},
|
||||
onDragEnd = { vDraggingThumb = false },
|
||||
onDragCancel = { vDraggingThumb = false },
|
||||
)
|
||||
vChange.consume()
|
||||
} while (vEvent.changes.any { it.id == vDown.id && it.pressed })
|
||||
|
||||
vDraggingThumb = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Klib ABI Dump
|
||||
// Targets: [linuxArm64, linuxX64, macosArm64, mingwX64]
|
||||
// Rendering settings:
|
||||
// - Signature version: 2
|
||||
// - Show manifest properties: true
|
||||
// - Show declarations: true
|
||||
|
||||
// Library unique name: <com.bitsycore.compose.sdl:material-ripple>
|
||||
abstract interface androidx.compose.material.ripple/RippleTheme { // androidx.compose.material.ripple/RippleTheme|null[0]
|
||||
abstract fun defaultColor(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics/Color // androidx.compose.material.ripple/RippleTheme.defaultColor|defaultColor(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
abstract fun rippleAlpha(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.material.ripple/RippleAlpha // androidx.compose.material.ripple/RippleTheme.rippleAlpha|rippleAlpha(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
|
||||
final object Companion { // androidx.compose.material.ripple/RippleTheme.Companion|null[0]
|
||||
final fun defaultRippleAlpha(androidx.compose.ui.graphics/Color, kotlin/Boolean): androidx.compose.material.ripple/RippleAlpha // androidx.compose.material.ripple/RippleTheme.Companion.defaultRippleAlpha|defaultRippleAlpha(androidx.compose.ui.graphics.Color;kotlin.Boolean){}[0]
|
||||
final fun defaultRippleColor(androidx.compose.ui.graphics/Color, kotlin/Boolean): androidx.compose.ui.graphics/Color // androidx.compose.material.ripple/RippleTheme.Companion.defaultRippleColor|defaultRippleColor(androidx.compose.ui.graphics.Color;kotlin.Boolean){}[0]
|
||||
}
|
||||
}
|
||||
|
||||
final class androidx.compose.material.ripple/RippleAlpha { // androidx.compose.material.ripple/RippleAlpha|null[0]
|
||||
constructor <init>(kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Float) // androidx.compose.material.ripple/RippleAlpha.<init>|<init>(kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Float){}[0]
|
||||
|
||||
final val draggedAlpha // androidx.compose.material.ripple/RippleAlpha.draggedAlpha|{}draggedAlpha[0]
|
||||
final fun <get-draggedAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.draggedAlpha.<get-draggedAlpha>|<get-draggedAlpha>(){}[0]
|
||||
final val focusedAlpha // androidx.compose.material.ripple/RippleAlpha.focusedAlpha|{}focusedAlpha[0]
|
||||
final fun <get-focusedAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.focusedAlpha.<get-focusedAlpha>|<get-focusedAlpha>(){}[0]
|
||||
final val hoveredAlpha // androidx.compose.material.ripple/RippleAlpha.hoveredAlpha|{}hoveredAlpha[0]
|
||||
final fun <get-hoveredAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.hoveredAlpha.<get-hoveredAlpha>|<get-hoveredAlpha>(){}[0]
|
||||
final val pressedAlpha // androidx.compose.material.ripple/RippleAlpha.pressedAlpha|{}pressedAlpha[0]
|
||||
final fun <get-pressedAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.pressedAlpha.<get-pressedAlpha>|<get-pressedAlpha>(){}[0]
|
||||
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // androidx.compose.material.ripple/RippleAlpha.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // androidx.compose.material.ripple/RippleAlpha.hashCode|hashCode(){}[0]
|
||||
final fun toString(): kotlin/String // androidx.compose.material.ripple/RippleAlpha.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final val androidx.compose.material.ripple/LocalRippleTheme // androidx.compose.material.ripple/LocalRippleTheme|{}LocalRippleTheme[0]
|
||||
final fun <get-LocalRippleTheme>(): androidx.compose.runtime/ProvidableCompositionLocal<androidx.compose.material.ripple/RippleTheme> // androidx.compose.material.ripple/LocalRippleTheme.<get-LocalRippleTheme>|<get-LocalRippleTheme>(){}[0]
|
||||
final val androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop // androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop|#static{}androidx_compose_material_ripple_RippleAlpha$stableprop[0]
|
||||
|
||||
final fun androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop_getter(): kotlin/Int // androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop_getter|androidx_compose_material_ripple_RippleAlpha$stableprop_getter(){}[0]
|
||||
final fun androidx.compose.material.ripple/createRippleModifierNode(androidx.compose.foundation.interaction/InteractionSource, kotlin/Boolean, androidx.compose.ui.unit/Dp, androidx.compose.ui.graphics/ColorProducer, kotlin/Function0<androidx.compose.material.ripple/RippleAlpha>): androidx.compose.ui.node/DelegatableNode // androidx.compose.material.ripple/createRippleModifierNode|createRippleModifierNode(androidx.compose.foundation.interaction.InteractionSource;kotlin.Boolean;androidx.compose.ui.unit.Dp;androidx.compose.ui.graphics.ColorProducer;kotlin.Function0<androidx.compose.material.ripple.RippleAlpha>){}[0]
|
||||
final fun androidx.compose.material.ripple/rememberRipple(kotlin/Boolean, androidx.compose.ui.unit/Dp, androidx.compose.ui.graphics/Color, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.foundation/Indication // androidx.compose.material.ripple/rememberRipple|rememberRipple(kotlin.Boolean;androidx.compose.ui.unit.Dp;androidx.compose.ui.graphics.Color;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
|
||||
File diff suppressed because it is too large
Load Diff
+93
-189
@@ -1834,6 +1834,10 @@ abstract interface androidx.compose.ui/UiMediaScope { // androidx.compose.ui/UiM
|
||||
}
|
||||
}
|
||||
|
||||
abstract interface com.compose.sdl.graphics/EncodedImageDecoder { // com.compose.sdl.graphics/EncodedImageDecoder|null[0]
|
||||
abstract fun decode(kotlin/ByteArray): androidx.compose.ui.graphics/ImageBitmap? // com.compose.sdl.graphics/EncodedImageDecoder.decode|decode(kotlin.ByteArray){}[0]
|
||||
}
|
||||
|
||||
abstract interface com.compose.sdl.graphics/NativePainterCanvas { // com.compose.sdl.graphics/NativePainterCanvas|null[0]
|
||||
abstract fun drawNativePainter(kotlin/String, com.compose.sdl.res/ResourceKind, kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Float, androidx.compose.ui.layout/ContentScale, kotlin/Float) // com.compose.sdl.graphics/NativePainterCanvas.drawNativePainter|drawNativePainter(kotlin.String;com.compose.sdl.res.ResourceKind;kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Float;androidx.compose.ui.layout.ContentScale;kotlin.Float){}[0]
|
||||
}
|
||||
@@ -2522,9 +2526,23 @@ final class androidx.compose.ui.autofill/AutofillTree { // androidx.compose.ui.a
|
||||
final fun plusAssign(androidx.compose.ui.autofill/AutofillNode) // androidx.compose.ui.autofill/AutofillTree.plusAssign|plusAssign(androidx.compose.ui.autofill.AutofillNode){}[0]
|
||||
}
|
||||
|
||||
final class androidx.compose.ui.draganddrop/DragAndDropEvent // androidx.compose.ui.draganddrop/DragAndDropEvent|null[0]
|
||||
final class androidx.compose.ui.draganddrop/DragAndDropEvent { // androidx.compose.ui.draganddrop/DragAndDropEvent|null[0]
|
||||
final val position // androidx.compose.ui.draganddrop/DragAndDropEvent.position|{}position[0]
|
||||
final fun <get-position>(): androidx.compose.ui.geometry/Offset // androidx.compose.ui.draganddrop/DragAndDropEvent.position.<get-position>|<get-position>(){}[0]
|
||||
final val transferData // androidx.compose.ui.draganddrop/DragAndDropEvent.transferData|{}transferData[0]
|
||||
final fun <get-transferData>(): androidx.compose.ui.draganddrop/DragAndDropTransferData // androidx.compose.ui.draganddrop/DragAndDropEvent.transferData.<get-transferData>|<get-transferData>(){}[0]
|
||||
}
|
||||
|
||||
final class androidx.compose.ui.draganddrop/DragAndDropTransferData // androidx.compose.ui.draganddrop/DragAndDropTransferData|null[0]
|
||||
final class androidx.compose.ui.draganddrop/DragAndDropTransferData { // androidx.compose.ui.draganddrop/DragAndDropTransferData|null[0]
|
||||
final val filePaths // androidx.compose.ui.draganddrop/DragAndDropTransferData.filePaths|{}filePaths[0]
|
||||
final fun <get-filePaths>(): kotlin.collections/List<kotlin/String> // androidx.compose.ui.draganddrop/DragAndDropTransferData.filePaths.<get-filePaths>|<get-filePaths>(){}[0]
|
||||
final val hasFiles // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasFiles|{}hasFiles[0]
|
||||
final fun <get-hasFiles>(): kotlin/Boolean // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasFiles.<get-hasFiles>|<get-hasFiles>(){}[0]
|
||||
final val hasText // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasText|{}hasText[0]
|
||||
final fun <get-hasText>(): kotlin/Boolean // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasText.<get-hasText>|<get-hasText>(){}[0]
|
||||
final val text // androidx.compose.ui.draganddrop/DragAndDropTransferData.text|{}text[0]
|
||||
final fun <get-text>(): kotlin/String? // androidx.compose.ui.draganddrop/DragAndDropTransferData.text.<get-text>|<get-text>(){}[0]
|
||||
}
|
||||
|
||||
final class androidx.compose.ui.draw/CacheDrawScope : androidx.compose.ui.unit/Density { // androidx.compose.ui.draw/CacheDrawScope|null[0]
|
||||
final val density // androidx.compose.ui.draw/CacheDrawScope.density|{}density[0]
|
||||
@@ -3654,9 +3672,11 @@ final class androidx.compose.ui.platform/ClipEntry { // androidx.compose.ui.plat
|
||||
final val clipMetadata // androidx.compose.ui.platform/ClipEntry.clipMetadata|{}clipMetadata[0]
|
||||
final fun <get-clipMetadata>(): androidx.compose.ui.platform/ClipMetadata // androidx.compose.ui.platform/ClipEntry.clipMetadata.<get-clipMetadata>|<get-clipMetadata>(){}[0]
|
||||
|
||||
final fun getImage(): kotlin/ByteArray? // androidx.compose.ui.platform/ClipEntry.getImage|getImage(){}[0]
|
||||
final fun getPlainText(): kotlin/String? // androidx.compose.ui.platform/ClipEntry.getPlainText|getPlainText(){}[0]
|
||||
|
||||
final object Companion { // androidx.compose.ui.platform/ClipEntry.Companion|null[0]
|
||||
final fun withImage(kotlin/ByteArray): androidx.compose.ui.platform/ClipEntry // androidx.compose.ui.platform/ClipEntry.Companion.withImage|withImage(kotlin.ByteArray){}[0]
|
||||
final fun withPlainText(kotlin/String): androidx.compose.ui.platform/ClipEntry // androidx.compose.ui.platform/ClipEntry.Companion.withPlainText|withPlainText(kotlin.String){}[0]
|
||||
}
|
||||
}
|
||||
@@ -5348,136 +5368,6 @@ final class com.compose.sdl.element/GraphicsLayerNode : androidx.compose.ui/Modi
|
||||
final fun <set-translationY>(kotlin/Float) // com.compose.sdl.element/GraphicsLayerNode.translationY.<set-translationY>|<set-translationY>(kotlin.Float){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/MiddleClickModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/MiddleClickNode> { // com.compose.sdl.element/MiddleClickModifier|null[0]
|
||||
constructor <init>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/MiddleClickModifier.<init>|<init>(kotlin.Function0<kotlin.Unit>){}[0]
|
||||
|
||||
final val onClick // com.compose.sdl.element/MiddleClickModifier.onClick|{}onClick[0]
|
||||
final fun <get-onClick>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/MiddleClickModifier.onClick.<get-onClick>|<get-onClick>(){}[0]
|
||||
|
||||
final fun create(): com.compose.sdl.element/MiddleClickNode // com.compose.sdl.element/MiddleClickModifier.create|create(){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/MiddleClickModifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl.element/MiddleClickModifier.hashCode|hashCode(){}[0]
|
||||
final fun update(com.compose.sdl.element/MiddleClickNode) // com.compose.sdl.element/MiddleClickModifier.update|update(com.compose.sdl.element.MiddleClickNode){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/MiddleClickNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/MiddleClickNode|null[0]
|
||||
constructor <init>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/MiddleClickNode.<init>|<init>(kotlin.Function0<kotlin.Unit>){}[0]
|
||||
|
||||
final var onClick // com.compose.sdl.element/MiddleClickNode.onClick|{}onClick[0]
|
||||
final fun <get-onClick>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/MiddleClickNode.onClick.<get-onClick>|<get-onClick>(){}[0]
|
||||
final fun <set-onClick>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/MiddleClickNode.onClick.<set-onClick>|<set-onClick>(kotlin.Function0<kotlin.Unit>){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/OnDragModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/OnDragNode> { // com.compose.sdl.element/OnDragModifier|null[0]
|
||||
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/OnDragModifier.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function0<kotlin.Unit>){}[0]
|
||||
|
||||
final val onDrag // com.compose.sdl.element/OnDragModifier.onDrag|{}onDrag[0]
|
||||
final fun <get-onDrag>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragModifier.onDrag.<get-onDrag>|<get-onDrag>(){}[0]
|
||||
final val onEnd // com.compose.sdl.element/OnDragModifier.onEnd|{}onEnd[0]
|
||||
final fun <get-onEnd>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/OnDragModifier.onEnd.<get-onEnd>|<get-onEnd>(){}[0]
|
||||
final val onStart // com.compose.sdl.element/OnDragModifier.onStart|{}onStart[0]
|
||||
final fun <get-onStart>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragModifier.onStart.<get-onStart>|<get-onStart>(){}[0]
|
||||
|
||||
final fun create(): com.compose.sdl.element/OnDragNode // com.compose.sdl.element/OnDragModifier.create|create(){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/OnDragModifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl.element/OnDragModifier.hashCode|hashCode(){}[0]
|
||||
final fun update(com.compose.sdl.element/OnDragNode) // com.compose.sdl.element/OnDragModifier.update|update(com.compose.sdl.element.OnDragNode){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/OnDragNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/OnDragNode|null[0]
|
||||
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/OnDragNode.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function0<kotlin.Unit>){}[0]
|
||||
|
||||
final var onDrag // com.compose.sdl.element/OnDragNode.onDrag|{}onDrag[0]
|
||||
final fun <get-onDrag>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragNode.onDrag.<get-onDrag>|<get-onDrag>(){}[0]
|
||||
final fun <set-onDrag>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnDragNode.onDrag.<set-onDrag>|<set-onDrag>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
final var onEnd // com.compose.sdl.element/OnDragNode.onEnd|{}onEnd[0]
|
||||
final fun <get-onEnd>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/OnDragNode.onEnd.<get-onEnd>|<get-onEnd>(){}[0]
|
||||
final fun <set-onEnd>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/OnDragNode.onEnd.<set-onEnd>|<set-onEnd>(kotlin.Function0<kotlin.Unit>){}[0]
|
||||
final var onStart // com.compose.sdl.element/OnDragNode.onStart|{}onStart[0]
|
||||
final fun <get-onStart>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragNode.onStart.<get-onStart>|<get-onStart>(){}[0]
|
||||
final fun <set-onStart>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnDragNode.onStart.<set-onStart>|<set-onStart>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/OnPressedModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/OnPressedNode> { // com.compose.sdl.element/OnPressedModifier|null[0]
|
||||
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnPressedModifier.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
|
||||
final val handler // com.compose.sdl.element/OnPressedModifier.handler|{}handler[0]
|
||||
final fun <get-handler>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnPressedModifier.handler.<get-handler>|<get-handler>(){}[0]
|
||||
|
||||
final fun create(): com.compose.sdl.element/OnPressedNode // com.compose.sdl.element/OnPressedModifier.create|create(){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/OnPressedModifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl.element/OnPressedModifier.hashCode|hashCode(){}[0]
|
||||
final fun update(com.compose.sdl.element/OnPressedNode) // com.compose.sdl.element/OnPressedModifier.update|update(com.compose.sdl.element.OnPressedNode){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/OnPressedNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/OnPressedNode|null[0]
|
||||
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnPressedNode.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
|
||||
final var handler // com.compose.sdl.element/OnPressedNode.handler|{}handler[0]
|
||||
final fun <get-handler>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnPressedNode.handler.<get-handler>|<get-handler>(){}[0]
|
||||
final fun <set-handler>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnPressedNode.handler.<set-handler>|<set-handler>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/OnTextInputModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/OnTextInputNode> { // com.compose.sdl.element/OnTextInputModifier|null[0]
|
||||
constructor <init>(kotlin/Function1<kotlin/String, kotlin/Unit>) // com.compose.sdl.element/OnTextInputModifier.<init>|<init>(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
|
||||
|
||||
final val handler // com.compose.sdl.element/OnTextInputModifier.handler|{}handler[0]
|
||||
final fun <get-handler>(): kotlin/Function1<kotlin/String, kotlin/Unit> // com.compose.sdl.element/OnTextInputModifier.handler.<get-handler>|<get-handler>(){}[0]
|
||||
|
||||
final fun create(): com.compose.sdl.element/OnTextInputNode // com.compose.sdl.element/OnTextInputModifier.create|create(){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/OnTextInputModifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl.element/OnTextInputModifier.hashCode|hashCode(){}[0]
|
||||
final fun update(com.compose.sdl.element/OnTextInputNode) // com.compose.sdl.element/OnTextInputModifier.update|update(com.compose.sdl.element.OnTextInputNode){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/OnTextInputNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/OnTextInputNode|null[0]
|
||||
constructor <init>(kotlin/Function1<kotlin/String, kotlin/Unit>) // com.compose.sdl.element/OnTextInputNode.<init>|<init>(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
|
||||
|
||||
final var handler // com.compose.sdl.element/OnTextInputNode.handler|{}handler[0]
|
||||
final fun <get-handler>(): kotlin/Function1<kotlin/String, kotlin/Unit> // com.compose.sdl.element/OnTextInputNode.handler.<get-handler>|<get-handler>(){}[0]
|
||||
final fun <set-handler>(kotlin/Function1<kotlin/String, kotlin/Unit>) // com.compose.sdl.element/OnTextInputNode.handler.<set-handler>|<set-handler>(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/PressableModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/PressableNode> { // com.compose.sdl.element/PressableModifier|null[0]
|
||||
constructor <init>(kotlin/Function1<kotlin/Boolean, kotlin/Unit>) // com.compose.sdl.element/PressableModifier.<init>|<init>(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
|
||||
|
||||
final val onChange // com.compose.sdl.element/PressableModifier.onChange|{}onChange[0]
|
||||
final fun <get-onChange>(): kotlin/Function1<kotlin/Boolean, kotlin/Unit> // com.compose.sdl.element/PressableModifier.onChange.<get-onChange>|<get-onChange>(){}[0]
|
||||
|
||||
final fun create(): com.compose.sdl.element/PressableNode // com.compose.sdl.element/PressableModifier.create|create(){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/PressableModifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl.element/PressableModifier.hashCode|hashCode(){}[0]
|
||||
final fun update(com.compose.sdl.element/PressableNode) // com.compose.sdl.element/PressableModifier.update|update(com.compose.sdl.element.PressableNode){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/PressableNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/PressableNode|null[0]
|
||||
constructor <init>(kotlin/Function1<kotlin/Boolean, kotlin/Unit>) // com.compose.sdl.element/PressableNode.<init>|<init>(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
|
||||
|
||||
final var onChange // com.compose.sdl.element/PressableNode.onChange|{}onChange[0]
|
||||
final fun <get-onChange>(): kotlin/Function1<kotlin/Boolean, kotlin/Unit> // com.compose.sdl.element/PressableNode.onChange.<get-onChange>|<get-onChange>(){}[0]
|
||||
final fun <set-onChange>(kotlin/Function1<kotlin/Boolean, kotlin/Unit>) // com.compose.sdl.element/PressableNode.onChange.<set-onChange>|<set-onChange>(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/SecondaryClickModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/SecondaryClickNode> { // com.compose.sdl.element/SecondaryClickModifier|null[0]
|
||||
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/SecondaryClickModifier.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
|
||||
final val onClick // com.compose.sdl.element/SecondaryClickModifier.onClick|{}onClick[0]
|
||||
final fun <get-onClick>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/SecondaryClickModifier.onClick.<get-onClick>|<get-onClick>(){}[0]
|
||||
|
||||
final fun create(): com.compose.sdl.element/SecondaryClickNode // com.compose.sdl.element/SecondaryClickModifier.create|create(){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/SecondaryClickModifier.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl.element/SecondaryClickModifier.hashCode|hashCode(){}[0]
|
||||
final fun update(com.compose.sdl.element/SecondaryClickNode) // com.compose.sdl.element/SecondaryClickModifier.update|update(com.compose.sdl.element.SecondaryClickNode){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.element/SecondaryClickNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/SecondaryClickNode|null[0]
|
||||
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/SecondaryClickNode.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
|
||||
final var onClick // com.compose.sdl.element/SecondaryClickNode.onClick|{}onClick[0]
|
||||
final fun <get-onClick>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/SecondaryClickNode.onClick.<get-onClick>|<get-onClick>(){}[0]
|
||||
final fun <set-onClick>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/SecondaryClickNode.onClick.<set-onClick>|<set-onClick>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
}
|
||||
|
||||
final class com.compose.sdl.graphics/ProjectCanvas : androidx.compose.ui.graphics/Canvas { // com.compose.sdl.graphics/ProjectCanvas|null[0]
|
||||
constructor <init>() // com.compose.sdl.graphics/ProjectCanvas.<init>|<init>(){}[0]
|
||||
|
||||
@@ -5649,8 +5539,6 @@ final class com.compose.sdl.node/ComposeRootHost { // com.compose.sdl.node/Compo
|
||||
|
||||
final val applier // com.compose.sdl.node/ComposeRootHost.applier|{}applier[0]
|
||||
final fun <get-applier>(): androidx.compose.runtime/Applier<*> // com.compose.sdl.node/ComposeRootHost.applier.<get-applier>|<get-applier>(){}[0]
|
||||
final val autofillTree // com.compose.sdl.node/ComposeRootHost.autofillTree|{}autofillTree[0]
|
||||
final fun <get-autofillTree>(): androidx.compose.ui.autofill/AutofillTree // com.compose.sdl.node/ComposeRootHost.autofillTree.<get-autofillTree>|<get-autofillTree>(){}[0]
|
||||
final val density // com.compose.sdl.node/ComposeRootHost.density|{}density[0]
|
||||
final fun <get-density>(): androidx.compose.ui.unit/Density // com.compose.sdl.node/ComposeRootHost.density.<get-density>|<get-density>(){}[0]
|
||||
final val focusManager // com.compose.sdl.node/ComposeRootHost.focusManager|{}focusManager[0]
|
||||
@@ -5665,8 +5553,6 @@ final class com.compose.sdl.node/ComposeRootHost { // com.compose.sdl.node/Compo
|
||||
final fun <get-layoutDirection>(): androidx.compose.ui.unit/LayoutDirection // com.compose.sdl.node/ComposeRootHost.layoutDirection.<get-layoutDirection>|<get-layoutDirection>(){}[0]
|
||||
final val softwareKeyboardController // com.compose.sdl.node/ComposeRootHost.softwareKeyboardController|{}softwareKeyboardController[0]
|
||||
final fun <get-softwareKeyboardController>(): androidx.compose.ui.platform/SoftwareKeyboardController // com.compose.sdl.node/ComposeRootHost.softwareKeyboardController.<get-softwareKeyboardController>|<get-softwareKeyboardController>(){}[0]
|
||||
final val textInputService // com.compose.sdl.node/ComposeRootHost.textInputService|{}textInputService[0]
|
||||
final fun <get-textInputService>(): androidx.compose.ui.text.input/TextInputService // com.compose.sdl.node/ComposeRootHost.textInputService.<get-textInputService>|<get-textInputService>(){}[0]
|
||||
final val textToolbar // com.compose.sdl.node/ComposeRootHost.textToolbar|{}textToolbar[0]
|
||||
final fun <get-textToolbar>(): androidx.compose.ui.platform/TextToolbar // com.compose.sdl.node/ComposeRootHost.textToolbar.<get-textToolbar>|<get-textToolbar>(){}[0]
|
||||
final val viewConfiguration // com.compose.sdl.node/ComposeRootHost.viewConfiguration|{}viewConfiguration[0]
|
||||
@@ -5676,9 +5562,12 @@ final class com.compose.sdl.node/ComposeRootHost { // com.compose.sdl.node/Compo
|
||||
|
||||
final fun attach() // com.compose.sdl.node/ComposeRootHost.attach|attach(){}[0]
|
||||
final fun dispatchKeyEvent(androidx.compose.ui.input.key/KeyEvent): kotlin/Boolean // com.compose.sdl.node/ComposeRootHost.dispatchKeyEvent|dispatchKeyEvent(androidx.compose.ui.input.key.KeyEvent){}[0]
|
||||
final fun dispatchTextInput(kotlin/String): kotlin/Boolean // com.compose.sdl.node/ComposeRootHost.dispatchTextInput|dispatchTextInput(kotlin.String){}[0]
|
||||
final fun measureAndLayout() // com.compose.sdl.node/ComposeRootHost.measureAndLayout|measureAndLayout(){}[0]
|
||||
final fun onPointer(kotlin/Float, kotlin/Float, kotlin/Int, kotlin/Int) // com.compose.sdl.node/ComposeRootHost.onPointer|onPointer(kotlin.Float;kotlin.Float;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun onDropBegin() // com.compose.sdl.node/ComposeRootHost.onDropBegin|onDropBegin(){}[0]
|
||||
final fun onDropComplete() // com.compose.sdl.node/ComposeRootHost.onDropComplete|onDropComplete(){}[0]
|
||||
final fun onDropFile(kotlin/String) // com.compose.sdl.node/ComposeRootHost.onDropFile|onDropFile(kotlin.String){}[0]
|
||||
final fun onDropPosition(kotlin/Float, kotlin/Float) // com.compose.sdl.node/ComposeRootHost.onDropPosition|onDropPosition(kotlin.Float;kotlin.Float){}[0]
|
||||
final fun onDropText(kotlin/String) // com.compose.sdl.node/ComposeRootHost.onDropText|onDropText(kotlin.String){}[0]
|
||||
final fun onPointerRaw(kotlin/Float, kotlin/Float, kotlin/Int, kotlin/Int, kotlin/Long) // com.compose.sdl.node/ComposeRootHost.onPointerRaw|onPointerRaw(kotlin.Float;kotlin.Float;kotlin.Int;kotlin.Int;kotlin.Long){}[0]
|
||||
final fun onWheel(kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Long) // com.compose.sdl.node/ComposeRootHost.onWheel|onWheel(kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Long){}[0]
|
||||
final fun sendAnimationFrame(kotlin/Long) // com.compose.sdl.node/ComposeRootHost.sendAnimationFrame|sendAnimationFrame(kotlin.Long){}[0]
|
||||
@@ -8387,6 +8276,45 @@ sealed class androidx.compose.ui.text.font/SystemFontFamily : androidx.compose.u
|
||||
sealed class androidx.compose.ui.text/TtsAnnotation : androidx.compose.ui.text/AnnotatedString.Annotation // androidx.compose.ui.text/TtsAnnotation|null[0]
|
||||
|
||||
sealed class com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent|null[0]
|
||||
final enum class DropPhase : kotlin/Enum<com.compose.sdl/AppEvent.DropPhase> { // com.compose.sdl/AppEvent.DropPhase|null[0]
|
||||
enum entry BEGIN // com.compose.sdl/AppEvent.DropPhase.BEGIN|null[0]
|
||||
enum entry COMPLETE // com.compose.sdl/AppEvent.DropPhase.COMPLETE|null[0]
|
||||
enum entry FILE // com.compose.sdl/AppEvent.DropPhase.FILE|null[0]
|
||||
enum entry POSITION // com.compose.sdl/AppEvent.DropPhase.POSITION|null[0]
|
||||
enum entry TEXT // com.compose.sdl/AppEvent.DropPhase.TEXT|null[0]
|
||||
|
||||
final val entries // com.compose.sdl/AppEvent.DropPhase.entries|#static{}entries[0]
|
||||
final fun <get-entries>(): kotlin.enums/EnumEntries<com.compose.sdl/AppEvent.DropPhase> // com.compose.sdl/AppEvent.DropPhase.entries.<get-entries>|<get-entries>#static(){}[0]
|
||||
|
||||
final fun valueOf(kotlin/String): com.compose.sdl/AppEvent.DropPhase // com.compose.sdl/AppEvent.DropPhase.valueOf|valueOf#static(kotlin.String){}[0]
|
||||
final fun values(): kotlin/Array<com.compose.sdl/AppEvent.DropPhase> // com.compose.sdl/AppEvent.DropPhase.values|values#static(){}[0]
|
||||
}
|
||||
|
||||
final class Drop : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.Drop|null[0]
|
||||
constructor <init>(kotlin/UInt, com.compose.sdl/AppEvent.DropPhase, kotlin/Float = ..., kotlin/Float = ..., kotlin/String? = ...) // com.compose.sdl/AppEvent.Drop.<init>|<init>(kotlin.UInt;com.compose.sdl.AppEvent.DropPhase;kotlin.Float;kotlin.Float;kotlin.String?){}[0]
|
||||
|
||||
final val data // com.compose.sdl/AppEvent.Drop.data|{}data[0]
|
||||
final fun <get-data>(): kotlin/String? // com.compose.sdl/AppEvent.Drop.data.<get-data>|<get-data>(){}[0]
|
||||
final val phase // com.compose.sdl/AppEvent.Drop.phase|{}phase[0]
|
||||
final fun <get-phase>(): com.compose.sdl/AppEvent.DropPhase // com.compose.sdl/AppEvent.Drop.phase.<get-phase>|<get-phase>(){}[0]
|
||||
final val windowId // com.compose.sdl/AppEvent.Drop.windowId|{}windowId[0]
|
||||
final fun <get-windowId>(): kotlin/UInt // com.compose.sdl/AppEvent.Drop.windowId.<get-windowId>|<get-windowId>(){}[0]
|
||||
final val x // com.compose.sdl/AppEvent.Drop.x|{}x[0]
|
||||
final fun <get-x>(): kotlin/Float // com.compose.sdl/AppEvent.Drop.x.<get-x>|<get-x>(){}[0]
|
||||
final val y // com.compose.sdl/AppEvent.Drop.y|{}y[0]
|
||||
final fun <get-y>(): kotlin/Float // com.compose.sdl/AppEvent.Drop.y.<get-y>|<get-y>(){}[0]
|
||||
|
||||
final fun component1(): kotlin/UInt // com.compose.sdl/AppEvent.Drop.component1|component1(){}[0]
|
||||
final fun component2(): com.compose.sdl/AppEvent.DropPhase // com.compose.sdl/AppEvent.Drop.component2|component2(){}[0]
|
||||
final fun component3(): kotlin/Float // com.compose.sdl/AppEvent.Drop.component3|component3(){}[0]
|
||||
final fun component4(): kotlin/Float // com.compose.sdl/AppEvent.Drop.component4|component4(){}[0]
|
||||
final fun component5(): kotlin/String? // com.compose.sdl/AppEvent.Drop.component5|component5(){}[0]
|
||||
final fun copy(kotlin/UInt = ..., com.compose.sdl/AppEvent.DropPhase = ..., kotlin/Float = ..., kotlin/Float = ..., kotlin/String? = ...): com.compose.sdl/AppEvent.Drop // com.compose.sdl/AppEvent.Drop.copy|copy(kotlin.UInt;com.compose.sdl.AppEvent.DropPhase;kotlin.Float;kotlin.Float;kotlin.String?){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl/AppEvent.Drop.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl/AppEvent.Drop.hashCode|hashCode(){}[0]
|
||||
final fun toString(): kotlin/String // com.compose.sdl/AppEvent.Drop.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class Key : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.Key|null[0]
|
||||
constructor <init>(androidx.compose.ui.input.key/KeyEvent, kotlin/UInt = ...) // com.compose.sdl/AppEvent.Key.<init>|<init>(androidx.compose.ui.input.key.KeyEvent;kotlin.UInt){}[0]
|
||||
|
||||
@@ -8473,6 +8401,25 @@ sealed class com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent|null[0]
|
||||
final fun toString(): kotlin/String // com.compose.sdl/AppEvent.TextInput.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class WindowActivation : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.WindowActivation|null[0]
|
||||
constructor <init>(kotlin/UInt = ..., kotlin/Boolean? = ..., kotlin/Boolean? = ...) // com.compose.sdl/AppEvent.WindowActivation.<init>|<init>(kotlin.UInt;kotlin.Boolean?;kotlin.Boolean?){}[0]
|
||||
|
||||
final val focused // com.compose.sdl/AppEvent.WindowActivation.focused|{}focused[0]
|
||||
final fun <get-focused>(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.focused.<get-focused>|<get-focused>(){}[0]
|
||||
final val visible // com.compose.sdl/AppEvent.WindowActivation.visible|{}visible[0]
|
||||
final fun <get-visible>(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.visible.<get-visible>|<get-visible>(){}[0]
|
||||
final val windowId // com.compose.sdl/AppEvent.WindowActivation.windowId|{}windowId[0]
|
||||
final fun <get-windowId>(): kotlin/UInt // com.compose.sdl/AppEvent.WindowActivation.windowId.<get-windowId>|<get-windowId>(){}[0]
|
||||
|
||||
final fun component1(): kotlin/UInt // com.compose.sdl/AppEvent.WindowActivation.component1|component1(){}[0]
|
||||
final fun component2(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.component2|component2(){}[0]
|
||||
final fun component3(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.component3|component3(){}[0]
|
||||
final fun copy(kotlin/UInt = ..., kotlin/Boolean? = ..., kotlin/Boolean? = ...): com.compose.sdl/AppEvent.WindowActivation // com.compose.sdl/AppEvent.WindowActivation.copy|copy(kotlin.UInt;kotlin.Boolean?;kotlin.Boolean?){}[0]
|
||||
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl/AppEvent.WindowActivation.equals|equals(kotlin.Any?){}[0]
|
||||
final fun hashCode(): kotlin/Int // com.compose.sdl/AppEvent.WindowActivation.hashCode|hashCode(){}[0]
|
||||
final fun toString(): kotlin/String // com.compose.sdl/AppEvent.WindowActivation.toString|toString(){}[0]
|
||||
}
|
||||
|
||||
final class WindowClose : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.WindowClose|null[0]
|
||||
constructor <init>(kotlin/UInt = ...) // com.compose.sdl/AppEvent.WindowClose.<init>|<init>(kotlin.UInt){}[0]
|
||||
|
||||
@@ -9299,16 +9246,6 @@ final val androidx.compose.ui.platform/androidx_compose_ui_platform_InspectorVal
|
||||
final val androidx.compose.ui.platform/androidx_compose_ui_platform_PlatformWindowInsetsProviderNode$stableprop // androidx.compose.ui.platform/androidx_compose_ui_platform_PlatformWindowInsetsProviderNode$stableprop|#static{}androidx_compose_ui_platform_PlatformWindowInsetsProviderNode$stableprop[0]
|
||||
final val androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElement$stableprop // androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElement$stableprop|#static{}androidx_compose_ui_platform_ValueElement$stableprop[0]
|
||||
final val androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop // androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop|#static{}androidx_compose_ui_platform_ValueElementSequence$stableprop[0]
|
||||
final val androidx.compose.ui.platform/currentClipboard // androidx.compose.ui.platform/currentClipboard|{}currentClipboard[0]
|
||||
final fun <get-currentClipboard>(): androidx.compose.ui.platform/ClipboardManager // androidx.compose.ui.platform/currentClipboard.<get-currentClipboard>|<get-currentClipboard>(){}[0]
|
||||
final val androidx.compose.ui.platform/defaultClipboard // androidx.compose.ui.platform/defaultClipboard|{}defaultClipboard[0]
|
||||
final fun <get-defaultClipboard>(): androidx.compose.ui.platform/Clipboard // androidx.compose.ui.platform/defaultClipboard.<get-defaultClipboard>|<get-defaultClipboard>(){}[0]
|
||||
final val androidx.compose.ui.platform/defaultClipboardManager // androidx.compose.ui.platform/defaultClipboardManager|{}defaultClipboardManager[0]
|
||||
final fun <get-defaultClipboardManager>(): androidx.compose.ui.platform/ClipboardManager // androidx.compose.ui.platform/defaultClipboardManager.<get-defaultClipboardManager>|<get-defaultClipboardManager>(){}[0]
|
||||
final val androidx.compose.ui.platform/platformClipboard // androidx.compose.ui.platform/platformClipboard|{}platformClipboard[0]
|
||||
final fun <get-platformClipboard>(): androidx.compose.ui.platform/Clipboard // androidx.compose.ui.platform/platformClipboard.<get-platformClipboard>|<get-platformClipboard>(){}[0]
|
||||
final val androidx.compose.ui.platform/platformClipboardManager // androidx.compose.ui.platform/platformClipboardManager|{}platformClipboardManager[0]
|
||||
final fun <get-platformClipboardManager>(): androidx.compose.ui.platform/ClipboardManager // androidx.compose.ui.platform/platformClipboardManager.<get-platformClipboardManager>|<get-platformClipboardManager>(){}[0]
|
||||
final val androidx.compose.ui.platform/safeContent // androidx.compose.ui.platform/safeContent|@androidx.compose.ui.platform.PlatformWindowInsets{}safeContent[0]
|
||||
final fun (androidx.compose.ui.platform/PlatformWindowInsets).<get-safeContent>(): androidx.compose.ui.platform/PlatformInsets // androidx.compose.ui.platform/safeContent.<get-safeContent>|<get-safeContent>@androidx.compose.ui.platform.PlatformWindowInsets(){}[0]
|
||||
final val androidx.compose.ui.platform/safeDrawing // androidx.compose.ui.platform/safeDrawing|@androidx.compose.ui.platform.PlatformWindowInsets{}safeDrawing[0]
|
||||
@@ -9424,22 +9361,6 @@ final val com.compose.sdl.element/com_compose_sdl_element_ClipModifier$stablepro
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop|#static{}com_compose_sdl_element_ClipNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop|#static{}com_compose_sdl_element_GraphicsLayerModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop|#static{}com_compose_sdl_element_GraphicsLayerNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop|#static{}com_compose_sdl_element_MiddleClickModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop|#static{}com_compose_sdl_element_MiddleClickNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop|#static{}com_compose_sdl_element_OnDragModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop|#static{}com_compose_sdl_element_OnDragNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop|#static{}com_compose_sdl_element_OnPressedModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop|#static{}com_compose_sdl_element_OnPressedNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop|#static{}com_compose_sdl_element_OnTextInputModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop|#static{}com_compose_sdl_element_OnTextInputNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop|#static{}com_compose_sdl_element_PressableModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop|#static{}com_compose_sdl_element_PressableNode$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop|#static{}com_compose_sdl_element_SecondaryClickModifier$stableprop[0]
|
||||
final val com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop|#static{}com_compose_sdl_element_SecondaryClickNode$stableprop[0]
|
||||
final val com.compose.sdl.graphics/a8 // com.compose.sdl.graphics/a8|@androidx.compose.ui.graphics.Color{}a8[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).<get-a8>(): kotlin/Int // com.compose.sdl.graphics/a8.<get-a8>|<get-a8>@androidx.compose.ui.graphics.Color(){}[0]
|
||||
final val com.compose.sdl.graphics/b8 // com.compose.sdl.graphics/b8|@androidx.compose.ui.graphics.Color{}b8[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).<get-b8>(): kotlin/Int // com.compose.sdl.graphics/b8.<get-b8>|<get-b8>@androidx.compose.ui.graphics.Color(){}[0]
|
||||
final val com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop|#static{}com_compose_sdl_graphics_PathCommand_Close$stableprop[0]
|
||||
final val com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop|#static{}com_compose_sdl_graphics_PathCommand_CubicTo$stableprop[0]
|
||||
final val com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop|#static{}com_compose_sdl_graphics_PathCommand_LineTo$stableprop[0]
|
||||
@@ -9450,8 +9371,6 @@ final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectImageBitmap$s
|
||||
final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop|#static{}com_compose_sdl_graphics_ProjectPaint$stableprop[0]
|
||||
final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop|#static{}com_compose_sdl_graphics_ProjectPath$stableprop[0]
|
||||
final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop|#static{}com_compose_sdl_graphics_ProjectPathIterator$stableprop[0]
|
||||
final val com.compose.sdl.graphics/g8 // com.compose.sdl.graphics/g8|@androidx.compose.ui.graphics.Color{}g8[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).<get-g8>(): kotlin/Int // com.compose.sdl.graphics/g8.<get-g8>|<get-g8>@androidx.compose.ui.graphics.Color(){}[0]
|
||||
final val com.compose.sdl.graphics/gradientCenter // com.compose.sdl.graphics/gradientCenter|@androidx.compose.ui.graphics.RadialGradient{}gradientCenter[0]
|
||||
final fun (androidx.compose.ui.graphics/RadialGradient).<get-gradientCenter>(): androidx.compose.ui.geometry/Offset // com.compose.sdl.graphics/gradientCenter.<get-gradientCenter>|<get-gradientCenter>@androidx.compose.ui.graphics.RadialGradient(){}[0]
|
||||
final val com.compose.sdl.graphics/gradientCenter // com.compose.sdl.graphics/gradientCenter|@androidx.compose.ui.graphics.SweepGradient{}gradientCenter[0]
|
||||
@@ -9478,8 +9397,6 @@ final val com.compose.sdl.graphics/gradientTileMode // com.compose.sdl.graphics/
|
||||
final fun (androidx.compose.ui.graphics/LinearGradient).<get-gradientTileMode>(): androidx.compose.ui.graphics/TileMode // com.compose.sdl.graphics/gradientTileMode.<get-gradientTileMode>|<get-gradientTileMode>@androidx.compose.ui.graphics.LinearGradient(){}[0]
|
||||
final val com.compose.sdl.graphics/gradientTileMode // com.compose.sdl.graphics/gradientTileMode|@androidx.compose.ui.graphics.RadialGradient{}gradientTileMode[0]
|
||||
final fun (androidx.compose.ui.graphics/RadialGradient).<get-gradientTileMode>(): androidx.compose.ui.graphics/TileMode // com.compose.sdl.graphics/gradientTileMode.<get-gradientTileMode>|<get-gradientTileMode>@androidx.compose.ui.graphics.RadialGradient(){}[0]
|
||||
final val com.compose.sdl.graphics/r8 // com.compose.sdl.graphics/r8|@androidx.compose.ui.graphics.Color{}r8[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).<get-r8>(): kotlin/Int // com.compose.sdl.graphics/r8.<get-r8>|<get-r8>@androidx.compose.ui.graphics.Color(){}[0]
|
||||
final val com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop // com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop|#static{}com_compose_sdl_icons_IconFont$stableprop[0]
|
||||
final val com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop // com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop|#static{}com_compose_sdl_input_LegacyPointerEvent$stableprop[0]
|
||||
final val com.compose.sdl.layout/intOffset // com.compose.sdl.layout/intOffset|@androidx.compose.ui.layout.LayoutCoordinates{}intOffset[0]
|
||||
@@ -9512,12 +9429,14 @@ final val com.compose.sdl.window/com_compose_sdl_window_PopupHostState$stablepro
|
||||
final val com.compose.sdl/LocalComposeNativeWindow // com.compose.sdl/LocalComposeNativeWindow|{}LocalComposeNativeWindow[0]
|
||||
final fun <get-LocalComposeNativeWindow>(): androidx.compose.runtime/ProvidableCompositionLocal<com.compose.sdl/ComposeNativeWindow> // com.compose.sdl/LocalComposeNativeWindow.<get-LocalComposeNativeWindow>|<get-LocalComposeNativeWindow>(){}[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent$stableprop // com.compose.sdl/com_compose_sdl_AppEvent$stableprop|#static{}com_compose_sdl_AppEvent$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop|#static{}com_compose_sdl_AppEvent_Drop$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop|#static{}com_compose_sdl_AppEvent_Key$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop|#static{}com_compose_sdl_AppEvent_MouseWheel$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop|#static{}com_compose_sdl_AppEvent_Pointer$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop|#static{}com_compose_sdl_AppEvent_Quit$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop|#static{}com_compose_sdl_AppEvent_RedrawNeeded$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop|#static{}com_compose_sdl_AppEvent_TextInput$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop|#static{}com_compose_sdl_AppEvent_WindowActivation$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop|#static{}com_compose_sdl_AppEvent_WindowClose$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop|#static{}com_compose_sdl_AppEvent_WindowResized$stableprop[0]
|
||||
final val com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop // com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop|#static{}com_compose_sdl_ComposeNativeWindow$stableprop[0]
|
||||
@@ -9655,6 +9574,8 @@ final var androidx.compose.ui/isDialogAnimationEnabled // androidx.compose.ui/is
|
||||
final var androidx.compose.ui/useLegacyRenderNodeLayers // androidx.compose.ui/useLegacyRenderNodeLayers|@androidx.compose.ui.ComposeUiFlags{}useLegacyRenderNodeLayers[0]
|
||||
final fun (androidx.compose.ui/ComposeUiFlags).<get-useLegacyRenderNodeLayers>(): kotlin/Boolean // androidx.compose.ui/useLegacyRenderNodeLayers.<get-useLegacyRenderNodeLayers>|<get-useLegacyRenderNodeLayers>@androidx.compose.ui.ComposeUiFlags(){}[0]
|
||||
final fun (androidx.compose.ui/ComposeUiFlags).<set-useLegacyRenderNodeLayers>(kotlin/Boolean) // androidx.compose.ui/useLegacyRenderNodeLayers.<set-useLegacyRenderNodeLayers>|<set-useLegacyRenderNodeLayers>@androidx.compose.ui.ComposeUiFlags(kotlin.Boolean){}[0]
|
||||
final var com.compose.sdl.graphics/encodedImageDecoder // com.compose.sdl.graphics/encodedImageDecoder|{}encodedImageDecoder[0]
|
||||
final fun <get-encodedImageDecoder>(): com.compose.sdl.graphics/EncodedImageDecoder? // com.compose.sdl.graphics/encodedImageDecoder.<get-encodedImageDecoder>|<get-encodedImageDecoder>(){}[0]
|
||||
final var com.compose.sdl.res/currentImageLoader // com.compose.sdl.res/currentImageLoader|{}currentImageLoader[0]
|
||||
final fun <get-currentImageLoader>(): com.compose.sdl.res/ImageLoader // com.compose.sdl.res/currentImageLoader.<get-currentImageLoader>|<get-currentImageLoader>(){}[0]
|
||||
final fun <set-currentImageLoader>(com.compose.sdl.res/ImageLoader) // com.compose.sdl.res/currentImageLoader.<set-currentImageLoader>|<set-currentImageLoader>(com.compose.sdl.res.ImageLoader){}[0]
|
||||
@@ -9703,9 +9624,6 @@ final fun (androidx.compose.ui.graphics/Canvas).androidx.compose.ui.graphics/sca
|
||||
final fun (androidx.compose.ui.graphics/Color).androidx.compose.ui.graphics/compositeOver(androidx.compose.ui.graphics/Color): androidx.compose.ui.graphics/Color // androidx.compose.ui.graphics/compositeOver|compositeOver@androidx.compose.ui.graphics.Color(androidx.compose.ui.graphics.Color){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).androidx.compose.ui.graphics/luminance(): kotlin/Float // androidx.compose.ui.graphics/luminance|luminance@androidx.compose.ui.graphics.Color(){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).androidx.compose.ui.graphics/toArgb(): kotlin/Int // androidx.compose.ui.graphics/toArgb|toArgb@androidx.compose.ui.graphics.Color(){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).com.compose.sdl.graphics/blend(androidx.compose.ui.graphics/Color, kotlin/Float): androidx.compose.ui.graphics/Color // com.compose.sdl.graphics/blend|blend@androidx.compose.ui.graphics.Color(androidx.compose.ui.graphics.Color;kotlin.Float){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).com.compose.sdl.graphics/darken(kotlin/Float): androidx.compose.ui.graphics/Color // com.compose.sdl.graphics/darken|darken@androidx.compose.ui.graphics.Color(kotlin.Float){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Color).com.compose.sdl.graphics/lighten(kotlin/Float): androidx.compose.ui.graphics/Color // com.compose.sdl.graphics/lighten|lighten@androidx.compose.ui.graphics.Color(kotlin.Float){}[0]
|
||||
final fun (androidx.compose.ui.graphics/ImageBitmap).androidx.compose.ui.graphics/toPixelMap(kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/IntArray = ..., kotlin/Int = ..., kotlin/Int = ...): androidx.compose.ui.graphics/PixelMap // androidx.compose.ui.graphics/toPixelMap|toPixelMap@androidx.compose.ui.graphics.ImageBitmap(kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.IntArray;kotlin.Int;kotlin.Int){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Matrix).androidx.compose.ui.graphics/isIdentity(): kotlin/Boolean // androidx.compose.ui.graphics/isIdentity|isIdentity@androidx.compose.ui.graphics.Matrix(){}[0]
|
||||
final fun (androidx.compose.ui.graphics/Path).androidx.compose.ui.graphics/addOutline(androidx.compose.ui.graphics/Outline) // androidx.compose.ui.graphics/addOutline|addOutline@androidx.compose.ui.graphics.Path(androidx.compose.ui.graphics.Outline){}[0]
|
||||
@@ -9908,12 +9826,6 @@ final fun (androidx.compose.ui/Modifier).androidx.compose.ui/preferredFrameRate(
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.ui/preferredFrameRate(kotlin/Float): androidx.compose.ui/Modifier // androidx.compose.ui/preferredFrameRate|preferredFrameRate@androidx.compose.ui.Modifier(kotlin.Float){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.ui/sensitiveContent(kotlin/Boolean = ...): androidx.compose.ui/Modifier // androidx.compose.ui/sensitiveContent|sensitiveContent@androidx.compose.ui.Modifier(kotlin.Boolean){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).androidx.compose.ui/zIndex(kotlin/Float): androidx.compose.ui/Modifier // androidx.compose.ui/zIndex|zIndex@androidx.compose.ui.Modifier(kotlin.Float){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onDrag(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> = ..., kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> = ..., kotlin/Function0<kotlin/Unit> = ...): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onDrag|onDrag@androidx.compose.ui.Modifier(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function0<kotlin.Unit>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onMiddleClick(kotlin/Function0<kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onMiddleClick|onMiddleClick@androidx.compose.ui.Modifier(kotlin.Function0<kotlin.Unit>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onPressed(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onPressed|onPressed@androidx.compose.ui.Modifier(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onSecondaryClick(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onSecondaryClick|onSecondaryClick@androidx.compose.ui.Modifier(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onTextInput(kotlin/Function1<kotlin/String, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onTextInput|onTextInput@androidx.compose.ui.Modifier(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
|
||||
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/pressable(kotlin/Function1<kotlin/Boolean, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/pressable|pressable@androidx.compose.ui.Modifier(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
|
||||
final fun (kotlin.collections/List<androidx.compose.ui.graphics.vector/PathNode>).androidx.compose.ui.graphics.vector/toPath(androidx.compose.ui.graphics/Path = ...): androidx.compose.ui.graphics/Path // androidx.compose.ui.graphics.vector/toPath|toPath@kotlin.collections.List<androidx.compose.ui.graphics.vector.PathNode>(androidx.compose.ui.graphics.Path){}[0]
|
||||
final fun (kotlin/ByteArray).androidx.compose.ui.graphics/decodeToImageBitmap(): androidx.compose.ui.graphics/ImageBitmap // androidx.compose.ui.graphics/decodeToImageBitmap|decodeToImageBitmap@kotlin.ByteArray(){}[0]
|
||||
final fun (kotlin/CharSequence).androidx.compose.ui.text/substring(androidx.compose.ui.text/TextRange): kotlin/String // androidx.compose.ui.text/substring|substring@kotlin.CharSequence(androidx.compose.ui.text.TextRange){}[0]
|
||||
@@ -10168,6 +10080,7 @@ final fun androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElement
|
||||
final fun androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop_getter(): kotlin/Int // androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop_getter|androidx_compose_ui_platform_ValueElementSequence$stableprop_getter(){}[0]
|
||||
final fun androidx.compose.ui.platform/findComposeDefaultViewModelStoreOwner(androidx.compose.runtime/Composer?, kotlin/Int): androidx.lifecycle/ViewModelStoreOwner? // androidx.compose.ui.platform/findComposeDefaultViewModelStoreOwner|findComposeDefaultViewModelStoreOwner(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun androidx.compose.ui.platform/findDefaultNavigationEventDispatcherOwner(androidx.compose.runtime/Composer?, kotlin/Int): androidx.navigationevent/NavigationEventDispatcherOwner? // androidx.compose.ui.platform/findDefaultNavigationEventDispatcherOwner|findDefaultNavigationEventDispatcherOwner(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
|
||||
final fun androidx.compose.ui.platform/platformClipboard(): androidx.compose.ui.platform/Clipboard // androidx.compose.ui.platform/platformClipboard|platformClipboard(){}[0]
|
||||
final fun androidx.compose.ui.scene/androidx_compose_ui_scene_ComposeScenePointer$stableprop_getter(): kotlin/Int // androidx.compose.ui.scene/androidx_compose_ui_scene_ComposeScenePointer$stableprop_getter|androidx_compose_ui_scene_ComposeScenePointer$stableprop_getter(){}[0]
|
||||
final fun androidx.compose.ui.semantics/androidx_compose_ui_semantics_AccessibilityAction$stableprop_getter(): kotlin/Int // androidx.compose.ui.semantics/androidx_compose_ui_semantics_AccessibilityAction$stableprop_getter|androidx_compose_ui_semantics_AccessibilityAction$stableprop_getter(){}[0]
|
||||
final fun androidx.compose.ui.semantics/androidx_compose_ui_semantics_CollectionInfo$stableprop_getter(): kotlin/Int // androidx.compose.ui.semantics/androidx_compose_ui_semantics_CollectionInfo$stableprop_getter|androidx_compose_ui_semantics_CollectionInfo$stableprop_getter(){}[0]
|
||||
@@ -10303,18 +10216,6 @@ final fun com.compose.sdl.element/com_compose_sdl_element_ClipModifier$stablepro
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop_getter|com_compose_sdl_element_ClipNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop_getter|com_compose_sdl_element_GraphicsLayerModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop_getter|com_compose_sdl_element_GraphicsLayerNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop_getter|com_compose_sdl_element_MiddleClickModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop_getter|com_compose_sdl_element_MiddleClickNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop_getter|com_compose_sdl_element_OnDragModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop_getter|com_compose_sdl_element_OnDragNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop_getter|com_compose_sdl_element_OnPressedModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop_getter|com_compose_sdl_element_OnPressedNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop_getter|com_compose_sdl_element_OnTextInputModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop_getter|com_compose_sdl_element_OnTextInputNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop_getter|com_compose_sdl_element_PressableModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop_getter|com_compose_sdl_element_PressableNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop_getter|com_compose_sdl_element_SecondaryClickModifier$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop_getter|com_compose_sdl_element_SecondaryClickNode$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop_getter|com_compose_sdl_graphics_PathCommand_Close$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop_getter|com_compose_sdl_graphics_PathCommand_CubicTo$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop_getter|com_compose_sdl_graphics_PathCommand_LineTo$stableprop_getter(){}[0]
|
||||
@@ -10325,6 +10226,7 @@ final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectImageBitmap$s
|
||||
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop_getter|com_compose_sdl_graphics_ProjectPaint$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop_getter|com_compose_sdl_graphics_ProjectPath$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop_getter|com_compose_sdl_graphics_ProjectPathIterator$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.graphics/decodeEncodedImageBitmap(kotlin/ByteArray): androidx.compose.ui.graphics/ImageBitmap? // com.compose.sdl.graphics/decodeEncodedImageBitmap|decodeEncodedImageBitmap(kotlin.ByteArray){}[0]
|
||||
final fun com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop_getter(): kotlin/Int // com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop_getter|com_compose_sdl_icons_IconFont$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop_getter(): kotlin/Int // com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop_getter|com_compose_sdl_input_LegacyPointerEvent$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl.node/com_compose_sdl_node_ComposeRootHost$stableprop_getter(): kotlin/Int // com.compose.sdl.node/com_compose_sdl_node_ComposeRootHost$stableprop_getter|com_compose_sdl_node_ComposeRootHost$stableprop_getter(){}[0]
|
||||
@@ -10358,12 +10260,14 @@ final fun com.compose.sdl.window/com_compose_sdl_window_PopupHostState$stablepro
|
||||
final fun com.compose.sdl.window/createPopupHostState(): com.compose.sdl.window/PopupHostState // com.compose.sdl.window/createPopupHostState|createPopupHostState(){}[0]
|
||||
final fun com.compose.sdl/appDataDir(kotlin/String, kotlin/String): kotlin/String? // com.compose.sdl/appDataDir|appDataDir(kotlin.String;kotlin.String){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent$stableprop_getter|com_compose_sdl_AppEvent$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop_getter|com_compose_sdl_AppEvent_Drop$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop_getter|com_compose_sdl_AppEvent_Key$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop_getter|com_compose_sdl_AppEvent_MouseWheel$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop_getter|com_compose_sdl_AppEvent_Pointer$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop_getter|com_compose_sdl_AppEvent_Quit$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop_getter|com_compose_sdl_AppEvent_RedrawNeeded$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop_getter|com_compose_sdl_AppEvent_TextInput$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop_getter|com_compose_sdl_AppEvent_WindowActivation$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop_getter|com_compose_sdl_AppEvent_WindowClose$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop_getter|com_compose_sdl_AppEvent_WindowResized$stableprop_getter(){}[0]
|
||||
final fun com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop_getter|com_compose_sdl_ComposeNativeWindow$stableprop_getter(){}[0]
|
||||
|
||||
@@ -32,7 +32,7 @@ plugins {
|
||||
val useSdl3Everywhere = (findProperty("renderer") as? String) == "sdl3"
|
||||
|
||||
// All targets pull headers from the in-repo static build tree at <repo>/libs,
|
||||
// populated by scripts/build-sdl/build-all.sh (or the per-library scripts).
|
||||
// populated by scripts/build-sdl/build-all.py (optionally one library at a time).
|
||||
// Same paths on macOS / Linux / Windows — the .def files are pathless and
|
||||
// rely on these -I injections. Cross-target cinterop indexing under
|
||||
// kotlin.mpp.enableCInteropCommonization is fine: clang silently ignores -I
|
||||
|
||||
@@ -6,7 +6,7 @@ headerFilter = SDL3/**
|
||||
# archive location comes from :ui build.gradle.kts (-libraryPath) because
|
||||
# .def files can't reference $rootDir. The linker options below list the
|
||||
# system frameworks / libs SDL3's static build depends on (see the Libs
|
||||
# line in libs/SDL3/lib/pkgconfig/sdl3.pc after build-sdl3.sh runs) —
|
||||
# line in libs/SDL3/lib/pkgconfig/sdl3.pc after build-all.py runs) —
|
||||
# cinterop propagates them through the klib to the final app link.
|
||||
|
||||
staticLibraries = libSDL3.a
|
||||
|
||||
@@ -5,6 +5,6 @@ depends = sdl3
|
||||
# libSDL3_image.a + its vendored codec archives (PNG/JPG built-in via stb,
|
||||
# WEBP, SVG built-in) are all baked into the cinterop klib. See sdl3.def —
|
||||
# the static archive location is injected via :ui build.gradle.kts
|
||||
# (-libraryPath). build-sdl3-image.sh normalises libzlibstatic.a → libz.a
|
||||
# on Windows so the same filename works everywhere.
|
||||
# (-libraryPath). build-all.py's sdl3-image step normalises libzlibstatic.a
|
||||
# → libz.a on Windows so the same filename works everywhere.
|
||||
staticLibraries = libSDL3_image.a libpng16.a libz.a libwebp.a libwebpdemux.a libwebpmux.a libsharpyuv.a
|
||||
|
||||
+55
-7
@@ -13,6 +13,31 @@ plugins {
|
||||
// Skip mingwX64 on non-Windows hosts; see root build.gradle.kts.
|
||||
val vHostSupportsMingw = rootProject.extra["vHostSupportsMingw"] as Boolean
|
||||
|
||||
// JVM parity target's Compose version — the dev build matching the pinned
|
||||
// COMPOSE_CORE_REF (see scripts/compose-fork/compose.properties). material3
|
||||
// rides its OWN release train: same +dev build number, different base
|
||||
// version. Gradle orders "+dev" qualifiers BELOW the plain version, so
|
||||
// currentOs's beta01 would win conflict resolution — force the core-repo
|
||||
// groups on every jvm configuration. Umbrella-repo groups (desktop,
|
||||
// components) are NOT forced: their dev numbering differs.
|
||||
val vComposeJvmVersion = "1.12.0-beta01+dev4324"
|
||||
val vComposeM3JvmVersion = "1.12.0-alpha03+dev4324"
|
||||
val vComposeJvmForced = mapOf(
|
||||
"org.jetbrains.compose.runtime" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.ui" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.foundation" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.animation" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.material" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.material3" to vComposeM3JvmVersion,
|
||||
)
|
||||
configurations.configureEach {
|
||||
if (name.startsWith("jvm")) {
|
||||
resolutionStrategy.eachDependency {
|
||||
vComposeJvmForced[requested.group]?.let { useVersion(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
|
||||
@@ -72,30 +97,36 @@ kotlin {
|
||||
// substitute it for the vendored :components-resources below
|
||||
// (the Maven artifact ships no mingwX64/linux klibs).
|
||||
implementation(compose.components.resources)
|
||||
// Common API on both stacks (its native/jvm actuals pick the
|
||||
// right rendering pipeline) — usable from shared screens.
|
||||
implementation(project(":material-symbols"))
|
||||
}
|
||||
}
|
||||
nativeMain {
|
||||
dependencies {
|
||||
implementation(project(":window"))
|
||||
implementation(project(":material3"))
|
||||
implementation(project(":material-symbols"))
|
||||
implementation(project(":navigation3-ui"))
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.11.0")
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.compose.runtime:runtime:1.12.0-alpha03")
|
||||
implementation("org.jetbrains.compose.foundation:foundation:1.12.0-alpha03")
|
||||
implementation("org.jetbrains.compose.animation:animation:1.12.0-alpha03")
|
||||
implementation("org.jetbrains.compose.material3:material3:1.12.0-alpha03")
|
||||
implementation("org.jetbrains.compose.ui:ui:1.12.0-alpha03")
|
||||
// The +dev build matching scripts/compose-fork's pinned
|
||||
// COMPOSE_CORE_REF — byte-exact parity with the vendored
|
||||
// sources, and (unlike the published beta01) its desktop
|
||||
// loadTypeface applies Font.variationSettings, so the
|
||||
// Material Symbols variable-font axes work on JVM.
|
||||
implementation("org.jetbrains.compose.runtime:runtime:$vComposeJvmVersion")
|
||||
implementation("org.jetbrains.compose.foundation:foundation:$vComposeJvmVersion")
|
||||
implementation("org.jetbrains.compose.animation:animation:$vComposeJvmVersion")
|
||||
implementation("org.jetbrains.compose.material3:material3:$vComposeM3JvmVersion")
|
||||
implementation("org.jetbrains.compose.ui:ui:$vComposeJvmVersion")
|
||||
|
||||
implementation("androidx.navigation3:navigation3-runtime:1.2.0-alpha05")
|
||||
implementation("org.jetbrains.androidx.navigation3:navigation3-ui:1.2.0-alpha02")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.11.0")
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation("org.jetbrains.compose.material:material-icons-extended:1.7.3")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,3 +269,20 @@ for (variant in variants) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================
|
||||
// MARK: Stage Material Symbols fonts onto the JVM classpath
|
||||
// ==================
|
||||
// The :material-symbols JVM actual loads each style's font from the classpath
|
||||
// at font/<Style>.ttf — the JVM analog of the data.kres font/ entries above.
|
||||
// Same style detection: only the fonts the sources actually reference.
|
||||
tasks.named<ProcessResources>("jvmProcessResources") {
|
||||
val vSymbolsProject = rootProject.project(":material-symbols")
|
||||
for (vStyle in vUsedStyles) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val vFontFile = vSymbolsProject.extra["iconFontFile$vStyle"] as Provider<RegularFile>
|
||||
val vDownloadTask = vSymbolsProject.extra["iconFontDownloadTask$vStyle"] as TaskProvider<*>
|
||||
from(vFontFile) { into("font") }
|
||||
dependsOn(vDownloadTask)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ val CoreScreens: List<DemoScreen> = listOf(
|
||||
val Material3Screens: List<DemoScreen> = listOf(
|
||||
// Ordered by family: typography, buttons, inputs, containers, navigation, overlays.
|
||||
DemoScreen("Text") { TextScreen() },
|
||||
DemoScreen("Icons") { IconsScreen() },
|
||||
DemoScreen("Buttons") { ButtonsScreen() },
|
||||
DemoScreen("ButtonsExtra") { M3ButtonsExtraScreen() },
|
||||
DemoScreen("Fab") { FabScreen() },
|
||||
@@ -86,10 +87,17 @@ val Navigation3Screens: List<DemoScreen> = listOf(
|
||||
DemoScreen("Navigation3") { Navigation3Screen() },
|
||||
)
|
||||
|
||||
// Screens that aren't a Compose-artifact showcase: project utility modules
|
||||
// (Material Symbols engine, ...).
|
||||
val OthersScreens: List<DemoScreen> = listOf(
|
||||
DemoScreen("MaterialSymbols") { MaterialSymbolsScreen() },
|
||||
)
|
||||
|
||||
val commonCategories: List<DemoCategory> = listOf(
|
||||
DemoCategory("core", "Core", CoreScreens),
|
||||
DemoCategory("material3", "Material3", Material3Screens),
|
||||
DemoCategory("navigation3", "Navigation3", Navigation3Screens),
|
||||
DemoCategory("others", "Others", OthersScreens),
|
||||
)
|
||||
|
||||
/* Platform extras that fill the dropdown dynamically: screens that can't be
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.ui.platform.ClipEntry
|
||||
|
||||
// ==================
|
||||
// MARK: DemoClipboard — portable ClipEntry construction / reading
|
||||
// ==================
|
||||
|
||||
/* Upstream Compose has no COMMON way to build or read a ClipEntry — every
|
||||
platform actual differs. This port mirrors upstream's macOS actual
|
||||
(ClipEntry.withPlainText / getPlainText / getImage), while upstream JVM
|
||||
desktop wraps an AWT Transferable and exposes nothing text-typed. Shared
|
||||
screens go through these four helpers; each stack maps them 1:1 onto its
|
||||
native shape. */
|
||||
|
||||
/* A ClipEntry carrying plain text, for Clipboard.setClipEntry. */
|
||||
expect fun demoClipEntryOfText(text: String): ClipEntry
|
||||
|
||||
/* A ClipEntry carrying an image from already-PNG-encoded bytes. */
|
||||
expect fun demoClipEntryOfPng(pngBytes: ByteArray): ClipEntry
|
||||
|
||||
/* The entry's plain text, or null when it carries none. */
|
||||
expect fun ClipEntry.demoPlainText(): String?
|
||||
|
||||
/* The entry's image as PNG-encoded bytes, or null when it carries none. */
|
||||
expect fun ClipEntry.demoPngImage(): ByteArray?
|
||||
@@ -5,16 +5,18 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.compose.sdl.icons.MaterialSymbols
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
|
||||
|
||||
// ==================
|
||||
// MARK: DemoIcon — platform-neutral icon token
|
||||
// ==================
|
||||
|
||||
/* A platform-neutral icon reference for the shared demo screens. On native it
|
||||
maps to a Material Symbols codepoint rendered by the project icon-font engine
|
||||
(com.compose.sdl.icons); on a future jvm target it maps to an
|
||||
androidx.compose.material.icons ImageVector. Shared screens reference icons
|
||||
ONLY through this enum, so the exact same code compiles on both stacks. */
|
||||
/* A platform-neutral icon reference for the shared demo screens. Now that
|
||||
:material-symbols exposes its API from commonMain (native draws through the
|
||||
port's IconFont pipeline, JVM through upstream variable-font text), the
|
||||
token resolves to a Material Symbols codepoint on BOTH stacks — the same
|
||||
glyphs render everywhere, which is exactly what the parity build compares. */
|
||||
enum class DemoIcon {
|
||||
Home, Search, Person, Settings, Add, Edit, Favorite, Star, Close, Image,
|
||||
Delete, Share, Check, MoreVert, ContentCopy, KeyboardArrowDown, Bookmark,
|
||||
@@ -22,15 +24,50 @@ enum class DemoIcon {
|
||||
ExpandMore, ExpandLess,
|
||||
}
|
||||
|
||||
/* Renders [icon]. The portable stand-in for material3's Icon(imageVector, …) /
|
||||
the project's MaterialSymbolsOutlined(codepoint, …). Deliberately exposes no
|
||||
variable-font axes (fill / weight / grade / opticalSize) — those have no
|
||||
upstream analog. */
|
||||
/* Renders [icon] via MaterialSymbolsOutlined — the portable stand-in for
|
||||
material3's Icon(imageVector, …). Color.Unspecified tint falls back to
|
||||
material3's LocalContentColor inside MaterialSymbolsOutlined. */
|
||||
@Composable
|
||||
expect fun DemoIcon(
|
||||
fun DemoIcon(
|
||||
icon: DemoIcon,
|
||||
contentDescription: String? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = Color.Unspecified,
|
||||
size: Dp = 24.dp,
|
||||
)
|
||||
) {
|
||||
val codepoint = when (icon) {
|
||||
DemoIcon.Home -> MaterialSymbols.Home
|
||||
DemoIcon.Search -> MaterialSymbols.Search
|
||||
DemoIcon.Person -> MaterialSymbols.Person
|
||||
DemoIcon.Settings -> MaterialSymbols.Settings
|
||||
DemoIcon.Add -> MaterialSymbols.Add
|
||||
DemoIcon.Edit -> MaterialSymbols.Edit
|
||||
DemoIcon.Favorite -> MaterialSymbols.Favorite
|
||||
DemoIcon.Star -> MaterialSymbols.Star
|
||||
DemoIcon.Close -> MaterialSymbols.Close
|
||||
DemoIcon.Image -> MaterialSymbols.Image
|
||||
DemoIcon.Delete -> MaterialSymbols.Delete
|
||||
DemoIcon.Share -> MaterialSymbols.Share
|
||||
DemoIcon.Check -> MaterialSymbols.Check
|
||||
DemoIcon.MoreVert -> MaterialSymbols.MoreVert
|
||||
DemoIcon.ContentCopy -> MaterialSymbols.ContentCopy
|
||||
DemoIcon.KeyboardArrowDown -> MaterialSymbols.KeyboardArrowDown
|
||||
DemoIcon.Bookmark -> MaterialSymbols.Bookmark
|
||||
DemoIcon.Notifications -> MaterialSymbols.Notifications
|
||||
DemoIcon.Menu -> MaterialSymbols.Menu
|
||||
DemoIcon.ArrowBack -> MaterialSymbols.ArrowBack
|
||||
DemoIcon.Save -> MaterialSymbols.Save
|
||||
DemoIcon.Refresh -> MaterialSymbols.Refresh
|
||||
DemoIcon.Download -> MaterialSymbols.Download
|
||||
DemoIcon.Upload -> MaterialSymbols.Upload
|
||||
DemoIcon.ExpandMore -> MaterialSymbols.ExpandMore
|
||||
DemoIcon.ExpandLess -> MaterialSymbols.ExpandLess
|
||||
}
|
||||
MaterialSymbolsOutlined(
|
||||
icon = codepoint,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint,
|
||||
size = size,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,12 +21,11 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.ClipEntry
|
||||
import androidx.compose.ui.platform.Clipboard
|
||||
import androidx.compose.ui.platform.LocalClipboard
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import demo.shim.demoDecodeImage
|
||||
import demo.shim.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.compose.resources.readResourceBytes
|
||||
@@ -43,9 +42,10 @@ private const val kLogoResourcePath = "composeResources/demo.generated.resources
|
||||
// ==================
|
||||
|
||||
/* Round-trips text AND PNG images through the OS clipboard via LocalClipboard
|
||||
(suspend, ClipEntry-typed) over SDL3's SDL_[GS]etClipboardText and
|
||||
SDL_[GS]etClipboardData("image/png"). Text and images share one Compose
|
||||
ClipEntry: getPlainText() vs getImage() surface whichever is present.
|
||||
(suspend, ClipEntry-typed) — on native over SDL3's SDL_[GS]etClipboardText /
|
||||
SDL_[GS]etClipboardData("image/png"), on JVM over the AWT clipboard.
|
||||
ClipEntry construction/reading has NO common upstream API (each platform
|
||||
actual differs), so this screen goes through demo.shim.DemoClipboard.
|
||||
Non-composable callers reach it by capturing LocalClipboard.current +
|
||||
rememberCoroutineScope() in composition and passing both into the callback. */
|
||||
@Composable
|
||||
@@ -68,8 +68,9 @@ internal fun ClipboardScreen() {
|
||||
)
|
||||
|
||||
// ============
|
||||
// Text copy — ClipEntry.withPlainText / getPlainText.
|
||||
Section("Copy text", "scope.launch { clipboard.setClipEntry(ClipEntry.withPlainText(...)) }") {
|
||||
// Text copy — demoClipEntryOfText (ClipEntry.withPlainText on native,
|
||||
// AWT StringSelection on JVM).
|
||||
Section("Copy text", "scope.launch { clipboard.setClipEntry(demoClipEntryOfText(...)) }") {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
OutlinedTextField(
|
||||
value = draft,
|
||||
@@ -78,7 +79,7 @@ internal fun ClipboardScreen() {
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
Button(onClick = {
|
||||
scope.launch { clipboard.setClipEntry(ClipEntry.withPlainText(draft)) }
|
||||
scope.launch { clipboard.setClipEntry(demoClipEntryOfText(draft)) }
|
||||
note = "Copied ${draft.length} char(s) to the system clipboard."
|
||||
}) {
|
||||
Text("Copy text", color = MaterialTheme.colorScheme.onPrimary)
|
||||
@@ -92,7 +93,7 @@ internal fun ClipboardScreen() {
|
||||
// image-aware app (Preview / Paint / a browser tab) to verify.
|
||||
Section(
|
||||
"Copy image",
|
||||
"readResourceBytes(\"drawable/compose_logo.png\") → ClipEntry.withImage(pngBytes). " +
|
||||
"readResourceBytes(\"drawable/compose_logo.png\") → demoClipEntryOfPng(pngBytes). " +
|
||||
"Paste into another app to verify.",
|
||||
) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
@@ -115,7 +116,7 @@ internal fun ClipboardScreen() {
|
||||
scope.launch {
|
||||
val vBytes = runCatching { readResourceBytes(kLogoResourcePath) }.getOrNull()
|
||||
if (vBytes != null) {
|
||||
clipboard.setClipEntry(ClipEntry.withImage(vBytes))
|
||||
clipboard.setClipEntry(demoClipEntryOfPng(vBytes))
|
||||
note = "Copied ${vBytes.size} byte(s) of PNG to the system clipboard."
|
||||
} else {
|
||||
note = "Failed to load the source image."
|
||||
@@ -130,15 +131,15 @@ internal fun ClipboardScreen() {
|
||||
|
||||
// ============
|
||||
// Paste — surfaces whatever's on the clipboard: text OR image.
|
||||
Section("Paste", "clipboard.getClipEntry()?.getPlainText() / .getImage()") {
|
||||
Section("Paste", "clipboard.getClipEntry()?.demoPlainText() / .demoPngImage()") {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Button(onClick = {
|
||||
pastedText = null; pastedImage = null; pastedNote = null
|
||||
scope.launch {
|
||||
val vEntry = clipboard.getClipEntry()
|
||||
val vImage = vEntry?.getImage()
|
||||
val vText = vEntry?.getPlainText()
|
||||
val vImage = vEntry?.demoPngImage()
|
||||
val vText = vEntry?.demoPlainText()
|
||||
when {
|
||||
vImage != null -> {
|
||||
pastedImage = demoDecodeImage(vImage)
|
||||
@@ -212,6 +213,6 @@ internal fun ClipboardScreen() {
|
||||
modern Clipboard is intentionally suspend-only. */
|
||||
private fun copyFromPlainFunction(scope: CoroutineScope, clipboard: Clipboard) {
|
||||
scope.launch {
|
||||
clipboard.setClipEntry(ClipEntry.withPlainText("Set from a plain, non-@Composable function."))
|
||||
clipboard.setClipEntry(demoClipEntryOfText("Set from a plain, non-@Composable function."))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package screens
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.compose.sdl.icons.MaterialSymbols
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsRounded
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsSharp
|
||||
import demo.generated.resources.Res
|
||||
import demo.generated.resources.heart
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
// ==================
|
||||
// MARK: Icons screen — material3 icon APIs
|
||||
// ==================
|
||||
|
||||
/* material3 icon APIs: Icon(painter) over compose resources and IconButton. */
|
||||
@Composable
|
||||
internal fun IconsScreen() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
ScreenTitle(
|
||||
"Icons",
|
||||
"material3 Icon(painter) over compose resources + IconButton.",
|
||||
)
|
||||
|
||||
Section("Painter-based Icon", "Reads from composeResources/drawable/*.xml (Android vector) or *.svg.") {
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Icon(painter = painterResource(Res.drawable.heart), contentDescription = "Heart")
|
||||
Text("painterResource(Res.drawable.heart)", fontSize = 13.sp)
|
||||
}
|
||||
}
|
||||
|
||||
Section("IconButton", "40dp clickable circle. Hover overlay matches Material 1.") {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
IconButton(onClick = {}) {
|
||||
MaterialSymbolsOutlined(MaterialSymbols.Favorite,
|
||||
tint = MaterialTheme.colorScheme.primary, fill = 1f, weight = 600)
|
||||
}
|
||||
IconButton(onClick = {}) {
|
||||
MaterialSymbolsRounded(MaterialSymbols.Share,
|
||||
tint = MaterialTheme.colorScheme.onSurface)
|
||||
}
|
||||
IconButton(onClick = {}) {
|
||||
MaterialSymbolsSharp(MaterialSymbols.MoreVert,
|
||||
tint = MaterialTheme.colorScheme.onSurface)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
-35
@@ -1,11 +1,14 @@
|
||||
package screens
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -14,22 +17,29 @@ import com.compose.sdl.icons.MaterialSymbols
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsRounded
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsSharp
|
||||
import demo.generated.resources.Res
|
||||
import demo.generated.resources.heart
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
// ==================
|
||||
// MARK: Material Symbols screen — variable-font icon engine showcase
|
||||
// ==================
|
||||
|
||||
/* The :material-symbols engine demos: the four variable-font axes (FILL /
|
||||
wght / GRAD / opsz), the animated fill transition, and the three style
|
||||
families. Runs the SAME shared code on native (IconFont over SDL3_ttf-fork
|
||||
/ Skia) and JVM (Skiko direct) — differences between the builds = port
|
||||
bugs. */
|
||||
@Composable
|
||||
internal fun IconsScreen() {
|
||||
internal fun MaterialSymbolsScreen() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
ScreenTitle(
|
||||
"Icons",
|
||||
"MaterialSymbolsOutlined / Rounded / Sharp — drop the dependency, call the composable, font auto-installs.",
|
||||
"Material Symbols",
|
||||
"MaterialSymbolsOutlined / Rounded / Sharp — drop the dependency, call the composable, " +
|
||||
"font auto-installs. Four variable-font axes as direct parameters.",
|
||||
)
|
||||
|
||||
// ============
|
||||
// Variable-font axes — the priority demo. The four axes are direct
|
||||
// parameters on the icon composable, so each row pins everything
|
||||
// except one. Skia honours every axis; SDL3_ttf 3.2 ignores them.
|
||||
// Variable-font axes — each row pins everything except one axis.
|
||||
// Skia, the SDL3_ttf fork (TTF_SetFontAxisValue) and the JVM build
|
||||
// (Skiko Typeface.makeClone) all honour the axes.
|
||||
|
||||
Section(
|
||||
"Weight (wght 100..700)",
|
||||
@@ -75,6 +85,24 @@ internal fun IconsScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
// ============
|
||||
// Animated fill — the modern M3 selected-state icon transition:
|
||||
// the FILL axis (and tint) animate on click instead of swapping
|
||||
// between two static icons.
|
||||
Section(
|
||||
"Animated fill",
|
||||
"Click an icon: animateFloatAsState drives the FILL axis (plus tint) — " +
|
||||
"the Material 3 selected-state transition, morphing the glyph instead of swapping it.",
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(20.dp)) {
|
||||
AnimatedFillIcon(MaterialSymbols.Favorite, "Favorite")
|
||||
AnimatedFillIcon(MaterialSymbols.Star, "Star")
|
||||
AnimatedFillIcon(MaterialSymbols.Bookmark, "Bookmark")
|
||||
AnimatedFillIcon(MaterialSymbols.Notifications, "Notifications")
|
||||
}
|
||||
}
|
||||
|
||||
Section(
|
||||
"Grade (GRAD -25..200)",
|
||||
"Fine weight nudge without changing the glyph footprint. Negative = thinner, positive = heavier.",
|
||||
@@ -157,15 +185,7 @@ internal fun IconsScreen() {
|
||||
}
|
||||
|
||||
// ============
|
||||
// Style families + drawable icons.
|
||||
|
||||
Section("Painter-based Icon", "Reads from composeResources/drawable/*.xml (Android vector) or *.svg.") {
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Icon(painter = painterResource(Res.drawable.heart), contentDescription = "Heart")
|
||||
Text("painterResource(Res.drawable.heart)", fontSize = 13.sp)
|
||||
}
|
||||
}
|
||||
// Style families.
|
||||
|
||||
val vNames = listOf(
|
||||
"Home" to MaterialSymbols.Home,
|
||||
@@ -246,22 +266,31 @@ internal fun IconsScreen() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section("IconButton", "40dp clickable circle. Hover overlay matches Material 1.") {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
IconButton(onClick = {}) {
|
||||
MaterialSymbolsOutlined(MaterialSymbols.Favorite,
|
||||
tint = MaterialTheme.colorScheme.primary, fill = 1f, weight = 600)
|
||||
}
|
||||
IconButton(onClick = {}) {
|
||||
MaterialSymbolsRounded(MaterialSymbols.Share,
|
||||
tint = MaterialTheme.colorScheme.onSurface)
|
||||
}
|
||||
IconButton(onClick = {}) {
|
||||
MaterialSymbolsSharp(MaterialSymbols.MoreVert,
|
||||
tint = MaterialTheme.colorScheme.onSurface)
|
||||
}
|
||||
}
|
||||
/* One click-toggled icon: FILL 0↔1 and tint animate together — swap-free
|
||||
selected-state feedback, the Material 3 expressive icon pattern. */
|
||||
@Composable
|
||||
private fun AnimatedFillIcon(codepoint: Int, label: String) {
|
||||
var vSelected by remember { mutableStateOf(false) }
|
||||
val vFill by animateFloatAsState(
|
||||
targetValue = if (vSelected) 1f else 0f,
|
||||
animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing),
|
||||
label = "fill",
|
||||
)
|
||||
val vTint by animateColorAsState(
|
||||
targetValue = if (vSelected) MaterialTheme.colorScheme.primary
|
||||
else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
animationSpec = tween(durationMillis = 300),
|
||||
label = "tint",
|
||||
)
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)) {
|
||||
IconButton(onClick = { vSelected = !vSelected }) {
|
||||
MaterialSymbolsOutlined(codepoint, size = 28.dp, tint = vTint, fill = vFill)
|
||||
}
|
||||
Text(label, fontSize = 11.sp,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@file:OptIn(ExperimentalComposeUiApi::class)
|
||||
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.platform.ClipEntry
|
||||
import androidx.compose.ui.platform.asAwtTransferable
|
||||
import java.awt.datatransfer.DataFlavor
|
||||
import java.awt.datatransfer.StringSelection
|
||||
import java.awt.datatransfer.Transferable
|
||||
import java.awt.datatransfer.UnsupportedFlavorException
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
/* JVM (Compose Desktop) actuals: upstream's desktop ClipEntry wraps an AWT
|
||||
Transferable — text rides DataFlavor.stringFlavor, images ride
|
||||
DataFlavor.imageFlavor as a decoded java.awt.Image (PNG bytes are
|
||||
en/decoded with ImageIO at the edges). */
|
||||
|
||||
actual fun demoClipEntryOfText(text: String): ClipEntry = ClipEntry(StringSelection(text))
|
||||
|
||||
actual fun demoClipEntryOfPng(pngBytes: ByteArray): ClipEntry = ClipEntry(PngTransferable(pngBytes))
|
||||
|
||||
actual fun ClipEntry.demoPlainText(): String? {
|
||||
val transferable = asAwtTransferable ?: return null
|
||||
if (!transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) return null
|
||||
return runCatching { transferable.getTransferData(DataFlavor.stringFlavor) as? String }.getOrNull()
|
||||
}
|
||||
|
||||
actual fun ClipEntry.demoPngImage(): ByteArray? {
|
||||
val transferable = asAwtTransferable ?: return null
|
||||
if (!transferable.isDataFlavorSupported(DataFlavor.imageFlavor)) return null
|
||||
val image = runCatching { transferable.getTransferData(DataFlavor.imageFlavor) as? java.awt.Image }
|
||||
.getOrNull() ?: return null
|
||||
val buffered = image as? BufferedImage ?: BufferedImage(
|
||||
image.getWidth(null).coerceAtLeast(1),
|
||||
image.getHeight(null).coerceAtLeast(1),
|
||||
BufferedImage.TYPE_INT_ARGB,
|
||||
).also { it.createGraphics().apply { drawImage(image, 0, 0, null); dispose() } }
|
||||
val out = ByteArrayOutputStream()
|
||||
val ok = runCatching { ImageIO.write(buffered, "png", out) }.getOrDefault(false)
|
||||
return if (ok) out.toByteArray() else null
|
||||
}
|
||||
|
||||
/* Serves PNG bytes as DataFlavor.imageFlavor — AWT's canonical image exchange
|
||||
format, so pasting into other desktop apps works. */
|
||||
private class PngTransferable(private val pngBytes: ByteArray) : Transferable {
|
||||
override fun getTransferDataFlavors(): Array<DataFlavor> = arrayOf(DataFlavor.imageFlavor)
|
||||
override fun isDataFlavorSupported(flavor: DataFlavor?): Boolean = flavor == DataFlavor.imageFlavor
|
||||
override fun getTransferData(flavor: DataFlavor?): Any =
|
||||
if (flavor == DataFlavor.imageFlavor)
|
||||
ImageIO.read(ByteArrayInputStream(pngBytes)) ?: throw UnsupportedFlavorException(flavor)
|
||||
else throw UnsupportedFlavorException(flavor)
|
||||
}
|
||||
@@ -1,15 +1,19 @@
|
||||
@file:OptIn(ExperimentalComposeUiApi::class)
|
||||
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.draganddrop.DragAndDropEvent
|
||||
import androidx.compose.ui.draganddrop.awtTransferable
|
||||
import java.awt.datatransfer.DataFlavor
|
||||
import java.io.File
|
||||
|
||||
/* JVM (Compose Desktop) actual: DragAndDropEvent wraps an AWT
|
||||
* java.awt.dnd.DropTargetDropEvent whose transferable exposes the payload
|
||||
* through the standard AWT flavor system. */
|
||||
/* JVM (Compose Desktop) actual: DragAndDropEvent exposes the payload through
|
||||
* the AWT flavor system via the awtTransferable extension (throws when the
|
||||
* event carries no transferable — hence the runCatching). */
|
||||
|
||||
actual fun DragAndDropEvent.demoReadFilePaths(): List<String> {
|
||||
val transferable = runCatching { nativeEvent.transferable }.getOrNull() ?: return emptyList()
|
||||
val transferable = runCatching { awtTransferable }.getOrNull() ?: return emptyList()
|
||||
if (!transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) return emptyList()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val files = transferable.getTransferData(DataFlavor.javaFileListFlavor) as? List<File> ?: return emptyList()
|
||||
@@ -17,7 +21,7 @@ actual fun DragAndDropEvent.demoReadFilePaths(): List<String> {
|
||||
}
|
||||
|
||||
actual fun DragAndDropEvent.demoReadText(): String? {
|
||||
val transferable = runCatching { nativeEvent.transferable }.getOrNull() ?: return null
|
||||
val transferable = runCatching { awtTransferable }.getOrNull() ?: return null
|
||||
if (!transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) return null
|
||||
return runCatching { transferable.getTransferData(DataFlavor.stringFlavor) as? String }.getOrNull()
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
// JVM actual: map the token to an upstream Material Icons vector (material-icons
|
||||
// -extended) and draw it with material3's Icon — the direct counterpart to the
|
||||
// native actual's MaterialSymbols codepoint + font glyph.
|
||||
@Composable
|
||||
actual fun DemoIcon(
|
||||
icon: DemoIcon,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier,
|
||||
tint: Color,
|
||||
size: Dp,
|
||||
) {
|
||||
val vector: ImageVector = when (icon) {
|
||||
DemoIcon.Home -> Icons.Filled.Home
|
||||
DemoIcon.Search -> Icons.Filled.Search
|
||||
DemoIcon.Person -> Icons.Filled.Person
|
||||
DemoIcon.Settings -> Icons.Filled.Settings
|
||||
DemoIcon.Add -> Icons.Filled.Add
|
||||
DemoIcon.Edit -> Icons.Filled.Edit
|
||||
DemoIcon.Favorite -> Icons.Filled.Favorite
|
||||
DemoIcon.Star -> Icons.Filled.Star
|
||||
DemoIcon.Close -> Icons.Filled.Close
|
||||
DemoIcon.Image -> Icons.Filled.Image
|
||||
DemoIcon.Delete -> Icons.Filled.Delete
|
||||
DemoIcon.Share -> Icons.Filled.Share
|
||||
DemoIcon.Check -> Icons.Filled.Check
|
||||
DemoIcon.MoreVert -> Icons.Filled.MoreVert
|
||||
DemoIcon.ContentCopy -> Icons.Filled.ContentCopy
|
||||
DemoIcon.KeyboardArrowDown -> Icons.Filled.KeyboardArrowDown
|
||||
DemoIcon.Bookmark -> Icons.Filled.Bookmark
|
||||
DemoIcon.Notifications -> Icons.Filled.Notifications
|
||||
DemoIcon.Menu -> Icons.Filled.Menu
|
||||
DemoIcon.ArrowBack -> Icons.Filled.ArrowBack
|
||||
DemoIcon.Save -> Icons.Filled.Save
|
||||
DemoIcon.Refresh -> Icons.Filled.Refresh
|
||||
DemoIcon.Download -> Icons.Filled.Download
|
||||
DemoIcon.Upload -> Icons.Filled.Upload
|
||||
DemoIcon.ExpandMore -> Icons.Filled.ExpandMore
|
||||
DemoIcon.ExpandLess -> Icons.Filled.ExpandLess
|
||||
}
|
||||
Icon(
|
||||
imageVector = vector,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier.size(size),
|
||||
tint = if (tint.isSpecified) tint else LocalContentColor.current,
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||
import org.jetbrains.skia.Image
|
||||
import org.jetbrains.skiko.toComposeImageBitmap
|
||||
|
||||
actual fun demoDecodeImage(bytes: ByteArray): ImageBitmap? =
|
||||
runCatching { Image.makeFromEncoded(bytes).toComposeImageBitmap() }.getOrNull()
|
||||
|
||||
@@ -17,11 +17,6 @@ actual fun getPlatformCategories(): List<DemoCategory> = listOf(
|
||||
// IconFontIcon / IconText glyph engine + desktop scrollbars — no upstream analog.
|
||||
DemoScreen("FoundationExtra") { FoundationExtraScreen() },
|
||||
)),
|
||||
DemoCategory("material3", "Material3", listOf(
|
||||
// Icons demos the variable-font axes + Outlined/Rounded/Sharp families — project-only,
|
||||
// no upstream analog, so it can't be common.
|
||||
DemoScreen("Icons") { IconsScreen() },
|
||||
)),
|
||||
DemoCategory("native", "Native", listOf(
|
||||
DemoScreen("Window") { WindowScreen() },
|
||||
DemoScreen("Dispatchers") { DispatchersScreen() },
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.ui.platform.ClipEntry
|
||||
|
||||
/* Native actuals: 1:1 onto the port's ClipEntry, which mirrors upstream's
|
||||
macOS actual (withPlainText / getPlainText) extended with the PNG image
|
||||
path (withImage / getImage over SDL_[GS]etClipboardData "image/png"). */
|
||||
|
||||
actual fun demoClipEntryOfText(text: String): ClipEntry = ClipEntry.withPlainText(text)
|
||||
|
||||
actual fun demoClipEntryOfPng(pngBytes: ByteArray): ClipEntry = ClipEntry.withImage(pngBytes)
|
||||
|
||||
actual fun ClipEntry.demoPlainText(): String? = getPlainText()
|
||||
|
||||
actual fun ClipEntry.demoPngImage(): ByteArray? = getImage()
|
||||
@@ -1,55 +0,0 @@
|
||||
package demo.shim
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.compose.sdl.icons.MaterialSymbols
|
||||
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
|
||||
|
||||
// Native actual: resolve the token to a Material Symbols codepoint and draw it
|
||||
// through the Outlined variable font (SDL3_ttf / FreeType or Skia).
|
||||
@Composable
|
||||
actual fun DemoIcon(
|
||||
icon: DemoIcon,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier,
|
||||
tint: Color,
|
||||
size: Dp,
|
||||
) {
|
||||
val codepoint = when (icon) {
|
||||
DemoIcon.Home -> MaterialSymbols.Home
|
||||
DemoIcon.Search -> MaterialSymbols.Search
|
||||
DemoIcon.Person -> MaterialSymbols.Person
|
||||
DemoIcon.Settings -> MaterialSymbols.Settings
|
||||
DemoIcon.Add -> MaterialSymbols.Add
|
||||
DemoIcon.Edit -> MaterialSymbols.Edit
|
||||
DemoIcon.Favorite -> MaterialSymbols.Favorite
|
||||
DemoIcon.Star -> MaterialSymbols.Star
|
||||
DemoIcon.Close -> MaterialSymbols.Close
|
||||
DemoIcon.Image -> MaterialSymbols.Image
|
||||
DemoIcon.Delete -> MaterialSymbols.Delete
|
||||
DemoIcon.Share -> MaterialSymbols.Share
|
||||
DemoIcon.Check -> MaterialSymbols.Check
|
||||
DemoIcon.MoreVert -> MaterialSymbols.MoreVert
|
||||
DemoIcon.ContentCopy -> MaterialSymbols.ContentCopy
|
||||
DemoIcon.KeyboardArrowDown -> MaterialSymbols.KeyboardArrowDown
|
||||
DemoIcon.Bookmark -> MaterialSymbols.Bookmark
|
||||
DemoIcon.Notifications -> MaterialSymbols.Notifications
|
||||
DemoIcon.Menu -> MaterialSymbols.Menu
|
||||
DemoIcon.ArrowBack -> MaterialSymbols.ArrowBack
|
||||
DemoIcon.Save -> MaterialSymbols.Save
|
||||
DemoIcon.Refresh -> MaterialSymbols.Refresh
|
||||
DemoIcon.Download -> MaterialSymbols.Download
|
||||
DemoIcon.Upload -> MaterialSymbols.Upload
|
||||
DemoIcon.ExpandMore -> MaterialSymbols.ExpandMore
|
||||
DemoIcon.ExpandLess -> MaterialSymbols.ExpandLess
|
||||
}
|
||||
// Color.Unspecified → let MaterialSymbolsOutlined fall back to LocalContentColor.
|
||||
if (tint.isSpecified) {
|
||||
MaterialSymbolsOutlined(codepoint, contentDescription, modifier, tint = tint, size = size)
|
||||
} else {
|
||||
MaterialSymbolsOutlined(codepoint, contentDescription, modifier, size = size)
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared helpers for scripts/build-sdl/*.sh — host OS detection, path
|
||||
# translation for CMake, Ninja discovery, and toolchain wiring. Each build
|
||||
# script sources this file so it can drive the same CMake configure/build/
|
||||
# install flow on macOS, Linux, and Windows without conditionals sprinkled
|
||||
# through the script bodies.
|
||||
#
|
||||
# Assumes on every host: git, cmake in PATH. Ninja is fetched into
|
||||
# libs/.build/ninja-bin/ when absent. On Windows the fetch also uses
|
||||
# python + curl (Git Bash defaults).
|
||||
|
||||
# detect_host — normalises `uname -s` into macos / linux / windows.
|
||||
detect_host() {
|
||||
case "$(uname -s)" in
|
||||
Darwin) echo "macos" ;;
|
||||
Linux) echo "linux" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# cmake_path <path> — return `path` in the form CMake expects for the current
|
||||
# host. On Windows CMake is a native .exe that wants Windows-style paths;
|
||||
# elsewhere plain Unix paths work.
|
||||
cmake_path() {
|
||||
if [ "${BUILD_SDL_HOST:-}" = "windows" ]; then
|
||||
cygpath -m "$1"
|
||||
else
|
||||
printf '%s' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# find_ninja <build_dir> — echo the CMake-visible path to a ninja binary. If
|
||||
# no ninja is on PATH, fetches the platform-appropriate release binary once
|
||||
# into <build_dir>/ninja-bin/.
|
||||
find_ninja() {
|
||||
local build_dir="$1"
|
||||
if command -v ninja >/dev/null 2>&1; then
|
||||
echo "ninja"
|
||||
return
|
||||
fi
|
||||
local host="${BUILD_SDL_HOST:-$(detect_host)}"
|
||||
local dir="$build_dir/ninja-bin"
|
||||
mkdir -p "$dir"
|
||||
if [ ! -x "$dir/ninja" ] && [ ! -f "$dir/ninja.exe" ]; then
|
||||
echo ">> fetching ninja for $host" >&2
|
||||
local url
|
||||
case "$host" in
|
||||
macos) url="https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-mac.zip" ;;
|
||||
linux) url="https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux.zip" ;;
|
||||
windows) url="https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-win.zip" ;;
|
||||
*) echo "ERROR: no ninja binary for host $host" >&2; return 1 ;;
|
||||
esac
|
||||
curl -fL -o "$dir/ninja.zip" "$url"
|
||||
if [ "$host" = "windows" ]; then
|
||||
python -c "import zipfile,sys;zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])" \
|
||||
"$dir/ninja.zip" "$dir"
|
||||
else
|
||||
(cd "$dir" && unzip -q -o ninja.zip)
|
||||
chmod +x "$dir/ninja"
|
||||
fi
|
||||
fi
|
||||
if [ -f "$dir/ninja.exe" ]; then
|
||||
cmake_path "$dir/ninja.exe"
|
||||
else
|
||||
echo "$dir/ninja"
|
||||
fi
|
||||
}
|
||||
|
||||
# setup_toolchain — export CC / CXX so CMake picks up the right compiler for
|
||||
# static K/N-compatible builds:
|
||||
# * macOS → clang / clang++ from Xcode command line tools
|
||||
# * Linux → system gcc / g++
|
||||
# * Windows → K/N's own bundled mingw-w64 gcc (matches its CRT) for C, and
|
||||
# the SYSTEM g++ for C++ (K/N's mingw is C-only). Set KN_MINGW=0
|
||||
# to force the system gcc if the K/N one is unavailable.
|
||||
setup_toolchain() {
|
||||
local host="${BUILD_SDL_HOST:-$(detect_host)}"
|
||||
case "$host" in
|
||||
macos)
|
||||
export CC="${CC:-clang}"
|
||||
export CXX="${CXX:-clang++}"
|
||||
;;
|
||||
linux)
|
||||
export CC="${CC:-gcc}"
|
||||
export CXX="${CXX:-g++}"
|
||||
;;
|
||||
windows)
|
||||
if [ -z "${CXX:-}" ]; then
|
||||
local sys_gxx
|
||||
sys_gxx="$(command -v g++ 2>/dev/null || true)"
|
||||
[ -f "${sys_gxx}.exe" ] && sys_gxx="${sys_gxx}.exe"
|
||||
if [ -n "$sys_gxx" ]; then
|
||||
export CXX="$(cygpath -m "$sys_gxx")"
|
||||
echo ">> C++ compiler (K/N mingw is C-only): $CXX" >&2
|
||||
else
|
||||
echo ">> WARNING: no system g++ on PATH; SDL3's CMake configure needs a working" >&2
|
||||
echo ">> C++ compiler and will fail. Install mingw-w64 g++." >&2
|
||||
fi
|
||||
fi
|
||||
if [ "${KN_MINGW:-1}" != "0" ]; then
|
||||
local kn_bin
|
||||
kn_bin="$(ls -d "${KONAN_DATA_DIR:-$HOME/.konan}"/dependencies/*mingw*/bin 2>/dev/null | head -1 || true)"
|
||||
if [ -n "$kn_bin" ] && [ -x "$kn_bin/gcc.exe" ]; then
|
||||
export PATH="$kn_bin:$PATH"
|
||||
echo ">> using Kotlin/Native bundled mingw: $(gcc --version | head -1)" >&2
|
||||
else
|
||||
echo ">> WARNING: K/N bundled mingw not found; using system gcc." >&2
|
||||
fi
|
||||
fi
|
||||
export CC="${CC:-gcc}"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unsupported host: $host" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ==================
|
||||
# MARK: Manifest — build-sdl.properties
|
||||
# ==================
|
||||
# One file at scripts/build-sdl/build-sdl.properties defines the URL + ref for
|
||||
# every static library the build scripts pull. Format is `KEY=value`, with
|
||||
# `KEY_<host>=value` per-host overrides (host = macos / linux / windows).
|
||||
#
|
||||
# manifest_value <KEY> — echo the winning value, honoring:
|
||||
# 1. Environment variable of that name (highest priority)
|
||||
# 2. KEY_<host> in build-sdl.properties (only when host matches)
|
||||
# 3. KEY in build-sdl.properties (base)
|
||||
# Prints nothing if none set — pair with require_manifest to make the key
|
||||
# mandatory. MANIFEST_FILE can be pointed at a different file for testing.
|
||||
|
||||
MANIFEST_FILE="${MANIFEST_FILE:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/build-sdl.properties}"
|
||||
|
||||
manifest_value() {
|
||||
local vKey="$1"
|
||||
local vEnv
|
||||
eval "vEnv=\${$vKey:-}"
|
||||
if [ -n "$vEnv" ]; then
|
||||
printf '%s\n' "$vEnv"
|
||||
return
|
||||
fi
|
||||
[ -f "$MANIFEST_FILE" ] || return 0
|
||||
local vHost="${BUILD_SDL_HOST:-$(detect_host)}"
|
||||
local vHostVal
|
||||
vHostVal="$(sed -n "s/^${vKey}_${vHost}=//p" "$MANIFEST_FILE" | head -1)"
|
||||
if [ -n "$vHostVal" ]; then
|
||||
printf '%s\n' "$vHostVal"
|
||||
return
|
||||
fi
|
||||
sed -n "s/^${vKey}=//p" "$MANIFEST_FILE" | head -1
|
||||
}
|
||||
|
||||
# require_manifest <KEY> — echo manifest_value, or fail with a clear error if
|
||||
# the key resolves to an empty string (no env var, no override, no base).
|
||||
require_manifest() {
|
||||
local vKey="$1"
|
||||
local vVal
|
||||
vVal="$(manifest_value "$vKey")"
|
||||
if [ -z "$vVal" ]; then
|
||||
echo "ERROR: $vKey not defined — add it to $MANIFEST_FILE or export it as an env var" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf '%s\n' "$vVal"
|
||||
}
|
||||
|
||||
# extra_cmake_args — echo host-specific extra CMake arguments (e.g. macOS
|
||||
# arch pin). Meant to be interpolated unquoted into a cmake command line.
|
||||
extra_cmake_args() {
|
||||
local host="${BUILD_SDL_HOST:-$(detect_host)}"
|
||||
case "$host" in
|
||||
macos)
|
||||
# Port targets macosArm64 only. Force the arch so a universal-
|
||||
# arch host build stays trimmed and matches the K/N target.
|
||||
echo "-DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0"
|
||||
;;
|
||||
*) : ;;
|
||||
esac
|
||||
}
|
||||
@@ -0,0 +1,592 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
One-shot dependency setup — builds every native dependency this project links
|
||||
into the executable as a STATIC library, installing each into <repo>/libs/.
|
||||
Runs on macOS, Linux, and Windows with plain Python 3 — no Git Bash, curl or
|
||||
cygpath needed. Replaces the former build-*.sh scripts.
|
||||
|
||||
Build order matters — later libraries link the earlier ones:
|
||||
1. freetype -> libs/FreeType/lib/libfreetype.a
|
||||
2. sdl3 -> libs/SDL3/lib/libSDL3.a
|
||||
3. sdl3-image -> libs/SDL3_image (vendored PNG/JPG/SVG/WEBP; needs SDL3)
|
||||
4. sdl3-ttf -> libs/SDL3_ttf (variable-font-axes patch; needs SDL3 + FreeType)
|
||||
|
||||
Usage:
|
||||
python3 build-all.py build everything, in order
|
||||
python3 build-all.py sdl3 sdl3-ttf build a subset (canonical order enforced)
|
||||
|
||||
Everything is static + HarfBuzz/plutosvg-free, so the app links to a clean
|
||||
<app> + data.kres with no runtime .dylib / .so / .dll alongside.
|
||||
|
||||
Requires on every host: git, cmake, python 3. Ninja is fetched into
|
||||
libs/.build/ninja-bin when absent. Windows also needs a mingw-w64 g++ on PATH
|
||||
(for SDL3's GameInput backend; K/N's bundled mingw is C-only). URLs + refs for
|
||||
each library come from build-sdl.properties; edit it to change versions or
|
||||
repos, or set the corresponding env vars (SDL_URL / SDL_REF / SDL_IMAGE_URL /
|
||||
SDL_IMAGE_REF / SDL_TTF_URL / SDL_TTF_REF / FREETYPE_URL / FREETYPE_TAG) for a
|
||||
one-off override.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.request
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
# ==================
|
||||
# MARK: Constants
|
||||
# ==================
|
||||
|
||||
kToolsDir = Path(__file__).resolve().parent
|
||||
kRepoRoot = kToolsDir.parent.parent
|
||||
kLibsDir = kRepoRoot / "libs"
|
||||
kBuildOrder = ["freetype", "sdl3", "sdl3-image", "sdl3-ttf"]
|
||||
|
||||
# Compile flags shared by every library: size-optimised and sectioned so the
|
||||
# final link's --gc-sections can drop every function the app never calls.
|
||||
kSizeFlags = "-ffunction-sections -fdata-sections -Os"
|
||||
|
||||
kNinjaVersion = "1.12.1"
|
||||
kNinjaZipByHost = {
|
||||
"macos": "ninja-mac.zip",
|
||||
"linux": "ninja-linux.zip",
|
||||
"windows": "ninja-win.zip",
|
||||
}
|
||||
|
||||
# Windows: mingw-w64's <setjmp.h> emits external references to
|
||||
# __intrinsic_setjmpex from any TU using setjmp() (freetype, libpng, ...).
|
||||
# K/N's LLD sysroot for mingwX64 doesn't provide this symbol and the LLD
|
||||
# built by K/N 2.4.0 doesn't accept --defsym as a linker workaround, so a
|
||||
# tiny stub aliases the symbol to msvcrt's _setjmpex (see bakeSetjmpStub).
|
||||
kSetjmpStubSource = """#include <setjmp.h>
|
||||
|
||||
extern int __cdecl _setjmpex(jmp_buf _Buf, void *_Ctx);
|
||||
|
||||
/** Alias mingw-w64's __intrinsic_setjmpex onto msvcrt's _setjmpex. */
|
||||
int __cdecl __intrinsic_setjmpex(jmp_buf _Buf, void *_Ctx) {
|
||||
return _setjmpex(_Buf, _Ctx);
|
||||
}
|
||||
"""
|
||||
|
||||
# ==================
|
||||
# MARK: Helpers
|
||||
# ==================
|
||||
|
||||
def detectHost():
|
||||
"""Normalise the running platform into macos / linux / windows / unknown.
|
||||
BUILD_SDL_HOST in the environment overrides detection (testing hook)."""
|
||||
vOverride = os.environ.get("BUILD_SDL_HOST", "")
|
||||
if vOverride:
|
||||
return vOverride
|
||||
vSystem = platform.system()
|
||||
if vSystem == "Darwin":
|
||||
return "macos"
|
||||
if vSystem == "Linux":
|
||||
return "linux"
|
||||
if vSystem == "Windows" or vSystem.startswith(("MINGW", "MSYS", "CYGWIN")):
|
||||
return "windows"
|
||||
return "unknown"
|
||||
|
||||
|
||||
def run(inArgs, inCwd=None):
|
||||
"""Echo and run a command, aborting the whole build on a non-zero exit."""
|
||||
vArgs = [str(vArg) for vArg in inArgs]
|
||||
print(">> $ " + " ".join(vArgs), flush=True)
|
||||
subprocess.run(vArgs, cwd=inCwd, check=True)
|
||||
|
||||
|
||||
def forceRmtree(inPath):
|
||||
"""rm -rf equivalent that clears read-only bits before retrying — git
|
||||
object files in cloned trees are read-only on Windows and would make a
|
||||
plain shutil.rmtree fail."""
|
||||
vPath = Path(inPath)
|
||||
if not vPath.exists():
|
||||
return
|
||||
|
||||
def clearAndRetry(inFunc, inTarget, inExcInfo):
|
||||
"""onerror/onexc hook: make the entry writable and retry the delete."""
|
||||
os.chmod(inTarget, stat.S_IWRITE)
|
||||
inFunc(inTarget)
|
||||
|
||||
if sys.version_info >= (3, 12):
|
||||
shutil.rmtree(vPath, onexc=clearAndRetry)
|
||||
else:
|
||||
shutil.rmtree(vPath, onerror=clearAndRetry)
|
||||
|
||||
|
||||
def findNinja(inBuildDir, inHost):
|
||||
"""Return the CMake-visible path to a ninja binary. If no ninja is on
|
||||
PATH, fetches the platform-appropriate release binary once into
|
||||
<inBuildDir>/ninja-bin."""
|
||||
if shutil.which("ninja"):
|
||||
return "ninja"
|
||||
vDir = Path(inBuildDir) / "ninja-bin"
|
||||
vDir.mkdir(parents=True, exist_ok=True)
|
||||
vExe = vDir / ("ninja.exe" if inHost == "windows" else "ninja")
|
||||
if not vExe.is_file():
|
||||
vZipName = kNinjaZipByHost.get(inHost)
|
||||
if vZipName is None:
|
||||
raise SystemExit("ERROR: no ninja binary for host " + inHost)
|
||||
print(">> fetching ninja for " + inHost, flush=True)
|
||||
vUrl = ("https://github.com/ninja-build/ninja/releases/download/v"
|
||||
+ kNinjaVersion + "/" + vZipName)
|
||||
vZipPath = vDir / "ninja.zip"
|
||||
urllib.request.urlretrieve(vUrl, vZipPath)
|
||||
with zipfile.ZipFile(vZipPath) as vZip:
|
||||
vZip.extractall(vDir)
|
||||
if inHost != "windows":
|
||||
vExe.chmod(vExe.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
return vExe.as_posix()
|
||||
|
||||
|
||||
def setupToolchain(inHost):
|
||||
"""Export CC / CXX so CMake picks up the right compiler for static
|
||||
K/N-compatible builds, returning (cc, cxx):
|
||||
macos -> clang / clang++ from Xcode command line tools
|
||||
linux -> system gcc / g++
|
||||
windows -> K/N's own bundled mingw-w64 gcc (matches its CRT) for C, and
|
||||
the SYSTEM g++ for C++ (K/N's mingw is C-only). Set KN_MINGW=0
|
||||
to force the system gcc if the K/N one is unavailable."""
|
||||
if inHost == "macos":
|
||||
vCc = os.environ.get("CC") or "clang"
|
||||
vCxx = os.environ.get("CXX") or "clang++"
|
||||
elif inHost == "linux":
|
||||
vCc = os.environ.get("CC") or "gcc"
|
||||
vCxx = os.environ.get("CXX") or "g++"
|
||||
elif inHost == "windows":
|
||||
vCxx = os.environ.get("CXX") or ""
|
||||
if not vCxx:
|
||||
vSysGxx = shutil.which("g++")
|
||||
if vSysGxx:
|
||||
vCxx = Path(vSysGxx).as_posix()
|
||||
print(">> C++ compiler (K/N mingw is C-only): " + vCxx)
|
||||
else:
|
||||
print(">> WARNING: no system g++ on PATH; SDL3's CMake configure needs a working")
|
||||
print(">> C++ compiler and will fail. Install mingw-w64 g++.")
|
||||
if os.environ.get("KN_MINGW", "1") != "0":
|
||||
vKonanDir = Path(os.environ.get("KONAN_DATA_DIR") or (Path.home() / ".konan"))
|
||||
vKnBin = next((vBin for vBin in sorted(vKonanDir.glob("dependencies/*mingw*/bin"))
|
||||
if (vBin / "gcc.exe").is_file()), None)
|
||||
if vKnBin is not None:
|
||||
os.environ["PATH"] = str(vKnBin) + os.pathsep + os.environ["PATH"]
|
||||
vGccVersion = subprocess.run(["gcc", "--version"], capture_output=True,
|
||||
text=True).stdout.splitlines()[0]
|
||||
print(">> using Kotlin/Native bundled mingw: " + vGccVersion)
|
||||
else:
|
||||
print(">> WARNING: K/N bundled mingw not found; using system gcc.")
|
||||
vCc = os.environ.get("CC") or "gcc"
|
||||
else:
|
||||
raise SystemExit("ERROR: unsupported host: " + inHost)
|
||||
os.environ["CC"] = vCc
|
||||
if vCxx:
|
||||
os.environ["CXX"] = vCxx
|
||||
return vCc, vCxx
|
||||
|
||||
|
||||
def extraCmakeArgs(inHost):
|
||||
"""Host-specific extra CMake arguments. The port targets macosArm64 only —
|
||||
force the arch so a universal-arch host build stays trimmed and matches
|
||||
the K/N target."""
|
||||
if inHost == "macos":
|
||||
return ["-DCMAKE_OSX_ARCHITECTURES=arm64", "-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0"]
|
||||
return []
|
||||
|
||||
# ==================
|
||||
# MARK: Manifest — build-sdl.properties
|
||||
# ==================
|
||||
# One file at scripts/build-sdl/build-sdl.properties defines the URL + ref for
|
||||
# every static library this script pulls. Format is `KEY=value`, with
|
||||
# `KEY_<host>=value` per-host overrides (host = macos / linux / windows).
|
||||
|
||||
def manifestValue(inKey, inHost):
|
||||
"""Resolve inKey, honoring:
|
||||
1. Environment variable of that name (highest priority)
|
||||
2. KEY_<host> in build-sdl.properties (only when host matches)
|
||||
3. KEY in build-sdl.properties (base)
|
||||
Returns "" if none set — pair with requireManifest to make the key
|
||||
mandatory. MANIFEST_FILE can be pointed at a different file for testing."""
|
||||
vEnv = os.environ.get(inKey, "")
|
||||
if vEnv:
|
||||
return vEnv
|
||||
vFile = Path(os.environ.get("MANIFEST_FILE") or (kToolsDir / "build-sdl.properties"))
|
||||
if not vFile.is_file():
|
||||
return ""
|
||||
vBase = ""
|
||||
vHostVal = ""
|
||||
for vLine in vFile.read_text(encoding="utf-8").splitlines():
|
||||
vLine = vLine.strip()
|
||||
if not vLine or vLine.startswith("#") or "=" not in vLine:
|
||||
continue
|
||||
vName, vValue = vLine.split("=", 1)
|
||||
if vName == inKey + "_" + inHost and not vHostVal:
|
||||
vHostVal = vValue.strip()
|
||||
elif vName == inKey and not vBase:
|
||||
vBase = vValue.strip()
|
||||
return vHostVal or vBase
|
||||
|
||||
|
||||
def requireManifest(inKey, inHost):
|
||||
"""manifestValue, or fail with a clear error if the key resolves empty."""
|
||||
vVal = manifestValue(inKey, inHost)
|
||||
if not vVal:
|
||||
raise SystemExit("ERROR: " + inKey + " not defined — add it to "
|
||||
+ str(kToolsDir / "build-sdl.properties") + " or export it as an env var")
|
||||
return vVal
|
||||
|
||||
# ==================
|
||||
# MARK: Shared build flow
|
||||
# ==================
|
||||
|
||||
def cloneIfChanged(inBuildDir, inUrl, inRef, inBlobFilter=False):
|
||||
"""Clone inUrl at inRef into <inBuildDir>/src, re-cloning whenever URL/ref
|
||||
changes so switching versions is clean. inBlobFilter uses a blobless full
|
||||
clone + checkout instead of --depth 1 -b, so inRef can be any commit.
|
||||
Returns the src path."""
|
||||
vSrc = Path(inBuildDir) / "src"
|
||||
vMarker = Path(inBuildDir) / ".source"
|
||||
vWant = inUrl + " " + inRef
|
||||
vHave = vMarker.read_text(encoding="utf-8").strip() if vMarker.is_file() else ""
|
||||
if not (vSrc / "CMakeLists.txt").is_file() or vHave != vWant:
|
||||
print(">> cloning " + inUrl + " @ " + inRef)
|
||||
forceRmtree(vSrc)
|
||||
if inBlobFilter:
|
||||
run(["git", "clone", "--filter=blob:none", inUrl, vSrc])
|
||||
run(["git", "-C", vSrc, "checkout", "--quiet", inRef])
|
||||
else:
|
||||
run(["git", "clone", "--depth", "1", "-b", inRef, inUrl, vSrc])
|
||||
vMarker.write_text(vWant + "\n", encoding="utf-8")
|
||||
return vSrc
|
||||
|
||||
|
||||
def cmakeConfigure(inSrc, inOut, inNinja, inCc, inHost, inPrefix, inExtra):
|
||||
"""Run the CMake configure shared by every library (Ninja, Release,
|
||||
static, PIC, size-sectioned C flags) plus per-library inExtra args."""
|
||||
run(["cmake", "-S", Path(inSrc).as_posix(), "-B", Path(inOut).as_posix(), "-G", "Ninja",
|
||||
"-DCMAKE_MAKE_PROGRAM=" + inNinja,
|
||||
"-DCMAKE_C_COMPILER=" + inCc,
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DBUILD_SHARED_LIBS=OFF",
|
||||
"-DCMAKE_POSITION_INDEPENDENT_CODE=ON"]
|
||||
+ inExtra
|
||||
+ ["-DCMAKE_C_FLAGS=" + kSizeFlags]
|
||||
+ extraCmakeArgs(inHost)
|
||||
+ ["-DCMAKE_INSTALL_PREFIX=" + Path(inPrefix).as_posix()])
|
||||
|
||||
|
||||
def cmakeBuildInstall(inOut):
|
||||
"""cmake --build then --install of an already-configured build tree."""
|
||||
run(["cmake", "--build", Path(inOut).as_posix()])
|
||||
run(["cmake", "--install", Path(inOut).as_posix()])
|
||||
|
||||
# ==================
|
||||
# MARK: FreeType
|
||||
# ==================
|
||||
|
||||
def buildFreetype(inHost, inCc, inCxx):
|
||||
"""Build a self-contained static FreeType into libs/FreeType. Optional
|
||||
dependencies (PNG / HarfBuzz / Brotli / BZip2 / system zlib) are DISABLED —
|
||||
only core + variable-font (MM / GX) support is kept, which is all the SDL3
|
||||
renderer needs for Material Symbols axes and variable Roboto. The result
|
||||
is a static libfreetype.a with NO external DLLs / dylibs that links
|
||||
straight into the Kotlin/Native binary (the freetype.def does -lfreetype)."""
|
||||
vBuild = kLibsDir / ".build" / "freetype"
|
||||
vBuild.mkdir(parents=True, exist_ok=True)
|
||||
vNinja = findNinja(vBuild, inHost)
|
||||
vUrl = requireManifest("FREETYPE_URL", inHost)
|
||||
vTag = requireManifest("FREETYPE_TAG", inHost)
|
||||
vSrc = cloneIfChanged(vBuild, vUrl, vTag)
|
||||
|
||||
print(">> configuring (static, optional deps off)")
|
||||
cmakeConfigure(vSrc, vBuild / "out", vNinja, inCc, inHost, kLibsDir / "FreeType", [
|
||||
"-DFT_DISABLE_HARFBUZZ=ON", "-DFT_DISABLE_PNG=ON", "-DFT_DISABLE_BROTLI=ON",
|
||||
"-DFT_DISABLE_BZIP2=ON", "-DFT_DISABLE_ZLIB=ON",
|
||||
])
|
||||
|
||||
print(">> building + installing")
|
||||
cmakeBuildInstall(vBuild / "out")
|
||||
print(">> done: " + str(kLibsDir / "FreeType") + " (static libfreetype.a, no runtime deps)")
|
||||
|
||||
# ==================
|
||||
# MARK: SDL3
|
||||
# ==================
|
||||
|
||||
def buildSdl3(inHost, inCc, inCxx):
|
||||
"""Build a static SDL3 (no shared lib) into libs/SDL3 so the app links
|
||||
SDL3 straight into the executable. The set of system libraries SDL3 needs
|
||||
when static is recorded in libs/SDL3/lib/pkgconfig/sdl3-static.pc
|
||||
(Libs.private) after this runs; the app's linker line has to include those.
|
||||
|
||||
On Windows SDL >= 3.4 needs a working C++ compiler (GameInput backend) —
|
||||
see setupToolchain. The D3D12 render driver and SDL_GPU subsystem are
|
||||
forced OFF because K/N's mingw dxgi1_6.h is too old for SDL >= 3.4's
|
||||
IDXGIFactory6 / DXGI_GPU_PREFERENCE_* usage. D3D11 (default Windows
|
||||
driver) is unaffected, and this project only ever uses SDL_Render."""
|
||||
vBuild = kLibsDir / ".build" / "sdl3src"
|
||||
vBuild.mkdir(parents=True, exist_ok=True)
|
||||
vNinja = findNinja(vBuild, inHost)
|
||||
vUrl = requireManifest("SDL_URL", inHost)
|
||||
vRef = requireManifest("SDL_REF", inHost)
|
||||
vSrc = cloneIfChanged(vBuild, vUrl, vRef)
|
||||
vOut = vBuild / "out"
|
||||
vPrefix = vBuild / "prefix"
|
||||
|
||||
vExtra = [
|
||||
"-DSDL_SHARED=OFF", "-DSDL_STATIC=ON",
|
||||
"-DSDL_TESTS=OFF", "-DSDL_TEST_LIBRARY=OFF", "-DSDL_EXAMPLES=OFF",
|
||||
"-DSDL_INSTALL_TESTS=OFF",
|
||||
"-DCMAKE_CXX_FLAGS=" + kSizeFlags,
|
||||
]
|
||||
if inHost == "windows":
|
||||
# Kill the D3D12 driver + GPU subsystem (K/N mingw dxgi1_6.h too old).
|
||||
vExtra += ["-DSDL_RENDER_D3D12=OFF", "-DSDL_GPU=OFF"]
|
||||
if inHost == "linux":
|
||||
# SDL3's CMake feature-detection sees glibc's memfd_create and
|
||||
# posix_spawn_file_actions_addchdir_np on modern hosts (>= 2.27 /
|
||||
# 2.29), but K/N's LLD sysroot for linuxX64 doesn't have them at final
|
||||
# app link. Pre-set the cache vars so check_symbol_exists honors our
|
||||
# OFF value (it only checks vars that aren't already cached) and SDL3
|
||||
# falls back to its portable implementations.
|
||||
vExtra += ["-DHAVE_MEMFD_CREATE=0", "-DHAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP=0"]
|
||||
|
||||
print(">> configuring (static, size-sectioned)")
|
||||
forceRmtree(vOut)
|
||||
cmakeConfigure(vSrc, vOut, vNinja, inCc, inHost, vPrefix, vExtra)
|
||||
|
||||
print(">> building + installing")
|
||||
forceRmtree(vPrefix)
|
||||
cmakeBuildInstall(vOut)
|
||||
|
||||
vDest = kLibsDir / "SDL3"
|
||||
print(">> installing into " + str(vDest))
|
||||
forceRmtree(vDest)
|
||||
vDest.mkdir(parents=True)
|
||||
shutil.copytree(vPrefix / "include", vDest / "include")
|
||||
shutil.copytree(vPrefix / "lib", vDest / "lib")
|
||||
|
||||
if inHost == "windows":
|
||||
bakeSetjmpStub(vBuild, vDest, inCc)
|
||||
|
||||
print(">> done: " + str(vDest) + " (static libSDL3.a, no shared lib)")
|
||||
vPc = vDest / "lib" / "pkgconfig" / "sdl3-static.pc"
|
||||
if vPc.is_file():
|
||||
print(">> SDL3 static system libs (Libs.private):")
|
||||
for vLine in vPc.read_text(encoding="utf-8").splitlines():
|
||||
if vLine.startswith("Libs.private:"):
|
||||
print(" " + vLine[len("Libs.private:"):].strip())
|
||||
|
||||
|
||||
def bakeSetjmpStub(inBuildDir, inSdl3Dir, inCc):
|
||||
"""Compile kSetjmpStubSource and append its object into libSDL3.a so the
|
||||
archive travels with everything needed to link consumers (see the constant
|
||||
for why mingwX64 needs the __intrinsic_setjmpex alias)."""
|
||||
print(">> baking __intrinsic_setjmpex alias stub into libSDL3.a")
|
||||
vCFile = Path(inBuildDir) / "mingw_setjmp_stub.c"
|
||||
vObj = Path(inBuildDir) / "mingw_setjmp_stub.o"
|
||||
vCFile.write_text(kSetjmpStubSource, encoding="utf-8")
|
||||
run([inCc, "-c", "-Os", vCFile.as_posix(), "-o", vObj.as_posix()])
|
||||
run(["ar", "rcs", (Path(inSdl3Dir) / "lib" / "libSDL3.a").as_posix(), vObj.as_posix()])
|
||||
|
||||
# ==================
|
||||
# MARK: SDL3_image
|
||||
# ==================
|
||||
|
||||
def buildSdl3Image(inHost, inCc, inCxx):
|
||||
"""Build a static SDL3_image into libs/SDL3_image plus the static archives
|
||||
of its vendored codecs (zlib, libpng, libwebp). Formats: PNG + JPG
|
||||
(built-in stb backend) + WEBP + SVG (and the built-in BMP/GIF/QOI/TGA/...
|
||||
which need no external codec). AVIF / TIFF / JXL are OFF — they pull the
|
||||
very large dav1d / aom / libjxl submodules we don't init.
|
||||
|
||||
Static archives don't bundle their dependencies, so every vendored *.a is
|
||||
copied out of the build tree next to libSDL3_image.a; the app's linker
|
||||
line lists them. Needs sdl3 built FIRST (links against libs/SDL3)."""
|
||||
if not (kLibsDir / "SDL3" / "lib").is_dir():
|
||||
raise SystemExit("ERROR: static SDL3 not found — run `python3 "
|
||||
+ str(kToolsDir / "build-all.py") + " sdl3` first")
|
||||
vBuild = kLibsDir / ".build" / "sdl3imgsrc"
|
||||
vBuild.mkdir(parents=True, exist_ok=True)
|
||||
vNinja = findNinja(vBuild, inHost)
|
||||
vUrl = requireManifest("SDL_IMAGE_URL", inHost)
|
||||
vRef = requireManifest("SDL_IMAGE_REF", inHost)
|
||||
vSrc = cloneIfChanged(vBuild, vUrl, vRef)
|
||||
vOut = vBuild / "out"
|
||||
vPrefix = vBuild / "prefix"
|
||||
|
||||
print(">> fetching vendored codec submodules (zlib, libpng, libwebp)")
|
||||
run(["git", "-C", vSrc, "submodule", "update", "--init", "--depth", "1",
|
||||
"external/zlib", "external/libpng", "external/libwebp"])
|
||||
|
||||
print(">> configuring (static, vendored PNG/WEBP + stb JPG + built-in SVG; AVIF/TIF/JXL off)")
|
||||
forceRmtree(vOut)
|
||||
cmakeConfigure(vSrc, vOut, vNinja, inCc, inHost, vPrefix, [
|
||||
"-DCMAKE_CXX_COMPILER=" + (inCxx or inCc),
|
||||
"-DCMAKE_PREFIX_PATH=" + (kLibsDir / "SDL3").as_posix(),
|
||||
"-DSDLIMAGE_VENDORED=ON",
|
||||
"-DSDLIMAGE_DEPS_SHARED=OFF",
|
||||
"-DSDLIMAGE_SAMPLES=OFF", "-DSDLIMAGE_TESTS=OFF", "-DSDLIMAGE_INSTALL=ON",
|
||||
"-DSDLIMAGE_PNG=ON", "-DSDLIMAGE_JPG=ON", "-DSDLIMAGE_WEBP=ON", "-DSDLIMAGE_SVG=ON",
|
||||
"-DSDLIMAGE_AVIF=OFF", "-DSDLIMAGE_TIF=OFF", "-DSDLIMAGE_JXL=OFF",
|
||||
])
|
||||
|
||||
print(">> building + installing")
|
||||
forceRmtree(vPrefix)
|
||||
cmakeBuildInstall(vOut)
|
||||
|
||||
vDest = kLibsDir / "SDL3_image"
|
||||
print(">> installing into " + str(vDest) + " (+ vendored codec archives)")
|
||||
forceRmtree(vDest)
|
||||
(vDest / "lib").mkdir(parents=True)
|
||||
shutil.copytree(vPrefix / "include", vDest / "include")
|
||||
for vLib in (vPrefix / "lib").rglob("libSDL3_image*.a"):
|
||||
shutil.copy2(vLib, vDest / "lib" / vLib.name)
|
||||
# Harvest the vendored codec static archives from the build tree.
|
||||
for vLib in vOut.rglob("*.a"):
|
||||
if vLib.name != "libSDL3_image.a":
|
||||
shutil.copy2(vLib, vDest / "lib" / vLib.name)
|
||||
# libpng installs both libpng.a and an identical libpng16.a — keep one.
|
||||
(vDest / "lib" / "libpng.a").unlink(missing_ok=True)
|
||||
# Normalize zlib archive name across platforms: on Windows CMake produces
|
||||
# libzlibstatic.a, elsewhere libz.a. The cinterop staticLibraries directive
|
||||
# lists a single filename per platform, so drop a libz.a alias if only the
|
||||
# libzlibstatic.a form exists.
|
||||
vZlibStatic = vDest / "lib" / "libzlibstatic.a"
|
||||
if vZlibStatic.is_file() and not (vDest / "lib" / "libz.a").is_file():
|
||||
shutil.copy2(vZlibStatic, vDest / "lib" / "libz.a")
|
||||
|
||||
print(">> done: " + str(vDest))
|
||||
print(">> static archives present:")
|
||||
for vLib in sorted((vDest / "lib").iterdir()):
|
||||
print(" " + vLib.name)
|
||||
|
||||
# ==================
|
||||
# MARK: SDL3_ttf
|
||||
# ==================
|
||||
|
||||
def buildSdl3Ttf(inHost, inCc, inCxx):
|
||||
"""Build a static SDL3_ttf into libs/SDL3_ttf. Defaults (from
|
||||
build-sdl.properties) point at the in-house fork
|
||||
https://github.com/bitsycore/SDL_ttf @ variable-font-axes: upstream
|
||||
SDL3_ttf has no public API to set OpenType variable-font axes
|
||||
(wght / wdth / opsz / GRAD / FILL ...); the fork adds it so the renderer
|
||||
can drive axes through TTF_SetFontAxisValue() instead of bypassing SDL_ttf
|
||||
and talking to FreeType directly.
|
||||
|
||||
Static: a static archive doesn't bundle its dependencies, so the app's
|
||||
final link pulls in libs/FreeType and libs/SDL3 to resolve SDL_ttf's
|
||||
symbols. HarfBuzz and plutosvg are OFF, matching this repo's HarfBuzz-free
|
||||
FreeType build. Needs sdl3 + freetype built FIRST."""
|
||||
if not (kLibsDir / "SDL3" / "lib" / "cmake" / "SDL3" / "SDL3Config.cmake").is_file():
|
||||
raise SystemExit("ERROR: SDL3 not found in libs/SDL3 — run `python3 "
|
||||
+ str(kToolsDir / "build-all.py") + " sdl3` first")
|
||||
if not (kLibsDir / "FreeType" / "lib" / "libfreetype.a").is_file():
|
||||
raise SystemExit("ERROR: FreeType not found in libs/FreeType — run `python3 "
|
||||
+ str(kToolsDir / "build-all.py") + " freetype` first")
|
||||
vBuild = kLibsDir / ".build" / "sdl3_ttf"
|
||||
vBuild.mkdir(parents=True, exist_ok=True)
|
||||
vNinja = findNinja(vBuild, inHost)
|
||||
vUrl = requireManifest("SDL_TTF_URL", inHost)
|
||||
vRef = requireManifest("SDL_TTF_REF", inHost)
|
||||
vSrc = cloneIfChanged(vBuild, vUrl, vRef, inBlobFilter=True)
|
||||
vOut = vBuild / "out"
|
||||
vPrefix = vBuild / "prefix"
|
||||
|
||||
print(">> configuring (non-vendored: libs/FreeType + libs/SDL3; HarfBuzz/plutosvg off)")
|
||||
forceRmtree(vOut)
|
||||
cmakeConfigure(vSrc, vOut, vNinja, inCc, inHost, vPrefix, [
|
||||
"-DCMAKE_PREFIX_PATH=" + (kLibsDir / "SDL3").as_posix() + ";"
|
||||
+ (kLibsDir / "FreeType").as_posix(),
|
||||
"-DSDLTTF_VENDORED=OFF",
|
||||
"-DSDLTTF_HARFBUZZ=OFF",
|
||||
"-DSDLTTF_PLUTOSVG=OFF",
|
||||
"-DSDLTTF_SAMPLES=OFF",
|
||||
"-DSDLTTF_INSTALL=ON",
|
||||
])
|
||||
|
||||
print(">> building + installing")
|
||||
forceRmtree(vPrefix)
|
||||
cmakeBuildInstall(vOut)
|
||||
|
||||
vDest = kLibsDir / "SDL3_ttf"
|
||||
print(">> installing into " + str(vDest))
|
||||
forceRmtree(vDest)
|
||||
vDest.mkdir(parents=True)
|
||||
shutil.copytree(vPrefix / "include", vDest / "include")
|
||||
shutil.copytree(vPrefix / "lib", vDest / "lib")
|
||||
print(">> done: " + str(vDest) + " (libSDL3_ttf.a from " + vRef + ", static, no HarfBuzz)")
|
||||
|
||||
# ==================
|
||||
# MARK: Entry point
|
||||
# ==================
|
||||
|
||||
kBuilders = {
|
||||
"freetype": buildFreetype,
|
||||
"sdl3": buildSdl3,
|
||||
"sdl3-image": buildSdl3Image,
|
||||
"sdl3-ttf": buildSdl3Ttf,
|
||||
}
|
||||
|
||||
|
||||
def printNextSteps(inHost):
|
||||
"""Print the per-host gradle command that links the freshly built libs."""
|
||||
if inHost == "macos":
|
||||
print("Build the app (links everything into a self-contained macosArm64 binary):")
|
||||
print(" ./gradlew :demo:runDebugExecutableMacosArm64")
|
||||
print(" ./gradlew :apidemo:runDebugExecutableMacosArm64")
|
||||
elif inHost == "linux":
|
||||
print("Build the app (links everything into a self-contained Linux binary):")
|
||||
print(" ./gradlew :demo:runDebugExecutableLinuxX64")
|
||||
print(" ./gradlew :apidemo:runDebugExecutableLinuxX64")
|
||||
elif inHost == "windows":
|
||||
print("Build the app (links everything into a DLL-free .exe + data.kres):")
|
||||
print(" gradlew.bat :apidemo:runDebugExecutableMingwX64")
|
||||
print(" gradlew.bat :demo:runDebugExecutableMingwX64")
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse the library selection, wire the host toolchain, and run the
|
||||
selected build steps in canonical order."""
|
||||
vParser = argparse.ArgumentParser(
|
||||
description="Build the static SDL3 / SDL3_ttf / SDL3_image / FreeType "
|
||||
+ "libraries into <repo>/libs/ (see build-sdl.properties for versions).")
|
||||
vParser.add_argument("libs", nargs="*", metavar="lib",
|
||||
help="libraries to build: " + " ".join(kBuildOrder) + " (default: all, in order)")
|
||||
vArgs = vParser.parse_args()
|
||||
for vName in vArgs.libs:
|
||||
if vName not in kBuildOrder:
|
||||
vParser.error("unknown library '" + vName + "' (choose from: "
|
||||
+ " ".join(kBuildOrder) + ")")
|
||||
vWanted = set(vArgs.libs) if vArgs.libs else set(kBuildOrder)
|
||||
vSelected = [vName for vName in kBuildOrder if vName in vWanted]
|
||||
|
||||
vHost = detectHost()
|
||||
if vHost == "unknown":
|
||||
raise SystemExit("ERROR: unsupported host — this script runs on macOS, Linux, and Windows.")
|
||||
print(">> host: " + vHost)
|
||||
os.environ["BUILD_SDL_HOST"] = vHost
|
||||
vCc, vCxx = setupToolchain(vHost)
|
||||
|
||||
for vName in vSelected:
|
||||
print("")
|
||||
print("=" * 60)
|
||||
print("== " + vName)
|
||||
print("=" * 60)
|
||||
kBuilders[vName](vHost, vCc, vCxx)
|
||||
|
||||
print("")
|
||||
print("=" * 60)
|
||||
print("== Built (static) into libs/: " + ", ".join(vSelected))
|
||||
print("=" * 60)
|
||||
printNextSteps(vHost)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except subprocess.CalledProcessError as vError:
|
||||
raise SystemExit("ERROR: command failed with exit code "
|
||||
+ str(vError.returncode) + ": " + " ".join(vError.cmd))
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-shot dependency setup — builds every native dependency this project
|
||||
# links into the executable as a STATIC library, installing each into
|
||||
# <repo>/libs/. Runs on macOS, Linux, and Windows (Git Bash).
|
||||
#
|
||||
# Build order matters — later libraries link the earlier ones:
|
||||
# 1. FreeType → libs/FreeType/lib/libfreetype.a
|
||||
# 2. SDL3 → libs/SDL3/lib/libSDL3.a
|
||||
# 3. SDL3_image → libs/SDL3_image (vendored PNG/JPG/SVG/WEBP; needs SDL3)
|
||||
# 4. SDL3_ttf → libs/SDL3_ttf (variable-font-axes patch; needs
|
||||
# SDL3 + FreeType)
|
||||
#
|
||||
# Everything is static + HarfBuzz/plutosvg-free, so the app links to a clean
|
||||
# <app> + data.kres with no runtime .dylib / .so / .dll alongside.
|
||||
#
|
||||
# Requires on every host: git, cmake. Ninja is fetched into libs/.build/ninja-bin
|
||||
# when absent. Windows also needs Python + curl (Git Bash defaults) plus a
|
||||
# mingw-w64 g++ on PATH (for SDL3's GameInput backend; K/N's bundled mingw is
|
||||
# C-only). URLs + refs for each library come from build-sdl.properties; edit
|
||||
# it to change versions or repos, or set the corresponding env vars (SDL_URL /
|
||||
# SDL_REF / SDL_IMAGE_URL / SDL_IMAGE_REF / SDL_TTF_URL / SDL_TTF_REF /
|
||||
# FREETYPE_URL / FREETYPE_TAG) for a one-off override.
|
||||
set -euo pipefail
|
||||
|
||||
TOOLS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./_lib.sh
|
||||
source "$TOOLS/_lib.sh"
|
||||
|
||||
export BUILD_SDL_HOST="$(detect_host)"
|
||||
if [ "$BUILD_SDL_HOST" = "unknown" ]; then
|
||||
echo "ERROR: unsupported host — this script runs on macOS, Linux, and Git Bash on Windows." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo ">> host: $BUILD_SDL_HOST"
|
||||
|
||||
step() {
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "== $1"
|
||||
echo "============================================================"
|
||||
bash "$TOOLS/$1"
|
||||
}
|
||||
|
||||
step build-freetype.sh
|
||||
step build-sdl3.sh
|
||||
step build-sdl3-image.sh
|
||||
step build-sdl3-ttf.sh
|
||||
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "== All dependencies built (static) into libs/"
|
||||
echo "============================================================"
|
||||
case "$BUILD_SDL_HOST" in
|
||||
macos)
|
||||
echo "Build the app (links everything into a self-contained macosArm64 binary):"
|
||||
echo " ./gradlew :demo:runDebugExecutableMacosArm64"
|
||||
echo " ./gradlew :apidemo:runDebugExecutableMacosArm64"
|
||||
;;
|
||||
linux)
|
||||
echo "Build the app (links everything into a self-contained Linux binary):"
|
||||
echo " ./gradlew :demo:runDebugExecutableLinuxX64"
|
||||
echo " ./gradlew :apidemo:runDebugExecutableLinuxX64"
|
||||
;;
|
||||
windows)
|
||||
echo "Build the app (links everything into a DLL-free .exe + data.kres):"
|
||||
echo " gradlew.bat :apidemo:runDebugExecutableMingwX64"
|
||||
echo " gradlew.bat :demo:runDebugExecutableMingwX64"
|
||||
;;
|
||||
esac
|
||||
@@ -1,59 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a self-contained static FreeType and install it into <repo>/libs/FreeType.
|
||||
# Runs on macOS, Linux, and Windows (Git Bash) — see _lib.sh for host handling.
|
||||
#
|
||||
# Optional dependencies (PNG / HarfBuzz / Brotli / BZip2 / system zlib) are
|
||||
# DISABLED — only core + variable-font (MM / GX) support is kept, which is all
|
||||
# the SDL3 renderer needs for Material Symbols axes and variable Roboto.
|
||||
#
|
||||
# The result is a static libfreetype.a with NO external DLLs / dylibs that
|
||||
# links straight into the Kotlin/Native binary (the freetype.def does
|
||||
# `-lfreetype`). URL + ref come from scripts/build-sdl/build-sdl.properties
|
||||
# (FREETYPE_URL / FREETYPE_TAG); a same-named env var overrides for one-offs.
|
||||
set -euo pipefail
|
||||
|
||||
TOOLS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./_lib.sh
|
||||
source "$TOOLS/_lib.sh"
|
||||
|
||||
BUILD_SDL_HOST="$(detect_host)"
|
||||
setup_toolchain
|
||||
|
||||
FT_URL="$(require_manifest FREETYPE_URL)"
|
||||
FT_TAG="$(require_manifest FREETYPE_TAG)"
|
||||
REPO="$(cd "$TOOLS/../.." && pwd)"
|
||||
LIBS="$REPO/libs"
|
||||
BUILD="$LIBS/.build/freetype"
|
||||
mkdir -p "$BUILD"
|
||||
|
||||
NINJA="$(find_ninja "$BUILD")"
|
||||
|
||||
# Re-clone whenever URL / tag changes so switching versions is clean.
|
||||
MARKER="$BUILD/.source"
|
||||
WANT="$FT_URL $FT_TAG"
|
||||
if [ ! -f "$BUILD/src/CMakeLists.txt" ] || [ "$(cat "$MARKER" 2>/dev/null)" != "$WANT" ]; then
|
||||
echo ">> cloning FreeType $FT_TAG"
|
||||
rm -rf "$BUILD/src"
|
||||
git clone --depth 1 -b "$FT_TAG" "$FT_URL" "$BUILD/src"
|
||||
echo "$WANT" > "$MARKER"
|
||||
fi
|
||||
|
||||
echo ">> configuring (static, optional deps off)"
|
||||
# shellcheck disable=SC2046
|
||||
cmake -S "$(cmake_path "$BUILD/src")" -B "$(cmake_path "$BUILD/out")" -G Ninja \
|
||||
-DCMAKE_MAKE_PROGRAM="$NINJA" \
|
||||
-DCMAKE_C_COMPILER="$CC" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DFT_DISABLE_HARFBUZZ=ON -DFT_DISABLE_PNG=ON -DFT_DISABLE_BROTLI=ON \
|
||||
-DFT_DISABLE_BZIP2=ON -DFT_DISABLE_ZLIB=ON \
|
||||
-DCMAKE_C_FLAGS="-ffunction-sections -fdata-sections -Os" \
|
||||
$(extra_cmake_args) \
|
||||
-DCMAKE_INSTALL_PREFIX="$(cmake_path "$LIBS/FreeType")"
|
||||
|
||||
echo ">> building + installing"
|
||||
cmake --build "$(cmake_path "$BUILD/out")"
|
||||
cmake --install "$(cmake_path "$BUILD/out")"
|
||||
|
||||
echo ">> done: $LIBS/FreeType (static libfreetype.a, no runtime deps)"
|
||||
@@ -1,99 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a static SDL3_image and install it into <repo>/libs/SDL3_image. Runs
|
||||
# on macOS, Linux, and Windows (Git Bash) — see _lib.sh for host handling.
|
||||
#
|
||||
# Produces libSDL3_image.a plus the static archives of its vendored codecs
|
||||
# (zlib, libpng, libwebp) so the app links image decoding straight into the
|
||||
# executable — no runtime .so / .dylib / .dll alongside.
|
||||
#
|
||||
# Formats: PNG + JPG (built-in stb backend) + WEBP + SVG (and the built-in
|
||||
# BMP/GIF/QOI/TGA/... which need no external codec). AVIF / TIFF / JXL are OFF
|
||||
# — they pull the very large dav1d / aom / libjxl submodules we don't init.
|
||||
#
|
||||
# Static archives don't bundle their dependencies, so we copy every vendored
|
||||
# *.a out of the build tree next to libSDL3_image.a; the app's linker line
|
||||
# lists them. URL + ref come from scripts/build-sdl/build-sdl.properties
|
||||
# (SDL_IMAGE_URL / SDL_IMAGE_REF); a same-named env var overrides for one-offs.
|
||||
#
|
||||
# Run build-sdl3.sh FIRST (SDL3_image links against libs/SDL3).
|
||||
set -euo pipefail
|
||||
|
||||
TOOLS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./_lib.sh
|
||||
source "$TOOLS/_lib.sh"
|
||||
|
||||
BUILD_SDL_HOST="$(detect_host)"
|
||||
setup_toolchain
|
||||
|
||||
SDL_IMAGE_URL="$(require_manifest SDL_IMAGE_URL)"
|
||||
SDL_IMAGE_REF="$(require_manifest SDL_IMAGE_REF)"
|
||||
REPO="$(cd "$TOOLS/../.." && pwd)"
|
||||
LIBS="$REPO/libs"
|
||||
BUILD="$LIBS/.build/sdl3imgsrc"
|
||||
SRC="$BUILD/src"
|
||||
OUT="$BUILD/out"
|
||||
PREFIX="$BUILD/prefix"
|
||||
mkdir -p "$BUILD"
|
||||
|
||||
[ -d "$LIBS/SDL3/lib" ] || { echo "ERROR: static SDL3 not found — run scripts/build-sdl/build-sdl3.sh first" >&2; exit 1; }
|
||||
|
||||
NINJA="$(find_ninja "$BUILD")"
|
||||
|
||||
# Re-clone whenever URL / ref changes so switching versions is clean.
|
||||
MARKER="$BUILD/.source"
|
||||
WANT="$SDL_IMAGE_URL $SDL_IMAGE_REF"
|
||||
if [ ! -f "$SRC/CMakeLists.txt" ] || [ "$(cat "$MARKER" 2>/dev/null)" != "$WANT" ]; then
|
||||
echo ">> cloning SDL_image $SDL_IMAGE_REF"
|
||||
rm -rf "$SRC"
|
||||
git clone --depth 1 -b "$SDL_IMAGE_REF" "$SDL_IMAGE_URL" "$SRC"
|
||||
echo "$WANT" > "$MARKER"
|
||||
fi
|
||||
|
||||
echo ">> fetching vendored codec submodules (zlib, libpng, libwebp)"
|
||||
git -C "$SRC" submodule update --init --depth 1 \
|
||||
external/zlib external/libpng external/libwebp
|
||||
|
||||
echo ">> configuring (static, vendored PNG/WEBP + stb JPG + built-in SVG; AVIF/TIF/JXL off)"
|
||||
rm -rf "$OUT"
|
||||
# shellcheck disable=SC2046
|
||||
cmake -S "$(cmake_path "$SRC")" -B "$(cmake_path "$OUT")" -G Ninja \
|
||||
-DCMAKE_MAKE_PROGRAM="$NINJA" \
|
||||
-DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="${CXX:-$CC}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH="$(cmake_path "$LIBS/SDL3")" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DSDLIMAGE_VENDORED=ON \
|
||||
-DSDLIMAGE_DEPS_SHARED=OFF \
|
||||
-DSDLIMAGE_SAMPLES=OFF -DSDLIMAGE_TESTS=OFF -DSDLIMAGE_INSTALL=ON \
|
||||
-DSDLIMAGE_PNG=ON -DSDLIMAGE_JPG=ON -DSDLIMAGE_WEBP=ON -DSDLIMAGE_SVG=ON \
|
||||
-DSDLIMAGE_AVIF=OFF -DSDLIMAGE_TIF=OFF -DSDLIMAGE_JXL=OFF \
|
||||
-DCMAKE_C_FLAGS="-ffunction-sections -fdata-sections -Os" \
|
||||
$(extra_cmake_args) \
|
||||
-DCMAKE_INSTALL_PREFIX="$(cmake_path "$PREFIX")"
|
||||
|
||||
echo ">> building + installing"
|
||||
rm -rf "$PREFIX"
|
||||
cmake --build "$(cmake_path "$OUT")"
|
||||
cmake --install "$(cmake_path "$OUT")"
|
||||
|
||||
echo ">> installing into $LIBS/SDL3_image (+ vendored codec archives)"
|
||||
rm -rf "$LIBS/SDL3_image"
|
||||
mkdir -p "$LIBS/SDL3_image/lib"
|
||||
cp -R "$PREFIX/include" "$LIBS/SDL3_image/"
|
||||
find "$PREFIX/lib" -name 'libSDL3_image*.a' -exec cp {} "$LIBS/SDL3_image/lib/" \;
|
||||
# Harvest the vendored codec static archives from the build tree.
|
||||
find "$OUT" -name '*.a' ! -name 'libSDL3_image.a' -exec cp -f {} "$LIBS/SDL3_image/lib/" \;
|
||||
# libpng installs both libpng.a and an identical libpng16.a — keep one.
|
||||
rm -f "$LIBS/SDL3_image/lib/libpng.a"
|
||||
# Normalize zlib archive name across platforms: on Windows CMake produces
|
||||
# libzlibstatic.a, elsewhere libz.a. The cinterop staticLibraries directive
|
||||
# lists a single filename per platform, so drop a libz.a alias if only the
|
||||
# libzlibstatic.a form exists.
|
||||
if [ -f "$LIBS/SDL3_image/lib/libzlibstatic.a" ] && [ ! -f "$LIBS/SDL3_image/lib/libz.a" ]; then
|
||||
cp "$LIBS/SDL3_image/lib/libzlibstatic.a" "$LIBS/SDL3_image/lib/libz.a"
|
||||
fi
|
||||
|
||||
echo ">> done: $LIBS/SDL3_image"
|
||||
echo ">> static archives present:"
|
||||
ls "$LIBS/SDL3_image/lib/" | sed 's/^/ /'
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a static SDL3_ttf and install it into <repo>/libs/SDL3_ttf. Runs on
|
||||
# macOS, Linux, and Windows (Git Bash) — see _lib.sh for host handling.
|
||||
#
|
||||
# Defaults (from scripts/build-sdl/build-sdl.properties) point at the in-house
|
||||
# fork:
|
||||
#
|
||||
# https://github.com/bitsycore/SDL_ttf (branch: variable-font-axes)
|
||||
#
|
||||
# Upstream SDL3_ttf has no public API to set OpenType variable-font axes
|
||||
# (wght / wdth / opsz / GRAD / FILL ...); the fork adds it so the renderer
|
||||
# can drive axes through TTF_SetFontAxisValue() instead of bypassing SDL_ttf
|
||||
# and talking to FreeType directly.
|
||||
#
|
||||
# URL + ref come from scripts/build-sdl/build-sdl.properties (SDL_TTF_URL /
|
||||
# SDL_TTF_REF); a same-named env var overrides for one-offs. Swapping either
|
||||
# value re-clones automatically. Examples:
|
||||
# SDL_TTF_URL=https://github.com/libsdl-org/SDL_ttf.git SDL_TTF_REF=main ./build-sdl3-ttf.sh
|
||||
# SDL_TTF_REF=release-3.2.2 ./build-sdl3-ttf.sh
|
||||
#
|
||||
# Static: produces libSDL3_ttf.a (no shared lib). A static archive doesn't
|
||||
# bundle its dependencies, so the app's final link pulls in libs/FreeType
|
||||
# (libfreetype.a) and libs/SDL3 (libSDL3.a) to resolve SDL_ttf's symbols.
|
||||
# HarfBuzz and plutosvg are OFF, matching this repo's HarfBuzz-free FreeType
|
||||
# build. Run build-sdl3.sh and build-freetype.sh FIRST.
|
||||
set -euo pipefail
|
||||
|
||||
TOOLS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./_lib.sh
|
||||
source "$TOOLS/_lib.sh"
|
||||
|
||||
BUILD_SDL_HOST="$(detect_host)"
|
||||
setup_toolchain
|
||||
|
||||
SDL_TTF_URL="$(require_manifest SDL_TTF_URL)"
|
||||
SDL_TTF_REF="$(require_manifest SDL_TTF_REF)"
|
||||
REPO="$(cd "$TOOLS/../.." && pwd)"
|
||||
LIBS="$REPO/libs"
|
||||
BUILD="$LIBS/.build/sdl3_ttf"
|
||||
SRC="$BUILD/src"
|
||||
OUT="$BUILD/out"
|
||||
PREFIX="$BUILD/prefix"
|
||||
MARKER="$BUILD/.source"
|
||||
mkdir -p "$BUILD"
|
||||
|
||||
[ -f "$LIBS/SDL3/lib/cmake/SDL3/SDL3Config.cmake" ] || { echo "ERROR: SDL3 not found in libs/SDL3 — run scripts/build-sdl/build-sdl3.sh first" >&2; exit 1; }
|
||||
[ -f "$LIBS/FreeType/lib/libfreetype.a" ] || { echo "ERROR: FreeType not found in libs/FreeType — run scripts/build-sdl/build-freetype.sh first" >&2; exit 1; }
|
||||
|
||||
NINJA="$(find_ninja "$BUILD")"
|
||||
|
||||
# Re-clone whenever URL/ref changes so switching versions is clean.
|
||||
WANT="$SDL_TTF_URL $SDL_TTF_REF"
|
||||
if [ ! -f "$SRC/CMakeLists.txt" ] || [ "$(cat "$MARKER" 2>/dev/null)" != "$WANT" ]; then
|
||||
echo ">> cloning $SDL_TTF_URL @ $SDL_TTF_REF"
|
||||
rm -rf "$SRC"
|
||||
git clone --filter=blob:none "$SDL_TTF_URL" "$SRC"
|
||||
git -C "$SRC" checkout --quiet "$SDL_TTF_REF"
|
||||
echo "$WANT" > "$MARKER"
|
||||
fi
|
||||
|
||||
echo ">> configuring (non-vendored: libs/FreeType + libs/SDL3; HarfBuzz/plutosvg off)"
|
||||
rm -rf "$OUT"
|
||||
# shellcheck disable=SC2046
|
||||
cmake -S "$(cmake_path "$SRC")" -B "$(cmake_path "$OUT")" -G Ninja \
|
||||
-DCMAKE_MAKE_PROGRAM="$NINJA" \
|
||||
-DCMAKE_C_COMPILER="$CC" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH="$(cmake_path "$LIBS/SDL3");$(cmake_path "$LIBS/FreeType")" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DSDLTTF_VENDORED=OFF \
|
||||
-DSDLTTF_HARFBUZZ=OFF \
|
||||
-DSDLTTF_PLUTOSVG=OFF \
|
||||
-DSDLTTF_SAMPLES=OFF \
|
||||
-DSDLTTF_INSTALL=ON \
|
||||
-DCMAKE_C_FLAGS="-ffunction-sections -fdata-sections -Os" \
|
||||
$(extra_cmake_args) \
|
||||
-DCMAKE_INSTALL_PREFIX="$(cmake_path "$PREFIX")"
|
||||
|
||||
echo ">> building + installing"
|
||||
rm -rf "$PREFIX"
|
||||
cmake --build "$(cmake_path "$OUT")"
|
||||
cmake --install "$(cmake_path "$OUT")"
|
||||
|
||||
echo ">> installing into $LIBS/SDL3_ttf"
|
||||
rm -rf "$LIBS/SDL3_ttf"
|
||||
mkdir -p "$LIBS/SDL3_ttf"
|
||||
cp -R "$PREFIX/include" "$PREFIX/lib" "$LIBS/SDL3_ttf/"
|
||||
|
||||
echo ">> done: $LIBS/SDL3_ttf (libSDL3_ttf.a from $SDL_TTF_REF, static, no HarfBuzz)"
|
||||
@@ -1,123 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build a static SDL3 and install it into <repo>/libs/SDL3. Runs on macOS,
|
||||
# Linux, and Windows (Git Bash) — see _lib.sh for host handling.
|
||||
#
|
||||
# Produces libSDL3.a (no shared lib) so the app links SDL3 straight into the
|
||||
# executable — clean <app> + data.kres with no runtime .dylib / .so / .dll
|
||||
# alongside. Compiled with -ffunction-sections -fdata-sections so the final
|
||||
# link's --gc-sections can drop every SDL function the app never calls.
|
||||
#
|
||||
# The set of system libraries SDL3 needs when static is recorded in
|
||||
# libs/SDL3/lib/pkgconfig/sdl3-static.pc (Libs.private) after this runs; the
|
||||
# app's linker line has to include those. URL + ref come from
|
||||
# scripts/build-sdl/build-sdl.properties (SDL_URL / SDL_REF); a same-named env
|
||||
# var overrides for one-offs. Swapping either value re-clones automatically.
|
||||
#
|
||||
# On Windows SDL >= 3.4 needs a working C++ compiler (GameInput backend). See
|
||||
# _lib.sh's setup_toolchain: system g++ is captured for CXX because K/N's
|
||||
# bundled mingw is C-only. The D3D12 render driver and SDL_GPU subsystem are
|
||||
# forced OFF because K/N's mingw dxgi1_6.h is too old for SDL >= 3.4's
|
||||
# IDXGIFactory6 / DXGI_GPU_PREFERENCE_* usage. D3D11 (default Windows driver)
|
||||
# is unaffected, and this project only ever uses SDL_Render.
|
||||
set -euo pipefail
|
||||
|
||||
TOOLS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./_lib.sh
|
||||
source "$TOOLS/_lib.sh"
|
||||
|
||||
BUILD_SDL_HOST="$(detect_host)"
|
||||
setup_toolchain
|
||||
|
||||
SDL_URL="$(require_manifest SDL_URL)"
|
||||
SDL_REF="$(require_manifest SDL_REF)"
|
||||
REPO="$(cd "$TOOLS/../.." && pwd)"
|
||||
LIBS="$REPO/libs"
|
||||
BUILD="$LIBS/.build/sdl3src"
|
||||
SRC="$BUILD/src"
|
||||
OUT="$BUILD/out"
|
||||
PREFIX="$BUILD/prefix"
|
||||
mkdir -p "$BUILD"
|
||||
|
||||
NINJA="$(find_ninja "$BUILD")"
|
||||
|
||||
# Re-clone whenever URL/ref changes so switching versions is clean.
|
||||
MARKER="$BUILD/.source"
|
||||
WANT="$SDL_URL $SDL_REF"
|
||||
if [ ! -f "$SRC/CMakeLists.txt" ] || [ "$(cat "$MARKER" 2>/dev/null)" != "$WANT" ]; then
|
||||
echo ">> cloning SDL $SDL_REF"
|
||||
rm -rf "$SRC"
|
||||
git clone --depth 1 -b "$SDL_REF" "$SDL_URL" "$SRC"
|
||||
echo "$WANT" > "$MARKER"
|
||||
fi
|
||||
|
||||
# Windows-only extras: kill the D3D12 driver + GPU subsystem (K/N mingw
|
||||
# dxgi1_6.h too old). On macOS/Linux SDL picks Metal/Cocoa or Wayland/X11
|
||||
# based on what's available in the host SDK.
|
||||
WIN_ONLY=""
|
||||
if [ "$BUILD_SDL_HOST" = "windows" ]; then
|
||||
WIN_ONLY="-DSDL_RENDER_D3D12=OFF -DSDL_GPU=OFF"
|
||||
fi
|
||||
|
||||
# Linux-only extras: SDL3's CMake feature-detection sees glibc's memfd_create
|
||||
# and posix_spawn_file_actions_addchdir_np on modern hosts (>= 2.27 / 2.29),
|
||||
# but K/N's LLD sysroot for linuxX64 doesn't have them at final app link.
|
||||
# Pre-set the cache vars so check_symbol_exists honors our OFF value (it only
|
||||
# checks vars that aren't already cached) and SDL3 falls back to its portable
|
||||
# implementations.
|
||||
LINUX_ONLY=""
|
||||
if [ "$BUILD_SDL_HOST" = "linux" ]; then
|
||||
LINUX_ONLY="-DHAVE_MEMFD_CREATE=0 -DHAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP=0"
|
||||
fi
|
||||
|
||||
echo ">> configuring (static, size-sectioned)"
|
||||
rm -rf "$OUT"
|
||||
# shellcheck disable=SC2046
|
||||
cmake -S "$(cmake_path "$SRC")" -B "$(cmake_path "$OUT")" -G Ninja \
|
||||
-DCMAKE_MAKE_PROGRAM="$NINJA" \
|
||||
-DCMAKE_C_COMPILER="$CC" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
||||
-DSDL_SHARED=OFF -DSDL_STATIC=ON \
|
||||
-DSDL_TESTS=OFF -DSDL_TEST_LIBRARY=OFF -DSDL_EXAMPLES=OFF \
|
||||
-DSDL_INSTALL_TESTS=OFF \
|
||||
$WIN_ONLY \
|
||||
$LINUX_ONLY \
|
||||
-DCMAKE_C_FLAGS="-ffunction-sections -fdata-sections -Os" \
|
||||
-DCMAKE_CXX_FLAGS="-ffunction-sections -fdata-sections -Os" \
|
||||
$(extra_cmake_args) \
|
||||
-DCMAKE_INSTALL_PREFIX="$(cmake_path "$PREFIX")"
|
||||
|
||||
echo ">> building + installing"
|
||||
rm -rf "$PREFIX"
|
||||
cmake --build "$(cmake_path "$OUT")"
|
||||
cmake --install "$(cmake_path "$OUT")"
|
||||
|
||||
echo ">> installing into $LIBS/SDL3"
|
||||
rm -rf "$LIBS/SDL3"
|
||||
mkdir -p "$LIBS/SDL3"
|
||||
cp -R "$PREFIX/include" "$PREFIX/lib" "$LIBS/SDL3/"
|
||||
|
||||
# Windows: mingw-w64's <setjmp.h> emits external references to
|
||||
# __intrinsic_setjmpex from any TU using setjmp() (freetype, libpng, ...).
|
||||
# K/N's LLD sysroot for mingwX64 doesn't provide this symbol and the LLD
|
||||
# built by K/N 2.4.0 doesn't accept --defsym as a linker workaround.
|
||||
# Compile a tiny stub that aliases the symbol to msvcrt's _setjmpex, and
|
||||
# append its object into libSDL3.a so the archive travels with everything
|
||||
# needed to link consumers.
|
||||
if [ "$BUILD_SDL_HOST" = "windows" ]; then
|
||||
echo ">> baking __intrinsic_setjmpex alias stub into libSDL3.a"
|
||||
cat > "$BUILD/mingw_setjmp_stub.c" <<'CSTUB'
|
||||
#include <setjmp.h>
|
||||
extern int __cdecl _setjmpex(jmp_buf _Buf, void *_Ctx);
|
||||
int __cdecl __intrinsic_setjmpex(jmp_buf _Buf, void *_Ctx) {
|
||||
return _setjmpex(_Buf, _Ctx);
|
||||
}
|
||||
CSTUB
|
||||
"$CC" -c -Os "$BUILD/mingw_setjmp_stub.c" -o "$BUILD/mingw_setjmp_stub.o"
|
||||
ar rcs "$LIBS/SDL3/lib/libSDL3.a" "$BUILD/mingw_setjmp_stub.o"
|
||||
fi
|
||||
|
||||
echo ">> done: $LIBS/SDL3 (static libSDL3.a, no shared lib)"
|
||||
echo ">> SDL3 static system libs (Libs.private):"
|
||||
sed -n 's/^Libs.private:/ /p' "$LIBS/SDL3/lib/pkgconfig/sdl3-static.pc" 2>/dev/null || true
|
||||
+393
-94
@@ -1,126 +1,425 @@
|
||||
#!/usr/bin/env python3
|
||||
# Compose-API coverage: for each androidx.compose.* package, count how many of
|
||||
# upstream's public declarations we also expose.
|
||||
#
|
||||
# Uses the same klib.api parsing as compose-fidelity-check.py — a declaration is
|
||||
# identified by its `<pkg>/<name>` decl-id, extracted from the trailing
|
||||
# `// <decl-id>|<mangle>` comment the binary-compatibility-validator plugin
|
||||
# emits.
|
||||
#
|
||||
# Inputs:
|
||||
# - our dumps: <module>/api/<module>.klib.api (`./gradlew apiDump`)
|
||||
# - official dumps: cmp-ref clone (default: ../cmp-ref, then $CMP_REF)
|
||||
#
|
||||
# Output: a per-package table sorted by upstream size, with covered/total and a
|
||||
# coverage bar. Packages we don't touch are hidden by default; pass --all to
|
||||
# include them.
|
||||
"""
|
||||
Compose API coverage + fidelity — one script, two questions, per upstream module:
|
||||
|
||||
1. COVERAGE how much of each upstream module's public API do we also expose?
|
||||
(per-module and per-package tables with percentages)
|
||||
2. FIDELITY do we expose anything under the mirrored package prefixes that
|
||||
upstream does NOT have? (invented / divergent public surface — the old
|
||||
compose-fidelity-check.py, now folded in)
|
||||
|
||||
Both sides are Kotlin binary-compatibility-validator klib dumps, so "covered"
|
||||
means the declaration exists with a compatible public shape: each dump line
|
||||
carries a trailing `// <decl-id>|<mangle>` comment and we compare normalised
|
||||
<decl-id> sets.
|
||||
|
||||
Inputs
|
||||
ours: **/api/*.klib.api in this repo (regenerate: ./gradlew apiDump)
|
||||
upstream: the ref clones scripts/compose-fork/sync.sh maintains —
|
||||
../cmp-ref JetBrains/compose-multiplatform-core ($CMP_REF)
|
||||
../cmp-ref-<name> any other repo ($CMP_REF_<NAME>)
|
||||
|
||||
Usage
|
||||
python3 scripts/compose-coverage.py # per-module table + fidelity summary
|
||||
python3 scripts/compose-coverage.py --missing # list upstream decls we DON'T cover
|
||||
python3 scripts/compose-coverage.py --missing ui-util # ...for one module only
|
||||
python3 scripts/compose-coverage.py --packages # per-package breakdown
|
||||
python3 scripts/compose-coverage.py --extras # list every divergent decl
|
||||
python3 scripts/compose-coverage.py --all # with --packages: include packages upstream lacks
|
||||
|
||||
Output is informational, not a hard gate (exit 0 unless inputs are missing) —
|
||||
review divergences against CLAUDE.md's vendoring/fidelity rules. Known quirks
|
||||
of upstream's checked-in dumps: some lag their own sources or were generated
|
||||
with different BCV versions/filters (e.g. material3 misses recent experimental
|
||||
API its own sources have; ui-backhandler's dump holds nothing but $stable
|
||||
noise), so "extras" are review candidates, not automatically invented API.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
kRoot = Path(__file__).resolve().parent.parent
|
||||
if len(sys.argv) > 1 and not sys.argv[1].startswith("--"):
|
||||
kRefDir = Path(sys.argv[1])
|
||||
elif os.environ.get("CMP_REF"):
|
||||
kRefDir = Path(os.environ["CMP_REF"])
|
||||
elif (kRoot.parent / "cmp-ref").exists():
|
||||
kRefDir = kRoot.parent / "cmp-ref"
|
||||
else:
|
||||
kRefDir = Path("C:/Dev/cmp-ref")
|
||||
|
||||
kShowAll = "--all" in sys.argv
|
||||
# ==================
|
||||
# MARK: Targets — add a line here to track a new upstream repo / module
|
||||
# ==================
|
||||
# repo last path segment of the upstream repo URL. Resolves to the sync.sh
|
||||
# ref clone: ../cmp-ref for compose-multiplatform-core, ../cmp-ref-<repo>
|
||||
# for anything else — overridable via CMP_REF / CMP_REF_<REPO>.
|
||||
# upstream module dir inside that repo; its api/<name>.klib.api is the reference.
|
||||
# ours module dir in THIS repo whose dump mirrors it. Several upstream
|
||||
# modules may map to one of ours (ui-graphics / ui-text merge into :ui).
|
||||
|
||||
_ACCESSOR = re.compile(r"\.<(get|set)-[^>]+>$")
|
||||
kCoreRepo = "compose-multiplatform-core"
|
||||
kUmbrellaRepo = "compose-multiplatform"
|
||||
|
||||
kTargets = [
|
||||
# repo upstream module dir our module dir
|
||||
(kCoreRepo, "compose/ui/ui-util", "compose/ui/ui-util"),
|
||||
(kCoreRepo, "compose/ui/ui-geometry", "compose/ui/ui-geometry"),
|
||||
(kCoreRepo, "compose/ui/ui-unit", "compose/ui/ui-unit"),
|
||||
(kCoreRepo, "compose/ui/ui-backhandler", "compose/ui/ui-backhandler"),
|
||||
(kCoreRepo, "compose/ui/ui", "compose/ui/ui"),
|
||||
(kCoreRepo, "compose/ui/ui-graphics", "compose/ui/ui"),
|
||||
(kCoreRepo, "compose/ui/ui-text", "compose/ui/ui"),
|
||||
(kCoreRepo, "compose/animation/animation-core", "compose/animation/animation-core"),
|
||||
(kCoreRepo, "compose/animation/animation", "compose/animation/animation"),
|
||||
(kCoreRepo, "compose/animation/animation-graphics", "compose/animation/animation-graphics"),
|
||||
(kCoreRepo, "compose/foundation/foundation-layout", "compose/foundation/foundation-layout"),
|
||||
(kCoreRepo, "compose/foundation/foundation", "compose/foundation/foundation"),
|
||||
(kCoreRepo, "compose/material/material-ripple", "compose/material/material-ripple"),
|
||||
(kCoreRepo, "compose/material3/material3", "compose/material3/material3"),
|
||||
(kCoreRepo, "navigation3/navigation3-ui", "navigation3/navigation3-ui"),
|
||||
(kUmbrellaRepo, "components/resources/library", "components/resources/library"),
|
||||
]
|
||||
|
||||
# Packages under these prefixes are MIRRORED surface: anything we expose here
|
||||
# that no upstream target has is divergent/invented API and shows up in the
|
||||
# fidelity report. Project packages (com.compose.sdl.*, material symbols, ...)
|
||||
# are deliberately absent — they never count as divergent.
|
||||
kMirroredPrefixes = (
|
||||
"androidx.compose.",
|
||||
"androidx.navigation3.",
|
||||
"org.jetbrains.compose.resources",
|
||||
)
|
||||
|
||||
# The K/N targets this port builds. Upstream dumps are merged across THEIR
|
||||
# targets (ios / js / macos / wasm) with `// Targets: [...]` sections gating
|
||||
# target-specific decls; anything gated to targets outside this set (e.g.
|
||||
# ios-only enableTraceOSLog) can never exist here and is excluded from the
|
||||
# comparison, so the tables reflect the COMMON surface we can actually mirror.
|
||||
kOurTargets = {"linuxX64", "linuxArm64", "macosArm64", "mingwX64"}
|
||||
|
||||
# ==================
|
||||
# MARK: klib.api parsing
|
||||
# ==================
|
||||
|
||||
# Property accessors collapse onto the property, constructors onto the class,
|
||||
# so ours/upstream compare on stable names.
|
||||
kAccessorRe = re.compile(r"\.<(get|set)-[^>]+>$")
|
||||
kCtorRe = re.compile(r"\.<init>.*$")
|
||||
|
||||
# Merged-dump structure markers: the first `// Targets:` line is the file
|
||||
# header (every target the dump covers); later ones gate the next declaration
|
||||
# (and its whole block, for classes) to a subset. `// Alias:` names groups.
|
||||
kTargetSectionRe = re.compile(r"^// Targets: \[([^\]]*)\]")
|
||||
kAliasRe = re.compile(r"^// Alias: (\w+) => \[([^\]]*)\]")
|
||||
|
||||
|
||||
def decl_ids(in_path):
|
||||
def parseTargetList(inText, inAliases):
|
||||
"""'ios, macosArm64' -> the expanded set of concrete target names."""
|
||||
vSet = set()
|
||||
for vName in (vPart.strip() for vPart in inText.split(",")):
|
||||
if vName:
|
||||
vSet |= inAliases.get(vName, {vName})
|
||||
return vSet
|
||||
|
||||
|
||||
def declIds(inPath):
|
||||
"""Extract the normalised public decl-ids from a BCV .klib.api dump as
|
||||
(ids, skippedIds). A decl line ends in `// <decl-id>|<mangle>`; header
|
||||
comments have no `|` and no `<pkg>/<name>` shape, so requiring both filters
|
||||
them out. Declarations gated by a `// Targets: [...]` section that shares
|
||||
no target with kOurTargets (ios / js / wasm-only API) can never exist on
|
||||
this port: they land in skippedIds — out of the coverage denominator but
|
||||
still known-upstream for the fidelity check."""
|
||||
vIds = set()
|
||||
for vLine in in_path.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||
vSkipped = set()
|
||||
vAliases = {}
|
||||
vAllTargets = None # the file header's full target list; None until seen
|
||||
vScopes = [] # target set in force for each currently open block
|
||||
vPending = None # targets a section comment set for the NEXT decl
|
||||
for vLine in inPath.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||
vStripped = vLine.strip()
|
||||
vAlias = kAliasRe.match(vStripped)
|
||||
if vAlias:
|
||||
vAliases[vAlias.group(1)] = parseTargetList(vAlias.group(2), vAliases)
|
||||
continue
|
||||
vSection = kTargetSectionRe.match(vStripped)
|
||||
if vSection:
|
||||
vTargets = parseTargetList(vSection.group(1), vAliases)
|
||||
if vAllTargets is None:
|
||||
vAllTargets = vTargets
|
||||
else:
|
||||
vPending = vTargets
|
||||
continue
|
||||
vIdx = vLine.find("// ")
|
||||
if vIdx < 0:
|
||||
vCode = vLine[:vIdx] if vIdx >= 0 else vLine
|
||||
vComment = vLine[vIdx + 3:] if vIdx >= 0 else ""
|
||||
vEffective = vPending if vPending is not None else (vScopes[-1] if vScopes else vAllTargets)
|
||||
if "|" in vComment:
|
||||
vId = vComment.split("|", 1)[0].strip()
|
||||
if "/" in vId and "$stable" not in vId: # skip headers + stability props
|
||||
vId = kCtorRe.sub("", kAccessorRe.sub("", vId))
|
||||
if vEffective is not None and not (vEffective & kOurTargets):
|
||||
vSkipped.add(vId)
|
||||
else:
|
||||
vIds.add(vId)
|
||||
# Track blocks on the code part only — mangle comments contain `{}`.
|
||||
for _ in range(vCode.count("{")):
|
||||
vScopes.append(vEffective)
|
||||
for _ in range(vCode.count("}")):
|
||||
if vScopes:
|
||||
vScopes.pop()
|
||||
if vCode.strip() or "|" in vComment:
|
||||
vPending = None # a section comment only scopes the decl right after it
|
||||
return vIds, vSkipped
|
||||
|
||||
|
||||
def packageOf(inId):
|
||||
"""'androidx.compose.ui.unit/Density.toDpSize' -> 'androidx.compose.ui.unit'."""
|
||||
return inId.split("/", 1)[0]
|
||||
|
||||
|
||||
# Module dir segments too generic to identify a target on their own.
|
||||
kGenericSegments = {"library", "core"}
|
||||
|
||||
|
||||
def targetLabel(inModule):
|
||||
"""Short display label for an upstream module dir: its last path segment,
|
||||
plus the parent segment when the last one alone is generic
|
||||
('components/resources/library' -> 'resources/library')."""
|
||||
vParts = inModule.split("/")
|
||||
if vParts[-1] in kGenericSegments and len(vParts) > 1:
|
||||
return vParts[-2] + "/" + vParts[-1]
|
||||
return vParts[-1]
|
||||
|
||||
# ==================
|
||||
# MARK: Input discovery
|
||||
# ==================
|
||||
|
||||
def refCloneDir(inRepo):
|
||||
"""Resolve the local ref-clone dir for an upstream repo name, mirroring
|
||||
scripts/compose-fork/sync.py: ../cmp-ref for compose-multiplatform-core
|
||||
(override $CMP_REF), ../cmp-ref-<repo> otherwise (override $CMP_REF_<REPO>)."""
|
||||
if inRepo == kCoreRepo:
|
||||
return Path(os.environ.get("CMP_REF") or (kRoot.parent / "cmp-ref"))
|
||||
vEnv = os.environ.get("CMP_REF_" + re.sub(r"[^A-Za-z0-9]+", "_", inRepo).upper())
|
||||
return Path(vEnv) if vEnv else kRoot.parent / ("cmp-ref-" + inRepo)
|
||||
|
||||
|
||||
def refHead(inDir):
|
||||
"""Short HEAD of a ref clone, or '?' when git can't answer."""
|
||||
try:
|
||||
vOut = subprocess.run(["git", "-C", str(inDir), "rev-parse", "--short", "HEAD"],
|
||||
capture_output=True, text=True)
|
||||
return vOut.stdout.strip() or "?"
|
||||
except OSError:
|
||||
return "?"
|
||||
|
||||
|
||||
def upstreamApiFile(inRepo, inModule):
|
||||
"""Path to the single .klib.api reference dump of an upstream module, or
|
||||
None when the clone / dump isn't there (sparse checkout not synced)."""
|
||||
vApiDir = refCloneDir(inRepo) / inModule / "api"
|
||||
vFiles = sorted(vApiDir.glob("*.klib.api"))
|
||||
return vFiles[0] if vFiles else None
|
||||
|
||||
|
||||
def loadOurDumps():
|
||||
"""All of this repo's api/*.klib.api dumps (any nesting depth, skipping
|
||||
build intermediates and libs/), as {module-dir-posix: {decl-ids}}."""
|
||||
vDumps = {}
|
||||
for vFile in sorted(kRoot.rglob("*.klib.api")):
|
||||
vRel = vFile.relative_to(kRoot)
|
||||
if vFile.parent.name != "api" or {"build", "libs", ".git"} & set(vRel.parts):
|
||||
continue
|
||||
vId = vLine[vIdx + 3:].split("|", 1)[0].strip()
|
||||
if not vId.startswith("androidx.compose"):
|
||||
continue
|
||||
if "$stable" in vId:
|
||||
continue
|
||||
vId = _ACCESSOR.sub("", vId)
|
||||
vId = re.sub(r"\.<init>.*$", "", vId)
|
||||
vIds.add(vId)
|
||||
return vIds
|
||||
vDumps[vFile.parent.parent.relative_to(kRoot).as_posix()] = declIds(vFile)[0]
|
||||
return vDumps
|
||||
|
||||
# ==================
|
||||
# MARK: Report
|
||||
# ==================
|
||||
|
||||
def package_of(in_id):
|
||||
return in_id.split("/", 1)[0]
|
||||
|
||||
|
||||
def bar(in_pct, in_width=20):
|
||||
vFilled = int(round(in_pct * in_width / 100))
|
||||
return "#" * vFilled + "." * (in_width - vFilled)
|
||||
def bar(inPct, inWidth=20):
|
||||
"""Render a 0-100 percentage as a #/. progress bar."""
|
||||
vFilled = int(round(inPct * inWidth / 100))
|
||||
return "#" * vFilled + "." * (inWidth - vFilled)
|
||||
|
||||
|
||||
def main():
|
||||
vRefFiles = sorted(kRefDir.glob("compose/**/api/*.klib.api"))
|
||||
if not vRefFiles:
|
||||
print(f"!! No official klib.api under {kRefDir}", file=sys.stderr)
|
||||
"""Load both ABI universes, print the per-module coverage table, then the
|
||||
optional per-package table and divergent-decl listing."""
|
||||
vParser = argparse.ArgumentParser(description="Compose API coverage + fidelity vs upstream klib dumps.")
|
||||
vParser.add_argument("--missing", nargs="?", const="", metavar="MODULE",
|
||||
help="list upstream decls we don't cover, grouped by package (optionally one module label, e.g. ui-util)")
|
||||
vParser.add_argument("--packages", action="store_true", help="per-package breakdown table")
|
||||
vParser.add_argument("--extras", action="store_true", help="list every divergent decl (old fidelity-check output)")
|
||||
vParser.add_argument("--all", action="store_true", help="with --packages: include our packages upstream lacks")
|
||||
vArgs = vParser.parse_args()
|
||||
|
||||
# ============
|
||||
# Load upstream refs, target by target
|
||||
vUpstreamByTarget = {} # {target-label: {decl-ids}}
|
||||
vOursDirByTarget = {} # {target-label: our module dir}
|
||||
vMissingRefs = []
|
||||
vSkippedUnion = set()
|
||||
for vRepo, vModule, vOursDir in kTargets:
|
||||
vLabel = targetLabel(vModule)
|
||||
vFile = upstreamApiFile(vRepo, vModule)
|
||||
if vFile is None:
|
||||
vMissingRefs.append((vRepo, vModule))
|
||||
continue
|
||||
vUpstreamByTarget[vLabel], vSkipped = declIds(vFile)
|
||||
vSkippedUnion |= vSkipped
|
||||
vOursDirByTarget[vLabel] = vOursDir
|
||||
if not vUpstreamByTarget:
|
||||
print("!! No upstream klib.api dumps found -- run scripts/compose-fork/sync.sh first "
|
||||
+ "(or point CMP_REF / CMP_REF_<REPO> at the clones).", file=sys.stderr)
|
||||
return 1
|
||||
vAllUpstream = set().union(*vUpstreamByTarget.values())
|
||||
|
||||
# Map each upstream .klib.api file to a short label for grouping.
|
||||
vUpstream = {} # {pkg: {decl_ids}}
|
||||
vUpstreamModules = {} # {pkg: {module_labels}}
|
||||
for vF in vRefFiles:
|
||||
vModule = vF.parent.parent.name # e.g. "foundation-layout"
|
||||
for vId in decl_ids(vF):
|
||||
vPkg = package_of(vId)
|
||||
vUpstream.setdefault(vPkg, set()).add(vId)
|
||||
vUpstreamModules.setdefault(vPkg, set()).add(vModule)
|
||||
|
||||
vOurFiles = sorted(kRoot.glob("*/api/*.klib.api")) + sorted(kRoot.glob("*/*/api/*.klib.api"))
|
||||
if not vOurFiles:
|
||||
print("!! No local api/*.klib.api dumps — run `./gradlew apiDump` first.", file=sys.stderr)
|
||||
# ============
|
||||
# Load our dumps
|
||||
vOurDumps = loadOurDumps()
|
||||
if not vOurDumps:
|
||||
print("!! No local api/*.klib.api dumps -- run `./gradlew apiDump` first.", file=sys.stderr)
|
||||
return 1
|
||||
vOurs = set().union(*vOurDumps.values())
|
||||
vOursMirrored = {vId for vId in vOurs if vId.startswith(kMirroredPrefixes)}
|
||||
# Fidelity baseline includes target-gated upstream decls: implementing one
|
||||
# of those is coverage beyond our targets, not invented API.
|
||||
vDivergent = vOursMirrored - vAllUpstream - vSkippedUnion
|
||||
|
||||
vOurs = set()
|
||||
for vF in vOurFiles:
|
||||
vOurs |= decl_ids(vF)
|
||||
# ============
|
||||
# Warnings — a target whose module has no local dump reports fake 0%
|
||||
for vRepo, vModule in vMissingRefs:
|
||||
print(f"!! upstream dump missing: {refCloneDir(vRepo) / vModule}/api/*.klib.api "
|
||||
+ "-- re-run scripts/compose-fork/sync.sh (target skipped)", file=sys.stderr)
|
||||
vNoDump = sorted({vDir for vDir in vOursDirByTarget.values() if vDir not in vOurDumps})
|
||||
for vDir in vNoDump:
|
||||
print(f"!! no local dump for {vDir} -- its rows undercount; run `./gradlew apiDump`", file=sys.stderr)
|
||||
if vMissingRefs or vNoDump:
|
||||
print(file=sys.stderr)
|
||||
|
||||
# Compute per-package stats.
|
||||
vRows = []
|
||||
for vPkg, vUpstreamSet in vUpstream.items():
|
||||
vCovered = vUpstreamSet & vOurs
|
||||
vExtra = {vId for vId in vOurs if package_of(vId) == vPkg} - vUpstreamSet
|
||||
vPct = 100.0 * len(vCovered) / len(vUpstreamSet) if vUpstreamSet else 0.0
|
||||
vRows.append((vPkg, len(vCovered), len(vUpstreamSet), vPct, len(vExtra),
|
||||
",".join(sorted(vUpstreamModules[vPkg]))))
|
||||
# Also count our extras in packages upstream doesn't have here.
|
||||
vOurPkgs = {package_of(vId) for vId in vOurs}
|
||||
for vPkg in vOurPkgs - set(vUpstream.keys()):
|
||||
vExtra = sum(1 for vId in vOurs if package_of(vId) == vPkg)
|
||||
vRows.append((vPkg, 0, 0, 0.0, vExtra, "(not in ref)"))
|
||||
|
||||
vRows.sort(key=lambda r: -r[2])
|
||||
|
||||
print(f"Official refs: {len(vRefFiles)} klib.api files")
|
||||
print(f"Our dumps: {len(vOurFiles)} files, {len(vOurs)} androidx.compose.* decls")
|
||||
vRepoNotes = ", ".join(f"{vRepo} @ {refHead(refCloneDir(vRepo))}"
|
||||
for vRepo in dict.fromkeys(vT[0] for vT in kTargets))
|
||||
print(f"Upstream: {len(vUpstreamByTarget)} modules, {len(vAllUpstream)} decls"
|
||||
+ f" ({len(vSkippedUnion)} decls for targets we don't build excluded) ({vRepoNotes})")
|
||||
print(f"Ours: {len(vOurDumps)} dumps, {len(vOurs)} decls ({len(vOursMirrored)} under mirrored prefixes)")
|
||||
print()
|
||||
|
||||
vFmt = " {:<52} {:>6} / {:>5} {:>5}% {} extras={:<4} {}"
|
||||
print(vFmt.format("package", "ours", "up", "cov", " " * 20, "extra", "upstream module"))
|
||||
print(" " + "-" * 130)
|
||||
vTotalCov = 0
|
||||
vTotalUp = 0
|
||||
for vPkg, vC, vU, vPct, vE, vMod in vRows:
|
||||
if vU == 0 and not kShowAll:
|
||||
# ============
|
||||
# Attribute each divergent decl to the target owning its package
|
||||
vPkgOwner = {} # {pkg: target-label with the most decls in pkg}
|
||||
vPkgCount = {}
|
||||
for vLabel, vIds in vUpstreamByTarget.items():
|
||||
for vId in vIds:
|
||||
vPkg = packageOf(vId)
|
||||
vCount = vPkgCount.get((vPkg, vLabel), 0) + 1
|
||||
vPkgCount[(vPkg, vLabel)] = vCount
|
||||
if vCount > vPkgCount.get((vPkg, vPkgOwner.get(vPkg)), 0):
|
||||
vPkgOwner[vPkg] = vLabel
|
||||
vExtrasByTarget = {}
|
||||
vOrphanExtras = set() # divergent decls in packages NO upstream target has
|
||||
for vId in vDivergent:
|
||||
vOwner = vPkgOwner.get(packageOf(vId))
|
||||
if vOwner is None:
|
||||
vOrphanExtras.add(vId)
|
||||
else:
|
||||
vExtrasByTarget.setdefault(vOwner, set()).add(vId)
|
||||
|
||||
# ============
|
||||
# Per-module table (kTargets order)
|
||||
vFmt = " {:<38} {:<28} {:>6} / {:>6} {:>5} {} {:>6}"
|
||||
print(vFmt.format("upstream module", "ours", "cover", "total", "cov", " " * 20, "extras"))
|
||||
print(" " + "-" * 118)
|
||||
vTotalCov, vTotalUp = 0, 0
|
||||
for vRepo, vModule, vOursDir in kTargets:
|
||||
vLabel = targetLabel(vModule)
|
||||
if vLabel not in vUpstreamByTarget:
|
||||
continue
|
||||
vTotalCov += vC
|
||||
vTotalUp += vU
|
||||
print(vFmt.format(vPkg, vC, vU, f"{vPct:.0f}", bar(vPct), vE, vMod))
|
||||
if vTotalUp:
|
||||
vOverall = 100.0 * vTotalCov / vTotalUp
|
||||
vUp = vUpstreamByTarget[vLabel]
|
||||
vCov = len(vUp & vOurs)
|
||||
vPct = 100.0 * vCov / len(vUp) if vUp else 0.0
|
||||
vTotalCov += vCov
|
||||
vTotalUp += len(vUp)
|
||||
vPctStr = f"{vPct:.0f}%" if vUp else "-"
|
||||
vOursNote = vOursDir.rsplit("/", 1)[-1] + (" (NO DUMP)" if vOursDir in vNoDump else "")
|
||||
print(vFmt.format(vModule, vOursNote, vCov, len(vUp), vPctStr,
|
||||
bar(vPct), len(vExtrasByTarget.get(vLabel, ()))))
|
||||
print(" " + "-" * 118)
|
||||
vOverall = 100.0 * vTotalCov / vTotalUp if vTotalUp else 0.0
|
||||
print(vFmt.format("TOTAL", "", vTotalCov, vTotalUp, f"{vOverall:.0f}%", bar(vOverall), len(vDivergent)))
|
||||
print()
|
||||
|
||||
# ============
|
||||
# Missing decl listing (--missing [MODULE])
|
||||
if vArgs.missing is not None:
|
||||
if vArgs.missing and vArgs.missing not in vUpstreamByTarget:
|
||||
print(f"!! unknown module label '{vArgs.missing}' -- valid: "
|
||||
+ " ".join(vUpstreamByTarget), file=sys.stderr)
|
||||
return 1
|
||||
for vRepo, vModule, vOursDir in kTargets:
|
||||
vLabel = targetLabel(vModule)
|
||||
if vLabel not in vUpstreamByTarget or (vArgs.missing and vLabel != vArgs.missing):
|
||||
continue
|
||||
vMissing = sorted(vUpstreamByTarget[vLabel] - vOurs)
|
||||
if not vMissing:
|
||||
continue
|
||||
print(f"Missing from {vLabel} -- upstream has, we don't ({len(vMissing)} decls):")
|
||||
vByPkg = {}
|
||||
for vId in vMissing:
|
||||
vByPkg.setdefault(packageOf(vId), []).append(vId)
|
||||
for vPkg in sorted(vByPkg):
|
||||
print(f" [{vPkg}] ({len(vByPkg[vPkg])})")
|
||||
for vId in vByPkg[vPkg]:
|
||||
print(f" {vId.split('/', 1)[1]}")
|
||||
print()
|
||||
|
||||
# ============
|
||||
# Per-package table (--packages)
|
||||
if vArgs.packages:
|
||||
vUpByPkg = {} # {pkg: {decl-ids}}
|
||||
vPkgModules = {} # {pkg: {target-labels}}
|
||||
for vLabel, vIds in vUpstreamByTarget.items():
|
||||
for vId in vIds:
|
||||
vUpByPkg.setdefault(packageOf(vId), set()).add(vId)
|
||||
vPkgModules.setdefault(packageOf(vId), set()).add(vLabel)
|
||||
vRows = []
|
||||
for vPkg, vUp in vUpByPkg.items():
|
||||
vCov = len(vUp & vOurs)
|
||||
vExtra = sum(1 for vId in vDivergent if packageOf(vId) == vPkg)
|
||||
vRows.append((vPkg, vCov, len(vUp), vExtra, ",".join(sorted(vPkgModules[vPkg]))))
|
||||
if vArgs.all:
|
||||
for vPkg in {packageOf(vId) for vId in vOursMirrored} - set(vUpByPkg):
|
||||
vExtra = sum(1 for vId in vOursMirrored if packageOf(vId) == vPkg)
|
||||
vRows.append((vPkg, 0, 0, vExtra, "(not upstream)"))
|
||||
vRows.sort(key=lambda vRow: -vRow[2])
|
||||
vPkgFmt = " {:<52} {:>6} / {:>6} {:>5} {} {:>6} {}"
|
||||
print(vPkgFmt.format("package", "cover", "total", "cov", " " * 20, "extras", "upstream module"))
|
||||
print(" " + "-" * 130)
|
||||
print(vFmt.format("TOTAL (shown)", vTotalCov, vTotalUp, f"{vOverall:.0f}", bar(vOverall), "", ""))
|
||||
vPkgCov = vPkgUp = 0
|
||||
for vPkg, vCov, vUp, vExtra, vMods in vRows:
|
||||
vPct = 100.0 * vCov / vUp if vUp else 0.0
|
||||
vPkgCov += vCov
|
||||
vPkgUp += vUp
|
||||
print(vPkgFmt.format(vPkg, vCov, vUp, f"{vPct:.0f}%" if vUp else "-", bar(vPct), vExtra, vMods))
|
||||
vPkgPct = 100.0 * vPkgCov / vPkgUp if vPkgUp else 0.0
|
||||
print(" " + "-" * 130)
|
||||
print(vPkgFmt.format("TOTAL", vPkgCov, vPkgUp, f"{vPkgPct:.0f}%", bar(vPkgPct), len(vDivergent), ""))
|
||||
print()
|
||||
|
||||
# ============
|
||||
# Fidelity: divergent decl listing (--extras) or one-line summary
|
||||
if vArgs.extras:
|
||||
print(f"Divergent -- under mirrored prefixes but not upstream ({len(vDivergent)} decls):")
|
||||
vByPkg = {}
|
||||
for vId in sorted(vDivergent):
|
||||
vByPkg.setdefault(packageOf(vId), []).append(vId)
|
||||
for vPkg in sorted(vByPkg):
|
||||
vOwner = vPkgOwner.get(vPkg, "(package not upstream)")
|
||||
print(f" [{vPkg}] ({len(vByPkg[vPkg])}) -> {vOwner}")
|
||||
for vId in vByPkg[vPkg]:
|
||||
print(f" {vId.split('/', 1)[1]}")
|
||||
else:
|
||||
vOrphanNote = f" ({len(vOrphanExtras)} in packages upstream lacks)" if vOrphanExtras else ""
|
||||
print(f"Fidelity: {len(vDivergent)} decls under mirrored prefixes not found upstream{vOrphanNote}"
|
||||
+ " -- run with --extras to list them.")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Compose-API fidelity check: diff this project's PUBLIC androidx.compose.* ABI
|
||||
# against the official Compose klib ABI, flagging declarations we expose that
|
||||
# upstream Compose does not (invented / divergent public surface).
|
||||
#
|
||||
# Inputs:
|
||||
# - our dumps: <module>/api/<module>.klib.api (generated by `./gradlew apiDump`,
|
||||
# Kotlin binary-compatibility-validator plugin)
|
||||
# - official dumps: the JetBrains/compose-multiplatform-core clone's
|
||||
# compose/**/api/*.klib.api (default: C:/Dev/cmp-ref)
|
||||
#
|
||||
# Usage: ./gradlew apiDump && python3 scripts/compose-fidelity-check.py [cmp-ref-dir]
|
||||
#
|
||||
# Both files use the same binary-compatibility-validator klib format, where each
|
||||
# declaration carries a trailing `// <decl-id>|<mangle>` comment. We compare the
|
||||
# <decl-id> path (normalised) as a set, so a name present in ours but not upstream
|
||||
# is surfaced. NOTE: the reference clone is sparse (ui / foundation / animation /
|
||||
# runtime) — material and desktop-only foundation (e.g. Scrollbar) have no upstream
|
||||
# file here, so declarations in those areas show up as "not upstream" and are
|
||||
# expected project surface, not bugs. Treat the output as candidates to review
|
||||
# against CLAUDE.md's fidelity rules, not a hard gate.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
kRoot = Path(__file__).resolve().parent.parent
|
||||
# cmp-ref clone: explicit arg, then $CMP_REF, then <repo>/../cmp-ref (where
|
||||
# scripts/compose-fork/sync.sh puts it), then the old Windows default. Portable
|
||||
# across Windows / macOS / Linux.
|
||||
if len(sys.argv) > 1:
|
||||
kRefDir = Path(sys.argv[1])
|
||||
elif os.environ.get("CMP_REF"):
|
||||
kRefDir = Path(os.environ["CMP_REF"])
|
||||
elif (kRoot.parent / "cmp-ref").exists():
|
||||
kRefDir = kRoot.parent / "cmp-ref"
|
||||
else:
|
||||
kRefDir = Path("C:/Dev/cmp-ref")
|
||||
|
||||
# decl-id is the text between "// " and the first "|". Strip accessor / ctor
|
||||
# noise so a property and its getter collapse to one name.
|
||||
_ACCESSOR = re.compile(r"\.<(get|set)-[^>]+>$")
|
||||
|
||||
|
||||
def decl_ids(in_path):
|
||||
vIds = set()
|
||||
for vLine in in_path.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||
vIdx = vLine.find("// ")
|
||||
if vIdx < 0:
|
||||
continue
|
||||
vId = vLine[vIdx + 3:].split("|", 1)[0].strip()
|
||||
if not vId.startswith("androidx.compose"):
|
||||
continue
|
||||
if "$stable" in vId: # Compose-compiler-generated stability props — not real API
|
||||
continue
|
||||
vId = _ACCESSOR.sub("", vId)
|
||||
vId = re.sub(r"\.<init>.*$", "", vId) # constructors -> owning class
|
||||
vIds.add(vId)
|
||||
return vIds
|
||||
|
||||
|
||||
def package_of(in_id):
|
||||
# "androidx.compose.ui.unit/Density.toDpSize" -> "androidx.compose.ui.unit"
|
||||
return in_id.split("/", 1)[0]
|
||||
|
||||
|
||||
def main():
|
||||
vOfficial = set()
|
||||
vRefFiles = sorted(kRefDir.glob("compose/**/api/*.klib.api"))
|
||||
for vF in vRefFiles:
|
||||
vOfficial |= decl_ids(vF)
|
||||
if not vOfficial:
|
||||
print(f"!! No official klib.api found under {kRefDir} — clone JetBrains/compose-multiplatform-core there.")
|
||||
return 1
|
||||
|
||||
vOurFiles = sorted(kRoot.glob("*/api/*.klib.api")) + sorted(kRoot.glob("*/*/api/*.klib.api"))
|
||||
if not vOurFiles:
|
||||
print("!! No local api/*.klib.api dumps — run `./gradlew apiDump` first.")
|
||||
return 1
|
||||
|
||||
vOurs = {}
|
||||
for vF in vOurFiles:
|
||||
for vId in decl_ids(vF):
|
||||
vOurs.setdefault(vId, vF.parent.parent.name)
|
||||
|
||||
vDivergent = sorted(set(vOurs) - vOfficial)
|
||||
print(f"Official refs: {len(vRefFiles)} klib.api files, {len(vOfficial)} androidx.compose.* decls")
|
||||
print(f"Our dumps: {len(vOurFiles)} files, {len(vOurs)} androidx.compose.* decls")
|
||||
print(f"Not found in upstream Compose: {len(vDivergent)} decls\n")
|
||||
|
||||
vByPkg = {}
|
||||
for vId in vDivergent:
|
||||
vByPkg.setdefault(package_of(vId), []).append(vId)
|
||||
for vPkg in sorted(vByPkg):
|
||||
print(f" [{vPkg}] ({len(vByPkg[vPkg])})")
|
||||
for vId in vByPkg[vPkg]:
|
||||
print(f" {vId.split('/', 1)[1]}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -70,20 +70,11 @@ def main():
|
||||
vSb.append("// MARK: MaterialSymbols (codepoints)")
|
||||
vSb.append("// ==================")
|
||||
vSb.append("")
|
||||
vSb.append("/* GENERATED — do not edit by hand. Regenerate with")
|
||||
vSb.append("/** GENERATED — do not edit by hand. Regenerate with")
|
||||
vSb.append(" scripts/generate-material-symbols.py (downloads Google's .codepoints")
|
||||
vSb.append(" file for the Material Symbols variable font and emits every glyph as a")
|
||||
vSb.append(" const). The codepoints are identical across the outlined / rounded /")
|
||||
vSb.append(" sharp styles, so these constants resolve against whichever style module")
|
||||
vSb.append(" (:material-symbols:{outlined,rounded,sharp}) is installed.")
|
||||
vSb.append("")
|
||||
vSb.append(" Usage:")
|
||||
vSb.append("")
|
||||
vSb.append(" import com.compose.sdl.icons.MaterialSymbols")
|
||||
vSb.append(" import com.compose.sdl.icons.material.symbols.outlined.MaterialSymbolsOutlined")
|
||||
vSb.append("")
|
||||
vSb.append(" MaterialSymbolsOutlined.install() // once at startup")
|
||||
vSb.append(" Icon(codepoint = MaterialSymbols.Home, fontFamily = MaterialSymbolsOutlined.Family)")
|
||||
vSb.append(" sharp styles.")
|
||||
vSb.append("")
|
||||
vSb.append(" Shipping all names is free: with -PsubsetIcons=true each app's font is")
|
||||
vSb.append(f" hb-subset down to only the glyphs it references. {len(vEntries)} icons. */")
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
// :material-symbols — codepoint constants + all three Material Symbols style
|
||||
// composables (Outlined / Rounded / Sharp) in one module.
|
||||
// composables (Outlined / Rounded / Sharp) in one module, for BOTH stacks:
|
||||
//
|
||||
// Previously each style lived in its own :material-symbols:outlined /
|
||||
// :rounded / :sharp sub-module and apps opted in by listing the style
|
||||
// dependencies they wanted. The three styles are 100% pure Kotlin
|
||||
// (`object MaterialSymbolsOutlined { … }`) — no cinterops, no per-target
|
||||
// actuals, no reason to be separate modules. Consolidated so apps just
|
||||
// `implementation(project(":material-symbols"))` once and get all three;
|
||||
// the app's data.kres Zip task decides which style FONT to actually
|
||||
// bundle by scanning the app's Kotlin sources for MaterialSymbols<Style>
|
||||
// call sites (see :apidemo / :demo build files).
|
||||
// commonMain — the MaterialSymbols codepoints + the PUBLIC API
|
||||
// (MaterialSymbols<Style> objects, axis defaults) so
|
||||
// consumers' shared code and IDE analysis resolve it.
|
||||
// nativeMain — actual renderer over the port's IconFont pipeline
|
||||
// (:foundation IconFontIcon; IconFont itself handles the
|
||||
// SDL3 / Skia renderer split — this module never sees it).
|
||||
// jvmMain — actual renderer over Skiko directly (Typeface.makeClone
|
||||
// per axes combination + TextLine on the native canvas);
|
||||
// the upstream Font(variationSettings) route is unusable —
|
||||
// its FontCache drops the settings from the cache key.
|
||||
//
|
||||
// commonMain compiles against the OFFICIAL Maven Compose artifacts (metadata
|
||||
// + jvm resolve them); the NATIVE target configurations substitute ui /
|
||||
// material3 for the port's project modules — the FULL-COMMONIZATION BRIDGE
|
||||
// declared once in the root build (the Maven artifacts ship no mingw/linux
|
||||
// klibs). The runtime is the official klib everywhere, never substituted.
|
||||
//
|
||||
// The app owns the font files: the data.kres Zip task bundles the styles an
|
||||
// app's sources actually reference (native), and the app's
|
||||
// jvmProcessResources stages the same fonts onto the JVM classpath at
|
||||
// font/<file>.ttf (see :demo's build file).
|
||||
//
|
||||
// Publication artifactId (when set up): compose-desktop-material-symbols.
|
||||
|
||||
@@ -28,7 +40,34 @@ plugins {
|
||||
// Skip mingwX64 on non-Windows hosts; see root build.gradle.kts.
|
||||
val vHostSupportsMingw = rootProject.extra["vHostSupportsMingw"] as Boolean
|
||||
|
||||
// JVM stack version — the dev build matching the pinned COMPOSE_CORE_REF
|
||||
// (scripts/compose-fork/compose.properties): byte-exact parity with the
|
||||
// vendored sources, and (unlike published beta01) its desktop loadTypeface
|
||||
// applies Font.variationSettings — required for the icon axes on JVM.
|
||||
// material3 rides its own release train (same +dev build, different base).
|
||||
// Gradle orders "+dev" BELOW the plain version, so force the core-repo
|
||||
// groups on jvm configurations (mirrors :demo's forcing).
|
||||
val vComposeJvmVersion = "1.12.0-beta01+dev4324"
|
||||
val vComposeM3JvmVersion = "1.12.0-alpha03+dev4324"
|
||||
val vComposeJvmForced = mapOf(
|
||||
"org.jetbrains.compose.runtime" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.ui" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.foundation" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.animation" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.material" to vComposeJvmVersion,
|
||||
"org.jetbrains.compose.material3" to vComposeM3JvmVersion,
|
||||
)
|
||||
configurations.configureEach {
|
||||
if (name.startsWith("jvm")) {
|
||||
resolutionStrategy.eachDependency {
|
||||
vComposeJvmForced[requested.group]?.let { useVersion(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
|
||||
linuxArm64()
|
||||
linuxX64()
|
||||
macosArm64()
|
||||
@@ -38,16 +77,25 @@ kotlin {
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
// The MaterialSymbols<Style> objects emit Icon(...) via
|
||||
// com.compose.sdl.icons.IconFontIcon and reference
|
||||
// MaterialIconAxisDefaults / IconDefaults — those live in
|
||||
// :foundation (com.compose.sdl.icons package), which
|
||||
// itself already api-depends on :ui.
|
||||
// The official runtime klibs — the SAME artifact/version the port
|
||||
// itself uses (:ui pins it); resolves for metadata, jvm AND native.
|
||||
api("org.jetbrains.compose.runtime:runtime:1.11.1")
|
||||
// Official Maven coordinates for the API surface (Modifier / Color
|
||||
// / Dp / material3's LocalContentColor). Metadata + jvm resolve
|
||||
// them from Maven; NATIVE configurations substitute them for
|
||||
// project(":ui") / project(":material3") (root build bridge).
|
||||
api("org.jetbrains.compose.ui:ui:$vComposeJvmVersion")
|
||||
api("org.jetbrains.compose.material3:material3:$vComposeM3JvmVersion")
|
||||
}
|
||||
nativeMain.dependencies {
|
||||
// The native actual draws via com.compose.sdl.icons.IconFontIcon —
|
||||
// project code in :foundation (which api-depends on :ui).
|
||||
api(project(":foundation"))
|
||||
// Default tint follows upstream material3 Icon:
|
||||
// `tint: Color = LocalContentColor.current` — needs material3's
|
||||
// LocalContentColor (provided by Surface / button content / …).
|
||||
api(project(":material3"))
|
||||
}
|
||||
jvmMain.dependencies {
|
||||
// BasicText for the JVM actual — same version as :demo's jvm
|
||||
// parity target.
|
||||
api("org.jetbrains.compose.foundation:foundation:$vComposeJvmVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
@file:Suppress("PropertyName", "ConstPropertyName")
|
||||
|
||||
package com.compose.sdl.icons.material.symbols
|
||||
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
// ==================
|
||||
// MARK: MaterialSymbolsIcon — COMMON API
|
||||
// ==================
|
||||
|
||||
/* The public Material Symbols surface, declared in commonMain so consumers'
|
||||
shared code (and the IDE's common analysis) resolve it directly. Rendering
|
||||
goes through the internal expect below:
|
||||
|
||||
native — the port's IconFont pipeline (:foundation IconFontIcon; the
|
||||
SDL3 / Skia renderer split is handled inside :ui — this module
|
||||
never sees it). Fonts come from data.kres.
|
||||
jvm — upstream Compose Desktop: a classpath ResourceFont carrying the
|
||||
variable-font axes via FontVariation.Settings + BasicText.
|
||||
|
||||
The app owns the font files for both stacks (data.kres Zip task on native,
|
||||
jvm resources at font/<Style>.ttf on JVM — see :demo's build file). */
|
||||
sealed class MaterialSymbolsIcon {
|
||||
|
||||
/* Font-family key the glyphs render under (also the install/cache key). */
|
||||
abstract val Family: String
|
||||
|
||||
/* Where the app is expected to ship this style's variable font. */
|
||||
abstract val DefaultResourcePath: String
|
||||
|
||||
@Composable
|
||||
operator fun invoke(
|
||||
icon: Int,
|
||||
contentDescription: String? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = Color.Unspecified,
|
||||
size: Dp = 24.dp,
|
||||
fill: Float = MaterialIconAxisDefaults.Fill,
|
||||
weight: Int = MaterialIconAxisDefaults.Weight,
|
||||
grade: Int = MaterialIconAxisDefaults.Grade,
|
||||
opticalSize: Int = MaterialIconAxisDefaults.OpticalSize,
|
||||
) {
|
||||
renderMaterialSymbol(
|
||||
style = this,
|
||||
codepoint = icon,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
// Default tint mirrors upstream material3 Icon: LocalContentColor.
|
||||
tint = if (tint.isSpecified) tint else LocalContentColor.current,
|
||||
size = size,
|
||||
fill = fill,
|
||||
weight = weight,
|
||||
grade = grade,
|
||||
opticalSize = opticalSize,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object MaterialSymbolsOutlined : MaterialSymbolsIcon() {
|
||||
override val Family: String = "material-symbols-outlined"
|
||||
override val DefaultResourcePath: String = "font/MaterialSymbolsOutlined.ttf"
|
||||
}
|
||||
|
||||
object MaterialSymbolsSharp : MaterialSymbolsIcon() {
|
||||
override val Family: String = "material-symbols-sharp"
|
||||
override val DefaultResourcePath: String = "font/MaterialSymbolsSharp.ttf"
|
||||
}
|
||||
|
||||
object MaterialSymbolsRounded : MaterialSymbolsIcon() {
|
||||
override val Family: String = "material-symbols-rounded"
|
||||
override val DefaultResourcePath: String = "font/MaterialSymbolsRounded.ttf"
|
||||
}
|
||||
|
||||
/* Default positions of the four Material Symbols variable-font axes. */
|
||||
object MaterialIconAxisDefaults {
|
||||
const val Fill: Float = 0f
|
||||
const val Weight: Int = 400
|
||||
const val Grade: Int = 0
|
||||
const val OpticalSize: Int = 24
|
||||
}
|
||||
|
||||
/* Per-stack glyph renderer — receives the tint already resolved. */
|
||||
@Composable
|
||||
internal expect fun renderMaterialSymbol(
|
||||
style: MaterialSymbolsIcon,
|
||||
codepoint: Int,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier,
|
||||
tint: Color,
|
||||
size: Dp,
|
||||
fill: Float,
|
||||
weight: Int,
|
||||
grade: Int,
|
||||
opticalSize: Int,
|
||||
)
|
||||
|
||||
/* Converts a Unicode codepoint to a String, handling supplementary-plane
|
||||
codepoints (≥0x10000) via UTF-16 surrogate pairs. */
|
||||
internal fun codepointToString(codepoint: Int): String {
|
||||
if (codepoint < 0x10000) return Char(codepoint).toString()
|
||||
val adjusted = codepoint - 0x10000
|
||||
val high = (0xD800 or (adjusted shr 10)).toChar()
|
||||
val low = (0xDC00 or (adjusted and 0x3FF)).toChar()
|
||||
return charArrayOf(high, low).concatToString()
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package com.compose.sdl.icons.material.symbols
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.role
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import org.jetbrains.skia.Data
|
||||
import org.jetbrains.skia.FontMgr
|
||||
import org.jetbrains.skia.TextLine
|
||||
import org.jetbrains.skia.Font as SkFont
|
||||
import org.jetbrains.skia.FontVariation as SkFontVariation
|
||||
import org.jetbrains.skia.Paint as SkPaint
|
||||
import org.jetbrains.skia.Typeface as SkTypeface
|
||||
|
||||
// ==================
|
||||
// MARK: renderMaterialSymbol — JVM actual (Skiko direct)
|
||||
// ==================
|
||||
|
||||
/* Draws the glyph straight through Skiko (Compose Desktop's rendering
|
||||
backend): the style's variable font is loaded once, Typeface.makeClone
|
||||
instantiates the FILL / wght / GRAD / opsz axes per combination, and the
|
||||
glyph is drawn as a TextLine on the native Skia canvas.
|
||||
|
||||
Deliberately NOT the upstream Font(variationSettings) + BasicText route:
|
||||
the published desktop artifacts ignore variationSettings at typeface load,
|
||||
and even where they don't, FontCache keys typefaces by identity/weight/
|
||||
style WITHOUT the variation settings — every axes combination of the same
|
||||
resource collapses onto the first one loaded. Skiko-direct sidesteps both.
|
||||
|
||||
The app supplies the font on the JVM classpath at the style's
|
||||
DefaultResourcePath (see :demo's jvmProcessResources wiring). */
|
||||
|
||||
private val baseTypefaces = HashMap<String, SkTypeface?>()
|
||||
private val variantTypefaces = HashMap<String, SkTypeface>()
|
||||
|
||||
/* The style's font as loaded from the classpath (no axes applied), null when
|
||||
the app didn't bundle it — warned once, icon renders blank. */
|
||||
private fun baseTypeface(style: MaterialSymbolsIcon): SkTypeface? {
|
||||
if (style.Family in baseTypefaces) return baseTypefaces[style.Family]
|
||||
val bytes = MaterialSymbolsIcon::class.java.classLoader
|
||||
.getResourceAsStream(style.DefaultResourcePath)?.use { it.readBytes() }
|
||||
val typeface = bytes?.let { FontMgr.default.makeFromData(Data.makeFromBytes(it)) }
|
||||
if (typeface == null) {
|
||||
println(
|
||||
"${style.Family}: font missing at \"${style.DefaultResourcePath}\" on the JVM classpath. " +
|
||||
"Add the font to your app's jvm resources."
|
||||
)
|
||||
}
|
||||
baseTypefaces[style.Family] = typeface
|
||||
return typeface
|
||||
}
|
||||
|
||||
/* One clone per (style, axes) combination; the default axes use the font's
|
||||
own default position, no clone needed. Fill is quantised to 1/100 steps so
|
||||
ANIMATED fill values (arbitrary floats every frame) hit a bounded set of
|
||||
cached clones instead of growing the cache forever. */
|
||||
private fun variantTypeface(
|
||||
style: MaterialSymbolsIcon,
|
||||
fill: Float,
|
||||
weight: Int,
|
||||
grade: Int,
|
||||
opticalSize: Int,
|
||||
): SkTypeface? {
|
||||
val base = baseTypeface(style) ?: return null
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val fill = kotlin.math.round(fill * 100f) / 100f
|
||||
if (fill == MaterialIconAxisDefaults.Fill &&
|
||||
weight == MaterialIconAxisDefaults.Weight &&
|
||||
grade == MaterialIconAxisDefaults.Grade &&
|
||||
opticalSize == MaterialIconAxisDefaults.OpticalSize
|
||||
) return base
|
||||
val key = "${style.Family}/$fill/$weight/$grade/$opticalSize"
|
||||
return variantTypefaces.getOrPut(key) {
|
||||
base.makeClone(
|
||||
arrayOf(
|
||||
SkFontVariation("FILL", fill),
|
||||
SkFontVariation("wght", weight.toFloat()),
|
||||
SkFontVariation("GRAD", grade.toFloat()),
|
||||
SkFontVariation("opsz", opticalSize.toFloat()),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal actual fun renderMaterialSymbol(
|
||||
style: MaterialSymbolsIcon,
|
||||
codepoint: Int,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier,
|
||||
tint: Color,
|
||||
size: Dp,
|
||||
fill: Float,
|
||||
weight: Int,
|
||||
grade: Int,
|
||||
opticalSize: Int,
|
||||
) {
|
||||
val semanticsModifier =
|
||||
if (contentDescription != null) {
|
||||
Modifier.semantics {
|
||||
this.contentDescription = contentDescription
|
||||
this.role = Role.Image
|
||||
}
|
||||
} else Modifier
|
||||
Box(
|
||||
modifier
|
||||
.size(size)
|
||||
.then(semanticsModifier)
|
||||
.drawWithCache {
|
||||
val typeface = variantTypeface(style, fill, weight, grade, opticalSize)
|
||||
if (typeface == null) {
|
||||
onDrawBehind {}
|
||||
} else {
|
||||
val skFont = SkFont(typeface, this.size.height)
|
||||
val line = TextLine.make(codepointToString(codepoint), skFont)
|
||||
val paint = SkPaint().apply {
|
||||
color = tint.toArgb()
|
||||
isAntiAlias = true
|
||||
}
|
||||
// Center the glyph: x from the measured advance, baseline
|
||||
// from the line's ascent/descent (ascent is negative).
|
||||
val x = (this.size.width - line.width) / 2f
|
||||
val y = this.size.height / 2f - (line.ascent + line.descent) / 2f
|
||||
onDrawBehind {
|
||||
drawIntoCanvas { it.nativeCanvas.drawTextLine(line, x, y, paint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
@file:Suppress("PropertyName", "ConstPropertyName")
|
||||
|
||||
package com.compose.sdl.icons.material.symbols
|
||||
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
import androidx.compose.ui.text.font.FontVariation
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.compose.sdl.icons.IconDefaults
|
||||
import com.compose.sdl.icons.IconFont
|
||||
import com.compose.sdl.icons.IconFontIcon
|
||||
import com.compose.sdl.loadComposeResourceBytes
|
||||
import com.compose.sdl.text.TextRendererCapabilities
|
||||
|
||||
sealed class MaterialSymbolsIcon {
|
||||
|
||||
abstract val Family: String
|
||||
abstract val DefaultResourcePath: String
|
||||
|
||||
private var isInstalled = false
|
||||
|
||||
internal fun install(resourcePath: String = DefaultResourcePath): Boolean {
|
||||
if (isInstalled) return true
|
||||
val vBytes = loadComposeResourceBytes(resourcePath)
|
||||
if (vBytes == null) {
|
||||
println(
|
||||
"$Family: font missing at \"$resourcePath\" in data.kres. " +
|
||||
"Add the font to your app's resources."
|
||||
)
|
||||
return false
|
||||
}
|
||||
IconFont.registerIcon(Family, vBytes)
|
||||
isInstalled = true
|
||||
if (TextRendererCapabilities.supportsFontVariations == false) {
|
||||
println(
|
||||
"$Family: the active text renderer does not support variable-font axes. " +
|
||||
"Icons will render at the font's default position (wght=${MaterialIconAxisDefaults.Weight}, FILL=${MaterialIconAxisDefaults.Fill}, GRAD=${MaterialIconAxisDefaults.Grade}, opsz=${MaterialIconAxisDefaults.OpticalSize}). " +
|
||||
"fill / weight / grade / opticalSize parameters are ignored."
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Composable
|
||||
operator fun invoke(
|
||||
icon: Int,
|
||||
contentDescription: String? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = Color.Unspecified,
|
||||
size: Dp = IconDefaults.DefaultIconSize,
|
||||
fill: Float = MaterialIconAxisDefaults.Fill,
|
||||
weight: Int = MaterialIconAxisDefaults.Weight,
|
||||
grade: Int = MaterialIconAxisDefaults.Grade,
|
||||
opticalSize: Int = MaterialIconAxisDefaults.OpticalSize,
|
||||
) {
|
||||
install()
|
||||
IconFontIcon(
|
||||
codepoint = icon,
|
||||
fontFamily = Family,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = if (tint.isSpecified) tint else LocalContentColor.current,
|
||||
size = size,
|
||||
fontVariationSettings = materialIconAxes(fill, weight, grade, opticalSize),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object MaterialSymbolsOutlined : MaterialSymbolsIcon() {
|
||||
override val Family: String = "material-symbols-outlined"
|
||||
override val DefaultResourcePath: String = "font/MaterialSymbolsOutlined.ttf"
|
||||
}
|
||||
|
||||
object MaterialSymbolsSharp : MaterialSymbolsIcon() {
|
||||
override val Family: String = "material-symbols-sharp"
|
||||
override val DefaultResourcePath: String = "font/MaterialSymbolsSharp.ttf"
|
||||
}
|
||||
|
||||
object MaterialSymbolsRounded : MaterialSymbolsIcon() {
|
||||
override val Family: String = "material-symbols-rounded"
|
||||
override val DefaultResourcePath: String = "font/MaterialSymbolsRounded.ttf"
|
||||
}
|
||||
|
||||
object MaterialIconAxisDefaults {
|
||||
const val Fill: Float = 0f
|
||||
const val Weight: Int = 400
|
||||
const val Grade: Int = 0
|
||||
const val OpticalSize: Int = 24
|
||||
}
|
||||
|
||||
private fun materialIconAxes(
|
||||
fill: Float = MaterialIconAxisDefaults.Fill,
|
||||
weight: Int = MaterialIconAxisDefaults.Weight,
|
||||
grade: Int = MaterialIconAxisDefaults.Grade,
|
||||
opticalSize: Int = MaterialIconAxisDefaults.OpticalSize,
|
||||
): List<FontVariation.Setting> {
|
||||
if (fill == MaterialIconAxisDefaults.Fill &&
|
||||
weight == MaterialIconAxisDefaults.Weight &&
|
||||
grade == MaterialIconAxisDefaults.Grade &&
|
||||
opticalSize == MaterialIconAxisDefaults.OpticalSize
|
||||
) return emptyList()
|
||||
return listOf(
|
||||
FontVariation.Setting("FILL", fill),
|
||||
FontVariation.Setting("wght", weight.toFloat()),
|
||||
FontVariation.Setting("GRAD", grade.toFloat()),
|
||||
FontVariation.Setting("opsz", opticalSize.toFloat()),
|
||||
)
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.compose.sdl.icons.material.symbols
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontVariation
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.compose.sdl.icons.IconFont
|
||||
import com.compose.sdl.icons.IconFontIcon
|
||||
import com.compose.sdl.loadComposeResourceBytes
|
||||
import com.compose.sdl.text.TextRendererCapabilities
|
||||
|
||||
// ==================
|
||||
// MARK: renderMaterialSymbol — native actual (port IconFont pipeline)
|
||||
// ==================
|
||||
|
||||
/* Draws through :foundation's IconFontIcon; IconFont / the text renderers in
|
||||
:ui handle the SDL3-vs-Skia split, so this module stays renderer-unaware.
|
||||
The style's variable font is loaded once per family from data.kres. */
|
||||
|
||||
private val installedFamilies = mutableSetOf<String>()
|
||||
|
||||
/* Registers the style's font with IconFont on first use. Returns false (and
|
||||
warns) when the app's data.kres doesn't carry the font — the icon then
|
||||
renders as blank, same as before. */
|
||||
private fun ensureInstalled(style: MaterialSymbolsIcon): Boolean {
|
||||
if (style.Family in installedFamilies) return true
|
||||
val bytes = loadComposeResourceBytes(style.DefaultResourcePath)
|
||||
if (bytes == null) {
|
||||
println(
|
||||
"${style.Family}: font missing at \"${style.DefaultResourcePath}\" in data.kres. " +
|
||||
"Add the font to your app's resources."
|
||||
)
|
||||
return false
|
||||
}
|
||||
IconFont.registerIcon(style.Family, bytes)
|
||||
installedFamilies.add(style.Family)
|
||||
if (TextRendererCapabilities.supportsFontVariations == false) {
|
||||
println(
|
||||
"${style.Family}: the active text renderer does not support variable-font axes. " +
|
||||
"Icons will render at the font's default position (wght=${MaterialIconAxisDefaults.Weight}, FILL=${MaterialIconAxisDefaults.Fill}, GRAD=${MaterialIconAxisDefaults.Grade}, opsz=${MaterialIconAxisDefaults.OpticalSize}). " +
|
||||
"fill / weight / grade / opticalSize parameters are ignored."
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal actual fun renderMaterialSymbol(
|
||||
style: MaterialSymbolsIcon,
|
||||
codepoint: Int,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier,
|
||||
tint: Color,
|
||||
size: Dp,
|
||||
fill: Float,
|
||||
weight: Int,
|
||||
grade: Int,
|
||||
opticalSize: Int,
|
||||
) {
|
||||
ensureInstalled(style)
|
||||
IconFontIcon(
|
||||
codepoint = codepoint,
|
||||
fontFamily = style.Family,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint,
|
||||
size = size,
|
||||
fontVariationSettings = materialIconAxes(fill, weight, grade, opticalSize),
|
||||
)
|
||||
}
|
||||
|
||||
/* Axis list for IconFontIcon — empty at the defaults so the renderers skip
|
||||
the variable-font instancing path entirely. */
|
||||
private fun materialIconAxes(
|
||||
fill: Float,
|
||||
weight: Int,
|
||||
grade: Int,
|
||||
opticalSize: Int,
|
||||
): List<FontVariation.Setting> {
|
||||
if (fill == MaterialIconAxisDefaults.Fill &&
|
||||
weight == MaterialIconAxisDefaults.Weight &&
|
||||
grade == MaterialIconAxisDefaults.Grade &&
|
||||
opticalSize == MaterialIconAxisDefaults.OpticalSize
|
||||
) return emptyList()
|
||||
return listOf(
|
||||
FontVariation.Setting("FILL", fill),
|
||||
FontVariation.Setting("wght", weight.toFloat()),
|
||||
FontVariation.Setting("GRAD", grade.toFloat()),
|
||||
FontVariation.Setting("opsz", opticalSize.toFloat()),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user