TextBoxes for PCBNew.

This commit is contained in:
Jeff Young 2022-01-30 10:52:52 +00:00
parent 60bcfd1bf1
commit 5739505aa3
91 changed files with 5603 additions and 566 deletions

View File

@ -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 );

View File

@ -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 <board_adapter.h>
#include <footprint.h>
#include <pad.h>
@ -55,42 +56,49 @@
#include <macros.h>
#include <callback_gal.h>
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<const SHAPE_SEGMENT*>( 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<const SHAPE_SEGMENT*>( 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<const SHAPE_CIRCLE*>( 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<FP_TEXT*> 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<FP_TEXT*>( 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<FP_TEXTBOX*>( 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<PCB_DIMENSION_BASE*>( 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<FP_SHAPE*>( item );
if( shape->GetLayer() == aLayerId )
addShape( static_cast<const PCB_SHAPE*>( 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<const SHAPE_SEGMENT*>( 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<const SHAPE_CIRCLE*>( 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<const SHAPE_RECT*>( 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<const SHAPE_ARC*>( 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<VECTOR2I> 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 ) );
}
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
* 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 <footprint.h>
#include <pad.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <fp_shape.h>
#include <zone.h>
#include <convert_basic_shapes_to_polygon.h>
@ -606,11 +607,16 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
switch( item->Type() )
{
case PCB_SHAPE_T:
addShape( static_cast<PCB_SHAPE*>( item ), layerContainer );
addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item );
break;
case PCB_TEXT_T:
addShape( static_cast<PCB_TEXT*>( item ), layerContainer );
addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
break;
case PCB_TEXTBOX_T:
addText( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
addShape( static_cast<PCB_TEXTBOX*>( 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<PCB_DIMENSION_BASE*>( item ), layerContainer );
addShape( static_cast<PCB_DIMENSION_BASE*>( 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<PCB_TEXTBOX*>( 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<PCB_SHAPE*>( item ), layerContainer );
addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item );
break;
case PCB_TEXT_T:
addShape( static_cast<PCB_TEXT*>( item ), layerContainer );
addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
break;
case PCB_TEXTBOX_T:
addText( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
addShape( static_cast<PCB_TEXTBOX*>( 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<PCB_DIMENSION_BASE*>( item ), layerContainer );
addShape( static_cast<PCB_DIMENSION_BASE*>( 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<PCB_TEXTBOX*>( item );
textbox->TransformTextShapeWithClearanceToPolygon( *layerPoly, curr_layer_id, 0,
ARC_HIGH_DEF, ERROR_INSIDE );
break;
}
default:
break;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
* 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 <wx/log.h>
#include <map>
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 );

View File

@ -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

View File

@ -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" ) )

View File

@ -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();

View File

@ -457,8 +457,11 @@ EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
m_render_cache.clear();
KIFONT::OUTLINE_FONT* font = static_cast<KIFONT::OUTLINE_FONT*>( 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<int>( 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<VECTOR2I>& 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<VECTOR2I>& 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<SHAPE_COMPOUND> 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 );
}
}

View File

@ -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 )
{

View File

@ -191,20 +191,6 @@ BOX2I OUTLINE_FONT::getBoundingBox( const std::vector<std::unique_ptr<GLYPH>>& a
}
void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
const EDA_TEXT* aText ) const
{
wxArrayString strings;
std::vector<VECTOR2I> positions;
std::vector<VECTOR2I> 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<std::unique_ptr<GLYPH>>* aGlyphs,
const wxString& aText, const VECTOR2I& aPosition,
const TEXT_ATTRIBUTES& aAttrs ) const

View File

@ -27,6 +27,7 @@
#include <footprint.h>
#include <fp_text.h>
#include <fp_textbox.h>
#include <fp_shape.h>
#include <pad.h>
@ -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<const FP_TEXTBOX*>( 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)" );
}

View File

@ -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

View File

@ -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 );

View File

@ -512,7 +512,7 @@
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="flag">wxRIGHT|wxLEFT</property>
<property name="row">0</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="1">

View File

@ -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 );

View File

@ -222,7 +222,7 @@
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="flag">wxRIGHT|wxLEFT</property>
<property name="row">2</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="1">
@ -356,7 +356,7 @@
<property name="flag">wxEXPAND</property>
<property name="row">2</property>
<property name="rowspan">1</property>
<object class="wxBoxSizer" expanded="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">formattingSizer</property>
<property name="orient">wxHORIZONTAL</property>

View File

@ -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 );

View File

@ -211,7 +211,7 @@
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxRIGHT|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="1">
@ -275,7 +275,7 @@
<property name="border">5</property>
<property name="colspan">2</property>
<property name="column">1</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxEXPAND</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxChoice" expanded="1">
@ -342,17 +342,17 @@
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">3</property>
<property name="flag">wxEXPAND</property>
<property name="flag">wxEXPAND|wxTOP</property>
<property name="row">1</property>
<property name="rowspan">1</property>
<object class="wxBoxSizer" expanded="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizeCtrlSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -424,7 +424,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -496,7 +496,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -568,7 +568,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -640,7 +640,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -712,7 +712,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -784,7 +784,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -856,7 +856,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxALIGN_CENTER_VERTICAL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>
@ -928,7 +928,7 @@
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM</property>
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="0">
<property name="BottomDockable">1</property>

View File

@ -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<MSG_PANEL_ITEM>& aList )
{
wxString msg;
// Don't use GetShownText() here; we want to show the user the variable references
aList.emplace_back( _( "Text Box" ), UnescapeString( GetText() ) );

View File

@ -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:

View File

@ -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;

View File

@ -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<MSG_PANEL_ITEM>& aList )
{
wxString msg;
// Don't use GetShownText() here; we want to show the user the variable references
aList.emplace_back( _( "Text Box" ), UnescapeString( GetText() ) );

View File

@ -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:

View File

@ -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<std::unique_ptr<KIFONT::GLYPH>> 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;

View File

@ -112,9 +112,6 @@ public:
* @param aGlyphs returns text glyphs
* @param aText the text item
*/
void GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
const EDA_TEXT* aText ) const;
void GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs, const wxString& aText,
const VECTOR2I& aPosition, const TEXT_ATTRIBUTES& aAttrs ) const;

View File

@ -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

View File

@ -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:

View File

@ -5,7 +5,7 @@
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
*
* 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 <pcb_target.h>
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <core/arraydim.h>
#include <core/kicad_algo.h>
#include <connectivity/connectivity_data.h>
@ -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<const PCB_TEXT*>( aSecond );
return text->Compare( other );
}
else if( aFirst->Type() == PCB_TEXTBOX_T )
{
const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( aFirst );
const PCB_TEXTBOX* other = static_cast<const PCB_TEXTBOX*>( 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<const PCB_TEXTBOX*>( item );
textbox->TransformTextShapeWithClearanceToPolygon( aOutlines, aLayer, 0, maxError,
ERROR_INSIDE );
break;
}
default:
break;
}

View File

@ -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<FOOTPRINT*>( aItem->GetParent() ) );
return aItem;
case PCB_ZONE_T:
wxASSERT( !dynamic_cast<FOOTPRINT*>( aItem->GetParent() ) );
return aItem;
default:
break;
default:
break;
}
return aItem;

View File

@ -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<FP_TEXT*>( 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<FP_TEXT*>( 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<FP_TEXT*>( 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;

View File

@ -311,7 +311,8 @@ std::string FormatProbeItem( BOARD_ITEM* aItem )
footprint = static_cast<FOOTPRINT*>( aItem->GetParent() );
wxString pad = static_cast<PAD*>( 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() ) );
}

View File

@ -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;

View File

@ -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 );

View File

@ -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 <widgets/bitmap_button.h>
#include <widgets/font_choice.h>
#include <dialog_textbox_properties.h>
#include <confirm.h>
#include <widgets/unit_binder.h>
#include <board_commit.h>
#include <board.h>
#include <footprint.h>
#include <string_utils.h>
#include <pcb_textbox.h>
#include <fp_textbox.h>
#include <pcbnew.h>
#include <pcb_edit_frame.h>
#include <pcb_layer_box_selector.h>
#include <wx/valnum.h>
#include <math/util.h> // for KiROUND
#include <scintilla_tricks.h>
#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<FP_TEXTBOX*>( 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<PCB_TEXTBOX*>( 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();
}

View File

@ -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 <widgets/unit_binder.h>
#include <wx/valnum.h>
#include <dialog_textbox_properties_base.h>
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

View File

@ -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 );
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class BITMAP_BUTTON;
class FONT_CHOICE;
class PCB_LAYER_BOX_SELECTOR;
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/stc/stc.h>
#include <wx/sizer.h>
#include <wx/checkbox.h>
#include <wx/bmpcbox.h>
#include <wx/choice.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/textctrl.h>
#include <wx/combobox.h>
#include <wx/gbsizer.h>
#include <wx/statline.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// 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();
};

