You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

819 lines
27 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
10 months ago
10 months ago
4 years ago
4 years ago
4 years ago
10 months ago
4 years ago
10 months ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  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 The 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. #include "drawing_tool.h"
  25. #include <kiplatform/ui.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 <gal/painter.h>
  33. #include <tools/zone_filler_tool.h>
  34. #include <board_design_settings.h>
  35. #include <footprint.h>
  36. #include <pcb_shape.h>
  37. #include <pcb_group.h>
  38. #include <pcb_text.h>
  39. #include <view/view_controls.h>
  40. #include <string_utils.h>
  41. #include <wx/utils.h>
  42. using SCOPED_DRAW_MODE = SCOPED_SET_RESET<DRAWING_TOOL::MODE>;
  43. static std::vector<BOARD_ITEM*> initTextTable( std::vector<std::vector<PCB_TEXT*>> aContent,
  44. VECTOR2I origin, PCB_LAYER_ID aLayer,
  45. VECTOR2I* aTableSize, bool aDrawFrame = true )
  46. {
  47. int i;
  48. int j;
  49. int nbCols = aContent.size();
  50. int nbRows = 0;
  51. for( const std::vector<PCB_TEXT*>& col : aContent )
  52. nbRows = std::max( nbRows, static_cast<int>( col.size() ) );
  53. // Limit the number of cells
  54. nbCols = std::min( nbCols, 99 );
  55. nbRows = std::min( nbRows, 99 );
  56. int rowHeight[99];
  57. int colWidth[99];
  58. std::vector<BOARD_ITEM*> table;
  59. // xmargin and ymargin are margins between the text and the table lines.
  60. //
  61. // +--------------------------------+
  62. // | ^ |
  63. // | | ymargin |
  64. // | v |
  65. // |<------->TEXT_TEXT_TEXT<------->|
  66. // | xmargin ^ xmargin |
  67. // | | ymargin |
  68. // | v |
  69. // +--------------------------------+
  70. //
  71. int xmargin = pcbIUScale.mmToIU( 0.75 );
  72. int ymargin = pcbIUScale.mmToIU( 0.75 );
  73. // Init table
  74. for( i = 0; i < nbRows; i++ )
  75. rowHeight[i] = 0;
  76. for( i = 0; i < nbCols; i++ )
  77. colWidth[i] = 0;
  78. // First, we determine what the height/Width should be for every cell
  79. i = 0;
  80. for( const std::vector<PCB_TEXT*>& col : aContent )
  81. {
  82. j = 0;
  83. if( i >= nbCols )
  84. break;
  85. for( const PCB_TEXT* cell : col )
  86. {
  87. if( j >= nbRows )
  88. break;
  89. int height = cell->GetBoundingBox().GetHeight() + 2 * ymargin;
  90. int width = cell->GetBoundingBox().GetWidth() + 2 * xmargin;
  91. rowHeight[j] = rowHeight[j] > height ? rowHeight[j] : height;
  92. colWidth[i] = colWidth[i] > width ? colWidth[i] : width;
  93. j++;
  94. }
  95. i++;
  96. }
  97. // get table size
  98. int height = std::accumulate( rowHeight, rowHeight + nbRows, 0 );
  99. int width = std::accumulate( colWidth, colWidth + nbCols, 0 );
  100. aTableSize->x = width;
  101. aTableSize->y = height;
  102. // Draw the frame
  103. if( aDrawFrame )
  104. {
  105. int y = origin.y;
  106. PCB_SHAPE* line;
  107. for( i = 0; i < nbRows; i++ )
  108. {
  109. line = new PCB_SHAPE;
  110. line->SetLayer( aLayer );
  111. line->SetStart( VECTOR2I( origin.x, y ) );
  112. line->SetEnd( VECTOR2I( origin.x + width, y ) );
  113. y += rowHeight[i];
  114. table.push_back( line );
  115. }
  116. line = new PCB_SHAPE;
  117. line->SetLayer( aLayer );
  118. line->SetStart( VECTOR2I( origin.x, y ) );
  119. line->SetEnd( VECTOR2I( origin.x + width, y ) );
  120. table.push_back( line );
  121. int x = origin.x;
  122. for( i = 0; i < nbCols; i++ )
  123. {
  124. line = new PCB_SHAPE;
  125. line->SetLayer( aLayer );
  126. line->SetStart( VECTOR2I( x, origin.y ) );
  127. line->SetEnd( VECTOR2I( x, origin.y + height ) );
  128. x += colWidth[i];
  129. table.push_back( line );
  130. }
  131. line = new PCB_SHAPE;
  132. line->SetLayer( aLayer );
  133. line->SetStart( VECTOR2I( x, origin.y ) );
  134. line->SetEnd( VECTOR2I( x, origin.y + height ) );
  135. table.push_back( line );
  136. }
  137. //Now add the text
  138. i = 0;
  139. VECTOR2I pos( origin.x + xmargin, origin.y + ymargin );
  140. for( std::vector<PCB_TEXT*>& col : aContent )
  141. {
  142. j = 0;
  143. if( i >= nbCols )
  144. break;
  145. pos.y = origin.y + ymargin;
  146. for( PCB_TEXT* cell : col )
  147. {
  148. if( j >= nbRows )
  149. break;
  150. cell->SetTextPos( pos );
  151. cell->SetLayer( aLayer );
  152. pos.y = pos.y + rowHeight[j];
  153. table.push_back( cell );
  154. j++;
  155. }
  156. pos.x = pos.x + colWidth[i];
  157. i++;
  158. }
  159. return table;
  160. }
  161. std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawSpecificationStackup( const VECTOR2I& aOrigin,
  162. PCB_LAYER_ID aLayer,
  163. bool aDrawNow,
  164. VECTOR2I* tableSize )
  165. {
  166. BOARD_COMMIT commit( m_frame );
  167. FOOTPRINT* footprint = static_cast<FOOTPRINT*>( m_frame->GetModel() );
  168. std::vector<std::vector<PCB_TEXT*>> texts;
  169. // Style : Header
  170. std::unique_ptr<PCB_TEXT> headStyle = std::make_unique<PCB_TEXT>( footprint );
  171. headStyle->SetLayer( Eco1_User );
  172. headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
  173. headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.3 ) );
  174. headStyle->SetItalic( false );
  175. headStyle->SetTextPos( VECTOR2I( 0, 0 ) );
  176. headStyle->SetText( _( "Layer" ) );
  177. headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  178. headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  179. // Style : data
  180. std::unique_ptr<PCB_TEXT> dataStyle = std::make_unique<PCB_TEXT>( footprint );
  181. dataStyle->SetLayer( Eco1_User );
  182. dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
  183. dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.1 ) );
  184. dataStyle->SetItalic( false );
  185. dataStyle->SetTextPos( VECTOR2I( 0, 0 ) );
  186. dataStyle->SetText( _( "Layer" ) );
  187. dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  188. dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  189. //Get Layer names
  190. BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
  191. BOARD_STACKUP& stackup = dsnSettings.GetStackupDescriptor();
  192. stackup.SynchronizeWithBoard( &dsnSettings );
  193. std::vector<BOARD_STACKUP_ITEM*> layers = stackup.GetList();
  194. std::vector<PCB_TEXT*> colLayer;
  195. std::vector<PCB_TEXT*> colType;
  196. std::vector<PCB_TEXT*> colMaterial;
  197. std::vector<PCB_TEXT*> colThickness;
  198. std::vector<PCB_TEXT*> colColor;
  199. std::vector<PCB_TEXT*> colEpsilon;
  200. std::vector<PCB_TEXT*> colTanD;
  201. PCB_TEXT* t;
  202. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  203. t->SetText( _( "Layer Name" ) );
  204. colLayer.push_back( t );
  205. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  206. t->SetText( _( "Type" ) );
  207. colType.push_back( t );
  208. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  209. t->SetText( _( "Material" ) );
  210. colMaterial.push_back( t );
  211. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  212. switch( m_frame->GetUserUnits() )
  213. {
  214. case EDA_UNITS::MM: t->SetText( _( "Thickness (mm)" ) ); break;
  215. case EDA_UNITS::INCH: t->SetText( _( "Thickness (inches)" ) ); break;
  216. case EDA_UNITS::MILS: t->SetText( _( "Thickness (mils)" ) ); break;
  217. default: wxFAIL_MSG( wxT( "Unhandled unit type" ) );
  218. }
  219. colThickness.push_back( t );
  220. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  221. t->SetText( _( "Color" ) );
  222. colColor.push_back( t );
  223. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  224. t->SetText( _( "Epsilon R" ) );
  225. colEpsilon.push_back( t );
  226. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  227. t->SetText( _( "Loss Tangent" ) );
  228. colTanD.push_back( t );
  229. for( int i = 0; i < stackup.GetCount(); i++ )
  230. {
  231. BOARD_STACKUP_ITEM* stackup_item = layers.at( i );
  232. for( int sublayer_id = 0; sublayer_id < stackup_item->GetSublayersCount(); sublayer_id++ )
  233. {
  234. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  235. // Layer names are empty until we close at least once the board setup dialog.
  236. // If the user did not open the dialog, then get the names from the board.
  237. // But dielectric layer names will be missing.
  238. // In this case, for dielectric, a dummy name will be used
  239. if( stackup_item->GetLayerName().IsEmpty() )
  240. {
  241. wxString ly_name;
  242. if( IsValidLayer( stackup_item->GetBrdLayerId() ) )
  243. ly_name = m_frame->GetBoard()->GetLayerName( stackup_item->GetBrdLayerId() );
  244. if( ly_name.IsEmpty() && stackup_item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
  245. ly_name = _( "Dielectric" );
  246. t->SetText( ly_name );
  247. }
  248. else
  249. {
  250. t->SetText( stackup_item->GetLayerName() );
  251. }
  252. colLayer.push_back( t );
  253. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  254. t->SetText( stackup_item->GetTypeName() );
  255. colType.push_back( t );
  256. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  257. t->SetText( stackup_item->GetMaterial( sublayer_id ) );
  258. colMaterial.push_back( t );
  259. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  260. t->SetText( m_frame->StringFromValue( stackup_item->GetThickness( sublayer_id ), true ) );
  261. colThickness.push_back( t );
  262. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  263. t->SetText( stackup_item->GetColor( sublayer_id ) );
  264. colColor.push_back( t );
  265. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  266. t->SetText( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED,
  267. stackup_item->GetEpsilonR( sublayer_id ), false ) );
  268. colEpsilon.push_back( t );
  269. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  270. t->SetText( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED,
  271. stackup_item->GetLossTangent( sublayer_id ), false ) );
  272. colTanD.push_back( t );
  273. }
  274. }
  275. texts.push_back( colLayer );
  276. texts.push_back( colType );
  277. texts.push_back( colMaterial );
  278. texts.push_back( colThickness );
  279. texts.push_back( colColor );
  280. texts.push_back( colEpsilon );
  281. texts.push_back( colTanD );
  282. std::vector<BOARD_ITEM*> table = initTextTable( texts, aOrigin, aLayer, tableSize, true );
  283. if( aDrawNow )
  284. {
  285. for( BOARD_ITEM* item : table )
  286. commit.Add( item );
  287. commit.Push( _( "Insert Board Stackup Table" ) );
  288. }
  289. return table;
  290. }
  291. std::vector<BOARD_ITEM*> DRAWING_TOOL::DrawBoardCharacteristics( const VECTOR2I& aOrigin,
  292. PCB_LAYER_ID aLayer,
  293. bool aDrawNow,
  294. VECTOR2I* tableSize )
  295. {
  296. BOARD_COMMIT commit( m_frame );
  297. std::vector<BOARD_ITEM*> objects;
  298. BOARD_DESIGN_SETTINGS& settings = m_frame->GetBoard()->GetDesignSettings();
  299. BOARD_STACKUP& stackup = settings.GetStackupDescriptor();
  300. VECTOR2I cursorPos = aOrigin;
  301. // Style : Section header
  302. std::unique_ptr<PCB_TEXT> headStyle =
  303. std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
  304. headStyle->SetLayer( Eco1_User );
  305. headStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 2.0 ), pcbIUScale.mmToIU( 2.0 ) ) );
  306. headStyle->SetTextThickness( pcbIUScale.mmToIU( 0.4 ) );
  307. headStyle->SetItalic( false );
  308. headStyle->SetTextPos( VECTOR2I( 0, 0 ) );
  309. headStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  310. headStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  311. // Style : Data
  312. std::unique_ptr<PCB_TEXT> dataStyle =
  313. std::make_unique<PCB_TEXT>( static_cast<FOOTPRINT*>( m_frame->GetModel() ) );
  314. dataStyle->SetLayer( Eco1_User );
  315. dataStyle->SetTextSize( VECTOR2I( pcbIUScale.mmToIU( 1.5 ), pcbIUScale.mmToIU( 1.5 ) ) );
  316. dataStyle->SetTextThickness( pcbIUScale.mmToIU( 0.2 ) );
  317. dataStyle->SetItalic( false );
  318. dataStyle->SetTextPos( VECTOR2I( 0, 0 ) );
  319. dataStyle->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  320. dataStyle->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  321. PCB_TEXT* t;
  322. t = static_cast<PCB_TEXT*>( headStyle->Duplicate() );
  323. t->SetText( _( "BOARD CHARACTERISTICS" ) );
  324. t->SetPosition( cursorPos );
  325. objects.push_back( t );
  326. cursorPos.y += t->GetBoundingBox().GetHeight()
  327. + EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, EDA_UNITS::MM, 1.0 );
  328. std::vector<std::vector<PCB_TEXT*>> texts;
  329. std::vector<PCB_TEXT*> colLabel1;
  330. std::vector<PCB_TEXT*> colData1;
  331. std::vector<PCB_TEXT*> colbreak;
  332. std::vector<PCB_TEXT*> colLabel2;
  333. std::vector<PCB_TEXT*> colData2;
  334. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  335. t->SetText( _( "Copper Layer Count: " ) );
  336. colLabel1.push_back( t );
  337. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  338. t->SetText( EDA_UNIT_UTILS::UI::StringFromValue( unityScale, EDA_UNITS::UNSCALED,
  339. settings.GetCopperLayerCount(), false ) );
  340. colData1.push_back( t );
  341. SHAPE_POLY_SET outline;
  342. m_frame->GetBoard()->GetBoardPolygonOutlines( outline );
  343. BOX2I size = outline.BBox();
  344. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  345. t->SetText( _( "Board overall dimensions: " ) );
  346. colLabel1.push_back( t );
  347. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  348. t->SetText( wxString::Format( wxT( "%s x %s" ),
  349. m_frame->MessageTextFromValue( size.GetWidth(), true ),
  350. m_frame->MessageTextFromValue( size.GetHeight(), true ) ) );
  351. colData1.push_back( t );
  352. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  353. t->SetText( _( "Min track/spacing: " ) );
  354. colLabel1.push_back( t );
  355. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  356. t->SetText( wxString::Format( wxT( "%s / %s" ),
  357. m_frame->MessageTextFromValue( settings.m_TrackMinWidth, true ),
  358. m_frame->MessageTextFromValue( settings.m_MinClearance, true ) ) );
  359. colData1.push_back( t );
  360. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  361. t->SetText( _( "Copper Finish: " ) );
  362. colLabel1.push_back( t );
  363. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  364. t->SetText( stackup.m_FinishType );
  365. colData1.push_back( t );
  366. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  367. t->SetText( _( "Castellated pads: " ) );
  368. colLabel1.push_back( t );
  369. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  370. t->SetText( stackup.m_CastellatedPads ? _( "Yes" ) : _( "No" ) );
  371. colData1.push_back( t );
  372. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  373. t->SetText( _( "Board Thickness: " ) );
  374. colLabel2.push_back( t );
  375. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  376. t->SetText( m_frame->MessageTextFromValue( settings.GetBoardThickness(), true ) );
  377. colData2.push_back( t );
  378. // some empty cells
  379. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  380. colLabel2.push_back( t );
  381. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  382. colData2.push_back( t );
  383. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  384. t->SetText( _( "Min hole diameter: " ) );
  385. colLabel2.push_back( t );
  386. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  387. double holeSize = std::min( settings.m_MinThroughDrill, settings.m_ViasMinSize );
  388. t->SetText( m_frame->MessageTextFromValue( holeSize, true ) );
  389. colData2.push_back( t );
  390. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  391. t->SetText( _( "Impedance Control: " ) );
  392. colLabel2.push_back( t );
  393. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  394. t->SetText( stackup.m_HasDielectricConstrains ? _( "Yes" ) : _( "No" ) );
  395. colData2.push_back( t );
  396. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  397. t->SetText( _( "Plated Board Edge: " ) );
  398. colLabel2.push_back( t );
  399. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  400. t->SetText( stackup.m_EdgePlating ? _( "Yes" ) : _( "No" ) );
  401. colData2.push_back( t );
  402. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  403. t->SetText( _( "Edge card connectors: " ) );
  404. colLabel1.push_back( t );
  405. t = static_cast<PCB_TEXT*>( dataStyle->Duplicate() );
  406. switch( stackup.m_EdgeConnectorConstraints )
  407. {
  408. case BS_EDGE_CONNECTOR_NONE: t->SetText( _( "No" ) ); break;
  409. case BS_EDGE_CONNECTOR_IN_USE: t->SetText( _( "Yes" ) ); break;
  410. case BS_EDGE_CONNECTOR_BEVELLED: t->SetText( _( "Yes, Bevelled" ) ); break;
  411. }
  412. colData1.push_back( t );
  413. texts.push_back( colLabel1 );
  414. texts.push_back( colData1 );
  415. texts.push_back( colbreak );
  416. texts.push_back( colLabel2 );
  417. texts.push_back( colData2 );
  418. VECTOR2I tableSize2;
  419. std::vector<BOARD_ITEM*> table = initTextTable( texts, cursorPos, Eco1_User, &tableSize2,
  420. false );
  421. for( BOARD_ITEM* item : table )
  422. objects.push_back( item );
  423. if( aDrawNow )
  424. {
  425. for( BOARD_ITEM* item : objects )
  426. commit.Add( item );
  427. commit.Push( _( "Board Characteristics" ) );
  428. }
  429. tableSize->x = tableSize2.x;
  430. tableSize->y = cursorPos.y + tableSize2.y
  431. + EDA_UNIT_UTILS::UI::FromUserUnit( pcbIUScale, EDA_UNITS::MM, 2.0 );
  432. return objects;
  433. }
  434. int DRAWING_TOOL::InteractivePlaceWithPreview( const TOOL_EVENT& aEvent,
  435. std::vector<BOARD_ITEM*>& aItems,
  436. std::vector<BOARD_ITEM*>& aPreview,
  437. LSET* aLayers )
  438. {
  439. if( m_isFootprintEditor && !m_frame->GetModel() )
  440. return -1;
  441. bool cancelled = false;
  442. BOARD_COMMIT commit( m_frame );
  443. m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
  444. // do not capture or auto-pan until we start placing the table
  445. SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::TEXT );
  446. m_frame->PushTool( aEvent );
  447. Activate();
  448. // Must be done after Activate() so that it gets set into the correct context
  449. m_controls->ShowCursor( true );
  450. if( aEvent.HasPosition() )
  451. m_toolMgr->PrimeTool( aEvent.Position() );
  452. // Main loop: keep receiving events
  453. VECTOR2I cursorPosition;
  454. VECTOR2I previousCursorPosition;
  455. view()->ClearPreview();
  456. view()->InitPreview();
  457. for( BOARD_ITEM* item : aPreview )
  458. {
  459. item->Move( cursorPosition - previousCursorPosition );
  460. view()->AddToPreview( item );
  461. }
  462. while( TOOL_EVENT* evt = Wait() )
  463. {
  464. m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
  465. cursorPosition = m_controls->GetCursorPosition();
  466. if( evt->IsCancelInteractive() )
  467. {
  468. m_frame->PopTool( aEvent );
  469. cancelled = true;
  470. break;
  471. }
  472. else if( evt->IsMotion() )
  473. {
  474. view()->ShowPreview( false );
  475. for( BOARD_ITEM* item : aPreview )
  476. item->Move( cursorPosition - previousCursorPosition );
  477. view()->ShowPreview( true );
  478. previousCursorPosition = cursorPosition;
  479. }
  480. else if( evt->IsActivate() )
  481. {
  482. if( evt->IsMoveTool() )
  483. {
  484. // leave ourselves on the stack so we come back after the move
  485. cancelled = true;
  486. break;
  487. }
  488. else
  489. {
  490. m_frame->PopTool( aEvent );
  491. cancelled = true;
  492. break;
  493. }
  494. }
  495. else if( evt->IsClick( BUT_RIGHT ) )
  496. {
  497. m_menu->ShowContextMenu( selection() );
  498. }
  499. else if( evt->IsClick( BUT_LEFT ) )
  500. {
  501. if( aLayers != nullptr )
  502. {
  503. PCB_LAYER_ID destLayer =
  504. frame()->SelectOneLayer( PCB_LAYER_ID::PCB_LAYER_ID_COUNT, *aLayers,
  505. KIPLATFORM::UI::GetMousePosition() );
  506. view()->ClearPreview();
  507. if( destLayer == PCB_LAYER_ID::UNDEFINED_LAYER )
  508. {
  509. // The user did not pick any layer.
  510. m_frame->PopTool( aEvent );
  511. cancelled = true;
  512. break;
  513. }
  514. for( BOARD_ITEM* item : aItems )
  515. {
  516. item->SetLayer( destLayer );
  517. item->RunOnChildren(
  518. [&]( BOARD_ITEM* descendant )
  519. {
  520. descendant->SetLayer( destLayer );
  521. },
  522. RECURSE_MODE::RECURSE );
  523. }
  524. }
  525. for( BOARD_ITEM* item : aItems )
  526. {
  527. item->Move( cursorPosition );
  528. commit.Add( item );
  529. item->RunOnChildren(
  530. [&]( BOARD_ITEM* descendant )
  531. {
  532. commit.Add( descendant );
  533. },
  534. RECURSE_MODE::RECURSE );
  535. }
  536. commit.Push( _( "Place Items" ) );
  537. m_frame->PopTool( aEvent );
  538. break;
  539. }
  540. // TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
  541. // but we don't at present have that, so we just knock out some of the egregious ones.
  542. else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
  543. {
  544. wxBell();
  545. }
  546. else
  547. {
  548. evt->SetPassEvent();
  549. }
  550. }
  551. view()->ClearPreview();
  552. frame()->SetMsgPanel( board() );
  553. if( cancelled )
  554. return -1;
  555. return 0;
  556. }
  557. int DRAWING_TOOL::PlaceCharacteristics( const TOOL_EVENT& aEvent )
  558. {
  559. VECTOR2I tableSize;
  560. LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
  561. layerSet = layerSet.set( Edge_Cuts ).set( Margin );
  562. layerSet = layerSet.reset( F_Fab ).reset( B_Fab );
  563. PCB_LAYER_ID layer = m_frame->GetActiveLayer();
  564. if( ( layerSet & LSET( { layer } ) ).count() ) // if layer is a forbidden layer
  565. m_frame->SetActiveLayer( Cmts_User );
  566. std::vector<BOARD_ITEM*> table = DrawBoardCharacteristics( { 0, 0 }, m_frame->GetActiveLayer(),
  567. false, &tableSize );
  568. std::vector<BOARD_ITEM*> preview;
  569. std::vector<BOARD_ITEM*> items;
  570. PCB_SHAPE* line1 = new PCB_SHAPE;
  571. PCB_SHAPE* line2 = new PCB_SHAPE;
  572. PCB_SHAPE* line3 = new PCB_SHAPE;
  573. PCB_SHAPE* line4 = new PCB_SHAPE;
  574. line1->SetStart( VECTOR2I( 0, 0 ) );
  575. line1->SetEnd( VECTOR2I( tableSize.x, 0 ) );
  576. line2->SetStart( VECTOR2I( 0, 0 ) );
  577. line2->SetEnd( VECTOR2I( 0, tableSize.y ) );
  578. line3->SetStart( VECTOR2I( tableSize.x, 0 ) );
  579. line3->SetEnd( tableSize );
  580. line4->SetStart( VECTOR2I( 0, tableSize.y ) );
  581. line4->SetEnd( tableSize );
  582. line1->SetLayer( m_frame->GetActiveLayer() );
  583. line2->SetLayer( m_frame->GetActiveLayer() );
  584. line3->SetLayer( m_frame->GetActiveLayer() );
  585. line4->SetLayer( m_frame->GetActiveLayer() );
  586. preview.push_back( line1 );
  587. preview.push_back( line2 );
  588. preview.push_back( line3 );
  589. preview.push_back( line4 );
  590. PCB_GROUP* group = new PCB_GROUP( m_board );
  591. group->SetName("group-boardCharacteristics");
  592. for( auto item : table )
  593. group->AddItem( static_cast<BOARD_ITEM*>( item ) );
  594. items.push_back( static_cast<BOARD_ITEM*>( group ) );
  595. if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
  596. m_frame->SetActiveLayer( layer );
  597. else
  598. m_frame->SetActiveLayer( table.front()->GetLayer() );
  599. return 0;
  600. }
  601. int DRAWING_TOOL::PlaceStackup( const TOOL_EVENT& aEvent )
  602. {
  603. VECTOR2I tableSize;
  604. LSET layerSet = ( layerSet.AllCuMask() | layerSet.AllTechMask() );
  605. layerSet = layerSet.set( Edge_Cuts ).set( Margin );
  606. layerSet = layerSet.reset( F_Fab ).reset( B_Fab );
  607. PCB_LAYER_ID layer = m_frame->GetActiveLayer();
  608. PCB_LAYER_ID savedLayer = layer;
  609. if( ( layerSet & LSET( { layer } ) ).count() ) // if layer is a forbidden layer
  610. {
  611. m_frame->SetActiveLayer( Cmts_User );
  612. layer = Cmts_User;
  613. }
  614. std::vector<BOARD_ITEM*> table = DrawSpecificationStackup( VECTOR2I( 0, 0 ),
  615. m_frame->GetActiveLayer(), false,
  616. &tableSize );
  617. std::vector<BOARD_ITEM*> preview;
  618. std::vector<BOARD_ITEM*> items;
  619. PCB_SHAPE* line1 = new PCB_SHAPE;
  620. PCB_SHAPE* line2 = new PCB_SHAPE;
  621. PCB_SHAPE* line3 = new PCB_SHAPE;
  622. PCB_SHAPE* line4 = new PCB_SHAPE;
  623. line1->SetStart( VECTOR2I( 0, 0 ) );
  624. line1->SetEnd( VECTOR2I( tableSize.x, 0 ) );
  625. line2->SetStart( VECTOR2I( 0, 0 ) );
  626. line2->SetEnd( VECTOR2I( 0, tableSize.y ) );
  627. line3->SetStart( VECTOR2I( tableSize.x, 0 ) );
  628. line3->SetEnd( tableSize );
  629. line4->SetStart( VECTOR2I( 0, tableSize.y ) );
  630. line4->SetEnd( tableSize );
  631. line1->SetLayer( m_frame->GetActiveLayer() );
  632. line2->SetLayer( m_frame->GetActiveLayer() );
  633. line3->SetLayer( m_frame->GetActiveLayer() );
  634. line4->SetLayer( m_frame->GetActiveLayer() );
  635. preview.push_back( line1 );
  636. preview.push_back( line2 );
  637. preview.push_back( line3 );
  638. preview.push_back( line4 );
  639. PCB_GROUP* group = new PCB_GROUP( m_board );
  640. group->SetName( "group-boardStackUp" );
  641. for( BOARD_ITEM* item : table )
  642. group->AddItem( item );
  643. items.push_back( static_cast<BOARD_ITEM*>( group ) );
  644. if( InteractivePlaceWithPreview( aEvent, items, preview, &layerSet ) == -1 )
  645. m_frame->SetActiveLayer( savedLayer );
  646. else
  647. m_frame->SetActiveLayer( table.front()->GetLayer() );
  648. return 0;
  649. }