Support resizing a reference cel with Move tool

This commit is contained in:
David Capello 2016-10-25 19:15:36 -03:00
parent 6ce73a831a
commit 609946c33f
4 changed files with 107 additions and 29 deletions

View File

@ -33,10 +33,16 @@ namespace app {
using namespace ui;
MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg)
MovingCelState::MovingCelState(Editor* editor,
MouseMessage* msg,
const HandleType handle)
: m_reader(UIContext::instance(), 500)
, m_celOffset(0.0, 0.0)
, m_celScale(1.0, 1.0)
, m_canceled(false)
, m_hasReference(false)
, m_scaled(false)
, m_handle(handle)
{
ContextWriter writer(m_reader);
Document* document = editor->document();
@ -44,11 +50,14 @@ MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg)
LayerImage* layer = static_cast<LayerImage*>(editor->layer());
ASSERT(layer->isImage());
Cel* currentCel = layer->cel(editor->frame());
ASSERT(currentCel); // The cel cannot be null
m_cel = layer->cel(editor->frame());
ASSERT(m_cel); // The cel cannot be null
if (!range.enabled())
range = DocumentRange(currentCel);
range = DocumentRange(m_cel);
if (m_cel)
m_celMainSize = m_cel->boundsF().size();
// Record start positions of all cels in selected range
for (Cel* cel : get_unique_cels(writer.sprite(), range)) {
@ -68,7 +77,6 @@ MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg)
}
m_cursorStart = editor->screenToEditorF(msg->position());
m_celOffset = gfx::PointF(0, 0);
editor->captureMouse();
// Hide the mask (temporarily, until mouse-up event)
@ -85,7 +93,7 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg)
// Here we put back the cel into its original coordinate (so we can
// add an undoer before).
if ((m_hasReference && m_celOffset != gfx::PointF(0, 0)) ||
if ((m_hasReference && (m_celOffset != gfx::PointF(0, 0) || m_scaled)) ||
(!m_hasReference && gfx::Point(m_celOffset) != gfx::Point(0, 0))) {
// Put the cels in the original position.
for (size_t i=0; i<m_celList.size(); ++i) {
@ -111,6 +119,10 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg)
gfx::RectF celBounds = cel->boundsF();
celBounds.x += m_celOffset.x;
celBounds.y += m_celOffset.y;
if (m_scaled) {
celBounds.w *= m_celScale.w;
celBounds.h *= m_celScale.h;
}
transaction.execute(new cmd::SetCelBoundsF(cel, celBounds));
}
else {
@ -150,15 +162,35 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg)
{
gfx::PointF newCursorPos = editor->screenToEditorF(msg->position());
m_celOffset = newCursorPos - m_cursorStart;
switch (m_handle) {
if (int(editor->getCustomizationDelegate()
->getPressedKeyAction(KeyContext::TranslatingSelection) & KeyAction::LockAxis)) {
if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) {
m_celOffset.x = 0;
}
else {
m_celOffset.y = 0;
case MoveHandle:
m_celOffset = newCursorPos - m_cursorStart;
if (int(editor->getCustomizationDelegate()
->getPressedKeyAction(KeyContext::TranslatingSelection) & KeyAction::LockAxis)) {
if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) {
m_celOffset.x = 0;
}
else {
m_celOffset.y = 0;
}
}
break;
case ScaleSEHandle: {
gfx::PointF delta(newCursorPos - m_cursorStart);
m_celScale.w = 1.0 + (delta.x / m_celMainSize.w);
m_celScale.h = 1.0 + (delta.y / m_celMainSize.h);
if (m_celScale.w < 1.0/m_celMainSize.w) m_celScale.w = 1.0/m_celMainSize.w;
if (m_celScale.h < 1.0/m_celMainSize.h) m_celScale.h = 1.0/m_celMainSize.h;
if (int(editor->getCustomizationDelegate()
->getPressedKeyAction(KeyContext::ScalingSelection) & KeyAction::MaintainAspectRatio)) {
m_celScale.w = m_celScale.h = MAX(m_celScale.w, m_celScale.h);
}
m_scaled = true;
break;
}
}
@ -168,6 +200,11 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg)
celBounds.x += m_celOffset.x;
celBounds.y += m_celOffset.y;
if (m_scaled) {
celBounds.w *= m_celScale.w;
celBounds.h *= m_celScale.h;
}
if (cel->layer()->isReference())
cel->setBoundsF(celBounds);
else
@ -184,22 +221,29 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg)
bool MovingCelState::onUpdateStatusBar(Editor* editor)
{
if (m_hasReference) {
StatusBar::instance()->setStatusText
(0,
":pos: %.2f %.2f :offset: %.2f %.2f",
m_cursorStart.x,
m_cursorStart.y,
m_celOffset.x,
m_celOffset.y);
if (m_scaled && m_cel) {
StatusBar::instance()->setStatusText
(0,
":pos: %.2f %.2f :offset: %.2f %.2f :size: %.2f%% %.2f%%",
m_cursorStart.x, m_cursorStart.y,
m_celOffset.x, m_celOffset.y,
100.0*m_celScale.w*m_celMainSize.w/m_cel->image()->width(),
100.0*m_celScale.h*m_celMainSize.h/m_cel->image()->height());
}
else {
StatusBar::instance()->setStatusText
(0,
":pos: %.2f %.2f :offset: %.2f %.2f",
m_cursorStart.x, m_cursorStart.y,
m_celOffset.x, m_celOffset.y);
}
}
else {
StatusBar::instance()->setStatusText
(0,
":pos: %3d %3d :offset: %3d %3d",
int(m_cursorStart.x),
int(m_cursorStart.y),
int(m_celOffset.x),
int(m_celOffset.y));
int(m_cursorStart.x), int(m_cursorStart.y),
int(m_celOffset.x), int(m_celOffset.y));
}
return true;

