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_H_INCLUDED
8 #define APP_UI_EDITOR_H_INCLUDED
9 #pragma once
10 
11 #include "app/color.h"
12 #include "app/doc.h"
13 #include "app/doc_observer.h"
14 #include "app/pref/preferences.h"
15 #include "app/tools/active_tool_observer.h"
16 #include "app/tools/tool_loop_modifiers.h"
17 #include "app/ui/color_source.h"
18 #include "app/ui/editor/brush_preview.h"
19 #include "app/ui/editor/editor_hit.h"
20 #include "app/ui/editor/editor_observers.h"
21 #include "app/ui/editor/editor_state.h"
22 #include "app/ui/editor/editor_states_history.h"
23 #include "doc/algorithm/flip_type.h"
24 #include "doc/frame.h"
25 #include "doc/image_buffer.h"
26 #include "filters/tiled_mode.h"
27 #include "gfx/fwd.h"
28 #include "obs/connection.h"
29 #include "render/projection.h"
30 #include "render/zoom.h"
31 #include "ui/base.h"
32 #include "ui/cursor_type.h"
33 #include "ui/pointer_type.h"
34 #include "ui/timer.h"
35 #include "ui/widget.h"
36 
37 namespace doc {
38   class Layer;
39   class Sprite;
40 }
41 namespace gfx {
42   class Region;
43 }
44 namespace ui {
45   class Cursor;
46   class Graphics;
47   class View;
48 }
49 
50 namespace app {
51   class Context;
52   class DocView;
53   class EditorCustomizationDelegate;
54   class EditorRender;
55   class PixelsMovement;
56   class Site;
57 
58   namespace tools {
59     class Ink;
60     class Tool;
61   }
62 
63   enum class AutoScroll {
64     MouseDir,
65     ScrollDir,
66   };
67 
68   class Editor : public ui::Widget,
69                  public app::DocObserver,
70                  public IColorSource,
71                  public tools::ActiveToolObserver {
72   public:
73     enum EditorFlags {
74       kNoneFlag = 0,
75       kShowGrid = 1,
76       kShowMask = 2,
77       kShowOnionskin = 4,
78       kShowOutside = 8,
79       kShowDecorators = 16,
80       kShowSymmetryLine = 32,
81       kShowSlices = 64,
82       kUseNonactiveLayersOpacityWhenEnabled = 128,
83       kDefaultEditorFlags = (kShowGrid |
84                              kShowMask |
85                              kShowOnionskin |
86                              kShowOutside |
87                              kShowDecorators |
88                              kShowSymmetryLine |
89                              kShowSlices |
90                              kUseNonactiveLayersOpacityWhenEnabled)
91     };
92 
93     enum class ZoomBehavior {
94       CENTER,                   // Zoom from center (don't change center of the editor)
95       MOUSE,                    // Zoom from cursor
96     };
97 
98     Editor(Doc* document, EditorFlags flags = kDefaultEditorFlags);
99     ~Editor();
100 
101     static void destroyEditorSharedInternals();
102 
103     bool isActive() const;
104 
getDocView()105     DocView* getDocView() { return m_docView; }
setDocView(DocView * docView)106     void setDocView(DocView* docView) { m_docView = docView; }
107 
108     // Returns the current state.
getState()109     EditorStatePtr getState() { return m_state; }
110 
111     bool isMovingPixels() const;
112     void dropMovingPixels();
113 
114     // Changes the state of the editor.
115     void setState(const EditorStatePtr& newState);
116 
117     // Backs to previous state.
118     void backToPreviousState();
119 
120     // Gets/sets the current decorator. The decorator is not owned by
121     // the Editor, so it must be deleted by the caller.
decorator()122     EditorDecorator* decorator() { return m_decorator; }
setDecorator(EditorDecorator * decorator)123     void setDecorator(EditorDecorator* decorator) { m_decorator = decorator; }
124     void getInvalidDecoratoredRegion(gfx::Region& region);
125 
editorFlags()126     EditorFlags editorFlags() const { return m_flags; }
setEditorFlags(EditorFlags flags)127     void setEditorFlags(EditorFlags flags) { m_flags = flags; }
128 
document()129     Doc* document() { return m_document; }
sprite()130     Sprite* sprite() { return m_sprite; }
layer()131     Layer* layer() { return m_layer; }
frame()132     frame_t frame() { return m_frame; }
docPref()133     DocumentPreferences& docPref() { return m_docPref; }
134 
135     void getSite(Site* site) const;
136     Site getSite() const;
137 
138     void setLayer(const Layer* layer);
139     void setFrame(frame_t frame);
140 
projection()141     const render::Projection& projection() const { return m_proj; }
zoom()142     const render::Zoom& zoom() const { return m_proj.zoom(); }
padding()143     const gfx::Point& padding() const { return m_padding; }
144 
145     void setZoom(const render::Zoom& zoom);
146     void setDefaultScroll();
147     void setScrollAndZoomToFitScreen();
148     void setEditorScroll(const gfx::Point& scroll);
149     void setEditorZoom(const render::Zoom& zoom);
150 
151     // Updates the Editor's view.
152     void updateEditor();
153 
154     // Draws the sprite taking care of the whole clipping region.
155     void drawSpriteClipped(const gfx::Region& updateRegion);
156 
157     void flashCurrentLayer();
158 
159     gfx::Point screenToEditor(const gfx::Point& pt);
160     gfx::PointF screenToEditorF(const gfx::Point& pt);
161     gfx::Point editorToScreen(const gfx::Point& pt);
162     gfx::PointF editorToScreenF(const gfx::PointF& pt);
163     gfx::Rect screenToEditor(const gfx::Rect& rc);
164     gfx::Rect editorToScreen(const gfx::Rect& rc);
165     gfx::RectF editorToScreenF(const gfx::RectF& rc);
166 
167     void add_observer(EditorObserver* observer);
168     void remove_observer(EditorObserver* observer);
169 
170     void setCustomizationDelegate(EditorCustomizationDelegate* delegate);
171 
getCustomizationDelegate()172     EditorCustomizationDelegate* getCustomizationDelegate() {
173       return m_customizationDelegate;
174     }
175 
176     // Returns the visible area of the viewport in sprite coordinates.
177     gfx::Rect getViewportBounds();
178 
179     // Returns the visible area of the active sprite.
180     gfx::Rect getVisibleSpriteBounds();
181 
182     gfx::Size canvasSize() const;
183     gfx::Point mainTilePosition() const;
184     void expandRegionByTiledMode(gfx::Region& rgn,
185                                  const bool withProj) const;
186 
187     // Changes the scroll to see the given point as the center of the editor.
188     void centerInSpritePoint(const gfx::Point& spritePos);
189 
190     void updateStatusBar();
191 
192     // Control scroll when cursor goes out of the editor viewport.
193     gfx::Point autoScroll(ui::MouseMessage* msg, AutoScroll dir);
194 
195     tools::Tool* getCurrentEditorTool();
196     tools::Ink* getCurrentEditorInk();
197 
getToolLoopModifiers()198     tools::ToolLoopModifiers getToolLoopModifiers() const { return m_toolLoopModifiers; }
199     bool isAutoSelectLayer() const;
200 
201     // Returns true if we are able to draw in the current doc/sprite/layer/cel.
202     bool canDraw();
203 
204     // Returns true if the cursor is inside the active mask/selection.
205     bool isInsideSelection();
206 
207     // Returns true if the cursor is inside the selection and the
208     // selection mode is the default one which prioritizes and easy
209     // way to move the selection.
210     bool canStartMovingSelectionPixels();
211 
212     // Returns the element that will be modified if the mouse is used
213     // in the given position.
214     EditorHit calcHit(const gfx::Point& mouseScreenPos);
215 
216     void setZoomAndCenterInMouse(const render::Zoom& zoom,
217       const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
218 
219     void pasteImage(const Image* image, const Mask* mask = nullptr);
220 
221     void startSelectionTransformation(const gfx::Point& move, double angle);
222 
223     void startFlipTransformation(doc::algorithm::FlipType flipType);
224 
225     // Used by EditorView to notify changes in the view's scroll
226     // position.
227     void notifyScrollChanged();
228     void notifyZoomChanged();
229 
230     // Returns true and changes to ScrollingState when "msg" says "the
231     // user wants to scroll". Same for zoom.
232     bool checkForScroll(ui::MouseMessage* msg);
233     bool checkForZoom(ui::MouseMessage* msg);
234 
235     // Start Scrolling/ZoomingState
236     void startScrollingState(ui::MouseMessage* msg);
237     void startZoomingState(ui::MouseMessage* msg);
238 
239     // Animation control
240     void play(const bool playOnce,
241               const bool playAll);
242     void stop();
243     bool isPlaying() const;
244 
245     // Shows a popup menu to change the editor animation speed.
246     void showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
247                                            Option<bool>& playAll,
248                                            const bool withStopBehaviorOptions);
249     double getAnimationSpeedMultiplier() const;
250     void setAnimationSpeedMultiplier(double speed);
251 
252     // Functions to be used in EditorState::onSetCursor()
253     void showMouseCursor(ui::CursorType cursorType,
254                          const ui::Cursor* cursor = nullptr);
255     void showBrushPreview(const gfx::Point& pos);
256 
257     // Gets the brush preview controller.
brushPreview()258     BrushPreview& brushPreview() { return m_brushPreview; }
259 
renderEngine()260     static EditorRender& renderEngine() { return *m_renderEngine; }
261 
262     // IColorSource
263     app::Color getColorByPosition(const gfx::Point& pos) override;
264 
setTagFocusBand(int value)265     void setTagFocusBand(int value) { m_tagFocusBand = value; }
tagFocusBand()266     int tagFocusBand() const { return m_tagFocusBand; }
267 
268     // Returns true if the Shift key to draw straight lines with a
269     // freehand tool is pressed.
270     bool startStraightLineWithFreehandTool(const ui::MouseMessage* msg);
271 
272     static void registerCommands();
273 
274   protected:
275     bool onProcessMessage(ui::Message* msg) override;
276     void onSizeHint(ui::SizeHintEvent& ev) override;
277     void onResize(ui::ResizeEvent& ev) override;
278     void onPaint(ui::PaintEvent& ev) override;
279     void onInvalidateRegion(const gfx::Region& region) override;
280     void onFgColorChange();
281     void onContextBarBrushChange();
282     void onTiledModeBeforeChange();
283     void onTiledModeChange();
284     void onShowExtrasChange();
285 
286     // DocObserver impl
287     void onExposeSpritePixels(DocEvent& ev) override;
288     void onSpritePixelRatioChanged(DocEvent& ev) override;
289     void onBeforeRemoveLayer(DocEvent& ev) override;
290     void onRemoveCel(DocEvent& ev) override;
291     void onAddFrameTag(DocEvent& ev) override;
292     void onRemoveFrameTag(DocEvent& ev) override;
293 
294     // ActiveToolObserver impl
295     void onActiveToolChange(tools::Tool* tool) override;
296 
297   private:
298     void setStateInternal(const EditorStatePtr& newState);
299     void updateQuicktool();
300     void updateToolByTipProximity(ui::PointerType pointerType);
301     void updateToolLoopModifiersIndicators();
302 
303     void drawBackground(ui::Graphics* g);
304     void drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc);
305     void drawMaskSafe();
306     void drawMask(ui::Graphics* g);
307     void drawGrid(ui::Graphics* g, const gfx::Rect& spriteBounds, const gfx::Rect& gridBounds,
308                   const app::Color& color, int alpha);
309     void drawSlices(ui::Graphics* g);
310     void drawCelBounds(ui::Graphics* g, const Cel* cel, const gfx::Color color);
311     void drawCelGuides(ui::Graphics* g, const Cel* cel, const Cel* mouseCel);
312     void drawCelHGuide(ui::Graphics* g,
313                        const int sprX1, const int sprX2,
314                        const int scrX1, const int scrX2, const int scrY,
315                        const gfx::Rect& scrCelBounds, const gfx::Rect& scrCmpBounds,
316                        const int dottedX);
317     void drawCelVGuide(ui::Graphics* g,
318                        const int sprY1, const int sprY2,
319                        const int scrY1, const int scrY2, const int scrX,
320                        const gfx::Rect& scrCelBounds, const gfx::Rect& scrCmpBounds,
321                        const int dottedY);
322     gfx::Rect getCelScreenBounds(const Cel* cel);
323 
324     void setCursor(const gfx::Point& mouseScreenPos);
325 
326     // Draws the specified portion of sprite in the editor.  Warning:
327     // You should setup the clip of the screen before calling this
328     // routine.
329     void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy);
330 
331     gfx::Point calcExtraPadding(const render::Projection& proj);
332 
333     void invalidateIfActive();
334     bool showAutoCelGuides();
335     void updateAutoCelGuides(ui::Message* msg);
336 
337     // Stack of states. The top element in the stack is the current state (m_state).
338     EditorStatesHistory m_statesHistory;
339     EditorStatesHistory m_deletedStates;
340 
341     // Current editor state (it can be shared between several editors to
342     // the same document). This member cannot be NULL.
343     EditorStatePtr m_state;
344 
345     // Current decorator (to draw extra UI elements).
346     EditorDecorator* m_decorator;
347 
348     Doc* m_document;              // Active document in the editor
349     Sprite* m_sprite;             // Active sprite in the editor
350     Layer* m_layer;               // Active layer in the editor
351     frame_t m_frame;              // Active frame in the editor
352     render::Projection m_proj;    // Zoom/pixel ratio in the editor
353     DocumentPreferences& m_docPref;
354 
355     // Brush preview
356     BrushPreview m_brushPreview;
357 
358     tools::ToolLoopModifiers m_toolLoopModifiers;
359 
360     // Extra space around the sprite.
361     gfx::Point m_padding;
362 
363     // Marching ants stuff
364     ui::Timer m_antsTimer;
365     int m_antsOffset;
366 
367     obs::scoped_connection m_fgColorChangeConn;
368     obs::scoped_connection m_contextBarBrushChangeConn;
369     obs::scoped_connection m_showExtrasConn;
370 
371     // Slots listeing document preferences.
372     obs::scoped_connection m_tiledConnBefore;
373     obs::scoped_connection m_tiledConn;
374     obs::scoped_connection m_gridConn;
375     obs::scoped_connection m_pixelGridConn;
376     obs::scoped_connection m_bgConn;
377     obs::scoped_connection m_onionskinConn;
378     obs::scoped_connection m_symmetryModeConn;
379 
380     EditorObservers m_observers;
381 
382     EditorCustomizationDelegate* m_customizationDelegate;
383 
384     // TODO This field shouldn't be here. It should be removed when
385     // editors.cpp are finally replaced with a fully funtional Workspace
386     // widget.
387     DocView* m_docView;
388 
389     gfx::Point m_oldPos;
390 
391     EditorFlags m_flags;
392 
393     bool m_secondaryButton;
394 
395     // Animation speed multiplier.
396     double m_aniSpeed;
397     bool m_isPlaying;
398 
399     // The Cel that is above the mouse if the Ctrl (or Cmd) key is
400     // pressed (move key).
401     Cel* m_showGuidesThisCel;
402 
403     // Focused tag band. Used by the Timeline to save/restore the
404     // focused tag band for each sprite/editor.
405     int m_tagFocusBand;
406 
407     // Used to restore scroll when the tiled mode is changed.
408     // TODO could we avoid one extra field just to do this?
409     gfx::Point m_oldMainTilePos;
410 
411 #if ENABLE_DEVMODE
412     gfx::Rect m_perfInfoBounds;
413 #endif
414 
415     // The render engine must be shared between all editors so when a
416     // DrawingState is being used in one editor, other editors for the
417     // same document can show the same preview image/stroke being drawn
418     // (search for Render::setPreviewImage()).
419     static EditorRender* m_renderEngine;
420   };
421 
422   ui::WidgetType editor_type();
423 
424 } // namespace app
425 
426 #endif
427