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) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, you may find one here: 19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 20 * or you may search the http://www.gnu.org website for the version 2 license, 21 * or you may write to the Free Software Foundation, Inc., 22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 */ 24 25 #ifndef SCH_SHEEET_H 26 #define SCH_SHEEET_H 27 28 #include <sch_field.h> 29 30 class KIID_PATH; 31 class SCH_SCREEN; 32 class SCH_SHEET_PIN; 33 class SCH_SHEET_PATH; 34 class EDA_DRAW_FRAME; 35 36 37 #define MIN_SHEET_WIDTH 500 // Units are mils. 38 #define MIN_SHEET_HEIGHT 150 // Units are mils. 39 40 41 enum SHEET_FIELD_TYPE 42 { 43 SHEETNAME = 0, 44 SHEETFILENAME, 45 46 /// The first 2 are mandatory, and must be instantiated in SCH_SHEET 47 SHEET_MANDATORY_FIELDS 48 }; 49 50 51 /** 52 * Sheet symbol placed in a schematic, and is the entry point for a sub schematic. 53 */ 54 class SCH_SHEET : public SCH_ITEM 55 { 56 public: 57 SCH_SHEET( EDA_ITEM* aParent = nullptr, const wxPoint& aPos = wxPoint( 0, 0 ), 58 wxSize aSize = wxSize( Mils2iu( MIN_SHEET_WIDTH ), Mils2iu( MIN_SHEET_HEIGHT ) ), 59 FIELDS_AUTOPLACED aAutoplaceFields = FIELDS_AUTOPLACED_AUTO ); 60 61 /** 62 * Copy \a aSheet into a new object. All sheet pins are copied as is except and 63 * the SCH_SHEET_PIN's #m_Parent pointers are set to the new copied parent object. 64 */ 65 SCH_SHEET( const SCH_SHEET& aSheet ); 66 67 ~SCH_SHEET(); 68 ClassOf(const EDA_ITEM * aItem)69 static inline bool ClassOf( const EDA_ITEM* aItem ) 70 { 71 return aItem && SCH_SHEET_T == aItem->Type(); 72 } 73 GetClass()74 wxString GetClass() const override 75 { 76 return wxT( "SCH_SHEET" ); 77 } 78 79 /** 80 * Return true for items which are moved with the anchor point at mouse cursor 81 * and false for items moved with no reference to anchor. 82 * 83 * Usually return true for small items (labels, junctions) and false for 84 * items which can be large (hierarchical sheets, symbols). 85 * 86 * @return false for a hierarchical sheet. 87 */ IsMovableFromAnchorPoint()88 bool IsMovableFromAnchorPoint() const override { return false; } 89 GetFields()90 std::vector<SCH_FIELD>& GetFields() { return m_fields; } GetFields()91 const std::vector<SCH_FIELD>& GetFields() const { return m_fields; } 92 93 /** 94 * Set multiple schematic fields. 95 * 96 * @param aFields are the fields to set in this symbol. 97 */ SetFields(const std::vector<SCH_FIELD> & aFields)98 void SetFields( const std::vector<SCH_FIELD>& aFields ) 99 { 100 m_fields = aFields; // vector copying, length is changed possibly 101 } 102 GetName()103 wxString GetName() const { return m_fields[ SHEETNAME ].GetText(); } 104 GetScreen()105 SCH_SCREEN* GetScreen() const { return m_screen; } 106 GetSize()107 wxSize GetSize() const { return m_size; } SetSize(const wxSize & aSize)108 void SetSize( const wxSize& aSize ) { m_size = aSize; } 109 GetBorderWidth()110 int GetBorderWidth() const { return m_borderWidth; } SetBorderWidth(int aWidth)111 void SetBorderWidth( int aWidth ) { m_borderWidth = aWidth; } 112 GetBorderColor()113 KIGFX::COLOR4D GetBorderColor() const { return m_borderColor; } SetBorderColor(KIGFX::COLOR4D aColor)114 void SetBorderColor( KIGFX::COLOR4D aColor ) { m_borderColor = aColor; } 115 GetBackgroundColor()116 KIGFX::COLOR4D GetBackgroundColor() const { return m_backgroundColor; } SetBackgroundColor(KIGFX::COLOR4D aColor)117 void SetBackgroundColor( KIGFX::COLOR4D aColor ) { m_backgroundColor = aColor; } 118 119 /** 120 * Test this sheet to see if the default stroke is used to draw the outline. 121 * 122 * The default stroke is defined as follows: 123 * * The outline width is the default line width or 0. 124 * * The outline style is set to #PLOT_DASH_TYPE::DEFAULT or #PLOT_DASH_TYPE::SOLID. 125 * * The outline color is set to #COLOR4D::UNSPECIFIED. 126 * 127 * @return True if the outline stroke meets the default criteria. 128 */ 129 bool UsesDefaultStroke() const; 130 131 /** 132 * @return true if this sheet is the root sheet. 133 */ 134 bool IsRootSheet() const; 135 136 /** 137 * Set the #SCH_SCREEN associated with this sheet to \a aScreen. 138 * 139 * The screen reference counting is performed by SetScreen. If \a aScreen is not 140 * the same as the current screen, the current screen reference count is decremented 141 * and \a aScreen becomes the screen for the sheet. If the current screen reference 142 * count reaches zero, the current screen is deleted. NULL is a valid value for 143 * \a aScreen. 144 * 145 * @param aScreen The new screen to associate with the sheet. 146 */ 147 void SetScreen( SCH_SCREEN* aScreen ); 148 149 /** 150 * Return the number of times the associated screen for the sheet is being used. 151 * 152 * If no screen is associated with the sheet, then zero is returned. 153 */ 154 int GetScreenCount() const; 155 156 /** 157 * Return the list of system text vars & fields for this sheet. 158 */ 159 void GetContextualTextVars( wxArrayString* aVars ) const; 160 161 /** 162 * Resolve any references to system tokens supported by the sheet. 163 * 164 * @param aDepth is a counter to limit recursion and circular references. 165 */ 166 bool ResolveTextVar( wxString* token, int aDepth = 0 ) const; 167 168 void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; 169 170 /* there is no member for orientation in sch_sheet, to preserve file 171 * format, we detect orientation based on pin edges 172 */ 173 bool IsVerticalOrientation() const; 174 175 /** 176 * Add aSheetPin to the sheet. 177 * 178 * @note Once a sheet pin is added to the sheet, it is owned by the sheet. 179 * Do not delete the sheet pin object or you will likely get a segfault 180 * when the sheet is destroyed. 181 * 182 * @param aSheetPin The sheet pin item to add to the sheet. 183 */ 184 void AddPin( SCH_SHEET_PIN* aSheetPin ); 185 GetPins()186 std::vector<SCH_SHEET_PIN*>& GetPins() { return m_pins; } 187 GetPins()188 const std::vector<SCH_SHEET_PIN*>& GetPins() const 189 { 190 return m_pins; 191 } 192 193 /** 194 * Remove \a aSheetPin from the sheet. 195 * 196 * @param aSheetPin The sheet pin item to remove from the sheet. 197 */ 198 void RemovePin( const SCH_SHEET_PIN* aSheetPin ); 199 200 /** 201 * Delete sheet label which do not have a corresponding hierarchical label. 202 * 203 * @note Make sure you save a copy of the sheet in the undo list before calling 204 * CleanupSheet() otherwise any unreferenced sheet labels will be lost. 205 */ 206 void CleanupSheet(); 207 208 /** 209 * Return the sheet pin item found at \a aPosition in the sheet. 210 * 211 * @param aPosition The position to check for a sheet pin. 212 * 213 * @return The sheet pin found at \a aPosition or NULL if no sheet pin is found. 214 */ 215 SCH_SHEET_PIN* GetPin( const wxPoint& aPosition ); 216 217 /** 218 * Checks if the sheet already has a sheet pin named \a aName. 219 * 220 * @param aName Name of the sheet pin to search for. 221 * @return True if sheet pin with \a aName is found, otherwise false. 222 */ 223 bool HasPin( const wxString& aName ) const; 224 HasPins()225 bool HasPins() const { return !m_pins.empty(); } 226 227 /** 228 * Check all sheet labels against schematic for undefined hierarchical labels. 229 * 230 * @return True if there are any undefined labels. 231 */ 232 bool HasUndefinedPins() const; 233 234 /** 235 * Return the minimum width of the sheet based on the widths of the sheet pin text. 236 * 237 * The minimum sheet width is determined by the width of the bounding box of each 238 * hierarchical sheet pin. If two pins are horizontally adjacent ( same Y position ) 239 * to each other, the sum of the bounding box widths is used. If at some point in 240 * the future sheet objects can be rotated or pins can be placed in the vertical 241 * orientation, this function will need to be changed. 242 * 243 * @return The minimum width the sheet can be resized. 244 */ 245 int GetMinWidth( bool aFromLeft ) const; 246 247 /** 248 * Return the minimum height that the sheet can be resized based on the sheet pin positions. 249 * 250 * The minimum width of a sheet is determined by the Y axis location of the bottom 251 * most sheet pin. If at some point in the future sheet objects can be rotated or 252 * pins can be placed in the vertical orientation, this function will need to be 253 * changed. 254 * 255 * @return The minimum height the sheet can be resized. 256 */ 257 int GetMinHeight( bool aFromTop ) const; 258 259 int GetPenWidth() const override; 260 261 void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) override; 262 263 /** 264 * Return a bounding box for the sheet body but not the fields. 265 */ 266 const EDA_RECT GetBodyBoundingBox() const; 267 268 const EDA_RECT GetBoundingBox() const override; 269 270 /** 271 * Rotating around the boundingBox's center can cause walking when the sheetname or 272 * filename is longer than the edge it's on. Use this instead, which always returns 273 * the center of the sheet itself. 274 */ 275 wxPoint GetRotationCenter() const; 276 277 void SwapData( SCH_ITEM* aItem ) override; 278 279 /** 280 * Count our own symbols, without the power symbols. 281 */ 282 int SymbolCount() const; 283 284 /** 285 * Search the existing hierarchy for an instance of screen loaded from \a aFileName. 286 * 287 * @param aFilename The filename to find (MUST be absolute, and in wxPATH_NATIVE encoding). 288 * @param aScreen A location to return a pointer to the screen (if found). 289 * @return true if found, and a pointer to the screen 290 */ 291 bool SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen ); 292 293 /** 294 * Search the existing hierarchy for an instance of screen loaded from \a aFileName. 295 * 296 * Don't bother looking at the root sheet, it must be unique. No other references to 297 * its m_screen otherwise there would be loops in the hierarchy. 298 * 299 * @param[in] aScreen The SCH_SCREEN* screen that we search for. 300 * @param[in] aList The SCH_SHEET_PATH* that must be used. 301 * @return true if found. 302 */ 303 bool LocatePathOfScreen( SCH_SCREEN* aScreen, SCH_SHEET_PATH* aList ); 304 305 /** 306 * Count the number of sheets found in "this" sheet including all of the subsheets. 307 * 308 * @return the full count of sheets+subsheets contained by "this" 309 */ 310 int CountSheets() const; 311 312 /** 313 * Return the filename corresponding to this sheet. 314 * 315 * @return a wxString containing the filename 316 */ GetFileName()317 wxString GetFileName() const 318 { 319 return m_fields[ SHEETFILENAME ].GetText(); 320 } 321 322 // Set a new filename without changing anything else SetFileName(const wxString & aFilename)323 void SetFileName( const wxString& aFilename ) 324 { 325 // Filenames are stored using unix notation 326 wxString tmp = aFilename; 327 tmp.Replace( wxT( "\\" ), wxT( "/" ) ); 328 m_fields[ SHEETFILENAME ].SetText( tmp ); 329 } 330 331 // Geometric transforms (used in block operations): 332 333 void Move( const wxPoint& aMoveVector ) override; 334 void MirrorHorizontally( int aCenter ) override; 335 void MirrorVertically( int aCenter ) override; 336 void Rotate( const wxPoint& aCenter ) override; 337 338 bool Matches( const wxFindReplaceData& aSearchData, void* aAuxData ) const override; 339 IsReplaceable()340 bool IsReplaceable() const override { return true; } 341 342 /** 343 * Resize this sheet to aSize and adjust all of the labels accordingly. 344 * 345 * @param[in] aSize The new size for this sheet. 346 */ 347 void Resize( const wxSize& aSize ); 348 349 void AutoplaceFields( SCH_SCREEN* aScreen, bool aManual ) override; 350 351 void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList ) override; 352 353 bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList, 354 const SCH_SHEET_PATH* aPath = nullptr ) override; 355 IsConnectable()356 bool IsConnectable() const override { return true; } 357 CanConnect(const SCH_ITEM * aItem)358 bool CanConnect( const SCH_ITEM* aItem ) const override 359 { 360 return ( aItem->Type() == SCH_LINE_T && aItem->GetLayer() == LAYER_WIRE ) 361 || ( aItem->Type() == SCH_LINE_T && aItem->GetLayer() == LAYER_BUS ) 362 || ( aItem->Type() == SCH_NO_CONNECT_T ) 363 || ( aItem->Type() == SCH_SYMBOL_T ); 364 } 365 366 std::vector<wxPoint> GetConnectionPoints() const override; 367 368 SEARCH_RESULT Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] ) override; 369 370 void RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction ) override; 371 372 wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; 373 374 BITMAPS GetMenuImage() const override; 375 376 SCH_SHEET& operator=( const SCH_ITEM& aSheet ); 377 378 bool operator <( const SCH_ITEM& aItem ) const override; 379 380 void ViewGetLayers( int aLayers[], int& aCount ) const override; 381 GetPosition()382 wxPoint GetPosition() const override { return m_pos; } 383 void SetPosition( const wxPoint& aPosition ) override; 384 385 bool HitTest( const wxPoint& aPosition, int aAccuracy ) const override; 386 bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; 387 388 void Plot( PLOTTER* aPlotter ) const override; 389 390 EDA_ITEM* Clone() const override; 391 392 /** 393 * @return the list of #SCH_SHEET_INSTANCE objects for this sheet. 394 */ GetInstances()395 const std::vector<SCH_SHEET_INSTANCE>& GetInstances() const { return m_instances; } 396 SetInstances(const std::vector<SCH_SHEET_INSTANCE> & aInstances)397 void SetInstances( const std::vector<SCH_SHEET_INSTANCE>& aInstances ) 398 { 399 m_instances = aInstances; 400 } 401 402 /** 403 * Add a new instance \a aSheetPath to the instance list. 404 * 405 * If \a aSheetPath does not already exist, it is added to the list. If already exists 406 * in the list, do nothing. Sheet instances allow for the sharing in complex hierarchies 407 * which allows for per instance data such as page number for sheets to stored. 408 * 409 * @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the 410 * #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path 411 * will raise an assertion on debug builds and silently fail and return false 412 * on release builds. 413 * 414 * @param[in] aInstance is the #SCH_SHEET_PATH of the sheet instance to the instance list. 415 * @return false if the instance already exists, true if the instance was added. 416 */ 417 bool AddInstance( const SCH_SHEET_PATH& aInstance ); 418 419 /** 420 * Return the sheet page number for \a aInstance. 421 * 422 * @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the 423 * #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path 424 * will raise an assertion on debug builds and silently fail and return an empty 425 * page number on release builds. 426 * 427 * @return the page number for the requested sheet instance. 428 */ 429 wxString GetPageNumber( const SCH_SHEET_PATH& aInstance ) const; 430 431 /** 432 * Set the page number for the sheet instance \a aInstance. 433 * 434 * @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the 435 * #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path 436 * will raise an assertion on debug builds and silently fail and return on release 437 * builds. 438 * 439 * @param[in] aInstance is the hierarchical path of the sheet. 440 * @param[in] aReference is the new page number for the sheet. 441 */ 442 void SetPageNumber( const SCH_SHEET_PATH& aInstance, const wxString& aPageNumber ); 443 444 /** 445 * Compares page numbers of schematic sheets. 446 * 447 * @return 0 if the page numbers are equal, -1 if aPageNumberA < aPageNumberB, 1 otherwise 448 */ 449 static int ComparePageNum( const wxString& aPageNumberA, const wxString& aPageNumberB ); 450 451 #if defined(DEBUG) 452 void Show( int nestLevel, std::ostream& os ) const override; 453 #endif 454 455 static const wxString GetDefaultFieldName( int aFieldNdx, bool aTranslated = true ); 456 457 protected: 458 /** 459 * Renumber the sheet pins in the sheet. 460 * 461 * This method is used internally by SCH_SHEET to update the pin numbering 462 * when the pin list changes. Make sure you call this method any time a 463 * sheet pin is added or removed. 464 */ 465 void renumberPins(); 466 467 private: 468 bool doIsConnected( const wxPoint& aPosition ) const override; 469 470 friend class SCH_SHEET_PIN; 471 472 SCH_SCREEN* m_screen; // Screen that contains the physical data for the sheet. In 473 // complex hierarchies multiple sheets can share a common screen. 474 475 std::vector<SCH_SHEET_PIN*> m_pins; // The list of sheet connection points. 476 std::vector<SCH_FIELD> m_fields; 477 478 wxPoint m_pos; // The position of the sheet. 479 wxSize m_size; // The size of the sheet. 480 int m_borderWidth; 481 KIGFX::COLOR4D m_borderColor; 482 KIGFX::COLOR4D m_backgroundColor; 483 484 std::vector<SCH_SHEET_INSTANCE> m_instances; 485 }; 486 487 488 #endif // SCH_SHEEET_H 489