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

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

#include "vtkActor2D.h"
#include "vtkCallbackCommand.h"
#include "vtkCamera.h"
#include "vtkKWApplication.h"
#include "vtkKWMessageDialog.h"
#include "vtkKWInternationalization.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper2D.h"
#include "vtkProperty2D.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
#include "vtkKWWindowBase.h"

vtkCxxRevisionMacro(vtkKWScaleBarWidget, "$Revision: 1.49 $");
vtkStandardNewMacro(vtkKWScaleBarWidget);

#ifdef KWCommonPro_USE_XML_RW
#include "XML/vtkXMLKWScaleBarWidgetReader.h"
#include "XML/vtkXMLKWScaleBarWidgetWriter.h"
#endif
vtkKWGetXMLReaderWriterObjectsImplementationMacro(vtkKWScaleBarWidget, vtkXMLKWScaleBarWidgetReader, vtkXMLKWScaleBarWidgetWriter);

//----------------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkKWScaleBarWidget, Application, vtkKWApplication);

//----------------------------------------------------------------------------
vtkKWScaleBarWidget::vtkKWScaleBarWidget()
{
  this->EventCallbackCommand->SetCallback(vtkKWScaleBarWidget::ProcessEvents);
  
  this->DistanceUnits = NULL;
  this->CurrentScale = 1.0;

  this->ScaleBar = vtkPolyData::New();
  this->ScaleBar->Allocate(3, 1);
  
  vtkPoints *points = vtkPoints::New();
  points->Allocate(4);
  // bottom line 0,1
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(1.0, 0.0, 0.0);
  // end line points 2,3
  points->InsertNextPoint(0.0, 1.0, 0.0);
  points->InsertNextPoint(1.0, 1.0, 0.0);
  // up to six mid points (two points each)
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(0.0, 0.0, 0.0);
  
  this->ScaleBar->SetPoints(points);
  vtkIdType ptIds[] = {0, 1};
  this->ScaleBar->InsertNextCell(VTK_LINE, 2, ptIds);
  ptIds[1] = 2;
  this->ScaleBar->InsertNextCell(VTK_LINE, 2, ptIds);
  ptIds[0] = 1;
  ptIds[1] = 3;
  this->ScaleBar->InsertNextCell(VTK_LINE, 2, ptIds);
  int i;
  for (i = 0; i < 6; ++i)
    {
    ptIds[0] = i*2+4;
    ptIds[1] = i*2+5;
    this->ScaleBar->InsertNextCell(VTK_LINE, 2, ptIds);
    }
  vtkPolyDataMapper2D *pdm = vtkPolyDataMapper2D::New();
  pdm->SetInput(this->ScaleBar);

  this->Width = .25;

  this->ScaleBarActor = vtkActor2D::New();
  this->ScaleBarActor->SetMapper(pdm);
  this->ScaleBarActor->GetProperty()->SetColor(1, 1, 1);
  this->ScaleBarActor->GetPositionCoordinate()
    ->SetCoordinateSystemToNormalizedViewport();
  this->ScaleBarActor->SetPosition(0.4, 0.05);
  this->ScaleBarActor->SetHeight(0.03);
  this->ScaleBarActor->SetWidth(this->Width);
  
  points->Delete();
  pdm->Delete();
  
  this->Moving = 0;
  this->MouseCursorState = vtkKWScaleBarWidget::Outside;
  
  this->TextActor = vtkTextActor::New();
  this->TextActor->ScaledTextOn();
  this->TextActor->SetNonLinearFontScale(0.7,10);
  this->TextActor->GetTextProperty()->SetJustificationToLeft();
  this->TextActor->GetTextProperty()->SetVerticalJustificationToTop();
  this->TextActor->GetTextProperty()->SetColor(1, 1, 1);
  this->TextActor->GetPositionCoordinate()
    ->SetCoordinateSystemToNormalizedViewport();

  // Default text below the ScaleBarActor towards the right.
  double textActorPos = this->Width +
      this->ScaleBarActor->GetPositionCoordinate()->GetValue()[0];
  this->TextActor->SetPosition(textActorPos+0.01, 0.01);
  this->TextActor->SetHeight(0.03);
  this->TextActor->SetWidth(this->Width);

  this->ScaleSize = 1;
  
  this->Initialized = 0;
  
  this->Priority = 0.55;
  
  this->Application = NULL;
  this->Repositionable = 1;
}

