i_slint_backend_qt/qt_widgets/
combobox.rs1use i_slint_core::input::FocusEventResult;
5
6use super::*;
7
8#[repr(C)]
9#[derive(FieldOffsets, Default, SlintElement)]
10#[pin]
11pub struct NativeComboBox {
12 pub enabled: Property<bool>,
13 pub has_focus: Property<bool>,
14 pub pressed: Property<bool>,
15 pub has_hover: Property<bool>,
16 pub is_open: Property<bool>,
17 pub current_value: Property<SharedString>,
18 widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
19 animation_tracker: Property<i32>,
20 pub cached_rendering_data: CachedRenderingData,
21}
22
23impl Item for NativeComboBox {
24 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
25 let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
26 self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>" {
27 return make_unique_animated_widget<QComboBox>(animation_tracker_property_ptr);
28 }})
29 }
30
31 fn layout_info(
32 self: Pin<&Self>,
33 orientation: Orientation,
34 _window_adapter: &Rc<dyn WindowAdapter>,
35 _self_rc: &ItemRc,
36 ) -> LayoutInfo {
37 let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);
38 let size = cpp!(unsafe [widget as "QWidget*"] -> qttypes::QSize as "QSize" {
39 ensure_initialized();
40 QStyleOptionComboBox option;
41 option.rect = option.fontMetrics.boundingRect("******************");
43 option.subControls = QStyle::SC_All;
44 return qApp->style()->sizeFromContents(QStyle::CT_ComboBox, &option, option.rect.size(), widget);
45 });
46 let min = match orientation {
47 Orientation::Horizontal => size.width,
48 Orientation::Vertical => size.height,
49 } as f32;
50 LayoutInfo { min, preferred: min, ..LayoutInfo::default() }
51 }
52
53 fn input_event_filter_before_children(
54 self: Pin<&Self>,
55 event: &MouseEvent,
56 _window_adapter: &Rc<dyn WindowAdapter>,
57 _self_rc: &ItemRc,
58 ) -> InputEventFilterResult {
59 Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(!matches!(event, MouseEvent::Exit));
60 InputEventFilterResult::ForwardAndIgnore
61 }
62
63 fn input_event(
64 self: Pin<&Self>,
65 event: &MouseEvent,
66 _window_adapter: &Rc<dyn WindowAdapter>,
67 _self_rc: &i_slint_core::items::ItemRc,
68 ) -> InputEventResult {
69 if matches!(event, MouseEvent::Exit) {
70 Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false);
71 }
72 InputEventResult::EventIgnored
73 }
74
75 fn capture_key_event(
76 self: Pin<&Self>,
77 _event: &KeyEvent,
78 _window_adapter: &Rc<dyn WindowAdapter>,
79 _self_rc: &ItemRc,
80 ) -> KeyEventResult {
81 KeyEventResult::EventIgnored
82 }
83
84 fn key_event(
85 self: Pin<&Self>,
86 _: &KeyEvent,
87 _window_adapter: &Rc<dyn WindowAdapter>,
88 _self_rc: &ItemRc,
89 ) -> KeyEventResult {
90 KeyEventResult::EventIgnored
91 }
92
93 fn focus_event(
94 self: Pin<&Self>,
95 _: &FocusEvent,
96 _window_adapter: &Rc<dyn WindowAdapter>,
97 _self_rc: &ItemRc,
98 ) -> FocusEventResult {
99 FocusEventResult::FocusIgnored
100 }
101
102 fn_render! { this dpr size painter widget initial_state =>
103 let down: bool = this.pressed();
104 let is_open: bool = this.is_open();
105 let text: qttypes::QString =
106 this.current_value().as_str().into();
107 let enabled = this.enabled();
108 let has_focus = this.has_focus();
109 let has_hover = this.has_hover();
110 cpp!(unsafe [
111 painter as "QPainterPtr*",
112 widget as "QWidget*",
113 text as "QString",
114 enabled as "bool",
115 size as "QSize",
116 down as "bool",
117 is_open as "bool",
118 has_focus as "bool",
119 has_hover as "bool",
120 dpr as "float",
121 initial_state as "int"
122 ] {
123 ensure_initialized();
124 QStyleOptionComboBox option;
125 option.styleObject = widget;
126 option.state |= QStyle::State(initial_state);
127 option.currentText = std::move(text);
128 option.rect = QRect(QPoint(), size / dpr);
129 if (down)
130 option.state |= QStyle::State_Sunken;
131 else
132 option.state |= QStyle::State_Raised;
133 if (enabled) {
134 option.state |= QStyle::State_Enabled;
135 } else {
136 option.palette.setCurrentColorGroup(QPalette::Disabled);
137 }
138 if (has_focus) {
139 option.state |= QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange | QStyle::State_Item;
140 }
141 if (has_hover) {
142 option.state |= QStyle::State_MouseOver;
143 }
144 if (is_open) {
146 }
148 option.subControls = QStyle::SC_All;
149 qApp->style()->drawComplexControl(QStyle::CC_ComboBox, &option, painter->get(), widget);
150 qApp->style()->drawControl(QStyle::CE_ComboBoxLabel, &option, painter->get(), widget);
151 });
152 }
153
154 fn bounding_rect(
155 self: core::pin::Pin<&Self>,
156 _window_adapter: &Rc<dyn WindowAdapter>,
157 _self_rc: &ItemRc,
158 geometry: LogicalRect,
159 ) -> LogicalRect {
160 geometry
161 }
162
163 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
164 false
165 }
166}
167
168impl ItemConsts for NativeComboBox {
169 const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
170 Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
171}
172
173declare_item_vtable! {
174fn slint_get_NativeComboBoxVTable() -> NativeComboBoxVTable for NativeComboBox
175}
176
177#[repr(C)]
178#[derive(FieldOffsets, Default, SlintElement)]
179#[pin]
180pub struct NativeComboBoxPopup {
181 widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
182 animation_tracker: Property<i32>,
183 pub cached_rendering_data: CachedRenderingData,
184}
185
186impl Item for NativeComboBoxPopup {
187 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
188 let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
189 self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>" {
190 return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);
191 }})
192 }
193
194 fn layout_info(
195 self: Pin<&Self>,
196 _orientation: Orientation,
197 _window_adapter: &Rc<dyn WindowAdapter>,
198 _self_rc: &ItemRc,
199 ) -> LayoutInfo {
200 Default::default()
201 }
202
203 fn input_event_filter_before_children(
204 self: Pin<&Self>,
205 _: &MouseEvent,
206 _window_adapter: &Rc<dyn WindowAdapter>,
207 _self_rc: &ItemRc,
208 ) -> InputEventFilterResult {
209 InputEventFilterResult::ForwardAndIgnore
210 }
211
212 fn capture_key_event(
213 self: Pin<&Self>,
214 _event: &KeyEvent,
215 _window_adapter: &Rc<dyn WindowAdapter>,
216 _self_rc: &ItemRc,
217 ) -> KeyEventResult {
218 KeyEventResult::EventIgnored
219 }
220
221 fn input_event(
222 self: Pin<&Self>,
223 _: &MouseEvent,
224 _window_adapter: &Rc<dyn WindowAdapter>,
225 _self_rc: &i_slint_core::items::ItemRc,
226 ) -> InputEventResult {
227 InputEventResult::EventIgnored
228 }
229
230 fn key_event(
231 self: Pin<&Self>,
232 _: &KeyEvent,
233 _window_adapter: &Rc<dyn WindowAdapter>,
234 _self_rc: &ItemRc,
235 ) -> KeyEventResult {
236 KeyEventResult::EventIgnored
237 }
238
239 fn focus_event(
240 self: Pin<&Self>,
241 _: &FocusEvent,
242 _window_adapter: &Rc<dyn WindowAdapter>,
243 _self_rc: &ItemRc,
244 ) -> FocusEventResult {
245 FocusEventResult::FocusIgnored
246 }
247
248 fn_render! { _this dpr size painter widget initial_state =>
249 cpp!(unsafe [
250 painter as "QPainterPtr*",
251 widget as "QWidget*",
252 size as "QSize",
253 dpr as "float",
254 initial_state as "int"
255 ] {
256 ensure_initialized();
257 QStyleOptionComboBox cb_option;
258 QStyleOptionFrame option;
259 option.styleObject = widget;
260 option.state |= QStyle::State(initial_state);
261 option.lineWidth = 0;
262 option.midLineWidth = 0;
263 option.rect = QRect(QPoint(), size / dpr);
264 option.state |= QStyle::State_Sunken | QStyle::State_Enabled;
265
266 auto style = qApp->style();
267 painter->get()->fillRect(option.rect, option.palette.window());
268
269 if (style->styleHint(QStyle::SH_ComboBox_Popup, &cb_option, widget)) {
270 style->drawPrimitive(QStyle::PE_PanelMenu, &option, painter->get(), widget);
271 auto vm = style->pixelMetric(QStyle::PM_MenuVMargin, &option, widget);
272 auto hm = style->pixelMetric(QStyle::PM_MenuHMargin, &option, widget);
273 painter->get()->fillRect(option.rect.adjusted(hm, vm, -hm, -vm), option.palette.window());
274 } else {
275 option.lineWidth = 1;
276 }
277 auto frameStyle = style->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &option, widget);
278 if ((frameStyle & QFrame::Shadow_Mask) == QFrame::Sunken)
279 option.state |= QStyle::State_Sunken;
280 else if ((frameStyle & QFrame::Shadow_Mask) == QFrame::Raised)
281 option.state |= QStyle::State_Raised;
282 option.frameShape = QFrame::Shape(frameStyle & QFrame::Shape_Mask);
283 style->drawControl(QStyle::CE_ShapedFrame, &option, painter->get(), widget);
284 });
285 }
286
287 fn bounding_rect(
288 self: core::pin::Pin<&Self>,
289 _window_adapter: &Rc<dyn WindowAdapter>,
290 _self_rc: &ItemRc,
291 geometry: LogicalRect,
292 ) -> LogicalRect {
293 geometry
294 }
295
296 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
297 false
298 }
299}
300
301impl ItemConsts for NativeComboBoxPopup {
302 const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
303 Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
304}
305
306declare_item_vtable! {
307fn slint_get_NativeComboBoxPopupVTable() -> NativeComboBoxPopupVTable for NativeComboBoxPopup
308}