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

  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 "vtkKWRenderWidgetPro.h"

#include "vtkCallbackCommand.h"
#include "vtkCommand.h"
#include "vtkCornerAnnotation.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkProp.h"
#include "vtkProperty2D.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
#include "vtkVolumeProperty.h"

#include "vtkKW3DMarkersWidget.h"
#include "vtkKW3DSplineCurvesWidget.h"
#include "vtkKW3DSplineSurfacesWidget.h"
#include "vtkKWApplication.h"
#include "vtkKWEvent.h"
#include "vtkKWEventMap.h"
#include "vtkKWGenericRenderWindowInteractor.h"
#include "vtkKWIcon.h"
#include "vtkKWImageMapToWindowLevelColors.h"
#include "vtkKWInternationalization.h"
#include "vtkKWKeyBindingsManager.h"
#include "vtkKWMarker2D.h"
#include "vtkKWMenu.h"
#include "vtkKWOrientationWidget.h"
#include "vtkKWWindow.h"

#ifdef _WIN32
#include "vtkWin32OpenGLRenderWindow.h"
#endif

#include <vtksys/stl/string>

vtkCxxRevisionMacro(vtkKWRenderWidgetPro, "$Revision: 1.110 $");

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLKWRenderWidgetProReader.h"
#include "XML/vtkXMLKWRenderWidgetProWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkKWRenderWidgetPro, vtkXMLKWRenderWidgetProReader, vtkXMLKWRenderWidgetProWriter);

//----------------------------------------------------------------------------
vtkKWRenderWidgetPro::vtkKWRenderWidgetPro()
{
  this->Input = NULL;
  this->LastInputCheck = NULL;

  this->EventMap = vtkKWEventMap::New();

  vtkRenderWindowInteractor *interactor = this->GetRenderWindowInteractor();

  this->Marker2D = vtkKWMarker2D::New();
  this->Marker2D->SetParent(this);
  this->Marker2D->SetInteractor(interactor);

  this->Markers3D = vtkKW3DMarkersWidget::New();
  this->Markers3D->SetParent(this);
  this->Markers3D->SetInteractor(interactor);

  this->OrientationWidget = vtkKWOrientationWidget::New();
  this->OrientationWidget->SetInteractor(interactor);
  this->OrientationWidget->SetParent(this);

  this->SplineCurves3D = 0;
  this->SplineSurfaces3D = 0;

  this->DisplayChannels = 
    vtkKWImageMapToWindowLevelColors::DISPLAY_INTENSITIES;
  this->UseOpacityModulation = 0;

  int i;
  for (i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    this->ScalarUnits[i] = NULL;
    }
  this->Window = 1.0;
  this->Level = 0.0;
  this->EventIdentifier = -1;

  /*
  this->HeaderAnnotation->VisibilityOn();
  vtkTextProperty *tprop = this->HeaderAnnotation->GetTextProperty();
  tprop->SetColor(1.0, 0.0, 0.0); // the text actor still looks like crap
  */

  this->VolumeProperty = NULL;
  vtkVolumeProperty *volumeprop = vtkVolumeProperty::New();
  this->SetVolumeProperty(volumeprop);
  volumeprop->Delete();

  this->VolumeProperty->SetInterpolationTypeToLinear();

  this->LastIndependentComponents = 
    this->GetIndependentComponents();
}

