From d6ddaa7a273931377c80a00fbeba69d7ec39d7b9 Mon Sep 17 00:00:00 2001 From: Liebranca Date: Mon, 9 Sep 2024 05:03:54 -0300 Subject: [PATCH 1/5] Snap cels to grid on moving cel action (fix #4027) --- src/app/ui/editor/moving_cel_state.cpp | 75 +++++++++++++++++++++++++- src/app/ui/editor/moving_cel_state.h | 2 + 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/app/ui/editor/moving_cel_state.cpp b/src/app/ui/editor/moving_cel_state.cpp index 12c489f8e..8a0d8813f 100644 --- a/src/app/ui/editor/moving_cel_state.cpp +++ b/src/app/ui/editor/moving_cel_state.cpp @@ -17,6 +17,7 @@ #include "app/context_access.h" #include "app/doc_api.h" #include "app/doc_range.h" +#include "app/snap_to_grid.h" #include "app/tx.h" #include "app/ui/editor/editor.h" #include "app/ui/editor/editor_customization_delegate.h" @@ -104,11 +105,22 @@ MovingCelState::MovingCelState(Editor* editor, m_celMainSize = gfx::SizeF(m_cel->bounds().size()); } + // Assume all cels are on the same layer + m_multiLayer = false; + Layer* prevLayer = m_celList.back()->layer(); + // Record start positions of all cels in selected range for (Cel* cel : m_celList) { Layer* layer = cel->layer(); ASSERT(layer); + // If this inequality is ever true, then we have + // multiple layers selected + if (layer != prevLayer) + m_multiLayer = true; + + prevLayer = layer; + if (layer && layer->isMovable() && !layer->isBackground()) { if (layer->isReference()) { m_celStarts.push_back(cel->boundsF()); @@ -158,6 +170,8 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) gfx::Point intOffset = intCelOffset(); // And now we move the cel (or all selected range) to the new position. + bool snapToGrid = (Preferences::instance().selection.snapToGrid() && + editor->docPref().grid.snap()); for (Cel* cel : m_celList) { // Change reference layer with subpixel precision if (cel->layer()->isReference()) { @@ -168,12 +182,22 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) celBounds.w *= m_celScale.w; celBounds.h *= m_celScale.h; } + // Do not snap individual cel origins or scale when + // multiple layers are selected + if (snapToGrid && !m_multiLayer) + snapBoundsToGrid(celBounds); + tx(new cmd::SetCelBoundsF(cel, celBounds)); } else { + gfx::RectF celBounds = cel->boundsF(); + celBounds.x += intOffset.x; + celBounds.y += intOffset.y; + if (snapToGrid && !m_multiLayer) + snapBoundsToGrid(celBounds); + api.setCelPosition(writer.sprite(), cel, - cel->x() + intOffset.x, - cel->y() + intOffset.y); + celBounds.x, celBounds.y); } } @@ -227,10 +251,22 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg) void MovingCelState::onCommitMouseMove(Editor* editor, const gfx::PointF& newCursorPos) { + + bool snapToGrid = (Preferences::instance().selection.snapToGrid() && + editor->docPref().grid.snap()); + switch (m_handle) { case MovePixelsHandle: m_celOffset = newCursorPos - m_cursorStart; + // Snap the delta itself to the grid, so that the cels + // are moved or scaled in fixed steps + if (snapToGrid) + m_celOffset = snap_to_grid( + editor->getSite().gridBounds(), + gfx::Point(m_celOffset), + PreferSnapTo::ClosestGridVertex); + if (int(editor->getCustomizationDelegate() ->getPressedKeyAction(KeyContext::TranslatingSelection) & KeyAction::LockAxis)) { if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) { @@ -246,6 +282,12 @@ void MovingCelState::onCommitMouseMove(Editor* editor, case ScaleSEHandle: { gfx::PointF delta(newCursorPos - m_cursorStart); + if (snapToGrid) + delta = snap_to_grid( + editor->getSite().gridBounds(), + gfx::Point(delta), + PreferSnapTo::ClosestGridVertex); + m_celScale.w = 1.0 + (delta.x / m_celMainSize.w); m_celScale.h = 1.0 + (delta.y / m_celMainSize.h); if (m_celScale.w < 1.0/m_celMainSize.w) m_celScale.w = 1.0/m_celMainSize.w; @@ -275,11 +317,17 @@ void MovingCelState::onCommitMouseMove(Editor* editor, celBounds.w *= m_celScale.w; celBounds.h *= m_celScale.h; } + if (snapToGrid && !m_multiLayer) + snapBoundsToGrid(celBounds); + cel->setBoundsF(celBounds); } else { celBounds.x += intOffset.x; celBounds.y += intOffset.y; + if (snapToGrid && !m_multiLayer) + snapBoundsToGrid(celBounds); + cel->setBounds(gfx::Rect(celBounds)); } } @@ -367,6 +415,29 @@ gfx::RectF MovingCelState::calcFullBounds() const return bounds; } +void MovingCelState::snapBoundsToGrid(gfx::RectF& celBounds) const +{ + if (m_scaled) { + gfx::PointF gridOffset( + snap_to_grid( + m_editor->getSite().gridBounds(), + gfx::Point(celBounds.w, celBounds.h), + PreferSnapTo::ClosestGridVertex)); + + celBounds.w = gridOffset.x; + celBounds.h = gridOffset.y; + } + else if (m_moved) { + gfx::PointF gridOffset( + snap_to_grid( + m_editor->getSite().gridBounds(), + gfx::Point(celBounds.origin()), + PreferSnapTo::ClosestGridVertex)); + + celBounds.setOrigin(gridOffset); + } +} + bool MovingCelState::restoreCelStartPosition() const { bool modified = false; diff --git a/src/app/ui/editor/moving_cel_state.h b/src/app/ui/editor/moving_cel_state.h index 5bc98f58a..f1738993b 100644 --- a/src/app/ui/editor/moving_cel_state.h +++ b/src/app/ui/editor/moving_cel_state.h @@ -59,6 +59,7 @@ namespace app { gfx::Point intCelOffset() const; gfx::RectF calcFullBounds() const; bool restoreCelStartPosition() const; + void snapBoundsToGrid(gfx::RectF& celBounds) const; // ContextObserver void onBeforeCommandExecution(CommandExecutionEvent& ev); @@ -79,6 +80,7 @@ namespace app { bool m_hasReference = false; bool m_moved = false; bool m_scaled = false; + bool m_multiLayer = false; HandleType m_handle; Editor* m_editor; From dca06a53c055661e33eefd99f3cba59c5c6d22f6 Mon Sep 17 00:00:00 2001 From: Liebranca Date: Mon, 9 Sep 2024 05:38:00 -0300 Subject: [PATCH 2/5] Cap scaling to grid size --- src/app/ui/editor/moving_cel_state.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/ui/editor/moving_cel_state.cpp b/src/app/ui/editor/moving_cel_state.cpp index 8a0d8813f..c8b17eee1 100644 --- a/src/app/ui/editor/moving_cel_state.cpp +++ b/src/app/ui/editor/moving_cel_state.cpp @@ -417,20 +417,21 @@ gfx::RectF MovingCelState::calcFullBounds() const void MovingCelState::snapBoundsToGrid(gfx::RectF& celBounds) const { + const gfx::RectF& gridBounds = m_editor->getSite().gridBounds(); if (m_scaled) { gfx::PointF gridOffset( snap_to_grid( - m_editor->getSite().gridBounds(), + gridBounds, gfx::Point(celBounds.w, celBounds.h), PreferSnapTo::ClosestGridVertex)); - celBounds.w = gridOffset.x; - celBounds.h = gridOffset.y; + celBounds.w = std::max(gridBounds.w, gridOffset.x); + celBounds.h = std::max(gridBounds.h, gridOffset.y); } else if (m_moved) { gfx::PointF gridOffset( snap_to_grid( - m_editor->getSite().gridBounds(), + gridBounds, gfx::Point(celBounds.origin()), PreferSnapTo::ClosestGridVertex)); From 0a45319e068209ba70915562415c8f95b6ab81fd Mon Sep 17 00:00:00 2001 From: Liebranca Date: Fri, 20 Sep 2024 19:32:58 -0300 Subject: [PATCH 3/5] Fix cursor alignment and implement pivot point --- src/app/ui/editor/moving_cel_state.cpp | 94 ++++++++++++-------------- src/app/ui/editor/moving_cel_state.h | 6 +- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/app/ui/editor/moving_cel_state.cpp b/src/app/ui/editor/moving_cel_state.cpp index c8b17eee1..2142053c6 100644 --- a/src/app/ui/editor/moving_cel_state.cpp +++ b/src/app/ui/editor/moving_cel_state.cpp @@ -105,22 +105,11 @@ MovingCelState::MovingCelState(Editor* editor, m_celMainSize = gfx::SizeF(m_cel->bounds().size()); } - // Assume all cels are on the same layer - m_multiLayer = false; - Layer* prevLayer = m_celList.back()->layer(); - // Record start positions of all cels in selected range for (Cel* cel : m_celList) { Layer* layer = cel->layer(); ASSERT(layer); - // If this inequality is ever true, then we have - // multiple layers selected - if (layer != prevLayer) - m_multiLayer = true; - - prevLayer = layer; - if (layer && layer->isMovable() && !layer->isBackground()) { if (layer->isReference()) { m_celStarts.push_back(cel->boundsF()); @@ -137,6 +126,7 @@ MovingCelState::MovingCelState(Editor* editor, &MovingCelState::onBeforeCommandExecution, this); m_cursorStart = editor->screenToEditorF(msg->position()); + calcPivot(); editor->captureMouse(); // Hide the mask (temporarily, until mouse-up event) @@ -168,10 +158,12 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) Tx tx(writer, "Cel Movement", ModifyDocument); DocApi api = document->getApi(tx); gfx::Point intOffset = intCelOffset(); + bool snapToGrid = (Preferences::instance().selection.snapToGrid() && + m_editor->docPref().grid.snap()); + if (snapToGrid) + snapOffsetToGrid(intOffset); // And now we move the cel (or all selected range) to the new position. - bool snapToGrid = (Preferences::instance().selection.snapToGrid() && - editor->docPref().grid.snap()); for (Cel* cel : m_celList) { // Change reference layer with subpixel precision if (cel->layer()->isReference()) { @@ -182,22 +174,15 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) celBounds.w *= m_celScale.w; celBounds.h *= m_celScale.h; } - // Do not snap individual cel origins or scale when - // multiple layers are selected - if (snapToGrid && !m_multiLayer) + if (snapToGrid) snapBoundsToGrid(celBounds); tx(new cmd::SetCelBoundsF(cel, celBounds)); } else { - gfx::RectF celBounds = cel->boundsF(); - celBounds.x += intOffset.x; - celBounds.y += intOffset.y; - if (snapToGrid && !m_multiLayer) - snapBoundsToGrid(celBounds); - api.setCelPosition(writer.sprite(), cel, - celBounds.x, celBounds.y); + cel->x() + intOffset.x, + cel->y() + intOffset.y); } } @@ -248,25 +233,24 @@ bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg) return StandbyState::onMouseMove(editor, msg); } +void MovingCelState::calcPivot() +{ + // Get grid displacement from pivot point, for now hardcoded + // to be relative to initial position + m_fullBounds = calcFullBounds(); + m_pivot = gfx::PointF(0,0); + const gfx::RectF& gridBounds = m_editor->getSite().gridBounds(); + m_pivotOffset = gfx::PointF( + gridBounds.size()) - (m_pivot-m_fullBounds.origin()); +} + void MovingCelState::onCommitMouseMove(Editor* editor, const gfx::PointF& newCursorPos) { - - bool snapToGrid = (Preferences::instance().selection.snapToGrid() && - editor->docPref().grid.snap()); - switch (m_handle) { case MovePixelsHandle: m_celOffset = newCursorPos - m_cursorStart; - // Snap the delta itself to the grid, so that the cels - // are moved or scaled in fixed steps - if (snapToGrid) - m_celOffset = snap_to_grid( - editor->getSite().gridBounds(), - gfx::Point(m_celOffset), - PreferSnapTo::ClosestGridVertex); - if (int(editor->getCustomizationDelegate() ->getPressedKeyAction(KeyContext::TranslatingSelection) & KeyAction::LockAxis)) { if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) { @@ -282,12 +266,6 @@ void MovingCelState::onCommitMouseMove(Editor* editor, case ScaleSEHandle: { gfx::PointF delta(newCursorPos - m_cursorStart); - if (snapToGrid) - delta = snap_to_grid( - editor->getSite().gridBounds(), - gfx::Point(delta), - PreferSnapTo::ClosestGridVertex); - m_celScale.w = 1.0 + (delta.x / m_celMainSize.w); m_celScale.h = 1.0 + (delta.y / m_celMainSize.h); if (m_celScale.w < 1.0/m_celMainSize.w) m_celScale.w = 1.0/m_celMainSize.w; @@ -304,6 +282,10 @@ void MovingCelState::onCommitMouseMove(Editor* editor, } gfx::Point intOffset = intCelOffset(); + bool snapToGrid = (Preferences::instance().selection.snapToGrid() && + m_editor->docPref().grid.snap()); + if (snapToGrid) + snapOffsetToGrid(intOffset); for (size_t i=0; isetBoundsF(celBounds); @@ -325,9 +307,6 @@ void MovingCelState::onCommitMouseMove(Editor* editor, else { celBounds.x += intOffset.x; celBounds.y += intOffset.y; - if (snapToGrid && !m_multiLayer) - snapBoundsToGrid(celBounds); - cel->setBounds(gfx::Rect(celBounds)); } } @@ -415,15 +394,30 @@ gfx::RectF MovingCelState::calcFullBounds() const return bounds; } +void MovingCelState::snapOffsetToGrid(gfx::Point& offset) const +{ + const gfx::RectF& gridBounds = m_editor->getSite().gridBounds(); + const gfx::RectF displaceGrid(gridBounds.origin() + m_pivotOffset, + gridBounds.size()); + offset = snap_to_grid( + displaceGrid, + gfx::Point(m_fullBounds.origin() + offset), + PreferSnapTo::ClosestGridVertex) - m_fullBounds.origin(); +} + void MovingCelState::snapBoundsToGrid(gfx::RectF& celBounds) const { const gfx::RectF& gridBounds = m_editor->getSite().gridBounds(); + const gfx::RectF displaceGrid(gridBounds.origin() + m_pivotOffset, + gridBounds.size()); + const gfx::PointF& origin = celBounds.origin(); if (m_scaled) { gfx::PointF gridOffset( snap_to_grid( - gridBounds, - gfx::Point(celBounds.w, celBounds.h), - PreferSnapTo::ClosestGridVertex)); + displaceGrid, + gfx::Point(origin.x + celBounds.w, + origin.y + celBounds.h), + PreferSnapTo::ClosestGridVertex) - origin); celBounds.w = std::max(gridBounds.w, gridOffset.x); celBounds.h = std::max(gridBounds.h, gridOffset.y); @@ -431,8 +425,8 @@ void MovingCelState::snapBoundsToGrid(gfx::RectF& celBounds) const else if (m_moved) { gfx::PointF gridOffset( snap_to_grid( - gridBounds, - gfx::Point(celBounds.origin()), + displaceGrid, + gfx::Point(origin), PreferSnapTo::ClosestGridVertex)); celBounds.setOrigin(gridOffset); diff --git a/src/app/ui/editor/moving_cel_state.h b/src/app/ui/editor/moving_cel_state.h index f1738993b..ddceacd0c 100644 --- a/src/app/ui/editor/moving_cel_state.h +++ b/src/app/ui/editor/moving_cel_state.h @@ -58,7 +58,9 @@ namespace app { private: gfx::Point intCelOffset() const; gfx::RectF calcFullBounds() const; + void calcPivot(); bool restoreCelStartPosition() const; + void snapOffsetToGrid(gfx::Point& offset) const; void snapBoundsToGrid(gfx::RectF& celBounds) const; // ContextObserver void onBeforeCommandExecution(CommandExecutionEvent& ev); @@ -72,7 +74,10 @@ namespace app { Cel* m_cel; CelList m_celList; std::vector m_celStarts; + gfx::RectF m_fullBounds; gfx::PointF m_cursorStart; + gfx::PointF m_pivot; + gfx::PointF m_pivotOffset; gfx::PointF m_celOffset; gfx::SizeF m_celMainSize; gfx::SizeF m_celScale; @@ -80,7 +85,6 @@ namespace app { bool m_hasReference = false; bool m_moved = false; bool m_scaled = false; - bool m_multiLayer = false; HandleType m_handle; Editor* m_editor; From 11883a51ffa19eeb1a28c0ba788fd6a381940092 Mon Sep 17 00:00:00 2001 From: David Capello Date: Fri, 11 Oct 2024 14:59:37 -0300 Subject: [PATCH 4/5] Disable Curl tests in compilation This avoid creating a lot of testNNN projects inside the Visual Studio solution generated by cmake. --- third_party/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 374dbd8f3..5db887125 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -61,6 +61,7 @@ endif() if(REQUIRE_CURL AND NOT USE_SHARED_CURL) set(BUILD_RELEASE_DEBUG_DIRS ON BOOL) set(BUILD_CURL_EXE OFF CACHE BOOL "Set to ON to build curl executable.") + set(CURL_DISABLE_TESTS ON CACHE BOOL "Disable Curl tests") add_subdirectory(curl) endif() From a49bfe7f0a87b773fdd69be44650729f6e4dcd57 Mon Sep 17 00:00:00 2001 From: David Capello Date: Fri, 11 Oct 2024 15:05:18 -0300 Subject: [PATCH 5/5] Lua was still being compiled as C (instead of C++) when generating Visual Studio solutions We're compiling Lua as C++, but it seems that target_compile_options() doesn't work for Visual Studio solutions (only for Ninja/makefiles). The proper cmake solution to this issue is using set_source_files_properties() to specify C++ as the language to use to compile all Lua C files. This generates a valid Visual Studio solution. --- third_party/CMakeLists.txt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 5db887125..d80040fb1 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -204,17 +204,10 @@ if(ENABLE_SCRIPTING) target_compile_definitions(lua PUBLIC LUA_USE_LINUX=1) endif() - # Compile Lua as C++ to control errors with exceptions and have - # stack unwinding (i.e. calling destructors correctly). - if(MSVC) - target_compile_options(lua PRIVATE -TP) - target_compile_options(lualib PRIVATE -TP) - target_compile_options(lauxlib PRIVATE -TP) - else() - target_compile_options(lua PRIVATE -xc++) - target_compile_options(lualib PRIVATE -xc++) - target_compile_options(lauxlib PRIVATE -xc++) - endif() + # Compile Lua C files as C++ to control errors with exceptions and + # have stack unwinding (i.e. calling destructors correctly). + file(GLOB all_lua_source_files lua/*.c) + set_source_files_properties(${all_lua_source_files} PROPERTIES LANGUAGE CXX) target_compile_definitions(lua PUBLIC LUA_FLOORN2I=F2Ifloor) target_compile_definitions(lualib PRIVATE HAVE_SYSTEM)