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