mirror of
https://github.com/danbulant/mangui
synced 2026-06-13 19:31:17 +00:00
improved text and image support, support measuring sizes for taffy
This commit is contained in:
parent
f65588ec19
commit
389b147bfb
15 changed files with 435 additions and 128 deletions
209
Cargo.lock
generated
209
Cargo.lock
generated
|
|
@ -313,6 +313,29 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-text"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c578f2b9abb4d5f3fbb12aba4008084d435dc6a8425c195cfe0b3594bfea0c25"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"fontdb",
|
||||
"libm",
|
||||
"log",
|
||||
"rangemap",
|
||||
"rustc-hash",
|
||||
"rustybuzz 0.12.1",
|
||||
"self_cell",
|
||||
"swash",
|
||||
"sys-locale",
|
||||
"ttf-parser",
|
||||
"unicode-bidi",
|
||||
"unicode-linebreak",
|
||||
"unicode-script",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
|
|
@ -444,9 +467,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "femtovg"
|
||||
version = "0.7.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3a2d0ff0df09856a5c1c89cc83863a1f0f994c55452186621bb57a01f270b3"
|
||||
checksum = "18ab822e58e8bc2b89840dc5dde49afe39302e129c60d39c8520200c085404a7"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"fnv",
|
||||
|
|
@ -454,9 +477,10 @@ dependencies = [
|
|||
"glow",
|
||||
"image",
|
||||
"imgref",
|
||||
"log",
|
||||
"lru",
|
||||
"rgb",
|
||||
"rustybuzz",
|
||||
"rustybuzz 0.11.0",
|
||||
"unicode-bidi",
|
||||
"unicode-segmentation",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -488,6 +512,35 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "font-types"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bd7f3ea17572640b606b35df42cfb6ecdf003704b062580e59918692190b73d"
|
||||
|
||||
[[package]]
|
||||
name = "fontconfig-parser"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a595cb550439a117696039dfc69830492058211b771a2a165379f2a1a53d84d"
|
||||
dependencies = [
|
||||
"roxmltree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fontdb"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
|
||||
dependencies = [
|
||||
"fontconfig-parser",
|
||||
"log",
|
||||
"memmap2",
|
||||
"slotmap",
|
||||
"tinyvec",
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
|
|
@ -660,9 +713,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.12.0"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
|
||||
checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
|
|
@ -687,9 +740,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.12.3"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728"
|
||||
checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"slotmap",
|
||||
|
|
@ -764,9 +817,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "grid"
|
||||
version = "0.10.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eec1c01eb1de97451ee0d60de7d81cf1e72aabefb021616027f3d1c3ec1c723c"
|
||||
checksum = "d196ffc1627db18a531359249b2bf8416178d84b729f3cebeb278f285fb9b58c"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
|
|
@ -903,9 +956,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.24.8"
|
||||
version = "0.24.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "034bbe799d1909622a74d1193aa50147769440040ff36cb2baa947609b0a4e23"
|
||||
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
|
|
@ -1030,6 +1083,12 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.0.2"
|
||||
|
|
@ -1065,9 +1124,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
|||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.10.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670"
|
||||
checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22"
|
||||
|
||||
[[package]]
|
||||
name = "mangades"
|
||||
|
|
@ -1089,10 +1148,13 @@ dependencies = [
|
|||
name = "mangui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmic-text",
|
||||
"femtovg",
|
||||
"glutin",
|
||||
"glutin-winit",
|
||||
"lazy_static",
|
||||
"raw-window-handle 0.5.2",
|
||||
"swash",
|
||||
"taffy",
|
||||
"weak-table",
|
||||
"winit",
|
||||
|
|
@ -1325,7 +1387,7 @@ version = "0.20.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7"
|
||||
dependencies = [
|
||||
"ttf-parser 0.20.0",
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1447,6 +1509,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rangemap"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "795915a3930a5d6bafd9053d37602fea3e61be2e5d4d788983a8ba9654c1c6f2"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.5.2"
|
||||
|
|
@ -1479,6 +1547,15 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "read-fonts"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c044ab88c43e2eae05b34a17fc13598736679fdb03d71b49fcfe114443ec8a86"
|
||||
dependencies = [
|
||||
"font-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
|
|
@ -1546,6 +1623,12 @@ dependencies = [
|
|||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
|
||||
|
||||
[[package]]
|
||||
name = "rusalka"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1566,6 +1649,12 @@ version = "0.1.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
|
|
@ -1590,17 +1679,34 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustybuzz"
|
||||
version = "0.7.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a"
|
||||
checksum = "2ee8fe2a8461a0854a37101fe7a1b13998d0cfa987e43248e81d2a5f4570f6fa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
"smallvec",
|
||||
"ttf-parser 0.18.1",
|
||||
"ttf-parser",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-general-category",
|
||||
"unicode-properties",
|
||||
"unicode-script",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustybuzz"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0ae5692c5beaad6a9e22830deeed7874eae8a4e3ba4076fb48e12c56856222c"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bytemuck",
|
||||
"libm",
|
||||
"smallvec",
|
||||
"ttf-parser",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-properties",
|
||||
"unicode-script",
|
||||
]
|
||||
|
||||
|
|
@ -1676,6 +1782,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
|
|
@ -1817,6 +1929,17 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
|
||||
[[package]]
|
||||
name = "swash"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d06ff4664af8923625604261c645f5c4cc610cc83c84bec74b50d76237089de7"
|
||||
dependencies = [
|
||||
"read-fonts",
|
||||
"yazi",
|
||||
"zeno",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.50"
|
||||
|
|
@ -1834,6 +1957,15 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sys-locale"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
|
|
@ -1857,13 +1989,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "taffy"
|
||||
version = "0.3.18"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c2287b6d7f721ada4cddf61ade5e760b2c6207df041cac9bfaa192897362fd3"
|
||||
checksum = "fddbee94e20bc4612dcb789953324236eebd4fc6a08c650ccbf7f615e59a0d6a"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"grid",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"slotmap",
|
||||
]
|
||||
|
||||
|
|
@ -2052,12 +2185,6 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.20.0"
|
||||
|
|
@ -2082,18 +2209,18 @@ 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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-linebreak"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.23"
|
||||
|
|
@ -2103,6 +2230,12 @@ dependencies = [
|
|||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-script"
|
||||
version = "0.5.6"
|
||||
|
|
@ -2730,6 +2863,18 @@ version = "0.8.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
||||
|
||||
[[package]]
|
||||
name = "yazi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
|
||||
|
||||
[[package]]
|
||||
name = "zeno"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ impl Component for DemoComponent {
|
|||
style: Style {
|
||||
layout: mangui::nodes::TaffyStyle {
|
||||
min_size: Size {
|
||||
width: mangui::taffy::style::Dimension::Points( if **test.lock().unwrap() { 50. } else { 100. }),
|
||||
height: mangui::taffy::style::Dimension::Points(100.)
|
||||
width: mangui::taffy::style::Dimension::Length( if **test.lock().unwrap() { 50. } else { 100. }),
|
||||
height: mangui::taffy::style::Dimension::Length(100.)
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use rusalka_macro::make_component;
|
||||
use std::default::Default;
|
||||
use mangui::{femtovg::{ImageFlags, Color, Paint}, cosmic_text::Metrics, nodes::{layout::Layout, Style}, nodes::text::Text, nodes::image::Image, taffy::prelude::Size};
|
||||
use mangui::nodes::TaffyStyle;
|
||||
use mangui::taffy::Display::Block;
|
||||
|
||||
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes};
|
||||
|
||||
|
|
@ -28,34 +30,32 @@ make_component!(
|
|||
radius: if $test_ { attrs.radius } else { 0. },
|
||||
..Default::default()
|
||||
}
|
||||
@image {
|
||||
style: Style {
|
||||
layout: mangui::nodes::TaffyStyle {
|
||||
min_size: Size {
|
||||
width: mangui::taffy::style::Dimension::Points(width),
|
||||
height: mangui::taffy::style::Dimension::Points(height)
|
||||
@layout {
|
||||
@image {
|
||||
style: Style {
|
||||
layout: TaffyStyle {
|
||||
min_size: Size {
|
||||
width: mangui::taffy::style::Dimension::Length(width),
|
||||
height: mangui::taffy::style::Dimension::Length(height)
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
image: mangui::nodes::image::ImageLoad::LoadFile(imgpath, imgflags),
|
||||
radius: 5.,
|
||||
..Default::default()
|
||||
},
|
||||
image: mangui::nodes::image::ImageLoad::LoadFile(imgpath, imgflags),
|
||||
width,
|
||||
height,
|
||||
radius: 5.,
|
||||
events: Default::default(),
|
||||
parent: None
|
||||
}
|
||||
@text {
|
||||
text: String::from("Hello, World!"),
|
||||
metrics: Metrics::new(20., 25.),
|
||||
paint: Paint::color(Color::rgb(0, 255, 0)),
|
||||
}
|
||||
@text {
|
||||
text: String::from("Hello, World!"),
|
||||
metrics: Metrics::new(20., 25.),
|
||||
paint: Paint::color(Color::rgb(0, 255, 0)),
|
||||
..Default::default()
|
||||
}
|
||||
|
||||
style: Style {
|
||||
layout: mangui::nodes::TaffyStyle {
|
||||
min_size: Size {
|
||||
width: mangui::taffy::style::Dimension::Points(200.),
|
||||
height: mangui::taffy::style::Dimension::Points(40.)
|
||||
},
|
||||
layout: TaffyStyle {
|
||||
display: Block,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{sel
|
|||
|
||||
mod component_demo;
|
||||
mod component_demo_syntax;
|
||||
mod anilist;
|
||||
|
||||
use rusalka::component::Component;
|
||||
|
||||
|
|
@ -15,11 +16,10 @@ fn main() {
|
|||
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
||||
let right_node = Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||
style: Style {
|
||||
overflow: nodes::Overflow::Visible,
|
||||
layout: TaffyStyle {
|
||||
min_size: Size {
|
||||
width: Dimension::Points(50.),
|
||||
height: Dimension::Points(100.)
|
||||
width: Dimension::Length(50.),
|
||||
height: Dimension::Length(100.)
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -791,6 +791,9 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
|||
let num_offset = index % 32;
|
||||
*keys.get_mut(array_offset).unwrap() |= 1 << num_offset;
|
||||
}
|
||||
if keys.iter().all(|x| *x == 0) {
|
||||
continue 'block;
|
||||
}
|
||||
update_stream.extend(TokenStream::from(quote!(if)));
|
||||
|
||||
let mut i = 0;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
use std::sync::{Arc, RwLock};
|
||||
use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}};
|
||||
|
||||
use crate::{component::Component, SharedComponent, WeakSharedComponent};
|
||||
use crate::{component::Component, WeakSharedComponent};
|
||||
|
||||
use super::{insert, detach};
|
||||
|
||||
|
|
@ -43,8 +43,8 @@ impl Component for Rectangle {
|
|||
style: Style {
|
||||
layout: mangui::nodes::TaffyStyle {
|
||||
min_size: Size {
|
||||
width: mangui::taffy::style::Dimension::Points(50.),
|
||||
height: mangui::taffy::style::Dimension::Points(100.)
|
||||
width: mangui::taffy::style::Dimension::Length(50.),
|
||||
height: mangui::taffy::style::Dimension::Length(100.)
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
femtovg = "0.7.1"
|
||||
glutin = "0.31.0"
|
||||
femtovg = "0.8.2"
|
||||
glutin = "0.31.3"
|
||||
raw-window-handle = "0.5.0"
|
||||
winit = { version = "0.29.2" }
|
||||
winit = { version = "0.29.10" }
|
||||
glutin-winit = "0.4.2"
|
||||
taffy = "0.3.16"
|
||||
weak-table = "0.3.2"
|
||||
taffy = "0.4.0"
|
||||
weak-table = "0.3.2"
|
||||
cosmic-text = "0.11.2"
|
||||
swash = "0.1.12"
|
||||
lazy_static = "1.4.0"
|
||||
|
|
@ -185,8 +185,8 @@ impl Into<(f32, f32)> for Location {
|
|||
impl Into<Size<Dimension>> for Location {
|
||||
fn into(self) -> Size<Dimension> {
|
||||
Size {
|
||||
width: Dimension::Points(self.x as f32),
|
||||
height: Dimension::Points(self.y as f32)
|
||||
width: Dimension::Length(self.x as f32),
|
||||
height: Dimension::Length(self.y as f32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,9 @@ use glutin::{
|
|||
surface::{SurfaceAttributesBuilder, WindowSurface},
|
||||
};
|
||||
use taffy::geometry::Size;
|
||||
use taffy::style_helpers::TaffyMaxContent;
|
||||
use taffy::Taffy;
|
||||
use taffy::{style::AvailableSpace, TaffyTree};
|
||||
use weak_table::PtrWeakKeyHashMap;
|
||||
use crate::nodes::{layout_recursively, Node, render_recursively, RenderContext};
|
||||
use crate::nodes::{update_taffynode_children, MeasureContext, Node, render_recursively, RenderContext, prepare_render_recursively};
|
||||
|
||||
pub mod nodes;
|
||||
pub mod events;
|
||||
|
|
@ -41,7 +40,7 @@ pub type CurrentRenderer = OpenGl;
|
|||
pub type SharedNode = Arc<RwLock<dyn Node>>;
|
||||
type WeakNode = Weak<RwLock<dyn Node>>;
|
||||
type NodePtr = Option<Vec<WeakNode>>;
|
||||
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::node::Node>;
|
||||
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::tree::NodeId>;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref FONT_SYSTEM: Mutex<FontSystem> = Mutex::new(FontSystem::new());
|
||||
|
|
@ -77,7 +76,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
|
||||
let canvas = Canvas::new(renderer).expect("Cannot create canvas");
|
||||
|
||||
let mut taffy = Taffy::new();
|
||||
let mut taffy = TaffyTree::new();
|
||||
let mut taffy_map = NodeLayoutMap::new();
|
||||
{
|
||||
let clonned = entry.root.clone();
|
||||
|
|
@ -89,13 +88,15 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
taffy_map.insert(entry.root.clone(), taffy_root_node);
|
||||
}
|
||||
|
||||
let size = window.inner_size();
|
||||
let mut context = RenderContext {
|
||||
canvas,
|
||||
node_layout: taffy_map,
|
||||
taffy,
|
||||
mouse: None,
|
||||
keyboard_focus: None,
|
||||
scale_factor: window.scale_factor() as f32
|
||||
scale_factor: window.scale_factor() as f32,
|
||||
window_size: Size { width: size.width as f32, height: size.height as f32 }
|
||||
};
|
||||
let root = entry.root.clone();
|
||||
|
||||
|
|
@ -250,7 +251,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
if should_recompute {
|
||||
layout_recursively(&root, &mut context);
|
||||
update_taffynode_children(&root, &mut context);
|
||||
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
||||
context.node_layout.remove_expired();
|
||||
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
||||
|
|
@ -260,12 +261,33 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
dbg!("Removed node", src_node);
|
||||
}
|
||||
}
|
||||
prepare_render_recursively(&root, &mut context);
|
||||
for (node, taffy_node) in context.node_layout.iter() {
|
||||
let node = node.read().unwrap();
|
||||
let node_style = node.style();
|
||||
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
|
||||
}
|
||||
context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap();
|
||||
let size = window.inner_size();
|
||||
let size = Size { width: AvailableSpace::Definite(size.width as f32), height: AvailableSpace::Definite(size.height as f32) };
|
||||
let RenderContext { taffy, node_layout, canvas, scale_factor, .. } = &mut context;
|
||||
let mut measure_context = MeasureContext { canvas, scale_factor: *scale_factor };
|
||||
taffy.compute_layout_with_measure(
|
||||
*node_layout.get(&root).unwrap(),
|
||||
size,
|
||||
|known_dimensions, available_space, _node_id, node_context| {
|
||||
match node_context {
|
||||
Some(node) => {
|
||||
match node.upgrade() {
|
||||
Some(node) => {
|
||||
node.write().unwrap().measure(&mut measure_context, known_dimensions, available_space)
|
||||
},
|
||||
None => Size::ZERO
|
||||
}
|
||||
},
|
||||
None => Size::ZERO
|
||||
}
|
||||
},
|
||||
).unwrap();
|
||||
should_recompute = false;
|
||||
// Additional optimizations could be done here
|
||||
// - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty)
|
||||
|
|
@ -275,7 +297,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
// could perhaps be a significant boost regarding memory usage (and performance) during large layout changes
|
||||
// dbg!("recomputed");
|
||||
}
|
||||
// dbg!(&root);
|
||||
// Clear the render queue
|
||||
while let Ok(_) = entry.render.try_recv() {}
|
||||
render(&buffer_context, &surface, &window, &mut context, &root);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use std::{fmt::Debug, mem, path::PathBuf};
|
||||
use std::sync::Mutex;
|
||||
use femtovg::{Color, ErrorKind, ImageFlags, ImageId, Paint, Path};
|
||||
use taffy::{AvailableSpace, Size};
|
||||
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode};
|
||||
use super::{Node, NodeChildren, Style};
|
||||
use super::{MeasureContext, Node, NodeChildren, RenderContext, Style};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
/// Status of the image - when rendering, image node attempts to load the image and sets this status accordingly.
|
||||
/// Changes this if you want to change the image. If the previous status was loaded, free the image.
|
||||
/// In case the loading fails, image load status changes to Error and the node doesn't render.
|
||||
|
|
@ -11,27 +13,48 @@ pub enum ImageLoad {
|
|||
LoadFile(PathBuf, ImageFlags),
|
||||
// LoadArray(&[u8]),
|
||||
LoadVec(Vec<u8>, ImageFlags),
|
||||
Loaded(ImageId),
|
||||
Error(ErrorKind)
|
||||
Loaded(ImageHandle),
|
||||
Error(ErrorKind),
|
||||
#[default]
|
||||
Empty
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ImageHandle {
|
||||
image: ImageId
|
||||
}
|
||||
|
||||
impl ImageHandle {
|
||||
fn new(image: ImageId) -> ImageHandle {
|
||||
ImageHandle {
|
||||
image
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ImageHandle {
|
||||
fn drop(&mut self) {
|
||||
IMAGES_TO_UNLOAD.lock().unwrap().push(self.image);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
/// Image node.
|
||||
/// Sadly doesn't implement `Default` because of the `ImageLoad` enum.
|
||||
pub struct Image {
|
||||
pub style: Style,
|
||||
/// The image to be rendered.
|
||||
pub image: ImageLoad,
|
||||
/// Image width - note that you also have to set the style accordingly for it to render correctly, this is more about scaling the image
|
||||
pub width: f32,
|
||||
/// Image height - note that you also have to set the style accordingly for it to render correctly, this is more about scaling the image
|
||||
pub height: f32,
|
||||
/// Border radius
|
||||
pub radius: f32,
|
||||
pub events: EventHandlerDatabase,
|
||||
pub parent: Option<WeakNode>
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref IMAGES_TO_UNLOAD: Mutex<Vec<ImageId>> = Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
impl Node for Image {
|
||||
fn style(&self) -> &Style {
|
||||
&self.style
|
||||
|
|
@ -41,14 +64,14 @@ impl Node for Image {
|
|||
None
|
||||
}
|
||||
|
||||
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
|
||||
fn prepare_render(&mut self, context: &mut RenderContext) {
|
||||
match &self.image {
|
||||
ImageLoad::LoadFile(_, _) => {
|
||||
let image = mem::replace(&mut self.image, ImageLoad::Error(ErrorKind::UnknownError));
|
||||
if let ImageLoad::LoadFile(path, flags) = image {
|
||||
match context.canvas.load_image_file(path, flags) {
|
||||
Ok(image) => {
|
||||
self.image = ImageLoad::Loaded(image);
|
||||
self.image = ImageLoad::Loaded(ImageHandle::new(image));
|
||||
},
|
||||
Err(e) => {
|
||||
self.image = ImageLoad::Error(e);
|
||||
|
|
@ -59,7 +82,7 @@ impl Node for Image {
|
|||
ImageLoad::LoadVec(data, flags) => {
|
||||
match context.canvas.load_image_mem(data, *flags) {
|
||||
Ok(image) => {
|
||||
self.image = ImageLoad::Loaded(image);
|
||||
self.image = ImageLoad::Loaded(ImageHandle::new(image));
|
||||
},
|
||||
Err(e) => {
|
||||
self.image = ImageLoad::Error(e);
|
||||
|
|
@ -68,6 +91,9 @@ impl Node for Image {
|
|||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
|
||||
let mut path = Path::new();
|
||||
path.rounded_rect(
|
||||
0.,
|
||||
|
|
@ -80,13 +106,37 @@ impl Node for Image {
|
|||
ImageLoad::Loaded(image) => {
|
||||
context.canvas.fill_path(
|
||||
&path,
|
||||
&Paint::image(*image, 0., 0., self.width, self.height, 0., 1.)
|
||||
&Paint::image(image.image, 0., 0., layout.size.width, layout.size.height, 0., 1.)
|
||||
);
|
||||
},
|
||||
ImageLoad::Error(_) => {
|
||||
context.canvas.fill_path(&path, &Paint::color(Color::rgb(255, 0, 0)))
|
||||
},
|
||||
_ => unreachable!("We just loaded the image before, so it's either loaded or errored out.")
|
||||
_ => {
|
||||
// this shouldn't happen as the image should be loaded earlier during the render pass,
|
||||
// but someone can still change the image in another thread
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn measure(&mut self, context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, _available_space: Size<AvailableSpace>) -> Size<f32> {
|
||||
match &self.image {
|
||||
ImageLoad::Loaded(image) => {
|
||||
match context.canvas.image_size(image.image) {
|
||||
Ok((img_width, img_height)) => {
|
||||
let img_width = img_width as f32;
|
||||
let img_height = img_height as f32;
|
||||
match (known_dimensions.width, known_dimensions.height) {
|
||||
(Some(width), Some(height)) => Size { width, height },
|
||||
(Some(width), None) => Size { width, height: (width / img_width) * img_height },
|
||||
(None, Some(height)) => Size { width: (height / img_height) * img_width, height },
|
||||
(None, None) => Size { width: img_width, height: img_height },
|
||||
}
|
||||
},
|
||||
_ => Size::ZERO
|
||||
}
|
||||
},
|
||||
_ => Size::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ impl Node for Layout {
|
|||
Some(&self.children)
|
||||
}
|
||||
fn resize(&mut self, width: f32, height: f32) {
|
||||
self.style.layout.size.width = Dimension::Points(width);
|
||||
self.style.layout.size.height = Dimension::Points(height);
|
||||
self.style.layout.size.width = Dimension::Length(width);
|
||||
self.style.layout.size.height = Dimension::Length(height);
|
||||
}
|
||||
|
||||
fn add_child_at(&mut self, child: crate::SharedNode, index: usize) -> Result<(), super::ChildAddError> {
|
||||
|
|
|
|||
|
|
@ -7,22 +7,27 @@ pub mod text_render_cache;
|
|||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use femtovg::{Canvas, Color};
|
||||
use taffy::layout::Layout;
|
||||
use taffy::Taffy;
|
||||
use crate::events::Location;
|
||||
use crate::events::handler::InnerEventHandlerDataset;
|
||||
use crate::{NodeLayoutMap, NodePtr, CurrentRenderer, SharedNode, WeakNode};
|
||||
|
||||
pub use taffy::style::Style as TaffyStyle;
|
||||
use taffy::{Layout, Overflow, Size, TaffyTree};
|
||||
|
||||
pub type CanvasRenderer = Canvas<CurrentRenderer>;
|
||||
|
||||
pub struct RenderContext {
|
||||
pub canvas: CanvasRenderer,
|
||||
pub node_layout: NodeLayoutMap,
|
||||
pub taffy: Taffy,
|
||||
pub taffy: TaffyTree<WeakNode>,
|
||||
pub mouse: NodePtr,
|
||||
pub keyboard_focus: NodePtr,
|
||||
pub scale_factor: f32,
|
||||
pub window_size: Size<f32>
|
||||
}
|
||||
|
||||
pub struct MeasureContext<'a> {
|
||||
pub canvas: &'a mut CanvasRenderer,
|
||||
pub scale_factor: f32
|
||||
}
|
||||
|
||||
|
|
@ -39,18 +44,6 @@ impl RenderContext {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum Overflow {
|
||||
#[default]
|
||||
/// Content is not clipped and may be rendered outside the element's box
|
||||
Visible,
|
||||
/// Clips the content at the border of the element
|
||||
Hidden,
|
||||
// tbd :)
|
||||
// Scroll,
|
||||
// Auto
|
||||
}
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub enum Cursor {
|
||||
#[default]
|
||||
|
|
@ -59,7 +52,6 @@ pub enum Cursor {
|
|||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Style {
|
||||
pub layout: TaffyStyle,
|
||||
pub overflow: Overflow,
|
||||
pub cursor: Cursor
|
||||
}
|
||||
|
||||
|
|
@ -95,9 +87,26 @@ pub enum ChildAddError {
|
|||
/// # Events
|
||||
///
|
||||
/// If you need to handle events, implement [`Node::event_handlers`].
|
||||
///
|
||||
/// # Function call order
|
||||
///
|
||||
/// Read-only functions are called in any order (style, children, event_handlers, measure).
|
||||
///
|
||||
/// `resize` is called independently of the rendering process, but not concurrently with it. The render process is single-threaded.
|
||||
///
|
||||
/// During rendering, the order is following:
|
||||
///
|
||||
/// - parents are changed ([`Node::set_parent`]) to new state according to read-only functions
|
||||
/// - [`Node::prepare_render`] is called on each node
|
||||
/// - [`Node::style`] is read
|
||||
/// - [`Node::measure`] is called on some nodes (depends on taffy); can be called multiple times
|
||||
/// - nodes are rendered, i.e. on each node, starting from the root node, the following is called:
|
||||
/// - [`Node::render_pre_children`] is called
|
||||
/// - children are rendered
|
||||
/// - [`Node::render_post_children`] is called
|
||||
pub trait Node: Debug {
|
||||
/// Return style.
|
||||
///
|
||||
///insert
|
||||
/// If you're using [`Style`] in your struct directly, your implementation can be as simple as:
|
||||
/// ```rust
|
||||
/// fn style(&self) -> &Style { &self.style }
|
||||
|
|
@ -219,6 +228,22 @@ pub trait Node: Debug {
|
|||
None
|
||||
}
|
||||
|
||||
/// Called on each redraw. Use this to prepare for rendering. Called before any layouting or rendering happens.
|
||||
/// Order between nodes is not guaranteed.
|
||||
fn prepare_render(&mut self, _context: &mut RenderContext) {}
|
||||
|
||||
/// Called before rendering the node to measure it's size.
|
||||
/// The calling of this method is managed by taffy, and as such:
|
||||
/// - It may be called multiple times (with same or different arguments) during the same render pass
|
||||
/// - It may not be called at all
|
||||
/// - order between nodes is not guaranteed
|
||||
///
|
||||
/// If you need to change self during layouting, use [`Node::prepare_render`] to do so.
|
||||
/// You're getting &mut self here to support things like cosmic text that require changing text data to measure it.
|
||||
fn measure(&mut self, _context: &mut MeasureContext, _known_dimensions: Size<Option<f32>>, _available_space: Size<taffy::AvailableSpace>) -> Size<f32> {
|
||||
Size::ZERO
|
||||
}
|
||||
|
||||
/// Returns true if the node has the given child
|
||||
/// Returns false if there are no children (or if the node does not support children)
|
||||
fn has_child(&self, child: &SharedNode) -> Option<usize> {
|
||||
|
|
@ -295,12 +320,15 @@ pub(crate) fn get_element_at(node: &SharedNode, context: &RenderContext, locatio
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn layout_recursively(node: &SharedNode, context: &mut RenderContext) -> taffy::node::Node {
|
||||
pub(crate) fn update_taffynode_children(node: &SharedNode, context: &mut RenderContext) -> taffy::tree::NodeId {
|
||||
let taffy_node = context.node_layout.get(node);
|
||||
let taffy_node = match taffy_node {
|
||||
Some(taffy_node) => taffy_node,
|
||||
None => {
|
||||
let taffy_node = context.taffy.new_leaf(node.read().unwrap().style().layout.to_owned()).unwrap();
|
||||
let taffy_node = context.taffy.new_leaf_with_context(
|
||||
node.read().unwrap().style().layout.to_owned(),
|
||||
Arc::downgrade(node)
|
||||
).unwrap();
|
||||
context.node_layout.insert(node.clone(), taffy_node);
|
||||
context.node_layout.get(node).unwrap()
|
||||
}
|
||||
|
|
@ -313,7 +341,7 @@ pub(crate) fn layout_recursively(node: &SharedNode, context: &mut RenderContext)
|
|||
Some(children) => {
|
||||
let mut t_children = Vec::with_capacity(children.len());
|
||||
for child in children {
|
||||
t_children.push(layout_recursively(child, context).to_owned());
|
||||
t_children.push(update_taffynode_children(child, context).to_owned());
|
||||
child.write().unwrap().set_parent(Some(Arc::downgrade(node)));
|
||||
}
|
||||
context.taffy.set_children(taffy_node, t_children.as_slice()).unwrap();
|
||||
|
|
@ -331,16 +359,15 @@ pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext)
|
|||
let sself = node.clone();
|
||||
context.canvas.save();
|
||||
context.canvas.translate(layout.location.x, layout.location.y);
|
||||
match styles.overflow {
|
||||
Overflow::Visible => {},
|
||||
Overflow::Hidden => {
|
||||
context.canvas.scissor(
|
||||
0.,
|
||||
0.,
|
||||
layout.size.width,
|
||||
layout.size.height,
|
||||
);
|
||||
}
|
||||
let clip_width = matches!(styles.layout.overflow.x, Overflow::Hidden | Overflow::Clip);
|
||||
let clip_height = matches!(styles.layout.overflow.y, Overflow::Hidden | Overflow::Clip);
|
||||
if clip_width || clip_height {
|
||||
context.canvas.scissor(
|
||||
0.,
|
||||
0.,
|
||||
if clip_width { layout.size.width } else { f32::INFINITY },
|
||||
if clip_height { layout.size.height } else { f32::INFINITY },
|
||||
);
|
||||
}
|
||||
drop(read_node);
|
||||
sself.write().unwrap().render_pre_children(context, layout);
|
||||
|
|
@ -351,4 +378,14 @@ pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext)
|
|||
}
|
||||
sself.write().unwrap().render_post_children(context, layout);
|
||||
context.canvas.restore();
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_render_recursively(node: &SharedNode, context: &mut RenderContext) {
|
||||
let mut write_node = node.write().unwrap();
|
||||
write_node.prepare_render(context);
|
||||
if let Some(children) = write_node.children() {
|
||||
for child in children {
|
||||
prepare_render_recursively(child, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use femtovg::{Color, Paint, Path};
|
||||
use taffy::layout::Layout;
|
||||
use taffy::Layout;
|
||||
use crate::{nodes::{Node, NodeChildren, RenderContext, Style}, events::handler::EventHandlerDatabase, WeakNode, SharedNode};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use std::fmt::Debug;
|
||||
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM};
|
||||
use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style};
|
||||
use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style, MeasureContext, RenderContext};
|
||||
use cosmic_text::{Attrs, Buffer, Metrics, Shaping};
|
||||
use femtovg::Paint;
|
||||
use femtovg::{Color, Paint, Path};
|
||||
use taffy::{AvailableSpace, Size};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Text {
|
||||
|
|
@ -24,22 +25,66 @@ impl Node for Text {
|
|||
None
|
||||
}
|
||||
|
||||
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
|
||||
fn prepare_render(&mut self, _context: &mut RenderContext) {
|
||||
if let None = self.buffer {
|
||||
self.buffer = Some(Buffer::new(&mut FONT_SYSTEM.lock().unwrap(), self.metrics));
|
||||
}
|
||||
let buf = self.buffer.as_mut().unwrap();
|
||||
let mut font = FONT_SYSTEM.lock().unwrap();
|
||||
buf.set_text(&mut font, &self.text, Attrs::new(), Shaping::Advanced);
|
||||
}
|
||||
|
||||
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
|
||||
// this can crash, but it should crash earlier during measure -> see the comment there.
|
||||
let buf = self.buffer.as_mut().unwrap();
|
||||
let mut font = FONT_SYSTEM.lock().unwrap();
|
||||
buf.set_size(&mut font, layout.size.width, layout.size.height);
|
||||
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
||||
// fill_to_cmds requires FONT_SYSTEM lock.
|
||||
drop(font);
|
||||
let mut path = Path::new();
|
||||
path.rounded_rect(
|
||||
0.,
|
||||
0.,
|
||||
layout.size.width,
|
||||
layout.size.height,
|
||||
0.
|
||||
);
|
||||
context.canvas.fill_path(
|
||||
&path,
|
||||
&Paint::color(Color::rgb(255, 0, 0))
|
||||
);
|
||||
let cmds = RENDER_CACHE.lock().unwrap()
|
||||
.fill_to_cmds(&mut context.canvas, buf, (0.0, 0.0), context.scale_factor)
|
||||
.unwrap();
|
||||
context.canvas.draw_glyph_commands(cmds, &self.paint, 1.0);
|
||||
}
|
||||
|
||||
fn measure(&mut self, _context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
|
||||
let width_constraint = known_dimensions.width.unwrap_or(match available_space.width {
|
||||
AvailableSpace::MinContent => 0.0,
|
||||
AvailableSpace::MaxContent => f32::INFINITY,
|
||||
AvailableSpace::Definite(width) => width,
|
||||
});
|
||||
// yes, this can crash if someone removes `buffer` during render from another thread.
|
||||
// though they're asking for it, so let them crash.
|
||||
let buf = self.buffer.as_mut().unwrap();
|
||||
buf.set_size(&mut FONT_SYSTEM.lock().unwrap(), width_constraint, f32::INFINITY);
|
||||
|
||||
// Compute layout
|
||||
buf.shape_until_scroll(&mut FONT_SYSTEM.lock().unwrap(), false);
|
||||
|
||||
// Determine measured size of text
|
||||
let (width, total_lines) = buf
|
||||
.layout_runs()
|
||||
.fold((0.0, 0usize), |(width, total_lines), run| (run.line_w.max(width), total_lines + 1));
|
||||
let height = total_lines as f32 * buf.metrics().line_height;
|
||||
// fixes flickering of text on devices with non-integer scale factors due to loss of precision
|
||||
let width = width + 0.5;
|
||||
|
||||
Size { width, height }
|
||||
}
|
||||
|
||||
fn event_handlers(&self) -> Option<crate::events::handler::InnerEventHandlerDataset> {
|
||||
Some(self.events.handlers.clone())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ lazy_static::lazy_static! {
|
|||
}
|
||||
|
||||
impl RenderCache {
|
||||
/// Generates draw commands from cosmic text buffer.
|
||||
/// Note that this requires a lock on FONT_SYSTEM.
|
||||
pub(crate) fn fill_to_cmds(
|
||||
&mut self,
|
||||
canvas: &mut CanvasRenderer,
|
||||
|
|
|
|||
Loading…
Reference in a new issue