/*=========================================================================

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkKWImageWidget.h"

#include "vtkActor.h"
#include "vtkCallbackCommand.h"
#include "vtkCamera.h"
#include "vtkColorTransferFunction.h"
#include "vtkColorTransferFunction.h"
#include "vtkCornerAnnotation.h"
#include "vtkCutter.h"
#include "vtkImageActor.h"
#include "vtkImageData.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPlane.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkScalarBarActor.h"
#include "vtkSplineSurface2DWidget.h"
#include "vtkSplineSurfaceWidget.h"
#include "vtkVolumeProperty.h"

#include "vtkKW2DSplineSurfacesWidget.h"
#include "vtkKW3DMarkersWidget.h"
#include "vtkKW3DSplineCurvesWidget.h"
#include "vtkKW3DSplineSurfacesWidget.h"
#include "vtkKWCroppingRegionsWidget.h"
#include "vtkKWCursorWidget.h"
#include "vtkKWEvent.h"
#include "vtkKWEventMap.h"
#include "vtkKWGenericRenderWindowInteractor.h"
#include "vtkKWIcon.h"
#include "vtkKWImageMapToWindowLevelColors.h"
#include "vtkKWImageMapToWindowLevelColors.h"
#include "vtkKWInteractorStyleImageView.h"
#include "vtkKWInternationalization.h"
#include "vtkKWMenu.h"
#include "vtkKWScalarBarWidget.h"
#include "vtkKWScaleBarWidget.h"
#include "vtkKWScaleWithEntry.h"
#include "vtkKWWindow.h"

#include <vtksys/stl/string>

vtkStandardNewMacro(vtkKWImageWidget);
vtkCxxRevisionMacro(vtkKWImageWidget, "$Revision: 1.154 $");

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLKWImageWidgetReader.h"
#include "XML/vtkXMLKWImageWidgetWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkKWImageWidget, vtkXMLKWImageWidgetReader, vtkXMLKWImageWidgetWriter);

//----------------------------------------------------------------------------
vtkKWImageWidget::vtkKWImageWidget()
{
  this->Image = vtkImageActor::New();
  this->InteractorStyle = vtkKWInteractorStyleImageView::New();
  
  this->InteractorStyle->SetEventMap(this->EventMap);
  vtkRenderWindowInteractor *interactor = this->GetRenderWindowInteractor();
  if (interactor)
    {
    interactor->SetInteractorStyle(this->InteractorStyle);
    //  interactor->SetPriority(1.0);
    }
  
  this->Cursor3DType = vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR;
  this->Cursor3DWidget = vtkKWCursorWidget::New();
  this->Cursor3DWidget->SetInteractor(interactor);
  
  this->CroppingWidget = vtkKWCroppingRegionsWidget::New();
  this->CroppingWidget->SetInteractor(interactor);
  
  this->ScaleBarWidget = vtkKWScaleBarWidget::New();
  this->ScaleBarWidget->SetInteractor(interactor);
  this->ScaleBarWidget->SetParent(this);
  this->ScaleBarWidget->RepositionableOff();
  this->SupportScaleBar = 1;
  
  vtkScalarBarActor *scalarBar = vtkScalarBarActor::New();
  this->ScalarBarWidget = vtkKWScalarBarWidget::New();
  this->ScalarBarWidget->SetScalarBarActor(scalarBar);
  //scalarBar->SetLookupTable(this->GetTransferFunction(0));
  scalarBar->SetLabelFormat("%.5g");
  scalarBar->Delete();
  this->ScalarBarWidget->SetInteractor(interactor);
  scalarBar->GetPositionCoordinate()->SetValue(0.05,0.2);
  scalarBar->GetPosition2Coordinate()->SetValue(0.15,0.6);
  scalarBar->SetOrientation(1);
  this->SupportScalarBar = 1;

  this->SplineSurfaces = vtkKW2DSplineSurfacesWidget::New();
  this->SplineSurfaces->SetInteractor(interactor);
  this->SplineSurfaces->SetParent(this);
  
}

//----------------------------------------------------------------------------
vtkKWImageWidget::~vtkKWImageWidget()
{
  if (this->Image)
    {
    this->Image->Delete();
    this->Image = NULL;
    }

  if (this->InteractorStyle)
    {
    this->InteractorStyle->Delete();
    this->InteractorStyle = NULL;
    }
  
  if (this->Cursor3DWidget)
    {
    this->Cursor3DWidget->SetInteractor(NULL);
    this->Cursor3DWidget->Delete();
    this->Cursor3DWidget = NULL;
    }
  
  if (this->CroppingWidget)
    {
    this->CroppingWidget->SetInteractor(NULL);
    this->CroppingWidget->Delete();
    this->CroppingWidget = NULL;
    }

  if (this->ScalarBarWidget)
    {
    this->ScalarBarWidget->Delete();
    this->ScalarBarWidget = NULL;
    }

  if (this->ScaleBarWidget)
    {
    this->ScaleBarWidget->SetInteractor(NULL);
    this->ScaleBarWidget->Delete();
    this->ScaleBarWidget = NULL;
    }

  if( this->SplineSurfaces )
    {
    this->SplineSurfaces->SetInteractor(NULL);
    this->SplineSurfaces->Delete();
    this->SplineSurfaces = NULL;
    }
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::ConnectInternalPipeline()
{
  // Have a look at the documentation for this method (see .h).

  if (!this->Superclass::ConnectInternalPipeline())
    {
    return 0;
    }

  // Image actor

  if (this->Image)
    {
    vtkKWImageMapToWindowLevelColors *map = this->GetImageMapToRGBA();
    if (map && map->GetInput())
      {
      this->Image->SetInput(map->GetOutput());
      }
    else
      {
      this->Image->SetInput(NULL);
      }
    this->Image->Modified();
    }

  if (this->InteractorStyle)
    {
    vtkKWImageMapToWindowLevelColors *map = this->GetImageMapToRGBA();
    if (map)
      {
      this->InteractorStyle->SetImageMapToRGBA(map);
      }
    }

  // Force the cropping widget to update itself according to its input
  // That will reset the pipeline, bounds, flags, etc.

  if (this->CroppingWidget)
    {
    this->CroppingWidget->UpdateAccordingToInput();
    this->CroppingWidget->Modified();
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::InputScalarStructureHasChanged()
{
  // Have a look at the documentation for this method (see .h).

  if (!this->Superclass::InputScalarStructureHasChanged())
    {
    return 0;
    }

  // If we have more than 2 dependent components, do not display any 
  // scalar bar (would make no sense)
  
  int nb_components = 
    this->Input ? this->Input->GetNumberOfScalarComponents() : 0;

  if (!this->GetIndependentComponents() && nb_components > 2)
    {
    this->SetScalarBarVisibility(0);
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::InputBoundsHaveChanged()
{
  // Have a look at the documentation for this method (see .h).

  if (!this->Superclass::InputBoundsHaveChanged())
    {
    return 0;
    }

  // Force the cropping widget to update itself according to its input
  // That will recompute the bounds

  if (this->CroppingWidget)
    {
    this->CroppingWidget->UpdateAccordingToInput();
    this->CroppingWidget->Modified();
    }

  // Place the 3D widgets
  // At this point we now the display extent is OK (UpdateDisplayExtent() has
  // been called by the superclass)

  double bounds[6];

  this->Image->GetBounds(bounds);

  this->SplineSurfaces->PlaceWidget(bounds);

  // Reset the cursor 3D

  this->Cursor3DWidget->PlaceWidget(bounds);
  this->Cursor3DWidget->SetPosition(
    ((double)bounds[0] + (double)bounds[1]) * 0.5,
    ((double)bounds[2] + (double)bounds[3]) * 0.5,
    ((double)bounds[4] + (double)bounds[5]) * 0.5);

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::InputHasChanged(int mask)
{
  // Have a look at the documentation for this method (see .h).

  if (!this->Superclass::InputHasChanged(mask))
    {
    return 0;
    }

  if (this->ScalarBarWidget)
    {
    if (this->Input)
      {
      vtkKWImageMapToWindowLevelColors *map = this->GetImageMapToRGBA();
      if (map)
        {
        this->ScalarBarWidget->GetScalarBarActor()->SetLookupTable(
          map->GetLookupTable(this->GetScalarBarComponent()));
        }
      }
    else
      {
      this->ScalarBarWidget->GetScalarBarActor()->SetLookupTable(NULL);
      }
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::UpdateDisplayExtent()
{
  if (!this->Input || !this->Image->GetInput())
    {
    return;
    }

  // Go to the default slice if we are just out of the range
  // - GoToDefaultSlice() will call UpdateDisplayExtent()

  if (this->HasSliceControl && !this->IsSliceInRange(this->GetSlice()))
    {
    this->UpdateSliceScale();
    this->GoToDefaultSlice();
    return;
    }

  // Note the renderer won't add it twice it is already there

  vtkRenderer *ren = this->GetRenderer();

  ren->AddViewProp(this->Image);
  
  int display_extent[6];
  this->GetSliceDisplayExtent(this->GetSlice(), display_extent);
  this->Image->SetDisplayExtent(display_extent);

  double bounds[6];
  this->Image->GetBounds(bounds);
  
  // Adjust the 3D widgets

  this->Cursor3DWidget->PlaceWidget(bounds);
  this->Cursor3DWidget->SetSliceOrientation(this->SliceOrientation);

  // Figure out the correct clipping range?
  // first get it in world coords
/***
  double spos = (double)bounds[this->SliceOrientation * 2];
  double cpos = (double)
    ren->GetActiveCamera()->GetPosition()[this->SliceOrientation];
  double range = fabs(spos - cpos);
  double *spacing = this->Image->GetInput()->GetSpacing();
  double avgSpacing = 
    ((double)spacing[0] + (double)spacing[1] + (double)spacing[2]) / 3.0;
  ren->GetActiveCamera()->SetClippingRange(
    range - avgSpacing * 3.0, range + avgSpacing * 3.0);
***/
  this->UpdateImageMap();

  // Invoke an event after we change the update extent but before we 
  // invoke Render(). This should be an opportunity for you to update
  // any additional props such as contours etc, so that they get rendered
  // later on here. We do this to avoid additional renders.
  this->InvokeEvent(vtkKW2DRenderWidget::UpdateDisplayExtentEvent, NULL);
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::UpdateImageMap()
{
  vtkKWImageMapToWindowLevelColors *map = this->GetImageMapToRGBA();
  if (map && map->GetInput() && map->GetOutput())
    {
    vtkImageData *output = map->GetOutput();
    output->UpdateInformation();
    int *display_extent = this->Image->GetDisplayExtent();
    if (vtkMath::ExtentIsWithinOtherExtent(
          display_extent, output->GetWholeExtent()))
      {
      output->SetUpdateExtent(display_extent);
      output->PropagateUpdateExtent();
      }
    }

  this->Superclass::UpdateImageMap();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::UpdateAccordingToUnits()
{
  this->ScaleBarWidget->SetDistanceUnits(this->DistanceUnits);
} 

//----------------------------------------------------------------------------
void vtkKWImageWidget::UpdateSliceOrientationAndType()
{
  this->Superclass::UpdateSliceOrientationAndType();

  this->Cursor3DWidget->SetSliceOrientation(this->SliceOrientation);

  this->CroppingWidget->SetSliceOrientation(this->SliceOrientation);

  this->UpdateImplicitPlaneSplineSurfaces();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSlice(int slice)
{
  if (!this->Image || !this->Image->GetInput())
    {
    return;
    }

  this->Image->GetInput()->UpdateInformation();
  int *w_ext = this->Image->GetInput()->GetWholeExtent();
  int min_slice = w_ext[this->SliceOrientation * 2];
  int max_slice = w_ext[this->SliceOrientation * 2 + 1];
  if (min_slice > max_slice)
    {
    int temp = min_slice;
    min_slice = max_slice;
    max_slice = temp;
    }

  if (slice < min_slice)
    {
    slice = min_slice;
    }
  else if (slice > max_slice)
    {
    slice = max_slice;
    }

  // Just set the value of the slider, don't invoke anything
  // UPDATE: actually no, we want to be called back

  int disabled = this->SliceScale->GetDisableCommands();
  //this->SliceScale->DisableCommandsOn();
  this->SliceScale->SetValue(slice);
  this->SliceScale->SetDisableCommands(disabled);

  // Update cursor
  // To be performed *before* UpdateDisplayExtent
  // TODO: still buggy...
#if 0
  double cursor_pos[3];
  this->GetCursor3DPosition(cursor_pos);
  double *origin = this->Image->GetInput()->GetOrigin();
  double *spacing = this->Image->GetInput()->GetSpacing();
  cursor_pos[this->SliceOrientation] =
    (double)slice * spacing[this->SliceOrientation] + 
    origin[this->SliceOrientation];
  this->SetCursor3DPosition(cursor_pos[0], cursor_pos[1], cursor_pos[2]);
#endif

  this->UpdateDisplayExtent();

  this->CroppingWidget->SetSlice(slice);

  this->UpdateImplicitPlaneSplineSurfaces();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::UpdateImplicitPlaneSplineSurfaces()
{
  // Update the implicit plane for the spline surface intersection
  //
  if (!this->Image || !this->Image->GetInput())
    {
    return;
    }
  double *origin  = this->Image->GetInput()->GetOrigin();
  double *spacing = this->Image->GetInput()->GetSpacing();

  double planeorigin[3];
  planeorigin[0] = 0.0;
  planeorigin[1] = 0.0;
  planeorigin[2] = 0.0;

  int slice = this->GetSlice();

  planeorigin[this->SliceOrientation] = (double)origin[ this->SliceOrientation] 
                               + slice *(double)spacing[this->SliceOrientation];  

  this->SplineSurfaces->SetOrigin(planeorigin);

  double normal[3];
  normal[0] = 0.0;
  normal[1] = 0.0;
  normal[2] = 0.0;
  normal[this->SliceOrientation] = 1.0;
  this->SplineSurfaces->SetNormal(normal); 

}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SliceSelectedCallback(double value)
{
  double old_cursor_pos[3];
  this->GetCursor3DPosition(old_cursor_pos);
  
  this->Superclass::SliceSelectedCallback(value);

  int args[2];
  args[0] = this->GetSlice();
  args[1] = this->InteractorStyle->GetEventIdentifier();
  this->InvokeEvent(vtkKWEvent::ImageSliceChangedEvent, args);

  // Changing the slice can also change the cursor position
  // Trigger an event if that's the case
#if 0
  double cursor_pos[3];
  this->GetCursor3DPosition(cursor_pos);
  if (cursor_pos[0] != old_cursor_pos[0] ||
      cursor_pos[1] != old_cursor_pos[1] ||
      cursor_pos[2] != old_cursor_pos[2])
    {
    float fargs[3];
    fargs[0] = cursor_pos[0];
    fargs[1] = cursor_pos[1];
    fargs[2] = cursor_pos[2];
    this->InvokeEvent(vtkKWEvent::Cursor3DPositionChangedEvent, fargs);
    }
#endif
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::IncrementPage()
{
  this->SetSlice(this->GetSlice() + 10);
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::DecrementPage()
{
  this->SetSlice(this->GetSlice() - 10);
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::ComputeWorldCoordinate(
  int x, int y, double *result, int *id)
{
  // Convert 0,0,0 into display coordinates to get the depth

  double *bnds = this->Image->GetBounds();
  vtkRenderer *ren = this->GetRenderer();
  ren->SetWorldPoint(bnds[0], bnds[2], bnds[4], 1.0);
  ren->WorldToDisplay();
  double *DPoint = ren->GetDisplayPoint();
  double focalDepth = DPoint[2];
  
  // Convert the x,y probe location to world coordinates using the
  // computed depth

  ren->SetDisplayPoint(x, y, focalDepth);
  ren->DisplayToWorld();
  double *RPoint = ren->GetWorldPoint();
  if (RPoint[3] != 0.0)
    {
    RPoint[0] = (double)((double)RPoint[0] / (double)RPoint[3]);
    RPoint[1] = (double)((double)RPoint[1] / (double)RPoint[3]);
    RPoint[2] = (double)((double)RPoint[2] / (double)RPoint[3]);
    }
  
  int idx1 = (this->SliceOrientation + 1) % 3;
  int idx2 = (this->SliceOrientation + 2) % 3;
  
  // Do a quick check to make sure we are in the image

  if (RPoint[idx1] < bnds[idx1 * 2] || 
      RPoint[idx1] > bnds[idx1 * 2 + 1] ||
      RPoint[idx2] < bnds[idx2 * 2] || 
      RPoint[idx2] > bnds[idx2 * 2 + 1])
    {
    return 0;
    }

  if (result)
    {
    result[0] = RPoint[0];
    result[1] = RPoint[1];
    result[2] = RPoint[2];
    }
  if (id)
    {
    *id = this->GetRendererIndex(ren);
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::Render()
{
  if (this->CollapsingRenders)
    {
    this->CollapsingRendersCount++;
    return;
    }

  if (!this->RenderState)
    {
    return;
    }

  static int static_in_render = 0;
  if (static_in_render)
    {
    return;
    }
  static_in_render = 1;

  if (this->RenderMode != vtkKWRenderWidget::DisabledRender &&
      this->VTKWidget->IsCreated())
    {
    this->RenderWindow->Render();
    }
  
  static_in_render = 0;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DVisibility(int state)
{
  if (this->GetCursor3DVisibility() == state)
    {
    return;
    }

  this->Cursor3DWidget->SetEnabled(state);
  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetCursor3DVisibility()
{
  return this->Cursor3DWidget->GetEnabled();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetInterpolate(int state)
{
  if (this->GetInterpolate() != state)
    {
    this->Image->SetInterpolate(state);
    this->Render();
    this->InvokeEvent(vtkKWEvent::ImageInterpolateEvent, &state);
    }
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetInterpolate()
{
  return this->Image->GetInterpolate();
}

//---------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DPosition(double x, double y, double z)
{
  double pos[3];
  this->GetCursor3DPosition(pos);

  if (!pos || (pos[0] == x && pos[1] == y && pos[2] == z))
    {
    return;
    }

  // Make sure we have the required params

  if (!this->Cursor3DWidget)
    {
    return;
    }
  
  this->Cursor3DWidget->SetPosition(x, y, z);

  if (!this->Input)
    {
    if (this->GetCursor3DVisibility())
      {
      this->Render();
      }
    return;
    }

  double *bounds = this->Input->GetBounds();

  if (x < bounds[0])
    {
    x = bounds[0];
    }
  else if (x > bounds[1])
    {
    x = bounds[1];
    }
  if (y < bounds[2])
    {
    y = bounds[2];
    }
  else if (y > bounds[3])
    {
    y = bounds[3];
    }
  if (z < bounds[4])
    {
    z = bounds[4];
    }
  else if (z > bounds[5])
    {
    z = bounds[5];
    }
 
  int slice = 0;

  double *origin = this->Image->GetInput()->GetOrigin();
  double *spacing = this->Image->GetInput()->GetSpacing();

  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_YZ:
      slice = (int)(((double)x - (double)origin[this->SliceOrientation]) / 
                    (double)spacing[this->SliceOrientation] + 0.5);  
      break;

    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XZ:
      slice = (int)(((double)y - (double)origin[this->SliceOrientation]) / 
                    (double)spacing[this->SliceOrientation] + 0.5);  
      break;

    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XY:
      slice = (int)(((double)z - (double)origin[this->SliceOrientation]) / 
                    (double)spacing[this->SliceOrientation] + 0.5);  
      break;
    }
  
  if (slice != this->GetSlice())
    {
    this->SetSlice(slice);
    }
  else
    {
    if (this->GetCursor3DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
double* vtkKWImageWidget::GetCursor3DPosition()
{
  return this->Cursor3DWidget->GetPosition();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::GetCursor3DPosition(double pos[3])
{
  this->Cursor3DWidget->GetPosition(pos);
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DXColor(double r, double g, double b)
{
  double *color = this->GetCursor3DXColor();
  if (!color || (color[0] == r && color[1] == g && color[2] == b))
    {
    return;
    }

  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XY:
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XZ:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        this->Cursor3DWidget->SetAxis2Color(r, g, b);
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        this->Cursor3DWidget->SetAxis1Color(r, g, b);
        }
      if (this->GetCursor3DVisibility())
        {
        this->Render();
        }
      break;
    }
}

//----------------------------------------------------------------------------
double* vtkKWImageWidget::GetCursor3DXColor()
{
  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XY:
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XZ:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        return this->Cursor3DWidget->GetAxis2Color();
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        return this->Cursor3DWidget->GetAxis1Color();
        }
      break;
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DYColor(double r, double g, double b)
{
  double *color = this->GetCursor3DYColor();
  if (!color || (color[0] == r && color[1] == g && color[2] == b))
    {
    return;
    }

  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XY:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        this->Cursor3DWidget->SetAxis1Color(r, g, b);
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        this->Cursor3DWidget->SetAxis2Color(r, g, b);
        }
      if (this->GetCursor3DVisibility())
        {
        this->Render();
        }
      break;
      
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_YZ:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        this->Cursor3DWidget->SetAxis2Color( r, g, b );
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        this->Cursor3DWidget->SetAxis1Color( r, g, b );
        }
      if (this->GetCursor3DVisibility())
        {
        this->Render();
        }
      break;
    }
}

//----------------------------------------------------------------------------
double* vtkKWImageWidget::GetCursor3DYColor()
{
  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XY:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        return this->Cursor3DWidget->GetAxis1Color();
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        return this->Cursor3DWidget->GetAxis2Color();
        }
      break;
      
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_YZ:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        return this->Cursor3DWidget->GetAxis2Color();
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        return this->Cursor3DWidget->GetAxis1Color();
        }
      break;
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DZColor(double r, double g, double b)
{
  double *color = this->GetCursor3DZColor();
  if (!color || (color[0] == r && color[1] == g && color[2] == b))
    {
    return;
    }

  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XZ:
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_YZ:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        this->Cursor3DWidget->SetAxis1Color( r, g, b );
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        this->Cursor3DWidget->SetAxis2Color( r, g, b );
        }
      if (this->GetCursor3DVisibility())
        {
        this->Render();
        }
      break;
    }
}

//----------------------------------------------------------------------------
double* vtkKWImageWidget::GetCursor3DZColor()
{
  switch (this->SliceOrientation)
    {
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_XZ:
    case vtkKW2DRenderWidget::SLICE_ORIENTATION_YZ:
      if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_CROSSHAIR)
        {
        return this->Cursor3DWidget->GetAxis1Color();
        }
      else if (this->Cursor3DType == vtkKWImageWidget::CURSOR_TYPE_PLANE)
        {
        return this->Cursor3DWidget->GetAxis2Color();
        }
      break;
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DType(int type)
{
  if (this->GetCursor3DType() == type)
    {
    return;
    }

  double color1[3], color2[3];

  this->Cursor3DWidget->GetAxis1Color(color1);

  this->Cursor3DWidget->GetAxis2Color(color2);
    
  this->Cursor3DWidget->SetAxis1Color(color2);
    
  this->Cursor3DWidget->SetAxis2Color(color1);
    
  this->Cursor3DType = type;

  if (this->GetCursor3DVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetCursor3DType()
{
  return this->Cursor3DType;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCursor3DInteractiveState(int state)
{
  this->Cursor3DWidget->SetInteractive(state);
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCroppingRegionsVisibility(int state)
{
  if (this->GetCroppingRegionsVisibility() == state)
    {
    return;
    }

  this->CroppingWidget->SetEnabled(state);
  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetCroppingRegionsVisibility()
{
  return this->CroppingWidget->GetEnabled();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCroppingPlanes(double p[6])
{
  this->SetCroppingPlanes(p[0], p[1], p[2], p[3], p[4], p[5]);
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCroppingPlanes(
  double p0, double p1, double p2, double p3, double p4, double p5)
{
  double *current = this->GetCroppingPlanes();
  if (current[0] == p0 &&
      current[1] == p1 &&
      current[2] == p2 &&
      current[3] == p3 &&
      current[4] == p4 &&
      current[5] == p5)
    {
    return;
    }

  this->CroppingWidget->SetPlanePositions(p0, p1, p2, p3, p4, p5);

  if (this->GetCroppingRegionsVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::ResetCroppingPlanes()
{
  if (this->Input)
    {
    this->SetCroppingPlanes(this->Input->GetBounds());
    }
}

//----------------------------------------------------------------------------
double* vtkKWImageWidget::GetCroppingPlanes()
{
  return this->CroppingWidget->GetPlanePositions();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetCroppingRegionFlags(int i)
{
  if (this->GetCroppingRegionFlags() == i)
    {
    return;
    }

  this->CroppingWidget->SetCroppingRegionFlags(i);

  if (this->GetCroppingRegionsVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetCroppingRegionFlags()
{
  return this->CroppingWidget->GetCroppingRegionFlags();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSplineCurves3D( vtkKW3DSplineCurvesWidget * curves )
{
  this->Superclass::SetSplineCurves3D( curves );
  if( this->SplineCurves3D )
    {
    // ADD Here the interactions with the Cut filter
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSplineSurfaces3D( vtkKW3DSplineSurfacesWidget * surfaces )
{
  this->Superclass::SetSplineSurfaces3D( surfaces );
  if( this->SplineSurfaces3D )
    {
    if( !this->SplineSurfaces )
      {
      this->SplineSurfaces = vtkKW2DSplineSurfacesWidget::New();
      }
    
    this->SplineSurfaces->SetInteractor( this->GetRenderWindowInteractor() );

    this->SplineSurfaces->SetSplineSurfaces3D( this->SplineSurfaces3D );

    this->UpdateImplicitPlaneSplineSurfaces();
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSplineSurfaces3DVisibility(int v)
{
  if( this->SplineSurfaces3D )
    {
    if( this->SplineSurfaces )
      {
      this->SplineSurfaces->SetSplineSurfaceVisibility( v );
      }
    this->Render();
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSplineSurfaces3DVisibility(const char * surfaceId, int v)
{
  if( this->SplineSurfaces3D )
    {
    if( this->SplineSurfaces )
      {
      this->SplineSurfaces->SetSplineSurfaceVisibility( surfaceId, v );
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSplineSurfaces3DProperty(const char * surfaceId, vtkProperty * property)
{
  if( this->SplineSurfaces3D )
    {
    if( this->SplineSurfaces )
      {
      this->SplineSurfaces->SetSplineSurfaceProperty( surfaceId, property );
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetAnnotationsVisibility(int v)
{
  this->Superclass::SetAnnotationsVisibility(v);

  this->SetScaleBarVisibility(v);
  this->SetScalarBarVisibility(v);
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSupportScaleBar(int s)
{
  if (this->SupportScaleBar == s)
    {
    return;
    }

  this->SupportScaleBar = s;
  this->Modified();

  this->SetScaleBarVisibility( 
      this->GetScaleBarVisibility() & s );
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetScaleBarVisibility(int arg)
{
  if (this->GetScaleBarVisibility() == arg)
    {
    return;
    }

  if (arg)
    {
    if (this->SupportScaleBar)
      {
      this->ScaleBarWidget->SetEnabled(1);
      this->InvokeEvent(vtkKWEvent::ImageScaleBarVisibilityChangedEvent, &arg);
      }
    }
  else
    {
    this->ScaleBarWidget->SetEnabled(0);
    this->InvokeEvent(vtkKWEvent::ImageScaleBarVisibilityChangedEvent, &arg);
    }

  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetScaleBarVisibility()
{
  return this->ScaleBarWidget->GetEnabled();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::ToggleScaleBarVisibility()
{
  this->SetScaleBarVisibility(!this->GetScaleBarVisibility());
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetSupportScalarBar(int s)
{
  if (this->SupportScalarBar == s)
    {
    return;
    }

  this->SupportScalarBar = s;
  this->Modified();

  this->SetScalarBarVisibility( 
      this->GetScalarBarVisibility() & s );
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetScalarBarVisibility(int arg)
{
  if (this->GetScalarBarVisibility() == arg)
    {
    return;
    }

  if (arg)
    {
    if (this->SupportScalarBar)
      {
      this->ScalarBarWidget->SetEnabled(1);
      }
    }
  else
    {
    this->ScalarBarWidget->SetEnabled(0);
    }

  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetScalarBarVisibility()
{
  return this->ScalarBarWidget->GetEnabled();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::ToggleScalarBarVisibility()
{
  this->SetScalarBarVisibility(!this->GetScalarBarVisibility());
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetScalarBarComponent(int comp)
{
  if (comp == this->GetScalarBarComponent())
    {
    return;
    }

  vtkScalarBarActor *actor = this->ScalarBarWidget->GetScalarBarActor();
  if (actor)
    {
    actor->SetLookupTable(this->VolumeProperty->GetRGBTransferFunction(comp));
    if (this->GetScalarBarVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
int vtkKWImageWidget::GetScalarBarComponent()
{
  vtkScalarBarActor *actor = this->ScalarBarWidget->GetScalarBarActor();
  if (actor && actor->GetLookupTable())
    {
    for (int i = 0; i < VTK_MAX_VRCOMP; i++)
      {
      if (actor->GetLookupTable() == 
          this->VolumeProperty->GetRGBTransferFunction(i))
        {
        return i;
        }
      }
    }

  return 0;
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::SetScaleBarColor(double r, double g, double b)
{
  double *color = this->GetScaleBarColor();
  if (!color || (color[0] == r && color[1] == g && color[2] == b))
    {
    return;
    }

  this->ScaleBarWidget->SetColor(r, g, b);

  if (this->GetScaleBarVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
double* vtkKWImageWidget::GetScaleBarColor()
{
  return this->ScaleBarWidget->GetColor();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::CreateWidget()
{
  if (this->IsCreated())
    {
    vtkErrorMacro("widget already created " << this->GetClassName());
    return;
    }

  this->Superclass::CreateWidget();

  this->ScaleBarWidget->SetApplication(this->GetApplication());
  
  this->UpdateAccordingToUnits();
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::ConfigureEventMap()
{
  this->Superclass::ConfigureEventMap();

#if 0
  // Not used anymore

  const char *context = "2D image view";

  this->EventMap->AddKeyEvent(
    'p', vtkKWEventMap::NoModifier, "PlaceMarker3D",
    context, k_("Place 3D marker"));
#endif
}

//----------------------------------------------------------------------------
vtkKWInteractorStyle2DView* vtkKWImageWidget::GetInteractorStyle()
{
  return this->InteractorStyle; 
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::PopulateContextMenuWithAnnotationEntries(vtkKWMenu *menu)
{
  this->Superclass::PopulateContextMenuWithAnnotationEntries(menu);

  if (!menu)
    {
    return;
    }

  int tcl_major, tcl_minor, tcl_patch_level;
  Tcl_GetVersion(&tcl_major, &tcl_minor, &tcl_patch_level, NULL);
  int show_icons = (tcl_major > 8 || (tcl_major == 8 && tcl_minor >= 5));

  int index;

  // Scale bar

  if (this->SupportScaleBar)
    {
    index = menu->AddCheckButton(
      ks_("Annotation|Scale Bar"), this, "ToggleScaleBarVisibility");
    menu->SetItemSelectedState(index, this->GetScaleBarVisibility());
    if (show_icons)
      {
      menu->SetItemImageToPredefinedIcon(
        index, vtkKWIcon::IconScaleBarAnnotation);
      menu->SetItemCompoundModeToLeft(index);
      }
    }

  // Scalar bar

  if (this->SupportScalarBar)
    {

    index = menu->AddCheckButton(
      ks_("Annotation|Color Bar"), this, "ToggleScalarBarVisibility");
    menu->SetItemSelectedState(index, this->GetScalarBarVisibility());
    if (show_icons)
      {
      menu->SetItemImageToPredefinedIcon(
        index, vtkKWIcon::IconColorBarAnnotation);
      menu->SetItemCompoundModeToLeft(index);
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWImageWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  
  os << indent << "InteractorStyle: " << this->InteractorStyle << endl;
  os << indent << "CroppingWidget: " << this->CroppingWidget << endl;
  os << indent << "Cursor3DWidget: " << this->Cursor3DWidget << endl;
  os << indent << "ScaleBarWidget: " << this->ScaleBarWidget << endl;
  os << indent << "ScalarBarWidget: " << this->ScalarBarWidget <<endl;
  os << indent << "Image: " << this->Image <<endl;
  os << indent << "SupportScaleBar: " 
    << (this->SupportScaleBar ? "On" : "Off") << endl;
  os << indent << "SupportScalarBar: " 
     << (this->SupportScalarBar ? "On" : "Off") << endl;
}
