mittens_engine/engine/ecs/component/
selection.rs1use crate::engine::ecs::{ComponentId, component::Component};
2
3use super::ComponentRef;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum SelectionMode {
7 Single,
8 Multiple,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct SelectionEntry {
13 pub index: Option<usize>,
14 pub component: ComponentId,
15}
16
17#[derive(Debug, Clone)]
18pub struct SelectionComponent {
19 pub mode: SelectionMode,
20 pub allow_empty_single: bool,
21 pub target_root_source: Option<ComponentRef>,
22 pub selected_index: Option<usize>,
23 pub selected_component: Option<ComponentId>,
24 pub selected_payload: Option<ComponentId>,
25 pub selected_entries: Vec<SelectionEntry>,
26 component: Option<ComponentId>,
27}
28
29impl SelectionComponent {
30 pub fn new() -> Self {
31 Self {
32 mode: SelectionMode::Single,
33 allow_empty_single: false,
34 target_root_source: None,
35 selected_index: None,
36 selected_component: None,
37 selected_payload: None,
38 selected_entries: Vec::new(),
39 component: None,
40 }
41 }
42
43 pub fn multiple() -> Self {
44 Self {
45 mode: SelectionMode::Multiple,
46 ..Self::new()
47 }
48 }
49
50 pub fn optional() -> Self {
51 Self {
52 allow_empty_single: true,
53 ..Self::new()
54 }
55 }
56
57 pub fn is_multiple(&self) -> bool {
58 matches!(self.mode, SelectionMode::Multiple)
59 }
60
61 pub fn clear(&mut self) {
62 self.selected_index = None;
63 self.selected_component = None;
64 self.selected_payload = None;
65 self.selected_entries.clear();
66 }
67
68 pub fn select_entry(&mut self, entry: SelectionEntry) {
69 self.selected_index = entry.index;
70 self.selected_component = Some(entry.component);
71 self.selected_payload = None;
72 self.selected_entries.clear();
73 self.selected_entries.push(entry);
74 }
75
76 pub fn contains(&self, component: ComponentId) -> bool {
77 self.selected_entries
78 .iter()
79 .any(|entry| entry.component == component)
80 }
81
82 pub fn toggle_entry(&mut self, entry: SelectionEntry) -> bool {
83 if !self.is_multiple() {
84 self.select_entry(entry);
85 return true;
86 }
87
88 if let Some(index) = self
89 .selected_entries
90 .iter()
91 .position(|selected| selected.component == entry.component)
92 {
93 self.selected_entries.remove(index);
94 self.sync_primary_from_entries();
95 return false;
96 }
97
98 self.selected_entries.push(entry.clone());
99 self.selected_index = entry.index;
100 self.selected_component = Some(entry.component);
101 self.selected_payload = None;
102 true
103 }
104
105 fn sync_primary_from_entries(&mut self) {
106 if let Some(entry) = self.selected_entries.last().cloned() {
107 self.selected_index = entry.index;
108 self.selected_component = Some(entry.component);
109 self.selected_payload = None;
110 } else {
111 self.selected_index = None;
112 self.selected_component = None;
113 self.selected_payload = None;
114 }
115 }
116}
117
118impl Component for SelectionComponent {
119 fn set_id(&mut self, id: ComponentId) {
120 self.component = Some(id);
121 }
122
123 fn name(&self) -> &'static str {
124 "selection"
125 }
126
127 fn as_any(&self) -> &dyn std::any::Any {
128 self
129 }
130
131 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
132 self
133 }
134
135 fn to_mms_ast(
136 &self,
137 _world: &crate::engine::ecs::World,
138 ) -> crate::scripting::ast::ComponentExpression {
139 use crate::engine::ecs::component::ce_helpers::*;
140 let mut expr = match self.mode {
141 SelectionMode::Single => {
142 if self.allow_empty_single {
143 ce_call("Selection", "optional", vec![])
144 } else {
145 ce_call("Selection", "", vec![])
146 }
147 }
148 SelectionMode::Multiple => ce_call("Selection", "multiple", vec![]),
149 };
150 if let Some(source) = &self.target_root_source {
151 let arg = match source {
152 ComponentRef::Guid(uuid) => s(&format!("@uuid:{uuid}")),
153 ComponentRef::Query(selector) => s(selector),
154 };
155 expr.constructors
156 .push(crate::scripting::ast::ConstructorCall {
157 method: crate::scripting::ast::Ident("root".to_string()),
158 args: vec![arg],
159 });
160 }
161 expr
162 }
163}