Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
kicad-source-mirror
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
kicad-source-mirror
Commits
945f5f1e
Commit
945f5f1e
authored
Apr 12, 2008
by
charras
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
eeschema: code cleaning.
parent
0750a215
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
512 additions
and
442 deletions
+512
-442
change_log.txt
change_log.txt
+6
-0
annotate.cpp
eeschema/annotate.cpp
+14
-3
annotate_dialog.cpp
eeschema/annotate_dialog.cpp
+3
-0
class_drawsheet.cpp
eeschema/class_drawsheet.cpp
+76
-0
class_drawsheet.h
eeschema/class_drawsheet.h
+195
-0
class_screen.cpp
eeschema/class_screen.cpp
+8
-0
class_screen.h
eeschema/class_screen.h
+1
-184
component_class.cpp
eeschema/component_class.cpp
+188
-25
component_class.h
eeschema/component_class.h
+15
-6
load_one_schematic_file.cpp
eeschema/load_one_schematic_file.cpp
+2
-3
netform.cpp
eeschema/netform.cpp
+1
-1
program.h
eeschema/program.h
+1
-0
save_schemas.cpp
eeschema/save_schemas.cpp
+2
-220
No files found.
change_log.txt
View file @
945f5f1e
...
...
@@ -5,6 +5,12 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
email address.
2008-Apr-09 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+eeschema
code cleaning.
2008-Apr-09 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+eeschema
...
...
eeschema/annotate.cpp
View file @
945f5f1e
...
...
@@ -133,7 +133,14 @@ CmpListStruct* AllocateCmpListStrct( int numcomponents )
}
/* qsort function to annotate items by their position. */
/* qsort function to annotate items by their position.
* Components are sorted
* by reference
* if same reference: by sheet
* if same sheet, by X pos
* if same X pos, by Y pos
* if same Y pos, by time stamp
*/
int
AnnotateByPosition
(
const
void
*
o1
,
const
void
*
o2
)
{
CmpListStruct
*
item1
=
(
CmpListStruct
*
)
o1
;
...
...
@@ -214,6 +221,10 @@ void DeleteAnnotation( WinEDA_SchematicFrame* parent, bool annotateSchematic )
* Compute the annotation of the components for the whole project, or the
* current sheet only. All the components or the new ones only will be
* annotated.
* @param parent = Schematic frame
* @param annotateSchematic : true = entire schematic annotation, false = current scheet only
* @param sortByPosition : true = annotate by sorting X position, false = annotate by sorting value
* @param resetAnnotation : true = remove previous annotation false = anotate new components only
*****************************************************************************/
void
AnnotateComponents
(
WinEDA_SchematicFrame
*
parent
,
bool
annotateSchematic
,
...
...
@@ -277,10 +288,10 @@ void AnnotateComponents( WinEDA_SchematicFrame* parent,
if
(
sortByPosition
)
qsort
(
BaseListeCmp
,
NbOfCmp
,
sizeof
(
CmpListStruct
),
(
int
(
*
)
(
const
void
*
,
const
void
*
)
)
AnnotateBy
Value
);
(
int
(
*
)
(
const
void
*
,
const
void
*
)
)
AnnotateBy
Position
);
else
qsort
(
BaseListeCmp
,
NbOfCmp
,
sizeof
(
CmpListStruct
),
(
int
(
*
)
(
const
void
*
,
const
void
*
)
)
AnnotateByPosition
);
(
int
(
*
)
(
const
void
*
,
const
void
*
)
)
AnnotateByValue
);
/* Recalculate reference numbers */
ComputeReferenceNumber
(
BaseListeCmp
,
NbOfCmp
);
...
...
eeschema/annotate_dialog.cpp
View file @
945f5f1e
...
...
@@ -331,6 +331,9 @@ bool WinEDA_AnnotateFrame::GetResetItems( void )
}
bool
WinEDA_AnnotateFrame
::
GetSortOrder
(
void
)
/**
* @return true if annotation by position, false if annotation by value
*/
{
wxASSERT_MSG
(
(
m_rbSortByPosition
!=
NULL
)
&&
m_rbSortByPosition
->
IsKindOf
(
CLASSINFO
(
wxRadioButton
)
),
...
...
eeschema/class_drawsheet.cpp
View file @
945f5f1e
...
...
@@ -77,6 +77,82 @@ DrawSheetStruct::~DrawSheetStruct()
}
/**********************************************/
bool
DrawSheetStruct
::
Save
(
FILE
*
f
)
/***********************************************/
/* Routine utilisee dans la routine precedente.
Assure la sauvegarde de la structure LibItemStruct
*/
{
int
ii
;
bool
Failed
=
FALSE
;
DrawSheetLabelStruct
*
SheetLabel
;
fprintf
(
f
,
"$Sheet
\n
"
);
if
(
fprintf
(
f
,
"S %-4d %-4d %-4d %-4d
\n
"
,
m_Pos
.
x
,
m_Pos
.
y
,
m_Size
.
x
,
m_Size
.
y
)
==
EOF
){
Failed
=
TRUE
;
return
(
Failed
);
}
//save the unique timestamp, like other shematic parts.
if
(
fprintf
(
f
,
"U %8.8lX
\n
"
,
m_TimeStamp
)
==
EOF
){
Failed
=
TRUE
;
return
(
Failed
);
}
/* Generation de la liste des 2 textes (sheetname et filename) */
if
(
!
m_SheetName
.
IsEmpty
())
{
if
(
fprintf
(
f
,
"F0
\"
%s
\"
%d
\n
"
,
CONV_TO_UTF8
(
m_SheetName
),
m_SheetNameSize
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
}
if
(
!
GetFileName
().
IsEmpty
())
{
if
(
fprintf
(
f
,
"F1
\"
%s
\"
%d
\n
"
,
CONV_TO_UTF8
(
GetFileName
()),
m_FileNameSize
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
}
/* Generation de la liste des labels (entrees) de la sous feuille */
ii
=
2
;
SheetLabel
=
m_Label
;
while
(
SheetLabel
!=
NULL
)
{
int
type
=
'U'
,
side
=
'L'
;
if
(
SheetLabel
->
m_Text
.
IsEmpty
()
)
continue
;
if
(
SheetLabel
->
m_Edge
)
side
=
'R'
;
switch
(
SheetLabel
->
m_Shape
)
{
case
NET_INPUT
:
type
=
'I'
;
break
;
case
NET_OUTPUT
:
type
=
'O'
;
break
;
case
NET_BIDI
:
type
=
'B'
;
break
;
case
NET_TRISTATE
:
type
=
'T'
;
break
;
case
NET_UNSPECIFIED
:
type
=
'U'
;
break
;
}
if
(
fprintf
(
f
,
"F%d
\"
%s
\"
%c %c %-3d %-3d %-3d
\n
"
,
ii
,
CONV_TO_UTF8
(
SheetLabel
->
m_Text
),
type
,
side
,
SheetLabel
->
m_Pos
.
x
,
SheetLabel
->
m_Pos
.
y
,
SheetLabel
->
m_Size
.
x
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
ii
++
;
SheetLabel
=
(
DrawSheetLabelStruct
*
)
SheetLabel
->
Pnext
;
}
fprintf
(
f
,
"$EndSheet
\n
"
);
return
(
Failed
);
}
/***********************************************/
DrawSheetStruct
*
DrawSheetStruct
::
GenCopy
()
/***********************************************/
...
...
eeschema/class_drawsheet.h
0 → 100644
View file @
945f5f1e
/********************************************/
/* Definitions for the EESchema program: */
/********************************************/
#ifndef CLASS_DRAWSHEET_H
#define CLASS_DRAWSHEET_H
#ifndef eda_global
#define eda_global extern
#endif
#include "base_struct.h"
extern
DrawSheetStruct
*
g_RootSheet
;
class
DrawSheetLabelStruct
:
public
EDA_BaseStruct
,
public
EDA_TextStruct
{
public
:
int
m_Layer
;
int
m_Edge
,
m_Shape
;
bool
m_IsDangling
;
// TRUE non connected
public
:
DrawSheetLabelStruct
(
DrawSheetStruct
*
parent
,
const
wxPoint
&
pos
=
wxPoint
(
0
,
0
),
const
wxString
&
text
=
wxEmptyString
);
~
DrawSheetLabelStruct
()
{
}
virtual
wxString
GetClass
()
const
{
return
wxT
(
"DrawSheetLabelStruct"
);
}
DrawSheetLabelStruct
*
GenCopy
();
DrawSheetLabelStruct
*
Next
()
{
return
(
DrawSheetLabelStruct
*
)
Pnext
;
}
void
Place
(
WinEDA_DrawFrame
*
frame
,
wxDC
*
DC
);
virtual
void
Draw
(
WinEDA_DrawPanel
*
panel
,
wxDC
*
DC
,
const
wxPoint
&
offset
,
int
draw_mode
,
int
Color
=
-
1
);
};
/* class DrawSheetStruct
* This class is the sheet symbol placed in a schematic, and is the entry point for a sub schematic
*/
WX_DEFINE_ARRAY
(
DrawSheetStruct
*
,
SheetGrowArray
);
class
DrawSheetStruct
:
public
EDA_BaseStruct
/*public SCH_SCREEN*/
/* Gestion de la hierarchie */
{
public
:
wxString
m_SheetName
;
//this is equivalent to C101 for components:
// it is stored in F0 ... of the file.
private
:
wxString
m_FileName
;
//also in SCH_SCREEN (redundant),
//but need it here for loading after
//reading the sheet description from file.
public
:
int
m_SheetNameSize
;
// Size (height) of the text, used to draw the name
int
m_FileNameSize
;
// Size (height) of the text, used to draw the name
wxPoint
m_Pos
;
wxSize
m_Size
;
/* Position and Size of sheet symbol */
int
m_Layer
;
DrawSheetLabelStruct
*
m_Label
;
/* Points de connection, linked list.*/
int
m_NbLabel
;
/* Nombre de points de connexion */
SCH_SCREEN
*
m_AssociatedScreen
;
/* Associated Screen which handle the physical data
* In complex hierarchies we can have many DrawSheetStruct using the same data
*/
int
m_SheetNumber
;
// sheet number (used for info)
int
m_NumberOfSheets
;
// Sheets count in the whole schematic (used for info)
public
:
DrawSheetStruct
(
const
wxPoint
&
pos
=
wxPoint
(
0
,
0
)
);
~
DrawSheetStruct
();
virtual
wxString
GetClass
()
const
{
return
wxT
(
"DrawSheetStruct"
);
}
/** Function Save
* Write on file a DrawSheetStruct description
* @param f = output file
* return an error: false if ok, true if error
*/
bool
Save
(
FILE
*
f
);
void
Place
(
WinEDA_DrawFrame
*
frame
,
wxDC
*
DC
);
DrawSheetStruct
*
GenCopy
();
void
Display_Infos
(
WinEDA_DrawFrame
*
frame
);
void
CleanupSheet
(
WinEDA_SchematicFrame
*
frame
,
wxDC
*
DC
);
virtual
void
Draw
(
WinEDA_DrawPanel
*
panel
,
wxDC
*
DC
,
const
wxPoint
&
offset
,
int
draw_mode
,
int
Color
=
-
1
);
EDA_Rect
GetBoundingBox
();
void
SwapData
(
DrawSheetStruct
*
copyitem
);
void
DeleteAnnotation
(
bool
recurse
);
int
ComponentCount
();
bool
Load
(
WinEDA_SchematicFrame
*
frame
);
bool
SearchHierarchy
(
wxString
filename
,
SCH_SCREEN
**
screen
);
bool
LocatePathOfScreen
(
SCH_SCREEN
*
screen
,
DrawSheetPath
*
list
);
int
CountSheets
();
wxString
GetFileName
(
void
);
void
SetFileName
(
const
wxString
&
aFilename
);
// Set a new filename without changing anything else
bool
ChangeFileName
(
WinEDA_SchematicFrame
*
aFrame
,
const
wxString
&
aFileName
);
// Set a new filename and manage data and associated screen
//void RemoveSheet(DrawSheetStruct* sheet);
//to remove a sheet, just delete it
//-- the destructor should take care of everything else.
};
/**********************************************/
/* class to handle a series of sheets *********/
/* a 'path' so to speak.. *********************/
/**********************************************/
#define DSLSZ 32
class
DrawSheetPath
{
public
:
int
m_numSheets
;
DrawSheetStruct
*
m_sheets
[
DSLSZ
];
DrawSheetPath
();
~
DrawSheetPath
()
{
};
void
Clear
()
{
m_numSheets
=
0
;
}
int
Cmp
(
DrawSheetPath
&
d
);
DrawSheetStruct
*
Last
();
SCH_SCREEN
*
LastScreen
();
EDA_BaseStruct
*
LastDrawList
();
void
Push
(
DrawSheetStruct
*
sheet
);
DrawSheetStruct
*
Pop
();
wxString
Path
();
wxString
PathHumanReadable
();
void
UpdateAllScreenReferences
();
bool
operator
=
(
const
DrawSheetPath
&
d1
);
bool
operator
==
(
const
DrawSheetPath
&
d1
);
bool
operator
!=
(
const
DrawSheetPath
&
d1
);
};
/*******************************************************/
/* Class to handle the list of *Sheets* in a hierarchy */
/*******************************************************/
// sheets are not unique - can have many sheets with the same
// filename and the same SCH_SCREEN reference.
class
EDA_SheetList
{
private
:
DrawSheetPath
*
m_List
;
int
m_count
;
/* Number of sheets included in hierarchy,
* starting at the given sheet in constructor . the given sheet is counted
*/
int
m_index
;
DrawSheetPath
m_currList
;
public
:
EDA_SheetList
(
DrawSheetStruct
*
sheet
)
{
m_index
=
0
;
m_count
=
0
;
m_List
=
NULL
;
if
(
sheet
==
NULL
)
sheet
=
g_RootSheet
;
BuildSheetList
(
sheet
);
}
~
EDA_SheetList
()
{
if
(
m_List
)
{
free
(
m_List
);
}
m_List
=
NULL
;
}
int
GetCount
()
{
return
m_count
;
}
DrawSheetPath
*
GetFirst
();
DrawSheetPath
*
GetNext
();
DrawSheetPath
*
GetSheet
(
int
index
);
private
:
void
BuildSheetList
(
DrawSheetStruct
*
sheet
);
};
#endif
/* CLASS_DRAWSHEET_H */
eeschema/class_screen.cpp
View file @
945f5f1e
...
...
@@ -182,6 +182,14 @@ void SCH_SCREEN::AddToDrawList( EDA_BaseStruct* st )
/* Class EDA_ScreenList to handle the list of screens in a hierarchy */
/*********************************************************************/
/********************************/
EDA_ScreenList
::
EDA_ScreenList
()
/********************************/
{
m_Index
=
0
;
BuildScreenList
(
g_RootSheet
);
}
/*****************************************/
SCH_SCREEN
*
EDA_ScreenList
::
GetFirst
()
/*****************************************/
...
...
eeschema/class_screen.h
View file @
945f5f1e
...
...
@@ -16,11 +16,6 @@
#define NB_MAX_SHEET 500
/* Forward declarations */
class
DrawSheetStruct
;
extern
DrawSheetStruct
*
g_RootSheet
;
class
SCH_SCREEN
:
public
BASE_SCREEN
{
public
:
...
...
@@ -55,178 +50,6 @@ public:
};
class
DrawSheetLabelStruct
:
public
EDA_BaseStruct
,
public
EDA_TextStruct
{
public
:
int
m_Layer
;
int
m_Edge
,
m_Shape
;
bool
m_IsDangling
;
// TRUE non connected
public
:
DrawSheetLabelStruct
(
DrawSheetStruct
*
parent
,
const
wxPoint
&
pos
=
wxPoint
(
0
,
0
),
const
wxString
&
text
=
wxEmptyString
);
~
DrawSheetLabelStruct
()
{
}
virtual
wxString
GetClass
()
const
{
return
wxT
(
"DrawSheetLabelStruct"
);
}
DrawSheetLabelStruct
*
GenCopy
();
DrawSheetLabelStruct
*
Next
()
{
return
(
DrawSheetLabelStruct
*
)
Pnext
;
}
void
Place
(
WinEDA_DrawFrame
*
frame
,
wxDC
*
DC
);
virtual
void
Draw
(
WinEDA_DrawPanel
*
panel
,
wxDC
*
DC
,
const
wxPoint
&
offset
,
int
draw_mode
,
int
Color
=
-
1
);
};
/* class DrawSheetStruct
* This class is the sheet symbol placed in a schematic, and is the entry point for a sub schematic
*/
WX_DEFINE_ARRAY
(
DrawSheetStruct
*
,
SheetGrowArray
);
class
DrawSheetStruct
:
public
EDA_BaseStruct
/*public SCH_SCREEN*/
/* Gestion de la hierarchie */
{
public
:
wxString
m_SheetName
;
//this is equivalent to C101 for components:
// it is stored in F0 ... of the file.
private
:
wxString
m_FileName
;
//also in SCH_SCREEN (redundant),
//but need it here for loading after
//reading the sheet description from file.
public
:
int
m_SheetNameSize
;
// Size (height) of the text, used to draw the name
int
m_FileNameSize
;
// Size (height) of the text, used to draw the name
wxPoint
m_Pos
;
wxSize
m_Size
;
/* Position and Size of sheet symbol */
int
m_Layer
;
DrawSheetLabelStruct
*
m_Label
;
/* Points de connection, linked list.*/
int
m_NbLabel
;
/* Nombre de points de connexion */
SCH_SCREEN
*
m_AssociatedScreen
;
/* Associated Screen which handle the physical data
* In complex hierarchies we can have many DrawSheetStruct using the same data
*/
int
m_SheetNumber
;
// sheet number (used for info)
int
m_NumberOfSheets
;
// Sheets count in the whole schematic (used for info)
public
:
DrawSheetStruct
(
const
wxPoint
&
pos
=
wxPoint
(
0
,
0
)
);
~
DrawSheetStruct
();
virtual
wxString
GetClass
()
const
{
return
wxT
(
"DrawSheetStruct"
);
}
void
Place
(
WinEDA_DrawFrame
*
frame
,
wxDC
*
DC
);
DrawSheetStruct
*
GenCopy
();
void
Display_Infos
(
WinEDA_DrawFrame
*
frame
);
void
CleanupSheet
(
WinEDA_SchematicFrame
*
frame
,
wxDC
*
DC
);
virtual
void
Draw
(
WinEDA_DrawPanel
*
panel
,
wxDC
*
DC
,
const
wxPoint
&
offset
,
int
draw_mode
,
int
Color
=
-
1
);
EDA_Rect
GetBoundingBox
();
void
SwapData
(
DrawSheetStruct
*
copyitem
);
void
DeleteAnnotation
(
bool
recurse
);
int
ComponentCount
();
bool
Load
(
WinEDA_SchematicFrame
*
frame
);
bool
SearchHierarchy
(
wxString
filename
,
SCH_SCREEN
**
screen
);
bool
LocatePathOfScreen
(
SCH_SCREEN
*
screen
,
DrawSheetPath
*
list
);
int
CountSheets
();
wxString
GetFileName
(
void
);
void
SetFileName
(
const
wxString
&
aFilename
);
// Set a new filename without changing anything else
bool
ChangeFileName
(
WinEDA_SchematicFrame
*
aFrame
,
const
wxString
&
aFileName
);
// Set a new filename and manage data and associated screen
//void RemoveSheet(DrawSheetStruct* sheet);
//to remove a sheet, just delete it
//-- the destructor should take care of everything else.
};
/**********************************************/
/* class to handle a series of sheets *********/
/* a 'path' so to speak.. *********************/
/**********************************************/
#define DSLSZ 32
class
DrawSheetPath
{
public
:
int
m_numSheets
;
DrawSheetStruct
*
m_sheets
[
DSLSZ
];
DrawSheetPath
();
~
DrawSheetPath
()
{
};
void
Clear
()
{
m_numSheets
=
0
;
}
int
Cmp
(
DrawSheetPath
&
d
);
DrawSheetStruct
*
Last
();
SCH_SCREEN
*
LastScreen
();
EDA_BaseStruct
*
LastDrawList
();
void
Push
(
DrawSheetStruct
*
sheet
);
DrawSheetStruct
*
Pop
();
wxString
Path
();
wxString
PathHumanReadable
();
void
UpdateAllScreenReferences
();
bool
operator
=
(
const
DrawSheetPath
&
d1
);
bool
operator
==
(
const
DrawSheetPath
&
d1
);
bool
operator
!=
(
const
DrawSheetPath
&
d1
);
};
/*******************************************************/
/* Class to handle the list of *Sheets* in a hierarchy */
/*******************************************************/
// sheets are not unique - can have many sheets with the same
// filename and the same SCH_SCREEN reference.
class
EDA_SheetList
{
private
:
DrawSheetPath
*
m_List
;
int
m_count
;
/* Number of sheets included in hierarchy,
* starting at the given sheet in constructor . the given sheet is counted
*/
int
m_index
;
DrawSheetPath
m_currList
;
public
:
EDA_SheetList
(
DrawSheetStruct
*
sheet
)
{
m_index
=
0
;
m_count
=
0
;
m_List
=
NULL
;
if
(
sheet
==
NULL
)
sheet
=
g_RootSheet
;
BuildSheetList
(
sheet
);
}
~
EDA_SheetList
()
{
if
(
m_List
)
{
free
(
m_List
);
}
m_List
=
NULL
;
}
int
GetCount
()
{
return
m_count
;
}
DrawSheetPath
*
GetFirst
();
DrawSheetPath
*
GetNext
();
DrawSheetPath
*
GetSheet
(
int
index
);
private
:
void
BuildSheetList
(
DrawSheetStruct
*
sheet
);
};
/********************************************************/
/* Class to handle the list of *screens* in a hierarchy */
/********************************************************/
...
...
@@ -240,13 +63,7 @@ private:
unsigned
int
m_Index
;
public
:
EDA_ScreenList
()
{
m_Index
=
0
;
BuildScreenList
(
g_RootSheet
);
}
EDA_ScreenList
();
~
EDA_ScreenList
()
{
}
int
GetCount
()
{
return
m_List
.
GetCount
();
}
SCH_SCREEN
*
GetFirst
();
...
...
eeschema/component_class.cpp
View file @
945f5f1e
...
...
@@ -25,6 +25,18 @@ WX_DEFINE_OBJARRAY( ArrayOfSheetLists );
/* class SCH_COMPONENT */
/***************************/
/** Function AddHierarchicalReference
* Add a full hierachical reference (path + local reference)
* @param path = hierarchical path (/<sheet timestamp>/component timestamp> like /05678E50/A23EF560)
* @param ref = local reference like C45, R56
*/
void
SCH_COMPONENT
::
AddHierarchicalReference
(
const
wxString
&
path
,
const
wxString
&
ref
)
{
m_Paths
.
Add
(
path
);
m_References
.
Add
(
ref
);
}
/****************************************************************/
const
wxString
&
ReturnDefaultFieldName
(
int
aFieldNdx
)
/****************************************************************/
...
...
@@ -118,7 +130,7 @@ const wxString SCH_COMPONENT::GetRef( DrawSheetPath* sheet )
/***********************************************************************/
void
SCH_COMPONENT
::
SetRef
(
DrawSheetPath
*
sheet
,
wxString
ref
)
void
SCH_COMPONENT
::
SetRef
(
DrawSheetPath
*
sheet
,
const
wxString
&
ref
)
/***********************************************************************/
{
//check to see if it is already there before inserting it
...
...
@@ -127,6 +139,7 @@ void SCH_COMPONENT::SetRef( DrawSheetPath* sheet, wxString ref )
// printf( "SetRef path: %s ref: %s\n", CONV_TO_UTF8( path ), CONV_TO_UTF8( ref ) ); // Debug
unsigned
int
i
;
bool
notInArray
=
true
;
for
(
i
=
0
;
i
<
m_Paths
.
GetCount
();
i
++
)
{
if
(
m_Paths
[
i
].
Cmp
(
path
)
==
0
)
...
...
@@ -162,6 +175,7 @@ void SCH_COMPONENT::ClearRefs()
{
m_Paths
.
Empty
();
m_References
.
Empty
();
m_PartPerPackageSelections
.
Empty
();
}
...
...
@@ -210,8 +224,6 @@ SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos ) :
m_Field
[
VALUE
].
m_Layer
=
LAYER_VALUEPART
;
m_Field
[
REFERENCE
].
m_Layer
=
LAYER_REFERENCEPART
;
m_PinIsDangling
=
NULL
;
m_PrefixString
=
wxString
(
_
(
"U"
)
);
}
...
...
@@ -364,7 +376,14 @@ void SCH_COMPONENT::ClearAnnotation()
Entry
=
FindLibPart
(
m_ChipName
.
GetData
(),
wxEmptyString
,
FIND_ROOT
);
if
(
!
Entry
||
!
Entry
->
m_UnitSelectionLocked
)
{
m_Multi
=
1
;
m_PartPerPackageSelections
.
Empty
();
for
(
i
=
0
;
i
<
m_Paths
.
GetCount
();
i
++
)
{
m_PartPerPackageSelections
.
Add
(
wxT
(
"1"
)
);
}
}
}
...
...
@@ -512,7 +531,8 @@ void SCH_COMPONENT::SetRotationMiroir( int type_rotate )
}
if
(
Transform
)
{
/* The new matrix transform is the old matrix transform modified by the
{
/* The new matrix transform is the old matrix transform modified by the
* requested transformation, which is the TempMat transform (rot, mirror ..)
* in order to have (in term of matrix transform):
* transform coord = new_m_Transform * coord
...
...
@@ -666,8 +686,8 @@ void SCH_COMPONENT::Show( int nestLevel, std::ostream& os )
/***************************************************************************/
PartTextStruct
::
PartTextStruct
(
const
wxPoint
&
pos
,
const
wxString
&
text
)
:
EDA_BaseStruct
(
DRAW_PART_TEXT_STRUCT_TYPE
)
,
EDA_TextStruct
(
text
)
EDA_BaseStruct
(
DRAW_PART_TEXT_STRUCT_TYPE
)
,
EDA_TextStruct
(
text
)
/***************************************************************************/
{
m_Pos
=
pos
;
...
...
@@ -822,3 +842,146 @@ EDA_Rect PartTextStruct::GetBoundaryBox() const
return
BoundaryBox
;
}
/**********************************/
bool
SCH_COMPONENT
::
Save
(
FILE
*
f
)
/**********************************/
/** Function Save
* Write on file a SCH_COMPONENT decscription
* @param f = output file
* return an error: false if ok, true if error
*/
{
int
ii
,
Failed
=
FALSE
;
char
Name1
[
256
],
Name2
[
256
];
int
hjustify
,
vjustify
;
//this is redundant with the AR entries below, but it makes the
//files backwards-compatible.
if
(
m_References
.
GetCount
()
>
0
)
strncpy
(
Name1
,
CONV_TO_UTF8
(
m_References
[
0
]
),
sizeof
(
Name1
)
);
else
{
if
(
m_Field
[
REFERENCE
].
m_Text
.
IsEmpty
()
)
strncpy
(
Name1
,
CONV_TO_UTF8
(
m_PrefixString
),
sizeof
(
Name1
)
);
else
strncpy
(
Name1
,
CONV_TO_UTF8
(
m_Field
[
REFERENCE
].
m_Text
),
sizeof
(
Name1
)
);
}
for
(
ii
=
0
;
ii
<
(
int
)
strlen
(
Name1
);
ii
++
)
{
if
(
Name1
[
ii
]
<=
' '
)
Name1
[
ii
]
=
'~'
;
}
if
(
!
m_ChipName
.
IsEmpty
()
)
{
strncpy
(
Name2
,
CONV_TO_UTF8
(
m_ChipName
),
sizeof
(
Name2
)
);
for
(
ii
=
0
;
ii
<
(
int
)
strlen
(
Name2
);
ii
++
)
if
(
Name2
[
ii
]
<=
' '
)
Name2
[
ii
]
=
'~'
;
}
else
strncpy
(
Name2
,
NULL_STRING
,
sizeof
(
Name2
)
);
fprintf
(
f
,
"$Comp
\n
"
);
if
(
fprintf
(
f
,
"L %s %s
\n
"
,
Name2
,
Name1
)
==
EOF
)
{
Failed
=
TRUE
;
return
Failed
;
}
/* Generation de numero d'unit, convert et Time Stamp*/
if
(
fprintf
(
f
,
"U %d %d %8.8lX
\n
"
,
m_Multi
,
m_Convert
,
m_TimeStamp
)
==
EOF
)
{
Failed
=
TRUE
;
return
Failed
;
}
/* Sortie de la position */
if
(
fprintf
(
f
,
"P %d %d
\n
"
,
m_Pos
.
x
,
m_Pos
.
y
)
==
EOF
)
{
Failed
=
TRUE
;
return
Failed
;
}
unsigned
int
i
;
for
(
i
=
0
;
i
<
m_References
.
GetCount
();
i
++
)
{
/*format:
* AR Path="/140/2" Ref="C99"
* where 140 is the uid of the contianing sheet
* and 2 is the timestamp of this component.
* (timestamps are actually 8 hex chars)
* Ref is the conventional component reference for this 'path'
*/
if
(
fprintf
(
f
,
"AR Path=
\"
%s
\"
Ref=
\"
%s
\"
\n
"
,
CONV_TO_UTF8
(
m_Paths
[
i
]
),
CONV_TO_UTF8
(
m_References
[
i
]
)
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
}
for
(
ii
=
0
;
ii
<
NUMBER_OF_FIELDS
;
ii
++
)
{
PartTextStruct
*
field
=
&
m_Field
[
ii
];
if
(
field
->
m_Text
.
IsEmpty
()
)
continue
;
hjustify
=
'C'
;
if
(
field
->
m_HJustify
==
GR_TEXT_HJUSTIFY_LEFT
)
hjustify
=
'L'
;
else
if
(
field
->
m_HJustify
==
GR_TEXT_HJUSTIFY_RIGHT
)
hjustify
=
'R'
;
vjustify
=
'C'
;
if
(
field
->
m_VJustify
==
GR_TEXT_VJUSTIFY_BOTTOM
)
vjustify
=
'B'
;
else
if
(
field
->
m_VJustify
==
GR_TEXT_VJUSTIFY_TOP
)
vjustify
=
'T'
;
if
(
fprintf
(
f
,
"F %d
\"
%s
\"
%c %-3d %-3d %-3d %4.4X %c %c"
,
ii
,
CONV_TO_UTF8
(
field
->
m_Text
),
field
->
m_Orient
==
TEXT_ORIENT_HORIZ
?
'H'
:
'V'
,
field
->
m_Pos
.
x
,
field
->
m_Pos
.
y
,
field
->
m_Size
.
x
,
field
->
m_Attributs
,
hjustify
,
vjustify
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
// Save field name, if necessary
if
(
ii
>=
FIELD1
&&
!
field
->
m_Name
.
IsEmpty
()
)
{
wxString
fieldname
=
ReturnDefaultFieldName
(
ii
);
if
(
fieldname
!=
field
->
m_Name
)
if
(
fprintf
(
f
,
"
\"
%s
\"
"
,
CONV_TO_UTF8
(
field
->
m_Name
)
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
}
if
(
fprintf
(
f
,
"
\n
"
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
}
if
(
Failed
)
return
Failed
;
/* Generation du num unit, position, box ( ancienne norme )*/
if
(
fprintf
(
f
,
"
\t
%-4d %-4d %-4d
\n
"
,
m_Multi
,
m_Pos
.
x
,
m_Pos
.
y
)
==
EOF
)
{
Failed
=
TRUE
;
return
Failed
;
}
if
(
fprintf
(
f
,
"
\t
%-4d %-4d %-4d %-4d
\n
"
,
m_Transform
[
0
][
0
],
m_Transform
[
0
][
1
],
m_Transform
[
1
][
0
],
m_Transform
[
1
][
1
]
)
==
EOF
)
{
Failed
=
TRUE
;
return
Failed
;
}
fprintf
(
f
,
"$EndComp
\n
"
);
return
Failed
;
}
eeschema/component_class.h
View file @
945f5f1e
...
...
@@ -79,20 +79,20 @@ public:
wxPoint
m_Pos
;
wxString
m_ChipName
;
/* Key to look for in the library, i.e. "74LS00". */
wxString
m_PrefixString
;
/* C, R, U, Q etc - the first character which typically indicates what the component is.
* determined, upon placement, from the library component.
* determined, upon file load, by the first non-digits in the reference fields. */
PartTextStruct
m_Field
[
NUMBER_OF_FIELDS
];
//int m_FlagControlMulti;
ArrayOfSheetLists
m_UsedOnSheets
;
ArrayOfSheetLists
m_UsedOnSheets
;
// Used as flags when calculating netlist
int
m_Convert
;
/* Gestion (management) des mutiples representations (ex: conversion De Morgan) */
int
m_Transform
[
2
][
2
];
/* The rotation/mirror transformation matrix. */
bool
*
m_PinIsDangling
;
// liste des indicateurs de pin non connectee
private
:
wxArrayString
m_Paths
;
// /sheet1/C102, /sh2/sh1/U32 etc.
wxArrayString
m_References
;
// C102, U32 etc.
wxArrayString
m_PartPerPackageSelections
;
// "1", "2" etc. when a component has more than 1 partper package
wxString
m_PrefixString
;
/* C, R, U, Q etc - the first character which typically indicates what the component is.
* determined, upon placement, from the library component.
* determined, upon file load, by the first non-digits in the reference fields. */
public
:
SCH_COMPONENT
(
const
wxPoint
&
pos
=
wxPoint
(
0
,
0
)
);
...
...
@@ -103,6 +103,12 @@ public:
return
wxT
(
"SCH_COMPONENT"
);
}
/** Function Save
* Write on file a SCH_COMPONENT decscription
* @param f = output file
* return an error: false if ok, true if error
*/
bool
Save
(
FILE
*
f
);
SCH_COMPONENT
*
GenCopy
();
void
SetRotationMiroir
(
int
type
);
...
...
@@ -138,8 +144,11 @@ public:
//returns a unique ID, in the form of a path.
wxString
GetPath
(
DrawSheetPath
*
sheet
);
const
wxString
GetRef
(
DrawSheetPath
*
sheet
);
void
SetRef
(
DrawSheetPath
*
sheet
,
wxString
ref
);
void
SetRef
(
DrawSheetPath
*
sheet
,
const
wxString
&
ref
);
void
ClearRefs
();
void
AddHierarchicalReference
(
const
wxString
&
path
,
const
wxString
&
ref
);
int
GetUnitSelection
(
DrawSheetPath
*
aSheet
);
void
SetUnitSelection
(
DrawSheetPath
*
aSheet
,
int
aUnitSelection
);
#if defined (DEBUG)
...
...
eeschema/load_one_schematic_file.cpp
View file @
945f5f1e
...
...
@@ -3,7 +3,7 @@
/****************************************/
#include "fctsys.h"
#include "gr_basic.h"
//
#include "gr_basic.h"
#include "common.h"
#include "program.h"
...
...
@@ -633,8 +633,7 @@ static int ReadPartDescr( wxWindow* frame, char* Line, FILE* f,
Name1
[
j
]
=
0
;
wxString
ref
=
CONV_FROM_UTF8
(
Name1
);
LibItemStruct
->
m_Paths
.
Add
(
path
);
LibItemStruct
->
m_References
.
Add
(
ref
);
LibItemStruct
->
AddHierarchicalReference
(
path
,
ref
);
LibItemStruct
->
m_Field
[
REFERENCE
].
m_Text
=
ref
;
}
if
(
Line
[
0
]
==
'F'
)
...
...
eeschema/netform.cpp
View file @
945f5f1e
...
...
@@ -351,7 +351,7 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
/********************************************************/
static
void
ClearUsedFlags
(
WinEDA_SchematicFrame
*
frame
)
/********************************************************/
/* Clear flag
FlagControlMulti
, used in netlist generation */
/* Clear flag
list
, used in netlist generation */
{
SCH_SCREEN
*
screen
;
EDA_BaseStruct
*
DrawList
;
...
...
eeschema/program.h
View file @
945f5f1e
...
...
@@ -14,6 +14,7 @@
#include "component_class.h"
#include "class_screen.h"
#include "class_drawsheet.h"
#include "class_text-label.h"
#define DRAWJUNCTION_SIZE 16
/* Rayon du symbole connexion */
...
...
eeschema/save_schemas.cpp
View file @
945f5f1e
...
...
@@ -20,8 +20,6 @@
/* Fonctions externes */
/* Fonctions Locales */
static
int
SavePartDescr
(
FILE
*
f
,
SCH_COMPONENT
*
LibItemStruct
);
static
int
SaveSheetDescr
(
FILE
*
f
,
DrawSheetStruct
*
SheetStruct
);
static
void
SaveLayers
(
FILE
*
f
);
/* Variables locales */
...
...
@@ -146,11 +144,11 @@ bool WinEDA_SchematicFrame::SaveEEFile(SCH_SCREEN *screen, int FileSave)
switch
(
Phead
->
Type
())
{
case
TYPE_SCH_COMPONENT
:
/* Its a library item. */
SavePartDescr
(
f
,
(
SCH_COMPONENT
*
)
Phead
);
((
SCH_COMPONENT
*
)
Phead
)
->
Save
(
f
);
break
;
case
DRAW_SHEET_STRUCT_TYPE
:
/* Its a Sheet item. */
SaveSheetDescr
(
f
,
(
DrawSheetStruct
*
)
Phead
);
((
DrawSheetStruct
*
)
Phead
)
->
Save
(
f
);
break
;
case
DRAW_SEGMENT_STRUCT_TYPE
:
/* Its a Segment item. */
...
...
@@ -323,222 +321,6 @@ bool WinEDA_SchematicFrame::SaveEEFile(SCH_SCREEN *screen, int FileSave)
}
/*******************************************************************/
static
int
SavePartDescr
(
FILE
*
f
,
SCH_COMPONENT
*
LibItemStruct
)
/*******************************************************************/
/* Routine utilisee dans la routine precedente.
Assure la sauvegarde de la structure LibItemStruct
*/
{
int
ii
,
Failed
=
FALSE
;
char
Name1
[
256
],
Name2
[
256
];
int
hjustify
,
vjustify
;
//this is redundant with the AR entries below, but it makes the
//files backwards-compatible.
if
(
LibItemStruct
->
m_References
.
GetCount
()
>
0
)
strncpy
(
Name1
,
CONV_TO_UTF8
(
LibItemStruct
->
m_References
[
0
]),
sizeof
(
Name1
));
else
{
if
(
LibItemStruct
->
m_Field
[
REFERENCE
].
m_Text
.
IsEmpty
())
strncpy
(
Name1
,
CONV_TO_UTF8
(
LibItemStruct
->
m_PrefixString
),
sizeof
(
Name1
));
else
strncpy
(
Name1
,
CONV_TO_UTF8
(
LibItemStruct
->
m_Field
[
REFERENCE
].
m_Text
),
sizeof
(
Name1
));
}
for
(
ii
=
0
;
ii
<
(
int
)
strlen
(
Name1
);
ii
++
){
if
(
Name1
[
ii
]
<=
' '
)
Name1
[
ii
]
=
'~'
;
}
if
(
!
LibItemStruct
->
m_ChipName
.
IsEmpty
()
)
{
strncpy
(
Name2
,
CONV_TO_UTF8
(
LibItemStruct
->
m_ChipName
),
sizeof
(
Name2
));
for
(
ii
=
0
;
ii
<
(
int
)
strlen
(
Name2
);
ii
++
)
if
(
Name2
[
ii
]
<=
' '
)
Name2
[
ii
]
=
'~'
;
}
else
strncpy
(
Name2
,
NULL_STRING
,
sizeof
(
Name2
));
fprintf
(
f
,
"$Comp
\n
"
);
if
(
fprintf
(
f
,
"L %s %s
\n
"
,
Name2
,
Name1
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
/* Generation de numero d'unit, convert et Time Stamp*/
if
(
fprintf
(
f
,
"U %d %d %8.8lX
\n
"
,
LibItemStruct
->
m_Multi
,
LibItemStruct
->
m_Convert
,
LibItemStruct
->
m_TimeStamp
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
/* Sortie de la position */
if
(
fprintf
(
f
,
"P %d %d
\n
"
,
LibItemStruct
->
m_Pos
.
x
,
LibItemStruct
->
m_Pos
.
y
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
unsigned
int
i
;
for
(
i
=
0
;
i
<
LibItemStruct
->
m_References
.
GetCount
();
i
++
){
/*format:
AR Path="/140/2" Ref="C99"
where 140 is the uid of the contianing sheet
and 2 is the timestamp of this component.
(timestamps are actually 8 hex chars)
Ref is the conventional component reference for this 'path'
*/
/*printf("AR Path=\"%s\" Ref=\"%s\" \n",
CONV_TO_UTF8( LibItemStruct->m_Paths[i]),
CONV_TO_UTF8( LibItemStruct->m_References[i] ) ); */
if
(
fprintf
(
f
,
"AR Path=
\"
%s
\"
Ref=
\"
%s
\"
\n
"
,
CONV_TO_UTF8
(
LibItemStruct
->
m_Paths
[
i
]),
CONV_TO_UTF8
(
LibItemStruct
->
m_References
[
i
]
)
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
}
for
(
ii
=
0
;
ii
<
NUMBER_OF_FIELDS
;
ii
++
)
{
PartTextStruct
*
field
=
&
LibItemStruct
->
m_Field
[
ii
];
if
(
field
->
m_Text
.
IsEmpty
()
)
continue
;
hjustify
=
'C'
;
if
(
field
->
m_HJustify
==
GR_TEXT_HJUSTIFY_LEFT
)
hjustify
=
'L'
;
else
if
(
field
->
m_HJustify
==
GR_TEXT_HJUSTIFY_RIGHT
)
hjustify
=
'R'
;
vjustify
=
'C'
;
if
(
field
->
m_VJustify
==
GR_TEXT_VJUSTIFY_BOTTOM
)
vjustify
=
'B'
;
else
if
(
field
->
m_VJustify
==
GR_TEXT_VJUSTIFY_TOP
)
vjustify
=
'T'
;
if
(
fprintf
(
f
,
"F %d
\"
%s
\"
%c %-3d %-3d %-3d %4.4X %c %c"
,
ii
,
CONV_TO_UTF8
(
field
->
m_Text
),
field
->
m_Orient
==
TEXT_ORIENT_HORIZ
?
'H'
:
'V'
,
field
->
m_Pos
.
x
,
field
->
m_Pos
.
y
,
field
->
m_Size
.
x
,
field
->
m_Attributs
,
hjustify
,
vjustify
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
// Save field name, if necessary
if
(
ii
>=
FIELD1
&&
!
field
->
m_Name
.
IsEmpty
()
)
{
wxString
fieldname
=
ReturnDefaultFieldName
(
ii
);
if
(
fieldname
!=
field
->
m_Name
)
if
(
fprintf
(
f
,
"
\"
%s
\"
"
,
CONV_TO_UTF8
(
field
->
m_Name
)
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
}
if
(
fprintf
(
f
,
"
\n
"
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
}
if
(
Failed
)
return
(
Failed
);
/* Generation du num unit, position, box ( ancienne norme )*/
if
(
fprintf
(
f
,
"
\t
%-4d %-4d %-4d
\n
"
,
LibItemStruct
->
m_Multi
,
LibItemStruct
->
m_Pos
.
x
,
LibItemStruct
->
m_Pos
.
y
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
if
(
fprintf
(
f
,
"
\t
%-4d %-4d %-4d %-4d
\n
"
,
LibItemStruct
->
m_Transform
[
0
][
0
],
LibItemStruct
->
m_Transform
[
0
][
1
],
LibItemStruct
->
m_Transform
[
1
][
0
],
LibItemStruct
->
m_Transform
[
1
][
1
])
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
fprintf
(
f
,
"$EndComp
\n
"
);
return
(
Failed
);
}
/*******************************************************************/
static
int
SaveSheetDescr
(
FILE
*
f
,
DrawSheetStruct
*
SheetStruct
)
/*******************************************************************/
/* Routine utilisee dans la routine precedente.
Assure la sauvegarde de la structure LibItemStruct
*/
{
int
ii
;
int
Failed
=
FALSE
;
DrawSheetLabelStruct
*
SheetLabel
;
fprintf
(
f
,
"$Sheet
\n
"
);
if
(
fprintf
(
f
,
"S %-4d %-4d %-4d %-4d
\n
"
,
SheetStruct
->
m_Pos
.
x
,
SheetStruct
->
m_Pos
.
y
,
SheetStruct
->
m_Size
.
x
,
SheetStruct
->
m_Size
.
y
)
==
EOF
){
Failed
=
TRUE
;
return
(
Failed
);
}
//save the unique timestamp, like other shematic parts.
if
(
fprintf
(
f
,
"U %8.8lX
\n
"
,
SheetStruct
->
m_TimeStamp
)
==
EOF
){
Failed
=
TRUE
;
return
(
Failed
);
}
/* Generation de la liste des 2 textes (sheetname et filename) */
if
(
!
SheetStruct
->
m_SheetName
.
IsEmpty
())
{
if
(
fprintf
(
f
,
"F0
\"
%s
\"
%d
\n
"
,
CONV_TO_UTF8
(
SheetStruct
->
m_SheetName
),
SheetStruct
->
m_SheetNameSize
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
}
if
(
!
SheetStruct
->
GetFileName
().
IsEmpty
())
{
if
(
fprintf
(
f
,
"F1
\"
%s
\"
%d
\n
"
,
CONV_TO_UTF8
(
SheetStruct
->
GetFileName
()),
SheetStruct
->
m_FileNameSize
)
==
EOF
)
{
Failed
=
TRUE
;
return
(
Failed
);
}
}
/* Generation de la liste des labels (entrees) de la sous feuille */
ii
=
2
;
SheetLabel
=
SheetStruct
->
m_Label
;
while
(
SheetLabel
!=
NULL
)
{
int
type
=
'U'
,
side
=
'L'
;
if
(
SheetLabel
->
m_Text
.
IsEmpty
()
)
continue
;
if
(
SheetLabel
->
m_Edge
)
side
=
'R'
;
switch
(
SheetLabel
->
m_Shape
)
{
case
NET_INPUT
:
type
=
'I'
;
break
;
case
NET_OUTPUT
:
type
=
'O'
;
break
;
case
NET_BIDI
:
type
=
'B'
;
break
;
case
NET_TRISTATE
:
type
=
'T'
;
break
;
case
NET_UNSPECIFIED
:
type
=
'U'
;
break
;
}
if
(
fprintf
(
f
,
"F%d
\"
%s
\"
%c %c %-3d %-3d %-3d
\n
"
,
ii
,
CONV_TO_UTF8
(
SheetLabel
->
m_Text
),
type
,
side
,
SheetLabel
->
m_Pos
.
x
,
SheetLabel
->
m_Pos
.
y
,
SheetLabel
->
m_Size
.
x
)
==
EOF
)
{
Failed
=
TRUE
;
break
;
}
ii
++
;
SheetLabel
=
(
DrawSheetLabelStruct
*
)
SheetLabel
->
Pnext
;
}
fprintf
(
f
,
"$EndSheet
\n
"
);
return
(
Failed
);
}
/****************************/
static
void
SaveLayers
(
FILE
*
f
)
/****************************/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment