QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskSlider.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskSlider.h"
7#include "QskAnimationHint.h"
8#include "QskAspect.h"
9#include "QskIntervalF.h"
10#include "QskEvent.h"
11
12QSK_SUBCONTROL( QskSlider, Panel )
13QSK_SUBCONTROL( QskSlider, Groove )
14QSK_SUBCONTROL( QskSlider, Fill )
15QSK_SUBCONTROL( QskSlider, Scale )
16QSK_SUBCONTROL( QskSlider, Handle )
17QSK_SUBCONTROL( QskSlider, GrooveStopIndicators )
18QSK_SUBCONTROL( QskSlider, FillStopIndicators )
19
20QSK_SYSTEM_STATE( QskSlider, Pressed, QskAspect::FirstSystemState << 2 )
21
22class QskSlider::PrivateData
23{
24 public:
25 PrivateData( Qt::Orientation orientation )
26 : pressedValue( 0 )
27 , tracking( true )
28 , orientation( orientation )
29 {
30 }
31
32 QPointF pressedPos;
33 qreal pressedValue;
34 bool tracking : 1;
35 Qt::Orientation orientation : 2;
36};
37
38QskSlider::QskSlider( QQuickItem* parent )
39 : QskSlider( Qt::Horizontal, parent )
40{
41}
42
43QskSlider::QskSlider( Qt::Orientation orientation, QQuickItem* parent )
44 : Inherited( parent )
45 , m_data( new PrivateData( orientation ) )
46{
47 setAcceptHoverEvents( true );
48 setFocusPolicy( Qt::StrongFocus );
49
50 if ( orientation == Qt::Horizontal )
51 initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
52 else
53 initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Minimum );
54
55 connect( this, &QskSlider::boundariesChanged, this, &QskSlider::moveHandle );
56 connect( this, &QskSlider::valueChanged, this, &QskSlider::moveHandle );
57}
58
59QskSlider::~QskSlider()
60{
61}
62
63bool QskSlider::isPressed() const
64{
65 return hasSkinState( Pressed );
66}
67
68void QskSlider::setOrientation( Qt::Orientation orientation )
69{
70 if ( orientation != m_data->orientation )
71 {
72 m_data->orientation = orientation;
73#if 1
74 // swapping the size policy: guess this is what a user expects
75 setSizePolicy( sizePolicy( Qt::Vertical ), sizePolicy( Qt::Horizontal ) );
76#endif
78 update();
79
80 Q_EMIT orientationChanged( m_data->orientation );
81 }
82}
83
84Qt::Orientation QskSlider::orientation() const
85{
86 return m_data->orientation;
87}
88
90{
91 return static_cast< QskAspect::Variation >( m_data->orientation );
92}
93
94void QskSlider::setTracking( bool on )
95{
96 if ( on != m_data->tracking )
97 {
98 m_data->tracking = on;
99 Q_EMIT trackingChanged( on );
100 }
101}
102
103bool QskSlider::isTracking() const
104{
105 return m_data->tracking;
106}
107
109{
110 setPositionHint( Handle, valueAsRatio() );
112}
113
114QSizeF QskSlider::handleSize() const
115{
116 return handleRect().size();
117}
118
119QRectF QskSlider::handleRect() const
120{
121 auto rect = subControlRect( Handle );
122
123#if 1 // minimum handle strut size hardcoded here for now
124 const QSizeF strutSize( 60, 60 );
125 const auto w = qMax( ( strutSize.width() - rect.width() ) / 2, 0.0 );
126 const auto h = qMax( ( strutSize.height() - rect.height() ) / 2, 0.0 );
127#endif
128
129 return rect.marginsAdded( { w, h, w, h } );
130}
131
132void QskSlider::mousePressEvent( QMouseEvent* event )
133{
134 if ( handleRect().contains( event->pos() ) )
135 {
136 // Case 1: press started in the handle, start sliding
137
138 m_data->pressedPos = event->pos();
139 m_data->pressedValue = value();
140 setSkinStateFlag( Pressed );
141 Q_EMIT pressedChanged( true );
142 }
143 else if ( pageSteps() == 0 )
144 {
145 // Case 2: pageSize is not used, we're done here
146 }
147 else
148 {
149 // Case 3: pressed outside of the handle, page the scroller in
150 // the direction of the press requires an auto-repeat behavior
151 // until the slider reaches the destination, or it simply jumps
152 // there (configurable)
153 }
154}
155
156void QskSlider::mouseMoveEvent( QMouseEvent* event )
157{
158 if ( !isPressed() )
159 return;
160
161 const auto mousePos = qskMousePosition( event );
162 const auto r = subControlRect( Scale );
163
164 qreal newValue;
165
166 if ( m_data->orientation == Qt::Horizontal )
167 {
168 const auto distance = mousePos.x() - m_data->pressedPos.x();
169 newValue = m_data->pressedValue + distance / r.width() * boundaryLength();
170 }
171 else
172 {
173 const auto distance = mousePos.y() - m_data->pressedPos.y();
174 newValue = m_data->pressedValue - distance / r.height() * boundaryLength();
175 }
176
177 if ( m_data->tracking )
178 {
179 setValue( newValue );
180 }
181 else
182 {
183 moveHandleTo( newValue, QskAnimationHint() );
184 }
185}
186
187void QskSlider::mouseReleaseEvent( QMouseEvent* event )
188{
189 if ( !isPressed() ) // Page event
190 {
191 const auto mousePos = qskMousePosition( event );
192
193 const auto szHandle = handleSize();
194 const auto rect = contentsRect();
195
196 bool up;
197 if ( m_data->orientation == Qt::Horizontal )
198 {
199 const qreal w = szHandle.width();
200
201 const qreal x = ( mousePos.x() - rect.x() - w * 0.5 ) / ( rect.width() - w );
202 up = x > valueAsRatio();
203 }
204 else
205 {
206 const qreal h = szHandle.height();
207
208 const qreal y = ( mousePos.y() - rect.y() - h * 0.5 ) / ( rect.height() - h );
209 up = y < 1.0 - valueAsRatio();
210 }
211
212 if ( up )
213 pageUp();
214 else
215 pageDown();
216 }
217 else
218 {
219 if ( !m_data->tracking )
220 {
221 const auto pos = handlePosition();
222 setValue( valueFromRatio( pos ) );
223 }
224 }
225
226 setSkinStateFlag( Pressed, false );
227 Q_EMIT pressedChanged( false );
228}
229
230qreal QskSlider::handlePosition() const
231{
232 return positionHint( Handle );
233}
234
235void QskSlider::moveHandle()
236{
237 const auto aspect = Handle | QskAspect::Metric | QskAspect::Position;
238 moveHandleTo( value(), animationHint( aspect | skinStates() ) );
239}
240
241void QskSlider::moveHandleTo( qreal value, const QskAnimationHint& hint )
242{
243 const qreal pos = valueAsRatio( value );
244
245 if ( hint.isValid() )
246 {
247 const qreal oldPos = positionHint( Handle );
248 setPositionHint( Handle, pos );
249
250 const auto aspect = Handle | QskAspect::Metric | QskAspect::Position;
251 startTransition( aspect, hint, oldPos, pos );
252 }
253 else
254 {
255 setPositionHint( Handle, pos );
256 }
257
258 update();
259}
260
261#include "moc_QskSlider.cpp"
@ FirstSystemState
Definition QskAspect.h:115
Variation
Some sort of variation.
Definition QskAspect.h:82
QRectF subControlRect(QskAspect::Subcontrol) const
void setSizePolicy(QskSizePolicy)
QskSizePolicy sizePolicy
Definition QskControl.h:43
QRectF contentsRect() const
QRectF rect
Definition QskItem.h:21
void resetImplicitSize()
Definition QskItem.cpp:721
virtual void aboutToShow()
Definition QskItem.cpp:1091
QskAnimationHint animationHint(QskAspect, QskSkinHintStatus *=nullptr) const
void setSkinStateFlag(QskAspect::State, bool on=true)
QskAspect::Variation effectiveVariation() const override
Definition QskSlider.cpp:89
void aboutToShow() override