View File

@ -11,6 +11,7 @@
#include "app/ui/editor/standby_state.h"
#include "app/context_access.h"
#include "app/ui/editor/handle_type.h"
#include "doc/cel_list.h"
#include <vector>
@ -24,7 +25,9 @@ namespace app {
class MovingCelState : public StandbyState {
public:
MovingCelState(Editor* editor, ui::MouseMessage* msg);
MovingCelState(Editor* editor,
ui::MouseMessage* msg,
const HandleType handle);
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
@ -34,13 +37,18 @@ namespace app {
private:
ContextReader m_reader;
Cel* m_cel;
CelList m_celList;
std::vector<gfx::RectF> m_celStarts;
gfx::PointF m_cursorStart;
gfx::PointF m_celOffset;
gfx::SizeF m_celMainSize;
gfx::SizeF m_celScale;
bool m_canceled;
bool m_maskVisible;
bool m_hasReference;
bool m_scaled;
HandleType m_handle;
};
} // namespace app

View File

@ -117,7 +117,9 @@ void StandbyState::onActiveToolChange(Editor* editor, tools::Tool* tool)
// If the user change from a selection tool to a non-selection tool,
// or viceversa, we've to show or hide the transformation handles.
bool needDecorators = (tool && tool->getInk(0)->isSelection());
if (m_transformSelectionHandlesAreVisible != needDecorators) {
if (m_transformSelectionHandlesAreVisible != needDecorators ||
!editor->layer() ||
!editor->layer()->isReference()) {
m_transformSelectionHandlesAreVisible = false;
editor->invalidate();
}
@ -222,7 +224,11 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
}
else {
// Change to MovingCelState
editor->setState(EditorStatePtr(new MovingCelState(editor, msg)));
HandleType handle = MoveHandle;
if (resizeCelBounds(editor).contains(msg->position()))
handle = ScaleSEHandle;
editor->setState(EditorStatePtr(new MovingCelState(editor, msg, handle)));
}
}
@ -418,7 +424,10 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
return true;
}
else if (ink->isCelMovement()) {
editor->showMouseCursor(kMoveCursor);
if (resizeCelBounds(editor).contains(mouseScreenPos))
editor->showMouseCursor(kSizeSECursor);
else
editor->showMouseCursor(kMoveCursor);
return true;
}
else if (ink->isSlice()) {
@ -603,6 +612,22 @@ void StandbyState::onPivotChange(Editor* editor)
}
}
gfx::Rect StandbyState::resizeCelBounds(Editor* editor) const
{
gfx::Rect bounds;
Cel* refCel = (editor->layer() &&
editor->layer()->isReference() ?
editor->layer()->cel(editor->frame()): nullptr);
if (refCel) {
bounds = editor->editorToScreen(refCel->boundsF());
bounds.w /= 4;
bounds.h /= 4;
bounds.x += 3*bounds.w;
bounds.y += 3*bounds.h;
}
return bounds;
}
//////////////////////////////////////////////////////////////////////
// Decorator

View File

@ -74,6 +74,7 @@ namespace app {
private:
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);
void onPivotChange(Editor* editor);
gfx::Rect resizeCelBounds(Editor* editor) const;
Decorator* m_decorator;
obs::scoped_connection m_pivotVisConn;