View File

@ -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;

View File

@ -208,7 +208,8 @@ int DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector<KICAD_T>& 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<KICAD_T>& 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;

View File

@ -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_ITEM> drc = DRC_ITEM::Create( DRCE_TEXT_ON_EDGECUTS );
drc->SetItems( item );

View File

@ -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 <macros.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <fp_text.h>
#include <fp_textbox.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
@ -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<PCB_TEXT*>( item );
visible = textItem->IsVisible();
actualH = textItem->GetTextHeight();
actualT = textItem->GetTextThickness();
}
else if( item->Type() == PCB_FP_TEXT_T )
{
FP_TEXT* fpTextItem = static_cast<FP_TEXT*>( item );
visible = fpTextItem->IsVisible();
actualH = fpTextItem->GetTextHeight();
actualT = fpTextItem->GetTextThickness();
}
else
{
UNIMPLEMENTED_FOR( item->GetClass() );
case PCB_TEXT_T: text = static_cast<PCB_TEXT*>( item ); break;
case PCB_TEXTBOX_T: text = static_cast<PCB_TEXTBOX*>( item ); break;
case PCB_FP_TEXT_T: text = static_cast<FP_TEXT*>( item ); break;
case PCB_FP_TEXTBOX_T: text = static_cast<FP_TEXTBOX*>( item ); break;
default: UNIMPLEMENTED_FOR( item->GetClass() ); break;
}
visible = text->IsVisible();
actualH = text->GetTextHeight();
actualT = text->GetTextThickness();
if( !visible )
return true;

