// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
 * @class   vtkTextActor
 * @brief   An actor that displays text. Scaled or unscaled
 *
 * vtkTextActor can be used to place text annotation into a window.
 * When TextScaleMode is NONE, the text is fixed font and operation is
 * the same as a vtkPolyDataMapper2D/vtkActor2D pair.
 * When TextScaleMode is VIEWPORT, the font resizes such that it maintains a
 * consistent size relative to the viewport in which it is rendered.
 * When TextScaleMode is PROP, the font resizes such that the text fits inside
 * the box defined by the position 1 & 2 coordinates. This class replaces the
 * deprecated vtkScaledTextActor and acts as a convenient wrapper for
 * a vtkTextMapper/vtkActor2D pair.
 * Set the text property/attributes through the vtkTextProperty associated to
 * this actor.
 *
 * @sa
 * vtkActor2D vtkPolyDataMapper vtkTextProperty vtkTextRenderer
 */

#ifndef vtkTextActor_h
#define vtkTextActor_h

#include "vtkRenderingCoreModule.h" // For export macro
#include "vtkTexturedActor2D.h"
#include "vtkWrappingHints.h" // For VTK_MARSHALAUTO

VTK_ABI_NAMESPACE_BEGIN
class vtkImageData;
class vtkPoints;
class vtkPolyData;
class vtkPolyDataMapper2D;
class vtkProperty2D;
class vtkTextProperty;
class vtkTextRenderer;
class vtkTransform;

class VTKRENDERINGCORE_EXPORT VTK_MARSHALAUTO vtkTextActor : public vtkTexturedActor2D
{
public:
  vtkTypeMacro(vtkTextActor, vtkTexturedActor2D);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  /**
   * Instantiate object with a rectangle in normaled view coordinates
   * of (0.2,0.85, 0.8, 0.95).
   */
  static vtkTextActor* New();

  /**
   * Shallow copy of this text actor. Overloads the virtual
   * vtkProp method.
   */
  void ShallowCopy(vtkProp* prop) override;

  ///@{
  /**
   * Set the text string to be displayed. "\n" is recognized
   * as a carriage return/linefeed (line separator).
   * The characters must be in the UTF-8 encoding.
   * Convenience method to the underlying mapper
   */
  void SetInput(const char* inputString);
  char* GetInput();
  ///@}

  ///@{
  /**
   * Set/Get the minimum size in pixels for this actor.
   * Defaults to 10,10.
   * Only valid when TextScaleMode is PROP.
   */
  vtkSetVector2Macro(MinimumSize, int);
  vtkGetVector2Macro(MinimumSize, int);
  ///@}

  ///@{
  /**
   * Set/Get the maximum height of a line of text as a
   * percentage of the vertical area allocated to this
   * scaled text actor. Defaults to 1.0.
   * Only valid when TextScaleMode is PROP.
   */
  vtkSetMacro(MaximumLineHeight, float);
  vtkGetMacro(MaximumLineHeight, float);
  ///@}

  ///@{
  /**
   * Set how text should be scaled.  If set to
   * vtkTextActor::TEXT_SCALE_MODE_NONE, the font size will be fixed by the
   * size given in TextProperty.  If set to vtkTextActor::TEXT_SCALE_MODE_PROP,
   * the text will be scaled to fit exactly in the prop as specified by the
   * position 1 & 2 coordinates.  If set to
   * vtkTextActor::TEXT_SCALE_MODE_VIEWPORT, the text will be scaled based on
   * the size of the viewport it is displayed in.
   */
  vtkSetClampMacro(TextScaleMode, int, TEXT_SCALE_MODE_NONE, TEXT_SCALE_MODE_VIEWPORT);
  vtkGetMacro(TextScaleMode, int);
  void SetTextScaleModeToNone() { this->SetTextScaleMode(TEXT_SCALE_MODE_NONE); }
  void SetTextScaleModeToProp() { this->SetTextScaleMode(TEXT_SCALE_MODE_PROP); }
  void SetTextScaleModeToViewport() { this->SetTextScaleMode(TEXT_SCALE_MODE_VIEWPORT); }
  ///@}

