1 // Aseprite
2 // Copyright (C) 2017  David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "app/ui/editor/moving_slice_state.h"
12 
13 #include "app/cmd/set_slice_key.h"
14 #include "app/context_access.h"
15 #include "app/transaction.h"
16 #include "app/ui/editor/editor.h"
17 #include "app/ui/status_bar.h"
18 #include "app/ui_context.h"
19 #include "doc/slice.h"
20 #include "ui/message.h"
21 
22 #include <cmath>
23 
24 namespace app {
25 
26 using namespace ui;
27 
MovingSliceState(Editor * editor,MouseMessage * msg,const EditorHit & hit)28 MovingSliceState::MovingSliceState(Editor* editor, MouseMessage* msg,
29                                    const EditorHit& hit)
30   : m_hit(hit)
31 {
32   m_mouseStart = editor->screenToEditor(msg->position());
33 
34   auto keyPtr = m_hit.slice()->getByFrame(editor->frame());
35   ASSERT(keyPtr);
36   if (keyPtr)
37     m_keyStart = m_key = *keyPtr;
38 
39   editor->captureMouse();
40 }
41 
onMouseUp(Editor * editor,MouseMessage * msg)42 bool MovingSliceState::onMouseUp(Editor* editor, MouseMessage* msg)
43 {
44   {
45     ContextWriter writer(UIContext::instance(), 1000);
46     Transaction transaction(writer.context(), "Slice Movement", ModifyDocument);
47 
48     doc::SliceKey newKey = m_key;
49     m_hit.slice()->insert(editor->frame(), m_keyStart);
50 
51     transaction.execute(new cmd::SetSliceKey(m_hit.slice(),
52                                              editor->frame(),
53                                              newKey));
54     transaction.commit();
55   }
56 
57   editor->backToPreviousState();
58   editor->releaseMouse();
59   return true;
60 }
61 
onMouseMove(Editor * editor,MouseMessage * msg)62 bool MovingSliceState::onMouseMove(Editor* editor, MouseMessage* msg)
63 {
64   gfx::Point newCursorPos = editor->screenToEditor(msg->position());
65   gfx::Point delta = newCursorPos - m_mouseStart;
66 
67   m_key = m_keyStart;
68   gfx::Rect rc =
69     (m_hit.type() == EditorHit::SliceCenter ? m_key.center():
70                                               m_key.bounds());
71 
72   // Move slice
73   if (m_hit.border() == (CENTER | MIDDLE)) {
74     rc.x += delta.x;
75     rc.y += delta.y;
76   }
77   else {
78     if (m_hit.border() & LEFT) {
79       rc.x += delta.x;
80       rc.w -= delta.x;
81       if (rc.w < 1) {
82         rc.x += rc.w-1;
83         rc.w = 1;
84       }
85     }
86     if (m_hit.border() & TOP) {
87       rc.y += delta.y;
88       rc.h -= delta.y;
89       if (rc.h < 1) {
90         rc.y += rc.h-1;
91         rc.h = 1;
92       }
93     }
94     if (m_hit.border() & RIGHT) {
95       rc.w += delta.x;
96       if (rc.w < 1)
97         rc.w = 1;
98     }
99     if (m_hit.border() & BOTTOM) {
100       rc.h += delta.y;
101       if (rc.h < 1)
102         rc.h = 1;
103     }
104   }
105 
106   if (m_hit.type() == EditorHit::SliceCenter)
107     m_key.setCenter(rc);
108   else
109     m_key.setBounds(rc);
110 
111   // Update the slice key
112   m_hit.slice()->insert(editor->frame(), m_key);
113 
114   // Redraw the editor.
115   editor->invalidate();
116 
117   // Use StandbyState implementation
118   return StandbyState::onMouseMove(editor, msg);
119 }
120 
onSetCursor(Editor * editor,const gfx::Point & mouseScreenPos)121 bool MovingSliceState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
122 {
123   switch (m_hit.border()) {
124     case TOP | LEFT:
125       editor->showMouseCursor(kSizeNWCursor);
126       break;
127     case TOP:
128       editor->showMouseCursor(kSizeNCursor);
129       break;
130     case TOP | RIGHT:
131       editor->showMouseCursor(kSizeNECursor);
132       break;
133     case LEFT:
134       editor->showMouseCursor(kSizeWCursor);
135       break;
136     case RIGHT:
137       editor->showMouseCursor(kSizeECursor);
138       break;
139     case BOTTOM | LEFT:
140       editor->showMouseCursor(kSizeSWCursor);
141       break;
142     case BOTTOM:
143       editor->showMouseCursor(kSizeSCursor);
144       break;
145     case BOTTOM | RIGHT:
146       editor->showMouseCursor(kSizeSECursor);
147       break;
148   }
149   return true;
150 }
151 
152 } // namespace app
153