mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-10 15:40:31 +00:00
Add key modifier to draw straight lines from the last point (fix #562)
- Removed ToolLoop::screenToSprite(), now ToolLoopManager::Pointer has sprite coordinates (instead of screen coordinates)
This commit is contained in:
parent
c674c474f6
commit
8aefa24a5b
@ -437,6 +437,9 @@
|
|||||||
|
|
||||||
<!-- Modifiers for move tool -->
|
<!-- Modifiers for move tool -->
|
||||||
<key action="AutoSelectLayer" shortcut="Ctrl" mac="Cmd" />
|
<key action="AutoSelectLayer" shortcut="Ctrl" mac="Cmd" />
|
||||||
|
|
||||||
|
<!-- Modifiers for freehand tool controller -->
|
||||||
|
<key action="StraightLineFromLastPoint" shortcut="Shift" />
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
</keyboard>
|
</keyboard>
|
||||||
|
@ -342,6 +342,9 @@ private:
|
|||||||
case KeyContext::MoveTool:
|
case KeyContext::MoveTool:
|
||||||
text = "Move Tool: " + text;
|
text = "Move Tool: " + text;
|
||||||
break;
|
break;
|
||||||
|
case KeyContext::FreehandTool:
|
||||||
|
text = "Freehand Tools: " + text;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
|
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
|
||||||
|
|
||||||
|
@ -212,9 +212,6 @@ namespace app {
|
|||||||
// Returns true if the loop was canceled by the user
|
// Returns true if the loop was canceled by the user
|
||||||
virtual bool isCanceled() = 0;
|
virtual bool isCanceled() = 0;
|
||||||
|
|
||||||
// Converts a coordinate in the screen to the sprite.
|
|
||||||
virtual gfx::Point screenToSprite(const gfx::Point& screenPoint) = 0;
|
|
||||||
|
|
||||||
// This region is modified by the ToolLoopManager so then you know
|
// This region is modified by the ToolLoopManager so then you know
|
||||||
// what must be updated in updateDirtyArea().
|
// what must be updated in updateDirtyArea().
|
||||||
virtual gfx::Region& getDirtyArea() = 0;
|
virtual gfx::Region& getDirtyArea() = 0;
|
||||||
@ -223,7 +220,6 @@ namespace app {
|
|||||||
virtual void updateDirtyArea() = 0;
|
virtual void updateDirtyArea() = 0;
|
||||||
|
|
||||||
virtual void updateStatusBar(const char* text) = 0;
|
virtual void updateStatusBar(const char* text) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tools
|
} // namespace tools
|
||||||
|
@ -101,7 +101,7 @@ void ToolLoopManager::pressButton(const Pointer& pointer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the screen point to a sprite point
|
// Convert the screen point to a sprite point
|
||||||
Point spritePoint = m_toolLoop->screenToSprite(Point(pointer.x(), pointer.y()));
|
Point spritePoint = pointer.point();
|
||||||
m_toolLoop->setSpeed(Point(0, 0));
|
m_toolLoop->setSpeed(Point(0, 0));
|
||||||
m_oldPoint = spritePoint;
|
m_oldPoint = spritePoint;
|
||||||
snapToGrid(spritePoint);
|
snapToGrid(spritePoint);
|
||||||
@ -122,7 +122,7 @@ bool ToolLoopManager::releaseButton(const Pointer& pointer)
|
|||||||
if (isCanceled())
|
if (isCanceled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Point spritePoint = m_toolLoop->screenToSprite(Point(pointer.x(), pointer.y()));
|
Point spritePoint = pointer.point();
|
||||||
snapToGrid(spritePoint);
|
snapToGrid(spritePoint);
|
||||||
|
|
||||||
bool res = m_toolLoop->getController()->releaseButton(m_points, spritePoint);
|
bool res = m_toolLoop->getController()->releaseButton(m_points, spritePoint);
|
||||||
@ -144,7 +144,7 @@ void ToolLoopManager::movement(const Pointer& pointer)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Convert the screen point to a sprite point
|
// Convert the screen point to a sprite point
|
||||||
Point spritePoint = m_toolLoop->screenToSprite(Point(pointer.x(), pointer.y()));
|
Point spritePoint = pointer.point();
|
||||||
// Calculate the speed (new sprite point - old sprite point)
|
// Calculate the speed (new sprite point - old sprite point)
|
||||||
m_toolLoop->setSpeed(spritePoint - m_oldPoint);
|
m_toolLoop->setSpeed(spritePoint - m_oldPoint);
|
||||||
m_oldPoint = spritePoint;
|
m_oldPoint = spritePoint;
|
||||||
|
@ -46,17 +46,16 @@ namespace app {
|
|||||||
enum Button { None, Left, Middle, Right };
|
enum Button { None, Left, Middle, Right };
|
||||||
|
|
||||||
Pointer()
|
Pointer()
|
||||||
: m_x(0), m_y(0), m_button(None) { }
|
: m_point(0, 0), m_button(None) { }
|
||||||
|
|
||||||
Pointer(int x, int y, Button button)
|
Pointer(const gfx::Point& point, Button button)
|
||||||
: m_x(x), m_y(y), m_button(button) { }
|
: m_point(point), m_button(button) { }
|
||||||
|
|
||||||
int x() const { return m_x; }
|
const gfx::Point& point() const { return m_point; }
|
||||||
int y() const { return m_y; }
|
|
||||||
Button getButton() const { return m_button; }
|
Button getButton() const { return m_button; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_x, m_y;
|
gfx::Point m_point;
|
||||||
Button m_button;
|
Button m_button;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "app/tools/tool_loop.h"
|
#include "app/tools/tool_loop.h"
|
||||||
#include "app/tools/tool_loop_manager.h"
|
#include "app/tools/tool_loop_manager.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "app/ui/editor/editor_customization_delegate.h"
|
||||||
#include "app/ui/keyboard_shortcuts.h"
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
@ -44,10 +45,11 @@ static tools::ToolLoopManager::Pointer::Button button_from_msg(MouseMessage* msg
|
|||||||
tools::ToolLoopManager::Pointer::Left));
|
tools::ToolLoopManager::Pointer::Left));
|
||||||
}
|
}
|
||||||
|
|
||||||
static tools::ToolLoopManager::Pointer pointer_from_msg(MouseMessage* msg)
|
static tools::ToolLoopManager::Pointer pointer_from_msg(Editor* editor, MouseMessage* msg)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
tools::ToolLoopManager::Pointer(msg->position().x, msg->position().y, button_from_msg(msg));
|
tools::ToolLoopManager::Pointer(editor->screenToEditor(msg->position()),
|
||||||
|
button_from_msg(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawingState::DrawingState(tools::ToolLoop* toolLoop)
|
DrawingState::DrawingState(tools::ToolLoop* toolLoop)
|
||||||
@ -75,9 +77,33 @@ void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg)
|
|||||||
m_toolLoop->getFrame(),
|
m_toolLoop->getFrame(),
|
||||||
m_toolLoop->getDstImage());
|
m_toolLoop->getDstImage());
|
||||||
|
|
||||||
m_toolLoopManager->prepareLoop(pointer_from_msg(msg), msg->keyModifiers());
|
m_lastPoint = editor->lastDrawingPosition();
|
||||||
m_toolLoopManager->pressButton(pointer_from_msg(msg));
|
|
||||||
|
|
||||||
|
tools::ToolLoopManager::Pointer pointer;
|
||||||
|
bool movement = false;
|
||||||
|
|
||||||
|
if (m_toolLoop->getController()->isFreehand() &&
|
||||||
|
(editor->getCustomizationDelegate()
|
||||||
|
->getPressedKeyAction(KeyContext::FreehandTool) & KeyAction::StraightLineFromLastPoint) == KeyAction::StraightLineFromLastPoint &&
|
||||||
|
m_lastPoint.x >= 0) {
|
||||||
|
pointer = tools::ToolLoopManager::Pointer(m_lastPoint, button_from_msg(msg));
|
||||||
|
movement = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pointer = pointer_from_msg(editor, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_toolLoopManager->prepareLoop(pointer, msg->keyModifiers());
|
||||||
|
m_toolLoopManager->pressButton(pointer);
|
||||||
|
|
||||||
|
// This first movement is done when the user pressed Shift+click in
|
||||||
|
// a freehand tool to draw a straight line.
|
||||||
|
if (movement) {
|
||||||
|
pointer = pointer_from_msg(editor, msg);
|
||||||
|
m_toolLoopManager->movement(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
editor->setLastDrawingPosition(pointer.point());
|
||||||
editor->captureMouse();
|
editor->captureMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +113,7 @@ bool DrawingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
ASSERT(m_toolLoopManager != NULL);
|
ASSERT(m_toolLoopManager != NULL);
|
||||||
|
|
||||||
// Notify the mouse button down to the tool loop manager.
|
// Notify the mouse button down to the tool loop manager.
|
||||||
m_toolLoopManager->pressButton(pointer_from_msg(msg));
|
m_toolLoopManager->pressButton(pointer_from_msg(editor, msg));
|
||||||
|
|
||||||
// Cancel drawing loop
|
// Cancel drawing loop
|
||||||
if (m_toolLoopManager->isCanceled()) {
|
if (m_toolLoopManager->isCanceled()) {
|
||||||
@ -114,7 +140,7 @@ bool DrawingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
|||||||
// Notify the release of the mouse button to the tool loop
|
// Notify the release of the mouse button to the tool loop
|
||||||
// manager. This is the correct way to say "the user finishes the
|
// manager. This is the correct way to say "the user finishes the
|
||||||
// drawing trace correctly".
|
// drawing trace correctly".
|
||||||
if (m_toolLoopManager->releaseButton(pointer_from_msg(msg)))
|
if (m_toolLoopManager->releaseButton(pointer_from_msg(editor, msg)))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,12 +169,15 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
// Infinite scroll
|
// Infinite scroll
|
||||||
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir, true);
|
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir, true);
|
||||||
|
tools::ToolLoopManager::Pointer pointer(editor->screenToEditor(mousePos),
|
||||||
|
button_from_msg(msg));
|
||||||
|
|
||||||
// Notify mouse movement to the tool
|
// Notify mouse movement to the tool
|
||||||
ASSERT(m_toolLoopManager != NULL);
|
ASSERT(m_toolLoopManager != NULL);
|
||||||
m_toolLoopManager
|
m_toolLoopManager->movement(pointer);
|
||||||
->movement(tools::ToolLoopManager::Pointer(mousePos.x, mousePos.y,
|
|
||||||
button_from_msg(msg)));
|
// Save the last point.
|
||||||
|
editor->setLastDrawingPosition(pointer.point());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -203,8 +232,14 @@ void DrawingState::onExposeSpritePixels(const gfx::Region& rgn)
|
|||||||
|
|
||||||
void DrawingState::destroyLoop(Editor* editor)
|
void DrawingState::destroyLoop(Editor* editor)
|
||||||
{
|
{
|
||||||
if (editor)
|
if (editor) {
|
||||||
|
if (m_toolLoopManager &&
|
||||||
|
m_toolLoopManager->isCanceled()) {
|
||||||
|
editor->setLastDrawingPosition(m_lastPoint);
|
||||||
|
}
|
||||||
|
|
||||||
editor->renderEngine().removePreviewImage();
|
editor->renderEngine().removePreviewImage();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_toolLoop)
|
if (m_toolLoop)
|
||||||
m_toolLoop->dispose();
|
m_toolLoop->dispose();
|
||||||
|
@ -49,6 +49,11 @@ namespace app {
|
|||||||
// cancel selection tool (deselect) when the user click (press and
|
// cancel selection tool (deselect) when the user click (press and
|
||||||
// release the mouse button in the same location).
|
// release the mouse button in the same location).
|
||||||
bool m_mouseMoveReceived;
|
bool m_mouseMoveReceived;
|
||||||
|
|
||||||
|
// Stores the last drawing position before we start this
|
||||||
|
// DrawingState. It's used to restore the last drawing position in
|
||||||
|
// case this stroke is canceled.
|
||||||
|
gfx::Point m_lastPoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -152,6 +152,7 @@ Editor::Editor(Document* document, EditorFlags flags)
|
|||||||
, m_frame(frame_t(0))
|
, m_frame(frame_t(0))
|
||||||
, m_zoom(1, 1)
|
, m_zoom(1, 1)
|
||||||
, m_brushPreview(this)
|
, m_brushPreview(this)
|
||||||
|
, m_lastDrawingPosition(-1, -1)
|
||||||
, m_quicktool(NULL)
|
, m_quicktool(NULL)
|
||||||
, m_selectionMode(tools::SelectionMode::DEFAULT)
|
, m_selectionMode(tools::SelectionMode::DEFAULT)
|
||||||
, m_padding(0, 0)
|
, m_padding(0, 0)
|
||||||
@ -1384,6 +1385,11 @@ void Editor::setCursor(const gfx::Point& mouseScreenPos)
|
|||||||
showMouseCursor(kArrowCursor);
|
showMouseCursor(kArrowCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Editor::setLastDrawingPosition(const gfx::Point& pos)
|
||||||
|
{
|
||||||
|
m_lastDrawingPosition = pos;
|
||||||
|
}
|
||||||
|
|
||||||
bool Editor::canDraw()
|
bool Editor::canDraw()
|
||||||
{
|
{
|
||||||
return (m_layer != NULL &&
|
return (m_layer != NULL &&
|
||||||
|
@ -168,6 +168,9 @@ namespace app {
|
|||||||
|
|
||||||
bool isSecondaryButton() const { return m_secondaryButton; }
|
bool isSecondaryButton() const { return m_secondaryButton; }
|
||||||
|
|
||||||
|
gfx::Point lastDrawingPosition() const { return m_lastDrawingPosition; }
|
||||||
|
void setLastDrawingPosition(const gfx::Point& pos);
|
||||||
|
|
||||||
// Returns true if we are able to draw in the current doc/sprite/layer/cel.
|
// Returns true if we are able to draw in the current doc/sprite/layer/cel.
|
||||||
bool canDraw();
|
bool canDraw();
|
||||||
|
|
||||||
@ -258,6 +261,10 @@ namespace app {
|
|||||||
// Brush preview
|
// Brush preview
|
||||||
BrushPreview m_brushPreview;
|
BrushPreview m_brushPreview;
|
||||||
|
|
||||||
|
// Position used to draw straight lines using freehand tools + Shift key
|
||||||
|
// (EditorCustomizationDelegate::isStraightLineFromLastPoint() modifier)
|
||||||
|
gfx::Point m_lastDrawingPosition;
|
||||||
|
|
||||||
// Current selected quicktool (this genererally should be NULL if
|
// Current selected quicktool (this genererally should be NULL if
|
||||||
// the user is not pressing any keyboard key).
|
// the user is not pressing any keyboard key).
|
||||||
tools::Tool* m_quicktool;
|
tools::Tool* m_quicktool;
|
||||||
|
@ -195,10 +195,6 @@ public:
|
|||||||
tools::TracePolicy getTracePolicy() override { return m_tracePolicy; }
|
tools::TracePolicy getTracePolicy() override { return m_tracePolicy; }
|
||||||
doc::Remap* getShadingRemap() override { return m_shadingRemap; }
|
doc::Remap* getShadingRemap() override { return m_shadingRemap; }
|
||||||
|
|
||||||
gfx::Point screenToSprite(const gfx::Point& screenPoint) override {
|
|
||||||
return m_editor->screenToEditor(screenPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx::Region& getDirtyArea() override {
|
gfx::Region& getDirtyArea() override {
|
||||||
return m_dirtyArea;
|
return m_dirtyArea;
|
||||||
}
|
}
|
||||||
@ -213,6 +209,7 @@ public:
|
|||||||
void updateStatusBar(const char* text) override {
|
void updateStatusBar(const char* text) override {
|
||||||
StatusBar::instance()->setStatusText(0, text);
|
StatusBar::instance()->setStatusText(0, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -43,6 +43,7 @@ namespace {
|
|||||||
{ "AddSelection" , "Add Selection" , app::KeyAction::AddSelection },
|
{ "AddSelection" , "Add Selection" , app::KeyAction::AddSelection },
|
||||||
{ "SubtractSelection" , "Subtract Selection" , app::KeyAction::SubtractSelection },
|
{ "SubtractSelection" , "Subtract Selection" , app::KeyAction::SubtractSelection },
|
||||||
{ "AutoSelectLayer" , "Auto Select Layer" , app::KeyAction::AutoSelectLayer },
|
{ "AutoSelectLayer" , "Auto Select Layer" , app::KeyAction::AutoSelectLayer },
|
||||||
|
{ "StraightLineFromLastPoint", "Straight Line from Last Point", app::KeyAction::StraightLineFromLastPoint },
|
||||||
{ "LeftMouseButton" , "Trigger Left Mouse Button" , app::KeyAction::LeftMouseButton },
|
{ "LeftMouseButton" , "Trigger Left Mouse Button" , app::KeyAction::LeftMouseButton },
|
||||||
{ "RightMouseButton" , "Trigger Right Mouse Button" , app::KeyAction::RightMouseButton },
|
{ "RightMouseButton" , "Trigger Right Mouse Button" , app::KeyAction::RightMouseButton },
|
||||||
{ NULL , NULL , app::KeyAction::None }
|
{ NULL , NULL , app::KeyAction::None }
|
||||||
@ -158,6 +159,9 @@ Key::Key(KeyAction action)
|
|||||||
case KeyAction::AutoSelectLayer:
|
case KeyAction::AutoSelectLayer:
|
||||||
m_keycontext = KeyContext::MoveTool;
|
m_keycontext = KeyContext::MoveTool;
|
||||||
break;
|
break;
|
||||||
|
case KeyAction::StraightLineFromLastPoint:
|
||||||
|
m_keycontext = KeyContext::FreehandTool;
|
||||||
|
break;
|
||||||
case KeyAction::LeftMouseButton:
|
case KeyAction::LeftMouseButton:
|
||||||
m_keycontext = KeyContext::Any;
|
m_keycontext = KeyContext::Any;
|
||||||
break;
|
break;
|
||||||
@ -533,6 +537,9 @@ void KeyboardShortcuts::exportAccel(TiXmlElement& parent, Key* key, const ui::Ac
|
|||||||
case KeyContext::MoveTool:
|
case KeyContext::MoveTool:
|
||||||
keycontextStr = "MoveTool";
|
keycontextStr = "MoveTool";
|
||||||
break;
|
break;
|
||||||
|
case KeyContext::FreehandTool:
|
||||||
|
keycontextStr = "FreehandTool";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keycontextStr)
|
if (keycontextStr)
|
||||||
|
@ -38,6 +38,7 @@ namespace app {
|
|||||||
ScalingSelection,
|
ScalingSelection,
|
||||||
RotatingSelection,
|
RotatingSelection,
|
||||||
MoveTool,
|
MoveTool,
|
||||||
|
FreehandTool,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class KeySource {
|
enum class KeySource {
|
||||||
@ -54,17 +55,18 @@ namespace app {
|
|||||||
|
|
||||||
// TODO This should be called "KeyActionModifier" or something similar
|
// TODO This should be called "KeyActionModifier" or something similar
|
||||||
enum class KeyAction {
|
enum class KeyAction {
|
||||||
None = 0x00000000,
|
None = 0x00000000,
|
||||||
CopySelection = 0x00000001,
|
CopySelection = 0x00000001,
|
||||||
SnapToGrid = 0x00000002,
|
SnapToGrid = 0x00000002,
|
||||||
AngleSnap = 0x00000004,
|
AngleSnap = 0x00000004,
|
||||||
MaintainAspectRatio = 0x00000008,
|
MaintainAspectRatio = 0x00000008,
|
||||||
LockAxis = 0x00000010,
|
LockAxis = 0x00000010,
|
||||||
AddSelection = 0x00000020,
|
AddSelection = 0x00000020,
|
||||||
SubtractSelection = 0x00000040,
|
SubtractSelection = 0x00000040,
|
||||||
AutoSelectLayer = 0x00000080,
|
AutoSelectLayer = 0x00000080,
|
||||||
LeftMouseButton = 0x00000100,
|
LeftMouseButton = 0x00000100,
|
||||||
RightMouseButton = 0x00000200,
|
RightMouseButton = 0x00000200,
|
||||||
|
StraightLineFromLastPoint = 0x00000400
|
||||||
};
|
};
|
||||||
|
|
||||||
inline KeyAction operator&(KeyAction a, KeyAction b) {
|
inline KeyAction operator&(KeyAction a, KeyAction b) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user