  enum
  {
    TEXT_SCALE_MODE_NONE = 0,
    TEXT_SCALE_MODE_PROP,
    TEXT_SCALE_MODE_VIEWPORT
  };

  ///@{
  /**
   * Turn on or off the UseBorderAlign option.
   * When UseBorderAlign is on, the bounding rectangle is used to align the text,
   * which is the proper behavior when using vtkTextRepresentation
   */
  vtkSetMacro(UseBorderAlign, vtkTypeBool);
  vtkGetMacro(UseBorderAlign, vtkTypeBool);
  vtkBooleanMacro(UseBorderAlign, vtkTypeBool);
  ///@}

  ///@{
  /**
   * This method is being deprecated.  Use SetJustification and
   * SetVerticalJustification in text property instead.
   * Set/Get the Alignment point
   * if zero (default), the text aligns itself to the bottom left corner
   * (which is defined by the PositionCoordinate)
   * otherwise the text aligns itself to corner/midpoint or centre
   * @verbatim
   * 6   7   8
   * 3   4   5
   * 0   1   2
   * @endverbatim
   * This is the same as setting the TextProperty's justification.
   * Currently TextActor is not oriented around its AlignmentPoint.
   */
  VTK_MARSHALEXCLUDE(VTK_MARSHAL_EXCLUDE_REASON_IS_REDUNDANT)
  void SetAlignmentPoint(int point);
  VTK_MARSHALEXCLUDE(VTK_MARSHAL_EXCLUDE_REASON_IS_REDUNDANT)
  int GetAlignmentPoint();
  ///@}

  ///@{
  /**
   * Counterclockwise rotation around the Alignment point.
   * Units are in degrees and defaults to 0.
   * The orientation in the text property rotates the text in the
   * texture map.  It will proba ly not give you the effect you
   * desire.
   */
  void SetOrientation(float orientation);
  vtkGetMacro(Orientation, float);
  ///@}

  ///@{
  /**
   * Set/Get the text property.
   */
  virtual void SetTextProperty(vtkTextProperty* p);
  vtkGetObjectMacro(TextProperty, vtkTextProperty);
  ///@}

  /**
   * Return the bounding box coordinates of the text in pixels.
   * The bbox array is populated with [ xmin, xmax, ymin, ymax ]
   * values in that order.
   */
  virtual void GetBoundingBox(vtkViewport* vport, double bbox[4]);

  /**
   * Syntactic sugar to get the size of text instead of the entire bounding box.
   */
  virtual void GetSize(vtkViewport* vport, double size[2]);

  ///@{
  /**
   * Set and return the font size required to make this mapper fit in a given
   * target rectangle (width x height, in pixels). A static version of the
   * method is also available for convenience to other classes (e.g., widgets).
   */
  virtual int SetConstrainedFontSize(vtkViewport*, int targetWidth, int targetHeight);
  static int SetConstrainedFontSize(vtkTextActor*, vtkViewport*, int targetWidth, int targetHeight);
  ///@}

  /**
   * Set and return the font size required to make each element of an array
   * of mappers fit in a given rectangle (width x height, in pixels).  This
   * font size is the smallest size that was required to fit the largest
   * mapper in this constraint.
   */
  static int SetMultipleConstrainedFontSize(vtkViewport*, int targetWidth, int targetHeight,
    vtkTextActor** actors, int nbOfActors, int* maxResultingSize);

  /**
   * Enable non-linear scaling of font sizes. This is useful in combination
   * with scaled text. With small windows you want to use the entire scaled
   * text area. With larger windows you want to reduce the font size some so
   * that the entire area is not used. These values modify the computed font
   * size as follows:
   * newFontSize = pow(FontSize,exponent)*pow(target,1.0 - exponent)
   * typically exponent should be around 0.7 and target should be around 10
   */
  virtual void SetNonLinearFontScale(double exponent, int target);

