• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 9273261865

28 May 2024 04:46PM UTC coverage: 32.005% (+0.001%) from 32.004%
9273261865

push

github

mcallegari
ui: update range slider against upstream code

6 of 20 new or added lines in 1 file covered. (30.0%)

1 existing line in 1 file now uncovered.

15401 of 48120 relevant lines covered (32.01%)

22984.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.78
/ui/src/ctkrangeslider.cpp
1
/*=========================================================================
2

3
  Library:   CTK
4

5
  Copyright (c) Kitware Inc.
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18

19
=========================================================================*/
20

21
// Qt includes
22
#include <QDebug>
23
#include <QMouseEvent>
24
#include <QKeyEvent>
25
#include <QStyleOptionSlider>
26
#include <QApplication>
27
#include <QStylePainter>
28
#include <QStyle>
29
#include <QToolTip>
30

31
// CTK includes
32
#include "ctkrangeslider.h"
33

34
class ctkRangeSliderPrivate
35
{
36
    Q_DECLARE_PUBLIC(ctkRangeSlider);
26✔
37
protected:
38
    ctkRangeSlider *const q_ptr;
39
public:
40
    /// Boolean indicates the selected handle
41
    ///   True for the minimum range handle, false for the maximum range handle
42
    enum Handle {
43
        NoHandle = 0x0,
44
        MinimumHandle = 0x1,
45
        MaximumHandle = 0x2
46
    };
47
    Q_DECLARE_FLAGS(Handles, Handle);
48

49
    ctkRangeSliderPrivate(ctkRangeSlider& object);
50
    void init();
51

52
    /// Return the handle at the given pos, or none if no handle is at the pos.
53
    /// If a handle is selected, handleRect is set to the handle rect.
54
    /// otherwise return NoHandle and handleRect is set to the combined rect of
55
    /// the min and max handles
56
    Handle handleAtPos(const QPoint& pos, QRect& handleRect)const;
57

58
    /// Copied verbatim from QSliderPrivate class (see QSlider.cpp)
59
    int pixelPosToRangeValue(int pos) const;
60
    int pixelPosFromRangeValue(int val) const;
61

62
    /// Draw the bottom and top sliders.
63
    void drawMinimumSlider(QStylePainter *painter) const;
64
    void drawMaximumSlider(QStylePainter *painter) const;
65

66
    /// End points of the range on the Model
67
    int m_MaximumValue;
68
    int m_MinimumValue;
69

70
    /// End points of the range on the GUI. This is synced with the model.
71
    int m_MaximumPosition;
72
    int m_MinimumPosition;
73

74
    /// Controls selected ?
75
    QStyle::SubControl m_MinimumSliderSelected;
76
    QStyle::SubControl m_MaximumSliderSelected;
77

78
    /// See QSliderPrivate::clickOffset.
79
    /// Overrides this ivar
80
    int m_SubclassClickOffset;
81

82
    /// See QSliderPrivate::position
83
    /// Overrides this ivar.
84
    int m_SubclassPosition;
85

86
    /// Original width between the 2 bounds before any moves
87
    float m_SubclassWidth;
88

89
    ctkRangeSliderPrivate::Handles m_SelectedHandles;
90

91
    /// When symmetricMoves is true, moving a handle will move the other handle
92
    /// symmetrically, otherwise the handles are independent.
93
    bool m_SymmetricMoves;
94

95
    QString m_HandleToolTip;
96

97
private:
98
    Q_DISABLE_COPY(ctkRangeSliderPrivate);
99
};
100

101
// --------------------------------------------------------------------------
102
ctkRangeSliderPrivate::ctkRangeSliderPrivate(ctkRangeSlider& object)
18✔
103
    : q_ptr(&object)
18✔
104
{
105
    this->m_MinimumValue = 0;
18✔
106
    this->m_MaximumValue = 100;
18✔
107
    this->m_MinimumPosition = 0;
18✔
108
    this->m_MaximumPosition = 100;
18✔
109
    this->m_MinimumSliderSelected = QStyle::SC_None;
18✔
110
    this->m_MaximumSliderSelected = QStyle::SC_None;
18✔
111
    this->m_SubclassClickOffset = 0;
18✔
112
    this->m_SubclassPosition = 0;
18✔
113
    this->m_SubclassWidth = 0.0;
18✔
114
    this->m_SelectedHandles = ctkRangeSliderPrivate::Handles();;
18✔
115
    this->m_SymmetricMoves = false;
18✔
116
}
18✔
117