//----------------------------------------------------------------------------
vtkKWScaleBarWidget::~vtkKWScaleBarWidget()
{
  this->SetDistanceUnits(NULL);
  this->ScaleBar->Delete();
  this->ScaleBarActor->Delete();
  this->TextActor->Delete();
  this->SetApplication(NULL);
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::SetEnabled(int enabling)
{
  if ( ! this->Interactor )
    {
    vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget");
    return;
    }
  
  if ( enabling ) 
    {
    vtkDebugMacro(<<"Enabling scale bar widget");
    if ( this->Enabled ) //already enabled, just return
      {
      return;
      }
    
    // make sure the current renderer is set
    if (!this->CurrentRenderer)
      {
      this->SetCurrentRenderer( 
        this->Interactor->FindPokedRenderer(
          this->Interactor->GetLastEventPosition()[0],
          this->Interactor->GetLastEventPosition()[1]));
      if (this->CurrentRenderer == NULL)
        {
        return;
        }
      }
    
    if ( ! this->CurrentRenderer->GetActiveCamera()->GetParallelProjection())
      {
      vtkKWWindowBase *window = NULL;
      if (this->GetApplication())
        {
        window = this->GetApplication()->GetNthWindow(0);
        }
      vtkKWMessageDialog::PopupMessage(
        this->GetApplication(), window, 
        ks_("Scale Bar Widget|Dialog|Scale Bar Error!"),
        k_("The scale bar widget only works when parallel projection is used."),
        vtkKWMessageDialog::ErrorIcon);
      return;
      }
    
    this->Enabled = 1;
    
    // listen for the following events
    vtkRenderWindowInteractor *i = this->Interactor;
    i->AddObserver(vtkCommand::MouseMoveEvent, 
                   this->EventCallbackCommand, this->Priority);
    i->AddObserver(vtkCommand::LeftButtonPressEvent, 
                   this->EventCallbackCommand, this->Priority);
    i->AddObserver(vtkCommand::LeftButtonReleaseEvent, 
                   this->EventCallbackCommand, this->Priority);
    i->AddObserver(vtkCommand::MiddleButtonPressEvent, 
                   this->EventCallbackCommand, this->Priority);
    i->AddObserver(vtkCommand::MiddleButtonReleaseEvent, 
                   this->EventCallbackCommand, this->Priority);
    i->AddObserver(vtkCommand::RightButtonPressEvent, 
                   this->EventCallbackCommand, this->Priority);
    i->AddObserver(vtkCommand::RightButtonReleaseEvent, 
                   this->EventCallbackCommand, this->Priority);

    this->CurrentRenderer->AddObserver(vtkCommand::StartEvent,
                                       this->EventCallbackCommand,
                                       this->Priority);
    
    // Add the scale bar
    this->CurrentRenderer->AddViewProp(this->ScaleBarActor);
    this->CurrentRenderer->AddViewProp(this->TextActor);

    if (!this->Initialized)
      {
      this->Initialized = 1;
      
      this->ScaleBarActor->SetWidth(this->Width);
      this->TextActor->SetWidth(this->Width);
      
      this->OnScaleChange();
      }
    
    this->InvokeEvent(vtkCommand::EnableEvent,NULL);
    }
  else //disabling------------------------------------------
    {
    vtkDebugMacro(<<"Disabling scale bar widget");
    if ( ! this->Enabled ) //already disabled, just return
      {
      return;
      }
    this->Enabled = 0;
    
    // don't listen for events any more
    this->Interactor->RemoveObserver(this->EventCallbackCommand);
    if (this->CurrentRenderer)
      {
      this->CurrentRenderer->RemoveObserver(this->EventCallbackCommand);
      
      // turn off the scale bar
      this->CurrentRenderer->RemoveActor(this->ScaleBarActor);
      this->CurrentRenderer->RemoveActor(this->TextActor);
      }
    
    this->InvokeEvent(vtkCommand::DisableEvent,NULL);
    }
  this->Interactor->Render();
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::ProcessEvents(vtkObject* vtkNotUsed(object),
                                        unsigned long event,
                                        void* clientdata,
                                        void* vtkNotUsed(calldata))
{
  vtkKWScaleBarWidget* self = reinterpret_cast<vtkKWScaleBarWidget *>(clientdata);
  
  switch (event)
    {
    case vtkCommand::LeftButtonPressEvent:
      self->OnButtonPress();
      break;
    case vtkCommand::MouseMoveEvent:
      self->OnMouseMove();
      break;
    case vtkCommand::LeftButtonReleaseEvent:
      self->OnButtonRelease();
      break;
    case vtkCommand::StartEvent:
      self->OnScaleChange();
      break;
    }  
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::OnButtonPress()
{
  if (this->MouseCursorState == vtkKWScaleBarWidget::Outside)
    {
    return;
    }
  
  this->SetMouseCursor(this->MouseCursorState);

  this->StartPosition[0] = this->Interactor->GetEventPosition()[0];
  this->StartPosition[1] = this->Interactor->GetEventPosition()[1];
  
  this->Moving = 1;
  this->EventCallbackCommand->SetAbortFlag(1);
  this->StartInteraction();
  this->InvokeEvent(vtkCommand::StartInteractionEvent, NULL);
  this->Interactor->Render();
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::OnMouseMove()
{
  if (this->Moving)
    {
    switch (this->MouseCursorState)
      {
      case vtkKWScaleBarWidget::Inside:
        if (this->Repositionable)
          {
          this->MoveBar();
          }
        break;
      case vtkKWScaleBarWidget::ResizeLeft:
      case vtkKWScaleBarWidget::ResizeRight:
        this->ResizeBar();
        break;
      }
    this->UpdateCursorIcon();
    this->EventCallbackCommand->SetAbortFlag(1);
    this->InvokeEvent(vtkCommand::InteractionEvent, NULL);
    this->Interactor->Render();
    }
  else
    {
    this->UpdateCursorIcon();
    }
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::OnButtonRelease()
{
  if (this->MouseCursorState == vtkKWScaleBarWidget::Outside)
    {
    return;
    }
  
  this->Moving = 0;
  this->EventCallbackCommand->SetAbortFlag(1);
  this->EndInteraction();
  this->InvokeEvent(vtkCommand::EndInteractionEvent, NULL);
  this->Interactor->Render();
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::OnScaleChange()
{
  if (!this->CurrentRenderer ||
      !this->CurrentRenderer->GetActiveCamera())
    {
    return;
    }
  
  double newScale =
    this->CurrentRenderer->GetActiveCamera()->GetParallelScale();
  int *size = this->CurrentRenderer->GetSize();
  static int prevSize[2] = {0, 0};
  
  if (this->CurrentScale == newScale &&
      prevSize[0] == size[0] && prevSize[1] == size[1])
    {
    return;
    }

  // scale has changed, we must resize the scale and text widgets
  // and modify the value of the text. We need to figure out what
  // a reasonable width should be
  double width = this->ScaleSize*0.5*size[1]/(newScale*size[0]);
  double newScaleSize = this->ScaleSize;
  newScaleSize = 2*newScale/(double)size[1] * this->Width*size[0];
  
  int rootPower = static_cast<int>(floor(log10f(newScaleSize)-1));
  double root = pow(10.0f,rootPower);
  double val = newScaleSize/root;
  int newIntScale = 10;
  if (val >= 15)
    {
    newIntScale = 15;
    }
  if (val >= 20)
    {
    newIntScale = 20;
    }
  if (val >= 30)
    {
    newIntScale = 30;
    }
  if (val >= 50)
    {
    newIntScale = 50;
    }
  if (val >= 70)
    {
    newIntScale = 70;
    }
  width = newIntScale*root*0.5*size[1]/(newScale*size[0]);
  
  this->ScaleSize = width * size[0]/size[1] * 2 * newScale;

  // update the points possibly
  vtkPoints *points = this->ScaleBar->GetPoints();
  points->SetPoint(1, width * size[0], 0, 0);
  points->SetPoint(2, 0, size[1]*0.025, 0);
  points->SetPoint(3, width * size[0], size[1]*0.025, 0);

  // clear old ticks
  int i;
  for (i = 0; i < 6; ++i)
    {
    points->SetPoint(i*2+4,0,0,0);
    points->SetPoint(i*2+5,0,0,0);
    }
  
  // add the small ticks
  switch (newIntScale)
    {
    // add a half and quater ticks
    case 20:
      points->SetPoint(4, width*size[0]*0.5,0,0);
      points->SetPoint(5, width*size[0]*0.5,size[1]*0.015,0);
      points->SetPoint(6, width*size[0]*0.25,0,0);
      points->SetPoint(7, width*size[0]*0.25,size[1]*0.01,0);
      points->SetPoint(8, width*size[0]*0.75,0,0);
      points->SetPoint(9, width*size[0]*0.75,size[1]*0.01,0);
      break;
    case 15:
    case 30:
      // add third ticks
      points->SetPoint(4, width*size[0]*0.33,0,0);
      points->SetPoint(5, width*size[0]*0.33,size[1]*0.015,0);
      points->SetPoint(6, width*size[0]*0.67,0,0);
      points->SetPoint(7, width*size[0]*0.67,size[1]*0.015,0);
      break;
    case 10:
    case 50:
      // add fifth ticks
      points->SetPoint(4, width*size[0]*0.2,0,0);
      points->SetPoint(5, width*size[0]*0.2,size[1]*0.015,0);
      points->SetPoint(6, width*size[0]*0.4,0,0);
      points->SetPoint(7, width*size[0]*0.4,size[1]*0.015,0);
      points->SetPoint(8, width*size[0]*0.6,0,0);
      points->SetPoint(9, width*size[0]*0.6,size[1]*0.015,0);
      points->SetPoint(10, width*size[0]*0.8,0,0);
      points->SetPoint(11, width*size[0]*0.8,size[1]*0.015,0);
      break;
    case 70:
      // add seventh ticks
      points->SetPoint(4, width*size[0]*0.143,0,0);
      points->SetPoint(5, width*size[0]*0.143,size[1]*0.015,0);
      points->SetPoint(6, width*size[0]*0.286,0,0);
      points->SetPoint(7, width*size[0]*0.286,size[1]*0.015,0);
      points->SetPoint(8, width*size[0]*0.428,0,0);
      points->SetPoint(9, width*size[0]*0.428,size[1]*0.015,0);
      points->SetPoint(10, width*size[0]*0.571,0,0);
      points->SetPoint(11, width*size[0]*0.571,size[1]*0.015,0);
      points->SetPoint(12, width*size[0]*0.714,0,0);
      points->SetPoint(13, width*size[0]*0.714,size[1]*0.015,0);
      points->SetPoint(14, width*size[0]*0.857,0,0);
      points->SetPoint(15, width*size[0]*0.857,size[1]*0.015,0);
      break;
    }
  
  this->TextActor->SetPosition(
        this->ScaleBarActor->GetPositionCoordinate()->GetValue()[0]+width+0.01,
        this->ScaleBarActor->GetPositionCoordinate()->GetValue()[1]);
  
  // compute a new ScaleSize, try to keep within the current width
  this->UpdateDistance();
  
  this->CurrentScale = newScale;
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::UpdateCursorIcon()
{
  if ( ! this->Enabled)
    {
    this->SetMouseCursor(vtkKWScaleBarWidget::Outside);
    return;
    }
  
  if (!this->CurrentRenderer)
    {
    return;
    }

  if (this->Moving)
    {
    return;
    }
  
  int x = this->Interactor->GetEventPosition()[0];
  int y = this->Interactor->GetEventPosition()[1];
  
  int *pos1 = this->ScaleBarActor->GetPositionCoordinate()->
    GetComputedDisplayValue(this->CurrentRenderer);
  int *pos2 = this->ScaleBarActor->GetPosition2Coordinate()->
    GetComputedDisplayValue(this->CurrentRenderer);
  
  int pState = this->MouseCursorState;
  
  if (x > pos1[0] && x < pos2[0] && y > pos1[1] && y < pos2[1])
    {
    this->MouseCursorState = vtkKWScaleBarWidget::Inside;
    }
  else if (abs(x-pos1[0]) < 3 && y > pos1[1] && y < pos2[1])
    {
    this->MouseCursorState = vtkKWScaleBarWidget::ResizeLeft;
    }
  else if (abs(x-pos2[0]) < 3 && y > pos1[1] && y < pos2[1])
    {
    this->MouseCursorState = vtkKWScaleBarWidget::ResizeRight;
    }
  else
    {
    this->MouseCursorState = vtkKWScaleBarWidget::Outside;
    }
  
  if (pState == this->MouseCursorState)
    {
    return;
    }
  
  this->SetMouseCursor(this->MouseCursorState);
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::SetMouseCursor(int cursorState)
{
  switch (cursorState)
    {
    case vtkKWScaleBarWidget::Outside:
      this->Interactor->GetRenderWindow()->SetCurrentCursor(VTK_CURSOR_DEFAULT);
      break;
    case vtkKWScaleBarWidget::Inside:
      if (this->Repositionable)
        {
        this->Interactor->GetRenderWindow()->SetCurrentCursor(VTK_CURSOR_SIZEALL);
        }
      break;
    case vtkKWScaleBarWidget::ResizeLeft:
      this->Interactor->GetRenderWindow()->SetCurrentCursor(VTK_CURSOR_SIZEWE);
      break;
    case vtkKWScaleBarWidget::ResizeRight:
      this->Interactor->GetRenderWindow()->SetCurrentCursor(VTK_CURSOR_SIZEWE);
      break;
    }
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::MoveBar()
{
  if (!this->CurrentRenderer)
    {
    return;
    }

  int x = this->Interactor->GetEventPosition()[0];
  int y = this->Interactor->GetEventPosition()[1];
  
  int dx = x - this->StartPosition[0];
  int dy = y - this->StartPosition[1];
  
  int *pos1 = this->ScaleBarActor->GetPositionCoordinate()->
    GetComputedDisplayValue(this->CurrentRenderer);
  int *pos2 = this->ScaleBarActor->GetPosition2Coordinate()->
    GetComputedDisplayValue(this->CurrentRenderer);
  int *size = this->CurrentRenderer->GetSize();
  double newPos[2];

  this->StartPosition[0] = x;
  this->StartPosition[1] = y;  
  newPos[0] = pos1[0]+dx;
  newPos[1] = pos1[1]+dy;

  if (pos1[0]+dx < 0)
    {
    this->StartPosition[0] = 0;
    newPos[0] = (double)this->StartPosition[0];
    }
  if (pos1[1]+dy < 0)
    {
    this->StartPosition[1] = 0;
    newPos[1] = (double)this->StartPosition[1];
    }
  if (pos2[0]+dx > size[0])
    {
    this->StartPosition[0] = size[0] - (pos2[0]-pos1[0]);
    newPos[0] = (double)this->StartPosition[0];
    }
  if (pos2[1]+dy > size[1])
    {
    this->StartPosition[1] = size[1] - (pos2[1]-pos1[1]);
    newPos[1] = (double)this->StartPosition[1];
    }
  
  double startTextPos[2];
  startTextPos[0] = newPos[0];
  startTextPos[1] = newPos[1];
  
  this->CurrentRenderer->DisplayToNormalizedDisplay(newPos[0], newPos[1]);
  this->CurrentRenderer->NormalizedDisplayToViewport(newPos[0], newPos[1]);
  this->CurrentRenderer->ViewportToNormalizedViewport(newPos[0], newPos[1]);
  
  this->ScaleBarActor->SetPosition(newPos);
  
  double newX = this->ComputeXTextPosition(size[0],
                                           this->ScaleBarActor->GetWidth(),
                                           this->TextActor->GetWidth(),
                                           startTextPos[0]);

  this->CurrentRenderer->DisplayToNormalizedDisplay(newX, startTextPos[1]);
  this->CurrentRenderer->NormalizedDisplayToViewport(newX, startTextPos[1]);
  this->CurrentRenderer->ViewportToNormalizedViewport(newX, startTextPos[1]);
  
  this->TextActor->SetPosition(newX+
      this->ScaleBarActor->GetPosition2Coordinate()->GetValue()[0]+0.01, startTextPos[1]-0.01);
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::ResizeBar()
{
  if (!this->CurrentRenderer)
    {
    return;
    }

  int x = this->Interactor->GetEventPosition()[0];
  int y = this->Interactor->GetEventPosition()[1];
  
  int dx = x - this->StartPosition[0];
  
  int *pos1 = this->ScaleBarActor->GetPositionCoordinate()->
    GetComputedDisplayValue(this->CurrentRenderer);
  int *pos2 = this->ScaleBarActor->GetPosition2Coordinate()->
    GetComputedDisplayValue(this->CurrentRenderer);
  
  int *size = this->CurrentRenderer->GetSize();
  double newPos[2];
  
  this->StartPosition[0] = x;
  this->StartPosition[1] = y;  

  double width = this->ScaleBarActor->GetWidth();
  double newWidth = width;
  int useMinWidth = 0;
  
  switch (this->MouseCursorState)
    {
    case vtkKWScaleBarWidget::ResizeLeft:
      {
      newPos[0] = pos1[0]+dx;
      if (newPos[0] < 0)
        {
        newPos[0] = 0;
        dx = 0;
        this->StartPosition[0] = 0;
        }
      if (newPos[0] >= pos2[0])
        {
        newPos[0] = pos2[0]-2;
        useMinWidth = 1;
        this->StartPosition[0] = pos2[0]-2;
        }
      
      double startTextPos[2];
      startTextPos[0] = newPos[0];
      startTextPos[1] = pos1[1];
      
      double fPos1Y = pos1[1];
      
      this->CurrentRenderer->DisplayToNormalizedDisplay(newPos[0], fPos1Y);
      this->CurrentRenderer->NormalizedDisplayToViewport(newPos[0], fPos1Y);
      this->CurrentRenderer->ViewportToNormalizedViewport(newPos[0], fPos1Y);
      
      this->ScaleBarActor->SetPosition(newPos[0], fPos1Y);

      double newX = this->ComputeXTextPosition(size[0],
                                               this->ScaleBarActor->GetWidth(),
                                               this->TextActor->GetWidth(),
                                               startTextPos[0]);
      
      this->CurrentRenderer->DisplayToNormalizedDisplay(newX, startTextPos[1]);
      this->CurrentRenderer->NormalizedDisplayToViewport(newX, startTextPos[1]);
      this->CurrentRenderer->ViewportToNormalizedViewport(newX, startTextPos[1]);
      
      this->TextActor->SetPosition(newX+
          this->ScaleBarActor->GetPosition2Coordinate()->GetValue()[0]+0.01, startTextPos[1]-0.01);

      if ( ! useMinWidth)
        {
        newWidth = width - dx/(double)size[0];
        }
      else
        {
        newWidth = 2.0/(double)size[0];
        }
      this->ScaleBarActor->SetWidth(newWidth);
      this->TextActor->SetWidth(newWidth);
      this->Width = newWidth;
      this->OnScaleChange();
      break;
      }
    case vtkKWScaleBarWidget::ResizeRight:
      {
      newPos[0] = pos2[0]+dx;
      if (newPos[0] > size[0])
        {
        newPos[0] = size[0];
        dx = 0;
        this->StartPosition[0] = size[0];
        }
      if (newPos[0] <= pos1[0])
        {
        newPos[0] = pos1[0]+2;
        useMinWidth = 1;
        this->StartPosition[0] = pos1[0]+2;
        }
      
      if ( ! useMinWidth)
        {
        newWidth = width + dx/(double)size[0];
        }
      else
        {
        newWidth = 2.0/(double)size[0];
        }
      this->ScaleBarActor->SetWidth(newWidth);
      this->TextActor->SetWidth(newWidth);
      this->Width = newWidth;
      this->OnScaleChange();
      break;
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::SetDistanceUnits(const char *name)
{
  if ( ! this->DistanceUnits && ! name)
    {
    return;
    }
  if (this->DistanceUnits && name && ! strcmp(this->DistanceUnits, name))
    {
    return;
    }
  if (this->DistanceUnits)
    {
    delete [] this->DistanceUnits;
    }
  if (name)
    {
    this->DistanceUnits = new char [strlen(name)+1];
    strcpy(this->DistanceUnits, name);
    }
  else
    {
    this->DistanceUnits = NULL;
    }

  this->Modified();
  this->UpdateDistance();
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::SetColor(double r, double g, double b)
{
  this->ScaleBarActor->GetProperty()->SetColor(r, g, b);
  this->TextActor->GetTextProperty()->SetColor(r, g, b);
  this->Interactor->Render();
}

//----------------------------------------------------------------------------
double* vtkKWScaleBarWidget::GetColor()
{
  return this->ScaleBarActor->GetProperty()->GetColor();
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::SetPosition(double x, double y)
{
  if (!this->CurrentRenderer)
    {
    return;
    }

  double textPos[2];
  textPos[0] = x;
  textPos[1] = y;
  this->CurrentRenderer->NormalizedDisplayToDisplay(textPos[0], textPos[1]);
  
  this->CurrentRenderer->NormalizedDisplayToViewport(x, y);
  this->CurrentRenderer->ViewportToNormalizedViewport(x, y);
  
  double *f = this->ScaleBarActor->GetPosition();
  f[0] = x;
  f[1] = y;

  this->ScaleBarActor->SetPosition(f);
  
  int *size = this->CurrentRenderer->GetSize();
  double newX = this->ComputeXTextPosition(size[0],
                                           this->ScaleBarActor->GetWidth(),
                                           this->TextActor->GetWidth(),
                                           textPos[0]);
  
  this->CurrentRenderer->DisplayToNormalizedDisplay(newX, textPos[1]);
  this->CurrentRenderer->NormalizedDisplayToViewport(newX, textPos[1]);
  this->CurrentRenderer->ViewportToNormalizedViewport(newX, textPos[1]);
  this->TextActor->SetPosition(newX+0.01, textPos[1]-0.04);
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::GetPosition(double fp[2])
{
  if (!this->CurrentRenderer)
    {
    fp[0] = fp[1] = 0.0;
    return;
    }

  double *f = this->ScaleBarActor->GetPosition();
  fp[0] = f[0];
  fp[1] = f[1];

  this->CurrentRenderer->NormalizedViewportToViewport(fp[0], fp[1]);
  this->CurrentRenderer->ViewportToNormalizedDisplay(fp[0], fp[1]);
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::SetSize(double size)
{
  if (!this->CurrentRenderer)
    {
    return;
    }

  int *renSize = this->CurrentRenderer->GetSize();
  double parallelScale =
    this->CurrentRenderer->GetActiveCamera()->GetParallelScale();
  
  double width = size * renSize[1] / (renSize[0] * 2 * parallelScale);
  this->Width = width;
  this->ScaleBarActor->SetPosition2(width, 0.05);
  this->TextActor->SetWidth(width);
  this->OnScaleChange();
}

//----------------------------------------------------------------------------
double vtkKWScaleBarWidget::GetSize()
{
  return this->ScaleSize;
}

//----------------------------------------------------------------------------
double vtkKWScaleBarWidget::ComputeXTextPosition(int renXSize,
                                                double currentWidth,
                                                double newWidth,
                                                double startXPos)
{
  return startXPos + 0.5*renXSize*(currentWidth - newWidth);
}

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::UpdateDistance()
{
  const char *units = 
    (this->DistanceUnits ? this->DistanceUnits : k_("Units"));

  char *label = new char[strlen(units) + 100];
  sprintf(label, "%.3g %s", this->ScaleSize, units);
  this->TextActor->SetInput(label);
  delete [] label;
 }

//----------------------------------------------------------------------------
void vtkKWScaleBarWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  
  os << indent << "DistanceUnits: " << this->DistanceUnits << endl;
  os << indent << "Application: ";
  if (this->GetApplication())
    {
    os << this->GetApplication() << endl;
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "Repositionable: " << this->Repositionable << endl;
}
