GOFIGURE2  0.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ctkDoubleRangeSlider.cpp
Go to the documentation of this file.
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.commontk.org/LICENSE
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 <QHBoxLayout>
24 
25 // CTK includes
26 #include "ctkRangeSlider.h"
27 #include "ctkDoubleRangeSlider.h"
28 
29 
30 //-----------------------------------------------------------------------------
32 {
34 protected:
36 public:
38 
39  int toInt(double _value)const;
40  double minFromInt(int _value)const;
41  double maxFromInt(int _value)const;
42  void init();
43  void connectSlider();
44  void updateMinOffset(double value);
45  void updateMaxOffset(double value);
46 
48  double Minimum;
49  double Maximum;
51 
52  // we should have a MinValueOffset and MinPositionOffset (and MinimumOffset?)
53  double MinOffset;
54  // we should have a MaxValueOffset and MaxPositionOffset (and MaximumOffset?)
55  double MaxOffset;
56  double SingleStep;
57  double MinValue;
58  double MaxValue;
59 };
60 
61 // --------------------------------------------------------------------------
63  :q_ptr(&object)
64 {
65  // the initial values will be overwritten in
66  // ctkDoubleRangeSliderPrivate::init()
67  this->Slider = 0;
68  this->Minimum = 0.;
69  this->Maximum = 99.;
70  this->SettingRange = false;
71  this->MinOffset = 0.;
72  this->MaxOffset = 0.;
73  this->SingleStep = 1.;
74  this->MinValue = 0.;
75  this->MaxValue = 99.;
76 }
77 
78 // --------------------------------------------------------------------------
80 {
82  this->Slider = new ctkRangeSlider(q);
83  QHBoxLayout* l = new QHBoxLayout(q);
84  l->addWidget(this->Slider);
85  l->setContentsMargins(0,0,0,0);
86 
87  this->Minimum = this->Slider->minimum();
88  this->Maximum = this->Slider->maximum();
89  this->MinValue = this->Slider->minimumValue();
90  this->MaxValue = this->Slider->maximumValue();
91  this->SingleStep = this->Slider->singleStep();
92 
93  q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed,
94  QSizePolicy::Slider));
95 
96  this->connectSlider();
97 }
98 
99 // --------------------------------------------------------------------------
101 {
103  q->connect(this->Slider, SIGNAL(minimumValueChanged(int)),
104  q, SLOT(onMinValueChanged(int)));
105  q->connect(this->Slider, SIGNAL(maximumValueChanged(int)),
106  q, SLOT(onMaxValueChanged(int)));
107  q->connect(this->Slider, SIGNAL(valuesChanged(int,int)),
108  q, SLOT(onValuesChanged(int,int)));
109 
110  q->connect(this->Slider, SIGNAL(minimumPositionChanged(int)),
111  q, SLOT(onMinPosChanged(int)));
112  q->connect(this->Slider, SIGNAL(maximumPositionChanged(int)),
113  q, SLOT(onMaxPosChanged(int)));
114  q->connect(this->Slider, SIGNAL(positionsChanged(int,int)),
115  q, SLOT(onPositionsChanged(int,int)));
116 
117  q->connect(this->Slider, SIGNAL(sliderPressed()),
118  q, SIGNAL(sliderPressed()));
119  q->connect(this->Slider, SIGNAL(sliderReleased()),
120  q, SIGNAL(sliderReleased()));
121  q->connect(this->Slider, SIGNAL(rangeChanged(int, int)),
122  q, SLOT(onRangeChanged(int, int)));
123 }
124 
125 // --------------------------------------------------------------------------
126 int ctkDoubleRangeSliderPrivate::toInt(double doubleValue)const
127 {
128  double tmp = doubleValue / this->SingleStep;
129  int intValue = qRound(tmp);
130  return intValue;
131 }
132 
133 // --------------------------------------------------------------------------
135 {
136  double doubleValue = this->SingleStep * (this->MinOffset + intValue) ;
137  return doubleValue;
138 }
139 
140 // --------------------------------------------------------------------------
142 {
143  double doubleValue = this->SingleStep * (this->MaxOffset + intValue) ;
144  return doubleValue;
145 }
146 
147 // --------------------------------------------------------------------------
149 {
150  this->MinOffset = (value / this->SingleStep) - this->toInt(value);
151 }
152 
153 // --------------------------------------------------------------------------
155 {
156  this->MaxOffset = (value / this->SingleStep) - this->toInt(value);
157 }
158 
159 // --------------------------------------------------------------------------
161  , d_ptr(new ctkDoubleRangeSliderPrivate(*this))
162 {
164  d->init();
165 }
166 
167 // --------------------------------------------------------------------------
168 ctkDoubleRangeSlider::ctkDoubleRangeSlider(Qt::Orientation _orientation, QWidget* _parent)
169  : Superclass(_parent)
170  , d_ptr(new ctkDoubleRangeSliderPrivate(*this))
171 {
173  d->init();
174  this->setOrientation(_orientation);
175 }
176 
177 // --------------------------------------------------------------------------
179 {
180 }
181 
182 // --------------------------------------------------------------------------
184 {
186  d->Minimum = min;
187  if (d->Minimum >= d->MinValue)
188  {// TBD: use same offset
189  d->updateMinOffset(d->Minimum);
190  }
191  if (d->Minimum >= d->MaxValue)
192  {// TBD: use same offset
193  d->updateMaxOffset(d->Minimum);
194  }
195  d->SettingRange = true;
196  d->Slider->setMinimum(d->toInt(min));
197  d->SettingRange = false;
198  emit this->rangeChanged(d->Minimum, d->Maximum);
199 }
200 
201 // --------------------------------------------------------------------------
202 double ctkDoubleRangeSlider::minimum()const
203 {
204  Q_D(const ctkDoubleRangeSlider);
205  return d->Minimum;
206 }
207 
208 // --------------------------------------------------------------------------
210 {
212  d->Maximum = max;
213  if (d->Maximum <= d->MinValue)
214  {// TBD: use same offset
215  d->updateMinOffset(d->Maximum);
216  }
217  if (d->Maximum <= d->MaxValue)
218  {// TBD: use same offset ?
219  d->updateMaxOffset(d->Maximum);
220  }
221  d->SettingRange = true;
222  d->Slider->setMaximum(d->toInt(max));
223  d->SettingRange = false;
224  emit this->rangeChanged(d->Minimum, d->Maximum);
225 }
226 
227 // --------------------------------------------------------------------------
228 double ctkDoubleRangeSlider::maximum()const
229 {
230  Q_D(const ctkDoubleRangeSlider);
231  return d->Maximum;
232 }
233 
234 // --------------------------------------------------------------------------
235 void ctkDoubleRangeSlider::setRange(double min, double max)
236 {
238  d->Minimum = min;
239  d->Maximum = max;
240  if (d->Minimum >= d->MinValue)
241  {// TBD: use same offset
242  d->updateMinOffset(d->Minimum);
243  }
244  if (d->Minimum >= d->MaxValue)
245  {// TBD: use same offset
246  d->updateMaxOffset(d->Minimum);
247  }
248  if (d->Maximum <= d->MinValue)
249  {// TBD: use same offset
250  d->updateMinOffset(d->Maximum);
251  }
252  if (d->Maximum <= d->MaxValue)
253  {// TBD: use same offset ?
254  d->updateMaxOffset(d->Maximum);
255  }
256  d->SettingRange = true;
257  d->Slider->setRange(d->toInt(min), d->toInt(max));
258  d->SettingRange = false;
259  emit this->rangeChanged(d->Minimum, d->Maximum);
260 }
261 
262 // --------------------------------------------------------------------------
264 {
265  Q_D(const ctkDoubleRangeSlider);
266  return d->minFromInt(d->Slider->minimumPosition());
267 }
268 
269 // --------------------------------------------------------------------------
271 {
273  d->Slider->setMinimumPosition(d->toInt(minPos));
274 }
275 
276 // --------------------------------------------------------------------------
278 {
279  Q_D(const ctkDoubleRangeSlider);
280  return d->maxFromInt(d->Slider->maximumPosition());
281 }
282 
283 // --------------------------------------------------------------------------
285 {
287  d->Slider->setMaximumPosition(d->toInt(maxPos));
288 }
289 
290 // --------------------------------------------------------------------------
291 void ctkDoubleRangeSlider::setPositions(double minPos, double maxPos)
292 {
294  d->Slider->setPositions(d->toInt(minPos), d->toInt(maxPos));
295 }
296 
297 // --------------------------------------------------------------------------
299 {
300  Q_D(const ctkDoubleRangeSlider);
301  return d->MinValue;
302 }
303 
304 // --------------------------------------------------------------------------
306 {
308  newMinValue = qBound(d->Minimum, newMinValue, d->Maximum);
309  d->updateMinOffset(newMinValue);
310  if (newMinValue >= d->MaxValue)
311  {
312  d->updateMaxOffset(newMinValue);
313  }
314  int newIntValue = d->toInt(newMinValue);
315  if (newIntValue != d->Slider->minimumValue())
316  {
317  // d->Slider will emit a minimumValueChanged signal that is connected to
318  // ctkDoubleSlider::onValueChanged
319  d->Slider->setMinimumValue(newIntValue);
320  }
321  else
322  {
323  double oldValue = d->MinValue;
324  d->MinValue = newMinValue;
325  // don't emit a valuechanged signal if the new value is quite
326  // similar to the old value.
327  if (qAbs(newMinValue - oldValue) > (d->SingleStep * 0.000000001))
328  {
329  emit this->valuesChanged(newMinValue, this->maximumValue());
330  emit this->minimumValueChanged(newMinValue);
331  }
332  }
333 }
334 
335 // --------------------------------------------------------------------------
337 {
338  Q_D(const ctkDoubleRangeSlider);
339  return d->MaxValue;
340 }
341 
342 // --------------------------------------------------------------------------
344 {
346  newMaxValue = qBound(d->Minimum, newMaxValue, d->Maximum);
347  d->updateMaxOffset(newMaxValue);
348  if (newMaxValue <= d->MinValue)
349  {
350  d->updateMinOffset(newMaxValue);
351  }
352  int newIntValue = d->toInt(newMaxValue);
353  if (newIntValue != d->Slider->maximumValue())
354  {
355  // d->Slider will emit a maximumValueChanged signal that is connected to
356  // ctkDoubleSlider::onValueChanged
357  d->Slider->setMaximumValue(newIntValue);
358  }
359  else
360  {
361  double oldValue = d->MaxValue;
362  d->MaxValue = newMaxValue;
363  // don't emit a valuechanged signal if the new value is quite
364  // similar to the old value.
365  if (qAbs(newMaxValue - oldValue) > (d->SingleStep * 0.000000001))
366  {
367  emit this->valuesChanged(this->minimumValue(), newMaxValue);
368  emit this->maximumValueChanged(newMaxValue);
369  }
370  }
371 }
372 
373 // --------------------------------------------------------------------------
374 void ctkDoubleRangeSlider::setValues(double newMinVal, double newMaxVal)
375 {
377  // We can't call setMinimumValue() and setMaximumValue() as they would
378  // generate an inconsistent state. when minimumValueChanged() is fired the
379  // new max value wouldn't be updated yet.
380  double newMinValue = qBound(d->Minimum, qMin(newMinVal, newMaxVal), d->Maximum);
381  double newMaxValue = qBound(d->Minimum, qMax(newMinVal, newMaxVal), d->Maximum);
382  d->updateMinOffset(newMinValue);
383  d->updateMaxOffset(newMaxValue);
384  int newMinIntValue = d->toInt(newMinValue);
385  int newMaxIntValue = d->toInt(newMaxValue);
386  if (newMinIntValue != d->Slider->minimumValue() ||
387  newMaxIntValue != d->Slider->maximumValue())
388  {
389  // d->Slider will emit a maximumValueChanged signal that is connected to
390  // ctkDoubleSlider::onValueChanged
391  d->Slider->setValues(newMinIntValue, newMaxIntValue);
392  }
393  else
394  {
395  double oldMinValue = d->MinValue;
396  double oldMaxValue = d->MaxValue;
397  d->MinValue = newMinValue;
398  d->MaxValue = newMaxValue;
399  // don't emit a valuechanged signal if the new value is quite
400  // similar to the old value.
401  bool minChanged = qAbs(newMinValue - oldMinValue) > (d->SingleStep * 0.000000001);
402  bool maxChanged = qAbs(newMaxValue - oldMaxValue) > (d->SingleStep * 0.000000001);
403  if (minChanged || maxChanged)
404  {
405  emit this->valuesChanged(newMinValue, newMaxValue);
406  if (minChanged)
407  {
408  emit this->minimumValueChanged(newMinValue);
409  }
410  if (maxChanged)
411  {
412  emit this->maximumValueChanged(newMaxValue);
413  }
414  }
415  }
416 }
417 
418 // --------------------------------------------------------------------------
420 {
421  Q_D(const ctkDoubleRangeSlider);
422  return d->SingleStep;
423 }
424 
425 // --------------------------------------------------------------------------
427 {
429  d->SingleStep = newStep;
430  // The following can fire A LOT of signals that shouldn't be
431  // fired.
432  bool oldBlockSignals = this->blockSignals(true);
433  d->updateMinOffset(d->MinValue);
434  d->updateMaxOffset(d->MaxValue);
435  // update the new values of the ctkRangeSlider
436  double _minvalue = d->MinValue;
437  double _maxvalue = d->MaxValue;
438  // calling setMinimum or setMaximum can change the values MinimumValue
439  // and MaximumValue, this is why we re-set them later.
440  this->setMinimum(d->Minimum);
441  this->setMaximum(d->Maximum);
442  this->setMinimumValue(_minvalue);
443  this->setMinimumPosition(_minvalue);
444  this->setMaximumValue(_maxvalue);
445  this->setMaximumPosition(_maxvalue);
446  this->blockSignals(oldBlockSignals);
447 }
448 
449 // --------------------------------------------------------------------------
451 {
452  Q_D(const ctkDoubleRangeSlider);
453  return d->minFromInt(d->Slider->tickInterval());
454 }
455 
456 // --------------------------------------------------------------------------
457 void ctkDoubleRangeSlider::setTickInterval(double newTickInterval)
458 {
460  d->Slider->setTickInterval(d->toInt(newTickInterval));
461 }
462 
463 // --------------------------------------------------------------------------
465 {
466  Q_D(const ctkDoubleRangeSlider);
467  return d->Slider->hasTracking();
468 }
469 
470 // --------------------------------------------------------------------------
472 {
474  d->Slider->setTracking(enable);
475 }
476 
477 // --------------------------------------------------------------------------
478 void ctkDoubleRangeSlider::triggerAction( QAbstractSlider::SliderAction action)
479 {
481  d->Slider->triggerAction(action);
482 }
483 
484 // --------------------------------------------------------------------------
485 void ctkDoubleRangeSlider::setOrientation(Qt::Orientation newOrientation)
486 {
488  d->Slider->setOrientation(newOrientation);
489 }
490 
491 // --------------------------------------------------------------------------
492 Qt::Orientation ctkDoubleRangeSlider::orientation()const
493 {
494  Q_D(const ctkDoubleRangeSlider);
495  return d->Slider->orientation();
496 }
497 
498 // --------------------------------------------------------------------------
500 {
501  Q_D(const ctkDoubleRangeSlider);
502  return d->Slider->symmetricMoves();
503 }
504 
505 // --------------------------------------------------------------------------
507 {
509  d->Slider->setSymmetricMoves(symmetry);
510 }
511 
512 // --------------------------------------------------------------------------
514 {
516  double doubleNewValue = d->minFromInt(newValue);
517  if (d->MinValue == doubleNewValue)
518  {
519  return;
520  }
521  d->MinValue = doubleNewValue;
522  emit this->valuesChanged(d->MinValue, d->MaxValue);
523  emit this->minimumValueChanged(d->MinValue);
524 }
525 
526 // --------------------------------------------------------------------------
528 {
530  double doubleNewValue = d->maxFromInt(newValue);
531  if (d->MaxValue == doubleNewValue)
532  {
533  return;
534  }
535  d->MaxValue = doubleNewValue;
536  emit this->valuesChanged(d->MinValue, d->MaxValue);
537  emit this->maximumValueChanged(d->MaxValue);
538 }
539 
540 // --------------------------------------------------------------------------
541 void ctkDoubleRangeSlider::onValuesChanged(int newMinValue, int newMaxValue)
542 {
544  double doubleNewMinValue = d->minFromInt(newMinValue);
545  double doubleNewMaxValue = d->maxFromInt(newMaxValue);
546 
547  bool emitMinValueChanged = (d->MinValue != doubleNewMinValue);
548  bool emitMaxValueChanged = (d->MaxValue != doubleNewMaxValue);
549 
550  if (!emitMinValueChanged && !emitMaxValueChanged)
551  {
552  return;
553  }
554  d->MinValue = doubleNewMinValue;
555  d->MaxValue = doubleNewMaxValue;
556  emit this->valuesChanged(d->MinValue, d->MaxValue);
557  if (emitMinValueChanged)
558  {
559  emit this->minimumValueChanged(d->MinValue);
560  }
561  if (emitMaxValueChanged)
562  {
563  emit this->maximumValueChanged(d->MaxValue);
564  }
565 }
566 
567 // --------------------------------------------------------------------------
569 {
570  Q_D(const ctkDoubleRangeSlider);
571  emit this->minimumPositionChanged(d->minFromInt(newPosition));
572 }
573 
574 // --------------------------------------------------------------------------
576 {
577  Q_D(const ctkDoubleRangeSlider);
578  emit this->maximumPositionChanged(d->maxFromInt(newPosition));
579 }
580 
581 // --------------------------------------------------------------------------
583 {
584  Q_D(const ctkDoubleRangeSlider);
585  emit this->positionsChanged(d->minFromInt(min), d->maxFromInt(max));
586 }
587 
588 // --------------------------------------------------------------------------
590 {
591  Q_D(const ctkDoubleRangeSlider);
592  if (!d->SettingRange)
593  {
594  this->setRange(d->minFromInt(min), d->maxFromInt(max));
595  }
596 }
597 
598 // --------------------------------------------------------------------------
600 {
601  Q_D(const ctkDoubleRangeSlider);
602  return d->Slider;
603 }
604 
605 // --------------------------------------------------------------------------
607 {
609  t_slider->setOrientation(d->Slider->orientation());
610  t_slider->setMinimum(d->Slider->minimum());
611  t_slider->setMaximum(d->Slider->maximum());
612  t_slider->setValues(d->Slider->minimumValue(), d->Slider->maximumValue());
613  t_slider->setSingleStep(d->Slider->singleStep());
614  t_slider->setTracking(d->Slider->hasTracking());
615  t_slider->setTickInterval(d->Slider->tickInterval());
616  delete d->Slider;
617  qobject_cast<QHBoxLayout*>(this->layout())->addWidget(t_slider);
618  d->Slider = t_slider;
619  d->connectSlider();
620 }
QLayout * layout() const
Q_DECLARE_PUBLIC(ctkDoubleRangeSlider)
void setContentsMargins(int left, int top, int right, int bottom)
ctkDoubleRangeSlider(Qt::Orientation o, QWidget *par=0)
void setTracking(bool enable)
ctkDoubleRangeSliderPrivate(ctkDoubleRangeSlider &object)
double minimum() const
void onMaxValueChanged(int value)
double minimumPosition() const
void setOrientation(Qt::Orientation orientation)
void valuesChanged(double minVal, double maxVal)
Utility signal that is fired when minimum or maximum values have changed.
void setSymmetricMoves(bool symmetry)
double tickInterval() const
void setMaximumValue(double maxVal)
void setPositions(double minPos, double maxPos)
void setSlider(ctkRangeSlider *slider)
Subclasses can change the internal slider.
ctkDoubleRangeSlider *const q_ptr
void onValuesChanged(int min, int max)
void maximumValueChanged(double maxVal)
double minimumValue() const
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
void setOrientation(Qt::Orientation)
void onRangeChanged(int min, int max)
double maximum() const
void onPositionsChanged(int min, int max)
void maximumPositionChanged(double maxPos)
int toInt(double _value) const
double maxFromInt(int _value) const
double maximumValue() const
void rangeChanged(double min, double max)
void setRange(double min, double max)
void onMinValueChanged(int value)
void setMinimumPosition(double minPos)
void setMinimumValue(double minVal)
bool blockSignals(bool block)
void setValues(double minVal, double maxVal)
Utility function that set the minimum value and maximum value at once.
virtual ~ctkDoubleRangeSlider()
Destructor.
void positionsChanged(double minPos, double maxPos)
void minimumPositionChanged(double minPos)
double singleStep() const
double maximumPosition() const
void minimumValueChanged(double minVal)
void setTracking(bool enable)
void setTickInterval(int ti)
double minFromInt(int _value) const
bool symmetricMoves() const
void setMaximumPosition(double maxPos)
void triggerAction(QAbstractSlider::SliderAction action)
ctkRangeSlider * slider() const
Qt::Orientation orientation() const
void setValues(int min, int max)