mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
ParaView-5.0.1: Added the source-tree to ThirdParty-dev and patched as described in the README file
Resolves bug-report http://bugs.openfoam.org/view.php?id=2098
This commit is contained in:
929
ParaView-5.0.1/Qt/Widgets/ctkRangeSlider.cpp
Normal file
929
ParaView-5.0.1/Qt/Widgets/ctkRangeSlider.cpp
Normal file
@ -0,0 +1,929 @@
|
||||
/*=========================================================================
|
||||
|
||||
Program: ParaView
|
||||
Module: $RCSfile$
|
||||
|
||||
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
|
||||
All rights reserved.
|
||||
|
||||
ParaView is a free software; you can redistribute it and/or modify it
|
||||
under the terms of the ParaView license version 1.2.
|
||||
|
||||
See License_v1.2.txt for the full ParaView license.
|
||||
A copy of this license can be obtained by contacting
|
||||
Kitware Inc.
|
||||
28 Corporate Drive
|
||||
Clifton Park, NY 12065
|
||||
USA
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
========================================================================*/
|
||||
/*=========================================================================
|
||||
|
||||
Library: CTK
|
||||
|
||||
Copyright (c) Kitware Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
=========================================================================*/
|
||||
|
||||
// Qt includes
|
||||
#include <QDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QStyleOptionSlider>
|
||||
#include <QApplication>
|
||||
#include <QStylePainter>
|
||||
#include <QStyle>
|
||||
#include <QToolTip>
|
||||
|
||||
// CTK includes
|
||||
#include "ctkRangeSlider.h"
|
||||
|
||||
class ctkRangeSliderPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(ctkRangeSlider);
|
||||
protected:
|
||||
ctkRangeSlider* const q_ptr;
|
||||
public:
|
||||
/// Boolean indicates the selected handle
|
||||
/// True for the minimum range handle, false for the maximum range handle
|
||||
enum Handle {
|
||||
NoHandle = 0x0,
|
||||
MinimumHandle = 0x1,
|
||||
MaximumHandle = 0x2
|
||||
};
|
||||
Q_DECLARE_FLAGS(Handles, Handle);
|
||||
|
||||
ctkRangeSliderPrivate(ctkRangeSlider& object);
|
||||
void init();
|
||||
|
||||
/// Return the handle at the given pos, or none if no handle is at the pos.
|
||||
/// If a handle is selected, handleRect is set to the handle rect.
|
||||
/// otherwise return NoHandle and handleRect is set to the combined rect of
|
||||
/// the min and max handles
|
||||
Handle handleAtPos(const QPoint& pos, QRect& handleRect)const;
|
||||
|
||||
/// Copied verbatim from QSliderPrivate class (see QSlider.cpp)
|
||||
int pixelPosToRangeValue(int pos) const;
|
||||
int pixelPosFromRangeValue(int val) const;
|
||||
|
||||
/// Draw the bottom and top sliders.
|
||||
void drawMinimumSlider( QStylePainter* painter ) const;
|
||||
void drawMaximumSlider( QStylePainter* painter ) const;
|
||||
|
||||
/// End points of the range on the Model
|
||||
int m_MaximumValue;
|
||||
int m_MinimumValue;
|
||||
|
||||
/// End points of the range on the GUI. This is synced with the model.
|
||||
int m_MaximumPosition;
|
||||
int m_MinimumPosition;
|
||||
|
||||
/// Controls selected ?
|
||||
QStyle::SubControl m_MinimumSliderSelected;
|
||||
QStyle::SubControl m_MaximumSliderSelected;
|
||||
|
||||
/// See QSliderPrivate::clickOffset.
|
||||
/// Overrides this ivar
|
||||
int m_SubclassClickOffset;
|
||||
|
||||
/// See QSliderPrivate::position
|
||||
/// Overrides this ivar.
|
||||
int m_SubclassPosition;
|
||||
|
||||
/// Original width between the 2 bounds before any moves
|
||||
int m_SubclassWidth;
|
||||
|
||||
ctkRangeSliderPrivate::Handles m_SelectedHandles;
|
||||
|
||||
/// When symmetricMoves is true, moving a handle will move the other handle
|
||||
/// symmetrically, otherwise the handles are independent.
|
||||
bool m_SymmetricMoves;
|
||||
|
||||
QString m_HandleToolTip;
|
||||
|
||||
private:
|
||||
ctkRangeSliderPrivate & operator=(const ctkRangeSliderPrivate &);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSliderPrivate::ctkRangeSliderPrivate(ctkRangeSlider& object)
|
||||
:q_ptr(&object)
|
||||
{
|
||||
this->m_MinimumValue = 0;
|
||||
this->m_MaximumValue = 100;
|
||||
this->m_MinimumPosition = 0;
|
||||
this->m_MaximumPosition = 100;
|
||||
this->m_MinimumSliderSelected = QStyle::SC_None;
|
||||
this->m_MaximumSliderSelected = QStyle::SC_None;
|
||||
this->m_SubclassClickOffset = 0;
|
||||
this->m_SubclassPosition = 0;
|
||||
this->m_SubclassWidth = 0;
|
||||
this->m_SelectedHandles = 0;
|
||||
this->m_SymmetricMoves = false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSliderPrivate::init()
|
||||
{
|
||||
Q_Q(ctkRangeSlider);
|
||||
this->m_MinimumValue = q->minimum();
|
||||
this->m_MaximumValue = q->maximum();
|
||||
this->m_MinimumPosition = q->minimum();
|
||||
this->m_MaximumPosition = q->maximum();
|
||||
q->connect(q, SIGNAL(rangeChanged(int,int)), q, SLOT(onRangeChanged(int,int)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSliderPrivate::Handle ctkRangeSliderPrivate::handleAtPos(const QPoint& pos, QRect& handleRect)const
|
||||
{
|
||||
Q_Q(const ctkRangeSlider);
|
||||
|
||||
QStyleOptionSlider option;
|
||||
q->initStyleOption( &option );
|
||||
|
||||
// The functinos hitTestComplexControl only know about 1 handle. As we have
|
||||
// 2, we change the position of the handle and test if the pos correspond to
|
||||
// any of the 2 positions.
|
||||
|
||||
// Test the MinimumHandle
|
||||
option.sliderPosition = this->m_MinimumPosition;
|
||||
option.sliderValue = this->m_MinimumValue;
|
||||
|
||||
QStyle::SubControl minimumControl = q->style()->hitTestComplexControl(
|
||||
QStyle::CC_Slider, &option, pos, q);
|
||||
QRect minimumHandleRect = q->style()->subControlRect(
|
||||
QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q);
|
||||
|
||||
// Test if the pos is under the Maximum handle
|
||||
option.sliderPosition = this->m_MaximumPosition;
|
||||
option.sliderValue = this->m_MaximumValue;
|
||||
|
||||
QStyle::SubControl maximumControl = q->style()->hitTestComplexControl(
|
||||
QStyle::CC_Slider, &option, pos, q);
|
||||
QRect maximumHandleRect = q->style()->subControlRect(
|
||||
QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q);
|
||||
|
||||
// The pos is above both handles, select the closest handle
|
||||
if (minimumControl == QStyle::SC_SliderHandle &&
|
||||
maximumControl == QStyle::SC_SliderHandle)
|
||||
{
|
||||
int minDist = 0;
|
||||
int maxDist = 0;
|
||||
if (q->orientation() == Qt::Horizontal)
|
||||
{
|
||||
minDist = pos.x() - minimumHandleRect.left();
|
||||
maxDist = maximumHandleRect.right() - pos.x();
|
||||
}
|
||||
else //if (q->orientation() == Qt::Vertical)
|
||||
{
|
||||
minDist = minimumHandleRect.bottom() - pos.y();
|
||||
maxDist = pos.y() - maximumHandleRect.top();
|
||||
}
|
||||
Q_ASSERT( minDist >= 0 && maxDist >= 0);
|
||||
minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None;
|
||||
}
|
||||
|
||||
if (minimumControl == QStyle::SC_SliderHandle)
|
||||
{
|
||||
handleRect = minimumHandleRect;
|
||||
return MinimumHandle;
|
||||
}
|
||||
else if (maximumControl == QStyle::SC_SliderHandle)
|
||||
{
|
||||
handleRect = maximumHandleRect;
|
||||
return MaximumHandle;
|
||||
}
|
||||
handleRect = minimumHandleRect.united(maximumHandleRect);
|
||||
return NoHandle;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Copied verbatim from QSliderPrivate::pixelPosToRangeValue. See QSlider.cpp
|
||||
//
|
||||
int ctkRangeSliderPrivate::pixelPosToRangeValue( int pos ) const
|
||||
{
|
||||
Q_Q(const ctkRangeSlider);
|
||||
QStyleOptionSlider option;
|
||||
q->initStyleOption( &option );
|
||||
|
||||
QRect gr = q->style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderGroove,
|
||||
q );
|
||||
QRect sr = q->style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderHandle,
|
||||
q );
|
||||
int sliderMin, sliderMax, sliderLength;
|
||||
if (option.orientation == Qt::Horizontal)
|
||||
{
|
||||
sliderLength = sr.width();
|
||||
sliderMin = gr.x();
|
||||
sliderMax = gr.right() - sliderLength + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderLength = sr.height();
|
||||
sliderMin = gr.y();
|
||||
sliderMax = gr.bottom() - sliderLength + 1;
|
||||
}
|
||||
|
||||
return QStyle::sliderValueFromPosition( q->minimum(),
|
||||
q->maximum(),
|
||||
pos - sliderMin,
|
||||
sliderMax - sliderMin,
|
||||
option.upsideDown );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int ctkRangeSliderPrivate::pixelPosFromRangeValue( int val ) const
|
||||
{
|
||||
Q_Q(const ctkRangeSlider);
|
||||
QStyleOptionSlider option;
|
||||
q->initStyleOption( &option );
|
||||
|
||||
QRect gr = q->style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderGroove,
|
||||
q );
|
||||
QRect sr = q->style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderHandle,
|
||||
q );
|
||||
int sliderMin, sliderMax, sliderLength;
|
||||
if (option.orientation == Qt::Horizontal)
|
||||
{
|
||||
sliderLength = sr.width();
|
||||
sliderMin = gr.x();
|
||||
sliderMax = gr.right() - sliderLength + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderLength = sr.height();
|
||||
sliderMin = gr.y();
|
||||
sliderMax = gr.bottom() - sliderLength + 1;
|
||||
}
|
||||
|
||||
return QStyle::sliderPositionFromValue( q->minimum(),
|
||||
q->maximum(),
|
||||
val,
|
||||
sliderMax - sliderMin,
|
||||
option.upsideDown ) + sliderMin;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Draw slider at the bottom end of the range
|
||||
void ctkRangeSliderPrivate::drawMinimumSlider( QStylePainter* painter ) const
|
||||
{
|
||||
Q_Q(const ctkRangeSlider);
|
||||
QStyleOptionSlider option;
|
||||
q->initMinimumSliderStyleOption( &option );
|
||||
|
||||
option.subControls = QStyle::SC_SliderHandle;
|
||||
option.sliderValue = m_MinimumValue;
|
||||
option.sliderPosition = m_MinimumPosition;
|
||||
if (q->isMinimumSliderDown())
|
||||
{
|
||||
option.activeSubControls = QStyle::SC_SliderHandle;
|
||||
option.state |= QStyle::State_Sunken;
|
||||
}
|
||||
#ifdef Q_OS_MAC
|
||||
// On mac style, drawing just the handle actually draws also the groove.
|
||||
QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
|
||||
QStyle::SC_SliderHandle, q);
|
||||
painter->setClipRect(clip);
|
||||
#endif
|
||||
painter->drawComplexControl(QStyle::CC_Slider, option);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Draw slider at the top end of the range
|
||||
void ctkRangeSliderPrivate::drawMaximumSlider( QStylePainter* painter ) const
|
||||
{
|
||||
Q_Q(const ctkRangeSlider);
|
||||
QStyleOptionSlider option;
|
||||
q->initMaximumSliderStyleOption( &option );
|
||||
|
||||
option.subControls = QStyle::SC_SliderHandle;
|
||||
option.sliderValue = m_MaximumValue;
|
||||
option.sliderPosition = m_MaximumPosition;
|
||||
if (q->isMaximumSliderDown())
|
||||
{
|
||||
option.activeSubControls = QStyle::SC_SliderHandle;
|
||||
option.state |= QStyle::State_Sunken;
|
||||
}
|
||||
#ifdef Q_OS_MAC
|
||||
// On mac style, drawing just the handle actually draws also the groove.
|
||||
QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
|
||||
QStyle::SC_SliderHandle, q);
|
||||
painter->setClipRect(clip);
|
||||
#endif
|
||||
painter->drawComplexControl(QStyle::CC_Slider, option);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSlider::ctkRangeSlider(QWidget* _parent)
|
||||
: QSlider(_parent)
|
||||
, d_ptr(new ctkRangeSliderPrivate(*this))
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
d->init();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSlider::ctkRangeSlider( Qt::Orientation o,
|
||||
QWidget* parentObject )
|
||||
:QSlider(o, parentObject)
|
||||
, d_ptr(new ctkRangeSliderPrivate(*this))
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
d->init();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate* impl, QWidget* _parent)
|
||||
: QSlider(_parent)
|
||||
, d_ptr(impl)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
d->init();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSlider::ctkRangeSlider( ctkRangeSliderPrivate* impl, Qt::Orientation o,
|
||||
QWidget* parentObject )
|
||||
:QSlider(o, parentObject)
|
||||
, d_ptr(impl)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
d->init();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
ctkRangeSlider::~ctkRangeSlider()
|
||||
{
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
int ctkRangeSlider::minimumValue() const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_MinimumValue;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setMinimumValue( int min )
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
this->setValues( min, qMax(d->m_MaximumValue,min) );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
int ctkRangeSlider::maximumValue() const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_MaximumValue;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setMaximumValue( int max )
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
this->setValues( qMin(d->m_MinimumValue, max), max );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setValues(int l, int u)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
const int minValue =
|
||||
qBound(this->minimum(), qMin(l,u), this->maximum());
|
||||
const int maxValue =
|
||||
qBound(this->minimum(), qMax(l,u), this->maximum());
|
||||
bool emitMinValChanged = (minValue != d->m_MinimumValue);
|
||||
bool emitMaxValChanged = (maxValue != d->m_MaximumValue);
|
||||
|
||||
d->m_MinimumValue = minValue;
|
||||
d->m_MaximumValue = maxValue;
|
||||
|
||||
bool emitMinPosChanged =
|
||||
(minValue != d->m_MinimumPosition);
|
||||
bool emitMaxPosChanged =
|
||||
(maxValue != d->m_MaximumPosition);
|
||||
d->m_MinimumPosition = minValue;
|
||||
d->m_MaximumPosition = maxValue;
|
||||
|
||||
if (isSliderDown())
|
||||
{
|
||||
if (emitMinPosChanged || emitMaxPosChanged)
|
||||
{
|
||||
emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
|
||||
}
|
||||
if (emitMinPosChanged)
|
||||
{
|
||||
emit minimumPositionChanged(d->m_MinimumPosition);
|
||||
}
|
||||
if (emitMaxPosChanged)
|
||||
{
|
||||
emit maximumPositionChanged(d->m_MaximumPosition);
|
||||
}
|
||||
}
|
||||
if (emitMinValChanged || emitMaxValChanged)
|
||||
{
|
||||
emit valuesChanged(d->m_MinimumValue,
|
||||
d->m_MaximumValue);
|
||||
}
|
||||
if (emitMinValChanged)
|
||||
{
|
||||
emit minimumValueChanged(d->m_MinimumValue);
|
||||
}
|
||||
if (emitMaxValChanged)
|
||||
{
|
||||
emit maximumValueChanged(d->m_MaximumValue);
|
||||
}
|
||||
if (emitMinPosChanged || emitMaxPosChanged ||
|
||||
emitMinValChanged || emitMaxValChanged)
|
||||
{
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
int ctkRangeSlider::minimumPosition() const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_MinimumPosition;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
int ctkRangeSlider::maximumPosition() const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_MaximumPosition;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setMinimumPosition(int l)
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
this->setPositions(l, qMax(l, d->m_MaximumPosition));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setMaximumPosition(int u)
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
this->setPositions(qMin(d->m_MinimumPosition, u), u);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setPositions(int min, int max)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
const int minPosition =
|
||||
qBound(this->minimum(), qMin(min, max), this->maximum());
|
||||
const int maxPosition =
|
||||
qBound(this->minimum(), qMax(min, max), this->maximum());
|
||||
|
||||
bool emitMinPosChanged = (minPosition != d->m_MinimumPosition);
|
||||
bool emitMaxPosChanged = (maxPosition != d->m_MaximumPosition);
|
||||
|
||||
if (!emitMinPosChanged && !emitMaxPosChanged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d->m_MinimumPosition = minPosition;
|
||||
d->m_MaximumPosition = maxPosition;
|
||||
|
||||
if (!this->hasTracking())
|
||||
{
|
||||
this->update();
|
||||
}
|
||||
if (isSliderDown())
|
||||
{
|
||||
if (emitMinPosChanged)
|
||||
{
|
||||
emit minimumPositionChanged(d->m_MinimumPosition);
|
||||
}
|
||||
if (emitMaxPosChanged)
|
||||
{
|
||||
emit maximumPositionChanged(d->m_MaximumPosition);
|
||||
}
|
||||
if (emitMinPosChanged || emitMaxPosChanged)
|
||||
{
|
||||
emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
|
||||
}
|
||||
}
|
||||
if (this->hasTracking())
|
||||
{
|
||||
this->triggerAction(SliderMove);
|
||||
this->setValues(d->m_MinimumPosition, d->m_MaximumPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setSymmetricMoves(bool symmetry)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
d->m_SymmetricMoves = symmetry;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
bool ctkRangeSlider::symmetricMoves()const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_SymmetricMoves;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::onRangeChanged(int _minimum, int _maximum)
|
||||
{
|
||||
Q_UNUSED(_minimum);
|
||||
Q_UNUSED(_maximum);
|
||||
Q_D(ctkRangeSlider);
|
||||
this->setValues(d->m_MinimumValue, d->m_MaximumValue);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Render
|
||||
void ctkRangeSlider::paintEvent( QPaintEvent* )
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
QStyleOptionSlider option;
|
||||
this->initStyleOption(&option);
|
||||
|
||||
QStylePainter painter(this);
|
||||
option.subControls = QStyle::SC_SliderGroove;
|
||||
// Move to minimum to not highlight the SliderGroove.
|
||||
// On mac style, drawing just the slider groove also draws the handles,
|
||||
// therefore we give a negative (outside of view) position.
|
||||
option.sliderValue = this->minimum() - this->maximum();
|
||||
option.sliderPosition = this->minimum() - this->maximum();
|
||||
painter.drawComplexControl(QStyle::CC_Slider, option);
|
||||
|
||||
option.sliderPosition = d->m_MinimumPosition;
|
||||
const QRect lr = style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderHandle,
|
||||
this);
|
||||
option.sliderPosition = d->m_MaximumPosition;
|
||||
|
||||
const QRect ur = style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderHandle,
|
||||
this);
|
||||
|
||||
QRect sr = style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderGroove,
|
||||
this);
|
||||
QRect rangeBox;
|
||||
if (option.orientation == Qt::Horizontal)
|
||||
{
|
||||
rangeBox = QRect(
|
||||
QPoint(qMin( lr.center().x(), ur.center().x() ), sr.center().y() - 2),
|
||||
QPoint(qMax( lr.center().x(), ur.center().x() ), sr.center().y() + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeBox = QRect(
|
||||
QPoint(sr.center().x() - 2, qMin( lr.center().y(), ur.center().y() )),
|
||||
QPoint(sr.center().x() + 1, qMax( lr.center().y(), ur.center().y() )));
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Render the range
|
||||
//
|
||||
QRect groove = this->style()->subControlRect( QStyle::CC_Slider,
|
||||
&option,
|
||||
QStyle::SC_SliderGroove,
|
||||
this );
|
||||
groove.adjust(0, 0, -1, 0);
|
||||
|
||||
// Create default colors based on the transfer function.
|
||||
//
|
||||
QColor highlight = this->palette().color(QPalette::Normal, QPalette::Highlight);
|
||||
QLinearGradient gradient;
|
||||
if (option.orientation == Qt::Horizontal)
|
||||
{
|
||||
gradient = QLinearGradient( groove.center().x(), groove.top(),
|
||||
groove.center().x(), groove.bottom());
|
||||
}
|
||||
else
|
||||
{
|
||||
gradient = QLinearGradient( groove.left(), groove.center().y(),
|
||||
groove.right(), groove.center().y());
|
||||
}
|
||||
|
||||
// TODO: Set this based on the supplied transfer function
|
||||
//QColor l = Qt::darkGray;
|
||||
//QColor u = Qt::black;
|
||||
|
||||
gradient.setColorAt(0, highlight.darker(120));
|
||||
gradient.setColorAt(1, highlight.lighter(160));
|
||||
|
||||
painter.setPen(QPen(highlight.darker(150), 0));
|
||||
painter.setBrush(gradient);
|
||||
painter.drawRect( rangeBox.intersected(groove) );
|
||||
|
||||
// -----------------------------------
|
||||
// Render the sliders
|
||||
//
|
||||
if (this->isMinimumSliderDown())
|
||||
{
|
||||
d->drawMaximumSlider( &painter );
|
||||
d->drawMinimumSlider( &painter );
|
||||
}
|
||||
else
|
||||
{
|
||||
d->drawMinimumSlider( &painter );
|
||||
d->drawMaximumSlider( &painter );
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Standard Qt UI events
|
||||
void ctkRangeSlider::mousePressEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button()))
|
||||
{
|
||||
mouseEvent->ignore();
|
||||
return;
|
||||
}
|
||||
int mepos = this->orientation() == Qt::Horizontal ?
|
||||
mouseEvent->pos().x() : mouseEvent->pos().y();
|
||||
|
||||
QStyleOptionSlider option;
|
||||
this->initStyleOption( &option );
|
||||
|
||||
QRect handleRect;
|
||||
ctkRangeSliderPrivate::Handle handle_ = d->handleAtPos(mouseEvent->pos(), handleRect);
|
||||
|
||||
if (handle_ != ctkRangeSliderPrivate::NoHandle)
|
||||
{
|
||||
d->m_SubclassPosition = (handle_ == ctkRangeSliderPrivate::MinimumHandle)?
|
||||
d->m_MinimumPosition : d->m_MaximumPosition;
|
||||
|
||||
// save the position of the mouse inside the handle for later
|
||||
d->m_SubclassClickOffset = mepos - (this->orientation() == Qt::Horizontal ?
|
||||
handleRect.left() : handleRect.top());
|
||||
|
||||
this->setSliderDown(true);
|
||||
|
||||
if (d->m_SelectedHandles != handle_)
|
||||
{
|
||||
d->m_SelectedHandles = handle_;
|
||||
this->update(handleRect);
|
||||
}
|
||||
// Accept the mouseEvent
|
||||
mouseEvent->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we are here, no handles have been pressed
|
||||
// Check if we pressed on the groove between the 2 handles
|
||||
|
||||
QStyle::SubControl control = this->style()->hitTestComplexControl(
|
||||
QStyle::CC_Slider, &option, mouseEvent->pos(), this);
|
||||
QRect sr = style()->subControlRect(
|
||||
QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this);
|
||||
int minCenter = (this->orientation() == Qt::Horizontal ?
|
||||
handleRect.left() : handleRect.top());
|
||||
int maxCenter = (this->orientation() == Qt::Horizontal ?
|
||||
handleRect.right() : handleRect.bottom());
|
||||
if (control == QStyle::SC_SliderGroove &&
|
||||
mepos > minCenter && mepos < maxCenter)
|
||||
{
|
||||
// warning lost of precision it might be fatal
|
||||
d->m_SubclassPosition = (d->m_MinimumPosition + d->m_MaximumPosition) / 2.;
|
||||
d->m_SubclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_SubclassPosition);
|
||||
d->m_SubclassWidth = (d->m_MaximumPosition - d->m_MinimumPosition) / 2;
|
||||
qMax(d->m_SubclassPosition - d->m_MinimumPosition, d->m_MaximumPosition - d->m_SubclassPosition);
|
||||
this->setSliderDown(true);
|
||||
if (!this->isMinimumSliderDown() || !this->isMaximumSliderDown())
|
||||
{
|
||||
d->m_SelectedHandles =
|
||||
QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MinimumHandle) |
|
||||
QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MaximumHandle);
|
||||
this->update(handleRect.united(sr));
|
||||
}
|
||||
mouseEvent->accept();
|
||||
return;
|
||||
}
|
||||
mouseEvent->ignore();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Standard Qt UI events
|
||||
void ctkRangeSlider::mouseMoveEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
if (!d->m_SelectedHandles)
|
||||
{
|
||||
mouseEvent->ignore();
|
||||
return;
|
||||
}
|
||||
int mepos = this->orientation() == Qt::Horizontal ?
|
||||
mouseEvent->pos().x() : mouseEvent->pos().y();
|
||||
|
||||
QStyleOptionSlider option;
|
||||
this->initStyleOption(&option);
|
||||
|
||||
const int m = style()->pixelMetric( QStyle::PM_MaximumDragDistance, &option, this );
|
||||
|
||||
int newPosition = d->pixelPosToRangeValue(mepos - d->m_SubclassClickOffset);
|
||||
|
||||
if (m >= 0)
|
||||
{
|
||||
const QRect r = rect().adjusted(-m, -m, m, m);
|
||||
if (!r.contains(mouseEvent->pos()))
|
||||
{
|
||||
newPosition = d->m_SubclassPosition;
|
||||
}
|
||||
}
|
||||
|
||||
// Only the lower/left slider is down
|
||||
if (this->isMinimumSliderDown() && !this->isMaximumSliderDown())
|
||||
{
|
||||
double newMinPos = qMin(newPosition,d->m_MaximumPosition);
|
||||
this->setPositions(newMinPos, d->m_MaximumPosition +
|
||||
(d->m_SymmetricMoves ? d->m_MinimumPosition - newMinPos : 0));
|
||||
}
|
||||
// Only the upper/right slider is down
|
||||
else if (this->isMaximumSliderDown() && !this->isMinimumSliderDown())
|
||||
{
|
||||
double newMaxPos = qMax(d->m_MinimumPosition, newPosition);
|
||||
this->setPositions(d->m_MinimumPosition -
|
||||
(d->m_SymmetricMoves ? newMaxPos - d->m_MaximumPosition: 0),
|
||||
newMaxPos);
|
||||
}
|
||||
// Both handles are down (the user clicked in between the handles)
|
||||
else if (this->isMinimumSliderDown() && this->isMaximumSliderDown())
|
||||
{
|
||||
this->setPositions(newPosition - d->m_SubclassWidth,
|
||||
newPosition + d->m_SubclassWidth );
|
||||
}
|
||||
mouseEvent->accept();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Standard Qt UI mouseEvents
|
||||
void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
this->QSlider::mouseReleaseEvent(mouseEvent);
|
||||
|
||||
setSliderDown(false);
|
||||
d->m_SelectedHandles = 0;
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
this->QSlider::mouseDoubleClickEvent(mouseEvent);
|
||||
|
||||
// if the user-double clicked outside the current range, move the min or max
|
||||
// slider as appropriate.
|
||||
if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button()) ||
|
||||
this->isMinimumSliderDown() || this->isMaximumSliderDown())
|
||||
{
|
||||
mouseEvent->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
int mepos = this->orientation() == Qt::Horizontal ?
|
||||
mouseEvent->pos().x() : mouseEvent->pos().y();
|
||||
// convert pixel to data-value.
|
||||
mepos = d->pixelPosToRangeValue(mepos);
|
||||
if (mepos < d->m_MinimumPosition)
|
||||
{
|
||||
// move min.
|
||||
this->setPositions(mepos, d->m_MaximumPosition +
|
||||
(d->m_SymmetricMoves? d->m_MinimumPosition - mepos : 0));
|
||||
mouseEvent->accept();
|
||||
}
|
||||
else if (mepos > d->m_MaximumPosition)
|
||||
{
|
||||
// move max.
|
||||
this->setPositions(d->m_MinimumPosition -
|
||||
(d->m_SymmetricMoves ? mepos - d->m_MaximumPosition: 0), mepos);
|
||||
mouseEvent->accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseEvent->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
bool ctkRangeSlider::isMinimumSliderDown()const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_SelectedHandles & ctkRangeSliderPrivate::MinimumHandle;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
bool ctkRangeSlider::isMaximumSliderDown()const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_SelectedHandles & ctkRangeSliderPrivate::MaximumHandle;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const
|
||||
{
|
||||
this->initStyleOption(option);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider* option) const
|
||||
{
|
||||
this->initStyleOption(option);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
QString ctkRangeSlider::handleToolTip()const
|
||||
{
|
||||
Q_D(const ctkRangeSlider);
|
||||
return d->m_HandleToolTip;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ctkRangeSlider::setHandleToolTip(const QString& _toolTip)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
d->m_HandleToolTip = _toolTip;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
bool ctkRangeSlider::event(QEvent* _event)
|
||||
{
|
||||
Q_D(ctkRangeSlider);
|
||||
switch(_event->type())
|
||||
{
|
||||
case QEvent::ToolTip:
|
||||
{
|
||||
QHelpEvent* helpEvent = static_cast<QHelpEvent*>(_event);
|
||||
QStyleOptionSlider opt;
|
||||
// Test the MinimumHandle
|
||||
opt.sliderPosition = d->m_MinimumPosition;
|
||||
opt.sliderValue = d->m_MinimumValue;
|
||||
this->initStyleOption(&opt);
|
||||
QStyle::SubControl hoveredControl =
|
||||
this->style()->hitTestComplexControl(
|
||||
QStyle::CC_Slider, &opt, helpEvent->pos(), this);
|
||||
if (!d->m_HandleToolTip.isEmpty() &&
|
||||
hoveredControl == QStyle::SC_SliderHandle)
|
||||
{
|
||||
QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->minimumValue()));
|
||||
_event->accept();
|
||||
return true;
|
||||
}
|
||||
// Test the MaximumHandle
|
||||
opt.sliderPosition = d->m_MaximumPosition;
|
||||
opt.sliderValue = d->m_MaximumValue;
|
||||
this->initStyleOption(&opt);
|
||||
hoveredControl = this->style()->hitTestComplexControl(
|
||||
QStyle::CC_Slider, &opt, helpEvent->pos(), this);
|
||||
if (!d->m_HandleToolTip.isEmpty() &&
|
||||
hoveredControl == QStyle::SC_SliderHandle)
|
||||
{
|
||||
QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->maximumValue()));
|
||||
_event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return this->Superclass::event(_event);
|
||||
}
|
||||
Reference in New Issue
Block a user