118
// --------------------------------------------------------------------------
119
void ctkRangeSliderPrivate::init()
18✔
120
{
121
    Q_Q(ctkRangeSlider);
18✔
122
    this->m_MinimumValue = q->minimum();
18✔
123
    this->m_MaximumValue = q->maximum();
18✔
124
    this->m_MinimumPosition = q->minimum();
18✔
125
    this->m_MaximumPosition = q->maximum();
18✔
126
    q->connect(q, SIGNAL(rangeChanged(int,int)), q, SLOT(onRangeChanged(int,int)));
18✔
127
}
18✔
128

129
// --------------------------------------------------------------------------
130
ctkRangeSliderPrivate::Handle ctkRangeSliderPrivate::handleAtPos(const QPoint& pos, QRect& handleRect)const
×
131
{
132
    Q_Q(const ctkRangeSlider);
×
133

134
    QStyleOptionSlider option;
×
135
    q->initStyleOption(&option);
×
136

137
    // The functinos hitTestComplexControl only know about 1 handle. As we have
138
    // 2, we change the position of the handle and test if the pos correspond to
139
    // any of the 2 positions.
140

141
    // Test the MinimumHandle
142
    option.sliderPosition = this->m_MinimumPosition;
×
143
    option.sliderValue    = this->m_MinimumValue;
×
144

145
    QStyle::SubControl minimumControl = q->style()->hitTestComplexControl(QStyle::CC_Slider, &option, pos, q);
×
146
    QRect minimumHandleRect = q->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q);
×
147

148
    // Test if the pos is under the Maximum handle
149
    option.sliderPosition = this->m_MaximumPosition;
×
150
    option.sliderValue    = this->m_MaximumValue;
×
151

152
    QStyle::SubControl maximumControl = q->style()->hitTestComplexControl(QStyle::CC_Slider, &option, pos, q);
×
153
    QRect maximumHandleRect = q->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q);
×
154

155
    // The pos is above both handles, select the closest handle
156
    if (minimumControl == QStyle::SC_SliderHandle &&
×
157
        maximumControl == QStyle::SC_SliderHandle)
158
    {
159
        int minDist = 0;
×
160
        int maxDist = 0;
×
161
        if (q->orientation() == Qt::Horizontal)
×
162
        {
163
            minDist = pos.x() - minimumHandleRect.left();
×
164
            maxDist = maximumHandleRect.right() - pos.x();
×
165
        }
166
        else //if (q->orientation() == Qt::Vertical)
167
        {
168
            minDist = minimumHandleRect.bottom() - pos.y();
×
169
            maxDist = pos.y() - maximumHandleRect.top();
×
170
        }
171
        Q_ASSERT(minDist >= 0 && maxDist >= 0);
×
172
        minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None;
×
173
    }
174

175
    if (minimumControl == QStyle::SC_SliderHandle)
×
176
    {
177
        handleRect = minimumHandleRect;
×
178
        return MinimumHandle;
×
179
    }
180
    else if (maximumControl == QStyle::SC_SliderHandle)
×
181
    {
182
        handleRect = maximumHandleRect;
×
183
        return MaximumHandle;
×
184
    }
185
    handleRect = minimumHandleRect.united(maximumHandleRect);
×
186
    return NoHandle;
×
187
}
188

189
// --------------------------------------------------------------------------
190
// Copied verbatim from QSliderPrivate::pixelPosToRangeValue. See QSlider.cpp
191
//
192
int ctkRangeSliderPrivate::pixelPosToRangeValue(int pos) const
×
193
{
194
    Q_Q(const ctkRangeSlider);
×
195
    QStyleOptionSlider option;
×
196
    q->initStyleOption(&option);
×
197

198
    QRect gr = q->style()->subControlRect(QStyle::CC_Slider,
×
199
                                          &option,
200
                                          QStyle::SC_SliderGroove,
201
                                          q);
×
202
    QRect sr = q->style()->subControlRect(QStyle::CC_Slider,
×
203
                                          &option,
204
                                          QStyle::SC_SliderHandle,
205
                                          q);
×
206
    int sliderMin, sliderMax, sliderLength;
NEW
207
    if (option.orientation == Qt::Horizontal)
×
208
    {
NEW
209
        sliderLength = sr.width();
×
NEW
210
        sliderMin = gr.x();
×
NEW
211
        sliderMax = gr.right() - sliderLength + 1;
×
212
    }
213
    else
214
    {
NEW
215
        sliderLength = sr.height();
×
NEW
216
        sliderMin = gr.y();
×
NEW
217
        sliderMax = gr.bottom() - sliderLength + 1;
×
218
    }
219

NEW
220
    return QStyle::sliderValueFromPosition(q->minimum(),
×
221
                                           q->maximum(),
222
                                           pos - sliderMin,
223
                                           sliderMax - sliderMin,
NEW
224
                                           option.upsideDown);
×
225
}
226

