mirror of https://github.com/aseprite/aseprite.git
Compare commits
3 Commits
523d9c75de
...
6df09c554b
Author | SHA1 | Date |
---|---|---|
|
6df09c554b | |
|
2ba051b59b | |
|
c98a2056e5 |
|
@ -705,6 +705,7 @@ target_sources(app-lib PRIVATE
|
|||
util/filetoks.cpp
|
||||
util/layer_boundaries.cpp
|
||||
util/layer_utils.cpp
|
||||
util/moving_utils.cpp
|
||||
util/msk_file.cpp
|
||||
util/new_image_from_mask.cpp
|
||||
util/open_file_job.cpp
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "app/util/tile_flags_utils.h"
|
||||
#include "base/chrono.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/doc.h"
|
||||
#include "doc/mask_boundaries.h"
|
||||
#include "doc/slice.h"
|
||||
|
@ -266,6 +267,23 @@ void Editor::setStateInternal(const EditorStatePtr& newState)
|
|||
{
|
||||
m_brushPreview.hide();
|
||||
|
||||
// Some onLeaveState impls (like the ones from MovingPixelsState,
|
||||
// WritingTextState, MovingSelectionState) might generate a
|
||||
// Tx/Transaction::commit(), which will add a new undo state,
|
||||
// triggering a sprite change scripting event
|
||||
// (SpriteEvents::onAddUndoState). This event could be handled by an
|
||||
// extension and that extension might want to save the current
|
||||
// sprite (e.g. calling Sprite_saveCopyAs, the kind of extension
|
||||
// that takes snapshots after each sprite change). That will be a
|
||||
// new Context::executeCommand() for the save command, generating a
|
||||
// BeforeCommandExecution signal, getting back to onLeaveState
|
||||
// again. In that case, we just ignore the reentry as the first
|
||||
// onLeaveState should handle everything (to avoid an stack
|
||||
// overflow/infinite recursion).
|
||||
if (m_leavingState)
|
||||
return;
|
||||
base::ScopedValue leaving(m_leavingState, true);
|
||||
|
||||
// Fire before change state event, set the state, and fire after
|
||||
// change state event.
|
||||
EditorState::LeaveAction leaveAction = m_state->onLeaveState(this, newState.get());
|
||||
|
|
|
@ -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
|
||||
|
@ -458,6 +458,13 @@ private:
|
|||
|
||||
DocView* m_docView;
|
||||
|
||||
// Special flag to avoid re-entering a new state when we are leaving
|
||||
// the current one. This avoids an infinite onLeaveState() recursion
|
||||
// in some special cases when an extension (third-party code)
|
||||
// creates a new sprite change in the same sprite change scripting
|
||||
// event.
|
||||
bool m_leavingState = false;
|
||||
|
||||
// Last known mouse position received by this editor when the
|
||||
// mouse button was pressed. Used for auto-scrolling. To get the
|
||||
// current mouse position on the editor you can use
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -247,14 +247,10 @@ void MovingCelState::onCommitMouseMove(Editor* editor, const gfx::PointF& newCur
|
|||
m_celOffset = newCursorPos - m_cursorStart;
|
||||
if (int(editor->getCustomizationDelegate()->getPressedKeyAction(
|
||||
KeyContext::TranslatingSelection) &
|
||||
KeyAction::LockAxis)) {
|
||||
if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) {
|
||||
m_celOffset.x = 0;
|
||||
}
|
||||
else {
|
||||
m_celOffset.y = 0;
|
||||
}
|
||||
}
|
||||
KeyAction::LockAxis))
|
||||
app::lockAxis(m_lockedAxis, m_celOffset);
|
||||
else
|
||||
m_lockedAxis = NONE;
|
||||
if (!m_moved && intCelOffset() != gfx::Point(0, 0))
|
||||
m_moved = true;
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2021-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2021-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -14,6 +14,7 @@
|
|||
#include "app/context_access.h"
|
||||
#include "app/ui/editor/delayed_mouse_move.h"
|
||||
#include "app/ui/editor/handle_type.h"
|
||||
#include "app/util/moving_utils.h"
|
||||
#include "doc/cel_list.h"
|
||||
|
||||
#include <vector>
|
||||
|
@ -80,6 +81,7 @@ private:
|
|||
gfx::PointF m_celOffset;
|
||||
gfx::SizeF m_celMainSize;
|
||||
gfx::SizeF m_celScale;
|
||||
LockedAxis m_lockedAxis;
|
||||
bool m_maskVisible;
|
||||
bool m_hasReference = false;
|
||||
bool m_moved = false;
|
||||
|
|
|
@ -376,6 +376,7 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
|
|||
switch (m_handle) {
|
||||
case MovePixelsHandle: {
|
||||
double dx, dy;
|
||||
const bool isLockAxis = ((moveModifier & LockAxisMovement) == LockAxisMovement);
|
||||
if (tilesModeOn) {
|
||||
if (m_catchPos.x == 0 && m_catchPos.y == 0) {
|
||||
// Movement through keyboard:
|
||||
|
@ -393,7 +394,8 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
|
|||
dy = point.y;
|
||||
}
|
||||
}
|
||||
else if ((moveModifier & FineControl) == 0) {
|
||||
// FineControl is discarded if 'Locked Axis' is active
|
||||
else if (isLockAxis || ((moveModifier & FineControl) == 0)) {
|
||||
dx = (std::floor(pos.x) - std::floor(m_catchPos.x));
|
||||
dy = (std::floor(pos.y) - std::floor(m_catchPos.y));
|
||||
}
|
||||
|
@ -402,12 +404,10 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
|
|||
dy = (pos.y - m_catchPos.y);
|
||||
}
|
||||
|
||||
if ((moveModifier & LockAxisMovement) == LockAxisMovement) {
|
||||
if (std::abs(dx) < std::abs(dy))
|
||||
dx = 0.0;
|
||||
else
|
||||
dy = 0.0;
|
||||
}
|
||||
if (isLockAxis)
|
||||
lockAxis(m_lockedAxis, dx, dy);
|
||||
else
|
||||
m_lockedAxis = LockedAxis::NONE;
|
||||
|
||||
bounds.offset(dx, dy);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -15,6 +15,7 @@
|
|||
#include "app/transformation.h"
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/editor/handle_type.h"
|
||||
#include "app/util/moving_utils.h"
|
||||
#include "doc/algorithm/flip_type.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_ref.h"
|
||||
|
@ -190,6 +191,7 @@ private:
|
|||
Transformation m_currentData;
|
||||
std::unique_ptr<Mask> m_initialMask, m_initialMask0;
|
||||
std::unique_ptr<Mask> m_currentMask;
|
||||
LockedAxis m_lockedAxis;
|
||||
bool m_opaque;
|
||||
color_t m_maskColor;
|
||||
obs::scoped_connection m_pivotVisConn;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#include "app/util/moving_utils.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace app {
|
||||
|
||||
void lockAxis(LockedAxis& lockedAxis, gfx::PointF& delta)
|
||||
{
|
||||
double dx = delta.x;
|
||||
double dy = delta.y;
|
||||
lockAxis(lockedAxis, dx, dy);
|
||||
delta.x = dx;
|
||||
delta.y = dy;
|
||||
}
|
||||
|
||||
void lockAxis(LockedAxis& lockedAxis, double& dx, double& dy)
|
||||
{
|
||||
if (lockedAxis == LockedAxis::NONE) {
|
||||
if (std::abs(dx) * 3 > std::abs(dy) * 7) {
|
||||
lockedAxis = LockedAxis::Y;
|
||||
dy = 0.0;
|
||||
}
|
||||
else if (std::abs(dy) * 3 > std::abs(dx) * 7) {
|
||||
lockedAxis = LockedAxis::X;
|
||||
dx = 0.0;
|
||||
}
|
||||
else {
|
||||
const bool sameSign = std::signbit(dx) == std::signbit(dy);
|
||||
lockedAxis = sameSign ? LockedAxis::R_DIAG : LockedAxis::L_DIAG;
|
||||
dy = sameSign ? dx : -dx;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (lockedAxis) {
|
||||
case LockedAxis::X: dx = 0.0; break;
|
||||
case LockedAxis::Y: dy = 0.0; break;
|
||||
case LockedAxis::R_DIAG: dy = dx; break;
|
||||
case LockedAxis::L_DIAG: dy = -dx; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
|
@ -0,0 +1,29 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2025 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UTIL_MOVING_UTILS_H_INCLUDED
|
||||
#define APP_UTIL_MOVING_UTILS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/point.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
enum LockedAxis {
|
||||
NONE,
|
||||
X,
|
||||
Y,
|
||||
R_DIAG,
|
||||
L_DIAG,
|
||||
};
|
||||
|
||||
void lockAxis(LockedAxis& lockedAxis, gfx::PointF& delta);
|
||||
|
||||
void lockAxis(LockedAxis& lockedAxis, double& dx, double& dy);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif // APP_UTIL_MOVING_UTILS_H_INCLUDED
|
Loading…
Reference in New Issue