ADDED: schematic tables.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/6806
This commit is contained in:
Jeff Young 2023-11-25 12:38:24 +00:00
parent 4a9df1e18e
commit 91df43c97a
46 changed files with 7573 additions and 61 deletions

View File

@ -374,6 +374,8 @@ static struct EDA_ITEM_DESC
.Map( SCH_SHAPE_T, _HKI( "Graphic" ) ) .Map( SCH_SHAPE_T, _HKI( "Graphic" ) )
.Map( SCH_TEXT_T, _HKI( "Text" ) ) .Map( SCH_TEXT_T, _HKI( "Text" ) )
.Map( SCH_TEXTBOX_T, _HKI( "Text Box" ) ) .Map( SCH_TEXTBOX_T, _HKI( "Text Box" ) )
.Map( SCH_TABLE_T, _HKI( "Table" ) )
.Map( SCH_TABLECELL_T, _HKI( "Table Cell" ) )
.Map( SCH_LABEL_T, _HKI( "Net Label" ) ) .Map( SCH_LABEL_T, _HKI( "Net Label" ) )
.Map( SCH_DIRECTIVE_LABEL_T, _HKI( "Directive Label" ) ) .Map( SCH_DIRECTIVE_LABEL_T, _HKI( "Directive Label" ) )
.Map( SCH_GLOBAL_LABEL_T, _HKI( "Global Label" ) ) .Map( SCH_GLOBAL_LABEL_T, _HKI( "Global Label" ) )

View File

@ -205,18 +205,18 @@ void STROKE_PARAMS::GetMsgPanelInfo( UNITS_PROVIDER* aUnitsProvider,
{ {
if( aIncludeStyle ) if( aIncludeStyle )
{ {
wxString lineStyle = _( "Default" ); wxString msg = _( "Default" );
for( const std::pair<const LINE_STYLE, LINE_STYLE_DESC>& typeEntry : lineTypeNames ) for( const auto& [ lineStyle, lineStyleDesc ] : lineTypeNames )
{ {
if( typeEntry.first == GetLineStyle() ) if( lineStyle == GetLineStyle() )
{ {
lineStyle = typeEntry.second.name; msg = lineStyleDesc.name;
break; break;
} }
} }
aList.emplace_back( _( "Line Style" ), lineStyle ); aList.emplace_back( _( "Line Style" ), msg );
} }
if( aIncludeWidth ) if( aIncludeWidth )

View File

@ -159,6 +159,8 @@ set( EESCHEMA_DLGS
dialogs/dialog_symbol_properties_base.cpp dialogs/dialog_symbol_properties_base.cpp
dialogs/dialog_symbol_remap.cpp dialogs/dialog_symbol_remap.cpp
dialogs/dialog_symbol_remap_base.cpp dialogs/dialog_symbol_remap_base.cpp
dialogs/dialog_tablecell_properties.cpp
dialogs/dialog_tablecell_properties_base.cpp
dialogs/dialog_text_properties.cpp dialogs/dialog_text_properties.cpp
dialogs/dialog_text_properties_base.cpp dialogs/dialog_text_properties_base.cpp
dialogs/dialog_update_from_pcb.cpp dialogs/dialog_update_from_pcb.cpp
@ -380,6 +382,8 @@ set( EESCHEMA_SRCS
sch_sheet_path.cpp sch_sheet_path.cpp
sch_sheet_pin.cpp sch_sheet_pin.cpp
sch_symbol.cpp sch_symbol.cpp
sch_table.cpp
sch_tablecell.cpp
sch_text.cpp sch_text.cpp
sch_textbox.cpp sch_textbox.cpp
sch_validators.cpp sch_validators.cpp
@ -419,6 +423,7 @@ set( EESCHEMA_SRCS
tools/ee_selection.cpp tools/ee_selection.cpp
tools/ee_selection_tool.cpp tools/ee_selection_tool.cpp
tools/sch_drawing_tools.cpp tools/sch_drawing_tools.cpp
tools/sch_edit_table_tool.cpp
tools/sch_edit_tool.cpp tools/sch_edit_tool.cpp
tools/sch_editor_control.cpp tools/sch_editor_control.cpp
tools/sch_editor_conditions.cpp tools/sch_editor_conditions.cpp

View File

@ -326,10 +326,10 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
bButtonsSizer->Add( 0, 0, 9, wxEXPAND, 5 ); bButtonsSizer->Add( 0, 0, 9, wxEXPAND, 5 );
m_buttonExport = new wxButton( this, wxID_ANY, _("Export"), wxDefaultPosition, wxDefaultSize, 0 ); m_buttonExport = new wxButton( this, wxID_ANY, _("Export"), wxDefaultPosition, wxDefaultSize, 0 );
bButtonsSizer->Add( m_buttonExport, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); bButtonsSizer->Add( m_buttonExport, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 10 );
m_buttonApply = new wxButton( this, wxID_ANY, _("Apply, Save Schematic && Continue"), wxDefaultPosition, wxDefaultSize, 0 ); m_buttonApply = new wxButton( this, wxID_ANY, _("Apply, Save Schematic && Continue"), wxDefaultPosition, wxDefaultSize, 0 );
bButtonsSizer->Add( m_buttonApply, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); bButtonsSizer->Add( m_buttonApply, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 10 );
m_sdbSizer = new wxStdDialogButtonSizer(); m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK ); m_sdbSizerOK = new wxButton( this, wxID_OK );

View File

@ -3373,8 +3373,8 @@
</object> </object>
</object> </object>
<object class="sizeritem" expanded="0"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">10</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property> <property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxButton" expanded="0"> <object class="wxButton" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -3447,8 +3447,8 @@
</object> </object>
</object> </object>
<object class="sizeritem" expanded="0"> <object class="sizeritem" expanded="0">
<property name="border">5</property> <property name="border">10</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property> <property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxButton" expanded="0"> <object class="wxButton" expanded="0">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>

View File

@ -0,0 +1,453 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 <gr_text.h>
#include <ee_actions.h>
#include <sch_edit_frame.h>
#include <widgets/bitmap_button.h>
#include <widgets/color_swatch.h>
#include <widgets/font_choice.h>
#include <settings/color_settings.h>
#include <sch_table.h>
#include <sch_commit.h>
#include <tool/tool_manager.h>
#include <dialog_tablecell_properties.h>
class TABLECELL_SCINTILLA_TRICKS : public SCINTILLA_TRICKS
{
public:
TABLECELL_SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla,
std::function<void( wxKeyEvent& )> onAcceptHandler,
std::function<void()> onNextHandler ) :
SCINTILLA_TRICKS( aScintilla, wxT( "{}" ), false, std::move( onAcceptHandler ) ),
m_onNextHandler( std::move( onNextHandler ) )
{ }
protected:
void onCharHook( wxKeyEvent& aEvent ) override
{
if( aEvent.GetKeyCode() == WXK_TAB && aEvent.AltDown() && !aEvent.ControlDown() )
m_onNextHandler();
else
SCINTILLA_TRICKS::onCharHook( aEvent );
}
private:
std::function<void()> m_onNextHandler;
};
DIALOG_TABLECELL_PROPERTIES::DIALOG_TABLECELL_PROPERTIES( SCH_EDIT_FRAME* aFrame,
SCH_TABLECELL* aCell ) :
DIALOG_TABLECELL_PROPERTIES_BASE( aFrame ),
m_frame( aFrame ),
m_table( nullptr ),
m_cell( aCell ),
m_borderWidth( aFrame, m_borderWidthLabel, m_borderWidthCtrl, m_borderWidthUnits ),
m_separatorsWidth( aFrame, m_separatorsWidthLabel, m_separatorsWidthCtrl, m_separatorsWidthUnits ),
m_textSize( aFrame, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits ),
m_scintillaTricks( nullptr )
{
m_table = static_cast<SCH_TABLE*>( m_cell->GetParent() );
#ifdef _WIN32
// Without this setting, on Windows, some esoteric unicode chars create display issue
// in a wxStyledTextCtrl.
// for SetTechnology() info, see https://www.scintilla.org/ScintillaDoc.html#SCI_SETTECHNOLOGY
m_textCtrl->SetTechnology(wxSTC_TECHNOLOGY_DIRECTWRITE);
#endif
m_scintillaTricks = new TABLECELL_SCINTILLA_TRICKS( m_textCtrl,
// onAccept handler
[this]( wxKeyEvent& aEvent )
{
wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
},
// onNext handler
[this]()
{
wxCommandEvent dummy;
OnApply( dummy );
} );
// A hack which causes Scintilla to auto-size the text editor canvas
// See: https://github.com/jacobslusser/ScintillaNET/issues/216
m_textCtrl->SetScrollWidth( 1 );
m_textCtrl->SetScrollWidthTracking( true );
SetInitialFocus( m_textCtrl );
for( const auto& [lineStyle, lineStyleDesc] : lineTypeNames )
{
m_borderStyleCombo->Append( lineStyleDesc.name, KiBitmap( lineStyleDesc.bitmap ) );
m_separatorsStyleCombo->Append( lineStyleDesc.name, KiBitmap( lineStyleDesc.bitmap ) );
}
m_borderStyleCombo->Append( DEFAULT_STYLE );
m_separatorsStyleCombo->Append( DEFAULT_STYLE );
if( m_frame->GetColorSettings()->GetOverrideSchItemColors() )
m_infoBar->ShowMessage( _( "Note: individual item colors overridden in Preferences." ) );
m_separator1->SetIsSeparator();
m_bold->SetIsCheckButton();
m_bold->SetBitmap( KiBitmapBundle( BITMAPS::text_bold ) );
m_italic->SetIsCheckButton();
m_italic->SetBitmap( KiBitmapBundle( BITMAPS::text_italic ) );
m_separator2->SetIsSeparator();
m_hAlignLeft->SetIsRadioButton();
m_hAlignLeft->SetBitmap( KiBitmapBundle( BITMAPS::text_align_left ) );
m_hAlignCenter->SetIsRadioButton();
m_hAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_align_center ) );
m_hAlignRight->SetIsRadioButton();
m_hAlignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) );
m_separator3->SetIsSeparator();
m_vAlignTop->SetIsRadioButton();
m_vAlignTop->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_top ) );
m_vAlignCenter->SetIsRadioButton();
m_vAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_center ) );
m_vAlignBottom->SetIsRadioButton();
m_vAlignBottom->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_bottom ) );
m_separator4->SetIsSeparator();
m_hotkeyHint->SetFont( KIUI::GetInfoFont( this ) );
m_hotkeyHint->SetLabel( wxString::Format( wxT( "(%s+%s)" ),
KeyNameFromKeyCode( WXK_ALT ),
KeyNameFromKeyCode( WXK_TAB ) ) );
SetupStandardButtons();
Layout();
m_hAlignLeft->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onHAlignButton, this );
m_hAlignCenter->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onHAlignButton, this );
m_hAlignRight->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onHAlignButton, this );
m_vAlignTop->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onVAlignButton, this );
m_vAlignCenter->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onVAlignButton, this );
m_vAlignBottom->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onVAlignButton, this );
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
}
DIALOG_TABLECELL_PROPERTIES::~DIALOG_TABLECELL_PROPERTIES()
{
delete m_scintillaTricks;
}
bool DIALOG_TABLECELL_PROPERTIES::TransferDataToWindow()
{
if( !wxDialog::TransferDataToWindow() )
return false;
m_borderCheckbox->SetValue( m_table->StrokeExternal() );
m_headerBorder->SetValue( m_table->StrokeHeader() );
if( m_table->GetBorderStroke().GetWidth() >= 0 )
m_borderWidth.SetValue( m_table->GetBorderStroke().GetWidth() );
m_borderColorSwatch->SetSwatchColor( m_table->GetBorderStroke().GetColor(), false );
int style = static_cast<int>( m_table->GetBorderStroke().GetLineStyle() );
if( style == -1 )
m_borderStyleCombo->SetStringSelection( DEFAULT_STYLE );
else if( style < (int) lineTypeNames.size() )
m_borderStyleCombo->SetSelection( style );
else
wxFAIL_MSG( "Line type not found in the type lookup map" );
m_borderWidth.Enable( m_table->StrokeExternal() || m_table->StrokeHeader() );
m_borderColorLabel->Enable( m_table->StrokeExternal() || m_table->StrokeHeader() );
m_borderColorSwatch->Enable( m_table->StrokeExternal() || m_table->StrokeHeader() );
m_borderStyleLabel->Enable( m_table->StrokeExternal() || m_table->StrokeHeader() );
m_borderStyleCombo->Enable( m_table->StrokeExternal() || m_table->StrokeHeader() );
bool rows = m_table->StrokeRows() && m_table->GetSeparatorsStroke().GetWidth() >= 0;
bool cols = m_table->StrokeColumns() && m_table->GetSeparatorsStroke().GetWidth() >= 0;
m_rowSeparators->SetValue( rows );
m_colSeparators->SetValue( cols );
if( m_table->GetSeparatorsStroke().GetWidth() >= 0 )
m_separatorsWidth.SetValue( m_table->GetSeparatorsStroke().GetWidth() );
m_separatorsColorSwatch->SetSwatchColor( m_table->GetSeparatorsStroke().GetColor(), false );
style = static_cast<int>( m_table->GetSeparatorsStroke().GetLineStyle() );
if( style == -1 )
m_separatorsStyleCombo->SetStringSelection( DEFAULT_STYLE );
else if( style < (int) lineTypeNames.size() )
m_separatorsStyleCombo->SetSelection( style );
else
wxFAIL_MSG( "Line type not found in the type lookup map" );
m_separatorsWidth.Enable( rows || cols );
m_separatorsColorLabel->Enable( rows || cols );
m_separatorsColorSwatch->Enable( rows || cols );
m_separatorsStyleLabel->Enable( rows || cols );
m_separatorsStyleCombo->Enable( rows || cols );
m_textCtrl->SetValue( m_cell->GetText() );
m_fontCtrl->SetFontSelection( m_cell->GetFont() );
m_textSize.SetValue( m_cell->GetTextWidth() );
m_bold->Check( m_cell->IsBold() );
m_italic->Check( m_cell->IsItalic() );
switch( m_cell->GetHorizJustify() )
{
case GR_TEXT_H_ALIGN_LEFT: m_hAlignLeft->Check(); break;
case GR_TEXT_H_ALIGN_CENTER: m_hAlignCenter->Check(); break;
case GR_TEXT_H_ALIGN_RIGHT: m_hAlignRight->Check(); break;
}
switch( m_cell->GetVertJustify() )
{
case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check(); break;
case GR_TEXT_V_ALIGN_CENTER: m_vAlignCenter->Check(); break;
case GR_TEXT_V_ALIGN_BOTTOM: m_vAlignBottom->Check(); break;
}
m_textColorSwatch->SetSwatchColor( m_cell->GetTextColor(), false );
if( m_cell->IsFilled() )
m_fillColorSwatch->SetSwatchColor( m_cell->GetFillColor(), false );
else
m_fillColorSwatch->SetSwatchColor( COLOR4D::UNSPECIFIED, false );
return true;
}
void DIALOG_TABLECELL_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
{
for( BITMAP_BUTTON* btn : { m_hAlignLeft, m_hAlignCenter, m_hAlignRight } )
{
if( btn->IsChecked() && btn != aEvent.GetEventObject() )
btn->Check( false );
}
}
void DIALOG_TABLECELL_PROPERTIES::onVAlignButton( wxCommandEvent& aEvent )
{
for( BITMAP_BUTTON* btn : { m_vAlignTop, m_vAlignCenter, m_vAlignBottom } )
{
if( btn->IsChecked() && btn != aEvent.GetEventObject() )
btn->Check( false );
}
}
void DIALOG_TABLECELL_PROPERTIES::onBorderChecked( wxCommandEvent& aEvent )
{
bool border = m_borderCheckbox->GetValue();
if( border && m_borderWidth.GetValue() < 0 )
m_borderWidth.SetValue( m_frame->eeconfig()->m_Drawing.default_line_thickness );
m_borderWidth.Enable( border );
m_borderColorLabel->Enable( border );
m_borderColorSwatch->Enable( border );
m_borderStyleLabel->Enable( border );
m_borderStyleCombo->Enable( border );
bool row = m_rowSeparators->GetValue();
bool col = m_colSeparators->GetValue();
if( ( row || col ) && m_separatorsWidth.GetValue() < 0 )
m_separatorsWidth.SetValue( m_frame->eeconfig()->m_Drawing.default_line_thickness );
m_separatorsWidth.Enable( row || col );
m_separatorsColorLabel->Enable( row || col );
m_separatorsColorSwatch->Enable( row || col );
m_separatorsStyleLabel->Enable( row || col );
m_separatorsStyleCombo->Enable( row || col );
}
void DIALOG_TABLECELL_PROPERTIES::OnCharHook( wxKeyEvent& aEvt )
{
if( aEvt.GetKeyCode() == WXK_TAB && aEvt.AltDown() && !aEvt.ControlDown() )
{
wxCommandEvent dummy;
OnApply( dummy );
}
else
{
DIALOG_SHIM::OnCharHook( aEvt );
}
}
void DIALOG_TABLECELL_PROPERTIES::OnApply( wxCommandEvent& aEvent )
{
TransferDataFromWindow();
for( size_t ii = 0; ii < m_table->GetCells().size(); ++ii )
{
if( m_table->GetCells()[ii] == m_cell )
{
ii++;
if( ii >= m_table->GetCells().size() )
ii = 0;
m_cell = m_table->GetCells()[ii];
m_frame->GetToolManager()->RunAction( EE_ACTIONS::clearSelection );
m_frame->GetToolManager()->RunAction<EDA_ITEM*>( EE_ACTIONS::addItemToSel, m_cell );
break;
}
}
TransferDataToWindow();
m_textCtrl->SelectAll();
}
bool DIALOG_TABLECELL_PROPERTIES::TransferDataFromWindow()
{
if( !wxDialog::TransferDataFromWindow() )
return false;
SCH_COMMIT commit( m_frame );
/* save table in undo list if not already in edit */
if( m_table->GetEditFlags() == 0 )
commit.Modify( m_table, m_frame->GetScreen() );
m_table->SetStrokeExternal( m_borderCheckbox->GetValue() );
m_table->SetStrokeHeader( m_headerBorder->GetValue() );
{
STROKE_PARAMS stroke = m_table->GetBorderStroke();
if( m_borderCheckbox->GetValue() )
stroke.SetWidth( std::max( 0, m_borderWidth.GetIntValue() ) );
else
stroke.SetWidth( -1 );
auto it = lineTypeNames.begin();
std::advance( it, m_borderStyleCombo->GetSelection() );
if( it == lineTypeNames.end() )
stroke.SetLineStyle( LINE_STYLE::DEFAULT );
else
stroke.SetLineStyle( it->first );
stroke.SetColor( m_borderColorSwatch->GetSwatchColor() );
m_table->SetBorderStroke( stroke );
}
m_table->SetStrokeRows( m_rowSeparators->GetValue() );
m_table->SetStrokeColumns( m_colSeparators->GetValue() );
{
STROKE_PARAMS stroke = m_table->GetSeparatorsStroke();
if( m_rowSeparators->GetValue() || m_colSeparators->GetValue() )
stroke.SetWidth( std::max( 0, m_separatorsWidth.GetIntValue() ) );
else
stroke.SetWidth( -1 );
auto it = lineTypeNames.begin();
std::advance( it, m_separatorsStyleCombo->GetSelection() );
if( it == lineTypeNames.end() )
stroke.SetLineStyle( LINE_STYLE::DEFAULT );
else
stroke.SetLineStyle( it->first );
stroke.SetColor( m_separatorsColorSwatch->GetSwatchColor() );
m_table->SetSeparatorsStroke( stroke );
}
m_cell->SetText( m_textCtrl->GetValue() );
if( m_fontCtrl->HaveFontSelection() )
{
m_cell->SetFont( m_fontCtrl->GetFontSelection( m_bold->IsChecked(),
m_italic->IsChecked() ) );
}
if( m_cell->GetTextWidth() != m_textSize.GetValue() )
m_cell->SetTextSize( VECTOR2I( m_textSize.GetValue(), m_textSize.GetValue() ) );
m_cell->SetTextColor( m_textColorSwatch->GetSwatchColor() );
if( m_bold->IsChecked() != m_cell->IsBold() )
{
if( m_bold->IsChecked() )
{
m_cell->SetBold( true );
m_cell->SetTextThickness( GetPenSizeForBold( m_cell->GetTextWidth() ) );
}
else
{
m_cell->SetBold( false );
m_cell->SetTextThickness( 0 ); // Use default pen width
}
}
if( m_hAlignRight->IsChecked() )
m_cell->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
else if( m_hAlignCenter->IsChecked() )
m_cell->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
else
m_cell->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
if( m_vAlignBottom->IsChecked() )
m_cell->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
else if( m_vAlignCenter->IsChecked() )
m_cell->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
else
m_cell->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
COLOR4D fillColor = m_fillColorSwatch->GetSwatchColor();
if( fillColor == COLOR4D::UNSPECIFIED )
{
m_cell->SetFillMode( FILL_T::NO_FILL );
}
else
{
m_cell->SetFillMode( FILL_T::FILLED_WITH_COLOR );
m_cell->SetFillColor( fillColor );
}
if( !commit.Empty() )
commit.Push( _( "Edit Table Cell" ), SKIP_CONNECTIVITY );
return true;
}

