ferroui_diagnostics/diagnostics/controls/
commit_text_box.rs1use ferroui_base::FerroObjectImplExt;
7use ferroui_base::input::InputElementImplExt;
8use ferroui_base::input::{FocusChangedEventArgs, InputElementImpl, Key, KeyEventArgs};
9use ferroui_base::interactivity::InteractiveImpl;
10use ferroui_base::layout::LayoutableImpl;
11use ferroui_base::{
12 ferro_class, ferro_class_info, ferro_impl_classes, ferro_properties, instantiate, DirectProperty, FerroObjectImpl,
13 FerroProperty, FerroPropertyChangedEventArgs, Ref, StyledElementImpl, TypeInfo, VisualImpl,
14};
15use ferroui_controls::primitives::TemplatedControlImpl;
16use ferroui_controls::{ControlImpl, DataValidationErrors, TextBox, TextBoxImpl};
17use std::cell::RefCell;
18
19#[repr(C)]
23pub struct CommitTextBox {
24 base: TextBox,
25 committed_text: RefCell<Option<String>>,
26}
27
28ferro_class!(CommitTextBox: TextBox);
29ferro_impl_classes!(
30 CommitTextBox: VisualImpl,
31 LayoutableImpl,
32 InteractiveImpl,
33 ControlImpl,
34 TemplatedControlImpl,
35 TextBoxImpl
36);
37ferro_class_info!(CommitTextBox { new: CommitTextBox::new });
38
39ferro_properties! {
40 impl CommitTextBox {
41 pub fn committed_text_property() -> DirectProperty<CommitTextBox, Option<String>> {
43 FerroProperty::register_direct::<CommitTextBox, _>(
44 "CommittedText",
45 |o| o.committed_text(),
46 Some(|o, v| o.set_committed_text(v)),
47 None,
48 )
49 }
50 }
51}
52
53impl StyledElementImpl for CommitTextBox {
54 fn style_key_override(_this: &Self) -> &'static TypeInfo {
55 TextBox::TYPE
56 }
57}
58
59impl FerroObjectImpl for CommitTextBox {
60 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
61 Self::parent_on_property_changed(this, change);
62
63 if change.property() == Self::committed_text_property().as_property() {
64 this.set_text(this.committed_text().as_deref());
65 }
66 }
67}
68
69impl InputElementImpl for CommitTextBox {
70 fn on_key_up(this: &Self, e: &KeyEventArgs) {
71 Self::parent_on_key_up(this, e);
72
73 match e.key {
74 Key::Enter => {
75 this.try_commit();
76
77 e.set_handled(true);
78 }
79
80 Key::Escape => {
81 this.cancel();
82
83 e.set_handled(true);
84 }
85
86 _ => {}
87 }
88 }
89
90 fn on_lost_focus(this: &Self, e: &FocusChangedEventArgs) {
91 Self::parent_on_lost_focus(this, e);
92
93 this.try_commit();
94 }
95}
96
97impl CommitTextBox {
98 pub fn construct() -> Self {
99 Self { base: TextBox::construct(), committed_text: RefCell::new(None) }
100 }
101
102 pub fn new() -> Ref<Self> {
103 instantiate(Self::construct())
104 }
105
106 pub fn committed_text(&self) -> Option<String> {
107 self.committed_text.borrow().clone()
108 }
109
110 pub fn set_committed_text(&self, value: Option<String>) {
111 self.set_and_raise(Self::committed_text_property(), &self.committed_text, value);
112 }
113
114 fn cancel(&self) {
115 self.set_text(self.committed_text().as_deref());
116 DataValidationErrors::clear_errors(self);
117 }
118
119 fn try_commit(&self) {
120 if !DataValidationErrors::get_has_errors(self) {
121 self.set_committed_text(self.text());
122 } else {
123 self.set_text(self.committed_text().as_deref());
124 DataValidationErrors::clear_errors(self);
125 }
126 }
127}