Fix "Straight Line from Last Point” bug in Tilemaps (fix #4623)

Prior to this fix, when the following conditions were met:
- On a tilemap layer
- Tilemap mode = OFF
- Tool = Pencil
- Tileset mode = Manual
- Modifying an existing tile with the "quick line"
  (i.e. holding down the SHIFT key)
resulted in incorrect tool behavior.
This commit is contained in:
Gaspar Capello 2025-01-23 15:03:45 -03:00
parent 3aa403d597
commit d4845ee96c

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2024 Igara Studio S.A.
// Copyright (C) 2018-2025 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -74,12 +74,6 @@ public:
};
class IntertwineAsLines : public Intertwine {
// It was introduced to know if joinStroke function
// was executed inmediatelly after a "Last" trace policy (i.e. after the
// user confirms a line draw while he is holding down the SHIFT key), so
// we have to ignore printing the first pixel of the line.
bool m_retainedTracePolicyLast = false;
// In freehand-like tools, on each mouse movement we draw only the
// line between the last two mouse points in the stroke (the
// complete stroke is not re-painted again), so we want to indicate
@ -90,22 +84,10 @@ class IntertwineAsLines : public Intertwine {
public:
bool snapByAngle() override { return true; }
void prepareIntertwine(ToolLoop* loop) override
{
m_retainedTracePolicyLast = false;
m_firstStroke = true;
}
void prepareIntertwine(ToolLoop* loop) override { m_firstStroke = true; }
void joinStroke(ToolLoop* loop, const Stroke& stroke) override
{
// Required for LineFreehand controller in the first stage, when
// we are drawing the line and the trace policy is "Last". Each
// new joinStroke() is like a fresh start. Without this fix, the
// first stage on LineFreehand will draw a "star" like pattern
// with lines from the first point to the last point.
if (loop->getTracePolicy() == TracePolicy::Last)
m_retainedTracePolicyLast = true;
if (stroke.size() == 0)
return;
else if (stroke.size() == 1) {
@ -129,9 +111,10 @@ public:
// when we use Shift+click in the Pencil tool to continue the
// old stroke).
// TODO useful only in the case when brush size = 1px
const int start =
(loop->getController()->isFreehand() && (m_retainedTracePolicyLast || !m_firstStroke) ? 1 :
0);
const int start = (loop->getController()->isFreehand() &&
((loop->getTracePolicy() == TracePolicy::Last) || !m_firstStroke) ?
1 :
0);
for (int c = start; c < pts.size(); ++c)
doPointshapeStrokePt(pts[c], loop);
@ -442,11 +425,6 @@ public:
};
class IntertwineAsPixelPerfect : public Intertwine {
// It was introduced to know if joinStroke function
// was executed inmediatelly after a "Last" trace policy (i.e. after the
// user confirms a line draw while he is holding down the SHIFT key), so
// we have to ignore printing the first pixel of the line.
bool m_retainedTracePolicyLast = false;
Stroke m_pts;
bool m_saveStrokeArea = false;
@ -483,7 +461,6 @@ public:
void prepareIntertwine(ToolLoop* loop) override
{
m_pts.reset();
m_retainedTracePolicyLast = false;
m_grid = m_dstGrid = m_celGrid = loop->getGrid();
m_restoredRegion.clear();
@ -509,10 +486,8 @@ public:
// new joinStroke() is like a fresh start. Without this fix, the
// first stage on LineFreehand will draw a "star" like pattern
// with lines from the first point to the last point.
if (loop->getTracePolicy() == TracePolicy::Last) {
m_retainedTracePolicyLast = true;
if (loop->getTracePolicy() == TracePolicy::Last)
m_pts.reset();
}
int thirdFromLastPt = 0, nextPt = 0;
@ -572,14 +547,17 @@ public:
// a joinStroke pass with a retained "Last" trace policy
// (i.e. the user confirms draw a line while he is holding
// the SHIFT key))
if (c == 0 && m_retainedTracePolicyLast)
if (c == 0 && loop->getTracePolicy() == TracePolicy::Last)
continue;
// For the last point we need to store the source image content at that
// point so we can restore it when erasing a point because of
// pixel-perfect. So we set the following flag to indicate this, and
// use it in doTransformPoint.
m_saveStrokeArea = (c == m_pts.size() - 1);
// The previous behavior isn't required for LineFreehand controller and
// the trace policy is "Last" (i.e. the user is drawing a line while
// he is holding the SHIFT key)
m_saveStrokeArea = ((c == m_pts.size() - 1) && loop->getTracePolicy() != TracePolicy::Last);
if (m_saveStrokeArea) {
clearPointshapeStrokePtAreas();
setLastPtIndex(c);