32#include <QPainterPath>
38 QVBoxLayout *vl =
new QVBoxLayout();
39 vl->setContentsMargins( 0, 0, 0, 0 );
41 mConfigureButton =
new QToolButton();
42 mConfigureButton->setPopupMode( QToolButton::InstantPopup );
44 QHBoxLayout *hl =
new QHBoxLayout();
45 hl->setContentsMargins( 0, 0, 0, 0 );
46 hl->addWidget( mConfigureButton );
49 mMenu =
new QMenu(
this );
50 mConfigureButton->setMenu( mMenu );
52 QgsElevationControllerSettingsAction *settingsAction =
new QgsElevationControllerSettingsAction( mMenu );
53 mMenu->addAction( settingsAction );
55 settingsAction->sizeSpin()->clear();
56 connect( settingsAction->sizeSpin(), qOverload< double >( &QgsDoubleSpinBox::valueChanged ),
this, [
this](
double size )
58 setFixedRangeSize( size < 0 ? -1 : size );
61 mMenu->addSeparator();
66 mSliderLabels =
new QgsElevationControllerLabels();
68 QHBoxLayout *hlSlider =
new QHBoxLayout();
69 hlSlider->setContentsMargins( 0, 0, 0, 0 );
70 hlSlider->setSpacing( 2 );
71 hlSlider->addWidget( mSlider );
72 hlSlider->addWidget( mSliderLabels, 1 );
73 hlSlider->addStretch();
74 vl->addLayout( hlSlider );
76 setCursor( Qt::ArrowCursor );
92 if ( mBlockSliderChanges )
96 mSliderLabels->setRange(
range() );
106 QWidget::resizeEvent( event );
113 const int snappedLower =
static_cast< int >( std::floor( mCurrentRange.
lower() * mSliderPrecision ) );
114 const int snappedUpper =
static_cast< int >( std::ceil( mCurrentRange.
upper() * mSliderPrecision ) );
116 return mCurrentRange;
119 if ( mFixedRangeSize >= 0 )
123 if ( sliderRange.
upper() + mFixedRangeSize <= mRangeLimits.
upper() )
151 if (
range == mCurrentRange )
154 mCurrentRange =
range;
155 mBlockSliderChanges =
true;
156 mSlider->
setRange(
static_cast< int >( std::floor(
range.
lower() * mSliderPrecision ) ),
157 static_cast< int >( std::ceil(
range.
upper() * mSliderPrecision ) ) );
158 mBlockSliderChanges =
false;
161 mSliderLabels->setRange( mCurrentRange );
169 mRangeLimits = limits;
171 const double limitRange = limits.
upper() - limits.
lower();
174 mSliderPrecision = std::max( 1000, mSlider->height() ) / limitRange;
176 mBlockSliderChanges =
true;
177 mSlider->
setRangeLimits(
static_cast< int >( std::floor( limits.
lower() * mSliderPrecision ) ),
178 static_cast< int >( std::ceil( limits.
upper() * mSliderPrecision ) ) );
181 const double newCurrentLower = std::max( mCurrentRange.
lower(), limits.
lower() );
182 const double newCurrentUpper = std::min( mCurrentRange.
upper(), limits.
upper() );
183 const bool rangeHasChanged = newCurrentLower != mCurrentRange.
lower() || newCurrentUpper != mCurrentRange.
upper();
185 mSlider->
setRange(
static_cast< int >( std::floor( newCurrentLower * mSliderPrecision ) ),
186 static_cast< int >( std::ceil( newCurrentUpper * mSliderPrecision ) ) );
187 mCurrentRange =
QgsDoubleRange( newCurrentLower, newCurrentUpper );
188 mBlockSliderChanges =
false;
189 if ( rangeHasChanged )
192 mSliderLabels->setLimits( mRangeLimits );
195void QgsElevationControllerWidget::updateWidgetMask()
203 QRegion reg( frameGeometry() );
204 reg -= QRegion( geometry() );
205 reg += childrenRegion();
211 return mFixedRangeSize;
216 if ( size == mFixedRangeSize )
219 mFixedRangeSize = size;
220 if ( mFixedRangeSize < 0 )
226 mSlider->
setFixedRangeSize(
static_cast< int >( std::round( mFixedRangeSize * mSliderPrecision ) ) );
234QgsElevationControllerLabels::QgsElevationControllerLabels( QWidget *parent )
238 QFont smallerFont = font();
239 int fontSize = smallerFont.pointSize();
241 fontSize = std::max( fontSize - 1, 8 );
243 fontSize = std::max( fontSize - 2, 7 );
245 smallerFont.setPointSize( fontSize );
246 setFont( smallerFont );
248 const QFontMetrics fm( smallerFont );
249 setMinimumWidth( fm.horizontalAdvance(
'0' ) * 5 );
250 setAttribute( Qt::WA_TransparentForMouseEvents );
253void QgsElevationControllerLabels::paintEvent( QPaintEvent * )
255 QStyleOptionSlider styleOption;
256 styleOption.initFrom(
this );
258 const QRect sliderRect = style()->subControlRect( QStyle::CC_Slider, &styleOption, QStyle::SC_SliderHandle,
this );
259 const int sliderHeight = sliderRect.height();
262 const QFontMetrics fm( f );
264 const int left = rect().left() + 2;
266 const double limitRange = mLimits.upper() - mLimits.lower();
267 const double lowerFraction = ( mRange.lower() - mLimits.lower() ) / limitRange;
268 const double upperFraction = ( mRange.upper() - mLimits.lower() ) / limitRange;
269 const int lowerY = std::min(
static_cast< int >( std::round( rect().bottom() - sliderHeight * 0.5 - ( rect().height() - sliderHeight ) * lowerFraction + fm.ascent() ) ),
270 rect().bottom() - fm.descent() );
271 const int upperY = std::max(
static_cast< int >( std::round( rect().bottom() - sliderHeight * 0.5 - ( rect().height() - sliderHeight ) * upperFraction - fm.descent() ) ),
272 rect().top() + fm.ascent() );
274 const bool lowerIsCloseToLimit = lowerY + fm.height() > rect().bottom() - fm.descent();
275 const bool upperIsCloseToLimit = upperY - fm.height() < rect().top() + fm.ascent();
276 const bool lowerIsCloseToUpperLimit = lowerY - fm.height() < rect().top() + fm.ascent();
281 if ( mLimits.lower() > std::numeric_limits< double >::lowest() )
283 if ( lowerIsCloseToLimit )
286 path.addText( left, lowerY, f, locale.toString( mRange.lower() ) );
291 path.addText( left, lowerY, f, locale.toString( mRange.lower() ) );
293 path.addText( left, rect().bottom() - fm.descent(), f, locale.toString( mLimits.lower() ) );
297 if ( mLimits.upper() < std::numeric_limits< double >::max() )
301 if ( !lowerIsCloseToUpperLimit )
304 path.addText( left, rect().top() + fm.ascent(), f, locale.toString( mLimits.upper() ) );
309 if ( upperIsCloseToLimit )
312 path.addText( left, upperY, f, locale.toString( mRange.upper() ) );
317 path.addText( left, upperY, f, locale.toString( mRange.upper() ) );
319 path.addText( left, rect().top() + fm.ascent(), f, locale.toString( mLimits.upper() ) );
325 p.setRenderHint( QPainter::Antialiasing,
true );
326 const QColor bufferColor = palette().color( QPalette::Window );
327 const QColor textColor = palette().color( QPalette::WindowText );
328 QPen pen( bufferColor );
329 pen.setJoinStyle( Qt::RoundJoin );
330 pen.setCapStyle( Qt::RoundCap );
333 p.setBrush( Qt::NoBrush );
335 p.setPen( Qt::NoPen );
336 p.setBrush( QBrush( textColor ) );
341void QgsElevationControllerLabels::setLimits(
const QgsDoubleRange &limits )
343 if ( limits == mLimits )
346 const QFontMetrics fm( font() );
347 const int maxChars = std::max( QLocale().toString( std::floor( limits.
lower() ) ).length(),
348 QLocale().toString( std::floor( limits.
upper() ) ).length() ) + 3;
349 setMinimumWidth( fm.horizontalAdvance(
'0' ) * maxChars );
355void QgsElevationControllerLabels::setRange(
const QgsDoubleRange &range )
357 if ( range == mRange )
368QgsElevationControllerSettingsAction::QgsElevationControllerSettingsAction( QWidget *parent )
369 : QWidgetAction( parent )
371 QGridLayout *gLayout =
new QGridLayout();
372 gLayout->setContentsMargins( 3, 2, 3, 2 );
374 QLabel *label =
new QLabel( tr(
"Fixed Range Size" ) );
375 gLayout->addWidget( label, 0, 0 );
378 mSizeSpin->setDecimals( 4 );
379 mSizeSpin->setMinimum( -1.0 );
380 mSizeSpin->setMaximum( 999999999.0 );
381 mSizeSpin->setClearValue( -1, tr(
"Not set" ) );
382 mSizeSpin->setKeyboardTracking(
false );
383 mSizeSpin->setToolTip( tr(
"Limit elevation range to a fixed size" ) );
385 gLayout->addWidget( mSizeSpin, 0, 1 );
387 QWidget *w =
new QWidget();
388 w->setLayout( gLayout );
389 setDefaultWidget( w );
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
QgsRange which stores a range of double values.
bool isInfinite() const
Returns true if the range consists of all possible values.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
QgsDoubleRange elevationRange() const
Returns the project's elevation range, which indicates the upper and lower elevation limits associate...
void elevationRangeChanged(const QgsDoubleRange &range)
Emitted when the project's elevation is changed.
static QgsProject * instance()
Returns the QgsProject singleton instance.
const QgsProjectElevationProperties * elevationProperties() const
Returns the project's elevation properties, which contains the project's elevation related settings.
A slider control with two interactive endpoints, for interactive selection of a range of values.
void setRangeLimits(int minimum, int maximum)
Sets the minimum and maximum range limits for values allowed in the widget.
int upperValue() const
Returns the upper value for the range selected in the widget.
void rangeChanged(int minimum, int maximum)
Emitted when the range selected in the widget is changed.
void setFlippedDirection(bool flipped)
Sets whether the slider has its values flipped.
void setRange(int lower, int upper)
Sets the current range selected in the widget.
int lowerValue() const
Returns the lower value for the range selected in the widget.
void setFixedRangeSize(int size)
Sets the slider's fixed range size.
T lower() const
Returns the lower bound of the range.
T upper() const
Returns the upper bound of the range.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)