View File

@ -0,0 +1,67 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 DIALOG_TABLECELL_PROPERTIES_H
#define DIALOG_TABLECELL_PROPERTIES_H
#include <widgets/unit_binder.h>
#include <dialog_tablecell_properties_base.h>
class SCH_EDIT_FRAME;
class SCH_TABLE;
class DIALOG_TABLECELL_PROPERTIES : public DIALOG_TABLECELL_PROPERTIES_BASE
{
public:
DIALOG_TABLECELL_PROPERTIES( SCH_EDIT_FRAME* aParentFrame, SCH_TABLECELL* aCell );
~DIALOG_TABLECELL_PROPERTIES();
protected:
void OnCharHook( wxKeyEvent& aEvt ) override;
private:
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
void onHAlignButton( wxCommandEvent &aEvent );
void onVAlignButton( wxCommandEvent &aEvent );
void onBorderChecked( wxCommandEvent& aEvent ) override;
void OnApply( wxCommandEvent& aEvent ) override;
private:
SCH_EDIT_FRAME* m_frame;
SCH_TABLE* m_table;
SCH_TABLECELL* m_cell;
UNIT_BINDER m_borderWidth;
UNIT_BINDER m_separatorsWidth;
UNIT_BINDER m_textSize;
SCINTILLA_TRICKS* m_scintillaTricks;
};
#endif // DIALOG_TABLECELL_PROPERTIES_H

View File

