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

  Program:   ParaView
  Module:    vtkPVBoxWidget.cxx

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkPVBoxWidget.h"

#include "vtkArrayMap.txx"
#include "vtkKWEntry.h"
#include "vtkKWEvent.h"
#include "vtkKWFrame.h"
#include "vtkKWFrame.h"
#include "vtkKWLabel.h"
#include "vtkKWPushButton.h"
#include "vtkKWScaleWithEntry.h"
#include "vtkKWThumbWheel.h"
#include "vtkKWView.h"
#include "vtkMatrix4x4.h" 
#include "vtkObjectFactory.h"
#include "vtkPVApplication.h"
#include "vtkPVDataInformation.h"
#include "vtkPVInputMenu.h"
#include "vtkPVSource.h"
#include "vtkPVVectorEntry.h"
#include "vtkPVXMLElement.h"
#include "vtkSMBoxWidgetProxy.h"
#include "vtkSMDoubleVectorProperty.h"
#include "vtkSMProxy.h"
#include "vtkSMProxyManager.h"
#include "vtkSMProxyProperty.h"
#include "vtkSMSourceProxy.h"
#include "vtkCommand.h"
#include "vtkPVWindow.h"
#include "vtkPVTraceHelper.h"

vtkStandardNewMacro(vtkPVBoxWidget);
vtkCxxRevisionMacro(vtkPVBoxWidget, "1.69");

vtkCxxSetObjectMacro(vtkPVBoxWidget, InputMenu, vtkPVInputMenu);

//----------------------------------------------------------------------------
vtkPVBoxWidget::vtkPVBoxWidget()
{
  this->InputMenu = 0;
  this->ControlFrame = vtkKWFrame::New();
  this->TranslateLabel = vtkKWLabel::New();
  this->ScaleLabel = vtkKWLabel::New();
  this->OrientationLabel = vtkKWLabel::New();

  int cc;
  for ( cc = 0; cc < 3; cc ++ )
    {
    this->TranslateThumbWheel[cc] = vtkKWThumbWheel::New();
    this->ScaleThumbWheel[cc] = vtkKWThumbWheel::New();
    this->OrientationScale[cc] = vtkKWScaleWithEntry::New();
    }

  this->BoxProxy = 0; // This is the implicit function proxy
  this->BoxTransformProxy = 0;

  this->UseInputBounds = true;
  
  this->SetWidgetProxyXMLName("BoxWidgetProxy");
}