227
//---------------------------------------------------------------------------
228
int ctkRangeSliderPrivate::pixelPosFromRangeValue(int val) const
×
229
{
230
    Q_Q(const ctkRangeSlider);
×
231
    QStyleOptionSlider option;
×
232
    q->initStyleOption(&option);
×
233

234
    QRect gr = q->style()->subControlRect(QStyle::CC_Slider,
×
235
                                          &option,
236
                                          QStyle::SC_SliderGroove,
237
                                          q);
×
238
    QRect sr = q->style()->subControlRect(QStyle::CC_Slider,
×
239
                                          &option,
240
                                          QStyle::SC_SliderHandle,
241
                                          q);
×
242
    int sliderMin, sliderMax, sliderLength;
243
    if (option.orientation == Qt::Horizontal)
×
244
    {
245
        sliderLength = sr.width();
×
246
        sliderMin = gr.x();
×
247
        sliderMax = gr.right() - sliderLength + 1;
×
248
    }
249
    else
250
    {
251
        sliderLength = sr.height();
×
252
        sliderMin = gr.y();
×
253
        sliderMax = gr.bottom() - sliderLength + 1;
×
254
    }
255

256
    return QStyle::sliderPositionFromValue(q->minimum(),
×
257
                                           q->maximum(),
258
                                           val,
259
                                           sliderMax - sliderMin,
260
                                           option.upsideDown) + sliderMin;
×
261
}
262

263
//---------------------------------------------------------------------------
264
// Draw slider at the bottom end of the range
265
void ctkRangeSliderPrivate::drawMinimumSlider(QStylePainter *painter) const
4✔
266
{
267
    Q_Q(const ctkRangeSlider);
4✔
268
    QStyleOptionSlider option;
8✔
269
    q->initMinimumSliderStyleOption(&option);
4✔
270

271
    option.subControls = QStyle::SC_SliderHandle;
4✔
272
    option.sliderValue = m_MinimumValue;
4✔
273
    option.sliderPosition = m_MinimumPosition;
4✔
274
    if (q->isMinimumSliderDown())
4✔
275
    {
276
        option.activeSubControls = QStyle::SC_SliderHandle;
×
277
        option.state |= QStyle::State_Sunken;
×
278
    }
279
#ifdef Q_OS_MAC
280
    // On mac style, drawing just the handle actually draws also the groove.
281
    QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
282
                                            QStyle::SC_SliderHandle, q);
283
    painter->setClipRect(clip);
284
#endif
285
    painter->drawComplexControl(QStyle::CC_Slider, option);
4✔
286
}
4✔
287

288
//---------------------------------------------------------------------------
289
// Draw slider at the top end of the range
290
void ctkRangeSliderPrivate::drawMaximumSlider(QStylePainter *painter) const
4✔
291
{
292
    Q_Q(const ctkRangeSlider);
4✔
293
    QStyleOptionSlider option;
8✔
294
    q->initMaximumSliderStyleOption(&option);
4✔
295

296
    option.subControls = QStyle::SC_SliderHandle;
4✔
297
    option.sliderValue = m_MaximumValue;
4✔
298
    option.sliderPosition = m_MaximumPosition;
4✔
299
    if (q->isMaximumSliderDown())
4✔
300
    {
301
        option.activeSubControls = QStyle::SC_SliderHandle;
×
302
        option.state |= QStyle::State_Sunken;
×
303
    }
304
#ifdef Q_OS_MAC
305
    // On mac style, drawing just the handle actually draws also the groove.
306
    QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
307
                                            QStyle::SC_SliderHandle, q);
308
    painter->setClipRect(clip);
309
#endif
310
    painter->drawComplexControl(QStyle::CC_Slider, option);
4✔
311
}
4✔
312

313
// --------------------------------------------------------------------------
314
ctkRangeSlider::ctkRangeSlider(QWidget *_parent)
9✔
315
    : QSlider(_parent)
316
    , d_ptr(new ctkRangeSliderPrivate(*this))
