Compare commits

...

3 Commits

Author SHA1 Message Date
Gaspar Capello fa842311f1
Merge c98a2056e5 into 4bb9239f50 2025-08-02 15:01:24 -05:00
Christian Kaiser 4bb9239f50 [lua] Add `resizeable` property to Dialog constructor (fix #5177)
build / build (Debug, macos-latest, lua, cli) (push) Has been cancelled Details
build / build (Debug, macos-latest, noscripts, cli) (push) Has been cancelled Details
build / build (Debug, ubuntu-latest, lua, cli) (push) Has been cancelled Details
build / build (Debug, ubuntu-latest, noscripts, cli) (push) Has been cancelled Details
build / build (Debug, windows-latest, lua, cli) (push) Has been cancelled Details
build / build (Debug, windows-latest, noscripts, cli) (push) Has been cancelled Details
build / build (RelWithDebInfo, macos-latest, lua, gui) (push) Has been cancelled Details
build / build (RelWithDebInfo, ubuntu-latest, lua, gui) (push) Has been cancelled Details
build / build (RelWithDebInfo, windows-latest, lua, gui) (push) Has been cancelled Details
2025-08-01 18:57:50 -03:00
Gaspar Capello c98a2056e5 Add Lock Axis alternative (fix #5251)
The lock axis is selected and held as soon as SHIFT is pressed.
A diagonal translation lock has also been added.
2025-07-04 15:54:49 -03:00
8 changed files with 106 additions and 20 deletions

View File

@ -705,6 +705,7 @@ target_sources(app-lib PRIVATE
util/filetoks.cpp util/filetoks.cpp
util/layer_boundaries.cpp util/layer_boundaries.cpp
util/layer_utils.cpp util/layer_utils.cpp
util/moving_utils.cpp
util/msk_file.cpp util/msk_file.cpp
util/new_image_from_mask.cpp util/new_image_from_mask.cpp
util/open_file_job.cpp util/open_file_job.cpp

View File

@ -127,12 +127,13 @@ struct Dialog {
int showRef = LUA_REFNIL; int showRef = LUA_REFNIL;
lua_State* L = nullptr; lua_State* L = nullptr;
Dialog(const ui::Window::Type windowType, const std::string& title) Dialog(const ui::Window::Type windowType, const std::string& title, bool sizeable)
: window(windowType, title) : window(windowType, title)
, grid(2, false) , grid(2, false)
, currentGrid(&grid) , currentGrid(&grid)
{ {
window.addChild(&grid); window.addChild(&grid);
window.setSizeable(sizeable);
all_dialogs.push_back(this); all_dialogs.push_back(this);
} }
@ -365,6 +366,7 @@ int Dialog_new(lua_State* L)
// Get the title and the type of window (with or without title bar) // Get the title and the type of window (with or without title bar)
ui::Window::Type windowType = ui::Window::WithTitleBar; ui::Window::Type windowType = ui::Window::WithTitleBar;
std::string title = "Script"; std::string title = "Script";
bool sizeable = true;
if (lua_isstring(L, 1)) { if (lua_isstring(L, 1)) {
title = lua_tostring(L, 1); title = lua_tostring(L, 1);
} }
@ -378,9 +380,14 @@ int Dialog_new(lua_State* L)
if (type != LUA_TNIL && lua_toboolean(L, -1)) if (type != LUA_TNIL && lua_toboolean(L, -1))
windowType = ui::Window::WithoutTitleBar; windowType = ui::Window::WithoutTitleBar;
lua_pop(L, 1); lua_pop(L, 1);
type = lua_getfield(L, 1, "resizeable");
if (type != LUA_TNIL && !lua_toboolean(L, -1))
sizeable = false;
lua_pop(L, 1);
} }
auto dlg = push_new<Dialog>(L, windowType, title); auto dlg = push_new<Dialog>(L, windowType, title, sizeable);
// The uservalue of the dialog userdata will contain a table that // The uservalue of the dialog userdata will contain a table that
// stores all the callbacks to handle events. As these callbacks can // stores all the callbacks to handle events. As these callbacks can

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020-2023 Igara Studio S.A. // Copyright (C) 2020-2025 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // 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; m_celOffset = newCursorPos - m_cursorStart;
if (int(editor->getCustomizationDelegate()->getPressedKeyAction( if (int(editor->getCustomizationDelegate()->getPressedKeyAction(
KeyContext::TranslatingSelection) & KeyContext::TranslatingSelection) &
KeyAction::LockAxis)) { KeyAction::LockAxis))
if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) { app::lockAxis(m_lockedAxis, m_celOffset);
m_celOffset.x = 0; else
} m_lockedAxis = NONE;
else {
m_celOffset.y = 0;
}
}
if (!m_moved && intCelOffset() != gfx::Point(0, 0)) if (!m_moved && intCelOffset() != gfx::Point(0, 0))
m_moved = true; m_moved = true;
break; break;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2021-2022 Igara Studio S.A. // Copyright (C) 2021-2025 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -14,6 +14,7 @@
#include "app/context_access.h" #include "app/context_access.h"
#include "app/ui/editor/delayed_mouse_move.h" #include "app/ui/editor/delayed_mouse_move.h"
#include "app/ui/editor/handle_type.h" #include "app/ui/editor/handle_type.h"
#include "app/util/moving_utils.h"
#include "doc/cel_list.h" #include "doc/cel_list.h"
#include <vector> #include <vector>
@ -80,6 +81,7 @@ private:
gfx::PointF m_celOffset; gfx::PointF m_celOffset;
gfx::SizeF m_celMainSize; gfx::SizeF m_celMainSize;
gfx::SizeF m_celScale; gfx::SizeF m_celScale;
LockedAxis m_lockedAxis;
bool m_maskVisible; bool m_maskVisible;
bool m_hasReference = false; bool m_hasReference = false;
bool m_moved = false; bool m_moved = false;

View File

@ -376,6 +376,7 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
switch (m_handle) { switch (m_handle) {
case MovePixelsHandle: { case MovePixelsHandle: {
double dx, dy; double dx, dy;
const bool isLockAxis = ((moveModifier & LockAxisMovement) == LockAxisMovement);
if (tilesModeOn) { if (tilesModeOn) {
if (m_catchPos.x == 0 && m_catchPos.y == 0) { if (m_catchPos.x == 0 && m_catchPos.y == 0) {
// Movement through keyboard: // Movement through keyboard:
@ -393,7 +394,8 @@ void PixelsMovement::moveImage(const gfx::PointF& pos, MoveModifier moveModifier
dy = point.y; 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)); dx = (std::floor(pos.x) - std::floor(m_catchPos.x));
dy = (std::floor(pos.y) - std::floor(m_catchPos.y)); 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); dy = (pos.y - m_catchPos.y);
} }
if ((moveModifier & LockAxisMovement) == LockAxisMovement) { if (isLockAxis)
if (std::abs(dx) < std::abs(dy)) lockAxis(m_lockedAxis, dx, dy);
dx = 0.0; else
else m_lockedAxis = LockedAxis::NONE;
dy = 0.0;
}
bounds.offset(dx, dy); bounds.offset(dx, dy);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019-2024 Igara Studio S.A. // Copyright (C) 2019-2025 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -15,6 +15,7 @@
#include "app/transformation.h" #include "app/transformation.h"
#include "app/tx.h" #include "app/tx.h"
#include "app/ui/editor/handle_type.h" #include "app/ui/editor/handle_type.h"
#include "app/util/moving_utils.h"
#include "doc/algorithm/flip_type.h" #include "doc/algorithm/flip_type.h"
#include "doc/frame.h" #include "doc/frame.h"
#include "doc/image_ref.h" #include "doc/image_ref.h"
@ -190,6 +191,7 @@ private:
Transformation m_currentData; Transformation m_currentData;
std::unique_ptr<Mask> m_initialMask, m_initialMask0; std::unique_ptr<Mask> m_initialMask, m_initialMask0;
std::unique_ptr<Mask> m_currentMask; std::unique_ptr<Mask> m_currentMask;
LockedAxis m_lockedAxis;
bool m_opaque; bool m_opaque;
color_t m_maskColor; color_t m_maskColor;
obs::scoped_connection m_pivotVisConn; obs::scoped_connection m_pivotVisConn;

View File

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

View File

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