1use decay::prelude::*;
2
3fn main() {
4 decay::term::spawn_window();
5
6 App::new()
7 .plugin(CorePlugins)
8 .plugin(IntroPlugin)
9 .plugin(UiPlugin)
10 .system(Phase::Init, setup)
11 .system(Phase::Update, handle_buttons)
12 .run();
13}
14
15struct StatusLabel(Entity);
16impl Resource for StatusLabel {}
17
18struct CounterLabel(Entity);
19impl Resource for CounterLabel {}
20
21struct ClickCount(u32);
22impl Resource for ClickCount {}
23
24fn setup(world: &mut World) {
25 let root = world.spawn((
27 Node::new(0, 0, 0, 0),
28 Container,
29 Anchor::fill(),
30 ));
31
32 world.spawn((
34 Node::new(0, 0, 0, 0),
35 Text::new("Decay UI Demo"),
36 UiStyle { fg: Some((100, 160, 255)), bold: true, ..UiStyle::new() },
37 Anchor { min: (0.0, 0.0), max: (0.6, 0.0), offset: (4, 1, 0, 2) },
38 Parent(root),
39 ));
40
41 world.spawn((
43 Node::new(0, 0, 0, 0),
44 Text::new("A TUI framework built on an ECS core"),
45 UiStyle::dim(),
46 Anchor { min: (0.0, 0.0), max: (0.6, 0.0), offset: (4, 2, 0, 3) },
47 Parent(root),
48 ));
49
50 world.spawn((
52 Node::new(0, 0, 0, 0),
53 Separator::new(),
54 Anchor { min: (0.0, 0.0), max: (0.6, 0.0), offset: (4, 4, 0, 5) },
55 Parent(root),
56 ));
57
58 let status = world.spawn((
60 Node::new(0, 0, 0, 0),
61 Text::new("Select a button and press Enter..."),
62 Anchor { min: (0.0, 0.0), max: (0.7, 0.0), offset: (4, 6, 0, 7) },
63 Parent(root),
64 ));
65 world.insert_resource(StatusLabel(status));
66
67 let counter = world.spawn((
69 Node::new(0, 0, 0, 0),
70 Text::new("Clicks: 0"),
71 UiStyle::dim(),
72 Anchor { min: (0.0, 0.0), max: (0.7, 0.0), offset: (4, 7, 0, 8) },
73 Parent(root),
74 ));
75 world.insert_resource(CounterLabel(counter));
76 world.insert_resource(ClickCount(0));
77
78 world.spawn((
80 Node::new(0, 0, 0, 0),
81 Text::new("Say Hello"), Button, Interaction::None,
82 Anchor { min: (0.0, 0.0), max: (0.45, 0.0), offset: (4, 10, 0, 13) },
83 Parent(root),
84 ));
85
86 world.spawn((
87 Node::new(0, 0, 0, 0),
88 Text::new("Say Goodbye"), Button, Interaction::None,
89 Anchor { min: (0.0, 0.0), max: (0.45, 0.0), offset: (4, 14, 0, 17) },
90 Parent(root),
91 ));
92
93 world.spawn((
94 Node::new(0, 0, 0, 0),
95 Text::new("Reset Counter"), Button, Interaction::None,
96 Anchor { min: (0.0, 0.0), max: (0.45, 0.0), offset: (4, 18, 0, 21) },
97 Parent(root),
98 ));
99
100 world.spawn((
102 Node::new(0, 0, 0, 0),
103 Text::new("\u{2191}\u{2193}/Tab Navigate Enter/Space Click q Quit"),
104 UiStyle::dim(),
105 Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (4, 22, 0, 23) },
106 Parent(root),
107 ));
108}
109
110fn handle_buttons(world: &mut World) {
111 if world
112 .resource::<Input>()
113 .is_some_and(|i| i.just_pressed(KeyCode::Char('q')) || i.just_pressed(KeyCode::Escape))
114 {
115 world.resource_mut::<AppExit>().unwrap().0 = true;
116 return;
117 }
118
119 let pressed_text: Option<String> = world
120 .query::<(&Interaction, &Text)>()
121 .find(|(_, (i, _))| **i == Interaction::Pressed)
122 .map(|(_, (_, t))| t.value.clone());
123
124 if let Some(btn_text) = pressed_text {
125 let is_reset = btn_text == "Reset Counter";
126
127 if is_reset {
128 world.resource_mut::<ClickCount>().unwrap().0 = 0;
129 } else {
130 world.resource_mut::<ClickCount>().unwrap().0 += 1;
131 }
132
133 let status_e = world.resource::<StatusLabel>().unwrap().0;
134 let msg = match btn_text.as_str() {
135 "Say Hello" => "Hello, World!",
136 "Say Goodbye" => "Goodbye, World!",
137 "Reset Counter" => "Counter reset.",
138 _ => "Unknown",
139 };
140 if let Some(text) = world.get_mut::<Text>(status_e) {
141 text.value = msg.to_string();
142 }
143
144 let count = world.resource::<ClickCount>().unwrap().0;
145 let counter_e = world.resource::<CounterLabel>().unwrap().0;
146 if let Some(text) = world.get_mut::<Text>(counter_e) {
147 text.value = format!("Clicks: {}", count);
148 }
149 }
150}