9✔
317
{
318
    Q_D(ctkRangeSlider);
9✔
319
    d->init();
9✔
320
}
9✔
321

322
// --------------------------------------------------------------------------
323
ctkRangeSlider::ctkRangeSlider(Qt::Orientation o,
9✔
324
                               QWidget *parentObject)
9✔
325
    : QSlider(o, parentObject)
326
    , d_ptr(new ctkRangeSliderPrivate(*this))
9✔
327
{
328
    Q_D(ctkRangeSlider);
9✔
329
    d->init();
9✔
330
}
9✔
331

332
// --------------------------------------------------------------------------
333
ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate *impl, QWidget *_parent)
×
334
    : QSlider(_parent)
335
    , d_ptr(impl)
×
336
{
337
    Q_D(ctkRangeSlider);
×
338
    d->init();
×
339
}
×
340

341
// --------------------------------------------------------------------------
342
ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate *impl, Qt::Orientation o,
×
343
                               QWidget *parentObject)
×
344
    : QSlider(o, parentObject)
345
    , d_ptr(impl)
×
346
{
347
    Q_D(ctkRangeSlider);
×
348
    d->init();
×
349
}
×
350

351
// --------------------------------------------------------------------------
352
ctkRangeSlider::~ctkRangeSlider()
36✔
353
{
354
}
36✔
355

356
// --------------------------------------------------------------------------
357
int ctkRangeSlider::minimumValue() const
×
358
{
359
    Q_D(const ctkRangeSlider);
×
360
    return d->m_MinimumValue;
×
361
}
362

363
// --------------------------------------------------------------------------
364
void ctkRangeSlider::setMinimumValue(int min)
×
365
{
366
    Q_D(ctkRangeSlider);
×
367
    this->setValues(min, qMax(d->m_MaximumValue,min));
×
368
}
×
369

370
// --------------------------------------------------------------------------
371
int ctkRangeSlider::maximumValue() const
×
372
{
373
    Q_D(const ctkRangeSlider);
×
374
    return d->m_MaximumValue;
×
375
}
376

377
// --------------------------------------------------------------------------
378
void ctkRangeSlider::setMaximumValue(int max)
×
379
{
380
    Q_D(ctkRangeSlider);
×
381
    this->setValues(qMin(d->m_MinimumValue, max), max);
×
382
}
×
383

384
// --------------------------------------------------------------------------
385
void ctkRangeSlider::setValues(int l, int u)
36✔
386
{
387
    Q_D(ctkRangeSlider);
36✔
388
    const int minValue = qBound(this->minimum(), qMin(l,u), this->maximum());
36✔
389
    const int maxValue = qBound(this->minimum(), qMax(l,u), this->maximum());
36✔
390
    bool emitMinValChanged = (minValue != d->m_MinimumValue);
36✔
391
    bool emitMaxValChanged = (maxValue != d->m_MaximumValue);
36✔
392

393
    d->m_MinimumValue = minValue;
36✔
394
    d->m_MaximumValue = maxValue;
36✔
395

396
    bool emitMinPosChanged = (minValue != d->m_MinimumPosition);
36✔
397
    bool emitMaxPosChanged = (maxValue != d->m_MaximumPosition);
36✔
398
    d->m_MinimumPosition = minValue;
36✔
399
    d->m_MaximumPosition = maxValue;
36✔
400

401
    if (isSliderDown())
36✔
402
    {
403
        if (emitMinPosChanged || emitMaxPosChanged)
×
404
        {
405
            emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
×
406
        }
407
        if (emitMinPosChanged)
×
408
        {
409
            emit minimumPositionChanged(d->m_MinimumPosition);
×
410
        }
411
        if (emitMaxPosChanged)
×
412
        {
413
            emit maximumPositionChanged(d->m_MaximumPosition);
×
414
        }
415
    }
416
    if (emitMinValChanged || emitMaxValChanged)
36✔
417
    {
418
        emit valuesChanged(d->m_MinimumValue, d->m_MaximumValue);
18✔
419
    }
420
    if (emitMinValChanged)
36✔
421
    {
422
        emit minimumValueChanged(d->m_MinimumValue);
×
423
    }
424
    if (emitMaxValChanged)
36✔
425
    {
426
        emit maximumValueChanged(d->m_MaximumValue);
18✔
427
    }
428
    if (emitMinPosChanged || emitMaxPosChanged ||
36✔
429
        emitMinValChanged || emitMaxValChanged)
36✔
430
    {
431
        this->update();
18✔
432
    }
433
}
36✔
434

