Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_feathers/src/controls/disclosure_toggle.rs
30636 views
1
use bevy_app::{App, Plugin, PreUpdate};
2
use bevy_ecs::{
3
hierarchy::Children,
4
lifecycle::RemovedComponents,
5
query::{Added, Has, Or, With},
6
schedule::IntoScheduleConfigs,
7
system::{Query, Res},
8
};
9
use bevy_input_focus::tab_navigation::TabIndex;
10
use bevy_math::Rot2;
11
use bevy_picking::PickingSystems;
12
use bevy_scene::{bsn, Scene, SceneComponent};
13
use bevy_ui::{
14
px, widget::ImageNode, AlignItems, Checked, Display, InteractionDisabled, JustifyContent, Node,
15
UiTransform,
16
};
17
use bevy_ui_widgets::Checkbox;
18
use bevy_window::SystemCursorIcon;
19
20
use crate::{
21
constants::icons, cursor::EntityCursor, display::icon, focus::FocusIndicator, theme::UiTheme,
22
tokens,
23
};
24
25
/// A toggle button which shows a chevron that points either right or down, used to expand or
26
/// collapse a panel. Functionally, this is equivalent to a checkbox, and has a [`Checked`]
27
/// state.
28
///
29
/// This is spawnable by inheriting it as a "scene component".
30
#[derive(SceneComponent, Default, Clone)]
31
pub struct FeathersDisclosureToggle;
32
33
impl FeathersDisclosureToggle {
34
fn scene() -> impl Scene {
35
bsn!(
36
Node {
37
width: px(12),
38
height: px(12),
39
display: Display::Flex,
40
align_items: AlignItems::Center,
41
justify_content: JustifyContent::Center,
42
}
43
Checkbox
44
EntityCursor::System(SystemCursorIcon::Pointer)
45
FocusIndicator
46
TabIndex(0)
47
Children [
48
icon(icons::CHEVRON_RIGHT)
49
]
50
)
51
}
52
}
53
54
fn update_toggle_styles(
55
mut q_toggle: Query<
56
(
57
Has<InteractionDisabled>,
58
Has<Checked>,
59
&mut UiTransform,
60
&Children,
61
),
62
(
63
With<FeathersDisclosureToggle>,
64
Or<(Added<Checkbox>, Added<Checked>, Added<InteractionDisabled>)>,
65
),
66
>,
67
mut q_icon: Query<&mut ImageNode>,
68
theme: Res<UiTheme>,
69
) {
70
for (disabled, checked, mut transform, children) in q_toggle.iter_mut() {
71
let Some(child_id) = children.first() else {
72
continue;
73
};
74
let Ok(mut icon_child) = q_icon.get_mut(*child_id) else {
75
continue;
76
};
77
set_toggle_styles(
78
disabled,
79
checked,
80
transform.as_mut(),
81
&mut icon_child,
82
&theme,
83
);
84
}
85
}
86
87
fn update_toggle_styles_remove(
88
mut q_toggle: Query<
89
(
90
Has<InteractionDisabled>,
91
Has<Checked>,
92
&mut UiTransform,
93
&Children,
94
),
95
With<FeathersDisclosureToggle>,
96
>,
97
mut q_icon: Query<&mut ImageNode>,
98
mut removed_disabled: RemovedComponents<InteractionDisabled>,
99
mut removed_checked: RemovedComponents<Checked>,
100
theme: Res<UiTheme>,
101
) {
102
removed_disabled
103
.read()
104
.chain(removed_checked.read())
105
.for_each(|ent| {
106
if let Ok((disabled, checked, mut transform, children)) = q_toggle.get_mut(ent) {
107
let Some(child_id) = children.first() else {
108
return;
109
};
110
let Ok(mut icon_child) = q_icon.get_mut(*child_id) else {
111
return;
112
};
113
set_toggle_styles(
114
disabled,
115
checked,
116
transform.as_mut(),
117
&mut icon_child,
118
&theme,
119
);
120
}
121
});
122
}
123
124
fn set_toggle_styles(
125
disabled: bool,
126
checked: bool,
127
transform: &mut UiTransform,
128
image_node: &mut ImageNode,
129
theme: &Res<'_, UiTheme>,
130
) {
131
// It's effectively the same color as the caption of a "plain" variant tool button with an icon.
132
let icon_color = match disabled {
133
true => theme.color(&tokens::BUTTON_TEXT_DISABLED),
134
false => theme.color(&tokens::BUTTON_TEXT),
135
};
136
137
// Change icon color
138
if image_node.color != icon_color {
139
image_node.color = icon_color;
140
}
141
142
match checked {
143
true => {
144
transform.rotation = Rot2::turn_fraction(0.25);
145
}
146
false => {
147
transform.rotation = Rot2::turn_fraction(0.0);
148
}
149
};
150
}
151
152
/// Plugin which registers the systems for updating the toggle switch styles.
153
pub struct DisclosureTogglePlugin;
154
155
impl Plugin for DisclosureTogglePlugin {
156
fn build(&self, app: &mut App) {
157
app.add_systems(
158
PreUpdate,
159
(update_toggle_styles, update_toggle_styles_remove).in_set(PickingSystems::Last),
160
);
161
}
162
}
163
164