Bläddra i källkod

Merge branch 'transfer_function_editors'

* transfer_function_editors:
  Synchronize the ranges in ctkVTKVolumePropertyWidget
  Add color to the opacity control points
  Synchronize Opacity and Colors range
  Support custom range in ctkVTKThresholdWidget
  Support custom bounds in ctkVTKChartViews
  Add ctkVTKThresholdWidget
Julien Finet 14 år sedan
förälder
incheckning
a63094f8ef

+ 4 - 0
Libs/Visualization/VTK/Widgets/CMakeLists.txt

@@ -38,6 +38,8 @@ SET(KIT_SRCS
   ctkVTKSurfaceMaterialPropertyWidget.h
   ctkVTKTextPropertyWidget.cpp
   ctkVTKTextPropertyWidget.h
+  ctkVTKThresholdWidget.cpp
+  ctkVTKThresholdWidget.h
   ctkVTKThumbnailView.cpp
   ctkVTKThumbnailView.h
   )
@@ -59,6 +61,7 @@ SET(KIT_MOC_SRCS
   ctkVTKSliceView_p.h
   ctkVTKSurfaceMaterialPropertyWidget.h
   ctkVTKTextPropertyWidget.h
+  ctkVTKThresholdWidget.h
   ctkVTKThumbnailView.h
   )
 
@@ -66,6 +69,7 @@ SET(KIT_MOC_SRCS
 SET(KIT_UI_FORMS
   Resources/UI/ctkVTKScalarBarWidget.ui
   Resources/UI/ctkVTKTextPropertyWidget.ui
+  Resources/UI/ctkVTKThresholdWidget.ui
 )
 
 # Resources

+ 3 - 0
Libs/Visualization/VTK/Widgets/Plugins/CMakeLists.txt

@@ -27,6 +27,8 @@ SET(PLUGIN_SRCS
   ctkVTKSurfaceMaterialPropertyWidgetPlugin.h
   ctkVTKTextPropertyWidgetPlugin.cpp
   ctkVTKTextPropertyWidgetPlugin.h
+  ctkVTKThresholdWidgetPlugin.cpp
+  ctkVTKThresholdWidgetPlugin.h
   )
 
 # Headers that should run through moc
@@ -40,6 +42,7 @@ SET(PLUGIN_MOC_SRCS
   ctkVTKSliceViewPlugin.h
   ctkVTKSurfaceMaterialPropertyWidgetPlugin.h
   ctkVTKTextPropertyWidgetPlugin.h
+  ctkVTKThresholdWidgetPlugin.h
   )
   
 IF(CTK_USE_CHARTS)

+ 64 - 0
Libs/Visualization/VTK/Widgets/Plugins/ctkVTKThresholdWidgetPlugin.cpp

@@ -0,0 +1,64 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 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.
+
+=========================================================================*/
+
+// CTK includes
+#include "ctkVTKThresholdWidget.h"
+#include "ctkVTKThresholdWidgetPlugin.h"
+
+//-----------------------------------------------------------------------------
+ctkVTKThresholdWidgetPlugin
+::ctkVTKThresholdWidgetPlugin(QObject *parentObject)
+ : QObject(parentObject)
+{
+}
+
+//-----------------------------------------------------------------------------
+QWidget *ctkVTKThresholdWidgetPlugin::createWidget(QWidget *parentWidget)
+{
+  ctkVTKThresholdWidget* newWidget =
+    new ctkVTKThresholdWidget(parentWidget);
+  return newWidget;
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKThresholdWidgetPlugin::domXml() const
+{
+  return "<widget class=\"ctkVTKThresholdWidget\" \
+          name=\"Threshold\">\n"
+          "</widget>\n";
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKThresholdWidgetPlugin::includeFile() const
+{
+  return "ctkVTKThresholdWidget.h";
+}
+
+//-----------------------------------------------------------------------------
+bool ctkVTKThresholdWidgetPlugin::isContainer() const
+{
+  return false;
+}
+
+//-----------------------------------------------------------------------------
+QString ctkVTKThresholdWidgetPlugin::name() const
+{
+  return "ctkVTKThresholdWidget";
+}

+ 43 - 0
Libs/Visualization/VTK/Widgets/Plugins/ctkVTKThresholdWidgetPlugin.h

@@ -0,0 +1,43 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 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 __ctkVTKThresholdWidgetPlugin_h
+#define __ctkVTKThresholdWidgetPlugin_h
+
+// CTK includes
+#include "ctkVTKWidgetsAbstractPlugin.h"
+
+class CTK_VISUALIZATION_VTK_WIDGETS_PLUGINS_EXPORT ctkVTKThresholdWidgetPlugin :
+  public QObject,
+  public ctkVTKWidgetsAbstractPlugin
+{
+  Q_OBJECT
+
+public:
+  ctkVTKThresholdWidgetPlugin(QObject *parent = 0);
+
+  QWidget *createWidget(QWidget *parent);
+  QString domXml() const;
+  QString includeFile() const;
+  bool isContainer() const;
+  QString name() const;
+};
+
+#endif

+ 2 - 0
Libs/Visualization/VTK/Widgets/Plugins/ctkVTKWidgetsPlugins.h

@@ -38,6 +38,7 @@
 #include "ctkVTKSliceViewPlugin.h"
 #include "ctkVTKSurfaceMaterialPropertyWidgetPlugin.h"
 #include "ctkVTKTextPropertyWidgetPlugin.h"
+#include "ctkVTKThresholdWidgetPlugin.h"
 
 /// \class Group the plugins in one library
 class CTK_VISUALIZATION_VTK_WIDGETS_PLUGINS_EXPORT ctkVTKWidgetsPlugins :
@@ -63,6 +64,7 @@ public:
     plugins << new ctkVTKSliceViewPlugin;
     plugins << new ctkVTKSurfaceMaterialPropertyWidgetPlugin;
     plugins << new ctkVTKTextPropertyWidgetPlugin;
+    plugins << new ctkVTKThresholdWidgetPlugin;
     return plugins;
     }
 };

+ 72 - 0
Libs/Visualization/VTK/Widgets/Resources/UI/ctkVTKThresholdWidget.ui

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ctkVTKThresholdWidget</class>
+ <widget class="QWidget" name="ctkVTKThresholdWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>251</width>
+    <height>46</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Threshold</string>
+  </property>
+  <layout class="QFormLayout" name="formLayout">
+   <property name="fieldGrowthPolicy">
+    <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+   </property>
+   <property name="margin">
+    <number>0</number>
+   </property>
+   <item row="0" column="0">
+    <widget class="QLabel" name="ThresholdLabel">
+     <property name="text">
+      <string>Threshold:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="ctkRangeWidget" name="ThresholdSliderWidget"/>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="OpacityLabel">
+     <property name="text">
+      <string>Opacity:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="ctkSliderWidget" name="OpacitySliderWidget">
+     <property name="singleStep">
+      <double>0.010000000000000</double>
+     </property>
+     <property name="pageStep">
+      <double>0.100000000000000</double>
+     </property>
+     <property name="maximum">
+      <double>1.000000000000000</double>
+     </property>
+     <property name="value">
+      <double>1.000000000000000</double>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ctkRangeWidget</class>
+   <extends>QWidget</extends>
+   <header>ctkRangeWidget.h</header>
+  </customwidget>
+  <customwidget>
+   <class>ctkSliderWidget</class>
+   <extends>QWidget</extends>
+   <header>ctkSliderWidget.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

+ 12 - 1
Libs/Visualization/VTK/Widgets/Resources/UI/ctkVTKVolumePropertyWidget.ui

@@ -26,7 +26,10 @@
       <property name="margin">
        <number>0</number>
       </property>
-      <item>
+       <item>
+        <widget class="ctkVTKThresholdWidget" name="ScalarOpacityThresholdWidget"/>
+       </item>
+       <item>
        <widget class="ctkVTKScalarsToColorsWidget" name="ScalarOpacityWidget">
         <property name="minimumSize">
          <size>
@@ -34,6 +37,9 @@
           <height>120</height>
          </size>
         </property>
+        <property name="editColors">
+         <bool>false</bool>
+        </property>
        </widget>
       </item>
      </layout>
@@ -147,6 +153,11 @@
  </widget>
  <customwidgets>
   <customwidget>
+   <class>ctkVTKThresholdWidget</class>
+   <extends>QWidget</extends>
+   <header>ctkVTKThresholdWidget.h</header>
+  </customwidget>
+  <customwidget>
    <class>ctkVTKScalarsToColorsWidget</class>
    <extends>QWidget</extends>
    <header>ctkVTKScalarsToColorsWidget.h</header>

+ 3 - 0
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKVolumePropertyWidgetTest1.cpp

@@ -62,8 +62,11 @@ int ctkVTKVolumePropertyWidgetTest1(int argc, char * argv [] )
     vtkSmartPointer<vtkVolumeProperty>::New();
   volumeProperty->SetColor(ctf);
   volumeProperty->SetScalarOpacity(otf);
+  double range[2] = {0., 1.};
+  volumeProperty->GetGradientOpacity()->AdjustRange(range);
 
   ctkVTKVolumePropertyWidget widget;
+  //widget.setUseThresholdSlider(true);
   widget.setVolumeProperty(volumeProperty);
 
   volumeProperty->SetScalarOpacity(otf2);

+ 100 - 62
Libs/Visualization/VTK/Widgets/ctkVTKChartView.cpp

@@ -49,9 +49,11 @@ protected:
 public:
   ctkVTKChartViewPrivate(ctkVTKChartView& object);
   void init();
+  void chartBounds(double* bounds)const;
 
   vtkSmartPointer<vtkContextView> ContextView;
   vtkSmartPointer<vtkChartXY> Chart;
+  double UserBounds[8];
 };
 
 // ----------------------------------------------------------------------------
