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:
David Capello 2015-09-16 12:19:10 -03:00
parent c674c474f6
commit 8aefa24a5b
12 changed files with 98 additions and 38 deletions

View File

@ -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>

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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();

View File

@ -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

View File

@ -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 &&

View File

@ -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;

View File

@ -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);
}
};
//////////////////////////////////////////////////////////////////////

View File

@ -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)

View File

@ -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) {