diff --git a/common/plotters/PDF_plotter.cpp b/common/plotters/PDF_plotter.cpp index 760a0a0532..3ed60bbff0 100644 --- a/common/plotters/PDF_plotter.cpp +++ b/common/plotters/PDF_plotter.cpp @@ -1978,15 +1978,14 @@ void PDF_PLOTTER::Text( const VECTOR2I& aPos, while( str_tok.HasMoreTokens() ) { wxString word = str_tok.GetNextToken(); - pos = renderWord( word, pos, t_size, aOrient, textMirrored, aWidth, aBold, aItalic, - aFont, aFontMetrics, aV_justify, 0 ); + pos = renderWord( word, pos, t_size, aOrient, textMirrored, aWidth, aBold, aItalic, aFont, + aFontMetrics, aV_justify, 0 ); } return; } // Calculate the full text bounding box for alignment - VECTOR2I full_box( aFont->StringBoundaryLimits( text, t_size, aWidth, aBold, aItalic, - aFontMetrics ) ); + VECTOR2I full_box( aFont->StringBoundaryLimits( text, t_size, aWidth, aBold, aItalic, aFontMetrics ) ); if( textMirrored ) full_box.x *= -1; @@ -2027,7 +2026,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi if( wxGetEnv( "KICAD_DEBUG_SYN_STYLE", nullptr ) ) { int styleFlags = 0; - if( aFont && aFont->IsOutline() ) + if( aFont->IsOutline() ) styleFlags = static_cast( aFont )->GetFace() ? static_cast( aFont )->GetFace()->style_flags : 0; wxLogTrace( tracePdfPlotter, "renderWord enter word='%s' bold=%d italic=%d textStyle=%u styleFlags=%d", TO_UTF8( aWord ), (int) aBold, (int) aItalic, (unsigned) aTextStyle, styleFlags ); } @@ -2040,8 +2039,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi if( aWord == wxT(" ") ) { // Calculate space width and advance position - VECTOR2I spaceBox( aFont->StringBoundaryLimits( wxT("n"), aSize, aWidth, - aBold, aItalic, aFontMetrics ).x / 2, 0 ); + VECTOR2I spaceBox( aFont->StringBoundaryLimits( "n", aSize, aWidth, aBold, aItalic, aFontMetrics ).x / 2, 0 ); if( aTextMirrored ) spaceBox.x *= -1; @@ -2055,15 +2053,16 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi double ctm_a, ctm_b, ctm_c, ctm_d, ctm_e, ctm_f; double wideningFactor, heightFactor; - computeTextParameters( aPosition, aWord, aOrient, aSize, aTextMirrored, - GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_BOTTOM, aWidth, - aItalic, aBold, &wideningFactor, &ctm_a, &ctm_b, &ctm_c, - &ctm_d, &ctm_e, &ctm_f, &heightFactor ); + computeTextParameters( aPosition, aWord, aOrient, aSize, aTextMirrored, GR_TEXT_H_ALIGN_LEFT, + GR_TEXT_V_ALIGN_BOTTOM, aWidth, aItalic, aBold, &wideningFactor, + &ctm_a, &ctm_b, &ctm_c, &ctm_d, &ctm_e, &ctm_f, &heightFactor ); // Calculate next position for word spacing VECTOR2I bbox( aFont->StringBoundaryLimits( aWord, aSize, aWidth, aBold, aItalic, aFontMetrics ).x, 0 ); + if( aTextMirrored ) bbox.x *= -1; + RotatePoint( bbox, aOrient ); VECTOR2I nextPos = aPosition + bbox; @@ -2072,7 +2071,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi // Outline fonts need: superscript +1 full font height higher; subscript +1 full font height higher if( aTextStyle & TEXT_STYLE::SUPERSCRIPT ) { - double factor = ( aFont && aFont->IsOutline() ) ? 0.050 : 0.030; // stroke original ~0.40, outline needs +1.0 + double factor = aFont->IsOutline() ? 0.050 : 0.030; // stroke original ~0.40, outline needs +1.0 VECTOR2I offset( 0, static_cast( std::lround( aSize.y * factor ) ) ); RotatePoint( offset, aOrient ); ctm_e -= offset.x; @@ -2083,7 +2082,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi // For outline fonts raise by one font height versus stroke (which shifts downward slightly) VECTOR2I offset( 0, 0 ); - if( !aFont || aFont->IsStroke() ) + if( aFont->IsStroke() ) offset.y = static_cast( std::lround( aSize.y * 0.01 ) ); RotatePoint( offset, aOrient ); @@ -2092,9 +2091,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi } // Render the word using existing outline font logic - bool useOutlineFont = aFont && aFont->IsOutline(); - - if( useOutlineFont ) + if( aFont->IsOutline() ) { std::vector outlineRuns; @@ -2111,6 +2108,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi // Apply baseline adjustment (keeping existing logic) double baseline_factor = 0.17; double alignment_multiplier = 1.0; + if( aV_justify == GR_TEXT_V_ALIGN_CENTER ) alignment_multiplier = 2.0; else if( aV_justify == GR_TEXT_V_ALIGN_TOP ) @@ -2132,16 +2130,6 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi double adj_c = ctm_c; double adj_d = ctm_d; - if( aItalic && ( !aFont || !aFont->IsOutline() ) ) - { - double tilt = -ITALIC_TILT; - if( wideningFactor < 0 ) - tilt = -tilt; - - adj_c -= ctm_a * tilt; - adj_d -= ctm_b * tilt; - } - // Synthetic italic (shear) for outline font if requested but font not intrinsically italic bool syntheticItalicApplied = false; double appliedTilt = 0.0; @@ -2150,13 +2138,15 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi double syn_a = ctm_a; double syn_b = ctm_b; bool wantItalic = ( aItalic || ( aTextStyle & TEXT_STYLE::ITALIC ) ); + if( std::getenv( "KICAD_FORCE_SYN_ITALIC" ) ) wantItalic = true; // debug: ensure path triggers when forcing synthetic italic - bool wantBold = ( aBold || ( aTextStyle & TEXT_STYLE::BOLD ) ); - bool fontIsItalic = aFont && aFont->IsOutline() && aFont->IsItalic(); - bool fontIsBold = aFont && aFont->IsOutline() && aFont->IsBold(); - bool fontIsFakeItalic = aFont && aFont->IsOutline() && static_cast( aFont )->IsFakeItalic(); - bool fontIsFakeBold = aFont && aFont->IsOutline() && static_cast( aFont )->IsFakeBold(); + + bool wantBold = ( aBold || ( aTextStyle & TEXT_STYLE::BOLD ) ); + bool fontIsItalic = aFont->IsItalic(); + bool fontIsBold = aFont->IsBold(); + bool fontIsFakeItalic = static_cast( aFont )->IsFakeItalic(); + bool fontIsFakeBold = static_cast( aFont )->IsFakeBold(); // Environment overrides for testing synthetic italics: // KICAD_FORCE_SYN_ITALIC=1 forces synthetic shear even if font has italic face @@ -2164,6 +2154,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi // otherwise treat as raw tilt factor (x += tilt*y) bool forceSynItalic = false; double overrideTilt = 0.0; + if( const char* envForce = std::getenv( "KICAD_FORCE_SYN_ITALIC" ) ) { if( *envForce != '\0' && *envForce != '0' ) @@ -2173,6 +2164,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi if( const char* envTilt = std::getenv( "KICAD_SYN_ITALIC_TILT" ) ) { std::string tiltStr( envTilt ); + try { if( tiltStr.find( "deg" ) != std::string::npos ) @@ -2202,8 +2194,9 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi // - Italic requested AND outline font // - And either forceSynItalic env var set OR there is no REAL italic face. // (A fake italic flag from fontconfig substitution should NOT block synthetic shear.) - bool realItalicFace = aFont && aFont->IsOutline() && aFont->IsItalic() && !fontIsFakeItalic; - if( wantItalic && aFont && aFont->IsOutline() && ( forceSynItalic || !realItalicFace ) ) + bool realItalicFace = fontIsItalic && !fontIsFakeItalic; + + if( wantItalic && ( forceSynItalic || !realItalicFace ) ) { // We want to apply a horizontal shear so that x' = x + tilt * y in the glyph's // local coordinate system BEFORE rotation. The existing text matrix columns are: @@ -2215,6 +2208,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi // to the second column: (c', d') = (c + tilt * a, d + tilt * b). // This produces a right-leaning italic for positive tilt. double tilt = ( overrideTilt != 0.0 ) ? overrideTilt : ITALIC_TILT; + if( wideningFactor < 0 ) // mirrored text should mirror the shear tilt = -tilt; @@ -2223,12 +2217,11 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi appliedTilt = tilt; syntheticItalicApplied = true; - wxLogTrace( tracePdfPlotter, - "Synthetic italic shear applied: tilt=%f a=%f b=%f c->%f d->%f", + wxLogTrace( tracePdfPlotter, "Synthetic italic shear applied: tilt=%f a=%f b=%f c->%f d->%f", tilt, syn_a, syn_b, syn_c, syn_d ); } - if( wantBold && aFont && aFont->IsOutline() && !fontIsBold ) + if( wantBold && !fontIsBold ) { // Slight horizontal widening to simulate bold (~3%) syn_a *= 1.03; @@ -2238,7 +2231,8 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi if( syntheticItalicApplied ) { // PDF comment to allow manual inspection in the output stream - fmt::print( m_workFile, "% syn-italic tilt={} a={} b={} c={} d={}\n", appliedTilt, syn_a, syn_b, syn_c, syn_d ); + fmt::print( m_workFile, "% syn-italic tilt={} a={} b={} c={} d={}\n", + appliedTilt, syn_a, syn_b, syn_c, syn_d ); } fmt::print( m_workFile, "q {:f} {:f} {:f} {:f} {:f} {:f} cm BT {} Tr {:g} Tz ", @@ -2287,6 +2281,7 @@ VECTOR2I PDF_PLOTTER::renderWord( const wxString& aWord, const VECTOR2I& aPositi if( aItalic && ( !aFont || !aFont->IsOutline() ) ) { double tilt = -ITALIC_TILT; + if( wideningFactor < 0 ) tilt = -tilt; @@ -2368,9 +2363,9 @@ VECTOR2I PDF_PLOTTER::renderMarkupNode( const MARKUP::NODE* aNode, const VECTOR2 { wxString word = str_tok.GetNextToken(); nextPosition = renderWord( word, nextPosition, currentSize, aOrient, aTextMirrored, - aWidth, aBaseBold || (currentStyle & TEXT_STYLE::BOLD), - aBaseItalic || (currentStyle & TEXT_STYLE::ITALIC), - aFont, aFontMetrics, aV_justify, currentStyle ); + aWidth, aBaseBold || (currentStyle & TEXT_STYLE::BOLD), + aBaseItalic || (currentStyle & TEXT_STYLE::ITALIC), + aFont, aFontMetrics, aV_justify, currentStyle ); } } } @@ -2381,14 +2376,14 @@ VECTOR2I PDF_PLOTTER::renderMarkupNode( const MARKUP::NODE* aNode, const VECTOR2 VECTOR2I startPos = nextPosition; nextPosition = renderMarkupNode( child.get(), nextPosition, currentSize, aOrient, - aTextMirrored, aWidth, aBaseBold, aBaseItalic, - aFont, aFontMetrics, aV_justify, currentStyle, aOverbars ); + aTextMirrored, aWidth, aBaseBold, aBaseItalic, + aFont, aFontMetrics, aV_justify, currentStyle, aOverbars ); // Store overbar info for later rendering if( drawOverbar ) { VECTOR2I endPos = nextPosition; - aOverbars.push_back( { startPos, endPos, currentSize, aFont && aFont->IsOutline(), aV_justify } ); + aOverbars.push_back( { startPos, endPos, currentSize, aFont->IsOutline(), aV_justify } ); } } diff --git a/common/plotters/pdf_stroke_font.cpp b/common/plotters/pdf_stroke_font.cpp index ffcfc326b7..851edd579f 100644 --- a/common/plotters/pdf_stroke_font.cpp +++ b/common/plotters/pdf_stroke_font.cpp @@ -172,7 +172,6 @@ int PDF_STROKE_FONT_SUBSET::EnsureGlyph( wxUniChar aCode ) return -1; int glyphIndex = glyphIndexForUnicode( aCode ); - const KIFONT::STROKE_GLYPH* glyph = m_font ? m_font->GetGlyph( glyphIndex ) : nullptr; int code = m_nextCode++; m_lastCode = std::max( m_lastCode, code ); @@ -184,7 +183,15 @@ int PDF_STROKE_FONT_SUBSET::EnsureGlyph( wxUniChar aCode ) data.m_name = makeGlyphName( code ); data.m_charProcHandle = -1; - const BOX2D& bbox = m_font->GetGlyphBoundingBox( glyphIndex ); + const KIFONT::STROKE_GLYPH* glyph = nullptr; + BOX2D bbox; + + if( m_font ) + { + glyph = m_font->GetGlyph( glyphIndex ); + bbox = m_font->GetGlyphBoundingBox( glyphIndex ); + } + VECTOR2D origin = bbox.GetOrigin(); VECTOR2D size = bbox.GetSize(); @@ -231,7 +238,7 @@ int PDF_STROKE_FONT_SUBSET::EnsureGlyph( wxUniChar aCode ) m_bboxMaxX = std::max( m_bboxMaxX, data.m_maxX ); m_bboxMaxY = std::max( m_bboxMaxY, data.m_maxY ); - m_glyphs.push_back( data ); + m_glyphs.push_back( std::move( data ) ); m_unicodeToCode.emplace( aCode, code ); return code; @@ -434,7 +441,7 @@ void PDF_STROKE_FONT_MANAGER::EncodeString( const wxString& aText, for( wxUniChar ch : aText ) { - PDF_STROKE_FONT_SUBSET* subset = ensureSubsetForGlyph( ch, aBold, aItalic ); + PDF_STROKE_FONT_SUBSET* subset = ensureSubsetForGlyph( ch, aBold, aItalic ); if( !subset ) continue; @@ -457,7 +464,7 @@ void PDF_STROKE_FONT_MANAGER::EncodeString( const wxString& aText, } if( !currentBytes.empty() && currentSubset ) - aRuns->push_back( { currentSubset, currentBytes, aBold, aItalic } ); + aRuns->push_back( { currentSubset, std::move( currentBytes ), aBold, aItalic } ); } PDF_STROKE_FONT_SUBSET* PDF_STROKE_FONT_MANAGER::ensureSubsetForGlyph( wxUniChar aCode, bool aBold, bool aItalic ) diff --git a/eeschema/dialogs/dialog_lib_fields_table.cpp b/eeschema/dialogs/dialog_lib_fields_table.cpp index a0410a74a3..0b2a351a66 100644 --- a/eeschema/dialogs/dialog_lib_fields_table.cpp +++ b/eeschema/dialogs/dialog_lib_fields_table.cpp @@ -168,18 +168,20 @@ protected: } else if( event.GetId() == MYID_CREATE_DERIVED_SYMBOL ) { + EDA_DRAW_FRAME* frame = dynamic_cast( m_dlg->GetParent() ); + wxCHECK( frame, /* void */ ); + const LIB_SYMBOL* parentSymbol = m_dataModel->GetSymbolForRow( row ); wxArrayString symbolNames; m_dataModel->GetSymbolNames( symbolNames ); auto validator = - [&]( wxString newName ) -> bool + [&]( const wxString& newName ) -> bool { return symbolNames.Index( newName ) == wxNOT_FOUND; }; - EDA_DRAW_FRAME* frame = dynamic_cast( m_dlg->GetParent() ); DIALOG_NEW_SYMBOL dlg( frame, symbolNames, parentSymbol->GetName(), validator ); if( dlg.ShowModal() != wxID_OK ) diff --git a/eeschema/dialogs/dialog_lib_new_symbol.cpp b/eeschema/dialogs/dialog_lib_new_symbol.cpp index 95fb2d7e11..5411669ef5 100644 --- a/eeschema/dialogs/dialog_lib_new_symbol.cpp +++ b/eeschema/dialogs/dialog_lib_new_symbol.cpp @@ -39,7 +39,7 @@ static wxString getDerivativeName( const wxString& aParentName ) DIALOG_LIB_NEW_SYMBOL::DIALOG_LIB_NEW_SYMBOL( EDA_DRAW_FRAME* aParent, const wxArrayString& aSymbolNames, const wxString& aInheritFromSymbolName, - std::function aValidator ) : + std::function aValidator ) : DIALOG_LIB_NEW_SYMBOL_BASE( dynamic_cast( aParent ) ), m_pinTextPosition( aParent, m_staticPinTextPositionLabel, m_textPinTextPosition, m_staticPinTextPositionUnits, true ), diff --git a/eeschema/dialogs/dialog_lib_new_symbol.h b/eeschema/dialogs/dialog_lib_new_symbol.h index c4f6d4688d..710e139d72 100644 --- a/eeschema/dialogs/dialog_lib_new_symbol.h +++ b/eeschema/dialogs/dialog_lib_new_symbol.h @@ -35,8 +35,8 @@ class DIALOG_LIB_NEW_SYMBOL : public DIALOG_LIB_NEW_SYMBOL_BASE { public: DIALOG_LIB_NEW_SYMBOL( EDA_DRAW_FRAME* aParent, const wxArrayString& aSymbolNames, - const wxString& aInheritFromSymbolName, - std::function aValidator ); + const wxString& aInheritFromSymbolName, + std::function aValidator ); ~DIALOG_LIB_NEW_SYMBOL(); @@ -118,8 +118,8 @@ private: void syncControls( bool aIsDerivedPart ); private: - UNIT_BINDER m_pinTextPosition; - std::function m_validator; - wxString m_inheritFromSymbolName; - bool m_nameIsDefaulted; + UNIT_BINDER m_pinTextPosition; + std::function m_validator; + wxString m_inheritFromSymbolName; + bool m_nameIsDefaulted; }; diff --git a/qa/tests/eeschema/test_pin_stacked_layout.cpp b/qa/tests/eeschema/test_pin_stacked_layout.cpp index d4bbe984a2..2839dce4f7 100644 --- a/qa/tests/eeschema/test_pin_stacked_layout.cpp +++ b/qa/tests/eeschema/test_pin_stacked_layout.cpp @@ -148,12 +148,13 @@ static bool boxIntersectsLine( const BOX2I& box, const VECTOR2I& lineStart, cons BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) { // Create test symbol - auto symbol = createTestResistorSymbol(); + std::unique_ptr symbol = createTestResistorSymbol(); BOOST_REQUIRE( symbol ); // Get the pins std::vector pins; - for( auto& item : symbol->GetDrawItems() ) + + for( SCH_ITEM& item : symbol->GetDrawItems() ) { if( item.Type() == SCH_PIN_T ) pins.push_back( static_cast( &item ) ); @@ -188,12 +189,12 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) PIN_LAYOUT_CACHE cache( *pin ); // Get pin number text info (shadow width 0 for testing) - auto numberInfoOpt = cache.GetPinNumberInfo( 0 ); + std::optional numberInfoOpt = cache.GetPinNumberInfo( 0 ); if( !numberInfoOpt.has_value() ) continue; - PIN_LAYOUT_CACHE::TEXT_INFO numberInfo = numberInfoOpt.value(); + const PIN_LAYOUT_CACHE::TEXT_INFO& numberInfo = numberInfoOpt.value(); if( numberInfo.m_Text.IsEmpty() ) continue; @@ -220,8 +221,10 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) textWidth = lines.size() * lineSpacing; // Find longest line for height size_t maxLen = 0; + for( const wxString& line : lines ) maxLen = std::max( maxLen, line.Length() ); + textHeight = maxLen * textHeight * 0.6; } else @@ -231,8 +234,10 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) textHeight = lines.size() * lineSpacing; // Find longest line for width size_t maxLen = 0; + for( const wxString& line : lines ) maxLen = std::max( maxLen, line.Length() ); + textWidth = maxLen * textHeight * 0.6; } } @@ -240,7 +245,7 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) // Create text bounding box around text position BOX2I textBbox; textBbox.SetOrigin( numberInfo.m_TextPosition.x - textWidth/2, - numberInfo.m_TextPosition.y - textHeight/2 ); + numberInfo.m_TextPosition.y - textHeight/2 ); textBbox.SetSize( textWidth, textHeight ); // Check for intersection @@ -248,16 +253,16 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) // Log detailed info for debugging wxLogMessage( wxT("Rotation %s, Pin %s: pos=(%d,%d) textPos=(%d,%d) pinLine=(%d,%d)-(%d,%d) textBox=(%d,%d,%dx%d) overlap=%s"), - rotName, pin->GetNumber(), - pinStart.x, pinStart.y, - numberInfo.m_TextPosition.x, numberInfo.m_TextPosition.y, - pinStart.x, pinStart.y, pinEnd.x, pinEnd.y, - (int)textBbox.GetLeft(), (int)textBbox.GetTop(), (int)textBbox.GetWidth(), (int)textBbox.GetHeight(), - overlaps ? wxT("YES") : wxT("NO") ); + rotName, pin->GetNumber(), + pinStart.x, pinStart.y, + numberInfo.m_TextPosition.x, numberInfo.m_TextPosition.y, + pinStart.x, pinStart.y, pinEnd.x, pinEnd.y, + (int)textBbox.GetLeft(), (int)textBbox.GetTop(), (int)textBbox.GetWidth(), (int)textBbox.GetHeight(), + overlaps ? wxT("YES") : wxT("NO") ); // Test assertion BOOST_CHECK_MESSAGE( !overlaps, - "Pin number '" << pin->GetNumber() << "' overlaps with pin geometry at rotation " << rotName ); + "Pin number '" << pin->GetNumber() << "' overlaps with pin geometry at rotation " << rotName ); } // Restore original transform @@ -272,12 +277,13 @@ BOOST_AUTO_TEST_CASE( PinNumbersNoOverlapAllRotations ) BOOST_AUTO_TEST_CASE( PinTextConsistentSidePlacement ) { // Create test symbol with both types of pins - auto symbol = createTestResistorSymbol(); + std::unique_ptr symbol = createTestResistorSymbol(); BOOST_REQUIRE( symbol ); // Get the pins - one will be multiline formatted, one will not std::vector pins; - for( auto& item : symbol->GetDrawItems() ) + + for( SCH_ITEM& item : symbol->GetDrawItems() ) { if( item.Type() == SCH_PIN_T ) pins.push_back( static_cast( &item ) ); @@ -315,7 +321,7 @@ BOOST_AUTO_TEST_CASE( PinTextConsistentSidePlacement ) std::vector pinInfos; - for( auto* pin : pins ) + for( SCH_PIN* pin : pins ) { PinTextInfo info; info.pinPos = pin->GetPosition(); @@ -325,30 +331,32 @@ BOOST_AUTO_TEST_CASE( PinTextConsistentSidePlacement ) PIN_LAYOUT_CACHE cache( *pin ); // Get number position (shadow width 0 for testing) - auto numberInfoOpt = cache.GetPinNumberInfo( 0 ); + std::optional numberInfoOpt = cache.GetPinNumberInfo( 0 ); + if( numberInfoOpt.has_value() ) { - auto numberInfo = numberInfoOpt.value(); + const PIN_LAYOUT_CACHE::TEXT_INFO& numberInfo = numberInfoOpt.value(); info.numberPos = numberInfo.m_TextPosition; info.isMultiline = numberInfo.m_Text.Contains( '\n' ); } // Get name position - auto nameInfoOpt = cache.GetPinNameInfo( 0 ); + std::optional nameInfoOpt = cache.GetPinNameInfo( 0 ); + if( nameInfoOpt.has_value() ) { - auto nameInfo = nameInfoOpt.value(); + const PIN_LAYOUT_CACHE::TEXT_INFO& nameInfo = nameInfoOpt.value(); info.namePos = nameInfo.m_TextPosition; } pinInfos.push_back( info ); wxLogDebug( "Rotation %s, Pin %s: pos=(%d,%d) numberPos=(%d,%d) namePos=(%d,%d) multiline=%s", - rotName, info.pinNumber, - info.pinPos.x, info.pinPos.y, - info.numberPos.x, info.numberPos.y, - info.namePos.x, info.namePos.y, - info.isMultiline ? wxT("YES") : wxT("NO") ); + rotName, info.pinNumber, + info.pinPos.x, info.pinPos.y, + info.numberPos.x, info.numberPos.y, + info.namePos.x, info.namePos.y, + info.isMultiline ? wxT("YES") : wxT("NO") ); } BOOST_REQUIRE_EQUAL( pinInfos.size(), 2 ); @@ -360,7 +368,7 @@ BOOST_AUTO_TEST_CASE( PinTextConsistentSidePlacement ) if( orient == PIN_ORIENTATION::PIN_UP || orient == PIN_ORIENTATION::PIN_DOWN ) { - for( const auto& inf : pinInfos ) + for( const PinTextInfo& inf : pinInfos ) { BOOST_CHECK_MESSAGE( inf.numberPos.x < inf.pinPos.x, "At rotation " << rotName << ", number for pin " << inf.pinNumber << " not left of vertical pin." ); @@ -370,7 +378,7 @@ BOOST_AUTO_TEST_CASE( PinTextConsistentSidePlacement ) } else if( orient == PIN_ORIENTATION::PIN_LEFT || orient == PIN_ORIENTATION::PIN_RIGHT ) { - for( const auto& inf : pinInfos ) + for( const PinTextInfo& inf : pinInfos ) { BOOST_CHECK_MESSAGE( inf.numberPos.y < inf.pinPos.y, "At rotation " << rotName << ", number for pin " << inf.pinNumber << " not above horizontal pin." ); @@ -391,12 +399,13 @@ BOOST_AUTO_TEST_CASE( PinTextConsistentSidePlacement ) BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) { // Create test symbol with both types of pins - auto symbol = createTestResistorSymbol(); + std::unique_ptr symbol = createTestResistorSymbol(); BOOST_REQUIRE( symbol ); // Get the pins - one will be multiline formatted, one will not std::vector pins; - for( auto& item : symbol->GetDrawItems() ) + + for( SCH_ITEM& item : symbol->GetDrawItems() ) { if( item.Type() == SCH_PIN_T ) pins.push_back( static_cast( &item ) ); @@ -436,7 +445,7 @@ BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) std::vector pinData; - for( auto* pin : pins ) + for( SCH_PIN* pin : pins ) { PinTextData data; data.pinPos = pin->GetPosition(); @@ -446,8 +455,9 @@ BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) PIN_LAYOUT_CACHE cache( *pin ); // Get number position (shadow width 0 for testing) - auto numberInfoOpt = cache.GetPinNumberInfo( 0 ); + std::optional numberInfoOpt = cache.GetPinNumberInfo( 0 ); PIN_LAYOUT_CACHE::TEXT_INFO numberInfo; // store for later heuristics + if( numberInfoOpt.has_value() ) { numberInfo = numberInfoOpt.value(); @@ -460,8 +470,9 @@ BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) } // Get name position - auto nameInfoOpt = cache.GetPinNameInfo( 0 ); + std::optional nameInfoOpt = cache.GetPinNameInfo( 0 ); PIN_LAYOUT_CACHE::TEXT_INFO nameInfo; // store for width/height heuristic + if( nameInfoOpt.has_value() ) { nameInfo = nameInfoOpt.value(); @@ -480,6 +491,7 @@ BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) // Vertical pins: measure clearance from pin (at pin.x) to RIGHT edge of text box. // We approximate half width from text length heuristic. int textWidth = data.isMultiline ? 0 : (int)( data.pinNumber.Length() * numberInfo.m_TextSize * 0.6 ); + // (Multiline case: numberInfo.m_Text already contains \n; heuristic in earlier section) if( data.isMultiline ) { @@ -487,6 +499,7 @@ BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) int lineSpacing = numberInfo.m_TextSize * 1.3; textWidth = lines.size() * lineSpacing; // when vertical orientation text is rotated } + int rightEdge = data.numberPos.x + textWidth / 2; data.numberBottomDistance = data.pinPos.x - rightEdge; // positive gap int nameWidth = (int)( nameInfo.m_Text.Length() * nameInfo.m_TextSize * 0.6 ); @@ -503,12 +516,12 @@ BOOST_AUTO_TEST_CASE( PinTextSameBottomCoordinate ) pinData.push_back( data ); wxLogDebug( "Rotation %s, Pin %s: pos=(%d,%d) numberPos=(%d,%d) namePos=(%d,%d) multiline=%s numberBottomDist=%d nameBottomDist=%d", - rotName, data.pinNumber, - data.pinPos.x, data.pinPos.y, - data.numberPos.x, data.numberPos.y, - data.namePos.x, data.namePos.y, - data.isMultiline ? wxT("YES") : wxT("NO"), - data.numberBottomDistance, data.nameBottomDistance ); + rotName, data.pinNumber, + data.pinPos.x, data.pinPos.y, + data.numberPos.x, data.numberPos.y, + data.namePos.x, data.namePos.y, + data.isMultiline ? wxT("YES") : wxT("NO"), + data.numberBottomDistance, data.nameBottomDistance ); } BOOST_REQUIRE_EQUAL( pinData.size(), 2 );