Skip to main content

mittens_engine/engine/ecs/component/
selection.rs

1use 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}