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.

332 lines
11 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014 CERN
  5. * Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
  6. * @author Maciej Suminski <maciej.suminski@cern.ch>
  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 <kiface_base.h>
  26. #include <kiplatform/ui.h>
  27. #include <pcb_base_edit_frame.h>
  28. #include <tool/tool_manager.h>
  29. #include <tools/pcb_actions.h>
  30. #include <tools/pcb_selection_tool.h>
  31. #include <pgm_base.h>
  32. #include <board.h>
  33. #include <board_design_settings.h>
  34. #include <pcb_dimension.h>
  35. #include <footprint_info_impl.h>
  36. #include <project.h>
  37. #include <settings/color_settings.h>
  38. #include <settings/settings_manager.h>
  39. #include <widgets/appearance_controls.h>
  40. #include <widgets/pcb_properties_panel.h>
  41. #include <dialogs/eda_view_switcher.h>
  42. #include <wildcards_and_files_ext.h>
  43. #include <collectors.h>
  44. PCB_BASE_EDIT_FRAME::PCB_BASE_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent,
  45. FRAME_T aFrameType, const wxString& aTitle,
  46. const wxPoint& aPos, const wxSize& aSize, long aStyle,
  47. const wxString& aFrameName ) :
  48. PCB_BASE_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ),
  49. m_undoRedoBlocked( false ),
  50. m_selectionFilterPanel( nullptr ),
  51. m_appearancePanel( nullptr ),
  52. m_propertiesPanel( nullptr ),
  53. m_tabbedPanel( nullptr )
  54. {
  55. m_darkMode = KIPLATFORM::UI::IsDarkTheme();
  56. Bind( wxEVT_IDLE,
  57. [this]( wxIdleEvent& aEvent )
  58. {
  59. // Handle cursor adjustments. While we can get motion and key events through
  60. // wxWidgets, we can't get modifier-key-up events.
  61. if( m_toolManager )
  62. {
  63. PCB_SELECTION_TOOL* selTool = m_toolManager->GetTool<PCB_SELECTION_TOOL>();
  64. if( selTool )
  65. selTool->OnIdle( aEvent );
  66. }
  67. if( m_darkMode != KIPLATFORM::UI::IsDarkTheme() )
  68. {
  69. onDarkModeToggle();
  70. m_darkMode = KIPLATFORM::UI::IsDarkTheme();
  71. }
  72. } );
  73. }
  74. PCB_BASE_EDIT_FRAME::~PCB_BASE_EDIT_FRAME()
  75. {
  76. GetCanvas()->GetView()->Clear();
  77. }
  78. void PCB_BASE_EDIT_FRAME::doCloseWindow()
  79. {
  80. SETTINGS_MANAGER* mgr = GetSettingsManager();
  81. wxFileName projectName( Prj().GetProjectFullName() );
  82. if( mgr->IsProjectOpen() && wxFileName::IsDirWritable( projectName.GetPath() )
  83. && projectName.Exists() )
  84. {
  85. GFootprintList.WriteCacheToFile( Prj().GetProjectPath() + wxT( "fp-info-cache" ) );
  86. }
  87. // Close the project if we are standalone, so it gets cleaned up properly
  88. if( mgr->IsProjectOpen() && Kiface().IsSingle() )
  89. mgr->UnloadProject( &Prj(), false );
  90. }
  91. bool PCB_BASE_EDIT_FRAME::TryBefore( wxEvent& aEvent )
  92. {
  93. static bool s_presetSwitcherShown = false;
  94. static bool s_viewportSwitcherShown = false;
  95. // wxWidgets generates no key events for the tab key when the ctrl key is held down. One
  96. // way around this is to look at all events and inspect the keyboard state of the tab key.
  97. // However, this runs into issues on some linux VMs where querying the keyboard state is
  98. // very slow. Fortunately we only use ctrl-tab on Mac, so we implement this lovely hack:
  99. #ifdef __WXMAC__
  100. if( wxGetKeyState( WXK_TAB ) )
  101. #else
  102. if( ( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
  103. && static_cast<wxKeyEvent&>( aEvent ).GetKeyCode() == WXK_TAB )
  104. #endif
  105. {
  106. if( !s_presetSwitcherShown && wxGetKeyState( PRESET_SWITCH_KEY ) )
  107. {
  108. if( m_appearancePanel && this->IsActive() )
  109. {
  110. const wxArrayString& mru = m_appearancePanel->GetLayerPresetsMRU();
  111. if( mru.size() > 0 )
  112. {
  113. EDA_VIEW_SWITCHER switcher( this, mru, PRESET_SWITCH_KEY );
  114. s_presetSwitcherShown = true;
  115. switcher.ShowModal();
  116. s_presetSwitcherShown = false;
  117. int idx = switcher.GetSelection();
  118. if( idx >= 0 && idx < (int) mru.size() )
  119. m_appearancePanel->ApplyLayerPreset( mru[idx] );
  120. return true;
  121. }
  122. }
  123. }
  124. else if( !s_viewportSwitcherShown && wxGetKeyState( VIEWPORT_SWITCH_KEY ) )
  125. {
  126. if( m_appearancePanel && this->IsActive() )
  127. {
  128. const wxArrayString& mru = m_appearancePanel->GetViewportsMRU();
  129. if( mru.size() > 0 )
  130. {
  131. EDA_VIEW_SWITCHER switcher( this, mru, VIEWPORT_SWITCH_KEY );
  132. s_viewportSwitcherShown = true;
  133. switcher.ShowModal();
  134. s_viewportSwitcherShown = false;
  135. int idx = switcher.GetSelection();
  136. if( idx >= 0 && idx < (int) mru.size() )
  137. m_appearancePanel->ApplyViewport( mru[idx] );
  138. return true;
  139. }
  140. }
  141. }
  142. }
  143. return PCB_BASE_FRAME::TryBefore( aEvent );
  144. }
  145. EDA_ANGLE PCB_BASE_EDIT_FRAME::GetRotationAngle() const
  146. {
  147. // Return a default angle (90 degrees) used for rotate operations.
  148. return ANGLE_90;
  149. }
  150. void PCB_BASE_EDIT_FRAME::ActivateGalCanvas()
  151. {
  152. PCB_BASE_FRAME::ActivateGalCanvas();
  153. GetCanvas()->SyncLayersVisibility( m_pcb );
  154. }
  155. void PCB_BASE_EDIT_FRAME::SetBoard( BOARD* aBoard, PROGRESS_REPORTER* aReporter )
  156. {
  157. bool new_board = ( aBoard != m_pcb );
  158. if( new_board )
  159. {
  160. if( m_toolManager )
  161. m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
  162. GetCanvas()->GetView()->Clear();
  163. GetCanvas()->GetView()->InitPreview();
  164. }
  165. PCB_BASE_FRAME::SetBoard( aBoard, aReporter );
  166. GetCanvas()->GetGAL()->SetGridOrigin( VECTOR2D( aBoard->GetDesignSettings().GetGridOrigin() ) );
  167. if( new_board )
  168. {
  169. BOARD_DESIGN_SETTINGS& bds = aBoard->GetDesignSettings();
  170. bds.m_DRCEngine = std::make_shared<DRC_ENGINE>( aBoard, &bds );
  171. }
  172. // update the tool manager with the new board and its view.
  173. if( m_toolManager )
  174. {
  175. GetCanvas()->DisplayBoard( aBoard, aReporter );
  176. GetCanvas()->UpdateColors();
  177. m_toolManager->SetEnvironment( aBoard, GetCanvas()->GetView(),
  178. GetCanvas()->GetViewControls(), config(), this );
  179. if( new_board )
  180. m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
  181. }
  182. }
  183. void PCB_BASE_EDIT_FRAME::unitsChangeRefresh()
  184. {
  185. PCB_BASE_FRAME::unitsChangeRefresh();
  186. if( BOARD* board = GetBoard() )
  187. {
  188. EDA_UNITS units = GetUserUnits();
  189. KIGFX::VIEW* view = GetCanvas()->GetView();
  190. bool selectedItemModified = false;
  191. INSPECTOR_FUNC inspector =
  192. [units, view, &selectedItemModified]( EDA_ITEM* aItem, void* aTestData )
  193. {
  194. PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( aItem );
  195. if( dimension->GetUnitsMode() == DIM_UNITS_MODE::AUTOMATIC )
  196. {
  197. dimension->SetUnits( units );
  198. dimension->Update();
  199. if( dimension->IsSelected() )
  200. selectedItemModified = true;
  201. view->Update( dimension );
  202. }
  203. return INSPECT_RESULT::CONTINUE;
  204. };
  205. board->Visit( inspector, nullptr, { PCB_DIM_ALIGNED_T,
  206. PCB_DIM_LEADER_T,
  207. PCB_DIM_ORTHOGONAL_T,
  208. PCB_DIM_CENTER_T,
  209. PCB_DIM_RADIAL_T,
  210. PCB_FP_DIM_ALIGNED_T,
  211. PCB_FP_DIM_LEADER_T,
  212. PCB_FP_DIM_ORTHOGONAL_T,
  213. PCB_FP_DIM_CENTER_T,
  214. PCB_FP_DIM_RADIAL_T } );
  215. if( selectedItemModified )
  216. m_toolManager->PostEvent( EVENTS::SelectedItemsModified );
  217. }
  218. ReCreateAuxiliaryToolbar();
  219. UpdateProperties();
  220. }
  221. void PCB_BASE_EDIT_FRAME::SetGridVisibility( bool aVisible )
  222. {
  223. PCB_BASE_FRAME::SetGridVisibility( aVisible );
  224. // Update the grid checkbox in the layer widget
  225. if( m_appearancePanel )
  226. m_appearancePanel->SetObjectVisible( LAYER_GRID, aVisible );
  227. }
  228. void PCB_BASE_EDIT_FRAME::SetObjectVisible( GAL_LAYER_ID aLayer, bool aVisible )
  229. {
  230. if( m_appearancePanel )
  231. m_appearancePanel->SetObjectVisible( aLayer, aVisible );
  232. }
  233. COLOR_SETTINGS* PCB_BASE_EDIT_FRAME::GetColorSettings( bool aForceRefresh ) const
  234. {
  235. return Pgm().GetSettingsManager().GetColorSettings( GetPcbNewSettings()->m_ColorTheme );
  236. }
  237. wxString PCB_BASE_EDIT_FRAME::GetDesignRulesPath()
  238. {
  239. if( !GetBoard() )
  240. return wxEmptyString;
  241. wxFileName fn = GetBoard()->GetFileName();
  242. fn.SetExt( DesignRulesFileExtension );
  243. return Prj().AbsolutePath( fn.GetFullName() );
  244. }
  245. void PCB_BASE_EDIT_FRAME::handleActivateEvent( wxActivateEvent& aEvent )
  246. {
  247. PCB_BASE_FRAME::handleActivateEvent( aEvent );
  248. // The text in the collapsible pane headers need to be updated
  249. if( m_appearancePanel )
  250. m_appearancePanel->RefreshCollapsiblePanes();
  251. }
  252. void PCB_BASE_EDIT_FRAME::onDarkModeToggle()
  253. {
  254. m_appearancePanel->OnDarkModeToggle();
  255. }
  256. void PCB_BASE_EDIT_FRAME::UpdateProperties()
  257. {
  258. if( !m_propertiesPanel || !m_propertiesPanel->IsShownOnScreen() )
  259. return;
  260. m_propertiesPanel->UpdateData();
  261. }