435
// --------------------------------------------------------------------------
436
int ctkRangeSlider::minimumPosition() const
2✔
437
{
438
    Q_D(const ctkRangeSlider);
2✔
439
    return d->m_MinimumPosition;
2✔
440
}
441

442
// --------------------------------------------------------------------------
443
int ctkRangeSlider::maximumPosition() const
2✔
444
{
445
    Q_D(const ctkRangeSlider);
2✔
446
    return d->m_MaximumPosition;
2✔
447
}
448

449
// --------------------------------------------------------------------------
450
void ctkRangeSlider::setMinimumPosition(int l)
×
451
{
452
    Q_D(const ctkRangeSlider);
×
453
    this->setPositions(l, qMax(l, d->m_MaximumPosition));
×
454
}
×
455

456
// --------------------------------------------------------------------------
457
void ctkRangeSlider::setMaximumPosition(int u)
18✔
458
{
459
    Q_D(const ctkRangeSlider);
18✔
460
    this->setPositions(qMin(d->m_MinimumPosition, u), u);
18✔
461
}
18✔
462

463
// --------------------------------------------------------------------------
464
void ctkRangeSlider::setPositions(int min, int max)
18✔
465
{
466
    Q_D(ctkRangeSlider);
18✔
467
    const int minPosition = qBound(this->minimum(), qMin(min, max), this->maximum());
18✔
468
    const int maxPosition = qBound(this->minimum(), qMax(min, max), this->maximum());
18✔
469

470
    bool emitMinPosChanged = (minPosition != d->m_MinimumPosition);
18✔
471
    bool emitMaxPosChanged = (maxPosition != d->m_MaximumPosition);
18✔
472

473
    if (!emitMinPosChanged && !emitMaxPosChanged)
18✔
474
    {
475
        return;
×
476
    }
477

478
    d->m_MinimumPosition = minPosition;
18✔
479
    d->m_MaximumPosition = maxPosition;
18✔
480

481
    if (!this->hasTracking())
18✔
482
    {
483
        this->update();
×
484
    }
485
    if (isSliderDown())
18✔
486
    {
487
        if (emitMinPosChanged)
×
488
        {
489
            emit minimumPositionChanged(d->m_MinimumPosition);
×
490
        }
491
        if (emitMaxPosChanged)
×
492
        {
493
            emit maximumPositionChanged(d->m_MaximumPosition);
×
494
        }
495
        if (emitMinPosChanged || emitMaxPosChanged)
×
496
        {
497
            emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
×
498
        }
499
    }
500
    if (this->hasTracking())
18✔
501
    {
502
        this->triggerAction(SliderMove);
18✔
503
        this->setValues(d->m_MinimumPosition, d->m_MaximumPosition);
18✔
504
    }
505
}
506

507
// --------------------------------------------------------------------------
508
void ctkRangeSlider::setSymmetricMoves(bool symmetry)
×
509
{
510
    Q_D(ctkRangeSlider);
×
511
    d->m_SymmetricMoves = symmetry;
×
512
}
×
513

514
// --------------------------------------------------------------------------
515
bool ctkRangeSlider::symmetricMoves()const
×
516
{
517
    Q_D(const ctkRangeSlider);
×
518
    return d->m_SymmetricMoves;
×
519
}
520

521
// --------------------------------------------------------------------------
522
void ctkRangeSlider::onRangeChanged(int _minimum, int _maximum)
18✔
523
{
524
    Q_UNUSED(_minimum);
525
    Q_UNUSED(_maximum);
526
    Q_D(ctkRangeSlider);
18✔
527
    this->setValues(d->m_MinimumValue, d->m_MaximumValue);
18✔
528
}
18✔
529

