From c21ae6efcaa06f2bbbe49d3b74dd401282c398da Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Nov 2013 15:19:50 +0100 Subject: [PATCH 01/84] Double click support for the Tool Framework. --- common/drawpanel_gal.cpp | 27 +++++++++-------- common/gal/cairo/cairo_gal.cpp | 19 +++++++----- common/gal/opengl/opengl_gal.cpp | 19 +++++++----- common/tool/tool_dispatcher.cpp | 25 +++++++++++---- common/tool/tool_event.cpp | 3 +- include/tool/tool_event.h | 52 +++++++++++++++++++------------- 6 files changed, 89 insertions(+), 56 deletions(-) diff --git a/common/drawpanel_gal.cpp b/common/drawpanel_gal.cpp index 3ec9568fde..bbfefd3c10 100644 --- a/common/drawpanel_gal.cpp +++ b/common/drawpanel_gal.cpp @@ -78,18 +78,21 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin Connect( wxEVT_SIZE, wxSizeEventHandler( EDA_DRAW_PANEL_GAL::onSize ), NULL, this ); /* Generic events for the Tool Dispatcher */ - Connect( wxEVT_MOTION, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_LEFT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_LEFT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_RIGHT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_RIGHT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) ); - Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); - Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this ); + Connect( wxEVT_MOTION, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_LEFT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_LEFT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_LEFT_DCLICK, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_RIGHT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_RIGHT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_RIGHT_DCLICK, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_MIDDLE_DCLICK, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) ); + Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); + Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this ); Connect( KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this ); diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 110f647146..5f180d7338 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -57,15 +57,18 @@ CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, Connect( wxEVT_PAINT, wxPaintEventHandler( CAIRO_GAL::onPaint ) ); // Mouse events are skipped to the parent - Connect( wxEVT_MOTION, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); - Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); - Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); - Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); - Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); - Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); - Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_MOTION, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); #if defined _WIN32 || defined _WIN64 - Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); #endif SetSize( aParent->GetSize() ); diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 970cc32d16..f9cccbd365 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -70,15 +70,18 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::onPaint ) ); // Mouse events are skipped to the parent - Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); - Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); - Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); - Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); - Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); - Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); - Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_MOTION, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_LEFT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); #if defined _WIN32 || defined _WIN64 - Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); #endif SetSize( aParent->GetSize() ); diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 49ab4382ac..b655113b38 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -43,10 +43,11 @@ using boost::optional; struct TOOL_DISPATCHER::BUTTON_STATE { BUTTON_STATE( TOOL_MOUSE_BUTTONS aButton, const wxEventType& aDownEvent, - const wxEventType& aUpEvent ) : + const wxEventType& aUpEvent, const wxEventType& aDblClickEvent ) : button( aButton ), downEvent( aDownEvent ), - upEvent( aUpEvent ) + upEvent( aUpEvent ), + dblClickEvent( aDblClickEvent ) {}; ///> Flag indicating that dragging is active for the given button. @@ -74,6 +75,9 @@ struct TOOL_DISPATCHER::BUTTON_STATE ///> The type of wxEvent that determines mouse button release. wxEventType upEvent; + ///> The type of wxEvent that determines mouse button double click. + wxEventType dblClickEvent; + ///> Time stamp for the last mouse button press event. wxLongLong downTimestamp; @@ -89,9 +93,12 @@ struct TOOL_DISPATCHER::BUTTON_STATE TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ) : m_toolMgr( aToolMgr ), m_editFrame( aEditFrame ) { - m_buttons.push_back( new BUTTON_STATE( BUT_LEFT, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) ); - m_buttons.push_back( new BUTTON_STATE( BUT_RIGHT, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP ) ); - m_buttons.push_back( new BUTTON_STATE( BUT_MIDDLE, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP ) ); + m_buttons.push_back( new BUTTON_STATE( BUT_LEFT, wxEVT_LEFT_DOWN, + wxEVT_LEFT_UP, wxEVT_LEFT_DCLICK ) ); + m_buttons.push_back( new BUTTON_STATE( BUT_RIGHT, wxEVT_RIGHT_DOWN, + wxEVT_RIGHT_UP, wxEVT_RIGHT_DCLICK ) ); + m_buttons.push_back( new BUTTON_STATE( BUT_MIDDLE, wxEVT_MIDDLE_DOWN, + wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DCLICK ) ); ResetState(); } @@ -126,6 +133,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti bool up = type == st->upEvent; bool down = type == st->downEvent; + bool dblClick = type == st->dblClickEvent; int mods = decodeModifiers( static_cast( &aEvent ) ); int args = st->button | mods; @@ -162,6 +170,10 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti st->dragging = false; } + else if( dblClick ) + { + evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DBLCLICK, args ); + } if( st->pressed && aMotion ) { @@ -204,8 +216,9 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP || type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP || + type == wxEVT_LEFT_DCLICK || type == wxEVT_MIDDLE_DCLICK || type == wxEVT_RIGHT_DCLICK || // Event issued whem mouse retains position in screen coordinates, - // but changes in world coordinates (eg. autopanning) + // but changes in world coordinates (e.g. autopanning) type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) { VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition(); diff --git a/common/tool/tool_event.cpp b/common/tool/tool_event.cpp index 15ae3314e7..978550406b 100644 --- a/common/tool/tool_event.cpp +++ b/common/tool/tool_event.cpp @@ -77,6 +77,7 @@ const std::string TOOL_EVENT::Format() const const FlagString actions[] = { { TA_MOUSE_CLICK, "click" }, + { TA_MOUSE_DBLCLICK, "double click" }, { TA_MOUSE_UP, "button-up" }, { TA_MOUSE_DOWN, "button-down" }, { TA_MOUSE_DRAG, "drag" }, @@ -102,7 +103,7 @@ const std::string TOOL_EVENT::Format() const { BUT_LEFT, "left" }, { BUT_RIGHT, "right" }, { BUT_MIDDLE, "middle" }, - { 0, "" } + { 0, "" } }; const FlagString modifiers[] = diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index 44cb4379cd..1ec5b1414d 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -54,39 +54,43 @@ enum TOOL_EVENT_CATEGORY enum TOOL_ACTIONS { // UI input events - TA_NONE = 0x0000, - TA_MOUSE_CLICK = 0x0001, - TA_MOUSE_UP = 0x0002, - TA_MOUSE_DOWN = 0x0004, - TA_MOUSE_DRAG = 0x0008, - TA_MOUSE_MOTION = 0x0010, - TA_MOUSE_WHEEL = 0x0020, - TA_MOUSE = 0x003f, - TA_KEY_UP = 0x0040, - TA_KEY_DOWN = 0x0080, - TA_KEYBOARD = TA_KEY_UP | TA_KEY_DOWN, + TA_NONE = 0x0000, + TA_MOUSE_CLICK = 0x0001, + TA_MOUSE_DBLCLICK = 0x0002, + TA_MOUSE_UP = 0x0004, + TA_MOUSE_DOWN = 0x0008, + TA_MOUSE_DRAG = 0x0010, + TA_MOUSE_MOTION = 0x0020, + TA_MOUSE_WHEEL = 0x0040, + TA_MOUSE = 0x007f, + + TA_KEY_UP = 0x0080, + TA_KEY_DOWN = 0x0100, + TA_KEYBOARD = TA_KEY_UP | TA_KEY_DOWN, // View related events - TA_VIEW_REFRESH = 0x0100, - TA_VIEW_ZOOM = 0x0200, - TA_VIEW_PAN = 0x0400, - TA_VIEW_DIRTY = 0x0800, - TA_CHANGE_LAYER = 0x1000, + TA_VIEW_REFRESH = 0x0200, + TA_VIEW_ZOOM = 0x0400, + TA_VIEW_PAN = 0x0800, + TA_VIEW_DIRTY = 0x1000, + TA_VIEW = 0x1e00, + + TA_CHANGE_LAYER = 0x2000, // Tool cancel event. Issued automagically when the user hits escape or selects End Tool from // the context menu. - TA_CANCEL_TOOL = 0x2000, + TA_CANCEL_TOOL = 0x4000, // Context menu update. Issued whenever context menu is open and the user hovers the mouse // over one of choices. Used in dynamic highligting in disambiguation menu - TA_CONTEXT_MENU_UPDATE = 0x4000, + TA_CONTEXT_MENU_UPDATE = 0x8000, // Context menu choice. Sent if the user picked something from the context menu or // closed it without selecting anything. - TA_CONTEXT_MENU_CHOICE = 0x8000, + TA_CONTEXT_MENU_CHOICE = 0x10000, // Tool action (allows to control tools) - TA_ACTION = 0x10000, + TA_ACTION = 0x20000, TA_ANY = 0xffffffff }; @@ -233,6 +237,12 @@ public: && ( ( m_mouseButtons & aButtonMask ) == aButtonMask ); } + bool IsDblClick( int aButtonMask = BUT_ANY ) const + { + return ( m_actions == TA_MOUSE_DBLCLICK ) + && ( ( m_mouseButtons & aButtonMask ) == aButtonMask ); + } + bool IsDrag( int aButtonMask = BUT_ANY ) const { return ( m_actions == TA_MOUSE_DRAG ) && ( ( m_mouseButtons & aButtonMask ) == aButtonMask ); @@ -277,7 +287,7 @@ public: void SetMouseDragOrigin( const VECTOR2D& aP ) { m_mouseDragOrigin = aP; - } + } void SetMousePosition( const VECTOR2D& aP ) { From af976b2d36e0b4bd323c3b6da3081bb794f50d7b Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 28 Nov 2013 15:24:19 +0100 Subject: [PATCH 02/84] Automatic unregistration of tool actions during ACTION_MANAGER destruction. --- common/tool/action_manager.cpp | 7 +++++++ include/tool/action_manager.h | 6 ++++++ pcbnew/tools/pcb_tools.cpp | 7 +------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index be90ef055f..63aa99f8d8 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -34,6 +34,13 @@ ACTION_MANAGER::ACTION_MANAGER( TOOL_MANAGER* aToolManager ) : } +ACTION_MANAGER::~ACTION_MANAGER() +{ + while( !m_actionIdIndex.empty() ) + UnregisterAction( m_actionIdIndex.begin()->second ); +} + + void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) { assert( aAction->GetId() == -1 ); // Check if the TOOL_ACTION was not registered before diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index 239ad606b7..dbcb7b33b6 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -47,6 +47,12 @@ public: */ ACTION_MANAGER( TOOL_MANAGER* aToolManager ); + /** + * Destructor. + * Unregisters every registered action. + */ + ~ACTION_MANAGER(); + /** * Function RegisterAction() * Adds a tool action to the manager and sets it up. After that is is possible to invoke diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index f3749a0c94..2f9676cb94 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -61,13 +61,8 @@ void PCB_EDIT_FRAME::setupTools() void PCB_EDIT_FRAME::destroyTools() { - m_toolManager->UnregisterAction( &COMMON_ACTIONS::moveActivate ); - m_toolManager->UnregisterAction( &COMMON_ACTIONS::selectionActivate ); - m_toolManager->UnregisterAction( &COMMON_ACTIONS::rotate ); - m_toolManager->UnregisterAction( &COMMON_ACTIONS::flip ); - - delete m_toolDispatcher; delete m_toolManager; + delete m_toolDispatcher; } From 3ce3d22b974d6ee5a11ab357f15e590571d3b99c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 29 Nov 2013 09:37:23 +0100 Subject: [PATCH 03/84] Moved the SELECTION_TOOL out of the KIGFX namespace. --- pcbnew/tools/selection_tool.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 262d93ac45..decd7fe9e5 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -47,7 +47,6 @@ #include "bright_box.h" #include "common_actions.h" -using namespace KIGFX; using boost::optional; SELECTION_TOOL::SELECTION_TOOL() : @@ -81,7 +80,7 @@ void SELECTION_TOOL::Reset() int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) { - VIEW* view = getView(); + KIGFX::VIEW* view = getView(); assert( getModel( PCB_T ) != NULL ); @@ -176,7 +175,7 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) void SELECTION_TOOL::clearSelection() { - VIEW_GROUP::const_iter it, it_end; + KIGFX::VIEW_GROUP::const_iter it, it_end; for( it = m_selection.group->Begin(), it_end = m_selection.group->End(); it != it_end; ++it ) { @@ -286,7 +285,7 @@ bool SELECTION_TOOL::selectMultiple() { bool cancelled = false; // Was the tool cancelled while it was running? m_multiple = true; // Multiple selection mode is active - VIEW* view = getView(); + KIGFX::VIEW* view = getView(); getViewControls()->SetAutoPan( true ); view->Add( m_selArea ); @@ -308,7 +307,7 @@ bool SELECTION_TOOL::selectMultiple() m_selArea->SetOrigin( evt->DragOrigin() ); m_selArea->SetEnd( evt->Position() ); m_selArea->ViewSetVisible( true ); - m_selArea->ViewUpdate( VIEW_ITEM::GEOMETRY ); + m_selArea->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } if( evt->IsMouseUp( BUT_LEFT ) ) @@ -317,11 +316,11 @@ bool SELECTION_TOOL::selectMultiple() m_selArea->ViewSetVisible( false ); // Mark items within the selection box as selected - std::vector selectedItems; + std::vector selectedItems; BOX2I selectionBox = m_selArea->ViewBBox(); view->Query( selectionBox, selectedItems ); // Get the list of selected items - std::vector::iterator it, it_end; + std::vector::iterator it, it_end; for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { @@ -405,7 +404,7 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) } // Removes possible brighten mark - getView()->MarkTargetDirty( TARGET_OVERLAY ); + getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); // Restore the original menu SetContextMenu( &m_menu, CMENU_BUTTON ); From 4876dbea249b84b62969f60160ac178452f092d7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 29 Nov 2013 16:45:39 +0100 Subject: [PATCH 04/84] Storing the selected item position from a context menu. --- common/tool/context_menu.cpp | 7 +++++-- common/tool/tool_dispatcher.cpp | 2 +- common/tool/tool_manager.cpp | 9 ++++++--- include/tool/context_menu.h | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index e20dfdf115..6dfab27e58 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -29,7 +29,7 @@ #include CONTEXT_MENU::CONTEXT_MENU() : - m_titleSet( false ), m_handler( this ), m_tool( NULL ) + m_titleSet( false ), m_selected( -1 ), m_handler( this ), m_tool( NULL ) { m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ), NULL, &m_handler ); @@ -43,7 +43,7 @@ CONTEXT_MENU::CONTEXT_MENU() : CONTEXT_MENU::CONTEXT_MENU( const CONTEXT_MENU& aMenu ) : - m_titleSet( aMenu.m_titleSet ), m_handler( this ), m_tool( aMenu.m_tool ) + m_titleSet( aMenu.m_titleSet ), m_selected( -1 ), m_handler( this ), m_tool( aMenu.m_tool ) { m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ), NULL, &m_handler ); @@ -164,6 +164,9 @@ void CONTEXT_MENU::CMEventHandler::onEvent( wxEvent& aEvent ) // One of menu entries was selected.. else if( type == wxEVT_COMMAND_MENU_SELECTED ) { + // Store the selected position + m_menu->m_selected = aEvent.GetId(); + // Check if there is a TOOL_ACTION for the given ID if( m_menu->m_toolActions.count( aEvent.GetId() ) == 1 ) { diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index b655113b38..35cefd81a2 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -147,7 +147,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti st->pressed = true; evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DOWN, args ); } - else if( up ) // Handle mouse button release + else if( up ) // Handle mouse button release { st->pressed = false; diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 75ac02574e..2644076508 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -446,9 +446,12 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent ) boost::scoped_ptr menu( new CONTEXT_MENU( *st->contextMenu ) ); GetEditFrame()->PopupMenu( menu->GetMenu() ); - // - TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CHOICE ); - dispatchInternal( evt ); + // If nothing was chosen from the context menu, we must notify the tool as well + if( menu->GetSelected() < 0 ) + { + TOOL_EVENT evt( TC_COMMAND, TA_CONTEXT_MENU_CHOICE ); + dispatchInternal( evt ); + } break; } diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index 90a5e106e8..df6f7cb0b7 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -78,6 +78,17 @@ public: */ void Clear(); + /** + * Function GetSelected() + * Returns the position of selected item. If the returned value is negative, that means that + * menu was dismissed. + * @return The position of selected item in the context menu. + */ + int GetSelected() const + { + return m_selected; + } + /** * Function GetMenu() * Returns the instance of wxMenu object used to display the menu. @@ -131,6 +142,9 @@ private: ///> Instance of wxMenu used for display of the context menu. wxMenu m_menu; + ///> Stores the id number of selected item. + int m_selected; + ///> Instance of menu event handler. CMEventHandler m_handler; From 08fd9d8cbdd3e8586f567e0bf4d8113312b96d4f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 2 Dec 2013 14:35:05 +0100 Subject: [PATCH 05/84] Overridden ViewUpdate() for MODULE class, so it handles its pads, drawings and texts. --- common/view/view.cpp | 2 +- common/view/view_item.cpp | 2 +- include/view/view.h | 13 ++++++++----- pcbnew/class_module.cpp | 22 ++++++++++++++++++++++ pcbnew/class_module.h | 3 +++ 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/common/view/view.cpp b/common/view/view.cpp index 078fa0b907..ebc0b1c1b9 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -819,7 +819,7 @@ void VIEW::clearGroupCache() } -void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ) +void VIEW::InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ) { // updateLayers updates geometry too, so we do not have to update both of them at the same time if( aUpdateFlags & VIEW_ITEM::LAYERS ) diff --git a/common/view/view_item.cpp b/common/view/view_item.cpp index 1521c88a9e..e2ddd6a01d 100644 --- a/common/view/view_item.cpp +++ b/common/view/view_item.cpp @@ -53,7 +53,7 @@ void VIEW_ITEM::ViewUpdate( int aUpdateFlags ) if( !m_view ) return; - m_view->invalidateItem( this, aUpdateFlags ); + m_view->InvalidateItem( this, aUpdateFlags ); } diff --git a/include/view/view.h b/include/view/view.h index a5e0756219..f7a7e90984 100644 --- a/include/view/view.h +++ b/include/view/view.h @@ -493,6 +493,14 @@ public: m_scaleLimits = VECTOR2D( aMaximum, aMinimum ); } + /** + * Function InvalidateItem() + * Manages dirty flags & redraw queueing when updating an item. + * @param aItem is the item to be updated. + * @param aUpdateFlags determines the way an item is refreshed. + */ + void InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ); + static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown private: @@ -563,11 +571,6 @@ private: */ void draw( VIEW_GROUP* aGroup, bool aImmediate = false ) const; - - ///* Manages dirty flags & redraw queueing when updating an item. Called internally - /// via VIEW_ITEM::ViewUpdate() - void invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags ); - ///* Sorts m_orderedLayers when layer rendering order has changed void sortLayers(); diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index dd1aca96e5..9694607a39 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -728,6 +728,28 @@ EDA_ITEM* MODULE::Clone() const } +void MODULE::ViewUpdate( int aUpdateFlags ) +{ + if( !m_view ) + return; + + // Update pads + for( D_PAD* pad = m_Pads.GetFirst(); pad; pad = pad->Next() ) + m_view->InvalidateItem( pad, aUpdateFlags ); + + // Update module's drawing (mostly silkscreen) + for( BOARD_ITEM* drawing = m_Drawings.GetFirst(); drawing; drawing = drawing->Next() ) + m_view->InvalidateItem( drawing, aUpdateFlags ); + + // Update module's texts + m_view->InvalidateItem( m_Reference, aUpdateFlags ); + m_view->InvalidateItem( m_Value, aUpdateFlags ); + + // Update the module itself + m_view->InvalidateItem( this, aUpdateFlags ); +} + + /* Test for validity of the name in a library of the footprint * ( no spaces, dir separators ... ) * return true if the given name is valid diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 184e9e7288..a1564db05e 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -447,6 +447,9 @@ public: EDA_ITEM* Clone() const; + /// @copydoc VIEW_ITEM::ViewUpdate() + void ViewUpdate( int aUpdateFlags ); + /** * Function CopyNetlistSettings * copies the netlist settings to \a aModule. From bec2e9b17850c9965185c73a76d5f072670b2c22 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 3 Dec 2013 15:17:43 +0100 Subject: [PATCH 06/84] Added some comments & asserts. --- common/tool/action_manager.cpp | 2 ++ common/tool/tool_manager.cpp | 16 +++++++++++++--- include/tool/tool_event.h | 3 +++ pcbnew/basepcbframe.cpp | 2 +- pcbnew/tools/selection_tool.h | 11 ++++++++++- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index 63aa99f8d8..d38ad1eccf 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -44,6 +44,8 @@ ACTION_MANAGER::~ACTION_MANAGER() void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) { assert( aAction->GetId() == -1 ); // Check if the TOOL_ACTION was not registered before + assert( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() ); + assert( m_actionIdIndex.find( aAction->m_id ) == m_actionIdIndex.end() ); aAction->setId( MakeActionId( aAction->m_name ) ); diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 2644076508..9fe8715604 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -120,6 +120,11 @@ TOOL_MANAGER::~TOOL_MANAGER() void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool ) { + wxASSERT_MSG( m_toolNameIndex.find( aTool->GetName() ) == m_toolNameIndex.end(), + wxT( "Adding two tools with the same name may result in unexpected behaviour.") ); + wxASSERT_MSG( m_toolIdIndex.find( aTool->GetId() ) == m_toolIdIndex.end(), + wxT( "Adding two tools with the same ID may result in unexpected behaviour.") ); + TOOL_STATE* st = new TOOL_STATE; st->theTool = aTool; @@ -227,7 +232,10 @@ bool TOOL_MANAGER::runTool( TOOL_BASE* aTool ) wxASSERT( aTool != NULL ); if( !isRegistered( aTool ) ) + { + wxASSERT_MSG( false, wxT( "You cannot run unregistered tools" ) ); return false; + } TOOL_STATE* state = m_toolState[aTool]; @@ -334,10 +342,11 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) // Go() method that match the event. if( st->transitions.size() ) { - BOOST_FOREACH( TRANSITION tr, st->transitions ) + BOOST_FOREACH( TRANSITION& tr, st->transitions ) { if( tr.first.Matches( aEvent ) ) { + // as the state changes, the transition table has to be set up again st->transitions.clear(); // no tool context allocated yet? Create one. @@ -351,6 +360,9 @@ void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent ) if( !st->cofunc->Running() ) finishTool( st ); // The couroutine has finished immediately? + + // there is no point in further checking, as transitions got cleared + break; } } } @@ -406,8 +418,6 @@ void TOOL_MANAGER::finishTool( TOOL_STATE* aState ) if( it != m_activeTools.end() ) m_activeTools.erase( it ); - else - wxLogWarning( wxT( "Tried to finish inactive tool" ) ); aState->idle = true; delete aState->cofunc; diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index 1ec5b1414d..a2815035d2 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -321,6 +321,9 @@ public: if( m_commandId && aEvent.m_commandId ) return *m_commandId == *aEvent.m_commandId; + + // Command-type event has to contain either id or string + assert( false ); } return true; diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index 89c5a8866e..dd235976c3 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -609,7 +609,7 @@ void PCB_BASE_FRAME::UseGalCanvas( bool aEnable ) EDA_DRAW_FRAME::UseGalCanvas( aEnable ); m_toolManager->SetEnvironment( m_Pcb, m_galCanvas->GetView(), - m_galCanvas->GetViewControls(), this ); + m_galCanvas->GetViewControls(), this ); ViewReloadBoard( m_Pcb ); } diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index ee8cf45003..faf48ef8db 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -68,7 +68,16 @@ public: KIGFX::VIEW_GROUP* group; /// Checks if there is anything selected - bool Empty() const { return items.empty(); } + bool Empty() const + { + return items.empty(); + } + + /// Returns the number of selected parts + int Size() const + { + return items.size(); + } }; /// @copydoc TOOL_INTERACTIVE::Reset() From ad3cb1f36adbd3938f0ab9e7e013374a46119db7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 3 Dec 2013 15:41:41 +0100 Subject: [PATCH 07/84] Added TOOL_MANAGER::RunAction() function. --- common/tool/tool_manager.cpp | 6 ++++++ include/tool/tool_manager.h | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 9fe8715604..9e56e61545 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -194,6 +194,12 @@ void TOOL_MANAGER::UnregisterAction( TOOL_ACTION* aAction ) } +bool TOOL_MANAGER::RunAction( const std::string& aActionName ) +{ + return m_actionMgr->RunAction( aActionName ); +} + + bool TOOL_MANAGER::invokeTool( TOOL_BASE* aTool ) { wxASSERT( aTool != NULL ); diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h index 38a2879ccd..57026c2712 100644 --- a/include/tool/tool_manager.h +++ b/include/tool/tool_manager.h @@ -99,6 +99,15 @@ public: */ void UnregisterAction( TOOL_ACTION* aAction ); + /** + * Function RunAction() + * Runs the specified action. The common format is "application.ToolName.Action". + * + * @param aActionName is the name of action to be invoked. + * @return True if the action finished successfully, false otherwise. + */ + bool RunAction( const std::string& aActionName ); + /** * Function FindTool() * Searches for a tool with given ID. From b582162cb5f3d480002b3ad03d1645a3cd9d1260 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 3 Dec 2013 15:57:09 +0100 Subject: [PATCH 08/84] Split rotate and flip operations into separate functions. Added Properties action (display properties windows) --- pcbnew/tools/common_actions.cpp | 6 +- pcbnew/tools/common_actions.h | 5 +- pcbnew/tools/move_tool.cpp | 144 ++++++++++++++++++++++++-------- pcbnew/tools/move_tool.h | 35 +++++++- pcbnew/tools/pcb_tools.cpp | 1 + pcbnew/tools/selection_tool.cpp | 18 +++- 6 files changed, 164 insertions(+), 45 deletions(-) diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index a61ebc52b0..e1b95141c6 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -36,9 +36,13 @@ TOOL_ACTION COMMON_ACTIONS::moveActivate( "pcbnew.InteractiveMove", "Move", "Moves the selected item(s)" ); TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.InteractiveMove.rotate", - AS_CONTEXT, ' ', + AS_CONTEXT, 'R', "Rotate", "Rotates selected item(s)" ); TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveMove.flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ); + +TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveMove.properties", + AS_GLOBAL, 'E', + "Properties...", "Displays properties window" ); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 547b86f814..c93dd29220 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -24,7 +24,7 @@ #include -class ACTION_MANAGER; +//class ACTION_MANAGER; /** * Class COMMON_ACTIONS @@ -46,4 +46,7 @@ public: /// Flipping of selected objects static TOOL_ACTION flip; + + /// Activation of the edit tool + static TOOL_ACTION properties; }; diff --git a/pcbnew/tools/move_tool.cpp b/pcbnew/tools/move_tool.cpp index 6750d3e8fd..ccafa2c835 100644 --- a/pcbnew/tools/move_tool.cpp +++ b/pcbnew/tools/move_tool.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -41,38 +42,26 @@ MOVE_TOOL::MOVE_TOOL() : } -MOVE_TOOL::~MOVE_TOOL() -{ -} - - -void MOVE_TOOL::Reset() -{ - // The tool launches upon reception of action event ("pcbnew.InteractiveMove") - Go( &MOVE_TOOL::Main, COMMON_ACTIONS::moveActivate.MakeEvent() ); -} - - bool MOVE_TOOL::Init() { // Find the selection tool, so they can cooperate TOOL_BASE* selectionTool = m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ); - if( selectionTool ) - { - m_selectionTool = static_cast( selectionTool ); - - // Add context menu entries that are displayed when selection tool is active - m_selectionTool->AddMenuItem( COMMON_ACTIONS::moveActivate ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::rotate ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::flip ); - } - else + m_selectionTool = static_cast( selectionTool ); + if( !selectionTool ) { DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) ); return false; } + // Add context menu entries that are displayed when selection tool is active + m_selectionTool->AddMenuItem( COMMON_ACTIONS::moveActivate ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::rotate ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::flip ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties ); + + setTransitions(); + return true; } @@ -85,7 +74,7 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) return 0; // there are no items to operate on VECTOR2D dragPosition; - bool dragging = false; + m_dragging = false; bool restore = false; // Should items' state be restored when finishing the tool? VIEW_CONTROLS* controls = getViewControls(); @@ -105,23 +94,15 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) // Dispatch TOOL_ACTIONs else if( evt->Category() == TC_COMMAND ) { - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); - - if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) // got rotation event? - { - m_state.Rotate( cursorPos, 900.0 ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) // got flip event? - { - m_state.Flip( cursorPos ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } + if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + Rotate( aEvent ); + else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + Flip( aEvent ); } else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { - if( dragging ) + if( m_dragging ) { // Drag items to the current cursor position VECTOR2D movement = ( evt->Position() - dragPosition ); @@ -138,16 +119,19 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) m_state.Save( *it ); } - dragging = true; + m_dragging = true; } selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); dragPosition = evt->Position(); } + else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) break; // Finish } + m_dragging = false; + if( restore ) { // Modifications has to be rollbacked, so restore the previous state of items @@ -165,5 +149,91 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) controls->SetSnapping( false ); controls->SetAutoPan( false ); + setTransitions(); + return 0; } + + +int MOVE_TOOL::Properties( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + + // Properties are displayed when there is only one item selected + if( selection.items.size() == 1 ) + { + // Display properties dialog + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + BOARD_ITEM* item = *selection.items.begin(); + editFrame->OnEditItemRequest( NULL, item ); + + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + setTransitions(); + + return 0; +} + + +int MOVE_TOOL::Rotate( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + + if( m_dragging ) + { + m_state.Rotate( cursorPos, 900.0 ); + selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); + } + else + { + std::set::iterator it; + + for( it = selection.items.begin(); it != selection.items.end(); ++it ) + { + (*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 ); + (*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + setTransitions(); + } + + return 0; +} + + +int MOVE_TOOL::Flip( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + + if( m_dragging ) + { + m_state.Flip( cursorPos ); + selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); + } + else + { + std::set::iterator it; + + for( it = selection.items.begin(); it != selection.items.end(); ++it ) + { + (*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); + (*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); + } + + setTransitions(); + } + + return 0; +} + + +void MOVE_TOOL::setTransitions() +{ + Go( &MOVE_TOOL::Main, COMMON_ACTIONS::moveActivate.MakeEvent() ); + Go( &MOVE_TOOL::Rotate, COMMON_ACTIONS::rotate.MakeEvent() ); + Go( &MOVE_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); + Go( &MOVE_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); +} diff --git a/pcbnew/tools/move_tool.h b/pcbnew/tools/move_tool.h index 1140d0067e..9b7a88012d 100644 --- a/pcbnew/tools/move_tool.h +++ b/pcbnew/tools/move_tool.h @@ -49,10 +49,9 @@ class MOVE_TOOL : public TOOL_INTERACTIVE { public: MOVE_TOOL(); - ~MOVE_TOOL(); /// @copydoc TOOL_INTERACTIVE::Reset() - void Reset(); + void Reset() {}; /// @copydoc TOOL_INTERACTIVE::Init() bool Init(); @@ -61,15 +60,43 @@ public: * Function Main() * * Main loop in which events are handled. + * @param aEvent is the handled event. */ int Main( TOOL_EVENT& aEvent ); + /** + * Function Edit() + * + * Displays properties window for the selected object. + */ + int Properties( TOOL_EVENT& aEvent ); + + /** + * Function Rotate() + * + * Rotates currently selected items. + */ + int Rotate( TOOL_EVENT& aEvent ); + + /** + * Function Flip() + * + * Rotates currently selected items. The rotation point is the current cursor position. + */ + int Flip( TOOL_EVENT& aEvent ); + private: - /// Saves the state of items and allows to restore them + ///> Saves the state of items and allows to restore them ITEM_STATE m_state; - /// Selection tool used for obtaining selected items + ///> Selection tool used for obtaining selected items SELECTION_TOOL* m_selectionTool; + + ///> Flag determining if anything is being dragged right now + bool m_dragging; + + ///> Sets up handlers for various events + void setTransitions(); }; #endif diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index 2f9676cb94..aaccb18978 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -51,6 +51,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionActivate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::rotate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::flip ); + m_toolManager->RegisterAction( &COMMON_ACTIONS::properties ); // Register tools m_toolManager->RegisterTool( new SELECTION_TOOL ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index decd7fe9e5..e7d56cd291 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -102,11 +102,25 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) } // single click? Select single object - if( evt->IsClick( BUT_LEFT ) ) + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !m_additive && m_selection.Size() > 1 ) + clearSelection(); + selectSingle( evt->Position() ); + } + + else if( evt->IsDblClick( BUT_LEFT ) ) + { + if( m_selection.Empty() ) + selectSingle( evt->Position() ); + + // Display properties window + m_toolMgr->RunAction( "pcbnew.InteractiveMove.properties" ); + } // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them - if( evt->IsDrag( BUT_LEFT ) ) + else if( evt->IsDrag( BUT_LEFT ) ) { if( m_selection.Empty() || m_additive ) { From 07a5774a1ef2c3aeba27074c69820f35ccf8357c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 3 Dec 2013 16:09:03 +0100 Subject: [PATCH 09/84] Renamed MOVE_TOOL to EDIT_TOOL. --- pcbnew/CMakeLists.txt | 2 +- pcbnew/tools/common_actions.cpp | 10 +- pcbnew/tools/common_actions.h | 2 +- pcbnew/tools/move_tool.cpp | 239 -------------------------------- pcbnew/tools/move_tool.h | 102 -------------- pcbnew/tools/pcb_tools.cpp | 6 +- pcbnew/tools/selection_tool.cpp | 4 +- pcbnew/tools/selection_tool.h | 2 +- 8 files changed, 13 insertions(+), 354 deletions(-) delete mode 100644 pcbnew/tools/move_tool.cpp delete mode 100644 pcbnew/tools/move_tool.h diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 360f98a5c3..770554f2c0 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -241,7 +241,7 @@ set( PCBNEW_CLASS_SRCS tools/selection_tool.cpp tools/selection_area.cpp tools/bright_box.cpp - tools/move_tool.cpp + tools/edit_tool.cpp tools/pcb_tools.cpp tools/common_actions.cpp ) diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index e1b95141c6..12aa52cb8f 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -30,19 +30,19 @@ TOOL_ACTION COMMON_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection", AS_GLOBAL, 'S', "Selection tool", "Allows to select items" ); -// Move tool actions -TOOL_ACTION COMMON_ACTIONS::moveActivate( "pcbnew.InteractiveMove", +// Edit tool actions +TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", AS_GLOBAL, 'M', "Move", "Moves the selected item(s)" ); -TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.InteractiveMove.rotate", +TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.InteractiveEdit.rotate", AS_CONTEXT, 'R', "Rotate", "Rotates selected item(s)" ); -TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveMove.flip", +TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ); -TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveMove.properties", +TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties", AS_GLOBAL, 'E', "Properties...", "Displays properties window" ); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index c93dd29220..5e8bbd7efc 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -36,7 +36,7 @@ class COMMON_ACTIONS { public: /// Activation of the move tool - static TOOL_ACTION moveActivate; + static TOOL_ACTION editActivate; /// Activation of the selection tool static TOOL_ACTION selectionActivate; diff --git a/pcbnew/tools/move_tool.cpp b/pcbnew/tools/move_tool.cpp deleted file mode 100644 index ccafa2c835..0000000000 --- a/pcbnew/tools/move_tool.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * 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 -#include -#include -#include -#include -#include - -#include "common_actions.h" -#include "selection_tool.h" -#include "move_tool.h" - -using namespace KIGFX; -using boost::optional; - -MOVE_TOOL::MOVE_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveMove" ), m_selectionTool( NULL ) -{ -} - - -bool MOVE_TOOL::Init() -{ - // Find the selection tool, so they can cooperate - TOOL_BASE* selectionTool = m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ); - - m_selectionTool = static_cast( selectionTool ); - if( !selectionTool ) - { - DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) ); - return false; - } - - // Add context menu entries that are displayed when selection tool is active - m_selectionTool->AddMenuItem( COMMON_ACTIONS::moveActivate ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::rotate ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::flip ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties ); - - setTransitions(); - - return true; -} - - -int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) -{ - const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - - if( selection.Empty() ) - return 0; // there are no items to operate on - - VECTOR2D dragPosition; - m_dragging = false; - bool restore = false; // Should items' state be restored when finishing the tool? - - VIEW_CONTROLS* controls = getViewControls(); - controls->ShowCursor( true ); - controls->SetSnapping( true ); - controls->SetAutoPan( true ); - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - if( evt->IsCancel() ) - { - restore = true; // Cancelling the tool means that items have to be restored - break; // Finish - } - - // Dispatch TOOL_ACTIONs - else if( evt->Category() == TC_COMMAND ) - { - if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) - Rotate( aEvent ); - else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) - Flip( aEvent ); - } - - else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) - { - if( m_dragging ) - { - // Drag items to the current cursor position - VECTOR2D movement = ( evt->Position() - dragPosition ); - m_state.Move( movement ); - } - else - { - // Prepare to drag - std::set::iterator it; - - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - // Save the state of the selected items, in case it has to be restored - m_state.Save( *it ); - } - - m_dragging = true; - } - - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - dragPosition = evt->Position(); - } - - else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) - break; // Finish - } - - m_dragging = false; - - if( restore ) - { - // Modifications has to be rollbacked, so restore the previous state of items - selection.group->ItemsViewUpdate( VIEW_ITEM::APPEARANCE ); - m_state.RestoreAll(); - } - else - { - // Changes are applied, so update the items - selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() ); - m_state.Apply(); - } - - controls->ShowCursor( false ); - controls->SetSnapping( false ); - controls->SetAutoPan( false ); - - setTransitions(); - - return 0; -} - - -int MOVE_TOOL::Properties( TOOL_EVENT& aEvent ) -{ - const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - - // Properties are displayed when there is only one item selected - if( selection.items.size() == 1 ) - { - // Display properties dialog - PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); - BOARD_ITEM* item = *selection.items.begin(); - editFrame->OnEditItemRequest( NULL, item ); - - item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - - setTransitions(); - - return 0; -} - - -int MOVE_TOOL::Rotate( TOOL_EVENT& aEvent ) -{ - const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); - - if( m_dragging ) - { - m_state.Rotate( cursorPos, 900.0 ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else - { - std::set::iterator it; - - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - (*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 ); - (*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - - setTransitions(); - } - - return 0; -} - - -int MOVE_TOOL::Flip( TOOL_EVENT& aEvent ) -{ - const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); - - if( m_dragging ) - { - m_state.Flip( cursorPos ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else - { - std::set::iterator it; - - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - (*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); - (*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); - } - - setTransitions(); - } - - return 0; -} - - -void MOVE_TOOL::setTransitions() -{ - Go( &MOVE_TOOL::Main, COMMON_ACTIONS::moveActivate.MakeEvent() ); - Go( &MOVE_TOOL::Rotate, COMMON_ACTIONS::rotate.MakeEvent() ); - Go( &MOVE_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); - Go( &MOVE_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); -} diff --git a/pcbnew/tools/move_tool.h b/pcbnew/tools/move_tool.h deleted file mode 100644 index 9b7a88012d..0000000000 --- a/pcbnew/tools/move_tool.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * 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 __MOVE_TOOL_H -#define __MOVE_TOOL_H - -#include -#include -#include -#include "item_state.h" - -class BOARD_ITEM; -class SELECTION_TOOL; - -namespace KIGFX -{ -class VIEW_GROUP; -} - -/** - * Class MOVE_TOOL - * - * Our sample move tool. Allows to move, rotate and flip items selected by - * pcbnew.InteractiveSelection tool. - */ - -class MOVE_TOOL : public TOOL_INTERACTIVE -{ -public: - MOVE_TOOL(); - - /// @copydoc TOOL_INTERACTIVE::Reset() - void Reset() {}; - - /// @copydoc TOOL_INTERACTIVE::Init() - bool Init(); - - /** - * Function Main() - * - * Main loop in which events are handled. - * @param aEvent is the handled event. - */ - int Main( TOOL_EVENT& aEvent ); - - /** - * Function Edit() - * - * Displays properties window for the selected object. - */ - int Properties( TOOL_EVENT& aEvent ); - - /** - * Function Rotate() - * - * Rotates currently selected items. - */ - int Rotate( TOOL_EVENT& aEvent ); - - /** - * Function Flip() - * - * Rotates currently selected items. The rotation point is the current cursor position. - */ - int Flip( TOOL_EVENT& aEvent ); - -private: - ///> Saves the state of items and allows to restore them - ITEM_STATE m_state; - - ///> Selection tool used for obtaining selected items - SELECTION_TOOL* m_selectionTool; - - ///> Flag determining if anything is being dragged right now - bool m_dragging; - - ///> Sets up handlers for various events - void setTransitions(); -}; - -#endif diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index aaccb18978..f6903f6420 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -35,7 +35,7 @@ #include #include "selection_tool.h" -#include "move_tool.h" +#include "edit_tool.h" #include "common_actions.h" #include @@ -47,7 +47,7 @@ void PCB_EDIT_FRAME::setupTools() m_galCanvas->SetEventDispatcher( m_toolDispatcher ); // Register tool actions - m_toolManager->RegisterAction( &COMMON_ACTIONS::moveActivate ); + m_toolManager->RegisterAction( &COMMON_ACTIONS::editActivate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionActivate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::rotate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::flip ); @@ -56,7 +56,7 @@ void PCB_EDIT_FRAME::setupTools() // Register tools m_toolManager->RegisterTool( new SELECTION_TOOL ); m_toolManager->RegisterTool( new ROUTER_TOOL ); - m_toolManager->RegisterTool( new MOVE_TOOL ); + m_toolManager->RegisterTool( new EDIT_TOOL ); } diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index e7d56cd291..23033b02f4 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -116,7 +116,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) selectSingle( evt->Position() ); // Display properties window - m_toolMgr->RunAction( "pcbnew.InteractiveMove.properties" ); + m_toolMgr->RunAction( "pcbnew.InteractiveEdit.properties" ); } // drag with LMB? Select multiple objects (or at least draw a selection box) or drag them @@ -134,7 +134,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) if( containsSelected( evt->Position() ) ) { // Yes -> run the move tool and wait till it finishes - m_toolMgr->InvokeTool( "pcbnew.InteractiveMove" ); + m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); } else { diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index faf48ef8db..6b3d62ba28 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -50,7 +50,7 @@ class VIEW_GROUP; * - draw selection box (drag LMB) * - handles MODULEs properly (ie. selects either MODULE or its PADs, TEXTs, etc.) * - takes into account high-contrast & layer visibility settings - * - invokes InteractiveMove tool when user starts to drag selected items + * - invokes InteractiveEdit tool when user starts to drag selected items */ class SELECTION_TOOL : public TOOL_INTERACTIVE From 24a317ce28aa552e239d71590b2360279e900240 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 3 Dec 2013 17:11:22 +0100 Subject: [PATCH 10/84] The Selection Tool is always active. Removed entries for toolbar menu and hotkeys for the tool. --- common/tool/tool_dispatcher.cpp | 5 ----- common/tool/tool_manager.cpp | 5 +++-- pcbnew/menubar_pcbframe.cpp | 5 ----- pcbnew/pcbframe.cpp | 2 -- pcbnew/pcbnew_id.h | 1 - pcbnew/tools/common_actions.cpp | 3 +-- pcbnew/tools/common_actions.h | 6 +++--- pcbnew/tools/pcb_tools.cpp | 7 ++++++- pcbnew/tools/selection_tool.cpp | 27 +++++++++++++++------------ pcbnew/tools/selection_tool.h | 4 ++++ 10 files changed, 32 insertions(+), 33 deletions(-) diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 35cefd81a2..6fb5d5f500 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -280,11 +280,6 @@ void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent ) toolName = "pcbnew.InteractiveRouter"; activateTool = true; break; - - case ID_SELECTION_TOOL: - toolName = "pcbnew.InteractiveSelection"; - activateTool = true; - break; } // do nothing if the legacy view is active diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 9e56e61545..695203f447 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -97,7 +97,7 @@ struct TOOL_MANAGER::TOOL_STATE TOOL_MANAGER::TOOL_MANAGER() : - m_model( NULL ), m_view( NULL ) + m_model( NULL ), m_view( NULL ), m_viewControls( NULL ), m_editFrame( NULL ) { m_actionMgr = new ACTION_MANAGER( this ); } @@ -476,7 +476,8 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent ) if( m_view->IsDirty() ) { PCB_EDIT_FRAME* f = static_cast( GetEditFrame() ); - f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER. + if( f->IsGalCanvasActive() ) + f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER. } return false; diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 766b563833..9db3c5e309 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -310,11 +310,6 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() editMenu->AppendSeparator(); - AddMenuItem( editMenu, ID_SELECTION_TOOL, - _( "Select Tool" ), - _( "Interactive selection and drag&drop tool." ), - KiBitmap( tools_xpm ) ); - AddMenuItem( editMenu, ID_PNS_ROUTER_TOOL, _( "Interactive router" ), _( "Interactive router drag&drop tool." ), diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index b6a2a2c2d5..963581d197 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -121,8 +121,6 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) // menu Config /* Tom's hacks start */ - EVT_MENU ( ID_SELECTION_TOOL, PCB_EDIT_FRAME::onGenericCommand ) - EVT_TOOL ( ID_SELECTION_TOOL, PCB_EDIT_FRAME::onGenericCommand ) EVT_MENU ( ID_PNS_ROUTER_TOOL, PCB_EDIT_FRAME::onGenericCommand ) EVT_TOOL ( ID_PNS_ROUTER_TOOL, PCB_EDIT_FRAME::onGenericCommand ) /* Tom's hacks end */ diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index 1a03a3764c..d5a836b93a 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -370,7 +370,6 @@ enum pcbnew_ids ID_FOOTPRINT_WIZARD_SELECT_WIZARD, ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD, - ID_SELECTION_TOOL, ID_PNS_ROUTER_TOOL }; diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 12aa52cb8f..7a7aef37b1 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -27,8 +27,7 @@ // Selection tool actions TOOL_ACTION COMMON_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection", - AS_GLOBAL, 'S', - "Selection tool", "Allows to select items" ); + AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere // Edit tool actions TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 5e8bbd7efc..ae12439870 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -35,12 +35,12 @@ class COMMON_ACTIONS { public: - /// Activation of the move tool - static TOOL_ACTION editActivate; - /// Activation of the selection tool static TOOL_ACTION selectionActivate; + /// Activation of the edit tool + static TOOL_ACTION editActivate; + /// Rotation of selected objects static TOOL_ACTION rotate; diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index f6903f6420..db347e8c4b 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -48,7 +48,6 @@ void PCB_EDIT_FRAME::setupTools() // Register tool actions m_toolManager->RegisterAction( &COMMON_ACTIONS::editActivate ); - m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionActivate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::rotate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::flip ); m_toolManager->RegisterAction( &COMMON_ACTIONS::properties ); @@ -57,6 +56,12 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new SELECTION_TOOL ); m_toolManager->RegisterTool( new ROUTER_TOOL ); m_toolManager->RegisterTool( new EDIT_TOOL ); + + m_toolManager->SetEnvironment( NULL, m_galCanvas->GetView(), + m_galCanvas->GetViewControls(), this ); + + // Run the selection tool, it is supposed to be always active + m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" ); } diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index b175e85b09..918fb8f2aa 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -66,6 +66,8 @@ SELECTION_TOOL::~SELECTION_TOOL() void SELECTION_TOOL::Reset() { + clearSelection(); + // Reinsert the VIEW_GROUP, in case it was removed from the VIEW getView()->Remove( m_selection.group ); getView()->Add( m_selection.group ); @@ -77,12 +79,6 @@ void SELECTION_TOOL::Reset() int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) { - KIGFX::VIEW* view = getView(); - - assert( getModel( PCB_T ) != NULL ); - - view->Add( m_selection.group ); - // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { @@ -94,8 +90,8 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) { if( !m_selection.Empty() ) // Cancel event deselects items... clearSelection(); - else // ...unless there is nothing selected - break; // then exit the tool + + // This tool never exits } // single click? Select single object @@ -142,8 +138,8 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) } } - m_selection.group->Clear(); - view->Remove( m_selection.group ); + // This tool is supposed to be active forever + assert( false ); return 0; } @@ -188,6 +184,7 @@ void SELECTION_TOOL::clearSelection() { KIGFX::VIEW_GROUP::const_iter it, it_end; + // Restore the initial properties for( it = m_selection.group->Begin(), it_end = m_selection.group->End(); it != it_end; ++it ) { BOARD_ITEM* item = static_cast( *it ); @@ -196,8 +193,7 @@ void SELECTION_TOOL::clearSelection() item->ClearSelected(); } - m_selection.group->Clear(); - m_selection.items.clear(); + m_selection.Clear(); // Do not show the context menu when there is nothing selected SetContextMenu( &m_menu, CMENU_OFF ); @@ -609,3 +605,10 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const return false; } + + +void SELECTION_TOOL::SELECTION::Clear() +{ + items.clear(); + group->Clear(); +} diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 6b3d62ba28..40806c3b94 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -78,6 +78,10 @@ public: { return items.size(); } + + /// Clears both the VIEW_GROUP and set of selected items. Please note that it does not + /// change properties of selected items (e.g. selection flag). + void Clear(); }; /// @copydoc TOOL_INTERACTIVE::Reset() From 27c7eb5dcec71aa66708b8672843396291b74951 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 4 Dec 2013 10:58:51 +0100 Subject: [PATCH 11/84] The Selection Tool displays information about selected items. ClearSelection() made public. --- pcbnew/tools/selection_tool.cpp | 110 ++++++++++++++++++-------------- pcbnew/tools/selection_tool.h | 15 ++++- 2 files changed, 73 insertions(+), 52 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 918fb8f2aa..9538f27c4b 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -66,7 +66,7 @@ SELECTION_TOOL::~SELECTION_TOOL() void SELECTION_TOOL::Reset() { - clearSelection(); + ClearSelection(); // Reinsert the VIEW_GROUP, in case it was removed from the VIEW getView()->Remove( m_selection.group ); @@ -89,7 +89,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) if( evt->IsCancel() ) { if( !m_selection.Empty() ) // Cancel event deselects items... - clearSelection(); + ClearSelection(); // This tool never exits } @@ -98,7 +98,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) else if( evt->IsClick( BUT_LEFT ) ) { if( !m_additive && m_selection.Size() > 1 ) - clearSelection(); + ClearSelection(); selectSingle( evt->Position() ); } @@ -132,7 +132,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) else { // No -> clear the selection list - clearSelection(); + ClearSelection(); } } } @@ -145,42 +145,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) } -void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) -{ - assert( aAction.GetId() > 0 ); // Check if the action was registered before in ACTION_MANAGER - - m_menu.Add( aAction ); -} - - -void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) -{ - if( m_selection.items.find( aItem ) != m_selection.items.end() ) - { - deselectItem( aItem ); - - // If there is nothing selected, disable the context menu - if( m_selection.Empty() ) - SetContextMenu( &m_menu, CMENU_OFF ); - } - else - { - if( !m_additive ) - clearSelection(); - - // Prevent selection of invisible or inactive items - if( selectable( aItem ) ) - { - selectItem( aItem ); - - // Now the context menu should be enabled - SetContextMenu( &m_menu, CMENU_BUTTON ); - } - } -} - - -void SELECTION_TOOL::clearSelection() +void SELECTION_TOOL::ClearSelection() { KIGFX::VIEW_GROUP::const_iter it, it_end; @@ -195,11 +160,45 @@ void SELECTION_TOOL::clearSelection() m_selection.Clear(); + getEditFrame()->SetCurItem( NULL ); + // Do not show the context menu when there is nothing selected SetContextMenu( &m_menu, CMENU_OFF ); } +void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) +{ + assert( aAction.GetId() > 0 ); // Check if the action was registered before in ACTION_MANAGER + + m_menu.Add( aAction ); +} + + +void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) +{ + if( isSelected( aItem ) ) + { + deselectItem( aItem ); + } + else + { + if( !m_additive ) + ClearSelection(); + + // Prevent selection of invisible or inactive items + if( selectable( aItem ) ) + selectItem( aItem ); + } +} + + +bool SELECTION_TOOL::isSelected( const BOARD_ITEM* aItem ) const +{ + return ( m_selection.items.find( const_cast( aItem ) ) != m_selection.items.end() ); +} + + void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) { BOARD* pcb = getModel( PCB_T ); @@ -214,7 +213,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) { case 0: if( !m_additive ) - clearSelection(); + ClearSelection(); break; @@ -308,7 +307,7 @@ bool SELECTION_TOOL::selectMultiple() if( evt->IsDrag( BUT_LEFT ) ) { if( !m_additive ) - clearSelection(); + ClearSelection(); // Start drawing a selection box m_selArea->SetOrigin( evt->DragOrigin() ); @@ -338,11 +337,10 @@ bool SELECTION_TOOL::selectMultiple() selectItem( item ); } - // Now the context menu should be enabled - if( !m_selection.Empty() ) - SetContextMenu( &m_menu, CMENU_BUTTON ); + // Do not display information about selected item,as there is more than one + getEditFrame()->SetCurItem( NULL ); - break; + break; // Stop waiting for events } } @@ -413,9 +411,6 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) // Removes possible brighten mark getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); - // Restore the original menu - SetContextMenu( &m_menu, CMENU_BUTTON ); - return current; } @@ -542,6 +537,16 @@ void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) // Add items to the VIEW_GROUP, so they will be displayed on the overlay selectBase( aItem ); m_selection.items.insert( aItem ); + + // It is enough to do it only for the first selected item + if( m_selection.items.size() == 1 ) + { + // Set as the current item, so the information about selection is displayed + getEditFrame()->SetCurItem( aItem, true ); + + // Now the context menu should be enabled + SetContextMenu( &m_menu, CMENU_BUTTON ); + } } @@ -584,6 +589,13 @@ void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) deselectBase( aItem ); m_selection.items.erase( aItem ); + + // If there is nothing selected, disable the context menu + if( m_selection.Empty() ) + { + SetContextMenu( &m_menu, CMENU_OFF ); + getEditFrame()->SetCurItem( NULL ); + } } diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 40806c3b94..fa6ed0f545 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -104,6 +104,12 @@ public: return m_selection; } + /** + * Function ClearSelection() + * Clears the current selection. + */ + void ClearSelection(); + /** * Function AddAction() * @@ -156,10 +162,13 @@ private: void toggleSelection( BOARD_ITEM* aItem ); /** - * Function clearSelection() - * Clears selections of currently selected items. + * Function isSelected() + * Tests if an item is currently selected. + * + * @param aItem is the item to be checked. + * @return True if the item is selected, false otherwise. */ - void clearSelection(); + bool isSelected( const BOARD_ITEM* aItem ) const; /** * Function selectable() From c5a1df62164080e39e4efa6d066ab26e649fb0a7 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 5 Dec 2013 14:48:44 +0100 Subject: [PATCH 12/84] ClearHotKey() function. --- common/tool/action_manager.cpp | 12 ++++++++++++ include/tool/action_manager.h | 13 ++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index d38ad1eccf..fde03fb510 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -53,7 +53,13 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) m_actionIdIndex[aAction->m_id] = aAction; if( aAction->HasHotKey() ) + { + // Duplication of hot keys leads to unexpected behaviour + // The right way to change a hotkey is to use ACTION_MANAGER::ClearHotKey() first + assert( m_actionHotKeys.find( aAction->m_currentHotKey ) == m_actionHotKeys.end() ); + m_actionHotKeys[aAction->m_currentHotKey] = aAction; + } aAction->setActionMgr( this ); } @@ -107,6 +113,12 @@ bool ACTION_MANAGER::RunHotKey( int aHotKey ) const } +void ACTION_MANAGER::ClearHotKey( int aHotKey ) +{ + m_actionHotKeys.erase( aHotKey ); +} + + void ACTION_MANAGER::runAction( const TOOL_ACTION* aAction ) const { TOOL_EVENT event = aAction->MakeEvent(); diff --git a/include/tool/action_manager.h b/include/tool/action_manager.h index dbcb7b33b6..fa66a23eba 100644 --- a/include/tool/action_manager.h +++ b/include/tool/action_manager.h @@ -81,18 +81,21 @@ public: */ bool RunAction( const std::string& aActionName ) const; - // TODO to be considered - // bool RunAction( int aActionId ) const; - // bool RunAction( TOOL_ACTION* aAction ) const; - /** * Function RunHotKey() * Runs an action associated with a hotkey (if there is one available). - * @param aHotKey is the hotkey to be served. + * @param aHotKey is the hotkey to be handled. * @return True if there was an action associated with the hotkey, false otherwise. */ bool RunHotKey( int aHotKey ) const; + /** + * Function ClearHotKey() + * Removes an action associated with a hotkey. + * @param aHotKey is the hotkey to be cleared. + */ + void ClearHotKey( int aHotKey ); + private: ///> Tool manager needed to run actions TOOL_MANAGER* m_toolMgr; From fc2d8e91c926d85abad0407c3790d631c2813607 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 5 Dec 2013 14:52:08 +0100 Subject: [PATCH 13/84] Changed selection rules (pads&modules can be selected depending on the 'modules front/back' visibility instead of corresponding copper layers). Fixed comments. --- pcbnew/tools/selection_tool.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 9538f27c4b..f24dbaffd9 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -458,21 +458,21 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const break; case PCB_PAD_T: - { // Pads are not selectable in multiple selection mode if( m_multiple ) return false; + /* no break */ - // Pads are supposed to be on top, bottom or both at the same time (THT) - if( aItem->IsOnLayer( LAYER_N_FRONT ) && board->IsLayerVisible( LAYER_N_FRONT ) ) + case PCB_MODULE_T: + if( aItem->IsOnLayer( LAYER_N_FRONT ) && board->IsElementVisible( MOD_FR_VISIBLE ) ) return true; - if( aItem->IsOnLayer( LAYER_N_BACK ) && board->IsLayerVisible( LAYER_N_BACK ) ) + if( aItem->IsOnLayer( LAYER_N_BACK ) && board->IsLayerVisible( MOD_BK_VISIBLE ) ) return true; return false; - } - break; + + break; case PCB_MODULE_TEXT_T: // Module texts are not selectable in multiple selection mode @@ -483,7 +483,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const // These are not selectable, otherwise silkscreen drawings would be easily destroyed case PCB_MODULE_EDGE_T: - // and some other stuff that should be selected + // and some other stuff that should not be selected case NOT_USED: case TYPE_NOT_INIT: return false; @@ -516,8 +516,8 @@ void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) } } selectBase( m_selection ); - // Modules are treated in a special way - when they are moved, we have to - // move all the parts that make the module, not the module itself + // Modules are treated in a special way - when they are selected, we have to + // select all the parts that make the module, not the module itself if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); @@ -569,8 +569,8 @@ void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) } } deselectBase( m_selection ); - // Modules are treated in a special way - when they are moved, we have to - // move all the parts that make the module, not the module itself + // Modules are treated in a special way - when they are selected, we have to + // select all the parts that make the module, not the module itself if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); From aebb8b3ff9c7f10e383e5f1e331d1c3d60312570 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 6 Dec 2013 13:57:56 +0100 Subject: [PATCH 14/84] Fixed an infinite loop in the destructor of ACTION_MANAGER; --- common/tool/action_manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/tool/action_manager.cpp b/common/tool/action_manager.cpp index fde03fb510..a00d4d08cc 100644 --- a/common/tool/action_manager.cpp +++ b/common/tool/action_manager.cpp @@ -67,13 +67,13 @@ void ACTION_MANAGER::RegisterAction( TOOL_ACTION* aAction ) void ACTION_MANAGER::UnregisterAction( TOOL_ACTION* aAction ) { + m_actionNameIndex.erase( aAction->m_name ); + m_actionIdIndex.erase( aAction->m_id ); + // Indicate that the ACTION_MANAGER no longer care about the object aAction->setActionMgr( NULL ); aAction->setId( -1 ); - m_actionNameIndex.erase( aAction->m_name ); - m_actionIdIndex.erase( aAction->m_id ); - if( aAction->HasHotKey() ) m_actionHotKeys.erase( aAction->m_currentHotKey ); } From d8acd1c7187a6591802a10022c81a5a595bd924f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 9 Dec 2013 10:42:38 +0100 Subject: [PATCH 15/84] Moved Init() & Reset() from TOOL_INTERACTIVE to TOOL_BASE. Added REASON enum for Reset() function, so tools will know why a reset occured. Fixed SELECTION_TOOL (it was bailing out, when a new board was loaded and some items were still selected). Added removal of VIEW_ITEM groups after changing layers and removing items. --- common/tool/tool_manager.cpp | 40 +++++++++++++++------------------ common/view/view.cpp | 12 ++++++++++ common/view/view_item.cpp | 6 ----- include/tool/tool_base.h | 27 ++++++++++++++++++++++ include/tool/tool_interactive.h | 18 --------------- include/tool/tool_manager.h | 6 ++--- pcbnew/basepcbframe.cpp | 11 +++++++-- pcbnew/router/router_tool.cpp | 2 +- pcbnew/router/router_tool.h | 2 +- pcbnew/tools/selection_tool.cpp | 11 ++++++--- pcbnew/tools/selection_tool.h | 2 +- 11 files changed, 80 insertions(+), 57 deletions(-) diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 695203f447..ffc5a2d44b 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -140,22 +140,20 @@ void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool ) aTool->m_toolMgr = this; - if( aTool->GetType() == INTERACTIVE ) + if( !aTool->Init() ) { - if( !static_cast( aTool )->Init() ) - { - std::string msg = StrPrintf( "Initialization of the %s tool failed", aTool->GetName().c_str() ); + std::string msg = StrPrintf( "Initialization of the %s tool failed", + aTool->GetName().c_str() ); - DisplayError( NULL, wxString::FromUTF8( msg.c_str() ) ); + DisplayError( NULL, wxString::FromUTF8( msg.c_str() ) ); - // Unregister the tool - m_toolState.erase( aTool ); - m_toolNameIndex.erase( aTool->GetName() ); - m_toolIdIndex.erase( aTool->GetId() ); + // Unregister the tool + m_toolState.erase( aTool ); + m_toolNameIndex.erase( aTool->GetName() ); + m_toolIdIndex.erase( aTool->GetId() ); - delete st; - delete aTool; - } + delete st; + delete aTool; } } @@ -251,7 +249,7 @@ bool TOOL_MANAGER::runTool( TOOL_BASE* aTool ) state->idle = false; - static_cast( aTool )->Reset(); + aTool->Reset( TOOL_INTERACTIVE::RUN ); // Add the tool on the front of the processing queue (it gets events first) m_activeTools.push_front( aTool->GetId() ); @@ -282,6 +280,13 @@ TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const } +void TOOL_MANAGER::ResetTools( TOOL_BASE::RESET_REASON aReason ) +{ + BOOST_FOREACH( TOOL_BASE* tool, m_toolState | boost::adaptors::map_keys ) + tool->Reset( aReason ); +} + + void TOOL_MANAGER::ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler, const TOOL_EVENT_LIST& aConditions ) { @@ -513,15 +518,6 @@ void TOOL_MANAGER::SetEnvironment( EDA_ITEM* aModel, KIGFX::VIEW* aView, m_view = aView; m_viewControls = aViewControls; m_editFrame = aFrame; - - // Reset state of the registered tools - BOOST_FOREACH( TOOL_ID toolId, m_activeTools ) - { - TOOL_BASE* tool = m_toolIdIndex[toolId]->theTool; - - if( tool->GetType() == INTERACTIVE ) - static_cast( tool )->Reset(); - } } diff --git a/common/view/view.cpp b/common/view/view.cpp index a68fbc7f71..a607c6112b 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -122,6 +122,12 @@ void VIEW::Remove( VIEW_ITEM* aItem ) { VIEW_LAYER& l = m_layers[layers[i]]; l.items->Remove( aItem ); + MarkTargetDirty( l.target ); + + // Clear the GAL cache + int prevGroup = aItem->getGroup( layers[i] ); + if( prevGroup >= 0 ) + m_gal->DeleteGroup( prevGroup ); } } @@ -930,6 +936,12 @@ void VIEW::updateLayers( VIEW_ITEM* aItem ) VIEW_LAYER& l = m_layers[layers[i]]; l.items->Remove( aItem ); MarkTargetDirty( l.target ); + + // Redraw the item from scratch + int prevGroup = aItem->getGroup( layers[i] ); + + if( prevGroup >= 0 ) + m_gal->DeleteGroup( prevGroup ); } // Add the item to new layer set diff --git a/common/view/view_item.cpp b/common/view/view_item.cpp index e2ddd6a01d..305ab68579 100644 --- a/common/view/view_item.cpp +++ b/common/view/view_item.cpp @@ -34,17 +34,13 @@ void VIEW_ITEM::ViewSetVisible( bool aIsVisible ) bool update = false; if( m_visible != aIsVisible ) - { update = true; - } m_visible = aIsVisible; // update only if the visibility has really changed if( update ) - { ViewUpdate( APPEARANCE ); - } } @@ -60,9 +56,7 @@ void VIEW_ITEM::ViewUpdate( int aUpdateFlags ) void VIEW_ITEM::ViewRelease() { if( m_view && m_view->IsDynamic() ) - { m_view->Remove( this ); - } } diff --git a/include/tool/tool_base.h b/include/tool/tool_base.h index 7425ea8801..681e3099d9 100644 --- a/include/tool/tool_base.h +++ b/include/tool/tool_base.h @@ -70,6 +70,33 @@ public: virtual ~TOOL_BASE() {}; + ///> Determines the reason of reset for a tool + enum RESET_REASON + { + RUN, ///< Tool is invoked after being inactive + MODEL_RELOAD, ///< Model changes + GAL_SWITCH ///< Rendering engine changes + }; + + /** + * Function Init() + * Init() is called once upon a registration of the tool. + * + * @return True if the initialization went fine, false - otherwise. + */ + virtual bool Init() + { + return true; + } + + /** + * Function Reset() + * Brings the tool to a known, initial state. If the tool claimed anything from + * the model or the view, it must release it when its reset. + * @param aReason contains information about the reason of tool reset. + */ + virtual void Reset( RESET_REASON aReason ) = 0; + /** * Function GetType() * Returns the type of the tool. diff --git a/include/tool/tool_interactive.h b/include/tool/tool_interactive.h index 855f84af5c..7e816bd3a4 100644 --- a/include/tool/tool_interactive.h +++ b/include/tool/tool_interactive.h @@ -48,24 +48,6 @@ public: TOOL_INTERACTIVE( const std::string& aName ); virtual ~TOOL_INTERACTIVE(); - /** - * Function Reset() - * Brings the tool to a known, initial state. If the tool claimed anything from - * the model or the view, it must release it when its reset. - */ - virtual void Reset() = 0; - - /** - * Function Init() - * Init() is called once upon a registration of the tool. - * - * @return True if the initialization went fine, false - otherwise. - */ - virtual bool Init() - { - return true; - } - /** * Function SetContextMenu() * diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h index 57026c2712..6e9c18acb0 100644 --- a/include/tool/tool_manager.h +++ b/include/tool/tool_manager.h @@ -127,10 +127,10 @@ public: TOOL_BASE* FindTool( const std::string& aName ) const; /** - * Resets the state of a given tool by clearing its wait and - * transition lists and calling tool's internal Reset() method. + * Function ResetTools() + * Resets all tools (i.e. calls their Reset() method). */ - void ResetTool( TOOL_BASE* aTool ); + void ResetTools( TOOL_BASE::RESET_REASON aReason ); /** * Takes an event from the TOOL_DISPATCHER and propagates it to diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index aeda80468a..22983f9063 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -187,7 +187,10 @@ void PCB_BASE_FRAME::SetBoard( BOARD* aBoard ) // update the tool manager with the new board and its view. if( m_toolManager ) + { m_toolManager->SetEnvironment( m_Pcb, view, m_galCanvas->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD ); + } } } @@ -610,8 +613,12 @@ void PCB_BASE_FRAME::UseGalCanvas( bool aEnable ) ViewReloadBoard( m_Pcb ); - m_toolManager->SetEnvironment( m_Pcb, m_galCanvas->GetView(), - m_galCanvas->GetViewControls(), this ); + if( aEnable ) + { + m_toolManager->SetEnvironment( m_Pcb, m_galCanvas->GetView(), + m_galCanvas->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::GAL_SWITCH ); + } } diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index d85b1470ae..19b92a42cf 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -72,7 +72,7 @@ ROUTER_TOOL::~ROUTER_TOOL() } -void ROUTER_TOOL::Reset() +void ROUTER_TOOL::Reset( RESET_REASON aReason ) { if( m_router ) delete m_router; diff --git a/pcbnew/router/router_tool.h b/pcbnew/router/router_tool.h index da2a36601d..c43283a051 100644 --- a/pcbnew/router/router_tool.h +++ b/pcbnew/router/router_tool.h @@ -41,7 +41,7 @@ public: ROUTER_TOOL(); ~ROUTER_TOOL(); - void Reset(); + void Reset( RESET_REASON aReason ); int Main( TOOL_EVENT& aEvent ); private: diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index f24dbaffd9..bf78405612 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -64,9 +64,15 @@ SELECTION_TOOL::~SELECTION_TOOL() } -void SELECTION_TOOL::Reset() +void SELECTION_TOOL::Reset( RESET_REASON aReason ) { - ClearSelection(); + if( aReason == TOOL_BASE::MODEL_RELOAD ) + // Remove pointers to the selected items from containers + // without changing their properties (as they are already deleted) + m_selection.Clear(); + else + // Restore previous properties of selected items and remove them from containers + ClearSelection(); // Reinsert the VIEW_GROUP, in case it was removed from the VIEW getView()->Remove( m_selection.group ); @@ -157,7 +163,6 @@ void SELECTION_TOOL::ClearSelection() item->ViewSetVisible( true ); item->ClearSelected(); } - m_selection.Clear(); getEditFrame()->SetCurItem( NULL ); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index fa6ed0f545..33fc4b2494 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -85,7 +85,7 @@ public: }; /// @copydoc TOOL_INTERACTIVE::Reset() - void Reset(); + void Reset( RESET_REASON aReason ); /** * Function Main() From a3909d4f71852c82fe95cdd33b39d575886d5231 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 9 Dec 2013 11:01:05 +0100 Subject: [PATCH 16/84] Added removal of BOARD_ITEMs for the TOOL_FRAMEWORK. --- pcbnew/tools/common_actions.cpp | 4 + pcbnew/tools/common_actions.h | 3 + pcbnew/tools/edit_tool.cpp | 328 ++++++++++++++++++++++++++++++++ pcbnew/tools/edit_tool.h | 111 +++++++++++ pcbnew/tools/pcb_tools.cpp | 2 + 5 files changed, 448 insertions(+) create mode 100644 pcbnew/tools/edit_tool.cpp create mode 100644 pcbnew/tools/edit_tool.h diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 7a7aef37b1..1a80bd5a9c 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -42,6 +42,10 @@ TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ); +TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.delete", + AS_GLOBAL, 127, // 127 stands for DELETE key + "Remove", "Deletes selected item(s)" ); + TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties", AS_GLOBAL, 'E', "Properties...", "Displays properties window" ); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index ae12439870..19b0004182 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -49,4 +49,7 @@ public: /// Activation of the edit tool static TOOL_ACTION properties; + + /// Deleting a BOARD_ITEM + static TOOL_ACTION remove; }; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp new file mode 100644 index 0000000000..c6f46071d5 --- /dev/null +++ b/pcbnew/tools/edit_tool.cpp @@ -0,0 +1,328 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "common_actions.h" +#include "selection_tool.h" +#include "edit_tool.h" + +using namespace KIGFX; +using boost::optional; + +EDIT_TOOL::EDIT_TOOL() : + TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ) +{ +} + + +bool EDIT_TOOL::Init() +{ + // Find the selection tool, so they can cooperate + TOOL_BASE* selectionTool = m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ); + + m_selectionTool = static_cast( selectionTool ); + if( !selectionTool ) + { + DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) ); + return false; + } + + // Add context menu entries that are displayed when selection tool is active + m_selectionTool->AddMenuItem( COMMON_ACTIONS::editActivate ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::rotate ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::flip ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove ); + m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties ); + + setTransitions(); + + return true; +} + + +int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + + if( selection.Empty() ) + return 0; // there are no items to operate on + + VECTOR2D dragPosition; + m_dragging = false; + bool restore = false; // Should items' state be restored when finishing the tool? + + VIEW_CONTROLS* controls = getViewControls(); + controls->ShowCursor( true ); + controls->SetSnapping( true ); + controls->SetAutoPan( true ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + if( evt->IsCancel() ) + { + restore = true; // Cancelling the tool means that items have to be restored + break; // Finish + } + + // Dispatch TOOL_ACTIONs + else if( evt->Category() == TC_COMMAND ) + { + if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + Rotate( aEvent ); + else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + Flip( aEvent ); + } + + else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) + { + if( m_dragging ) + { + // Drag items to the current cursor position + VECTOR2D movement = ( evt->Position() - dragPosition ); + m_state.Move( movement ); + } + else + { + // Prepare to drag + std::set::iterator it; + + for( it = selection.items.begin(); it != selection.items.end(); ++it ) + { + // Save the state of the selected items, in case it has to be restored + m_state.Save( *it ); + } + + m_dragging = true; + } + + selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); + dragPosition = evt->Position(); + } + + else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) + break; // Finish + } + + m_dragging = false; + + if( restore ) + { + // Modifications has to be rollbacked, so restore the previous state of items + selection.group->ItemsViewUpdate( VIEW_ITEM::APPEARANCE ); + m_state.RestoreAll(); + } + else + { + // Changes are applied, so update the items + selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() ); + m_state.Apply(); + } + + controls->ShowCursor( false ); + controls->SetSnapping( false ); + controls->SetAutoPan( false ); + + setTransitions(); + + return 0; +} + + +int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + + // Properties are displayed when there is only one item selected + if( selection.items.size() == 1 ) + { + // Display properties dialog + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + BOARD_ITEM* item = *selection.items.begin(); + editFrame->OnEditItemRequest( NULL, item ); + + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + setTransitions(); + + return 0; +} + + +int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + + if( m_dragging ) + { + m_state.Rotate( cursorPos, 900.0 ); + selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); + } + else + { + std::set::iterator it; + + for( it = selection.items.begin(); it != selection.items.end(); ++it ) + { + (*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 ); + (*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } + + setTransitions(); + } + + return 0; +} + + +int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + + if( m_dragging ) + { + m_state.Flip( cursorPos ); + selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); + } + else + { + std::set::iterator it; + + for( it = selection.items.begin(); it != selection.items.end(); ++it ) + { + (*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); + (*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); + } + + setTransitions(); + } + + return 0; +} + + +int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) +{ + // Get a copy of the selected items set + std::set selectedItems = m_selectionTool->GetSelection().items; + + // As we are about to remove items, they have to be removed from the selection + m_selectionTool->ClearSelection(); + + std::set::iterator it; + for( it = selectedItems.begin(); it != selectedItems.end(); ++it ) + remove( *it ); + + BOARD* board = getModel( PCB_T ); + // Rebuild list of pads and nets if necessary + if( !( board->GetStatus() & NET_CODES_OK ) ) + board->BuildListOfNets(); + + setTransitions(); + + return 0; +} + + +void EDIT_TOOL::remove( BOARD_ITEM* aItem ) +{ + BOARD* board = getModel( PCB_T ); + + switch( aItem->Type() ) + { + case PCB_MODULE_T: + { + MODULE* module = static_cast( aItem ); + + for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + getView()->Remove( pad ); + + for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; + drawing = drawing->Next() ) + getView()->Remove( drawing ); + + getView()->Remove( &module->Reference() ); + getView()->Remove( &module->Value() ); + + // Module itself is deleted after the switch scope + // list of pads is rebuild by BOARD::BuildListOfNets() + +// module->ClearFlags(); // TODO is it necessary? clearing ratsnest/list of pads? + // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore + board->m_Status_Pcb = 0; + } + break; + + case PCB_ZONE_AREA_T: + getView()->Remove( aItem ); + getModel( PCB_T )->Delete( aItem ); + return; + + // These are not supposed to be removed + case PCB_PAD_T: + case PCB_MODULE_TEXT_T: + case PCB_MODULE_EDGE_T: + return; + + case PCB_LINE_T: // a segment not on copper layers + case PCB_TEXT_T: // a text on a layer + case PCB_TRACE_T: // a track segment (segment on a copper layer) + case PCB_VIA_T: // a via (like track segment on a copper layer) + case PCB_DIMENSION_T: // a dimension (graphic item) + case PCB_TARGET_T: // a target (graphic item) + case PCB_MARKER_T: // a marker used to show something + case PCB_ZONE_T: // SEG_ZONE items are now deprecated + break; + + // TODO + default: // other types do not need to (or should not) be handled + assert( false ); + return; + break; + } + + getView()->Remove( aItem ); + board->Delete( aItem ); +} + + +void EDIT_TOOL::setTransitions() +{ + Go( &EDIT_TOOL::Main, COMMON_ACTIONS::editActivate.MakeEvent() ); + Go( &EDIT_TOOL::Rotate, COMMON_ACTIONS::rotate.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/edit_tool.h b/pcbnew/tools/edit_tool.h new file mode 100644 index 0000000000..3f823eff7d --- /dev/null +++ b/pcbnew/tools/edit_tool.h @@ -0,0 +1,111 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * 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 __EDIT_TOOL_H +#define __EDIT_TOOL_H + +#include +#include +#include +#include "item_state.h" + +class BOARD_ITEM; +class SELECTION_TOOL; + +namespace KIGFX +{ +class VIEW_GROUP; +} + +/** + * Class EDIT_TOOL + * + * The interactive edit tool. Allows to move, rotate, flip and change properties of items selected + * using the pcbnew.InteractiveSelection tool. + */ + +class EDIT_TOOL : public TOOL_INTERACTIVE +{ +public: + EDIT_TOOL(); + + /// @copydoc TOOL_INTERACTIVE::Reset() + void Reset( RESET_REASON aReason ) {}; + + /// @copydoc TOOL_INTERACTIVE::Init() + bool Init(); + + /** + * Function Main() + * + * Main loop in which events are handled. + * @param aEvent is the handled event. + */ + int Main( TOOL_EVENT& aEvent ); + + /** + * Function Edit() + * + * Displays properties window for the selected object. + */ + int Properties( TOOL_EVENT& aEvent ); + + /** + * Function Rotate() + * + * Rotates currently selected items. + */ + int Rotate( TOOL_EVENT& aEvent ); + + /** + * Function Flip() + * + * Rotates currently selected items. The rotation point is the current cursor position. + */ + int Flip( TOOL_EVENT& aEvent ); + + /** + * Function Remove() + * + * Deletes currently selected items. The rotation point is the current cursor position. + */ + int Remove( TOOL_EVENT& aEvent ); + +private: + ///> Saves the state of items and allows to restore them + ITEM_STATE m_state; + + ///> Selection tool used for obtaining selected items + SELECTION_TOOL* m_selectionTool; + + ///> Flag determining if anything is being dragged right now + bool m_dragging; + + void remove( BOARD_ITEM* aItem ); + + ///> Sets up handlers for various events + void setTransitions(); +}; + +#endif diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index db347e8c4b..bef26764c5 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -50,6 +50,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->RegisterAction( &COMMON_ACTIONS::editActivate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::rotate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::flip ); + m_toolManager->RegisterAction( &COMMON_ACTIONS::remove ); m_toolManager->RegisterAction( &COMMON_ACTIONS::properties ); // Register tools @@ -59,6 +60,7 @@ void PCB_EDIT_FRAME::setupTools() m_toolManager->SetEnvironment( NULL, m_galCanvas->GetView(), m_galCanvas->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::RUN ); // Run the selection tool, it is supposed to be always active m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" ); From 7e60cc530af90502c61d3c38331b7544b834bc47 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 9 Dec 2013 11:07:30 +0100 Subject: [PATCH 17/84] Comments. --- pcbnew/tools/edit_tool.cpp | 7 +++---- pcbnew/tools/edit_tool.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index c6f46071d5..f790ca1679 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -238,15 +238,15 @@ int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) // Get a copy of the selected items set std::set selectedItems = m_selectionTool->GetSelection().items; - // As we are about to remove items, they have to be removed from the selection + // As we are about to remove items, they have to be removed from the selection first m_selectionTool->ClearSelection(); std::set::iterator it; for( it = selectedItems.begin(); it != selectedItems.end(); ++it ) remove( *it ); - BOARD* board = getModel( PCB_T ); // Rebuild list of pads and nets if necessary + BOARD* board = getModel( PCB_T ); if( !( board->GetStatus() & NET_CODES_OK ) ) board->BuildListOfNets(); @@ -276,10 +276,9 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) getView()->Remove( &module->Reference() ); getView()->Remove( &module->Value() ); - // Module itself is deleted after the switch scope + // Module itself is deleted after the switch scope is finished // list of pads is rebuild by BOARD::BuildListOfNets() -// module->ClearFlags(); // TODO is it necessary? clearing ratsnest/list of pads? // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore board->m_Status_Pcb = 0; } diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index 3f823eff7d..2e60a21fa3 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -102,6 +102,7 @@ private: ///> Flag determining if anything is being dragged right now bool m_dragging; + ///> Removes and frees a single BOARD_ITEM. void remove( BOARD_ITEM* aItem ); ///> Sets up handlers for various events From 4a0407fb69c46def2c85b3697e1070c44c19d3a2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 12:46:18 +0100 Subject: [PATCH 18/84] Removed some debug logs. --- common/gal/opengl/gpu_manager.cpp | 14 ++++++-------- common/view/view.cpp | 12 ++++++------ pcbnew/router/trace.h | 3 ++- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/common/gal/opengl/gpu_manager.cpp b/common/gal/opengl/gpu_manager.cpp index 8b556b32ce..25cd5fa418 100644 --- a/common/gal/opengl/gpu_manager.cpp +++ b/common/gal/opengl/gpu_manager.cpp @@ -34,11 +34,11 @@ #include #include #include -#ifdef __WXDEBUG__ +#ifdef PROFILE #include #include #include -#endif +#endif /* PROFILE */ using namespace KIGFX; @@ -187,10 +187,10 @@ void GPU_CACHED_MANAGER::EndDrawing() void GPU_CACHED_MANAGER::uploadToGpu() { -#ifdef __WXDEBUG__ +#ifdef PROFILE prof_counter totalTime; prof_start( &totalTime ); -#endif /* __WXDEBUG__ */ +#endif /* PROFILE */ if( !m_buffersInitialized ) Initialize(); @@ -207,15 +207,13 @@ void GPU_CACHED_MANAGER::uploadToGpu() m_indices.reset( new GLuint[bufferSize] ); if( glGetError() != GL_NO_ERROR ) - { DisplayError( NULL, wxT( "Error during data upload to the GPU memory" ) ); - } -#ifdef __WXDEBUG__ +#ifdef PROFILE prof_end( &totalTime ); wxLogDebug( wxT( "Uploading %d vertices to GPU / %.1f ms" ), bufferSize, totalTime.msecs() ); -#endif /* __WXDEBUG__ */ +#endif /* PROFILE */ } diff --git a/common/view/view.cpp b/common/view/view.cpp index a607c6112b..0ff8708ed0 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -34,9 +34,9 @@ #include #include -#ifdef __WXDEBUG__ +#ifdef PROFILE #include -#endif /* __WXDEBUG__ */ +#endif /* PROFILE */ using namespace KIGFX; @@ -981,10 +981,10 @@ void VIEW::RecacheAllItems( bool aImmediately ) r.SetMaximum(); -#ifdef __WXDEBUG__ +#ifdef PROFILE prof_counter totalRealTime; prof_start( &totalRealTime ); -#endif /* __WXDEBUG__ */ +#endif /* PROFILE */ for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i ) { @@ -1000,12 +1000,12 @@ void VIEW::RecacheAllItems( bool aImmediately ) } } -#ifdef __WXDEBUG__ +#ifdef PROFILE prof_end( &totalRealTime ); wxLogDebug( wxT( "RecacheAllItems::immediately: %u %.1f ms" ), aImmediately, totalRealTime.msecs() ); -#endif /* __WXDEBUG__ */ +#endif /* PROFILE */ } diff --git a/pcbnew/router/trace.h b/pcbnew/router/trace.h index b1acfd688f..1f8a3e32c9 100644 --- a/pcbnew/router/trace.h +++ b/pcbnew/router/trace.h @@ -21,7 +21,8 @@ #ifndef __TRACE_H #define __TRACE_H -#ifdef DEBUG +// #ifdef DEBUG +#if 0 #include #include From 32065b339a2764a336f80fdffd726fb30337ddce Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 13:27:18 +0100 Subject: [PATCH 19/84] Added const modifiers where applicable (PICKED_ITEMS_LIST). Added PICKED_ITEMS_LIST::FindItem(). --- common/class_undoredo_container.cpp | 26 +++++++++++++++++++------- cvpcb/class_DisplayFootprintsFrame.h | 2 +- eeschema/schematic_undo_redo.cpp | 2 +- gerbview/gerbview_frame.h | 2 +- include/class_undoredo_container.h | 23 +++++++++++++++-------- include/wxBasePcbFrame.h | 2 +- include/wxEeschemaStruct.h | 2 +- include/wxPcbStruct.h | 2 +- pcbnew/board_undo_redo.cpp | 2 +- pcbnew/footprint_wizard_frame.h | 2 +- pcbnew/modedit_undo_redo.cpp | 2 +- pcbnew/module_editor_frame.h | 2 +- pcbnew/modview_frame.h | 2 +- 13 files changed, 45 insertions(+), 26 deletions(-) diff --git a/common/class_undoredo_container.cpp b/common/class_undoredo_container.cpp index e56d765139..2dd862ef01 100644 --- a/common/class_undoredo_container.cpp +++ b/common/class_undoredo_container.cpp @@ -50,7 +50,7 @@ PICKED_ITEMS_LIST::~PICKED_ITEMS_LIST() } -void PICKED_ITEMS_LIST::PushItem( ITEM_PICKER& aItem ) +void PICKED_ITEMS_LIST::PushItem( const ITEM_PICKER& aItem ) { m_ItemsList.push_back( aItem ); } @@ -70,7 +70,7 @@ ITEM_PICKER PICKED_ITEMS_LIST::PopItem() } -bool PICKED_ITEMS_LIST::ContainsItem( EDA_ITEM* aItem ) const +bool PICKED_ITEMS_LIST::ContainsItem( const EDA_ITEM* aItem ) const { for( size_t i = 0; i < m_ItemsList.size(); i++ ) { @@ -82,6 +82,18 @@ bool PICKED_ITEMS_LIST::ContainsItem( EDA_ITEM* aItem ) const } +int PICKED_ITEMS_LIST::FindItem( const EDA_ITEM* aItem ) const +{ + for( size_t i = 0; i < m_ItemsList.size(); i++ ) + { + if( m_ItemsList[i].GetItem() == aItem ) + return i; + } + + return -1; +} + + void PICKED_ITEMS_LIST::ClearItemsList() { m_ItemsList.clear(); @@ -157,7 +169,7 @@ void PICKED_ITEMS_LIST::ClearListAndDeleteItems() } -ITEM_PICKER PICKED_ITEMS_LIST::GetItemWrapper( unsigned int aIdx ) +ITEM_PICKER PICKED_ITEMS_LIST::GetItemWrapper( unsigned int aIdx ) const { ITEM_PICKER picker; @@ -168,7 +180,7 @@ ITEM_PICKER PICKED_ITEMS_LIST::GetItemWrapper( unsigned int aIdx ) } -EDA_ITEM* PICKED_ITEMS_LIST::GetPickedItem( unsigned int aIdx ) +EDA_ITEM* PICKED_ITEMS_LIST::GetPickedItem( unsigned int aIdx ) const { if( aIdx < m_ItemsList.size() ) return m_ItemsList[aIdx].GetItem(); @@ -177,7 +189,7 @@ EDA_ITEM* PICKED_ITEMS_LIST::GetPickedItem( unsigned int aIdx ) } -EDA_ITEM* PICKED_ITEMS_LIST::GetPickedItemLink( unsigned int aIdx ) +EDA_ITEM* PICKED_ITEMS_LIST::GetPickedItemLink( unsigned int aIdx ) const { if( aIdx < m_ItemsList.size() ) return m_ItemsList[aIdx].GetLink(); @@ -186,7 +198,7 @@ EDA_ITEM* PICKED_ITEMS_LIST::GetPickedItemLink( unsigned int aIdx ) } -UNDO_REDO_T PICKED_ITEMS_LIST::GetPickedItemStatus( unsigned int aIdx ) +UNDO_REDO_T PICKED_ITEMS_LIST::GetPickedItemStatus( unsigned int aIdx ) const { if( aIdx < m_ItemsList.size() ) return m_ItemsList[aIdx].GetStatus(); @@ -195,7 +207,7 @@ UNDO_REDO_T PICKED_ITEMS_LIST::GetPickedItemStatus( unsigned int aIdx ) } -STATUS_FLAGS PICKED_ITEMS_LIST::GetPickerFlags( unsigned aIdx ) +STATUS_FLAGS PICKED_ITEMS_LIST::GetPickerFlags( unsigned aIdx ) const { if( aIdx < m_ItemsList.size() ) return m_ItemsList[aIdx].GetFlags(); diff --git a/cvpcb/class_DisplayFootprintsFrame.h b/cvpcb/class_DisplayFootprintsFrame.h index 52b1366813..3244d62325 100644 --- a/cvpcb/class_DisplayFootprintsFrame.h +++ b/cvpcb/class_DisplayFootprintsFrame.h @@ -124,7 +124,7 @@ public: * @param aTransformPoint = the reference point of the transformation, * for commands like move */ - virtual void SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, + virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ) { diff --git a/eeschema/schematic_undo_redo.cpp b/eeschema/schematic_undo_redo.cpp index 4481e8cce0..1ab8948d78 100644 --- a/eeschema/schematic_undo_redo.cpp +++ b/eeschema/schematic_undo_redo.cpp @@ -160,7 +160,7 @@ void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM* aItem, } -void SCH_EDIT_FRAME::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, +void SCH_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint ) { diff --git a/gerbview/gerbview_frame.h b/gerbview/gerbview_frame.h index 6a69191706..9cabd38b16 100644 --- a/gerbview/gerbview_frame.h +++ b/gerbview/gerbview_frame.h @@ -676,7 +676,7 @@ public: * @param aTransformPoint = the reference point of the transformation, * for commands like move */ - void SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, + void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ) { diff --git a/include/class_undoredo_container.h b/include/class_undoredo_container.h index 6c95bae24d..13c9e85b23 100644 --- a/include/class_undoredo_container.h +++ b/include/class_undoredo_container.h @@ -111,7 +111,7 @@ public: void SetStatus( UNDO_REDO_T aStatus ) { m_undoRedoStatus = aStatus; } - UNDO_REDO_T GetStatus() { return m_undoRedoStatus; } + UNDO_REDO_T GetStatus() const { return m_undoRedoStatus; } void SetFlags( STATUS_FLAGS aFlags ) { m_pickerFlags = aFlags; } @@ -148,7 +148,7 @@ public: * pushes \a aItem to the top of the list * @param aItem Picker to push on to the list. */ - void PushItem( ITEM_PICKER& aItem ); + void PushItem( const ITEM_PICKER& aItem ); /** * Function PopItem @@ -160,7 +160,14 @@ public: * Function IsItemInList * @return True if \a aItem is found in the pick list. */ - bool ContainsItem( EDA_ITEM* aItem ) const; + bool ContainsItem( const EDA_ITEM* aItem ) const; + + /** + * Function FindItem + * @return Index of the searched item. If the item is not stored in the list, negative value + * is returned. + */ + int FindItem( const EDA_ITEM* aItem ) const; /** * Function ClearItemsList @@ -201,21 +208,21 @@ public: * if this picker does not exist, a picker is returned, * with its members set to 0 or NULL */ - ITEM_PICKER GetItemWrapper( unsigned int aIdx ); + ITEM_PICKER GetItemWrapper( unsigned int aIdx ) const; /** * Function GetPickedItem * @return A pointer to the picked item * @param aIdx Index of the picked item in the picked list */ - EDA_ITEM* GetPickedItem( unsigned int aIdx ); + EDA_ITEM* GetPickedItem( unsigned int aIdx ) const; /** * Function GetPickedItemLink * @return link of the picked item, or null if does not exist * @param aIdx Index of the picked item in the picked list */ - EDA_ITEM* GetPickedItemLink( unsigned int aIdx ); + EDA_ITEM* GetPickedItemLink( unsigned int aIdx ) const; /** * Function GetPickedItemStatus @@ -223,7 +230,7 @@ public: * or UR_UNSPECIFIED if does not exist * @param aIdx Index of the picked item in the picked list */ - UNDO_REDO_T GetPickedItemStatus( unsigned int aIdx ); + UNDO_REDO_T GetPickedItemStatus( unsigned int aIdx ) const; /** * Function GetPickerFlags @@ -231,7 +238,7 @@ public: * @param aIdx Index of the picker in the picked list * @return The value stored in the picker, if the picker exists, or 0 if does not exist */ - STATUS_FLAGS GetPickerFlags( unsigned aIdx ); + STATUS_FLAGS GetPickerFlags( unsigned aIdx ) const; /** * Function SetPickedItem diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h index ff0db2f2c2..cbc96f31df 100644 --- a/include/wxBasePcbFrame.h +++ b/include/wxBasePcbFrame.h @@ -669,7 +669,7 @@ public: * @param aTransformPoint = the reference point of the transformation, * for commands like move */ - virtual void SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, + virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ) = 0; diff --git a/include/wxEeschemaStruct.h b/include/wxEeschemaStruct.h index b3f60bac0f..30a5b3827a 100644 --- a/include/wxEeschemaStruct.h +++ b/include/wxEeschemaStruct.h @@ -1080,7 +1080,7 @@ public: * @param aTransformPoint = the reference point of the transformation, * for commands like move */ - void SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, + void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index fc7d379a07..33ab87d567 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -659,7 +659,7 @@ public: * @param aTransformPoint = the reference point of the transformation, for * commands like move */ - virtual void SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, + virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index e58e734320..36a073d065 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -346,7 +346,7 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem, } -void PCB_EDIT_FRAME::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, +void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint ) { diff --git a/pcbnew/footprint_wizard_frame.h b/pcbnew/footprint_wizard_frame.h index f65ee1d62d..9027e29e73 100644 --- a/pcbnew/footprint_wizard_frame.h +++ b/pcbnew/footprint_wizard_frame.h @@ -198,7 +198,7 @@ private: */ void OnLeftDClick( wxDC*, const wxPoint& ) {} void SaveCopyInUndoList( BOARD_ITEM*, UNDO_REDO_T, const wxPoint& ) {} - void SaveCopyInUndoList( PICKED_ITEMS_LIST&, UNDO_REDO_T, const wxPoint& ) {} + void SaveCopyInUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO_T, const wxPoint& ) {} DECLARE_EVENT_TABLE() diff --git a/pcbnew/modedit_undo_redo.cpp b/pcbnew/modedit_undo_redo.cpp index 4f273eb3c7..613f4d8d2b 100644 --- a/pcbnew/modedit_undo_redo.cpp +++ b/pcbnew/modedit_undo_redo.cpp @@ -46,7 +46,7 @@ void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem, } -void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, +void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint ) { diff --git a/pcbnew/module_editor_frame.h b/pcbnew/module_editor_frame.h index 01e9a304ca..49682348e5 100644 --- a/pcbnew/module_editor_frame.h +++ b/pcbnew/module_editor_frame.h @@ -245,7 +245,7 @@ public: * @param aTransformPoint = the reference point of the transformation, for * commands like move */ - virtual void SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList, + virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); diff --git a/pcbnew/modview_frame.h b/pcbnew/modview_frame.h index c833e5c10c..0e099e4fea 100644 --- a/pcbnew/modview_frame.h +++ b/pcbnew/modview_frame.h @@ -202,7 +202,7 @@ private: */ void OnLeftDClick( wxDC*, const wxPoint& ) {} void SaveCopyInUndoList( BOARD_ITEM*, UNDO_REDO_T, const wxPoint& ) {} - void SaveCopyInUndoList( PICKED_ITEMS_LIST&, UNDO_REDO_T, const wxPoint &) {} + void SaveCopyInUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO_T, const wxPoint &) {} DECLARE_EVENT_TABLE() From e4efe212d6f9f017107a97a0d536e0612f2bedc6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 13:39:11 +0100 Subject: [PATCH 20/84] Added MODULE::RunOnChildren(). --- pcbnew/basepcbframe.cpp | 29 +++-------------------------- pcbnew/class_module.cpp | 13 +++++++++++++ pcbnew/class_module.h | 9 +++++++++ 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index 22983f9063..95b356d915 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -200,46 +200,25 @@ void PCB_BASE_FRAME::ViewReloadBoard( const BOARD* aBoard ) const KIGFX::VIEW* view = m_galCanvas->GetView(); view->Clear(); - // All of PCB drawing elements should be added to the VIEW - // in order to be displayed + // All the PCB drawable items should be added to the VIEW in order to be displayed // Load zones for( int i = 0; i < aBoard->GetAreaCount(); ++i ) - { view->Add( (KIGFX::VIEW_ITEM*) ( aBoard->GetArea( i ) ) ); - } // Load drawings for( BOARD_ITEM* drawing = aBoard->m_Drawings; drawing; drawing = drawing->Next() ) - { view->Add( drawing ); - } // Load tracks for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) - { view->Add( track ); - } // Load modules and its additional elements for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { - // Load module's pads - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - { - view->Add( pad ); - } - - // Load module's drawing (mostly silkscreen) - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - { - view->Add( drawing ); - } - - // Load module's texts (name and value) - view->Add( &module->Reference() ); - view->Add( &module->Value() ); + // Load items that belong to a module + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), view ) ); // Add the module itself view->Add( module ); @@ -247,9 +226,7 @@ void PCB_BASE_FRAME::ViewReloadBoard( const BOARD* aBoard ) const // Segzones (equivalent of ZONE_CONTAINER for legacy boards) for( SEGZONE* zone = aBoard->m_Zone; zone; zone = zone->Next() ) - { view->Add( zone ); - } // Add an entry for the worksheet layout KIGFX::WORKSHEET_VIEWITEM* worksheet = new KIGFX::WORKSHEET_VIEWITEM( diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 9694607a39..1885eb16c9 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -728,6 +728,19 @@ EDA_ITEM* MODULE::Clone() const } +void MODULE::RunOnChildren( boost::function aFunction ) +{ + for( D_PAD* pad = m_Pads.GetFirst(); pad; pad = pad->Next() ) + aFunction( static_cast( pad ) ); + + for( BOARD_ITEM* drawing = m_Drawings.GetFirst(); drawing; drawing = drawing->Next() ) + aFunction( drawing ); + + aFunction( static_cast( m_Reference ) ); + aFunction( static_cast( m_Value ) ); +} + + void MODULE::ViewUpdate( int aUpdateFlags ) { if( !m_view ) diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index a1564db05e..dbea0179d9 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -41,6 +41,7 @@ #include #include "zones.h" +#include class LINE_READER; class EDA_3D_CANVAS; @@ -447,6 +448,14 @@ public: EDA_ITEM* Clone() const; + /** + * Function RunOnChildren + * + * Invokes a function on all BOARD_ITEMs that belong to the module (pads, drawings, texts). + * @param aFunction is the function to be invoked. + */ + void RunOnChildren( boost::function aFunction ); + /// @copydoc VIEW_ITEM::ViewUpdate() void ViewUpdate( int aUpdateFlags ); From 873235304e4781c190861d128c771e2da8e582b3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 14:33:34 +0100 Subject: [PATCH 21/84] SELECTION_TOOL uses ITEMS_PICKED_LIST to store selected items. Modifications done using the EDIT_TOOL are saved using the default KiCad's undo buffer. If there is only one item selected, info about the item is displayed in the bottom status bar. --- pcbnew/board_undo_redo.cpp | 58 +++++++ pcbnew/tools/edit_tool.cpp | 144 ++++++++++------ pcbnew/tools/edit_tool.h | 14 +- pcbnew/tools/item_state.h | 284 -------------------------------- pcbnew/tools/selection_tool.cpp | 132 ++++++--------- pcbnew/tools/selection_tool.h | 38 +++-- 6 files changed, 231 insertions(+), 439 deletions(-) delete mode 100644 pcbnew/tools/item_state.h diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 36a073d065..fb8578fa4f 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -40,6 +41,8 @@ #include #include +#include +#include /* Functions to undo and redo edit commands. * commands to undo are stored in CurrentScreen->m_UndoList @@ -424,6 +427,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed BOARD_ITEM* item; bool not_found = false; bool reBuild_ratsnest = false; + KIGFX::VIEW* view = m_galCanvas->GetView(); // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command @@ -484,35 +488,80 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed case UR_CHANGED: /* Exchange old and new data for each item */ { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); + + // Remove all pads/drawings/texts, as they become invalid + // for the VIEW after SwapData() called for modules + if( item->Type() == PCB_MODULE_T ) + { + MODULE* oldModule = static_cast( item ); + oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), + view ) ); + } + item->SwapData( image ); + + // Update all pads/drawings/texts, as they become invalid + // for the VIEW after SwapData() called for modules + if( item->Type() == PCB_MODULE_T ) + { + MODULE* newModule = static_cast( item ); + newModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), + view ) ); + } + + item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetBoard()->Remove( item ); + + if( item->Type() == PCB_MODULE_T ) + { + MODULE* module = static_cast( item ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), + view ) ); + } + view->Remove( item ); + + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetBoard()->Add( item ); + + if( item->Type() == PCB_MODULE_T ) + { + MODULE* module = static_cast( item ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), + view ) ); + } + view->Add( item ); + + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); build_item_list = true; break; case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? 900 : -900 ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); + item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); break; default: @@ -540,6 +589,11 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event ) if( GetScreen()->GetUndoCommandCount() <= 0 ) return; + // Clear the selection, as it may be altered with undone items + SELECTION_TOOL* selectionTool = static_cast( m_toolManager->FindTool( + "pcbnew.InteractiveSelection" ) ); + selectionTool->ClearSelection(); + /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); /* Undo the command */ @@ -559,6 +613,10 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event ) if( GetScreen()->GetRedoCommandCount() == 0 ) return; + // Clear the selection, as it may be altered with redone items + SELECTION_TOOL* selectionTool = static_cast( m_toolManager->FindTool( + "pcbnew.InteractiveSelection" ) ); + selectionTool->ClearSelection(); /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index f790ca1679..e8accb4ca7 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -72,11 +72,15 @@ bool EDIT_TOOL::Init() int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + + // By default, modified items need to update their geometry + m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; if( selection.Empty() ) return 0; // there are no items to operate on - VECTOR2D dragPosition; + VECTOR2D dragPosition; // The last position of the cursor while dragging m_dragging = false; bool restore = false; // Should items' state be restored when finishing the tool? @@ -98,9 +102,16 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) else if( evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + { Rotate( aEvent ); + } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + { Flip( aEvent ); + + // Flip causes change of layers + enableUpdateFlag( KIGFX::VIEW_ITEM::LAYERS ); + } } else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) @@ -109,19 +120,24 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { // Drag items to the current cursor position VECTOR2D movement = ( evt->Position() - dragPosition ); - m_state.Move( movement ); + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + item->Move( wxPoint( movement.x, movement.y ) ); + } } else { - // Prepare to drag - std::set::iterator it; - - for( it = selection.items.begin(); it != selection.items.end(); ++it ) + // Prepare to drag - save items, so changes can be undone + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { - // Save the state of the selected items, in case it has to be restored - m_state.Save( *it ); + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + std::cout << "saved " << (unsigned long) item << std::endl; } + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + m_dragging = true; } @@ -138,14 +154,13 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) if( restore ) { // Modifications has to be rollbacked, so restore the previous state of items - selection.group->ItemsViewUpdate( VIEW_ITEM::APPEARANCE ); - m_state.RestoreAll(); + wxCommandEvent dummy; + editFrame->GetBoardFromUndoList( dummy ); } else { // Changes are applied, so update the items - selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() ); - m_state.Apply(); + selection.group->ItemsViewUpdate( m_updateFlag ); } controls->ShowCursor( false ); @@ -161,13 +176,20 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // Properties are displayed when there is only one item selected - if( selection.items.size() == 1 ) + if( selection.Size() == 1 ) { // Display properties dialog - PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); - BOARD_ITEM* item = *selection.items.begin(); + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( 0 ) ); + + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag + { + editFrame->SaveCopyInUndoList( item, UR_CHANGED ); + editFrame->OnModify(); + } + editFrame->OnEditItemRequest( NULL, item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); @@ -182,25 +204,28 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + VECTOR2D cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag + { + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, wxPoint( cursor.x, cursor.y ) ); + } + + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + + item->Rotate( wxPoint( cursor.x, cursor.y ), 900.0 ); + if( !m_dragging ) + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } if( m_dragging ) - { - m_state.Rotate( cursorPos, 900.0 ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else - { - std::set::iterator it; + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - (*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 ); - (*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - - setTransitions(); - } + setTransitions(); return 0; } @@ -209,25 +234,28 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + VECTOR2D cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag + { + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, wxPoint( cursor.x, cursor.y ) ); + } + + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + + item->Flip( wxPoint( cursor.x, cursor.y ) ); + if( !m_dragging ) + item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); + } if( m_dragging ) - { - m_state.Flip( cursorPos ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else - { - std::set::iterator it; + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - (*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); - (*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); - } - - setTransitions(); - } + setTransitions(); return 0; } @@ -236,14 +264,24 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) { // Get a copy of the selected items set - std::set selectedItems = m_selectionTool->GetSelection().items; + PICKED_ITEMS_LIST selectedItems = m_selectionTool->GetSelection().items; + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // As we are about to remove items, they have to be removed from the selection first m_selectionTool->ClearSelection(); - std::set::iterator it; - for( it = selectedItems.begin(); it != selectedItems.end(); ++it ) - remove( *it ); + // Save them + for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) + selectedItems.SetPickedItemStatus( UR_DELETED, i ); + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selectedItems, UR_DELETED ); + + // And now remove + for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selectedItems.GetPickedItem( i ) ); + remove( item ); + } // Rebuild list of pads and nets if necessary BOARD* board = getModel( PCB_T ); @@ -265,6 +303,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) case PCB_MODULE_T: { MODULE* module = static_cast( aItem ); + module->ClearFlags(); for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) getView()->Remove( pad ); @@ -305,7 +344,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) case PCB_ZONE_T: // SEG_ZONE items are now deprecated break; - // TODO default: // other types do not need to (or should not) be handled assert( false ); return; @@ -313,7 +351,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) } getView()->Remove( aItem ); - board->Delete( aItem ); + board->Remove( aItem ); } diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index 2e60a21fa3..5ddcb84f5d 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -28,7 +28,6 @@ #include #include #include -#include "item_state.h" class BOARD_ITEM; class SELECTION_TOOL; @@ -93,9 +92,6 @@ public: int Remove( TOOL_EVENT& aEvent ); private: - ///> Saves the state of items and allows to restore them - ITEM_STATE m_state; - ///> Selection tool used for obtaining selected items SELECTION_TOOL* m_selectionTool; @@ -107,6 +103,16 @@ private: ///> Sets up handlers for various events void setTransitions(); + + ///> The required update flag for modified items + KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS m_updateFlag; + + ///> Enables higher order update flag + void enableUpdateFlag( KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS aFlag ) + { + if( m_updateFlag < aFlag ) + m_updateFlag = aFlag; + } }; #endif diff --git a/pcbnew/tools/item_state.h b/pcbnew/tools/item_state.h deleted file mode 100644 index ed562c623d..0000000000 --- a/pcbnew/tools/item_state.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * 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 ITEM_STATE_H_ -#define ITEM_STATE_H_ - -#include -#include - -/** - * Class ITEM_STATE - * - * Provides means for modifying properties of groups of items and gives possibility of rolling back - * the introduced changes. Does not take ownership of modified items, neither takes care of - * refreshing. - */ -class ITEM_STATE -{ -public: - ITEM_STATE() : - m_movement( 0.0, 0.0 ), m_flips( 0 ), m_rotation( 0.0 ) - { -#ifdef __WXDEBUG__ - m_canSave = true; -#endif - } - - /** - * Function Save() - * - * Adds an item and saves it's state. - * @param aItem is the item to be added. - */ - void Save( BOARD_ITEM* aItem ) - { -#ifdef __WXDEBUG__ - wxASSERT_MSG( m_canSave, wxT( "You cannot save items after issuing commands. You have " - "either RestoreAll() or Apply() before adding items!" ) ); -#endif - m_items.push_back( aItem ); - } - - /** - * Function RestoreAll() - * - * Rollbacks all the changes to the initial state. - */ - void RestoreAll() - { - // Check if there is a not saved movement command - saveMovement(); - - std::deque::iterator it, it_end; - std::deque::iterator cmd, cmd_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - { - for( cmd = m_commands.begin(), cmd_end = m_commands.end(); cmd != cmd_end; ++cmd ) - cmd->Revert( *it ); - } - - reset(); - } - - /** - * Function Apply() - * - * Resets the state, clears the list of items & changes, so the object can be reused for - * other items. - */ - void Apply() - { - reset(); - } - - /** - * Function Move() - * - * Moves stored items by a given vector. - * @param aMovement is the movement vector. - */ - void Move( const VECTOR2D& aMovement ) - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->Move( wxPoint( aMovement.x, aMovement.y ) ); - - m_movement += aMovement; - } - - /** - * Function Rotate() - * - * Rotates stored items by a given angle. - * @param aAngle is the angle (in decidegrees). - */ - void Rotate( const VECTOR2D& aPoint, double aAngle ) - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - saveMovement(); - m_commands.push_front( COMMAND( COMMAND::ROTATE, aPoint, aAngle ) ); - - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->Rotate( wxPoint( aPoint.x, aPoint.y ), aAngle ); - - m_rotation += aAngle; - } - - /** - * Function Flip() - * - * Changes the board side for stored items. - * @param aPoint is the rotation point. - */ - void Flip( const VECTOR2D& aPoint ) - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - saveMovement(); - m_commands.push_front( COMMAND( COMMAND::FLIP, aPoint ) ); - - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->Flip( wxPoint( aPoint.x, aPoint.y ) ); - - m_flips++; - } - - /** - * Function ToggleVisibility() - * - * Switches the visibility property of stored items. - */ - void ToggleVisibility() - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - m_commands.push_front( COMMAND( COMMAND::VISIBILITY ) ); - - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->ViewSetVisible( !(*it)->ViewIsVisible() ); - } - - /** - * Function GetUpdateFlag() - * - * Returns information on what kind of update should be applied to items in order to display - * them properly. - * @return Flag required to refresh items. - */ - KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS GetUpdateFlag() const - { - if( m_flips % 2 == 1 ) // If number of flips is odd, then we need to change layers - return KIGFX::VIEW_ITEM::LAYERS; - else if( m_movement.x != 0.0 || m_movement.y != 0.0 || m_rotation != 0.0 ) - return KIGFX::VIEW_ITEM::GEOMETRY; - - return KIGFX::VIEW_ITEM::APPEARANCE; - } - -private: - /// COMMAND stores modifications that were done to items - struct COMMAND - { - /// Type of command - enum TYPE { MOVE, ROTATE, FLIP, VISIBILITY }; - TYPE m_type; - - /// Point where flip/rotation occurred or movement vector - VECTOR2D m_point; - - /// Used only for rotation - double m_angle; - - COMMAND( TYPE aType, VECTOR2D aPoint = VECTOR2D( 0.0, 0.0 ), double aAngle = 0.0 ) : - m_type( aType ), m_point( aPoint ), m_angle( aAngle ) {}; - - void Revert( BOARD_ITEM* aItem ) - { - switch( m_type ) - { - case MOVE: - aItem->Move( wxPoint( -m_point.x, -m_point.y ) ); - break; - - case ROTATE: - aItem->Rotate( wxPoint( m_point.x, m_point.y ), -m_angle ); - break; - - case FLIP: - aItem->Flip( wxPoint( m_point.x, m_point.y ) ); - break; - - case VISIBILITY: - aItem->ViewSetVisible( !aItem->ViewIsVisible() ); - break; - } - } - }; - - /// Adds a MOVEMENT command basing on the current movement vector - void saveMovement() - { - if( m_movement.x != 0.0 || m_movement.y != 0.0 ) - { - m_commands.push_front( COMMAND( COMMAND::MOVE, m_movement ) ); - - m_movement.x = 0.0; - m_movement.y = 0.0; - } - } - - /// Restores the initial state - void reset() - { - m_movement.x = 0.0; - m_movement.y = 0.0; - m_flips = 0; - m_rotation = 0.0; - - m_items.clear(); - m_commands.clear(); - -#ifdef __WXDEBUG__ - m_canSave = true; -#endif - } - - /// List of issued commands - std::deque m_items; - - /// List of items that are affected by commands - std::deque m_commands; - - /// Current movement vector (updated by Move() command) - VECTOR2D m_movement; - - /// Number of flips applied to items - unsigned int m_flips; - - /// Total rotation applied to items - double m_rotation; - -#ifdef __WXDEBUG__ - /// Debug flag assuring that functions are called in proper order - bool m_canSave; -#endif -}; - -#endif /* ITEM_STATE_H_ */ diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index bf78405612..dabf03dda8 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -182,9 +182,9 @@ void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) { - if( isSelected( aItem ) ) + if( aItem->IsSelected() ) { - deselectItem( aItem ); + deselect( aItem ); } else { @@ -193,17 +193,11 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) // Prevent selection of invisible or inactive items if( selectable( aItem ) ) - selectItem( aItem ); + select( aItem ); } } -bool SELECTION_TOOL::isSelected( const BOARD_ITEM* aItem ) const -{ - return ( m_selection.items.find( const_cast( aItem ) ) != m_selection.items.end() ); -} - - void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) { BOARD* pcb = getModel( PCB_T ); @@ -219,7 +213,6 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) case 0: if( !m_additive ) ClearSelection(); - break; case 1: @@ -231,7 +224,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) // contain anything but module footprint and not selectable items for( int i = collector.GetCount() - 1; i >= 0 ; --i ) { - BOARD_ITEM* boardItem = ( collector )[i]; + BOARD_ITEM* boardItem = collector[i]; if( boardItem->Type() == PCB_MODULE_T || !selectable( boardItem ) ) collector.Remove( i ); @@ -338,8 +331,8 @@ bool SELECTION_TOOL::selectMultiple() BOARD_ITEM* item = static_cast( it->first ); // Add only those items that are visible and fully within the selection box - if( selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) - selectItem( item ); + if( !item->IsSelected() && selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) + select( item ); } // Do not display information about selected item,as there is more than one @@ -502,49 +495,23 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const } -void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) +void SELECTION_TOOL::select( BOARD_ITEM* aItem ) { - /// Selecting an item needs a few operations, so they are wrapped in a functor - class selectBase_ - { - SELECTION& s; - - public: - selectBase_( SELECTION& s_ ) : s( s_ ) {} - - void operator()( BOARD_ITEM* item ) - { - s.group->Add( item ); - // Hide the original item, so it is shown only on overlay - item->ViewSetVisible( false ); - item->SetSelected(); - } - } selectBase( m_selection ); - - // Modules are treated in a special way - when they are selected, we have to - // select all the parts that make the module, not the module itself + // Modules are treated in a special way - when they are selected, we have to mark + // all the parts that make the module as selected if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); + module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::selectVisually ), this ) ); - // Add everything that belongs to the module (besides the module itself) - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - selectBase( pad ); - - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - selectBase( drawing ); - - selectBase( &module->Reference() ); - selectBase( &module->Value() ); } - // Add items to the VIEW_GROUP, so they will be displayed on the overlay - selectBase( aItem ); - m_selection.items.insert( aItem ); + selectVisually( aItem ); + ITEM_PICKER picker( aItem ); + m_selection.items.PushItem( picker ); // It is enough to do it only for the first selected item - if( m_selection.items.size() == 1 ) + if( m_selection.Size() == 1 ) { // Set as the current item, so the information about selection is displayed getEditFrame()->SetCurItem( aItem, true ); @@ -552,48 +519,30 @@ void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) // Now the context menu should be enabled SetContextMenu( &m_menu, CMENU_BUTTON ); } + else + { + // If multiple items are selected, do not show the information about the selected item + getEditFrame()->SetCurItem( NULL, true ); + } } -void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) +void SELECTION_TOOL::deselect( BOARD_ITEM* aItem ) { - /// Deselecting an item needs a few operations, so they are wrapped in a functor - class deselectBase_ - { - SELECTION& s; - - public: - deselectBase_( SELECTION& s_ ) : s( s_ ) {} - - void operator()( BOARD_ITEM* item ) - { - s.group->Remove( item ); - // Restore original item visibility - item->ViewSetVisible( true ); - item->ClearSelected(); - } - } deselectBase( m_selection ); - // Modules are treated in a special way - when they are selected, we have to - // select all the parts that make the module, not the module itself + // deselect all the parts that make the module, not the module itself if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); + module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::deselectVisually ), this ) ); - // Add everything that belongs to the module (besides the module itself) - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - deselectBase( pad ); - - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - deselectBase( drawing ); - - deselectBase( &module->Reference() ); - deselectBase( &module->Value() ); } - deselectBase( aItem ); - m_selection.items.erase( aItem ); + deselectVisually( aItem ); + + int itemIdx = m_selection.items.FindItem( aItem ); + if( itemIdx >= 0 ) + m_selection.items.RemovePicker( itemIdx ); // If there is nothing selected, disable the context menu if( m_selection.Empty() ) @@ -604,6 +553,26 @@ void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) } +void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem ) const +{ + m_selection.group->Add( aItem ); + + // Hide the original item, so it is shown only on overlay + aItem->ViewSetVisible( false ); + aItem->SetSelected(); +} + + +void SELECTION_TOOL::deselectVisually( BOARD_ITEM* aItem ) const +{ + m_selection.group->Remove( aItem ); + + // Restore original item visibility + aItem->ViewSetVisible( true ); + aItem->ClearSelected(); +} + + bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const { const unsigned GRIP_MARGIN = 500000; @@ -611,9 +580,10 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const // Check if the point is located within any of the currently selected items bounding boxes std::set::iterator it, it_end; - for( it = m_selection.items.begin(), it_end = m_selection.items.end(); it != it_end; ++it ) + for( unsigned int i = 0; i < m_selection.items.GetCount(); ++i ) { - BOX2I itemBox = (*it)->ViewBBox(); + BOARD_ITEM* item = static_cast( m_selection.items.GetPickedItem( i ) ); + BOX2I itemBox = item->ViewBBox(); itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item if( itemBox.Contains( aPoint ) ) @@ -626,6 +596,6 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const void SELECTION_TOOL::SELECTION::Clear() { - items.clear(); + items.ClearItemsList(); group->Clear(); } diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 33fc4b2494..168f2288da 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -26,11 +26,10 @@ #ifndef __SELECTION_TOOL_H #define __SELECTION_TOOL_H -#include - #include #include #include +#include class SELECTION_AREA; class BOARD_ITEM; @@ -62,7 +61,7 @@ public: struct SELECTION { /// Set of selected items - std::set items; + PICKED_ITEMS_LIST items; /// VIEW_GROUP that holds currently selected items KIGFX::VIEW_GROUP* group; @@ -70,13 +69,13 @@ public: /// Checks if there is anything selected bool Empty() const { - return items.empty(); + return ( items.GetCount() == 0 ); } /// Returns the number of selected parts int Size() const { - return items.size(); + return items.GetCount(); } /// Clears both the VIEW_GROUP and set of selected items. Please note that it does not @@ -111,7 +110,7 @@ public: void ClearSelection(); /** - * Function AddAction() + * Function AddMenuItem() * * Adds a menu entry to run a TOOL_ACTION on selected items. * @param aAction is a menu entry to be added. @@ -161,15 +160,6 @@ private: */ void toggleSelection( BOARD_ITEM* aItem ); - /** - * Function isSelected() - * Tests if an item is currently selected. - * - * @param aItem is the item to be checked. - * @return True if the item is selected, false otherwise. - */ - bool isSelected( const BOARD_ITEM* aItem ) const; - /** * Function selectable() * Checks conditions for an item to be selected. @@ -184,7 +174,7 @@ private: * * @param aItem is an item to be selected. */ - void selectItem( BOARD_ITEM* aItem ); + void select( BOARD_ITEM* aItem ); /** * Function deselectItem() @@ -192,7 +182,21 @@ private: * * @param aItem is an item to be deselected. */ - void deselectItem( BOARD_ITEM* aItem ); + void deselect( BOARD_ITEM* aItem ); + + /** + * Function deselectVisually() + * Marks item as selected, but does not add it to the ITEMS_PICKED_LIST. + * @param aItem is an item to be be marked. + */ + void selectVisually( BOARD_ITEM* aItem ) const; + + /** + * Function deselectVisually() + * Marks item as selected, but does not add it to the ITEMS_PICKED_LIST. + * @param aItem is an item to be be marked. + */ + void deselectVisually( BOARD_ITEM* aItem ) const; /** * Function containsSelected() From c1d6e44413809fdb1616beabc859b42f2032ef5c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 15:09:09 +0100 Subject: [PATCH 22/84] Speed optimization during selection of multiple items. Removed debug output. --- pcbnew/tools/edit_tool.cpp | 6 ------ pcbnew/tools/selection_tool.cpp | 6 ++---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index e8accb4ca7..a51d9dccf9 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -129,12 +129,6 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) else { // Prepare to drag - save items, so changes can be undone - for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) - { - BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - std::cout << "saved " << (unsigned long) item << std::endl; - } - editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index dabf03dda8..540ea5cb3d 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -503,7 +503,6 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem ) { MODULE* module = static_cast( aItem ); module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::selectVisually ), this ) ); - } selectVisually( aItem ); @@ -519,8 +518,8 @@ void SELECTION_TOOL::select( BOARD_ITEM* aItem ) // Now the context menu should be enabled SetContextMenu( &m_menu, CMENU_BUTTON ); } - else - { + else if( m_selection.Size() == 2 ) // Check only for 2, so it will not be + { // called for every next selected item // If multiple items are selected, do not show the information about the selected item getEditFrame()->SetCurItem( NULL, true ); } @@ -535,7 +534,6 @@ void SELECTION_TOOL::deselect( BOARD_ITEM* aItem ) { MODULE* module = static_cast( aItem ); module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::deselectVisually ), this ) ); - } deselectVisually( aItem ); From fd0a3348ea00b5c05a6a2eef8230d18139a1adb6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 15:11:12 +0100 Subject: [PATCH 23/84] More elegant way of handling interruption of current modifications. --- pcbnew/tools/edit_tool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index a51d9dccf9..f1f7c75f0b 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -148,8 +148,8 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) if( restore ) { // Modifications has to be rollbacked, so restore the previous state of items - wxCommandEvent dummy; - editFrame->GetBoardFromUndoList( dummy ); + wxCommandEvent undoEvent( wxEVT_TOOL, wxID_UNDO ); + wxPostEvent( editFrame, undoEvent ); } else { From f4de2877f3fc16522bd017a19016dc3cb3849d65 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 15:38:38 +0100 Subject: [PATCH 24/84] Added possibility of removing selected items while dragging. --- pcbnew/tools/common_actions.cpp | 5 +++-- pcbnew/tools/edit_tool.cpp | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 1a80bd5a9c..6756e10a9d 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -24,6 +24,7 @@ #include "common_actions.h" #include +#include // Selection tool actions TOOL_ACTION COMMON_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection", @@ -42,8 +43,8 @@ TOOL_ACTION COMMON_ACTIONS::flip( "pcbnew.InteractiveEdit.flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ); -TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.delete", - AS_GLOBAL, 127, // 127 stands for DELETE key +TOOL_ACTION COMMON_ACTIONS::remove( "pcbnew.InteractiveEdit.remove", + AS_GLOBAL, WXK_DELETE, "Remove", "Deletes selected item(s)" ); TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties", diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index f1f7c75f0b..99f44b9dfb 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -112,6 +112,11 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) // Flip causes change of layers enableUpdateFlag( KIGFX::VIEW_ITEM::LAYERS ); } + else if( evt->IsAction( &COMMON_ACTIONS::remove ) ) + { + Remove( aEvent ); + break; + } } else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) From fb78432367c44582009cf621262685cc008d85ad Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 16:26:21 +0100 Subject: [PATCH 25/84] Made pads & module texts unselectable --- pcbnew/tools/selection_tool.cpp | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 540ea5cb3d..fe7568c873 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -220,13 +220,10 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) break; default: - // Remove modules, they have to be selected by clicking on area that does not - // contain anything but module footprint and not selectable items + // Remove unselectable items for( int i = collector.GetCount() - 1; i >= 0 ; --i ) { - BOARD_ITEM* boardItem = collector[i]; - - if( boardItem->Type() == PCB_MODULE_T || !selectable( boardItem ) ) + if( !selectable( collector[i] ) ) collector.Remove( i ); } @@ -455,12 +452,6 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const } break; - case PCB_PAD_T: - // Pads are not selectable in multiple selection mode - if( m_multiple ) - return false; - /* no break */ - case PCB_MODULE_T: if( aItem->IsOnLayer( LAYER_N_FRONT ) && board->IsElementVisible( MOD_FR_VISIBLE ) ) return true; @@ -472,16 +463,10 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const break; - case PCB_MODULE_TEXT_T: - // Module texts are not selectable in multiple selection mode - if( m_multiple ) - return false; - - break; - - // These are not selectable, otherwise silkscreen drawings would be easily destroyed + // These are not selectable case PCB_MODULE_EDGE_T: - // and some other stuff that should not be selected + case PCB_MODULE_TEXT_T: + case PCB_PAD_T: case NOT_USED: case TYPE_NOT_INIT: return false; From 7ce91d4e38c59c7ec8fe287c14a9584cccd85246 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 18 Dec 2013 17:16:15 +0100 Subject: [PATCH 26/84] Fixed zone area removal (& undoing) using the EDIT_TOOL. --- pcbnew/tools/edit_tool.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 99f44b9dfb..3d2191f5a8 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -303,16 +303,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) { MODULE* module = static_cast( aItem ); module->ClearFlags(); - - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - getView()->Remove( pad ); - - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - getView()->Remove( drawing ); - - getView()->Remove( &module->Reference() ); - getView()->Remove( &module->Value() ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), getView() ) ); // Module itself is deleted after the switch scope is finished // list of pads is rebuild by BOARD::BuildListOfNets() @@ -322,11 +313,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) } break; - case PCB_ZONE_AREA_T: - getView()->Remove( aItem ); - getModel( PCB_T )->Delete( aItem ); - return; - // These are not supposed to be removed case PCB_PAD_T: case PCB_MODULE_TEXT_T: @@ -341,6 +327,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) case PCB_TARGET_T: // a target (graphic item) case PCB_MARKER_T: // a marker used to show something case PCB_ZONE_T: // SEG_ZONE items are now deprecated + case PCB_ZONE_AREA_T: break; default: // other types do not need to (or should not) be handled From d613da8b8d98c7e6c13e888036881f40f90dc860 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 19 Dec 2013 10:10:42 +0100 Subject: [PATCH 27/84] Module texts are undo/redoable. --- pcbnew/board_undo_redo.cpp | 25 +++++++++++++++++++++++++ pcbnew/tools/selection_tool.cpp | 6 +++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index fb8578fa4f..85b8e5b194 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -295,6 +295,17 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem, if( aItem == NULL ) // Nothing to save return; + // For texts belonging to modules, we need to save state of the parent module + if( aItem->Type() == PCB_MODULE_TEXT_T ) + { + aItem = aItem->GetParent(); + wxASSERT( aItem->Type() == PCB_MODULE_T ); + aCommandType = UR_CHANGED; + + if( aItem == NULL ) + return; + } + PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); commandToUndo->m_TransformPoint = aTransformPoint; @@ -364,6 +375,20 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ ) { BOARD_ITEM* item = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii ); + + // For texts belonging to modules, we need to save state of the parent module + if( item->Type() == PCB_MODULE_TEXT_T ) + { + item = item->GetParent(); + wxASSERT( item->Type() == PCB_MODULE_T ); + + if( item == NULL ) + continue; + + commandToUndo->SetPickedItem( item, ii ); + commandToUndo->SetPickedItemStatus( UR_CHANGED, ii ); + } + UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii ); if( command == UR_UNSPECIFIED ) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index fe7568c873..4d4d8e5404 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -463,9 +463,13 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const break; + case PCB_MODULE_TEXT_T: + if( m_multiple ) + return false; + break; + // These are not selectable case PCB_MODULE_EDGE_T: - case PCB_MODULE_TEXT_T: case PCB_PAD_T: case NOT_USED: case TYPE_NOT_INIT: From 3dc9f295a4b509b3eb9154254617f1c9986ab226 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 20 Dec 2013 16:07:58 +0100 Subject: [PATCH 28/84] Fixed cursor force position option. --- common/tool/tool_dispatcher.cpp | 2 +- common/view/wx_view_controls.cpp | 11 ----------- include/view/wx_view_controls.h | 5 ++++- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 6fb5d5f500..66efcc2581 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -221,7 +221,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) // but changes in world coordinates (e.g. autopanning) type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) { - VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition(); + VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetMousePosition(); VECTOR2D pos = getView()->ToWorld( screenPos ); if( pos != m_lastMousePos || type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) diff --git a/common/view/wx_view_controls.cpp b/common/view/wx_view_controls.cpp index 7f7308d935..20778c7d3e 100644 --- a/common/view/wx_view_controls.cpp +++ b/common/view/wx_view_controls.cpp @@ -83,9 +83,7 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent ) bool isAutoPanning = false; if( m_autoPanEnabled ) - { isAutoPanning = handleAutoPanning( aEvent ); - } if( !isAutoPanning && aEvent.Dragging() ) { @@ -243,15 +241,6 @@ const VECTOR2D WX_VIEW_CONTROLS::GetMousePosition() const } -const VECTOR2D WX_VIEW_CONTROLS::GetCursorPosition() const -{ - if( m_snappingEnabled ) - return m_view->GetGAL()->GetGridPoint( GetMousePosition() ); - else - return GetMousePosition(); -} - - bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent ) { VECTOR2D p( aEvent.GetX(), aEvent.GetY() ); diff --git a/include/view/wx_view_controls.h b/include/view/wx_view_controls.h index f5561f7d2d..cfec3eac9b 100644 --- a/include/view/wx_view_controls.h +++ b/include/view/wx_view_controls.h @@ -84,7 +84,10 @@ public: const VECTOR2D GetMousePosition() const; /// @copydoc VIEW_CONTROLS::GetCursorPosition() - const VECTOR2D GetCursorPosition() const; + const VECTOR2D GetCursorPosition() const + { + return m_cursorPosition; + } /// Event that forces mouse move event in the dispatcher (eg. used in autopanning, when mouse /// cursor does not move in screen coordinates, but does in world coordinates) From 7784365b39b4c2375b211c5446a181303512f2c1 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:09:27 +0100 Subject: [PATCH 29/84] Fixed bounding box for module texts. --- pcbnew/class_text_mod.cpp | 12 ++++++++++++ pcbnew/class_text_mod.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/pcbnew/class_text_mod.cpp b/pcbnew/class_text_mod.cpp index fbebde39bd..71deb4a462 100644 --- a/pcbnew/class_text_mod.cpp +++ b/pcbnew/class_text_mod.cpp @@ -415,6 +415,18 @@ EDA_ITEM* TEXTE_MODULE::Clone() const } +const BOX2I TEXTE_MODULE::ViewBBox() const +{ + double angle = GetDrawRotation(); + EDA_RECT text_area = GetTextBox( -1, -1 ); + + if( angle ) + text_area = text_area.GetBoundingBoxRotated( m_Pos, angle ); + + return BOX2I( text_area.GetPosition(), text_area.GetSize() ); +} + + void TEXTE_MODULE::ViewGetLayers( int aLayers[], int& aCount ) const { switch( m_Type ) diff --git a/pcbnew/class_text_mod.h b/pcbnew/class_text_mod.h index 3452d4f316..97e15ab202 100644 --- a/pcbnew/class_text_mod.h +++ b/pcbnew/class_text_mod.h @@ -165,6 +165,9 @@ public: EDA_ITEM* Clone() const; + /// @copydoc VIEW_ITEM::ViewBBox() + virtual const BOX2I ViewBBox() const; + /// @copydoc VIEW_ITEM::ViewGetLayers() virtual void ViewGetLayers( int aLayers[], int& aCount ) const; From bc71a2c007d74e7b340b1ce6d5e52941131b876a Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:11:53 +0100 Subject: [PATCH 30/84] Removed TOOL_STATE.idle field, as it was redundant. --- common/tool/tool_manager.cpp | 23 ++-- pcbnew/tools/move_tool.cpp | 204 ----------------------------------- pcbnew/tools/move_tool.h | 76 ------------- 3 files changed, 9 insertions(+), 294 deletions(-) delete mode 100644 pcbnew/tools/move_tool.cpp delete mode 100644 pcbnew/tools/move_tool.h diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp index 937a178653..f36d0cb343 100644 --- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -127,7 +127,6 @@ void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool ) TOOL_STATE* st = new TOOL_STATE; st->theTool = aTool; - st->idle = true; st->pendingWait = false; st->pendingContextMenu = false; st->cofunc = NULL; @@ -240,14 +239,10 @@ bool TOOL_MANAGER::runTool( TOOL_BASE* aTool ) return false; } - TOOL_STATE* state = m_toolState[aTool]; - // If the tool is already active, do not invoke it again - if( state->idle == false ) + if( isActive( aTool ) ) return false; - state->idle = false; - aTool->Reset( TOOL_INTERACTIVE::RUN ); // Add the tool on the front of the processing queue (it gets events first) @@ -417,19 +412,18 @@ bool TOOL_MANAGER::dispatchActivation( TOOL_EVENT& aEvent ) void TOOL_MANAGER::finishTool( TOOL_STATE* aState ) { - // Find the tool to be deactivated - std::deque::iterator it, it_end; + std::deque::iterator it, itEnd; - for( it = m_activeTools.begin(), it_end = m_activeTools.end(); it != it_end; ++it ) + // Find the tool and deactivate it + for( it = m_activeTools.begin(), itEnd = m_activeTools.end(); it != itEnd; ++it ) { if( aState == m_toolIdIndex[*it] ) + { + m_activeTools.erase( it ); break; + } } - if( it != m_activeTools.end() ) - m_activeTools.erase( it ); - - aState->idle = true; delete aState->cofunc; aState->cofunc = NULL; } @@ -525,5 +519,6 @@ bool TOOL_MANAGER::isActive( TOOL_BASE* aTool ) if( !isRegistered( aTool ) ) return false; - return !m_toolState[aTool]->idle; + // Just check if the tool is on the active tools stack + return std::find( m_activeTools.begin(), m_activeTools.end(), aTool->GetId() ) != m_activeTools.end(); } diff --git a/pcbnew/tools/move_tool.cpp b/pcbnew/tools/move_tool.cpp deleted file mode 100644 index 2cc3b0752e..0000000000 --- a/pcbnew/tools/move_tool.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * 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 -#include -#include -#include -#include -#include - -#include - -#include "common_actions.h" -#include "selection_tool.h" -#include "move_tool.h" - -using namespace KIGFX; -using boost::optional; - -MOVE_TOOL::MOVE_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveMove" ), m_selectionTool( NULL ) -{ -} - - -void MOVE_TOOL::Reset() -{ - // The tool launches upon reception of action event ("pcbnew.InteractiveMove") - Go( &MOVE_TOOL::Main, COMMON_ACTIONS::moveActivate.MakeEvent() ); -} - - -bool MOVE_TOOL::Init() -{ - // Find the selection tool, so they can cooperate - TOOL_BASE* selectionTool = m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ); - - if( selectionTool ) - { - m_selectionTool = static_cast( selectionTool ); - - // Add context menu entries that are displayed when selection tool is active - m_selectionTool->AddMenuItem( COMMON_ACTIONS::moveActivate ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::rotate ); - m_selectionTool->AddMenuItem( COMMON_ACTIONS::flip ); - } - else - { - DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) ); - return false; - } - - return true; -} - - -int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) -{ - const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - - if( selection.Empty() ) - return 0; // there are no items to operate on - - VECTOR2D dragPosition; - bool dragging = false; - bool restore = false; // Should items' state be restored when finishing the tool? - - VIEW_CONTROLS* controls = getViewControls(); - controls->ShowCursor( true ); - controls->SetSnapping( true ); - controls->SetAutoPan( true ); - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - if( evt->IsCancel() ) - { - restore = true; // Cancelling the tool means that items have to be restored - break; // Finish - } - - // Dispatch TOOL_ACTIONs - else if( evt->Category() == TC_COMMAND ) - { - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); - - if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) // got rotation event? - { - m_state.Rotate( cursorPos, 900.0 ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - updateRatsnest( true ); - } - else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) // got flip event? - { - m_state.Flip( cursorPos ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - updateRatsnest( true ); - } - } - - else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) - { - if( dragging ) - { - // Drag items to the current cursor position - VECTOR2D movement = ( evt->Position() - dragPosition ); - m_state.Move( movement ); - - updateRatsnest( true ); - } - else - { - // Prepare to drag - std::set::iterator it; - - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - // Save the state of the selected items, in case it has to be restored - m_state.Save( *it ); - } - - dragging = true; - } - - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - dragPosition = evt->Position(); - } - else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) - break; // Finish - } - - if( restore ) - { - // Modifications has to be rollbacked, so restore the previous state of items - selection.group->ItemsViewUpdate( VIEW_ITEM::APPEARANCE ); - m_state.RestoreAll(); - - updateRatsnest( false ); - } - else - { - // Changes are applied, so update the items - selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() ); - m_state.Apply(); - - } - - RN_DATA* ratsnest = static_cast( m_toolMgr->GetModel() )->GetRatsnest(); - ratsnest->Recalculate(); - - controls->ShowCursor( false ); - controls->SetSnapping( false ); - controls->SetAutoPan( false ); - - return 0; -} - - -void MOVE_TOOL::updateRatsnest( bool aRedraw ) -{ - const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - RN_DATA* ratsnest = static_cast( m_toolMgr->GetModel() )->GetRatsnest(); - - ratsnest->ClearSimple(); - BOOST_FOREACH( BOARD_ITEM* item, selection.items ) - { - if( item->Type() == PCB_PAD_T || item->Type() == PCB_TRACE_T || - item->Type() == PCB_VIA_T || item->Type() == PCB_ZONE_AREA_T ) - { - ratsnest->Update( static_cast( item ) ); - - if( aRedraw ) - ratsnest->AddSimple( static_cast( item ) ); - } - else if( item->Type() == PCB_MODULE_T ) - { - ratsnest->Update( static_cast( item ) ); - - if( aRedraw ) - ratsnest->AddSimple( static_cast( item ) ); - } - } -} diff --git a/pcbnew/tools/move_tool.h b/pcbnew/tools/move_tool.h deleted file mode 100644 index 10783a5ed4..0000000000 --- a/pcbnew/tools/move_tool.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * 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 __MOVE_TOOL_H -#define __MOVE_TOOL_H - -#include -#include -#include -#include "item_state.h" - -class BOARD_ITEM; -class SELECTION_TOOL; - -namespace KIGFX -{ -class VIEW_GROUP; -} - -/** - * Class MOVE_TOOL - * - * Our sample move tool. Allows to move, rotate and flip items selected by - * pcbnew.InteractiveSelection tool. - */ - -class MOVE_TOOL : public TOOL_INTERACTIVE -{ -public: - MOVE_TOOL(); - - /// @copydoc TOOL_INTERACTIVE::Reset() - void Reset(); - - /// @copydoc TOOL_INTERACTIVE::Init() - bool Init(); - - /** - * Function Main() - * - * Main loop in which events are handled. - */ - int Main( TOOL_EVENT& aEvent ); - -private: - void updateRatsnest( bool aRedraw ); - - /// Saves the state of items and allows to restore them - ITEM_STATE m_state; - - /// Selection tool used for obtaining selected items - SELECTION_TOOL* m_selectionTool; -}; - -#endif From aaf857e8946e512a4ec6aeaacd1fab913ca8afae Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:15:40 +0100 Subject: [PATCH 31/84] Items removed from board are removed from ratsnest as well. Corrected the way of items removal from ratsnest. --- pcbnew/class_board.cpp | 27 +++++++--- pcbnew/ratsnest_data.cpp | 113 ++++++++++++++++++++++++--------------- pcbnew/ratsnest_data.h | 5 +- 3 files changed, 94 insertions(+), 51 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index a56c226d63..c046fb70fd 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -867,26 +867,41 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) break; case PCB_ZONE_AREA_T: // this one uses a vector + { + ZONE_CONTAINER* zone = static_cast( aBoardItem ); + // find the item in the vector, then delete then erase it. - for( unsigned i = 0; iGetNets()[zone->GetNet()].RemoveItem( zone ); + } + break; case PCB_MODULE_T: + { + MODULE* module = static_cast( aBoardItem ); m_Modules.Remove( (MODULE*) aBoardItem ); - break; + + for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + m_ratsnest->GetNets()[pad->GetNet()].RemoveItem( pad ); + } + break; case PCB_TRACE_T: case PCB_VIA_T: - m_Track.Remove( (TRACK*) aBoardItem ); - break; + { + TRACK* track = static_cast( aBoardItem ); + m_Track.Remove( track ); + m_ratsnest->GetNets()[track->GetNet()].RemoveItem( track ); + } + break; case PCB_ZONE_T: m_Zone.Remove( (SEGZONE*) aBoardItem ); diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index e66451b86b..a5f708e0fe 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -201,12 +201,18 @@ const RN_NODE_PTR& RN_LINKS::AddNode( int aX, int aY ) } -void RN_LINKS::RemoveNode( const RN_NODE_PTR& aNode ) +bool RN_LINKS::RemoveNode( const RN_NODE_PTR& aNode ) { aNode->DecRefCount(); // TODO use the shared_ptr use_count if( aNode->GetRefCount() == 0 ) + { m_nodes.erase( aNode ); + + return true; + } + + return false; } @@ -270,6 +276,9 @@ void RN_NET::compute() void RN_NET::clearNode( const RN_NODE_PTR& aNode ) { + if( !m_rnEdges ) + return; + std::vector::iterator newEnd; // Remove all ratsnest edges for associated with the node @@ -430,75 +439,92 @@ void RN_NET::AddItem( const ZONE_CONTAINER* aZone ) void RN_NET::RemoveItem( const D_PAD* aPad ) { - RN_NODE_PTR& node = m_pads[aPad]; - if( !node ) - return; + try + { + RN_NODE_PTR node = m_pads.at( aPad ); - // Remove edges associated with the node - clearNode( node ); - m_links.RemoveNode( node ); + if( m_links.RemoveNode( node ) ) + clearNode( node ); - m_pads.erase( aPad ); + m_pads.erase( aPad ); - m_dirty = true; + m_dirty = true; + } + catch( ... ) + { + } } void RN_NET::RemoveItem( const SEGVIA* aVia ) { - RN_NODE_PTR& node = m_vias[aVia]; - if( !node ) - return; + try + { + RN_NODE_PTR node = m_vias.at( aVia ); - // Remove edges associated with the node - clearNode( node ); - m_links.RemoveNode( node ); + if( m_links.RemoveNode( node ) ) + clearNode( node ); - m_vias.erase( aVia ); + m_vias.erase( aVia ); - m_dirty = true; + m_dirty = true; + } + catch( ... ) + { + } } void RN_NET::RemoveItem( const TRACK* aTrack ) { - RN_EDGE_PTR& edge = m_tracks[aTrack]; - if( !edge ) - return; + try + { + RN_EDGE_PTR& edge = m_tracks.at( aTrack ); - // Save nodes, so they can be cleared later - const RN_NODE_PTR& aBegin = edge->getSourceNode(); - const RN_NODE_PTR& aEnd = edge->getTargetNode(); - m_links.RemoveConnection( edge ); + // Save nodes, so they can be cleared later + RN_NODE_PTR aBegin = edge->getSourceNode(); + RN_NODE_PTR aEnd = edge->getTargetNode(); + m_links.RemoveConnection( edge ); - // Remove nodes associated with the edge. It is done in a safe way, there is a check - // if nodes are not used by other edges. - clearNode( aBegin ); - clearNode( aEnd ); - m_links.RemoveNode( aBegin ); - m_links.RemoveNode( aEnd ); + // Remove nodes associated with the edge. It is done in a safe way, there is a check + // if nodes are not used by other edges. + if( m_links.RemoveNode( aBegin ) ) + clearNode( aBegin ); - m_tracks.erase( aTrack ); + if( m_links.RemoveNode( aEnd ) ) + clearNode( aEnd ); - m_dirty = true; + m_tracks.erase( aTrack ); + + m_dirty = true; + } + catch( ... ) + { + } } void RN_NET::RemoveItem( const ZONE_CONTAINER* aZone ) { - // Remove all subpolygons that make the zone - std::deque& polygons = m_zonePolygons[aZone]; - BOOST_FOREACH( RN_POLY& polygon, polygons ) - m_links.RemoveNode( polygon.GetNode() ); - polygons.clear(); + try + { + // Remove all subpolygons that make the zone + std::deque& polygons = m_zonePolygons.at( aZone ); + BOOST_FOREACH( RN_POLY& polygon, polygons ) + m_links.RemoveNode( polygon.GetNode() ); + polygons.clear(); - // Remove all connections added by the zone - std::deque& edges = m_zoneConnections[aZone]; - BOOST_FOREACH( RN_EDGE_PTR& edge, edges ) - m_links.RemoveConnection( edge ); - edges.clear(); + // Remove all connections added by the zone + std::deque& edges = m_zoneConnections.at( aZone ); + BOOST_FOREACH( RN_EDGE_PTR& edge, edges ) + m_links.RemoveConnection( edge ); + edges.clear(); - m_dirty = true; + m_dirty = true; + } + catch( ... ) + { + } } @@ -832,6 +858,7 @@ void RN_DATA::Recalculate( int aNet ) // Start with net number 1, as 0 stand for not connected for( unsigned int i = 1; i < m_board->GetNetCount(); ++i ) { + // Recompute only nets that require it if( m_nets[i].IsDirty() ) updateNet( i ); } diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index 6d0e7ee896..f8ffbf2406 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -129,8 +129,9 @@ public: * Function RemoveNode() * Removes a node described by a given node pointer. * @param aNode is a pointer to node to be removed. + * @return True if node was removed, false if there were other references, so it was kept. */ - void RemoveNode( const RN_NODE_PTR& aNode ); + bool RemoveNode( const RN_NODE_PTR& aNode ); /** * Function GetNodes() @@ -577,7 +578,7 @@ public: * Returns ratsnest grouped by net numbers. * @return Vector of ratsnest grouped by net numbers. */ - const std::vector& GetNets() const + std::vector& GetNets() { return m_nets; } From 3fe183c472729d9b28a11a48a12b67c4e2911dc8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:16:47 +0100 Subject: [PATCH 32/84] Tools have possibility to react to GAL switching or model (board) reload. --- pcbnew/pcbframe.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 56e80d84bc..32e8c27ba7 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -334,16 +334,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, SetBoard( new BOARD() ); - if( GetGalCanvas() ) - { - ViewReloadBoard( m_Pcb ); - - // update the tool manager with the new board and its view. - if( m_toolManager ) - m_toolManager->SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), - GetGalCanvas()->GetViewControls(), this ); - } - // Create the PCB_LAYER_WIDGET *after* SetBoard(): wxFont font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); @@ -543,8 +533,11 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard ) // update the tool manager with the new board and its view. if( m_toolManager ) + { m_toolManager->SetEnvironment( aBoard, GetGalCanvas()->GetView(), GetGalCanvas()->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD ); + } } } @@ -749,10 +742,14 @@ void PCB_EDIT_FRAME::UseGalCanvas( bool aEnable ) { EDA_DRAW_FRAME::UseGalCanvas( aEnable ); - m_toolManager->SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), - GetGalCanvas()->GetViewControls(), this ); - ViewReloadBoard( m_Pcb ); + + if( aEnable ) + { + m_toolManager->SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), + GetGalCanvas()->GetViewControls(), this ); + m_toolManager->ResetTools( TOOL_BASE::GAL_SWITCH ); + } } From 69cf8aa325c690cbd65aee8907c24483dd47a581 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:21:37 +0100 Subject: [PATCH 33/84] Fixed snapping for Push and Shove router. --- pcbnew/router/router_tool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index d43ea3ece4..6e8d732040 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -278,7 +278,7 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) else { m_endItem = NULL; - m_endSnapPoint = p; + m_endSnapPoint = getView()->ToWorld( ctls->GetCursorPosition() ); ctls->ForceCursorPosition( false ); } @@ -407,6 +407,7 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) // Restore the default settings ctls->SetAutoPan( false ); ctls->ShowCursor( false ); + ctls->ForceCursorPosition( false ); return 0; } From 75db0cebb7458b22c5f9a0e6c65ea5aa61e2dcdd Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:22:37 +0100 Subject: [PATCH 34/84] Fixed Push and Shove and ratsnest cooperation (tracks added by PNS are taken into account while calculating ratsnest). --- pcbnew/router/pns_router.cpp | 9 ++++----- pcbnew/router/router_tool.cpp | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 151b28ffa1..33a512b451 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -263,7 +263,7 @@ void PNS_ROUTER::SyncWorld() if( type == PCB_TRACE_T ) item = syncTrack( t ); else if( type == PCB_VIA_T ) - item = syncVia( static_cast (t) ); + item = syncVia( static_cast( t ) ); if( item ) m_world->Add( item ); @@ -754,13 +754,12 @@ bool PNS_ROUTER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) void PNS_ROUTER::StopRouting() { + // Update the ratsnest with new changes + m_board->GetRatsnest()->Recalculate( m_currentNet ); + if( !RoutingInProgress() ) return; - // highlightCurrent(false); - - // Update the ratsnest - m_board->GetRatsnest()->Recalculate( m_currentNet ); EraseView(); m_state = IDLE; diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 6e8d732040..b301901048 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -369,8 +369,7 @@ void ROUTER_TOOL::startRouting() } } - if( m_router->RoutingInProgress() ) - m_router->StopRouting(); + m_router->StopRouting(); ctls->SetAutoPan( false ); ctls->ForceCursorPosition( false ); From 6ad9d013e2eef6fbaf41b7eb7f5279cebf8c29e8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 14:23:46 +0100 Subject: [PATCH 35/84] Safer way for syncing pads in Push and Shover router. --- pcbnew/router/pns_router.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 33a512b451..e70fe550bf 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include #include @@ -248,11 +248,15 @@ void PNS_ROUTER::SyncWorld() m_world->SetMaxClearance( 1000000 ); // m_board->GetBiggestClearanceValue()); pads = m_board->GetPads(); - BOOST_FOREACH( D_PAD * pad, pads ) { - PNS_ITEM* solid = syncPad( pad ); + for( MODULE* module = m_board->m_Modules; module; module = module->Next() ) + { + for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) + { + PNS_ITEM* solid = syncPad( pad ); - if( solid ) - m_world->Add( solid ); + if( solid ) + m_world->Add( solid ); + } } for( TRACK* t = m_board->m_Track; t; t = t->Next() ) From 84412ce13592449b17864840a5a0271922e2e3d4 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 15:52:10 +0100 Subject: [PATCH 36/84] Delaunau triangulation algorithm was bailing out if run on an emprty container. --- pcbnew/ratsnest_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index a5f708e0fe..f33d5e96e6 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -246,7 +246,7 @@ void RN_NET::compute() return; } - else if( boardNodes.size() == 1 ) // This case is even simpler + else if( boardNodes.size() == 1 || boardNodes.empty() ) // This case is even simpler { m_rnEdges.reset( new std::vector( 0 ) ); From 8f054a606f4e46111e5f05a5e1df80f6c9b06f35 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 7 Jan 2014 17:23:17 +0100 Subject: [PATCH 37/84] Fixed snapping and ratsnest update for EDIT_TOOL. --- pcbnew/tools/edit_tool.cpp | 50 +++++++++++++++++++++++++++++++++++--- pcbnew/tools/edit_tool.h | 2 ++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 7f35d8a01e..277fefa8c1 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -28,8 +28,10 @@ #include #include #include +#include #include #include +#include #include "common_actions.h" #include "selection_tool.h" @@ -88,6 +90,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) controls->ShowCursor( true ); controls->SetSnapping( true ); controls->SetAutoPan( true ); + controls->ForceCursorPosition( false ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) @@ -115,6 +118,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) else if( evt->IsAction( &COMMON_ACTIONS::remove ) ) { Remove( aEvent ); + break; } } @@ -124,12 +128,15 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) if( m_dragging ) { // Drag items to the current cursor position - VECTOR2D movement = ( evt->Position() - dragPosition ); + VECTOR2D movement = ( getView()->ToWorld( controls->GetCursorPosition() ) - + dragPosition ); for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); item->Move( wxPoint( movement.x, movement.y ) ); } + + updateRatsnest( true ); } else { @@ -141,7 +148,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) } selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - dragPosition = evt->Position(); + dragPosition = getView()->ToWorld( controls->GetCursorPosition() ); } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) @@ -162,6 +169,10 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) selection.group->ItemsViewUpdate( m_updateFlag ); } + RN_DATA* ratsnest = getModel( PCB_T )->GetRatsnest(); + ratsnest->ClearSimple(); + ratsnest->Recalculate(); + controls->ShowCursor( false ); controls->SetSnapping( false ); controls->SetAutoPan( false ); @@ -195,6 +206,7 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) } setTransitions(); + updateRatsnest( true ); return 0; } @@ -225,6 +237,7 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); setTransitions(); + updateRatsnest( true ); return 0; } @@ -255,6 +268,7 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); setTransitions(); + updateRatsnest( true ); return 0; } @@ -284,10 +298,11 @@ int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) // Rebuild list of pads and nets if necessary BOARD* board = getModel( PCB_T ); - if( !( board->GetStatus() & NET_CODES_OK ) ) + if( !( board->m_Status_Pcb & NET_CODES_OK ) ) board->BuildListOfNets(); setTransitions(); + board->GetRatsnest()->Recalculate(); return 0; } @@ -349,3 +364,32 @@ void EDIT_TOOL::setTransitions() Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() ); Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); } + + +void EDIT_TOOL::updateRatsnest( bool aRedraw ) +{ + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + RN_DATA* ratsnest = getModel( PCB_T )->GetRatsnest(); + + ratsnest->ClearSimple(); + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + + if( item->Type() == PCB_PAD_T || item->Type() == PCB_TRACE_T || + item->Type() == PCB_VIA_T || item->Type() == PCB_ZONE_AREA_T ) + { + ratsnest->Update( static_cast( item ) ); + + if( aRedraw ) + ratsnest->AddSimple( static_cast( item ) ); + } + else if( item->Type() == PCB_MODULE_T ) + { + ratsnest->Update( static_cast( item ) ); + + if( aRedraw ) + ratsnest->AddSimple( static_cast( item ) ); + } + } +} diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index 5ddcb84f5d..0079d332b3 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -113,6 +113,8 @@ private: if( m_updateFlag < aFlag ) m_updateFlag = aFlag; } + + void updateRatsnest( bool aRedraw ); }; #endif From 487b609e7604ee008167b9ed30b8bd764d78ce96 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 9 Jan 2014 15:51:47 +0100 Subject: [PATCH 38/84] Removed NETINFO_ITEM::SetNet() and NETINFO_ITEM::SetNetname() methods. NETINFO_ITEM::m_Net and NETINFO_ITEM::m_Netname are const. Changes to be verified: - pcbnew/minimun_spanning_tree.cpp: It segfaults is m_Size == 0 - pcbnew/exporters/export_gencad.cpp: I removed the SetNetname() call, as it changes only the unconnected net and in the next line it returns if the net is unconnected. Still, I wonder if name for the unconnected net matters. What about tests that check if a net name is empty to decide if it is unconnected net or not. --- pcbnew/class_netinfo.h | 39 ++++++++++++++++++-------- pcbnew/class_netinfo_item.cpp | 19 ++----------- pcbnew/class_netinfolist.cpp | 45 ++++++++---------------------- pcbnew/exporters/export_gencad.cpp | 1 - pcbnew/legacy_plugin.cpp | 7 ++--- pcbnew/minimun_spanning_tree.cpp | 2 +- pcbnew/pcb_parser.cpp | 4 +-- 7 files changed, 45 insertions(+), 72 deletions(-) diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index 427a7b5685..a3c1807e14 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -228,14 +228,14 @@ private: class NETINFO_ITEM { private: - int m_NetCode; ///< A number equivalent to the net name. + const int m_NetCode; ///< A number equivalent to the net name. ///< Used for fast comparisons in ratsnest and DRC computations. - wxString m_Netname; ///< Full net name like /mysheet/mysubsheet/vout + const wxString m_Netname; ///< Full net name like /mysheet/mysubsheet/vout ///< used by Eeschema - wxString m_ShortNetname; // short net name, like vout from - // /mysheet/mysubsheet/vout + const wxString m_ShortNetname; // short net name, like vout from + // /mysheet/mysubsheet/vout wxString m_NetClassName; // Net Class name. if void this is equivalent // to "default" (the first @@ -386,8 +386,10 @@ public: */ int GetNet() const { return m_NetCode; } - void SetNet( int aNetCode ) { m_NetCode = aNetCode; } - + /** + * Function GetNodesCount + * @return int - number of nodes in the net + */ int GetNodesCount() const { return m_PadInNetList.size(); } /** @@ -402,12 +404,6 @@ public: */ wxString GetShortNetname() const { return m_ShortNetname; } - /** - * Function SetNetname - * @param aNetname : the new netname - */ - void SetNetname( const wxString& aNetname ); - /** * Function GetMsgPanelInfo * returns the information about the #NETINFO_ITEM in \a aList to display in the @@ -416,6 +412,25 @@ public: * @param aList is the list in which to place the status information. */ void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); + + /** + * Function Clear + * sets all fields to their defaults values. + */ + void Clear() + { + m_PadInNetList.clear(); + + m_NbNodes = 0; + m_NbLink = 0; + m_NbNoconn = 0; + m_Flag = 0; + m_RatsnestStartIdx = 0; // Starting point of ratsnests of this net in a + // general buffer of ratsnest + m_RatsnestEndIdx = 0; // Ending point of ratsnests of this net + + SetClass( NULL ); + } }; diff --git a/pcbnew/class_netinfo_item.cpp b/pcbnew/class_netinfo_item.cpp index f96132dfc1..05bcabb1bc 100644 --- a/pcbnew/class_netinfo_item.cpp +++ b/pcbnew/class_netinfo_item.cpp @@ -49,13 +49,9 @@ /* class NETINFO_ITEM: handle data relative to a given net */ /*********************************************************/ -NETINFO_ITEM::NETINFO_ITEM( BOARD_ITEM* aParent, const wxString& aNetName, int aNetCode ) +NETINFO_ITEM::NETINFO_ITEM( BOARD_ITEM* aParent, const wxString& aNetName, int aNetCode ) : + m_NetCode( aNetCode ), m_Netname( aNetName ), m_ShortNetname( m_Netname.AfterLast( '/' ) ) { - SetNet( aNetCode ); - - if( aNetName.size() ) - SetNetname( aNetName ); - m_parent = aParent; m_NbNodes = 0; m_NbLink = 0; @@ -77,17 +73,6 @@ NETINFO_ITEM::~NETINFO_ITEM() } -/** - * Function SetNetname - * @param aNetname : the new netname - */ -void NETINFO_ITEM::SetNetname( const wxString& aNetname ) -{ - m_Netname = aNetname; - m_ShortNetname = m_Netname.AfterLast( '/' ); -} - - /** * Function Draw (TODO) */ diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index df5f8039de..75bad023a2 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -37,10 +37,6 @@ void NETINFO_LIST::clear() } -/** - * Function Append - * adds \a aNewElement to the end of the list. - */ void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement ) { m_NetBuffer.push_back( aNewElement ); @@ -80,46 +76,29 @@ void NETINFO_LIST::buildListOfNets() int nodes_count = 0; NETINFO_ITEM* net_item; - clear(); // Remove all nets info and free memory - - // Create and add the "unconnected net", always existing, - // used to handle pads and tracks that are not member of a "real" net - net_item = new NETINFO_ITEM( m_Parent ); - AppendNet( net_item ); - // Build the PAD list, sorted by net buildPadsFullList(); - // Build netnames list, and create a netcode for each netname - D_PAD* last_pad = NULL; - int netcode = 0; + // Restore the initial state of NETINFO_ITEMs + for( unsigned i = 0; i < GetNetCount(); ++i ) + { + GetNetItem( i )->Clear(); + } + std::cout << m_PadsFullList.size() << std::endl; + + // Assign pads to appropriate NETINFO_ITEMs for( unsigned ii = 0; ii < m_PadsFullList.size(); ii++ ) { pad = m_PadsFullList[ii]; - if( pad->GetNetname().IsEmpty() ) // pad not connected - { - pad->SetNet( 0 ); + if( pad->GetNet() == 0 ) // pad not connected continue; - } - /* if the current netname was already found: add pad to the current net_item , - * else create a new net_code and a new net_item - */ - if( last_pad == NULL || ( pad->GetNetname() != last_pad->GetNetname() ) ) - { - netcode++; - net_item = new NETINFO_ITEM( m_Parent, pad->GetNetname(), netcode ); - AppendNet( net_item ); - } - - pad->SetNet( netcode ); + net_item = GetNetItem( pad->GetNet() ); net_item->m_PadInNetList.push_back( pad ); - nodes_count++; - - last_pad = pad; + ++nodes_count; } m_Parent->SetNodeCount( nodes_count ); @@ -129,8 +108,6 @@ void NETINFO_LIST::buildListOfNets() m_Parent->m_Status_Pcb |= NET_CODES_OK; m_Parent->SetAreasNetCodesFromNetNames(); - - // D( Show(); ) } #if defined(DEBUG) diff --git a/pcbnew/exporters/export_gencad.cpp b/pcbnew/exporters/export_gencad.cpp index f04496ff7c..394a39f808 100644 --- a/pcbnew/exporters/export_gencad.cpp +++ b/pcbnew/exporters/export_gencad.cpp @@ -647,7 +647,6 @@ static void CreateSignalsSection( FILE* aFile, BOARD* aPcb ) if( net->GetNetname() == wxEmptyString ) // dummy netlist (no connection) { wxString msg; msg << wxT( "NoConnection" ) << NbNoConn++; - net->SetNetname( msg ); } if( net->GetNet() <= 0 ) // dummy netlist (no connection) diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 4bc6e4550a..ab5a4fe34f 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -1811,7 +1811,7 @@ void LEGACY_PLUGIN::loadNETINFO_ITEM() { char buf[1024]; - NETINFO_ITEM* net = new NETINFO_ITEM( m_board ); + NETINFO_ITEM* net; char* line; while( ( line = READLINE( m_reader ) ) != NULL ) @@ -1822,11 +1822,10 @@ void LEGACY_PLUGIN::loadNETINFO_ITEM() { // e.g. "Na 58 "/cpu.sch/PAD7"\r\n" - int tmp = intParse( line + SZ( "Na" ), &data ); - net->SetNet( tmp ); + int netCode = intParse( line + SZ( "Na" ), &data ); ReadDelimitedText( buf, data, sizeof(buf) ); - net->SetNetname( FROM_UTF8( buf ) ); + net = new NETINFO_ITEM( m_board, FROM_UTF8( buf ), netCode ); } else if( TESTLINE( "$EndEQUIPOT" ) ) diff --git a/pcbnew/minimun_spanning_tree.cpp b/pcbnew/minimun_spanning_tree.cpp index f107590d6c..8d683f7786 100644 --- a/pcbnew/minimun_spanning_tree.cpp +++ b/pcbnew/minimun_spanning_tree.cpp @@ -69,7 +69,7 @@ MIN_SPAN_TREE::MIN_SPAN_TREE() void MIN_SPAN_TREE::MSP_Init( int aNodesCount ) { - m_Size = aNodesCount; + m_Size = std::max( aNodesCount, 1 ); inTree.clear(); linkedTo.clear(); distTo.clear(); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 1b47c69158..f1eaa3026c 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -1066,9 +1066,7 @@ void PCB_PARSER::parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR ) // (TODO: a better test.) if( number > 0 || m_board->FindNet( 0 ) == NULL ) { - NETINFO_ITEM* net = new NETINFO_ITEM( m_board ); - net->SetNet( number ); - net->SetNetname( name ); + NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, number ); m_board->AppendNet( net ); } } From 386d1fc2578e7a78b8c921c6a83ba6bf57874764 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 10 Jan 2014 17:19:33 +0100 Subject: [PATCH 39/84] Made two functions immune to empty containers. --- pcbnew/ratsnest.cpp | 5 ++++- pcbnew/ratsnest_data.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pcbnew/ratsnest.cpp b/pcbnew/ratsnest.cpp index 00cec1cea0..b5347d3e85 100644 --- a/pcbnew/ratsnest.cpp +++ b/pcbnew/ratsnest.cpp @@ -70,7 +70,10 @@ public: void MIN_SPAN_TREE_PADS::AddTreeToRatsnest( std::vector &aRatsnestList ) { - std::vector & padsBuffer = *m_PadsList; + std::vector& padsBuffer = *m_PadsList; + if( padsBuffer.empty() ) + return; + int netcode = padsBuffer[0]->GetNet(); // Note: to get edges in minimum spanning tree, // the index value 0 is not used: it is just diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index e66451b86b..6ed72cfbe0 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -240,7 +240,7 @@ void RN_NET::compute() return; } - else if( boardNodes.size() == 1 ) // This case is even simpler + else if( boardNodes.size() == 1 || boardNodes.empty() ) // This case is even simpler { m_rnEdges.reset( new std::vector( 0 ) ); From bf80cc770ecaf7c8cb14d759b3d201c11438ba65 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 10 Jan 2014 18:04:07 +0100 Subject: [PATCH 40/84] Changed the way of looking up NETINFO_ITEM using net names (using boost::unordered_map). Added a hash function (wxString) for that. Introduced NETINFO_ITEM::GetNetItem( wxString ). BOARD::FindNet() uses the map. Net codes are updated upon net list update. (BOARD::ReplaceNetlist()) Added in some places (mostly class_board.cpp) pad->SetNet() calls to synchronize net codes. On creation of NETINFO_LIST, the first NETINFO_ITEM is added (the unconnected items net). Removed COMPONENT_NET::m_netNumber, as it was not used anywhere. Added an assert to D_PAD::GetNetname(), checking if net code and net name is consistent for unconnected pads. Added an assert for NETINFO_LIST::AppendNet() to assure that appended nets are unique. It seems that at this point: - Updating net lists works fine. The only difference between the file ouput is that after changes it contains empty nets as well. - Nets are not saved in the lexical order. Still, net names and net codes are properly assigned to all items in the .kicad_pcb file. It is going to be addressed in the next commit. I believe it should not create any problems, as pads are sorted by their net names anyway (NETINFO_LIST::buildPadsFullList()) Performed tests: - Created a blank PCB, saved as pic_programmer.kicad_pcb (from demos folder). Updated net lists. .kicad_pcb file (comparing to the results from master branch) differ with net order (as mentioned before), net codes and timestamps. - Removed some of components from the above .kicad_pcb file and updated net lists. Modules reappeared. .kicad_pcb file differs in the same way as described above. - Trying to change a pad net name (via properties dialog) results in assert being fired. It is done on purpose (as there is a call to GetNetname() and net name and net code do not match). This will not happen after the next commit. - Prepared a simple project (starting with schematics). Imported net list, changed schematic, reimported net list - changes are applied. - Eagle & KiCad legacy boards seem to load without any problem. --- include/hashtables.h | 18 +++++++ pcbnew/class_board.cpp | 93 +++++++------------------------- pcbnew/class_netinfo.h | 28 ++++++++-- pcbnew/class_netinfolist.cpp | 22 ++++---- pcbnew/class_pad.cpp | 1 + pcbnew/class_pad.h | 8 ++- pcbnew/pad_edition_functions.cpp | 1 + pcbnew/pcb_netlist.h | 6 +-- 8 files changed, 84 insertions(+), 93 deletions(-) diff --git a/include/hashtables.h b/include/hashtables.h index edb3f798e0..ed319ec64c 100644 --- a/include/hashtables.h +++ b/include/hashtables.h @@ -98,6 +98,24 @@ struct fnv_1a }; +/// Hash function for wxString, counterpart of std::string hash +struct WXSTRING_HASH : std::unary_function +{ + std::size_t operator()( const wxString& aString ) const + { + std::size_t hash = 2166136261u; + + for( wxString::const_iterator it = aString.begin(); it != aString.end(); ++it ) + { + hash ^= (unsigned char) *it; + hash *= 16777619; + } + + return hash; + } +}; + + /** * Type KEYWORD_MAP * is a hashtable made of a const char* and an int. Note that use of this diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index a56c226d63..214e78f5de 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -1355,79 +1355,7 @@ NETINFO_ITEM* BOARD::FindNet( int aNetcode ) const NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const { - // the first valid netcode is 1. - // zero is reserved for "no connection" and is not used. - if( aNetname.IsEmpty() ) - return NULL; - - int ncount = m_NetInfo.GetNetCount(); - - // Search for a netname = aNetname -#if 0 - - // Use a sequential search: easy to understand, but slow - for( int ii = 1; ii < ncount; ii++ ) - { - NETINFO_ITEM* item = m_NetInfo.GetNetItem( ii ); - - if( item && item->GetNetname() == aNetname ) - { - return item; - } - } - -#else - - // Use a fast binary search, - // this is possible because Nets are alphabetically ordered in list - // see NETINFO_LIST::BuildListOfNets() and - // NETINFO_LIST::Build_Pads_Full_List() - int imax = ncount - 1; - int index = imax; - - while( ncount > 0 ) - { - int ii = ncount; - ncount >>= 1; - - if( (ii & 1) && ( ii > 1 ) ) - ncount++; - - NETINFO_ITEM* item = m_NetInfo.GetNetItem( index ); - - if( item == NULL ) - return NULL; - - int icmp = item->GetNetname().Cmp( aNetname ); - - if( icmp == 0 ) // found ! - { - return item; - } - - if( icmp < 0 ) // must search after item - { - index += ncount; - - if( index > imax ) - index = imax; - - continue; - } - - if( icmp > 0 ) // must search before item - { - index -= ncount; - - if( index < 1 ) - index = 1; - - continue; - } - } - -#endif - return NULL; + return m_NetInfo.GetNetItem( aNetname ); } @@ -2618,7 +2546,10 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, } if( !aNetlist.IsDryRun() ) + { pad->SetNetname( wxEmptyString ); + pad->SetNet( 0 ); + } } } else // Footprint pad has a net. @@ -2638,7 +2569,19 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, } if( !aNetlist.IsDryRun() ) + { pad->SetNetname( net.GetNetName() ); + + NETINFO_ITEM* netinfo = FindNet( net.GetNetName() ); + if( netinfo == NULL ) + { + // It is a new net, we have to add it + netinfo = new NETINFO_ITEM( this, net.GetNetName(), m_NetInfo.GetNetCount() ); + m_NetInfo.AppendNet( netinfo ); + } + + pad->SetNet( netinfo->GetNet() ); + } } } } @@ -2711,6 +2654,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, aReporter->Report( msg ); } previouspad->SetNetname( wxEmptyString ); + previouspad->SetNet( 0 ); } netname = pad->GetNetname(); count = 1; @@ -2723,7 +2667,10 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, // Examine last pad if( pad && count == 1 ) + { pad->SetNetname( wxEmptyString ); + pad->SetNet( 0 ); + } } // Last step: Some tests: diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index a3c1807e14..c0e81a684e 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -37,6 +37,8 @@ #include #include #include +#include +#include class wxDC; @@ -115,7 +117,6 @@ public: }; - /** * Class NETINFO * is a container class for NETINFO_ITEM elements, which are the nets. That makes @@ -141,6 +142,20 @@ public: return m_NetBuffer[aNetcode]; } + /** + * Function GetItem + * @param aNetName = net name to identify a given NETINFO_ITEM + * @return NETINFO_ITEM* - by \a aNetName, or NULL if not found + */ + NETINFO_ITEM* GetNetItem( const wxString& aNetName ) const + { + NETNAMES_MAP::const_iterator result = m_netNames.find( aNetName ); + if( result != m_netNames.end() ) + return (*result).second; + + return NULL; + } + /** * Function GetNetCount * @return the number of nets ( always >= 1 ) @@ -188,6 +203,8 @@ public: void Show() const; #endif + typedef boost::unordered_map NETNAMES_MAP; + private: /** @@ -214,6 +231,7 @@ private: void buildPadsFullList(); BOARD* m_Parent; + NETNAMES_MAP m_netNames; ///< map for a fast look up by net names std::vector m_NetBuffer; ///< net list (name, design constraints ..) std::vector m_PadsFullList; ///< contains all pads, sorted by pad's netname. @@ -394,15 +412,15 @@ public: /** * Function GetNetname - * @return const wxString * , a pointer to the full netname + * @return const wxString&, a reference to the full netname */ - wxString GetNetname() const { return m_Netname; } + const wxString& GetNetname() const { return m_Netname; } /** * Function GetShortNetname - * @return const wxString * , a pointer to the short netname + * @return const wxString &, a reference to the short netname */ - wxString GetShortNetname() const { return m_ShortNetname; } + const wxString& GetShortNetname() const { return m_ShortNetname; } /** * Function GetMsgPanelInfo diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index 75bad023a2..561e845e21 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -15,9 +15,10 @@ // Constructor and destructor -NETINFO_LIST::NETINFO_LIST( BOARD* aParent ) +NETINFO_LIST::NETINFO_LIST( BOARD* aParent ) : m_Parent( aParent ) { - m_Parent = aParent; + // Make sure that the unconnected net has number 0 + AppendNet( new NETINFO_ITEM( aParent, wxEmptyString, 0 ) ); } @@ -34,14 +35,20 @@ void NETINFO_LIST::clear() m_NetBuffer.clear(); m_PadsFullList.clear(); + m_netNames.clear(); } void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement ) { + // net names & codes are supposed to be unique + assert( GetNetItem( aNewElement->GetNetname() ) == NULL ); + assert( GetNetItem( aNewElement->GetNet() ) == NULL ); + m_NetBuffer.push_back( aNewElement ); - // D(Show();) + // add an entry for fast look up by a net name using a map + m_netNames.insert( std::make_pair( aNewElement->GetNetname(), aNewElement ) ); } @@ -74,18 +81,13 @@ void NETINFO_LIST::buildListOfNets() { D_PAD* pad; int nodes_count = 0; - NETINFO_ITEM* net_item; // Build the PAD list, sorted by net buildPadsFullList(); // Restore the initial state of NETINFO_ITEMs for( unsigned i = 0; i < GetNetCount(); ++i ) - { GetNetItem( i )->Clear(); - } - - std::cout << m_PadsFullList.size() << std::endl; // Assign pads to appropriate NETINFO_ITEMs for( unsigned ii = 0; ii < m_PadsFullList.size(); ii++ ) @@ -95,8 +97,8 @@ void NETINFO_LIST::buildListOfNets() if( pad->GetNet() == 0 ) // pad not connected continue; - net_item = GetNetItem( pad->GetNet() ); - net_item->m_PadInNetList.push_back( pad ); + // Add pad to the appropriate list of pads + GetNetItem( pad->GetNet() )->m_PadInNetList.push_back( pad ); ++nodes_count; } diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index f984e4aa9b..2b707ead14 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -413,6 +413,7 @@ void D_PAD::CopyNetlistSettings( D_PAD* aPad ) wxCHECK_RET( aPad != NULL && aPad != this, wxT( "Cannot copy to NULL or yourself." ) ); aPad->SetNetname( GetNetname() ); + aPad->SetNet( GetNet() ); aPad->SetLocalClearance( m_LocalClearance ); aPad->SetLocalSolderMaskMargin( m_LocalSolderMaskMargin ); diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 5a385ea917..3c0b567c28 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -128,7 +128,13 @@ public: * Function GetNetname * @return const wxString& - the full netname */ - const wxString& GetNetname() const { return m_Netname; } + const wxString& GetNetname() const + { + assert( ( GetNet() == 0 ) == m_Netname.IsEmpty() ); + // assert( GetBoard()->FindNet( GetNet() ) == GetBoard()->FindNet( m_Netname ) ); + + return m_Netname; + } /** * Function GetShortNetname diff --git a/pcbnew/pad_edition_functions.cpp b/pcbnew/pad_edition_functions.cpp index b99bd1580a..3e890af710 100644 --- a/pcbnew/pad_edition_functions.cpp +++ b/pcbnew/pad_edition_functions.cpp @@ -142,6 +142,7 @@ void PCB_BASE_FRAME::AddPad( MODULE* aModule, bool draw ) // Update the pad properties. Import_Pad_Settings( pad, false ); pad->SetNetname( wxEmptyString ); + pad->SetNet( 0 ); pad->SetPosition( GetCrossHairPosition() ); diff --git a/pcbnew/pcb_netlist.h b/pcbnew/pcb_netlist.h index ff9544e10f..58ab9bf17d 100644 --- a/pcbnew/pcb_netlist.h +++ b/pcbnew/pcb_netlist.h @@ -47,16 +47,14 @@ class REPORTER; class COMPONENT_NET { wxString m_pinName; - wxString m_netNumber; wxString m_netName; public: COMPONENT_NET() {} - COMPONENT_NET( const wxString& aPinName, const wxString& aNetName ) + COMPONENT_NET( const wxString& aPinName, const wxString& aNetName ) : + m_pinName( aPinName ), m_netName( aNetName ) { - m_pinName = aPinName; - m_netName = aNetName; } const wxString& GetPinName() const { return m_pinName; } From 654e7e556e61b9848eb4443256c973f85d682442 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 14 Jan 2014 10:41:52 +0100 Subject: [PATCH 41/84] Removed D_PAD::SetNetname() function and D_PAD::m_Netname, D_PAD::m_ShortNetname fields. D_PAD::GetNetname() and D_PAD::GetShortNetname() were moved to BOARD_CONNECTED_ITEM. Now they use the net name stored in NETINFO_ITEM. Moved some one-line functions from class_board_connected_item.cpp to class_board_connected_item.h. Added a copyright notice, moved Doxygen comments from class_board_connected_item.cpp to class_board_connected_item.h. I have some doubts if changes introduced pcbnew/dialogs/dialog_pad_properties.cpp do not break anything, but I could not find a test case that breaks the pcbnew. Performed tests: - changed pad's net name from empty to existent - ok, name was changed - changed pad's net name from empty to nonexistent - ok, error message is displayed, net name stays empty - changed pad's net name from existent to empty - ok, net name became empty - changed pad's net name from existent to nonexistent - ok, error message is displayed, net name is not changed - (re)reading netlists, including net changes - fine, changes are applied, but empty nets are still kept - loaded pcbnew/pcad2kicadpcb_plugin/examples/CK1202_V1.pcb to test P-CAD import plugin - ok, net names are correct - imported an Eagle 6.0 board (Arduino Uno; http://arduino.cc/en/uploads/Main/arduino_Uno_Rev3-02-TH.zip) then saved in .kicad_pcb format and reloaded - ok, net names are correct - saved demos/video/video.kicad_pcb in legacy format and then loaded it again - ok, net names are correct --- pcbnew/class_board.cpp | 10 +-- pcbnew/class_board_connected_item.cpp | 78 ++++++------------------ pcbnew/class_board_connected_item.h | 75 ++++++++++++++++++++--- pcbnew/class_pad.cpp | 12 +--- pcbnew/class_pad.h | 28 --------- pcbnew/class_pad_draw_functions.cpp | 6 +- pcbnew/dialogs/dialog_pad_properties.cpp | 32 +++++----- pcbnew/eagle_plugin.cpp | 1 - pcbnew/legacy_plugin.cpp | 2 +- pcbnew/pad_edition_functions.cpp | 1 - pcbnew/pcad2kicadpcb_plugin/pcb.cpp | 10 +-- pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp | 12 +++- pcbnew/pcb_parser.cpp | 2 +- pcbnew/xchgmod.cpp | 4 -- 14 files changed, 122 insertions(+), 151 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 214e78f5de..dfcebd69e8 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2546,10 +2546,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, } if( !aNetlist.IsDryRun() ) - { - pad->SetNetname( wxEmptyString ); pad->SetNet( 0 ); - } } } else // Footprint pad has a net. @@ -2570,8 +2567,6 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, if( !aNetlist.IsDryRun() ) { - pad->SetNetname( net.GetNetName() ); - NETINFO_ITEM* netinfo = FindNet( net.GetNetName() ); if( netinfo == NULL ) { @@ -2653,7 +2648,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, GetChars( previouspad->GetPadName() ) ); aReporter->Report( msg ); } - previouspad->SetNetname( wxEmptyString ); + previouspad->SetNet( 0 ); } netname = pad->GetNetname(); @@ -2667,10 +2662,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, // Examine last pad if( pad && count == 1 ) - { - pad->SetNetname( wxEmptyString ); pad->SetNet( 0 ); - } } // Last step: Some tests: diff --git a/pcbnew/class_board_connected_item.cpp b/pcbnew/class_board_connected_item.cpp index eaf793f9b7..cf44e1dc7a 100644 --- a/pcbnew/class_board_connected_item.cpp +++ b/pcbnew/class_board_connected_item.cpp @@ -1,8 +1,3 @@ -/** - * @file class_board_connected_item.cpp - * @brief BOARD_CONNECTED_ITEM class functions. - */ - /* * This program source code file is part of KiCad, a free EDA CAD application. * @@ -28,6 +23,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +/** + * @file class_board_connected_item.cpp + * @brief BOARD_CONNECTED_ITEM class functions. + */ + #include #include @@ -36,68 +36,32 @@ BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ) : - BOARD_ITEM( aParent, idtype ) + BOARD_ITEM( aParent, idtype ), m_NetCode( 0 ), m_Subnet( 0 ), m_ZoneSubnet( 0 ) { - m_NetCode = 0; - m_Subnet = 0; - m_ZoneSubnet = 0; } BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem ) : - BOARD_ITEM( aItem ) + BOARD_ITEM( aItem ), m_NetCode( aItem.m_NetCode ), m_Subnet( aItem.m_Subnet ), + m_ZoneSubnet( aItem.m_ZoneSubnet ) { - m_NetCode = aItem.m_NetCode; - m_Subnet = aItem.m_Subnet; - m_ZoneSubnet = aItem.m_ZoneSubnet; } -/** - * Function GetNet - * @return int - the net code. - */ -int BOARD_CONNECTED_ITEM::GetNet() const +const wxString& BOARD_CONNECTED_ITEM::GetNetname() const { - return m_NetCode; + BOARD* board = GetBoard(); + NETINFO_ITEM* netinfo = board->FindNet( m_NetCode ); + + return netinfo->GetNetname(); } -void BOARD_CONNECTED_ITEM::SetNet( int aNetCode ) +const wxString& BOARD_CONNECTED_ITEM::GetShortNetname() const { - m_NetCode = aNetCode; -} + NETINFO_ITEM* netinfo = GetBoard()->FindNet( m_NetCode ); - -/** - * Function GetSubNet - * @return int - the sub net code. - */ -int BOARD_CONNECTED_ITEM::GetSubNet() const -{ - return m_Subnet; -} - - -void BOARD_CONNECTED_ITEM::SetSubNet( int aSubNetCode ) -{ - m_Subnet = aSubNetCode; -} - - -/** - * Function GetZoneSubNet - * @return int - the sub net code in zone connections. - */ -int BOARD_CONNECTED_ITEM::GetZoneSubNet() const -{ - return m_ZoneSubnet; -} - - -void BOARD_CONNECTED_ITEM::SetZoneSubNet( int aSubNetCode ) -{ - m_ZoneSubnet = aSubNetCode; + return netinfo->GetShortNetname(); } @@ -132,11 +96,6 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_CONNECTED_ITEM* aItem ) const } -/** return a pointer to the netclass of the zone - * if the net is not found (can happen when a netlist is reread, - * and the net name is not existant, return the default net class - * So should not return a null pointer - */ NETCLASS* BOARD_CONNECTED_ITEM::GetNetClass() const { // It is important that this be implemented without any sequential searching. @@ -176,10 +135,7 @@ NETCLASS* BOARD_CONNECTED_ITEM::GetNetClass() const return board->m_NetClasses.GetDefault(); } -/** - * Function GetNetClassName - * @return the Net Class name of this item - */ + wxString BOARD_CONNECTED_ITEM::GetNetClassName() const { wxString name; diff --git a/pcbnew/class_board_connected_item.h b/pcbnew/class_board_connected_item.h index 67cd457398..9b2f5df7b8 100644 --- a/pcbnew/class_board_connected_item.h +++ b/pcbnew/class_board_connected_item.h @@ -1,3 +1,28 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr + * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2012 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 + */ + /** * @file class_board_connected_item.h * @brief Class BOARD_CONNECTED_ITEM. @@ -6,7 +31,6 @@ #ifndef BOARD_CONNECTED_ITEM_H #define BOARD_CONNECTED_ITEM_H - #include class NETCLASS; @@ -48,22 +72,55 @@ public: * Function GetNet * @return int - the net code. */ - int GetNet() const; - virtual void SetNet( int aNetCode ); + int GetNet() const + { + return m_NetCode; + } + + virtual void SetNet( int aNetCode ) + { + m_NetCode = aNetCode; + } /** * Function GetSubNet * @return int - the sub net code. */ - int GetSubNet() const; - void SetSubNet( int aSubNetCode ); + int GetSubNet() const + { + return m_Subnet; + } + + void SetSubNet( int aSubNetCode ) + { + m_Subnet = aSubNetCode; + } /** * Function GetZoneSubNet * @return int - the sub net code in zone connections. */ - int GetZoneSubNet() const; - void SetZoneSubNet( int aSubNetCode ); + int GetZoneSubNet() const + { + return m_ZoneSubnet; + } + + void SetZoneSubNet( int aSubNetCode ) + { + m_ZoneSubnet = aSubNetCode; + } + + /** + * Function GetNetname + * @return const wxString& - the full netname + */ + const wxString& GetNetname() const; + + /** + * Function GetShortNetname + * @return const wxString& - the short netname + */ + const wxString& GetShortNetname() const; /** * Function GetClearance @@ -84,6 +141,10 @@ public: /** * Function GetNetClassName + * returns a pointer to the netclass of the zone. + * If the net is not found (can happen when a netlist is reread, + * and the net name does not exist, return the default net class + * (should not return a null pointer). * @return the Net Class name of this item */ wxString GetNetClassName() const; diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index 2b707ead14..b9877c4a56 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -364,13 +364,6 @@ void D_PAD::SetPadName( const wxString& name ) } -void D_PAD::SetNetname( const wxString& aNetname ) -{ - m_Netname = aNetname; - m_ShortNetname = m_Netname.AfterLast( '/' ); -} - - void D_PAD::Copy( D_PAD* source ) { if( source == NULL ) @@ -402,8 +395,6 @@ void D_PAD::Copy( D_PAD* source ) SetSubRatsnest( 0 ); SetSubNet( 0 ); - m_Netname = source->m_Netname; - m_ShortNetname = source->m_ShortNetname; } @@ -412,7 +403,6 @@ void D_PAD::CopyNetlistSettings( D_PAD* aPad ) // Don't do anything foolish like trying to copy to yourself. wxCHECK_RET( aPad != NULL && aPad != this, wxT( "Cannot copy to NULL or yourself." ) ); - aPad->SetNetname( GetNetname() ); aPad->SetNet( GetNet() ); aPad->SetLocalClearance( m_LocalClearance ); @@ -578,7 +568,7 @@ void D_PAD::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM>& aList ) aList.push_back( MSG_PANEL_ITEM( _( "Pad" ), Line, BROWN ) ); } - aList.push_back( MSG_PANEL_ITEM( _( "Net" ), m_Netname, DARKCYAN ) ); + aList.push_back( MSG_PANEL_ITEM( _( "Net" ), GetNetname(), DARKCYAN ) ); /* For test and debug only: display m_physical_connexion and * m_logical_connexion */ diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 3c0b567c28..579b4bbeef 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -118,30 +118,6 @@ public: return m_NumPadName == other->m_NumPadName; // hide tricks behind sensible API } - /** - * Function SetNetname - * @param aNetname: the new netname - */ - void SetNetname( const wxString& aNetname ); - - /** - * Function GetNetname - * @return const wxString& - the full netname - */ - const wxString& GetNetname() const - { - assert( ( GetNet() == 0 ) == m_Netname.IsEmpty() ); - // assert( GetBoard()->FindNet( GetNet() ) == GetBoard()->FindNet( m_Netname ) ); - - return m_Netname; - } - - /** - * Function GetShortNetname - * @return const wxString& - the short netname - */ - const wxString& GetShortNetname() const { return m_ShortNetname; } - /** * Function GetShape * @return the shape of this pad. @@ -475,10 +451,6 @@ private: int m_boundingRadius; ///< radius of the circle containing the pad shape - - wxString m_Netname; ///< Full net name like /mysheet/mysubsheet/vout used by Eeschema - wxString m_ShortNetname; ///< short net name, like vout from /mysheet/mysubsheet/vout - /// Pad name (4 char) or a long identifier (used in pad name /// comparisons because this is faster than string comparison) union diff --git a/pcbnew/class_pad_draw_functions.cpp b/pcbnew/class_pad_draw_functions.cpp index c590d55e99..346a4980e6 100644 --- a/pcbnew/class_pad_draw_functions.cpp +++ b/pcbnew/class_pad_draw_functions.cpp @@ -473,7 +473,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) GRSetDrawMode( aDC, aDrawInfo.m_DrawMode ); // Draw "No connect" ( / or \ or cross X ) if necessary - if( m_Netname.IsEmpty() && aDrawInfo.m_ShowNCMark ) + if( GetNet() == 0 && aDrawInfo.m_ShowNCMark ) { int dx0 = std::min( halfsize.x, halfsize.y ); EDA_COLOR_T nc_color = BLUE; @@ -499,7 +499,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) wxPoint tpos0 = shape_pos; // Position of the centre of text wxPoint tpos = tpos0; wxSize AreaSize; // size of text area, normalized to AreaSize.y < AreaSize.x - int shortname_len = m_ShortNetname.Len(); + int shortname_len = GetShortNetname().Len(); if( !aDrawInfo.m_Display_netname ) shortname_len = 0; @@ -583,7 +583,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) tsize = ( tsize * 7 ) / 10; DrawGraphicHaloText( clipBox, aDC, tpos, aDrawInfo.m_Color, BLACK, WHITE, - m_ShortNetname, t_angle, + GetShortNetname(), t_angle, wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false ); } diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 7dc306a063..ae1e93036f 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -151,7 +151,8 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP m_parent = aParent; m_currentPad = aPad; m_board = m_parent->GetBoard(); - m_dummyPad = new D_PAD( (MODULE*) NULL ); + m_dummyPad = new D_PAD( aPad->GetParent() ); + m_padMaster.SetParent( aPad->GetParent() ); if( aPad ) m_dummyPad->Copy( aPad ); @@ -809,25 +810,16 @@ void DIALOG_PAD_PROPERTIES::PadPropertiesAccept( wxCommandEvent& event ) m_currentPad->SetPadName( m_padMaster.GetPadName() ); - if( m_currentPad->GetNetname() != m_padMaster.GetNetname() ) + if( m_currentPad->GetNetname() != m_PadNetNameCtrl->GetValue() ) { - if( m_padMaster.GetNetname().IsEmpty() ) + if( !m_PadNetNameCtrl->GetValue().IsEmpty() && m_padMaster.GetNet() == 0 ) { - rastnestIsChanged = true; - m_currentPad->SetNet( 0 ); - m_currentPad->SetNetname( wxEmptyString ); + DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); } else { - const NETINFO_ITEM* net = m_board->FindNet( m_padMaster.GetNetname() ); - if( net ) - { - rastnestIsChanged = true; - m_currentPad->SetNetname( m_padMaster.GetNetname() ); - m_currentPad->SetNet( net->GetNet() ); - } - else - DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); + rastnestIsChanged = true; + m_currentPad->SetNet( m_padMaster.GetNet() ); } } @@ -986,7 +978,13 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) msg = m_PadNumCtrl->GetValue().Left( 4 ); aPad->SetPadName( msg ); - aPad->SetNetname( m_PadNetNameCtrl->GetValue() ); + + // Check if user has set an existing net name + const NETINFO_ITEM* netinfo = m_board->FindNet( m_PadNetNameCtrl->GetValue() ); + if( netinfo != NULL ) + aPad->SetNet( netinfo->GetNet() ); + else + aPad->SetNet( 0 ); // Clear some values, according to the pad type and shape switch( aPad->GetShape() ) @@ -1034,7 +1032,7 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) // no offset, no net name, no pad name allowed aPad->SetOffset( wxPoint( 0, 0 ) ); aPad->SetPadName( wxEmptyString ); - aPad->SetNetname( wxEmptyString ); + aPad->SetNet( 0 ); break; default: diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 80b2fe78c5..6fec2fbdb2 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -1696,7 +1696,6 @@ void EAGLE_PLUGIN::loadElements( CPTREE& aElements ) if( ni != m_pads_to_nets.end() ) { const ENET* enet = &ni->second; - pad->SetNetname( FROM_UTF8( enet->netname.c_str() ) ); pad->SetNet( enet->netcode ); } } diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index ab5a4fe34f..532750329c 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -1303,7 +1303,7 @@ void LEGACY_PLUGIN::loadPAD( MODULE* aModule ) // read Netname ReadDelimitedText( buf, data, sizeof(buf) ); - pad->SetNetname( FROM_UTF8( StrPurge( buf ) ) ); + assert( m_board->FindNet( netcode )->GetNetname() == FROM_UTF8( StrPurge( buf ) ) ); } else if( TESTLINE( "Po" ) ) // (Po)sition diff --git a/pcbnew/pad_edition_functions.cpp b/pcbnew/pad_edition_functions.cpp index 3e890af710..839d1f39fc 100644 --- a/pcbnew/pad_edition_functions.cpp +++ b/pcbnew/pad_edition_functions.cpp @@ -141,7 +141,6 @@ void PCB_BASE_FRAME::AddPad( MODULE* aModule, bool draw ) // Update the pad properties. Import_Pad_Settings( pad, false ); - pad->SetNetname( wxEmptyString ); pad->SetNet( 0 ); pad->SetPosition( GetCrossHairPosition() ); diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb.cpp index 39a65ebf33..6afde99801 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb.cpp @@ -914,17 +914,17 @@ void PCB::AddToBoard() m_board->SetCopperLayerCount( m_layersStackup.GetCount() ); - for( i = 0; i < (int) m_pcbComponents.GetCount(); i++ ) - { - m_pcbComponents[i]->AddToBoard(); - } - for( i = 0; i < (int) m_pcbNetlist.GetCount(); i++ ) { net = m_pcbNetlist[i]; m_board->AppendNet( new NETINFO_ITEM( m_board, net->m_name, net->m_netCode ) ); } + + for( i = 0; i < (int) m_pcbComponents.GetCount(); i++ ) + { + m_pcbComponents[i]->AddToBoard(); + } } } // namespace PCAD2KICAD diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp index 4ec4338efa..c3cd2e34af 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp @@ -273,8 +273,16 @@ void PCB_PAD::AddToModule( MODULE* aModule, int aRotation, bool aEncapsulatedPad pad->SetAttribute( padType ); - pad->SetNet( 0 ); - pad->SetNetname( m_net ); + // Set the proper net code + NETINFO_ITEM* netinfo = m_board->FindNet( m_net ); + if( netinfo == NULL ) // I believe this should not happen, but just in case + { + // It is a new net + netinfo = new NETINFO_ITEM( m_board, m_net, m_board->GetNetCount() ); + m_board->AppendNet( netinfo ); + } + + pad->SetNet( netinfo->GetNet() ); } if( !aEncapsulatedPad ) diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index f1eaa3026c..b25251a5db 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2191,7 +2191,7 @@ D_PAD* PCB_PARSER::parseD_PAD() throw( IO_ERROR, PARSE_ERROR ) case T_net: pad->SetNet( parseInt( "net number" ) ); NeedSYMBOLorNUMBER(); - pad->SetNetname( FromUTF8() ); + assert( FromUTF8() == m_board->FindNet( pad->GetNet() )->GetNetname() ); NeedRIGHT(); break; diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index a4ce86869f..e983a0d6ee 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -455,17 +455,13 @@ void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, // Update pad netnames ( when possible) for( D_PAD* pad = aNewModule->Pads(); pad != NULL; pad = pad->Next() ) { - pad->SetNetname( wxEmptyString ); pad->SetNet( 0 ); D_PAD* old_pad = aOldModule->Pads(); for( ; old_pad != NULL; old_pad = old_pad->Next() ) { if( pad->PadNameEqual( old_pad ) ) - { - pad->SetNetname( old_pad->GetNetname() ); pad->SetNet( old_pad->GetNet() ); - } } } From 78732f13f7d2f670fd16dbe12382b9c6d7260036 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 14 Jan 2014 11:41:06 +0100 Subject: [PATCH 42/84] Removed: - ZONE_CONTAINER::m_Netname field - ZONE_CONTAINER::SetNetName() - ZONE_CONTAINER::SetNet() [it uses the one in BOARD_CONNECTED_ITEM] - ZONE_CONTAINER::GetNetName() [instead BOARD_CONNECTED_ITEM::GetNetname is used] - ZONE_CONTAINER::SetNetNameFromNetCode() Performed tests: - Drawn a zone that belongs to a net, then modified schematics so the net does not exist anymore. After reloading the net list, all pads/tracks are updated. Zones still belongs to the net that does not exist in the schematic (but still exists in .kicad_pcb file). After running DRC, the zone becomes not filled. - Undo & redo affects assignment of a polygon to a specific net (you may change net of a polygon, refill it and undo/redo the changes). --- pcbnew/class_board.cpp | 4 +- pcbnew/class_zone.cpp | 43 +-------------------- pcbnew/class_zone.h | 26 ------------- pcbnew/eagle_plugin.cpp | 5 --- pcbnew/kicad_plugin.cpp | 2 +- pcbnew/legacy_plugin.cpp | 16 +++----- pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp | 1 - pcbnew/pcb_parser.cpp | 7 +--- pcbnew/specctra_export.cpp | 2 +- pcbnew/zones_by_polygon.cpp | 4 +- pcbnew/zones_by_polygon_fill_functions.cpp | 4 +- pcbnew/zones_functions_for_undo_redo.cpp | 2 +- 12 files changed, 18 insertions(+), 98 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index dfcebd69e8..af7cc3e4f0 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -1535,7 +1535,7 @@ int BOARD::SetAreasNetCodesFromNetNames( void ) if( GetArea( ii )->GetNet() != 0 ) // i.e. if this zone is connected to a net { - const NETINFO_ITEM* net = FindNet( GetArea( ii )->GetNetName() ); + const NETINFO_ITEM* net = FindNet( GetArea( ii )->GetNetname() ); if( net ) { @@ -2720,7 +2720,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, " has non-existent net name \"%s\" **\n" ), GetChars( coord ), GetChars( zone->GetLayerName() ), - GetChars( zone->GetNetName() ) ); + GetChars( zone->GetNetname() ) ); aReporter->Report( msg ); } } diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index b1d8405c81..941f95f3b5 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -138,31 +138,6 @@ const wxPoint& ZONE_CONTAINER::GetPosition() const } -void ZONE_CONTAINER::SetNet( int aNetCode ) -{ - BOARD_CONNECTED_ITEM::SetNet( aNetCode ); - - if( aNetCode < 0 ) - return; - - BOARD* board = GetBoard(); - - if( board ) - { - NETINFO_ITEM* net = board->FindNet( aNetCode ); - - if( net ) - m_Netname = net->GetNetname(); - else - m_Netname.Empty(); - } - else - { - m_Netname.Empty(); - } -} - - void ZONE_CONTAINER::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset ) { @@ -658,7 +633,7 @@ void ZONE_CONTAINER::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) else // a netcode < 0 is an error { msg = wxT( " [" ); - msg << m_Netname + wxT( "]" ); + msg << GetNetname() + wxT( "]" ); msg << wxT( " <" ) << _( "Not Found" ) << wxT( ">" ); } @@ -849,20 +824,6 @@ void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src ) } -bool ZONE_CONTAINER::SetNetNameFromNetCode( void ) -{ - NETINFO_ITEM* net; - - if( m_Parent && ( net = ( (BOARD*) m_Parent )->FindNet( GetNet() ) ) ) - { - m_Netname = net->GetNetname(); - return true; - } - - return false; -} - - ZoneConnection ZONE_CONTAINER::GetPadConnection( D_PAD* aPad ) const { if( aPad == NULL || aPad->GetZoneConnection() == UNDEFINED_CONNECTION ) @@ -928,7 +889,7 @@ wxString ZONE_CONTAINER::GetSelectMenuText() const else { // A netcode < 0 is an error: // Netname not found or area not initialised - text << wxT( " [" ) << m_Netname << wxT( "]" ); + text << wxT( " [" ) << GetNetname() << wxT( "]" ); text << wxT( " <" ) << _( "Not Found" ) << wxT( ">" ); } } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 513859b9d8..6423d85396 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -186,31 +186,6 @@ public: return ( GetLayer() < FIRST_NON_COPPER_LAYER ) ? true : false; } - /** - * Function SetNet - * sets the netcode and the netname. - * - * @param aNetCode The net code of the zone container if greater than or equal to - * zero. Otherwise the current net code is kept and set the net - * code error flag. - */ - virtual void SetNet( int aNetCode ); - - /** - * Function SetNetNameFromNetCode - * Find the net name corresponding to the net code. - * @return bool - true if net found, else false - */ - bool SetNetNameFromNetCode( void ); - - /** - * Function GetNetName - * returns the net name. - * @return const wxString& - The net name. - */ - const wxString& GetNetName() const { return m_Netname; }; - void SetNetName( const wxString& aName ) { m_Netname = aName; } - /// How to fill areas: 0 = use filled polygons, 1 => fill with segments. void SetFillMode( int aFillMode ) { m_FillMode = aFillMode; } int GetFillMode() const { return m_FillMode; } @@ -607,7 +582,6 @@ public: private: CPolyLine* m_Poly; ///< Outline of the zone. - wxString m_Netname; ///< Name of the net assigned to the zone. CPolyLine* m_smoothedPoly; // Corner-smoothed version of m_Poly int m_cornerSmoothingType; unsigned int m_cornerRadius; diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 6fec2fbdb2..14405e9753 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -2259,7 +2259,6 @@ void EAGLE_PLUGIN::packageHole( MODULE* aModule, CPTREE& aTree ) const // no offset, no net name, no pad name allowed // pad->SetOffset( wxPoint( 0, 0 ) ); // pad->SetPadName( wxEmptyString ); - // pad->SetNetname( wxEmptyString ); wxPoint padpos( kicad_x( e.x ), kicad_y( e.y ) ); @@ -2496,7 +2495,6 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) zone->SetTimeStamp( timeStamp( it->second ) ); zone->SetLayer( layer ); zone->SetNet( netCode ); - zone->SetNetName( netName ); CPolyLine::HATCH_STYLE outline_hatch = CPolyLine::DIAGONAL_EDGE; @@ -2552,10 +2550,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) // KiCad does not support an unconnected zone with its own non-zero netcode, // but only when assigned netcode = 0 w/o a name... for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it ) - { (*it)->SetNet( 0 ); - (*it)->SetNetName( wxEmptyString ); - } // therefore omit this signal/net. } diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index d18c32edaa..ed6d7c062e 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -1406,7 +1406,7 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const // (perhaps netcode and netname should be not stored) m_out->Print( aNestLevel, "(zone (net %d) (net_name %s)", aZone->GetIsKeepout() ? 0 : aZone->GetNet(), - m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetName() ).c_str() ); + m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() ); formatLayer( aZone ); diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 532750329c..ade83543f1 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2238,7 +2238,6 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() // the zone net name is the name read in file. // (When mismatch, the user will be prompted in DRC, to fix the actual name) zc->BOARD_CONNECTED_ITEM::SetNet( netcode ); - zc->SetNetName( FROM_UTF8( buf ) ); // init the net name here } else if( TESTLINE( "ZLayer" ) ) // layer found @@ -2255,7 +2254,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() if( !hopt ) { - m_error.Printf( wxT( "Bad ZAux for CZONE_CONTAINER '%s'" ), zc->GetNetName().GetData() ); + m_error.Printf( wxT( "Bad ZAux for CZONE_CONTAINER '%s'" ), zc->GetNetname().GetData() ); THROW_IO_ERROR( m_error ); } @@ -2266,7 +2265,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() case 'F': outline_hatch = CPolyLine::DIAGONAL_FULL; break; default: - m_error.Printf( wxT( "Bad ZAux for CZONE_CONTAINER '%s'" ), zc->GetNetName().GetData() ); + m_error.Printf( wxT( "Bad ZAux for CZONE_CONTAINER '%s'" ), zc->GetNetname().GetData() ); THROW_IO_ERROR( m_error ); } @@ -2283,7 +2282,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() if( smoothing >= ZONE_SETTINGS::SMOOTHING_LAST || smoothing < 0 ) { - m_error.Printf( wxT( "Bad ZSmoothing for CZONE_CONTAINER '%s'" ), zc->GetNetName().GetData() ); + m_error.Printf( wxT( "Bad ZSmoothing for CZONE_CONTAINER '%s'" ), zc->GetNetname().GetData() ); THROW_IO_ERROR( m_error ); } @@ -2358,7 +2357,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() default: m_error.Printf( wxT( "Bad ZClearance padoption for CZONE_CONTAINER '%s'" ), - zc->GetNetName().GetData() ); + zc->GetNetname().GetData() ); THROW_IO_ERROR( m_error ); } @@ -2422,10 +2421,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() // Ensure keepout does not have a net // (which have no sense for a keepout zone) if( zc->GetIsKeepout() ) - { - zc->SetNet(0); - zc->SetNetName( wxEmptyString ); - } + zc->SetNet( 0 ); // should always occur, but who knows, a zone without two corners // is no zone at all, it's a spot? @@ -3644,7 +3640,7 @@ void LEGACY_PLUGIN::saveZONE_CONTAINER( const ZONE_CONTAINER* me ) const fprintf( m_fp, "ZInfo %lX %d %s\n", me->GetTimeStamp(), me->GetIsKeepout() ? 0 : me->GetNet(), - EscapedUTF8( me->GetIsKeepout() ? wxT("") : me->GetNetName() ).c_str() ); + EscapedUTF8( me->GetIsKeepout() ? wxT("") : me->GetNetname() ).c_str() ); // Save the outline layer info fprintf( m_fp, "ZLayer %d\n", me->GetLayer() ); diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp index d64f626bf9..5fab0055e8 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp @@ -172,7 +172,6 @@ void PCB_POLYGON::AddToBoard() zone->SetTimeStamp( m_timestamp ); zone->SetLayer( m_KiCadLayer ); zone->SetNet( m_netCode ); - zone->SetNetName( m_net ); // add outline int outline_hatch = CPolyLine::DIAGONAL_EDGE; diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index b25251a5db..0fd7f55b64 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2423,7 +2423,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) case T_net_name: NeedSYMBOLorNUMBER(); - zone->SetNetName( FromUTF8() ); + assert( m_board->FindNet( zone->GetNet() )->GetNetname() == FromUTF8() ); NeedRIGHT(); break; @@ -2699,10 +2699,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) // Ensure keepout does not have a net (which have no sense for a keepout zone) if( zone->GetIsKeepout() ) - { - zone->SetNet(0); - zone->SetNetName( wxEmptyString ); - } + zone->SetNet( 0 ); return zone.release(); } diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index 535d6834fa..dee6c8be03 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -1557,7 +1557,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IO_ERROR ) plane->SetShape( mainPolygon ); - plane->name = TO_UTF8( item->GetNetName() ); + plane->name = TO_UTF8( item->GetNetname() ); if( plane->name.size() == 0 ) { diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 19dcfe5f2a..977fef6e29 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -550,7 +550,6 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode(); zone->SetNet( zoneInfo.m_NetcodeSelection ); - zone->SetNetNameFromNetCode( ); } double tmp = ZONE_THERMAL_RELIEF_GAP_MIL; wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp ); @@ -579,7 +578,6 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) // Netcode and netname are irrelevant, // so ensure they are cleared zone->SetNet( 0 ); - zone->SetNetName( wxEmptyString ); edited = InvokeKeepoutAreaEditor( this, &zoneInfo ); } else @@ -904,7 +902,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) NETINFO_ITEM* net = GetBoard()->FindNet( zoneInfo.m_NetcodeSelection ); if( net ) // net == NULL should not occur - aZone->SetNetName( net->GetNetname() ); + aZone->SetNet( net->GetNet() ); // Combine zones if possible GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone ); diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp index 61324cb6c7..73ca2a8217 100644 --- a/pcbnew/zones_by_polygon_fill_functions.cpp +++ b/pcbnew/zones_by_polygon_fill_functions.cpp @@ -103,7 +103,7 @@ int PCB_EDIT_FRAME::Fill_Zone( ZONE_CONTAINER* aZone ) zoneInfo.m_NetcodeSelection = aZone->GetNet(); SetZoneSettings( zoneInfo ); - msg = aZone->GetNetName(); + msg = aZone->GetNetname(); if( msg.IsEmpty() ) msg = wxT( "No net" ); @@ -150,7 +150,7 @@ int PCB_EDIT_FRAME::Fill_All_Zones( wxWindow * aActiveWindow, bool aVerbose ) if( zoneContainer->GetIsKeepout() ) continue; - msg.Printf( FORMAT_STRING, ii+1, areaCount, GetChars( zoneContainer->GetNetName() ) ); + msg.Printf( FORMAT_STRING, ii + 1, areaCount, GetChars( zoneContainer->GetNetname() ) ); if( progressDialog ) { diff --git a/pcbnew/zones_functions_for_undo_redo.cpp b/pcbnew/zones_functions_for_undo_redo.cpp index 52166bc5db..8abd5b6306 100644 --- a/pcbnew/zones_functions_for_undo_redo.cpp +++ b/pcbnew/zones_functions_for_undo_redo.cpp @@ -67,7 +67,7 @@ bool ZONE_CONTAINER::IsSame( const ZONE_CONTAINER& aZoneToCompare ) if( GetLayer() != aZoneToCompare.GetLayer() ) return false; - if( m_Netname != aZoneToCompare.m_Netname ) + if( GetNet() != aZoneToCompare.GetNet() ) return false; if( GetPriority() != aZoneToCompare.GetPriority() ) From 3017b617118a4fccc7e59763af3f279a647333fa Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 15 Jan 2014 09:34:16 +0100 Subject: [PATCH 43/84] Added NETINFO_LIST::UNCONNECTED constant. --- pcbnew/class_board.cpp | 8 ++++---- pcbnew/class_netinfo.h | 3 +++ pcbnew/class_netinfolist.cpp | 3 +++ pcbnew/class_track.cpp | 4 ++-- pcbnew/connect.cpp | 2 +- pcbnew/eagle_plugin.cpp | 4 ++-- pcbnew/legacy_plugin.cpp | 4 ++-- pcbnew/pad_edition_functions.cpp | 2 +- pcbnew/pcb_parser.cpp | 4 ++-- pcbnew/ratsnest.cpp | 2 +- pcbnew/xchgmod.cpp | 2 +- pcbnew/zones_by_polygon.cpp | 2 +- 12 files changed, 23 insertions(+), 17 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index af7cc3e4f0..416044cc5d 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -1529,7 +1529,7 @@ int BOARD::SetAreasNetCodesFromNetNames( void ) { if( !GetArea( ii )->IsOnCopperLayer() ) { - GetArea( ii )->SetNet( 0 ); + GetArea( ii )->SetNet( NETINFO_LIST::UNCONNECTED ); continue; } @@ -2546,7 +2546,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, } if( !aNetlist.IsDryRun() ) - pad->SetNet( 0 ); + pad->SetNet( NETINFO_LIST::UNCONNECTED ); } } else // Footprint pad has a net. @@ -2649,7 +2649,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, aReporter->Report( msg ); } - previouspad->SetNet( 0 ); + previouspad->SetNet( NETINFO_LIST::UNCONNECTED ); } netname = pad->GetNetname(); count = 1; @@ -2662,7 +2662,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, // Examine last pad if( pad && count == 1 ) - pad->SetNet( 0 ); + pad->SetNet( NETINFO_LIST::UNCONNECTED ); } // Last step: Some tests: diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index c0e81a684e..8ea47c3676 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -199,6 +199,9 @@ public: return NULL; } + ///> Constant that holds the unconnected net number + static const int UNCONNECTED; + #if defined(DEBUG) void Show() const; #endif diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index 561e845e21..590cd352ce 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -162,3 +162,6 @@ void NETINFO_LIST::buildPadsFullList() m_Parent->m_Status_Pcb = LISTE_PAD_OK; } + + +const int NETINFO_LIST::UNCONNECTED = 0; diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index 21cca65517..89c52bb9f9 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -690,7 +690,7 @@ void TRACK::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, if( aDC->LogicalToDeviceXRel( m_Width ) < MIN_TEXT_SIZE ) return; - if( GetNet() == 0 ) + if( GetNet() == NETINFO_LIST::UNCONNECTED ) return; NETINFO_ITEM* net = ( (BOARD*) GetParent() )->FindNet( GetNet() ); @@ -952,7 +952,7 @@ void SEGVIA::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, } // Display the short netname: - if( GetNet() == 0 ) + if( GetNet() == NETINFO_LIST::UNCONNECTED ) return; if( DisplayOpt.DisplayNetNamesMode == 0 || DisplayOpt.DisplayNetNamesMode == 1 ) diff --git a/pcbnew/connect.cpp b/pcbnew/connect.cpp index aa8d4867e6..1833bd0d65 100644 --- a/pcbnew/connect.cpp +++ b/pcbnew/connect.cpp @@ -842,7 +842,7 @@ void PCB_BASE_FRAME::RecalculateAllTracksNetcode() curr_track->end = NULL; curr_track->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, false ); curr_track->SetZoneSubNet( 0 ); - curr_track->SetNet( 0 ); // net code = 0 means not connected + curr_track->SetNet( NETINFO_LIST::UNCONNECTED ); } // If no pad, reset pointers and netcode, and do nothing else diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 14405e9753..cc60db125f 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -1493,7 +1493,7 @@ void EAGLE_PLUGIN::loadPlain( CPTREE& aGraphics ) zone->SetTimeStamp( timeStamp( gr->second ) ); zone->SetLayer( layer ); - zone->SetNet( 0 ); + zone->SetNet( NETINFO_LIST::UNCONNECTED ); CPolyLine::HATCH_STYLE outline_hatch = CPolyLine::DIAGONAL_EDGE; @@ -2550,7 +2550,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) // KiCad does not support an unconnected zone with its own non-zero netcode, // but only when assigned netcode = 0 w/o a name... for( ZONES::iterator it = zones.begin(); it != zones.end(); ++it ) - (*it)->SetNet( 0 ); + (*it)->SetNet( NETINFO_LIST::UNCONNECTED ); // therefore omit this signal/net. } diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index ade83543f1..8b09403302 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2421,7 +2421,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() // Ensure keepout does not have a net // (which have no sense for a keepout zone) if( zc->GetIsKeepout() ) - zc->SetNet( 0 ); + zc->SetNet( NETINFO_LIST::UNCONNECTED ); // should always occur, but who knows, a zone without two corners // is no zone at all, it's a spot? @@ -2431,7 +2431,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() if( !zc->IsOnCopperLayer() ) { zc->SetFillMode( 0 ); - zc->SetNet( 0 ); + zc->SetNet( NETINFO_LIST::UNCONNECTED ); } // Hatch here, after outlines corners are read diff --git a/pcbnew/pad_edition_functions.cpp b/pcbnew/pad_edition_functions.cpp index 839d1f39fc..e73e8d829a 100644 --- a/pcbnew/pad_edition_functions.cpp +++ b/pcbnew/pad_edition_functions.cpp @@ -141,7 +141,7 @@ void PCB_BASE_FRAME::AddPad( MODULE* aModule, bool draw ) // Update the pad properties. Import_Pad_Settings( pad, false ); - pad->SetNet( 0 ); + pad->SetNet( NETINFO_LIST::UNCONNECTED ); pad->SetPosition( GetCrossHairPosition() ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 0fd7f55b64..b05ce179f2 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2687,7 +2687,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) if( !zone->IsOnCopperLayer() ) { zone->SetFillMode( 0 ); - zone->SetNet( 0 ); + zone->SetNet( NETINFO_LIST::UNCONNECTED ); } // Set hatch here, after outlines corners are read @@ -2699,7 +2699,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) // Ensure keepout does not have a net (which have no sense for a keepout zone) if( zone->GetIsKeepout() ) - zone->SetNet( 0 ); + zone->SetNet( NETINFO_LIST::UNCONNECTED ); return zone.release(); } diff --git a/pcbnew/ratsnest.cpp b/pcbnew/ratsnest.cpp index b5347d3e85..32dba7213d 100644 --- a/pcbnew/ratsnest.cpp +++ b/pcbnew/ratsnest.cpp @@ -540,7 +540,7 @@ void PCB_BASE_FRAME::build_ratsnest_module( MODULE* aModule ) // collect active pads of the module: for( pad_ref = aModule->Pads(); pad_ref != NULL; pad_ref = pad_ref->Next() ) { - if( pad_ref->GetNet() == 0 ) + if( pad_ref->GetNet() == NETINFO_LIST::UNCONNECTED ) continue; localPadList.push_back( pad_ref ); diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index e983a0d6ee..af46b91592 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -455,7 +455,7 @@ void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, // Update pad netnames ( when possible) for( D_PAD* pad = aNewModule->Pads(); pad != NULL; pad = pad->Next() ) { - pad->SetNet( 0 ); + pad->SetNet( NETINFO_LIST::UNCONNECTED ); D_PAD* old_pad = aOldModule->Pads(); for( ; old_pad != NULL; old_pad = old_pad->Next() ) diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 977fef6e29..9eddd5f7bb 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -577,7 +577,7 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) zoneInfo.SetIsKeepout( true ); // Netcode and netname are irrelevant, // so ensure they are cleared - zone->SetNet( 0 ); + zone->SetNet( NETINFO_LIST::UNCONNECTED ); edited = InvokeKeepoutAreaEditor( this, &zoneInfo ); } else From d62b47a0dfe59bfe0e5722c8375a1e8fbf0d37ea Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 15 Jan 2014 18:03:06 +0100 Subject: [PATCH 44/84] BOARD_CONNECTED_ITEMs do not store net code anymore (m_NetCode field), instead net info is stored using a pointer to NETINFO_ITEM. GetNet() refers to the net code stored in the NETINFO_ITEM. SetNet() finds an appropriate NETINFO_ITEM and uses it. Removing GetNet() & SetNet() (and the whole net code idea) requires too many changes in the code (~250 references to the mentioned functions). BOARD_CONNECTED_ITEMs by default get a pointer to NETINFO_ITEM that stores unconnected items. This requires for all BOARD_CONNECTED_ITEMs to have a parent (so BOARD* is accessible). The only orphaned item is BOARD_DESIGN_SETTINGS::m_Pad_Master, but it does not cause any issues so far. Items that do not have access to a BOARD (do not have set parents) and therefore cannot get net assigned, by default get const static NETINFO_LIST::ORPHANED. Performed tests: - loaded .kicad_pcb, KiCad legacy board, Eagle 6.0 board, P-CAD board - all ok - load a simple project, reload netlist after changing connections in eeschema - ok - save & reload a board - ok, but still contain empty nets - remove everything, restore with undo - ok - remove everything, reload netlist - ok - changing net names (all possibilites: empty->existing, empty->not existing, existing->empty, existing->not existing) - all ok - zones: when net is changed to a net that does not have any nodes besides the zone itself, it does not get filled --- include/class_board_item.h | 3 +- pcbnew/class_board.cpp | 3 +- pcbnew/class_board_connected_item.cpp | 38 ++++++++++++++++++-------- pcbnew/class_board_connected_item.h | 26 ++++++++++-------- pcbnew/class_board_design_settings.cpp | 2 +- pcbnew/class_netinfo.h | 4 +++ pcbnew/class_netinfolist.cpp | 1 + pcbnew/class_zone.cpp | 1 - pcbnew/eagle_plugin.cpp | 5 ++-- pcbnew/pcb_parser.cpp | 6 ++-- pcbnew/pcb_parser.h | 2 +- 11 files changed, 57 insertions(+), 34 deletions(-) diff --git a/include/class_board_item.h b/include/class_board_item.h index 6f6bf201d6..b6e5e905a6 100644 --- a/include/class_board_item.h +++ b/include/class_board_item.h @@ -83,8 +83,7 @@ protected: public: BOARD_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ) : - EDA_ITEM( aParent, idtype ) - , m_Layer( FIRST_LAYER ) + EDA_ITEM( aParent, idtype ), m_Layer( FIRST_LAYER ) { } diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 416044cc5d..691e379cc7 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2571,7 +2571,8 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, if( netinfo == NULL ) { // It is a new net, we have to add it - netinfo = new NETINFO_ITEM( this, net.GetNetName(), m_NetInfo.GetNetCount() ); + netinfo = new NETINFO_ITEM( this, net.GetNetName(), + m_NetInfo.GetNetCount() ); m_NetInfo.AppendNet( netinfo ); } diff --git a/pcbnew/class_board_connected_item.cpp b/pcbnew/class_board_connected_item.cpp index cf44e1dc7a..69bcfacb7e 100644 --- a/pcbnew/class_board_connected_item.cpp +++ b/pcbnew/class_board_connected_item.cpp @@ -34,34 +34,50 @@ #include #include - BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ) : - BOARD_ITEM( aParent, idtype ), m_NetCode( 0 ), m_Subnet( 0 ), m_ZoneSubnet( 0 ) + BOARD_ITEM( aParent, idtype ), m_Subnet( 0 ), m_ZoneSubnet( 0 ), + m_netinfo( &NETINFO_LIST::ORPHANED ) { + // The unconnected is set only in case the item belongs to a BOARD + SetNet( NETINFO_LIST::UNCONNECTED ); } BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem ) : - BOARD_ITEM( aItem ), m_NetCode( aItem.m_NetCode ), m_Subnet( aItem.m_Subnet ), - m_ZoneSubnet( aItem.m_ZoneSubnet ) + BOARD_ITEM( aItem ), m_Subnet( aItem.m_Subnet ), m_ZoneSubnet( aItem.m_ZoneSubnet ), + m_netinfo( aItem.m_netinfo ) { } +int BOARD_CONNECTED_ITEM::GetNet() const +{ + return m_netinfo->GetNet(); +} + + +void BOARD_CONNECTED_ITEM::SetNet( int aNetCode ) +{ + BOARD* board = GetBoard(); + if( board ) + { + m_netinfo = board->FindNet( aNetCode ); + + if( m_netinfo == NULL ) + m_netinfo = board->FindNet( NETINFO_LIST::UNCONNECTED ); + } +} + + const wxString& BOARD_CONNECTED_ITEM::GetNetname() const { - BOARD* board = GetBoard(); - NETINFO_ITEM* netinfo = board->FindNet( m_NetCode ); - - return netinfo->GetNetname(); + return m_netinfo->GetNetname(); } const wxString& BOARD_CONNECTED_ITEM::GetShortNetname() const { - NETINFO_ITEM* netinfo = GetBoard()->FindNet( m_NetCode ); - - return netinfo->GetShortNetname(); + return m_netinfo->GetShortNetname(); } diff --git a/pcbnew/class_board_connected_item.h b/pcbnew/class_board_connected_item.h index 9b2f5df7b8..b7a059c9f4 100644 --- a/pcbnew/class_board_connected_item.h +++ b/pcbnew/class_board_connected_item.h @@ -33,6 +33,7 @@ #include +class NETINFO_ITEM; class NETCLASS; class TRACK; class D_PAD; @@ -54,8 +55,6 @@ public: std::vector m_PadsConnected; // list of other pads connected to me private: - int m_NetCode; // Net number - int m_Subnet; /* In rastnest routines : for the current net, block number * (number common to the current connected items found) */ @@ -63,6 +62,9 @@ private: int m_ZoneSubnet; // used in rastnest computations : for the current net, // handle cluster number in zone connection + /// Stores all informations about the net that item belongs to + const NETINFO_ITEM* m_netinfo; + public: BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ); @@ -72,15 +74,15 @@ public: * Function GetNet * @return int - the net code. */ - int GetNet() const - { - return m_NetCode; - } + int GetNet() const; - virtual void SetNet( int aNetCode ) - { - m_NetCode = aNetCode; - } + /** + * Function SetNet + * sets net using a net code. + * @param aNetCode is a net code for the new net. It has to exist in NETINFO_LIST held by BOARD. + * Otherwise, item is assigned to the unconnected net. + */ + void SetNet( int aNetCode ); /** * Function GetSubNet @@ -112,13 +114,13 @@ public: /** * Function GetNetname - * @return const wxString& - the full netname + * @return wxString - the full netname */ const wxString& GetNetname() const; /** * Function GetShortNetname - * @return const wxString& - the short netname + * @return wxString - the short netname */ const wxString& GetShortNetname() const; diff --git a/pcbnew/class_board_design_settings.cpp b/pcbnew/class_board_design_settings.cpp index e98dc81ef1..a24e6bf94e 100644 --- a/pcbnew/class_board_design_settings.cpp +++ b/pcbnew/class_board_design_settings.cpp @@ -52,7 +52,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() : - m_Pad_Master( 0 ) + m_Pad_Master( NULL ) { m_EnabledLayers = ALL_LAYERS; // All layers enabled at first. // SetCopperLayerCount() will adjust this. diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index 8ea47c3676..3e836d0b95 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -202,6 +202,10 @@ public: ///> Constant that holds the unconnected net number static const int UNCONNECTED; + ///> NETINFO_ITEM meaning that there was no net assigned for an item, as there was no + ///> board storing net list available. + static const NETINFO_ITEM ORPHANED; + #if defined(DEBUG) void Show() const; #endif diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index 590cd352ce..e2f16a014b 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -164,4 +164,5 @@ void NETINFO_LIST::buildPadsFullList() } +const NETINFO_ITEM NETINFO_LIST::ORPHANED = NETINFO_ITEM( NULL, wxString( "orphaned" ), -1 ); const int NETINFO_LIST::UNCONNECTED = 0; diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 941f95f3b5..cf5ab48ff7 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -53,7 +53,6 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD* aBoard ) : BOARD_CONNECTED_ITEM( aBoard, PCB_ZONE_AREA_T ) { - SetNet( -1 ); // Net number for fast comparisons m_CornerSelection = -1; m_IsFilled = false; // fill status : true when the zone is filled m_FillMode = 0; // How to fill areas: 0 = use filled polygons, != 0 fill with segments diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index cc60db125f..078600f081 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -1879,7 +1879,7 @@ void EAGLE_PLUGIN::orientModuleText( MODULE* m, const EELEMENT& e, MODULE* EAGLE_PLUGIN::makeModule( CPTREE& aPackage, const string& aPkgName ) const { - std::auto_ptr m( new MODULE( NULL ) ); + std::auto_ptr m( new MODULE( m_board ) ); m->SetFPID( FPID( aPkgName ) ); @@ -2351,6 +2351,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) const string& nname = net->second.get( ".name" ); wxString netName = FROM_UTF8( nname.c_str() ); + m_board->AppendNet( new NETINFO_ITEM( m_board, netName, netCode ) ); m_xpath->Value( nname.c_str() ); @@ -2555,7 +2556,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) // therefore omit this signal/net. } else - m_board->AppendNet( new NETINFO_ITEM( m_board, netName, netCode++ ) ); + netCode++; } m_xpath->pop(); // "signals.signal" diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index b05ce179f2..db9ed25acf 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -1731,7 +1731,7 @@ MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments ) throw( IO_ERR case T_pad: { - D_PAD* pad = parseD_PAD(); + D_PAD* pad = parseD_PAD( module.get() ); wxPoint pt = pad->GetPos0(); RotatePoint( &pt, module->GetOrientation() ); pad->SetPosition( pt + module->GetPosition() ); @@ -2011,14 +2011,14 @@ EDGE_MODULE* PCB_PARSER::parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ) } -D_PAD* PCB_PARSER::parseD_PAD() throw( IO_ERROR, PARSE_ERROR ) +D_PAD* PCB_PARSER::parseD_PAD( MODULE* aParent ) throw( IO_ERROR, PARSE_ERROR ) { wxCHECK_MSG( CurTok() == T_pad, NULL, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) ); wxSize sz; wxPoint pt; - std::auto_ptr< D_PAD > pad( new D_PAD( NULL ) ); + std::auto_ptr< D_PAD > pad( new D_PAD( aParent ) ); NeedSYMBOLorNUMBER(); pad->SetPadName( FromUTF8() ); diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h index 233acb1291..0dfb0bbdc5 100644 --- a/pcbnew/pcb_parser.h +++ b/pcbnew/pcb_parser.h @@ -99,7 +99,7 @@ class PCB_PARSER : public PCB_LEXER MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ) throw( IO_ERROR, PARSE_ERROR ); TEXTE_MODULE* parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR ); EDGE_MODULE* parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR ); - D_PAD* parseD_PAD() throw( IO_ERROR, PARSE_ERROR ); + D_PAD* parseD_PAD( MODULE* aParent = NULL ) throw( IO_ERROR, PARSE_ERROR ); TRACK* parseTRACK() throw( IO_ERROR, PARSE_ERROR ); SEGVIA* parseSEGVIA() throw( IO_ERROR, PARSE_ERROR ); ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ); From 8a4e7235049cd5a7f16058dbd4c5afb5b730eb5d Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 16 Jan 2014 14:20:51 +0100 Subject: [PATCH 45/84] NETINFO_ITEMs are not stored in a vector anymore, instead they are held in a unordered_map. Now, the net codes may be not consecutive. There is another way for assigning net codes (using a static int that holds a possible empty net code and a function that makes sure it is not used [getFreeNetCode()]). Removed some unused fields (NETINFO_ITEM::m_NbNodes, m_NbLink, m_NbNoconn, m_Flag). --- pcbnew/class_board.cpp | 3 +- pcbnew/class_netinfo.h | 46 ++++++++++++++----------- pcbnew/class_netinfo_item.cpp | 4 --- pcbnew/class_netinfolist.cpp | 34 +++++++++++++----- pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp | 2 +- 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 691e379cc7..acde874db3 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2571,8 +2571,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, if( netinfo == NULL ) { // It is a new net, we have to add it - netinfo = new NETINFO_ITEM( this, net.GetNetName(), - m_NetInfo.GetNetCount() ); + netinfo = new NETINFO_ITEM( this, net.GetNetName() ); m_NetInfo.AppendNet( netinfo ); } diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index 3e836d0b95..34f38188ae 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -34,7 +34,6 @@ #define __CLASSES_NETINFO__ -#include #include #include #include @@ -132,14 +131,16 @@ public: /** * Function GetItem - * @param aNetcode = netcode to identify a given NETINFO_ITEM - * @return NETINFO_ITEM* - by \a aNetcode, or NULL if not found + * @param aNetCode = netcode to identify a given NETINFO_ITEM + * @return NETINFO_ITEM* - by \a aNetCode, or NULL if not found */ - NETINFO_ITEM* GetNetItem( int aNetcode ) const + NETINFO_ITEM* GetNetItem( int aNetCode ) const { - if( unsigned( aNetcode ) >= GetNetCount() ) // catches < 0 too - return NULL; - return m_NetBuffer[aNetcode]; + NETCODES_MAP::const_iterator result = m_netCodes.find( aNetCode ); + if( result != m_netCodes.end() ) + return (*result).second; + + return NULL; } /** @@ -161,7 +162,7 @@ public: * @return the number of nets ( always >= 1 ) * because the first net is the "not connected" net and always exists */ - unsigned GetNetCount() const { return m_NetBuffer.size(); } + unsigned GetNetCount() const { return m_netNames.size(); } /** * Function Append @@ -211,9 +212,9 @@ public: #endif typedef boost::unordered_map NETNAMES_MAP; + typedef boost::unordered_map NETCODES_MAP; private: - /** * Function DeleteData * deletes the list of nets (and free memory) @@ -237,9 +238,20 @@ private: */ void buildPadsFullList(); + /** + * Function getFreeNetCode + * returns the first available net code that is not used by any other net. + */ + int getFreeNetCode() const; + BOARD* m_Parent; + NETNAMES_MAP m_netNames; ///< map for a fast look up by net names - std::vector m_NetBuffer; ///< net list (name, design constraints ..) + NETCODES_MAP m_netCodes; ///< map for a fast look up by net codes + + static int m_newNetCode; ///< number that has a *high* chance to be unused + ///< (to be sure, it is advised to use + ///< getFreeNetCode() function) std::vector m_PadsFullList; ///< contains all pads, sorted by pad's netname. ///< can be used in ratsnest calculations. @@ -252,6 +264,8 @@ private: */ class NETINFO_ITEM { + friend class NETINFO_LIST; + private: const int m_NetCode; ///< A number equivalent to the net name. ///< Used for fast comparisons in ratsnest and DRC computations. @@ -271,12 +285,6 @@ private: BOARD_ITEM* m_parent; ///< The parent board item object the net belongs to. public: - int m_NbNodes; // Pads count for this net - int m_NbLink; // Ratsnets count for this net - int m_NbNoconn; // Ratsnets remaining to route count - int m_Flag; // used in some calculations. Had no - // special meaning - std::vector m_PadInNetList; // List of pads connected to this net unsigned m_RatsnestStartIdx; /* Starting point of ratsnests of this @@ -287,7 +295,7 @@ public: unsigned m_RatsnestEndIdx; // Ending point of ratsnests of this net // (excluded) in this buffer - NETINFO_ITEM( BOARD_ITEM* aParent, const wxString& aNetName = wxEmptyString, int aNetCode = 0 ); + NETINFO_ITEM( BOARD_ITEM* aParent, const wxString& aNetName = wxEmptyString, int aNetCode = -1 ); ~NETINFO_ITEM(); /** @@ -446,10 +454,6 @@ public: { m_PadInNetList.clear(); - m_NbNodes = 0; - m_NbLink = 0; - m_NbNoconn = 0; - m_Flag = 0; m_RatsnestStartIdx = 0; // Starting point of ratsnests of this net in a // general buffer of ratsnest m_RatsnestEndIdx = 0; // Ending point of ratsnests of this net diff --git a/pcbnew/class_netinfo_item.cpp b/pcbnew/class_netinfo_item.cpp index 05bcabb1bc..1ca37ec3a1 100644 --- a/pcbnew/class_netinfo_item.cpp +++ b/pcbnew/class_netinfo_item.cpp @@ -53,10 +53,6 @@ NETINFO_ITEM::NETINFO_ITEM( BOARD_ITEM* aParent, const wxString& aNetName, int a m_NetCode( aNetCode ), m_Netname( aNetName ), m_ShortNetname( m_Netname.AfterLast( '/' ) ) { m_parent = aParent; - m_NbNodes = 0; - m_NbLink = 0; - m_NbNoconn = 0; - m_Flag = 0; m_RatsnestStartIdx = 0; // Starting point of ratsnests of this net in a // general buffer of ratsnest m_RatsnestEndIdx = 0; // Ending point of ratsnests of this net diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index e2f16a014b..4c5221f372 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -30,25 +30,29 @@ NETINFO_LIST::~NETINFO_LIST() void NETINFO_LIST::clear() { - for( unsigned ii = 0; ii < GetNetCount(); ii++ ) - delete m_NetBuffer[ii]; + NETNAMES_MAP::iterator it, itEnd; + for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it ) + delete it->second; - m_NetBuffer.clear(); m_PadsFullList.clear(); m_netNames.clear(); + m_netCodes.clear(); } void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement ) { + // negative net code means that it has to be auto assigned + if( aNewElement->m_NetCode < 0 ) + const_cast( aNewElement->m_NetCode ) = getFreeNetCode(); + // net names & codes are supposed to be unique assert( GetNetItem( aNewElement->GetNetname() ) == NULL ); assert( GetNetItem( aNewElement->GetNet() ) == NULL ); - m_NetBuffer.push_back( aNewElement ); - // add an entry for fast look up by a net name using a map m_netNames.insert( std::make_pair( aNewElement->GetNetname(), aNewElement ) ); + m_netCodes.insert( std::make_pair( aNewElement->GetNet(), aNewElement ) ); } @@ -115,11 +119,13 @@ void NETINFO_LIST::buildListOfNets() #if defined(DEBUG) void NETINFO_LIST::Show() const { - for( unsigned i=0; i < m_NetBuffer.size(); ++i ) + int i = 0; + NETNAMES_MAP::const_iterator it, itEnd; + for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it ) { printf( "[%d]: netcode:%d netname:<%s>\n", - i, m_NetBuffer[i]->GetNet(), - TO_UTF8( m_NetBuffer[i]->GetNetname() ) ); + i++, it->second->GetNet(), + TO_UTF8( it->second->GetNetname() ) ); } } #endif @@ -164,5 +170,17 @@ void NETINFO_LIST::buildPadsFullList() } +int NETINFO_LIST::getFreeNetCode() const +{ + do { + if( m_newNetCode < 0 ) + m_newNetCode = 0; + } while( m_netCodes.count( ++NETINFO_LIST::m_newNetCode ) != 0 ); + + return m_newNetCode; +} + + const NETINFO_ITEM NETINFO_LIST::ORPHANED = NETINFO_ITEM( NULL, wxString( "orphaned" ), -1 ); const int NETINFO_LIST::UNCONNECTED = 0; +int NETINFO_LIST::m_newNetCode = 0; diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp index c3cd2e34af..c5c05d849b 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp @@ -278,7 +278,7 @@ void PCB_PAD::AddToModule( MODULE* aModule, int aRotation, bool aEncapsulatedPad if( netinfo == NULL ) // I believe this should not happen, but just in case { // It is a new net - netinfo = new NETINFO_ITEM( m_board, m_net, m_board->GetNetCount() ); + netinfo = new NETINFO_ITEM( m_board, m_net ); m_board->AppendNet( netinfo ); } From af7520ccb9804234b5bab6dbb7c919afe160c396 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 16 Jan 2014 14:36:09 +0100 Subject: [PATCH 46/84] wxWidgets 2.8 fix --- pcbnew/class_netinfolist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index 4c5221f372..556ed1d3d7 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -181,6 +181,6 @@ int NETINFO_LIST::getFreeNetCode() const } -const NETINFO_ITEM NETINFO_LIST::ORPHANED = NETINFO_ITEM( NULL, wxString( "orphaned" ), -1 ); +const NETINFO_ITEM NETINFO_LIST::ORPHANED = NETINFO_ITEM( NULL, wxString::FromUTF8( "orphaned" ), -1 ); const int NETINFO_LIST::UNCONNECTED = 0; int NETINFO_LIST::m_newNetCode = 0; From 441e03172c58a7ebf1292fa5ef4a9e10637112d1 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 16 Jan 2014 16:47:31 +0100 Subject: [PATCH 47/84] Added iterators for NETINFO_LIST (as net codes for existing net codes may be not consecutive). --- pcbnew/class_board.cpp | 7 +++-- pcbnew/class_board.h | 18 +++++++++++ pcbnew/class_netclass.cpp | 38 ++++++++++++----------- pcbnew/class_netinfo.h | 60 ++++++++++++++++++++++++++++++++++++ pcbnew/class_netinfolist.cpp | 4 +-- pcbnew/kicad_plugin.cpp | 17 ++++++---- 6 files changed, 115 insertions(+), 29 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index acde874db3..5c435f634a 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -1440,10 +1440,11 @@ int BOARD::ReturnSortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCoun netBuffer.reserve( m_NetInfo.GetNetCount() ); - for( unsigned ii = 1; ii < m_NetInfo.GetNetCount(); ii++ ) + for( NETINFO_LIST::iterator net( m_NetInfo.begin() ), netEnd( m_NetInfo.end() ); + net != netEnd; ++net ) { - if( m_NetInfo.GetNetItem( ii )->GetNet() > 0 ) - netBuffer.push_back( m_NetInfo.GetNetItem( ii ) ); + if( net->GetNet() > 0 ) + netBuffer.push_back( *net ); } // sort the list diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index cd20413baa..c32d1d90e7 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -845,6 +845,24 @@ public: m_NetInfo.AppendNet( aNewNet ); } + /** + * Function BeginNets + * @return iterator to the first element of the NETINFO_ITEMs list + */ + NETINFO_LIST::iterator BeginNets() const + { + return m_NetInfo.begin(); + } + + /** + * Function EndNets + * @return iterator to the last element of the NETINFO_ITEMs list + */ + NETINFO_LIST::iterator EndNets() const + { + return m_NetInfo.end(); + } + /** * Function GetNetCount * @return the number of nets (NETINFO_ITEM) diff --git a/pcbnew/class_netclass.cpp b/pcbnew/class_netclass.cpp index f945963a95..655595a41d 100644 --- a/pcbnew/class_netclass.cpp +++ b/pcbnew/class_netclass.cpp @@ -203,12 +203,10 @@ void BOARD::SynchronizeNetsAndNetClasses() // set all NETs to the default NETCLASS, then later override some // as we go through the NETCLASSes. - int count = m_NetInfo.GetNetCount(); - for( int i=0; iSetClass( m_NetClasses.GetDefault() ); + net->SetClass( m_NetClasses.GetDefault() ); } // Add netclass name and pointer to nets. If a net is in more than one netclass, @@ -248,21 +246,18 @@ void BOARD::SynchronizeNetsAndNetClasses() m_NetClasses.GetDefault()->Clear(); - for( int i=0; iGetClassName(); + const wxString& classname = net->GetClassName(); - // because of the std:map<> this should be fast, and because of - // prior logic, netclass should not be NULL. - NETCLASS* netclass = m_NetClasses.Find( classname ); + // because of the std:map<> this should be fast, and because of + // prior logic, netclass should not be NULL. + NETCLASS* netclass = m_NetClasses.Find( classname ); - wxASSERT( netclass ); + wxASSERT( netclass ); - netclass->Add( net->GetNetname() ); - } + netclass->Add( net->GetNetname() ); } // D(printf("stop\n");) @@ -337,8 +332,15 @@ void NETCLASS::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControl aFormatter->Print( aNestLevel+1, "(uvia_dia %s)\n", FMT_IU( GetuViaDiameter() ).c_str() ); aFormatter->Print( aNestLevel+1, "(uvia_drill %s)\n", FMT_IU( GetuViaDrill() ).c_str() ); - for( NETCLASS::const_iterator it = begin(); it!= end(); ++it ) - aFormatter->Print( aNestLevel+1, "(add_net %s)\n", aFormatter->Quotew( *it ).c_str() ); + for( NETCLASS::const_iterator it = begin(); it != end(); ++it ) + { + NETINFO_ITEM* netinfo = m_Parent->FindNet( *it ); + + if( netinfo && netinfo->GetNodesCount() > 0 ) + { + aFormatter->Print( aNestLevel+1, "(add_net %s)\n", aFormatter->Quotew( *it ).c_str() ); + } + } aFormatter->Print( aNestLevel, ")\n\n" ); } diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index 34f38188ae..326a0fa3b4 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -214,6 +214,66 @@ public: typedef boost::unordered_map NETNAMES_MAP; typedef boost::unordered_map NETCODES_MAP; + ///> Wrapper class, so you can iterate through NETINFO_ITEM*s, not + ///> std::pair + class iterator + { + public: + iterator( NETNAMES_MAP::const_iterator aIter ) : m_iterator( aIter ) + { + } + + /// pre-increment operator + const iterator& operator++() + { + ++m_iterator; + + return *this; + } + + /// post-increment operator + iterator operator++( int ) + { + iterator ret = *this; + ++m_iterator; + + return ret; + } + + NETINFO_ITEM* operator*() const + { + return m_iterator->second; + } + + NETINFO_ITEM* operator->() const + { + return m_iterator->second; + } + + bool operator!=( const iterator& aOther ) const + { + return m_iterator != aOther.m_iterator; + } + + bool operator==( const iterator& aOther ) const + { + return m_iterator == aOther.m_iterator; + } + + private: + NETNAMES_MAP::const_iterator m_iterator; + }; + + iterator begin() const + { + return iterator( m_netNames.begin() ); + } + + iterator end() const + { + return iterator( m_netNames.end() ); + } + private: /** * Function DeleteData diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index 556ed1d3d7..e57bbfed8b 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -90,8 +90,8 @@ void NETINFO_LIST::buildListOfNets() buildPadsFullList(); // Restore the initial state of NETINFO_ITEMs - for( unsigned i = 0; i < GetNetCount(); ++i ) - GetNetItem( i )->Clear(); + for( NETINFO_LIST::iterator net( begin() ), netEnd( end() ); net != netEnd; ++net ) + net->Clear(); // Assign pads to appropriate NETINFO_ITEMs for( unsigned ii = 0; ii < m_PadsFullList.size(); ii++ ) diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index ed6d7c062e..3cda985754 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -654,14 +654,19 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const m_out->Print( aNestLevel, ")\n\n" ); - int netcount = aBoard->GetNetCount(); + // Unconditionally save the unconnected net + m_out->Print( aNestLevel, "(net 0 \"\")\n" ); - for( int i = 0; i < netcount; ++i ) + // and now the rest of nets + for( NETINFO_LIST::iterator net( aBoard->BeginNet() ), netEnd( aBoard->EndNet() ); + net != netEnd; ++net ) { - NETINFO_ITEM* net = aBoard->FindNet( i ); - m_out->Print( aNestLevel, "(net %d %s)\n", - net->GetNet(), - m_out->Quotew( net->GetNetname() ).c_str() ); + if( net->GetNodesCount() > 0 ) // save only not empty nets + { + m_out->Print( aNestLevel, "(net %d %s)\n", + net->GetNet(), + m_out->Quotew( net->GetNetname() ).c_str() ); + } } m_out->Print( 0, "\n" ); From a10d918cac1ec48ceccfe5a4dd38e312ddedeae4 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 27 Jan 2014 11:42:47 +0100 Subject: [PATCH 48/84] Thread-safe version of Delaunay triangulation. --- common/geometry/hetriang.cpp | 72 ++++++-- include/ttl/halfedge/hetraits.h | 124 ------------- include/ttl/halfedge/hetriang.h | 78 +++++++-- include/ttl/ttl.h | 297 +++++++++++++++++--------------- include/ttl/ttl_constr.h | 65 +++---- pcbnew/ratsnest_data.cpp | 2 +- 6 files changed, 317 insertions(+), 321 deletions(-) diff --git a/common/geometry/hetriang.cpp b/common/geometry/hetriang.cpp index c1523ac347..175e80dbd5 100644 --- a/common/geometry/hetriang.cpp +++ b/common/geometry/hetriang.cpp @@ -51,8 +51,6 @@ using namespace hed; using namespace std; -Triangulation* TTLtraits::triang_ = NULL; - #ifdef TTL_USE_NODE_ID int Node::id_count = 0; #endif @@ -164,11 +162,30 @@ EdgePtr Triangulation::initTwoEnclosingTriangles(NodesContainer::iterator first, } +//-------------------------------------------------------------------------------------------------- +Triangulation::Triangulation() { + helper = new ttl::TriangulationHelper( *this ); +} + + +//-------------------------------------------------------------------------------------------------- +Triangulation::Triangulation(const Triangulation& tr) { + std::cout << "Triangulation: Copy constructor not present - EXIT."; + exit(-1); +} + + +//-------------------------------------------------------------------------------------------------- +Triangulation::~Triangulation() { + cleanAll(); + delete helper; +} + + //-------------------------------------------------------------------------------------------------- void Triangulation::createDelaunay(NodesContainer::iterator first, NodesContainer::iterator last) { - - TTLtraits::triang_ = this; + cleanAll(); EdgePtr bedge = initTwoEnclosingTriangles(first, last); @@ -178,7 +195,7 @@ void Triangulation::createDelaunay(NodesContainer::iterator first, NodesContainer::iterator it; for (it = first; it != last; ++it) { - ttl::insertNode(d_iter, *it); + helper->insertNode(d_iter, *it); } // In general (e.g. for the triangle based data structure), the initial dart @@ -189,7 +206,7 @@ void Triangulation::createDelaunay(NodesContainer::iterator first, // triangle "outside" the triangulation.) // Assumes rectangular domain - ttl::removeRectangularBoundary(dc); + helper->removeRectangularBoundary(dc); } @@ -269,7 +286,7 @@ cout << "Iterate boundary 2" << endl; Dart dart_iter = dart; do { - if (ttl::isBoundaryEdge(dart_iter)) + if (helper->isBoundaryEdge(dart_iter)) dart_iter.alpha0().alpha1(); else dart_iter.alpha2().alpha1(); @@ -322,6 +339,31 @@ void Triangulation::cleanAll() { } +//-------------------------------------------------------------------------------------------------- +void Triangulation::swapEdge(Dart& dart) { + if (!dart.getEdge()->isConstrained()) swapEdge(dart.getEdge()); +} + + +//-------------------------------------------------------------------------------------------------- +void Triangulation::splitTriangle(Dart& dart, NodePtr point) { + EdgePtr edge = splitTriangle(dart.getEdge(), point); + dart.init(edge); +} + + +//-------------------------------------------------------------------------------------------------- +void Triangulation::reverse_splitTriangle(Dart& dart) { + reverse_splitTriangle(dart.getEdge()); +} + + +//-------------------------------------------------------------------------------------------------- +void Triangulation::removeBoundaryTriangle(Dart& d) { + removeTriangle(d.getEdge()); +} + + #ifdef TTL_USE_NODE_FLAG //-------------------------------------------------------------------------------------------------- // This is a "template" for accessing all nodes (but multiple tests) @@ -486,7 +528,7 @@ void Triangulation::swapEdge(EdgePtr& diagonal) { // Note that diagonal is both input and output and it is always // kept in counterclockwise direction (this is not required by all - // finctions in ttl:: now) + // functions in TriangulationHelper now) // Swap by rotating counterclockwise // Use the same objects - no deletion or new objects @@ -567,7 +609,7 @@ bool Triangulation::checkDelaunay() const { // only one of the half-edges if (!twinedge || (size_t)edge.get() > (size_t)twinedge.get()) { Dart dart(edge); - if (ttl::swapTestDelaunay(dart)) { + if (helper->swapTestDelaunay(dart)) { noNotDelaunay++; //printEdge(dart,os); os << "\n"; @@ -610,7 +652,7 @@ void Triangulation::optimizeDelaunay() { Dart dart(edge); // Constrained edges should not be swapped - if (!edge->isConstrained() && ttl::swapTestDelaunay(dart, cycling_check)) { + if (!edge->isConstrained() && helper->swapTestDelaunay(dart, cycling_check)) { optimal = false; swapEdge(edge); } @@ -632,7 +674,7 @@ EdgePtr Triangulation::getInteriorNode() const { for (int i = 0; i < 3; ++i) { if (edge->getTwinEdge()) { - if (!ttl::isBoundaryNode(Dart(edge))) + if (!helper->isBoundaryNode(Dart(edge))) return edge; } edge = edge->getNextEdgeInFace(); @@ -643,18 +685,18 @@ EdgePtr Triangulation::getInteriorNode() const { //-------------------------------------------------------------------------------------------------- -static EdgePtr getBoundaryEdgeInTriangle(const EdgePtr& e) { +EdgePtr Triangulation::getBoundaryEdgeInTriangle(const EdgePtr& e) const { EdgePtr edge = e; - if (ttl::isBoundaryEdge(Dart(edge))) + if (helper->isBoundaryEdge(Dart(edge))) return edge; edge = edge->getNextEdgeInFace(); - if (ttl::isBoundaryEdge(Dart(edge))) + if (helper->isBoundaryEdge(Dart(edge))) return edge; edge = edge->getNextEdgeInFace(); - if (ttl::isBoundaryEdge(Dart(edge))) + if (helper->isBoundaryEdge(Dart(edge))) return edge; return EdgePtr(); diff --git a/include/ttl/halfedge/hetraits.h b/include/ttl/halfedge/hetraits.h index e25e993e0e..e24cd0697d 100644 --- a/include/ttl/halfedge/hetraits.h +++ b/include/ttl/halfedge/hetraits.h @@ -69,9 +69,6 @@ namespace hed { struct TTLtraits { - // The actual triangulation object - static Triangulation* triang_; - /** The floating point type used in calculations * involving scalar products and cross products. */ @@ -172,127 +169,6 @@ namespace hed { } //@} // End of Geometric Predicates Group - - - // A rationale for directing these functions to traits is: - // e.g., constraints - - //---------------------------------------------------------------------------------------------- - /* Checks if the edge associated with \e dart should be swapped - * according to the Delaunay criterion.
- * - * \note - * This function is also present in the TTL as ttl::swapTestDelaunay.
- * Thus, the function can be implemented simply as: - * \code - * { return ttl::swapTestDelaunay(dart); } - * \endcode - */ - //static bool swapTestDelaunay(const Dart& dart) { - // return ttl::swapTestDelaunay(dart); - //} - - - //---------------------------------------------------------------------------------------------- - /* Checks if the edge associated with \e dart can be swapped, i.e., - * if the edge is a diagonal in a (strictly) convex quadrilateral. - * This function is also present as ttl::swappableEdge. - */ - //static bool swappableEdge(const Dart& dart) { - // return ttl::swappableEdge(dart); - //} - - - //---------------------------------------------------------------------------------------------- - /* Checks if the edge associated with \e dart should be \e fixed, meaning - * that it should never be swapped. ??? Use when constraints. - */ - //static bool fixedEdge(const Dart& dart) { - // return dart.getEdge()->isConstrained(); - //} - - - //---------------------------------------------------------------------------------------------- - // ----------------------- Functions for Delaunay Triangulation Group ------------------------- - //---------------------------------------------------------------------------------------------- - - /** @name Functions for Delaunay Triangulation */ - //@{ - - //---------------------------------------------------------------------------------------------- - /** Swaps the edge associated with \e dart in the actual data structure. - * - *
- * \image html swapEdge.gif - *
- * - * \param dart - * Some of the functions require a dart as output. - * If this is required by the actual function, the dart should be delivered - * back in a position as seen if it was glued to the edge when swapping (rotating) - * the edge CCW; see the figure. - * - * \note - * - If the edge is \e constrained, or if it should not be swapped for - * some other reason, this function need not do the actual swap of the edge. - * - Some functions in TTL require that \c swapEdge is implemented such that - * darts outside the quadrilateral are not affected by the swap. - */ - static void swapEdge(Dart& dart) { - if (!dart.getEdge()->isConstrained()) triang_->swapEdge(dart.getEdge()); - } - - - //---------------------------------------------------------------------------------------------- - /** Splits the triangle associated with \e dart in the actual data structure into - * three new triangles joining at \e point. - * - *
- * \image html splitTriangle.gif - *
- * - * \param dart - * Output: A CCW dart incident with the new node; see the figure. - */ - static void splitTriangle(Dart& dart, NodePtr point) { - EdgePtr edge = triang_->splitTriangle(dart.getEdge(), point); - dart.init(edge); - } - - //@} // End of Functions for Delaunay Triangulation group - - - //---------------------------------------------------------------------------------------------- - // --------------------------- Functions for removing nodes Group ----------------------------- - //---------------------------------------------------------------------------------------------- - - /** @name Functions for removing nodes */ - //@{ - - //---------------------------------------------------------------------------------------------- - /** The reverse operation of TTLtraits::splitTriangle. - * This function is only required for functions that involve - * removal of interior nodes; see for example ttl::removeInteriorNode. - * - *
- * \image html reverse_splitTriangle.gif - *
- */ - static void reverse_splitTriangle(Dart& dart) { - triang_->reverse_splitTriangle(dart.getEdge()); - } - - - //---------------------------------------------------------------------------------------------- - /** Removes a triangle with an edge at the boundary of the triangulation - * in the actual data structure - */ - static void removeBoundaryTriangle(Dart& d) { - triang_->removeTriangle(d.getEdge()); - } - - //@} // End of Functions for removing nodes Group - }; }; // End of hed namespace diff --git a/include/ttl/halfedge/hetriang.h b/include/ttl/halfedge/hetriang.h index ccee31bc0c..c8326a417d 100644 --- a/include/ttl/halfedge/hetriang.h +++ b/include/ttl/halfedge/hetriang.h @@ -51,10 +51,13 @@ #include #include #include -#include #include #include +namespace ttl { + class TriangulationHelper; +}; + //-------------------------------------------------------------------------------------------------- // The half-edge data structure //-------------------------------------------------------------------------------------------------- @@ -242,26 +245,75 @@ public: class Triangulation { protected: - list leadingEdges_; // one half-edge for each arc + std::list leadingEdges_; // one half-edge for each arc + + ttl::TriangulationHelper* helper; + void addLeadingEdge(EdgePtr& edge) { edge->setAsLeadingEdge(); leadingEdges_.push_front( edge ); } + bool removeLeadingEdgeFromList(EdgePtr& leadingEdge); + void cleanAll(); + /** Swaps the edge associated with \e dart in the actual data structure. + * + *
+ * \image html swapEdge.gif + *
+ * + * \param dart + * Some of the functions require a dart as output. + * If this is required by the actual function, the dart should be delivered + * back in a position as seen if it was glued to the edge when swapping (rotating) + * the edge CCW; see the figure. + * + * \note + * - If the edge is \e constrained, or if it should not be swapped for + * some other reason, this function need not do the actual swap of the edge. + * - Some functions in TTL require that \c swapEdge is implemented such that + * darts outside the quadrilateral are not affected by the swap. + */ + void swapEdge(Dart& dart); + + /** Splits the triangle associated with \e dart in the actual data structure into + * three new triangles joining at \e point. + * + *
+ * \image html splitTriangle.gif + *
+ * + * \param dart + * Output: A CCW dart incident with the new node; see the figure. + */ + void splitTriangle(Dart& dart, NodePtr point); + + /** The reverse operation of TTLtraits::splitTriangle. + * This function is only required for functions that involve + * removal of interior nodes; see for example TrinagulationHelper::removeInteriorNode. + * + *
+ * \image html reverse_splitTriangle.gif + *
+ */ + void reverse_splitTriangle(Dart& dart); + + /** Removes a triangle with an edge at the boundary of the triangulation + * in the actual data structure + */ + void removeBoundaryTriangle(Dart& d); + public: /// Default constructor - Triangulation() {} + Triangulation(); /// Copy constructor - Triangulation(const Triangulation& tr) { - std::cout << "Triangulation: Copy constructor not present - EXIT."; - exit(-1); - } + Triangulation(const Triangulation& tr); /// Destructor - ~Triangulation() { cleanAll(); } + ~Triangulation(); /// Creates a Delaunay triangulation from a set of points void createDelaunay(NodesContainer::iterator first, @@ -295,20 +347,20 @@ public: Dart createDart(); /// Returns a list of "triangles" (one leading half-edge for each triangle) - const list& getLeadingEdges() const { return leadingEdges_; } + const std::list& getLeadingEdges() const { return leadingEdges_; } /// Returns the number of triangles int noTriangles() const { return (int)leadingEdges_.size(); } /// Returns a list of half-edges (one half-edge for each arc) - list* getEdges(bool skip_boundary_edges = false) const; + std::list* getEdges(bool skip_boundary_edges = false) const; #ifdef TTL_USE_NODE_FLAG /// Sets flag in all the nodes void flagNodes(bool flag) const; /// Returns a list of nodes. This function requires TTL_USE_NODE_FLAG to be defined. \see Node. - list* getNodes() const; + std::list* getNodes() const; #endif /// Swaps edges until the triangulation is Delaunay (constrained edges are not swapped) @@ -320,12 +372,16 @@ public: /// Returns an arbitrary interior node (as the source node of the returned edge) EdgePtr getInteriorNode() const; + EdgePtr getBoundaryEdgeInTriangle(const EdgePtr& e) const; + /// Returns an arbitrary boundary edge EdgePtr getBoundaryEdge() const; /// Print edges for plotting with, e.g., gnuplot void printEdges(std::ofstream& os) const; + friend class ttl::TriangulationHelper; + }; // End of class Triangulation diff --git a/include/ttl/ttl.h b/include/ttl/ttl.h index 003e0d81c6..7d7c655843 100644 --- a/include/ttl/ttl.h +++ b/include/ttl/ttl.h @@ -52,8 +52,6 @@ } #endif - using std::list; - // Next on TOPOLOGY: // - get triangle strips @@ -102,7 +100,7 @@ * - \e CW - clockwise * - \e 0_orbit, \e 1_orbit and \e 2_orbit: A sequence of darts around * a node, around an edge and in a triangle respectively; -* see ttl::get_0_orbit_interior and ttl::get_0_orbit_boundary +* see get_0_orbit_interior and get_0_orbit_boundary * - \e arc - In a triangulation an arc is equivalent with an edge * * \see @@ -115,15 +113,15 @@ namespace ttl { - +class TriangulationHelper +{ #ifndef DOXYGEN_SHOULD_SKIP_THIS - //------------------------------------------------------------------------------------------------ - // ----------------------------------- Forward declarations ------------------------------------- - //------------------------------------------------------------------------------------------------ -#if ((_MSC_VER > 0) && (_MSC_VER < 1300)) -#else - +public: + TriangulationHelper(hed::Triangulation& triang) : triangulation(triang) + { + } + // Delaunay Triangulation // ---------------------- template @@ -145,55 +143,55 @@ namespace ttl { // Topological and Geometric Queries // --------------------------------- template - bool locateFaceSimplest(const PointType& point, DartType& dart); + static bool locateFaceSimplest(const PointType& point, DartType& dart); template - bool locateTriangle(const PointType& point, DartType& dart); + static bool locateTriangle(const PointType& point, DartType& dart); template - bool inTriangleSimplest(const PointType& point, const DartType& dart); + static bool inTriangleSimplest(const PointType& point, const DartType& dart); template - bool inTriangle(const PointType& point, const DartType& dart); + static bool inTriangle(const PointType& point, const DartType& dart); template - void getBoundary(const DartType& dart, DartListType& boundary); + static void getBoundary(const DartType& dart, DartListType& boundary); template - bool isBoundaryEdge(const DartType& dart); + static bool isBoundaryEdge(const DartType& dart); template - bool isBoundaryFace(const DartType& dart); + static bool isBoundaryFace(const DartType& dart); template - bool isBoundaryNode(const DartType& dart); + static bool isBoundaryNode(const DartType& dart); template - int getDegreeOfNode(const DartType& dart); + static int getDegreeOfNode(const DartType& dart); template - void get_0_orbit_interior(const DartType& dart, DartListType& orbit); + static void get_0_orbit_interior(const DartType& dart, DartListType& orbit); template - void get_0_orbit_boundary(const DartType& dart, DartListType& orbit); + static void get_0_orbit_boundary(const DartType& dart, DartListType& orbit); template - bool same_0_orbit(const DartType& d1, const DartType& d2); + static bool same_0_orbit(const DartType& d1, const DartType& d2); template - bool same_1_orbit(const DartType& d1, const DartType& d2); + static bool same_1_orbit(const DartType& d1, const DartType& d2); template - bool same_2_orbit(const DartType& d1, const DartType& d2); + static bool same_2_orbit(const DartType& d1, const DartType& d2); template - bool swappableEdge(const DartType& dart, bool allowDegeneracy = false); + static bool swappableEdge(const DartType& dart, bool allowDegeneracy = false); template - void positionAtNextBoundaryEdge(DartType& dart); + static void positionAtNextBoundaryEdge(DartType& dart); template - bool convexBoundary(const DartType& dart); + static bool convexBoundary(const DartType& dart); // Utilities for Delaunay Triangulation @@ -205,7 +203,7 @@ namespace ttl { void optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end); template - bool swapTestDelaunay(const DartType& dart, bool cycling_check = false); + bool swapTestDelaunay(const DartType& dart, bool cycling_check = false) const; template void recSwapDelaunay(DartType& diagonal); @@ -223,9 +221,29 @@ namespace ttl { // Constrained Triangulation // ------------------------- template - DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay); - -#endif + static DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay); + +private: + hed::Triangulation& triangulation; + + template + void insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart); + + template + static bool isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart); + + template + static bool locateFaceWithNode(const NodeType& node, DartType& dart_iter); + + template + static void getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3); + + template + static void getNeighborNodes(const DartType& dart, std::list& node_list, bool& boundary); + + template + static bool degenerateTriangle(const DartType& dart); +}; #endif // DOXYGEN_SHOULD_SKIP_THIS @@ -245,7 +263,7 @@ namespace ttl { * can be created as two triangles forming a rectangle that contains * all the points. * After \c insertNode has been called repeatedly with all the points, - * ttl::removeRectangularBoundary can be called to remove triangles + * removeRectangularBoundary can be called to remove triangles * at the boundary of the triangulation so that the boundary * form the convex hull of the points. * @@ -268,19 +286,19 @@ namespace ttl { * - \ref hed::TTLtraits::splitTriangle "TraitsType::splitTriangle" (DartType&, const PointType&) * * \using - * - ttl::locateTriangle - * - ttl::recSwapDelaunay + * - locateTriangle + * - recSwapDelaunay * * \note * - For efficiency reasons \e dart should be close to the insertion \e point. * * \see - * ttl::removeRectangularBoundary + * removeRectangularBoundary */ template - bool insertNode(DartType& dart, PointType& point) { + bool TriangulationHelper::insertNode(DartType& dart, PointType& point) { - bool found = ttl::locateTriangle(point, dart); + bool found = locateTriangle(point, dart); if (!found) { #ifdef DEBUG_TTL cout << "ERROR: Triangulation::insertNode: NO triangle found. /n"; @@ -289,7 +307,7 @@ namespace ttl { } // ??? can we hide the dart? this is not possible if one triangle only - TraitsType::splitTriangle(dart, point); + triangulation.splitTriangle(dart, point); DartType d1 = dart; d1.alpha2().alpha1().alpha2().alpha0().alpha1(); @@ -304,14 +322,14 @@ namespace ttl { //DartType dsav = d3; d3.alpha0().alpha1(); - //if (!TraitsType::fixedEdge(d1) && !ttl::isBoundaryEdge(d1)) { - if (!ttl::isBoundaryEdge(d1)) { + //if (!TraitsType::fixedEdge(d1) && !isBoundaryEdge(d1)) { + if (!isBoundaryEdge(d1)) { d1.alpha2(); recSwapDelaunay(d1); } - //if (!TraitsType::fixedEdge(d2) && !ttl::isBoundaryEdge(d2)) { - if (!ttl::isBoundaryEdge(d2)) { + //if (!TraitsType::fixedEdge(d2) && !isBoundaryEdge(d2)) { + if (!isBoundaryEdge(d2)) { d2.alpha2(); recSwapDelaunay(d2); } @@ -319,8 +337,8 @@ namespace ttl { // Preserve the incoming dart as output incident to the node and CCW //d = dsav.alpha2(); dart.alpha2(); - //if (!TraitsType::fixedEdge(d3) && !ttl::isBoundaryEdge(d3)) { - if (!ttl::isBoundaryEdge(d3)) { + //if (!TraitsType::fixedEdge(d3) && !isBoundaryEdge(d3)) { + if (!isBoundaryEdge(d3)) { d3.alpha2(); recSwapDelaunay(d3); } @@ -332,7 +350,7 @@ namespace ttl { //------------------------------------------------------------------------------------------------ // Private/Hidden function (might change later) template - void insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart) { + void TriangulationHelper::insertNodes(ForwardIterator first, ForwardIterator last, DartType& dart) { // Assumes that the dereferenced point objects are pointers. // References to the point objects are then passed to TTL. @@ -355,14 +373,14 @@ namespace ttl { * Output: A CCW dart at the new boundary * * \using - * - ttl::removeBoundaryNode + * - removeBoundaryNode * * \note * - This function requires that the boundary of the triangulation is * a rectangle with four nodes (one in each corner). */ template - void removeRectangularBoundary(DartType& dart) { + void TriangulationHelper::removeRectangularBoundary(DartType& dart) { DartType d_next = dart; DartType d_iter; @@ -370,8 +388,8 @@ namespace ttl { for (int i = 0; i < 4; i++) { d_iter = d_next; d_next.alpha0(); - ttl::positionAtNextBoundaryEdge(d_next); - ttl::removeBoundaryNode(d_iter); + positionAtNextBoundaryEdge(d_next); + removeBoundaryNode(d_iter); } dart = d_next; // Return a dart at the new boundary @@ -383,20 +401,20 @@ namespace ttl { * updates the triangulation to be Delaunay. * * \using - * - ttl::removeBoundaryNode if \e dart represents a node at the boundary - * - ttl::removeInteriorNode if \e dart represents an interior node + * - removeBoundaryNode if \e dart represents a node at the boundary + * - removeInteriorNode if \e dart represents an interior node * * \note * - The node cannot belong to a fixed (constrained) edge that is not * swappable. (An endless loop is likely to occur in this case). */ template - void removeNode(DartType& dart) { + void TriangulationHelper::removeNode(DartType& dart) { - if (ttl::isBoundaryNode(dart)) - ttl::removeBoundaryNode(dart); + if (isBoundaryNode(dart)) + removeBoundaryNode(dart); else - ttl::removeInteriorNode(dart); + removeInteriorNode(dart); } @@ -405,14 +423,14 @@ namespace ttl { * updates the triangulation to be Delaunay. * * \using - * - ttl::swapEdgesAwayFromBoundaryNode - * - ttl::optimizeDelaunay + * - swapEdgesAwayFromBoundaryNode + * - optimizeDelaunay * * \require * - \ref hed::TTLtraits::removeBoundaryTriangle "TraitsType::removeBoundaryTriangle" (Dart&) */ template - void removeBoundaryNode(DartType& dart) { + void TriangulationHelper::removeBoundaryNode(DartType& dart) { // ... and update Delaunay // - CCW dart must be given (for remove) @@ -420,13 +438,13 @@ namespace ttl { // we assume that there is not only one triangle left in the triangulation. // Position at boundary edge and CCW - if (!ttl::isBoundaryEdge(dart)) { + if (!isBoundaryEdge(dart)) { dart.alpha1(); // ensures that next function delivers back a CCW dart (if the given dart is CCW) - ttl::positionAtNextBoundaryEdge(dart); + positionAtNextBoundaryEdge(dart); } - list swapped_edges; - ttl::swapEdgesAwayFromBoundaryNode(dart, swapped_edges); + std::list swapped_edges; + swapEdgesAwayFromBoundaryNode(dart, swapped_edges); // Remove boundary triangles and remove the new boundary from the list // of swapped edges, see below. @@ -435,7 +453,7 @@ namespace ttl { bool bend = false; while (bend == false) { dnext.alpha1().alpha2(); - if (ttl::isBoundaryEdge(dnext)) + if (isBoundaryEdge(dnext)) bend = true; // Stop when boundary // Generic: Also remove the new boundary from the list of swapped edges @@ -443,20 +461,20 @@ namespace ttl { n_bedge.alpha1().alpha0().alpha1().alpha2(); // new boundary edge // ??? can we avoid find if we do this in swap away? - typename list::iterator it; + typename std::list::iterator it; it = find(swapped_edges.begin(), swapped_edges.end(), n_bedge); if (it != swapped_edges.end()) swapped_edges.erase(it); // Remove the boundary triangle - TraitsType::removeBoundaryTriangle(d_iter); + triangulation.removeBoundaryTriangle(d_iter); d_iter = dnext; } // Optimize Delaunay - typedef list DartListType; - ttl::optimizeDelaunay(swapped_edges); + typedef std::list DartListType; + optimizeDelaunay(swapped_edges); } @@ -465,8 +483,8 @@ namespace ttl { * updates the triangulation to be Delaunay. * * \using - * - ttl::swapEdgesAwayFromInteriorNode - * - ttl::optimizeDelaunay + * - swapEdgesAwayFromInteriorNode + * - optimizeDelaunay * * \require * - \ref hed::TTLtraits::reverse_splitTriangle "TraitsType::reverse_splitTriangle" (Dart&) @@ -476,7 +494,7 @@ namespace ttl { * swappable. (An endless loop is likely to occur in this case). */ template - void removeInteriorNode(DartType& dart) { + void TriangulationHelper::removeInteriorNode(DartType& dart) { // ... and update to Delaunay. // Must allow degeneracy temporarily, see comments in swap edges away @@ -492,13 +510,13 @@ namespace ttl { // Assumes dart is counterclockwise - list swapped_edges; - ttl::swapEdgesAwayFromInteriorNode(dart, swapped_edges); + std::list swapped_edges; + swapEdgesAwayFromInteriorNode(dart, swapped_edges); // The reverse operation of split triangle: // Make one triangle of the three triangles at the node associated with dart // TraitsType:: - TraitsType::reverse_splitTriangle(dart); + triangulation.reverse_splitTriangle(dart); // ???? Not generic yet if we are very strict: // When calling unsplit triangle, darts at the three opposite sides may @@ -511,7 +529,7 @@ namespace ttl { // Note the theoretical result: if there are no edges in the list, // the triangulation is Delaunay already - ttl::optimizeDelaunay(swapped_edges); + optimizeDelaunay(swapped_edges); } //@} // End of Delaunay Triangulation Group @@ -527,7 +545,7 @@ namespace ttl { //------------------------------------------------------------------------------------------------ // Private/Hidden function (might change later) template - bool isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart) { + bool TriangulationHelper::isMemberOfFace(const TopologyElementType& topologyElement, const DartType& dart) { // Check if the given topology element (node, edge or face) is a member of the face // Assumes: @@ -547,7 +565,7 @@ namespace ttl { //------------------------------------------------------------------------------------------------ // Private/Hidden function (might change later) template - bool locateFaceWithNode(const NodeType& node, DartType& dart_iter) { + bool TriangulationHelper::locateFaceWithNode(const NodeType& node, DartType& dart_iter) { // Locate a face in the topology structure with the given node as a member // Assumes: // - TraitsType::orient2d(DartType, DartType, NodeType) @@ -594,10 +612,10 @@ namespace ttl { * \e regular as explained above. * * \see - * ttl::locateTriangle + * locateTriangle */ template - bool locateFaceSimplest(const PointType& point, DartType& dart) { + bool TriangulationHelper::locateFaceSimplest(const PointType& point, DartType& dart) { // Not degenerate triangles if point is on the extension of the edges // But inTriangle may be called in case of true (may update to inFace2) // Convex boundary @@ -660,11 +678,11 @@ namespace ttl { * then the edge associated with \e dart will be at the boundary of the triangulation. * * \using - * - ttl::locateFaceSimplest - * - ttl::inTriangle + * - locateFaceSimplest + * - inTriangle */ template - bool locateTriangle(const PointType& point, DartType& dart) { + bool TriangulationHelper::locateTriangle(const PointType& point, DartType& dart) { // The purpose is to have a fast and stable procedure that // i) avoids concluding that a point is inside a triangle if it is not inside // ii) avoids infinite loops @@ -713,10 +731,10 @@ namespace ttl { * - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&) * * \see - * ttl::inTriangle for a more robust function + * inTriangle for a more robust function */ template - bool inTriangleSimplest(const PointType& point, const DartType& dart) { + bool TriangulationHelper::inTriangleSimplest(const PointType& point, const DartType& dart) { // Fast and simple: Do not deal with degenerate faces, i.e., if there is // degeneracy, true will be returned if the point is on the extension of the @@ -757,10 +775,10 @@ namespace ttl { * - \ref hed::TTLtraits::scalarProduct2d "TraitsType::scalarProduct2d" (DartType&, PointType&) * * \see - * ttl::inTriangleSimplest + * inTriangleSimplest */ template - bool inTriangle(const PointType& point, const DartType& dart) { + bool TriangulationHelper::inTriangle(const PointType& point, const DartType& dart) { // SHOULD WE INCLUDE A STRATEGY WITH EDGE X e_1 ETC? TO GUARANTEE THAT // ONLY ON ONE EDGE? BUT THIS DOES NOT SOLVE PROBLEMS WITH @@ -841,7 +859,7 @@ namespace ttl { //------------------------------------------------------------------------------------------------ // Private/Hidden function (might change later) template - void getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3) { + void TriangulationHelper::getAdjacentTriangles(const DartType& dart, DartType& t1, DartType& t2, DartType& t3) { DartType dart_iter = dart; @@ -886,7 +904,7 @@ namespace ttl { * - DartListType::push_back (DartType&) */ template - void getBoundary(const DartType& dart, DartListType& boundary) { + void TriangulationHelper::getBoundary(const DartType& dart, DartListType& boundary) { // assumes the given dart is at the boundary (by edge) DartType dart_iter(dart); @@ -932,7 +950,7 @@ namespace ttl { * \endcode */ template - bool isBoundaryEdge(const DartType& dart) { + bool TriangulationHelper::isBoundaryEdge(const DartType& dart) { DartType dart_iter = dart; if (dart_iter.alpha2() == dart) @@ -947,7 +965,7 @@ namespace ttl { * the boundary of the triangulation. */ template - bool isBoundaryFace(const DartType& dart) { + bool TriangulationHelper::isBoundaryFace(const DartType& dart) { // Strategy: boundary if alpha2(d)=d @@ -976,7 +994,7 @@ namespace ttl { * the boundary of the triangulation. */ template - bool isBoundaryNode(const DartType& dart) { + bool TriangulationHelper::isBoundaryNode(const DartType& dart) { // Strategy: boundary if alpha2(d)=d @@ -1009,7 +1027,7 @@ namespace ttl { * the number of edges joining \e V with another node in the triangulation. */ template - int getDegreeOfNode(const DartType& dart) { + int TriangulationHelper::getDegreeOfNode(const DartType& dart) { DartType dart_iter(dart); DartType dart_prev; @@ -1069,7 +1087,8 @@ namespace ttl { // Private/Hidden function template - void getNeighborNodes(const DartType& dart, std::list& node_list, bool& boundary) { + void TriangulationHelper::getNeighborNodes(const DartType& dart, + std::list& node_list, bool& boundary) { DartType dart_iter(dart); @@ -1131,10 +1150,10 @@ namespace ttl { * - DartListType::push_back (DartType&) * * \see - * ttl::get_0_orbit_boundary + * get_0_orbit_boundary */ template - void get_0_orbit_interior(const DartType& dart, DartListType& orbit) { + void TriangulationHelper::get_0_orbit_interior(const DartType& dart, DartListType& orbit) { DartType d_iter = dart; orbit.push_back(d_iter); @@ -1165,10 +1184,10 @@ namespace ttl { * - The last dart in the sequence have opposite orientation compared to the others! * * \see - * ttl::get_0_orbit_interior + * get_0_orbit_interior */ template - void get_0_orbit_boundary(const DartType& dart, DartListType& orbit) { + void TriangulationHelper::get_0_orbit_boundary(const DartType& dart, DartListType& orbit) { DartType dart_prev; DartType d_iter = dart; @@ -1195,17 +1214,17 @@ namespace ttl { * own version.) */ template - bool same_0_orbit(const DartType& d1, const DartType& d2) { + bool TriangulationHelper::same_0_orbit(const DartType& d1, const DartType& d2) { // Two copies of the same dart DartType d_iter = d2; DartType d_end = d2; - if (ttl::isBoundaryNode(d_iter)) { + if (isBoundaryNode(d_iter)) { // position at both boundary edges - ttl::positionAtNextBoundaryEdge(d_iter); + positionAtNextBoundaryEdge(d_iter); d_end.alpha1(); - ttl::positionAtNextBoundaryEdge(d_end); + positionAtNextBoundaryEdge(d_end); } for (;;) { @@ -1229,7 +1248,7 @@ namespace ttl { * \e d1 and/or \e d2 can be CCW or CW. */ template - bool same_1_orbit(const DartType& d1, const DartType& d2) { + bool TriangulationHelper::same_1_orbit(const DartType& d1, const DartType& d2) { DartType d_iter = d2; // (Also works at the boundary) @@ -1245,7 +1264,7 @@ namespace ttl { * \e d1 and/or \e d2 can be CCW or CW */ template - bool same_2_orbit(const DartType& d1, const DartType& d2) { + bool TriangulationHelper::same_2_orbit(const DartType& d1, const DartType& d2) { DartType d_iter = d2; if (d_iter == d1 || d_iter.alpha0() == d1 || @@ -1259,7 +1278,7 @@ namespace ttl { //------------------------------------------------------------------------------------------------ // Private/Hidden function template - bool degenerateTriangle(const DartType& dart) { + bool TriangulationHelper::degenerateTriangle(const DartType& dart) { // Check if triangle is degenerate // Assumes CCW dart @@ -1287,7 +1306,7 @@ namespace ttl { * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (Dart&, Dart&) */ template - bool swappableEdge(const DartType& dart, bool allowDegeneracy) { + bool TriangulationHelper::swappableEdge(const DartType& dart, bool allowDegeneracy) { // How "safe" is it? @@ -1340,7 +1359,7 @@ namespace ttl { * infinit loop occurs. */ template - void positionAtNextBoundaryEdge(DartType& dart) { + void TriangulationHelper::positionAtNextBoundaryEdge(DartType& dart) { DartType dart_prev; @@ -1365,14 +1384,14 @@ namespace ttl { * - \ref hed::TTLtraits::crossProduct2d "TraitsType::crossProduct2d" (const Dart&, const Dart&) */ template - bool convexBoundary(const DartType& dart) { + bool TriangulationHelper::convexBoundary(const DartType& dart) { - list blist; - ttl::getBoundary(dart, blist); + std::list blist; + getBoundary(dart, blist); int no; no = (int)blist.size(); - typename list::const_iterator bit = blist.begin(); + typename std::list::const_iterator bit = blist.begin(); DartType d1 = *bit; ++bit; DartType d2; @@ -1428,17 +1447,17 @@ namespace ttl { * seen if it was glued to the edge when swapping (rotating) the edge CCW * * \using - * - ttl::swapTestDelaunay + * - swapTestDelaunay */ template - void optimizeDelaunay(DartListType& elist) { + void TriangulationHelper::optimizeDelaunay(DartListType& elist) { optimizeDelaunay(elist, elist.end()); } //------------------------------------------------------------------------------------------------ template - void optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end) { + void TriangulationHelper::optimizeDelaunay(DartListType& elist, const typename DartListType::iterator end) { // CCW darts // Optimize here means Delaunay, but could be any criterion by @@ -1481,14 +1500,14 @@ namespace ttl { while(!optimal) { optimal = true; for (it = elist.begin(); it != end_opt; ++it) { - if (ttl::swapTestDelaunay(*it, cycling_check)) { + if (swapTestDelaunay(*it, cycling_check)) { // Preserve darts. Potential darts in the list are: // - The current dart // - the four CCW darts on the boundary of the quadrilateral // (the current arc has only one dart) - ttl::swapEdgeInList(it, elist); + swapEdgeInList(it, elist); optimal = false; } // end if should swap @@ -1513,9 +1532,9 @@ namespace ttl { */ template #if ((_MSC_VER > 0) && (_MSC_VER < 1300))//#ifdef _MSC_VER - bool swapTestDelaunay(const DartType& dart, bool cycling_check = false) { + bool TriangulationHelper::swapTestDelaunay(const DartType& dart, bool cycling_check = false) const { #else - bool swapTestDelaunay(const DartType& dart, bool cycling_check) { + bool TriangulationHelper::swapTestDelaunay(const DartType& dart, bool cycling_check) const { #endif // The general strategy is taken from Cline & Renka. They claim that @@ -1627,17 +1646,17 @@ namespace ttl { * - Calls itself recursively */ template - void recSwapDelaunay(DartType& diagonal) { + void TriangulationHelper::recSwapDelaunay(DartType& diagonal) { - if (!ttl::swapTestDelaunay(diagonal)) - // ??? ttl::swapTestDelaunay also checks if boundary, so this can be optimized + if (!swapTestDelaunay(diagonal)) + // ??? swapTestDelaunay also checks if boundary, so this can be optimized return; // Get the other "edges" of the current triangle; see illustration above. DartType oppEdge1 = diagonal; oppEdge1.alpha1(); bool b1; - if (ttl::isBoundaryEdge(oppEdge1)) + if (isBoundaryEdge(oppEdge1)) b1 = true; else { b1 = false; @@ -1648,7 +1667,7 @@ namespace ttl { DartType oppEdge2 = diagonal; oppEdge2.alpha0().alpha1().alpha0(); bool b2; - if (ttl::isBoundaryEdge(oppEdge2)) + if (isBoundaryEdge(oppEdge2)) b2 = true; else { b2 = false; @@ -1656,7 +1675,7 @@ namespace ttl { } // Swap the given diagonal - TraitsType::swapEdge(diagonal); + triangulation.swapEdge(diagonal); if (!b1) recSwapDelaunay(oppEdge1); @@ -1669,7 +1688,7 @@ namespace ttl { /** Swaps edges away from the (interior) node associated with * \e dart such that that exactly three edges remain incident * with the node. - * This function is used as a first step in ttl::removeInteriorNode + * This function is used as a first step in removeInteriorNode * * \retval dart * A CCW dart incident with the node @@ -1689,10 +1708,10 @@ namespace ttl { * at the node that is given as input. * * \see - * ttl::swapEdgesAwayFromBoundaryNode + * swapEdgesAwayFromBoundaryNode */ template - void swapEdgesAwayFromInteriorNode(DartType& dart, ListType& swapped_edges) { + void TriangulationHelper::swapEdgesAwayFromInteriorNode(DartType& dart, ListType& swapped_edges) { // Same iteration as in fixEdgesAtCorner, but not boundary DartType dnext = dart; @@ -1706,14 +1725,14 @@ namespace ttl { // infinite loop with degree > 3. bool allowDegeneracy = true; - int degree = ttl::getDegreeOfNode(dart); + int degree = getDegreeOfNode(dart); DartType d_iter; while (degree > 3) { d_iter = dnext; dnext.alpha1().alpha2(); - if (ttl::swappableEdge(d_iter, allowDegeneracy)) { - TraitsType::swapEdge(d_iter); // swap the edge away + if (swappableEdge(d_iter, allowDegeneracy)) { + triangulation.swapEdge(d_iter); // swap the edge away // Collect swapped edges in the list // "Hide" the dart on the other side of the edge to avoid it being changed for // other swaps @@ -1733,7 +1752,7 @@ namespace ttl { /** Swaps edges away from the (boundary) node associated with * \e dart in such a way that when removing the edges that remain incident * with the node, the boundary of the triangulation will be convex. - * This function is used as a first step in ttl::removeBoundaryNode + * This function is used as a first step in removeBoundaryNode * * \retval dart * A CCW dart incident with the node @@ -1747,10 +1766,10 @@ namespace ttl { * - The node associated with \e dart is at the boundary of the triangulation. * * \see - * ttl::swapEdgesAwayFromInteriorNode + * swapEdgesAwayFromInteriorNode */ template - void swapEdgesAwayFromBoundaryNode(DartType& dart, ListType& swapped_edges) { + void TriangulationHelper::swapEdgesAwayFromBoundaryNode(DartType& dart, ListType& swapped_edges) { // All darts that are swappable. // To treat collinear nodes at an existing boundary, we must allow degeneracy @@ -1762,7 +1781,7 @@ namespace ttl { // - A dart on the swapped edge is delivered back in a position as // seen if it was glued to the edge when swapping (rotating) the edge CCW - //int degree = ttl::getDegreeOfNode(dart); + //int degree = getDegreeOfNode(dart); passes: @@ -1780,7 +1799,7 @@ passes: while (!bend) { d_next.alpha1().alpha2(); - if (ttl::isBoundaryEdge(d_next)) + if (isBoundaryEdge(d_next)) bend = true; // then it is CW since alpha2 // To allow removing among collinear nodes at the boundary, @@ -1789,13 +1808,13 @@ passes: tmp1 = d_iter; tmp1.alpha1(); tmp2 = d_iter; tmp2.alpha2().alpha1(); // don't bother with boundary (checked later) - if (ttl::isBoundaryEdge(tmp1) && ttl::isBoundaryEdge(tmp2)) + if (isBoundaryEdge(tmp1) && isBoundaryEdge(tmp2)) allowDegeneracy = true; else allowDegeneracy = false; - if (ttl::swappableEdge(d_iter, allowDegeneracy)) { - TraitsType::swapEdge(d_iter); + if (swappableEdge(d_iter, allowDegeneracy)) { + triangulation.swapEdge(d_iter); // Collect swapped edges in the list // "Hide" the dart on the other side of the edge to avoid it being changed for @@ -1821,7 +1840,7 @@ passes: else { d_iter.alpha1(); // CW and see below } - ttl::positionAtNextBoundaryEdge(d_iter); // CCW + positionAtNextBoundaryEdge(d_iter); // CCW dart = d_iter; // for next pass or output @@ -1839,7 +1858,7 @@ passes: * keep them in \e elist. */ template - void swapEdgeInList(const typename DartListType::iterator& it, DartListType& elist) { + void TriangulationHelper::swapEdgeInList(const typename DartListType::iterator& it, DartListType& elist) { typename DartListType::iterator it1, it2, it3, it4; DartType dart(*it); @@ -1867,7 +1886,7 @@ passes: it3 = find(elist.begin(), elist.end(), d3); it4 = find(elist.begin(), elist.end(), d4); - TraitsType::swapEdge(dart); + triangulation.swapEdge(dart); // Update the current dart which may have changed *it = dart; diff --git a/include/ttl/ttl_constr.h b/include/ttl/ttl_constr.h index 67b46fcbf0..125bddeb23 100644 --- a/include/ttl/ttl_constr.h +++ b/include/ttl/ttl_constr.h @@ -51,9 +51,6 @@ static ofstream ofile_constr("qweCons.dat"); #endif - -//using namespace std; - /** \brief Constrained Delaunay triangulation * * Basic generic algorithms in TTL for inserting a constrained edge between two existing nodes.\n @@ -61,7 +58,7 @@ * See documentation for the namespace ttl for general requirements and assumptions. * * \author -* Øyvind Hjelle, oyvindhj@ifi.uio.no +* �yvind Hjelle, oyvindhj@ifi.uio.no */ namespace ttl_constr { @@ -73,6 +70,9 @@ namespace ttl_constr { #endif +class ConstrainedTriangulation +{ + public: //------------------------------------------------------------------------------------------------ /* Checks if \e dart has start and end points in \e dstart and \e dend. * @@ -89,14 +89,14 @@ namespace ttl_constr { * A bool confirming that it's the constraint or not * * \using - * ttl::same_0_orbit + * same_0_orbit */ template - bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) { + static bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) { DartType d0 = dart; d0.alpha0(); // CW - if ((ttl::same_0_orbit(dstart, dart) && ttl::same_0_orbit(dend, d0)) || - (ttl::same_0_orbit(dstart, d0) && ttl::same_0_orbit(dend, dart))) { + if ((ttl::TriangulationHelper::same_0_orbit(dstart, dart) && ttl::TriangulationHelper::same_0_orbit(dend, d0)) || + (ttl::TriangulationHelper::same_0_orbit(dstart, d0) && ttl::TriangulationHelper::same_0_orbit(dend, dart))) { return true; } return false; @@ -123,7 +123,7 @@ namespace ttl_constr { * TraitsType::orient2d */ template - bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) { + static bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) { typename TraitsType::real_type orient_1 = TraitsType::orient2d(dstart,d1,dend); typename TraitsType::real_type orient_2 = TraitsType::orient2d(dstart,d2,dend); @@ -156,12 +156,12 @@ namespace ttl_constr { * The dart \e d making the smallest positive (or == 0) angle * * \using - * ttl::isBoundaryNode - * ttl::positionAtNextBoundaryEdge + * isBoundaryNode + * positionAtNextBoundaryEdge * TraitsType::orient2d */ template - DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) { + static DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) { // - Must boundary be convex??? // - Handle the case where the constraint is already present??? @@ -169,9 +169,9 @@ namespace ttl_constr { // (dstart and dend may define a boundary edge) DartType d_iter = dstart; - if (ttl::isBoundaryNode(d_iter)) { + if (ttl::TriangulationHelper::isBoundaryNode(d_iter)) { d_iter.alpha1(); // CW - ttl::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary) + ttl::TriangulationHelper::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary) } // assume convex boundary; see comments @@ -273,7 +273,7 @@ namespace ttl_constr { * Returns the next "collinear" starting node such that dend is returned when done. */ template - DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) { + static DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) { const DartType my_start = getAtSmallestAngle(dstart, dend); DartType my_end = getAtSmallestAngle(dend, dstart); @@ -387,15 +387,16 @@ namespace ttl_constr { * A list containing all the edges crossing the spesified constraint * * \using - * ttl::swappableEdge - * ttl::swapEdgeInList - * ttl::crossesConstraint - * ttl::isTheConstraint + * swappableEdge + * swapEdgeInList + * crossesConstraint + * isTheConstraint */ template - void transformToConstraint(DartType& dstart, DartType& dend, std::list& elist) { + void transformToConstraint(ttl::TriangulationHelper helper, DartType& dstart, DartType& dend, + std::list& elist) const { - typename list::iterator it, used; + typename std::list::iterator it, used; // We may enter in a situation where dstart and dend are altered because of a swap. // (The general rule is that darts inside the actual quadrilateral can be changed, @@ -423,7 +424,7 @@ namespace ttl_constr { if (counter > dartsInList) break; - if (ttl::swappableEdge(*it, true)) { + if (ttl::TriangulationHelper::swappableEdge(*it, true)) { // Dyn & Goren & Rippa 's notation: // The node assosiated with dart *it is denoted u_m. u_m has edges crossing the constraint // named w_1, ... , w_r . The other node to the edge assosiated with dart *it is w_s. @@ -456,7 +457,7 @@ namespace ttl_constr { end = true; // This is the only place swapping is called when inserting a constraint - ttl::swapEdgeInList(it,elist); + helper.swapEdgeInList(it,elist); // If we, during look-ahead, found that dstart and/or dend were in the quadrilateral, // we update them. @@ -512,6 +513,8 @@ namespace ttl_constr { } +}; // End of ConstrainedTriangulation class + }; // End of ttl_constr namespace scope @@ -546,14 +549,14 @@ namespace ttl { // (extension) * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType&) * * \using - * - ttl::optimizeDelaunay if \e optimize_delaunay is set to \c true + * - optimizeDelaunay if \e optimize_delaunay is set to \c true * * \par Assumes: * - The constrained edge must be inside the existing triangulation (and it cannot * cross the boundary of the triangulation). */ template - DartType insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) { + DartType TriangulationHelper::insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) { // Assumes: // - It is the users responsibility to avoid crossing constraints @@ -567,8 +570,8 @@ namespace ttl { // (extension) // calls itself recursively. // RECURSION - list elist; - DartType next_start = ttl_constr::findCrossingEdges(dstart, dend, elist); + std::list elist; + DartType next_start = ttl_constr::ConstrainedTriangulation::findCrossingEdges(dstart, dend, elist); // If there are no crossing edges (elist is empty), we assume that the constraint // is an existing edge. @@ -583,7 +586,7 @@ namespace ttl { // (extension) // findCrossingEdges stops if it finds a node lying on the constraint. // A dart with this node as start node is returned // We call insertConstraint recursivly until the received dart is dend - if (!ttl::same_0_orbit(next_start, dend)) { + if (!same_0_orbit(next_start, dend)) { #ifdef DEBUG_TTL_CONSTR_PLOT cout << "RECURSION due to collinearity along constraint" << endl; @@ -594,7 +597,7 @@ namespace ttl { // (extension) // Swap edges such that the constraint edge is present in the transformed triangulation. if (elist.size() > 0) // by Thomas Sevaldrud - ttl_constr::transformToConstraint(dstart, next_start, elist); + ttl_constr::ConstrainedTriangulation::transformToConstraint(dstart, next_start, elist); #ifdef DEBUG_TTL_CONSTR_PLOT cout << "size of elist = " << elist.size() << endl; @@ -607,13 +610,13 @@ namespace ttl { // (extension) #endif // Optimize to constrained Delaunay triangulation if required. - typename list::iterator end_opt = elist.end(); + typename std::list::iterator end_opt = elist.end(); if (optimize_delaunay) { // Indicate that the constrained edge, which is the last element in the list, // should not be swapped --end_opt; - ttl::optimizeDelaunay(elist, end_opt); + optimizeDelaunay(elist, end_opt); } if(elist.size() == 0) // by Thomas Sevaldrud diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index e66451b86b..af5f6932fd 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -240,7 +240,7 @@ void RN_NET::compute() return; } - else if( boardNodes.size() == 1 ) // This case is even simpler + else if( boardNodes.size() <= 1 ) // This case is even simpler { m_rnEdges.reset( new std::vector( 0 ) ); From 15b8d3d20ac797800b3c617b0731cda833e66b56 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 28 Jan 2014 10:19:51 +0100 Subject: [PATCH 49/84] Added NETINFO_MAPPING, to ease saving nets with consecutive net codes (without modifying the net codes during the run time). Now, nets are saved with consecutive net codes (both modern & legacy plugins). Zones are saved together with their nets, without depending on the fact if there are any pads with such net. Therefore validation of zone net names was removed (pcbnew/class_board.cpp). Performed tests: - Changed a pad's net name from empty to existent - ok, name was changed. - Changed a pad's net name from empty to nonexistent - ok, error message is displayed, net name stays empty. - Changed a pad's net name from existent to empty - ok, net name became empty - Changed a pad's net name from existent to nonexistent - ok, error message is displayed, net name is not changed. - Drawn a zone that belongs to a net, then modified schematics so the net does not exist anymore. After reloading the net list, all pads/tracks are updated. Zones still belongs to the net that does not exist in the schematic (but still exists in .kicad_pcb file). After running DRC, the zone becomes not filled. - Undo & redo affects assignment of a polygon to a specific net (you may change net of a polygon, refill it and undo/redo the changes). - KiCad s-expr & legacy, Eagle, P-CAD boards seem to load without any problem (they also contain correct net names assigned to the appropriate pads). All types of board file formats were loaded, then saved in sexpr format and reopened with a KiCad built from the master branch (without my modifications). - A few boards were also saved using the legacy format and were opened with the master KiCad without any issues. - Change a net name for a pad, restore with undo/redo - ok - Remove everything, restore with undo - ok - Remove everything, reload netlist - ok Differences observed between files saved by the master branch KiCad and this one: - list of nets are not saved in any particular order, so net codes may differ - the default net class does not contain the unconnected net --- pcbnew/class_board.cpp | 25 ------ pcbnew/class_board_connected_item.cpp | 6 ++ pcbnew/class_netinfo.h | 123 ++++++++++++++++++++++++-- pcbnew/class_netinfolist.cpp | 73 ++++++++++++++- pcbnew/kicad_plugin.cpp | 44 ++++----- pcbnew/kicad_plugin.h | 7 +- pcbnew/legacy_plugin.cpp | 19 ++-- pcbnew/legacy_plugin.h | 4 + pcbnew/pcb_parser.cpp | 11 ++- 9 files changed, 240 insertions(+), 72 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 5c435f634a..b32e48ae22 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2700,31 +2700,6 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, } } } - - // Verify zone net names validity: - // After schematic changes, a zone can have a non existing net name. - // It should be reported - if( aReporter && aReporter->ReportErrors() ) - { - //Loop through all copper zones - for( i = 0; i < m_ZoneDescriptorList.size(); i++ ) - { - ZONE_CONTAINER* zone = m_ZoneDescriptorList[i]; - - if( zone->GetNet() >= 0 || !zone->IsOnCopperLayer() ) - continue; - - // Net name not valid, report error - wxString coord; - coord << zone->GetPosition(); - msg.Printf( _( "** Error: Zone '%s' layer '%s'" - " has non-existent net name \"%s\" **\n" ), - GetChars( coord ), - GetChars( zone->GetLayerName() ), - GetChars( zone->GetNetname() ) ); - aReporter->Report( msg ); - } - } } /* Extracts the board outlines and build a closed polygon diff --git a/pcbnew/class_board_connected_item.cpp b/pcbnew/class_board_connected_item.cpp index 69bcfacb7e..26cca19772 100644 --- a/pcbnew/class_board_connected_item.cpp +++ b/pcbnew/class_board_connected_item.cpp @@ -63,9 +63,15 @@ void BOARD_CONNECTED_ITEM::SetNet( int aNetCode ) { m_netinfo = board->FindNet( aNetCode ); + // The requested net does not exist, mark it as unconnected if( m_netinfo == NULL ) m_netinfo = board->FindNet( NETINFO_LIST::UNCONNECTED ); } + else + { + // There is no board that contains list of nets, the item is orphaned + m_netinfo = &NETINFO_LIST::ORPHANED; + } } diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index 326a0fa3b4..50bb30457d 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -116,6 +116,121 @@ public: }; +class NETINFO_MAPPING +{ +public: + /** + * Function SetBoard + * Sets a BOARD object that is used to prepare the net code map. + */ + void SetBoard( const BOARD* aBoard ) + { + m_board = aBoard; + Update(); + } + + /** + * Function Update + * Prepares a mapping for net codes so they can be saved as consecutive numbers. + * To retrieve a mapped net code, use translateNet() function after calling this. + */ + void Update(); + + /** + * Function Translate + * Translates net number according to the map prepared by Update() function. It + * allows to have items stored with consecutive net codes. + * @param aNetCode is an old net code. + * @return Net code that follows the mapping. + */ + int Translate( int aNetCode ) const; + + ///> Wrapper class, so you can iterate through NETINFO_ITEM*s, not + ///> std::pair + class iterator + { + public: + iterator( std::map::const_iterator aIter, const NETINFO_MAPPING* aMapping ) : + m_iterator( aIter ), m_mapping( aMapping ) + { + } + + /// pre-increment operator + const iterator& operator++() + { + ++m_iterator; + + return *this; + } + + /// post-increment operator + iterator operator++( int ) + { + iterator ret = *this; + ++m_iterator; + + return ret; + } + + NETINFO_ITEM* operator*() const; + + NETINFO_ITEM* operator->() const; + + bool operator!=( const iterator& aOther ) const + { + return m_iterator != aOther.m_iterator; + } + + bool operator==( const iterator& aOther ) const + { + return m_iterator == aOther.m_iterator; + } + + private: + std::map::const_iterator m_iterator; + const NETINFO_MAPPING* m_mapping; + }; + + /** + * Function begin() + * Returns iterator to the first entry in the mapping. + * NOTE: The entry is a pointer to the original NETINFO_ITEM object, this it contains + * not mapped net code. + */ + iterator begin() const + { + return iterator( m_netMapping.begin(), this ); + } + + /** + * Function end() + * Returns iterator to the last entry in the mapping. + * NOTE: The entry is a pointer to the original NETINFO_ITEM object, this it contains + * not mapped net code. + */ + iterator end() const + { + return iterator( m_netMapping.end(), this ); + } + + /** + * Function GetSize + * @return Number of mapped nets (i.e. not empty nets for a given BOARD object). + */ + int GetSize() const + { + return m_netMapping.size(); + } + +private: + ///> Board for which mapping is prepared + const BOARD* m_board; + + ///> Map that allows saving net codes with consecutive numbers (for compatibility reasons) + std::map m_netMapping; +}; + + /** * Class NETINFO * is a container class for NETINFO_ITEM elements, which are the nets. That makes @@ -304,16 +419,12 @@ private: */ int getFreeNetCode() const; - BOARD* m_Parent; + BOARD* m_Parent; NETNAMES_MAP m_netNames; ///< map for a fast look up by net names NETCODES_MAP m_netCodes; ///< map for a fast look up by net codes - static int m_newNetCode; ///< number that has a *high* chance to be unused - ///< (to be sure, it is advised to use - ///< getFreeNetCode() function) - - std::vector m_PadsFullList; ///< contains all pads, sorted by pad's netname. + std::vector m_PadsFullList; ///< contains all pads, sorted by pad's netname. ///< can be used in ratsnest calculations. }; diff --git a/pcbnew/class_netinfolist.cpp b/pcbnew/class_netinfolist.cpp index e57bbfed8b..34b2eded9a 100644 --- a/pcbnew/class_netinfolist.cpp +++ b/pcbnew/class_netinfolist.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include +#include #include @@ -98,7 +101,7 @@ void NETINFO_LIST::buildListOfNets() { pad = m_PadsFullList[ii]; - if( pad->GetNet() == 0 ) // pad not connected + if( pad->GetNet() == NETINFO_LIST::UNCONNECTED ) // pad not connected continue; // Add pad to the appropriate list of pads @@ -172,15 +175,79 @@ void NETINFO_LIST::buildPadsFullList() int NETINFO_LIST::getFreeNetCode() const { + static int m_newNetCode = 0; + do { if( m_newNetCode < 0 ) m_newNetCode = 0; - } while( m_netCodes.count( ++NETINFO_LIST::m_newNetCode ) != 0 ); + } while( m_netCodes.count( ++m_newNetCode ) != 0 ); return m_newNetCode; } +int NETINFO_MAPPING::Translate( int aNetCode ) const +{ + std::map::const_iterator value = m_netMapping.find( aNetCode ); + + if( value != m_netMapping.end() ) + return value->second; + + // There was no entry for the given net code + return aNetCode; +} + + +void NETINFO_MAPPING::Update() +{ + // Collect all the used nets + std::set nets; + + // Be sure that the unconnected gets 0 and is mapped as 0 + nets.insert( 0 ); + + // Zones + for( int i = 0; i < m_board->GetAreaCount(); ++i ) + nets.insert( m_board->GetArea( i )->GetNet() ); + + // Tracks + for( TRACK* track = m_board->m_Track; track; track = track->Next() ) + nets.insert( track->GetNet() ); + + // Modules/pads + for( MODULE* module = m_board->m_Modules; module; module = module->Next() ) + { + for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + { + nets.insert( pad->GetNet() ); + } + } + + // Segzones + for( SEGZONE* zone = m_board->m_Zone; zone; zone = zone->Next() ) + nets.insert( zone->GetNet() ); + + // Prepare the new mapping + m_netMapping.clear(); + + // Now the nets variable stores all the used net codes (not only for pads) + int newNetCode = 0; + for( std::set::const_iterator it = nets.begin(), itEnd = nets.end(); it != itEnd; ++it ) + m_netMapping[*it] = newNetCode++; +} + + +NETINFO_ITEM* NETINFO_MAPPING::iterator::operator*() const +{ + return m_mapping->m_board->FindNet( m_iterator->first ); +} + + +NETINFO_ITEM* NETINFO_MAPPING::iterator::operator->() const +{ + return m_mapping->m_board->FindNet( m_iterator->first ); +} + + const NETINFO_ITEM NETINFO_LIST::ORPHANED = NETINFO_ITEM( NULL, wxString::FromUTF8( "orphaned" ), -1 ); const int NETINFO_LIST::UNCONNECTED = 0; -int NETINFO_LIST::m_newNetCode = 0; diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 3cda985754..fbdcf0fd3e 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -380,6 +380,9 @@ void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* a m_board = aBoard; // after init() + // Prepare net mapping that assures that net codes saved in a file are consecutive integers + m_mapping->SetBoard( aBoard ); + FILE_OUTPUTFORMATTER formatter( aFileName ); m_out = &formatter; // no ownership @@ -499,7 +502,7 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() ); m_out->Print( aNestLevel+1, "(zones %d)\n", aBoard->GetNumSegmZone() ); m_out->Print( aNestLevel+1, "(modules %d)\n", aBoard->m_Modules.GetCount() ); - m_out->Print( aNestLevel+1, "(nets %d)\n", aBoard->GetNetCount() ); + m_out->Print( aNestLevel+1, "(nets %d)\n", (int) m_mapping->GetSize() ); m_out->Print( aNestLevel, ")\n\n" ); aBoard->GetPageSettings().Format( m_out, aNestLevel, m_ctl ); @@ -654,20 +657,14 @@ void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const m_out->Print( aNestLevel, ")\n\n" ); - // Unconditionally save the unconnected net - m_out->Print( aNestLevel, "(net 0 \"\")\n" ); - - // and now the rest of nets - for( NETINFO_LIST::iterator net( aBoard->BeginNet() ), netEnd( aBoard->EndNet() ); + // Save net codes and names + for( NETINFO_MAPPING::iterator net = m_mapping->begin(), netEnd = m_mapping->end(); net != netEnd; ++net ) { - if( net->GetNodesCount() > 0 ) // save only not empty nets - { - m_out->Print( aNestLevel, "(net %d %s)\n", - net->GetNet(), - m_out->Quotew( net->GetNetname() ).c_str() ); - } - } + m_out->Print( aNestLevel, "(net %d %s)\n", + m_mapping->Translate( net->GetNet() ), + m_out->Quotew( net->GetNetname() ).c_str() ); + } m_out->Print( 0, "\n" ); @@ -1234,7 +1231,8 @@ void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const // Unconnected pad is default net so don't save it. if( !(m_ctl & CTL_OMIT_NETS) && aPad->GetNet() != 0 ) - StrPrintf( &output, " (net %d %s)", aPad->GetNet(), m_out->Quotew( aPad->GetNetname() ).c_str() ); + StrPrintf( &output, " (net %d %s)", m_mapping->Translate( aPad->GetNet() ), + m_out->Quotew( aPad->GetNetname() ).c_str() ); if( aPad->GetPadToDieLength() != 0 ) StrPrintf( &output, " (die_length %s)", FMT_IU( aPad->GetPadToDieLength() ).c_str() ); @@ -1391,7 +1389,7 @@ void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const m_out->Print( 0, " (layer %s)", m_out->Quotew( aTrack->GetLayerName() ).c_str() ); } - m_out->Print( 0, " (net %d)", aTrack->GetNet() ); + m_out->Print( 0, " (net %d)", m_mapping->Translate( aTrack->GetNet() ) ); if( aTrack->GetTimeStamp() != 0 ) m_out->Print( 0, " (tstamp %lX)", aTrack->GetTimeStamp() ); @@ -1410,7 +1408,7 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const // so be sure a dummy value is stored, just for ZONE_CONTAINER compatibility // (perhaps netcode and netname should be not stored) m_out->Print( aNestLevel, "(zone (net %d) (net_name %s)", - aZone->GetIsKeepout() ? 0 : aZone->GetNet(), + aZone->GetIsKeepout() ? 0 : m_mapping->Translate( aZone->GetNet() ), m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() ); formatLayer( aZone ); @@ -1627,20 +1625,11 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const } -PCB_IO::PCB_IO() : - m_cache( 0 ), - m_ctl( CTL_FOR_BOARD ), // expecting to OUTPUTFORMAT into BOARD files. - m_parser( new PCB_PARSER() ) -{ - init( 0 ); - m_out = &m_sf; -} - - PCB_IO::PCB_IO( int aControlFlags ) : m_cache( 0 ), m_ctl( aControlFlags ), - m_parser( new PCB_PARSER() ) + m_parser( new PCB_PARSER() ), + m_mapping( new NETINFO_MAPPING() ) { init( 0 ); m_out = &m_sf; @@ -1651,6 +1640,7 @@ PCB_IO::~PCB_IO() { delete m_cache; delete m_parser; + delete m_mapping; } diff --git a/pcbnew/kicad_plugin.h b/pcbnew/kicad_plugin.h index ce7c40ef38..95986e7531 100644 --- a/pcbnew/kicad_plugin.h +++ b/pcbnew/kicad_plugin.h @@ -32,6 +32,7 @@ class BOARD; class BOARD_ITEM; class FP_CACHE; class PCB_PARSER; +class NETINFO_MAPPING; /// Current s-expression file format version. 2 was the last legacy format version. @@ -122,9 +123,7 @@ public: //------------------------------------------------------------- - PCB_IO(); - - PCB_IO( int aControlFlags ); + PCB_IO( int aControlFlags = CTL_FOR_BOARD ); ~PCB_IO(); @@ -171,6 +170,8 @@ protected: OUTPUTFORMATTER* m_out; ///< output any Format()s to this, no ownership int m_ctl; PCB_PARSER* m_parser; + NETINFO_MAPPING* m_mapping; ///< mapping for net codes, so only not empty net codes + ///< are stored with consecutive integers as net codes /// we only cache one footprint library, this determines which one. void cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName = wxEmptyString ); diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 8b09403302..6e08682234 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2899,6 +2899,8 @@ do { \ void LEGACY_PLUGIN::SaveBOARD( const BOARD* aBoard ) const { + m_mapping->SetBoard( aBoard ); + saveGENERAL( aBoard ); saveSHEET( aBoard ); @@ -2947,7 +2949,7 @@ void LEGACY_PLUGIN::saveGENERAL( const BOARD* aBoard ) const fprintf( m_fp, "Nzone %d\n", aBoard->GetNumSegmZone() ); fprintf( m_fp, "BoardThickness %s\n", fmtBIU( aBoard->GetDesignSettings().GetBoardThickness() ).c_str() ); fprintf( m_fp, "Nmodule %d\n", aBoard->m_Modules.GetCount() ); - fprintf( m_fp, "Nnets %d\n", aBoard->GetNetCount() ); + fprintf( m_fp, "Nnets %d\n", m_mapping->GetSize() ); fprintf( m_fp, "$EndGENERAL\n\n" ); } @@ -3088,9 +3090,11 @@ void LEGACY_PLUGIN::saveSETUP( const BOARD* aBoard ) const void LEGACY_PLUGIN::saveBOARD_ITEMS( const BOARD* aBoard ) const { // save the nets - int netcount = aBoard->GetNetCount(); - for( int i = 0; i < netcount; ++i ) - saveNETINFO_ITEM( aBoard->FindNet( i ) ); + for( NETINFO_MAPPING::iterator net = m_mapping->begin(), netEnd = m_mapping->end(); + net != netEnd; ++net ) + { + saveNETINFO_ITEM( *net ); + } // Saved nets do not include netclass names, so save netclasses after nets. saveNETCLASSES( &aBoard->m_NetClasses ); @@ -3148,7 +3152,8 @@ void LEGACY_PLUGIN::saveBOARD_ITEMS( const BOARD* aBoard ) const void LEGACY_PLUGIN::saveNETINFO_ITEM( const NETINFO_ITEM* aNet ) const { fprintf( m_fp, "$EQUIPOT\n" ); - fprintf( m_fp, "Na %d %s\n", aNet->GetNet(), EscapedUTF8( aNet->GetNetname() ).c_str() ); + fprintf( m_fp, "Na %d %s\n", m_mapping->Translate( aNet->GetNet() ), + EscapedUTF8( aNet->GetNetname() ).c_str() ); fprintf( m_fp, "St %s\n", "~" ); fprintf( m_fp, "$EndEQUIPOT\n" ); @@ -4417,7 +4422,8 @@ LEGACY_PLUGIN::LEGACY_PLUGIN() : m_props( 0 ), m_reader( 0 ), m_fp( 0 ), - m_cache( 0 ) + m_cache( 0 ), + m_mapping( new NETINFO_MAPPING() ) { init( NULL ); } @@ -4426,4 +4432,5 @@ LEGACY_PLUGIN::LEGACY_PLUGIN() : LEGACY_PLUGIN::~LEGACY_PLUGIN() { delete m_cache; + delete m_mapping; } diff --git a/pcbnew/legacy_plugin.h b/pcbnew/legacy_plugin.h index c5eba40083..dec3bfcbac 100644 --- a/pcbnew/legacy_plugin.h +++ b/pcbnew/legacy_plugin.h @@ -44,6 +44,7 @@ class NETCLASSES; class ZONE_CONTAINER; class DIMENSION; class NETINFO_ITEM; +class NETINFO_MAPPING; class TEXTE_MODULE; class EDGE_MODULE; class TRACK; @@ -124,6 +125,9 @@ protected: int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing? LP_CACHE* m_cache; + NETINFO_MAPPING* m_mapping; ///< mapping for net codes, so only not empty net codes + ///< are stored with consecutive integers as net codes + /// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed. void init( const PROPERTIES* aProperties ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index db9ed25acf..d7456b06ea 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -2417,13 +2418,19 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) // Init the net code only, not the netname, to be sure // the zone net name is the name read in file. // (When mismatch, the user will be prompted in DRC, to fix the actual name) - zone->BOARD_CONNECTED_ITEM::SetNet( parseInt( "net number" ) ); + zone->SetNet( parseInt( "net number" ) ); NeedRIGHT(); break; case T_net_name: NeedSYMBOLorNUMBER(); - assert( m_board->FindNet( zone->GetNet() )->GetNetname() == FromUTF8() ); + if( m_board->FindNet( zone->GetNet() )->GetNetname() != FromUTF8() ) + { + DisplayError( NULL, wxString::Format( _( "There is a zone that belongs to a not " + "existing net (%s), you should verify it." ), + FromUTF8() ) ); + zone->SetNet( NETINFO_LIST::UNCONNECTED ); + } NeedRIGHT(); break; From 2b8f9fc62158369a2bf55ed4b417a864206d4704 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 28 Jan 2014 16:23:08 +0100 Subject: [PATCH 50/84] Added BOARD_[CONNECTED_]ITEM::IsConnected() for checking if a BOARD_ITEM is BOARD_CONNECTED_ITEM as well. --- include/class_board_item.h | 10 ++++++++++ pcbnew/class_board_connected_item.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/include/class_board_item.h b/include/class_board_item.h index b6e5e905a6..ceb428af5e 100644 --- a/include/class_board_item.h +++ b/include/class_board_item.h @@ -93,6 +93,16 @@ public: virtual void SetPosition( const wxPoint& aPos ) = 0; + /** + * Function IsConnected() + * Returns information if the object is derived from BOARD_CONNECTED_ITEM. + * @return True if the object is of BOARD_CONNECTED_ITEM type, false otherwise. + */ + virtual bool IsConnected() const + { + return false; + } + /** * A value of wxPoint(0,0) which can be passed to the Draw() functions. */ diff --git a/pcbnew/class_board_connected_item.h b/pcbnew/class_board_connected_item.h index b7a059c9f4..eab6d310fd 100644 --- a/pcbnew/class_board_connected_item.h +++ b/pcbnew/class_board_connected_item.h @@ -70,6 +70,12 @@ public: BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem ); + ///> @copydoc BOARD_ITEM::IsConnected() + bool IsConnected() const + { + return true; + } + /** * Function GetNet * @return int - the net code. From 83f7c7e35e8bf16f9317fc957c03593039b76ae5 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 28 Jan 2014 16:30:58 +0100 Subject: [PATCH 51/84] Added RN_DATA::Add()/Remove() methods. RN_DATA::Update()/AddSimple() take BOARD_ITEM* as the parameter (instead of being split to versions with BOARD_CONNECTED_ITEM* and MODULE*), to make the code look clearer. --- pcbnew/ratsnest_data.cpp | 177 +++++++++++++++++++++++------------ pcbnew/ratsnest_data.h | 35 ++++--- pcbnew/router/pns_router.cpp | 2 +- pcbnew/tools/edit_tool.cpp | 17 +--- 4 files changed, 140 insertions(+), 91 deletions(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index f33d5e96e6..ea9d8a7c57 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -673,6 +673,39 @@ std::list RN_NET::GetNodes( const BOARD_CONNECTED_ITEM* aItem ) con } +void RN_DATA::AddSimple( const BOARD_ITEM* aItem ) +{ + int net; + + if( aItem->IsConnected() ) + { + const BOARD_CONNECTED_ITEM* item = static_cast( aItem ); + net = item->GetNet(); + + if( net < 1 ) // do not process unconnected items + return; + + // Get list of nodes responding to the item + std::list nodes = m_nets[net].GetNodes( item ); + std::list::iterator it, itEnd; + + for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it ) + m_nets[net].AddSimpleNode( *it ); + } + else if( aItem->Type() == PCB_MODULE_T ) + { + const MODULE* module = static_cast( aItem ); + + for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + AddSimple( pad ); + + return; + } + else + return; +} + + void RN_NET::ClearSimple() { BOOST_FOREACH( const RN_NODE_PTR& node, m_simpleNodes ) @@ -682,28 +715,6 @@ void RN_NET::ClearSimple() } -void RN_DATA::AddSimple( const BOARD_CONNECTED_ITEM* aItem ) -{ - int net = aItem->GetNet(); - if( net < 1 ) // do not process unconnected items - return; - - // Get list of nodes responding to the item - std::list nodes = m_nets[net].GetNodes( aItem ); - std::list::iterator it, itEnd; - - for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it ) - m_nets[net].AddSimpleNode( *it ); -} - - -void RN_DATA::AddSimple( const MODULE* aModule ) -{ - for( const D_PAD* pad = aModule->Pads().GetFirst(); pad; pad = pad->Next() ) - AddSimple( pad ); -} - - void RN_NET::processZones() { BOOST_FOREACH( std::deque& edges, m_zoneConnections | boost::adaptors::map_values ) @@ -762,45 +773,51 @@ void RN_DATA::updateNet( int aNetCode ) } -void RN_DATA::Update( const BOARD_CONNECTED_ITEM* aItem ) +void RN_DATA::Add( const BOARD_ITEM* aItem ) { - int net = aItem->GetNet(); - if( net < 1 ) // do not process unconnected items + int net; + + if( aItem->IsConnected() ) + { + net = static_cast( aItem )->GetNet(); + if( net < 1 ) // do not process unconnected items + return; + } + else if( aItem->Type() == PCB_MODULE_T ) + { + const MODULE* module = static_cast( aItem ); + for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + { + net = pad->GetNet(); + + if( net < 1 ) // do not process unconnected items + continue; + + m_nets[net].AddItem( pad ); + } + + return; + } + else return; switch( aItem->Type() ) { case PCB_PAD_T: - { - const D_PAD* pad = static_cast( aItem ); - m_nets[net].RemoveItem( pad ); - m_nets[net].AddItem( pad ); - } - break; + m_nets[net].AddItem( static_cast( aItem ) ); + break; case PCB_TRACE_T: - { - const TRACK* track = static_cast( aItem ); - m_nets[net].RemoveItem( track ); - m_nets[net].AddItem( track ); - } - break; + m_nets[net].AddItem( static_cast( aItem ) ); + break; case PCB_VIA_T: - { - const SEGVIA* via = static_cast( aItem ); - m_nets[net].RemoveItem( via ); - m_nets[net].AddItem( via ); - } - break; + m_nets[net].AddItem( static_cast( aItem ) ); + break; case PCB_ZONE_AREA_T: - { - const ZONE_CONTAINER* zone = static_cast( aItem ); - m_nets[net].RemoveItem( zone); - m_nets[net].AddItem( zone ); - } - break; + m_nets[net].AddItem( static_cast( aItem ) ); + break; default: break; @@ -808,18 +825,62 @@ void RN_DATA::Update( const BOARD_CONNECTED_ITEM* aItem ) } -void RN_DATA::Update( const MODULE* aModule ) +void RN_DATA::Remove( const BOARD_ITEM* aItem ) { - for( const D_PAD* pad = aModule->Pads().GetFirst(); pad; pad = pad->Next() ) - { - int net = pad->GetNet(); + int net; - if( net > 0 ) // do not process unconnected items - { - m_nets[net].RemoveItem( pad ); - m_nets[net].AddItem( pad ); - } + if( aItem->IsConnected() ) + { + net = static_cast( aItem )->GetNet(); + if( net < 1 ) // do not process unconnected items + return; } + else if( aItem->Type() == PCB_MODULE_T ) + { + const MODULE* module = static_cast( aItem ); + for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + { + net = pad->GetNet(); + + if( net < 1 ) // do not process unconnected items + continue; + + m_nets[net].RemoveItem( pad ); + } + + return; + } + else + return; + + switch( aItem->Type() ) + { + case PCB_PAD_T: + m_nets[net].RemoveItem( static_cast( aItem ) ); + break; + + case PCB_TRACE_T: + m_nets[net].RemoveItem( static_cast( aItem ) ); + break; + + case PCB_VIA_T: + m_nets[net].RemoveItem( static_cast( aItem ) ); + break; + + case PCB_ZONE_AREA_T: + m_nets[net].RemoveItem( static_cast( aItem ) ); + break; + + default: + break; + } +} + + +void RN_DATA::Update( const BOARD_ITEM* aItem ) +{ + Remove( aItem ); + Add( aItem ); } diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index f8ffbf2406..860fffa5fa 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -524,34 +524,33 @@ public: RN_DATA( const BOARD* aBoard ) : m_board( aBoard ) {} /** - * Function UpdateItem() - * Updates ratsnest data for an item. - * @param aItem is an item to be updated. + * Function Add() + * Adds an item to the ratsnest data. + * @param aItem is an item to be added. */ - void Update( const BOARD_CONNECTED_ITEM* aItem ); + void Add( const BOARD_ITEM* aItem ); /** - * Function UpdateItem() - * Updates ratsnest data for a module. - * @param aItem is a module to be updated. + * Function Remove() + * Removes an item from the ratsnest data. + * @param aItem is an item to be updated. */ - void Update( const MODULE* aModule ); + void Remove( const BOARD_ITEM* aItem ); + + /** + * Function Update() + * Updates the ratsnest data for an item. + * @param aItem is an item to be updated. + */ + void Update( const BOARD_ITEM* aItem ); /** * Function AddSimple() * Sets an item to be drawn in simple mode (ie. one line per node, instead of full ratsnest). - * It is used for drawing temporary ratsnest, eg. while moving an item. + * It is used for drawing quick, temporary ratsnest, eg. while moving an item. * @param aItem is an item to be drawn in simple node. */ - void AddSimple( const BOARD_CONNECTED_ITEM* aItem ); - - /** - * Function AddSimple() - * Sets a module to be drawn in simple mode (ie. one line per node, instead of full ratsnest). - * It is used for drawing temporary ratsnest, eg. while moving a module. - * @param aModule is a module to be drawn in simple node. - */ - void AddSimple( const MODULE* aModule ); + void AddSimple( const BOARD_ITEM* aItem ); /** * Function ClearSimple() diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index e70fe550bf..9373ff985f 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -631,7 +631,7 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) newBI->ClearFlags(); m_view->Add( newBI ); m_board->Add( newBI ); - m_board->GetRatsnest()->Update( static_cast( newBI ) ); + m_board->GetRatsnest()->Update( newBI ); newBI->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 277fefa8c1..706134d1bc 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -376,20 +376,9 @@ void EDIT_TOOL::updateRatsnest( bool aRedraw ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - if( item->Type() == PCB_PAD_T || item->Type() == PCB_TRACE_T || - item->Type() == PCB_VIA_T || item->Type() == PCB_ZONE_AREA_T ) - { - ratsnest->Update( static_cast( item ) ); + ratsnest->Update( static_cast( item ) ); - if( aRedraw ) - ratsnest->AddSimple( static_cast( item ) ); - } - else if( item->Type() == PCB_MODULE_T ) - { - ratsnest->Update( static_cast( item ) ); - - if( aRedraw ) - ratsnest->AddSimple( static_cast( item ) ); - } + if( aRedraw ) + ratsnest->AddSimple( item ); } } From bec24b6c7fd090a0ef50a40629699d732a451f66 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 29 Jan 2014 10:17:14 +0100 Subject: [PATCH 52/84] Ratsnest is updated after rotation, flip, undo/redo operations. Fixed crashes of ratsnest when a pointer for an item has changed after undo/redo operations. Vias are properly removed from ratsnest (pcbnew/class_board.cpp). --- pcbnew/board_undo_redo.cpp | 24 ++++++++++++++++++------ pcbnew/class_board.cpp | 9 ++++++++- pcbnew/tools/edit_tool.cpp | 19 ++++++++++++------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index a0bb32575c..484b76fa05 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -41,6 +41,8 @@ #include #include +#include + #include #include @@ -453,13 +455,14 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed bool not_found = false; bool reBuild_ratsnest = false; KIGFX::VIEW* view = GetGalCanvas()->GetView(); + RN_DATA* ratsnest = GetBoard()->GetRatsnest(); // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command bool build_item_list = true; // if true the list of existing items must be rebuilt - for( int ii = aList->GetCount()-1; ii >= 0 ; ii-- ) + for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- ) { item = (BOARD_ITEM*) aList->GetPickedItem( ii ); wxASSERT( item ); @@ -519,8 +522,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* oldModule = static_cast( item ); - oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), - view ) ); + oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), view ) ); + oldModule->RunOnChildren( std::bind1st( std::mem_fun( &RN_DATA::Remove ), ratsnest ) ); } item->SwapData( image ); @@ -530,8 +533,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* newModule = static_cast( item ); - newModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), - view ) ); + newModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), view ) ); + newModule->RunOnChildren( std::bind1st( std::mem_fun( &RN_DATA::Add ), ratsnest ) ); } item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); @@ -577,11 +580,13 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? m_rotationAngle : -m_rotationAngle ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -m_rotationAngle : m_rotationAngle ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_FLIPPED: @@ -598,6 +603,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed } break; } + + ratsnest->Update( item ); } if( not_found ) @@ -605,7 +612,12 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed // Rebuild pointers and ratsnest that can be changed. if( reBuild_ratsnest && aRebuildRatsnet ) - Compile_Ratsnest( NULL, true ); + { + if( IsGalCanvasActive() ) + ratsnest->Recalculate(); + else + Compile_Ratsnest( NULL, true ); + } } diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 446f1f5bf3..5c32b53881 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -895,7 +895,6 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) break; case PCB_TRACE_T: - case PCB_VIA_T: { TRACK* track = static_cast( aBoardItem ); m_Track.Remove( track ); @@ -903,6 +902,14 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) } break; + case PCB_VIA_T: + { + SEGVIA* via = static_cast( aBoardItem ); + m_Track.Remove( via ); + m_ratsnest->GetNets()[via->GetNet()].RemoveItem( via ); + } + break; + case PCB_ZONE_T: m_Zone.Remove( (SEGZONE*) aBoardItem ); break; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 706134d1bc..451164bf23 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -119,7 +119,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { Remove( aEvent ); - break; + break; // exit the loop, as there is no further processing for removed items } } @@ -207,6 +207,7 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) setTransitions(); updateRatsnest( true ); + getModel( PCB_T )->GetRatsnest()->Recalculate(); return 0; } @@ -233,12 +234,14 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } - if( m_dragging ) - selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - setTransitions(); updateRatsnest( true ); + if( m_dragging ) + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + else + getModel( PCB_T )->GetRatsnest()->Recalculate(); + return 0; } @@ -264,12 +267,14 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } - if( m_dragging ) - selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - setTransitions(); updateRatsnest( true ); + if( m_dragging ) + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + else + getModel( PCB_T )->GetRatsnest()->Recalculate(); + return 0; } From b52e5fabdaff267d395cab1cd078e04d7a4f3b9a Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 29 Jan 2014 14:51:50 +0100 Subject: [PATCH 53/84] Ratsnest lines are drawn using a more transparent color. BOARD::chainMarkedSegments() uses a safer method for gettings pads. --- pcbnew/class_board.cpp | 2 +- pcbnew/ratsnest_viewitem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 5c32b53881..90d8ad7b20 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -206,7 +206,7 @@ void BOARD::chainMarkedSegments( wxPoint aPosition, LAYER_MSK aLayerMask, TRACK_ */ for( ; ; ) { - if( GetPadFast( aPosition, aLayerMask ) != NULL ) + if( GetPad( aPosition, aLayerMask ) != NULL ) return; /* Test for a via: a via changes the layer mask and can connect a lot diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index 282c0998a0..634a0d57c9 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -57,7 +57,7 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const aGal->SetIsStroke( true ); aGal->SetIsFill( false ); aGal->SetLineWidth( 1.0 ); - aGal->SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 0.4 ) ); + aGal->SetStrokeColor( COLOR4D( 0.8, 0.8, 0.8, 0.2 ) ); // Draw the temporary ratsnest BOOST_FOREACH( const RN_NET& net, m_data->GetNets() ) From af350eb1e61a4250bfe828cfa73545a4fd8fefaf Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 29 Jan 2014 15:24:19 +0100 Subject: [PATCH 54/84] RN_DATA::GetNets() -> RN_DATA::GetNet() with an assert to check if someone calls it for the unconnected net. Only items that belong to a net are removed from ratsnest. --- pcbnew/class_board.cpp | 16 ++++++++++++---- pcbnew/ratsnest_data.h | 23 ++++++++++++++++++----- pcbnew/ratsnest_viewitem.cpp | 6 ++++-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 90d8ad7b20..896e44b8f6 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -880,7 +880,8 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) } } - m_ratsnest->GetNets()[zone->GetNet()].RemoveItem( zone ); + if( zone->GetNet() > 0 ) + m_ratsnest->GetNet( zone->GetNet() ).RemoveItem( zone ); } break; @@ -890,7 +891,10 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) m_Modules.Remove( (MODULE*) aBoardItem ); for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - m_ratsnest->GetNets()[pad->GetNet()].RemoveItem( pad ); + { + if( pad->GetNet() > 0 ) + m_ratsnest->GetNet( pad->GetNet() ).RemoveItem( pad ); + } } break; @@ -898,7 +902,9 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) { TRACK* track = static_cast( aBoardItem ); m_Track.Remove( track ); - m_ratsnest->GetNets()[track->GetNet()].RemoveItem( track ); + + if( track->GetNet() > 0 ) + m_ratsnest->GetNet( track->GetNet() ).RemoveItem( track ); } break; @@ -906,7 +912,9 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) { SEGVIA* via = static_cast( aBoardItem ); m_Track.Remove( via ); - m_ratsnest->GetNets()[via->GetNet()].RemoveItem( via ); + + if( via->GetNet() > 0 ) + m_ratsnest->GetNet( via->GetNet() ).RemoveItem( via ); } break; diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index 860fffa5fa..4340c74e78 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -573,13 +573,26 @@ public: void Recalculate( int aNet = -1 ); /** - * Function GetNets() - * Returns ratsnest grouped by net numbers. - * @return Vector of ratsnest grouped by net numbers. + * Function GetNetCount() + * Returns the number of nets handled by the ratsnest. + * @return Number of the nets. */ - std::vector& GetNets() + int GetNetCount() const { - return m_nets; + return m_nets.size(); + } + + /** + * Function GetNet() + * Returns ratsnest grouped by net numbers. + * @param aNetCode is the net code. + * @return Ratsnest data for a specified net. + */ + RN_NET& GetNet( int aNetCode ) + { + assert( aNetCode > 0 ); // ratsnest does not handle the unconnected net + + return m_nets[aNetCode]; } protected: diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index 634a0d57c9..0e23b00306 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -59,9 +59,11 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const aGal->SetLineWidth( 1.0 ); aGal->SetStrokeColor( COLOR4D( 0.8, 0.8, 0.8, 0.2 ) ); - // Draw the temporary ratsnest - BOOST_FOREACH( const RN_NET& net, m_data->GetNets() ) + // Draw the temporary ratsnest (skip the unconnected net [net code == 0]) + for( int i = 1; i < m_data->GetNetCount(); ++i ) { + const RN_NET& net = m_data->GetNet( i ); + if( !net.IsVisible() ) continue; From 57bfaca13133438240fa114651184ab746f59d82 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 29 Jan 2014 15:35:25 +0100 Subject: [PATCH 55/84] PNS_ITEM::m_parent: BOARD_ITEM->BOARD_CONNECTED_ITEM --- pcbnew/router/pns_item.h | 8 ++++---- pcbnew/router/pns_router.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pcbnew/router/pns_item.h b/pcbnew/router/pns_item.h index e9c856e086..c375a7ada5 100644 --- a/pcbnew/router/pns_item.h +++ b/pcbnew/router/pns_item.h @@ -28,7 +28,7 @@ #include "pns_layerset.h" -class BOARD_ITEM; +class BOARD_CONNECTED_ITEM; class PNS_NODE; /** @@ -94,8 +94,8 @@ public: const std::string GetKindStr() const; ///> Gets/Sets the corresponding parent object in the host application's model (pcbnew) - void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; } - BOARD_ITEM* GetParent() const { return m_parent; } + void SetParent( BOARD_CONNECTED_ITEM* aParent ) { m_parent = aParent; } + BOARD_CONNECTED_ITEM* GetParent() const { return m_parent; } ///> Net accessors int GetNet() const { return m_net; } @@ -145,7 +145,7 @@ private: protected: PnsKind m_kind; - BOARD_ITEM* m_parent; + BOARD_CONNECTED_ITEM* m_parent; PNS_NODE* m_world; PNS_NODE* m_owner; PNS_LAYERSET m_layers; diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 9373ff985f..991dd71e84 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -580,7 +580,7 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) for( unsigned int i = 0; i < removed.size(); i++ ) { - BOARD_ITEM* parent = removed[i]->GetParent(); + BOARD_CONNECTED_ITEM* parent = removed[i]->GetParent(); if( parent ) { @@ -591,7 +591,7 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) BOOST_FOREACH( PNS_ITEM* item, added ) { - BOARD_ITEM* newBI = NULL; + BOARD_CONNECTED_ITEM* newBI = NULL; switch( item->GetKind() ) { From a73e3865055ebb7b8339815628ce8c993b1a7763 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 30 Jan 2014 11:18:58 +0100 Subject: [PATCH 56/84] Added a new tool event: TA_UNDO_REDO, sent after undo/redo operation is issued. --- common/tool/tool_event.cpp | 1 + include/tool/tool_event.h | 5 ++++- include/wxPcbStruct.h | 4 ++-- pcbnew/board_undo_redo.cpp | 22 ++++++++++------------ pcbnew/tools/selection_tool.cpp | 6 ++++++ 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/common/tool/tool_event.cpp b/common/tool/tool_event.cpp index 481b8c1b95..07460f3571 100644 --- a/common/tool/tool_event.cpp +++ b/common/tool/tool_event.cpp @@ -91,6 +91,7 @@ const std::string TOOL_EVENT::Format() const { TA_CANCEL_TOOL, "cancel-tool" }, { TA_CONTEXT_MENU_UPDATE, "context-menu-update" }, { TA_CONTEXT_MENU_CHOICE, "context-menu-choice" }, + { TA_UNDO_REDO, "undo-redo" }, { TA_ACTION, "action" }, { 0, "" } }; diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index a2815035d2..9acc1f8f87 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -89,8 +89,11 @@ enum TOOL_ACTIONS // closed it without selecting anything. TA_CONTEXT_MENU_CHOICE = 0x10000, + // This event is sent *after* undo/redo command is finished. + TA_UNDO_REDO = 0x20000, + // Tool action (allows to control tools) - TA_ACTION = 0x20000, + TA_ACTION = 0x40000, TA_ANY = 0xffffffff }; diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 0ce0ef4ac4..1b5bc4b299 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -704,7 +704,7 @@ public: * - Get an old version of the board from Redo list * @return none */ - void GetBoardFromRedoList( wxCommandEvent& event ); + void GetBoardFromRedoList( wxCommandEvent& aEvent ); /** * Function GetBoardFromUndoList @@ -713,7 +713,7 @@ public: * - Get an old version of the board from Undo list * @return none */ - void GetBoardFromUndoList( wxCommandEvent& event ); + void GetBoardFromUndoList( wxCommandEvent& aEvent ); /* Block operations: */ diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 484b76fa05..3112bc5e27 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -621,16 +621,11 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed } -void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event ) +void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& aEvent ) { if( GetScreen()->GetUndoCommandCount() <= 0 ) return; - // Clear the selection, as it may be altered with undone items - SELECTION_TOOL* selectionTool = static_cast( m_toolManager->FindTool( - "pcbnew.InteractiveSelection" ) ); - selectionTool->ClearSelection(); - /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); /* Undo the command */ @@ -640,21 +635,20 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event ) List->ReversePickersListOrder(); GetScreen()->PushCommandToRedoList( List ); + // Inform tools that undo has just occurred + TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); + m_toolManager->ProcessEvent( event ); + OnModify(); m_canvas->Refresh(); } -void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event ) +void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& aEvent ) { if( GetScreen()->GetRedoCommandCount() == 0 ) return; - // Clear the selection, as it may be altered with redone items - SELECTION_TOOL* selectionTool = static_cast( m_toolManager->FindTool( - "pcbnew.InteractiveSelection" ) ); - selectionTool->ClearSelection(); - /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); @@ -665,6 +659,10 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event ) List->ReversePickersListOrder(); GetScreen()->PushCommandToUndoList( List ); + // Inform tools that redo has just occurred + TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); + m_toolManager->ProcessEvent( event ); + OnModify(); m_canvas->Refresh(); } diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 4d4d8e5404..324bb50032 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -100,6 +100,12 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) // This tool never exits } + else if( evt->Action() == TA_UNDO_REDO ) + { + // Clear the selection, as it may be altered with undone items + ClearSelection(); + } + // single click? Select single object else if( evt->IsClick( BUT_LEFT ) ) { From bbb3972fb7b4e01232d831d91ad3deae84441a29 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 30 Jan 2014 11:32:08 +0100 Subject: [PATCH 57/84] Undo buffer for the PNS router. Still, it has a bug - it crashes when an undo/redo operation is performed while routing a track. --- pcbnew/router/pns_router.cpp | 5 +++-- pcbnew/router/pns_router.h | 16 ++++++++++++++++ pcbnew/router/router_tool.cpp | 11 +++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 991dd71e84..3046c13f6e 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -241,7 +241,6 @@ void PNS_ROUTER::SyncWorld() ClearWorld(); - m_clearanceFunc = new PCBNEW_CLEARANCE_FUNC( m_board ); m_world = new PNS_NODE(); m_world->SetClearanceFunctor( m_clearanceFunc ); @@ -584,8 +583,9 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) if( parent ) { - m_view->Remove( parent ); + m_undoBuffer.PushItem( ITEM_PICKER( parent, UR_DELETED ) ); m_board->Remove( parent ); + m_view->Remove( parent ); } } @@ -632,6 +632,7 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) m_view->Add( newBI ); m_board->Add( newBI ); m_board->GetRatsnest()->Update( newBI ); + m_undoBuffer.PushItem( ITEM_PICKER( newBI, UR_NEW ) ); newBI->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } } diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index 0bb882fa25..3ba7be0125 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -27,6 +27,7 @@ #include #include +#include #include "pns_routing_settings.h" #include "pns_item.h" @@ -137,6 +138,18 @@ public: const PNS_ITEMSET QueryHoverItems( const VECTOR2I& aP ); const VECTOR2I SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment ); + /** + * Returns the last changes introduced by the router. After calling the method the list of + * changes is cleared, so only the latest changes are stored. + */ + PICKED_ITEMS_LIST GetLastChanges() + { + PICKED_ITEMS_LIST copy = m_undoBuffer; + m_undoBuffer.ClearItemsList(); // TODO and delete? + + return copy; + } + private: void clearViewFlags(); @@ -188,6 +201,9 @@ private: PNS_CLEARANCE_FUNC* m_clearanceFunc; boost::unordered_set m_hiddenItems; + + ///> Stores list of modified items in the current operation + PICKED_ITEMS_LIST m_undoBuffer; }; #endif diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index b301901048..ed3eb18092 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -322,6 +322,11 @@ void ROUTER_TOOL::startRouting() updateEndItem( *evt ); m_router->Move( m_endSnapPoint, m_endItem ); } + else if( evt->Action() == TA_UNDO_REDO ) + { + std::cout << "syncing the world while routing, I am going to craaaaaaaaaaaash!" << std::endl; + m_router->SyncWorld(); + } else if( evt->IsClick( BUT_LEFT ) ) { updateEndItem( *evt ); @@ -371,6 +376,10 @@ void ROUTER_TOOL::startRouting() m_router->StopRouting(); + // Save the recent changes in the undo buffer + getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), UR_UNSPECIFIED ); + getEditFrame()->OnModify(); + ctls->SetAutoPan( false ); ctls->ForceCursorPosition( false ); highlightNet( false ); @@ -392,6 +401,8 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) { if( evt->IsCancel() ) break; // Finish + else if( evt->Action() == TA_UNDO_REDO ) + m_router->SyncWorld(); else if( evt->IsMotion() ) updateStartItem( *evt ); else if( evt->IsClick( BUT_LEFT ) ) From 510fee13587862e66c0059ec53c2200cdbb08981 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 30 Jan 2014 15:46:39 +0100 Subject: [PATCH 58/84] Another way of handling items for the ratsnest (clearer and now finally supports undo/redo of the PNS created tracks). --- pcbnew/board_undo_redo.cpp | 12 +++++----- pcbnew/class_board.cpp | 46 +++++++++----------------------------- pcbnew/pcb_parser.cpp | 4 ++-- pcbnew/pcbframe.cpp | 1 - pcbnew/ratsnest_data.cpp | 14 ++++++++---- 5 files changed, 28 insertions(+), 49 deletions(-) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 3112bc5e27..68d008bebb 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -548,8 +548,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( item ); - module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), - view ) ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), view ) ); } view->Remove( item ); @@ -563,8 +562,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( item ); - module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), - view ) ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), view ) ); } view->Add( item ); @@ -575,23 +573,27 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + ratsnest->Update( item ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? m_rotationAngle : -m_rotationAngle ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + ratsnest->Update( item ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -m_rotationAngle : m_rotationAngle ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + ratsnest->Update( item ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); + ratsnest->Update( item ); break; default: @@ -603,8 +605,6 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed } break; } - - ratsnest->Update( item ); } if( not_found ) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 896e44b8f6..da3bd81fa9 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -842,6 +842,8 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) } break; } + + m_ratsnest->Add( aBoardItem ); } @@ -867,56 +869,26 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) break; case PCB_ZONE_AREA_T: // this one uses a vector - { - ZONE_CONTAINER* zone = static_cast( aBoardItem ); - // find the item in the vector, then delete then erase it. - for( unsigned i = 0; i < m_ZoneDescriptorList.size(); ++i ) + for( unsigned i = 0; iGetNet() > 0 ) - m_ratsnest->GetNet( zone->GetNet() ).RemoveItem( zone ); - } - break; + break; case PCB_MODULE_T: - { - MODULE* module = static_cast( aBoardItem ); m_Modules.Remove( (MODULE*) aBoardItem ); - - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - { - if( pad->GetNet() > 0 ) - m_ratsnest->GetNet( pad->GetNet() ).RemoveItem( pad ); - } - } - break; + break; case PCB_TRACE_T: - { - TRACK* track = static_cast( aBoardItem ); - m_Track.Remove( track ); - - if( track->GetNet() > 0 ) - m_ratsnest->GetNet( track->GetNet() ).RemoveItem( track ); - } - break; - case PCB_VIA_T: - { - SEGVIA* via = static_cast( aBoardItem ); - m_Track.Remove( via ); - - if( via->GetNet() > 0 ) - m_ratsnest->GetNet( via->GetNet() ).RemoveItem( via ); - } - break; + m_Track.Remove( (TRACK*) aBoardItem ); + break; case PCB_ZONE_T: m_Zone.Remove( (SEGZONE*) aBoardItem ); @@ -935,6 +907,8 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) wxFAIL_MSG( wxT( "BOARD::Remove() needs more ::Type() support" ) ); } + m_ratsnest->Remove( aBoardItem ); + return aBoardItem; } diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 41fb0037e5..1f06ac2ed1 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -428,11 +428,11 @@ BOARD* PCB_PARSER::parseBOARD() throw( IO_ERROR, PARSE_ERROR ) break; case T_segment: - m_board->m_Track.Append( parseTRACK() ); + m_board->Add( parseTRACK(), ADD_APPEND ); break; case T_via: - m_board->m_Track.Append( parseSEGVIA() ); + m_board->Add( parseSEGVIA(), ADD_APPEND ); break; case T_zone: diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 8823dcf4c3..72930927ca 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -612,7 +612,6 @@ void PCB_EDIT_FRAME::ViewReloadBoard( const BOARD* aBoard ) const // Add an entry for the ratsnest RN_DATA* ratsnest = aBoard->GetRatsnest(); - ratsnest->ProcessBoard(); ratsnest->Recalculate(); view->Add( new KIGFX::RATSNEST_VIEWITEM( ratsnest ) ); diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index ea9d8a7c57..99c84d05eb 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -782,6 +782,10 @@ void RN_DATA::Add( const BOARD_ITEM* aItem ) net = static_cast( aItem )->GetNet(); if( net < 1 ) // do not process unconnected items return; + + // Autoresize + if( net >= (int) m_nets.size() ) + m_nets.resize( net + 1 ); } else if( aItem->Type() == PCB_MODULE_T ) { @@ -789,10 +793,13 @@ void RN_DATA::Add( const BOARD_ITEM* aItem ) for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) { net = pad->GetNet(); - if( net < 1 ) // do not process unconnected items continue; + // Autoresize + if( net >= (int) m_nets.size() ) + m_nets.resize( net + 1 ); + m_nets[net].AddItem( pad ); } @@ -841,7 +848,6 @@ void RN_DATA::Remove( const BOARD_ITEM* aItem ) for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) { net = pad->GetNet(); - if( net < 1 ) // do not process unconnected items continue; @@ -916,8 +922,8 @@ void RN_DATA::Recalculate( int aNet ) { if( aNet < 0 ) // Recompute everything { - // Start with net number 1, as 0 stand for not connected - for( unsigned int i = 1; i < m_board->GetNetCount(); ++i ) + // Start with net number 1, as 0 stands for not connected + for( unsigned int i = 1; i < m_nets.size(); ++i ) { // Recompute only nets that require it if( m_nets[i].IsDirty() ) From 5fea60d20f3312e21ba0546654b03e24da5a2463 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 30 Jan 2014 17:11:40 +0100 Subject: [PATCH 59/84] Fixed undo/redo while routing with the PNS error. --- pcbnew/router/router_tool.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index ed3eb18092..d7c29d10ff 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -290,6 +290,7 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) void ROUTER_TOOL::startRouting() { + bool saveUndoBuffer = true; VIEW_CONTROLS* ctls = getViewControls(); int width = getDefaultWidth( m_startItem ? m_startItem->GetNet() : -1 ); @@ -317,16 +318,16 @@ void ROUTER_TOOL::startRouting() { if( evt->IsCancel() ) break; + else if( evt->Action() == TA_UNDO_REDO ) + { + saveUndoBuffer = false; + break; + } else if( evt->IsMotion() ) { updateEndItem( *evt ); m_router->Move( m_endSnapPoint, m_endItem ); } - else if( evt->Action() == TA_UNDO_REDO ) - { - std::cout << "syncing the world while routing, I am going to craaaaaaaaaaaash!" << std::endl; - m_router->SyncWorld(); - } else if( evt->IsClick( BUT_LEFT ) ) { updateEndItem( *evt ); @@ -376,9 +377,17 @@ void ROUTER_TOOL::startRouting() m_router->StopRouting(); - // Save the recent changes in the undo buffer - getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), UR_UNSPECIFIED ); - getEditFrame()->OnModify(); + if( saveUndoBuffer ) + { + // Save the recent changes in the undo buffer + getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), UR_UNSPECIFIED ); + getEditFrame()->OnModify(); + } + else + { + // It was interrupted by TA_UNDO_REDO event, so we have to sync the world now + m_router->SyncWorld(); + } ctls->SetAutoPan( false ); ctls->ForceCursorPosition( false ); From 3827f495ca0da2b019f13b5b65e1c35d96327e57 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 11:16:01 +0100 Subject: [PATCH 60/84] Ratsnest color is saved in RENDER_SETTINGS. Temporary ratsnest is drawn using a brightened color. --- include/gal/color4d.h | 2 +- pcbnew/pcb_painter.cpp | 1 + pcbnew/ratsnest_viewitem.cpp | 10 ++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/gal/color4d.h b/include/gal/color4d.h index c476f10e0e..fb4d9d9cf3 100644 --- a/include/gal/color4d.h +++ b/include/gal/color4d.h @@ -136,7 +136,7 @@ public: * Function Brightened * Returns a color that is brighter by a given factor, without modifying object. * @param aFactor Specifies how bright the color should become (valid values: 0.0 .. 1.0). - * @return COLOR4D Highlightedd color. + * @return COLOR4D Highlighted color. */ COLOR4D Brightened( double aFactor ) const { diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 105362f83c..4ffdfa4667 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -75,6 +75,7 @@ void PCB_RENDER_SETTINGS::ImportLegacyColors( COLORS_DESIGN_SETTINGS* aSettings m_layerColors[ITEM_GAL_LAYER( PADS_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 ); m_layerColors[ITEM_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 ); m_layerColors[ITEM_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE )] = COLOR4D( 0.8, 0.8, 0.8, 0.7 ); + m_layerColors[ITEM_GAL_LAYER( RATSNEST_VISIBLE )] = COLOR4D( 0.4, 0.4, 0.4, 0.7 ); m_layerColors[ITEM_GAL_LAYER( WORKSHEET )] = COLOR4D( 0.5, 0.0, 0.0, 1.0 ); // Netnames for copper layers diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index 0e23b00306..7bf9d79568 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -57,9 +58,9 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const aGal->SetIsStroke( true ); aGal->SetIsFill( false ); aGal->SetLineWidth( 1.0 ); - aGal->SetStrokeColor( COLOR4D( 0.8, 0.8, 0.8, 0.2 ) ); + RENDER_SETTINGS* rs = m_view->GetPainter()->GetSettings(); + COLOR4D color = rs->GetColor( NULL, ITEM_GAL_LAYER( RATSNEST_VISIBLE ) ); - // Draw the temporary ratsnest (skip the unconnected net [net code == 0]) for( int i = 1; i < m_data->GetNetCount(); ++i ) { const RN_NET& net = m_data->GetNet( i ); @@ -70,6 +71,9 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const // Avoid duplicate destinations for ratsnest lines by storing already used nodes boost::unordered_set usedDestinations; + // Set brighter color for the temporary ratsnest + aGal->SetStrokeColor( color.Brightened( 0.8 ) ); + // Draw the "dynamic" ratsnest (ie. for objects that may be currently being moved) BOOST_FOREACH( const RN_NODE_PTR& node, net.GetSimpleNodes() ) { @@ -86,6 +90,8 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const } // Draw the "static" ratsnest + aGal->SetStrokeColor( color ); // using the default ratsnest color + const std::vector* edges = net.GetUnconnected(); if( edges == NULL ) continue; From 7f4648149bb04c68dfa3e34e63dd644cc01ee327 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 13:14:18 +0100 Subject: [PATCH 61/84] Ratsnest is updated after backend switch. --- pcbnew/pcbframe.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 72930927ca..15822a9b17 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -742,6 +742,9 @@ void PCB_EDIT_FRAME::UseGalCanvas( bool aEnable ) if( aEnable ) { + // Update potential changes in the ratsnest + m_Pcb->GetRatsnest()->Recalculate(); + m_toolManager->SetEnvironment( m_Pcb, GetGalCanvas()->GetView(), GetGalCanvas()->GetViewControls(), this ); m_toolManager->ResetTools( TOOL_BASE::GAL_SWITCH ); From 7f3bf1bef7490ce05c832c0c363b5d020dfb5245 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 13:19:59 +0100 Subject: [PATCH 62/84] Added missing operators==/!= for RN_NODE_PTR. Moved ClearSimple() functions back to the header file. --- pcbnew/ratsnest_data.cpp | 43 ++++++++++++++++++---------------------- pcbnew/ratsnest_data.h | 20 ++++++++++++++++--- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 99c84d05eb..95ca62e59b 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -75,10 +74,21 @@ bool sortArea( const RN_POLY& aP1, const RN_POLY& aP2 ) } +bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ) +{ + return aFirst->GetX() == aSecond->GetX() && aFirst->GetY() == aSecond->GetY(); +} + + +bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ) +{ + return aFirst->GetX() != aSecond->GetX() || aFirst->GetY() != aSecond->GetY(); +} + + bool isEdgeConnectingNode( const RN_EDGE_PTR& aEdge, const RN_NODE_PTR& aNode ) { - return ( aEdge->getSourceNode().get() == aNode.get() ) || - ( aEdge->getTargetNode().get() == aNode.get() ); + return aEdge->getSourceNode() == aNode || aEdge->getTargetNode() == aNode; } @@ -246,7 +256,7 @@ void RN_NET::compute() return; } - else if( boardNodes.size() == 1 || boardNodes.empty() ) // This case is even simpler + else if( boardNodes.size() <= 1 ) // This case is even simpler { m_rnEdges.reset( new std::vector( 0 ) ); @@ -566,17 +576,18 @@ const RN_NODE_PTR RN_NET::GetClosestNode( const RN_NODE_PTR& aNode, for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it ) { - RN_NODE_PTR baseNode = *it; + RN_NODE_PTR node = *it; // Obviously the distance between node and itself is the shortest, // that's why we have to skip it - if( *it != aNode && aFilter( baseNode ) ) + if( node != aNode && aFilter( node ) ) { - unsigned int distance = getDistance( *it, aNode ); + unsigned int distance = getDistance( node, aNode ); + if( distance < minDistance ) { minDistance = distance; - closest = *it; + closest = node; } } } @@ -706,15 +717,6 @@ void RN_DATA::AddSimple( const BOARD_ITEM* aItem ) } -void RN_NET::ClearSimple() -{ - BOOST_FOREACH( const RN_NODE_PTR& node, m_simpleNodes ) - node->SetFlag( false ); - - m_simpleNodes.clear(); -} - - void RN_NET::processZones() { BOOST_FOREACH( std::deque& edges, m_zoneConnections | boost::adaptors::map_values ) @@ -935,10 +937,3 @@ void RN_DATA::Recalculate( int aNet ) updateNet( aNet ); } } - - -void RN_DATA::ClearSimple() -{ - BOOST_FOREACH( RN_NET& net, m_nets ) - net.ClearSimple(); -} diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index 4340c74e78..d51c070ee8 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -37,6 +37,7 @@ #include #include +#include class BOARD; class BOARD_ITEM; @@ -57,6 +58,9 @@ typedef hed::EdgeMST RN_EDGE_MST; typedef boost::shared_ptr RN_EDGE_MST_PTR; typedef hed::Triangulation TRIANGULATOR; +bool operator==( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ); +bool operator!=( const RN_NODE_PTR& aFirst, const RN_NODE_PTR& aSecond ); + ///> General interface for filtering out nodes in search functions. struct RN_NODE_FILTER : public std::unary_function { @@ -83,7 +87,7 @@ struct RN_NODE_COMPARE : std::binary_function { bool operator()( const RN_NODE_PTR& aNode1, const RN_NODE_PTR& aNode2 ) const { - return ( aNode1->GetX() == aNode2->GetX() && aNode1->GetY() == aNode2->GetY() ); + return aNode1 == aNode2; } }; @@ -461,7 +465,13 @@ public: * Function ClearSimple() * Removes all nodes and edges that are used for displaying ratsnest in simple mode. */ - void ClearSimple(); + void ClearSimple() + { + BOOST_FOREACH( const RN_NODE_PTR& node, m_simpleNodes ) + node->SetFlag( false ); + + m_simpleNodes.clear(); + } protected: ///> Validates edge, ie. modifies source and target nodes for an edge @@ -556,7 +566,11 @@ public: * Function ClearSimple() * Clears the list of nodes for which ratsnest is drawn in simple mode (one line per node). */ - void ClearSimple(); + void ClearSimple() + { + BOOST_FOREACH( RN_NET& net, m_nets ) + net.ClearSimple(); + } /** * Function ProcessBoard() From 630a3fb1b93b8dc32b11e06208a5f6fa827350a3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 14:41:15 +0100 Subject: [PATCH 63/84] Safer RN_NET::GetNodes() --- pcbnew/ratsnest_data.cpp | 67 +++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 95ca62e59b..948362317f 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -548,15 +548,17 @@ const RN_NODE_PTR RN_NET::GetClosestNode( const RN_NODE_PTR& aNode ) const for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it ) { + RN_NODE_PTR node = *it; + // Obviously the distance between node and itself is the shortest, // that's why we have to skip it - if( *it != aNode ) + if( node != aNode ) { - unsigned int distance = getDistance( *it, aNode ); + unsigned int distance = getDistance( node, aNode ); if( distance < minDistance ) { minDistance = distance; - closest = *it; + closest = node; } } } @@ -650,34 +652,41 @@ std::list RN_NET::GetNodes( const BOARD_CONNECTED_ITEM* aItem ) con { std::list nodes; - switch( aItem->Type() ) + try { - case PCB_PAD_T: - { - const D_PAD* pad = static_cast( aItem ); - nodes.push_back( m_pads.at( pad ) ); - } - break; - - case PCB_VIA_T: - { - const SEGVIA* via = static_cast( aItem ); - nodes.push_back( m_vias.at( via ) ); - } - break; - - case PCB_TRACE_T: - { - const TRACK* track = static_cast( aItem ); - RN_EDGE_PTR edge = m_tracks.at( track ); - - nodes.push_back( edge->getSourceNode() ); - nodes.push_back( edge->getTargetNode() ); - } - break; - - default: + switch( aItem->Type() ) + { + case PCB_PAD_T: + { + const D_PAD* pad = static_cast( aItem ); + nodes.push_back( m_pads.at( pad ) ); + } break; + + case PCB_VIA_T: + { + const SEGVIA* via = static_cast( aItem ); + nodes.push_back( m_vias.at( via ) ); + } + break; + + case PCB_TRACE_T: + { + const TRACK* track = static_cast( aItem ); + RN_EDGE_PTR edge = m_tracks.at( track ); + + nodes.push_back( edge->getSourceNode() ); + nodes.push_back( edge->getTargetNode() ); + } + break; + + default: + break; + } + } + catch ( ... ) + { + return nodes; } return nodes; From 24ba75ba9207bd610d7b7f830ee7541a1f9ca3f3 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 14:52:01 +0100 Subject: [PATCH 64/84] Minor change to clearing selection handling. --- pcbnew/tools/selection_tool.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 324bb50032..f226709a86 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -94,8 +94,8 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) if( evt->IsCancel() ) { - if( !m_selection.Empty() ) // Cancel event deselects items... - ClearSelection(); + // Cancel event deselects items... + ClearSelection(); // This tool never exits } @@ -109,7 +109,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) // single click? Select single object else if( evt->IsClick( BUT_LEFT ) ) { - if( !m_additive && m_selection.Size() > 1 ) + if( !m_additive ) ClearSelection(); selectSingle( evt->Position() ); @@ -159,6 +159,9 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) void SELECTION_TOOL::ClearSelection() { + if( m_selection.Empty() ) + return; + KIGFX::VIEW_GROUP::const_iter it, it_end; // Restore the initial properties From 3e2e11fb42277051093e5fd8d1fd58c53ae0c8d1 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 16:08:20 +0100 Subject: [PATCH 65/84] Undo/redo buffer fixed once again.. --- include/tool/tool_event.h | 2 +- pcbnew/board_undo_redo.cpp | 20 ++++++++++---------- pcbnew/router/router_tool.cpp | 15 +++++++++++---- pcbnew/router/router_tool.h | 3 +++ 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/include/tool/tool_event.h b/include/tool/tool_event.h index 9acc1f8f87..46b06e1eed 100644 --- a/include/tool/tool_event.h +++ b/include/tool/tool_event.h @@ -89,7 +89,7 @@ enum TOOL_ACTIONS // closed it without selecting anything. TA_CONTEXT_MENU_CHOICE = 0x10000, - // This event is sent *after* undo/redo command is finished. + // This event is sent *before* undo/redo command is performed. TA_UNDO_REDO = 0x20000, // Tool action (allows to control tools) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 68d008bebb..970ea3167d 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -523,8 +523,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed { MODULE* oldModule = static_cast( item ); oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), view ) ); - oldModule->RunOnChildren( std::bind1st( std::mem_fun( &RN_DATA::Remove ), ratsnest ) ); } + ratsnest->Remove( item ); item->SwapData( image ); @@ -534,8 +534,8 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed { MODULE* newModule = static_cast( item ); newModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), view ) ); - newModule->RunOnChildren( std::bind1st( std::mem_fun( &RN_DATA::Add ), ratsnest ) ); } + ratsnest->Add( item ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } @@ -626,6 +626,10 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& aEvent ) if( GetScreen()->GetUndoCommandCount() <= 0 ) return; + // Inform tools that undo command was issued + TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); + m_toolManager->ProcessEvent( event ); + /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); /* Undo the command */ @@ -635,10 +639,6 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& aEvent ) List->ReversePickersListOrder(); GetScreen()->PushCommandToRedoList( List ); - // Inform tools that undo has just occurred - TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); - OnModify(); m_canvas->Refresh(); } @@ -649,6 +649,10 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& aEvent ) if( GetScreen()->GetRedoCommandCount() == 0 ) return; + // Inform tools that redo command was issued + TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); + m_toolManager->ProcessEvent( event ); + /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); @@ -659,10 +663,6 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& aEvent ) List->ReversePickersListOrder(); GetScreen()->PushCommandToUndoList( List ); - // Inform tools that redo has just occurred - TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); - OnModify(); m_canvas->Refresh(); } diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index d7c29d10ff..94475132e2 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -31,7 +31,6 @@ #include #include -#include #include "router_tool.h" #include "pns_segment.h" @@ -82,6 +81,7 @@ void ROUTER_TOOL::Reset( RESET_REASON aReason ) m_router->ClearWorld(); m_router->SetBoard( getModel( PCB_T ) ); m_router->SyncWorld(); + m_needsSync = false; if( getView() ) m_router->SetView( getView() ); @@ -380,13 +380,14 @@ void ROUTER_TOOL::startRouting() if( saveUndoBuffer ) { // Save the recent changes in the undo buffer - getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), UR_UNSPECIFIED ); + getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), + UR_UNSPECIFIED ); getEditFrame()->OnModify(); } else { // It was interrupted by TA_UNDO_REDO event, so we have to sync the world now - m_router->SyncWorld(); + m_needsSync = true; } ctls->SetAutoPan( false ); @@ -408,10 +409,16 @@ int ROUTER_TOOL::Main( TOOL_EVENT& aEvent ) // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { + if( m_needsSync ) + { + m_router->SyncWorld(); + m_needsSync = false; + } + if( evt->IsCancel() ) break; // Finish else if( evt->Action() == TA_UNDO_REDO ) - m_router->SyncWorld(); + m_needsSync = true; else if( evt->IsMotion() ) updateStartItem( *evt ); else if( evt->IsClick( BUT_LEFT ) ) diff --git a/pcbnew/router/router_tool.h b/pcbnew/router/router_tool.h index c43283a051..42bbceb19c 100644 --- a/pcbnew/router/router_tool.h +++ b/pcbnew/router/router_tool.h @@ -72,6 +72,9 @@ private: PNS_ITEM* m_endItem; VECTOR2I m_endSnapPoint; + ///> Flag marking that the router's world needs syncing. + bool m_needsSync; + /*boost::shared_ptr m_menu;*/ CONTEXT_MENU* m_menu; }; From 0c67e26e9c4fd841a03923fd52f61ace949b3845 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Fri, 31 Jan 2014 18:05:11 +0100 Subject: [PATCH 66/84] Added the dynamic ratsnest for the tracks that are currently routed with the PNS router. --- pcbnew/ratsnest_data.cpp | 71 ++++++++++++++++++++++++++--------- pcbnew/ratsnest_data.h | 51 +++++++++++++++++++++---- pcbnew/ratsnest_viewitem.cpp | 11 +++--- pcbnew/router/pns_router.h | 17 ++++++--- pcbnew/router/router_tool.cpp | 27 +++++++++++++ 5 files changed, 141 insertions(+), 36 deletions(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 948362317f..bf58ea31b2 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -705,12 +705,9 @@ void RN_DATA::AddSimple( const BOARD_ITEM* aItem ) if( net < 1 ) // do not process unconnected items return; - // Get list of nodes responding to the item - std::list nodes = m_nets[net].GetNodes( item ); - std::list::iterator it, itEnd; - - for( it = nodes.begin(), itEnd = nodes.end(); it != itEnd; ++it ) - m_nets[net].AddSimpleNode( *it ); + // Add all nodes belonging to the item + BOOST_FOREACH( RN_NODE_PTR node, m_nets[net].GetNodes( item ) ) + m_nets[net].AddSimpleNode( node ); } else if( aItem->Type() == PCB_MODULE_T ) { @@ -726,6 +723,46 @@ void RN_DATA::AddSimple( const BOARD_ITEM* aItem ) } +void RN_DATA::AddBlocked( const BOARD_ITEM* aItem ) +{ + int net; + + if( aItem->IsConnected() ) + { + const BOARD_CONNECTED_ITEM* item = static_cast( aItem ); + net = item->GetNet(); + + if( net < 1 ) // do not process unconnected items + return; + + // Block all nodes belonging to the item + BOOST_FOREACH( RN_NODE_PTR node, m_nets[net].GetNodes( item ) ) + m_nets[net].AddBlockedNode( node ); + } + else if( aItem->Type() == PCB_MODULE_T ) + { + const MODULE* module = static_cast( aItem ); + + for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + AddBlocked( pad ); + + return; + } + else + return; +} + + +void RN_DATA::AddSimple( const VECTOR2I& aPosition, int aNetCode ) +{ + assert( aNetCode > 0 ); + + RN_NODE_PTR newNode = boost::make_shared( aPosition.x, aPosition.y ); + + m_nets[aNetCode].AddSimpleNode( newNode ); +} + + void RN_NET::processZones() { BOOST_FOREACH( std::deque& edges, m_zoneConnections | boost::adaptors::map_values ) @@ -773,17 +810,6 @@ void RN_NET::processZones() } -void RN_DATA::updateNet( int aNetCode ) -{ - assert( aNetCode < (int) m_nets.size() ); - if( aNetCode < 1 ) - return; - - m_nets[aNetCode].ClearSimple(); - m_nets[aNetCode].Update(); -} - - void RN_DATA::Add( const BOARD_ITEM* aItem ) { int net; @@ -946,3 +972,14 @@ void RN_DATA::Recalculate( int aNet ) updateNet( aNet ); } } + + +void RN_DATA::updateNet( int aNetCode ) +{ + assert( aNetCode < (int) m_nets.size() ); + if( aNetCode < 1 ) + return; + + m_nets[aNetCode].ClearSimple(); + m_nets[aNetCode].Update(); +} diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index d51c070ee8..712909f2fa 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -284,7 +284,7 @@ public: /** * Function MarkDirty() - * Marks ratsnest for given net as 'dirty', ie. requiring recomputation. + * Marks ratsnest for given net as 'dirty', i.e. requiring recomputation. */ void MarkDirty() { @@ -432,7 +432,7 @@ public: /** * Function GetEdges() * Returns pointer to the vector of edges that makes ratsnest for a given net. - * @return Pointer to the vector of edges that makes ratsnest for a given net + * @return Pointer to the vector of edges that makes ratsnest for a given net. */ const std::vector* GetEdges() const { @@ -441,8 +441,8 @@ public: /** * Function AddSimpleNode() - * Changes drawing mode for a node to simple (ie. one ratsnest line per node). - * @param aNode is a node that changes its drawing mode.. + * Changes drawing mode for a node to simple (i.e. one ratsnest line per node). + * @param aNode is a node that changes its drawing mode. */ void AddSimpleNode( RN_NODE_PTR& aNode ) { @@ -450,9 +450,21 @@ public: aNode->SetFlag( true ); } + /** + * Function AddBlockedNode() + * Specifies a node as not suitable as a ratsnest line target (i.e. ratsnest lines will not + * target the node). The status is cleared after calling ClearSimple(). + * @param aNode is the node that is not going to be used as a ratsnest line target. + */ + void AddBlockedNode( RN_NODE_PTR& aNode ) + { + m_blockedNodes.push_back( aNode ); + aNode->SetFlag( true ); + } + /** * Function GetSimpleNodes() - * Returns list of nodes for which ratsnest is drawn in simple mode (ie. one + * Returns list of nodes for which ratsnest is drawn in simple mode (i.e. one * ratsnest line per node). * @return list of nodes for which ratsnest is drawn in simple mode. */ @@ -470,11 +482,15 @@ public: BOOST_FOREACH( const RN_NODE_PTR& node, m_simpleNodes ) node->SetFlag( false ); + BOOST_FOREACH( const RN_NODE_PTR& node, m_blockedNodes ) + node->SetFlag( false ); + m_simpleNodes.clear(); + m_blockedNodes.clear(); } protected: - ///> Validates edge, ie. modifies source and target nodes for an edge + ///> Validates edge, i.e. modifies source and target nodes for an edge ///> to make sure that they are not ones with the flag set. void validateEdge( RN_EDGE_PTR& aEdge ); @@ -496,6 +512,9 @@ protected: ///> List of nodes for which ratsnest is drawn in simple mode. std::deque m_simpleNodes; + ///> List of nodes which should be used as ratsnest target nodes.. + std::deque m_blockedNodes; + ///> Flag indicating necessity of recalculation of ratsnest for a net. bool m_dirty; @@ -556,12 +575,30 @@ public: /** * Function AddSimple() - * Sets an item to be drawn in simple mode (ie. one line per node, instead of full ratsnest). + * Sets an item to be drawn in simple mode (i.e. one line per node, instead of full ratsnest). * It is used for drawing quick, temporary ratsnest, eg. while moving an item. * @param aItem is an item to be drawn in simple node. */ void AddSimple( const BOARD_ITEM* aItem ); + /** + * Function AddSimple() + * Allows to draw a ratsnest line using a position expressed in world coordinates and a + * net code (so there is no need to have a real BOARD_ITEM to draw ratsnest line). + * It is used for drawing quick, temporary ratsnest, eg. while moving an item. + * @param aPosition is the point for which ratsnest line are going to be drawn. + * @param aNetCode determines the net code for which the ratsnest line are going to be drawn. + */ + void AddSimple( const VECTOR2I& aPosition, int aNetCode ); + + /** + * Function AddBlocked() + * Specifies an item as not suitable as a ratsnest line target (i.e. ratsnest lines will not + * target its node(s)). The status is cleared after calling ClearSimple(). + * @param aItem is the item of which node(s) are not going to be used as a ratsnest line target. + */ + void AddBlocked( const BOARD_ITEM* aItem ); + /** * Function ClearSimple() * Clears the list of nodes for which ratsnest is drawn in simple mode (one line per node). diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index 7bf9d79568..5de2527111 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -63,14 +63,11 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const for( int i = 1; i < m_data->GetNetCount(); ++i ) { - const RN_NET& net = m_data->GetNet( i ); + RN_NET& net = m_data->GetNet( i ); if( !net.IsVisible() ) continue; - // Avoid duplicate destinations for ratsnest lines by storing already used nodes - boost::unordered_set usedDestinations; - // Set brighter color for the temporary ratsnest aGal->SetStrokeColor( color.Brightened( 0.8 ) ); @@ -79,13 +76,15 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const { RN_NODE_PTR dest = net.GetClosestNode( node, WITHOUT_FLAG() ); - if( dest && usedDestinations.find( dest ) == usedDestinations.end() ) + if( dest ) { VECTOR2D origin( node->GetX(), node->GetY() ); VECTOR2D end( dest->GetX(), dest->GetY() ); aGal->DrawLine( origin, end ); - usedDestinations.insert( dest ); + + // Avoid duplicate destinations for ratsnest lines by storing already used nodes + net.AddBlockedNode( dest ); } } diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index 3ba7be0125..430f950a37 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -139,15 +139,20 @@ public: const VECTOR2I SnapToItem( PNS_ITEM* item, VECTOR2I aP, bool& aSplitsSegment ); /** - * Returns the last changes introduced by the router. After calling the method the list of - * changes is cleared, so only the latest changes are stored. + * Returns the last changes introduced by the router (since the last time ClearLastChanges() + * was called or a new track has been started). */ - PICKED_ITEMS_LIST GetLastChanges() + const PICKED_ITEMS_LIST& GetLastChanges() const { - PICKED_ITEMS_LIST copy = m_undoBuffer; - m_undoBuffer.ClearItemsList(); // TODO and delete? + return m_undoBuffer; + } - return copy; + /** + * Clears the list of recent changes, saved to be stored in the undo buffer. + */ + void ClearLastChanges() + { + m_undoBuffer.ClearItemsList(); } private: diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 94475132e2..9a8528d23a 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -32,6 +32,8 @@ #include +#include + #include "router_tool.h" #include "pns_segment.h" #include "pns_router.h" @@ -282,6 +284,30 @@ void ROUTER_TOOL::updateEndItem( TOOL_EVENT& aEvent ) ctls->ForceCursorPosition( false ); } + // Draw ratsnest for the currently routed track + RN_DATA* ratsnest = getModel( PCB_T )->GetRatsnest(); + ratsnest->ClearSimple(); + + if( ( m_endItem == NULL || m_endItem == m_startItem ) && m_startItem->GetNet() > 0 ) + { + // The ending node has to be first, so the line for the track is drawn first + ratsnest->AddSimple( m_endSnapPoint, m_startItem->GetNet() ); + + // Those nodes are added just to force ratsnest not to drawn + // lines to already routed parts of the track + const PICKED_ITEMS_LIST& changes = m_router->GetLastChanges(); + for( unsigned int i = 0; i < changes.GetCount(); ++i ) + { + // Block the new tracks, do not handle tracks that were moved + // (moved tracks are saved in the undo buffer with UR_DELETED status instead) + if( changes.GetPickedItemStatus( i ) == UR_NEW ) + ratsnest->AddBlocked( static_cast( changes.GetPickedItem( i ) ) ); + } + + // Also the origin of the new track should be skipped in the ratsnest shown for the routed track + ratsnest->AddBlocked( static_cast( m_startItem->GetParent() ) ); + } + if( m_endItem ) TRACE( 0, "%s, layer : %d", m_endItem->GetKindStr().c_str() % m_endItem->GetLayers().Start() ); @@ -382,6 +408,7 @@ void ROUTER_TOOL::startRouting() // Save the recent changes in the undo buffer getEditFrame()->SaveCopyInUndoList( m_router->GetLastChanges(), UR_UNSPECIFIED ); + m_router->ClearLastChanges(); getEditFrame()->OnModify(); } else From 1490099ddd10dffebcd6d9020b3a4f3c0624b69c Mon Sep 17 00:00:00 2001 From: Carl Poirier Date: Fri, 31 Jan 2014 18:27:06 +0100 Subject: [PATCH 67/84] Parallelized the RN_DATA::Recalculate() function. --- CMakeLists.txt | 7 +++++++ pcbnew/CMakeLists.txt | 2 ++ pcbnew/ratsnest_data.cpp | 28 +++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d72d54d6de..c3fc56208b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,13 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden" ) endif() + find_package( OpenMP QUIET ) + if( OPENMP_FOUND ) + set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" ) + add_definitions( -DUSE_OPENMP ) + endif() + if( MINGW ) set( CMAKE_EXE_LINKER_FLAGS_RELEASE "-s" ) diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 11663c684f..86e8dd296d 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -1,6 +1,8 @@ set( MAKE_LINK_MAPS false ) +set( CMAKE_CXX_FLAGS "-fopenmp" ) + add_definitions( -DPCBNEW ) add_subdirectory(router) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index af5f6932fd..977e3bcc9e 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -27,6 +27,10 @@ * @brief Class that computes missing connections on a PCB. */ +#ifdef USE_OPENMP +#include +#endif /* USE_OPENMP */ + #include #include @@ -829,12 +833,25 @@ void RN_DATA::Recalculate( int aNet ) { if( aNet < 0 ) // Recompute everything { - // Start with net number 1, as 0 stand for not connected - for( unsigned int i = 1; i < m_board->GetNetCount(); ++i ) + unsigned int tid, i, chunk, netCount; + netCount = m_board->GetNetCount(); + chunk = 1; + +#ifdef USE_OPENMP + #pragma omp parallel shared(chunk, netCount) private(i, tid) { - if( m_nets[i].IsDirty() ) - updateNet( i ); - } + tid = omp_get_thread_num(); + #pragma omp for schedule(guided, chunk) +#else /* USE_OPENMP */ + { +#endif + // Start with net number 1, as 0 stand for not connected + for( i = 1; i < netCount; ++i ) + { + if( m_nets[i].IsDirty() ) + updateNet( i ); + } + } /* end of parallel section */ } else if( aNet > 0 ) // Recompute only specific net { @@ -848,3 +865,4 @@ void RN_DATA::ClearSimple() BOOST_FOREACH( RN_NET& net, m_nets ) net.ClearSimple(); } + From 3f5c3d434900320955b28b101124d23637e0fa23 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 3 Feb 2014 16:02:54 +0100 Subject: [PATCH 68/84] Minor changes (fix cvpcb build issue, wx2.8 compatibility, some other stuff). --- common/CMakeLists.txt | 1 + pcbnew/CMakeLists.txt | 1 - pcbnew/pcb_painter.cpp | 3 +-- pcbnew/pcb_parser.cpp | 6 +++--- pcbnew/router/pns_router.cpp | 1 - 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 44569f29e2..cd3ae84acc 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -219,6 +219,7 @@ set( PCB_COMMON_SRCS ../pcbnew/class_zone.cpp ../pcbnew/class_zone_settings.cpp ../pcbnew/classpcb.cpp + ../pcbnew/ratsnest_data.cpp ../pcbnew/collectors.cpp ../pcbnew/netlist_reader.cpp ../pcbnew/legacy_netlist_reader.cpp diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 1ff4550e43..7a715d181c 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -221,7 +221,6 @@ set( PCBNEW_CLASS_SRCS print_board_functions.cpp printout_controler.cpp ratsnest.cpp - ratsnest_data.cpp ratsnest_viewitem.cpp # specctra.cpp #moved in pcbcommon lib # specctra_export.cpp diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 4ffdfa4667..b7f9ff0cc3 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -281,7 +280,7 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer ) if( !net ) return; - std::wstring netName = std::wstring( net->GetShortNetname().wc_str() ); + const wxString& netName = aTrack->GetShortNetname(); VECTOR2D textPosition = start + line / 2.0; // center of the track double textOrientation = -atan( line.y / line.x ); double textSize = std::min( static_cast( width ), length / netName.length() ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 1f06ac2ed1..f68743b741 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2426,9 +2426,9 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) NeedSYMBOLorNUMBER(); if( m_board->FindNet( zone->GetNet() )->GetNetname() != FromUTF8() ) { - DisplayError( NULL, wxString::Format( _( "There is a zone that belongs to a not " - "existing net (%s), you should verify it." ), - FromUTF8() ) ); + wxString msg = _( "There is a zone that belongs to a not " + "existing net (" ) + FromUTF8() + _("), you should verify it." ); + DisplayError( NULL, msg ); zone->SetNet( NETINFO_LIST::UNCONNECTED ); } NeedRIGHT(); diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 3046c13f6e..1babefa598 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -631,7 +631,6 @@ void PNS_ROUTER::commitRouting( PNS_NODE* aNode ) newBI->ClearFlags(); m_view->Add( newBI ); m_board->Add( newBI ); - m_board->GetRatsnest()->Update( newBI ); m_undoBuffer.PushItem( ITEM_PICKER( newBI, UR_NEW ) ); newBI->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } From f6aa4470360ed87530ed9353d846c7874af0d9c5 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 3 Feb 2014 17:40:39 +0100 Subject: [PATCH 69/84] Ratsnest lines for zones are removed when a zone is dragged. --- pcbnew/ratsnest_data.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index bf58ea31b2..4f49e6bed4 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -521,7 +521,12 @@ void RN_NET::RemoveItem( const ZONE_CONTAINER* aZone ) // Remove all subpolygons that make the zone std::deque& polygons = m_zonePolygons.at( aZone ); BOOST_FOREACH( RN_POLY& polygon, polygons ) - m_links.RemoveNode( polygon.GetNode() ); + { + const RN_NODE_PTR node = polygon.GetNode(); + + if( m_links.RemoveNode( node ) ) + clearNode( node ); + } polygons.clear(); // Remove all connections added by the zone From f87b6962e00f33136a495ec049ccc959d6f013bb Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 3 Feb 2014 18:09:17 +0100 Subject: [PATCH 70/84] Enabled PNS for selected items. --- pcbnew/router/router_tool.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 9a8528d23a..558b4dfab6 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -140,7 +140,8 @@ PNS_ITEM* ROUTER_TOOL::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLa if( !IsCopperLayer( item->GetLayers().Start() ) ) continue; - if( item->GetParent() && !item->GetParent()->ViewIsVisible() ) + if( item->GetParent() && !item->GetParent()->ViewIsVisible() && + !item->GetParent()->IsSelected() ) continue; if( aNet < 0 || item->GetNet() == aNet ) From b317894ea0167d14adcad04eec7c0872c607c6f1 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 09:44:16 +0100 Subject: [PATCH 71/84] Snapping settings are valid while autopanning. --- common/tool/tool_dispatcher.cpp | 2 +- common/view/wx_view_controls.cpp | 24 ++++++++++++++---------- include/view/wx_view_controls.h | 6 ++++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 66efcc2581..f35689c97f 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -224,7 +224,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetMousePosition(); VECTOR2D pos = getView()->ToWorld( screenPos ); - if( pos != m_lastMousePos || type == KIGFX::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE ) + if( pos != m_lastMousePos ) { motion = true; m_lastMousePos = pos; diff --git a/common/view/wx_view_controls.cpp b/common/view/wx_view_controls.cpp index 20778c7d3e..3aeabd6d7d 100644 --- a/common/view/wx_view_controls.cpp +++ b/common/view/wx_view_controls.cpp @@ -73,12 +73,7 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent ) m_mousePosition.x = aEvent.GetX(); m_mousePosition.y = aEvent.GetY(); - if( m_forceCursorPosition ) - m_cursorPosition = m_view->ToScreen( m_forcedPosition ); - else if( m_snappingEnabled ) - m_cursorPosition = m_view->GetGAL()->GetGridPoint( m_mousePosition ); - else - m_cursorPosition = m_mousePosition; + updateCursor(); bool isAutoPanning = false; @@ -166,17 +161,13 @@ void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent ) } if( aEvent.LeftUp() ) - { m_state = IDLE; // Stop autopanning when user release left mouse button - } break; case DRAG_PANNING: if( aEvent.MiddleUp() ) - { m_state = IDLE; - } break; } @@ -208,6 +199,8 @@ void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent ) dir = m_view->ToWorld( dir, false ); m_view->SetCenter( m_view->GetCenter() + dir * m_autoPanSpeed ); + updateCursor(); + // Notify tools that the cursor position has changed in the world coordinates wxCommandEvent moveEvent( EVT_REFRESH_MOUSE ); wxPostEvent( m_parentPanel, moveEvent ); @@ -298,3 +291,14 @@ bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent ) wxASSERT_MSG( false, wxT( "This line should never be reached" ) ); return false; // Should not be reached, just avoid the compiler warnings.. } + + +void WX_VIEW_CONTROLS::updateCursor() +{ + if( m_forceCursorPosition ) + m_cursorPosition = m_view->ToScreen( m_forcedPosition ); + else if( m_snappingEnabled ) + m_cursorPosition = m_view->GetGAL()->GetGridPoint( m_mousePosition ); + else + m_cursorPosition = m_mousePosition; +} diff --git a/include/view/wx_view_controls.h b/include/view/wx_view_controls.h index cfec3eac9b..5df48f3de3 100644 --- a/include/view/wx_view_controls.h +++ b/include/view/wx_view_controls.h @@ -112,6 +112,12 @@ private: */ bool handleAutoPanning( const wxMouseEvent& aEvent ); + /** + * Function updateCursor() + * Recomputes the cursor coordinates basing on the current snapping settings and mouse position. + */ + void updateCursor(); + /// Current state of VIEW_CONTROLS STATE m_state; From 82ca611ed32b5d6a4e396ceaa9c406b553945d80 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 11:37:54 +0100 Subject: [PATCH 72/84] SELECTION_TOOL::SELECTION::Clear made private, as there was no chance to call it outside the SELECTION_TOOL class. --- pcbnew/tools/selection_tool.cpp | 8 ++++---- pcbnew/tools/selection_tool.h | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index f226709a86..9cdd5fc072 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -69,7 +69,7 @@ void SELECTION_TOOL::Reset( RESET_REASON aReason ) if( aReason == TOOL_BASE::MODEL_RELOAD ) // Remove pointers to the selected items from containers // without changing their properties (as they are already deleted) - m_selection.Clear(); + m_selection.clear(); else // Restore previous properties of selected items and remove them from containers ClearSelection(); @@ -172,7 +172,7 @@ void SELECTION_TOOL::ClearSelection() item->ViewSetVisible( true ); item->ClearSelected(); } - m_selection.Clear(); + m_selection.clear(); getEditFrame()->SetCurItem( NULL ); @@ -465,7 +465,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const if( aItem->IsOnLayer( LAYER_N_FRONT ) && board->IsElementVisible( MOD_FR_VISIBLE ) ) return true; - if( aItem->IsOnLayer( LAYER_N_BACK ) && board->IsLayerVisible( MOD_BK_VISIBLE ) ) + if( aItem->IsOnLayer( LAYER_N_BACK ) && board->IsElementVisible( MOD_BK_VISIBLE ) ) return true; return false; @@ -590,7 +590,7 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const } -void SELECTION_TOOL::SELECTION::Clear() +void SELECTION_TOOL::SELECTION::clear() { items.ClearItemsList(); group->Clear(); diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 168f2288da..93b25083c6 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -78,9 +78,12 @@ public: return items.GetCount(); } + private: /// Clears both the VIEW_GROUP and set of selected items. Please note that it does not /// change properties of selected items (e.g. selection flag). - void Clear(); + void clear(); + + friend class SELECTION_TOOL; }; /// @copydoc TOOL_INTERACTIVE::Reset() From 0b9a8709f82c5d5cdf41066b61702c8786f903db Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 13:38:18 +0100 Subject: [PATCH 73/84] Modifiers (Alt/Shift/Control) are properly set for events when autopanning is active. --- common/view/wx_view_controls.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/common/view/wx_view_controls.cpp b/common/view/wx_view_controls.cpp index 3aeabd6d7d..f9a17fa86a 100644 --- a/common/view/wx_view_controls.cpp +++ b/common/view/wx_view_controls.cpp @@ -202,7 +202,20 @@ void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent ) updateCursor(); // Notify tools that the cursor position has changed in the world coordinates - wxCommandEvent moveEvent( EVT_REFRESH_MOUSE ); + wxMouseEvent moveEvent( EVT_REFRESH_MOUSE ); + + // Set the modifiers state +#if wxCHECK_VERSION( 3, 0, 0 ) + moveEvent.SetControlDown( wxGetKeyState( WXK_CONTROL ) ); + moveEvent.SetShiftDown( wxGetKeyState( WXK_SHIFT ) ); + moveEvent.SetAltDown( wxGetKeyState( WXK_ALT) ); +#else + // wx <3.0 do not have accessors, but the fields are exposed + moveEvent.m_controlDown = wxGetKeyState( WXK_CONTROL ); + moveEvent.m_shiftDown = wxGetKeyState( WXK_SHIFT ); + moveEvent.m_altDown = wxGetKeyState( WXK_ALT ); +#endif + wxPostEvent( m_parentPanel, moveEvent ); } break; From 347649e855da809b1cca92528045349d4f8647bb Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 13:40:39 +0100 Subject: [PATCH 74/84] Protection against non consecutive net codes. --- pcbnew/router/pns_router.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 1babefa598..b655ac363f 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -66,6 +66,9 @@ public: for( unsigned int i = 0; i < aBoard->GetNetCount(); i++ ) { NETINFO_ITEM* ni = aBoard->FindNet( i ); + if( ni == NULL ) + continue; + wxString netClassName = ni->GetClassName(); NETCLASS* nc = aBoard->m_NetClasses.Find( netClassName ); int clearance = nc->GetClearance(); From 106fa9bbd8076002978b23e4784074226df8062c Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 14:21:29 +0100 Subject: [PATCH 75/84] Edit tool may still be activated if it was invoked with no selected items. --- pcbnew/tools/edit_tool.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 451164bf23..812d7732dd 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -80,7 +80,11 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; if( selection.Empty() ) - return 0; // there are no items to operate on + { + setTransitions(); // this is necessary, so later the tool may + // be activated upon reception of the activation event + return 0; // there are no items to operate on, so we can end now + } VECTOR2D dragPosition; // The last position of the cursor while dragging m_dragging = false; From 625dcddb2714f03220b3c881cf726d10c3d87c73 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 16:03:56 +0100 Subject: [PATCH 76/84] Added 2 tool actions: - pcbnew.InteractiveSelection.Single for selecting a single item - pcbnew.InteractiveSelection.Clear for clearing the selection Made SELECTION_TOOL::clearSelection private. --- pcbnew/tools/common_actions.cpp | 6 ++ pcbnew/tools/common_actions.h | 12 ++- pcbnew/tools/edit_tool.cpp | 12 +-- pcbnew/tools/pcb_tools.cpp | 2 + pcbnew/tools/selection_tool.cpp | 147 ++++++++++++++++---------------- pcbnew/tools/selection_tool.h | 12 +-- 6 files changed, 100 insertions(+), 91 deletions(-) diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 6756e10a9d..f1fb3befd6 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -30,6 +30,12 @@ TOOL_ACTION COMMON_ACTIONS::selectionActivate( "pcbnew.InteractiveSelection", AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere +TOOL_ACTION COMMON_ACTIONS::selectionSingle( "pcbnew.InteractiveSelection.Single", + AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere + +TOOL_ACTION COMMON_ACTIONS::selectionClear( "pcbnew.InteractiveSelection.Clear", + AS_GLOBAL, 0, "", "" ); // No description, it is not supposed to be shown anywhere + // Edit tool actions TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", AS_GLOBAL, 'M', diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 19b0004182..86aafe5894 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -24,13 +24,11 @@ #include -//class ACTION_MANAGER; - /** * Class COMMON_ACTIONS * - * Gathers all the actions that are shared by tools. The instance of COMMON_ACTIOSN is created - * inside of ACTION_MANAGER object and registers them. + * Gathers all the actions that are shared by tools. The instance of COMMON_ACTION is created + * inside of ACTION_MANAGER object that registers the actions. */ class COMMON_ACTIONS { @@ -38,6 +36,12 @@ public: /// Activation of the selection tool static TOOL_ACTION selectionActivate; + /// Select a single item under the cursor position + static TOOL_ACTION selectionSingle; + + /// Clears the current selection + static TOOL_ACTION selectionClear; + /// Activation of the edit tool static TOOL_ACTION editActivate; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 812d7732dd..008305193d 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -74,10 +74,6 @@ bool EDIT_TOOL::Init() int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); - - // By default, modified items need to update their geometry - m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; if( selection.Empty() ) { @@ -90,7 +86,11 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) m_dragging = false; bool restore = false; // Should items' state be restored when finishing the tool? + // By default, modified items need to update their geometry + m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; + VIEW_CONTROLS* controls = getViewControls(); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); controls->ShowCursor( true ); controls->SetSnapping( true ); controls->SetAutoPan( true ); @@ -163,7 +163,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) if( restore ) { - // Modifications has to be rollbacked, so restore the previous state of items + // Modifications have to be rollbacked, so restore the previous state of items wxCommandEvent dummy; editFrame->GetBoardFromUndoList( dummy ); } @@ -290,7 +290,7 @@ int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // As we are about to remove items, they have to be removed from the selection first - m_selectionTool->ClearSelection(); + m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); // Save them for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) diff --git a/pcbnew/tools/pcb_tools.cpp b/pcbnew/tools/pcb_tools.cpp index 9908012f6b..a4b4f21a24 100644 --- a/pcbnew/tools/pcb_tools.cpp +++ b/pcbnew/tools/pcb_tools.cpp @@ -47,6 +47,8 @@ void PCB_EDIT_FRAME::setupTools() GetGalCanvas()->SetEventDispatcher( m_toolDispatcher ); // Register tool actions + m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionSingle ); + m_toolManager->RegisterAction( &COMMON_ACTIONS::selectionClear ); m_toolManager->RegisterAction( &COMMON_ACTIONS::editActivate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::rotate ); m_toolManager->RegisterAction( &COMMON_ACTIONS::flip ); diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 9cdd5fc072..ce59adbb1f 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -72,7 +72,7 @@ void SELECTION_TOOL::Reset( RESET_REASON aReason ) m_selection.clear(); else // Restore previous properties of selected items and remove them from containers - ClearSelection(); + clearSelection(); // Reinsert the VIEW_GROUP, in case it was removed from the VIEW getView()->Remove( m_selection.group ); @@ -92,25 +92,22 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) // become the new selection (discarding previously selected items) m_additive = evt->Modifier( MD_SHIFT ); - if( evt->IsCancel() ) + if( evt->IsAction( &COMMON_ACTIONS::selectionSingle ) ) { - // Cancel event deselects items... - ClearSelection(); - - // This tool never exits + selectSingle( getView()->ToWorld( getViewControls()->GetMousePosition() ) ); } - else if( evt->Action() == TA_UNDO_REDO ) + else if( evt->IsCancel() || evt->Action() == TA_UNDO_REDO || + evt->IsAction( &COMMON_ACTIONS::selectionClear ) ) { - // Clear the selection, as it may be altered with undone items - ClearSelection(); + clearSelection(); } // single click? Select single object else if( evt->IsClick( BUT_LEFT ) ) { if( !m_additive ) - ClearSelection(); + clearSelection(); selectSingle( evt->Position() ); } @@ -144,7 +141,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) else { // No -> clear the selection list - ClearSelection(); + clearSelection(); } } } @@ -157,30 +154,6 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) } -void SELECTION_TOOL::ClearSelection() -{ - if( m_selection.Empty() ) - return; - - KIGFX::VIEW_GROUP::const_iter it, it_end; - - // Restore the initial properties - for( it = m_selection.group->Begin(), it_end = m_selection.group->End(); it != it_end; ++it ) - { - BOARD_ITEM* item = static_cast( *it ); - - item->ViewSetVisible( true ); - item->ClearSelected(); - } - m_selection.clear(); - - getEditFrame()->SetCurItem( NULL ); - - // Do not show the context menu when there is nothing selected - SetContextMenu( &m_menu, CMENU_OFF ); -} - - void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) { assert( aAction.GetId() > 0 ); // Check if the action was registered before in ACTION_MANAGER @@ -198,7 +171,7 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) else { if( !m_additive ) - ClearSelection(); + clearSelection(); // Prevent selection of invisible or inactive items if( selectable( aItem ) ) @@ -221,7 +194,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) { case 0: if( !m_additive ) - ClearSelection(); + clearSelection(); break; case 1: @@ -254,43 +227,6 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) } -BOARD_ITEM* SELECTION_TOOL::pickSmallestComponent( GENERAL_COLLECTOR* aCollector ) -{ - int count = aCollector->GetPrimaryCount(); // try to use preferred layer - - if( 0 == count ) - count = aCollector->GetCount(); - - for( int i = 0; i < count; ++i ) - { - if( ( *aCollector )[i]->Type() != PCB_MODULE_T ) - return NULL; - } - - // All are modules, now find smallest MODULE - int minDim = 0x7FFFFFFF; - int minNdx = 0; - - for( int i = 0; i < count; ++i ) - { - MODULE* module = (MODULE*) ( *aCollector )[i]; - - int lx = module->GetBoundingBox().GetWidth(); - int ly = module->GetBoundingBox().GetHeight(); - - int lmin = std::min( lx, ly ); - - if( lmin < minDim ) - { - minDim = lmin; - minNdx = i; - } - } - - return (*aCollector)[minNdx]; -} - - bool SELECTION_TOOL::selectMultiple() { bool cancelled = false; // Was the tool cancelled while it was running? @@ -311,7 +247,7 @@ bool SELECTION_TOOL::selectMultiple() if( evt->IsDrag( BUT_LEFT ) ) { if( !m_additive ) - ClearSelection(); + clearSelection(); // Start drawing a selection box m_selArea->SetOrigin( evt->DragOrigin() ); @@ -356,6 +292,30 @@ bool SELECTION_TOOL::selectMultiple() } +void SELECTION_TOOL::clearSelection() +{ + if( m_selection.Empty() ) + return; + + KIGFX::VIEW_GROUP::const_iter it, it_end; + + // Restore the initial properties + for( it = m_selection.group->Begin(), it_end = m_selection.group->End(); it != it_end; ++it ) + { + BOARD_ITEM* item = static_cast( *it ); + + item->ViewSetVisible( true ); + item->ClearSelected(); + } + m_selection.clear(); + + getEditFrame()->SetCurItem( NULL ); + + // Do not show the context menu when there is nothing selected + SetContextMenu( &m_menu, CMENU_OFF ); +} + + BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) { BOARD_ITEM* current = NULL; @@ -419,6 +379,43 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector ) } +BOARD_ITEM* SELECTION_TOOL::pickSmallestComponent( GENERAL_COLLECTOR* aCollector ) +{ + int count = aCollector->GetPrimaryCount(); // try to use preferred layer + + if( 0 == count ) + count = aCollector->GetCount(); + + for( int i = 0; i < count; ++i ) + { + if( ( *aCollector )[i]->Type() != PCB_MODULE_T ) + return NULL; + } + + // All are modules, now find smallest MODULE + int minDim = 0x7FFFFFFF; + int minNdx = 0; + + for( int i = 0; i < count; ++i ) + { + MODULE* module = (MODULE*) ( *aCollector )[i]; + + int lx = module->GetBoundingBox().GetWidth(); + int ly = module->GetBoundingBox().GetHeight(); + + int lmin = std::min( lx, ly ); + + if( lmin < minDim ) + { + minDim = lmin; + minNdx = i; + } + } + + return (*aCollector)[minNdx]; +} + + bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const { // Is high contrast mode enabled? diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 93b25083c6..4c5e4b2d9a 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -106,12 +106,6 @@ public: return m_selection; } - /** - * Function ClearSelection() - * Clears the current selection. - */ - void ClearSelection(); - /** * Function AddMenuItem() * @@ -138,6 +132,12 @@ private: */ bool selectMultiple(); + /** + * Function ClearSelection() + * Clears the current selection. + */ + void clearSelection(); + /** * Function disambiguationMenu() * Handles the menu that allows to select one of many items in case there is more than one From 8df0f769f7ccbb5a0f5c65c368935a1876e56ecd Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Feb 2014 17:27:00 +0100 Subject: [PATCH 77/84] Added KiCad-style modification methods (hover over an item and press a hot key, without selecting first). Modification point is selected basing on the number of selected items. Rotation angle setting (Preferences->General) is taken into account while rotating. --- pcbnew/tools/edit_tool.cpp | 122 +++++++++++++++++++++++++------- pcbnew/tools/edit_tool.h | 8 +++ pcbnew/tools/selection_tool.cpp | 2 +- 3 files changed, 105 insertions(+), 27 deletions(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 008305193d..9d99f3275c 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -49,10 +49,9 @@ EDIT_TOOL::EDIT_TOOL() : bool EDIT_TOOL::Init() { // Find the selection tool, so they can cooperate - TOOL_BASE* selectionTool = m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ); + m_selectionTool = static_cast( m_toolMgr->FindTool( "pcbnew.InteractiveSelection" ) ); - m_selectionTool = static_cast( selectionTool ); - if( !selectionTool ) + if( !m_selectionTool ) { DisplayError( NULL, wxT( "pcbnew.InteractiveSelection tool is not available" ) ); return false; @@ -75,15 +74,15 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Empty() ) - { - setTransitions(); // this is necessary, so later the tool may - // be activated upon reception of the activation event - return 0; // there are no items to operate on, so we can end now - } + // Shall the selection be cleared at the end? + bool unselect = selection.Empty(); + + // Be sure that there is at least one item that we can modify + if( !makeSelection( selection ) ) + return 0; VECTOR2D dragPosition; // The last position of the cursor while dragging - m_dragging = false; + m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? // By default, modified items need to update their geometry @@ -173,6 +172,9 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) selection.group->ItemsViewUpdate( m_updateFlag ); } + if( unselect ) + m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + RN_DATA* ratsnest = getModel( PCB_T )->GetRatsnest(); ratsnest->ClearSimple(); ratsnest->Recalculate(); @@ -192,26 +194,32 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + // Shall the selection be cleared at the end? + bool unselect = selection.Empty(); + + if( !makeSelection( selection ) ) + return 0; + // Properties are displayed when there is only one item selected if( selection.Size() == 1 ) { // Display properties dialog BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( 0 ) ); - if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag - { - editFrame->SaveCopyInUndoList( item, UR_CHANGED ); - editFrame->OnModify(); - } - + editFrame->SaveCopyInUndoList( item, UR_CHANGED ); + editFrame->OnModify(); editFrame->OnEditItemRequest( NULL, item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + updateRatsnest( true ); + getModel( PCB_T )->GetRatsnest()->Recalculate(); + + if( unselect ) + m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); } setTransitions(); - updateRatsnest( true ); - getModel( PCB_T )->GetRatsnest()->Recalculate(); return 0; } @@ -220,20 +228,28 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + // Shall the selection be cleared at the end? + bool unselect = selection.Empty(); + + if( !makeSelection( selection ) ) + return 0; + + wxPoint rotatePoint = getModificationPoint( selection ); + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag { editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, wxPoint( cursor.x, cursor.y ) ); + editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, rotatePoint ); } for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - item->Rotate( wxPoint( cursor.x, cursor.y ), 900.0 ); + item->Rotate( rotatePoint, editFrame->GetRotationAngle() ); + if( !m_dragging ) item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } @@ -246,6 +262,9 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) else getModel( PCB_T )->GetRatsnest()->Recalculate(); + if( unselect ) + m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + return 0; } @@ -253,20 +272,28 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + // Shall the selection be cleared at the end? + bool unselect = selection.Empty(); + + if( !makeSelection( selection ) ) + return 0; + + wxPoint flipPoint = getModificationPoint( selection ); + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag { editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, wxPoint( cursor.x, cursor.y ) ); + editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, flipPoint ); } for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - item->Flip( wxPoint( cursor.x, cursor.y ) ); + item->Flip( flipPoint ); + if( !m_dragging ) item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } @@ -279,14 +306,22 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) else getModel( PCB_T )->GetRatsnest()->Recalculate(); + if( unselect ) + m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Clear" ); + return 0; } int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) { + const SELECTION_TOOL::SELECTION selection = m_selectionTool->GetSelection(); + + if( !makeSelection( selection ) ) + return 0; + // Get a copy of the selected items set - PICKED_ITEMS_LIST selectedItems = m_selectionTool->GetSelection().items; + PICKED_ITEMS_LIST selectedItems = selection.items; PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // As we are about to remove items, they have to be removed from the selection first @@ -385,9 +420,44 @@ void EDIT_TOOL::updateRatsnest( bool aRedraw ) { BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); - ratsnest->Update( static_cast( item ) ); + ratsnest->Update( item ); if( aRedraw ) ratsnest->AddSimple( item ); } } + + +wxPoint EDIT_TOOL::getModificationPoint( const SELECTION_TOOL::SELECTION& aSelection ) +{ + if( aSelection.Size() == 1 ) + { + return static_cast( aSelection.items.GetPickedItem( 0 ) )->GetPosition(); + } + else + { + VECTOR2I cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + return wxPoint( cursor.x, cursor.y ); + } +} + + +bool EDIT_TOOL::makeSelection( const SELECTION_TOOL::SELECTION& aSelection ) +{ + if( aSelection.Empty() ) + { + // Try to find an item that could be modified + m_toolMgr->RunAction( "pcbnew.InteractiveSelection.Single" ); + + if( aSelection.Empty() ) + { + // This is necessary, so later the tool may be activated upon + // reception of the activation event + setTransitions(); + + return false; // Still no items to work with + } + } + + return true; +} diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index 0079d332b3..d31b159aa5 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -115,6 +115,14 @@ private: } void updateRatsnest( bool aRedraw ); + + ///> Returns the right modification point (e.g. for rotation), depending on the number of + ///> selected items. + wxPoint getModificationPoint( const SELECTION_TOOL::SELECTION& aSelection ); + + ///> If there are no items currently selected, it tries to choose the item that is under + ///> the cursor or displays a disambiguation menu if there are multpile items. + bool makeSelection( const SELECTION_TOOL::SELECTION& aSelection ); }; #endif diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index ce59adbb1f..17fcd05ee7 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -112,12 +112,12 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent ) selectSingle( evt->Position() ); } + // double click? Display the properties window else if( evt->IsDblClick( BUT_LEFT ) ) { if( m_selection.Empty() ) selectSingle( evt->Position() ); - // Display properties window m_toolMgr->RunAction( "pcbnew.InteractiveEdit.properties" ); } From f92253397882b6eb120f87f5e6db3cf9fd679b09 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 09:05:27 +0100 Subject: [PATCH 78/84] Added possibility for editing pads properties. --- pcbnew/tools/edit_tool.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 9d99f3275c..2fa4108047 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -205,6 +205,21 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) { // Display properties dialog BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( 0 ) ); + VECTOR2I cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + + // Check if user wants to edit pad or module properties + if( item->Type() == PCB_MODULE_T ) + { + for( D_PAD* pad = static_cast( item )->Pads(); pad; pad = pad->Next() ) + { + if( pad->ViewBBox().Contains( cursor ) ) + { + // Turns out that user wants to edit a pad properties + item = pad; + break; + } + } + } editFrame->SaveCopyInUndoList( item, UR_CHANGED ); editFrame->OnModify(); From a9031edc0ddc53f1eb37028aa9662add4938cc40 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 10:17:14 +0100 Subject: [PATCH 79/84] Grip margin is relative to the world's zoom. --- pcbnew/tools/selection_tool.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 17fcd05ee7..4f2489e81c 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -568,16 +568,15 @@ void SELECTION_TOOL::deselectVisually( BOARD_ITEM* aItem ) const bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const { - const unsigned GRIP_MARGIN = 500000; + const unsigned GRIP_MARGIN = 20; + VECTOR2D margin = getView()->ToWorld( VECTOR2D( GRIP_MARGIN, GRIP_MARGIN ), false ); // Check if the point is located within any of the currently selected items bounding boxes - std::set::iterator it, it_end; - for( unsigned int i = 0; i < m_selection.items.GetCount(); ++i ) { BOARD_ITEM* item = static_cast( m_selection.items.GetPickedItem( i ) ); BOX2I itemBox = item->ViewBBox(); - itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item + itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item if( itemBox.Contains( aPoint ) ) return true; From d7517e472b7e7480b5c8508d1de55db1db0fedc9 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 10:30:50 +0100 Subject: [PATCH 80/84] Some items were still marked as selected after undoing an operation. --- pcbnew/board_undo_redo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 970ea3167d..9931b6c1e6 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -537,6 +537,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed } ratsnest->Add( item ); + item->ClearSelected(); // TODO or ClearFlags? item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; From 857956e42e4fd93ab80c5ac113a2a1f50db0f3b6 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 10:47:55 +0100 Subject: [PATCH 81/84] Fixed bug introduced in the last commit. --- pcbnew/board_undo_redo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 9931b6c1e6..a5a3ad314e 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -537,7 +537,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed } ratsnest->Add( item ); - item->ClearSelected(); // TODO or ClearFlags? + item->ClearFlags( SELECTED ); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; From 17c030aa98033b549b57ad5940ccc3996cc42dc2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 11:08:34 +0100 Subject: [PATCH 82/84] Fixed removal of items in the KiCad-default style. --- pcbnew/tools/edit_tool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 2fa4108047..f5f1c3b0ff 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -330,7 +330,7 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) { - const SELECTION_TOOL::SELECTION selection = m_selectionTool->GetSelection(); + const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); if( !makeSelection( selection ) ) return 0; From 3a15f5ad289ca1ce57a6a0c3781b5b2adfef062e Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 11:33:45 +0100 Subject: [PATCH 83/84] Initialized value to suppress Valgrind warnings. --- pcbnew/tools/selection_tool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 4f2489e81c..366c81659a 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -50,7 +50,7 @@ using boost::optional; SELECTION_TOOL::SELECTION_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveSelection" ), m_multiple( false ) + TOOL_INTERACTIVE( "pcbnew.InteractiveSelection" ), m_additive( false ), m_multiple( false ) { m_selArea = new SELECTION_AREA; m_selection.group = new KIGFX::VIEW_GROUP; From 1d4c6ad40e1907c039932cc9fe33aba00caf3bad Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 5 Feb 2014 14:51:19 +0100 Subject: [PATCH 84/84] Minor optimizations. --- common/geometry/hetriang.cpp | 74 +++++++++++++++--------------------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/common/geometry/hetriang.cpp b/common/geometry/hetriang.cpp index 175e80dbd5..b69255cdbf 100644 --- a/common/geometry/hetriang.cpp +++ b/common/geometry/hetriang.cpp @@ -223,8 +223,8 @@ void Triangulation::removeTriangle(EdgePtr& edge) { removeLeadingEdgeFromList(e1); // cout << "No leading edges = " << leadingEdges_.size() << endl; // Remove the triangle - EdgePtr e2 = e1->getNextEdgeInFace(); - EdgePtr e3 = e2->getNextEdgeInFace(); + EdgePtr e2(e1->getNextEdgeInFace()); + EdgePtr e3(e2->getNextEdgeInFace()); if (e1->getTwinEdge()) e1->getTwinEdge()->setTwinEdge(EdgePtr()); @@ -240,15 +240,15 @@ void Triangulation::reverse_splitTriangle(EdgePtr& edge) { // Reverse operation of splitTriangle - EdgePtr e1 = edge->getNextEdgeInFace(); - EdgePtr le = getLeadingEdgeInTriangle(e1); + EdgePtr e1(edge->getNextEdgeInFace()); + EdgePtr le(getLeadingEdgeInTriangle(e1)); #ifdef DEBUG_HE if (!le) errorAndExit("Triangulation::removeTriangle: could not find leading edge"); #endif removeLeadingEdgeFromList(le); - EdgePtr e2 = e1->getNextEdgeInFace()->getTwinEdge()->getNextEdgeInFace(); + EdgePtr e2(e1->getNextEdgeInFace()->getTwinEdge()->getNextEdgeInFace()); le = getLeadingEdgeInTriangle(e2); #ifdef DEBUG_HE if (!le) @@ -256,7 +256,7 @@ void Triangulation::reverse_splitTriangle(EdgePtr& edge) { #endif removeLeadingEdgeFromList(le); - EdgePtr e3 = edge->getTwinEdge()->getNextEdgeInFace()->getNextEdgeInFace(); + EdgePtr e3(edge->getTwinEdge()->getNextEdgeInFace()->getNextEdgeInFace()); le = getLeadingEdgeInTriangle(e3); #ifdef DEBUG_HE if (!le) @@ -322,14 +322,11 @@ bool Triangulation::removeLeadingEdgeFromList(EdgePtr& leadingEdge) { edge->setAsLeadingEdge(false); it = leadingEdges_.erase(it); - break; + return true; } } - if (it == leadingEdges_.end()) - return false; - - return true; + return false; } @@ -451,14 +448,14 @@ EdgePtr Triangulation::splitTriangle(EdgePtr& edge, NodePtr& point) { // Add the node to the structure //NodePtr new_node(new Node(x,y,z)); - NodePtr n1 = edge->getSourceNode(); - EdgePtr e1 = edge; + NodePtr n1(edge->getSourceNode()); + EdgePtr e1(edge); - EdgePtr e2 = edge->getNextEdgeInFace(); - NodePtr n2 = e2->getSourceNode(); + EdgePtr e2(edge->getNextEdgeInFace()); + NodePtr n2(e2->getSourceNode()); - EdgePtr e3 = e2->getNextEdgeInFace(); - NodePtr n3 = e3->getSourceNode(); + EdgePtr e3(e2->getNextEdgeInFace()); + NodePtr n3(e3->getSourceNode()); EdgePtr e1_n(new Edge); EdgePtr e11_n(new Edge); @@ -489,7 +486,6 @@ EdgePtr Triangulation::splitTriangle(EdgePtr& edge, NodePtr& point) { e22_n->setNextEdgeInFace(e2); e33_n->setNextEdgeInFace(e3); - // and update old's next edge e1->setNextEdgeInFace(e2_n); e2->setNextEdgeInFace(e3_n); @@ -500,19 +496,15 @@ EdgePtr Triangulation::splitTriangle(EdgePtr& edge, NodePtr& point) { // Use the field telling if an edge is a leading edge // NOTE: Must search in the list!!! - - EdgePtr leadingEdge; if (e1->isLeadingEdge()) - leadingEdge = e1; + removeLeadingEdgeFromList(e1); else if (e2->isLeadingEdge()) - leadingEdge = e2; + removeLeadingEdgeFromList(e2); else if(e3->isLeadingEdge()) - leadingEdge = e3; + removeLeadingEdgeFromList(e3); else return EdgePtr(); - removeLeadingEdgeFromList(leadingEdge); - addLeadingEdge(e1_n); addLeadingEdge(e2_n); addLeadingEdge(e3_n); @@ -532,16 +524,16 @@ void Triangulation::swapEdge(EdgePtr& diagonal) { // Swap by rotating counterclockwise // Use the same objects - no deletion or new objects - EdgePtr eL = diagonal; - EdgePtr eR = eL->getTwinEdge(); - EdgePtr eL_1 = eL->getNextEdgeInFace(); - EdgePtr eL_2 = eL_1->getNextEdgeInFace(); - EdgePtr eR_1 = eR->getNextEdgeInFace(); - EdgePtr eR_2 = eR_1->getNextEdgeInFace(); + EdgePtr eL(diagonal); + EdgePtr eR(eL->getTwinEdge()); + EdgePtr eL_1(eL->getNextEdgeInFace()); + EdgePtr eL_2(eL_1->getNextEdgeInFace()); + EdgePtr eR_1(eR->getNextEdgeInFace()); + EdgePtr eR_2(eR_1->getNextEdgeInFace()); // avoid node to be dereferenced to zero and deleted - NodePtr nR = eR_2->getSourceNode(); - NodePtr nL = eL_2->getSourceNode(); + NodePtr nR(eR_2->getSourceNode()); + NodePtr nL(eL_2->getSourceNode()); eL->setSourceNode(nR); eR->setSourceNode(nL); @@ -555,24 +547,20 @@ void Triangulation::swapEdge(EdgePtr& diagonal) { eR_2->setNextEdgeInFace(eL_1); eL_1->setNextEdgeInFace(eR); - EdgePtr leL; if (eL->isLeadingEdge()) - leL = eL; + removeLeadingEdgeFromList(eL); else if (eL_1->isLeadingEdge()) - leL = eL_1; + removeLeadingEdgeFromList(eL_1); else if (eL_2->isLeadingEdge()) - leL = eL_2; + removeLeadingEdgeFromList(eL_2); - EdgePtr leR; if (eR->isLeadingEdge()) - leR = eR; + removeLeadingEdgeFromList(eR); else if (eR_1->isLeadingEdge()) - leR = eR_1; + removeLeadingEdgeFromList(eR_1); else if (eR_2->isLeadingEdge()) - leR = eR_2; + removeLeadingEdgeFromList(eR_2); - removeLeadingEdgeFromList(leL); - removeLeadingEdgeFromList(leR); addLeadingEdge(eL); addLeadingEdge(eR); }