View File

@ -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<PAD*>( 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;

View File

@ -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;

View File

@ -39,6 +39,9 @@
#include <pcbplot.h>
#include <gendrill_file_writer_base.h>
#include <pcb_painter.h>
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
/* 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<PCB_SHAPE*>( item ) );
break;
case PCB_TEXT_T:
itemplotter.PlotPcbText( (PCB_TEXT*) item );
itemplotter.PlotPcbText( static_cast<PCB_TEXT*>( item ), item->GetLayer() );
break;
case PCB_TEXTBOX_T:
itemplotter.PlotPcbText( static_cast<PCB_TEXTBOX*>( item ), item->GetLayer() );
itemplotter.PlotPcbShape( static_cast<PCB_TEXTBOX*>( item ) );
break;
case PCB_DIM_ALIGNED_T:

View File

@ -34,12 +34,14 @@
#include <board.h>
#include <board_design_settings.h>
#include <pcb_shape.h>
#include <pcbplot.h>
#include <wildcards_and_files_ext.h>
#include <gbr_metadata.h>
#include <footprint.h>
#include <pad.h>
#include <fp_shape.h>
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<FP_SHAPE*>( item ) );
}
}
}

View File

@ -47,6 +47,7 @@
#include <i18n_utility.h>
#include <convert_shape_list_to_polygon.h>
#include <geometry/convex_hull.h>
#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<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS,
"Please report this bug: Invalid remove operation on required text" );
wxCHECK_RET( static_cast<FP_TEXT*>( 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<BOARD_ITEM*>( 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<FP_TEXT*>( item )->Flip( m_pos, false );
break;
case PCB_FP_TEXTBOX_T:
static_cast<FP_TEXTBOX*>( 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<FP_SHAPE*>( 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<FP_SHAPE*>( item );
shape->Move( moveVector );
}
break;
}
case PCB_FP_TEXT_T:
{
FP_TEXT* text = static_cast<FP_TEXT*>( 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<FP_SHAPE*>( item )->SetDrawCoord();
else if( item->Type() == PCB_FP_TEXT_T )
break;
case PCB_FP_TEXT_T:
static_cast<FP_TEXT*>( 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<const FP_TEXTBOX*>( aItem ) );
const_cast<KIID&>( 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<const FP_TEXTBOX*>( 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<FP_TEXTBOX*>( 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<FP_SHAPE*>( item );

View File

@ -4,7 +4,7 @@
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2015-2016 Wayne Stambaugh <stambaughw@gmail.com>
* 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 );

View File

@ -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;

View File

@ -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;
}
}

View File

@ -37,8 +37,8 @@
#include <view/view.h>
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;
}

View File

@ -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<MSG_PANEL_ITEM>& aList ) override;

406
pcbnew/fp_textbox.cpp Normal file
View File

@ -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 <pcb_edit_frame.h>
#include <base_units.h>
#include <bitmaps.h>
#include <board.h>
#include <board_design_settings.h>
#include <core/mirror.h>
#include <footprint.h>
#include <fp_textbox.h>
#include <settings/settings_manager.h>
#include <trigo.h>
#include <string_utils.h>
#include <painter.h>
#include <geometry/shape_compound.h>
#include <callback_gal.h>
#include <convert_basic_shapes_to_polygon.h>
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<FOOTPRINT*>( m_parent );
EDA_ANGLE rotation = GetTextAngle();
if( parentFootprint )
rotation += parentFootprint->GetOrientation();
rotation.Normalize();
return rotation;
}
std::vector<VECTOR2I> FP_TEXTBOX::GetAnchorAndOppositeCorner() const
{
std::vector<VECTOR2I> pts;
std::vector<VECTOR2I> 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<VECTOR2I> 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<MSG_PANEL_ITEM>& 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<FOOTPRINT*>( 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<double>::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<FOOTPRINT*>( GetParent() );
wxASSERT( parentFootprint );
const BOARD* board = parentFootprint->GetBoard();
std::function<bool( wxString* )> footprintResolver =
[&]( wxString* token ) -> bool
{
return parentFootprint && parentFootprint->ResolveTextVar( token, aDepth );
};
std::function<bool( wxString* )> 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<BOARD*>( parentFootprint->GetParent() )->GetProject();
if( aDepth < 10 )
text = ExpandTextVars( text, &footprintResolver, &boardTextResolver, project );
}
KIFONT::FONT* font = GetDrawFont();
std::vector<VECTOR2I> 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<SHAPE> 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<FP_TEXTBOX, FP_SHAPE> );
propMgr.AddTypeCast( new TYPE_CAST<FP_TEXTBOX, EDA_TEXT> );
propMgr.InheritsAfter( TYPE_HASH( FP_TEXTBOX ), TYPE_HASH( FP_SHAPE ) );
propMgr.InheritsAfter( TYPE_HASH( FP_TEXTBOX ), TYPE_HASH( EDA_TEXT ) );
propMgr.AddProperty( new PROPERTY<FP_TEXTBOX, wxString>( _HKI( "Parent" ),
NO_SETTER( FP_TEXTBOX, wxString ), &FP_TEXTBOX::GetParentAsString ) );
}
} _FP_TEXTBOX_DESC;

144
pcbnew/fp_textbox.h Normal file
View File

@ -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 <eda_text.h>
#include <fp_shape.h>
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<VECTOR2I> 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<MSG_PANEL_ITEM>& 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<SHAPE> 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

View File

@ -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 <pcb_group.h>
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <fp_text.h>
#include <fp_textbox.h>
#include <zone.h>
#include <locale_io.h>
#include <netinfo.h>
@ -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<FP_TEXTBOX*>( 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

View File

@ -4,7 +4,7 @@
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2015 Wayne Stambaugh <stambaughw@gmail.com>
* 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 );

View File

@ -4,7 +4,7 @@
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
* 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 );

View File

@ -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()

View File

@ -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:

View File

@ -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 );

View File

@ -30,15 +30,16 @@
#include <pcb_track.h>
#include <pcb_group.h>
#include <footprint.h>
#include <fp_textbox.h>
#include <pad.h>
#include <pcb_shape.h>
#include <string_utils.h>
#include <zone.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <pcb_marker.h>
#include <pcb_dimension.h>
#include <pcb_target.h>
#include <advanced_config.h>
#include <layer_ids.h>
#include <pcb_painter.h>
@ -460,10 +461,18 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
draw( static_cast<const PCB_TEXT*>( item ), aLayer );
break;
case PCB_TEXTBOX_T:
draw( static_cast<const PCB_TEXTBOX*>( item ), aLayer );
break;
case PCB_FP_TEXT_T:
draw( static_cast<const FP_TEXT*>( item ), aLayer );
break;
case PCB_FP_TEXTBOX_T:
draw( static_cast<const FP_TEXTBOX*>( item ), aLayer );
break;
case PCB_FOOTPRINT_T:
draw( static_cast<const FOOTPRINT*>( 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<VECTOR2I> 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<SHAPE*> 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<std::unique_ptr<KIFONT::GLYPH>>* cache = aTextBox->GetRenderCache( resolvedText );
if( cache )
{
for( const std::unique_ptr<KIFONT::GLYPH>& 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<VECTOR2I> 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<SHAPE*> 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<std::unique_ptr<KIFONT::GLYPH>>* cache = aTextBox->GetRenderCache( resolvedText );
if( cache )
{
for( const std::unique_ptr<KIFONT::GLYPH>& 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 );
}
}

View File

@ -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 <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>
@ -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 );

View File

@ -4,7 +4,7 @@
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
* 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 <base_units.h>
#include <geometry/shape_compound.h>
#include <pcb_shape.h>
#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<VECTOR2I> PCB_SHAPE::GetCorners() const
{
std::vector<VECTOR2I> 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 );

View File

@ -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<VECTOR2I> 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.

View File

@ -23,7 +23,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <eda_item.h>
#include <pcb_edit_frame.h>
#include <base_units.h>
#include <bitmaps.h>

View File

@ -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" );
}
/**

340
pcbnew/pcb_textbox.cpp Normal file
View File

@ -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 <pcb_edit_frame.h>
#include <base_units.h>
#include <bitmaps.h>
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>
#include <pcb_textbox.h>
#include <pcb_painter.h>
#include <trigo.h>
#include <string_utils.h>
#include <geometry/shape_compound.h>
#include <callback_gal.h>
#include <convert_basic_shapes_to_polygon.h>
#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<VECTOR2I> 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<VECTOR2I> pts;
std::vector<VECTOR2I> 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<VECTOR2I> 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<BOARD*>( GetParent() );
std::function<bool( wxString* )> 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<FOOTPRINT*>( refItem );
if( refFP->ResolveTextVar( &remainder, aDepth + 1 ) )
{
*token = remainder;
return true;
}
}
}
return false;
};
std::function<bool( wxString* )> 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<VECTOR2I> 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<MSG_PANEL_ITEM>& 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<SHAPE> 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<PCB_TEXTBOX, PCB_SHAPE> );
propMgr.AddTypeCast( new TYPE_CAST<PCB_TEXTBOX, EDA_TEXT> );
propMgr.InheritsAfter( TYPE_HASH( PCB_TEXTBOX ), TYPE_HASH( PCB_SHAPE ) );
propMgr.InheritsAfter( TYPE_HASH( PCB_TEXTBOX ), TYPE_HASH( EDA_TEXT ) );
}
} _PCB_TEXTBOX_DESC;

127
pcbnew/pcb_textbox.h Normal file
View File

@ -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 <eda_text.h>
#include <pcb_shape.h>
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<VECTOR2I> 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<MSG_PANEL_ITEM>& 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<SHAPE> 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

View File

@ -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 );
/**

View File

@ -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<const FP_SHAPE*>( item ) );
itemplotter.PlotFootprintShape( static_cast<const FP_SHAPE*>( item ) );
}
}
}

View File

@ -55,10 +55,12 @@
#include <fp_shape.h>
#include <footprint.h>
#include <fp_text.h>
#include <fp_textbox.h>
#include <pcb_track.h>
#include <pad.h>
#include <pcb_target.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <zone.h>
#include <wx/debug.h> // for wxASSERT_MSG
@ -350,7 +352,12 @@ void BRDITEMS_PLOTTER::PlotPcbGraphicItem( const BOARD_ITEM* item )
break;
case PCB_TEXT_T:
PlotPcbText( static_cast<const PCB_TEXT*>( item ) );
PlotPcbText( static_cast<const PCB_TEXT*>( item ), item->GetLayer() );
break;
case PCB_TEXTBOX_T:
PlotPcbText( static_cast<const PCB_TEXTBOX*>( item ), item->GetLayer() );
PlotPcbShape( static_cast<const PCB_TEXTBOX*>( 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>& 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<const FP_SHAPE*>( 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<const FP_TEXTBOX*>( 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<const PCB_DIMENSION_BASE*>( 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 );
}

View File

@ -35,19 +35,21 @@
#include <board.h>
#include <board_design_settings.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <pcb_dimension.h>
#include <pcb_shape.h>
#include <fp_shape.h>
#include <pcb_group.h>
#include <pcb_target.h>
#include <pcb_track.h>
#include <pcb_textbox.h>
#include <pad.h>
#include <zone.h>
#include <footprint.h>
#include <geometry/shape_line_chain.h>
#include <font/font.h>
#include <ignore.h>
#include <netclass.h>
#include <pad.h>
#include <pcb_track.h>
#include <zone.h>
#include <plugins/kicad/pcb_plugin.h>
#include <pcb_plot_params_parser.h>
#include <pcb_plot_params.h>
@ -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<PCB_TEXT> text = std::make_unique<PCB_TEXT>( 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<PCB_TEXTBOX> textbox = std::make_unique<PCB_TEXTBOX>( 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<KIID&>( textbox->m_Uuid ) = CurStrToKIID();
NeedRIGHT();
break;
case T_effects:
parseEDA_TEXT( static_cast<EDA_TEXT*>( textbox.get() ) );
break;
case T_render_cache:
parseRenderCache( static_cast<EDA_TEXT*>( 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<FP_TEXTBOX> textbox = std::make_unique<FP_TEXTBOX>( 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<EDA_TEXT*>( textbox.get() ) );
break;
case T_render_cache:
parseRenderCache( static_cast<EDA_TEXT*>( textbox.get() ) );
break;
case T_tstamp:
NextTok();
const_cast<KIID&>( 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 ||

View File

@ -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 );

View File

@ -33,6 +33,7 @@
#include <pcb_dimension.h>
#include <footprint.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <string_utils.h>
#include <kiface_base.h>
#include <locale_io.h>
@ -42,6 +43,7 @@
#include <pcb_shape.h>
#include <pcb_target.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <pcbnew_settings.h>
#include <plugins/kicad/pcb_plugin.h>
#include <plugins/kicad/pcb_parser.h>
@ -437,10 +439,18 @@ void PCB_PLUGIN::Format( const BOARD_ITEM* aItem, int aNestLevel ) const
format( static_cast<const PCB_TEXT*>( aItem ), aNestLevel );
break;
case PCB_TEXTBOX_T:
format( static_cast<const PCB_TEXTBOX*>( aItem ), aNestLevel );
break;
case PCB_FP_TEXT_T:
format( static_cast<const FP_TEXT*>( aItem ), aNestLevel );
break;
case PCB_FP_TEXTBOX_T:
format( static_cast<const FP_TEXTBOX*>( aItem ), aNestLevel );
break;
case PCB_GROUP_T:
format( static_cast<const PCB_GROUP*>( 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 )

View File

@ -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;

View File

@ -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<PCB_SHAPE*>( 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<PCB_SHAPE*>( mgitem ) );
}

View File

@ -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;

View File

@ -4,7 +4,7 @@
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
* 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 );

View File

@ -4,7 +4,7 @@
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@gmail.com>
* 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 );

View File

@ -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 <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -40,7 +40,6 @@
#include <router/router_tool.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_editor_conditions.h>
#include <tools/pcb_grid_helper.h>
#include <tools/pcb_selection_tool.h>
#include <tools/tool_event_utils.h>
@ -56,11 +55,13 @@
#include <confirm.h>
#include <footprint.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <macros.h>
#include <painter.h>
#include <pcb_edit_frame.h>
#include <pcb_group.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <pcb_dimension.h>
#include <pcbnew_id.h>
#include <preview_items/arc_assistant.h>
@ -333,12 +334,34 @@ int DRAWING_TOOL::DrawRectangle( const TOOL_EVENT& aEvent )
REENTRANCY_GUARD guard( &m_inDrawingTool );
FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( 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<VECTOR2D> startingPoint = boost::make_optional<VECTOR2D>( false, VECTOR2D( 0, 0 ) );
auto makeNew =
[&]() -> PCB_SHAPE*
{
if( m_isFootprintEditor )
{
FOOTPRINT* parentFootprint = dynamic_cast<FOOTPRINT*>( 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<FP_SHAPE*>( 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<PCB_DIM_RADIAL*>( 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<BOARD_ITEM*>( 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<BOARD_ITEM*>( 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<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
auto view = m_frame->GetCanvas()->GetView();
KIGFX::PCB_VIEW* view = m_frame->GetCanvas()->GetView();
std::vector<PCB_TRACK*> possible_tracks;
view->Query( bbox, items );
for( auto it : items )
for( const KIGFX::VIEW::LAYER_ITEM_PAIR& it : items )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( 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<PCB_VIA*>( 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() );

View File

@ -30,6 +30,7 @@
#include <board_design_settings.h>
#include <footprint.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <collectors.h>
#include <pcb_edit_frame.h>
#include <drawing_sheet/ds_proxy_view_item.h>
@ -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<FP_TEXTBOX*>( item );
textbox->Mirror( mirrorPoint, false );
break;
}
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( item );
@ -1849,6 +1858,17 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
break;
}
case PCB_FP_TEXTBOX_T:
{
FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( item );
FOOTPRINT* parent = static_cast<FOOTPRINT*>( 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:

View File

@ -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:

View File

@ -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" ),

View File

@ -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;

View File

@ -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 <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -40,9 +40,11 @@
#include <pcb_dimension.h>
#include <footprint.h>
#include <pcb_group.h>
#include <pcb_textbox.h>
#include <pcb_track.h>
#include <zone.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <confirm.h>
#include <connectivity/connectivity_data.h>
#include <core/kicad_algo.h>
@ -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<FP_SHAPE*>( 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<PCB_TEXTBOX*>( clipDrawItem );
// Convert to PCB_FP_TEXTBOX_T
FP_TEXTBOX* pastedTextBox = new FP_TEXTBOX( editorFootprint );
static_cast<EDA_TEXT*>( pastedTextBox )->SwapText( *clipTextBox );
static_cast<EDA_TEXT*>( pastedTextBox )->SwapAttributes( *clipTextBox );
pastedTextBox->SetParent( editorFootprint );
pastedItems.push_back( pastedTextBox );
}
}
delete clipBoard;

View File

@ -24,7 +24,6 @@
*/
#include <functional>
#include <board.h>
#include <pcb_dimension.h>
#include <fp_shape.h>
#include <footprint.h>
@ -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;

View File

@ -32,15 +32,16 @@ using namespace std::placeholders;
#include <view/view_controls.h>
#include <geometry/seg.h>
#include <confirm.h>
#include "pcb_actions.h"
#include "pcb_selection_tool.h"
#include "pcb_point_editor.h"
#include "pcb_grid_helper.h"
#include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h>
#include <tools/pcb_point_editor.h>
#include <tools/pcb_grid_helper.h>
#include <board_commit.h>
#include <bitmaps.h>
#include <status_popup.h>
#include <pcb_edit_frame.h>
#include <pcb_textbox.h>
#include <fp_shape.h>
#include <fp_textbox.h>
#include <pcb_dimension.h>
#include <pad.h>
#include <zone.h>
@ -154,8 +155,7 @@ void PCB_POINT_EDITOR::buildForPolyOutline( std::shared_ptr<EDIT_POINTS> 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<EDIT_POINTS> 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<const PCB_SHAPE*>( 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<const PCB_SHAPE*>( 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<const PCB_SHAPE*>( item );

View File

@ -39,6 +39,8 @@ using namespace std::placeholders;
#include <pcb_group.h>
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <fp_textbox.h>
#include <pcb_marker.h>
#include <zone.h>
#include <collectors.h>
@ -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<PCB_TEXTBOX*>( aItem );
textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
break;
}
case PCB_FP_TEXT_T:
{
FP_TEXT* text = static_cast<FP_TEXT*>( 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<FP_TEXTBOX*>( aItem );
textbox->GetEffectiveTextShape()->Collide( loc, aMaxDistance, &distance );
break;
}
case PCB_ZONE_T:
{
ZONE* zone = static_cast<ZONE*>( 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 );

View File

@ -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 );
}

View File

@ -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;

View File

@ -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 <pad.h>
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <fp_text.h>
#include <fp_textbox.h>
#include <fp_shape.h>
#include <zone.h>
#include <pcb_track.h>
@ -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 );