button/
button.rs

1//! Simple button, port of <https://github.com/bevyengine/bevy/blob/main/examples/ui/button.rs>.
2
3mod utils;
4use utils::*;
5
6use bevy::prelude::*;
7use haalka::prelude::*;
8
9fn main() {
10    App::new()
11        .add_plugins(examples_plugin)
12        .add_systems(
13            Startup,
14            (
15                |world: &mut World| {
16                    ui_root().spawn(world);
17                },
18                camera,
19            ),
20        )
21        .run();
22}
23
24const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
25const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
26const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
27
28fn button() -> impl Element {
29    let (pressed, pressed_signal) = Mutable::new_and_signal(false);
30    let (hovered, hovered_signal) = Mutable::new_and_signal(false);
31    let pressed_hovered_broadcaster =
32        map_ref!(pressed_signal, hovered_signal => (*pressed_signal, *hovered_signal)).broadcast();
33    let border_color_signal = {
34        pressed_hovered_broadcaster
35            .signal()
36            .map(|(pressed, hovered)| {
37                if pressed {
38                    bevy::color::palettes::basic::RED.into()
39                } else if hovered {
40                    Color::WHITE
41                } else {
42                    Color::BLACK
43                }
44            })
45            .map(BorderColor)
46    };
47    let background_color_signal = {
48        pressed_hovered_broadcaster
49            .signal()
50            .map(|(pressed, hovered)| {
51                if pressed {
52                    PRESSED_BUTTON
53                } else if hovered {
54                    HOVERED_BUTTON
55                } else {
56                    NORMAL_BUTTON
57                }
58            })
59            .map(BackgroundColor)
60    };
61    El::<Node>::new()
62        .with_node(|mut node| {
63            node.width = Val::Px(150.0);
64            node.height = Val::Px(65.);
65            node.border = UiRect::all(Val::Px(5.0));
66        })
67        .cursor(CursorIcon::System(SystemCursorIcon::Pointer))
68        .align_content(Align::center())
69        .border_color_signal(border_color_signal)
70        .background_color_signal(background_color_signal)
71        .border_radius(BorderRadius::MAX)
72        .hovered_sync(hovered)
73        .pressed_sync(pressed)
74        .child(
75            El::<Text>::new()
76                .text_font(TextFont {
77                    font_size: 33.0,
78                    ..default()
79                })
80                .text_color(TextColor(Color::srgb(0.9, 0.9, 0.9)))
81                .text_signal(
82                    pressed_hovered_broadcaster
83                        .signal()
84                        .map(|(pressed, hovered)| {
85                            if pressed {
86                                "Press"
87                            } else if hovered {
88                                "Hover"
89                            } else {
90                                "Button"
91                            }
92                        })
93                        .map(Text::new),
94                ),
95        )
96}
97
98fn camera(mut commands: Commands) {
99    commands.spawn(Camera2d);
100}
101
102fn ui_root() -> impl Element {
103    El::<Node>::new()
104        .with_node(|mut node| {
105            node.width = Val::Percent(100.);
106            node.height = Val::Percent(100.);
107        })
108        .cursor(CursorIcon::default())
109        .align_content(Align::center())
110        .child(button())
111}