ctkDoubleRangeSlider.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 2010 Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QDebug>
  16. #include <QHBoxLayout>
  17. // CTK includes
  18. #include "ctkRangeSlider.h"
  19. #include "ctkDoubleRangeSlider.h"
  20. //-----------------------------------------------------------------------------
  21. class ctkDoubleRangeSliderPrivate: public ctkPrivate<ctkDoubleRangeSlider>
  22. {
  23. public:
  24. ctkDoubleRangeSliderPrivate();
  25. int toInt(double _value)const;
  26. double minFromInt(int _value)const;
  27. double maxFromInt(int _value)const;
  28. void init();
  29. void updateMinOffset(double value);
  30. void updateMaxOffset(double value);
  31. ctkRangeSlider* Slider;
  32. double Minimum;
  33. double Maximum;
  34. // we should have a MinValueOffset and MinPositionOffset (and MinimumOffset?)
  35. double MinOffset;
  36. // we should have a MaxValueOffset and MaxPositionOffset (and MaximumOffset?)
  37. double MaxOffset;
  38. double SingleStep;
  39. double MinValue;
  40. double MaxValue;
  41. };
  42. // --------------------------------------------------------------------------
  43. ctkDoubleRangeSliderPrivate::ctkDoubleRangeSliderPrivate()
  44. {
  45. this->Slider = 0;
  46. this->Minimum = 0.;
  47. this->Maximum = 99.;
  48. this->MinOffset = 0.;
  49. this->MaxOffset = 0.;
  50. this->SingleStep = 1.;
  51. this->MinValue = 0.;
  52. this->MaxValue = 99.;
  53. }
  54. // --------------------------------------------------------------------------
  55. void ctkDoubleRangeSliderPrivate::init()
  56. {
  57. CTK_P(ctkDoubleRangeSlider);
  58. this->Slider = new ctkRangeSlider(p);
  59. QHBoxLayout* l = new QHBoxLayout(p);
  60. l->addWidget(this->Slider);
  61. l->setContentsMargins(0,0,0,0);
  62. this->Minimum = this->Slider->minimum();
  63. this->Maximum = this->Slider->maximum();
  64. this->MinValue = this->Slider->minimumValue();
  65. this->MaxValue = this->Slider->maximumValue();
  66. this->SingleStep = this->Slider->singleStep();
  67. p->connect(this->Slider, SIGNAL(minimumValueChanged(int)), p, SLOT(onMinValueChanged(int)));
  68. p->connect(this->Slider, SIGNAL(maximumValueChanged(int)), p, SLOT(onMaxValueChanged(int)));
  69. p->connect(this->Slider, SIGNAL(valuesChanged(int,int)), p, SLOT(onValuesChanged(int,int)));
  70. p->connect(this->Slider, SIGNAL(minimumPositionChanged(int)), p, SLOT(onMinPosChanged(int)));
  71. p->connect(this->Slider, SIGNAL(maximumPositionChanged(int)), p, SLOT(onMaxPosChanged(int)));
  72. p->connect(this->Slider, SIGNAL(positionsChanged(int,int)), p, SLOT(onPositionsChanged(int,int)));
  73. p->connect(this->Slider, SIGNAL(sliderPressed()), p, SIGNAL(sliderPressed()));
  74. p->connect(this->Slider, SIGNAL(sliderReleased()), p, SIGNAL(sliderReleased()));
  75. }
  76. // --------------------------------------------------------------------------
  77. int ctkDoubleRangeSliderPrivate::toInt(double doubleValue)const
  78. {
  79. double tmp = doubleValue / this->SingleStep;
  80. int intValue = qRound(tmp);
  81. return intValue;
  82. }
  83. // --------------------------------------------------------------------------
  84. double ctkDoubleRangeSliderPrivate::minFromInt(int intValue)const
  85. {
  86. double doubleValue = this->SingleStep * (this->MinOffset + intValue) ;
  87. return doubleValue;
  88. }
  89. // --------------------------------------------------------------------------
  90. double ctkDoubleRangeSliderPrivate::maxFromInt(int intValue)const
  91. {
  92. double doubleValue = this->SingleStep * (this->MaxOffset + intValue) ;
  93. return doubleValue;
  94. }
  95. // --------------------------------------------------------------------------
  96. void ctkDoubleRangeSliderPrivate::updateMinOffset(double value)
  97. {
  98. this->MinOffset = (value / this->SingleStep) - this->toInt(value);
  99. }
  100. // --------------------------------------------------------------------------
  101. void ctkDoubleRangeSliderPrivate::updateMaxOffset(double value)
  102. {
  103. this->MaxOffset = (value / this->SingleStep) - this->toInt(value);
  104. }
  105. // --------------------------------------------------------------------------
  106. ctkDoubleRangeSlider::ctkDoubleRangeSlider(QWidget* _parent) : Superclass(_parent)
  107. {
  108. CTK_INIT_PRIVATE(ctkDoubleRangeSlider);
  109. ctk_d()->init();
  110. }
  111. // --------------------------------------------------------------------------
  112. ctkDoubleRangeSlider::ctkDoubleRangeSlider(Qt::Orientation _orientation, QWidget* _parent)
  113. : Superclass(_parent)
  114. {
  115. CTK_INIT_PRIVATE(ctkDoubleRangeSlider);
  116. ctk_d()->init();
  117. this->setOrientation(_orientation);
  118. }
  119. // --------------------------------------------------------------------------
  120. void ctkDoubleRangeSlider::setMinimum(double min)
  121. {
  122. CTK_D(ctkDoubleRangeSlider);
  123. d->Minimum = min;
  124. if (d->Minimum >= d->MinValue)
  125. {// TBD: use same offset
  126. d->updateMinOffset(d->Minimum);
  127. }
  128. if (d->Minimum >= d->MaxValue)
  129. {// TBD: use same offset
  130. d->updateMaxOffset(d->Minimum);
  131. }
  132. d->Slider->setMinimum(d->toInt(min));
  133. }
  134. // --------------------------------------------------------------------------
  135. double ctkDoubleRangeSlider::minimum()const
  136. {
  137. CTK_D(const ctkDoubleRangeSlider);
  138. return d->Minimum;
  139. }
  140. // --------------------------------------------------------------------------
  141. void ctkDoubleRangeSlider::setMaximum(double max)
  142. {
  143. CTK_D(ctkDoubleRangeSlider);
  144. d->Maximum = max;
  145. if (d->Maximum <= d->MinValue)
  146. {// TBD: use same offset
  147. d->updateMinOffset(d->Maximum);
  148. }
  149. if (d->Maximum <= d->MaxValue)
  150. {// TBD: use same offset ?
  151. d->updateMaxOffset(d->Maximum);
  152. }
  153. d->Slider->setMaximum(d->toInt(max));
  154. }
  155. // --------------------------------------------------------------------------
  156. double ctkDoubleRangeSlider::maximum()const
  157. {
  158. CTK_D(const ctkDoubleRangeSlider);
  159. return d->Maximum;
  160. }
  161. // --------------------------------------------------------------------------
  162. void ctkDoubleRangeSlider::setRange(double min, double max)
  163. {
  164. CTK_D(ctkDoubleRangeSlider);
  165. d->Minimum = min;
  166. d->Maximum = max;
  167. if (d->Minimum >= d->MinValue)
  168. {// TBD: use same offset
  169. d->updateMinOffset(d->Minimum);
  170. }
  171. if (d->Minimum >= d->MaxValue)
  172. {// TBD: use same offset
  173. d->updateMaxOffset(d->Minimum);
  174. }
  175. if (d->Maximum <= d->MinValue)
  176. {// TBD: use same offset
  177. d->updateMinOffset(d->Maximum);
  178. }
  179. if (d->Maximum <= d->MaxValue)
  180. {// TBD: use same offset ?
  181. d->updateMaxOffset(d->Maximum);
  182. }
  183. d->Slider->setRange(d->toInt(min), d->toInt(max));
  184. }
  185. // --------------------------------------------------------------------------
  186. double ctkDoubleRangeSlider::minimumPosition()const
  187. {
  188. CTK_D(const ctkDoubleRangeSlider);
  189. return d->minFromInt(d->Slider->minimumPosition());
  190. }
  191. // --------------------------------------------------------------------------
  192. void ctkDoubleRangeSlider::setMinimumPosition(double minPos)
  193. {
  194. CTK_D(ctkDoubleRangeSlider);
  195. d->Slider->setMinimumPosition(d->toInt(minPos));
  196. }
  197. // --------------------------------------------------------------------------
  198. double ctkDoubleRangeSlider::maximumPosition()const
  199. {
  200. CTK_D(const ctkDoubleRangeSlider);
  201. return d->maxFromInt(d->Slider->maximumPosition());
  202. }
  203. // --------------------------------------------------------------------------
  204. void ctkDoubleRangeSlider::setMaximumPosition(double maxPos)
  205. {
  206. CTK_D(ctkDoubleRangeSlider);
  207. d->Slider->setMaximumPosition(d->toInt(maxPos));
  208. }
  209. // --------------------------------------------------------------------------
  210. void ctkDoubleRangeSlider::setPositions(double minPos, double maxPos)
  211. {
  212. CTK_D(ctkDoubleRangeSlider);
  213. d->Slider->setPositions(d->toInt(minPos), d->toInt(maxPos));
  214. }
  215. // --------------------------------------------------------------------------
  216. double ctkDoubleRangeSlider::minimumValue()const
  217. {
  218. CTK_D(const ctkDoubleRangeSlider);
  219. return d->MinValue;
  220. }
  221. // --------------------------------------------------------------------------
  222. void ctkDoubleRangeSlider::setMinimumValue(double newMinValue)
  223. {
  224. CTK_D(ctkDoubleRangeSlider);
  225. newMinValue = qBound(d->Minimum, newMinValue, d->Maximum);
  226. d->updateMinOffset(newMinValue);
  227. if (newMinValue >= d->MaxValue)
  228. {
  229. d->updateMaxOffset(newMinValue);
  230. }
  231. int newIntValue = d->toInt(newMinValue);
  232. if (newIntValue != d->Slider->minimumValue())
  233. {
  234. // d->Slider will emit a minimumValueChanged signal that is connected to
  235. // ctkDoubleSlider::onValueChanged
  236. d->Slider->setMinimumValue(newIntValue);
  237. }
  238. else
  239. {
  240. double oldValue = d->MinValue;
  241. d->MinValue = newMinValue;
  242. // don't emit a valuechanged signal if the new value is quite
  243. // similar to the old value.
  244. if (qAbs(newMinValue - oldValue) > (d->SingleStep * 0.000000001))
  245. {
  246. emit this->minimumValueChanged(newMinValue);
  247. }
  248. }
  249. }
  250. // --------------------------------------------------------------------------
  251. double ctkDoubleRangeSlider::maximumValue()const
  252. {
  253. CTK_D(const ctkDoubleRangeSlider);
  254. return d->MaxValue;
  255. }
  256. // --------------------------------------------------------------------------
  257. void ctkDoubleRangeSlider::setMaximumValue(double newMaxValue)
  258. {
  259. CTK_D(ctkDoubleRangeSlider);
  260. newMaxValue = qBound(d->Minimum, newMaxValue, d->Maximum);
  261. d->updateMaxOffset(newMaxValue);
  262. if (newMaxValue <= d->MinValue)
  263. {
  264. d->updateMinOffset(newMaxValue);
  265. }
  266. int newIntValue = d->toInt(newMaxValue);
  267. if (newIntValue != d->Slider->maximumValue())
  268. {
  269. // d->Slider will emit a maximumValueChanged signal that is connected to
  270. // ctkDoubleSlider::onValueChanged
  271. d->Slider->setMaximumValue(newIntValue);
  272. }
  273. else
  274. {
  275. double oldValue = d->MaxValue;
  276. d->MaxValue = newMaxValue;
  277. // don't emit a valuechanged signal if the new value is quite
  278. // similar to the old value.
  279. if (qAbs(newMaxValue - oldValue) > (d->SingleStep * 0.000000001))
  280. {
  281. emit this->maximumValueChanged(newMaxValue);
  282. }
  283. }
  284. }
  285. // --------------------------------------------------------------------------
  286. void ctkDoubleRangeSlider::setValues(double newMinValue, double newMaxValue)
  287. {
  288. this->setMinimumValue(qMin(newMinValue, newMaxValue));
  289. this->setMaximumValue(qMax(newMinValue, newMaxValue));
  290. }
  291. // --------------------------------------------------------------------------
  292. double ctkDoubleRangeSlider::singleStep()const
  293. {
  294. CTK_D(const ctkDoubleRangeSlider);
  295. return d->SingleStep;
  296. }
  297. // --------------------------------------------------------------------------
  298. void ctkDoubleRangeSlider::setSingleStep(double newStep)
  299. {
  300. CTK_D(ctkDoubleRangeSlider);
  301. d->SingleStep = newStep;
  302. // The following can fire A LOT of signals that shouldn't be
  303. // fired.
  304. bool oldBlockSignals = this->blockSignals(true);
  305. d->updateMinOffset(d->MinValue);
  306. d->updateMaxOffset(d->MaxValue);
  307. // update the new values of the ctkRangeSlider
  308. double _minvalue = d->MinValue;
  309. double _maxvalue = d->MaxValue;
  310. // calling setMinimum or setMaximum can change the values MinimumValue
  311. // and MaximumValue, this is why we re-set them later.
  312. this->setMinimum(d->Minimum);
  313. this->setMaximum(d->Maximum);
  314. this->setMinimumValue(_minvalue);
  315. this->setMinimumPosition(_minvalue);
  316. this->setMaximumValue(_maxvalue);
  317. this->setMaximumPosition(_maxvalue);
  318. this->blockSignals(oldBlockSignals);
  319. }
  320. // --------------------------------------------------------------------------
  321. double ctkDoubleRangeSlider::tickInterval()const
  322. {
  323. CTK_D(const ctkDoubleRangeSlider);
  324. return d->minFromInt(d->Slider->tickInterval());
  325. }
  326. // --------------------------------------------------------------------------
  327. void ctkDoubleRangeSlider::setTickInterval(double newTickInterval)
  328. {
  329. CTK_D(ctkDoubleRangeSlider);
  330. d->Slider->setTickInterval(d->toInt(newTickInterval));
  331. }
  332. // --------------------------------------------------------------------------
  333. bool ctkDoubleRangeSlider::hasTracking()const
  334. {
  335. CTK_D(const ctkDoubleRangeSlider);
  336. return d->Slider->hasTracking();
  337. }
  338. // --------------------------------------------------------------------------
  339. void ctkDoubleRangeSlider::setTracking(bool enable)
  340. {
  341. CTK_D(ctkDoubleRangeSlider);
  342. d->Slider->setTracking(enable);
  343. }
  344. // --------------------------------------------------------------------------
  345. void ctkDoubleRangeSlider::triggerAction( QAbstractSlider::SliderAction action)
  346. {
  347. CTK_D(ctkDoubleRangeSlider);
  348. d->Slider->triggerAction(action);
  349. }
  350. // --------------------------------------------------------------------------
  351. void ctkDoubleRangeSlider::setOrientation(Qt::Orientation newOrientation)
  352. {
  353. CTK_D(ctkDoubleRangeSlider);
  354. d->Slider->setOrientation(newOrientation);
  355. }
  356. // --------------------------------------------------------------------------
  357. Qt::Orientation ctkDoubleRangeSlider::orientation()const
  358. {
  359. CTK_D(const ctkDoubleRangeSlider);
  360. return d->Slider->orientation();
  361. }
  362. // --------------------------------------------------------------------------
  363. void ctkDoubleRangeSlider::onMinValueChanged(int newValue)
  364. {
  365. CTK_D(ctkDoubleRangeSlider);
  366. double doubleNewValue = d->minFromInt(newValue);
  367. if (d->MinValue == doubleNewValue)
  368. {
  369. return;
  370. }
  371. d->MinValue = doubleNewValue;
  372. emit this->minimumValueChanged(d->MinValue);
  373. }
  374. // --------------------------------------------------------------------------
  375. void ctkDoubleRangeSlider::onMaxValueChanged(int newValue)
  376. {
  377. CTK_D(ctkDoubleRangeSlider);
  378. double doubleNewValue = d->maxFromInt(newValue);
  379. if (d->MaxValue == doubleNewValue)
  380. {
  381. return;
  382. }
  383. d->MaxValue = doubleNewValue;
  384. emit this->maximumValueChanged(d->MaxValue);
  385. }
  386. // --------------------------------------------------------------------------
  387. void ctkDoubleRangeSlider::onValuesChanged(int min, int max)
  388. {
  389. CTK_D(ctkDoubleRangeSlider);
  390. emit this->valuesChanged(d->minFromInt(min), d->maxFromInt(max));
  391. }
  392. // --------------------------------------------------------------------------
  393. void ctkDoubleRangeSlider::onMinPosChanged(int newPosition)
  394. {
  395. CTK_D(const ctkDoubleRangeSlider);
  396. emit this->minimumPositionChanged(d->minFromInt(newPosition));
  397. }
  398. // --------------------------------------------------------------------------
  399. void ctkDoubleRangeSlider::onMaxPosChanged(int newPosition)
  400. {
  401. CTK_D(const ctkDoubleRangeSlider);
  402. emit this->maximumPositionChanged(d->maxFromInt(newPosition));
  403. }
  404. // --------------------------------------------------------------------------
  405. void ctkDoubleRangeSlider::onPositionsChanged(int min, int max)
  406. {
  407. CTK_D(const ctkDoubleRangeSlider);
  408. emit this->positionsChanged(d->minFromInt(min), d->maxFromInt(max));
  409. }