530
// --------------------------------------------------------------------------
531
// Render
532
void ctkRangeSlider::paintEvent(QPaintEvent *)
4✔
533
{
534
    Q_D(ctkRangeSlider);
4✔
535
    QStyleOptionSlider option;
8✔
536
    this->initStyleOption(&option);
4✔
537

538
    QStylePainter painter(this);
8✔
539
    option.subControls = QStyle::SC_SliderGroove;
4✔
540
    // Move to minimum to not highlight the SliderGroove.
541
    // On mac style, drawing just the slider groove also draws the handles,
542
    // therefore we give a negative (outside of view) position.
543
    option.sliderValue = this->minimum() - this->maximum();
4✔
544
    option.sliderPosition = this->minimum() - this->maximum();
4✔
545
    painter.drawComplexControl(QStyle::CC_Slider, option);
4✔
546

547
    option.sliderPosition = d->m_MinimumPosition;
4✔
548
    const QRect lr = style()->subControlRect(QStyle::CC_Slider,
4✔
549
                                             &option,
550
                                             QStyle::SC_SliderHandle,
551
                                             this);
4✔
552
    option.sliderPosition = d->m_MaximumPosition;
4✔
553

554
    const QRect ur = style()->subControlRect(QStyle::CC_Slider,
4✔
555
                                             &option,
556
                                             QStyle::SC_SliderHandle,
557
                                             this);
4✔
558

559
    QRect sr = style()->subControlRect(QStyle::CC_Slider,
4✔
560
                                       &option,
561
                                       QStyle::SC_SliderGroove,
562
                                       this);
4✔
563
    QRect rangeBox;
4✔
564
    if (option.orientation == Qt::Horizontal)
4✔
565
    {
566
        rangeBox = QRect(
2✔
567
            QPoint(qMin(lr.center().x(), ur.center().x()), sr.center().y() - 2),
2✔
568
            QPoint(qMax(lr.center().x(), ur.center().x()), sr.center().y() + 1));
4✔
569
    }
570
    else
571
    {
572
        rangeBox = QRect(
2✔
573
            QPoint(sr.center().x() - 2, qMin(lr.center().y(), ur.center().y())),
2✔
574
            QPoint(sr.center().x() + 1, qMax(lr.center().y(), ur.center().y())));
4✔
575
    }
576

577
    // -----------------------------
578
    // Render the range
579
    //
580
    QRect groove = this->style()->subControlRect(QStyle::CC_Slider,
4✔
581
                                                 &option,
582
                                                 QStyle::SC_SliderGroove,
583
                                                 this);
4✔
584
    groove.adjust(0, 0, -1, 0);
4✔
585

586
    // Create default colors based on the transfer function.
587
    //
588
    QColor highlight = this->palette().color(QPalette::Highlight);
4✔
589
    QLinearGradient gradient;
8✔
590
    if (option.orientation == Qt::Horizontal)
4✔
591
    {
592
        gradient = QLinearGradient(groove.center().x(), groove.top(),
4✔
593
                                   groove.center().x(), groove.bottom());
6✔
594
    }
595
    else
596
    {
597
        gradient = QLinearGradient(groove.left(), groove.center().y(),
4✔
598
                                   groove.right(), groove.center().y());
6✔
599
    }
600

601
    // TODO: Set this based on the supplied transfer function
602
    //QColor l = Qt::darkGray;
603
    //QColor u = Qt::black;
604

605
    // Like Fusion Style to match QSlider
606
    gradient.setColorAt(0, highlight.darker(120));
4✔
607
    gradient.setColorAt(1, highlight.lighter(160));
4✔
608

609
    painter.setPen(QPen(highlight.darker(150), 0));
4✔
610
    painter.setBrush(gradient);
4✔
611
    painter.drawRect(rangeBox.intersected(groove));
4✔
612

613
    //  -----------------------------------
614
    // Render the sliders
615
    //
616
    if (this->isMinimumSliderDown())
4✔
617
    {
NEW
618
        painter.setClipRect(ur);
×
619
        d->drawMaximumSlider(&painter);
×
NEW
620
        painter.setClipRect(lr);
×
UNCOV
621
        d->drawMinimumSlider(&painter);
×
622
    }
623
    else
624
    {
625
        painter.setClipRect(lr);
4✔
626
        d->drawMinimumSlider(&painter);
4✔
627
        painter.setClipRect(ur);
4✔
628
        d->drawMaximumSlider(&painter);
4✔
629
    }
630
}
4✔
631

