KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <kiplatform/ui.h>
27#include "pcb_actions.h"
28#include <pcb_edit_frame.h>
29#include <view/view.h>
30#include <tool/tool_manager.h>
31#include <board_commit.h>
32#include <scoped_set_reset.h>
33#include <gal/painter.h>
36#include <footprint.h>
37#include <pcb_shape.h>
38#include <pcb_group.h>
39#include <pcb_text.h>
40#include <view/view_controls.h>
41#include <string_utils.h>
42#include <wx/utils.h>
43
44
46
47
48static std::vector<BOARD_ITEM*> initTextTable( std::vector<std::vector<PCB_TEXT*>> aContent,
49 VECTOR2I origin, PCB_LAYER_ID aLayer,
50 VECTOR2I* aTableSize, bool aDrawFrame = true )
51{
52 int i;
53 int j;
54
55 int nbCols = aContent.size();
56 int nbRows = 0;
57
58 for( const std::vector<PCB_TEXT*>& col : aContent )
59 nbRows = std::max( nbRows, static_cast<int>( col.size() ) );
60
61 // Limit the number of cells
62 nbCols = std::min( nbCols, 99 );
63 nbRows = std::min( nbRows, 99 );
64
65 int rowHeight[99];
66 int colWidth[99];
67
68 std::vector<BOARD_ITEM*> table;
69
70 // xmargin and ymargin are margins between the text and the table lines.
71 //
72 // +--------------------------------+
73 // | ^ |
74 // | | ymargin |
75 // | v |
76 // |<------->TEXT_TEXT_TEXT<------->|
77 // | xmargin ^ xmargin |
78 // | | ymargin |
79 // | v |
80 // +--------------------------------+
81 //
82
83 int xmargin = pcbIUScale.mmToIU( 0.75 );
84 int ymargin = pcbIUScale.mmToIU( 0.75 );
85
86 // Init table
87 for( i = 0; i < nbRows; i++ )
88 rowHeight[i] = 0;
89
90 for( i = 0; i < nbCols; i++ )
91 colWidth[i] = 0;
92
93 // First, we determine what the height/Width should be for every cell
94 i = 0;
95
96 for( const std::vector<PCB_TEXT*>& col : aContent )
97 {
98 j = 0;
99
100 if( i >= nbCols )
101 break;
102
103 for( const PCB_TEXT* cell : col )
104 {
105 if( j >= nbRows )
106 break;
107
108 int height = cell->GetBoundingBox().GetHeight() + 2 * ymargin;
109 int width = cell->GetBoundingBox().GetWidth() + 2 * xmargin;
110 rowHeight[j] = rowHeight[j] > height ? rowHeight[j] : height;
111 colWidth[i] = colWidth[i] > width ? colWidth[i] : width;
112 j++;
113 }
114
115 i++;
116 }
117
118 // get table size
119 int height = std::accumulate( rowHeight, rowHeight + nbRows, 0 );
120 int width = std::accumulate( colWidth, colWidth + nbCols, 0 );
121
122 aTableSize->x = width;
123 aTableSize->y = height;
124 // Draw the frame
125
126 if( aDrawFrame )
127 {
128 int y = origin.y;
129 PCB_SHAPE* line;
130
131 for( i = 0; i < nbRows; i++ )
132 {
133 line = new PCB_SHAPE;
134 line->SetLayer( aLayer );
135 line->SetStart( VECTOR2I( origin.x, y ) );
136 line->SetEnd( VECTOR2I( origin.x + width, y ) );
137 y += rowHeight[i];
138 table.push_back( line );
139 }
140
141 line = new PCB_SHAPE;
142 line->SetLayer( aLayer );
143 line->SetStart( VECTOR2I( origin.x, y ) );
144 line->SetEnd( VECTOR2I( origin.x + width, y ) );
145 table.push_back( line );
146 int x = origin.x;
147
148 for( i = 0; i < nbCols; i++ )
149 {
150 line = new PCB_SHAPE;
151 line->SetLayer( aLayer );
152 line->SetStart( VECTOR2I( x, origin.y ) );
153 line->SetEnd( VECTOR2I( x, origin.y + height ) );
154 x += colWidth[i];
155 table.push_back( line );
156 }
157
158 line = new PCB_SHAPE;
159 line->SetLayer( aLayer );
160 line->SetStart( VECTOR2I( x, origin.y ) );
161 line->SetEnd( VECTOR2I( x, origin.y + height ) );
162 table.push_back( line );
163 }
164
165 //Now add the text
166 i = 0;
167 VECTOR2I pos( origin.x + xmargin, origin.y + ymargin );
168
169 for( std::vector<PCB_TEXT*>& col : aContent )
170 {
171 j = 0;
172
173 if( i >= nbCols )
174 break;
175
176 pos.y = origin.y + ymargin;
177
178 for( PCB_TEXT* cell : col )
179 {
180 if( j >= nbRows )
181 break;
182
183 cell->SetTextPos( pos );
184 cell->SetLayer( aLayer );
185 pos.y = pos.y + rowHeight[j];
186 table.push_back( cell );
187 j++;
188 }
189
190 pos.x = pos.x + colWidth[i];
191 i++;
192 }
193
194 return table;
195}
196
197
198std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawSpecificationStackup( const VECTOR2I& aOrigin,
199 PCB_LAYER_ID aLayer,
200 bool aDrawNow,
201 VECTOR2I* tableSize )
202{
203 BOARD_COMMIT commit( m_frame );
204 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( m_frame->GetModel() );
205
206 std::vector<std::vector<PCB_TEXT*>> texts;
207
208 // Style : Header
209 std::unique_ptr<PCB_TEXT> headStyle = std::make_unique<PCB_TEXT>( footprint );
210 headStyle->SetLayer( Eco1_User );
211 headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
212 headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.3 ) );
213 headStyle->SetItalic( false );
214 headStyle->SetTextPos( VECTOR2I( 0, 0 ) );
215 headStyle->SetText( _( "Layer" ) );
216 headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
217 headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
218
219 // Style : data
220 std::unique_ptr<PCB_TEXT> dataStyle = std::make_unique<PCB_TEXT>( footprint );
221 dataStyle->SetLayer( Eco1_User );
222 dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
223 dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.1 ) );
224 dataStyle->SetItalic( false );
225 dataStyle->SetTextPos( VECTOR2I( 0, 0 ) );
226 dataStyle->SetText( _( "Layer" ) );
227 dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
228 dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
229
230 //Get Layer names
232 BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
233 stackup.SynchronizeWithBoard( &dsnSettings );
234
235 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
236
237 std::vector<PCB_TEXT*> colLayer;
238 std::vector<PCB_TEXT*> colType;
239 std::vector<PCB_TEXT*> colMaterial;
240 std::vector<PCB_TEXT*> colThickness;
241 std::vector<PCB_TEXT*> colColor;
242 std::vector<PCB_TEXT*> colEpsilon;
243 std::vector<PCB_TEXT*> colTanD;
244 PCB_TEXT* t;
245
246 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
247 t->SetText( _( "Layer Name" ) );
248 colLayer.push_back( t );
249
250 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
251 t->SetText( _( "Type" ) );
252 colType.push_back( t );
253
254 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
255 t->SetText( _( "Material" ) );
256 colMaterial.push_back( t );
257
258 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
259
260 switch( m_frame->GetUserUnits() )
261 {
262 case EDA_UNITS::MILLIMETRES: t->SetText( _( "Thickness (mm)" ) ); break;
263 case EDA_UNITS::INCHES: t->SetText( _( "Thickness (inches)" ) ); break;
264 case EDA_UNITS::MILS: t->SetText( _( "Thickness (mils)" ) ); break;
265 default: wxFAIL_MSG( wxT( "Unhandled unit type" ) );
266 }
267
268 colThickness.push_back( t );
269
270 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
271 t->SetText( _( "Color" ) );
272 colColor.push_back( t );
273
274 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
275 t->SetText( _( "Epsilon R" ) );
276 colEpsilon.push_back( t );
277
278 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
279 t->SetText( _( "Loss Tangent" ) );
280 colTanD.push_back( t );
281
282 for( int i = 0; i < stackup.GetCount(); i++ )
283 {
284 BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
285
286 for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ )
287 {
288 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
289
290 // Layer names are empty until we close at least once the board setup dialog.
291 // If the user did not open the dialog, then get the names from the board.
292 // But dielectric layer names will be missing.
293 // In this case, for dielectric, a dummy name will be used
294 if( stackup_item->GetLayerName().IsEmpty() )
295 {
296 wxString ly_name;
297
298 if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
299 ly_name = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() );
300
301 if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
302 ly_name = _( "Dielectric" );
303
304 t->SetText( ly_name );
305 }
306 else
307 {
308 t->SetText( stackup_item->GetLayerName() );
309 }
310
311 colLayer.push_back( t );
312
313 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
314 t->SetText( stackup_item->GetTypeName() );
315 colType.push_back( t );
316
317 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
318 t->SetText( stackup_item->GetMaterial( sublayer_id ) );
319 colMaterial.push_back( t );
320
321 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
322 t->SetText( m_frame->StringFromValue( stackup_item->GetThickness( sublayer_id ), true ) );
323 colThickness.push_back( t );
324
325 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
326 t->SetText( stackup_item->GetColor( sublayer_id ) );
327 colColor.push_back( t );
328
329 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
331 stackup_item->GetEpsilonR( sublayer_id ), false ) );
332 colEpsilon.push_back( t );
333
334 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
336 stackup_item->GetLossTangent( sublayer_id ), false ) );
337 colTanD.push_back( t );
338 }
339 }
340
341 texts.push_back( colLayer );
342 texts.push_back( colType );
343 texts.push_back( colMaterial );
344 texts.push_back( colThickness );
345 texts.push_back( colColor );
346 texts.push_back( colEpsilon );
347 texts.push_back( colTanD );
348 std::vector<BOARD_ITEM*> table = initTextTable( texts, aOrigin, aLayer, tableSize, true );
349
350 if( aDrawNow )
351 {
352 for( BOARD_ITEM* item : table )
353 commit.Add( item );
354
355 commit.Push( _( "Insert Board Stackup Table" ) );
356 }
357
358 return table;
359}
360
361
362std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawBoardCharacteristics( const VECTOR2I& aOrigin,
363 PCB_LAYER_ID aLayer,
364 bool aDrawNow,
365 VECTOR2I* tableSize )
366{
367 BOARD_COMMIT commit( m_frame );
368 std::vector<BOARD_ITEM*> objects;
370 BOARD_STACKUP& stackup = settings.GetStackupDescriptor();
371
372 VECTOR2I cursorPos = aOrigin;
373
374 // Style : Section header
375 std::unique_ptr<PCB_TEXT> headStyle =
376 std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
377 headStyle->SetLayer( Eco1_User );
378 headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.0 ), pcbIUScale.mmToIU( 2.0 ) ) );
379 headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.4 ) );
380 headStyle->SetItalic( false );
381 headStyle->SetTextPos( VECTOR2I( 0, 0 ) );
382 headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
383 headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
384
385 // Style : Data
386 std::unique_ptr<PCB_TEXT> dataStyle =
387 std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
388 dataStyle->SetLayer( Eco1_User );
389 dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
390 dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) );
391 dataStyle->SetItalic( false );
392 dataStyle->SetTextPos( VECTOR2I( 0, 0 ) );
393 dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
394 dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
395
396 PCB_TEXT* t;
397
398 t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
399 t->SetText( _( "BOARD CHARACTERISTICS" ) );
400 t->SetPosition( cursorPos );
401 objects.push_back( t );
402
403 cursorPos.y = cursorPos.y + t->GetBoundingBox().GetHeight()
404 + EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, EDA_UNITS::MILLIMETRES, 1.0 );
405
406 std::vector<std::vector<PCB_TEXT*>> texts;
407 std::vector<PCB_TEXT*> colLabel1;
408 std::vector<PCB_TEXT*> colData1;
409 std::vector<PCB_TEXT*> colbreak;
410 std::vector<PCB_TEXT*> colLabel2;
411 std::vector<PCB_TEXT*> colData2;
412
413 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
414 t->SetText( _( "Copper Layer Count: " ) );
415 colLabel1.push_back( t );
416
417 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
419 settings.GetCopperLayerCount(), false ) );
420 colData1.push_back( t );
421
422 SHAPE_POLY_SET outline;
424 BOX2I size = outline.BBox();
425 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
426 t->SetText( _( "Board overall dimensions: " ) );
427 colLabel1.push_back( t );
428
429 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
430 t->SetText( wxString::Format( wxT( "%s x %s" ),
431 m_frame->MessageTextFromValue( size.GetWidth(), true ),
432 m_frame->MessageTextFromValue( size.GetHeight(), true ) ) );
433 colData1.push_back( t );
434
435 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
436 t->SetText( _( "Min track/spacing: " ) );
437 colLabel1.push_back( t );
438
439 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
440 t->SetText( wxString::Format( wxT( "%s / %s" ),
442 m_frame->MessageTextFromValue( settings.m_MinClearance, true ) ) );
443 colData1.push_back( t );
444
445 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
446 t->SetText( _( "Copper Finish: " ) );
447 colLabel1.push_back( t );
448
449 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
450 t->SetText( stackup.m_FinishType );
451 colData1.push_back( t );
452
453 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
454 t->SetText( _( "Castellated pads: " ) );
455 colLabel1.push_back( t );
456
457 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
458 t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) );
459 colData1.push_back( t );
460
461 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
462 t->SetText( _( "Board Thickness: " ) );
463 colLabel2.push_back( t );
464
465 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
466 t->SetText( m_frame->MessageTextFromValue( settings.GetBoardThickness(), true ) );
467 colData2.push_back( t );
468
469 // some empty cells
470 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
471 colLabel2.push_back( t );
472 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
473 colData2.push_back( t );
474
475 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
476 t->SetText( _( "Min hole diameter: " ) );
477 colLabel2.push_back( t );
478 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
479
480 double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize );
481 t->SetText( m_frame->MessageTextFromValue( holeSize, true ) );
482 colData2.push_back( t );
483
484 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
485 t->SetText( _( "Impedance Control: " ) );
486 colLabel2.push_back( t );
487
488 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
489 t->SetText( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) );
490 colData2.push_back( t );
491
492 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
493 t->SetText( _( "Plated Board Edge: " ) );
494 colLabel2.push_back( t );
495
496 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
497 t->SetText( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) );
498 colData2.push_back( t );
499
500 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
501 t->SetText( _( "Edge card connectors: " ) );
502 colLabel1.push_back( t );
503
504 t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
505 switch( stackup.m_EdgeConnectorConstraints )
506 {
507 case BS_EDGE_CONNECTOR_NONE: t->SetText( _( "No" ) ); break;
508 case BS_EDGE_CONNECTOR_IN_USE: t->SetText( _( "Yes" ) ); break;
509 case BS_EDGE_CONNECTOR_BEVELLED: t->SetText( _( "Yes, Bevelled" ) ); break;
510 }
511 colData1.push_back( t );
512
513 texts.push_back( colLabel1 );
514 texts.push_back( colData1 );
515 texts.push_back( colbreak );
516 texts.push_back( colLabel2 );
517 texts.push_back( colData2 );
518 VECTOR2I tableSize2;
519
520 std::vector<BOARD_ITEM*> table = initTextTable( texts, cursorPos, Eco1_User, &tableSize2,
521 false );
522
523 for( BOARD_ITEM* item : table )
524 objects.push_back( item );
525
526 if( aDrawNow )
527 {
528 for( BOARD_ITEM* item : objects )
529 commit.Add( item );
530
531 commit.Push( wxT( "Board Characteristics" ) );
532 }
533
534 tableSize->x = tableSize2.x;
535 tableSize->y = cursorPos.y + tableSize2.y
536 + EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, EDA_UNITS::MILLIMETRES, 2.0 );
537
538 return objects;
539}
540
541
543 std::vector<BOARD_ITEM*>& aItems,
544 std::vector<BOARD_ITEM*>& aPreview,
545 LSET* aLayers )
546{
548 return -1;
549
550 bool cancelled = false;
551
552 BOARD_COMMIT commit( m_frame );
553
555
556 // do not capture or auto-pan until we start placing the table
557 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
558
559 m_frame->PushTool( aEvent );
560
561 Activate();
562 // Must be done after Activate() so that it gets set into the correct context
563 m_controls->ShowCursor( true );
564
565 if( aEvent.HasPosition() )
566 m_toolMgr->PrimeTool( aEvent.Position() );
567
568 // Main loop: keep receiving events
569 VECTOR2I cursorPosition;
570 VECTOR2I previousCursorPosition;
571
572 view()->ClearPreview();
573 view()->InitPreview();
574
575 for( BOARD_ITEM* item : aPreview )
576 {
577 item->Move( cursorPosition - previousCursorPosition );
578 view()->AddToPreview( item );
579 }
580
581 while( TOOL_EVENT* evt = Wait() )
582 {
583 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
584 cursorPosition = m_controls->GetCursorPosition();
585
586 if( evt->IsCancelInteractive() )
587 {
588 m_frame->PopTool( aEvent );
589 cancelled = true;
590 break;
591 }
592 else if( evt->IsMotion() )
593 {
594 view()->ShowPreview( false );
595
596 for( BOARD_ITEM* item : aPreview )
597 item->Move( cursorPosition - previousCursorPosition );
598
599 view()->ShowPreview( true );
600
601 previousCursorPosition = cursorPosition;
602 }
603 else if( evt->IsActivate() )
604 {
605 if( evt->IsMoveTool() )
606 {
607 // leave ourselves on the stack so we come back after the move
608 cancelled = true;
609 break;
610 }
611 else
612 {
613 m_frame->PopTool( aEvent );
614 cancelled = true;
615 break;
616 }
617 }
618 else if( evt->IsClick( BUT_RIGHT ) )
619 {
621 }
622 else if( evt->IsClick( BUT_LEFT ) )
623 {
624 if( aLayers != nullptr )
625 {
626 PCB_LAYER_ID destLayer =
627 frame()->SelectOneLayer( PCB_LAYER_ID::PCB_LAYER_ID_COUNT, *aLayers,
629
630 view()->ClearPreview();
631
632 if( destLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
633 {
634 // The user did not pick any layer.
635 m_frame->PopTool( aEvent );
636 cancelled = true;
637 break;
638 }
639
640 for( BOARD_ITEM* item : aItems )
641 {
642 item->SetLayer( destLayer );
643
644 item->RunOnDescendants(
645 [&]( BOARD_ITEM* descendant )
646 {
647 descendant->SetLayer( destLayer );
648 } );
649 }
650 }
651
652 for( BOARD_ITEM* item : aItems )
653 {
654 item->Move( cursorPosition );
655 commit.Add( item );
656
657 item->RunOnDescendants(
658 [&]( BOARD_ITEM* descendant )
659 {
660 commit.Add( descendant );
661 } );
662 }
663
664 commit.Push( wxT( "Placing items" ) );
665 m_frame->PopTool( aEvent );
666
667 break;
668 }
669 // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
670 // but we don't at present have that, so we just knock out some of the egregious ones.
671 else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
672 {
673 wxBell();
674 }
675 else
676 {
677 evt->SetPassEvent();
678 }
679 }
680
681 view()->ClearPreview();
682 frame()->SetMsgPanel( board() );
683
684 if( cancelled )
685 return -1;
686
687 return 0;
688}
689
690
692{
693 VECTOR2I tableSize;
694
695 LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
696 layerSet = layerSet.set( Edge_Cuts ).set( Margin );
697 layerSet = layerSet.reset( F_Fab ).reset( B_Fab );
698
700
701 if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
703
704 std::vector<BOARD_ITEM*> table = DrawBoardCharacteristics( { 0, 0 }, m_frame->GetActiveLayer(),
705 false, &tableSize );
706 std::vector<BOARD_ITEM*> preview;
707 std::vector<BOARD_ITEM*> items;
708
709 PCB_SHAPE* line1 = new PCB_SHAPE;
710 PCB_SHAPE* line2 = new PCB_SHAPE;
711 PCB_SHAPE* line3 = new PCB_SHAPE;
712 PCB_SHAPE* line4 = new PCB_SHAPE;
713
714 line1->SetStart( VECTOR2I( 0, 0 ) );
715 line1->SetEnd( VECTOR2I( tableSize.x, 0 ) );
716
717 line2->SetStart( VECTOR2I( 0, 0 ) );
718 line2->SetEnd( VECTOR2I( 0, tableSize.y ) );
719
720 line3->SetStart( VECTOR2I( tableSize.x, 0 ) );
721 line3->SetEnd( tableSize );
722
723 line4->SetStart( VECTOR2I( 0, tableSize.y ) );
724 line4->SetEnd( tableSize );
725
726 line1->SetLayer( m_frame->GetActiveLayer() );
727 line2->SetLayer( m_frame->GetActiveLayer() );
728 line3->SetLayer( m_frame->GetActiveLayer() );
729 line4->SetLayer( m_frame->GetActiveLayer() );
730
731 preview.push_back( line1 );
732 preview.push_back( line2 );
733 preview.push_back( line3 );
734 preview.push_back( line4 );
735
737 group->SetName("group-boardCharacteristics");
738
739 for( auto item : table )
740 group->AddItem( static_cast<BOARD_ITEM*>( item ) );
741
742 items.push_back( static_cast<BOARD_ITEM*>( group ) );
743
744 if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
745 m_frame->SetActiveLayer( layer );
746 else
747 m_frame->SetActiveLayer( table.front()->GetLayer() );
748
749 return 0;
750}
751
752
754{
755 VECTOR2I tableSize;
756
757 LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
758 layerSet = layerSet.set( Edge_Cuts ).set( Margin );
759 layerSet = layerSet.reset( F_Fab ).reset( B_Fab );
760
762 PCB_LAYER_ID savedLayer = layer;
763
764 if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
765 {
767 layer = Cmts_User;
768 }
769
770 std::vector<BOARD_ITEM*> table = DrawSpecificationStackup( VECTOR2I( 0, 0 ),
771 m_frame->GetActiveLayer(), false,
772 &tableSize );
773 std::vector<BOARD_ITEM*> preview;
774 std::vector<BOARD_ITEM*> items;
775
776 PCB_SHAPE* line1 = new PCB_SHAPE;
777 PCB_SHAPE* line2 = new PCB_SHAPE;
778 PCB_SHAPE* line3 = new PCB_SHAPE;
779 PCB_SHAPE* line4 = new PCB_SHAPE;
780
781 line1->SetStart( VECTOR2I( 0, 0 ) );
782 line1->SetEnd( VECTOR2I( tableSize.x, 0 ) );
783
784 line2->SetStart( VECTOR2I( 0, 0 ) );
785 line2->SetEnd( VECTOR2I( 0, tableSize.y ) );
786
787 line3->SetStart( VECTOR2I( tableSize.x, 0 ) );
788 line3->SetEnd( tableSize );
789
790 line4->SetStart( VECTOR2I( 0, tableSize.y ) );
791 line4->SetEnd( tableSize );
792
793 line1->SetLayer( m_frame->GetActiveLayer() );
794 line2->SetLayer( m_frame->GetActiveLayer() );
795 line3->SetLayer( m_frame->GetActiveLayer() );
796 line4->SetLayer( m_frame->GetActiveLayer() );
797
798 preview.push_back( line1 );
799 preview.push_back( line2 );
800 preview.push_back( line3 );
801 preview.push_back( line4 );
802
804 group->SetName( "group-boardStackUp" );
805
806 for( BOARD_ITEM* item : table )
807 group->AddItem( item );
808
809 items.push_back( static_cast<BOARD_ITEM*>( group ) );
810
811 if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
812 m_frame->SetActiveLayer( savedLayer );
813 else
814 m_frame->SetActiveLayer( table.front()->GetLayer() );
815
816 return 0;
817}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr EDA_IU_SCALE unityScale
Definition: base_units.h:111
@ BS_EDGE_CONNECTOR_BEVELLED
Definition: board_stackup.h:58
@ BS_EDGE_CONNECTOR_NONE
Definition: board_stackup.h:56
@ BS_EDGE_CONNECTOR_IN_USE
Definition: board_stackup.h:57
@ BS_ITEM_TYPE_DIELECTRIC
Definition: board_stackup.h:45
virtual void Push(const wxString &aMessage=wxEmptyString, 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:77
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:260
Manage one layer needed to make a physical board.
Definition: board_stackup.h:95
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, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:2373
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:564
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
size_type GetHeight() const
Definition: box2.h:205
size_type GetWidth() const
Definition: box2.h:204
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
KIGFX::VIEW_CONTROLS * m_controls
Definition: drawing_tool.h:352
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:353
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:354
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:129
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:166
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:181
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:1689
void InitPreview()
Definition: view.cpp:1668
void ClearPreview()
Definition: view.cpp:1653
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1675
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:575
static LSET AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition: lset.cpp:931
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:68
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:285
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_shape.cpp:315
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_text.cpp:393
virtual void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_text.h:87
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:217
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool HasPosition() const
Definition: tool_event.h:256
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
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, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
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 MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
EDA_UNITS GetUserUnits() const
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
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:60
@ 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
@ 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:859
KICOMMON_API double FromUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Return in internal units the value aValue given in a real unit such as "in", "mm",...
Definition: eda_units.cpp:510
KICOMMON_API 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:300
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: gtk/ui.cpp:606
Class to handle a set of BOARD_ITEMs.
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_TOP
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
VECTOR2< int > VECTOR2I
Definition: vector2d.h:602