1use alloc::{string::String, vec::Vec};
11
12use azul_core::{
13 callbacks::{CoreCallback, CoreCallbackData, Update},
14 dom::Dom,
15 refany::RefAny,
16 task::OptionTimerId,
17 window::VirtualKeyCode,
18};
19#[allow(clippy::wildcard_imports)] use azul_css::{
21 dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec},
22 props::{
23 basic::*,
24 layout::*,
25 property::{CssProperty, *},
26 style::*,
27 },
28 *,
29};
30use azul_css::css::BoxOrStatic;
31
32use crate::callbacks::{Callback, CallbackInfo};
33
34const BACKGROUND_COLOR: ColorU = ColorU {
35 r: 255,
36 g: 255,
37 b: 255,
38 a: 255,
39}; const BLACK: ColorU = ColorU {
41 r: 0,
42 g: 0,
43 b: 0,
44 a: 255,
45};
46const TEXT_COLOR: StyleTextColor = StyleTextColor { inner: BLACK }; const COLOR_9B9B9B: ColorU = ColorU {
48 r: 155,
49 g: 155,
50 b: 155,
51 a: 255,
52}; const COLOR_4286F4: ColorU = ColorU {
54 r: 66,
55 g: 134,
56 b: 244,
57 a: 255,
58}; const COLOR_4C4C4C: ColorU = ColorU {
60 r: 76,
61 g: 76,
62 b: 76,
63 a: 255,
64}; const CURSOR_COLOR_BLACK: &[StyleBackgroundContent] = &[StyleBackgroundContent::Color(BLACK)];
67const CURSOR_COLOR: StyleBackgroundContentVec =
68 StyleBackgroundContentVec::from_const_slice(CURSOR_COLOR_BLACK);
69
70const BACKGROUND_THEME_LIGHT: &[StyleBackgroundContent] =
71 &[StyleBackgroundContent::Color(BACKGROUND_COLOR)];
72const BACKGROUND_COLOR_LIGHT: StyleBackgroundContentVec =
73 StyleBackgroundContentVec::from_const_slice(BACKGROUND_THEME_LIGHT);
74
75const SANS_SERIF_STR: &str = "system:ui";
76const SANS_SERIF: AzString = AzString::from_const_str(SANS_SERIF_STR);
77const SANS_SERIF_FAMILIES: &[StyleFontFamily] = &[StyleFontFamily::System(SANS_SERIF)];
78const SANS_SERIF_FAMILY: StyleFontFamilyVec =
79 StyleFontFamilyVec::from_const_slice(SANS_SERIF_FAMILIES);
80
81const TEXT_CURSOR_TRANSFORM: &[StyleTransform] =
84 &[StyleTransform::Translate(StyleTransformTranslate2D {
85 x: PixelValue::const_px(0),
86 y: PixelValue::const_px(2),
87 })];
88
89static TEXT_CURSOR_PROPS: &[CssPropertyWithConditions] = &[
90 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Absolute)),
91 CssPropertyWithConditions::simple(CssProperty::const_width(LayoutWidth::const_px(1))),
92 CssPropertyWithConditions::simple(CssProperty::const_height(LayoutHeight::const_px(11))),
93 CssPropertyWithConditions::simple(CssProperty::const_background_content(CURSOR_COLOR)),
94 CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(0))),
95 CssPropertyWithConditions::simple(CssProperty::const_transform(
96 StyleTransformVec::from_const_slice(TEXT_CURSOR_TRANSFORM),
97 )),
98];
99
100#[cfg(target_os = "windows")]
103static TEXT_INPUT_CONTAINER_PROPS: &[CssPropertyWithConditions] = &[
104 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
105 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Text)),
106 CssPropertyWithConditions::simple(CssProperty::const_box_sizing(LayoutBoxSizing::BorderBox)),
107 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(1))),
108 CssPropertyWithConditions::simple(CssProperty::const_background_content(
109 BACKGROUND_COLOR_LIGHT,
110 )),
111 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
112 inner: COLOR_4C4C4C,
113 })),
114 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
115 LayoutPaddingLeft::const_px(2),
116 )),
117 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
118 LayoutPaddingRight::const_px(2),
119 )),
120 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
121 1,
122 ))),
123 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
124 LayoutPaddingBottom::const_px(1),
125 )),
126 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
128 LayoutBorderTopWidth::const_px(1),
129 )),
130 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
131 LayoutBorderBottomWidth::const_px(1),
132 )),
133 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
134 LayoutBorderLeftWidth::const_px(1),
135 )),
136 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
137 LayoutBorderRightWidth::const_px(1),
138 )),
139 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
140 inner: BorderStyle::Inset,
141 })),
142 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
143 StyleBorderBottomStyle {
144 inner: BorderStyle::Inset,
145 },
146 )),
147 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
148 inner: BorderStyle::Inset,
149 })),
150 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
151 StyleBorderRightStyle {
152 inner: BorderStyle::Inset,
153 },
154 )),
155 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
156 inner: COLOR_9B9B9B,
157 })),
158 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
159 StyleBorderBottomColor {
160 inner: COLOR_9B9B9B,
161 },
162 )),
163 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
164 inner: COLOR_9B9B9B,
165 })),
166 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
167 StyleBorderRightColor {
168 inner: COLOR_9B9B9B,
169 },
170 )),
171 CssPropertyWithConditions::simple(CssProperty::const_overflow_x(LayoutOverflow::Hidden)),
172 CssPropertyWithConditions::simple(CssProperty::const_overflow_y(LayoutOverflow::Hidden)),
173 CssPropertyWithConditions::simple(CssProperty::const_justify_content(
174 LayoutJustifyContent::Center,
175 )),
176 CssPropertyWithConditions::on_hover(CssProperty::const_border_top_color(StyleBorderTopColor {
178 inner: COLOR_4C4C4C,
179 })),
180 CssPropertyWithConditions::on_hover(CssProperty::const_border_bottom_color(
181 StyleBorderBottomColor {
182 inner: COLOR_4C4C4C,
183 },
184 )),
185 CssPropertyWithConditions::on_hover(CssProperty::const_border_left_color(
186 StyleBorderLeftColor {
187 inner: COLOR_4C4C4C,
188 },
189 )),
190 CssPropertyWithConditions::on_hover(CssProperty::const_border_right_color(
191 StyleBorderRightColor {
192 inner: COLOR_4C4C4C,
193 },
194 )),
195 CssPropertyWithConditions::on_focus(CssProperty::const_border_top_color(StyleBorderTopColor {
197 inner: COLOR_4286F4,
198 })),
199 CssPropertyWithConditions::on_focus(CssProperty::const_border_bottom_color(
200 StyleBorderBottomColor {
201 inner: COLOR_4286F4,
202 },
203 )),
204 CssPropertyWithConditions::on_focus(CssProperty::const_border_left_color(
205 StyleBorderLeftColor {
206 inner: COLOR_4286F4,
207 },
208 )),
209 CssPropertyWithConditions::on_focus(CssProperty::const_border_right_color(
210 StyleBorderRightColor {
211 inner: COLOR_4286F4,
212 },
213 )),
214];
215
216#[cfg(target_os = "linux")]
217static TEXT_INPUT_CONTAINER_PROPS: &[CssPropertyWithConditions] = &[
218 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
219 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Text)),
220 CssPropertyWithConditions::simple(CssProperty::const_box_sizing(LayoutBoxSizing::BorderBox)),
221 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
222 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(1))),
223 CssPropertyWithConditions::simple(CssProperty::const_background_content(
224 BACKGROUND_COLOR_LIGHT,
225 )),
226 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
227 inner: COLOR_4C4C4C,
228 })),
229 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
230 LayoutPaddingLeft::const_px(2),
231 )),
232 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
233 LayoutPaddingRight::const_px(2),
234 )),
235 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
236 1,
237 ))),
238 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
239 LayoutPaddingBottom::const_px(1),
240 )),
241 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
243 LayoutBorderTopWidth::const_px(1),
244 )),
245 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
246 LayoutBorderBottomWidth::const_px(1),
247 )),
248 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
249 LayoutBorderLeftWidth::const_px(1),
250 )),
251 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
252 LayoutBorderRightWidth::const_px(1),
253 )),
254 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
255 inner: BorderStyle::Inset,
256 })),
257 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
258 StyleBorderBottomStyle {
259 inner: BorderStyle::Inset,
260 },
261 )),
262 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
263 inner: BorderStyle::Inset,
264 })),
265 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
266 StyleBorderRightStyle {
267 inner: BorderStyle::Inset,
268 },
269 )),
270 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
271 inner: COLOR_9B9B9B,
272 })),
273 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
274 StyleBorderBottomColor {
275 inner: COLOR_9B9B9B,
276 },
277 )),
278 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
279 inner: COLOR_9B9B9B,
280 })),
281 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
282 StyleBorderRightColor {
283 inner: COLOR_9B9B9B,
284 },
285 )),
286 CssPropertyWithConditions::simple(CssProperty::const_overflow_x(LayoutOverflow::Hidden)),
287 CssPropertyWithConditions::simple(CssProperty::const_overflow_y(LayoutOverflow::Hidden)),
288 CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Left)),
289 CssPropertyWithConditions::simple(CssProperty::const_justify_content(
290 LayoutJustifyContent::Center,
291 )),
292 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
293 CssPropertyWithConditions::on_hover(CssProperty::const_border_top_color(StyleBorderTopColor {
295 inner: COLOR_4286F4,
296 })),
297 CssPropertyWithConditions::on_hover(CssProperty::const_border_bottom_color(
298 StyleBorderBottomColor {
299 inner: COLOR_4286F4,
300 },
301 )),
302 CssPropertyWithConditions::on_hover(CssProperty::const_border_left_color(
303 StyleBorderLeftColor {
304 inner: COLOR_4286F4,
305 },
306 )),
307 CssPropertyWithConditions::on_hover(CssProperty::const_border_right_color(
308 StyleBorderRightColor {
309 inner: COLOR_4286F4,
310 },
311 )),
312 CssPropertyWithConditions::on_focus(CssProperty::const_border_top_color(StyleBorderTopColor {
314 inner: COLOR_4286F4,
315 })),
316 CssPropertyWithConditions::on_focus(CssProperty::const_border_bottom_color(
317 StyleBorderBottomColor {
318 inner: COLOR_4286F4,
319 },
320 )),
321 CssPropertyWithConditions::on_focus(CssProperty::const_border_left_color(
322 StyleBorderLeftColor {
323 inner: COLOR_4286F4,
324 },
325 )),
326 CssPropertyWithConditions::on_focus(CssProperty::const_border_right_color(
327 StyleBorderRightColor {
328 inner: COLOR_4286F4,
329 },
330 )),
331];
332
333#[cfg(not(any(target_os = "windows", target_os = "linux")))]
336static TEXT_INPUT_CONTAINER_PROPS: &[CssPropertyWithConditions] = &[
337 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
338 CssPropertyWithConditions::simple(CssProperty::const_cursor(StyleCursor::Text)),
339 CssPropertyWithConditions::simple(CssProperty::const_box_sizing(LayoutBoxSizing::BorderBox)),
340 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(1))),
341 CssPropertyWithConditions::simple(CssProperty::const_background_content(
342 BACKGROUND_COLOR_LIGHT,
343 )),
344 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
345 inner: COLOR_4C4C4C,
346 })),
347 CssPropertyWithConditions::simple(CssProperty::const_padding_left(
348 LayoutPaddingLeft::const_px(2),
349 )),
350 CssPropertyWithConditions::simple(CssProperty::const_padding_right(
351 LayoutPaddingRight::const_px(2),
352 )),
353 CssPropertyWithConditions::simple(CssProperty::const_padding_top(LayoutPaddingTop::const_px(
354 1,
355 ))),
356 CssPropertyWithConditions::simple(CssProperty::const_padding_bottom(
357 LayoutPaddingBottom::const_px(1),
358 )),
359 CssPropertyWithConditions::simple(CssProperty::const_border_top_width(
361 LayoutBorderTopWidth::const_px(1),
362 )),
363 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_width(
364 LayoutBorderBottomWidth::const_px(1),
365 )),
366 CssPropertyWithConditions::simple(CssProperty::const_border_left_width(
367 LayoutBorderLeftWidth::const_px(1),
368 )),
369 CssPropertyWithConditions::simple(CssProperty::const_border_right_width(
370 LayoutBorderRightWidth::const_px(1),
371 )),
372 CssPropertyWithConditions::simple(CssProperty::const_border_top_style(StyleBorderTopStyle {
373 inner: BorderStyle::Inset,
374 })),
375 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_style(
376 StyleBorderBottomStyle {
377 inner: BorderStyle::Inset,
378 },
379 )),
380 CssPropertyWithConditions::simple(CssProperty::const_border_left_style(StyleBorderLeftStyle {
381 inner: BorderStyle::Inset,
382 })),
383 CssPropertyWithConditions::simple(CssProperty::const_border_right_style(
384 StyleBorderRightStyle {
385 inner: BorderStyle::Inset,
386 },
387 )),
388 CssPropertyWithConditions::simple(CssProperty::const_border_top_color(StyleBorderTopColor {
389 inner: COLOR_9B9B9B,
390 })),
391 CssPropertyWithConditions::simple(CssProperty::const_border_bottom_color(
392 StyleBorderBottomColor {
393 inner: COLOR_9B9B9B,
394 },
395 )),
396 CssPropertyWithConditions::simple(CssProperty::const_border_left_color(StyleBorderLeftColor {
397 inner: COLOR_9B9B9B,
398 })),
399 CssPropertyWithConditions::simple(CssProperty::const_border_right_color(
400 StyleBorderRightColor {
401 inner: COLOR_9B9B9B,
402 },
403 )),
404 CssPropertyWithConditions::simple(CssProperty::const_overflow_x(LayoutOverflow::Hidden)),
405 CssPropertyWithConditions::simple(CssProperty::const_overflow_y(LayoutOverflow::Hidden)),
406 CssPropertyWithConditions::simple(CssProperty::const_text_align(StyleTextAlign::Left)),
407 CssPropertyWithConditions::simple(CssProperty::const_justify_content(
408 LayoutJustifyContent::Center,
409 )),
410 CssPropertyWithConditions::on_hover(CssProperty::const_border_top_color(StyleBorderTopColor {
412 inner: COLOR_4286F4,
413 })),
414 CssPropertyWithConditions::on_hover(CssProperty::const_border_bottom_color(
415 StyleBorderBottomColor {
416 inner: COLOR_4286F4,
417 },
418 )),
419 CssPropertyWithConditions::on_hover(CssProperty::const_border_left_color(
420 StyleBorderLeftColor {
421 inner: COLOR_4286F4,
422 },
423 )),
424 CssPropertyWithConditions::on_hover(CssProperty::const_border_right_color(
425 StyleBorderRightColor {
426 inner: COLOR_4286F4,
427 },
428 )),
429 CssPropertyWithConditions::on_focus(CssProperty::const_border_top_color(StyleBorderTopColor {
431 inner: COLOR_4286F4,
432 })),
433 CssPropertyWithConditions::on_focus(CssProperty::const_border_bottom_color(
434 StyleBorderBottomColor {
435 inner: COLOR_4286F4,
436 },
437 )),
438 CssPropertyWithConditions::on_focus(CssProperty::const_border_left_color(
439 StyleBorderLeftColor {
440 inner: COLOR_4286F4,
441 },
442 )),
443 CssPropertyWithConditions::on_focus(CssProperty::const_border_right_color(
444 StyleBorderRightColor {
445 inner: COLOR_4286F4,
446 },
447 )),
448];
449
450#[cfg(target_os = "windows")]
453static TEXT_INPUT_LABEL_PROPS: &[CssPropertyWithConditions] = &[
454 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
455 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
456 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
457 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
458 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
459 inner: COLOR_4C4C4C,
460 })),
461 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
462];
463
464#[cfg(target_os = "linux")]
465static TEXT_INPUT_LABEL_PROPS: &[CssPropertyWithConditions] = &[
466 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
467 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
468 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
469 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
470 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
471 inner: COLOR_4C4C4C,
472 })),
473 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
474];
475
476#[cfg(not(any(target_os = "windows", target_os = "linux")))]
477static TEXT_INPUT_LABEL_PROPS: &[CssPropertyWithConditions] = &[
478 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::InlineBlock)),
479 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
480 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Relative)),
481 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
482 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
483 inner: COLOR_4C4C4C,
484 })),
485 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
486];
487
488#[cfg(target_os = "windows")]
491static TEXT_INPUT_PLACEHOLDER_PROPS: &[CssPropertyWithConditions] = &[
492 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::Block)),
493 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
494 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Absolute)),
495 CssPropertyWithConditions::simple(CssProperty::const_top(LayoutTop::const_px(2))),
496 CssPropertyWithConditions::simple(CssProperty::const_left(LayoutLeft::const_px(2))),
497 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
498 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
499 inner: COLOR_4C4C4C,
500 })),
501 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
502 CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(100))),
503];
504
505#[cfg(target_os = "linux")]
506static TEXT_INPUT_PLACEHOLDER_PROPS: &[CssPropertyWithConditions] = &[
507 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::Block)),
508 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
509 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Absolute)),
510 CssPropertyWithConditions::simple(CssProperty::const_top(LayoutTop::const_px(2))),
511 CssPropertyWithConditions::simple(CssProperty::const_left(LayoutLeft::const_px(2))),
512 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
513 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
514 inner: COLOR_4C4C4C,
515 })),
516 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
517 CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(100))),
518];
519
520#[cfg(not(any(target_os = "windows", target_os = "linux")))]
521static TEXT_INPUT_PLACEHOLDER_PROPS: &[CssPropertyWithConditions] = &[
522 CssPropertyWithConditions::simple(CssProperty::const_display(LayoutDisplay::Block)),
523 CssPropertyWithConditions::simple(CssProperty::const_flex_grow(LayoutFlexGrow::const_new(0))),
524 CssPropertyWithConditions::simple(CssProperty::const_position(LayoutPosition::Absolute)),
525 CssPropertyWithConditions::simple(CssProperty::const_top(LayoutTop::const_px(2))),
526 CssPropertyWithConditions::simple(CssProperty::const_left(LayoutLeft::const_px(2))),
527 CssPropertyWithConditions::simple(CssProperty::const_font_size(StyleFontSize::const_px(11))),
528 CssPropertyWithConditions::simple(CssProperty::const_text_color(StyleTextColor {
529 inner: COLOR_4C4C4C,
530 })),
531 CssPropertyWithConditions::simple(CssProperty::const_font_family(SANS_SERIF_FAMILY)),
532 CssPropertyWithConditions::simple(CssProperty::const_opacity(StyleOpacity::const_new(100))),
533];
534
535#[derive(Debug, Clone, PartialEq, Eq)]
541#[repr(C)]
542pub struct TextInput {
543 pub text_input_state: TextInputStateWrapper,
544 pub placeholder_style: CssPropertyWithConditionsVec,
545 pub container_style: CssPropertyWithConditionsVec,
546 pub label_style: CssPropertyWithConditionsVec,
547}
548
549#[derive(Debug, Clone, PartialEq, Eq)]
551#[repr(C)]
552pub struct TextInputState {
553 pub text: U32Vec, pub placeholder: OptionString,
555 pub max_len: usize,
556 pub selection: OptionTextInputSelection,
557 pub cursor_pos: usize,
558}
559
560#[derive(Debug, Clone, PartialEq, Eq)]
562#[repr(C)]
563pub struct TextInputStateWrapper {
564 pub inner: TextInputState,
565 pub on_text_input: OptionTextInputOnTextInput,
566 pub on_virtual_key_down: OptionTextInputOnVirtualKeyDown,
567 pub on_focus_lost: OptionTextInputOnFocusLost,
568 pub update_text_input_before_calling_focus_lost_fn: bool,
569 pub update_text_input_before_calling_vk_down_fn: bool,
570 pub cursor_animation: OptionTimerId,
571}
572
573#[derive(Debug, Copy, Clone, PartialEq, Eq)]
576#[repr(C)]
577pub struct OnTextInputReturn {
578 pub update: Update,
579 pub valid: TextInputValid,
580}
581
582#[derive(Debug, Copy, Clone, PartialEq, Eq)]
584#[repr(C)]
585pub enum TextInputValid {
586 Yes,
587 No,
588}
589
590pub type TextInputOnTextInputCallbackType =
593 extern "C" fn(RefAny, CallbackInfo, TextInputState) -> OnTextInputReturn;
594impl_widget_callback!(
595 TextInputOnTextInput,
596 OptionTextInputOnTextInput,
597 TextInputOnTextInputCallback,
598 TextInputOnTextInputCallbackType
599);
600
601azul_core::impl_managed_callback! {
602 wrapper: TextInputOnTextInputCallback,
603 info_ty: CallbackInfo,
604 return_ty: OnTextInputReturn,
605 default_ret: OnTextInputReturn { update: Update::DoNothing, valid: TextInputValid::Yes },
606 invoker_static: TEXT_INPUT_ON_TEXT_INPUT_INVOKER,
607 invoker_ty: AzTextInputOnTextInputCallbackInvoker,
608 thunk_fn: az_text_input_on_text_input_callback_thunk,
609 setter_fn: AzApp_setTextInputOnTextInputCallbackInvoker,
610 from_handle_fn: AzTextInputOnTextInputCallback_createFromHostHandle,
611 extra_args: [ state: TextInputState ],
612}
613
614pub type TextInputOnVirtualKeyDownCallbackType =
615 extern "C" fn(RefAny, CallbackInfo, TextInputState) -> OnTextInputReturn;
616impl_widget_callback!(
617 TextInputOnVirtualKeyDown,
618 OptionTextInputOnVirtualKeyDown,
619 TextInputOnVirtualKeyDownCallback,
620 TextInputOnVirtualKeyDownCallbackType
621);
622
623azul_core::impl_managed_callback! {
624 wrapper: TextInputOnVirtualKeyDownCallback,
625 info_ty: CallbackInfo,
626 return_ty: OnTextInputReturn,
627 default_ret: OnTextInputReturn { update: Update::DoNothing, valid: TextInputValid::Yes },
628 invoker_static: TEXT_INPUT_ON_VIRTUAL_KEY_DOWN_INVOKER,
629 invoker_ty: AzTextInputOnVirtualKeyDownCallbackInvoker,
630 thunk_fn: az_text_input_on_virtual_key_down_callback_thunk,
631 setter_fn: AzApp_setTextInputOnVirtualKeyDownCallbackInvoker,
632 from_handle_fn: AzTextInputOnVirtualKeyDownCallback_createFromHostHandle,
633 extra_args: [ state: TextInputState ],
634}
635
636pub type TextInputOnFocusLostCallbackType =
637 extern "C" fn(RefAny, CallbackInfo, TextInputState) -> Update;
638impl_widget_callback!(
639 TextInputOnFocusLost,
640 OptionTextInputOnFocusLost,
641 TextInputOnFocusLostCallback,
642 TextInputOnFocusLostCallbackType
643);
644
645azul_core::impl_managed_callback! {
646 wrapper: TextInputOnFocusLostCallback,
647 info_ty: CallbackInfo,
648 return_ty: Update,
649 default_ret: Update::DoNothing,
650 invoker_static: TEXT_INPUT_ON_FOCUS_LOST_INVOKER,
651 invoker_ty: AzTextInputOnFocusLostCallbackInvoker,
652 thunk_fn: az_text_input_on_focus_lost_callback_thunk,
653 setter_fn: AzApp_setTextInputOnFocusLostCallbackInvoker,
654 from_handle_fn: AzTextInputOnFocusLostCallback_createFromHostHandle,
655 extra_args: [ state: TextInputState ],
656}
657#[allow(variant_size_differences)] #[derive(Copy, Debug, Clone, Hash, PartialEq, Eq)]
659#[repr(C, u8)]
660pub enum TextInputSelection {
661 All,
662 FromTo(TextInputSelectionRange),
663}
664
665azul_css::impl_option!(
666 TextInputSelection,
667 OptionTextInputSelection,
668 copy = false,
669 [Debug, Clone, Hash, PartialEq, Eq]
670);
671
672#[derive(Copy, Debug, Clone, Hash, PartialEq, Eq)]
673#[repr(C)]
674pub struct TextInputSelectionRange {
675 pub dir_from: usize,
676 pub dir_to: usize,
677}
678
679impl Default for TextInput {
680 fn default() -> Self {
681 Self {
682 text_input_state: TextInputStateWrapper::default(),
683 placeholder_style: CssPropertyWithConditionsVec::from_const_slice(
684 TEXT_INPUT_PLACEHOLDER_PROPS,
685 ),
686 container_style: CssPropertyWithConditionsVec::from_const_slice(
687 TEXT_INPUT_CONTAINER_PROPS,
688 ),
689 label_style: CssPropertyWithConditionsVec::from_const_slice(TEXT_INPUT_LABEL_PROPS),
690 }
691 }
692}
693
694impl Default for TextInputState {
695 fn default() -> Self {
696 Self {
697 text: Vec::new().into(),
698 placeholder: None.into(),
699 max_len: 50,
700 selection: None.into(),
701 cursor_pos: 0,
702 }
703 }
704}
705
706impl TextInputState {
707 #[must_use] pub fn get_text(&self) -> String {
708 self.text
709 .iter()
710 .filter_map(|c| core::char::from_u32(*c))
711 .collect()
712 }
713}
714
715impl Default for TextInputStateWrapper {
716 fn default() -> Self {
717 Self {
718 inner: TextInputState::default(),
719 on_text_input: None.into(),
720 on_virtual_key_down: None.into(),
721 on_focus_lost: None.into(),
722 update_text_input_before_calling_focus_lost_fn: true,
723 update_text_input_before_calling_vk_down_fn: true,
724 cursor_animation: None.into(),
725 }
726 }
727}
728
729impl TextInput {
730 #[must_use] pub fn create() -> Self {
731 Self::default()
732 }
733
734 #[must_use] pub fn with_text(mut self, text: AzString) -> Self {
735 self.set_text(text);
736 self
737 }
738
739 #[allow(clippy::needless_pass_by_value)]
741 pub fn set_text(&mut self, text: AzString) {
742 self.text_input_state.inner.text = text
743 .as_str()
744 .chars()
745 .map(|c| c as u32)
746 .collect::<Vec<_>>()
747 .into();
748 }
749
750 pub fn set_placeholder(&mut self, placeholder: AzString) {
751 self.text_input_state.inner.placeholder = Some(placeholder).into();
752 }
753
754 #[must_use] pub fn with_placeholder(mut self, placeholder: AzString) -> Self {
755 self.set_placeholder(placeholder);
756 self
757 }
758
759 pub fn set_on_text_input<C: Into<TextInputOnTextInputCallback>>(
760 &mut self,
761 refany: RefAny,
762 callback: C,
763 ) {
764 self.text_input_state.on_text_input = Some(TextInputOnTextInput {
765 callback: callback.into(),
766 refany,
767 })
768 .into();
769 }
770
771 #[must_use]
772 pub fn with_on_text_input<C: Into<TextInputOnTextInputCallback>>(
773 mut self,
774 refany: RefAny,
775 callback: C,
776 ) -> Self {
777 self.set_on_text_input(refany, callback);
778 self
779 }
780
781 pub fn set_on_virtual_key_down<C: Into<TextInputOnVirtualKeyDownCallback>>(
782 &mut self,
783 refany: RefAny,
784 callback: C,
785 ) {
786 self.text_input_state.on_virtual_key_down = Some(TextInputOnVirtualKeyDown {
787 callback: callback.into(),
788 refany,
789 })
790 .into();
791 }
792
793 #[must_use]
794 pub fn with_on_virtual_key_down<C: Into<TextInputOnVirtualKeyDownCallback>>(
795 mut self,
796 refany: RefAny,
797 callback: C,
798 ) -> Self {
799 self.set_on_virtual_key_down(refany, callback);
800 self
801 }
802
803 pub fn set_on_focus_lost<C: Into<TextInputOnFocusLostCallback>>(
804 &mut self,
805 refany: RefAny,
806 callback: C,
807 ) {
808 self.text_input_state.on_focus_lost = Some(TextInputOnFocusLost {
809 callback: callback.into(),
810 refany,
811 })
812 .into();
813 }
814
815 #[must_use]
816 pub fn with_on_focus_lost<C: Into<TextInputOnFocusLostCallback>>(
817 mut self,
818 refany: RefAny,
819 callback: C,
820 ) -> Self {
821 self.set_on_focus_lost(refany, callback);
822 self
823 }
824
825 pub fn set_placeholder_style(&mut self, style: CssPropertyWithConditionsVec) {
826 self.placeholder_style = style;
827 }
828
829 #[must_use] pub fn with_placeholder_style(mut self, style: CssPropertyWithConditionsVec) -> Self {
830 self.set_placeholder_style(style);
831 self
832 }
833
834 pub fn set_container_style(&mut self, style: CssPropertyWithConditionsVec) {
835 self.container_style = style;
836 }
837
838 #[must_use] pub fn with_container_style(mut self, style: CssPropertyWithConditionsVec) -> Self {
839 self.set_container_style(style);
840 self
841 }
842
843 pub fn set_label_style(&mut self, style: CssPropertyWithConditionsVec) {
844 self.label_style = style;
845 }
846
847 #[must_use] pub fn with_label_style(mut self, style: CssPropertyWithConditionsVec) -> Self {
848 self.set_label_style(style);
849 self
850 }
851
852 #[must_use]
853 pub fn swap_with_default(&mut self) -> Self {
854 let mut s = Self::default();
855 core::mem::swap(&mut s, self);
856 s
857 }
858
859 #[must_use] pub fn dom(mut self) -> Dom {
860 use azul_core::{
861 callbacks::CoreCallbackData,
862 dom::{EventFilter, FocusEventFilter, HoverEventFilter, IdOrClass::Class, TabIndex},
863 };
864
865 self.text_input_state.inner.cursor_pos = self.text_input_state.inner.text.len();
866
867 let label_text: String = self
868 .text_input_state
869 .inner
870 .text
871 .iter()
872 .filter_map(|s| core::char::from_u32(*s))
873 .collect();
874
875 let placeholder = self
876 .text_input_state
877 .inner
878 .placeholder
879 .as_ref()
880 .map(|s| s.as_str().to_string())
881 .unwrap_or_default();
882
883 let state_ref = RefAny::new(self.text_input_state);
884
885 Dom::create_div()
886 .with_ids_and_classes(vec![Class("__azul-native-text-input-container".into())].into())
887 .with_css_props(self.container_style)
888 .with_tab_index(TabIndex::Auto)
889 .with_dataset(Some(state_ref.clone()).into())
890 .with_callbacks(
891 vec![
892 CoreCallbackData {
893 event: EventFilter::Focus(FocusEventFilter::FocusReceived),
894 refany: state_ref.clone(),
895 callback: CoreCallback {
896 cb: default_on_focus_received as usize,
897 ctx: azul_core::refany::OptionRefAny::None,
898 },
899 },
900 CoreCallbackData {
901 event: EventFilter::Focus(FocusEventFilter::FocusLost),
902 refany: state_ref.clone(),
903 callback: CoreCallback {
904 cb: default_on_focus_lost as usize,
905 ctx: azul_core::refany::OptionRefAny::None,
906 },
907 },
908 CoreCallbackData {
909 event: EventFilter::Focus(FocusEventFilter::TextInput),
910 refany: state_ref.clone(),
911 callback: CoreCallback {
912 cb: default_on_text_input as usize,
913 ctx: azul_core::refany::OptionRefAny::None,
914 },
915 },
916 CoreCallbackData {
917 event: EventFilter::Focus(FocusEventFilter::VirtualKeyDown),
918 refany: state_ref.clone(),
919 callback: CoreCallback {
920 cb: default_on_virtual_key_down as usize,
921 ctx: azul_core::refany::OptionRefAny::None,
922 },
923 },
924 CoreCallbackData {
925 event: EventFilter::Hover(HoverEventFilter::MouseOver),
926 refany: state_ref,
927 callback: CoreCallback {
928 cb: default_on_mouse_hover as usize,
929 ctx: azul_core::refany::OptionRefAny::None,
930 },
931 },
932 ]
933 .into(),
934 )
935 .with_children(
936 vec![
937 Dom::create_text(placeholder)
938 .with_ids_and_classes(
939 vec![Class("__azul-native-text-input-placeholder".into())].into(),
940 )
941 .with_css_props(self.placeholder_style),
942 Dom::create_text(label_text)
943 .with_ids_and_classes(
944 vec![Class("__azul-native-text-input-label".into())].into(),
945 )
946 .with_css_props(self.label_style)
947 .with_children(
948 vec![Dom::create_div()
949 .with_ids_and_classes(
950 vec![Class("__azul-native-text-input-cursor".into())].into(),
951 )
952 .with_css_props(CssPropertyWithConditionsVec::from_const_slice(
953 TEXT_CURSOR_PROPS,
954 ))]
955 .into(),
956 ),
957 ]
958 .into(),
959 )
960 }
961}
962
963extern "C" fn default_on_focus_received(mut text_input: RefAny, mut info: CallbackInfo) -> Update {
964 let Some(mut text_input) = text_input.downcast_mut::<TextInputStateWrapper>() else {
965 return Update::DoNothing;
966 };
967
968 let text_input = &mut *text_input;
969
970 let Some(placeholder_text_node_id) = info.get_first_child(info.get_hit_node()) else {
971 return Update::DoNothing;
972 };
973
974 if text_input.inner.text.is_empty() {
976 info.set_css_property(
977 placeholder_text_node_id,
978 CssProperty::const_opacity(StyleOpacity::const_new(0)),
979 );
980 }
981
982 text_input.inner.cursor_pos = text_input.inner.text.len();
983
984 Update::DoNothing
985}
986
987extern "C" fn default_on_focus_lost(mut text_input: RefAny, mut info: CallbackInfo) -> Update {
988 let Some(mut text_input) = text_input.downcast_mut::<TextInputStateWrapper>() else {
989 return Update::DoNothing;
990 };
991
992 let text_input = &mut *text_input;
993
994 let Some(placeholder_text_node_id) = info.get_first_child(info.get_hit_node()) else {
995 return Update::DoNothing;
996 };
997
998 if text_input.inner.text.is_empty() {
1000 info.set_css_property(
1001 placeholder_text_node_id,
1002 CssProperty::const_opacity(StyleOpacity::const_new(100)),
1003 );
1004 }
1005
1006 let text_input = &mut *text_input;
1008 let onfocuslost = &mut text_input.on_focus_lost;
1009 let inner = text_input.inner.clone();
1010
1011 match onfocuslost.as_mut() {
1012 Some(TextInputOnFocusLost { callback, refany }) => {
1013 (callback.cb)(refany.clone(), info, inner)
1014 }
1015 None => Update::DoNothing,
1016 }
1017}
1018
1019extern "C" fn default_on_text_input(text_input: RefAny, info: CallbackInfo) -> Update {
1020 default_on_text_input_inner(text_input, info).unwrap_or(Update::DoNothing)
1021}
1022
1023fn default_on_text_input_inner(mut text_input: RefAny, mut info: CallbackInfo) -> Option<Update> {
1024 let mut text_input = text_input.downcast_mut::<TextInputStateWrapper>()?;
1025
1026 let changeset = info.get_text_changeset()?;
1028 let inserted_text = changeset.inserted_text.as_str().to_string();
1029
1030 if inserted_text.is_empty() {
1032 return None;
1033 }
1034
1035 let placeholder_node_id = info.get_first_child(info.get_hit_node())?;
1036 let label_node_id = info.get_next_sibling(placeholder_node_id)?;
1037 let _cursor_node_id = info.get_first_child(label_node_id)?;
1038
1039 let result = {
1040 let text_input = &mut *text_input;
1042 let ontextinput = &mut text_input.on_text_input;
1043
1044 let mut inner_clone = text_input.inner.clone();
1046 inner_clone.cursor_pos = inner_clone.cursor_pos.saturating_add(inserted_text.len());
1047 inner_clone.text = {
1048 let mut internal = inner_clone.text.clone().into_library_owned_vec();
1049 internal.extend(inserted_text.chars().map(|c| c as u32));
1050 internal.into()
1051 };
1052
1053 match ontextinput.as_mut() {
1054 Some(TextInputOnTextInput { callback, refany }) => {
1055 (callback.cb)(refany.clone(), info, inner_clone)
1056 }
1057 None => OnTextInputReturn {
1058 update: Update::DoNothing,
1059 valid: TextInputValid::Yes,
1060 },
1061 }
1062 };
1063
1064 if result.valid == TextInputValid::Yes {
1065 info.set_css_property(
1067 placeholder_node_id,
1068 CssProperty::const_opacity(StyleOpacity::const_new(0)),
1069 );
1070
1071 text_input.inner.text = {
1073 let mut internal = text_input.inner.text.clone().into_library_owned_vec();
1074 internal.extend(inserted_text.chars().map(|c| c as u32));
1075 internal.into()
1076 };
1077 text_input.inner.cursor_pos = text_input
1078 .inner
1079 .cursor_pos
1080 .saturating_add(inserted_text.len());
1081
1082 info.change_node_text(label_node_id, text_input.inner.get_text().into());
1083 }
1084
1085 Some(result.update)
1086}
1087
1088extern "C" fn default_on_virtual_key_down(text_input: RefAny, info: CallbackInfo) -> Update {
1089 default_on_virtual_key_down_inner(text_input, info).unwrap_or(Update::DoNothing)
1090}
1091
1092fn default_on_virtual_key_down_inner(
1093 mut text_input: RefAny,
1094 mut info: CallbackInfo,
1095) -> Option<Update> {
1096 let mut text_input = text_input.downcast_mut::<TextInputStateWrapper>()?;
1097 let keyboard_state = info.get_current_keyboard_state();
1098
1099 let c = keyboard_state.current_virtual_keycode.into_option()?;
1100 let placeholder_node_id = info.get_first_child(info.get_hit_node())?;
1101 let label_node_id = info.get_next_sibling(placeholder_node_id)?;
1102 let _cursor_node_id = info.get_first_child(label_node_id)?;
1103
1104 let result = {
1107 let text_input = &mut *text_input;
1109 let inner_clone = text_input.inner.clone();
1110 match text_input.on_virtual_key_down.as_mut() {
1111 Some(TextInputOnVirtualKeyDown { callback, refany }) => {
1112 (callback.cb)(refany.clone(), info, inner_clone)
1113 }
1114 None => OnTextInputReturn {
1115 update: Update::DoNothing,
1116 valid: TextInputValid::Yes,
1117 },
1118 }
1119 };
1120
1121 if result.valid == TextInputValid::Yes && c == VirtualKeyCode::Back {
1122 text_input.inner.text = {
1123 let mut internal = text_input.inner.text.clone().into_library_owned_vec();
1124 internal.pop();
1125 internal.into()
1126 };
1127 text_input.inner.cursor_pos = text_input.inner.cursor_pos.saturating_sub(1);
1128
1129 info.change_node_text(label_node_id, text_input.inner.get_text().into());
1130 }
1131
1132 Some(result.update)
1133}
1134
1135extern "C" fn default_on_mouse_hover(mut text_input: RefAny, _info: CallbackInfo) -> Update {
1136 let Some(_text_input) = text_input.downcast_mut::<TextInputStateWrapper>() else {
1137 return Update::DoNothing;
1138 };
1139
1140 Update::DoNothing
1141}