Skip to main content

beuvy_runtime/select/
model.rs

1use crate::button::ButtonLabel;
2use crate::text::{
3    LocalizedTextFormat, TypographyStyle, set_localized_text, set_localized_text_format,
4    set_plain_text,
5};
6use bevy::prelude::*;
7use bevy_localization::{Localization, TextKey};
8
9pub const SELECT_CHEVRON_CLOSED: &str = "⌄";
10pub const SELECT_CHEVRON_OPEN: &str = "⌃";
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct SelectOptionState {
14    pub entity: Entity,
15    pub value: String,
16    pub text: String,
17    pub localized_text: Option<TextKey>,
18    pub localized_text_format: Option<LocalizedTextFormat>,
19    pub disabled: bool,
20}
21
22#[derive(Component, Debug, Clone)]
23pub struct Select {
24    pub name: String,
25    pub value: String,
26    pub initial_value: String,
27    pub options: Vec<SelectOptionState>,
28    pub panel: Entity,
29    pub trigger: Entity,
30    pub chevron_glyph: Entity,
31    pub open: bool,
32    pub disabled: bool,
33}
34
35#[derive(Message, Debug, Clone, PartialEq, Eq)]
36pub struct SelectValueChangedMessage {
37    pub entity: Entity,
38    pub name: String,
39    pub value: String,
40}
41
42#[derive(Component, Debug, Clone)]
43pub(crate) struct SelectTrigger {
44    pub(crate) select: Entity,
45}
46
47#[derive(Component, Debug, Clone)]
48pub(crate) struct SelectOptionButton {
49    pub(crate) select: Entity,
50    pub(crate) value: String,
51}
52
53#[derive(Component, Debug, Clone)]
54pub struct SelectPanel;
55
56#[derive(Component, Debug, Clone)]
57pub(crate) struct SelectOptionIndicator;
58
59#[derive(Component, Debug, Clone)]
60pub(crate) struct SelectChevron;
61
62#[derive(Component, Debug, Clone)]
63pub(crate) struct SelectChevronGlyph;
64
65#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct AddSelectOption {
67    pub name: String,
68    pub value: String,
69    pub text: String,
70    pub localized_text: Option<TextKey>,
71    pub localized_text_format: Option<LocalizedTextFormat>,
72    pub disabled: bool,
73}
74
75#[derive(Component, Debug, Clone, PartialEq)]
76pub struct AddSelect {
77    pub name: String,
78    pub value: String,
79    pub options: Vec<AddSelectOption>,
80    pub class: Option<String>,
81    pub trigger_class: Option<String>,
82    pub label_class: Option<String>,
83    pub label_typography: TypographyStyle,
84    pub panel_class: Option<String>,
85    pub chevron_class: Option<String>,
86    pub option_class: Option<String>,
87    pub indicator_class: Option<String>,
88    pub disabled: bool,
89}
90
91impl Default for AddSelect {
92    fn default() -> Self {
93        Self {
94            name: String::new(),
95            value: String::new(),
96            options: Vec::new(),
97            class: None,
98            trigger_class: None,
99            label_class: None,
100            label_typography: TypographyStyle::default(),
101            panel_class: None,
102            chevron_class: None,
103            option_class: None,
104            indicator_class: None,
105            disabled: false,
106        }
107    }
108}
109
110pub fn default_select_node() -> Node {
111    Node::default()
112}
113
114pub fn selected_option(select: &Select) -> Option<&SelectOptionState> {
115    select
116        .options
117        .iter()
118        .find(|option| option.value == select.value)
119}
120
121pub fn trigger_label_entity(
122    trigger_labels: &Query<&ButtonLabel>,
123    select: &Select,
124) -> Option<Entity> {
125    trigger_labels
126        .get(select.trigger)
127        .ok()
128        .map(|label| label.entity)
129}
130
131pub fn sync_select_label(
132    commands: &mut Commands,
133    localization: Option<&Localization>,
134    label_entity: Entity,
135    option: Option<&SelectOptionState>,
136    fallback_value: &str,
137) {
138    let Some(option) = option else {
139        set_plain_text(commands, label_entity, fallback_value);
140        return;
141    };
142
143    if let (Some(localization), Some(format)) = (localization, option.localized_text_format.clone())
144    {
145        set_localized_text_format(commands, label_entity, localization, format);
146        return;
147    }
148    if let (Some(localization), Some(key)) = (localization, option.localized_text) {
149        set_localized_text(commands, label_entity, localization, key);
150        return;
151    }
152    set_plain_text(commands, label_entity, option.text.clone());
153}