CustusX  15.3.4-beta
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxDoubleWidgets.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 
34 #include "cxDoubleWidgets.h"
35 
36 #include <iostream>
37 #include "cxVector3D.h"
38 #include "cxTypeConversions.h"
39 #include "cxMousePadWidget.h"
40 #include "cxHelperWidgets.h"
41 
42 namespace cx
43 {
44 
46  OptimizedUpdateWidget(parent), mSlider(NULL), mDial(NULL), mSpinBox(NULL), mLabel(NULL), mEdit(NULL), mInfiniteSlider(NULL)
47 {
48  mData = dataInterface;
49  connect(mData.get(), SIGNAL(changed()), this, SLOT(setModified()));
50  this->enableAll(mData->getEnabled());
51 }
52 
54 {
55  mLabel = new QLabel(this);
56  mLabel->setText(mData->getDisplayName());
57 }
58 
60 {
61  mSlider = new DoubleSlider(this);
62  mSlider->setMinimumWidth(50);
63  mSlider->setOrientation(Qt::Horizontal);
64  connect(mSlider, SIGNAL(doubleValueChanged(double)), this, SLOT(doubleValueChanged(double)));
65 }
66 
68 {
69  mDial = new QDial(this);
70  mDial->setMaximumWidth(50);
71  mDial->setMaximumHeight(50);
72  mDial->setNotchesVisible(true);
73  connect(mDial, SIGNAL(valueChanged(int)), this, SLOT(intValueChanged(int)));
74 }
75 
77 {
78  QSize minBarSize = QSize(20, 20);
79  mInfiniteSlider = new MousePadWidget(this, minBarSize);
80  mInfiniteSlider->setFixedYPos(true);
81  connect(mInfiniteSlider, SIGNAL(mouseMoved(QPointF)), this, SLOT(infiniteSliderMouseMoved(QPointF)));
82 }
83 
84 void ScalarInteractionWidget::infiniteSliderMouseMoved(QPointF delta)
85 {
86  double scale = mData->getValueRange().range() / 2.0;
87  // double scale = M_PI_2;
88  double factor = scale * delta.x();
89  double current = mData->getValue();
90  mData->setValue(current + factor);
91 }
92 
94 {
95  mEdit = new DoubleLineEdit(this);
96  connect(mEdit, SIGNAL(editingFinished()), this, SLOT(textEditedSlot()));
97 }
98 
100 {
101  mSpinBox = new QDoubleSpinBox(this);
102  connect(mSpinBox, SIGNAL(valueChanged(double)), this, SLOT(doubleValueChanged(double)));
103 }
104 
109 {
110  QHBoxLayout* topLayout = new QHBoxLayout;
111  topLayout->setMargin(0);
112  this->setLayout(topLayout);
113 
114  if (mLabel)
115  topLayout->addWidget(mLabel, 0);
116  if (mEdit)
117  topLayout->addWidget(mEdit, 0);
118  if (mSpinBox)
119  topLayout->addWidget(mSpinBox, 0);
120  if (mDial)
121  topLayout->addWidget(mDial, 0);
122  if (mSlider)
123  topLayout->addWidget(mSlider, 1);
124  if (mInfiniteSlider)
125  topLayout->addWidget(mInfiniteSlider, 1);
126 }
127 
131 void ScalarInteractionWidget::addToGridLayout(QGridLayout* gridLayout, int row)
132 {
133  //Since SliderGroupWidget (this) is a widget we need to add this.
134  //If not we will get an invisible widget on top of all the other widgets of the parent
135  gridLayout->addLayout(mergeWidgetsIntoHBoxLayout(mLabel, addDummyMargin(this)), row, 0);
136 
137  QHBoxLayout* controlsLayout = new QHBoxLayout;
138  controlsLayout->setSpacing(0);
139  controlsLayout->setMargin(0);
140  gridLayout->addLayout(controlsLayout, row, 1);
141 
142 
143  if (mEdit)
144  controlsLayout->addWidget(mEdit);
145  if (mSpinBox)
146  controlsLayout->addWidget(mSpinBox);
147  if (mDial)
148  gridLayout->addWidget(mDial, row, 2);
149  if (mSlider)
150  controlsLayout->addWidget(mSlider, 1);
151  if (mInfiniteSlider)
152  controlsLayout->addWidget(mInfiniteSlider, 1);
153 }
154 
155 void ScalarInteractionWidget::build(QGridLayout* gridLayout, int row)
156 {
157  if (gridLayout)
158  this->addToGridLayout(gridLayout, row);
159  else
160  this->addToOwnLayout();
161 
162  this->setModified();
163 }
164 
165 
166 void ScalarInteractionWidget::intValueChanged(int val)
167 {
168  this->doubleValueChanged(val/100.0);
169 }
170 
171 
172 void ScalarInteractionWidget::doubleValueChanged(double val)
173 {
174  val = mData->convertDisplay2Internal(val);
175 
176  if (similar(val, mData->getValue()))
177  return;
178 
179  mData->setValue(val);
180 }
181 
182 void ScalarInteractionWidget::textEditedSlot()
183 {
184  if (!mEdit)
185  return;
186 
187  double defVal = mData->convertInternal2Display(mData->getValue()); // defval in display space
188  double newVal = mData->convertDisplay2Internal(mEdit->getDoubleValue(defVal)); // newval iin internal space
189 
190  if (similar(newVal, mData->getValue()))
191  return;
192 
193  mData->setValue(newVal);
194 }
195 
196 //void ScalarInteractionWidget::setModified()
197 //{
198 // OptimizedUpdateWidget::setModified();
199 // // Problem: If one of the sliders are visible, paint() is not called.
200 // // Force repaint here.
201 // //
202 // // Possible solution: this is obscured by the slider,
203 // // but repaint goes to the children. Maybe design is flawed and we need to
204 // // listen to the children as well?
207 //}
208 
210 {
211  this->enableAll(mData->getEnabled());
212 
213 // std::cout << "ScalarInteractionWidget::prePaintEvent() " << this << " " << mData->getDisplayName() << std::endl;
214  DoubleRange range = mData->getValueRange();
215  DoubleRange dRange(mData->convertInternal2Display(range.min()), mData->convertInternal2Display(range.max()),
216  mData->convertInternal2Display(range.step()));
217 
218  if (mSlider)
219  {
220  mSlider->blockSignals(true);
221  mSlider->setDoubleRange(dRange); // in case the image is changed
222  mSlider->setDoubleValue(mData->convertInternal2Display(mData->getValue()));
223  mSlider->setToolTip(mData->getHelp());
224  mSlider->blockSignals(false);
225  }
226 
227  if (mEdit)
228  {
229  mEdit->blockSignals(true);
230  mEdit->setDoubleValue(mData->convertInternal2Display(mData->getValue()));
231  mEdit->setToolTip(mData->getHelp());
232  mEdit->blockSignals(false);
233  }
234 
235  if (mSpinBox)
236  {
237  mSpinBox->blockSignals(true);
238  mSpinBox->setRange(dRange.min(), dRange.max()); // in case the image is changed
239  mSpinBox->setSingleStep(dRange.step());
240  mSpinBox->setDecimals(mData->getValueDecimals());
241  mSpinBox->setValue(mData->convertInternal2Display(mData->getValue()));
242  mSpinBox->setToolTip(mData->getHelp());
243  mSpinBox->blockSignals(false);
244  }
245 
246  if (mDial)
247  {
248  mDial->blockSignals(true);
249  mDial->setContentsMargins(0,0,0,0);
250  mDial->setRange(dRange.min()*100, dRange.max()*100);
251  mDial->setSingleStep(dRange.step()*100);
252  mDial->setValue(mData->convertInternal2Display(mData->getValue())*100);
253  mDial->setToolTip(mData->getHelp());
254  mDial->blockSignals(false);
255  }
256 
257  if (mLabel)
258  {
259  mLabel->setToolTip(mData->getHelp());
260  }
261 }
262 
263 void ScalarInteractionWidget::enableAll(bool enable)
264 {
265  if(this)
266  QWidget::setEnabled(enable);
267  if(mSlider)
268  mSlider->setEnabled(enable);
269  if(mSpinBox)
270  mSpinBox->setEnabled(enable);
271  if(mLabel)
272  mLabel->setEnabled(enable);
273  if(mEdit)
274  mEdit->setEnabled(enable);
275  if(mInfiniteSlider)
276  mInfiniteSlider->setEnabled(enable);
277 }
278 
279 // --------------------------------------------------------
280 // --------------------------------------------------------
281 
282 // --------------------------------------------------------
283 // --------------------------------------------------------
284 
285 
287 {
288  QSize size = QLineEdit::minimumSizeHint();
289  size.setWidth(size.height() * 3);
290  return size;
291 }
292 
294 {
295  QSize size = QLineEdit::minimumSizeHint();
296  return size;
297 }
298 
299 // --------------------------------------------------------
300 // --------------------------------------------------------
301 
302 SliderGroupWidget::SliderGroupWidget(QWidget* parent, DoublePropertyBasePtr dataInterface, QGridLayout* gridLayout,
303  int row) :
304  ScalarInteractionWidget(parent, dataInterface)
305 {
306  this->enableLabel();
307  this->enableSlider();
308  this->enableEdit();
309 
310  this->build(gridLayout, row);
311 }
312 
313 // --------------------------------------------------------
314 // --------------------------------------------------------
315 
317  QGridLayout* gridLayout, int row) :
318  ScalarInteractionWidget(parent, dataInterface)
319 {
320  this->enableLabel();
321  this->enableSpinBox();
322 
323  this->build(gridLayout, row);
324 }
325 
326 // --------------------------------------------------------
327 
329  QGridLayout* gridLayout, int row) :
330  ScalarInteractionWidget(parent, dataInterface)
331 {
332  this->enableLabel();
333  this->enableSpinBox();
334  this->enableSlider();
335 
336  this->build(gridLayout, row);
337 }
338 // --------------------------------------------------------
340  QGridLayout* gridLayout, int row) :
341  ScalarInteractionWidget(parent, dataInterface)
342 {
343  this->enableLabel();
344  this->enableSpinBox();
345  this->enableDial();
346 
347  this->build(gridLayout, row);
348 }
349 
350 // --------------------------------------------------------
351 
353  DoublePropertyBasePtr dataInterface, QGridLayout* gridLayout, int row) :
354  ScalarInteractionWidget(parent, dataInterface)
355 {
356  this->enableLabel();
357  this->enableSpinBox();
358  this->enableInfiniteSlider();
359 
360  this->build(gridLayout, row);
361 }
362 
363 } // namespace cx
QWidget * addDummyMargin(QWidget *widget)
void setDoubleValue(double val)
void build(QGridLayout *gridLayout=0, int row=0)
SpinBoxGroupWidget(QWidget *parent, DoublePropertyBasePtr, QGridLayout *gridLayout=0, int row=0)
double max() const
maximum value
Definition: cxDoubleRange.h:70
Utility class for describing a bounded numeric range.
Definition: cxDoubleRange.h:53
DoublePropertyBasePtr mData
A touchpad-friendly area for performing 1D/2D scroll operations.
SliderGroupWidget(QWidget *parent, DoublePropertyBasePtr, QGridLayout *gridLayout=0, int row=0)
SpinBoxInfiniteSliderGroupWidget(QWidget *parent, DoublePropertyBasePtr, QGridLayout *gridLayout=0, int row=0)
Composite widget for scalar data manipulation.
SpinBoxAndSliderGroupWidget(QWidget *parent, DoublePropertyBasePtr, QGridLayout *gridLayout=0, int row=0)
bool similar(const DoubleBoundingBox3D &a, const DoubleBoundingBox3D &b, double tol)
QHBoxLayout * mergeWidgetsIntoHBoxLayout(QWidget *first, QWidget *second)
virtual QSize sizeHint() const
double getDoubleValue(double defVal=0.0) const
void setDoubleRange(const DoubleRange &range)
ScalarInteractionWidget(QWidget *parent, DoublePropertyBasePtr)
double min() const
minimum value
Definition: cxDoubleRange.h:66
Custom widget for display of double-valued data.
boost::shared_ptr< class DoublePropertyBase > DoublePropertyBasePtr
double step() const
smallest reasonable increment
Definition: cxDoubleRange.h:74
void setFixedYPos(bool on)
A QLineEdit specialized to deal with double data.
void setDoubleValue(double val)
void addToGridLayout(QGridLayout *gridLayout=0, int row=0)
SpinBoxAndDialGroupWidget(QWidget *parent, DoublePropertyBasePtr, QGridLayout *gridLayout=0, int row=0)
Interface for all classes following the modified/prepaint paradigm.
virtual QSize minimumSizeHint() const