← Back to team overview

kicad-developers team mailing list archive

[PATCH] CCW Rotation in GAL

 

Hi,

Here is a patch for adding CCW rotation to the GAL canvas.

Possibly controversial is the new namespace in tool_action_utils.h for
dumping generic free function helpers that act on TOOL_ACTIONS and on
other classes in concert. I feel that this is a way to isolate the
these routines, giving access to whichever GAL tool functions needed
them, while emphasising that they act via public interfaces of the
relevant classes, but I defer to the GAL wizards for comment!

Fixes: https://bugs.launchpad.net/kicad/+bug/1660731 (but it's more
extensive than just that, as it adds bidirectional rotation to
everywhere there is unidirectional rotation in GAL now).

Cheers,

John
From 77bc4b3b42d64137d915aecdfef0139150c0844b Mon Sep 17 00:00:00 2001
From: John Beard <john.j.beard@xxxxxxxxx>
Date: Sat, 4 Feb 2017 13:09:50 +0800
Subject: [PATCH] Add CCW rotation to GAL canvas

This makes "rotate" into two separate TOOL_EVENTs, which each have a
"multiplier" parameter.

Also added is a namespace for 'free functions' that use TOOL_EVENT
public interfaces (perhaps with other inputs too) to centralise some
decision-making and calculations.

Fixes: lp:1660731
* https://bugs.launchpad.net/kicad/+bug/1660731
---
 pcbnew/CMakeLists.txt                |  1 +
 pcbnew/tools/common_actions.cpp      | 10 ++++--
 pcbnew/tools/common_actions.h        |  7 ++--
 pcbnew/tools/drawing_tool.cpp        | 21 +++++++----
 pcbnew/tools/edit_tool.cpp           | 11 ++++--
 pcbnew/tools/module_editor_tools.cpp | 14 +++++---
 pcbnew/tools/pcb_editor_control.cpp  |  8 +++--
 pcbnew/tools/tool_event_utils.cpp    | 48 +++++++++++++++++++++++++
 pcbnew/tools/tool_event_utils.h      | 68 ++++++++++++++++++++++++++++++++++++
 9 files changed, 168 insertions(+), 20 deletions(-)
 create mode 100644 pcbnew/tools/tool_event_utils.cpp
 create mode 100644 pcbnew/tools/tool_event_utils.h

diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index eedb3a6f0..7c36570c9 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -297,6 +297,7 @@ set( PCBNEW_CLASS_SRCS
     tools/picker_tool.cpp
     tools/zoom_tool.cpp
     tools/tools_common.cpp
+    tools/tool_event_utils.cpp
     tools/tool_menu.cpp
 
     tools/grid_menu.cpp
diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp
index 498d86355..604201fd5 100644
--- a/pcbnew/tools/common_actions.cpp
+++ b/pcbnew/tools/common_actions.cpp
@@ -117,9 +117,15 @@ TOOL_ACTION COMMON_ACTIONS::createArray( "pcbnew.InteractiveEdit.createArray",
         AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_CREATE_ARRAY ),
         _( "Create array" ), _( "Create array" ), array_module_xpm, AF_ACTIVATE );
 
-TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.InteractiveEdit.rotate",
+TOOL_ACTION COMMON_ACTIONS::rotateCw( "pcbnew.InteractiveEdit.rotateCw",
         AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ROTATE_ITEM ),
-        _( "Rotate" ), _( "Rotates selected item(s)" ), rotate_cw_xpm );
+        _( "Rotate clockwise" ), _( "Rotates selected item(s) clockwise" ),
+        rotate_cw_xpm, AF_NONE, (void*) 1 );
+
+TOOL_ACTION COMMON_ACTIONS::rotateCcw( "pcbnew.InteractiveEdit.rotateCcw",
+        AS_GLOBAL, MD_SHIFT + 'R',
+        _( "Rotate counter-clockwise" ), _( "Rotates selected item(s) counter-clockwise" ),
+        rotate_ccw_xpm, AF_NONE, (void*) -1 );
 
 TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip",
         AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_FLIP_ITEM ),
diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h
index b8167cf3c..b9800dcd4 100644
--- a/pcbnew/tools/common_actions.h
+++ b/pcbnew/tools/common_actions.h
@@ -70,8 +70,11 @@ public:
     /// Activation of the edit tool
     static TOOL_ACTION editActivate;
 
-    /// Rotation of selected objects
-    static TOOL_ACTION rotate;
+    /// Rotation of selected objects clockwise
+    static TOOL_ACTION rotateCw;
+
+    /// Rotation of selected objects counter-clockwise
+    static TOOL_ACTION rotateCcw;
 
     /// Flipping of selected objects
     static TOOL_ACTION flip;
diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp
index c0b897361..c2196070d 100644
--- a/pcbnew/tools/drawing_tool.cpp
+++ b/pcbnew/tools/drawing_tool.cpp
@@ -53,7 +53,7 @@
 #include <class_module.h>
 
 #include <tools/selection_tool.h>
-
+#include <tools/tool_event_utils.h>
 
 using SCOPED_DRAW_MODE = SCOPED_SET_RESET<DRAWING_TOOL::MODE>;
 
@@ -236,12 +236,14 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
 
         else if( text && evt->Category() == TC_COMMAND )
         {
-            if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
+            if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
             {
-                text->Rotate( text->GetPosition(), m_frame->GetRotationAngle() );
+                const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
+                        *m_frame, *evt );
+
+                text->Rotate( text->GetPosition(), rotationAngle );
                 m_view->Update( &preview );
             }
-            // TODO rotate CCW
             else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
             {
                 text->Flip( text->GetPosition() );
@@ -617,11 +619,16 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent )
         else if( evt->Category() == TC_COMMAND )
         {
             // TODO it should be handled by EDIT_TOOL, so add items and select?
-            if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
+            if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
             {
+                const auto rotationPoint = wxPoint( cursorPos.x, cursorPos.y );
+                const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
+                        *m_frame, *evt );
+
                 for( auto item : preview )
-                    item->Rotate( wxPoint( cursorPos.x, cursorPos.y ),
-                                 m_frame->GetRotationAngle() );
+                {
+                    item->Rotate( rotationPoint, rotationAngle );
+                }
 
                 m_view->Update( &preview );
             }
diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp
index a344b3110..031f2db4f 100644
--- a/pcbnew/tools/edit_tool.cpp
+++ b/pcbnew/tools/edit_tool.cpp
@@ -58,6 +58,8 @@ using namespace std::placeholders;
 #include <dialogs/dialog_track_via_properties.h>
 #include <dialogs/dialog_exchange_modules.h>
 
+#include <tools/tool_event_utils.h>
+
 #include <board_commit.h>
 
 EDIT_TOOL::EDIT_TOOL() :
@@ -97,7 +99,8 @@ bool EDIT_TOOL::Init()
     // Add context menu entries that are displayed when selection tool is active
     CONDITIONAL_MENU& menu = m_selectionTool->GetToolMenu().GetMenu();
     menu.AddItem( COMMON_ACTIONS::editActivate, SELECTION_CONDITIONS::NotEmpty );
-    menu.AddItem( COMMON_ACTIONS::rotate, SELECTION_CONDITIONS::NotEmpty );
+    menu.AddItem( COMMON_ACTIONS::rotateCw, SELECTION_CONDITIONS::NotEmpty );
+    menu.AddItem( COMMON_ACTIONS::rotateCcw, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( COMMON_ACTIONS::flip, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty );
     menu.AddItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::Count( 1 )
@@ -399,11 +402,12 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
         return 0;
 
     wxPoint rotatePoint = getModificationPoint( selection );
+    const int rotateAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *editFrame, aEvent );
 
     for( auto item : selection )
     {
         m_commit->Modify( item );
-        item->Rotate( rotatePoint, editFrame->GetRotationAngle() );
+        item->Rotate( rotatePoint, rotateAngle );
     }
 
     if( !m_dragging )
@@ -816,7 +820,8 @@ int EDIT_TOOL::ExchangeFootprints( const TOOL_EVENT& aEvent )
 void EDIT_TOOL::SetTransitions()
 {
     Go( &EDIT_TOOL::Main,       COMMON_ACTIONS::editActivate.MakeEvent() );
-    Go( &EDIT_TOOL::Rotate,     COMMON_ACTIONS::rotate.MakeEvent() );
+    Go( &EDIT_TOOL::Rotate,     COMMON_ACTIONS::rotateCw.MakeEvent() );
+    Go( &EDIT_TOOL::Rotate,     COMMON_ACTIONS::rotateCcw.MakeEvent() );
     Go( &EDIT_TOOL::Flip,       COMMON_ACTIONS::flip.MakeEvent() );
     Go( &EDIT_TOOL::Remove,     COMMON_ACTIONS::remove.MakeEvent() );
     Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() );
diff --git a/pcbnew/tools/module_editor_tools.cpp b/pcbnew/tools/module_editor_tools.cpp
index 8ee451cbd..ab0c28535 100644
--- a/pcbnew/tools/module_editor_tools.cpp
+++ b/pcbnew/tools/module_editor_tools.cpp
@@ -45,6 +45,8 @@
 #include <class_edge_mod.h>
 #include <board_commit.h>
 
+#include <tools/tool_event_utils.h>
+
 #include <functional>
 using namespace std::placeholders;
 #include <wx/defs.h>
