winio_ui_winui/widgets/
edit.rs1use std::rc::Rc;
2
3use inherit_methods_macro::inherit_methods;
4use send_wrapper::SendWrapper;
5use windows::core::{HSTRING, Interface};
6use winio_callback::Callback;
7use winio_handle::{AsContainer, AsWidget, BorrowedContainer};
8use winio_primitive::{HAlign, Point, Size};
9use winui3::Microsoft::UI::Xaml::{
10 Controls::{self as MUXC, ScrollBarVisibility, ScrollViewer, TextChangedEventHandler},
11 RoutedEventHandler, TextWrapping, Visibility,
12};
13
14use crate::{GlobalRuntime, Result, Widget, widgets::Convertible};
15
16#[derive(Debug)]
17pub struct Edit {
18 on_change: SendWrapper<Rc<Callback>>,
19 handle: Widget,
20 password: bool,
21 halign: HAlign,
22}
23
24#[inherit_methods(from = "self.handle")]
25impl Edit {
26 pub fn new(parent: impl AsContainer) -> Result<Self> {
27 let text_box = MUXC::TextBox::new()?;
28 let password_box = MUXC::PasswordBox::new()?;
29 password_box.SetVisibility(Visibility::Collapsed)?;
30
31 let on_change = SendWrapper::new(Rc::new(Callback::new()));
32 {
33 let on_change = on_change.clone();
34 text_box.TextChanged(&TextChangedEventHandler::new(move |_, _| {
35 on_change.signal::<GlobalRuntime>(());
36 Ok(())
37 }))?;
38 }
39 {
40 let on_change = on_change.clone();
41 password_box.PasswordChanged(&RoutedEventHandler::new(move |_, _| {
42 on_change.signal::<GlobalRuntime>(());
43 Ok(())
44 }))?;
45 }
46
47 Ok(Self {
48 on_change,
49 handle: Widget::new(&parent, text_box.cast()?)?,
50 password: false,
51 halign: HAlign::Left,
52 })
53 }
54
55 fn recreate(&mut self, password: bool) -> Result<()> {
56 let parent = self.handle.parent()?;
57 let mut widget = if password {
58 let password_box = MUXC::PasswordBox::new()?;
59 let text_box = self.handle.as_widget().as_winui().cast::<MUXC::TextBox>()?;
60 password_box.SetPassword(&text_box.Text()?)?;
61 Widget::new(BorrowedContainer::winui(&parent), password_box.cast()?)?
62 } else {
63 let text_box = MUXC::TextBox::new()?;
64 let password_box = self
65 .handle
66 .as_widget()
67 .as_winui()
68 .cast::<MUXC::PasswordBox>()?;
69 text_box.SetText(&password_box.Password()?)?;
70 text_box.SetTextAlignment(self.halign.to_native())?;
71 Widget::new(BorrowedContainer::winui(&parent), text_box.cast()?)?
72 };
73 widget.set_visible(self.handle.is_visible()?)?;
74 widget.set_enabled(self.handle.is_enabled()?)?;
75 widget.set_loc(self.handle.loc()?)?;
76 widget.set_size(self.handle.size()?)?;
77 widget.set_tooltip(self.handle.tooltip()?)?;
78 self.handle = widget;
79 Ok(())
80 }
81
82 pub fn is_visible(&self) -> Result<bool>;
83
84 pub fn set_visible(&mut self, v: bool) -> Result<()>;
85
86 pub fn is_enabled(&self) -> Result<bool>;
87
88 pub fn set_enabled(&mut self, v: bool) -> Result<()>;
89
90 pub fn preferred_size(&self) -> Result<Size>;
91
92 pub fn loc(&self) -> Result<Point>;
93
94 pub fn set_loc(&mut self, p: Point) -> Result<()>;
95
96 pub fn size(&self) -> Result<Size>;
97
98 pub fn set_size(&mut self, v: Size) -> Result<()>;
99
100 pub fn tooltip(&self) -> Result<String>;
101
102 pub fn set_tooltip(&mut self, s: impl AsRef<str>) -> Result<()>;
103
104 pub fn text(&self) -> Result<String> {
105 let text = if self.password {
106 self.handle
107 .as_widget()
108 .as_winui()
109 .cast::<MUXC::PasswordBox>()?
110 .Password()?
111 .to_string_lossy()
112 } else {
113 self.handle
114 .as_widget()
115 .as_winui()
116 .cast::<MUXC::TextBox>()?
117 .Text()?
118 .to_string_lossy()
119 };
120 Ok(text)
121 }
122
123 pub fn set_text(&mut self, s: impl AsRef<str>) -> Result<()> {
124 let s = HSTRING::from(s.as_ref());
125 if self.password {
126 let password_box = self
127 .handle
128 .as_widget()
129 .as_winui()
130 .cast::<MUXC::PasswordBox>()?;
131 password_box.SetPassword(&s)?;
132 } else {
133 let text_box = self.handle.as_widget().as_winui().cast::<MUXC::TextBox>()?;
134 text_box.SetText(&s)?;
135 }
136 Ok(())
137 }
138
139 pub fn is_password(&self) -> Result<bool> {
140 Ok(self.password)
141 }
142
143 pub fn set_password(&mut self, v: bool) -> Result<()> {
144 if self.password != v {
145 self.recreate(v)?;
146 self.password = v;
147 }
148 Ok(())
149 }
150
151 pub fn halign(&self) -> Result<HAlign> {
152 Ok(self.halign)
153 }
154
155 pub fn set_halign(&mut self, align: HAlign) -> Result<()> {
156 self.halign = align;
157 if let Ok(text_box) = self.handle.as_widget().as_winui().cast::<MUXC::TextBox>() {
158 text_box.SetTextAlignment(align.to_native())?;
159 }
160 Ok(())
161 }
162
163 pub fn is_readonly(&self) -> Result<bool> {
164 if self.password {
165 Ok(false)
166 } else {
167 Ok(self
168 .handle
169 .as_widget()
170 .as_winui()
171 .cast::<MUXC::TextBox>()?
172 .IsReadOnly()?)
173 }
174 }
175
176 pub fn set_readonly(&mut self, v: bool) -> Result<()> {
177 if !self.password {
178 let text_box = self.handle.as_widget().as_winui().cast::<MUXC::TextBox>()?;
179 text_box.SetIsReadOnly(v)?;
180 }
181 Ok(())
182 }
183
184 pub async fn wait_change(&self) {
185 self.on_change.wait().await
186 }
187}
188
189winio_handle::impl_as_widget!(Edit, handle);
190
191#[derive(Debug)]
192pub struct TextBox {
193 on_change: SendWrapper<Rc<Callback>>,
194 handle: Widget,
195 text_box: MUXC::TextBox,
196}
197
198#[inherit_methods(from = "self.handle")]
199impl TextBox {
200 pub fn new(parent: impl AsContainer) -> Result<Self> {
201 let text_box = MUXC::TextBox::new()?;
202 text_box.SetAcceptsReturn(true)?;
203 text_box.SetTextWrapping(TextWrapping::Wrap)?;
204 ScrollViewer::SetVerticalScrollBarVisibility2(&text_box, ScrollBarVisibility::Auto)?;
205 let on_change = SendWrapper::new(Rc::new(Callback::new()));
206 {
207 let on_change = on_change.clone();
208 text_box.TextChanged(&TextChangedEventHandler::new(move |_, _| {
209 on_change.signal::<GlobalRuntime>(());
210 Ok(())
211 }))?;
212 }
213 Ok(Self {
214 on_change,
215 handle: Widget::new(parent, text_box.cast()?)?,
216 text_box,
217 })
218 }
219
220 pub fn is_visible(&self) -> Result<bool>;
221
222 pub fn set_visible(&mut self, v: bool) -> Result<()>;
223
224 pub fn is_enabled(&self) -> Result<bool>;
225
226 pub fn set_enabled(&mut self, v: bool) -> Result<()>;
227
228 pub fn preferred_size(&self) -> Result<Size>;
229
230 pub fn min_size(&self) -> Result<Size>;
231
232 pub fn loc(&self) -> Result<Point>;
233
234 pub fn set_loc(&mut self, p: Point) -> Result<()>;
235
236 pub fn size(&self) -> Result<Size>;
237
238 pub fn set_size(&mut self, v: Size) -> Result<()>;
239
240 pub fn tooltip(&self) -> Result<String>;
241
242 pub fn set_tooltip(&mut self, s: impl AsRef<str>) -> Result<()>;
243
244 pub fn text(&self) -> Result<String> {
245 Ok(self.text_box.Text()?.to_string_lossy().replace("\r", "\n"))
246 }
247
248 pub fn set_text(&mut self, s: impl AsRef<str>) -> Result<()> {
249 self.text_box.SetText(&HSTRING::from(s.as_ref()))?;
250 Ok(())
251 }
252
253 pub fn halign(&self) -> Result<HAlign> {
254 Ok(HAlign::from_native(self.text_box.TextAlignment()?))
255 }
256
257 pub fn set_halign(&mut self, align: HAlign) -> Result<()> {
258 self.text_box.SetTextAlignment(align.to_native())?;
259 Ok(())
260 }
261
262 pub fn is_readonly(&self) -> Result<bool> {
263 self.text_box.IsReadOnly()
264 }
265
266 pub fn set_readonly(&mut self, v: bool) -> Result<()> {
267 self.text_box.SetIsReadOnly(v)?;
268 Ok(())
269 }
270
271 pub async fn wait_change(&self) {
272 self.on_change.wait().await
273 }
274}
275
276winio_handle::impl_as_widget!(TextBox, handle);