New connectivity algorithm and bus upgrades

Bus upgrades: core new connectivity code

Bus upgrades: eeschema integration and modifications

Bus upgrades: eeschema dialogs

Bus upgrades: netlist export

Bus upgrades: file format changes
This commit is contained in:
Jon Evans 2019-03-11 17:32:05 -04:00 committed by Wayne Stambaugh
parent 8985badc64
commit 83c7e7fc65
89 changed files with 7147 additions and 414 deletions

View File

@ -585,7 +585,7 @@ find_package( Pixman 0.30 REQUIRED )
#
# Find Boost headers, required.
find_package( Boost 1.54.0 REQUIRED )
find_package( Boost 1.54.0 REQUIRED COMPONENTS regex )
# Include MinGW resource compiler.
include( MinGWResourceCompiler )

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2013 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2018 CERN
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -28,6 +29,7 @@
*/
#include <kicad_string.h>
#include <confirm.h>
#include <validators.h>
#include <wx/grid.h>
@ -220,6 +222,57 @@ void ENV_VAR_NAME_VALIDATOR::OnTextChanged( wxCommandEvent& event )
}
bool REGEX_VALIDATOR::Validate( wxWindow* aParent )
{
// If window is disabled, simply return
if( !m_validatorWindow->IsEnabled() )
return true;
wxTextEntry* const textEntry = GetTextEntry();
if( !textEntry )
return false;
bool valid = true;
const wxString& value = textEntry->GetValue();
if( m_regEx.Matches( value ) )
{
size_t start, len;
m_regEx.GetMatch( &start, &len );
if( start != 0 || len != value.Length() ) // whole string must match
valid = false;
}
else // no match at all
{
valid = false;
}
if( !valid )
{
m_validatorWindow->SetFocus();
DisplayError( aParent, wxString::Format( _( "Incorrect value: %s" ), value ) );
return false;
}
return true;
}
void REGEX_VALIDATOR::compileRegEx( const wxString& aRegEx, int aFlags )
{
if( !m_regEx.Compile( aRegEx, aFlags ) )
{
throw std::runtime_error( "REGEX_VALIDATOR: Invalid regular expression: "
+ aRegEx.ToStdString() );
}
m_regExString = aRegEx;
m_regExFlags = aFlags;
}
void KIUI::ValidatorTransferToWindowWithoutEvents( wxValidator& aValidator )
{
wxWindow* ctrl = aValidator.GetWindow();
@ -228,4 +281,4 @@ void KIUI::ValidatorTransferToWindowWithoutEvents( wxValidator& aValidator )
wxEventBlocker orient_update_blocker( ctrl, wxEVT_ANY );
aValidator.TransferToWindow();
}
}

View File

@ -37,6 +37,7 @@ set( EESCHEMA_DLGS
dialogs/dialog_bom.cpp
dialogs/dialog_bom_base.cpp
dialogs/dialog_bom_cfg_keywords.cpp
dialogs/dialog_bus_manager.cpp
dialogs/dialog_fields_editor_global.cpp
dialogs/dialog_fields_editor_global_base.cpp
dialogs/dialog_choose_component.cpp
@ -64,6 +65,8 @@ set( EESCHEMA_DLGS
dialogs/dialog_lib_edit_text_base.cpp
dialogs/dialog_lib_new_component.cpp
dialogs/dialog_lib_new_component_base.cpp
dialogs/dialog_migrate_buses.cpp
dialogs/dialog_migrate_buses_base.cpp
dialogs/dialog_netlist.cpp
dialogs/dialog_netlist_base.cpp
dialogs/dialog_plot_schematic.cpp
@ -136,6 +139,7 @@ set( EESCHEMA_SRCS
autoplace_fields.cpp
backanno.cpp
block.cpp
bus_alias.cpp
bus-wire-junction.cpp
busentry.cpp
class_libentry.cpp
@ -144,6 +148,7 @@ set( EESCHEMA_SRCS
cmp_library_lexer.cpp
component_references_lister.cpp
controle.cpp
connection_graph.cpp
cross-probing.cpp
drc_erc_item.cpp
edit_bitmap.cpp
@ -195,6 +200,7 @@ set( EESCHEMA_SRCS
sch_bus_entry.cpp
sch_collectors.cpp
sch_component.cpp
sch_connection.cpp
sch_eagle_plugin.cpp
sch_field.cpp
sch_io_mgr.cpp
@ -204,6 +210,7 @@ set( EESCHEMA_SRCS
sch_line.cpp
sch_marker.cpp
sch_no_connect.cpp
sch_pin_connection.cpp
sch_plugin.cpp
sch_preview_panel.cpp
sch_screen.cpp

View File

@ -62,7 +62,7 @@ void SCH_EDIT_FRAME::DeleteAnnotation( bool aCurrentSheetOnly )
{
SCH_SCREEN* screen = GetScreen();
wxCHECK_RET( screen != NULL, wxT( "Attempt to clear annotation of a NULL screen." ) );
screen->ClearAnnotation( m_CurrentSheet );
screen->ClearAnnotation( g_CurrentSheet );
}
else
{
@ -71,7 +71,7 @@ void SCH_EDIT_FRAME::DeleteAnnotation( bool aCurrentSheetOnly )
}
// Update the references for the sheet that is currently being displayed.
m_CurrentSheet->UpdateAllScreenReferences();
g_CurrentSheet->UpdateAllScreenReferences();
SyncView();
GetCanvas()->Refresh();
@ -125,7 +125,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
}
else
{
m_CurrentSheet->GetMultiUnitComponents( lockedComponents );
g_CurrentSheet->GetMultiUnitComponents( lockedComponents );
}
}
@ -146,7 +146,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
}
else
{
m_CurrentSheet->GetComponents( references );
g_CurrentSheet->GetComponents( references );
}
// Break full components reference in name (prefix) and number:
@ -233,7 +233,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
aReporter.ReportTail( _( "Annotation complete." ), REPORTER::RPT_ACTION );
// Update on screen references, that can be modified by previous calculations:
m_CurrentSheet->UpdateAllScreenReferences();
g_CurrentSheet->UpdateAllScreenReferences();
SetSheetNumberAndCount();
SyncView();
@ -252,7 +252,7 @@ int SCH_EDIT_FRAME::CheckAnnotate( REPORTER& aReporter, bool aOneSheetOnly )
if( !aOneSheetOnly )
sheetList.GetComponents( componentsList );
else
m_CurrentSheet->GetComponents( componentsList );
g_CurrentSheet->GetComponents( componentsList );
return componentsList.CheckAnnotation( aReporter );
}

View File

@ -455,7 +455,7 @@ void SCH_EDIT_FRAME::PasteListOfItems( wxDC* DC )
return;
}
wxFileName destFn = m_CurrentSheet->Last()->GetFileName();
wxFileName destFn = g_CurrentSheet->Last()->GetFileName();
if( destFn.IsRelative() )
destFn.MakeAbsolute( Prj().GetProjectPath() );

View File

@ -42,6 +42,7 @@
#include <sch_text.h>
#include <sch_component.h>
#include <sch_sheet.h>
#include <list_operations.h>
#include <sch_view.h>
#include <view/view_group.h>
@ -53,7 +54,6 @@ static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint&
static DLIST< SCH_ITEM > s_wires; // when creating a new set of wires,
// stores here the new wires.
/**
* In a contiguous list of wires, remove wires that backtrack over the previous
* wire. Example:
@ -130,15 +130,49 @@ static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosi
wxPoint endpos = frame->GetCrossHairPosition();
auto view = static_cast<SCH_DRAW_PANEL*>( aPanel )->GetView();
view->ClearPreview();
// Update the bus unfold posture based on the mouse movement
if( frame->m_busUnfold.in_progress && !frame->m_busUnfold.label_placed )
{
auto cursor_delta = frame->GetCursorPosition( false ) - frame->m_busUnfold.origin;
auto entry = frame->m_busUnfold.entry;
bool offset = ( cursor_delta.x < 0 );
char shape = ( offset ? ( ( cursor_delta.y >= 0 ) ? '/' : '\\' )
: ( ( cursor_delta.y >= 0 ) ? '\\' : '/' ) );
// Erase and redraw if necessary
if( shape != entry->GetBusEntryShape() ||
offset != frame->m_busUnfold.offset )
{
entry->SetBusEntryShape( shape );
wxPoint entry_pos = frame->m_busUnfold.origin;
if( offset )
entry_pos -= entry->GetSize();
entry->SetPosition( entry_pos );
frame->m_busUnfold.offset = offset;
frame->RefreshItem( entry );
wxPoint wire_start = ( offset ? entry->GetPosition() : entry->m_End() );
( (SCH_LINE*) s_wires.begin() )->SetStartPoint( wire_start );
}
// Update the label "ghost" position
auto label = frame->m_busUnfold.label;
label->SetPosition( endpos );
view->AddToPreview( label->Clone() );
}
if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */
ComputeBreakPoint( frame->GetScreen(), (SCH_LINE*) s_wires.GetLast()->Back(), endpos );
else
( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos );
auto view = static_cast<SCH_DRAW_PANEL*>( aPanel )->GetView();
view->ClearPreview();
for( SCH_LINE* segment = (SCH_LINE*) s_wires.begin(); segment; segment = segment->Next() )
{
if( !segment->IsNull() ) // Add to preview if segment length != 0
@ -206,6 +240,30 @@ void SCH_EDIT_FRAME::BeginSegment( int type )
}
else // A segment is in progress: terminates the current segment and add a new segment.
{
// Place the label for bus unfolding if needed
if( IsBusUnfoldInProgress() && !m_busUnfold.label_placed )
{
wxASSERT( type == LAYER_WIRE );
AddToScreen( m_busUnfold.label );
m_busUnfold.label_placed = true;
nextSegment = new SCH_LINE( cursorpos, LAYER_WIRE );
segment->ClearFlags( IS_NEW );
segment->SetFlags( SELECTED );
nextSegment->SetStartPoint( cursorpos );
nextSegment->SetFlags( IS_NEW );
s_wires.PushBack( nextSegment );
GetScreen()->SetCurItem( nextSegment );
m_canvas->SetMouseCapture( DrawSegment, AbortCreateNewLine );
SetRepeatItem( NULL );
return;
}
SCH_LINE* prevSegment = segment->Back();
// Be aware prevSegment can be null when the horizontal and vertical lines only switch
@ -230,7 +288,8 @@ void SCH_EDIT_FRAME::BeginSegment( int type )
m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
// Terminate the command if the end point is on a pin, junction, or another wire or bus.
if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) )
if( !IsBusUnfoldInProgress() &&
GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) )
{
EndSegment();
return;
@ -328,6 +387,18 @@ void SCH_EDIT_FRAME::EndSegment()
itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) );
}
if( IsBusUnfoldInProgress() && m_busUnfold.label_placed )
{
wxASSERT( m_busUnfold.entry && m_busUnfold.label );
PICKED_ITEMS_LIST bus_items;
bus_items.PushItem( ITEM_PICKER( m_busUnfold.entry, UR_NEW ) );
bus_items.PushItem( ITEM_PICKER( m_busUnfold.label, UR_NEW ) );
SaveCopyInUndoList( bus_items, UR_NEW, false );
}
// Get the last non-null wire (this is the last created segment).
SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() );
@ -366,7 +437,13 @@ void SCH_EDIT_FRAME::EndSegment()
AddJunction( i, true );
}
if( IsBusUnfoldInProgress() )
{
FinishBusUnfold();
}
TestDanglingEnds();
screen->ClearDrawingState();
screen->SetCurItem( NULL );
m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false );
@ -564,12 +641,14 @@ bool SCH_EDIT_FRAME::TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool
}
bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend )
bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend, SCH_SCREEN* aScreen )
{
SCH_ITEM* item = NULL;
SCH_ITEM* secondItem = NULL;
PICKED_ITEMS_LIST itemList;
SCH_SCREEN* screen = GetScreen();
if( aScreen == nullptr )
aScreen = GetScreen();
auto remove_item = [ &itemList ]( SCH_ITEM* aItem ) -> void
{
@ -577,9 +656,9 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend )
itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
};
BreakSegmentsOnJunctions( true );
BreakSegmentsOnJunctions( true, aScreen );
for( item = screen->GetDrawItems(); item; item = item->Next() )
for( item = aScreen->GetDrawItems(); item; item = item->Next() )
{
if( ( item->Type() != SCH_LINE_T )
&& ( item->Type() != SCH_JUNCTION_T )
@ -591,7 +670,7 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend )
// Remove unneeded junctions
if( ( item->Type() == SCH_JUNCTION_T )
&& ( !screen->IsJunctionNeeded( item->GetPosition() ) ) )
&& ( !aScreen->IsJunctionNeeded( item->GetPosition() ) ) )
{
remove_item( item );
continue;
@ -634,16 +713,16 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend )
// If the end points overlap, check if we still need the junction
if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
needed = screen->IsJunctionNeeded( firstLine->GetStartPoint() );
needed = aScreen->IsJunctionNeeded( firstLine->GetStartPoint() );
else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
needed = screen->IsJunctionNeeded( firstLine->GetEndPoint() );
needed = aScreen->IsJunctionNeeded( firstLine->GetEndPoint() );
if( !needed && ( line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) ) )
{
remove_item( item );
remove_item( secondItem );
itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
AddToScreen( line );
AddToScreen( line, aScreen );
break;
}
}
@ -653,33 +732,33 @@ bool SCH_EDIT_FRAME::SchematicCleanUp( bool aAppend )
}
}
for( item = screen->GetDrawItems(); item; item = secondItem )
for( item = aScreen->GetDrawItems(); item; item = secondItem )
{
secondItem = item->Next();
if( item->GetFlags() & STRUCT_DELETED )
RemoveFromScreen( item );
RemoveFromScreen( item, aScreen );
}
SaveCopyInUndoList( itemList, UR_CHANGED, aAppend );
return itemList.GetCount() > 0;
}
bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend,
SCH_LINE** aNewSegment )
bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint,
bool aAppend, SCH_LINE** aNewSegment,
SCH_SCREEN* aScreen )
{
if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint )
|| aSegment->IsEndPoint( aPoint ) )
return false;
SaveCopyInUndoList( aSegment, UR_CHANGED, aAppend );
if( aScreen == nullptr )
aScreen = GetScreen();
SCH_LINE* newSegment = new SCH_LINE( *aSegment );
SaveCopyInUndoList( newSegment, UR_NEW, true );
newSegment->SetStartPoint( aPoint );
AddToScreen( newSegment );
AddToScreen( newSegment, aScreen );
RefreshItem( aSegment );
aSegment->SetEndPoint( aPoint );
@ -691,33 +770,41 @@ bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bo
}
bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend )
bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend,
SCH_SCREEN* aScreen )
{
if( aScreen == nullptr )
aScreen = GetScreen();
bool brokenSegments = false;
for( SCH_ITEM* segment = GetScreen()->GetDrawItems(); segment; segment = segment->Next() )
for( SCH_ITEM* segment = aScreen->GetDrawItems(); segment; segment = segment->Next() )
{
if( ( segment->Type() != SCH_LINE_T ) || ( segment->GetLayer() == LAYER_NOTES ) )
continue;
brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint, aAppend || brokenSegments );
brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint,
aAppend || brokenSegments, NULL, aScreen );
}
return brokenSegments;
}
bool SCH_EDIT_FRAME::BreakSegmentsOnJunctions( bool aAppend )
bool SCH_EDIT_FRAME::BreakSegmentsOnJunctions( bool aAppend, SCH_SCREEN* aScreen )
{
if( aScreen == nullptr )
aScreen = GetScreen();
bool brokenSegments = false;
for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
{
if( item->Type() == SCH_JUNCTION_T )
{
SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item;
if( BreakSegments( junction->GetPosition(), brokenSegments || aAppend ) )
if( BreakSegments( junction->GetPosition(), brokenSegments || aAppend, aScreen ) )
brokenSegments = true;
}
else
@ -725,8 +812,8 @@ bool SCH_EDIT_FRAME::BreakSegmentsOnJunctions( bool aAppend )
SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item );
if( busEntry )
{
if( BreakSegments( busEntry->GetPosition(), brokenSegments || aAppend )
|| BreakSegments( busEntry->m_End(), brokenSegments || aAppend ) )
if( BreakSegments( busEntry->GetPosition(), brokenSegments || aAppend, aScreen )
|| BreakSegments( busEntry->m_End(), brokenSegments || aAppend, aScreen ) )
brokenSegments = true;
}
}
@ -846,6 +933,7 @@ SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( const wxPoint& aPosition )
static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
{
SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
if( screen->GetCurItem() )
@ -858,6 +946,11 @@ static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
parent->SetRepeatItem( NULL );
}
if( parent->IsBusUnfoldInProgress() )
{
parent->CancelBusUnfold();
}
auto view = static_cast<SCH_DRAW_PANEL*>(aPanel)->GetView();
view->ClearPreview();
view->ShowPreview( false );

41
eeschema/bus_alias.cpp Normal file
View File

@ -0,0 +1,41 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include "bus_alias.h"
BUS_ALIAS::BUS_ALIAS( SCH_SCREEN* aParent ) :
m_parent( aParent )
{
}
BUS_ALIAS::~BUS_ALIAS()
{
}
bool BUS_ALIAS::Contains( const wxString& aName )
{
return ( std::find( m_members.begin(), m_members.end(), aName )
!= m_members.end() );
}

100
eeschema/bus_alias.h Normal file
View File

@ -0,0 +1,100 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BUS_ALIAS_H
#define _BUS_ALIAS_H
#include <memory>
#include <vector>
#include <wx/string.h>
class SCH_SCREEN;
class BUS_ALIAS
{
public:
BUS_ALIAS( SCH_SCREEN* aParent = NULL );
~BUS_ALIAS();
std::shared_ptr< BUS_ALIAS > Clone() const
{
return std::make_shared< BUS_ALIAS >( *this );
}
wxString GetName()
{
return m_name;
}
void SetName( const wxString& aName )
{
m_name = aName;
}
void ClearMembers()
{
m_members.clear();
}
void AddMember( const wxString& aName )
{
m_members.push_back( aName );
}
int GetMemberCount()
{
return m_members.size();
}
std::vector< wxString >& Members()
{
return m_members;
}
bool Contains( const wxString& aName );
SCH_SCREEN* GetParent()
{
return m_parent;
}
void SetParent( SCH_SCREEN* aParent )
{
m_parent = aParent;
}
protected:
wxString m_name;
std::vector< wxString > m_members;
/**
* The bus alias editor dialog can edit aliases from all open sheets.
* This means we have to store a reference back to our parent so that
* the dialog can update the parent if aliases are changed or removed.
*/
SCH_SCREEN* m_parent;
};
#endif

File diff suppressed because it is too large Load Diff

327
eeschema/connection_graph.h Normal file
View File

@ -0,0 +1,327 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CONNECTION_GRAPH_H
#define _CONNECTION_GRAPH_H
#include <mutex>
#include <vector>
#include <common.h>
#include <erc_settings.h>
#include <sch_connection.h>
#include <sch_item_struct.h>
#ifdef DEBUG
// Uncomment this line to enable connectivity debugging features
// #define CONNECTIVITY_DEBUG
#endif
class SCH_PIN_CONNECTION;
class SCH_EDIT_FRAME;
/**
* A subgraph is a set of items that are "physically" connected in the schematic.
*
* For example, a label connected to a wire and so on.
* A net is composed of one or more subgraphs.
*
* A set of items that appears to be physically connected may actually be more
* than one subgraph, because some items don't connect electrically.
*
* For example, multiple bus wires can come together at a junction but have
* different labels on each branch. Each label+wire branch is its own subgraph.
*
*/
class CONNECTION_SUBGRAPH
{
public:
CONNECTION_SUBGRAPH( SCH_EDIT_FRAME* aFrame ) :
m_dirty( false ), m_code( -1 ), m_multiple_power_ports( false ),
m_no_connect( nullptr ), m_driver( nullptr ), m_frame( aFrame )
{}
/**
* Determines which potential driver should drive the subgraph.
*
* If multiple possible drivers exist, picks one according to the priority.
* If multiple "winners" exist, returns false and sets m_driver to nullptr.
*
* @param aCreateMarkers controls whether ERC markers should be added for conflicts
* @return true if m_driver was set, or false if a conflict occurred
*/
bool ResolveDrivers( bool aCreateMarkers = false );
/**
* Returns the fully-qualified net name for this subgraph (if one exists)
*/
wxString GetNetName();
/// Returns all the bus labels attached to this subgraph (if any)
std::vector<SCH_ITEM*> GetBusLabels();
bool m_dirty;
long m_code;
/// True if this subgraph contains multiple power ports to join in one net
bool m_multiple_power_ports;
/// No-connect item in graph, if any
SCH_ITEM* m_no_connect;
std::vector<SCH_ITEM*> m_items;
std::vector<SCH_ITEM*> m_drivers;
SCH_ITEM* m_driver;
SCH_SHEET_PATH m_sheet;
// Needed for m_UserUnits for now; maybe refactor later
SCH_EDIT_FRAME* m_frame;
/**
* This map stores pointers to other subgraphs on the same sheet as this one
* which should be connected to this one.
*
* For example, if this subgraph is part of the bus D[7..0] and there is
* another subgraph on this sheet with connection D7, this map will include
* a pointer to that subgraph under the key D7 (where the key comes from
* the m_members list of the SCH_CONNECTION that drives this subgraph)
*/
std::unordered_map< std::shared_ptr<SCH_CONNECTION>,
std::vector<CONNECTION_SUBGRAPH*> > m_neighbor_map;
};
/**
* Calculates the connectivity of a schematic and generates netlists
*/
class CONNECTION_GRAPH
{
public:
CONNECTION_GRAPH( SCH_EDIT_FRAME* aFrame) :
m_frame( aFrame )
{}
void Reset();
/**
* Updates the connection graph for the given list of sheets.
*
* @param aSheetList should be the whole schematic for now
*/
void Recalculate( SCH_SHEET_LIST aSheetList );
/**
* Updates the connectivity graph based on a single item
*/
void RebuildGraphForItem( SCH_ITEM* aItem );
/**
* Returns a bus alias pointer for the given name if it exists (from cache)
*
* CONNECTION_GRAPH caches these, they are owned by the SCH_SCREEN that
* the alias was defined on. The cache is only used to update the graph.
*/
std::shared_ptr<BUS_ALIAS> GetBusAlias( wxString aName );
/**
* Determines which subgraphs have more than one conflicting bus label.
*
* @see DIALOG_MIGRATE_BUSES
* @return a list of subgraphs that need migration
*/
std::vector<CONNECTION_SUBGRAPH*> GetBusesNeedingMigration();
/**
* Returns true if the graph makes use of any of the new bus features
*
* For quality control during rollout of new bus features:
* - Aliases
* - Bus groups
*/
bool UsesNewBusFeatures() const;
/**
* Runs electrical rule checks on the connectivity graph.
*
* Precondition: graph is up-to-date
*
* @param aSettings is used to control which tests to run
* @param aCreateMarkers controls whether error markers are created
* @return the number of errors found
*/
int RunERC( const ERC_SETTINGS& aSettings, bool aCreateMarkers = true );
// TODO(JE) firm up API and move to private
std::map<int, std::vector<CONNECTION_SUBGRAPH*> > m_net_code_to_subgraphs_map;
private:
std::vector<SCH_ITEM*> m_items;
std::vector<CONNECTION_SUBGRAPH*> m_subgraphs;
std::vector<SCH_PIN_CONNECTION*> m_invisible_power_pins;
std::map<wxString, std::shared_ptr<BUS_ALIAS>> m_bus_alias_cache;
std::map<wxString, int> m_net_name_to_code_map;
std::map<wxString, int> m_bus_name_to_code_map;
std::unordered_map<int, CONNECTION_SUBGRAPH*> m_subgraph_code_map;
int m_last_net_code;
int m_last_bus_code;
int m_last_subgraph_code;
std::mutex m_item_mutex;
// Needed for m_UserUnits for now; maybe refactor later
SCH_EDIT_FRAME* m_frame;
/**
* Updates the graphical connectivity between items (i.e. where they touch)
* The items passed in must be on the same sheet.
*
* In the first phase, all items in aItemList have their connections
* initialized for the given sheet (since they may have connections on more
* than one sheet, and each needs to be calculated individually). The
* graphical connection points for the item are added to a map that stores
* (x, y) -> [list of items].
*
* Any item that is stored in the list of items that have a connection point
* at a given (x, y) location will eventually be electrically connected.
* This means that we can't store SCH_COMPONENTs in this map -- we must store
* a structure that links a specific pin on a component back to that
* component: a SCH_PIN_CONNECTION. This wrapper class is a convenience for
* linking a pin and component to a specific (x, y) point.
*
* In the second phase, we iterate over each value in the map, which is a
* vector of items that have overlapping connection points. After some
* checks to ensure that the items should actually connect, the items are
* linked together using ConnectedItems().
*
* As a side effect, items are loaded into m_items for BuildConnectionGraph()
*
* @param aSheet is the path to the sheet of all items in the list
* @param aItemList is a list of items to consider
*/
void updateItemConnectivity( SCH_SHEET_PATH aSheet,
std::vector<SCH_ITEM*> aItemList );
/**
* Generates the connection graph (after all item connectivity has been updated)
*
* In the first phase, the algorithm iterates over all items, and then over
* all items that are connected (graphically) to each item, placing them into
* CONNECTION_SUBGRAPHs. Items that can potentially drive connectivity (i.e.
* labels, pins, etc.) are added to the m_drivers vector of the subgraph.
*
* In the second phase, each subgraph is resolved. To resolve a subgraph,
* the driver is first selected by CONNECTION_SUBGRAPH::ResolveDrivers(),
* and then the connection for the chosen driver is propagated to all the
* other items in the subgraph.
*/
void buildConnectionGraph();
/**
* Helper to assign a new net code to a connection
*
* @return the assigned code
*/
int assignNewNetCode( SCH_CONNECTION& aConnection );
/**
* Checks one subgraph for conflicting connections between net and bus labels
*
* For example, a net wire connected to a bus port/pin, or vice versa
*
* @param aSubgraph is the subgraph to examine
* @param aCreateMarkers controls whether error markers are created
* @return true for no errors, false for errors
*/
bool ercCheckBusToNetConflicts( CONNECTION_SUBGRAPH* aSubgraph,
bool aCreateMarkers );
/**
* Checks one subgraph for conflicting connections between two bus items
*
* For example, a labeled bus wire connected to a hierarchical sheet pin
* where the labeled bus doesn't contain any of the same bus members as the
* sheet pin
*
* @param aSubgraph is the subgraph to examine
* @param aCreateMarkers controls whether error markers are created
* @return true for no errors, false for errors
*/
bool ercCheckBusToBusConflicts( CONNECTION_SUBGRAPH* aSubgraph,
bool aCreateMarkers );
/**
* Checks one subgraph for conflicting bus entry to bus connections
*
* For example, a wire with label "A0" is connected to a bus labeled "D[8..0]"
*
* Will also check for mistakes related to bus group names, for example:
* A bus group named "USB{DP DM}" should have bus entry connections like
* "USB.DP" but someone might accidentally just enter "DP"
*
* @param aSubgraph is the subgraph to examine
* @param aCreateMarkers controls whether error markers are created
* @return true for no errors, false for errors
*/
bool ercCheckBusToBusEntryConflicts( CONNECTION_SUBGRAPH* aSubgraph,
bool aCreateMarkers );
/**
* Checks one subgraph for proper presence or absence of no-connect symbols
*
* A pin with a no-connect symbol should not have any connections
* A pin without a no-connect symbol should have at least one connection
*
* @param aSubgraph is the subgraph to examine
* @param aCreateMarkers controls whether error markers are created
* @return true for no errors, false for errors
*/
bool ercCheckNoConnects( CONNECTION_SUBGRAPH* aSubgraph,
bool aCreateMarkers );
/**
* Checks one subgraph for proper connection of labels
*
* Labels should be connected to something
*
* @param aSubgraph is the subgraph to examine
* @param aCreateMarkers controls whether error markers are created
* @return true for no errors, false for errors
*/
bool ercCheckLabels( CONNECTION_SUBGRAPH* aSubgraph, bool aCreateMarkers );
};
#endif

