KiCad PCB EDA Suite
drawing_stackup_table_tool.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2014-2017 CERN
5 * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "drawing_tool.h"
26#include "pcb_actions.h"
27#include <pcb_edit_frame.h>
28#include <view/view.h>
29#include <tool/tool_manager.h>
30#include <board_commit.h>
31#include <scoped_set_reset.h>
32#include <painter.h>
35#include <footprint.h>
36#include <fp_shape.h>
37#include <pcb_group.h>
38#include <pcb_text.h>
39#include <string_utils.h>
40#include <wx/utils.h>
41
42
44
45
46static std::vector<BOARD_ITEM*> initTextTable( std::vector<std::vector<PCB_TEXT*>> aContent,
47 VECTOR2I origin, PCB_LAYER_ID aLayer,
48 VECTOR2I* aTableSize, bool aDrawFrame = true )
49{
50 int i;
51 int j;
52
53 int nbCols = aContent.size();
54 int nbRows = 0;
55
56 for( const std::vector<PCB_TEXT*>& col : aContent )
57 nbRows = std::max( nbRows, static_cast<int>( col.size() ) );
58
59 // Limit the number of cells
60 nbCols = std::min( nbCols, 99 );
61 nbRows = std::min( nbRows, 99 );
62
63 int rowHeight[99];
64 int colWidth[99];
65
66 std::vector<BOARD_ITEM*> table;
67
68 // xmargin and ymargin are margins between the text and the table lines.
69 //
70 // +--------------------------------+
71 // | ^ |
72 // | | ymargin |
73 // | v |
74 // |<------->TEXT_TEXT_TEXT<------->|
75 // | xmargin ^ xmargin |
76 // | | ymargin |
77 // | v |
78 // +--------------------------------+
79 //
80
81 int xmargin = pcbIUScale.mmToIU( 0.75 );
82 int ymargin = pcbIUScale.mmToIU( 0.75 );
83
84 // Init table
85 for( i = 0; i < nbRows; i++ )
86 rowHeight[i] = 0;
87
88 for( i = 0; i < nbCols; i++ )
89 colWidth[i] = 0;
90
91 // First, we determine what the height/Width should be for every cell
92 i = 0;
93
94 for( const std::vector<PCB_TEXT*>& col : aContent )
95 {
96 j = 0;
97
98 if( i >= nbCols )
99 break;
100
101 for( const PCB_TEXT* cell : col )
102 {
103 if( j >= nbRows )
104 break;
105
106 int height = cell->GetBoundingBox().GetHeight() + 2 * ymargin;
107 int width = cell->GetBoundingBox().GetWidth() + 2 * xmargin;
108 rowHeight[j] = rowHeight[j] > height ? rowHeight[j] : height;
109 colWidth[i] = colWidth[i] > width ? colWidth[i] : width;
110 j++;
111 }
112
113 i++;
114 }
115
116 // get table size
117 int height = std::accumulate( rowHeight, rowHeight + nbRows, 0 );
118 int width = std::accumulate( colWidth, colWidth + nbCols, 0 );
119
120 aTableSize->x = width;
121 aTableSize->y = height;
122 // Draw the frame
123
124 if( aDrawFrame )
125 {
126 int y = origin.y;
127 PCB_SHAPE* line;
128
129 for( i = 0; i < nbRows; i++ )
130 {
131 line = new PCB_SHAPE;
132 line->SetLayer( aLayer );
133 line->SetStart( VECTOR2I( origin.x, y ) );
134 line->SetEnd( VECTOR2I( origin.x + width, y ) );
135 y += rowHeight[i];
136 table.push_back( line );
137 }
138
139 line = new PCB_SHAPE;
140 line->SetLayer( aLayer );
141 line->SetStart( VECTOR2I( origin.x, y ) );
142 line->SetEnd( VECTOR2I( origin.x + width, y ) );
143 table.push_back( line );
144 int x = origin.x;
145
146 for( i = 0; i < nbCols; i++ )
147 {
148 line = new PCB_SHAPE;
149 line->SetLayer( aLayer );
150 line->SetStart( VECTOR2I( x, origin.y ) );
151 line->SetEnd( VECTOR2I( x, origin.y + height ) );
152 x += colWidth[i];
153 table.push_back( line );
154 }
155
156 line = new PCB_SHAPE;
157 line->SetLayer( aLayer );
158 line->SetStart( VECTOR2I( x, origin.y ) );
159 line->SetEnd( VECTOR2I( x, origin.y + height ) );
160 table.push_back( line );
161 }
162
163 //Now add the text
164 i = 0;
165 VECTOR2I pos( origin.x + xmargin, origin.y + ymargin );
166
167 for( std::vector<PCB_TEXT*>& col : aContent )
168 {
169 j = 0;
170
171 if( i >= nbCols )
172 break;
173
174 pos.y = origin.y + ymargin;
175
176 for( PCB_TEXT* cell : col )
177 {
178 if( j >= nbRows )
179 break;
180
181 cell->SetTextPos( pos );
182 cell->SetLayer( aLayer );
183 pos.y = pos.y + rowHeight[j];
184 table.push_back( cell );
185 j++;
186 }
187
188 pos.x = pos.x + colWidth[i];
189 i++;
190 }
191
192 return table;
193}
194
195
196std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawSpecificationStackup( const VECTOR2I& aOrigin,
197 PCB_LAYER_ID aLayer,
198 bool aDrawNow,
199 VECTOR2I* tableSize )
200{
201 BOARD_COMMIT commit( m_frame );
202 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( m_frame->GetModel() );
203
204 std::vector<std::vector<PCB_TEXT*>> texts;
205
206 // Style : Header
207 std::unique_ptr<PCB_TEXT> headStyle = std::make_unique<PCB_TEXT>( footprint );
208 headStyle->SetLayer( Eco1_User );
209 headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
210 headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.3 ) );
211 headStyle->SetItalic( false );
212 headStyle->SetTextPos( VECTOR2I( 0, 0 ) );
213 headStyle->SetText( _( "Layer" ) );
214 headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
215 headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
216
217 // Style : data
218 std::unique_ptr<PCB_TEXT> dataStyle = std::make_unique<PCB_TEXT>( footprint );
219 dataStyle->SetLayer( Eco1_User );
220 dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
221 dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.1 ) );
222 dataStyle->SetItalic( false );
223 dataStyle->SetTextPos( VECTOR2I( 0, 0 ) );
224 dataStyle->SetText( _( "Layer" ) );
225 dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
226 dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
227
228 //Get Layer names
230 BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
231 stackup.SynchronizeWithBoard( &dsnSettings );
232
233 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
234
235 std::vector<PCB_TEXT*> colLayer;
236 std::vector<PCB_TEXT*> colType;
237 std::vector<PCB_TEXT*> colMaterial;
238 std::vector<PCB_TEXT*> colThickness;
239 std::vector<PCB_TEXT*> colColor;
240 std::vector<PCB_TEXT*> colEpsilon;
241 std::vector<PCB_TEXT*> colTanD;
242 PCB_TEXT* t;
243
244 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
245 t->SetText( _( "Layer Name" ) );
246 colLayer.push_back( t );
247
248 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
249 t->SetText( _( "Type" ) );
250 colType.push_back( t );
251
252 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
253 t->SetText( _( "Material" ) );
254 colMaterial.push_back( t );
255
256 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
257
258 switch( m_frame->GetUserUnits() )
259 {
260 case EDA_UNITS::MILLIMETRES: t->SetText( _( "Thickness (mm)" ) ); break;
261 case EDA_UNITS::INCHES: t->SetText( _( "Thickness (inches)" ) ); break;
262 case EDA_UNITS::MILS: t->SetText( _( "Thickness (mils)" ) ); break;
263 default: wxFAIL_MSG( wxT( "Unhandled unit type" ) );
264 }
265
266 colThickness.push_back( t );
267
268 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
269 t->SetText( _( "Color" ) );
270 colColor.push_back( t );
271
272 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
273 t->SetText( _( "Epsilon R" ) );
274 colEpsilon.push_back( t );
275
276 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
277 t->SetText( _( "Loss Tangent" ) );
278 colTanD.push_back( t );
279
280 for( int i = 0; i < stackup.GetCount(); i++ )
281 {
282 BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
283
284 for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ )
285 {
286 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
287
288 // Layer names are empty until we close at least once the board setup dialog.
289 // If the user did not open the dialog, then get the names from the board.
290 // But dielectric layer names will be missing.
291 // In this case, for dielectric, a dummy name will be used
292 if( stackup_item->GetLayerName().IsEmpty() )
293 {
294 wxString ly_name;
295
296 if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
297 ly_name = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() );
298
299 if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
300 ly_name = _( "Dielectric" );
301
302 t->SetText( ly_name );
303 }
304 else
305 {
306 t->SetText( stackup_item->GetLayerName() );
307 }
308
309 colLayer.push_back( t );
310
311 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
312 t->SetText( stackup_item->GetTypeName() );
313 colType.push_back( t );
314
315 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
316 t->SetText( stackup_item->GetMaterial( sublayer_id ) );
317 colMaterial.push_back( t );
318
319 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
320 t->SetText( m_frame->StringFromValue( stackup_item->GetThickness( sublayer_id ), true ) );
321 colThickness.push_back( t );
322
323 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
324 t->SetText( stackup_item->GetColor( sublayer_id ) );
325 colColor.push_back( t );
326
327 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
329 stackup_item->GetEpsilonR( sublayer_id ), false ) );
330 colEpsilon.push_back( t );
331
332 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
334 stackup_item->GetLossTangent( sublayer_id ), false ) );
335 colTanD.push_back( t );
336 }
337 }
338
339 texts.push_back( colLayer );
340 texts.push_back( colType );
341 texts.push_back( colMaterial );
342 texts.push_back( colThickness );
343 texts.push_back( colColor );
344 texts.push_back( colEpsilon );
345 texts.push_back( colTanD );
346 std::vector<BOARD_ITEM*> table = initTextTable( texts, aOrigin, aLayer, tableSize, true );
347
348 if( aDrawNow )
349 {
350 for( BOARD_ITEM* item : table )
351 commit.Add( item );
352
353 commit.Push( _( "Insert board stackup table" ) );
354 }
355
356 return table;
357}
358
359
360std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawBoardCharacteristics( const VECTOR2I& aOrigin,
361 PCB_LAYER_ID aLayer,
362 bool aDrawNow,
363 VECTOR2I* tableSize )
364{
365 BOARD_COMMIT commit( m_frame );
366 std::vector<BOARD_ITEM*> objects;
368 BOARD_STACKUP& stackup = settings.GetStackupDescriptor();
369
370 VECTOR2I cursorPos = aOrigin;
371
372 // Style : Section header
373 std::unique_ptr<PCB_TEXT> headStyle =
374 std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
375 headStyle->SetLayer( Eco1_User );
376 headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.0 ), pcbIUScale.mmToIU( 2.0 ) ) );
377 headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.4 ) );
378 headStyle->SetItalic( false );
379 headStyle->SetTextPos( VECTOR2I( 0, 0 ) );
380 headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
381 headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
382
383 // Style : Data
384 std::unique_ptr<PCB_TEXT> dataStyle =
385 std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
386 dataStyle->SetLayer( Eco1_User );
387 dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
388 dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) );
389 dataStyle->SetItalic( false );
390 dataStyle->SetTextPos( VECTOR2I( 0, 0 ) );
391 dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
392 dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
393
394 PCB_TEXT* t;
395
396 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
397 t->SetText( _( "BOARD CHARACTERISTICS" ) );
398 t->SetPosition( cursorPos );
399 objects.push_back( t );
400
401 cursorPos.y = cursorPos.y + t->GetBoundingBox().GetHeight()
403
404 std::vector<std::vector<PCB_TEXT*>> texts;
405 std::vector<PCB_TEXT*> colLabel1;
406 std::vector<PCB_TEXT*> colData1;
407 std::vector<PCB_TEXT*> colbreak;
408 std::vector<PCB_TEXT*> colLabel2;
409 std::vector<PCB_TEXT*> colData2;
410
411 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
412 t->SetText( _( "Copper Layer Count: " ) );
413 colLabel1.push_back( t );
414
415 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
417 settings.GetCopperLayerCount(), false ) );
418 colData1.push_back( t );
419
420 SHAPE_POLY_SET outline;
422 BOX2I size = outline.BBox();
423 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
424 t->SetText( _( "Board overall dimensions: " ) );
425 colLabel1.push_back( t );
426
427 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
428 t->SetText( wxString::Format( wxT( "%s x %s" ),
429 m_frame->MessageTextFromValue( size.GetWidth(), true ),
430 m_frame->MessageTextFromValue( size.GetHeight(), true ) ) );
431 colData1.push_back( t );
432
433 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
434 t->SetText( _( "Min track/spacing: " ) );
435 colLabel1.push_back( t );
436
437 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
438 t->SetText( wxString::Format( wxT( "%s / %s" ),
440 m_frame->MessageTextFromValue( settings.m_MinClearance, true ) ) );
441 colData1.push_back( t );
442
443 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
444 t->SetText( _( "Copper Finish: " ) );
445 colLabel1.push_back( t );
446
447 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
448 t->SetText( stackup.m_FinishType );
449 colData1.push_back( t );
450
451 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
452 t->SetText( _( "Castellated pads: " ) );
453 colLabel1.push_back( t );
454
455 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
456 t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) );
457 colData1.push_back( t );
458
459 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
460 t->SetText( _( "Board Thickness: " ) );
461 colLabel2.push_back( t );
462
463 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
464 t->SetText( m_frame->MessageTextFromValue( settings.GetBoardThickness(), true ) );
465 colData2.push_back( t );
466
467 // some empty cells
468 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
469 colLabel2.push_back( t );
470 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
471 colData2.push_back( t );
472
473 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
474 t->SetText( _( "Min hole diameter: " ) );
475 colLabel2.push_back( t );
476 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
477
478 double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize );
479 t->SetText( m_frame->MessageTextFromValue( holeSize, true ) );
480 colData2.push_back( t );
481
482 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
483 t->SetText( _( "Impedance Control: " ) );
484 colLabel2.push_back( t );
485
486 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
487 t->SetText( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) );
488 colData2.push_back( t );
489
490 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
491 t->SetText( _( "Plated Board Edge: " ) );
492 colLabel2.push_back( t );
493
494 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
495 t->SetText( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) );
496 colData2.push_back( t );
497
498 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
499 t->SetText( _( "Edge card connectors: " ) );
500 colLabel1.push_back( t );
501
502 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
503 switch( stackup.m_EdgeConnectorConstraints )
504 {
505 case BS_EDGE_CONNECTOR_NONE: t->SetText( _( "No" ) ); break;
506 case BS_EDGE_CONNECTOR_IN_USE: t->SetText( _( "Yes" ) ); break;
507 case BS_EDGE_CONNECTOR_BEVELLED: t->SetText( _( "Yes, Bevelled" ) ); break;
508 }
509 colData1.push_back( t );
510
511 texts.push_back( colLabel1 );
512 texts.push_back( colData1 );
513 texts.push_back( colbreak );
514 texts.push_back( colLabel2 );
515 texts.push_back( colData2 );
516 VECTOR2I tableSize2;
517
518 std::vector<BOARD_ITEM*> table = initTextTable( texts, cursorPos, Eco1_User, &tableSize2,
519 false );
520
521 for( BOARD_ITEM* item : table )
522 objects.push_back( item );
523
524 if( aDrawNow )
525 {
526 for( BOARD_ITEM* item : objects )
527 commit.Add( item );
528
529 commit.Push( wxT( "Board Characteristics" ) );
530 }
531
532 tableSize->x = tableSize2.x;
533 tableSize->y = cursorPos.y + tableSize2.y
535
536 return objects;
537}
538
539
541 std::vector<BOARD_ITEM*>& aItems,
542 std::vector<BOARD_ITEM*>& aPreview,
543 LSET* aLayers )
544{
546 return -1;
547
548 bool cancelled = false;
549
550 BOARD_COMMIT commit( m_frame );
551
553
554 // do not capture or auto-pan until we start placing the table
555 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
556
557 m_frame->PushTool( aEvent );
558
559 Activate();
560 // Must be done after Activate() so that it gets set into the correct context
561 m_controls->ShowCursor( true );
562
563 if( aEvent.HasPosition() )
564 m_toolMgr->PrimeTool( aEvent.Position() );
565
566 // Main loop: keep receiving events
567 VECTOR2I cursorPosition;
568 VECTOR2I previousCursorPosition;
569
570 view()->ClearPreview();
571 view()->InitPreview();
572
573 for( BOARD_ITEM* item : aPreview )
574 {
575 item->Move( cursorPosition - previousCursorPosition );
576 view()->AddToPreview( item );
577 }
578
579 while( TOOL_EVENT* evt = Wait() )
580 {
582 cursorPosition = m_controls->GetCursorPosition();
583
584 if( evt->IsCancelInteractive() )
585 {
586 m_frame->PopTool( aEvent );
587 cancelled = true;
588 break;
589 }
590 else if( evt->IsMotion() )
591 {
592 view()->ShowPreview( false );
593
594 for( BOARD_ITEM* item : aPreview )
595 item->Move( cursorPosition - previousCursorPosition );
596
597 view()->ShowPreview( true );
598
599 previousCursorPosition = cursorPosition;
600 }
601 else if( evt->IsActivate() )
602 {
603 if( evt->IsMoveTool() )
604 {
605 // leave ourselves on the stack so we come back after the move
606 cancelled = true;
607 break;
608 }
609 else
610 {
611 m_frame->PopTool( aEvent );
612 cancelled = true;
613 break;
614 }
615 }
616 else if( evt->IsClick( BUT_RIGHT ) )
617 {
619 }
620 else if( evt->IsClick( BUT_LEFT ) )
621 {
622 if( aLayers != nullptr )
623 {
625 *aLayers, wxGetMousePosition() );
626
627 view()->ClearPreview();
628
629 if( destLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
630 {
631 // The user did not pick any layer.
632 m_frame->PopTool( aEvent );
633 cancelled = true;
634 break;
635 }
636
637 for( BOARD_ITEM* item : aItems )
638 {
639 if( item->Type() == PCB_GROUP_T )
640 static_cast<PCB_GROUP*>( item )->SetLayerRecursive( destLayer, 200 );
641 else
642 item->SetLayer( destLayer );
643 }
644 }
645
646 for( BOARD_ITEM* item : aItems )
647 {
648 item->Move( cursorPosition );
649
650 if( item->Type() == PCB_GROUP_T )
651 static_cast<PCB_GROUP*>( item )->AddChildrenToCommit( commit );
652
653 commit.Add( item );
654 }
655
656 commit.Push( wxT( "Placing items" ) );
657 m_frame->PopTool( aEvent );
658
659 break;
660 }
661 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
662 // but we don't at present have that, so we just knock out some of the egregious ones.
663 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
664 {
665 wxBell();
666 }
667 else
668 {
669 evt->SetPassEvent();
670 }
671 }
672
673 view()->ClearPreview();
674 frame()->SetMsgPanel( board() );
675
676 if( cancelled )
677 return -1;
678
679 return 0;
680}
681
682
684{
685 VECTOR2I tableSize;
686
687 LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
688 layerSet = layerSet.set( Edge_Cuts ).set( Margin );
689 layerSet = layerSet.reset( F_Fab ).reset( B_Fab );
690
692
693 if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
695
696 std::vector<BOARD_ITEM*> table = DrawBoardCharacteristics( { 0, 0 }, m_frame->GetActiveLayer(),
697 false, &tableSize );
698 std::vector<BOARD_ITEM*> preview;
699 std::vector<BOARD_ITEM*> items;
700
701 PCB_SHAPE* line1 = new PCB_SHAPE;
702 PCB_SHAPE* line2 = new PCB_SHAPE;
703 PCB_SHAPE* line3 = new PCB_SHAPE;
704 PCB_SHAPE* line4 = new PCB_SHAPE;
705
706 line1->SetStart( VECTOR2I( 0, 0 ) );
707 line1->SetEnd( VECTOR2I( tableSize.x, 0 ) );
708
709 line2->SetStart( VECTOR2I( 0, 0 ) );
710 line2->SetEnd( VECTOR2I( 0, tableSize.y ) );
711
712 line3->SetStart( VECTOR2I( tableSize.x, 0 ) );
713 line3->SetEnd( tableSize );
714
715 line4->SetStart( VECTOR2I( 0, tableSize.y ) );
716 line4->SetEnd( tableSize );
717
718 line1->SetLayer( m_frame->GetActiveLayer() );
719 line2->SetLayer( m_frame->GetActiveLayer() );
720 line3->SetLayer( m_frame->GetActiveLayer() );
721 line4->SetLayer( m_frame->GetActiveLayer() );
722
723 preview.push_back( line1 );
724 preview.push_back( line2 );
725 preview.push_back( line3 );
726 preview.push_back( line4 );
727
729 group->SetName("group-boardCharacteristics");
730
731 for( auto item : table )
732 group->AddItem( static_cast<BOARD_ITEM*>( item ) );
733
734 items.push_back( static_cast<BOARD_ITEM*>( group ) );
735
736 if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
737 m_frame->SetActiveLayer( layer );
738 else
739 m_frame->SetActiveLayer( table.front()->GetLayer() );
740
741 return 0;
742}
743
744
746{
747 VECTOR2I tableSize;
748
749 LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
750 layerSet = layerSet.set( Edge_Cuts ).set( Margin );
751 layerSet = layerSet.reset( F_Fab ).reset( B_Fab );
752
754 PCB_LAYER_ID savedLayer = layer;
755
756 if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
757 {
759 layer = Cmts_User;
760 }
761
762 std::vector<BOARD_ITEM*> table = DrawSpecificationStackup( VECTOR2I( 0, 0 ),
763 m_frame->GetActiveLayer(), false,
764 &tableSize );
765 std::vector<BOARD_ITEM*> preview;
766 std::vector<BOARD_ITEM*> items;
767
768 PCB_SHAPE* line1 = new PCB_SHAPE;
769 PCB_SHAPE* line2 = new PCB_SHAPE;
770 PCB_SHAPE* line3 = new PCB_SHAPE;
771 PCB_SHAPE* line4 = new PCB_SHAPE;
772
773 line1->SetStart( VECTOR2I( 0, 0 ) );
774 line1->SetEnd( VECTOR2I( tableSize.x, 0 ) );
775
776 line2->SetStart( VECTOR2I( 0, 0 ) );
777 line2->SetEnd( VECTOR2I( 0, tableSize.y ) );
778
779 line3->SetStart( VECTOR2I( tableSize.x, 0 ) );
780 line3->SetEnd( tableSize );
781
782 line4->SetStart( VECTOR2I( 0, tableSize.y ) );
783 line4->SetEnd( tableSize );
784
785 line1->SetLayer( m_frame->GetActiveLayer() );
786 line2->SetLayer( m_frame->GetActiveLayer() );
787 line3->SetLayer( m_frame->GetActiveLayer() );
788 line4->SetLayer( m_frame->GetActiveLayer() );
789
790 preview.push_back( line1 );
791 preview.push_back( line2 );
792 preview.push_back( line3 );
793 preview.push_back( line4 );
794
796 group->SetName( "group-boardStackUp" );
797
798 for( BOARD_ITEM* item : table )
799 group->AddItem( item );
800
801 items.push_back( static_cast<BOARD_ITEM*>( group ) );
802
803 if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
804 m_frame->SetActiveLayer( savedLayer );
805 else
806 m_frame->SetActiveLayer( table.front()->GetLayer() );
807
808 return 0;
809}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
constexpr EDA_IU_SCALE unityScale
Definition: base_units.h:112
@ BS_EDGE_CONNECTOR_BEVELLED
Definition: board_stackup.h:57
@ BS_EDGE_CONNECTOR_NONE
Definition: board_stackup.h:55
@ BS_EDGE_CONNECTOR_IN_USE
Definition: board_stackup.h:56
@ BS_ITEM_TYPE_DIELECTRIC
Definition: board_stackup.h:44
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
Container for design settings for a BOARD object.
int GetBoardThickness() const
The full thickness of the board including copper and masks.
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:226
Manage one layer needed to make a physical board.
Definition: board_stackup.h:91
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString GetColor(int aDielectricSubLayer=0) const
wxString GetLayerName() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
bool m_CastellatedPads
True if castellated pads exist.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int GetCount() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:1972
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:474
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:704
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
KIGFX::VIEW_CONTROLS * m_controls
Definition: drawing_tool.h:340
int PlaceCharacteristics(const TOOL_EVENT &aEvent)
int PlaceStackup(const TOOL_EVENT &aEvent)
int InteractivePlaceWithPreview(const TOOL_EVENT &aEvent, std::vector< BOARD_ITEM * > &aItems, std::vector< BOARD_ITEM * > &aPreview, LSET *aLayers)
Interactively place a set of BOARD_ITEM.
std::vector< BOARD_ITEM * > DrawBoardCharacteristics(const VECTOR2I &origin, PCB_LAYER_ID aLayer, bool aDrawNow, VECTOR2I *tablesize)
std::vector< BOARD_ITEM * > DrawSpecificationStackup(const VECTOR2I &origin, PCB_LAYER_ID aLayer, bool aDrawNow, VECTOR2I *tablesize)
BOARD * m_board
Definition: drawing_tool.h:341
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:342
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
void SetStart(const VECTOR2I &aStart)
Definition: eda_shape.h:124
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:149
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:165
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1649
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1635
void InitPreview()
Definition: view.cpp:1628
void ClearPreview()
Definition: view.cpp:1613
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:532
static LSET AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition: lset.cpp:841
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
PCB_LAYER_ID SelectOneLayer(PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask=LSET(), wxPoint aDlgPosition=wxDefaultPosition)
Show the dialog box for a layer selection.
Definition: sel_layer.cpp:274
virtual PCB_LAYER_ID GetActiveLayer() const
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: pcb_group.h:122
void AddChildrenToCommit(BOARD_COMMIT &aCommit)
Add all the immediate children of this group to the board commit.
Definition: pcb_group.h:196
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_text.cpp:140
virtual void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_text.h:81
KIGFX::PCB_VIEW * view() const
PCB_BASE_EDIT_FRAME * frame() const
BOARD * board() const
bool m_isFootprintEditor
const PCB_SELECTION & selection() const
FOOTPRINT * footprint() const
RAII class that sets an value at construction and resets it to the original value at destruction.
Represent a set of closed polygons.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool HasPosition() const
Definition: tool_event.h:243
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Converts aValue in internal units into a united string.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A lower-precision version of StringFromValue().
EDA_UNITS GetUserUnits() const
static bool IsZoneFillAction(const TOOL_EVENT *aEvent)
static std::vector< BOARD_ITEM * > initTextTable(std::vector< std::vector< PCB_TEXT * > > aContent, VECTOR2I origin, PCB_LAYER_ID aLayer, VECTOR2I *aTableSize, bool aDrawFrame=true)
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ Edge_Cuts
Definition: layer_ids.h:113
@ Cmts_User
Definition: layer_ids.h:110
@ Eco1_User
Definition: layer_ids.h:111
@ F_Fab
Definition: layer_ids.h:120
@ Margin
Definition: layer_ids.h:114
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:137
@ B_Fab
Definition: layer_ids.h:119
bool IsValidLayer(int aLayerId)
Test whether a given integer is a valid layer index, i.e.
Definition: layer_ids.h:805
double FromUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: eda_units.cpp:385
wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Returns the string from aValue according to aUnits (inch, mm ...) for display.
Definition: eda_units.cpp:225
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_TOP
@ BUT_LEFT
Definition: tool_event.h:127
@ BUT_RIGHT
Definition: tool_event.h:128
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:115
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590