@ -0,0 +1,415 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "widgets/bitmap_button.h"
#include "widgets/color_swatch.h"
#include "widgets/font_choice.h"
#include "widgets/wx_infobar.h"
#include "dialog_tablecell_properties_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_TABLECELL_PROPERTIES_BASE::DIALOG_TABLECELL_PROPERTIES_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL );
m_infoBar = new WX_INFOBAR( this );
m_infoBar->SetShowHideEffects( wxSHOW_EFFECT_NONE, wxSHOW_EFFECT_NONE );
m_infoBar->SetEffectDuration( 500 );
m_infoBar->Hide();
bMainSizer->Add( m_infoBar, 0, wxEXPAND|wxBOTTOM, 5 );
wxBoxSizer* bColumns;
bColumns = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bCellContentMargins;
bCellContentMargins = new wxBoxSizer( wxVERTICAL );
m_textCtrl = new wxStyledTextCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN, wxEmptyString );
m_textCtrl->SetUseTabs( true );
m_textCtrl->SetTabWidth( 4 );
m_textCtrl->SetIndent( 4 );
m_textCtrl->SetTabIndents( false );
m_textCtrl->SetBackSpaceUnIndents( false );
m_textCtrl->SetViewEOL( false );
m_textCtrl->SetViewWhiteSpace( false );
m_textCtrl->SetMarginWidth( 2, 0 );
m_textCtrl->SetIndentationGuides( false );
m_textCtrl->SetReadOnly( false );
m_textCtrl->SetMarginWidth( 1, 0 );
m_textCtrl->SetMarginWidth( 0, 0 );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS );
m_textCtrl->MarkerSetBackground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("BLACK") ) );
m_textCtrl->MarkerSetForeground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("WHITE") ) );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS );
m_textCtrl->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("BLACK") ) );
m_textCtrl->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("WHITE") ) );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUS );
m_textCtrl->MarkerSetBackground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("BLACK") ) );
m_textCtrl->MarkerSetForeground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("WHITE") ) );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUS );
m_textCtrl->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("BLACK") ) );
m_textCtrl->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("WHITE") ) );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY );
m_textCtrl->MarkerDefine( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY );
m_textCtrl->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
m_textCtrl->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
m_textCtrl->SetMinSize( wxSize( 500,-1 ) );
bCellContentMargins->Add( m_textCtrl, 1, wxEXPAND|wxTOP|wxBOTTOM, 1 );
bColumns->Add( bCellContentMargins, 1, wxEXPAND|wxTOP, 6 );
m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_tablePage = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer16;
bSizer16 = new wxBoxSizer( wxVERTICAL );
m_textEntrySizer = new wxGridBagSizer( 4, 3 );
m_textEntrySizer->SetFlexibleDirection( wxBOTH );
m_textEntrySizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_textEntrySizer->SetEmptyCellSize( wxSize( 0,2 ) );
m_borderCheckbox = new wxCheckBox( m_tablePage, wxID_ANY, _("External border"), wxDefaultPosition, wxDefaultSize, 0 );
m_textEntrySizer->Add( m_borderCheckbox, wxGBPosition( 0, 0 ), wxGBSpan( 1, 2 ), wxBOTTOM, 2 );
m_headerBorder = new wxCheckBox( m_tablePage, wxID_ANY, _("Header border"), wxDefaultPosition, wxDefaultSize, 0 );
m_textEntrySizer->Add( m_headerBorder, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxLEFT, 20 );
m_borderWidthLabel = new wxStaticText( m_tablePage, wxID_ANY, _("Width:"), wxDefaultPosition, wxDefaultSize, 0 );
m_borderWidthLabel->Wrap( -1 );
m_textEntrySizer->Add( m_borderWidthLabel, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxHORIZONTAL );
m_borderWidthCtrl = new wxTextCtrl( m_tablePage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer7->Add( m_borderWidthCtrl, 0, wxEXPAND, 5 );
m_borderWidthUnits = new wxStaticText( m_tablePage, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_borderWidthUnits->Wrap( -1 );
bSizer7->Add( m_borderWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 3 );
m_borderColorLabel = new wxStaticText( m_tablePage, wxID_ANY, _("Color:"), wxDefaultPosition, wxDefaultSize, 0 );
m_borderColorLabel->Wrap( -1 );
bSizer7->Add( m_borderColorLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 15 );
bSizer7->Add( 5, 0, 0, 0, 5 );
m_panelBorderColor = new wxPanel( m_tablePage, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE|wxTAB_TRAVERSAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
m_borderColorSwatch = new COLOR_SWATCH( m_panelBorderColor, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
bSizer2->Add( m_borderColorSwatch, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
m_panelBorderColor->SetSizer( bSizer2 );
m_panelBorderColor->Layout();
bSizer2->Fit( m_panelBorderColor );
bSizer7->Add( m_panelBorderColor, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_textEntrySizer->Add( bSizer7, wxGBPosition( 2, 1 ), wxGBSpan( 1, 2 ), wxEXPAND, 5 );
m_borderStyleLabel = new wxStaticText( m_tablePage, wxID_ANY, _("Style:"), wxDefaultPosition, wxDefaultSize, 0 );
m_borderStyleLabel->Wrap( -1 );
m_textEntrySizer->Add( m_borderStyleLabel, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
m_borderStyleCombo = new wxBitmapComboBox( m_tablePage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY );
m_borderStyleCombo->SetMinSize( wxSize( 200,-1 ) );
m_textEntrySizer->Add( m_borderStyleCombo, wxGBPosition( 3, 1 ), wxGBSpan( 1, 2 ), wxEXPAND, 5 );
m_textEntrySizer->Add( 0, 20, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
m_rowSeparators = new wxCheckBox( m_tablePage, wxID_ANY, _("Row lines"), wxDefaultPosition, wxDefaultSize, 0 );
m_textEntrySizer->Add( m_rowSeparators, wxGBPosition( 5, 0 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxRIGHT, 15 );
m_colSeparators = new wxCheckBox( m_tablePage, wxID_ANY, _("Column lines"), wxDefaultPosition, wxDefaultSize, 0 );
m_textEntrySizer->Add( m_colSeparators, wxGBPosition( 5, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 20 );
m_separatorsWidthLabel = new wxStaticText( m_tablePage, wxID_ANY, _("Width:"), wxDefaultPosition, wxDefaultSize, 0 );
m_separatorsWidthLabel->Wrap( -1 );
m_textEntrySizer->Add( m_separatorsWidthLabel, wxGBPosition( 7, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer71;
bSizer71 = new wxBoxSizer( wxHORIZONTAL );
m_separatorsWidthCtrl = new wxTextCtrl( m_tablePage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer71->Add( m_separatorsWidthCtrl, 0, wxEXPAND, 5 );
m_separatorsWidthUnits = new wxStaticText( m_tablePage, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_separatorsWidthUnits->Wrap( -1 );
bSizer71->Add( m_separatorsWidthUnits, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 3 );
m_separatorsColorLabel = new wxStaticText( m_tablePage, wxID_ANY, _("Color:"), wxDefaultPosition, wxDefaultSize, 0 );
m_separatorsColorLabel->Wrap( -1 );
bSizer71->Add( m_separatorsColorLabel, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 15 );
bSizer71->Add( 5, 0, 0, 0, 5 );
m_panelSeparatorsColor = new wxPanel( m_tablePage, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE|wxTAB_TRAVERSAL );
wxBoxSizer* bSizer21;
bSizer21 = new wxBoxSizer( wxVERTICAL );
m_separatorsColorSwatch = new COLOR_SWATCH( m_panelSeparatorsColor, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
bSizer21->Add( m_separatorsColorSwatch, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
m_panelSeparatorsColor->SetSizer( bSizer21 );
m_panelSeparatorsColor->Layout();
bSizer21->Fit( m_panelSeparatorsColor );
bSizer71->Add( m_panelSeparatorsColor, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_textEntrySizer->Add( bSizer71, wxGBPosition( 7, 1 ), wxGBSpan( 1, 2 ), wxEXPAND, 5 );
m_separatorsStyleLabel = new wxStaticText( m_tablePage, wxID_ANY, _("Style:"), wxDefaultPosition, wxDefaultSize, 0 );
m_separatorsStyleLabel->Wrap( -1 );
m_textEntrySizer->Add( m_separatorsStyleLabel, wxGBPosition( 8, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
m_separatorsStyleCombo = new wxBitmapComboBox( m_tablePage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY );
m_separatorsStyleCombo->SetMinSize( wxSize( 200,-1 ) );
m_textEntrySizer->Add( m_separatorsStyleCombo, wxGBPosition( 8, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_textEntrySizer->AddGrowableCol( 1 );
bSizer16->Add( m_textEntrySizer, 1, wxEXPAND|wxALL, 5 );
m_tablePage->SetSizer( bSizer16 );
m_tablePage->Layout();
bSizer16->Fit( m_tablePage );
m_notebook->AddPage( m_tablePage, _("Table"), false );
m_cellPage = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer13;
bSizer13 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bMargins;
bMargins = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizeCtrlSizer;
bSizeCtrlSizer = new wxBoxSizer( wxHORIZONTAL );
m_separator1 = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_separator1->Enable( false );
bSizeCtrlSizer->Add( m_separator1, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_bold = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_bold->SetToolTip( _("Bold") );
bSizeCtrlSizer->Add( m_bold, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_italic = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_italic->SetToolTip( _("Italic") );
bSizeCtrlSizer->Add( m_italic, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_separator2 = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_separator2->Enable( false );
bSizeCtrlSizer->Add( m_separator2, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_hAlignLeft = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_hAlignLeft->SetToolTip( _("Align left") );
bSizeCtrlSizer->Add( m_hAlignLeft, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_hAlignCenter = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_hAlignCenter->SetToolTip( _("Align horizontal center") );
bSizeCtrlSizer->Add( m_hAlignCenter, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_hAlignRight = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_hAlignRight->SetToolTip( _("Align right") );
bSizeCtrlSizer->Add( m_hAlignRight, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_separator3 = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_separator3->Enable( false );
bSizeCtrlSizer->Add( m_separator3, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_vAlignTop = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_vAlignTop->SetToolTip( _("Align top") );
bSizeCtrlSizer->Add( m_vAlignTop, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_vAlignCenter = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_vAlignCenter->SetToolTip( _("Align vertical center") );
bSizeCtrlSizer->Add( m_vAlignCenter, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_vAlignBottom = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_vAlignBottom->SetToolTip( _("Align bottom") );
bSizeCtrlSizer->Add( m_vAlignBottom, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_separator4 = new BITMAP_BUTTON( m_cellPage, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE );
m_separator4->Enable( false );
bSizeCtrlSizer->Add( m_separator4, 0, wxALIGN_CENTER_VERTICAL, 5 );
bMargins->Add( bSizeCtrlSizer, 0, wxBOTTOM, 10 );
wxGridBagSizer* gbSizer2;
gbSizer2 = new wxGridBagSizer( 4, 5 );
gbSizer2->SetFlexibleDirection( wxBOTH );
gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
gbSizer2->SetEmptyCellSize( wxSize( -1,5 ) );
m_fontLabel = new wxStaticText( m_cellPage, wxID_ANY, _("Font:"), wxDefaultPosition, wxDefaultSize, 0 );
m_fontLabel->Wrap( -1 );
gbSizer2->Add( m_fontLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 1 );
wxString m_fontCtrlChoices[] = { _("Default Font"), _("KiCad Font") };
int m_fontCtrlNChoices = sizeof( m_fontCtrlChoices ) / sizeof( wxString );
m_fontCtrl = new FONT_CHOICE( m_cellPage, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_fontCtrlNChoices, m_fontCtrlChoices, 0 );
m_fontCtrl->SetSelection( 0 );
gbSizer2->Add( m_fontCtrl, wxGBPosition( 0, 1 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_textSizeLabel = new wxStaticText( m_cellPage, wxID_ANY, _("Size:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textSizeLabel->Wrap( -1 );
gbSizer2->Add( m_textSizeLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer15;
bSizer15 = new wxBoxSizer( wxHORIZONTAL );
m_textSizeCtrl = new wxTextCtrl( m_cellPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer15->Add( m_textSizeCtrl, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_textSizeUnits = new wxStaticText( m_cellPage, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
m_textSizeUnits->Wrap( -1 );
bSizer15->Add( m_textSizeUnits, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 3 );
gbSizer2->Add( bSizer15, wxGBPosition( 1, 1 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL, 5 );
gbSizer2->AddGrowableCol( 1 );
bMargins->Add( gbSizer2, 0, wxEXPAND|wxBOTTOM, 5 );
wxFlexGridSizer* fgSizer1;
fgSizer1 = new wxFlexGridSizer( 0, 2, 6, 5 );
fgSizer1->SetFlexibleDirection( wxBOTH );
fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_textColorLabel = new wxStaticText( m_cellPage, wxID_ANY, _("Text color:"), wxDefaultPosition, wxDefaultSize, 0 );
m_textColorLabel->Wrap( -1 );
fgSizer1->Add( m_textColorLabel, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_panelTextColor = new wxPanel( m_cellPage, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE|wxTAB_TRAVERSAL );
wxBoxSizer* bSizer221;
bSizer221 = new wxBoxSizer( wxVERTICAL );
m_textColorSwatch = new COLOR_SWATCH( m_panelTextColor, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
bSizer221->Add( m_textColorSwatch, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
m_panelTextColor->SetSizer( bSizer221 );
m_panelTextColor->Layout();
bSizer221->Fit( m_panelTextColor );
fgSizer1->Add( m_panelTextColor, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_fillColorLabel = new wxStaticText( m_cellPage, wxID_ANY, _("Background fill:"), wxDefaultPosition, wxDefaultSize, 0 );
m_fillColorLabel->Wrap( -1 );
fgSizer1->Add( m_fillColorLabel, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_panelFillColor = new wxPanel( m_cellPage, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE|wxTAB_TRAVERSAL );
wxBoxSizer* bSizer22;
bSizer22 = new wxBoxSizer( wxVERTICAL );
m_fillColorSwatch = new COLOR_SWATCH( m_panelFillColor, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
bSizer22->Add( m_fillColorSwatch, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
m_panelFillColor->SetSizer( bSizer22 );
m_panelFillColor->Layout();
bSizer22->Fit( m_panelFillColor );
fgSizer1->Add( m_panelFillColor, 0, wxALIGN_CENTER_VERTICAL, 5 );
bMargins->Add( fgSizer1, 1, wxEXPAND|wxTOP, 5 );
bSizer13->Add( bMargins, 1, wxEXPAND|wxALL, 5 );
m_cellPage->SetSizer( bSizer13 );
m_cellPage->Layout();
bSizer13->Fit( m_cellPage );
m_notebook->AddPage( m_cellPage, _("Cell"), true );
bColumns->Add( m_notebook, 0, wxEXPAND|wxBOTTOM|wxLEFT, 10 );
bMainSizer->Add( bColumns, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );
wxBoxSizer* bButtons;
bButtons = new wxBoxSizer( wxHORIZONTAL );
bButtons->Add( 0, 0, 1, wxEXPAND, 5 );
m_applyButton = new wxButton( this, wxID_ANY, _("Apply && Go to Next Cell"), wxDefaultPosition, wxDefaultSize, 0 );
bButtons->Add( m_applyButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
m_hotkeyHint = new wxStaticText( this, wxID_ANY, _("(Option+Tab)"), wxDefaultPosition, wxDefaultSize, 0 );
m_hotkeyHint->Wrap( -1 );
bButtons->Add( m_hotkeyHint, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 10 );
m_sdbSizer1 = new wxStdDialogButtonSizer();
m_sdbSizer1OK = new wxButton( this, wxID_OK );
m_sdbSizer1->AddButton( m_sdbSizer1OK );
m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL );
m_sdbSizer1->AddButton( m_sdbSizer1Cancel );
m_sdbSizer1->Realize();
bButtons->Add( m_sdbSizer1, 0, wxEXPAND|wxALL, 5 );
bMainSizer->Add( bButtons, 0, wxEXPAND, 5 );
this->SetSizer( bMainSizer );
this->Layout();
bMainSizer->Fit( this );
// Connect Events
m_textCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onMultiLineTCLostFocus ), NULL, this );
m_borderCheckbox->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onBorderChecked ), NULL, this );
m_rowSeparators->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onBorderChecked ), NULL, this );
m_colSeparators->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onBorderChecked ), NULL, this );
m_applyButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::OnApply ), NULL, this );
}
DIALOG_TABLECELL_PROPERTIES_BASE::~DIALOG_TABLECELL_PROPERTIES_BASE()
{
// Disconnect Events
m_textCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onMultiLineTCLostFocus ), NULL, this );
m_borderCheckbox->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onBorderChecked ), NULL, this );
m_rowSeparators->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onBorderChecked ), NULL, this );
m_colSeparators->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::onBorderChecked ), NULL, this );
m_applyButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TABLECELL_PROPERTIES_BASE::OnApply ), NULL, this );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,120 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class BITMAP_BUTTON;
class COLOR_SWATCH;
class FONT_CHOICE;
class WX_INFOBAR;
#include "dialog_shim.h"
#include <wx/infobar.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/stc/stc.h>
#include <wx/sizer.h>
#include <wx/checkbox.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/panel.h>
#include <wx/bmpcbox.h>
#include <wx/gbsizer.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_TABLECELL_PROPERTIES_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_TABLECELL_PROPERTIES_BASE : public DIALOG_SHIM
{
private:
protected:
WX_INFOBAR* m_infoBar;
wxStyledTextCtrl* m_textCtrl;
wxNotebook* m_notebook;
wxPanel* m_tablePage;
wxGridBagSizer* m_textEntrySizer;
wxCheckBox* m_borderCheckbox;
wxCheckBox* m_headerBorder;
wxStaticText* m_borderWidthLabel;
wxTextCtrl* m_borderWidthCtrl;
wxStaticText* m_borderWidthUnits;
wxStaticText* m_borderColorLabel;
wxPanel* m_panelBorderColor;
COLOR_SWATCH* m_borderColorSwatch;
wxStaticText* m_borderStyleLabel;
wxBitmapComboBox* m_borderStyleCombo;
wxCheckBox* m_rowSeparators;
wxCheckBox* m_colSeparators;
wxStaticText* m_separatorsWidthLabel;
wxTextCtrl* m_separatorsWidthCtrl;
wxStaticText* m_separatorsWidthUnits;
wxStaticText* m_separatorsColorLabel;
wxPanel* m_panelSeparatorsColor;
COLOR_SWATCH* m_separatorsColorSwatch;
wxStaticText* m_separatorsStyleLabel;
wxBitmapComboBox* m_separatorsStyleCombo;
wxPanel* m_cellPage;
BITMAP_BUTTON* m_separator1;
BITMAP_BUTTON* m_bold;
BITMAP_BUTTON* m_italic;
BITMAP_BUTTON* m_separator2;
BITMAP_BUTTON* m_hAlignLeft;
BITMAP_BUTTON* m_hAlignCenter;
BITMAP_BUTTON* m_hAlignRight;
BITMAP_BUTTON* m_separator3;
BITMAP_BUTTON* m_vAlignTop;
BITMAP_BUTTON* m_vAlignCenter;
BITMAP_BUTTON* m_vAlignBottom;
BITMAP_BUTTON* m_separator4;
wxStaticText* m_fontLabel;
FONT_CHOICE* m_fontCtrl;
wxStaticText* m_textSizeLabel;
wxTextCtrl* m_textSizeCtrl;
wxStaticText* m_textSizeUnits;
wxStaticText* m_textColorLabel;
wxPanel* m_panelTextColor;
COLOR_SWATCH* m_textColorSwatch;
wxStaticText* m_fillColorLabel;
wxPanel* m_panelFillColor;
COLOR_SWATCH* m_fillColorSwatch;
wxButton* m_applyButton;
wxStaticText* m_hotkeyHint;
wxStdDialogButtonSizer* m_sdbSizer1;
wxButton* m_sdbSizer1OK;
wxButton* m_sdbSizer1Cancel;
// Virtual event handlers, override them in your derived class
virtual void onMultiLineTCLostFocus( wxFocusEvent& event ) { event.Skip(); }
virtual void onBorderChecked( wxCommandEvent& event ) { event.Skip(); }
virtual void OnApply( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_TABLECELL_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Table Cell Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_TABLECELL_PROPERTIES_BASE();
};

View File

@ -132,6 +132,7 @@ DIALOG_TEXT_PROPERTIES::DIALOG_TEXT_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH_ITE
m_hAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_align_center ) ); m_hAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_align_center ) );
m_hAlignRight->SetIsRadioButton(); m_hAlignRight->SetIsRadioButton();
m_hAlignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) ); m_hAlignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) );
m_separator3->SetIsSeparator(); m_separator3->SetIsSeparator();
m_vAlignTop->SetIsRadioButton(); m_vAlignTop->SetIsRadioButton();

View File

@ -40,6 +40,7 @@ const std::vector<KICAD_T> EE_COLLECTOR::EditableItems = {
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLECELL_T,
SCH_LABEL_T, SCH_LABEL_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_HIER_LABEL_T,
@ -67,6 +68,8 @@ const std::vector<KICAD_T> EE_COLLECTOR::MovableItems =
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLE_T,
SCH_TABLECELL_T, // will be promoted to parent table(s)
SCH_LABEL_T, SCH_LABEL_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_HIER_LABEL_T,

View File

@ -259,6 +259,7 @@ void SCH_EDIT_FRAME::doReCreateMenuBar()
placeMenu->AppendSeparator(); placeMenu->AppendSeparator();
placeMenu->Add( EE_ACTIONS::placeSchematicText ); placeMenu->Add( EE_ACTIONS::placeSchematicText );
placeMenu->Add( EE_ACTIONS::drawTextBox ); placeMenu->Add( EE_ACTIONS::drawTextBox );
placeMenu->Add( EE_ACTIONS::drawTable );
placeMenu->Add( EE_ACTIONS::drawRectangle ); placeMenu->Add( EE_ACTIONS::drawRectangle );
placeMenu->Add( EE_ACTIONS::drawCircle ); placeMenu->Add( EE_ACTIONS::drawCircle );
placeMenu->Add( EE_ACTIONS::drawArc ); placeMenu->Add( EE_ACTIONS::drawArc );

View File

@ -380,7 +380,7 @@ void SCH_BASE_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpda
GetCanvas()->GetView()->Update( aItem ); GetCanvas()->GetView()->Update( aItem );
// Some children are drawn from their parents. Mark them for re-paint. // Some children are drawn from their parents. Mark them for re-paint.
if( parent && parent->IsType( { SCH_SYMBOL_T, SCH_SHEET_T, SCH_LABEL_LOCATE_ANY_T } ) ) if( parent && parent->IsType( { SCH_SYMBOL_T, SCH_SHEET_T, SCH_LABEL_LOCATE_ANY_T, SCH_TABLE_T } ) )
GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT ); GetCanvas()->GetView()->Update( parent, KIGFX::REPAINT );
} }
@ -446,6 +446,7 @@ void SCH_BASE_FRAME::AddToScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen )
if( aScreen == nullptr ) if( aScreen == nullptr )
screen = GetScreen(); screen = GetScreen();
if( aItem->Type() != SCH_TABLECELL_T )
screen->Append( (SCH_ITEM*) aItem ); screen->Append( (SCH_ITEM*) aItem );
if( screen == GetScreen() ) if( screen == GetScreen() )
@ -466,6 +467,7 @@ void SCH_BASE_FRAME::RemoveFromScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen )
if( screen == GetScreen() ) if( screen == GetScreen() )
GetCanvas()->GetView()->Remove( aItem ); GetCanvas()->GetView()->Remove( aItem );
if( aItem->Type() != SCH_TABLECELL_T )
screen->Remove( (SCH_ITEM*) aItem ); screen->Remove( (SCH_ITEM*) aItem );
if( screen == GetScreen() ) if( screen == GetScreen() )

View File

@ -76,6 +76,7 @@
#include <tools/ee_selection_tool.h> #include <tools/ee_selection_tool.h>
#include <tools/sch_drawing_tools.h> #include <tools/sch_drawing_tools.h>
#include <tools/sch_edit_tool.h> #include <tools/sch_edit_tool.h>
#include <tools/sch_edit_table_tool.h>
#include <tools/sch_editor_conditions.h> #include <tools/sch_editor_conditions.h>
#include <tools/sch_editor_control.h> #include <tools/sch_editor_control.h>
#include <tools/sch_line_wire_bus_tool.h> #include <tools/sch_line_wire_bus_tool.h>
@ -477,6 +478,7 @@ void SCH_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new SCH_LINE_WIRE_BUS_TOOL ); m_toolManager->RegisterTool( new SCH_LINE_WIRE_BUS_TOOL );
m_toolManager->RegisterTool( new SCH_MOVE_TOOL ); m_toolManager->RegisterTool( new SCH_MOVE_TOOL );
m_toolManager->RegisterTool( new SCH_EDIT_TOOL ); m_toolManager->RegisterTool( new SCH_EDIT_TOOL );
m_toolManager->RegisterTool( new SCH_EDIT_TABLE_TOOL );
m_toolManager->RegisterTool( new EE_INSPECTION_TOOL ); m_toolManager->RegisterTool( new EE_INSPECTION_TOOL );
m_toolManager->RegisterTool( new SCH_EDITOR_CONTROL ); m_toolManager->RegisterTool( new SCH_EDITOR_CONTROL );
m_toolManager->RegisterTool( new SCH_FIND_REPLACE_TOOL ); m_toolManager->RegisterTool( new SCH_FIND_REPLACE_TOOL );
@ -731,6 +733,7 @@ void SCH_EDIT_FRAME::setupUIConditions()
CURRENT_TOOL( EE_ACTIONS::drawLines ); CURRENT_TOOL( EE_ACTIONS::drawLines );
CURRENT_TOOL( EE_ACTIONS::placeSchematicText ); CURRENT_TOOL( EE_ACTIONS::placeSchematicText );
CURRENT_TOOL( EE_ACTIONS::drawTextBox ); CURRENT_TOOL( EE_ACTIONS::drawTextBox );
CURRENT_TOOL( EE_ACTIONS::drawTable );
CURRENT_TOOL( EE_ACTIONS::placeImage ); CURRENT_TOOL( EE_ACTIONS::placeImage );
#undef CURRENT_TOOL #undef CURRENT_TOOL

View File

@ -102,4 +102,5 @@
//#define SEXPR_SCHEMATIC_FILE_VERSION 20230620 // ki_description -> Description Field //#define SEXPR_SCHEMATIC_FILE_VERSION 20230620 // ki_description -> Description Field
//#define SEXPR_SCHEMATIC_FILE_VERSION 20230808 // Move Sim.Enable field to exclude_from_sim attr //#define SEXPR_SCHEMATIC_FILE_VERSION 20230808 // Move Sim.Enable field to exclude_from_sim attr
//#define SEXPR_SCHEMATIC_FILE_VERSION 20230819 // Allow multiple library symbol inheritance depth. //#define SEXPR_SCHEMATIC_FILE_VERSION 20230819 // Allow multiple library symbol inheritance depth.
#define SEXPR_SCHEMATIC_FILE_VERSION 20231120 // generator_version; V8 cleanups //#define SEXPR_SCHEMATIC_FILE_VERSION 20231120 // generator_version; V8 cleanups
#define SEXPR_SCHEMATIC_FILE_VERSION 20240101 // Tables.

View File

@ -43,6 +43,8 @@
#include <sch_no_connect.h> #include <sch_no_connect.h>
#include <sch_text.h> #include <sch_text.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <schematic.h> #include <schematic.h>
@ -486,6 +488,10 @@ void SCH_IO_KICAD_SEXPR::Format( SCH_SHEET* aSheet )
saveTextBox( static_cast<SCH_TEXTBOX*>( item ), 1 ); saveTextBox( static_cast<SCH_TEXTBOX*>( item ), 1 );
break; break;
case SCH_TABLE_T:
saveTable( static_cast<SCH_TABLE*>( item ), 1 );
break;
default: default:
wxASSERT( "Unexpected schematic object type in SCH_IO_KICAD_SEXPR::Format()" ); wxASSERT( "Unexpected schematic object type in SCH_IO_KICAD_SEXPR::Format()" );
} }
@ -1336,13 +1342,14 @@ void SCH_IO_KICAD_SEXPR::saveTextBox( SCH_TEXTBOX* aTextBox, int aNestLevel )
{ {
wxCHECK_RET( aTextBox != nullptr && m_out != nullptr, "" ); wxCHECK_RET( aTextBox != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(text_box %s\n", m_out->Print( aNestLevel, "(%s %s\n",
aTextBox->Type() == SCH_TABLECELL_T ? "table_cell" : "text_box",
m_out->Quotew( aTextBox->GetText() ).c_str() ); m_out->Quotew( aTextBox->GetText() ).c_str() );
VECTOR2I pos = aTextBox->GetStart(); VECTOR2I pos = aTextBox->GetStart();
VECTOR2I size = aTextBox->GetEnd() - pos; VECTOR2I size = aTextBox->GetEnd() - pos;
m_out->Print( aNestLevel + 1, "(exclude_from_sim %s) (at %s %s %s) (size %s %s)\n", m_out->Print( aNestLevel + 1, "(exclude_from_sim %s) (at %s %s %s) (size %s %s)",
aTextBox->GetExcludedFromSim() ? "yes" : "no", aTextBox->GetExcludedFromSim() ? "yes" : "no",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pos.x ).c_str(), EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pos.x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pos.y ).c_str(), EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pos.y ).c_str(),
@ -1350,8 +1357,17 @@ void SCH_IO_KICAD_SEXPR::saveTextBox( SCH_TEXTBOX* aTextBox, int aNestLevel )
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, size.x ).c_str(), EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, size.x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, size.y ).c_str() ); EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, size.y ).c_str() );
if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( aTextBox ) )
m_out->Print( 0, " (span %d %d)", cell->GetColSpan(), cell->GetRowSpan() );
m_out->Print( 0, "\n" );
if( aTextBox->Type() != SCH_TABLECELL_T )
{
aTextBox->GetStroke().Format( m_out, schIUScale, aNestLevel + 1 ); aTextBox->GetStroke().Format( m_out, schIUScale, aNestLevel + 1 );
m_out->Print( 0, "\n" ); m_out->Print( 0, "\n" );
}
formatFill( m_out, aNestLevel + 1, aTextBox->GetFillMode(), aTextBox->GetFillColor() ); formatFill( m_out, aNestLevel + 1, aTextBox->GetFillMode(), aTextBox->GetFillColor() );
m_out->Print( 0, "\n" ); m_out->Print( 0, "\n" );
@ -1364,6 +1380,69 @@ void SCH_IO_KICAD_SEXPR::saveTextBox( SCH_TEXTBOX* aTextBox, int aNestLevel )
} }
void SCH_IO_KICAD_SEXPR::saveTable( SCH_TABLE* aTable, int aNestLevel )
{
wxCHECK_RET( aTable != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(table (column_count %d)\n",
aTable->GetColCount() );
m_out->Print( aNestLevel + 1, "(border (external %s) (header %s)",
aTable->StrokeExternal() ? "yes" : "no",
aTable->StrokeHeader() ? "yes" : "no" );
if( aTable->StrokeExternal() || aTable->StrokeHeader() )
{
m_out->Print( 0, " " );
aTable->GetBorderStroke().Format( m_out, schIUScale, 0 );
}
m_out->Print( 0, ")\n" );
m_out->Print( aNestLevel + 1, "(separators (rows %s) (cols %s)",
aTable->StrokeRows() ? "yes" : "no",
aTable->StrokeColumns() ? "yes" : "no" );
if( aTable->StrokeRows() || aTable->StrokeColumns() )
{
m_out->Print( 0, " " );
aTable->GetSeparatorsStroke().Format( m_out, schIUScale, 0 );
}
m_out->Print( 0, ")\n" ); // Close `separators` token.
m_out->Print( aNestLevel + 1, "(column_widths" );
for( int col = 0; col < aTable->GetColCount(); ++col )
{
m_out->Print( 0, " %s",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aTable->GetColWidth( col ) ).c_str() );
}
m_out->Print( 0, ")\n" );
m_out->Print( aNestLevel + 1, "(row_heights" );
for( int row = 0; row < aTable->GetRowCount(); ++row )
{
m_out->Print( 0, " %s",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aTable->GetRowHeight( row ) ).c_str() );
}
m_out->Print( 0, ")\n" );
m_out->Print( aNestLevel + 1, "(cells\n" );
for( SCH_TABLECELL* cell : aTable->GetCells() )
saveTextBox( cell, aNestLevel + 2 );
m_out->Print( aNestLevel + 1, ")\n" ); // Close `cells` token.
m_out->Print( aNestLevel, ")\n" ); // Close `table` token.
}
void SCH_IO_KICAD_SEXPR::saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias, int aNestLevel ) void SCH_IO_KICAD_SEXPR::saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias, int aNestLevel )
{ {
wxCHECK_RET( aAlias != nullptr, "BUS_ALIAS* is NULL" ); wxCHECK_RET( aAlias != nullptr, "BUS_ALIAS* is NULL" );

View File

@ -46,6 +46,7 @@ class SCH_SHAPE;
class SCH_BUS_ENTRY_BASE; class SCH_BUS_ENTRY_BASE;
class SCH_TEXT; class SCH_TEXT;
class SCH_TEXTBOX; class SCH_TEXTBOX;
class SCH_TABLE;
class SCH_SYMBOL; class SCH_SYMBOL;
class SCH_FIELD; class SCH_FIELD;
struct SCH_SYMBOL_INSTANCE; struct SCH_SYMBOL_INSTANCE;
@ -152,6 +153,7 @@ private:
void saveShape( SCH_SHAPE* aShape, int aNestLevel ); void saveShape( SCH_SHAPE* aShape, int aNestLevel );
void saveText( SCH_TEXT* aText, int aNestLevel ); void saveText( SCH_TEXT* aText, int aNestLevel );
void saveTextBox( SCH_TEXTBOX* aText, int aNestLevel ); void saveTextBox( SCH_TEXTBOX* aText, int aNestLevel );
void saveTable( SCH_TABLE* aTable, int aNestLevel );
void saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias, int aNestLevel ); void saveBusAlias( std::shared_ptr<BUS_ALIAS> aAlias, int aNestLevel );
void saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheets, int aNestLevel ); void saveInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheets, int aNestLevel );

View File

@ -50,6 +50,8 @@
#include <sch_field.h> #include <sch_field.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_label.h> #include <sch_label.h>
#include <sch_junction.h> #include <sch_junction.h>
#include <sch_no_connect.h> #include <sch_no_connect.h>
@ -2729,6 +2731,10 @@ void SCH_IO_KICAD_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopya
screen->Append( parseSchTextBox() ); screen->Append( parseSchTextBox() );
break; break;
case T_table:
screen->Append( parseSchTable() );
break;
case T_sheet_instances: case T_sheet_instances:
parseSchSheetInstances( aSheet, screen ); parseSchSheetInstances( aSheet, screen );
break; break;
@ -4141,6 +4147,29 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox()
wxCHECK_MSG( CurTok() == T_text_box, nullptr, wxCHECK_MSG( CurTok() == T_text_box, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a text box." ) ); wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a text box." ) );
std::unique_ptr<SCH_TEXTBOX> textBox = std::make_unique<SCH_TEXTBOX>();
parseSchTextBoxContent( textBox.get() );
return textBox.release();
}
SCH_TABLECELL* SCH_IO_KICAD_SEXPR_PARSER::parseSchTableCell()
{
wxCHECK_MSG( CurTok() == T_table_cell, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a table cell." ) );
std::unique_ptr<SCH_TABLECELL> cell = std::make_unique<SCH_TABLECELL>();
parseSchTextBoxContent( cell.get() );
return cell.release();
}
void SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBoxContent( SCH_TEXTBOX* aTextBox )
{
T token; T token;
VECTOR2I pos; VECTOR2I pos;
VECTOR2I end; VECTOR2I end;
@ -4149,11 +4178,10 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox()
bool foundSize = false; bool foundSize = false;
STROKE_PARAMS stroke( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ), LINE_STYLE::DEFAULT ); STROKE_PARAMS stroke( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ), LINE_STYLE::DEFAULT );
FILL_PARAMS fill; FILL_PARAMS fill;
std::unique_ptr<SCH_TEXTBOX> textBox = std::make_unique<SCH_TEXTBOX>();
NeedSYMBOL(); NeedSYMBOL();
textBox->SetText( FromUTF8() ); aTextBox->SetText( FromUTF8() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
@ -4165,7 +4193,7 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox()
switch( token ) switch( token )
{ {
case T_exclude_from_sim: case T_exclude_from_sim:
textBox->SetExcludedFromSim( parseBool() ); aTextBox->SetExcludedFromSim( parseBool() );
NeedRIGHT(); NeedRIGHT();
break; break;
@ -4182,7 +4210,7 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox()
case T_at: case T_at:
pos = parseXY(); pos = parseXY();
textBox->SetTextAngle( EDA_ANGLE( parseDouble( "textbox angle" ), DEGREES_T ) ); aTextBox->SetTextAngle( EDA_ANGLE( parseDouble( "textbox angle" ), DEGREES_T ) );
NeedRIGHT(); NeedRIGHT();
break; break;
@ -4192,24 +4220,34 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox()
NeedRIGHT(); NeedRIGHT();
break; break;
case T_span:
if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( aTextBox ) )
{
cell->SetColSpan( parseInt( "column span" ) );
cell->SetRowSpan( parseInt( "row span" ) );
}
NeedRIGHT();
break;
case T_stroke: case T_stroke:
parseStroke( stroke ); parseStroke( stroke );
textBox->SetStroke( stroke ); aTextBox->SetStroke( stroke );
break; break;
case T_fill: case T_fill:
parseFill( fill ); parseFill( fill );
textBox->SetFillMode( fill.m_FillType ); aTextBox->SetFillMode( fill.m_FillType );
textBox->SetFillColor( fill.m_Color ); aTextBox->SetFillColor( fill.m_Color );
break; break;
case T_effects: case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( textBox.get() ), false ); parseEDA_TEXT( static_cast<EDA_TEXT*>( aTextBox ), false );
break; break;
case T_uuid: case T_uuid:
NeedSYMBOL(); NeedSYMBOL();
const_cast<KIID&>( textBox->m_Uuid ) = KIID( FromUTF8() ); const_cast<KIID&>( aTextBox->m_Uuid ) = KIID( FromUTF8() );
NeedRIGHT(); NeedRIGHT();
break; break;
@ -4218,16 +4256,150 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox()
} }
} }
textBox->SetPosition( pos ); aTextBox->SetPosition( pos );
if( foundEnd ) if( foundEnd )
textBox->SetEnd( end ); aTextBox->SetEnd( end );
else if( foundSize ) else if( foundSize )
textBox->SetEnd( pos + size ); aTextBox->SetEnd( pos + size );
else else
Expecting( "size" ); Expecting( "size" );
}
return textBox.release();
SCH_TABLE* SCH_IO_KICAD_SEXPR_PARSER::parseSchTable()
{
wxCHECK_MSG( CurTok() == T_table, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a table." ) );
T token;
int defaultLineWidth = schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
STROKE_PARAMS borderStroke( defaultLineWidth, LINE_STYLE::DEFAULT );
STROKE_PARAMS separatorsStroke( defaultLineWidth, LINE_STYLE::DEFAULT );
std::unique_ptr<SCH_TABLE> table = std::make_unique<SCH_TABLE>( defaultLineWidth );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_column_count:
table->SetColCount( parseInt( "column count" ) );
NeedRIGHT();
break;
case T_column_widths:
{
int col = 0;
while( ( token = NextTok() ) != T_RIGHT )
table->SetColWidth( col++, parseInternalUnits() );
break;
}
case T_row_heights:
{
int row = 0;
while( ( token = NextTok() ) != T_RIGHT )
table->SetRowHeight( row++, parseInternalUnits() );
break;
}
case T_cells:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( token != T_table_cell )
Expecting( "table_cell" );
table->AddCell( parseSchTableCell() );
}
break;
case T_border:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_external:
table->SetStrokeExternal( parseBool() );
NeedRIGHT();
break;
case T_header:
table->SetStrokeHeader( parseBool() );
NeedRIGHT();
break;
case T_stroke:
parseStroke( borderStroke );
table->SetBorderStroke( borderStroke );
break;
default:
Expecting( "external, header or stroke" );
break;
}
}
break;
case T_separators:
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_rows:
table->SetStrokeRows( parseBool() );
NeedRIGHT();
break;
case T_cols:
table->SetStrokeColumns( parseBool() );
NeedRIGHT();
break;
case T_stroke:
parseStroke( separatorsStroke );
table->SetSeparatorsStroke( separatorsStroke );
break;
default:
Expecting( "rows, cols, or stroke" );
break;
}
}
break;
default:
Expecting( "columns, col_widths, row_heights, border, separators, header or cells" );
}
}
return table.release();
} }

