QmlMaterial 0.1.0
Loading...
Searching...
No Matches
carousel_view.hpp
1#pragma once
2
3#include <QPointer>
4#include <QQuickItem>
5#include <QQmlComponent>
6#include <QQmlEngine>
7#include <QVariant>
8#include <QVector>
9
10#include <QPersistentModelIndex>
11
12#include "qml_material/carousel/carousel_attached.hpp"
13#include "qml_material/carousel/carousel_strategy.hpp"
14
15class QAbstractItemModel;
16
17namespace qml_material
18{
19
20class CarouselView : public QQuickItem {
21 Q_OBJECT
22 QML_ELEMENT
23 QML_ATTACHED(CarouselAttached)
24
25 Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged FINAL)
26 Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
27 Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
28 Q_PROPERTY(int layout READ layout WRITE setLayout NOTIFY layoutChanged FINAL)
29 Q_PROPERTY(
30 int orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
31 Q_PROPERTY(qreal itemExtent READ itemExtent WRITE setItemExtent NOTIFY itemExtentChanged FINAL)
32 Q_PROPERTY(qreal minSmallItemWidth READ minSmallItemWidth WRITE setMinSmallItemWidth NOTIFY
33 minSmallItemWidthChanged FINAL)
34 Q_PROPERTY(qreal maxSmallItemWidth READ maxSmallItemWidth WRITE setMaxSmallItemWidth NOTIFY
35 maxSmallItemWidthChanged FINAL)
36 Q_PROPERTY(
37 bool itemSnapping READ itemSnapping WRITE setItemSnapping NOTIFY itemSnappingChanged FINAL)
38 Q_PROPERTY(
39 int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
40 Q_PROPERTY(
41 int initialItem READ initialItem WRITE setInitialItem NOTIFY initialItemChanged FINAL)
42 Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged FINAL)
43 Q_PROPERTY(qreal contentPaddingStart READ contentPaddingStart WRITE setContentPaddingStart
44 NOTIFY contentPaddingChanged FINAL)
45 Q_PROPERTY(qreal contentPaddingEnd READ contentPaddingEnd WRITE setContentPaddingEnd NOTIFY
46 contentPaddingChanged FINAL)
47 Q_PROPERTY(qreal contentPaddingCross READ contentPaddingCross WRITE setContentPaddingCross
48 NOTIFY contentPaddingCrossChanged FINAL)
49 Q_PROPERTY(bool clipContainer READ clipContainer WRITE setClipContainer NOTIFY
50 clipContainerChanged FINAL)
51 Q_PROPERTY(
52 bool reduceMotion READ reduceMotion WRITE setReduceMotion NOTIFY reduceMotionChanged FINAL)
53 Q_PROPERTY(
54 bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged FINAL)
55 Q_PROPERTY(qreal itemCornerRadius READ itemCornerRadius WRITE setItemCornerRadius NOTIFY
56 itemCornerRadiusChanged FINAL)
57 Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentWidthChanged FINAL)
58 Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentHeightChanged FINAL)
59 Q_PROPERTY(QQuickItem* flickable READ flickable CONSTANT FINAL)
60
61public:
62 explicit CarouselView(QQuickItem* parent = nullptr);
63 ~CarouselView() override;
64
65 static CarouselAttached* qmlAttachedProperties(QObject* object);
66
67 QVariant model() const;
68 void setModel(const QVariant& model);
69 QQmlComponent* delegate() const;
70 void setDelegate(QQmlComponent* delegate);
71 int count() const;
72
73 int layout() const;
74 void setLayout(int layout);
75 int orientation() const;
76 void setOrientation(int orientation);
77
78 qreal itemExtent() const;
79 void setItemExtent(qreal extent);
80 qreal minSmallItemWidth() const;
81 void setMinSmallItemWidth(qreal width);
82 qreal maxSmallItemWidth() const;
83 void setMaxSmallItemWidth(qreal width);
84 bool itemSnapping() const;
85 void setItemSnapping(bool snapping);
86 int currentIndex() const;
87 void setCurrentIndex(int index);
88 int initialItem() const;
89 void setInitialItem(int item);
90 qreal spacing() const;
91 void setSpacing(qreal spacing);
92 qreal contentPaddingStart() const;
93 void setContentPaddingStart(qreal padding);
94 qreal contentPaddingEnd() const;
95 void setContentPaddingEnd(qreal padding);
96 qreal contentPaddingCross() const;
97 void setContentPaddingCross(qreal padding);
98 bool clipContainer() const;
99 void setClipContainer(bool clip);
100 bool reduceMotion() const;
101 void setReduceMotion(bool reduce);
102 qreal itemCornerRadius() const;
103 void setItemCornerRadius(qreal radius);
104 bool interactive() const;
105 void setInteractive(bool interactive);
106 qreal contentWidth() const;
107 qreal contentHeight() const;
108 QQuickItem* flickable() const;
109
110 Q_INVOKABLE void incrementCurrentIndex();
111 Q_INVOKABLE void decrementCurrentIndex();
112 Q_INVOKABLE void incrementCurrentIndexFromKeyboard();
113 Q_INVOKABLE void decrementCurrentIndexFromKeyboard();
114 Q_INVOKABLE void setCurrentIndexAnimated(int index);
115 Q_INVOKABLE void focusCurrentItem();
116 Q_INVOKABLE void claimInteractionFocus();
117 Q_INVOKABLE void engageTabFocus();
118 Q_INVOKABLE void suppressFocusRing();
119
120 Q_SIGNAL void modelChanged();
121 Q_SIGNAL void delegateChanged();
122 Q_SIGNAL void countChanged();
123 Q_SIGNAL void layoutChanged();
124 Q_SIGNAL void orientationChanged();
125 Q_SIGNAL void itemExtentChanged();
126 Q_SIGNAL void minSmallItemWidthChanged();
127 Q_SIGNAL void maxSmallItemWidthChanged();
128 Q_SIGNAL void itemSnappingChanged();
129 Q_SIGNAL void currentIndexChanged();
130 Q_SIGNAL void initialItemChanged();
131 Q_SIGNAL void spacingChanged();
132 Q_SIGNAL void contentPaddingChanged();
133 Q_SIGNAL void contentPaddingCrossChanged();
134 Q_SIGNAL void clipContainerChanged();
135 Q_SIGNAL void reduceMotionChanged();
136 Q_SIGNAL void itemCornerRadiusChanged();
137 Q_SIGNAL void interactiveChanged();
138 Q_SIGNAL void contentWidthChanged();
139 Q_SIGNAL void contentHeightChanged();
140 Q_SIGNAL void clicked(int index);
141
142protected:
143 void componentComplete() override;
144 void geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) override;
145 void itemChange(ItemChange change, const ItemChangeData& value) override;
146
147private Q_SLOTS:
148 void onDelegateClicked();
149 void onDelegateAspectRatioChanged();
150 void onSnapTick();
151 void onModelRowsChanged();
152 void onModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight,
153 const QList<int>& roles);
154
155private:
156 void syncCurrentIndexAfterCountChange();
157 void rebuildItems();
158 void updateLayout();
159 void updateCount();
160 void clearLayout();
161 void bindItemModel(QAbstractItemModel* model);
162 void unbindItemModel();
163 void snapAfterGesture();
164 void cancelSnapAnimation();
165 void applySnapAnimation(qreal targetOffset);
166 void finishSnap(qreal targetOffset);
167 qreal snapOffsetForIndex(int index) const;
168 void syncScrollToIndex(int index);
169 qreal snapTargetForGesture(qreal offset, qreal velocity) const;
170 int snapIndexForOffset(qreal offset) const;
171 int snapIndexForFling(qreal offset, qreal velocity) const;
172 bool usesSingleAdvanceFling() const;
173 bool usesFreeScrollSnap() const;
174 QVariant modelDataAt(int index) const;
175 QVariantMap initialPropertiesForDelegate(int index) const;
176 void applyDelegateProperties(QQuickItem* item, int index) const;
177 void createDelegate(int index);
178 void destroyDelegate(int index);
179 void positionItem(QQuickItem* item, const CarouselItemGeometry& geom, bool isActive);
180 int activeIndexForLayout(const CarouselLayoutOutput& out) const;
181 void broadcastFocusRingState();
182 void completeKeyboardNavigation();
183
184 QVariant m_model;
185 QQmlComponent* m_delegate = nullptr;
186 QPointer<QAbstractItemModel> m_item_model;
187 QPersistentModelIndex m_current_model_index;
188 int m_count = 0;
189 int m_layout = 0;
190 Qt::Orientation m_orientation = Qt::Horizontal;
191 qreal m_item_extent = 180;
192 qreal m_min_small_item_width = 40;
193 qreal m_max_small_item_width = 56;
194 qreal m_item_corner_radius = 28;
195 bool m_item_snapping = true;
196 int m_current_index = 0;
197 int m_initial_item = 0;
198 qreal m_spacing = 8;
199 qreal m_content_padding_start = 0;
200 qreal m_content_padding_end = 0;
201 qreal m_content_padding_cross = 0;
202 bool m_clip_container = true;
203 bool m_reduce_motion = false;
204 bool m_interactive = true;
205 bool m_snapping = false;
206 qreal m_content_width = 0;
207 qreal m_content_height = 0;
208 bool m_completed = false;
209
210 qreal m_snap_pos = 0;
211 qreal m_snap_velocity = 0;
212 qreal m_snap_target = 0;
213 class QTimer* m_snap_timer = nullptr;
214 QObject* m_snap_anim = nullptr;
215
216 QQuickItem* m_flickable = nullptr;
217 QQuickItem* m_content = nullptr;
218 QVector<QQuickItem*> m_items;
219 QVector<CarouselItemGeometry> m_geometries;
220 QVector<qreal> m_snap_offsets;
221 QVector<qreal> m_item_aspects;
222 qreal m_max_scroll_offset = 0;
223 qreal m_end_snap_offset = 0;
224 qreal m_scroll_step = 0;
225 bool m_updating = false;
226 bool m_focus_ring_suppressed = true;
227 bool m_tab_focus_engaged = false;
228 bool m_keyboard_nav_pending = false;
229 bool m_suppress_tab_engage = false;
230};
231
232} // namespace qml_material