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

mcallegari / qlcplus / 7252848206

18 Dec 2023 07:26PM UTC coverage: 32.067% (+0.001%) from 32.066%
7252848206

push

github

mcallegari
Code style review #1427

199 of 628 new or added lines in 101 files covered. (31.69%)

8 existing lines in 2 files now uncovered.

15169 of 47304 relevant lines covered (32.07%)

23733.74 hits per line

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

42.71
/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
    int 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;
18✔
114
    this->m_SelectedHandles = NoHandle;
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
{
NEW
132
    Q_Q(const ctkRangeSlider);
×
133

NEW
134
    QStyleOptionSlider option;
×
NEW
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
NEW
142
    option.sliderPosition = this->m_MinimumPosition;
×
NEW
143
    option.sliderValue    = this->m_MinimumValue;
×
144

NEW
145
    QStyle::SubControl minimumControl = q->style()->hitTestComplexControl(QStyle::CC_Slider, &option, pos, q);
×
NEW
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
NEW
149
    option.sliderPosition = this->m_MaximumPosition;
×
NEW
150
    option.sliderValue    = this->m_MaximumValue;
×
151

NEW
152
    QStyle::SubControl maximumControl = q->style()->hitTestComplexControl(QStyle::CC_Slider, &option, pos, q);
×
NEW
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
NEW
156
    if (minimumControl == QStyle::SC_SliderHandle &&
×
157
        maximumControl == QStyle::SC_SliderHandle)
158
    {
NEW
159
        int minDist = 0;
×
NEW
160
        int maxDist = 0;
×
NEW
161
        if (q->orientation() == Qt::Horizontal)
×
162
        {
NEW
163
            minDist = pos.x() - minimumHandleRect.left();
×
NEW
164
            maxDist = maximumHandleRect.right() - pos.x();
×
165
        }
166
        else //if (q->orientation() == Qt::Vertical)
167
        {
NEW
168
            minDist = minimumHandleRect.bottom() - pos.y();
×
NEW
169
            maxDist = pos.y() - maximumHandleRect.top();
×
170
        }
NEW
171
        Q_ASSERT(minDist >= 0 && maxDist >= 0);
×
NEW
172
        minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None;
×
173
    }
174

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

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

NEW
198
    QRect gr = q->style()->subControlRect(QStyle::CC_Slider,
×
199
                                          &option,
200
                                          QStyle::SC_SliderGroove,
NEW
201
                                          q);
×
NEW
202
    QRect sr = q->style()->subControlRect(QStyle::CC_Slider,
×
203
                                          &option,
204
                                          QStyle::SC_SliderHandle,
NEW
205
                                          q);
×
206
  int sliderMin, sliderMax, sliderLength;
207
  if (option.orientation == Qt::Horizontal)
×
208
    {
209
    sliderLength = sr.width();
×
210
    sliderMin = gr.x();
×
211
    sliderMax = gr.right() - sliderLength + 1;
×
212
    }
213
  else
214
    {
215
    sliderLength = sr.height();
×
216
    sliderMin = gr.y();
×
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
//---------------------------------------------------------------------------
NEW
228
int ctkRangeSliderPrivate::pixelPosFromRangeValue(int val) const
×
229
{
NEW
230
    Q_Q(const ctkRangeSlider);
×
NEW
231
    QStyleOptionSlider option;
×
NEW
232
    q->initStyleOption(&option);
×
233

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

NEW
256
    return QStyle::sliderPositionFromValue(q->minimum(),
×
257
                                           q->maximum(),
258
                                           val,
259
                                           sliderMax - sliderMin,
NEW
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
    {
NEW
276
        option.activeSubControls = QStyle::SC_SliderHandle;
×
NEW
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
    {
NEW
301
        option.activeSubControls = QStyle::SC_SliderHandle;
×
NEW
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
// --------------------------------------------------------------------------
NEW
333
ctkRangeSlider::ctkRangeSlider(ctkRangeSliderPrivate *impl, QWidget *_parent)
×
334
    : QSlider(_parent)
NEW
335
    , d_ptr(impl)
×
336
{
NEW
337
    Q_D(ctkRangeSlider);
×
NEW
338
    d->init();
×
UNCOV
339
}
×
340

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

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

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

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

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

377
// --------------------------------------------------------------------------
NEW
378
void ctkRangeSlider::setMaximumValue(int max)
×
379
{
NEW
380
    Q_D(ctkRangeSlider);
×
NEW
381
    this->setValues(qMin(d->m_MinimumValue, max), max);
×
UNCOV
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
    {
NEW
403
        if (emitMinPosChanged || emitMaxPosChanged)
×
404
        {
NEW
405
            emit positionsChanged(d->m_MinimumPosition, d->m_MaximumPosition);
×
406
        }
NEW
407
        if (emitMinPosChanged)
×
408
        {
NEW
409
            emit minimumPositionChanged(d->m_MinimumPosition);
×
410
        }
NEW
411
        if (emitMaxPosChanged)
×
412
        {
NEW
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
    {
NEW
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
{
NEW
452
    Q_D(const ctkRangeSlider);
×
NEW
453
    this->setPositions(l, qMax(l, d->m_MaximumPosition));
×
UNCOV
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
    {
NEW
475
        return;
×
476
    }
477

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

481
    if (!this->hasTracking())
18✔
482
    {
NEW
483
        this->update();
×
484
    }
485
    if (isSliderDown())
18✔
486
    {
NEW
487
        if (emitMinPosChanged)
×
488
        {
NEW
489
            emit minimumPositionChanged(d->m_MinimumPosition);
×
490
        }
NEW
491
        if (emitMaxPosChanged)
×
492
        {
NEW
493
            emit maximumPositionChanged(d->m_MaximumPosition);
×
494
        }
NEW
495
        if (emitMinPosChanged || emitMaxPosChanged)
×
496
        {
NEW
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
{
NEW
510
    Q_D(ctkRangeSlider);
×
NEW
511
    d->m_SymmetricMoves = symmetry;
×
UNCOV
512
}
×
513

514
// --------------------------------------------------------------------------
515
bool ctkRangeSlider::symmetricMoves()const
×
516
{
NEW
517
    Q_D(const ctkRangeSlider);
×
NEW
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::Normal, 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
    gradient.setColorAt(0, highlight.darker(120));
4✔
606
    gradient.setColorAt(1, highlight.lighter(160));
4✔
607

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

612
    //  -----------------------------------
613
    // Render the sliders
614
    //
615
    if (this->isMinimumSliderDown())
4✔
616
    {
NEW
617
        d->drawMaximumSlider(&painter);
×
NEW
618
        d->drawMinimumSlider(&painter);
×
619
    }
620
    else
621
    {
622
        d->drawMinimumSlider(&painter);
4✔
623
        d->drawMaximumSlider(&painter);
4✔
624
    }
625
}
4✔
626

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

NEW
640
    QStyleOptionSlider option;
×
NEW
641
    this->initStyleOption(&option);
×
642

NEW
643
    QRect handleRect;
×
NEW
644
    ctkRangeSliderPrivate::Handle handle_ = d->handleAtPos(mouseEvent->pos(), handleRect);
×
645

NEW
646
    if (handle_ != ctkRangeSliderPrivate::NoHandle)
×
647
    {
NEW
648
        d->m_SubclassPosition = (handle_ == ctkRangeSliderPrivate::MinimumHandle) ?
×
649
                                    d->m_MinimumPosition : d->m_MaximumPosition;
650

651
        // save the position of the mouse inside the handle for later
NEW
652
        d->m_SubclassClickOffset = mepos - (this->orientation() == Qt::Horizontal ?
×
NEW
653
                                                handleRect.left() : handleRect.top());
×
654

NEW
655
        this->setSliderDown(true);
×
656

NEW
657
        if (d->m_SelectedHandles != handle_)
×
658
        {
NEW
659
            d->m_SelectedHandles = handle_;
×
NEW
660
            this->update(handleRect);
×
661
        }
662
        // Accept the mouseEvent
NEW
663
        mouseEvent->accept();
×
NEW
664
        return;
×
665
    }
666

667
    // if we are here, no handles have been pressed
668
    // Check if we pressed on the groove between the 2 handles
669

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

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

NEW
711
    QStyleOptionSlider option;
×
NEW
712
    this->initStyleOption(&option);
×
713

NEW
714
    const int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &option, this);
×
715

NEW
716
    int newPosition = d->pixelPosToRangeValue(mepos - d->m_SubclassClickOffset);
×
717

NEW
718
    if (m >= 0)
×
719
    {
NEW
720
        const QRect r = rect().adjusted(-m, -m, m, m);
×
NEW
721
        if (!r.contains(mouseEvent->pos()))
×
722
        {
NEW
723
            newPosition = d->m_SubclassPosition;
×
724
        }
725
    }
726

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

751
// --------------------------------------------------------------------------
752
// Standard Qt UI mouseEvents
753
void ctkRangeSlider::mouseReleaseEvent(QMouseEvent* mouseEvent)
×
754
{
NEW
755
    Q_D(ctkRangeSlider);
×
NEW
756
    this->QSlider::mouseReleaseEvent(mouseEvent);
×
757

NEW
758
    setSliderDown(false);
×
NEW
759
    d->m_SelectedHandles = ctkRangeSliderPrivate::NoHandle;
×
760

NEW
761
    this->update();
×
762
}
×
763

764
// --------------------------------------------------------------------------
765
bool ctkRangeSlider::isMinimumSliderDown()const
8✔
766
{
767
    Q_D(const ctkRangeSlider);
8✔
768
    return d->m_SelectedHandles & ctkRangeSliderPrivate::MinimumHandle;
8✔
769
}
770

771
// --------------------------------------------------------------------------
772
bool ctkRangeSlider::isMaximumSliderDown()const
4✔
773
{
774
    Q_D(const ctkRangeSlider);
4✔
775
    return d->m_SelectedHandles & ctkRangeSliderPrivate::MaximumHandle;
4✔
776
}
777

778
// --------------------------------------------------------------------------
779
void ctkRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider* option) const
4✔
780
{
781
    this->initStyleOption(option);
4✔
782
}
4✔
783

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

790
// --------------------------------------------------------------------------
791
QString ctkRangeSlider::handleToolTip()const
×
792
{
NEW
793
    Q_D(const ctkRangeSlider);
×
NEW
794
    return d->m_HandleToolTip;
×
795
}
796

797
// --------------------------------------------------------------------------
798
void ctkRangeSlider::setHandleToolTip(const QString& _toolTip)
×
799
{
NEW
800
    Q_D(ctkRangeSlider);
×
NEW
801
    d->m_HandleToolTip = _toolTip;
×
UNCOV
802
}
×
803

804
// --------------------------------------------------------------------------
805
bool ctkRangeSlider::event(QEvent* _event)
50✔
806
{
807
    Q_D(ctkRangeSlider);
50✔
808
    switch(_event->type())
50✔
809
    {
810
    case QEvent::ToolTip:
×
811
    {
NEW
812
        QHelpEvent* helpEvent = static_cast<QHelpEvent*>(_event);
×
NEW
813
        QStyleOptionSlider opt;
×
814
        // Test the MinimumHandle
NEW
815
        opt.sliderPosition = d->m_MinimumPosition;
×
NEW
816
        opt.sliderValue = d->m_MinimumValue;
×
NEW
817
        this->initStyleOption(&opt);
×
818
        QStyle::SubControl hoveredControl =
NEW
819
            this->style()->hitTestComplexControl(
×
NEW
820
                QStyle::CC_Slider, &opt, helpEvent->pos(), this);
×
NEW
821
        if (!d->m_HandleToolTip.isEmpty() &&
×
822
            hoveredControl == QStyle::SC_SliderHandle)
823
        {
NEW
824
            QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->minimumValue()));
×
NEW
825
            _event->accept();
×
NEW
826
            return true;
×
827
        }
828
        // Test the MaximumHandle
NEW
829
        opt.sliderPosition = d->m_MaximumPosition;
×
NEW
830
        opt.sliderValue = d->m_MaximumValue;
×
NEW
831
        this->initStyleOption(&opt);
×
NEW
832
        hoveredControl = this->style()->hitTestComplexControl(
×
NEW
833
            QStyle::CC_Slider, &opt, helpEvent->pos(), this);
×
NEW
834
        if (!d->m_HandleToolTip.isEmpty() &&
×
835
            hoveredControl == QStyle::SC_SliderHandle)
836
        {
NEW
837
            QToolTip::showText(helpEvent->globalPos(), d->m_HandleToolTip.arg(this->maximumValue()));
×
NEW
838
            _event->accept();
×
NEW
839
            return true;
×
840
        }
841
    }
842
    default:
843
        break;
50✔
844
    }
845
    return this->Superclass::event(_event);
50✔
846
}
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

© 2026 Coveralls, Inc