2016-02-19 15:59:31 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2021-01-13 14:40:30 +00:00
|
|
|
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
2016-02-19 15:59:31 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2016-02-19 15:59:31 +00:00
|
|
|
#include "dialog_lib_edit_pin_table.h"
|
2020-01-13 01:44:19 +00:00
|
|
|
#include "grid_tricks.h"
|
2015-03-27 10:26:07 +00:00
|
|
|
#include "lib_pin.h"
|
2021-07-28 18:50:17 +00:00
|
|
|
#include "pin_numbers.h"
|
2021-04-29 05:21:19 +00:00
|
|
|
#include "pgm_base.h"
|
2018-02-08 12:16:07 +00:00
|
|
|
#include <bitmaps.h>
|
2018-11-16 15:10:53 +00:00
|
|
|
#include <confirm.h>
|
2020-10-31 01:27:16 +00:00
|
|
|
#include <symbol_edit_frame.h>
|
|
|
|
#include <symbol_editor_settings.h>
|
2021-12-16 14:39:58 +00:00
|
|
|
#include <kiplatform/ui.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <widgets/grid_icon_text_helpers.h>
|
2021-04-25 17:41:20 +00:00
|
|
|
#include <widgets/grid_combobox.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <widgets/wx_grid.h>
|
2020-04-12 23:09:17 +00:00
|
|
|
#include <settings/settings_manager.h>
|
2021-04-29 05:21:19 +00:00
|
|
|
#include <wx/tokenzr.h>
|
2021-07-29 09:56:22 +00:00
|
|
|
#include <string_utils.h>
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-04-25 17:41:20 +00:00
|
|
|
#define UNITS_ALL "ALL"
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
class PIN_TABLE_DATA_MODEL : public wxGridTableBase
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
|
|
|
public:
|
2021-04-29 05:21:19 +00:00
|
|
|
PIN_TABLE_DATA_MODEL( SYMBOL_EDIT_FRAME* aFrame, DIALOG_LIB_EDIT_PIN_TABLE* aPinTable ) :
|
2021-12-22 21:43:41 +00:00
|
|
|
m_frame( aFrame ),
|
2021-04-29 05:21:19 +00:00
|
|
|
m_edited( false ),
|
|
|
|
m_pinTable( aPinTable )
|
2019-12-20 14:11:39 +00:00
|
|
|
{
|
2021-12-22 21:43:41 +00:00
|
|
|
m_frame->Bind( UNITS_CHANGED, &PIN_TABLE_DATA_MODEL::onUnitsChanged, this );
|
2019-12-20 14:11:39 +00:00
|
|
|
}
|
2018-02-08 12:16:07 +00:00
|
|
|
|
2021-12-22 21:43:41 +00:00
|
|
|
~PIN_TABLE_DATA_MODEL()
|
|
|
|
{
|
|
|
|
m_frame->Unbind( UNITS_CHANGED, &PIN_TABLE_DATA_MODEL::onUnitsChanged, this );
|
|
|
|
}
|
|
|
|
|
|
|
|
void onUnitsChanged( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
if( GetView() )
|
|
|
|
GetView()->ForceRefresh();
|
|
|
|
|
|
|
|
aEvent.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
int GetNumberRows() override { return (int) m_rows.size(); }
|
|
|
|
int GetNumberCols() override { return COL_COUNT; }
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
wxString GetColLabelValue( int aCol ) override
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
switch( aCol )
|
|
|
|
{
|
2021-04-22 04:50:14 +00:00
|
|
|
case COL_PIN_COUNT: return _( "Count" );
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_NUMBER: return _( "Number" );
|
|
|
|
case COL_NAME: return _( "Name" );
|
|
|
|
case COL_TYPE: return _( "Electrical Type" );
|
|
|
|
case COL_SHAPE: return _( "Graphic Style" );
|
|
|
|
case COL_ORIENTATION: return _( "Orientation" );
|
|
|
|
case COL_NUMBER_SIZE: return _( "Number Text Size" );
|
|
|
|
case COL_NAME_SIZE: return _( "Name Text Size" );
|
|
|
|
case COL_LENGTH: return _( "Length" );
|
|
|
|
case COL_POSX: return _( "X Position" );
|
|
|
|
case COL_POSY: return _( "Y Position" );
|
2021-01-14 21:03:51 +00:00
|
|
|
case COL_VISIBLE: return _( "Visible" );
|
2021-04-25 17:41:20 +00:00
|
|
|
case COL_UNIT: return _( "Unit" );
|
2018-02-08 12:16:07 +00:00
|
|
|
default: wxFAIL; return wxEmptyString;
|
|
|
|
}
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
bool IsEmptyCell( int row, int col ) override
|
|
|
|
{
|
|
|
|
return false; // don't allow adjacent cell overflow, even if we are actually empty
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
wxString GetValue( int aRow, int aCol ) override
|
|
|
|
{
|
2021-12-22 21:43:41 +00:00
|
|
|
return GetValue( m_rows[ aRow ], aCol, m_frame->GetUserUnits() );
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2019-12-20 14:11:39 +00:00
|
|
|
static wxString GetValue( const LIB_PINS& pins, int aCol, EDA_UNITS aUserUnits )
|
2018-02-08 12:16:07 +00:00
|
|
|
{
|
|
|
|
wxString fieldValue;
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2020-11-24 22:16:41 +00:00
|
|
|
if( pins.empty() )
|
2018-02-08 12:16:07 +00:00
|
|
|
return fieldValue;
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
for( LIB_PIN* pin : pins )
|
|
|
|
{
|
|
|
|
wxString val;
|
|
|
|
|
|
|
|
switch( aCol )
|
|
|
|
{
|
2021-04-22 04:50:14 +00:00
|
|
|
case COL_PIN_COUNT: val << pins.size(); break;
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_NUMBER:
|
|
|
|
val = pin->GetNumber();
|
|
|
|
break;
|
|
|
|
case COL_NAME:
|
|
|
|
val = pin->GetName();
|
|
|
|
break;
|
|
|
|
case COL_TYPE:
|
2020-08-21 15:54:24 +00:00
|
|
|
val = PinTypeNames()[static_cast<int>( pin->GetType() )];
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_SHAPE:
|
2020-08-21 15:54:24 +00:00
|
|
|
val = PinShapeNames()[static_cast<int>( pin->GetShape() )];
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_ORIENTATION:
|
2020-08-21 15:54:24 +00:00
|
|
|
if( PinOrientationIndex( pin->GetOrientation() ) >= 0 )
|
|
|
|
val = PinOrientationNames()[ PinOrientationIndex( pin->GetOrientation() ) ];
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_NUMBER_SIZE:
|
2020-10-02 20:51:24 +00:00
|
|
|
val = StringFromValue( aUserUnits, pin->GetNumberTextSize(), true );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_NAME_SIZE:
|
2020-10-02 20:51:24 +00:00
|
|
|
val = StringFromValue( aUserUnits, pin->GetNameTextSize(), true );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_LENGTH:
|
2021-12-21 19:07:28 +00:00
|
|
|
val = StringFromValue( aUserUnits, pin->GetLength(), true );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_POSX:
|
2021-12-21 19:07:28 +00:00
|
|
|
val = StringFromValue( aUserUnits, pin->GetPosition().x, true );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
|
|
|
case COL_POSY:
|
2021-12-21 19:07:28 +00:00
|
|
|
val = StringFromValue( aUserUnits, pin->GetPosition().y, true );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2021-01-14 21:03:51 +00:00
|
|
|
case COL_VISIBLE:
|
|
|
|
val = StringFromBool( pin->IsVisible() );
|
|
|
|
break;
|
2021-04-25 17:41:20 +00:00
|
|
|
case COL_UNIT:
|
|
|
|
if( pin->GetUnit() )
|
|
|
|
val = LIB_SYMBOL::SubReference( pin->GetUnit(), false );
|
|
|
|
else
|
|
|
|
val = UNITS_ALL;
|
|
|
|
break;
|
2018-02-08 12:16:07 +00:00
|
|
|
default:
|
|
|
|
wxFAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( aCol == COL_NUMBER )
|
|
|
|
{
|
|
|
|
if( fieldValue.length() )
|
|
|
|
fieldValue += wxT( ", " );
|
|
|
|
fieldValue += val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !fieldValue.Length() )
|
|
|
|
fieldValue = val;
|
|
|
|
else if( val != fieldValue )
|
2020-05-05 15:40:18 +00:00
|
|
|
fieldValue = INDETERMINATE_STATE;
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
return fieldValue;
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void SetValue( int aRow, int aCol, const wxString &aValue ) override
|
2018-01-20 23:41:25 +00:00
|
|
|
{
|
2020-05-05 15:40:18 +00:00
|
|
|
if( aValue == INDETERMINATE_STATE )
|
2018-02-08 12:16:07 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
LIB_PINS pins = m_rows[ aRow ];
|
|
|
|
|
2021-04-29 05:21:19 +00:00
|
|
|
// If the NUMBER column is edited and the pins are grouped, renumber, and add or remove pins based on the comma separated list of pins.
|
|
|
|
if( aCol == COL_NUMBER && m_pinTable->IsDisplayGrouped() )
|
|
|
|
{
|
|
|
|
wxStringTokenizer tokenizer( aValue, "," );
|
|
|
|
size_t i = 0;
|
|
|
|
while( tokenizer.HasMoreTokens() )
|
|
|
|
{
|
|
|
|
wxString pinName = tokenizer.GetNextToken();
|
|
|
|
|
|
|
|
// Trim whitespace from both ends of the string
|
|
|
|
pinName.Trim( true ).Trim( false );
|
|
|
|
|
|
|
|
if( i < pins.size() )
|
|
|
|
{
|
|
|
|
// Renumber the existing pins
|
|
|
|
pins.at( i )->SetNumber( pinName );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Create new pins
|
|
|
|
LIB_PIN* newPin = new LIB_PIN( nullptr );
|
|
|
|
LIB_PIN* last = pins.back();
|
|
|
|
|
|
|
|
newPin->SetNumber( pinName );
|
|
|
|
newPin->SetName( last->GetName() );
|
|
|
|
newPin->SetOrientation( last->GetOrientation() );
|
|
|
|
newPin->SetType( last->GetType() );
|
|
|
|
newPin->SetShape( last->GetShape() );
|
|
|
|
newPin->SetUnit( last->GetUnit() );
|
|
|
|
newPin->SetParent( last->GetParent() );
|
|
|
|
|
|
|
|
VECTOR2I pos = last->GetPosition();
|
|
|
|
|
|
|
|
auto* cfg = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
|
|
|
|
|
|
|
|
if( last->GetOrientation() == PIN_LEFT || last->GetOrientation() == PIN_RIGHT )
|
|
|
|
pos.y -= Mils2iu( cfg->m_Repeat.pin_step );
|
|
|
|
else
|
|
|
|
pos.x += Mils2iu( cfg->m_Repeat.pin_step );
|
|
|
|
|
|
|
|
newPin->SetPosition( pos );
|
|
|
|
|
|
|
|
pins.push_back( newPin );
|
|
|
|
m_pinTable->AddPin( newPin );
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( i < pins.size() )
|
|
|
|
{
|
|
|
|
auto pin = pins.back();
|
|
|
|
m_pinTable->RemovePin( pin );
|
|
|
|
pins.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_rows[aRow] = pins;
|
|
|
|
m_edited = true;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
for( LIB_PIN* pin : pins )
|
|
|
|
{
|
|
|
|
switch( aCol )
|
|
|
|
{
|
|
|
|
case COL_NUMBER:
|
2021-04-29 05:21:19 +00:00
|
|
|
if( !m_pinTable->IsDisplayGrouped() )
|
|
|
|
{
|
2021-10-28 14:25:51 +00:00
|
|
|
pin->SetNumber( aValue );
|
2021-04-29 05:21:19 +00:00
|
|
|
}
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_NAME:
|
|
|
|
pin->SetName( aValue );
|
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_TYPE:
|
2020-08-21 15:54:24 +00:00
|
|
|
if( PinTypeNames().Index( aValue ) != wxNOT_FOUND )
|
|
|
|
pin->SetType( (ELECTRICAL_PINTYPE) PinTypeNames().Index( aValue ) );
|
2019-01-17 14:23:25 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_SHAPE:
|
2020-08-21 15:54:24 +00:00
|
|
|
if( PinShapeNames().Index( aValue ) != wxNOT_FOUND )
|
|
|
|
pin->SetShape( (GRAPHIC_PINSHAPE) PinShapeNames().Index( aValue ) );
|
2019-01-17 14:23:25 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_ORIENTATION:
|
2020-08-21 15:54:24 +00:00
|
|
|
if( PinOrientationNames().Index( aValue ) != wxNOT_FOUND )
|
|
|
|
pin->SetOrientation( PinOrientationCode( PinOrientationNames().Index( aValue ) ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_NUMBER_SIZE:
|
2021-12-22 21:43:41 +00:00
|
|
|
pin->SetNumberTextSize( ValueFromString( m_frame->GetUserUnits(), aValue ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_NAME_SIZE:
|
2021-12-22 21:43:41 +00:00
|
|
|
pin->SetNameTextSize( ValueFromString( m_frame->GetUserUnits(), aValue ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_LENGTH:
|
2021-12-22 21:43:41 +00:00
|
|
|
pin->SetLength( ValueFromString( m_frame->GetUserUnits(), aValue ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_POSX:
|
2021-12-22 21:43:41 +00:00
|
|
|
pin->SetPosition( wxPoint( ValueFromString( m_frame->GetUserUnits(), aValue ),
|
2020-08-03 21:12:29 +00:00
|
|
|
pin->GetPosition().y ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2020-08-03 21:12:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
case COL_POSY:
|
2020-08-03 21:12:29 +00:00
|
|
|
pin->SetPosition( wxPoint( pin->GetPosition().x,
|
2021-12-22 21:43:41 +00:00
|
|
|
ValueFromString( m_frame->GetUserUnits(), aValue ) ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
break;
|
2021-01-15 14:28:36 +00:00
|
|
|
|
2021-01-14 21:03:51 +00:00
|
|
|
case COL_VISIBLE:
|
|
|
|
pin->SetVisible(BoolFromString( aValue ));
|
|
|
|
break;
|
2021-04-25 17:41:20 +00:00
|
|
|
|
|
|
|
case COL_UNIT:
|
|
|
|
if( aValue == UNITS_ALL )
|
|
|
|
{
|
|
|
|
pin->SetUnit( 0 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for( auto i = 1; i <= pin->GetParent()->GetUnitCount(); i++ )
|
|
|
|
{
|
|
|
|
if( aValue == LIB_SYMBOL::SubReference( i, false ) )
|
|
|
|
{
|
|
|
|
pin->SetUnit( i );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2018-02-08 12:16:07 +00:00
|
|
|
default:
|
|
|
|
wxFAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-11-16 15:10:53 +00:00
|
|
|
|
|
|
|
m_edited = true;
|
2018-01-20 23:41:25 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
static int findRow( const std::vector<LIB_PINS>& aRowSet, const wxString& aName )
|
|
|
|
{
|
|
|
|
for( size_t i = 0; i < aRowSet.size(); ++i )
|
|
|
|
{
|
|
|
|
if( aRowSet[ i ][ 0 ] && aRowSet[ i ][ 0 ]->GetName() == aName )
|
|
|
|
return i;
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2016-01-13 19:17:54 +00:00
|
|
|
|
2020-08-21 15:54:24 +00:00
|
|
|
static bool compare( const LIB_PINS& lhs, const LIB_PINS& rhs, int sortCol, bool ascending,
|
|
|
|
EDA_UNITS units )
|
2018-02-08 12:16:07 +00:00
|
|
|
{
|
|
|
|
wxString lhStr = GetValue( lhs, sortCol, units );
|
|
|
|
wxString rhStr = GetValue( rhs, sortCol, units );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( lhStr == rhStr )
|
|
|
|
{
|
|
|
|
// Secondary sort key is always COL_NUMBER
|
2018-10-09 13:53:55 +00:00
|
|
|
sortCol = COL_NUMBER;
|
|
|
|
lhStr = GetValue( lhs, sortCol, units );
|
|
|
|
rhStr = GetValue( rhs, sortCol, units );
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2019-11-13 01:24:57 +00:00
|
|
|
bool res;
|
|
|
|
|
|
|
|
// N.B. To meet the iterator sort conditions, we cannot simply invert the truth
|
|
|
|
// to get the opposite sort. i.e. ~(a<b) != (a>b)
|
|
|
|
auto cmp = [ ascending ]( const auto a, const auto b )
|
2020-08-21 15:54:24 +00:00
|
|
|
{
|
|
|
|
if( ascending )
|
|
|
|
return a < b;
|
|
|
|
else
|
|
|
|
return b < a;
|
|
|
|
};
|
2018-10-09 13:53:55 +00:00
|
|
|
|
|
|
|
switch( sortCol )
|
|
|
|
{
|
|
|
|
case COL_NUMBER:
|
|
|
|
case COL_NAME:
|
2021-07-28 18:50:17 +00:00
|
|
|
res = cmp( PIN_NUMBERS::Compare( lhStr, rhStr ), 0 );
|
2018-10-09 13:53:55 +00:00
|
|
|
break;
|
|
|
|
case COL_NUMBER_SIZE:
|
|
|
|
case COL_NAME_SIZE:
|
2021-07-28 18:50:17 +00:00
|
|
|
res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
|
2018-10-09 13:53:55 +00:00
|
|
|
break;
|
|
|
|
case COL_LENGTH:
|
|
|
|
case COL_POSX:
|
|
|
|
case COL_POSY:
|
2019-11-13 01:24:57 +00:00
|
|
|
res = cmp( ValueFromString( units, lhStr ), ValueFromString( units, rhStr ) );
|
2018-10-09 13:53:55 +00:00
|
|
|
break;
|
2021-01-14 21:03:51 +00:00
|
|
|
case COL_VISIBLE:
|
2018-10-09 13:53:55 +00:00
|
|
|
default:
|
2019-11-13 01:24:57 +00:00
|
|
|
res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
|
2018-10-09 13:53:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-11-13 01:24:57 +00:00
|
|
|
return res;
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2020-11-18 19:50:36 +00:00
|
|
|
void RebuildRows( const LIB_PINS& aPins, bool groupByName )
|
2018-02-08 12:16:07 +00:00
|
|
|
{
|
|
|
|
if ( GetView() )
|
|
|
|
{
|
|
|
|
// Commit any pending in-place edits before the row gets moved out from under
|
|
|
|
// the editor.
|
2020-01-13 15:22:26 +00:00
|
|
|
if( auto grid = dynamic_cast<WX_GRID*>( GetView() ) )
|
|
|
|
grid->CommitPendingChanges( true );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
2016-01-13 19:17:54 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_rows.clear();
|
2016-01-13 19:17:54 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
for( LIB_PIN* pin : aPins )
|
|
|
|
{
|
|
|
|
int rowIndex = -1;
|
2016-01-13 19:17:54 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( groupByName )
|
|
|
|
rowIndex = findRow( m_rows, pin->GetName() );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( rowIndex < 0 )
|
|
|
|
{
|
|
|
|
m_rows.emplace_back( LIB_PINS() );
|
|
|
|
rowIndex = m_rows.size() - 1;
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_rows[ rowIndex ].push_back( pin );
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
int sortCol = 0;
|
|
|
|
bool ascending = true;
|
2018-01-20 23:41:25 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND )
|
|
|
|
{
|
|
|
|
sortCol = GetView()->GetSortingColumn();
|
|
|
|
ascending = GetView()->IsSortOrderAscending();
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2019-08-21 19:16:21 +00:00
|
|
|
for( LIB_PINS& row : m_rows )
|
|
|
|
SortPins( row );
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
SortRows( sortCol, ascending );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if ( GetView() )
|
|
|
|
{
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void SortRows( int aSortCol, bool ascending )
|
|
|
|
{
|
|
|
|
std::sort( m_rows.begin(), m_rows.end(),
|
2019-11-13 01:24:57 +00:00
|
|
|
[ aSortCol, ascending, this ]( const LIB_PINS& lhs, const LIB_PINS& rhs ) -> bool
|
2019-08-21 19:16:21 +00:00
|
|
|
{
|
2021-12-22 21:43:41 +00:00
|
|
|
return compare( lhs, rhs, aSortCol, ascending, m_frame->GetUserUnits() );
|
2019-08-21 19:16:21 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
void SortPins( LIB_PINS& aRow )
|
|
|
|
{
|
|
|
|
std::sort( aRow.begin(), aRow.end(),
|
|
|
|
[]( LIB_PIN* lhs, LIB_PIN* rhs ) -> bool
|
|
|
|
{
|
2021-07-28 18:50:17 +00:00
|
|
|
return PIN_NUMBERS::Compare( lhs->GetNumber(), rhs->GetNumber() ) < 0;
|
2019-08-21 19:16:21 +00:00
|
|
|
} );
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void AppendRow( LIB_PIN* aPin )
|
2016-02-28 17:33:29 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
LIB_PINS row;
|
|
|
|
row.push_back( aPin );
|
|
|
|
m_rows.push_back( row );
|
|
|
|
|
|
|
|
if ( GetView() )
|
|
|
|
{
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
|
|
|
}
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
LIB_PINS RemoveRow( int aRow )
|
|
|
|
{
|
|
|
|
LIB_PINS removedRow = m_rows[ aRow ];
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_rows.erase( m_rows.begin() + aRow );
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if ( GetView() )
|
|
|
|
{
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
return removedRow;
|
|
|
|
}
|
2018-11-16 15:10:53 +00:00
|
|
|
|
|
|
|
bool IsEdited()
|
|
|
|
{
|
|
|
|
return m_edited;
|
|
|
|
}
|
2021-01-13 14:40:30 +00:00
|
|
|
|
|
|
|
private:
|
2021-01-14 21:03:51 +00:00
|
|
|
static wxString StringFromBool( bool aValue )
|
|
|
|
{
|
|
|
|
if( aValue )
|
|
|
|
return wxT( "1" );
|
|
|
|
else
|
|
|
|
return wxT( "0" );
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool BoolFromString( wxString aValue )
|
|
|
|
{
|
|
|
|
if( aValue == "1" )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if( aValue == "0" )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-04 00:02:14 +00:00
|
|
|
wxFAIL_MSG( wxString::Format( "string '%s' can't be converted to boolean "
|
2021-01-15 14:28:36 +00:00
|
|
|
"correctly, it will have been perceived as FALSE",
|
|
|
|
aValue ) );
|
2021-01-14 21:03:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-01-15 14:28:36 +00:00
|
|
|
|
2021-12-22 21:43:41 +00:00
|
|
|
private:
|
|
|
|
SYMBOL_EDIT_FRAME* m_frame;
|
|
|
|
|
2021-01-15 14:28:36 +00:00
|
|
|
// Because the rows of the grid can either be a single pin or a group of pins, the
|
|
|
|
// data model is a 2D vector. If we're in the single pin case, each row's LIB_PINS
|
|
|
|
// contains only a single pin.
|
|
|
|
std::vector<LIB_PINS> m_rows;
|
|
|
|
|
2021-12-22 21:43:41 +00:00
|
|
|
bool m_edited;
|
2021-04-29 05:21:19 +00:00
|
|
|
|
|
|
|
DIALOG_LIB_EDIT_PIN_TABLE* m_pinTable;
|
2018-02-08 12:16:07 +00:00
|
|
|
};
|
2015-03-27 10:26:07 +00:00
|
|
|
|
|
|
|
|
2021-06-10 18:51:46 +00:00
|
|
|
DIALOG_LIB_EDIT_PIN_TABLE::DIALOG_LIB_EDIT_PIN_TABLE( SYMBOL_EDIT_FRAME* parent,
|
|
|
|
LIB_SYMBOL* aSymbol ) :
|
2020-05-05 15:40:18 +00:00
|
|
|
DIALOG_LIB_EDIT_PIN_TABLE_BASE( parent ),
|
|
|
|
m_editFrame( parent ),
|
2021-06-10 18:51:46 +00:00
|
|
|
m_part( aSymbol )
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2021-04-29 05:21:19 +00:00
|
|
|
m_dataModel = new PIN_TABLE_DATA_MODEL( m_editFrame, this );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
// Save original columns widths so we can do proportional sizing.
|
|
|
|
for( int i = 0; i < COL_COUNT; ++i )
|
|
|
|
m_originalColWidths[ i ] = m_grid->GetColSize( i );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
// Give a bit more room for combobox editors
|
|
|
|
m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-05-30 10:52:19 +00:00
|
|
|
m_grid->SetTable( m_dataModel );
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
// Show/hide columns according to the user's preference
|
2020-01-13 01:44:19 +00:00
|
|
|
auto cfg = parent->GetSettings();
|
|
|
|
m_columnsShown = cfg->m_PinTableVisibleColumns;
|
|
|
|
|
2018-05-30 10:52:19 +00:00
|
|
|
m_grid->ShowHideColumns( m_columnsShown );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
// Set special attributes
|
|
|
|
wxGridCellAttr* attr;
|
|
|
|
|
2021-04-22 04:50:14 +00:00
|
|
|
attr = new wxGridCellAttr;
|
|
|
|
attr->SetReadOnly( true );
|
|
|
|
m_grid->SetColAttr( COL_PIN_COUNT, attr );
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
attr = new wxGridCellAttr;
|
2020-08-21 15:54:24 +00:00
|
|
|
wxArrayString typeNames = PinTypeNames();
|
|
|
|
typeNames.push_back( INDETERMINATE_STATE );
|
|
|
|
attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinTypeIcons(), typeNames ) );
|
|
|
|
attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinTypeIcons(), typeNames ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->SetColAttr( COL_TYPE, attr );
|
|
|
|
|
|
|
|
attr = new wxGridCellAttr;
|
2020-08-21 15:54:24 +00:00
|
|
|
wxArrayString shapeNames = PinShapeNames();
|
|
|
|
shapeNames.push_back( INDETERMINATE_STATE );
|
|
|
|
attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinShapeIcons(), shapeNames ) );
|
|
|
|
attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinShapeIcons(), shapeNames ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->SetColAttr( COL_SHAPE, attr );
|
|
|
|
|
|
|
|
attr = new wxGridCellAttr;
|
2020-08-21 15:54:24 +00:00
|
|
|
wxArrayString orientationNames = PinOrientationNames();
|
|
|
|
orientationNames.push_back( INDETERMINATE_STATE );
|
2021-01-13 14:40:30 +00:00
|
|
|
attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( PinOrientationIcons(),
|
|
|
|
orientationNames ) );
|
2020-08-21 15:54:24 +00:00
|
|
|
attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( PinOrientationIcons(), orientationNames ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->SetColAttr( COL_ORIENTATION, attr );
|
2021-01-15 14:28:36 +00:00
|
|
|
|
2021-04-25 17:41:20 +00:00
|
|
|
attr = new wxGridCellAttr;
|
|
|
|
wxArrayString unitNames;
|
|
|
|
unitNames.push_back( _("ALL") );
|
|
|
|
|
|
|
|
for( auto i = 1; i <= aSymbol->GetUnitCount(); i++ )
|
|
|
|
{
|
|
|
|
unitNames.push_back( LIB_SYMBOL::SubReference( i, false ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
attr->SetEditor( new GRID_CELL_COMBOBOX( unitNames ) );
|
|
|
|
m_grid->SetColAttr( COL_UNIT, attr );
|
|
|
|
|
2021-01-14 21:03:51 +00:00
|
|
|
attr = new wxGridCellAttr;
|
|
|
|
attr->SetRenderer( new wxGridCellBoolRenderer() );
|
|
|
|
attr->SetEditor( new wxGridCellBoolEditor() );
|
|
|
|
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
|
|
|
|
m_grid->SetColAttr( COL_VISIBLE, attr );
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
/* Right-aligned position values look much better, but only MSW and GTK2+
|
2021-01-15 14:28:36 +00:00
|
|
|
* currently support right-aligned textEditCtrls, so the text jumps on all
|
2018-02-08 12:16:07 +00:00
|
|
|
* the other platforms when you edit it.
|
|
|
|
attr = new wxGridCellAttr;
|
|
|
|
attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
|
|
|
|
m_grid->SetColAttr( COL_POSX, attr );
|
|
|
|
|
|
|
|
attr = new wxGridCellAttr;
|
|
|
|
attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_TOP );
|
|
|
|
m_grid->SetColAttr( COL_POSY, attr );
|
|
|
|
*/
|
|
|
|
|
2021-03-08 02:59:07 +00:00
|
|
|
m_addButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
|
|
|
|
m_deleteButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
|
|
|
|
m_refreshButton->SetBitmap( KiBitmap( BITMAPS::small_refresh ) );
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
GetSizer()->SetSizeHints(this);
|
|
|
|
Centre();
|
|
|
|
|
2021-11-16 19:39:58 +00:00
|
|
|
SetupStandardButtons();
|
|
|
|
|
2021-02-10 22:56:26 +00:00
|
|
|
if( !parent->IsSymbolEditable() || parent->IsSymbolAlias() )
|
2020-12-22 02:29:27 +00:00
|
|
|
{
|
|
|
|
m_ButtonsCancel->SetDefault();
|
|
|
|
m_ButtonsOK->SetLabel( _( "Read Only" ) );
|
|
|
|
m_ButtonsOK->Enable( false );
|
|
|
|
}
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_initialized = true;
|
2019-01-03 03:41:18 +00:00
|
|
|
m_modified = false;
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
// Connect Events
|
2021-01-13 14:40:30 +00:00
|
|
|
m_grid->Connect( wxEVT_GRID_COL_SORT,
|
|
|
|
wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
DIALOG_LIB_EDIT_PIN_TABLE::~DIALOG_LIB_EDIT_PIN_TABLE()
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2020-01-13 01:44:19 +00:00
|
|
|
auto cfg = m_editFrame->GetSettings();
|
|
|
|
cfg->m_PinTableVisibleColumns = m_grid->GetShownColumns().ToStdString();
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
// Disconnect Events
|
2021-01-13 14:40:30 +00:00
|
|
|
m_grid->Disconnect( wxEVT_GRID_COL_SORT,
|
|
|
|
wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this );
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
// Prevents crash bug in wxGrid's d'tor
|
2018-05-30 10:52:19 +00:00
|
|
|
m_grid->DestroyTable( m_dataModel );
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
// Delete the GRID_TRICKS.
|
|
|
|
m_grid->PopEventHandler( true );
|
|
|
|
|
2021-01-15 14:28:36 +00:00
|
|
|
// This is our copy of the pins. If they were transferred to the part on an OK, then
|
2018-02-08 12:16:07 +00:00
|
|
|
// m_pins will already be empty.
|
|
|
|
for( auto pin : m_pins )
|
|
|
|
delete pin;
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
bool DIALOG_LIB_EDIT_PIN_TABLE::TransferDataToWindow()
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
// Make a copy of the pins for editing
|
|
|
|
for( LIB_PIN* pin = m_part->GetNextPin( nullptr ); pin; pin = m_part->GetNextPin( pin ) )
|
|
|
|
m_pins.push_back( new LIB_PIN( *pin ) );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-04-25 17:41:20 +00:00
|
|
|
if( m_part->IsMulti() )
|
|
|
|
{
|
|
|
|
m_grid->ShowCol( COL_UNIT );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_grid->HideCol( COL_UNIT );
|
|
|
|
}
|
|
|
|
|
2021-04-22 04:50:14 +00:00
|
|
|
if( m_cbGroup->GetValue() )
|
|
|
|
m_grid->ShowCol( COL_PIN_COUNT );
|
|
|
|
else
|
|
|
|
m_grid->HideCol( COL_PIN_COUNT );
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
updateSummary();
|
|
|
|
|
|
|
|
return true;
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
bool DIALOG_LIB_EDIT_PIN_TABLE::TransferDataFromWindow()
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2018-08-19 16:10:14 +00:00
|
|
|
if( !m_grid->CommitPendingChanges() )
|
|
|
|
return false;
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
// Delete the part's pins
|
|
|
|
while( LIB_PIN* pin = m_part->GetNextPin( nullptr ) )
|
|
|
|
m_part->RemoveDrawItem( pin );
|
|
|
|
|
|
|
|
// Transfer our pins to the part
|
|
|
|
for( LIB_PIN* pin : m_pins )
|
|
|
|
{
|
|
|
|
pin->SetParent( m_part );
|
|
|
|
m_part->AddDrawItem( pin );
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_pins.clear();
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
return true;
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnColSort( wxGridEvent& aEvent )
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
int sortCol = aEvent.GetCol();
|
|
|
|
bool ascending;
|
|
|
|
|
|
|
|
// This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
|
|
|
|
// event, and if we ask it will give us pre-event info.
|
|
|
|
if( m_grid->IsSortingBy( sortCol ) )
|
|
|
|
// same column; invert ascending
|
|
|
|
ascending = !m_grid->IsSortOrderAscending();
|
2016-01-15 02:26:42 +00:00
|
|
|
else
|
2018-02-08 12:16:07 +00:00
|
|
|
// different column; start with ascending
|
|
|
|
ascending = true;
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_dataModel->SortRows( sortCol, ascending );
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event )
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2018-08-19 16:10:14 +00:00
|
|
|
if( !m_grid->CommitPendingChanges() )
|
|
|
|
return;
|
|
|
|
|
2019-04-01 01:09:06 +00:00
|
|
|
LIB_PIN* newPin = new LIB_PIN( nullptr );
|
|
|
|
|
2021-04-29 05:21:19 +00:00
|
|
|
// Copy the settings of the last pin onto the new pin.
|
2019-04-01 01:09:06 +00:00
|
|
|
if( m_pins.size() > 0 )
|
|
|
|
{
|
|
|
|
LIB_PIN* last = m_pins.back();
|
|
|
|
|
|
|
|
newPin->SetOrientation( last->GetOrientation() );
|
|
|
|
newPin->SetType( last->GetType() );
|
|
|
|
newPin->SetShape( last->GetShape() );
|
2021-04-29 05:21:19 +00:00
|
|
|
newPin->SetUnit( last->GetUnit() );
|
2019-04-01 01:09:06 +00:00
|
|
|
|
2022-01-01 06:04:08 +00:00
|
|
|
VECTOR2I pos = last->GetPosition();
|
2019-04-01 01:09:06 +00:00
|
|
|
|
2021-06-06 22:36:31 +00:00
|
|
|
SYMBOL_EDITOR_SETTINGS* cfg = m_editFrame->GetSettings();
|
2020-04-12 23:09:17 +00:00
|
|
|
|
2019-04-01 01:09:06 +00:00
|
|
|
if( last->GetOrientation() == PIN_LEFT || last->GetOrientation() == PIN_RIGHT )
|
2020-09-20 19:31:40 +00:00
|
|
|
pos.y -= Mils2iu(cfg->m_Repeat.pin_step);
|
2019-04-01 01:09:06 +00:00
|
|
|
else
|
2020-09-20 19:31:40 +00:00
|
|
|
pos.x += Mils2iu(cfg->m_Repeat.pin_step);
|
2019-04-01 01:09:06 +00:00
|
|
|
|
|
|
|
newPin->SetPosition( pos );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pins.push_back( newPin );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_dataModel->AppendRow( m_pins[ m_pins.size() - 1 ] );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-04-22 04:50:14 +00:00
|
|
|
m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 1 );
|
|
|
|
m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 1 );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->EnableCellEditControl( true );
|
|
|
|
m_grid->ShowCellEditControl();
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
updateSummary();
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-29 05:21:19 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::AddPin( LIB_PIN* pin )
|
|
|
|
{
|
|
|
|
m_pins.push_back( pin );
|
|
|
|
updateSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event )
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2021-12-12 17:27:40 +00:00
|
|
|
// TODO: handle delete of multiple rows....
|
|
|
|
|
2018-08-19 16:10:14 +00:00
|
|
|
if( !m_grid->CommitPendingChanges() )
|
|
|
|
return;
|
|
|
|
|
2019-03-30 08:29:38 +00:00
|
|
|
if( m_pins.size() == 0 ) // empty table
|
|
|
|
return;
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
int curRow = m_grid->GetGridCursorRow();
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( curRow < 0 )
|
|
|
|
return;
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
LIB_PINS removedRow = m_dataModel->RemoveRow( curRow );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
for( auto pin : removedRow )
|
|
|
|
m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-09-28 17:48:04 +00:00
|
|
|
curRow = std::min( curRow, m_grid->GetNumberRows() - 1 );
|
2021-09-28 16:29:55 +00:00
|
|
|
m_grid->GoToCell( curRow, m_grid->GetGridCursorCol() );
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() );
|
2021-09-28 16:29:55 +00:00
|
|
|
m_grid->SelectRow( curRow );
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
updateSummary();
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-29 05:21:19 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::RemovePin( LIB_PIN* pin )
|
|
|
|
{
|
|
|
|
m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) );
|
|
|
|
updateSummary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnCellEdited( wxGridEvent& event )
|
2016-01-13 19:17:54 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
updateSummary();
|
2016-01-13 19:17:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-29 05:21:19 +00:00
|
|
|
bool DIALOG_LIB_EDIT_PIN_TABLE::IsDisplayGrouped()
|
|
|
|
{
|
|
|
|
return m_cbGroup->GetValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnRebuildRows( wxCommandEvent& )
|
2016-01-15 02:21:26 +00:00
|
|
|
{
|
2018-08-19 16:10:14 +00:00
|
|
|
if( !m_grid->CommitPendingChanges() )
|
|
|
|
return;
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() );
|
2016-01-15 02:21:26 +00:00
|
|
|
|
2021-04-22 04:50:14 +00:00
|
|
|
if( m_cbGroup->GetValue() )
|
|
|
|
{
|
|
|
|
m_grid->ShowCol( COL_PIN_COUNT );
|
|
|
|
m_grid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_grid->HideCol( COL_PIN_COUNT );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-16 14:39:58 +00:00
|
|
|
adjustGridColumns();
|
2016-01-15 02:21:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-16 14:39:58 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::adjustGridColumns()
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
// Account for scroll bars
|
2021-12-16 14:39:58 +00:00
|
|
|
int width = KIPLATFORM::UI::GetUnobscuredSize( m_grid ).x;
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
wxGridUpdateLocker deferRepaintsTillLeavingScope;
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
// The Number and Name columns must be at least wide enough to hold their contents, but
|
|
|
|
// no less wide than their original widths.
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->AutoSizeColumn( COL_NUMBER );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( m_grid->GetColSize( COL_NUMBER ) < m_originalColWidths[ COL_NUMBER ] )
|
|
|
|
m_grid->SetColSize( COL_NUMBER, m_originalColWidths[ COL_NUMBER ] );
|
2016-01-15 02:21:26 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
m_grid->AutoSizeColumn( COL_NAME );
|
2016-01-15 02:21:26 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( m_grid->GetColSize( COL_NAME ) < m_originalColWidths[ COL_NAME ] )
|
|
|
|
m_grid->SetColSize( COL_NAME, m_originalColWidths[ COL_NAME ] );
|
2016-01-15 02:21:26 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
// If the grid is still wider than the columns, then stretch the Number and Name columns
|
|
|
|
// to fit.
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
for( int i = 0; i < COL_COUNT; ++i )
|
2021-12-16 14:39:58 +00:00
|
|
|
width -= m_grid->GetColSize( i );
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-12-16 14:39:58 +00:00
|
|
|
if( width > 0 )
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2021-12-16 14:39:58 +00:00
|
|
|
m_grid->SetColSize( COL_NUMBER, m_grid->GetColSize( COL_NUMBER ) + width / 2 );
|
|
|
|
m_grid->SetColSize( COL_NAME, m_grid->GetColSize( COL_NAME ) + width / 2 );
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnSize( wxSizeEvent& event )
|
|
|
|
{
|
2021-12-17 04:00:24 +00:00
|
|
|
auto new_size = event.GetSize();
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-12-17 04:00:24 +00:00
|
|
|
if( m_initialized && m_size != new_size )
|
2019-02-27 07:07:32 +00:00
|
|
|
{
|
2021-12-17 04:00:24 +00:00
|
|
|
m_size = new_size;
|
2021-12-16 14:39:58 +00:00
|
|
|
|
|
|
|
adjustGridColumns();
|
2019-02-27 07:07:32 +00:00
|
|
|
}
|
2019-04-27 12:50:21 +00:00
|
|
|
|
|
|
|
// Always propagate for a grid repaint (needed if the height changes, as well as width)
|
|
|
|
event.Skip();
|
2015-03-27 10:26:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnUpdateUI( wxUpdateUIEvent& event )
|
2016-01-15 02:21:26 +00:00
|
|
|
{
|
2018-05-30 10:52:19 +00:00
|
|
|
wxString columnsShown = m_grid->GetShownColumns();
|
2018-02-08 12:16:07 +00:00
|
|
|
|
|
|
|
if( columnsShown != m_columnsShown )
|
2016-02-28 17:33:29 +00:00
|
|
|
{
|
2018-02-08 12:16:07 +00:00
|
|
|
m_columnsShown = columnsShown;
|
2016-02-28 17:33:29 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
if( !m_grid->IsCellEditControlShown() )
|
2021-12-16 14:39:58 +00:00
|
|
|
adjustGridColumns();
|
2016-02-28 17:33:29 +00:00
|
|
|
}
|
2016-01-15 02:21:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-16 15:10:53 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnCancel( wxCommandEvent& event )
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::OnClose( wxCloseEvent& event )
|
|
|
|
{
|
|
|
|
// This is a cancel, so commit quietly as we're going to throw the results away anyway.
|
|
|
|
m_grid->CommitPendingChanges( true );
|
|
|
|
|
2020-09-04 07:49:54 +00:00
|
|
|
int retval = wxID_CANCEL;
|
2020-08-10 20:48:26 +00:00
|
|
|
|
2018-11-16 15:10:53 +00:00
|
|
|
if( m_dataModel->IsEdited() )
|
|
|
|
{
|
2020-08-10 20:48:26 +00:00
|
|
|
if( HandleUnsavedChanges( this, _( "Save changes?" ),
|
2021-10-01 20:49:14 +00:00
|
|
|
[&]() -> bool
|
2020-08-10 20:48:26 +00:00
|
|
|
{
|
|
|
|
if( TransferDataFromWindow() )
|
|
|
|
{
|
2020-09-04 07:49:54 +00:00
|
|
|
retval = wxID_OK;
|
2020-08-10 20:48:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} ) )
|
|
|
|
{
|
|
|
|
if( IsQuasiModal() )
|
|
|
|
EndQuasiModal( retval );
|
|
|
|
else
|
2021-07-21 21:37:49 +00:00
|
|
|
EndDialog( retval );
|
2020-08-10 20:48:26 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
2018-11-16 15:10:53 +00:00
|
|
|
{
|
|
|
|
event.Veto();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 07:49:54 +00:00
|
|
|
// No change in dialog: we can close it
|
|
|
|
if( IsQuasiModal() )
|
|
|
|
EndQuasiModal( retval );
|
|
|
|
else
|
2021-07-21 21:37:49 +00:00
|
|
|
EndDialog( retval );
|
2020-09-04 07:49:54 +00:00
|
|
|
|
|
|
|
return;
|
2018-11-16 15:10:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
void DIALOG_LIB_EDIT_PIN_TABLE::updateSummary()
|
2015-03-27 10:26:07 +00:00
|
|
|
{
|
2021-07-28 18:50:17 +00:00
|
|
|
PIN_NUMBERS pinNumbers;
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2018-02-08 12:16:07 +00:00
|
|
|
for( LIB_PIN* pin : m_pins )
|
|
|
|
{
|
|
|
|
if( pin->GetNumber().Length() )
|
|
|
|
pinNumbers.insert( pin->GetNumber() );
|
|
|
|
}
|
2015-03-27 10:26:07 +00:00
|
|
|
|
2021-04-19 04:44:13 +00:00
|
|
|
m_pin_numbers_summary->SetLabel( pinNumbers.GetSummary() );
|
|
|
|
|
|
|
|
wxString count;
|
|
|
|
count << m_pins.size();
|
|
|
|
m_pin_count->SetLabel( count );
|
|
|
|
|
|
|
|
m_duplicate_pins->SetLabel( pinNumbers.GetDuplicates() );
|
2018-02-08 12:16:07 +00:00
|
|
|
}
|