@@ -64,6 +66,8 @@ ctkVTKChartViewPrivate::ctkVTKChartViewPrivate(ctkVTKChartView& object)
   this->ContextView = vtkSmartPointer<vtkContextView>::New();
   this->Chart = vtkSmartPointer<vtkChartXY>::New();
   this->ContextView->GetScene()->AddItem(this->Chart);
+  this->UserBounds[0] = this->UserBounds[2] = this->UserBounds[4] = this->UserBounds[6] = 0.;
+  this->UserBounds[1] = this->UserBounds[3] = this->UserBounds[5] = this->UserBounds[7] = -1.;
 }
 
 // ----------------------------------------------------------------------------
@@ -81,71 +85,12 @@ void ctkVTKChartViewPrivate::init()
 }
 
 // ----------------------------------------------------------------------------
-// ctkVTKChartView methods
-
-// ----------------------------------------------------------------------------
-ctkVTKChartView::ctkVTKChartView(QWidget* parentWidget)
-  :QVTKWidget(parentWidget)
-  , d_ptr(new ctkVTKChartViewPrivate(*this))
-{
-  Q_D(ctkVTKChartView);
-  d->init();
-  this->setAutomaticImageCacheEnabled(true);
-}
-
-// ----------------------------------------------------------------------------
-ctkVTKChartView::~ctkVTKChartView()
-{
-}
-
-// ----------------------------------------------------------------------------
-void ctkVTKChartView::setTitle(const QString& newTitle)
-{
-  Q_D(ctkVTKChartView);
-  d->Chart->SetTitle(newTitle.toLatin1().data());
-}
-
-// ----------------------------------------------------------------------------
-QString ctkVTKChartView::title()const
-{
-  Q_D(const ctkVTKChartView);
-  return QString(d->Chart->GetTitle());
-}
-
-// ----------------------------------------------------------------------------
-vtkChartXY* ctkVTKChartView::chart()const
-{
-  Q_D(const ctkVTKChartView);
-  return d->Chart;
-}
-
-// ----------------------------------------------------------------------------
-vtkContextScene* ctkVTKChartView::scene()const
-{
-  Q_D(const ctkVTKChartView);
-  return d->ContextView->GetScene();
-}
-
-// ----------------------------------------------------------------------------
-void ctkVTKChartView::addPlot(vtkPlot* plot)
-{
-  Q_D(ctkVTKChartView);
-  d->Chart->AddPlot(plot);
-  emit this->plotAdded(plot);
-  this->onChartUpdated();
-}
-
-// ----------------------------------------------------------------------------
-void ctkVTKChartView::onChartUpdated()
-{
-}
-
-// ----------------------------------------------------------------------------
-void ctkVTKChartView::chartBounds(double* bounds)
+void ctkVTKChartViewPrivate::chartBounds(double* bounds)const
 {
+  Q_Q(const ctkVTKChartView);
   bounds[0] = bounds[2] = bounds[4] = bounds[6] = VTK_DOUBLE_MAX;
   bounds[1] = bounds[3] = bounds[5] = bounds[7] = VTK_DOUBLE_MIN;
-  vtkChartXY* chart = this->chart();
+  vtkChartXY* chart = q->chart();
   const vtkIdType plotCount = chart->GetNumberOfPlots();
   for (vtkIdType i = 0; i < plotCount; ++i)
     {
@@ -213,6 +158,99 @@ void ctkVTKChartView::chartBounds(double* bounds)
 }
 
 // ----------------------------------------------------------------------------
+// ctkVTKChartView methods
+
+// ----------------------------------------------------------------------------
+ctkVTKChartView::ctkVTKChartView(QWidget* parentWidget)
+  :QVTKWidget(parentWidget)
+  , d_ptr(new ctkVTKChartViewPrivate(*this))
+{
+  Q_D(ctkVTKChartView);
+  d->init();
+  this->setAutomaticImageCacheEnabled(true);
+}
+
+// ----------------------------------------------------------------------------
+ctkVTKChartView::~ctkVTKChartView()
+{
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKChartView::setTitle(const QString& newTitle)
+{
+  Q_D(ctkVTKChartView);
+  d->Chart->SetTitle(newTitle.toLatin1().data());
+}
+
+// ----------------------------------------------------------------------------
+QString ctkVTKChartView::title()const
+{
+  Q_D(const ctkVTKChartView);
+  return QString(d->Chart->GetTitle());
+}
+
+// ----------------------------------------------------------------------------
+vtkChartXY* ctkVTKChartView::chart()const
+{
+  Q_D(const ctkVTKChartView);
+  return d->Chart;
+}
+
+// ----------------------------------------------------------------------------
+vtkContextScene* ctkVTKChartView::scene()const
+{
+  Q_D(const ctkVTKChartView);
+  return d->ContextView->GetScene();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKChartView::addPlot(vtkPlot* plot)
+{
+  Q_D(ctkVTKChartView);
+  d->Chart->AddPlot(plot);
+  emit this->plotAdded(plot);
+  this->onChartUpdated();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKChartView::onChartUpdated()
+{
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKChartView::chartBounds(double* bounds)const
+{
+  Q_D(const ctkVTKChartView);
+  if (d->UserBounds[1] < d->UserBounds[0])
+    {
+    d->chartBounds(bounds);
+    return;
+    }
+  this->chartUserBounds(bounds);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKChartView::setChartUserBounds(double* userBounds)
+{
+  Q_D(ctkVTKChartView);
+  for (int i= 0; i < 8; ++i)
+    {
+    d->UserBounds[i] = userBounds[i];
+    }
+  emit boundsChanged();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKChartView::chartUserBounds(double* bounds)const
+{
+  Q_D(const ctkVTKChartView);
+  for (int i= 0; i < 8; ++i)
+    {
+    bounds[i] = d->UserBounds[i];
+    }
+}
+
+// ----------------------------------------------------------------------------
 void ctkVTKChartView::setAxesToChartBounds()
 {
   vtkChartXY* chart = this->chart();

+ 10 - 3
Libs/Visualization/VTK/Widgets/ctkVTKChartView.h

@@ -54,9 +54,16 @@ public:
   QString title()const;
   void setTitle(const QString& title);
 
-  /// Compute the bounds for the 4 chart axes
-  void chartBounds(double* bounds);
-  void setAxesToChartBounds();
+  /// Return the chart bounds for the 4 chart axes.
+  /// bounds must be an array of 8 doubles.
+  /// If no bounds is provided by the user, compute the bounds for the 4 chart
+  /// axes from the vtkPlots bounds.
+  void chartBounds(double* bounds)const;
+  void setChartUserBounds(double* bounds);
+  void chartUserBounds(double* bounds)const;
+
+  /// 
+  virtual void setAxesToChartBounds();
   void boundAxesToChartBounds();
 
 signals:

+ 31 - 1
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsView.cpp

@@ -322,7 +322,9 @@ QList<vtkPlot*> ctkVTKScalarsToColorsView::opacityFunctionPlots()const
   foreach(vtkPlot* plot, this->plots())
     {
     if (vtkPiecewiseFunctionItem::SafeDownCast(plot) ||
-        vtkPiecewiseControlPointsItem::SafeDownCast(plot))
+        vtkPiecewiseControlPointsItem::SafeDownCast(plot) ||
+        vtkCompositeTransferFunctionItem::SafeDownCast(plot) ||
+        vtkCompositeControlPointsItem::SafeDownCast(plot))
       {
       res << plot;
       }
@@ -433,6 +435,22 @@ void ctkVTKScalarsToColorsView
 }
 
 // ----------------------------------------------------------------------------
+void ctkVTKScalarsToColorsView
+::setUserBoundsToPlots(double* bounds)
+{
+  foreach(vtkScalarsToColorsItem* plot,
+          this->plots<vtkScalarsToColorsItem>())
+    {
+    plot->SetUserBounds(bounds);
+    }
+  foreach(vtkControlPointsItem* plot,
+          this->plots<vtkControlPointsItem>())
+    {
+    plot->SetUserBounds(bounds);
+    }
+}
+
+// ----------------------------------------------------------------------------
 void ctkVTKScalarsToColorsView::editPoint(vtkObject* caller, void* callData)
 {
   vtkControlPointsItem* controlPoints = reinterpret_cast<vtkControlPointsItem*>(caller);
@@ -459,3 +477,15 @@ void ctkVTKScalarsToColorsView::editPoint(vtkObject* caller, void* callData)
       }
     }
 }
+
+// ----------------------------------------------------------------------------
+void ctkVTKScalarsToColorsView::setAxesToChartBounds()
+{
+  vtkChartXY* chart = this->chart();
+  double userBounds[8];
+  this->chartUserBounds(userBounds);
+  if (userBounds[0] < userBounds[1])
+    {
+    this->setUserBoundsToPlots(userBounds);
+    }
+}

+ 4 - 0
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsView.h

@@ -75,7 +75,11 @@ public:
   void setColorTransferFunctionToPlots(vtkColorTransferFunction* colorTF);
   void setOpacityFunctionToPlots(vtkPiecewiseFunction* opacityTF);
   void setPiecewiseFunctionToPlots(vtkPiecewiseFunction* piecewiseTF);
+  
+  void setUserBoundsToPlots(double* bounds);
 
+  /// Reimplemented to set the bounds to the plots as well
+  virtual void setAxesToChartBounds();
 public slots:
   void editPoint(vtkObject* plot, void * pointId);
 

+ 56 - 9
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsWidget.cpp

@@ -59,6 +59,7 @@ public:
   bool blockSignals(bool);
 
   vtkControlPointsItem* CurrentControlPointsItem;
+  bool EditColors;
 };
 
 // ----------------------------------------------------------------------------
@@ -70,6 +71,7 @@ ctkVTKScalarsToColorsWidgetPrivate::ctkVTKScalarsToColorsWidgetPrivate(
   : q_ptr(&object)
 {
   this->CurrentControlPointsItem = 0;
+  this->EditColors = true;
 }
 
 // ----------------------------------------------------------------------------
@@ -98,9 +100,14 @@ void ctkVTKScalarsToColorsWidgetPrivate::setupUi(QWidget* widget)
   this->OpacityLabel->setVisible(false);
   this->OpacitySpinBox->setVisible(false);
   QObject::connect(this->XRangeSlider, SIGNAL(valuesChanged(double, double)),
-                   q, SLOT(onXRangeChanged(double, double)));
+                   q, SLOT(setXRange(double, double)));
   QObject::connect(this->YRangeSlider, SIGNAL(valuesChanged(double, double)),
-                   q, SLOT(onYRangeChanged(double, double)));
+                   q, SLOT(setYRange(double, double)));
+  QObject::connect(this->XRangeSlider, SIGNAL(valuesChanged(double, double)),
+                   q, SIGNAL(axesModified()));
+  QObject::connect(this->YRangeSlider, SIGNAL(valuesChanged(double, double)),
+                   q, SIGNAL(axesModified()));
+
   q->qvtkConnect(this->View->chart()->GetAxis(0),vtkCommand::ModifiedEvent,
                     q, SLOT(onAxesModified()));
   q->qvtkConnect(this->View->chart()->GetAxis(1),vtkCommand::ModifiedEvent,
@@ -172,6 +179,20 @@ void ctkVTKScalarsToColorsWidget::setVerticalSliderVisible(bool visible)
 }
 
 // ----------------------------------------------------------------------------
+bool ctkVTKScalarsToColorsWidget::editColors()const
+{
+  Q_D(const ctkVTKScalarsToColorsWidget);
+  return d->EditColors;
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKScalarsToColorsWidget::setEditColors(bool edit)
+{
+  Q_D(ctkVTKScalarsToColorsWidget);
+  d->EditColors = edit;
+}
+
+// ----------------------------------------------------------------------------
 void ctkVTKScalarsToColorsWidget::onPlotAdded(vtkPlot* plot)
 {
   if (vtkControlPointsItem::SafeDownCast(plot))
@@ -211,6 +232,7 @@ void ctkVTKScalarsToColorsWidget::setCurrentPoint(int newPoint)
 {
   Q_D(ctkVTKScalarsToColorsWidget);
   d->PointIdSpinBox->setValue(newPoint);
+  Q_ASSERT( newPoint == d->PointIdSpinBox->value());
 }
 
 // ----------------------------------------------------------------------------
@@ -236,9 +258,9 @@ void ctkVTKScalarsToColorsWidget::setCurrentControlPointsItem(vtkControlPointsIt
   d->CurrentControlPointsItem = item;
   if (item)
     {
-    d->ColorPickerButton->setVisible(
-      vtkColorTransferControlPointsItem::SafeDownCast(item) != 0 ||
-      vtkCompositeControlPointsItem::SafeDownCast(item) != 0);
+    d->ColorPickerButton->setVisible( d->EditColors &&
+      (vtkColorTransferControlPointsItem::SafeDownCast(item) != 0 ||
+       vtkCompositeControlPointsItem::SafeDownCast(item) != 0));
     d->OpacityLabel->setVisible(vtkPiecewiseControlPointsItem::SafeDownCast(item) != 0 ||
                                 vtkCompositeControlPointsItem::SafeDownCast(item) != 0);
     d->OpacitySpinBox->setVisible(vtkPiecewiseControlPointsItem::SafeDownCast(item) != 0 ||
@@ -378,26 +400,49 @@ void ctkVTKScalarsToColorsWidget::onSharpnessChanged(double sharpness)
   d->CurrentControlPointsItem->SetControlPoint(d->PointIdSpinBox->value(), point);
 }
 
+
+// ----------------------------------------------------------------------------
+void ctkVTKScalarsToColorsWidget::xRange(double* range)const
+{
+  Q_D(const ctkVTKScalarsToColorsWidget);
+  vtkAxis* xAxis = d->CurrentControlPointsItem ?
+    d->CurrentControlPointsItem->GetXAxis() : d->View->chart()->GetAxis(vtkAxis::BOTTOM);
+  Q_ASSERT(xAxis);
+  range[0] = xAxis->GetMinimum();
+  range[1] = xAxis->GetMaximum();
+}
+
 // ----------------------------------------------------------------------------
-void ctkVTKScalarsToColorsWidget::onXRangeChanged(double min, double max)
+void ctkVTKScalarsToColorsWidget::setXRange(double min, double max)
 {
   Q_D(ctkVTKScalarsToColorsWidget);
   vtkAxis* xAxis = d->CurrentControlPointsItem ?
     d->CurrentControlPointsItem->GetXAxis() : d->View->chart()->GetAxis(vtkAxis::BOTTOM);
   Q_ASSERT(xAxis);
-  xAxis->SetRange(min, max);
   d->View->scene()->SetDirty(true);
+  xAxis->SetRange(min, max);
 }
 
 // ----------------------------------------------------------------------------
-void ctkVTKScalarsToColorsWidget::onYRangeChanged(double min, double max)
+void ctkVTKScalarsToColorsWidget::yRange(double* range)const
+{
+  Q_D(const ctkVTKScalarsToColorsWidget);
+  vtkAxis* yAxis = d->CurrentControlPointsItem ?
+    d->CurrentControlPointsItem->GetYAxis() : d->View->chart()->GetAxis(vtkAxis::LEFT);
+  Q_ASSERT(yAxis);
+  range[0] = yAxis->GetMinimum();
+  range[1] = yAxis->GetMaximum();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKScalarsToColorsWidget::setYRange(double min, double max)
 {
   Q_D(ctkVTKScalarsToColorsWidget);
   vtkAxis* yAxis = d->CurrentControlPointsItem ?
     d->CurrentControlPointsItem->GetYAxis() : d->View->chart()->GetAxis(vtkAxis::LEFT);
   Q_ASSERT(yAxis);
-  yAxis->SetRange(min, max);
   d->View->scene()->SetDirty(true);
+  yAxis->SetRange(min, max);
 }
 
 // ----------------------------------------------------------------------------
@@ -412,4 +457,6 @@ void ctkVTKScalarsToColorsWidget::onAxesModified()
     d->CurrentControlPointsItem->GetYAxis() : d->View->chart()->GetAxis(vtkAxis::LEFT);
   Q_ASSERT(yAxis);
   d->YRangeSlider->setValues(yAxis->GetMinimum(), yAxis->GetMaximum());
+    d->View->scene()->SetDirty(true);
+  //emit this->axesModified();
 }

+ 12 - 2
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsWidget.h

@@ -40,6 +40,7 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKScalarsToColorsWidget : public
   QVTK_OBJECT
   Q_PROPERTY(bool horizontalSliderVisible READ isHorizontalSliderVisible WRITE setHorizontalSliderVisible)
   Q_PROPERTY(bool verticalSliderVisible READ isVerticalSliderVisible WRITE setVerticalSliderVisible)
+  Q_PROPERTY(bool editColors READ editColors WRITE setEditColors)
 public:
   ctkVTKScalarsToColorsWidget(QWidget* parent = 0);
   virtual ~ctkVTKScalarsToColorsWidget();
@@ -52,10 +53,21 @@ public:
 
   bool isVerticalSliderVisible()const;
   void setVerticalSliderVisible(bool visible);
+  
+  bool editColors()const;
+  void setEditColors(bool edit);
+  
+  void xRange(double* range)const;
+  void yRange(double* range)const;
 
 public slots:
   void setCurrentControlPointsItem(vtkControlPointsItem* item);
   void setCurrentPoint(int pointId);
+  void setXRange(double min, double max);
+  void setYRange(double min, double max);
+
+signals:
+  void axesModified();
 
 protected slots:
   void onPlotAdded(vtkPlot*);
@@ -67,8 +79,6 @@ protected slots:
   void onOpacityChanged(double opacity);
   void onMidPointChanged(double midPoint);
   void onSharpnessChanged(double sharpness);
-  void onXRangeChanged(double min, double max);
-  void onYRangeChanged(double min, double max);
   void onAxesModified();
 protected:
   QScopedPointer<ctkVTKScalarsToColorsWidgetPrivate> d_ptr;

+ 317 - 0
Libs/Visualization/VTK/Widgets/ctkVTKThresholdWidget.cpp

@@ -0,0 +1,317 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 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>
+
+// CTK includes
+#include "ctkLogger.h"
+#include "ctkVTKThresholdWidget.h"
+#include "ctkUtils.h"
+#include "ui_ctkVTKThresholdWidget.h"
+
+// VTK includes
+#include <vtkPiecewiseFunction.h>
+
+//----------------------------------------------------------------------------
+static ctkLogger logger("org.commontk.visualization.vtk.widgets.ctkVTKThresholdWidget");
+//----------------------------------------------------------------------------
+
+class ctkVTKThresholdWidgetPrivate:
+  public Ui_ctkVTKThresholdWidget
+{
+   Q_DECLARE_PUBLIC(ctkVTKThresholdWidget);
+protected:
+  ctkVTKThresholdWidget* const q_ptr;
+public:
+  ctkVTKThresholdWidgetPrivate(ctkVTKThresholdWidget& object);
+  void setupUi(QWidget* widget);
+
+  void setThreshold(double min, double max, double opacity);
+  void setRange(double min, double max);
+  void guessThreshold(double& min, double& max, double& opacity);
+  
+  vtkPiecewiseFunction* PiecewiseFunction;
+  bool UserRange;
+};
+
+// ----------------------------------------------------------------------------
+// ctkVTKThresholdWidgetPrivate methods
+
+// ----------------------------------------------------------------------------
+ctkVTKThresholdWidgetPrivate::ctkVTKThresholdWidgetPrivate(
+  ctkVTKThresholdWidget& object)
+  : q_ptr(&object)
+{
+  this->PiecewiseFunction = 0;
+  this->UserRange = false;
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidgetPrivate::setupUi(QWidget* widget)
+{
+  Q_Q(ctkVTKThresholdWidget);
+  Q_ASSERT(q == widget);
+  this->Ui_ctkVTKThresholdWidget::setupUi(widget);
+
+  QObject::connect(this->ThresholdSliderWidget, SIGNAL(valuesChanged(double, double)),
+                   q, SLOT(setThresholdValues(double, double)));
+  QObject::connect(this->OpacitySliderWidget, SIGNAL(valueChanged(double)),
+                   q, SLOT(setOpacity(double)));
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidgetPrivate::guessThreshold(double& min, double& max, double& opacity)
+{
+  min = this->ThresholdSliderWidget->minimum();
+  max = this->ThresholdSliderWidget->maximum();
+  opacity = 1.;
+  if (!this->PiecewiseFunction || this->PiecewiseFunction->GetSize() == 0)
+    {
+    return;
+    }
+  int minIndex; 
+  for (minIndex=0; minIndex < this->PiecewiseFunction->GetSize(); ++minIndex)
+    {
+    double node[4];
+    this->PiecewiseFunction->GetNodeValue(minIndex, node);
+    if (node[1] > 0.)
+      {
+      min = node[0];
+      opacity = node[1];
+      break;
+      }
+    }
+  if (minIndex == this->PiecewiseFunction->GetSize())
+    {
+    return;
+    }
+  int maxIndex;
+  for (maxIndex = minIndex + 1;
+       maxIndex < this->PiecewiseFunction->GetSize();
+       ++maxIndex)
+    {
+    double node[4];
+    this->PiecewiseFunction->GetNodeValue(maxIndex, node);
+    // average the opacities
+    opacity += node[1];
+    if (node[1] == 0.)
+      {
+      max = node[0];
+      opacity /= maxIndex - minIndex + 1;
+      break;
+      }
+    }
+  // couldn't find the upper threshold value, use the upper range
+  if (maxIndex == this->PiecewiseFunction->GetSize())
+    {
+    opacity /= maxIndex - minIndex;
+    }
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidgetPrivate::setRange(double min, double max)
+{
+  bool wasBlocking = this->ThresholdSliderWidget->blockSignals(true);
+  int decimals = qMax(0, -ctk::orderOfMagnitude(max - min) + 2);
+  this->ThresholdSliderWidget->setDecimals(decimals);
+  this->ThresholdSliderWidget->setSingleStep(pow(10., -decimals));
+  this->ThresholdSliderWidget->setRange(min, max);
+  this->ThresholdSliderWidget->blockSignals(wasBlocking);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidgetPrivate::setThreshold(double min, double max, double opacity)
+{
+  if (!this->PiecewiseFunction)
+    {
+    return;
+    }
+  double range[2];
+  this->ThresholdSliderWidget->range(range);
+ 
+  double node[4];
+  node[0] = range[0];
+  node[1] = 0.;
+  node[2] = 0.5;
+  node[3] = 0.;
+  if (this->PiecewiseFunction->GetSize() < 1)
+    {
+    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
+    }
+  else
+    {
+    this->PiecewiseFunction->SetNodeValue(0, node);
+    }
+
+  node[0] = min;
+  node[1] = 0.;
+  node[2] = 0.;
+  node[3] = 1.;
+  if (this->PiecewiseFunction->GetSize() < 2)
+    {
+    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
+    }
+  else
+    {
+    this->PiecewiseFunction->SetNodeValue(1, node);
+    }
+  node[0] = max;
+  node[1] = opacity;
+  if (this->PiecewiseFunction->GetSize() < 3)
+    {
+    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
+    }
+  else
+    {
+    this->PiecewiseFunction->SetNodeValue(2, node);
+    }
+  node[0] = (max == range[1]) ? range[1] + 0.00000000000001 : range[1];
+  node[1] = 0.;
+  node[2] = 0.5;
+  node[3] = 0.;
+  if (this->PiecewiseFunction->GetSize() < 4)
+    {
+    this->PiecewiseFunction->AddPoint(node[0], node[1], node[2], node[3]);
+    }
+  else
+    {
+    this->PiecewiseFunction->SetNodeValue(3, node);
+    }
+
+}
+
+// ----------------------------------------------------------------------------
+// ctkVTKThresholdWidget methods
+
+// ----------------------------------------------------------------------------
+ctkVTKThresholdWidget::ctkVTKThresholdWidget(QWidget* parentWidget)
+  :QWidget(parentWidget)
+   , d_ptr(new ctkVTKThresholdWidgetPrivate(*this))
+{
+  Q_D(ctkVTKThresholdWidget);
+  d->setupUi(this);
+}
+
+// ----------------------------------------------------------------------------
+ctkVTKThresholdWidget::~ctkVTKThresholdWidget()
+{
+}
+
+// ----------------------------------------------------------------------------
+vtkPiecewiseFunction* ctkVTKThresholdWidget::piecewiseFunction()const
+{
+  Q_D(const ctkVTKThresholdWidget);
+  return d->PiecewiseFunction;
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget
+::setPiecewiseFunction(vtkPiecewiseFunction* newFunction)
+{
+  Q_D(ctkVTKThresholdWidget);
+  if (d->PiecewiseFunction == newFunction)
+    {
+    return;
+    }
+  this->qvtkReconnect(d->PiecewiseFunction, newFunction, vtkCommand::ModifiedEvent,
+                      this, SLOT(updateFromPiecewiseFunction()));
+  d->PiecewiseFunction = newFunction;
+  
+  if (!d->UserRange)
+    {
+    double range[2] = {0., 1.};
+    if (d->PiecewiseFunction)
+      {
+      d->PiecewiseFunction->GetRange(range);
+      }
+    d->setRange(range[0], range[1]);
+    }
+  if (d->PiecewiseFunction)
+    {
+    double min, max, value;
+    d->guessThreshold(min, max, value);
+    d->setThreshold(min, max, value);
+    }
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget::updateFromPiecewiseFunction()
+{
+  Q_D(ctkVTKThresholdWidget);
+  
+  if (!d->PiecewiseFunction)
+    {
+    return;
+    }
+  double range[2];
+  d->ThresholdSliderWidget->range(range);
+  double minThreshold = range[0];
+  double maxThreshold = range[1];
+  double opacity = 1.;
+  double node[4];
+  if (d->PiecewiseFunction->GetSize() > 1)
+    {
+    d->PiecewiseFunction->GetNodeValue(1, node);
+    minThreshold = node[0];
+    }
+  if (d->PiecewiseFunction->GetSize() > 2)
+    {
+    d->PiecewiseFunction->GetNodeValue(2, node);
+    maxThreshold = node[0];
+    opacity = node[1];
+    }
+  bool wasBlocking = d->ThresholdSliderWidget->blockSignals(true);
+  d->ThresholdSliderWidget->setValues(minThreshold, maxThreshold);
+  d->ThresholdSliderWidget->blockSignals(wasBlocking);
+  d->OpacitySliderWidget->blockSignals(true);
+  d->OpacitySliderWidget->setValue(opacity);
+  d->OpacitySliderWidget->blockSignals(wasBlocking);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget::setThresholdValues(double min, double max)
+{
+  Q_D(ctkVTKThresholdWidget);
+  d->setThreshold(min, max, d->OpacitySliderWidget->value());
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget::setOpacity(double opacity)
+{
+  Q_D(ctkVTKThresholdWidget);
+  d->setThreshold(d->ThresholdSliderWidget->minimumValue(),
+                  d->ThresholdSliderWidget->maximumValue(), opacity);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget::range(double* range)const
+{
+  Q_D(const ctkVTKThresholdWidget);
+  d->ThresholdSliderWidget->range(range);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKThresholdWidget::setRange(double min, double max)
+{
+  Q_D(ctkVTKThresholdWidget);
+  d->UserRange = true;
+  d->setRange(min, max);
+}

+ 65 - 0
Libs/Visualization/VTK/Widgets/ctkVTKThresholdWidget.h

@@ -0,0 +1,65 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 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 __ctkVTKThresholdWidget_h
+#define __ctkVTKThresholdWidget_h
+
+//Qt includes
+#include <QWidget>
+
+// CTK includes
+#include <ctkVTKObject.h>
+#include "ctkVisualizationVTKWidgetsExport.h"
+class ctkVTKThresholdWidgetPrivate;
+
+// VTK includes
+class vtkPiecewiseFunction;
+
+class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKThresholdWidget
+  : public QWidget
+{
+  Q_OBJECT
+  QVTK_OBJECT
+
+public:
+  ctkVTKThresholdWidget(QWidget* parent = 0);
+  virtual ~ctkVTKThresholdWidget();
+
+  vtkPiecewiseFunction* piecewiseFunction()const;
+  void range(double* range)const;
+
+public slots:
+  void setPiecewiseFunction(vtkPiecewiseFunction* function);
+  void setRange(double min, double max);
+
+protected slots:
+  void updateFromPiecewiseFunction();
+  void setThresholdValues(double min, double max);
+  void setOpacity(double opacity);
+
+protected:
+  QScopedPointer<ctkVTKThresholdWidgetPrivate> d_ptr;
+
+private:
+  Q_DECLARE_PRIVATE(ctkVTKThresholdWidget);
+  Q_DISABLE_COPY(ctkVTKThresholdWidget);
+};
+
+#endif

+ 113 - 2
Libs/Visualization/VTK/Widgets/ctkVTKVolumePropertyWidget.cpp

@@ -25,6 +25,7 @@
 #include "ctkLogger.h"
 #include "ctkVTKScalarsToColorsView.h"
 #include "ctkVTKVolumePropertyWidget.h"
+#include "ctkUtils.h"
 #include "ui_ctkVTKVolumePropertyWidget.h"
 
 // VTK includes
@@ -54,7 +55,10 @@ protected:
 public:
   ctkVTKVolumePropertyWidgetPrivate(ctkVTKVolumePropertyWidget& object);
   void setupUi(QWidget* widget);
-
+  void computeRange(double* range);
+  void updateThresholdSlider(vtkPiecewiseFunction* opacityFunction);
+  void setThreshold(double min, double max, double opacity);
+  
   vtkVolumeProperty* VolumeProperty;
   int                CurrentComponent;
 };
@@ -78,9 +82,19 @@ void ctkVTKVolumePropertyWidgetPrivate::setupUi(QWidget* widget)
   Q_ASSERT(q == widget);
   this->Ui_ctkVTKVolumePropertyWidget::setupUi(widget);
 
-  this->ScalarOpacityWidget->view()->addCompositeFunction(0, 0, false, true);
+  this->ScalarOpacityWidget->view()->addCompositeFunction(0, 0, true, true);
+  vtkCompositeControlPointsItem::SafeDownCast(
+    this->ScalarOpacityWidget->view()->opacityFunctionPlots()[1])->SetColorFill(true);
   this->ScalarColorWidget->view()->addColorTransferFunction(0);
   this->GradientWidget->view()->addPiecewiseFunction(0);
+  this->ScalarOpacityThresholdWidget->setVisible(false);
+
+  QObject::connect(this->ScalarOpacityWidget, SIGNAL(axesModified()),
+                   q, SLOT(onAxesModified()), Qt::QueuedConnection);
+  QObject::connect(this->ScalarColorWidget, SIGNAL(axesModified()),
+                   q, SLOT(onAxesModified()), Qt::QueuedConnection);
+  QObject::connect(this->GradientWidget, SIGNAL(axesModified()),
+                   q, SLOT(onAxesModified()), Qt::QueuedConnection);
 
   this->GradientGroupBox->setCollapsed(true);
   this->AdvancedGroupBox->setCollapsed(true);
@@ -100,6 +114,36 @@ void ctkVTKVolumePropertyWidgetPrivate::setupUi(QWidget* widget)
 }
 
 // ----------------------------------------------------------------------------
+void ctkVTKVolumePropertyWidgetPrivate::computeRange(double* range)
+{
+  range[0] = 0.;
+  range[1] = 1.;
+
+  if (!this->VolumeProperty)
+    {
+    return;
+    }
+  Q_ASSERT(this->VolumeProperty->GetRGBTransferFunction(this->CurrentComponent));
+  Q_ASSERT(this->VolumeProperty->GetScalarOpacity(this->CurrentComponent));
+  Q_ASSERT(this->VolumeProperty->GetGradientOpacity(this->CurrentComponent));
+  
+  double colorRange[2] = {0., 1.};
+  this->VolumeProperty->GetRGBTransferFunction(this->CurrentComponent)->GetRange(colorRange);
+  range[0] = qMin(range[0], colorRange[0]);
+  range[1] = qMax(range[1], colorRange[1]);
+
+  double opacityRange[2] = {0., 1.};
+  this->VolumeProperty->GetScalarOpacity(this->CurrentComponent)->GetRange(opacityRange);
+  range[0] = qMin(range[0], opacityRange[0]);
+  range[1] = qMax(range[1], opacityRange[1]);
+  
+  double gradientRange[2] = {0., 1.};
+  this->VolumeProperty->GetGradientOpacity(this->CurrentComponent)->GetRange(gradientRange);
+  range[0] = qMin(range[0], gradientRange[0]);
+  range[1] = qMax(range[1], gradientRange[1]);
+}
+
+// ----------------------------------------------------------------------------
 // ctkVTKVolumePropertyWidget methods
 
 // ----------------------------------------------------------------------------
@@ -131,7 +175,27 @@ void ctkVTKVolumePropertyWidget
   this->qvtkReconnect(d->VolumeProperty, newVolumeProperty, vtkCommand::ModifiedEvent,
                       this, SLOT(updateFromVolumeProperty()));
   d->VolumeProperty = newVolumeProperty;
+
   this->updateFromVolumeProperty();
+
+  double range[2];
+  d->computeRange(range);
+  d->ScalarOpacityThresholdWidget->setRange(range[0], range[1]);
+
+  double chartBounds[8];
+  d->ScalarOpacityWidget->view()->chartBounds(chartBounds);
+  chartBounds[2] = range[0];
+  chartBounds[3] = range[1];
+  d->ScalarOpacityWidget->view()->setChartUserBounds(chartBounds);
+  
+  d->ScalarColorWidget->view()->chartBounds(chartBounds);
+  chartBounds[2] = range[0];
+  chartBounds[3] = range[1];
+  d->ScalarColorWidget->view()->setChartUserBounds(chartBounds);
+  d->GradientWidget->view()->chartBounds(chartBounds);
+  chartBounds[2] = range[0];
+  chartBounds[3] = range[1];
+  d->GradientWidget->view()->setChartUserBounds(chartBounds);
 }
 
 // ----------------------------------------------------------------------------
@@ -154,6 +218,8 @@ void ctkVTKVolumePropertyWidget::updateFromVolumeProperty()
       d->VolumeProperty->GetGradientOpacity() : 0;
     }
 
+  d->ScalarOpacityThresholdWidget->setPiecewiseFunction(this->useThresholdSlider() ? opacityFunction : 0);
+  
   d->ScalarOpacityWidget->view()->setOpacityFunctionToPlots(opacityFunction);
   d->ScalarOpacityWidget->view()->setColorTransferFunctionToPlots(colorTransferFunction);
   d->ScalarColorWidget->view()->setColorTransferFunctionToPlots(colorTransferFunction);
@@ -242,4 +308,49 @@ void ctkVTKVolumePropertyWidget::setSpecularPower(double value)
   d->VolumeProperty->SetSpecularPower(d->CurrentComponent, value);
 }
 
+// ----------------------------------------------------------------------------
+bool ctkVTKVolumePropertyWidget::useThresholdSlider()const
+{
+  Q_D(const ctkVTKVolumePropertyWidget);
+  return d->ScalarOpacityThresholdWidget->isVisibleTo(
+    const_cast<ctkVTKVolumePropertyWidget*>(this));
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKVolumePropertyWidget::setUseThresholdSlider(bool enable)
+{
+  Q_D(ctkVTKVolumePropertyWidget);
+  d->ScalarOpacityThresholdWidget->setVisible(enable);
+  d->ScalarOpacityWidget->setVisible(!enable);
+  this->updateFromVolumeProperty();
+}
 
+// ----------------------------------------------------------------------------
+void ctkVTKVolumePropertyWidget::onAxesModified()
+{
+  Q_D(ctkVTKVolumePropertyWidget);
+  //return;
+  ctkVTKScalarsToColorsWidget* senderWidget =
+    qobject_cast<ctkVTKScalarsToColorsWidget*>(this->sender());
+  
+  double xRange[2] = {0.,0.};
+  senderWidget->xRange(xRange);
+  if (senderWidget != d->ScalarOpacityWidget)
+    {
+    bool wasBlocking = d->ScalarOpacityWidget->blockSignals(true);
+    d->ScalarOpacityWidget->setXRange(xRange[0], xRange[1]);
+    d->ScalarOpacityWidget->blockSignals(wasBlocking);
+    }
+  if (senderWidget != d->ScalarColorWidget)
+    {
+    bool wasBlocking = d->ScalarColorWidget->blockSignals(true);
+    d->ScalarColorWidget->setXRange(xRange[0], xRange[1]);
+    d->ScalarColorWidget->blockSignals(wasBlocking);
+    }
+  if (senderWidget != d->GradientWidget)
+    {
+    bool wasBlocking = d->GradientWidget->blockSignals(true);
+    d->GradientWidget->setXRange(xRange[0], xRange[1]);
+    d->GradientWidget->blockSignals(wasBlocking);
+    }
+}

+ 11 - 0
Libs/Visualization/VTK/Widgets/ctkVTKVolumePropertyWidget.h

@@ -37,6 +37,10 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKVolumePropertyWidget
 {
   Q_OBJECT
   QVTK_OBJECT
+  ///
+  /// Control wether a range slider widget is used to edit the opacity
+  /// function instead of a chart editor. False by default
+  Q_PROPERTY(bool useThresholdSlider READ useThresholdSlider WRITE setUseThresholdSlider)
 
 public:
   ctkVTKVolumePropertyWidget(QWidget* parent = 0);
@@ -44,6 +48,9 @@ public:
 
   vtkVolumeProperty* volumeProperty()const;
 
+  bool useThresholdSlider()const;
+  void setUseThresholdSlider(bool enable);
+
 public slots:
   void setVolumeProperty(vtkVolumeProperty* volumeProperty);
 
@@ -56,6 +63,10 @@ protected slots:
   void setDiffuse(double value);
   void setSpecular(double value);
   void setSpecularPower(double value);
+  
+  /// Called whenever a view (opacity, colors or gradient) has one of its axis
+  /// modified. It synchronize all the views to see the same.
+  void onAxesModified();
 
 protected:
   QScopedPointer<ctkVTKVolumePropertyWidgetPrivate> d_ptr;

+ 10 - 0
Libs/Widgets/ctkRangeWidget.cpp

@@ -236,6 +236,16 @@ double ctkRangeWidget::maximum()const
 }
 
 // --------------------------------------------------------------------------
+void ctkRangeWidget::range(double* range)const
+{
+  Q_D(const ctkRangeWidget);
+  Q_ASSERT(d->equal(d->MinimumSpinBox->minimum(),d->Slider->minimum()));
+  Q_ASSERT(d->equal(d->MaximumSpinBox->maximum(), d->Slider->maximum()));
+  range[0] = d->Slider->minimum();
+  range[1] = d->Slider->maximum();
+}
+
+// --------------------------------------------------------------------------
 void ctkRangeWidget::setMinimum(double min)
 {
   Q_D(ctkRangeWidget);

+ 3 - 0
Libs/Widgets/ctkRangeWidget.h

@@ -86,6 +86,9 @@ public:
   /// Description
   /// Utility function that set the min/max in once
   void setRange(double min, double max);
+  /// Description
+  /// Return the range of the slider
+  void range(double* range)const;
 
   ///
   /// This property holds the slider and spinbox minimum value.