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

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 година
родитељ
комит
328a070a5e
32 измењених фајлова са 3055 додато и 99 уклоњено
  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