diff --git a/common/tool/context_menu.cpp b/common/tool/context_menu.cpp index 9028fd047c..f280a1fd02 100644 --- a/common/tool/context_menu.cpp +++ b/common/tool/context_menu.cpp @@ -186,6 +186,13 @@ void CONTEXT_MENU::UpdateAll() } +TOOL_MANAGER* CONTEXT_MENU::getToolManager() +{ + assert( m_tool ); + return m_tool->GetManager(); +} + + void CONTEXT_MENU::updateHotKeys() { for( std::map::const_iterator it = m_toolActions.begin(); diff --git a/include/tool/context_menu.h b/include/tool/context_menu.h index eca9bf5b66..3e02ace78f 100644 --- a/include/tool/context_menu.h +++ b/include/tool/context_menu.h @@ -125,6 +125,7 @@ public: */ void UpdateAll(); + // Helper typedefs typedef boost::function MENU_HANDLER; typedef boost::function UPDATE_HANDLER; @@ -146,6 +147,16 @@ public: m_update_handler = aUpdateHandler; } +protected: + ///> Returns an instance of TOOL_MANAGER class. + TOOL_MANAGER* getToolManager(); + + ///> Returns the corresponding wxMenuItem identifier for a TOOL_ACTION object. + static inline int getMenuId( const TOOL_ACTION& aAction ) + { + return aAction.GetId() + ACTION_ID; + } + private: // Empty stubs used by the default constructor static OPT_TOOL_EVENT menuHandlerStub(const wxMenuEvent& ); @@ -183,12 +194,6 @@ private: ///> Runs a function on the menu and all its submenus. void runOnSubmenus( boost::function aFunction ); - ///> Returns the corresponding wxMenuItem identifier for a TOOL_ACTION object. - static inline int getMenuId( const TOOL_ACTION& aAction ) - { - return aAction.GetId() + ACTION_ID; - } - ///> Flag indicating that the menu title was set up. bool m_titleSet; diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 7e33530ff0..8f470194e7 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -374,6 +374,10 @@ TOOL_ACTION COMMON_ACTIONS::zoneUnfillAll( "pcbnew.EditorControl.zoneUnfillAll", AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_ZONE_REMOVE_FILLED ), _( "Unfill all" ), _( "Unfill all zones" ) ); +TOOL_ACTION COMMON_ACTIONS::zoneMerge( "pcbnew.EditorControl.zoneMerge", + AS_GLOBAL, 0, + _( "Merge zones" ), _( "Merge zones" ) ); + TOOL_ACTION COMMON_ACTIONS::placeTarget( "pcbnew.EditorControl.placeTarget", AS_GLOBAL, 0, diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 0fbd338e27..aa14264370 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -242,6 +242,7 @@ public: static TOOL_ACTION zoneFillAll; static TOOL_ACTION zoneUnfill; static TOOL_ACTION zoneUnfillAll; + static TOOL_ACTION zoneMerge; // Module editor tools /// Activation of the drawing tool (placing a PAD) diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp index 5b58e546c4..b9fcae052f 100644 --- a/pcbnew/tools/pcb_editor_control.cpp +++ b/pcbnew/tools/pcb_editor_control.cpp @@ -42,11 +42,14 @@ #include #include #include +#include #include #include #include +#include + class ZONE_CONTEXT_MENU : public CONTEXT_MENU { @@ -54,10 +57,26 @@ public: ZONE_CONTEXT_MENU() { SetIcon( add_zone_xpm ); + SetUpdateHandler( boost::bind( &ZONE_CONTEXT_MENU::update, this ) ); Add( COMMON_ACTIONS::zoneFill ); Add( COMMON_ACTIONS::zoneFillAll ); Add( COMMON_ACTIONS::zoneUnfill ); Add( COMMON_ACTIONS::zoneUnfillAll ); + Add( COMMON_ACTIONS::zoneMerge ); + } + +private: + void update() + { + SELECTION_TOOL* selTool = getToolManager()->GetTool(); + + // lines like this make me really think about a better name for SELECTION_CONDITIONS class + bool mergeEnabled = ( SELECTION_CONDITIONS::MoreThan( 1 ) && + /*SELECTION_CONDITIONS::OnlyType( PCB_ZONE_AREA_T ) &&*/ + SELECTION_CONDITIONS::SameNet() && + SELECTION_CONDITIONS::SameLayer() )( selTool->GetSelection() ); + + Enable( getMenuId( COMMON_ACTIONS::zoneMerge ), mergeEnabled ); } }; @@ -473,6 +492,102 @@ int PCB_EDITOR_CONTROL::ZoneUnfillAll( const TOOL_EVENT& aEvent ) } +int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent ) +{ + SELECTION selection = m_toolMgr->GetTool()->GetSelection(); + BOARD* board = getModel(); + RN_DATA* ratsnest = board->GetRatsnest(); + KIGFX::VIEW* view = getView(); + + if( selection.Size() < 2 ) + return 0; + + PICKED_ITEMS_LIST changes; + int netcode = -1; + + // Loop through all combinations + for( int ia1 = 0; ia1 < selection.Size() - 1; ++ia1 ) + { + ZONE_CONTAINER* curr_area = dynamic_cast( selection.Item( ia1 ) ); + + if( !curr_area ) + continue; + + netcode = curr_area->GetNetCode(); + + EDA_RECT b1 = curr_area->Outline()->GetBoundingBox(); + bool mod_ia1 = false; + + for( int ia2 = selection.Size() - 1; ia2 > ia1; --ia2 ) + { + ZONE_CONTAINER* area2 = dynamic_cast( selection.Item( ia2 ) ); + + if( !area2 ) + continue; + + if( area2->GetNetCode() != netcode ) + continue; + + if( curr_area->GetPriority() != area2->GetPriority() ) + continue; + + if( curr_area->GetIsKeepout() != area2->GetIsKeepout() ) + continue; + + if( curr_area->GetLayer() != area2->GetLayer() ) + continue; + + EDA_RECT b2 = area2->Outline()->GetBoundingBox(); + + if( b1.Intersects( b2 ) ) + { + EDA_ITEM* backup = curr_area->Clone(); + bool ret = board->TestAreaIntersection( curr_area, area2 ); + + if( ret && board->CombineAreas( &changes, curr_area, area2 ) ) + { + mod_ia1 = true; + selection.items.RemovePicker( ia2 ); + + ITEM_PICKER picker( curr_area, UR_CHANGED ); + picker.SetLink( backup ); + changes.PushItem( picker ); + } + else + { + delete backup; + } + } + } + + if( mod_ia1 ) + --ia1; // if modified, we need to check it again + } + + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + m_frame->SaveCopyInUndoList( changes, UR_UNSPECIFIED ); + + for( unsigned i = 0; i < changes.GetCount(); ++i ) + { + ITEM_PICKER picker = changes.GetItemWrapper( i ); + BOARD_ITEM* item = static_cast( picker.GetItem() ); + + if( picker.GetStatus() == UR_DELETED ) + { + view->Remove( item ); + ratsnest->Remove( item ); + } + else if( picker.GetStatus() == UR_CHANGED ) + { + item->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); + m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, item ); + } + } + + return 0; +} + + int PCB_EDITOR_CONTROL::SelectionCrossProbe( const TOOL_EVENT& aEvent ) { SELECTION_TOOL* selTool = m_toolMgr->GetTool(); @@ -575,6 +690,7 @@ void PCB_EDITOR_CONTROL::SetTransitions() Go( &PCB_EDITOR_CONTROL::ZoneFillAll, COMMON_ACTIONS::zoneFillAll.MakeEvent() ); Go( &PCB_EDITOR_CONTROL::ZoneUnfill, COMMON_ACTIONS::zoneUnfill.MakeEvent() ); Go( &PCB_EDITOR_CONTROL::ZoneUnfillAll, COMMON_ACTIONS::zoneUnfillAll.MakeEvent() ); + Go( &PCB_EDITOR_CONTROL::ZoneMerge, COMMON_ACTIONS::zoneMerge.MakeEvent() ); // Placing tools Go( &PCB_EDITOR_CONTROL::PlaceTarget, COMMON_ACTIONS::placeTarget.MakeEvent() ); diff --git a/pcbnew/tools/pcb_editor_control.h b/pcbnew/tools/pcb_editor_control.h index e038ae304a..901a2f5c5e 100644 --- a/pcbnew/tools/pcb_editor_control.h +++ b/pcbnew/tools/pcb_editor_control.h @@ -60,6 +60,7 @@ public: int ZoneFillAll( const TOOL_EVENT& aEvent ); int ZoneUnfill( const TOOL_EVENT& aEvent ); int ZoneUnfillAll( const TOOL_EVENT& aEvent ); + int ZoneMerge( const TOOL_EVENT& aEvent ); /** * Function PlaceTarget()