View File

@ -56,6 +56,8 @@ class SCH_SHEET;
class SCH_SHEET_PIN; class SCH_SHEET_PIN;
class SCH_TEXT; class SCH_TEXT;
class SCH_TEXTBOX; class SCH_TEXTBOX;
class SCH_TABLE;
class SCH_TABLECELL;
class TITLE_BLOCK; class TITLE_BLOCK;
@ -216,6 +218,9 @@ private:
SCH_SHAPE* parseSchBezier(); SCH_SHAPE* parseSchBezier();
SCH_TEXT* parseSchText(); SCH_TEXT* parseSchText();
SCH_TEXTBOX* parseSchTextBox(); SCH_TEXTBOX* parseSchTextBox();
void parseSchTextBoxContent( SCH_TEXTBOX* aTextBox );
SCH_TABLECELL* parseSchTableCell();
SCH_TABLE* parseSchTable();
void parseBusAlias( SCH_SCREEN* aScreen ); void parseBusAlias( SCH_SCREEN* aScreen );
private: private:

View File

@ -32,7 +32,7 @@
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <callback_gal.h> #include <callback_gal.h>
#include <geometry/shape_segment.h> #include <geometry/shape_segment.h>
#include <geometry/shape_simple.h> #include <geometry/shape_rect.h>
#include <gr_text.h> #include <gr_text.h>
#include <lib_shape.h> #include <lib_shape.h>
#include <lib_field.h> #include <lib_field.h>
@ -55,6 +55,7 @@
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <sch_text.h> #include <sch_text.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h>
#include <schematic.h> #include <schematic.h>
#include <settings/color_settings.h> #include <settings/color_settings.h>
#include <view/view.h> #include <view/view.h>
@ -280,6 +281,9 @@ void SCH_PAINTER::draw( const EDA_ITEM* aItem, int aLayer, bool aDimmed )
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:
draw( static_cast<const SCH_TEXTBOX*>( aItem ), aLayer ); draw( static_cast<const SCH_TEXTBOX*>( aItem ), aLayer );
break; break;
case SCH_TABLE_T:
draw( static_cast<const SCH_TABLE*>( aItem ), aLayer );
break;
case SCH_LABEL_T: case SCH_LABEL_T:
draw( static_cast<const SCH_LABEL*>( aItem ), aLayer ); draw( static_cast<const SCH_LABEL*>( aItem ), aLayer );
break; break;
@ -432,9 +436,9 @@ COLOR4D SCH_PAINTER::getRenderColor( const EDA_ITEM* aItem, int aLayer, bool aDr
{ {
color = static_cast<const SCH_FIELD*>( aItem )->GetFieldColor(); color = static_cast<const SCH_FIELD*>( aItem )->GetFieldColor();
} }
else if( aItem->Type() == SCH_TEXTBOX_T ) else if( aItem->Type() == SCH_TEXTBOX_T || aItem->Type() == SCH_TABLECELL_T )
{ {
const SCH_TEXTBOX* textBox = static_cast<const SCH_TEXTBOX*>( aItem ); const SCH_TEXTBOX* textBox = dynamic_cast<const SCH_TEXTBOX*>( aItem );
if( aLayer == LAYER_NOTES_BACKGROUND ) if( aLayer == LAYER_NOTES_BACKGROUND )
color = textBox->GetFillColor(); color = textBox->GetFillColor();
@ -556,6 +560,7 @@ float SCH_PAINTER::getTextThickness( const EDA_ITEM* aItem ) const
break; break;
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:
case SCH_TABLECELL_T:
pen = static_cast<const SCH_TEXTBOX*>( aItem )->GetEffectiveTextPenWidth( pen ); pen = static_cast<const SCH_TEXTBOX*>( aItem )->GetEffectiveTextPenWidth( pen );
break; break;
@ -2285,6 +2290,14 @@ void SCH_PAINTER::draw( const SCH_TEXT* aText, int aLayer )
void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer ) void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer )
{ {
if( aTextBox->Type() == SCH_TABLECELL_T )
{
const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aTextBox );
if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
return;
}
bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS; bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
if( m_schSettings.IsPrinting() && drawingShadows ) if( m_schSettings.IsPrinting() && drawingShadows )
@ -2403,6 +2416,143 @@ void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer )
} }
void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer )
{
const_cast<SCH_TABLE*>( aTable )->RunOnChildren(
[&]( SCH_ITEM* aChild )
{
draw( static_cast<SCH_TEXTBOX*>( aChild ), aLayer );
} );
if( aLayer == LAYER_SELECTION_SHADOWS )
return;
VECTOR2I pos = aTable->GetPosition();
VECTOR2I end = aTable->GetEnd();
int lineWidth;
COLOR4D color;
LINE_STYLE lineStyle;
auto setupStroke =
[&]( const STROKE_PARAMS& stroke )
{
lineWidth = stroke.GetWidth();
color = stroke.GetColor();
lineStyle = stroke.GetLineStyle();
if( lineWidth == 0 )
lineWidth = m_schSettings.m_defaultPenWidth;
if( color == COLOR4D::UNSPECIFIED )
color = m_schSettings.GetLayerColor( LAYER_NOTES );
if( lineStyle == LINE_STYLE::DEFAULT )
lineStyle = LINE_STYLE::SOLID;
m_gal->SetIsFill( false );
m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( color );
m_gal->SetLineWidth( lineWidth );
};
auto strokeShape =
[&]( const SHAPE& shape )
{
STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, &m_schSettings,
[&]( const VECTOR2I& a, const VECTOR2I& b )
{
// DrawLine has problem with 0 length lines so enforce minimum
if( a == b )
m_gal->DrawLine( a+1, b );
else
m_gal->DrawLine( a, b );
} );
};
auto strokeLine =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
{
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
m_gal->DrawLine( ptA, ptB );
}
else
{
SHAPE_SEGMENT seg( ptA, ptB );
strokeShape( seg );
}
};
auto strokeRect =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
{
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
m_gal->DrawRectangle( ptA, ptB );
}
else
{
SHAPE_RECT rect( BOX2I( ptA, ptB - ptA ) );
strokeShape( rect );
}
};
if( aTable->GetSeparatorsStroke().GetWidth() >= 0 )
{
setupStroke( aTable->GetSeparatorsStroke() );
if( aTable->StrokeColumns() )
{
for( int col = 0; col < aTable->GetColCount() - 1; ++col )
{
for( int row = 0; row < aTable->GetRowCount(); ++row )
{
SCH_TABLECELL* cell = aTable->GetCell( row, col );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
strokeLine( VECTOR2I( cell->GetEndX(), cell->GetStartY() ),
VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
if( aTable->StrokeRows() )
{
for( int row = 0; row < aTable->GetRowCount() - 1; ++row )
{
for( int col = 0; col < aTable->GetColCount(); ++col )
{
SCH_TABLECELL* cell = aTable->GetCell( row, 0 );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
strokeLine( VECTOR2I( cell->GetStartX(), cell->GetEndY() ),
VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
}
if( aTable->GetBorderStroke().GetWidth() >= 0 )
{
setupStroke( aTable->GetBorderStroke() );
if( aTable->StrokeHeader() )
{
SCH_TABLECELL* cell = aTable->GetCell( 0, 0 );
strokeLine( VECTOR2I( pos.x, cell->GetEndY() ), VECTOR2I( end.x, cell->GetEndY() ) );
}
if( aTable->StrokeExternal() )
strokeRect( pos, end );
}
}
static void orientSymbol( LIB_SYMBOL* symbol, int orientation ) static void orientSymbol( LIB_SYMBOL* symbol, int orientation )
{ {
struct ORIENT struct ORIENT

View File

@ -45,6 +45,7 @@ class SCH_JUNCTION;
class SCH_LABEL; class SCH_LABEL;
class SCH_TEXT; class SCH_TEXT;
class SCH_TEXTBOX; class SCH_TEXTBOX;
class SCH_TABLE;
class SCH_HIERLABEL; class SCH_HIERLABEL;
class SCH_DIRECTIVE_LABEL; class SCH_DIRECTIVE_LABEL;
class SCH_GLOBALLABEL; class SCH_GLOBALLABEL;
@ -158,6 +159,7 @@ private:
void draw( const SCH_SHAPE* aShape, int aLayer ); void draw( const SCH_SHAPE* aShape, int aLayer );
void draw( const SCH_TEXTBOX* aTextBox, int aLayer ); void draw( const SCH_TEXTBOX* aTextBox, int aLayer );
void draw( const SCH_TEXT* aText, int aLayer ); void draw( const SCH_TEXT* aText, int aLayer );
void draw( const SCH_TABLE* aTable, int aLayer );
void draw( const SCH_LABEL* aText, int aLayer ); void draw( const SCH_LABEL* aText, int aLayer );
void draw( const SCH_DIRECTIVE_LABEL* aLabel, int aLayer ); void draw( const SCH_DIRECTIVE_LABEL* aLabel, int aLayer );
void draw( const SCH_HIERLABEL* aLabel, int aLayer ); void draw( const SCH_HIERLABEL* aLabel, int aLayer );

634
eeschema/sch_table.cpp Normal file
View File

@ -0,0 +1,634 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 <pgm_base.h>
#include <sch_edit_frame.h>
#include <plotters/plotter.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_rect.h>
#include <bitmaps.h>
#include <string_utils.h>
#include <schematic.h>
#include <settings/color_settings.h>
#include <sch_painter.h>
#include <wx/log.h>
#include <sch_table.h>
using KIGFX::SCH_RENDER_SETTINGS;
SCH_TABLE::SCH_TABLE( int aLineWidth ) :
SCH_ITEM( nullptr, SCH_TABLE_T ),
m_strokeExternal( true ),
m_strokeHeader( true ),
m_borderStroke( aLineWidth, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
m_strokeRows( true ),
m_strokeColumns( true ),
m_separatorsStroke( aLineWidth, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
m_colCount( 0 )
{
SetLayer( LAYER_NOTES );
}
SCH_TABLE::SCH_TABLE( const SCH_TABLE& aTable ) :
SCH_ITEM( aTable )
{
m_strokeExternal = aTable.m_strokeExternal;
m_strokeHeader = aTable.m_strokeHeader;
m_borderStroke = aTable.m_borderStroke;
m_strokeRows = aTable.m_strokeRows;
m_strokeColumns = aTable.m_strokeColumns;
m_separatorsStroke = aTable.m_separatorsStroke;
m_colCount = aTable.m_colCount;
m_colWidths = aTable.m_colWidths;
m_rowHeights = aTable.m_rowHeights;
for( SCH_TABLECELL* src : aTable.m_cells )
m_cells.push_back( new SCH_TABLECELL( *src ) );
for( SCH_TABLECELL* dest : m_cells )
dest->SetParent( this );
}
SCH_TABLE::~SCH_TABLE()
{
// We own our cells; delete them
for( SCH_TABLECELL* cell : m_cells )
delete cell;
}
void SCH_TABLE::SwapData( SCH_ITEM* aItem )
{
SCH_ITEM::SwapFlags( aItem );
wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_TABLE_T,
wxT( "Cannot swap data with invalid table." ) );
SCH_TABLE* table = static_cast<SCH_TABLE*>( aItem );
std::swap( m_strokeExternal, table->m_strokeExternal );
std::swap( m_strokeHeader, table->m_strokeHeader );
std::swap( m_borderStroke, table->m_borderStroke );
std::swap( m_strokeRows, table->m_strokeRows );
std::swap( m_strokeColumns, table->m_strokeColumns );
std::swap( m_separatorsStroke, table->m_separatorsStroke );
std::swap( m_colCount, table->m_colCount );
std::swap( m_colWidths, table->m_colWidths );
std::swap( m_rowHeights, table->m_rowHeights );
std::swap( m_cells, table->m_cells );
for( SCH_TABLECELL* cell : m_cells )
cell->SetParent( this );
for( SCH_TABLECELL* cell : table->m_cells )
cell->SetParent( table );
}
void SCH_TABLE::SetPosition( const VECTOR2I& aPos )
{
Move( aPos - GetPosition() );
}
VECTOR2I SCH_TABLE::GetPosition() const
{
return m_cells[0]->GetPosition();
}
VECTOR2I SCH_TABLE::GetEnd() const
{
VECTOR2I tableSize;
for( int ii = 0; ii < GetColCount(); ++ii )
tableSize.x += GetColWidth( ii );
for( int ii = 0; ii < GetRowCount(); ++ii )
tableSize.y += GetRowHeight( ii );
return GetPosition() + tableSize;
}
void SCH_TABLE::Normalize()
{
int y = GetPosition().y;
for( int row = 0; row < GetRowCount(); ++row )
{
int x = GetPosition().x;
int rowHeight = m_rowHeights[ row ];
for( int col = 0; col < GetColCount(); ++col )
{
int colWidth = m_colWidths[ col ];
SCH_TABLECELL* cell = GetCell( row, col );
cell->SetPosition( VECTOR2I( x, y ) );
cell->SetEnd( cell->GetStart() + VECTOR2I( colWidth, rowHeight ) );
if( cell->GetColSpan() > 1 || cell->GetRowSpan() > 1 )
{
VECTOR2I extraSize;
for( int ii = col + 1; ii < col + cell->GetColSpan(); ++ii )
extraSize.x += m_colWidths[ii];
for( int ii = row + 1; ii < row + cell->GetRowSpan(); ++ii )
extraSize.y += m_rowHeights[ii];
cell->SetEnd( cell->GetEnd() + extraSize );
}
x += colWidth;
}
y += rowHeight;
}
}
void SCH_TABLE::Move( const VECTOR2I& aMoveVector )
{
for( SCH_TABLECELL* cell : m_cells )
cell->Move( aMoveVector );
}
void SCH_TABLE::MirrorHorizontally( int aCenter )
{
// We could mirror all the cells, but it doesn't seem useful....
}
void SCH_TABLE::MirrorVertically( int aCenter )
{
// We could mirror all the cells, but it doesn't seem useful....
}
void SCH_TABLE::Rotate( const VECTOR2I& aCenter )
{
for( SCH_TABLECELL* cell : m_cells )
cell->Rotate( aCenter );
}
bool SCH_TABLE::operator<( const SCH_ITEM& aItem ) const
{
if( Type() != aItem.Type() )
return Type() < aItem.Type();
const SCH_TABLE& other = static_cast<const SCH_TABLE&>( aItem );
if( m_cells.size() != other.m_cells.size() )
return m_cells.size() < other.m_cells.size();
if( GetPosition().x != other.GetPosition().x )
return GetPosition().x < GetPosition().x;
if( GetPosition().y != GetPosition().y )
return GetPosition().y < GetPosition().y;
return m_cells[0] < other.m_cells[0];
}
void SCH_TABLE::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction )
{
for( SCH_TABLECELL* cell : m_cells )
aFunction( cell );
}
void SCH_TABLE::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset )
{
for( SCH_TABLECELL* cell : m_cells )
cell->Print( aSettings, aOffset );
wxDC* DC = aSettings->GetPrintDC();
VECTOR2I pos = GetPosition();
VECTOR2I end = GetEnd();
int lineWidth;
COLOR4D color;
LINE_STYLE lineStyle;
auto setupStroke =
[&]( const STROKE_PARAMS& stroke )
{
lineWidth = stroke.GetWidth();
color = stroke.GetColor();
lineStyle = stroke.GetLineStyle();
if( lineWidth == 0 )
lineWidth = aSettings->GetDefaultPenWidth();
if( color == COLOR4D::UNSPECIFIED )
color = aSettings->GetLayerColor( LAYER_NOTES );
if( lineStyle == LINE_STYLE::DEFAULT )
lineStyle = LINE_STYLE::SOLID;
};
auto strokeShape =
[&]( const SHAPE& shape )
{
STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, aSettings,
[&]( const VECTOR2I& a, const VECTOR2I& b )
{
GRLine( DC, a.x, a.y, b.x, b.y, lineWidth, color );
} );
};
auto strokeLine =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
{
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
GRLine( DC, ptA.x, ptA.y, ptB.x, ptB.y, lineWidth, color );
}
else
{
SHAPE_SEGMENT seg( ptA, ptB );
strokeShape( seg );
}
};
auto strokeRect =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
{
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
GRRect( DC, ptA, ptB, lineWidth, color );
}
else
{
SHAPE_RECT rect( BOX2I( ptA, ptB - ptA ) );
strokeShape( rect );
}
};
if( GetSeparatorsStroke().GetWidth() >= 0 )
{
setupStroke( GetSeparatorsStroke() );
if( StrokeColumns() )
{
for( int col = 0; col < GetColCount() - 1; ++col )
{
for( int row = 0; row < GetRowCount(); ++row )
{
SCH_TABLECELL* cell = GetCell( row, col );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
strokeLine( VECTOR2I( cell->GetEndX(), cell->GetStartY() ),
VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
if( StrokeRows() )
{
for( int row = 0; row < GetRowCount() - 1; ++row )
{
for( int col = 0; col < GetColCount(); ++col )
{
SCH_TABLECELL* cell = GetCell( row, 0 );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
strokeLine( VECTOR2I( cell->GetStartX(), cell->GetEndY() ),
VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
}
if( GetBorderStroke().GetWidth() >= 0 )
{
setupStroke( GetBorderStroke() );
if( StrokeHeader() )
{
SCH_TABLECELL* cell = GetCell( 0, 0 );
strokeLine( VECTOR2I( pos.x, cell->GetEndY() ), VECTOR2I( end.x, cell->GetEndY() ) );
}
if( StrokeExternal() )
strokeRect( pos, end );
}
}
const BOX2I SCH_TABLE::GetBoundingBox() const
{
// Note: a table with no cells is not allowed
BOX2I bbox = m_cells[0]->GetBoundingBox();
bbox.Merge( m_cells[ m_cells.size() - 1 ]->GetBoundingBox() );
return bbox;
}
INSPECT_RESULT SCH_TABLE::Visit( INSPECTOR aInspector, void* aTestData,
const std::vector<KICAD_T>& aScanTypes )
{
for( KICAD_T scanType : aScanTypes )
{
if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_TABLE_T )
{
if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
return INSPECT_RESULT::QUIT;
}
if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_TABLECELL_T )
{
for( SCH_TABLECELL* cell : m_cells )
{
if( INSPECT_RESULT::QUIT == aInspector( cell, (void*) this ) )
return INSPECT_RESULT::QUIT;
}
}
}
return INSPECT_RESULT::CONTINUE;
}
wxString SCH_TABLE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
{
return wxString::Format( _( "%d Column Table" ), m_colCount );
}
BITMAPS SCH_TABLE::GetMenuImage() const
{
return BITMAPS::spreadsheet; // JEY TODO
}
void SCH_TABLE::ViewGetLayers( int aLayers[], int& aCount ) const
{
aCount = 3;
aLayers[0] = LAYER_NOTES;
aLayers[1] = LAYER_NOTES_BACKGROUND;
aLayers[2] = LAYER_SELECTION_SHADOWS;
}
bool SCH_TABLE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
{
BOX2I rect = GetBoundingBox();
rect.Inflate( aAccuracy );
return rect.Contains( aPosition );
}
bool SCH_TABLE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
{
BOX2I rect = aRect;
rect.Inflate( aAccuracy );
if( aContained )
return rect.Contains( GetBoundingBox() );
return rect.Intersects( GetBoundingBox() );
}
void SCH_TABLE::Plot( PLOTTER* aPlotter, bool aBackground,
const SCH_PLOT_SETTINGS& aPlotSettings ) const
{
for( SCH_TABLECELL* cell : m_cells )
cell->Plot( aPlotter, aBackground, aPlotSettings );
if( aBackground )
return;
RENDER_SETTINGS* settings = aPlotter->RenderSettings();
VECTOR2I pos = GetPosition();
VECTOR2I end = GetEnd();
int lineWidth;
COLOR4D color;
LINE_STYLE lineStyle;
auto setupStroke =
[&]( const STROKE_PARAMS& stroke )
{
lineWidth = stroke.GetWidth();
color = stroke.GetColor();
lineStyle = stroke.GetLineStyle();
if( lineWidth == 0 )
{
if( SCHEMATIC* schematic = Schematic() )
lineWidth = schematic->Settings().m_DefaultLineWidth;
else
lineWidth = schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
}
if( lineWidth < settings->GetMinPenWidth() )
lineWidth = settings->GetMinPenWidth();
if( !aPlotter->GetColorMode() || color == COLOR4D::UNSPECIFIED )
color = settings->GetLayerColor( m_layer );
if( lineStyle == LINE_STYLE::DEFAULT )
lineStyle = LINE_STYLE::SOLID;
aPlotter->SetColor( color );
aPlotter->SetDash( lineWidth, lineStyle );
};
if( GetSeparatorsStroke().GetWidth() >= 0 )
{
setupStroke( GetSeparatorsStroke() );
if( StrokeColumns() )
{
for( int col = 0; col < GetColCount() - 1; ++col )
{
for( int row = 0; row < GetRowCount(); ++row )
{
SCH_TABLECELL* cell = GetCell( row, col );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
aPlotter->MoveTo( VECTOR2I( cell->GetEndX(), cell->GetStartY() ) );
aPlotter->FinishTo( VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
if( StrokeRows() )
{
for( int row = 0; row < GetRowCount() - 1; ++row )
{
for( int col = 0; col < GetColCount(); ++col )
{
SCH_TABLECELL* cell = GetCell( row, 0 );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
aPlotter->MoveTo( VECTOR2I( cell->GetStartX(), cell->GetEndY() ) );
aPlotter->FinishTo( VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
}
if( GetBorderStroke().GetWidth() >= 0 )
{
setupStroke( GetBorderStroke() );
if( StrokeHeader() )
{
SCH_TABLECELL* cell = GetCell( 0, 0 );
aPlotter->MoveTo( VECTOR2I( pos.x, cell->GetEndY() ) );
aPlotter->FinishTo( VECTOR2I( end.x, cell->GetEndY() ) );
}
if( StrokeExternal() )
aPlotter->Rect( pos, end, FILL_T::NO_FILL, lineWidth );
}
}
void SCH_TABLE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
// Don't use GetShownText() here; we want to show the user the variable references
aList.emplace_back( _( "Table" ), wxString::Format( _( "%d Columns" ), m_colCount ) );
}
bool SCH_TABLE::operator==( const SCH_ITEM& aOther ) const
{
if( Type() != aOther.Type() )
return false;
const SCH_TABLE& other = static_cast<const SCH_TABLE&>( aOther );
if( m_cells.size() != other.m_cells.size() )
return false;
if( m_colWidths != other.m_colWidths )
return false;
if( m_rowHeights != other.m_rowHeights )
return false;
for( int ii = 0; ii < (int) m_cells.size(); ++ii )
{
if( !( *m_cells[ii] == *other.m_cells[ii] ) )
return false;
}
return true;
}
double SCH_TABLE::Similarity( const SCH_ITEM& aOther ) const
{
if( aOther.Type() != Type() )
return 0.0;
const SCH_TABLE& other = static_cast<const SCH_TABLE&>( aOther );
if( m_cells.size() != other.m_cells.size() )
return 0.1;
double similarity = 1.0;
for( int ii = 0; ii < (int) m_cells.size(); ++ii )
similarity *= m_cells[ii]->Similarity( *other.m_cells[ii] );
return similarity;
}
static struct SCH_TABLE_DESC
{
SCH_TABLE_DESC()
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
REGISTER_TYPE( SCH_TABLE );
propMgr.AddTypeCast( new TYPE_CAST<SCH_TABLE, SCH_ITEM> );
propMgr.InheritsAfter( TYPE_HASH( SCH_TABLE ), TYPE_HASH( SCH_ITEM ) );
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start X" ),
&EDA_SHAPE::SetStartX, &EDA_SHAPE::GetStartX, PROPERTY_DISPLAY::PT_COORD,
ORIGIN_TRANSFORMS::ABS_X_COORD ) );
propMgr.AddProperty( new PROPERTY<EDA_SHAPE, int>( _HKI( "Start Y" ),
&EDA_SHAPE::SetStartY, &EDA_SHAPE::GetStartY, PROPERTY_DISPLAY::PT_COORD,
ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, bool>( _HKI( "External Border" ),
&SCH_TABLE::SetStrokeExternal, &SCH_TABLE::StrokeExternal ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, bool>( _HKI( "Header Border" ),
&SCH_TABLE::SetStrokeHeader, &SCH_TABLE::StrokeHeader ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, int>( _HKI( "Border Width" ),
&SCH_TABLE::SetBorderWidth, &SCH_TABLE::GetBorderWidth,
PROPERTY_DISPLAY::PT_SIZE ) );
propMgr.AddProperty( new PROPERTY_ENUM<SCH_TABLE, LINE_STYLE>( _HKI( "Border Style" ),
&SCH_TABLE::SetBorderStyle, &SCH_TABLE::GetBorderStyle ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, COLOR4D>( _HKI( "Border Color" ),
&SCH_TABLE::SetBorderColor, &SCH_TABLE::GetBorderColor ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, bool>( _HKI( "Row Separators" ),
&SCH_TABLE::SetStrokeRows, &SCH_TABLE::StrokeRows ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, bool>( _HKI( "Cell Separators" ),
&SCH_TABLE::SetStrokeColumns, &SCH_TABLE::StrokeColumns ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, int>( _HKI( "Separators Width" ),
&SCH_TABLE::SetSeparatorsWidth, &SCH_TABLE::GetSeparatorsWidth,
PROPERTY_DISPLAY::PT_SIZE ) );
propMgr.AddProperty( new PROPERTY_ENUM<SCH_TABLE, LINE_STYLE>( _HKI( "Separators Style" ),
&SCH_TABLE::SetSeparatorsStyle, &SCH_TABLE::GetSeparatorsStyle ) );
propMgr.AddProperty( new PROPERTY<SCH_TABLE, COLOR4D>( _HKI( "Separators Color" ),
&SCH_TABLE::SetSeparatorsColor, &SCH_TABLE::GetSeparatorsColor ) );
}
} _SCH_TABLE_DESC;

233
eeschema/sch_table.h Normal file
View File

@ -0,0 +1,233 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 SCH_TABLE_H
#define SCH_TABLE_H
#include <sch_tablecell.h>
#include <sch_item.h>
class SCH_TABLE : public SCH_ITEM
{
public:
SCH_TABLE( int aLineWidth );
SCH_TABLE( const SCH_TABLE& aTable );
~SCH_TABLE();
static inline bool ClassOf( const EDA_ITEM* aItem )
{
return aItem && SCH_TABLE_T == aItem->Type();
}
virtual wxString GetClass() const override
{
return wxT( "SCH_TABLE" );
}
void SwapData( SCH_ITEM* aItem ) override;
void SetStrokeExternal( bool aDoStroke ) { m_strokeExternal = aDoStroke; }
bool StrokeExternal() const { return m_strokeExternal; }
void SetStrokeHeader( bool aDoStroke ) { m_strokeHeader = aDoStroke; }
bool StrokeHeader() const { return m_strokeHeader; }
void SetBorderStroke( const STROKE_PARAMS& aParams ) { m_borderStroke = aParams; }
const STROKE_PARAMS& GetBorderStroke() const { return m_borderStroke; }
void SetBorderWidth( int aWidth ) { m_borderStroke.SetWidth( aWidth ); }
int GetBorderWidth() const { return m_borderStroke.GetWidth(); }
void SetBorderStyle( const LINE_STYLE aStyle ) { m_borderStroke.SetLineStyle( aStyle ); }
LINE_STYLE GetBorderStyle() const { return m_borderStroke.GetLineStyle(); }
void SetBorderColor( const COLOR4D& aColor ) { m_borderStroke.SetColor( aColor ); }
COLOR4D GetBorderColor() const { return m_borderStroke.GetColor(); }
void SetSeparatorsStroke( const STROKE_PARAMS& aParams ) { m_separatorsStroke = aParams; }
const STROKE_PARAMS& GetSeparatorsStroke() const { return m_separatorsStroke; }
void SetSeparatorsWidth( int aWidth ) { m_separatorsStroke.SetWidth( aWidth ); }
int GetSeparatorsWidth() const { return m_separatorsStroke.GetWidth(); }
void SetSeparatorsStyle( const LINE_STYLE aStyle ) { m_separatorsStroke.SetLineStyle( aStyle ); }
LINE_STYLE GetSeparatorsStyle() const { return m_separatorsStroke.GetLineStyle(); }
void SetSeparatorsColor( const COLOR4D& aColor ) { m_separatorsStroke.SetColor( aColor ); }
COLOR4D GetSeparatorsColor() const { return m_separatorsStroke.GetColor(); }
void SetStrokeColumns( bool aDoStroke ) { m_strokeColumns = aDoStroke; }
bool StrokeColumns() const { return m_strokeColumns; }
void SetStrokeRows( bool aDoStroke ) { m_strokeRows = aDoStroke; }
bool StrokeRows() const { return m_strokeRows; }
void RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction ) override;
void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& offset ) override;
bool operator<( const SCH_ITEM& aItem ) const override;
void SetPosition( const VECTOR2I& aPos ) override;
VECTOR2I GetPosition() const override;
VECTOR2I GetEnd() const;
void SetColCount( int aCount ) { m_colCount = aCount; }
int GetColCount() const { return m_colCount; }
int GetRowCount() const
{
return m_cells.size() / m_colCount;
}
void SetColWidth( int aCol, int aWidth ) { m_colWidths[aCol] = aWidth; }
int GetColWidth( int aCol ) const
{
if( m_colWidths.count( aCol ) )
return m_colWidths.at( aCol );
return 0;
}
void SetRowHeight( int aRow, int aHeight ) { m_rowHeights[aRow] = aHeight; }
int GetRowHeight( int aRow ) const
{
if( m_rowHeights.count( aRow ) )
return m_rowHeights.at( aRow );
return 0;
}
SCH_TABLECELL* GetCell( int aRow, int aCol ) const
{
int idx = aRow * m_colCount + aCol;
if( idx < (int) m_cells.size() )
return m_cells[ idx ];
else
return nullptr;
}
std::vector<SCH_TABLECELL*> GetCells() const
{
return m_cells;
}
void AddCell( SCH_TABLECELL* aCell )
{
m_cells.push_back( aCell );
aCell->SetParent( this );
}
void InsertCell( int aIdx, SCH_TABLECELL* aCell )
{
m_cells.insert( m_cells.begin() + aIdx, aCell );
aCell->SetParent( this );
}
void ClearCells()
{
for( SCH_TABLECELL* cell : m_cells )
delete cell;
m_cells.clear();
}
void DeleteMarkedCells()
{
alg::delete_if( m_cells,
[]( SCH_TABLECELL* cell )
{
return ( cell->GetFlags() & STRUCT_DELETED ) > 0;
} );
}
void Normalize();
void Move( const VECTOR2I& aMoveVector ) override;
void MirrorHorizontally( int aCenter ) override;
void MirrorVertically( int aCenter ) override;
void Rotate( const VECTOR2I& aCenter ) override;
const BOX2I GetBoundingBox() const override;
INSPECT_RESULT Visit( INSPECTOR inspector, void* testData,
const std::vector<KICAD_T>& aScanTypes ) override;
bool Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const override
{
// Symbols are searchable via the child field and pin item text.
return false;
}
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override;
BITMAPS GetMenuImage() const override;
void ViewGetLayers( int aLayers[], int& aCount ) const override;
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override;
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
void Plot( PLOTTER* aPlotter, bool aBackground,
const SCH_PLOT_SETTINGS& aPlotSettings ) const override;
EDA_ITEM* Clone() const override
{
return new SCH_TABLE( *this );
}
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
double Similarity( const SCH_ITEM& aOther ) const override;
bool operator==( const SCH_ITEM& aOther ) const override;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
bool m_strokeExternal;
bool m_strokeHeader;
STROKE_PARAMS m_borderStroke;
bool m_strokeRows;
bool m_strokeColumns;
STROKE_PARAMS m_separatorsStroke;
int m_colCount;
std::map<int, int> m_colWidths;
std::map<int, int> m_rowHeights;
std::vector<SCH_TABLECELL*> m_cells;
};
#endif /* SCH_TABLE_H */

170
eeschema/sch_tablecell.cpp Normal file
View File

@ -0,0 +1,170 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 <sch_edit_frame.h>
#include <widgets/msgpanel.h>
#include <string_utils.h>
#include <schematic.h>
#include <sch_table.h>
#include <sch_tablecell.h>
using KIGFX::SCH_RENDER_SETTINGS;
SCH_TABLECELL::SCH_TABLECELL( int aLineWidth, FILL_T aFillType ) :
SCH_TEXTBOX( aLineWidth, aFillType, wxEmptyString, SCH_TABLECELL_T ),
m_colSpan( 1 ),
m_rowSpan( 1 )
{
}
void SCH_TABLECELL::SwapData( SCH_ITEM* aItem )
{
SCH_TEXTBOX::SwapData( aItem );
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( aItem );
std::swap( m_colSpan, cell->m_colSpan );
std::swap( m_rowSpan, cell->m_rowSpan );
}
wxString SCH_TABLECELL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
{
return wxString::Format( _( "Table Cell %s" ), GetAddr() );
}
int SCH_TABLECELL::GetRow() const
{
const SCH_TABLE* table = static_cast<const SCH_TABLE*>( GetParent() );
for( int row = 0; row < table->GetRowCount(); ++row )
{
for( int col = 0; col < table->GetColCount(); ++col )
{
if( table->GetCell( row, col ) == this )
return row;
}
}
return -1;
}
int SCH_TABLECELL::GetColumn() const
{
const SCH_TABLE* table = static_cast<const SCH_TABLE*>( GetParent() );
for( int row = 0; row < table->GetRowCount(); ++row )
{
for( int col = 0; col < table->GetColCount(); ++col )
{
if( table->GetCell( row, col ) == this )
return col;
}
}
return -1;
}
wxString SCH_TABLECELL::GetAddr() const
{
return wxString::Format( wxT( "%c%d" ),
'A' + GetColumn() % 26,
GetRow() + 1 );
}
void SCH_TABLECELL::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset )
{
if( m_colSpan >= 1 && m_rowSpan >= 1 )
SCH_TEXTBOX::Print( aSettings, aOffset );
}
void SCH_TABLECELL::Plot( PLOTTER* aPlotter, bool aBackground,
const SCH_PLOT_SETTINGS& aPlotSettings ) const
{
if( m_colSpan >= 1 && m_rowSpan >= 1 )
SCH_TEXTBOX::Plot( aPlotter, aBackground, aPlotSettings );
}
void SCH_TABLECELL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{
aList.emplace_back( _( "Table Cell" ), GetAddr() );
// Don't use GetShownText() here; we want to show the user the variable references
aList.emplace_back( _( "Text" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
aList.emplace_back( _( "Cell Width" ),
aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
aList.emplace_back( _( "Cell Height" ),
aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) };
int style = IsBold() && IsItalic() ? 3 : IsBold() ? 2 : IsItalic() ? 1 : 0;
aList.emplace_back( _( "Style" ), textStyle[style] );
aList.emplace_back( _( "Text Size" ), aFrame->MessageTextFromValue( GetTextWidth() ) );
}
static struct SCH_TABLECELL_DESC
{
SCH_TABLECELL_DESC()
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
REGISTER_TYPE( SCH_TABLECELL );
propMgr.AddTypeCast( new TYPE_CAST<SCH_TABLECELL, SCH_TEXTBOX> );
propMgr.AddTypeCast( new TYPE_CAST<SCH_TABLECELL, SCH_SHAPE> );
propMgr.AddTypeCast( new TYPE_CAST<SCH_TABLECELL, EDA_SHAPE> );
propMgr.AddTypeCast( new TYPE_CAST<SCH_TABLECELL, EDA_TEXT> );
propMgr.InheritsAfter( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( SCH_TEXTBOX ) );
propMgr.InheritsAfter( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( SCH_SHAPE ) );
propMgr.InheritsAfter( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ) );
propMgr.InheritsAfter( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start X" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Start Y" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "End X" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "End Y" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Shape" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Width" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Style" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Color" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Thickness" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Hyperlink" ) );
}
} _SCH_TABLECELL_DESC;

80
eeschema/sch_tablecell.h Normal file
View File

@ -0,0 +1,80 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 SCH_TABLECELL_H
#define SCH_TABLECELL_H
#include <sch_textbox.h>
class SCH_TABLECELL : public SCH_TEXTBOX
{
public:
SCH_TABLECELL( int aLineWidth = 0, FILL_T aFillType = FILL_T::NO_FILL );
static inline bool ClassOf( const EDA_ITEM* aItem )
{
return aItem && SCH_TABLECELL_T == aItem->Type();
}
virtual wxString GetClass() const override
{
return wxT( "SCH_TABLECELL" );
}
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override;
EDA_ITEM* Clone() const override
{
return new SCH_TABLECELL( *this );
}
void SwapData( SCH_ITEM* aItem ) override;
int GetRow() const;
int GetColumn() const;
// @return the spreadsheet nomenclature for the cell (ie: B3 for 2nd column, 3rd row)
wxString GetAddr() const;
int GetColSpan() const { return m_colSpan; }
void SetColSpan( int aSpan ) { m_colSpan = aSpan; }
int GetRowSpan() const { return m_rowSpan; }
void SetRowSpan( int aSpan ) { m_rowSpan = aSpan; }
void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& offset ) override;
void Plot( PLOTTER* aPlotter, bool aBackground,
const SCH_PLOT_SETTINGS& aPlotSettings ) const override;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
protected:
int m_colSpan;
int m_rowSpan;
};
#endif /* SCH_TABLECELL_H */

View File

@ -43,8 +43,8 @@
using KIGFX::SCH_RENDER_SETTINGS; using KIGFX::SCH_RENDER_SETTINGS;
SCH_TEXTBOX::SCH_TEXTBOX( int aLineWidth, FILL_T aFillType, const wxString& text ) : SCH_TEXTBOX::SCH_TEXTBOX( int aLineWidth, FILL_T aFillType, const wxString& text, KICAD_T aType ) :
SCH_SHAPE( SHAPE_T::RECTANGLE, aLineWidth, aFillType, SCH_TEXTBOX_T ), SCH_SHAPE( SHAPE_T::RECTANGLE, aLineWidth, aFillType, aType ),
EDA_TEXT( schIUScale, text ) EDA_TEXT( schIUScale, text )
{ {
m_layer = LAYER_NOTES; m_layer = LAYER_NOTES;

View File

@ -36,7 +36,7 @@ class SCH_TEXTBOX : public SCH_SHAPE, public EDA_TEXT
{ {
public: public:
SCH_TEXTBOX( int aLineWidth = 0, FILL_T aFillType = FILL_T::NO_FILL, SCH_TEXTBOX( int aLineWidth = 0, FILL_T aFillType = FILL_T::NO_FILL,
const wxString& aText = wxEmptyString ); const wxString& aText = wxEmptyString, KICAD_T aType = SCH_TEXTBOX_T );
SCH_TEXTBOX( const SCH_TEXTBOX& aText ); SCH_TEXTBOX( const SCH_TEXTBOX& aText );

View File

@ -9,15 +9,20 @@ bezier
bidirectional bidirectional
bitmap bitmap
bold bold
border
bottom bottom
bus bus
bus_alias bus_alias
bus_entry bus_entry
cells
center center
circle circle
clock clock
clock_low clock_low
color color
cols
column_count
column_widths
comment comment
company company
convert convert
@ -35,6 +40,7 @@ edge_clock_high
effects effects
end end
extends extends
external
exclude_from_sim exclude_from_sim
face face
fields_autoplaced fields_autoplaced
@ -45,6 +51,7 @@ free
generator generator
generator_version generator_version
global_label global_label
header
hide hide
hierarchical_label hierarchical_label
hint_alt_swap hint_alt_swap
@ -118,16 +125,22 @@ required
rev rev
right right
round round
rows
row_heights
scale scale
separators
shape shape
sheet sheet
sheet_instances sheet_instances
show_name show_name
size size
span
start start
stroke stroke
symbol symbol
symbol_instances symbol_instances
table
table_cell
text text
text_box text_box
thickness thickness

View File

@ -32,6 +32,7 @@
#include <sch_line.h> #include <sch_line.h>
#include <sch_bitmap.h> #include <sch_bitmap.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <sch_table.h>
#include <tools/ee_selection_tool.h> #include <tools/ee_selection_tool.h>
#include <drawing_sheet/ds_proxy_undo_item.h> #include <drawing_sheet/ds_proxy_undo_item.h>
#include <tool/actions.h> #include <tool/actions.h>
@ -268,6 +269,7 @@ void SCH_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList )
std::vector<SCH_ITEM*> bulkAddedItems; std::vector<SCH_ITEM*> bulkAddedItems;
std::vector<SCH_ITEM*> bulkRemovedItems; std::vector<SCH_ITEM*> bulkRemovedItems;
std::vector<SCH_ITEM*> bulkChangedItems; std::vector<SCH_ITEM*> bulkChangedItems;
std::set<SCH_TABLE*> changedTables;
bool dirtyConnectivity = false; bool dirtyConnectivity = false;
SCH_CLEANUP_FLAGS connectivityCleanUp = NO_CLEANUP; SCH_CLEANUP_FLAGS connectivityCleanUp = NO_CLEANUP;

View File

@ -168,6 +168,7 @@ void SCH_EDIT_FRAME::ReCreateVToolbar()
m_drawToolBar->AddScaledSeparator( this ); m_drawToolBar->AddScaledSeparator( this );
m_drawToolBar->Add( EE_ACTIONS::placeSchematicText, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::placeSchematicText, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawTextBox, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::drawTextBox, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawTable, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawRectangle, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::drawRectangle, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE );
m_drawToolBar->Add( EE_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE );

View File

@ -145,6 +145,82 @@ TOOL_ACTION EE_ACTIONS::syncSelection( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveSelection.SyncSelection" ) .Name( "eeschema.InteractiveSelection.SyncSelection" )
.Scope( AS_GLOBAL ) ); .Scope( AS_GLOBAL ) );
TOOL_ACTION EE_ACTIONS::selectColumns( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveSelection.SelectColumns" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Select Column(s)" ) )
.Tooltip( _( "Select complete column(s) containing the current selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::selectRows( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveSelection.Rows" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Select Row(s)" ) )
.Tooltip( _( "Select complete row(s) containing the current selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::selectTable( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveSelection.SelectTable" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Select Table" ) )
.Tooltip( _( "Select parent table of selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::addRowAbove( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.addRowAbove" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Add Row Above" ) )
.Tooltip( _( "Insert a new table row above the selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::addRowBelow( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.addRowBelow" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Add Row Below" ) )
.Tooltip( _( "Insert a new table row below the selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::addColumnBefore( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.addColumnBefore" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Add Column Before" ) )
.Tooltip( _( "Insert a new table column before the selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::addColumnAfter( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.addColumnAfter" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Add Column After" ) )
.Tooltip( _( "Insert a new table column after the selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::deleteRows( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.deleteRows" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Delete Row(s)" ) )
.Tooltip( _( "Delete rows containing the currently selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::deleteColumns( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.deleteColumns" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Delete Column(s)" ) )
.Tooltip( _( "Delete columns containing the currently selected cell(s)" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::mergeCells( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.mergeCells" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Merge Cells" ) )
.Tooltip( _( "Turn selected table cells into a single cell" ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
TOOL_ACTION EE_ACTIONS::unmergeCells( TOOL_ACTION_ARGS()
.Name( "eeschema.TableEditor.unmergeCell" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Unmerge Cells" ) )
.Tooltip( _( "Turn merged table cells back into separate cells." ) )
.Icon( BITMAPS::spreadsheet ) ); // JEY TODO: need icon
// SYMBOL_EDITOR_CONTROL // SYMBOL_EDITOR_CONTROL
// //
@ -521,6 +597,14 @@ TOOL_ACTION EE_ACTIONS::drawTextBox( TOOL_ACTION_ARGS()
.Flags( AF_ACTIVATE ) .Flags( AF_ACTIVATE )
.Parameter( SHAPE_T::RECTANGLE ) ); .Parameter( SHAPE_T::RECTANGLE ) );
TOOL_ACTION EE_ACTIONS::drawTable( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.drawTable" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "Add Table" ) )
.Tooltip( _( "Draw table" ) )
.Icon( BITMAPS::spreadsheet ) // JEY TODO
.Flags( AF_ACTIVATE ) );
TOOL_ACTION EE_ACTIONS::drawRectangle( TOOL_ACTION_ARGS() TOOL_ACTION EE_ACTIONS::drawRectangle( TOOL_ACTION_ARGS()
.Name( "eeschema.InteractiveDrawing.drawRectangle" ) .Name( "eeschema.InteractiveDrawing.drawRectangle" )
.Scope( AS_GLOBAL ) .Scope( AS_GLOBAL )

View File

@ -69,6 +69,19 @@ public:
/// Selection synchronization (PCB -> SCH) /// Selection synchronization (PCB -> SCH)
static TOOL_ACTION syncSelection; static TOOL_ACTION syncSelection;
// Tables
static TOOL_ACTION selectRows;
static TOOL_ACTION selectColumns;
static TOOL_ACTION selectTable;
static TOOL_ACTION addRowAbove;
static TOOL_ACTION addRowBelow;
static TOOL_ACTION addColumnBefore;
static TOOL_ACTION addColumnAfter;
static TOOL_ACTION deleteRows;
static TOOL_ACTION deleteColumns;
static TOOL_ACTION mergeCells;
static TOOL_ACTION unmergeCells;
// Locking // Locking
static TOOL_ACTION toggleLock; static TOOL_ACTION toggleLock;
static TOOL_ACTION lock; static TOOL_ACTION lock;
@ -92,6 +105,7 @@ public:
static TOOL_ACTION importSheetPin; static TOOL_ACTION importSheetPin;
static TOOL_ACTION placeSchematicText; static TOOL_ACTION placeSchematicText;
static TOOL_ACTION drawTextBox; static TOOL_ACTION drawTextBox;
static TOOL_ACTION drawTable;
static TOOL_ACTION drawRectangle; static TOOL_ACTION drawRectangle;
static TOOL_ACTION drawCircle; static TOOL_ACTION drawCircle;
static TOOL_ACTION drawArc; static TOOL_ACTION drawArc;

View File

@ -28,6 +28,8 @@
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <sch_item.h> #include <sch_item.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_painter.h> #include <sch_painter.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <settings/app_settings.h> #include <settings/app_settings.h>
@ -416,7 +418,6 @@ void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, b
switch( aItem->Type() ) switch( aItem->Type() )
{ {
case SCH_TEXT_T: case SCH_TEXT_T:
case SCH_TEXTBOX_T:
case SCH_FIELD_T: case SCH_FIELD_T:
{ {
if( aIncludeText ) if( aIncludeText )
@ -425,6 +426,29 @@ void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, b
break; break;
} }
case SCH_TABLE_T:
{
if( aIncludeText )
{
addAnchor( aItem->GetPosition(), SNAPPABLE | CORNER, aItem );
addAnchor( static_cast<SCH_TABLE*>( aItem )->GetEnd(), SNAPPABLE | CORNER, aItem );
}
break;
}
case SCH_TEXTBOX_T:
case SCH_TABLECELL_T:
{
if( aIncludeText )
{
addAnchor( aItem->GetPosition(), SNAPPABLE | CORNER, aItem );
addAnchor( dynamic_cast<SCH_SHAPE*>( aItem )->GetEnd(), SNAPPABLE | CORNER, aItem );
}
break;
}
case SCH_SYMBOL_T: case SCH_SYMBOL_T:
case SCH_SHEET_T: case SCH_SHEET_T:
addAnchor( aItem->GetPosition(), ORIGIN, aItem ); addAnchor( aItem->GetPosition(), ORIGIN, aItem );

View File

@ -39,6 +39,8 @@ using namespace std::placeholders;
#include <sch_bitmap.h> #include <sch_bitmap.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_shape.h> #include <sch_shape.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <symbol_edit_frame.h> #include <symbol_edit_frame.h>
@ -70,6 +72,10 @@ enum RECTANGLE_LINES
RECT_TOP, RECT_RIGHT, RECT_BOT, RECT_LEFT RECT_TOP, RECT_RIGHT, RECT_BOT, RECT_LEFT
}; };
enum TABLECELL_POINTS
{
COL_WIDTH, ROW_HEIGHT
};
enum LINE_POINTS enum LINE_POINTS
{ {
@ -273,6 +279,14 @@ public:
break; break;
} }
case SCH_TABLECELL_T:
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( aItem );
points->AddPoint( cell->GetEnd() - VECTOR2I( 0, cell->GetRectangleHeight() / 2 ) );
points->AddPoint( cell->GetEnd() - VECTOR2I( cell->GetRectangleWidth() / 2, 0 ) );
break;
}
case SCH_SHEET_T: case SCH_SHEET_T:
{ {
SCH_SHEET* sheet = (SCH_SHEET*) aItem; SCH_SHEET* sheet = (SCH_SHEET*) aItem;
@ -448,6 +462,7 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
if( selection.Size() != 1 || !selection.Front()->IsType( { LIB_SHAPE_T, SCH_SHAPE_T, if( selection.Size() != 1 || !selection.Front()->IsType( { LIB_SHAPE_T, SCH_SHAPE_T,
LIB_TEXTBOX_T, SCH_TEXTBOX_T, LIB_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLECELL_T,
SCH_SHEET_T, SCH_SHEET_T,
SCH_ITEM_LOCATE_GRAPHIC_LINE_T, SCH_ITEM_LOCATE_GRAPHIC_LINE_T,
SCH_BITMAP_T } ) ) SCH_BITMAP_T } ) )
@ -516,6 +531,13 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
if( connected.first ) if( connected.first )
commit.Modify( connected.first, m_frame->GetScreen() ); commit.Modify( connected.first, m_frame->GetScreen() );
} }
else if( m_editPoints->GetParent()->Type() == SCH_TABLECELL_T )
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( m_editPoints->GetParent() );
SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
commit.Modify( table, m_frame->GetScreen() );
}
inDrag = true; inDrag = true;
} }
@ -1016,6 +1038,39 @@ void EE_POINT_EDITOR::updateParentItem( bool aSnapToGrid ) const
break; break;
} }
case SCH_TABLECELL_T:
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
if( isModified( m_editPoints->Point( COL_WIDTH ) ) )
{
cell->SetEnd( VECTOR2I( m_editPoints->Point( 0 ).GetX(), cell->GetEndY() ) );
int colWidth = cell->GetRectangleWidth();
for( int ii = 0; ii < cell->GetColSpan() - 1; ++ii )
colWidth -= table->GetColWidth( cell->GetColumn() + ii );
table->SetColWidth( cell->GetColumn() + cell->GetColSpan() - 1, colWidth );
table->Normalize();
}
else if( isModified( m_editPoints->Point( ROW_HEIGHT ) ) )
{
cell->SetEnd( VECTOR2I( cell->GetEndX(), m_editPoints->Point( 1 ).GetY() ) );
int rowHeight = cell->GetRectangleHeight();
for( int ii = 0; ii < cell->GetRowSpan() - 1; ++ii )
rowHeight -= table->GetRowHeight( cell->GetRow() + ii );
table->SetRowHeight( cell->GetRow() + cell->GetRowSpan() - 1, rowHeight );
table->Normalize();
}
break;
}
case SCH_BITMAP_T: case SCH_BITMAP_T:
{ {
EE_GRID_HELPER gridHelper( m_toolMgr ); EE_GRID_HELPER gridHelper( m_toolMgr );
@ -1350,6 +1405,17 @@ void EE_POINT_EDITOR::updatePoints()
break; break;
} }
case SCH_TABLECELL_T:
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
m_editPoints->Point( 0 ).SetPosition( cell->GetEndX(),
cell->GetEndY() - cell->GetRectangleHeight() / 2 );
m_editPoints->Point( 1 ).SetPosition( cell->GetEndX() - cell->GetRectangleWidth() / 2,
cell->GetEndY() );
break;
}
case SCH_BITMAP_T: case SCH_BITMAP_T:
{ {
SCH_BITMAP* bitmap = (SCH_BITMAP*) item; SCH_BITMAP* bitmap = (SCH_BITMAP*) item;

View File

@ -51,6 +51,8 @@
#include <sch_no_connect.h> #include <sch_no_connect.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <lib_shape.h> #include <lib_shape.h>
#include <schematic.h> #include <schematic.h>
#include <tool/tool_event.h> #include <tool/tool_event.h>
@ -216,8 +218,8 @@ bool EE_SELECTION_TOOL::Init()
SCH_ITEM_LOCATE_BUS_T } ); SCH_ITEM_LOCATE_BUS_T } );
auto connectedSelection = E_C::Count( 1 ) && E_C::OnlyTypes( connectedTypes ); auto connectedSelection = E_C::Count( 1 ) && E_C::OnlyTypes( connectedTypes );
auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_SHEET_T } ); auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_SHEET_T } );
auto crossProbingSelection = E_C::MoreThan( 0 ) && auto crossProbingSelection = E_C::MoreThan( 0 ) && E_C::HasTypes( { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T } );
E_C::HasTypes( { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T } ); auto tableCellSelection = E_C::MoreThan( 0 ) && E_C::OnlyTypes( { SCH_TABLECELL_T } );
auto schEditSheetPageNumberCondition = auto schEditSheetPageNumberCondition =
[&] ( const SELECTION& aSel ) [&] ( const SELECTION& aSel )
@ -278,6 +280,10 @@ bool EE_SELECTION_TOOL::Init()
menu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 ); menu.AddItem( EE_ACTIONS::clearHighlight, haveHighlight && EE_CONDITIONS::Idle, 1 );
menu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 ); menu.AddSeparator( haveHighlight && EE_CONDITIONS::Idle, 1 );
menu.AddItem( EE_ACTIONS::selectColumns, tableCellSelection && EE_CONDITIONS::Idle, 2 );
menu.AddItem( EE_ACTIONS::selectRows, tableCellSelection && EE_CONDITIONS::Idle, 2 );
menu.AddItem( EE_ACTIONS::selectTable, tableCellSelection && EE_CONDITIONS::Idle, 2 );
menu.AddSeparator( 100 ); menu.AddSeparator( 100 );
menu.AddItem( EE_ACTIONS::drawWire, schEditCondition && EE_CONDITIONS::Empty, 100 ); menu.AddItem( EE_ACTIONS::drawWire, schEditCondition && EE_CONDITIONS::Empty, 100 );
menu.AddItem( EE_ACTIONS::drawBus, schEditCondition && EE_CONDITIONS::Empty, 100 ); menu.AddItem( EE_ACTIONS::drawBus, schEditCondition && EE_CONDITIONS::Empty, 100 );
@ -292,7 +298,6 @@ bool EE_SELECTION_TOOL::Init()
menu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 ); menu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
menu.AddSeparator( 200 ); menu.AddSeparator( 200 );
menu.AddItem( EE_ACTIONS::selectConnection, connectedSelection && EE_CONDITIONS::Idle, 250 );
menu.AddItem( EE_ACTIONS::placeJunction, wireOrBusSelection && EE_CONDITIONS::Idle, 250 ); menu.AddItem( EE_ACTIONS::placeJunction, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
menu.AddItem( EE_ACTIONS::placeLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 ); menu.AddItem( EE_ACTIONS::placeLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
menu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 ); menu.AddItem( EE_ACTIONS::placeClassLabel, wireOrBusSelection && EE_CONDITIONS::Idle, 250 );
@ -540,7 +545,13 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) ) if( SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
schframe->FocusOnItem( nullptr ); schframe->FocusOnItem( nullptr );
if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT ) EE_COLLECTOR collector;
if( CollectHits( collector, evt->DragOrigin(), { SCH_TABLECELL_T } ) )
{
selectTableCells( static_cast<SCH_TABLE*>( collector[0]->GetParent() ) );
}
else if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT )
{ {
selectMultiple(); selectMultiple();
} }
@ -1310,6 +1321,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
SCH_LINE* line = dynamic_cast<SCH_LINE*>( item ); SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
LIB_SHAPE* shape = dynamic_cast<LIB_SHAPE*>( item ); LIB_SHAPE* shape = dynamic_cast<LIB_SHAPE*>( item );
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ); SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
SCH_TABLE* table = dynamic_cast<SCH_TABLE*>( item );
// Lines are hard to hit. Give them a bit more slop to still be considered "exact". // Lines are hard to hit. Give them a bit more slop to still be considered "exact".
if( line || ( shape && shape->GetShape() == SHAPE_T::POLY ) if( line || ( shape && shape->GetShape() == SHAPE_T::POLY )
@ -1325,6 +1337,10 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
if( symbol->GetBodyAndPinsBoundingBox().Contains( aPos ) ) if( symbol->GetBodyAndPinsBoundingBox().Contains( aPos ) )
exactHits.insert( item ); exactHits.insert( item );
} }
else if( table )
{
// Consider table cells exact, but not the table itself
}
else else
{ {
if( item->HitTest( aPos, 0 ) ) if( item->HitTest( aPos, 0 ) )
@ -1468,8 +1484,12 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const
} }
EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes ) EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& aScanTypes,
bool aPromoteCellSelections )
{ {
bool anyUnselected = false;
bool anySelected = false;
if( m_selection.Empty() ) if( m_selection.Empty() )
{ {
VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true ); VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true );
@ -1482,7 +1502,6 @@ EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& a
else // Trim an existing selection by aFilterList else // Trim an existing selection by aFilterList
{ {
bool isMoving = false; bool isMoving = false;
bool anyUnselected = false;
for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i ) for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
{ {
@ -1496,13 +1515,42 @@ EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>& a
} }
} }
if( anyUnselected )
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
if( !isMoving ) if( !isMoving )
updateReferencePoint(); updateReferencePoint();
} }
if( aPromoteCellSelections )
{
std::set<EDA_ITEM*> parents;
for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i )
{
EDA_ITEM* item = (EDA_ITEM*) m_selection.GetItem( i );
if( item->Type() == SCH_TABLECELL_T )
{
parents.insert( item->GetParent() );
unselect( item );
anyUnselected = true;
}
}
for( EDA_ITEM* parent : parents )
{
if( !parent->IsSelected() )
{
select( parent );
anySelected = true;
}
}
}
if( anyUnselected )
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
if( anySelected )
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
return m_selection; return m_selection;
} }
@ -1773,6 +1821,112 @@ bool EE_SELECTION_TOOL::selectMultiple()
} }
bool EE_SELECTION_TOOL::selectTableCells( SCH_TABLE* aTable )
{
bool cancelled = false; // Was the tool canceled while it was running?
m_multiple = true; // Multiple selection mode is active
for( SCH_TABLECELL* cell : aTable->GetCells() )
{
if( cell->IsSelected() )
cell->SetFlags( CANDIDATE );
else
cell->ClearFlags( CANDIDATE );
}
auto wasSelected =
[]( EDA_ITEM* aItem )
{
return ( aItem->GetFlags() & CANDIDATE ) > 0;
};
while( TOOL_EVENT* evt = Wait() )
{
if( evt->IsCancelInteractive() || evt->IsActivate() )
{
cancelled = true;
break;
}
else if( evt->IsDrag( BUT_LEFT ) )
{
getViewControls()->SetAutoPan( true );
BOX2I selectionRect( evt->DragOrigin(), evt->Position() - evt->DragOrigin() );
selectionRect.Normalize();
for( SCH_TABLECELL* cell : aTable->GetCells() )
{
bool doSelect = false;
if( cell->HitTest( selectionRect, false ) )
{
if( m_subtractive )
doSelect = false;
else if( m_exclusive_or )
doSelect = !wasSelected( cell );
else
doSelect = true;
}
else if( wasSelected( cell ) )
{
doSelect = m_additive || m_subtractive || m_exclusive_or;
}
if( doSelect && !cell->IsSelected() )
select( cell );
else if( !doSelect && cell->IsSelected() )
unselect( cell );
}
}
else if( evt->IsMouseUp( BUT_LEFT ) )
{
m_selection.SetIsHover( false );
bool anyAdded = false;
bool anySubtracted = false;
for( SCH_TABLECELL* cell : aTable->GetCells() )
{
if( cell->IsSelected() && !wasSelected( cell ) )
anyAdded = true;
else if( wasSelected( cell ) && !cell->IsSelected() )
anySubtracted = true;
}
// Inform other potentially interested tools
if( anyAdded )
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
if( anySubtracted )
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
break; // Stop waiting for events
}
else
{
// Allow some actions for navigation
for( int i = 0; allowedActions[i]; ++i )
{
if( evt->IsAction( allowedActions[i] ) )
{
evt->SetPassEvent();
break;
}
}
}
}
getViewControls()->SetAutoPan( false );
m_multiple = false; // Multiple selection mode is inactive
if( !cancelled )
m_selection.ClearReferencePoint();
return cancelled;
}
EDA_ITEM* EE_SELECTION_TOOL::GetNode( const VECTOR2I& aPosition ) EDA_ITEM* EE_SELECTION_TOOL::GetNode( const VECTOR2I& aPosition )
{ {
EE_COLLECTOR collector; EE_COLLECTOR collector;
@ -1852,6 +2006,105 @@ int EE_SELECTION_TOOL::SelectConnection( const TOOL_EVENT& aEvent )
} }
int EE_SELECTION_TOOL::SelectColumns( const TOOL_EVENT& aEvent )
{
std::set<std::pair<SCH_TABLE*, int>> columns;
bool added = false;
for( EDA_ITEM* item : m_selection )
{
if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
{
SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
columns.insert( std::make_pair( table, cell->GetColumn() ) );
}
}
for( auto& [ table, col ] : columns )
{
for( int row = 0; row < table->GetRowCount(); ++row )
{
SCH_TABLECELL* cell = table->GetCell( row, col );
if( !cell->IsSelected() )
{
select( table->GetCell( row, col ) );
added = true;
}
}
}
if( added )
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
return 0;
}
int EE_SELECTION_TOOL::SelectRows( const TOOL_EVENT& aEvent )
{
std::set<std::pair<SCH_TABLE*, int>> rows;
bool added = false;
for( EDA_ITEM* item : m_selection )
{
if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
{
SCH_TABLE* table = static_cast<SCH_TABLE*>( cell->GetParent() );
rows.insert( std::make_pair( table, cell->GetRow() ) );
}
}
for( auto& [ table, row ] : rows )
{
for( int col = 0; col < table->GetRowCount(); ++col )
{
SCH_TABLECELL* cell = table->GetCell( row, col );
if( !cell->IsSelected() )
{
select( table->GetCell( row, col ) );
added = true;
}
}
}
if( added )
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
return 0;
}
int EE_SELECTION_TOOL::SelectTable( const TOOL_EVENT& aEvent )
{
std::set<SCH_TABLE*> tables;
bool added = false;
for( EDA_ITEM* item : m_selection )
{
if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
tables.insert( static_cast<SCH_TABLE*>( cell->GetParent() ) );
}
ClearSelection();
for( SCH_TABLE* table : tables )
{
if( !table->IsSelected() )
{
select( table );
added = true;
}
}
if( added )
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
return 0;
}
int EE_SELECTION_TOOL::ClearSelection( const TOOL_EVENT& aEvent ) int EE_SELECTION_TOOL::ClearSelection( const TOOL_EVENT& aEvent )
{ {
ClearSelection(); ClearSelection();
@ -2115,7 +2368,7 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
case LIB_PIN_T: case LIB_PIN_T:
if( symEditFrame ) if( symEditFrame )
{ {
LIB_ITEM* lib_item = (LIB_ITEM*) aItem; const LIB_ITEM* lib_item = static_cast<const LIB_ITEM*>( aItem );
if( lib_item->GetUnit() && lib_item->GetUnit() != symEditFrame->GetUnit() ) if( lib_item->GetUnit() && lib_item->GetUnit() != symEditFrame->GetUnit() )
return false; return false;
@ -2129,6 +2382,16 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
case SCH_MARKER_T: // Always selectable case SCH_MARKER_T: // Always selectable
return true; return true;
case SCH_TABLECELL_T:
{
const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aItem );
if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
return false;
break;
}
default: // Suppress warnings default: // Suppress warnings
break; break;
} }
@ -2170,8 +2433,6 @@ void EE_SELECTION_TOOL::unselect( EDA_ITEM* aItem )
void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup ) void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
{ {
KICAD_T itemType = aItem->Type();
if( aMode == SELECTED ) if( aMode == SELECTED )
aItem->SetSelected(); aItem->SetSelected();
else if( aMode == BRIGHTENED ) else if( aMode == BRIGHTENED )
@ -2202,7 +2463,7 @@ void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup
if( aGroup && aMode != BRIGHTENED ) if( aGroup && aMode != BRIGHTENED )
getView()->Hide( aItem, true ); getView()->Hide( aItem, true );
if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T ) if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
getView()->Update( aItem->GetParent(), KIGFX::REPAINT ); getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
else else
getView()->Update( aItem, KIGFX::REPAINT ); getView()->Update( aItem, KIGFX::REPAINT );
@ -2211,8 +2472,6 @@ void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup
void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup ) void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup )
{ {
KICAD_T itemType = aItem->Type();
if( aMode == SELECTED ) if( aMode == SELECTED )
{ {
aItem->ClearSelected(); aItem->ClearSelected();
@ -2253,7 +2512,7 @@ void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, SELECTION* aGro
} ); } );
} }
if( itemType == SCH_PIN_T || itemType == SCH_FIELD_T || itemType == SCH_SHEET_PIN_T ) if( aItem->GetParent() && aItem->GetParent()->Type() != SCHEMATIC_T )
getView()->Update( aItem->GetParent(), KIGFX::REPAINT ); getView()->Update( aItem->GetParent(), KIGFX::REPAINT );
else else
getView()->Update( aItem, KIGFX::REPAINT ); getView()->Update( aItem, KIGFX::REPAINT );
@ -2286,6 +2545,10 @@ void EE_SELECTION_TOOL::setTransitions()
Go( &EE_SELECTION_TOOL::Main, EE_ACTIONS::selectionActivate.MakeEvent() ); Go( &EE_SELECTION_TOOL::Main, EE_ACTIONS::selectionActivate.MakeEvent() );
Go( &EE_SELECTION_TOOL::SelectNode, EE_ACTIONS::selectNode.MakeEvent() ); Go( &EE_SELECTION_TOOL::SelectNode, EE_ACTIONS::selectNode.MakeEvent() );
Go( &EE_SELECTION_TOOL::SelectConnection, EE_ACTIONS::selectConnection.MakeEvent() ); Go( &EE_SELECTION_TOOL::SelectConnection, EE_ACTIONS::selectConnection.MakeEvent() );
Go( &EE_SELECTION_TOOL::SelectColumns, EE_ACTIONS::selectColumns.MakeEvent() );
Go( &EE_SELECTION_TOOL::SelectRows, EE_ACTIONS::selectRows.MakeEvent() );
Go( &EE_SELECTION_TOOL::SelectTable, EE_ACTIONS::selectTable.MakeEvent() );
Go( &EE_SELECTION_TOOL::ClearSelection, EE_ACTIONS::clearSelection.MakeEvent() ); Go( &EE_SELECTION_TOOL::ClearSelection, EE_ACTIONS::clearSelection.MakeEvent() );
Go( &EE_SELECTION_TOOL::AddItemToSel, EE_ACTIONS::addItemToSel.MakeEvent() ); Go( &EE_SELECTION_TOOL::AddItemToSel, EE_ACTIONS::addItemToSel.MakeEvent() );

View File

@ -35,6 +35,7 @@
class SCH_BASE_FRAME; class SCH_BASE_FRAME;
class SCH_ITEM; class SCH_ITEM;
class SCH_TABLE;
class EE_GRID_HELPER; class EE_GRID_HELPER;
namespace KIGFX namespace KIGFX
@ -91,7 +92,8 @@ public:
* @param aScanTypes [optional] List of item types that are acceptable for selection. * @param aScanTypes [optional] List of item types that are acceptable for selection.
* @return either the current selection or, if empty, the selection at the cursor. * @return either the current selection or, if empty, the selection at the cursor.
*/ */
EE_SELECTION& RequestSelection( const std::vector<KICAD_T>& aScanTypes = { SCH_LOCATE_ANY_T } ); EE_SELECTION& RequestSelection( const std::vector<KICAD_T>& aScanTypes = { SCH_LOCATE_ANY_T },
bool aPromoteCellSelections = false );
/** /**
* Perform a click-type selection at a point (usually the cursor position). * Perform a click-type selection at a point (usually the cursor position).
@ -135,6 +137,10 @@ public:
*/ */
int SelectConnection( const TOOL_EVENT& aEvent ); int SelectConnection( const TOOL_EVENT& aEvent );
int SelectColumns( const TOOL_EVENT& aEvent );
int SelectRows( const TOOL_EVENT& aEvent );
int SelectTable( const TOOL_EVENT& aEvent );
///< Clear current selection event handler. ///< Clear current selection event handler.
int ClearSelection( const TOOL_EVENT& aEvent ); int ClearSelection( const TOOL_EVENT& aEvent );
@ -228,6 +234,13 @@ private:
*/ */
bool selectMultiple(); bool selectMultiple();
/**
* Handle a table cell drag selection within a table.
*
* @return true if the function was canceled (i.e. CancelEvent was received).
*/
bool selectTableCells( SCH_TABLE* aTable );
/** /**
* Handle disambiguation actions including displaying the menu. * Handle disambiguation actions including displaying the menu.
*/ */

View File

@ -119,6 +119,7 @@ protected:
case SCH_PIN_T: case SCH_PIN_T:
case SCH_FIELD_T: case SCH_FIELD_T:
case SCH_TABLECELL_T:
getView()->Update( aItem ); getView()->Update( aItem );
getView()->Update( aItem->GetParent() ); getView()->Update( aItem->GetParent() );
@ -132,6 +133,8 @@ protected:
if( aUpdateRTree && dynamic_cast<SCH_ITEM*>( aItem ) ) if( aUpdateRTree && dynamic_cast<SCH_ITEM*>( aItem ) )
m_frame->GetScreen()->Update( static_cast<SCH_ITEM*>( aItem ) ); m_frame->GetScreen()->Update( static_cast<SCH_ITEM*>( aItem ) );
break;
} }
} }

View File

@ -45,6 +45,8 @@
#include <sch_bus_entry.h> #include <sch_bus_entry.h>
#include <sch_text.h> #include <sch_text.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_sheet.h> #include <sch_sheet.h>
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <sch_bitmap.h> #include <sch_bitmap.h>
@ -2025,6 +2027,212 @@ void SCH_DRAWING_TOOLS::initSharedInstancePageNumbers( const SCH_SHEET_PATH& aAd
} }
int SCH_DRAWING_TOOLS::DrawTable( const TOOL_EVENT& aEvent )
{
SCHEMATIC* schematic = getModel<SCHEMATIC>();
SCH_TABLE* table = nullptr;
if( m_inDrawingTool )
return 0;
REENTRANCY_GUARD guard( &m_inDrawingTool );
KIGFX::VIEW_CONTROLS* controls = getViewControls();
EE_GRID_HELPER grid( m_toolMgr );
VECTOR2I cursorPos;
// We might be running as the same shape in another co-routine. Make sure that one
// gets whacked.
m_toolMgr->DeactivateTool();
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
m_frame->PushTool( aEvent );
auto setCursor =
[&]()
{
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
};
auto cleanup =
[&] ()
{
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
m_view->ClearPreview();
delete table;
table = nullptr;
};
Activate();
// Must be done after Activate() so that it gets set into the correct context
getViewControls()->ShowCursor( true );
// Set initial cursor
setCursor();
if( aEvent.HasPosition() )
m_toolMgr->PrimeTool( aEvent.Position() );
// Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() )
{
setCursor();
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
controls->ForceCursorPosition( true, cursorPos );
// The tool hotkey is interpreted as a click when drawing
bool isSyntheticClick = table && evt->IsActivate() && evt->HasPosition()
&& evt->Matches( aEvent );
if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
{
if( table )
{
cleanup();
}
else
{
m_frame->PopTool( aEvent );
break;
}
}
else if( evt->IsActivate() && !isSyntheticClick )
{
if( table && evt->IsMoveTool() )
{
// we're already drawing our own item; ignore the move tool
evt->SetPassEvent( false );
continue;
}
if( table )
cleanup();
if( evt->IsPointEditor() )
{
// don't exit (the point editor runs in the background)
}
else if( evt->IsMoveTool() )
{
// leave ourselves on the stack so we come back after the move
break;
}
else
{
m_frame->PopTool( aEvent );
break;
}
}
else if( evt->IsClick( BUT_LEFT ) && !table )
{
m_toolMgr->RunAction( EE_ACTIONS::clearSelection );
table = new SCH_TABLE( 0 );
table->SetColCount( 1 );
table->AddCell( new SCH_TABLECELL() );
table->SetParent( schematic );
table->SetFlags( IS_NEW );
table->SetPosition( cursorPos );
m_view->ClearPreview();
m_view->AddToPreview( table->Clone() );
}
else if( table && ( evt->IsClick( BUT_LEFT )
|| evt->IsDblClick( BUT_LEFT )
|| isSyntheticClick
|| evt->IsAction( &EE_ACTIONS::finishInteractive ) ) )
{
table->ClearEditFlags();
table->SetFlags( IS_NEW );
table->Normalize();
SCH_COMMIT commit( m_toolMgr );
commit.Add( table, m_frame->GetScreen() );
commit.Push( _( "Draw Table" ) );
m_selectionTool->AddItemToSel( table );
table = nullptr;
m_view->ClearPreview();
m_toolMgr->PostAction( ACTIONS::activatePointEditor );
}
else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
{
VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
VECTOR2I origin( table->GetPosition() );
VECTOR2I requestedSize( cursorPos - origin );
int colCount = std::max( 1, requestedSize.x / ( gridSize.x * 24 ) );
int rowCount = std::max( 1, requestedSize.y / ( gridSize.y * 8 ) );
VECTOR2I cellSize( std::max( gridSize.x * 4, requestedSize.x / colCount ),
std::max( gridSize.y * 2, requestedSize.y / rowCount ) );
cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
table->ClearCells();
table->SetColCount( colCount );
for( int col = 0; col < colCount; ++col )
table->SetColWidth( col, cellSize.x );
for( int row = 0; row < rowCount; ++row )
{
table->SetRowHeight( row, cellSize.y );
for( int col = 0; col < colCount; ++col )
{
SCH_TABLECELL* cell = new SCH_TABLECELL();
cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
cell->SetEnd( cell->GetPosition() + cellSize );
table->AddCell( cell );
}
}
m_view->ClearPreview();
m_view->AddToPreview( table->Clone() );
m_frame->SetMsgPanel( table );
}
else if( evt->IsDblClick( BUT_LEFT ) && !table )
{
m_toolMgr->RunAction( EE_ACTIONS::properties );
}
else if( evt->IsClick( BUT_RIGHT ) )
{
// Warp after context menu only if dragging...
if( !table )
m_toolMgr->VetoContextMenuMouseWarp();
m_menu.ShowContextMenu( m_selectionTool->GetSelection() );
}
else if( table && evt->IsAction( &ACTIONS::redo ) )
{
wxBell();
}
else
{
evt->SetPassEvent();
}
// Enable autopanning and cursor capture only when there is a shape being drawn
getViewControls()->SetAutoPan( table != nullptr );
getViewControls()->CaptureCursor( table != nullptr );
}
getViewControls()->SetAutoPan( false );
getViewControls()->CaptureCursor( false );
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
return 0;
}
int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent ) int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
{ {
SCH_SHEET* sheet = nullptr; SCH_SHEET* sheet = nullptr;
@ -2280,6 +2488,7 @@ void SCH_DRAWING_TOOLS::setTransitions()
Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawCircle.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawCircle.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawArc.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawArc.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawTextBox.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::DrawShape, EE_ACTIONS::drawTextBox.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::DrawTable, EE_ACTIONS::drawTable.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::PlaceImage, EE_ACTIONS::placeImage.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::PlaceImage, EE_ACTIONS::placeImage.MakeEvent() );
Go( &SCH_DRAWING_TOOLS::ImportGraphics, EE_ACTIONS::importGraphics.MakeEvent() ); Go( &SCH_DRAWING_TOOLS::ImportGraphics, EE_ACTIONS::importGraphics.MakeEvent() );
} }

View File

@ -53,6 +53,7 @@ public:
int SingleClickPlace( const TOOL_EVENT& aEvent ); int SingleClickPlace( const TOOL_EVENT& aEvent );
int TwoClickPlace( const TOOL_EVENT& aEvent ); int TwoClickPlace( const TOOL_EVENT& aEvent );
int DrawShape( const TOOL_EVENT& aEvent ); int DrawShape( const TOOL_EVENT& aEvent );
int DrawTable( const TOOL_EVENT& aEvent );
int DrawSheet( const TOOL_EVENT& aEvent ); int DrawSheet( const TOOL_EVENT& aEvent );
int PlaceImage( const TOOL_EVENT& aEvent ); int PlaceImage( const TOOL_EVENT& aEvent );
int ImportGraphics( const TOOL_EVENT& aEvent ); int ImportGraphics( const TOOL_EVENT& aEvent );

View File

@ -0,0 +1,541 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 <kiway.h>
#include <tools/sch_edit_tool.h>
#include <tools/ee_selection_tool.h>
#include <ee_actions.h>
#include <string_utils.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_commit.h>
#include <pgm_base.h>
#include <core/kicad_algo.h>
#include <tools/sch_edit_table_tool.h>
SCH_EDIT_TABLE_TOOL::SCH_EDIT_TABLE_TOOL() :
EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.TableEditor" )
{
}
bool SCH_EDIT_TABLE_TOOL::Init()
{
EE_TOOL_BASE::Init();
auto tableCellSelection = EE_CONDITIONS::MoreThan( 0 )
&& EE_CONDITIONS::OnlyTypes( { SCH_TABLECELL_T } );
auto tableCellBlockSelection =
[&]( const SELECTION& sel )
{
if( sel.CountType( SCH_TABLECELL_T ) < 2 )
return false;
int colMin = std::numeric_limits<int>::max();
int colMax = 0;
int rowMin = std::numeric_limits<int>::max();
int rowMax = 0;
int selectedArea = 0;
for( EDA_ITEM* item : sel )
{
wxCHECK2( item->Type() == SCH_TABLECELL_T, continue );
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
colMin = std::min( colMin, cell->GetColumn() );
colMax = std::max( colMax, cell->GetColumn() + cell->GetColSpan() );
rowMin = std::min( rowMin, cell->GetRow() );
rowMax = std::max( rowMax, cell->GetRow() + cell->GetRowSpan() );
selectedArea += cell->GetColSpan() * cell->GetRowSpan();
}
return selectedArea == ( colMax - colMin ) * ( rowMax - rowMin );
};
auto mergedCellsSelection =
[&]( const SELECTION& sel )
{
for( EDA_ITEM* item : sel )
{
if( SCH_TABLECELL* cell = dynamic_cast<SCH_TABLECELL*>( item ) )
{
if( cell->GetColSpan() > 1 || cell->GetRowSpan() > 1 )
return true;
}
}
return false;
};
//
// Add editing actions to the selection tool menu
//
CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
selToolMenu.AddSeparator( 100 );
selToolMenu.AddItem( EE_ACTIONS::addRowAbove, tableCellSelection && EE_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( EE_ACTIONS::addRowBelow, tableCellSelection && EE_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( EE_ACTIONS::addColumnBefore, tableCellSelection && EE_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( EE_ACTIONS::addColumnAfter, tableCellSelection && EE_CONDITIONS::Idle, 100 );
selToolMenu.AddSeparator( 100 );
selToolMenu.AddItem( EE_ACTIONS::deleteRows, tableCellSelection && EE_CONDITIONS::Idle, 100 );
selToolMenu.AddItem( EE_ACTIONS::deleteColumns, tableCellSelection && EE_CONDITIONS::Idle, 100 );
selToolMenu.AddSeparator( 100 );
selToolMenu.AddItem( EE_ACTIONS::mergeCells, tableCellSelection && tableCellBlockSelection, 100 );
selToolMenu.AddItem( EE_ACTIONS::unmergeCells, tableCellSelection && mergedCellsSelection, 100 );
selToolMenu.AddSeparator( 100 );
return true;
}
SCH_TABLECELL* copyCell( SCH_TABLECELL* aSource )
{
SCH_TABLECELL* cell = new SCH_TABLECELL();
cell->SetEnd( aSource->GetEnd() - aSource->GetStart() );
cell->SetFillMode( aSource->GetFillMode() );
cell->SetFillColor( aSource->GetFillColor() );
return cell;
}
int SCH_EDIT_TABLE_TOOL::AddRowAbove( const TOOL_EVENT& aEvent )
{
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
SCH_TABLECELL* topmost = nullptr;
for( EDA_ITEM* item : selection )
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
if( !topmost || cell->GetRow() < topmost->GetRow() )
topmost = cell;
}
if( !topmost )
return 0;
int row = topmost->GetRow();
SCH_TABLE* table = static_cast<SCH_TABLE*>( topmost->GetParent() );
SCH_COMMIT commit( m_toolMgr );
// Make a copy of the source row before things start moving around
std::vector<SCH_TABLECELL*> sources;
sources.reserve( table->GetColCount() );
for( int col = 0; col < table->GetColCount(); ++col )
sources.push_back( table->GetCell( row, col ) );
commit.Modify( table, m_frame->GetScreen() );
for( int col = 0; col < table->GetColCount(); ++col )
{
SCH_TABLECELL* cell = copyCell( sources[col] );
table->InsertCell( row * table->GetColCount(), cell );
}
table->Normalize();
commit.Push( _( "Add Row Above" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::AddRowBelow( const TOOL_EVENT& aEvent )
{
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
SCH_TABLECELL* bottommost = nullptr;
if( selection.Empty() )
return 0;
for( EDA_ITEM* item : selection )
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
if( !bottommost || cell->GetRow() > bottommost->GetRow() )
bottommost = cell;
}
if( !bottommost )
return 0;
int row = bottommost->GetRow();
SCH_TABLE* table = static_cast<SCH_TABLE*>( bottommost->GetParent() );
SCH_COMMIT commit( m_toolMgr );
// Make a copy of the source row before things start moving around
std::vector<SCH_TABLECELL*> sources;
sources.reserve( table->GetColCount() );
for( int col = 0; col < table->GetColCount(); ++col )
sources.push_back( table->GetCell( row, col ) );
commit.Modify( table, m_frame->GetScreen() );
for( int col = 0; col < table->GetColCount(); ++col )
{
SCH_TABLECELL* cell = copyCell( sources[col] );
table->InsertCell( ( row + 1 ) * table->GetColCount(), cell );
}
table->Normalize();
commit.Push( _( "Add Row Below" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::AddColumnBefore( const TOOL_EVENT& aEvent )
{
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
SCH_TABLECELL* leftmost = nullptr;
for( EDA_ITEM* item : selection )
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
if( !leftmost || cell->GetColumn() < leftmost->GetColumn() )
leftmost = cell;
}
if( !leftmost )
return 0;
int col = leftmost->GetColumn();
SCH_TABLE* table = static_cast<SCH_TABLE*>( leftmost->GetParent() );
int rowCount = table->GetRowCount();
SCH_COMMIT commit( m_toolMgr );
// Make a copy of the source column before things start moving around
std::vector<SCH_TABLECELL*> sources;
sources.reserve( rowCount );
for( int row = 0; row < rowCount; ++row )
sources.push_back( table->GetCell( row, col ) );
commit.Modify( table, m_frame->GetScreen() );
table->SetColCount( table->GetColCount() + 1 );
for( int row = 0; row < rowCount; ++row )
{
SCH_TABLECELL* cell = copyCell( sources[row] );
table->InsertCell( row * table->GetColCount() + col, cell );
}
table->Normalize();
commit.Push( _( "Add Column Before" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::AddColumnAfter( const TOOL_EVENT& aEvent )
{
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
SCH_TABLECELL* rightmost = nullptr;
for( EDA_ITEM* item : selection )
{
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
if( !rightmost || cell->GetColumn() > rightmost->GetColumn() )
rightmost = cell;
}
if( !rightmost )
return 0;
int col = rightmost->GetColumn();
SCH_TABLE* table = static_cast<SCH_TABLE*>( rightmost->GetParent() );
int rowCount = table->GetRowCount();
SCH_COMMIT commit( m_toolMgr );
// Make a copy of the source column before things start moving around
std::vector<SCH_TABLECELL*> sources;
sources.reserve( rowCount );
for( int row = 0; row < rowCount; ++row )
sources.push_back( table->GetCell( row, col ) );
commit.Modify( table, m_frame->GetScreen() );
table->SetColCount( table->GetColCount() + 1 );
for( int row = 0; row < rowCount; ++row )
{
SCH_TABLECELL* cell = copyCell( sources[row] );
table->InsertCell( row * table->GetColCount() + col + 1, cell );
}
table->Normalize();
commit.Push( _( "Add Column After" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::DeleteColumns( const TOOL_EVENT& aEvent )
{
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
if( selection.Empty() )
return 0;
SCH_TABLE* table = static_cast<SCH_TABLE*>( selection[0]->GetParent() );
int deleted = 0;
for( int col = 0; col < table->GetColCount(); ++col )
{
bool deleteColumn = false;
for( int row = 0; row < table->GetRowCount(); ++row )
{
if( table->GetCell( row, col )->IsSelected() )
{
deleteColumn = true;
break;
}
}
if( deleteColumn )
{
for( int row = 0; row < table->GetRowCount(); ++row )
table->GetCell( row, col )->SetFlags( STRUCT_DELETED );
deleted++;
}
}
SCH_COMMIT commit( m_toolMgr );
if( deleted == table->GetColCount() )
{
commit.Remove( table, m_frame->GetScreen() );
}
else
{
commit.Modify( table, m_frame->GetScreen() );
table->DeleteMarkedCells();
table->SetColCount( table->GetColCount() - deleted );
table->Normalize();
}
if( deleted > 1 )
commit.Push( _( "Delete Columns" ) );
else
commit.Push( _( "Delete Column" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::DeleteRows( const TOOL_EVENT& aEvent )
{
EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
if( selection.Empty() )
return 0;
SCH_TABLE* table = static_cast<SCH_TABLE*>( selection[0]->GetParent() );
int deleted = 0;
for( int row = 0; row < table->GetRowCount(); ++row )
{
bool deleteRow = false;
for( int col = 0; col < table->GetColCount(); ++col )
{
if( table->GetCell( row, col )->IsSelected() )
{
deleteRow = true;
break;
}
}
if( deleteRow )
{
for( int col = 0; col < table->GetColCount(); ++col )
table->GetCell( row, col )->SetFlags( STRUCT_DELETED );
deleted++;
}
}
SCH_COMMIT commit( m_toolMgr );
if( deleted == table->GetRowCount() )
{
commit.Remove( table, m_frame->GetScreen() );
}
else
{
commit.Modify( table, m_frame->GetScreen() );
table->DeleteMarkedCells();
table->Normalize();
}
if( deleted > 1 )
commit.Push( _( "Delete Rows" ) );
else
commit.Push( _( "Delete Row" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::MergeCells( const TOOL_EVENT& aEvent )
{
EE_SELECTION& sel = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
if( sel.Empty() )
return 0;
int colMin = std::numeric_limits<int>::max();
int colMax = 0;
int rowMin = std::numeric_limits<int>::max();
int rowMax = 0;
SCH_COMMIT commit( m_toolMgr );
SCH_TABLE* table = static_cast<SCH_TABLE*>( sel[0]->GetParent() );
for( EDA_ITEM* item : sel )
{
wxCHECK2( item->Type() == SCH_TABLECELL_T, continue );
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
colMin = std::min( colMin, cell->GetColumn() );
colMax = std::max( colMax, cell->GetColumn() + cell->GetColSpan() );
rowMin = std::min( rowMin, cell->GetRow() );
rowMax = std::max( rowMax, cell->GetRow() + cell->GetRowSpan() );
}
wxString content;
VECTOR2I extents;
for( int row = rowMin; row < rowMax; ++row )
{
extents.y += table->GetRowHeight( row );
extents.x = 0;
for( int col = colMin; col < colMax; ++col )
{
extents.x += table->GetColWidth( col );
SCH_TABLECELL* cell = table->GetCell( row, col );
if( !cell->GetText().IsEmpty() )
{
if( !content.IsEmpty() )
content += "\n";
content += cell->GetText();
}
commit.Modify( cell, m_frame->GetScreen() );
cell->SetColSpan( 0 );
cell->SetRowSpan( 0 );
cell->SetText( wxEmptyString );
}
}
SCH_TABLECELL* topLeft = table->GetCell( rowMin, colMin );
topLeft->SetColSpan( colMax - colMin );
topLeft->SetRowSpan( rowMax - rowMin );
topLeft->SetText( content );
topLeft->SetEnd( topLeft->GetStart() + extents );
table->Normalize();
commit.Push( _( "Merge Cells" ) );
return 0;
}
int SCH_EDIT_TABLE_TOOL::UnmergeCells( const TOOL_EVENT& aEvent )
{
EE_SELECTION& sel = m_selectionTool->RequestSelection( { SCH_TABLECELL_T } );
if( sel.Empty() )
return 0;
SCH_COMMIT commit( m_toolMgr );
SCH_TABLE* table = static_cast<SCH_TABLE*>( sel[0]->GetParent() );
for( EDA_ITEM* item : sel )
{
wxCHECK2( item->Type() == SCH_TABLECELL_T, continue );
SCH_TABLECELL* cell = static_cast<SCH_TABLECELL*>( item );
int rowSpan = cell->GetRowSpan();
int colSpan = cell->GetColSpan();
for( int row = cell->GetRow(); row < cell->GetRow() + rowSpan; ++row )
{
for( int col = cell->GetColumn(); col < cell->GetColumn() + colSpan; ++col )
{
SCH_TABLECELL* target = table->GetCell( row, col );
commit.Modify( target, m_frame->GetScreen() );
target->SetColSpan( 1 );
target->SetRowSpan( 1 );
VECTOR2I extents( table->GetColWidth( col ), table->GetRowHeight( row ) );
target->SetEnd( target->GetStart() + extents );
}
}
}
table->Normalize();
commit.Push( _( "Unmerge Cells" ) );
return 0;
}
void SCH_EDIT_TABLE_TOOL::setTransitions()
{
Go( &SCH_EDIT_TABLE_TOOL::AddRowAbove, EE_ACTIONS::addRowAbove.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::AddRowBelow, EE_ACTIONS::addRowBelow.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::AddColumnBefore, EE_ACTIONS::addColumnBefore.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::AddColumnAfter, EE_ACTIONS::addColumnAfter.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::DeleteRows, EE_ACTIONS::deleteRows.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::DeleteColumns, EE_ACTIONS::deleteColumns.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::MergeCells, EE_ACTIONS::mergeCells.MakeEvent() );
Go( &SCH_EDIT_TABLE_TOOL::UnmergeCells, EE_ACTIONS::unmergeCells.MakeEvent() );
}

View File

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 SCH_TABLE_TOOL_H
#define SCH_TABLE_TOOL_H
#include <tools/ee_tool_base.h>
class SCH_EDIT_FRAME;
class SCH_EDIT_TABLE_TOOL : public EE_TOOL_BASE<SCH_EDIT_FRAME>
{
public:
SCH_EDIT_TABLE_TOOL();
~SCH_EDIT_TABLE_TOOL() override { }
/// @copydoc TOOL_INTERACTIVE::Init()
bool Init() override;
int AddRowAbove( const TOOL_EVENT& aEvent );
int AddRowBelow( const TOOL_EVENT& aEvent );
int AddColumnBefore( const TOOL_EVENT& aEvent );
int AddColumnAfter( const TOOL_EVENT& aEvent );
int DeleteRows( const TOOL_EVENT& aEvent );
int DeleteColumns( const TOOL_EVENT& aEvent );
int MergeCells( const TOOL_EVENT& aEvent );
int UnmergeCells( const TOOL_EVENT& aEvent );
private:
///< Set up handlers for various events.
void setTransitions() override;
};
#endif //SCH_TABLE_TOOL_H

View File

@ -39,6 +39,8 @@
#include <sch_sheet_pin.h> #include <sch_sheet_pin.h>
#include <sch_text.h> #include <sch_text.h>
#include <sch_textbox.h> #include <sch_textbox.h>
#include <sch_table.h>
#include <sch_tablecell.h>
#include <sch_bitmap.h> #include <sch_bitmap.h>
#include <sch_view.h> #include <sch_view.h>
#include <sch_line.h> #include <sch_line.h>
@ -60,6 +62,7 @@
#include <dialogs/dialog_shape_properties.h> #include <dialogs/dialog_shape_properties.h>
#include <dialogs/dialog_label_properties.h> #include <dialogs/dialog_label_properties.h>
#include <dialogs/dialog_text_properties.h> #include <dialogs/dialog_text_properties.h>
#include <dialogs/dialog_tablecell_properties.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <symbol_editor_settings.h> #include <symbol_editor_settings.h>
@ -301,6 +304,8 @@ bool SCH_EDIT_TOOL::Init()
case SCH_SHEET_PIN_T: case SCH_SHEET_PIN_T:
case SCH_TEXT_T: case SCH_TEXT_T:
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:
case SCH_TABLE_T:
case SCH_TABLECELL_T:
case SCH_LABEL_T: case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T: case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T: case SCH_HIER_LABEL_T:
@ -612,6 +617,8 @@ const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = {
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLE_T,
SCH_TABLECELL_T, // will be promoted to parent table(s)
SCH_LABEL_T, SCH_LABEL_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_HIER_LABEL_T,
@ -632,7 +639,7 @@ const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = {
int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{ {
bool clockwise = ( aEvent.Matches( EE_ACTIONS::rotateCW.MakeEvent() ) ); bool clockwise = ( aEvent.Matches( EE_ACTIONS::rotateCW.MakeEvent() ) );
EE_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems ); EE_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, true );
if( selection.GetSize() == 0 ) if( selection.GetSize() == 0 )
return 0; return 0;
@ -768,6 +775,19 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
break; break;
case SCH_TABLE_T:
{
// Rotate the table on itself. Tables do not have an anchor point.
SCH_TABLE* table = static_cast<SCH_TABLE*>( head );
BOX2I box( table->GetPosition(), table->GetEnd() - table->GetPosition() );
rotPoint = m_frame->GetNearestHalfGridPosition( box.GetCenter() );
for( int i = 0; clockwise ? i < 3 : i < 1; ++i )
head->Rotate( rotPoint );
break;
}
case SCH_BITMAP_T: case SCH_BITMAP_T:
for( int i = 0; clockwise ? i < 3 : i < 1; ++i ) for( int i = 0; clockwise ? i < 3 : i < 1; ++i )
head->Rotate( rotPoint ); head->Rotate( rotPoint );
@ -778,10 +798,10 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
case SCH_SHEET_T: case SCH_SHEET_T:
{ {
// Rotate the sheet on itself. Sheets do not have an anchor point.
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( head ); SCH_SHEET* sheet = static_cast<SCH_SHEET*>( head );
rotPoint = m_frame->GetNearestHalfGridPosition( sheet->GetRotationCenter() ); rotPoint = m_frame->GetNearestHalfGridPosition( sheet->GetRotationCenter() );
// Rotate the sheet on itself. Sheets do not have an anchor point.
for( int i = 0; clockwise ? i < 3 : i < 1; ++i ) for( int i = 0; clockwise ? i < 3 : i < 1; ++i )
sheet->Rotate( rotPoint ); sheet->Rotate( rotPoint );
@ -1344,6 +1364,8 @@ static std::vector<KICAD_T> deletableItems =
SCH_SHAPE_T, SCH_SHAPE_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TABLECELL_T, // Clear contents
SCH_TABLE_T,
SCH_LABEL_T, SCH_LABEL_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_HIER_LABEL_T,
@ -1408,6 +1430,11 @@ int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
commit.Modify( item, m_frame->GetScreen() ); commit.Modify( item, m_frame->GetScreen() );
static_cast<SCH_FIELD*>( sch_item )->SetVisible( false ); static_cast<SCH_FIELD*>( sch_item )->SetVisible( false );
} }
else if( sch_item->Type() == SCH_TABLECELL_T )
{
commit.Modify( item, m_frame->GetScreen() );
static_cast<SCH_TABLECELL*>( sch_item )->SetText( wxEmptyString );
}
else else
{ {
sch_item->SetFlags( STRUCT_DELETED ); sch_item->SetFlags( STRUCT_DELETED );
@ -1884,8 +1911,19 @@ int SCH_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
// QuasiModal required for syntax help and Scintilla auto-complete // QuasiModal required for syntax help and Scintilla auto-complete
if( dlg.ShowQuasiModal() == wxID_OK ) if( dlg.ShowQuasiModal() == wxID_OK )
m_frame->OnModify(); m_frame->OnModify();
}
break; break;
}
case SCH_TABLECELL_T:
{
DIALOG_TABLECELL_PROPERTIES dlg( m_frame, static_cast<SCH_TABLECELL*>( curr_item ) );
if( dlg.ShowModal() == wxID_OK )
m_frame->OnModify();
break;
}
case SCH_LABEL_T: case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T: case SCH_GLOBAL_LABEL_T:

View File

@ -446,7 +446,8 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
// Be sure that there is at least one item that we can move. If there's no selection try // Be sure that there is at least one item that we can move. If there's no selection try
// looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection). // looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection).
EE_SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::MovableItems ); EE_SELECTION& selection = m_selectionTool->RequestSelection( EE_COLLECTOR::MovableItems,
true );
bool unselect = selection.IsHover(); bool unselect = selection.IsHover();
// Keep an original copy of the starting points for cleanup after the move // Keep an original copy of the starting points for cleanup after the move

View File

@ -148,6 +148,8 @@ enum KICAD_T
SCH_BITMAP_T, SCH_BITMAP_T,
SCH_TEXTBOX_T, SCH_TEXTBOX_T,
SCH_TEXT_T, SCH_TEXT_T,
SCH_TABLE_T,
SCH_TABLECELL_T,
SCH_LABEL_T, SCH_LABEL_T,
SCH_GLOBAL_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_HIER_LABEL_T,
@ -382,6 +384,8 @@ constexpr bool IsEeschemaType( const KICAD_T aType )
case SCH_BITMAP_T: case SCH_BITMAP_T:
case SCH_TEXT_T: case SCH_TEXT_T:
case SCH_TEXTBOX_T: case SCH_TEXTBOX_T:
case SCH_TABLE_T:
case SCH_TABLECELL_T:
case SCH_LABEL_T: case SCH_LABEL_T:
case SCH_DIRECTIVE_LABEL_T: case SCH_DIRECTIVE_LABEL_T:
case SCH_GLOBAL_LABEL_T: case SCH_GLOBAL_LABEL_T:

View File

@ -58,7 +58,7 @@ protected:
int firstNonWhitespace( int aLine, int* aWhitespaceCount = nullptr ); int firstNonWhitespace( int aLine, int* aWhitespaceCount = nullptr );
void onCharHook( wxKeyEvent& aEvent ); virtual void onCharHook( wxKeyEvent& aEvent );
void onChar( wxStyledTextEvent& aEvent ); void onChar( wxStyledTextEvent& aEvent );
void onModified( wxStyledTextEvent& aEvent ); void onModified( wxStyledTextEvent& aEvent );
void onScintillaUpdateUI( wxStyledTextEvent& aEvent ); void onScintillaUpdateUI( wxStyledTextEvent& aEvent );