Преглед изворни кода

Merge branch 'master', remote branch 'origin' into DICOMRetrieve

Daniel Blezek пре 15 година
родитељ
комит
286bf7f2da

+ 45 - 0
Applications/ctkDICOMRetrieve/CMakeLists.txt

@@ -0,0 +1,45 @@
+PROJECT(ctkDICOMRetrieve)
+
+#
+# See CTK/CMake/ctkMacroBuildApp.cmake for details
+#
+  
+# Source files
+SET(KIT_SRCS
+  ctkDICOMRetrieveMain.cpp
+  )
+
+# Headers that should run through moc
+SET(KIT_MOC_SRCS
+  )
+
+# UI files
+SET(KIT_UI_FORMS
+)
+
+# Resources
+SET(KIT_resources
+)
+
+# Target libraries - See CMake/ctkMacroGetTargetLibraries.cmake
+# The following macro will read the target libraries from the file 'target_libraries.cmake'
+ctkMacroGetTargetLibraries(KIT_target_libraries)
+
+# Additional directories to include - Not that CTK_INCLUDE_LIBRARIES is already included
+SET(KIT_include_directories
+  )
+
+ctkMacroBuildApp(
+  NAME ${PROJECT_NAME}
+  INCLUDE_DIRECTORIES ${KIT_include_directories}
+  SRCS ${KIT_SRCS}
+  MOC_SRCS ${KIT_MOC_SRCS}
+  UI_FORMS ${KIT_UI_FORMS}
+  TARGET_LIBRARIES ${KIT_target_libraries}
+  RESOURCES ${KIT_resources}
+  )
+
+# Testing
+IF(BUILD_TESTING)
+  #ADD_SUBDIRECTORY(Testing)
+ENDIF(BUILD_TESTING)

+ 102 - 0
Applications/ctkDICOMRetrieve/ctkDICOMRetrieveMain.cpp

@@ -0,0 +1,102 @@
+/*=========================================================================
+
+  Library:   CTK
+ 
+  Copyright (c) 2010  
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ 
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QTextStream>
+
+// CTK includes
+#include <ctkDICOMRetrieve.h>
+#include <ctkDICOM.h>
+#include "ctkLogger.h"
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+void print_usage()
+{
+  std::cerr << "Usage:\n";
+  std::cerr << "  ctkDICOMRetrieve SeriesUID OutputDirectory callingAETitle callingPort calledAETitle host calledPort\n";
+  return;
+}
+
+
+/**
+  *
+*/
+int main(int argc, char** argv)
+{
+  ctkLogger::configure();
+  ctkLogger logger ( "org.commontk.dicom.DICOMRetieveApp" );
+  logger.setDebug();
+
+  if (argc < 8)
+  {
+    print_usage();
+    return EXIT_FAILURE;
+  }
+
+  QApplication app(argc, argv);
+  QTextStream out(stdout);
+
+  QString SeriesUID ( argv[1] );
+  QDir OutputDirectory ( argv[1] );
+  QString CallingAETitle ( argv[3] ); 
+  bool ok;
+  int CallingPort = QString ( argv[4] ).toInt ( &ok );
+  if ( !ok )
+    {
+    std::cerr << "Could not convert " << argv[4] << " to an integer for the callingPort" << std::endl;
+    print_usage();
+    return EXIT_FAILURE;
+    }
+
+  QString CalledAETitle ( argv[5] ); 
+  QString Host ( argv[6] ); 
+  int CalledPort = QString ( argv[7] ).toInt ( &ok );
+  if ( !ok )
+    {
+    std::cerr << "Could not convert " << argv[7] << " to an integer for the calledPoint" << std::endl;
+    print_usage();
+    return EXIT_FAILURE;
+    }
+
+  ctkDICOMRetrieve retrieve;
+  retrieve.setCallingAETitle ( CallingAETitle );
+  retrieve.setCallingPort ( CallingPort );
+  retrieve.setCalledAETitle ( CalledAETitle );
+  retrieve.setCalledPort ( CalledPort );
+  retrieve.setHost ( Host );
+
+  logger.info ( "Starting to retrieve" );
+  try
+    {
+    retrieve.retrieveSeries ( SeriesUID, QDir ( OutputDirectory ) );
+    }
+  catch (std::exception e)
+    {
+    logger.error ( "Retrieve failed" );
+    return EXIT_FAILURE;
+    }
+  logger.info ( "Retrieve success" );
+  return EXIT_SUCCESS;
+}

+ 9 - 0
Applications/ctkDICOMRetrieve/target_libraries.cmake

