diff --git a/common/base_struct.cpp b/common/base_struct.cpp index 2ea2636c23..43b6a38f30 100644 --- a/common/base_struct.cpp +++ b/common/base_struct.cpp @@ -337,6 +337,45 @@ bool EDA_RECT::Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2 ) cons } +bool EDA_RECT::Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2, + wxPoint* aIntersection1, wxPoint* aIntersection2 ) const +{ + wxPoint point2, point4; + + point2.x = GetEnd().x; + point2.y = GetOrigin().y; + point4.x = GetOrigin().x; + point4.y = GetEnd().y; + + bool intersects = false; + + wxPoint* aPointToFill = aIntersection1; + + if( SegmentIntersectsSegment( aPoint1, aPoint2, GetOrigin(), point2, aPointToFill ) ) + intersects = true; + + if( intersects ) + aPointToFill = aIntersection2; + + if( SegmentIntersectsSegment( aPoint1, aPoint2, point2, GetEnd(), aPointToFill ) ) + intersects = true; + + if( intersects ) + aPointToFill = aIntersection2; + + if( SegmentIntersectsSegment( aPoint1, aPoint2, GetEnd(), point4, aPointToFill ) ) + intersects = true; + + if( intersects ) + aPointToFill = aIntersection2; + + if( SegmentIntersectsSegment( aPoint1, aPoint2, point4, GetOrigin(), aPointToFill ) ) + intersects = true; + + return intersects; +} + + bool EDA_RECT::Intersects( const EDA_RECT& aRect ) const { if( !m_init ) diff --git a/common/pcb.keywords b/common/pcb.keywords index eb62d34e02..9173e4d942 100644 --- a/common/pcb.keywords +++ b/common/pcb.keywords @@ -146,6 +146,7 @@ italic justify keepout keep_end_layers +keep_text_aligned keep_upright kicad_pcb last_trace_width diff --git a/include/eda_rect.h b/include/eda_rect.h index a419d03718..b49a4386fb 100644 --- a/include/eda_rect.h +++ b/include/eda_rect.h @@ -243,6 +243,17 @@ public: */ bool Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2 ) const; + /** + * Tests for intersection between a segment and this rectangle, returning the intersections + * @param aPoint1 is the first point of the segment to test intersection with + * @param aPoint2 is the second point of the segment to test intersection with + * @param aIntersection1 will be filled with the first intersection point, if any + * @param aIntersection2 will be filled with the second intersection point, if any + * @return true if the segment intersects the rect + */ + bool Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2, + wxPoint* aIntersection1, wxPoint* aIntersection2 ) const; + /** * Return the point in this rect that is closest to the provided point */ diff --git a/pcbnew/class_dimension.cpp b/pcbnew/class_dimension.cpp index 92c00d5343..67ed2184fc 100644 --- a/pcbnew/class_dimension.cpp +++ b/pcbnew/class_dimension.cpp @@ -36,22 +36,22 @@ #include -DIMENSION::DIMENSION( BOARD_ITEM* aParent ) - : BOARD_ITEM( aParent, PCB_DIMENSION_T ), - m_overrideValue( false ), - m_units( EDA_UNITS::INCHES ), - m_useMils( false ), - m_autoUnits( false ), - m_unitsFormat( DIM_UNITS_FORMAT::BARE_SUFFIX ), - m_precision( 4 ), - m_suppressZeroes( false ), - m_lineThickness( Millimeter2iu( 0.2 ) ), - m_arrowLength( Mils2iu( 50 ) ), - m_extensionOffset( 0 ), - m_textPosition( DIM_TEXT_POSITION::OUTSIDE ), - m_keepTextAligned( true ), - m_text( this ), - m_measuredValue( 0 ) +DIMENSION::DIMENSION( BOARD_ITEM* aParent ) : + BOARD_ITEM( aParent, PCB_DIMENSION_T ), + m_overrideTextEnabled( false ), + m_units( EDA_UNITS::INCHES ), + m_useMils( false ), + m_autoUnits( false ), + m_unitsFormat( DIM_UNITS_FORMAT::BARE_SUFFIX ), + m_precision( 4 ), + m_suppressZeroes( false ), + m_lineThickness( Millimeter2iu( 0.2 ) ), + m_arrowLength( Mils2iu( 50 ) ), + m_extensionOffset( 0 ), + m_textPosition( DIM_TEXT_POSITION::OUTSIDE ), + m_keepTextAligned( true ), + m_text( this ), + m_measuredValue( 0 ) { m_Layer = Dwgs_User; } @@ -69,6 +69,81 @@ wxPoint DIMENSION::GetPosition() const } +void DIMENSION::updateText() +{ + wxString text = m_overrideTextEnabled ? m_valueString : GetValueText(); + + switch( m_unitsFormat ) + { + case DIM_UNITS_FORMAT::NO_SUFFIX: // no units + break; + + case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal + text += " "; + text += GetAbbreviatedUnitsLabel( m_units, m_useMils ); + break; + + case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical + text += " ("; + text += GetAbbreviatedUnitsLabel( m_units, m_useMils ); + text += ")"; + break; + } + + text.Prepend( m_prefix ); + text.Append( m_suffix ); + + m_text.SetText( text ); +} + + +wxString DIMENSION::GetValueText() const +{ + int val = GetMeasuredValue(); + + wxString text; + wxString format = wxT( "%." ) + wxString::Format( "%i", m_precision ) + wxT( "f" ); + + text.Printf( format, To_User_Unit( m_units, val, m_useMils ) ); + + if( m_suppressZeroes ) + { + while( text.Last() == '0' ) + { + text.RemoveLast(); + + if( text.Last() == '.' ) + { + text.RemoveLast(); + break; + } + } + + } + + return text; +} + + +void DIMENSION::SetPrefix( const wxString& aPrefix ) +{ + m_prefix = aPrefix; +} + + +void DIMENSION::SetSuffix( const wxString& aSuffix ) +{ + m_suffix = aSuffix; +} + + +void DIMENSION::SetUnits( EDA_UNITS aUnits, bool aUseMils ) +{ + m_units = aUnits; + m_useMils = aUseMils; +} + + DIM_UNITS_MODE DIMENSION::GetUnitsMode() const { if( m_autoUnits ) @@ -84,16 +159,17 @@ DIM_UNITS_MODE DIMENSION::GetUnitsMode() const void DIMENSION::SetUnitsMode( DIM_UNITS_MODE aMode ) { - m_units = EDA_UNITS::INCHES; m_autoUnits = false; m_useMils = false; switch( aMode ) { case DIM_UNITS_MODE::INCHES: + m_units = EDA_UNITS::INCHES; break; case DIM_UNITS_MODE::MILS: + m_units = EDA_UNITS::INCHES; m_useMils = true; break; @@ -110,7 +186,8 @@ void DIMENSION::SetUnitsMode( DIM_UNITS_MODE aMode ) void DIMENSION::SetText( const wxString& aNewText ) { - m_text.SetText( aNewText ); + m_valueString = aNewText; + updateText(); } @@ -134,7 +211,7 @@ void DIMENSION::Move( const wxPoint& offset ) m_start += offset; m_end += offset; - updateGeometry(); + Update(); } @@ -157,7 +234,7 @@ void DIMENSION::Rotate( const wxPoint& aRotCentre, double aAngle ) RotatePoint( &m_start, aRotCentre, aAngle ); RotatePoint( &m_end, aRotCentre, aAngle ); - updateGeometry(); + Update(); } @@ -199,21 +276,21 @@ void DIMENSION::Mirror( const wxPoint& axis_pos, bool aMirrorLeftRight ) INVERT( m_end.y ); } - updateGeometry(); + Update(); } void DIMENSION::SetStart( const wxPoint& aOrigin ) { m_start = aOrigin; - updateGeometry(); + Update(); } void DIMENSION::SetEnd( const wxPoint& aEnd ) { m_end = aEnd; - updateGeometry(); + Update(); } @@ -333,7 +410,7 @@ ALIGNED_DIMENSION::ALIGNED_DIMENSION( BOARD_ITEM* aParent ) : m_height( 0 ) { // To preserve look of old dimensions, initialize extension height based on default arrow length - m_extensionHeight = m_arrowLength * std::sin( DEG2RAD( s_arrowAngle ) ); + m_extensionHeight = static_cast( m_arrowLength * std::sin( DEG2RAD( s_arrowAngle ) ) ); } @@ -347,14 +424,15 @@ void ALIGNED_DIMENSION::SwapData( BOARD_ITEM* aImage ) { assert( aImage->Type() == PCB_DIMENSION_T ); - std::swap( *static_cast( this ), *static_cast( aImage ) ); + std::swap( *static_cast( this ), + *static_cast( aImage ) ); } void ALIGNED_DIMENSION::SetHeight( int aHeight ) { m_height = aHeight; - updateGeometry(); + Update(); } @@ -368,7 +446,7 @@ void ALIGNED_DIMENSION::UpdateHeight( const wxPoint& aCrossbarStart, const wxPoi else m_height = height.EuclideanNorm(); - updateGeometry(); + Update(); } @@ -410,13 +488,71 @@ void ALIGNED_DIMENSION::updateGeometry() // Update text after calculating crossbar position but before adding crossbar lines updateText(); - // Now that we have the text updated, we can determine if the crossbar needs to be broken - if( m_textPosition == DIM_TEXT_POSITION::INLINE ) + // Now that we have the text updated, we can determine how to draw the crossbar. + // First we need to create an appropriate bounding polygon to collide with + EDA_RECT textBox = m_text.GetTextBox().Inflate( m_text.GetTextWidth() / 2, + m_text.GetEffectiveTextPenWidth() ); + + SHAPE_POLY_SET polyBox; + polyBox.NewOutline(); + polyBox.Append( textBox.GetOrigin() ); + polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y ); + polyBox.Append( textBox.GetEnd() ); + polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y ); + polyBox.Rotate( -m_text.GetTextAngleRadians(), textBox.GetCenter() ); + + // The ideal crossbar, if the text doesn't collide + SEG crossbar( m_crossBarStart, m_crossBarEnd ); + + auto findEndpoint = + [&]( const VECTOR2I& aStart, const VECTOR2I& aEnd ) -> VECTOR2I + { + VECTOR2I endpoint( aEnd ); + + for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ ) + { + if( OPT_VECTOR2I intersection = ( *seg ).Intersect( crossbar ) ) + { + if( ( *intersection - aStart ).SquaredEuclideanNorm() < + ( endpoint - aStart ).SquaredEuclideanNorm() ) + endpoint = *intersection; + } + } + + return endpoint; + }; + + // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides + + bool containsA = polyBox.Contains( crossbar.A ); + bool containsB = polyBox.Contains( crossbar.B ); + + if( containsA && !containsB ) { - + m_lines.emplace_back( SEG( findEndpoint( crossbar.B, crossbar.A ), crossbar.B ) ); } + else if( containsB && !containsA ) + { + m_lines.emplace_back( SEG( crossbar.A, findEndpoint( crossbar.A, crossbar.B ) ) ); + } + else if( polyBox.Collide( crossbar ) ) + { + // text box collides and we need two segs + VECTOR2I endpoint1 = findEndpoint( crossbar.B, crossbar.A ); + VECTOR2I endpoint2 = findEndpoint( crossbar.A, crossbar.B ); - m_lines.emplace_back( SEG( m_crossBarStart, m_crossBarEnd ) ); + if( ( crossbar.B - endpoint1 ).SquaredEuclideanNorm() > + ( crossbar.B - endpoint2 ).SquaredEuclideanNorm() ) + std::swap( endpoint1, endpoint2 ); + + m_lines.emplace_back( SEG( endpoint1, crossbar.B ) ); + m_lines.emplace_back( SEG( crossbar.A, endpoint2 ) ); + } + else if( !containsA && !containsB ) + { + // No collision + m_lines.emplace_back( crossbar ); + } // Add arrows VECTOR2I arrowEnd( m_arrowLength, 0 ); @@ -442,7 +578,7 @@ void ALIGNED_DIMENSION::updateText() { VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 ); - if( m_textPosition != DIM_TEXT_POSITION::MANUAL ) + if( m_textPosition == DIM_TEXT_POSITION::OUTSIDE ) { int textOffsetDistance = m_text.GetEffectiveTextPenWidth() + m_text.GetTextHeight(); @@ -452,6 +588,10 @@ void ALIGNED_DIMENSION::updateText() m_text.SetTextPos( m_crossBarStart + wxPoint( textOffset ) ); } + else if( m_textPosition == DIM_TEXT_POSITION::INLINE ) + { + m_text.SetTextPos( m_crossBarStart + wxPoint( crossbarCenter ) ); + } if( m_keepTextAligned ) { @@ -464,17 +604,6 @@ void ALIGNED_DIMENSION::updateText() m_text.SetTextAngle( textAngle ); } - else - { - m_text.SetTextAngle( 0 ); - } - wxString text; - wxString format = wxT( "%." ) + wxString::Format( "%i", m_precision ) + wxT( "f" ); - - text.Printf( format, To_User_Unit( m_units, m_measuredValue, m_useMils ) ); - text += " "; - text += GetAbbreviatedUnitsLabel( m_units, m_useMils ); - - SetText( text ); + DIMENSION::updateText(); } diff --git a/pcbnew/class_dimension.h b/pcbnew/class_dimension.h index 5689b365f7..7b4e29247e 100644 --- a/pcbnew/class_dimension.h +++ b/pcbnew/class_dimension.h @@ -106,21 +106,33 @@ public: wxPoint GetPosition() const override; void SetPosition( const wxPoint& aPos ) override; - bool GetOverrideValue() const { return m_overrideValue; } - void SetOverrideValue( bool aOverride ) { m_overrideValue = aOverride; } + bool GetOverrideTextEnabled() const { return m_overrideTextEnabled; } + void SetOverrideTextEnabled( bool aOverride ) { m_overrideTextEnabled = aOverride; } + + wxString GetOverrideText() const { return m_valueString; } + void SetOverrideText( const wxString& aValue ) { m_valueString = aValue; } int GetMeasuredValue() const { return m_measuredValue; } /** - * @return the text that should be shown, including any prefix and suffix + * @return the dimension value, rendered with precision / zero suppression but no units, etc */ - wxString GetDisplayedText() const; + wxString GetValueText() const; + + /** + * Updates the dimension's cached text and geometry + */ + void Update() + { + updateGeometry(); + updateText(); + } wxString GetPrefix() const { return m_prefix; } - void SetPrefix( const wxString& aPrefix ) { m_prefix = aPrefix; } + void SetPrefix( const wxString& aPrefix ); wxString GetSuffix() const { return m_suffix; } - void SetSuffix( const wxString& aSuffix ) { m_suffix = aSuffix; } + void SetSuffix( const wxString& aSuffix ); void GetUnits( EDA_UNITS& aUnits, bool& aUseMils ) const { @@ -128,11 +140,7 @@ public: aUseMils = m_useMils; } - void SetUnits( EDA_UNITS aUnits, bool aUseMils ) - { - m_units = aUnits; - m_useMils = aUseMils; - } + void SetUnits( EDA_UNITS aUnits, bool aUseMils ); DIM_UNITS_MODE GetUnitsMode() const; void SetUnitsMode( DIM_UNITS_MODE aMode ); @@ -170,7 +178,16 @@ public: m_text.SetTextSize( aTextSize ); } + /** + * Sets the override text - has no effect if m_overrideValue == false + * @param aNewText is the text to use as the value + */ void SetText( const wxString& aNewText ); + + /** + * Retrieves the value text or override text, not including prefix or suffix + * @return the value portion of the dimension text (either overridden or not) + */ const wxString GetText() const; TEXTE_PCB& Text() { return m_text; } @@ -222,11 +239,11 @@ protected: /** * Updates the text field value from the current geometry (called by updateGeometry normally) */ - virtual void updateText() {} + virtual void updateText(); // Value format - bool m_overrideValue; ///< Manually specify the displayed measurement value - wxString m_overrideText; ///< The shown value if m_overrideValue is true + bool m_overrideTextEnabled; ///< Manually specify the displayed measurement value + wxString m_valueString; ///< Displayed value when m_overrideValue = true wxString m_prefix; ///< String prepended to the value wxString m_suffix; ///< String appended to the value EDA_UNITS m_units; ///< 0 = inches, 1 = mm diff --git a/pcbnew/collectors.cpp b/pcbnew/collectors.cpp index c1656aecd5..3d8c0ac5c7 100644 --- a/pcbnew/collectors.cpp +++ b/pcbnew/collectors.cpp @@ -163,6 +163,13 @@ const KICAD_T GENERAL_COLLECTOR::Zones[] = { }; +const KICAD_T GENERAL_COLLECTOR::Dimensions[] = { + PCB_DIMENSION_T, + EOT +}; + + + SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData ) { diff --git a/pcbnew/collectors.h b/pcbnew/collectors.h index 042b6b517e..c07b02ebc6 100644 --- a/pcbnew/collectors.h +++ b/pcbnew/collectors.h @@ -317,6 +317,11 @@ public: */ static const KICAD_T LockableItems[]; + /** + * A scan list for dimensions + */ + static const KICAD_T Dimensions[]; + /** * Constructor GENERALCOLLECTOR */ diff --git a/pcbnew/dialogs/dialog_dimension_properties.cpp b/pcbnew/dialogs/dialog_dimension_properties.cpp index 139717876e..581299017a 100644 --- a/pcbnew/dialogs/dialog_dimension_properties.cpp +++ b/pcbnew/dialogs/dialog_dimension_properties.cpp @@ -45,6 +45,7 @@ DIALOG_DIMENSION_PROPERTIES::DIALOG_DIMENSION_PROPERTIES( PCB_BASE_EDIT_FRAME* a { wxASSERT( aItem->Type() == PCB_DIMENSION_T ); m_dimension = static_cast( aItem ); + m_previewDimension = static_cast( m_dimension->Clone() ); // Configure display origin transforms m_textPosX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD ); @@ -81,14 +82,14 @@ DIALOG_DIMENSION_PROPERTIES::DIALOG_DIMENSION_PROPERTIES( PCB_BASE_EDIT_FRAME* a m_txtValue->Enable( m_cbOverrideValue->GetValue() ); if( !m_cbOverrideValue->GetValue() ) - m_txtValue->SetValue( getValueText() ); + m_txtValue->SetValue( m_dimension->GetValueText() ); } ); auto updateEventHandler = [&]( wxCommandEvent& evt ) { if( !m_cbOverrideValue->GetValue() ) - m_txtValue->ChangeValue( getValueText() ); + m_txtValue->ChangeValue( m_dimension->GetValueText() ); updatePreviewText(); }; @@ -102,19 +103,36 @@ DIALOG_DIMENSION_PROPERTIES::DIALOG_DIMENSION_PROPERTIES( PCB_BASE_EDIT_FRAME* a m_cbPrecision->Bind( wxEVT_CHOICE, updateEventHandler ); m_cbSuppressZeroes->Bind( wxEVT_CHECKBOX, updateEventHandler ); + m_cbTextPositionMode->Bind( wxEVT_CHOICE, + [&]( wxCommandEvent& aEvt ) + { + // manual mode + bool allowPositioning = ( m_cbTextPositionMode->GetSelection() == 2 ); + + m_txtTextPosX->Enable( allowPositioning ); + m_txtTextPosY->Enable( allowPositioning ); + } ); + + m_cbKeepAligned->Bind( wxEVT_CHECKBOX, + [&]( wxCommandEvent& aEvt ) + { + m_cbTextOrientation->Enable( !m_cbKeepAligned->GetValue() ); + } ); + FinishDialogSettings(); } DIALOG_DIMENSION_PROPERTIES::~DIALOG_DIMENSION_PROPERTIES() { + delete m_previewDimension; } bool DIALOG_DIMENSION_PROPERTIES::TransferDataToWindow() { - m_txtValue->Enable( m_dimension->GetOverrideValue() ); - m_cbOverrideValue->SetValue( m_dimension->GetOverrideValue() ); + m_txtValue->Enable( m_dimension->GetOverrideTextEnabled() ); + m_cbOverrideValue->SetValue( m_dimension->GetOverrideTextEnabled() ); EDA_UNITS units; bool useMils; @@ -141,10 +159,20 @@ bool DIALOG_DIMENSION_PROPERTIES::TransferDataToWindow() m_textWidth.SetValue( text.GetTextSize().x ); m_textHeight.SetValue( text.GetTextSize().y ); m_textThickness.SetValue( text.GetTextThickness() ); + m_textPosX.SetValue( text.GetTextPos().x ); m_textPosY.SetValue( text.GetTextPos().y ); + m_cbTextPositionMode->SetSelection( static_cast( m_dimension->GetTextPositionMode() ) ); + + if( m_dimension->GetTextPositionMode() != DIM_TEXT_POSITION::MANUAL ) + { + m_txtTextPosX->Disable(); + m_txtTextPosY->Disable(); + } + m_orientValue = text.GetTextAngleDegrees(); m_cbKeepAligned->SetValue( m_dimension->GetKeepTextAligned() ); + m_cbTextOrientation->Enable( !m_dimension->GetKeepTextAligned() ); m_cbItalic->SetValue( text.IsItalic() ); m_cbMirrored->SetValue( text.IsMirrored() ); @@ -155,7 +183,12 @@ bool DIALOG_DIMENSION_PROPERTIES::TransferDataToWindow() m_arrowLength.SetValue( m_dimension->GetArrowLength() ); // Do this last; it depends on the other settings - m_txtValue->SetValue( getValueText() ); + if( m_dimension->GetOverrideTextEnabled() ) + m_txtValue->SetValue( m_dimension->GetOverrideText() ); + else + m_txtValue->SetValue( m_dimension->GetValueText() ); + + m_orientValidator.TransferToWindow(); return DIALOG_DIMENSION_PROPERTIES_BASE::TransferDataToWindow(); } @@ -163,25 +196,64 @@ bool DIALOG_DIMENSION_PROPERTIES::TransferDataToWindow() bool DIALOG_DIMENSION_PROPERTIES::TransferDataFromWindow() { - m_dimension->SetOverrideValue( m_cbOverrideValue->GetValue() ); + if( !DIALOG_DIMENSION_PROPERTIES_BASE::TransferDataFromWindow() ) + return false; + + BOARD_COMMIT commit( m_frame ); + commit.Modify( m_dimension ); + + // 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_dimension->GetEditFlags() == 0 ); + + /* set flag in edit to force undo/redo/abort proper operation, + * and avoid new calls to SaveCopyInUndoList for the same dimension + * this can occurs when a dimension is moved, and then rotated, edited .. + */ + if( !pushCommit ) + m_dimension->SetFlags( IN_EDIT ); + + updateDimensionFromDialog( m_dimension ); + + if( pushCommit ) + commit.Push( _( "Change dimension properties" ) ); + + return true; +} + + +void DIALOG_DIMENSION_PROPERTIES::updateDimensionFromDialog( DIMENSION* aTarget ) +{ + m_orientValidator.TransferFromWindow(); + + aTarget->SetOverrideTextEnabled( m_cbOverrideValue->GetValue() ); if( m_cbOverrideValue->GetValue() ) - m_dimension->SetText( m_txtValue->GetValue() ); + aTarget->SetOverrideText( m_txtValue->GetValue() ); - m_dimension->SetPrefix( m_txtPrefix->GetValue() ); - m_dimension->SetSuffix( m_txtSuffix->GetValue() ); - m_dimension->SetLayer( static_cast( m_cbLayer->GetLayerSelection() ) ); + aTarget->SetPrefix( m_txtPrefix->GetValue() ); + aTarget->SetSuffix( m_txtSuffix->GetValue() ); + aTarget->SetLayer( static_cast( m_cbLayer->GetLayerSelection() ) ); - m_dimension->SetUnitsMode( static_cast( m_cbUnits->GetSelection() ) ); - m_dimension->SetUnitsFormat( static_cast( m_cbUnitsFormat->GetSelection() ) ); - m_dimension->SetPrecision( m_cbPrecision->GetSelection() ); - m_dimension->SetSuppressZeroes( m_cbSuppressZeroes->GetValue() ); + aTarget->SetUnits( m_frame->GetUserUnits(), false ); + aTarget->SetUnitsMode( static_cast( m_cbUnits->GetSelection() ) ); + aTarget->SetUnitsFormat( static_cast( m_cbUnitsFormat->GetSelection() ) ); + aTarget->SetPrecision( m_cbPrecision->GetSelection() ); + aTarget->SetSuppressZeroes( m_cbSuppressZeroes->GetValue() ); - TEXTE_PCB& text = m_dimension->Text(); + TEXTE_PCB& text = aTarget->Text(); + + DIM_TEXT_POSITION tpm = static_cast( m_cbTextPositionMode->GetSelection() ); + aTarget->SetTextPositionMode( tpm ); + + if( tpm == DIM_TEXT_POSITION::MANUAL ) + { + wxPoint pos( m_textPosX.GetValue(), m_textPosY.GetValue() ); + text.SetPosition( pos ); + } + + aTarget->SetKeepTextAligned( m_cbKeepAligned->GetValue() ); - // TODO(JE) text positioning modes - wxPoint pos( m_textPosX.GetValue(), m_textPosY.GetValue() ); - text.SetPosition( pos ); text.SetTextAngle( KiROUND( m_orientValue * 10.0 ) ); text.SetTextWidth( m_textWidth.GetValue() ); text.SetTextHeight( m_textHeight.GetValue() ); @@ -190,95 +262,16 @@ bool DIALOG_DIMENSION_PROPERTIES::TransferDataFromWindow() text.SetMirrored( m_cbMirrored->GetValue() ); int justification = m_cbJustification->GetSelection() - 1; text.SetHorizJustify( static_cast( justification ) ); - m_dimension->SetKeepTextAligned( m_cbKeepAligned->GetValue() ); - m_dimension->SetLineThickness( m_lineThickness.GetValue() ); - m_dimension->SetArrowLength( m_arrowLength.GetValue() ); + aTarget->SetLineThickness( m_lineThickness.GetValue() ); + aTarget->SetArrowLength( m_arrowLength.GetValue() ); - return true; -} - - -void DIALOG_DIMENSION_PROPERTIES::getUnitsSelection( EDA_UNITS& aUnits, bool& aUseMils ) -{ - aUseMils = false; - - switch( m_cbUnits->GetSelection() ) - { - case 0: // inches - aUnits = EDA_UNITS::INCHES; - break; - - case 1: // mils - aUnits = EDA_UNITS::INCHES; - aUseMils = true; - break; - - case 2: // mm - aUnits = EDA_UNITS::MILLIMETRES; - break; - - case 3: // auto - aUnits = m_frame->GetUserUnits(); - break; - - default: - break; - } -} - - -wxString DIALOG_DIMENSION_PROPERTIES::getValueText() -{ - int val = m_dimension->GetMeasuredValue(); - int precision = m_cbPrecision->GetSelection(); - - EDA_UNITS units; - bool useMils; - getUnitsSelection( units, useMils ); - - wxString text; - wxString format = wxT( "%." ) + wxString::Format( "%i", precision ) + wxT( "f" ); - - text.Printf( format, To_User_Unit( units, val, useMils ) ); - - if( m_cbSuppressZeroes->GetValue() ) - { - while( text[text.Length() - 1] == '0' || text[text.Length() - 1] == '.' ) - text.Remove( text.Length() - 1 ); - } - - return text; + aTarget->Update(); } void DIALOG_DIMENSION_PROPERTIES::updatePreviewText() { - wxString text = m_cbOverrideValue->GetValue() ? m_txtValue->GetValue() : getValueText(); - - EDA_UNITS units; - bool useMils; - getUnitsSelection( units, useMils ); - - switch( m_cbUnitsFormat->GetSelection() ) - { - case 0: // no units - break; - - case 1: // normal - text += " "; - text += GetAbbreviatedUnitsLabel( units, useMils ); - break; - - case 2: // parenthetical - text += " ("; - text += GetAbbreviatedUnitsLabel( units, useMils ); - text += ")"; - break; - } - - text.Prepend( m_txtPrefix->GetValue() ); - text.Append( m_txtSuffix->GetValue() ); - - m_staticTextPreview->SetLabel( text ); + updateDimensionFromDialog( m_previewDimension ); + m_staticTextPreview->SetLabel( m_previewDimension->Text().GetShownText() ); } diff --git a/pcbnew/dialogs/dialog_dimension_properties.h b/pcbnew/dialogs/dialog_dimension_properties.h index 70c5212185..980af19b5d 100644 --- a/pcbnew/dialogs/dialog_dimension_properties.h +++ b/pcbnew/dialogs/dialog_dimension_properties.h @@ -49,6 +49,7 @@ private: PCB_BASE_EDIT_FRAME* m_frame; DIMENSION* m_dimension; + DIMENSION* m_previewDimension; UNIT_BINDER m_textWidth; UNIT_BINDER m_textHeight; @@ -62,9 +63,7 @@ private: UNIT_BINDER m_lineThickness; UNIT_BINDER m_arrowLength; - void getUnitsSelection( EDA_UNITS& aUnits, bool& aUseMils ); - - wxString getValueText(); + void updateDimensionFromDialog( DIMENSION* aTarget ); void updatePreviewText(); }; diff --git a/pcbnew/dialogs/dialog_dimension_properties_base.cpp b/pcbnew/dialogs/dialog_dimension_properties_base.cpp index d772f3b00f..f7919a9f0e 100644 --- a/pcbnew/dialogs/dialog_dimension_properties_base.cpp +++ b/pcbnew/dialogs/dialog_dimension_properties_base.cpp @@ -222,14 +222,14 @@ DIALOG_DIMENSION_PROPERTIES_BASE::DIALOG_DIMENSION_PROPERTIES_BASE( wxWindow* pa m_lblTextOrientation->Wrap( -1 ); m_lblTextOrientation->SetToolTip( _("Text orientation") ); - gbSizerText->Add( m_lblTextOrientation, wxGBPosition( 2, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + gbSizerText->Add( m_lblTextOrientation, wxGBPosition( 3, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_cbTextOrientation = new wxComboBox( sbSizerText->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); m_cbTextOrientation->Append( _("0.0") ); m_cbTextOrientation->Append( _("90.0") ); m_cbTextOrientation->Append( _("-90.0") ); m_cbTextOrientation->Append( _("180.0") ); - gbSizerText->Add( m_cbTextOrientation, wxGBPosition( 2, 5 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); + gbSizerText->Add( m_cbTextOrientation, wxGBPosition( 3, 5 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); m_cbItalic = new wxCheckBox( sbSizerText->GetStaticBox(), wxID_ANY, _("Italic"), wxDefaultPosition, wxDefaultSize, 0 ); gbSizerText->Add( m_cbItalic, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); @@ -237,7 +237,7 @@ DIALOG_DIMENSION_PROPERTIES_BASE::DIALOG_DIMENSION_PROPERTIES_BASE( wxWindow* pa m_cbKeepAligned = new wxCheckBox( sbSizerText->GetStaticBox(), wxID_ANY, _("Keep aligned with dimension"), wxDefaultPosition, wxDefaultSize, 0 ); m_cbKeepAligned->SetToolTip( _("Automatically set the text orientation to match the dimension lines") ); - gbSizerText->Add( m_cbKeepAligned, wxGBPosition( 3, 4 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + gbSizerText->Add( m_cbKeepAligned, wxGBPosition( 4, 4 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_cbMirrored = new wxCheckBox( sbSizerText->GetStaticBox(), wxID_ANY, _("Mirrored"), wxDefaultPosition, wxDefaultSize, 0 ); m_cbMirrored->SetToolTip( _("Mirror text") ); @@ -246,13 +246,25 @@ DIALOG_DIMENSION_PROPERTIES_BASE::DIALOG_DIMENSION_PROPERTIES_BASE( wxWindow* pa m_lblJustification = new wxStaticText( sbSizerText->GetStaticBox(), wxID_ANY, _("Justification:"), wxDefaultPosition, wxDefaultSize, 0 ); m_lblJustification->Wrap( -1 ); - gbSizerText->Add( m_lblJustification, wxGBPosition( 4, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + gbSizerText->Add( m_lblJustification, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); wxString m_cbJustificationChoices[] = { _("Left"), _("Center"), _("Right") }; int m_cbJustificationNChoices = sizeof( m_cbJustificationChoices ) / sizeof( wxString ); m_cbJustification = new wxChoice( sbSizerText->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cbJustificationNChoices, m_cbJustificationChoices, 0 ); m_cbJustification->SetSelection( 0 ); - gbSizerText->Add( m_cbJustification, wxGBPosition( 4, 5 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); + gbSizerText->Add( m_cbJustification, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); + + m_lblTextPositionMode = new wxStaticText( sbSizerText->GetStaticBox(), wxID_ANY, _("Position mode:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblTextPositionMode->Wrap( -1 ); + gbSizerText->Add( m_lblTextPositionMode, wxGBPosition( 2, 4 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxString m_cbTextPositionModeChoices[] = { _("Outside"), _("Inline"), _("Manual") }; + int m_cbTextPositionModeNChoices = sizeof( m_cbTextPositionModeChoices ) / sizeof( wxString ); + m_cbTextPositionMode = new wxChoice( sbSizerText->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cbTextPositionModeNChoices, m_cbTextPositionModeChoices, 0 ); + m_cbTextPositionMode->SetSelection( 0 ); + m_cbTextPositionMode->SetToolTip( _("Choose how to position the text relative to the dimension line") ); + + gbSizerText->Add( m_cbTextPositionMode, wxGBPosition( 2, 5 ), wxGBSpan( 1, 1 ), wxALL|wxEXPAND, 5 ); gbSizerText->AddGrowableCol( 1 ); diff --git a/pcbnew/dialogs/dialog_dimension_properties_base.fbp b/pcbnew/dialogs/dialog_dimension_properties_base.fbp index 76318ad8b1..16036eff1f 100644 --- a/pcbnew/dialogs/dialog_dimension_properties_base.fbp +++ b/pcbnew/dialogs/dialog_dimension_properties_base.fbp @@ -2309,7 +2309,7 @@ 1 4 wxALIGN_CENTER_VERTICAL|wxALL - 2 + 3 1 1 @@ -2373,7 +2373,7 @@ 1 5 wxALL|wxEXPAND - 2 + 3 1 1 @@ -2509,7 +2509,7 @@ 3 4 wxALIGN_CENTER_VERTICAL|wxALL - 3 + 4 1 1 @@ -2641,9 +2641,9 @@ 5 1 - 4 + 0 wxALIGN_CENTER_VERTICAL|wxALL - 4 + 5 1 1 @@ -2705,9 +2705,9 @@ 5 1 - 5 + 1 wxALL|wxEXPAND - 4 + 5 1 1 @@ -2769,6 +2769,137 @@ + + 5 + 1 + 4 + wxALIGN_CENTER_VERTICAL|wxALL + 2 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Position mode: + 0 + + 0 + + + 0 + + 1 + m_lblTextPositionMode + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + 1 + 5 + wxALL|wxEXPAND + 2 + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + "Outside" "Inline" "Manual" + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_cbTextPositionMode + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + Choose how to position the text relative to the dimension line + + wxFILTER_NONE + wxDefaultValidator + + + + + + diff --git a/pcbnew/dialogs/dialog_dimension_properties_base.h b/pcbnew/dialogs/dialog_dimension_properties_base.h index 0f395a8e83..fb68cc9ba1 100644 --- a/pcbnew/dialogs/dialog_dimension_properties_base.h +++ b/pcbnew/dialogs/dialog_dimension_properties_base.h @@ -82,6 +82,8 @@ class DIALOG_DIMENSION_PROPERTIES_BASE : public DIALOG_SHIM wxCheckBox* m_cbMirrored; wxStaticText* m_lblJustification; wxChoice* m_cbJustification; + wxStaticText* m_lblTextPositionMode; + wxChoice* m_cbTextPositionMode; wxStaticText* m_lblLineThickness; wxTextCtrl* m_txtLineThickness; wxStaticText* m_lblLineThicknessUnits; diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index d0aa2837b3..dc76ec38eb 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -683,17 +683,17 @@ void PCB_IO::format( ALIGNED_DIMENSION* aDimension, int aNestLevel ) const m_out->Print( aNestLevel+1, "(format" ); if( !aDimension->GetPrefix().IsEmpty() ) - m_out->Print( 0, " (prefix %s)", TO_UTF8( aDimension->GetPrefix() ) ); + m_out->Print( 0, " (prefix \"%s\")", TO_UTF8( aDimension->GetPrefix() ) ); if( !aDimension->GetSuffix().IsEmpty() ) - m_out->Print( 0, " (suffix %s)", TO_UTF8( aDimension->GetSuffix() ) ); + m_out->Print( 0, " (suffix \"%s\")", TO_UTF8( aDimension->GetSuffix() ) ); m_out->Print( 0, " (units %d) (units_format %d) (precision %d)", static_cast( aDimension->GetUnitsMode() ), static_cast( aDimension->GetUnitsFormat() ), aDimension->GetPrecision() ); - if( aDimension->GetOverrideValue() ) - m_out->Print( 0, " override_value" ); + if( aDimension->GetOverrideTextEnabled() ) + m_out->Print( 0, " (override_value \"%s\")", TO_UTF8( aDimension->GetOverrideText() ) ); if( aDimension->GetSuppressZeroes() ) m_out->Print( 0, " suppress_zeroes" ); @@ -710,7 +710,7 @@ void PCB_IO::format( ALIGNED_DIMENSION* aDimension, int aNestLevel ) const FormatInternalUnits( aDimension->GetExtensionOffset() ).c_str() ); if( !aDimension->GetKeepTextAligned() ) - m_out->Print( 0, " keep_upright" ); + m_out->Print( 0, " keep_text_aligned" ); m_out->Print( 0, ")\n" ); diff --git a/pcbnew/pcb_base_edit_frame.cpp b/pcbnew/pcb_base_edit_frame.cpp index 696f05bf7c..9d05627d14 100644 --- a/pcbnew/pcb_base_edit_frame.cpp +++ b/pcbnew/pcb_base_edit_frame.cpp @@ -38,6 +38,7 @@ #include #include #include +#include PCB_BASE_EDIT_FRAME::PCB_BASE_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType, const wxString& aTitle, @@ -160,6 +161,29 @@ void PCB_BASE_EDIT_FRAME::unitsChangeRefresh() { PCB_BASE_FRAME::unitsChangeRefresh(); + if( BOARD* board = GetBoard() ) + { + EDA_UNITS units = GetUserUnits(); + KIGFX::VIEW* view = GetCanvas()->GetView(); + + INSPECTOR_FUNC inspector = + [units, view]( EDA_ITEM* aItem, void* aTestData ) + { + DIMENSION* dimension = static_cast( aItem ); + + if( dimension->GetUnitsMode() == DIM_UNITS_MODE::AUTOMATIC ) + { + dimension->SetUnits( units, false ); + dimension->Update(); + view->Update( dimension ); + } + + return SEARCH_RESULT::CONTINUE; + }; + + board->Visit( inspector, nullptr, GENERAL_COLLECTOR::Dimensions ); + } + ReCreateAuxiliaryToolbar(); } diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 5732e50528..7df580d444 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -1296,7 +1296,7 @@ void PCB_PAINTER::draw( const DIMENSION* aDimension, int aLayer ) } m_gal->SetTextAttributes( &text ); - m_gal->StrokeText( text.GetShownText(), position, text.GetTextAngleRadians() ); + m_gal->StrokeText( aDimension->GetText(), position, text.GetTextAngleRadians() ); } diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 35791f7da3..4e81f9245e 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2486,11 +2486,19 @@ DIMENSION* PCB_PARSER::parseDIMENSION() break; case T_override_value: - dimension->SetOverrideValue( true ); + NeedSYMBOLorNUMBER(); + dimension->SetOverrideTextEnabled( true ); + dimension->SetOverrideText( FromUTF8() ); + NeedRIGHT(); + break; + + case T_suppress_zeroes: + dimension->SetSuppressZeroes( true ); break; default: - Expecting( "prefix, suffix, units, units_format, precision, override_value" ); + Expecting( "prefix, suffix, units, units_format, precision, override_value, " + "suppress_zeroes" ); } } break; @@ -2498,6 +2506,9 @@ DIMENSION* PCB_PARSER::parseDIMENSION() case T_style: { + // new format: default to keep text aligned off unless token is present + dimension->SetKeepTextAligned( false ); + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { switch( token ) @@ -2533,6 +2544,10 @@ DIMENSION* PCB_PARSER::parseDIMENSION() NeedRIGHT(); break; + case T_keep_text_aligned: + dimension->SetKeepTextAligned( true ); + break; + default: Expecting( "thickness, arrow_length, text_position_mode, extension_height, " "extension_offset" ); @@ -2664,6 +2679,8 @@ DIMENSION* PCB_PARSER::parseDIMENSION() } } + dimension->Update(); + return dimension.release(); } diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp index ea5dd3af38..1c53a39f74 100644 --- a/pcbnew/tools/point_editor.cpp +++ b/pcbnew/tools/point_editor.cpp @@ -80,6 +80,7 @@ enum DIMENSION_POINTS DIM_CROSSBAREND, DIM_START, DIM_END, + DIM_TEXT }; class EDIT_POINTS_FACTORY @@ -251,6 +252,7 @@ public: points->AddPoint( dimension->GetCrossbarEnd() ); points->AddPoint( dimension->GetStart() ); points->AddPoint( dimension->GetEnd() ); + points->AddPoint( dimension->Text().GetPosition() ); // Dimension height setting - edit points should move only along the feature lines points->Point( DIM_CROSSBARSTART ).SetConstraint( new EC_LINE( points->Point( DIM_CROSSBARSTART ), @@ -1297,6 +1299,14 @@ void POINT_EDITOR::updateItem() const m_editPoints->Point( DIM_END ) ) ); } + else if( isModified( m_editPoints->Point(DIM_TEXT ) ) ) + { + // Force manual mode if we weren't already in it + dimension->SetTextPositionMode( DIM_TEXT_POSITION::MANUAL ); + dimension->Text().SetPosition( wxPoint( m_editedPoint->GetPosition() ) ); + dimension->Update(); + } + break; } @@ -1525,6 +1535,7 @@ void POINT_EDITOR::updatePoints() m_editPoints->Point( DIM_CROSSBAREND ).SetPosition( dimension->GetCrossbarEnd() ); m_editPoints->Point( DIM_START ).SetPosition( dimension->GetStart() ); m_editPoints->Point( DIM_END ).SetPosition( dimension->GetEnd() ); + m_editPoints->Point( DIM_TEXT ).SetPosition( dimension->Text().GetPosition() ); break; }