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.

239 lines
7.7 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 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 "symbol_preview_widget.h"
  20. #include <wx/stattext.h>
  21. #include <wx/sizer.h>
  22. #include <kiway.h>
  23. #include <sch_view.h>
  24. #include <gal/gal_display_options.h>
  25. #include <class_libentry.h>
  26. #include <symbol_lib_table.h>
  27. #include <sch_preview_panel.h>
  28. #include <pgm_base.h>
  29. #include <sch_painter.h>
  30. #include <draw_frame.h>
  31. SYMBOL_PREVIEW_WIDGET::SYMBOL_PREVIEW_WIDGET( wxWindow* aParent, KIWAY& aKiway,
  32. EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType ) :
  33. wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ),
  34. m_kiway( aKiway ),
  35. m_preview( nullptr ), m_status( nullptr ), m_statusSizer( nullptr ), m_previewItem( nullptr )
  36. {
  37. wxString eeschemaFrameKey( SCH_EDIT_FRAME_NAME );
  38. std::unique_ptr<wxConfigBase> eeschemaConfig = GetNewConfig( Pgm().App().GetAppName() );
  39. wxConfigBase& commonConfig = *Pgm().CommonSettings();
  40. m_galDisplayOptions.ReadConfig( commonConfig, *eeschemaConfig, eeschemaFrameKey, this );
  41. EDA_DRAW_PANEL_GAL::GAL_TYPE canvasType = aCanvasType;
  42. // Allows only a CAIRO or OPENGL canvas:
  43. if( canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL &&
  44. canvasType != EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO )
  45. canvasType = EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL;
  46. m_preview = new SCH_PREVIEW_PANEL( aParent, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ),
  47. m_galDisplayOptions, canvasType );
  48. m_preview->SetStealsFocus( false );
  49. // Do not display the grid: the look is not good for a small canvas area.
  50. // But mainly, due to some strange bug I (JPC) was unable to fix, the grid creates
  51. // strange artifacts on Windows when eeschema is run from Kicad manager (but not in stand alone...).
  52. m_preview->GetGAL()->SetGridVisibility( false );
  53. // Early initialization of the canvas background color,
  54. // before any OnPaint event is fired for the canvas using a wrong bg color
  55. KIGFX::VIEW* view = m_preview->GetView();
  56. auto settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
  57. m_preview->GetGAL()->SetClearColor( settings->GetBackgroundColor() );
  58. SetBackgroundColour( *wxWHITE );
  59. SetForegroundColour( *wxBLACK );
  60. m_status = new wxStaticText( this, wxID_ANY, wxEmptyString );
  61. m_statusSizer = new wxBoxSizer( wxVERTICAL );
  62. m_statusSizer->Add( 0, 0, 1 ); // add a spacer
  63. m_statusSizer->Add( m_status, 0, wxALIGN_CENTER );
  64. m_statusSizer->Add( 0, 0, 1 ); // add a spacer
  65. auto outer_sizer = new wxBoxSizer( wxVERTICAL );
  66. outer_sizer->Add( m_preview, 1, wxTOP | wxEXPAND, 5 );
  67. outer_sizer->Add( m_statusSizer, 1, wxALIGN_CENTER );
  68. m_statusSizer->ShowItems( false );
  69. SetSizer( outer_sizer );
  70. Connect( wxEVT_SIZE, wxSizeEventHandler( SYMBOL_PREVIEW_WIDGET::onSize ), NULL, this );
  71. }
  72. SYMBOL_PREVIEW_WIDGET::~SYMBOL_PREVIEW_WIDGET()
  73. {
  74. if( m_previewItem )
  75. m_preview->GetView()->Remove( m_previewItem );
  76. delete m_previewItem;
  77. }
  78. void SYMBOL_PREVIEW_WIDGET::SetStatusText( wxString const& aText )
  79. {
  80. m_status->SetLabel( aText );
  81. m_statusSizer->ShowItems( true );
  82. m_preview->Hide();
  83. Layout();
  84. }
  85. void SYMBOL_PREVIEW_WIDGET::onSize( wxSizeEvent& aEvent )
  86. {
  87. if( m_previewItem )
  88. {
  89. fitOnDrawArea();
  90. m_preview->ForceRefresh();
  91. }
  92. aEvent.Skip();
  93. }
  94. void SYMBOL_PREVIEW_WIDGET::fitOnDrawArea()
  95. {
  96. if( !m_previewItem )
  97. return;
  98. // set the view scale to fit the item on screen
  99. KIGFX::VIEW* view = m_preview->GetView();
  100. // Calculate the drawing area size, in internal units, for a scaling factor = 1.0
  101. view->SetScale( 1.0 );
  102. VECTOR2D clientSize = view->ToWorld( m_preview->GetClientSize(), false );
  103. // Calculate the draw scale to fit the drawing area
  104. double scale = std::min( fabs( clientSize.x / m_itemBBox.GetWidth() ),
  105. fabs( clientSize.y / m_itemBBox.GetHeight() ) );
  106. // Above calculation will yield an exact fit; add a bit of whitespace around symbol
  107. scale /= 1.2;
  108. // Now fix the best scale
  109. view->SetScale( scale );
  110. view->SetCenter( m_itemBBox.Centre() );
  111. }
  112. void SYMBOL_PREVIEW_WIDGET::DisplaySymbol( const LIB_ID& aSymbolID, int aUnit )
  113. {
  114. KIGFX::VIEW* view = m_preview->GetView();
  115. auto settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
  116. LIB_ALIAS* alias = nullptr;
  117. try
  118. {
  119. alias = m_kiway.Prj().SchSymbolLibTable()->LoadSymbol( aSymbolID );
  120. }
  121. catch( const IO_ERROR& ioe )
  122. {
  123. wxLogError( wxString::Format( _( "Error loading symbol %s from library %s.\n\n%s" ),
  124. aSymbolID.GetLibItemName().wx_str(),
  125. aSymbolID.GetLibNickname().wx_str(),
  126. ioe.What() ) );
  127. }
  128. if( m_previewItem )
  129. {
  130. view->Remove( m_previewItem );
  131. delete m_previewItem;
  132. m_previewItem = nullptr;
  133. }
  134. if( alias )
  135. {
  136. LIB_PART* part = alias->GetPart();
  137. // If unit isn't specified for a multi-unit part, pick the first. (Otherwise we'll
  138. // draw all of them.)
  139. if( part->IsMulti() && aUnit == 0 )
  140. aUnit = 1;
  141. settings->m_ShowUnit = aUnit;
  142. // For symbols having a De Morgan body style, use the first style
  143. settings->m_ShowConvert = part->HasConversion() ? 1 : 0;
  144. m_previewItem = new LIB_ALIAS( *alias, part );
  145. view->Add( m_previewItem );
  146. // Get the symbole size, in internal units
  147. m_itemBBox = part->GetUnitBoundingBox( aUnit, 0 );
  148. if( !m_preview->IsShown() )
  149. {
  150. m_preview->Show();
  151. m_statusSizer->ShowItems( false );
  152. Layout(); // Ensure panel size is up to date.
  153. }
  154. // Calculate the draw scale to fit the drawing area
  155. fitOnDrawArea();
  156. }
  157. m_preview->ForceRefresh();
  158. }
  159. void SYMBOL_PREVIEW_WIDGET::DisplayPart( LIB_PART* aPart, int aUnit )
  160. {
  161. KIGFX::VIEW* view = m_preview->GetView();
  162. if( m_previewItem )
  163. {
  164. view->Remove( m_previewItem );
  165. delete m_previewItem;
  166. m_previewItem = nullptr;
  167. }
  168. if( aPart )
  169. {
  170. // If unit isn't specified for a multi-unit part, pick the first. (Otherwise we'll
  171. // draw all of them.)
  172. if( aPart->IsMulti() && aUnit == 0 )
  173. aUnit = 1;
  174. // For symbols having a De Morgan body style, use the first style
  175. auto settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( view->GetPainter()->GetSettings() );
  176. settings->m_ShowConvert = aPart->HasConversion() ? 1 : 0;
  177. m_previewItem = new LIB_PART( *aPart );
  178. view->Add( m_previewItem );
  179. // Get the symbole size, in internal units
  180. m_itemBBox = aPart->GetUnitBoundingBox( aUnit, 0 );
  181. // Calculate the draw scale to fit the drawing area
  182. fitOnDrawArea();
  183. }
  184. m_preview->ForceRefresh();
  185. m_preview->Show();
  186. m_statusSizer->ShowItems( false );
  187. }