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-2021 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 <tools/pcb_actions.h>
31 #include <tools/tool_event_utils.h>
32 #include <tools/drawing_tool.h>
33 #include <board_commit.h>
34 #include <scoped_set_reset.h>
35 #include <bitmaps.h>
36 #include <painter.h>
37 #include <board.h>
38 #include <board_design_settings.h>
39 #include <footprint.h>
40 #include <fp_shape.h>
41 #include <pcb_group.h>
42 #include <pcb_text.h>
43 #include <string_utils.h>
44 #include <wx/utils.h>
45 
46 
48 
49 
50 static std::vector<BOARD_ITEM*> initTextTable( std::vector<std::vector<PCB_TEXT*>> aContent,
51  wxPoint origin, PCB_LAYER_ID aLayer,
52  wxPoint* aTableSize,
53  bool aDrawFrame = true )
54 {
55  int i;
56  int j;
57 
58  int nbCols = aContent.size();
59  int nbRows = 0;
60 
61  for( auto col : aContent )
62  nbRows = std::max( nbRows, static_cast<int>( col.size() ) );
63 
64  // Limit the number of cells
65  nbCols = std::min( nbCols, 99 );
66  nbRows = std::min( nbRows, 99 );
67 
68  int rowHeight[99];
69  int colWidth[99];
70 
71  std::vector<BOARD_ITEM*> table;
72 
73  // xmargin and ymargin are margins between the text and the table lines.
74  //
75  // +--------------------------------+
76  // | ^ |
77  // | | ymargin |
78  // | v |
79  // |<------->TEXT_TEXT_TEXT<------->|
80  // | xmargin ^ xmargin |
81  // | | ymargin |
82  // | v |
83  // +--------------------------------+
84  //
85 
86  int xmargin = Millimeter2iu( 0.75 );
87  int ymargin = Millimeter2iu( 0.75 );
88 
89  // Init table
90  for( i = 0; i < nbRows; i++ )
91  rowHeight[i] = 0;
92 
93  for( i = 0; i < nbCols; i++ )
94  colWidth[i] = 0;
95 
96  // First, we determine what the height/Width should be for every cell
97  i = 0;
98 
99  for( const std::vector<PCB_TEXT*>& col : aContent )
100  {
101  j = 0;
102 
103  if( i >= nbCols )
104  break;
105 
106  for( const PCB_TEXT* cell : col )
107  {
108 
109  if( j >= nbRows )
110  break;
111 
112  int height = cell->GetBoundingBox().GetHeight() + 2 * ymargin;
113  int width = cell->GetBoundingBox().GetWidth() + 2 * xmargin;
114  rowHeight[j] = rowHeight[j] > height ? rowHeight[j] : height;
115  colWidth[i] = colWidth[i] > width ? colWidth[i] : width;
116  j++;
117 
118  }
119 
120  i++;
121  }
122 
123  // get table size
124  int height = std::accumulate( rowHeight, rowHeight + nbRows, 0 );
125  int width = std::accumulate( colWidth, colWidth + nbCols, 0 );
126 
127  aTableSize->x = width;
128  aTableSize->y = height;
129  // Draw the frame
130 
131  if( aDrawFrame )
132  {
133  int y = origin.y;
134  PCB_SHAPE* line;
135 
136  for( i = 0; i < nbRows; i++ )
137  {
138  line = new PCB_SHAPE;
139  line->SetLayer( aLayer );
140  line->SetStartX( origin.x );
141  line->SetStartY( y );
142  line->SetEndX( origin.x + width );
143  line->SetEndY( y );
144  y += rowHeight[i];
145  table.push_back( line );
146  }
147 
148  line = new PCB_SHAPE;
149  line->SetLayer( aLayer );
150  line->SetStartX( origin.x );
151  line->SetStartY( y );
152  line->SetEndX( origin.x + width );
153  line->SetEndY( y );
154  table.push_back( line );
155  int x = origin.x;
156 
157  for( i = 0; i < nbCols; i++ )
158  {
159  line = new PCB_SHAPE;
160  line->SetLayer( aLayer );
161  line->SetStartX( x );
162  line->SetStartY( origin.y );
163  line->SetEndX( x );
164  line->SetEndY( origin.y + height );
165  x += colWidth[i];
166  table.push_back( line );
167  }
168 
169  line = new PCB_SHAPE;
170  line->SetLayer( aLayer );
171  line->SetStartX( x );
172  line->SetStartY( origin.y );
173  line->SetEndX( x );
174  line->SetEndY( origin.y + height );
175  table.push_back( line );
176  }
177 
178  //Now add the text
179  i = 0;
180  wxPoint pos = wxPoint( origin.x + xmargin, origin.y + ymargin );
181 
182  for( std::vector<PCB_TEXT*>& col : aContent )
183  {
184  j = 0;
185 
186  if( i >= nbCols )
187  break;
188 
189  pos.y = origin.y + ymargin;
190 
191  for( PCB_TEXT* cell : col )
192  {
193 
194  if( j >= nbRows )
195  break;
196 
197  cell->SetTextPos( pos );
198  cell->SetLayer( aLayer );
199  pos.y = pos.y + rowHeight[j];
200  table.push_back( cell );
201  j++;
202  }
203 
204  pos.x = pos.x + colWidth[i];
205  i++;
206  }
207  return table;
208 }
209 
210 
211 std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawSpecificationStackup( const wxPoint& aOrigin,
212  PCB_LAYER_ID aLayer,
213  bool aDrawNow,
214  wxPoint* tableSize )
215 {
216  BOARD_COMMIT commit( m_frame );
217  std::vector<std::vector<PCB_TEXT*>> texts;
218 
219  // Style : Header
220  std::unique_ptr<PCB_TEXT> headStyle =
221  std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
222  headStyle->SetLayer( Eco1_User );
223  headStyle->SetTextSize( wxSize( Millimeter2iu( 1.5 ), Millimeter2iu( 1.5 ) ) );
224  headStyle->SetTextThickness( Millimeter2iu( 0.3 ) );
225  headStyle->SetItalic( false );
226  headStyle->SetTextPos( wxPoint( 0, 0 ) );
227  headStyle->SetText( _( "Layer" ) );
228  headStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
229  headStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
230 
231  // Style : data
232  std::unique_ptr<PCB_TEXT> dataStyle =
233  std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
234  dataStyle->SetLayer( Eco1_User );
235  dataStyle->SetTextSize( wxSize( Millimeter2iu( 1.5 ), Millimeter2iu( 1.5 ) ) );
236  dataStyle->SetTextThickness( Millimeter2iu( 0.1 ) );
237  dataStyle->SetItalic( false );
238  dataStyle->SetTextPos( wxPoint( 0, 0 ) );
239  dataStyle->SetText( _( "Layer" ) );
240  dataStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
241  dataStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
242 
243  //Get Layer names
245  BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
246  stackup.SynchronizeWithBoard( &dsnSettings );
247 
248  std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
249 
250  std::vector<PCB_TEXT*> colLayer;
251  std::vector<PCB_TEXT*> colType;
252  std::vector<PCB_TEXT*> colMaterial;
253  std::vector<PCB_TEXT*> colThickness;
254  std::vector<PCB_TEXT*> colColor;
255  std::vector<PCB_TEXT*> colEpsilon;
256  std::vector<PCB_TEXT*> colTanD;
257  PCB_TEXT* t;
258 
259  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
260  t->SetText( _( "Layer Name" ) );
261  colLayer.push_back( t );
262 
263  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
264  t->SetText( _( "Type" ) );
265  colType.push_back( t );
266 
267  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
268  t->SetText( _( "Material" ) );
269  colMaterial.push_back( t );
270 
271  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
272 
273  switch( m_frame->GetUserUnits() )
274  {
275  case EDA_UNITS::MILLIMETRES: t->SetText( _( "Thickness (mm)" ) ); break;
276  case EDA_UNITS::INCHES: t->SetText( _( "Thickness (inches)" ) ); break;
277  case EDA_UNITS::MILS: t->SetText( _( "Thickness (mils)" ) ); break;
278  default: wxFAIL_MSG( wxT( "Unhandled unit type" ) );
279  }
280 
281  colThickness.push_back( t );
282 
283  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
284  t->SetText( _( "Color" ) );
285  colColor.push_back( t );
286 
287  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
288  t->SetText( _( "Epsilon R" ) );
289  colEpsilon.push_back( t );
290 
291  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
292  t->SetText( _( "Loss Tangent" ) );
293  colTanD.push_back( t );
294 
295  for( int i = 0; i < stackup.GetCount(); i++ )
296  {
297  BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
298 
299  for( int j = 0; j < stackup_item->GetSublayersCount(); j++ )
300  {
301  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
302 
303  // Layer names are empty until we close at least once the board setup dialog.
304  // If the user did not open the dialog, then get the names from the board.
305  // But dielectric layer names will be missing.
306  // In this case, for dielectric, a dummy name will be used
307  if( stackup_item->GetLayerName().IsEmpty() )
308  {
309  wxString ly_name;
310 
311  if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
312  ly_name = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() );
313 
314  if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
315  ly_name = _( "Dielectric" );
316 
317  t->SetText( ly_name );
318  }
319  else
320  t->SetText( stackup_item->GetLayerName() );
321 
322  colLayer.push_back( t );
323 
324  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
325  t->SetText( stackup_item->GetTypeName() );
326  colType.push_back( t );
327 
328  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
329  t->SetText( stackup_item->GetMaterial( j ) );
330  colMaterial.push_back( t );
331 
332  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
333  t->SetText( StringFromValue( m_frame->GetUserUnits(), stackup_item->GetThickness( j ),
334  true ) );
335  colThickness.push_back( t );
336 
337  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
338  t->SetText( stackup_item->GetColor() );
339  colColor.push_back( t );
340 
341  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
342  t->SetText( StringFromValue( EDA_UNITS::UNSCALED, stackup_item->GetEpsilonR( j ),
343  false ) );
344  colEpsilon.push_back( t );
345 
346  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
348  false ) );
349  colTanD.push_back( t );
350  }
351  }
352 
353  texts.push_back( colLayer );
354  texts.push_back( colType );
355  texts.push_back( colMaterial );
356  texts.push_back( colThickness );
357  texts.push_back( colColor );
358  texts.push_back( colEpsilon );
359  texts.push_back( colTanD );
360  std::vector<BOARD_ITEM*> table = initTextTable( texts, aOrigin, aLayer, tableSize, true );
361 
362  if( aDrawNow )
363  {
364  for( BOARD_ITEM* item : table )
365  commit.Add( item );
366 
367  commit.Push( _( "Insert board stackup table" ) );
368  }
369 
370  return table;
371 }
372 
373 
374 std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawBoardCharacteristics( const wxPoint& aOrigin,
375  PCB_LAYER_ID aLayer,
376  bool aDrawNow,
377  wxPoint* tableSize )
378 {
379  BOARD_COMMIT commit( m_frame );
380  std::vector<BOARD_ITEM*> objects;
382  BOARD_STACKUP& stackup = settings.GetStackupDescriptor();
383 
384  wxPoint cursorPos = aOrigin;
385 
386  // Style : Section header
387  std::unique_ptr<PCB_TEXT> headStyle =
388  std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
389  headStyle->SetLayer( Eco1_User );
390  headStyle->SetTextSize( wxSize( Millimeter2iu( 2.0 ), Millimeter2iu( 2.0 ) ) );
391  headStyle->SetTextThickness( Millimeter2iu( 0.4 ) );
392  headStyle->SetItalic( false );
393  headStyle->SetTextPos( wxPoint( 0, 0 ) );
394  headStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
395  headStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
396 
397  // Style : Data
398  std::unique_ptr<PCB_TEXT> dataStyle =
399  std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
400  dataStyle->SetLayer( Eco1_User );
401  dataStyle->SetTextSize( wxSize( Millimeter2iu( 1.5 ), Millimeter2iu( 1.5 ) ) );
402  dataStyle->SetTextThickness( Millimeter2iu( 0.2 ) );
403  dataStyle->SetItalic( false );
404  dataStyle->SetTextPos( wxPoint( 0, 0 ) );
405  dataStyle->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
406  dataStyle->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
407 
408  PCB_TEXT* t;
409 
410  t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
411  t->SetText( _( "BOARD CHARACTERISTICS" ) );
412  t->SetPosition( cursorPos );
413  objects.push_back( t );
414 
415  cursorPos.y = cursorPos.y + t->GetBoundingBox().GetHeight()
417 
418  std::vector<std::vector<PCB_TEXT*>> texts;
419  std::vector<PCB_TEXT*> colLabel1;
420  std::vector<PCB_TEXT*> colData1;
421  std::vector<PCB_TEXT*> colbreak;
422  std::vector<PCB_TEXT*> colLabel2;
423  std::vector<PCB_TEXT*> colData2;
424  wxString text;
425 
426  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
427  t->SetText( _( "Copper Layer Count: " ) );
428  colLabel1.push_back( t );
429 
430  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
432  colData1.push_back( t );
433 
434  SHAPE_POLY_SET outline;
436  BOX2I size = outline.BBox();
437  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
438  t->SetText( _( "Board overall dimensions: " ) );
439  colLabel1.push_back( t );
440 
441  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
442  t->SetText( wxString::Format( wxT( "%s x %s" ),
444  MessageTextFromValue( m_frame->GetUserUnits(), size.GetHeight(), true ) ) );
445  colData1.push_back( t );
446 
447  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
448  t->SetText( _( "Min track/spacing: " ) );
449  colLabel1.push_back( t );
450 
451  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
452  t->SetText( wxString::Format( wxT( "%s / %s" ),
454  MessageTextFromValue( m_frame->GetUserUnits(), settings.m_MinClearance, true ) ) );
455  colData1.push_back( t );
456 
457  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
458  t->SetText( _( "Copper Finish: " ) );
459  colLabel1.push_back( t );
460 
461  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
462  t->SetText( stackup.m_FinishType );
463  colData1.push_back( t );
464 
465  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
466  t->SetText( _( "Castellated pads: " ) );
467  colLabel1.push_back( t );
468 
469  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
470  t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) );
471  colData1.push_back( t );
472 
473  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
474  t->SetText( _( "Board Thickness: " ) );
475  colLabel2.push_back( t );
476 
477  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
479 
480  t->SetText( text );
481  colData2.push_back( t );
482 
483  // some empty cells
484  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
485  colLabel2.push_back( t );
486  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
487  colData2.push_back( t );
488 
489  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
490  t->SetText( _( "Min hole diameter: " ) );
491  colLabel2.push_back( t );
492  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
493 
494  double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize );
495  text = MessageTextFromValue( m_frame->GetUserUnits(), holeSize, true );
496  t->SetText( text );
497  colData2.push_back( t );
498 
499  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
500  t->SetText( _( "Impedance Control: " ) );
501  colLabel2.push_back( t );
502 
503  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
504  t->SetText( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) );
505  colData2.push_back( t );
506 
507  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
508  t->SetText( _( "Plated Board Edge: " ) );
509  colLabel2.push_back( t );
510 
511  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
512  t->SetText( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) );
513  colData2.push_back( t );
514 
515  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
516  t->SetText( _( "Edge card connectors: " ) );
517  colLabel1.push_back( t );
518 
519  t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
520  switch( stackup.m_EdgeConnectorConstraints )
521  {
522  case BS_EDGE_CONNECTOR_NONE: t->SetText( _( "No" ) ); break;
523  case BS_EDGE_CONNECTOR_IN_USE: t->SetText( _( "Yes" ) ); break;
524  case BS_EDGE_CONNECTOR_BEVELLED: t->SetText( _( "Yes, Bevelled" ) ); break;
525  }
526  colData1.push_back( t );
527 
528  texts.push_back( colLabel1 );
529  texts.push_back( colData1 );
530  texts.push_back( colbreak );
531  texts.push_back( colLabel2 );
532  texts.push_back( colData2 );
533  wxPoint tableSize2 = wxPoint();
534 
535  std::vector<BOARD_ITEM*> table = initTextTable( texts, cursorPos, Eco1_User, &tableSize2,
536  false );
537 
538  for( BOARD_ITEM* item : table )
539  objects.push_back( item );
540 
541  if( aDrawNow )
542  {
543  for( auto item : objects )
544  commit.Add( item );
545 
546  commit.Push( wxT( "Board Characteristics" ) );
547  }
548 
549  tableSize->x = tableSize2.x;
550  tableSize->y = cursorPos.y + tableSize2.y + From_User_Unit( EDA_UNITS::MILLIMETRES, 2.0 );
551 
552  return objects;
553 }
554 
555 
557  std::vector<BOARD_ITEM*>& aItems,
558  std::vector<BOARD_ITEM*>& aPreview,
559  LSET* aLayers )
560 {
562  return -1;
563 
564  bool cancelled = false;
565 
566  BOARD_COMMIT commit( m_frame );
567 
569 
570  // do not capture or auto-pan until we start placing the table
571  SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
572 
573  std::string tool = aEvent.GetCommandStr().get();
574  m_frame->PushTool( tool );
575 
576  Activate();
577  // Must be done after Activate() so that it gets set into the correct context
578  m_controls->ShowCursor( true );
579 
580  // Prime the pump
581  if( aEvent.HasPosition() )
583 
584  // Main loop: keep receiving events
585  wxPoint wxCursorPosition = wxPoint();
586  wxPoint wxPreviousCursorPosition = wxPoint( 0, 0 );
587 
588  view()->ClearPreview();
589  view()->InitPreview();
590 
591  for( BOARD_ITEM* item : aPreview )
592  {
593  item->Move( wxCursorPosition - wxPreviousCursorPosition );
594  view()->AddToPreview( item );
595  }
596 
597  while( TOOL_EVENT* evt = Wait() )
598  {
601  wxCursorPosition.x = pos.x;
602  wxCursorPosition.y = pos.y;
603 
604  if( evt->IsCancelInteractive() )
605  {
606  m_frame->PopTool( tool );
607  cancelled = true;
608  break;
609  }
610 
611  if( evt->IsMotion() )
612  {
613  view()->ShowPreview( false );
614 
615  for( auto item : aPreview )
616  {
617  item->Move( wxCursorPosition - wxPreviousCursorPosition );
618  }
619 
620  view()->ShowPreview( true );
621 
622  wxPreviousCursorPosition.x = wxCursorPosition.x;
623  wxPreviousCursorPosition.y = wxCursorPosition.y;
624 
625  }
626  else if( evt->IsActivate() )
627  {
628 
629  if( evt->IsMoveTool() )
630  {
631  // leave ourselves on the stack so we come back after the move
632  cancelled = true;
633  break;
634  }
635  else
636  {
637  m_frame->PopTool( tool );
638  cancelled = true;
639  break;
640  }
641  }
642  else if( evt->IsClick( BUT_RIGHT ) )
643  {
645  }
646  else if( evt->IsClick( BUT_LEFT ) )
647  {
648  if( aLayers != nullptr )
649  {
651  *aLayers, wxGetMousePosition() );
652 
653  view()->ClearPreview();
654 
655  if( destLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
656  {
657  // The user did not pick any layer.
658  m_frame->PopTool( tool );
659  cancelled = true;
660  break;
661  }
662 
663  for( BOARD_ITEM* item : aItems )
664  {
665  if( item->Type() == PCB_GROUP_T )
666  static_cast<PCB_GROUP*>( item )->SetLayerRecursive( destLayer, 200 );
667  else
668  item->SetLayer( destLayer );
669  }
670  }
671 
672  for( BOARD_ITEM* item : aItems )
673  {
674  item->Move( wxCursorPosition );
675 
676  if( item->Type() == PCB_GROUP_T )
677  static_cast<PCB_GROUP*>( item )->AddChildrenToCommit( commit );
678 
679  commit.Add( item );
680  }
681 
682  commit.Push( wxT( "Placing items" ) );
683  m_frame->PopTool( tool );
684 
685  break;
686  }
687  else
688  {
689  evt->SetPassEvent();
690  }
691  }
692 
693  view()->ClearPreview();
694  frame()->SetMsgPanel( board() );
695 
696  if( cancelled )
697  return -1;
698 
699  return 0;
700 }
701 
702 
704 {
705  wxPoint tableSize = wxPoint();
706 
707  LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
708  layerSet = static_cast<LSET>( layerSet.set( Edge_Cuts ).set( Margin ) );
709  layerSet = static_cast<LSET>( layerSet.reset( F_Fab ).reset( B_Fab ) );
710 
712  PCB_LAYER_ID savedLayer = layer;
713 
714  if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
715  {
717  layer = Cmts_User;
718  }
719 
720  std::vector<BOARD_ITEM*> table = DrawBoardCharacteristics( wxPoint( 0, 0 ),
721  m_frame->GetActiveLayer(), false,
722  &tableSize );
723  std::vector<BOARD_ITEM*> preview;
724  std::vector<BOARD_ITEM*> items;
725 
726  PCB_SHAPE* line1 = new PCB_SHAPE;
727  PCB_SHAPE* line2 = new PCB_SHAPE;
728  PCB_SHAPE* line3 = new PCB_SHAPE;
729  PCB_SHAPE* line4 = new PCB_SHAPE;
730 
731  line1->SetStartX( 0 );
732  line1->SetStartY( 0 );
733  line1->SetEndX( tableSize.x );
734  line1->SetEndY( 0 );
735 
736  line2->SetStartX( 0 );
737  line2->SetStartY( 0 );
738  line2->SetEndX( 0 );
739  line2->SetEndY( tableSize.y );
740 
741  line3->SetStartX( tableSize.x );
742  line3->SetStartY( 0 );
743  line3->SetEndX( tableSize.x );
744  line3->SetEndY( tableSize.y );
745 
746  line4->SetStartX( 0 );
747  line4->SetStartY( tableSize.y );
748  line4->SetEndX( tableSize.x );
749  line4->SetEndY( tableSize.y );
750 
751  line1->SetLayer( m_frame->GetActiveLayer() );
752  line2->SetLayer( m_frame->GetActiveLayer() );
753  line3->SetLayer( m_frame->GetActiveLayer() );
754  line4->SetLayer( m_frame->GetActiveLayer() );
755 
756  preview.push_back( line1 );
757  preview.push_back( line2 );
758  preview.push_back( line3 );
759  preview.push_back( line4 );
760 
761  PCB_GROUP* group = new PCB_GROUP( m_board );
762  group->SetName("group-boardCharacteristics");
763 
764  for( auto item : table )
765  group->AddItem( static_cast<BOARD_ITEM*>( item ) );
766 
767  items.push_back( static_cast<BOARD_ITEM*>( group ) );
768 
769  if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
770  m_frame->SetActiveLayer( savedLayer );
771  else
772  m_frame->SetActiveLayer( table.front()->GetLayer() );
773 
774  return 0;
775 }
776 
777 
779 {
780  wxPoint tableSize = wxPoint();
781 
782  LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
783  layerSet = static_cast<LSET>( layerSet.set( Edge_Cuts ).set( Margin ) );
784  layerSet = static_cast<LSET>( layerSet.reset( F_Fab ).reset( B_Fab ) );
785 
787  PCB_LAYER_ID savedLayer = layer;
788 
789  if( ( layerSet & LSET( layer ) ).count() ) // if layer is a forbidden layer
790  {
792  layer = Cmts_User;
793  }
794 
795  std::vector<BOARD_ITEM*> table = DrawSpecificationStackup(
796  wxPoint( 0, 0 ), m_frame->GetActiveLayer(), false, &tableSize );
797  std::vector<BOARD_ITEM*> preview;
798  std::vector<BOARD_ITEM*> items;
799 
800  PCB_SHAPE* line1 = new PCB_SHAPE;
801  PCB_SHAPE* line2 = new PCB_SHAPE;
802  PCB_SHAPE* line3 = new PCB_SHAPE;
803  PCB_SHAPE* line4 = new PCB_SHAPE;
804 
805  line1->SetStartX( 0 );
806  line1->SetStartY( 0 );
807  line1->SetEndX( tableSize.x );
808  line1->SetEndY( 0 );
809 
810  line2->SetStartX( 0 );
811  line2->SetStartY( 0 );
812  line2->SetEndX( 0 );
813  line2->SetEndY( tableSize.y );
814 
815  line3->SetStartX( tableSize.x );
816  line3->SetStartY( 0 );
817  line3->SetEndX( tableSize.x );
818  line3->SetEndY( tableSize.y );
819 
820  line4->SetStartX( 0 );
821  line4->SetStartY( tableSize.y );
822  line4->SetEndX( tableSize.x );
823  line4->SetEndY( tableSize.y );
824 
825  line1->SetLayer( m_frame->GetActiveLayer() );
826  line2->SetLayer( m_frame->GetActiveLayer() );
827  line3->SetLayer( m_frame->GetActiveLayer() );
828  line4->SetLayer( m_frame->GetActiveLayer() );
829 
830  preview.push_back( line1 );
831  preview.push_back( line2 );
832  preview.push_back( line3 );
833  preview.push_back( line4 );
834 
835  PCB_GROUP* group = new PCB_GROUP( m_board );
836  group->SetName("group-boardStackUp");
837 
838  for( BOARD_ITEM* item : table )
839  group->AddItem( item );
840 
841  items.push_back( static_cast<BOARD_ITEM*>( group ) );
842 
843  if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
844  m_frame->SetActiveLayer( savedLayer );
845  else
846  m_frame->SetActiveLayer( table.front()->GetLayer() );
847 
848  return 0;
849 }
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: pcb_actions.h:59
BOARD_STACKUP_ITEM_TYPE GetType() const
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
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:759
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:104
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.
TOOL_MENU m_menu
The functions below are not yet implemented - their interface may change.
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Returns the BOARD_DESIGN_SETTINGS for the open project.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:362
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:1835
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.
BOARD * board() const
BOARD * m_board
Definition: drawing_tool.h:268
virtual void SetPosition(const wxPoint &aPos) override
Definition: pcb_text.h:81
Manage layers needed to make a physical board.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:164
int GetSublayersCount() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
std::vector< BOARD_ITEM * > DrawBoardCharacteristics(const wxPoint &origin, PCB_LAYER_ID aLayer, bool aDrawNow, wxPoint *tablesize)
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
wxString m_FinishType
The name of external copper finish.
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1614
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
bool m_EdgePlating
True if the edge board is plated.
void SetStartY(int y)
Definition: eda_shape.h:116
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:214
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
void InitPreview()
Definition: view.cpp:1607
bool m_CastellatedPads
True if castellated pads exist.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
wxString GetColor() const
void SetEndY(int y)
Definition: eda_shape.h:141
static LSET AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition: lset.cpp:829
static std::vector< BOARD_ITEM * > initTextTable(std::vector< std::vector< PCB_TEXT * >> aContent, wxPoint origin, PCB_LAYER_ID aLayer, wxPoint *aTableSize, bool aDrawFrame=true)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
double GetLossTangent(int aDielectricSubLayer=0) const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
void ShowPreview(bool aShow=true)
Definition: view.cpp:1628
PCB_BASE_EDIT_FRAME * frame() const
virtual PCB_LAYER_ID GetActiveLayer() const
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
BOARD_STACKUP & GetStackupDescriptor()
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
RAII class that sets an value at construction and resets it to the original value at destruction.
const PCB_SELECTION & selection() const
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
int GetThickness(int aDielectricSubLayer=0) const
Represent a set of closed polygons.
virtual void PopTool(const std::string &actionName)
coord_type GetWidth() const
Definition: box2.h:180
Generic, UI-independent tool event.
Definition: tool_event.h:152
double GetEpsilonR(int aDielectricSubLayer=0) const
void ClearPreview()
Definition: view.cpp:1592
KIGFX::PCB_VIEW * view() const
wxString GetTypeName() const
#define _(s)
int PlaceCharacteristics(const TOOL_EVENT &aEvent)
KIGFX::VIEW_CONTROLS * m_controls
Definition: drawing_tool.h:267
std::vector< BOARD_ITEM * > DrawSpecificationStackup(const wxPoint &origin, PCB_LAYER_ID aLayer, bool aDrawNow, wxPoint *tablesize)
int GetCount() const
virtual void SetActiveLayer(PCB_LAYER_ID aLayer)
bool m_isFootprintEditor
Manage one layer needed to make a physical board.
Definition: board_stackup.h:89
int GetHeight() const
Definition: eda_rect.h:119
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
PCB_LAYER_ID GetBrdLayerId() const
PCB_BASE_EDIT_FRAME * m_frame
Definition: drawing_tool.h:269
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
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
wxString GetLayerName() const
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:460
void SetEndX(int x)
Definition: eda_shape.h:147
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
int PlaceStackup(const TOOL_EVENT &aEvent)
coord_type GetHeight() const
Definition: box2.h:181
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:204
void Activate()
Run the tool.
bool IsValidLayer(LAYER_NUM aLayerId)
Test whether a given integer is a valid layer index, i.e.
Definition: layer_ids.h:786
bool HasPosition() const
Definition: tool_event.h:240
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_text.cpp:132
BOARD * GetBoard() const
static constexpr int Millimeter2iu(double mm)
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:59
wxString GetMaterial(int aDielectricSubLayer=0) const
double From_User_Unit(EDA_UNITS aUnits, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: base_units.cpp:282
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
static TOOL_ACTION cursorClick
Definition: actions.h:123
void SetStartX(int x)
Definition: eda_shape.h:122
Container for design settings for a BOARD object.