1 // Aseprite
2 // Copyright (C) 2001-2018  David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #ifndef APP_UI_EDITOR_PIXELS_MOVEMENT_H_INCLUDED
8 #define APP_UI_EDITOR_PIXELS_MOVEMENT_H_INCLUDED
9 #pragma once
10 
11 #include "app/context_access.h"
12 #include "app/extra_cel.h"
13 #include "app/site.h"
14 #include "app/transaction.h"
15 #include "app/ui/editor/handle_type.h"
16 #include "base/shared_ptr.h"
17 #include "doc/algorithm/flip_type.h"
18 #include "gfx/size.h"
19 #include "obs/connection.h"
20 
21 namespace doc {
22   class Image;
23   class Mask;
24   class Sprite;
25 }
26 
27 namespace app {
28   class Doc;
29 
30   namespace cmd {
31     class SetMask;
32   }
33 
34   // Helper class to move pixels interactively and control undo history
35   // correctly.  The extra cel of the sprite is temporally used to show
36   // feedback, drag, and drop the specified image in the constructor
37   // (which generally would be the selected region or the clipboard
38   // content).
39   class PixelsMovement {
40   public:
41     enum MoveModifier {
42       NormalMovement = 1,
43       SnapToGridMovement = 2,
44       AngleSnapMovement = 4,
45       MaintainAspectRatioMovement = 8,
46       LockAxisMovement = 16,
47       ScaleFromPivot = 32,
48     };
49 
50     enum CommitChangesOption {
51       DontCommitChanges,
52       CommitChanges,
53     };
54 
55     enum KeepMaskOption {
56       DontKeepMask,
57       KeepMask,
58     };
59 
60     PixelsMovement(Context* context,
61                    Site site,
62                    const Image* moveThis,
63                    const Mask* mask,
64                    const char* operationName);
65     ~PixelsMovement();
66 
handle()67     HandleType handle() const { return m_handle; }
68 
69     void trim();
70     void cutMask();
71     void copyMask();
72     void catchImage(const gfx::Point& pos, HandleType handle);
73     void catchImageAgain(const gfx::Point& pos, HandleType handle);
74 
75     // Moves the image to the new position (relative to the start
76     // position given in the ctor).
77     void moveImage(const gfx::Point& pos, MoveModifier moveModifier);
78 
79     // Returns a copy of the current image being dragged with the
80     // current transformation.
81     void getDraggedImageCopy(base::UniquePtr<Image>& outputImage,
82                              base::UniquePtr<Mask>& outputMask);
83 
84     // Copies the image being dragged in the current position.
85     void stampImage();
86 
87     void dropImageTemporarily();
88     void dropImage();
89     void discardImage(const CommitChangesOption commit = CommitChanges,
90                       const KeepMaskOption keepMask = DontKeepMask);
91     bool isDragging() const;
92 
93     gfx::Rect getImageBounds();
94     gfx::Size getInitialImageSize() const;
95 
96     void setMaskColor(bool opaque, color_t mask_color);
97 
98     // Flips the image and mask in the given direction in "flipType".
99     // Flip Horizontally/Vertically commands are replaced calling this
100     // function, so they work more as the user would expect (flip the
101     // current selection instead of dropping and flipping it).
102     void flipImage(doc::algorithm::FlipType flipType);
103 
104     // Rotates the image and the mask the given angle. It's used to
105     // simulate RotateCommand when we're inside MovingPixelsState.
106     void rotate(double angle);
107 
getTransformation()108     const Transformation& getTransformation() const { return m_currentData; }
109 
110   private:
111     void onPivotChange();
112     void onRotationAlgorithmChange();
113     void redrawExtraImage();
114     void redrawCurrentMask();
115     void drawImage(doc::Image* dst, const gfx::Point& pos, bool renderOriginalLayer);
116     void drawMask(doc::Mask* dst, bool shrink);
117     void drawParallelogram(doc::Image* dst, const doc::Image* src, const doc::Mask* mask,
118       const Transformation::Corners& corners,
119       const gfx::Point& leftTop);
120     void updateDocumentMask();
121 
122     const ContextReader m_reader;
123     Site m_site;
124     Doc* m_document;
125     Sprite* m_sprite;
126     Layer* m_layer;
127     Transaction m_transaction;
128     cmd::SetMask* m_setMaskCmd;
129     bool m_isDragging;
130     bool m_adjustPivot;
131     HandleType m_handle;
132     Image* m_originalImage;
133     gfx::Point m_catchPos;
134     Transformation m_initialData;
135     Transformation m_currentData;
136     Mask* m_initialMask;
137     Mask* m_currentMask;
138     bool m_opaque;
139     color_t m_maskColor;
140     obs::scoped_connection m_pivotVisConn;
141     obs::scoped_connection m_pivotPosConn;
142     obs::scoped_connection m_rotAlgoConn;
143     ExtraCelRef m_extraCel;
144   };
145 
146   inline PixelsMovement::MoveModifier& operator|=(PixelsMovement::MoveModifier& a,
147                                                   const PixelsMovement::MoveModifier& b) {
148     a = static_cast<PixelsMovement::MoveModifier>(a | b);
149     return a;
150   }
151 
152   typedef base::SharedPtr<PixelsMovement> PixelsMovementPtr;
153 
154 } // namespace app
155 
156 #endif
157