Browse Source

Add ctkVTKDiscretizableColorTransferWidget

Add a new widget to preview and edit a color transfer function given as
a vtkScalarsToColors.
The widget owns an instance of vtkScalarsToColorsContextItem that can be
added to a vtkContextView. vtkScalarsToColorsContextItem holds three
different charts to represent the information associated to the color transfer
function :
  - vtkDiscretizableColorTransferFunctionChart: Uses
  vtkControlPointsItem to edit the color transfer function

  - vtkScalarsToColorsPreviewChart: Preview the current color transfer
  function.

  -vtkScalarsToColorsHistogramChart: Display the histogram of an input
  image while applying the color transfer function to the histogram.

The widget also owns an instance of vtkScalarsToColorsComboBox to access
different presets.
Lucas Gandel 7 years ago
parent
commit
328a070a5e
32 changed files with 3055 additions and 99 deletions
  1. 37 0
      Libs/Visualization/VTK/Core/CMakeLists.txt
  2. 6 0
      Libs/Visualization/VTK/Core/Testing/Cpp/CMakeLists.txt
  3. 74 0
      Libs/Visualization/VTK/Core/Testing/Cpp/vtkScalarsToColorsPreviewChartTest1.cpp
  4. 145 0
      Libs/Visualization/VTK/Core/ctkVTKScalarsToColorsUtils.cpp
  5. 60 0
      Libs/Visualization/VTK/Core/ctkVTKScalarsToColorsUtils.h
  6. 462 0
      Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferChart.cpp
  7. 106 0
      Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferChart.h
  8. 127 0
      Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferControlPointsItem.cpp
  9. 63 0
      Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferControlPointsItem.h
  10. 285 0
      Libs/Visualization/VTK/Core/vtkScalarsToColorsContextItem.cpp
  11. 110 0
      Libs/Visualization/VTK/Core/vtkScalarsToColorsContextItem.h
  12. 87 0
      Libs/Visualization/VTK/Core/vtkScalarsToColorsHistogramChart.cpp
  13. 61 0
      Libs/Visualization/VTK/Core/vtkScalarsToColorsHistogramChart.h
  14. 88 0
      Libs/Visualization/VTK/Core/vtkScalarsToColorsPreviewChart.cpp
  15. 20 14
      Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsUtils.h
  16. 7 2
      Libs/Visualization/VTK/Widgets/CMakeLists.txt
  17. BIN
      Libs/Visualization/VTK/Widgets/Resources/Icons/invert.png
  18. BIN
      Libs/Visualization/VTK/Widgets/Resources/Icons/resetRange.png
  19. BIN
      Libs/Visualization/VTK/Widgets/Resources/Icons/resetRangeCustom.png
  20. 188 0
      Libs/Visualization/VTK/Widgets/Resources/UI/ctkVTKDiscretizableColorTransferWidget.ui
  21. 3 0
      Libs/Visualization/VTK/Widgets/Resources/ctkVTKWidgets.qrc
  22. 3 1
      Libs/Visualization/VTK/Widgets/Testing/Cpp/CMakeLists.txt
  23. 79 0
      Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKDiscretizableColorTransferWidgetTest1.cpp
  24. 79 0
      Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKScalarsToColorsComboBoxTest1.cpp
  25. 1 1
      Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKScalarsToColorsUtilsTest1.cpp
  26. 549 0
      Libs/Visualization/VTK/Widgets/ctkVTKDiscretizableColorTransferWidget.cpp
  27. 90 0
      Libs/Visualization/VTK/Widgets/ctkVTKDiscretizableColorTransferWidget.h
  28. 175 0
      Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsComboBox.cpp
  29. 92 0
      Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsComboBox.h
  30. 0 81
      Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsUtils.cpp
  31. 50 0
      Libs/Visualization/VTK/Widgets/ctkVTKWidgetsUtils.cpp
  32. 8 0
      Libs/Visualization/VTK/Widgets/ctkVTKWidgetsUtils.h

+ 37 - 0
Libs/Visualization/VTK/Core/CMakeLists.txt

@@ -28,6 +28,8 @@ set(KIT_SRCS
   ctkVTKObject.h
   ctkVTKObjectEventsObserver.cpp
   ctkVTKObjectEventsObserver.h
+  ctkVTKScalarsToColorsUtils.cpp
+  ctkVTKScalarsToColorsUtils.h
   vtkLightBoxRendererManager.cpp
   vtkLightBoxRendererManager.h
   )
@@ -106,6 +108,41 @@ else()
     )
 endif()
 
+if(CTK_LIB_Visualization/VTK/Widgets_USE_TRANSFER_FUNCTION_CHARTS)
+  set(CTK_USE_CHARTS 1)
+endif()
+
+if(${CTK_USE_CHARTS})
+  set(KIT_SRCS
+    vtkDiscretizableColorTransferChart.cpp
+    vtkDiscretizableColorTransferChart.h
+    vtkDiscretizableColorTransferControlPointsItem.cpp
+    vtkDiscretizableColorTransferControlPointsItem.h
+    vtkScalarsToColorsContextItem.cpp
+    vtkScalarsToColorsContextItem.h
+    vtkScalarsToColorsHistogramChart.cpp
+    vtkScalarsToColorsHistogramChart.h
+    vtkScalarsToColorsPreviewChart.cpp
+    vtkScalarsToColorsPreviewChart.h
+    ${KIT_SRCS})
+  if(${VTK_VERSION_MAJOR} GREATER 5)
+    set(VTK_LIBRARIES
+      vtkChartsCore
+      ${VTK_LIBRARIES})
+  else()
+    set(VTK_LIBRARIES
+      vtkCharts
+      ${VTK_LIBRARIES})
+  endif()
+  add_definitions(-DCTK_USE_CHARTS)
+  set(VTK_LIBRARIES
+    vtkViewsContext2D
+	${VTK_LIBRARIES})
+  if(TARGET vtkRenderingContext${VTK_RENDERING_BACKEND})
+    list(APPEND VTK_LIBRARIES vtkRenderingContext${VTK_RENDERING_BACKEND})
+  endif()
+endif()
+
 if(CTK_LIB_Scripting/Python/Core AND CTK_LIB_Scripting/Python/Core_PYTHONQT_USE_VTK)
   list(APPEND VTK_LIBRARIES ${PYTHON_LIBRARY} ${PYTHONQT_LIBRARIES})
   if(${VTK_VERSION_MAJOR} GREATER 5)

+ 6 - 0
Libs/Visualization/VTK/Core/Testing/Cpp/CMakeLists.txt

@@ -9,6 +9,11 @@ set(TEST_SOURCES
   ctkVTKObjectTest1.cpp
   )
 
+if(CTK_USE_CHARTS)
+  set(TEST_SOURCES
+    vtkScalarsToColorsPreviewChartTest1.cpp
+    ${TEST_SOURCES})
+endif()
 #
 # Tests expecting CTKData to be set
 #
