diff --git a/3d-viewer/3d_canvas/board_adapter.h b/3d-viewer/3d_canvas/board_adapter.h index 8a0d7ab3b9..b00b7d892b 100644 --- a/3d-viewer/3d_canvas/board_adapter.h +++ b/3d-viewer/3d_canvas/board_adapter.h @@ -479,18 +479,21 @@ private: void addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayerId ); - void addShape( const PCB_TEXT* aText, CONTAINER_2D_BASE* aDstContainer ); + void addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aDstContainer, + const BOARD_ITEM* aOwner ); - void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstContainer ); + void addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer, + const BOARD_ITEM* aOwner ); - void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer ); + void addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aDstContainer, + const BOARD_ITEM* aOwner ); - void addSolidAreasShapes( const ZONE* aZoneContainer, CONTAINER_2D_BASE* aDstContainer, + void addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayerId ); void transformArcToSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart, const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount, int aWidth, - CONTAINER_2D_BASE* aDstContainer, const BOARD_ITEM& aBoardItem ); + CONTAINER_2D_BASE* aDstContainer, const BOARD_ITEM& aOwner ); void buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer, int aWidth ); diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index c344dab757..a87648e3b4 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -34,6 +34,7 @@ #include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h" #include "../3d_rendering/raytracing/shapes2D/round_segment_2d.h" #include "../3d_rendering/raytracing/shapes2D/triangle_2d.h" +#include "fp_textbox.h" #include #include #include @@ -55,42 +56,49 @@ #include #include -void BOARD_ADAPTER::addShape( const PCB_TEXT* aText, CONTAINER_2D_BASE* aDstContainer ) + +#define TO_3DU( x ) ( x * m_biuTo3Dunits ) + +#define TO_SFVEC2F( vec ) SFVEC2F( TO_3DU( vec.x ), TO_3DU( -vec.y ) ) + + +void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer, + const BOARD_ITEM* aOwner ) { KIGFX::GAL_DISPLAY_OPTIONS empty_opts; KIFONT::FONT* font = aText->GetDrawFont(); - float penWidth = aText->GetEffectiveTextPenWidth() * m_biuTo3Dunits; + float penWidth = TO_3DU( aText->GetEffectiveTextPenWidth() ); CALLBACK_GAL callback_gal( empty_opts, // Stroke callback [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) { - const SFVEC2F a3DU( aPt1.x * m_biuTo3Dunits, -aPt1.y * m_biuTo3Dunits ); - const SFVEC2F b3DU( aPt2.x * m_biuTo3Dunits, -aPt2.y * m_biuTo3Dunits ); + const SFVEC2F pt1_3DU = TO_SFVEC2F( aPt1 ); + const SFVEC2F pt2_3DU = TO_SFVEC2F( aPt2 ); - if( Is_segment_a_circle( a3DU, b3DU ) ) - aDstContainer->Add( new FILLED_CIRCLE_2D( a3DU, penWidth / 2, *aText ) ); + if( Is_segment_a_circle( pt1_3DU, pt2_3DU ) ) + aContainer->Add( new FILLED_CIRCLE_2D( pt1_3DU, penWidth / 2, *aOwner ) ); else - aDstContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, penWidth, *aText ) ); + aContainer->Add( new ROUND_SEGMENT_2D( pt1_3DU, pt2_3DU, penWidth, *aOwner ) ); }, // Triangulation callback [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 ) { - const SFVEC2F a3DU( aPt1.x * m_biuTo3Dunits, -aPt1.y * m_biuTo3Dunits ); - const SFVEC2F b3DU( aPt2.x * m_biuTo3Dunits, -aPt2.y * m_biuTo3Dunits ); - const SFVEC2F c3DU( aPt3.x * m_biuTo3Dunits, -aPt3.y * m_biuTo3Dunits ); - - aDstContainer->Add( new TRIANGLE_2D( a3DU, b3DU, c3DU, *aText ) ); + aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ), + TO_SFVEC2F( aPt3 ), *aOwner ) ); } ); - font->Draw( &callback_gal, aText->GetShownText(), aText->GetTextPos(), aText->GetAttributes() ); + TEXT_ATTRIBUTES attrs = aText->GetAttributes(); + attrs.m_Angle = aText->GetDrawRotation(); + + font->Draw( &callback_gal, aText->GetShownText(), aText->GetDrawPos(), attrs ); } -void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, - CONTAINER_2D_BASE* aDstContainer ) +void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, CONTAINER_2D_BASE* aContainer, + const BOARD_ITEM* aOwner ) { - addShape( &aDimension->Text(), aDstContainer ); + addText( &aDimension->Text(), aContainer, aDimension ); const int linewidth = aDimension->GetLineThickness(); @@ -100,12 +108,10 @@ void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, { case SH_SEGMENT: { - const SEG& seg = static_cast( shape.get() )->GetSeg(); - const SFVEC2F start3DU( seg.A.x * m_biuTo3Dunits, -seg.A.y * m_biuTo3Dunits ); - const SFVEC2F end3DU ( seg.B.x * m_biuTo3Dunits, -seg.B.y * m_biuTo3Dunits ); + const SEG& seg = static_cast( shape.get() )->GetSeg(); - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth * m_biuTo3Dunits, - *aDimension ) ); + aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ), + TO_3DU( linewidth ), *aOwner ) ); break; } @@ -114,12 +120,8 @@ void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, int radius = static_cast( shape.get() )->GetRadius(); int delta = aDimension->GetLineThickness() / 2; - SFVEC2F center( shape->Centre().x * m_biuTo3Dunits, - shape->Centre().y * m_biuTo3Dunits ); - - aDstContainer->Add( new RING_2D( center, ( radius - delta ) * m_biuTo3Dunits, - ( radius + delta ) * m_biuTo3Dunits, *aDimension ) ); - + aContainer->Add( new RING_2D( TO_SFVEC2F( shape->Centre() ), TO_3DU( radius - delta ), + TO_3DU( radius + delta ), *aOwner ) ); break; } @@ -130,41 +132,16 @@ void BOARD_ADAPTER::addShape( const PCB_DIMENSION_BASE* aDimension, } -void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, - CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayerId ) +void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer, + PCB_LAYER_ID aLayerId ) { KIGFX::GAL_DISPLAY_OPTIONS empty_opts; - std::vector textItems; - FP_TEXT* textItem = nullptr; - float penWidth = 0; - - CALLBACK_GAL callback_gal( empty_opts, - // Stroke callback - [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) - { - const SFVEC2F a3DU( aPt1.x * m_biuTo3Dunits, -aPt1.y * m_biuTo3Dunits ); - const SFVEC2F b3DU( aPt2.x * m_biuTo3Dunits, -aPt2.y * m_biuTo3Dunits ); - - if( Is_segment_a_circle( a3DU, b3DU ) ) - aDstContainer->Add( new FILLED_CIRCLE_2D( a3DU, penWidth / 2, *textItem ) ); - else - aDstContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, penWidth, *textItem ) ); - }, - // Triangulation callback - [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 ) - { - const SFVEC2F a3DU( aPt1.x * m_biuTo3Dunits, -aPt1.y * m_biuTo3Dunits ); - const SFVEC2F b3DU( aPt2.x * m_biuTo3Dunits, -aPt2.y * m_biuTo3Dunits ); - const SFVEC2F c3DU( aPt3.x * m_biuTo3Dunits, -aPt3.y * m_biuTo3Dunits ); - - aDstContainer->Add( new TRIANGLE_2D( a3DU, b3DU, c3DU, *textItem ) ); - } ); if( aFootprint->Reference().GetLayer() == aLayerId && aFootprint->Reference().IsVisible() ) - textItems.push_back( &aFootprint->Reference() ); + addText( &aFootprint->Reference(), aContainer, &aFootprint->Reference() ); if( aFootprint->Value().GetLayer() == aLayerId && aFootprint->Value().IsVisible() ) - textItems.push_back( &aFootprint->Value() ); + addText( &aFootprint->Value(), aContainer, &aFootprint->Value() ); for( BOARD_ITEM* item : aFootprint->GraphicalItems() ) { @@ -175,7 +152,20 @@ void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, FP_TEXT* text = static_cast( item ); if( text->GetLayer() == aLayerId && text->IsVisible() ) - textItems.push_back( text ); + addText( text, aContainer, text ); + + break; + } + + case PCB_FP_TEXTBOX_T: + { + FP_TEXTBOX* textbox = static_cast( item ); + + if( textbox->GetLayer() == aLayerId ) + { + addShape( textbox, aContainer, aFootprint ); + addText( textbox, aContainer, aFootprint ); + } break; } @@ -189,7 +179,7 @@ void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, PCB_DIMENSION_BASE* dimension = static_cast( item ); if( dimension->GetLayer() == aLayerId ) - addShape( dimension, aDstContainer ); + addShape( dimension, aContainer, aFootprint ); break; } @@ -199,7 +189,7 @@ void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, FP_SHAPE* shape = static_cast( item ); if( shape->GetLayer() == aLayerId ) - addShape( static_cast( shape ), aDstContainer ); + addShape( shape, aContainer, aFootprint ); break; } @@ -208,32 +198,19 @@ void BOARD_ADAPTER::addFootprintShapes( const FOOTPRINT* aFootprint, break; } } - - for( FP_TEXT* text : textItems ) - { - textItem = text; - penWidth = textItem->GetEffectiveTextPenWidth() * m_biuTo3Dunits; - - KIFONT::FONT* font = textItem->GetDrawFont(); - TEXT_ATTRIBUTES attrs = textItem->GetAttributes(); - - attrs.m_Angle = textItem->GetDrawRotation(); - - font->Draw( &callback_gal, textItem->GetShownText(), textItem->GetTextPos(), attrs ); - } } void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer ) { - SFVEC2F start3DU( aTrack->GetStart().x * m_biuTo3Dunits, - -aTrack->GetStart().y * m_biuTo3Dunits ); // y coord is inverted + SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() ); + SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() ); switch( aTrack->Type() ) { case PCB_VIA_T: { - const float radius3DU = ( aTrack->GetWidth() / 2 ) * m_biuTo3Dunits; + const float radius3DU = TO_3DU( aTrack->GetWidth() / 2 ); aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aTrack ) ); break; } @@ -267,20 +244,16 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs case PCB_TRACE_T: // Track is a usual straight segment { - SFVEC2F end3DU( aTrack->GetEnd().x * m_biuTo3Dunits, -aTrack->GetEnd().y * m_biuTo3Dunits ); - // Cannot add segments that have the same start and end point if( Is_segment_a_circle( start3DU, end3DU ) ) { - const float radius3DU = ( aTrack->GetWidth() / 2 ) * m_biuTo3Dunits; - - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aTrack ) ); + aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aTrack->GetWidth() / 2 ), + *aTrack ) ); } else { - const float width3DU = aTrack->GetWidth() * m_biuTo3Dunits; - - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, width3DU, *aTrack ) ); + aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aTrack->GetWidth() ), + *aTrack ) ); } break; @@ -292,7 +265,7 @@ void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDs } -void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer, +void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aContainer, PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const { SHAPE_POLY_SET poly; @@ -329,37 +302,34 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aDs { case SH_SEGMENT: { - const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape; + const SHAPE_SEGMENT* seg = static_cast( shape ); - const SFVEC2F a3DU( seg->GetSeg().A.x * m_biuTo3Dunits, - -seg->GetSeg().A.y * m_biuTo3Dunits ); - const SFVEC2F b3DU( seg->GetSeg().B.x * m_biuTo3Dunits, - -seg->GetSeg().B.y * m_biuTo3Dunits ); - const double width3DU = ( seg->GetWidth() + clearance.x * 2 ) * m_biuTo3Dunits; + const SFVEC2F a3DU = TO_SFVEC2F( seg->GetSeg().A ); + const SFVEC2F b3DU = TO_SFVEC2F( seg->GetSeg().B ); + const double width3DU = TO_3DU( seg->GetWidth() + clearance.x * 2 ); // Cannot add segments that have the same start and end point if( Is_segment_a_circle( a3DU, b3DU ) ) - aDstContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) ); + aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) ); else - aDstContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) ); + aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) ); } break; case SH_CIRCLE: { - const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape; + const SHAPE_CIRCLE* circle = static_cast( shape ); - const double radius3DU = ( circle->GetRadius() + clearance.x ) * m_biuTo3Dunits; - const SFVEC2F center3DU( circle->GetCenter().x * m_biuTo3Dunits, - -circle->GetCenter().y * m_biuTo3Dunits ); + const double radius3DU = TO_3DU( circle->GetRadius() + clearance.x ); + const SFVEC2F center3DU = TO_SFVEC2F( circle->GetCenter() ); - aDstContainer->Add( new FILLED_CIRCLE_2D( center3DU, radius3DU, *aPad ) ); + aContainer->Add( new FILLED_CIRCLE_2D( center3DU, radius3DU, *aPad ) ); } break; case SH_RECT: { - SHAPE_RECT* rect = (SHAPE_RECT*) shape; + const SHAPE_RECT* rect = static_cast( shape ); poly.NewOutline(); poly.Append( rect->GetPosition() ); @@ -379,23 +349,21 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aDs case SH_ARC: { - SHAPE_ARC* arc = (SHAPE_ARC*) shape; + const SHAPE_ARC* arc = static_cast( shape ); SHAPE_LINE_CHAIN l = arc->ConvertToPolyline( maxError ); for( int i = 0; i < l.SegmentCount(); i++ ) { SHAPE_SEGMENT seg( l.Segment( i ).A, l.Segment( i ).B, arc->GetWidth() ); - const SFVEC2F a3DU( seg.GetSeg().A.x * m_biuTo3Dunits, - -seg.GetSeg().A.y * m_biuTo3Dunits ); - const SFVEC2F b3DU( seg.GetSeg().B.x * m_biuTo3Dunits, - -seg.GetSeg().B.y * m_biuTo3Dunits ); - const double width3DU = ( arc->GetWidth() + clearance.x * 2 ) * m_biuTo3Dunits; + const SFVEC2F a3DU = TO_SFVEC2F( seg.GetSeg().A ); + const SFVEC2F b3DU = TO_SFVEC2F( seg.GetSeg().B ); + const double width3DU = TO_3DU( arc->GetWidth() + clearance.x * 2 ); // Cannot add segments that have the same start and end point if( Is_segment_a_circle( a3DU, b3DU ) ) - aDstContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) ); + aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) ); else - aDstContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) ); + aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) ); } } break; @@ -413,7 +381,7 @@ void BOARD_ADAPTER::createPadWithMargin( const PAD* aPad, CONTAINER_2D_BASE* aDs poly.Inflate( clearance.x, 32 ); // Add the PAD polygon - ConvertPolygonToTriangles( poly, *aDstContainer, m_biuTo3Dunits, *aPad ); + ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad ); } } @@ -432,10 +400,7 @@ OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue { const int radius = ( drillSize.x / 2 ) + aInflateValue; - const SFVEC2F center( aPad->GetPosition().x * m_biuTo3Dunits, - -aPad->GetPosition().y * m_biuTo3Dunits ); - - return new FILLED_CIRCLE_2D( center, radius * m_biuTo3Dunits, *aPad ); + return new FILLED_CIRCLE_2D( TO_SFVEC2F( aPad->GetPosition() ), TO_3DU( radius ), *aPad ); } else // Oblong hole @@ -443,20 +408,13 @@ OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape(); float width = seg->GetWidth() + aInflateValue * 2; - SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits, - -seg->GetSeg().A.y * m_biuTo3Dunits ); - - SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits, - -seg->GetSeg().B.y * m_biuTo3Dunits ); - - return new ROUND_SEGMENT_2D( start3DU, end3DU, width * m_biuTo3Dunits, *aPad ); + return new ROUND_SEGMENT_2D( TO_SFVEC2F( seg->GetSeg().A ), TO_SFVEC2F( seg->GetSeg().B ), + TO_3DU( width ), *aPad ); } - - return nullptr; } -void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDstContainer, +void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer, PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads, bool aSkipNonPlatedPads ) { @@ -523,7 +481,7 @@ void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDs break; } - createPadWithMargin( pad, aDstContainer, aLayerId, margin ); + createPadWithMargin( pad, aContainer, aLayerId, margin ); } } @@ -532,8 +490,8 @@ void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aDs // common/convert_basic_shapes_to_polygon.cpp void BOARD_ADAPTER::transformArcToSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart, const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount, - int aWidth, CONTAINER_2D_BASE* aDstContainer, - const BOARD_ITEM& aBoardItem ) + int aWidth, CONTAINER_2D_BASE* aContainer, + const BOARD_ITEM& aOwner ) { VECTOR2I arc_start, arc_end; EDA_ANGLE arcAngle( aArcAngle ); @@ -559,43 +517,32 @@ void BOARD_ADAPTER::transformArcToSegments( const VECTOR2I& aCentre, const VECTO curr_end = arc_start; RotatePoint( curr_end, aCentre, -ii ); - const SFVEC2F start3DU( curr_start.x * m_biuTo3Dunits, -curr_start.y * m_biuTo3Dunits ); - const SFVEC2F end3DU ( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits ); + const SFVEC2F start3DU = TO_SFVEC2F( curr_start ); + const SFVEC2F end3DU = TO_SFVEC2F( curr_end ); if( Is_segment_a_circle( start3DU, end3DU ) ) - { - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits, - aBoardItem ) ); - } + aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), aOwner ) ); else - { - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, aWidth * m_biuTo3Dunits, - aBoardItem ) ); - } + aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), aOwner ) ); curr_start = curr_end; } if( curr_end != arc_end ) { - const SFVEC2F start3DU( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits ); - const SFVEC2F end3DU ( arc_end.x * m_biuTo3Dunits, -arc_end.y * m_biuTo3Dunits ); + const SFVEC2F start3DU = TO_SFVEC2F( curr_end ); + const SFVEC2F end3DU = TO_SFVEC2F( arc_end ); if( Is_segment_a_circle( start3DU, end3DU ) ) - { - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits, - aBoardItem ) ); - } + aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), aOwner ) ); else - { - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, aWidth * m_biuTo3Dunits, - aBoardItem ) ); - } + aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), aOwner ) ); } } -void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstContainer ) +void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer, + const BOARD_ITEM* aOwner ) { // The full width of the lines to create // The extra 1 protects the inner/outer radius values from degeneracy @@ -605,19 +552,17 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstCo { case SHAPE_T::CIRCLE: { - const SFVEC2F center3DU( aShape->GetCenter().x * m_biuTo3Dunits, - -aShape->GetCenter().y * m_biuTo3Dunits ); + const SFVEC2F center3DU = TO_SFVEC2F( aShape->GetCenter() ); + float inner_radius3DU = TO_3DU( aShape->GetRadius() - linewidth / 2 ); + float outer_radius3DU = TO_3DU( aShape->GetRadius() + linewidth / 2 ); - float inner_radius = ( aShape->GetRadius() - linewidth / 2 ) * m_biuTo3Dunits; - float outer_radius = ( aShape->GetRadius() + linewidth / 2 ) * m_biuTo3Dunits; - - if( inner_radius < 0 ) - inner_radius = 0; + if( inner_radius3DU < 0 ) + inner_radius3DU = 0; if( aShape->IsFilled() ) - aDstContainer->Add( new FILLED_CIRCLE_2D( center3DU, outer_radius, *aShape ) ); + aContainer->Add( new FILLED_CIRCLE_2D( center3DU, outer_radius3DU, *aOwner ) ); else - aDstContainer->Add( new RING_2D( center3DU, inner_radius, outer_radius, *aShape ) ); + aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU, *aOwner ) ); } break; @@ -631,25 +576,20 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstCo polyList.Simplify( SHAPE_POLY_SET::PM_FAST ); - ConvertPolygonToTriangles( polyList, *aDstContainer, m_biuTo3Dunits, *aShape ); + ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner ); } else { std::vector pts = aShape->GetRectCorners(); - const SFVEC2F topLeft3DU( pts[0].x * m_biuTo3Dunits, -pts[0].y * m_biuTo3Dunits ); - const SFVEC2F topRight3DU( pts[1].x * m_biuTo3Dunits, -pts[1].y * m_biuTo3Dunits ); - const SFVEC2F botRight3DU( pts[2].x * m_biuTo3Dunits, -pts[2].y * m_biuTo3Dunits ); - const SFVEC2F botLeft3DU( pts[3].x * m_biuTo3Dunits, -pts[3].y * m_biuTo3Dunits ); - - aDstContainer->Add( new ROUND_SEGMENT_2D( topLeft3DU, topRight3DU, - linewidth * m_biuTo3Dunits, *aShape ) ); - aDstContainer->Add( new ROUND_SEGMENT_2D( topRight3DU, botRight3DU, - linewidth * m_biuTo3Dunits, *aShape ) ); - aDstContainer->Add( new ROUND_SEGMENT_2D( botRight3DU, botLeft3DU, - linewidth * m_biuTo3Dunits, *aShape ) ); - aDstContainer->Add( new ROUND_SEGMENT_2D( botLeft3DU, topLeft3DU, - linewidth * m_biuTo3Dunits, *aShape ) ); + aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ), + TO_3DU( linewidth ), *aOwner ) ); + aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ), + TO_3DU( linewidth ), *aOwner ) ); + aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ), + TO_3DU( linewidth ), *aOwner ) ); + aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ), + TO_3DU( linewidth ), *aOwner ) ); } break; @@ -658,28 +598,20 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstCo unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() ); transformArcToSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(), - segCount, linewidth, aDstContainer, *aShape ); + segCount, linewidth, aContainer, *aOwner ); } break; case SHAPE_T::SEGMENT: { - const SFVEC2F start3DU( aShape->GetStart().x * m_biuTo3Dunits, - -aShape->GetStart().y * m_biuTo3Dunits ); - - const SFVEC2F end3DU ( aShape->GetEnd().x * m_biuTo3Dunits, - -aShape->GetEnd().y * m_biuTo3Dunits ); + const SFVEC2F start3DU = TO_SFVEC2F( aShape->GetStart() ); + const SFVEC2F end3DU = TO_SFVEC2F( aShape->GetEnd() ); + const double linewidth3DU = TO_3DU( linewidth ); if( Is_segment_a_circle( start3DU, end3DU ) ) - { - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, ( linewidth / 2 ) * m_biuTo3Dunits, - *aShape ) ); - } + aContainer->Add( new FILLED_CIRCLE_2D( start3DU, linewidth3DU / 2, *aOwner ) ); else - { - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth * m_biuTo3Dunits, - *aShape ) ); - } + aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth3DU, *aOwner ) ); } break; @@ -696,7 +628,7 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstCo if( polyList.IsEmpty() ) // Just for caution break; - ConvertPolygonToTriangles( polyList, *aDstContainer, m_biuTo3Dunits, *aShape ); + ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner ); } break; @@ -708,24 +640,21 @@ void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aDstCo } -// Based on -// TransformSolidAreasShapesToPolygonSet -// board_items_to_polygon_shape_transform.cpp -void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZoneContainer, - CONTAINER_2D_BASE* aDstContainer, PCB_LAYER_ID aLayerId ) +void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZone, CONTAINER_2D_BASE* aContainer, + PCB_LAYER_ID aLayerId ) { // Copy the polys list because we have to simplify it - SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZoneContainer->GetFilledPolysList( aLayerId ) ); + SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZone->GetFilledPolysList( aLayerId ) ); // This convert the poly in outline and holes - ConvertPolygonToTriangles( polyList, *aDstContainer, m_biuTo3Dunits, *aZoneContainer ); + ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aZone ); // add filled areas outlines, which are drawn with thick lines segments // but only if filled polygons outlines have thickness - if( !aZoneContainer->GetFilledPolysUseThickness() ) + if( !aZone->GetFilledPolysUseThickness() ) return; - float line_thickness = aZoneContainer->GetMinThickness() * m_biuTo3Dunits; + float width3DU = TO_3DU( aZone->GetMinThickness() ); for( int i = 0; i < polyList.OutlineCount(); ++i ) { @@ -734,23 +663,19 @@ void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZoneContainer, for( int j = 0; j < pathOutline.PointCount(); ++j ) { - const VECTOR2I& a = pathOutline.CPoint( j ); - const VECTOR2I& b = pathOutline.CPoint( j + 1 ); - - SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits ); - SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits ); + SFVEC2F start3DU = TO_SFVEC2F( pathOutline.CPoint( j ) ); + SFVEC2F end3DU = TO_SFVEC2F( pathOutline.CPoint( j + 1 ) ); if( Is_segment_a_circle( start3DU, end3DU ) ) { - float radius = line_thickness/2; + float radius3DU = width3DU / 2; - if( radius > 0.0 ) // degenerated circles crash 3D viewer - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius, *aZoneContainer ) ); + if( radius3DU > 0.0 ) // degenerated circles crash 3D viewer + aContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aZone ) ); } else { - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, line_thickness, - *aZoneContainer ) ); + aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, width3DU, *aZone ) ); } } @@ -761,24 +686,19 @@ void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZoneContainer, for( int j = 0; j < pathHole.PointCount(); j++ ) { - const VECTOR2I& a = pathHole.CPoint( j ); - const VECTOR2I& b = pathHole.CPoint( j + 1 ); - - SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits ); - SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits ); + SFVEC2F start3DU = TO_SFVEC2F( pathHole.CPoint( j ) ); + SFVEC2F end3DU = TO_SFVEC2F( pathHole.CPoint( j + 1 ) ); if( Is_segment_a_circle( start3DU, end3DU ) ) { - float radius = line_thickness/2; + float radius3DU = width3DU / 2; - if( radius > 0.0 ) // degenerated circles crash 3D viewer - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius, - *aZoneContainer ) ); + if( radius3DU > 0.0 ) // degenerated circles crash 3D viewer + aContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aZone ) ); } else { - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, line_thickness, - *aZoneContainer ) ); + aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, width3DU, *aZone ) ); } } } @@ -786,19 +706,17 @@ void BOARD_ADAPTER::addSolidAreasShapes( const ZONE* aZoneContainer, } -void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BASE* aDstContainer, +void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BASE* aContainer, int aWidth ) { if( aPad->GetShape() == PAD_SHAPE::CIRCLE ) // Draw a ring { - const SFVEC2F center3DU( aPad->ShapePos().x * m_biuTo3Dunits, - -aPad->ShapePos().y * m_biuTo3Dunits ); + const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos() ); + const int radius = aPad->GetSize().x / 2; + const float inner_radius3DU = TO_3DU( radius - aWidth / 2 ); + const float outer_radius3DU = TO_3DU( radius + aWidth / 2 ); - const int radius = aPad->GetSize().x / 2; - const float inner_radius = ( radius - aWidth / 2 ) * m_biuTo3Dunits; - const float outer_radius = ( radius + aWidth / 2 ) * m_biuTo3Dunits; - - aDstContainer->Add( new RING_2D( center3DU, inner_radius, outer_radius, *aPad ) ); + aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU, *aPad ) ); return; } @@ -809,21 +727,12 @@ void BOARD_ADAPTER::buildPadOutlineAsSegments( const PAD* aPad, CONTAINER_2D_BAS for( int j = 0; j < path.PointCount(); j++ ) { - const VECTOR2I& a = path.CPoint( j ); - const VECTOR2I& b = path.CPoint( j + 1 ); - - SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits ); - SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits ); + SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) ); + SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) ); if( Is_segment_a_circle( start3DU, end3DU ) ) - { - aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits, - *aPad ) ); - } + aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), *aPad ) ); else - { - aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, aWidth * m_biuTo3Dunits, - *aPad ) ); - } + aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), *aPad ) ); } } diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp index 3838c66d80..9cdc1efb8a 100644 --- a/3d-viewer/3d_canvas/create_layer_items.cpp +++ b/3d-viewer/3d_canvas/create_layer_items.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015-2016 Mario Luzeiro - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -606,11 +607,16 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) switch( item->Type() ) { case PCB_SHAPE_T: - addShape( static_cast( item ), layerContainer ); + addShape( static_cast( item ), layerContainer, item ); break; case PCB_TEXT_T: - addShape( static_cast( item ), layerContainer ); + addText( static_cast( item ), layerContainer, item ); + break; + + case PCB_TEXTBOX_T: + addText( static_cast( item ), layerContainer, item ); + addShape( static_cast( item ), layerContainer, item ); break; case PCB_DIM_ALIGNED_T: @@ -618,7 +624,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) case PCB_DIM_RADIAL_T: case PCB_DIM_ORTHOGONAL_T: case PCB_DIM_LEADER_T: - addShape( static_cast( item ), layerContainer ); + addShape( static_cast( item ), layerContainer, item ); break; default: @@ -657,8 +663,17 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) text->TransformTextShapeWithClearanceToPolygon( *layerPoly, cur_layer_id, 0, ARC_HIGH_DEF, ERROR_INSIDE ); - } break; + } + + case PCB_TEXTBOX_T: + { + PCB_TEXTBOX* textbox = static_cast( item ); + + textbox->TransformTextShapeWithClearanceToPolygon( *layerPoly, cur_layer_id, 0, + ARC_HIGH_DEF, ERROR_INSIDE ); + break; + } default: wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), @@ -911,11 +926,16 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) switch( item->Type() ) { case PCB_SHAPE_T: - addShape( static_cast( item ), layerContainer ); + addShape( static_cast( item ), layerContainer, item ); break; case PCB_TEXT_T: - addShape( static_cast( item ), layerContainer ); + addText( static_cast( item ), layerContainer, item ); + break; + + case PCB_TEXTBOX_T: + addText( static_cast( item ), layerContainer, item ); + addShape( static_cast( item ), layerContainer, item ); break; case PCB_DIM_ALIGNED_T: @@ -923,7 +943,7 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) case PCB_DIM_RADIAL_T: case PCB_DIM_ORTHOGONAL_T: case PCB_DIM_LEADER_T: - addShape( static_cast( item ), layerContainer ); + addShape( static_cast( item ), layerContainer, item ); break; default: @@ -950,8 +970,17 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) text->TransformTextShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0, ARC_HIGH_DEF, ERROR_INSIDE ); - } break; + } + + case PCB_TEXTBOX_T: + { + PCB_TEXTBOX* textbox = static_cast( item ); + + textbox->TransformTextShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0, + ARC_HIGH_DEF, ERROR_INSIDE ); + break; + } default: break; diff --git a/3d-viewer/3d_rendering/raytracing/shapes2D/object_2d.cpp b/3d-viewer/3d_rendering/raytracing/shapes2D/object_2d.cpp index cfeaadac96..a538c8da9c 100644 --- a/3d-viewer/3d_rendering/raytracing/shapes2D/object_2d.cpp +++ b/3d-viewer/3d_rendering/raytracing/shapes2D/object_2d.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015-2020 Mario Luzeiro - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -22,19 +22,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -/** - * @file object_2d.cpp - */ - #include "object_2d.h" -#include #include OBJECT_2D_STATS *OBJECT_2D_STATS::s_instance = nullptr; -OBJECT_2D::OBJECT_2D( OBJECT_2D_TYPE aObjType, const BOARD_ITEM& aBoardItem ) - : m_boardItem(aBoardItem) +OBJECT_2D::OBJECT_2D( OBJECT_2D_TYPE aObjType, const BOARD_ITEM& aBoardItem ) : + m_boardItem( aBoardItem ) { m_obj_type = aObjType; OBJECT_2D_STATS::Instance().AddOne( aObjType ); diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 3e0cc66d58..026c388e06 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -545,8 +545,10 @@ set( PCB_COMMON_SRCS ${CMAKE_SOURCE_DIR}/pcbnew/pad.cpp ${CMAKE_SOURCE_DIR}/pcbnew/pcb_target.cpp ${CMAKE_SOURCE_DIR}/pcbnew/pcb_text.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/pcb_textbox.cpp ${CMAKE_SOURCE_DIR}/pcbnew/board_stackup_manager/board_stackup.cpp ${CMAKE_SOURCE_DIR}/pcbnew/fp_text.cpp + ${CMAKE_SOURCE_DIR}/pcbnew/fp_textbox.cpp ${CMAKE_SOURCE_DIR}/pcbnew/pcb_track.cpp ${CMAKE_SOURCE_DIR}/pcbnew/zone.cpp ${CMAKE_SOURCE_DIR}/pcbnew/collectors.cpp diff --git a/common/eda_item.cpp b/common/eda_item.cpp index 373cdb63a1..1231bad124 100644 --- a/common/eda_item.cpp +++ b/common/eda_item.cpp @@ -316,7 +316,9 @@ static struct EDA_ITEM_DESC .Map( PCB_PAD_T, _HKI( "Pad" ) ) .Map( PCB_SHAPE_T, _HKI( "Graphic" ) ) .Map( PCB_TEXT_T, _HKI( "Text" ) ) + .Map( PCB_TEXTBOX_T, _HKI( "Text Box" ) ) .Map( PCB_FP_TEXT_T, _HKI( "Text" ) ) + .Map( PCB_FP_TEXTBOX_T, _HKI( "Text Box" ) ) .Map( PCB_FP_SHAPE_T, _HKI( "Graphic" ) ) .Map( PCB_FP_DIM_ALIGNED_T, _HKI( "Dimension" ) ) .Map( PCB_FP_DIM_ORTHOGONAL_T, _HKI( "Dimension" ) ) diff --git a/common/eda_shape.cpp b/common/eda_shape.cpp index 3883d9fd4f..3fda107585 100644 --- a/common/eda_shape.cpp +++ b/common/eda_shape.cpp @@ -246,7 +246,7 @@ void EDA_SHAPE::rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) break; } - // Convert non-cartesian-rotated rect to a diamond + // Convert non-cardinally-rotated rect to a diamond m_shape = SHAPE_T::POLY; m_poly.RemoveAllContours(); m_poly.NewOutline(); diff --git a/common/eda_text.cpp b/common/eda_text.cpp index 3271dd273e..7ebd53b8b1 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -457,8 +457,11 @@ EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const m_render_cache.clear(); KIFONT::OUTLINE_FONT* font = static_cast( GetFont() ); - font->GetLinesAsGlyphs( &m_render_cache, this ); + TEXT_ATTRIBUTES attrs = GetAttributes(); + attrs.m_Angle = resolvedAngle; + + font->GetLinesAsGlyphs( &m_render_cache, GetShownText(), GetDrawPos(), attrs ); m_render_cache_angle = resolvedAngle; m_render_cache_text = forResolvedText; } @@ -507,8 +510,14 @@ int EDA_TEXT::GetInterline() const EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const { + VECTOR2I drawPos = GetDrawPos(); + if( m_bounding_box_cache_valid && aLine < 0 && !aInvertY ) + { + m_bounding_box_cache.Offset( drawPos - m_bounding_box_cache_pos ); + m_bounding_box_cache_pos = drawPos; return m_bounding_box_cache; + } EDA_RECT rect; wxArrayString strings; @@ -540,7 +549,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const // Creates bounding box (rectangle) for horizontal, left and top justified text. The // bounding box will be moved later according to the actual text options wxSize textsize = wxSize( dx, fontSize.y ); - VECTOR2I pos = GetTextPos(); + VECTOR2I pos = drawPos; if( IsMultilineAllowed() && aLine > 0 && ( aLine < static_cast( strings.GetCount() ) ) ) pos.y -= aLine * GetInterline(); @@ -599,6 +608,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const if( aLine < 0 && !aInvertY ) { m_bounding_box_cache_valid = true; + m_bounding_box_cache_pos = drawPos; m_bounding_box_cache = rect; } @@ -612,7 +622,7 @@ bool EDA_TEXT::TextHitTest( const VECTOR2I& aPoint, int aAccuracy ) const VECTOR2I location = aPoint; rect.Inflate( aAccuracy ); - RotatePoint( location, GetTextPos(), -GetTextAngle() ); + RotatePoint( location, GetDrawPos(), -GetDrawRotation() ); return rect.Contains( location ); } @@ -627,7 +637,7 @@ bool EDA_TEXT::TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy if( aContains ) return rect.Contains( GetTextBox() ); - return rect.Intersects( GetTextBox(), GetTextAngle() ); + return rect.Intersects( GetTextBox(), GetDrawRotation() ); } @@ -649,14 +659,14 @@ void EDA_TEXT::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset, } else { - printOneLineOfText( aSettings, aOffset, aColor, aFillMode, GetShownText(), GetTextPos() ); + printOneLineOfText( aSettings, aOffset, aColor, aFillMode, GetShownText(), GetDrawPos() ); } } void EDA_TEXT::GetLinePositions( std::vector& aPositions, int aLineCount ) const { - VECTOR2I pos = GetTextPos(); // Position of first line of the multiline text according + VECTOR2I pos = GetDrawPos(); // Position of first line of the multiline text according // to the center of the multiline text block VECTOR2I offset; // Offset to next line. @@ -681,10 +691,10 @@ void EDA_TEXT::GetLinePositions( std::vector& aPositions, int aLineCou } // Rotate the position of the first line around the center of the multiline text block - RotatePoint( pos, GetTextPos(), GetTextAngle() ); + RotatePoint( pos, GetDrawPos(), GetDrawRotation() ); // Rotate the offset lines to increase happened in the right direction - RotatePoint( offset, GetTextAngle() ); + RotatePoint( offset, GetDrawRotation() ); for( int ii = 0; ii < aLineCount; ii++ ) { @@ -709,7 +719,7 @@ void EDA_TEXT::printOneLineOfText( const RENDER_SETTINGS* aSettings, const VECTO if( IsMirrored() ) size.x = -size.x; - GRPrintText( DC, aOffset + aPos, aColor, aText, GetTextAngle(), size, GetHorizJustify(), + GRPrintText( DC, aOffset + aPos, aColor, aText, GetDrawRotation(), size, GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(), IsBold(), GetDrawFont() ); } @@ -850,7 +860,7 @@ std::shared_ptr EDA_TEXT::GetEffectiveTextShape( ) const TEXT_ATTRIBUTES attrs = GetAttributes(); attrs.m_Angle = GetDrawRotation(); - font->Draw( &callback_gal, GetShownText(), GetTextPos(), attrs ); + font->Draw( &callback_gal, GetShownText(), GetDrawPos(), attrs ); return shape; } @@ -930,7 +940,7 @@ void EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon( SHAPE_POLY_SET* aCorn for( VECTOR2I& corner : corners ) { // Rotate polygon - RotatePoint( corner, GetTextPos(), GetTextAngle() ); + RotatePoint( corner, GetDrawPos(), GetDrawRotation() ); aCornerBuffer->Append( corner.x, corner.y ); } } diff --git a/common/font/font.cpp b/common/font/font.cpp index 869659dd4e..8b0d9d1944 100644 --- a/common/font/font.cpp +++ b/common/font/font.cpp @@ -447,7 +447,8 @@ void FONT::LinebreakText( wxString& aText, int aColumnWidth, const VECTOR2I& aSi for( size_t jj = 0; jj < words.size(); /* advance in loop */ ) { - if( lineWidth + spaceWidth + words[jj].second < aColumnWidth - aThickness ) + if( lineWidth == 0 + || lineWidth + spaceWidth + words[jj].second < aColumnWidth - aThickness ) { if( lineWidth > 0 ) { diff --git a/common/font/outline_font.cpp b/common/font/outline_font.cpp index cd4ebe609d..3731a47e81 100644 --- a/common/font/outline_font.cpp +++ b/common/font/outline_font.cpp @@ -191,20 +191,6 @@ BOX2I OUTLINE_FONT::getBoundingBox( const std::vector>& a } -void OUTLINE_FONT::GetLinesAsGlyphs( std::vector>* aGlyphs, - const EDA_TEXT* aText ) const -{ - wxArrayString strings; - std::vector positions; - std::vector extents; - TEXT_ATTRIBUTES attrs = aText->GetAttributes(); - - attrs.m_Angle = aText->GetDrawRotation(); - - return GetLinesAsGlyphs( aGlyphs, aText->GetShownText(), aText->GetTextPos(), attrs ); -} - - void OUTLINE_FONT::GetLinesAsGlyphs( std::vector>* aGlyphs, const wxString& aText, const VECTOR2I& aPosition, const TEXT_ATTRIBUTES& aAttrs ) const diff --git a/common/hash_eda.cpp b/common/hash_eda.cpp index 7d0d19e241..0939d2bc68 100644 --- a/common/hash_eda.cpp +++ b/common/hash_eda.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -115,7 +116,7 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags ) ret = hash_board_item( text, aFlags ); hash_combine( ret, text->GetText().ToStdString() ); - hash_combine( ret, text->IsItalic() ); + hash_combine( ret, text->IsItalic() ); hash_combine( ret, text->IsBold() ); hash_combine( ret, text->IsMirrored() ); hash_combine( ret, text->GetTextWidth() ); @@ -179,6 +180,46 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags ) } break; + case PCB_FP_TEXTBOX_T: + { + const FP_TEXTBOX* textbox = static_cast( aItem ); + + ret = hash_board_item( textbox, aFlags ); + hash_combine( ret, textbox->GetText().ToStdString() ); + hash_combine( ret, textbox->IsItalic() ); + hash_combine( ret, textbox->IsBold() ); + hash_combine( ret, textbox->IsMirrored() ); + hash_combine( ret, textbox->GetTextWidth() ); + hash_combine( ret, textbox->GetTextHeight() ); + hash_combine( ret, textbox->GetHorizJustify() ); + hash_combine( ret, textbox->GetVertJustify() ); + + if( aFlags & HASH_ROT ) + hash_combine( ret, textbox->GetTextAngle().AsDegrees() ); + + hash_combine( ret, textbox->GetShape() ); + hash_combine( ret, textbox->GetWidth() ); + + if( aFlags & HASH_POS ) + { + if( aFlags & REL_COORD ) + { + hash_combine( ret, textbox->GetStart0().x ); + hash_combine( ret, textbox->GetStart0().y ); + hash_combine( ret, textbox->GetEnd0().x ); + hash_combine( ret, textbox->GetEnd0().y ); + } + else + { + hash_combine( ret, textbox->GetStart().x ); + hash_combine( ret, textbox->GetStart().y ); + hash_combine( ret, textbox->GetEnd().x ); + hash_combine( ret, textbox->GetEnd().y ); + } + } + } + break; + default: wxASSERT_MSG( false, "Unhandled type in function hash_fp_item() (exporter_gencad.cpp)" ); } diff --git a/common/pcb.keywords b/common/pcb.keywords index 8ab096de41..c9bef4d109 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -2,7 +2,7 @@ # This program source code file is part of KiCad, a free EDA CAD application. # # Copyright (C) 2012 CERN. -# Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors. +# Copyright (C) 2019-2022 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 @@ -120,6 +120,7 @@ fp_line fp_poly fp_rect fp_text +fp_text_box free full general @@ -133,6 +134,7 @@ gr_line gr_poly gr_rect gr_text +gr_text_box hatch hatch_thickness hatch_gap diff --git a/eeschema/dialogs/dialog_field_properties_base.cpp b/eeschema/dialogs/dialog_field_properties_base.cpp index df0437c741..f61fdd6aae 100644 --- a/eeschema/dialogs/dialog_field_properties_base.cpp +++ b/eeschema/dialogs/dialog_field_properties_base.cpp @@ -96,7 +96,7 @@ DIALOG_FIELD_PROPERTIES_BASE::DIALOG_FIELD_PROPERTIES_BASE( wxWindow* parent, wx m_fontLabel = new wxStaticText( this, wxID_ANY, _("Font:"), wxDefaultPosition, wxDefaultSize, 0 ); m_fontLabel->Wrap( -1 ); - gbSizer1->Add( m_fontLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 ); + gbSizer1->Add( m_fontLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxRIGHT|wxLEFT, 5 ); wxString m_fontCtrlChoices[] = { _("Default Font"), _("KiCad Font") }; int m_fontCtrlNChoices = sizeof( m_fontCtrlChoices ) / sizeof( wxString ); diff --git a/eeschema/dialogs/dialog_field_properties_base.fbp b/eeschema/dialogs/dialog_field_properties_base.fbp index d2f1eec390..d2cc76fc22 100644 --- a/eeschema/dialogs/dialog_field_properties_base.fbp +++ b/eeschema/dialogs/dialog_field_properties_base.fbp @@ -512,7 +512,7 @@ 5 1 0 - wxALL + wxRIGHT|wxLEFT 0 1 diff --git a/eeschema/dialogs/dialog_lib_text_properties_base.cpp b/eeschema/dialogs/dialog_lib_text_properties_base.cpp index 1f234d0ce2..80fa9738ed 100644 --- a/eeschema/dialogs/dialog_lib_text_properties_base.cpp +++ b/eeschema/dialogs/dialog_lib_text_properties_base.cpp @@ -65,7 +65,7 @@ DIALOG_LIB_TEXT_PROPERTIES_BASE::DIALOG_LIB_TEXT_PROPERTIES_BASE( wxWindow* pare m_fontLabel = new wxStaticText( this, wxID_ANY, _("Font:"), wxDefaultPosition, wxDefaultSize, 0 ); m_fontLabel->Wrap( -1 ); - gbSizer1->Add( m_fontLabel, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 ); + gbSizer1->Add( m_fontLabel, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxRIGHT|wxLEFT, 5 ); wxString m_fontCtrlChoices[] = { _("Default Font"), _("KiCad Font") }; int m_fontCtrlNChoices = sizeof( m_fontCtrlChoices ) / sizeof( wxString ); diff --git a/eeschema/dialogs/dialog_lib_text_properties_base.fbp b/eeschema/dialogs/dialog_lib_text_properties_base.fbp index 31238aa229..2e55169235 100644 --- a/eeschema/dialogs/dialog_lib_text_properties_base.fbp +++ b/eeschema/dialogs/dialog_lib_text_properties_base.fbp @@ -222,7 +222,7 @@ 5 1 0 - wxALL + wxRIGHT|wxLEFT 2 1 @@ -356,7 +356,7 @@ wxEXPAND 2 1 - + formattingSizer wxHORIZONTAL diff --git a/eeschema/dialogs/dialog_lib_textbox_properties_base.cpp b/eeschema/dialogs/dialog_lib_textbox_properties_base.cpp index b1dbf84f91..7d4b5ff6bc 100644 --- a/eeschema/dialogs/dialog_lib_textbox_properties_base.cpp +++ b/eeschema/dialogs/dialog_lib_textbox_properties_base.cpp @@ -63,13 +63,13 @@ DIALOG_LIB_TEXTBOX_PROPERTIES_BASE::DIALOG_LIB_TEXTBOX_PROPERTIES_BASE( wxWindow m_fontLabel = new wxStaticText( this, wxID_ANY, _("Font:"), wxDefaultPosition, wxDefaultSize, 0 ); m_fontLabel->Wrap( -1 ); - m_textEntrySizer->Add( m_fontLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + m_textEntrySizer->Add( m_fontLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT, 5 ); wxString m_fontCtrlChoices[] = { _("Default Font"), _("KiCad Font") }; int m_fontCtrlNChoices = sizeof( m_fontCtrlChoices ) / sizeof( wxString ); m_fontCtrl = new FONT_CHOICE( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_fontCtrlNChoices, m_fontCtrlChoices, 0 ); m_fontCtrl->SetSelection( 0 ); - m_textEntrySizer->Add( m_fontCtrl, wxGBPosition( 1, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + m_textEntrySizer->Add( m_fontCtrl, wxGBPosition( 1, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP, 5 ); wxBoxSizer* bSizeCtrlSizer; bSizeCtrlSizer = new wxBoxSizer( wxHORIZONTAL ); @@ -77,50 +77,50 @@ DIALOG_LIB_TEXTBOX_PROPERTIES_BASE::DIALOG_LIB_TEXTBOX_PROPERTIES_BASE( wxWindow m_separator1 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_separator1->Enable( false ); - bSizeCtrlSizer->Add( m_separator1, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + bSizeCtrlSizer->Add( m_separator1, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); m_bold = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_bold->SetToolTip( _("Bold") ); - bSizeCtrlSizer->Add( m_bold, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_bold, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_italic = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_italic->SetToolTip( _("Italic") ); - bSizeCtrlSizer->Add( m_italic, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_italic, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_separator2 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_separator2->Enable( false ); - bSizeCtrlSizer->Add( m_separator2, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_separator2, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_spin0 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_spin0->SetToolTip( _("Align right") ); - bSizeCtrlSizer->Add( m_spin0, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_spin0, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_spin1 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_spin1->SetToolTip( _("Align bottom") ); - bSizeCtrlSizer->Add( m_spin1, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_spin1, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_spin2 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_spin2->SetToolTip( _("Align left") ); - bSizeCtrlSizer->Add( m_spin2, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_spin2, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_spin3 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_spin3->SetToolTip( _("Align top") ); - bSizeCtrlSizer->Add( m_spin3, 0, wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL, 5 ); + bSizeCtrlSizer->Add( m_spin3, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_separator3 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); m_separator3->Enable( false ); - bSizeCtrlSizer->Add( m_separator3, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 5 ); + bSizeCtrlSizer->Add( m_separator3, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_textEntrySizer->Add( bSizeCtrlSizer, wxGBPosition( 1, 3 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 ); + m_textEntrySizer->Add( bSizeCtrlSizer, wxGBPosition( 1, 3 ), wxGBSpan( 1, 1 ), wxEXPAND|wxTOP, 5 ); wxBoxSizer* bSizer41; bSizer41 = new wxBoxSizer( wxVERTICAL ); diff --git a/eeschema/dialogs/dialog_lib_textbox_properties_base.fbp b/eeschema/dialogs/dialog_lib_textbox_properties_base.fbp index 102846ba22..8054e0e7f2 100644 --- a/eeschema/dialogs/dialog_lib_textbox_properties_base.fbp +++ b/eeschema/dialogs/dialog_lib_textbox_properties_base.fbp @@ -211,7 +211,7 @@ 5 1 0 - wxRIGHT|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT 1 1 @@ -275,7 +275,7 @@ 5 2 1 - wxALIGN_CENTER_VERTICAL|wxEXPAND + wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP 1 1 @@ -342,17 +342,17 @@ 5 1 3 - wxEXPAND + wxEXPAND|wxTOP 1 1 - + bSizeCtrlSizer wxHORIZONTAL none 5 - wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT + wxALIGN_CENTER_VERTICAL|wxLEFT 0 1 @@ -424,7 +424,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -496,7 +496,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -568,7 +568,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -640,7 +640,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -712,7 +712,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -784,7 +784,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -856,7 +856,7 @@ 5 - wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL 0 1 @@ -928,7 +928,7 @@ 5 - wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM + wxALIGN_CENTER_VERTICAL 0 1 diff --git a/eeschema/lib_textbox.cpp b/eeschema/lib_textbox.cpp index 0c2497fb63..9adf0b60d3 100644 --- a/eeschema/lib_textbox.cpp +++ b/eeschema/lib_textbox.cpp @@ -120,20 +120,20 @@ void LIB_TEXTBOX::UpdateTextPosition() BOX2I bbox( VECTOR2I( std::min( m_start.x, m_end.x ), std::min( -m_start.y, -m_end.y ) ), VECTOR2I( abs( m_end.x - m_start.x ), abs( m_end.y - m_start.y ) ) ); - if( GetTextAngle() == ANGLE_HORIZONTAL ) - { - if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) - SetTextPos( VECTOR2I( bbox.GetRight() - margin, bbox.GetTop() + margin ) ); - else - SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetTop() + margin ) ); - } - else + if( GetTextAngle() == ANGLE_VERTICAL ) { if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetTop() + margin ) ); else SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetBottom() - margin ) ); } + else + { + if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) + SetTextPos( VECTOR2I( bbox.GetRight() - margin, bbox.GetTop() + margin ) ); + else + SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetTop() + margin ) ); + } } @@ -374,8 +374,6 @@ void LIB_TEXTBOX::Plot( PLOTTER* aPlotter, const VECTOR2I& aOffset, bool aFill, void LIB_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) { - wxString msg; - // Don't use GetShownText() here; we want to show the user the variable references aList.emplace_back( _( "Text Box" ), UnescapeString( GetText() ) ); diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp index e1ec4a87d0..35409d092b 100644 --- a/eeschema/sch_field.cpp +++ b/eeschema/sch_field.cpp @@ -404,24 +404,6 @@ EDA_ANGLE SCH_FIELD::GetDrawRotation() const } -VECTOR2I SCH_FIELD::GetDrawPos() const -{ - return GetBoundingBox().Centre(); -} - - -GR_TEXT_H_ALIGN_T SCH_FIELD::GetDrawHorizJustify() const -{ - return GR_TEXT_H_ALIGN_CENTER; -} - - -GR_TEXT_V_ALIGN_T SCH_FIELD::GetDrawVertJustify() const -{ - return GR_TEXT_V_ALIGN_CENTER; -} - - const EDA_RECT SCH_FIELD::GetBoundingBox() const { // Calculate the text bounding box: diff --git a/eeschema/sch_field.h b/eeschema/sch_field.h index 02dac77dfd..a2f2c783b8 100644 --- a/eeschema/sch_field.h +++ b/eeschema/sch_field.h @@ -122,9 +122,6 @@ public: * Adjusters to allow EDA_TEXT to draw/print/etc. text in absolute coords. */ EDA_ANGLE GetDrawRotation() const override; - VECTOR2I GetDrawPos() const override; - GR_TEXT_H_ALIGN_T GetDrawHorizJustify() const override; - GR_TEXT_V_ALIGN_T GetDrawVertJustify() const override; const EDA_RECT GetBoundingBox() const override; diff --git a/eeschema/sch_textbox.cpp b/eeschema/sch_textbox.cpp index 629033c499..67de701993 100644 --- a/eeschema/sch_textbox.cpp +++ b/eeschema/sch_textbox.cpp @@ -114,20 +114,20 @@ void SCH_TEXTBOX::UpdateTextPosition() bbox.Normalize(); - if( GetTextAngle() == ANGLE_HORIZONTAL ) - { - if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) - SetTextPos( VECTOR2I( bbox.GetRight() - margin, bbox.GetTop() + margin ) ); - else - SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetTop() + margin ) ); - } - else + if( GetTextAngle() == ANGLE_VERTICAL ) { if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetTop() + margin ) ); else SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetBottom() - margin ) ); } + else + { + if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT ) + SetTextPos( VECTOR2I( bbox.GetRight() - margin, bbox.GetTop() + margin ) ); + else + SetTextPos( VECTOR2I( bbox.GetLeft() + margin, bbox.GetTop() + margin ) ); + } } @@ -360,8 +360,6 @@ void SCH_TEXTBOX::Plot( PLOTTER* aPlotter ) const void SCH_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) { - wxString msg; - // Don't use GetShownText() here; we want to show the user the variable references aList.emplace_back( _( "Text Box" ), UnescapeString( GetText() ) ); diff --git a/include/core/typeinfo.h b/include/core/typeinfo.h index 028447edf2..757d1c0c9b 100644 --- a/include/core/typeinfo.h +++ b/include/core/typeinfo.h @@ -89,7 +89,9 @@ enum KICAD_T PCB_PAD_T, ///< class PAD, a pad in a footprint PCB_SHAPE_T, ///< class PCB_SHAPE, a segment not on copper layers PCB_TEXT_T, ///< class PCB_TEXT, text on a layer + PCB_TEXTBOX_T, ///< class PCB_TEXTBOX, wrapped text on a layer PCB_FP_TEXT_T, ///< class FP_TEXT, text in a footprint + PCB_FP_TEXTBOX_T, ///< class FP_TEXTBOX, wrapped text in a footprint PCB_FP_SHAPE_T, ///< class FP_SHAPE, a footprint edge PCB_FP_DIM_ALIGNED_T, ///< class PCB_DIM_ALIGNED, a linear dimension (graphic item) PCB_FP_DIM_LEADER_T, ///< class PCB_DIM_LEADER, a leader dimension (graphic item) @@ -405,7 +407,9 @@ constexpr bool IsPcbnewType( const KICAD_T aType ) case PCB_PAD_T: case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_DIM_ALIGNED_T: case PCB_FP_DIM_LEADER_T: diff --git a/include/eda_text.h b/include/eda_text.h index 25ea5bacae..b3d173b4c9 100644 --- a/include/eda_text.h +++ b/include/eda_text.h @@ -304,8 +304,6 @@ public: virtual KIFONT::FONT* GetDrawFont() const; virtual EDA_ANGLE GetDrawRotation() const { return GetTextAngle(); } virtual VECTOR2I GetDrawPos() const { return GetTextPos(); } - virtual GR_TEXT_H_ALIGN_T GetDrawHorizJustify() const { return GetHorizJustify(); }; - virtual GR_TEXT_V_ALIGN_T GetDrawVertJustify() const { return GetVertJustify(); }; virtual void ClearRenderCache(); virtual void ClearBoundingBoxCache(); @@ -344,6 +342,7 @@ private: mutable std::vector> m_render_cache; mutable bool m_bounding_box_cache_valid; + mutable VECTOR2I m_bounding_box_cache_pos; mutable EDA_RECT m_bounding_box_cache; TEXT_ATTRIBUTES m_attributes; diff --git a/include/font/outline_font.h b/include/font/outline_font.h index cf0bb7bbfb..f5ee84284f 100644 --- a/include/font/outline_font.h +++ b/include/font/outline_font.h @@ -112,9 +112,6 @@ public: * @param aGlyphs returns text glyphs * @param aText the text item */ - void GetLinesAsGlyphs( std::vector>* aGlyphs, - const EDA_TEXT* aText ) const; - void GetLinesAsGlyphs( std::vector>* aGlyphs, const wxString& aText, const VECTOR2I& aPosition, const TEXT_ATTRIBUTES& aAttrs ) const; diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 24c55e0b71..2e17db2ac2 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -141,6 +141,8 @@ set( PCBNEW_DIALOGS dialogs/dialog_target_properties_base.cpp dialogs/dialog_text_properties.cpp dialogs/dialog_text_properties_base.cpp + dialogs/dialog_textbox_properties.cpp + dialogs/dialog_textbox_properties_base.cpp dialogs/dialog_track_via_properties.cpp dialogs/dialog_track_via_properties_base.cpp dialogs/dialog_track_via_size.cpp diff --git a/pcbnew/array_creator.cpp b/pcbnew/array_creator.cpp index ffdaab199d..412faeb892 100644 --- a/pcbnew/array_creator.cpp +++ b/pcbnew/array_creator.cpp @@ -113,6 +113,7 @@ void ARRAY_CREATOR::Invoke() case PCB_FOOTPRINT_T: case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_TRACE_T: case PCB_ARC_T: case PCB_VIA_T: diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index b596698520..daf9cc8ff7 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -5,7 +5,7 @@ * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2011 Wayne Stambaugh * - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -299,6 +300,7 @@ void BOARD::Move( const VECTOR2I& aMoveVector ) // overload static const KICAD_T top_level_board_stuff[] = { PCB_MARKER_T, PCB_TEXT_T, + PCB_TEXTBOX_T, PCB_SHAPE_T, PCB_DIM_ALIGNED_T, PCB_DIM_ORTHOGONAL_T, @@ -680,6 +682,7 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) case PCB_DIM_LEADER_T: case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_TARGET_T: if( aMode == ADD_MODE::APPEND || aMode == ADD_MODE::BULK_APPEND ) m_drawings.push_back( aBoardItem ); @@ -787,6 +790,7 @@ void BOARD::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aRemoveMode ) case PCB_DIM_LEADER_T: case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_TARGET_T: alg::delete_matching( m_drawings, aBoardItem ); break; @@ -1225,6 +1229,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s case PCB_FOOTPRINT_T: case PCB_PAD_T: case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_DIM_ALIGNED_T: case PCB_FP_DIM_LEADER_T: @@ -1244,6 +1249,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s case PCB_FOOTPRINT_T: case PCB_PAD_T: case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_DIM_ALIGNED_T: case PCB_FP_DIM_LEADER_T: @@ -1264,6 +1270,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_DIM_ALIGNED_T: case PCB_DIM_CENTER_T: case PCB_DIM_RADIAL_T: @@ -1279,6 +1286,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s { case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_DIM_ALIGNED_T: case PCB_DIM_CENTER_T: case PCB_DIM_RADIAL_T: @@ -2193,6 +2201,13 @@ bool BOARD::cmp_drawings::operator()( const BOARD_ITEM* aFirst, const PCB_TEXT* other = static_cast( aSecond ); return text->Compare( other ); } + else if( aFirst->Type() == PCB_TEXTBOX_T ) + { + const PCB_TEXTBOX* textbox = static_cast( aFirst ); + const PCB_TEXTBOX* other = static_cast( aSecond ); + + return textbox->PCB_SHAPE::Compare( other ) && textbox->EDA_TEXT::Compare( other ); + } return aFirst->m_Uuid < aSecond->m_Uuid; } @@ -2263,6 +2278,14 @@ void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, break; } + case PCB_TEXTBOX_T: + { + const PCB_TEXTBOX* textbox = static_cast( item ); + textbox->TransformTextShapeWithClearanceToPolygon( aOutlines, aLayer, 0, maxError, + ERROR_INSIDE ); + break; + } + default: break; } diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp index a75dd1766e..ecca0bb117 100644 --- a/pcbnew/board_commit.cpp +++ b/pcbnew/board_commit.cpp @@ -179,15 +179,16 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a if( !( changeFlags & CHT_DONE ) ) board->Footprints().front()->Add( boardItem ); } - else if( boardItem->Type() == PCB_PAD_T || - boardItem->Type() == PCB_FP_TEXT_T || - boardItem->Type() == PCB_FP_SHAPE_T || - boardItem->Type() == PCB_FP_DIM_ALIGNED_T || - boardItem->Type() == PCB_FP_DIM_LEADER_T || - boardItem->Type() == PCB_FP_DIM_CENTER_T || - boardItem->Type() == PCB_FP_DIM_RADIAL_T || - boardItem->Type() == PCB_FP_DIM_ORTHOGONAL_T || - boardItem->Type() == PCB_FP_ZONE_T ) + else if( boardItem->Type() == PCB_PAD_T + || boardItem->Type() == PCB_FP_TEXT_T + || boardItem->Type() == PCB_FP_TEXTBOX_T + || boardItem->Type() == PCB_FP_SHAPE_T + || boardItem->Type() == PCB_FP_DIM_ALIGNED_T + || boardItem->Type() == PCB_FP_DIM_LEADER_T + || boardItem->Type() == PCB_FP_DIM_CENTER_T + || boardItem->Type() == PCB_FP_DIM_RADIAL_T + || boardItem->Type() == PCB_FP_DIM_ORTHOGONAL_T + || boardItem->Type() == PCB_FP_ZONE_T ) { wxASSERT( boardItem->GetParent() && boardItem->GetParent()->Type() == PCB_FOOTPRINT_T ); @@ -229,6 +230,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a case PCB_PAD_T: case PCB_FP_SHAPE_T: case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_DIM_ALIGNED_T: case PCB_FP_DIM_LEADER_T: case PCB_FP_DIM_CENTER_T: @@ -267,6 +269,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a // Board items case PCB_SHAPE_T: // a shape (normally not on copper layers) case PCB_TEXT_T: // a text on a layer + case PCB_TEXTBOX_T: // a wrapped text on a layer case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_ARC_T: // an arced track segment (segment on a copper layer) case PCB_VIA_T: // a via (like track segment on a copper layer) @@ -461,23 +464,24 @@ EDA_ITEM* BOARD_COMMIT::parentObject( EDA_ITEM* aItem ) const { switch( aItem->Type() ) { - case PCB_PAD_T: - case PCB_FP_SHAPE_T: - case PCB_FP_TEXT_T: - case PCB_FP_DIM_ALIGNED_T: - case PCB_FP_DIM_LEADER_T: - case PCB_FP_DIM_CENTER_T: - case PCB_FP_DIM_RADIAL_T: - case PCB_FP_DIM_ORTHOGONAL_T: - case PCB_FP_ZONE_T: - return aItem->GetParent(); + case PCB_PAD_T: + case PCB_FP_SHAPE_T: + case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: + case PCB_FP_DIM_ALIGNED_T: + case PCB_FP_DIM_LEADER_T: + case PCB_FP_DIM_CENTER_T: + case PCB_FP_DIM_RADIAL_T: + case PCB_FP_DIM_ORTHOGONAL_T: + case PCB_FP_ZONE_T: + return aItem->GetParent(); - case PCB_ZONE_T: - wxASSERT( !dynamic_cast( aItem->GetParent() ) ); - return aItem; + case PCB_ZONE_T: + wxASSERT( !dynamic_cast( aItem->GetParent() ) ); + return aItem; - default: - break; + default: + break; } return aItem; diff --git a/pcbnew/collectors.cpp b/pcbnew/collectors.cpp index f3f8f36754..bfca7df52b 100644 --- a/pcbnew/collectors.cpp +++ b/pcbnew/collectors.cpp @@ -49,6 +49,7 @@ const KICAD_T GENERAL_COLLECTOR::AllBoardItems[] = { // *** all items in a same list (shown here) must be contiguous **** PCB_MARKER_T, // in m_markers PCB_TEXT_T, // in m_drawings + PCB_TEXTBOX_T, // in m_drawings PCB_SHAPE_T, // in m_drawings PCB_DIM_ALIGNED_T, // in m_drawings PCB_DIM_CENTER_T, // in m_drawings @@ -61,6 +62,7 @@ const KICAD_T GENERAL_COLLECTOR::AllBoardItems[] = { PCB_ARC_T, // in m_tracks PCB_PAD_T, // in footprints PCB_FP_TEXT_T, // in footprints + PCB_FP_TEXTBOX_T, // in footprints PCB_FOOTPRINT_T, // in m_footprints PCB_GROUP_T, // in m_groups PCB_ZONE_T, // in m_zones @@ -71,6 +73,7 @@ const KICAD_T GENERAL_COLLECTOR::AllBoardItems[] = { const KICAD_T GENERAL_COLLECTOR::BoardLevelItems[] = { PCB_MARKER_T, PCB_TEXT_T, + PCB_TEXTBOX_T, PCB_SHAPE_T, PCB_DIM_ALIGNED_T, PCB_DIM_ORTHOGONAL_T, @@ -105,6 +108,7 @@ const KICAD_T GENERAL_COLLECTOR::PadsOrTracks[] = { const KICAD_T GENERAL_COLLECTOR::FootprintItems[] = { PCB_FP_TEXT_T, + PCB_FP_TEXTBOX_T, PCB_FP_SHAPE_T, PCB_FP_DIM_ALIGNED_T, PCB_FP_DIM_ORTHOGONAL_T, @@ -207,6 +211,10 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData ) breakhere++; break; + case PCB_TEXTBOX_T: + breakhere++; + break; + case PCB_SHAPE_T: breakhere++; break; @@ -224,6 +232,10 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData ) } break; + case PCB_FP_TEXTBOX_T: + breakhere++; + break; + case PCB_FOOTPRINT_T: { FOOTPRINT* footprint = (FOOTPRINT*) item; @@ -291,6 +303,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData ) break; case PCB_TEXT_T: + case PCB_TEXTBOX_T: break; case PCB_SHAPE_T: @@ -319,25 +332,36 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData ) break; case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: { - FP_TEXT *text = static_cast( item ); + PCB_LAYER_ID layer = item->GetLayer(); - if( m_Guide->IgnoreHiddenFPText() && !text->IsVisible() ) + if( m_Guide->IgnoreHiddenFPText() && item->Type() == PCB_FP_TEXT_T ) + { + FP_TEXT *text = static_cast( item ); + + if( !text->IsVisible() ) + goto exit; + } + + if( m_Guide->IgnoreFPTextOnBack() && IsBackLayer( layer ) ) goto exit; - if( m_Guide->IgnoreFPTextOnBack() && IsBackLayer( text->GetLayer() ) ) + if( m_Guide->IgnoreFPTextOnFront() && IsFrontLayer( layer ) ) goto exit; - if( m_Guide->IgnoreFPTextOnFront() && IsFrontLayer( text->GetLayer() ) ) - goto exit; + /* + * The three text types have different criteria: reference and value have their own + * ignore flags; user text instead follows their layer visibility. Checking this here + * is simpler than later (when layer visibility is checked for other entities) + */ - /* The three text types have different criteria: reference - * and value have their own ignore flags; user text instead - * follows their layer visibility. Checking this here is - * simpler than later (when layer visibility is checked for - * other entities) */ + FP_TEXT::TEXT_TYPE textType = FP_TEXT::TEXT_is_DIVERS; - switch( text->GetType() ) + if( item->Type() == PCB_FP_TEXT_T ) + textType = static_cast( item )->GetType(); + + switch( textType ) { case FP_TEXT::TEXT_is_REFERENCE: if( m_Guide->IgnoreFPReferences() ) @@ -352,8 +376,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData ) break; case FP_TEXT::TEXT_is_DIVERS: - if( !m_Guide->IsLayerVisible( text->GetLayer() ) - && m_Guide->IgnoreNonVisibleLayers() ) + if( !m_Guide->IsLayerVisible( layer ) && m_Guide->IgnoreNonVisibleLayers() ) goto exit; break; diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index ed717c63e4..4bf2139dc7 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -311,7 +311,8 @@ std::string FormatProbeItem( BOARD_ITEM* aItem ) footprint = static_cast( aItem->GetParent() ); wxString pad = static_cast( aItem )->GetNumber(); - return StrPrintf( "$PART: \"%s\" $PAD: \"%s\"", TO_UTF8( footprint->GetReference() ), + return StrPrintf( "$PART: \"%s\" $PAD: \"%s\"", + TO_UTF8( footprint->GetReference() ), TO_UTF8( pad ) ); } @@ -331,7 +332,9 @@ std::string FormatProbeItem( BOARD_ITEM* aItem ) else break; - return StrPrintf( "$PART: \"%s\" %s \"%s\"", TO_UTF8( footprint->GetReference() ), text_key, + return StrPrintf( "$PART: \"%s\" %s \"%s\"", + TO_UTF8( footprint->GetReference() ), + text_key, TO_UTF8( text->GetText() ) ); } diff --git a/pcbnew/dialogs/dialog_global_deletion.cpp b/pcbnew/dialogs/dialog_global_deletion.cpp index 76aa2f846d..3b0f7be7e2 100644 --- a/pcbnew/dialogs/dialog_global_deletion.cpp +++ b/pcbnew/dialogs/dialog_global_deletion.cpp @@ -195,7 +195,7 @@ void DIALOG_GLOBAL_DELETION::DoGlobalDeletions() if( !item->IsLocked() && !m_drawingFilterUnlocked->GetValue() ) continue; } - else if( type == PCB_TEXT_T ) + else if( type == PCB_TEXT_T || type == PCB_TEXTBOX_T ) { if( !delete_texts || !del_text_layers[layer] ) continue; diff --git a/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp b/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp index fba915166a..d6289ffe0d 100644 --- a/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp +++ b/pcbnew/dialogs/dialog_global_edit_text_and_graphics.cpp @@ -504,6 +504,11 @@ bool DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::TransferDataFromWindow() else if( m_otherFields->GetValue() ) visitItem( commit, boardItem ); } + else if( itemType == PCB_FP_TEXTBOX_T ) + { + if( m_otherFields->GetValue() ) + visitItem( commit, boardItem ); + } else if( itemType == PCB_FP_SHAPE_T || BaseType( itemType ) == PCB_DIMENSION_T ) { if( m_footprintGraphics->GetValue() ) @@ -519,7 +524,7 @@ bool DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::TransferDataFromWindow() { KICAD_T itemType = boardItem->Type(); - if( itemType == PCB_TEXT_T ) + if( itemType == PCB_TEXT_T || itemType == PCB_TEXTBOX_T ) { if( m_boardText->GetValue() ) visitItem( commit, boardItem ); diff --git a/pcbnew/dialogs/dialog_textbox_properties.cpp b/pcbnew/dialogs/dialog_textbox_properties.cpp new file mode 100644 index 0000000000..ac3ce0e399 --- /dev/null +++ b/pcbnew/dialogs/dialog_textbox_properties.cpp @@ -0,0 +1,340 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 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 +#include +#include +#include +#include // for KiROUND +#include +#include "macros.h" + +DIALOG_TEXTBOX_PROPERTIES::DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, + BOARD_ITEM* aItem ) : + DIALOG_TEXTBOX_PROPERTIES_BASE( aParent ), + m_frame( aParent ), + m_item( aItem ), + m_edaText( nullptr ), + m_fpTextBox( nullptr ), + m_pcbTextBox( nullptr ), + m_textWidth( aParent, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits ), + m_textHeight( aParent, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits ), + m_thickness( aParent, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits ), + m_orientation( aParent, m_OrientLabel, m_OrientCtrl, nullptr ) +{ + m_MultiLineText->SetEOLMode( wxSTC_EOL_LF ); + + m_scintillaTricks = new SCINTILLA_TRICKS( m_MultiLineText, wxT( "{}" ), false, + [this]() + { + wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) ); + } ); + + // A hack which causes Scintilla to auto-size the text editor canvas + // See: https://github.com/jacobslusser/ScintillaNET/issues/216 + m_MultiLineText->SetScrollWidth( 1 ); + m_MultiLineText->SetScrollWidthTracking( true ); + + if( m_item->Type() == PCB_FP_TEXTBOX_T ) + { + m_fpTextBox = static_cast( m_item ); + m_edaText = m_fpTextBox; + + // Do not allow locking items in the footprint editor + m_cbLocked->Show( false ); + } + else if( m_item->Type() == PCB_TEXTBOX_T ) + { + m_pcbTextBox = static_cast( m_item ); + m_edaText = m_pcbTextBox; + } + else + { + UNIMPLEMENTED_FOR( m_item->GetClass() ); + } + + SetInitialFocus( m_MultiLineText ); + + m_separator0->SetIsSeparator(); + + m_bold->SetIsCheckButton(); + m_bold->SetBitmap( KiBitmap( BITMAPS::text_bold ) ); + m_italic->SetIsCheckButton(); + m_italic->SetBitmap( KiBitmap( BITMAPS::text_italic ) ); + + m_separator1->SetIsSeparator(); + + m_alignLeft->SetIsCheckButton(); + m_alignLeft->SetBitmap( KiBitmap( BITMAPS::text_align_left ) ); + m_alignCenter->SetIsCheckButton(); + m_alignCenter->SetBitmap( KiBitmap( BITMAPS::text_align_center ) ); + m_alignRight->SetIsCheckButton(); + m_alignRight->SetBitmap( KiBitmap( BITMAPS::text_align_right ) ); + + m_separator2->SetIsSeparator(); + + m_mirrored->SetIsCheckButton(); + m_mirrored->SetBitmap( KiBitmap( BITMAPS::text_mirrored ) ); + + m_separator3->SetIsSeparator(); + + // Configure the layers list selector. Note that footprints are built outside the current + // board and so we may need to show all layers if the text is on an unactivated layer. + if( !m_frame->GetBoard()->IsLayerEnabled( m_item->GetLayer() ) ) + m_LayerSelectionCtrl->ShowNonActivatedLayers( true ); + + m_LayerSelectionCtrl->SetLayersHotkeys( false ); + m_LayerSelectionCtrl->SetBoardFrame( m_frame ); + m_LayerSelectionCtrl->Resync(); + + m_orientation.SetUnits( EDA_UNITS::DEGREES ); + m_orientation.SetPrecision( 3 ); + + // Set predefined rotations in combo dropdown, according to the locale floating point + // separator notation + double rot_list[] = { 0.0, 90.0, -90.0, 180.0 }; + + for( size_t ii = 0; ii < m_OrientCtrl->GetCount() && ii < 4; ++ii ) + m_OrientCtrl->SetString( ii, wxString::Format( "%.1f", rot_list[ii] ) ); + + SetupStandardButtons(); + + // wxTextCtrls fail to generate wxEVT_CHAR events when the wxTE_MULTILINE flag is set, + // so we have to listen to wxEVT_CHAR_HOOK events instead. + Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXTBOX_PROPERTIES::OnCharHook ), + nullptr, this ); + + finishDialogSettings(); +} + + +DIALOG_TEXTBOX_PROPERTIES::~DIALOG_TEXTBOX_PROPERTIES() +{ + Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TEXTBOX_PROPERTIES::OnCharHook ), + nullptr, this ); + + delete m_scintillaTricks; +} + + +int PCB_BASE_EDIT_FRAME::ShowTextBoxPropertiesDialog( BOARD_ITEM* aText ) +{ + DIALOG_TEXTBOX_PROPERTIES dlg( this, aText ); + return dlg.ShowQuasiModal(); +} + + +bool DIALOG_TEXTBOX_PROPERTIES::TransferDataToWindow() +{ + BOARD* board = m_frame->GetBoard(); + wxString converted = board->ConvertKIIDsToCrossReferences( + UnescapeString( m_edaText->GetText() ) ); + + m_MultiLineText->SetValue( converted ); + m_MultiLineText->SetSelection( -1, -1 ); + + m_cbLocked->SetValue( m_item->IsLocked() ); + + m_LayerSelectionCtrl->SetLayerSelection( m_item->GetLayer() ); + + m_fontCtrl->SetFontSelection( m_edaText->GetFont() ); + + m_textWidth.SetValue( m_edaText->GetTextSize().x ); + m_textHeight.SetValue( m_edaText->GetTextSize().y ); + m_thickness.SetValue( m_edaText->GetTextThickness() ); + + m_bold->Check( m_edaText->IsBold() ); + m_italic->Check( m_edaText->IsItalic() ); + + switch ( m_edaText->GetHorizJustify() ) + { + case GR_TEXT_H_ALIGN_LEFT: m_alignLeft->Check( true ); break; + case GR_TEXT_H_ALIGN_CENTER: m_alignCenter->Check( true ); break; + case GR_TEXT_H_ALIGN_RIGHT: m_alignRight->Check( true ); break; + } + + m_mirrored->Check( m_edaText->IsMirrored() ); + + m_orientation.SetAngleValue( m_edaText->GetTextAngle() ); + + return DIALOG_TEXTBOX_PROPERTIES_BASE::TransferDataToWindow(); +} + + +void DIALOG_TEXTBOX_PROPERTIES::onFontSelected( wxCommandEvent & aEvent ) +{ + if( KIFONT::FONT::IsStroke( aEvent.GetString() ) ) + { + m_thickness.Show( true ); + + int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() ); + int thickness = m_thickness.GetValue(); + + m_bold->Check( abs( thickness - GetPenSizeForBold( textSize ) ) + < abs( thickness - GetPenSizeForNormal( textSize ) ) ); + } + else + { + m_thickness.Show( false ); + } +} + + +void DIALOG_TEXTBOX_PROPERTIES::onBoldToggle( wxCommandEvent & aEvent ) +{ + int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() ); + + if( aEvent.IsChecked() ) + m_thickness.ChangeValue( GetPenSizeForBold( textSize ) ); + else + m_thickness.ChangeValue( GetPenSizeForNormal( textSize ) ); + + aEvent.Skip(); +} + + +void DIALOG_TEXTBOX_PROPERTIES::onAlignButton( wxCommandEvent& aEvent ) +{ + for( BITMAP_BUTTON* btn : { m_alignLeft, m_alignCenter, m_alignRight } ) + { + if( btn->IsChecked() && btn != aEvent.GetEventObject() ) + btn->Check( false ); + } +} + + +void DIALOG_TEXTBOX_PROPERTIES::onThickness( wxCommandEvent& event ) +{ + int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() ); + int thickness = m_thickness.GetValue(); + + m_bold->Check( abs( thickness - GetPenSizeForBold( textSize ) ) + < abs( thickness - GetPenSizeForNormal( textSize ) ) ); +} + + +bool DIALOG_TEXTBOX_PROPERTIES::TransferDataFromWindow() +{ + if( !DIALOG_TEXTBOX_PROPERTIES_BASE::TransferDataFromWindow() ) + return false; + + if( !m_textWidth.Validate( TEXTS_MIN_SIZE, TEXTS_MAX_SIZE ) + || !m_textHeight.Validate( TEXTS_MIN_SIZE, TEXTS_MAX_SIZE ) ) + { + return false; + } + + BOARD_COMMIT commit( m_frame ); + commit.Modify( m_item ); + + // If no other command in progress, prepare undo command + // (for a command in progress, will be made later, at the completion of command) + bool pushCommit = ( m_item->GetEditFlags() == 0 ); + + // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to + // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc.... + if( !pushCommit ) + m_item->SetFlags( IN_EDIT ); + + // Set the new text content + if( !m_MultiLineText->GetValue().IsEmpty() ) + { + BOARD* board = m_frame->GetBoard(); + wxString txt = board->ConvertCrossReferencesToKIIDs( m_MultiLineText->GetValue() ); + +#ifdef __WXMAC__ + // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting. + // Replace it now. + txt.Replace( "\r", "\n" ); +#elif defined( __WINDOWS__ ) + // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in + // drawing routines so strip the \r char. + txt.Replace( "\r", "" ); +#endif + m_edaText->SetText( EscapeString( txt, CTX_QUOTED_STR ) ); + } + + m_item->SetLocked( m_cbLocked->GetValue() ); + + m_item->SetLayer( ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() ) ); + + if( m_fontCtrl->HaveFontSelection() ) + { + m_edaText->SetFont( m_fontCtrl->GetFontSelection( m_bold->IsChecked(), + m_italic->IsChecked() ) ); + } + + m_edaText->SetTextSize( wxSize( m_textWidth.GetValue(), m_textHeight.GetValue() ) ); + m_edaText->SetTextThickness( m_thickness.GetValue() ); + + if( m_fpTextBox ) + m_fpTextBox->SetLocalCoord(); + + // Test for acceptable values for thickness and size and clamp if fails + int maxPenWidth = Clamp_Text_PenSize( m_edaText->GetTextThickness(), m_edaText->GetTextSize() ); + + if( m_edaText->GetTextThickness() > maxPenWidth ) + { + DisplayError( this, _( "The text thickness is too large for the text size.\n" + "It will be clamped." ) ); + m_edaText->SetTextThickness( maxPenWidth ); + } + + m_edaText->SetTextAngle( m_orientation.GetAngleValue() ); + m_edaText->SetBold( m_bold->IsChecked() ); + m_edaText->SetItalic( m_italic->IsChecked() ); + + if( m_alignLeft->IsChecked() ) + m_edaText->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + else if( m_alignCenter->IsChecked() ) + m_edaText->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER ); + else + m_edaText->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT ); + + m_edaText->SetMirrored( m_mirrored->IsChecked() ); + + if( pushCommit ) + commit.Push( _( "Change text box properties" ) ); + + return true; +} + + +void DIALOG_TEXTBOX_PROPERTIES::onMultiLineTCLostFocus( wxFocusEvent& event ) +{ + if( m_scintillaTricks ) + m_scintillaTricks->CancelAutocomplete(); + + event.Skip(); +} diff --git a/pcbnew/dialogs/dialog_textbox_properties.h b/pcbnew/dialogs/dialog_textbox_properties.h new file mode 100644 index 0000000000..9f2c354a90 --- /dev/null +++ b/pcbnew/dialogs/dialog_textbox_properties.h @@ -0,0 +1,73 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 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_TEXTBOX_PROPERTIES_H +#define DIALOG_TEXTBOX_PROPERTIES_H + +#include +#include + +#include + + +class PCB_BASE_EDIT_FRAME; +class BOARD_ITEM; +class EDA_TEXT; +class FP_TEXTBOX; +class PCB_TEXTBOX; +class SCINTILLA_TRICKS; + + +class DIALOG_TEXTBOX_PROPERTIES : public DIALOG_TEXTBOX_PROPERTIES_BASE +{ +public: + DIALOG_TEXTBOX_PROPERTIES( PCB_BASE_EDIT_FRAME* aParent, BOARD_ITEM* aItem ); + ~DIALOG_TEXTBOX_PROPERTIES(); + +private: + void onFontSelected( wxCommandEvent &aEvent ) override; + void onBoldToggle( wxCommandEvent &aEvent ) override; + void onAlignButton( wxCommandEvent &aEvent ) override; + void onThickness( wxCommandEvent &aEvent ) override; + + bool TransferDataToWindow() override; + bool TransferDataFromWindow() override; + void onMultiLineTCLostFocus( wxFocusEvent& event ) override; + +private: + PCB_BASE_EDIT_FRAME* m_frame; + BOARD_ITEM* m_item; // FP_TEXTBOX or PCB_TEXTBOX + EDA_TEXT* m_edaText; // always non-null + FP_TEXTBOX* m_fpTextBox; // only non-null for FP_TEXTBOXes + PCB_TEXTBOX* m_pcbTextBox; // only non-null for PCB_TEXTBOXes + + UNIT_BINDER m_textWidth; + UNIT_BINDER m_textHeight; + UNIT_BINDER m_thickness; + UNIT_BINDER m_orientation; // rotation in degrees + + SCINTILLA_TRICKS* m_scintillaTricks; +}; + + +#endif //DIALOG_TEXTBOX_PROPERTIES_H diff --git a/pcbnew/dialogs/dialog_textbox_properties_base.cpp b/pcbnew/dialogs/dialog_textbox_properties_base.cpp new file mode 100644 index 0000000000..bba3f9e926 --- /dev/null +++ b/pcbnew/dialogs/dialog_textbox_properties_base.cpp @@ -0,0 +1,274 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 26 2018) +// http://www.wxformbuilder.org/ +// +// PLEASE DO *NOT* EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "pcb_layer_box_selector.h" +#include "widgets/bitmap_button.h" +#include "widgets/font_choice.h" + +#include "dialog_textbox_properties_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_TEXTBOX_PROPERTIES_BASE::DIALOG_TEXTBOX_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( wxSize( -1,-1 ), wxDefaultSize ); + + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + m_MultiLineSizer = new wxBoxSizer( wxVERTICAL ); + + wxStaticText* textLabel; + textLabel = new wxStaticText( this, wxID_ANY, _("Text:"), wxDefaultPosition, wxDefaultSize, 0 ); + textLabel->Wrap( -1 ); + m_MultiLineSizer->Add( textLabel, 0, wxRIGHT|wxLEFT, 5 ); + + m_MultiLineText = new wxStyledTextCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString ); + m_MultiLineText->SetUseTabs( true ); + m_MultiLineText->SetTabWidth( 4 ); + m_MultiLineText->SetIndent( 4 ); + m_MultiLineText->SetTabIndents( false ); + m_MultiLineText->SetBackSpaceUnIndents( false ); + m_MultiLineText->SetViewEOL( false ); + m_MultiLineText->SetViewWhiteSpace( false ); + m_MultiLineText->SetMarginWidth( 2, 0 ); + m_MultiLineText->SetIndentationGuides( true ); + m_MultiLineText->SetMarginWidth( 1, 0 ); + m_MultiLineText->SetMarginWidth( 0, 0 ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS ); + m_MultiLineText->MarkerSetBackground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("BLACK") ) ); + m_MultiLineText->MarkerSetForeground( wxSTC_MARKNUM_FOLDER, wxColour( wxT("WHITE") ) ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS ); + m_MultiLineText->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("BLACK") ) ); + m_MultiLineText->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPEN, wxColour( wxT("WHITE") ) ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUS ); + m_MultiLineText->MarkerSetBackground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("BLACK") ) ); + m_MultiLineText->MarkerSetForeground( wxSTC_MARKNUM_FOLDEREND, wxColour( wxT("WHITE") ) ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUS ); + m_MultiLineText->MarkerSetBackground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("BLACK") ) ); + m_MultiLineText->MarkerSetForeground( wxSTC_MARKNUM_FOLDEROPENMID, wxColour( wxT("WHITE") ) ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY ); + m_MultiLineText->MarkerDefine( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY ); + m_MultiLineText->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) ); + m_MultiLineText->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) ); + m_MultiLineText->SetToolTip( _("Enter the text placed on selected layer.") ); + m_MultiLineText->SetMinSize( wxSize( -1,150 ) ); + + m_MultiLineSizer->Add( m_MultiLineText, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + + bMainSizer->Add( m_MultiLineSizer, 20, wxEXPAND|wxALL, 10 ); + + wxGridBagSizer* gbSizer1; + gbSizer1 = new wxGridBagSizer( 3, 5 ); + gbSizer1->SetFlexibleDirection( wxBOTH ); + gbSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + gbSizer1->SetEmptyCellSize( wxSize( 20,8 ) ); + + m_cbLocked = new wxCheckBox( this, wxID_ANY, _("Locked"), wxDefaultPosition, wxDefaultSize, 0 ); + gbSizer1->Add( m_cbLocked, wxGBPosition( 0, 0 ), wxGBSpan( 1, 3 ), wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_LayerLabel = new wxStaticText( this, wxID_ANY, _("Layer:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_LayerLabel->Wrap( -1 ); + gbSizer1->Add( m_LayerLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 ); + + m_LayerSelectionCtrl = new PCB_LAYER_BOX_SELECTOR( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + gbSizer1->Add( m_LayerSelectionCtrl, wxGBPosition( 1, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_fontLabel = new wxStaticText( this, wxID_ANY, _("Font:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_fontLabel->Wrap( -1 ); + gbSizer1->Add( m_fontLabel, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); + + wxString m_fontCtrlChoices[] = { _("KiCad Font") }; + int m_fontCtrlNChoices = sizeof( m_fontCtrlChoices ) / sizeof( wxString ); + m_fontCtrl = new FONT_CHOICE( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_fontCtrlNChoices, m_fontCtrlChoices, 0 ); + m_fontCtrl->SetSelection( 0 ); + gbSizer1->Add( m_fontCtrl, wxGBPosition( 3, 1 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL, 5 ); + + wxBoxSizer* bSizerButtonBar; + bSizerButtonBar = new wxBoxSizer( wxHORIZONTAL ); + + m_separator0 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + m_separator0->Enable( false ); + + bSizerButtonBar->Add( m_separator0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bold = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + bSizerButtonBar->Add( m_bold, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_italic = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + bSizerButtonBar->Add( m_italic, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_separator1 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + m_separator1->Enable( false ); + + bSizerButtonBar->Add( m_separator1, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_alignLeft = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + bSizerButtonBar->Add( m_alignLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_alignCenter = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + bSizerButtonBar->Add( m_alignCenter, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_alignRight = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + bSizerButtonBar->Add( m_alignRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_separator2 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + m_separator2->Enable( false ); + + bSizerButtonBar->Add( m_separator2, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_mirrored = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + bSizerButtonBar->Add( m_mirrored, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_separator3 = new BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 21,21 ), wxBU_AUTODRAW|wxBORDER_NONE ); + m_separator3->Enable( false ); + + bSizerButtonBar->Add( m_separator3, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + gbSizer1->Add( bSizerButtonBar, wxGBPosition( 3, 4 ), wxGBSpan( 1, 3 ), wxEXPAND|wxALIGN_CENTER_VERTICAL|wxRIGHT, 8 ); + + m_SizeXLabel = new wxStaticText( this, wxID_ANY, _("Text Width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeXLabel->Wrap( -1 ); + m_SizeXLabel->SetToolTip( _("Text width") ); + + gbSizer1->Add( m_SizeXLabel, wxGBPosition( 4, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_SizeXCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + gbSizer1->Add( m_SizeXCtrl, wxGBPosition( 4, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_SizeXUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeXUnits->Wrap( -1 ); + gbSizer1->Add( m_SizeXUnits, wxGBPosition( 4, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + + m_SizeYLabel = new wxStaticText( this, wxID_ANY, _("Text Height:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeYLabel->Wrap( -1 ); + m_SizeYLabel->SetToolTip( _("Text height") ); + + gbSizer1->Add( m_SizeYLabel, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_SizeYCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + gbSizer1->Add( m_SizeYCtrl, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_SizeYUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeYUnits->Wrap( -1 ); + gbSizer1->Add( m_SizeYUnits, wxGBPosition( 5, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + + m_ThicknessLabel = new wxStaticText( this, wxID_ANY, _("Thickness:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ThicknessLabel->Wrap( -1 ); + m_ThicknessLabel->SetToolTip( _("Text thickness") ); + + gbSizer1->Add( m_ThicknessLabel, wxGBPosition( 6, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_ThicknessCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER ); + gbSizer1->Add( m_ThicknessCtrl, wxGBPosition( 6, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + + m_ThicknessUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_ThicknessUnits->Wrap( -1 ); + gbSizer1->Add( m_ThicknessUnits, wxGBPosition( 6, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + + m_OrientLabel = new wxStaticText( this, wxID_ANY, _("Orientation:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_OrientLabel->Wrap( -1 ); + m_OrientLabel->SetToolTip( _("Text orientation") ); + + gbSizer1->Add( m_OrientLabel, wxGBPosition( 1, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_OrientCtrl = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + m_OrientCtrl->Append( _("0.0") ); + m_OrientCtrl->Append( _("90.0") ); + m_OrientCtrl->Append( _("-90.0") ); + m_OrientCtrl->Append( _("180.0") ); + gbSizer1->Add( m_OrientCtrl, wxGBPosition( 1, 5 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT, 5 ); + + m_borderWidthLabel = new wxStaticText( this, wxID_ANY, _("Border Width:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_borderWidthLabel->Wrap( -1 ); + gbSizer1->Add( m_borderWidthLabel, wxGBPosition( 5, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_borderWidthCtrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + gbSizer1->Add( m_borderWidthCtrl, wxGBPosition( 5, 5 ), wxGBSpan( 1, 1 ), wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); + + m_borderWidthUnits = new wxStaticText( this, wxID_ANY, _("unit"), wxDefaultPosition, wxDefaultSize, 0 ); + m_borderWidthUnits->Wrap( -1 ); + gbSizer1->Add( m_borderWidthUnits, wxGBPosition( 5, 6 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL, 5 ); + + m_borderStyleLabel = new wxStaticText( this, wxID_ANY, _("Border Style:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_borderStyleLabel->Wrap( -1 ); + gbSizer1->Add( m_borderStyleLabel, wxGBPosition( 6, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + + m_borderStyleCombo = new wxBitmapComboBox( this, wxID_ANY, _("Combo!"), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY ); + m_borderStyleCombo->SetMinSize( wxSize( 240,-1 ) ); + + gbSizer1->Add( m_borderStyleCombo, wxGBPosition( 6, 5 ), wxGBSpan( 1, 2 ), wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + + + gbSizer1->AddGrowableCol( 1 ); + gbSizer1->AddGrowableCol( 5 ); + + bMainSizer->Add( gbSizer1, 0, wxRIGHT|wxLEFT|wxEXPAND, 10 ); + + m_staticline = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bMainSizer->Add( m_staticline, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 ); + + wxBoxSizer* lowerSizer; + lowerSizer = new wxBoxSizer( wxHORIZONTAL ); + + + lowerSizer->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer->AddButton( m_sdbSizerCancel ); + m_sdbSizer->Realize(); + + lowerSizer->Add( m_sdbSizer, 0, wxALL, 5 ); + + + bMainSizer->Add( lowerSizer, 0, wxEXPAND, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + this->Centre( wxBOTH ); + + // Connect Events + this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnInitDlg ) ); + m_MultiLineText->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onMultiLineTCLostFocus ), NULL, this ); + m_fontCtrl->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onFontSelected ), NULL, this ); + m_bold->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onBoldToggle ), NULL, this ); + m_alignLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onAlignButton ), NULL, this ); + m_alignCenter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onAlignButton ), NULL, this ); + m_alignRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onAlignButton ), NULL, this ); + m_SizeXCtrl->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + m_SizeYCtrl->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + m_ThicknessCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onThickness ), NULL, this ); + m_OrientCtrl->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); +} + +DIALOG_TEXTBOX_PROPERTIES_BASE::~DIALOG_TEXTBOX_PROPERTIES_BASE() +{ + // Disconnect Events + this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnInitDlg ) ); + m_MultiLineText->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onMultiLineTCLostFocus ), NULL, this ); + m_fontCtrl->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onFontSelected ), NULL, this ); + m_bold->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onBoldToggle ), NULL, this ); + m_alignLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onAlignButton ), NULL, this ); + m_alignCenter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onAlignButton ), NULL, this ); + m_alignRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onAlignButton ), NULL, this ); + m_SizeXCtrl->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + m_SizeYCtrl->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + m_ThicknessCtrl->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::onThickness ), NULL, this ); + m_OrientCtrl->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_TEXTBOX_PROPERTIES_BASE::OnOkClick ), NULL, this ); + +} diff --git a/pcbnew/dialogs/dialog_textbox_properties_base.fbp b/pcbnew/dialogs/dialog_textbox_properties_base.fbp new file mode 100644 index 0000000000..85802a3078 --- /dev/null +++ b/pcbnew/dialogs/dialog_textbox_properties_base.fbp @@ -0,0 +1,2436 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_textbox_properties_base + 1000 + none + + 1 + DIALOG_TEXTBOX_PROPERTIES_BASE + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + -1,-1 + DIALOG_TEXTBOX_PROPERTIES_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU + DIALOG_SHIM; dialog_shim.h + Text Box Properties + + + + + OnInitDlg + + + bMainSizer + wxVERTICAL + none + + 10 + wxEXPAND|wxALL + 20 + + -1,-1 + m_MultiLineSizer + wxVERTICAL + protected + + 5 + wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text: + 0 + + 0 + + + 0 + + 1 + textLabel + 1 + + + none + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + 0 + + 0 + 0 + wxID_ANY + 1 + 0 + + 0 + + + 0 + -1,150 + 1 + m_MultiLineText + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + 4 + 0 + Enter the text placed on selected layer. + 1 + 0 + 0 + + + + onMultiLineTCLostFocus + + + + + + 10 + wxRIGHT|wxLEFT|wxEXPAND + 0 + + 20,8 + wxBOTH + 1,5 + + 5 + + gbSizer1 + wxFLEX_GROWMODE_SPECIFIED + none + 3 + + 5 + 3 + 0 + wxBOTTOM|wxRIGHT|wxLEFT + 0 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Locked + + 0 + + + 0 + + 1 + m_cbLocked + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT + 1 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Layer: + 0 + + 0 + + + 0 + + 1 + m_LayerLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + 2 + 1 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 1 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_LayerSelectionCtrl + 1 + + + protected + 1 + + Resizable + -1 + 1 + + + PCB_LAYER_BOX_SELECTOR; pcb_layer_box_selector.h + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 3 + 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 + 2 + 1 + wxALIGN_CENTER_VERTICAL + 3 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "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 + + + + + onFontSelected + + + + 8 + 3 + 4 + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxRIGHT + 3 + 1 + + + bSizerButtonBar + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + + 1 + + + 0 + 0 + wxID_ANY + + + 0 + + 0 + + + 0 + + 1 + m_separator0 + 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 + + + + + + + + + 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 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onBoldToggle + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 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 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 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 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Left + + 0 + + 0 + + + 0 + + 1 + m_alignLeft + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onAlignButton + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Center + + 0 + + 0 + + + 0 + + 1 + m_alignCenter + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onAlignButton + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Right + + 0 + + 0 + + + 0 + + 1 + m_alignRight + 1 + + + protected + 1 + + + + Resizable + 1 + 21,21 + wxBORDER_NONE + BITMAP_BUTTON; widgets/bitmap_button.h; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onAlignButton + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + + 1 + + + 0 + 0 + wxID_ANY + MyButton + + 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 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Mirrored + + 0 + + 0 + + + 0 + + 1 + m_mirrored + 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 + + + + + + + + + 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 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxLEFT + 4 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text Width: + 0 + + 0 + + + 0 + + 1 + m_SizeXLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Text width + + + + -1 + + + + 5 + 1 + 1 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 4 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_SizeXCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnOkClick + + + + 5 + 1 + 2 + wxALIGN_CENTER_VERTICAL + 4 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + 0 + + 0 + + + 0 + + 1 + m_SizeXUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxLEFT + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Text Height: + 0 + + 0 + + + 0 + + 1 + m_SizeYLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Text height + + + + -1 + + + + 5 + 1 + 1 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_SizeYCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnOkClick + + + + 5 + 1 + 2 + wxALIGN_CENTER_VERTICAL + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + 0 + + 0 + + + 0 + + 1 + m_SizeYUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + 5 + 1 + 0 + wxALIGN_CENTER_VERTICAL|wxLEFT + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Thickness: + 0 + + 0 + + + 0 + + 1 + m_ThicknessLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Text thickness + + + + -1 + + + + 5 + 1 + 1 + wxALIGN_CENTER_VERTICAL|wxEXPAND + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_ThicknessCtrl + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + onThickness + + + + 5 + 1 + 2 + wxALIGN_CENTER_VERTICAL + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + 0 + + 0 + + + 0 + + 1 + m_ThicknessUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + + + + + -1 + + + + 5 + 1 + 4 + wxALIGN_CENTER_VERTICAL|wxLEFT + 1 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Orientation: + 0 + + 0 + + + 0 + + 1 + m_OrientLabel + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Text orientation + + + + -1 + + + + 5 + 2 + 5 + wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT + 1 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "0.0" "90.0" "-90.0" "180.0" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_OrientCtrl + 1 + + + protected + 1 + + Resizable + -1 + 1 + + + ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + OnOkClick + + + + 5 + 1 + 4 + wxALIGN_CENTER_VERTICAL|wxLEFT + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Border Width: + 0 + + 0 + + + 0 + + 1 + m_borderWidthLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 1 + 5 + wxEXPAND|wxALIGN_CENTER_VERTICAL + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_borderWidthCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + 1 + 6 + wxALIGN_CENTER_VERTICAL + 5 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + unit + 0 + + 0 + + + 0 + + 1 + m_borderWidthUnits + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 1 + 4 + wxALIGN_CENTER_VERTICAL|wxLEFT + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Border Style: + 0 + + 0 + + + 0 + + 1 + m_borderStyleLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 2 + 5 + wxALIGN_CENTER_VERTICAL|wxRIGHT + 6 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + 240,-1 + 1 + m_borderStyleCombo + 1 + + + protected + 1 + + Resizable + -1 + 1 + + wxCB_READONLY + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Combo! + + + + + + + + + 10 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + + 0 + + + + + + + + 5 + wxEXPAND + 0 + + + lowerSizer + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + OnOkClick + + + + + + + + diff --git a/pcbnew/dialogs/dialog_textbox_properties_base.h b/pcbnew/dialogs/dialog_textbox_properties_base.h new file mode 100644 index 0000000000..15cafec75d --- /dev/null +++ b/pcbnew/dialogs/dialog_textbox_properties_base.h @@ -0,0 +1,105 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 26 2018) +// http://www.wxformbuilder.org/ +// +// PLEASE DO *NOT* EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include +class BITMAP_BUTTON; +class FONT_CHOICE; +class PCB_LAYER_BOX_SELECTOR; + +#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 + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_TEXTBOX_PROPERTIES_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_TEXTBOX_PROPERTIES_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxBoxSizer* m_MultiLineSizer; + wxStyledTextCtrl* m_MultiLineText; + wxCheckBox* m_cbLocked; + wxStaticText* m_LayerLabel; + PCB_LAYER_BOX_SELECTOR* m_LayerSelectionCtrl; + wxStaticText* m_fontLabel; + FONT_CHOICE* m_fontCtrl; + BITMAP_BUTTON* m_separator0; + BITMAP_BUTTON* m_bold; + BITMAP_BUTTON* m_italic; + BITMAP_BUTTON* m_separator1; + BITMAP_BUTTON* m_alignLeft; + BITMAP_BUTTON* m_alignCenter; + BITMAP_BUTTON* m_alignRight; + BITMAP_BUTTON* m_separator2; + BITMAP_BUTTON* m_mirrored; + BITMAP_BUTTON* m_separator3; + wxStaticText* m_SizeXLabel; + wxTextCtrl* m_SizeXCtrl; + wxStaticText* m_SizeXUnits; + wxStaticText* m_SizeYLabel; + wxTextCtrl* m_SizeYCtrl; + wxStaticText* m_SizeYUnits; + wxStaticText* m_ThicknessLabel; + wxTextCtrl* m_ThicknessCtrl; + wxStaticText* m_ThicknessUnits; + wxStaticText* m_OrientLabel; + wxComboBox* m_OrientCtrl; + wxStaticText* m_borderWidthLabel; + wxTextCtrl* m_borderWidthCtrl; + wxStaticText* m_borderWidthUnits; + wxStaticText* m_borderStyleLabel; + wxBitmapComboBox* m_borderStyleCombo; + wxStaticLine* m_staticline; + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + wxButton* m_sdbSizerCancel; + + // Virtual event handlers, overide them in your derived class + virtual void OnInitDlg( wxInitDialogEvent& event ) { event.Skip(); } + virtual void onMultiLineTCLostFocus( wxFocusEvent& event ) { event.Skip(); } + virtual void onFontSelected( wxCommandEvent& event ) { event.Skip(); } + virtual void onBoldToggle( wxCommandEvent& event ) { event.Skip(); } + virtual void onAlignButton( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); } + virtual void onThickness( wxCommandEvent& event ) { event.Skip(); } + + + public: + + DIALOG_TEXTBOX_PROPERTIES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Text Box Properties"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSYSTEM_MENU ); + ~DIALOG_TEXTBOX_PROPERTIES_BASE(); + +}; + diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index ad11d1a303..e4ba965d5a 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -995,7 +995,9 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break; case PCB_FP_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break; case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break; + case PCB_TEXTBOX_T: mask = DRC_DISALLOW_TEXTS; break; case PCB_FP_TEXT_T: mask = DRC_DISALLOW_TEXTS; break; + case PCB_FP_TEXTBOX_T: mask = DRC_DISALLOW_TEXTS; break; case PCB_ZONE_T: mask = DRC_DISALLOW_ZONES; break; case PCB_FP_ZONE_T: mask = DRC_DISALLOW_ZONES; break; case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break; diff --git a/pcbnew/drc/drc_test_provider.cpp b/pcbnew/drc/drc_test_provider.cpp index 0ec5827bb3..d1e612893c 100644 --- a/pcbnew/drc/drc_test_provider.cpp +++ b/pcbnew/drc/drc_test_provider.cpp @@ -208,7 +208,8 @@ int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector& aTypes, n++; } - else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T ) + else if( typeMask[ PCB_TEXT_T ] + && ( item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T ) ) { if( !aFunc( item ) ) return n; @@ -287,7 +288,8 @@ int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector& aTypes, n++; } - else if( typeMask[ PCB_FP_TEXT_T ] && dwg->Type() == PCB_FP_TEXT_T ) + else if( typeMask[ PCB_FP_TEXT_T ] + && ( dwg->Type() == PCB_FP_TEXT_T || dwg->Type() == PCB_FP_TEXTBOX_T ) ) { if( !aFunc( dwg ) ) return n; diff --git a/pcbnew/drc/drc_test_provider_disallow.cpp b/pcbnew/drc/drc_test_provider_disallow.cpp index b47606a7f7..63d727f37d 100644 --- a/pcbnew/drc/drc_test_provider_disallow.cpp +++ b/pcbnew/drc/drc_test_provider_disallow.cpp @@ -99,7 +99,9 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run() if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TEXT_ON_EDGECUTS ) && item->GetLayer() == Edge_Cuts ) { - if( item->Type() == PCB_TEXT_T || BaseType( item->Type() ) == PCB_DIMENSION_T ) + if( item->Type() == PCB_TEXT_T + || item->Type() == PCB_TEXTBOX_T + || BaseType( item->Type() ) == PCB_DIMENSION_T ) { std::shared_ptr drc = DRC_ITEM::Create( DRCE_TEXT_ON_EDGECUTS ); drc->SetItems( item ); diff --git a/pcbnew/drc/drc_test_provider_text_dims.cpp b/pcbnew/drc/drc_test_provider_text_dims.cpp index f959385306..eca9be4ef2 100644 --- a/pcbnew/drc/drc_test_provider_text_dims.cpp +++ b/pcbnew/drc/drc_test_provider_text_dims.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2021 KiCad Developers. + * Copyright (C) 2021-2022 KiCad Developers. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,7 +23,9 @@ #include #include +#include #include +#include #include #include #include @@ -104,32 +106,31 @@ bool DRC_TEST_PROVIDER_TEXT_DIMS::Run() if( !reportProgress( ii++, count, delta ) ) return false; - wxASSERT( item->Type() == PCB_TEXT_T || item->Type() == PCB_FP_TEXT_T ); + wxASSERT( item->Type() == PCB_TEXT_T + || item->Type() == PCB_TEXTBOX_T + || item->Type() == PCB_FP_TEXT_T + || item->Type() == PCB_FP_TEXTBOX_T ); DRC_CONSTRAINT constraint; int actualH = 0; int actualT = 0; bool visible = false; - if( item->Type() == PCB_TEXT_T ) + EDA_TEXT* text = nullptr; + + switch( item->Type() ) { - PCB_TEXT* textItem = static_cast( item ); - visible = textItem->IsVisible(); - actualH = textItem->GetTextHeight(); - actualT = textItem->GetTextThickness(); - } - else if( item->Type() == PCB_FP_TEXT_T ) - { - FP_TEXT* fpTextItem = static_cast( item ); - visible = fpTextItem->IsVisible(); - actualH = fpTextItem->GetTextHeight(); - actualT = fpTextItem->GetTextThickness(); - } - else - { - UNIMPLEMENTED_FOR( item->GetClass() ); + case PCB_TEXT_T: text = static_cast( item ); break; + case PCB_TEXTBOX_T: text = static_cast( item ); break; + case PCB_FP_TEXT_T: text = static_cast( item ); break; + case PCB_FP_TEXTBOX_T: text = static_cast( item ); break; + default: UNIMPLEMENTED_FOR( item->GetClass() ); break; } + visible = text->IsVisible(); + actualH = text->GetTextHeight(); + actualT = text->GetTextThickness(); + if( !visible ) return true; diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index 0b491278fb..de107c7e0f 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -120,9 +120,15 @@ void PCB_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem ) switch( aItem->Type() ) { case PCB_TEXT_T: + case PCB_FP_TEXT_T: ShowTextPropertiesDialog( aItem ); break; + case PCB_TEXTBOX_T: + case PCB_FP_TEXTBOX_T: + ShowTextBoxPropertiesDialog( aItem ); + break; + case PCB_PAD_T: ShowPadPropertiesDialog( static_cast( aItem ) ); break; @@ -146,10 +152,6 @@ void PCB_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem ) break; } - case PCB_FP_TEXT_T: - ShowTextPropertiesDialog( aItem ); - break; - case PCB_SHAPE_T: ShowGraphicItemPropertiesDialog( aItem ); break; diff --git a/pcbnew/exporters/export_gencad.cpp b/pcbnew/exporters/export_gencad.cpp index 7fd6164141..7eb5e67a99 100644 --- a/pcbnew/exporters/export_gencad.cpp +++ b/pcbnew/exporters/export_gencad.cpp @@ -1213,6 +1213,7 @@ static void FootprintWriteShape( FILE* aFile, FOOTPRINT* aFootprint, const wxStr switch( PtStruct->Type() ) { case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: // If we wanted to export text, this is not the correct section break; diff --git a/pcbnew/exporters/gen_drill_report_files.cpp b/pcbnew/exporters/gen_drill_report_files.cpp index 7194dc9c64..12d47eaa9b 100644 --- a/pcbnew/exporters/gen_drill_report_files.cpp +++ b/pcbnew/exporters/gen_drill_report_files.cpp @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include /* Conversion utilities - these will be used often in there... */ @@ -197,11 +200,16 @@ bool GENDRILL_WRITER_BASE::genDrillMapFile( const wxString& aFullFileName, PLOT_ switch( item->Type() ) { case PCB_SHAPE_T: - itemplotter.PlotPcbShape( (PCB_SHAPE*) item ); + itemplotter.PlotPcbShape( static_cast( item ) ); break; case PCB_TEXT_T: - itemplotter.PlotPcbText( (PCB_TEXT*) item ); + itemplotter.PlotPcbText( static_cast( item ), item->GetLayer() ); + break; + + case PCB_TEXTBOX_T: + itemplotter.PlotPcbText( static_cast( item ), item->GetLayer() ); + itemplotter.PlotPcbShape( static_cast( item ) ); break; case PCB_DIM_ALIGNED_T: diff --git a/pcbnew/exporters/gerber_placefile_writer.cpp b/pcbnew/exporters/gerber_placefile_writer.cpp index 321381902b..af9c2a04de 100644 --- a/pcbnew/exporters/gerber_placefile_writer.cpp +++ b/pcbnew/exporters/gerber_placefile_writer.cpp @@ -34,12 +34,14 @@ #include #include +#include #include #include #include #include #include +#include PLACEFILE_GERBER_WRITER::PLACEFILE_GERBER_WRITER( BOARD* aPcb ) @@ -302,7 +304,7 @@ int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER for( BOARD_ITEM* item : footprint->GraphicalItems() ) { if( item->Type() == PCB_FP_SHAPE_T && item->GetLayer() == Edge_Cuts ) - brd_plotter.PlotFootprintGraphicItem( (FP_SHAPE*) item ); + brd_plotter.PlotFootprintShape( static_cast( item ) ); } } } diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp index 7d9043991f..65ac380b6c 100644 --- a/pcbnew/footprint.cpp +++ b/pcbnew/footprint.cpp @@ -47,6 +47,7 @@ #include #include #include +#include "fp_textbox.h" FOOTPRINT::FOOTPRINT( BOARD* parent ) : BOARD_ITEM_CONTAINER((BOARD_ITEM*) parent, PCB_FOOTPRINT_T ), @@ -510,6 +511,7 @@ void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) case PCB_FP_DIM_RADIAL_T: case PCB_FP_DIM_ORTHOGONAL_T: case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: if( aMode == ADD_MODE::APPEND ) m_drawings.push_back( aBoardItem ); else @@ -559,9 +561,8 @@ void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode ) { case PCB_FP_TEXT_T: // Only user text can be removed this way. - wxCHECK_RET( - static_cast( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS, - "Please report this bug: Invalid remove operation on required text" ); + wxCHECK_RET( static_cast( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS, + "Please report this bug: Invalid remove operation on required text" ); KI_FALLTHROUGH; case PCB_FP_DIM_ALIGNED_T: @@ -570,6 +571,7 @@ void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode ) case PCB_FP_DIM_RADIAL_T: case PCB_FP_DIM_LEADER_T: case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it ) { if( *it == aBoardItem ) @@ -767,7 +769,7 @@ const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisi if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) ) continue; - if( item->Type() == PCB_FP_SHAPE_T || BaseType( item->Type() ) == PCB_DIMENSION_T ) + if( item->Type() != PCB_FP_TEXT_T ) area.Merge( item->GetBoundingBox() ); } @@ -787,6 +789,8 @@ const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisi if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) ) continue; + // Only FP_TEXT items are independently selectable; FP_TEXTBOX items go in with + // other graphic items above. if( item->Type() == PCB_FP_TEXT_T ) area.Merge( item->GetBoundingBox() ); } @@ -869,7 +873,7 @@ SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const if( !isFPEdit && m_privateLayers.test( item->GetLayer() ) ) continue; - if( item->Type() == PCB_FP_SHAPE_T || BaseType( item->Type() ) == PCB_DIMENSION_T ) + if( item->Type() != PCB_FP_TEXT_T ) { item->TransformShapeWithClearanceToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF, ERROR_OUTSIDE ); @@ -1069,6 +1073,9 @@ bool FOOTPRINT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) for( BOARD_ITEM* item : m_drawings ) { + // Text items are selectable on their own, and are therefore excluded from this + // test. TextBox items are NOT selectable on their own, and so MUST be included + // here. if( item->Type() != PCB_FP_TEXT_T && item->HitTest( arect, false, 0 ) ) return true; } @@ -1249,6 +1256,7 @@ SEARCH_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData, const KICAD case PCB_FP_DIM_RADIAL_T: case PCB_FP_DIM_ORTHOGONAL_T: case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: result = IterateForward( m_drawings, inspector, testData, p ); // skip over any types handled in the above call. @@ -1257,6 +1265,7 @@ SEARCH_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData, const KICAD switch( stype = *++p ) { case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_DIM_ALIGNED_T: case PCB_FP_DIM_LEADER_T: @@ -1557,6 +1566,10 @@ void FOOTPRINT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) static_cast( item )->Flip( m_pos, false ); break; + case PCB_FP_TEXTBOX_T: + static_cast( item )->Flip( m_pos, false ); + break; + default: wxMessageBox( wxT( "FOOTPRINT::Flip() error: Unknown Draw Type" ) ); break; @@ -1597,6 +1610,7 @@ void FOOTPRINT::SetPosition( const VECTOR2I& aPos ) switch( item->Type() ) { case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: { FP_SHAPE* shape = static_cast( item ); shape->SetDrawCoord(); @@ -1633,7 +1647,8 @@ void FOOTPRINT::SetPosition( const VECTOR2I& aPos ) void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector ) { - /* Move the reference point of the footprint + /* + * Move the reference point of the footprint * the footprints elements (pads, outlines, edges .. ) are moved * but: * - the footprint position is not modified. @@ -1641,7 +1656,6 @@ void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector ) * - Draw coordinates are updated */ - // Update (move) the relative coordinates relative to the new anchor point. VECTOR2I moveVector = aMoveVector; RotatePoint( moveVector, -GetOrientation() ); @@ -1665,19 +1679,20 @@ void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector ) switch( item->Type() ) { case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: { FP_SHAPE* shape = static_cast( item ); shape->Move( moveVector ); - } break; + } case PCB_FP_TEXT_T: { FP_TEXT* text = static_cast( item ); text->SetPos0( text->GetPos0() + moveVector ); text->SetDrawCoord(); - } break; + } default: break; @@ -1727,10 +1742,20 @@ void FOOTPRINT::SetOrientation( const EDA_ANGLE& aNewAngle ) // Displace contours and text of the footprint. for( BOARD_ITEM* item : m_drawings ) { - if( item->Type() == PCB_FP_SHAPE_T ) + switch( item->Type() ) + { + case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: static_cast( item )->SetDrawCoord(); - else if( item->Type() == PCB_FP_TEXT_T ) + break; + + case PCB_FP_TEXT_T: static_cast( item )->SetDrawCoord(); + break; + + default: + break; + } } m_boundingBoxCacheTimeStamp = 0; @@ -1822,6 +1847,18 @@ BOARD_ITEM* FOOTPRINT::DuplicateItem( const BOARD_ITEM* aItem, bool aAddToFootpr break; } + case PCB_FP_TEXTBOX_T: + { + FP_TEXTBOX* new_textbox = new FP_TEXTBOX( *static_cast( aItem ) ); + const_cast( new_textbox->m_Uuid ) = KIID(); + + if( aAddToFootprint ) + Add( new_textbox ); + + new_item = new_textbox; + break; + } + case PCB_FP_DIM_ALIGNED_T: case PCB_FP_DIM_LEADER_T: case PCB_FP_DIM_CENTER_T: @@ -1937,6 +1974,13 @@ double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLEC text->TransformTextShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, textMargin, ARC_LOW_DEF, ERROR_OUTSIDE ); } + else if( aItem->Type() == PCB_FP_TEXTBOX_T ) + { + const FP_TEXTBOX* textbox = static_cast( aItem ); + + textbox->TransformTextShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, textMargin, + ARC_LOW_DEF, ERROR_OUTSIDE ); + } else if( aItem->Type() == PCB_SHAPE_T ) { // Approximate "linear" shapes with just their width squared, as we don't want to consider @@ -2004,6 +2048,7 @@ double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const switch( item->Type() ) { case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: if( item->GetParent() != this ) { @@ -2013,6 +2058,7 @@ double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const break; case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_SHAPE_T: case PCB_TRACE_T: case PCB_ARC_T: @@ -2397,6 +2443,17 @@ void FOOTPRINT::TransformFPShapesWithClearanceToPolygon( SHAPE_POLY_SET& aCorner texts.push_back( text ); } + if( item->Type() == PCB_FP_TEXTBOX_T && aIncludeText ) + { + FP_TEXTBOX* textbox = static_cast( item ); + + if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer && textbox->IsVisible() ) + { + textbox->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0, + aError, aErrorLoc, false ); + } + } + if( item->Type() == PCB_FP_SHAPE_T && aIncludeShapes ) { const FP_SHAPE* outline = static_cast( item ); diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp index 21be761f2f..b33195cea3 100644 --- a/pcbnew/footprint_edit_frame.cpp +++ b/pcbnew/footprint_edit_frame.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2015-2016 Wayne Stambaugh - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -1162,6 +1162,7 @@ void FOOTPRINT_EDIT_FRAME::setupUIConditions() CURRENT_EDIT_TOOL( PCB_ACTIONS::drawPolygon ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawRuleArea ); CURRENT_EDIT_TOOL( PCB_ACTIONS::placeText ); + CURRENT_EDIT_TOOL( PCB_ACTIONS::drawTextBox ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawAlignedDimension ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawOrthogonalDimension ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawCenterDimension ); diff --git a/pcbnew/footprint_editor_utils.cpp b/pcbnew/footprint_editor_utils.cpp index 6b1154fb20..b92dac4ee7 100644 --- a/pcbnew/footprint_editor_utils.cpp +++ b/pcbnew/footprint_editor_utils.cpp @@ -190,6 +190,10 @@ void FOOTPRINT_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem ) ShowTextPropertiesDialog( aItem ); break; + case PCB_FP_TEXTBOX_T: + ShowTextBoxPropertiesDialog( aItem ); + break; + case PCB_FP_SHAPE_T : ShowGraphicItemPropertiesDialog( aItem ); break; diff --git a/pcbnew/footprint_libraries_utils.cpp b/pcbnew/footprint_libraries_utils.cpp index 3f8da55722..3325b383da 100644 --- a/pcbnew/footprint_libraries_utils.cpp +++ b/pcbnew/footprint_libraries_utils.cpp @@ -1150,14 +1150,9 @@ FOOTPRINT* PCB_BASE_FRAME::CreateNewFootprint( const wxString& aFootprintName, b switch( footprintType ) { - case 0: - footprintTranslated = FP_THROUGH_HOLE; - break; - case 1: - footprintTranslated = FP_SMD; - break; - default: - footprintTranslated = 0; + case 0: footprintTranslated = FP_THROUGH_HOLE; break; + case 1: footprintTranslated = FP_SMD; break; + default: footprintTranslated = 0; break; } } diff --git a/pcbnew/fp_shape.cpp b/pcbnew/fp_shape.cpp index 1b4200830d..b1caed6588 100644 --- a/pcbnew/fp_shape.cpp +++ b/pcbnew/fp_shape.cpp @@ -37,8 +37,8 @@ #include -FP_SHAPE::FP_SHAPE( FOOTPRINT* parent, SHAPE_T aShape ) : - PCB_SHAPE( parent, PCB_FP_SHAPE_T, aShape ) +FP_SHAPE::FP_SHAPE( FOOTPRINT* parent, SHAPE_T aShape, KICAD_T aItemType ) : + PCB_SHAPE( parent, aItemType, aShape ) { m_layer = F_SilkS; } diff --git a/pcbnew/fp_shape.h b/pcbnew/fp_shape.h index 3423828036..a645da47f7 100644 --- a/pcbnew/fp_shape.h +++ b/pcbnew/fp_shape.h @@ -37,7 +37,8 @@ class MSG_PANEL_ITEM; class FP_SHAPE : public PCB_SHAPE { public: - FP_SHAPE( FOOTPRINT* parent, SHAPE_T aShape = SHAPE_T::SEGMENT ); + FP_SHAPE( FOOTPRINT* aParent, SHAPE_T aShape = SHAPE_T::SEGMENT, + KICAD_T aItemType = PCB_FP_SHAPE_T ); // Do not create a copy constructor & operator=. // The ones generated by the compiler are adequate. @@ -128,13 +129,13 @@ public: * Call in only when the geometry or the footprint is modified and therefore the relative * coordinates have to be updated from the draw coordinates. */ - void SetLocalCoord(); + virtual void SetLocalCoord(); /** * Set draw coordinates (absolute values ) from relative coordinates. * Must be called when a relative coordinate has changed in order to see the changes on screen */ - void SetDrawCoord(); + virtual void SetDrawCoord(); void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) override; diff --git a/pcbnew/fp_textbox.cpp b/pcbnew/fp_textbox.cpp new file mode 100644 index 0000000000..d65959354d --- /dev/null +++ b/pcbnew/fp_textbox.cpp @@ -0,0 +1,406 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 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 +#include +#include +#include + +FP_TEXTBOX::FP_TEXTBOX( FOOTPRINT* aParentFootprint ) : + FP_SHAPE( aParentFootprint, SHAPE_T::RECT, PCB_FP_TEXTBOX_T ), + EDA_TEXT() +{ + SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + SetMultilineAllowed( true ); + + SetDrawCoord(); +} + + +FP_TEXTBOX::~FP_TEXTBOX() +{ +} + + +int FP_TEXTBOX::GetTextMargin() const +{ + return KiROUND( GetTextSize().y * 0.8 ); +} + + +EDA_ANGLE FP_TEXTBOX::GetDrawRotation() const +{ + FOOTPRINT* parentFootprint = static_cast( m_parent ); + EDA_ANGLE rotation = GetTextAngle(); + + if( parentFootprint ) + rotation += parentFootprint->GetOrientation(); + + rotation.Normalize(); + + return rotation; +} + + +std::vector FP_TEXTBOX::GetAnchorAndOppositeCorner() const +{ + std::vector pts; + std::vector corners = GetCorners(); + + EDA_ANGLE toCorner1( corners[0] - corners[1] ); + EDA_ANGLE toCorner3( corners[0] - corners[3] ); + EDA_ANGLE textAngle( GetDrawRotation() ); + toCorner1.Normalize(); + toCorner3.Normalize(); + textAngle.Normalize(); + + pts.emplace_back( corners[0] ); + + if( std::abs( toCorner1 - textAngle ) < std::abs( toCorner3 - textAngle ) ) + pts.emplace_back( corners[1] ); + else + pts.emplace_back( corners[3] ); + + return pts; +} + + +VECTOR2I FP_TEXTBOX::GetDrawPos() const +{ + std::vector corners = GetAnchorAndOppositeCorner(); + GR_TEXT_H_ALIGN_T effectiveAlignment = GetHorizJustify(); + VECTOR2I textAnchor; + VECTOR2I offset; + + if( IsMirrored() ) + { + switch( GetHorizJustify() ) + { + case GR_TEXT_H_ALIGN_LEFT: effectiveAlignment = GR_TEXT_H_ALIGN_RIGHT; break; + case GR_TEXT_H_ALIGN_CENTER: effectiveAlignment = GR_TEXT_H_ALIGN_CENTER; break; + case GR_TEXT_H_ALIGN_RIGHT: effectiveAlignment = GR_TEXT_H_ALIGN_LEFT; break; + } + } + + switch( effectiveAlignment ) + { + case GR_TEXT_H_ALIGN_LEFT: + textAnchor = corners[0]; + offset = VECTOR2I( GetTextMargin(), GetTextMargin() ); + break; + case GR_TEXT_H_ALIGN_CENTER: + textAnchor = ( corners[0] + corners[1] ) / 2; + offset = VECTOR2I( 0, GetTextMargin() ); + break; + case GR_TEXT_H_ALIGN_RIGHT: + textAnchor = corners[1]; + offset = VECTOR2I( -GetTextMargin(), GetTextMargin() ); + break; + } + + RotatePoint( offset, GetDrawRotation() ); + return textAnchor + offset; +} + + +bool FP_TEXTBOX::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const +{ + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPosition ); +} + + +bool FP_TEXTBOX::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +void FP_TEXTBOX::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) +{ + FP_SHAPE::Rotate( aRotCentre, aAngle ); + SetTextAngle( GetTextAngle() + aAngle ); +} + + +void FP_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) +{ + // flipping the footprint is relative to the X axis + if( aFlipLeftRight ) + { + SetTextX( MIRRORVAL( GetTextPos().x, aCentre.x ) ); + SetTextAngle( -GetTextAngle() ); + } + else + { + SetTextY( MIRRORVAL( GetTextPos().y, aCentre.y ) ); + SetTextAngle( ANGLE_180 - GetTextAngle() ); + } + + SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) ); + SetMirrored( IsBackLayer( GetLayer() ) ); + SetLocalCoord(); +} + + +void FP_TEXTBOX::Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis ) +{ + // the position is mirrored, but the text itself is not mirrored + + if( aMirrorAroundXAxis ) + SetTextY( ::MIRRORVAL( GetTextPos().y, aCentre.y ) ); + else + SetTextX( ::MIRRORVAL( GetTextPos().x, aCentre.x ) ); + + SetLocalCoord(); +} + + +void FP_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) +{ + EDA_UNITS units = aFrame->GetUserUnits(); + + // Don't use GetShownText() here; we want to show the user the variable references + aList.emplace_back( _( "Text Box" ), UnescapeString( GetText() ) ); + + if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() ) + aList.emplace_back( _( "Status" ), _( "Locked" ) ); + + aList.emplace_back( _( "Layer" ), GetLayerName() ); + aList.emplace_back( _( "Mirror" ), IsMirrored() ? _( "Yes" ) : _( "No" ) ); + aList.emplace_back( _( "Angle" ), wxString::Format( "%g", GetTextAngle().AsDegrees() ) ); + + aList.emplace_back( _( "Thickness" ), MessageTextFromValue( units, GetTextThickness() ) ); + aList.emplace_back( _( "Width" ), MessageTextFromValue( units, GetTextWidth() ) ); + aList.emplace_back( _( "Height" ), MessageTextFromValue( units, GetTextHeight() ) ); +} + + +wxString FP_TEXTBOX::GetSelectMenuText( EDA_UNITS aUnits ) const +{ + return wxString::Format( _( "Footprint Text Box of %s" ), + static_cast( GetParent() )->GetReference() ); +} + + +BITMAPS FP_TEXTBOX::GetMenuImage() const +{ + return BITMAPS::add_textbox; +} + + +EDA_ITEM* FP_TEXTBOX::Clone() const +{ + return new FP_TEXTBOX( *this ); +} + + +const BOX2I FP_TEXTBOX::ViewBBox() const +{ + EDA_ANGLE angle = GetDrawRotation(); + EDA_RECT text_area = GetTextBox(); + + if( !angle.IsZero() ) + text_area = text_area.GetBoundingBoxRotated( GetDrawPos(), angle ); + + return BOX2I( text_area.GetPosition(), text_area.GetSize() ); +} + + +void FP_TEXTBOX::ViewGetLayers( int aLayers[], int& aCount ) const +{ + if( IsVisible() ) + aLayers[0] = GetLayer(); + else + aLayers[0] = LAYER_MOD_TEXT_INVISIBLE; + + aCount = 1; +} + + +double FP_TEXTBOX::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const +{ + constexpr double HIDE = (double)std::numeric_limits::max(); + + if( !aView ) + return 0.0; + + // Hidden text gets put on the LAYER_MOD_TEXT_INVISIBLE for rendering, but + // should only render if its native layer is visible. + if( !aView->IsLayerVisible( GetLayer() ) ) + return HIDE; + + RENDER_SETTINGS* renderSettings = aView->GetPainter()->GetSettings(); + COLOR4D backgroundColor = renderSettings->GetLayerColor( LAYER_PCB_BACKGROUND ); + + // Handle Render tab switches + if( renderSettings->GetLayerColor( LAYER_MOD_TEXT ) == backgroundColor ) + return HIDE; + + if( !IsParentFlipped() && !aView->IsLayerVisible( LAYER_MOD_FR ) ) + return HIDE; + + if( IsParentFlipped() && !aView->IsLayerVisible( LAYER_MOD_BK ) ) + return HIDE; + + if( !aView->IsLayerVisible( LAYER_MOD_TEXT ) ) + return HIDE; + + // Other layers are shown without any conditions + return 0.0; +} + + +wxString FP_TEXTBOX::GetShownText( int aDepth ) const +{ + const FOOTPRINT* parentFootprint = static_cast( GetParent() ); + wxASSERT( parentFootprint ); + const BOARD* board = parentFootprint->GetBoard(); + + std::function footprintResolver = + [&]( wxString* token ) -> bool + { + return parentFootprint && parentFootprint->ResolveTextVar( token, aDepth ); + }; + + std::function boardTextResolver = + [&]( wxString* token ) -> bool + { + return board->ResolveTextVar( token, aDepth + 1 ); + }; + + wxString text = EDA_TEXT::GetShownText(); + + if( HasTextVars() ) + { + PROJECT* project = nullptr; + + if( parentFootprint && parentFootprint->GetParent() ) + project = static_cast( parentFootprint->GetParent() )->GetProject(); + + if( aDepth < 10 ) + text = ExpandTextVars( text, &footprintResolver, &boardTextResolver, project ); + } + + KIFONT::FONT* font = GetDrawFont(); + std::vector corners = GetAnchorAndOppositeCorner(); + int colWidth = ( corners[1] - corners[0] ).EuclideanNorm(); + + colWidth -= GetTextMargin() * 2; + font->LinebreakText( text, colWidth, GetTextSize(), GetTextThickness(), IsBold(), IsItalic() ); + + return text; +} + + +std::shared_ptr FP_TEXTBOX::GetEffectiveShape( PCB_LAYER_ID aLayer ) const +{ + return GetEffectiveTextShape(); +} + + +void FP_TEXTBOX::TransformTextShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + PCB_LAYER_ID aLayer, int aClearance, + int aError, ERROR_LOC aErrorLoc ) const +{ + KIGFX::GAL_DISPLAY_OPTIONS empty_opts; + KIFONT::FONT* font = GetDrawFont(); + int penWidth = GetEffectiveTextPenWidth(); + + CALLBACK_GAL callback_gal( empty_opts, + // Stroke callback + [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) + { + TransformOvalToPolygon( aCornerBuffer, aPt1, aPt2, penWidth + ( 2 * aClearance ), + aError, ERROR_INSIDE ); + }, + // Triangulation callback + [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 ) + { + aCornerBuffer.NewOutline(); + + for( const VECTOR2I& point : { aPt1, aPt2, aPt3 } ) + aCornerBuffer.Append( point.x, point.y ); + } ); + + TEXT_ATTRIBUTES attrs = GetAttributes(); + attrs.m_Angle = GetDrawRotation(); + + font->Draw( &callback_gal, GetShownText(), GetDrawPos(), attrs ); +} + + +void FP_TEXTBOX::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + PCB_LAYER_ID aLayer, int aClearance, + int aError, ERROR_LOC aErrorLoc, + bool aIgnoreLineWidth ) const +{ + if( PCB_SHAPE::GetStroke().GetWidth() >= 0 ) + { + FP_SHAPE::TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, aClearance, + aError, aErrorLoc ); + } + else + { + EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon( &aCornerBuffer, aClearance ); + } +} + + +static struct FP_TEXTBOX_DESC +{ + FP_TEXTBOX_DESC() + { + PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); + REGISTER_TYPE( FP_TEXTBOX ); + propMgr.AddTypeCast( new TYPE_CAST ); + propMgr.AddTypeCast( new TYPE_CAST ); + propMgr.InheritsAfter( TYPE_HASH( FP_TEXTBOX ), TYPE_HASH( FP_SHAPE ) ); + propMgr.InheritsAfter( TYPE_HASH( FP_TEXTBOX ), TYPE_HASH( EDA_TEXT ) ); + + propMgr.AddProperty( new PROPERTY( _HKI( "Parent" ), + NO_SETTER( FP_TEXTBOX, wxString ), &FP_TEXTBOX::GetParentAsString ) ); + } +} _FP_TEXTBOX_DESC; diff --git a/pcbnew/fp_textbox.h b/pcbnew/fp_textbox.h new file mode 100644 index 0000000000..7e6edf4bc9 --- /dev/null +++ b/pcbnew/fp_textbox.h @@ -0,0 +1,144 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 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 FP_TEXTBOX_H +#define FP_TEXTBOX_H + +#include +#include + +class LINE_READER; +class EDA_RECT; +class FOOTPRINT; +class MSG_PANEL_ITEM; +class PCB_BASE_FRAME; +class SHAPE; + + +class FP_TEXTBOX : public FP_SHAPE, public EDA_TEXT +{ +public: + FP_TEXTBOX( FOOTPRINT* aParentFootprint ); + + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. + + ~FP_TEXTBOX(); + + static inline bool ClassOf( const EDA_ITEM* aItem ) + { + return aItem && aItem->Type() == PCB_FP_TEXT_T; + } + + bool IsType( const KICAD_T aScanTypes[] ) const override + { + if( BOARD_ITEM::IsType( aScanTypes ) ) + return true; + + for( const KICAD_T* p = aScanTypes; *p != EOT; ++p ) + { + if( *p == PCB_LOCATE_TEXT_T ) + return true; + } + + return false; + } + + wxString GetParentAsString() const { return m_parent->m_Uuid.AsString(); } + + bool Matches( const wxFindReplaceData& aSearchData, void* aAuxData ) const override + { + return BOARD_ITEM::Matches( GetShownText(), aSearchData ); + } + + int GetTextMargin() const; + + virtual EDA_ANGLE GetDrawRotation() const override; + + VECTOR2I GetDrawPos() const override; + + std::vector GetAnchorAndOppositeCorner() const; + + /// Rotate text, in footprint editor + /// (for instance in footprint rotation transform) + void Rotate( const VECTOR2I& aOffset, const EDA_ANGLE& aAngle ) override; + + /// Flip entity during footprint flip + void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override; + + /// Mirror text position in footprint editing + /// the text itself is not mirrored, and the layer not modified, + /// only position is mirrored. + /// (use Flip to change layer to its paired and mirror the text in fp editor). + void Mirror( const VECTOR2I& aCentre, bool aMirrorAroundXAxis ); + + // The Pos0 accessors are for footprint-relative coordinates. + void SetPos0( const VECTOR2I& aPos ) { m_Pos0 = aPos; SetDrawCoord(); } + const VECTOR2I& GetPos0() const { return m_Pos0; } + + void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) override; + + bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override; + + bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; + + void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer, + int aClearance, int aError, ERROR_LOC aErrorLoc, + bool aIgnoreLineWidth ) const override; + + void TransformTextShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + PCB_LAYER_ID aLayer, int aClearanceValue, + int aError, ERROR_LOC aErrorLoc ) const; + + // @copydoc BOARD_ITEM::GetEffectiveShape + std::shared_ptr GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override; + + wxString GetClass() const override + { + return wxT( "MTEXT" ); + } + + wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; + + BITMAPS GetMenuImage() const override; + + EDA_ITEM* Clone() const override; + + virtual wxString GetShownText( int aDepth = 0 ) const override; + + virtual const BOX2I ViewBBox() const override; + + virtual void ViewGetLayers( int aLayers[], int& aCount ) const override; + + double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override; + +#if defined(DEBUG) + virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); } +#endif + +private: + VECTOR2I m_Pos0; ///< text coordinates relative to the footprint anchor, orient 0. + ///< text coordinate ref point is the text center +}; + +#endif // FP_TEXTBOX_H diff --git a/pcbnew/kicad_clipboard.cpp b/pcbnew/kicad_clipboard.cpp index e44d271968..c13a25ecbb 100644 --- a/pcbnew/kicad_clipboard.cpp +++ b/pcbnew/kicad_clipboard.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 KiCad Developers, see AUTHORS.TXT for contributors. - * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Kristoffer Ödmark * * This program is free software; you can redistribute it and/or @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -214,6 +216,18 @@ void CLIPBOARD_IO::SaveSelection( const PCB_SELECTION& aSelected, bool isFootpri pcb_text->SetLayer( fp_text->GetLayer() ); copy = pcb_text; } + else if( item->Type() == PCB_FP_TEXTBOX_T ) + { + // Convert to PCB_TEXTBOX_T + FP_TEXTBOX* fp_textbox = static_cast( item ); + PCB_TEXTBOX* pcb_textbox = new PCB_TEXTBOX( m_board ); + + pcb_textbox->CopyText( *fp_textbox ); + + pcb_textbox->SetAttributes( *fp_textbox ); + pcb_textbox->SetLayer( fp_textbox->GetLayer() ); + copy = pcb_textbox; + } else if( item->Type() == PCB_PAD_T ) { // Create a parent to own the copied pad diff --git a/pcbnew/menubar_footprint_editor.cpp b/pcbnew/menubar_footprint_editor.cpp index 426a6e35e4..fbba74543f 100644 --- a/pcbnew/menubar_footprint_editor.cpp +++ b/pcbnew/menubar_footprint_editor.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2015 Wayne Stambaugh - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -186,6 +186,7 @@ void FOOTPRINT_EDIT_FRAME::ReCreateMenuBar() placeMenu->Add( PCB_ACTIONS::drawCircle ); placeMenu->Add( PCB_ACTIONS::drawPolygon ); placeMenu->Add( PCB_ACTIONS::placeText ); + placeMenu->Add( PCB_ACTIONS::drawTextBox ); placeMenu->AppendSeparator(); placeMenu->Add( PCB_ACTIONS::drawAlignedDimension ); diff --git a/pcbnew/menubar_pcb_editor.cpp b/pcbnew/menubar_pcb_editor.cpp index d472ac056c..cb8794c840 100644 --- a/pcbnew/menubar_pcb_editor.cpp +++ b/pcbnew/menubar_pcb_editor.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -322,6 +322,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() placeMenu->Add( PCB_ACTIONS::drawCircle ); placeMenu->Add( PCB_ACTIONS::drawPolygon ); placeMenu->Add( PCB_ACTIONS::placeText ); + placeMenu->Add( PCB_ACTIONS::drawTextBox ); placeMenu->AppendSeparator(); placeMenu->Add( PCB_ACTIONS::drawAlignedDimension ); diff --git a/pcbnew/pcb_base_edit_frame.h b/pcbnew/pcb_base_edit_frame.h index fa701383f6..8b8b3d028e 100644 --- a/pcbnew/pcb_base_edit_frame.h +++ b/pcbnew/pcb_base_edit_frame.h @@ -167,6 +167,7 @@ public: //void SetRotationAngle( EDA_ANGLE aRotationAngle ); void ShowTextPropertiesDialog( BOARD_ITEM* aText ); + int ShowTextBoxPropertiesDialog( BOARD_ITEM* aText ); void ShowGraphicItemPropertiesDialog( BOARD_ITEM* aItem ); ///< @copydoc EDA_DRAW_FRAME::UseGalCanvas() diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index 20ee74bacb..3451d2bfb8 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -360,7 +360,9 @@ void PCB_BASE_FRAME::FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer ) case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_ZONE_T: case PCB_TRACE_T: diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp index 90e960b6cb..f6b4442ff5 100644 --- a/pcbnew/pcb_edit_frame.cpp +++ b/pcbnew/pcb_edit_frame.cpp @@ -815,6 +815,7 @@ void PCB_EDIT_FRAME::setupUIConditions() CURRENT_EDIT_TOOL( PCB_ACTIONS::drawArc ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawPolygon ); CURRENT_EDIT_TOOL( PCB_ACTIONS::placeText ); + CURRENT_EDIT_TOOL( PCB_ACTIONS::drawTextBox ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawAlignedDimension ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawOrthogonalDimension ); CURRENT_EDIT_TOOL( PCB_ACTIONS::drawCenterDimension ); diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index b146668324..10288eaa79 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -30,15 +30,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include -#include #include #include @@ -460,10 +461,18 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer ) draw( static_cast( item ), aLayer ); break; + case PCB_TEXTBOX_T: + draw( static_cast( item ), aLayer ); + break; + case PCB_FP_TEXT_T: draw( static_cast( item ), aLayer ); break; + case PCB_FP_TEXTBOX_T: + draw( static_cast( item ), aLayer ); + break; + case PCB_FOOTPRINT_T: draw( static_cast( item ), aLayer ); break; @@ -1603,6 +1612,66 @@ void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer ) } +void PCB_PAINTER::draw( const PCB_TEXTBOX* aTextBox, int aLayer ) +{ + const COLOR4D& color = m_pcbSettings.GetColor( aTextBox, aTextBox->GetLayer() ); + int thickness = getLineThickness( aTextBox->GetWidth() ); + PLOT_DASH_TYPE lineStyle = aTextBox->GetStroke().GetPlotStyle(); + + m_gal->SetFillColor( color ); + m_gal->SetStrokeColor( color ); + m_gal->SetIsFill( true ); + m_gal->SetIsStroke( false ); + + if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE ) + { + if( thickness > 0 ) + { + std::vector pts = aTextBox->GetCorners(); + + for( size_t ii = 0; ii < pts.size(); ++ii ) + m_gal->DrawSegment( pts[ ii ], pts[ (ii + 1) % pts.size() ], thickness ); + } + } + else + { + std::vector shapes = aTextBox->MakeEffectiveShapes( true ); + + for( SHAPE* shape : shapes ) + { + STROKE_PARAMS::Stroke( shape, lineStyle, thickness, &m_pcbSettings, + [&]( const VECTOR2I& a, const VECTOR2I& b ) + { + m_gal->DrawSegment( a, b, thickness ); + } ); + } + + for( SHAPE* shape : shapes ) + delete shape; + } + + wxString resolvedText( aTextBox->GetShownText() ); + + if( resolvedText.Length() == 0 ) + return; + + TEXT_ATTRIBUTES attrs = aTextBox->GetAttributes(); + attrs.m_StrokeWidth = getLineThickness( aTextBox->GetEffectiveTextPenWidth() ); + + std::vector>* cache = aTextBox->GetRenderCache( resolvedText ); + + if( cache ) + { + for( const std::unique_ptr& glyph : *cache ) + m_gal->DrawGlyph( *glyph.get() ); + } + else + { + strokeText( resolvedText, aTextBox->GetDrawPos(), attrs ); + } +} + + void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer ) { wxString resolvedText( aText->GetShownText() ); @@ -1647,6 +1716,67 @@ void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer ) } +void PCB_PAINTER::draw( const FP_TEXTBOX* aTextBox, int aLayer ) +{ + const COLOR4D& color = m_pcbSettings.GetColor( aTextBox, aTextBox->GetLayer() ); + int thickness = getLineThickness( aTextBox->GetWidth() ); + PLOT_DASH_TYPE lineStyle = aTextBox->GetStroke().GetPlotStyle(); + + m_gal->SetFillColor( color ); + m_gal->SetStrokeColor( color ); + m_gal->SetIsFill( true ); + m_gal->SetIsStroke( false ); + + if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE ) + { + if( thickness > 0 ) + { + std::vector pts = aTextBox->GetCorners(); + + for( size_t ii = 0; ii < pts.size(); ++ii ) + m_gal->DrawSegment( pts[ ii ], pts[ (ii + 1) % pts.size() ], thickness ); + } + } + else + { + std::vector shapes = aTextBox->MakeEffectiveShapes( true ); + + for( SHAPE* shape : shapes ) + { + STROKE_PARAMS::Stroke( shape, lineStyle, thickness, &m_pcbSettings, + [&]( const VECTOR2I& a, const VECTOR2I& b ) + { + m_gal->DrawSegment( a, b, thickness ); + } ); + } + + for( SHAPE* shape : shapes ) + delete shape; + } + + wxString resolvedText( aTextBox->GetShownText() ); + + if( resolvedText.Length() == 0 ) + return; + + TEXT_ATTRIBUTES attrs = aTextBox->GetAttributes(); + attrs.m_Angle = aTextBox->GetDrawRotation(); + attrs.m_StrokeWidth = getLineThickness( aTextBox->GetEffectiveTextPenWidth() ); + + std::vector>* cache = aTextBox->GetRenderCache( resolvedText ); + + if( cache ) + { + for( const std::unique_ptr& glyph : *cache ) + m_gal->DrawGlyph( *glyph.get() ); + } + else + { + strokeText( resolvedText, aTextBox->GetDrawPos(), attrs ); + } +} + + void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer ) { if( aLayer == LAYER_ANCHOR ) @@ -1866,7 +1996,6 @@ void PCB_PAINTER::draw( const PCB_DIMENSION_BASE* aDimension, int aLayer ) // Draw text const PCB_TEXT& text = aDimension->Text(); wxString resolvedText = text.GetShownText(); - VECTOR2D position( text.GetTextPos().x, text.GetTextPos().y ); TEXT_ATTRIBUTES attrs = text.GetAttributes(); if( outline_mode ) @@ -1883,7 +2012,7 @@ void PCB_PAINTER::draw( const PCB_DIMENSION_BASE* aDimension, int aLayer ) } else { - strokeText( resolvedText, position, attrs ); + strokeText( resolvedText, text.GetTextPos(), attrs ); } } diff --git a/pcbnew/pcb_painter.h b/pcbnew/pcb_painter.h index 0c1e9933de..837b68ce0c 100644 --- a/pcbnew/pcb_painter.h +++ b/pcbnew/pcb_painter.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 CERN - * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors. * * @author Tomasz Wlostowski * @author Maciej Suminski @@ -47,7 +47,9 @@ class PCB_GROUP; class FOOTPRINT; class ZONE; class PCB_TEXT; +class PCB_TEXTBOX; class FP_TEXT; +class FP_TEXTBOX; class PCB_DIMENSION_BASE; class PCB_TARGET; class PCB_MARKER; @@ -170,7 +172,9 @@ protected: void draw( const PAD* aPad, int aLayer ); void draw( const PCB_SHAPE* aSegment, int aLayer ); void draw( const PCB_TEXT* aText, int aLayer ); + void draw( const PCB_TEXTBOX* aText, int aLayer ); void draw( const FP_TEXT* aText, int aLayer ); + void draw( const FP_TEXTBOX* aText, int aLayer ); void draw( const FOOTPRINT* aFootprint, int aLayer ); void draw( const PCB_GROUP* aGroup, int aLayer ); void draw( const ZONE* aZone, int aLayer ); diff --git a/pcbnew/pcb_shape.cpp b/pcbnew/pcb_shape.cpp index 6dfeaddeaa..1e467e5c15 100644 --- a/pcbnew/pcb_shape.cpp +++ b/pcbnew/pcb_shape.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2011 Wayne Stambaugh - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -31,11 +31,11 @@ #include #include #include +#include "macros.h" - -PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T idtype, SHAPE_T shapetype ) : - BOARD_ITEM( aParent, idtype ), - EDA_SHAPE( shapetype, Millimeter2iu( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL, false ) +PCB_SHAPE::PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T aItemType, SHAPE_T aShapeType ) : + BOARD_ITEM( aParent, aItemType ), + EDA_SHAPE( aShapeType, Millimeter2iu( DEFAULT_LINE_WIDTH ), FILL_T::NO_FILL, false ) { } @@ -94,6 +94,31 @@ const VECTOR2I PCB_SHAPE::GetFocusPosition() const } +std::vector PCB_SHAPE::GetCorners() const +{ + std::vector pts; + + if( GetShape() == SHAPE_T::RECT ) + { + pts = GetRectCorners(); + } + else if( GetShape() == SHAPE_T::POLY ) + { + for( const VECTOR2I& pt : GetPolyShape().Outline( 0 ).CPoints() ) + pts.emplace_back( pt ); + } + else + { + UNIMPLEMENTED_FOR( SHAPE_T_asString() ); + } + + while( pts.size() < 4 ) + pts.emplace_back( pts.back() + VECTOR2I( 10, 10 ) ); + + return pts; +} + + void PCB_SHAPE::Move( const VECTOR2I& aMoveVector ) { move( aMoveVector ); diff --git a/pcbnew/pcb_shape.h b/pcbnew/pcb_shape.h index 1519733983..786af5da8b 100644 --- a/pcbnew/pcb_shape.h +++ b/pcbnew/pcb_shape.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2018 Jean-Pierre Charras jp.charras at wanadoo.fr - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -38,9 +38,9 @@ class MSG_PANEL_ITEM; class PCB_SHAPE : public BOARD_ITEM, public EDA_SHAPE { public: - PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T idtype, SHAPE_T shapetype ); + PCB_SHAPE( BOARD_ITEM* aParent, KICAD_T aItemType, SHAPE_T aShapeType ); - PCB_SHAPE( BOARD_ITEM* aParent = NULL, SHAPE_T shapetype = SHAPE_T::SEGMENT ); + PCB_SHAPE( BOARD_ITEM* aParent = NULL, SHAPE_T aShapeType = SHAPE_T::SEGMENT ); // Do not create a copy constructor & operator=. // The ones generated by the compiler are adequate. @@ -83,6 +83,12 @@ public: STROKE_PARAMS GetStroke() const override { return m_stroke; } void SetStroke( const STROKE_PARAMS& aStroke ) override { m_stroke = aStroke; } + /** + * Return 4 corners for a rectangle or rotated rectangle (stored as a poly). Unimplemented + * for other shapes. + */ + std::vector GetCorners() const; + /** * Allows items to return their visual center rather than their anchor. For some shapes this * is similar to GetCenter(), but for unfilled shapes a point on the outline is better. diff --git a/pcbnew/pcb_text.cpp b/pcbnew/pcb_text.cpp index 80a560d1b9..7c890210dd 100644 --- a/pcbnew/pcb_text.cpp +++ b/pcbnew/pcb_text.cpp @@ -23,7 +23,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include #include #include diff --git a/pcbnew/pcb_text.h b/pcbnew/pcb_text.h index 7670eafc94..54a446e9da 100644 --- a/pcbnew/pcb_text.h +++ b/pcbnew/pcb_text.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com - * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -112,7 +112,7 @@ public: wxString GetClass() const override { - return wxT( "PTEXT" ); + return wxT( "PCB_TEXT" ); } /** diff --git a/pcbnew/pcb_textbox.cpp b/pcbnew/pcb_textbox.cpp new file mode 100644 index 0000000000..45a4b03da2 --- /dev/null +++ b/pcbnew/pcb_textbox.cpp @@ -0,0 +1,340 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2022 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 +#include +#include "macros.h" + +using KIGFX::PCB_RENDER_SETTINGS; + + +PCB_TEXTBOX::PCB_TEXTBOX( BOARD_ITEM* parent ) : + PCB_SHAPE( parent, PCB_TEXTBOX_T, SHAPE_T::RECT ), + EDA_TEXT() +{ + SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); + SetVertJustify( GR_TEXT_V_ALIGN_TOP ); + SetMultilineAllowed( true ); +} + + +PCB_TEXTBOX::~PCB_TEXTBOX() +{ +} + + +int PCB_TEXTBOX::GetTextMargin() const +{ + return KiROUND( GetTextSize().y * 0.8 ); +} + + +std::vector PCB_TEXTBOX::GetAnchorAndOppositeCorner() const +{ + EDA_ANGLE epsilon( 1.0, DEGREES_T ); // Yeah, it's a pretty coarse epsilon, but anything + // under 45° will work for our purposes. + + std::vector pts; + std::vector corners = GetCorners(); + + EDA_ANGLE textAngle = GetDrawRotation().Normalize(); + EDA_ANGLE toCorner1 = EDA_ANGLE( corners[1] - corners[0] ).Normalize(); + EDA_ANGLE fromCorner1 = ( toCorner1 + ANGLE_180 ).Normalize(); + + pts.emplace_back( corners[0] ); + + if( std::abs( toCorner1 - textAngle ) < epsilon || std::abs( fromCorner1 - textAngle ) < epsilon ) + pts.emplace_back( corners[1] ); + else + pts.emplace_back( corners[3] ); + + return pts; +} + + +VECTOR2I PCB_TEXTBOX::GetDrawPos() const +{ + std::vector corners = GetAnchorAndOppositeCorner(); + GR_TEXT_H_ALIGN_T effectiveAlignment = GetHorizJustify(); + VECTOR2I textAnchor; + VECTOR2I offset; + + if( IsMirrored() ) + { + switch( GetHorizJustify() ) + { + case GR_TEXT_H_ALIGN_LEFT: effectiveAlignment = GR_TEXT_H_ALIGN_RIGHT; break; + case GR_TEXT_H_ALIGN_CENTER: effectiveAlignment = GR_TEXT_H_ALIGN_CENTER; break; + case GR_TEXT_H_ALIGN_RIGHT: effectiveAlignment = GR_TEXT_H_ALIGN_LEFT; break; + } + } + + switch( effectiveAlignment ) + { + case GR_TEXT_H_ALIGN_LEFT: + textAnchor = corners[0]; + offset = VECTOR2I( GetTextMargin(), GetTextMargin() ); + break; + case GR_TEXT_H_ALIGN_CENTER: + textAnchor = ( corners[0] + corners[1] ) / 2; + offset = VECTOR2I( 0, GetTextMargin() ); + break; + case GR_TEXT_H_ALIGN_RIGHT: + textAnchor = corners[1]; + offset = VECTOR2I( -GetTextMargin(), GetTextMargin() ); + break; + } + + RotatePoint( offset, GetDrawRotation() ); + return textAnchor + offset; +} + + +wxString PCB_TEXTBOX::GetShownText( int aDepth ) const +{ + BOARD* board = dynamic_cast( GetParent() ); + + std::function pcbTextResolver = + [&]( wxString* token ) -> bool + { + if( token->IsSameAs( wxT( "LAYER" ) ) ) + { + *token = GetLayerName(); + return true; + } + + if( token->Contains( ':' ) ) + { + wxString remainder; + wxString ref = token->BeforeFirst( ':', &remainder ); + BOARD_ITEM* refItem = board->GetItem( KIID( ref ) ); + + if( refItem && refItem->Type() == PCB_FOOTPRINT_T ) + { + FOOTPRINT* refFP = static_cast( refItem ); + + if( refFP->ResolveTextVar( &remainder, aDepth + 1 ) ) + { + *token = remainder; + return true; + } + } + } + return false; + }; + + std::function boardTextResolver = + [&]( wxString* token ) -> bool + { + return board->ResolveTextVar( token, aDepth + 1 ); + }; + + wxString text = EDA_TEXT::GetShownText(); + + if( board && HasTextVars() && aDepth < 10 ) + text = ExpandTextVars( text, &pcbTextResolver, &boardTextResolver, board->GetProject() ); + + KIFONT::FONT* font = GetDrawFont(); + std::vector corners = GetAnchorAndOppositeCorner(); + int colWidth = ( corners[1] - corners[0] ).EuclideanNorm(); + + colWidth -= GetTextMargin() * 2; + font->LinebreakText( text, colWidth, GetTextSize(), GetTextThickness(), IsBold(), IsItalic() ); + + return text; +} + + +void PCB_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) +{ + EDA_UNITS units = aFrame->GetUserUnits(); + + // Don't use GetShownText() here; we want to show the user the variable references + aList.emplace_back( _( "Text Box" ), UnescapeString( GetText() ) ); + + if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() ) + aList.emplace_back( _( "Status" ), _( "Locked" ) ); + + aList.emplace_back( _( "Layer" ), GetLayerName() ); + aList.emplace_back( _( "Mirror" ), IsMirrored() ? _( "Yes" ) : _( "No" ) ); + aList.emplace_back( _( "Angle" ), wxString::Format( "%g", GetTextAngle().AsDegrees() ) ); + + aList.emplace_back( _( "Thickness" ), MessageTextFromValue( units, GetTextThickness() ) ); + aList.emplace_back( _( "Width" ), MessageTextFromValue( units, GetTextWidth() ) ); + aList.emplace_back( _( "Height" ), MessageTextFromValue( units, GetTextHeight() ) ); +} + + +void PCB_TEXTBOX::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) +{ + PCB_SHAPE::Rotate( aRotCentre, aAngle ); + SetTextAngle( GetTextAngle() + aAngle ); +} + + +void PCB_TEXTBOX::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) +{ + if( aFlipLeftRight ) + { + m_start.x = aCentre.x - ( m_start.x - aCentre.x ); + m_end.x = aCentre.x - ( m_end.x - aCentre.x ); + SetTextAngle( -GetTextAngle() ); + } + else + { + m_start.y = aCentre.y - ( m_start.y - aCentre.y ); + m_end.y = aCentre.y - ( m_end.y - aCentre.y ); + SetTextAngle( ANGLE_180 - GetTextAngle() ); + } + + SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) ); + SetMirrored( !IsMirrored() ); +} + + +bool PCB_TEXTBOX::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const +{ + EDA_RECT rect = GetBoundingBox(); + + rect.Inflate( aAccuracy ); + + return rect.Contains( aPosition ); +} + + +bool PCB_TEXTBOX::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const +{ + EDA_RECT rect = aRect; + + rect.Inflate( aAccuracy ); + + if( aContained ) + return rect.Contains( GetBoundingBox() ); + + return rect.Intersects( GetBoundingBox() ); +} + + +wxString PCB_TEXTBOX::GetSelectMenuText( EDA_UNITS aUnits ) const +{ + return wxString::Format( _( "PCB Text Box on %s"), GetLayerName() ); +} + + +BITMAPS PCB_TEXTBOX::GetMenuImage() const +{ + return BITMAPS::add_textbox; +} + + +EDA_ITEM* PCB_TEXTBOX::Clone() const +{ + return new PCB_TEXTBOX( *this ); +} + + +void PCB_TEXTBOX::SwapData( BOARD_ITEM* aImage ) +{ + assert( aImage->Type() == PCB_TEXTBOX_T ); + + std::swap( *((PCB_TEXTBOX*) this), *((PCB_TEXTBOX*) aImage) ); +} + + +std::shared_ptr PCB_TEXTBOX::GetEffectiveShape( PCB_LAYER_ID aLayer ) const +{ + if( PCB_SHAPE::GetStroke().GetWidth() >= 0 ) + return PCB_SHAPE::GetEffectiveShape( aLayer ); + else + return GetEffectiveTextShape(); +} + + +void PCB_TEXTBOX::TransformTextShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + PCB_LAYER_ID aLayer, int aClearance, + int aError, ERROR_LOC aErrorLoc ) const +{ + KIGFX::GAL_DISPLAY_OPTIONS empty_opts; + KIFONT::FONT* font = GetDrawFont(); + int penWidth = GetEffectiveTextPenWidth(); + + CALLBACK_GAL callback_gal( empty_opts, + // Stroke callback + [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 ) + { + TransformOvalToPolygon( aCornerBuffer, aPt1, aPt2, penWidth+ ( 2 * aClearance ), + aError, ERROR_INSIDE ); + }, + // Triangulation callback + [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 ) + { + aCornerBuffer.NewOutline(); + + for( const VECTOR2I& point : { aPt1, aPt2, aPt3 } ) + aCornerBuffer.Append( point.x, point.y ); + } ); + + font->Draw( &callback_gal, GetShownText(), GetTextPos(), GetAttributes() ); +} + + +void PCB_TEXTBOX::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + PCB_LAYER_ID aLayer, int aClearance, + int aError, ERROR_LOC aErrorLoc, + bool aIgnoreLineWidth ) const +{ + if( PCB_SHAPE::GetStroke().GetWidth() >= 0 ) + { + PCB_SHAPE::TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, aClearance, + aError, aErrorLoc ); + } + else + { + EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon( &aCornerBuffer, aClearance ); + } +} + + +static struct PCB_TEXTBOX_DESC +{ + PCB_TEXTBOX_DESC() + { + PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); + REGISTER_TYPE( PCB_TEXTBOX ); + propMgr.AddTypeCast( new TYPE_CAST ); + propMgr.AddTypeCast( new TYPE_CAST ); + propMgr.InheritsAfter( TYPE_HASH( PCB_TEXTBOX ), TYPE_HASH( PCB_SHAPE ) ); + propMgr.InheritsAfter( TYPE_HASH( PCB_TEXTBOX ), TYPE_HASH( EDA_TEXT ) ); + } +} _PCB_TEXTBOX_DESC; diff --git a/pcbnew/pcb_textbox.h b/pcbnew/pcb_textbox.h new file mode 100644 index 0000000000..daa947967b --- /dev/null +++ b/pcbnew/pcb_textbox.h @@ -0,0 +1,127 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 1992-2022 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 PCB_TEXTBOX_H +#define PCB_TEXTBOX_H + +#include +#include + + +class LINE_READER; +class MSG_PANEL_ITEM; + + +class PCB_TEXTBOX : public PCB_SHAPE, public EDA_TEXT +{ +public: + PCB_TEXTBOX( BOARD_ITEM* parent ); + + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. + + ~PCB_TEXTBOX(); + + static inline bool ClassOf( const EDA_ITEM* aItem ) + { + return aItem && PCB_TEXTBOX_T == aItem->Type(); + } + + bool IsType( const KICAD_T aScanTypes[] ) const override + { + if( BOARD_ITEM::IsType( aScanTypes ) ) + return true; + + for( const KICAD_T* p = aScanTypes; *p != EOT; ++p ) + { + if( *p == PCB_LOCATE_TEXT_T ) + return true; + } + + return false; + } + + int GetTextMargin() const; + + VECTOR2I GetDrawPos() const override; + + wxString GetShownText( int aDepth = 0 ) const override; + + /// PCB_TEXTBOXes are always visible: + void SetVisible( bool aVisible ) override { /* do nothing */} + bool IsVisible() const override { return true; } + + bool Matches( const wxFindReplaceData& aSearchData, void* aAuxData ) const override + { + return BOARD_ITEM::Matches( GetShownText(), aSearchData ); + } + + std::vector GetAnchorAndOppositeCorner() const; + + void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override; + + void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override; + + void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) override; + + bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override; + + bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; + + wxString GetClass() const override + { + return wxT( "PCB_TEXTBOX" ); + } + + /** + * Function TransformTextShapeWithClearanceToPolygon + * Convert the text to a polygonSet describing the actual character strokes (one per segment). + * Used in 3D viewer + * Circles and arcs are approximated by segments + * @aCornerBuffer = SHAPE_POLY_SET to store the polygon corners + * @aClearanceValue = the clearance around the text + * @aError = the maximum error to allow when approximating curves + */ + void TransformTextShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, + PCB_LAYER_ID aLayer, int aClearanceValue, + int aError, ERROR_LOC aErrorLoc ) const; + + void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, PCB_LAYER_ID aLayer, + int aClearanceValue, int aError, ERROR_LOC aErrorLoc, + bool aIgnoreLineWidth = false ) const override; + + // @copydoc BOARD_ITEM::GetEffectiveShape + virtual std::shared_ptr GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) const override; + + wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; + + BITMAPS GetMenuImage() const override; + + // Virtual function + EDA_ITEM* Clone() const override; + + virtual void SwapData( BOARD_ITEM* aImage ) override; +}; + +#endif // #define PCB_TEXTBOX_H diff --git a/pcbnew/pcbplot.h b/pcbnew/pcbplot.h index 070632f9a2..b3729afc30 100644 --- a/pcbnew/pcbplot.h +++ b/pcbnew/pcbplot.h @@ -79,7 +79,7 @@ public: // Basic functions to plot a board item void SetLayerSet( LSET aLayerMask ) { m_layerMask = aLayerMask; } void PlotFootprintGraphicItems( const FOOTPRINT* aFootprint ); - void PlotFootprintGraphicItem( const FP_SHAPE* aShape ); + void PlotFootprintShape( const FP_SHAPE* aShape ); void PlotFootprintTextItem( const FP_TEXT* aText, const COLOR4D& aColor ); /* @@ -91,7 +91,7 @@ public: void PlotDimension( const PCB_DIMENSION_BASE* aDim ); void PlotPcbTarget( const PCB_TARGET* aMire ); void PlotFilledAreas( const ZONE* aZone, const SHAPE_POLY_SET& aPolysList ); - void PlotPcbText( const PCB_TEXT* aText ); + void PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer ); void PlotPcbShape( const PCB_SHAPE* aShape ); /** diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 8a0d2fdc42..b3f0bc4a80 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -873,7 +873,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask, } else if( item->Type() == PCB_FP_SHAPE_T && item->IsOnLayer( Edge_Cuts ) ) { - itemplotter.PlotFootprintGraphicItem( static_cast( item ) ); + itemplotter.PlotFootprintShape( static_cast( item ) ); } } } diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index de964d4477..5e326e01dd 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -55,10 +55,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include // for wxASSERT_MSG @@ -350,7 +352,12 @@ void BRDITEMS_PLOTTER::PlotPcbGraphicItem( const BOARD_ITEM* item ) break; case PCB_TEXT_T: - PlotPcbText( static_cast( item ) ); + PlotPcbText( static_cast( item ), item->GetLayer() ); + break; + + case PCB_TEXTBOX_T: + PlotPcbText( static_cast( item ), item->GetLayer() ); + PlotPcbShape( static_cast( item ) ); break; case PCB_DIM_ALIGNED_T: @@ -434,7 +441,7 @@ void BRDITEMS_PLOTTER::PlotDimension( const PCB_DIMENSION_BASE* aDim ) // the white items are not seen on a white paper or screen m_plotter->SetColor( color != WHITE ? color : LIGHTGRAY); - PlotPcbText( &aDim->Text() ); + PlotPcbText( &aDim->Text(), aDim->GetLayer() ); for( const std::shared_ptr& shape : aDim->GetShapes() ) { @@ -534,25 +541,57 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItems( const FOOTPRINT* aFootprint ) if( aFootprint->GetPrivateLayers().test( item->GetLayer() ) ) continue; - if( item->Type() == PCB_FP_SHAPE_T ) + switch( item->Type() ) + { + case PCB_FP_SHAPE_T: { const FP_SHAPE* shape = static_cast( item ); if( m_layerMask[ shape->GetLayer() ] ) - PlotFootprintGraphicItem( shape ); + PlotFootprintShape( shape ); + + break; } - else if( BaseType( item->Type() ) == PCB_DIMENSION_T ) + + case PCB_FP_TEXTBOX_T: + { + const FP_TEXTBOX* textbox = static_cast( item ); + + if( m_layerMask[ textbox->GetLayer() ] ) + { + PlotPcbText( textbox, textbox->GetLayer() ); + PlotFootprintShape( textbox ); + } + + break; + } + + case PCB_DIM_ALIGNED_T: + case PCB_DIM_CENTER_T: + case PCB_DIM_RADIAL_T: + case PCB_DIM_ORTHOGONAL_T: + case PCB_DIM_LEADER_T: { const PCB_DIMENSION_BASE* dimension = static_cast( item ); if( m_layerMask[ dimension->GetLayer() ] ) PlotDimension( dimension ); + + break; + } + + case PCB_FP_TEXT_T: + // Plotted in PlotFootprintTextItem() + break; + + default: + UNIMPLEMENTED_FOR( item->GetClass() ); } } } -void BRDITEMS_PLOTTER::PlotFootprintGraphicItem( const FP_SHAPE* aShape ) +void BRDITEMS_PLOTTER::PlotFootprintShape( const FP_SHAPE* aShape ) { if( aShape->Type() != PCB_FP_SHAPE_T ) return; @@ -735,7 +774,7 @@ void BRDITEMS_PLOTTER::PlotFootprintGraphicItem( const FP_SHAPE* aShape ) } -void BRDITEMS_PLOTTER::PlotPcbText( const PCB_TEXT* aText ) +void BRDITEMS_PLOTTER::PlotPcbText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer ) { wxString shownText( aText->GetShownText() ); KIFONT::FONT* font = aText->GetDrawFont(); @@ -743,15 +782,15 @@ void BRDITEMS_PLOTTER::PlotPcbText( const PCB_TEXT* aText ) if( shownText.IsEmpty() ) return; - if( !m_layerMask[aText->GetLayer()] ) + if( !m_layerMask[aLayer] ) return; GBR_METADATA gbr_metadata; - if( IsCopperLayer( aText->GetLayer() ) ) + if( IsCopperLayer( aLayer ) ) gbr_metadata.SetApertureAttrib( GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB_NONCONDUCTOR ); - COLOR4D color = getColor( aText->GetLayer() ); + COLOR4D color = getColor( aLayer ); m_plotter->SetColor( color ); VECTOR2I size = aText->GetTextSize(); @@ -781,14 +820,14 @@ void BRDITEMS_PLOTTER::PlotPcbText( const PCB_TEXT* aText ) for( unsigned ii = 0; ii < strings_list.Count(); ii++ ) { wxString& txt = strings_list.Item( ii ); - m_plotter->Text( positions[ii], color, txt, aText->GetTextAngle(), size, + m_plotter->Text( positions[ii], color, txt, aText->GetDrawRotation(), size, aText->GetHorizJustify(), aText->GetVertJustify(), thickness, aText->IsItalic(), allow_bold, false, font, &gbr_metadata ); } } else { - m_plotter->Text( pos, color, shownText, aText->GetTextAngle(), size, + m_plotter->Text( pos, color, shownText, aText->GetDrawRotation(), size, aText->GetHorizJustify(), aText->GetVertJustify(), thickness, aText->IsItalic(), allow_bold, false, font, &gbr_metadata ); } diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index 2622157b62..d010bfb5a7 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -35,19 +35,21 @@ #include #include +#include +#include #include #include -#include #include #include +#include +#include +#include +#include #include #include #include #include #include -#include -#include -#include #include #include #include @@ -849,6 +851,12 @@ BOARD* PCB_PARSER::parseBOARD_unchecked() bulkAddedItems.push_back( item ); break; + case T_gr_text_box: + item = parsePCB_TEXTBOX(); + m_board->Add( item, ADD_MODE::BULK_APPEND ); + bulkAddedItems.push_back( item ); + break; + case T_dimension: item = parseDIMENSION( m_board, false ); m_board->Add( item, ADD_MODE::BULK_APPEND ); @@ -1074,6 +1082,7 @@ void PCB_PARSER::resolveGroups( BOARD_ITEM* aParent ) { // We used to allow fp items in non-footprint groups. It was a mistake. case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_ZONE_T: case PCB_PAD_T: @@ -2810,9 +2819,10 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT() T token; std::unique_ptr text = std::make_unique( m_board ); - NeedSYMBOLorNUMBER(); + NeedSYMBOLorNUMBER(); text->SetText( FromUTF8() ); + NeedLEFT(); token = NextTok(); @@ -2867,7 +2877,7 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT() break; default: - Expecting( "layer, tstamp or effects" ); + Expecting( "layer, effects, render_cache or tstamp" ); } } @@ -2875,6 +2885,108 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT() } +PCB_TEXTBOX* PCB_PARSER::parsePCB_TEXTBOX() +{ + wxCHECK_MSG( CurTok() == T_gr_text_box, nullptr, + wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TEXTBOX." ) ); + + std::unique_ptr textbox = std::make_unique( m_board ); + + T token = NextTok(); + + if( token == T_locked ) + { + textbox->SetLocked( true ); + token = NextTok(); + } + + if( !IsSymbol( token ) && (int) token != DSN_NUMBER ) + Expecting( "text value" ); + + textbox->SetText( FromUTF8() ); + + NeedLEFT(); + token = NextTok(); + + if( token == T_start ) + { + int x = parseBoardUnits( "X coordinate" ); + int y = parseBoardUnits( "Y coordinate" ); + textbox->SetStart( VECTOR2I( x, y ) ); + NeedRIGHT(); + + NeedLEFT(); + token = NextTok(); + + if( token != T_end ) + Expecting( T_end ); + + x = parseBoardUnits( "X coordinate" ); + y = parseBoardUnits( "Y coordinate" ); + textbox->SetEnd( VECTOR2I( x, y ) ); + NeedRIGHT(); + } + else if( token == T_pts ) + { + textbox->SetShape( SHAPE_T::POLY ); + textbox->GetPolyShape().RemoveAllContours(); + textbox->GetPolyShape().NewOutline(); + + while( (token = NextTok() ) != T_RIGHT ) + parseOutlinePoints( textbox->GetPolyShape().Outline( 0 ) ); + } + else + { + Expecting( "start or pts" ); + } + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_angle: + textbox->SetTextAngle( EDA_ANGLE( parseDouble( "text box angle" ), DEGREES_T ) ); + NeedRIGHT(); + break; + + case T_width: + textbox->SetWidth( parseBoardUnits( "text box border width" ) ); + NeedRIGHT(); + break; + + case T_layer: + textbox->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_tstamp: + NextTok(); + const_cast( textbox->m_Uuid ) = CurStrToKIID(); + NeedRIGHT(); + break; + + case T_effects: + parseEDA_TEXT( static_cast( textbox.get() ) ); + break; + + case T_render_cache: + parseRenderCache( static_cast( textbox.get() ) ); + break; + + default: + Expecting( "angle, width, layer, effects, render_cache or tstamp" ); + } + } + + return textbox.release(); +} + + PCB_DIMENSION_BASE* PCB_PARSER::parseDIMENSION( BOARD_ITEM* aParent, bool aInFP ) { wxCHECK_MSG( CurTok() == T_dimension, nullptr, @@ -3590,6 +3702,15 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments break; } + case T_fp_text_box: + { + FP_TEXTBOX* textbox = parseFP_TEXTBOX(); + textbox->SetParent( footprint.get() ); + textbox->SetDrawCoord(); + footprint->Add( textbox, ADD_MODE::APPEND ); + break; + } + case T_fp_arc: case T_fp_circle: case T_fp_curve: @@ -3780,7 +3901,7 @@ FP_TEXT* PCB_PARSER::parseFP_TEXT() break; default: - Expecting( "layer, hide, effects or tstamp" ); + Expecting( "layer, hide, effects, render_cache or tstamp" ); } } @@ -3788,6 +3909,107 @@ FP_TEXT* PCB_PARSER::parseFP_TEXT() } +FP_TEXTBOX* PCB_PARSER::parseFP_TEXTBOX() +{ + wxCHECK_MSG( CurTok() == T_fp_text_box, nullptr, + wxString::Format( wxT( "Cannot parse %s as FP_TEXTBOX at line %d, offset %d." ), + GetTokenString( CurTok() ), CurLineNumber(), CurOffset() ) ); + + std::unique_ptr textbox = std::make_unique( nullptr ); + + T token = NextTok(); + + if( token == T_locked ) + { + textbox->SetLocked( true ); + token = NextTok(); + } + + if( !IsSymbol( token ) && (int) token != DSN_NUMBER ) + Expecting( "text value" ); + + textbox->SetText( FromUTF8() ); + + NeedLEFT(); + token = NextTok(); + + if( token == T_start ) + { + int x = parseBoardUnits( "X coordinate" ); + int y = parseBoardUnits( "Y coordinate" ); + textbox->SetStart0( VECTOR2I( x, y ) ); + NeedRIGHT(); + + NeedLEFT(); + token = NextTok(); + + if( token != T_end ) + Expecting( T_end ); + + x = parseBoardUnits( "X coordinate" ); + y = parseBoardUnits( "Y coordinate" ); + textbox->SetEnd0( VECTOR2I( x, y ) ); + NeedRIGHT(); + } + else if( token == T_pts ) + { + textbox->SetShape( SHAPE_T::POLY ); + textbox->GetPolyShape().RemoveAllContours(); + textbox->GetPolyShape().NewOutline(); + + while( (token = NextTok() ) != T_RIGHT ) + parseOutlinePoints( textbox->GetPolyShape().Outline( 0 ) ); + } + else + { + Expecting( "start or pts" ); + } + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token == T_LEFT ) + token = NextTok(); + + switch( token ) + { + case T_angle: + textbox->SetTextAngle( EDA_ANGLE( parseDouble( "text box angle" ), DEGREES_T ) ); + NeedRIGHT(); + break; + + case T_width: + textbox->SetWidth( parseBoardUnits( "text box border width" ) ); + NeedRIGHT(); + break; + + case T_layer: + textbox->SetLayer( parseBoardItemLayer() ); + NeedRIGHT(); + break; + + case T_effects: + parseEDA_TEXT( static_cast( textbox.get() ) ); + break; + + case T_render_cache: + parseRenderCache( static_cast( textbox.get() ) ); + break; + + case T_tstamp: + NextTok(); + const_cast( textbox->m_Uuid ) = CurStrToKIID(); + NeedRIGHT(); + break; + + default: + Expecting( "angle, width, layer, effects, render_cache or tstamp" ); + } + } + + return textbox.release(); +} + + FP_SHAPE* PCB_PARSER::parseFP_SHAPE() { wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve || diff --git a/pcbnew/plugins/kicad/pcb_parser.h b/pcbnew/plugins/kicad/pcb_parser.h index 67782699e0..6cbab5f5f4 100644 --- a/pcbnew/plugins/kicad/pcb_parser.h +++ b/pcbnew/plugins/kicad/pcb_parser.h @@ -174,12 +174,14 @@ private: PCB_SHAPE* parsePCB_SHAPE(); PCB_TEXT* parsePCB_TEXT(); + PCB_TEXTBOX* parsePCB_TEXTBOX(); PCB_DIMENSION_BASE* parseDIMENSION( BOARD_ITEM* aParent, bool aInFP ); // Parse a footprint, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically. FOOTPRINT* parseFOOTPRINT_unchecked( wxArrayString* aInitialComments = nullptr ); FP_TEXT* parseFP_TEXT(); + FP_TEXTBOX* parseFP_TEXTBOX(); FP_SHAPE* parseFP_SHAPE(); PAD* parsePAD( FOOTPRINT* aParent = nullptr ); diff --git a/pcbnew/plugins/kicad/pcb_plugin.cpp b/pcbnew/plugins/kicad/pcb_plugin.cpp index 79ec1d6487..9735853ac2 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.cpp +++ b/pcbnew/plugins/kicad/pcb_plugin.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -437,10 +439,18 @@ void PCB_PLUGIN::Format( const BOARD_ITEM* aItem, int aNestLevel ) const format( static_cast( aItem ), aNestLevel ); break; + case PCB_TEXTBOX_T: + format( static_cast( aItem ), aNestLevel ); + break; + case PCB_FP_TEXT_T: format( static_cast( aItem ), aNestLevel ); break; + case PCB_FP_TEXTBOX_T: + format( static_cast( aItem ), aNestLevel ); + break; + case PCB_GROUP_T: format( static_cast( aItem ), aNestLevel ); break; @@ -906,7 +916,7 @@ void PCB_PLUGIN::format( const PCB_SHAPE* aShape, int aNestLevel ) const { case SHAPE_T::SEGMENT: m_out->Print( aNestLevel, "(gr_line%s (start %s) (end %s)", - locked.c_str(), + locked.c_str(), FormatInternalUnits( aShape->GetStart() ).c_str(), FormatInternalUnits( aShape->GetEnd() ).c_str() ); break; @@ -1739,6 +1749,53 @@ void PCB_PLUGIN::format( const PCB_TEXT* aText, int aNestLevel ) const } +void PCB_PLUGIN::format( const PCB_TEXTBOX* aTextBox, int aNestLevel ) const +{ + std::string locked = aTextBox->IsLocked() ? " locked" : ""; + + m_out->Print( aNestLevel, "(gr_text_box%s %s\n", + locked.c_str(), + m_out->Quotew( aTextBox->GetText() ).c_str() ); + + if( aTextBox->GetShape() == SHAPE_T::RECT ) + { + m_out->Print( aNestLevel, "(start %s) (end %s)", + FormatInternalUnits( aTextBox->GetStart() ).c_str(), + FormatInternalUnits( aTextBox->GetEnd() ).c_str() ); + } + else if( aTextBox->GetShape() == SHAPE_T::POLY ) + { + const SHAPE_POLY_SET& poly = aTextBox->GetPolyShape(); + const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 ); + + formatPolyPts( outline, aNestLevel, true ); + } + else + { + UNIMPLEMENTED_FOR( aTextBox->SHAPE_T_asString() ); + } + + if( !aTextBox->GetTextAngle().IsZero() ) + m_out->Print( 0, " (angle %s)", FormatAngle( aTextBox->GetTextAngle() ).c_str() ); + + m_out->Print( 0, " (width %s)", FormatInternalUnits( aTextBox->GetWidth() ).c_str() ); + + formatLayer( aTextBox ); + + m_out->Print( 0, " (tstamp %s)", TO_UTF8( aTextBox->m_Uuid.AsString() ) ); + + m_out->Print( 0, "\n" ); + + // PCB_TEXTBOXes are never hidden, so always omit "hide" attribute + aTextBox->EDA_TEXT::Format( m_out, aNestLevel, m_ctl | CTL_OMIT_HIDE ); + + if( aTextBox->GetFont() && aTextBox->GetFont()->IsOutline() ) + formatRenderCache( aTextBox, aNestLevel + 1 ); + + m_out->Print( aNestLevel, ")\n" ); +} + + void PCB_PLUGIN::format( const PCB_GROUP* aGroup, int aNestLevel ) const { // Don't write empty groups @@ -1835,6 +1892,54 @@ void PCB_PLUGIN::format( const FP_TEXT* aText, int aNestLevel ) const } +void PCB_PLUGIN::format( const FP_TEXTBOX* aTextBox, int aNestLevel ) const +{ + std::string locked = aTextBox->IsLocked() ? " locked" : ""; + + m_out->Print( aNestLevel, "(fp_text_box%s %s\n", + locked.c_str(), + m_out->Quotew( aTextBox->GetText() ).c_str() ); + + if( aTextBox->GetShape() == SHAPE_T::RECT ) + { + m_out->Print( aNestLevel, "(start %s) (end %s) (angle %s) (width %s)", + FormatInternalUnits( aTextBox->GetStart0() ).c_str(), + FormatInternalUnits( aTextBox->GetEnd0() ).c_str(), + FormatAngle( aTextBox->GetTextAngle() ).c_str(), + FormatInternalUnits( aTextBox->GetWidth() ).c_str() ); + } + else if( aTextBox->GetShape() == SHAPE_T::POLY ) + { + const SHAPE_POLY_SET& poly = aTextBox->GetPolyShape(); + const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 ); + + formatPolyPts( outline, aNestLevel, true ); + + m_out->Print( aNestLevel, " (angle %s) (width %s)", + FormatAngle( aTextBox->GetTextAngle() ).c_str(), + FormatInternalUnits( aTextBox->GetWidth() ).c_str() ); + } + else + { + UNIMPLEMENTED_FOR( aTextBox->SHAPE_T_asString() ); + } + + formatLayer( aTextBox ); + + m_out->Print( 0, " (tstamp %s)", TO_UTF8( aTextBox->m_Uuid.AsString() ) ); + + m_out->Print( 0, "\n" ); + + // FP_TEXTBOXes are never hidden, so always omit "hide" attribute + aTextBox->EDA_TEXT::Format( m_out, aNestLevel, m_ctl | CTL_OMIT_HIDE ); + + if( aTextBox->GetFont() && aTextBox->GetFont()->IsOutline() ) + formatRenderCache( aTextBox, aNestLevel + 1 ); + + m_out->Print( aNestLevel, ")\n" ); +} + + void PCB_PLUGIN::format( const PCB_TRACK* aTrack, int aNestLevel ) const { if( aTrack->Type() == PCB_VIA_T ) diff --git a/pcbnew/plugins/kicad/pcb_plugin.h b/pcbnew/plugins/kicad/pcb_plugin.h index f60ce336ef..b480cb1cb6 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.h +++ b/pcbnew/plugins/kicad/pcb_plugin.h @@ -41,10 +41,12 @@ class PCB_SHAPE; class PCB_TARGET; class PAD; class FP_TEXT; +class FP_TEXTBOX; class PCB_GROUP; class PCB_TRACK; class ZONE; class PCB_TEXT; +class PCB_TEXTBOX; class EDA_TEXT; class SHAPE_LINE_CHAIN; @@ -275,8 +277,10 @@ private: void format( const PAD* aPad, int aNestLevel = 0 ) const; void format( const PCB_TEXT* aText, int aNestLevel = 0 ) const; + void format( const PCB_TEXTBOX* aTextBox, int aNestLevel = 0 ) const; void format( const FP_TEXT* aText, int aNestLevel = 0 ) const; + void format( const FP_TEXTBOX* aTextBox, int aNestLevel = 0 ) const; void format( const PCB_TRACK* aTrack, int aNestLevel = 0 ) const; diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 604c6801e8..14fab0aaab 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -1286,7 +1286,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld ) for( BOARD_ITEM* gitem : m_board->Drawings() ) { - if ( gitem->Type() == PCB_SHAPE_T ) + if ( gitem->Type() == PCB_SHAPE_T || gitem->Type() == PCB_TEXTBOX_T ) { syncGraphicalItem( aWorld, static_cast( gitem ) ); } @@ -1328,7 +1328,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld ) for( BOARD_ITEM* mgitem : footprint->GraphicalItems() ) { - if( mgitem->Type() == PCB_FP_SHAPE_T ) + if( mgitem->Type() == PCB_FP_SHAPE_T || mgitem->Type() == PCB_FP_TEXTBOX_T ) { syncGraphicalItem( aWorld, static_cast( mgitem ) ); } diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 16a0151578..88a96276cf 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -252,6 +252,8 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem, case PCB_TEXT_T: case PCB_FP_TEXT_T: + case PCB_TEXTBOX_T: + case PCB_FP_TEXTBOX_T: SetFailureReason( _( "Cannot start routing from a text item." ) ); break; diff --git a/pcbnew/toolbars_footprint_editor.cpp b/pcbnew/toolbars_footprint_editor.cpp index b9a619790d..6d0ef7d4d4 100644 --- a/pcbnew/toolbars_footprint_editor.cpp +++ b/pcbnew/toolbars_footprint_editor.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -186,6 +186,7 @@ void FOOTPRINT_EDIT_FRAME::ReCreateVToolbar() m_drawToolBar->Add( PCB_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE ); + m_drawToolBar->Add( PCB_ACTIONS::drawTextBox, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->AddGroup( dimensionGroup, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE ); diff --git a/pcbnew/toolbars_pcb_editor.cpp b/pcbnew/toolbars_pcb_editor.cpp index d7ed5ac486..64c4fa87ce 100644 --- a/pcbnew/toolbars_pcb_editor.cpp +++ b/pcbnew/toolbars_pcb_editor.cpp @@ -4,7 +4,7 @@ * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh - * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2022 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 @@ -456,6 +456,7 @@ void PCB_EDIT_FRAME::ReCreateVToolbar() m_drawToolBar->Add( PCB_ACTIONS::drawCircle, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::drawPolygon, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::placeText, ACTION_TOOLBAR::TOGGLE ); + m_drawToolBar->Add( PCB_ACTIONS::drawTextBox, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->AddGroup( dimensionGroup, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( PCB_ACTIONS::placeTarget, ACTION_TOOLBAR::TOGGLE ); m_drawToolBar->Add( ACTIONS::deleteTool, ACTION_TOOLBAR::TOGGLE ); diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index b5020ae8ff..711f1c446c 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014-2017 CERN - * Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -56,11 +55,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -333,12 +334,34 @@ int DRAWING_TOOL::DrawRectangle( const TOOL_EVENT& aEvent ) REENTRANCY_GUARD guard( &m_inDrawingTool ); - FOOTPRINT* parentFootprint = dynamic_cast( m_frame->GetModel() ); - PCB_SHAPE* rect = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE; + bool isTextBox = aEvent.IsAction( &PCB_ACTIONS::drawTextBox ); + PCB_SHAPE* rect = nullptr; BOARD_COMMIT commit( m_frame ); SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RECTANGLE ); OPT startingPoint = boost::make_optional( false, VECTOR2D( 0, 0 ) ); + auto makeNew = + [&]() -> PCB_SHAPE* + { + if( m_isFootprintEditor ) + { + FOOTPRINT* parentFootprint = dynamic_cast( m_frame->GetModel() ); + + if( isTextBox ) + return new FP_TEXTBOX( parentFootprint ); + else + return new FP_SHAPE( parentFootprint ); + } + else + { + if( isTextBox ) + return new PCB_TEXTBOX( m_frame->GetModel() ); + else + return new PCB_SHAPE(); + } + }; + + rect = makeNew(); rect->SetShape( SHAPE_T::RECT ); rect->SetFilled( false ); rect->SetFlags(IS_NEW ); @@ -357,13 +380,21 @@ int DRAWING_TOOL::DrawRectangle( const TOOL_EVENT& aEvent ) if( m_isFootprintEditor ) static_cast( rect )->SetLocalCoord(); - commit.Add( rect ); - commit.Push( _( "Draw a rectangle" ) ); + if( isTextBox && m_frame->ShowTextBoxPropertiesDialog( rect ) != wxID_OK ) + { + delete rect; + rect = nullptr; + } + else + { + commit.Add( rect ); + commit.Push( isTextBox ? _( "Draw a text box" ) : _( "Draw a rectangle" ) ); - m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, rect ); + m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, rect ); + } } - rect = m_isFootprintEditor ? new FP_SHAPE( parentFootprint ) : new PCB_SHAPE; + rect = makeNew(); rect->SetShape( SHAPE_T::RECT ); rect->SetFilled( false ); rect->SetFlags(IS_NEW ); @@ -589,7 +620,7 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent ) abs( thickness - GetPenSizeForNormal( textSize ) ) ); fpText->SetItalic( dsnSettings.GetTextItalic( layer ) ); fpText->SetKeepUpright( dsnSettings.GetTextUpright( layer ) ); - fpText->SetTextPos( (wxPoint) cursorPos ); + fpText->SetTextPos( cursorPos ); text = fpText; @@ -606,7 +637,7 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent ) delete text; text = nullptr; } - else if( fpText->GetTextPos() != (wxPoint) cursorPos ) + else if( fpText->GetTextPos() != cursorPos ) { // If the user modified the location then go ahead and place it there. // Otherwise we'll drag. @@ -629,7 +660,7 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent ) pcbText->SetBold( abs( thickness - GetPenSizeForBold( textSize ) ) < abs( thickness - GetPenSizeForNormal( textSize ) ) ); pcbText->SetItalic( dsnSettings.GetTextItalic( layer ) ); - pcbText->SetTextPos( (wxPoint) cursorPos ); + pcbText->SetTextPos( cursorPos ); RunMainStack( [&]() { @@ -686,7 +717,7 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent ) } else if( text && evt->IsMotion() ) { - text->SetPosition( (wxPoint) cursorPos ); + text->SetPosition( cursorPos ); selection().SetReferencePoint( cursorPos ); m_view->Update( &selection() ); } @@ -722,7 +753,7 @@ void DRAWING_TOOL::constrainDimension( PCB_DIMENSION_BASE* aDim ) { const VECTOR2I lineVector{ aDim->GetEnd() - aDim->GetStart() }; - aDim->SetEnd( wxPoint( VECTOR2I( aDim->GetStart() ) + GetVectorSnapped45( lineVector ) ) ); + aDim->SetEnd( aDim->GetStart() + GetVectorSnapped45( lineVector ) ); aDim->Update(); } @@ -914,7 +945,7 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) else if( originalEvent.IsAction( &PCB_ACTIONS::drawLeader ) ) { dimension = new PCB_DIM_LEADER( m_frame->GetModel(), m_isFootprintEditor ); - dimension->Text().SetPosition( wxPoint( cursorPos ) ); + dimension->Text().SetPosition( cursorPos ); } else { @@ -930,8 +961,8 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) dimension->SetLineThickness( boardSettings.GetLineThickness( layer ) ); dimension->SetArrowLength( boardSettings.m_DimensionArrowLength ); dimension->SetExtensionOffset( boardSettings.m_DimensionExtensionOffset ); - dimension->SetStart( (wxPoint) cursorPos ); - dimension->SetEnd( (wxPoint) cursorPos ); + dimension->SetStart( cursorPos ); + dimension->SetEnd( cursorPos ); dimension->Update(); if( !m_view->IsLayerVisible( layer ) ) @@ -1000,7 +1031,7 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) switch( step ) { case SET_END: - dimension->SetEnd( (wxPoint) cursorPos ); + dimension->SetEnd( cursorPos ); if( Is45Limited() || t == PCB_DIM_CENTER_T || t == PCB_FP_DIM_CENTER_T ) constrainDimension( dimension ); @@ -1021,7 +1052,7 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) else if( t == PCB_DIM_RADIAL_T || t == PCB_FP_DIM_RADIAL_T ) { PCB_DIM_RADIAL* radialDim = static_cast( dimension ); - wxPoint textOffset( radialDim->GetArrowLength() * 10, 0 ); + VECTOR2I textOffset( radialDim->GetArrowLength() * 10, 0 ); if( radialDim->GetEnd().x < radialDim->GetStart().x ) textOffset = -textOffset; @@ -1030,7 +1061,7 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) } else if( t == PCB_DIM_LEADER_T || t == PCB_FP_DIM_LEADER_T ) { - wxPoint textOffset( dimension->GetArrowLength() * 10, 0 ); + VECTOR2I textOffset( dimension->GetArrowLength() * 10, 0 ); if( dimension->GetEnd().x < dimension->GetStart().x ) textOffset = -textOffset; @@ -1266,7 +1297,7 @@ int DRAWING_TOOL::PlaceImportedGraphics( const TOOL_EVENT& aEvent ) VECTOR2I delta = cursorPos - static_cast( preview.Front() )->GetPosition(); for( BOARD_ITEM* item : selectedItems ) - item->Move( (wxPoint) delta ); + item->Move( delta ); m_view->Update( &preview ); @@ -1290,7 +1321,7 @@ int DRAWING_TOOL::PlaceImportedGraphics( const TOOL_EVENT& aEvent ) delta = cursorPos - static_cast( preview.Front() )->GetPosition(); for( BOARD_ITEM* item : selectedItems ) - item->Move( (wxPoint) delta ); + item->Move( delta ); m_view->Update( &preview ); } @@ -1375,7 +1406,7 @@ int DRAWING_TOOL::SetAnchor( const TOOL_EVENT& aEvent ) commit.Modify( footprint ); // set the new relative internal local coordinates of footprint items - VECTOR2I moveVector = footprint->GetPosition() - (wxPoint) cursorPos; + VECTOR2I moveVector = footprint->GetPosition() - cursorPos; footprint->MoveAnchorPosition( moveVector ); commit.Push( _( "Move the footprint reference anchor" ) ); @@ -1433,8 +1464,8 @@ static void updateSegmentFromGeometryMgr( const KIGFX::PREVIEW::TWO_POINT_GEOMET { if( !aMgr.IsReset() ) { - aGraphic->SetStart( (wxPoint) aMgr.GetOrigin() ); - aGraphic->SetEnd( (wxPoint) aMgr.GetEnd() ); + aGraphic->SetStart( aMgr.GetOrigin() ); + aGraphic->SetEnd( aMgr.GetEnd() ); } } @@ -1618,8 +1649,8 @@ bool DRAWING_TOOL::drawSegment( const std::string& aTool, PCB_SHAPE** aGraphic, graphic->SetLayer( m_layer ); grid.SetSkipPoint( cursorPos ); - twoPointManager.SetOrigin( (wxPoint) cursorPos ); - twoPointManager.SetEnd( (wxPoint) cursorPos ); + twoPointManager.SetOrigin( cursorPos ); + twoPointManager.SetEnd( cursorPos ); if( !isLocalOriginSet ) m_frame->GetScreen()->m_LocalOrigin = cursorPos; @@ -1691,12 +1722,12 @@ bool DRAWING_TOOL::drawSegment( const std::string& aTool, PCB_SHAPE** aGraphic, // get a restricted 45/H/V line from the last fixed point to the cursor auto newEnd = GetVectorSnapped45( lineVector, ( shape == SHAPE_T::RECT ) ); m_controls->ForceCursorPosition( true, VECTOR2I( twoPointManager.GetEnd() ) ); - twoPointManager.SetEnd( twoPointManager.GetOrigin() + (wxPoint) newEnd ); + twoPointManager.SetEnd( twoPointManager.GetOrigin() + newEnd ); twoPointManager.SetAngleSnap( true ); } else { - twoPointManager.SetEnd( (wxPoint) cursorPos ); + twoPointManager.SetEnd( cursorPos ); twoPointManager.SetAngleSnap( false ); } @@ -1766,12 +1797,12 @@ static void updateArcFromConstructionMgr( const KIGFX::PREVIEW::ARC_GEOM_MANAGER { VECTOR2I vec = aMgr.GetOrigin(); - aArc.SetCenter( (wxPoint) vec ); + aArc.SetCenter( vec ); vec = aMgr.GetStartRadiusEnd(); - aArc.SetStart( (wxPoint) vec ); + aArc.SetStart( vec ); vec = aMgr.GetEndRadiusEnd(); - aArc.SetEnd( (wxPoint) vec ); + aArc.SetEnd( vec ); } @@ -2275,7 +2306,7 @@ int DRAWING_TOOL::DrawZone( const TOOL_EVENT& aEvent ) if( polyGeomMgr.IsSelfIntersecting( true ) ) { - wxPoint p = wxGetMousePosition() + wxPoint( 20, 20 ); + VECTOR2I p = wxGetMousePosition() + wxPoint( 20, 20 ); status.Move( p ); status.PopupFor( 1500 ); } @@ -2376,15 +2407,15 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) { const LSET lset = aVia->GetLayerSet(); VECTOR2I position = aVia->GetPosition(); - BOX2I bbox = aVia->GetBoundingBox(); + BOX2I bbox = aVia->GetBoundingBox(); std::vector items; - auto view = m_frame->GetCanvas()->GetView(); + KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView(); std::vector possible_tracks; view->Query( bbox, items ); - for( auto it : items ) + for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items ) { BOARD_ITEM* item = static_cast( it.first ); @@ -2395,7 +2426,9 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) { if( TestSegmentHit( position, track->GetStart(), track->GetEnd(), ( track->GetWidth() + aVia->GetWidth() ) / 2 ) ) + { possible_tracks.push_back( track ); + } } } @@ -2525,15 +2558,17 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) PAD* findPad( PCB_VIA* aVia ) { const VECTOR2I position = aVia->GetPosition(); - const LSET lset = aVia->GetLayerSet(); + const LSET lset = aVia->GetLayerSet(); for( FOOTPRINT* fp : m_board->Footprints() ) { - for(PAD* pad : fp->Pads() ) + for( PAD* pad : fp->Pads() ) { if( pad->HitTest( position ) && ( pad->GetLayerSet() & lset ).any() ) + { if( pad->GetNetCode() > 0 ) return pad; + } } } @@ -2581,11 +2616,10 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) void SnapItem( BOARD_ITEM *aItem ) override { - // If you place a Via on a track but not on its centerline, the current - // connectivity algorithm will require us to put a kink in the track when - // we break it (so that each of the two segments ends on the via center). - // That's not ideal, and is in fact probably worse than forcing snap in - // this situation. + // If you place a Via on a track but not on its centerline, the current connectivity + // algorithm will require us to put a kink in the track when we break it (so that each + // of the two segments ends on the via center). + // That's not ideal, and is probably worse than forcing snap in this situation. m_gridHelper.SetSnap( !( m_modifiers & MD_SHIFT ) ); PCB_VIA* via = static_cast( aItem ); @@ -2598,11 +2632,10 @@ int DRAWING_TOOL::DrawVia( const TOOL_EVENT& aEvent ) SEG trackSeg( track->GetStart(), track->GetEnd() ); VECTOR2I snap = m_gridHelper.AlignToSegment( position, trackSeg ); - aItem->SetPosition( (wxPoint) snap ); + aItem->SetPosition( snap ); } else if( pad && m_gridHelper.GetSnap() - && m_frame->GetMagneticItemsSettings()->pads - == MAGNETIC_OPTIONS::CAPTURE_ALWAYS ) + && m_frame->GetMagneticItemsSettings()->pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS ) { aItem->SetPosition( pad->GetPosition() ); } @@ -2767,6 +2800,7 @@ void DRAWING_TOOL::setTransitions() Go( &DRAWING_TOOL::DrawZone, PCB_ACTIONS::drawSimilarZone.MakeEvent() ); Go( &DRAWING_TOOL::DrawVia, PCB_ACTIONS::drawVia.MakeEvent() ); Go( &DRAWING_TOOL::PlaceText, PCB_ACTIONS::placeText.MakeEvent() ); + Go( &DRAWING_TOOL::DrawRectangle, PCB_ACTIONS::drawTextBox.MakeEvent() ); Go( &DRAWING_TOOL::PlaceImportedGraphics, PCB_ACTIONS::placeImportedGraphics.MakeEvent() ); Go( &DRAWING_TOOL::SetAnchor, PCB_ACTIONS::setAnchor.MakeEvent() ); Go( &DRAWING_TOOL::ToggleLine45degMode, PCB_ACTIONS::toggle45.MakeEvent() ); diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index d081420427..6b6cb2bd26 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1584,6 +1585,7 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) { case PCB_FP_SHAPE_T: case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_ZONE_T: case PCB_PAD_T: // Only create undo entry for items on the board @@ -1619,6 +1621,13 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) break; } + case PCB_FP_TEXTBOX_T: + { + FP_TEXTBOX* textbox = static_cast( item ); + textbox->Mirror( mirrorPoint, false ); + break; + } + case PCB_PAD_T: { PAD* pad = static_cast( item ); @@ -1849,6 +1858,17 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) break; } + case PCB_FP_TEXTBOX_T: + { + FP_TEXTBOX* textbox = static_cast( item ); + FOOTPRINT* parent = static_cast( item->GetParent() ); + + m_commit->Modify( parent ); + getView()->Remove( textbox ); + parent->Remove( textbox ); + break; + } + case PCB_PAD_T: if( IsFootprintEditor() || frame()->Settings().m_AllowFreePads ) { @@ -2142,6 +2162,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) { case PCB_FOOTPRINT_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: case PCB_SHAPE_T: case PCB_TRACE_T: case PCB_ARC_T: diff --git a/pcbnew/tools/group_tool.cpp b/pcbnew/tools/group_tool.cpp index a3e086c18d..5d01156037 100644 --- a/pcbnew/tools/group_tool.cpp +++ b/pcbnew/tools/group_tool.cpp @@ -236,6 +236,7 @@ int GROUP_TOOL::Group( const TOOL_EVENT& aEvent ) switch( item->Type() ) { case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_FP_ZONE_T: case PCB_PAD_T: diff --git a/pcbnew/tools/pcb_actions.cpp b/pcbnew/tools/pcb_actions.cpp index 25251bd9fd..f482501703 100644 --- a/pcbnew/tools/pcb_actions.cpp +++ b/pcbnew/tools/pcb_actions.cpp @@ -123,6 +123,11 @@ TOOL_ACTION PCB_ACTIONS::placeText( "pcbnew.InteractiveDrawing.text", _( "Add Text" ), _( "Add a text item" ), BITMAPS::text, AF_ACTIVATE ); +TOOL_ACTION PCB_ACTIONS::drawTextBox( "pcbnew.InteractiveDrawing.textbox", + AS_GLOBAL, 0, "", + _( "Add Text Box" ), _( "Add a wrapped text item" ), + BITMAPS::add_textbox, AF_ACTIVATE ); + TOOL_ACTION PCB_ACTIONS::drawAlignedDimension( "pcbnew.InteractiveDrawing.alignedDimension", AS_GLOBAL, MD_SHIFT + MD_CTRL + 'H', LEGACY_HK_NAME( "Add Dimension" ), diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 77bd02d082..7d168b4072 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -148,6 +148,7 @@ public: static TOOL_ACTION drawCircle; static TOOL_ACTION drawArc; static TOOL_ACTION placeText; + static TOOL_ACTION drawTextBox; static TOOL_ACTION drawAlignedDimension; static TOOL_ACTION drawCenterDimension; static TOOL_ACTION drawRadialDimension; diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index 5b048f771c..7f8e86a530 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014-2016 CERN - * Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -40,9 +40,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -661,7 +663,7 @@ static void pasteFootprintItemsToFootprintEditor( FOOTPRINT* aClipFootprint, BOA // So they will be skipped for( BOARD_ITEM* item : aClipFootprint->GraphicalItems() ) { - if( item->Type() == PCB_FP_SHAPE_T ) + if( item->Type() == PCB_FP_SHAPE_T || item->Type() == PCB_FP_TEXTBOX_T ) { FP_SHAPE* shape = static_cast( item ); @@ -790,6 +792,18 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent ) pastedTextItem->SetParent( editorFootprint ); pastedItems.push_back( pastedTextItem ); } + else if( clipDrawItem->Type() == PCB_TEXTBOX_T ) + { + PCB_TEXTBOX* clipTextBox = static_cast( clipDrawItem ); + + // Convert to PCB_FP_TEXTBOX_T + FP_TEXTBOX* pastedTextBox = new FP_TEXTBOX( editorFootprint ); + static_cast( pastedTextBox )->SwapText( *clipTextBox ); + static_cast( pastedTextBox )->SwapAttributes( *clipTextBox ); + + pastedTextBox->SetParent( editorFootprint ); + pastedItems.push_back( pastedTextBox ); + } } delete clipBoard; diff --git a/pcbnew/tools/pcb_grid_helper.cpp b/pcbnew/tools/pcb_grid_helper.cpp index d247a42abc..c83994a8a9 100644 --- a/pcbnew/tools/pcb_grid_helper.cpp +++ b/pcbnew/tools/pcb_grid_helper.cpp @@ -24,7 +24,6 @@ */ #include -#include #include #include #include @@ -555,6 +554,8 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos case PCB_FP_SHAPE_T: case PCB_SHAPE_T: + case PCB_FP_TEXTBOX_T: + case PCB_TEXTBOX_T: { if( !m_magneticSettings->graphics ) break; diff --git a/pcbnew/tools/pcb_point_editor.cpp b/pcbnew/tools/pcb_point_editor.cpp index 3e843de780..0431cb1137 100644 --- a/pcbnew/tools/pcb_point_editor.cpp +++ b/pcbnew/tools/pcb_point_editor.cpp @@ -32,15 +32,16 @@ using namespace std::placeholders; #include #include #include -#include "pcb_actions.h" -#include "pcb_selection_tool.h" -#include "pcb_point_editor.h" -#include "pcb_grid_helper.h" +#include +#include +#include +#include #include -#include #include #include +#include #include +#include #include #include #include @@ -154,8 +155,7 @@ void PCB_POINT_EDITOR::buildForPolyOutline( std::shared_ptr points, points->AddBreak(); } - // Lines have to be added after creating edit points, - // as they use EDIT_POINT references + // Lines have to be added after creating edit points, as they use EDIT_POINT references for( int i = 0; i < cornersCount - 1; ++i ) { if( points->IsContourEnd( i ) ) @@ -182,9 +182,21 @@ std::shared_ptr PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem ) if( !aItem ) return points; + if( aItem->Type() == PCB_TEXTBOX_T || aItem->Type() == PCB_FP_TEXTBOX_T ) + { + const PCB_SHAPE* shape = static_cast( aItem ); + + // We can't currently handle TEXTBOXes that have been turned into SHAPE_T::POLYs due + // to non-cardinal rotations + if( shape->GetShape() != SHAPE_T::RECT ) + return points; + } + // Generate list of edit points basing on the item type switch( aItem->Type() ) { + case PCB_TEXTBOX_T: + case PCB_FP_TEXTBOX_T: case PCB_SHAPE_T: case PCB_FP_SHAPE_T: { @@ -1053,6 +1065,8 @@ void PCB_POINT_EDITOR::updateItem() const switch( item->Type() ) { + case PCB_TEXTBOX_T: + case PCB_FP_TEXTBOX_T: case PCB_SHAPE_T: case PCB_FP_SHAPE_T: { @@ -1108,11 +1122,14 @@ void PCB_POINT_EDITOR::updateItem() const for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i ) { if( !isModified( m_editPoints->Line( i ) ) ) + { m_editPoints->Line( i ).SetConstraint( new EC_PERPLINE( m_editPoints->Line( i ) ) ); + } } - } + break; + } case SHAPE_T::ARC: { @@ -1145,8 +1162,9 @@ void PCB_POINT_EDITOR::updateItem() const else editArcEndpointKeepTangent( shape, center, start, mid, end, cursorPos ); } - } + break; + } case SHAPE_T::CIRCLE: { @@ -1162,8 +1180,9 @@ void PCB_POINT_EDITOR::updateItem() const { shape->SetEnd( VECTOR2I( end.x, end.y ) ); } - } + break; + } case SHAPE_T::POLY: { @@ -1180,8 +1199,8 @@ void PCB_POINT_EDITOR::updateItem() const } validatePolygon( outline ); - } break; + } case SHAPE_T::BEZIER: if( isModified( m_editPoints->Point( BEZIER_CURVE_START ) ) ) @@ -1222,8 +1241,8 @@ void PCB_POINT_EDITOR::updateItem() const int diameter = (int) EuclideanNorm( end - pad->GetPosition() ) * 2; pad->SetSize( wxSize( diameter, diameter ) ); - } break; + } case PAD_SHAPE::OVAL: case PAD_SHAPE::TRAPEZOID: @@ -1307,8 +1326,8 @@ void PCB_POINT_EDITOR::updateItem() const pad->SetPosition( VECTOR2I( ( left + right ) / 2, ( top + bottom ) / 2 ) ); pad->SetLocalCoord(); } - } break; + } default: // suppress warnings break; @@ -1618,10 +1637,25 @@ void PCB_POINT_EDITOR::updatePoints() if( !item ) return; + if( item->Type() == PCB_TEXTBOX_T || item->Type() == PCB_FP_TEXTBOX_T ) + { + const PCB_SHAPE* shape = static_cast( item ); + + // We can't currently handle TEXTBOXes that have been turned into SHAPE_T::POLYs due + // to non-cardinal rotations + if( shape->GetShape() != SHAPE_T::RECT ) + { + m_editPoints.reset(); + return; + } + } + switch( item->Type() ) { case PCB_SHAPE_T: case PCB_FP_SHAPE_T: + case PCB_TEXTBOX_T: + case PCB_FP_TEXTBOX_T: { const PCB_SHAPE* shape = static_cast( item ); diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp index 2313aacdf5..65e86d7609 100644 --- a/pcbnew/tools/pcb_selection_tool.cpp +++ b/pcbnew/tools/pcb_selection_tool.cpp @@ -39,6 +39,8 @@ using namespace std::placeholders; #include #include #include +#include +#include #include #include #include @@ -1889,7 +1891,9 @@ static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard break; case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: include = aFilterOptions.includePcbTexts; break; @@ -2023,7 +2027,9 @@ bool PCB_SELECTION_TOOL::itemPassesFilter( BOARD_ITEM* aItem, bool aMultiSelect break; case PCB_FP_TEXT_T: + case PCB_FP_TEXTBOX_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: if( !m_filter.text ) return false; @@ -2430,6 +2436,7 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili break; case PCB_FP_SHAPE_T: + case PCB_FP_TEXTBOX_T: if( m_isFootprintEditor ) { if( !view()->IsLayerVisible( aItem->GetLayer() ) ) @@ -2652,6 +2659,13 @@ int PCB_SELECTION_TOOL::hitTestDistance( const wxPoint& aWhere, BOARD_ITEM* aIte break; } + case PCB_TEXTBOX_T: + { + PCB_TEXTBOX* textbox = static_cast( aItem ); + textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ); + break; + } + case PCB_FP_TEXT_T: { FP_TEXT* text = static_cast( aItem ); @@ -2659,6 +2673,13 @@ int PCB_SELECTION_TOOL::hitTestDistance( const wxPoint& aWhere, BOARD_ITEM* aIte break; } + case PCB_FP_TEXTBOX_T: + { + FP_TEXTBOX* textbox = static_cast( aItem ); + textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance ); + break; + } + case PCB_ZONE_T: { ZONE* zone = static_cast( aItem ); @@ -2757,7 +2778,7 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector BOARD_ITEM* item = aCollector[i]; KICAD_T type = item->Type(); - if( ( type == PCB_FP_TEXT_T || type == PCB_TEXT_T || type == PCB_SHAPE_T ) + if( ( type == PCB_TEXT_T || type == PCB_TEXTBOX_T || type == PCB_SHAPE_T ) && silkLayers[item->GetLayer()] ) { preferred.insert( item ); diff --git a/pcbnew/tools/pcb_viewer_tools.cpp b/pcbnew/tools/pcb_viewer_tools.cpp index 140f0456b5..b928f4dafe 100644 --- a/pcbnew/tools/pcb_viewer_tools.cpp +++ b/pcbnew/tools/pcb_viewer_tools.cpp @@ -169,7 +169,7 @@ int PCB_VIEWER_TOOLS::TextOutlines( const TOOL_EVENT& aEvent ) { KICAD_T t = item->Type(); - if( t == PCB_TEXT_T || BaseType( t ) == PCB_DIMENSION_T ) + if( t == PCB_TEXT_T || t == PCB_TEXTBOX_T || BaseType( t ) == PCB_DIMENSION_T ) view()->Update( item, KIGFX::REPAINT ); } diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 8cc8a4dee9..ea7e049a07 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -560,6 +560,8 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap, { case PCB_SHAPE_T: case PCB_TEXT_T: + case PCB_TEXTBOX_T: + case PCB_FP_TEXTBOX_T: case PCB_FP_SHAPE_T: case PCB_TARGET_T: aItem->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError, @@ -575,8 +577,9 @@ void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer, int aGap, text->TransformShapeWithClearanceToPolygon( aHoles, aLayer, aGap, m_maxError, ERROR_OUTSIDE, aIgnoreLineWidth ); } - } + break; + } default: break; diff --git a/qa/pcbnew/test_board_item.cpp b/qa/pcbnew/test_board_item.cpp index eaca9f96e2..c4e2aeed09 100644 --- a/qa/pcbnew/test_board_item.cpp +++ b/qa/pcbnew/test_board_item.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2021 KiCad Developers, see AUTHORS.TXT for contributors. + * Copyright (C) 2022 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 @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -73,7 +75,9 @@ public: case PCB_PAD_T: return new PAD( &m_footprint ); case PCB_SHAPE_T: return new PCB_SHAPE( &m_board ); case PCB_TEXT_T: return new PCB_TEXT( &m_board ); + case PCB_TEXTBOX_T: return new PCB_TEXTBOX( &m_board ); case PCB_FP_TEXT_T: return new FP_TEXT( &m_footprint ); + case PCB_FP_TEXTBOX_T: return new FP_TEXTBOX( &m_footprint ); case PCB_FP_SHAPE_T: return new FP_SHAPE( &m_footprint ); case PCB_FP_DIM_ALIGNED_T: return new PCB_DIM_ALIGNED( &m_footprint, PCB_FP_DIM_ALIGNED_T ); case PCB_FP_DIM_LEADER_T: return new PCB_DIM_LEADER( &m_footprint, true );