i_slint_backend_qt/qt_widgets/
lineedit.rs1use i_slint_core::graphics::{Image, Rgba8Pixel, SharedPixelBuffer};
5use i_slint_core::input::FocusEventResult;
6use i_slint_core::items::InputType;
7
8use super::*;
9
10#[repr(C)]
11#[derive(FieldOffsets, Default, SlintElement)]
12#[pin]
13pub struct NativeLineEdit {
14 pub cached_rendering_data: CachedRenderingData,
15 pub native_padding_left: Property<LogicalLength>,
16 pub native_padding_right: Property<LogicalLength>,
17 pub native_padding_top: Property<LogicalLength>,
18 pub native_padding_bottom: Property<LogicalLength>,
19 pub has_focus: Property<bool>,
20 pub enabled: Property<bool>,
21 pub input_type: Property<InputType>,
22 pub clear_icon: Property<Image>,
23 widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
24 animation_tracker: Property<i32>,
25}
26
27fn get_clear_icon() -> Image {
28 let dpr = cpp!(unsafe [] -> f32 as "float" {
29 return qApp->devicePixelRatio();
30 });
31
32 let size = cpp!(unsafe [] -> u32 as "uint" {
33 #if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
34 return qApp->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, nullptr);
35 #else
36 return qApp->style()->pixelMetric(QStyle::PM_LineEditIconSize, nullptr, nullptr);
37 #endif
38 });
39
40 let width = (size as f32 * dpr).ceil() as u32;
41 let height = width;
42
43 let mut pixel_buffer = SharedPixelBuffer::<Rgba8Pixel>::new(width, height);
44 let ptr = pixel_buffer.make_mut_bytes().as_mut_ptr();
45
46 cpp!(unsafe [
47 width as "uint32_t",
48 height as "uint32_t",
49 ptr as "uint8_t*"
50 ] {
51 QStyleOptionFrame option;
52 const QIcon icon = qApp->style()->standardIcon(QStyle::SP_LineEditClearButton, &option);
53 QImage image(ptr, width, height, QImage::Format_RGBA8888);
54 image.setDevicePixelRatio(1.0);
55 QPainter painter(&image);
56 icon.paint(&painter, 0, 0, width, height, Qt::AlignCenter);
57 });
58
59 Image::from_rgba8(pixel_buffer)
60}
61
62impl Item for NativeLineEdit {
63 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
64 let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
65 self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>" {
66 return make_unique_animated_widget<QLineEdit>(animation_tracker_property_ptr);
67 }});
68
69 let paddings = Rc::pin(Property::default());
70
71 paddings.as_ref().set_binding(move || {
72 cpp!(unsafe [] -> qttypes::QMargins as "QMargins" {
73 ensure_initialized();
74 QStyleOptionFrame option;
75 option.state |= QStyle::State_Enabled;
76 option.lineWidth = 1;
77 option.midLineWidth = 0;
78 option.rect = QRect(0, 0, 10000, 10000);
80 QRect contentsRect = qApp->style()->subElementRect(
81 QStyle::SE_LineEditContents, &option);
82
83 return {
86 (2 + contentsRect.left()),
87 (4 + contentsRect.top()),
88 (2 + option.rect.right() - contentsRect.right()),
89 (4 + option.rect.bottom() - contentsRect.bottom())
90 };
91 })
92 });
93
94 self.native_padding_left.set_binding({
95 let paddings = paddings.clone();
96 move || LogicalLength::new(paddings.as_ref().get().left as _)
97 });
98 self.native_padding_right.set_binding({
99 let paddings = paddings.clone();
100 move || LogicalLength::new(paddings.as_ref().get().right as _)
101 });
102 self.native_padding_top.set_binding({
103 let paddings = paddings.clone();
104 move || LogicalLength::new(paddings.as_ref().get().top as _)
105 });
106 self.native_padding_bottom.set_binding({
107 let paddings = paddings;
108 move || LogicalLength::new(paddings.as_ref().get().bottom as _)
109 });
110
111 self.clear_icon.set(get_clear_icon());
112 }
113
114 fn layout_info(
115 self: Pin<&Self>,
116 orientation: Orientation,
117 _window_adapter: &Rc<dyn WindowAdapter>,
118 _self_rc: &ItemRc,
119 ) -> LayoutInfo {
120 let min = match orientation {
121 Orientation::Horizontal => self.native_padding_left() + self.native_padding_right(),
122 Orientation::Vertical => self.native_padding_top() + self.native_padding_bottom(),
123 }
124 .get();
125 LayoutInfo {
126 min,
127 preferred: min,
128 stretch: if orientation == Orientation::Horizontal { 1. } else { 0. },
129 ..LayoutInfo::default()
130 }
131 }
132
133 fn input_event_filter_before_children(
134 self: Pin<&Self>,
135 _: &MouseEvent,
136 _window_adapter: &Rc<dyn WindowAdapter>,
137 _self_rc: &ItemRc,
138 ) -> InputEventFilterResult {
139 InputEventFilterResult::ForwardAndIgnore
140 }
141
142 fn input_event(
143 self: Pin<&Self>,
144 _: &MouseEvent,
145 _window_adapter: &Rc<dyn WindowAdapter>,
146 _self_rc: &i_slint_core::items::ItemRc,
147 ) -> InputEventResult {
148 InputEventResult::EventIgnored
149 }
150
151 fn capture_key_event(
152 self: Pin<&Self>,
153 _event: &KeyEvent,
154 _window_adapter: &Rc<dyn WindowAdapter>,
155 _self_rc: &ItemRc,
156 ) -> KeyEventResult {
157 KeyEventResult::EventIgnored
158 }
159
160 fn key_event(
161 self: Pin<&Self>,
162 _: &KeyEvent,
163 _window_adapter: &Rc<dyn WindowAdapter>,
164 _self_rc: &ItemRc,
165 ) -> KeyEventResult {
166 KeyEventResult::EventIgnored
167 }
168
169 fn focus_event(
170 self: Pin<&Self>,
171 _: &FocusEvent,
172 _window_adapter: &Rc<dyn WindowAdapter>,
173 _self_rc: &ItemRc,
174 ) -> FocusEventResult {
175 FocusEventResult::FocusIgnored
176 }
177
178 fn_render! { this dpr size painter widget initial_state =>
179 let has_focus: bool = this.has_focus();
180 let enabled: bool = this.enabled();
181
182 cpp!(unsafe [
183 painter as "QPainterPtr*",
184 widget as "QWidget*",
185 size as "QSize",
186 dpr as "float",
187 enabled as "bool",
188 has_focus as "bool",
189 initial_state as "int"
190 ] {
191 QStyleOptionFrame option;
192 option.styleObject = widget;
193 option.state |= QStyle::State(initial_state);
194 option.rect = QRect(QPoint(), size / dpr);
195 option.lineWidth = 1;
196 option.midLineWidth = 0;
197 if (enabled) {
198 option.state |= QStyle::State_Enabled;
199 if (has_focus)
200 option.state |= QStyle::State_HasFocus;
201 } else {
202 option.palette.setCurrentColorGroup(QPalette::Disabled);
203 }
204 qApp->style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, painter->get(), widget);
205 });
206 }
207
208 fn bounding_rect(
209 self: core::pin::Pin<&Self>,
210 _window_adapter: &Rc<dyn WindowAdapter>,
211 _self_rc: &ItemRc,
212 geometry: LogicalRect,
213 ) -> LogicalRect {
214 geometry
215 }
216
217 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
218 false
219 }
220}
221
222impl ItemConsts for NativeLineEdit {
223 const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
224 Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
225}
226
227declare_item_vtable! {
228fn slint_get_NativeLineEditVTable() -> NativeLineEditVTable for NativeLineEdit
229}