From bcd9a7745dded460ae74ad27d2f2c1da49229a68 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Thu, 8 Feb 2018 12:16:07 +0000 Subject: [PATCH] Make the pin table editable. Also adds generic icon + text grid renderer and grid editor. Fixes: lp:1521055 * https://bugs.launchpad.net/kicad/+bug/1521055 Fixes: lp:1528817 * https://bugs.launchpad.net/kicad/+bug/1528817 (cherry picked from commit 067f777) --- common/CMakeLists.txt | 1 + common/widgets/grid_icon_text_helpers.cpp | 191 ++++ eeschema/dialogs/dialog_lib_edit_pin.cpp | 6 +- .../dialogs/dialog_lib_edit_pin_table.cpp | 977 +++++++++--------- eeschema/dialogs/dialog_lib_edit_pin_table.h | 53 +- .../dialog_lib_edit_pin_table_base.cpp | 110 +- .../dialog_lib_edit_pin_table_base.fbp | 906 ++++++++++++++-- .../dialogs/dialog_lib_edit_pin_table_base.h | 37 +- eeschema/lib_edit_frame.cpp | 5 +- eeschema/lib_pin.cpp | 4 +- eeschema/lib_pin.h | 2 +- eeschema/pinedit.cpp | 2 +- include/widgets/grid_icon_text_helpers.h | 86 ++ 13 files changed, 1765 insertions(+), 615 deletions(-) create mode 100644 common/widgets/grid_icon_text_helpers.cpp create mode 100644 include/widgets/grid_icon_text_helpers.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index aa7330877d..a7719d4d60 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -178,6 +178,7 @@ set( COMMON_WIDGET_SRCS widgets/footprint_preview_widget.cpp widgets/footprint_select_widget.cpp widgets/gal_options_panel.cpp + widgets/grid_icon_text_helpers.cpp widgets/indicator_icon.cpp widgets/mathplot.cpp widgets/progress_reporter.cpp diff --git a/common/widgets/grid_icon_text_helpers.cpp b/common/widgets/grid_icon_text_helpers.cpp new file mode 100644 index 0000000000..8d348c7d0f --- /dev/null +++ b/common/widgets/grid_icon_text_helpers.cpp @@ -0,0 +1,191 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + + +//---- Grid helpers: custom wxGridCellRenderer ------------------------------------------ + + +GRID_CELL_ICON_TEXT_RENDERER::GRID_CELL_ICON_TEXT_RENDERER( const std::vector& icons, + const wxArrayString& names ) : + m_icons( icons ), + m_names( names ) +{ +} + +void GRID_CELL_ICON_TEXT_RENDERER::Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC, + const wxRect& aRect, int aRow, int aCol, + bool isSelected ) +{ + wxString value = aGrid.GetCellValue( aRow, aCol ); + wxBitmap bitmap; + + wxRect rect = aRect; + rect.Inflate( -1 ); + + // erase background + wxGridCellRenderer::Draw( aGrid, aAttr, aDC, aRect, aRow, aCol, isSelected ); + + // draw the icon + // note that the set of icons might be smaller than the set of labels if the last + // label is <...>. + if( m_names.Index( value ) < (int) m_icons.size() ) + { + bitmap = KiBitmap( (BITMAP_DEF) m_icons[ m_names.Index( value ) ] ); + aDC.DrawBitmap( bitmap, rect.GetLeft() + 3, rect.GetTop() + 2, true ); + } + // still need a bitmap to fetch the width + else + bitmap = KiBitmap( (BITMAP_DEF) m_icons[ 0 ] ); + + // draw the text + rect.SetLeft( rect.GetLeft() + bitmap.GetWidth() + 7 ); + SetTextColoursAndFont( aGrid, aAttr, aDC, isSelected ); + aGrid.DrawTextRectangle( aDC, value, rect, wxALIGN_LEFT, wxALIGN_CENTRE ); +} + + + +//---- Grid helpers: custom wxGridCellEditor ------------------------------------------ +// +// Note: this implementation is an adaptation of wxGridCellChoiceEditor + + +GRID_CELL_ICON_TEXT_POPUP::GRID_CELL_ICON_TEXT_POPUP( const std::vector& icons, + const wxArrayString& names ) : + m_icons( icons ), + m_names( names ) +{ +} + + +wxGridCellEditor* GRID_CELL_ICON_TEXT_POPUP::Clone() const +{ + return new GRID_CELL_ICON_TEXT_POPUP( m_icons, m_names ); +} + + +void GRID_CELL_ICON_TEXT_POPUP::Create( wxWindow* aParent, wxWindowID aId, + wxEvtHandler* aEventHandler ) +{ + m_control = new wxBitmapComboBox( + aParent, aId, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, + wxCB_READONLY | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxBORDER_NONE ); + + for( unsigned i = 0; i < m_names.size(); ++i ) + { + // note that the set of icons might be smaller than the set of labels if + // the last label is <...>. + if( i < m_icons.size() ) + Combo()->Append( m_names[ i ], KiBitmap( m_icons[ i ] ) ); + else + Combo()->Append( m_names[ i ] ); + } + + wxGridCellEditor::Create(aParent, aId, aEventHandler); +} + +wxString GRID_CELL_ICON_TEXT_POPUP::GetValue() const +{ + return Combo()->GetValue(); +} + +void GRID_CELL_ICON_TEXT_POPUP::SetSize( const wxRect& aRect ) +{ + wxRect rect( aRect ); + rect.Inflate( -1 ); + +#if !defined( __WXMSW__ ) && !defined( __WXGTK20__ ) + // Only implemented in generic wxBitmapComboBox; MSW and GTK use native controls + Combo()->SetButtonPosition( 0, 0, wxRIGHT, 2 ); +#endif + +#if defined( __WXMAC__ ) + rect.Inflate( 3 ); // no FOCUS_RING, even on Mac +#endif + + Combo()->SetSize( rect, wxSIZE_ALLOW_MINUS_ONE ); +} + + +void GRID_CELL_ICON_TEXT_POPUP::BeginEdit( int aRow, int aCol, wxGrid* aGrid ) +{ + auto evtHandler = static_cast( m_control->GetEventHandler() ); + + // Don't immediately end if we get a kill focus event within BeginEdit + evtHandler->SetInSetFocus( true ); + + m_value = aGrid->GetTable()->GetValue( aRow, aCol ); + + Combo()->SetSelection( Combo()->FindString( m_value ) ); + Combo()->SetFocus(); + +#ifdef __WXOSX_COCOA__ + // This is a work around for the combobox being simply dismissed when a + // choice is made in it under OS X. The bug is almost certainly due to a + // problem in focus events generation logic but it's not obvious to fix and + // for now this at least allows to use wxGrid. + Combo()->Popup(); +#endif + + // When dropping down the menu, a kill focus event + // happens after this point, so we can't reset the flag yet. +#if !defined(__WXGTK20__) + evtHandler->SetInSetFocus( false ); +#endif +} + + +bool GRID_CELL_ICON_TEXT_POPUP::EndEdit( int , int , const wxGrid* , const wxString& , + wxString *aNewVal ) +{ + const wxString value = Combo()->GetValue(); + + if( value == m_value ) + return false; + + m_value = value; + + if( aNewVal ) + *aNewVal = value; + + return true; +} + + +void GRID_CELL_ICON_TEXT_POPUP::ApplyEdit( int aRow, int aCol, wxGrid* aGrid ) +{ + aGrid->GetTable()->SetValue( aRow, aCol, m_value ); +} + + +void GRID_CELL_ICON_TEXT_POPUP::Reset() +{ + Combo()->SetSelection( Combo()->FindString( m_value ) ); +} + + diff --git a/eeschema/dialogs/dialog_lib_edit_pin.cpp b/eeschema/dialogs/dialog_lib_edit_pin.cpp index 89c248d499..618a900530 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin.cpp +++ b/eeschema/dialogs/dialog_lib_edit_pin.cpp @@ -133,10 +133,10 @@ void DIALOG_LIB_EDIT_PIN::OnPropertiesChange( wxCommandEvent& event ) if( ! IsShown() ) // do nothing at init time return; - int pinNameSize = ValueFromString( g_UserUnit, GetPinNameTextSize() ); - int pinNumSize = ValueFromString( g_UserUnit, GetPadNameTextSize()); + int pinNameSize = ValueFromString( m_units, GetPinNameTextSize() ); + int pinNumSize = ValueFromString( m_units, GetPadNameTextSize()); int pinOrient = LIB_PIN::GetOrientationCode( GetOrientation() ); - int pinLength = ValueFromString( g_UserUnit, GetLength() ); + int pinLength = ValueFromString( m_units, GetLength() ); GRAPHIC_PINSHAPE pinShape = GetStyle(); ELECTRICAL_PINTYPE pinType = GetElectricalType(); diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table.cpp b/eeschema/dialogs/dialog_lib_edit_pin_table.cpp index d97ad0ab6a..671535eae7 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin_table.cpp +++ b/eeschema/dialogs/dialog_lib_edit_pin_table.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,560 +24,593 @@ #include "dialog_lib_edit_pin_table.h" #include "lib_pin.h" #include "pin_number.h" +#include "grid_tricks.h" +#include -#include #include -#include -#include +#include +#include +#include +#include -/* Avoid wxWidgets bug #16906 -- http://trac.wxwidgets.org/ticket/16906 - * - * If multiple elements live in the root of a wxDataViewCtrl, using - * ItemsAdded() can run into an assertion failure. To avoid this, we avoid - * notifying the widget of changes, but rather reinitialize it. - * - * When a fix for this exists in wxWidgets, this is the place to turn it - * off. - */ -#define REASSOCIATE_HACK -class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel : - public wxDataViewModel +// Indicator that multiple values exist in child rows +#define ROW_MULT_ITEMS wxString( "< ... >" ) + +#define PinTableShownColumnsKey wxT( "PinTableShownColumns" ) + + +static std::vector g_typeIcons; +static wxArrayString g_typeNames; + +static std::vector g_shapeIcons; +static wxArrayString g_shapeNames; + +static std::vector g_orientationIcons; +static wxArrayString g_orientationNames; + + +class PIN_TABLE_DATA_MODEL : public wxGridTableBase { -public: - DataViewModel( LIB_PART& aPart ); - - // wxDataViewModel - virtual unsigned int GetColumnCount() const override; - virtual wxString GetColumnType( unsigned int col ) const override; - virtual void GetValue( wxVariant&, const wxDataViewItem&, unsigned int ) const override; - virtual bool SetValue( const wxVariant&, const wxDataViewItem&, unsigned int ) override; - virtual wxDataViewItem GetParent( const wxDataViewItem& ) const override; - virtual bool IsContainer( const wxDataViewItem& ) const override; - virtual bool HasContainerColumns( const wxDataViewItem& ) const override; - virtual unsigned int GetChildren( const wxDataViewItem&, wxDataViewItemArray& ) const override; - - virtual int Compare( const wxDataViewItem& lhs, - const wxDataViewItem& rhs, - unsigned int col, - bool ascending ) const override; - - void SetGroupingColumn( int aCol ); - void CalculateGrouping(); - void Refresh(); - - PinNumbers GetAllPinNumbers(); - -#ifdef REASSOCIATE_HACK - void SetWidget( wxDataViewCtrl* aWidget ) { m_Widget = aWidget; } -#endif - - enum - { - NONE = -1, - PIN_NUMBER = 0, - PIN_NAME = 1, - PIN_TYPE = 2, - PIN_POSITION = 3 - }; private: - LIB_PART& m_Part; - LIB_PINS m_Backing; - int m_GroupingColumn; - int m_UnitCount; + // 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 m_rows; - class Item; - class Group; - class Pin; + EDA_UNITS_T m_userUnits; - mutable std::list m_Pins; - mutable std::map m_Groups; - - // like GetValue, but always returns a string - wxString GetString( const wxDataViewItem&, unsigned int ) const; - -#ifdef REASSOCIATE_HACK - wxDataViewCtrl* m_Widget; -#endif -}; - -class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Item -{ public: - virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const = 0; - virtual wxString GetString( unsigned int aCol ) const = 0; - virtual wxDataViewItem GetParent() const = 0; - virtual bool IsContainer() const = 0; - virtual unsigned int GetChildren( wxDataViewItemArray& ) const = 0; -}; + PIN_TABLE_DATA_MODEL( EDA_UNITS_T aUserUnits ) : + m_userUnits( aUserUnits ) + {} -class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group : - public Item -{ -public: - Group( unsigned int aGroupingColumn ) : m_GroupingColumn( aGroupingColumn ) {} + int GetNumberRows() override { return (int) m_rows.size(); } + int GetNumberCols() override { return COL_COUNT; } - virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const override; - virtual wxString GetString( unsigned int aCol ) const override; - virtual wxDataViewItem GetParent() const override { return wxDataViewItem(); } - virtual bool IsContainer() const override { return true; } - virtual unsigned int GetChildren( wxDataViewItemArray& aItems ) const override + wxString GetColLabelValue( int aCol ) override { - /// @todo C++11 - for( std::list::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i ) - aItems.push_back( wxDataViewItem( *i ) ); - - return aItems.size(); + switch( aCol ) + { + 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" ); + default: wxFAIL; return wxEmptyString; + } } - unsigned int GetCount() const { return m_Members.size(); } - void Add( Pin* aPin ); - -private: - std::list m_Members; - unsigned int m_GroupingColumn; -}; - -class DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Pin : - public Item -{ -public: - Pin( DataViewModel& aModel, - LIB_PIN* aBacking ) : m_Model( aModel ), m_Backing( aBacking ), m_Group( 0 ) {} - - virtual void GetValue( wxVariant& aValue, unsigned int aCol ) const override; - virtual wxString GetString( unsigned int aCol ) const override; - virtual wxDataViewItem GetParent() const override { return wxDataViewItem( m_Group ); } - virtual bool IsContainer() const override { return false; } - virtual unsigned int GetChildren( wxDataViewItemArray& ) const override { return 0; } - - void SetGroup( Group* aGroup ) { m_Group = aGroup; } - - static bool Compare( const Pin& lhs, const Pin& rhs ) + bool IsEmptyCell( int row, int col ) override { - return PinNumbers::Compare( lhs.m_Backing->GetNumber(), rhs.m_Backing->GetNumber() ) < 0; + return false; // don't allow adjacent cell overflow, even if we are actually empty } -private: - DataViewModel& m_Model; - LIB_PIN* m_Backing; - Group* m_Group; + wxString GetValue( int aRow, int aCol ) override + { + return GetValue( m_rows[ aRow ], aCol, m_userUnits ); + } + + static wxString GetValue( const LIB_PINS& pins, int aCol, EDA_UNITS_T aUserUnits ) + { + wxString fieldValue; + + if( pins.empty()) + return fieldValue; + + for( LIB_PIN* pin : pins ) + { + wxString val; + + switch( aCol ) + { + case COL_NUMBER: + val = pin->GetNumber(); + break; + case COL_NAME: + val = pin->GetName(); + break; + case COL_TYPE: + val = g_typeNames[ pin->GetType() ]; + break; + case COL_SHAPE: + val = g_shapeNames[ pin->GetShape() ]; + break; + case COL_ORIENTATION: + val = g_orientationNames[ LIB_PIN::GetOrientationIndex( pin->GetOrientation() ) ]; + break; + case COL_NUMBER_SIZE: + val = StringFromValue( aUserUnits, pin->GetNumberTextSize(), true, true ); + break; + case COL_NAME_SIZE: + val = StringFromValue( aUserUnits, pin->GetNameTextSize(), true, true ); + break; + case COL_LENGTH: + val = StringFromValue( aUserUnits, pin->GetLength(), true ); + break; + case COL_POSX: + val = StringFromValue( aUserUnits, pin->GetPosition().x, true ); + break; + case COL_POSY: + val = StringFromValue( aUserUnits, pin->GetPosition().y, true ); + break; + default: + wxFAIL; + break; + } + + if( aCol == COL_NUMBER ) + { + if( fieldValue.length() ) + fieldValue += wxT( ", " ); + fieldValue += val; + } + else + { + if( !fieldValue.Length() ) + fieldValue = val; + else if( val != fieldValue ) + fieldValue = ROW_MULT_ITEMS; + } + } + + return fieldValue; + } + + void SetValue( int aRow, int aCol, const wxString &aValue ) override + { + if( aValue == ROW_MULT_ITEMS ) + return; + + LIB_PINS pins = m_rows[ aRow ]; + + for( LIB_PIN* pin : pins ) + { + switch( aCol ) + { + case COL_NUMBER: + pin->SetNumber( aValue ); + break; + case COL_NAME: + pin->SetName( aValue ); + break; + case COL_TYPE: + pin->SetType( (ELECTRICAL_PINTYPE) g_typeNames.Index( aValue ), false ); + break; + case COL_SHAPE: + pin->SetShape( (GRAPHIC_PINSHAPE) g_shapeNames.Index( aValue ) ); + break; + case COL_ORIENTATION: + pin->SetOrientation( LIB_PIN::GetOrientationCode( + g_orientationNames.Index( aValue ) ), false ); + break; + case COL_NUMBER_SIZE: + pin->SetNumberTextSize( ValueFromString( m_userUnits, aValue, true ) ); + break; + case COL_NAME_SIZE: + pin->SetNameTextSize( ValueFromString( m_userUnits, aValue, true ) ); + break; + case COL_LENGTH: + pin->SetLength( ValueFromString( m_userUnits, aValue ) ); + break; + case COL_POSX: + pin->SetPinPosition( wxPoint( ValueFromString( m_userUnits, aValue ), + pin->GetPosition().y ) ); + break; + case COL_POSY: + pin->SetPinPosition( wxPoint( pin->GetPosition().x, + ValueFromString( m_userUnits, aValue ) ) ); + break; + default: + wxFAIL; + break; + } + } + } + + static int findRow( const std::vector& aRowSet, const wxString& aName ) + { + for( size_t i = 0; i < aRowSet.size(); ++i ) + { + if( aRowSet[ i ][ 0 ] && aRowSet[ i ][ 0 ]->GetName() == aName ) + return i; + } + + return -1; + } + + static bool compare( const LIB_PINS& lhs, const LIB_PINS& rhs, + int sortCol, bool ascending, EDA_UNITS_T units ) + { + wxString lhStr = GetValue( lhs, sortCol, units ); + wxString rhStr = GetValue( rhs, sortCol, units ); + bool retVal; + + if( lhStr == rhStr ) + { + // Secondary sort key is always COL_NUMBER + retVal = GetValue( lhs, COL_NUMBER, units ) < GetValue( rhs, COL_NUMBER, units ); + } + else + retVal = lhStr < rhStr; + + return ascending == retVal; + } + + void RebuildRows( LIB_PINS& aPins, bool groupByName ) + { + if ( GetView() ) + { + // Commit any pending in-place edits before the row gets moved out from under + // the editor. + GetView()->DisableCellEditControl(); + + wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() ); + GetView()->ProcessTableMessage( msg ); + } + + m_rows.clear(); + + for( LIB_PIN* pin : aPins ) + { + int rowIndex = -1; + + if( groupByName ) + rowIndex = findRow( m_rows, pin->GetName() ); + + if( rowIndex < 0 ) + { + m_rows.emplace_back( LIB_PINS() ); + rowIndex = m_rows.size() - 1; + } + + m_rows[ rowIndex ].push_back( pin ); + } + + int sortCol = 0; + bool ascending = true; + + if( GetView() && GetView()->GetSortingColumn() != wxNOT_FOUND ) + { + sortCol = GetView()->GetSortingColumn(); + ascending = GetView()->IsSortOrderAscending(); + } + + SortRows( sortCol, ascending ); + + if ( GetView() ) + { + wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() ); + GetView()->ProcessTableMessage( msg ); + } + } + + void SortRows( int aSortCol, bool ascending ) + { + std::sort( m_rows.begin(), m_rows.end(), + [ aSortCol, ascending, this ]( LIB_PINS lhs, LIB_PINS rhs ) -> bool + { return compare( lhs, rhs, aSortCol, ascending, m_userUnits ); } ); + } + + void AppendRow( LIB_PIN* aPin ) + { + 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 ); + } + } + + LIB_PINS RemoveRow( int aRow ) + { + LIB_PINS removedRow = m_rows[ aRow ]; + + m_rows.erase( m_rows.begin() + aRow ); + + if ( GetView() ) + { + wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 ); + GetView()->ProcessTableMessage( msg ); + } + + return removedRow; + } }; -DIALOG_LIB_EDIT_PIN_TABLE::DIALOG_LIB_EDIT_PIN_TABLE( wxWindow* parent, - LIB_PART& aPart ) : + +DIALOG_LIB_EDIT_PIN_TABLE::DIALOG_LIB_EDIT_PIN_TABLE( wxWindow* parent, LIB_PART* aPart ) : DIALOG_LIB_EDIT_PIN_TABLE_BASE( parent ), - m_Model( new DataViewModel( aPart ) ) + m_part( aPart ) { -#ifdef REASSOCIATE_HACK - m_Model->SetWidget( m_Pins ); -#endif - m_Pins->AssociateModel( m_Model.get() ); + m_config = Kiface().KifaceSettings(); - /// @todo wxFormBuilder bug #61 -- move to base once supported - wxDataViewTextRenderer* rend0 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); - wxDataViewColumn* col0 = new wxDataViewColumn( _( "Number" ), - rend0, - DataViewModel::PIN_NUMBER, - 100, - wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), - wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE ); - wxDataViewTextRenderer* rend1 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); - wxDataViewColumn* col1 = new wxDataViewColumn( _( "Name" ), - rend1, - DataViewModel::PIN_NAME, - 100, - wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), - wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE ); - wxDataViewIconTextRenderer* rend2 = new wxDataViewIconTextRenderer( wxT( "wxDataViewIconText" ), wxDATAVIEW_CELL_INERT ); - wxDataViewColumn* col2 = new wxDataViewColumn( _( "Type" ), - rend2, - DataViewModel::PIN_TYPE, - 100, - wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), - wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE ); - wxDataViewTextRenderer* rend3 = new wxDataViewTextRenderer( wxT( "string" ), wxDATAVIEW_CELL_INERT ); - wxDataViewColumn* col3 = new wxDataViewColumn( _( "Position" ), - rend3, - DataViewModel::PIN_POSITION, - 100, - wxAlignment( wxALIGN_LEFT | wxALIGN_TOP ), - wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE ); - m_Pins->AppendColumn( col0 ); - m_Pins->SetExpanderColumn( col0 ); - m_Pins->AppendColumn( col1 ); - m_Pins->AppendColumn( col2 ); - m_Pins->AppendColumn( col3 ); + if( g_typeNames.empty()) + { + for( unsigned i = 0; i < PINTYPE_COUNT; ++i ) + g_typeIcons.push_back( GetBitmap( static_cast( i ) ) ); + for( unsigned i = 0; i < PINTYPE_COUNT; ++i ) + g_typeNames.push_back( GetText( static_cast( i ) ) ); + g_typeNames.push_back( ROW_MULT_ITEMS ); - UpdateSummary(); + for( unsigned i = 0; i < PINSHAPE_COUNT; ++i ) + g_shapeIcons.push_back( GetBitmap( static_cast( i ) ) ); + for( unsigned i = 0; i < PINSHAPE_COUNT; ++i ) + g_shapeNames.push_back( GetText( static_cast( i ) ) ); + g_shapeNames.push_back( ROW_MULT_ITEMS ); + + for( unsigned i = 0; i < LIB_PIN::GetOrientationNames().size(); ++i ) + g_orientationIcons.push_back( LIB_PIN::GetOrientationSymbols()[ i ] ); + g_orientationNames = LIB_PIN::GetOrientationNames(); + g_orientationNames.push_back( ROW_MULT_ITEMS ); + } + + m_dataModel = new PIN_TABLE_DATA_MODEL( GetUserUnits() ); + + // 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 ); + + // Give a bit more room for combobox editors + m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 ); + + // wxGrid::SetTable() messes up the column widths; use GRID_TRICKS version instead + GRID_TRICKS::SetGridTable( m_grid, m_dataModel ); + + m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) ); + + // Show/hide columns according to the user's preference + m_config->Read( PinTableShownColumnsKey, &m_columnsShown, wxT( "0 1 2 3 4 8 9" ) ); + GRID_TRICKS::ShowHideGridColumns( m_grid, m_columnsShown ); + + // Set special attributes + wxGridCellAttr* attr; + + attr = new wxGridCellAttr; + attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_typeIcons, g_typeNames ) ); + attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_typeIcons, g_typeNames ) ); + m_grid->SetColAttr( COL_TYPE, attr ); + + attr = new wxGridCellAttr; + attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_shapeIcons, g_shapeNames ) ); + attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_shapeIcons, g_shapeNames ) ); + m_grid->SetColAttr( COL_SHAPE, attr ); + + attr = new wxGridCellAttr; + attr->SetRenderer( new GRID_CELL_ICON_TEXT_RENDERER( g_orientationIcons, g_orientationNames ) ); + attr->SetEditor( new GRID_CELL_ICON_TEXT_POPUP( g_orientationIcons, g_orientationNames ) ); + m_grid->SetColAttr( COL_ORIENTATION, attr ); + + /* Right-aligned position values look much better, but only MSW and GTK2+ + * currently support righ-aligned textEditCtrls, so the text jumps on all + * 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 ); + */ + + m_addButton->SetBitmap( KiBitmap( small_plus_xpm ) ); + m_deleteButton->SetBitmap( KiBitmap( trash_xpm ) ); + m_refreshButton->SetBitmap( KiBitmap( refresh_xpm ) ); GetSizer()->SetSizeHints(this); Centre(); + + m_ButtonsOK->SetDefault(); + m_initialized = true; + + // Connect Events + m_grid->Connect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this ); } DIALOG_LIB_EDIT_PIN_TABLE::~DIALOG_LIB_EDIT_PIN_TABLE() { + m_config->Write( PinTableShownColumnsKey, GRID_TRICKS::GetShownColumns( m_grid ) ); + + // Disconnect Events + m_grid->Disconnect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE::OnColSort ), nullptr, this ); + + // Prevents crash bug in wxGrid's d'tor + GRID_TRICKS::DestroyGridTable( m_grid, m_dataModel ); + + // Delete the GRID_TRICKS. + m_grid->PopEventHandler( true ); + + // This is our copy of the pins. If they were transfered to the part on an OK, then + // m_pins will already be empty. + for( auto pin : m_pins ) + delete pin; } -void DIALOG_LIB_EDIT_PIN_TABLE::UpdateSummary() +bool DIALOG_LIB_EDIT_PIN_TABLE::TransferDataToWindow() { - PinNumbers pins = m_Model->GetAllPinNumbers(); + // 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 ) ); - m_Summary->SetValue( pins.GetSummary() ); -} + m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() ); + updateSummary(); -void DIALOG_LIB_EDIT_PIN_TABLE::OnColumnHeaderRightClicked( wxDataViewEvent& event ) -{ - m_Model->SetGroupingColumn( event.GetDataViewColumn()->GetModelColumn() ); - event.Skip(); -} - - -DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::DataViewModel( LIB_PART& aPart ) : - m_Part( aPart ), - m_GroupingColumn( 1 ), - m_UnitCount( m_Part.GetUnitCount() ) -{ -#ifdef REASSOCIATE_HACK - m_Widget = NULL; -#endif - aPart.GetPins( m_Backing ); - /// @todo C++11 - for( LIB_PINS::const_iterator i = m_Backing.begin(); i != m_Backing.end(); ++i ) - m_Pins.push_back( Pin( *this, *i ) ); - - m_Pins.sort(Pin::Compare); - - CalculateGrouping(); -} - - -unsigned int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetColumnCount() const -{ - return 4; -} - - -wxString DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetColumnType( unsigned int aCol ) const -{ - switch( aCol ) - { - case PIN_NUMBER: - return wxT( "string" ); - - case PIN_NAME: - return wxT( "string" ); - - case PIN_TYPE: - return wxT( "wxDataViewIconText" ); - - case PIN_POSITION: - return wxT( "string" ); - } - - assert( ! "Unhandled column" ); - return wxT( "" ); -} - - -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetValue( wxVariant& aVal, - const wxDataViewItem& aItem, - unsigned int aCol ) const -{ - assert( aItem.IsOk() ); - - reinterpret_cast( aItem.GetID() )->GetValue( aVal, aCol ); -} - - -bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::SetValue( const wxVariant&, - const wxDataViewItem&, - unsigned int ) -{ - return false; -} - - -wxDataViewItem DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetParent( const wxDataViewItem& aItem ) -const -{ - assert( aItem.IsOk() ); - - return reinterpret_cast( aItem.GetID() )->GetParent(); -} - - -bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::IsContainer( const wxDataViewItem& aItem ) const -{ - if( aItem.IsOk() ) - return reinterpret_cast( aItem.GetID() )->IsContainer(); - else - return true; -} - - -bool DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::HasContainerColumns( const wxDataViewItem& ) const -{ return true; } -unsigned int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetChildren( const wxDataViewItem& aItem, - wxDataViewItemArray& aItems ) const +bool DIALOG_LIB_EDIT_PIN_TABLE::TransferDataFromWindow() { - if( !aItem.IsOk() ) + // Commit any pending in-place edits and close the editor + m_grid->DisableCellEditControl(); + + // 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 ) { - for( std::map::iterator i = m_Groups.begin(); i != m_Groups.end(); ++i ) - if( i->second.GetCount() > 1 ) - aItems.push_back( wxDataViewItem( &i->second ) ); - - for( std::list::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) - if( !i->GetParent().IsOk() ) - aItems.push_back( wxDataViewItem( &*i ) ); - - return aItems.size(); + pin->SetParent( m_part ); + m_part->AddDrawItem( pin ); } + + m_pins.clear(); + + return true; +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::OnColSort( wxGridEvent& aEvent ) +{ + 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(); else - return reinterpret_cast( aItem.GetID() )->GetChildren( aItems ); + // different column; start with ascending + ascending = true; + + m_dataModel->SortRows( sortCol, ascending ); } -int DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Compare( const wxDataViewItem& aItem1, - const wxDataViewItem& aItem2, - unsigned int aCol, - bool aAscending ) const +void DIALOG_LIB_EDIT_PIN_TABLE::OnAddRow( wxCommandEvent& event ) { - wxString str1 = GetString( aItem1, aCol ); - wxString str2 = GetString( aItem2, aCol ); - int res = PinNumbers::Compare( str1, str2 ); + m_pins.push_back( new LIB_PIN( nullptr ) ); - if( res == 0 ) - res = ( aItem1.GetID() < aItem2.GetID() ) ? -1 : 1; + m_dataModel->AppendRow( m_pins[ m_pins.size() - 1 ] ); - return res * ( aAscending ? 1 : -1 ); + m_grid->MakeCellVisible( m_grid->GetNumberRows() - 1, 0 ); + m_grid->SetGridCursor( m_grid->GetNumberRows() - 1, 0 ); + + m_grid->EnableCellEditControl( true ); + m_grid->ShowCellEditControl(); + + updateSummary(); } -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::SetGroupingColumn( int aCol ) +void DIALOG_LIB_EDIT_PIN_TABLE::OnDeleteRow( wxCommandEvent& event ) { - if( m_GroupingColumn == aCol ) - m_GroupingColumn = NONE; - else - m_GroupingColumn = aCol; + int curRow = m_grid->GetGridCursorRow(); - Cleared(); - CalculateGrouping(); - Refresh(); + if( curRow < 0 ) + return; + + LIB_PINS removedRow = m_dataModel->RemoveRow( curRow ); + + for( auto pin : removedRow ) + m_pins.erase( std::find( m_pins.begin(), m_pins.end(), pin ) ); + + curRow = std::max( 0, curRow - 1 ); + m_grid->MakeCellVisible( curRow, m_grid->GetGridCursorCol() ); + m_grid->SetGridCursor( curRow, m_grid->GetGridCursorCol() ); + + updateSummary(); } -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::CalculateGrouping() +void DIALOG_LIB_EDIT_PIN_TABLE::OnCellEdited( wxGridEvent& event ) { - m_Groups.clear(); + updateSummary(); +} - if( m_GroupingColumn != -1 ) + +void DIALOG_LIB_EDIT_PIN_TABLE::OnRebuildRows( wxCommandEvent& ) +{ + m_dataModel->RebuildRows( m_pins, m_cbGroup->GetValue() ); + + adjustGridColumns( m_grid->GetRect().GetWidth() ); +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::adjustGridColumns( int aWidth ) +{ + // Account for scroll bars + aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x ); + + wxGridUpdateLocker deferRepaintsTillLeavingScope; + + // The Number and Name columns must be at least wide enough to hold their contents, but + // no less wide than their original widths. + + m_grid->AutoSizeColumn( COL_NUMBER ); + + if( m_grid->GetColSize( COL_NUMBER ) < m_originalColWidths[ COL_NUMBER ] ) + m_grid->SetColSize( COL_NUMBER, m_originalColWidths[ COL_NUMBER ] ); + + m_grid->AutoSizeColumn( COL_NAME ); + + if( m_grid->GetColSize( COL_NAME ) < m_originalColWidths[ COL_NAME ] ) + m_grid->SetColSize( COL_NAME, m_originalColWidths[ COL_NAME ] ); + + // If the grid is still wider than the columns, then stretch the Number and Name columns + // to fit. + + for( int i = 0; i < COL_COUNT; ++i ) + aWidth -= m_grid->GetColSize( i ); + + if( aWidth > 0 ) { - wxVariant value; - - for( std::list::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) - { - wxString str = i->GetString( m_GroupingColumn ); - std::map::iterator j = m_Groups.find( str ); - - if( j == m_Groups.end() ) - j = m_Groups.insert( std::make_pair( str, m_GroupingColumn ) ).first; - - j->second.Add( &*i ); - } - } - else - { - for( std::list::iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) - i->SetGroup( 0 ); + m_grid->SetColSize( COL_NUMBER, m_grid->GetColSize( COL_NUMBER ) + aWidth / 2 ); + m_grid->SetColSize( COL_NAME, m_grid->GetColSize( COL_NAME ) + aWidth / 2 ); } } -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Refresh() +void DIALOG_LIB_EDIT_PIN_TABLE::OnSize( wxSizeEvent& event ) { -#ifdef REASSOCIATE_HACK - m_Widget->AssociateModel( this ); -#else - std::queue todo; - todo.push( wxDataViewItem() ); + if( m_initialized ) + adjustGridColumns( event.GetSize().GetX() ); - while( !todo.empty() ) + event.Skip(); +} + + +void DIALOG_LIB_EDIT_PIN_TABLE::OnUpdateUI( wxUpdateUIEvent& event ) +{ + wxString columnsShown = GRID_TRICKS::GetShownColumns( m_grid ); + + if( columnsShown != m_columnsShown ) { - wxDataViewItem current = todo.front(); - wxDataViewItemArray items; + m_columnsShown = columnsShown; - GetChildren( current, items ); - ItemsAdded( current, items ); - - for( wxDataViewItemArray::const_iterator i = items.begin(); i != items.end(); ++i ) - { - if( IsContainer( *i ) ) - todo.push( *i ); - } - - todo.pop(); - } - -#endif -} - - -PinNumbers DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetAllPinNumbers() -{ - PinNumbers ret; - - for( std::list::const_iterator i = m_Pins.begin(); i != m_Pins.end(); ++i ) - ret.insert( i->GetString( PIN_NUMBER ) ); - - return ret; -} - - -wxString DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::GetString( const wxDataViewItem& aItem, unsigned int aCol ) const -{ - assert( aItem.IsOk() ); - - return reinterpret_cast( aItem.GetID() )->GetString( aCol ); -} - - -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group::GetValue( wxVariant& aValue, - unsigned int aCol ) const -{ - if( aCol == m_GroupingColumn ) - // shortcut - m_Members.front()->GetValue( aValue, aCol ); - else if( aCol != PIN_TYPE ) - aValue = GetString( aCol ); - else - { - PinNumbers values; - - for( std::list::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i ) - values.insert( (*i)->GetString( aCol ) ); - - if( values.size() > 1 ) - { - // when multiple pins are grouped, thes have not necessary the same electrical type - // therefore use a neutral icon to show a type. - // Do Not use a null icon, because on some OS (Linux), for an obscure reason, - // if a null icon is used somewhere, no other icon is displayed - wxIcon icon_notype; - icon_notype.CopyFromBitmap( KiBitmap ( pintype_notspecif_xpm ) ); // could be tree_nosel_xpm - aValue << wxDataViewIconText( boost::algorithm::join( values, "," ), icon_notype ); - } - else - m_Members.front()->GetValue( aValue, aCol ); + if( !m_grid->IsCellEditControlShown() ) + adjustGridColumns( m_grid->GetRect().GetWidth() ); } } -wxString DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group::GetString( unsigned int aCol ) const +void DIALOG_LIB_EDIT_PIN_TABLE::updateSummary() { - if( aCol == m_GroupingColumn ) - return m_Members.front()->GetString( aCol ); + PinNumbers pinNumbers; - PinNumbers values; - - for( std::list::const_iterator i = m_Members.begin(); i != m_Members.end(); ++i ) - values.insert( (*i)->GetString( aCol ) ); - - if( values.size() > 1 ) - return boost::algorithm::join( values, "," ); - else - return m_Members.front()->GetString( aCol ); -} - - -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Group::Add( Pin* aPin ) -{ - switch( GetCount() ) + for( LIB_PIN* pin : m_pins ) { - case 0: - aPin->SetGroup( 0 ); - break; - - case 1: - m_Members.front()->SetGroup( this ); - // fall through - - default: - aPin->SetGroup( this ); + if( pin->GetNumber().Length() ) + pinNumbers.insert( pin->GetNumber() ); } - m_Members.push_back( aPin ); + m_summary->SetLabel( pinNumbers.GetSummary() ); } -void DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Pin::GetValue( wxVariant& aValue, - unsigned int aCol ) const -{ - switch( aCol ) - { - case PIN_NUMBER: - case PIN_NAME: - case PIN_POSITION: - aValue = GetString( aCol ); - break; - - case PIN_TYPE: - { - wxIcon icon; - icon.CopyFromBitmap( KiBitmap ( GetBitmap( m_Backing->GetType() ) ) ); - aValue << wxDataViewIconText( m_Backing->GetElectricalTypeName(), icon ); - } - break; - } -} -wxString DIALOG_LIB_EDIT_PIN_TABLE::DataViewModel::Pin::GetString( unsigned int aCol ) const -{ - switch( aCol ) - { - case PIN_NUMBER: - return m_Backing->GetNumber(); - - case PIN_NAME: - if( m_Model.m_UnitCount > 1 ) - { - wxString name; - int unit = m_Backing->GetPartNumber(); - - if( unit ) - name << unit; - else - name << "com"; - - name << ':'; - name << m_Backing->GetName(); - return name; - } - else - { - return m_Backing->GetName(); - } - - case PIN_TYPE: - return m_Backing->GetElectricalTypeName(); - - case PIN_POSITION: - { - wxPoint position = m_Backing->GetPosition(); - wxString value; - value << "(" << position.x << "," << position.y << ")"; - return value; - } - } - - return wxEmptyString; -} diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table.h b/eeschema/dialogs/dialog_lib_edit_pin_table.h index 8be318a61e..a07295f890 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin_table.h +++ b/eeschema/dialogs/dialog_lib_edit_pin_table.h @@ -2,19 +2,54 @@ #include "class_library.h" -class DIALOG_LIB_EDIT_PIN_TABLE : - public DIALOG_LIB_EDIT_PIN_TABLE_BASE +enum COL_ORDER +{ + COL_NUMBER, + COL_NAME, + COL_TYPE, + COL_SHAPE, + COL_ORIENTATION, + COL_NUMBER_SIZE, + COL_NAME_SIZE, + COL_LENGTH, + COL_POSX, + COL_POSY, + + COL_COUNT // keep as last +}; + + +class PIN_TABLE_DATA_MODEL; + + +class DIALOG_LIB_EDIT_PIN_TABLE : public DIALOG_LIB_EDIT_PIN_TABLE_BASE { public: - DIALOG_LIB_EDIT_PIN_TABLE( wxWindow* parent, LIB_PART& aPart ); - ~DIALOG_LIB_EDIT_PIN_TABLE(); + DIALOG_LIB_EDIT_PIN_TABLE( wxWindow* parent, LIB_PART* aPart ); + ~DIALOG_LIB_EDIT_PIN_TABLE() override; - void UpdateSummary(); + bool TransferDataToWindow() override; + bool TransferDataFromWindow() override; - virtual void OnColumnHeaderRightClicked( wxDataViewEvent& aEvent ) override; + void OnColSort( wxGridEvent& aEvent ); + void OnAddRow( wxCommandEvent& event ) override; + void OnDeleteRow( wxCommandEvent& event ) override; + void OnSize( wxSizeEvent& event ) override; + void OnCellEdited( wxGridEvent& event ) override; + void OnRebuildRows( wxCommandEvent& event ) override; + void OnUpdateUI( wxUpdateUIEvent& event ) override; -private: - class DataViewModel; +protected: - wxObjectDataPtr m_Model; + void updateSummary(); + void adjustGridColumns( int aWidth ); + + wxConfigBase* m_config; + bool m_initialized = false; + int m_originalColWidths[ COL_COUNT ]; + wxString m_columnsShown; + LIB_PART* m_part; + LIB_PINS m_pins; // a copy of the pins owned by me + + PIN_TABLE_DATA_MODEL* m_dataModel; }; diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp b/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp index 5376208131..767c233469 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp +++ b/eeschema/dialogs/dialog_lib_edit_pin_table_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Nov 22 2017) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -16,20 +16,100 @@ DIALOG_LIB_EDIT_PIN_TABLE_BASE::DIALOG_LIB_EDIT_PIN_TABLE_BASE( wxWindow* parent wxBoxSizer* top_sizer; top_sizer = new wxBoxSizer( wxVERTICAL ); - m_Pins = new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxDV_HORIZ_RULES|wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES ); - m_Pins->SetMinSize( wxSize( 400,300 ) ); + m_grid = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); - top_sizer->Add( m_Pins, 1, wxALL|wxEXPAND, 5 ); + // Grid + m_grid->CreateGrid( 5, 10 ); + m_grid->EnableEditing( true ); + m_grid->EnableGridLines( true ); + m_grid->EnableDragGridSize( false ); + m_grid->SetMargins( 0, 0 ); - m_Summary = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY|wxNO_BORDER ); - top_sizer->Add( m_Summary, 0, wxALL|wxEXPAND, 5 ); + // Columns + m_grid->SetColSize( 0, 66 ); + m_grid->SetColSize( 1, 84 ); + m_grid->SetColSize( 2, 140 ); + m_grid->SetColSize( 3, 140 ); + m_grid->SetColSize( 4, 100 ); + m_grid->SetColSize( 5, 110 ); + m_grid->SetColSize( 6, 110 ); + m_grid->SetColSize( 7, 84 ); + m_grid->SetColSize( 8, 84 ); + m_grid->SetColSize( 9, 84 ); + m_grid->EnableDragColMove( false ); + m_grid->EnableDragColSize( true ); + m_grid->SetColLabelSize( 24 ); + m_grid->SetColLabelValue( 0, _("Number") ); + m_grid->SetColLabelValue( 1, _("Name") ); + m_grid->SetColLabelValue( 2, _("Electrical Type") ); + m_grid->SetColLabelValue( 3, _("Graphic Style") ); + m_grid->SetColLabelValue( 4, _("Orientation") ); + m_grid->SetColLabelValue( 5, _("Number Text Size") ); + m_grid->SetColLabelValue( 6, _("Name Text Size") ); + m_grid->SetColLabelValue( 7, _("Length") ); + m_grid->SetColLabelValue( 8, _("X Position") ); + m_grid->SetColLabelValue( 9, _("Y Position") ); + m_grid->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_grid->EnableDragRowSize( false ); + m_grid->SetRowLabelSize( 0 ); + m_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + m_grid->SetMinSize( wxSize( 720,240 ) ); + + top_sizer->Add( m_grid, 1, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 10 ); + + wxBoxSizer* bSizer2; + bSizer2 = new wxBoxSizer( wxHORIZONTAL ); + + m_addButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_addButton->SetMinSize( wxSize( 29,29 ) ); + + bSizer2->Add( m_addButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); + + m_deleteButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_deleteButton->SetMinSize( wxSize( 29,29 ) ); + + bSizer2->Add( m_deleteButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 10 ); + + m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); + bSizer2->Add( m_staticline1, 0, wxEXPAND|wxALL, 5 ); + + m_cbGroup = new wxCheckBox( this, wxID_ANY, _("Group by name"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_cbGroup, 0, wxALIGN_CENTER_VERTICAL|wxALL, 10 ); + + m_refreshButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_refreshButton->SetMinSize( wxSize( 29,29 ) ); + + bSizer2->Add( m_refreshButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 ); + + m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL ); + bSizer2->Add( m_staticline2, 0, wxEXPAND | wxALL, 5 ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, _("Pin numbers:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + bSizer2->Add( m_staticText1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 10 ); + + m_summary = new wxStaticText( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 ); + m_summary->Wrap( -1 ); + bSizer2->Add( m_summary, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_Buttons = new wxStdDialogButtonSizer(); m_ButtonsOK = new wxButton( this, wxID_OK ); m_Buttons->AddButton( m_ButtonsOK ); + m_ButtonsCancel = new wxButton( this, wxID_CANCEL ); + m_Buttons->AddButton( m_ButtonsCancel ); m_Buttons->Realize(); - top_sizer->Add( m_Buttons, 0, wxEXPAND|wxALL, 5 ); + bSizer2->Add( m_Buttons, 0, wxEXPAND, 5 ); + + + top_sizer->Add( bSizer2, 0, wxEXPAND|wxLEFT, 5 ); this->SetSizer( top_sizer ); @@ -39,12 +119,24 @@ DIALOG_LIB_EDIT_PIN_TABLE_BASE::DIALOG_LIB_EDIT_PIN_TABLE_BASE( wxWindow* parent this->Centre( wxBOTH ); // Connect Events - m_Pins->Connect( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, wxDataViewEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnColumnHeaderRightClicked ), NULL, this ); + this->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnUpdateUI ) ); + m_grid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnCellEdited ), NULL, this ); + m_grid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnSize ), NULL, this ); + m_addButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnAddRow ), NULL, this ); + m_deleteButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnDeleteRow ), NULL, this ); + m_cbGroup->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnRebuildRows ), NULL, this ); + m_refreshButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnRebuildRows ), NULL, this ); } DIALOG_LIB_EDIT_PIN_TABLE_BASE::~DIALOG_LIB_EDIT_PIN_TABLE_BASE() { // Disconnect Events - m_Pins->Disconnect( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, wxDataViewEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnColumnHeaderRightClicked ), NULL, this ); + this->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnUpdateUI ) ); + m_grid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnCellEdited ), NULL, this ); + m_grid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnSize ), NULL, this ); + m_addButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnAddRow ), NULL, this ); + m_deleteButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnDeleteRow ), NULL, this ); + m_cbGroup->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnRebuildRows ), NULL, this ); + m_refreshButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_LIB_EDIT_PIN_TABLE_BASE::OnRebuildRows ), NULL, this ); } diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp b/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp index a69d8653ef..a0d62aadc1 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp +++ b/eeschema/dialogs/dialog_lib_edit_pin_table_base.fbp @@ -87,85 +87,17 @@ - + OnUpdateUI top_sizer wxVERTICAL none - 5 - wxALL|wxEXPAND + 10 + wxEXPAND|wxLEFT|wxRIGHT|wxTOP 1 - - - - 1 - 1 - - - 0 - wxID_ANY - - 400,300 - m_Pins - protected - - -1,-1 - wxDV_HORIZ_RULES|wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES - - - - - - - - OnColumnHeaderRightClicked - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL|wxEXPAND - 0 - + 1 1 1 @@ -174,34 +106,58 @@ + 0 + 0 1 + + + wxALIGN_LEFT + + wxALIGN_TOP 0 1 + wxALIGN_CENTRE + 24 + "Number" "Name" "Electrical Type" "Graphic Style" "Orientation" "Number Text Size" "Name Text Size" "Length" "X Position" "Y Position" + wxALIGN_CENTRE + 10 + 66,84,140,140,100,110,110,84,84,84 1 0 Dock 0 Left + 0 + 1 + 0 + 0 + 1 1 1 + + 1 0 0 wxID_ANY + + + + 0 + 0 0 - 0 - + 720,240 1 - m_Summary + m_grid 1 @@ -209,23 +165,55 @@ 1 Resizable + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + + 5 1 - wxTE_READONLY - + ; forward_declare 0 - - wxFILTER_NONE - wxDefaultValidator - - - wxNO_BORDER + + OnCellEdited + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -244,38 +232,740 @@ - - - - - + OnSize 5 - wxEXPAND|wxALL + wxEXPAND|wxLEFT 0 - - 0 - 0 - 0 - 0 - 0 - 1 - 0 - 0 + - m_Buttons - protected - - - - - - - - + bSizer2 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + + wxID_ANY + Add Pin + + 0 + + 22,22 + 0 + 29,29 + 1 + m_addButton + 1 + + + protected + 1 + + Resizable + + 1 + + wxBU_AUTODRAW + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnAddRow + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + + wxID_ANY + Delete Pin + + 0 + + -1,-1 + 0 + 29,29 + 1 + m_deleteButton + 1 + + + protected + 1 + + Resizable + + 1 + + wxBU_AUTODRAW + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnDeleteRow + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_VERTICAL + ; forward_declare + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Group by name + + 0 + + + 0 + + 1 + m_cbGroup + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnRebuildRows + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + + wxID_ANY + Refresh Grouping + + 0 + + + 0 + 29,29 + 1 + m_refreshButton + 1 + + + protected + 1 + + Resizable + + 1 + + wxBU_AUTODRAW + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnRebuildRows + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_VERTICAL + ; forward_declare + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pin numbers: + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + + 0 + + + 0 + + 1 + m_summary + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_Buttons + protected + + + + + + + + + + diff --git a/eeschema/dialogs/dialog_lib_edit_pin_table_base.h b/eeschema/dialogs/dialog_lib_edit_pin_table_base.h index baa41736c0..d56cbe7d59 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin_table_base.h +++ b/eeschema/dialogs/dialog_lib_edit_pin_table_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Nov 22 2017) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // // PLEASE DO *NOT* EDIT THIS FILE! @@ -12,15 +12,21 @@ #include #include #include "dialog_shim.h" -#include -#include -#include #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include /////////////////////////////////////////////////////////////////////////// @@ -34,13 +40,26 @@ class DIALOG_LIB_EDIT_PIN_TABLE_BASE : public DIALOG_SHIM private: protected: - wxDataViewCtrl* m_Pins; - wxTextCtrl* m_Summary; + wxGrid* m_grid; + wxBitmapButton* m_addButton; + wxBitmapButton* m_deleteButton; + wxStaticLine* m_staticline1; + wxCheckBox* m_cbGroup; + wxBitmapButton* m_refreshButton; + wxStaticLine* m_staticline2; + wxStaticText* m_staticText1; + wxStaticText* m_summary; wxStdDialogButtonSizer* m_Buttons; wxButton* m_ButtonsOK; + wxButton* m_ButtonsCancel; // Virtual event handlers, overide them in your derived class - virtual void OnColumnHeaderRightClicked( wxDataViewEvent& event ) = 0; + virtual void OnUpdateUI( wxUpdateUIEvent& event ) = 0; + virtual void OnCellEdited( wxGridEvent& event ) = 0; + virtual void OnSize( wxSizeEvent& event ) = 0; + virtual void OnAddRow( wxCommandEvent& event ) = 0; + virtual void OnDeleteRow( wxCommandEvent& event ) = 0; + virtual void OnRebuildRows( wxCommandEvent& event ) = 0; public: diff --git a/eeschema/lib_edit_frame.cpp b/eeschema/lib_edit_frame.cpp index 4e80af7ea6..dee0134669 100644 --- a/eeschema/lib_edit_frame.cpp +++ b/eeschema/lib_edit_frame.cpp @@ -1519,12 +1519,15 @@ void LIB_EDIT_FRAME::OnSelectItem( wxCommandEvent& aEvent ) void LIB_EDIT_FRAME::OnOpenPinTable( wxCommandEvent& aEvent ) { LIB_PART* part = GetCurPart(); + SaveCopyInUndoList( part ); - DIALOG_LIB_EDIT_PIN_TABLE dlg( this, *part ); + DIALOG_LIB_EDIT_PIN_TABLE dlg( this, part ); if( dlg.ShowModal() == wxID_CANCEL ) return; + OnModify(); + m_canvas->Refresh(); return; } diff --git a/eeschema/lib_pin.cpp b/eeschema/lib_pin.cpp index 82ce46f460..c530c98174 100644 --- a/eeschema/lib_pin.cpp +++ b/eeschema/lib_pin.cpp @@ -1727,7 +1727,7 @@ void LIB_PIN::getMsgPanelInfoBase( MSG_PANEL_ITEMS& aList ) text = StringFromValue( g_UserUnit, m_length, true ); aList.push_back( MSG_PANEL_ITEM( _( "Length" ), text, MAGENTA ) ); - text = getPinOrientationName( (unsigned) GetOrientationCodeIndex( m_orientation ) ); + text = getPinOrientationName( (unsigned) GetOrientationIndex( m_orientation ) ); aList.push_back( MSG_PANEL_ITEM( _( "Orientation" ), text, DARKMAGENTA ) ); } @@ -1903,7 +1903,7 @@ int LIB_PIN::GetOrientationCode( int index ) } -int LIB_PIN::GetOrientationCodeIndex( int code ) +int LIB_PIN::GetOrientationIndex( int code ) { size_t i; diff --git a/eeschema/lib_pin.h b/eeschema/lib_pin.h index f94a10c405..870e2fa0f2 100644 --- a/eeschema/lib_pin.h +++ b/eeschema/lib_pin.h @@ -451,7 +451,7 @@ public: * @return The index of the orientation code if found. Otherwise, * return wxNOT_FOUND. */ - static int GetOrientationCodeIndex( int aCode ); + static int GetOrientationIndex( int aCode ); void SetOffset( const wxPoint& aOffset ) override; diff --git a/eeschema/pinedit.cpp b/eeschema/pinedit.cpp index 54c4a71a86..2be5c2bea1 100644 --- a/eeschema/pinedit.cpp +++ b/eeschema/pinedit.cpp @@ -105,7 +105,7 @@ void LIB_EDIT_FRAME::OnEditPin( wxCommandEvent& event ) dlg.SetDlgUnitsLabel( units ); dlg.SetOrientationList( LIB_PIN::GetOrientationNames(), LIB_PIN::GetOrientationSymbols() ); - dlg.SetOrientation( LIB_PIN::GetOrientationCodeIndex( pin->GetOrientation() ) ); + dlg.SetOrientation( LIB_PIN::GetOrientationIndex( pin->GetOrientation() ) ); dlg.SetStyle( pin->GetShape() ); dlg.SetElectricalType( pin->GetType() ); dlg.SetPinName( pin->GetName() ); diff --git a/include/widgets/grid_icon_text_helpers.h b/include/widgets/grid_icon_text_helpers.h new file mode 100644 index 0000000000..9e14829599 --- /dev/null +++ b/include/widgets/grid_icon_text_helpers.h @@ -0,0 +1,86 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef GRID_ICON_TEXT_HELPERS_H +#define GRID_ICON_TEXT_HELPERS_H + +#include +#include +#include +#include + +#include "bitmap_types.h" + +class wxGrid; + + +//---- Grid helpers: custom wxGridCellRenderer ------------------------------------------ + +class GRID_CELL_ICON_TEXT_RENDERER : public wxGridCellStringRenderer +{ +public: + GRID_CELL_ICON_TEXT_RENDERER( const std::vector& icons, const wxArrayString& names ); + + void Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC, + const wxRect& aRect, int aRow, int aCol, bool isSelected ) override; + +private: + const std::vector& m_icons; + const wxArrayString& m_names; +}; + + +//---- Grid helpers: custom wxGridCellEditor ------------------------------------------ +// +// Note: this implementation is an adaptation of wxGridCellChoiceEditor + +class GRID_CELL_ICON_TEXT_POPUP : public wxGridCellEditor +{ +public: + GRID_CELL_ICON_TEXT_POPUP( const std::vector& icons, const wxArrayString& names ); + + wxGridCellEditor* Clone() const override; + void Create( wxWindow* aParent, wxWindowID aId, wxEvtHandler* aEventHandler ) override; + + wxString GetValue() const override; + + void SetSize( const wxRect& aRect ) override; + + void BeginEdit( int aRow, int aCol, wxGrid* aGrid ) override; + bool EndEdit( int , int , const wxGrid* , const wxString& , wxString *aNewVal ) override; + void ApplyEdit( int aRow, int aCol, wxGrid* aGrid ) override; + void Reset() override; + +protected: + wxBitmapComboBox* Combo() const { return static_cast( m_control ); } + + const std::vector& m_icons; + const wxArrayString& m_names; + wxString m_value; + + wxDECLARE_NO_COPY_CLASS( GRID_CELL_ICON_TEXT_POPUP ); +}; + + + +#endif // GRID_ICON_TEXT_HELPERS_H