// Aseprite
// Copyright (C) 2019-2025  Igara Studio S.A.
// Copyright (C) 2001-2017  David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.

#ifndef APP_TOOLS_TOOL_LOOP_H_INCLUDED
#define APP_TOOLS_TOOL_LOOP_H_INCLUDED
#pragma once

#include "app/shade.h"
#include "app/tools/dynamics.h"
#include "app/tools/stroke.h"
#include "app/tools/tool_loop_modifiers.h"
#include "app/tools/trace_policy.h"
#include "app/util/tiled_mode.h"
#include "doc/brush.h"
#include "doc/color.h"
#include "doc/frame.h"
#include "doc/grid.h"
#include "filters/tiled_mode.h"
#include "gfx/point.h"
#include "gfx/rect.h"
#include "render/gradient.h"

namespace gfx {
class Region;
}

namespace doc {
class Image;
class Layer;
class Mask;
class Palette;
class Remap;
class RgbMap;
class Slice;
class Sprite;
class Tileset;
} // namespace doc

namespace render {
class DitheringAlgorithmBase;
class DitheringMatrix;
} // namespace render

namespace app {
class Context;
class Doc;
class ExpandCelCanvas;

namespace tools {
class Controller;
class Ink;
class Intertwine;
class PointShape;
class Symmetry;
class Tool;

using namespace doc;

// Interface to communicate the sprite editor with the tool when the user
// starts using a tool to paint, select, pick color, etc.
//
// All this information should be provided by the editor and consumed
// by the tool (+controller+intertwiner+pointshape+ink).
//
// TODO This interface is huge, it should be refactored.
class ToolLoop {
public:
  enum Button { Left = 0, Right = 1 };

  virtual ~ToolLoop() {}

  virtual void commit() = 0;
  virtual void rollback() = 0;

  // Returns the tool to use to draw or use
  virtual Tool* getTool() = 0;

  // Returns the brush which will be used with the tool
  virtual Brush* getBrush() = 0;
  virtual void setBrush(const BrushRef& newBrush) = 0;

  // Returns the document to which belongs the sprite.
  virtual Doc* getDocument() = 0;

  // Returns the sprite where we will draw on
  virtual Sprite* sprite() = 0;

  // Returns the layer that will be modified if the tool paints
  virtual Layer* getLayer() = 0;

  virtual const Cel* getCel() = 0;

  // Returns true if the current mode is TileMap (false = Pixels)
  virtual bool isTilemapMode() = 0;

  virtual bool isManualTilesetMode() const = 0;

  // Returns the frame where we're paiting
  virtual frame_t getFrame() = 0;

  // Should return an image where we can read pixels (readonly image)
  virtual const Image* getSrcImage() = 0;

  // The image used to get get pixels in floodfill algorithm.
  virtual const Image* getFloodFillSrcImage() = 0;

  // Should return an image where we can write pixels
  virtual Image* getDstImage() = 0;

  // Can return a tileset used for preview purposes in Manual
  // tiles mode (to show a preview modifying all instances of the
  // same tile at the same time).
  virtual Tileset* getDstTileset() = 0;

  // Makes the specified region valid in the source
  // image. Basically the implementation should copy from the
  // original cel the given region to the source image. The source
  // image is used by inks to create blur effects or similar.
  virtual void validateSrcImage(const gfx::Region& rgn) = 0;

  // Makes the specified destination image region valid to be
  // painted. The destination image is used by inks to compose the
  // brush, so we've to make sure that the destination image
  // matches the original cel when we make that composition.
  virtual void validateDstImage(const gfx::Region& rgn) = 0;
  virtual void validateDstTileset(const gfx::Region& rgn) = 0;

  // Invalidates the whole destination image. It's used for tools
  // like line or rectangle which don't accumulate the effect so
  // they need to start with a fresh destination image on each
  // loop step/cycle.
  virtual void invalidateDstImage() = 0;
  virtual void invalidateDstImage(const gfx::Region& rgn) = 0;

  // Copies the given region from the destination to the source
  // image, used by "overlap" tools like jumble or spray.
  virtual void copyValidDstToSrcImage(const gfx::Region& rgn) = 0;

  // Returns the current Palette.
  virtual Palette* getPalette() = 0;

  // Returns the RGB map used to convert RGB values to palette index.
  virtual RgbMap* getRgbMap() = 0;

  // Returns true if we should use the mask to limit the paint area.
  virtual bool useMask() = 0;

  // Current mask to limit paint area
  virtual Mask* getMask() = 0;
  virtual void setMask(Mask* newMask) = 0;

  // Gets mask X,Y origin coordinates
  virtual gfx::Point getMaskOrigin() = 0;

  // Return the mouse button which start the tool-loop. It can be used
  // by some tools that instead of using the primary/secondary color
  // uses the pressed button for different behavior (like selection
  // tools).
  virtual Button getMouseButton() = 0;

