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.

319 lines
10 KiB

Mark null project initial screen as zoom-initialized The variable `m_Initialized` in `BASE_SCREEN` is used by `SCH_EDIT_FRAME` to mark whether a screen had its zoom level initialized by the "zoom to fit screen" action. When this variable is `false`, the function `SCH_EDIT_FRAME::DisplayCurrentSheet()` performs "zoom to fit screen", modifying the zoom level. This function is indirectly called in the undo routines, so if `m_Initialized` is not set to `true`, a zoom change will occur when the user undoes an operation, a behavior that is undesired. `m_Initialized` was not initialized to `true` for the null schematic (the schematic that is loaded if no project is loaded), causing the aforementioned undesired behavior. To prevent this, I've changed the `SCH_EDIT_FRAME` constructor to set `m_Initialized` to `true`, since it zooms to fit screen already. I've moved `m_Initialized` from `BASE_SCREEN` to `SCH_SCREEN`, as it is used only in Eeschema, and renamed it to `m_zoomInitialized`, a name I believe that better describes what this variable does. I've also introduced the function `SCH_EDIT_FRAME::initScreenZoom()` to group the "zoom to fit screen" action with setting `m_Initialized` to `true`, as they often should occur together. I'd also like to say that I'm not confident whether `SCH_EDIT_FRAME::DisplayCurrentSheet()` should perform the zoom level initialization at this point, but I have decided to not change this behavior for now, as the commit history suggests it's several years old. Fixes https://gitlab.com/kicad/code/kicad/issues/7343
5 years ago
Mark null project initial screen as zoom-initialized The variable `m_Initialized` in `BASE_SCREEN` is used by `SCH_EDIT_FRAME` to mark whether a screen had its zoom level initialized by the "zoom to fit screen" action. When this variable is `false`, the function `SCH_EDIT_FRAME::DisplayCurrentSheet()` performs "zoom to fit screen", modifying the zoom level. This function is indirectly called in the undo routines, so if `m_Initialized` is not set to `true`, a zoom change will occur when the user undoes an operation, a behavior that is undesired. `m_Initialized` was not initialized to `true` for the null schematic (the schematic that is loaded if no project is loaded), causing the aforementioned undesired behavior. To prevent this, I've changed the `SCH_EDIT_FRAME` constructor to set `m_Initialized` to `true`, since it zooms to fit screen already. I've moved `m_Initialized` from `BASE_SCREEN` to `SCH_SCREEN`, as it is used only in Eeschema, and renamed it to `m_zoomInitialized`, a name I believe that better describes what this variable does. I've also introduced the function `SCH_EDIT_FRAME::initScreenZoom()` to group the "zoom to fit screen" action with setting `m_Initialized` to `true`, as they often should occur together. I'd also like to say that I'm not confident whether `SCH_EDIT_FRAME::DisplayCurrentSheet()` should perform the zoom level initialization at this point, but I have decided to not change this behavior for now, as the commit history suggests it's several years old. Fixes https://gitlab.com/kicad/code/kicad/issues/7343
5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
  6. * Copyright (C) 2004-2021 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 <sch_draw_panel.h>
  26. #include <confirm.h>
  27. #include <id.h>
  28. #include <bitmaps.h>
  29. #include <dialog_shim.h>
  30. #include <sch_edit_frame.h>
  31. #include <sch_sheet.h>
  32. #include <sch_sheet_path.h>
  33. #include <schematic.h>
  34. #include <tool/tool_manager.h>
  35. #include <tools/ee_actions.h>
  36. #include <tools/sch_editor_control.h>
  37. #include <sch_sheet_path.h>
  38. #include <hierarch.h>
  39. #include <view/view.h>
  40. #include <kiface_base.h>
  41. #include "eeschema_settings.h"
  42. #include <wx/object.h>
  43. class HIERARCHY_NAVIG_DLG;
  44. /**
  45. * Store an SCH_SHEET_PATH of each sheet in hierarchy.
  46. */
  47. class TreeItemData : public wxTreeItemData
  48. {
  49. public:
  50. SCH_SHEET_PATH m_SheetPath;
  51. TreeItemData( SCH_SHEET_PATH& sheet ) : wxTreeItemData()
  52. {
  53. m_SheetPath = sheet;
  54. }
  55. };
  56. // Need to use wxRTTI macros in order for OnCompareItems to work properly
  57. // See: https://docs.wxwidgets.org/3.1/classwx_tree_ctrl.html#ab90a465793c291ca7aa827a576b7d146
  58. wxIMPLEMENT_ABSTRACT_CLASS( HIERARCHY_TREE, wxTreeCtrl );
  59. HIERARCHY_TREE::HIERARCHY_TREE( HIERARCHY_NAVIG_DLG* parent ) :
  60. wxTreeCtrl( (wxWindow*) parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
  61. wxTR_HAS_BUTTONS, wxDefaultValidator, wxT( "HierachyTreeCtrl" ) )
  62. {
  63. m_parent = parent;
  64. // Make an image list containing small icons
  65. // All icons are expected having the same size.
  66. wxBitmap tree_nosel_bm( KiBitmap( BITMAPS::tree_nosel ) );
  67. imageList = new wxImageList( tree_nosel_bm.GetWidth(), tree_nosel_bm.GetHeight(), true, 2 );
  68. imageList->Add( tree_nosel_bm );
  69. imageList->Add( KiBitmap( BITMAPS::tree_sel ) );
  70. AssignImageList( imageList );
  71. }
  72. HIERARCHY_NAVIG_DLG::HIERARCHY_NAVIG_DLG( SCH_EDIT_FRAME* aParent ) :
  73. DIALOG_SHIM( aParent, wxID_ANY, _( "Navigator" ), wxDefaultPosition, wxDefaultSize,
  74. wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER, HIERARCHY_NAVIG_DLG_WNAME )
  75. {
  76. wxASSERT( dynamic_cast< SCH_EDIT_FRAME* >( aParent ) );
  77. m_SchFrameEditor = aParent;
  78. m_currSheet = aParent->GetCurrentSheet();
  79. m_Tree = new HIERARCHY_TREE( this );
  80. m_nbsheets = 1;
  81. // root is the link to the main sheet.
  82. wxTreeItemId root = m_Tree->AddRoot( getRootString(), 0, 1 );
  83. m_Tree->SetItemBold( root, true );
  84. m_list.push_back( &m_SchFrameEditor->Schematic().Root() );
  85. m_Tree->SetItemData( root, new TreeItemData( m_list ) );
  86. if( m_SchFrameEditor->GetCurrentSheet().Last() == &m_SchFrameEditor->Schematic().Root() )
  87. m_Tree->SelectItem( root );
  88. buildHierarchyTree( &m_list, &root );
  89. m_Tree->ExpandAll();
  90. // This bloc gives a good size to the dialog, better than the default "best" size,
  91. // the first time the dialog is opened, during a session
  92. wxRect itemrect;
  93. wxSize tree_size;
  94. m_Tree->GetBoundingRect( root, itemrect );
  95. // Set dialog window size to be large enough
  96. tree_size.x = itemrect.GetWidth() + 20;
  97. tree_size.x = std::max( tree_size.x, 250 );
  98. // Readjust the size of the frame to an optimal value.
  99. tree_size.y = m_nbsheets * itemrect.GetHeight();
  100. if( m_nbsheets < 2 )
  101. tree_size.y += 10; // gives a better look for small trees
  102. SetClientSize( tree_size );
  103. // manage the ESC key to close the dialog, because there is no Cancel button
  104. // in dialog
  105. m_Tree->Connect( wxEVT_CHAR, wxKeyEventHandler( HIERARCHY_TREE::onChar ) );
  106. // Manage double click on a selection, or the enter key:
  107. Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  108. // Manage a simple click on a selection, if the selection changes
  109. Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  110. // Connect close event for the dialog:
  111. this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( HIERARCHY_NAVIG_DLG::OnCloseNav ) );
  112. }
  113. HIERARCHY_NAVIG_DLG::~HIERARCHY_NAVIG_DLG()
  114. {
  115. Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  116. Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  117. m_Tree->Disconnect( wxEVT_CHAR, wxKeyEventHandler( HIERARCHY_TREE::onChar ) );
  118. Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( HIERARCHY_NAVIG_DLG::OnCloseNav ) );
  119. }
  120. void HIERARCHY_TREE::onChar( wxKeyEvent& event )
  121. {
  122. if( event.GetKeyCode() == WXK_ESCAPE )
  123. m_parent->Close( true );
  124. else
  125. event.Skip();
  126. }
  127. int HIERARCHY_TREE::OnCompareItems( const wxTreeItemId& item1, const wxTreeItemId& item2 )
  128. {
  129. SCH_SHEET_PATH* item1Path = &static_cast<TreeItemData*>( GetItemData( item1 ) )->m_SheetPath;
  130. SCH_SHEET_PATH* item2Path = &static_cast<TreeItemData*>( GetItemData( item2 ) )->m_SheetPath;
  131. return item1Path->ComparePageNumAndName( *item2Path );
  132. }
  133. void HIERARCHY_NAVIG_DLG::buildHierarchyTree( SCH_SHEET_PATH* aList, wxTreeItemId* aPreviousmenu )
  134. {
  135. wxCHECK_RET( m_nbsheets < NB_MAX_SHEET, "Maximum number of sheets exceeded." );
  136. std::vector<SCH_ITEM*> sheetChildren;
  137. aList->LastScreen()->GetSheets( &sheetChildren );
  138. for( SCH_ITEM* aItem : sheetChildren )
  139. {
  140. SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
  141. aList->push_back( sheet );
  142. wxString sheetName = formatPageString( sheet->GetFields()[SHEETNAME].GetShownText(),
  143. sheet->GetPageNumber( *aList ) );
  144. m_nbsheets++;
  145. wxTreeItemId menu;
  146. menu = m_Tree->AppendItem( *aPreviousmenu, sheetName, 0, 1 );
  147. m_Tree->SetItemData( menu, new TreeItemData( *aList ) );
  148. if( *aList == m_currSheet )
  149. {
  150. m_Tree->EnsureVisible( menu );
  151. m_Tree->SelectItem( menu );
  152. }
  153. buildHierarchyTree( aList, &menu );
  154. aList->pop_back();
  155. if( m_nbsheets >= NB_MAX_SHEET )
  156. break;
  157. }
  158. m_Tree->SortChildren( *aPreviousmenu );
  159. }
  160. void HIERARCHY_NAVIG_DLG::UpdateHierarchyTree()
  161. {
  162. Freeze();
  163. // Disable selection events
  164. Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  165. Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  166. m_currSheet = m_SchFrameEditor->GetCurrentSheet();
  167. m_Tree->DeleteAllItems();
  168. m_nbsheets = 1;
  169. wxTreeItemId root = m_Tree->AddRoot( getRootString(), 0, 1 );
  170. m_Tree->SetItemBold( root, true );
  171. m_list.clear();
  172. m_list.push_back( &m_SchFrameEditor->Schematic().Root() );
  173. m_Tree->SetItemData( root, new TreeItemData( m_list ) );
  174. if( m_SchFrameEditor->GetCurrentSheet().Last() == &m_SchFrameEditor->Schematic().Root() )
  175. m_Tree->SelectItem( root );
  176. buildHierarchyTree( &m_list, &root );
  177. m_Tree->ExpandAll();
  178. // Enable selection events
  179. Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  180. Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_NAVIG_DLG::onSelectSheetPath, this );
  181. Thaw();
  182. }
  183. void HIERARCHY_NAVIG_DLG::onSelectSheetPath( wxTreeEvent& event )
  184. {
  185. m_SchFrameEditor->GetToolManager()->RunAction( ACTIONS::cancelInteractive, true );
  186. m_SchFrameEditor->GetToolManager()->RunAction( EE_ACTIONS::clearSelection, true );
  187. wxTreeItemId itemSel = m_Tree->GetSelection();
  188. TreeItemData* itemData = static_cast<TreeItemData*>( m_Tree->GetItemData( itemSel ) );
  189. // Store the current zoom level into the current screen before switching
  190. m_SchFrameEditor->GetScreen()->m_LastZoomLevel =
  191. m_SchFrameEditor->GetCanvas()->GetView()->GetScale();
  192. m_SchFrameEditor->SetCurrentSheet( itemData->m_SheetPath );
  193. m_SchFrameEditor->DisplayCurrentSheet();
  194. EESCHEMA_SETTINGS* appSettings = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
  195. if( !appSettings->m_Appearance.navigator_stays_open )
  196. Close( true );
  197. }
  198. wxString HIERARCHY_NAVIG_DLG::getRootString()
  199. {
  200. SCH_SHEET* rootSheet = &m_SchFrameEditor->Schematic().Root();
  201. SCH_SHEET_PATH rootPath;
  202. rootPath.push_back( rootSheet );
  203. return formatPageString ( _( "Root" ), rootSheet->GetPageNumber( rootPath ) );
  204. }
  205. wxString HIERARCHY_NAVIG_DLG::formatPageString( const wxString& aName, const wxString& aPage )
  206. {
  207. return aName + wxT( " " ) + wxString::Format( _( "(page %s)" ), aPage );
  208. }
  209. void HIERARCHY_NAVIG_DLG::OnCloseNav( wxCloseEvent& event )
  210. {
  211. Destroy();
  212. }
  213. void SCH_EDIT_FRAME::DisplayCurrentSheet()
  214. {
  215. m_toolManager->RunAction( ACTIONS::cancelInteractive, true );
  216. m_toolManager->RunAction( EE_ACTIONS::clearSelection, true );
  217. SCH_SCREEN* screen = GetCurrentSheet().LastScreen();
  218. wxASSERT( screen );
  219. SetScreen( screen );
  220. // update the References
  221. GetCurrentSheet().UpdateAllScreenReferences();
  222. SetSheetNumberAndCount();
  223. if( !screen->m_zoomInitialized )
  224. {
  225. initScreenZoom();
  226. }
  227. else
  228. {
  229. // Set zoom to last used in this screen
  230. GetCanvas()->GetView()->SetScale( GetScreen()->m_LastZoomLevel );
  231. RedrawScreen( (wxPoint) GetScreen()->m_ScrollCenter, false );
  232. }
  233. UpdateTitle();
  234. SCH_EDITOR_CONTROL* editTool = m_toolManager->GetTool<SCH_EDITOR_CONTROL>();
  235. TOOL_EVENT dummy;
  236. editTool->UpdateNetHighlighting( dummy );
  237. HardRedraw(); // Ensure all items are redrawn (especially the drawing-sheet items)
  238. UpdateHierarchyNavigator();
  239. }