632
// --------------------------------------------------------------------------
633
// Standard Qt UI events
634
void ctkRangeSlider::mousePressEvent(QMouseEvent* mouseEvent)
×
635
{
636
    Q_D(ctkRangeSlider);
×
637
    if (minimum() == maximum() || (mouseEvent->buttons() ^ mouseEvent->button()))
×
638
    {
639
        mouseEvent->ignore();
×
640
        return;
×
641
    }
642
    int mepos = this->orientation() == Qt::Horizontal ?
×
643
                    mouseEvent->pos().x() : mouseEvent->pos().y();
×
644

645
    QStyleOptionSlider option;
×
646
    this->initStyleOption(&option);
×
647

648
    QRect handleRect;
×
649
    ctkRangeSliderPrivate::Handle handle_ = d->handleAtPos(mouseEvent->pos(), handleRect);
×
650

651
    if (handle_ != ctkRangeSliderPrivate::NoHandle)
×
652
    {
653
        d->m_SubclassPosition = (handle_ == ctkRangeSliderPrivate::MinimumHandle) ?
×
654
                                    d->m_MinimumPosition : d->m_MaximumPosition;
655

656
        // save the position of the mouse inside the handle for later
657
        d->m_SubclassClickOffset = mepos - (this->orientation() == Qt::Horizontal ?
×
658
                                                handleRect.left() : handleRect.top());
×
659

660
        this->setSliderDown(true);
×
661

662
        if (d->m_SelectedHandles != handle_)
×
663
        {
664
            d->m_SelectedHandles = handle_;
×
665
            this->update(handleRect);
×
666
        }
667
        // Accept the mouseEvent
668
        mouseEvent->accept();
×
669
        return;
×
670
    }
671

672
    // if we are here, no handles have been pressed
673
    // Check if we pressed on the groove between the 2 handles
674

675
    QStyle::SubControl control = this->style()->hitTestComplexControl(QStyle::CC_Slider, &option, mouseEvent->pos(), this);
×
676
    QRect sr = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this);
×
677
    int minCenter = (this->orientation() == Qt::Horizontal ?
×
678
                         handleRect.left() : handleRect.top());
×
679
    int maxCenter = (this->orientation() == Qt::Horizontal ?
×
680
                         handleRect.right() : handleRect.bottom());
×
681
    if (control == QStyle::SC_SliderGroove &&
×
682
        mepos > minCenter && mepos < maxCenter)
×
683
    {
684
        // warning lost of precision it might be fatal
685
        d->m_SubclassPosition = (d->m_MinimumPosition + d->m_MaximumPosition) / 2.;
×
686
        d->m_SubclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_SubclassPosition);
×
687
        d->m_SubclassWidth = (d->m_MaximumPosition - d->m_MinimumPosition) / 2;
×
688
        qMax(d->m_SubclassPosition - d->m_MinimumPosition, d->m_MaximumPosition - d->m_SubclassPosition);
×
689
        this->setSliderDown(true);
×
690
        if (!this->isMinimumSliderDown() || !this->isMaximumSliderDown())
×
691
        {
692
            d->m_SelectedHandles =
693
                QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MinimumHandle) |
×
694
                QFlags<ctkRangeSliderPrivate::Handle>(ctkRangeSliderPrivate::MaximumHandle);
×
695
            this->update(handleRect.united(sr));
×
696
        }
697
        mouseEvent->accept();
×
698
        return;
×
699
    }
700
    mouseEvent->ignore();
×
701
}
702

703
// --------------------------------------------------------------------------
704
// Standard Qt UI events
705
void ctkRangeSlider::mouseMoveEvent(QMouseEvent* mouseEvent)
×
706
{
707
    Q_D(ctkRangeSlider);
×
708
    if (!d->m_SelectedHandles)
×
709
    {
710
        mouseEvent->ignore();
×
711
        return;
×
712
    }
713
    int mepos = this->orientation() == Qt::Horizontal ?
×
714
                    mouseEvent->pos().x() : mouseEvent->pos().y();
×
715

716
    QStyleOptionSlider option;
×
717
    this->initStyleOption(&option);
×
718

719
    const int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &option, this);
×
720

721
    int newPosition = d->pixelPosToRangeValue(mepos - d->m_SubclassClickOffset);
×
722

723
    if (m >= 0)
×
724
    {
725
        const QRect r = rect().adjusted(-m, -m, m, m);
×
726
        if (!r.contains(mouseEvent->pos()))
×
727
        {
728
            newPosition = d->m_SubclassPosition;
×
729
        }
730
    }
731

732
    // Only the lower/left slider is down
733
    if (this->isMinimumSliderDown() && !this->isMaximumSliderDown())
×
734
    {
735
        double newMinPos = qMin(newPosition,d->m_MaximumPosition);
×
736
        this->setPositions(newMinPos, d->m_MaximumPosition +
×
737
                                          (d->m_SymmetricMoves ? d->m_MinimumPosition - newMinPos : 0));
×
738
    }
739
    // Only the upper/right slider is down
740
    else if (this->isMaximumSliderDown() && !this->isMinimumSliderDown())
