Commit 175fab48 authored by Wayne Stambaugh's avatar Wayne Stambaugh

EESchema multiple item hit testing and other minor improvements.

* Add item clarification context menu to EESchema when multiple unresolved
  items are found at the current cross hair position.
* Add collector class SCH_COLLECTOR for supporting multiple item hit testing.
* Removed bit wise masked filtering from schematic item hit testing.
* Removed all old hit testing functions and methods scattered about the
  EESchema source code.
* Move terminal point test function into SCH_SCREEN object.
* Fixed bug in terminal point test when terminating a bus to a label.
* Define the < operator for sorting schematic items.
* Add area calculation method to EDA_Rect item.
* Add method for returning an item's bitmap for menu display purposes.
* Add method for returning an item's menu text for menu display purposes.
* Changed EDA_ITEMS container from boost::ptr_vector to std::vector.
* Factor coordinate string conversion code from EDA_DRAW_FRAME to function
  CoordinateToString().
parents 5f6cd454 628f874c
......@@ -125,6 +125,16 @@ SEARCH_RESULT EDA_ITEM::Visit( INSPECTOR* inspector, const void* testData,
return SEARCH_CONTINUE;
}
wxString EDA_ITEM::GetSelectMenuText() const
{
wxFAIL_MSG( wxT( "GetSelectMenuText() was not overridden for schematic item type " ) +
GetClass() );
return wxString( wxT( "Undefined menu text for " ) + GetClass() );
}
#if defined(DEBUG)
......@@ -637,3 +647,9 @@ void EDA_Rect::Merge( const wxPoint& aPoint )
end.y = MAX( end.y, aPoint.y );
SetEnd( end );
}
double EDA_Rect::GetArea() const
{
return (double) GetWidth() * (double) GetHeight();
}
......@@ -708,6 +708,47 @@ const wxString& valeur_param( int valeur, wxString& buf_texte )
}
wxString CoordinateToString( int aValue, int aInternalUnits, bool aConvertToMils )
{
wxCHECK_MSG( (aInternalUnits == EESCHEMA_INTERNAL_UNIT)
|| (aInternalUnits == PCB_INTERNAL_UNIT),
wxString( _( "*** Bad Internal Units ***" ) ),
wxT( "Invalid interanl units value." ) );
wxString text;
const wxChar* format;
double value = To_User_Unit( g_UserUnit, aValue, aInternalUnits );
if( g_UserUnit == INCHES )
{
if( aConvertToMils )
{
format = ( aInternalUnits == EESCHEMA_INTERNAL_UNIT ) ? wxT( "%.0f" ) : wxT( "%.1f" );
value *= 1000;
}
else
{
format = ( aInternalUnits == EESCHEMA_INTERNAL_UNIT ) ? wxT( "%.3f" ) : wxT( "%.4f" );
}
}
else
{
format = ( aInternalUnits == EESCHEMA_INTERNAL_UNIT ) ? wxT( "%.2f" ) : wxT( "%.3f" );
}
text.Printf( format, value );
if( g_UserUnit == INCHES )
text += ( aConvertToMils ) ? _( " mils" ) : _( " in" );
else
text += _( " mm" );
return text;
}
/*
*
*/
......
......@@ -41,7 +41,7 @@ dialog_about::dialog_about(wxWindow *parent, AboutAppInfo& appInfo)
CreateNotebooks();
GetSizer()->SetSizeHints(this);
m_auiNotebook->Update();
SetFocus();
Centre();
}
......
......@@ -808,33 +808,5 @@ void EDA_DRAW_FRAME::ClearMsgPanel( void )
wxString EDA_DRAW_FRAME::CoordinateToString( int aValue, bool aConvertToMils )
{
wxString text;
const wxChar* format;
double value = To_User_Unit( g_UserUnit, aValue, m_InternalUnits );
if( g_UserUnit == INCHES )
{
if( aConvertToMils )
{
format = ( m_InternalUnits == EESCHEMA_INTERNAL_UNIT ) ? wxT( "%.0f" ) : wxT( "%.1f" );
value *= 1000;
}
else
{
format = ( m_InternalUnits == EESCHEMA_INTERNAL_UNIT ) ? wxT( "%.3f" ) : wxT( "%.4f" );
}
}
else
{
format = ( m_InternalUnits == EESCHEMA_INTERNAL_UNIT ) ? wxT( "%.2f" ) : wxT( "%.3f" );
}
text.Printf( format, value );
if( g_UserUnit == INCHES )
text += ( aConvertToMils ) ? _( " mils" ) : _( " in" );
else
text += _( " mm" );
return text;
return ::CoordinateToString( aValue, m_InternalUnits, aConvertToMils );
}
......@@ -17,6 +17,12 @@
#include "../eeschema/dialogs/dialog_schematic_find.h"
bool sort_schematic_items( const SCH_ITEM* aItem1, const SCH_ITEM* aItem2 )
{
return *aItem1 < *aItem2;
}
/* Constructor and destructor for SCH_ITEM */
/* They are not inline because this creates problems with gcc at linking time
* in debug mode
......@@ -38,18 +44,18 @@ SCH_ITEM::SCH_ITEM( const SCH_ITEM& aItem ) :
SCH_ITEM::~SCH_ITEM()
{
// Do not let the connections container go out of scope with any ojbects or they
// Do not let the connections container go out of scope with any objects or they
// will be deleted by the container will cause the EESchema to crash. These objects
// are owned by the sheet object container.
if( !m_connections.empty() )
m_connections.release();
m_connections.clear();
}
/**
* place the struct in m_drawList.
* if it is a new item, it it also put in undo list
* for an "old" item, saving it in undo list must be done before editiing,
* for an "old" item, saving it in undo list must be done before editing,
* and not here!
*/
void SCH_ITEM::Place( SCH_EDIT_FRAME* aFrame, wxDC* aDC )
......@@ -108,3 +114,10 @@ bool SCH_ITEM::IsConnected( const wxPoint& aPosition ) const
return doIsConnected( aPosition );
}
bool SCH_ITEM::operator < ( const SCH_ITEM& aItem ) const
{
wxCHECK_MSG( false, this->Type() < aItem.Type(),
wxT( "Less than operator not defined for " ) + GetClass() );
}
......@@ -425,6 +425,13 @@ int CrossProduct( wxPoint vectorA, wxPoint vectorB )
}
double GetLineLength( const wxPoint& aPointA, const wxPoint& aPointB )
{
return sqrt( pow( (double) aPointA.x - (double) aPointB.x, 2 ) +
pow( (double) aPointA.y - (double) aPointB.y, 2 ) );
}
double fsinus[3600] =
{
0.0000000000, 0.0017453284, 0.0034906514, 0.0052359638,
......
......@@ -7,7 +7,6 @@
#include "wxstruct.h"
#include "common.h"
#include "cvpcb.h"
//#include "protos.h"
#include "class_drawpanel.h"
#include "footprint_info.h"
#include "cvstruct.h"
......@@ -32,8 +31,8 @@ DIALOG_FOOTPRINTS_DISPLAY_OPTIONS::DIALOG_FOOTPRINTS_DISPLAY_OPTIONS( PCB_BASE_F
m_Parent = parent;
initDialog();
m_sdbSizer1OK->SetDefault();
GetSizer()->SetSizeHints( this );
Centre();
}
......
......@@ -104,7 +104,6 @@ set(EESCHEMA_SRCS
lib_text.cpp
libfield.cpp
load_one_schematic_file.cpp
locate.cpp
menubar.cpp
menubar_libedit.cpp
netform.cpp
......@@ -116,6 +115,7 @@ set(EESCHEMA_SRCS
pinedit.cpp
plot.cpp
sch_bus_entry.cpp
sch_collectors.cpp
sch_component.cpp
sch_field.cpp
sch_junction.cpp
......
......@@ -25,7 +25,6 @@
static void AbortCreateNewLine( EDA_DRAW_PANEL* Panel, wxDC* DC );
static bool IsTerminalPoint( SCH_SCREEN* screen, const wxPoint& pos, int layer );
static void ComputeBreakPoint( SCH_LINE* segment, const wxPoint& new_pos );
SCH_ITEM* s_OldWiresList;
......@@ -169,7 +168,7 @@ void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type )
/* Creates the new segment, or terminates the command
* if the end point is on a pin, junction or an other wire or bus */
if( IsTerminalPoint( GetScreen(), cursorpos, oldsegment->GetLayer() ) )
if( GetScreen()->IsTerminalPoint( cursorpos, oldsegment->GetLayer() ) )
{
EndSegment( DC );
return;
......@@ -572,98 +571,3 @@ void IncrementLabelMember( wxString& name )
name.Remove( ii ); name << number;
}
}
/* Return true if pos can be a terminal point for a wire or a bus
* i.e. :
* for a WIRE, if at pos is found:
* - a junction
* - or a pin
* - or an other wire
*
* - for a BUS, if at pos is found:
* - a BUS
*/
static bool IsTerminalPoint( SCH_SCREEN* screen, const wxPoint& pos, int layer )
{
EDA_ITEM* item;
LIB_PIN* pin;
SCH_COMPONENT* LibItem = NULL;
SCH_SHEET_PIN* pinsheet;
wxPoint itempos;
switch( layer )
{
case LAYER_BUS:
item = screen->GetItem( pos, 0, BUS_T );
if( item )
return true;
pinsheet = screen->GetSheetLabel( pos );
if( pinsheet && IsBusLabel( pinsheet->m_Text ) )
{
itempos = pinsheet->m_Pos;
if( (itempos.x == pos.x) && (itempos.y == pos.y) )
return true;
}
break;
case LAYER_NOTES:
item = screen->GetItem( pos, 0, DRAW_ITEM_T );
if( item )
return true;
break;
case LAYER_WIRE:
item = screen->GetItem( pos, MAX( g_DrawDefaultLineThickness, 3 ),
BUS_ENTRY_T | JUNCTION_T );
if( item )
return true;
pin = screen->GetPin( pos, &LibItem );
if( pin && LibItem )
{
// Calculate the exact position of the connection point of the pin,
// depending on orientation of the component.
itempos = LibItem->GetScreenCoord( pin->GetPosition() );
itempos.x += LibItem->m_Pos.x;
itempos.y += LibItem->m_Pos.y;
if( ( itempos.x == pos.x ) && ( itempos.y == pos.y ) )
return true;
}
item = screen->GetItem( pos, 0, WIRE_T );
if( item )
return true;
item = screen->GetItem( pos, 0, LABEL_T );
if( item && (item->Type() != SCH_TEXT_T)
&& ( ( (SCH_GLOBALLABEL*) item )->m_Pos.x == pos.x )
&& ( ( (SCH_GLOBALLABEL*) item )->m_Pos.y == pos.y ) )
return true;
pinsheet = screen->GetSheetLabel( pos );
if( pinsheet && !IsBusLabel( pinsheet->m_Text ) )
{
itempos = pinsheet->m_Pos;
if( ( itempos.x == pos.x ) && ( itempos.y == pos.y ) )
return true;
}
break;
default:
break;
}
return false;
}
......@@ -11,6 +11,7 @@
#include "eeschema_id.h"
#include "general.h"
#include "hotkeys.h"
#include "protos.h"
#include "libeditframe.h"
#include "viewlib_frame.h"
......@@ -22,29 +23,8 @@
#include "sch_component.h"
/**
* Function LocateAndShowItem
* search the schematic at \a aPosition in logical (drawing) units for any item.
* <p>
* The search is first performed at \a aPosition which may be off grid. If no item is
* found at \a aPosition, the search is repeated for the nearest grid position to \a
* aPosition.
*
* The search order is as follows:
* <ul>
* <li>Marker</li>
* <li>No Connect</li>
* <li>Junction</li>
* <li>Wire, bus, or entry</li>
* <li>Label</li>
* <li>Pin</li>
* <li>Component</li>
* </ul></p>
* @param aPosition The wxPoint on the schematic to search.
* @param aIncludePin = true to search for pins, false to ignore them
* @return A SCH_ITEM pointer on the item or NULL if no item found
*/
SCH_ITEM* SCH_EDIT_FRAME::LocateAndShowItem( const wxPoint& aPosition, bool aIncludePin )
SCH_ITEM* SCH_EDIT_FRAME::LocateAndShowItem( const wxPoint& aPosition, const KICAD_T aFilterList[],
int aHotKeyCommandId )
{
SCH_ITEM* item;
wxString msg;
......@@ -52,13 +32,26 @@ SCH_ITEM* SCH_EDIT_FRAME::LocateAndShowItem( const wxPoint& aPosition, bool aInc
SCH_COMPONENT* LibItem = NULL;
wxPoint gridPosition = GetScreen()->GetNearestGridPosition( aPosition );
item = LocateItem( aPosition, aIncludePin );
// Check the on grid position first. There is more likely to be multple items on
// grid than off grid.
item = LocateItem( gridPosition, aFilterList, aHotKeyCommandId );
if( !item && aPosition != gridPosition )
item = LocateItem( gridPosition, aIncludePin );
// If the user aborted the clarification context menu, don't show it again at the
// off grid position.
if( !item && DrawPanel->m_AbortRequest )
{
DrawPanel->m_AbortRequest = false;
return NULL;
}
if( !item && (aPosition != gridPosition) )
item = LocateItem( aPosition, aFilterList, aHotKeyCommandId );
if( !item )
{
DrawPanel->m_AbortRequest = false; // Just in case the user aborted the context menu.
return NULL;
}
/* Cross probing to pcbnew if a pin or a component is found */
switch( item->Type() )
......@@ -70,22 +63,16 @@ SCH_ITEM* SCH_EDIT_FRAME::LocateAndShowItem( const wxPoint& aPosition, bool aInc
break;
case SCH_COMPONENT_T:
Pin = GetScreen()->GetPin( GetScreen()->GetCrossHairPosition(), &LibItem );
if( Pin )
break; // Priority is probing a pin first
LibItem = (SCH_COMPONENT*) item;
SendMessageToPCBNEW( item, LibItem );
break;
default:
Pin = GetScreen()->GetPin( GetScreen()->GetCrossHairPosition(), &LibItem );
break;
case LIB_PIN_T:
Pin = (LIB_PIN*) item;
break;
default:
;
}
if( Pin )
......@@ -105,134 +92,74 @@ SCH_ITEM* SCH_EDIT_FRAME::LocateAndShowItem( const wxPoint& aPosition, bool aInc
}
/**
* Function LocateItem
* searches for an item at \a aPosition.
* @param aPosition The wxPoint location where to search.
* @param aIncludePin True to search for pins, false to ignore them.
* @return The SCH_ITEM pointer of the item or NULL if no item found.
*/
SCH_ITEM* SCH_EDIT_FRAME::LocateItem( const wxPoint& aPosition, bool aIncludePin )
SCH_ITEM* SCH_EDIT_FRAME::LocateItem( const wxPoint& aPosition, const KICAD_T aFilterList[],
int aHotKeyCommandId )
{
SCH_ITEM* item;
LIB_PIN* Pin;
SCH_COMPONENT* LibItem;
wxString Text;
wxString msg;
item = GetScreen()->GetItem( aPosition, 0, MARKER_T );
if( item )
{
item->DisplayInfo( this );
return item;
}
SCH_ITEM* item = NULL;
item = GetScreen()->GetItem( aPosition, 0, NO_CONNECT_T );
m_collectedItems.Collect( GetScreen()->GetDrawItems(), aFilterList, aPosition );
if( item )
if( m_collectedItems.GetCount() == 0 )
{
ClearMsgPanel();
return item;
}
item = GetScreen()->GetItem( aPosition, 0, JUNCTION_T );
if( item )
else if( m_collectedItems.GetCount() == 1 )
{
ClearMsgPanel();
return item;
item = m_collectedItems[0];
GetScreen()->SetCurItem( item );
}
item = GetScreen()->GetItem( aPosition, MAX( g_DrawDefaultLineThickness, 3 ),
WIRE_T | BUS_T | BUS_ENTRY_T );
if( item ) // We have found a wire: Search for a connected pin at the same location
else
{
Pin = GetScreen()->GetPin( aPosition, &LibItem );
if( Pin )
// There are certain combinations of items that do not need clarification such as
// a corner were two lines meet or all the items form a junction.
if( aHotKeyCommandId )
{
Pin->DisplayInfo( this );
if( LibItem )
AppendMsgPanel( LibItem->GetRef( GetSheet() ),
LibItem->GetField( VALUE )->m_Text, DARKCYAN );
switch( aHotKeyCommandId )
{
case HK_DRAG:
if( m_collectedItems.IsCorner() || m_collectedItems.IsNode( false ) )
{
item = m_collectedItems[0];
GetScreen()->SetCurItem( item );
}
else
ClearMsgPanel();
return item;
default:
;
}
item = GetScreen()->GetItem( aPosition, 0, DRAW_ITEM_T );
if( item )
{
ClearMsgPanel();
return item;
}
item = GetScreen()->GetItem( aPosition, 0, FIELD_T );
if( item )
if( item == NULL )
{
wxASSERT( item->Type() == SCH_FIELD_T );
wxASSERT_MSG( m_collectedItems.GetCount() <= MAX_SELECT_ITEM_IDS,
wxT( "Select item clarification context menu size limit exceeded." ) );
SCH_FIELD* Field = (SCH_FIELD*) item;
LibItem = (SCH_COMPONENT*) Field->GetParent();
LibItem->DisplayInfo( this );
wxMenu selectMenu;
wxMenuItem* title = new wxMenuItem( &selectMenu, wxID_NONE, _( "Clarify Selection" ) );
return item;
}
item = GetScreen()->GetItem( aPosition, 0, LABEL_T | TEXT_T );
selectMenu.Append( title );
selectMenu.AppendSeparator();
if( item )
for( int i = 0; i < m_collectedItems.GetCount() && i < MAX_SELECT_ITEM_IDS; i++ )
{
ClearMsgPanel();
return item;
wxString text = m_collectedItems[i]->GetSelectMenuText();
const char** xpm = m_collectedItems[i]->GetMenuImage();
ADD_MENUITEM( &selectMenu, ID_SCH_SELECT_ITEM_START + i, text, xpm );
}
/* search for a pin */
Pin = GetScreen()->GetPin( aPosition, &LibItem );
if( Pin )
{
Pin->DisplayInfo( this );
if( LibItem )
AppendMsgPanel( LibItem->GetRef( GetSheet() ),
LibItem->GetField( VALUE )->m_Text, DARKCYAN );
if( aIncludePin )
return LibItem;
// Set to NULL in case user aborts the clarification context menu.
GetScreen()->SetCurItem( NULL );
DrawPanel->m_AbortRequest = true; // Changed to false if an item is selected
PopupMenu( &selectMenu );
DrawPanel->MoveCursorToCrossHair();
item = GetScreen()->GetCurItem();
}
item = GetScreen()->GetItem( aPosition, 0, COMPONENT_T );
if( item )
{
item = LocateSmallestComponent( GetScreen() );
LibItem = (SCH_COMPONENT*) item;
LibItem->DisplayInfo( this );
return item;
}
item = GetScreen()->GetItem( aPosition, 0, SHEET_T );
if( item )
{
( (SCH_SHEET*) item )->DisplayInfo( this );
return item;
}
item = GetScreen()->GetItem( aPosition );
item->DisplayInfo( this );
else
ClearMsgPanel();
if( item )
return item;
ClearMsgPanel();
return NULL;
}
......
......@@ -25,6 +25,7 @@ void SCH_EDIT_FRAME::DeleteConnection( bool DeleteFullConnection )
{
SCH_ITEM* item;
EDA_ITEM* tmp;
EDA_ITEMS list;
PICKED_ITEMS_LIST pickList;
SCH_SCREEN* screen = GetScreen();
wxPoint pos = screen->GetCrossHairPosition();
......@@ -33,24 +34,19 @@ void SCH_EDIT_FRAME::DeleteConnection( bool DeleteFullConnection )
screen->ClearDrawingState();
screen->BreakSegmentsOnJunctions();
// Save the list entry point of this screen
SCH_ITEM* savedItems = screen->GetDrawItems();
item = screen->GetDrawItems();
if( screen->GetNode( pos, list ) == 0 )
return;
while( item && ( item = screen->GetItem( pos, 0, JUNCTION_T | WIRE_T | BUS_T ) ) != NULL )
for( size_t i = 0; i < list.size(); i++ )
{
item = (SCH_ITEM*) list[ i ];
item->SetFlags( SELECTEDNODE | STRUCT_DELETED );
/* Put this structure in the picked list: */
ITEM_PICKER picker( item, UR_DELETED );
pickList.PushItem( picker );
item = item->Next();
screen->SetDrawItems( item );
}
screen->SetDrawItems( savedItems ); // Restore the list entry point.
/* Mark all wires, junctions, .. connected to one of the item to delete
*/
if( DeleteFullConnection )
......@@ -172,7 +168,7 @@ void SCH_EDIT_FRAME::DeleteConnection( bool DeleteFullConnection )
if( item->Type() != SCH_LABEL_T )
continue;
tmp = screen->GetItem( ( (SCH_TEXT*) item )->m_Pos, 0, WIRE_T | BUS_T );
tmp = screen->GetWireOrBus( ( (SCH_TEXT*) item )->m_Pos );
if( tmp && tmp->GetFlags() & STRUCT_DELETED )
{
......@@ -199,42 +195,23 @@ bool SCH_EDIT_FRAME::DeleteItemAtCrossHair( wxDC* DC )
{
SCH_ITEM* item;
SCH_SCREEN* screen = GetScreen();
bool item_deleted = false;
item = screen->GetItem( screen->GetCrossHairPosition(), 0, MARKER_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, JUNCTION_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, NO_CONNECT_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, BUS_ENTRY_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, WIRE_T | BUS_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, DRAW_ITEM_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, TEXT_T | LABEL_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, COMPONENT_T );
if( item == NULL )
item = screen->GetItem( screen->GetCrossHairPosition(), 0, SHEET_T );
item = LocateItem( screen->GetCrossHairPosition(), SCH_COLLECTOR::ParentItems );
if( item )
{
bool itemHasConnections = item->IsConnectable();
GetScreen()->SetCurItem( NULL );
SetRepeatItem( NULL );
DeleteItem( item );
if( itemHasConnections )
screen->TestDanglingEnds( DrawPanel, DC );
OnModify();
item_deleted = true;
return true;
}
return item_deleted;
return false;
}
......@@ -77,13 +77,17 @@ void DialogLabelEditor::InitDialog()
break;
case SCH_HIERARCHICAL_LABEL_T:
SetTitle( _( "Hierarchal Label Properties" ) );
SetTitle( _( "Hierarchical Label Properties" ) );
break;
case SCH_LABEL_T:
SetTitle( _( "Label Properties" ) );
break;
case SCH_SHEET_LABEL_T:
SetTitle( _( "Hierarchical Sheet Pin Properties." ) );
break;
default:
SetTitle( _( "Text Properties" ) );
m_textLabel->Disconnect( wxEVT_COMMAND_TEXT_ENTER,
......
......@@ -80,98 +80,91 @@ void SCH_EDIT_FRAME::StartMoveCmpField( SCH_FIELD* aField, wxDC* DC )
/*
* Edit a field: text and size
*/
void SCH_EDIT_FRAME::EditCmpFieldText( SCH_FIELD* Field, wxDC* DC )
void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField, wxDC* aDC )
{
wxCHECK_RET( aField != NULL && aField->Type() == SCH_FIELD_T,
wxT( "Invalid schemaitic field type. " ) );
int fieldNdx, flag;
LIB_COMPONENT* Entry;
SCH_COMPONENT* component = (SCH_COMPONENT*) aField->GetParent();
if( Field == NULL )
{
DisplayError( this, _( "No Field To Edit" ), 10 );
return;
}
wxCHECK_RET( component != NULL && component->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic field parent item." ) );
SCH_COMPONENT* Cmp = (SCH_COMPONENT*) Field->GetParent();
LIB_COMPONENT* entry = CMP_LIBRARY::FindLibraryComponent( component->GetLibName() );
fieldNdx = Field->m_FieldId;
wxCHECK_RET( entry != NULL, wxT( "Library entry for component <" ) +
component->GetLibName() + wxT( "> could not be found." ) );
if( fieldNdx == VALUE )
{
Entry = CMP_LIBRARY::FindLibraryComponent( Cmp->GetLibName() );
fieldNdx = aField->GetId();
if( Entry && Entry->IsPower() )
if( fieldNdx == VALUE && entry->IsPower() )
{
DisplayInfoMessage( this, _( "Part is a POWER, value cannot be \
modified!\nYou must create a new power" ) );
DisplayInfoMessage( this, _( "The component is a POWER, it's value cannot be \
modified!\n\nYou must create a new power component with the value." ) );
return;
}
}
flag = 0;
if( fieldNdx == REFERENCE )
{
Entry = CMP_LIBRARY::FindLibraryComponent( Cmp->GetLibName() );
if( Entry != NULL )
{
if( Entry->GetPartCount() > 1 )
if( fieldNdx == REFERENCE && entry->GetPartCount() > 1 )
flag = 1;
}
}
/* save old cmp in undo list if not already in edit, or moving ... */
if( Field->m_Flags == 0 )
SaveCopyInUndoList( Cmp, UR_CHANGED );
if( aField->GetFlags() == 0 )
SaveCopyInUndoList( component, UR_CHANGED );
wxString newtext = Field->m_Text;
DrawPanel->m_IgnoreMouseEvents = TRUE;
wxString newtext = aField->m_Text;
DrawPanel->m_IgnoreMouseEvents = true;
wxString title = _( "Field: " ) + Field->m_Name;
wxString title = _( "Field " ) + aField->m_Name;
wxTextEntryDialog dlg( this, wxEmptyString , title, newtext );
int diag = dlg.ShowModal();
DrawPanel->MoveCursorToCrossHair();
DrawPanel->m_IgnoreMouseEvents = false;
newtext = dlg.GetValue( );
newtext.Trim( true );
newtext.Trim( false );
DrawPanel->MoveCursorToCrossHair();
DrawPanel->m_IgnoreMouseEvents = FALSE;
if ( diag != wxID_OK )
if ( diag != wxID_OK || newtext == aField->GetText() )
return; // cancelled by user
Field->m_AddExtraText = flag;
Field->Draw( DrawPanel, DC, wxPoint( 0, 0 ), g_XorMode );
aField->m_AddExtraText = flag;
aField->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
if( !newtext.IsEmpty() )
{
if( Field->m_Text.IsEmpty() )
if( aField->m_Text.IsEmpty() )
{
Field->m_Pos = Cmp->m_Pos;
Field->m_Size.x = Field->m_Size.y = m_TextFieldSize;
aField->m_Pos = component->m_Pos;
aField->m_Size.x = aField->m_Size.y = m_TextFieldSize;
}
Field->m_Text = newtext;
aField->m_Text = newtext;
if( fieldNdx == REFERENCE )
{
Cmp->SetRef( GetSheet(), newtext );
component->SetRef( GetSheet(), newtext );
}
}
else
{
if( fieldNdx == REFERENCE )
{
DisplayError( this, _( "Reference needed !, No change" ) );
DisplayError( this, _( "The reference field cannot be empty! No change" ) );
}
else if( fieldNdx == VALUE )
{
DisplayError( this, _( "Value needed !, No change" ) );
DisplayError( this, _( "The value field cannot be empty! No change" ) );
}
else
{
Field->m_Text = wxT( "~" );
aField->m_Text = wxT( "~" );
}
}
Field->Draw( DrawPanel, DC, wxPoint( 0, 0 ), g_XorMode );
Cmp->DisplayInfo( this );
aField->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
component->DisplayInfo( this );
OnModify();
}
......@@ -284,12 +277,12 @@ void SCH_EDIT_FRAME::RotateCmpField( SCH_FIELD* Field, wxDC* DC )
/****************************************************************************/
void SCH_EDIT_FRAME::EditComponentReference( SCH_COMPONENT* Cmp, wxDC* DC )
{
wxCHECK_RET( Cmp != NULL && Cmp->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic component item." ) );
LIB_COMPONENT* Entry;
int flag = 0;
if( Cmp == NULL )
return;
Entry = CMP_LIBRARY::FindLibraryComponent( Cmp->GetLibName() );
if( Entry == NULL )
......@@ -331,12 +324,12 @@ void SCH_EDIT_FRAME::EditComponentReference( SCH_COMPONENT* Cmp, wxDC* DC )
/*****************************************************************************/
void SCH_EDIT_FRAME::EditComponentValue( SCH_COMPONENT* Cmp, wxDC* DC )
{
wxCHECK_RET( Cmp != NULL && Cmp->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic component item." ) );
wxString message;
LIB_COMPONENT* Entry;
if( Cmp == NULL )
return;
Entry = CMP_LIBRARY::FindLibraryComponent( Cmp->GetLibName() );
if( Entry == NULL )
......@@ -373,12 +366,12 @@ void SCH_EDIT_FRAME::EditComponentValue( SCH_COMPONENT* Cmp, wxDC* DC )
void SCH_EDIT_FRAME::EditComponentFootprint( SCH_COMPONENT* Cmp, wxDC* DC )
{
wxCHECK_RET( Cmp != NULL && Cmp->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic component item." ) );
wxString message;
LIB_COMPONENT* Entry;
if( Cmp == NULL )
return;
Entry = CMP_LIBRARY::FindLibraryComponent( Cmp->GetLibName() );
if( Entry == NULL )
......
......@@ -78,19 +78,7 @@ void SCH_EDIT_FRAME::StartMoveTexte( SCH_TEXT* aTextItem, wxDC* aDC )
void SCH_EDIT_FRAME::ChangeTextOrient( SCH_TEXT* aTextItem, wxDC* aDC )
{
if( aTextItem == NULL )
aTextItem = (SCH_TEXT*) GetScreen()->GetItem( GetScreen()->GetCrossHairPosition(), 0,
TEXT_T | LABEL_T );
if( aTextItem == NULL )
return;
/* save old text in undo list if is not already in edit */
if( aTextItem->GetFlags() == 0 )
SaveCopyInUndoList( aTextItem, UR_CHANGED );
/* Erase old text */
DrawPanel->CrossHairOff( aDC );
aTextItem->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
wxCHECK_RET( aTextItem != NULL, wxT( "Invalid schematic text item." ) );
int orient;
......@@ -100,15 +88,22 @@ void SCH_EDIT_FRAME::ChangeTextOrient( SCH_TEXT* aTextItem, wxDC* aDC )
case SCH_GLOBAL_LABEL_T:
case SCH_HIERARCHICAL_LABEL_T:
case SCH_TEXT_T:
orient = aTextItem->GetOrientation() + 1;
orient &= 3;
aTextItem->SetOrientation( orient );
orient = ( aTextItem->GetOrientation() + 1 ) & 3;
break;
default:
break;
wxFAIL_MSG( wxT( "Invalid schematic item <" ) + aTextItem->GetClass() +
wxT( "> passed to SCH_EDIT_FRAME::ChangeTextOrient()" ) );
return;
}
// Save current text orientation in undo list if is not already in edit.
if( aTextItem->GetFlags() == 0 )
SaveCopyInUndoList( aTextItem, UR_CHANGED );
DrawPanel->CrossHairOff( aDC );
aTextItem->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
aTextItem->SetOrientation( orient );
OnModify();
aTextItem->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
DrawPanel->CrossHairOn( aDC );
......
......@@ -4,6 +4,15 @@
#include "id.h"
/**
* The maximum number of items in the clarify selection context menu. It is
* highly unlikely that there would ever be more than 10 items at the current
* cursor. Increase this number if that ever becomes a problem.
*/
#define MAX_SELECT_ITEM_IDS 10
/**
* Command IDs for the schematic editor.
*
......@@ -138,6 +147,9 @@ enum id_eeschema_frm
ID_POPUP_SCH_ROTATE_CMP_COUNTERCLOCKWISE,
ID_POPUP_SCH_ORIENT_NORMAL_CMP,
ID_SCH_SELECT_ITEM_START,
ID_SCH_SELECT_ITEM_END = ID_SCH_SELECT_ITEM_START + MAX_SELECT_ITEM_IDS,
// Schematic editor commmands. These are command IDs that are generated by multiple
// events (menus, toolbar, context menu, etc.) that result in the same event handler.
ID_CANCEL_CURRENT_COMMAND,
......
......@@ -247,18 +247,12 @@ static void ShowWhileMoving( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& a
void SCH_EDIT_FRAME::OnChangeComponentOrientation( wxCommandEvent& aEvent )
{
SCH_SCREEN* screen = GetScreen();
SCH_ITEM* item = screen->GetCurItem();
// Ensure the struct is a component (could be a struct of a
// component, like Field, text..)
if( screen->GetCurItem() == NULL || screen->GetCurItem()->Type() != SCH_COMPONENT_T )
{
screen->SetCurItem( LocateSmallestComponent( screen ) );
if( screen->GetCurItem() == NULL || screen->GetCurItem()->Type() != SCH_COMPONENT_T )
return;
}
wxCHECK_RET( item != NULL && item->Type() == SCH_COMPONENT_T,
wxT( "Cannot change orientation of invalid schematic item." ) );
SCH_COMPONENT* component = (SCH_COMPONENT*) screen->GetCurItem();
SCH_COMPONENT* component = (SCH_COMPONENT*) item;
int orientation;
......@@ -287,8 +281,8 @@ void SCH_EDIT_FRAME::OnChangeComponentOrientation( wxCommandEvent& aEvent )
DrawPanel->MoveCursorToCrossHair();
if( screen->GetCurItem()->GetFlags() == 0 )
SaveCopyInUndoList( screen->GetCurItem(), UR_CHANGED );
if( component->GetFlags() == 0 )
SaveCopyInUndoList( item, UR_CHANGED );
INSTALL_UNBUFFERED_DC( dc, DrawPanel );
......@@ -348,28 +342,16 @@ static void ExitPlaceCmp( EDA_DRAW_PANEL* Panel, wxDC* DC )
void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
{
SCH_SCREEN* screen = GetScreen();
SCH_ITEM* item = screen->GetCurItem();
if( screen->GetCurItem() == NULL )
return;
wxCHECK_RET( item != NULL && item->Type() == SCH_COMPONENT_T,
wxT( "Cannot select unit of invalid schematic item." ) );
INSTALL_UNBUFFERED_DC( dc, DrawPanel );
// Verify the selected item is a component, it may be part of a component such as a field
// or text item.
if( screen->GetCurItem()->Type() != SCH_COMPONENT_T )
{
screen->SetCurItem( LocateSmallestComponent( screen ) );
if( screen->GetCurItem() == NULL )
return;
}
DrawPanel->MoveCursorToCrossHair();
SCH_COMPONENT* component = (SCH_COMPONENT*) screen->GetCurItem();
wxCHECK_RET( (component != NULL) && (component->Type() == SCH_COMPONENT_T),
wxT( "Cannot select unit for invalid component." ) );
SCH_COMPONENT* component = (SCH_COMPONENT*) item;
int unit = aEvent.GetId() + 1 - ID_POPUP_SCH_SELECT_UNIT1;
......@@ -414,7 +396,7 @@ void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
else
component->Draw( DrawPanel, &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
GetScreen()->TestDanglingEnds( DrawPanel, &dc );
screen->TestDanglingEnds( DrawPanel, &dc );
OnModify();
}
......
This diff is collapsed.
......@@ -11,6 +11,7 @@
#include "drawtxt.h"
#include "plot_common.h"
#include "wxEeschemaStruct.h"
#include "bitmaps.h"
#include "general.h"
#include "protos.h"
......@@ -18,8 +19,8 @@
#include "class_libentry.h"
#include "lib_pin.h"
#include "transform.h"
#include "sch_component.h"
#include "bitmaps.h"
/**
* Note: The following name lists are sentence capitalized per the GNOME UI
......@@ -1875,6 +1876,20 @@ const char*** LIB_PIN::GetStyleSymbols()
return s_icons_Pins_Shapes;
}
const char** LIB_PIN::GetMenuImage() const
{
return s_icons_Pins_Electrical_Type[m_type];
}
wxString LIB_PIN::GetSelectMenuText() const
{
wxString tmp = _( "Pin " );
return tmp << GetNumberString() << wxT( ", " ) << GetTypeString() << wxT( ", " )
<< wxGetTranslation( pin_style_names[ GetStyleCodeIndex( m_shape ) ] );;
}
#if defined(DEBUG)
......
......@@ -9,6 +9,8 @@
#include "lib_draw_item.h"
class SCH_COMPONENT;
#define TARGET_PIN_DIAM 12 /* Circle diameter drawn at the active end of pins */
......@@ -134,12 +136,15 @@ public:
virtual bool Save( FILE* aFile );
virtual bool Load( char* aLine, wxString& aErrorMsg );
/**
* Test if the given point is within the bounds of this object.
*
* Function HitTest
* verifies that \a aRefPos within the bounds of this pin attached to \a aComponent.
* <p>
* The coordinates of the pin are calculated relative to \a aComponent if not NULL.
* Otherwise, the pin coordinates are relative to the library anchor position.
* </p>
* @param aRefPos A wxPoint to test
* @return - true if a hit, else false
* @return True \a aRefPos lies within the pin bounding box else false.
*/
virtual bool HitTest( const wxPoint& aRefPos );
......@@ -445,6 +450,10 @@ public:
*/
static const char*** GetElectricalTypeSymbols();
virtual const char** GetMenuImage() const;
virtual wxString GetSelectMenuText() const;
protected:
virtual LIB_DRAW_ITEM* DoGenCopy();
......
/******************************************************/
/* Routines for locating an element of a schematic. */
/******************************************************/
#include "fctsys.h"
#include "common.h"
#include "trigo.h"
#include "macros.h"
#include "class_sch_screen.h"
#include "general.h"
#include "protos.h"
#include "class_library.h"
#include "sch_bus_entry.h"
#include "sch_marker.h"
#include "sch_junction.h"
#include "sch_component.h"
#include "sch_line.h"
#include "sch_no_connect.h"
#include "sch_polyline.h"
#include "sch_sheet.h"
#include "lib_pin.h"
#include "template_fieldnames.h"
/**
* Search the smaller (considering its area) component under the mouse
* cursor or the pcb cursor
*
* If more than 1 component is found, a pointer to the smaller component is
* returned
*/
SCH_COMPONENT* LocateSmallestComponent( SCH_SCREEN* Screen )
{
double area = 0.0; // Quiet compiler
EDA_Rect rect;
PICKED_ITEMS_LIST itemList;
SCH_COMPONENT* component = NULL;
SCH_COMPONENT* lastcomponent = NULL;
if( Screen->GetItems( Screen->RefPos( true ), itemList, COMPONENT_T ) == 0 )
{
if( Screen->GetItems( Screen->GetCrossHairPosition(), itemList, COMPONENT_T ) == 0 )
return NULL;
}
if( itemList.GetCount() == 1 )
return (SCH_COMPONENT*) itemList.GetPickedItem( 0 );
for( size_t i = 0; i < itemList.GetCount(); i++ )
{
component = (SCH_COMPONENT*) itemList.GetPickedItem( i );
if( lastcomponent == NULL ) // First component
{
lastcomponent = component;
rect = lastcomponent->GetBoundingBox();
area = ABS( (double) rect.GetWidth() * (double) rect.GetHeight() );
}
else
{
rect = component->GetBoundingBox();
double tmp = ABS( (double) rect.GetWidth() * (double) rect.GetHeight() );
if( area > tmp ) // a smaller component is found
{
area = tmp;
lastcomponent = component;
}
}
}
return lastcomponent;
}
......@@ -80,9 +80,9 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
if( ( item && item->GetFlags() ) || ( g_RootSheet->CountSheets() == 0 ) )
break;
item = LocateAndShowItem( aPosition );
item = LocateAndShowItem( aPosition, SCH_COLLECTOR::SheetsOnly );
if( item && ( item->Type() == SCH_SHEET_T ) )
if( item )
{
m_CurrentSheet->Push( (SCH_SHEET*) item );
DisplayCurrentSheet();
......@@ -241,7 +241,7 @@ void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
case ID_IMPORT_HLABEL_BUTT:
case ID_SHEET_LABEL_BUTT:
if( ( item == NULL ) || ( item->GetFlags() == 0 ) )
item = LocateAndShowItem( aPosition );
item = LocateAndShowItem( aPosition, SCH_COLLECTOR::SheetsAndSheetLabels );
if( item == NULL )
break;
......@@ -345,7 +345,7 @@ void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition )
break;
case SCH_FIELD_T:
EditCmpFieldText( (SCH_FIELD*) item, aDC );
EditComponentFieldText( (SCH_FIELD*) item, aDC );
DrawPanel->MoveCursorToCrossHair();
break;
......
......@@ -50,7 +50,7 @@ static void AddMenusForMarkers( wxMenu* aPopMenu, SCH_MARKER* aMarker, SCH_EDIT_
*/
bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
{
SCH_ITEM* DrawStruct = (SCH_ITEM*) GetScreen()->GetCurItem();
SCH_ITEM* item = GetScreen()->GetCurItem();
bool BlockActive = GetScreen()->IsBlockActive();
// Do not start a block command on context menu.
......@@ -64,24 +64,22 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
}
// Try to locate items at cursor position.
if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) )
if( (item == NULL) || (item->GetFlags() == 0) )
{
DrawStruct = LocateAndShowItem( aPosition, false );
item = LocateAndShowItem( aPosition, SCH_COLLECTOR::AllItemsButPins );
if( DrawStruct && (DrawStruct->Type() == SCH_SHEET_T) )
// If the clarify item selection context menu is aborted, don't show the context menu.
if( item == NULL && DrawPanel->m_AbortRequest )
{
SCH_SHEET* sheet = (SCH_SHEET*) DrawStruct;
SCH_SHEET_PIN* slabel = sheet->GetLabel( GetScreen()->GetCrossHairPosition() );
if( slabel )
DrawStruct = slabel;
DrawPanel->m_AbortRequest = false;
return false;
}
}
// If Command in progress: add "cancel" and "end tool" menu
if( GetToolId() != ID_NO_TOOL_SELECTED )
{
if( DrawStruct && DrawStruct->GetFlags() )
if( item && item->GetFlags() )
{
ADD_MENUITEM( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "Cancel" ), cancel_xpm );
}
......@@ -93,29 +91,25 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
}
else
{
if( DrawStruct && DrawStruct->GetFlags() )
if( item && item->GetFlags() )
{
ADD_MENUITEM( PopMenu, ID_CANCEL_CURRENT_COMMAND, _( "Cancel" ), cancel_xpm );
PopMenu->AppendSeparator();
}
}
if( DrawStruct == NULL )
if( item == NULL )
{
if( GetSheet()->Last() != g_RootSheet )
{
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_LEAVE_SHEET, _( "Leave Sheet" ), leave_sheet_xpm );
PopMenu->AppendSeparator();
}
return true;
}
GetScreen()->SetCurItem( DrawStruct );
int flags = DrawStruct->GetFlags();
bool is_new = (flags & IS_NEW) ? TRUE : FALSE;
int flags = item->GetFlags();
bool is_new = (flags & IS_NEW) ? true : false;
switch( DrawStruct->Type() )
switch( item->Type() )
{
case SCH_NO_CONNECT_T:
......@@ -123,7 +117,7 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
break;
case SCH_JUNCTION_T:
AddMenusForJunction( PopMenu, (SCH_JUNCTION*) DrawStruct, this );
AddMenusForJunction( PopMenu, (SCH_JUNCTION*) item, this );
break;
case SCH_BUS_ENTRY_T:
......@@ -134,7 +128,7 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_MOVE_ITEM_REQUEST, msg, move_xpm );
}
if( GetBusEntryShape( (SCH_BUS_ENTRY*) DrawStruct ) == '\\' )
if( GetBusEntryShape( (SCH_BUS_ENTRY*) item ) == '\\' )
PopMenu->Append( ID_POPUP_SCH_ENTRY_SELECT_SLASH, _( "Set Bus Entry /" ) );
else
PopMenu->Append( ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH, _( "Set Bus Entry \\" ) );
......@@ -142,57 +136,42 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
break;
case SCH_MARKER_T:
AddMenusForMarkers( PopMenu, (SCH_MARKER*) DrawStruct, this );
AddMenusForMarkers( PopMenu, (SCH_MARKER*) item, this );
break;
case SCH_TEXT_T:
AddMenusForText( PopMenu, (SCH_TEXT*) DrawStruct );
AddMenusForText( PopMenu, (SCH_TEXT*) item );
break;
case SCH_LABEL_T:
AddMenusForLabel( PopMenu, (SCH_LABEL*) DrawStruct );
AddMenusForLabel( PopMenu, (SCH_LABEL*) item );
break;
case SCH_GLOBAL_LABEL_T:
AddMenusForGLabel( PopMenu, (SCH_GLOBALLABEL*) DrawStruct );
AddMenusForGLabel( PopMenu, (SCH_GLOBALLABEL*) item );
break;
case SCH_HIERARCHICAL_LABEL_T:
AddMenusForHLabel( PopMenu, (SCH_HIERLABEL*) DrawStruct );
AddMenusForHLabel( PopMenu, (SCH_HIERLABEL*) item );
break;
case SCH_FIELD_T:
{
AddMenusForComponentField( PopMenu, (SCH_FIELD*) DrawStruct );
if( flags )
break;
// Many fields are inside a component. If this is the case, add the
// component menu
SCH_COMPONENT* Component = LocateSmallestComponent( GetScreen() );
if( Component )
{
PopMenu->AppendSeparator();
AddMenusForComponent( PopMenu, Component );
}
}
AddMenusForComponentField( PopMenu, (SCH_FIELD*) item );
break;
case SCH_COMPONENT_T:
AddMenusForComponent( PopMenu, (SCH_COMPONENT*) DrawStruct );
AddMenusForComponent( PopMenu, (SCH_COMPONENT*) item );
break;
case SCH_LINE_T:
switch( DrawStruct->GetLayer() )
switch( item->GetLayer() )
{
case LAYER_WIRE:
AddMenusForWire( PopMenu, (SCH_LINE*) DrawStruct, this );
AddMenusForWire( PopMenu, (SCH_LINE*) item, this );
break;
case LAYER_BUS:
AddMenusForBus( PopMenu, (SCH_LINE*) DrawStruct, this );
AddMenusForBus( PopMenu, (SCH_LINE*) item, this );
break;
default:
......@@ -204,17 +183,17 @@ bool SCH_EDIT_FRAME::OnRightClick( const wxPoint& aPosition, wxMenu* PopMenu )
break;
case SCH_SHEET_T:
AddMenusForHierchicalSheet( PopMenu, (SCH_SHEET*) DrawStruct );
AddMenusForHierchicalSheet( PopMenu, (SCH_SHEET*) item );
break;
case SCH_SHEET_LABEL_T:
AddMenusForPinSheet( PopMenu, (SCH_SHEET_PIN*) DrawStruct );
AddMenusForPinSheet( PopMenu, (SCH_SHEET_PIN*) item );
break;
default:
wxString msg;
msg.Printf( wxT( "SCH_EDIT_FRAME::OnRightClick Error: unknown DrawType %d" ),
DrawStruct->Type() );
item->Type() );
DisplayError( this, msg );
break;
}
......@@ -495,15 +474,14 @@ void AddMenusForJunction( wxMenu* PopMenu, SCH_JUNCTION* Junction, SCH_EDIT_FRAM
if( !is_new )
{
if( screen->GetItem( screen->GetCrossHairPosition(), 0,
WIRE_T | BUS_T | EXCLUDE_ENDPOINTS_T ) )
if( screen->GetWire( screen->GetCrossHairPosition(), EXCLUDE_END_POINTS_T ) )
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Wire" ), break_line_xpm );
}
msg = AddHotkeyName( _( "Delete Junction" ), s_Schematic_Hokeys_Descr, HK_DELETE );
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_DELETE, msg, delete_xpm );
if( screen->GetItem( screen->GetCrossHairPosition(), 0, WIRE_T | BUS_T ) )
if( screen->GetWireOrBus( screen->GetCrossHairPosition() ) )
{
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_DELETE_NODE, _( "Delete Node" ), delete_node_xpm );
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_DELETE_CONNECTION, _( "Delete Connection" ),
......@@ -534,8 +512,9 @@ void AddMenusForWire( wxMenu* PopMenu, SCH_LINE* Wire, SCH_EDIT_FRAME* frame )
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_DELETE_CONNECTION, _( "Delete Connection" ),
delete_connection_xpm );
if( screen->GetItem( screen->GetCrossHairPosition(), 0,
WIRE_T | BUS_T | EXCLUDE_ENDPOINTS_T ) )
SCH_LINE* line = screen->GetWireOrBus( screen->GetCrossHairPosition() );
if( line && !line->IsEndPoint( screen->GetCrossHairPosition() ) )
ADD_MENUITEM( PopMenu, ID_POPUP_SCH_BREAK_WIRE, _( "Break Wire" ), break_line_xpm );
PopMenu->AppendSeparator();
......
......@@ -67,12 +67,6 @@ void DeleteItemsInList( EDA_DRAW_PANEL* panel, PICKED_ITEMS_LIST& aItemsList );
*/
SCH_ITEM* DuplicateStruct( SCH_ITEM* DrawStruct, bool aClone = false );
/*************/
/* LOCATE.CPP */
/*************/
SCH_COMPONENT* LocateSmallestComponent( SCH_SCREEN* Screen );
/***************/
/* EEREDRAW.CPP */
......
......@@ -224,11 +224,17 @@ void SCH_BUS_ENTRY::GetConnectionPoints( vector< wxPoint >& aPoints ) const
}
bool SCH_BUS_ENTRY::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_BUS_ENTRY::GetSelectMenuText() const
{
if( !( aFilter & BUS_ENTRY_T ) )
return false;
if( m_Layer == LAYER_WIRE )
return wxString( _( "Bus to Wire Entry" ) );
return wxString( _( "Bus to Bus Entry" ) );
}
bool SCH_BUS_ENTRY::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return TestSegmentHit( aPoint, m_Pos, m_End(), aAccuracy );
}
......
......@@ -107,8 +107,12 @@ public:
virtual void GetConnectionPoints( vector< wxPoint >& aPoints ) const;
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_entry_xpm; }
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2011 Kicad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "general.h"
#include "transform.h"
#include "sch_collectors.h"
#include "sch_component.h"
#include "sch_line.h"
const KICAD_T SCH_COLLECTOR::AllItems[] = {
SCH_MARKER_T,
SCH_JUNCTION_T,
SCH_NO_CONNECT_T,
SCH_BUS_ENTRY_T,
SCH_LINE_T,
SCH_POLYLINE_T,
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
LIB_PIN_T,
SCH_SHEET_LABEL_T,
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::AllItemsButPins[] = {
SCH_MARKER_T,
SCH_JUNCTION_T,
SCH_NO_CONNECT_T,
SCH_BUS_ENTRY_T,
SCH_LINE_T,
SCH_POLYLINE_T,
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
SCH_SHEET_LABEL_T,
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::EditableItems[] = {
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
SCH_SHEET_LABEL_T,
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::MovableItems[] = {
SCH_MARKER_T,
// SCH_JUNCTION_T,
SCH_NO_CONNECT_T,
SCH_BUS_ENTRY_T,
// SCH_LINE_T,
SCH_POLYLINE_T,
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
SCH_SHEET_LABEL_T,
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::DraggableItems[] = {
SCH_JUNCTION_T,
SCH_BUS_ENTRY_T,
SCH_LINE_T,
SCH_POLYLINE_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_COMPONENT_T,
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::RotatableItems[] = {
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
EOT
};
const KICAD_T SCH_COLLECTOR::ParentItems[] = {
SCH_MARKER_T,
SCH_JUNCTION_T,
SCH_NO_CONNECT_T,
SCH_BUS_ENTRY_T,
SCH_LINE_T,
SCH_POLYLINE_T,
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_COMPONENT_T,
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::ComponentsOnly[] = {
SCH_COMPONENT_T,
EOT
};
const KICAD_T SCH_COLLECTOR::SheetsOnly[] = {
SCH_SHEET_T,
EOT
};
const KICAD_T SCH_COLLECTOR::SheetsAndSheetLabels[] = {
SCH_SHEET_LABEL_T,
SCH_SHEET_T,
EOT
};
SEARCH_RESULT SCH_COLLECTOR::Inspect( EDA_ITEM* aItem, const void* aTestData )
{
if( aItem->Type() != LIB_PIN_T && !aItem->HitTest( m_RefPos ) )
return SEARCH_CONTINUE;
// Pins have special hit testing requirements that are relative to their parent
// SCH_COMPONENT item.
if( aItem->Type() == LIB_PIN_T )
{
wxCHECK_MSG( aTestData && ( (EDA_ITEM*) aTestData )->Type() == SCH_COMPONENT_T,
SEARCH_CONTINUE, wxT( "Cannot inspect invalid data. Bad programmer!" ) );
// Pin hit testing is relative to the components position and orientation in the
// schematic. The hit test position must be converted to library coordinates.
SCH_COMPONENT* component = (SCH_COMPONENT*) aTestData;
TRANSFORM transform = component->GetTransform().InverseTransform();
wxPoint position = transform.TransformCoordinate( m_RefPos - component->m_Pos );
position.y *= -1; // Y axis polarity in schematic is inverted from library.
if( !aItem->HitTest( position ) )
return SEARCH_CONTINUE;
}
Append( aItem );
return SEARCH_CONTINUE;
}
void SCH_COLLECTOR::Collect( SCH_ITEM* aItem, const KICAD_T aFilterList[],
const wxPoint& aPosition )
{
Empty(); // empty the collection just in case
SetScanTypes( aFilterList );
// remember where the snapshot was taken from and pass refPos to the Inspect() function.
SetRefPos( aPosition );
EDA_ITEM::IterateForward( aItem, this, NULL, m_ScanTypes );
}
bool SCH_COLLECTOR::IsCorner() const
{
if( GetCount() != 2 )
return false;
if( (m_List[0]->Type() == SCH_LINE_T) && (m_List[1]->Type() == SCH_LINE_T) )
return true;
if( (m_List[0]->Type() == SCH_LINE_T) && (m_List[1]->Type() == SCH_BUS_ENTRY_T) )
return true;
if( (m_List[0]->Type() == SCH_BUS_ENTRY_T) && (m_List[1]->Type() == SCH_LINE_T) )
return true;
return false;
}
bool SCH_COLLECTOR::IsNode( bool aIncludePins ) const
{
for( size_t i = 0; i < m_List.size(); i++ )
{
SCH_ITEM* item = (SCH_ITEM*) m_List[ i ];
KICAD_T type = item->Type();
if( type == SCH_JUNCTION_T )
continue;
if( type == SCH_LINE_T )
{
if( item->GetLayer() != LAYER_WIRE )
return false;
continue;
}
if( type == LIB_PIN_T )
{
if( !aIncludePins )
return false;
continue;
}
// Any other item types indicate that this collection is not a node.
return false;
}
return true;
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-20011 Kicad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _SCH_COLLECTORS_H_
#define _SCH_COLLECTORS_H_
#include "class_collector.h"
#include "sch_item_struct.h"
/**
* Class SCH_COLLECTOR
*/
class SCH_COLLECTOR : public COLLECTOR
{
public:
/**
* A scan list for all schematic items.
*/
static const KICAD_T AllItems[];
/**
* A scan list for all editable schematic items.
*/
static const KICAD_T EditableItems[];
/**
* A scan list for all movable schematic items.
*/
static const KICAD_T MovableItems[];
/**
* A scan list for all draggable schematic items.
*/
static const KICAD_T DraggableItems[];
/**
* A scan list for all rotatable schematic items.
*/
static const KICAD_T RotatableItems[];
/**
* A scan list for only parent schematic items.
*/
static const KICAD_T ParentItems[];
/**
* A scan list for all schematic items except pins.
*/
static const KICAD_T AllItemsButPins[];
/**
* A scan list for schematic component items only.
*/
static const KICAD_T ComponentsOnly[];
/**
* A scan list for schematic sheet items only.
*/
static const KICAD_T SheetsOnly[];
/**
* A scan list for schematic sheet and sheet label items.
*/
static const KICAD_T SheetsAndSheetLabels[];
/**
* Constructor SCH_COLLECTOR
*/
SCH_COLLECTOR( const KICAD_T* aScanTypes = SCH_COLLECTOR::AllItems )
{
SetScanTypes( aScanTypes );
}
/**
* Operator []
* overloads COLLECTOR::operator[](int) to return a SCH_ITEM* instead of
* an EDA_ITEM* type.
* @param aIndex The index into the list.
* @return SCH_ITEM* at \a aIndex or NULL.
*/
SCH_ITEM* operator[]( int aIndex ) const
{
if( (unsigned)aIndex < (unsigned)GetCount() )
return (SCH_ITEM*) m_List[ aIndex ];
return NULL;
}
/**
* Function Inspect
* is the examining function within the INSPECTOR which is passed to the
* Iterate function.
*
* @param aItem An EDA_ITEM to examine.
* @param aTestData is not used in this class.
* @return SEARCH_RESULT #SEARCH_QUIT if the iterator is to stop the scan,
* else #SEARCH_CONTINUE;
*/
SEARCH_RESULT Inspect( EDA_ITEM* aItem, const void* aTestData = NULL );
/**
* Function Collect
* scans a SCH_ITEM using this class's Inspector method, which does the collection.
* @param aItem A SCH_ITEM to scan.
* @param aFilterList A list of #KICAD_T types with a terminating #EOT, that determines
* what is to be collected and the priority order of the resulting
* collection.
* @param aPosition A wxPoint to use in hit-testing.
*/
void Collect( SCH_ITEM* aItem, const KICAD_T aScanList[], const wxPoint& aPositiion );
/**
* Function IsCorner
* tests if the collected items forms as corner of two line segments.
* @return True if the collected items form a corner of two line segments.
*/
bool IsCorner() const;
/**
* Function IsNode
* tests if the collected items form a node.
*
* @param aIncludePins Indicate if component pin items should be included in the test.
* @return True if the collected items form a node.
*/
bool IsNode( bool aIncludePins = true ) const;
};
#endif // _SCH_COLLECTORS_H_
......@@ -326,22 +326,6 @@ void SCH_COMPONENT::AddHierarchicalReference( const wxString& aPath,
}
wxString SCH_COMPONENT::ReturnFieldName( int aFieldNdx ) const
{
SCH_FIELD* field = GetField( aFieldNdx );
if( field )
{
if( !field->m_Name.IsEmpty() )
return field->m_Name;
else
return TEMPLATE_FIELDNAME::GetDefaultFieldName( aFieldNdx );
}
return wxEmptyString;
}
wxString SCH_COMPONENT::GetPath( SCH_SHEET_PATH* sheet )
{
wxString str;
......@@ -865,7 +849,7 @@ void SCH_COMPONENT::Show( int nestLevel, std::ostream& os )
{
// for now, make it look like XML:
NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
<< " ref=\"" << TO_UTF8( ReturnFieldName( 0 ) )
<< " ref=\"" << TO_UTF8( GetField( 0 )->GetName() )
<< '"' << " chipName=\""
<< TO_UTF8( m_ChipName ) << '"' << m_Pos
<< " layer=\"" << m_Layer
......@@ -879,7 +863,7 @@ void SCH_COMPONENT::Show( int nestLevel, std::ostream& os )
if( !value.IsEmpty() )
{
NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
<< TO_UTF8( ReturnFieldName( i ) )
<< TO_UTF8( GetField( i )->GetName() )
<< '"' << " value=\""
<< TO_UTF8( value ) << "\"/>\n";
}
......@@ -1405,18 +1389,7 @@ EDA_Rect SCH_COMPONENT::GetBodyBoundingBox() const
EDA_Rect SCH_COMPONENT::GetBoundingBox() const
{
EDA_Rect bBox = GetBodyBoundingBox();
// Include BoundingBoxes of fields if they are visible and not empty.
for( int ii = 0; ii < GetFieldCount(); ii++ )
{
if( !GetField( ii )->IsVisible() || GetField( ii )->IsVoid() )
continue;
bBox.Merge( GetField( ii )->GetBoundingBox() );
}
return bBox;
return GetBodyBoundingBox();
}
......@@ -1672,34 +1645,88 @@ LIB_DRAW_ITEM* SCH_COMPONENT::GetDrawItem( const wxPoint& aPosition, KICAD_T aTy
}
bool SCH_COMPONENT::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_COMPONENT::GetSelectMenuText() const
{
EDA_Rect bBox;
wxString tmp = _( "Component " );
return tmp << m_ChipName << wxT( ", " ) << GetField( REFERENCE )->GetText();
}
if( aFilter & FIELD_T )
SEARCH_RESULT SCH_COMPONENT::Visit( INSPECTOR* aInspector, const void* aTestData,
const KICAD_T aFilterTypes[] )
{
KICAD_T stype;
for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
{
// If caller wants to inspect component type or and component children types.
if( stype == Type() )
{
if( SEARCH_QUIT == aInspector->Inspect( this, aTestData ) )
return SEARCH_QUIT;
}
else if( stype == SCH_FIELD_T )
{
// Test the bounding boxes of fields if they are visible and not empty.
for( int ii = 0; ii < GetFieldCount(); ii++ )
{
if( !GetField( ii )->IsVisible() || GetField( ii )->IsVoid() )
continue;
if( SEARCH_QUIT == aInspector->Inspect( GetField( ii ), aTestData ) )
return SEARCH_QUIT;
}
}
else if( stype == LIB_PIN_T )
{
LIB_COMPONENT* component = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
bBox = GetField( ii )->GetBoundingBox();
bBox.Inflate( aAccuracy );
if( component != NULL )
{
LIB_PIN_LIST pins;
if( bBox.Contains( aPoint ) )
return true;
component->GetPins( pins, m_unit, m_convert );
for( size_t i = 0; i < pins.size(); i++ )
{
if( SEARCH_QUIT == aInspector->Inspect( pins[ i ], (void*) this ) )
return SEARCH_QUIT;
}
}
}
}
if( aFilter & COMPONENT_T )
{
bBox = GetBodyBoundingBox();
return SEARCH_CONTINUE;
}
bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
{
if( Type() != aItem.Type() )
return Type() < aItem.Type();
SCH_COMPONENT* component = (SCH_COMPONENT*) &aItem;
EDA_Rect rect = GetBodyBoundingBox();
if( rect.GetArea() != component->GetBodyBoundingBox().GetArea() )
return rect.GetArea() < component->GetBodyBoundingBox().GetArea();
if( m_Pos.x != component->m_Pos.x )
return m_Pos.x < component->m_Pos.x;
if( m_Pos.y != component->m_Pos.y )
return m_Pos.y < component->m_Pos.y;
return false;
}
bool SCH_COMPONENT::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
EDA_Rect bBox = GetBodyBoundingBox();
bBox.Inflate( aAccuracy );
if( bBox.Contains( aPoint ) )
return true;
}
return false;
}
......
......@@ -193,13 +193,6 @@ public:
//-----<Fields>-----------------------------------------------------------
/**
* Function ReturnFieldName
* returns the Field name given a field index like (REFERENCE, VALUE ..)
* @return wxString - the field name or wxEmptyString if invalid field index.
*/
wxString ReturnFieldName( int aFieldNdx ) const;
/**
* Function GetField
* returns a field.
......@@ -353,6 +346,9 @@ public:
virtual void GetConnectionPoints( vector< wxPoint >& aPoints ) const;
virtual SEARCH_RESULT Visit( INSPECTOR* inspector, const void* testData,
const KICAD_T scanTypes[] );
/**
* Function GetDrawItem().
* Return the component library item at \a aPosition that is part of this component.
......@@ -362,6 +358,13 @@ public:
* @return A pointer to the component library object if found, otherwise NULL.
*/
LIB_DRAW_ITEM* GetDrawItem( const wxPoint& aPosition, KICAD_T aType = TYPE_NOT_INIT );
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_component_xpm; }
virtual bool operator <( const SCH_ITEM& aItem ) const;
#if defined(DEBUG)
/**
......@@ -376,7 +379,7 @@ public:
#endif
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual bool doIsConnected( const wxPoint& aPosition ) const;
virtual EDA_ITEM* doClone() const;
......
......@@ -447,10 +447,42 @@ void SCH_FIELD::Rotate( wxPoint rotationPoint )
}
bool SCH_FIELD::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_FIELD::GetSelectMenuText() const
{
wxString tmp = _( "Field " );
return tmp + GetName();
}
wxString SCH_FIELD::GetName() const
{
if( !m_Name.IsEmpty() )
return m_Name;
else
return TEMPLATE_FIELDNAME::GetDefaultFieldName( m_FieldId );
}
const char** SCH_FIELD::GetMenuImage() const
{
if( m_FieldId == REFERENCE )
return (const char**) edit_comp_ref_xpm;
if( m_FieldId == VALUE )
return (const char**) edit_comp_value_xpm;
if( m_FieldId == FOOTPRINT )
return (const char**) edit_comp_footprint_xpm;
return (const char**) edit_text_xpm;
}
bool SCH_FIELD::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
// Do not hit test hidden or empty fields.
if( !(aFilter & FIELD_T) || !IsVisible() || IsVoid() )
if( !IsVisible() || IsVoid() )
return false;
EDA_Rect rect = GetBoundingBox();
......@@ -464,7 +496,7 @@ bool SCH_FIELD::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aF
bool SCH_FIELD::doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const
{
// Do not hit test hidden fields.
if( !IsVisible() )
if( !IsVisible() || IsVoid() )
return false;
EDA_Rect rect = aRect;
......
......@@ -50,6 +50,16 @@ public:
return wxT( "SCH_FIELD" );
}
/**
* Function GetName
* returns the field name. If the field name is emply, the default field name is
* returned. Field names are VALUE, REFERENCE, etc.
* @return The name of the field.
*/
wxString GetName() const;
int GetId() const { return m_FieldId; }
void Place( SCH_EDIT_FRAME* frame, wxDC* DC );
EDA_Rect GetBoundingBox() const;
......@@ -161,10 +171,14 @@ public:
* @return True if this field text matches the search criteria.
*/
virtual bool Matches( wxFindReplaceData& aSearchData,
void* aAuxData, wxPoint * aFindLocation );
void* aAuxData, wxPoint* aFindLocation );
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const;
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......
......@@ -177,11 +177,8 @@ void SCH_JUNCTION::Show( int nestLevel, std::ostream& os )
#endif
bool SCH_JUNCTION::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
bool SCH_JUNCTION::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
if( !( aFilter & JUNCTION_T ) )
return false;
EDA_Rect rect = GetBoundingBox();
rect.Inflate( aAccuracy );
......
......@@ -91,12 +91,16 @@ public:
virtual void GetConnectionPoints( vector< wxPoint >& aPoints ) const;
virtual wxString GetSelectMenuText() const { return wxString( _( "Junction" ) ); }
virtual const char** GetMenuImage() const { return (const char**) add_junction_xpm; }
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os );
#endif
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual bool doIsConnected( const wxPoint& aPosition ) const;
virtual EDA_ITEM* doClone() const;
......
......@@ -108,6 +108,12 @@ EDA_Rect SCH_LINE::GetBoundingBox() const
}
double SCH_LINE::GetLength() const
{
return GetLineLength( m_Start, m_End );
}
bool SCH_LINE::Save( FILE* aFile ) const
{
bool success = true;
......@@ -411,31 +417,75 @@ void SCH_LINE::GetConnectionPoints( vector< wxPoint >& aPoints ) const
}
bool SCH_LINE::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_LINE::GetSelectMenuText() const
{
if( !( aFilter & ( DRAW_ITEM_T | WIRE_T | BUS_T ) ) )
return false;
wxString menuText;
if( ( ( aFilter & DRAW_ITEM_T ) && ( m_Layer == LAYER_NOTES ) )
|| ( ( aFilter & WIRE_T ) && ( m_Layer == LAYER_WIRE ) )
|| ( ( aFilter & BUS_T ) && ( m_Layer == LAYER_BUS ) ) )
switch( m_Layer )
{
if( !TestSegmentHit( aPoint, m_Start, m_End, aAccuracy ) )
return false;
case LAYER_NOTES:
menuText = _( "Graphic Line " );
break;
if( ( aFilter & EXCLUDE_ENDPOINTS_T ) && IsEndPoint( aPoint ) )
return false;
case LAYER_WIRE:
menuText = _( "Wire " );
break;
if( ( aFilter & ENDPOINTS_ONLY_T ) && !IsEndPoint( aPoint ) )
return false;
case LAYER_BUS:
menuText = _( "Bus " );
break;
return true;
default:
menuText = _( "Line on Unkown Layer " );
}
menuText << wxT( "from (" ) << CoordinateToString( m_Start.x, EESCHEMA_INTERNAL_UNIT )
<< wxT( "," ) << CoordinateToString( m_Start.y, EESCHEMA_INTERNAL_UNIT )
<< wxT( ")" );
menuText << wxT( " to (" ) << CoordinateToString( m_End.x, EESCHEMA_INTERNAL_UNIT )
<< wxT( "," ) << CoordinateToString( m_End.y, EESCHEMA_INTERNAL_UNIT ) << wxT( ")" );
return menuText;
}
const char** SCH_LINE::GetMenuImage() const
{
if( m_Layer == LAYER_NOTES )
return (const char**) add_dashed_line_xpm;
else if( m_Layer == LAYER_WIRE )
return (const char**) add_line_xpm;
return (const char**) add_bus_xpm;
}
bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
{
if( Type() != aItem.Type() )
return Type() < aItem.Type();
SCH_LINE* line = (SCH_LINE*) &aItem;
if( GetLength() != line->GetLength() )
return GetLength() < line->GetLength();
if( m_Start.x != line->m_Start.x )
return m_Start.x < line->m_Start.x;
if( m_Start.y != line->m_Start.y )
return m_Start.y < line->m_Start.y;
return false;
}
bool SCH_LINE::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return TestSegmentHit( aPoint, m_Start, m_End, aAccuracy );
}
bool SCH_LINE::doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const
{
EDA_Rect rect = aRect;
......
......@@ -54,6 +54,12 @@ public:
*/
EDA_Rect GetBoundingBox() const;
/**
* Function GetLength
* @return The length of the line segment.
*/
double GetLength() const;
virtual void Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aOffset,
int aDrawMode, int aColor = -1 );
......@@ -127,12 +133,18 @@ public:
virtual void GetConnectionPoints( vector< wxPoint >& aPoints ) const;
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const;
virtual bool operator <( const SCH_ITEM& aItem ) const;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const;
#endif
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual bool doIsConnected( const wxPoint& aPosition ) const;
virtual EDA_ITEM* doClone() const;
......
......@@ -195,11 +195,8 @@ bool SCH_MARKER::IsSelectStateChanged( const wxRect& aRect )
}
bool SCH_MARKER::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
bool SCH_MARKER::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
if( !( aFilter & MARKER_T ) )
return false;
return HitTestMarker( aPoint );
}
......@@ -97,12 +97,16 @@ public:
virtual bool IsSelectStateChanged( const wxRect& aRect );
virtual wxString GetSelectMenuText() const { return wxString( _( "ERC Marker" ) ); }
virtual const char** GetMenuImage() const { return (const char**) erc_xpm; }
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os );
#endif
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......
......@@ -157,11 +157,8 @@ bool SCH_NO_CONNECT::doIsConnected( const wxPoint& aPosition ) const
return m_Pos == aPosition;
}
bool SCH_NO_CONNECT::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
bool SCH_NO_CONNECT::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
if( !( aFilter & NO_CONNECT_T ) )
return false;
int delta = ( ( m_Size.x + g_DrawDefaultLineThickness ) / 2 ) + aAccuracy;
wxPoint dist = aPoint - m_Pos;
......
......@@ -94,9 +94,13 @@ public:
virtual void GetConnectionPoints( vector< wxPoint >& aPoints ) const;
virtual wxString GetSelectMenuText() const { return wxString( _( "No Connect" ) ); }
virtual const char** GetMenuImage() const { return (const char**) noconn_button; }
private:
virtual bool doIsConnected( const wxPoint& aPosition ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......
......@@ -205,11 +205,47 @@ void SCH_POLYLINE::Rotate( wxPoint rotationPoint )
}
bool SCH_POLYLINE::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_POLYLINE::GetSelectMenuText() const
{
if( !( aFilter & ( DRAW_ITEM_T | WIRE_T | BUS_T ) ) )
return false;
wxString menuText;
switch( m_Layer )
{
case LAYER_NOTES:
menuText = _( "Graphic Polyline " );
break;
case LAYER_WIRE:
menuText = _( "Polyline Wire " );
break;
case LAYER_BUS:
menuText = _( "Polyline Bus " );
break;
default:
menuText = _( "Polyline on Unkown Layer " );
}
menuText += wxString::Format( _( "with %d Points" ), m_PolyPoints.size() );
return menuText;
}
const char** SCH_POLYLINE::GetMenuImage() const
{
if( m_Layer == LAYER_NOTES )
return (const char**) add_dashed_line_xpm;
else if( m_Layer == LAYER_WIRE )
return (const char**) add_line_xpm;
return (const char**) add_bus_xpm;
}
bool SCH_POLYLINE::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
for( size_t i = 0; i < m_PolyPoints.size() - 1; i++ )
{
if( TestSegmentHit( aPoint, m_PolyPoints[i], m_PolyPoints[i + 1], aAccuracy ) )
......
......@@ -94,8 +94,12 @@ public:
virtual void Rotate( wxPoint rotationPoint );
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const;
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......
This diff is collapsed.
......@@ -965,11 +965,42 @@ void SCH_SHEET::GetConnectionPoints( vector< wxPoint >& aPoints ) const
}
bool SCH_SHEET::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
SEARCH_RESULT SCH_SHEET::Visit( INSPECTOR* aInspector, const void* aTestData,
const KICAD_T aFilterTypes[] )
{
if( !( aFilter & SHEET_T ) )
return false;
KICAD_T stype;
for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
{
// If caller wants to inspect my type
if( stype == Type() )
{
if( SEARCH_QUIT == aInspector->Inspect( this, aTestData ) )
return SEARCH_QUIT;
}
else if( stype == SCH_SHEET_LABEL_T )
{
// Test the bounding boxes of sheet labels.
for( size_t i = 0; i < m_labels.size(); i++ )
{
if( SEARCH_QUIT == aInspector->Inspect( &m_labels[ i ], aTestData ) )
return SEARCH_QUIT;
}
}
}
return SEARCH_CONTINUE;
}
wxString SCH_SHEET::GetSelectMenuText() const
{
return wxString( _( "Hierarchical Sheet " ) ) + m_SheetName;
}
bool SCH_SHEET::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
EDA_Rect rect = GetBoundingBox();
rect.Inflate( aAccuracy );
......
......@@ -49,6 +49,8 @@ private:
virtual EDA_ITEM* doClone() const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
public:
SCH_SHEET_PIN( SCH_SHEET* parent,
const wxPoint& pos = wxPoint( 0, 0 ),
......@@ -77,8 +79,7 @@ public:
* @param aCorner_list = a buffer to fill with polygon corners coordinates
* @param aPos = Position of the shape
*/
virtual void CreateGraphicShape( std::vector <wxPoint>& aCorner_list,
const wxPoint& aPos );
virtual void CreateGraphicShape( std::vector <wxPoint>& aCorner_list, const wxPoint& aPos );
void SwapData( SCH_SHEET_PIN* copyitem );
......@@ -184,6 +185,10 @@ public:
virtual void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList );
virtual bool IsConnectable() const { return true; }
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_hierar_pin_xpm; }
};
......@@ -486,13 +491,13 @@ public:
* Function GetSheetNamePosition
* @return the position of the anchor of sheet name text
*/
wxPoint GetSheetNamePosition ();
wxPoint GetSheetNamePosition();
/**
* Function GetFileNamePosition
* @return the position of the anchor of filename text
*/
wxPoint GetFileNamePosition ();
wxPoint GetFileNamePosition();
virtual void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList );
......@@ -506,6 +511,16 @@ public:
virtual void GetConnectionPoints( vector< wxPoint >& aPoints ) const;
virtual SEARCH_RESULT Visit( INSPECTOR* inspector, const void* testData,
const KICAD_T scanTypes[] );
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const
{
return (const char**) add_hierarchical_subsheet_xpm;
}
#if defined(DEBUG)
// comment inherited by Doxygen from Base_Struct
......@@ -525,7 +540,7 @@ protected:
void renumberLabels();
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......
......@@ -459,6 +459,22 @@ void SCH_SHEET_PIN::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
}
wxString SCH_SHEET_PIN::GetSelectMenuText() const
{
return wxString( _( "Hierarchical Sheet Label " ) ) + GetText();
}
bool SCH_SHEET_PIN::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
EDA_Rect rect = GetBoundingBox();
rect.Inflate( aAccuracy );
return rect.Contains( aPoint );
}
#if defined(DEBUG)
void SCH_SHEET_PIN::Show( int nestLevel, std::ostream& os )
......
......@@ -620,11 +620,20 @@ EDA_Rect SCH_TEXT::GetBoundingBox() const
}
bool SCH_TEXT::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_TEXT::GetSelectMenuText() const
{
if( !( aFilter & TEXT_T ) )
return false;
wxString tmp = GetText();
tmp.Replace( wxT( "\n" ), wxT( " " ) );
tmp.Replace( wxT( "\r" ), wxT( " " ) );
tmp.Replace( wxT( "\t" ), wxT( " " ) );
tmp =( tmp.Length() > 15 ) ? tmp.Left( 12 ) + wxT( "..." ) : tmp;
return wxString( _( "Graphic Text " ) ) + tmp;
}
bool SCH_TEXT::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return TextHitTest( aPoint, aAccuracy );
}
......@@ -846,11 +855,16 @@ EDA_Rect SCH_LABEL::GetBoundingBox() const
}
bool SCH_LABEL::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_LABEL::GetSelectMenuText() const
{
if( !( aFilter & LABEL_T ) )
return false;
wxString tmp = ( GetText().Length() > 15 ) ? GetText().Left( 12 ) + wxT( "..." ) : GetText();
return wxString( _( "Label " ) ) + tmp;
}
bool SCH_LABEL::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return TextHitTest( aPoint, aAccuracy );
}
......@@ -1272,11 +1286,16 @@ EDA_Rect SCH_GLOBALLABEL::GetBoundingBox() const
}
bool SCH_GLOBALLABEL::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_GLOBALLABEL::GetSelectMenuText() const
{
if( !( aFilter & LABEL_T ) )
return false;
wxString tmp = ( GetText().Length() > 15 ) ? GetText().Left( 12 ) + wxT( "..." ) : GetText();
return wxString( _( "Global Label " ) ) + tmp;
}
bool SCH_GLOBALLABEL::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return TextHitTest( aPoint, aAccuracy );
}
......@@ -1622,10 +1641,15 @@ void SCH_HIERLABEL::Rotate( wxPoint rotationPoint )
}
bool SCH_HIERLABEL::doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
wxString SCH_HIERLABEL::GetSelectMenuText() const
{
if( !( aFilter & LABEL_T ) )
return false;
wxString tmp = ( GetText().Length() > 15 ) ? GetText().Left( 12 ) + wxT( "..." ) : GetText();
return wxString( _( "Hierarchical Label " ) ) + tmp;
}
bool SCH_HIERLABEL::doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return TextHitTest( aPoint, aAccuracy );
}
......@@ -202,12 +202,16 @@ public:
virtual bool CanIncrementLabel() const { return true; }
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_text_xpm; }
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os );
#endif
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doHitTest( const EDA_Rect& aRect, bool aContained, int aAccuracy ) const;
virtual EDA_ITEM* doClone() const;
};
......@@ -292,8 +296,13 @@ public:
virtual bool IsConnectable() const { return true; }
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_line_label_xpm; }
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doIsConnected( const wxPoint& aPosition ) const { return m_Pos == aPosition; }
virtual EDA_ITEM* doClone() const;
};
......@@ -391,8 +400,13 @@ public:
virtual bool IsConnectable() const { return true; }
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_glabel_xpm; }
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doIsConnected( const wxPoint& aPosition ) const { return m_Pos == aPosition; }
virtual EDA_ITEM* doClone() const;
};
......@@ -492,8 +506,13 @@ public:
virtual bool IsConnectable() const { return true; }
virtual wxString GetSelectMenuText() const;
virtual const char** GetMenuImage() const { return (const char**) add_hierarchical_label_xpm; }
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const;
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const;
virtual bool doIsConnected( const wxPoint& aPosition ) const { return m_Pos == aPosition; }
virtual EDA_ITEM* doClone() const;
};
......
This diff is collapsed.
......@@ -127,6 +127,10 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_MENU_RANGE( ID_POPUP_SCH_MIROR_X_CMP, ID_POPUP_SCH_ORIENT_NORMAL_CMP,
SCH_EDIT_FRAME::OnChangeComponentOrientation )
// Multple item selection context menu commands.
EVT_MENU_RANGE( ID_SCH_SELECT_ITEM_START, ID_SCH_SELECT_ITEM_END,
SCH_EDIT_FRAME::OnSelectItem )
/* Handle user interface update events. */
EVT_UPDATE_UI( wxID_CUT, SCH_EDIT_FRAME::OnUpdateBlockSelected )
EVT_UPDATE_UI( wxID_COPY, SCH_EDIT_FRAME::OnUpdateBlockSelected )
......@@ -712,3 +716,18 @@ void SCH_EDIT_FRAME::SVG_Print( wxCommandEvent& event )
frame.ShowModal();
}
void SCH_EDIT_FRAME::OnSelectItem( wxCommandEvent& aEvent )
{
int id = aEvent.GetId();
int index = id - ID_SCH_SELECT_ITEM_START;
if( (id >= ID_SCH_SELECT_ITEM_START && id <= ID_SCH_SELECT_ITEM_END)
&& (index >= 0 && index < m_collectedItems.GetCount()) )
{
SCH_ITEM* item = m_collectedItems[index];
DrawPanel->m_AbortRequest = false;
GetScreen()->SetCurItem( item );
}
}
......@@ -127,9 +127,6 @@ int SCH_EDIT_FRAME::Edit_PinSheet( SCH_SHEET_PIN* aLabel, wxDC* aDC )
if( aLabel == NULL )
return wxID_CANCEL;
if( aDC )
aLabel->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
DIALOG_SCH_EDIT_SHEET_PIN dlg( this );
dlg.SetLabelName( aLabel->m_Text );
......@@ -151,6 +148,9 @@ int SCH_EDIT_FRAME::Edit_PinSheet( SCH_SHEET_PIN* aLabel, wxDC* aDC )
if( dlg.ShowModal() == wxID_CANCEL )
return wxID_CANCEL;
if( aDC )
aLabel->Draw( DrawPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
aLabel->m_Text = dlg.GetLabelName();
aLabel->m_Size.y = ReturnValueFromString( g_UserUnit, dlg.GetTextHeight(), m_InternalUnits );
aLabel->m_Size.x = ReturnValueFromString( g_UserUnit, dlg.GetTextWidth(), m_InternalUnits );
......
......@@ -6,6 +6,7 @@
#define BASE_STRUCT_H
#include "colors.h"
#include "bitmaps.h"
#include <boost/ptr_container/ptr_vector.hpp>
......@@ -45,21 +46,23 @@ enum KICAD_T {
TYPE_ZONE_CONTAINER, // a zone area
TYPE_BOARD_ITEM_LIST, // a list of board items
// Draw Items in schematic
SCH_POLYLINE_T,
// Schematic draw Items. The order of these items effects the sort order.
// It is currenlty ordered to mimic the old EESchema locate behavior where
// the smallest item is the selected item.
SCH_MARKER_T,
SCH_JUNCTION_T,
SCH_NO_CONNECT_T,
SCH_BUS_ENTRY_T,
SCH_LINE_T,
SCH_POLYLINE_T,
SCH_TEXT_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIERARCHICAL_LABEL_T,
SCH_FIELD_T,
SCH_COMPONENT_T,
SCH_LINE_T,
SCH_BUS_ENTRY_T,
SCH_SHEET_T,
SCH_SHEET_LABEL_T,
SCH_MARKER_T,
SCH_NO_CONNECT_T,
SCH_FIELD_T,
SCH_SHEET_T,
// General
SCH_SCREEN_T,
......@@ -275,6 +278,13 @@ public:
* @param aPoint The point to merge with the rectangle.
*/
void Merge( const wxPoint& aPoint );
/**
* Function GetArea
* returns the area of the rectangle.
* @return The area of the rectangle.
*/
double GetArea() const;
};
......@@ -519,7 +529,6 @@ public:
const void* testData,
const KICAD_T scanTypes[] );
/**
* Function Visit
* may be re-implemented for each derived class in order to handle
......@@ -537,7 +546,6 @@ public:
virtual SEARCH_RESULT Visit( INSPECTOR* inspector, const void* testData,
const KICAD_T scanTypes[] );
/**
* Function GetClass
* returns the class name.
......@@ -548,6 +556,26 @@ public:
return wxT( "EDA_ITEM" );
}
/**
* Function GetSelectMenuText
* returns the text to display to be used in the selection clarification context menu
* when multiple items are found at the current cursor position. The default version
* of this function raises an assertion in the debug mode and returns a string to
* indicate that it was not overridden to provide the object specific text.
*
* @return The menu text string.
*/
virtual wxString GetSelectMenuText() const;
/**
* Function GetMenuImage
* returns a pointer to an image to be used in menus. The default version returns
* the right arrow image. Overide this function to provide object specific menu
* images.
* @return The menu image associated with the item.
*/
virtual const char** GetMenuImage() const { return (const char**) right_xpm; }
#if defined(DEBUG)
......@@ -576,7 +604,7 @@ public:
/**
* Function new_clone
* provides cloning capabilities for all Boost pointer containers of EDA_ITEMs.
* provides cloning capabilities for all Boost pointer containers of EDA_ITEM pointers.
*
* @param aItem EDA_ITEM to clone.
* @return Clone of \a aItem.
......@@ -587,10 +615,10 @@ inline EDA_ITEM* new_clone( const EDA_ITEM& aItem ) { return aItem.Clone(); }
/**
* Define list of drawing items for screens.
*
* The Boost containter was choosen over the statand C++ contain because you can detach
* the pointer from a list with the release method.
* The standard C++ containter was choosen so the pointer can be removed from a list without
* it being destroyed.
*/
typedef boost::ptr_vector< EDA_ITEM > EDA_ITEMS;
typedef std::vector< EDA_ITEM* > EDA_ITEMS;
// Graphic Text justify:
......
......@@ -142,6 +142,23 @@ public:
return &m_List[0];
}
/**
* Function HasItem
* tests if \a aItem has already been collected.
*
* @param aItem The EDA_ITEM* to be tested.
* @return True if \a aItem is already collected.
*/
bool HasItem( const EDA_ITEM* aItem ) const
{
for( size_t i = 0; i < m_List.size(); i++ )
{
if( m_List[i] == aItem )
return true;
}
return false;
}
/**
* Function SetScanTypes
......@@ -159,6 +176,7 @@ public:
{
m_TimeAtCollection = GetTimeStamp();
}
int GetTime()
{
return m_TimeAtCollection;
......
......@@ -101,7 +101,7 @@ public:
* @see EDA_DRAW_FRAME::GetGridColor() for the color of the grid.
* @param aDC The device context to draw the grid.
*/
void DrawGrid( wxDC* DC );
void DrawGrid( wxDC* aDC );
/**
* Function DrawAuxiliaryAxis
......
......@@ -9,12 +9,23 @@
#include "sch_item_struct.h"
#include "class_base_screen.h"
#include "../eeschema/general.h"
class LIB_PIN;
class SCH_COMPONENT;
class SCH_SHEET_PATH;
class SCH_SHEET_PIN;
class SCH_LINE;
class SCH_TEXT;
enum SCH_LINE_TEST_T
{
ENTIRE_LENGTH_T,
END_POINTS_ONLY_T,
EXCLUDE_END_POINTS_T
};
/* Max number of sheets in a hierarchy project: */
......@@ -30,7 +41,7 @@ class SCH_SCREEN : public BASE_SCREEN
* Function addConnectedItemsToBlock
* add items connected at \a aPosition to the block pick list.
* <p>
* This method tests all connectable unselected items in the screen that are connected to
* This method tests all connectible unselected items in the screen that are connected to
* \a aPosition and adds them to the block selection pick list. This is used when a block
* drag is being performed to ensure connections to items in the block are not lost.
*</p>
......@@ -84,39 +95,15 @@ public:
void FreeDrawList();
/**
* Function GetItems
* adds all items found at \a aPosition to \a aItemList. Please note that \a aItemList
* will own the item pointers added to it. Do not allow it to go out of scope without
* first calling the release() method. Otherwise, the pointer will be deleted and
* EESchema will crash.
* @param aPosition The position to test.
* @param aItemList The list to place items into.
* @return The number of items found at \a aPosition.
*/
int GetItems( const wxPoint& aPosition, SCH_ITEMS& aItemList ) const;
/**
* Function FindItem
* Function GetItem
* checks \a aPosition within a distance of \a aAccuracy for items of type \a aFilter.
* @param aPosition Position in drawing units.
* @param aAccuracy The maximum distance within \a Position to check for an item.
* @param aFilter The type of items to find.
* @param aType The type of item to find or #NOT_USED to find any item type.
* @return The item found that meets the search criteria or NULL if none found.
*/
SCH_ITEM* GetItem( const wxPoint& aPosition, int aAccuracy = 0,
int aFilter = NO_FILTER_T ) const;
/**
* Function GetItems
* checks \a aPosition within a distance of \a aAccuracy for items of type \a aFilter.
* @param aPosition Position in drawing units.
* @param aItemList The list to add found items to.
* @param aAccuracy The maximum distance within \a Position to check for an item.
* @param aFilter The type of items to find.
* @return The number of items found that meets the search criteria.
*/
int GetItems( const wxPoint& aPosition, PICKED_ITEMS_LIST& aItemList, int aAccuracy = 0,
int aFilter = NO_FILTER_T ) const;
KICAD_T aType = NOT_USED ) const;
void Place( SCH_EDIT_FRAME* frame, wxDC* DC ) { };
......@@ -150,6 +137,15 @@ public:
void AddToDrawList( SCH_ITEM* st );
/**
* Function SchematicCleanUp
* performs routine schematic cleaning including breaking wire and buses and
* deleting identical objects superimposed on top of each other.
*
* @param aCanvas The window to draw on.
* @param aDC The device context used for drawing to \a aCanvas.
* @return True if any schematic clean up was performed.
*/
bool SchematicCleanUp( EDA_DRAW_PANEL* aCanvas = NULL, wxDC* aDC = NULL );
/**
......@@ -167,8 +163,8 @@ public:
* them with a copy. Old item must be put in undo list, and the new ones can be
* modified by clean up safely. If an abort command is made, old wires must be put
* in GetDrawItems(), and copies must be deleted. This is because previously stored
* undo commands can handle pointers on wires or busses, and we do not delete wires or
* busses, we must put they in undo list.
* undo commands can handle pointers on wires or buses, and we do not delete wires or
* buss-es, we must put they in undo list.
*
* Because cleanup delete and/or modify bus and wires, the it is easier is to put
* all wires in undo list and use a new copy of wires for cleanup.
......@@ -187,7 +183,6 @@ public:
* add all wires and junctions connected to \a aSegment which are not connected any
* component pin to \a aItemList.
* @param aSegment The segment to test for connections.
* @param aItemList List of items to add connections.
*/
void MarkConnections( SCH_LINE* aSegment );
......@@ -257,7 +252,18 @@ public:
* @param aPosition The position to test.
* @return True if a junction is required at \a aPosition.
*/
bool IsJunctionNeeded( const wxPoint& aPosition ) const;
bool IsJunctionNeeded( const wxPoint& aPosition );
/**
* Function IsTerminalPoint
* tests if \a aPosition is a connection point on \a aLayer.
*
* @param aPosition Position to test.
* @param aLayer The layer type to test against. Valid layer types are #LAYER_NOTES,
* #LAYER_BUS, and #LAYER_WIRE.
* @return True if \a Position is a connection point on \a aLayer.
*/
bool IsTerminalPoint( const wxPoint& aPosition, int aLayer );
/**
* Function GetPin
......@@ -292,7 +298,64 @@ public:
* adds all schematic sheet and component object in the screen to \a aItems.
* @param aItems Hierarchical item list to fill.
*/
void GetHierarchicalItems( std::vector <SCH_ITEM*>& aItems );
void GetHierarchicalItems( EDA_ITEMS& aItems );
/**
* Function GetNode
* returns all the items at \a aPosition that form a node.
*
* @param aPosition The wxPoint to test for node items.
* @param aList A #EDA_ITEMS container to place the items found.
* @return The number of node items found at \a aPosition.
*/
int GetNode( const wxPoint& aPosition, EDA_ITEMS& aList );
/**
* Function GetWireOrBus
* returns a wire or bus item located at \a aPosition.
*
* @param aPosition The wxPoint to test for node items.
* @return The SCH_LINE* of the wire or bus item found at \a aPosition or NULL if item not
* found.
*/
SCH_LINE* GetWireOrBus( const wxPoint& aPosition );
/**
* Function GetLine
* returns a line item located at \a aPosition.
*
* @param aPosition The wxPoint to test for a line item.
* @param aAccuracy Amount to inflate the item hit test bounding box.
* @param aLayer The layer the line is drawn upon.
* @param aSearchType Additional line test criteria.
* @return The SCH_LINE* of the wire item found at \a aPosition or NULL if item not
* found.
*/
SCH_LINE* GetLine( const wxPoint& aPosition, int aAccuracy = 0, int aLayer = LAYER_NOTES,
SCH_LINE_TEST_T aSearchType = ENTIRE_LENGTH_T );
SCH_LINE* GetWire( const wxPoint& aPosition, int aAccuracy = 0,
SCH_LINE_TEST_T aSearchType = ENTIRE_LENGTH_T )
{
return GetLine( aPosition, aAccuracy, LAYER_WIRE, aSearchType );
}
SCH_LINE* GetBus( const wxPoint& aPosition, int aAccuracy = 0,
SCH_LINE_TEST_T aSearchType = ENTIRE_LENGTH_T )
{
return GetLine( aPosition, aAccuracy, LAYER_BUS, aSearchType );
}
/**
* Function GetLabel
* returns a label item located at \a aPosition.
*
* @param aPosition The wxPoint to test for label items.
* @param aAccuracy Amount to inflate the item hit test bounding box.
* @return The SCH_TEXT* of the label item found at \a aPosition or NULL if item not
* found.
*/
SCH_TEXT* GetLabel( const wxPoint& aPosition, int aAccuracy = 0 );
/**
* Function SelectBlockItems
......@@ -370,7 +433,7 @@ public:
* Function DeleteAllMarkers
* deletes all electronic rules check markers of \a aMarkerType from all the screens in
* the list.
* @param aType Type of markers to be deleted.
* @param aMarkerType Type of markers to be deleted.
*/
void DeleteAllMarkers( int aMarkerType );
......
......@@ -301,6 +301,20 @@ int GetCommandOptions( const int argc, const char** argv,
*/
const wxString& valeur_param( int valeur, wxString& buf_texte );
/**
* Function CoordinateToString
* is a helper to convert the integer coordinate \a aValue to a string in inches,
* millimeters, or unscaled units according to the current user units setting.
*
* @param aValue The coordinate to convert.
* @param aInternalUnits The internal units of the application. #EESCHEMA_INTERNAL_UNIT
* and #PCB_INTERNAL_UNIT are the only valid value.
* @param aConvertToMils Convert inch values to mils if true. This setting has no effect if
* the current user unit is millimeters.
* @return The converted string for display in user interface elements.
*/
wxString CoordinateToString( int aValue, int aInternalUnits, bool aConvertToMils = false );
/**
* Returns the units symbol.
*
......
......@@ -22,28 +22,6 @@ typedef SCH_ITEMS::iterator SCH_ITEMS_ITR;
typedef vector< SCH_ITEMS_ITR > SCH_ITEMS_ITRS;
// Schematic item filter mask for hit test objects in schematic editor.
enum SCH_FILTER_T {
COMPONENT_T = 0x0001,
WIRE_T = 0X0002,
BUS_T = 0x0004,
BUS_ENTRY_T = 0x0008,
JUNCTION_T = 0x0010,
DRAW_ITEM_T = 0x0020,
TEXT_T = 0x0040,
LABEL_T = 0x0080,
SHEET_T = 0x0100,
MARKER_T = 0x0200,
NO_CONNECT_T = 0x0400,
SHEET_LABEL_T = 0x0800,
FIELD_T = 0x1000,
EXCLUDE_ENDPOINTS_T = 0x2000,
ENDPOINTS_ONLY_T = 0x4000,
PIN_T = 0x8000,
NO_FILTER_T = 0xFFFF
};
/* used to calculate the pen size from default value
* the actual pen size is default value * BUS_WIDTH_EXPAND
*/
......@@ -147,7 +125,7 @@ public:
/**
* Function Move
* moves the item by \a aMoveVector to a new position.
* @param aMoveVector = the deplacement vector
* @param aMoveVector = the displacement vector
*/
virtual void Move( const wxPoint& aMoveVector ) = 0;
......@@ -248,7 +226,7 @@ public:
* True is be return anytime the select state changes. If you need to know the
* the current selection state, use the IsSelected() method.
*
* @param aRect - Rectange to test against.
* @param aRect - Rectangle to test against.
*/
virtual bool IsSelectStateChanged( const wxRect& aRect ) { return false; }
......@@ -275,7 +253,7 @@ public:
* The vector release method is used to prevent the item pointers from being deleted.
* Do not use the vector erase method on the connection list.
*/
void ClearConnections() { m_connections.release(); }
void ClearConnections() { m_connections.clear(); }
/**
* Function IsConnected
......@@ -286,19 +264,19 @@ public:
*/
bool IsConnected( const wxPoint& aPoint ) const;
virtual bool HitTest( const wxPoint& aPosition ) { return HitTest( aPosition, 0 ); }
/**
* Function HitTest
* tests if \a aPoint is contained within or on the bounding box of an item.
*
* @param aPoint - Point to test.
* @param aAccuracy - Increase the item bounding box by this amount.
* @param aFilter - Mask to provide more granular hit testing. See enum SCH_FILTER_T.
* @return True if \a aPoint is within the item and meets the filter criteria.
* @return True if \a aPoint is within the item bounding box.
*/
bool HitTest( const wxPoint& aPoint, int aAccuracy = 0,
SCH_FILTER_T aFilter = NO_FILTER_T ) const
bool HitTest( const wxPoint& aPoint, int aAccuracy = 0 ) const
{
return doHitTest( aPoint, aAccuracy, aFilter );
return doHitTest( aPoint, aAccuracy );
}
/**
......@@ -317,6 +295,8 @@ public:
virtual bool CanIncrementLabel() const { return false; }
virtual bool operator <( const SCH_ITEM& aItem ) const;
/**
* @note - The DoXXX() functions below are used to enforce the interface while retaining
* the ability of change the implementation behavior of derived classes. See
......@@ -324,7 +304,7 @@ public:
* http://www.gotw.ca/publications/mill18.htm.
*/
private:
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy, SCH_FILTER_T aFilter ) const
virtual bool doHitTest( const wxPoint& aPoint, int aAccuracy ) const
{
return false;
}
......@@ -337,4 +317,8 @@ private:
virtual bool doIsConnected( const wxPoint& aPosition ) const { return false; }
};
extern bool sort_schematic_items( const SCH_ITEM* aItem1, const SCH_ITEM* aItem2 );
#endif /* SCH_ITEM_STRUCT_H */
......@@ -27,30 +27,30 @@ bool DistanceTest( int seuil, int dx, int dy, int spot_cX, int spot_cY );
//! @param linePointA Point on line
//! @param linePointB Point on line
//! @param referencePoint Reference point
double DistanceLinePoint(wxPoint linePointA, wxPoint linePointB, wxPoint referencePoint);
double DistanceLinePoint( wxPoint linePointA, wxPoint linePointB, wxPoint referencePoint );
//! @brief Euclidean norm of a 2D vector
//! @param vector Two-dimensional vector
//! @return Euclidean norm of the vector
double EuclideanNorm(wxPoint vector);
double EuclideanNorm( wxPoint vector );
//! @brief Vector between two points
//! @param startPoint The start point
//! @param endPoint The end point
//! @return Vector between the points
wxPoint TwoPointVector(wxPoint startPoint, wxPoint endPoint);
wxPoint TwoPointVector( wxPoint startPoint, wxPoint endPoint );
//! @brief Test, if two points are near each other
//! @param pointA First point
//! @param pointB Second point
//! @param threshold The maximum distance
//! @return True or false
bool HitTestPoints(wxPoint pointA, wxPoint pointB, double threshold);
bool HitTestPoints( wxPoint pointA, wxPoint pointB, double threshold );
//! @brief Determine the cross product
//! @param vectorA Two-dimensional vector
//! @param vectorB Two-dimensional vector
int CrossProduct(wxPoint vectorA, wxPoint vectorB);
int CrossProduct( wxPoint vectorA, wxPoint vectorB );
/**
......@@ -62,9 +62,14 @@ int CrossProduct(wxPoint vectorA, wxPoint vectorB);
* @param aEnd is the second end-point of the line segment
* @param aDist = maximum distance for hit
*/
bool TestSegmentHit( wxPoint aRefPoint, wxPoint aStart, wxPoint aEnd,
int aDist );
bool TestSegmentHit( wxPoint aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist );
/**
* Function GetLineLength
* returns the length of a line segment defined by \a aPointA and \a aPointB.
* @return Length of a line.
*/
double GetLineLength( const wxPoint& aPointA, const wxPoint& aPointB );
/*******************/
......
......@@ -11,6 +11,7 @@
#include "template_fieldnames.h"
#include "block_commande.h"
#include "class_sch_screen.h"
#include "sch_collectors.h"
class LIB_EDIT_FRAME;
......@@ -94,6 +95,7 @@ private:
BLOCK_SELECTOR m_blockItems; ///< List of selected items.
SCH_ITEM* m_itemToRepeat; ///< Last item to insert by the repeat command.
int m_repeatLabelDelta; ///< Repeat label number increment step.
SCH_COLLECTOR m_collectedItems; ///< List of collected items.
public:
SCH_EDIT_FRAME( wxWindow* father,
......@@ -204,24 +206,52 @@ public:
void OnSelectOptionToolbar( wxCommandEvent& event );
int BestZoom();
SCH_ITEM* LocateAndShowItem( const wxPoint& aPosition, bool aIncludePin = true );
SCH_ITEM* LocateItem( const wxPoint& aPosition, bool aIncludePin );
/**
* Function LocateAndShowItem
* checks the schematic at \a aPosition in logical (drawing) units for a item
* matching \a aFilterList and \a aGuide.
* <p>
* The search is first performed at the nearest grid position to \a aPosition. If no
* item if found on grid, then \a aPosition is tested for any items. If the item found
* can be cross probed, a message is send to PCBNew and the selected item is highlighted
* in PCB editor.
* </p>
* @param aPosition The wxPoint on the schematic to search.
* @param aFilterList A list of #KICAD_T types to to filter.
* @param aHotKeyCommandId A hot key command ID for performing additional tests when
* multiple items are found at \a aPosition.
* @return A SCH_ITEM pointer of the item found or NULL if no item found
*/
SCH_ITEM* LocateAndShowItem( const wxPoint& aPosition,
const KICAD_T aFilterList[] = SCH_COLLECTOR::AllItems,
int aHotKeyCommandId = 0 );
/**
* Function LocateItem
* checks for items at \a aPosition matching \a aFilter.
* <p>
* If multiple items are located at \a aPosition, a context menu is displayed to clarify
* which item the user intended to select. If the user aborts the context menu, NULL is
* returned and the abort request flag will be set to true. Make sure to clear this flag
* before attempting to display any other context menus.
* </p>
*
* @param aPosition The wxPoint location where to search.
* @param aFilterList A list of #KICAD_T types to to filter.
* @param aHotKeyCommandId A hot key command ID for performing additional tests when
* multiple items are found at \a aPosition.
* @return The SCH_ITEM pointer of the item found or NULL if no item found.
*/
SCH_ITEM* LocateItem( const wxPoint& aPosition,
const KICAD_T aFilterList[] = SCH_COLLECTOR::AllItems,
int aHotKeyCommandId = 0 );
/**
* Function DeleteItemAtCrossHair
* delete the item found under the cross hair.
* <p>
* If more than one item found, the priority order is:
* <ol>
* Marker
* Junction
* No connect
* Wire or bus
* Graphic item
* Text
* Component
* Sheet
* </ol></p>
* delete the item found under the cross hair. If multiple items are found at the
* cross hair position, a context menu is displayed to clarify which item to delete.
* See LocateItem() for more information on locating multiple items.
*
* @param aDC The device context to update if and item is deleted.
* @return True if an item was deleted.
*/
......@@ -440,6 +470,8 @@ private:
void OnSetOptions( wxCommandEvent& event );
void OnCancelCurrentCommand( wxCommandEvent& aEvent );
void OnSelectItem( wxCommandEvent& aEvent );
/* edition events functions */
void OnCopySchematicItemRequest( wxCommandEvent& event );
......@@ -552,13 +584,11 @@ private:
void OnSelectUnit( wxCommandEvent& aEvent );
void ConvertPart( SCH_COMPONENT* DrawComponent, wxDC* DC );
void SetInitCmp( SCH_COMPONENT* DrawComponent, wxDC* DC );
void EditComponentReference( SCH_COMPONENT* DrawLibItem,
wxDC* DC );
void EditComponentReference( SCH_COMPONENT* DrawLibItem, wxDC* DC );
void EditComponentValue( SCH_COMPONENT* DrawLibItem, wxDC* DC );
void EditComponentFootprint( SCH_COMPONENT* DrawLibItem,
wxDC* DC );
void EditComponentFootprint( SCH_COMPONENT* DrawLibItem, wxDC* DC );
void StartMoveCmpField( SCH_FIELD* Field, wxDC* DC );
void EditCmpFieldText( SCH_FIELD* Field, wxDC* DC );
void EditComponentFieldText( SCH_FIELD* aField, wxDC* aDC );
void RotateCmpField( SCH_FIELD* Field, wxDC* DC );
void PasteListOfItems( wxDC* DC );
......
......@@ -191,20 +191,23 @@ public:
virtual void SetLanguage( wxCommandEvent& event );
/**
* function GetFileFromHistory
* Fetch the file name from the file history list.
* @param aFileHistory = the wxFileHistory in use. If null,
* the main application file history is used
* Function GetFileFromHistory
* fetches the file name from the file history list.
* @param cmdId The command ID associated with the \a aFileHistory object.
* @param type Please document me!
* @param aFileHistory The wxFileHistory in use. If null, the main application file
* history is used
* @return a wxString containing the selected filename
*/
wxString GetFileFromHistory( int cmdId, const wxString& type,
wxFileHistory * aFileHistory = NULL);
wxFileHistory* aFileHistory = NULL);
/**
* Function UpdateFileHistory
* Update the list of recent opened files.
* @param aFileHistory = the wxFileHistory in use. If NULL,
* the main application file history is used
* ypdates the list of recently opened files.
* @param FullFileName The full file name including the path.
* @param aFileHistory The wxFileHistory in use. If NULL, the main application file
* history is used.
*/
void UpdateFileHistory( const wxString& FullFileName,
wxFileHistory * aFileHistory = NULL );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment