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

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

#include "vtkAbstractWidget.h"
#include "vtkAngleRepresentation2D.h"
#include "vtkAxisActor2D.h"
#include "vtkBiDimensionalRepresentation2D.h"
#include "vtkCamera.h"
#include "vtkCaptionActor2D.h"
#include "vtkCaptionRepresentation.h"
#include "vtkCommand.h"
#include "vtkDistanceRepresentation2D.h"
#include "vtkHandleWidget.h"
#include "vtkImageActor.h"
#include "vtkImageActorPointHandleRepresentation3D.h"
#include "vtkImageActorPointPlacer.h"
#include "vtkImageActorPointPlacer.h"
#include "vtkLODProp3D.h"
#include "vtkLeaderActor2D.h"
#include "vtkObjectFactory.h"
#include "vtkOrientedGlyphContourRepresentation.h"
#include "vtkOrientedGlyphFocalPlaneContourRepresentation.h"
#include "vtkPropCollection.h"
#include "vtkProperty.h"
#include "vtkProperty2D.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkTextProperty.h"

#include "vtkKWAngleWidget.h"
#include "vtkKWBiDimensionalWidget.h"
#include "vtkKWCaptionWidget.h"
#include "vtkKWContourWidget.h"
#include "vtkKWDistanceWidget.h"
#include "vtkKWEvent.h"
#include "vtkKWImageWidget.h"
#include "vtkKWLightboxWidget.h"
#include "vtkKWProbeImageWidget.h"
#include "vtkKWRenderWidget.h"
#include "vtkKWVolumeWidget.h"

#include "vtkKWEPaintbrushWidget.h"
#include "vtkKWEPaintbrushRepresentation2D.h"
#include "vtkKWEPaintbrushShape.h"
#include "vtkKWEPaintbrushOperation.h"
#include "vtkKWEPaintbrushDrawing.h"
#include "vtkKWEPaintbrushSketch.h"
#include "vtkKWEPaintbrushProperty.h"
#include "vtkKWEPaintbrushLabelData.h"
#include "vtkKWELightPaintbrushWidgetCallbackMapper.h"
#include "vtkKWEWidgetGroup.h"

#include "vtkVVDataItem.h"
#include "vtkVVHandleWidget.h"
#include "vtkVVPaintbrushWidgetEditor.h"

#include <vtksys/stl/vector>

vtkStandardNewMacro(vtkVVSelectionFrame);
vtkCxxRevisionMacro(vtkVVSelectionFrame, "$Revision: 1.60 $");

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLVVSelectionFrameReader.h"
#include "XML/vtkXMLVVSelectionFrameWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkVVSelectionFrame, vtkXMLVVSelectionFrameReader, vtkXMLVVSelectionFrameWriter);

//----------------------------------------------------------------------------
class vtkVVSelectionFrameInternals
{
public:

  struct WidgetSlot
  {
    vtkAbstractWidget *Widget;
    int Lock;
    int Visibility;
    int OriginalSlice;
  };
  
  // Interactor widgets

  typedef vtksys_stl::vector<WidgetSlot> InteractorWidgetPoolType;
  typedef vtksys_stl::vector<WidgetSlot>::iterator InteractorWidgetPoolIterator;
  InteractorWidgetPoolType InteractorWidgetPool;
  
  InteractorWidgetPoolIterator FindSlot(vtkAbstractWidget *widget);
};

//----------------------------------------------------------------------------
vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator
vtkVVSelectionFrameInternals::FindSlot(vtkAbstractWidget *widget)
{
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->InteractorWidgetPool.end();
  if (widget)
    {
    vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
      this->InteractorWidgetPool.begin();
    for (; it != end; ++it)
      {
      if ((*it).Widget == widget)
        {
        return it;
        }
      }
    }
  return end;
}

//----------------------------------------------------------------------------
vtkVVSelectionFrame::vtkVVSelectionFrame()
{
  this->Internals = new vtkVVSelectionFrameInternals;
  this->RenderWidget = NULL;
  this->DataItem = NULL;
  this->BindRenderWidgetOnlyWhenSelected = 1;
}

