1use glam::Vec2;
10use wisp::application::Application;
11use wisp::render::Renderer;
12use wisp::text::{CaptionBlock, TextPreset, TextTexturePipeline, WispText};
13use wisp::texture::render_texture::RenderTexture;
14use wisp::{Color, Container, Fill, Graphics, Sprite, Stage, Stroke};
15
16use crate::story::Story;
17
18pub fn story() -> Story {
19 Story {
20 id: "text-callouts",
21 category: "Text",
22 title: "Callout boxes + label + badges + arrows",
23 milestone: "M-TEXT.10",
24 writeup: include_str!("writeups/text_callouts.md"),
25 build,
26 tick: None,
27 }
28}
29
30fn build(app: &Application, stage: &mut Stage) {
31 let pipeline = TextTexturePipeline::new(app, wgpu::TextureFormat::Rgba8UnormSrgb);
32 let root = stage.root();
33
34 let format = wgpu::TextureFormat::Rgba8Unorm;
36 let renderer = Renderer::new(app, format).expect("renderer");
37 let backdrop_rt = RenderTexture::with_format(app, 256, 256, format);
38 let _ = renderer.render_stage(
39 app,
40 backdrop_rt.view(),
41 Color::rgba(0.92, 0.93, 0.95, 1.0),
42 &Stage::new(),
43 );
44 let backdrop_bytes = backdrop_rt.read_pixels(app);
45 let backdrop_tex = wisp::Texture::from_rgba(app, 256, 256, &backdrop_bytes);
46 let mut backdrop = Sprite::from_texture(backdrop_tex).with_anchor(Vec2::splat(0.5));
47 backdrop.container.transform.scale = Vec2::splat(2.0);
48 let _ = stage.add_child(root, backdrop);
49
50 let pill = CaptionBlock::from_text(
52 WispText::new("Now recording")
53 .with_style(TextPreset::Caption.style().with_color(Color::WHITE)),
54 )
55 .with_width(0.7)
56 .with_padding(0.04)
57 .with_radius(0.10)
58 .with_background(Color::rgba_u8(220, 60, 80, 240));
59 let layout = pill.layout(app, &pipeline);
60 let mut cont = Container::new();
61 cont.transform.position = Vec2::new(-0.35, 0.75);
62 let id = stage.add_child(root, cont).expect("attach");
63 let _ = stage.add_child(id, layout.background);
64 let _ = stage.add_child(id, layout.text_sprite);
65
66 let mut badge_bg = Graphics::new();
68 badge_bg.fill(Fill::Solid(Color::rgba_u8(45, 130, 220, 255)));
69 badge_bg.draw_ellipse(Vec2::new(-0.65, 0.35), Vec2::splat(0.08));
70 let _ = stage.add_child(root, badge_bg);
71
72 let n_text =
73 WispText::new("3").with_style(TextPreset::StepBadge.style().with_color(Color::WHITE));
74 let n_rt = pipeline.render(app, &n_text, 192, 192);
75 let mut n_sprite = Sprite::from_texture(n_rt.as_texture()).with_anchor(Vec2::splat(0.5));
76 n_sprite.container.transform.position = Vec2::new(-0.65, 0.35);
77 n_sprite.container.transform.scale = Vec2::new(0.12, -0.12);
78 let _ = stage.add_child(root, n_sprite);
79
80 let label = CaptionBlock::from_text(
82 WispText::new("Caption block")
83 .with_style(TextPreset::Caption.style().with_color(Color::WHITE)),
84 )
85 .with_width(0.55)
86 .with_padding(0.04)
87 .with_radius(0.04)
88 .with_background(Color::rgba_u8(20, 28, 40, 220));
89 let lab_layout = label.layout(app, &pipeline);
90 let mut lab_cont = Container::new();
91 lab_cont.transform.position = Vec2::new(-0.45, -0.05);
92 let lab_id = stage.add_child(root, lab_cont).expect("attach");
93 let _ = stage.add_child(lab_id, lab_layout.background);
94 let _ = stage.add_child(lab_id, lab_layout.text_sprite);
95
96 let mut pointer = Graphics::new();
98 pointer.stroke(Some(Stroke::new(0.012, Color::rgba_u8(20, 28, 40, 255))));
99 pointer.fill(Fill::Solid(Color::TRANSPARENT));
100 pointer.draw_line(Vec2::new(0.10, 0.05), Vec2::new(0.55, -0.20), 0.012);
101 pointer.fill(Fill::Solid(Color::rgba_u8(20, 28, 40, 255)));
103 pointer.draw_ellipse(Vec2::new(0.55, -0.20), Vec2::splat(0.02));
104 let _ = stage.add_child(root, pointer);
105
106 let mut arrow = Graphics::new();
110 arrow.fill(Fill::Solid(Color::TRANSPARENT));
111 let arrow_color = Color::rgba_u8(45, 130, 220, 255);
112 arrow.stroke(Some(Stroke::new(0.014, arrow_color)));
113 let arrow_tip = Vec2::new(-0.20, -0.75);
114 let arrow_tail = Vec2::new(0.45, -0.45);
115 arrow.draw_line(arrow_tail, arrow_tip, 0.014);
116 arrow.draw_line(arrow_tip, arrow_tip + Vec2::new(0.10, 0.04), 0.014);
118 arrow.draw_line(arrow_tip, arrow_tip + Vec2::new(0.07, 0.10), 0.014);
119 let _ = stage.add_child(root, arrow);
120
121 let arrow_label = WispText::new("click").with_style(
123 TextPreset::Caption
124 .style()
125 .with_color(Color::rgba_u8(45, 130, 220, 255)),
126 );
127 let al_rt = pipeline.render(app, &arrow_label, 384, 192);
128 let mut al_sprite = Sprite::from_texture(al_rt.as_texture()).with_anchor(Vec2::new(0.0, 0.5));
129 al_sprite.container.transform.position = Vec2::new(0.48, -0.42);
130 al_sprite.container.transform.scale = Vec2::new(0.45, -0.18);
131 let _ = stage.add_child(root, al_sprite);
132}