// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkCaptionWidget.h"
#include "vtkCallbackCommand.h"
#include "vtkCaptionRepresentation.h"
#include "vtkCommand.h"
#include "vtkHandleWidget.h"
#include "vtkObjectFactory.h"
#include "vtkPointHandleRepresentation3D.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkWidgetEvent.h"

VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkCaptionWidget);

// The point widget invokes events that we watch for. Basically
// the attachment/anchor point is moved with the point widget.
class vtkCaptionAnchorCallback : public vtkCommand
{
public:
  static vtkCaptionAnchorCallback* New() { return new vtkCaptionAnchorCallback; }
  void Execute(vtkObject*, unsigned long eventId, void*) override
  {
    switch (eventId)
    {
      case vtkCommand::StartInteractionEvent:
        this->CaptionWidget->StartAnchorInteraction();
        break;
      case vtkCommand::InteractionEvent:
        this->CaptionWidget->AnchorInteraction();
        break;
      case vtkCommand::EndInteractionEvent:
        this->CaptionWidget->EndAnchorInteraction();
        break;
    }
  }
  vtkCaptionAnchorCallback()
    : CaptionWidget(nullptr)
  {
  }
  vtkCaptionWidget* CaptionWidget;
};

//------------------------------------------------------------------------------
vtkCaptionWidget::vtkCaptionWidget()
{
  // The priority of the point widget is set a little higher than me.
  // This is so Enable/Disable events are caught by the anchor and then
  // dispatched to the BorderWidget.
  this->HandleWidget = vtkHandleWidget::New();
  this->HandleWidget->SetPriority(this->Priority + 0.01);
  this->HandleWidget->KeyPressActivationOff();

  // over ride the call back mapper on the border widget superclass to move
  // the caption widget using the left mouse button (still moves on middle
  // mouse button press). Release is already mapped to end select action
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkWidgetEvent::Select,
    this, vtkBorderWidget::TranslateAction);

  this->AnchorCallback = vtkCaptionAnchorCallback::New();
  this->AnchorCallback->CaptionWidget = this;
  this->HandleWidget->AddObserver(vtkCommand::StartInteractionEvent, this->AnchorCallback, 1.0);
  this->HandleWidget->AddObserver(vtkCommand::InteractionEvent, this->AnchorCallback, 1.0);
  this->HandleWidget->AddObserver(vtkCommand::EndInteractionEvent, this->AnchorCallback, 1.0);
}

//------------------------------------------------------------------------------
vtkCaptionWidget::~vtkCaptionWidget()
{
  this->HandleWidget->Delete();
  this->AnchorCallback->Delete();
}

//------------------------------------------------------------------------------
void vtkCaptionWidget::SetEnabled(int enabling)
{
  if (this->Interactor)
  {
    this->Interactor->Disable(); // avoid extra renders
  }

  if (enabling)
  {
    this->CreateDefaultRepresentation();
    this->HandleWidget->SetRepresentation(
      reinterpret_cast<vtkCaptionRepresentation*>(this->WidgetRep)->GetAnchorRepresentation());
    this->HandleWidget->SetInteractor(this->Interactor);
    this->HandleWidget->SetEnabled(1);
  }
  else
  {
    this->HandleWidget->SetEnabled(0);
  }
  if (this->Interactor)
  {
    this->Interactor->Enable();
  }

  this->Superclass::SetEnabled(enabling);
}

//------------------------------------------------------------------------------
void vtkCaptionWidget::CreateDefaultRepresentation()
{
  if (!this->WidgetRep)
  {
    this->WidgetRep = vtkCaptionRepresentation::New();
  }
}

//------------------------------------------------------------------------------
void vtkCaptionWidget::SetCaptionActor2D(vtkCaptionActor2D* capActor)
{
  vtkCaptionRepresentation* capRep = reinterpret_cast<vtkCaptionRepresentation*>(this->WidgetRep);
  if (!capRep)
  {
    this->CreateDefaultRepresentation();
    capRep = reinterpret_cast<vtkCaptionRepresentation*>(this->WidgetRep);
  }

  if (capRep->GetCaptionActor2D() != capActor)
  {
    capRep->SetCaptionActor2D(capActor);
    this->Modified();
  }
}

//------------------------------------------------------------------------------
vtkCaptionActor2D* vtkCaptionWidget::GetCaptionActor2D()
{
  vtkCaptionRepresentation* capRep = reinterpret_cast<vtkCaptionRepresentation*>(this->WidgetRep);
  if (!capRep)
  {
    return nullptr;
  }
  else
  {
    return capRep->GetCaptionActor2D();
  }
}

//------------------------------------------------------------------------------
void vtkCaptionWidget::StartAnchorInteraction()
{
  this->Superclass::StartInteraction();
  this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
}

//------------------------------------------------------------------------------
void vtkCaptionWidget::AnchorInteraction()
{
  vtkCaptionRepresentation* rep = reinterpret_cast<vtkCaptionRepresentation*>(this->WidgetRep);
  double pos[3];
  rep->GetAnchorRepresentation()->GetWorldPosition(pos);
  rep->SetAnchorPosition(pos);
  this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
}

//------------------------------------------------------------------------------
void vtkCaptionWidget::EndAnchorInteraction()
{
  this->Superclass::EndInteraction();
  this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
}

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