VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 20 months ago

Copyright year updates by scm.

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

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use