1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2015 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-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 
26 #include <pgm_base.h>
27 #include <sch_draw_panel.h>
28 #include <sch_edit_frame.h>
29 #include <symbol_edit_frame.h>
30 #include <lib_pin.h>
31 #include <settings/settings_manager.h>
32 #include <symbol_editor/symbol_editor_settings.h>
33 #include <trigo.h>
34 #include <string_utils.h>
35 #include "sch_painter.h"
36 
37 // small margin in internal units between the pin text and the pin line
38 #define PIN_TEXT_MARGIN 4
39 
GetCanonicalElectricalTypeName(ELECTRICAL_PINTYPE aType)40 const wxString LIB_PIN::GetCanonicalElectricalTypeName( ELECTRICAL_PINTYPE aType )
41 {
42     // These strings are the canonical name of the electrictal type
43     // Not translated, no space in name, only ASCII chars.
44     // to use when the string name must be known and well defined
45     // must have same order than enum ELECTRICAL_PINTYPE (see lib_pin.h)
46     static const wxChar* msgPinElectricType[] =
47     {
48         wxT( "input" ),
49         wxT( "output" ),
50         wxT( "bidirectional" ),
51         wxT( "tri_state" ),
52         wxT( "passive" ),
53         wxT( "free" ),
54         wxT( "unspecified" ),
55         wxT( "power_in" ),
56         wxT( "power_out" ),
57         wxT( "open_collector" ),
58         wxT( "open_emitter" ),
59         wxT( "no_connect" )
60     };
61 
62     return msgPinElectricType[static_cast<int>( aType )];
63 }
64 
65 
66 /// Utility for getting the size of the 'internal' pin decorators (as a radius)
67 // i.e. the clock symbols (falling clock is actually external but is of
68 // the same kind)
69 
internalPinDecoSize(const RENDER_SETTINGS * aSettings,const LIB_PIN & aPin)70 static int internalPinDecoSize( const RENDER_SETTINGS* aSettings, const LIB_PIN &aPin )
71 {
72     const KIGFX::SCH_RENDER_SETTINGS* settings = static_cast<const KIGFX::SCH_RENDER_SETTINGS*>( aSettings );
73 
74     if( settings && settings->m_PinSymbolSize )
75         return settings->m_PinSymbolSize;
76 
77     return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
78 }
79 
80 /// Utility for getting the size of the 'external' pin decorators (as a radius)
81 // i.e. the negation circle, the polarity 'slopes' and the nonlogic
82 // marker
externalPinDecoSize(const RENDER_SETTINGS * aSettings,const LIB_PIN & aPin)83 static int externalPinDecoSize( const RENDER_SETTINGS* aSettings, const LIB_PIN &aPin )
84 {
85     const KIGFX::SCH_RENDER_SETTINGS* settings = static_cast<const KIGFX::SCH_RENDER_SETTINGS*>( aSettings );
86 
87     if( settings && settings->m_PinSymbolSize )
88         return settings->m_PinSymbolSize;
89 
90     return aPin.GetNumberTextSize() / 2;
91 }
92 
93 
LIB_PIN(LIB_SYMBOL * aParent)94 LIB_PIN::LIB_PIN( LIB_SYMBOL* aParent ) :
95         LIB_ITEM( LIB_PIN_T, aParent ),
96         m_orientation( PIN_RIGHT ),
97         m_shape( GRAPHIC_PINSHAPE::LINE ),
98         m_type( ELECTRICAL_PINTYPE::PT_UNSPECIFIED ),
99         m_attributes( 0 )
100 {
101     // Use the application settings for pin sizes if exists.
102     // pgm can be nullptr when running a shared lib from a script, not from a kicad appl
103     PGM_BASE* pgm  = PgmOrNull();
104 
105     if( pgm )
106     {
107         auto* settings = pgm->GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
108         m_length       = Mils2iu( settings->m_Defaults.pin_length );
109         m_numTextSize  = Mils2iu( settings->m_Defaults.pin_num_size );
110         m_nameTextSize = Mils2iu( settings->m_Defaults.pin_name_size );
111     }
112     else    // Use hardcoded eeschema defaults: symbol_editor settings are not existing.
113     {
114         m_length       = Mils2iu( DEFAULT_PIN_LENGTH );
115         m_numTextSize  = Mils2iu( DEFAULT_PINNUM_SIZE );
116         m_nameTextSize = Mils2iu( DEFAULT_PINNAME_SIZE );
117     }
118 }
119 
120 
LIB_PIN(LIB_SYMBOL * aParent,const wxString & aName,const wxString & aNumber,int aOrientation,ELECTRICAL_PINTYPE aPinType,int aLength,int aNameTextSize,int aNumTextSize,int aConvert,const wxPoint & aPos,int aUnit)121 LIB_PIN::LIB_PIN( LIB_SYMBOL* aParent, const wxString& aName, const wxString& aNumber,
122                   int aOrientation, ELECTRICAL_PINTYPE aPinType, int aLength, int aNameTextSize,
123                   int aNumTextSize, int aConvert, const wxPoint& aPos, int aUnit ) :
124         LIB_ITEM( LIB_PIN_T, aParent ),
125         m_position( aPos ),
126         m_length( aLength ),
127         m_orientation( aOrientation ),
128         m_shape( GRAPHIC_PINSHAPE::LINE ),
129         m_type( aPinType ),
130         m_attributes( 0 ),
131         m_numTextSize( aNumTextSize ),
132         m_nameTextSize( aNameTextSize )
133 {
134     SetName( aName );
135     SetNumber( aNumber );
136     SetUnit( aUnit );
137     SetConvert( aConvert );
138 }
139 
140 
HitTest(const wxPoint & aPosition,int aAccuracy) const141 bool LIB_PIN::HitTest( const wxPoint& aPosition, int aAccuracy ) const
142 {
143     EDA_RECT rect = GetBoundingBox();
144 
145     return rect.Inflate( aAccuracy ).Contains( aPosition );
146 }
147 
148 
HitTest(const EDA_RECT & aRect,bool aContained,int aAccuracy) const149 bool LIB_PIN::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
150 {
151     if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) )
152         return false;
153 
154     EDA_RECT sel = aRect;
155 
156     if ( aAccuracy )
157         sel.Inflate( aAccuracy );
158 
159     if( aContained )
160         return sel.Contains( GetBoundingBox( false, true ) );
161 
162     return sel.Intersects( GetBoundingBox( false, true ) );
163 }
164 
165 
GetPenWidth() const166 int LIB_PIN::GetPenWidth() const
167 {
168     return 0;
169 }
170 
171 
GetShownName() const172 wxString LIB_PIN::GetShownName() const
173 {
174     if( m_name == "~" )
175         return wxEmptyString;
176     else
177         return m_name;
178 }
179 
180 
GetPinRoot() const181 wxPoint LIB_PIN::GetPinRoot() const
182 {
183     switch( m_orientation )
184     {
185     default:
186     case PIN_RIGHT: return wxPoint( m_position.x + m_length, -( m_position.y ) );
187     case PIN_LEFT:  return wxPoint( m_position.x - m_length, -( m_position.y ) );
188     case PIN_UP:    return wxPoint( m_position.x, -( m_position.y + m_length ) );
189     case PIN_DOWN:  return wxPoint( m_position.x, -( m_position.y - m_length ) );
190     }
191 }
192 
193 
print(const RENDER_SETTINGS * aSettings,const wxPoint & aOffset,void * aData,const TRANSFORM & aTransform)194 void LIB_PIN::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData,
195                      const TRANSFORM& aTransform )
196 {
197     LIB_SYMBOL_OPTIONS* opts = (LIB_SYMBOL_OPTIONS*) aData;
198     bool                drawHiddenFields   = opts ? opts->draw_hidden_fields : false;
199     bool                showPinType        = opts ? opts->show_elec_type     : false;
200     bool                show_connect_point = opts ? opts->show_connect_point : false;
201 
202     LIB_SYMBOL* part = GetParent();
203 
204     /* Calculate pin orient taking in account the symbol orientation. */
205     int orient = PinDrawOrient( aTransform );
206 
207     /* Calculate the pin position */
208     wxPoint pos1 = aTransform.TransformCoordinate( m_position ) + aOffset;
209 
210     if( IsVisible() || drawHiddenFields )
211     {
212         printPinSymbol( aSettings, pos1, orient );
213 
214         printPinTexts( aSettings, pos1, orient, part->GetPinNameOffset(), part->ShowPinNumbers(),
215                        part->ShowPinNames() );
216 
217         if( showPinType )
218             printPinElectricalTypeName( aSettings, pos1, orient );
219 
220         if( show_connect_point
221                 && m_type != ELECTRICAL_PINTYPE::PT_NC
222                 && m_type != ELECTRICAL_PINTYPE::PT_NIC )
223         {
224             wxDC* DC = aSettings->GetPrintDC();
225             COLOR4D color = aSettings->GetLayerColor( IsVisible() ? LAYER_PIN : LAYER_HIDDEN );
226             GRCircle( nullptr, DC, pos1.x, pos1.y, TARGET_PIN_RADIUS, 0, color );
227         }
228     }
229 }
230 
231 
printPinSymbol(const RENDER_SETTINGS * aSettings,const wxPoint & aPos,int aOrient)232 void LIB_PIN::printPinSymbol( const RENDER_SETTINGS* aSettings, const wxPoint& aPos, int aOrient )
233 {
234     wxDC*   DC = aSettings->GetPrintDC();
235     int     MapX1, MapY1, x1, y1;
236     int     width = GetEffectivePenWidth( aSettings );
237     int     posX = aPos.x, posY = aPos.y, len = m_length;
238     COLOR4D color = aSettings->GetLayerColor( IsVisible() ? LAYER_PIN : LAYER_HIDDEN );
239 
240     MapX1 = MapY1 = 0;
241     x1    = posX;
242     y1    = posY;
243 
244     switch( aOrient )
245     {
246     case PIN_UP:     y1 = posY - len;  MapY1 = 1;   break;
247     case PIN_DOWN:   y1 = posY + len;  MapY1 = -1;  break;
248     case PIN_LEFT:   x1 = posX - len;  MapX1 = 1;   break;
249     case PIN_RIGHT:  x1 = posX + len;  MapX1 = -1;  break;
250     }
251 
252     if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK )
253     {
254         const int radius = externalPinDecoSize( aSettings, *this );
255         GRCircle( nullptr, DC, MapX1 * radius + x1, MapY1 * radius + y1, radius, width, color );
256 
257         GRMoveTo( MapX1 * radius * 2 + x1, MapY1 * radius * 2 + y1 );
258         GRLineTo( nullptr, DC, posX, posY, width, color );
259     }
260     else
261     {
262         GRMoveTo( x1, y1 );
263         GRLineTo( nullptr, DC, posX, posY, width, color );
264     }
265 
266     // Draw the clock shape (>)inside the symbol
267     if( m_shape == GRAPHIC_PINSHAPE::CLOCK
268             || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK
269             || m_shape == GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK
270             || m_shape == GRAPHIC_PINSHAPE::CLOCK_LOW )
271     {
272         const int clock_size = internalPinDecoSize( aSettings, *this );
273         if( MapY1 == 0 ) /* MapX1 = +- 1 */
274         {
275             GRMoveTo( x1, y1 + clock_size );
276             GRLineTo( nullptr, DC, x1 - MapX1 * clock_size * 2, y1, width, color );
277             GRLineTo( nullptr, DC, x1, y1 - clock_size, width, color );
278         }
279         else    /* MapX1 = 0 */
280         {
281             GRMoveTo( x1 + clock_size, y1 );
282             GRLineTo( nullptr, DC, x1, y1 - MapY1 * clock_size * 2, width, color );
283             GRLineTo( nullptr, DC, x1 - clock_size, y1, width, color );
284         }
285     }
286 
287     // Draw the active low (or H to L active transition)
288     if( m_shape == GRAPHIC_PINSHAPE::INPUT_LOW
289             || m_shape == GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK
290             || m_shape == GRAPHIC_PINSHAPE::CLOCK_LOW )
291     {
292         const int deco_size = externalPinDecoSize( aSettings, *this );
293         if( MapY1 == 0 )            /* MapX1 = +- 1 */
294         {
295             GRMoveTo( x1 + MapX1 * deco_size * 2, y1 );
296             GRLineTo( nullptr, DC, x1 + MapX1 * deco_size * 2, y1 - deco_size * 2, width, color );
297             GRLineTo( nullptr, DC, x1, y1, width, color );
298         }
299         else    /* MapX1 = 0 */
300         {
301             GRMoveTo( x1, y1 + MapY1 * deco_size * 2 );
302             GRLineTo( nullptr, DC, x1 - deco_size * 2, y1 + MapY1 * deco_size * 2, width, color );
303             GRLineTo( nullptr, DC, x1, y1, width, color );
304         }
305     }
306 
307     if( m_shape == GRAPHIC_PINSHAPE::OUTPUT_LOW ) /* IEEE symbol "Active Low Output" */
308     {
309         const int deco_size = externalPinDecoSize( aSettings, *this );
310         if( MapY1 == 0 )            /* MapX1 = +- 1 */
311         {
312             GRMoveTo( x1, y1 - deco_size * 2 );
313             GRLineTo( nullptr, DC, x1 + MapX1 * deco_size * 2, y1, width, color );
314         }
315         else    /* MapX1 = 0 */
316         {
317             GRMoveTo( x1 - deco_size * 2, y1 );
318             GRLineTo( nullptr, DC, x1, y1 + MapY1 * deco_size * 2, width, color );
319         }
320     }
321     else if( m_shape == GRAPHIC_PINSHAPE::NONLOGIC ) /* NonLogic pin symbol */
322     {
323         const int deco_size = externalPinDecoSize( aSettings, *this );
324         GRMoveTo( x1 - (MapX1 + MapY1) * deco_size, y1 - (MapY1 - MapX1) * deco_size );
325         GRLineTo( nullptr, DC, x1 + (MapX1 + MapY1) * deco_size,
326                   y1 + ( MapY1 - MapX1 ) * deco_size, width, color );
327         GRMoveTo( x1 - (MapX1 - MapY1) * deco_size, y1 - (MapY1 + MapX1) * deco_size );
328         GRLineTo( nullptr, DC, x1 + (MapX1 - MapY1) * deco_size,
329                   y1 + ( MapY1 + MapX1 ) * deco_size, width, color );
330     }
331 
332     if( m_type == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
333     {
334         const int deco_size = TARGET_PIN_RADIUS;
335         GRLine( nullptr, DC, posX - deco_size, posY - deco_size, posX + deco_size,
336                 posY + deco_size, width, color );
337         GRLine( nullptr, DC, posX + deco_size, posY - deco_size, posX - deco_size,
338                 posY + deco_size, width, color );
339     }
340 }
341 
342 
printPinTexts(const RENDER_SETTINGS * aSettings,wxPoint & aPinPos,int aPinOrient,int aTextInside,bool aDrawPinNum,bool aDrawPinName)343 void LIB_PIN::printPinTexts( const RENDER_SETTINGS* aSettings, wxPoint& aPinPos, int aPinOrient,
344                              int aTextInside, bool aDrawPinNum, bool aDrawPinName )
345 {
346     if( !aDrawPinName && !aDrawPinNum )
347         return;
348 
349     int    x, y;
350     wxDC*  DC = aSettings->GetPrintDC();
351     wxSize PinNameSize( m_nameTextSize, m_nameTextSize );
352     wxSize PinNumSize( m_numTextSize, m_numTextSize );
353 
354     int    namePenWidth = std::max( Clamp_Text_PenSize( GetPenWidth(), m_nameTextSize, false ),
355                                     aSettings->GetDefaultPenWidth() );
356     int    numPenWidth = std::max( Clamp_Text_PenSize( GetPenWidth(), m_numTextSize, false ),
357                                    aSettings->GetDefaultPenWidth() );
358 
359     int    name_offset = Mils2iu( PIN_TEXT_MARGIN ) + namePenWidth;
360     int    num_offset = Mils2iu( PIN_TEXT_MARGIN ) + numPenWidth;
361 
362     /* Get the num and name colors */
363     COLOR4D NameColor = aSettings->GetLayerColor( IsVisible() ? LAYER_PINNAM : LAYER_HIDDEN );
364     COLOR4D NumColor  = aSettings->GetLayerColor( IsVisible() ? LAYER_PINNUM : LAYER_HIDDEN );
365 
366     int x1 = aPinPos.x;
367     int y1 = aPinPos.y;
368 
369     switch( aPinOrient )
370     {
371     case PIN_UP:    y1 -= m_length; break;
372     case PIN_DOWN:  y1 += m_length; break;
373     case PIN_LEFT:  x1 -= m_length; break;
374     case PIN_RIGHT: x1 += m_length; break;
375     }
376 
377     wxString name = GetShownName();
378     wxString number = GetShownNumber();
379 
380     if( name.IsEmpty() )
381         aDrawPinName = false;
382 
383     if( number.IsEmpty() )
384         aDrawPinNum = false;
385 
386     if( aTextInside )  // Draw the text inside, but the pin numbers outside.
387     {
388         if(( aPinOrient == PIN_LEFT) || ( aPinOrient == PIN_RIGHT) )
389         {
390             // It is an horizontal line
391             if( aDrawPinName )
392             {
393                 if( aPinOrient == PIN_RIGHT )
394                 {
395                     x = x1 + aTextInside;
396                     GRText( DC, wxPoint( x, y1 ), NameColor, name, TEXT_ANGLE_HORIZ, PinNameSize,
397                             GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER, namePenWidth, false,
398                             false );
399                 }
400                 else    // Orient == PIN_LEFT
401                 {
402                     x = x1 - aTextInside;
403                     GRText( DC, wxPoint( x, y1 ), NameColor, name, TEXT_ANGLE_HORIZ, PinNameSize,
404                             GR_TEXT_HJUSTIFY_RIGHT, GR_TEXT_VJUSTIFY_CENTER, namePenWidth, false,
405                             false );
406                 }
407             }
408 
409             if( aDrawPinNum )
410             {
411                 GRText( DC, wxPoint(( x1 + aPinPos.x) / 2, y1 - num_offset ), NumColor, number,
412                         TEXT_ANGLE_HORIZ, PinNumSize, GR_TEXT_HJUSTIFY_CENTER,
413                         GR_TEXT_VJUSTIFY_BOTTOM, numPenWidth, false, false );
414             }
415         }
416         else            /* Its a vertical line. */
417         {
418             // Text is drawn from bottom to top (i.e. to negative value for Y axis)
419             if( aPinOrient == PIN_DOWN )
420             {
421                 y = y1 + aTextInside;
422 
423                 if( aDrawPinName )
424                 {
425                     GRText( DC, wxPoint( x1, y ), NameColor, name, TEXT_ANGLE_VERT, PinNameSize,
426                             GR_TEXT_HJUSTIFY_RIGHT, GR_TEXT_VJUSTIFY_CENTER, namePenWidth, false,
427                             false );
428                 }
429 
430                 if( aDrawPinNum )
431                 {
432                     GRText( DC, wxPoint( x1 - num_offset, ( y1 + aPinPos.y) / 2 ), NumColor,
433                             number, TEXT_ANGLE_VERT, PinNumSize, GR_TEXT_HJUSTIFY_CENTER,
434                             GR_TEXT_VJUSTIFY_BOTTOM, numPenWidth, false, false );
435                 }
436             }
437             else        /* PIN_UP */
438             {
439                 y = y1 - aTextInside;
440 
441                 if( aDrawPinName )
442                 {
443                     GRText( DC, wxPoint( x1, y ), NameColor, name, TEXT_ANGLE_VERT, PinNameSize,
444                             GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER, namePenWidth, false,
445                             false );
446                 }
447 
448                 if( aDrawPinNum )
449                 {
450                     GRText( DC, wxPoint( x1 - num_offset, ( y1 + aPinPos.y) / 2 ), NumColor,
451                             number, TEXT_ANGLE_VERT, PinNumSize, GR_TEXT_HJUSTIFY_CENTER,
452                             GR_TEXT_VJUSTIFY_BOTTOM, numPenWidth, false, false );
453                 }
454             }
455         }
456     }
457     else     /**** Draw num & text pin outside  ****/
458     {
459         if(( aPinOrient == PIN_LEFT) || ( aPinOrient == PIN_RIGHT) )
460         {
461             /* Its an horizontal line. */
462             if( aDrawPinName )
463             {
464                 x = ( x1 + aPinPos.x) / 2;
465                 GRText( DC, wxPoint( x, y1 - name_offset ), NameColor, name, TEXT_ANGLE_HORIZ,
466                         PinNameSize, GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_BOTTOM,
467                         namePenWidth, false, false );
468             }
469             if( aDrawPinNum )
470             {
471                 x = ( x1 + aPinPos.x) / 2;
472                 GRText( DC, wxPoint( x, y1 + num_offset ), NumColor, number, TEXT_ANGLE_HORIZ,
473                         PinNumSize, GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_TOP, numPenWidth,
474                         false, false );
475             }
476         }
477         else     /* Its a vertical line. */
478         {
479             if( aDrawPinName )
480             {
481                 y = ( y1 + aPinPos.y) / 2;
482                 GRText( DC, wxPoint( x1 - name_offset, y ), NameColor, name, TEXT_ANGLE_VERT,
483                         PinNameSize, GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_BOTTOM,
484                         namePenWidth, false, false );
485             }
486 
487             if( aDrawPinNum )
488             {
489                 GRText( DC, wxPoint( x1 + num_offset, ( y1 + aPinPos.y) / 2 ), NumColor, number,
490                         TEXT_ANGLE_VERT, PinNumSize, GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_TOP,
491                         numPenWidth, false, false );
492             }
493         }
494     }
495 }
496 
497 
498 
printPinElectricalTypeName(const RENDER_SETTINGS * aSettings,wxPoint & aPosition,int aOrientation)499 void LIB_PIN::printPinElectricalTypeName( const RENDER_SETTINGS* aSettings, wxPoint& aPosition,
500                                           int aOrientation )
501 {
502     wxDC*       DC = aSettings->GetPrintDC();
503     wxString    typeName = GetElectricalTypeName();
504 
505     // Use a reasonable (small) size to draw the text
506     int         textSize = ( m_nameTextSize * 3 ) / 4;
507 
508     #define ETXT_MAX_SIZE Millimeter2iu( 0.7 )
509 
510     if( textSize > ETXT_MAX_SIZE )
511         textSize = ETXT_MAX_SIZE;
512 
513     // Use a reasonable pen size to draw the text
514     int pensize = textSize/6;
515 
516     // Get a suitable color
517     COLOR4D color = aSettings->GetLayerColor( IsVisible() ? LAYER_NOTES : LAYER_HIDDEN );
518 
519     wxPoint txtpos = aPosition;
520     int offset = Millimeter2iu( 0.4 );
521     EDA_TEXT_HJUSTIFY_T hjustify = GR_TEXT_HJUSTIFY_LEFT;
522     int orient = TEXT_ANGLE_HORIZ;
523 
524     switch( aOrientation )
525     {
526     case PIN_UP:
527         txtpos.y += offset;
528         orient = TEXT_ANGLE_VERT;
529         hjustify = GR_TEXT_HJUSTIFY_RIGHT;
530         break;
531 
532     case PIN_DOWN:
533         txtpos.y -= offset;
534         orient = TEXT_ANGLE_VERT;
535         break;
536 
537     case PIN_LEFT:
538         txtpos.x += offset;
539         break;
540 
541     case PIN_RIGHT:
542         txtpos.x -= offset;
543         hjustify = GR_TEXT_HJUSTIFY_RIGHT;
544         break;
545     }
546 
547     GRText( DC, txtpos, color, typeName, orient, wxSize( textSize, textSize ), hjustify,
548             GR_TEXT_VJUSTIFY_CENTER, pensize, false, false, nullptr );
549 }
550 
551 
PlotSymbol(PLOTTER * aPlotter,const wxPoint & aPosition,int aOrientation) const552 void LIB_PIN::PlotSymbol( PLOTTER* aPlotter, const wxPoint& aPosition, int aOrientation ) const
553 {
554     int     MapX1, MapY1, x1, y1;
555     COLOR4D color = aPlotter->RenderSettings()->GetLayerColor( LAYER_PIN );
556     int     penWidth = GetEffectivePenWidth( aPlotter->RenderSettings() );
557 
558     aPlotter->SetColor( color );
559     aPlotter->SetCurrentLineWidth( penWidth );
560 
561     MapX1 = MapY1 = 0;
562     x1 = aPosition.x; y1 = aPosition.y;
563 
564     switch( aOrientation )
565     {
566     case PIN_UP:     y1 = aPosition.y - m_length;  MapY1 = 1;   break;
567     case PIN_DOWN:   y1 = aPosition.y + m_length;  MapY1 = -1;  break;
568     case PIN_LEFT:   x1 = aPosition.x - m_length;  MapX1 = 1;   break;
569     case PIN_RIGHT:  x1 = aPosition.x + m_length;  MapX1 = -1;  break;
570     }
571 
572     if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK )
573     {
574         const int radius = externalPinDecoSize( aPlotter->RenderSettings(), *this );
575         aPlotter->Circle( wxPoint( MapX1 * radius + x1, MapY1 * radius + y1 ), radius * 2,
576                           FILL_T::NO_FILL, penWidth );
577 
578         aPlotter->MoveTo( wxPoint( MapX1 * radius * 2 + x1, MapY1 * radius * 2 + y1 ) );
579         aPlotter->FinishTo( aPosition );
580     }
581     else if( m_shape == GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK )
582     {
583         const int deco_size = internalPinDecoSize( aPlotter->RenderSettings(), *this );
584         if( MapY1 == 0 ) /* MapX1 = +- 1 */
585         {
586             aPlotter->MoveTo( wxPoint( x1, y1 + deco_size ) );
587             aPlotter->LineTo( wxPoint( x1 + MapX1 * deco_size * 2, y1 ) );
588             aPlotter->FinishTo( wxPoint( x1, y1 - deco_size ) );
589         }
590         else    /* MapX1 = 0 */
591         {
592             aPlotter->MoveTo( wxPoint( x1 + deco_size, y1 ) );
593             aPlotter->LineTo( wxPoint( x1, y1 + MapY1 * deco_size * 2 ) );
594             aPlotter->FinishTo( wxPoint( x1 - deco_size, y1 ) );
595         }
596 
597         aPlotter->MoveTo( wxPoint( MapX1 * deco_size * 2 + x1, MapY1 * deco_size * 2 + y1 ) );
598         aPlotter->FinishTo( aPosition );
599     }
600     else
601     {
602         aPlotter->MoveTo( wxPoint( x1, y1 ) );
603         aPlotter->FinishTo( aPosition );
604     }
605 
606     if( m_shape == GRAPHIC_PINSHAPE::CLOCK
607             || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK
608             || m_shape == GRAPHIC_PINSHAPE::CLOCK_LOW )
609     {
610         const int deco_size = internalPinDecoSize( aPlotter->RenderSettings(), *this );
611         if( MapY1 == 0 ) /* MapX1 = +- 1 */
612         {
613             aPlotter->MoveTo( wxPoint( x1, y1 + deco_size ) );
614             aPlotter->LineTo( wxPoint( x1 - MapX1 * deco_size * 2, y1 ) );
615             aPlotter->FinishTo( wxPoint( x1, y1 - deco_size ) );
616         }
617         else    /* MapX1 = 0 */
618         {
619             aPlotter->MoveTo( wxPoint( x1 + deco_size, y1 ) );
620             aPlotter->LineTo( wxPoint( x1, y1 - MapY1 * deco_size * 2 ) );
621             aPlotter->FinishTo( wxPoint( x1 - deco_size, y1 ) );
622         }
623     }
624 
625     if( m_shape == GRAPHIC_PINSHAPE::INPUT_LOW
626             || m_shape == GRAPHIC_PINSHAPE::CLOCK_LOW ) /* IEEE symbol "Active Low Input" */
627     {
628         const int deco_size = externalPinDecoSize( aPlotter->RenderSettings(), *this );
629 
630         if( MapY1 == 0 )        /* MapX1 = +- 1 */
631         {
632             aPlotter->MoveTo( wxPoint( x1 + MapX1 * deco_size * 2, y1 ) );
633             aPlotter->LineTo( wxPoint( x1 + MapX1 * deco_size * 2, y1 - deco_size * 2 ) );
634             aPlotter->FinishTo( wxPoint( x1, y1 ) );
635         }
636         else    /* MapX1 = 0 */
637         {
638             aPlotter->MoveTo( wxPoint( x1, y1 + MapY1 * deco_size * 2 ) );
639             aPlotter->LineTo( wxPoint( x1 - deco_size * 2, y1 + MapY1 * deco_size * 2 ) );
640             aPlotter->FinishTo( wxPoint( x1, y1 ) );
641         }
642     }
643 
644     if( m_shape == GRAPHIC_PINSHAPE::OUTPUT_LOW ) /* IEEE symbol "Active Low Output" */
645     {
646         const int symbol_size = externalPinDecoSize( aPlotter->RenderSettings(), *this );
647 
648         if( MapY1 == 0 )        /* MapX1 = +- 1 */
649         {
650             aPlotter->MoveTo( wxPoint( x1, y1 - symbol_size * 2 ) );
651             aPlotter->FinishTo( wxPoint( x1 + MapX1 * symbol_size * 2, y1 ) );
652         }
653         else    /* MapX1 = 0 */
654         {
655             aPlotter->MoveTo( wxPoint( x1 - symbol_size * 2, y1 ) );
656             aPlotter->FinishTo( wxPoint( x1, y1 + MapY1 * symbol_size * 2 ) );
657         }
658     }
659     else if( m_shape == GRAPHIC_PINSHAPE::NONLOGIC ) /* NonLogic pin symbol */
660     {
661         const int deco_size = externalPinDecoSize( aPlotter->RenderSettings(), *this );
662         aPlotter->MoveTo( wxPoint( x1 - (MapX1 + MapY1) * deco_size, y1 - (MapY1 - MapX1) * deco_size ) );
663         aPlotter->FinishTo( wxPoint( x1 + (MapX1 + MapY1) * deco_size, y1 + (MapY1 - MapX1) * deco_size ) );
664         aPlotter->MoveTo( wxPoint( x1 - (MapX1 - MapY1) * deco_size, y1 - (MapY1 + MapX1) * deco_size ) );
665         aPlotter->FinishTo( wxPoint( x1 + (MapX1 - MapY1) * deco_size, y1 + (MapY1 + MapX1) * deco_size ) );
666     }
667 
668     if( m_type == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
669     {
670         const int deco_size = TARGET_PIN_RADIUS;
671         const int ex1 = aPosition.x;
672         const int ey1 = aPosition.y;
673         aPlotter->MoveTo( wxPoint( ex1 - deco_size, ey1 - deco_size ) );
674         aPlotter->FinishTo( wxPoint( ex1 + deco_size, ey1 + deco_size ) );
675         aPlotter->MoveTo( wxPoint( ex1 + deco_size, ey1 - deco_size ) );
676         aPlotter->FinishTo( wxPoint( ex1 - deco_size, ey1 + deco_size ) );
677     }
678 }
679 
680 
PlotPinTexts(PLOTTER * aPlotter,const wxPoint & aPinPos,int aPinOrient,int aTextInside,bool aDrawPinNum,bool aDrawPinName) const681 void LIB_PIN::PlotPinTexts( PLOTTER* aPlotter, const wxPoint& aPinPos, int aPinOrient, int aTextInside,
682                             bool aDrawPinNum, bool aDrawPinName ) const
683 {
684     wxString name = GetShownName();
685     wxString number = GetShownNumber();
686 
687     if( name.IsEmpty() )
688         aDrawPinName = false;
689 
690     if( number.IsEmpty() )
691         aDrawPinNum = false;
692 
693     if( !aDrawPinNum && !aDrawPinName )
694         return;
695 
696     int     x, y;
697     wxSize  pinNameSize = wxSize( m_nameTextSize, m_nameTextSize );
698     wxSize  pinNumSize  = wxSize( m_numTextSize, m_numTextSize );
699 
700     int     namePenWidth = std::max( Clamp_Text_PenSize( GetPenWidth(), m_nameTextSize, false ),
701                                      aPlotter->RenderSettings()->GetDefaultPenWidth() );
702     int     numPenWidth  = std::max( Clamp_Text_PenSize( GetPenWidth(), m_numTextSize, false ),
703                                      aPlotter->RenderSettings()->GetDefaultPenWidth() );
704 
705     int     name_offset = Mils2iu( PIN_TEXT_MARGIN ) + namePenWidth;
706     int     num_offset  = Mils2iu( PIN_TEXT_MARGIN ) + numPenWidth;
707 
708     /* Get the num and name colors */
709     COLOR4D nameColor = aPlotter->RenderSettings()->GetLayerColor( LAYER_PINNAM );
710     COLOR4D numColor  = aPlotter->RenderSettings()->GetLayerColor( LAYER_PINNUM );
711 
712     int x1 = aPinPos.x;
713     int y1 = aPinPos.y;
714 
715     switch( aPinOrient )
716     {
717     case PIN_UP:     y1 -= m_length;  break;
718     case PIN_DOWN:   y1 += m_length;  break;
719     case PIN_LEFT:   x1 -= m_length;  break;
720     case PIN_RIGHT:  x1 += m_length;  break;
721     }
722 
723     /* Draw the text inside, but the pin numbers outside. */
724     if( aTextInside )
725     {
726         if( ( aPinOrient == PIN_LEFT) || ( aPinOrient == PIN_RIGHT) ) /* Its an horizontal line. */
727         {
728             if( aDrawPinName )
729             {
730                 EDA_TEXT_HJUSTIFY_T hjustify;
731                 if( aPinOrient == PIN_RIGHT )
732                 {
733                     x = x1 + aTextInside;
734                     hjustify = GR_TEXT_HJUSTIFY_LEFT;
735                 }
736                 else    // orient == PIN_LEFT
737                 {
738                     x = x1 - aTextInside;
739                     hjustify = GR_TEXT_HJUSTIFY_RIGHT;
740                 }
741 
742                 aPlotter->Text( wxPoint( x, y1 ), nameColor, name, TEXT_ANGLE_HORIZ, pinNameSize,
743                                 hjustify, GR_TEXT_VJUSTIFY_CENTER, namePenWidth,
744                                 false, false );
745             }
746             if( aDrawPinNum )
747             {
748                 aPlotter->Text( wxPoint( ( x1 + aPinPos.x) / 2, y1 - num_offset ), numColor,
749                                 number, TEXT_ANGLE_HORIZ, pinNumSize, GR_TEXT_HJUSTIFY_CENTER,
750                                 GR_TEXT_VJUSTIFY_BOTTOM, numPenWidth, false, false );
751             }
752         }
753         else         /* Its a vertical line. */
754         {
755             if( aPinOrient == PIN_DOWN )
756             {
757                 y = y1 + aTextInside;
758 
759                 if( aDrawPinName )
760                     aPlotter->Text( wxPoint( x1, y ), nameColor, name, TEXT_ANGLE_VERT,
761                                     pinNameSize, GR_TEXT_HJUSTIFY_RIGHT, GR_TEXT_VJUSTIFY_CENTER,
762                                     namePenWidth, false, false );
763 
764                 if( aDrawPinNum )
765                 {
766                     aPlotter->Text( wxPoint( x1 - num_offset, ( y1 + aPinPos.y) / 2 ), numColor,
767                                     number, TEXT_ANGLE_VERT, pinNumSize, GR_TEXT_HJUSTIFY_CENTER,
768                                     GR_TEXT_VJUSTIFY_BOTTOM, numPenWidth, false, false );
769                 }
770             }
771             else        /* PIN_UP */
772             {
773                 y = y1 - aTextInside;
774 
775                 if( aDrawPinName )
776                 {
777                     aPlotter->Text( wxPoint( x1, y ), nameColor, name, TEXT_ANGLE_VERT,
778                                     pinNameSize, GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER,
779                                     namePenWidth, false, false );
780                 }
781 
782                 if( aDrawPinNum )
783                 {
784                     aPlotter->Text( wxPoint( x1 - num_offset,  ( y1 + aPinPos.y) / 2 ), numColor,
785                                     number, TEXT_ANGLE_VERT, pinNumSize, GR_TEXT_HJUSTIFY_CENTER,
786                                     GR_TEXT_VJUSTIFY_BOTTOM, numPenWidth, false, false );
787                 }
788             }
789         }
790     }
791     else     /* Draw num & text pin outside */
792     {
793         if(( aPinOrient == PIN_LEFT) || ( aPinOrient == PIN_RIGHT) )
794         {
795             /* Its an horizontal line. */
796             if( aDrawPinName )
797             {
798                 x = ( x1 + aPinPos.x) / 2;
799                 aPlotter->Text( wxPoint( x, y1 - name_offset ), nameColor, name,
800                                 TEXT_ANGLE_HORIZ, pinNameSize, GR_TEXT_HJUSTIFY_CENTER,
801                                 GR_TEXT_VJUSTIFY_BOTTOM, namePenWidth, false, false );
802             }
803 
804             if( aDrawPinNum )
805             {
806                 x = ( x1 + aPinPos.x ) / 2;
807                 aPlotter->Text( wxPoint( x, y1 + num_offset ), numColor, number,
808                                 TEXT_ANGLE_HORIZ, pinNumSize, GR_TEXT_HJUSTIFY_CENTER,
809                                 GR_TEXT_VJUSTIFY_TOP, numPenWidth, false, false );
810             }
811         }
812         else     /* Its a vertical line. */
813         {
814             if( aDrawPinName )
815             {
816                 y = ( y1 + aPinPos.y ) / 2;
817                 aPlotter->Text( wxPoint( x1 - name_offset, y ), nameColor, name,
818                                 TEXT_ANGLE_VERT, pinNameSize, GR_TEXT_HJUSTIFY_CENTER,
819                                 GR_TEXT_VJUSTIFY_BOTTOM, namePenWidth, false, false );
820             }
821 
822             if( aDrawPinNum )
823             {
824                 aPlotter->Text( wxPoint( x1 + num_offset, ( y1 + aPinPos.y ) / 2 ), numColor,
825                                 number, TEXT_ANGLE_VERT, pinNumSize, GR_TEXT_HJUSTIFY_CENTER,
826                                 GR_TEXT_VJUSTIFY_TOP, numPenWidth, false, false );
827             }
828         }
829     }
830 }
831 
832 
PinDrawOrient(const TRANSFORM & aTransform) const833 int LIB_PIN::PinDrawOrient( const TRANSFORM& aTransform ) const
834 {
835     int     orient;
836     wxPoint end;   // position of pin end starting at 0,0 according to its orientation, length = 1
837 
838     switch( m_orientation )
839     {
840     case PIN_UP:     end.y = 1;   break;
841     case PIN_DOWN:   end.y = -1;  break;
842     case PIN_LEFT:   end.x = -1;  break;
843     case PIN_RIGHT:  end.x = 1;   break;
844     }
845 
846     // = pos of end point, according to the symbol orientation.
847     end    = aTransform.TransformCoordinate( end );
848     orient = PIN_UP;
849 
850     if( end.x == 0 )
851     {
852         if( end.y > 0 )
853             orient = PIN_DOWN;
854     }
855     else
856     {
857         orient = PIN_RIGHT;
858 
859         if( end.x < 0 )
860             orient = PIN_LEFT;
861     }
862 
863     return orient;
864 }
865 
866 
Clone() const867 EDA_ITEM* LIB_PIN::Clone() const
868 {
869     return new LIB_PIN( *this );
870 }
871 
872 
compare(const LIB_ITEM & aOther,LIB_ITEM::COMPARE_FLAGS aCompareFlags) const873 int LIB_PIN::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const
874 {
875     wxASSERT( aOther.Type() == LIB_PIN_T );
876 
877     int retv = LIB_ITEM::compare( aOther, aCompareFlags );
878 
879     if( retv )
880         return retv;
881 
882     const LIB_PIN* tmp = (LIB_PIN*) &aOther;
883 
884     // When comparing units, we do not compare the part numbers.  If everything else is
885     // identical, then we can just renumber the parts for the inherited symbol.
886     if( !( aCompareFlags & COMPARE_FLAGS::UNIT ) && m_number != tmp->m_number )
887         return m_number.Cmp( tmp->m_number );
888 
889     int result = m_name.CmpNoCase( tmp->m_name );
890 
891     if( result )
892         return result;
893 
894     if( m_position.x != tmp->m_position.x )
895         return m_position.x - tmp->m_position.x;
896 
897     if( m_position.y != tmp->m_position.y )
898         return m_position.y - tmp->m_position.y;
899 
900     if( m_length != tmp->m_length )
901         return m_length - tmp->m_length;
902 
903     if( m_orientation != tmp->m_orientation )
904         return m_orientation - tmp->m_orientation;
905 
906     if( m_shape != tmp->m_shape )
907         return static_cast<int>( m_shape ) - static_cast<int>( tmp->m_shape );
908 
909     if( m_type != tmp->m_type )
910         return static_cast<int>( m_type ) - static_cast<int>( tmp->m_type );
911 
912     if( m_attributes != tmp->m_attributes )
913         return m_attributes - tmp->m_attributes;
914 
915     if( m_numTextSize != tmp->m_numTextSize )
916         return m_numTextSize - tmp->m_numTextSize;
917 
918     if( m_nameTextSize != tmp->m_nameTextSize )
919         return m_nameTextSize - tmp->m_nameTextSize;
920 
921     if( m_alternates.size() != tmp->m_alternates.size() )
922         return m_alternates.size() - tmp->m_alternates.size();
923 
924     auto lhsItem = m_alternates.begin();
925     auto rhsItem = tmp->m_alternates.begin();
926 
927     while( lhsItem != m_alternates.end() )
928     {
929         const ALT& lhsAlt = lhsItem->second;
930         const ALT& rhsAlt = rhsItem->second;
931 
932         retv = lhsAlt.m_Name.Cmp( rhsAlt.m_Name );
933 
934         if( retv )
935             return retv;
936 
937         if( lhsAlt.m_Type != rhsAlt.m_Type )
938             return static_cast<int>( lhsAlt.m_Type ) - static_cast<int>( rhsAlt.m_Type );
939 
940         if( lhsAlt.m_Shape != rhsAlt.m_Shape )
941             return static_cast<int>( lhsAlt.m_Shape ) - static_cast<int>( rhsAlt.m_Shape );
942 
943         ++lhsItem;
944         ++rhsItem;
945     }
946 
947     return 0;
948 }
949 
950 
Offset(const wxPoint & aOffset)951 void LIB_PIN::Offset( const wxPoint& aOffset )
952 {
953     m_position += aOffset;
954 }
955 
956 
MoveTo(const wxPoint & aNewPosition)957 void LIB_PIN::MoveTo( const wxPoint& aNewPosition )
958 {
959     if( m_position != aNewPosition )
960     {
961         m_position = aNewPosition;
962         SetModified();
963     }
964 }
965 
966 
MirrorHorizontal(const wxPoint & aCenter)967 void LIB_PIN::MirrorHorizontal( const wxPoint& aCenter )
968 {
969     m_position.x -= aCenter.x;
970     m_position.x *= -1;
971     m_position.x += aCenter.x;
972 
973     if( m_orientation == PIN_RIGHT )
974         m_orientation = PIN_LEFT;
975     else if( m_orientation == PIN_LEFT )
976         m_orientation = PIN_RIGHT;
977 }
978 
979 
MirrorVertical(const wxPoint & aCenter)980 void LIB_PIN::MirrorVertical( const wxPoint& aCenter )
981 {
982     m_position.y -= aCenter.y;
983     m_position.y *= -1;
984     m_position.y += aCenter.y;
985 
986     if( m_orientation == PIN_UP )
987         m_orientation = PIN_DOWN;
988     else if( m_orientation == PIN_DOWN )
989         m_orientation = PIN_UP;
990 }
991 
992 
Rotate(const wxPoint & aCenter,bool aRotateCCW)993 void LIB_PIN::Rotate( const wxPoint& aCenter, bool aRotateCCW )
994 {
995     int rot_angle = aRotateCCW ? -900 : 900;
996 
997     RotatePoint( &m_position, aCenter, rot_angle );
998 
999     if( aRotateCCW )
1000     {
1001         switch( m_orientation )
1002         {
1003         case PIN_RIGHT: m_orientation = PIN_UP;    break;
1004         case PIN_UP:    m_orientation = PIN_LEFT;  break;
1005         case PIN_LEFT:  m_orientation = PIN_DOWN;  break;
1006         case PIN_DOWN:  m_orientation = PIN_RIGHT; break;
1007         }
1008     }
1009     else
1010     {
1011         switch( m_orientation )
1012         {
1013         case PIN_RIGHT: m_orientation = PIN_DOWN;  break;
1014         case PIN_UP:    m_orientation = PIN_RIGHT; break;
1015         case PIN_LEFT:  m_orientation = PIN_UP;    break;
1016         case PIN_DOWN:  m_orientation = PIN_LEFT;  break;
1017         }
1018     }
1019 }
1020 
1021 
Plot(PLOTTER * aPlotter,const wxPoint & aPffset,bool aFill,const TRANSFORM & aTransform) const1022 void LIB_PIN::Plot( PLOTTER* aPlotter, const wxPoint& aPffset, bool aFill,
1023                     const TRANSFORM& aTransform ) const
1024 {
1025     if( !IsVisible() )
1026         return;
1027 
1028     int     orient = PinDrawOrient( aTransform );
1029     wxPoint pos = aTransform.TransformCoordinate( m_position ) + aPffset;
1030 
1031     PlotSymbol( aPlotter, pos, orient );
1032     PlotPinTexts( aPlotter, pos, orient, GetParent()->GetPinNameOffset(),
1033                   GetParent()->ShowPinNumbers(), GetParent()->ShowPinNames() );
1034 }
1035 
1036 
GetMsgPanelInfo(EDA_DRAW_FRAME * aFrame,std::vector<MSG_PANEL_ITEM> & aList)1037 void LIB_PIN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1038 {
1039     LIB_ITEM::GetMsgPanelInfo( aFrame, aList );
1040 
1041     aList.emplace_back( _( "Name" ), UnescapeString( GetShownName() ) );
1042     aList.emplace_back( _( "Number" ), GetShownNumber() );
1043     aList.emplace_back( _( "Type" ), ElectricalPinTypeGetText( m_type ) );
1044     aList.emplace_back( _( "Style" ), PinShapeGetText( m_shape ) );
1045 
1046     aList.emplace_back( _( "Style" ), IsVisible() ? _( "Yes" ) : _( "No" ) );
1047 
1048     // Display pin length
1049     aList.emplace_back( _( "Length" ), StringFromValue( aFrame->GetUserUnits(), m_length ) );
1050 
1051     int i = PinOrientationIndex( m_orientation );
1052     aList.emplace_back( _( "Orientation" ), PinOrientationName( (unsigned) i ) );
1053 
1054     wxPoint pinpos = GetPosition();
1055     pinpos.y = -pinpos.y;   // Display coords are top to bottom; lib item coords are bottom to top
1056 
1057     aList.emplace_back( _( "Pos X" ), MessageTextFromValue( aFrame->GetUserUnits(), pinpos.x ) );
1058     aList.emplace_back( _( "Pos Y" ), MessageTextFromValue( aFrame->GetUserUnits(), pinpos.y ) );
1059 }
1060 
1061 
GetBoundingBox(bool aIncludeInvisibles,bool aPinOnly) const1062 const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly ) const
1063 {
1064     EDA_RECT       bbox;
1065     wxPoint        begin;
1066     wxPoint        end;
1067     int            nameTextOffset = 0;
1068     wxString       name = GetShownName();
1069     wxString       number = GetShownNumber();
1070     bool           showName = !name.IsEmpty();
1071     bool           showNum = !number.IsEmpty();
1072     int            minsizeV = TARGET_PIN_RADIUS;
1073 
1074     if( !aIncludeInvisibles && !IsVisible() )
1075         showName = false;
1076 
1077     if( GetParent() )
1078     {
1079         if( GetParent()->ShowPinNames() )
1080             nameTextOffset = GetParent()->GetPinNameOffset();
1081         else
1082             showName = false;
1083 
1084         if( !GetParent()->ShowPinNumbers() )
1085             showNum = false;
1086     }
1087 
1088     if( aPinOnly )
1089     {
1090         showName = false;
1091         showNum = false;
1092     }
1093 
1094     // First, calculate boundary box corners position
1095     int numberTextLength = showNum ? m_numTextSize * number.Len() : 0;
1096 
1097     // Actual text height is bigger than text size
1098     int numberTextHeight  = showNum ? KiROUND( m_numTextSize * 1.1 ) : 0;
1099 
1100     if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK )
1101         minsizeV = std::max( TARGET_PIN_RADIUS, externalPinDecoSize( nullptr, *this ) );
1102 
1103     // calculate top left corner position
1104     // for the default pin orientation (PIN_RIGHT)
1105     begin.y = std::max( minsizeV, numberTextHeight + Mils2iu( PIN_TEXT_MARGIN ) );
1106     begin.x = std::min( 0, m_length - (numberTextLength / 2) );
1107 
1108     // calculate bottom right corner position and adjust top left corner position
1109     int nameTextLength = 0;
1110     int nameTextHeight = 0;
1111 
1112     if( showName )
1113     {
1114         int length = name.Len();
1115 
1116         // TODO: exclude markup characters!
1117         nameTextLength = ( m_nameTextSize * length ) + nameTextOffset;
1118 
1119         // Actual text height are bigger than text size
1120         nameTextHeight = KiROUND( m_nameTextSize * 1.1 ) + Mils2iu( PIN_TEXT_MARGIN );
1121     }
1122 
1123     if( nameTextOffset )        // for values > 0, pin name is inside the body
1124     {
1125         end.x = m_length + nameTextLength;
1126         end.y = std::min( -minsizeV, -nameTextHeight / 2 );
1127     }
1128     else        // if value == 0:
1129                 // pin name is outside the body, and above the pin line
1130                 // pin num is below the pin line
1131     {
1132         end.x   = std::max( m_length, nameTextLength );
1133         end.y   = -begin.y;
1134         begin.y = std::max( minsizeV, nameTextHeight );
1135     }
1136 
1137     // Now, calculate boundary box corners position for the actual pin orientation
1138     int orient = PinDrawOrient( DefaultTransform );
1139 
1140     /* Calculate the pin position */
1141     switch( orient )
1142     {
1143     case PIN_UP:
1144         // Pin is rotated and texts positions are mirrored
1145         RotatePoint( &begin, wxPoint( 0, 0 ), -900 );
1146         RotatePoint( &end, wxPoint( 0, 0 ), -900 );
1147         break;
1148 
1149     case PIN_DOWN:
1150         RotatePoint( &begin, wxPoint( 0, 0 ), 900 );
1151         RotatePoint( &end, wxPoint( 0, 0 ), 900 );
1152         begin.x = -begin.x;
1153         end.x = -end.x;
1154         break;
1155 
1156     case PIN_LEFT:
1157         begin.x = -begin.x;
1158         end.x = -end.x;
1159         break;
1160 
1161     case PIN_RIGHT:
1162         break;
1163     }
1164 
1165     begin += m_position;
1166     end += m_position;
1167 
1168     bbox.SetOrigin( begin );
1169     bbox.SetEnd( end );
1170     bbox.Normalize();
1171     bbox.Inflate( ( GetPenWidth() / 2 ) + 1 );
1172 
1173     // Draw Y axis is reversed in schematic:
1174     bbox.RevertYAxis();
1175 
1176     return bbox;
1177 }
1178 
1179 
GetMenuImage() const1180 BITMAPS LIB_PIN::GetMenuImage() const
1181 {
1182     return ElectricalPinTypeGetBitmap( m_type );
1183 }
1184 
1185 
GetSelectMenuText(EDA_UNITS aUnits) const1186 wxString LIB_PIN::GetSelectMenuText( EDA_UNITS aUnits ) const
1187 {
1188     if( !m_name.IsEmpty() )
1189     {
1190         return wxString::Format( _( "Pin %s [%s, %s, %s]" ),
1191                                  GetShownNumber(),
1192                                  UnescapeString( GetShownName() ),
1193                                  GetElectricalTypeName(),
1194                                  PinShapeGetText( m_shape ) );
1195     }
1196     else
1197     {
1198         return wxString::Format( _( "Pin %s [%s, %s]" ),
1199                                  GetShownNumber(),
1200                                  GetElectricalTypeName(),
1201                                  PinShapeGetText( m_shape ) );
1202     }
1203 }
1204 
1205 
1206 #if defined(DEBUG)
1207 
Show(int nestLevel,std::ostream & os) const1208 void LIB_PIN::Show( int nestLevel, std::ostream& os ) const
1209 {
1210     NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
1211                                  << " num=\"" << m_number.mb_str()
1212                                  << '"' << "/>\n";
1213 
1214 //    NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
1215 }
1216 
1217 #endif
1218 
CalcEdit(const wxPoint & aPosition)1219 void LIB_PIN::CalcEdit( const wxPoint& aPosition )
1220 {
1221     if( IsMoving() )
1222         MoveTo( aPosition );
1223 }
1224