//----------------------------------------------------------------------------
vtkPVBoxWidget::~vtkPVBoxWidget()
{
  this->UnsetPropertyObservers();
  this->SetInputMenu(NULL);
  this->ControlFrame->Delete();
  this->TranslateLabel->Delete();
  this->ScaleLabel->Delete();
  this->OrientationLabel->Delete();

  int cc;
  for ( cc = 0; cc < 3; cc ++ )
    {
    this->TranslateThumbWheel[cc]->Delete();
    this->ScaleThumbWheel[cc]->Delete();
    this->OrientationScale[cc]->Delete();
    }
  if(this->BoxProxy)
    {
    vtkSMProxyManager* proxyM = vtkSMObject::GetProxyManager();
    const char* proxyName 
      = proxyM->GetProxyName("implicit_functions", this->BoxProxy);
    if (proxyName)
      {
      proxyM->UnRegisterProxy("implicit_functions", proxyName);
      }
    proxyName = proxyM->GetProxyName("animateable", this->BoxProxy);
    if (proxyName)
      {
      proxyM->UnRegisterProxy("animateable", proxyName);
      }
    this->BoxProxy->Delete();
    this->BoxProxy = 0;
    }

  if(this->BoxTransformProxy)
    {
    vtkSMProxyManager* proxyM = vtkSMObject::GetProxyManager();
    const char* proxyName 
      = proxyM->GetProxyName("transforms", this->BoxTransformProxy);
    if (proxyName)
      {
      proxyM->UnRegisterProxy("transforms", proxyName);
      }
    proxyName = proxyM->GetProxyName("animateable", this->BoxTransformProxy);
    if (proxyName)
      {
      proxyM->UnRegisterProxy("animateable", proxyName);
      }
    this->BoxTransformProxy->Delete();
    this->BoxTransformProxy = 0;
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::Initialize()
{
  this->PlaceWidget();

  this->Accept();
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::ResetInternal()
{
  if ( !this->ModifiedFlag )
    {
    return;
    }
  const char* properties[] = {"Scale","Position","Rotation", 0 };
  int i;
  for (i=0;properties[i]; i++)
    {
    vtkSMDoubleVectorProperty* sdvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->BoxTransformProxy->GetProperty(properties[i]));
    vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->WidgetProxy->GetProperty(properties[i]));
    if (sdvp && dvp)
      {
      dvp->SetElements(sdvp->GetElements());
      }
    else
      {
      vtkErrorMacro("BoxTransformProxy or WidgetProxy has missing property " << properties[i]);
      }
    }
  
  this->WidgetProxy->UpdateVTKObjects(); 
  this->Superclass::ResetInternal();
}


//----------------------------------------------------------------------------
void vtkPVBoxWidget::PlaceWidget(double xMin, double xMax, double yMin, double yMax, double zMin, double zMax)
{
  double bds[6];

  bds[0] = xMin;
  bds[1] = xMax;
  bds[2] = yMin;
  bds[3] = yMax;
  bds[4] = zMin;
  bds[5] = zMax;

  this->PlaceWidget(bds);

  // when this method is called, we no longer want to update when input changes
  this->UseInputBounds = false;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::PlaceWidget(double bds[6])
{
  this->Superclass::PlaceWidget(bds);
  if (this->BoxProxy)
    {
    vtkSMDoubleVectorProperty *dvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->BoxProxy->GetProperty("Bounds"));
    if (dvp)
      {
      dvp->SetElements(bds);
      }
    this->BoxProxy->UpdateVTKObjects(); 
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::Accept()
{
  int modFlag = this->GetModifiedFlag();
  
  double values[3][3];
  this->WidgetProxy->UpdatePropertyInformation();
  this->GetScaleInternal(values[0]);
  this->GetPositionInternal(values[1]);
  this->GetRotationInternal(values[2]);

  const char* properties[] = { "Scale","Position","Rotation", 0 };
  int i;
  for (i=0; properties[i]; i++)
    {
    vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->BoxProxy->GetProperty(properties[i]));
    if (dvp)
      {
      dvp->SetElements(values[i]);
      }
    else
      {
      vtkErrorMacro("BoxProxy does not have "<< properties[i] <<" property");
      }  
    dvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->BoxTransformProxy->GetProperty(properties[i]));
    if (dvp)
      {
      dvp->SetElements(values[i]);
      }
    else
      {
      vtkErrorMacro("BoxTransformProxy does not have "<< properties[i] <<" property");
      }
    }
  this->BoxProxy->UpdateVTKObjects();
  this->BoxTransformProxy->UpdateVTKObjects();
  // 3DWidgets need to explictly call UpdateAnimationInterface on accept
  // since the animatable proxies might have been registered/unregistered
  // which needs to be updated in the Animation interface.
  this->GetPVApplication()->GetMainWindow()->UpdateAnimationInterface();
  this->ModifiedFlag = 0;
  // I put this after the accept internal, because
  // vtkPVGroupWidget inactivates and builds an input list ...
  // Putting this here simplifies subclasses AcceptInternal methods.
  if (modFlag)
    {
    vtkPVApplication *pvApp = this->GetPVApplication();
    ofstream* file = pvApp->GetTraceFile();
    if (file)
      {
      this->Trace(file);
      }
    }

}

//---------------------------------------------------------------------------
void vtkPVBoxWidget::Trace(ofstream *file)
{
  if ( ! this->GetTraceHelper()->Initialize(file))
    {
    return;
    }

  // Called to save the state of the widget's visibility
  this->Superclass::Trace(file);

  // If the bounds have not been specified explicitly, widget will be initialized using scale, rotate, position parameters
  if(this->UseInputBounds)
    {
    this->GetRotationFromGUI();
    this->GetScaleFromGUI();
    this->GetPositionFromGUI();

    *file << "$kw(" << this->GetTclName() << ") SetScale "
      << this->ScaleGUI[0] << " "
      << this->ScaleGUI[1] << " "
      << this->ScaleGUI[2] << endl;
    *file << "$kw(" << this->GetTclName() << ") SetTranslate "
      << this->PositionGUI[0] << " "
      << this->PositionGUI[1] << " "
      << this->PositionGUI[2] << endl;
    if ( this->RotationGUI[0] < 0 ) { this->RotationGUI[0] += 360; }
    if ( this->RotationGUI[1] < 0 ) { this->RotationGUI[1] += 360; }
    if ( this->RotationGUI[2] < 0 ) { this->RotationGUI[2] += 360; }
    *file << "$kw(" << this->GetTclName() << ") SetOrientation "
      << this->RotationGUI[0] << " "
      << this->RotationGUI[1] << " "
      << this->RotationGUI[2] << endl;
    }
  else if(this->BoxProxy)
    {
    vtkSMDoubleVectorProperty *dvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->BoxProxy->GetProperty("Bounds"));
    if (dvp)
      {
      *file << "$kw(" << this->GetTclName() << ") PlaceWidget "
          << dvp->GetElement(0) << " "
          << dvp->GetElement(1) << " "
          << dvp->GetElement(2) << " "
          << dvp->GetElement(3) << " "
          << dvp->GetElement(4) << " "
          << dvp->GetElement(5) << endl;
      }
    }

  /*
  for ( cc = 0; cc < 3; cc ++ )
  {
  val[cc] = atof( this->CenterEntry[cc]->GetValue() );
  }
   *file << "$kw(" << this->GetTclName() << ") SetCenter "
   << val[0] << " " << val[1] << " " << val[2] << endl;

   rad = atof(this->RadiusEntry->GetValue());
   this->GetTraceHelper()->AddEntry("$kw(%s) SetRadius %f", 
   this->GetTclName(), rad);
   *file << "$kw(" << this->GetTclName() << ") SetRadius "
   << rad << endl;
   */
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SaveInBatchScript(ofstream *file)
{
  this->WidgetProxy->SaveInBatchScript(file);
  
  *file << endl;
  int i;
  if (this->BoxTransformProxy)
    {
    const char* boxTransformID = this->BoxTransformProxy->GetSelfIDAsString();
    *file << "set pvTemp" << boxTransformID
      << " [$proxyManager NewProxy transforms Transform2]"
      << endl;
    *file << "  $proxyManager RegisterProxy transforms pvTemp" << boxTransformID
      << " $pvTemp" << boxTransformID << endl;
    *file << "  $pvTemp" << boxTransformID << " UnRegister {}" << endl;

    //NOw, set the properties of the BoxTransformProxy
    const char *properties[] = { "Rotation", "Scale", "Position" , 0};
    for (i=0; properties[i] != 0; i++)
      {
      vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast(
        this->BoxProxy->GetProperty(properties[i]));
      if (dvp)
        {
        *file << "  [$pvTemp" << boxTransformID 
              << " GetProperty " << properties[i] 
              << "] SetElement 0 " << dvp->GetElement(0) << endl;
        *file << "  [$pvTemp" << boxTransformID 
              << " GetProperty " << properties[i] 
              << "] SetElement 1 " << dvp->GetElement(1) << endl;
        *file << "  [$pvTemp" << boxTransformID 
              << " GetProperty " << properties[i] 
              << "] SetElement 2 " << dvp->GetElement(2) << endl;
        }
      }
    *file << "  $pvTemp" << boxTransformID
      << " UpdateVTKObjects"  << endl;
    *file << endl;
    }

  if (this->BoxProxy)
    {
    const char* boxID = this->BoxProxy->GetSelfIDAsString();
    *file << "set pvTemp" << boxID
      << " [$proxyManager NewProxy implicit_functions Box]" << endl;
    *file << "  $proxyManager RegisterProxy implicit_functions pvTemp" << boxID
      << " $pvTemp" << boxID << endl;
    *file << "  $pvTemp" << boxID << " UnRegister {}" << endl;

    //Now, set the properties of the BoxProxy
    vtkSMDoubleVectorProperty *dvp = vtkSMDoubleVectorProperty::SafeDownCast(
      this->BoxProxy->GetProperty("Bounds"));
    if (dvp)
      {
      for( i=0;i<6;i++)
        {
        *file << "  [$pvTemp" << boxID << " GetProperty Bounds] SetElement " 
          << i << " "  << dvp->GetElement(i) << endl;
        }
      }
    const char *properties[] = { "Rotation", "Scale", "Position" , 0};
    for (i=0; properties[i] != 0; i++)
      {
      dvp = vtkSMDoubleVectorProperty::SafeDownCast(
        this->BoxProxy->GetProperty(properties[i]));
      if (dvp)
        {
        *file << "  [$pvTemp" << boxID << " GetProperty " << properties[i] 
              << "] SetElement 0 " << dvp->GetElement(0) << endl;
        *file << "  [$pvTemp" << boxID << " GetProperty " << properties[i] 
              << "] SetElement 1 " << dvp->GetElement(1) << endl;
        *file << "  [$pvTemp" << boxID << " GetProperty " << properties[i] 
              << "] SetElement 2 " << dvp->GetElement(2) << endl;
        }
      }
    *file << "  $pvTemp" << boxID << " UpdateVTKObjects" << endl;
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "BoxProxy: " << this->BoxProxy << endl;
  os << indent << "BoxTransformProxy: " << this->BoxTransformProxy << endl;
  os << indent << "InputMenu: " << this->InputMenu << endl;

}

//----------------------------------------------------------------------------
vtkPVWidget* vtkPVBoxWidget::ClonePrototypeInternal(
  vtkPVSource* pvSource,
  vtkArrayMap<vtkPVWidget*, vtkPVWidget*>* map)
{
  vtkPVWidget* pvWidget = 0;

  // Check if a clone of this widget has already been created
  if ( map->GetItem(this, pvWidget) != VTK_OK )
    {
    // If not, create one and add it to the map
    pvWidget = this->NewInstance();
    map->SetItem(this, pvWidget);
    // Now copy all the properties
    this->CopyProperties(pvWidget, pvSource, map);

    vtkPVBoxWidget* bw = vtkPVBoxWidget::SafeDownCast(pvWidget);
    if (!bw)
      {
      vtkErrorMacro("Internal error. Could not downcast pointer.");
      pvWidget->Delete();
      return 0;
      }

    if (this->InputMenu)
      {
      // This will either clone or return a previously cloned
      // object.
      vtkPVInputMenu* im = this->InputMenu->ClonePrototype(pvSource, map);
      bw->SetInputMenu(im);
      im->Delete();
      }
    }
  else
    {
    // Increment the reference count. This is necessary
    // to make the behavior same whether a widget is created
    // or returned from the map. Always call Delete() after
    // cloning.
    pvWidget->Register(this);
    }

  return pvWidget;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::ChildCreate()
{
  if ((this->GetTraceHelper()->GetObjectNameState() == 
       vtkPVTraceHelper::ObjectNameStateUninitialized ||
      this->GetTraceHelper()->GetObjectNameState() == 
       vtkPVTraceHelper::ObjectNameStateDefault) )
    {
    this->GetTraceHelper()->SetObjectName("Box");
    this->GetTraceHelper()->SetObjectNameState(
      vtkPVTraceHelper::ObjectNameStateSelfInitialized);
    }

  this->SetFrameLabel("Box Widget");
  this->ControlFrame->SetParent(this->Frame);
  this->ControlFrame->Create();

  this->TranslateLabel->SetParent(this->ControlFrame);
  this->TranslateLabel->Create();
  this->TranslateLabel->SetText("Translate:");
  this->TranslateLabel->SetBalloonHelpString(
    "Translate the geometry relative to the dataset location.");

  this->ScaleLabel->SetParent(this->ControlFrame);
  this->ScaleLabel->Create();
  this->ScaleLabel->SetText("Scale:");
  this->ScaleLabel->SetBalloonHelpString(
    "Scale the geometry relative to the size of the dataset.");

  this->OrientationLabel->SetParent(this->ControlFrame);
  this->OrientationLabel->Create();
  this->OrientationLabel->SetText("Orientation:");
  this->OrientationLabel->SetBalloonHelpString(
    "Orient the geometry relative to the dataset origin.");

  int cc;
  for ( cc = 0; cc < 3; cc ++ )
    {
    this->TranslateThumbWheel[cc]->SetParent(this->ControlFrame);
    this->TranslateThumbWheel[cc]->PopupModeOn();
    this->TranslateThumbWheel[cc]->SetValue(0.0);
    this->TranslateThumbWheel[cc]->SetResolution(0.001);
    this->TranslateThumbWheel[cc]->Create();
    this->TranslateThumbWheel[cc]->DisplayEntryOn();
    this->TranslateThumbWheel[cc]->DisplayEntryAndLabelOnTopOff();
    this->TranslateThumbWheel[cc]->ExpandEntryOn();
    this->TranslateThumbWheel[cc]->GetEntry()->SetWidth(5);
    this->TranslateThumbWheel[cc]->GetEntry()->AddBinding(
      "<Key>", this, "SetValueChanged");
    //EntryCommand is called on <Return> and <FocusOut>
    this->TranslateThumbWheel[cc]->SetEntryCommand(this, "TranslateCallback");
    //Command is called when the value is changed  
    this->TranslateThumbWheel[cc]->SetCommand(this, "ValueChangedCallback");
    //EndCommand is called when Thumbwheel/Scale motion is stopped
    this->TranslateThumbWheel[cc]->SetEndCommand(this,"TranslateCallback");
    this->TranslateThumbWheel[cc]->SetBalloonHelpString(
      "Translate the geometry relative to the dataset location.");

    this->ScaleThumbWheel[cc]->SetParent(this->ControlFrame);
    this->ScaleThumbWheel[cc]->PopupModeOn();
    this->ScaleThumbWheel[cc]->SetValue(1.0);
    this->ScaleThumbWheel[cc]->SetResolution(0.001);
    this->ScaleThumbWheel[cc]->Create();
    this->ScaleThumbWheel[cc]->DisplayEntryOn();
    this->ScaleThumbWheel[cc]->DisplayEntryAndLabelOnTopOff();
    this->ScaleThumbWheel[cc]->ExpandEntryOn();
    this->ScaleThumbWheel[cc]->GetEntry()->SetWidth(5);
    this->ScaleThumbWheel[cc]->GetEntry()->AddBinding(
      "<Key>", this, "SetValueChanged");
    //EntryCommand is called on <Return> and <FocusOut>
    this->ScaleThumbWheel[cc]->SetEntryCommand(this, "ScaleCallback");
    this->ScaleThumbWheel[cc]->SetCommand(this, "ValueChangedCallback");
    this->ScaleThumbWheel[cc]->SetEndCommand(this, "ScaleCallback");
    this->ScaleThumbWheel[cc]->SetBalloonHelpString(
      "Scale the geometry relative to the size of the dataset.");

    this->OrientationScale[cc]->SetParent(this->ControlFrame);
    this->OrientationScale[cc]->PopupModeOn();
    this->OrientationScale[cc]->Create();
    this->OrientationScale[cc]->SetRange(0, 360);
    this->OrientationScale[cc]->SetResolution(.001);
    this->OrientationScale[cc]->SetValue(0);
    this->OrientationScale[cc]->ExpandEntryOn();
    this->OrientationScale[cc]->GetEntry()->SetWidth(5);
    this->OrientationScale[cc]->GetEntry()->AddBinding(
      "<Key>", this, "SetValueChanged");
    //EntryCommand is called on <Return> and <FocusOut>
    this->OrientationScale[cc]->SetEntryCommand(this,"OrientationCallback");
    this->OrientationScale[cc]->SetCommand(this, "ValueChangedCallback");
    this->OrientationScale[cc]->SetEndCommand(this, "OrientationCallback");
    this->OrientationScale[cc]->SetBalloonHelpString(
      "Orient the geometry relative to the dataset origin.");

    }
  int button_pady = 1;
  this->Script("grid %s %s %s %s -sticky news -pady %d",
    this->TranslateLabel->GetWidgetName(),
    this->TranslateThumbWheel[0]->GetWidgetName(),
    this->TranslateThumbWheel[1]->GetWidgetName(),
    this->TranslateThumbWheel[2]->GetWidgetName(),
    button_pady);

  this->Script("grid %s -sticky nws",
    this->TranslateLabel->GetWidgetName());

  this->Script("grid %s %s %s %s -sticky news -pady %d",
    this->ScaleLabel->GetWidgetName(),
    this->ScaleThumbWheel[0]->GetWidgetName(),
    this->ScaleThumbWheel[1]->GetWidgetName(),
    this->ScaleThumbWheel[2]->GetWidgetName(),
    button_pady);

  this->Script("grid %s -sticky nws",
    this->ScaleLabel->GetWidgetName());

  this->Script("grid %s %s %s %s -sticky news -pady %d",
    this->OrientationLabel->GetWidgetName(),
    this->OrientationScale[0]->GetWidgetName(),
    this->OrientationScale[1]->GetWidgetName(),
    this->OrientationScale[2]->GetWidgetName(),
    button_pady);

  this->Script("grid %s -sticky nws",
    this->OrientationLabel->GetWidgetName());

  this->Script("grid columnconfigure %s 0 -weight 0", 
    this->ControlFrame->GetWidgetName());
  this->Script("grid columnconfigure %s 1 -weight 2", 
    this->ControlFrame->GetWidgetName());
  this->Script("grid columnconfigure %s 2 -weight 2", 
    this->ControlFrame->GetWidgetName());
  this->Script("grid columnconfigure %s 3 -weight 2", 
    this->ControlFrame->GetWidgetName());

  this->Script("pack %s -fill x -expand t -pady 2",
    this->ControlFrame->GetWidgetName());

  // Initialize the center of the sphere based on the input bounds.
  if (this->PVSource)
    {
    vtkPVSource *input = this->PVSource->GetPVInput(0);
    if (input)
      {
      this->Reset();
      this->ActualPlaceWidget();
      }
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::CreateWidget()
{
  this->Superclass::CreateWidget();

  static int instanceCount = 0;
  vtkSMProxyManager *pm = vtkSMObject::GetProxyManager();
  this->BoxProxy = pm->NewProxy("implicit_functions", "Box");
  ostrstream str1;
  str1 << "vtkPVBoxWidget_Box" << instanceCount << ends;
  pm->RegisterProxy("implicit_functions", str1.str(), this->BoxProxy);
  delete[] str1.str();

  this->BoxTransformProxy = pm->NewProxy("transforms", "Transform2");
  ostrstream str2;
  str2 << "vtkPVBoxWidget_BoxTransform" << instanceCount << ends;
  pm->RegisterProxy("transforms", str2.str(), this->BoxTransformProxy);
  delete[] str2.str();

  this->SetupPropertyObservers();

  // Set up controller properties. Controller properties are set so 
  // that in the SM State, we can have a mapping from the widget to the 
  // controlled implicit function.
  const char* properties[] = { "Rotation", "Scale", "Position", 0 };
  int i;
  for (i=0; properties[i] != 0 ; i++)
    {
    vtkSMProperty* pbox = this->BoxProxy->GetProperty(properties[i]);
    pbox->SetController(this->WidgetProxy, properties[i]);
    vtkSMProperty* ptrans = this->BoxTransformProxy->GetProperty(properties[i]);
    ptrans->SetController(this->WidgetProxy, properties[i]);
    }
  
  
  instanceCount++;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::ScaleCallback(double)
{
  if (!this->ValueChanged)
    {
    return;
    }
  double val[3];
  int cc;
  for ( cc = 0; cc < 3; cc++)
    {
    val[cc] = atof(this->ScaleThumbWheel[cc]->GetEntry()->GetValue());
    }
  this->SetScale(val[0],val[1],val[2]);
  this->Render();
  this->ValueChanged = 0;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::TranslateCallback(double)
{
  if ( !this->ValueChanged )
    {
    return;
    }
  double val[3];
  int cc;
  for ( cc = 0; cc < 3; cc++)
    {
    val[cc] = atof(this->TranslateThumbWheel[cc]->GetEntry()->GetValue());
    }
  this->SetTranslate(val[0],val[1],val[2]);
  this->Render();
  this->ValueChanged = 0;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::ValueChangedCallback(double)
{
  this->SetValueChanged();
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::OrientationCallback(double)
{
  if (!this->ValueChanged)
    {
    return;
    }
  double val[3];
  int cc;
  for ( cc = 0; cc < 3; cc++)
    {
    val[cc] = atof(this->OrientationScale[cc]->GetEntry()->GetValue());
    }
  this->SetOrientation(val[0],val[1],val[2]);
  this->Render();
  this->ValueChanged = 0;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetOrientationInternal(double x, double y, double z)
{
  vtkSMDoubleVectorProperty *dvp = vtkSMDoubleVectorProperty::SafeDownCast(
    this->WidgetProxy->GetProperty("Rotation"));
  if (dvp)
    {
    dvp->SetElements3(x,y,z);
    }
  this->WidgetProxy->UpdateVTKObjects();

  this->OrientationScale[0]->GetEntry()->SetValueAsDouble(x);
  this->OrientationScale[1]->GetEntry()->SetValueAsDouble(y);
  this->OrientationScale[2]->GetEntry()->SetValueAsDouble(z);
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetTranslateInternal(double x, double y, double z)
{
  vtkSMDoubleVectorProperty *dvp = vtkSMDoubleVectorProperty::SafeDownCast(
    this->WidgetProxy->GetProperty("Position"));
  if (dvp)
    {
    dvp->SetElements3(x,y,z);
    }
  this->WidgetProxy->UpdateVTKObjects();

  this->TranslateThumbWheel[0]->GetEntry()->SetValueAsDouble(x);
  this->TranslateThumbWheel[1]->GetEntry()->SetValueAsDouble(y);
  this->TranslateThumbWheel[2]->GetEntry()->SetValueAsDouble(z);
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetScaleInternal(double x, double y, double z)
{
  vtkSMDoubleVectorProperty *dvp = vtkSMDoubleVectorProperty::SafeDownCast(
    this->WidgetProxy->GetProperty("Scale"));
  if(dvp)
    {
    dvp->SetElements3(x,y,z);
    }
  this->WidgetProxy->UpdateVTKObjects();
  
  this->ScaleThumbWheel[0]->GetEntry()->SetValueAsDouble(x);
  this->ScaleThumbWheel[1]->GetEntry()->SetValueAsDouble(y);
  this->ScaleThumbWheel[2]->GetEntry()->SetValueAsDouble(z);
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetOrientation(double px, double py, double pz)
{
  if ( px < 0 ) { px += 360; }
  if ( py < 0 ) { py += 360; }
  if ( pz < 0 ) { pz += 360; }
  this->SetOrientationInternal(px, py, pz);
  this->GetTraceHelper()->AddEntry("$kw(%s) SetOrientation %f %f %f",
    this->GetTclName(), px, py, pz);  
  this->ModifiedCallback();
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetScale(double px, double py, double pz)
{
  this->SetScaleInternal(px, py, pz);
  this->GetTraceHelper()->AddEntry("$kw(%s) SetScale %f %f %f",
    this->GetTclName(), px, py, pz);  
  this->ModifiedCallback();
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetTranslate(double px, double py, double pz)
{
  this->SetTranslateInternal(px, py, pz);
  this->GetTraceHelper()->AddEntry("$kw(%s) SetTranslate %f %f %f",
    this->GetTclName(), px, py, pz);  
  this->ModifiedCallback();
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::GetScaleInternal(double scale[3])
{
 vtkSMDoubleVectorProperty *dvpScale = vtkSMDoubleVectorProperty::SafeDownCast(
    this->WidgetProxy->GetProperty("ScaleInfo")); 
 if (dvpScale)
   {
   scale[0] = dvpScale->GetElement(0);
   scale[1] = dvpScale->GetElement(1);
   scale[2] = dvpScale->GetElement(2);
   }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::GetRotationInternal(double rotation[3])
{
  vtkSMDoubleVectorProperty *dvpRotation = vtkSMDoubleVectorProperty::SafeDownCast(
    this->WidgetProxy->GetProperty("RotationInfo"));
  if (dvpRotation)
    {
    rotation[0] = dvpRotation->GetElement(0);
    rotation[1] = dvpRotation->GetElement(1);
    rotation[2] = dvpRotation->GetElement(2);
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::GetPositionInternal(double position[3])
{
  vtkSMDoubleVectorProperty *dvpPosition = vtkSMDoubleVectorProperty::SafeDownCast(
    this->WidgetProxy->GetProperty("PositionInfo"));
  if (dvpPosition)
    {
    position[0] = dvpPosition->GetElement(0);
    position[1] = dvpPosition->GetElement(1);
    position[2] = dvpPosition->GetElement(2);
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::UpdateFromBox()
{
  this->WidgetProxy->UpdatePropertyInformation();

  double scale[3], position[3], rotation[3];
  this->GetScaleInternal(scale);
  this->GetPositionInternal(position);
  this->GetRotationInternal(rotation);

  this->ScaleThumbWheel[0]->SetValue(scale[0]);
  this->ScaleThumbWheel[1]->SetValue(scale[1]);
  this->ScaleThumbWheel[2]->SetValue(scale[2]);

  this->TranslateThumbWheel[0]->SetValue(position[0]);
  this->TranslateThumbWheel[1]->SetValue(position[1]);
  this->TranslateThumbWheel[2]->SetValue(position[2]);

  double orientation[3];
  orientation[0] = rotation[0];
  orientation[1] = rotation[1];
  orientation[2] = rotation[2];
  if ( orientation[0] < 0 ) { orientation[0] += 360; }
  if ( orientation[1] < 0 ) { orientation[1] += 360; }
  if ( orientation[2] < 0 ) { orientation[2] += 360; }
  this->OrientationScale[0]->SetValue(orientation[0]);
  this->OrientationScale[1]->SetValue(orientation[1]);
  this->OrientationScale[2]->SetValue(orientation[2]);
}

//----------------------------------------------------------------------------
double* vtkPVBoxWidget::GetPositionFromGUI()
{
  this->PositionGUI[0] = this->TranslateThumbWheel[0]->GetValue();
  this->PositionGUI[1] = this->TranslateThumbWheel[1]->GetValue();
  this->PositionGUI[2] = this->TranslateThumbWheel[2]->GetValue();
  return this->PositionGUI;
}

//----------------------------------------------------------------------------
double* vtkPVBoxWidget::GetRotationFromGUI()
{
  this->RotationGUI[0] = this->OrientationScale[0]->GetValue();
  this->RotationGUI[1] = this->OrientationScale[1]->GetValue();
  this->RotationGUI[2] = this->OrientationScale[2]->GetValue();
  return this->RotationGUI;
}

//----------------------------------------------------------------------------
double* vtkPVBoxWidget::GetScaleFromGUI()
{
  this->ScaleGUI[0] = this->ScaleThumbWheel[0]->GetValue();
  this->ScaleGUI[1] = this->ScaleThumbWheel[1]->GetValue();
  this->ScaleGUI[2] = this->ScaleThumbWheel[2]->GetValue();
  return this->ScaleGUI;
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::ExecuteEvent(vtkObject* wdg, unsigned long event, void* p)
{
  if(vtkSM3DWidgetProxy::SafeDownCast(wdg) && event == vtkCommand::WidgetModifiedEvent)
    {//case to update the display values from iVars
    this->UpdateFromBox();
    }
  if (vtkSMProperty::SafeDownCast(wdg))
    {
    switch(event)
      {
    case vtkCommand::ModifiedEvent:
      if (!this->ModifiedFlag)
        {
        // This is the reset to make the widget reflect the state of the properties.
        // If the widget has been modified, we don't reset it. This also helps
        // avoid the reset from being called while 'Accept'ing the values.
        this->ResetInternal();
        }
      break;
      }
    }
  this->Superclass::ExecuteEvent(wdg, event, p);
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::SetupPropertyObservers()
{
  if (!this->BoxTransformProxy || ! this->BoxProxy)
    {
    return;
    }
  const char* properties[] = {"Scale","Position","Rotation", 0 };
  int i;
  for (i=0;properties[i]; i++)
    {
    vtkSMProperty* pT = this->BoxTransformProxy->GetProperty(properties[i]);
    vtkSMProperty* pB = this->BoxProxy->GetProperty(properties[i]);
    
    if (pT)
      {
      this->AddPropertyObservers(pT);
      }
    if (pB)
      {
      this->AddPropertyObservers(pB);
      }
    } 
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::UnsetPropertyObservers()
{
  if (!this->BoxTransformProxy || ! this->BoxProxy)
    {
    return;
    }
  const char* properties[] = {"Scale","Position","Rotation", 0 };
  int i;
  for (i=0;properties[i]; i++)
    {
    vtkSMProperty* pT = this->BoxTransformProxy->GetProperty(properties[i]);
    vtkSMProperty* pB = this->BoxProxy->GetProperty(properties[i]);
    
    if (pT)
      {
      this->RemovePropertyObservers(pT);
      }
    if (pB)
      {
      this->RemovePropertyObservers(pB);
      }
    } 
}

//----------------------------------------------------------------------------
int vtkPVBoxWidget::ReadXMLAttributes(vtkPVXMLElement* element,
  vtkPVXMLPackageParser* parser)
{
  if(!this->Superclass::ReadXMLAttributes(element, parser)) { return 0; }  

  // Setup the InputMenu.
  const char* input_menu = element->GetAttribute("input_menu");
  if(!input_menu)
    {
    vtkErrorMacro("No input_menu attribute.");
    return 0;
    }

  vtkPVXMLElement* ame = element->LookupElement(input_menu);
  if (!ame)
    {
    vtkErrorMacro("Couldn't find InputMenu element " << input_menu);
    return 0;
    }
  vtkPVWidget* w = this->GetPVWidgetFromParser(ame, parser);
  vtkPVInputMenu* imw = vtkPVInputMenu::SafeDownCast(w);
  if(!imw)
    {
    if(w) { w->Delete(); }
    vtkErrorMacro("Couldn't get InputMenu widget " << input_menu);
    return 0;
    }
  imw->AddDependent(this);
  this->SetInputMenu(imw);
  imw->Delete();  

  return 1;
}

//----------------------------------------------------------------------------
vtkSMProxy* vtkPVBoxWidget::GetProxyByName(const char *name)
{
  if (!strcmp(name, "Box"))
    {
    return this->BoxProxy;
    }
  if (!strcmp(name, "BoxTransform"))
    {
    return this->BoxTransformProxy;
    }
  vtkErrorMacro("GetProxyByName called with invalid proxy name: " << name);
  return 0;
}

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


  this->PropagateEnableState(this->InputMenu);
  this->PropagateEnableState(this->ControlFrame);
  this->PropagateEnableState(this->TranslateLabel);
  this->PropagateEnableState(this->ScaleLabel);
  this->PropagateEnableState(this->OrientationLabel);

  int cc;
  for ( cc = 0; cc < 3; cc ++ )
    {
    this->PropagateEnableState(this->TranslateThumbWheel[cc]);
    this->PropagateEnableState(this->ScaleThumbWheel[cc]);
    this->PropagateEnableState(this->OrientationScale[cc]);
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::RegisterAnimateableProxies()
{
  vtkSMProxyManager *pm = vtkSMObject::GetProxyManager();
  if (this->PVSource)
    {
    vtkSMSourceProxy* sproxy = this->PVSource->GetProxy();
    if (sproxy)
      {
      const char* root = pm->GetProxyName("animateable", sproxy);
      if (root && this->BoxProxy)
        {
        ostrstream animName;
        animName << root << ".Box" << ends;
        pm->RegisterProxy("animateable", animName.str(), this->BoxProxy);
        animName.rdbuf()->freeze(0);
        }

      if (root && this->BoxTransformProxy)
        {
        ostrstream animName;
        animName << root << ".BoxTransform" << ends;
        pm->RegisterProxy(
          "animateable", animName.str(), this->BoxTransformProxy);
        animName.rdbuf()->freeze(0);
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkPVBoxWidget::UnregisterAnimateableProxies()
{
  const char* proxyName;
  vtkSMProxyManager *proxyM= vtkSMObject::GetProxyManager();
  if (this->BoxProxy)
    {
    proxyName = proxyM->GetProxyName("animateable", this->BoxProxy);
    if (proxyName)
      {
      proxyM->UnRegisterProxy("animateable", proxyName);
      }
    }
  if (this->BoxTransformProxy)
    {
    proxyName = proxyM->GetProxyName("animateable", this->BoxTransformProxy);
    if (proxyName)
      {
      proxyM->UnRegisterProxy("animateable", proxyName);
      }
    }
}
//----------------------------------------------------------------------------
void vtkPVBoxWidget::Update()
{
  vtkPVSource* input;
  double bds[6];

  this->Superclass::Update();
  //Input bounds may have changed so call place widget
  input = this->InputMenu->GetCurrentValue();
  
  // Do not place widget if we are not using input data bounds to set up widget
  if (input && this->UseInputBounds)
    {
    input->GetDataInformation()->GetBounds(bds);
    this->PlaceWidget(bds);
    }
}