×
741
    {
742
        double newMaxPos = qMax(d->m_MinimumPosition, newPosition);
×
743
        this->setPositions(d->m_MinimumPosition -
×
744
                           (d->m_SymmetricMoves ? newMaxPos - d->m_MaximumPosition: 0),
×
745
                           newMaxPos);
746
    }
747
    // Both handles are down (the user clicked in between the handles)
748
    else if (this->isMinimumSliderDown() && this->isMaximumSliderDown())
×
749
    {
NEW
750
        this->setPositions(newPosition - static_cast<int>(d->m_SubclassWidth),
×
NEW
751
                           newPosition + static_cast<int>(d->m_SubclassWidth + .5));
×
752
    }
753
    mouseEvent->accept();
×
754
}
755

756
// --------------------------------------------------------------------------
757
// Standard Qt UI mouseEvents
758
void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent)
×
759
{
760
    Q_D(ctkRangeSlider);
×
761
    this->QSlider::mouseReleaseEvent(mouseEvent);
×
762

763
    setSliderDown(false);
×
NEW
764
    d->m_SelectedHandles = ctkRangeSliderPrivate::Handles();
×
765

766
    this->update();
×
767
}
×
768

769
// --------------------------------------------------------------------------
770
bool ctkRangeSlider::isMinimumSliderDown()const
8✔
771
{
772
    Q_D(const ctkRangeSlider);
8✔
773
    return d->m_SelectedHandles & ctkRangeSliderPrivate::MinimumHandle;
8✔
774
}
775

776
// --------------------------------------------------------------------------
777
bool ctkRangeSlider::isMaximumSliderDown()const
4✔
778
{
779
    Q_D(const ctkRangeSlider);
4✔
780
    return d->m_SelectedHandles & ctkRangeSliderPrivate::MaximumHandle;
4✔
781
}
782

783
// --------------------------------------------------------------------------
784
void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const
4✔
785
{
786
    this->initStyleOption(option);
4✔
787
}
4✔
788

789
// --------------------------------------------------------------------------
790
void ctkRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider* option) const
4✔
791
{
792
    this->initStyleOption(option);
4✔
793
}
4✔
794

795
// --------------------------------------------------------------------------
796
QString ctkRangeSlider::handleToolTip()const
×
797
{
798
    Q_D(const ctkRangeSlider);
×
799
    return d->m_HandleToolTip;
×
800
}
801

802
// --------------------------------------------------------------------------
803
void ctkRangeSlider::setHandleToolTip(const QString& _toolTip)
×
804
{
805
    Q_D(ctkRangeSlider);
×
806
    d->m_HandleToolTip = _toolTip;
×
807
}
×
808

809
// --------------------------------------------------------------------------
810
bool ctkRangeSlider::event(QEvent* _event)
50✔
811
{
812
    Q_D(ctkRangeSlider);
50✔
813
    switch(_event->type())
50✔
814
    {
815
    case QEvent::ToolTip:
×
816
    {
817
        QHelpEvent* helpEvent = static_cast<QHelpEvent*>(_event);
×
818
        QStyleOptionSlider opt;
×
819
        // Test the MinimumHandle
820
        opt.sliderPosition = d->m_MinimumPosition;
×
821
        opt.sliderValue = d->m_MinimumValue;
×
822
        this->initStyleOption(&opt);
×
823
        QStyle::SubControl hoveredControl =
824
            this->style()->hitTestComplexControl(
×
825
                QStyle::CC_Slider, &opt, helpEvent->pos(), this);
×
826
        if (!d->m_HandleToolTip.isEmpty() &&
×
827
            hoveredControl == QStyle::SC_SliderHandle)
828
        {
829
            QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->minimumValue()));
×
830
            _event->accept();
×
831
            return true;
×
832
        }
833
        // Test the MaximumHandle
834
        opt.sliderPosition = d->m_MaximumPosition;
×
835
        opt.sliderValue = d->m_MaximumValue;
×
836
        this->initStyleOption(&opt);
×
837
        hoveredControl = this->style()->hitTestComplexControl(
×
838
            QStyle::CC_Slider, &opt, helpEvent->pos(), this);
×
839
        if (!d->m_HandleToolTip.isEmpty() &&
×
840
            hoveredControl == QStyle::SC_SliderHandle)
841
        {
842
            QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->maximumValue()));
×
843
            _event->accept();
×
844
            return true;
×
845
        }
846
    }
847
    default:
848
        break;
50✔
849
    }
850
    return this->Superclass::event(_event);
50✔
851
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc