mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-05 09:40:02 +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 -->
|
||||
<key action="AutoSelectLayer" shortcut="Ctrl" mac="Cmd" />
|
||||
|
||||
<!-- Modifiers for freehand tool controller -->
|
||||
<key action="StraightLineFromLastPoint" shortcut="Shift" />
|
||||
</actions>
|
||||
|
||||
</keyboard>
|
||||
|
@ -342,6 +342,9 @@ private:
|
||||
case KeyContext::MoveTool:
|
||||
text = "Move Tool: " + text;
|
||||
break;
|
||||
case KeyContext::FreehandTool:
|
||||
text = "Freehand Tools: " + text;
|
||||
break;
|
||||
}
|
||||
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
|
||||
|
||||
|
@ -212,9 +212,6 @@ namespace app {
|
||||
// Returns true if the loop was canceled by the user
|
||||
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
|
||||
// what must be updated in updateDirtyArea().
|
||||
virtual gfx::Region& getDirtyArea() = 0;
|
||||
@ -223,7 +220,6 @@ namespace app {
|
||||
virtual void updateDirtyArea() = 0;
|
||||
|
||||
virtual void updateStatusBar(const char* text) = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
|
@ -101,7 +101,7 @@ void ToolLoopManager::pressButton(const Pointer& pointer)
|
||||
}
|
||||
|
||||
// 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_oldPoint = spritePoint;
|
||||
snapToGrid(spritePoint);
|
||||
@ -122,7 +122,7 @@ bool ToolLoopManager::releaseButton(const Pointer& pointer)
|
||||
if (isCanceled())
|
||||
return false;
|
||||
|
||||
Point spritePoint = m_toolLoop->screenToSprite(Point(pointer.x(), pointer.y()));
|
||||
Point spritePoint = pointer.point();
|
||||
snapToGrid(spritePoint);
|
||||
|
||||
bool res = m_toolLoop->getController()->releaseButton(m_points, spritePoint);
|
||||
@ -144,7 +144,7 @@ void ToolLoopManager::movement(const Pointer& pointer)
|
||||
return;
|
||||
|
||||
// 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)
|
||||
m_toolLoop->setSpeed(spritePoint - m_oldPoint);
|
||||
m_oldPoint = spritePoint;
|
||||
|
@ -46,17 +46,16 @@ namespace app {
|
||||
enum Button { None, Left, Middle, Right };
|
||||
|
||||
Pointer()
|
||||
: m_x(0), m_y(0), m_button(None) { }
|
||||
: m_point(0, 0), m_button(None) { }
|
||||
|
||||
Pointer(int x, int y, Button button)
|
||||
: m_x(x), m_y(y), m_button(button) { }
|
||||
Pointer(const gfx::Point& point, Button button)
|
||||
: m_point(point), m_button(button) { }
|
||||
|
||||
int x() const { return m_x; }
|
||||
int y() const { return m_y; }
|
||||
const gfx::Point& point() const { return m_point; }
|
||||
Button getButton() const { return m_button; }
|
||||
|
||||
private:
|
||||
int m_x, m_y;
|
||||
gfx::Point m_point;
|
||||
Button m_button;
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "app/tools/tool_loop_manager.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/editor_customization_delegate.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "ui/message.h"
|
||||
@ -44,10 +45,11 @@ static tools::ToolLoopManager::Pointer::Button button_from_msg(MouseMessage* msg
|
||||
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
|
||||
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)
|
||||
@ -75,9 +77,33 @@ void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg)
|
||||
m_toolLoop->getFrame(),
|
||||
m_toolLoop->getDstImage());
|
||||
|
||||
m_toolLoopManager->prepareLoop(pointer_from_msg(msg), msg->keyModifiers());
|
||||
m_toolLoopManager->pressButton(pointer_from_msg(msg));
|
||||
m_lastPoint = editor->lastDrawingPosition();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -87,7 +113,7 @@ bool DrawingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
|
||||
// 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
|
||||
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
|
||||
// manager. This is the correct way to say "the user finishes the
|
||||
// drawing trace correctly".
|
||||
if (m_toolLoopManager->releaseButton(pointer_from_msg(msg)))
|
||||
if (m_toolLoopManager->releaseButton(pointer_from_msg(editor, msg)))
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -143,12 +169,15 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
|
||||
// Infinite scroll
|
||||
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
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
m_toolLoopManager
|
||||
->movement(tools::ToolLoopManager::Pointer(mousePos.x, mousePos.y,
|
||||
button_from_msg(msg)));
|
||||
m_toolLoopManager->movement(pointer);
|
||||
|
||||
// Save the last point.
|
||||
editor->setLastDrawingPosition(pointer.point());
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -203,8 +232,14 @@ void DrawingState::onExposeSpritePixels(const gfx::Region& rgn)
|
||||
|
||||
void DrawingState::destroyLoop(Editor* editor)
|
||||
{
|
||||
if (editor)
|
||||
if (editor) {
|
||||
if (m_toolLoopManager &&
|
||||
m_toolLoopManager->isCanceled()) {
|
||||
editor->setLastDrawingPosition(m_lastPoint);
|
||||
}
|
||||
|
||||
editor->renderEngine().removePreviewImage();
|
||||
}
|
||||
|
||||
if (m_toolLoop)
|
||||
m_toolLoop->dispose();
|
||||
|
@ -49,6 +49,11 @@ namespace app {
|
||||
// cancel selection tool (deselect) when the user click (press and
|
||||
// release the mouse button in the same location).
|
||||
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
|
||||
|
@ -152,6 +152,7 @@ Editor::Editor(Document* document, EditorFlags flags)
|
||||
, m_frame(frame_t(0))
|
||||
, m_zoom(1, 1)
|
||||
, m_brushPreview(this)
|
||||
, m_lastDrawingPosition(-1, -1)
|
||||
, m_quicktool(NULL)
|
||||
, m_selectionMode(tools::SelectionMode::DEFAULT)
|
||||
, m_padding(0, 0)
|
||||
@ -1384,6 +1385,11 @@ void Editor::setCursor(const gfx::Point& mouseScreenPos)
|
||||
showMouseCursor(kArrowCursor);
|
||||
}
|
||||
|
||||
void Editor::setLastDrawingPosition(const gfx::Point& pos)
|
||||
{
|
||||
m_lastDrawingPosition = pos;
|
||||
}
|
||||
|
||||
bool Editor::canDraw()
|
||||
{
|
||||
return (m_layer != NULL &&
|
||||
|
@ -168,6 +168,9 @@ namespace app {
|
||||
|
||||
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.
|
||||
bool canDraw();
|
||||
|
||||
@ -258,6 +261,10 @@ namespace app {
|
||||
// Brush preview
|
||||
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
|
||||
// the user is not pressing any keyboard key).
|
||||
tools::Tool* m_quicktool;
|
||||
|
@ -195,10 +195,6 @@ public:
|
||||
tools::TracePolicy getTracePolicy() override { return m_tracePolicy; }
|
||||
doc::Remap* getShadingRemap() override { return m_shadingRemap; }
|
||||
|
||||
gfx::Point screenToSprite(const gfx::Point& screenPoint) override {
|
||||
return m_editor->screenToEditor(screenPoint);
|
||||
}
|
||||
|
||||
gfx::Region& getDirtyArea() override {
|
||||
return m_dirtyArea;
|
||||
}
|
||||
@ -213,6 +209,7 @@ public:
|
||||
void updateStatusBar(const char* text) override {
|
||||
StatusBar::instance()->setStatusText(0, text);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -43,6 +43,7 @@ namespace {
|
||||
{ "AddSelection" , "Add Selection" , app::KeyAction::AddSelection },
|
||||
{ "SubtractSelection" , "Subtract Selection" , app::KeyAction::SubtractSelection },
|
||||
{ "AutoSelectLayer" , "Auto Select Layer" , app::KeyAction::AutoSelectLayer },
|
||||
{ "StraightLineFromLastPoint", "Straight Line from Last Point", app::KeyAction::StraightLineFromLastPoint },
|
||||
{ "LeftMouseButton" , "Trigger Left Mouse Button" , app::KeyAction::LeftMouseButton },
|
||||
{ "RightMouseButton" , "Trigger Right Mouse Button" , app::KeyAction::RightMouseButton },
|
||||
{ NULL , NULL , app::KeyAction::None }
|
||||
@ -158,6 +159,9 @@ Key::Key(KeyAction action)
|
||||
case KeyAction::AutoSelectLayer:
|
||||
m_keycontext = KeyContext::MoveTool;
|
||||
break;
|
||||
case KeyAction::StraightLineFromLastPoint:
|
||||
m_keycontext = KeyContext::FreehandTool;
|
||||
break;
|
||||
case KeyAction::LeftMouseButton:
|
||||
m_keycontext = KeyContext::Any;
|
||||
break;
|
||||
@ -533,6 +537,9 @@ void KeyboardShortcuts::exportAccel(TiXmlElement& parent, Key* key, const ui::Ac
|
||||
case KeyContext::MoveTool:
|
||||
keycontextStr = "MoveTool";
|
||||
break;
|
||||
case KeyContext::FreehandTool:
|
||||
keycontextStr = "FreehandTool";
|
||||
break;
|
||||
}
|
||||
|
||||
if (keycontextStr)
|
||||
|
@ -38,6 +38,7 @@ namespace app {
|
||||
ScalingSelection,
|
||||
RotatingSelection,
|
||||
MoveTool,
|
||||
FreehandTool,
|
||||
};
|
||||
|
||||
enum class KeySource {
|
||||
@ -54,17 +55,18 @@ namespace app {
|
||||
|
||||
// TODO This should be called "KeyActionModifier" or something similar
|
||||
enum class KeyAction {
|
||||
None = 0x00000000,
|
||||
CopySelection = 0x00000001,
|
||||
SnapToGrid = 0x00000002,
|
||||
AngleSnap = 0x00000004,
|
||||
MaintainAspectRatio = 0x00000008,
|
||||
LockAxis = 0x00000010,
|
||||
AddSelection = 0x00000020,
|
||||
SubtractSelection = 0x00000040,
|
||||
AutoSelectLayer = 0x00000080,
|
||||
LeftMouseButton = 0x00000100,
|
||||
RightMouseButton = 0x00000200,
|
||||
None = 0x00000000,
|
||||
CopySelection = 0x00000001,
|
||||
SnapToGrid = 0x00000002,
|
||||
AngleSnap = 0x00000004,
|
||||
MaintainAspectRatio = 0x00000008,
|
||||
LockAxis = 0x00000010,
|
||||
AddSelection = 0x00000020,
|
||||
SubtractSelection = 0x00000040,
|
||||
AutoSelectLayer = 0x00000080,
|
||||
LeftMouseButton = 0x00000100,
|
||||
RightMouseButton = 0x00000200,
|
||||
StraightLineFromLastPoint = 0x00000400
|
||||
};
|
||||
|
||||
inline KeyAction operator&(KeyAction a, KeyAction b) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user