GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
examples/probe/scene.rs (6.4K)
1 //! The renderer probe's scene: one app drawn by both renderers, natively in
2 //! the Wayland runner (`probe_native`) and in a browser through the WebGPU
3 //! renderer (`probe_web`), so the two can be compared pixel for pixel.
4 //!
5 //! It reaches every path a frame takes: the root plate and its roll, flat
6 //! fills, a checker under frosted plates in all three frost recipes (the
7 //! blur snapshot), raised / flush / flat control plates, fields in each form,
8 //! recesses, bevels, a sphere, grooves, circles and capped vectors, text in
9 //! two families at four sizes, and an uploaded image drawn at two sizes.
10
11 use cce_ui::engine::{AppSender, Application, LogicalPosition, LogicalSize, WindowSettings};
12 use cce_ui::scene::layout::Rect;
13 use cce_ui::scene::paint::{Cap, ControlPlate, DisplayList, Field, PaintCtx, PlateSpec, PlateStance};
14 use cce_ui::scene::{Frost, Material};
15 use cce_ui::widget::{ElementState, KeyEvent, MouseButton, MouseScrollDelta};
16
17 pub const W: u32 = 1280;
18 pub const H: u32 = 800;
19
20 pub struct ProbeApp {
21 image: u32,
22 }
23
24 fn r(x: f32, y: f32, w: f32, h: f32) -> Rect {
25 Rect { x, y, width: w, height: h }
26 }
27
28 const SANS: &str = "DejaVu Sans";
29 const MONO: &str = "DejaVu Sans Mono";
30
31 impl Application for ProbeApp {
32 type Message = ();
33
34 fn create(_sender: AppSender<()>) -> Self {
35 cce_ui::scale::set_scale_factor(1.0);
36 let (iw, ih) = (64u32, 40u32);
37 let mut px = Vec::with_capacity((iw * ih * 4) as usize);
38 for y in 0..ih {
39 for x in 0..iw {
40 px.extend([(x * 255 / (iw - 1)) as u8, (y * 255 / (ih - 1)) as u8, 160, 255]);
41 }
42 }
43 ProbeApp { image: cce_ui::draw::upload_rgba(px, iw, ih) }
44 }
45
46 fn settings(&self) -> WindowSettings {
47 WindowSettings { title: "probe".into(), app_id: "cce-probe".into(), width: W, height: H, fullscreen: false, min_size: None }
48 }
49
50 fn load_system_fonts(&self) -> bool {
51 true
52 }
53
54 fn display_list_text(&self) -> bool {
55 true
56 }
57
58 fn update(&mut self, _: (), _: &mut bool, _: &mut bool) {}
59 fn tick(&mut self, _: f32, _: &mut bool) {}
60
61 fn display_list(&mut self, size: LogicalSize, scale: f64) -> Option<DisplayList> {
62 cce_ui::scale::set_scale_factor(scale as f32);
63 let (w, h) = (size.width, size.height);
64 let mut pc = PaintCtx::new();
65 pc.root_plate(w, h);
66
67 // A checker under three frosted plates: unfrosted-compression,
68 // compressed, and clear (frost_pair's recipes).
69 for i in 0..16 {
70 let c = if i % 2 == 0 { [1.0, 1.0, 1.0, 1.0] } else { [0.02, 0.02, 0.03, 1.0] };
71 pc.quad(r(30.0 + i as f32 * 30.0, 30.0, 30.0, 220.0), c);
72 }
73 let tint = [0.0015, 0.0015, 0.0024, 0.25];
74 for (i, (k, radius)) in [(0.0, Frost::DEFAULT_RADIUS), (0.85, Frost::DEFAULT_RADIUS), (0.0, 0.0)].iter().enumerate() {
75 let m = Material::opaque(tint).with_frost(Frost::Frosted { compression: *k, refraction: 0.0, radius: *radius });
76 pc.plate_spec(&PlateSpec {
77 rect: r(40.0 + i as f32 * 155.0, 60.0, 140.0, 160.0),
78 material: m,
79 window_corners: (false, false, false, false),
80 depth: 6.0,
81 });
82 }
83
84 // A pane plate with the control vocabulary on it.
85 pc.plate_spec(&PlateSpec {
86 rect: r(540.0, 30.0, 700.0, 330.0),
87 material: Material::pane(),
88 window_corners: (false, false, false, false),
89 depth: cce_ui::layout::bevel_width(),
90 });
91 let face = Some(Material::opaque([0.18, 0.22, 0.32, 1.0]));
92 pc.control_plate(&ControlPlate::control(r(570.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Raised, face));
93 pc.control_plate(&ControlPlate::control(r(730.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Raised, None));
94 pc.control_plate(&ControlPlate::control(r(890.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Flush, None));
95 pc.control_plate(&ControlPlate::control(r(1050.0, 60.0, 140.0, 36.0), 8.0, PlateStance::Flat, face));
96 let radii = (8.0, 8.0, 8.0, 8.0);
97 pc.field(&Field::well(r(570.0, 120.0, 300.0, 34.0), radii, 6.0));
98 pc.field(&Field::ending_in_run(r(890.0, 120.0, 300.0, 34.0), radii, 6.0, 1150.0));
99 pc.field(&Field::sliding_run(r(570.0, 180.0, 90.0, 34.0), (17.0, 17.0, 17.0, 17.0), 6.0, 45.0, 0.0));
100 pc.field(&Field::sliding_run(r(680.0, 180.0, 90.0, 34.0), (17.0, 17.0, 17.0, 17.0), 6.0, 45.0, 1.0));
101 pc.recess(r(800.0, 180.0, 120.0, 60.0), (12.0, 12.0, 12.0, 12.0), 8.0);
102 pc.bevel(r(950.0, 180.0, 120.0, 60.0), (12.0, 12.0, 12.0, 12.0), &Material::opaque([0.35, 0.30, 0.42, 1.0]), 8.0);
103 pc.sphere(1140.0, 210.0, 30.0, &Material::opaque([0.55, 0.25, 0.25, 1.0]));
104 let host = r(540.0, 30.0, 700.0, 330.0);
105 pc.groove((570.0, 280.0), (1210.0, 280.0), 4.0, 3.0, host);
106 pc.groove((600.0, 300.0), (760.0, 340.0), 4.0, 3.0, host);
107
108 // Flat geometry: circles and capped vectors.
109 for (i, cap) in [Cap::Flat, Cap::Round, Cap::Arrow].into_iter().enumerate() {
110 let y = 300.0 + i as f32 * 25.0;
111 pc.vector(820.0, y, 1000.0, y + 10.0, 5.0, [0.9, 0.6, 0.2, 1.0], cap);
112 }
113 pc.circle(1080.0, 320.0, 22.0, [0.2, 0.7, 0.5, 1.0]);
114 pc.circle(1150.0, 320.0, 22.0, [0.2, 0.5, 0.9, 0.6]);
115
116 // Text, two families at four sizes.
117 let mut y = 400.0;
118 for (i, size) in [11.0, 14.0, 20.0, 28.0].into_iter().enumerate() {
119 let family = if i % 2 == 0 { SANS } else { MONO };
120 pc.text_with(
121 format!("The quick brown fox jumps over the lazy dog — {size}px {family}"),
122 40.0,
123 y,
124 size,
125 [230, 230, 236],
126 Some(family.to_string()),
127 None,
128 );
129 y += size * 1.8;
130 }
131
132 // The image, at its size and scaled up.
133 pc.image(self.image, r(40.0, 620.0, 64.0, 40.0), 1.0);
134 pc.image(self.image, r(130.0, 600.0, 256.0, 160.0), 0.85);
135
136 Some(pc.finish())
137 }
138
139 fn handle_pointer_move(&mut self, _: LogicalPosition, _: &mut bool) {}
140 fn handle_mouse_input(&mut self, _: MouseButton, _: ElementState, _: LogicalPosition, _: &mut bool) -> Option<()> {
141 None
142 }
143 fn handle_mouse_wheel(&mut self, _: &MouseScrollDelta, _: LogicalPosition, _: &mut bool) {}
144 fn handle_key_input(&mut self, _: &KeyEvent, _: &mut bool) -> Option<()> {
145 None
146 }
147 }