From 91df43c97ae256b36d46b1ed8cb8376826fabf8f Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 25 Nov 2023 12:38:24 +0000 Subject: [PATCH] ADDED: schematic tables. Fixes https://gitlab.com/kicad/code/kicad/-/issues/6806 --- common/eda_item.cpp | 2 + common/stroke_params.cpp | 10 +- eeschema/CMakeLists.txt | 5 + .../dialog_symbol_fields_table_base.cpp | 4 +- .../dialog_symbol_fields_table_base.fbp | 8 +- .../dialogs/dialog_tablecell_properties.cpp | 453 +++ .../dialogs/dialog_tablecell_properties.h | 67 + .../dialog_tablecell_properties_base.cpp | 415 ++ .../dialog_tablecell_properties_base.fbp | 3578 +++++++++++++++++ .../dialog_tablecell_properties_base.h | 120 + eeschema/dialogs/dialog_text_properties.cpp | 1 + eeschema/ee_collectors.cpp | 3 + eeschema/menubar.cpp | 1 + eeschema/sch_base_frame.cpp | 8 +- eeschema/sch_edit_frame.cpp | 3 + eeschema/sch_file_versions.h | 3 +- .../sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp | 85 +- .../sch_io/kicad_sexpr/sch_io_kicad_sexpr.h | 2 + .../kicad_sexpr/sch_io_kicad_sexpr_parser.cpp | 198 +- .../kicad_sexpr/sch_io_kicad_sexpr_parser.h | 5 + eeschema/sch_painter.cpp | 156 +- eeschema/sch_painter.h | 2 + eeschema/sch_table.cpp | 634 +++ eeschema/sch_table.h | 233 ++ eeschema/sch_tablecell.cpp | 170 + eeschema/sch_tablecell.h | 80 + eeschema/sch_textbox.cpp | 4 +- eeschema/sch_textbox.h | 2 +- eeschema/schematic.keywords | 13 + eeschema/schematic_undo_redo.cpp | 2 + eeschema/toolbars_sch_editor.cpp | 1 + eeschema/tools/ee_actions.cpp | 84 + eeschema/tools/ee_actions.h | 14 + eeschema/tools/ee_grid_helper.cpp | 26 +- eeschema/tools/ee_point_editor.cpp | 66 + eeschema/tools/ee_selection_tool.cpp | 295 +- eeschema/tools/ee_selection_tool.h | 15 +- eeschema/tools/ee_tool_base.h | 3 + eeschema/tools/sch_drawing_tools.cpp | 209 + eeschema/tools/sch_drawing_tools.h | 1 + eeschema/tools/sch_edit_table_tool.cpp | 541 +++ eeschema/tools/sch_edit_table_tool.h | 57 + eeschema/tools/sch_edit_tool.cpp | 46 +- eeschema/tools/sch_move_tool.cpp | 3 +- include/core/typeinfo.h | 4 + include/scintilla_tricks.h | 2 +- 46 files changed, 7573 insertions(+), 61 deletions(-) create mode 100644 eeschema/dialogs/dialog_tablecell_properties.cpp create mode 100644 eeschema/dialogs/dialog_tablecell_properties.h create mode 100644 eeschema/dialogs/dialog_tablecell_properties_base.cpp create mode 100644 eeschema/dialogs/dialog_tablecell_properties_base.fbp create mode 100644 eeschema/dialogs/dialog_tablecell_properties_base.h create mode 100644 eeschema/sch_table.cpp create mode 100644 eeschema/sch_table.h create mode 100644 eeschema/sch_tablecell.cpp create mode 100644 eeschema/sch_tablecell.h create mode 100644 eeschema/tools/sch_edit_table_tool.cpp create mode 100644 eeschema/tools/sch_edit_table_tool.h diff --git a/common/eda_item.cpp b/common/eda_item.cpp index 2b8b5e4db1..0b5450334e 100644 --- a/common/eda_item.cpp +++ b/common/eda_item.cpp @@ -374,6 +374,8 @@ static struct EDA_ITEM_DESC .Map( SCH_SHAPE_T, _HKI( "Graphic" ) ) .Map( SCH_TEXT_T, _HKI( "Text" ) ) .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_DIRECTIVE_LABEL_T, _HKI( "Directive Label" ) ) .Map( SCH_GLOBAL_LABEL_T, _HKI( "Global Label" ) ) diff --git a/common/stroke_params.cpp b/common/stroke_params.cpp index d130223079..6bbeb70f85 100644 --- a/common/stroke_params.cpp +++ b/common/stroke_params.cpp @@ -205,18 +205,18 @@ void STROKE_PARAMS::GetMsgPanelInfo( UNITS_PROVIDER* aUnitsProvider, { if( aIncludeStyle ) { - wxString lineStyle = _( "Default" ); + wxString msg = _( "Default" ); - for( const std::pair& typeEntry : lineTypeNames ) + for( const auto& [ lineStyle, lineStyleDesc ] : lineTypeNames ) { - if( typeEntry.first == GetLineStyle() ) + if( lineStyle == GetLineStyle() ) { - lineStyle = typeEntry.second.name; + msg = lineStyleDesc.name; break; } } - aList.emplace_back( _( "Line Style" ), lineStyle ); + aList.emplace_back( _( "Line Style" ), msg ); } if( aIncludeWidth ) diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 734fb5fc29..8e6427d398 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -159,6 +159,8 @@ set( EESCHEMA_DLGS dialogs/dialog_symbol_properties_base.cpp dialogs/dialog_symbol_remap.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_base.cpp dialogs/dialog_update_from_pcb.cpp @@ -380,6 +382,8 @@ set( EESCHEMA_SRCS sch_sheet_path.cpp sch_sheet_pin.cpp sch_symbol.cpp + sch_table.cpp + sch_tablecell.cpp sch_text.cpp sch_textbox.cpp sch_validators.cpp @@ -419,6 +423,7 @@ set( EESCHEMA_SRCS tools/ee_selection.cpp tools/ee_selection_tool.cpp tools/sch_drawing_tools.cpp + tools/sch_edit_table_tool.cpp tools/sch_edit_tool.cpp tools/sch_editor_control.cpp tools/sch_editor_conditions.cpp diff --git a/eeschema/dialogs/dialog_symbol_fields_table_base.cpp b/eeschema/dialogs/dialog_symbol_fields_table_base.cpp index dbdf54f1a9..4b888840e5 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table_base.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table_base.cpp @@ -326,10 +326,10 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare bButtonsSizer->Add( 0, 0, 9, wxEXPAND, 5 ); 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 ); - 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_sdbSizerOK = new wxButton( this, wxID_OK ); diff --git a/eeschema/dialogs/dialog_symbol_fields_table_base.fbp b/eeschema/dialogs/dialog_symbol_fields_table_base.fbp index cc7ee788d0..cec9969c7f 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table_base.fbp +++ b/eeschema/dialogs/dialog_symbol_fields_table_base.fbp @@ -3373,8 +3373,8 @@ - 5 - wxALIGN_CENTER_VERTICAL|wxALL + 10 + wxALIGN_CENTER_VERTICAL|wxRIGHT 0 1 @@ -3447,8 +3447,8 @@ - 5 - wxALIGN_CENTER_VERTICAL|wxALL + 10 + wxALIGN_CENTER_VERTICAL|wxRIGHT 0 1 diff --git a/eeschema/dialogs/dialog_tablecell_properties.cpp b/eeschema/dialogs/dialog_tablecell_properties.cpp new file mode 100644 index 0000000000..70fe1bd3c6 --- /dev/null +++ b/eeschema/dialogs/dialog_tablecell_properties.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class TABLECELL_SCINTILLA_TRICKS : public SCINTILLA_TRICKS +{ +public: + TABLECELL_SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, + std::function onAcceptHandler, + std::function 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 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( 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( 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( 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( 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; +} diff --git a/eeschema/dialogs/dialog_tablecell_properties.h b/eeschema/dialogs/dialog_tablecell_properties.h new file mode 100644 index 0000000000..6ac8e0b3dd --- /dev/null +++ b/eeschema/dialogs/dialog_tablecell_properties.h @@ -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 +#include + + +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 diff --git a/eeschema/dialogs/dialog_tablecell_properties_base.cpp b/eeschema/dialogs/dialog_tablecell_properties_base.cpp new file mode 100644 index 0000000000..624a1faff9 --- /dev/null +++ b/eeschema/dialogs/dialog_tablecell_properties_base.cpp @@ -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 ); + +} diff --git a/eeschema/dialogs/dialog_tablecell_properties_base.fbp b/eeschema/dialogs/dialog_tablecell_properties_base.fbp new file mode 100644 index 0000000000..c57f228180 --- /dev/null +++ b/eeschema/dialogs/dialog_tablecell_properties_base.fbp @@ -0,0 +1,3578 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_tablecell_properties_base + 1000 + none + + + 1 + dialog_tablecell_properties_base + + . + + 1 + 1 + 1 + 1 + UI + 0 + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_TABLECELL_PROPERTIES_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Table Cell Properties + + 0 + + + + + + bMainSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 500 + 1 + + 1 + + 0 + 1 + wxSHOW_EFFECT_NONE + wxID_ANY + + 0 + + + 0 + + 1 + m_infoBar + 1 + + + protected + 1 + + Resizable + 1 + wxSHOW_EFFECT_NONE + + WX_INFOBAR; widgets/wx_infobar.h; forward_declare + 0 + + + + + + + + 10 + wxEXPAND|wxRIGHT|wxLEFT + 1 + + + bColumns + wxHORIZONTAL + none + + 6 + wxEXPAND|wxTOP + 1 + + + bCellContentMargins + wxVERTICAL + none + + 1 + wxEXPAND|wxTOP|wxBOTTOM + 1 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + 0 + + 0 + 0 + wxID_ANY + 0 + 0 + + 0 + + + 0 + 500,-1 + 1 + m_textCtrl + 1 + + + protected + 1 + + 0 + Resizable + 1 + + ; forward_declare + 0 + 4 + 0 + + 1 + 0 + 0 + + + wxBORDER_SUNKEN + onMultiLineTCLostFocus + + + + + + 10 + wxEXPAND|wxBOTTOM|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_notebook + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + + + Table + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_tablePage + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer16 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 1 + + 0,2 + wxBOTH + 1 + + 3 + + m_textEntrySizer + wxFLEX_GROWMODE_SPECIFIED + protected + 4 + + 2 + 2 + 0 + wxBOTTOM + 0 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + External border + + 0 + + + 0 + + 1 + m_borderCheckbox + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onBorderChecked + + + + 20 + 1 + 2 + wxLEFT + 0 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Header border + + 0 + + + 0 + + 1 + m_headerBorder + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL + 2 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Width: + 0 + + 0 + + + 0 + + 1 + m_borderWidthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 2 + 1 + wxEXPAND + 2 + 1 + + + bSizer7 + wxHORIZONTAL + none + + 5 + wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + -1,-1 + 0 + -1,-1 + 1 + m_borderWidthCtrl + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + -1,-1 + 1 + m_borderWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 15 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Color: + 0 + + 0 + + + 0 + + 1 + m_borderColorLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; Not forward_declare + 0 + + + + + -1 + + + + 5 + + 0 + + 0 + protected + 5 + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panelBorderColor + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxBORDER_SIMPLE|wxTAB_TRAVERSAL + + + bSizer2 + wxVERTICAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + COLOR_SWATCH + 1 + + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_borderColorSwatch + 1 + + + protected + 1 + + Resizable + + 1 + + COLOR_SWATCH; widgets/color_swatch.h; forward_declare + 0 + + + + + + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL + 3 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Style: + 0 + + 0 + + + 0 + + 1 + m_borderStyleLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 2 + 1 + wxEXPAND + 3 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 200,-1 + 1 + m_borderStyleCombo + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + 1 + 0 + wxEXPAND + 4 + 1 + + 20 + protected + 0 + + + + 15 + 2 + 0 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Row lines + + 0 + + + 0 + + 1 + m_rowSeparators + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onBorderChecked + + + + 20 + 1 + 2 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Column lines + + 0 + + + 0 + + 1 + m_colSeparators + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onBorderChecked + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL + 7 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Width: + 0 + + 0 + + + 0 + + 1 + m_separatorsWidthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 2 + 1 + wxEXPAND + 7 + 1 + + + bSizer71 + wxHORIZONTAL + none + + 5 + wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + -1,-1 + 0 + -1,-1 + 1 + m_separatorsWidthCtrl + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 3 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + -1,-1 + 1 + m_separatorsWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 15 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Color: + 0 + + 0 + + + 0 + + 1 + m_separatorsColorLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; Not forward_declare + 0 + + + + + -1 + + + + 5 + + 0 + + 0 + protected + 5 + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panelSeparatorsColor + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxBORDER_SIMPLE|wxTAB_TRAVERSAL + + + bSizer21 + wxVERTICAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + COLOR_SWATCH + 1 + + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + + 1 + m_separatorsColorSwatch + 1 + + + protected + 1 + + Resizable + + 1 + + COLOR_SWATCH; widgets/color_swatch.h; forward_declare + 0 + + + + + + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL + 8 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Style: + 0 + + 0 + + + 0 + + 1 + m_separatorsStyleLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 2 + 1 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 8 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 200,-1 + 1 + m_separatorsStyleCombo + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + Cell + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_cellPage + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer13 + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 1 + + + bMargins + wxVERTICAL + none + + 10 + wxBOTTOM + 0 + + + bSizeCtrlSizer + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + + 1 + + + 0 + 0 + wxID_ANY + + + 0 + + 0 + + + 0 + + 1 + m_separator1 + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Bold + + 0 + + 0 + + + 0 + + 1 + m_bold + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Bold + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Italic + + 0 + + 0 + + + 0 + + 1 + m_italic + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Italic + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + + 1 + + + 0 + 0 + wxID_ANY + + + 0 + + 0 + + + 0 + + 1 + m_separator2 + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Align left + + 0 + + 0 + + + 0 + + 1 + m_hAlignLeft + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Align left + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Align center + + 0 + + 0 + + + 0 + + 1 + m_hAlignCenter + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Align horizontal center + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Align right + + 0 + + 0 + + + 0 + + 1 + m_hAlignRight + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Align right + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + + 1 + + + 0 + 0 + wxID_ANY + + + 0 + + 0 + + + 0 + + 1 + m_separator3 + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Align top + + 0 + + 0 + + + 0 + + 1 + m_vAlignTop + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Align top + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Align middle + + 0 + + 0 + + + 0 + + 1 + m_vAlignCenter + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Align vertical center + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Align bottom + + 0 + + 0 + + + 0 + + 1 + m_vAlignBottom + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + Align bottom + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + + 1 + + + 0 + 0 + wxID_ANY + + + 0 + + 0 + + + 0 + + 1 + m_separator4 + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND|wxBOTTOM + 0 + + -1,5 + wxBOTH + 1 + + 5 + + gbSizer2 + wxFLEX_GROWMODE_SPECIFIED + none + 4 + + 1 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxLEFT + 0 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Font: + 0 + + 0 + + + 0 + + 1 + m_fontLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 3 + 1 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Default Font" "KiCad Font" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_fontCtrl + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + FONT_CHOICE; widgets/font_choice.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL + 1 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Size: + 0 + + 0 + + + 0 + + 1 + m_textSizeLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + 3 + 1 + wxALIGN_CENTER_VERTICAL + 1 + 1 + + + bSizer15 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + -1,-1 + 0 + -1,-1 + 1 + m_textSizeCtrl + 1 + + + protected + 1 + + Resizable + 1 + -1,-1 + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 3 + wxLEFT|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + 0 + + 0 + + + 0 + -1,-1 + 1 + m_textSizeUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + 5 + wxEXPAND|wxTOP + 1 + + 2 + wxBOTH + + + 5 + + fgSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 6 + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text color: + 0 + + 0 + + + 0 + + 1 + m_textColorLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panelTextColor + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxBORDER_SIMPLE|wxTAB_TRAVERSAL + + + bSizer221 + wxVERTICAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + COLOR_SWATCH + 1 + + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + -1,-1 + 1 + m_textColorSwatch + 1 + + + protected + 1 + + Resizable + + 1 + + COLOR_SWATCH; widgets/color_swatch.h; forward_declare + 0 + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Background fill: + 0 + + 0 + + + 0 + + 1 + m_fillColorLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panelFillColor + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxBORDER_SIMPLE|wxTAB_TRAVERSAL + + + bSizer22 + wxVERTICAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + COLOR_SWATCH + 1 + + + 1 + + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + + 0 + + + 0 + -1,-1 + 1 + m_fillColorSwatch + 1 + + + protected + 1 + + Resizable + + 1 + + COLOR_SWATCH; widgets/color_swatch.h; forward_declare + 0 + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bButtons + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Apply && Go to Next Cell + + 0 + + 0 + + + 0 + + 1 + m_applyButton + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnApply + + + + 10 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + (Option+Tab) + 0 + + 0 + + + 0 + + 1 + m_hotkeyHint + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND|wxALL + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + + + + + + + diff --git a/eeschema/dialogs/dialog_tablecell_properties_base.h b/eeschema/dialogs/dialog_tablecell_properties_base.h new file mode 100644 index 0000000000..1152174ec1 --- /dev/null +++ b/eeschema/dialogs/dialog_tablecell_properties_base.h @@ -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 +#include +#include +class BITMAP_BUTTON; +class COLOR_SWATCH; +class FONT_CHOICE; +class WX_INFOBAR; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// 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(); + +}; + diff --git a/eeschema/dialogs/dialog_text_properties.cpp b/eeschema/dialogs/dialog_text_properties.cpp index ede077b53f..c4803f6510 100644 --- a/eeschema/dialogs/dialog_text_properties.cpp +++ b/eeschema/dialogs/dialog_text_properties.cpp @@ -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_hAlignRight->SetIsRadioButton(); m_hAlignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) ); + m_separator3->SetIsSeparator(); m_vAlignTop->SetIsRadioButton(); diff --git a/eeschema/ee_collectors.cpp b/eeschema/ee_collectors.cpp index caf8649717..5d48bb15a8 100644 --- a/eeschema/ee_collectors.cpp +++ b/eeschema/ee_collectors.cpp @@ -40,6 +40,7 @@ const std::vector EE_COLLECTOR::EditableItems = { SCH_SHAPE_T, SCH_TEXT_T, SCH_TEXTBOX_T, + SCH_TABLECELL_T, SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, @@ -67,6 +68,8 @@ const std::vector EE_COLLECTOR::MovableItems = SCH_SHAPE_T, SCH_TEXT_T, SCH_TEXTBOX_T, + SCH_TABLE_T, + SCH_TABLECELL_T, // will be promoted to parent table(s) SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp index 01aebe90f5..bf733bab03 100644 --- a/eeschema/menubar.cpp +++ b/eeschema/menubar.cpp @@ -259,6 +259,7 @@ void SCH_EDIT_FRAME::doReCreateMenuBar() placeMenu->AppendSeparator(); placeMenu->Add( EE_ACTIONS::placeSchematicText ); placeMenu->Add( EE_ACTIONS::drawTextBox ); + placeMenu->Add( EE_ACTIONS::drawTable ); placeMenu->Add( EE_ACTIONS::drawRectangle ); placeMenu->Add( EE_ACTIONS::drawCircle ); placeMenu->Add( EE_ACTIONS::drawArc ); diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index 197966dd6f..71810e5f19 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -380,7 +380,7 @@ void SCH_BASE_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpda GetCanvas()->GetView()->Update( aItem ); // 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 ); } @@ -446,7 +446,8 @@ void SCH_BASE_FRAME::AddToScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen ) if( aScreen == nullptr ) screen = GetScreen(); - screen->Append( (SCH_ITEM*) aItem ); + if( aItem->Type() != SCH_TABLECELL_T ) + screen->Append( (SCH_ITEM*) aItem ); if( screen == GetScreen() ) { @@ -466,7 +467,8 @@ void SCH_BASE_FRAME::RemoveFromScreen( EDA_ITEM* aItem, SCH_SCREEN* aScreen ) if( screen == GetScreen() ) GetCanvas()->GetView()->Remove( aItem ); - screen->Remove( (SCH_ITEM*) aItem ); + if( aItem->Type() != SCH_TABLECELL_T ) + screen->Remove( (SCH_ITEM*) aItem ); if( screen == GetScreen() ) UpdateItem( aItem, true ); // handle any additional parent semantics diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 1c2adc4bec..86441dc1f4 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -477,6 +478,7 @@ void SCH_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new SCH_LINE_WIRE_BUS_TOOL ); m_toolManager->RegisterTool( new SCH_MOVE_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 SCH_EDITOR_CONTROL ); 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::placeSchematicText ); CURRENT_TOOL( EE_ACTIONS::drawTextBox ); + CURRENT_TOOL( EE_ACTIONS::drawTable ); CURRENT_TOOL( EE_ACTIONS::placeImage ); #undef CURRENT_TOOL diff --git a/eeschema/sch_file_versions.h b/eeschema/sch_file_versions.h index f0bf9e6391..3c9c791588 100644 --- a/eeschema/sch_file_versions.h +++ b/eeschema/sch_file_versions.h @@ -102,4 +102,5 @@ //#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 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. diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp index 5368affa9a..0e7fa0f1c2 100644 --- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp +++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -486,6 +488,10 @@ void SCH_IO_KICAD_SEXPR::Format( SCH_SHEET* aSheet ) saveTextBox( static_cast( item ), 1 ); break; + case SCH_TABLE_T: + saveTable( static_cast( item ), 1 ); + break; + default: 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, "" ); - 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() ); VECTOR2I pos = aTextBox->GetStart(); 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", EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pos.x ).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.y ).c_str() ); - aTextBox->GetStroke().Format( m_out, schIUScale, aNestLevel + 1 ); + if( SCH_TABLECELL* cell = dynamic_cast( 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 ); + m_out->Print( 0, "\n" ); + } + formatFill( m_out, aNestLevel + 1, aTextBox->GetFillMode(), aTextBox->GetFillColor() ); 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 aAlias, int aNestLevel ) { wxCHECK_RET( aAlias != nullptr, "BUS_ALIAS* is NULL" ); diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h index b34df5fd2a..3f7f95a386 100644 --- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h +++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h @@ -46,6 +46,7 @@ class SCH_SHAPE; class SCH_BUS_ENTRY_BASE; class SCH_TEXT; class SCH_TEXTBOX; +class SCH_TABLE; class SCH_SYMBOL; class SCH_FIELD; struct SCH_SYMBOL_INSTANCE; @@ -152,6 +153,7 @@ private: void saveShape( SCH_SHAPE* aShape, int aNestLevel ); void saveText( SCH_TEXT* aText, int aNestLevel ); void saveTextBox( SCH_TEXTBOX* aText, int aNestLevel ); + void saveTable( SCH_TABLE* aTable, int aNestLevel ); void saveBusAlias( std::shared_ptr aAlias, int aNestLevel ); void saveInstances( const std::vector& aSheets, int aNestLevel ); diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp index b1eb503990..707985f908 100644 --- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp +++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include #include @@ -2729,6 +2731,10 @@ void SCH_IO_KICAD_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopya screen->Append( parseSchTextBox() ); break; + case T_table: + screen->Append( parseSchTable() ); + break; + case T_sheet_instances: parseSchSheetInstances( aSheet, screen ); break; @@ -4141,6 +4147,29 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox() wxCHECK_MSG( CurTok() == T_text_box, nullptr, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a text box." ) ); + std::unique_ptr textBox = std::make_unique(); + + 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 cell = std::make_unique(); + + parseSchTextBoxContent( cell.get() ); + + return cell.release(); +} + + +void SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBoxContent( SCH_TEXTBOX* aTextBox ) +{ T token; VECTOR2I pos; VECTOR2I end; @@ -4149,11 +4178,10 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox() bool foundSize = false; STROKE_PARAMS stroke( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ), LINE_STYLE::DEFAULT ); FILL_PARAMS fill; - std::unique_ptr textBox = std::make_unique(); NeedSYMBOL(); - textBox->SetText( FromUTF8() ); + aTextBox->SetText( FromUTF8() ); for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { @@ -4165,7 +4193,7 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox() switch( token ) { case T_exclude_from_sim: - textBox->SetExcludedFromSim( parseBool() ); + aTextBox->SetExcludedFromSim( parseBool() ); NeedRIGHT(); break; @@ -4182,7 +4210,7 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox() case T_at: pos = parseXY(); - textBox->SetTextAngle( EDA_ANGLE( parseDouble( "textbox angle" ), DEGREES_T ) ); + aTextBox->SetTextAngle( EDA_ANGLE( parseDouble( "textbox angle" ), DEGREES_T ) ); NeedRIGHT(); break; @@ -4192,24 +4220,34 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox() NeedRIGHT(); break; + case T_span: + if( SCH_TABLECELL* cell = dynamic_cast( aTextBox ) ) + { + cell->SetColSpan( parseInt( "column span" ) ); + cell->SetRowSpan( parseInt( "row span" ) ); + } + + NeedRIGHT(); + break; + case T_stroke: parseStroke( stroke ); - textBox->SetStroke( stroke ); + aTextBox->SetStroke( stroke ); break; case T_fill: parseFill( fill ); - textBox->SetFillMode( fill.m_FillType ); - textBox->SetFillColor( fill.m_Color ); + aTextBox->SetFillMode( fill.m_FillType ); + aTextBox->SetFillColor( fill.m_Color ); break; case T_effects: - parseEDA_TEXT( static_cast( textBox.get() ), false ); + parseEDA_TEXT( static_cast( aTextBox ), false ); break; case T_uuid: NeedSYMBOL(); - const_cast( textBox->m_Uuid ) = KIID( FromUTF8() ); + const_cast( aTextBox->m_Uuid ) = KIID( FromUTF8() ); NeedRIGHT(); break; @@ -4218,16 +4256,150 @@ SCH_TEXTBOX* SCH_IO_KICAD_SEXPR_PARSER::parseSchTextBox() } } - textBox->SetPosition( pos ); + aTextBox->SetPosition( pos ); if( foundEnd ) - textBox->SetEnd( end ); + aTextBox->SetEnd( end ); else if( foundSize ) - textBox->SetEnd( pos + size ); + aTextBox->SetEnd( pos + size ); else 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 table = std::make_unique( 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(); } diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.h b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.h index dc05b6164c..49faa40a51 100644 --- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.h +++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.h @@ -56,6 +56,8 @@ class SCH_SHEET; class SCH_SHEET_PIN; class SCH_TEXT; class SCH_TEXTBOX; +class SCH_TABLE; +class SCH_TABLECELL; class TITLE_BLOCK; @@ -216,6 +218,9 @@ private: SCH_SHAPE* parseSchBezier(); SCH_TEXT* parseSchText(); SCH_TEXTBOX* parseSchTextBox(); + void parseSchTextBoxContent( SCH_TEXTBOX* aTextBox ); + SCH_TABLECELL* parseSchTableCell(); + SCH_TABLE* parseSchTable(); void parseBusAlias( SCH_SCREEN* aScreen ); private: diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp index ef911e047b..c9ff1f292c 100644 --- a/eeschema/sch_painter.cpp +++ b/eeschema/sch_painter.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,9 @@ void SCH_PAINTER::draw( const EDA_ITEM* aItem, int aLayer, bool aDimmed ) case SCH_TEXTBOX_T: draw( static_cast( aItem ), aLayer ); break; + case SCH_TABLE_T: + draw( static_cast( aItem ), aLayer ); + break; case SCH_LABEL_T: draw( static_cast( aItem ), aLayer ); break; @@ -432,9 +436,9 @@ COLOR4D SCH_PAINTER::getRenderColor( const EDA_ITEM* aItem, int aLayer, bool aDr { color = static_cast( 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( aItem ); + const SCH_TEXTBOX* textBox = dynamic_cast( aItem ); if( aLayer == LAYER_NOTES_BACKGROUND ) color = textBox->GetFillColor(); @@ -556,6 +560,7 @@ float SCH_PAINTER::getTextThickness( const EDA_ITEM* aItem ) const break; case SCH_TEXTBOX_T: + case SCH_TABLECELL_T: pen = static_cast( aItem )->GetEffectiveTextPenWidth( pen ); 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 ) { + if( aTextBox->Type() == SCH_TABLECELL_T ) + { + const SCH_TABLECELL* cell = static_cast( aTextBox ); + + if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 ) + return; + } + bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS; 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( aTable )->RunOnChildren( + [&]( SCH_ITEM* aChild ) + { + draw( static_cast( 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 ) { struct ORIENT diff --git a/eeschema/sch_painter.h b/eeschema/sch_painter.h index 34582a816d..9102e2722c 100644 --- a/eeschema/sch_painter.h +++ b/eeschema/sch_painter.h @@ -45,6 +45,7 @@ class SCH_JUNCTION; class SCH_LABEL; class SCH_TEXT; class SCH_TEXTBOX; +class SCH_TABLE; class SCH_HIERLABEL; class SCH_DIRECTIVE_LABEL; class SCH_GLOBALLABEL; @@ -158,6 +159,7 @@ private: void draw( const SCH_SHAPE* aShape, int aLayer ); void draw( const SCH_TEXTBOX* aTextBox, 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_DIRECTIVE_LABEL* aLabel, int aLayer ); void draw( const SCH_HIERLABEL* aLabel, int aLayer ); diff --git a/eeschema/sch_table.cpp b/eeschema/sch_table.cpp new file mode 100644 index 0000000000..6d464fbdf9 --- /dev/null +++ b/eeschema/sch_table.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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( 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( 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& 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& 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& 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( 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( 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 ); + propMgr.InheritsAfter( TYPE_HASH( SCH_TABLE ), TYPE_HASH( SCH_ITEM ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Start X" ), + &EDA_SHAPE::SetStartX, &EDA_SHAPE::GetStartX, PROPERTY_DISPLAY::PT_COORD, + ORIGIN_TRANSFORMS::ABS_X_COORD ) ); + propMgr.AddProperty( new PROPERTY( _HKI( "Start Y" ), + &EDA_SHAPE::SetStartY, &EDA_SHAPE::GetStartY, PROPERTY_DISPLAY::PT_COORD, + ORIGIN_TRANSFORMS::ABS_Y_COORD ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "External Border" ), + &SCH_TABLE::SetStrokeExternal, &SCH_TABLE::StrokeExternal ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Header Border" ), + &SCH_TABLE::SetStrokeHeader, &SCH_TABLE::StrokeHeader ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Border Width" ), + &SCH_TABLE::SetBorderWidth, &SCH_TABLE::GetBorderWidth, + PROPERTY_DISPLAY::PT_SIZE ) ); + + propMgr.AddProperty( new PROPERTY_ENUM( _HKI( "Border Style" ), + &SCH_TABLE::SetBorderStyle, &SCH_TABLE::GetBorderStyle ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Border Color" ), + &SCH_TABLE::SetBorderColor, &SCH_TABLE::GetBorderColor ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Row Separators" ), + &SCH_TABLE::SetStrokeRows, &SCH_TABLE::StrokeRows ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Cell Separators" ), + &SCH_TABLE::SetStrokeColumns, &SCH_TABLE::StrokeColumns ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Separators Width" ), + &SCH_TABLE::SetSeparatorsWidth, &SCH_TABLE::GetSeparatorsWidth, + PROPERTY_DISPLAY::PT_SIZE ) ); + + propMgr.AddProperty( new PROPERTY_ENUM( _HKI( "Separators Style" ), + &SCH_TABLE::SetSeparatorsStyle, &SCH_TABLE::GetSeparatorsStyle ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Separators Color" ), + &SCH_TABLE::SetSeparatorsColor, &SCH_TABLE::GetSeparatorsColor ) ); + } +} _SCH_TABLE_DESC; diff --git a/eeschema/sch_table.h b/eeschema/sch_table.h new file mode 100644 index 0000000000..d0e70faf55 --- /dev/null +++ b/eeschema/sch_table.h @@ -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 +#include + + +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& 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 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& 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& 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 m_colWidths; + std::map m_rowHeights; + std::vector m_cells; +}; + + +#endif /* SCH_TABLE_H */ diff --git a/eeschema/sch_tablecell.cpp b/eeschema/sch_tablecell.cpp new file mode 100644 index 0000000000..64da3414da --- /dev/null +++ b/eeschema/sch_tablecell.cpp @@ -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 +#include +#include +#include +#include +#include + +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( 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( 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( 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& 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 ); + propMgr.AddTypeCast( new TYPE_CAST ); + propMgr.AddTypeCast( new TYPE_CAST ); + propMgr.AddTypeCast( new TYPE_CAST ); + 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; diff --git a/eeschema/sch_tablecell.h b/eeschema/sch_tablecell.h new file mode 100644 index 0000000000..fb33909d4a --- /dev/null +++ b/eeschema/sch_tablecell.h @@ -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 + + +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& aList ) override; + +protected: + int m_colSpan; + int m_rowSpan; +}; + + +#endif /* SCH_TABLECELL_H */ diff --git a/eeschema/sch_textbox.cpp b/eeschema/sch_textbox.cpp index ea852e276a..ce4758728b 100644 --- a/eeschema/sch_textbox.cpp +++ b/eeschema/sch_textbox.cpp @@ -43,8 +43,8 @@ using KIGFX::SCH_RENDER_SETTINGS; -SCH_TEXTBOX::SCH_TEXTBOX( int aLineWidth, FILL_T aFillType, const wxString& text ) : - SCH_SHAPE( SHAPE_T::RECTANGLE, aLineWidth, aFillType, SCH_TEXTBOX_T ), +SCH_TEXTBOX::SCH_TEXTBOX( int aLineWidth, FILL_T aFillType, const wxString& text, KICAD_T aType ) : + SCH_SHAPE( SHAPE_T::RECTANGLE, aLineWidth, aFillType, aType ), EDA_TEXT( schIUScale, text ) { m_layer = LAYER_NOTES; diff --git a/eeschema/sch_textbox.h b/eeschema/sch_textbox.h index b595b46509..83a111421a 100644 --- a/eeschema/sch_textbox.h +++ b/eeschema/sch_textbox.h @@ -36,7 +36,7 @@ class SCH_TEXTBOX : public SCH_SHAPE, public EDA_TEXT { public: 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 ); diff --git a/eeschema/schematic.keywords b/eeschema/schematic.keywords index 1b27293f3b..955ce4c386 100644 --- a/eeschema/schematic.keywords +++ b/eeschema/schematic.keywords @@ -9,15 +9,20 @@ bezier bidirectional bitmap bold +border bottom bus bus_alias bus_entry +cells center circle clock clock_low color +cols +column_count +column_widths comment company convert @@ -35,6 +40,7 @@ edge_clock_high effects end extends +external exclude_from_sim face fields_autoplaced @@ -45,6 +51,7 @@ free generator generator_version global_label +header hide hierarchical_label hint_alt_swap @@ -118,16 +125,22 @@ required rev right round +rows +row_heights scale +separators shape sheet sheet_instances show_name size +span start stroke symbol symbol_instances +table +table_cell text text_box thickness diff --git a/eeschema/schematic_undo_redo.cpp b/eeschema/schematic_undo_redo.cpp index f5e572e171..624acf2f73 100644 --- a/eeschema/schematic_undo_redo.cpp +++ b/eeschema/schematic_undo_redo.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -268,6 +269,7 @@ void SCH_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList ) std::vector bulkAddedItems; std::vector bulkRemovedItems; std::vector bulkChangedItems; + std::set changedTables; bool dirtyConnectivity = false; SCH_CLEANUP_FLAGS connectivityCleanUp = NO_CLEANUP; diff --git a/eeschema/toolbars_sch_editor.cpp b/eeschema/toolbars_sch_editor.cpp index 512c9f6bc6..05332b492f 100644 --- a/eeschema/toolbars_sch_editor.cpp +++ b/eeschema/toolbars_sch_editor.cpp @@ -168,6 +168,7 @@ void SCH_EDIT_FRAME::ReCreateVToolbar() m_drawToolBar->AddScaledSeparator( this ); m_drawToolBar->Add( EE_ACTIONS::placeSchematicText, 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::drawCircle, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( EE_ACTIONS::drawArc, ACTION_TOOLBAR::TOGGLE ); diff --git a/eeschema/tools/ee_actions.cpp b/eeschema/tools/ee_actions.cpp index 5794c21c68..afa4282c25 100644 --- a/eeschema/tools/ee_actions.cpp +++ b/eeschema/tools/ee_actions.cpp @@ -145,6 +145,82 @@ TOOL_ACTION EE_ACTIONS::syncSelection( TOOL_ACTION_ARGS() .Name( "eeschema.InteractiveSelection.SyncSelection" ) .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 // @@ -521,6 +597,14 @@ TOOL_ACTION EE_ACTIONS::drawTextBox( TOOL_ACTION_ARGS() .Flags( AF_ACTIVATE ) .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() .Name( "eeschema.InteractiveDrawing.drawRectangle" ) .Scope( AS_GLOBAL ) diff --git a/eeschema/tools/ee_actions.h b/eeschema/tools/ee_actions.h index c3bceeef5d..2b9966a58e 100644 --- a/eeschema/tools/ee_actions.h +++ b/eeschema/tools/ee_actions.h @@ -69,6 +69,19 @@ public: /// Selection synchronization (PCB -> SCH) 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 static TOOL_ACTION toggleLock; static TOOL_ACTION lock; @@ -92,6 +105,7 @@ public: static TOOL_ACTION importSheetPin; static TOOL_ACTION placeSchematicText; static TOOL_ACTION drawTextBox; + static TOOL_ACTION drawTable; static TOOL_ACTION drawRectangle; static TOOL_ACTION drawCircle; static TOOL_ACTION drawArc; diff --git a/eeschema/tools/ee_grid_helper.cpp b/eeschema/tools/ee_grid_helper.cpp index 4b8f2de7e3..bb22b76baf 100644 --- a/eeschema/tools/ee_grid_helper.cpp +++ b/eeschema/tools/ee_grid_helper.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -416,7 +418,6 @@ void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, b switch( aItem->Type() ) { case SCH_TEXT_T: - case SCH_TEXTBOX_T: case SCH_FIELD_T: { if( aIncludeText ) @@ -425,6 +426,29 @@ void EE_GRID_HELPER::computeAnchors( SCH_ITEM *aItem, const VECTOR2I &aRefPos, b break; } + case SCH_TABLE_T: + { + if( aIncludeText ) + { + addAnchor( aItem->GetPosition(), SNAPPABLE | CORNER, aItem ); + addAnchor( static_cast( 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( aItem )->GetEnd(), SNAPPABLE | CORNER, aItem ); + } + + break; + } + case SCH_SYMBOL_T: case SCH_SHEET_T: addAnchor( aItem->GetPosition(), ORIGIN, aItem ); diff --git a/eeschema/tools/ee_point_editor.cpp b/eeschema/tools/ee_point_editor.cpp index 0a029022be..16ed857820 100644 --- a/eeschema/tools/ee_point_editor.cpp +++ b/eeschema/tools/ee_point_editor.cpp @@ -39,6 +39,8 @@ using namespace std::placeholders; #include #include #include +#include +#include #include #include #include @@ -70,6 +72,10 @@ enum RECTANGLE_LINES RECT_TOP, RECT_RIGHT, RECT_BOT, RECT_LEFT }; +enum TABLECELL_POINTS +{ + COL_WIDTH, ROW_HEIGHT +}; enum LINE_POINTS { @@ -273,6 +279,14 @@ public: break; } + case SCH_TABLECELL_T: + { + SCH_TABLECELL* cell = static_cast( aItem ); + points->AddPoint( cell->GetEnd() - VECTOR2I( 0, cell->GetRectangleHeight() / 2 ) ); + points->AddPoint( cell->GetEnd() - VECTOR2I( cell->GetRectangleWidth() / 2, 0 ) ); + break; + } + case SCH_SHEET_T: { 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, LIB_TEXTBOX_T, SCH_TEXTBOX_T, + SCH_TABLECELL_T, SCH_SHEET_T, SCH_ITEM_LOCATE_GRAPHIC_LINE_T, SCH_BITMAP_T } ) ) @@ -516,6 +531,13 @@ int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent ) if( connected.first ) commit.Modify( connected.first, m_frame->GetScreen() ); } + else if( m_editPoints->GetParent()->Type() == SCH_TABLECELL_T ) + { + SCH_TABLECELL* cell = static_cast( m_editPoints->GetParent() ); + SCH_TABLE* table = static_cast( cell->GetParent() ); + + commit.Modify( table, m_frame->GetScreen() ); + } inDrag = true; } @@ -1016,6 +1038,39 @@ void EE_POINT_EDITOR::updateParentItem( bool aSnapToGrid ) const break; } + case SCH_TABLECELL_T: + { + SCH_TABLECELL* cell = static_cast( item ); + SCH_TABLE* table = static_cast( 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: { EE_GRID_HELPER gridHelper( m_toolMgr ); @@ -1350,6 +1405,17 @@ void EE_POINT_EDITOR::updatePoints() break; } + case SCH_TABLECELL_T: + { + SCH_TABLECELL* cell = static_cast( 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: { SCH_BITMAP* bitmap = (SCH_BITMAP*) item; diff --git a/eeschema/tools/ee_selection_tool.cpp b/eeschema/tools/ee_selection_tool.cpp index 6b0398a599..ada738ba83 100644 --- a/eeschema/tools/ee_selection_tool.cpp +++ b/eeschema/tools/ee_selection_tool.cpp @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include #include #include @@ -216,8 +218,8 @@ bool EE_SELECTION_TOOL::Init() SCH_ITEM_LOCATE_BUS_T } ); auto connectedSelection = E_C::Count( 1 ) && E_C::OnlyTypes( connectedTypes ); auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyTypes( { SCH_SHEET_T } ); - auto crossProbingSelection = E_C::MoreThan( 0 ) && - E_C::HasTypes( { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T } ); + auto crossProbingSelection = E_C::MoreThan( 0 ) && 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 = [&] ( const SELECTION& aSel ) @@ -278,6 +280,10 @@ bool EE_SELECTION_TOOL::Init() menu.AddItem( EE_ACTIONS::clearHighlight, 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.AddItem( EE_ACTIONS::drawWire, 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.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::placeLabel, 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( m_frame ) ) 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( collector[0]->GetParent() ) ); + } + else if( hasModifier() || drag_action == MOUSE_DRAG_ACTION::SELECT ) { selectMultiple(); } @@ -1310,6 +1321,7 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const SCH_LINE* line = dynamic_cast( item ); LIB_SHAPE* shape = dynamic_cast( item ); SCH_SYMBOL* symbol = dynamic_cast( item ); + SCH_TABLE* table = dynamic_cast( item ); // Lines are hard to hit. Give them a bit more slop to still be considered "exact". 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 ) ) exactHits.insert( item ); } + else if( table ) + { + // Consider table cells exact, but not the table itself + } else { 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& aScanTypes ) +EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector& aScanTypes, + bool aPromoteCellSelections ) { + bool anyUnselected = false; + bool anySelected = false; + if( m_selection.Empty() ) { VECTOR2D cursorPos = getViewControls()->GetCursorPosition( true ); @@ -1482,7 +1502,6 @@ EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector& a else // Trim an existing selection by aFilterList { bool isMoving = false; - bool anyUnselected = false; for( int i = (int) m_selection.GetSize() - 1; i >= 0; --i ) { @@ -1496,13 +1515,42 @@ EE_SELECTION& EE_SELECTION_TOOL::RequestSelection( const std::vector& a } } - if( anyUnselected ) - m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); - if( !isMoving ) updateReferencePoint(); } + if( aPromoteCellSelections ) + { + std::set 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; } @@ -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 ) { 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> columns; + bool added = false; + + for( EDA_ITEM* item : m_selection ) + { + if( SCH_TABLECELL* cell = dynamic_cast( item ) ) + { + SCH_TABLE* table = static_cast( 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> rows; + bool added = false; + + for( EDA_ITEM* item : m_selection ) + { + if( SCH_TABLECELL* cell = dynamic_cast( item ) ) + { + SCH_TABLE* table = static_cast( 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 tables; + bool added = false; + + for( EDA_ITEM* item : m_selection ) + { + if( SCH_TABLECELL* cell = dynamic_cast( item ) ) + tables.insert( static_cast( 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 ) { ClearSelection(); @@ -2115,7 +2368,7 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos, case LIB_PIN_T: if( symEditFrame ) { - LIB_ITEM* lib_item = (LIB_ITEM*) aItem; + const LIB_ITEM* lib_item = static_cast( aItem ); if( lib_item->GetUnit() && lib_item->GetUnit() != symEditFrame->GetUnit() ) return false; @@ -2129,6 +2382,16 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos, case SCH_MARKER_T: // Always selectable return true; + case SCH_TABLECELL_T: + { + const SCH_TABLECELL* cell = static_cast( aItem ); + + if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 ) + return false; + + break; + } + default: // Suppress warnings 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 ) { - KICAD_T itemType = aItem->Type(); - if( aMode == SELECTED ) aItem->SetSelected(); else if( aMode == BRIGHTENED ) @@ -2202,7 +2463,7 @@ void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGroup if( aGroup && aMode != BRIGHTENED ) 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 ); else 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 ) { - KICAD_T itemType = aItem->Type(); - if( aMode == SELECTED ) { 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 ); else 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::SelectNode, EE_ACTIONS::selectNode.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::AddItemToSel, EE_ACTIONS::addItemToSel.MakeEvent() ); diff --git a/eeschema/tools/ee_selection_tool.h b/eeschema/tools/ee_selection_tool.h index baa796697b..f620a8cb1e 100644 --- a/eeschema/tools/ee_selection_tool.h +++ b/eeschema/tools/ee_selection_tool.h @@ -35,6 +35,7 @@ class SCH_BASE_FRAME; class SCH_ITEM; +class SCH_TABLE; class EE_GRID_HELPER; namespace KIGFX @@ -91,7 +92,8 @@ public: * @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. */ - EE_SELECTION& RequestSelection( const std::vector& aScanTypes = { SCH_LOCATE_ANY_T } ); + EE_SELECTION& RequestSelection( const std::vector& aScanTypes = { SCH_LOCATE_ANY_T }, + bool aPromoteCellSelections = false ); /** * Perform a click-type selection at a point (usually the cursor position). @@ -135,6 +137,10 @@ public: */ 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. int ClearSelection( const TOOL_EVENT& aEvent ); @@ -228,6 +234,13 @@ private: */ 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. */ diff --git a/eeschema/tools/ee_tool_base.h b/eeschema/tools/ee_tool_base.h index 2a365e588d..0a98196349 100644 --- a/eeschema/tools/ee_tool_base.h +++ b/eeschema/tools/ee_tool_base.h @@ -119,6 +119,7 @@ protected: case SCH_PIN_T: case SCH_FIELD_T: + case SCH_TABLECELL_T: getView()->Update( aItem ); getView()->Update( aItem->GetParent() ); @@ -132,6 +133,8 @@ protected: if( aUpdateRTree && dynamic_cast( aItem ) ) m_frame->GetScreen()->Update( static_cast( aItem ) ); + + break; } } diff --git a/eeschema/tools/sch_drawing_tools.cpp b/eeschema/tools/sch_drawing_tools.cpp index 9b6985c84f..1f2cde2ec6 100644 --- a/eeschema/tools/sch_drawing_tools.cpp +++ b/eeschema/tools/sch_drawing_tools.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include #include @@ -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(); + 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 ) { 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::drawArc.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::ImportGraphics, EE_ACTIONS::importGraphics.MakeEvent() ); } diff --git a/eeschema/tools/sch_drawing_tools.h b/eeschema/tools/sch_drawing_tools.h index 2211552e76..2f738d3a39 100644 --- a/eeschema/tools/sch_drawing_tools.h +++ b/eeschema/tools/sch_drawing_tools.h @@ -53,6 +53,7 @@ public: int SingleClickPlace( const TOOL_EVENT& aEvent ); int TwoClickPlace( const TOOL_EVENT& aEvent ); int DrawShape( const TOOL_EVENT& aEvent ); + int DrawTable( const TOOL_EVENT& aEvent ); int DrawSheet( const TOOL_EVENT& aEvent ); int PlaceImage( const TOOL_EVENT& aEvent ); int ImportGraphics( const TOOL_EVENT& aEvent ); diff --git a/eeschema/tools/sch_edit_table_tool.cpp b/eeschema/tools/sch_edit_table_tool.cpp new file mode 100644 index 0000000000..e522bc5edc --- /dev/null +++ b/eeschema/tools/sch_edit_table_tool.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +SCH_EDIT_TABLE_TOOL::SCH_EDIT_TABLE_TOOL() : + EE_TOOL_BASE( "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::max(); + int colMax = 0; + int rowMin = std::numeric_limits::max(); + int rowMax = 0; + int selectedArea = 0; + + for( EDA_ITEM* item : sel ) + { + wxCHECK2( item->Type() == SCH_TABLECELL_T, continue ); + + SCH_TABLECELL* cell = static_cast( 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( 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( item ); + + if( !topmost || cell->GetRow() < topmost->GetRow() ) + topmost = cell; + } + + if( !topmost ) + return 0; + + int row = topmost->GetRow(); + SCH_TABLE* table = static_cast( topmost->GetParent() ); + SCH_COMMIT commit( m_toolMgr ); + + // Make a copy of the source row before things start moving around + std::vector 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( item ); + + if( !bottommost || cell->GetRow() > bottommost->GetRow() ) + bottommost = cell; + } + + if( !bottommost ) + return 0; + + int row = bottommost->GetRow(); + SCH_TABLE* table = static_cast( bottommost->GetParent() ); + SCH_COMMIT commit( m_toolMgr ); + + // Make a copy of the source row before things start moving around + std::vector 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( item ); + + if( !leftmost || cell->GetColumn() < leftmost->GetColumn() ) + leftmost = cell; + } + + if( !leftmost ) + return 0; + + int col = leftmost->GetColumn(); + SCH_TABLE* table = static_cast( 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 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( item ); + + if( !rightmost || cell->GetColumn() > rightmost->GetColumn() ) + rightmost = cell; + } + + if( !rightmost ) + return 0; + + int col = rightmost->GetColumn(); + SCH_TABLE* table = static_cast( 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 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( 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( 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::max(); + int colMax = 0; + int rowMin = std::numeric_limits::max(); + int rowMax = 0; + + SCH_COMMIT commit( m_toolMgr ); + SCH_TABLE* table = static_cast( sel[0]->GetParent() ); + + for( EDA_ITEM* item : sel ) + { + wxCHECK2( item->Type() == SCH_TABLECELL_T, continue ); + + SCH_TABLECELL* cell = static_cast( 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( sel[0]->GetParent() ); + + for( EDA_ITEM* item : sel ) + { + wxCHECK2( item->Type() == SCH_TABLECELL_T, continue ); + + SCH_TABLECELL* cell = static_cast( 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() ); +} diff --git a/eeschema/tools/sch_edit_table_tool.h b/eeschema/tools/sch_edit_table_tool.h new file mode 100644 index 0000000000..ba5bebd360 --- /dev/null +++ b/eeschema/tools/sch_edit_table_tool.h @@ -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 + + +class SCH_EDIT_FRAME; + + +class SCH_EDIT_TABLE_TOOL : public EE_TOOL_BASE +{ +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 diff --git a/eeschema/tools/sch_edit_tool.cpp b/eeschema/tools/sch_edit_tool.cpp index feef497b03..6f475d6b5f 100644 --- a/eeschema/tools/sch_edit_tool.cpp +++ b/eeschema/tools/sch_edit_tool.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -60,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -301,6 +304,8 @@ bool SCH_EDIT_TOOL::Init() case SCH_SHEET_PIN_T: case SCH_TEXT_T: case SCH_TEXTBOX_T: + case SCH_TABLE_T: + case SCH_TABLECELL_T: case SCH_LABEL_T: case SCH_GLOBAL_LABEL_T: case SCH_HIER_LABEL_T: @@ -612,6 +617,8 @@ const std::vector SCH_EDIT_TOOL::RotatableItems = { SCH_SHAPE_T, SCH_TEXT_T, SCH_TEXTBOX_T, + SCH_TABLE_T, + SCH_TABLECELL_T, // will be promoted to parent table(s) SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, @@ -632,7 +639,7 @@ const std::vector SCH_EDIT_TOOL::RotatableItems = { int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) { 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 ) return 0; @@ -768,6 +775,19 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) break; + case SCH_TABLE_T: + { + // Rotate the table on itself. Tables do not have an anchor point. + SCH_TABLE* table = static_cast( 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: for( int i = 0; clockwise ? i < 3 : i < 1; ++i ) head->Rotate( rotPoint ); @@ -778,10 +798,10 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) case SCH_SHEET_T: { + // Rotate the sheet on itself. Sheets do not have an anchor point. SCH_SHEET* sheet = static_cast( head ); 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 ) sheet->Rotate( rotPoint ); @@ -1344,6 +1364,8 @@ static std::vector deletableItems = SCH_SHAPE_T, SCH_TEXT_T, SCH_TEXTBOX_T, + SCH_TABLECELL_T, // Clear contents + SCH_TABLE_T, SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, @@ -1352,7 +1374,7 @@ static std::vector deletableItems = SCH_SHEET_T, SCH_SHEET_PIN_T, SCH_SYMBOL_T, - SCH_FIELD_T, // Will be hidden + SCH_FIELD_T, // Will be hidden SCH_BITMAP_T }; @@ -1408,6 +1430,11 @@ int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent ) commit.Modify( item, m_frame->GetScreen() ); static_cast( sch_item )->SetVisible( false ); } + else if( sch_item->Type() == SCH_TABLECELL_T ) + { + commit.Modify( item, m_frame->GetScreen() ); + static_cast( sch_item )->SetText( wxEmptyString ); + } else { 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 if( dlg.ShowQuasiModal() == wxID_OK ) m_frame->OnModify(); - } + break; + } + + case SCH_TABLECELL_T: + { + DIALOG_TABLECELL_PROPERTIES dlg( m_frame, static_cast( curr_item ) ); + + if( dlg.ShowModal() == wxID_OK ) + m_frame->OnModify(); + + break; + } case SCH_LABEL_T: case SCH_GLOBAL_LABEL_T: diff --git a/eeschema/tools/sch_move_tool.cpp b/eeschema/tools/sch_move_tool.cpp index 8446156654..200c4bab01 100644 --- a/eeschema/tools/sch_move_tool.cpp +++ b/eeschema/tools/sch_move_tool.cpp @@ -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 // 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(); // Keep an original copy of the starting points for cleanup after the move diff --git a/include/core/typeinfo.h b/include/core/typeinfo.h index 2cf2f5718b..2ee1398a13 100644 --- a/include/core/typeinfo.h +++ b/include/core/typeinfo.h @@ -148,6 +148,8 @@ enum KICAD_T SCH_BITMAP_T, SCH_TEXTBOX_T, SCH_TEXT_T, + SCH_TABLE_T, + SCH_TABLECELL_T, SCH_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, @@ -382,6 +384,8 @@ constexpr bool IsEeschemaType( const KICAD_T aType ) case SCH_BITMAP_T: case SCH_TEXT_T: case SCH_TEXTBOX_T: + case SCH_TABLE_T: + case SCH_TABLECELL_T: case SCH_LABEL_T: case SCH_DIRECTIVE_LABEL_T: case SCH_GLOBAL_LABEL_T: diff --git a/include/scintilla_tricks.h b/include/scintilla_tricks.h index b5dd771f95..ad40fae448 100644 --- a/include/scintilla_tricks.h +++ b/include/scintilla_tricks.h @@ -58,7 +58,7 @@ protected: int firstNonWhitespace( int aLine, int* aWhitespaceCount = nullptr ); - void onCharHook( wxKeyEvent& aEvent ); + virtual void onCharHook( wxKeyEvent& aEvent ); void onChar( wxStyledTextEvent& aEvent ); void onModified( wxStyledTextEvent& aEvent ); void onScintillaUpdateUI( wxStyledTextEvent& aEvent );