View File

@ -228,9 +228,6 @@ SCH_ITEM* SCH_EDIT_FRAME::LocateItem( const wxPoint& aPosition, const KICAD_T aF
if( item )
{
if( item->Type() == SCH_COMPONENT_T )
( (SCH_COMPONENT*) item )->SetCurrentSheetPath( &GetCurrentSheet() );
MSG_PANEL_ITEMS items;
item->GetMsgPanelInfo( m_UserUnits, items );
SetMsgPanel( items );

View File

@ -0,0 +1,517 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <wx/tokenzr.h>
#include <invoke_sch_dialog.h>
#include <sch_sheet_path.h>
#include "dialog_bus_manager.h"
BEGIN_EVENT_TABLE( DIALOG_BUS_MANAGER, DIALOG_SHIM )
EVT_BUTTON( wxID_OK, DIALOG_BUS_MANAGER::OnOkClick )
EVT_BUTTON( wxID_CANCEL, DIALOG_BUS_MANAGER::OnCancelClick )
END_EVENT_TABLE()
DIALOG_BUS_MANAGER::DIALOG_BUS_MANAGER( SCH_EDIT_FRAME* aParent )
: DIALOG_SHIM( aParent, wxID_ANY, _( "Bus Definitions" ),
wxDefaultPosition, wxSize( 640, 480 ),
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
m_parent( aParent )
{
auto sizer = new wxBoxSizer( wxVERTICAL );
auto buttons = new wxStdDialogButtonSizer();
buttons->AddButton( new wxButton( this, wxID_OK ) );
buttons->AddButton( new wxButton( this, wxID_CANCEL ) );
buttons->Realize();
auto top_container = new wxBoxSizer( wxHORIZONTAL );
auto left_pane = new wxBoxSizer( wxVERTICAL );
auto right_pane = new wxBoxSizer( wxVERTICAL );
// Left pane: alias list
auto lbl_aliases = new wxStaticText( this, wxID_ANY, _( "Bus Aliases" ),
wxDefaultPosition, wxDefaultSize,
wxALIGN_LEFT );
m_bus_list_view = new wxListView( this, wxID_ANY, wxDefaultPosition,
wxSize( 300, 300 ), wxLC_ALIGN_LEFT |
wxLC_NO_HEADER | wxLC_REPORT |
wxLC_SINGLE_SEL );
m_bus_list_view->InsertColumn( 0, "" );
auto lbl_alias_edit = new wxStaticText( this, wxID_ANY, _( "Alias Name" ),
wxDefaultPosition, wxDefaultSize,
wxALIGN_LEFT );
m_bus_edit = new wxTextCtrl( this, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
auto left_button_sizer = new wxBoxSizer( wxHORIZONTAL );
m_btn_add_bus = new wxButton( this, wxID_ANY, _( "Add" ) );
m_btn_rename_bus = new wxButton( this, wxID_ANY, _( "Rename" ) );
m_btn_remove_bus = new wxButton( this, wxID_ANY, _( "Remove" ) );
left_button_sizer->Add( m_btn_add_bus );
left_button_sizer->Add( m_btn_rename_bus );
left_button_sizer->Add( m_btn_remove_bus );
left_pane->Add( lbl_aliases, 0, wxEXPAND | wxALL, 5 );
left_pane->Add( m_bus_list_view, 1, wxEXPAND | wxALL, 5 );
left_pane->Add( lbl_alias_edit, 0, wxEXPAND | wxALL, 5 );
left_pane->Add( m_bus_edit, 0, wxEXPAND | wxALL, 5 );
left_pane->Add( left_button_sizer, 0, wxEXPAND | wxALL, 5 );
// Right pane: signal list
auto lbl_signals = new wxStaticText( this, wxID_ANY, _( "Alias Members" ),
wxDefaultPosition, wxDefaultSize,
wxALIGN_LEFT );
m_signal_list_view = new wxListView( this, wxID_ANY, wxDefaultPosition,
wxSize( 300, 300 ), wxLC_ALIGN_LEFT |
wxLC_NO_HEADER | wxLC_REPORT |
wxLC_SINGLE_SEL );
m_signal_list_view->InsertColumn( 0, "" );
auto lbl_signal_edit = new wxStaticText( this, wxID_ANY, _( "Member Name" ),
wxDefaultPosition, wxDefaultSize,
wxALIGN_LEFT );
m_signal_edit = new wxTextCtrl( this, wxID_ANY, wxEmptyString,
wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
auto right_button_sizer = new wxBoxSizer( wxHORIZONTAL );
m_btn_add_signal = new wxButton( this, wxID_ANY, _( "Add" ) );
m_btn_rename_signal = new wxButton( this, wxID_ANY, _( "Rename" ) );
m_btn_remove_signal = new wxButton( this, wxID_ANY, _( "Remove" ) );
right_button_sizer->Add( m_btn_add_signal );
right_button_sizer->Add( m_btn_rename_signal );
right_button_sizer->Add( m_btn_remove_signal );
right_pane->Add( lbl_signals, 0, wxEXPAND | wxALL, 5 );
right_pane->Add( m_signal_list_view, 1, wxEXPAND | wxALL, 5 );
right_pane->Add( lbl_signal_edit, 0, wxEXPAND | wxALL, 5 );
right_pane->Add( m_signal_edit, 0, wxEXPAND | wxALL, 5 );
right_pane->Add( right_button_sizer, 0, wxEXPAND | wxALL, 5 );
top_container->Add( left_pane, 1, wxEXPAND );
top_container->Add( right_pane, 1, wxEXPAND );
sizer->Add( top_container, 1, wxEXPAND | wxALL, 5 );
sizer->Add( buttons, 0, wxEXPAND | wxBOTTOM, 10 );
SetSizer( sizer );
// Setup validators
wxTextValidator validator;
validator.SetStyle( wxFILTER_EXCLUDE_CHAR_LIST );
validator.SetCharExcludes( "\r\n\t " );
m_bus_edit->SetValidator( validator );
// Allow spaces in the signal edit, so that you can type in a list of
// signals in the box and it can automatically split them when you add.
validator.SetCharExcludes( "\r\n\t" );
m_signal_edit->SetValidator( validator );
// Setup events
Bind( wxEVT_INIT_DIALOG, &DIALOG_BUS_MANAGER::OnInitDialog, this );
m_bus_list_view->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED,
wxListEventHandler( DIALOG_BUS_MANAGER::OnSelectBus ), NULL, this );
m_bus_list_view->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED,
wxListEventHandler( DIALOG_BUS_MANAGER::OnSelectBus ), NULL, this );
m_signal_list_view->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED,
wxListEventHandler( DIALOG_BUS_MANAGER::OnSelectSignal ), NULL, this );
m_signal_list_view->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED,
wxListEventHandler( DIALOG_BUS_MANAGER::OnSelectSignal ), NULL, this );
m_btn_add_bus->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnAddBus ), NULL, this );
m_btn_rename_bus->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnRenameBus ), NULL, this );
m_btn_remove_bus->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnRemoveBus ), NULL, this );
m_signal_edit->Connect( wxEVT_TEXT_ENTER,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnAddSignal ), NULL, this );
m_btn_add_signal->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnAddSignal ), NULL, this );
m_btn_rename_signal->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnRenameSignal ), NULL, this );
m_btn_remove_signal->Connect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnRemoveSignal ), NULL, this );
m_bus_edit->Connect( wxEVT_TEXT_ENTER,
wxCommandEventHandler( DIALOG_BUS_MANAGER::OnAddBus ), NULL, this );
// Set initial UI state
m_btn_rename_bus->Disable();
m_btn_remove_bus->Disable();
m_btn_add_signal->Disable();
m_btn_rename_signal->Disable();
m_btn_remove_signal->Disable();
m_bus_edit->SetHint( _T( "Bus Alias Name" ) );
m_signal_edit->SetHint( _T( "Net or Bus Name" ) );
FinishDialogSettings();
}
void DIALOG_BUS_MANAGER::OnInitDialog( wxInitDialogEvent& aEvent )
{
TransferDataToWindow();
}
bool DIALOG_BUS_MANAGER::TransferDataToWindow()
{
m_aliases.clear();
SCH_SHEET_LIST aSheets( g_RootSheet );
std::vector< std::shared_ptr< BUS_ALIAS > > original_aliases;
// collect aliases from each open sheet
for( unsigned i = 0; i < aSheets.size(); i++ )
{
auto sheet_aliases = aSheets[i].LastScreen()->GetBusAliases();
original_aliases.insert( original_aliases.end(), sheet_aliases.begin(),
sheet_aliases.end() );
}
original_aliases.erase( std::unique( original_aliases.begin(),
original_aliases.end() ),
original_aliases.end() );
// clone into a temporary working set
int idx = 0;
for( auto alias : original_aliases )
{
m_aliases.push_back( alias->Clone() );
auto text = getAliasDisplayText( alias );
m_bus_list_view->InsertItem( idx, text );
m_bus_list_view->SetItemPtrData( idx, wxUIntPtr( m_aliases[idx].get() ) );
idx++;
}
m_bus_list_view->SetColumnWidth( 0, -1 );
return true;
}
void DIALOG_BUS_MANAGER::OnOkClick( wxCommandEvent& aEvent )
{
if( TransferDataFromWindow() )
{
( ( SCH_EDIT_FRAME* )GetParent() )->OnModify();
EndModal( wxID_OK );
}
}
void DIALOG_BUS_MANAGER::OnCancelClick( wxCommandEvent& aEvent )
{
EndModal( wxID_CANCEL );
}
bool DIALOG_BUS_MANAGER::TransferDataFromWindow()
{
// Since we have a clone of all the data, and it is from potentially
// multiple screens, the way this works is to rebuild each screen's aliases.
// A list of screens is stored here so that the screen's alias list is only
// cleared once.
std::unordered_set< SCH_SCREEN* > cleared_list;
for( auto alias : m_aliases )
{
auto screen = alias->GetParent();
if( cleared_list.count( screen ) == 0 )
{
screen->ClearBusAliases();
cleared_list.insert( screen );
}
screen->AddBusAlias( alias );
}
return true;
}
void DIALOG_BUS_MANAGER::OnSelectBus( wxListEvent& event )
{
if( event.GetEventType() == wxEVT_COMMAND_LIST_ITEM_SELECTED )
{
auto alias = m_aliases[ event.GetIndex() ];
if( m_active_alias != alias )
{
m_active_alias = alias;
m_bus_edit->ChangeValue( alias->GetName() );
m_btn_add_bus->Disable();
m_btn_rename_bus->Enable();
m_btn_remove_bus->Enable();
auto members = alias->Members();
// TODO(JE) Clear() seems to be clearing the hint, contrary to
// the wx documentation.
m_signal_edit->Clear();
m_signal_list_view->DeleteAllItems();
for( unsigned i = 0; i < members.size(); i++ )
{
m_signal_list_view->InsertItem( i, members[i] );
}
m_signal_list_view->SetColumnWidth( 0, -1 );
m_btn_add_signal->Enable();
m_btn_rename_signal->Disable();
m_btn_remove_signal->Disable();
}
}
else
{
m_active_alias = NULL;
m_bus_edit->Clear();
m_signal_edit->Clear();
m_signal_list_view->DeleteAllItems();
m_btn_add_bus->Enable();
m_btn_rename_bus->Disable();
m_btn_remove_bus->Disable();
m_btn_add_signal->Disable();
m_btn_rename_signal->Disable();
m_btn_remove_signal->Disable();
}
}
void DIALOG_BUS_MANAGER::OnSelectSignal( wxListEvent& event )
{
if( event.GetEventType() == wxEVT_COMMAND_LIST_ITEM_SELECTED )
{
m_signal_edit->ChangeValue( event.GetText() );
m_btn_rename_signal->Enable();
m_btn_remove_signal->Enable();
}
else
{
m_signal_edit->Clear();
m_btn_rename_signal->Disable();
m_btn_remove_signal->Disable();
}
}
void DIALOG_BUS_MANAGER::OnAddBus( wxCommandEvent& aEvent )
{
// If there is an active alias, then check that the user actually
// changed the text in the edit box (we can't have duplicate aliases)
auto new_name = m_bus_edit->GetValue();
if( new_name.Length() == 0 )
{
return;
}
for( auto alias : m_aliases )
{
if( alias->GetName() == new_name )
{
// TODO(JE) display error?
return;
}
}
if( !m_active_alias ||
( m_active_alias && m_active_alias->GetName().Cmp( new_name ) ) )
{
// The values are different; create a new alias
auto alias = std::make_shared<BUS_ALIAS>();
alias->SetName( new_name );
// New aliases get stored on the currently visible sheet
alias->SetParent( static_cast<SCH_EDIT_FRAME*>( GetParent() )->GetScreen() );
auto text = getAliasDisplayText( alias );
m_aliases.push_back( alias );
long idx = m_bus_list_view->InsertItem( m_aliases.size() - 1, text );
m_bus_list_view->SetColumnWidth( 0, -1 );
m_bus_list_view->Select( idx );
m_bus_edit->Clear();
}
else
{
// TODO(JE) Check about desired result here.
// Maybe warn the user? Or just do nothing
}
}
void DIALOG_BUS_MANAGER::OnRenameBus( wxCommandEvent& aEvent )
{
// We should only get here if there is an active alias
wxASSERT( m_active_alias );
m_active_alias->SetName( m_bus_edit->GetValue() );
long idx = m_bus_list_view->FindItem( -1, wxUIntPtr( m_active_alias.get() ) );
wxASSERT( idx >= 0 );
m_bus_list_view->SetItemText( idx, getAliasDisplayText( m_active_alias ) );
}
void DIALOG_BUS_MANAGER::OnRemoveBus( wxCommandEvent& aEvent )
{
// We should only get here if there is an active alias
wxASSERT( m_active_alias );
long i = m_bus_list_view->GetFirstSelected();
wxASSERT( m_active_alias == m_aliases[ i ] );
m_bus_list_view->DeleteItem( i );
m_aliases.erase( m_aliases.begin() + i );
m_bus_edit->Clear();
m_active_alias = NULL;
auto evt = wxListEvent( wxEVT_COMMAND_LIST_ITEM_DESELECTED );
OnSelectBus( evt );
}
void DIALOG_BUS_MANAGER::OnAddSignal( wxCommandEvent& aEvent )
{
auto name_list = m_signal_edit->GetValue();
if( !m_active_alias || name_list.Length() == 0 )
{
return;
}
// String collecting net names that were not added to the bus
wxString notAdded;
// Parse a space-separated list and add each one
wxStringTokenizer tok( name_list, " " );
while( tok.HasMoreTokens() )
{
auto name = tok.GetNextToken();
if( !m_active_alias->Contains( name ) )
{
m_active_alias->AddMember( name );
long idx = m_signal_list_view->InsertItem(
m_active_alias->GetMemberCount() - 1, name );
m_signal_list_view->SetColumnWidth( 0, -1 );
m_signal_list_view->Select( idx );
}
else
{
// Some of the requested net names were not added to the list, so keep them for editing
notAdded = notAdded.IsEmpty() ? name : notAdded + " " + name;
}
}
m_signal_edit->SetValue( notAdded );
m_signal_edit->SetInsertionPointEnd();
}
void DIALOG_BUS_MANAGER::OnRenameSignal( wxCommandEvent& aEvent )
{
// We should only get here if there is an active alias
wxASSERT( m_active_alias );
auto new_name = m_signal_edit->GetValue();
long idx = m_signal_list_view->GetFirstSelected();
wxASSERT( idx >= 0 );
auto old_name = m_active_alias->Members()[ idx ];
// User could have typed a space here, so check first
if( new_name.Find( " " ) != wxNOT_FOUND )
{
// TODO(JE) error feedback
m_signal_edit->ChangeValue( old_name );
return;
}
m_active_alias->Members()[ idx ] = new_name;
m_signal_list_view->SetItemText( idx, new_name );
m_signal_list_view->SetColumnWidth( 0, -1 );
}
void DIALOG_BUS_MANAGER::OnRemoveSignal( wxCommandEvent& aEvent )
{
// We should only get here if there is an active alias
wxASSERT( m_active_alias );
long idx = m_signal_list_view->GetFirstSelected();
wxASSERT( idx >= 0 );
m_active_alias->Members().erase( m_active_alias->Members().begin() + idx );
m_signal_list_view->DeleteItem( idx );
m_signal_edit->Clear();
m_btn_rename_signal->Disable();
m_btn_remove_signal->Disable();
}
wxString DIALOG_BUS_MANAGER::getAliasDisplayText( std::shared_ptr< BUS_ALIAS > aAlias )
{
wxString name = aAlias->GetName();
wxFileName sheet_name( aAlias->GetParent()->GetFileName() );
name += _T( " (" ) + sheet_name.GetFullName() + _T( ")" );
return name;
}
// see invoke_sch_dialog.h
void InvokeDialogBusManager( SCH_EDIT_FRAME* aCaller )
{
DIALOG_BUS_MANAGER dlg( aCaller );
dlg.ShowModal();
}

View File

@ -0,0 +1,90 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DIALOG_BUS_MANAGER_H_
#define _DIALOG_BUS_MANAGER_H_
#include "dialog_shim.h"
#include <sch_edit_frame.h>
#include <wx/listctrl.h>
#include <bus_alias.h>
class DIALOG_BUS_MANAGER : public DIALOG_SHIM
{
public:
DIALOG_BUS_MANAGER( SCH_EDIT_FRAME* aParent );
~DIALOG_BUS_MANAGER() {}
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
void OnAddBus( wxCommandEvent& aEvent );
void OnRenameBus( wxCommandEvent& aEvent );
void OnRemoveBus( wxCommandEvent& aEvent );
void OnAddSignal( wxCommandEvent& aEvent );
void OnRenameSignal( wxCommandEvent& aEvent );
void OnRemoveSignal( wxCommandEvent& aEvent );
protected:
void OnInitDialog( wxInitDialogEvent& aEvent );
void OnSelectBus( wxListEvent& event );
void OnSelectSignal( wxListEvent& event );
SCH_EDIT_FRAME* m_parent;
wxListView* m_bus_list_view;
wxListView* m_signal_list_view;
wxTextCtrl* m_bus_edit;
wxTextCtrl* m_signal_edit;
wxButton* m_btn_add_bus;
wxButton* m_btn_rename_bus;
wxButton* m_btn_remove_bus;
wxButton* m_btn_add_signal;
wxButton* m_btn_rename_signal;
wxButton* m_btn_remove_signal;
private:
virtual void OnOkClick( wxCommandEvent& aEvent );
virtual void OnCancelClick( wxCommandEvent& aEvent );
wxString getAliasDisplayText( std::shared_ptr< BUS_ALIAS > aAlias );
std::vector< std::shared_ptr< BUS_ALIAS > > m_aliases;
std::shared_ptr< BUS_ALIAS > m_active_alias;
DECLARE_EVENT_TABLE()
};
#endif
// _DIALOG_BUS_MANAGER_H_

View File

@ -29,10 +29,9 @@
*/
#include <fctsys.h>
#include <wx/valgen.h>
#include <wx/valnum.h>
#include <sch_edit_frame.h>
#include <base_units.h>
#include <validators.h>
#include <sch_draw_panel.h>
#include <general.h>
@ -87,6 +86,7 @@ private:
wxWindow* m_activeTextCtrl;
wxTextEntry* m_activeTextEntry;
UNIT_BINDER m_textSize;
REGEX_VALIDATOR m_netNameValidator;
};
@ -108,7 +108,9 @@ const int MAX_TEXTSIZE = INT_MAX;
DIALOG_LABEL_EDITOR::DIALOG_LABEL_EDITOR( SCH_EDIT_FRAME* aParent, SCH_TEXT* aTextItem ) :
DIALOG_LABEL_EDITOR_BASE( aParent ),
m_textSize( aParent, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits, false )
m_textSize( aParent, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits, false ),
// first part matches single nets and bus vector, the second part matches complex buses
m_netNameValidator( "([^/ ]+)|({[^/]+})" )
{
m_Parent = aParent;
m_CurrentText = aTextItem;
@ -151,8 +153,9 @@ DIALOG_LABEL_EDITOR::DIALOG_LABEL_EDITOR( SCH_EDIT_FRAME* aParent, SCH_TEXT* aTe
SetInitialFocus( m_activeTextCtrl );
// Enable validator for net names
if( m_CurrentText->Type() != SCH_TEXT_T )
( (wxTextValidator*) m_activeTextCtrl->GetValidator() )->SetCharExcludes( wxT( " /" ) );
m_activeTextCtrl->SetValidator( m_netNameValidator );
m_TextShape->Show( m_CurrentText->Type() == SCH_GLOBAL_LABEL_T ||
m_CurrentText->Type() == SCH_HIERARCHICAL_LABEL_T );

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Aug 4 2017)
// C++ code generated with wxFormBuilder (version Oct 17 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -31,8 +31,6 @@ DIALOG_LABEL_EDITOR_BASE::DIALOG_LABEL_EDITOR_BASE( wxWindow* parent, wxWindowID
m_valueSingleLine = new wxTextCtrl( this, wxID_VALUESINGLE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER|wxTE_RICH );
m_valueSingleLine->SetMinSize( wxSize( 360,-1 ) );
m_valueSingleLine->SetValidator( wxTextValidator( wxFILTER_EXCLUDE_CHAR_LIST, &m_labelText ) );
m_textEntrySizer->Add( m_valueSingleLine, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 3 );
m_labelMultiLine = new wxStaticText( this, wxID_ANY, _("Text:"), wxDefaultPosition, wxDefaultSize, 0 );

View File

@ -14,7 +14,6 @@
<property name="file">dialog_edit_label_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">dialog_edit_label_base</property>
<property name="namespace"></property>
@ -247,10 +246,10 @@
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type">wxString</property>
<property name="validator_style">wxFILTER_EXCLUDE_CHAR_LIST</property>
<property name="validator_type">wxTextValidator</property>
<property name="validator_variable">m_labelText</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
@ -606,8 +605,6 @@
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCombobox"></event>
<event name="OnComboboxCloseup"></event>
<event name="OnComboboxDropdown"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Aug 4 2017)
// C++ code generated with wxFormBuilder (version Oct 17 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
@ -21,8 +21,8 @@ class DIALOG_SHIM;
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/valtext.h>
#include <wx/combobox.h>
#include <wx/valtext.h>
#include <wx/sizer.h>
#include <wx/radiobox.h>
#include <wx/button.h>
@ -67,7 +67,6 @@ class DIALOG_LABEL_EDITOR_BASE : public DIALOG_SHIM
public:
wxString m_labelText;
wxString m_comboText;
DIALOG_LABEL_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Text Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );

View File

