forked from aseprite/aseprite
-
Notifications
You must be signed in to change notification settings - Fork 2
/
editor.h
506 lines (402 loc) · 17.1 KB
/
editor.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
// Aseprite
// Copyright (C) 2018-2024 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_UI_EDITOR_H_INCLUDED
#define APP_UI_EDITOR_H_INCLUDED
#pragma once
#include "app/color.h"
#include "app/doc.h"
#include "app/doc_observer.h"
#include "app/pref/preferences.h"
#include "app/tools/active_tool_observer.h"
#include "app/tools/tool_loop_modifiers.h"
#include "app/ui/color_source.h"
#include "app/ui/editor/brush_preview.h"
#include "app/ui/editor/editor_hit.h"
#include "app/ui/editor/editor_observers.h"
#include "app/ui/editor/editor_state.h"
#include "app/ui/editor/editor_states_history.h"
#include "app/ui/tile_source.h"
#include "app/util/tiled_mode.h"
#include "doc/algorithm/flip_type.h"
#include "doc/frame.h"
#include "doc/image_buffer.h"
#include "doc/selected_objects.h"
#include "filters/tiled_mode.h"
#include "gfx/fwd.h"
#include "obs/connection.h"
#include "os/color_space.h"
#include "render/projection.h"
#include "render/zoom.h"
#include "ui/base.h"
#include "ui/cursor_type.h"
#include "ui/pointer_type.h"
#include "ui/timer.h"
#include "ui/widget.h"
#include <memory>
#include <set>
namespace doc {
class Layer;
class Sprite;
}
namespace gfx {
class Region;
}
namespace ui {
class Cursor;
class Graphics;
class View;
}
namespace app {
class Context;
class DocView;
class EditorCustomizationDelegate;
class EditorRender;
class PixelsMovement;
class Site;
class Transformation;
namespace tools {
class Ink;
class Pointer;
class Tool;
}
enum class AutoScroll {
MouseDir,
ScrollDir,
};
class Editor : public ui::Widget,
public app::DocObserver,
public IColorSource,
public ITileSource,
public tools::ActiveToolObserver {
public:
enum EditorFlags {
kNoneFlag = 0,
kShowGrid = 1,
kShowMask = 2,
kShowOnionskin = 4,
kShowOutside = 8,
kShowDecorators = 16,
kShowSymmetryLine = 32,
kShowSlices = 64,
kDefaultEditorFlags = (kShowGrid |
kShowMask |
kShowOnionskin |
kShowOutside |
kShowDecorators |
kShowSymmetryLine |
kShowSlices)
};
enum class ZoomBehavior {
CENTER, // Zoom from center (don't change center of the editor)
MOUSE, // Zoom from cursor
};
static ui::WidgetType Type();
Editor(Doc* document,
EditorFlags flags = kDefaultEditorFlags,
EditorStatePtr state = nullptr);
~Editor();
static Editor* activeEditor() { return m_activeEditor; }
static void _setActiveEditor(Editor* editor) { m_activeEditor = editor; }
static void destroyEditorSharedInternals();
bool isActive() const { return (m_activeEditor == this); }
bool isUsingNewRenderEngine() const;
DocView* getDocView() { return m_docView; }
void setDocView(DocView* docView) { m_docView = docView; }
// Returns the current state.
EditorStatePtr getState() { return m_state; }
bool isMovingPixels() const;
void dropMovingPixels();
// Changes the state of the editor.
void setState(const EditorStatePtr& newState);
// Backs to previous state.
void backToPreviousState();
// Gets/sets the current decorator. The decorator is not owned by
// the Editor, so it must be deleted by the caller.
EditorDecorator* decorator() { return m_decorator; }
void setDecorator(EditorDecorator* decorator) { m_decorator = decorator; }
void getInvalidDecoratoredRegion(gfx::Region& region);
EditorFlags editorFlags() const { return m_flags; }
void setEditorFlags(EditorFlags flags) { m_flags = flags; }
bool isExtraCelLocked() const {
return m_flashing != Flashing::None;
}
Doc* document() { return m_document; }
Sprite* sprite() { return m_sprite; }
Layer* layer() { return m_layer; }
frame_t frame() { return m_frame; }
DocumentPreferences& docPref() { return m_docPref; }
void getSite(Site* site) const;
Site getSite() const;
void setLayer(const Layer* layer);
void setFrame(frame_t frame);
const render::Projection& projection() const { return m_proj; }
const render::Zoom& zoom() const { return m_proj.zoom(); }
const gfx::Point& padding() const { return m_padding; }
void setZoom(const render::Zoom& zoom);
void setDefaultScroll();
void setScrollToCenter();
void setScrollAndZoomToFitScreen();
void setEditorScroll(const gfx::Point& scroll);
void setEditorZoom(const render::Zoom& zoom);
// Updates the Editor's view.
void updateEditor(const bool restoreScrollPos);
// Draws the sprite taking care of the whole clipping region.
void drawSpriteClipped(const gfx::Region& updateRegion);
void flashCurrentLayer();
// Convert ui::Display coordinates (pixel relative to the top-left
// corner of the in the display content bounds) from/to
// editor/sprite coordinates (pixel in the canvas).
//
// TODO we should rename these functions to displayToEditor() and editorToDisplay()
gfx::Point screenToEditor(const gfx::Point& pt);
gfx::Point screenToEditorCeiling(const gfx::Point& pt);
gfx::PointF screenToEditorF(const gfx::Point& pt);
gfx::Point editorToScreen(const gfx::Point& pt);
gfx::PointF editorToScreenF(const gfx::PointF& pt);
gfx::Rect screenToEditor(const gfx::Rect& rc);
gfx::Rect editorToScreen(const gfx::Rect& rc);
gfx::RectF editorToScreenF(const gfx::RectF& rc);
void add_observer(EditorObserver* observer);
void remove_observer(EditorObserver* observer);
void setCustomizationDelegate(EditorCustomizationDelegate* delegate);
EditorCustomizationDelegate* getCustomizationDelegate() {
return m_customizationDelegate;
}
// Returns the visible area of the viewport in sprite coordinates.
gfx::Rect getViewportBounds();
// Returns the visible area of the active sprite.
gfx::Rect getVisibleSpriteBounds();
gfx::Size canvasSize() const;
gfx::Point mainTilePosition() const;
void expandRegionByTiledMode(gfx::Region& rgn,
const bool withProj) const;
void collapseRegionByTiledMode(gfx::Region& rgn) const;
// Changes the scroll to see the given point as the center of the editor.
void centerInSpritePoint(const gfx::Point& spritePos);
void updateStatusBar();
// Control scroll when cursor goes out of the editor viewport.
gfx::Point autoScroll(const ui::MouseMessage* msg,
const AutoScroll dir);
tools::Tool* getCurrentEditorTool() const;
tools::Ink* getCurrentEditorInk() const;
tools::ToolLoopModifiers getToolLoopModifiers() const { return m_toolLoopModifiers; }
bool isAutoSelectLayer();
// Returns true if we are able to draw in the current doc/sprite/layer/cel.
bool canDraw();
// Returns true if the cursor is inside the active mask/selection.
bool isInsideSelection();
// Returns true if the cursor is inside the selection and the
// selection mode is the default one which prioritizes and easy
// way to move the selection.
bool canStartMovingSelectionPixels();
// Returns true if the range selected in the timeline should be
// kept. E.g. When we are moving/transforming pixels on multiple
// cels, the MovingPixelsState can handle previous/next frame
// commands, so it's nice to keep the timeline range intact while
// we are in the MovingPixelsState.
bool keepTimelineRange();
// Returns the element that will be modified if the mouse is used
// in the given position.
EditorHit calcHit(const gfx::Point& mouseScreenPos);
void setZoomAndCenterInMouse(const render::Zoom& zoom,
const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
void pasteImage(const Image* image, const Mask* mask = nullptr);
void startSelectionTransformation(const gfx::Point& move, double angle);
void startFlipTransformation(doc::algorithm::FlipType flipType);
void updateTransformation(const Transformation& transform);
// Used by EditorView to notify changes in the view's scroll
// position.
void notifyScrollChanged();
void notifyZoomChanged();
// Returns true and changes to ScrollingState when "msg" says "the
// user wants to scroll". Same for zoom.
bool checkForScroll(ui::MouseMessage* msg);
bool checkForZoom(ui::MouseMessage* msg);
// Start Scrolling/ZoomingState
void startScrollingState(ui::MouseMessage* msg);
void startZoomingState(ui::MouseMessage* msg);
// Animation control
void play(const bool playOnce,
const bool playAll,
const bool playSubtags);
void stop();
bool isPlaying() const;
// Shows a popup menu to change the editor animation speed.
void showAnimationSpeedMultiplierPopup();
double getAnimationSpeedMultiplier() const;
void setAnimationSpeedMultiplier(double speed);
// Functions to be used in EditorState::onSetCursor()
void showMouseCursor(ui::CursorType cursorType,
const ui::Cursor* cursor = nullptr);
void showBrushPreview(const gfx::Point& pos);
// Gets the brush preview controller.
BrushPreview& brushPreview() { return m_brushPreview; }
static EditorRender& renderEngine() { return *m_renderEngine; }
// IColorSource
app::Color getColorByPosition(const gfx::Point& pos) override;
// ITileSource
doc::tile_t getTileByPosition(const gfx::Point& pos) override;
void setTagFocusBand(int value) { m_tagFocusBand = value; }
int tagFocusBand() const { return m_tagFocusBand; }
// Returns true if the Shift key to draw straight lines with a
// freehand tool is pressed.
bool startStraightLineWithFreehandTool(const tools::Pointer* pointer);
// Functions to handle the set of selected slices.
bool isSliceSelected(const doc::Slice* slice) const;
void clearSlicesSelection();
void selectSlice(const doc::Slice* slice);
bool selectSliceBox(const gfx::Rect& box);
void selectAllSlices();
bool hasSelectedSlices() const { return !m_selectedSlices.empty(); }
// Called by DocView's InputChainElement::onCancel() impl when Esc
// key is pressed to cancel the active selection.
void cancelSelections();
// Properties to show information in the status bar
bool showAutoCelGuides() const { return m_showAutoCelGuides; }
// Used in case an unhandled exception was caught when processing
// an Editor or EditorState event.
void showUnhandledException(const std::exception& ex,
const ui::Message* msg);
static void registerCommands();
protected:
bool onProcessMessage(ui::Message* msg) override;
void onSizeHint(ui::SizeHintEvent& ev) override;
void onResize(ui::ResizeEvent& ev) override;
void onPaint(ui::PaintEvent& ev) override;
void onInvalidateRegion(const gfx::Region& region) override;
void onSamplingChange();
void onFgColorChange();
void onContextBarBrushChange();
void onTiledModeBeforeChange();
void onTiledModeChange();
void onShowExtrasChange();
// DocObserver impl
void onColorSpaceChanged(DocEvent& ev) override;
void onExposeSpritePixels(DocEvent& ev) override;
void onSpritePixelRatioChanged(DocEvent& ev) override;
void onBeforeRemoveLayer(DocEvent& ev) override;
void onBeforeRemoveCel(DocEvent& ev) override;
void onAddTag(DocEvent& ev) override;
void onRemoveTag(DocEvent& ev) override;
void onRemoveSlice(DocEvent& ev) override;
void onBeforeLayerVisibilityChange(DocEvent& ev, bool newState) override;
// ActiveToolObserver impl
void onActiveToolChange(tools::Tool* tool) override;
private:
enum class Flashing { None, WithFlashExtraCel, WaitingDeferedPaint };
void setStateInternal(const EditorStatePtr& newState);
void updateQuicktool();
void updateToolByTipProximity(ui::PointerType pointerType);
// firstFromMouseDown=true when we call this function from the
// first MouseDown message (instead of KeyDown).
void updateToolLoopModifiersIndicators(const bool firstFromMouseDown = false);
void drawBackground(ui::Graphics* g);
void drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc);
void drawMaskSafe();
void drawMask(ui::Graphics* g);
void drawGrid(ui::Graphics* g, const gfx::Rect& spriteBounds, const gfx::Rect& gridBounds,
const app::Color& color, int alpha);
void drawSlices(ui::Graphics* g);
void drawTileNumbers(ui::Graphics* g, const Cel* cel);
void drawCelBounds(ui::Graphics* g, const Cel* cel, const gfx::Color color);
void drawCelGuides(ui::Graphics* g, const Cel* cel, const Cel* mouseCel);
void drawCelHGuide(ui::Graphics* g,
const int sprX1, const int sprX2,
const int scrX1, const int scrX2, const int scrY,
const gfx::Rect& scrCelBounds, const gfx::Rect& scrCmpBounds,
const int dottedX);
void drawCelVGuide(ui::Graphics* g,
const int sprY1, const int sprY2,
const int scrY1, const int scrY2, const int scrX,
const gfx::Rect& scrCelBounds, const gfx::Rect& scrCmpBounds,
const int dottedY);
gfx::Rect getCelScreenBounds(const Cel* cel);
void setCursor(const gfx::Point& mouseDisplayPos);
// Draws the specified portion of sprite in the editor. Warning:
// You should setup the clip of the screen before calling this
// routine.
void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy);
gfx::Point calcExtraPadding(const render::Projection& proj);
void invalidateCanvas();
void invalidateIfActive();
void updateAutoCelGuides(ui::Message* msg);
int otherLayersOpacity() const;
// Stack of states. The top element in the stack is the current state (m_state).
EditorStatesHistory m_statesHistory;
EditorStatesHistory m_deletedStates;
// Current editor state (it can be shared between several editors to
// the same document). This member cannot be NULL.
EditorStatePtr m_state;
// Current decorator (to draw extra UI elements).
EditorDecorator* m_decorator;
Doc* m_document; // Active document in the editor
Sprite* m_sprite; // Active sprite in the editor
Layer* m_layer; // Active layer in the editor
frame_t m_frame; // Active frame in the editor
render::Projection m_proj; // Zoom/pixel ratio in the editor
DocumentPreferences& m_docPref;
// Helper functions affected by the current Tiled Mode.
app::TiledModeHelper m_tiledModeHelper;
// Brush preview
BrushPreview m_brushPreview;
tools::ToolLoopModifiers m_toolLoopModifiers;
// Extra space around the sprite.
gfx::Point m_padding;
// Marching ants stuff
ui::Timer m_antsTimer;
int m_antsOffset;
obs::scoped_connection m_samplingChangeConn;
obs::scoped_connection m_fgColorChangeConn;
obs::scoped_connection m_contextBarBrushChangeConn;
obs::scoped_connection m_showExtrasConn;
// Slots listeing document preferences.
obs::scoped_connection m_tiledConnBefore;
obs::scoped_connection m_tiledConn;
obs::scoped_connection m_gridConn;
obs::scoped_connection m_pixelGridConn;
obs::scoped_connection m_bgConn;
obs::scoped_connection m_onionskinConn;
obs::scoped_connection m_symmetryModeConn;
EditorObservers m_observers;
EditorCustomizationDelegate* m_customizationDelegate;
DocView* m_docView;
// Last known mouse position received by this editor when the
// mouse button was pressed. Used for auto-scrolling. To get the
// current mouse position on the editor you can use
// ui::Display::lastMousePos().
gfx::Point m_oldPos;
EditorFlags m_flags;
bool m_secondaryButton;
Flashing m_flashing;
// Animation speed multiplier.
double m_aniSpeed;
bool m_isPlaying;
// The Cel that is above the mouse if the Ctrl (or Cmd) key is
// pressed (move key).
Cel* m_showGuidesThisCel;
bool m_showAutoCelGuides;
// Focused tag band. Used by the Timeline to save/restore the
// focused tag band for each sprite/editor.
int m_tagFocusBand;
// Used to restore scroll when the tiled mode is changed.
// TODO could we avoid one extra field just to do this?
gfx::Point m_oldMainTilePos;
#if ENABLE_DEVMODE
gfx::Rect m_perfInfoBounds;
#endif
// For slices
doc::SelectedObjects m_selectedSlices;
// Active sprite editor with the keyboard focus.
static Editor* m_activeEditor;
// The render engine must be shared between all editors so when a
// DrawingState is being used in one editor, other editors for the
// same document can show the same preview image/stroke being drawn
// (search for Render::setPreviewImage()).
static std::unique_ptr<EditorRender> m_renderEngine;
};
} // namespace app
#endif