You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
6.9 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <preview_items/preview_utils.h>
  20. #include <gal/graphics_abstraction_layer.h>
  21. #include <base_units.h>
  22. #include <gal/painter.h>
  23. #include <view/view.h>
  24. #include <gal/hidpi_gl_canvas.h>
  25. double KIGFX::PREVIEW::PreviewOverlayDeemphAlpha( bool aDeemph )
  26. {
  27. return aDeemph ? 0.5 : 1.0;
  28. }
  29. wxString KIGFX::PREVIEW::DimensionLabel( const wxString& prefix, double aVal,
  30. const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  31. bool aIncludeUnits )
  32. {
  33. wxString str;
  34. if( prefix.size() )
  35. str << prefix << ": ";
  36. wxString fmtStr;
  37. // show a sane precision for the preview, which doesn't need to be accurate down to the
  38. // nanometre
  39. switch( aUnits )
  40. {
  41. case EDA_UNITS::UM: fmtStr = wxT( "%.0f" ); break; // 1um
  42. case EDA_UNITS::MM: fmtStr = wxT( "%.3f" ); break; // 1um
  43. case EDA_UNITS::CM: fmtStr = wxT( "%.4f" ); break; // 1um
  44. case EDA_UNITS::MILS: fmtStr = wxT( "%.1f" ); break; // 0.1mil
  45. case EDA_UNITS::INCH: fmtStr = wxT( "%.4f" ); break; // 0.1mil
  46. case EDA_UNITS::DEGREES: fmtStr = wxT( "%.1f" ); break; // 0.1deg
  47. case EDA_UNITS::PERCENT: fmtStr = wxT( "%.1f" ); break; // 0.1%
  48. case EDA_UNITS::FS: fmtStr = wxT( "%.4f" ); break; // 0.0001ps
  49. case EDA_UNITS::PS: fmtStr = wxT( "%.3f" ); break; // 0.001ps
  50. case EDA_UNITS::PS_PER_INCH: fmtStr = wxT( "%.3f" ); break; // 0.001ps/in
  51. case EDA_UNITS::PS_PER_CM: fmtStr = wxT( "%.3f" ); break; // 0.001ps/cm
  52. case EDA_UNITS::PS_PER_MM: fmtStr = wxT( "%.3f" ); break; // 0.001ps/mm
  53. case EDA_UNITS::UNSCALED: fmtStr = wxT( "%f" ); break;
  54. }
  55. str << wxString::Format( fmtStr, EDA_UNIT_UTILS::UI::ToUserUnit( aIuScale, aUnits, aVal ) );
  56. if( aIncludeUnits )
  57. str << EDA_UNIT_UTILS::GetText( aUnits );
  58. return str;
  59. }
  60. KIGFX::PREVIEW::TEXT_DIMS KIGFX::PREVIEW::GetConstantGlyphHeight( KIGFX::GAL* aGal,
  61. int aRelativeSize )
  62. {
  63. constexpr double aspectRatio = 1.0;
  64. constexpr double hdpiSizes[] = { 7, 8, 9, 11, 13, 14, 16 };
  65. constexpr double sizes[] = { 8, 10, 12, 14, 15, 16, 18 };
  66. double height;
  67. double thicknessFactor;
  68. double shadowFactor;
  69. double linePitchFactor;
  70. HIDPI_GL_CANVAS* canvas = dynamic_cast<HIDPI_GL_CANVAS*>( aGal );
  71. if( canvas && canvas->GetScaleFactor() > 1 )
  72. {
  73. height = hdpiSizes[ 3 + aRelativeSize ];
  74. thicknessFactor = 0.15;
  75. shadowFactor = 0.10;
  76. linePitchFactor = 1.7;
  77. }
  78. else
  79. {
  80. height = sizes[ 3 + aRelativeSize ];
  81. thicknessFactor = 0.20;
  82. shadowFactor = 0.15;
  83. linePitchFactor = 1.9;
  84. }
  85. height /= aGal->GetWorldScale();
  86. TEXT_DIMS textDims;
  87. textDims.GlyphSize = VECTOR2I( height * aspectRatio, height );
  88. textDims.StrokeWidth = height * thicknessFactor;
  89. textDims.ShadowWidth = height * shadowFactor;
  90. textDims.LinePitch = height * linePitchFactor;
  91. return textDims;
  92. }
  93. KIGFX::COLOR4D KIGFX::PREVIEW::GetShadowColor( const KIGFX::COLOR4D& aColor )
  94. {
  95. if( aColor.GetBrightness() > 0.5 )
  96. return COLOR4D::BLACK;
  97. else
  98. return COLOR4D::WHITE;
  99. }
  100. void KIGFX::PREVIEW::DrawTextNextToCursor( KIGFX::VIEW* aView, const VECTOR2D& aCursorPos,
  101. const VECTOR2D& aTextQuadrant,
  102. const wxArrayString& aStrings,
  103. bool aDrawingDropShadows )
  104. {
  105. KIGFX::GAL* gal = aView->GetGAL();
  106. GAL_SCOPED_ATTRS settings( *gal, GAL_SCOPED_ATTRS::STROKE_FILL );
  107. KIFONT::FONT* font = KIFONT::FONT::GetFont();
  108. // constant text size on screen
  109. TEXT_DIMS textDims = GetConstantGlyphHeight( gal );
  110. TEXT_ATTRIBUTES textAttrs;
  111. // radius string goes on the right of the cursor centre line with a small horizontal
  112. // offset (enough to keep clear of a system cursor if present)
  113. VECTOR2D textPos = aCursorPos;
  114. bool viewFlipped = gal->IsFlippedX();
  115. // if the text goes above the cursor, shift it up
  116. if( aTextQuadrant.y > 0 )
  117. textPos.y -= textDims.LinePitch * ( aStrings.size() + 1 );
  118. if( aTextQuadrant.x < 0 )
  119. {
  120. if( viewFlipped )
  121. textAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
  122. else
  123. textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
  124. textPos.x += 15.0 / gal->GetWorldScale();
  125. }
  126. else
  127. {
  128. if( viewFlipped )
  129. textAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
  130. else
  131. textAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
  132. textPos.x -= 15.0 / gal->GetWorldScale();
  133. }
  134. // text is left (or right) aligned, so a shadow text need a small offset to be draw
  135. // around the basic text
  136. int shadowXoffset = aDrawingDropShadows ? textDims.ShadowWidth : 0;
  137. // Due to the fact a shadow text is drawn left or right aligned,
  138. // it needs an offset = shadowWidth/2 to be drawn at the same place as normal text
  139. // But for some reason we need to slightly modify this offset
  140. // for a better look for KiCad font (better alignment of shadow shape)
  141. const float adjust = 1.2f; // Value chosen after tests
  142. shadowXoffset *= adjust;
  143. if( ( textAttrs.m_Halign == GR_TEXT_H_ALIGN_LEFT ) != viewFlipped )
  144. textPos.x -= shadowXoffset;
  145. else
  146. textPos.x += shadowXoffset;
  147. gal->SetStrokeColor( aView->GetPainter()->GetSettings()->GetLayerColor( LAYER_AUX_ITEMS ) );
  148. textAttrs.m_Mirrored = viewFlipped; // Prevent text flipping when view is flipped
  149. textAttrs.m_Size = textDims.GlyphSize;
  150. textAttrs.m_StrokeWidth = textDims.StrokeWidth;
  151. gal->SetIsFill( false );
  152. gal->SetIsStroke( true );
  153. if( aDrawingDropShadows )
  154. {
  155. textAttrs.m_StrokeWidth = textDims.StrokeWidth + ( 2 * textDims.ShadowWidth );
  156. gal->SetStrokeColor( GetShadowColor( gal->GetStrokeColor() ) );
  157. }
  158. // write strings top-to-bottom
  159. for( const wxString& str : aStrings )
  160. {
  161. textPos.y += textDims.LinePitch;
  162. font->Draw( gal, str, textPos, textAttrs, KIFONT::METRICS::Default() );
  163. }
  164. }