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.

461 lines
12 KiB

10 years ago
Introduction of Graphics Abstraction Layer based rendering for pcbnew. New classes: - VIEW - represents view that is seen by user, takes care of layer ordering & visibility and how it is displayed (which location, how much zoomed, etc.) - VIEW_ITEM - Base class for every item that can be displayed on VIEW (the biggest change is that now it may be necessary to override ViewBBox & ViewGetLayers method for derived classes). - EDA_DRAW_PANEL_GAL - Inherits after EDA_DRAW_PANEL, displays VIEW output, right now it is not editable (in opposite to usual EDA_DRAW_PANEL). - GAL/OPENGL_GAL/CAIRO_GAL - Base Graphics Abstraction Layer class + two different flavours (Cairo is not fully supported yet), that offers methods to draw primitives using different libraries. - WX_VIEW_CONTROLS - Controller for VIEW, handles user events, allows zooming, panning, etc. - PAINTER/PCB_PAINTER - Classes that uses GAL interface to draw items (as you may have already guessed - PCB_PAINTER is a class for drawing PCB specific object, PAINTER is an abstract class). Its methods are invoked by VIEW, when an item has to be drawn. To display a new type of item - you need to implement draw(ITEM_TYPE*) method that draws it using GAL methods. - STROKE_FONT - Implements stroke font drawing using GAL methods. Most important changes to Kicad original code: * EDA_ITEM now inherits from VIEW_ITEM, which is a base class for all drawable objects. * EDA_DRAW_FRAME contains both usual EDA_DRAW_PANEL and new EDA_DRAW_PANEL_GAL, that can be switched anytime. * There are some new layers for displaying multilayer pads, vias & pads holes (these are not shown yet on the right sidebar in pcbnew) * Display order of layers is different than in previous versions (if you are curious - you may check m_galLayerOrder@pcbnew/basepcbframe.cpp). Preserving usual order would result in not very natural display, such as showing silkscreen texts on the bottom. * Introduced new hotkey (Alt+F12) and new menu option (View->Switch canvas) for switching canvas during runtime. * Some of classes (mostly derived from BOARD_ITEM) now includes ViewBBox & ViewGetLayers methods. * Removed tools/class_painter.h, as now it is extended and included in source code. Build changes: * GAL-based rendering option is turned on by a new compilation CMake option KICAD_GAL. * When compiling with CMake option KICAD_GAL=ON, GLEW and Cairo libraries are required. * GAL-related code is compiled into a static library (common/libgal). * Build with KICAD_GAL=OFF should not need any new libraries and should come out as a standard version of Kicad Currently most of items in pcbnew can be displayed using OpenGL (to be done are DIMENSIONS and MARKERS). More details about GAL can be found in: http://www.ohwr.org/attachments/1884/view-spec.pdf
13 years ago
Introduction of Graphics Abstraction Layer based rendering for pcbnew. New classes: - VIEW - represents view that is seen by user, takes care of layer ordering & visibility and how it is displayed (which location, how much zoomed, etc.) - VIEW_ITEM - Base class for every item that can be displayed on VIEW (the biggest change is that now it may be necessary to override ViewBBox & ViewGetLayers method for derived classes). - EDA_DRAW_PANEL_GAL - Inherits after EDA_DRAW_PANEL, displays VIEW output, right now it is not editable (in opposite to usual EDA_DRAW_PANEL). - GAL/OPENGL_GAL/CAIRO_GAL - Base Graphics Abstraction Layer class + two different flavours (Cairo is not fully supported yet), that offers methods to draw primitives using different libraries. - WX_VIEW_CONTROLS - Controller for VIEW, handles user events, allows zooming, panning, etc. - PAINTER/PCB_PAINTER - Classes that uses GAL interface to draw items (as you may have already guessed - PCB_PAINTER is a class for drawing PCB specific object, PAINTER is an abstract class). Its methods are invoked by VIEW, when an item has to be drawn. To display a new type of item - you need to implement draw(ITEM_TYPE*) method that draws it using GAL methods. - STROKE_FONT - Implements stroke font drawing using GAL methods. Most important changes to Kicad original code: * EDA_ITEM now inherits from VIEW_ITEM, which is a base class for all drawable objects. * EDA_DRAW_FRAME contains both usual EDA_DRAW_PANEL and new EDA_DRAW_PANEL_GAL, that can be switched anytime. * There are some new layers for displaying multilayer pads, vias & pads holes (these are not shown yet on the right sidebar in pcbnew) * Display order of layers is different than in previous versions (if you are curious - you may check m_galLayerOrder@pcbnew/basepcbframe.cpp). Preserving usual order would result in not very natural display, such as showing silkscreen texts on the bottom. * Introduced new hotkey (Alt+F12) and new menu option (View->Switch canvas) for switching canvas during runtime. * Some of classes (mostly derived from BOARD_ITEM) now includes ViewBBox & ViewGetLayers methods. * Removed tools/class_painter.h, as now it is extended and included in source code. Build changes: * GAL-based rendering option is turned on by a new compilation CMake option KICAD_GAL. * When compiling with CMake option KICAD_GAL=ON, GLEW and Cairo libraries are required. * GAL-related code is compiled into a static library (common/libgal). * Build with KICAD_GAL=OFF should not need any new libraries and should come out as a standard version of Kicad Currently most of items in pcbnew can be displayed using OpenGL (to be done are DIMENSIONS and MARKERS). More details about GAL can be found in: http://www.ohwr.org/attachments/1884/view-spec.pdf
13 years ago
Introduction of Graphics Abstraction Layer based rendering for pcbnew. New classes: - VIEW - represents view that is seen by user, takes care of layer ordering & visibility and how it is displayed (which location, how much zoomed, etc.) - VIEW_ITEM - Base class for every item that can be displayed on VIEW (the biggest change is that now it may be necessary to override ViewBBox & ViewGetLayers method for derived classes). - EDA_DRAW_PANEL_GAL - Inherits after EDA_DRAW_PANEL, displays VIEW output, right now it is not editable (in opposite to usual EDA_DRAW_PANEL). - GAL/OPENGL_GAL/CAIRO_GAL - Base Graphics Abstraction Layer class + two different flavours (Cairo is not fully supported yet), that offers methods to draw primitives using different libraries. - WX_VIEW_CONTROLS - Controller for VIEW, handles user events, allows zooming, panning, etc. - PAINTER/PCB_PAINTER - Classes that uses GAL interface to draw items (as you may have already guessed - PCB_PAINTER is a class for drawing PCB specific object, PAINTER is an abstract class). Its methods are invoked by VIEW, when an item has to be drawn. To display a new type of item - you need to implement draw(ITEM_TYPE*) method that draws it using GAL methods. - STROKE_FONT - Implements stroke font drawing using GAL methods. Most important changes to Kicad original code: * EDA_ITEM now inherits from VIEW_ITEM, which is a base class for all drawable objects. * EDA_DRAW_FRAME contains both usual EDA_DRAW_PANEL and new EDA_DRAW_PANEL_GAL, that can be switched anytime. * There are some new layers for displaying multilayer pads, vias & pads holes (these are not shown yet on the right sidebar in pcbnew) * Display order of layers is different than in previous versions (if you are curious - you may check m_galLayerOrder@pcbnew/basepcbframe.cpp). Preserving usual order would result in not very natural display, such as showing silkscreen texts on the bottom. * Introduced new hotkey (Alt+F12) and new menu option (View->Switch canvas) for switching canvas during runtime. * Some of classes (mostly derived from BOARD_ITEM) now includes ViewBBox & ViewGetLayers methods. * Removed tools/class_painter.h, as now it is extended and included in source code. Build changes: * GAL-based rendering option is turned on by a new compilation CMake option KICAD_GAL. * When compiling with CMake option KICAD_GAL=ON, GLEW and Cairo libraries are required. * GAL-related code is compiled into a static library (common/libgal). * Build with KICAD_GAL=OFF should not need any new libraries and should come out as a standard version of Kicad Currently most of items in pcbnew can be displayed using OpenGL (to be done are DIMENSIONS and MARKERS). More details about GAL can be found in: http://www.ohwr.org/attachments/1884/view-spec.pdf
13 years ago
5 years ago
5 years ago
5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <pcb_edit_frame.h>
  26. #include <base_units.h>
  27. #include <bitmaps.h>
  28. #include <board.h>
  29. #include <core/mirror.h>
  30. #include <footprint.h>
  31. #include <settings/settings_manager.h>
  32. #include <trigo.h>
  33. FP_TEXT::FP_TEXT( FOOTPRINT* aParentFootprint, TEXT_TYPE text_type ) :
  34. BOARD_ITEM( aParentFootprint, PCB_FP_TEXT_T ),
  35. EDA_TEXT()
  36. {
  37. FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
  38. m_Type = text_type;
  39. m_keepUpright = true;
  40. // Set text thickness to a default value
  41. SetTextThickness( Millimeter2iu( DEFAULT_TEXT_WIDTH ) );
  42. SetLayer( F_SilkS );
  43. // Set position and give a default layer if a valid parent footprint exists
  44. if( parentFootprint && parentFootprint->Type() == PCB_FOOTPRINT_T )
  45. {
  46. SetTextPos( parentFootprint->GetPosition() );
  47. if( IsBackLayer( parentFootprint->GetLayer() ) )
  48. {
  49. SetLayer( B_SilkS );
  50. SetMirrored( true );
  51. }
  52. }
  53. SetDrawCoord();
  54. }
  55. FP_TEXT::~FP_TEXT()
  56. {
  57. }
  58. void FP_TEXT::SetTextAngle( double aAngle )
  59. {
  60. EDA_TEXT::SetTextAngle( NormalizeAngle360Min( aAngle ) );
  61. }
  62. bool FP_TEXT::TextHitTest( const wxPoint& aPoint, int aAccuracy ) const
  63. {
  64. EDA_RECT rect = GetTextBox();
  65. wxPoint location = aPoint;
  66. rect.Inflate( aAccuracy );
  67. RotatePoint( &location, GetTextPos(), -GetDrawRotation() );
  68. return rect.Contains( location );
  69. }
  70. bool FP_TEXT::TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy ) const
  71. {
  72. EDA_RECT rect = aRect;
  73. rect.Inflate( aAccuracy );
  74. if( aContains )
  75. return rect.Contains( GetBoundingBox() );
  76. else
  77. return rect.Intersects( GetTextBox(), GetDrawRotation() );
  78. }
  79. void FP_TEXT::KeepUpright( double aOldOrientation, double aNewOrientation )
  80. {
  81. if( !IsKeepUpright() )
  82. return;
  83. double currentAngle = GetTextAngle() + aOldOrientation;
  84. double newAngle = GetTextAngle() + aNewOrientation;
  85. NORMALIZE_ANGLE_POS( currentAngle );
  86. NORMALIZE_ANGLE_POS( newAngle );
  87. bool isFlipped = currentAngle >= 1800.0;
  88. bool needsFlipped = newAngle >= 1800.0;
  89. if( isFlipped != needsFlipped )
  90. {
  91. if( GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
  92. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  93. else if( GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
  94. SetHorizJustify(GR_TEXT_HJUSTIFY_LEFT );
  95. SetTextAngle( GetTextAngle() + 1800.0 );
  96. SetDrawCoord();
  97. }
  98. }
  99. void FP_TEXT::Rotate( const wxPoint& aRotCentre, double aAngle )
  100. {
  101. // Used in footprint editing
  102. // Note also in footprint editor, m_Pos0 = m_Pos
  103. wxPoint pt = GetTextPos();
  104. RotatePoint( &pt, aRotCentre, aAngle );
  105. SetTextPos( pt );
  106. SetTextAngle( GetTextAngle() + aAngle );
  107. SetLocalCoord();
  108. }
  109. void FP_TEXT::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
  110. {
  111. // flipping the footprint is relative to the X axis
  112. if( aFlipLeftRight )
  113. SetTextX( ::MIRRORVAL( GetTextPos().x, aCentre.x ) );
  114. else
  115. SetTextY( ::MIRRORVAL( GetTextPos().y, aCentre.y ) );
  116. SetTextAngle( -GetTextAngle() );
  117. SetLayer( FlipLayer( GetLayer() ) );
  118. SetMirrored( IsBackLayer( GetLayer() ) );
  119. SetLocalCoord();
  120. // adjust justified text for mirroring
  121. if( GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT || GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
  122. {
  123. SetHorizJustify( static_cast<EDA_TEXT_HJUSTIFY_T>( -GetHorizJustify() ) );
  124. SetDrawCoord();
  125. }
  126. }
  127. bool FP_TEXT::IsParentFlipped() const
  128. {
  129. if( GetParent() && GetParent()->GetLayer() == B_Cu )
  130. return true;
  131. return false;
  132. }
  133. void FP_TEXT::Mirror( const wxPoint& aCentre, bool aMirrorAroundXAxis )
  134. {
  135. // the position is mirrored, but the text itself is not mirrored
  136. if( aMirrorAroundXAxis )
  137. SetTextY( ::MIRRORVAL( GetTextPos().y, aCentre.y ) );
  138. else
  139. SetTextX( ::MIRRORVAL( GetTextPos().x, aCentre.x ) );
  140. SetLocalCoord();
  141. }
  142. void FP_TEXT::Move( const wxPoint& aMoveVector )
  143. {
  144. Offset( aMoveVector );
  145. SetLocalCoord();
  146. }
  147. int FP_TEXT::GetLength() const
  148. {
  149. return GetText().Len();
  150. }
  151. void FP_TEXT::SetDrawCoord()
  152. {
  153. const FOOTPRINT* parentFootprint = static_cast<const FOOTPRINT*>( m_parent );
  154. SetTextPos( m_Pos0 );
  155. if( parentFootprint )
  156. {
  157. double angle = parentFootprint->GetOrientation();
  158. wxPoint pt = GetTextPos();
  159. RotatePoint( &pt, angle );
  160. SetTextPos( pt );
  161. Offset( parentFootprint->GetPosition() );
  162. }
  163. }
  164. void FP_TEXT::SetLocalCoord()
  165. {
  166. const FOOTPRINT* parentFootprint = static_cast<const FOOTPRINT*>( m_parent );
  167. if( parentFootprint )
  168. {
  169. m_Pos0 = GetTextPos() - parentFootprint->GetPosition();
  170. double angle = parentFootprint->GetOrientation();
  171. RotatePoint( &m_Pos0.x, &m_Pos0.y, -angle );
  172. }
  173. else
  174. {
  175. m_Pos0 = GetTextPos();
  176. }
  177. }
  178. const EDA_RECT FP_TEXT::GetBoundingBox() const
  179. {
  180. double angle = GetDrawRotation();
  181. EDA_RECT text_area = GetTextBox();
  182. if( angle )
  183. text_area = text_area.GetBoundingBoxRotated( GetTextPos(), angle );
  184. return text_area;
  185. }
  186. double FP_TEXT::GetDrawRotation() const
  187. {
  188. FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( m_parent );
  189. double rotation = GetTextAngle();
  190. if( parentFootprint )
  191. rotation += parentFootprint->GetOrientation();
  192. if( m_keepUpright )
  193. {
  194. // Keep angle between 0 .. 90 deg. Otherwise the text is not easy to read
  195. while( rotation > 900 )
  196. rotation -= 1800;
  197. while( rotation < 0 )
  198. rotation += 1800;
  199. }
  200. else
  201. {
  202. NORMALIZE_ANGLE_POS( rotation );
  203. }
  204. return rotation;
  205. }
  206. void FP_TEXT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  207. {
  208. FOOTPRINT* fp = static_cast<FOOTPRINT*>( m_parent );
  209. wxString msg;
  210. static const wxString text_type_msg[3] =
  211. {
  212. _( "Ref." ), _( "Value" ), _( "Text" )
  213. };
  214. aList.emplace_back( _( "Footprint" ), fp ? fp->GetReference() : _( "<invalid>" ) );
  215. aList.emplace_back( _( "Text" ), GetShownText() );
  216. wxASSERT( m_Type >= TEXT_is_REFERENCE && m_Type <= TEXT_is_DIVERS );
  217. aList.emplace_back( _( "Type" ), text_type_msg[m_Type] );
  218. if( IsLocked() )
  219. aList.emplace_back( _( "Status" ), _( "locked" ) );
  220. aList.emplace_back( _( "Display" ), IsVisible() ? _( "Yes" ) : _( "No" ) );
  221. // Display text layer
  222. aList.emplace_back( _( "Layer" ), GetLayerName() );
  223. aList.emplace_back( _( "Mirror" ), IsMirrored() ? _( "Yes" ) : _( "No" ) );
  224. msg.Printf( wxT( "%g" ), GetTextAngleDegrees() );
  225. aList.emplace_back( _( "Angle" ), msg );
  226. msg = MessageTextFromValue( aFrame->GetUserUnits(), GetTextThickness() );
  227. aList.emplace_back( _( "Thickness" ), msg );
  228. msg = MessageTextFromValue( aFrame->GetUserUnits(), GetTextWidth() );
  229. aList.emplace_back( _( "Width" ), msg );
  230. msg = MessageTextFromValue( aFrame->GetUserUnits(), GetTextHeight() );
  231. aList.emplace_back( _( "Height" ), msg );
  232. }
  233. wxString FP_TEXT::GetSelectMenuText( EDA_UNITS aUnits ) const
  234. {
  235. switch( m_Type )
  236. {
  237. case TEXT_is_REFERENCE:
  238. return wxString::Format( _( "Reference '%s'" ),
  239. static_cast<FOOTPRINT*>( GetParent() )->GetReference() );
  240. case TEXT_is_VALUE:
  241. return wxString::Format( _( "Value '%s' of %s" ),
  242. GetShownText(),
  243. static_cast<FOOTPRINT*>( GetParent() )->GetReference() );
  244. default:
  245. return wxString::Format( _( "Footprint Text '%s' of %s" ),
  246. ShortenedShownText(),
  247. static_cast<FOOTPRINT*>( GetParent() )->GetReference() );
  248. }
  249. }
  250. BITMAP_DEF FP_TEXT::GetMenuImage() const
  251. {
  252. return text_xpm;
  253. }
  254. EDA_ITEM* FP_TEXT::Clone() const
  255. {
  256. return new FP_TEXT( *this );
  257. }
  258. const BOX2I FP_TEXT::ViewBBox() const
  259. {
  260. double angle = GetDrawRotation();
  261. EDA_RECT text_area = GetTextBox();
  262. if( angle != 0.0 )
  263. text_area = text_area.GetBoundingBoxRotated( GetTextPos(), angle );
  264. return BOX2I( text_area.GetPosition(), text_area.GetSize() );
  265. }
  266. void FP_TEXT::ViewGetLayers( int aLayers[], int& aCount ) const
  267. {
  268. if( IsVisible() )
  269. aLayers[0] = GetLayer();
  270. else
  271. aLayers[0] = LAYER_MOD_TEXT_INVISIBLE;
  272. aCount = 1;
  273. }
  274. double FP_TEXT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
  275. {
  276. constexpr double HIDE = (double)std::numeric_limits<double>::max();
  277. if( !aView )
  278. return 0.0;
  279. // Hidden text gets put on the LAYER_MOD_TEXT_INVISIBLE for rendering, but
  280. // should only render if its native layer is visible.
  281. if( !aView->IsLayerVisible( GetLayer() ) )
  282. return HIDE;
  283. // Handle Render tab switches
  284. if( ( m_Type == TEXT_is_VALUE || GetText() == wxT( "${VALUE}" ) )
  285. && !aView->IsLayerVisible( LAYER_MOD_VALUES ) )
  286. return HIDE;
  287. if( ( m_Type == TEXT_is_REFERENCE || GetText() == wxT( "${REFERENCE}" ) )
  288. && !aView->IsLayerVisible( LAYER_MOD_REFERENCES ) )
  289. return HIDE;
  290. if( !IsParentFlipped() && !aView->IsLayerVisible( LAYER_MOD_FR ) )
  291. return HIDE;
  292. if( IsParentFlipped() && !aView->IsLayerVisible( LAYER_MOD_BK ) )
  293. return HIDE;
  294. if( IsFrontLayer( m_layer ) && !aView->IsLayerVisible( LAYER_MOD_TEXT_FR ) )
  295. return HIDE;
  296. if( IsBackLayer( m_layer ) && !aView->IsLayerVisible( LAYER_MOD_TEXT_BK ) )
  297. return HIDE;
  298. // Other layers are shown without any conditions
  299. return 0.0;
  300. }
  301. wxString FP_TEXT::GetShownText( int aDepth ) const
  302. {
  303. const FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( GetParent() );
  304. wxASSERT( parentFootprint );
  305. const BOARD* board = parentFootprint->GetBoard();
  306. std::function<bool( wxString* )> footprintResolver =
  307. [&]( wxString* token ) -> bool
  308. {
  309. return parentFootprint && parentFootprint->ResolveTextVar( token, aDepth );
  310. };
  311. std::function<bool( wxString* )> boardTextResolver =
  312. [&]( wxString* token ) -> bool
  313. {
  314. return board->ResolveTextVar( token, aDepth + 1 );
  315. };
  316. bool processTextVars = false;
  317. wxString text = EDA_TEXT::GetShownText( &processTextVars );
  318. if( processTextVars )
  319. {
  320. PROJECT* project = nullptr;
  321. if( parentFootprint && parentFootprint->GetParent() )
  322. project = static_cast<BOARD*>( parentFootprint->GetParent() )->GetProject();
  323. if( aDepth < 10 )
  324. text = ExpandTextVars( text, &footprintResolver, &boardTextResolver, project );
  325. }
  326. return text;
  327. }
  328. std::shared_ptr<SHAPE> FP_TEXT::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
  329. {
  330. return GetEffectiveTextShape();
  331. }
  332. static struct FP_TEXT_DESC
  333. {
  334. FP_TEXT_DESC()
  335. {
  336. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  337. REGISTER_TYPE( FP_TEXT );
  338. propMgr.AddTypeCast( new TYPE_CAST<FP_TEXT, BOARD_ITEM> );
  339. propMgr.AddTypeCast( new TYPE_CAST<FP_TEXT, EDA_TEXT> );
  340. propMgr.InheritsAfter( TYPE_HASH( FP_TEXT ), TYPE_HASH( BOARD_ITEM ) );
  341. propMgr.InheritsAfter( TYPE_HASH( FP_TEXT ), TYPE_HASH( EDA_TEXT ) );
  342. }
  343. } _FP_TEXT_DESC;