@@ -60,6 +65,7 @@ create_test_sourcelist(Tests ${KIT}CppTests.cpp
 SET (TestsToRun ${Tests})
 REMOVE (TestsToRun ${KIT}CppTests.cpp)
 
+
 set(LIBRARY_NAME ${PROJECT_NAME})
 
 add_executable(${KIT}CppTests ${Tests} ${KIT_HELPER_SRCS})

+ 74 - 0
Libs/Visualization/VTK/Core/Testing/Cpp/vtkScalarsToColorsPreviewChartTest1.cpp

@@ -0,0 +1,74 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 <QDebug>
+#include <QTimer>
+
+// CTK includes
+#include "vtkScalarsToColorsPreviewChart.h"
+
+// VTK includes
+#include <vtkContextScene.h>
+#include <vtkContextView.h>
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkNew.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+
+// STD includes
+
+//-----------------------------------------------------------------------------
+int vtkScalarsToColorsPreviewChartTest1(int argc, char * argv [] )
+{
+  QCoreApplication app(argc, argv);
+
+  vtkNew<vtkScalarsToColorsPreviewChart> previewChart;
+
+  vtkNew<vtkContextView> contextView;
+  contextView->GetScene()->AddItem(previewChart.Get());
+
+  //Dummy presets
+  vtkNew<vtkDiscretizableColorTransferFunction> discretizableCTF;
+  discretizableCTF->AddRGBPoint(0.0, 0, 0, 1.0);
+  discretizableCTF->AddRGBPoint(255.0, 1.0, 0, 0);
+  vtkNew<vtkPiecewiseFunction> piecewiseFunction;
+  piecewiseFunction->AddPoint(0.0, 0);
+  piecewiseFunction->AddPoint(255.0, 1.0);
+  discretizableCTF->SetScalarOpacityFunction(piecewiseFunction.Get());
+  discretizableCTF->EnableOpacityMappingOn();
+
+  previewChart->SetColorTransferFunction(discretizableCTF.Get());
+  previewChart->SetLayoutStrategy(vtkChart::FILL_SCENE);
+
+  contextView->GetRenderWindow()->Render();
+  contextView->GetRenderWindow()->GetInteractor()->Initialize();
+  contextView->GetRenderWindow()->GetInteractor()->CreateOneShotTimer(10);
+  contextView->GetRenderWindow()->GetInteractor()->Start();
+
+  if (argc < 2 || QString(argv[1]) != "-I")
+  {
+    QTimer::singleShot(1000, &app, SLOT(quit()));
+  }
+
+  return app.exec();
+}

+ 145 - 0
Libs/Visualization/VTK/Core/ctkVTKScalarsToColorsUtils.cpp

@@ -0,0 +1,145 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 "ctkLogger.h"
+#include "ctkVTKScalarsToColorsUtils.h"
+
+// VTK includes
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkMath.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkScalarsToColors.h>
+
+// ----------------------------------------------------------------------------
+static ctkLogger logger(
+  "org.commontk.visualization.vtk.core.ctkVTKScalarsToColorsUtils");
+
+// ----------------------------------------------------------------------------
+void ctk::remapColorScale(
+  vtkDiscretizableColorTransferFunction* colorTransferFunction,
+  vtkDiscretizableColorTransferFunction* rescaledColorTransferFunction,
+  double minRescale, double maxRescale)
+{
+  /// Color
+  double rescaleWidth = maxRescale - minRescale;
+  double* range = colorTransferFunction->GetRange();
+
+  rescaledColorTransferFunction->RemoveAllPoints();
+
+  for (int i = 0; i < colorTransferFunction->GetSize(); i++)
+  {
+    double val[6];
+    colorTransferFunction->GetNodeValue(i, val);
+    double normalized = (val[0] - range[0]) / (range[1] - range[0]);
+
+    double newX = minRescale + normalized * rescaleWidth;
+    rescaledColorTransferFunction->AddRGBPoint(newX, val[1], val[2], val[3],
+      val[4], val[5]);
+  }
+
+  /// Opacity
+  if (rescaledColorTransferFunction->GetScalarOpacityFunction() != nullptr)
+  {
+    rescaledColorTransferFunction->GetScalarOpacityFunction()->
+      RemoveAllPoints();
+  }
+  else
+  {
+    vtkSmartPointer<vtkPiecewiseFunction> opacityFunction =
+      vtkSmartPointer<vtkPiecewiseFunction>::New();
+    rescaledColorTransferFunction->SetScalarOpacityFunction(opacityFunction);
+  }
+
+  if (colorTransferFunction->GetScalarOpacityFunction() == nullptr)
+  {
+    rescaledColorTransferFunction->Build();
+    return;
+  }
+
+  for (int i = 0;
+    i < colorTransferFunction->GetScalarOpacityFunction()->GetSize(); i++)
+  {
+    double val[4];
+    colorTransferFunction->GetScalarOpacityFunction()->GetNodeValue(i, val);
+    double normalized = (val[0] - range[0]) / (range[1] - range[0]);
+
+    double newX = minRescale + normalized * rescaleWidth;
+    rescaledColorTransferFunction->GetScalarOpacityFunction()->AddPoint(newX,
+      val[1], val[2], val[3]);
+  }
+  rescaledColorTransferFunction->Build();
+}
+
+// ----------------------------------------------------------------------------
+void ctk::remapColorScale(
+  vtkDiscretizableColorTransferFunction* colorTransferFunction,
+  double minRescale, double maxRescale)
+{
+  vtkSmartPointer<vtkDiscretizableColorTransferFunction> rescaled =
+    vtkSmartPointer<vtkDiscretizableColorTransferFunction>::New();
+  ctk::remapColorScale(colorTransferFunction, rescaled, minRescale, maxRescale);
+  ctk::remapColorScale(rescaled, colorTransferFunction, minRescale, maxRescale);
+}
+
+// ----------------------------------------------------------------------------
+void ctk::reverseColorMap(vtkDiscretizableColorTransferFunction* ctf)
+{
+  if (ctf == nullptr)
+  {
+    return;
+  }
+
+  int size = ctf->GetSize();
+  for (int i = 0; i < size / 2; i++)
+  {
+    double val[6];
+    ctf->GetNodeValue(i, val);
+
+    double valRev[6];
+    ctf->GetNodeValue(size - 1 - i, valRev);
+
+    std::swap(val[0], valRev[0]);
+
+    ctf->SetNodeValue(i, valRev);
+    ctf->SetNodeValue(size - 1 - i, val);
+  }
+  ctf->Modified();
+}
+
+// ----------------------------------------------------------------------------
+void ctk::setTransparency(vtkDiscretizableColorTransferFunction* ctf,
+  double transparency)
+{
+  if (ctf == nullptr)
+  {
+    return;
+  }
+
+  for (int i = 0; i < ctf->GetScalarOpacityFunction()->GetSize(); ++i)
+  {
+    double val[4];
+    ctf->GetScalarOpacityFunction()->GetNodeValue(i, val);
+
+    val[1] = vtkMath::ClampValue(val[1] * transparency, 1e-6, 1.);
+
+    ctf->GetScalarOpacityFunction()->SetNodeValue(i, val);
+  }
+  ctf->Modified();
+}

+ 60 - 0
Libs/Visualization/VTK/Core/ctkVTKScalarsToColorsUtils.h

@@ -0,0 +1,60 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __ctkVTKScalarsToColorsUtils_h
+#define __ctkVTKScalarsToColorsUtils_h
+
+// CTK includes
+#include "ctkVisualizationVTKCoreExport.h"
+
+// VTK includes
+class vtkDiscretizableColorTransferFunction;
+class vtkScalarsToColors;
+
+namespace ctk
+{
+
+/// \ingroup Visualization_VTK_Core
+/// Remap color transfer function into the specified range
+void CTK_VISUALIZATION_VTK_CORE_EXPORT remapColorScale(
+  vtkDiscretizableColorTransferFunction* colorTransferFunction,
+  double minRescale, double maxRescale);
+
+/// \ingroup Visualization_VTK_Core
+/// Remap color transfer function into the specified range.
+/// \param colorTransferFunction is not modified and the output is copied to
+/// into \param rescaledColorTranferFunction
+void CTK_VISUALIZATION_VTK_CORE_EXPORT remapColorScale(
+  vtkDiscretizableColorTransferFunction* colorTransferFunction,
+  vtkDiscretizableColorTransferFunction* rescaledColorTransferFunction,
+  double minRescale, double maxRescale);
+
+/// \ingroup Visualization_VTK_Core
+/// Reverse color transfer function
+void CTK_VISUALIZATION_VTK_CORE_EXPORT reverseColorMap(vtkDiscretizableColorTransferFunction* colorTransferFunction);
+
+/// \ingroup Visualization_VTK_Core
+/// Set global opacity of the color transfer function.
+/// Transparency is multiplied to each node opacity.
+void CTK_VISUALIZATION_VTK_CORE_EXPORT setTransparency(vtkDiscretizableColorTransferFunction* colorTransferFunction, double transparency);
+
+}
+
+#endif

+ 462 - 0
Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferChart.cpp

@@ -0,0 +1,462 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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.
+
+=========================================================================*/
+#include "vtkDiscretizableColorTransferChart.h"
+
+#include "ctkVTKScalarsToColorsUtils.h"
+#include "vtkDiscretizableColorTransferControlPointsItem.h"
+
+#include <vtkAxis.h>
+#include <vtkColorTransferFunction.h>
+#include <vtkContextMouseEvent.h>
+#include <vtkContextScene.h>
+#include <vtkCompositeTransferFunctionItem.h>
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkFloatArray.h>
+#include <vtkObjectFactory.h>
+#include <vtkTable.h>
+#include <vtkTransform2D.h>
+
+// ----------------------------------------------------------------------------
+class vtkHistogramMarker : public vtkObject
+{
+public:
+
+  static vtkHistogramMarker* New();
+
+  vtkHistogramMarker();
+  virtual ~vtkHistogramMarker();
+
+  void SetPosition(double pos);
+
+  vtkSmartPointer<vtkTable> GetTable();
+
+private:
+  vtkSmartPointer<vtkTable> m_table;
+
+};
+
+// ----------------------------------------------------------------------------
+// vtkHistogramMarker methods
+
+// ----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkHistogramMarker)
+
+// ----------------------------------------------------------------------------
+vtkHistogramMarker::vtkHistogramMarker()
+{
+  m_table = vtkSmartPointer<vtkTable>::New();
+
+  vtkSmartPointer<vtkFloatArray> arrX = vtkSmartPointer<vtkFloatArray>::New();
+  arrX->SetName("X Axis");
+  m_table->AddColumn(arrX);
+
+  vtkSmartPointer<vtkFloatArray> arrC = vtkSmartPointer<vtkFloatArray>::New();
+  arrC->SetName("YAxis");
+  m_table->AddColumn(arrC);
+
+  m_table->SetNumberOfRows(2);
+  m_table->SetValue(0, 0, 55);
+  m_table->SetValue(0, 1, 0);
+
+  m_table->SetValue(1, 0, 55);
+  m_table->SetValue(1, 1, 1);
+}
+
+// ----------------------------------------------------------------------------
+vtkSmartPointer<vtkTable> vtkHistogramMarker::GetTable()
+{
+  return m_table;
+}
+
+// ----------------------------------------------------------------------------
+void vtkHistogramMarker::SetPosition(double pos)
+{
+  m_table->SetValue(0, 0, pos);
+  m_table->SetValue(1, 0, pos);
+  m_table->Modified();
+}
+
+// ----------------------------------------------------------------------------
+vtkHistogramMarker::~vtkHistogramMarker()
+{
+}
+
+// ----------------------------------------------------------------------------
+// vtkDiscretizableColorTransferChart methods
+
+// ----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkDiscretizableColorTransferChart)
+
+// ----------------------------------------------------------------------------
+vtkDiscretizableColorTransferChart::vtkDiscretizableColorTransferChart()
+{
+  this->Transform = vtkSmartPointer<vtkTransform2D>::New();
+
+  this->MinMarker = vtkSmartPointer<vtkHistogramMarker>::New();
+  this->MaxMarker = vtkSmartPointer<vtkHistogramMarker>::New();
+
+  this->ForceAxesToBoundsOn();
+  this->SetAutoAxes(false);
+  this->SetLayoutStrategy(vtkChart::FILL_SCENE);
+  this->SetRenderEmpty(true);
+  this->ZoomWithMouseWheelOff();
+
+  for (int i = 0; i < 4; ++i)
+  {
+    this->GetAxis(i)->SetVisible(true);
+    this->GetAxis(i)->SetNumberOfTicks(0);
+    this->GetAxis(i)->SetLabelsVisible(false);
+    this->GetAxis(i)->SetMargins(0, 0);
+    this->GetAxis(i)->SetTitle("");
+  }
+
+  this->CompositeHiddenItem = nullptr;
+  this->ControlPoints = nullptr;
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::SetColorTransferFunction(
+  vtkDiscretizableColorTransferFunction* function)
+{
+  if (function == nullptr)
+  {
+    vtkSmartPointer<vtkDiscretizableColorTransferFunction> emptyCtf =
+      vtkSmartPointer<vtkDiscretizableColorTransferFunction>::New();
+    this->SetColorTransferFunction(emptyCtf, 0, 255);
+    return;
+  }
+
+  this->SetColorTransferFunction(function,
+    function->GetRange()[0], function->GetRange()[1]);
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::SetColorTransferFunction(
+  vtkDiscretizableColorTransferFunction* function,
+  double rangeMin, double rangeMax)
+{
+  this->ColorTransferFunction = function;
+  this->ClearPlots();
+
+  ///Build the histogram chart
+  this->CompositeHiddenItem =
+    vtkSmartPointer<vtkCompositeTransferFunctionItem>::New();
+  this->CompositeHiddenItem->SetMaskAboveCurve(true);
+  this->CompositeHiddenItem->SetOpacity(0);
+  this->CompositeHiddenItem->SetInteractive(false);
+  this->CompositeHiddenItem->SetColorTransferFunction(function);
+  this->CompositeHiddenItem->SetOpacityFunction(
+    function->GetScalarOpacityFunction());
+
+  this->ControlPoints =
+    vtkSmartPointer<vtkDiscretizableColorTransferControlPointsItem>::New();
+  this->ControlPoints->SetUseOpacityPointHandles(false);
+  this->ControlPoints->SetEndPointsRemovable(false);
+  this->ControlPoints->SetInteractive(false);
+  this->ControlPoints->SetEndPointsXMovable(false);
+  this->ControlPoints->SetColorTransferFunction(function);
+  this->ControlPoints->SetOpacityFunction(
+    function->GetScalarOpacityFunction());
+  this->ControlPoints->SetPointsFunction(
+    vtkCompositeControlPointsItem::ColorAndOpacityPointsFunction);
+
+  this->OriginalRange[0] = rangeMin;
+  this->OriginalRange[1] = rangeMax;
+
+  ///Add the Min/Max Markers
+  this->MinPlot = AddPlot(vtkChart::LINE);
+  this->MaxPlot = AddPlot(vtkChart::LINE);
+  this->MinLinePlot = AddPlot(vtkChart::LINE);
+  this->MaxLinePlot = AddPlot(vtkChart::LINE);
+
+  this->MinPlot->SetInputData(this->MinMarker->GetTable(), 0, 1);
+  this->MaxPlot->SetInputData(this->MaxMarker->GetTable(), 0, 1);
+  this->MinLinePlot->SetInputData(this->MinMarker->GetTable(), 0, 1);
+  this->MaxLinePlot->SetInputData(this->MaxMarker->GetTable(), 0, 1);
+
+  this->MinPlot->SetColor(187, 187, 187, 100);
+  this->MinPlot->SetWidth(11.0);
+
+  this->MaxPlot->SetColor(187, 187, 187, 100);
+  this->MaxPlot->SetWidth(11.0);
+
+  this->MinLinePlot->SetColor(255, 255, 255, 255);
+  this->MinLinePlot->SetWidth(1.0);
+
+  this->MaxLinePlot->SetColor(255, 255, 255, 255);
+  this->MaxLinePlot->SetWidth(1.0);
+
+  this->CurrentRange[0] = rangeMin;
+  this->MinMarker->SetPosition(this->CurrentRange[0]);
+
+  this->CurrentRange[1] = rangeMax;
+  this->MaxMarker->SetPosition(this->CurrentRange[1]);
+
+  this->AddPlot(this->CompositeHiddenItem);
+  this->AddPlot(this->ControlPoints);
+
+  ///Disable zooming
+  this->SetActionToButton(ZOOM, -1);
+}
+
+// ----------------------------------------------------------------------------
+vtkDiscretizableColorTransferChart::~vtkDiscretizableColorTransferChart()
+{
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::UpdateMarkerPosition(
+  const vtkContextMouseEvent& m)
+{
+  vtkVector2f pos;
+  this->Transform->InverseTransformPoints(m.GetScenePos().GetData(),
+    pos.GetData(), 1);
+
+  if (rangeMoving == RangeMoving::MIN)
+  {
+    double newValue = static_cast<double>(pos.GetX());
+    if (newValue < this->OriginalRange[0])
+    {
+      this->CurrentRange[0] = this->OriginalRange[0];
+    }
+    else if (newValue < this->CurrentRange[1])
+    {
+      this->CurrentRange[0] = newValue;
+    }
+    this->MinMarker->SetPosition(this->CurrentRange[0]);
+    if (this->ColorTransferFunction != nullptr)
+    {
+      this->ControlPoints->StartProcessing();
+      ctk::remapColorScale(this->ColorTransferFunction, this->CurrentRange[0],
+        this->CurrentRange[1]);
+      this->ControlPoints->EndProcessing();
+    }
+  }
+  else if (rangeMoving == RangeMoving::MAX)
+  {
+    double newValue = static_cast<double>(pos.GetX());
+    if (newValue > this->OriginalRange[1])
+    {
+      this->CurrentRange[1] = this->OriginalRange[1];
+    }
+    else if (newValue > this->CurrentRange[0])
+    {
+      this->CurrentRange[1] = newValue;
+    }
+    this->MaxMarker->SetPosition(this->CurrentRange[1]);
+    if (this->ColorTransferFunction)
+    {
+      this->ControlPoints->StartProcessing();
+      ctk::remapColorScale(this->ColorTransferFunction, this->CurrentRange[0],
+        this->CurrentRange[1]);
+      this->ControlPoints->EndProcessing();
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferChart::MouseMoveEvent(
+  const vtkContextMouseEvent &mouse)
+{
+  if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON &&
+    rangeMoving != RangeMoving::NONE)
+  {
+    this->UpdateMarkerPosition(mouse);
+  }
+
+  return this->Superclass::MouseMoveEvent(mouse);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferChart::IsInRange(double min, double max,
+  double value)
+{
+  return value >= min && value < max;
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferChart::MouseButtonPressEvent(
+  const vtkContextMouseEvent& mouse)
+{
+  if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
+  {
+    if (rangeMoving == RangeMoving::NONE)
+    {
+      this->CalculateUnscaledPlotTransform(
+        this->CompositeHiddenItem->GetXAxis(),
+        this->CompositeHiddenItem->GetYAxis(), this->Transform.Get());
+
+      ///Need to compute the position of the cursor toward the marker
+      double minCoord[2] = {this->CurrentRange[0], 0};
+      double pixelMin[2];
+      this->Transform->TransformPoints(minCoord, pixelMin, 1);
+
+      double maxCoord[2] = {this->CurrentRange[1], 0};
+      double pixelMax[2];
+      this->Transform->TransformPoints(maxCoord, pixelMax, 1);
+
+      double catchWidth = 5;
+      ///If min and max get close prefer min over max
+      if (IsInRange(pixelMin[0] - catchWidth,
+        pixelMin[0] + catchWidth, mouse.GetPos().GetX()))
+      {
+        rangeMoving = RangeMoving::MIN;
+      }
+      else if (IsInRange( pixelMax[0] - catchWidth, pixelMax[0] + catchWidth,
+        mouse.GetPos().GetX()))
+      {
+        rangeMoving = RangeMoving::MAX;
+      }
+    }
+  }
+  return this->Superclass::MouseButtonPressEvent(mouse);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferChart::MouseButtonReleaseEvent(
+  const vtkContextMouseEvent &mouse)
+{
+  rangeMoving = RangeMoving::NONE;
+  return this->Superclass::MouseButtonReleaseEvent(mouse);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferChart::GetCurrentControlPointColor(
+  double rgb[3])
+{
+  vtkColorTransferFunction* ctf =
+    this->ControlPoints->GetColorTransferFunction();
+  if (!ctf)
+  {
+    return false;
+  }
+
+  vtkIdType currentIdx = this->ControlPoints->GetCurrentPoint();
+  if (currentIdx < 0)
+  {
+    return false;
+  }
+
+  double xrgbms[6];
+  ctf->GetNodeValue(currentIdx, xrgbms);
+  rgb[0] = xrgbms[1];
+  rgb[1] = xrgbms[2];
+  rgb[2] = xrgbms[3];
+
+  return true;
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::SetCurrentControlPointColor(
+  const double rgb[3])
+{
+  vtkColorTransferFunction* ctf =
+    this->ControlPoints->GetColorTransferFunction();
+  if (!ctf)
+  {
+    return;
+  }
+
+  vtkIdType currentIdx = this->ControlPoints->GetCurrentPoint();
+  if (currentIdx < 0)
+  {
+    return;
+  }
+
+  double xrgbms[6];
+  ctf->GetNodeValue(currentIdx, xrgbms);
+  xrgbms[1] = rgb[0];
+  xrgbms[2] = rgb[1];
+  xrgbms[3] = rgb[2];
+  ctf->SetNodeValue(currentIdx, xrgbms);
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::SetDataRange(double min, double max)
+{
+  this->DataRange[0] = min;
+  this->DataRange[1] = max;
+}
+
+// ----------------------------------------------------------------------------
+double* vtkDiscretizableColorTransferChart::GetDataRange()
+{
+  return this->DataRange;
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::SetCurrentRange(
+  double min, double max)
+{
+  ///check if min < max;
+  min = vtkMath::ClampValue(min, this->OriginalRange[0], this->OriginalRange[1]);
+  max = vtkMath::ClampValue(max, this->OriginalRange[0], this->OriginalRange[1]);
+  if (min < max)
+  {
+    this->CurrentRange[0] = 
+      min < this->OriginalRange[0] ? this->OriginalRange[0] : min;
+    this->CurrentRange[1] =
+      max > this->OriginalRange[1] ? this->OriginalRange[1] : max;
+    this->MinMarker->SetPosition(this->CurrentRange[0]);
+    this->MaxMarker->SetPosition(this->CurrentRange[1]);
+  }
+
+  if (this->ColorTransferFunction != nullptr)
+  {
+    this->ControlPoints->StartProcessing();
+    ctk::remapColorScale(this->ColorTransferFunction,
+      this->CurrentRange[0], this->CurrentRange[1]);
+    this->ControlPoints->EndProcessing();
+  }
+}
+
+// ----------------------------------------------------------------------------
+double* vtkDiscretizableColorTransferChart::GetCurrentRange()
+{
+  return this->CurrentRange;
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferChart::CenterRange(double center)
+{
+  double width = this->CurrentRange[1] - this->CurrentRange[0];
+  double minCenter = this->OriginalRange[0] + width / 2.0;
+  double maxCenter = this->OriginalRange[1] - width / 2.0;
+
+  center = vtkMath::ClampValue(center, minCenter, maxCenter);
+  double newMin = center - width / 2;
+  double newMax = newMin + width;
+
+  this->SetCurrentRange(newMin, newMax);
+}
+
+// ----------------------------------------------------------------------------
+vtkCompositeControlPointsItem*
+vtkDiscretizableColorTransferChart::GetControlPointsItem()
+{
+  return this->ControlPoints;
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferChart::IsProcessingColorTransferFunction() const
+{
+  return this->ControlPoints->IsProcessing();
+}
+

+ 106 - 0
Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferChart.h

@@ -0,0 +1,106 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __vtkDiscretizableColorTransferChart_h
+#define __vtkDiscretizableColorTransferChart_h
+
+#include "ctkVisualizationVTKCoreExport.h"
+
+#include <vtkChartXY.h>
+#include <vtkSmartPointer.h>
+
+class vtkCompositeControlPointsItem;
+class vtkCompositeTransferFunctionItem;
+class vtkDiscretizableColorTransferControlPointsItem;
+class vtkDiscretizableColorTransferFunction;
+class vtkHistogramMarker;
+class vtkTransform2D;
+
+class CTK_VISUALIZATION_VTK_CORE_EXPORT vtkDiscretizableColorTransferChart
+  : public vtkChartXY
+{
+public:
+  vtkTypeMacro(vtkDiscretizableColorTransferChart, vtkChartXY)
+  static vtkDiscretizableColorTransferChart* New();
+
+  void SetColorTransferFunction(
+    vtkDiscretizableColorTransferFunction* function);
+  void SetColorTransferFunction(
+    vtkDiscretizableColorTransferFunction* function,
+    double dataRangeMin, double dataRangeMax);
+
+  /// is a currently selected control point, false otherwise.
+  bool GetCurrentControlPointColor(double rgb[3]);
+
+  /// Set the color of the current color control point.
+  void SetCurrentControlPointColor(const double rgb[3]);
+
+  ///Set/Get the data range
+  void SetDataRange(double min, double max);
+  double* GetDataRange();
+
+  /// Set/Get the current range
+  ///
+  /// Set will clamp values into the current dataRange
+  void SetCurrentRange(double min, double max);
+  double* GetCurrentRange();
+
+  /// Center the current position to the given point
+  void CenterRange(double center);
+
+  vtkCompositeControlPointsItem* GetControlPointsItem();
+
+  bool IsProcessingColorTransferFunction() const;
+
+  bool MouseMoveEvent(const vtkContextMouseEvent &mouse) VTK_OVERRIDE;
+  bool MouseButtonPressEvent(const vtkContextMouseEvent& mouse) VTK_OVERRIDE;
+  bool MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse) VTK_OVERRIDE;
+
+protected:
+
+  static bool IsInRange(double min, double max, double value);
+  void UpdateMarkerPosition(const vtkContextMouseEvent& m);
+
+  vtkSmartPointer<vtkCompositeTransferFunctionItem> CompositeHiddenItem;
+  vtkSmartPointer<vtkDiscretizableColorTransferControlPointsItem> ControlPoints;
+
+  vtkSmartPointer<vtkTransform2D> Transform;
+  vtkSmartPointer<vtkDiscretizableColorTransferFunction> ColorTransferFunction;
+
+  vtkPlot *MinPlot;
+  vtkPlot *MaxPlot;
+  vtkPlot *MinLinePlot;
+  vtkPlot *MaxLinePlot;
+  vtkSmartPointer<vtkHistogramMarker> MinMarker;
+  vtkSmartPointer<vtkHistogramMarker> MaxMarker;
+
+  enum class RangeMoving {
+    NONE, MIN, MAX
+  } rangeMoving = RangeMoving::NONE;
+  double DataRange[2];
+  double CurrentRange[2];
+  double OriginalRange[2];
+
+private:
+  vtkDiscretizableColorTransferChart();
+  virtual ~vtkDiscretizableColorTransferChart();
+};
+
+#endif

+ 127 - 0
Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferControlPointsItem.cpp

@@ -0,0 +1,127 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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.
+
+=========================================================================*/
+
+#include "vtkDiscretizableColorTransferControlPointsItem.h"
+#include <vtkContextMouseEvent.h>
+#include <vtkObjectFactory.h>
+#include <vtkPiecewiseFunction.h>
+
+// ----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkDiscretizableColorTransferControlPointsItem)
+
+// ----------------------------------------------------------------------------
+vtkDiscretizableColorTransferControlPointsItem::
+  vtkDiscretizableColorTransferControlPointsItem()
+{
+}
+
+// ----------------------------------------------------------------------------
+vtkDiscretizableColorTransferControlPointsItem::
+  ~vtkDiscretizableColorTransferControlPointsItem()
+{
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferControlPointsItem::MouseButtonPressEvent(
+  const vtkContextMouseEvent& mouse)
+{
+  if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
+  {
+    vtkVector2f vpos = mouse.GetPos();
+    this->TransformScreenToData(vpos, vpos);
+    double pos[2];
+    pos[0] = vpos.GetX();
+    pos[1] = vpos.GetY();
+
+    bool pointOnFunction = this->PointNearPiecewiseFunction(pos);
+    if (!pointOnFunction)
+    {
+      this->SetCurrentPoint(-1);
+      return false;
+    }
+  }
+
+  return this->Superclass::MouseButtonPressEvent(mouse);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferControlPointsItem::
+  MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse)
+{
+  // If no point is selected, abort event
+  if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON &&
+    this->GetCurrentPoint() < 0)
+  {
+    return false;
+  }
+
+  return this->Superclass::MouseButtonReleaseEvent(mouse);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferControlPointsItem::MouseMoveEvent(
+  const vtkContextMouseEvent &mouse)
+{
+  // If no point is selected, abort event
+  if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON &&
+    this->GetCurrentPoint() < 0)
+  {
+    return false;
+  }
+
+   return this->Superclass::MouseMoveEvent(mouse);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferControlPointsItem::
+  PointNearPiecewiseFunction(const double position[2])
+{
+  double x = position[0];
+  double y = 0.0;
+
+  vtkPiecewiseFunction* pwf = this->GetOpacityFunction();
+  if (!pwf) {
+    return false;
+  }
+
+  // Evaluate the piewewise function at the given point and get the y position.
+  // If we are within a small distance of the piecewise function, return true.
+  // Otherwise, we are too far away from the line, and return false.
+  pwf->GetTable(x, x, 1, &y, 1);
+  return (fabs(y - position[1]) < 0.05);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkDiscretizableColorTransferControlPointsItem::IsProcessing()
+{
+  return this->StartedChanges > 0;
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferControlPointsItem::StartProcessing()
+{
+  this->StartChanges();
+}
+
+// ----------------------------------------------------------------------------
+void vtkDiscretizableColorTransferControlPointsItem::EndProcessing()
+{
+  this->EndChanges();
+}

+ 63 - 0
Libs/Visualization/VTK/Core/vtkDiscretizableColorTransferControlPointsItem.h

@@ -0,0 +1,63 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __vtkDiscretizableColorTransferControlPointsItem_h
+#define __vtkDiscretizableColorTransferControlPointsItem_h
+
+#include "ctkVisualizationVTKCoreExport.h"
+#include <vtkCompositeControlPointsItem.h>
+
+class vtkContextMouseEvent;
+
+/// \ingroup Visualization_VTK_Core
+///
+/// Special control points item class that overriding mouse events
+/// to add points only when close to the transfer function.
+class CTK_VISUALIZATION_VTK_CORE_EXPORT vtkDiscretizableColorTransferControlPointsItem
+  : public vtkCompositeControlPointsItem
+{
+public:
+  vtkTypeMacro(vtkDiscretizableColorTransferControlPointsItem,
+    vtkCompositeControlPointsItem)
+  static vtkDiscretizableColorTransferControlPointsItem* New();
+
+  bool MouseMoveEvent(const vtkContextMouseEvent &mouse) override;
+  bool MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse) override;
+  bool MouseButtonPressEvent(const vtkContextMouseEvent& mouse) override;
+
+  bool IsProcessing();
+  void StartProcessing();
+  void EndProcessing();
+
+protected:
+  vtkDiscretizableColorTransferControlPointsItem();
+  virtual ~vtkDiscretizableColorTransferControlPointsItem();
+
+  /// Utility function to determine whether a position is near the piecewise
+  /// function.
+  bool PointNearPiecewiseFunction(const double pos[2]);
+
+private:
+  vtkDiscretizableColorTransferControlPointsItem(
+    const vtkDiscretizableColorTransferControlPointsItem&); // Not implemented.
+  void operator=(const vtkDiscretizableColorTransferControlPointsItem&); // Not implemented.
+};
+
+#endif

+ 285 - 0
Libs/Visualization/VTK/Core/vtkScalarsToColorsContextItem.cpp

@@ -0,0 +1,285 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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.
+
+=========================================================================*/
+#include "vtkScalarsToColorsContextItem.h"
+
+// CTK includes
+#include "ctkVTKScalarsToColorsUtils.h"
+#include "vtkDiscretizableColorTransferChart.h"
+#include "vtkScalarsToColorsHistogramChart.h"
+#include "vtkScalarsToColorsPreviewChart.h"
+
+// VTK includes
+#include <vtkAxis.h>
+#include <vtkBrush.h>
+#include <vtkContextScene.h>
+#include <vtkCommand.h>
+#include <vtkCompositeControlPointsItem.h>
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkObjectFactory.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkTable.h>
+#include <vtkVector.h>
+
+//-----------------------------------------------------------------------------
+// Internal class EventForwarder
+//-----------------------------------------------------------------------------
+class vtkScalarsToColorsContextItem::EventForwarder
+{
+public:
+  EventForwarder(vtkScalarsToColorsContextItem* parent)
+    :Self(parent)
+  {}
+
+  ~EventForwarder()
+  {}
+
+  void ForwardEvent(vtkObject* vtkNotUsed(object), unsigned long eventId,
+    void* vtkNotUsed(data))
+  {
+    this->Self->InvokeEvent(eventId);
+  }
+
+  // Reference to owner of the EventForwarder
+  vtkScalarsToColorsContextItem* Self;
+};
+
+// ----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkScalarsToColorsContextItem)
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColorsContextItem::vtkScalarsToColorsContextItem()
+{
+  this->PrivateEventForwarder = new EventForwarder(this);
+
+  this->LastSceneSize = vtkVector2i(0, 0);
+
+  vtkSmartPointer<vtkBrush> b = vtkSmartPointer<vtkBrush>::New();
+  b->SetOpacityF(0);
+
+  //Histogram
+  this->HistogramChart =
+    vtkSmartPointer<vtkScalarsToColorsHistogramChart>::New();
+  this->HistogramChart->SetScalarVisibility(true);
+  AddItem(this->HistogramChart.GetPointer());
+
+  //Editor 
+  this->EditorChart =
+    vtkSmartPointer<vtkDiscretizableColorTransferChart>::New();
+  this->EditorChart->SetBackgroundBrush(b);
+  AddItem(this->EditorChart.GetPointer());
+
+  //Preview
+  this->PreviewChart =
+    vtkSmartPointer<vtkScalarsToColorsPreviewChart>::New();
+  AddItem(this->PreviewChart.GetPointer());
+
+  this->SetColorTransferFunction(nullptr);
+}
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColorsContextItem::~vtkScalarsToColorsContextItem()
+{
+  this->RemoveAllObservers();
+
+  delete this->PrivateEventForwarder;
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetColorTransferFunction(
+  vtkScalarsToColors* ctf)
+{
+  if (ctf == nullptr)
+  {
+    this->SetDiscretizableColorTransferFunction(nullptr);
+    return;
+  }
+
+  if (ctf->IsA("vtkDiscretizableColorTransferFunction"))
+  {
+    this->SetDiscretizableColorTransferFunction(
+      vtkDiscretizableColorTransferFunction::SafeDownCast(ctf));
+  }
+  else if (ctf->IsA("vtkColorTransferFunction"))
+  {
+    vtkSmartPointer<vtkColorTransferFunction> newCtf =
+      vtkColorTransferFunction::SafeDownCast(ctf);
+
+    vtkSmartPointer<vtkDiscretizableColorTransferFunction> dctf =
+      vtkSmartPointer<vtkDiscretizableColorTransferFunction>::New();
+    dctf->vtkColorTransferFunction::DeepCopy(newCtf);
+
+    vtkSmartPointer<vtkPiecewiseFunction> opacityFunction =
+      vtkSmartPointer<vtkPiecewiseFunction>::New();
+    opacityFunction->AddPoint(0.0, 0.0);
+    opacityFunction->AddPoint(255.0, 1.0);
+    dctf->SetScalarOpacityFunction(opacityFunction);
+    dctf->EnableOpacityMappingOn();
+
+    this->SetDiscretizableColorTransferFunction(dctf);
+  }
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetDiscretizableColorTransferFunction(
+  vtkDiscretizableColorTransferFunction* colorTransfer)
+{
+  vtkSmartPointer<vtkCompositeControlPointsItem> oldControlPoints =
+    this->EditorChart->GetControlPointsItem();
+
+  if (oldControlPoints != nullptr)
+  {
+    oldControlPoints->RemoveObservers(vtkCommand::EndEvent);
+    oldControlPoints->RemoveObservers(
+      vtkControlPointsItem::CurrentPointEditEvent);
+  }
+
+  this->ColorTransferFunction = colorTransfer;
+
+  this->EditorChart->SetColorTransferFunction(this->ColorTransferFunction);
+
+  this->PreviewChart->SetColorTransferFunction(this->ColorTransferFunction);
+
+  this->HistogramChart->SetLookupTable(this->ColorTransferFunction);
+
+  vtkSmartPointer<vtkCompositeControlPointsItem> controlPoints =
+    this->EditorChart->GetControlPointsItem();
+
+  controlPoints->AddObserver(vtkCommand::EndEvent,
+    this->PrivateEventForwarder, &EventForwarder::ForwardEvent);
+  controlPoints->AddObserver(vtkControlPointsItem::CurrentPointEditEvent,
+    this->PrivateEventForwarder, &EventForwarder::ForwardEvent);
+
+  /// Set the preview chart range to the color transfer function range
+  if (this->ColorTransferFunction == nullptr)
+  {
+    this->PreviewChart->GetAxis(vtkAxis::BOTTOM)->SetRange(0, 0);
+    return;
+  }
+  this->PreviewChart->GetAxis(vtkAxis::BOTTOM)->SetRange(
+    this->ColorTransferFunction->GetRange());
+}
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColors* vtkScalarsToColorsContextItem::GetColorTransferFunction()
+{
+  return this->ColorTransferFunction;
+}
+
+// ----------------------------------------------------------------------------
+vtkDiscretizableColorTransferFunction*
+  vtkScalarsToColorsContextItem::GetDiscretizableColorTransferFunction()
+{
+  return this->ColorTransferFunction;
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetHistogramTable(vtkTable* table,
+  const char* xAxisColumn, const char* yAxisColumn)
+{
+  this->HistogramChart->SetHistogramInputData(table, xAxisColumn, yAxisColumn);
+  this->HistogramChart->SetLookupTable(this->ColorTransferFunction);
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetDataRange(double min, double max)
+{
+  this->EditorChart->SetDataRange(min, max);
+}
+
+// ----------------------------------------------------------------------------
+double* vtkScalarsToColorsContextItem::GetDataRange()
+{
+  return this->EditorChart->GetDataRange();
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetCurrentRange(double min, double max)
+{
+  this->EditorChart->SetCurrentRange(min, max);
+}
+
+// ----------------------------------------------------------------------------
+double* vtkScalarsToColorsContextItem::GetCurrentRange()
+{
+  return this->EditorChart->GetCurrentRange();
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::CenterRange(double center)
+{
+  this->EditorChart->CenterRange(center);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkScalarsToColorsContextItem::GetCurrentControlPointColor(double rgb[3])
+{
+  return this->EditorChart->GetCurrentControlPointColor(rgb);
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetCurrentControlPointColor(
+    const double rgb[3])
+{
+  this->EditorChart->SetCurrentControlPointColor(rgb);
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::SetGlobalOpacity(double opacity)
+{
+  ctk::setTransparency(this->ColorTransferFunction, (opacity));
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsContextItem::InvertColorTransferFunction()
+{
+  ctk::reverseColorMap(this->ColorTransferFunction);
+}
+
+// ----------------------------------------------------------------------------
+bool vtkScalarsToColorsContextItem::IsProcessingColorTransferFunction() const
+{
+  return this->EditorChart->IsProcessingColorTransferFunction();
+}
+
+// ----------------------------------------------------------------------------
+bool vtkScalarsToColorsContextItem::Paint(vtkContext2D* painter)
+{
+  vtkContextScene* scene = this->GetScene();
+
+  int sceneWidth = scene->GetSceneWidth();
+  int sceneHeight = scene->GetSceneHeight();
+
+  if (sceneWidth != this->LastSceneSize.GetX()
+    || sceneHeight != this->LastSceneSize.GetY())
+  {
+    // Update the geometry size cache
+    this->LastSceneSize.Set(sceneWidth, sceneHeight);
+
+    float colorBarThickness = 20;
+    vtkRectf colorTransferFunctionChartSize(0.0, 0.0, sceneWidth,
+     colorBarThickness);
+
+    this->PreviewChart->SetSize(colorTransferFunctionChartSize);
+    this->PreviewChart->SetHiddenAxisBorder(0);
+    this->PreviewChart->RecalculateBounds();
+  }
+
+  return this->Superclass::Paint(painter);
+}

+ 110 - 0
Libs/Visualization/VTK/Core/vtkScalarsToColorsContextItem.h

@@ -0,0 +1,110 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __vtkScalarsToColorsContextItem_h
+#define __vtkScalarsToColorsContextItem_h
+
+#include "ctkVisualizationVTKCoreExport.h"
+
+#include <vtkAbstractContextItem.h>
+#include <vtkNew.h>
+#include <vtkSmartPointer.h>
+#include <vtkVector.h>
+
+class vtkScalarsToColorsHistogramChart;
+class vtkDiscretizableColorTransferChart;
+class vtkDiscretizableColorTransferFunction;
+class vtkScalarsToColors;
+class vtkScalarsToColorsPreviewChart;
+class vtkTable;
+
+/// \ingroup Visualization_VTK_Core
+/// This class uses three charts to combine an histogram from a dataset,
+/// a color transfer function editor, and a preview of the resulting color
+/// transfer function.
+class CTK_VISUALIZATION_VTK_CORE_EXPORT vtkScalarsToColorsContextItem
+  : public vtkAbstractContextItem
+{
+  vtkTypeMacro(vtkScalarsToColorsContextItem, vtkAbstractContextItem)
+public:
+  static vtkScalarsToColorsContextItem* New();
+
+  /// Set/Get the color transfer function as a vtkScalarsToColors
+  void SetColorTransferFunction(vtkScalarsToColors* ctf);
+  vtkScalarsToColors* GetColorTransferFunction();
+
+  /// Set/Get the color transfer function as a
+  /// vtkDiscretizableColorTransferFunction
+  void SetDiscretizableColorTransferFunction(
+    vtkDiscretizableColorTransferFunction* dctf);
+  vtkDiscretizableColorTransferFunction* GetDiscretizableColorTransferFunction();
+
+  /// Set the table used by the histogram chart
+  void SetHistogramTable(vtkTable* table,
+    const char* xAxisColumn, const char* yAxisColumn);
+
+  /// Paint event.
+  bool Paint(vtkContext2D* painter) override;
+
+  /// Get/Set the color of the current control point.
+  void SetCurrentControlPointColor(const double rgb[3]);
+  bool GetCurrentControlPointColor(double rgb[3]);
+
+  /// Get/Set the range defined by histogram data
+  void SetDataRange(double min, double max);
+  double* GetDataRange();
+
+  /// Get/Set the range used by the color transfer function
+  void SetCurrentRange(double min, double max);
+  double* GetCurrentRange();
+
+  /// Center the color tranfer function around \center
+  void CenterRange(double center);
+
+  /// Weight opacity control points by \opacity 
+  void SetGlobalOpacity(double opacity);
+
+  /// Reverse the color map of the transfer function. Note that opacity values
+  /// not modified.
+  void InvertColorTransferFunction();
+
+  /// Indicates if the color transfer function is being modified by control
+  /// points items.
+  bool IsProcessingColorTransferFunction() const;
+
+protected:
+  vtkSmartPointer<vtkDiscretizableColorTransferChart> EditorChart;
+  vtkSmartPointer<vtkScalarsToColorsPreviewChart> PreviewChart;
+  vtkSmartPointer<vtkScalarsToColorsHistogramChart> HistogramChart;
+
+  vtkSmartPointer<vtkDiscretizableColorTransferFunction> ColorTransferFunction;
+
+private:
+  vtkScalarsToColorsContextItem();
+  ~vtkScalarsToColorsContextItem() override;
+
+  /// Cached geometry of the scene
+  vtkVector2i LastSceneSize;
+
+  /// Internal event forwarder
+  class EventForwarder;
+  EventForwarder* PrivateEventForwarder;
+};
+#endif // __vtkScalarsToColorsContextItem_h

+ 87 - 0
Libs/Visualization/VTK/Core/vtkScalarsToColorsHistogramChart.cpp

@@ -0,0 +1,87 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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.
+
+=========================================================================*/
+#include "vtkScalarsToColorsHistogramChart.h"
+
+#include <vtkAxis.h>
+#include <vtkObjectFactory.h>
+#include <vtkPen.h>
+#include <vtkPlotBar.h>
+#include <vtkScalarsToColors.h>
+#include <vtkTable.h>
+
+// ----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkScalarsToColorsHistogramChart)
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColorsHistogramChart::vtkScalarsToColorsHistogramChart()
+{
+  this->ForceAxesToBoundsOn();
+  this->SetLayoutStrategy(vtkChart::FILL_SCENE);
+
+  for (int i = 0; i < 4; ++i)
+  {
+    this->GetAxis(i)->SetVisible(true);
+    this->GetAxis(i)->SetNumberOfTicks(0);
+    this->GetAxis(i)->SetLabelsVisible(false);
+    this->GetAxis(i)->SetMargins(0, 0);
+    this->GetAxis(i)->SetTitle("");
+  }
+
+  this->SetBarWidthFraction(1.0);
+
+  // Set up the plot bar
+  this->AddPlot(this->HistogramPlotBar.Get());
+
+  this->HistogramPlotBar->GetPen()->SetLineType(vtkPen::NO_PEN);
+  this->HistogramPlotBar->SetSelectable(false);
+  this->HistogramPlotBar->SetInteractive(false);
+}
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColorsHistogramChart::~vtkScalarsToColorsHistogramChart()
+{
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsHistogramChart::SetHistogramInputData(vtkTable* table,
+    const char* xAxisColumn, const char* yAxisColumn)
+{
+  this->HistogramPlotBar->SetInputData(table, xAxisColumn, yAxisColumn);
+  this->SelectColorArray(xAxisColumn);
+  this->RecalculateBounds();
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsHistogramChart::SetScalarVisibility(bool visible)
+{
+  this->HistogramPlotBar->SetScalarVisibility(visible);
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsHistogramChart::SetLookupTable(vtkScalarsToColors* lut)
+{
+  this->HistogramPlotBar->SetLookupTable(lut);
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsHistogramChart::SelectColorArray(const char* arrayName)
+{
+  this->HistogramPlotBar->SelectColorArray(arrayName);
+}

+ 61 - 0
Libs/Visualization/VTK/Core/vtkScalarsToColorsHistogramChart.h

@@ -0,0 +1,61 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __vtkScalarsToColorsHistogramChart_h
+#define __vtkScalarsToColorsHistogramChart_h
+
+#include "ctkVisualizationVTKCoreExport.h"
+
+#include <vtkChartXY.h>
+#include <vtkNew.h>
+
+class vtkPlotBar;
+class vtkScalarsToColors;
+class vtkTable;
+
+class CTK_VISUALIZATION_VTK_CORE_EXPORT vtkScalarsToColorsHistogramChart
+  : public vtkChartXY
+{
+public:
+  vtkTypeMacro(vtkScalarsToColorsHistogramChart, vtkChartXY)
+  static vtkScalarsToColorsHistogramChart* New();
+
+  /// Set input for histogram
+  virtual void SetHistogramInputData(vtkTable* table, const char* xAxisColumn,
+    const char* yAxisColumn);
+
+  /// Set scalar visibility in the histogram plot bar
+  virtual void SetScalarVisibility(bool visible);
+
+  /// Set lookup table
+  virtual void SetLookupTable(vtkScalarsToColors* lut);
+
+  /// Set the color array name
+  virtual void SelectColorArray(const char* arrayName);
+
+protected:
+  vtkNew<vtkPlotBar> HistogramPlotBar;
+
+private:
+  vtkScalarsToColorsHistogramChart();
+  virtual ~vtkScalarsToColorsHistogramChart();
+};
+
+#endif // __vtkScalarsToColorsHistogramChart_h

+ 88 - 0
Libs/Visualization/VTK/Core/vtkScalarsToColorsPreviewChart.cpp

@@ -0,0 +1,88 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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.
+
+=========================================================================*/
+
+#include "vtkScalarsToColorsPreviewChart.h"
+
+#include <vtkAxis.h>
+#include <vtkColorTransferFunctionItem.h>
+#include <vtkColorTransferFunction.h>
+#include <vtkObjectFactory.h>
+
+// ----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkScalarsToColorsPreviewChart)
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColorsPreviewChart::vtkScalarsToColorsPreviewChart()
+{
+  this->SetAutoAxes(false);
+  this->SetRenderEmpty(true);
+  this->SetLayoutStrategy(vtkChart::FILL_RECT);
+  this->ZoomWithMouseWheelOff();
+
+  for (int i = 0; i < 4; ++i)
+  {
+    this->GetAxis(i)->SetNumberOfTicks(0);
+    this->GetAxis(i)->SetLabelsVisible(false);
+    this->GetAxis(i)->SetTitle("");
+  }
+  this->GetAxis(vtkAxis::LEFT)->SetVisible(true);
+  this->GetAxis(vtkAxis::LEFT)->SetMargins(20, 0);
+  this->GetAxis(vtkAxis::RIGHT)->SetVisible(true);
+  this->GetAxis(vtkAxis::RIGHT)->SetMargins(20, 0);
+  this->GetAxis(vtkAxis::BOTTOM)->SetVisible(false);
+  this->GetAxis(vtkAxis::BOTTOM)->SetMargins(0, 0);
+  this->GetAxis(vtkAxis::TOP)->SetVisible(false);
+  this->GetAxis(vtkAxis::TOP)->SetMargins(0, 0);
+
+  //
+  this->GetAxis(vtkAxis::BOTTOM)->SetBehavior(vtkAxis::FIXED);
+
+  this->SetInteractive(false);
+}
+
+// ----------------------------------------------------------------------------
+void vtkScalarsToColorsPreviewChart::SetColorTransferFunction(
+  vtkColorTransferFunction* function)
+{
+  this->ClearPlots();
+
+  vtkSmartPointer<vtkColorTransferFunctionItem> compositeVisibleItem =
+    vtkSmartPointer<vtkColorTransferFunctionItem>::New();
+  compositeVisibleItem->SetMaskAboveCurve(false);
+  compositeVisibleItem->SetInteractive(false);
+  compositeVisibleItem->SetOpacity(1);
+  compositeVisibleItem->SelectableOff();
+  if (function == nullptr)
+  {
+    vtkSmartPointer<vtkColorTransferFunction> ctf =
+      vtkSmartPointer<vtkColorTransferFunction>::New();
+    compositeVisibleItem->SetColorTransferFunction(ctf);
+  }
+  else
+  {
+    compositeVisibleItem->SetColorTransferFunction(function);
+  }
+  this->AddPlot(compositeVisibleItem);
+}
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColorsPreviewChart::~vtkScalarsToColorsPreviewChart()
+{
+}

+ 20 - 14
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsUtils.h

@@ -18,22 +18,28 @@
 
 =========================================================================*/
 
-#ifndef __ctkVTKScalarsToColorsUtils_h
-#define __ctkVTKScalarsToColorsUtils_h
+#ifndef __vtkScalarsToColorsPreviewChart_h
+#define __vtkScalarsToColorsPreviewChart_h
 
-// CTK includes
-#include "ctkVisualizationVTKWidgetsExport.h"
+#include "ctkVisualizationVTKCoreExport.h"
 
-// VTK includes
-class vtkScalarsToColors;
+#include <vtkChartXY.h>
+#include <vtkSmartPointer.h>
 
-namespace ctk {
-///
-/// \ingroup Visualization_VTK_Widgets
-/// Convert a vtkScalarsToColors into a QImage
-/// If size is empty, it will use the large icon size of the application style
-QImage CTK_VISUALIZATION_VTK_WIDGETS_EXPORT scalarsToColorsImage(vtkScalarsToColors* scalarsToColors, const QSize& size = QSize());
+class vtkColorTransferFunction;
 
-}
+class CTK_VISUALIZATION_VTK_CORE_EXPORT vtkScalarsToColorsPreviewChart
+  : public vtkChartXY
+{
+public:
+  vtkTypeMacro(vtkScalarsToColorsPreviewChart, vtkChartXY)
+  static vtkScalarsToColorsPreviewChart* New();
 
-#endif
+  void SetColorTransferFunction(vtkColorTransferFunction* colorTransfer);
+
+protected:
+  vtkScalarsToColorsPreviewChart();
+  virtual ~vtkScalarsToColorsPreviewChart();
+};
+
+#endif /* __vtkScalarsToColorsPreviewChart_h */

+ 7 - 2
Libs/Visualization/VTK/Widgets/CMakeLists.txt

@@ -53,8 +53,8 @@ set(KIT_SRCS
   ctkVTKRenderView_p.h
   ctkVTKScalarBarWidget.cpp
   ctkVTKScalarBarWidget.h
-  ctkVTKScalarsToColorsUtils.cpp
-  ctkVTKScalarsToColorsUtils.h
+  ctkVTKScalarsToColorsComboBox.cpp
+  ctkVTKScalarsToColorsComboBox.h
   ctkVTKSliceView.cpp
   ctkVTKSliceView.h
   ctkVTKSliceView_p.h
@@ -89,6 +89,7 @@ set(KIT_MOC_SRCS
   ctkVTKRenderView.h
   ctkVTKRenderView_p.h
   ctkVTKScalarBarWidget.h
+  ctkVTKScalarsToColorsComboBox.h
   ctkVTKSliceView.h
   ctkVTKSliceView_p.h
   ctkVTKSurfaceMaterialPropertyWidget.h
@@ -99,6 +100,7 @@ set(KIT_MOC_SRCS
 
 # UI files
 set(KIT_UI_FORMS
+  Resources/UI/ctkVTKDiscretizableColorTransferWidget.ui
   Resources/UI/ctkVTKScalarBarWidget.ui
   Resources/UI/ctkVTKTextPropertyWidget.ui
   Resources/UI/ctkVTKPropertyWidget.ui
@@ -146,6 +148,8 @@ if(${CTK_USE_CHARTS})
   set(KIT_SRCS
       ctkVTKChartView.cpp
       ctkVTKChartView.h
+	  ctkVTKDiscretizableColorTransferWidget.h
+	  ctkVTKDiscretizableColorTransferWidget.cpp
       ctkVTKVolumePropertyWidget.cpp
       ctkVTKVolumePropertyWidget.h
       ctkVTKScalarsToColorsView.cpp
@@ -155,6 +159,7 @@ if(${CTK_USE_CHARTS})
       ${KIT_SRCS})
   set(KIT_MOC_SRCS
       ctkVTKChartView.h
+	  ctkVTKDiscretizableColorTransferWidget.h
       ctkVTKVolumePropertyWidget.h
       ctkVTKScalarsToColorsView.h
       ctkVTKScalarsToColorsWidget.h

BIN
Libs/Visualization/VTK/Widgets/Resources/Icons/invert.png


BIN
Libs/Visualization/VTK/Widgets/Resources/Icons/resetRange.png


BIN
Libs/Visualization/VTK/Widgets/Resources/Icons/resetRangeCustom.png


+ 188 - 0
Libs/Visualization/VTK/Widgets/Resources/UI/ctkVTKDiscretizableColorTransferWidget.ui

@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ctkVTKDiscretizableColorTransferWidget</class>
+ <widget class="QWidget" name="ctkVTKDiscretizableColorTransferWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>447</width>
+    <height>232</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Color Transfer Function</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item row="9" column="1">
+    <widget class="QLabel" name="minOpacityLabel">
+     <property name="text">
+      <string>0</string>
+     </property>
+    </widget>
+   </item>
+   <item row="9" column="3">
+    <widget class="QToolButton" name="optionButton">
+     <property name="contextMenuPolicy">
+      <enum>Qt::DefaultContextMenu</enum>
+     </property>
+     <property name="toolTip">
+      <string>Other options</string>
+     </property>
+    </widget>
+   </item>
+   <item row="10" column="1" colspan="3">
+    <widget class="ctkRangeWidget" name="rangeSlider"/>
+   </item>
+   <item row="7" column="3">
+    <widget class="QToolButton" name="invertColorTransferFunctionButton">
+     <property name="toolTip">
+      <string>Invert color map</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../ctkVTKWidgets.qrc">
+       <normaloff>:/Icons/invert.png</normaloff>:/Icons/invert.png</iconset>
+     </property>
+     <property name="popupMode">
+      <enum>QToolButton::DelayedPopup</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="2" rowspan="7">
+    <widget class="QVTKWidget" name="scalarsToColorsView" native="true"/>
+   </item>
+   <item row="3" column="3">
+    <widget class="QToolButton" name="resetRangeButton">
+     <property name="toolTip">
+      <string>Reset to data range</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../ctkVTKWidgets.qrc">
+       <normaloff>:/Icons/resetRange.png</normaloff>:/Icons/resetRange.png</iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="1" rowspan="5">
+    <widget class="ctkDoubleSlider" name="opacitySlider">
+     <property name="value">
+      <double>1.000000000000000</double>
+     </property>
+     <property name="singleStep">
+      <double>0.100000000000000</double>
+     </property>
+     <property name="pageStep">
+      <double>0.200000000000000</double>
+     </property>
+     <property name="minimum">
+      <double>0.000001000000000</double>
+     </property>
+     <property name="maximum">
+      <double>1.000000000000000</double>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1">
+    <widget class="QLabel" name="maxOpacityLabel">
+     <property name="text">
+      <string>1</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="3">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="5" column="3">
+    <widget class="QToolButton" name="centerRangeButton">
+     <property name="toolTip">
+      <string>Center current range on median</string>
+     </property>
+     <property name="icon">
+      <iconset resource="../ctkVTKWidgets.qrc">
+       <normaloff>:/Icons/resetRangeCustom.png</normaloff>:/Icons/resetRangeCustom.png</iconset>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="3">
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="8" column="3">
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="1" colspan="3">
+    <widget class="ctkVTKScalarsToColorsComboBox" name="scalarsToColorsSelector"/>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ctkDoubleSlider</class>
+   <extends>QWidget</extends>
+   <header>ctkDoubleSlider.h</header>
+  </customwidget>
+  <customwidget>
+   <class>ctkRangeWidget</class>
+   <extends>QWidget</extends>
+   <header>ctkRangeWidget.h</header>
+  </customwidget>
+  <customwidget>
+   <class>ctkVTKScalarsToColorsComboBox</class>
+   <extends>QComboBox</extends>
+   <header>ctkVTKScalarsToColorsComboBox.h</header>
+  </customwidget>
+  <customwidget>
+   <class>QVTKWidget</class>
+   <extends>QWidget</extends>
+   <header>QVTKWidget.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources>
+  <include location="../ctkVTKWidgets.qrc"/>
+ </resources>
+ <connections/>
+</ui>

+ 3 - 0
Libs/Visualization/VTK/Widgets/Resources/ctkVTKWidgets.qrc

@@ -1,5 +1,8 @@
 <!DOCTYPE RCC><RCC version="1.0">
   <qresource>
+    <file>Icons/invert.png</file>
+    <file>Icons/resetRange.png</file>
+    <file>Icons/resetRangeCustom.png</file>
     <file>Icons/threshold.png</file>
   </qresource>
 </RCC>

+ 3 - 1
Libs/Visualization/VTK/Widgets/Testing/Cpp/CMakeLists.txt

@@ -26,6 +26,7 @@ set(TEST_SOURCES
   ctkTransferFunctionViewTest5.cpp
   ctkVTKPropertyWidgetTest.cpp
   ctkVTKRenderViewTest1.cpp
+  ctkVTKScalarsToColorsComboBoxTest1.cpp
   ctkVTKScalarsToColorsUtilsTest1.cpp
   ctkVTKSliceViewTest1.cpp
   ctkVTKSurfaceMaterialPropertyWidgetTest1.cpp
@@ -39,6 +40,7 @@ if(CTK_USE_CHARTS)
   set(TEST_SOURCES
       ctkVTKChartViewTest1.cpp
       ctkVTKVolumePropertyWidgetTest1.cpp
+	  ctkVTKDiscretizableColorTransferWidgetTest1.cpp
       ctkVTKScalarsToColorsViewTest1.cpp
       ctkVTKScalarsToColorsViewTest2.cpp
       ctkVTKScalarsToColorsViewTest3.cpp
@@ -136,7 +138,7 @@ endif()
 
 
 
-target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${VTK_CHARTS_LIB} ${CTK_BASE_LIBRARIES} CTKQtTesting)
+target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${VTK_CHARTS_LIB} ${CTK_BASE_LIBRARIES})
 
 if(CTK_QT_VERSION VERSION_GREATER "4")
   target_link_libraries(${KIT}CppTests ${Qt5Test_LIBRARIES})

+ 79 - 0
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKDiscretizableColorTransferWidgetTest1.cpp

@@ -0,0 +1,79 @@
+/*=========================================================================
+
+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.apache.org/licenses/LICENSE-2.0.txt
+
+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 <QTimer>
+
+// CTK includes
+#include "ctkVTKDiscretizableColorTransferWidget.h"
+#include "ctkVTKScalarsToColorsComboBox.h"
+
+// VTK includes
+#include <QVTKWidget.h>
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkNew.h>
+#include <vtkPiecewiseFunction.h>
+
+//-----------------------------------------------------------------------------
+int ctkVTKDiscretizableColorTransferWidgetTest1(int argc, char * argv[])
+{
+  QApplication app(argc, argv);
+
+  ///Dummy presets
+  vtkNew<vtkDiscretizableColorTransferFunction> dctf0;
+  dctf0->AddRGBPoint(0.0, 0.0, 0.0, 1.0);
+  dctf0->AddRGBPoint(255.0, 1.0, 0.0, 0.0);
+  vtkNew<vtkPiecewiseFunction> pf0;
+  pf0->AddPoint(0.0, 0.0);
+  pf0->AddPoint(255.0, 1.0);
+  dctf0->SetScalarOpacityFunction(pf0.Get());
+  dctf0->EnableOpacityMappingOn();
+
+  vtkNew<vtkDiscretizableColorTransferFunction> dctf1;
+  dctf1->AddRGBPoint(0.0, 1.0, 1.0, 1.0);
+  dctf1->AddRGBPoint(255.0, 0.0, 0.0, 0.0);
+  vtkNew<vtkPiecewiseFunction> pf1;
+  pf1->AddPoint(0.0, 0.0);
+  pf1->AddPoint(255.0, 0.5);
+  dctf1->SetScalarOpacityFunction(pf1.Get());
+  dctf1->EnableOpacityMappingOn();
+
+  vtkNew<vtkColorTransferFunction> ctf0;
+  ctf0->AddRGBPoint(0.0, 1.0, 0.0, 1.0);
+  ctf0->AddRGBPoint(255.0, 0.0, 1.0, 0.0);
+
+  /// Discretizable transfer function widget
+  ctkVTKDiscretizableColorTransferWidget mWidget;
+  mWidget.setColorTransferFunction(dctf0.Get());
+  mWidget.show();
+
+  /// Add presets to the widget selector
+  mWidget.scalarsToColorsSelector()->addScalarsToColors(dctf1.Get(), "White to Black");
+  mWidget.scalarsToColorsSelector()->addScalarsToColors(ctf0.Get(), "Purple to Green");
+
+  if (argc < 2 || QString(argv[1]) != "-I")
+  {
+    QTimer::singleShot(1000, &app, SLOT(quit()));
+  }
+
+  return app.exec();
+}
+

+ 79 - 0
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKScalarsToColorsComboBoxTest1.cpp

@@ -0,0 +1,79 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 <QDebug>
+#include <QTimer>
+
+// CTK includes
+#include "ctkVTKScalarsToColorsComboBox.h"
+
+// VTK includes
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkNew.h>
+#include <vtkPiecewiseFunction.h>
+
+// STD includes
+
+//-----------------------------------------------------------------------------
+int ctkVTKScalarsToColorsComboBoxTest1(int argc, char * argv [] )
+{
+  QApplication app(argc, argv);
+
+  ctkVTKScalarsToColorsComboBox scalarsToColorsComboBox;
+  //scalarsToColorsComboBox.setFixedHeight(25);
+  //scalarsToColorsComboBox.setDefaultText("Select color transfer function ...");
+  //scalarsToColorsComboBox.setCurrentIndex(-1);//Start with default
+
+  //Dummy presets
+  vtkNew<vtkDiscretizableColorTransferFunction> discretizableCTF;
+  discretizableCTF->AddRGBPoint(0.0, 0, 0, 1.0);
+  discretizableCTF->AddRGBPoint(255.0, 1.0, 0, 0);
+  vtkNew<vtkPiecewiseFunction> piecewiseFunction;
+  piecewiseFunction->AddPoint(0.0, 0);
+  piecewiseFunction->AddPoint(255.0, 1.0);
+  discretizableCTF->SetScalarOpacityFunction(piecewiseFunction);
+  discretizableCTF->EnableOpacityMappingOn();
+  vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction =
+    vtkSmartPointer<vtkColorTransferFunction>::New();
+  colorTransferFunction->AddRGBPoint(255, 0, 0, 1.0);
+  colorTransferFunction->AddRGBPoint(0, 1.0, 0, 0);
+
+  scalarsToColorsComboBox.addScalarsToColors(discretizableCTF.Get(), "ColorTransferFunctionTest1");
+  scalarsToColorsComboBox.addScalarsToColors(colorTransferFunction.Get(), "ColorTransferFunctionTest2");
+
+  if (scalarsToColorsComboBox.count() != 2)
+  {
+    std::cerr << "Line " << __LINE__ << " - Expected 2 items in the combobox\n"
+      "\tCurrent count: " << scalarsToColorsComboBox.count() << "\n";
+    return EXIT_FAILURE;
+  }
+  scalarsToColorsComboBox.addScalarsToColors(nullptr, "(none)");
+
+  scalarsToColorsComboBox.show();
+
+  if (argc < 2 || QString(argv[1]) != "-I")
+  {
+    QTimer::singleShot(1000, &app, SLOT(quit()));
+  }
+
+  return app.exec();
+}

+ 1 - 1
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKScalarsToColorsUtilsTest1.cpp

@@ -26,7 +26,7 @@
 
 // CTK includes
 #include "ctkWidgetsUtils.h"
-#include "ctkVTKScalarsToColorsUtils.h"
+#include "ctkVTKWidgetsUtils.h"
 
 // VTK includes
 #include <vtkColorTransferFunction.h>

+ 549 - 0
Libs/Visualization/VTK/Widgets/ctkVTKDiscretizableColorTransferWidget.cpp

@@ -0,0 +1,549 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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.
+
+=========================================================================*/
+
+#include "ctkVTKDiscretizableColorTransferWidget.h"
+
+// CTK includes
+#include "ctkColorPickerButton.h"
+#include "ctkDoubleSlider.h"
+#include "ctkVTKScalarsToColorsComboBox.h"
+#include "ctkVTKScalarsToColorsUtils.h"
+#include "ui_ctkVTKDiscretizableColorTransferWidget.h"
+#include "vtkScalarsToColorsContextItem.h"
+
+// Qt includes
+#include <QColorDialog>
+#include <QCheckBox>
+#include <QDoubleValidator>
+#include <QHBoxLayout>
+#include <QIcon>
+#include <QLineEdit>
+#include <QLabel>
+#include <QMenu>
+#include <QPushButton>
+#include <QSpinBox>
+#include <QTimer>
+#include <QToolButton>
+#include <QVBoxLayout>
+#include <QWidgetAction>
+
+// VTK includes
+#include <QVTKWidget.h>
+#include <vtkCallbackCommand.h>
+#include <vtkContextScene.h>
+#include <vtkContextView.h>
+#include <vtkControlPointsItem.h>
+#include <vtkDiscretizableColorTransferFunction.h>
+#include <vtkDoubleArray.h>
+#include <vtkEventQtSlotConnect.h>
+#include <vtkIntArray.h>
+#include <vtkImageAccumulate.h>
+#include <vtkImageData.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkRenderer.h>
+#include <vtkRenderWindow.h>
+#include <vtkScalarsToColors.h>
+#include <vtkTable.h>
+
+// ----------------------------------------------------------------------------
+class ctkVTKDiscretizableColorTransferWidgetPrivate :
+  public Ui_ctkVTKDiscretizableColorTransferWidget
+{
+  Q_DECLARE_PUBLIC(ctkVTKDiscretizableColorTransferWidget);
+protected:
+  ctkVTKDiscretizableColorTransferWidget* const q_ptr;
+
+public:
+  ctkVTKDiscretizableColorTransferWidgetPrivate(
+    ctkVTKDiscretizableColorTransferWidget& object);
+
+  void setupUi(QWidget* widget);
+
+  vtkSmartPointer<vtkScalarsToColorsContextItem> scalarsToColorsContextItem;
+  vtkSmartPointer<vtkContextView> scalarsToColorsContextView;
+  vtkSmartPointer<vtkEventQtSlotConnect> eventLink;
+
+  ///Option part
+  ctkColorPickerButton* nanButton;
+  QCheckBox* discretizeCheckBox;
+  QSpinBox* nbOfDiscreteValuesSpinBox;
+
+  /// Stores the range of the data.
+  /// Extracted from the histogram
+  double dataRange[2];
+  double dataMean;
+
+  double previousOpacityValue;
+
+  vtkSmartPointer<vtkCallbackCommand> colorTransferFunctionModified;
+  static void colorTransferFunctionModifiedCallback(vtkObject *caller,
+    unsigned long eid, void *clientdata, void *calldata);
+};
+
+// ----------------------------------------------------------------------------
+ctkVTKDiscretizableColorTransferWidgetPrivate
+::ctkVTKDiscretizableColorTransferWidgetPrivate(
+  ctkVTKDiscretizableColorTransferWidget& object)
+  : q_ptr(&object)
+{
+  this->scalarsToColorsSelector = nullptr;
+
+  // Option menu
+  this->nanButton = nullptr;
+  this->discretizeCheckBox = nullptr;
+  this->nbOfDiscreteValuesSpinBox = nullptr;
+
+  this->dataRange[0] = VTK_DOUBLE_MAX;
+  this->dataRange[1] = VTK_DOUBLE_MIN;
+  this->dataMean = 0.;
+
+  this->previousOpacityValue = 0.;
+
+  this->colorTransferFunctionModified =
+    vtkSmartPointer<vtkCallbackCommand>::New();
+  this->colorTransferFunctionModified->SetClientData(this);
+  this->colorTransferFunctionModified->SetCallback(
+    this->colorTransferFunctionModifiedCallback);
+}
+
+//-----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidgetPrivate::setupUi(QWidget* widget)
+{
+  Q_Q(ctkVTKDiscretizableColorTransferWidget);
+
+  this->Ui_ctkVTKDiscretizableColorTransferWidget::setupUi(widget);
+
+  this->scalarsToColorsContextItem =
+    vtkSmartPointer<vtkScalarsToColorsContextItem>::New();
+  this->scalarsToColorsContextView = vtkSmartPointer<vtkContextView> ::New();
+
+  this->scalarsToColorsContextView->GetScene()->AddItem(
+    this->scalarsToColorsContextItem.Get());
+  this->scalarsToColorsContextView->SetInteractor(
+    this->scalarsToColorsView->GetInteractor());
+  this->scalarsToColorsView->SetRenderWindow(
+    this->scalarsToColorsContextView->GetRenderWindow());
+
+  q->setViewBackgroundColor(QColor(49, 54, 59));
+
+  this->previousOpacityValue = opacitySlider->value();
+
+  this->scalarsToColorsSelector->addScalarsToColors(nullptr, q->tr("Reset"));
+  this->scalarsToColorsSelector->setCurrentIndex(-1);
+
+  this->eventLink = vtkSmartPointer<vtkEventQtSlotConnect>::New();
+  this->eventLink->Connect(scalarsToColorsContextItem.Get(),
+    vtkControlPointsItem::CurrentPointEditEvent,
+    q, SLOT(onCurrentPointEdit()));
+
+  this->scalarsToColorsContextItem->AddObserver(vtkCommand::EndEvent,
+    this->colorTransferFunctionModified);
+
+  QObject::connect(this->scalarsToColorsSelector,
+    SIGNAL(currentScalarsToColorsChanged(vtkScalarsToColors*)),
+    q, SLOT(onPaletteIndexChanged(vtkScalarsToColors*)));
+
+  QObject::connect(opacitySlider, SIGNAL(valueChanged(double)),
+    q, SLOT(setGlobalOpacity(double)));
+
+  QObject::connect(resetRangeButton, SIGNAL(clicked()),
+    q, SLOT(resetColorTransferFunctionRange()));
+
+  QObject::connect(centerRangeButton, SIGNAL(clicked()),
+    q, SLOT(centerColorTransferFunctionRange()));
+
+  QObject::connect(invertColorTransferFunctionButton, SIGNAL(clicked()),
+    q, SLOT(invertColorTransferFunction()));
+
+  QObject::connect(rangeSlider, SIGNAL(valuesChanged(double, double)),
+    q, SLOT(setColorTransferFunctionRange(double, double)));
+
+  /// Option panel menu
+  QWidget* nanColorWidget = new QWidget(optionButton);
+  QHBoxLayout* nanColorLayout = new QHBoxLayout(nanColorWidget);
+  QWidget* discretizeWidget = new QWidget(optionButton);
+  QHBoxLayout* discretizeLayout = new QHBoxLayout(discretizeWidget);
+
+  nanColorLayout->setContentsMargins(0, 0, 0, 0);
+  discretizeLayout->setContentsMargins(0, 0, 0, 0);
+
+  optionButton->setIcon(q->style()->standardIcon(
+    QStyle::SP_FileDialogDetailedView, nullptr, optionButton));
+
+  QLabel* nanLabel = new QLabel(q->tr("NaN values"));
+  nanButton = new ctkColorPickerButton;
+  nanButton->setToolTip(q->tr("NaN color"));
+  nanColorLayout->addWidget(nanButton);
+  nanColorLayout->addWidget(nanLabel);
+
+  discretizeCheckBox = new QCheckBox;
+  discretizeCheckBox->setText(q->tr("Discretize"));
+  discretizeCheckBox->setToolTip(q->tr("Discretize color transfer function"));
+  nbOfDiscreteValuesSpinBox = new QSpinBox;
+  nbOfDiscreteValuesSpinBox->setMinimum(1);
+  nbOfDiscreteValuesSpinBox->setMaximum(255);
+  nbOfDiscreteValuesSpinBox->setToolTip(q->tr("Number of discrete values"));
+  nbOfDiscreteValuesSpinBox->setEnabled(discretizeCheckBox->isChecked());
+
+  discretizeLayout->addWidget(discretizeCheckBox);
+  discretizeLayout->addWidget(nbOfDiscreteValuesSpinBox);
+
+  QMenu* optionMenu = new QMenu(optionButton);
+  QWidgetAction* nanColorAction = new QWidgetAction(optionButton);
+  nanColorAction->setDefaultWidget(nanColorWidget);
+  QWidgetAction* discretizeAction = new QWidgetAction(optionButton);
+  discretizeAction->setDefaultWidget(discretizeWidget);
+  optionMenu->addAction(nanColorAction);
+  optionMenu->addSeparator();
+  optionMenu->addAction(discretizeAction);
+
+  optionButton->setMenu(optionMenu);
+  optionButton->setPopupMode(QToolButton::InstantPopup);
+
+  QObject::connect(nanButton, SIGNAL(clicked()), q, SLOT(setNaNColor()));
+
+  QObject::connect(discretizeCheckBox, SIGNAL(toggled(bool)),
+    q, SLOT(setDiscretize(bool)));
+
+  QObject::connect(nbOfDiscreteValuesSpinBox, SIGNAL(valueChanged(int)),
+    q, SLOT(setNumberOfDiscreteValues(int)));
+
+  ///Enable nbOfValuesSpinBox only if we use discretize
+  QObject::connect(discretizeCheckBox, SIGNAL(toggled(bool)),
+    nbOfDiscreteValuesSpinBox, SLOT(setEnabled(bool)));
+}
+
+// ----------------------------------------------------------------------------
+void
+ctkVTKDiscretizableColorTransferWidgetPrivate::colorTransferFunctionModifiedCallback(
+  vtkObject *caller, unsigned long eid, void *clientdata, void *calldata)
+{
+  ctkVTKDiscretizableColorTransferWidgetPrivate* self =
+    reinterpret_cast<ctkVTKDiscretizableColorTransferWidgetPrivate*>(
+      clientdata);
+
+  vtkSmartPointer<vtkDiscretizableColorTransferFunction> dctf =
+    self->scalarsToColorsContextItem->GetDiscretizableColorTransferFunction();
+
+  if (dctf == nullptr)
+  {
+    return;
+  }
+
+  if (self->scalarsToColorsContextItem->IsProcessingColorTransferFunction())
+  {
+    return;
+  }
+
+  if (dctf->GetDiscretize())
+  {
+    dctf->Build();
+  }
+
+  self->discretizeCheckBox->setChecked(dctf->GetDiscretize());
+
+  if (dctf->GetDiscretize())
+  {
+    self->nbOfDiscreteValuesSpinBox->setValue(dctf->GetNumberOfValues());
+  }
+
+  double* newRange = self->scalarsToColorsContextItem->GetCurrentRange();
+  self->rangeSlider->setValues(newRange[0], newRange[1]);
+
+  double r, g, b;
+  self->scalarsToColorsContextItem->GetDiscretizableColorTransferFunction()->
+    GetNanColor(r, g, b);
+  QColor selected = QColor::fromRgbF(r, g, b);
+  self->nanButton->setColor(selected);
+
+  self->scalarsToColorsView->GetInteractor()->Render();
+}
+
+// ----------------------------------------------------------------------------
+ctkVTKDiscretizableColorTransferWidget::ctkVTKDiscretizableColorTransferWidget(
+  QWidget* parent)
+  : QWidget(parent)
+  , d_ptr(new ctkVTKDiscretizableColorTransferWidgetPrivate(*this))
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  d->setupUi(this);
+}
+
+// ----------------------------------------------------------------------------
+ctkVTKDiscretizableColorTransferWidget::~ctkVTKDiscretizableColorTransferWidget()
+{
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setColorTransferFunction(
+  vtkScalarsToColors* ctf)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+
+  vtkScalarsToColors* oldCtf =
+    d->scalarsToColorsContextItem->GetDiscretizableColorTransferFunction();
+  if (oldCtf != nullptr)
+  {
+    oldCtf->RemoveObserver(d->colorTransferFunctionModified);
+  }
+
+  ///Setting the transfer function to the scalarsToColorsContextItem convert
+  /// it to a vtkDiscretizableTransferFunction
+  d->scalarsToColorsContextItem->SetColorTransferFunction(ctf);
+
+  ctf = d->scalarsToColorsContextItem->GetColorTransferFunction();
+  emit(currentScalarsToColorsChanged(ctf));
+
+  if (ctf == nullptr)
+  {
+    d->rangeSlider->setRange(0., 255.);
+    d->rangeSlider->setValues(0., 1.);
+    d->rangeSlider->setEnabled(false);
+    d->previousOpacityValue = 0.0;
+    d->opacitySlider->setValue(d->previousOpacityValue);
+    d->opacitySlider->setEnabled(false);
+    d->optionButton->setEnabled(false);
+    d->resetRangeButton->setEnabled(false);
+    d->centerRangeButton->setEnabled(false);
+    d->invertColorTransferFunctionButton->setEnabled(false);
+    return;
+  }
+
+  // Set sliders values depending on the new color transfer function
+  d->rangeSlider->setEnabled(true);
+  d->opacitySlider->setEnabled(true);
+  d->optionButton->setEnabled(true);
+  d->resetRangeButton->setEnabled(true);
+  d->centerRangeButton->setEnabled(true);
+  d->invertColorTransferFunctionButton->setEnabled(true);
+
+  double* newRange = d->scalarsToColorsContextItem->
+    GetDiscretizableColorTransferFunction()->GetRange();
+
+  d->rangeSlider->setRange(newRange[0], newRange[1]);
+
+  d->previousOpacityValue = 1.0;
+  d->opacitySlider->setValue(d->previousOpacityValue);
+
+  ctf->AddObserver(
+    vtkCommand::ModifiedEvent, d->colorTransferFunctionModified);
+  d->colorTransferFunctionModified->Execute(ctf, vtkCommand::ModifiedEvent,
+    this);
+}
+
+// ----------------------------------------------------------------------------
+vtkScalarsToColors*
+ctkVTKDiscretizableColorTransferWidget::colorTransferFunction() const
+{
+  Q_D(const ctkVTKDiscretizableColorTransferWidget);
+  return d->scalarsToColorsContextItem->GetColorTransferFunction();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setHistogram(
+  vtkImageAccumulate* histogram)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  histogram->Update();
+  d->dataRange[0] = histogram->GetMin()[0];
+  d->dataRange[1] = histogram->GetMax()[0];
+  d->dataMean = histogram->GetMean()[0];
+
+  int* output = static_cast<int*>(histogram->GetOutput()->GetScalarPointer());
+  double spacing = histogram->GetComponentSpacing()[0];
+  double bin = histogram->GetComponentOrigin()[0];
+
+  vtkSmartPointer<vtkDoubleArray> bins =
+    vtkSmartPointer<vtkDoubleArray>::New();
+  bins->SetNumberOfComponents(1);
+  bins->SetNumberOfTuples(255);
+  bins->SetName("image_extents");
+  vtkSmartPointer<vtkIntArray> frequencies =
+    vtkSmartPointer<vtkIntArray>::New();
+  frequencies->SetNumberOfComponents(1);
+  frequencies->SetNumberOfTuples(255);
+  frequencies->SetName("Frequency");
+
+  for (unsigned int j = 0; j < 255; ++j)
+  {
+    bins->SetTuple1(j, bin);
+    bin += spacing;
+    frequencies->SetTuple1(j, *output++);
+  }
+
+  vtkNew<vtkTable> table;
+  table->AddColumn(bins);
+  table->AddColumn(frequencies);
+
+  d->scalarsToColorsContextItem->SetHistogramTable(table.Get(),
+    "image_extents", "Frequency");
+
+  d->scalarsToColorsContextItem->SetDataRange(d->dataRange[0], d->dataRange[1]);
+
+  d->scalarsToColorsView->GetInteractor()->Render();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::onPaletteIndexChanged(
+  vtkScalarsToColors* ctf)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+
+  if (ctf == nullptr)
+  {
+    this->setColorTransferFunction(ctf);
+    return;
+  }
+
+  if (ctf->IsA("vtkDiscretizableColorTransferFunction"))
+  {
+    vtkNew<vtkDiscretizableColorTransferFunction> newCtf;
+    vtkNew<vtkPiecewiseFunction> newPf;
+    newCtf->DeepCopy(vtkDiscretizableColorTransferFunction::SafeDownCast(ctf));
+    newPf->DeepCopy(vtkDiscretizableColorTransferFunction::SafeDownCast(ctf)->GetScalarOpacityFunction());
+    newCtf->SetScalarOpacityFunction(newPf.Get());
+    newCtf->EnableOpacityMappingOn();
+    this->setColorTransferFunction(newCtf.Get());
+  }
+  else if (ctf->IsA("vtkColorTransferFunction"))
+  {
+    vtkNew<vtkColorTransferFunction> newCtf;
+    newCtf->DeepCopy(vtkColorTransferFunction::SafeDownCast(ctf));
+    this->setColorTransferFunction(newCtf.Get());
+  }
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setGlobalOpacity(double value)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  d->scalarsToColorsContextItem->SetGlobalOpacity(
+    value / d->previousOpacityValue);
+  d->previousOpacityValue = value;
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setNaNColor()
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+
+  QColor selected = d->nanButton->color();
+  d->scalarsToColorsContextItem->GetDiscretizableColorTransferFunction()->
+    SetNanColor(selected.redF(), selected.greenF(), selected.blueF());
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setDiscretize(bool checked)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+
+  d->scalarsToColorsContextItem->GetDiscretizableColorTransferFunction()->
+    SetDiscretize(checked);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setNumberOfDiscreteValues(
+  int value)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+
+  d->scalarsToColorsContextItem->GetDiscretizableColorTransferFunction()
+    ->SetNumberOfValues(value);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setColorTransferFunctionRange(
+  double minValue, double maxValue)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+
+  d->scalarsToColorsContextItem->SetCurrentRange(minValue, maxValue);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::onCurrentPointEdit()
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  double rgb[3];
+  if (d->scalarsToColorsContextItem->GetCurrentControlPointColor(rgb))
+  {
+    QColor color = QColorDialog::getColor(
+      QColor::fromRgbF(rgb[0], rgb[1], rgb[2]), this, "Select color at point",
+        QColorDialog::DontUseNativeDialog);
+    if (color.isValid())
+    {
+      rgb[0] = color.redF();
+      rgb[1] = color.greenF();
+      rgb[2] = color.blueF();
+      d->scalarsToColorsContextItem->SetCurrentControlPointColor(rgb);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::resetColorTransferFunctionRange()
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  if (d->dataRange[0] <= d->dataRange[1])
+  {
+    d->scalarsToColorsContextItem->SetCurrentRange(
+      d->dataRange[0], d->dataRange[1]);
+  }
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::centerColorTransferFunctionRange()
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  d->scalarsToColorsContextItem->CenterRange(d->dataMean);
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::invertColorTransferFunction()
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  d->scalarsToColorsContextItem->InvertColorTransferFunction();
+}
+
+// ----------------------------------------------------------------------------
+void ctkVTKDiscretizableColorTransferWidget::setViewBackgroundColor(
+  const QColor& i_color)
+{
+  Q_D(ctkVTKDiscretizableColorTransferWidget);
+  d->scalarsToColorsContextView->GetRenderer()->SetBackground(
+    i_color.redF(), i_color.greenF(), i_color.blueF());
+}
+
+// ----------------------------------------------------------------------------
+QColor ctkVTKDiscretizableColorTransferWidget::viewBackgroundColor() const
+{
+  Q_D(const ctkVTKDiscretizableColorTransferWidget);
+  double rgb[3];
+  d->scalarsToColorsContextView->GetRenderer()->GetBackground(rgb);
+  return QColor::fromRgbF(rgb[0], rgb[1], rgb[2]);
+}
+
+// ----------------------------------------------------------------------------
+ctkVTKScalarsToColorsComboBox*
+ctkVTKDiscretizableColorTransferWidget::scalarsToColorsSelector() const
+{
+  Q_D(const ctkVTKDiscretizableColorTransferWidget);
+  return d->scalarsToColorsSelector;
+}

+ 90 - 0
Libs/Visualization/VTK/Widgets/ctkVTKDiscretizableColorTransferWidget.h

@@ -0,0 +1,90 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __ctkVTKDiscretizableColorTransferWidget_h
+#define __ctkVTKDiscretizableColorTransferWidget_h
+
+// CTK includes
+#include "ctkVisualizationVTKWidgetsExport.h"
+class ctkVTKDiscretizableColorTransferWidgetPrivate;
+class ctkVTKScalarsToColorsComboBox;
+
+// VTK includes
+#include <vtkSmartPointer.h>
+class QVTKWidget;
+class vtkImageAccumulate;
+class vtkPiecewiseFunction;
+class vtkScalarsToColors;
+
+// Qt includes
+#include <QWidget>
+class QCheckBox;
+class QLineEdit;
+class QSpinBox;
+class QToolButton;
+
+class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKDiscretizableColorTransferWidget: public QWidget
+{
+  Q_OBJECT
+  /// This property controls the color of the view.
+  /// Dark gray by default.
+  /// \accessors viewBackgroundColor() setViewBackgroundColor()
+  Q_PROPERTY(QColor viewBackgroundColor READ viewBackgroundColor WRITE setViewBackgroundColor)
+public:
+  explicit ctkVTKDiscretizableColorTransferWidget(QWidget* parent_ = nullptr);
+  virtual ~ctkVTKDiscretizableColorTransferWidget();
+
+  void setColorTransferFunction(vtkScalarsToColors* ctf);
+  vtkScalarsToColors* colorTransferFunction() const;
+
+  void setHistogram(vtkImageAccumulate* hist);
+
+  void setViewBackgroundColor(const QColor& i_color);
+  QColor viewBackgroundColor() const;
+
+  ctkVTKScalarsToColorsComboBox* scalarsToColorsSelector() const;
+
+signals:
+  void currentScalarsToColorsModified();
+  void currentScalarsToColorsChanged(vtkScalarsToColors* ctf);
+
+public slots:
+  void onCurrentPointEdit();
+  void onPaletteIndexChanged(vtkScalarsToColors* ctf);
+
+  void setGlobalOpacity(double opacity);
+
+  void resetColorTransferFunctionRange();
+  void centerColorTransferFunctionRange();
+  void invertColorTransferFunction();
+
+  void setNaNColor();
+  void setDiscretize(bool checked);
+  void setNumberOfDiscreteValues(int value);
+  void setColorTransferFunctionRange(double minValue, double maxValue);
+
+protected:
+  QScopedPointer<ctkVTKDiscretizableColorTransferWidgetPrivate> d_ptr;
+
+private:
+  Q_DECLARE_PRIVATE(ctkVTKDiscretizableColorTransferWidget);
+  Q_DISABLE_COPY(ctkVTKDiscretizableColorTransferWidget);
+};
+#endif // __ctkVTKDiscretizableColorTransferWidget_h

+ 175 - 0
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsComboBox.cpp

@@ -0,0 +1,175 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 <QPainter>
+
+// CTK includes
+#include "ctkVTKScalarsToColorsComboBox.h"
+#include "ctkVTKWidgetsUtils.h"
+
+// VTK includes
+#include <vtkScalarsToColors.h>
+
+//-----------------------------------------------------------------------------
+class ctkVTKScalarsToColorsComboBoxPrivate
+{
+  Q_DECLARE_PUBLIC(ctkVTKScalarsToColorsComboBox);
+protected:
+  ctkVTKScalarsToColorsComboBox* const q_ptr;
+public:
+  ctkVTKScalarsToColorsComboBoxPrivate(ctkVTKScalarsToColorsComboBox& object);
+  void init();
+
+};
+
+// --------------------------------------------------------------------------
+// ctkVTKScalarsToColorsComboBoxPrivate methods
+
+// --------------------------------------------------------------------------
+ctkVTKScalarsToColorsComboBoxPrivate::ctkVTKScalarsToColorsComboBoxPrivate(
+  ctkVTKScalarsToColorsComboBox& object)
+  : q_ptr(&object)
+{
+}
+
+// --------------------------------------------------------------------------
+void ctkVTKScalarsToColorsComboBoxPrivate::init()
+{
+  Q_Q(ctkVTKScalarsToColorsComboBox);
+
+  QObject::connect(q->model(),
+    SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
+    q, SLOT(onRowsAboutToBeRemoved(const QModelIndex&, int, int)));
+
+  q->setIconSize(QSize(100, 20));
+
+  // Add default raw
+  q->setDefaultText(q->tr("Select a color transfer function..."));
+  q->forceDefault(true);
+
+  // Connect signals and slots
+  QObject::connect(q, SIGNAL(currentIndexChanged(int)),
+    q, SLOT(onCurrentIndexChanged(int)));
+}
+
+// --------------------------------------------------------------------------
+// ctkVTKScalarsToColorsComboBox methods
+
+// --------------------------------------------------------------------------
+ctkVTKScalarsToColorsComboBox::ctkVTKScalarsToColorsComboBox(QWidget* _parent)
+  : Superclass(_parent)
+  , d_ptr(new ctkVTKScalarsToColorsComboBoxPrivate(*this))
+{
+  Q_D(ctkVTKScalarsToColorsComboBox);
+  d->init();
+}
+
+// --------------------------------------------------------------------------
+ctkVTKScalarsToColorsComboBox::~ctkVTKScalarsToColorsComboBox()
+{
+}
+
+// --------------------------------------------------------------------------
+int ctkVTKScalarsToColorsComboBox::addScalarsToColors(
+  vtkScalarsToColors* scFunction, const QString& name)
+{
+  QImage img;
+  if (scFunction != nullptr)
+  {
+    scFunction->Register(nullptr);
+    img = ctk::scalarsToColorsImage(scFunction, this->iconSize());
+  }
+  else
+  {
+    img = QImage(this->iconSize(), QImage::Format::Format_ARGB32);
+    img.fill(Qt::transparent);
+  }
+
+  this->addItem(QPixmap::fromImage(img), name,
+    QVariant::fromValue<void*>(scFunction));
+  return count() - 1;
+}
+
+// --------------------------------------------------------------------------
+vtkScalarsToColors* ctkVTKScalarsToColorsComboBox::getScalarsToColors(
+  int index) const
+{
+  QVariant data = itemData(index);
+  if (!data.isValid())
+  {
+    return nullptr;
+  }
+
+  vtkScalarsToColors* ctf =
+    reinterpret_cast<vtkScalarsToColors*>(data.value<void*>());
+
+  return ctf;
+}
+
+// --------------------------------------------------------------------------
+int ctkVTKScalarsToColorsComboBox::findScalarsToColors(
+  vtkScalarsToColors* scFunction) const
+{
+  return findData(QVariant::fromValue<void*>(scFunction));
+}
+
+// --------------------------------------------------------------------------
+void ctkVTKScalarsToColorsComboBox::removeScalarsToColors(
+  vtkScalarsToColors* scFunction)
+{
+  QComboBox::removeItem(findScalarsToColors(scFunction));
+}
+
+// --------------------------------------------------------------------------
+vtkScalarsToColors*
+ctkVTKScalarsToColorsComboBox::currentScalarsToColors() const
+{
+  return getScalarsToColors(currentIndex());
+}
+
+// --------------------------------------------------------------------------
+void ctkVTKScalarsToColorsComboBox::setCurrentScalarsToColors(
+  vtkScalarsToColors* scFunction)
+{
+  setCurrentIndex(findScalarsToColors(scFunction));
+}
+
+// --------------------------------------------------------------------------
+void ctkVTKScalarsToColorsComboBox::onCurrentIndexChanged(int index)
+{
+  Q_D(ctkVTKScalarsToColorsComboBox);
+  emit currentScalarsToColorsChanged(getScalarsToColors(index));
+}
+
+// --------------------------------------------------------------------------
+void ctkVTKScalarsToColorsComboBox::onRowsAboutToBeRemoved(
+  const QModelIndex& parent, int first, int last)
+{
+  for (int i = first; i <= last; ++i)
+  {
+    vtkScalarsToColors* scFunction = reinterpret_cast<vtkScalarsToColors*>(
+      model()->data(model()->index(i, 0, parent)).value<void*>());
+    if (scFunction != nullptr)
+    {
+      scFunction->Delete();
+    }
+  }
+}

+ 92 - 0
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsComboBox.h

@@ -0,0 +1,92 @@
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 __ctkVTKScalarsToColorsComboBox_h
+#define __ctkVTKScalarsToColorsComboBox_h
+
+// CTK includes
+#include "ctkComboBox.h"
+#include "ctkVisualizationVTKWidgetsExport.h"
+
+// VTK includes
+#include <vtkSmartPointer.h>
+
+class ctkVTKScalarsToColorsComboBoxPrivate;
+class vtkScalarsToColors;
+
+/// \ingroup Visualization_VTK_Widgets
+///
+/// QComboBox linked to vtkScalarsToColors objects
+class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKScalarsToColorsComboBox
+  : public ctkComboBox
+{
+  Q_OBJECT
+  /// Superclass typedef
+  typedef ctkComboBox Superclass;
+
+  /// This property controls the current scalarsToColors item of the combobox.
+  /// \accessors currentScalarsToColors(), setCurrentScalarsToColors()
+  Q_PROPERTY(vtkScalarsToColors* currentScalarsToColors
+    READ currentScalarsToColors WRITE setCurrentScalarsToColors
+    NOTIFY currentScalarsToColorsChanged);
+public:
+
+  /// Constructors
+  explicit ctkVTKScalarsToColorsComboBox(QWidget* parent = 0);
+  virtual ~ctkVTKScalarsToColorsComboBox();
+
+  /// Add scalars to colors function (of any type) to the combobox.
+  /// Increment reference count of given function (if any)
+  /// Returns the index of the added function.
+  int addScalarsToColors(vtkScalarsToColors* function, const QString& text =
+    QString());
+  vtkScalarsToColors* getScalarsToColors(int index) const;
+
+  /// Searches the combobox for the given scalarsToColors
+  /// \sa findText()
+  int findScalarsToColors(vtkScalarsToColors* scalarsToColors) const;
+
+  void removeScalarsToColors(vtkScalarsToColors* scalarsToColors);
+
+  /// Returns the currentScalarsToColors property value
+  /// 0 if no item is selected
+  vtkScalarsToColors* currentScalarsToColors() const;
+
+public slots:
+  ///
+  void setCurrentScalarsToColors(vtkScalarsToColors* scalarsToColors);
+
+signals:
+  /// Signal triggered when the current scalars to colors function changes.
+  void currentScalarsToColorsChanged(vtkScalarsToColors*);
+
+protected slots:
+  void onCurrentIndexChanged(int);
+  void onRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last);
+
+protected:
+  QScopedPointer<ctkVTKScalarsToColorsComboBoxPrivate> d_ptr;
+
+private:
+  Q_DECLARE_PRIVATE(ctkVTKScalarsToColorsComboBox);
+  Q_DISABLE_COPY(ctkVTKScalarsToColorsComboBox);
+};
+
+#endif

+ 0 - 81
Libs/Visualization/VTK/Widgets/ctkVTKScalarsToColorsUtils.cpp

@@ -1,81 +0,0 @@
-/*=========================================================================
-
-  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.apache.org/licenses/LICENSE-2.0.txt
-
-  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 <QBuffer>
-#include <QImage>
-#include <QStyle>
-
-// CTK includes
-#include "ctkLogger.h"
-#include "ctkVTKScalarsToColorsUtils.h"
-
-// VTK includes
-#include <vtkScalarsToColors.h>
-
-//----------------------------------------------------------------------------
-static ctkLogger logger("org.commontk.visualization.vtk.widgets.ctkVTKScalarsToColorsUtils");
-//----------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------
-QImage ctk::scalarsToColorsImage(vtkScalarsToColors* scalarsToColors, const QSize& size)
-{
-  if (!scalarsToColors ||
-      scalarsToColors->GetNumberOfAvailableColors() <= 0)
-    {
-    return QImage();
-    }
-  int width = size.width();
-  int height = size.height();
-  if (size.isEmpty())
-    {
-    width = height = qApp->style()->pixelMetric(QStyle::PM_LargeIconSize);
-    }
-  
-  double* values = new double[width];
-  const double* range = scalarsToColors->GetRange();
-  for (int i = 0; i < width; ++i)
-    {
-    values[i] = range[0] + i * (range[1] - range[0]) / (width - 1);
-    }
-
-  QImage transferFunctionImage(width, height, QImage::Format_RGB32);
-  unsigned char* colors = transferFunctionImage.bits();
-  // Map the first line
-  scalarsToColors->MapScalarsThroughTable2(
-    values, colors, VTK_DOUBLE, width, 1, VTK_RGBA);
-  delete [] values;
-  // Pixels are not correctly ordered, reorder them correctly
-  unsigned char* colorsPtr = colors;
-  QRgb* rgbPtr = reinterpret_cast<QRgb*>(colors);
-  for (int i = 0; i < width; ++i)
-    {
-    *(rgbPtr++) = QColor(colorsPtr[0], colorsPtr[1], colorsPtr[2]).rgb();
-    colorsPtr += 4;
-    }
-  // Fill the other lines
-  for (int i = 1; i < height; ++i)
-    {
-    memcpy(colors + i*VTK_RGBA*width, colors, VTK_RGBA*width);
-    }
-
-  return transferFunctionImage;
-}

+ 50 - 0
Libs/Visualization/VTK/Widgets/ctkVTKWidgetsUtils.cpp

@@ -19,8 +19,10 @@
 =========================================================================*/
 
 // Qt includes
+#include <QApplication>
 #include <QImage>
 #include <QPainter>
+#include <QStyle>
 #include <QWidget>
 
 // ctkWidgets includes
@@ -34,6 +36,8 @@
 #include <QVTKWidget.h>
 #endif
 #include <vtkImageData.h>
+#include <vtkPiecewiseFunction.h>
+#include <vtkScalarsToColors.h>
 #include <vtkVersion.h>
 
 //----------------------------------------------------------------------------
@@ -109,3 +113,49 @@ QImage ctk::vtkImageDataToQImage(vtkImageData* imageData)
     }
   return image;
 }
+
+//----------------------------------------------------------------------------
+QImage ctk::scalarsToColorsImage(vtkScalarsToColors* scalarsToColors,
+  const QSize& size)
+{
+  if (!scalarsToColors ||
+    scalarsToColors->GetNumberOfAvailableColors() <= 0)
+  {
+    return QImage();
+  }
+  int width = size.width();
+  int height = size.height();
+  if (size.isEmpty())
+  {
+    width = height = qApp->style()->pixelMetric(QStyle::PM_LargeIconSize);
+  }
+
+  double* values = new double[width];
+  const double* range = scalarsToColors->GetRange();
+  for (int i = 0; i < width; ++i)
+  {
+    values[i] = range[0] + i * (range[1] - range[0]) / (width - 1);
+  }
+
+  QImage transferFunctionImage(width, height, QImage::Format_RGB32);
+  unsigned char* colors = transferFunctionImage.bits();
+  // Map the first line
+  scalarsToColors->MapScalarsThroughTable2(
+    values, colors, VTK_DOUBLE, width, 1, VTK_RGBA);
+  delete[] values;
+  // Pixels are not correctly ordered, reorder them correctly
+  unsigned char* colorsPtr = colors;
+  QRgb* rgbPtr = reinterpret_cast<QRgb*>(colors);
+  for (int i = 0; i < width; ++i)
+  {
+    *(rgbPtr++) = QColor(colorsPtr[0], colorsPtr[1], colorsPtr[2]).rgb();
+    colorsPtr += 4;
+  }
+  // Fill the other lines
+  for (int i = 1; i < height; ++i)
+  {
+    memcpy(colors + i*VTK_RGBA*width, colors, VTK_RGBA*width);
+  }
+
+  return transferFunctionImage;
+}

+ 8 - 0
Libs/Visualization/VTK/Widgets/ctkVTKWidgetsUtils.h

@@ -31,6 +31,7 @@ class QWidget;
 
 // VTK includes
 class vtkImageData;
+class vtkScalarsToColors;
 
 namespace ctk {
 
@@ -46,6 +47,13 @@ QImage CTK_VISUALIZATION_VTK_WIDGETS_EXPORT grabVTKWidget(QWidget* widget, QRect
 /// Convert a vtkImageData into a QImage
 QImage CTK_VISUALIZATION_VTK_WIDGETS_EXPORT vtkImageDataToQImage(vtkImageData* imageData);
 
+///
+/// \ingroup Visualization_VTK_Widgets
+/// Convert a vtkScalarsToColors into a QImage
+/// If size is empty, it will use the large icon size of the application style
+QImage CTK_VISUALIZATION_VTK_WIDGETS_EXPORT scalarsToColorsImage(
+  vtkScalarsToColors* scalarsToColors, const QSize& size = QSize());
+
 }
 
 #endif