From 7e561acf5373038a7151a3efa852e2b3d6b1d26c Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Sun, 16 Jun 2024 17:14:31 -0700 Subject: [PATCH] Altium: Handle textboxes Also, corrects a minor issue with the text width calculation where Altium calculates centerline to centerline but KiCad text heights are to the edge of the stroke font. Need to still do better adjustments for the various altium stroke fonts Fixes https://gitlab.com/kicad/code/kicad/-/issues/9468 --- pcbnew/pcb_io/altium/altium_parser_pcb.cpp | 11 +- pcbnew/pcb_io/altium/altium_parser_pcb.h | 8 +- pcbnew/pcb_io/altium/altium_pcb.cpp | 174 ++++++++++++++++++--- 3 files changed, 160 insertions(+), 33 deletions(-) diff --git a/pcbnew/pcb_io/altium/altium_parser_pcb.cpp b/pcbnew/pcb_io/altium/altium_parser_pcb.cpp index c644c82f29..8f7630b419 100644 --- a/pcbnew/pcb_io/altium/altium_parser_pcb.cpp +++ b/pcbnew/pcb_io/altium/altium_parser_pcb.cpp @@ -1040,14 +1040,13 @@ ATEXT6::ATEXT6( ALTIUM_BINARY_PARSER& aReader, std::map& aSt widestring_index = aReader.Read(); aReader.Skip( 4 ); - // An inverted rect in Altium is like a text box with the text inverted. The box has a defined - // width and height, justification and offet (indent). This is not currently supported in KiCad. + // An inverted rect in Altium is like a text box with the text inverted. isInvertedRect = aReader.Read() != 0; - inverted_rect_width = aReader.ReadKicadUnit(); - inverted_rect_height = aReader.ReadKicadUnit(); - inverted_rect_justification = static_cast( aReader.Read() ); - inverted_rect_offset = aReader.ReadKicadUnit(); + textbox_rect_width = aReader.ReadKicadUnit(); + textbox_rect_height = aReader.ReadKicadUnit(); + textbox_rect_justification = static_cast( aReader.Read() ); + textbox_rect_offset = aReader.ReadKicadUnit(); aReader.SkipSubrecord(); // Subrecord 2 - Legacy 8bit string, max 255 chars, unknown codepage diff --git a/pcbnew/pcb_io/altium/altium_parser_pcb.h b/pcbnew/pcb_io/altium/altium_parser_pcb.h index 1066fc45a3..e5dcfd4929 100644 --- a/pcbnew/pcb_io/altium/altium_parser_pcb.h +++ b/pcbnew/pcb_io/altium/altium_parser_pcb.h @@ -741,13 +741,13 @@ struct ATEXT6 bool isInverted; bool isInvertedRect; uint32_t inverted_borderwidth; - uint32_t inverted_rect_width; - uint32_t inverted_rect_height; - uint32_t inverted_rect_offset; + uint32_t textbox_rect_width; + uint32_t textbox_rect_height; + uint32_t textbox_rect_offset; // Justification only applies when there is a text box size specified // Then, the text is justified within the box - ALTIUM_TEXT_POSITION inverted_rect_justification; + ALTIUM_TEXT_POSITION textbox_rect_justification; uint32_t widestring_index; diff --git a/pcbnew/pcb_io/altium/altium_pcb.cpp b/pcbnew/pcb_io/altium/altium_pcb.cpp index b33f6675a3..7ad1de0e80 100644 --- a/pcbnew/pcb_io/altium/altium_pcb.cpp +++ b/pcbnew/pcb_io/altium/altium_pcb.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -4072,43 +4073,115 @@ void ALTIUM_PCB::ConvertTexts6ToFootprintItem( FOOTPRINT* aFootprint, const ATEX void ALTIUM_PCB::ConvertTexts6ToBoardItemOnLayer( const ATEXT6& aElem, PCB_LAYER_ID aLayer ) { + std::unique_ptr pcbTextbox = std::make_unique( m_board ); std::unique_ptr pcbText = std::make_unique( m_board ); + bool isTextbox = ( aElem.textbox_rect_height != 0 ); static const std::map variableMap = { { "LAYER_NAME", "LAYER" }, { "PRINT_DATE", "CURRENT_DATE"}, }; - wxString kicadText = AltiumPcbSpecialStringsToKiCadStrings( aElem.text, variableMap ); + wxString kicadText = AltiumPcbSpecialStringsToKiCadStrings( aElem.text, variableMap ); + BOARD_ITEM* item = pcbText.get(); + EDA_TEXT* text = pcbText.get(); - pcbText->SetText(kicadText); - pcbText->SetLayer( aLayer ); - pcbText->SetPosition( aElem.position ); - pcbText->SetIsKnockout( aElem.isInverted ); + if( isTextbox ) + { + // Altium textboxes do not have borders + pcbTextbox->SetBorderEnabled( false ); - ConvertTexts6ToEdaTextSettings( aElem, *pcbText ); + item = pcbTextbox.get(); + text = pcbTextbox.get(); + pcbTextbox->SetPosition( aElem.position ); + pcbTextbox->SetRectangleHeight( -aElem.textbox_rect_height ); + pcbTextbox->SetRectangleWidth( aElem.textbox_rect_width ); - m_board->Add( pcbText.release(), ADD_MODE::APPEND ); + switch( aElem.textbox_rect_justification ) + { + case ALTIUM_TEXT_POSITION::LEFT_TOP: + case ALTIUM_TEXT_POSITION::LEFT_CENTER: + case ALTIUM_TEXT_POSITION::LEFT_BOTTOM: + pcbTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + pcbTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + case ALTIUM_TEXT_POSITION::CENTER_TOP: + case ALTIUM_TEXT_POSITION::CENTER_CENTER: + case ALTIUM_TEXT_POSITION::CENTER_BOTTOM: + pcbTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER ); + pcbTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + case ALTIUM_TEXT_POSITION::RIGHT_TOP: + case ALTIUM_TEXT_POSITION::RIGHT_CENTER: + case ALTIUM_TEXT_POSITION::RIGHT_BOTTOM: + pcbTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); + pcbTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + default: + if( m_reporter ) + { + wxString msg; + msg.Printf( _( "Unknown textbox justification %d, text %s" ), + aElem.textbox_rect_justification, aElem.text ); + m_reporter->Report( msg, RPT_SEVERITY_DEBUG ); + } + + pcbTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + pcbTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + } + + } + else + { + pcbText->SetPosition( aElem.position ); + pcbText->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + pcbText->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM ); + } + + text->SetText(kicadText); + item->SetLayer( aLayer ); + item->SetIsKnockout( aElem.isInverted ); + + ConvertTexts6ToEdaTextSettings( aElem, *text ); + + if( isTextbox ) + m_board->Add( pcbTextbox.release(), ADD_MODE::APPEND ); + else + m_board->Add( pcbText.release(), ADD_MODE::APPEND ); } void ALTIUM_PCB::ConvertTexts6ToFootprintItemOnLayer( FOOTPRINT* aFootprint, const ATEXT6& aElem, PCB_LAYER_ID aLayer ) { - PCB_TEXT* fpText; + std::unique_ptr fpTextbox = std::make_unique( aFootprint ); + std::unique_ptr fpText = std::make_unique( aFootprint ); + + BOARD_ITEM* item = fpText.get(); + EDA_TEXT* text = fpText.get(); + PCB_FIELD* field = nullptr; + + bool isTextbox = ( aElem.textbox_rect_height != 0 ); + bool toAdd = false; if( aElem.isDesignator ) { - fpText = &aFootprint->Reference(); // TODO: handle multiple layers + item = &aFootprint->Reference(); // TODO: handle multiple layers + text = &aFootprint->Reference(); + field = &aFootprint->Reference(); } else if( aElem.isComment ) { - fpText = &aFootprint->Value(); // TODO: handle multiple layers + item = &aFootprint->Value(); // TODO: handle multiple layers + text = &aFootprint->Value(); + field = &aFootprint->Value(); } else { - fpText = new PCB_TEXT( aFootprint ); - aFootprint->Add( fpText, ADD_MODE::APPEND ); + item = fpText.get(); + text = fpText.get(); + toAdd = true; } static const std::map variableMap = { @@ -4121,19 +4194,78 @@ void ALTIUM_PCB::ConvertTexts6ToFootprintItemOnLayer( FOOTPRINT* aFootprint, con wxString kicadText = AltiumPcbSpecialStringsToKiCadStrings( aElem.text, variableMap ); - fpText->SetText(kicadText); - fpText->SetKeepUpright( false ); - fpText->SetLayer( aLayer ); - fpText->SetPosition( aElem.position ); - fpText->SetIsKnockout( aElem.isInverted ); + text->SetText(kicadText); + text->SetKeepUpright( false ); + item->SetLayer( aLayer ); + item->SetIsKnockout( aElem.isInverted ); - ConvertTexts6ToEdaTextSettings( aElem, *fpText ); + if( isTextbox ) + { + item = fpTextbox.get(); + text = fpTextbox.get(); + fpTextbox->SetPosition( aElem.position ); + fpTextbox->SetRectangleHeight( aElem.textbox_rect_height ); + fpTextbox->SetRectangleWidth( aElem.textbox_rect_width ); + + // KiCad only does top alignment for textboxes atm + switch( aElem.textbox_rect_justification ) + { + case ALTIUM_TEXT_POSITION::LEFT_TOP: + case ALTIUM_TEXT_POSITION::LEFT_CENTER: + case ALTIUM_TEXT_POSITION::LEFT_BOTTOM: + fpTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + fpTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + case ALTIUM_TEXT_POSITION::CENTER_TOP: + case ALTIUM_TEXT_POSITION::CENTER_CENTER: + case ALTIUM_TEXT_POSITION::CENTER_BOTTOM: + fpTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER ); + fpTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + case ALTIUM_TEXT_POSITION::RIGHT_TOP: + case ALTIUM_TEXT_POSITION::RIGHT_CENTER: + case ALTIUM_TEXT_POSITION::RIGHT_BOTTOM: + fpTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); + fpTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + default: + if( m_reporter ) + { + wxString msg; + msg.Printf( _( "Unknown textbox justification %d, text %s" ), + aElem.textbox_rect_justification, aElem.text ); + m_reporter->Report( msg, RPT_SEVERITY_DEBUG ); + } + + fpTextbox->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + fpTextbox->SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + break; + } + + } + else + { + field->SetPosition( aElem.position ); + } + + ConvertTexts6ToEdaTextSettings( aElem, *text ); + + if( toAdd ) + { + if( isTextbox ) + aFootprint->Add( fpTextbox.release(), ADD_MODE::APPEND ); + else + aFootprint->Add( fpText.release(), ADD_MODE::APPEND ); + } } void ALTIUM_PCB::ConvertTexts6ToEdaTextSettings( const ATEXT6& aElem, EDA_TEXT& aEdaText ) { - aEdaText.SetTextSize( VECTOR2I( aElem.height, aElem.height ) ); // TODO: parse text width + // Altium counts the width of the text from the centerline of each stroke while KiCad measures + // it to the outside of the stroke. TODO: need to adjust this based on the stroke font. Altium Default is + // definitely wider than the sans serif font. + aEdaText.SetTextSize( VECTOR2I( aElem.height, aElem.height + aElem.strokewidth ) ); if( aElem.fonttype == ALTIUM_TEXT_TYPE::TRUETYPE ) { @@ -4155,10 +4287,6 @@ void ALTIUM_PCB::ConvertTexts6ToEdaTextSettings( const ATEXT6& aElem, EDA_TEXT& aEdaText.SetItalic( aElem.isItalic ); aEdaText.SetMirrored( aElem.isMirrored ); aEdaText.SetTextAngle( EDA_ANGLE( aElem.rotation, DEGREES_T ) ); - - aEdaText.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); - aEdaText.SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM ); - }