@ -48,6 +48,7 @@
#include <sch_sheet.h>
#include <lib_pin.h>
#include <sch_component.h>
#include <connection_graph.h>
#include <dialog_erc.h>
#include <erc.h>
@ -58,10 +59,7 @@ extern int DiagErc[PINTYPE_COUNT][PINTYPE_COUNT];
extern int DefaultDiagErc[PINTYPE_COUNT][PINTYPE_COUNT];
bool DIALOG_ERC::m_writeErcFile = false; // saved only for the current session
bool DIALOG_ERC::m_TestSimilarLabels = true; // Save in project config
bool DIALOG_ERC::m_diagErcTableInit = false; // saved only for the current session
bool DIALOG_ERC::m_tstUniqueGlobalLabels = true; // saved only for the current session
// Control identifiers for events
#define ID_MATRIX_0 1800
@ -102,8 +100,13 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
DIALOG_ERC::~DIALOG_ERC()
{
m_TestSimilarLabels = m_cbTestSimilarLabels->GetValue();
m_tstUniqueGlobalLabels = m_cbTestUniqueGlbLabels->GetValue();
transferControlsToSettings();
if( m_settings != m_parent->GetErcSettings() )
{
m_parent->UpdateErcSettings( m_settings );
m_parent->SaveProjectSettings( false );
}
}
@ -117,9 +120,8 @@ void DIALOG_ERC::Init()
m_buttonList[ii][jj] = NULL;
}
m_WriteResultOpt->SetValue( m_writeErcFile );
m_cbTestSimilarLabels->SetValue( m_TestSimilarLabels );
m_cbTestUniqueGlbLabels->SetValue( m_tstUniqueGlobalLabels );
m_settings = m_parent->GetErcSettings();
transferSettingsToControls();
SCH_SCREENS screens;
updateMarkerCounts( &screens );
@ -131,6 +133,30 @@ void DIALOG_ERC::Init()
}
void DIALOG_ERC::transferSettingsToControls()
{
m_WriteResultOpt->SetValue( m_settings.write_erc_file );
m_cbTestSimilarLabels->SetValue( m_settings.check_similar_labels );
m_cbTestUniqueGlbLabels->SetValue( m_settings.check_unique_global_labels );
m_cbCheckBusDriverConflicts->SetValue( m_settings.check_bus_driver_conflicts );
m_cbCheckBusEntries->SetValue( m_settings.check_bus_entry_conflicts );
m_cbCheckBusToBusConflicts->SetValue( m_settings.check_bus_to_bus_conflicts );
m_cbCheckBusToNetConflicts->SetValue( m_settings.check_bus_to_net_conflicts );
}
void DIALOG_ERC::transferControlsToSettings()
{
m_settings.write_erc_file = m_WriteResultOpt->GetValue();
m_settings.check_similar_labels = m_cbTestSimilarLabels->GetValue();
m_settings.check_unique_global_labels = m_cbTestUniqueGlbLabels->GetValue();
m_settings.check_bus_driver_conflicts = m_cbCheckBusDriverConflicts->GetValue();
m_settings.check_bus_entry_conflicts = m_cbCheckBusEntries->GetValue();
m_settings.check_bus_to_bus_conflicts = m_cbCheckBusToBusConflicts->GetValue();
m_settings.check_bus_to_net_conflicts = m_cbCheckBusToNetConflicts->GetValue();
}
void DIALOG_ERC::updateMarkerCounts( SCH_SCREENS *screens )
{
int markers = screens->GetMarkerCount( MARKER_BASE::MARKER_ERC,
@ -436,10 +462,8 @@ void DIALOG_ERC::ResetDefaultERCDiag( wxCommandEvent& event )
{
memcpy( DiagErc, DefaultDiagErc, sizeof( DiagErc ) );
ReBuildMatrixPanel();
m_TestSimilarLabels = true;
m_cbTestSimilarLabels->SetValue( m_TestSimilarLabels );
m_tstUniqueGlobalLabels = true;
m_cbTestUniqueGlbLabels->SetValue( m_tstUniqueGlobalLabels );
m_settings.LoadDefaults();
transferSettingsToControls();
}
@ -483,9 +507,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
{
wxFileName fn;
m_writeErcFile = m_WriteResultOpt->GetValue();
m_TestSimilarLabels = m_cbTestSimilarLabels->GetValue();
m_tstUniqueGlobalLabels = m_cbTestUniqueGlbLabels->GetValue();
transferControlsToSettings();
// Build the whole sheet list in hierarchy (sheet, not screen)
SCH_SHEET_LIST sheets( g_RootSheet );
@ -509,6 +531,12 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
*/
TestDuplicateSheetNames( true );
TestConflictingBusAliases();
// The connection graph has a whole set of ERC checks it can run
m_parent->RecalculateConnections();
g_ConnectionGraph->RunERC( m_settings );
/* Test is all units of each multiunit component have the same footprint assigned.
*/
TestMultiunitFootprints( sheets );
@ -518,9 +546,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
// Reset the connection type indicator
objectsConnectedList->ResetConnectionsType();
unsigned lastItemIdx;
unsigned nextItemIdx = lastItemIdx = 0;
int MinConn = NOC;
unsigned lastItemIdx = 0;
/* Check that a pin appears in only one net. This check is necessary
* because multi-unit components that have shared pins can be wired to
@ -547,13 +573,6 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
wxASSERT_MSG( lastNet <= net, wxT( "Netlist not correctly ordered" ) );
if( lastNet != net )
{
// New net found:
MinConn = NOC;
nextItemIdx = itemIdx;
}
switch( item->m_Type )
{
// These items do not create erc problems
@ -567,30 +586,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
case NET_GLOBBUSLABELMEMBER:
break;
case NET_HIERLABEL:
case NET_HIERBUSLABELMEMBER:
case NET_SHEETLABEL:
case NET_SHEETBUSLABELMEMBER:
// ERC problems when pin sheets do not match hierarchical labels.
// Each pin sheet must match a hierarchical label
// Each hierarchical label must match a pin sheet
objectsConnectedList->TestforNonOrphanLabel( itemIdx, nextItemIdx );
break;
case NET_GLOBLABEL:
if( m_tstUniqueGlobalLabels )
objectsConnectedList->TestforNonOrphanLabel( itemIdx, nextItemIdx );
break;
case NET_NOCONNECT:
// ERC problems when a noconnect symbol is connected to more than one pin.
MinConn = NET_NC;
if( objectsConnectedList->CountPinsInNet( nextItemIdx ) > 1 )
Diagnose( item, NULL, MinConn, UNC );
break;
// TODO(JE) Port this to the new system
case NET_PIN:
{
// Check if this pin has appeared before on a different net
@ -619,10 +615,13 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
}
}
// TODO(JE) Remove this if new system is finished
// Look for ERC problems between pins:
TestOthersItems( objectsConnectedList.get(), itemIdx, nextItemIdx, &MinConn );
//TestOthersItems( objectsConnectedList.get(), itemIdx, nextItemIdx, &MinConn );
break;
}
default:
break;
}
lastItemIdx = itemIdx;
@ -630,7 +629,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
// Test similar labels (i;e. labels which are identical when
// using case insensitive comparisons)
if( m_TestSimilarLabels )
if( m_settings.check_similar_labels )
objectsConnectedList->TestforSimilarLabels();
// Displays global results:
@ -653,7 +652,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
// Display message
aReporter.ReportTail( _( "Finished" ), REPORTER::RPT_INFO );
if( m_writeErcFile )
if( m_settings.write_erc_file )
{
fn = g_RootSheet->GetScreen()->GetFileName();
fn.SetExt( wxT( "erc" ) );

View File

@ -30,6 +30,7 @@
#include <lib_pin.h> // For PINTYPE_COUNT definition
#include <dialog_erc_base.h>
#include <erc_settings.h>
#include "dialog_erc_listbox.h"
// DIALOG_ERC class declaration
@ -43,12 +44,8 @@ private:
wxBitmapButton* m_buttonList[PINTYPE_COUNT][PINTYPE_COUNT];
bool m_initialized;
const SCH_MARKER* m_lastMarkerFound;
static bool m_writeErcFile;
static bool m_diagErcTableInit; // go to true after DiagErc init
static bool m_tstUniqueGlobalLabels;
public:
static bool m_TestSimilarLabels;
ERC_SETTINGS m_settings;
public:
DIALOG_ERC( SCH_EDIT_FRAME* parent );
@ -79,6 +76,8 @@ private:
void ReBuildMatrixPanel();
void setDRCMatrixButtonState( wxBitmapButton *aButton, int aState );
void updateMarkerCounts( SCH_SCREENS *screens );
void transferSettingsToControls();
void transferControlsToSettings();
};

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jan 17 2019)
// C++ code generated with wxFormBuilder (version Feb 17 2019)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -131,6 +131,24 @@ DIALOG_ERC_BASE::DIALOG_ERC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
m_panelMatrixSizer->Add( sbSizer3, 0, wxALL|wxEXPAND, 5 );
wxStaticBoxSizer* sbSizer31;
sbSizer31 = new wxStaticBoxSizer( new wxStaticBox( m_PanelERCOptions, wxID_ANY, _("Bus Connections") ), wxVERTICAL );
m_cbCheckBusToNetConflicts = new wxCheckBox( sbSizer31->GetStaticBox(), wxID_ANY, _("Check that bus wires are not connected to hierarchical net pins and vice versa"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer31->Add( m_cbCheckBusToNetConflicts, 0, wxALL, 5 );
m_cbCheckBusToBusConflicts = new wxCheckBox( sbSizer31->GetStaticBox(), wxID_ANY, _("Check that bus-to-bus connections have shared members"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer31->Add( m_cbCheckBusToBusConflicts, 0, wxALL, 5 );
m_cbCheckBusEntries = new wxCheckBox( sbSizer31->GetStaticBox(), wxID_ANY, _("Check that nets are members of buses they graphically connect to"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer31->Add( m_cbCheckBusEntries, 0, wxALL, 5 );
m_cbCheckBusDriverConflicts = new wxCheckBox( sbSizer31->GetStaticBox(), wxID_ANY, _("Check buses for conflicting drivers"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer31->Add( m_cbCheckBusDriverConflicts, 0, wxALL, 5 );
m_panelMatrixSizer->Add( sbSizer31, 0, wxALL|wxEXPAND, 5 );
m_PanelERCOptions->SetSizer( m_panelMatrixSizer );
m_PanelERCOptions->Layout();

View File

@ -1318,6 +1318,373 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">Bus Connections</property>
<property name="minimum_size"></property>
<property name="name">sbSizer31</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<event name="OnUpdateUI"></event>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Check that bus wires are not connected to hierarchical net pins and vice versa</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbCheckBusToNetConflicts</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Check that bus-to-bus connections have shared members</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbCheckBusToBusConflicts</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Check that nets are members of buses they graphically connect to</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbCheckBusEntries</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Check buses for conflicting drivers</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbCheckBusDriverConflicts</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jan 17 2019)
// C++ code generated with wxFormBuilder (version Feb 17 2019)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -65,6 +65,10 @@ class DIALOG_ERC_BASE : public DIALOG_SHIM
wxCheckBox* m_cbTestUniqueGlbLabels;
wxPanel* m_matrixPanel;
wxButton* m_ResetOptButton;
wxCheckBox* m_cbCheckBusToNetConflicts;
wxCheckBox* m_cbCheckBusToBusConflicts;
wxCheckBox* m_cbCheckBusEntries;
wxCheckBox* m_cbCheckBusDriverConflicts;
wxButton* m_buttondelmarkers;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;

View File

@ -0,0 +1,229 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <sch_connection.h>
#include <connection_graph.h>
#include <dialog_migrate_buses.h>
/**
* Migrates buses using legacy multi-label joining behavior.
*
* In KiCad verions before 6.0, you were allowed to place multiple labels
* on a given bus subgraph, and that would have the effect of making those
* bus descriptions equivalent according to the bus vector number.
*
* For example, if the labels PCA[0..15], ADR[0.7], and BUS[5..10] are all
* attached to the same subgraph, the intention is that there is connectivity
* between PCA0 and ADR0, between PCA10 and BUS10, and between PCA5, ADR5,
* and BUS5 (basically connect all the prefix names where the vector numbers
* line up).
*
* This is no longer allowed, because it doesn't map well onto the new
* bus groups feature and because it is confusing (the netlist will take on
* one of the possible names and it's impossible to control which one is
* used).
*
* This dialog identifies all of the subgraphs that have this behavior,
* and corrects them by determining a new name for the subgraph and removing
* all but one label. The name is determined by choosing a prefix and bus
* vector notation that can capture all the attached buses. In the above
* example, the result would need to have the vector notation [0..15] to
* capture all of the attached buses, and the name could be any of PCA, ADR,
* or BUS. We present a dialog to the user for them to select which name
* they want to use.
*/
DIALOG_MIGRATE_BUSES::DIALOG_MIGRATE_BUSES( SCH_EDIT_FRAME* aParent ) :
DIALOG_MIGRATE_BUSES_BASE( aParent ),
m_frame( aParent )
{
m_migration_list->Bind( wxEVT_LIST_ITEM_SELECTED,
&DIALOG_MIGRATE_BUSES::onItemSelected, this );
m_btn_accept->Bind( wxEVT_COMMAND_BUTTON_CLICKED,
&DIALOG_MIGRATE_BUSES::onAcceptClicked, this );
loadGraphData();
updateUi();
m_frame->Zoom_Automatique( false );
}
void DIALOG_MIGRATE_BUSES::loadGraphData()
{
m_items.clear();
auto subgraphs = g_ConnectionGraph->GetBusesNeedingMigration();
for( auto subgraph : subgraphs )
{
BUS_MIGRATION_STATUS status;
status.subgraph = subgraph;
status.approved = false;
auto labels = subgraph->GetBusLabels();
wxASSERT( labels.size() > 1 );
for( auto label : labels )
status.labels.push_back( static_cast<SCH_TEXT*>( label )->GetText() );
status.possible_labels = getProposedLabels( status.labels );
m_items.push_back( status );
}
}
void DIALOG_MIGRATE_BUSES::updateUi()
{
m_migration_list->DeleteAllItems();
m_migration_list->InsertColumn( 0, _( "Sheet" ) );
m_migration_list->InsertColumn( 1, _( "Conflicting Labels" ) );
m_migration_list->InsertColumn( 2, _( "New Label" ) );
m_migration_list->InsertColumn( 3, _( "Status" ) );
for( auto item : m_items )
{
wxString old = item.labels[0];
for( unsigned j = 1; j < item.labels.size(); j++ )
old << ", " << item.labels[j];
auto i = m_migration_list->InsertItem( m_migration_list->GetItemCount(),
wxEmptyString );
m_migration_list->SetItem( i, 0, item.subgraph->m_sheet.PathHumanReadable() );
m_migration_list->SetItem( i, 1, old );
m_migration_list->SetItem( i, 2, item.possible_labels[0] );
m_migration_list->SetItem( i, 3, "" );
}
m_migration_list->Select( 0 );
m_migration_list->SetColumnWidth( 1, -1 );
}
std::vector<wxString> DIALOG_MIGRATE_BUSES::getProposedLabels( std::vector<wxString> aLabelList )
{
int lowest_start = INT_MAX;
int highest_end = -1;
int widest_bus = -1;
for( auto label : aLabelList )
{
SCH_CONNECTION conn;
conn.ConfigureFromLabel( label );
int start = conn.VectorStart();
int end = conn.VectorEnd();
if( start < lowest_start )
lowest_start = start;
if( end > highest_end )
highest_end = end;
if( end - start + 1 > widest_bus )
widest_bus = end - start + 1;
}
SCH_CONNECTION conn;
std::vector<wxString> proposals;
for( auto label : aLabelList )
{
conn.ConfigureFromLabel( label );
wxString proposal = conn.VectorPrefix();
proposal << "[" << highest_end << ".." << lowest_start << "]";
proposals.push_back( proposal );
}
return proposals;
}
void DIALOG_MIGRATE_BUSES::onItemSelected( wxListEvent& aEvent )
{
unsigned sel = aEvent.GetIndex();
wxASSERT( sel < m_items.size() );
m_selected_index = sel;
auto subgraph = m_items[sel].subgraph;
auto sheet = subgraph->m_sheet;
auto driver = subgraph->m_driver;
if( sheet != *g_CurrentSheet )
{
sheet.LastScreen()->SetZoom( m_frame->GetScreen()->GetZoom() );
*g_CurrentSheet = sheet;
g_CurrentSheet->UpdateAllScreenReferences();
sheet.LastScreen()->TestDanglingEnds();
}
auto pos = driver->GetPosition();
m_frame->SetCrossHairPosition( pos );
m_frame->RedrawScreen( pos, false );
m_cb_new_name->Clear();
for( auto option : m_items[sel].possible_labels )
m_cb_new_name->Append( option );
m_cb_new_name->Select( 0 );
}
void DIALOG_MIGRATE_BUSES::onAcceptClicked( wxCommandEvent& aEvent )
{
wxASSERT( m_selected_index < m_items.size() );
auto sel = m_selected_index;
m_items[sel].approved_label = m_cb_new_name->GetStringSelection();
m_items[sel].approved = true;
auto sheet = m_items[sel].subgraph->m_sheet;
auto screen = sheet.LastScreen();
auto labels = m_items[sel].subgraph->GetBusLabels();
static_cast<SCH_TEXT*>( labels[0] )->SetText( m_items[sel].approved_label );
labels.erase( labels.begin() );
for( auto label : labels )
{
label->SetFlags( STRUCT_DELETED );
screen->Remove( label );
}
m_migration_list->SetItem( sel, 2, m_items[sel].approved_label );
m_migration_list->SetItem( sel, 3, _( "Updated" ) );
if( sel < m_items.size() - 1 )
{
m_migration_list->Select( sel + 1 );
}
}

View File

@ -0,0 +1,71 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DIALOG_MIGRATE_BUSES_H
#define _DIALOG_MIGRATE_BUSES_H
#include <vector>
#include <sch_edit_frame.h>
#include <dialog_migrate_buses_base.h>
class CONNECTION_SUBGRAPH;
struct BUS_MIGRATION_STATUS
{
CONNECTION_SUBGRAPH* subgraph;
std::vector<wxString> labels;
std::vector<wxString> possible_labels;
wxString approved_label;
bool approved;
};
class DIALOG_MIGRATE_BUSES : public DIALOG_MIGRATE_BUSES_BASE
{
public:
DIALOG_MIGRATE_BUSES( SCH_EDIT_FRAME* aParent );
private:
SCH_EDIT_FRAME* m_frame;
unsigned m_selected_index;
void loadGraphData();
void updateUi();
std::vector<wxString> getProposedLabels( std::vector<wxString> aLabelList );
void onItemSelected( wxListEvent& aEvent );
void onAcceptClicked( wxCommandEvent& aEvent );
std::vector<BUS_MIGRATION_STATUS> m_items;
};
#endif

View File

@ -0,0 +1,70 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 17 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_migrate_buses_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_MIGRATE_BUSES_BASE::DIALOG_MIGRATE_BUSES_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* main_sizer;
main_sizer = new wxBoxSizer( wxVERTICAL );
m_staticText5 = new wxStaticText( this, wxID_ANY, _("This schematic has one or more buses with more than one label. This was allowed in previous KiCad versions but is no longer permitted."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText5->Wrap( 480 );
main_sizer->Add( m_staticText5, 0, wxALL|wxEXPAND, 5 );
m_staticText7 = new wxStaticText( this, wxID_ANY, _("Please select a new name for each of the buses below.\nA name has been suggested for you based on the labels attached to the bus."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText7->Wrap( 480 );
m_staticText7->SetMinSize( wxSize( -1,60 ) );
main_sizer->Add( m_staticText7, 0, wxALL|wxEXPAND, 5 );
m_migration_list = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES );
m_migration_list->SetMinSize( wxSize( 460,100 ) );
main_sizer->Add( m_migration_list, 1, wxALL|wxEXPAND, 5 );
m_staticText6 = new wxStaticText( this, wxID_ANY, _("Proposed new name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText6->Wrap( -1 );
main_sizer->Add( m_staticText6, 0, wxALL, 5 );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxHORIZONTAL );
m_cb_new_name = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
m_cb_new_name->SetMinSize( wxSize( 300,-1 ) );
m_cb_new_name->SetMaxSize( wxSize( 460,-1 ) );
bSizer7->Add( m_cb_new_name, 1, wxALL|wxEXPAND, 5 );
m_btn_accept = new wxButton( this, wxID_ANY, _("Accept Name"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer7->Add( m_btn_accept, 0, wxALL, 5 );
main_sizer->Add( bSizer7, 0, wxEXPAND, 5 );
m_sdbSizer1 = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK );
m_sdbSizer1->AddButton( m_sdbSizer1OK );
m_sdbSizer1->Realize();
main_sizer->Add( m_sdbSizer1, 0, wxEXPAND, 5 );
this->SetSizer( main_sizer );
this->Layout();
main_sizer->Fit( this );
this->Centre( wxBOTH );
}
DIALOG_MIGRATE_BUSES_BASE::~DIALOG_MIGRATE_BUSES_BASE()
{
}

View File

@ -0,0 +1,669 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="13" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">dialog_migrate_buses_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="internationalize">1</property>
<property name="name">DIALOG_MIGRATE_BUSES_BASE</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">DIALOG_MIGRATE_BUSES_BASE</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style">wxDEFAULT_DIALOG_STYLE</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title">Migrate Buses</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnActivate"></event>
<event name="OnActivateApp"></event>
<event name="OnAuiFindManager"></event>
<event name="OnAuiPaneButton"></event>
<event name="OnAuiPaneClose"></event>
<event name="OnAuiPaneMaximize"></event>
<event name="OnAuiPaneRestore"></event>
<event name="OnAuiRender"></event>
<event name="OnChar"></event>
<event name="OnClose"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnHibernate"></event>
<event name="OnIconize"></event>
<event name="OnIdle"></event>
<event name="OnInitDialog"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">main_sizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">This schematic has one or more buses with more than one label. This was allowed in previous KiCad versions but is no longer permitted.</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticText5</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">480</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Please select a new name for each of the buses below.&#x0A;A name has been suggested for you based on the labels attached to the bus.</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,60</property>
<property name="moveable">1</property>
<property name="name">m_staticText7</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">480</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxListCtrl" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">460,100</property>
<property name="moveable">1</property>
<property name="name">m_migration_list</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES</property>
<property name="subclass">wxListView; </property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnListBeginDrag"></event>
<event name="OnListBeginLabelEdit"></event>
<event name="OnListBeginRDrag"></event>
<event name="OnListCacheHint"></event>
<event name="OnListColBeginDrag"></event>
<event name="OnListColClick"></event>
<event name="OnListColDragging"></event>
<event name="OnListColEndDrag"></event>
<event name="OnListColRightClick"></event>
<event name="OnListDeleteAllItems"></event>
<event name="OnListDeleteItem"></event>
<event name="OnListEndLabelEdit"></event>
<event name="OnListInsertItem"></event>
<event name="OnListItemActivated"></event>
<event name="OnListItemDeselected"></event>
<event name="OnListItemFocused"></event>
<event name="OnListItemMiddleClick"></event>
<event name="OnListItemRightClick"></event>
<event name="OnListItemSelected"></event>
<event name="OnListKeyDown"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Proposed new name:</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticText6</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer7</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxComboBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices"></property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size">460,-1</property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">300,-1</property>
<property name="moveable">1</property>
<property name="name">m_cb_new_name</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCombobox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnText"></event>
<event name="OnTextEnter"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Accept Name</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_btn_accept</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick"></event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">0</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_sdbSizer1</property>
<property name="permission">protected</property>
<event name="OnApplyButtonClick"></event>
<event name="OnCancelButtonClick"></event>
<event name="OnContextHelpButtonClick"></event>
<event name="OnHelpButtonClick"></event>
<event name="OnNoButtonClick"></event>
<event name="OnOKButtonClick"></event>
<event name="OnSaveButtonClick"></event>
<event name="OnYesButtonClick"></event>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 17 2016)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_MIGRATE_BUSES_BASE_H__
#define __DIALOG_MIGRATE_BUSES_BASE_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class DIALOG_SHIM;
class wxListView;
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/listctrl.h>
#include <wx/combobox.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_MIGRATE_BUSES_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_MIGRATE_BUSES_BASE : public DIALOG_SHIM
{
private:
protected:
wxStaticText* m_staticText5;
wxStaticText* m_staticText7;
wxListView* m_migration_list;
wxStaticText* m_staticText6;
wxComboBox* m_cb_new_name;
wxButton* m_btn_accept;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
public:
DIALOG_MIGRATE_BUSES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Migrate Buses"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
~DIALOG_MIGRATE_BUSES_BASE();
};
#endif //__DIALOG_MIGRATE_BUSES_BASE_H__

View File

@ -23,6 +23,7 @@
*/
#include <sch_edit_frame.h>
#include <sch_sheet.h>
#include <dialog_sch_edit_sheet_pin.h>

View File

@ -33,6 +33,7 @@
#include <widgets/tab_traversal.h>
#include <sch_edit_frame.h>
#include <sch_sheet.h>
DIALOG_SCH_SHEET_PROPS::DIALOG_SCH_SHEET_PROPS( SCH_EDIT_FRAME* parent, SCH_SHEET* aSheet ) :

View File

@ -52,8 +52,8 @@ wxString DRC_ITEM::GetErrorText() const
return wxString( _("Mismatch between hierarchical labels and pins sheets"));
case ERCE_NOCONNECT_CONNECTED:
return wxString( _("A pin with a \"no connection\" flag is connected"));
case ERCE_GLOBLABEL:
return wxString( _("Global label not connected to any other global label") );
case ERCE_LABEL_NOT_CONNECTED:
return wxString( _("A label not connected to any other item") );
case ERCE_SIMILAR_LABELS:
return wxString( _("Labels are similar (lower/upper case difference only)") );
case ERCE_SIMILAR_GLBL_LABELS:
@ -62,7 +62,18 @@ wxString DRC_ITEM::GetErrorText() const
return wxString( _("Different footprint assigned in another unit of the same component") );
case ERCE_DIFFERENT_UNIT_NET:
return wxString( _("Different net assigned to a shared pin in another unit of the same component" ) );
case ERCE_BUS_ALIAS_CONFLICT:
return wxString( _("Conflict between bus alias definitions across schematic sheets") );
case ERCE_DRIVER_CONFLICT:
return wxString( _( "More than one name given to this bus or net" ) );
case ERCE_BUS_ENTRY_CONFLICT:
return wxString( _( "Net is graphically connected to a bus but not a bus member" ) );
case ERCE_BUS_LABEL_ERROR:
return wxString( _( "Label attached to bus item does not describe a bus" ) );
case ERCE_BUS_TO_BUS_CONFLICT:
return wxString( _( "No nets are shared between two bus items" ) );
case ERCE_BUS_TO_NET_CONFLICT:
return wxString( _( "Invalid connection between bus and net items" ) );
default:
wxFAIL_MSG( "Missing ERC error description" );
return wxString( wxT("Unknown.") );

View File

@ -77,7 +77,7 @@ void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField )
return;
}
dlg.UpdateField( aField, m_CurrentSheet );
dlg.UpdateField( aField, g_CurrentSheet );
m_canvas->MoveCursorToCrossHair();
m_canvas->SetIgnoreMouseEvents( false );
@ -88,7 +88,6 @@ void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField )
OnModify();
MSG_PANEL_ITEMS items;
component->SetCurrentSheetPath( &GetCurrentSheet() );
component->GetMsgPanelInfo( m_UserUnits, items );
SetMsgPanel( items );
}

View File

@ -32,6 +32,7 @@
#include <confirm.h>
#include <gestfich.h>
#include <sch_edit_frame.h>
#include <sch_sheet.h>
#include <invoke_sch_dialog.h>
#include <lib_edit_frame.h>
#include <eeschema_config.h>
@ -249,8 +250,26 @@ PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetProjectFileParametersList()
&s_defaultTextSize,
DEFAULT_SIZE_TEXT, 5, 1000 ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_WriteFile" ),
&m_ercSettings.write_erc_file, false ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_TestSimilarLabels" ),
&DIALOG_ERC::m_TestSimilarLabels, true ) );
&m_ercSettings.check_similar_labels, true ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_CheckUniqueGlobalLabels" ),
&m_ercSettings.check_unique_global_labels, true ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_CheckBusDriverConflicts" ),
&m_ercSettings.check_bus_driver_conflicts, true ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_CheckBusEntryConflicts" ),
&m_ercSettings.check_bus_entry_conflicts, true ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_CheckBusToBusConflicts" ),
&m_ercSettings.check_bus_to_bus_conflicts, true ) );
m_projectFileParams.push_back( new PARAM_CFG_BOOL( wxT( "ERC_CheckBusToNetConflicts" ),
&m_ercSettings.check_bus_to_net_conflicts, true ) );
return m_projectFileParams;
}

View File

@ -66,6 +66,7 @@ enum id_eeschema_frm
/* Schematic editor main menubar IDs. */
ID_RESCUE_CACHED,
ID_EDIT_SYM_LIB_TABLE,
ID_BUS_MANAGER,
ID_REMAP_SYMBOLS,
ID_EDIT_COMPONENTS_TO_SYMBOLS_LIB_ID,
ID_GRID_SETTINGS,
@ -166,6 +167,10 @@ enum id_eeschema_frm
ID_POPUP_SCH_GETINFO_MARKER,
ID_POPUP_END_RANGE,
// Dynamically bound in AddMenusForBus()
ID_POPUP_SCH_UNFOLD_BUS,
ID_POPUP_SCH_UNFOLD_BUS_END = ID_POPUP_SCH_UNFOLD_BUS + 64,
ID_POPUP_SCH_DISPLAYDOC_CMP,
ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP,
@ -200,6 +205,7 @@ enum id_eeschema_frm
ID_SCH_EDIT_COMPONENT_FOOTPRINT,
ID_SCH_MOVE_ITEM,
ID_SCH_DRAG_ITEM,
ID_SCH_UNFOLD_BUS,
ID_AUTOPLACE_FIELDS,

View File

