i_slint_backend_qt/qt_widgets/
listviewitem.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use i_slint_core::input::FocusEventResult;
5
6use super::*;
7
8#[repr(C)]
9#[derive(FieldOffsets, Default, SlintElement)]
10#[pin]
11pub struct NativeStandardListViewItem {
12    pub item: Property<i_slint_core::model::StandardListViewItem>,
13    pub index: Property<i32>,
14    pub is_selected: Property<bool>,
15    pub cached_rendering_data: CachedRenderingData,
16    pub has_hover: Property<bool>,
17    pub has_focus: Property<bool>,
18    pub pressed: Property<bool>,
19    pub pressed_x: Property<LogicalLength>,
20    pub pressed_y: Property<LogicalLength>,
21
22    /// Specify that this item is in fact used in a ComboBox
23    pub combobox: Property<bool>,
24    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
25    animation_tracker: Property<i32>,
26}
27
28impl Item for NativeStandardListViewItem {
29    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
30        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
31        self.widget_ptr.set(cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>"  {
32            return make_unique_animated_widget<QWidget>(animation_tracker_property_ptr);
33        }})
34    }
35
36    fn layout_info(
37        self: Pin<&Self>,
38        orientation: Orientation,
39        _window_adapter: &Rc<dyn WindowAdapter>,
40        _self_rc: &ItemRc,
41    ) -> LayoutInfo {
42        let index: i32 = self.index();
43        let item = self.item();
44        let text: qttypes::QString = item.text.as_str().into();
45        let combobox: bool = self.combobox();
46
47        let s = cpp!(unsafe [
48            index as "int",
49            text as "QString",
50            combobox as "bool"
51        ] -> qttypes::QSize as "QSize" {
52            ensure_initialized();
53
54            QStyleOptionComboBox cb_opt;
55            if (combobox && qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, &cb_opt, nullptr)) {
56                QStyleOptionMenuItem option;
57                option.text = text;
58                option.text.replace(QChar('&'), QLatin1String("&&"));
59                return qApp->style()->sizeFromContents(QStyle::CT_MenuItem, &option, QSize{}, nullptr);
60            } else {
61                QStyleOptionViewItem option;
62                option.decorationPosition = QStyleOptionViewItem::Left;
63                option.decorationAlignment = Qt::AlignCenter;
64                option.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;
65                option.showDecorationSelected = qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, nullptr);
66                if (index % 2) {
67                    option.features |= QStyleOptionViewItem::Alternate;
68                }
69                option.features |= QStyleOptionViewItem::HasDisplay;
70                option.text = text;
71                return qApp->style()->sizeFromContents(QStyle::CT_ItemViewItem, &option, QSize{}, nullptr);
72                }
73        });
74        let min = match orientation {
75            Orientation::Horizontal => s.width,
76            Orientation::Vertical => s.height,
77        } as f32;
78        LayoutInfo { min, preferred: min, ..LayoutInfo::default() }
79    }
80
81    fn input_event_filter_before_children(
82        self: Pin<&Self>,
83        _: &MouseEvent,
84        _window_adapter: &Rc<dyn WindowAdapter>,
85        _self_rc: &ItemRc,
86    ) -> InputEventFilterResult {
87        InputEventFilterResult::ForwardAndIgnore
88    }
89
90    fn input_event(
91        self: Pin<&Self>,
92        _: &MouseEvent,
93        _window_adapter: &Rc<dyn WindowAdapter>,
94        _self_rc: &i_slint_core::items::ItemRc,
95    ) -> InputEventResult {
96        InputEventResult::EventIgnored
97    }
98
99    fn capture_key_event(
100        self: Pin<&Self>,
101        _event: &KeyEvent,
102        _window_adapter: &Rc<dyn WindowAdapter>,
103        _self_rc: &ItemRc,
104    ) -> KeyEventResult {
105        KeyEventResult::EventIgnored
106    }
107
108    fn key_event(
109        self: Pin<&Self>,
110        _: &KeyEvent,
111        _window_adapter: &Rc<dyn WindowAdapter>,
112        _self_rc: &ItemRc,
113    ) -> KeyEventResult {
114        KeyEventResult::EventIgnored
115    }
116
117    fn focus_event(
118        self: Pin<&Self>,
119        _: &FocusEvent,
120        _window_adapter: &Rc<dyn WindowAdapter>,
121        _self_rc: &ItemRc,
122    ) -> FocusEventResult {
123        FocusEventResult::FocusIgnored
124    }
125
126    fn_render! { this dpr size painter widget initial_state =>
127        let index: i32 = this.index();
128        let is_selected: bool = this.is_selected();
129        let combobox: bool = this.combobox();
130        let has_hover: bool = this.has_hover();
131        let has_focus: bool = this.has_focus();
132        let item = this.item();
133        let text: qttypes::QString = item.text.as_str().into();
134        cpp!(unsafe [
135            painter as "QPainterPtr*",
136            widget as "QWidget*",
137            size as "QSize",
138            dpr as "float",
139            index as "int",
140            is_selected as "bool",
141            has_hover as "bool",
142            has_focus as "bool",
143            text as "QString",
144            initial_state as "int",
145            combobox as "bool"
146        ] {
147            QStyleOptionComboBox cb_opt;
148            if (combobox && qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, &cb_opt, widget)) {
149                widget->setProperty("_q_isComboBoxPopupItem", true);
150                QStyleOptionMenuItem option;
151                option.styleObject = widget;
152                option.state |= QStyle::State(initial_state);
153                option.rect = QRect(QPoint(), size / dpr);
154                option.menuRect = QRect(QPoint(), size / dpr);
155                option.state = QStyle::State_Enabled;
156                if (has_hover) {
157                    option.state |= QStyle::State_MouseOver;
158                    option.state |= QStyle::State_Selected;
159                }
160
161                if (has_focus) {
162                    option.state |= QStyle::State_HasFocus;
163                    option.state |= QStyle::State_Selected;
164                }
165                option.text = text;
166                option.text.replace(QChar('&'), QLatin1String("&&"));
167                option.checked = is_selected;
168                option.menuItemType = QStyleOptionMenuItem::Normal;
169                //option.reservedShortcutWidth = 0;
170                //option.maxIconWidth = 4;
171
172                qApp->style()->drawControl(QStyle::CE_MenuItem, &option, painter->get(), widget);
173                widget->setProperty("_q_isComboBoxPopupItem", {});
174            } else {
175                QStyleOptionViewItem option;
176                option.styleObject = widget;
177                option.state |= QStyle::State(initial_state);
178                option.rect = QRect(QPoint(), size / dpr);
179                option.state |= QStyle::State_Enabled;
180                if (is_selected) {
181                    option.state |= QStyle::State_Selected;
182                }
183                if (has_hover) {
184                    option.state |= QStyle::State_MouseOver;
185                }
186                if (has_focus) {
187                    option.state |= QStyle::State_HasFocus;
188                }
189                option.decorationPosition = QStyleOptionViewItem::Left;
190                option.decorationAlignment = Qt::AlignCenter;
191                option.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter;
192                option.showDecorationSelected = qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, nullptr);
193
194                if (index % 2) {
195                    option.features |= QStyleOptionViewItem::Alternate;
196                }
197                option.features |= QStyleOptionViewItem::HasDisplay;
198
199                option.text = text;
200
201                qApp->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &option, painter->get(), widget);
202                qApp->style()->drawControl(QStyle::CE_ItemViewItem, &option, painter->get(), widget);
203            }
204        });
205    }
206
207    fn bounding_rect(
208        self: core::pin::Pin<&Self>,
209        _window_adapter: &Rc<dyn WindowAdapter>,
210        _self_rc: &ItemRc,
211        geometry: LogicalRect,
212    ) -> LogicalRect {
213        geometry
214    }
215
216    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
217        false
218    }
219}
220
221impl ItemConsts for NativeStandardListViewItem {
222    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
223        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
224}
225
226declare_item_vtable! {
227fn slint_get_NativeStandardListViewItemVTable() -> NativeStandardListViewItemVTable for NativeStandardListViewItem
228}