ctkDoubleSpinBox.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 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.apache.org/licenses/LICENSE-2.0.txt
  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. // CTK includes
  15. #include "ctkDoubleSpinBox_p.h"
  16. #include "ctkUtils.h"
  17. #include "ctkPimpl.h"
  18. #include <QDebug>
  19. // Qt includes
  20. #include <QEvent>
  21. #include <QHBoxLayout>
  22. #include <QKeyEvent>
  23. #include <QShortcut>
  24. #include <QSizePolicy>
  25. #include <QVariant>
  26. //----------------------------------------------------------------------------
  27. ctkQDoubleSpinBox::ctkQDoubleSpinBox(QWidget* spinBoxParent)
  28. : QDoubleSpinBox(spinBoxParent)
  29. {
  30. this->InvertedControls = false;
  31. }
  32. //----------------------------------------------------------------------------
  33. void ctkQDoubleSpinBox::setInvertedControls(bool invertedControls)
  34. {
  35. this->InvertedControls = invertedControls;
  36. }
  37. //----------------------------------------------------------------------------
  38. bool ctkQDoubleSpinBox::invertedControls() const
  39. {
  40. return this->InvertedControls;
  41. }
  42. //----------------------------------------------------------------------------
  43. void ctkQDoubleSpinBox::stepBy(int steps)
  44. {
  45. if (this->InvertedControls)
  46. {
  47. steps = -steps;
  48. }
  49. this->Superclass::stepBy(steps);
  50. }
  51. //----------------------------------------------------------------------------
  52. QAbstractSpinBox::StepEnabled ctkQDoubleSpinBox::stepEnabled() const
  53. {
  54. if (!this->InvertedControls)
  55. {
  56. return this->Superclass::stepEnabled();
  57. }
  58. if (this->isReadOnly())
  59. {
  60. return StepNone;
  61. }
  62. if (this->wrapping())
  63. {
  64. return StepEnabled(StepUpEnabled | StepDownEnabled);
  65. }
  66. StepEnabled ret = StepNone;
  67. double value = this->value();
  68. if (value < this->maximum())
  69. {
  70. ret |= StepDownEnabled;
  71. }
  72. if (value > this->minimum())
  73. {
  74. ret |= StepUpEnabled;
  75. }
  76. return ret;
  77. }
  78. //-----------------------------------------------------------------------------
  79. ctkDoubleSpinBoxPrivate::ctkDoubleSpinBoxPrivate(ctkDoubleSpinBox& object)
  80. : q_ptr(&object)
  81. {
  82. qRegisterMetaType<ctkDoubleSpinBox::SetMode>("ctkDoubleSpinBox::SetMode");
  83. qRegisterMetaType<ctkDoubleSpinBox::DecimalsOptions>("ctkDoubleSpinBox::DecimalsOption");
  84. this->SpinBox = 0;
  85. this->Mode = ctkDoubleSpinBox::SetIfDifferent;
  86. this->DefaultDecimals = 2;
  87. this->DOption = ctkDoubleSpinBox::UseShortcuts;
  88. this->InvertedControls = false;
  89. }
  90. //-----------------------------------------------------------------------------
  91. void ctkDoubleSpinBoxPrivate::init()
  92. {
  93. Q_Q(ctkDoubleSpinBox);
  94. this->SpinBox = new ctkQDoubleSpinBox(q);
  95. this->SpinBox->setInvertedControls(this->InvertedControls);
  96. QObject::connect(this->SpinBox, SIGNAL(valueChanged(double)),
  97. q, SIGNAL(valueChanged(double)));
  98. QObject::connect(this->SpinBox, SIGNAL(valueChanged(const QString&)),
  99. q, SIGNAL(valueChanged(const QString &)));
  100. QObject::connect(this->SpinBox, SIGNAL(editingFinished()),
  101. q, SIGNAL(editingFinished()));
  102. QHBoxLayout* l = new QHBoxLayout(q);
  103. l->addWidget(this->SpinBox);
  104. l->setContentsMargins(0,0,0,0);
  105. q->setLayout(l);
  106. q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,
  107. QSizePolicy::Fixed, QSizePolicy::ButtonBox));
  108. this->SpinBox->installEventFilter(q);
  109. }
  110. //-----------------------------------------------------------------------------
  111. bool ctkDoubleSpinBoxPrivate::compare(double x1, double x2) const
  112. {
  113. Q_Q(const ctkDoubleSpinBox);
  114. return q->round(x1) == q->round(x2);
  115. }
  116. //-----------------------------------------------------------------------------
  117. void ctkDoubleSpinBoxPrivate::setDecimals(int dec)
  118. {
  119. Q_Q(ctkDoubleSpinBox);
  120. this->SpinBox->setDecimals(dec);
  121. emit q->decimalsChanged(dec);
  122. }
  123. //-----------------------------------------------------------------------------
  124. ctkDoubleSpinBox::ctkDoubleSpinBox(QWidget* newParent)
  125. : QWidget(newParent)
  126. , d_ptr(new ctkDoubleSpinBoxPrivate(*this))
  127. {
  128. Q_D(ctkDoubleSpinBox);
  129. d->init();
  130. }
  131. //-----------------------------------------------------------------------------
  132. ctkDoubleSpinBox::ctkDoubleSpinBox(ctkDoubleSpinBox::SetMode mode, QWidget* newParent)
  133. : QWidget(newParent)
  134. , d_ptr(new ctkDoubleSpinBoxPrivate(*this))
  135. {
  136. Q_D(ctkDoubleSpinBox);
  137. d->init();
  138. this->setSetMode(mode);
  139. }
  140. //-----------------------------------------------------------------------------
  141. double ctkDoubleSpinBox::value() const
  142. {
  143. Q_D(const ctkDoubleSpinBox);
  144. return d->SpinBox->value();
  145. }
  146. //-----------------------------------------------------------------------------
  147. double ctkDoubleSpinBox::displayedValue() const
  148. {
  149. return this->round(this->value());
  150. }
  151. //-----------------------------------------------------------------------------
  152. QString ctkDoubleSpinBox::text() const
  153. {
  154. Q_D(const ctkDoubleSpinBox);
  155. return d->SpinBox->text();
  156. }
  157. //-----------------------------------------------------------------------------
  158. QString ctkDoubleSpinBox::cleanText() const
  159. {
  160. Q_D(const ctkDoubleSpinBox);
  161. return d->SpinBox->cleanText();
  162. }
  163. //-----------------------------------------------------------------------------
  164. Qt::Alignment ctkDoubleSpinBox::alignment() const
  165. {
  166. Q_D(const ctkDoubleSpinBox);
  167. return d->SpinBox->alignment();
  168. }
  169. //-----------------------------------------------------------------------------
  170. void ctkDoubleSpinBox::setAlignment(Qt::Alignment flag)
  171. {
  172. Q_D(const ctkDoubleSpinBox);
  173. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && flag == d->SpinBox->alignment())
  174. {
  175. return;
  176. }
  177. d->SpinBox->setAlignment(flag);
  178. }
  179. //-----------------------------------------------------------------------------
  180. void ctkDoubleSpinBox::setFrame(bool frame)
  181. {
  182. Q_D(const ctkDoubleSpinBox);
  183. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && frame == d->SpinBox->hasFrame())
  184. {
  185. return;
  186. }
  187. d->SpinBox->setFrame(frame);
  188. }
  189. //-----------------------------------------------------------------------------
  190. bool ctkDoubleSpinBox::hasFrame() const
  191. {
  192. Q_D(const ctkDoubleSpinBox);
  193. return d->SpinBox->hasFrame();
  194. }
  195. //-----------------------------------------------------------------------------
  196. QString ctkDoubleSpinBox::prefix() const
  197. {
  198. Q_D(const ctkDoubleSpinBox);
  199. return d->SpinBox->prefix();
  200. }
  201. //-----------------------------------------------------------------------------
  202. void ctkDoubleSpinBox::setPrefix(const QString &prefix)
  203. {
  204. Q_D(const ctkDoubleSpinBox);
  205. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && prefix == d->SpinBox->prefix())
  206. {
  207. return;
  208. }
  209. #if QT_VERSION < 0x040800
  210. /// Setting the prefix doesn't recompute the sizehint, do it manually here:
  211. /// See: http://bugreports.qt.nokia.com/browse/QTBUG-9530
  212. d->SpinBox->setRange(d->SpinBox->minimum(), d->SpinBox->maximum());
  213. #endif
  214. d->SpinBox->setPrefix(prefix);
  215. }
  216. //-----------------------------------------------------------------------------
  217. QString ctkDoubleSpinBox::suffix() const
  218. {
  219. Q_D(const ctkDoubleSpinBox);
  220. return d->SpinBox->suffix();
  221. }
  222. //-----------------------------------------------------------------------------
  223. void ctkDoubleSpinBox::setSuffix(const QString &suffix)
  224. {
  225. Q_D(const ctkDoubleSpinBox);
  226. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && suffix == d->SpinBox->suffix())
  227. {
  228. return;
  229. }
  230. #if QT_VERSION < 0x040800
  231. /// Setting the suffix doesn't recompute the sizehint, do it manually here:
  232. /// See: http://bugreports.qt.nokia.com/browse/QTBUG-9530
  233. d->SpinBox->setRange(d->SpinBox->minimum(), d->SpinBox->maximum());
  234. #endif
  235. d->SpinBox->setSuffix(suffix);
  236. }
  237. //-----------------------------------------------------------------------------
  238. double ctkDoubleSpinBox::singleStep() const
  239. {
  240. Q_D(const ctkDoubleSpinBox);
  241. return d->SpinBox->singleStep();
  242. }
  243. //-----------------------------------------------------------------------------
  244. void ctkDoubleSpinBox::setSingleStep(double step)
  245. {
  246. Q_D(ctkDoubleSpinBox);
  247. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent
  248. && d->compare(step, this->singleStep()))
  249. {
  250. return;
  251. }
  252. d->SpinBox->setSingleStep(step);
  253. }
  254. //-----------------------------------------------------------------------------
  255. double ctkDoubleSpinBox::minimum() const
  256. {
  257. Q_D(const ctkDoubleSpinBox);
  258. return d->SpinBox->minimum();
  259. }
  260. //-----------------------------------------------------------------------------
  261. void ctkDoubleSpinBox::setMinimum(double min)
  262. {
  263. Q_D(ctkDoubleSpinBox);
  264. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent
  265. && d->compare(min, this->minimum()))
  266. {
  267. return;
  268. }
  269. d->SpinBox->setMinimum(min);
  270. }
  271. //-----------------------------------------------------------------------------
  272. double ctkDoubleSpinBox::maximum() const
  273. {
  274. Q_D(const ctkDoubleSpinBox);
  275. return d->SpinBox->maximum();
  276. }
  277. //-----------------------------------------------------------------------------
  278. void ctkDoubleSpinBox::setMaximum(double max)
  279. {
  280. Q_D(ctkDoubleSpinBox);
  281. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent
  282. && d->compare(max, this->maximum()))
  283. {
  284. return;
  285. }
  286. d->SpinBox->setMaximum(max);
  287. }
  288. //-----------------------------------------------------------------------------
  289. void ctkDoubleSpinBox::setRange(double min, double max)
  290. {
  291. Q_D(ctkDoubleSpinBox);
  292. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent
  293. && d->compare(max, this->maximum()) && d->compare(min, this->minimum()))
  294. {
  295. return;
  296. }
  297. d->SpinBox->setRange(min, max);
  298. }
  299. //-----------------------------------------------------------------------------
  300. int ctkDoubleSpinBox::decimals() const
  301. {
  302. Q_D(const ctkDoubleSpinBox);
  303. return d->SpinBox->decimals();
  304. }
  305. //-----------------------------------------------------------------------------
  306. void ctkDoubleSpinBox::setDecimals(int dec)
  307. {
  308. Q_D(ctkDoubleSpinBox);
  309. dec = qMax(0, dec);
  310. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && dec == this->decimals())
  311. {
  312. return;
  313. }
  314. d->DefaultDecimals = dec;
  315. d->setDecimals(d->DefaultDecimals);
  316. }
  317. //-----------------------------------------------------------------------------
  318. double ctkDoubleSpinBox::round(double value) const
  319. {
  320. Q_D(const ctkDoubleSpinBox);
  321. return QString::number(value, 'f', d->SpinBox->decimals()).toDouble();
  322. }
  323. //-----------------------------------------------------------------------------
  324. QDoubleSpinBox* ctkDoubleSpinBox::spinBox() const
  325. {
  326. Q_D(const ctkDoubleSpinBox);
  327. return d->SpinBox;
  328. }
  329. //-----------------------------------------------------------------------------
  330. void ctkDoubleSpinBox::setValue(double value)
  331. {
  332. Q_D(ctkDoubleSpinBox);
  333. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent)
  334. {
  335. this->setValueIfDifferent(value);
  336. }
  337. else
  338. {
  339. this->setValueAlways(value);
  340. }
  341. }
  342. //-----------------------------------------------------------------------------
  343. void ctkDoubleSpinBox::setValueIfDifferent(double value)
  344. {
  345. Q_D(ctkDoubleSpinBox);
  346. if (! d->compare(this->value(), value))
  347. {
  348. d->SpinBox->setValue(value);
  349. }
  350. }
  351. //-----------------------------------------------------------------------------
  352. void ctkDoubleSpinBox::setValueAlways(double value)
  353. {
  354. Q_D(const ctkDoubleSpinBox);
  355. d->SpinBox->setValue(value);
  356. }
  357. //-----------------------------------------------------------------------------
  358. void ctkDoubleSpinBox::stepUp()
  359. {
  360. Q_D(const ctkDoubleSpinBox);
  361. d->SpinBox->stepUp();
  362. }
  363. //-----------------------------------------------------------------------------
  364. void ctkDoubleSpinBox::stepDown()
  365. {
  366. Q_D(const ctkDoubleSpinBox);
  367. d->SpinBox->stepDown();
  368. }
  369. //-----------------------------------------------------------------------------
  370. ctkDoubleSpinBox::SetMode ctkDoubleSpinBox::setMode() const
  371. {
  372. Q_D(const ctkDoubleSpinBox);
  373. return d->Mode;
  374. }
  375. //-----------------------------------------------------------------------------
  376. void ctkDoubleSpinBox::setSetMode(ctkDoubleSpinBox::SetMode newMode)
  377. {
  378. Q_D(ctkDoubleSpinBox);
  379. d->Mode = newMode;
  380. }
  381. //-----------------------------------------------------------------------------
  382. ctkDoubleSpinBox::DecimalsOptions ctkDoubleSpinBox::decimalsOption()
  383. {
  384. Q_D(const ctkDoubleSpinBox);
  385. return d->DOption;
  386. }
  387. //-----------------------------------------------------------------------------
  388. void ctkDoubleSpinBox::setDecimalsOption(ctkDoubleSpinBox::DecimalsOptions option)
  389. {
  390. Q_D(ctkDoubleSpinBox);
  391. if (d->Mode == ctkDoubleSpinBox::SetIfDifferent && option == d->DOption)
  392. {
  393. return;
  394. }
  395. d->DOption = option;
  396. }
  397. //----------------------------------------------------------------------------
  398. void ctkDoubleSpinBox::setInvertedControls(bool invertedControls)
  399. {
  400. Q_D(ctkDoubleSpinBox);
  401. d->InvertedControls = invertedControls;
  402. d->SpinBox->setInvertedControls(d->InvertedControls);
  403. }
  404. //----------------------------------------------------------------------------
  405. bool ctkDoubleSpinBox::invertedControls() const
  406. {
  407. Q_D(const ctkDoubleSpinBox);
  408. return d->InvertedControls;
  409. }
  410. //-----------------------------------------------------------------------------
  411. bool ctkDoubleSpinBox::eventFilter(QObject* obj, QEvent* event)
  412. {
  413. Q_D(ctkDoubleSpinBox);
  414. if (d->DOption & ctkDoubleSpinBox::UseShortcuts &&
  415. obj == d->SpinBox && event->type() == QEvent::KeyPress)
  416. {
  417. QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
  418. Q_ASSERT(keyEvent);
  419. if (keyEvent->modifiers() & Qt::ControlModifier)
  420. {
  421. if (keyEvent->key() == Qt::Key_Plus
  422. || keyEvent->key() == Qt::Key_Equal)
  423. {
  424. d->setDecimals(this->decimals() + 1);
  425. return true;
  426. }
  427. else if (keyEvent->key() == Qt::Key_Minus)
  428. {
  429. d->setDecimals(this->decimals() - 1);
  430. return true;
  431. }
  432. else if (keyEvent->key() == Qt::Key_0)
  433. {
  434. d->setDecimals(d->DefaultDecimals);
  435. return true;
  436. }
  437. }
  438. return QWidget::eventFilter(obj, event);
  439. }
  440. else
  441. {
  442. // pass the event on to the parent class
  443. return QWidget::eventFilter(obj, event);
  444. }
  445. }