winio/widgets/
combo_box.rs1use inherit_methods_macro::inherit_methods;
2use winio_elm::{Component, ComponentSender, ObservableVecEvent};
3use winio_handle::BorrowedContainer;
4use winio_primitive::{Enable, Failable, Layoutable, Point, Size, TextWidget, ToolTip, Visible};
5
6use crate::{
7 sys,
8 sys::{Error, Result},
9};
10
11#[derive(Debug)]
13pub struct ComboBox {
14 widget: sys::ComboBox,
15}
16
17impl Failable for ComboBox {
18 type Error = Error;
19}
20
21#[inherit_methods(from = "self.widget")]
22impl ToolTip for ComboBox {
23 fn tooltip(&self) -> Result<String>;
24
25 fn set_tooltip(&mut self, s: impl AsRef<str>) -> Result<()>;
26}
27
28#[inherit_methods(from = "self.widget")]
29impl TextWidget for ComboBox {
30 fn text(&self) -> Result<String>;
31
32 fn set_text(&mut self, s: impl AsRef<str>) -> Result<()>;
33}
34
35#[inherit_methods(from = "self.widget")]
36impl ComboBox {
37 pub fn selection(&self) -> Result<Option<usize>>;
39
40 pub fn set_selection(&mut self, i: usize) -> Result<()>;
42
43 pub fn is_editable(&self) -> Result<bool>;
45
46 pub fn set_editable(&mut self, v: bool) -> Result<()>;
48
49 pub fn len(&self) -> Result<usize>;
51
52 pub fn is_empty(&self) -> Result<bool>;
54
55 pub fn clear(&mut self) -> Result<()>;
57
58 pub fn get(&self, i: usize) -> Result<String>;
60
61 pub fn set(&mut self, i: usize, s: impl AsRef<str>) -> Result<()>;
63
64 pub fn insert(&mut self, i: usize, s: impl AsRef<str>) -> Result<()>;
66
67 pub fn remove(&mut self, i: usize) -> Result<()>;
69
70 pub fn push(&mut self, s: impl AsRef<str>) -> Result<()> {
72 let len = self.len()?;
73 self.insert(len, s)
74 }
75
76 pub fn set_items<U: Into<String>>(&mut self, items: impl IntoIterator<Item = U>) -> Result<()> {
78 self.clear()?;
79 for it in items {
80 self.push(it.into())?;
81 }
82 Ok(())
83 }
84}
85
86#[inherit_methods(from = "self.widget")]
87impl Visible for ComboBox {
88 fn is_visible(&self) -> Result<bool>;
89
90 fn set_visible(&mut self, v: bool) -> Result<()>;
91}
92
93#[inherit_methods(from = "self.widget")]
94impl Enable for ComboBox {
95 fn is_enabled(&self) -> Result<bool>;
96
97 fn set_enabled(&mut self, v: bool) -> Result<()>;
98}
99
100#[inherit_methods(from = "self.widget")]
101impl Layoutable for ComboBox {
102 fn loc(&self) -> Result<Point>;
103
104 fn set_loc(&mut self, p: Point) -> Result<()> {
105 if !super::approx_eq_point(self.loc()?, p) {
106 self.widget.set_loc(p)?;
107 }
108 Ok(())
109 }
110
111 fn size(&self) -> Result<Size>;
112
113 fn set_size(&mut self, v: Size) -> Result<()> {
114 if !super::approx_eq_size(self.size()?, v) {
115 self.widget.set_size(v)?;
116 }
117 Ok(())
118 }
119
120 fn preferred_size(&self) -> Result<Size>;
121}
122
123#[derive(Debug)]
125#[non_exhaustive]
126pub enum ComboBoxEvent {
127 Select,
129 Change,
131}
132
133#[derive(Debug)]
135#[non_exhaustive]
136pub enum ComboBoxMessage {
137 Insert {
139 at: usize,
141 value: String,
143 },
144 Remove {
146 at: usize,
148 },
149 Replace {
151 at: usize,
153 value: String,
155 },
156 Clear,
158}
159
160impl ComboBoxMessage {
161 pub fn from_observable_vec_event_by<T>(
164 e: ObservableVecEvent<T>,
165 mut f: impl FnMut(T) -> String,
166 ) -> Self {
167 match e {
168 ObservableVecEvent::Insert { at, value } => Self::Insert {
169 at,
170 value: f(value),
171 },
172 ObservableVecEvent::Remove { at, .. } => Self::Remove { at },
173 ObservableVecEvent::Replace { at, new, .. } => Self::Replace { at, value: f(new) },
174 ObservableVecEvent::Clear => Self::Clear,
175 }
176 }
177
178 pub fn from_observable_vec_event<T: ToString>(e: ObservableVecEvent<T>) -> Self {
180 Self::from_observable_vec_event_by(e, |v| v.to_string())
181 }
182}
183
184impl Component for ComboBox {
185 type Error = Error;
186 type Event = ComboBoxEvent;
187 type Init<'a> = BorrowedContainer<'a>;
188 type Message = ComboBoxMessage;
189
190 async fn init(init: Self::Init<'_>, _sender: &ComponentSender<Self>) -> Result<Self> {
191 let widget = sys::ComboBox::new(init)?;
192 Ok(Self { widget })
193 }
194
195 async fn start(&mut self, sender: &ComponentSender<Self>) -> ! {
196 let fut_select = async {
197 loop {
198 self.widget.wait_select().await;
199 sender.output(ComboBoxEvent::Select);
200 }
201 };
202 let fut_change = async {
203 loop {
204 self.widget.wait_change().await;
205 sender.output(ComboBoxEvent::Change);
206 }
207 };
208 futures_util::future::join(fut_select, fut_change).await.0
209 }
210
211 async fn update(
212 &mut self,
213 message: Self::Message,
214 _sender: &ComponentSender<Self>,
215 ) -> Result<bool> {
216 match message {
217 ComboBoxMessage::Insert { at, value } => self.insert(at, value)?,
218 ComboBoxMessage::Remove { at } => self.remove(at)?,
219 ComboBoxMessage::Replace { at, value } => self.set(at, value)?,
220 ComboBoxMessage::Clear => self.clear()?,
221 }
222 Ok(true)
223 }
224}
225
226winio_handle::impl_as_widget!(ComboBox, widget);