VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIAdvancedSlider.cpp@ 82781

Last change on this file since 82781 was 76606, checked in by vboxsync, 5 years ago

FE/Qt: Cleaning out old precompiled header experiment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/* $Id: QIAdvancedSlider.cpp 76606 2019-01-02 05:40:39Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QIAdvancedSlider class implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* Qt includes: */
19#include <QPainter>
20#include <QSlider>
21#include <QStyle>
22#include <QVBoxLayout>
23
24/* GUI includes: */
25#include "QIAdvancedSlider.h"
26
27/* Qt includes: */
28#include <QStyleOptionSlider>
29
30/* External includes: */
31#include <math.h>
32
33
34/** QSlider subclass for our private needs. */
35class UIPrivateSlider : public QSlider
36{
37 Q_OBJECT;
38
39public:
40
41 /** Constructs private-slider passing @a pParent and @a enmOrientation to the base-class. */
42 UIPrivateSlider(Qt::Orientation enmOrientation, QWidget *pParent = 0);
43
44 /** Returns suitable position for @a iValue. */
45 int positionForValue(int iValue) const;
46
47 /** @todo encapsulate below stuff accordingly.. */
48
49 /** Holds the minimum optimal border. */
50 int m_minOpt;
51 /** Holds the maximum optimal border. */
52 int m_maxOpt;
53 /** Holds the minimum warning border. */
54 int m_minWrn;
55 /** Holds the maximum warning border. */
56 int m_maxWrn;
57 /** Holds the minimum error border. */
58 int m_minErr;
59 /** Holds the maximum error border. */
60 int m_maxErr;
61
62protected:
63
64 /** Handles paint @a pEvent. */
65 virtual void paintEvent(QPaintEvent *pEvent);
66
67private:
68
69 /** Holds the optimal color. */
70 QColor m_optColor;
71 /** Holds the warning color. */
72 QColor m_wrnColor;
73 /** Holds the error color. */
74 QColor m_errColor;
75};
76
77
78/*********************************************************************************************************************************
79* Class UIPrivateSlider implementation. *
80*********************************************************************************************************************************/
81
82UIPrivateSlider::UIPrivateSlider(Qt::Orientation enmOrientation, QWidget *pParent /* = 0 */)
83 : QSlider(enmOrientation, pParent)
84 , m_minOpt(-1)
85 , m_maxOpt(-1)
86 , m_minWrn(-1)
87 , m_maxWrn(-1)
88 , m_minErr(-1)
89 , m_maxErr(-1)
90 , m_optColor(0x0, 0xff, 0x0, 0x3c)
91 , m_wrnColor(0xff, 0x54, 0x0, 0x3c)
92 , m_errColor(0xff, 0x0, 0x0, 0x3c)
93{
94 /* Make sure ticks *always* positioned below: */
95 setTickPosition(QSlider::TicksBelow);
96}
97
98int UIPrivateSlider::positionForValue(int iValue) const
99{
100 QStyleOptionSlider opt;
101 initStyleOption(&opt);
102 opt.subControls = QStyle::SC_All;
103 int iAvailable = opt.rect.width() - style()->pixelMetric(QStyle::PM_SliderLength, &opt, this);
104 return QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, iValue, iAvailable);
105}
106
107void UIPrivateSlider::paintEvent(QPaintEvent *pEvent)
108{
109 QPainter p(this);
110
111 QStyleOptionSlider opt;
112 initStyleOption(&opt);
113 opt.subControls = QStyle::SC_All;
114
115 int iAvailable = opt.rect.width() - style()->pixelMetric(QStyle::PM_SliderLength, &opt, this);
116 QSize s = size();
117
118 /* We want to acquire SC_SliderTickmarks sub-control rectangle
119 * and fill it with necessary background colors: */
120#ifdef VBOX_WS_MAC
121 // WORKAROUND:
122 // Under MacOS X SC_SliderTickmarks is not fully reliable
123 // source of the information we need, providing us with incorrect width.
124 // So we have to calculate tickmarks rectangle ourself.
125 QRect ticks = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderTickmarks, this);
126 ticks.setRect((s.width() - iAvailable) / 2, s.height() - ticks.y(), iAvailable, ticks.height());
127#else /* VBOX_WS_MAC */
128 // WORKAROUND:
129 // Under Windows SC_SliderTickmarks is fully unreliable
130 // source of the information we need, providing us with empty rectangle.
131 // Under X11 SC_SliderTickmarks is not fully reliable
132 // source of the information we need, providing us with different rectangles
133 // (correct or incorrect) under different look&feel styles.
134 // So we have to calculate tickmarks rectangle ourself.
135 QRect ticks = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this) |
136 style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
137 ticks.setRect((s.width() - iAvailable) / 2, ticks.bottom() + 1, iAvailable, s.height() - ticks.bottom() - 1);
138#endif /* VBOX_WS_MAC */
139
140 if ((m_minOpt != -1 &&
141 m_maxOpt != -1) &&
142 m_minOpt != m_maxOpt)
143 {
144 int iPosMinOpt = QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, m_minOpt, iAvailable);
145 int iPosMaxOpt = QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, m_maxOpt, iAvailable);
146 p.fillRect(ticks.x() + iPosMinOpt, ticks.y(), iPosMaxOpt - iPosMinOpt + 1, ticks.height(), m_optColor);
147 }
148 if ((m_minWrn != -1 &&
149 m_maxWrn != -1) &&
150 m_minWrn != m_maxWrn)
151 {
152 int iPosMinWrn = QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, m_minWrn, iAvailable);
153 int iPosMaxWrn = QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, m_maxWrn, iAvailable);
154 p.fillRect(ticks.x() + iPosMinWrn, ticks.y(), iPosMaxWrn - iPosMinWrn + 1, ticks.height(), m_wrnColor);
155 }
156 if ((m_minErr != -1 &&
157 m_maxErr != -1) &&
158 m_minErr != m_maxErr)
159 {
160 int iPosMinErr = QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, m_minErr, iAvailable);
161 int iPosMaxErr = QStyle::sliderPositionFromValue(opt.minimum, opt.maximum, m_maxErr, iAvailable);
162 p.fillRect(ticks.x() + iPosMinErr, ticks.y(), iPosMaxErr - iPosMinErr + 1, ticks.height(), m_errColor);
163 }
164 p.end();
165
166 /* Call to base-class: */
167 QSlider::paintEvent(pEvent);
168}
169
170
171/*********************************************************************************************************************************
172* Class QIAdvancedSlider implementation. *
173*********************************************************************************************************************************/
174
175QIAdvancedSlider::QIAdvancedSlider(QWidget *pParent /* = 0 */)
176 : QWidget(pParent)
177{
178 prepare();
179}
180
181QIAdvancedSlider::QIAdvancedSlider(Qt::Orientation enmOrientation, QWidget *pParent /* = 0 */)
182 : QWidget(pParent)
183{
184 prepare(enmOrientation);
185}
186
187int QIAdvancedSlider::value() const
188{
189 return m_pSlider->value();
190}
191
192void QIAdvancedSlider::setRange(int iMin, int iMax)
193{
194 m_pSlider->setRange(iMin, iMax);
195}
196
197void QIAdvancedSlider::setMaximum(int iValue)
198{
199 m_pSlider->setMaximum(iValue);
200}
201
202int QIAdvancedSlider::maximum() const
203{
204 return m_pSlider->maximum();
205}
206
207void QIAdvancedSlider::setMinimum(int iValue)
208{
209 m_pSlider->setMinimum(iValue);
210}
211
212int QIAdvancedSlider::minimum() const
213{
214 return m_pSlider->minimum();
215}
216
217void QIAdvancedSlider::setPageStep(int iValue)
218{
219 m_pSlider->setPageStep(iValue);
220}
221
222int QIAdvancedSlider::pageStep() const
223{
224 return m_pSlider->pageStep();
225}
226
227void QIAdvancedSlider::setSingleStep(int iValue)
228{
229 m_pSlider->setSingleStep(iValue);
230}
231
232int QIAdvancedSlider::singelStep() const
233{
234 return m_pSlider->singleStep();
235}
236
237void QIAdvancedSlider::setTickInterval(int iValue)
238{
239 m_pSlider->setTickInterval(iValue);
240}
241
242int QIAdvancedSlider::tickInterval() const
243{
244 return m_pSlider->tickInterval();
245}
246
247Qt::Orientation QIAdvancedSlider::orientation() const
248{
249 return m_pSlider->orientation();
250}
251
252void QIAdvancedSlider::setSnappingEnabled(bool fOn)
253{
254 m_fSnappingEnabled = fOn;
255}
256
257bool QIAdvancedSlider::isSnappingEnabled() const
258{
259 return m_fSnappingEnabled;
260}
261
262void QIAdvancedSlider::setOptimalHint(int iMin, int iMax)
263{
264 m_pSlider->m_minOpt = iMin;
265 m_pSlider->m_maxOpt = iMax;
266
267 update();
268}
269
270void QIAdvancedSlider::setWarningHint(int iMin, int iMax)
271{
272 m_pSlider->m_minWrn = iMin;
273 m_pSlider->m_maxWrn = iMax;
274
275 update();
276}
277
278void QIAdvancedSlider::setErrorHint(int iMin, int iMax)
279{
280 m_pSlider->m_minErr = iMin;
281 m_pSlider->m_maxErr = iMax;
282
283 update();
284}
285
286void QIAdvancedSlider::setOrientation(Qt::Orientation enmOrientation)
287{
288 m_pSlider->setOrientation(enmOrientation);
289}
290
291void QIAdvancedSlider::setValue (int iValue)
292{
293 m_pSlider->setValue(iValue);
294}
295
296void QIAdvancedSlider::sltSliderMoved(int iValue)
297{
298 iValue = snapValue(iValue);
299 m_pSlider->setValue(iValue);
300 emit sliderMoved(iValue);
301}
302
303void QIAdvancedSlider::prepare(Qt::Orientation enmOrientation /* = Qt::Horizontal */)
304{
305 m_fSnappingEnabled = false;
306
307 /* Create layout: */
308 QVBoxLayout *pMainLayout = new QVBoxLayout(this);
309 if (pMainLayout)
310 {
311 /* Configure layout: */
312 pMainLayout->setContentsMargins(0, 0, 0, 0);
313
314 /* Create private-slider: */
315 m_pSlider = new UIPrivateSlider(enmOrientation, this);
316 if (m_pSlider)
317 {
318 connect(m_pSlider, &UIPrivateSlider::sliderMoved, this, &QIAdvancedSlider::sltSliderMoved);
319 connect(m_pSlider, &UIPrivateSlider::valueChanged, this, &QIAdvancedSlider::valueChanged);
320 connect(m_pSlider, &UIPrivateSlider::sliderPressed, this, &QIAdvancedSlider::sliderPressed);
321 connect(m_pSlider, &UIPrivateSlider::sliderReleased, this, &QIAdvancedSlider::sliderReleased);
322
323 /* Add into layout: */
324 pMainLayout->addWidget(m_pSlider);
325 }
326 }
327}
328
329int QIAdvancedSlider::snapValue(int iValue)
330{
331 if (m_fSnappingEnabled &&
332 iValue > 2)
333 {
334 float l2 = log((float)iValue)/log(2.0);
335 int iNewVal = (int)pow((float)2, (int)qRound(l2)); /* The value to snap on */
336 int iPos = m_pSlider->positionForValue(iValue); /* Get the relative screen pos for the original value */
337 int iNewPos = m_pSlider->positionForValue(iNewVal); /* Get the relative screen pos for the snap value */
338 if (abs(iNewPos - iPos) < 5) /* 10 pixel snapping range */
339 {
340 iValue = iNewVal;
341 if (iValue > m_pSlider->maximum())
342 iValue = m_pSlider->maximum();
343 else if (iValue < m_pSlider->minimum())
344 iValue = m_pSlider->minimum();
345 }
346 }
347 return iValue;
348}
349
350
351#include "QIAdvancedSlider.moc"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use