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