7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-03-30 05:46:55 +00:00

Collapse SCH_TABLE border drawing into shared code.

Also pushes GetCornersInSequence() into EDA_SHAPE
so it can be shared between SCH_TABLE and PCB_TABLE.

Also fixes bug in drawing column rulings over the
right external border.

Also fixes a bug with dialog control enabling.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20350
This commit is contained in:
Jeff Young 2025-03-16 20:21:09 +00:00
parent 1333c4c305
commit 413d6747c5
10 changed files with 217 additions and 313 deletions

View File

@ -1556,6 +1556,105 @@ std::vector<VECTOR2I> EDA_SHAPE::GetRectCorners() const
}
std::vector<VECTOR2I> EDA_SHAPE::GetCornersInSequence() const
{
std::vector<VECTOR2I> pts;
EDA_ANGLE textAngle( getDrawRotation() );
textAngle.Normalize();
BOX2I bbox = getBoundingBox();
bbox.Normalize();
if( textAngle.IsCardinal() )
{
if( textAngle == ANGLE_0 )
{
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
}
else if( textAngle == ANGLE_90 )
{
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
}
else if( textAngle == ANGLE_180 )
{
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
}
else if( textAngle == ANGLE_270 )
{
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
}
}
else
{
std::vector<VECTOR2I> corners = GetRectCorners();
VECTOR2I minX = corners[0];
VECTOR2I maxX = corners[0];
VECTOR2I minY = corners[0];
VECTOR2I maxY = corners[0];
for( const VECTOR2I& corner : corners )
{
if( corner.x < minX.x )
minX = corner;
if( corner.x > maxX.x )
maxX = corner;
if( corner.y < minY.y )
minY = corner;
if( corner.y > maxY.y )
maxY = corner;
}
if( textAngle < ANGLE_90 )
{
pts.emplace_back( minX );
pts.emplace_back( minY );
pts.emplace_back( maxX );
pts.emplace_back( maxY );
}
else if( textAngle < ANGLE_180 )
{
pts.emplace_back( maxY );
pts.emplace_back( minX );
pts.emplace_back( minY );
pts.emplace_back( maxX );
}
else if( textAngle < ANGLE_270 )
{
pts.emplace_back( maxX );
pts.emplace_back( maxY );
pts.emplace_back( minX );
pts.emplace_back( minY );
}
else
{
pts.emplace_back( minY );
pts.emplace_back( maxX );
pts.emplace_back( maxY );
pts.emplace_back( minX );
}
}
return pts;
}
void EDA_SHAPE::computeArcBBox( BOX2I& aBBox ) const
{
// Start, end, and each inflection point the arc crosses will enclose the entire arc.

View File

@ -280,15 +280,16 @@ void DIALOG_TABLE_PROPERTIES::getContextualTextVars( const wxString& aCrossRef,
void DIALOG_TABLE_PROPERTIES::onBorderChecked( wxCommandEvent& aEvent )
{
bool border = m_borderCheckbox->GetValue();
bool headerSeparator = m_headerBorder->GetValue();
if( border && m_borderWidth.GetValue() < 0 )
if( ( border || headerSeparator ) && m_borderWidth.GetValue() < 0 )
m_borderWidth.SetValue( m_frame->eeconfig()->m_Drawing.default_line_thickness );
m_borderWidth.Enable( border );
m_borderColorLabel->Enable( border );
m_borderColorSwatch->Enable( border );
m_borderStyleLabel->Enable( border );
m_borderStyleCombo->Enable( border );
m_borderWidth.Enable( border || headerSeparator );
m_borderColorLabel->Enable( border || headerSeparator );
m_borderColorSwatch->Enable( border || headerSeparator );
m_borderStyleLabel->Enable( border || headerSeparator );
m_borderStyleCombo->Enable( border || headerSeparator );
bool row = m_rowSeparators->GetValue();
bool col = m_colSeparators->GetValue();
@ -348,7 +349,7 @@ bool DIALOG_TABLE_PROPERTIES::TransferDataFromWindow()
{
STROKE_PARAMS stroke = m_table->GetBorderStroke();
if( m_borderCheckbox->GetValue() )
if( m_borderCheckbox->GetValue() || m_headerBorder->GetValue() )
stroke.SetWidth( std::max( 0, m_borderWidth.GetIntValue() ) );
else
stroke.SetWidth( -1 );

View File

@ -2098,19 +2098,12 @@ void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer, bool aDimmed )
if( aLayer == LAYER_SELECTION_SHADOWS )
return;
VECTOR2I pos = aTable->GetPosition();
VECTOR2I end = aTable->GetEnd();
int lineWidth;
COLOR4D color;
LINE_STYLE lineStyle;
auto setupStroke =
[&]( const STROKE_PARAMS& stroke )
aTable->DrawBorders(
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
{
lineWidth = stroke.GetWidth();
color = stroke.GetColor();
lineStyle = stroke.GetLineStyle();
int lineWidth = stroke.GetWidth();
COLOR4D color = stroke.GetColor();
LINE_STYLE lineStyle = stroke.GetLineStyle();
if( lineWidth == 0 )
lineWidth = m_schSettings.GetDefaultPenWidth();
@ -2125,25 +2118,7 @@ void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer, bool aDimmed )
m_gal->SetIsStroke( true );
m_gal->SetStrokeColor( color );
m_gal->SetLineWidth( (float) lineWidth );
};
auto strokeShape =
[&]( const SHAPE& shape )
{
STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, &m_schSettings,
[&]( const VECTOR2I& a, const VECTOR2I& b )
{
// DrawLine has problem with 0 length lines so enforce minimum
if( a == b )
m_gal->DrawLine( a+1, b );
else
m_gal->DrawLine( a, b );
} );
};
auto strokeLine =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
{
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
m_gal->DrawLine( ptA, ptB );
@ -2151,92 +2126,17 @@ void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer, bool aDimmed )
else
{
SHAPE_SEGMENT seg( ptA, ptB );
strokeShape( seg );
STROKE_PARAMS::Stroke( &seg, lineStyle, lineWidth, &m_schSettings,
[&]( const VECTOR2I& a, const VECTOR2I& b )
{
// DrawLine has problem with 0 length lines so enforce minimum
if( a == b )
m_gal->DrawLine( a+1, b );
else
m_gal->DrawLine( a, b );
} );
}
};
auto strokeRect =
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
{
if( lineStyle <= LINE_STYLE::FIRST_TYPE )
{
m_gal->DrawRectangle( ptA, ptB );
}
else
{
SHAPE_RECT rect( BOX2I( ptA, ptB - ptA ) );
strokeShape( rect );
}
};
if( aTable->GetSeparatorsStroke().GetWidth() >= 0 )
{
setupStroke( aTable->GetSeparatorsStroke() );
if( aTable->StrokeColumns() )
{
for( int col = 0; col < aTable->GetColCount() - 1; ++col )
{
for( int row = 0; row < aTable->GetRowCount(); ++row )
{
SCH_TABLECELL* cell = aTable->GetCell( row, col );
VECTOR2I topRight( cell->GetEndX(), cell->GetStartY() );
if( !cell->GetTextAngle().IsHorizontal() )
topRight = VECTOR2I( cell->GetStartX(), cell->GetEndY() );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
strokeLine( topRight, cell->GetEnd() );
}
}
}
if( aTable->StrokeRows() )
{
for( int row = 0; row < aTable->GetRowCount() - 1; ++row )
{
for( int col = 0; col < aTable->GetColCount(); ++col )
{
SCH_TABLECELL* cell = aTable->GetCell( row, col );
VECTOR2I botLeft( cell->GetStartX(), cell->GetEndY() );
if( !cell->GetTextAngle().IsHorizontal() )
botLeft = VECTOR2I( cell->GetEndX(), cell->GetStartY() );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
strokeLine( botLeft, cell->GetEnd() );
}
}
}
}
if( aTable->GetBorderStroke().GetWidth() >= 0 )
{
SCH_TABLECELL* first = aTable->GetCell( 0, 0 );
setupStroke( aTable->GetBorderStroke() );
if( aTable->StrokeHeaderSeparator() )
{
if( !first->GetTextAngle().IsHorizontal() )
strokeLine( VECTOR2I( first->GetEndX(), pos.y ),
VECTOR2I( first->GetEndX(), first->GetEndY() ) );
else
strokeLine( VECTOR2I( pos.x, first->GetEndY() ),
VECTOR2I( end.x, first->GetEndY() ) );
}
if( aTable->StrokeExternal() )
{
if( !first->GetTextAngle().IsHorizontal() )
{
RotatePoint( pos, aTable->GetPosition(), ANGLE_90 );
RotatePoint( end, aTable->GetPosition(), ANGLE_90 );
}
strokeRect( pos, end );
}
}
} );
}

