mirror of
https://github.com/danbulant/cushy
synced 2026-06-19 22:41:10 +00:00
More progress on input/event handling
This commit is contained in:
parent
ff9fa043c3
commit
983b6a97ad
16 changed files with 957 additions and 388 deletions
197
Cargo.lock
generated
197
Cargo.lock
generated
|
|
@ -44,12 +44,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aliasable"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
|
|
@ -64,12 +58,12 @@ checksum = "0f1063fbee2ac6d371ffcb55cb443f4d5b469f1b8eace60042878242bb534169"
|
|||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.5.0-beta.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "934936a9ad4dc79563cd6644fcef68dc328f105d927679454de39ad03ca1cfe8"
|
||||
checksum = "052ad56e336bcc615a214bffbeca6c181ee9550acec193f0327e0b103b033a4d"
|
||||
dependencies = [
|
||||
"android-properties",
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"cc",
|
||||
"cesu8",
|
||||
"jni",
|
||||
|
|
@ -101,9 +95,9 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "appit"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/khonsulabs/appit#0503b3d4668ec9e153952e509462216a2c5d85a9"
|
||||
source = "git+https://github.com/khonsulabs/appit#665107f59b0d1b1cc6780800fa1e172faf615f07"
|
||||
dependencies = [
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.5.2",
|
||||
"winit",
|
||||
]
|
||||
|
||||
|
|
@ -184,9 +178,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
|
|
@ -367,16 +361,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cosmic-text"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0b68966c2543609f8d92f9d33ac3b719b2a67529b0c6c0b3e025637b477eef9"
|
||||
checksum = "75acbfb314aeb4f5210d379af45ed1ec2c98c7f1790bf57b8a4c562ac0c51b71"
|
||||
dependencies = [
|
||||
"aliasable",
|
||||
"fontdb",
|
||||
"libm",
|
||||
"log",
|
||||
"rangemap",
|
||||
"rustc-hash",
|
||||
"rustybuzz",
|
||||
"self_cell",
|
||||
"swash",
|
||||
"sys-locale",
|
||||
"unicode-bidi",
|
||||
|
|
@ -397,7 +392,7 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16e44ab292b1dddfdaf7be62cfd8877df52f2f3fde5858d95bab606be259f20"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"libloading 0.8.1",
|
||||
"winapi",
|
||||
]
|
||||
|
|
@ -475,16 +470,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fontdb"
|
||||
version = "0.14.1"
|
||||
name = "fontconfig-parser"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af8d8cbea8f21307d7e84bca254772981296f058a1d36b461bf4d83a7499fc9e"
|
||||
checksum = "674e258f4b5d2dcd63888c01c68413c51f565e8af99d2f7701c7b81d79ef41c4"
|
||||
dependencies = [
|
||||
"roxmltree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontdb"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "020e203f177c0fb250fb19455a252e838d2bbbce1f80f25ecc42402aafa8cd38"
|
||||
dependencies = [
|
||||
"fontconfig-parser",
|
||||
"log",
|
||||
"memmap2 0.6.2",
|
||||
"memmap2 0.8.0",
|
||||
"slotmap",
|
||||
"tinyvec",
|
||||
"ttf-parser",
|
||||
"ttf-parser 0.19.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -572,7 +577,7 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"gpu-alloc-types",
|
||||
]
|
||||
|
||||
|
|
@ -582,7 +587,7 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -604,9 +609,9 @@ version = "0.2.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"gpu-descriptor-types",
|
||||
"hashbrown 0.14.1",
|
||||
"hashbrown 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -615,7 +620,7 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -626,9 +631,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.1"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
|
|
@ -702,7 +707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.1",
|
||||
"hashbrown 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -776,7 +781,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "kludgine"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/khonsulabs/kludgine#6f8df041075f1c25f30cb53a134f06931c1b7a37"
|
||||
source = "git+https://github.com/khonsulabs/kludgine#80d722cbf4fbb1e1819f2b5ab8cb52bb331e9cf4"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"alot",
|
||||
|
|
@ -838,9 +843,9 @@ checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
|||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
|
|
@ -910,9 +915,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.6.2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872"
|
||||
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
@ -941,7 +946,7 @@ version = "0.26.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "623b5e6cefd76e58f774bd3cc0c6f5c7615c58c03a97815245a25c3c9bdee318"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"block",
|
||||
"core-graphics-types",
|
||||
"foreign-types 0.5.0",
|
||||
|
|
@ -972,7 +977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c1ceaaa4eedaece7e4ec08c55c640ba03dbb73fb812a6570a59bcf1930d0f70e"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"codespan-reporting",
|
||||
"hexf-parse",
|
||||
"indexmap 1.9.3",
|
||||
|
|
@ -987,16 +992,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.8.0-beta.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f58741784b0f6ac12311c3f6fbdb3c766a992f8914d035c77a07b5fd2940dc"
|
||||
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.6.0",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
|
@ -1008,9 +1013,9 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
|||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.5.0-beta.0+25.2.9519653"
|
||||
version = "0.5.0+25.2.9519653"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff38603775cba10d0f1141fab1b167df73662a0636a4b631c187fe11fb624042"
|
||||
checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
|
@ -1164,7 +1169,7 @@ version = "0.3.46"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8378ac0dfbd4e7895f2d2c1f1345cab3836910baf3a300b000d04250f0c8428f"
|
||||
dependencies = [
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.3.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1173,7 +1178,7 @@ version = "0.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4"
|
||||
dependencies = [
|
||||
"ttf-parser",
|
||||
"ttf-parser 0.19.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1188,13 +1193,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.8"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
|
@ -1284,6 +1289,12 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
|
|
@ -1293,12 +1304,30 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "renderdoc-sys"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b"
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "862340e351ce1b271a378ec53f304a5558f7db87f3769dc655a8f6ecbb68b302"
|
||||
dependencies = [
|
||||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
|
|
@ -1313,11 +1342,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.19"
|
||||
version = "0.38.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
|
||||
checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
|
@ -1326,18 +1355,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustybuzz"
|
||||
version = "0.8.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82eea22c8f56965eeaf3a209b3d24508256c7b920fb3b6211b8ba0f7c0583250"
|
||||
checksum = "2ee8fe2a8461a0854a37101fe7a1b13998d0cfa987e43248e81d2a5f4570f6fa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
"libm",
|
||||
"smallvec",
|
||||
"ttf-parser",
|
||||
"ttf-parser 0.20.0",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-general-category",
|
||||
"unicode-properties",
|
||||
"unicode-script",
|
||||
]
|
||||
|
||||
|
|
@ -1375,6 +1404,12 @@ dependencies = [
|
|||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.189"
|
||||
|
|
@ -1512,18 +1547,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.49"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.49"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1593,6 +1628,12 @@ version = "0.19.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
|
|
@ -1611,12 +1652,6 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-general-category"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
|
|
@ -1629,6 +1664,12 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-script"
|
||||
version = "0.5.5"
|
||||
|
|
@ -1861,7 +1902,7 @@ dependencies = [
|
|||
"naga",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.5.2",
|
||||
"smallvec",
|
||||
"static_assertions",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -1880,13 +1921,13 @@ checksum = "0f8a44dd301a30ceeed3c27d8c0090433d3da04d7b2a4042738095a424d12ae7"
|
|||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-vec",
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"codespan-reporting",
|
||||
"log",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.5.2",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
|
|
@ -1905,7 +1946,7 @@ dependencies = [
|
|||
"arrayvec",
|
||||
"ash",
|
||||
"bit-set",
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"block",
|
||||
"core-graphics-types",
|
||||
"d3d12",
|
||||
|
|
@ -1925,7 +1966,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.5.2",
|
||||
"renderdoc-sys",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
|
|
@ -1942,7 +1983,7 @@ version = "0.17.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee64d7398d0c2f9ca48922c902ef69c42d000c759f3db41e355f4a570b052b67"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"js-sys",
|
||||
"web-sys",
|
||||
]
|
||||
|
|
@ -2142,7 +2183,7 @@ checksum = "ab977231134a3123c5382f0358b728118e70c216ec99017aa24e9eed35d5e3e1"
|
|||
dependencies = [
|
||||
"android-activity",
|
||||
"atomic-waker",
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"bytemuck",
|
||||
"calloop",
|
||||
"cfg_aliases",
|
||||
|
|
@ -2161,8 +2202,8 @@ dependencies = [
|
|||
"once_cell",
|
||||
"orbclient",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"redox_syscall",
|
||||
"raw-window-handle 0.5.2",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"sctk-adwaita",
|
||||
"smithay-client-toolkit",
|
||||
|
|
@ -2242,7 +2283,7 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6924668544c48c0133152e7eec86d644a056ca3d09275eb8d5cdb9855f9d8699"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.1",
|
||||
"dlib",
|
||||
"log",
|
||||
"once_cell",
|
||||
|
|
@ -2255,6 +2296,12 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621"
|
||||
|
||||
[[package]]
|
||||
name = "xmlparser"
|
||||
version = "0.13.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
|
||||
|
||||
[[package]]
|
||||
name = "yazi"
|
||||
version = "0.1.6"
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ use kludgine::Color;
|
|||
|
||||
fn main() -> gooey::Result<()> {
|
||||
let mut angle = Angle::degrees(0);
|
||||
Canvas::new(move |graphics, _window| {
|
||||
Canvas::new(move |context| {
|
||||
angle += Angle::degrees(1);
|
||||
|
||||
let center = Point::from(graphics.size()).into_signed() / 2;
|
||||
graphics.draw_text(
|
||||
let center = Point::from(context.graphics.size()).into_signed() / 2;
|
||||
context.graphics.draw_text(
|
||||
"Canvas exposes the full power of Kludgine",
|
||||
Color::WHITE,
|
||||
kludgine::text::TextOrigin::Center,
|
||||
|
|
@ -20,7 +20,7 @@ fn main() -> gooey::Result<()> {
|
|||
None,
|
||||
None,
|
||||
);
|
||||
graphics.draw_shape(
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(Point::new(Px(-50), Px(-50)), Size::new(Px(100), Px(100))),
|
||||
Color::RED,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use gooey::dynamic::Dynamic;
|
||||
use gooey::widget::Widget;
|
||||
use gooey::widgets::{Button, Input};
|
||||
use gooey::widgets::Input;
|
||||
use gooey::EventLoopError;
|
||||
|
||||
fn main() -> Result<(), EventLoopError> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use gooey::children::Children;
|
||||
use gooey::styles::{Styles, TextColor};
|
||||
use gooey::widget::Widget;
|
||||
use gooey::widgets::array::Array;
|
||||
use gooey::widgets::{Button, Style};
|
||||
use gooey::window::Window;
|
||||
|
|
@ -10,11 +11,12 @@ fn main() -> Result<(), EventLoopError> {
|
|||
Window::for_widget(Array::rows(
|
||||
Children::new()
|
||||
.with_widget(Button::new("Default"))
|
||||
.with_widget(Style::new(
|
||||
Styles::new().with(&TextColor, Color::RED),
|
||||
Button::new("Styled"),
|
||||
)),
|
||||
.with_widget(styled(Button::new("Styled"))),
|
||||
))
|
||||
.styles(Styles::new().with(&TextColor, Color::GREEN))
|
||||
.run()
|
||||
}
|
||||
|
||||
fn styled(w: impl Widget) -> Style {
|
||||
Style::new(Styles::new().with(&TextColor, Color::RED), w)
|
||||
}
|
||||
|
|
|
|||
396
src/context.rs
396
src/context.rs
|
|
@ -1,80 +1,35 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use kludgine::app::winit::event::{DeviceId, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase};
|
||||
use kludgine::app::winit::event::{
|
||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
};
|
||||
use kludgine::figures::units::{Px, UPx};
|
||||
use kludgine::figures::{IntoSigned, Point, Rect, Size};
|
||||
use kludgine::shapes::{Shape, StrokeOptions};
|
||||
use kludgine::Kludgine;
|
||||
|
||||
use crate::dynamic::Dynamic;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::styles::{ComponentDefaultvalue, Styles};
|
||||
use crate::styles::{ComponentDefaultvalue, HighlightColor, Styles};
|
||||
use crate::widget::{BoxedWidget, EventHandling, ManagedWidget};
|
||||
use crate::window::RunningWindow;
|
||||
use crate::ConstraintLimit;
|
||||
|
||||
pub struct Context<'context, 'window> {
|
||||
current_node: &'context ManagedWidget,
|
||||
window: &'context mut RunningWindow<'window>,
|
||||
pending_state: PendingState<'context>,
|
||||
pub struct EventContext<'context, 'window> {
|
||||
pub widget: WidgetContext<'context, 'window>,
|
||||
pub kludgine: &'context mut Kludgine,
|
||||
}
|
||||
|
||||
impl<'context, 'window> Context<'context, 'window> {
|
||||
pub fn new(
|
||||
current_node: &'context ManagedWidget,
|
||||
window: &'context mut RunningWindow<'window>,
|
||||
) -> Self {
|
||||
Self {
|
||||
current_node,
|
||||
window,
|
||||
pending_state: PendingState::Owned(PendingWidgetState {
|
||||
focus: current_node
|
||||
.tree
|
||||
.focused_widget()
|
||||
.map(|id| current_node.tree.widget(id)),
|
||||
active: current_node
|
||||
.tree
|
||||
.active_widget()
|
||||
.map(|id| current_node.tree.widget(id)),
|
||||
}),
|
||||
}
|
||||
impl<'context, 'window> EventContext<'context, 'window> {
|
||||
pub fn new(widget: WidgetContext<'context, 'window>, kludgine: &'context mut Kludgine) -> Self {
|
||||
Self { widget, kludgine }
|
||||
}
|
||||
|
||||
pub fn for_other<'child>(
|
||||
&'child mut self,
|
||||
widget: &'child ManagedWidget,
|
||||
) -> Context<'child, 'window> {
|
||||
Context {
|
||||
current_node: widget,
|
||||
window: &mut *self.window,
|
||||
pending_state: self.pending_state.borrowed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parent(&self) -> Option<ManagedWidget> {
|
||||
self.current_node.parent()
|
||||
}
|
||||
|
||||
pub fn redraw_when_changed<T>(&self, value: &Dynamic<T>) {
|
||||
value.redraw_when_changed(self.window.handle());
|
||||
}
|
||||
|
||||
pub fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>) {
|
||||
// TODO this should not use clip_rect, because it forces UPx, and once
|
||||
// we have scrolling, we can have negative offsets of rectangles where
|
||||
// it's clipped partially.
|
||||
self.current_node
|
||||
.note_rendered_rect(graphics.clip_rect().into_signed());
|
||||
self.current_node.lock().redraw(graphics, self);
|
||||
}
|
||||
|
||||
pub fn measure(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
graphics: &mut Graphics<'_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
self.current_node
|
||||
.lock()
|
||||
.measure(available_space, graphics, self)
|
||||
) -> EventContext<'child, 'window> {
|
||||
EventContext::new(self.widget.for_other(widget), self.kludgine)
|
||||
}
|
||||
|
||||
pub fn hit_test(&mut self, location: Point<Px>) -> bool {
|
||||
|
|
@ -114,11 +69,14 @@ impl<'context, 'window> Context<'context, 'window> {
|
|||
device_id: DeviceId,
|
||||
input: KeyEvent,
|
||||
is_synthetic: bool,
|
||||
kludgine: &mut Kludgine,
|
||||
) -> EventHandling {
|
||||
self.current_node
|
||||
.lock()
|
||||
.keyboard_input(device_id, input, is_synthetic, kludgine, self)
|
||||
.keyboard_input(device_id, input, is_synthetic, self)
|
||||
}
|
||||
|
||||
pub fn ime(&mut self, ime: Ime) -> EventHandling {
|
||||
self.current_node.lock().ime(ime, self)
|
||||
}
|
||||
|
||||
pub fn mouse_wheel(
|
||||
|
|
@ -132,30 +90,6 @@ impl<'context, 'window> Context<'context, 'window> {
|
|||
.mouse_wheel(device_id, delta, phase, self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn push_child(&mut self, child: BoxedWidget) -> ManagedWidget {
|
||||
let pushed_widget = self
|
||||
.current_node
|
||||
.tree
|
||||
.push_boxed(child, Some(self.current_node));
|
||||
pushed_widget
|
||||
.lock()
|
||||
.mounted(&mut self.for_other(&pushed_widget));
|
||||
pushed_widget
|
||||
}
|
||||
|
||||
pub fn remove_child(&mut self, child: &ManagedWidget) {
|
||||
self.current_node
|
||||
.tree
|
||||
.remove_child(child, self.current_node);
|
||||
child.lock().unmounted(&mut self.for_other(child));
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn last_rendered_at(&self) -> Option<Rect<Px>> {
|
||||
self.current_node.last_rendered_at()
|
||||
}
|
||||
|
||||
pub(crate) fn hover(&mut self, location: Point<Px>) {
|
||||
let newly_hovered = match self.current_node.tree.hover(Some(self.current_node)) {
|
||||
Ok(old_hover) => {
|
||||
|
|
@ -178,6 +112,250 @@ impl<'context, 'window> Context<'context, 'window> {
|
|||
old_hover.lock().unhover(&mut old_hover_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'context, 'window> Deref for EventContext<'context, 'window> {
|
||||
type Target = WidgetContext<'context, 'window>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.widget
|
||||
}
|
||||
}
|
||||
|
||||
impl<'context, 'window> DerefMut for EventContext<'context, 'window> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.widget
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Exclusive<'a, T> {
|
||||
Borrowed(&'a mut T),
|
||||
Owned(T),
|
||||
}
|
||||
|
||||
impl<T> Deref for Exclusive<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Exclusive::Borrowed(wrapped) => wrapped,
|
||||
Exclusive::Owned(wrapped) => wrapped,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Exclusive<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match self {
|
||||
Exclusive::Borrowed(wrapped) => wrapped,
|
||||
Exclusive::Owned(wrapped) => wrapped,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass> {
|
||||
pub widget: WidgetContext<'context, 'window>,
|
||||
pub graphics: Exclusive<'context, Graphics<'clip, 'gfx, 'pass>>,
|
||||
}
|
||||
|
||||
impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass> {
|
||||
pub fn for_other<'child>(
|
||||
&'child mut self,
|
||||
widget: &'child ManagedWidget,
|
||||
) -> GraphicsContext<'child, 'window, 'clip, 'gfx, 'pass> {
|
||||
GraphicsContext {
|
||||
widget: self.widget.for_other(widget),
|
||||
graphics: Exclusive::Borrowed(&mut *self.graphics),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn measure(&mut self, available_space: Size<ConstraintLimit>) -> Size<UPx> {
|
||||
self.current_node.lock().measure(available_space, self)
|
||||
}
|
||||
|
||||
pub fn redraw(&mut self) {
|
||||
// TODO this should not use clip_rect, because it forces UPx, and once
|
||||
// we have scrolling, we can have negative offsets of rectangles where
|
||||
// it's clipped partially.
|
||||
self.current_node
|
||||
.note_rendered_rect(self.graphics.clip_rect().into_signed());
|
||||
self.current_node.lock().redraw(self);
|
||||
}
|
||||
|
||||
pub fn clipped_to(&mut self, clip: Rect<UPx>) -> GraphicsContext<'_, 'window, '_, 'gfx, 'pass> {
|
||||
GraphicsContext {
|
||||
widget: self.widget.borrowed(),
|
||||
graphics: Exclusive::Owned(self.graphics.clipped_to(clip)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_focus_ring(&mut self, styles: &Styles) {
|
||||
let visible_rect = Rect::from(self.graphics.size() - (UPx(1), UPx(1)));
|
||||
let focus_ring = Shape::stroked_rect(
|
||||
visible_rect,
|
||||
styles.get_or_default(&HighlightColor),
|
||||
StrokeOptions::default(),
|
||||
);
|
||||
self.graphics
|
||||
.draw_shape(&focus_ring, Point::default(), None, None);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'context, 'window, 'clip, 'gfx, 'pass> Deref
|
||||
for GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>
|
||||
{
|
||||
type Target = WidgetContext<'context, 'window>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.widget
|
||||
}
|
||||
}
|
||||
|
||||
impl<'context, 'window, 'clip, 'gfx, 'pass> DerefMut
|
||||
for GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.widget
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsEventContext<'window> {
|
||||
fn as_event_context(&mut self) -> EventContext<'_, 'window>;
|
||||
|
||||
#[must_use]
|
||||
fn push_child(&mut self, child: BoxedWidget) -> ManagedWidget {
|
||||
let mut context = self.as_event_context();
|
||||
let pushed_widget = context
|
||||
.current_node
|
||||
.tree
|
||||
.push_boxed(child, Some(context.current_node));
|
||||
pushed_widget
|
||||
.lock()
|
||||
.mounted(&mut context.for_other(&pushed_widget));
|
||||
pushed_widget
|
||||
}
|
||||
|
||||
fn remove_child(&mut self, child: &ManagedWidget) {
|
||||
let mut context = self.as_event_context();
|
||||
context
|
||||
.current_node
|
||||
.tree
|
||||
.remove_child(child, context.current_node);
|
||||
child.lock().unmounted(&mut context.for_other(child));
|
||||
}
|
||||
|
||||
fn apply_pending_state(&mut self) {
|
||||
let mut context = self.as_event_context();
|
||||
let active = context.pending_state.active.take();
|
||||
if context.current_node.tree.active_widget() != active.as_ref().map(|active| active.id) {
|
||||
let new = match context.current_node.tree.activate(active.as_ref()) {
|
||||
Ok(old) => {
|
||||
if let Some(old) = old {
|
||||
let mut old_context = context.for_other(&old);
|
||||
old.lock().deactivate(&mut old_context);
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
};
|
||||
if new {
|
||||
if let Some(active) = active {
|
||||
active.lock().activate(&mut context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let focus = context.pending_state.focus.take();
|
||||
if context.current_node.tree.focused_widget() != focus.as_ref().map(|focus| focus.id) {
|
||||
let new = match context.current_node.tree.focus(focus.as_ref()) {
|
||||
Ok(old) => {
|
||||
if let Some(old) = old {
|
||||
let mut old_context = context.for_other(&old);
|
||||
old.lock().blur(&mut old_context);
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
};
|
||||
if new {
|
||||
if let Some(focus) = focus {
|
||||
focus.lock().focus(&mut context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'window> AsEventContext<'window> for EventContext<'_, 'window> {
|
||||
fn as_event_context(&mut self) -> EventContext<'_, 'window> {
|
||||
EventContext::new(self.widget.borrowed(), self.kludgine)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'window> AsEventContext<'window> for GraphicsContext<'_, 'window, '_, '_, '_> {
|
||||
fn as_event_context(&mut self) -> EventContext<'_, 'window> {
|
||||
EventContext::new(self.widget.borrowed(), &mut self.graphics)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WidgetContext<'context, 'window> {
|
||||
current_node: &'context ManagedWidget,
|
||||
window: &'context mut RunningWindow<'window>,
|
||||
pending_state: PendingState<'context>,
|
||||
}
|
||||
|
||||
impl<'context, 'window> WidgetContext<'context, 'window> {
|
||||
pub(crate) fn new(
|
||||
current_node: &'context ManagedWidget,
|
||||
window: &'context mut RunningWindow<'window>,
|
||||
) -> Self {
|
||||
Self {
|
||||
current_node,
|
||||
window,
|
||||
pending_state: PendingState::Owned(PendingWidgetState {
|
||||
focus: current_node
|
||||
.tree
|
||||
.focused_widget()
|
||||
.map(|id| current_node.tree.widget(id)),
|
||||
active: current_node
|
||||
.tree
|
||||
.active_widget()
|
||||
.map(|id| current_node.tree.widget(id)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrowed(&mut self) -> WidgetContext<'_, 'window> {
|
||||
WidgetContext {
|
||||
current_node: self.current_node,
|
||||
window: &mut *self.window,
|
||||
pending_state: self.pending_state.borrowed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_other<'child>(
|
||||
&'child mut self,
|
||||
widget: &'child ManagedWidget,
|
||||
) -> WidgetContext<'child, 'window> {
|
||||
WidgetContext {
|
||||
current_node: widget,
|
||||
window: &mut *self.window,
|
||||
pending_state: self.pending_state.borrowed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parent(&self) -> Option<ManagedWidget> {
|
||||
self.current_node.parent()
|
||||
}
|
||||
|
||||
pub fn redraw_when_changed<T>(&self, value: &Dynamic<T>) {
|
||||
value.redraw_when_changed(self.window.handle());
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn last_rendered_at(&self) -> Option<Rect<Px>> {
|
||||
self.current_node.last_rendered_at()
|
||||
}
|
||||
|
||||
pub fn focus(&mut self) {
|
||||
self.pending_state.focus = Some(self.current_node.clone());
|
||||
|
|
@ -238,46 +416,6 @@ impl<'context, 'window> Context<'context, 'window> {
|
|||
self.pending_state.focus.as_ref() == Some(self.current_node)
|
||||
}
|
||||
|
||||
fn apply_pending_state(&mut self) {
|
||||
let active = self.pending_state.active.take();
|
||||
if self.current_node.tree.active_widget() != active.as_ref().map(|active| active.id) {
|
||||
let new = match self.current_node.tree.activate(active.as_ref()) {
|
||||
Ok(old) => {
|
||||
if let Some(old) = old {
|
||||
let mut old_context = self.for_other(&old);
|
||||
old.lock().deactivate(&mut old_context);
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
};
|
||||
if new {
|
||||
if let Some(active) = active {
|
||||
active.lock().activate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let focus = self.pending_state.focus.take();
|
||||
if self.current_node.tree.focused_widget() != focus.as_ref().map(|focus| focus.id) {
|
||||
let new = match self.current_node.tree.focus(focus.as_ref()) {
|
||||
Ok(old) => {
|
||||
if let Some(old) = old {
|
||||
let mut old_context = self.for_other(&old);
|
||||
old.lock().blur(&mut old_context);
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
};
|
||||
if new {
|
||||
if let Some(focus) = focus {
|
||||
focus.lock().focus(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn widget(&self) -> &ManagedWidget {
|
||||
self.current_node
|
||||
|
|
@ -293,22 +431,24 @@ impl<'context, 'window> Context<'context, 'window> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for Context<'_, '_> {
|
||||
impl dyn AsEventContext<'_> {}
|
||||
|
||||
impl Drop for EventContext<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
if matches!(self.pending_state, PendingState::Owned(_)) {
|
||||
if matches!(self.widget.pending_state, PendingState::Owned(_)) {
|
||||
self.apply_pending_state();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'window> Deref for Context<'_, 'window> {
|
||||
impl<'window> Deref for WidgetContext<'_, 'window> {
|
||||
type Target = RunningWindow<'window>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.window
|
||||
}
|
||||
}
|
||||
impl<'window> DerefMut for Context<'_, 'window> {
|
||||
impl<'window> DerefMut for WidgetContext<'_, 'window> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.window
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ use kludgine::figures::units::UPx;
|
|||
use kludgine::figures::Rect;
|
||||
|
||||
pub struct Graphics<'clip, 'gfx, 'pass> {
|
||||
renderer: GraphicsContext<'clip, 'gfx, 'pass>,
|
||||
renderer: RenderContext<'clip, 'gfx, 'pass>,
|
||||
}
|
||||
|
||||
enum GraphicsContext<'clip, 'gfx, 'pass> {
|
||||
enum RenderContext<'clip, 'gfx, 'pass> {
|
||||
Renderer(kludgine::render::Renderer<'gfx, 'pass>),
|
||||
Clipped(kludgine::ClipGuard<'clip, kludgine::render::Renderer<'gfx, 'pass>>),
|
||||
}
|
||||
|
|
@ -16,13 +16,13 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
|
|||
#[must_use]
|
||||
pub fn new(renderer: kludgine::render::Renderer<'gfx, 'pass>) -> Self {
|
||||
Self {
|
||||
renderer: GraphicsContext::Renderer(renderer),
|
||||
renderer: RenderContext::Renderer(renderer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clipped_to(&mut self, clip: Rect<UPx>) -> Graphics<'_, 'gfx, 'pass> {
|
||||
Graphics {
|
||||
renderer: GraphicsContext::Clipped(self.deref_mut().clipped_to(clip)),
|
||||
renderer: RenderContext::Clipped(self.deref_mut().clipped_to(clip)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,8 +32,8 @@ impl<'gfx, 'pass> Deref for Graphics<'_, 'gfx, 'pass> {
|
|||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match &self.renderer {
|
||||
GraphicsContext::Renderer(renderer) => renderer,
|
||||
GraphicsContext::Clipped(clipped) => clipped,
|
||||
RenderContext::Renderer(renderer) => renderer,
|
||||
RenderContext::Clipped(clipped) => clipped,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,8 +41,8 @@ impl<'gfx, 'pass> Deref for Graphics<'_, 'gfx, 'pass> {
|
|||
impl<'gfx, 'pass> DerefMut for Graphics<'_, 'gfx, 'pass> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match &mut self.renderer {
|
||||
GraphicsContext::Renderer(renderer) => renderer,
|
||||
GraphicsContext::Clipped(clipped) => &mut *clipped,
|
||||
RenderContext::Renderer(renderer) => renderer,
|
||||
RenderContext::Clipped(clipped) => &mut *clipped,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ use std::fmt::Debug;
|
|||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
|
||||
use kludgine::figures::units::{Lp, Px};
|
||||
use kludgine::figures::ScreenScale;
|
||||
use kludgine::Color;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -155,6 +156,33 @@ impl From<Lp> for Dimension {
|
|||
}
|
||||
}
|
||||
|
||||
impl ScreenScale for Dimension {
|
||||
type Lp = Lp;
|
||||
type Px = Px;
|
||||
|
||||
fn into_px(self, scale: kludgine::figures::Fraction) -> Px {
|
||||
match self {
|
||||
Dimension::Px(px) => px,
|
||||
Dimension::Lp(lp) => lp.into_px(scale),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_px(px: Px, _scale: kludgine::figures::Fraction) -> Self {
|
||||
Self::from(px)
|
||||
}
|
||||
|
||||
fn into_lp(self, scale: kludgine::figures::Fraction) -> Lp {
|
||||
match self {
|
||||
Dimension::Px(px) => px.into_lp(scale),
|
||||
Dimension::Lp(lp) => lp,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_lp(lp: Lp, _scale: kludgine::figures::Fraction) -> Self {
|
||||
Self::from(lp)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoxedComponent(Arc<dyn AnyComponent>);
|
||||
|
||||
|
|
@ -280,6 +308,40 @@ impl NamedComponent for Cow<'_, ComponentName> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct TextSize;
|
||||
|
||||
impl NamedComponent for TextSize {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("text_size"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for TextSize {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self) -> Dimension {
|
||||
Dimension::Lp(Lp::points(12))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct LineHeight;
|
||||
|
||||
impl NamedComponent for LineHeight {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("line_height"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for LineHeight {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self) -> Dimension {
|
||||
Dimension::Lp(Lp::points(14))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct TextColor;
|
||||
|
||||
|
|
|
|||
22
src/utils.rs
22
src/utils.rs
|
|
@ -1,10 +1,12 @@
|
|||
use std::ops::Deref;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use kludgine::app::winit::event::Modifiers;
|
||||
use kludgine::app::winit::keyboard::ModifiersState;
|
||||
|
||||
pub trait ModifiersExt {
|
||||
fn primary(&self) -> bool;
|
||||
fn word_select(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ModifiersExt for ModifiersState {
|
||||
|
|
@ -17,6 +19,26 @@ impl ModifiersExt for ModifiersState {
|
|||
fn primary(&self) -> bool {
|
||||
self.control_key()
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
fn word_select(&self) -> bool {
|
||||
self.alt_key()
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
fn word_select(&self) -> bool {
|
||||
self.control_key()
|
||||
}
|
||||
}
|
||||
|
||||
impl ModifiersExt for Modifiers {
|
||||
fn primary(&self) -> bool {
|
||||
self.state().primary()
|
||||
}
|
||||
|
||||
fn word_select(&self) -> bool {
|
||||
self.state().word_select()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lazy<T> {
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ use std::panic::UnwindSafe;
|
|||
use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
|
||||
|
||||
use kludgine::app::winit::error::EventLoopError;
|
||||
use kludgine::app::winit::event::{DeviceId, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase};
|
||||
use kludgine::app::winit::event::{
|
||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
};
|
||||
use kludgine::figures::units::{Px, UPx};
|
||||
use kludgine::figures::{Point, Rect, Size};
|
||||
use kludgine::Kludgine;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::context::{EventContext, GraphicsContext};
|
||||
use crate::dynamic::Dynamic;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::styles::{Component, Group, Styles};
|
||||
use crate::tree::{Tree, WidgetId};
|
||||
use crate::window::{RunningWindow, Window, WindowBehavior};
|
||||
|
|
@ -26,42 +26,41 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
Window::<BoxedWidget>::new(BoxedWidget::new(self)).run()
|
||||
}
|
||||
|
||||
fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context<'_, '_>);
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>);
|
||||
|
||||
fn measure(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
graphics: &mut Graphics<'_, '_, '_>,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx>;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn mounted(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn mounted(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
#[allow(unused_variables)]
|
||||
fn unmounted(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn unmounted(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn hit_test(&mut self, location: Point<Px>, context: &mut Context<'_, '_>) -> bool {
|
||||
fn hit_test(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn hover(&mut self, location: Point<Px>, context: &mut Context<'_, '_>) {}
|
||||
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn unhover(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn focus(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn blur(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn blur(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn activate(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn activate(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn deactivate(&mut self, context: &mut Context<'_, '_>) {}
|
||||
fn deactivate(&mut self, context: &mut EventContext<'_, '_>) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn mouse_down(
|
||||
|
|
@ -69,7 +68,7 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
location: Point<Px>,
|
||||
device_id: DeviceId,
|
||||
button: MouseButton,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
UNHANDLED
|
||||
}
|
||||
|
|
@ -80,7 +79,7 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
location: Point<Px>,
|
||||
device_id: DeviceId,
|
||||
button: MouseButton,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +89,7 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
location: Option<Point<Px>>,
|
||||
device_id: DeviceId,
|
||||
button: MouseButton,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -100,11 +99,14 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
device_id: DeviceId,
|
||||
input: KeyEvent,
|
||||
is_synthetic: bool,
|
||||
kludgine: &mut Kludgine,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
UNHANDLED
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn ime(&mut self, ime: Ime, context: &mut EventContext<'_, '_>) -> EventHandling {
|
||||
UNHANDLED
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn mouse_wheel(
|
||||
|
|
@ -112,7 +114,7 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
|||
device_id: DeviceId,
|
||||
delta: MouseScrollDelta,
|
||||
phase: TouchPhase,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
UNHANDLED
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ use kludgine::figures::units::UPx;
|
|||
use kludgine::figures::{Point, Rect, Size};
|
||||
|
||||
use crate::children::Children;
|
||||
use crate::context::Context;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext};
|
||||
use crate::widget::{IntoValue, ManagedWidget, Value, Widget};
|
||||
use crate::ConstraintLimit;
|
||||
|
||||
|
|
@ -45,7 +44,7 @@ impl Array {
|
|||
Self::new(ArrayDirection::rows(), children)
|
||||
}
|
||||
|
||||
fn synchronize_children(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn synchronize_children(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
let current_generation = self.children.generation();
|
||||
if current_generation.map_or_else(
|
||||
|| self.children.map(Children::len) != self.layout.children.len(),
|
||||
|
|
@ -91,30 +90,30 @@ impl Array {
|
|||
}
|
||||
|
||||
impl Widget for Array {
|
||||
fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context) {
|
||||
self.synchronize_children(context);
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self.synchronize_children(&mut context.as_event_context());
|
||||
self.layout.update(
|
||||
Size::new(
|
||||
ConstraintLimit::Known(graphics.size().width),
|
||||
ConstraintLimit::Known(graphics.size().height),
|
||||
ConstraintLimit::Known(context.graphics.size().width),
|
||||
ConstraintLimit::Known(context.graphics.size().height),
|
||||
),
|
||||
|child_index, constraints| {
|
||||
context
|
||||
.for_other(&self.synced_children[child_index])
|
||||
.measure(constraints, graphics)
|
||||
.measure(constraints)
|
||||
},
|
||||
);
|
||||
|
||||
for (index, layout) in self.layout.iter().enumerate() {
|
||||
let child = &self.synced_children[index];
|
||||
if layout.size > 0 {
|
||||
let mut clipped = graphics.clipped_to(Rect::new(
|
||||
let mut clipped = context.clipped_to(Rect::new(
|
||||
self.layout.orientation.make_point(layout.offset, UPx(0)),
|
||||
self.layout
|
||||
.orientation
|
||||
.make_size(layout.size, self.layout.other),
|
||||
));
|
||||
context.for_other(child).redraw(&mut clipped);
|
||||
clipped.for_other(child).redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -122,16 +121,15 @@ impl Widget for Array {
|
|||
fn measure(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
graphics: &mut Graphics<'_, '_, '_>,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
self.synchronize_children(context);
|
||||
self.synchronize_children(&mut context.as_event_context());
|
||||
|
||||
self.layout
|
||||
.update(available_space, |child_index, constraints| {
|
||||
context
|
||||
.for_other(&self.synced_children[child_index])
|
||||
.measure(constraints, graphics)
|
||||
.measure(constraints)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton}
|
|||
use kludgine::app::winit::keyboard::KeyCode;
|
||||
use kludgine::figures::units::{Px, UPx};
|
||||
use kludgine::figures::{IntoUnsigned, Point, Rect, Size};
|
||||
use kludgine::shapes::{Shape, StrokeOptions};
|
||||
use kludgine::{Color, Kludgine};
|
||||
use kludgine::shapes::Shape;
|
||||
use kludgine::Color;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::context::{EventContext, GraphicsContext};
|
||||
use crate::names::Name;
|
||||
use crate::styles::{
|
||||
ComponentDefinition, ComponentGroup, ComponentName, HighlightColor, NamedComponent, TextColor,
|
||||
|
|
@ -49,8 +48,8 @@ impl Button {
|
|||
}
|
||||
|
||||
impl Widget for Button {
|
||||
fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context) {
|
||||
let center = Point::from(graphics.size()) / 2;
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
let center = Point::from(context.graphics.size()) / 2;
|
||||
if let Value::Dynamic(label) = &self.label {
|
||||
context.redraw_when_changed(label);
|
||||
}
|
||||
|
|
@ -63,7 +62,7 @@ impl Widget for Button {
|
|||
&ButtonHoverBackground,
|
||||
]);
|
||||
|
||||
let visible_rect = Rect::from(graphics.size() - (UPx(1), UPx(1)));
|
||||
let visible_rect = Rect::from(context.graphics.size() - (UPx(1), UPx(1)));
|
||||
|
||||
let background = if context.active() {
|
||||
styles.get_or_default(&ButtonActiveBackground)
|
||||
|
|
@ -73,20 +72,17 @@ impl Widget for Button {
|
|||
styles.get_or_default(&ButtonBackground)
|
||||
};
|
||||
let background = Shape::filled_rect(visible_rect, background);
|
||||
graphics.draw_shape(&background, Point::default(), None, None);
|
||||
context
|
||||
.graphics
|
||||
.draw_shape(&background, Point::default(), None, None);
|
||||
|
||||
if context.focused() {
|
||||
let focus_ring = Shape::stroked_rect(
|
||||
visible_rect,
|
||||
styles.get_or_default(&HighlightColor),
|
||||
StrokeOptions::default(),
|
||||
);
|
||||
graphics.draw_shape(&focus_ring, Point::default(), None, None);
|
||||
context.draw_focus_ring(&styles);
|
||||
}
|
||||
|
||||
let width = graphics.size().width;
|
||||
let width = context.graphics.size().width;
|
||||
self.label.map(|label| {
|
||||
graphics.draw_text(
|
||||
context.graphics.draw_text(
|
||||
label,
|
||||
styles.get_or_default(&TextColor),
|
||||
kludgine::text::TextOrigin::Center,
|
||||
|
|
@ -98,7 +94,7 @@ impl Widget for Button {
|
|||
});
|
||||
}
|
||||
|
||||
fn hit_test(&mut self, _location: Point<Px>, _context: &mut Context<'_, '_>) -> bool {
|
||||
fn hit_test(&mut self, _location: Point<Px>, _context: &mut EventContext<'_, '_>) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +103,7 @@ impl Widget for Button {
|
|||
_location: Point<Px>,
|
||||
_device_id: DeviceId,
|
||||
_button: MouseButton,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
self.buttons_pressed += 1;
|
||||
context.activate();
|
||||
|
|
@ -119,7 +115,7 @@ impl Widget for Button {
|
|||
location: Point<Px>,
|
||||
_device_id: DeviceId,
|
||||
_button: MouseButton,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
let changed = if Rect::from(
|
||||
context
|
||||
|
|
@ -144,7 +140,7 @@ impl Widget for Button {
|
|||
location: Option<Point<Px>>,
|
||||
_device_id: DeviceId,
|
||||
_button: MouseButton,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
self.buttons_pressed -= 1;
|
||||
if self.buttons_pressed == 0 {
|
||||
|
|
@ -170,12 +166,13 @@ impl Widget for Button {
|
|||
fn measure(
|
||||
&mut self,
|
||||
available_space: Size<crate::ConstraintLimit>,
|
||||
graphics: &mut Graphics<'_, '_, '_>,
|
||||
_context: &mut Context<'_, '_>,
|
||||
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
|
||||
self.label.map(|label| {
|
||||
let measured = graphics.measure_text::<Px>(label, Color::WHITE, Some(width));
|
||||
let measured = context
|
||||
.graphics
|
||||
.measure_text::<Px>(label, Color::WHITE, Some(width));
|
||||
|
||||
let mut size = measured.size.into_unsigned();
|
||||
size.height = size.height.max(measured.line_height.into_unsigned());
|
||||
|
|
@ -188,8 +185,7 @@ impl Widget for Button {
|
|||
_device_id: DeviceId,
|
||||
input: KeyEvent,
|
||||
_is_synthetic: bool,
|
||||
kludgine: &mut Kludgine,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
if input.physical_key == KeyCode::Space {
|
||||
let changed = match input.state {
|
||||
|
|
@ -208,27 +204,27 @@ impl Widget for Button {
|
|||
}
|
||||
}
|
||||
|
||||
fn unhover(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
||||
fn hover(&mut self, _location: Point<Px>, context: &mut Context<'_, '_>) {
|
||||
fn hover(&mut self, _location: Point<Px>, context: &mut EventContext<'_, '_>) {
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
||||
fn focus(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
||||
fn blur(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn blur(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
||||
fn activate(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn activate(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
||||
fn deactivate(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn deactivate(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ use std::time::{Duration, Instant};
|
|||
use kludgine::figures::units::UPx;
|
||||
use kludgine::figures::Size;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::context::GraphicsContext;
|
||||
use crate::widget::Widget;
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -20,8 +19,7 @@ impl Canvas {
|
|||
pub fn new<F>(render: F) -> Self
|
||||
where
|
||||
F: for<'clip, 'gfx, 'pass, 'context, 'window> FnMut(
|
||||
&mut Graphics<'clip, 'gfx, 'pass>,
|
||||
&mut Context<'context, 'window>,
|
||||
&mut GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
) + Send
|
||||
+ UnwindSafe
|
||||
+ 'static,
|
||||
|
|
@ -42,8 +40,8 @@ impl Canvas {
|
|||
}
|
||||
|
||||
impl Widget for Canvas {
|
||||
fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context<'_, '_>) {
|
||||
self.render.render(graphics, context);
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self.render.render(context);
|
||||
|
||||
if let Some(target_frame_duration) = self.target_frame_duration {
|
||||
let now = Instant::now();
|
||||
|
|
@ -58,8 +56,7 @@ impl Widget for Canvas {
|
|||
fn measure(
|
||||
&mut self,
|
||||
available_space: Size<crate::ConstraintLimit>,
|
||||
_graphics: &mut Graphics<'_, '_, '_>,
|
||||
_context: &mut Context<'_, '_>,
|
||||
_context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
Size::new(available_space.width.max(), available_space.height.max())
|
||||
}
|
||||
|
|
@ -72,19 +69,18 @@ impl Debug for Canvas {
|
|||
}
|
||||
|
||||
trait RenderFunction: Send + UnwindSafe + 'static {
|
||||
fn render(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context<'_, '_>);
|
||||
fn render(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>);
|
||||
}
|
||||
|
||||
impl<F> RenderFunction for F
|
||||
where
|
||||
F: for<'clip, 'gfx, 'pass, 'context, 'window> FnMut(
|
||||
&mut Graphics<'clip, 'gfx, 'pass>,
|
||||
&mut Context<'context, 'window>,
|
||||
&mut GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
) + Send
|
||||
+ UnwindSafe
|
||||
+ 'static,
|
||||
{
|
||||
fn render(&mut self, graphics: &mut Graphics<'_, '_, '_>, window: &mut Context<'_, '_>) {
|
||||
self(graphics, window);
|
||||
fn render(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self(context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use kludgine::app::winit::event::Ime;
|
||||
use kludgine::app::winit::keyboard::Key;
|
||||
use kludgine::cosmic_text::{Action, Attrs, Buffer, Edit, Editor, FontSystem, Metrics, Shaping};
|
||||
use kludgine::cosmic_text::{Action, Attrs, Buffer, Cursor, Edit, Editor, Metrics, Shaping};
|
||||
use kludgine::figures::units::Px;
|
||||
use kludgine::figures::{FloatConversion, IntoUnsigned, Point};
|
||||
use kludgine::figures::{
|
||||
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
|
||||
};
|
||||
use kludgine::shapes::Shape;
|
||||
use kludgine::text::TextOrigin;
|
||||
use kludgine::{Color, Kludgine};
|
||||
|
||||
use crate::styles::{Styles, TextColor};
|
||||
use crate::context::{EventContext, WidgetContext};
|
||||
use crate::styles::{HighlightColor, LineHeight, Styles, TextColor, TextSize};
|
||||
use crate::utils::ModifiersExt;
|
||||
use crate::widget::{EventHandling, IntoValue, Value, Widget, HANDLED, UNHANDLED};
|
||||
|
||||
|
|
@ -29,13 +35,28 @@ impl Input {
|
|||
}
|
||||
}
|
||||
|
||||
fn editor_mut(&mut self, font_system: &mut FontSystem, styles: &Styles) -> &mut Editor {
|
||||
fn editor_mut(&mut self, kludgine: &mut Kludgine, styles: &Styles) -> &mut Editor {
|
||||
match (&self.editor, self.text.generation()) {
|
||||
(Some(editor), generation) if editor.generation == generation => {}
|
||||
(_, generation) => {
|
||||
let mut buffer = Buffer::new(font_system, Metrics::new(12., 18.));
|
||||
let scale = kludgine.scale();
|
||||
let mut buffer = Buffer::new(
|
||||
kludgine.font_system(),
|
||||
Metrics::new(
|
||||
styles.get_or_default(&TextSize).into_px(scale).into_float(),
|
||||
styles
|
||||
.get_or_default(&LineHeight)
|
||||
.into_px(scale)
|
||||
.into_float(),
|
||||
),
|
||||
);
|
||||
self.text.map(|text| {
|
||||
buffer.set_text(font_system, text, Attrs::new(), Shaping::Advanced);
|
||||
buffer.set_text(
|
||||
kludgine.font_system(),
|
||||
text,
|
||||
Attrs::new(),
|
||||
Shaping::Advanced,
|
||||
);
|
||||
});
|
||||
self.editor = Some(LiveEditor {
|
||||
editor: Editor::new(buffer),
|
||||
|
|
@ -46,6 +67,10 @@ impl Input {
|
|||
|
||||
&mut self.editor.as_mut().expect("just initialized").editor
|
||||
}
|
||||
|
||||
fn styles(context: &WidgetContext<'_, '_>) -> Styles {
|
||||
context.query_style(&[&TextColor, &TextSize, &LineHeight])
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Input {
|
||||
|
|
@ -57,52 +82,186 @@ impl Debug for Input {
|
|||
}
|
||||
|
||||
impl Widget for Input {
|
||||
fn hit_test(
|
||||
&mut self,
|
||||
location: Point<Px>,
|
||||
context: &mut crate::context::Context<'_, '_>,
|
||||
) -> bool {
|
||||
fn hit_test(&mut self, _location: Point<Px>, _context: &mut EventContext<'_, '_>) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn mouse_down(
|
||||
&mut self,
|
||||
location: Point<Px>,
|
||||
device_id: kludgine::app::winit::event::DeviceId,
|
||||
button: kludgine::app::winit::event::MouseButton,
|
||||
context: &mut crate::context::Context<'_, '_>,
|
||||
_device_id: kludgine::app::winit::event::DeviceId,
|
||||
_button: kludgine::app::winit::event::MouseButton,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
// self.editor_mut(, styles);
|
||||
|
||||
context.focus();
|
||||
let styles = context.query_style(&[&TextColor]);
|
||||
self.editor_mut(context.kludgine, &styles).action(
|
||||
context.kludgine.font_system(),
|
||||
Action::Click {
|
||||
x: location.x.0,
|
||||
y: location.y.0,
|
||||
},
|
||||
);
|
||||
context.set_needs_redraw();
|
||||
HANDLED
|
||||
}
|
||||
|
||||
fn mouse_up(
|
||||
fn mouse_drag(
|
||||
&mut self,
|
||||
location: Option<Point<Px>>,
|
||||
device_id: kludgine::app::winit::event::DeviceId,
|
||||
button: kludgine::app::winit::event::MouseButton,
|
||||
context: &mut crate::context::Context<'_, '_>,
|
||||
location: Point<Px>,
|
||||
_device_id: kludgine::app::winit::event::DeviceId,
|
||||
_button: kludgine::app::winit::event::MouseButton,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
context.focus();
|
||||
let styles = context.query_style(&[&TextColor]);
|
||||
self.editor_mut(context.kludgine, &styles).action(
|
||||
context.kludgine.font_system(),
|
||||
Action::Drag {
|
||||
x: location.x.0,
|
||||
y: location.y.0,
|
||||
},
|
||||
);
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
||||
fn redraw(
|
||||
&mut self,
|
||||
graphics: &mut crate::graphics::Graphics<'_, '_, '_>,
|
||||
context: &mut crate::context::Context<'_, '_>,
|
||||
) {
|
||||
let size = graphics.size();
|
||||
let styles = context.query_style(&[&TextColor]);
|
||||
let editor = self.editor_mut(graphics.font_system(), &styles);
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
let size = context.graphics.size();
|
||||
let styles = context.query_style(&[&TextColor, &HighlightColor]);
|
||||
let highlight = styles.get_or_default(&HighlightColor);
|
||||
let editor = self.editor_mut(&mut context.graphics, &styles);
|
||||
let cursor = editor.cursor();
|
||||
let selection = editor.select_opt();
|
||||
let buffer = editor.buffer_mut();
|
||||
buffer.set_size(
|
||||
graphics.font_system(),
|
||||
context.graphics.font_system(),
|
||||
size.width.into_float(),
|
||||
size.height.into_float(),
|
||||
);
|
||||
buffer.shape_until_scroll(graphics.font_system());
|
||||
graphics.draw_text_buffer(
|
||||
buffer.shape_until_scroll(context.graphics.font_system());
|
||||
|
||||
if context.focused() {
|
||||
context.draw_focus_ring(&styles);
|
||||
context.set_ime_allowed(true);
|
||||
let line_height = Px::from_float(buffer.metrics().line_height);
|
||||
if let Some(selection) = selection {
|
||||
let (start, end) = if selection < cursor {
|
||||
(selection, cursor)
|
||||
} else {
|
||||
(cursor, selection)
|
||||
};
|
||||
|
||||
match (cursor_glyph(buffer, &start), cursor_glyph(buffer, &end)) {
|
||||
(Ok((start_position, _)), Ok((end_position, end_width))) => {
|
||||
if start_position.y == end_position.y {
|
||||
// Single line selection
|
||||
let width = end_position.x - start_position.x + end_width;
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(start_position, Size::new(width, line_height)),
|
||||
highlight,
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
// Draw from start to end of line,
|
||||
let width = size.width.into_signed() - start_position.x;
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(start_position, Size::new(width, line_height)),
|
||||
highlight,
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
// Fill region between
|
||||
let bottom_of_first_line = start_position.y + line_height;
|
||||
let distance_between = end_position.y - bottom_of_first_line;
|
||||
if distance_between > 0 {
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(Px(0), bottom_of_first_line),
|
||||
Size::new(size.width.into_signed(), distance_between),
|
||||
),
|
||||
highlight,
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
// Draw from 0 to end + width
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(Px(0), end_position.y),
|
||||
Size::new(end_position.x + end_width, line_height),
|
||||
),
|
||||
highlight,
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
(Ok((start_position, _)), Err(_)) => {
|
||||
let width = size.width.into_signed() - start_position.x;
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(start_position, Size::new(width, line_height)),
|
||||
highlight,
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
(Err(_), Ok((end_position, end_width))) => {
|
||||
if end_position.y > 0 {
|
||||
todo!("fill above start");
|
||||
}
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(Px(0), end_position.y),
|
||||
Size::new(end_position.x + end_width, line_height),
|
||||
),
|
||||
highlight,
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
(Err(start_not_visible), Err(end_not_visible))
|
||||
if start_not_visible != end_not_visible =>
|
||||
{
|
||||
todo!("render full selection")
|
||||
}
|
||||
(Err(_), Err(_)) => {}
|
||||
}
|
||||
} else if let Ok((location, _)) = cursor_glyph(buffer, &cursor) {
|
||||
context.graphics.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
location,
|
||||
Size::new(Px(1), line_height),
|
||||
),
|
||||
highlight, // TODO cursor should be a bold color, highlight probably not. This should have its own color.
|
||||
),
|
||||
Point::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
context.graphics.draw_text_buffer(
|
||||
buffer,
|
||||
styles.get_or_default(&TextColor),
|
||||
TextOrigin::TopLeft,
|
||||
|
|
@ -115,18 +274,18 @@ impl Widget for Input {
|
|||
fn measure(
|
||||
&mut self,
|
||||
available_space: kludgine::figures::Size<crate::ConstraintLimit>,
|
||||
graphics: &mut crate::graphics::Graphics<'_, '_, '_>,
|
||||
context: &mut crate::context::Context<'_, '_>,
|
||||
context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> kludgine::figures::Size<kludgine::figures::units::UPx> {
|
||||
let styles = context.query_style(&[&TextColor]);
|
||||
let editor = self.editor_mut(graphics.font_system(), &styles);
|
||||
let editor = self.editor_mut(&mut context.graphics, &styles);
|
||||
let buffer = editor.buffer_mut();
|
||||
buffer.set_size(
|
||||
graphics.font_system(),
|
||||
context.graphics.font_system(),
|
||||
available_space.width.max().into_float(),
|
||||
available_space.height.max().into_float(),
|
||||
);
|
||||
graphics
|
||||
context
|
||||
.graphics
|
||||
.measure_text_buffer::<Px>(buffer, Color::WHITE)
|
||||
.size
|
||||
.into_unsigned()
|
||||
|
|
@ -134,22 +293,59 @@ impl Widget for Input {
|
|||
|
||||
fn keyboard_input(
|
||||
&mut self,
|
||||
device_id: kludgine::app::winit::event::DeviceId,
|
||||
_device_id: kludgine::app::winit::event::DeviceId,
|
||||
input: kludgine::app::winit::event::KeyEvent,
|
||||
is_synthetic: bool,
|
||||
kludgine: &mut Kludgine,
|
||||
context: &mut crate::context::Context<'_, '_>,
|
||||
_is_synthetic: bool,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
) -> EventHandling {
|
||||
if !input.state.is_pressed() {
|
||||
return UNHANDLED;
|
||||
}
|
||||
|
||||
let styles = context.query_style(&[&TextColor]);
|
||||
let editor = &mut self.editor.as_mut().expect("input without editor").editor;
|
||||
let editor = self.editor_mut(context.kludgine, &styles);
|
||||
|
||||
println!(
|
||||
"Keyboard input: {:?}. {:?}, {:?}",
|
||||
input.logical_key, input.text, input.physical_key
|
||||
);
|
||||
match (input.logical_key, input.text) {
|
||||
(Key::Backspace, _) => {
|
||||
editor.action(kludgine.font_system(), Action::Backspace);
|
||||
(key @ (Key::Backspace | Key::Delete), _) => {
|
||||
editor.action(
|
||||
context.kludgine.font_system(),
|
||||
match key {
|
||||
Key::Backspace => Action::Backspace,
|
||||
Key::Delete => Action::Delete,
|
||||
_ => unreachable!("previously matched"),
|
||||
},
|
||||
);
|
||||
context.set_needs_redraw();
|
||||
HANDLED
|
||||
}
|
||||
(key @ (Key::ArrowLeft | Key::ArrowDown | Key::ArrowUp | Key::ArrowRight), _) => {
|
||||
let modifiers = context.modifiers();
|
||||
match (editor.select_opt(), modifiers.state().shift_key()) {
|
||||
(None, true) => {
|
||||
editor.set_select_opt(Some(editor.cursor()));
|
||||
}
|
||||
(Some(_), false) => {
|
||||
editor.set_select_opt(None);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
editor.action(
|
||||
context.kludgine.font_system(),
|
||||
match key {
|
||||
Key::ArrowLeft if modifiers.word_select() => Action::PreviousWord,
|
||||
Key::ArrowLeft => Action::Left,
|
||||
Key::ArrowDown => Action::Down,
|
||||
Key::ArrowUp => Action::Up,
|
||||
Key::ArrowRight if modifiers.word_select() => Action::NextWord,
|
||||
Key::ArrowRight => Action::Right,
|
||||
_ => unreachable!("previously matched"),
|
||||
},
|
||||
);
|
||||
context.set_needs_redraw();
|
||||
HANDLED
|
||||
}
|
||||
|
|
@ -162,11 +358,27 @@ impl Widget for Input {
|
|||
}
|
||||
}
|
||||
|
||||
fn focus(&mut self, context: &mut crate::context::Context<'_, '_>) {
|
||||
fn ime(&mut self, ime: Ime, context: &mut EventContext<'_, '_>) -> EventHandling {
|
||||
match ime {
|
||||
Ime::Enabled | Ime::Disabled => {}
|
||||
Ime::Preedit(text, cursor) => {
|
||||
println!("TODO: preview IME input {text}, cursor: {cursor:?}");
|
||||
}
|
||||
Ime::Commit(text) => {
|
||||
self.editor_mut(context.kludgine, &Self::styles(&context.widget))
|
||||
.insert_string(&text, None);
|
||||
}
|
||||
}
|
||||
|
||||
HANDLED
|
||||
}
|
||||
|
||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.set_ime_allowed(true);
|
||||
}
|
||||
|
||||
fn blur(&mut self, context: &mut crate::context::Context<'_, '_>) {
|
||||
fn blur(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
println!("Blur");
|
||||
context.set_ime_allowed(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -175,3 +387,74 @@ struct LiveEditor {
|
|||
editor: Editor,
|
||||
generation: Option<usize>,
|
||||
}
|
||||
|
||||
fn cursor_glyph(buffer: &Buffer, cursor: &Cursor) -> Result<(Point<Px>, Px), NotVisible> {
|
||||
// let cursor = buffer.layout_cursor(cursor);
|
||||
|
||||
let mut layout_cursor = buffer.layout_cursor(cursor);
|
||||
// TODO this is because of a TODO inside of layout_cursor. It currently
|
||||
// falls back to 0,0 on the current line, rather than picking the last one.
|
||||
if layout_cursor.glyph == 0 && layout_cursor.layout == 0 && cursor.index > 0 {
|
||||
layout_cursor.glyph = usize::MAX;
|
||||
}
|
||||
let mut return_after_character = false;
|
||||
let searching_for = match buffer
|
||||
.lines
|
||||
.get(layout_cursor.line)
|
||||
.and_then(|line| {
|
||||
line.layout_opt()
|
||||
.as_ref()
|
||||
.expect("line layout missing")
|
||||
.get(layout_cursor.layout)
|
||||
})
|
||||
.and_then(|layout| layout.glyphs.get(layout_cursor.glyph))
|
||||
// TODO these should progressively fail rather than a single or_else.
|
||||
.or_else(|| {
|
||||
return_after_character = true;
|
||||
buffer
|
||||
.lines
|
||||
.last()
|
||||
.and_then(|line| {
|
||||
line.layout_opt()
|
||||
.as_ref()
|
||||
.expect("line layout missing")
|
||||
.last()
|
||||
})
|
||||
.and_then(|layout| layout.glyphs.last())
|
||||
}) {
|
||||
Some(glyph) => glyph,
|
||||
None => return Err(NotVisible::Before),
|
||||
}
|
||||
.start;
|
||||
|
||||
for (index, run) in buffer.layout_runs().enumerate() {
|
||||
match run.line_i.cmp(&cursor.line) {
|
||||
Ordering::Less => continue,
|
||||
Ordering::Equal => {}
|
||||
Ordering::Greater => {
|
||||
if index > 0 {
|
||||
return Err(NotVisible::After);
|
||||
}
|
||||
return Err(NotVisible::Before);
|
||||
}
|
||||
}
|
||||
if let Some(glyph) = run.glyphs.iter().find(|g| g.start == searching_for) {
|
||||
let physical = glyph.physical((0., run.line_y), 1.);
|
||||
let position = Point::new(Px(physical.x), Px::from_float(run.line_top));
|
||||
let width = Px::from_float(glyph.w);
|
||||
return Ok(if return_after_character {
|
||||
(Point::new(position.x + width, position.y), Px(0))
|
||||
} else {
|
||||
(position, width)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Err(NotVisible::After)
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum NotVisible {
|
||||
Before,
|
||||
After,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ use kludgine::figures::{Point, Size};
|
|||
use kludgine::text::TextOrigin;
|
||||
use kludgine::Color;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::context::GraphicsContext;
|
||||
use crate::styles::TextColor;
|
||||
use crate::widget::{IntoValue, Value, Widget};
|
||||
|
||||
|
|
@ -22,15 +21,15 @@ impl Label {
|
|||
}
|
||||
|
||||
impl Widget for Label {
|
||||
fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context<'_, '_>) {
|
||||
let center = Point::from(graphics.size()) / 2;
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
let center = Point::from(context.graphics.size()) / 2;
|
||||
if let Value::Dynamic(contents) = &mut self.contents {
|
||||
context.redraw_when_changed(contents);
|
||||
}
|
||||
let styles = context.query_style(&[&TextColor]);
|
||||
let width = graphics.size().width;
|
||||
let width = context.graphics.size().width;
|
||||
self.contents.map(|contents| {
|
||||
graphics.draw_text(
|
||||
context.graphics.draw_text(
|
||||
contents,
|
||||
styles.get_or_default(&TextColor),
|
||||
TextOrigin::Center,
|
||||
|
|
@ -45,12 +44,12 @@ impl Widget for Label {
|
|||
fn measure(
|
||||
&mut self,
|
||||
available_space: Size<crate::ConstraintLimit>,
|
||||
graphics: &mut Graphics<'_, '_, '_>,
|
||||
_context: &mut Context<'_, '_>,
|
||||
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
|
||||
self.contents.map(|contents| {
|
||||
graphics
|
||||
context
|
||||
.graphics
|
||||
.measure_text(contents, Color::RED, Some(width))
|
||||
.size
|
||||
.try_cast()
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use kludgine::figures::units::UPx;
|
||||
use kludgine::figures::Size;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::graphics::Graphics;
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext};
|
||||
use crate::styles::Styles;
|
||||
use crate::widget::{BoxedWidget, ManagedWidget, Widget};
|
||||
use crate::ConstraintLimit;
|
||||
|
|
@ -28,12 +27,12 @@ impl Style {
|
|||
}
|
||||
|
||||
impl Widget for Style {
|
||||
fn mounted(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn mounted(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
context.attach_styles(self.styles.clone());
|
||||
self.mounted_child = Some(context.push_child(self.child.clone()));
|
||||
}
|
||||
|
||||
fn unmounted(&mut self, context: &mut Context<'_, '_>) {
|
||||
fn unmounted(&mut self, context: &mut EventContext<'_, '_>) {
|
||||
let child = self
|
||||
.mounted_child
|
||||
.take()
|
||||
|
|
@ -41,21 +40,20 @@ impl Widget for Style {
|
|||
context.remove_child(&child);
|
||||
}
|
||||
|
||||
fn redraw(&mut self, graphics: &mut Graphics<'_, '_, '_>, context: &mut Context<'_, '_>) {
|
||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
context
|
||||
.for_other(
|
||||
self.mounted_child
|
||||
.as_ref()
|
||||
.expect("measuring without being mounted"),
|
||||
)
|
||||
.redraw(graphics);
|
||||
.redraw();
|
||||
}
|
||||
|
||||
fn measure(
|
||||
&mut self,
|
||||
available_space: Size<ConstraintLimit>,
|
||||
graphics: &mut Graphics<'_, '_, '_>,
|
||||
context: &mut Context<'_, '_>,
|
||||
context: &mut GraphicsContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
context
|
||||
.for_other(
|
||||
|
|
@ -63,6 +61,6 @@ impl Widget for Style {
|
|||
.as_ref()
|
||||
.expect("measuring without being mounted"),
|
||||
)
|
||||
.measure(available_space, graphics)
|
||||
.measure(available_space)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::panic::{AssertUnwindSafe, UnwindSafe};
|
|||
use kludgine::app::winit::dpi::PhysicalPosition;
|
||||
use kludgine::app::winit::error::EventLoopError;
|
||||
use kludgine::app::winit::event::{
|
||||
DeviceId, ElementState, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
DeviceId, ElementState, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
};
|
||||
use kludgine::app::winit::keyboard::KeyCode;
|
||||
use kludgine::app::WindowBehavior as _;
|
||||
|
|
@ -14,7 +14,7 @@ use kludgine::figures::Point;
|
|||
use kludgine::render::Drawing;
|
||||
use kludgine::Kludgine;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::context::{EventContext, Exclusive, GraphicsContext, WidgetContext};
|
||||
use crate::graphics::Graphics;
|
||||
use crate::styles::Styles;
|
||||
use crate::tree::Tree;
|
||||
|
|
@ -162,8 +162,11 @@ where
|
|||
graphics.reset_text_attributes();
|
||||
self.root.tree.reset_render_order();
|
||||
let graphics = self.contents.new_frame(graphics);
|
||||
let mut context = Context::new(&self.root, &mut window);
|
||||
context.redraw(&mut Graphics::new(graphics));
|
||||
GraphicsContext {
|
||||
widget: WidgetContext::new(&self.root, &mut window),
|
||||
graphics: Exclusive::Owned(Graphics::new(graphics)),
|
||||
}
|
||||
.redraw();
|
||||
}
|
||||
|
||||
fn render<'pass>(
|
||||
|
|
@ -187,7 +190,7 @@ where
|
|||
.expect("called more than once")
|
||||
}
|
||||
|
||||
fn close_requested(&mut self, mut window: RunningWindow<'_>) -> bool {
|
||||
fn close_requested(&mut self, mut window: RunningWindow<'_>, _kludgine: &mut Kludgine) -> bool {
|
||||
self.request_close(&mut window)
|
||||
}
|
||||
|
||||
|
|
@ -224,17 +227,17 @@ where
|
|||
fn keyboard_input(
|
||||
&mut self,
|
||||
mut window: RunningWindow<'_>,
|
||||
kludgine: &mut Kludgine,
|
||||
device_id: DeviceId,
|
||||
input: KeyEvent,
|
||||
is_synthetic: bool,
|
||||
kludgine: &mut Kludgine,
|
||||
) {
|
||||
let target = self.root.tree.hovered_widget().unwrap_or(self.root.id);
|
||||
let target = self.root.tree.focused_widget().unwrap_or(self.root.id);
|
||||
let target = self.root.tree.widget(target);
|
||||
let mut target = Context::new(&target, &mut window);
|
||||
let mut target = EventContext::new(WidgetContext::new(&target, &mut window), kludgine);
|
||||
|
||||
let handled = recursively_handle_event(&mut target, |widget| {
|
||||
widget.keyboard_input(device_id, input.clone(), is_synthetic, kludgine)
|
||||
widget.keyboard_input(device_id, input.clone(), is_synthetic)
|
||||
})
|
||||
.is_some();
|
||||
drop(target);
|
||||
|
|
@ -254,6 +257,7 @@ where
|
|||
fn mouse_wheel(
|
||||
&mut self,
|
||||
mut window: RunningWindow<'_>,
|
||||
kludgine: &mut Kludgine,
|
||||
device_id: DeviceId,
|
||||
delta: MouseScrollDelta,
|
||||
phase: TouchPhase,
|
||||
|
|
@ -261,7 +265,7 @@ where
|
|||
let widget = self.root.tree.hovered_widget().unwrap_or(self.root.id);
|
||||
|
||||
let widget = self.root.tree.widget(widget);
|
||||
let mut widget = Context::new(&widget, &mut window);
|
||||
let mut widget = EventContext::new(WidgetContext::new(&widget, &mut window), kludgine);
|
||||
recursively_handle_event(&mut widget, |widget| {
|
||||
widget.mouse_wheel(device_id, delta, phase)
|
||||
});
|
||||
|
|
@ -269,13 +273,19 @@ where
|
|||
|
||||
// fn modifiers_changed(&mut self, window: kludgine::app::Window<'_, ()>) {}
|
||||
|
||||
fn ime(&mut self, mut window: RunningWindow<'_>, ime: kludgine::app::winit::event::Ime) {
|
||||
dbg!(ime);
|
||||
fn ime(&mut self, mut window: RunningWindow<'_>, kludgine: &mut Kludgine, ime: Ime) {
|
||||
let target = self.root.tree.focused_widget().unwrap_or(self.root.id);
|
||||
let target = self.root.tree.widget(target);
|
||||
let mut target = EventContext::new(WidgetContext::new(&target, &mut window), kludgine);
|
||||
|
||||
let _handled =
|
||||
recursively_handle_event(&mut target, |widget| widget.ime(ime.clone())).is_some();
|
||||
}
|
||||
|
||||
fn cursor_moved(
|
||||
&mut self,
|
||||
mut window: RunningWindow<'_>,
|
||||
kludgine: &mut Kludgine,
|
||||
device_id: DeviceId,
|
||||
position: PhysicalPosition<f64>,
|
||||
) {
|
||||
|
|
@ -285,13 +295,15 @@ where
|
|||
if let Some(state) = self.mouse_state.devices.get(&device_id) {
|
||||
// Mouse Drag
|
||||
for (button, handler) in state {
|
||||
let mut context = Context::new(handler, &mut window);
|
||||
let mut context =
|
||||
EventContext::new(WidgetContext::new(handler, &mut window), kludgine);
|
||||
let last_rendered_at = context.last_rendered_at().expect("passed hit test");
|
||||
context.mouse_drag(location - last_rendered_at.origin, device_id, *button);
|
||||
}
|
||||
} else {
|
||||
// Hover
|
||||
let mut context = Context::new(&self.root, &mut window);
|
||||
let mut context =
|
||||
EventContext::new(WidgetContext::new(&self.root, &mut window), kludgine);
|
||||
self.mouse_state.widget = None;
|
||||
for widget in self.root.tree.widgets_at_point(location) {
|
||||
let mut widget_context = context.for_other(&widget);
|
||||
|
|
@ -315,9 +327,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn cursor_left(&mut self, mut window: RunningWindow<'_>, _device_id: DeviceId) {
|
||||
fn cursor_left(
|
||||
&mut self,
|
||||
mut window: RunningWindow<'_>,
|
||||
kludgine: &mut Kludgine,
|
||||
_device_id: DeviceId,
|
||||
) {
|
||||
if self.mouse_state.widget.take().is_some() {
|
||||
let mut context = Context::new(&self.root, &mut window);
|
||||
let mut context =
|
||||
EventContext::new(WidgetContext::new(&self.root, &mut window), kludgine);
|
||||
context.clear_hover();
|
||||
}
|
||||
}
|
||||
|
|
@ -325,19 +343,20 @@ where
|
|||
fn mouse_input(
|
||||
&mut self,
|
||||
mut window: RunningWindow<'_>,
|
||||
kludgine: &mut Kludgine,
|
||||
device_id: DeviceId,
|
||||
state: ElementState,
|
||||
button: MouseButton,
|
||||
) {
|
||||
match state {
|
||||
ElementState::Pressed => {
|
||||
Context::new(&self.root, &mut window).clear_focus();
|
||||
WidgetContext::new(&self.root, &mut window).clear_focus();
|
||||
|
||||
if let (ElementState::Pressed, Some(location), Some(hovered)) =
|
||||
(state, &self.mouse_state.location, &self.mouse_state.widget)
|
||||
{
|
||||
if let Some(handler) = recursively_handle_event(
|
||||
&mut Context::new(hovered, &mut window),
|
||||
&mut EventContext::new(WidgetContext::new(hovered, &mut window), kludgine),
|
||||
|context| {
|
||||
let relative = *location
|
||||
- context.last_rendered_at().expect("passed hit test").origin;
|
||||
|
|
@ -363,7 +382,8 @@ where
|
|||
self.mouse_state.devices.remove(&device_id);
|
||||
}
|
||||
|
||||
let mut context = Context::new(&handler, &mut window);
|
||||
let mut context =
|
||||
EventContext::new(WidgetContext::new(&handler, &mut window), kludgine);
|
||||
|
||||
let relative = if let (Some(last_rendered), Some(location)) =
|
||||
(context.last_rendered_at(), self.mouse_state.location)
|
||||
|
|
@ -378,7 +398,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn event(&mut self, event: WindowCommand, mut window: RunningWindow<'_>) {
|
||||
fn event(
|
||||
&mut self,
|
||||
mut window: RunningWindow<'_>,
|
||||
_kludgine: &mut Kludgine,
|
||||
event: WindowCommand,
|
||||
) {
|
||||
match event {
|
||||
WindowCommand::Redraw => {
|
||||
window.set_needs_redraw();
|
||||
|
|
@ -388,8 +413,8 @@ where
|
|||
}
|
||||
|
||||
fn recursively_handle_event(
|
||||
context: &mut Context<'_, '_>,
|
||||
mut each_widget: impl FnMut(&mut Context<'_, '_>) -> EventHandling,
|
||||
context: &mut EventContext<'_, '_>,
|
||||
mut each_widget: impl FnMut(&mut EventContext<'_, '_>) -> EventHandling,
|
||||
) -> Option<ManagedWidget> {
|
||||
match each_widget(context) {
|
||||
HANDLED => Some(context.widget().clone()),
|
||||
|
|
|
|||
Loading…
Reference in a new issue