  /**
   * This is just a simple coordinate conversion method used in the render
   * process.
   */
  void SpecifiedToDisplay(double* pos, vtkViewport* vport, int specified);

  /**
   * This is just a simple coordinate conversion method used in the render
   * process.
   */
  void DisplayToSpecified(double* pos, vtkViewport* vport, int specified);

  /**
   * Compute the scale the font should be given the viewport.  The result
   * is placed in the ScaledTextProperty ivar.
   */
  virtual void ComputeScaledFont(vtkViewport* viewport);

  ///@{
  /**
   * Get the scaled font.  Use ComputeScaledFont to set the scale for a given
   * viewport.
   */
  vtkGetObjectMacro(ScaledTextProperty, vtkTextProperty);
  ///@}

  /**
   * Provide a font scaling based on a viewport.  This is the scaling factor
   * used when the TextScaleMode is set to VIEWPORT and has been made public for
   * other components to use.  This scaling assumes that the long dimension of
   * the viewport is meant to be 6 inches (a typical width of text in a paper)
   * and then resizes based on if that long dimension was 72 DPI.
   */
  static float GetFontScale(vtkViewport* viewport);

  /**
   * WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
   * DO NOT USE THIS METHOD OUTSIDE OF THE RENDERING PROCESS.
   * Release any graphics resources that are being consumed by this actor.
   * The parameter window could be used to determine which graphic
   * resources to release.
   */
  void ReleaseGraphicsResources(vtkWindow*) override;

  ///@{
  /**
   * WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
   * DO NOT USE THIS METHOD OUTSIDE OF THE RENDERING PROCESS.
   * Draw the text actor to the screen.
   */
  int RenderOpaqueGeometry(vtkViewport* viewport) override;
  int RenderTranslucentPolygonalGeometry(vtkViewport*) override { return 0; }
  int RenderOverlay(vtkViewport* viewport) override;
  ///@}

  /**
   * Does this prop have some translucent polygonal geometry?
   */
  vtkTypeBool HasTranslucentPolygonalGeometry() override;

protected:
  /**
   * Render Input to Image using the supplied font property.
   */
  virtual bool RenderImage(vtkTextProperty* tprop, vtkViewport* viewport);

  /**
   * Get the bounding box for Input using the supplied font property.
   */
  virtual bool GetImageBoundingBox(vtkTextProperty* tprop, vtkViewport* viewport, int bbox[4]);

  vtkTextActor();
  ~vtkTextActor() override;

  int MinimumSize[2];
  float MaximumLineHeight;
  double FontScaleExponent;
  int TextScaleMode;
  float Orientation;
  vtkTypeBool UseBorderAlign;

  vtkTextProperty* TextProperty;
  vtkImageData* ImageData;
  vtkTextRenderer* TextRenderer;
  vtkTimeStamp BuildTime;
  vtkTransform* Transform;
  int LastSize[2];
  int LastOrigin[2];
  char* Input;
  bool InputRendered;
  double FormerOrientation;
  int RenderedDPI;

  vtkTextProperty* ScaledTextProperty;

  // Stuff needed to display the image text as a texture map.
  vtkPolyData* Rectangle;
  vtkPoints* RectanglePoints;

  virtual void ComputeRectangle(vtkViewport* viewport);

  /**
   * Ensure that \a Rectangle and \a RectanglePoints are valid and up-to-date.

   * Unlike ComputeRectangle(), this may do nothing (if the rectangle is valid),
   * or it may render the text to an image and recompute rectangle points by
   * calling ComputeRectangle.

   * Returns a non-zero value upon success or zero upon failure to
   * render the image.

   * This may be called with a NULL viewport when bounds are required before
   * a rendering has occurred.
   */
  virtual int UpdateRectangle(vtkViewport* viewport);

private:
  vtkTextActor(const vtkTextActor&) = delete;
  void operator=(const vtkTextActor&) = delete;
};

VTK_ABI_NAMESPACE_END
#endif