View File

@ -329,6 +329,75 @@ bool SCH_TABLE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
}
void SCH_TABLE::DrawBorders( const std::function<void( const VECTOR2I& aPt1, const VECTOR2I& aPt2,
const STROKE_PARAMS& aStroke )>& aCallback ) const
{
std::vector<VECTOR2I> topLeft = GetCell( 0, 0 )->GetCornersInSequence();
std::vector<VECTOR2I> bottomLeft = GetCell( GetRowCount() - 1, 0 )->GetCornersInSequence();
std::vector<VECTOR2I> topRight = GetCell( 0, GetColCount() - 1 )->GetCornersInSequence();
std::vector<VECTOR2I> bottomRight = GetCell( GetRowCount() - 1, GetColCount() - 1 )->GetCornersInSequence();
STROKE_PARAMS stroke;
for( int col = 0; col < GetColCount() - 1; ++col )
{
if( StrokeColumns() )
stroke = GetSeparatorsStroke();
else
continue;
for( int row = 0; row < GetRowCount(); ++row )
{
SCH_TABLECELL* cell = GetCell( row, col );
if( cell->GetColSpan() == 0 )
continue;
if( col + cell->GetColSpan() == GetColCount() )
continue;
std::vector<VECTOR2I> corners = cell->GetCornersInSequence();
if( corners.size() == 4 )
aCallback( corners[1], corners[2], stroke );
}
}
for( int row = 0; row < GetRowCount() - 1; ++row )
{
if( row == 0 && StrokeHeaderSeparator() )
stroke = GetBorderStroke();
else if( StrokeRows() )
stroke = GetSeparatorsStroke();
else
continue;
for( int col = 0; col < GetColCount(); ++col )
{
SCH_TABLECELL* cell = GetCell( row, col );
if( cell->GetRowSpan() == 0 )
continue;
if( row + cell->GetRowSpan() == GetRowCount() )
continue;
std::vector<VECTOR2I> corners = cell->GetCornersInSequence();
if( corners.size() == 4 )
aCallback( corners[2], corners[3], stroke );
}
}
if( StrokeExternal() && GetBorderStroke().GetWidth() >= 0 )
{
aCallback( topLeft[0], topRight[1], GetBorderStroke() );
aCallback( topRight[1], bottomRight[2], GetBorderStroke() );
aCallback( bottomRight[2], bottomLeft[3], GetBorderStroke() );
aCallback( bottomLeft[3], topLeft[0], GetBorderStroke() );
}
}
void SCH_TABLE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
{
@ -339,18 +408,13 @@ void SCH_TABLE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
return;
RENDER_SETTINGS* settings = aPlotter->RenderSettings();
VECTOR2I pos = GetPosition();
VECTOR2I end = GetEnd();
int lineWidth;
COLOR4D color;
LINE_STYLE lineStyle;
auto setupStroke =
[&]( const STROKE_PARAMS& stroke )
DrawBorders(
[&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
{
lineWidth = stroke.GetWidth();
color = stroke.GetColor();
lineStyle = stroke.GetLineStyle();
int lineWidth = stroke.GetWidth();
COLOR4D color = stroke.GetColor();
LINE_STYLE lineStyle = stroke.GetLineStyle();
if( lineWidth == 0 )
{
@ -371,82 +435,10 @@ void SCH_TABLE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS&
aPlotter->SetColor( color );
aPlotter->SetDash( lineWidth, lineStyle );
};
if( GetSeparatorsStroke().GetWidth() >= 0 )
{
setupStroke( GetSeparatorsStroke() );
if( StrokeColumns() )
{
for( int col = 0; col < GetColCount() - 1; ++col )
{
for( int row = 0; row < GetRowCount(); ++row )
{
SCH_TABLECELL* cell = GetCell( row, col );
VECTOR2I topRight( cell->GetEndX(), cell->GetStartY() );
if( !cell->GetTextAngle().IsHorizontal() )
topRight = VECTOR2I( cell->GetStartX(), cell->GetEndY() );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
aPlotter->MoveTo( topRight );
aPlotter->FinishTo( VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
if( StrokeRows() )
{
for( int row = 0; row < GetRowCount() - 1; ++row )
{
for( int col = 0; col < GetColCount(); ++col )
{
SCH_TABLECELL* cell = GetCell( row, col );
VECTOR2I botLeft( cell->GetStartX(), cell->GetEndY() );
if( !cell->GetTextAngle().IsHorizontal() )
botLeft = VECTOR2I( cell->GetEndX(), cell->GetStartY() );
if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
{
aPlotter->MoveTo( botLeft );
aPlotter->FinishTo( VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
}
}
}
}
if( GetBorderStroke().GetWidth() >= 0 )
{
setupStroke( GetBorderStroke() );
SCH_TABLECELL* cell = GetCell( 0, 0 );
if( StrokeHeaderSeparator() )
{
if( !cell->GetTextAngle().IsHorizontal() )
{
aPlotter->MoveTo( VECTOR2I( cell->GetEndX(), pos.y ) );
aPlotter->FinishTo( VECTOR2I( cell->GetEndX(), cell->GetEndY() ) );
}
else
{
aPlotter->MoveTo( VECTOR2I( pos.x, cell->GetEndY() ) );
aPlotter->FinishTo( VECTOR2I( end.x, cell->GetEndY() ) );
}
}
if( StrokeExternal() )
{
RotatePoint( pos, GetPosition(), cell->GetTextAngle() );
RotatePoint( end, GetPosition(), cell->GetTextAngle() );
aPlotter->Rect( pos, end, FILL_T::NO_FILL, lineWidth );
}
}
aPlotter->MoveTo( ptA );
aPlotter->FinishTo( ptB );
} );
}

View File

@ -218,6 +218,9 @@ public:
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
void DrawBorders( const std::function<void( const VECTOR2I& aPt1, const VECTOR2I& aPt2,
const STROKE_PARAMS& aStroke )>& aCallback ) const;
void Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed ) override;

View File

@ -285,6 +285,7 @@ public:
VECTOR2I GetArcMid() const;
std::vector<VECTOR2I> GetRectCorners() const;
std::vector<VECTOR2I> GetCornersInSequence() const;
/**
* Calc arc start and end angles such that aStartAngle < aEndAngle. Each may be between
@ -440,6 +441,8 @@ protected:
void flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection );
void scale( double aScale );
virtual EDA_ANGLE getDrawRotation() const { return ANGLE_0; }
const BOX2I getBoundingBox() const;
void computeArcBBox( BOX2I& aBBox ) const;

View File

@ -236,8 +236,7 @@ const BOX2I PCB_TABLE::GetBoundingBox() const
}
void PCB_TABLE::DrawBorders( const std::function<void( const VECTOR2I& aPt1,
const VECTOR2I& aPt2,
void PCB_TABLE::DrawBorders( const std::function<void( const VECTOR2I& aPt1, const VECTOR2I& aPt2,
const STROKE_PARAMS& aStroke )>& aCallback ) const
{
std::vector<VECTOR2I> topLeft = GetCell( 0, 0 )->GetCornersInSequence();
@ -260,6 +259,9 @@ void PCB_TABLE::DrawBorders( const std::function<void( const VECTOR2I& aPt1,
if( cell->GetColSpan() == 0 )
continue;
if( col + cell->GetColSpan() == GetColCount() )
continue;
std::vector<VECTOR2I> corners = cell->GetCornersInSequence();
if( corners.size() == 4 )
@ -283,6 +285,9 @@ void PCB_TABLE::DrawBorders( const std::function<void( const VECTOR2I& aPt1,
if( cell->GetRowSpan() == 0 )
continue;
if( row + cell->GetRowSpan() == GetRowCount() )
continue;
std::vector<VECTOR2I> corners = cell->GetCornersInSequence();
if( corners.size() == 4 )

View File

@ -204,8 +204,7 @@ public:
const BOX2I GetBoundingBox() const override;
void DrawBorders( const std::function<void( const VECTOR2I& aPt1,
const VECTOR2I& aPt2,
void DrawBorders( const std::function<void( const VECTOR2I& aPt1, const VECTOR2I& aPt2,
const STROKE_PARAMS& aStroke )>& aCallback ) const;
// @copydoc BOARD_ITEM::GetEffectiveShape

View File

@ -257,105 +257,6 @@ void PCB_TEXTBOX::SetTextAngle( const EDA_ANGLE& aAngle )
}
std::vector<VECTOR2I> PCB_TEXTBOX::GetCornersInSequence() const
{
std::vector<VECTOR2I> pts;
EDA_ANGLE textAngle( GetDrawRotation() );
textAngle.Normalize();
BOX2I bbox = PCB_SHAPE::GetBoundingBox();
bbox.Normalize();
if( textAngle.IsCardinal() )
{
if( textAngle == ANGLE_0 )
{
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
}
else if( textAngle == ANGLE_90 )
{
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
}
else if( textAngle == ANGLE_180 )
{
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
}
else if( textAngle == ANGLE_270 )
{
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetTop() ) );
pts.emplace_back( VECTOR2I( bbox.GetRight(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetBottom() ) );
pts.emplace_back( VECTOR2I( bbox.GetLeft(), bbox.GetTop() ) );
}
}
else
{
std::vector<VECTOR2I> corners = GetCorners();
VECTOR2I minX = corners[0];
VECTOR2I maxX = corners[0];
VECTOR2I minY = corners[0];
VECTOR2I maxY = corners[0];
for( const VECTOR2I& corner : corners )
{
if( corner.x < minX.x )
minX = corner;
if( corner.x > maxX.x )
maxX = corner;
if( corner.y < minY.y )
minY = corner;
if( corner.y > maxY.y )
maxY = corner;
}
if( textAngle < ANGLE_90 )
{
pts.emplace_back( minX );
pts.emplace_back( minY );
pts.emplace_back( maxX );
pts.emplace_back( maxY );
}
else if( textAngle < ANGLE_180 )
{
pts.emplace_back( maxY );
pts.emplace_back( minX );
pts.emplace_back( minY );
pts.emplace_back( maxX );
}
else if( textAngle < ANGLE_270 )
{
pts.emplace_back( maxX );
pts.emplace_back( maxY );
pts.emplace_back( minX );
pts.emplace_back( minY );
}
else
{
pts.emplace_back( minY );
pts.emplace_back( maxX );
pts.emplace_back( maxY );
pts.emplace_back( minX );
}
}
return pts;
}
VECTOR2I PCB_TEXTBOX::GetDrawPos() const
{
return GetDrawPos( false );

View File

@ -98,8 +98,6 @@ public:
bool Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const override;
std::vector<VECTOR2I> GetCornersInSequence() const;
void Move( const VECTOR2I& aMoveVector ) override;
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
@ -164,12 +162,15 @@ public:
bool operator==( const BOARD_ITEM& aBoardItem ) const override;
protected:
bool m_borderEnabled; ///< Controls drawing the border (as defined by the stroke members)
EDA_ANGLE getDrawRotation() const override { return GetDrawRotation(); }
virtual void swapData( BOARD_ITEM* aImage ) override;
const KIFONT::METRICS& getFontMetrics() const override { return GetFontMetrics(); }
protected:
bool m_borderEnabled; ///< Controls drawing the border (as defined by the stroke members)
private:
int m_marginLeft;
int m_marginTop;