mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 21:46:20 +00:00
Pencil: Shift key shows a real-time preview of a straight line (#1387)
This commit is contained in:
parent
34e794519c
commit
265d18635c
@ -8,6 +8,7 @@
|
||||
#define APP_TOOLS_CONTROLLER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/tools/trace_policy.h"
|
||||
#include "gfx/point.h"
|
||||
|
||||
#include <string>
|
||||
@ -28,6 +29,8 @@ namespace app {
|
||||
virtual bool isFreehand() { return false; }
|
||||
virtual bool isOnePoint() { return false; }
|
||||
|
||||
virtual void prepareController(ToolLoop* loop) { }
|
||||
|
||||
// Called when the user starts drawing and each time a new button is
|
||||
// pressed. The controller could be sure that this method is called
|
||||
// at least one time. The point is a position relative to sprite
|
||||
@ -47,6 +50,13 @@ namespace app {
|
||||
// Last point used by this controller, useful to save the last
|
||||
// point of a freehand tool.
|
||||
virtual gfx::Point getLastPoint() const { return gfx::Point(0, 0); }
|
||||
|
||||
// Special trace policy that can change in the middle of the
|
||||
// ToolLoop. This is for LineFreehandController which uses a
|
||||
// TracePolicy::Last for TwoPoints controller (Line-like tool)
|
||||
// and then a TracePolicy::Accumulate for freehand (Pencil tool).
|
||||
virtual bool handleTracePolicy() const { return false; }
|
||||
virtual TracePolicy getTracePolicy() const { return TracePolicy::Accumulate; }
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
|
@ -99,6 +99,10 @@ private:
|
||||
// Controls clicks for tools like line
|
||||
class TwoPointsController : public MoveOriginCapability {
|
||||
public:
|
||||
TwoPointsController(const bool enableModifiers)
|
||||
: m_enableModifiers(enableModifiers) {
|
||||
}
|
||||
|
||||
void pressButton(Stroke& stroke, const Point& point) override {
|
||||
MoveOriginCapability::pressButton(stroke, point);
|
||||
|
||||
@ -122,7 +126,8 @@ public:
|
||||
|
||||
stroke[1] = point;
|
||||
|
||||
if (int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect)) {
|
||||
if (m_enableModifiers &&
|
||||
(int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect))) {
|
||||
int dx = stroke[1].x - m_first.x;
|
||||
int dy = stroke[1].y - m_first.y;
|
||||
int minsize = MIN(ABS(dx), ABS(dy));
|
||||
@ -167,7 +172,8 @@ public:
|
||||
|
||||
stroke[0] = m_first;
|
||||
|
||||
if (int(loop->getModifiers()) & int(ToolLoopModifiers::kFromCenter)) {
|
||||
if (m_enableModifiers &&
|
||||
(int(loop->getModifiers()) & int(ToolLoopModifiers::kFromCenter))) {
|
||||
int rx = stroke[1].x - m_first.x;
|
||||
int ry = stroke[1].y - m_first.y;
|
||||
stroke[0].x = m_first.x - rx;
|
||||
@ -226,6 +232,7 @@ private:
|
||||
}
|
||||
|
||||
Point m_first;
|
||||
bool m_enableModifiers;
|
||||
};
|
||||
|
||||
// Controls clicks for tools like polygon
|
||||
@ -379,5 +386,64 @@ private:
|
||||
int m_clickCounter;
|
||||
};
|
||||
|
||||
// Controls the shift+click to draw a two-points line and then
|
||||
// freehand until the mouse is released.
|
||||
class LineFreehandController : public Controller {
|
||||
public:
|
||||
LineFreehandController() : m_twoPoints(false) { }
|
||||
|
||||
bool isFreehand() override { return true; }
|
||||
|
||||
gfx::Point getLastPoint() const override { return m_last; }
|
||||
|
||||
void prepareController(ToolLoop* loop) override {
|
||||
m_controller = nullptr;
|
||||
}
|
||||
|
||||
void pressButton(Stroke& stroke, const Point& point) override {
|
||||
m_last = point;
|
||||
|
||||
if (m_controller == nullptr)
|
||||
m_controller = &m_twoPoints;
|
||||
else if (m_controller == &m_twoPoints) {
|
||||
m_controller = &m_freehand;
|
||||
return; // Don't send first pressButton() click to the freehand controller
|
||||
}
|
||||
|
||||
m_controller->pressButton(stroke, point);
|
||||
}
|
||||
|
||||
bool releaseButton(Stroke& stroke, const Point& point) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void movement(ToolLoop* loop, Stroke& stroke, const Point& point) override {
|
||||
m_last = point;
|
||||
m_controller->movement(loop, stroke, point);
|
||||
}
|
||||
|
||||
void getStrokeToInterwine(const Stroke& input, Stroke& output) override {
|
||||
m_controller->getStrokeToInterwine(input, output);
|
||||
}
|
||||
|
||||
void getStatusBarText(const Stroke& stroke, std::string& text) override {
|
||||
m_controller->getStatusBarText(stroke, text);
|
||||
}
|
||||
|
||||
bool handleTracePolicy() const override {
|
||||
return (m_controller == &m_twoPoints);
|
||||
}
|
||||
|
||||
TracePolicy getTracePolicy() const override {
|
||||
return TracePolicy::Last;
|
||||
}
|
||||
|
||||
private:
|
||||
Point m_last;
|
||||
TwoPointsController m_twoPoints;
|
||||
FreehandController m_freehand;
|
||||
Controller* m_controller;
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
} // namespace app
|
||||
|
@ -69,6 +69,13 @@ const char* WellKnownInks::MoveSlice = "move_slice";
|
||||
const char* WellKnownInks::Blur = "blur";
|
||||
const char* WellKnownInks::Jumble = "jumble";
|
||||
|
||||
const char* WellKnownControllers::Freehand = "freehand";
|
||||
const char* WellKnownControllers::PointByPoint = "point_by_point";
|
||||
const char* WellKnownControllers::OnePoints = "one_point";
|
||||
const char* WellKnownControllers::TwoPoints = "two_points";
|
||||
const char* WellKnownControllers::FourPoints = "four_points";
|
||||
const char* WellKnownControllers::LineFreehand = "line_freehand";
|
||||
|
||||
const char* WellKnownIntertwiners::None = "none";
|
||||
const char* WellKnownIntertwiners::FirstPoint = "first_point";
|
||||
const char* WellKnownIntertwiners::AsLines = "as_lines";
|
||||
@ -105,11 +112,12 @@ ToolBox::ToolBox()
|
||||
m_inks[WellKnownInks::Blur] = new BlurInk();
|
||||
m_inks[WellKnownInks::Jumble] = new JumbleInk();
|
||||
|
||||
m_controllers["freehand"] = new FreehandController();
|
||||
m_controllers["point_by_point"] = new PointByPointController();
|
||||
m_controllers["one_point"] = new OnePointController();
|
||||
m_controllers["two_points"] = new TwoPointsController();
|
||||
m_controllers["four_points"] = new FourPointsController();
|
||||
m_controllers[WellKnownControllers::Freehand] = new FreehandController();
|
||||
m_controllers[WellKnownControllers::PointByPoint] = new PointByPointController();
|
||||
m_controllers[WellKnownControllers::OnePoints] = new OnePointController();
|
||||
m_controllers[WellKnownControllers::TwoPoints] = new TwoPointsController(true);
|
||||
m_controllers[WellKnownControllers::FourPoints] = new FourPointsController();
|
||||
m_controllers[WellKnownControllers::LineFreehand] = new LineFreehandController();
|
||||
|
||||
m_pointshapers[WellKnownPointShapes::None] = new NonePointShape();
|
||||
m_pointshapers[WellKnownPointShapes::Pixel] = new PixelPointShape();
|
||||
@ -161,6 +169,11 @@ Ink* ToolBox::getInkById(const std::string& id)
|
||||
return m_inks[id];
|
||||
}
|
||||
|
||||
Controller* ToolBox::getControllerById(const std::string& id)
|
||||
{
|
||||
return m_controllers[id];
|
||||
}
|
||||
|
||||
Intertwine* ToolBox::getIntertwinerById(const std::string& id)
|
||||
{
|
||||
return m_intertwiners[id];
|
||||
|
@ -52,6 +52,15 @@ namespace app {
|
||||
extern const char* Jumble;
|
||||
};
|
||||
|
||||
namespace WellKnownControllers {
|
||||
extern const char* Freehand;
|
||||
extern const char* PointByPoint;
|
||||
extern const char* OnePoints;
|
||||
extern const char* TwoPoints;
|
||||
extern const char* FourPoints;
|
||||
extern const char* LineFreehand;
|
||||
};
|
||||
|
||||
namespace WellKnownIntertwiners {
|
||||
extern const char* None;
|
||||
extern const char* FirstPoint;
|
||||
@ -92,6 +101,7 @@ namespace app {
|
||||
|
||||
Tool* getToolById(const std::string& id);
|
||||
Ink* getInkById(const std::string& id);
|
||||
Controller* getControllerById(const std::string& id);
|
||||
Intertwine* getIntertwinerById(const std::string& id);
|
||||
PointShape* getPointShapeById(const std::string& id);
|
||||
int getGroupsCount() const { return m_groups.size(); }
|
||||
|
@ -54,6 +54,7 @@ void ToolLoopManager::prepareLoop(const Pointer& pointer)
|
||||
|
||||
// Prepare the ink
|
||||
m_toolLoop->getInk()->prepareInk(m_toolLoop);
|
||||
m_toolLoop->getController()->prepareController(m_toolLoop);
|
||||
m_toolLoop->getIntertwine()->prepareIntertwine();
|
||||
m_toolLoop->getPointShape()->preparePointShape(m_toolLoop);
|
||||
}
|
||||
|
@ -39,10 +39,13 @@ namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
DrawingState::DrawingState(tools::ToolLoop* toolLoop)
|
||||
: m_toolLoop(toolLoop)
|
||||
DrawingState::DrawingState(tools::ToolLoop* toolLoop,
|
||||
const DrawingType type)
|
||||
: m_type(type)
|
||||
, m_toolLoop(toolLoop)
|
||||
, m_toolLoopManager(new tools::ToolLoopManager(toolLoop))
|
||||
, m_mouseMoveReceived(false)
|
||||
, m_mousePressedReceived(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -51,7 +54,8 @@ DrawingState::~DrawingState()
|
||||
destroyLoop(nullptr);
|
||||
}
|
||||
|
||||
void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg)
|
||||
void DrawingState::initToolLoop(Editor* editor,
|
||||
const tools::Pointer& pointer)
|
||||
{
|
||||
// Prepare preview image (the destination image will be our preview
|
||||
// in the tool-loop time, so we can see what we are drawing)
|
||||
@ -65,35 +69,18 @@ void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg)
|
||||
static_cast<LayerImage*>(m_toolLoop->getLayer())->blendMode():
|
||||
BlendMode::NEG_BW));
|
||||
|
||||
tools::Pointer pointer;
|
||||
bool movement = false;
|
||||
|
||||
if (m_toolLoop->getController()->isFreehand() &&
|
||||
m_toolLoop->getInk()->isPaint() &&
|
||||
(editor->getCustomizationDelegate()
|
||||
->getPressedKeyAction(KeyContext::FreehandTool) & KeyAction::StraightLineFromLastPoint) == KeyAction::StraightLineFromLastPoint &&
|
||||
editor->document()->lastDrawingPoint() != app::Document::NoLastDrawingPoint()) {
|
||||
pointer = tools::Pointer(editor->document()->lastDrawingPoint(),
|
||||
button_from_msg(msg));
|
||||
movement = true;
|
||||
}
|
||||
else {
|
||||
pointer = pointer_from_msg(editor, msg);
|
||||
}
|
||||
|
||||
m_toolLoopManager->prepareLoop(pointer);
|
||||
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->captureMouse();
|
||||
}
|
||||
|
||||
void DrawingState::sendMovementToToolLoop(const tools::Pointer& pointer)
|
||||
{
|
||||
ASSERT(m_toolLoopManager);
|
||||
m_toolLoopManager->movement(pointer);
|
||||
}
|
||||
|
||||
void DrawingState::notifyToolLoopModifiersChange(Editor* editor)
|
||||
{
|
||||
if (!m_toolLoopManager->isCanceled())
|
||||
@ -105,6 +92,8 @@ bool DrawingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
// Drawing loop
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
|
||||
m_mousePressedReceived = true;
|
||||
|
||||
// Notify the mouse button down to the tool loop manager.
|
||||
m_toolLoopManager->pressButton(pointer_from_msg(editor, msg));
|
||||
|
||||
@ -195,8 +184,15 @@ bool DrawingState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
|
||||
bool DrawingState::onKeyUp(Editor* editor, KeyMessage* msg)
|
||||
{
|
||||
if (msg->scancode() == ui::kKeyEsc)
|
||||
// Cancel loop pressing Esc key...
|
||||
if (msg->scancode() == ui::kKeyEsc ||
|
||||
// Cancel "Shift on freehand" line preview when the Shift key is
|
||||
// released and the user didn't press the mouse button..
|
||||
(m_type == DrawingType::LineFreehand &&
|
||||
!m_mousePressedReceived &&
|
||||
!editor->startStraightLineWithFreehandTool())) {
|
||||
m_toolLoop->cancel();
|
||||
}
|
||||
|
||||
// The user might have canceled the tool loop pressing the 'Esc' key.
|
||||
destroyLoopIfCanceled(editor);
|
||||
|
@ -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.
|
||||
@ -12,13 +12,15 @@
|
||||
|
||||
namespace app {
|
||||
namespace tools {
|
||||
class Pointer;
|
||||
class ToolLoop;
|
||||
class ToolLoopManager;
|
||||
}
|
||||
|
||||
class DrawingState : public StandbyState {
|
||||
public:
|
||||
DrawingState(tools::ToolLoop* loop);
|
||||
DrawingState(tools::ToolLoop* loop,
|
||||
const DrawingType type);
|
||||
virtual ~DrawingState();
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
@ -33,13 +35,21 @@ namespace app {
|
||||
// already drawing (viewing the real trace).
|
||||
virtual bool requireBrushPreview() override { return false; }
|
||||
|
||||
void initToolLoop(Editor* editor, ui::MouseMessage* msg);
|
||||
void initToolLoop(Editor* editor,
|
||||
const tools::Pointer& pointer);
|
||||
|
||||
// Used to send a movement() to the ToolLoopManager when
|
||||
// Shift+brush tool is used to paint a line.
|
||||
void sendMovementToToolLoop(const tools::Pointer& pointer);
|
||||
|
||||
void notifyToolLoopModifiersChange(Editor* editor);
|
||||
|
||||
private:
|
||||
void destroyLoopIfCanceled(Editor* editor);
|
||||
void destroyLoop(Editor* editor);
|
||||
|
||||
DrawingType m_type;
|
||||
|
||||
// The tool-loop.
|
||||
tools::ToolLoop* m_toolLoop;
|
||||
|
||||
@ -55,6 +65,12 @@ namespace app {
|
||||
// DrawingState. It's used to restore the last drawing position in
|
||||
// case this stroke is canceled.
|
||||
gfx::Point m_lastPoint;
|
||||
|
||||
// Used to know if the button was pressed after the DrawingState
|
||||
// was initialized. In this way we can cancel the ToolLoop if the
|
||||
// Shift press is used to draw a line, but then released without a
|
||||
// mouse click.
|
||||
bool m_mousePressedReceived;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/tools/active_tool.h"
|
||||
#include "app/tools/controller.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
@ -59,6 +60,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -1512,6 +1514,18 @@ app::Color Editor::getColorByPosition(const gfx::Point& mousePos)
|
||||
return app::Color::fromMask();
|
||||
}
|
||||
|
||||
bool Editor::startStraightLineWithFreehandTool()
|
||||
{
|
||||
tools::Tool* tool = App::instance()->activeToolManager()->selectedTool();
|
||||
return
|
||||
(tool &&
|
||||
tool->getController(0)->isFreehand() &&
|
||||
tool->getInk(0)->isPaint() &&
|
||||
(getCustomizationDelegate()
|
||||
->getPressedKeyAction(KeyContext::FreehandTool) & KeyAction::StraightLineFromLastPoint) == KeyAction::StraightLineFromLastPoint &&
|
||||
document()->lastDrawingPoint() != app::Document::NoLastDrawingPoint());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Message handler for the editor
|
||||
|
||||
|
@ -254,6 +254,10 @@ namespace app {
|
||||
void setTagFocusBand(int value) { m_tagFocusBand = value; }
|
||||
int tagFocusBand() const { return m_tagFocusBand; }
|
||||
|
||||
// Returns true if the Shift key to draw straight lines with a
|
||||
// freehand tool is pressed.
|
||||
bool startStraightLineWithFreehandTool();
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onSizeHint(ui::SizeHintEvent& ev) override;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "app/ui/editor/drawing_state.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/editor_customization_delegate.h"
|
||||
#include "app/ui/editor/glue.h"
|
||||
#include "app/ui/editor/handle_type.h"
|
||||
#include "app/ui/editor/moving_cel_state.h"
|
||||
#include "app/ui/editor/moving_pixels_state.h"
|
||||
@ -320,20 +321,9 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
if (layerEdges)
|
||||
layerEdgesOption(false);
|
||||
|
||||
// We need to clear and redraw the brush boundaries after the
|
||||
// first mouse pressed/point shape if drawn. This is to avoid
|
||||
// graphical glitches (invalid areas in the ToolLoop's src/dst
|
||||
// images).
|
||||
HideBrushPreview hide(editor->brushPreview());
|
||||
|
||||
tools::ToolLoop* toolLoop = create_tool_loop(editor, context);
|
||||
if (toolLoop) {
|
||||
EditorStatePtr newState(new DrawingState(toolLoop));
|
||||
editor->setState(newState);
|
||||
|
||||
static_cast<DrawingState*>(newState.get())
|
||||
->initToolLoop(editor, msg);
|
||||
}
|
||||
startDrawingState(editor,
|
||||
DrawingType::Regular,
|
||||
pointer_from_msg(editor, msg));
|
||||
|
||||
// Restore layer edges
|
||||
if (layerEdges)
|
||||
@ -497,6 +487,22 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
|
||||
bool StandbyState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
{
|
||||
// Start line preview with shift key
|
||||
if (editor->startStraightLineWithFreehandTool()) {
|
||||
DrawingState* drawingState =
|
||||
startDrawingState(editor,
|
||||
DrawingType::LineFreehand,
|
||||
tools::Pointer(
|
||||
editor->document()->lastDrawingPoint(),
|
||||
tools::Pointer::Left));
|
||||
if (drawingState) {
|
||||
drawingState->sendMovementToToolLoop(
|
||||
tools::Pointer(
|
||||
editor->screenToEditor(ui::get_mouse_position()),
|
||||
tools::Pointer::Left));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -586,6 +592,35 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
|
||||
return true;
|
||||
}
|
||||
|
||||
DrawingState* StandbyState::startDrawingState(Editor* editor,
|
||||
const DrawingType drawingType,
|
||||
const tools::Pointer& pointer)
|
||||
{
|
||||
// We need to clear and redraw the brush boundaries after the
|
||||
// first mouse pressed/point shape if drawn. This is to avoid
|
||||
// graphical glitches (invalid areas in the ToolLoop's src/dst
|
||||
// images).
|
||||
HideBrushPreview hide(editor->brushPreview());
|
||||
|
||||
tools::ToolLoop* toolLoop = create_tool_loop(
|
||||
editor,
|
||||
UIContext::instance(),
|
||||
(drawingType == DrawingType::LineFreehand));
|
||||
if (!toolLoop)
|
||||
return nullptr;
|
||||
|
||||
EditorStatePtr newState(
|
||||
new DrawingState(toolLoop,
|
||||
drawingType));
|
||||
editor->setState(newState);
|
||||
|
||||
static_cast<DrawingState*>(newState.get())
|
||||
->initToolLoop(editor,
|
||||
pointer);
|
||||
|
||||
return static_cast<DrawingState*>(newState.get());
|
||||
}
|
||||
|
||||
Transformation StandbyState::getTransformation(Editor* editor)
|
||||
{
|
||||
Transformation t = editor->document()->getTransformation();
|
||||
|
@ -17,12 +17,16 @@
|
||||
namespace app {
|
||||
namespace tools {
|
||||
class Ink;
|
||||
class Pointer;
|
||||
}
|
||||
|
||||
class DrawingState;
|
||||
class TransformHandles;
|
||||
|
||||
class StandbyState : public StateWithWheelBehavior {
|
||||
public:
|
||||
enum class DrawingType { Regular, LineFreehand };
|
||||
|
||||
StandbyState();
|
||||
virtual ~StandbyState();
|
||||
virtual void onEnterState(Editor* editor) override;
|
||||
@ -76,6 +80,9 @@ namespace app {
|
||||
};
|
||||
|
||||
private:
|
||||
DrawingState* startDrawingState(Editor* editor,
|
||||
const DrawingType drawingType,
|
||||
const tools::Pointer& pointer);
|
||||
void transformSelection(Editor* editor, ui::MouseMessage* msg, HandleType handle);
|
||||
void onPivotChange(Editor* editor);
|
||||
gfx::Rect resizeCelBounds(Editor* editor) const;
|
||||
|
@ -97,6 +97,7 @@ public:
|
||||
Layer* layer,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
tools::Controller* controller,
|
||||
Document* document,
|
||||
tools::ToolLoop::Button button,
|
||||
const app::Color& fgColor,
|
||||
@ -116,7 +117,7 @@ public:
|
||||
, m_contiguous(m_toolPref.contiguous())
|
||||
, m_button(button)
|
||||
, m_ink(ink->clone())
|
||||
, m_controller(m_tool->getController(m_button))
|
||||
, m_controller(controller)
|
||||
, m_pointShape(m_tool->getPointShape(m_button))
|
||||
, m_intertwine(m_tool->getIntertwine(m_button))
|
||||
, m_tracePolicy(m_tool->getTracePolicy(m_button))
|
||||
@ -243,7 +244,12 @@ public:
|
||||
tools::Controller* getController() override { return m_controller; }
|
||||
tools::PointShape* getPointShape() override { return m_pointShape; }
|
||||
tools::Intertwine* getIntertwine() override { return m_intertwine; }
|
||||
tools::TracePolicy getTracePolicy() override { return m_tracePolicy; }
|
||||
tools::TracePolicy getTracePolicy() override {
|
||||
if (m_controller->handleTracePolicy())
|
||||
return m_controller->getTracePolicy();
|
||||
else
|
||||
return m_tracePolicy;
|
||||
}
|
||||
tools::Symmetry* getSymmetry() override { return m_symmetry.get(); }
|
||||
doc::Remap* getShadingRemap() override { return m_shadingRemap; }
|
||||
|
||||
@ -293,6 +299,7 @@ class ToolLoopImpl : public ToolLoopBase {
|
||||
Transaction m_transaction;
|
||||
ExpandCelCanvas* m_expandCelCanvas;
|
||||
Image* m_floodfillSrcImage;
|
||||
bool m_saveLastPoint;
|
||||
|
||||
public:
|
||||
ToolLoopImpl(Editor* editor,
|
||||
@ -300,12 +307,21 @@ public:
|
||||
Context* context,
|
||||
tools::Tool* tool,
|
||||
tools::Ink* ink,
|
||||
tools::Controller* controller,
|
||||
Document* document,
|
||||
tools::ToolLoop::Button button,
|
||||
const app::Color& fgColor,
|
||||
const app::Color& bgColor)
|
||||
: ToolLoopBase(editor, layer, tool, ink, document,
|
||||
button, fgColor, bgColor)
|
||||
const app::Color& bgColor,
|
||||
const bool saveLastPoint)
|
||||
: ToolLoopBase(editor,
|
||||
layer,
|
||||
tool,
|
||||
ink,
|
||||
controller,
|
||||
document,
|
||||
button,
|
||||
fgColor,
|
||||
bgColor)
|
||||
, m_context(context)
|
||||
, m_canceled(false)
|
||||
, m_transaction(m_context,
|
||||
@ -318,6 +334,7 @@ public:
|
||||
ModifyDocument))
|
||||
, m_expandCelCanvas(nullptr)
|
||||
, m_floodfillSrcImage(nullptr)
|
||||
, m_saveLastPoint(saveLastPoint)
|
||||
{
|
||||
ASSERT(m_context->activeDocument() == m_editor->document());
|
||||
|
||||
@ -414,15 +431,16 @@ public:
|
||||
bool redraw = false;
|
||||
|
||||
if (!m_canceled) {
|
||||
// Paint ink
|
||||
if (getInk()->isPaint()) {
|
||||
// Freehand changes the last point
|
||||
if (getController()->isFreehand())
|
||||
if (m_saveLastPoint) {
|
||||
m_transaction.execute(
|
||||
new cmd::SetLastPoint(
|
||||
m_document,
|
||||
getController()->getLastPoint()));
|
||||
}
|
||||
|
||||
// Paint ink
|
||||
if (getInk()->isPaint()) {
|
||||
try {
|
||||
ContextReader reader(m_context, 500);
|
||||
ContextWriter writer(reader, 500);
|
||||
@ -512,12 +530,15 @@ public:
|
||||
|
||||
};
|
||||
|
||||
tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
||||
tools::ToolLoop* create_tool_loop(
|
||||
Editor* editor,
|
||||
Context* context,
|
||||
const bool convertLineToFreehand)
|
||||
{
|
||||
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
||||
tools::Ink* current_ink = editor->getCurrentEditorInk();
|
||||
if (!current_tool || !current_ink)
|
||||
return NULL;
|
||||
tools::Tool* tool = editor->getCurrentEditorTool();
|
||||
tools::Ink* ink = editor->getCurrentEditorInk();
|
||||
if (!tool || !ink)
|
||||
return nullptr;
|
||||
|
||||
Layer* layer;
|
||||
|
||||
@ -530,8 +551,8 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
||||
// Anyway this cannot be used in 'magic wand' tool (isSelection +
|
||||
// isFloodFill) because we need the original layer source
|
||||
// image/pixels to stop the flood-fill algorithm.
|
||||
if (current_ink->isSelection() &&
|
||||
!current_tool->getPointShape(editor->isSecondaryButton() ? 1: 0)->isFloodFill()) {
|
||||
if (ink->isSelection() &&
|
||||
!tool->getPointShape(editor->isSecondaryButton() ? 1: 0)->isFloodFill()) {
|
||||
layer = nullptr;
|
||||
}
|
||||
else {
|
||||
@ -578,13 +599,30 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context)
|
||||
|
||||
// Create the new tool loop
|
||||
try {
|
||||
tools::ToolLoop::Button button =
|
||||
(!editor->isSecondaryButton() ? tools::ToolLoop::Left:
|
||||
tools::ToolLoop::Right);
|
||||
|
||||
tools::Controller* controller =
|
||||
(convertLineToFreehand ?
|
||||
App::instance()->toolBox()->getControllerById(
|
||||
tools::WellKnownControllers::LineFreehand):
|
||||
tool->getController(button));
|
||||
|
||||
const bool saveLastPoint =
|
||||
(ink->isPaint() &&
|
||||
(controller->isFreehand() ||
|
||||
convertLineToFreehand));
|
||||
|
||||
return new ToolLoopImpl(
|
||||
editor, layer, context,
|
||||
current_tool,
|
||||
current_ink,
|
||||
tool,
|
||||
ink,
|
||||
controller,
|
||||
editor->document(),
|
||||
!editor->isSecondaryButton() ? tools::ToolLoop::Left: tools::ToolLoop::Right,
|
||||
fg, bg);
|
||||
button,
|
||||
fg, bg,
|
||||
saveLastPoint);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
Alert::show(PACKAGE
|
||||
@ -612,8 +650,15 @@ public:
|
||||
const app::Color& bgColor,
|
||||
Image* image,
|
||||
const gfx::Point& celOrigin)
|
||||
: ToolLoopBase(editor, editor->layer(), tool, ink, document,
|
||||
tools::ToolLoop::Left, fgColor, bgColor)
|
||||
: ToolLoopBase(editor,
|
||||
editor->layer(),
|
||||
tool,
|
||||
ink,
|
||||
tool->getController(tools::ToolLoop::Left),
|
||||
document,
|
||||
tools::ToolLoop::Left,
|
||||
fgColor,
|
||||
bgColor)
|
||||
, m_image(image)
|
||||
{
|
||||
m_celOrigin = celOrigin;
|
||||
@ -661,9 +706,9 @@ tools::ToolLoop* create_tool_loop_preview(
|
||||
Editor* editor, Image* image,
|
||||
const gfx::Point& celOrigin)
|
||||
{
|
||||
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
||||
tools::Ink* current_ink = editor->getCurrentEditorInk();
|
||||
if (!current_tool || !current_ink)
|
||||
tools::Tool* tool = editor->getCurrentEditorTool();
|
||||
tools::Ink* ink = editor->getCurrentEditorInk();
|
||||
if (!tool || !ink)
|
||||
return NULL;
|
||||
|
||||
Layer* layer = editor->layer();
|
||||
@ -685,8 +730,8 @@ tools::ToolLoop* create_tool_loop_preview(
|
||||
try {
|
||||
return new PreviewToolLoopImpl(
|
||||
editor,
|
||||
current_tool,
|
||||
current_ink,
|
||||
tool,
|
||||
ink,
|
||||
editor->document(),
|
||||
fg, bg, image, celOrigin);
|
||||
}
|
||||
|
@ -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.
|
||||
@ -24,10 +24,13 @@ namespace app {
|
||||
}
|
||||
|
||||
tools::ToolLoop* create_tool_loop(
|
||||
Editor* editor, Context* context);
|
||||
Editor* editor,
|
||||
Context* context,
|
||||
const bool convertLineToFreehand);
|
||||
|
||||
tools::ToolLoop* create_tool_loop_preview(
|
||||
Editor* editor, doc::Image* image,
|
||||
Editor* editor,
|
||||
doc::Image* image,
|
||||
const gfx::Point& celOrigin);
|
||||
|
||||
} // namespace app
|
||||
|
Loading…
Reference in New Issue
Block a user