  // Returns active foreground/background color (certain tools
  // needs to know the exact foreground/background color, they
  // cannot used the primary/secondary).
  virtual doc::color_t getFgColor() = 0;
  virtual doc::color_t getBgColor() = 0;

  // Primary color to draw (e.g. foreground if the user start drawing
  // with the left button, or background color if he used the right
  // button)
  virtual doc::color_t getPrimaryColor() = 0;
  virtual void setPrimaryColor(doc::color_t color) = 0;

  // Secondary color to draw (e.g. background if the user start drawing
  // with the left button, or foreground color if he used the right
  // button)
  virtual doc::color_t getSecondaryColor() = 0;
  virtual void setSecondaryColor(doc::color_t color) = 0;

  // Returns the opacity to be used by the ink (Ink).
  virtual int getOpacity() = 0;

  // Returns the tolerance to be used by the ink (Ink).
  virtual int getTolerance() = 0;

  // Returns true if the flood fill algorithm should take care
  // contiguous pixels or not.
  virtual bool getContiguous() = 0;

  // Returns flags/modifiers that change the way each part of the
  // tool (ink/controllers/etc.) work.
  virtual tools::ToolLoopModifiers getModifiers() = 0;

  // Returns the preferred "tiled" mode of the document.
  // See the method PointShape::doInkHline to check how this member is
  // used. When tiled mode is activated, each scanline can be divided
  // in various sub-lines if they pass the image bounds. For each of
  // these scanlines a Ink::inkHline is called
  virtual filters::TiledMode getTiledMode() = 0;

  virtual bool getGridVisible() = 0;
  virtual bool getSnapToGrid() = 0;
  virtual bool isSelectingTiles() = 0;
  virtual bool getStopAtGrid() = 0; // For floodfill-like tools
  virtual const doc::Grid& getGrid() const = 0;
  virtual gfx::Rect getGridBounds() = 0;
  virtual bool isPixelConnectivityEightConnected() = 0;
  virtual bool isPointInsideCanvas(const gfx::Point& point) = 0;

  // Returns true if the figure must be filled when we release the
  // mouse (e.g. a filled rectangle, etc.)
  //
  // To fill a shape, the Intertwine::fillPoints function is used.
  virtual bool getFilled() = 0;

  // Returns true if the preview should be with filled shapes.
  virtual bool getPreviewFilled() = 0;

  // Spray configuration
  virtual int getSprayWidth() = 0;
  virtual int getSpraySpeed() = 0;

  // X,Y origin of the cel where we are drawing
  virtual gfx::Point getCelOrigin() = 0;
  virtual bool needsCelCoordinates() = 0;

  // Velocity vector of the mouse
  virtual void setSpeed(const gfx::Point& speed) = 0;
  virtual gfx::Point getSpeed() = 0;

  // Returns the ink to use with the tool. Each tool has an associated
  // ink, but it could be modified for this specific loop, so
  // generally you should return the same ink as the tool, but it can
  // be different. The same for the other properties.
  virtual Ink* getInk() = 0;
  virtual Controller* getController() = 0;
  virtual PointShape* getPointShape() = 0;
  virtual Intertwine* getIntertwine() = 0;
  virtual TracePolicy getTracePolicy() = 0;
  virtual Symmetry* getSymmetry() = 0;

  virtual const Shade& getShade() = 0;
  virtual const doc::Remap* getShadingRemap() = 0;

  virtual void limitDirtyAreaToViewport(gfx::Region& rgn) = 0;

  // Redraws the dirty area.
  virtual void updateDirtyArea(const gfx::Region& dirtyArea) = 0;

  virtual void updateStatusBar(const char* text) = 0;
  virtual gfx::Point statusBarPositionOffset() = 0;

  // For gradients
  virtual render::DitheringMatrix getDitheringMatrix() = 0;
  virtual render::DitheringAlgorithmBase* getDitheringAlgorithm() = 0;
  virtual render::GradientType getGradientType() = 0;

  // For freehand algorithms with dynamics
  virtual tools::DynamicsOptions getDynamics() = 0;

  // Called when the user release the mouse on SliceInk
  virtual void onSliceRect(const gfx::Rect& bounds) = 0;

  virtual const app::TiledModeHelper& getTiledModeHelper() = 0;

  // Used by selection tools
  virtual bool isSelectionToolLoop() const = 0;
  virtual void addSelectionToolPoint(const gfx::Rect& rc) = 0;
  virtual void clearSelectionToolMask(const bool finalStep) = 0;

  // Used to restore the sprite status temporarily in case we want to
  // access its original state in the middle of a ToolLoop.
  virtual ExpandCelCanvas* expandCelCanvas() const = 0;
};

} // namespace tools
} // namespace app

#endif // TOOLS_TOOL_LOOP_H_INCLUDED