@@ -0,0 +1,9 @@
+#
+# See CMake/ctkMacroGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK application.
+# 
+
+SET(target_libraries
+  CTKDICOMCore
+  )

+ 18 - 17
Libs/Visualization/VTK/Core/Testing/Cpp/ctkVTKConnectionTest1.cpp

@@ -19,7 +19,8 @@
 #include <vtkSmartPointer.h>
 #include <vtkTimerLog.h>
 
-void doit(vtkObject* obj, unsigned long event, void* client_data, void* param)
+void doit(vtkObject* vtkNotUsed(obj), unsigned long vtkNotUsed(event),
+          void* client_data, void* vtkNotUsed(param))
 {
   QTimer* t = reinterpret_cast<QTimer*>(client_data);
   t->stop();
@@ -28,10 +29,10 @@ void doit(vtkObject* obj, unsigned long event, void* client_data, void* param)
 int ctkVTKConnectionTest1( int argc, char * argv [] )
 {
   QApplication app(argc, argv);
-  
+
   int objects = 1000;
   int events = 100;
-  
+
   vtkObject* obj = vtkObject::New();
   vtkObject* obj2 = vtkObject::New();
   vtkObject* obj3 = vtkObject::New();
@@ -41,7 +42,7 @@ int ctkVTKConnectionTest1( int argc, char * argv [] )
   QObject*   topObject = new QObject(0);
   // It could be here any kind of Qt object, QTimer has a no op slot so use it
   QTimer*    slotObject = new QTimer(topObject);
-  
+
   for (int i = 0; i < objects; ++i)
     {
     ctkVTKConnection* connection = new ctkVTKConnection(topObject);
@@ -52,7 +53,7 @@ int ctkVTKConnectionTest1( int argc, char * argv [] )
     vtkCallbackCommand* callback = vtkCallbackCommand::New();
     callback->SetClientData(slotObject);
     callback->SetCallback(doit);
-    
+
     obj2->AddObserver(vtkCommand::ModifiedEvent, callback);
     callback->Delete();
 
@@ -65,29 +66,29 @@ int ctkVTKConnectionTest1( int argc, char * argv [] )
     connection3->observeDeletion(false);
     connection3->setup(obj4, vtkCommand::ModifiedEvent,
                       new QTimer(topObject), SLOT(stop()));
-    
+
     ctkVTKConnection* connection4 = new ctkVTKConnection(topObject);
     connection4->observeDeletion(true);
     connection4->setup(obj5, vtkCommand::ModifiedEvent,
                       slotObject, SLOT(stop()));
     }
 
-  vtkSmartPointer<vtkTimerLog> timerLog = 
+  vtkSmartPointer<vtkTimerLog> timerLog =
     vtkSmartPointer<vtkTimerLog>::New();
-  
+
   timerLog->StartTimer();
   for (int i = 0; i < events; ++i)
     {
     obj->Modified();
     }
   timerLog->StopTimer();
-  
+
   double t1 = timerLog->GetElapsedTime();
   qDebug() << events << "events listened by" << objects << "objects (ctkVTKConnection): " << t1 << "seconds";
 
   // Callback only
 
-  vtkSmartPointer<vtkTimerLog> timerLog2 = 
+  vtkSmartPointer<vtkTimerLog> timerLog2 =
     vtkSmartPointer<vtkTimerLog>::New();
   timerLog2->StartTimer();
   for (int i = 0; i < events; ++i)
@@ -101,29 +102,29 @@ int ctkVTKConnectionTest1( int argc, char * argv [] )
   double ratio = t1 / t2;
   qDebug() << "ctkVTKConnection / vtkCallbacks: " << ratio;
 
-  vtkSmartPointer<vtkTimerLog> timerLog3 = 
+  vtkSmartPointer<vtkTimerLog> timerLog3 =
     vtkSmartPointer<vtkTimerLog>::New();
-  
+
   timerLog3->StartTimer();
   for (int i = 0; i < events; ++i)
     {
     obj3->Modified();
     }
   timerLog3->StopTimer();
-  
+
   double t3 = timerLog3->GetElapsedTime();
   qDebug() << events << "events listened by" << objects << "objects (observed ctkVTKConnection): " << t3 << "seconds";
 
-  vtkSmartPointer<vtkTimerLog> timerLog4 = 
+  vtkSmartPointer<vtkTimerLog> timerLog4 =
     vtkSmartPointer<vtkTimerLog>::New();
-  
+
   timerLog4->StartTimer();
   for (int i = 0; i < events; ++i)
     {
     obj4->Modified();
     }
   timerLog4->StopTimer();
-  
+
   double t4 = timerLog4->GetElapsedTime();
   qDebug() << events << "events listened by" << objects << "objects (ctkVTKConnection, 1-1): " << t4 << "seconds";
 
@@ -136,7 +137,7 @@ int ctkVTKConnectionTest1( int argc, char * argv [] )
 
   obj4->Delete();
   obj5->Delete();
-  
+
   // Ideally a ratio ~= 1. but the ratio can be more in Debug mode... up to 2.
   if (ratio > 2.)
     {

+ 3 - 0
Libs/Widgets/CMakeLists.txt

@@ -40,6 +40,8 @@ SET(KIT_SRCS
   ctkDoubleSlider.h
   ctkDynamicSpacer.cpp
   ctkDynamicSpacer.h
+  ctkFileDialog.cpp
+  ctkFileDialog.h
   ctkFittedTextBrowser.cpp
   ctkFittedTextBrowser.h
   ctkMatrixWidget.cpp
@@ -88,6 +90,7 @@ SET(KIT_MOC_SRCS
   ctkDoubleRangeSlider.h
   ctkDoubleSlider.h
   ctkDynamicSpacer.h
+  ctkFileDialog.h
   ctkFittedTextBrowser.h
   ctkMatrixWidget.h
   ctkMenuButton.h

+ 8 - 7
Libs/Widgets/Resources/UI/ctkRangeWidget.ui

@@ -7,9 +7,15 @@
     <x>0</x>
     <y>0</y>
     <width>302</width>
-    <height>20</height>
+    <height>27</height>
    </rect>
   </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
   <property name="windowTitle">
    <string>ctkSliderSpinBoxWidget</string>
   </property>
@@ -34,13 +40,8 @@
  </widget>
  <customwidgets>
   <customwidget>
-   <class>ctkRangeSlider</class>
-   <extends>QSlider</extends>
-   <header>ctkRangeSlider.h</header>
-  </customwidget>
-  <customwidget>
    <class>ctkDoubleRangeSlider</class>
-   <extends>ctkRangeSlider</extends>
+   <extends>QWidget</extends>
    <header>ctkDoubleRangeSlider.h</header>
   </customwidget>
  </customwidgets>

+ 6 - 0
Libs/Widgets/Resources/UI/ctkSliderSpinBoxWidget.ui

@@ -10,6 +10,12 @@
     <height>32</height>
    </rect>
   </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
   <property name="windowTitle">
    <string>ctkSliderSpinBoxWidget</string>
   </property>

+ 2 - 0
Libs/Widgets/Testing/Cpp/CMakeLists.txt

@@ -12,6 +12,7 @@ CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cxx
   ctkCoordinatesWidgetTest1.cpp
   ctkDoubleRangeSliderTest1.cpp
   ctkDoubleSliderTest1.cpp
+  ctkFileDialogTest1.cpp
   ctkFittedTextBrowserTest1.cpp
   ctkMatrixWidgetTest1.cpp
   ctkRangeSliderTest1.cpp
@@ -53,6 +54,7 @@ SIMPLE_TEST( ctkComboBoxTest1 )
 SIMPLE_TEST( ctkCoordinatesWidgetTest1 )
 SIMPLE_TEST( ctkDoubleRangeSliderTest1 )
 SIMPLE_TEST( ctkDoubleSliderTest1 )
+SIMPLE_TEST( ctkFileDialogTest1 )
 SIMPLE_TEST( ctkFittedTextBrowserTest1 )
 SIMPLE_TEST( ctkMatrixWidgetTest1 )
 SIMPLE_TEST( ctkRangeSliderTest1 )

+ 61 - 0
Libs/Widgets/Testing/Cpp/ctkFileDialogTest1.cpp

@@ -0,0 +1,61 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QCheckBox>
+
+// CTK includes
+#include "ctkFileDialog.h"
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+
+//-----------------------------------------------------------------------------
+int ctkFileDialogTest1(int argc, char * argv [] )
+{
+  QApplication app(argc, argv);
+
+  ctkFileDialog fileDialog;
+  fileDialog.setFileMode(QFileDialog::AnyFile);
+  fileDialog.setNameFilter("Images (*.png *.xpm *.jpg)");
+  fileDialog.setViewMode(QFileDialog::Detail);
+  QCheckBox* checkBox = new QCheckBox;
+  fileDialog.setBottomWidget(checkBox, "Foo Bar:");
+  if (checkBox != fileDialog.bottomWidget())
+    {
+    return EXIT_FAILURE;
+    }
+  // the following is only in interactive mode
+  if (argc < 2 || QString(argv[1]) != "-I" )
+    {
+    return EXIT_SUCCESS;
+    }
+  QObject::connect(checkBox, SIGNAL(toggled(bool)),
+                   &fileDialog, SLOT(setAcceptButtonEnable(bool)));
+  fileDialog.setAcceptButtonEnable(false);
+  if (!fileDialog.exec())
+    {
+    return EXIT_FAILURE;
+    }
+  return EXIT_SUCCESS;
+
+}

+ 5 - 0
Libs/Widgets/ctkCollapsibleButton.h

@@ -34,6 +34,11 @@ class QStyleOptionButton;
 
 /// Description
 /// A Collapsible widget that show/hide its children depending on its checked/collapsed properties
+/// Warning: As ctkCollapsibleButton forces the Visiblity of its children to
+/// true when it get expanded, any Visibility property is lost. All the widgets
+/// will be visible. To avoid this behavior, use an intermediate widget that
+/// contains all the children (they would become grandchildren and their
+/// will remain relative to their parent: ctkCollapsibleButton's unique child.
 class CTK_WIDGETS_EXPORT ctkCollapsibleButton : public QAbstractButton
 {
   Q_OBJECT

+ 154 - 0
Libs/Widgets/ctkFileDialog.cpp

@@ -0,0 +1,154 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// QT includes
+#include <QDebug>
+#include <QDialogButtonBox>
+#include <QEvent>
+#include <QGridLayout>
+#include <QLabel>
+#include <QPushButton>
+
+// CTK includes
+#include "ctkFileDialog.h"
+
+//------------------------------------------------------------------------------
+class ctkFileDialogPrivate: public ctkPrivate<ctkFileDialog>
+{
+public:
+  ctkFileDialogPrivate();
+  void init();
+  QPushButton* acceptButton()const;
+  bool AcceptButtonEnable;
+  bool AcceptButtonState;
+  bool IgnoreEvent;
+};
+
+//------------------------------------------------------------------------------
+ctkFileDialogPrivate::ctkFileDialogPrivate()
+{
+  this->IgnoreEvent = false;
+  this->AcceptButtonEnable = true;
+  this->AcceptButtonState = true;
+}
+
+//------------------------------------------------------------------------------
+void ctkFileDialogPrivate::init()
+{
+  CTK_P(ctkFileDialog);
+  QPushButton* button = this->acceptButton();
+  Q_ASSERT(button);
+  this->AcceptButtonState =
+    button->isEnabledTo(qobject_cast<QWidget*>(button->parent()));
+  button->installEventFilter(p);
+}
+
+//------------------------------------------------------------------------------
+QPushButton* ctkFileDialogPrivate::acceptButton()const
+{
+  CTK_P(const ctkFileDialog);
+  QDialogButtonBox* buttonBox = p->findChild<QDialogButtonBox*>();
+  Q_ASSERT(buttonBox);
+  QDialogButtonBox::StandardButton button =
+    (p->acceptMode() == QFileDialog::AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
+  return buttonBox->button(button);
+}
+
+//------------------------------------------------------------------------------
+ctkFileDialog::ctkFileDialog(QWidget *parentWidget,
+              const QString &caption,
+              const QString &directory,
+              const QString &filter)
+  :QFileDialog(parentWidget, caption, directory, filter)
+{
+  CTK_INIT_PRIVATE(ctkFileDialog);
+  CTK_D(ctkFileDialog);
+  d->init();
+}
+
+//------------------------------------------------------------------------------
+ctkFileDialog::~ctkFileDialog()
+{
+}
+
+//------------------------------------------------------------------------------
+void ctkFileDialog::setBottomWidget(QWidget* widget, const QString& label)
+{
+  QGridLayout* gridLayout = qobject_cast<QGridLayout*>(this->layout());
+  QWidget* oldBottomWidget = this->bottomWidget();
+  if (oldBottomWidget)
+    {
+    if (oldBottomWidget == widget)
+      {
+      return;
+      }
+    gridLayout->removeWidget(oldBottomWidget);
+    delete oldBottomWidget;
+    }
+  if (widget == 0)
+    {
+    return;
+    }
+  if (!label.isEmpty())
+    {
+    gridLayout->addWidget(new QLabel(label), 4, 0);
+    gridLayout->addWidget(widget,4, 1,1, 1);
+    }
+  else
+    {
+    gridLayout->addWidget(widget,4, 0,1, 2);
+    }
+  QDialogButtonBox* buttonBox = this->findChild<QDialogButtonBox*>();
+  Q_ASSERT(buttonBox);
+  gridLayout->removeWidget(buttonBox);
+  gridLayout->addWidget(buttonBox, 2, 2, 3, 1);
+}
+
+//------------------------------------------------------------------------------
+QWidget* ctkFileDialog::bottomWidget()const
+{
+  QGridLayout* gridLayout = qobject_cast<QGridLayout*>(this->layout());
+  QLayoutItem* item = gridLayout->itemAtPosition(4,1);
+  return item ? item->widget() : 0;
+}
+
+//------------------------------------------------------------------------------
+void ctkFileDialog::setAcceptButtonEnable(bool enable)
+{
+  CTK_D(ctkFileDialog);
+  d->AcceptButtonEnable = enable;
+  d->acceptButton()->setEnabled(d->AcceptButtonEnable && d->AcceptButtonState);
+}
+
+//------------------------------------------------------------------------------
+bool ctkFileDialog::eventFilter(QObject *obj, QEvent *event)
+{
+  CTK_D(ctkFileDialog);
+  QPushButton* button = d->acceptButton();
+  if (obj == button && event->type() == QEvent::EnabledChange &&
+      !d->IgnoreEvent)
+    {
+    d->IgnoreEvent = true;
+    d->AcceptButtonState = button->isEnabledTo(qobject_cast<QWidget*>(button->parent()));
+    button->setEnabled(d->AcceptButtonEnable && d->AcceptButtonState);
+    d->IgnoreEvent = false;
+    }
+  return QFileDialog::eventFilter(obj, event);
+}

+ 58 - 0
Libs/Widgets/ctkFileDialog.h

@@ -0,0 +1,58 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 2010  Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+#ifndef __ctkFileDialog_h
+#define __ctkFileDialog_h
+
+// Qt includes
+#include <QFileDialog>
+
+// CTK includes
+#include <ctkPimpl.h>
+#include "CTKWidgetsExport.h"
+
+class ctkFileDialogPrivate;
+
+class CTK_WIDGETS_EXPORT ctkFileDialog : public QFileDialog
+{
+  Q_OBJECT
+
+public:
+  // Superclass typedef
+  typedef QFileDialog Superclass;
+  // Constructors
+  explicit ctkFileDialog(QWidget *parent = 0,
+              const QString &caption = QString(),
+              const QString &directory = QString(),
+              const QString &filter = QString());
+  virtual ~ctkFileDialog();
+
+  void setBottomWidget(QWidget* widget, const QString& label=QString());
+  QWidget* bottomWidget()const;
+
+  bool eventFilter(QObject *obj, QEvent *event);
+public slots:
+  void setAcceptButtonEnable(bool enable);
+
+private:
+  CTK_DECLARE_PRIVATE(ctkFileDialog);
+};
+
+#endif

+ 1 - 0
Libs/Widgets/ctkRangeSlider.cpp

@@ -423,6 +423,7 @@ void ctkRangeSlider::paintEvent( QPaintEvent* )
 
   QStylePainter painter(this);
   option.subControls = QStyle::SC_SliderGroove;
+  option.sliderPosition = this->minimum(); // don't highlight the SliderGroove
   painter.drawComplexControl(QStyle::CC_Slider, option);
 
   option.sliderPosition = d->m_MinimumPosition;

+ 10 - 0
Libs/Widgets/ctkRangeWidget.cpp

@@ -251,6 +251,16 @@ double ctkRangeWidget::previousSliderPosition()
 */
 
 // --------------------------------------------------------------------------
+void ctkRangeWidget::values(double &minValue, double &maxValue)const
+{
+  CTK_D(const ctkRangeWidget);
+  Q_ASSERT(d->equal(d->Slider->minimumValue(), d->MinimumSpinBox->value()));
+  Q_ASSERT(d->equal(d->Slider->maximumValue(), d->MaximumSpinBox->value()));
+  minValue = d->Changing ? d->MinimumValueBeforeChange : d->Slider->minimumValue();
+  maxValue = d->Changing ? d->MaximumValueBeforeChange : d->Slider->maximumValue();
+}
+
+// --------------------------------------------------------------------------
 double ctkRangeWidget::minimumValue()const
 {
   CTK_D(const ctkRangeWidget);

+ 5 - 0
Libs/Widgets/ctkRangeWidget.h

@@ -95,6 +95,11 @@ public:
   double maximumValue()const;
 
   ///
+  /// Utility function that returns both values at the same time
+  /// Returns minimumValue and maximumValue
+  void values(double &minValue, double &maxValue)const;
+
+  ///
   /// This property holds the single step.
   /// The smaller of two natural steps that the
   /// slider provides and typically corresponds to the