@ -225,6 +225,73 @@ int TestDuplicateSheetNames( bool aCreateMarker )
}
int TestConflictingBusAliases( bool aCreateMarker )
{
using std::pair;
using std::shared_ptr;
using std::vector;
int err_count = 0;
SCH_SCREENS screens;
vector< shared_ptr<BUS_ALIAS> > aliases;
vector< pair< shared_ptr<BUS_ALIAS>, shared_ptr<BUS_ALIAS> > > conflicts;
for( auto screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
{
auto screen_aliases = screen->GetBusAliases();
for( auto alias : screen_aliases )
{
for( auto test : aliases )
{
if( alias->GetName() == test->GetName() &&
alias->Members() != test->Members() )
{
conflicts.push_back( std::make_pair( alias, test ) );
}
}
}
aliases.insert( aliases.end(),
screen_aliases.begin(), screen_aliases.end() );
}
if( !conflicts.empty() )
{
if( aCreateMarker )
{
wxString msg;
for( auto conflict : conflicts )
{
auto marker = new SCH_MARKER();
auto a1 = conflict.first;
auto a2 = conflict.second;
msg.Printf( _( "Bus alias %s has conflicting definitions on multiple sheets: " ),
GetChars( a1->GetName() ) );
wxFileName f1 = a1->GetParent()->GetFileName();
wxFileName f2 = a2->GetParent()->GetFileName();
msg << f1.GetFullName() << " and " << f2.GetFullName();
marker->SetData( ERCE_BUS_ALIAS_CONFLICT, wxPoint( 0, 0 ),
msg, wxPoint( 0, 0 ) );
marker->SetMarkerType( MARKER_BASE::MARKER_ERC );
marker->SetErrorLevel( MARKER_BASE::MARKER_SEVERITY_ERROR );
a2->GetParent()->Append( marker );
++err_count;
}
}
}
return err_count;
}
int TestMultiunitFootprints( SCH_SHEET_LIST& aSheetList )
{
int errors = 0;
@ -314,6 +381,7 @@ void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst,
if( aMinConn < 0 )
{
#if 0
if( aNetItemRef->m_Type == NET_HIERLABEL || aNetItemRef->m_Type == NET_HIERBUSLABELMEMBER )
{
msg.Printf( _( "Hierarchical label %s is not connected to a sheet label." ),
@ -341,7 +409,7 @@ void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst,
msg,
aNetItemRef->m_Start );
}
#endif
return;
}

View File

@ -49,21 +49,28 @@ extern const wxString CommentERC_H[];
extern const wxString CommentERC_V[];
/// DRC error codes:
#define ERCE_UNSPECIFIED 0
#define ERCE_DUPLICATE_SHEET_NAME 1 // duplicate sheet names within a given sheet
#define ERCE_PIN_NOT_CONNECTED 2 // pin not connected and not no connect symbol
#define ERCE_PIN_NOT_DRIVEN 3 // pin connected to some others pins but no pin to drive it
#define ERCE_PIN_TO_PIN_WARNING 4 // pin connected to another pin: warning level
#define ERCE_PIN_TO_PIN_ERROR 5 // pin connected to another pin: error level
#define ERCE_HIERACHICAL_LABEL 6 // mismatch between hierarchical labels and pins sheets
#define ERCE_NOCONNECT_CONNECTED 7 // a no connect symbol is connected to more than 1 pin
#define ERCE_GLOBLABEL 8 // global label not connected to any other global label
#define ERCE_SIMILAR_LABELS 9 // 2 labels are equal fir case insensitive comparisons
#define ERCE_SIMILAR_GLBL_LABELS 10 // 2 labels are equal fir case insensitive comparisons
#define ERCE_DIFFERENT_UNIT_FP 11 // different units of the same component have different
// footprints assigned
#define ERCE_DIFFERENT_UNIT_NET 12 // a shared pin in a multi-unit component is connected
// to more than one net
enum ERCE_T
{
ERCE_UNSPECIFIED = 0,
ERCE_DUPLICATE_SHEET_NAME, // duplicate sheet names within a given sheet
ERCE_PIN_NOT_CONNECTED, // pin not connected and not no connect symbol
ERCE_PIN_NOT_DRIVEN, // pin connected to some others pins but no pin to drive it
ERCE_PIN_TO_PIN_WARNING, // pin connected to an other pin: warning level
ERCE_PIN_TO_PIN_ERROR, // pin connected to an other pin: error level
ERCE_HIERACHICAL_LABEL, // mismatch between hierarchical labels and pins sheets
ERCE_NOCONNECT_CONNECTED, // a no connect symbol is connected to more than 1 pin
ERCE_LABEL_NOT_CONNECTED, // label not connected to anything
ERCE_SIMILAR_LABELS, // 2 labels are equal fir case insensitive comparisons
ERCE_SIMILAR_GLBL_LABELS, // 2 labels are equal fir case insensitive comparisons
ERCE_DIFFERENT_UNIT_FP, // different units of the same component have different footprints assigned
ERCE_DIFFERENT_UNIT_NET, // a shared pin in a multi-unit component is connected to more than one net
ERCE_BUS_ALIAS_CONFLICT, // conflicting bus alias definitions across sheets
ERCE_DRIVER_CONFLICT, // conflicting drivers (labels, etc) on a subgraph
ERCE_BUS_ENTRY_CONFLICT, // a wire connected to a bus doesn't match the bus
ERCE_BUS_LABEL_ERROR, // a label attached to a bus isn't in bus format
ERCE_BUS_TO_BUS_CONFLICT, // a connection between bus objects doesn't share at least one net
ERCE_BUS_TO_NET_CONFLICT, // a bus wire is graphically connected to a net port/pin (or vice versa)
};
/* Minimal connection table */
#define NPI 4 // Net with Pin isolated, this pin has type Not Connected and must be left N.C.
@ -112,6 +119,18 @@ void TestOthersItems( NETLIST_OBJECT_LIST* aList,
*/
int TestDuplicateSheetNames( bool aCreateMarker );
/**
* Checks that there are not conflicting bus alias definitions in the schematic
*
* (for example, two hierarchical sub-sheets contain different definitions for
* the same bus alias)
*
* @param aCreateMarker: true = create error markers in schematic,
* false = calculate error count only
* @return the error count
*/
int TestConflictingBusAliases( bool aCreateMarker = true );
/**
* Test if all units of each multiunit component have the same footprint assigned.
* @param aSheetList contains components to be validated.

82
eeschema/erc_settings.h Normal file
View File

@ -0,0 +1,82 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _ERC_SETTINGS_H
#define _ERC_SETTINGS_H
/**
* Container for ERC settings
*
* Currently only stores flags about checks to run, but could later be expanded
* to contain the matrix of electrical pin types.
*/
class ERC_SETTINGS
{
public:
void LoadDefaults()
{
write_erc_file = false;
check_similar_labels = true;
check_unique_global_labels = true;
check_bus_driver_conflicts = true;
check_bus_entry_conflicts = true;
check_bus_to_bus_conflicts = true;
check_bus_to_net_conflicts = true;
}
bool operator==( const ERC_SETTINGS& other ) const
{
return ( other.write_erc_file == write_erc_file &&
other.check_similar_labels == check_similar_labels &&
other.check_unique_global_labels == check_unique_global_labels &&
other.check_bus_driver_conflicts == check_bus_driver_conflicts &&
other.check_bus_entry_conflicts == check_bus_entry_conflicts &&
other.check_bus_to_bus_conflicts == check_bus_to_bus_conflicts &&
other.check_bus_to_net_conflicts == check_bus_to_net_conflicts );
}
bool operator!=( const ERC_SETTINGS& other ) const
{
return !( other == *this );
}
/// If true, write ERC results to a file
bool write_erc_file;
/// If true, check each sheet for labels that differ only by letter case
bool check_similar_labels;
/// If true, check to ensure that each global label apperas more than once
bool check_unique_global_labels;
/// If true, check that buses don't have conflicting drivers
bool check_bus_driver_conflicts;
/// If true, check that wires connecting to buses actually exist in the bus
bool check_bus_entry_conflicts;
/// If true, check that bus-to-bus connections share at least one member
bool check_bus_to_bus_conflicts;
/// If true, check that bus wires don't graphically connect to net objects (or vice versa)
bool check_bus_to_net_conflicts;
};
#endif

View File

@ -51,7 +51,9 @@
#include <sch_eagle_plugin.h>
#include <symbol_lib_table.h>
#include <dialog_symbol_remap.h>
#include <dialog_migrate_buses.h>
#include <worksheet_shape_builder.h>
#include <connection_graph.h>
bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName,
@ -287,6 +289,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
SetScreen( nullptr );
delete g_RootSheet; // Delete the current project.
g_RootSheet = NULL; // Force CreateScreens() to build new empty project on load failure.
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
// This will rename the file if there is an autosave and the user want to recover
@ -295,8 +298,10 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
try
{
g_RootSheet = pi->Load( fullFileName, &Kiway() );
m_CurrentSheet->clear();
m_CurrentSheet->push_back( g_RootSheet );
g_CurrentSheet = new SCH_SHEET_PATH();
g_CurrentSheet->clear();
g_CurrentSheet->push_back( g_RootSheet );
if( !pi->GetError().IsEmpty() )
{
@ -362,13 +367,27 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
}
schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
SetScreen( m_CurrentSheet->LastScreen() );
SetScreen( g_CurrentSheet->LastScreen() );
// Ensure the schematic is fully segmented on first display
BreakSegmentsOnJunctions();
SchematicCleanUp( true );
GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
RecalculateConnections(); // Update connectivity graph
// Migrate conflicting bus definitions
// TODO(JE) This should only run once based on schematic file version
if( g_ConnectionGraph->GetBusesNeedingMigration().size() > 0 )
{
DIALOG_MIGRATE_BUSES dlg( this );
dlg.ShowQuasiModal();
RecalculateConnections();
OnModify();
}
GetScreen()->m_Initialized = true;
}
@ -816,9 +835,9 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
newfilename.SetName( Prj().GetProjectName() );
newfilename.SetExt( SchematicFileExtension );
m_CurrentSheet->clear();
m_CurrentSheet->push_back( g_RootSheet );
SetScreen( m_CurrentSheet->LastScreen() );
g_CurrentSheet->clear();
g_CurrentSheet->push_back( g_RootSheet );
SetScreen( g_CurrentSheet->LastScreen() );
g_RootSheet->SetFileName( newfilename.GetFullPath() );
GetScreen()->SetFileName( newfilename.GetFullPath() );

View File

@ -70,8 +70,8 @@ void SCH_EDIT_FRAME::OnFindDrcMarker( wxFindDialogEvent& event )
if( event.GetFlags() & FR_CURRENT_SHEET_ONLY )
{
sheetFoundIn = m_CurrentSheet;
lastMarker = (SCH_MARKER*) m_CurrentSheet->FindNextItem( SCH_MARKER_T, lastMarker, wrap );
sheetFoundIn = g_CurrentSheet;
lastMarker = (SCH_MARKER*) g_CurrentSheet->FindNextItem( SCH_MARKER_T, lastMarker, wrap );
}
else
{
@ -81,11 +81,11 @@ void SCH_EDIT_FRAME::OnFindDrcMarker( wxFindDialogEvent& event )
if( lastMarker != NULL )
{
if( *sheetFoundIn != *m_CurrentSheet )
if( *sheetFoundIn != *g_CurrentSheet )
{
sheetFoundIn->LastScreen()->SetZoom( GetScreen()->GetZoom() );
*m_CurrentSheet = *sheetFoundIn;
m_CurrentSheet->UpdateAllScreenReferences();
*g_CurrentSheet = *sheetFoundIn;
g_CurrentSheet->UpdateAllScreenReferences();
}
SetCrossHairPosition( lastMarker->GetPosition() );
@ -122,7 +122,7 @@ SCH_ITEM* SCH_EDIT_FRAME::FindComponentAndItem( const wxString& aReference,
EDA_ITEM* foundItem = nullptr;
if( !aSearchHierarchy )
sheetList.push_back( *m_CurrentSheet );
sheetList.push_back( *g_CurrentSheet );
else
sheetList.BuildSheetList( g_RootSheet );
@ -193,10 +193,10 @@ SCH_ITEM* SCH_EDIT_FRAME::FindComponentAndItem( const wxString& aReference,
{
sheet = sheetWithComponentFound;
if( *sheet != *m_CurrentSheet )
if( *sheet != *g_CurrentSheet )
{
sheet->LastScreen()->SetZoom( GetScreen()->GetZoom() );
*m_CurrentSheet = *sheet;
*g_CurrentSheet = *sheet;
DisplayCurrentSheet();
}
@ -279,7 +279,7 @@ void SCH_EDIT_FRAME::OnFindSchematicItem( wxFindDialogEvent& aEvent )
{
if( aEvent.GetFlags() & FR_CURRENT_SHEET_ONLY && g_RootSheet->CountSheets() > 1 )
{
m_foundItems.Collect( searchCriteria, m_CurrentSheet );
m_foundItems.Collect( searchCriteria, g_CurrentSheet );
}
else
{
@ -317,7 +317,7 @@ void SCH_EDIT_FRAME::OnFindReplace( wxFindDialogEvent& aEvent )
{
if( aEvent.GetFlags() & FR_CURRENT_SHEET_ONLY && g_RootSheet->CountSheets() > 1 )
{
m_foundItems.Collect( searchCriteria, m_CurrentSheet );
m_foundItems.Collect( searchCriteria, g_CurrentSheet );
}
else
{
@ -423,11 +423,11 @@ void SCH_EDIT_FRAME::updateFindReplaceView( wxFindDialogEvent& aEvent )
item->SetForceVisible( true );
}
if( sheet->PathHumanReadable() != m_CurrentSheet->PathHumanReadable() )
if( sheet->PathHumanReadable() != g_CurrentSheet->PathHumanReadable() )
{
sheet->LastScreen()->SetZoom( GetScreen()->GetZoom() );
*m_CurrentSheet = *sheet;
m_CurrentSheet->UpdateAllScreenReferences();
*g_CurrentSheet = *sheet;
g_CurrentSheet->UpdateAllScreenReferences();
SetScreen( sheet->LastScreen() );
sheet->LastScreen()->TestDanglingEnds();
}

View File

@ -34,8 +34,10 @@
using KIGFX::COLOR4D;
class CONNECTION_GRAPH;
class TRANSFORM;
class SCH_SHEET;
class SCH_SHEET_PATH;
#define EESCHEMA_VERSION 4
#define SCHEMATIC_HEAD_STRING "Schematic File Version"
@ -83,6 +85,18 @@ extern TRANSFORM DefaultTransform;
/* First and main (root) screen */
extern SCH_SHEET* g_RootSheet;
/**
* With the new connectivity algorithm, many more places than before want to
* know what the current sheet is. This was moved here from SCH_EDIT_FRAME
* but we could refactor things to get rid of this global.
*/
extern SCH_SHEET_PATH* g_CurrentSheet; ///< which sheet we are presently working on.
/**
* This also wants to live in the eventual SCHEMATIC object
*/
extern CONNECTION_GRAPH* g_ConnectionGraph;
/**
* Default line thickness used to draw/plot items having a
* default thickness line value (i.e. = 0 ).

View File

@ -243,7 +243,7 @@ SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( const SCHLIB_FILTER* aF
if( !part )
return NULL;
SCH_COMPONENT* component = new SCH_COMPONENT( *part, libId, m_CurrentSheet,
SCH_COMPONENT* component = new SCH_COMPONENT( *part, libId, g_CurrentSheet,
sel.Unit, sel.Convert,
GetCrossHairPosition(), true );
@ -261,7 +261,6 @@ SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( const SCHLIB_FILTER* aF
MSG_PANEL_ITEMS items;
component->SetCurrentSheetPath( &GetCurrentSheet() );
component->GetMsgPanelInfo( m_UserUnits, items );
SetMsgPanel( items );
@ -333,7 +332,7 @@ void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
SaveCopyInUndoList( component, UR_CHANGED );
/* Update the unit number. */
component->SetUnitSelection( m_CurrentSheet, unit );
component->SetUnitSelection( g_CurrentSheet, unit );
component->SetUnit( unit );
component->ClearFlags();
component->SetFlags( flags ); // Restore m_Flag modified by SetUnit()

View File

@ -79,6 +79,7 @@
#define HELP_RUN_LIB_EDITOR _( "Create, delete, and edit symbols" )
#define HELP_RUN_LIB_VIEWER _( "Browse symbol libraries" )
#define HELP_GENERATE_BOM _( "Generate bill of materials" )
#define HELP_BUS_MANAGER _( "Manage bus definitions" )
#define HELP_IMPORT_FOOTPRINTS \
_( "Back-import symbol footprint association fields from the .cmp back import file created by Pcbnew" )

View File

@ -267,7 +267,7 @@ void SCH_EDIT_FRAME::DisplayCurrentSheet()
SetRepeatItem( NULL );
ClearMsgPanel();
SCH_SCREEN* screen = m_CurrentSheet->LastScreen();
SCH_SCREEN* screen = g_CurrentSheet->LastScreen();
// Switch to current sheet,
// and update the grid size, because it can be modified in latest screen
@ -275,7 +275,7 @@ void SCH_EDIT_FRAME::DisplayCurrentSheet()
GetScreen()->SetGrid( m_LastGridSizeId + ID_POPUP_GRID_LEVEL_1000 );
// update the References
m_CurrentSheet->UpdateAllScreenReferences();
g_CurrentSheet->UpdateAllScreenReferences();
SetSheetNumberAndCount();
m_canvas->SetCanStartBlock( -1 );
@ -284,12 +284,11 @@ void SCH_EDIT_FRAME::DisplayCurrentSheet()
Zoom_Automatique( false );
screen->m_Initialized = true;
// Ensure the schematic is fully segmented on first display
BreakSegmentsOnJunctions();
SchematicCleanUp( true );
screen->ClearUndoORRedoList( screen->m_UndoList, 1 );
// TODO(JE) should be able to just recalculate the current sheet path
// RecalculateConnections() handles cleanup and dangling ends tests
RecalculateConnections();
screen->TestDanglingEnds();
screen->ClearUndoORRedoList( screen->m_UndoList, 1 );
}
else
{

View File

@ -35,42 +35,43 @@
#include <erc.h>
#include <netlist_object.h>
#include <sch_component.h>
#include <sch_sheet.h>
// List of items having the highlight option modified, therefore need to be redrawn
// TODO(JE) Probably use netcode rather than connection name here eventually
bool SCH_EDIT_FRAME::HighlightConnectionAtPosition( wxPoint aPosition )
{
std::vector<EDA_ITEM*> itemsToRedraw;
m_SelectedNetName = "";
bool buildNetlistOk = false;
SetStatusText( "" );
// find which connected item is selected
EDA_ITEMS nodeList;
wxPoint gridPosition = GetGridPosition( aPosition );
if( GetScreen()->GetNode( gridPosition,nodeList ) )
if( GetScreen()->GetNode( gridPosition, nodeList ) )
{
if( TestDuplicateSheetNames( false ) > 0 )
wxMessageBox( _( "Error: duplicate sub-sheet names found in current sheet. Fix it" ) );
else
{
// Build netlist info to get the proper netnames of connected items
std::unique_ptr<NETLIST_OBJECT_LIST> objectsConnectedList( BuildNetListBase() );
buildNetlistOk = true;
for( auto obj : *objectsConnectedList )
if( auto item = dynamic_cast<SCH_ITEM*>( nodeList[0] ) )
{
if( obj->m_SheetPath == *m_CurrentSheet && obj->m_Comp == nodeList[0] )
if( item->Connection( *g_CurrentSheet ) )
{
m_SelectedNetName = obj->GetNetName( true );
break;
m_SelectedNetName = item->Connection( *g_CurrentSheet )->Name();
SetStatusText( _( "Highlighted net: " ) + m_SelectedNetName );
}
}
}
}
SendCrossProbeNetName( m_SelectedNetName );
SetStatusText( "selected net: " + m_SelectedNetName );
SetStatusText( _( "Selected net: " ) + m_SelectedNetName );
SetCurrentSheetHighlightFlags( &itemsToRedraw );
// Be sure hightlight change will be redrawn
@ -87,7 +88,7 @@ bool SCH_EDIT_FRAME::HighlightConnectionAtPosition( wxPoint aPosition )
bool SCH_EDIT_FRAME::SetCurrentSheetHighlightFlags( std::vector<EDA_ITEM*>* aItemsToRedrawList )
{
SCH_SCREEN* screen = m_CurrentSheet->LastScreen();
SCH_SCREEN* screen = g_CurrentSheet->LastScreen();
if( !screen )
return true;
@ -95,20 +96,33 @@ bool SCH_EDIT_FRAME::SetCurrentSheetHighlightFlags( std::vector<EDA_ITEM*>* aIte
// Disable highlight flag on all items in the current screen
for( SCH_ITEM* ptr = screen->GetDrawItems(); ptr; ptr = ptr->Next() )
{
if( ptr->GetState( BRIGHTENED ) && aItemsToRedrawList )
auto conn = ptr->Connection( *g_CurrentSheet );
bool bright = ptr->GetState( BRIGHTENED );
if( bright && aItemsToRedrawList )
aItemsToRedrawList->push_back( ptr );
ptr->SetState( BRIGHTENED, false );
ptr->SetState( BRIGHTENED, ( conn && conn->Name() == m_SelectedNetName ) );
if( !bright && ptr->GetState( BRIGHTENED ) && aItemsToRedrawList )
aItemsToRedrawList->push_back( ptr );
if( ptr->Type() == SCH_SHEET_T )
{
for( SCH_SHEET_PIN& pin : static_cast<SCH_SHEET*>( ptr )->GetPins() )
{
if( ptr->GetState( BRIGHTENED ) && aItemsToRedrawList )
auto pin_conn = pin.Connection( *g_CurrentSheet );
bright = pin.GetState( BRIGHTENED );
if( bright && aItemsToRedrawList )
aItemsToRedrawList->push_back( &pin );
pin.SetState( BRIGHTENED, false );
pin.SetState( BRIGHTENED, ( pin_conn &&
pin_conn->Name() == m_SelectedNetName ) );
if( !bright && pin.GetState( BRIGHTENED ) && aItemsToRedrawList )
aItemsToRedrawList->push_back( &pin );
}
}
}
@ -119,37 +133,5 @@ bool SCH_EDIT_FRAME::SetCurrentSheetHighlightFlags( std::vector<EDA_ITEM*>* aIte
if( TestDuplicateSheetNames( false ) > 0 )
return false;
// Build netlist info to get the proper netnames
std::unique_ptr<NETLIST_OBJECT_LIST> objectsConnectedList( BuildNetListBase( false ) );
// highlight the items belonging to this net
for( auto obj1 : *objectsConnectedList )
{
if( obj1->m_SheetPath == *m_CurrentSheet &&
obj1->GetNetName( true ) == m_SelectedNetName && obj1->m_Comp )
{
obj1->m_Comp->SetState( BRIGHTENED, true );
if( aItemsToRedrawList )
aItemsToRedrawList->push_back( obj1->m_Comp );
//if a bus is associated with this net highlight it as well
if( obj1->m_BusNetCode )
{
for( auto obj2 : *objectsConnectedList )
{
if( obj2 && obj2->m_Comp && obj2->m_SheetPath == *m_CurrentSheet &&
obj1->m_BusNetCode == obj2->m_BusNetCode )
{
if( aItemsToRedrawList )
aItemsToRedrawList->push_back( obj2->m_Comp );
obj2->m_Comp->SetState( BRIGHTENED, true );
}
}
}
}
}
return true;
}

View File

@ -220,6 +220,9 @@ static EDA_HOTKEY HkUpdatePcbFromSch( _HKI( "Update PCB from Schematic" ), HK_UP
static EDA_HOTKEY HkHighlightConnection( _HKI( "Highlight Connection" ), ID_HOTKEY_HIGHLIGHT,
'B' + GR_KB_CTRL );
static EDA_HOTKEY HkUnfoldBus( _HKI( "Unfold Bus" ), HK_UNFOLD_BUS, 'D',
ID_SCH_UNFOLD_BUS );
// Common: hotkeys_basic.h
static EDA_HOTKEY HkNew( _HKI( "New" ), HK_NEW, GR_KB_CTRL + 'N', (int) wxID_NEW );
static EDA_HOTKEY HkOpen( _HKI( "Open" ), HK_OPEN, GR_KB_CTRL + 'O', (int) wxID_OPEN );
@ -332,6 +335,7 @@ static EDA_HOTKEY* schematic_Hotkey_List[] =
&HkLeaveSheet,
&HkDeleteNode,
&HkHighlightConnection,
&HkUnfoldBus,
&HkCanvasCairo,
&HkCanvasOpenGL,
NULL
@ -639,6 +643,7 @@ bool SCH_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition,
case HK_ROTATE: // Rotate schematic item.
case HK_EDIT_COMPONENT_WITH_LIBEDIT: // Call Libedit and load the current component
case HK_AUTOPLACE_FIELDS: // Autoplace all fields around component
case HK_UNFOLD_BUS: // Unfold a bus wire
case HK_CANVAS_CAIRO:
case HK_CANVAS_OPENGL:
{

View File

@ -80,6 +80,7 @@ enum hotkey_id_commnand {
HK_AUTOPLACE_FIELDS,
HK_UPDATE_PCB_FROM_SCH,
HK_SELECT_ITEMS_ON_PCB,
HK_UNFOLD_BUS,
HK_CANVAS_OPENGL,
HK_CANVAS_CAIRO,
};

View File

@ -81,6 +81,9 @@ int InvokeDialogPrintUsingPrinter( SCH_EDIT_FRAME* aCaller );
/// DIALOG_BOM::ShowModal() returns.
int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller );
/// Create and show DIALOG_BUS_MANAGER
void InvokeDialogBusManager( SCH_EDIT_FRAME* aCaller );
/// Update symbol fields
int InvokeDialogUpdateFields( SCH_EDIT_FRAME* aCaller,
const std::list<SCH_COMPONENT*> aComponents, bool aCreateUndoEntry );

View File

@ -35,6 +35,7 @@
#include <eda_rect.h>
#include <transform.h>
#include <gr_basic.h>
#include <sch_connection.h>
class LINE_READER;

View File

@ -47,6 +47,7 @@
#include <lib_pin.h>
#include <transform.h>
#include <sch_component.h>
#include <sch_sheet_path.h>
#include <trace_helpers.h>
@ -1770,6 +1771,19 @@ void LIB_PIN::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >
aList.push_back( MSG_PANEL_ITEM( aComponent->GetField( REFERENCE )->GetShownText(),
aComponent->GetField( VALUE )->GetShownText(),
DARKCYAN ) );
#if defined(DEBUG)
if( auto pin_connection = aComponent->GetConnectionForPin( this ) )
{
auto conn = pin_connection->Connection( *g_CurrentSheet );
wxASSERT( conn );
conn->AppendDebugInfoToMsgPanel( aList );
}
#endif
}
const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles ) const

View File

@ -571,6 +571,12 @@ void prepareToolsMenu( wxMenu* aParentMenu )
HELP_GENERATE_BOM,
KiBitmap( bom_xpm ) );
AddMenuItem( aParentMenu,
ID_BUS_MANAGER,
_( "Bus &Definitions" ),
HELP_BUS_MANAGER,
KiBitmap( bom_xpm ) ); // TODO(JE) new icon?
aParentMenu->AppendSeparator();
// Run CvPcb

View File

@ -26,6 +26,9 @@
#include "netlist_exporter_generic.h"
#include <build_version.h>
#include <sch_base_frame.h>
#include <class_library.h>
#include <connection_graph.h>
#include <refdes_utils.h>
#include <class_library.h>
@ -499,44 +502,94 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets()
m_LibParts.clear(); // must call this function before using m_LibParts.
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
if( m_use_graph && m_graph )
{
NETLIST_OBJECT* nitem = m_masterList->GetItem( ii );
SCH_COMPONENT* comp;
// New net found, write net id;
if( ( netCode = nitem->GetNet() ) != lastNetCode )
for( auto it : m_graph->m_net_code_to_subgraphs_map )
{
sameNetcodeCount = 0; // item count for this net
netName = nitem->GetNetName();
lastNetCode = netCode;
bool added = false;
auto code = it.first;
auto subgraphs = it.second;
auto net_name = subgraphs[0]->GetNetName();
XNODE* xnode;
for( auto subgraph : subgraphs )
{
auto sheet = subgraph->m_sheet;
for( auto item : subgraph->m_items )
{
if( item->Type() == SCH_PIN_CONNECTION_T )
{
auto pc = static_cast<SCH_PIN_CONNECTION*>( item );
// Skip power symbols
if( (LIB_PART*)( pc->m_pin->GetParent() )->IsPower() )
continue;
if( !added )
{
xnets->AddChild( xnet = node( "net" ) );
netCodeTxt.Printf( "%d", code );
xnet->AddAttribute( "code", netCodeTxt );
xnet->AddAttribute( "name", net_name );
added = true;
}
auto refText = pc->m_comp->GetRef( &sheet );
auto pinText = pc->m_pin->GetNumber();
xnet->AddChild( xnode = node( "node" ) );
xnode->AddAttribute( "ref", refText );
xnode->AddAttribute( "pin", pinText );
}
}
}
}
if( nitem->m_Type != NET_PIN )
continue;
if( nitem->m_Flag != 0 ) // Redundant pin, skip it
continue;
comp = nitem->GetComponentParent();
// Get the reference for the net name and the main parent component
ref = comp->GetRef( &nitem->m_SheetPath );
if( ref[0] == wxChar( '#' ) )
continue;
if( ++sameNetcodeCount == 1 )
}
else
{
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
{
xnets->AddChild( xnet = node( "net" ) );
netCodeTxt.Printf( "%d", netCode );
xnet->AddAttribute( "code", netCodeTxt );
xnet->AddAttribute( "name", netName );
}
NETLIST_OBJECT* nitem = m_masterList->GetItem( ii );
SCH_COMPONENT* comp;
XNODE* xnode;
xnet->AddChild( xnode = node( "node" ) );
xnode->AddAttribute( "ref", ref );
xnode->AddAttribute( "pin", nitem->GetPinNumText() );
// New net found, write net id;
if( ( netCode = nitem->GetNet() ) != lastNetCode )
{
sameNetcodeCount = 0; // item count for this net
netName = nitem->GetNetName();
lastNetCode = netCode;
}
if( nitem->m_Type != NET_PIN )
continue;
if( nitem->m_Flag != 0 ) // Redundant pin, skip it
continue;
comp = nitem->GetComponentParent();
// Get the reference for the net name and the main parent component
ref = comp->GetRef( &nitem->m_SheetPath );
if( ref[0] == wxChar( '#' ) )
continue;
if( ++sameNetcodeCount == 1 )
{
xnets->AddChild( xnet = node( "net" ) );
netCodeTxt.Printf( "%d", netCode );
xnet->AddAttribute( "code", netCodeTxt );
xnet->AddAttribute( "name", netName );
}
XNODE* xnode;
xnet->AddChild( xnode = node( "node" ) );
xnode->AddAttribute( "ref", ref );
xnode->AddAttribute( "pin", nitem->GetPinNumText() );
}
}
return xnets;

View File

@ -33,6 +33,7 @@
#include <sch_edit_frame.h>
class CONNECTION_GRAPH;
class SYMBOL_LIB_TABLE;
#define GENERIC_INTERMEDIATE_NETLIST_EXT wxT( "xml" )
@ -63,10 +64,20 @@ private:
SYMBOL_LIB_TABLE* m_libTable;
protected:
CONNECTION_GRAPH* m_graph;
// TODO(JE) Remove if not needed
bool m_use_graph;
public:
NETLIST_EXPORTER_GENERIC( SCH_EDIT_FRAME* aFrame, NETLIST_OBJECT_LIST* aMasterList ) :
NETLIST_EXPORTER_GENERIC( SCH_EDIT_FRAME* aFrame,
NETLIST_OBJECT_LIST* aMasterList,
CONNECTION_GRAPH* aGraph = nullptr ) :
NETLIST_EXPORTER( aMasterList ),
m_libTable( aFrame->Prj().SchSymbolLibTable() )
m_libTable( aFrame->Prj().SchSymbolLibTable() ),
m_graph( aGraph ),
m_use_graph( true )
{}
/**

View File

@ -24,15 +24,22 @@
*/
#include <algorithm>
#include <fctsys.h>
#include <build_version.h>
#include <confirm.h>
#include <sch_edit_frame.h>
#include <xnode.h>
#include <connection_graph.h>
#include "netlist_exporter_kicad.h"
bool NETLIST_EXPORTER_KICAD::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions )
{
wxASSERT( m_graph );
m_use_graph = true;
try
{
FILE_OUTPUTFORMATTER formatter( aOutFileName );
@ -45,6 +52,130 @@ bool NETLIST_EXPORTER_KICAD::WriteNetlist( const wxString& aOutFileName, unsigne
return false;
}
/**
* Temporary QC measure:
* Generate the netlist again using the old algorithm and compare.
* In theory, if the schematic does not use any of the new bus techniques
* (bus aliases, bus groups, etc) they should match. If not, we can throw
* a warning and generate some debug output to fix the new netlister.
*
* This whole block can be removed once we are confident in the new code.
*/
if( !m_graph->UsesNewBusFeatures() )
{
m_use_graph = false;
auto old_nets = makeListOfNets();
bool different = false;
for( auto it : m_graph->m_net_code_to_subgraphs_map )
{
// auto code = it.first;
auto subgraphs = it.second;
auto net_name = subgraphs[0]->GetNetName();
std::set<wxString> net_pins;
for( auto subgraph : subgraphs )
{
auto sheet = subgraph->m_sheet;
for( auto item : subgraph->m_items )
{
if( item->Type() == SCH_PIN_CONNECTION_T )
{
auto pc = static_cast<SCH_PIN_CONNECTION*>( item );
if( pc->m_pin->IsPowerConnection() ||
(LIB_PART*)( pc->m_pin->GetParent() )->IsPower() )
continue;
wxString refText = pc->m_comp->GetRef( &sheet );
wxString pinText = pc->m_pin->GetNumber();
net_pins.insert( refText + "-" + pinText );
}
}
}
bool found = false;
// Yes this is slow, but it's a temporary debugging thing.
for( auto kid = old_nets->GetChildren(); kid; kid = kid->GetNext() )
{
for( auto attr = kid->GetAttributes(); attr; attr = attr->GetNext() )
{
if( attr->GetName() == "name" && attr->GetValue() == net_name )
{
found = true;
// Check members of this net
std::set<wxString> old_net_pins;
for( auto pin_node = kid->GetChildren();
pin_node; pin_node = pin_node->GetNext() )
{
wxString ref, pin;
for( auto pin_attr = pin_node->GetAttributes();
pin_attr; pin_attr = pin_attr->GetNext() )
{
if( pin_attr->GetName() == "ref" )
ref = pin_attr->GetValue();
if( pin_attr->GetName() == "pin" )
pin = pin_attr->GetValue();
}
old_net_pins.insert( ref + "-" + pin );
}
std::vector<wxString> difference( std::max( net_pins.size(),
old_net_pins.size() ) );
auto end = std::set_symmetric_difference( net_pins.begin(),
net_pins.end(),
old_net_pins.begin(),
old_net_pins.end(),
difference.begin() );
difference.resize( end - difference.begin() );
if( difference.size() > 0 )
{
different = true;
}
}
}
}
if( !found )
{
different = true;
}
}
if( different )
{
wxLogDebug( "NOTE: New netlist algorithm is inconsistent with old! "
"Please contact Jon Evans <jon@craftyjon.com> "
"to help debug this issue" );
try
{
FILE_OUTPUTFORMATTER formatter( aOutFileName + ".old_algo" );
Format( &formatter, GNL_ALL );
}
catch( const IO_ERROR& ioe )
{
DisplayError( NULL, ioe.What() );
return false;
}
}
}
return true;
}

View File

@ -38,8 +38,10 @@ class OUTPUTFORMATTER;
class NETLIST_EXPORTER_KICAD : public NETLIST_EXPORTER_GENERIC
{
public:
NETLIST_EXPORTER_KICAD( SCH_EDIT_FRAME* aFrame, NETLIST_OBJECT_LIST* aMasterList ) :
NETLIST_EXPORTER_GENERIC( aFrame, aMasterList )
NETLIST_EXPORTER_KICAD( SCH_EDIT_FRAME* aFrame,
NETLIST_OBJECT_LIST* aMasterList,
CONNECTION_GRAPH* aGraph = nullptr ) :
NETLIST_EXPORTER_GENERIC( aFrame, aMasterList, aGraph )
{}
/**

View File

@ -61,7 +61,8 @@ bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST* aConnectedItemsList,
switch( aFormat )
{
case NET_TYPE_PCBNEW:
helper = new NETLIST_EXPORTER_KICAD( this, aConnectedItemsList );
helper = new NETLIST_EXPORTER_KICAD( this, aConnectedItemsList,
g_ConnectionGraph );
break;
case NET_TYPE_ORCADPCB2:
@ -82,7 +83,8 @@ bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST* aConnectedItemsList,
tmpFile.SetExt( GENERIC_INTERMEDIATE_NETLIST_EXT );
fileName = tmpFile.GetFullPath();
helper = new NETLIST_EXPORTER_GENERIC( this, aConnectedItemsList );
helper = new NETLIST_EXPORTER_GENERIC( this, aConnectedItemsList,
g_ConnectionGraph );
executeCommandLine = true;
}
break;

View File

@ -30,30 +30,12 @@
#include <fctsys.h>
#include <macros.h>
#include <sch_edit_frame.h>
#include <list>
#include <sch_component.h>
#include <sch_connection.h>
#include <netlist_object.h>
#include <wx/regex.h>
/**
* The regular expression string for label bus notation. Valid bus labels are defined as
* one or more non-whitespace characters from the beginning of the string followed by the
* bus notation [nn...mm] with no characters after the closing bracket.
*/
static wxRegEx busLabelRe( wxT( "^([^[:space:]]+)(\\[[\\d]+\\.+[\\d]+\\])$" ), wxRE_ADVANCED );
bool IsBusLabel( const wxString& aLabel )
{
wxCHECK_MSG( busLabelRe.IsValid(), false,
wxT( "Invalid regular expression in IsBusLabel()." ) );
return busLabelRe.Matches( aLabel );
}
#include <sch_edit_frame.h>
#if defined(DEBUG)
@ -240,7 +222,8 @@ bool NETLIST_OBJECT::IsLabelConnected( NETLIST_OBJECT* aNetItem )
void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItems )
{
wxCHECK_RET( IsBusLabel( m_Label ),
SCH_CONNECTION conn;
wxCHECK_RET( conn.IsBusLabel( m_Label ),
wxT( "<" ) + m_Label + wxT( "> is not a valid bus label." ) );
if( m_Type == NET_HIERLABEL )
@ -254,61 +237,109 @@ void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItem
else
wxCHECK_RET( false, wxT( "Net list object type is not valid." ) );
unsigned i;
wxString tmp, busName, busNumber;
long begin, end, member;
// NOTE: all netlist objects generated from a single bus definition need to have different
// member codes set. For bus vectors, the member code matches the vector index, but for
// bus groups (including with nested vectors) the code is something arbitrary.
long member_offset = 0;
busName = busLabelRe.GetMatch( m_Label, 1 );
busNumber = busLabelRe.GetMatch( m_Label, 2 );
/* Search for '[' because a bus label is like "busname[nn..mm]" */
i = busNumber.Find( '[' );
i++;
while( i < busNumber.Len() && busNumber[i] != '.' )
auto alias = SCH_SCREEN::GetBusAlias( m_Label );
if( alias || conn.IsBusGroupLabel( m_Label ) )
{
tmp.Append( busNumber[i] );
i++;
wxString group_name;
bool self_set = false;
std::vector<wxString> bus_contents_vec;
if( alias )
{
bus_contents_vec = alias->Members();
}
else
{
wxCHECK_RET( conn.ParseBusGroup( m_Label, &group_name, bus_contents_vec ),
_( "Failed to parse bus group " ) + m_Label );
}
// For named bus groups, like "USB{DP DM}"
auto group_prefix = ( group_name != "" ) ? ( group_name + "." ) : "";
std::list<wxString> bus_contents( bus_contents_vec.begin(),
bus_contents_vec.end() );
for( auto bus_member : bus_contents )
{
// Nested bus vector inside a bus group
if( conn.IsBusVectorLabel( bus_member ) )
{
wxString prefix;
long begin, end;
conn.ParseBusVector( bus_member, &prefix, &begin, &end );
prefix = group_prefix + prefix;
if( !self_set )
{
m_Label = prefix;
m_Label << begin;
m_Member = ( begin++ ) + ( member_offset++ );
self_set = true;
begin++;
}
fillBusVector( aNetListItems, prefix, begin, end, member_offset );
member_offset += std::abs( end - begin );
}
else if( auto nested_alias = SCH_SCREEN::GetBusAlias( bus_member ) )
{
// Nested alias inside a group
for( auto alias_member : nested_alias->Members() )
{
bus_contents.push_back( alias_member );
}
}
else
{
if( !self_set )
{
m_Label = group_prefix + bus_member;
m_Member = member_offset++;
self_set = true;
}
else
{
auto item = new NETLIST_OBJECT( *this );
item->m_Label = group_prefix + bus_member;
item->m_Member = member_offset++;
aNetListItems.push_back( item );
}
}
}
}
tmp.ToLong( &begin );
while( i < busNumber.Len() && busNumber[i] == '.' )
i++;
tmp.Empty();
while( i < busNumber.Len() && busNumber[i] != ']' )
else
{
tmp.Append( busNumber[i] );
i++;
// Plain bus vector
wxString prefix;
long begin, end;
conn.ParseBusVector( m_Label, &prefix, &begin, &end );
m_Label = prefix;
m_Label << begin;
m_Member = begin;
fillBusVector( aNetListItems, prefix, begin + 1, end, 0 );
}
}
tmp.ToLong( &end );
if( begin < 0 )
begin = 0;
if( end < 0 )
end = 0;
if( begin > end )
std::swap( begin, end );
member = begin;
tmp = busName;
tmp << member;
m_Label = tmp;
m_Member = member;
for( member++; member <= end; member++ )
void NETLIST_OBJECT::fillBusVector( NETLIST_OBJECT_LIST& aNetListItems,
wxString aName, long aBegin, long aEnd, long aOffset )
{
for( long member = aBegin; member <= aEnd; member++ )
{
NETLIST_OBJECT* item = new NETLIST_OBJECT( *this );
auto item = new NETLIST_OBJECT( *this );
// Conversion of bus label to the root name + the current member id.
tmp = busName;
tmp << member;
item->m_Label = tmp;
item->m_Label = aName;
item->m_Label << member;
item->m_Member = member;
aNetListItems.push_back( item );

View File

@ -264,6 +264,21 @@ public:
* the bus label NETLIST_OBJECTs.
*/
void ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItems );
private:
/**
* Given a bus vector, append the appropriate members into the list
* If given something like "DATA", 7, 0, will append "DATA7", "DATA6", etc.
*
* @param aNetListItems is the list to append to
* @param aName is the prefix for the vector, like "DATA"
* @param aBegin is the first entry in the vector
* @param aEnd is the last entry in the vector
* @param aOffset is an offset to add to the member code for each member
*/
void fillBusVector( NETLIST_OBJECT_LIST& aNetListItems, wxString aName,
long aBegin, long aEnd, long aOffset );
};

View File

@ -408,7 +408,7 @@ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition )
switch( item->Type() )
{
case SCH_SHEET_T:
m_CurrentSheet->push_back( (SCH_SHEET*) item );
g_CurrentSheet->push_back( (SCH_SHEET*) item );
DisplayCurrentSheet();
break;

View File

@ -34,9 +34,10 @@
#include <sch_edit_frame.h>
#include <menus_helpers.h>
#include <class_library.h>
#include <general.h>
#include <hotkeys.h>
#include <class_library.h>
#include <netlist_object.h>
#include <sch_bus_entry.h>
#include <sch_marker.h>
#include <sch_text.h>
@ -48,6 +49,7 @@
#include <sch_sheet_path.h>
#include <sch_bitmap.h>
#include <symbol_lib_table.h>
#include <sch_connection.h>
#include <sch_view.h>
#include <iostream>
@ -208,7 +210,7 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
PopMenu->AppendSeparator();
}
if( m_CurrentSheet->Last() != g_RootSheet )
if( g_CurrentSheet->Last() != g_RootSheet )
{
msg = AddHotkeyName( _( "Leave Sheet" ), g_Schematic_Hokeys_Descr, HK_LEAVE_SHEET );
AddMenuItem( PopMenu, ID_POPUP_SCH_LEAVE_SHEET, msg,
@ -766,6 +768,58 @@ void AddMenusForBus( wxMenu* PopMenu, SCH_LINE* Bus, SCH_EDIT_FRAME* frame )
AddMenuItem( PopMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Bus" ), KiBitmap( break_bus_xpm ) );
// Bus unfolding menu (only available if bus is properly defined)
auto connection = Bus->Connection( *g_CurrentSheet );
if( connection && connection->IsBus() && connection->Members().size() > 0 )
{
int idx = 0;
wxMenu* bus_unfolding_menu = new wxMenu;
PopMenu->AppendSubMenu( bus_unfolding_menu, _( "Unfold Bus" ) );
for( const auto& member : connection->Members() )
{
int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
auto name = member->Name( true );
if( member->Type() == CONNECTION_BUS )
{
wxMenu* submenu = new wxMenu;
bus_unfolding_menu->AppendSubMenu( submenu, _( name ) );
for( const auto& sub_member : member->Members() )
{
id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
submenu->Append( id, sub_member->Name( true ), wxEmptyString );
// See comment in else clause below
auto sub_item_clone = new wxMenuItem();
sub_item_clone->SetItemLabel( sub_member->Name( true ) );
frame->Bind( wxEVT_COMMAND_MENU_SELECTED, &SCH_EDIT_FRAME::OnUnfoldBus,
frame, id, id, sub_item_clone );
}
}
else
{
bus_unfolding_menu->Append( id, name, wxEmptyString );
// Because Bind() takes ownership of the user data item, we
// make a new menu item here and set its label. Why create a
// menu item instead of just a wxString or something? Because
// Bind() requires a pointer to wxObject rather than a void
// pointer. Maybe at some point I'll think of a better way...
auto item_clone = new wxMenuItem();
item_clone->SetItemLabel( name );
frame->Bind( wxEVT_COMMAND_MENU_SELECTED, &SCH_EDIT_FRAME::OnUnfoldBus,
frame, id, id, item_clone );
}
}
}
PopMenu->AppendSeparator();
msg = AddHotkeyName( _( "Add Junction" ), g_Schematic_Hokeys_Descr, HK_ADD_JUNCTION );
AddMenuItem( PopMenu, ID_POPUP_SCH_ADD_JUNCTION, msg, KiBitmap( add_junction_xpm ) );

View File

@ -441,6 +441,8 @@ void SCH_BASE_FRAME::RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointe
else
GetCanvas()->GetView()->SetScale( scale );
GetCanvas()->GetView()->SetCenter( aCenterPoint );
if( aWarpPointer )
GetCanvas()->GetViewControls()->CenterOnCursor();
@ -623,31 +625,57 @@ void SCH_BASE_FRAME::RefreshItem( SCH_ITEM* aItem, bool isAddOrDelete )
}
void SCH_BASE_FRAME::AddToScreen( SCH_ITEM* aItem )
void SCH_BASE_FRAME::AddToScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen )
{
GetScreen()->Append( aItem );
GetCanvas()->GetView()->Add( aItem );
RefreshItem( aItem, true ); // handle any additional parent semantics
auto screen = aScreen;
if( aScreen == nullptr )
screen = GetScreen();
screen->Append( aItem );
if( screen == GetScreen() )
{
GetCanvas()->GetView()->Add( aItem );
RefreshItem( aItem, true ); // handle any additional parent semantics
}
}
void SCH_BASE_FRAME::AddToScreen( DLIST<SCH_ITEM>& aItems )
void SCH_BASE_FRAME::AddToScreen( DLIST<SCH_ITEM>& aItems, SCH_SCREEN* aScreen )
{
for( SCH_ITEM* item = aItems.begin(); item; item = item->Next() )
auto screen = aScreen;
if( aScreen == nullptr )
screen = GetScreen();
if( screen == GetScreen() )
{
GetCanvas()->GetView()->Add( item );
RefreshItem( item, true ); // handle any additional parent semantics
for( SCH_ITEM* item = aItems.begin(); item; item = item->Next() )
{
GetCanvas()->GetView()->Add( item );
RefreshItem( item, true ); // handle any additional parent semantics
}
}
GetScreen()->Append( aItems );
screen->Append( aItems );
}
void SCH_BASE_FRAME::RemoveFromScreen( SCH_ITEM* aItem )
void SCH_BASE_FRAME::RemoveFromScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen )
{
GetCanvas()->GetView()->Remove( aItem );
GetScreen()->Remove( aItem );
RefreshItem( aItem, true ); // handle any additional parent semantics
auto screen = aScreen;
if( aScreen == nullptr )
screen = GetScreen();
if( screen == GetScreen() )
GetCanvas()->GetView()->Remove( aItem );
screen->Remove( aItem );
if( screen == GetScreen() )
RefreshItem( aItem, true ); // handle any additional parent semantics
}

View File

@ -298,18 +298,21 @@ public:
/**
* Add an item to the screen (and view)
* aScreen is the screen the item is located on, if not the current screen
*/
void AddToScreen( SCH_ITEM* aItem );
void AddToScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen = nullptr );
/**
* Add a list of items to the screen (and view)
* aScreen is the screen the item is located on, if not the current screen
*/
void AddToScreen( DLIST<SCH_ITEM>& aItems );
void AddToScreen( DLIST<SCH_ITEM>& aItems, SCH_SCREEN* aScreen = nullptr );
/**
* Remove an item from the screen (and view)
* aScreen is the screen the item is located on, if not the current screen
*/
void RemoveFromScreen( SCH_ITEM* aItem );
void RemoveFromScreen( SCH_ITEM* aItem, SCH_SCREEN* aScreen = nullptr );
/**
* Mark an item for refresh.

View File

@ -40,6 +40,7 @@
#include <eeschema_config.h>
#include <general.h>
#include <sch_bus_entry.h>
#include <sch_line.h>
SCH_BUS_ENTRY_BASE::SCH_BUS_ENTRY_BASE( KICAD_T aType, const wxPoint& pos, char shape ) :
@ -59,12 +60,15 @@ SCH_BUS_WIRE_ENTRY::SCH_BUS_WIRE_ENTRY( const wxPoint& pos, char shape ) :
SCH_BUS_ENTRY_BASE( SCH_BUS_WIRE_ENTRY_T, pos, shape )
{
m_Layer = LAYER_WIRE;
m_connected_bus_item = nullptr;
}
SCH_BUS_BUS_ENTRY::SCH_BUS_BUS_ENTRY( const wxPoint& pos, char shape ) :
SCH_BUS_ENTRY_BASE( SCH_BUS_BUS_ENTRY_T, pos, shape )
{
m_Layer = LAYER_BUS;
m_connected_bus_items[0] = nullptr;
m_connected_bus_items[1] = nullptr;
}
EDA_ITEM* SCH_BUS_WIRE_ENTRY::Clone() const
@ -416,3 +420,30 @@ char SCH_BUS_ENTRY_BASE::GetBusEntryShape() const
else
return '\\';
}
void SCH_BUS_ENTRY_BASE::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList )
{
if( auto conn = Connection( *g_CurrentSheet ) )
{
#if defined(DEBUG)
conn->AppendDebugInfoToMsgPanel( aList );
#else
conn->AppendInfoToMsgPanel( aList );
#endif
}
}
bool SCH_BUS_WIRE_ENTRY::ConnectionPropagatesTo( const EDA_ITEM* aItem ) const
{
// Don't generate connections between bus entries and buses, since there is
// a connectivity change at that point (e.g. A[7..0] to A7)
if( ( aItem->Type() == SCH_LINE_T ) &&
( static_cast<const SCH_LINE*>( aItem )->GetLayer() == LAYER_BUS ) )
{
return false;
}
return true;
}

View File

@ -120,6 +120,8 @@ public:
void Plot( PLOTTER* aPlotter ) override;
void GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList ) override;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
@ -157,9 +159,17 @@ public:
EDA_ITEM* Clone() const override;
virtual bool ConnectionPropagatesTo( const EDA_ITEM* aItem ) const override;
BITMAP_DEF GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override;
/**
* Pointer to the bus item (usually a bus wire) connected to this bus-wire
* entry, if it is connected to one.
*/
SCH_ITEM* m_connected_bus_item;
};
/**
@ -193,6 +203,12 @@ public:
BITMAP_DEF GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override;
/**
* Pointer to the bus items (usually bus wires) connected to this bus-bus
* entry (either or both may be nullptr)
*/
SCH_ITEM* m_connected_bus_items[2];
};
#endif // _SCH_BUS_ENTRY_H_

View File

@ -123,7 +123,6 @@ SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos, SCH_ITEM* aParent ) :
SCH_ITEM( aParent, SCH_COMPONENT_T )
{
Init( aPos );
m_currentSheetPath = NULL;
m_fieldsAutoplaced = AUTOPLACED_NO;
}
@ -138,7 +137,6 @@ SCH_COMPONENT::SCH_COMPONENT( LIB_PART& aPart, LIB_ID aLibId, SCH_SHEET_PATH* sh
m_convert = convert;
m_lib_id = aLibId;
m_part = aPart.SharedPtr();
m_currentSheetPath = NULL;
m_fieldsAutoplaced = AUTOPLACED_NO;
SetTimeStamp( GetNewTimeStamp() );
@ -163,7 +161,6 @@ SCH_COMPONENT::SCH_COMPONENT( LIB_PART& aPart, LIB_ID aLibId, SCH_SHEET_PATH* sh
SCH_COMPONENT::SCH_COMPONENT( const SCH_COMPONENT& aComponent ) :
SCH_ITEM( aComponent )
{
m_currentSheetPath = NULL;
m_Parent = aComponent.m_Parent;
m_Pos = aComponent.m_Pos;
m_unit = aComponent.m_unit;
@ -471,6 +468,7 @@ void SCH_COMPONENT::UpdatePinCache()
if( PART_SPTR part = m_part.lock() )
{
m_Pins.clear();
for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
{
wxASSERT( pin->Type() == LIB_PIN_T );
@ -534,6 +532,54 @@ void SCH_COMPONENT::UpdateAllPinCaches( const SCH_COLLECTOR& aComponents )
}
void SCH_COMPONENT::UpdatePinConnections( SCH_SHEET_PATH aSheet )
{
if( PART_SPTR part = m_part.lock() )
{
for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
{
wxASSERT( pin->Type() == LIB_PIN_T );
if( pin->GetUnit() && m_unit && ( m_unit != pin->GetUnit() ) )
continue;
if( pin->GetConvert() && m_convert && ( m_convert != pin->GetConvert() ) )
continue;
SCH_PIN_CONNECTION* connection = nullptr;
try
{
connection = m_pin_connections.at( pin );
}
catch( const std::out_of_range& oor )
{
connection = new SCH_PIN_CONNECTION();
m_pin_connections[ pin ] = connection;
}
connection->m_pin = pin;
connection->m_comp = this;
connection->InitializeConnection( aSheet );
}
}
}
SCH_PIN_CONNECTION* SCH_COMPONENT::GetConnectionForPin( LIB_PIN* aPin )
{
try
{
return m_pin_connections.at( aPin );
}
catch( const std::out_of_range& oor )
{
return nullptr;
}
}
void SCH_COMPONENT::SetUnit( int aUnit )
{
if( m_unit != aUnit )
@ -1436,9 +1482,9 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList
if( !alias )
return;
if( m_currentSheetPath )
if( g_CurrentSheet )
aList.push_back( MSG_PANEL_ITEM( _( "Reference" ),
GetRef( m_currentSheetPath ),
GetRef( g_CurrentSheet ),
DARKCYAN ) );
msg = part->IsPower() ? _( "Power symbol" ) : _( "Value" );
@ -1476,8 +1522,8 @@ void SCH_COMPONENT::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList
}
else
{
if( m_currentSheetPath )
aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), GetRef( m_currentSheetPath ),
if( g_CurrentSheet )
aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), GetRef( g_CurrentSheet ),
DARKCYAN ) );
aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetField( VALUE )->GetShownText(),

View File

@ -40,6 +40,7 @@
#include <vector>
#include <set>
#include <lib_draw_item.h>
#include <sch_pin_connection.h>
class SCH_SCREEN;
class SCH_SHEET_PATH;
@ -71,6 +72,7 @@ class SCH_COMPONENT : public SCH_ITEM
{
public:
enum AUTOPLACED { AUTOPLACED_NO = 0, AUTOPLACED_AUTO, AUTOPLACED_MANUAL };
private:
wxPoint m_Pos;
@ -97,14 +99,6 @@ private:
AUTOPLACED m_fieldsAutoplaced; ///< indicates status of field autoplacement
/**
* A temporary sheet path is required to generate the correct reference designator string
* in complex hierarchies. Hopefully this is only a temporary hack to decouple schematic
* objects from the drawing window until a better design for handling complex hierarchies
* can be implemented.
*/
const SCH_SHEET_PATH* m_currentSheetPath;
/**
* Defines the hierarchical path and reference of the component. This allows support
* for hierarchical sheets that reference the same schematic. The format for the path
@ -113,6 +107,8 @@ private:
*/
wxArrayString m_PathsAndReferences;
std::unordered_map<LIB_PIN*, SCH_PIN_CONNECTION*> m_pin_connections;
void Init( const wxPoint& pos = wxPoint( 0, 0 ) );
public:
@ -219,6 +215,21 @@ public:
*/
static void UpdateAllPinCaches( const SCH_COLLECTOR& aComponents );
/**
* Updates the local cache of SCH_PIN_CONNECTION objects for each pin
*/
void UpdatePinConnections( SCH_SHEET_PATH aSheet );
/**
* Retrieves the pin connection for a given pin of the component
*/
SCH_PIN_CONNECTION* GetConnectionForPin( LIB_PIN* aPin );
const std::unordered_map<LIB_PIN*, SCH_PIN_CONNECTION*>& PinConnections()
{
return m_pin_connections;
}
/**
* Change the unit number to \a aUnit
*
@ -513,11 +524,6 @@ public:
*/
static bool IsReferenceStringValid( const wxString& aReferenceString );
void SetCurrentSheetPath( const SCH_SHEET_PATH* aSheetPath )
{
m_currentSheetPath = aSheetPath;
}
/**
* Return the reference for the given sheet path.
*
@ -666,5 +672,4 @@ private:
bool doIsConnected( const wxPoint& aPosition ) const override;
};
#endif /* COMPONENT_CLASS_H */

469
eeschema/sch_connection.cpp Normal file
View File

@ -0,0 +1,469 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <boost/regex.hpp>
#include <wx/tokenzr.h>
#include <connection_graph.h>
#include <sch_pin_connection.h>
#include <sch_screen.h>
#include <sch_connection.h>
/**
*
* Buses can be defined in multiple ways. A bus vector consists of a prefix and
* a numeric range of suffixes:
*
* BUS_NAME[M..N]
*
* For example, the bus A[3..0] will contain nets A3, A2, A1, and A0.
* The BUS_NAME is required. M and N must be integers but do not need to be in
* any particular order -- A[0..3] produces the same result.
*
* Like net names, bus names cannot contain whitespace.
*
* A bus group is just a grouping of signals, separated by spaces, some
* of which may be bus vectors. Bus groups can have names, but do not need to.
*
* MEMORY{A[15..0] D[7..0] RW CE OE}
*
* In named bus groups, the net names are expanded as <BUS_NAME>.<NET_NAME>
* In the above example, the nets would be named like MEMORY.A15, MEMORY.D0, etc.
*
* {USB_DP USB_DN}
*
* In the above example, the bus is unnamed and so the underlying net names are
* just USB_DP and USB_DN.
*
*/
static boost::regex bus_label_re( "^([^[:space:]]+)(\\[[\\d]+\\.+[\\d]+\\])$" );
static boost::regex bus_group_label_re( "^([^[:space:]]+)?\\{((?:[^[:space:]]+(?:\\[[\\d]+\\.+[\\d]+\\])? ?)+)\\}$" );
SCH_CONNECTION::SCH_CONNECTION( SCH_ITEM* aParent, SCH_SHEET_PATH aPath ) :
m_sheet( aPath ),
m_parent( aParent )
{
Reset();
}
bool SCH_CONNECTION::operator==( const SCH_CONNECTION& aOther ) const
{
// NOTE: Not comparing m_dirty or net/bus/subgraph codes
if( ( aOther.m_driver == m_driver ) &&
( aOther.m_type == m_type ) &&
( aOther.m_name == m_name ) &&
( aOther.m_sheet == m_sheet ) )
{
return true;
}
return false;
}
void SCH_CONNECTION::SetDriver( SCH_ITEM* aItem )
{
m_driver = aItem;
for( auto member : m_members )
member->SetDriver( aItem );
}
void SCH_CONNECTION::SetSheet( SCH_SHEET_PATH aSheet )
{
m_sheet = aSheet;
for( auto member : m_members )
member->SetSheet( aSheet );
}
bool SCH_CONNECTION::operator!=( const SCH_CONNECTION& aOther ) const
{
return !( aOther == *this );
}
void SCH_CONNECTION::ConfigureFromLabel( wxString aLabel )
{
if( IsBusVectorLabel( aLabel ) )
{
m_name = aLabel;
m_type = CONNECTION_BUS;
ParseBusVector( aLabel, &m_vector_prefix, &m_vector_start, &m_vector_end );
for( long i = m_vector_start; i <= m_vector_end; ++i )
{
auto member = std::make_shared< SCH_CONNECTION >( m_parent, m_sheet );
wxString name = m_vector_prefix;
name << i;
member->m_type = CONNECTION_NET;
member->m_name = m_prefix + name;
member->m_vector_index = i;
m_members.push_back( member );
}
}
else if( IsBusGroupLabel( aLabel ) )
{
m_type = CONNECTION_BUS_GROUP;
m_name = aLabel;
std::vector<wxString> members;
wxString group_name;
if( ParseBusGroup( aLabel, &group_name, members ) )
{
// Named bus groups generate a net prefix, unnamed ones don't
auto prefix = ( group_name != "" ) ? ( group_name + "." ) : "";
for( auto group_member : members )
{
// Handle alias inside bus group member list
if( auto alias = g_ConnectionGraph->GetBusAlias( group_member ) )
{
for( auto alias_member : alias->Members() )
{
auto member = std::make_shared< SCH_CONNECTION >( m_parent, m_sheet );
member->SetPrefix( prefix );
member->ConfigureFromLabel( alias_member );
m_members.push_back( member );
}
}
else
{
auto member = std::make_shared< SCH_CONNECTION >( m_parent, m_sheet );
member->SetPrefix( prefix );
member->ConfigureFromLabel( group_member );
m_members.push_back( member );
}
}
}
}
else if( auto alias = g_ConnectionGraph->GetBusAlias( aLabel ) )
{
m_type = CONNECTION_BUS_GROUP;
m_name = aLabel;
for( auto alias_member : alias->Members() )
{
auto member = std::make_shared< SCH_CONNECTION >( m_parent );
member->ConfigureFromLabel( alias_member );
m_members.push_back( member );
}
}
else
{
m_name = m_prefix + aLabel;
m_type = CONNECTION_NET;
}
}
void SCH_CONNECTION::Reset()
{
m_type = CONNECTION_NONE;
m_name = "<NO NET>";
m_prefix = "";
m_driver = nullptr;
m_members.clear();
m_dirty = true;
m_net_code = 0;
m_bus_code = 0;
m_subgraph_code = 0;
m_vector_start = 0;
m_vector_end = 0;
m_vector_index = 0;
m_vector_prefix = "";
}
void SCH_CONNECTION::Clone( SCH_CONNECTION& aOther )
{
m_type = aOther.Type();
m_driver = aOther.Driver();
m_sheet = aOther.Sheet();
m_name = aOther.Name( true );
m_prefix = aOther.Prefix();
m_members = aOther.Members();
m_net_code = aOther.NetCode();
m_bus_code = aOther.BusCode();
//m_subgraph_code = aOther.SubgraphCode();
m_vector_start = aOther.VectorStart();
m_vector_end = aOther.VectorEnd();
m_vector_index = aOther.VectorIndex();
m_vector_prefix = aOther.VectorPrefix();
}
bool SCH_CONNECTION::IsDriver() const
{
wxASSERT( Parent() );
switch( Parent()->Type() )
{
case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T:
case SCH_HIERARCHICAL_LABEL_T:
case SCH_PIN_CONNECTION_T:
case SCH_SHEET_PIN_T:
case SCH_SHEET_T:
case LIB_PIN_T:
return true;
default:
return false;
}
}
wxString SCH_CONNECTION::Name( bool aIgnoreSheet ) const
{
wxString ret = m_name;
if( !Parent() || m_type == CONNECTION_NONE )
return ret;
bool prepend_path = true;
switch( Parent()->Type() )
{
case SCH_PIN_CONNECTION_T:
// Pins are either power connections or belong to a uniquely-annotated
// component, so they don't need a path
prepend_path = false;
break;
case SCH_GLOBAL_LABEL_T:
prepend_path = false;
break;
default:
break;
}
if( prepend_path && !aIgnoreSheet )
ret = m_sheet.PathHumanReadable() + ret;
return ret;
}
void SCH_CONNECTION::AppendInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const
{
wxString msg, group_name;
std::vector<wxString> group_members;
aList.push_back( MSG_PANEL_ITEM( _( "Connection Name" ), m_name, BROWN ) );
msg.Printf( "%d", m_net_code );
aList.push_back( MSG_PANEL_ITEM( _( "Net Code" ), msg, BROWN ) );
if( auto alias = g_ConnectionGraph->GetBusAlias( m_name ) )
{
msg.Printf( _( "Bus Alias %s Members" ), m_name );
wxString members;
for( auto member : alias->Members() )
members << member << " ";
aList.push_back( MSG_PANEL_ITEM( msg, members, RED ) );
}
else if( ParseBusGroup( m_name, &group_name, group_members ) )
{
for( auto group_member : group_members )
{
if( auto group_alias = g_ConnectionGraph->GetBusAlias( group_member ) )
{
msg.Printf( _( "Bus Alias %s Members" ), group_alias->GetName() );
wxString members;
for( auto member : group_alias->Members() )
members << member << " ";
aList.push_back( MSG_PANEL_ITEM( msg, members, RED ) );
}
}
}
}
void SCH_CONNECTION::AppendDebugInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const
{
wxString msg;
AppendInfoToMsgPanel( aList );
msg.Printf( "%d", m_bus_code );
aList.push_back( MSG_PANEL_ITEM( _( "Bus Code" ), msg, BROWN ) );
msg.Printf( "%d", m_subgraph_code );
aList.push_back( MSG_PANEL_ITEM( _( "Subgraph Code" ), msg, BROWN ) );
if( auto driver = Driver() )
{
msg.Printf( "%s at %p", driver->GetSelectMenuText( MILLIMETRES ), driver );
aList.push_back( MSG_PANEL_ITEM( _( "Connection Source" ), msg, RED ) );
}
msg.Printf( "%s at %p", Parent()->GetSelectMenuText( MILLIMETRES ), Parent() );
aList.push_back( MSG_PANEL_ITEM( _( "Attached To" ), msg, RED ) );
}
bool SCH_CONNECTION::IsBusLabel( const wxString& aLabel )
{
return IsBusVectorLabel( aLabel ) || IsBusGroupLabel( aLabel );
}
bool SCH_CONNECTION::IsBusVectorLabel( const wxString& aLabel )
{
return boost::regex_match( std::string( aLabel.mb_str() ), bus_label_re );
}
bool SCH_CONNECTION::IsBusGroupLabel( const wxString& aLabel )
{
return boost::regex_match( std::string( aLabel.mb_str() ), bus_group_label_re );
}
void SCH_CONNECTION::ParseBusVector( wxString aVector, wxString* aName,
long* begin, long* end ) const
{
auto ss_vector = std::string( aVector.mb_str() );
boost::smatch matches;
if( !boost::regex_match( ss_vector, matches, bus_label_re ) )
{
wxFAIL_MSG( wxT( "<" ) + aVector + wxT( "> is not a valid bus vector." ) );
return;
}
*aName = wxString( matches[1] );
wxString numberString( matches[2] );
// numberString will include the brackets, e.g. [5..0] so skip the first one
size_t i = 1, len = numberString.Len();
wxString tmp;
while( i < len && numberString[i] != '.' )
{
tmp.Append( numberString[i] );
i++;
}
tmp.ToLong( begin );
while( i < len && numberString[i] == '.' )
i++;
tmp.Empty();
while( i < len && numberString[i] != ']' )
{
tmp.Append( numberString[i] );
i++;
}
tmp.ToLong( end );
if( *begin < 0 )
*begin = 0;
if( *end < 0 )
*end = 0;
if( *begin > *end )
std::swap( *begin, *end );
}
bool SCH_CONNECTION::ParseBusGroup( wxString aGroup, wxString* aName,
std::vector<wxString>& aMemberList ) const
{
auto ss_group = std::string( aGroup.mb_str() );
boost::smatch matches;
if( !boost::regex_match( ss_group, matches, bus_group_label_re ) )
{
return false;
}
*aName = wxString( matches[1] );
wxStringTokenizer tokenizer( wxString( matches[2] ), " " );
while( tokenizer.HasMoreTokens() )
{
aMemberList.push_back( tokenizer.GetNextToken() );
}
return true;
}
bool SCH_CONNECTION::IsSubsetOf( SCH_CONNECTION* aOther ) const
{
if( aOther->IsNet() )
return IsNet() ? ( aOther->Name( true ) == Name( true ) ) : false;
if( !IsBus() )
return false;
std::vector<wxString> mine, theirs;
for( auto m : Members() )
mine.push_back( m->Name( true ) );
for( auto m : aOther->Members() )
theirs.push_back( m->Name( true ) );
std::set<wxString> subset;
std::set_intersection( mine.begin(), mine.end(),
theirs.begin(), theirs.end(),
std::inserter(subset, subset.begin() ) );
return ( !subset.empty() );
}
bool SCH_CONNECTION::IsMemberOfBus( SCH_CONNECTION* aOther ) const
{
if( !aOther->IsBus() )
return false;
auto me = Name( true );
for( auto m : aOther->Members() )
if( m->Name( true ) == me )
return true;
return false;
}

347
eeschema/sch_connection.h Normal file
View File

@ -0,0 +1,347 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SCH_CONNECTION_H
#define _SCH_CONNECTION_H
#include <memory>
#include <unordered_set>
#include <boost/optional.hpp>
#include <wx/regex.h>
#include <bus_alias.h>
#include <msgpanel.h>
#include <sch_sheet_path.h>
class SCH_ITEM;
class SCH_SHEET_PATH;
enum CONNECTION_TYPE
{
CONNECTION_NONE, ///< No connection to this item
CONNECTION_NET, ///< This item represents a net
CONNECTION_BUS, ///< This item represents a bus vector
CONNECTION_BUS_GROUP, ///< This item represents a bus group
};
/**
* Each graphical item can have a SCH_CONNECTION describing its logical
* connection (to a bus or net). These are generated when netlisting, or when
* editing operations that can change the netlist are performed.
*
* In hierarchical schematics, a single SCH_ITEM object can refer to multiple
* distinct parts of a design (in the case of a sub-sheet that is instanced
* more than once in a higher level sheet). Because of this, a single item may
* contain more than one SCH_CONNECTION -- each is specific to a sheet.
*
* Components contain connections for each of their pins (and for each sheet
* they exist on) but don't use their own connection object.
*/
class SCH_CONNECTION
{
public:
SCH_CONNECTION( SCH_ITEM* aParent = nullptr, SCH_SHEET_PATH aPath = SCH_SHEET_PATH() );
~SCH_CONNECTION()
{}
/**
* Note: the equality operator for SCH_CONNECTION only tests the net
* properties, not the ownership / sheet location!
*/
bool operator==( const SCH_CONNECTION& aOther ) const;
bool operator!=( const SCH_CONNECTION& aOther ) const;
/**
* Configures the connection given a label.
* For CONNECTION_NET, this just sets the name.
* For CONNECTION_BUS, this will deduce the correct BUS_TYPE and also
* generate a correct list of members.
*/
void ConfigureFromLabel( wxString aLabel );
/**
* Clears connectivity information
*/
void Reset();
/**
* Copies connectivity information (but not parent) from another connection
*
* @param aOther is the connection to clone
*/
void Clone( SCH_CONNECTION& aOther );
SCH_ITEM* Parent() const
{
return m_parent;
}
SCH_ITEM* Driver() const
{
return m_driver;
}
SCH_SHEET_PATH Sheet() const
{
return m_sheet;
}
void SetDriver( SCH_ITEM* aItem );
void SetSheet( SCH_SHEET_PATH aSheet );
/**
* Checks if the SCH_ITEM this connection is attached to can drive connections
* Drivers can be labels, sheet pins, or component pins.
*
* @return true if the attached items is a driver
*/
bool IsDriver() const;
bool IsBus() const
{
return ( m_type == CONNECTION_BUS || m_type == CONNECTION_BUS_GROUP );
}
bool IsNet() const
{
return ( m_type == CONNECTION_NET );
}
bool IsDirty() const
{
return m_dirty;
}
void SetDirty()
{
m_dirty = true;
}
void ClearDirty()
{
m_dirty = false;
}
wxString Name( bool aIgnoreSheet = false ) const;
wxString Prefix() const
{
return m_prefix;
}
void SetPrefix( wxString aPrefix )
{
m_prefix = aPrefix;
}
CONNECTION_TYPE Type() const
{
return m_type;
}
void SetType( CONNECTION_TYPE aType )
{
m_type = aType;
}
int NetCode() const
{
return m_net_code;
}
void SetNetCode( int aCode )
{
m_net_code = aCode;
}
int BusCode() const
{
return m_bus_code;
}
void SetBusCode( int aCode )
{
m_bus_code = aCode;
}
int SubgraphCode() const
{
return m_subgraph_code;
}
void SetSubgraphCode( int aCode )
{
m_subgraph_code = aCode;
}
long VectorStart() const
{
return m_vector_start;
}
long VectorEnd() const
{
return m_vector_end;
}
long VectorIndex() const
{
return m_vector_index;
}
wxString VectorPrefix() const
{
return m_vector_prefix;
}
std::vector< std::shared_ptr< SCH_CONNECTION > >& Members()
{
return m_members;
}
const std::vector< std::shared_ptr< SCH_CONNECTION > >& Members() const
{
return m_members;
}
/**
* Returns true if aOther is a subset of this connection or vice versa.
*
* For plain nets, this just tests whether or not the connectio names are
* the same. For buses, this tests whether the two have any shared members.
*
* Will always return false if one connection is a bus and the other a net.
*/
bool IsSubsetOf( SCH_CONNECTION* aOther ) const;
/**
* Returns true if this connection is a member of bus connection aOther
*
* Will always return false if aOther is not a bus connection
*/
bool IsMemberOfBus( SCH_CONNECTION* aOther ) const;
/**
* Parses a bus vector (e.g. A[7..0]) into name, begin, and end.
* Ensures that begin and end are positive and that end > begin.
*
* @param vector is a bus vector label string
* @param name output of the name portion of the label
* @param begin is the first entry in the vector
* @param end is the last entry in the vector
*/
void ParseBusVector( wxString vector, wxString* name,
long* begin, long* end ) const;
/**
* Parses a bus group label into the name and a list of components
*
* @param aGroup is the input label, e.g. "USB{DP DM}"
* @param name is the output group name, e.g. "USB"
* @param aMemberList is a list of member strings, e.g. "DP", "DM"
* @return true if aGroup was successfully parsed
*/
bool ParseBusGroup( wxString aGroup, wxString* name,
std::vector<wxString>& aMemberList ) const;
/**
* Adds information about the connection object to aList
*/
void AppendInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const;
/**
* Adds extended debug information about the connection object to aList
*/
void AppendDebugInfoToMsgPanel( MSG_PANEL_ITEMS& aList ) const;
/**
* Test if \a aLabel has a bus notation.
*
* @param aLabel A wxString object containing the label to test.
* @return true if text is a bus notation format otherwise false is returned.
*/
bool IsBusLabel( const wxString& aLabel );
/**
* Test if \a aLabel has a bus vector notation (simple bus, e.g. A[7..0])
*
* @param aLabel A wxString object containing the label to test.
* @return true if text is a bus notation format otherwise false is returned.
*/
bool IsBusVectorLabel( const wxString& aLabel );
/**
* Test if \a aLabel has a bus group notation.
*
* @param aLabel A wxString object containing the label to test.
* @return true if text is a bus group notation format
*/
bool IsBusGroupLabel( const wxString& aLabel );
private:
bool m_dirty;
SCH_SHEET_PATH m_sheet; ///< The hierarchical sheet this connection is on
SCH_ITEM* m_parent; ///< The SCH_ITEM this connection is owned by
SCH_ITEM* m_driver; ///< The SCH_ITEM that drives this connection's net
CONNECTION_TYPE m_type; ///< @see enum CONNECTION_TYPE
wxString m_name; ///< Name of the bus.
///< Prefix if connection is member of a labeled bus group (or "" if not)
wxString m_prefix;
int m_net_code; // TODO(JE) remove if unused
int m_bus_code; // TODO(JE) remove if unused
int m_subgraph_code; ///< Groups directly-connected items
long m_vector_index; ///< Index of bus vector member nets
long m_vector_start; ///< Highest member of a vector bus
long m_vector_end; ///< Lowest member of a vector bus
///< Prefix name of the vector, if m_type == CONNECTION_BUS (or "" if not)
wxString m_vector_prefix;
/**
* For bus connections, store a list of member connections
*
* NOTE: All connections that Clone() others share the list of member
* pointers. This seems fine at the moment.
*/
std::vector< std::shared_ptr< SCH_CONNECTION > > m_members;
};
#endif

View File

@ -69,6 +69,7 @@
#include <wildcards_and_files_ext.h>
#include <netlist_exporter_kicad.h>
#include <connection_graph.h>
#include <kiway.h>
#include <dialogs/dialog_fields_editor_global.h>
@ -77,6 +78,9 @@
#include <gal/graphics_abstraction_layer.h>
SCH_SHEET_PATH* g_CurrentSheet = nullptr; // declared in general.h
CONNECTION_GRAPH* g_ConnectionGraph = nullptr;
// non-member so it can be moved easily, and kept REALLY private.
// Do NOT Clear() in here.
static void add_search_paths( SEARCH_STACK* aDst, const SEARCH_STACK& aSrc, int aIndex )
@ -284,6 +288,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_TOOL( ID_UPDATE_PCB_FROM_SCH, SCH_EDIT_FRAME::OnUpdatePCB )
EVT_TOOL( ID_GET_TOOLS, SCH_EDIT_FRAME::OnCreateBillOfMaterials )
EVT_TOOL( ID_OPEN_CMP_TABLE, SCH_EDIT_FRAME::OnLaunchBomManager )
EVT_TOOL( ID_BUS_MANAGER, SCH_EDIT_FRAME::OnLaunchBusManager )
EVT_TOOL( ID_FIND_ITEMS, SCH_EDIT_FRAME::OnFindItems )
EVT_TOOL( wxID_REPLACE, SCH_EDIT_FRAME::OnFindItems )
EVT_TOOL( ID_BACKANNO_ITEMS, SCH_EDIT_FRAME::OnLoadCmpToFootprintLinkFile )
@ -321,6 +326,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_MENU_RANGE( ID_SCH_MIRROR_X, ID_SCH_ORIENT_NORMAL, SCH_EDIT_FRAME::OnOrient )
EVT_MENU_RANGE( ID_POPUP_START_RANGE, ID_POPUP_END_RANGE,
SCH_EDIT_FRAME::Process_Special_Functions )
EVT_MENU( ID_SCH_UNFOLD_BUS, SCH_EDIT_FRAME::OnUnfoldBusHotkey )
EVT_MENU( ID_POPUP_SCH_DISPLAYDOC_CMP, SCH_EDIT_FRAME::OnEditItem )
EVT_MENU( ID_MENU_CANVAS_CAIRO, SCH_EDIT_FRAME::OnSwitchCanvas )
@ -371,9 +377,11 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ):
wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, SCH_EDIT_FRAME_NAME ),
m_item_to_repeat( 0 )
{
g_CurrentSheet = new SCH_SHEET_PATH();
g_ConnectionGraph = new CONNECTION_GRAPH( this );
m_showAxis = false; // true to show axis
m_showBorderAndTitleBlock = true; // true to show sheet references
m_CurrentSheet = new SCH_SHEET_PATH;
m_DefaultSchematicFileName = NAMELESS_PROJECT;
m_DefaultSchematicFileName += wxT( ".sch" );
m_showAllPins = false;
@ -386,6 +394,7 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ):
m_findReplaceStatus = new wxString( wxEmptyString );
m_undoItem = NULL;
m_hasAutoSave = true;
m_busUnfold = {};
m_FrameSize = ConvertDialogToPixels( wxSize( 500, 350 ) ); // default in case of no prefs
m_toolManager = new TOOL_MANAGER;
@ -458,12 +467,15 @@ SCH_EDIT_FRAME::~SCH_EDIT_FRAME()
SetScreen( NULL );
delete m_CurrentSheet; // a SCH_SHEET_PATH, on the heap.
delete g_CurrentSheet; // a SCH_SHEET_PATH, on the heap.
delete g_ConnectionGraph;
delete m_undoItem;
delete m_findReplaceData;
delete m_findReplaceStatus;
delete g_RootSheet;
g_CurrentSheet = nullptr;
g_ConnectionGraph = nullptr;
g_RootSheet = NULL;
}
@ -503,7 +515,7 @@ void SCH_EDIT_FRAME::SetSheetNumberAndCount()
*/
int sheet_count = g_RootSheet->CountSheets();
int SheetNumber = 1;
wxString current_sheetpath = m_CurrentSheet->Path();
wxString current_sheetpath = g_CurrentSheet->Path();
SCH_SHEET_LIST sheetList( g_RootSheet );
// Examine all sheets path to find the current sheets path,
@ -520,7 +532,7 @@ void SCH_EDIT_FRAME::SetSheetNumberAndCount()
* path */
}
m_CurrentSheet->SetPageNumber( SheetNumber );
g_CurrentSheet->SetPageNumber( SheetNumber );
for( screen = s_list.GetFirst(); screen != NULL; screen = s_list.GetNext() )
{
@ -533,13 +545,13 @@ void SCH_EDIT_FRAME::SetSheetNumberAndCount()
SCH_SCREEN* SCH_EDIT_FRAME::GetScreen() const
{
return m_CurrentSheet->LastScreen();
return g_CurrentSheet->LastScreen();
}
wxString SCH_EDIT_FRAME::GetScreenDesc() const
{
wxString s = m_CurrentSheet->PathHumanReadable();
wxString s = g_CurrentSheet->PathHumanReadable();
return s;
}
@ -562,8 +574,9 @@ void SCH_EDIT_FRAME::CreateScreens()
g_RootSheet->GetScreen()->SetFileName( m_DefaultSchematicFileName );
m_CurrentSheet->clear();
m_CurrentSheet->push_back( g_RootSheet );
g_CurrentSheet->clear();
g_CurrentSheet->push_back( g_RootSheet );
g_ConnectionGraph->Reset();
if( GetScreen() == NULL )
{
@ -578,26 +591,26 @@ void SCH_EDIT_FRAME::CreateScreens()
SCH_SHEET_PATH& SCH_EDIT_FRAME::GetCurrentSheet()
{
wxASSERT_MSG( m_CurrentSheet != NULL, wxT( "SCH_EDIT_FRAME m_CurrentSheet member is NULL." ) );
wxASSERT_MSG( g_CurrentSheet != NULL, wxT( "SCH_EDIT_FRAME g_CurrentSheet member is NULL." ) );
return *m_CurrentSheet;
return *g_CurrentSheet;
}
void SCH_EDIT_FRAME::SetCurrentSheet( const SCH_SHEET_PATH& aSheet )
{
if( aSheet != *m_CurrentSheet )
if( aSheet != *g_CurrentSheet )
{
*m_CurrentSheet = aSheet;
*g_CurrentSheet = aSheet;
static_cast<SCH_DRAW_PANEL*>( m_canvas )->DisplaySheet( m_CurrentSheet->LastScreen() );
static_cast<SCH_DRAW_PANEL*>( m_canvas )->DisplaySheet( g_CurrentSheet->LastScreen() );
}
}
void SCH_EDIT_FRAME::HardRedraw()
{
static_cast<SCH_DRAW_PANEL*>( m_canvas )->DisplaySheet( m_CurrentSheet->LastScreen() );
static_cast<SCH_DRAW_PANEL*>( m_canvas )->DisplaySheet( g_CurrentSheet->LastScreen() );
GetCanvas()->Refresh();
}
@ -709,7 +722,7 @@ void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
g_RootSheet->GetScreen()->Clear();
// all sub sheets are deleted, only the main sheet is usable
m_CurrentSheet->clear();
g_CurrentSheet->clear();
Destroy();
}
@ -739,7 +752,7 @@ wxString SCH_EDIT_FRAME::GetUniqueFilenameForCurrentSheet()
#define FN_LEN_MAX 80 // A reasonable value for the short filename len
wxString filename = fn.GetName();
wxString sheetFullName = m_CurrentSheet->PathHumanReadable();
wxString sheetFullName = g_CurrentSheet->PathHumanReadable();
// Remove the last '/' of the path human readable
// (and for the root sheet, make sheetFullName empty):
@ -767,6 +780,9 @@ void SCH_EDIT_FRAME::OnModify()
m_foundItems.SetForceSearch();
//RecalculateConnections( SCH_SHEET_LIST( g_CurrentSheet->Last() ) );
RecalculateConnections();
m_canvas->Refresh();
}
@ -824,7 +840,7 @@ void SCH_EDIT_FRAME::OnUpdateSaveSheet( wxUpdateUIEvent& aEvent )
void SCH_EDIT_FRAME::OnUpdateHierarchySheet( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_CurrentSheet->Last() != g_RootSheet );
aEvent.Enable( g_CurrentSheet->Last() != g_RootSheet );
}
@ -910,7 +926,7 @@ void SCH_EDIT_FRAME::doUpdatePcb( const wxString& aUpdateOptions )
}
NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
NETLIST_EXPORTER_KICAD exporter( this, net_atoms );
NETLIST_EXPORTER_KICAD exporter( this, net_atoms, g_ConnectionGraph );
STRING_FORMATTER formatter;
exporter.Format( &formatter, GNL_ALL );
@ -951,6 +967,12 @@ void SCH_EDIT_FRAME::OnLaunchBomManager( wxCommandEvent& event )
}
void SCH_EDIT_FRAME::OnLaunchBusManager( wxCommandEvent& )
{
InvokeDialogBusManager( this );
}
void SCH_EDIT_FRAME::OnFindItems( wxCommandEvent& aEvent )
{
wxCHECK_RET( m_findReplaceData != NULL,
@ -1393,7 +1415,7 @@ void SCH_EDIT_FRAME::addCurrentItemToScreen()
// the m_mouseCaptureCallback function.
m_canvas->SetMouseCapture( NULL, NULL );
if( !EditSheet( (SCH_SHEET*)item, m_CurrentSheet, &doClearAnnotation ) )
if( !EditSheet( (SCH_SHEET*)item, g_CurrentSheet, &doClearAnnotation ) )
{
screen->SetCurItem( NULL );
delete item;
@ -1438,6 +1460,9 @@ void SCH_EDIT_FRAME::addCurrentItemToScreen()
SCH_SCREENS screensList( g_RootSheet );
screensList.ClearAnnotationOfNewSheetPaths( initial_sheetpathList );
}
// Update connectivity info for new item
RecalculateConnections();
}
else
{
@ -1488,7 +1513,7 @@ void SCH_EDIT_FRAME::UpdateTitle()
wxFileName fn = fileName;
title.Printf( _( "Eeschema" ) + wxT( " \u2014 %s [%s] \u2014 %s" ),
fn.GetFullName(), m_CurrentSheet->PathHumanReadable(),
fn.GetFullName(), g_CurrentSheet->PathHumanReadable(),
fn.GetPath() );
if( fn.FileExists() )
@ -1504,6 +1529,18 @@ void SCH_EDIT_FRAME::UpdateTitle()
}
void SCH_EDIT_FRAME::RecalculateConnections()
{
SCH_SHEET_LIST list( g_RootSheet );
// Ensure schematic graph is accurate
for( const auto& sheet : list )
SchematicCleanUp( true, sheet.LastScreen() );
g_ConnectionGraph->Recalculate( list );
}
void SCH_EDIT_FRAME::CommonSettingsChanged()
{
SCH_BASE_FRAME::CommonSettingsChanged();

View File

@ -36,6 +36,7 @@
#include <template_fieldnames.h>
#include <block_commande.h>
#include <sch_collectors.h>
#include <erc_settings.h>
#include <sch_draw_panel.h>
// enum PINSHEETLABEL_SHAPE
@ -66,6 +67,7 @@ class wxFindDialogEvent;
class wxFindReplaceData;
class SCHLIB_FILTER;
class RESCUER;
class CONNECTION_GRAPH;
/// enum used in RotationMiroir()
@ -111,18 +113,36 @@ enum SCH_SEARCH_T {
};
/// Collection of data related to the bus unfolding tool
struct BUS_UNFOLDING_T {
bool in_progress; ///< True if bus unfold operation is running
bool offset; ///< True if the bus entry should be offset from origin
bool label_placed; ///< True if user has placed the net label
wxPoint origin; ///< Origin (on the bus) of the unfold
wxString net_name; ///< Net label for the unfolding operation
SCH_BUS_WIRE_ENTRY* entry;
SCH_LABEL* label;
};
/**
* Schematic editor (Eeschema) main window.
*/
class SCH_EDIT_FRAME : public SCH_BASE_FRAME
{
private:
SCH_SHEET_PATH* m_CurrentSheet; ///< which sheet we are presently working on.
wxString m_DefaultSchematicFileName;
wxString m_SelectedNetName;
PARAM_CFG_ARRAY m_projectFileParams;
PARAM_CFG_ARRAY m_configSettings;
ERC_SETTINGS m_ercSettings;
wxPageSetupDialogData m_pageSetupData;
wxFindReplaceData* m_findReplaceData;
wxString* m_findReplaceStatus;
@ -166,6 +186,18 @@ private:
/// Use netcodes (net number) as net names when generating spice net lists.
bool m_spiceAjustPassiveValues;
public: // TODO(JE) Make private
/// Data related to bus unfolding tool
BUS_UNFOLDING_T m_busUnfold;
private:
/* these are PROJECT specific, not schematic editor specific
wxString m_userLibraryPath;
wxArrayString m_componentLibFiles;
*/
static PINSHEETLABEL_SHAPE m_lastSheetPinType; ///< Last sheet pin type.
static wxSize m_lastSheetPinTextSize; ///< Last sheet pin text size.
static wxPoint m_lastSheetPinPosition; ///< Last sheet pin position.
@ -251,6 +283,13 @@ public:
void Process_Config( wxCommandEvent& event );
void OnSelectTool( wxCommandEvent& aEvent );
/**
* Processes an "Unfold Bus" command from the right-click menu.
* Depending on what the user clicked, this can result in the creation
* of one or more new objects.
*/
void OnUnfoldBus( wxCommandEvent& event );
bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey ) override;
/**
@ -277,6 +316,10 @@ public:
*/
bool LoadProjectFile();
const ERC_SETTINGS& GetErcSettings() { return m_ercSettings; }
void UpdateErcSettings( const ERC_SETTINGS& aSettings ) { m_ercSettings = aSettings; }
/**
* Return a default symbol field name for field \a aFieldNdx for all components.
*
@ -447,10 +490,12 @@ public:
* @param aPoint Point at which to break the segment
* @param aAppend Add the changes to the previous undo state
* @param aNewSegment Pointer to the newly created segment (if given and created)
* @param aScreen is the screen to examine, or nullptr to examine the current screen
* @return True if any wires or buses were broken.
*/
bool BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend = false,
SCH_LINE** aNewSegment = NULL );
bool BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint,
bool aAppend = false, SCH_LINE** aNewSegment = NULL,
SCH_SCREEN* aScreen = nullptr );
/**
* Checks every wire and bus for a intersection at \a aPoint and break into two segments
@ -458,18 +503,22 @@ public:
*
* @param aPoint Test this point for an intersection.
* @param aAppend Add the changes to the previous undo state
* @param aScreen is the screen to examine, or nullptr to examine the current screen
* @return True if any wires or buses were broken.
*/
bool BreakSegments( const wxPoint& aPoint, bool aAppend = false );
bool BreakSegments( const wxPoint& aPoint, bool aAppend = false,
SCH_SCREEN* aScreen = nullptr );
/**
* Tests all junctions and bus entries in the schematic for intersections with wires and
* buses and breaks any intersections into multiple segments.
*
* @param aAppend Add the changes to the previous undo state
* @param aScreen is the screen to examine, or nullptr to examine the current screen
* @return True if any wires or buses were broken.
*/
bool BreakSegmentsOnJunctions( bool aApped = false );
bool BreakSegmentsOnJunctions( bool aApped = false,
SCH_SCREEN* aScreen = nullptr );
/**
* Test all of the connectable objects in the schematic for unused connection points.
@ -795,6 +844,27 @@ public:
*/
bool AskToSaveChanges();
/**
* Checks if a bus unfolding operation is in progress, so that it can be
* properly canceled / commited along with the wire draw operation.
*/
bool IsBusUnfoldInProgress()
{
return m_busUnfold.in_progress;
}
/**
* Cancels a bus unfolding operation, cleaning up the bus entry and label
* that were created
*/
void CancelBusUnfold();
/**
* Completes a bus unfolding operation after the user finishes drawing the
* unfolded wire
*/
void FinishBusUnfold();
private:
/**
@ -835,6 +905,11 @@ private:
*/
void OnOrient( wxCommandEvent& aEvent );
/**
* Handles the keyboard hotkey for unfolding a bus
*/
void OnUnfoldBusHotkey( wxCommandEvent& event );
void OnExit( wxCommandEvent& event );
void OnAnnotate( wxCommandEvent& event );
void OnErc( wxCommandEvent& event );
@ -843,6 +918,7 @@ private:
void OnSimulate( wxCommandEvent& event );
void OnCreateBillOfMaterials( wxCommandEvent& event );
void OnLaunchBomManager( wxCommandEvent& event );
void OnLaunchBusManager( wxCommandEvent& event );
void OnFindItems( wxCommandEvent& event );
void OnFindDialogClose( wxFindDialogEvent& event );
void OnFindDrcMarker( wxFindDialogEvent& event );
@ -952,9 +1028,10 @@ private:
* deleting identical objects superimposed on top of each other.
*
* @param aAppend The changes to the schematic should be appended to the previous undo
* @param aScreen is the screen to examine, or nullptr to examine the current screen
* @return True if any schematic clean up was performed.
*/
bool SchematicCleanUp( bool aAppend = false );
bool SchematicCleanUp( bool aAppend = false, SCH_SCREEN* aScreen = nullptr );
/**
* If any single wire passes through _both points_, remove the portion between the two points,
@ -1475,6 +1552,11 @@ public:
wxString GetNetListerCommand() const { return m_netListerCommand; }
/**
* Generates the connection data for the entire schematic hierarchy.
*/
void RecalculateConnections();
/**
* Updates netlist and sends it to pcbnew.
* @param aUpdateOptions is a string defining update options:

View File

@ -33,6 +33,7 @@
#include <trace_helpers.h>
#include <sch_item_struct.h>
#include <sch_screen.h>
#include <sch_sheet_path.h>
#include <sch_draw_panel.h>
#include <sch_edit_frame.h>
@ -85,6 +86,49 @@ bool SCH_ITEM::IsConnected( const wxPoint& aPosition ) const
}
SCH_CONNECTION* SCH_ITEM::Connection( const SCH_SHEET_PATH& aSheet ) const
{
SCH_CONNECTION* conn = nullptr;
try
{
conn = m_connection_map.at( aSheet );
}
catch( const std::out_of_range& oor )
{
// TODO(JE) should we just call InitializeConnection here?
}
return conn;
}
std::unordered_set<SCH_ITEM*>& SCH_ITEM::ConnectedItems()
{
return m_connected_items;
}
void SCH_ITEM::AddConnectionTo( SCH_ITEM* aItem )
{
m_connected_items.insert( aItem );
}
void SCH_ITEM::InitializeConnection( const SCH_SHEET_PATH& aSheet )
{
if( Connection( aSheet ) )
{
Connection( aSheet )->Reset();
return;
}
auto connection = new SCH_CONNECTION( this );
connection->SetSheet( aSheet );
m_connection_map.insert( std::make_pair( aSheet, connection ) );
}
void SCH_ITEM::SwapData( SCH_ITEM* aItem )
{
wxFAIL_MSG( wxT( "SwapData() method not implemented for class " ) + GetClass() );

View File

@ -30,12 +30,16 @@
#ifndef SCH_ITEM_STRUCT_H
#define SCH_ITEM_STRUCT_H
#include <unordered_map>
#include <vector>
#include <base_screen.h>
#include <general.h>
#include <sch_connection.h>
#include <sch_sheet_path.h>
class SCH_ITEM;
class SCH_SHEET_PATH;
//class SCH_SHEET_PATH;
class LINE_READER;
class SCH_EDIT_FRAME;
class wxFindReplaceData;
@ -69,7 +73,7 @@ class DANGLING_END_ITEM
{
private:
/// A pointer to the connectable object.
const EDA_ITEM* m_item;
EDA_ITEM* m_item;
/// The position of the connection point.
wxPoint m_pos;
@ -81,7 +85,7 @@ private:
const EDA_ITEM* m_parent;
public:
DANGLING_END_ITEM( DANGLING_END_T aType, const EDA_ITEM* aItem, const wxPoint& aPosition )
DANGLING_END_ITEM( DANGLING_END_T aType, EDA_ITEM* aItem, const wxPoint& aPosition )
{
m_item = aItem;
m_type = aType;
@ -89,7 +93,7 @@ public:
m_parent = aItem;
}
DANGLING_END_ITEM( DANGLING_END_T aType, const EDA_ITEM* aItem,
DANGLING_END_ITEM( DANGLING_END_T aType, EDA_ITEM* aItem,
const wxPoint& aPosition, const EDA_ITEM* aParent )
{
m_item = aItem;
@ -99,7 +103,7 @@ public:
}
wxPoint GetPosition() const { return m_pos; }
const EDA_ITEM* GetItem() const { return m_item; }
EDA_ITEM* GetItem() const { return m_item; }
const EDA_ITEM* GetParent() const { return m_parent; }
DANGLING_END_T GetType() const { return m_type; }
};
@ -114,12 +118,20 @@ public:
*/
class SCH_ITEM : public EDA_ITEM
{
friend class CONNECTION_GRAPH;
protected:
SCH_LAYER_ID m_Layer;
EDA_ITEMS m_connections; ///< List of items connected to this item.
wxPoint m_storedPos; ///< a temporary variable used in some move commands
///> to store a initial pos (of the item or mouse cursor)
/// Stores pointers to other items that are connected to this one (schematic only)
std::unordered_set<SCH_ITEM*> m_connected_items;
/// Stores connectivity information, per sheet
std::unordered_map<SCH_SHEET_PATH, SCH_CONNECTION*> m_connection_map;
public:
SCH_ITEM( EDA_ITEM* aParent, KICAD_T aType );
@ -312,6 +324,33 @@ public:
*/
bool IsConnected( const wxPoint& aPoint ) const;
/**
* Retrieves the connection associated with this object in the given sheet
*/
SCH_CONNECTION* Connection( const SCH_SHEET_PATH& aPath ) const;
/**
* Retrieves the set of items connected to this item (schematic only)
*/
std::unordered_set<SCH_ITEM*>& ConnectedItems();
/**
* Adds a connection link between this item and another
*/
void AddConnectionTo( SCH_ITEM* aItem );
/**
* Creates a new connection object associated with this object
*
* @param aPath is the sheet path to initialize
*/
void InitializeConnection( const SCH_SHEET_PATH& aPath );
/**
* Returns true if this item should propagate connection info to aItem
*/
virtual bool ConnectionPropagatesTo( const EDA_ITEM* aItem ) const { return true; }
virtual bool HitTest( const wxPoint& aPosition ) const override
{
return HitTest( aPosition, 0 );

View File

@ -96,10 +96,14 @@ void SCH_JUNCTION::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffs
{
COLOR4D color;
auto conn = Connection( *g_CurrentSheet );
if( aColor != COLOR4D::UNSPECIFIED )
color = aColor;
else
color = GetLayerColor( GetState( BRIGHTENED ) ? LAYER_BRIGHTENED : m_Layer );
color = GetLayerColor( GetState( BRIGHTENED ) ? LAYER_BRIGHTENED :
( conn && conn->IsBus() ) ?
LAYER_BUS : m_Layer );
GRSetDrawMode( aDC, aDrawMode );

View File

@ -22,6 +22,7 @@
#include <ctype.h>
#include <algorithm>
#include <boost/algorithm/string/join.hpp>
#include <wx/mstream.h>
#include <wx/filename.h>
@ -45,6 +46,8 @@
#include <sch_no_connect.h>
#include <sch_text.h>
#include <sch_sheet.h>
#include <sch_bitmap.h>
#include <bus_alias.h>
#include <sch_legacy_plugin.h>
#include <template_fieldnames.h>
#include <sch_screen.h>
@ -759,6 +762,8 @@ void SCH_LEGACY_PLUGIN::loadFile( const wxString& aFileName, SCH_SCREEN* aScreen
aScreen->Append( loadBusEntry( reader ) );
else if( strCompare( "Text", line ) )
aScreen->Append( loadText( reader ) );
else if( strCompare( "BusAlias", line ) )
aScreen->AddBusAlias( loadBusAlias( reader, aScreen ) );
else if( strCompare( "$EndSCHEMATC", line ) )
return;
}
@ -1718,6 +1723,32 @@ SCH_COMPONENT* SCH_LEGACY_PLUGIN::loadComponent( FILE_LINE_READER& aReader )
}
std::shared_ptr< BUS_ALIAS > SCH_LEGACY_PLUGIN::loadBusAlias( FILE_LINE_READER& aReader,
SCH_SCREEN* aScreen )
{
auto busAlias = std::make_shared< BUS_ALIAS >( aScreen );
const char* line = aReader.Line();
wxCHECK( strCompare( "BusAlias", line, &line ), NULL );
wxString buf;
parseUnquotedString( buf, aReader, line, &line );
busAlias->SetName( buf );
while( *line != '\0' )
{
buf.clear();
parseUnquotedString( buf, aReader, line, &line, true );
if( buf.Len() > 0 )
{
busAlias->AddMember( buf );
}
}
return busAlias;
}
void SCH_LEGACY_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aScreen, KIWAY* aKiway,
const PROPERTIES* aProperties )
{
@ -1782,6 +1813,11 @@ void SCH_LEGACY_PLUGIN::Format( SCH_SCREEN* aScreen )
m_out->Print( 0, "Comment4 %s\n", EscapedUTF8( tb.GetComment4() ).c_str() );
m_out->Print( 0, "$EndDescr\n" );
for( auto alias : aScreen->GetBusAliases() )
{
saveBusAlias( alias );
}
for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
{
switch( item->Type() )
@ -2206,6 +2242,17 @@ void SCH_LEGACY_PLUGIN::saveText( SCH_TEXT* aText )
}
void SCH_LEGACY_PLUGIN::saveBusAlias( std::shared_ptr< BUS_ALIAS > aAlias )
{
wxCHECK_RET( aAlias != NULL, "BUS_ALIAS* is NULL" );
wxString members = boost::algorithm::join( aAlias->Members(), " " );
m_out->Print( 0, "BusAlias %s %s\n",
TO_UTF8( aAlias->GetName() ), TO_UTF8( members ) );
}
int SCH_LEGACY_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up

View File

@ -23,6 +23,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <memory>
#include <sch_io_mgr.h>
#include <stack>
@ -44,6 +45,7 @@ class SCH_LEGACY_PLUGIN_CACHE;
class LIB_PART;
class PART_LIB;
class LIB_ALIAS;
class BUS_ALIAS;
/**
@ -145,6 +147,7 @@ private:
SCH_BUS_ENTRY_BASE* loadBusEntry( FILE_LINE_READER& aReader );
SCH_TEXT* loadText( FILE_LINE_READER& aReader );
SCH_COMPONENT* loadComponent( FILE_LINE_READER& aReader );
std::shared_ptr< BUS_ALIAS > loadBusAlias( FILE_LINE_READER& aReader, SCH_SCREEN* aScreen );
void saveComponent( SCH_COMPONENT* aComponent );
void saveField( SCH_FIELD* aField );
@ -155,6 +158,7 @@ private:
void saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry );
void saveLine( SCH_LINE* aLine );
void saveText( SCH_TEXT* aText );
void saveBusAlias( std::shared_ptr< BUS_ALIAS > aAlias );
void cacheLib( const wxString& aLibraryFileName );
bool writeDocFile( const PROPERTIES* aProperties );

View File

@ -781,6 +781,41 @@ wxPoint SCH_LINE::MidPoint()
}
void SCH_LINE::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList )
{
wxString msg;
switch( GetLayer() )
{
case LAYER_WIRE:
msg = _( "Net Wire" );
break;
case LAYER_BUS:
msg = _( "Bus Wire" );
break;
default:
msg = _( "Graphical" );
return;
}
aList.push_back( MSG_PANEL_ITEM( _( "Line Type" ), msg, DARKCYAN ) );
if( auto conn = Connection( *g_CurrentSheet ) )
{
#if defined(DEBUG)
conn->AppendDebugInfoToMsgPanel( aList );
msg.Printf( "%zu", m_connected_items.size() );
aList.push_back( MSG_PANEL_ITEM( _( "Connections" ), msg, BROWN ) );
#else
conn->AppendInfoToMsgPanel( aList );
#endif
}
}
int SCH_EDIT_FRAME::EditLine( SCH_LINE* aLine, bool aRedraw )
{
if( aLine == NULL )

View File

@ -195,6 +195,8 @@ public:
void SwapData( SCH_ITEM* aItem ) override;
void GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList ) override;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override;
#endif

View File

@ -43,6 +43,7 @@
#include <sch_no_connect.h>
#include <sch_bus_entry.h>
#include <sch_bitmap.h>
#include <sch_sheet.h>
#include <draw_graphic_text.h>
#include <geometry/geometry_utils.h>
#include <lib_edit_frame.h>
@ -54,6 +55,7 @@
#include <view/view.h>
#include <gal/graphics_abstraction_layer.h>
#include <colors_design_settings.h>
#include <connection_graph.h>
#include <geometry/shape_line_chain.h>
#include <bezier_curves.h>
@ -167,6 +169,26 @@ bool SCH_PAINTER::Draw( const VIEW_ITEM *aItem, int aLayer )
m_schSettings.ImportLegacyColors( nullptr );
#ifdef CONNECTIVITY_DEBUG
auto sch_item = dynamic_cast<SCH_ITEM*>( item );
auto conn = sch_item ? sch_item->Connection( *g_CurrentSheet ) : nullptr;
if( conn )
{
auto pos = item->GetBoundingBox().Centre();
auto label = conn->Name( true );
m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
m_gal->SetStrokeColor( COLOR4D( LIGHTRED ) );
m_gal->SetLineWidth( 2 );
m_gal->SetGlyphSize( VECTOR2D( 20, 20 ) );
m_gal->StrokeText( conn->Name( true ), pos, 0.0 );
}
#endif
switch( item->Type() )
{
HANDLE_ITEM(LIB_ALIAS_T, LIB_ALIAS);
@ -903,6 +925,10 @@ static void drawDanglingSymbol( GAL* aGal, const wxPoint& aPos )
void SCH_PAINTER::draw( SCH_JUNCTION *aJct, int aLayer )
{
COLOR4D color = m_schSettings.GetLayerColor( LAYER_JUNCTION );
auto conn = aJct->Connection( *g_CurrentSheet );
if( conn && conn->IsBus() )
color = m_schSettings.GetLayerColor( LAYER_BUS );
if( aJct->GetState( BRIGHTENED ) )
color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );
@ -1003,6 +1029,13 @@ void SCH_PAINTER::draw( SCH_TEXT *aText, int aLayer )
default: color = m_schSettings.GetLayerColor( LAYER_NOTES ); break;
}
auto conn = aText->Connection( *g_CurrentSheet );
if( conn && conn->IsBus() &&
( aText->Type() == SCH_SHEET_PIN_T ||
aText->Type() == SCH_HIERARCHICAL_LABEL_T ) )
color = m_schSettings.GetLayerColor( LAYER_BUS );
if( aText->GetState( BRIGHTENED ) )
color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );
@ -1243,6 +1276,10 @@ void SCH_PAINTER::draw( SCH_HIERLABEL *aLabel, int aLayer )
auto back_color = m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND );
int width = aLabel->GetThickness() ? aLabel->GetThickness() : GetDefaultLineThickness();
auto conn = aLabel->Connection( *g_CurrentSheet );
if( conn && conn->IsBus() )
color = m_schSettings.GetLayerColor( LAYER_BUS );
if( aLabel->GetState( BRIGHTENED ) )
color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );

View File

@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <lib_pin.h>
#include <sch_component.h>
#include <sch_pin_connection.h>
#include <sch_sheet_path.h>
SCH_PIN_CONNECTION::SCH_PIN_CONNECTION( EDA_ITEM* aParent ) :
SCH_ITEM( aParent, SCH_PIN_CONNECTION_T )
{
}
wxString SCH_PIN_CONNECTION::GetSelectMenuText( EDA_UNITS_T aUnits ) const
{
wxString tmp;
#ifdef DEBUG
tmp.Printf( _( "SCH_PIN_CONNECTION for %s %s" ),
GetChars( m_comp->GetSelectMenuText( aUnits ) ),
GetChars( m_pin->GetSelectMenuText( aUnits ) ) );
#else
tmp.Printf( _( "%s %s" ),
GetChars( m_comp->GetSelectMenuText( aUnits ) ),
GetChars( m_pin->GetSelectMenuText( aUnits ) ) );
#endif
return tmp;
}
wxString SCH_PIN_CONNECTION::GetDefaultNetName( const SCH_SHEET_PATH aPath )
{
if( m_pin->IsPowerConnection() )
return m_pin->GetName();
wxString name;
try
{
name = m_net_name_map.at( aPath );
}
catch( const std::out_of_range& oor )
{
name = wxT( "Net-(" );
name << m_comp->GetRef( &aPath );
// TODO(JE) do we need adoptTimestamp?
if( /* adoptTimestamp && */ name.Last() == '?' )
name << m_comp->GetTimeStamp();
name << _( "-Pad" ) << m_pin->GetNumber() << _( ")" );
m_net_name_map[ aPath ] = name;
}
return name;
}
wxPoint SCH_PIN_CONNECTION::GetPosition() const
{
auto pos = m_comp->GetPosition();
auto transform = m_comp->GetTransform();
return pos + transform.TransformCoordinate( m_pin->GetPosition() );
}

View File

@ -0,0 +1,77 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 CERN
* @author Jon Evans <jon@craftyjon.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SCH_PIN_CONNECTION_H
#define _SCH_PIN_CONNECTION_H
#include <sch_item_struct.h>
#include <sch_connection.h>
#include <sch_sheet_path.h>
#include <lib_pin.h>
class SCH_COMPONENT;
/**
* Container to describe the net connectivity of a specific pin on a component.
*/
class SCH_PIN_CONNECTION : public SCH_ITEM
{
public:
SCH_PIN_CONNECTION( EDA_ITEM* aParent = nullptr );
wxString GetClass() const override
{
return wxT( "SCH_PIN_CONNECTION" );
}
wxString GetDefaultNetName( const SCH_SHEET_PATH aPath );
wxString GetSelectMenuText( EDA_UNITS_T aUnits ) const override;
void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset,
GR_DRAWMODE aDrawMode, COLOR4D aColor = COLOR4D::UNSPECIFIED ) override
{
}
void Move( const wxPoint& aMoveVector ) override {}
void MirrorY( int aYaxis_position ) override {}
void MirrorX( int aXaxis_position ) override {}
void Rotate( wxPoint aPosition ) override {}
wxPoint GetPosition() const override;
void SetPosition( const wxPoint& aPosition ) override {}
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override {}
#endif
LIB_PIN* m_pin;
SCH_COMPONENT* m_comp;
/// The name that this pin connection will drive onto a net
std::map<const SCH_SHEET_PATH, wxString> m_net_name_map;
};
#endif

