mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-14 19:06:03 +00:00
Add possibility to drag & drop the selection
This commit is contained in:
parent
5246c8341a
commit
90c364fe30
@ -188,6 +188,7 @@
|
||||
</section>
|
||||
<section id="selection">
|
||||
<option id="mode" type="SelectionMode" default="SelectionMode::DEFAULT" />
|
||||
<option id="move_edges" type="bool" default="true" />
|
||||
<option id="pivot_visibility" type="bool" default="false" />
|
||||
<option id="pivot_position" type="PivotPosition" default="PivotPosition::CENTER" />
|
||||
<option id="opaque" type="bool" default="false" />
|
||||
|
@ -435,6 +435,7 @@ add_library(app-lib
|
||||
ui/editor/editor_view.cpp
|
||||
ui/editor/moving_cel_state.cpp
|
||||
ui/editor/moving_pixels_state.cpp
|
||||
ui/editor/moving_selection_state.cpp
|
||||
ui/editor/moving_slice_state.cpp
|
||||
ui/editor/moving_symmetry_state.cpp
|
||||
ui/editor/navigate_state.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -16,7 +16,8 @@ namespace app {
|
||||
NoHandle,
|
||||
// This is the handle to move the pixels region, generally, the
|
||||
// whole region activates this handle.
|
||||
MoveHandle,
|
||||
MovePixelsHandle,
|
||||
MoveSelectionHandle,
|
||||
// One of the region's corders to scale.
|
||||
ScaleNWHandle, ScaleNHandle, ScaleNEHandle,
|
||||
ScaleWHandle, ScaleEHandle,
|
||||
|
@ -204,7 +204,7 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
|
||||
switch (m_handle) {
|
||||
|
||||
case MoveHandle:
|
||||
case MovePixelsHandle:
|
||||
m_celOffset = newCursorPos - m_cursorStart;
|
||||
if (int(editor->getCustomizationDelegate()
|
||||
->getPressedKeyAction(KeyContext::TranslatingSelection) & KeyAction::LockAxis)) {
|
||||
|
@ -125,7 +125,7 @@ void MovingPixelsState::translate(const gfx::Point& delta)
|
||||
if (m_pixelsMovement->isDragging())
|
||||
m_pixelsMovement->dropImageTemporarily();
|
||||
|
||||
m_pixelsMovement->catchImageAgain(gfx::Point(0, 0), MoveHandle);
|
||||
m_pixelsMovement->catchImageAgain(gfx::Point(0, 0), MovePixelsHandle);
|
||||
m_pixelsMovement->moveImage(delta, PixelsMovement::NormalMovement);
|
||||
m_pixelsMovement->dropImageTemporarily();
|
||||
}
|
||||
@ -287,7 +287,7 @@ bool MovingPixelsState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
|
||||
// Re-catch the image
|
||||
m_pixelsMovement->catchImageAgain(
|
||||
editor->screenToEditor(msg->position()), MoveHandle);
|
||||
editor->screenToEditor(msg->position()), MovePixelsHandle);
|
||||
|
||||
editor->captureMouse();
|
||||
return true;
|
||||
@ -333,7 +333,7 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
// Get the customization for the pixels movement (snap to grid, angle snap, etc.).
|
||||
KeyContext keyContext = KeyContext::Normal;
|
||||
switch (m_pixelsMovement->handle()) {
|
||||
case MoveHandle:
|
||||
case MovePixelsHandle:
|
||||
keyContext = KeyContext::TranslatingSelection;
|
||||
break;
|
||||
case ScaleNWHandle:
|
||||
|
135
src/app/ui/editor/moving_selection_state.cpp
Normal file
135
src/app/ui/editor/moving_selection_state.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui/editor/moving_selection_state.h"
|
||||
|
||||
#include "app/cmd/set_mask_position.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "doc/mask.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
MovingSelectionState::MovingSelectionState(Editor* editor, MouseMessage* msg)
|
||||
: m_cursorStart(editor->screenToEditor(msg->position()))
|
||||
, m_selOrigin(editor->document()->mask()->bounds().origin())
|
||||
{
|
||||
editor->captureMouse();
|
||||
}
|
||||
|
||||
MovingSelectionState::~MovingSelectionState()
|
||||
{
|
||||
}
|
||||
|
||||
void MovingSelectionState::onEnterState(Editor* editor)
|
||||
{
|
||||
StandbyState::onEnterState(editor);
|
||||
editor->document()->mask()->freeze();
|
||||
}
|
||||
|
||||
EditorState::LeaveAction MovingSelectionState::onLeaveState(Editor* editor, EditorState* newState)
|
||||
{
|
||||
Document* doc = editor->document();
|
||||
Mask* mask = doc->mask();
|
||||
gfx::Point newOrigin = mask->bounds().origin();
|
||||
|
||||
// Restore the mask to the original state so we can transform it
|
||||
// with the a undoable transaction.
|
||||
mask->setOrigin(m_selOrigin.x,
|
||||
m_selOrigin.y);
|
||||
mask->unfreeze();
|
||||
|
||||
{
|
||||
ContextWriter writer(UIContext::instance(), 1000);
|
||||
Transaction transaction(writer.context(), "Move Selection Edges", DoesntModifyDocument);
|
||||
transaction.execute(new cmd::SetMaskPosition(doc, newOrigin));
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
doc->resetTransformation();
|
||||
doc->notifyGeneralUpdate();
|
||||
return StandbyState::onLeaveState(editor, newState);
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
// Do nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onMouseUp(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
editor->backToPreviousState();
|
||||
editor->releaseMouse();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
const gfx::Point newCursorPos = editor->screenToEditor(msg->position());
|
||||
m_delta = newCursorPos - m_cursorStart;
|
||||
const gfx::Point newMaskOrigin = m_selOrigin + m_delta;
|
||||
const gfx::Point oldMaskOrigin = editor->document()->mask()->bounds().origin();
|
||||
|
||||
if (oldMaskOrigin != newMaskOrigin) {
|
||||
editor->document()->mask()->setOrigin(newMaskOrigin.x,
|
||||
newMaskOrigin.y);
|
||||
|
||||
MaskBoundaries* boundaries =
|
||||
const_cast<MaskBoundaries*>(editor->document()->getMaskBoundaries());
|
||||
const gfx::Point boundariesDelta = newMaskOrigin - oldMaskOrigin;
|
||||
boundaries->offset(boundariesDelta.x,
|
||||
boundariesDelta.y);
|
||||
|
||||
editor->invalidate();
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onMouseMove(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
editor->showMouseCursor(kMoveCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
{
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onKeyDown(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onKeyUp(Editor* editor, KeyMessage* msg)
|
||||
{
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onKeyUp(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingSelectionState::onUpdateStatusBar(Editor* editor)
|
||||
{
|
||||
const gfx::Rect bounds = editor->document()->mask()->bounds();
|
||||
|
||||
StatusBar::instance()->setStatusText
|
||||
(100, ":pos: %d %d :size: %3d %3d :offset: %d %d",
|
||||
bounds.x, bounds.y,
|
||||
bounds.w, bounds.h,
|
||||
m_delta.x, m_delta.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace app
|
39
src/app/ui/editor/moving_selection_state.h
Normal file
39
src/app/ui/editor/moving_selection_state.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_EDITOR_MOVING_SELECTION_STATE_H_INCLUDED
|
||||
#define APP_UI_EDITOR_MOVING_SELECTION_STATE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/editor/standby_state.h"
|
||||
|
||||
namespace app {
|
||||
class MovingSelectionState : public StandbyState {
|
||||
public:
|
||||
MovingSelectionState(Editor* editor, ui::MouseMessage* msg);
|
||||
virtual ~MovingSelectionState();
|
||||
|
||||
// EditorState
|
||||
virtual void onEnterState(Editor* editor) override;
|
||||
virtual LeaveAction onLeaveState(Editor* editor, EditorState* newState) override;
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
virtual bool requireBrushPreview() override { return false; }
|
||||
|
||||
private:
|
||||
gfx::Point m_cursorStart;
|
||||
gfx::Point m_selOrigin;
|
||||
gfx::Point m_delta;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif // APP_UI_EDITOR_MOVING_PIXELS_STATE_H_INCLUDED
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -255,7 +255,7 @@ void PixelsMovement::moveImage(const gfx::Point& pos, MoveModifier moveModifier)
|
||||
|
||||
switch (m_handle) {
|
||||
|
||||
case MoveHandle:
|
||||
case MovePixelsHandle:
|
||||
if ((moveModifier & LockAxisMovement) == LockAxisMovement) {
|
||||
if (ABS(dx) < ABS(dy))
|
||||
dx = 0.0;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "app/ui/editor/handle_type.h"
|
||||
#include "app/ui/editor/moving_cel_state.h"
|
||||
#include "app/ui/editor/moving_pixels_state.h"
|
||||
#include "app/ui/editor/moving_selection_state.h"
|
||||
#include "app/ui/editor/moving_slice_state.h"
|
||||
#include "app/ui/editor/moving_symmetry_state.h"
|
||||
#include "app/ui/editor/pivot_helpers.h"
|
||||
@ -194,7 +195,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
else {
|
||||
try {
|
||||
// Change to MovingCelState
|
||||
HandleType handle = MoveHandle;
|
||||
HandleType handle = MovePixelsHandle;
|
||||
if (resizeCelBounds(editor).contains(msg->position()))
|
||||
handle = ScaleSEHandle;
|
||||
|
||||
@ -282,6 +283,12 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Move selection edges
|
||||
if (overSelectionEdges(editor, msg->position())) {
|
||||
transformSelection(editor, msg, MoveSelectionHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move selected pixels
|
||||
if (layer && editor->isInsideSelection() && msg->left()) {
|
||||
if (!layer->isEditableHierarchy()) {
|
||||
@ -291,7 +298,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
transformSelection(editor, msg, MoveHandle);
|
||||
transformSelection(editor, msg, MovePixelsHandle);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -405,6 +412,11 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
if (ink) {
|
||||
// If the current tool change selection (e.g. rectangular marquee, etc.)
|
||||
if (ink->isSelection()) {
|
||||
if (overSelectionEdges(editor, mouseScreenPos)) {
|
||||
editor->showMouseCursor(kHandCursor); // TODO create a new mouse cursor
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move pixels
|
||||
if (editor->isInsideSelection()) {
|
||||
EditorCustomizationDelegate* customization = editor->getCustomizationDelegate();
|
||||
@ -612,6 +624,13 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
|
||||
}
|
||||
}
|
||||
|
||||
// Special case: Move only selection edges
|
||||
if (handle == MoveSelectionHandle) {
|
||||
EditorStatePtr newState(new MovingSelectionState(editor, msg));
|
||||
editor->setState(newState);
|
||||
return;
|
||||
}
|
||||
|
||||
Layer* layer = editor->layer();
|
||||
if (layer && layer->isReference()) {
|
||||
StatusBar::instance()->showTip(
|
||||
@ -699,6 +718,31 @@ gfx::Rect StandbyState::resizeCelBounds(Editor* editor) const
|
||||
return bounds;
|
||||
}
|
||||
|
||||
bool StandbyState::overSelectionEdges(Editor* editor,
|
||||
const gfx::Point& mouseScreenPos) const
|
||||
{
|
||||
// Move selection edges
|
||||
if (editor->isActive() &&
|
||||
editor->document()->isMaskVisible() &&
|
||||
editor->document()->getMaskBoundaries() &&
|
||||
Preferences::instance().selection.moveEdges()) {
|
||||
// For each selection edge
|
||||
for (const auto& seg : *editor->document()->getMaskBoundaries()) {
|
||||
gfx::Rect segBounds = editor->editorToScreen(seg.bounds());
|
||||
if (seg.vertical())
|
||||
segBounds.w = 1;
|
||||
else
|
||||
segBounds.h = 1;
|
||||
|
||||
if (gfx::Rect(segBounds).enlarge(2*guiscale()).contains(mouseScreenPos) &&
|
||||
!gfx::Rect(segBounds).shrink(2*guiscale()).contains(mouseScreenPos)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Decorator
|
||||
|
||||
|
@ -79,6 +79,7 @@ namespace app {
|
||||
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);
|
||||
void onPivotChange(Editor* editor);
|
||||
gfx::Rect resizeCelBounds(Editor* editor) const;
|
||||
bool overSelectionEdges(Editor* editor, const gfx::Point& mouseScreenPos) const;
|
||||
|
||||
Decorator* m_decorator;
|
||||
obs::scoped_connection m_pivotVisConn;
|
||||
|
Loading…
Reference in New Issue
Block a user