-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathextension.rs
More file actions
150 lines (129 loc) · 4.29 KB
/
Copy pathextension.rs
File metadata and controls
150 lines (129 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use bevy::ecs::{component::Component, entity::Entity, system::Command};
use bevy_immediate::{CapSet, ImmCapability, ImmEntity, ImplCap};
// This extension example tries to showcase the WORST case.
// Where code wants to read from and write to component.
//
// For very simple capability implementations see
// [bevy_immediate::ui] capability implementations
// like [bevy_immediate::ui::checked]
pub struct ExtensionExamplePlugin;
impl bevy::app::Plugin for ExtensionExamplePlugin {
fn build(&self, _app: &mut bevy::app::App) {
// No need to implement plugin in this case
}
}
/// Create your own capability
///
/// For example, we will create a capability which will allow to store toggle state
/// attached to component
pub struct CapUiToggle;
impl ImmCapability for CapUiToggle {
fn build<Cap: CapSet>(
app: &mut bevy::app::App,
cap_req: &mut bevy_immediate::ImmCapAccessRequests<Cap>,
) {
// Require necessary plugins
if !app.is_plugin_added::<ExtensionExamplePlugin>() {
app.add_plugins(ExtensionExamplePlugin);
}
// If necessary, you can add requirements for resources
// cap_req.request_resource_write::<Resource1>(app.world_mut());
// cap_req.request_resource_read::<Resource2>(app.world_mut());
// Add read, write requests for immediate mode managed entity components
cap_req.request_component_write::<ToggleState>(app.world_mut());
}
}
/// Component which will be modified by capability
#[derive(Component)]
struct ToggleState {
state: bool,
}
/// Implements access to collapse state
#[allow(unused)]
pub trait ImmCapUiCollapse {
fn get_toggle(&mut self) -> bool;
fn flip_toggle(&mut self);
fn set_toggle(self, value: bool) -> Self;
fn on_insert_toggle(self, toggle: bool) -> Self;
/// Toggle toggle with given transformation function
fn with_toggle(&mut self, f: impl FnOnce(Option<bool>) -> bool);
}
impl<Caps> ImmCapUiCollapse for ImmEntity<'_, '_, '_, Caps>
where
// Trait functions only implemented for capability sets with
// CapUiToggle capability
Caps: ImplCap<CapUiToggle>,
{
fn get_toggle(&mut self) -> bool {
if let Ok(Some(toggle)) = self.cap_get_component::<ToggleState>() {
toggle.state
} else {
let entity = self.entity();
self.commands().queue(SetOrInitToggleStateCommand {
entity,
state: false,
});
false
}
}
fn set_toggle(mut self, value: bool) -> Self {
self.with_toggle(|state| {
let _ = state;
value
});
self
}
fn flip_toggle(&mut self) {
self.with_toggle(|state| {
match state {
Some(state) => !state,
// We assume toggle is off by default
None => true,
}
});
}
fn on_insert_toggle(mut self, state: bool) -> Self {
if self.will_be_spawned() {
self.with_toggle(|stored_state| {
let _ = stored_state;
state
});
}
self
}
fn with_toggle(&mut self, f: impl FnOnce(Option<bool>) -> bool) {
if let Ok(Some(mut toggle)) = self.cap_get_component_mut::<ToggleState>() {
let new_state = f(Some(toggle.state));
// minimize change triggers
if new_state != toggle.state {
toggle.state = new_state;
}
return;
}
let new_state = f(None);
let entity = self.entity();
self.commands().queue(SetOrInitToggleStateCommand {
entity,
state: new_state,
});
}
}
struct SetOrInitToggleStateCommand {
entity: Entity,
state: bool,
}
impl Command for SetOrInitToggleStateCommand {
type Out = ();
fn apply(self, world: &mut bevy::ecs::world::World) -> Self::Out {
if let Ok(mut entity) = world.get_entity_mut(self.entity) {
if let Some(mut comp) = entity.get_mut::<ToggleState>() {
// minimize change triggers
if comp.state != self.state {
comp.state = self.state;
}
return;
}
entity.insert(ToggleState { state: self.state });
}
}
}