View File

@ -38,6 +38,7 @@
#include <kiway.h>
#include <sch_draw_panel.h>
#include <sch_item_struct.h>
#include <draw_graphic_text.h>
#include <sch_edit_frame.h>
#include <plotter.h>
@ -56,6 +57,11 @@
#include <symbol_lib_table.h>
#include <tool/common_tools.h>
// TODO(JE) Debugging only
#include <profile.h>
#include <boost/foreach.hpp>
#define EESCHEMA_FILE_STAMP "EESchema"
/* Default zoom values. Limited to these values to keep a decent size
@ -198,6 +204,9 @@ void SCH_SCREEN::DeleteItem( SCH_ITEM* aItem )
}
else
{
if( GetCurItem() == aItem )
SetCurItem( nullptr );
m_drawList.Remove( aItem );
delete aItem;
}
@ -411,6 +420,7 @@ bool SCH_SCREEN::IsTerminalPoint( const wxPoint& aPosition, int aLayer )
SCH_SHEET_PIN* label;
SCH_TEXT* text;
SCH_CONNECTION conn;
switch( aLayer )
{
@ -421,12 +431,12 @@ bool SCH_SCREEN::IsTerminalPoint( const wxPoint& aPosition, int aLayer )
label = GetSheetLabel( aPosition );
if( label && IsBusLabel( label->GetText() ) && label->IsConnected( aPosition ) )
if( label && conn.IsBusLabel( label->GetText() ) && label->IsConnected( aPosition ) )
return true;
text = GetLabel( aPosition );
if( text && IsBusLabel( text->GetText() ) && text->IsConnected( aPosition )
if( text && conn.IsBusLabel( text->GetText() ) && text->IsConnected( aPosition )
&& (text->Type() != SCH_LABEL_T) )
return true;
@ -457,12 +467,12 @@ bool SCH_SCREEN::IsTerminalPoint( const wxPoint& aPosition, int aLayer )
text = GetLabel( aPosition );
if( text && text->IsConnected( aPosition ) && !IsBusLabel( text->GetText() ) )
if( text && text->IsConnected( aPosition ) && !conn.IsBusLabel( text->GetText() ) )
return true;
label = GetSheetLabel( aPosition );
if( label && label->IsConnected( aPosition ) && !IsBusLabel( label->GetText() ) )
if( label && label->IsConnected( aPosition ) && !conn.IsBusLabel( label->GetText() ) )
return true;
break;
@ -525,6 +535,23 @@ void SCH_SCREEN::Draw( EDA_DRAW_PANEL* aCanvas, wxDC* aDC, GR_DRAWMODE aDrawMode
// uncomment line below when there is a virtual EDA_ITEM::GetBoundingBox()
// if( panel->GetClipBox().Intersects( item->GetBoundingBox() ) )
item->Draw( aCanvas, aDC, wxPoint( 0, 0 ), aDrawMode, aColor );
// TODO(JE) Remove debugging code
#ifdef DEBUG
auto conn = item->Connection( *g_CurrentSheet );
if( conn )
{
auto pos = item->GetBoundingBox().Centre();
int sz = Mils2iu( 15 );
auto label = conn->Name( true );
auto text = SCH_TEXT( pos, label, SCH_TEXT_T );
text.SetTextSize( wxSize( sz, sz ) );
text.Draw( aCanvas, aDC, wxPoint( 10, 10 ), aDrawMode, COLOR4D( LIGHTRED ) );
}
#endif
}
for( auto item : junctions )
@ -1209,6 +1236,48 @@ int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aLis
}
void SCH_SCREEN::AddBusAlias( std::shared_ptr<BUS_ALIAS> aAlias )
{
m_aliases.insert( aAlias );
}
bool SCH_SCREEN::IsBusAlias( const wxString& aLabel )
{
SCH_SHEET_LIST aSheets( g_RootSheet );
for( unsigned i = 0; i < aSheets.size(); i++ )
{
for( auto alias : aSheets[i].LastScreen()->GetBusAliases() )
{
if( alias->GetName() == aLabel )
{
return true;
}
}
}
return false;
}
std::shared_ptr<BUS_ALIAS> SCH_SCREEN::GetBusAlias( const wxString& aLabel )
{
SCH_SHEET_LIST aSheets( g_RootSheet );
for( unsigned i = 0; i < aSheets.size(); i++ )
{
for( auto alias : aSheets[i].LastScreen()->GetBusAliases() )
{
if( alias->GetName() == aLabel )
{
return alias;
}
}
}
return NULL;
}
#if defined(DEBUG)
void SCH_SCREEN::Show( int nestLevel, std::ostream& os ) const
{

View File

@ -30,6 +30,8 @@
#ifndef SCREEN_H
#define SCREEN_H
#include <unordered_set>
#include <macros.h>
#include <dlist.h>
#include <sch_item_struct.h>
@ -39,12 +41,14 @@
#include <page_info.h>
#include <kiway_player.h>
#include <sch_marker.h>
#include <bus_alias.h>
#include <../eeschema/general.h>
class LIB_PIN;
class SCH_COMPONENT;
class SCH_SHEET_LIST;
class SCH_SHEET_PATH;
class SCH_SHEET_PIN;
class SCH_LINE;
@ -95,6 +99,9 @@ private:
int m_modification_sync; ///< inequality with PART_LIBS::GetModificationHash()
///< will trigger ResolveAll().
/// List of bus aliases stored in this screen
std::unordered_set< std::shared_ptr< BUS_ALIAS > > m_aliases;
/**
* Add items connected at \a aPosition to the block pick list.
* <p>
@ -509,6 +516,38 @@ public:
*/
int UpdatePickList();
/**
* Adds a bus alias definition (and transfers ownership of the pointer)
*/
void AddBusAlias( std::shared_ptr<BUS_ALIAS> aAlias );
/**
* Removes all bus alias definitions
*/
void ClearBusAliases()
{
m_aliases.clear();
}
/**
* Returns a list of bus aliases defined in this screen
*/
std::unordered_set< std::shared_ptr<BUS_ALIAS> > GetBusAliases()
{
return m_aliases;
}
/**
* Returns true if the given string is a valid bus alias in a loaded screen
*/
static bool IsBusAlias( const wxString& aLabel );
/**
* Returns a pointer to a bus alias object for the given label,
* or null if one doesn't exist
*/
static std::shared_ptr<BUS_ALIAS> GetBusAlias( const wxString& aLabel );
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override;
#endif

