i_slint_backend_qt/qt_widgets/
progress_indicator.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 NativeProgressIndicator {
12    pub indeterminate: Property<bool>,
13    pub progress: Property<f32>,
14    widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
15    animation_tracker: Property<i32>,
16    pub cached_rendering_data: CachedRenderingData,
17}
18
19impl Item for NativeProgressIndicator {
20    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
21        let animation_tracker_property_ptr = Self::FIELD_OFFSETS.animation_tracker.apply_pin(self);
22        self.widget_ptr.set(
23            cpp! { unsafe [animation_tracker_property_ptr as "void*"] -> SlintTypeErasedWidgetPtr as "std::unique_ptr<SlintTypeErasedWidget>"  {
24                return make_unique_animated_widget<QProgressBar>(animation_tracker_property_ptr);
25            }},
26        )
27    }
28
29    fn layout_info(
30        self: Pin<&Self>,
31        orientation: Orientation,
32        _window_adapter: &Rc<dyn WindowAdapter>,
33        _self_rc: &ItemRc,
34    ) -> LayoutInfo {
35        let indeterminate = self.indeterminate();
36        let progress =
37            if indeterminate { 0 } else { (self.progress().max(0.0).min(1.0) * 100.) as i32 };
38        let widget: NonNull<()> = SlintTypeErasedWidgetPtr::qwidget_ptr(&self.widget_ptr);
39
40        let size = cpp!(unsafe [
41            progress as "int",
42            widget as "QWidget*"
43        ] -> qttypes::QSize as "QSize" {
44            ensure_initialized();
45            QStyleOptionProgressBar option;
46            option.maximum = 100;
47            option.minimum = 0;
48            option.progress = progress;
49            option.textVisible = false;
50            option.state |= QStyle::State_Horizontal;
51
52            int chunkWidth = qApp->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &option, widget);
53            auto size = QSize(chunkWidth * 10, option.fontMetrics.height() + 10);
54            return qApp->style()->sizeFromContents(QStyle::CT_ProgressBar, &option, size, widget);
55        });
56
57        match orientation {
58            Orientation::Horizontal => LayoutInfo {
59                min: size.width as f32,
60                preferred: size.width as f32,
61                stretch: 1.,
62                ..LayoutInfo::default()
63            },
64            Orientation::Vertical => LayoutInfo {
65                min: size.height as f32,
66                preferred: size.height as f32,
67                max: size.height as f32,
68                ..LayoutInfo::default()
69            },
70        }
71    }
72
73    fn input_event_filter_before_children(
74        self: Pin<&Self>,
75        _: &MouseEvent,
76        _window_adapter: &Rc<dyn WindowAdapter>,
77        _self_rc: &ItemRc,
78    ) -> InputEventFilterResult {
79        InputEventFilterResult::ForwardEvent
80    }
81
82    fn input_event(
83        self: Pin<&Self>,
84        _: &MouseEvent,
85        _window_adapter: &Rc<dyn WindowAdapter>,
86        _self_rc: &i_slint_core::items::ItemRc,
87    ) -> InputEventResult {
88        InputEventResult::EventIgnored
89    }
90
91    fn capture_key_event(
92        self: Pin<&Self>,
93        _event: &KeyEvent,
94        _window_adapter: &Rc<dyn WindowAdapter>,
95        _self_rc: &ItemRc,
96    ) -> KeyEventResult {
97        KeyEventResult::EventIgnored
98    }
99
100    fn key_event(
101        self: Pin<&Self>,
102        _: &KeyEvent,
103        _window_adapter: &Rc<dyn WindowAdapter>,
104        _self_rc: &ItemRc,
105    ) -> KeyEventResult {
106        KeyEventResult::EventIgnored
107    }
108
109    fn focus_event(
110        self: Pin<&Self>,
111        _: &FocusEvent,
112        _window_adapter: &Rc<dyn WindowAdapter>,
113        _self_rc: &ItemRc,
114    ) -> FocusEventResult {
115        FocusEventResult::FocusIgnored
116    }
117
118    fn_render! { this dpr size painter widget initial_state =>
119        let indeterminate = this.indeterminate();
120        let progress = if indeterminate { -1 } else { (this.progress().max(0.0).min(1.0) * 100.) as i32 };
121
122        cpp!(unsafe [
123            painter as "QPainterPtr*",
124            widget as "QWidget*",
125            size as "QSize",
126            progress as "int",
127            dpr as "float",
128            initial_state as "int"
129        ] {
130            QPainter *painter_ = painter->get();
131            QStyleOptionProgressBar option;
132            option.styleObject = widget;
133            option.state |= QStyle::State(initial_state) | QStyle::State_Horizontal |  QStyle::State_Enabled;
134            option.rect = QRect(QPoint(), size / dpr);
135            option.maximum = progress < 0 ? 0 : 100;
136            option.minimum = 0;
137            option.progress = progress;
138
139            qApp->style()->drawControl(QStyle::CE_ProgressBar, &option, painter_, widget);
140        });
141    }
142
143    fn bounding_rect(
144        self: core::pin::Pin<&Self>,
145        _window_adapter: &Rc<dyn WindowAdapter>,
146        _self_rc: &ItemRc,
147        geometry: LogicalRect,
148    ) -> LogicalRect {
149        geometry
150    }
151
152    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
153        false
154    }
155}
156
157impl ItemConsts for NativeProgressIndicator {
158    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
159        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
160}
161
162declare_item_vtable! {
163fn slint_get_NativeProgressIndicatorVTable() -> NativeProgressIndicatorVTable for NativeProgressIndicator
164}