@@ -138,9 +140,11 @@ int MODULE_EDITOR_TOOLS::PlacePad( const TOOL_EVENT& aEvent )
 
         else if( evt->Category() == TC_COMMAND )
         {
-            if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
+            if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
             {
-                pad->Rotate( pad->GetPosition(), m_frame->GetRotationAngle() );
+                const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
+                        *m_frame, *evt );
+                pad->Rotate( pad->GetPosition(), rotationAngle );
                 m_view->Update( &preview );
             }
             else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
@@ -451,9 +455,11 @@ int MODULE_EDITOR_TOOLS::PasteItems( const TOOL_EVENT& aEvent )
 
         else if( evt->Category() == TC_COMMAND )
         {
-            if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
+            if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
             {
-                pastedModule->Rotate( pastedModule->GetPosition(), m_frame->GetRotationAngle() );
+                const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
+                        *m_frame, *evt );
+                pastedModule->Rotate( pastedModule->GetPosition(), rotationAngle );
                 m_view->Update( &preview );
             }
             else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp
index 5fc9779e4..614bd14f5 100644
--- a/pcbnew/tools/pcb_editor_control.cpp
+++ b/pcbnew/tools/pcb_editor_control.cpp
@@ -50,6 +50,8 @@
 #include <view/view_controls.h>
 #include <origin_viewitem.h>
 
+#include <tools/tool_event_utils.h>
+
 #include <functional>
 using namespace std::placeholders;
 
@@ -312,9 +314,11 @@ int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent )
 
         else if( module && evt->Category() == TC_COMMAND )
         {
-            if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
+            if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) )
             {
-                module->Rotate( module->GetPosition(), m_frame->GetRotationAngle() );
+                const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle(
+                        *m_frame, *evt );
+                module->Rotate( module->GetPosition(), rotationAngle );
                 view->Update( &preview );
             }
             else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
diff --git a/pcbnew/tools/tool_event_utils.cpp b/pcbnew/tools/tool_event_utils.cpp
new file mode 100644
index 000000000..b24dae6e3
--- /dev/null
+++ b/pcbnew/tools/tool_event_utils.cpp
@@ -0,0 +1,48 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+
+ * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <tools/tool_event_utils.h>
+
+#include <tools/common_actions.h>
+
+#include <pcb_base_edit_frame.h>
+
+
+bool TOOL_EVT_UTILS::IsRotateToolEvt( const TOOL_EVENT& aEvt )
+{
+    return aEvt.IsAction( &COMMON_ACTIONS::rotateCw )
+            || aEvt.IsAction( &COMMON_ACTIONS::rotateCcw );
+}
+
+
+int TOOL_EVT_UTILS::GetEventRotationAngle( const PCB_BASE_EDIT_FRAME& aFrame,
+                                           const TOOL_EVENT& aEvt )
+{
+    wxASSERT_MSG( IsRotateToolEvt( aEvt ),
+                  _( "Expected rotation event" ) );
+
+    const int rotAngle = aFrame.GetRotationAngle();
+    const int angleMultiplier = aEvt.Parameter<intptr_t>();
+
+    return rotAngle * angleMultiplier;
+}
diff --git a/pcbnew/tools/tool_event_utils.h b/pcbnew/tools/tool_event_utils.h
new file mode 100644
index 000000000..308542454
--- /dev/null
+++ b/pcbnew/tools/tool_event_utils.h
@@ -0,0 +1,68 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+
+ * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef TOOL_EVENT_UTILS_H
+#define TOOL_EVENT_UTILS_H
+
+#include <tool/tool_interactive.h>
+
+
+class PCB_BASE_EDIT_FRAME;
+
+
+/**
+ * Namespace TOOL_EVT_UTILS
+ *
+ * Utility functions for dealing with various tool events. These are
+ * free functions, so they interface with any classes exclusively via
+ * the public interfaces, so they don't need to be subsumed into the
+ * "helped" classes.
+ */
+namespace TOOL_EVT_UTILS
+{
+    /**
+     * Function isRotateToolEvt()
+     *
+     * @param aEvt event to check
+     * @return true if the event is a rotation action tool event
+     */
+    bool IsRotateToolEvt( const TOOL_EVENT& aEvt );
+
+    /**
+     * Function getEventRotationAngle()
+     *
+     * Helper function to get a rotation angle based on a frame's
+     * configured angle and the direction indicated by a rotation action event
+     *
+     * @param aFrame the PCB edit frame to use to get the base rotation
+     * step value from
+     * @param aEvt the tool event - should be a rotation action event
+     * and should have a rotation multiplier parameter
+     *
+     * @return the rotation angle in clockwise internal units
+     */
+    int GetEventRotationAngle( const PCB_BASE_EDIT_FRAME& aFrame,
+                               const TOOL_EVENT& aEvt );
+};
+
+#endif // TOOL_EVENT_UTILS_H
-- 
2.11.0


Follow ups