From 626bcea8ceb86d874fb2b96ff87b52b682354a7e Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Wed, 30 Sep 2020 20:02:30 +0100 Subject: [PATCH] Move ruler drawing to the stroke font. We don't need to be fast, and this allows us to implement drop shadows for better readability. Fixes https://gitlab.com/kicad/code/kicad/issues/5654 --- common/preview_items/arc_assistant.cpp | 4 +- common/preview_items/preview_utils.cpp | 41 +++-- common/preview_items/ruler_item.cpp | 181 ++++++++++++------- common/preview_items/two_point_assistant.cpp | 2 +- include/preview_items/arc_assistant.h | 17 +- include/preview_items/preview_utils.h | 6 +- include/preview_items/two_point_assistant.h | 13 +- 7 files changed, 165 insertions(+), 99 deletions(-) diff --git a/common/preview_items/arc_assistant.cpp b/common/preview_items/arc_assistant.cpp index 64e6e10d35..6e3a95fe24 100644 --- a/common/preview_items/arc_assistant.cpp +++ b/common/preview_items/arc_assistant.cpp @@ -155,6 +155,6 @@ void ARC_ASSISTANT::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const // place the text next to cursor, on opposite side from radius DrawTextNextToCursor( aView, m_constructMan.GetLastPoint(), - origin - m_constructMan.GetLastPoint(), - cursorStrings ); + origin - m_constructMan.GetLastPoint(), + cursorStrings, aLayer == LAYER_GP_OVERLAY ); } diff --git a/common/preview_items/preview_utils.cpp b/common/preview_items/preview_utils.cpp index b95a3ee232..ac43993865 100644 --- a/common/preview_items/preview_utils.cpp +++ b/common/preview_items/preview_utils.cpp @@ -94,19 +94,19 @@ void KIGFX::PREVIEW::SetConstantGlyphHeight( KIGFX::GAL& aGal, double aHeight ) void KIGFX::PREVIEW::DrawTextNextToCursor( KIGFX::VIEW* aView, const VECTOR2D& aCursorPos, const VECTOR2D& aTextQuadrant, - const std::vector& aStrings ) + const std::vector& aStrings, + bool aDrawingDropShadows ) { - auto gal = aView->GetGAL(); - auto glyphSize = gal->GetGlyphSize(); - auto rs = aView->GetPainter()->GetSettings(); - - const auto lineSpace = glyphSize.y * 0.2; - auto linePitch = glyphSize.y + lineSpace; + KIGFX::GAL* gal = aView->GetGAL(); + VECTOR2D glyphSize = gal->GetGlyphSize(); + RENDER_SETTINGS* rs = aView->GetPainter()->GetSettings(); + double linePitch = glyphSize.y * 1.6; + double textThickness = glyphSize.x / 8; // radius string goes on the right of the cursor centre line // with a small horizontal offset (enough to keep clear of a // system cursor if present) - auto textPos = aCursorPos; + VECTOR2D textPos = aCursorPos; // if the text goes above the cursor, shift it up if( aTextQuadrant.y > 0 ) @@ -118,21 +118,38 @@ void KIGFX::PREVIEW::DrawTextNextToCursor( KIGFX::VIEW* aView, const VECTOR2D& a { gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT ); textPos.x += 15.0 / gal->GetWorldScale(); + + if( aDrawingDropShadows ) + textPos.x -= textThickness; } else { gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT ); textPos.x -= 15.0 / gal->GetWorldScale(); + + if( aDrawingDropShadows ) + textPos.x += textThickness; } - gal->SetLineWidth( 1.0f ); // TODO(ISM): Set to the minimum GAL linewidth for HiDPI compatibility - gal->SetStrokeColor( rs->GetLayerColor( LAYER_AUX_ITEMS ) ); gal->SetIsFill( false ); + gal->SetStrokeColor( rs->GetLayerColor( LAYER_AUX_ITEMS ) ); + + if( aDrawingDropShadows ) + { + if( gal->GetStrokeColor().GetBrightness() > 0.5 ) + gal->SetStrokeColor( COLOR4D::BLACK.WithAlpha( 0.7 ) ); + else + gal->SetStrokeColor( COLOR4D::WHITE.WithAlpha( 0.7 ) ); + + textThickness *= 3; + } + + gal->SetLineWidth( textThickness ); // write strings top-to-bottom - for( const auto& str : aStrings ) + for( const wxString& str : aStrings ) { textPos.y += linePitch; - gal->BitmapText( str, textPos, 0.0 ); + gal->StrokeText( str, textPos, 0.0 ); } } diff --git a/common/preview_items/ruler_item.cpp b/common/preview_items/ruler_item.cpp index 39b0b946dc..bc05fd6832 100644 --- a/common/preview_items/ruler_item.cpp +++ b/common/preview_items/ruler_item.cpp @@ -38,8 +38,15 @@ static const double maxTickDensity = 10.0; // min pixels between tick mark static const double midTickLengthFactor = 1.5; static const double majorTickLengthFactor = 2.5; +static const double tickLineWidth = 1.0; -static void drawCursorStrings( KIGFX::VIEW* aView, const VECTOR2D& aCursor, +// We need a pair of layers for the graphics and drop-shadows, but it's probably not +// worth adding more layers to the enum. +#define LAYER_RULER LAYER_SELECT_OVERLAY +#define LAYER_RULER_SHADOWS LAYER_GP_OVERLAY + + +static void drawCursorStrings( int aLayer, KIGFX::VIEW* aView, const VECTOR2D& aCursor, const VECTOR2D& aRulerVec, EDA_UNITS aUnits ) { // draw the cursor labels @@ -55,7 +62,17 @@ static void drawCursorStrings( KIGFX::VIEW* aView, const VECTOR2D& aCursor, EDA_UNITS::DEGREES ) ); auto temp = aRulerVec; - DrawTextNextToCursor( aView, aCursor, -temp, cursorStrings ); + DrawTextNextToCursor( aView, aCursor, -temp, cursorStrings, aLayer == LAYER_RULER_SHADOWS ); +} + + +static double getTickLineWidth( KIGFX::GAL* aGal, int aLayer ) +{ + if( aLayer == LAYER_RULER_SHADOWS ) + return ( tickLineWidth * 3.0 ) / aGal->GetWorldScale(); + else + return tickLineWidth / aGal->GetWorldScale(); + } @@ -107,6 +124,40 @@ static TICK_FORMAT getTickFormatForScale( double aScale, double& aTickSpace, EDA } +static wxString FormatRulerNumber( double aVal, EDA_UNITS aUnits ) +{ + int precision = 3; + + // show a sane precision for the ruler tick marks, which don't need to be accurate down to + // the nanometre + switch( aUnits ) + { + case EDA_UNITS::MILLIMETRES: + precision = 2; // 10um + break; + + case EDA_UNITS::INCHES: + precision = 3; // 1mil + break; + + case EDA_UNITS::DEGREES: + precision = 1; // 0.1deg + break; + + case EDA_UNITS::PERCENT: + precision = 1; // 0.1% + break; + + case EDA_UNITS::UNSCALED: + break; + } + + const wxString fmtStr = wxString::Format( "%%.%df", precision ); + + return wxString::Format( fmtStr, To_User_Unit( aUnits, aVal ) ); +} + + /** * Draw labelled ticks on a line. Ticks are spaced according to a * maximum density. Miror ticks are not labelled. @@ -116,35 +167,41 @@ static TICK_FORMAT getTickFormatForScale( double aScale, double& aTickSpace, EDA * @param aLine line vector * @param aMinorTickLen length of minor ticks in IU */ -void drawTicksAlongLine( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine, - double aMinorTickLen, EDA_UNITS aUnits ) +void drawTicksAlongLine( int aLayer, KIGFX::GAL* aGal, const VECTOR2D& aOrigin, + const VECTOR2D& aLine, double aMinorTickLen, EDA_UNITS aUnits ) { VECTOR2D tickLine = aLine.Rotate( -M_PI_2 ); - auto gal = aView->GetGAL(); double tickSpace; - TICK_FORMAT tickF = getTickFormatForScale( gal->GetWorldScale(), tickSpace, aUnits ); - auto rs = aView->GetPainter()->GetSettings(); + TICK_FORMAT tickF = getTickFormatForScale( aGal->GetWorldScale(), tickSpace, aUnits ); // number of ticks in whole ruler int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace ); // work out which way up the tick labels go double labelAngle = -tickLine.Angle(); + float textThickness = aGal->GetGlyphSize().x / 8; + float textOffset = 0; + + if( aLayer == LAYER_RULER_SHADOWS ) + { + // Drawing drop shadows + textOffset = textThickness; + textThickness *= 3.0; + } + + double majorTickLen = aMinorTickLen * ( majorTickLengthFactor + 1 ); + VECTOR2D labelOffset = tickLine.Resize( majorTickLen - textOffset ); if( aLine.Angle() > 0 ) { - gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT ); + aGal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT ); } else { - gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT ); + aGal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT ); labelAngle += M_PI; } - gal->SetStrokeColor( rs->GetLayerColor( LAYER_AUX_ITEMS ) ); - - const auto labelOffset = tickLine.Resize( aMinorTickLen * ( majorTickLengthFactor + 1 ) ); - for( int i = 0; i < numTicks; ++i ) { const auto tickPos = aOrigin + aLine.Resize( tickSpace * i ); @@ -163,12 +220,14 @@ void drawTicksAlongLine( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECT length *= midTickLengthFactor; } - gal->DrawLine( tickPos, tickPos + tickLine.Resize( length ) ); + aGal->SetLineWidth( getTickLineWidth( aGal, aLayer ) ); + aGal->DrawLine( tickPos, tickPos + tickLine.Resize( length ) ); if( drawLabel ) { - wxString label = DimensionLabel( "", tickSpace * i, aUnits ); - gal->BitmapText( label, tickPos + labelOffset, labelAngle ); + wxString label = FormatRulerNumber( tickSpace * i, aUnits ); + aGal->SetLineWidth( textThickness ); + aGal->StrokeText( label, tickPos + labelOffset, labelAngle ); } } } @@ -184,16 +243,17 @@ void drawTicksAlongLine( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECT * @param aTickLen length of ticks in IU * @param aNumDivisions number of parts to divide the line into */ -void drawBacksideTicks( KIGFX::GAL& aGal, const VECTOR2D& aOrigin, const VECTOR2D& aLine, - double aTickLen, int aNumDivisions ) +void drawBacksideTicks( int aLayer, KIGFX::GAL* aGal, const VECTOR2D& aOrigin, + const VECTOR2D& aLine, double aTickLen, int aNumDivisions ) { const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions; - const auto backTickVec = aLine.Rotate( M_PI_2 ).Resize( aTickLen ); + const VECTOR2D backTickVec = aLine.Rotate( M_PI_2 ).Resize( aTickLen ); for( int i = 0; i < aNumDivisions + 1; ++i ) { - const auto backTickPos = aOrigin + aLine.Resize( backTickSpace * i ); - aGal.DrawLine( backTickPos, backTickPos + backTickVec ); + const VECTOR2D backTickPos = aOrigin + aLine.Resize( backTickSpace * i ); + aGal->SetLineWidth( getTickLineWidth( aGal, aLayer ) ); + aGal->DrawLine( backTickPos, backTickPos + backTickVec ); } } @@ -219,79 +279,62 @@ const BOX2I RULER_ITEM::ViewBBox() const void RULER_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const { - aLayers[0] = LAYER_GP_OVERLAY; - aCount = 1; + aLayers[0] = LAYER_RULER; + aLayers[1] = LAYER_RULER_SHADOWS; + aCount = 2; } void RULER_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const { - auto& gal = *aView->GetGAL(); - auto rs = aView->GetPainter()->GetSettings(); + KIGFX::GAL* gal = aView->GetGAL(); + RENDER_SETTINGS* rs = aView->GetPainter()->GetSettings(); - gal.PushDepth(); - gal.SetLayerDepth( gal.GetMinDepth() ); + gal->PushDepth(); + gal->SetLayerDepth( gal->GetMinDepth() ); VECTOR2D origin = m_geomMgr.GetOrigin(); VECTOR2D end = m_geomMgr.GetEnd(); - gal.SetLineWidth( 1.0 ); - gal.SetIsStroke( true ); - gal.SetIsFill( false ); + gal->SetIsStroke( true ); + gal->SetIsFill( false ); - gal.SetTextMirrored( false ); - gal.SetStrokeColor( rs->GetLayerColor( LAYER_AUX_ITEMS ) ); + gal->SetTextMirrored( false ); + gal->SetStrokeColor( rs->GetLayerColor( LAYER_AUX_ITEMS ) ); - gal.ResetTextAttributes(); + if( aLayer == LAYER_RULER_SHADOWS ) + { + // Drawing drop-shadows + if( gal->GetStrokeColor().GetBrightness() > 0.5 ) + gal->SetStrokeColor( COLOR4D::BLACK.WithAlpha( 0.7 ) ); + else + gal->SetStrokeColor( COLOR4D::WHITE.WithAlpha( 0.7 ) ); + } + + gal->ResetTextAttributes(); // draw the main line from the origin to cursor - gal.DrawLine( origin, end ); + gal->SetLineWidth( getTickLineWidth( gal, aLayer ) ); + gal->DrawLine( origin, end ); VECTOR2D rulerVec( end - origin ); // constant text size on screen - SetConstantGlyphHeight( gal, 14.0 ); + SetConstantGlyphHeight( *gal, 10.0 ); - drawCursorStrings( aView, end, rulerVec, m_userUnits ); + drawCursorStrings( aLayer, aView, end, rulerVec, m_userUnits ); // tick label size - SetConstantGlyphHeight( gal, 12.0 ); + SetConstantGlyphHeight( *gal, 9.0 ); // basic tick size - const double minorTickLen = 5.0 / gal.GetWorldScale(); + const double minorTickLen = 5.0 / gal->GetWorldScale(); - drawTicksAlongLine( aView, origin, rulerVec, minorTickLen, m_userUnits ); + drawTicksAlongLine( aLayer, gal, origin, rulerVec, minorTickLen, m_userUnits ); - gal.SetStrokeColor( rs->GetLayerColor( LAYER_AUX_ITEMS ) ); - drawBacksideTicks( gal, origin, rulerVec, minorTickLen * majorTickLengthFactor, 2 ); + drawBacksideTicks( aLayer, gal, origin, rulerVec, minorTickLen * majorTickLengthFactor, 2 ); // draw the back of the origin "crosshair" - gal.DrawLine( origin, origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ) ); - - // Draw a shadow behind everything to help visibility on busy boards - if( rulerVec.SquaredEuclideanNorm() > 0 ) - { - VECTOR2D shadowOrigin = origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ); - - wxString dummyText = DimensionLabel( "", 0, m_userUnits ); - double textSize = gal.GetTextLineSize( dummyText ).x; - textSize += minorTickLen * ( majorTickLengthFactor + 1 ); - - VECTOR2D textVec = rulerVec.Rotate( -M_PI_2 ).Resize( textSize ); - - SHAPE_POLY_SET shadow; - shadow.NewOutline(); - shadow.Append( shadowOrigin ); - shadow.Append( end ); - shadow.Append( end + textVec ); - shadow.Append( shadowOrigin + textVec ); - - gal.SetLayerDepth( gal.GetMinDepth() + 1 ); - gal.SetIsStroke( false ); - gal.SetIsFill( true ); - gal.SetFillColor( rs->GetLayerColor( LAYER_PCB_BACKGROUND ).WithAlpha( 0.5 ) ); - gal.DrawPolygon( shadow ); - } - - gal.PopDepth(); + gal->DrawLine( origin, origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ) ); + gal->PopDepth(); } diff --git a/common/preview_items/two_point_assistant.cpp b/common/preview_items/two_point_assistant.cpp index 2d94f6c8ed..aeb9f3f34c 100644 --- a/common/preview_items/two_point_assistant.cpp +++ b/common/preview_items/two_point_assistant.cpp @@ -110,5 +110,5 @@ void TWO_POINT_ASSISTANT::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const } // place the text next to cursor, on opposite side from drawing - DrawTextNextToCursor( aView, end, origin - end, cursorStrings ); + DrawTextNextToCursor( aView, end, origin - end, cursorStrings, aLayer == LAYER_GP_OVERLAY ); } \ No newline at end of file diff --git a/include/preview_items/arc_assistant.h b/include/preview_items/arc_assistant.h index c46016985b..e9e8f8e874 100644 --- a/include/preview_items/arc_assistant.h +++ b/include/preview_items/arc_assistant.h @@ -26,16 +26,14 @@ #include #include +#include namespace KIGFX { namespace PREVIEW { /** - * SELECTION_AREA - * - * Represents an assistant draw when interactively drawing an - * arc on a canvas. + * Represents an assistant draw when interactively drawing an arc on a canvas. */ class ARC_ASSISTANT : public EDA_ITEM { @@ -44,6 +42,13 @@ namespace PREVIEW const BOX2I ViewBBox() const override; + void ViewGetLayers( int aLayers[], int& aCount ) const override + { + aLayers[0] = LAYER_GP_OVERLAY; // Drop shadows + aLayers[1] = LAYER_SELECT_OVERLAY; // Assitant graphics + aCount = 2; + } + /** * Draw the assistance (with reference to the contstruction manager */ @@ -55,10 +60,6 @@ namespace PREVIEW } #endif - /** - * Get class name - * @return string "ARC_ASSISTANT" - */ wxString GetClass() const override { return "ARC_ASSISTANT"; diff --git a/include/preview_items/preview_utils.h b/include/preview_items/preview_utils.h index 0f9fe9e8d3..33ab6508cd 100644 --- a/include/preview_items/preview_utils.h +++ b/include/preview_items/preview_utils.h @@ -67,9 +67,9 @@ void SetConstantGlyphHeight( KIGFX::GAL& aGal, double aHeight ); * text in * @param aStrings list of strings to draw, top to bottom */ -void DrawTextNextToCursor( KIGFX::VIEW* aView, - const VECTOR2D& aCursorPos, const VECTOR2D& aTextQuadrant, - const std::vector& aStrings ); +void DrawTextNextToCursor( KIGFX::VIEW* aView, const VECTOR2D& aCursorPos, + const VECTOR2D& aTextQuadrant, const std::vector& aStrings, + bool aDrawingDropShadows ); } // PREVIEW } // KIGFX diff --git a/include/preview_items/two_point_assistant.h b/include/preview_items/two_point_assistant.h index 8505b35646..730ed7991f 100644 --- a/include/preview_items/two_point_assistant.h +++ b/include/preview_items/two_point_assistant.h @@ -26,6 +26,7 @@ #include #include +#include namespace KIGFX { @@ -44,10 +45,7 @@ namespace PREVIEW }; /** - * SELECTION_AREA - * - * Represents an assistant draw when interactively drawing an - * line or circle on a canvas. + * Represents an assistant draw when interactively drawing a line or circle on a canvas. */ class TWO_POINT_ASSISTANT : public EDA_ITEM { @@ -57,6 +55,13 @@ namespace PREVIEW const BOX2I ViewBBox() const override; + void ViewGetLayers( int aLayers[], int& aCount ) const override + { + aLayers[0] = LAYER_GP_OVERLAY; // Drop shadows + aLayers[1] = LAYER_SELECT_OVERLAY; // Assitant graphics + aCount = 2; + } + /** * Draw the assistance (with reference to the contstruction manager */