View File

@ -926,7 +926,8 @@ void SCH_SHEET::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems,
item->m_Start = item->m_End = m_pins[i].GetPosition();
aNetListItems.push_back( item );
if( IsBusLabel( m_pins[i].GetText() ) )
SCH_CONNECTION conn;
if( conn.IsBusLabel( m_pins[i].GetText() ) )
item->ConvertBusToNetListItems( aNetListItems );
}
}

View File

@ -573,6 +573,6 @@ protected:
};
typedef std::vector< SCH_SHEET* > SCH_SHEETS; // no ownership over contained SCH_SHEETs
//typedef std::vector< SCH_SHEET* > SCH_SHEETS; // no ownership over contained SCH_SHEETs
#endif // SCH_SHEEET_H

View File

@ -38,13 +38,29 @@
#include <class_library.h>
#include <sch_sheet_path.h>
#include <sch_component.h>
#include <sch_sheet.h>
#include <template_fieldnames.h>
#include <dialogs/dialog_schematic_find.h>
#include <boost/functional/hash.hpp>
#include <wx/filename.h>
namespace std
{
size_t hash<SCH_SHEET_PATH>::operator()( const SCH_SHEET_PATH& path ) const
{
size_t seed = 0;
for( auto sheet : path )
boost::hash_combine( seed, sheet->GetTimeStamp() );
return seed;
}
}
SCH_SHEET_PATH::SCH_SHEET_PATH()
{
m_pageNumber = 0;

View File

@ -78,9 +78,9 @@
* (usable in flat and simple hierarchies).
*/
#include "sch_sheet.h" // SCH_SHEETS
class wxFindReplaceData;
class SCH_SHEET;
class SCH_SCREEN;
class SCH_MARKER;
class SCH_ITEM;
@ -89,6 +89,8 @@ class SCH_REFERENCE_LIST;
#define SHEET_NOT_FOUND -1
typedef std::vector< SCH_SHEET* > SCH_SHEETS; // no ownership over contained SCH_SHEETs
/**
* Type SCH_MULTI_UNIT_REFERENCE_MAP
@ -304,6 +306,15 @@ public:
};
namespace std
{
template<> struct hash<SCH_SHEET_PATH>
{
size_t operator()( const SCH_SHEET_PATH& path ) const;
};
}
typedef std::vector< SCH_SHEET_PATH > SCH_SHEET_PATHS;
typedef SCH_SHEET_PATHS::iterator SCH_SHEET_PATHS_ITER;
typedef SCH_SHEET_PATHS::const_iterator SCH_SHEET_PATHS_CITER;

View File

@ -113,6 +113,7 @@ SCH_TEXT::SCH_TEXT( const wxPoint& pos, const wxString& text, KICAD_T aType ) :
m_Layer = LAYER_NOTES;
SetTextPos( pos );
m_isDangling = false;
m_connectionType = CONNECTION_NONE;
m_spin_style = 0;
SetMultilineAllowed( true );
@ -361,6 +362,7 @@ bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
bool previousState = m_isDangling;
m_isDangling = true;
m_connectionType = CONNECTION_NONE;
for( unsigned ii = 0; ii < aItemList.size(); ii++ )
{
@ -376,12 +378,21 @@ bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
case SHEET_LABEL_END:
case NO_CONNECT_END:
if( GetTextPos() == item.GetPosition() )
{
m_isDangling = false;
if( item.GetType() != PIN_END )
m_connected_items.insert( static_cast< SCH_ITEM* >( item.GetItem() ) );
}
break;
case WIRE_START_END:
case BUS_START_END:
m_connectionType = CONNECTION_BUS;
// fall through
case WIRE_START_END:
{
// These schematic items have created 2 DANGLING_END_ITEM one per end. But being
// a paranoid programmer, I'll check just in case.
@ -392,6 +403,18 @@ bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
DANGLING_END_ITEM & nextItem = aItemList[ii];
m_isDangling = !IsPointOnSegment( item.GetPosition(), nextItem.GetPosition(), GetTextPos() );
if( !m_isDangling )
{
if( m_connectionType != CONNECTION_BUS )
m_connectionType = CONNECTION_NET;
// Add the line to the connected items, since it won't be picked
// up by a search of intersecting connection points
auto sch_item = static_cast< SCH_ITEM* >( item.GetItem() );
AddConnectionTo( sch_item );
sch_item->AddConnectionTo( this );
}
}
break;
@ -403,6 +426,9 @@ bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
break;
}
if( m_isDangling )
m_connectionType = CONNECTION_NONE;
return previousState != m_isDangling;
}
@ -492,8 +518,10 @@ void SCH_TEXT::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems,
aNetListItems.push_back( item );
// If a bus connects to label
if( IsBusLabel( m_Text ) )
if( Connection( *aSheetPath )->IsBusLabel( m_Text ) )
{
item->ConvertBusToNetListItems( aNetListItems );
}
}
@ -629,6 +657,18 @@ void SCH_TEXT::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList )
// Display text size (X or Y value, with are the same value in Eeschema)
msg = MessageTextFromValue( aUnits, GetTextWidth(), true );
aList.push_back( MSG_PANEL_ITEM( _( "Size" ), msg, RED ) );
#if defined(DEBUG)
if( auto conn = Connection( *g_CurrentSheet ) )
{
conn->AppendDebugInfoToMsgPanel( aList );
}
msg.Printf( "%p", this );
aList.push_back( MSG_PANEL_ITEM( _( "Object Address" ), msg, RED ) );
#endif
}
#if defined(DEBUG)
@ -1066,10 +1106,14 @@ void SCH_HIERLABEL::Draw( EDA_DRAW_PANEL* panel,
linewidth = Clamp_Text_PenSize( linewidth, GetTextSize(), IsBold() );
auto conn = Connection( *g_CurrentSheet );
if( Color != COLOR4D::UNSPECIFIED )
color = Color;
else
color = GetLayerColor( GetState( BRIGHTENED ) ? LAYER_BRIGHTENED : m_Layer );
color = GetLayerColor( GetState( BRIGHTENED ) ? LAYER_BRIGHTENED :
( conn && conn->IsBus() ) ?
LAYER_BUS : m_Layer );
GRSetDrawMode( DC, DrawMode );

View File

@ -34,6 +34,7 @@
#include <macros.h>
#include <eda_text.h>
#include <sch_item_struct.h>
#include <sch_connection.h> // for CONNECTION_TYPE
class LINE_READER;
@ -64,6 +65,8 @@ protected:
/// supports connections.
bool m_isDangling;
CONNECTION_TYPE m_connectionType;
/**
* The orientation of text and any associated drawing elements of derived objects.
* 0 is the horizontal and left justified.

View File

@ -279,16 +279,16 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
if( item && (item->Type() == SCH_SHEET_T) )
{
m_CurrentSheet->push_back( (SCH_SHEET*) item );
g_CurrentSheet->push_back( (SCH_SHEET*) item );
DisplayCurrentSheet();
}
break;
case ID_POPUP_SCH_LEAVE_SHEET:
if( m_CurrentSheet->Last() != g_RootSheet )
if( g_CurrentSheet->Last() != g_RootSheet )
{
m_CurrentSheet->pop_back();
g_CurrentSheet->pop_back();
DisplayCurrentSheet();
}
@ -376,6 +376,81 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
}
void SCH_EDIT_FRAME::OnUnfoldBus( wxCommandEvent& event )
{
auto screen = GetScreen();
auto item = static_cast< wxMenuItem* >( event.GetEventUserData() );
auto net = item->GetItemLabelText();
auto pos = GetCrossHairPosition();
/**
* Unfolding a bus consists of the following user inputs:
* 1) User selects a bus to unfold (see AddMenusForBus())
* We land in this event handler.
*
* 2) User clicks to set the net label location (handled by BeginSegment())
* Before this first click, the posture of the bus entry follows the
* mouse cursor in X and Y (handled by DrawSegment())
*
* 3) User is now in normal wiring mode and can exit in any normal way.
*/
wxASSERT( !m_busUnfold.in_progress );
m_busUnfold.entry = new SCH_BUS_WIRE_ENTRY( pos, '\\' );
SetSchItemParent( m_busUnfold.entry, screen );
AddToScreen( m_busUnfold.entry );
m_busUnfold.label = new SCH_LABEL( m_busUnfold.entry->m_End(), net );
m_busUnfold.label->SetTextSize( wxSize( GetDefaultTextSize(),
GetDefaultTextSize() ) );
m_busUnfold.label->SetLabelSpinStyle( 0 );
SetSchItemParent( m_busUnfold.label, screen );
m_busUnfold.in_progress = true;
m_busUnfold.origin = pos;
m_busUnfold.net_name = net;
SetToolID( ID_WIRE_BUTT, wxCURSOR_PENCIL, _( "Add wire" ) );
SetCrossHairPosition( m_busUnfold.entry->m_End() );
BeginSegment( LAYER_WIRE );
m_canvas->SetAutoPanRequest( true );
}
void SCH_EDIT_FRAME::CancelBusUnfold()
{
if( m_busUnfold.entry )
{
RemoveFromScreen( m_busUnfold.entry );
delete m_busUnfold.entry;
}
if( m_busUnfold.label )
{
if( m_busUnfold.label_placed )
RemoveFromScreen( m_busUnfold.label );
delete m_busUnfold.label;
}
FinishBusUnfold();
}
void SCH_EDIT_FRAME::FinishBusUnfold()
{
m_busUnfold = {};
SetToolID( ID_NO_TOOL_SELECTED, GetGalCanvas()->GetDefaultCursor(), wxEmptyString );
}
void SCH_EDIT_FRAME::OnMoveItem( wxCommandEvent& aEvent )
{
SCH_SCREEN* screen = GetScreen();
@ -1058,17 +1133,17 @@ void SCH_EDIT_FRAME::OnEditItem( wxCommandEvent& aEvent )
// Keep trace of existing sheet paths. EditSheet() can modify this list
SCH_SHEET_LIST initial_sheetpathList( g_RootSheet );
doRefresh = EditSheet( (SCH_SHEET*) item, m_CurrentSheet, &doClearAnnotation );
doRefresh = EditSheet( (SCH_SHEET*) item, g_CurrentSheet, &doClearAnnotation );
if( doClearAnnotation ) // happens when the current sheet load a existing file
{ // we must clear "new" components annotation
SCH_SCREENS screensList( g_RootSheet );
// We clear annotation of new sheet paths here:
screensList.ClearAnnotationOfNewSheetPaths( initial_sheetpathList );
// Clear annotation of m_CurrentSheet itself, because its sheetpath
// Clear annotation of g_CurrentSheet itself, because its sheetpath
// is not a new path, but components managed by its sheet path must have
// their annotation cleared, becuase they are new:
((SCH_SHEET*) item)->GetScreen()->ClearAnnotation( m_CurrentSheet );
((SCH_SHEET*) item)->GetScreen()->ClearAnnotation( g_CurrentSheet );
}
if( doRefresh )
@ -1331,3 +1406,77 @@ void SCH_EDIT_FRAME::OnOrient( wxCommandEvent& aEvent )
if( item->GetFlags() == 0 )
screen->SetCurItem( NULL );
}
void SCH_EDIT_FRAME::OnUnfoldBusHotkey( wxCommandEvent& aEvent )
{
auto data = (EDA_HOTKEY_CLIENT_DATA*) aEvent.GetClientObject();
auto item = GetScreen()->GetCurItem();
wxCHECK_RET( data != NULL, wxT( "Invalid hot key client object." ) );
if( item == NULL )
{
// If we didn't get here by a hot key, then something has gone wrong.
if( aEvent.GetInt() == 0 )
return;
item = LocateAndShowItem( data->GetPosition(), SCH_COLLECTOR::EditableItems,
aEvent.GetInt() );
// Exit if no item found at the current location or the item is already being edited.
if( (item == NULL) || (item->GetFlags() != 0) )
return;
}
auto connection = item->Connection( *g_CurrentSheet );
if( connection && connection->IsBus() )
{
int idx = 0;
wxMenu* bus_unfolding_menu = new wxMenu;
for( const auto& member : connection->Members() )
{
int id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
if( member->Type() == CONNECTION_BUS )
{
wxMenu* submenu = new wxMenu;
bus_unfolding_menu->AppendSubMenu( submenu, _( member->Name() ) );
for( const auto& sub_member : member->Members() )
{
id = ID_POPUP_SCH_UNFOLD_BUS + ( idx++ );
submenu->Append( id, sub_member->Name(), wxEmptyString );
// See comment in else clause below
auto sub_item_clone = new wxMenuItem();
sub_item_clone->SetItemLabel( sub_member->Name() );
Bind( wxEVT_COMMAND_MENU_SELECTED, &SCH_EDIT_FRAME::OnUnfoldBus,
this, id, id, sub_item_clone );
}
}
else
{
bus_unfolding_menu->Append( id, member->Name(),
wxEmptyString );
// Because Bind() takes ownership of the user data item, we
// make a new menu item here and set its label. Why create a
// menu item instead of just a wxString or something? Because
// Bind() requires a pointer to wxObject rather than a void
// pointer. Maybe at some point I'll think of a better way...
auto item_clone = new wxMenuItem();
item_clone->SetItemLabel( member->Name() );
Bind( wxEVT_COMMAND_MENU_SELECTED, &SCH_EDIT_FRAME::OnUnfoldBus,
this, id, id, item_clone );
}
}
GetGalCanvas()->PopupMenu( bus_unfolding_menu, GetCrossHairScreenPosition() );
}
}

