QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskPageIndicator.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskPageIndicator.h"
7#include "QskSkinlet.h"
8#include "QskEvent.h"
9
10QSK_SUBCONTROL( QskPageIndicator, Panel )
11QSK_SUBCONTROL( QskPageIndicator, Bullet )
12
13QSK_SYSTEM_STATE( QskPageIndicator, Selected, QskAspect::FirstSystemState << 1 )
14
15static int qskKeyIncrement(
16 const QskPageIndicator* indicator, const QKeyEvent* event )
17{
18 if ( qskIsStandardKeyInput( event, QKeySequence::MoveToNextChar ) )
19 return 1;
20
21 if ( qskIsStandardKeyInput( event, QKeySequence::MoveToPreviousChar ) )
22 return -1;
23
24 const auto key = event->key();
25
26 if ( indicator->orientation() == Qt::Horizontal )
27 {
28 const bool mirrored = indicator->layoutMirroring();
29
30 if ( key == Qt::Key_Left )
31 return mirrored ? 1 : -1;
32
33 if ( key == Qt::Key_Right )
34 return mirrored ? -1 : 1;
35 }
36 else
37 {
38 if ( key == Qt::Key_Up )
39 return -1;
40
41 if ( key == Qt::Key_Down )
42 return 1;
43 }
44
45 return 0;
46}
47
48
49class QskPageIndicator::PrivateData
50{
51 public:
52 PrivateData( int count )
53 : count( count )
54 , orientation( Qt::Horizontal )
55 {
56 }
57
58 qreal currentIndex = -1;
59 int pressedIndex = -1;
60
61 int count;
62 Qt::Orientation orientation : 2;
63};
64
65QskPageIndicator::QskPageIndicator( int count, QQuickItem* parent )
66 : Inherited( parent )
67 , m_data( new PrivateData( count ) )
68{
69 // as we don't stretch the bullets
70 initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
71}
72
73QskPageIndicator::QskPageIndicator( QQuickItem* parent )
74 : QskPageIndicator( 0, parent )
75{
76}
77
78QskPageIndicator::~QskPageIndicator()
79{
80}
81
82int QskPageIndicator::count() const
83{
84 return m_data->count;
85}
86
87qreal QskPageIndicator::currentIndex() const
88{
89 return m_data->currentIndex;
90}
91
92Qt::Orientation QskPageIndicator::orientation() const
93{
94 return m_data->orientation;
95}
96
97void QskPageIndicator::setOrientation( Qt::Orientation orientation )
98{
99 if ( orientation != m_data->orientation )
100 {
101 m_data->orientation = orientation;
102
104 update();
105
106 Q_EMIT orientationChanged( orientation );
107 }
108}
109
110void QskPageIndicator::setCount( int count )
111{
112 if ( count != m_data->count )
113 {
114 m_data->count = count;
115
117 update();
118
119 Q_EMIT countChanged( count );
120 }
121}
122
123void QskPageIndicator::setCurrentIndex( qreal index )
124{
125 if ( index < 0 || index >= m_data->count )
126 index = -1;
127
128 if ( index != m_data->currentIndex )
129 {
130 m_data->currentIndex = index;
131 update();
132
133 Q_EMIT currentIndexChanged( index );
134 }
135}
136
137qreal QskPageIndicator::valueRatioAt( int index ) const
138{
139 if ( m_data->currentIndex >= 0.0 && index >= 0 )
140 {
141 qreal pos = m_data->currentIndex;
142
143 if ( index == 0 && pos > m_data->count - 1 )
144 pos -= m_data->count;
145
146 const qreal diff = 1.0 - std::abs( pos - index );
147 return std::max( diff, 0.0 );
148 }
149
150 return 0.0;
151}
152
153QRectF QskPageIndicator::bulletRect( int index ) const
154{
155 return effectiveSkinlet()->sampleRect(
156 this, contentsRect(), QskPageIndicator::Bullet, index );
157}
158
159int QskPageIndicator::indexAtPosition( const QPointF& pos ) const
160{
161 return effectiveSkinlet()->sampleIndexAt(
162 this, contentsRect(), QskPageIndicator::Bullet, pos );
163}
164
166{
167 return static_cast< QskAspect::Variation >( m_data->orientation );
168}
169
170void QskPageIndicator::mousePressEvent( QMouseEvent* event )
171{
172 if ( event->button() == Qt::LeftButton )
173 {
174 /*
175 The bullets are usually small and therefore hard to click - with
176 touch input almost impossible. It might be better to
177 increment in direction of the mouse position ?
178
179 A swipe gesture might make more sense, TODO ...
180 */
181 const auto pos = qskMousePosition( event );
182 m_data->pressedIndex = indexAtPosition( pos );
183
184 return;
185 }
186
187 Inherited::mousePressEvent( event );
188}
189
190void QskPageIndicator::mouseUngrabEvent()
191{
192 m_data->pressedIndex = -1;
193}
194
195void QskPageIndicator::mouseReleaseEvent( QMouseEvent* event )
196{
197 if ( event->button() == Qt::LeftButton )
198 {
199 const auto index = m_data->pressedIndex;
200 m_data->pressedIndex = -1;
201
202 if ( index >= 0 )
203 {
204 const auto pos = qskMousePosition( event );
205 if ( indexAtPosition( pos ) == index )
206 Q_EMIT pageRequested( index );
207 }
208
209 return;
210 }
211
212 Inherited::mouseReleaseEvent( event );
213}
214
215void QskPageIndicator::keyPressEvent( QKeyEvent* event )
216{
217 if ( const int increment = qskKeyIncrement( this, event ) )
218 {
219 incrementRequested( increment );
220 return;
221 }
222
223 Inherited::keyPressEvent( event );
224}
225
226#ifndef QT_NO_WHEELEVENT
227
228void QskPageIndicator::wheelEvent( QWheelEvent* event )
229{
230 incrementRequested( qskWheelSteps( event ) );
231}
232
233#endif
234
235void QskPageIndicator::incrementRequested( int offset )
236{
237 const auto n = m_data->count;
238
239 if ( offset == 0 || n == 0 )
240 return;
241
242 int index = m_data->currentIndex;
243 if ( index < 0 && offset < 0 )
244 index = n;
245
246 // do we need a cycling on/off attribute, TODO ...
247
248 index = ( index + offset ) % n;
249 if ( index < 0 )
250 index += n;
251
252 if ( index != m_data->currentIndex )
253 Q_EMIT pageRequested( index );
254}
255
256#include "moc_QskPageIndicator.cpp"
@ FirstSystemState
Definition QskAspect.h:115
Variation
Some sort of variation.
Definition QskAspect.h:82
QRectF contentsRect() const
void resetImplicitSize()
Definition QskItem.cpp:721
QskAspect::Variation effectiveVariation() const override
const QskSkinlet * effectiveSkinlet() const