//----------------------------------------------------------------------------
vtkKWRenderWidgetPro::~vtkKWRenderWidgetPro()
{
  this->SetInput(NULL);

  int i;
  for (i = 0; i < VTK_MAX_VRCOMP; i++)
    {
    this->SetScalarUnits(i, 0);
    }

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

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

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

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

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

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetInput(vtkImageData *data)
{
  if (this->Input == data)
    {
    return;
    }

  if (this->Input)
    {
    this->Input->UnRegister(this);
    }
    
  this->Input = data;

  if (this->Input)
    {
    this->Input->Register(this);
    }

  this->Modified();

  // A whole new input, so let's delete the structure cache so that
  // we can be sure everything will be refreshed

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

  // Update internal objects according to the new Input

  this->UpdateAccordingToInput();
}

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

  int mask = vtkKWRenderWidgetPro::INPUT_UNCHANGED;

  // Make some corrections

  this->SetIndependentComponents(this->GetValidIndependentComponents());
    
  // Compare the current Input to the state of the Input the last time
  // this method was called

  // Scalar structure has changed ?

  if (!this->LastInputCheck ||
      !this->Input ||
      (this->Input->GetScalarType() !=
       this->LastInputCheck->GetScalarType()) ||
      (this->Input->GetNumberOfScalarComponents() !=
       this->LastInputCheck->GetNumberOfScalarComponents()) ||
      (this->GetIndependentComponents() != 
       this->LastIndependentComponents))
    {
    this->InputScalarStructureHasChanged();
    mask |= vtkKWRenderWidgetPro::INPUT_SCALAR_STRUCTURE_CHANGED;
    }

  // Input bounds have changed ?

  int boundsChanged = 0;  
  if (!this->LastInputCheck || !this->Input )
    {
    boundsChanged = 1;  
    }
  else // "double" tolerant comparision of bounds values.
    {
    double * bounds1 = this->Input->GetBounds();
    double * bounds2 = this->LastInputCheck->GetBounds();
    
    double extentX = fabs( bounds1[1] - bounds1[0] );
    if( extentX > fabs( bounds2[1] - bounds2[0] ) )
      {
      extentX =  fabs( bounds2[1] - bounds2[0] );
      }
    
    double extentY = bounds1[3] - bounds1[2];
    if( extentY > fabs( bounds2[3] - bounds2[2] ) )
      {
      extentY =  fabs( bounds2[3] - bounds2[2] );
      }
    
    double extentZ = bounds1[5] - bounds1[4];
    if( extentZ > fabs( bounds2[5] - bounds2[4] ) )
      {
      extentZ =  fabs( bounds2[5] - bounds2[4] );
      }
    
    double minextent[6];
    minextent[0] = minextent[1] = extentX;
    minextent[2] = minextent[3] = extentY;
    minextent[4] = minextent[5] = extentZ;

    const double tolerance = 1e-6;
    for(unsigned int i=0; i<6; i++)
      {
      const double difference = fabs( bounds2[i] - bounds1[i] ) / minextent[i];
      if( difference > tolerance )
        {
        boundsChanged = 1;  
        break;
        }
      }
    }

  if( boundsChanged )
    {
    this->InputBoundsHaveChanged();
    mask |= vtkKWRenderWidgetPro::INPUT_BOUNDS_CHANGED;
    }

  // Any changes

  if (mask)
    {
    this->InputHasChanged(mask);
    }

  // Update the status

  if (this->Input)
    {
    if (!this->LastInputCheck)
      {
      this->LastInputCheck = vtkImageData::New();
      }

    this->LastInputCheck->SetOrigin(this->Input->GetOrigin());
    this->LastInputCheck->SetSpacing(this->Input->GetSpacing());
    this->LastInputCheck->SetDimensions(this->Input->GetDimensions());
    this->LastInputCheck->SetWholeExtent(this->Input->GetWholeExtent());
    this->LastInputCheck->SetExtent(this->Input->GetExtent());
    this->LastInputCheck->SetUpdateExtent(this->Input->GetUpdateExtent());
    this->LastInputCheck->SetScalarType(this->Input->GetScalarType());
    this->LastInputCheck->SetNumberOfScalarComponents(
      this->Input->GetNumberOfScalarComponents());
    this->LastIndependentComponents = 
      this->GetIndependentComponents();
    }
  
  return mask;
}

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

  return 1;
}

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

  this->ConnectInternalPipeline();

  // Update color mapping, since not all combinations of IndependentComponents
  // DisplayChannels and UseOpacityModulation are valid depending of
  // the scalar

  this->UpdateColorMapping();

  // The scalar range has most likely changed now
  
  this->ResetWindowLevel();

  return 1;
}

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

  // Remove all 3D markers

  this->RemoveAll3DMarkers();

  return 1;
}

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

  // Need to make sure we are using the overlay renderer

  if (this->Input)
    {
    if (this->Marker2D)
      {
      this->Marker2D->SetDefaultRenderer(this->GetOverlayRenderer());
      }
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetIndependentComponents(int arg)
{
  if (this->GetIndependentComponents() == arg)
    {
    return;
    }

  int old_value = this->GetIndependentComponents();
  this->VolumeProperty->SetIndependentComponents(arg);
  int valid_value = this->GetValidIndependentComponents();
  this->VolumeProperty->SetIndependentComponents(valid_value);

  if (this->GetIndependentComponents() != old_value)
    {
    this->InputScalarStructureHasChanged(); // will call UpdateColorMapping()
    this->Modified();
    this->Render();
    }
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetIndependentComponents()
{
  return this->VolumeProperty->GetIndependentComponents();
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetValidIndependentComponents()
{
  if (this->Input)
    {
    int nb_components = this->Input->GetNumberOfScalarComponents();
    int scalar_type = this->Input->GetScalarType();

    if (nb_components == 1 || 
        nb_components == 3 || 
        (nb_components == 4 && scalar_type != VTK_UNSIGNED_CHAR))
      {
      if (!this->GetIndependentComponents())
        {
        return 1;
        }
      }
    }

  return this->GetIndependentComponents();
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetVolumeProperty(vtkVolumeProperty *arg)
{
  if (this->VolumeProperty == arg)
    {
    return;
    }

  if (this->VolumeProperty)
    {
    this->VolumeProperty->UnRegister(this);
    }
    
  this->VolumeProperty = arg;

  if (this->VolumeProperty)
    {
    this->VolumeProperty->Register(this);
    }  

  this->Modified();

  this->UpdateColorMapping();
  this->Render();
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetEnableShading(int index, int shade)
{
  if (this->GetEnableShading(index) == shade)
    {
    return;
    }

  this->VolumeProperty->SetShade(index, shade);

  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetEnableShading(int index)
{
  return this->VolumeProperty->GetShade(index);
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetGradientOpacityEnable(int index, int state)
{
  if (this->GetGradientOpacityEnable(index) == state)
    {
    return;
    }

  if (state)
    {
    this->VolumeProperty->DisableGradientOpacityOff(index);
    }
  else
    {
    this->VolumeProperty->DisableGradientOpacityOn(index);
    }
  
  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetGradientOpacityEnable(int index)
{
  return !this->VolumeProperty->GetDisableGradientOpacity(index);
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::VolumePropertyChanged()
{
  this->UpdateColorMapping();
  this->Render();
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::VolumePropertyChanging()
{
  this->UpdateColorMapping();
  int state = this->GetRenderMode();
  if (state != vtkKWRenderWidget::DisabledRender)
    {
    this->SetRenderModeToInteractive();
    this->Render();
    this->SetRenderMode(state);
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetDisplayChannels(int arg)
{
  if (this->DisplayChannels == arg)
    {
    return;
    }

  this->DisplayChannels = arg;
  this->Modified();

  this->UpdateColorMapping();
  this->Render();

  this->InvokeEvent(
    vtkKWRenderWidgetPro::DisplayChannelsChangedEvent, &arg);
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetUseOpacityModulation(int arg)
{
  if (this->UseOpacityModulation == arg)
    {
    return;
    }

  this->UseOpacityModulation = arg;
  this->Modified();

  this->UpdateColorMapping();
  this->Render();

  this->InvokeEvent(
    vtkKWRenderWidgetPro::UseOpacityModulationChangedEvent, &arg);
}

//----------------------------------------------------------------------------
const char *vtkKWRenderWidgetPro::GetScalarUnits(int index)
{
  if (index < 0 || index >= VTK_MAX_VRCOMP)
    {
    return NULL;
    }

  return this->ScalarUnits[index];
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetScalarUnits(int index, const char *_arg)
{
  if (index < 0 || index >= VTK_MAX_VRCOMP)
    {
    return;
    }

  vtkDebugMacro(<< this->GetClassName() << " (" << this
                << "): setting ScalarUnits to " << _arg );

  if (this->ScalarUnits[index] == NULL && _arg == NULL)
    {
    return;
    }

  if (this->ScalarUnits[index] && _arg &&
      (!strcmp(this->ScalarUnits[index], _arg)))
    {
    return;
    }

  if (this->ScalarUnits[index])
    {
    delete [] this->ScalarUnits[index];
    }

  if (_arg)
    {
    this->ScalarUnits[index] = new char[strlen(_arg) + 1];
    strcpy(this->ScalarUnits[index], _arg);
    }
  else
    {
    this->ScalarUnits[index] = NULL;
    }

  this->Modified();
}

//---------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetWindowLevel(double window, double level)
{
  if (this->Window == window && this->Level == level)
    {
    return;
    }

  this->Window = window;
  this->Level = level;
  this->Modified();

  this->UpdateColorMapping();
  this->Render();
}

//---------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetWindow(double window)
{
  this->SetWindowLevel(window, this->GetLevel());
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetLevel(double level)
{
  this->SetWindowLevel(this->GetWindow(), level);
}

//---------------------------------------------------------------------------
void vtkKWRenderWidgetPro::ResetWindowLevel()
{
  if (!this->Input)
    {
    return;
    }

  this->Input->Update();
  double *range = this->Input->GetScalarRange();
  double window = (double)(range[1] - range[0]);
  double level  = (double)((range[1] + range[0]) / 2.0);

  if (this->GetWindow() != window || this->GetLevel() != level)
    {
    this->SetWindowLevel(window, level);
    this->InvokeEvent(vtkKWEvent::WindowLevelResetEvent, NULL);
    }
}

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

  this->Superclass::CreateWidget();

  // Configure the event map

  this->ConfigureEventMap();

  // Add the event map key bindings to the key bindings manager

  vtkKWKeyBindingsManager *mgr = this->GetKeyBindingsManager();
  if (mgr)
    {
    mgr->SetKeyBindingsFromEventMap(this->EventMap);
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::Close()
{
  this->Superclass::Close();

  // Let's just not do that yet: a Close() is usually performed before new
  // data is loaded, therefore SetInput() is about to be called too, with 
  // a value that is likely to be the same (since the OpenWizard() use the same
  // output). If we don't change Input, we will be able to use the value
  // of LastInputCheck to update only the relevant parts.
  // this->SetInput(NULL);

  // Break the loop to the overlay renderer

  if (this->Marker2D)
    {
    this->Marker2D->SetDefaultRenderer(NULL);
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::ConfigureEventMap()
{
  this->EventMap->RemoveAllMouseEvents();
  this->EventMap->RemoveAllKeyEvents();
  this->EventMap->RemoveAllKeySymEvents();

#if 0
  // Not used anymore

  const char *context = "2D/3D View";

  this->EventMap->AddKeyEvent(
    'm', vtkKWEventMap::NoModifier, "ToggleMarker2D", 
    context, k_("Toggle 2D markers visibility On/Off"));
#endif
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::CreateDefaultRenderers()
{
  this->Superclass::CreateDefaultRenderers();

  vtkRenderer *ren = this->GetRenderer();
  if (ren)
    {
    this->OrientationWidget->SetParentRenderer(ren);
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetMarker2DVisibility(int v)
{
  if (this->GetMarker2DVisibility() == v)
    {
    return;
    }

  this->Marker2D->SetEnabled(v);
  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetMarker2DVisibility()
{
  if (this->Marker2D)
    {
    return this->Marker2D->GetEnabled();
    }

  return 0;
}

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

  if (this->Marker2D)
    {
    this->Marker2D->SetColor(r, g, b);
    if (this->GetMarker2DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
double* vtkKWRenderWidgetPro::GetMarker2DColor()
{
  if (this->Marker2D)
    {
    return this->Marker2D->GetColor();
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetMarker2DPosition(double x1, double y1, 
                                               double x2, double y2)
{
  if (!this->Marker2D)
    {
    return;
    }

  double pos[4];
  this->GetMarker2DPosition(pos);
  if (pos[0] == x1 && pos[1] == y1 && 
      pos[2] == x2 && pos[3] == y2)
    {
    return;
    }

  this->Marker2D->SetPosition(x1, y1, x2, y2);
  if (this->GetMarker2DVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::GetMarker2DPosition(double pos[4])
{
  if (this->Marker2D)
    {
    this->Marker2D->GetPosition(pos);
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetSplineCurves3D( vtkKW3DSplineCurvesWidget * curves )
{
  if( curves )
    {
    this->SplineCurves3D = curves;
    }
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetSplineCurves3DVisibility()
{
  if (this->SplineCurves3D)
    {
    return this->SplineCurves3D->GetEnabled();
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetSplineCurves3DVisibility(int v)
{
  if( this->SplineCurves3D )
  {
    if (this->GetSplineCurves3DVisibility() == v)
      {
      return;
      }
    this->SplineCurves3D->SetEnabled(v);  
    this->Render();
  }
}


//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetSplineSurfaces3D( vtkKW3DSplineSurfacesWidget * surfaces )
{
  if( surfaces )
    {
    this->SplineSurfaces3D = surfaces;
    }
}


//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetMarkers3DVisibility(int v)
{
  if (this->GetMarkers3DVisibility() == v)
    {
    return;
    }
  this->Markers3D->SetEnabled(v);
  this->Render();
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetMarkers3DVisibility()
{
  if (this->Markers3D)
    {
    return this->Markers3D->GetEnabled();
    }

  return 0;
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetMarkers3DGroupColor(unsigned int gid, 
                                                  double r, double g, double b)
{
  const double *color = this->GetMarkers3DGroupColor(gid);
  if (!color || (color[0] == r && color[1] == g && color[2] == b))
    {
    return;
    }

  if (this->Markers3D)
    {
    this->Markers3D->SetMarkersGroupColor(gid, r, g, b);
    if (this->GetMarkers3DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
double* vtkKWRenderWidgetPro::GetMarkers3DGroupColor(unsigned int gid) const
{
  if (this->Markers3D)
    {
    return this->Markers3D->GetMarkersGroupColor(gid);
    }
  return 0;
}

//----------------------------------------------------------------------------
const char * vtkKWRenderWidgetPro::GetMarkers3DGroupName(unsigned int gid) const
{
  if (this->Markers3D)
    {
    return this->Markers3D->GetMarkersGroupName( gid );
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetMarkers3DGroupId(const char *name) const
{
  if (this->Markers3D)
    {
    return this->Markers3D->GetMarkersGroupId(name);
    }
  return -1;
}

//----------------------------------------------------------------------------
unsigned int vtkKWRenderWidgetPro::GetNumberOfMarkers3DGroups() const
{
  if (this->Markers3D)
    {
    return this->Markers3D->GetNumberOfMarkersGroups();
    }
  return 0;
}


//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::Add3DMarker(unsigned int gid, 
                                       double x, double y, double z)
{
  if (this->Markers3D && !this->Markers3D->HasMarker(gid, x, y, z))
    {
    this->Markers3D->AddMarker(gid, x, y, z);
    if (this->GetMarkers3DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::RemoveSelected3DMarker()
{
  if (this->Markers3D && 
      this->Markers3D->RemoveSelectedMarker() && 
      this->GetMarkers3DVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::RemoveAll3DMarkers()
{
  if (this->Markers3D && 
      this->Markers3D->RemoveAllMarkers() &&
      this->GetMarkers3DVisibility())
    {
    this->Render();
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::Set3DMarkerPosition(unsigned int idx, 
                                               double x, double y, double z)
{
  double *pos = this->Get3DMarkerPosition(idx);
  if (!pos || (pos[0] == x && pos[1] == y && pos[2] == z))
    {
    return;
    }

  if (this->Markers3D)
    {
    this->Markers3D->SetMarkerPosition(idx, x, y, z);
    if (this->GetMarkers3DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::Add3DMarkersGroup(const char * groupName, 
                                             double r, double g, double b)
{
  if (this->Markers3D && !this->Markers3D->HasMarkersGroup( groupName ))
    {
    double color[3];
    color[0] = r;
    color[1] = g;
    color[2] = b;
    this->Markers3D->AddMarkersGroup( groupName, color );
    if (this->GetMarkers3DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::Remove3DMarkersGroup(const char * groupName)
{
  int groupIsRemovable = 0;
  if (this->Markers3D && this->Markers3D->HasMarkersGroup( groupName ))
    {
    groupIsRemovable = this->Markers3D->RemoveMarkersGroup( groupName );
    if ( groupIsRemovable && this->GetMarkers3DVisibility())
      {
      this->Render();
      }
    }
  return groupIsRemovable;
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::RemoveAll3DMarkersGroups()
{
  if (this->Markers3D )
    {
    this->Markers3D->RemoveAllMarkersGroups();
    if (this->GetMarkers3DVisibility())
      {
      this->Render();
      }
    }
}

//----------------------------------------------------------------------------
double* vtkKWRenderWidgetPro::Get3DMarkerPosition(unsigned int idx)
{
  if (this->Markers3D)
    {
    return this->Markers3D->GetMarkerPosition(idx);
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::Add3DSplineCurve()
{
  if (this->SplineCurves3D && this->Input )
    {
    this->SplineCurves3D->AddSplineCurve( this->Input->GetBounds() );
    if (this->GetSplineCurves3DVisibility())
      {
      this->Render();
      }
    }
}


//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::SetOrientationMarkerVisibility(int state)
{
  if (this->GetOrientationMarkerVisibility() == state)
    {
    return;
    }

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

//----------------------------------------------------------------------------
int vtkKWRenderWidgetPro::GetOrientationMarkerVisibility()
{
  return this->OrientationWidget->GetEnabled();
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::ToggleOrientationMarkerVisibility()
{
  this->SetOrientationMarkerVisibility(
    !this->GetOrientationMarkerVisibility());
}

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

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

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

//----------------------------------------------------------------------------
double* vtkKWRenderWidgetPro::GetOrientationMarkerColor() 
{
  return this->OrientationWidget->GetColor();
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::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;

  // Orientation cube

  index = menu->AddCheckButton(
    ks_("Annotation|Orientation Cube"), 
    this, "ToggleOrientationMarkerVisibility");
  menu->SetItemSelectedState(index, this->GetOrientationMarkerVisibility());
  if (show_icons)
    {
    menu->SetItemImageToPredefinedIcon(
      index, vtkKWIcon::IconOrientationCubeAnnotation);
    menu->SetItemCompoundModeToLeft(index);
    }
}

//----------------------------------------------------------------------------
void vtkKWRenderWidgetPro::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);

  os << indent << "Input: ";
  if (this->Input)
    {
    os << this->Input << endl;
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "EventMap: " << this->EventMap << endl;
  os << indent << "Marker2D: " << this->GetMarker2D() << endl;
  os << indent << "Markers3D: " << this->GetMarkers3D() << endl;
  os << indent << "DisplayChannels: " << this->DisplayChannels <<endl;
  os << indent << "UseOpacityModulation: " 
     << this->UseOpacityModulation <<endl;
  os << indent << "SplineCurves3D: " << this->SplineCurves3D << "\n";
  os << indent << "SplineSurfaces3D: " << this->SplineSurfaces3D << "\n";
  os << indent << "Window: " << this->Window <<endl;
  os << indent << "Level: " << this->Level <<endl;
  os << indent << "EventIdentifier: " << this->EventIdentifier << endl;
  os << indent << "OrientationWidget: " << this->OrientationWidget <<endl;
  os << indent << "VolumeProperty: " << this->VolumeProperty <<endl;
}