View File

@ -121,6 +121,7 @@ enum KICAD_T
SCH_COMPONENT_T,
SCH_SHEET_PIN_T,
SCH_SHEET_T,
SCH_PIN_CONNECTION_T,
// Be prudent with these 3 types:
// they should be used only to locate a specific field type

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2013 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2018 CERN
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,6 +33,7 @@
#include <wx/valtext.h>
#include <wx/grid.h>
#include <wx/regex.h>
/**
* Class GRID_CELL_TEXT_EDITOR
@ -112,6 +114,66 @@ public:
void OnTextChanged( wxCommandEvent& event );
};
/**
* Custom validator that checks verifies that a string *exactly* matches a
* regular expression.
*/
class REGEX_VALIDATOR : public wxTextValidator
{
public:
/**
* Constructor.
*
* @param aRegEx is a regular expression to validate strings.
* @param aValue is a pointer to a wxString containing the value to validate.
*/
REGEX_VALIDATOR( const wxString& aRegEx, wxString* aValue = NULL )
: wxTextValidator( wxFILTER_NONE, aValue )
{
compileRegEx( aRegEx, wxRE_DEFAULT );
}
/**
* Constructor.
*
* @param aRegEx is a regular expression to validate strings.
* @param aFlags are compilation flags (normally wxRE_DEFAULT).
* @param aValue is a pointer to a wxString containing the value to validate.
*/
REGEX_VALIDATOR( const wxString& aRegEx, int aFlags, wxString* aValue = NULL )
: wxTextValidator( wxFILTER_NONE, aValue )
{
compileRegEx( aRegEx, aFlags );
}
REGEX_VALIDATOR( const REGEX_VALIDATOR& aOther )
{
wxValidator::Copy( aOther );
compileRegEx( aOther.m_regExString, aOther.m_regExFlags );
}
virtual wxObject* Clone() const override
{
return new REGEX_VALIDATOR( *this );
}
bool Validate( wxWindow* aParent ) override;
protected:
///> Compiles and stores a regular expression
void compileRegEx( const wxString& aRegEx, int aFlags );
///> Original regular expression (for copy constructor)
wxString m_regExString;
///> Original compilation flags (for copy constructor)
int m_regExFlags;
///> Compiled regex
wxRegEx m_regEx;
};
namespace KIUI
{
/**