//----------------------------------------------------------------------------
vtkVVSelectionFrame::~vtkVVSelectionFrame()
{
  // Delete our pool

  if (this->Internals)
    {
    this->RemoveAllInteractorWidgets();
    delete this->Internals;
    }

  this->SetRenderWidget(NULL);
  this->SetDataItem(NULL);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::SetRenderWidget(vtkKWRenderWidget *arg)
{
  if (this->RenderWidget == arg)
    {
    return;
    }

  this->RemoveAllInteractorWidgets();

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

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

  this->Modified();

  // Create the render widget if needed

  if (this->RenderWidget && this->IsCreated())
    {
    this->CreateRenderWidget();
    }

  // Pack

  this->Pack();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::SetDataItem(vtkVVDataItem *arg)
{
  if (this->DataItem == arg)
    {
    return;
    }

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

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

  this->Modified();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::CreateWidget()
{
  // Check if already created

  if (this->IsCreated())
    {
    vtkErrorMacro(<< this->GetClassName() << " already created");
    return;
    }

  // Call the superclass to create the whole widget

  this->Superclass::CreateWidget();

  // Customize
  
  this->SetReliefToFlat();
  this->SetBorderWidth(1);
  this->SetBackgroundColor(0, 0, 0);
  this->SetOuterSelectionFrameWidth(2);
  this->SetOuterSelectionFrameSelectedColor(0.0, 1.0, 0.0);
  this->TitleBarVisibilityOff();
  this->AllowCloseOff();
  this->AllowChangeTitleOff();
  this->GetLeftUserFrame()->SetBackgroundColor(0.2, 0.2, 0.2);
  this->LeftUserFrameVisibilityOn();
  this->GetBodyFrame()->SetBackgroundColor(0, 0, 0);

  // Create the render widget if needed
  
  this->CreateRenderWidget();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::CreateRenderWidget()
{
  if (this->RenderWidget && !this->RenderWidget->IsCreated())
    {
    if (!this->RenderWidget->GetParent())
      {
      this->RenderWidget->SetParent(this->GetBodyFrame());
      }
    
    this->RenderWidget->Create();
    this->UpdateEnableState();
    this->Pack();
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::Pack()
{
  this->Superclass::Pack();

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

  ostrstream tk_cmd;

  if (this->RenderWidget && this->RenderWidget->IsCreated())
    {
    tk_cmd 
      << "pack " << this->RenderWidget->GetWidgetName()
      << " -expand y -fill both -padx 0 -pady 0 -ipadx 0 -ipady 0" << endl;
    }

  tk_cmd << ends;
  this->Script(tk_cmd.str());
  tk_cmd.rdbuf()->freeze(0);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::Bind()
{
  this->Superclass::Bind();
  this->BindRenderWidget();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::UnBind()
{
  this->Superclass::UnBind();
  this->UnBindRenderWidget();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::BindRenderWidget()
{
  if (this->RenderWidget)
    {
    this->RenderWidget->AddInteractionBindings();
    this->RenderWidget->GetVTKWidget()->SetBinding(
      "<Double-1>", this, "DoubleClickCallback");
    this->UpdateRenderWindowInteractorState();
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::UnBindRenderWidget()
{
  if (this->RenderWidget)
    {
    this->UpdateRenderWindowInteractorState();
    this->RenderWidget->RemoveInteractionBindings();
    this->RenderWidget->GetVTKWidget()->RemoveBinding("<Double-1>");
    }
}

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

  this->RemoveAllInteractorWidgets();

  if (this->RenderWidget)
    {
    this->RenderWidget->Close();
    }
  this->SetRenderWidget(NULL);

  this->SetDataItem(NULL);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::UpdateRenderWindowInteractorState()
{
  if (this->RenderWidget)
    {
    if (!this->BindRenderWidgetOnlyWhenSelected || this->GetSelected())
      {
      this->RenderWidget->GetRenderWindowInteractor()->Enable();
      }
    else
      {
      this->RenderWidget->GetRenderWindowInteractor()->Disable();
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::SetSelected(int arg)
{
  int old_selected = this->GetSelected();
  this->Superclass::SetSelected(arg);
  if (old_selected != this->GetSelected())
    {
    this->UpdateRenderWindowInteractorState();
    }
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::GetNumberOfInteractorWidgets()
{
  if (this->Internals)
    {
    return (int)this->Internals->InteractorWidgetPool.size();
    }

  return 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget *vtkVVSelectionFrame::GetNthInteractorWidget(int i)
{
  if (i < 0 || i >= this->GetNumberOfInteractorWidgets() || !this->Internals)
    {
    vtkErrorMacro("Index out of range");
    return NULL;
    }
  
  return this->Internals->InteractorWidgetPool[i].Widget;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::HasInteractorWidget(vtkAbstractWidget *widget)
{
  return this->Internals->FindSlot(widget) != 
    this->Internals->InteractorWidgetPool.end();
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::GetNumberOfPaintbrushWidgets()
{
  int count = 0;
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->InteractorWidgetPool.begin();
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  for (; it != end; ++it)
    {
    vtkKWEPaintbrushWidget *paintbrush_widget =
      vtkKWEPaintbrushWidget::SafeDownCast((*it).Widget);
    if (paintbrush_widget)
      {
      ++count;
      }
    }
  return count;
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::RemoveAllInteractorWidgets()
{
  if (this->Internals)
    {
    while (this->Internals->InteractorWidgetPool.size())
      {
      this->RemoveInteractorWidget(
        (*this->Internals->InteractorWidgetPool.begin()).Widget);
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::RemoveInteractorWidget(vtkAbstractWidget *interactor)
{
  if (!interactor)
    {
    return;
    }

  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(interactor);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    vtkVVSelectionFrame::RemoveInteractorWidgetObservers(this, (*it).Widget);
    //(*it).Widget->SetEnabled(0);
    (*it).Widget->SetInteractor(NULL);
    (*it).Widget->UnRegister(this);
    
    this->Internals->InteractorWidgetPool.erase(it);
    }
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddInteractorWidget(vtkAbstractWidget *interactor)
{
  if (!interactor)
    {
    vtkErrorMacro("can not add NULL interactor widget to pool!");
    return 0;
    }

  // Already in the pool ?

  if (this->HasInteractorWidget(interactor))
    {
    vtkErrorMacro("The interactor widget is already in the pool!");
    return 0;
    }
  
  if (this->RenderWidget)
    {
    if (!this->RenderWidget->IsCreated())
      {
      vtkErrorMacro("Can not add interactor widget to render widget that wasn't created yet!");
      return 0;
      }
    else
      {
      interactor->SetInteractor(
        this->RenderWidget->GetRenderWindow()->GetInteractor());
      }
    }
  struct vtkVVSelectionFrameInternals::WidgetSlot slot;
  slot.Widget = interactor;
  slot.Lock = 0;
  slot.Visibility = 1;
  slot.OriginalSlice = -1;
  this->Internals->InteractorWidgetPool.push_back(slot);

  interactor->Register(this);

  vtkVVSelectionFrame::AddInteractorWidgetObservers(this, interactor);
  return 1;
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::RemoveInteractorWidgetObservers(
  vtkKWObject *callback_owner, vtkAbstractWidget *interactor)
{
  if (!interactor || !callback_owner)
    {
    return;
    }

  vtkObject *obj = (vtkObject*)(interactor);
  callback_owner->RemoveCallbackCommandObserver(
    obj, vtkCommand::StartInteractionEvent);
  callback_owner->RemoveCallbackCommandObserver(
    obj, vtkCommand::InteractionEvent);
  callback_owner->RemoveCallbackCommandObserver(
    obj, vtkCommand::PlacePointEvent);
  callback_owner->RemoveCallbackCommandObserver(
    obj, vtkCommand::EndInteractionEvent);

  vtkKWEPaintbrushWidget *paintbrush_widget =
    vtkKWEPaintbrushWidget::SafeDownCast(interactor);
  if (paintbrush_widget)
    {
    callback_owner->RemoveCallbackCommandObserver(
      obj, vtkKWEPaintbrushWidget::BeginDrawStrokeEvent);
    callback_owner->RemoveCallbackCommandObserver(
      obj, vtkKWEPaintbrushWidget::ToggleSelectStateEvent);
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::AddInteractorWidgetObservers(
  vtkKWObject *callback_owner, vtkAbstractWidget *interactor)
{
  if (!interactor || !callback_owner)
    {
    return;
    }

  callback_owner->AddCallbackCommandObserver(
    interactor, vtkCommand::StartInteractionEvent);
  callback_owner->AddCallbackCommandObserver(
    interactor, vtkCommand::InteractionEvent);
  callback_owner->AddCallbackCommandObserver(
    interactor, vtkCommand::PlacePointEvent);
  callback_owner->AddCallbackCommandObserver(
    interactor, vtkCommand::EndInteractionEvent);

  vtkKWEPaintbrushWidget *paintbrush_widget =
    vtkKWEPaintbrushWidget::SafeDownCast(interactor);
  if (paintbrush_widget)
    {
    callback_owner->AddCallbackCommandObserver(
      interactor, vtkKWEPaintbrushWidget::BeginDrawStrokeEvent);
    callback_owner->AddCallbackCommandObserver(
      interactor, vtkKWEPaintbrushWidget::ToggleSelectStateEvent);
    }
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::DistanceWidgetIsSupported()
{
  return vtkKWImageWidget::SafeDownCast(this->RenderWidget) ? 1 : 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddDistanceWidget()
{
  vtkKWDistanceWidget *interactor = vtkKWDistanceWidget::New();
  int res = this->AddDistanceWidget(interactor);
  interactor->Delete();
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddDistanceWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  if (res)
    {
    interactor->SetDefaultRenderer(this->RenderWidget->GetRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetRenderer());
    interactor->CreateDefaultRepresentation();
    interactor->SetEnabled(1);
    vtkDistanceRepresentation *rep = vtkDistanceRepresentation::SafeDownCast(
      interactor->GetRepresentation());
    vtkDistanceRepresentation2D *rep2d = 
      vtkDistanceRepresentation2D::SafeDownCast(rep);
    if (rep2d)
      {
      // Set unit
      if (this->DataItem->GetDistanceUnits())
        {
        vtksys_stl::string dist_unit = "%-#6.4g";
        dist_unit += this->DataItem->GetDistanceUnits();
        rep2d->SetLabelFormat( dist_unit.c_str() );
        }

      rep2d->GetAxis()->GetProperty()->SetColor(1.0, 0.0, 0.0);
      // control the line width of the distance widget:
      rep2d->GetAxis()->GetProperty()->SetLineWidth(2.0);
      rep2d->GetAxis()->GetTitleTextProperty()->SetColor(
        rep2d->GetAxis()->GetProperty()->GetColor());
      }
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::BiDimensionalWidgetIsSupported()
{
  return vtkKWImageWidget::SafeDownCast(this->RenderWidget) ? 1 : 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddBiDimensionalWidget()
{
  vtkKWBiDimensionalWidget *interactor = vtkKWBiDimensionalWidget::New();
  int res = this->AddBiDimensionalWidget(interactor);
  interactor->Delete();
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddBiDimensionalWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  if (res)
    {
    interactor->SetDefaultRenderer(this->RenderWidget->GetRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetRenderer());
    interactor->CreateDefaultRepresentation();
    interactor->SetEnabled(1);
    vtkBiDimensionalRepresentation2D *rep2d = 
      vtkBiDimensionalRepresentation2D::SafeDownCast(
        interactor->GetRepresentation());
    if (rep2d)
      {
      // Set unit
      if (this->DataItem->GetDistanceUnits())
        {
        vtksys_stl::string dist_unit = "%-#6.4g";
        dist_unit += this->DataItem->GetDistanceUnits();
        rep2d->SetLabelFormat( dist_unit.c_str() );
        }

      // The BiDi wdg has different text actor, make sure that properties are the same
      // as dist wdg for consitency
      rep2d->GetTextProperty()->SetBold(1);
      rep2d->GetTextProperty()->SetItalic(1);
      rep2d->GetTextProperty()->SetShadow(1);
      rep2d->GetTextProperty()->SetFontFamilyToArial();
      rep2d->GetTextProperty()->SetFontSize(18);
      rep2d->GetLineProperty()->SetColor(1.0, 0.0, 0.0);
      // control the line width of the distance widget:
      rep2d->GetLineProperty()->SetLineWidth(2.0);
      rep2d->GetTextProperty()->SetColor(
        rep2d->GetLineProperty()->GetColor());
      }
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AngleWidgetIsSupported()
{
  return vtkKWImageWidget::SafeDownCast(this->RenderWidget) ? 1 : 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddAngleWidget()
{
  vtkKWAngleWidget *interactor = vtkKWAngleWidget::New();
  int res = this->AddAngleWidget(interactor);
  interactor->Delete();
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddAngleWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  if (res)
    {
    interactor->SetDefaultRenderer(this->RenderWidget->GetRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetRenderer());
    interactor->CreateDefaultRepresentation();
    interactor->SetEnabled(1);
    vtkAngleRepresentation *rep = vtkAngleRepresentation::SafeDownCast(
      interactor->GetRepresentation());
    vtkAngleRepresentation2D *rep2d = 
      vtkAngleRepresentation2D::SafeDownCast(rep);
    if (rep2d)
      {
      rep2d->SetLabelFormat( "%-#5.1f °" );
      rep2d->GetArc()->GetProperty()->SetColor(0.0, 1.0, 0.0);
      // control the line width of the angle widget:
      rep2d->GetArc()->GetProperty()->SetLineWidth(2.0);
      // Propagate:
      rep2d->GetArc()->GetLabelTextProperty()->SetColor(
        rep2d->GetArc()->GetProperty()->GetColor());
      rep2d->GetRay1()->GetProperty()->SetColor(
        rep2d->GetArc()->GetProperty()->GetColor());
      rep2d->GetRay1()->GetProperty()->SetLineWidth(
        rep2d->GetArc()->GetProperty()->GetLineWidth());
      rep2d->GetRay2()->GetProperty()->SetColor(
        rep2d->GetArc()->GetProperty()->GetColor());
      rep2d->GetRay2()->GetProperty()->SetLineWidth(
        rep2d->GetArc()->GetProperty()->GetLineWidth());

      // Change the size of the arrow heads
      rep2d->GetRay1()->SetArrowLength( 0.01 );
      rep2d->GetRay1()->SetArrowWidth( 0.0075 );

      rep2d->GetRay2()->SetArrowLength( 0.01 );
      rep2d->GetRay2()->SetArrowWidth( 0.0075 );

      }
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::ContourWidgetIsSupported()
{
  if (vtkKWImageWidget::SafeDownCast(this->RenderWidget) 
      
      // UNCOMMENT THIS LINE IF YOU WANT TO ALLOW CONTOURS TO BE DRAWN ON THE
      // VOLUME WIDGET
      
       || vtkKWVolumeWidget::SafeDownCast(this->RenderWidget)
      )
    {
    return 1;
    }
  return 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddContourWidget()
{
  vtkKWContourWidget *interactor = vtkKWContourWidget::New();
  int res = this->AddContourWidget(interactor);
  interactor->Delete();
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddContourWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  vtkKWContourWidget *contour_interactor = 
    vtkKWContourWidget::SafeDownCast(interactor);
  if (res)
    {
    interactor->SetDefaultRenderer(this->RenderWidget->GetRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetRenderer());
    if (vtkKWImageWidget::SafeDownCast(this->RenderWidget))
      {
      this->AddImageWidgetContourRepresentation(contour_interactor);
      }
    else if (vtkKWVolumeWidget::SafeDownCast(this->RenderWidget))
      {
      this->AddVolumeWidgetContourRepresentation(contour_interactor);
      }
    interactor->SetEnabled(1);
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::Label2DWidgetIsSupported()
{
  if(vtkKWLightboxWidget::SafeDownCast(this->RenderWidget))
    {
    return 0;
    }

  return 1;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddLabel2DWidget()
{
  vtkKWCaptionWidget *interactor = vtkKWCaptionWidget::New();
  vtkKWVolumeWidget* vw = vtkKWVolumeWidget::SafeDownCast(
    this->RenderWidget);
  if(vw)
    {
    vtkVolume* vol = vw->GetVolume();
    if(vol && vol->GetVisibility())
      {
      interactor->UseAnchorPointOpacityOn();
      interactor->SetPickingVolume(vol);
      }
    }

  int res = this->AddLabel2DWidget(interactor);
  interactor->Delete();
  
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddLabel2DWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  if (res)
    {
    interactor->SetDefaultRenderer(this->RenderWidget->GetRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetRenderer());
    vtkKWCaptionWidget *caption_widget = 
      vtkKWCaptionWidget::SafeDownCast(interactor);
    if (caption_widget)
      {
      caption_widget->GetHandleWidget()->SetDefaultRenderer(
        this->RenderWidget->GetOverlayRenderer());
      caption_widget->GetHandleWidget()->SetCurrentRenderer(
        this->RenderWidget->GetOverlayRenderer());
      caption_widget->SelectableOff();
      }
    interactor->CreateDefaultRepresentation();

    vtkCaptionRepresentation *rep2d = 
      vtkCaptionRepresentation::SafeDownCast(
      interactor->GetRepresentation());

    if (rep2d)
      {
      vtkCaptionActor2D* actor = rep2d->GetCaptionActor2D();
      vtkKWVolumeWidget* vw = vtkKWVolumeWidget::SafeDownCast(
        this->RenderWidget);
      if(vw)
        {
        actor->ThreeDimensionalLeaderOn();
        }
      else
        {
        actor->ThreeDimensionalLeaderOff();
        }

      actor->GetProperty()->SetColor(1.0, 0.0, 0.0);

      this->RenderWidget->RenderStateOff();
      interactor->EnabledOn();
      this->RenderWidget->RenderStateOn();
      //interactor->Render();
      }
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::HandleWidgetIsSupported()
{
  // Supported on the volume and image widgets only.
  vtkKWImageWidget *iw = vtkKWImageWidget::SafeDownCast(this->RenderWidget);
  vtkKWProbeImageWidget *pw = vtkKWProbeImageWidget::SafeDownCast(this->RenderWidget);
  vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast(this->RenderWidget);

  return (!pw && (iw || vw)) ? 1 : 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddHandleWidget()
{
  vtkVVHandleWidget *interactor = vtkVVHandleWidget::New();
  int res = this->AddHandleWidget(interactor);
  interactor->Delete();
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddHandleWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  if (res)
    {
    // Use the overlay renderer so that we can display a handle widget even
    // when it is technically obscured by a 2D slice
    interactor->SetDefaultRenderer(this->RenderWidget->GetOverlayRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetOverlayRenderer());
    vtkPointHandleRepresentation3D * rep = NULL;

    // Different representation for the image and the volume widgets. The 
    // handles are not allowed on the oblique probe. Too difficult to 
    // manage their exact location there. 

    vtkKWImageWidget *iw = 
        vtkKWImageWidget::SafeDownCast(this->RenderWidget);
    vtkKWVolumeWidget *vw = 
        vtkKWVolumeWidget::SafeDownCast(this->RenderWidget);
    if (iw)
      {
      vtkImageActorPointHandleRepresentation3D *rep_ia = 
        vtkImageActorPointHandleRepresentation3D::New();
      rep_ia->SetImageActor(iw->GetImage());
      rep = rep_ia;
      }
    else if (vw)
      {
      rep = vtkPointHandleRepresentation3D::New();
      }

    vtkVVHandleWidget * hw = vtkVVHandleWidget::SafeDownCast(interactor);
    hw->SetSelectionFrame(this);
    hw->SetRepresentation(rep);

    // Initialize position to undefined state until the user places us 
    // somewhere on the render window.
    // double worldPos[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX};
    //rep->SetWorldPosition( worldPos );

    interactor->SetEnabled(1);
    
    // Set some default properties.
    rep->GetProperty()->SetColor(1.0, 0.2, 0);
    rep->GetProperty()->SetLineWidth(1.0);
    rep->GetSelectedProperty()->SetLineWidth(1.0);

    rep->Delete();  
    }
  return res;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::PaintbrushWidgetIsSupported()
{
  // Supported in the 2D image widgets only.
  vtkKWImageWidget *iw = vtkKWImageWidget::SafeDownCast(this->RenderWidget);
  vtkKWProbeImageWidget *pw = vtkKWProbeImageWidget::SafeDownCast(
    this->RenderWidget);
  return (!pw && iw) ? 1 : 0;
}

//----------------------------------------------------------------------------
vtkAbstractWidget* vtkVVSelectionFrame::AddPaintbrushWidget()
{
  vtkKWEPaintbrushWidget *interactor = vtkKWEPaintbrushWidget::New();

  // To be lower than all other widgets since the active region is the whole 
  // viewport itself. All other widgets have discret active regions (say 
  // handles, at the end of a bidimensional widget), the paintbrush widget on
  // the other hand is active everywhere, all the time. Having one of them
  // will block all interactions with other widgets, so let's fix that by
  // changing the paintbrush widgets priority.
  interactor->SetPriority(0.4); 

  // Use the a custom callback mapper instead of the default one, (this 
  // supports fewer bindings and allows us to customize bindings for VolView)
  vtkKWELightPaintbrushWidgetCallbackMapper *bindings
    = vtkKWELightPaintbrushWidgetCallbackMapper::New();
  interactor->SetCallbackMapper(bindings);
  bindings->Delete();  
  
  int res = this->AddPaintbrushWidget(interactor);
  interactor->Delete();
  return res ? interactor : NULL;
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::AddPaintbrushWidget(vtkAbstractWidget *interactor)
{
  int res = this->AddInteractorWidget(interactor);
  if (res)
    {
    interactor->SetDefaultRenderer(this->RenderWidget->GetRenderer());
    interactor->SetCurrentRenderer(this->RenderWidget->GetRenderer());

    vtkKWEPaintbrushRepresentation2D *rep2d = 
      vtkKWEPaintbrushRepresentation2D::SafeDownCast(
        interactor->GetRepresentation());
    if (rep2d)
      {
      vtkImageActorPointPlacer *placer = vtkImageActorPointPlacer::New();
      rep2d->SetShapePlacer(placer);
      placer->Delete();
      vtkKWImageWidget *iw = vtkKWImageWidget::SafeDownCast(this->RenderWidget);
      if (iw)
        {
        rep2d->SetImageActor(iw->GetImage());
        vtkImageData *input = iw->GetInput();
        rep2d->SetImageData(input);
        vtkKWEPaintbrushShape *shape = 
          rep2d->GetPaintbrushOperation()->GetPaintbrushShape();
        shape->SetSpacing(input->GetSpacing());
        shape->SetOrigin(input->GetOrigin());
        }
      vtkKWEPaintbrushDrawing *drawing = rep2d->GetPaintbrushDrawing();
      drawing->SetRepresentationToLabel();
      // This will allocate our canvas based on the size of the overlay image
      // that was set on the WidgetRepresentation.
      drawing->InitializeData();
      drawing->RemoveAllItems(); 
      vtkKWEPaintbrushLabelData *ldata = 
        vtkKWEPaintbrushLabelData::SafeDownCast(drawing->GetPaintbrushData());

      vtkKWEPaintbrushSketch *sketch1 = vtkKWEPaintbrushSketch::New();
      drawing->AddItem(sketch1);
      sketch1->SetLabel(1);
      sketch1->GetPaintbrushProperty()->SetColor(
        vtkVVPaintbrushWidgetEditor::GetBasicColor(sketch1->GetLabel() - 1));
      sketch1->Initialize(ldata);
      sketch1->Delete();

      vtkKWEPaintbrushSketch *sketch2 = vtkKWEPaintbrushSketch::New();
      drawing->AddItem(sketch2);
      sketch2->SetLabel(2);
      sketch2->GetPaintbrushProperty()->SetColor(
        vtkVVPaintbrushWidgetEditor::GetBasicColor(sketch2->GetLabel() - 1));
      sketch2->Initialize(ldata);
      sketch2->Delete();
      }
    interactor->SetEnabled(1);
    }
  return res;
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::AddImageWidgetContourRepresentation(
    vtkKWContourWidget * interactor)
{
 vtkOrientedGlyphContourRepresentation *rep =
    vtkOrientedGlyphContourRepresentation::New();
  
  rep->GetProperty()->SetColor(0,1,0);
  // control the lines width of the contour widget:
  rep->GetLinesProperty()->SetLineWidth(2.0);
  rep->GetProperty()->SetPointSize(5);
  interactor->SetRepresentation(rep);

  rep->GetLinesProperty()->SetColor(1.0, 1.0, 0.0);
  
  vtkKWImageWidget *w = 
    vtkKWImageWidget::SafeDownCast(this->RenderWidget);
  if (w)
    {
    vtkImageActorPointPlacer *placer = vtkImageActorPointPlacer::New();
    rep->SetPointPlacer(placer);
    placer->SetImageActor(w->GetImage());
    placer->Delete();
    }
  rep->Delete();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::AddVolumeWidgetContourRepresentation(
    vtkKWContourWidget * interactor)
{
 vtkOrientedGlyphFocalPlaneContourRepresentation *rep =
    vtkOrientedGlyphFocalPlaneContourRepresentation::New();
  
  rep->GetProperty()->SetColor(0,1,0);
  // control the lines width of the contour widget:
  rep->GetLinesProperty()->SetLineWidth(2.0);
  rep->GetProperty()->SetPointSize(5);
  interactor->SetRepresentation(rep);

  rep->GetLinesProperty()->SetColor(1.0, 1.0, 0.0);
  rep->Delete();
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::GoToInteractorWidget(vtkAbstractWidget *widget)
{
  vtkKW2DRenderWidget *rw2d = vtkKW2DRenderWidget::SafeDownCast(
    this->GetRenderWidget());
  if (widget && rw2d && rw2d->GetHasSliceControl())
    {
    vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
      this->Internals->FindSlot(widget);
    if ((*it).OriginalSlice >= 0)
      {
      rw2d->SetSlice((*it).OriginalSlice);
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::SetInteractorWidgetLock(
  vtkAbstractWidget *widget, int val)
{
  // Invalid, or no change? Bye

  if (!widget || val < 0 || this->GetInteractorWidgetLock(widget) == val)
    {
    return;
    }

  // Special case for the paintbrush widget
  
  vtkKWEPaintbrushWidget *paintbrush_widget =
    vtkKWEPaintbrushWidget::SafeDownCast(widget);
  if (paintbrush_widget)
    {
    if (val)
      {
      paintbrush_widget->SetWidgetStateToDisabled();
      }
    else
      {
      paintbrush_widget->SetWidgetStateToEnabled();
      }
    return;
    }

  // Special case for the handle widgets, which not only keeps its own
  // variable for a "locked" state, but synchronizes all the handles in
  // other selection frame automatically.

  vtkVVHandleWidget *handle_widget = 
    vtkVVHandleWidget::SafeDownCast(widget);
  if (handle_widget)
    {
    handle_widget->SetDisplayForAllSlices(val ? 0 : 1);
    return;
    }

  // Look for the widget, change its lock, and update its enabled state

  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(widget);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    (*it).Lock = val;
    this->UpdateInteractorWidgetEnabledState(
      (*it).Widget, (*it).Visibility, (*it).Lock, (*it).OriginalSlice);
    }
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::GetInteractorWidgetLock(vtkAbstractWidget *widget)
{
  if (!widget)
    {
    return -1;
    }

  // Don't bother if not on a 2D view (for now), lock to a slice 
  // would not supported otherwise

  vtkKW2DRenderWidget *rw2d = vtkKW2DRenderWidget::SafeDownCast(
    this->GetRenderWidget());
  if (!rw2d || !rw2d->GetHasSliceControl())
    {
    return -1;
    }

  // Special case for the paintbrush widget
  
  vtkKWEPaintbrushWidget *paintbrush_widget =
    vtkKWEPaintbrushWidget::SafeDownCast(widget);
  if (paintbrush_widget)
    {
    return paintbrush_widget->GetWidgetState() == vtkKWEPaintbrushWidget::PaintbrushDisabled ? 1 : 0;
    }

  // Special case for the handle widgets, which not only keeps its own
  // variable for a "locked" state, but synchronizes all the handles in
  // other selection frame automatically.
  
  vtkVVHandleWidget *handle_widget = 
    vtkVVHandleWidget::SafeDownCast(widget);
  if (handle_widget)
    {
    return handle_widget->GetDisplayForAllSlices() ? 0 : 1;
    }

  // Otherwise look for the widget

  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(widget);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    return (*it).Lock;
    }
  
  return -1;
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::SetInteractorWidgetOriginalSlice(
  vtkAbstractWidget *widget, int val)
{
  // Invalid, or no change? Bye

  if (!widget || val < 0 || 
      this->GetInteractorWidgetOriginalSlice(widget) == val)
    {
    return;
    }

  // Look for the widget, change its slice, and update its enabled state

  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(widget);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    (*it).OriginalSlice = val;
    this->UpdateInteractorWidgetEnabledState(
      (*it).Widget, (*it).Visibility, (*it).Lock, (*it).OriginalSlice);
    }
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::GetInteractorWidgetOriginalSlice(
  vtkAbstractWidget *widget)
{
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(widget);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    return (*it).OriginalSlice;
    }
  
  return 0;
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::SetInteractorWidgetVisibility(
  vtkAbstractWidget *widget, int val)
{
  // Invalid, or no change? Bye

  if (!widget || val < 0 || this->GetInteractorWidgetVisibility(widget) == val)
    {
    return;
    }

  // Look for the widget, change its visibility, and update its enabled state

  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(widget);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    (*it).Visibility = val;
    this->UpdateInteractorWidgetEnabledState(
      (*it).Widget, (*it).Visibility, (*it).Lock, (*it).OriginalSlice);
    }
}

//----------------------------------------------------------------------------
int vtkVVSelectionFrame::GetInteractorWidgetVisibility(
  vtkAbstractWidget *widget)
{
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->FindSlot(widget);
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  if (it != end)
    {
    return (*it).Visibility;
    }
  
  return 0;
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::UpdateInteractorWidgetEnabledState(
  vtkAbstractWidget *widget, int visibility, int lock, int orig_slice)
{
  vtkKW2DRenderWidget *rw2d = vtkKW2DRenderWidget::SafeDownCast(
    this->GetRenderWidget());

  // If we are on a render widget that allows slices to be controlled
  // and the widget supports locking to a specific slice, update
  // the visibility so that we hide the widget if we are not on the same
  // slice and it is locked.

  if (rw2d && rw2d->GetHasSliceControl() && lock == 1 && orig_slice >= 0)
    {
    visibility &= ((rw2d->GetSlice() == orig_slice) ? 1 : 0);
    }
  
  vtkKWEPaintbrushWidget *paintbrush_widget =
    vtkKWEPaintbrushWidget::SafeDownCast(widget);
  if (widget->GetEnabled() != visibility)
    {
    if (paintbrush_widget)
      {
      paintbrush_widget->GetWidgetGroup()->SetEnabled(visibility);
      paintbrush_widget->GetWidgetGroup()->Render();
      }
    else
      {
      widget->SetEnabled(visibility);
      if (rw2d)
        {
        rw2d->Render();
        }
      }
    }
  if (widget->GetProcessEvents() != visibility)
    {
    if (paintbrush_widget)
      {
      // Not sure what to do here
      }
    else
      {
      widget->SetProcessEvents(visibility);
      }
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::UpdateInteractorWidgetsEnabledState()
{
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator it = 
    this->Internals->InteractorWidgetPool.begin();
  vtkVVSelectionFrameInternals::InteractorWidgetPoolIterator end = 
    this->Internals->InteractorWidgetPool.end();
  for (; it != end; ++it)
    {
    this->UpdateInteractorWidgetEnabledState(
      (*it).Widget, (*it).Visibility, (*it).Lock, (*it).OriginalSlice);
    }
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::AddCallbackCommandObservers()
{
  this->Superclass::AddCallbackCommandObservers();

  this->AddCallbackCommandObserver(
    this->RenderWidget, vtkKWEvent::FocusInEvent);

  this->AddCallbackCommandObserver(
    this->RenderWidget, vtkKW2DRenderWidget::UpdateDisplayExtentEvent);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::RemoveCallbackCommandObservers()
{
  this->Superclass::RemoveCallbackCommandObservers();

  this->RemoveCallbackCommandObserver(
    this->RenderWidget, vtkKWEvent::FocusInEvent);

  this->RemoveCallbackCommandObserver(
    this->RenderWidget, vtkKW2DRenderWidget::UpdateDisplayExtentEvent);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::ProcessCallbackCommandEvents(vtkObject *caller,
                                                       unsigned long event,
                                                       void *calldata)
{
  if (caller == this->GetRenderWidget())
    {
    switch (event)
      {
      case vtkKWEvent::FocusInEvent:
        this->SelectCallback();
        break;

      case vtkKW2DRenderWidget::UpdateDisplayExtentEvent:
        // If we change slice for example, we need to hide those widgets
        // that are locked to a specific slice
        this->UpdateInteractorWidgetsEnabledState();
        break;
      }
    }

  // At the end of an interactor widget creation, a few things need to be
  // done.

  if (event == vtkCommand::EndInteractionEvent)
    {
    // First synchronize the visibility flag with the Enabled state
    // (later on, the Enabled state will be a combination of the
    // visibility flag and the lock flag, both stored internally at
    // the selection frame level, since widgets should not be bothered
    // with that)

    vtkAbstractWidget *widget = 
      vtkAbstractWidget::SafeDownCast(caller);
    this->SetInteractorWidgetVisibility(widget, widget->GetEnabled());

    // Second, if the render widget this interactor widget was created on
    // supports slice control (changing slice), we need to remember
    // on which slice the widget was created.

    vtkKW2DRenderWidget *rw2d = vtkKW2DRenderWidget::SafeDownCast(
      this->GetRenderWidget());
    if (rw2d && rw2d->GetHasSliceControl())
      {
      this->SetInteractorWidgetOriginalSlice(widget, rw2d->GetSlice());
      }
    }

  this->Superclass::ProcessCallbackCommandEvents(caller, event, calldata);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::UpdateEnableState()
{
  this->Superclass::UpdateEnableState();

  this->PropagateEnableState(this->RenderWidget);
}

//----------------------------------------------------------------------------
void vtkVVSelectionFrame::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  
  os << indent << "RenderWidget: " << this->RenderWidget << endl;
  os << indent << "DataItem: " << this->DataItem << endl;
  os << indent << "BindRenderWidgetOnlyWhenSelected: " << (this->BindRenderWidgetOnlyWhenSelected ? "On" : "Off") << endl;
}

