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.

776 lines
20 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020-2021 KiCad Developers.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. // WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality
  24. // (unless you want to improve it).
  25. #include <wx/clipbrd.h>
  26. #include <qa_utils/utility_registry.h>
  27. #include <pgm_base.h>
  28. #include <profile.h>
  29. #include <view/view_overlay.h>
  30. #include "pns_log.h"
  31. #include "router/pns_diff_pair.h"
  32. #include "router/pns_utils.h"
  33. #include "pns_log_viewer_frame.h"
  34. #include "qa/drc_proto/drc_proto.h"
  35. #include "label_manager.h"
  36. #define TOM_EXTRA_DEBUG
  37. LABEL_MANAGER::LABEL_MANAGER( KIGFX::GAL* aGal ) : m_gal( aGal )
  38. {
  39. };
  40. LABEL_MANAGER::~LABEL_MANAGER()
  41. {
  42. }
  43. void LABEL_MANAGER::Add( VECTOR2I target, std::string msg, COLOR4D color )
  44. {
  45. LABEL lbl;
  46. lbl.m_target = target;
  47. lbl.m_msg = msg;
  48. lbl.m_color = color;
  49. m_gal->SetGlyphSize( VECTOR2D( m_textSize, m_textSize ) );
  50. VECTOR2I textDims = m_gal->GetTextLineSize( msg );
  51. lbl.m_bbox.SetOrigin( lbl.m_target - textDims - VECTOR2I( m_textSize, m_textSize ) );
  52. lbl.m_bbox.SetSize( textDims );
  53. m_labels.push_back( lbl );
  54. }
  55. void LABEL_MANAGER::Add( const SHAPE_LINE_CHAIN& aL, COLOR4D color )
  56. {
  57. for( int i = 0; i < aL.PointCount(); i++ )
  58. {
  59. char msg[1024];
  60. snprintf( msg, sizeof( msg ), "%d", i );
  61. Add( aL.CPoint( i ), msg, color );
  62. }
  63. }
  64. void LABEL_MANAGER::Redraw( KIGFX::VIEW_OVERLAY* aOvl )
  65. {
  66. recalculate();
  67. for( auto& lbl : m_labels )
  68. {
  69. aOvl->SetIsFill( false );
  70. aOvl->SetIsStroke( true );
  71. aOvl->SetLineWidth( 10000 );
  72. aOvl->SetStrokeColor( lbl.m_color.Brighten( 0.7 ) );
  73. aOvl->Rectangle( lbl.m_bbox.GetOrigin(), lbl.m_bbox.GetEnd() );
  74. aOvl->BitmapText( lbl.m_msg, lbl.m_bbox.Centre(), 0.0 );
  75. VECTOR2I nearest = nearestBoxCorner( lbl.m_bbox, lbl.m_target );
  76. aOvl->Line( lbl.m_target, nearest );
  77. }
  78. }
  79. VECTOR2I LABEL_MANAGER::nearestBoxCorner( BOX2I b, VECTOR2I p )
  80. {
  81. VECTOR2I ptest[4] = { b.GetPosition(), b.GetPosition() + VECTOR2I( b.GetWidth(), 0 ),
  82. b.GetPosition() + VECTOR2I( b.GetWidth(), b.GetHeight() ),
  83. b.GetPosition() + VECTOR2I( 0, b.GetHeight() ) };
  84. int bestDist = INT_MAX;
  85. VECTOR2I rv;
  86. for( int i = 0; i < 4; i++ )
  87. {
  88. int dist = ( ptest[i] - p ).EuclideanNorm();
  89. if( dist < bestDist )
  90. {
  91. bestDist = dist;
  92. rv = ptest[i];
  93. }
  94. }
  95. return rv;
  96. }
  97. VECTOR2I LABEL_MANAGER::boxMtv( BOX2I b1, BOX2I b2 )
  98. {
  99. VECTOR2I rv( 0, 0 );
  100. b1.Normalize();
  101. b2.Normalize();
  102. if( !b1.Intersects( b2 ) )
  103. return rv;
  104. int bestDist = INT_MAX;
  105. VECTOR2I p[4] = { b2.GetPosition(), b2.GetPosition() + VECTOR2I( b2.GetWidth(), 0 ),
  106. b2.GetPosition() + VECTOR2I( b2.GetWidth(), b2.GetHeight() ),
  107. b2.GetPosition() + VECTOR2I( 0, b2.GetHeight() ) };
  108. for( int i = 0; i < 4; i++ )
  109. {
  110. if( b1.Contains( p[i] ) )
  111. {
  112. // printf("CONT %d\n", i );
  113. VECTOR2I dp[4] = { VECTOR2I( b1.GetEnd().x - p[i].x + 1, 0 ),
  114. VECTOR2I( b1.GetPosition().x - p[i].x - 1, 0 ),
  115. VECTOR2I( 0, b1.GetEnd().y - p[i].y + 1 ),
  116. VECTOR2I( 0, b1.GetPosition().y - p[i].y - 1 ) };
  117. for( int j = 0; j < 4; j++ )
  118. {
  119. BOX2I btest( b2 );
  120. btest.Move( dp[j] );
  121. if( !b1.Intersects( btest ) )
  122. {
  123. int dist = dp[j].EuclideanNorm();
  124. if( dist < bestDist )
  125. {
  126. bestDist = dist;
  127. rv = dp[j];
  128. }
  129. }
  130. }
  131. }
  132. }
  133. return rv;
  134. }
  135. void LABEL_MANAGER::recalculate()
  136. {
  137. int iterLimit = 5;
  138. while( iterLimit > 0 )
  139. {
  140. printf( "Iter %d\n", iterLimit );
  141. bool collisionsFound = false;
  142. for( int i = 0; i < m_labels.size(); i++ )
  143. {
  144. for( int j = 0; j < m_labels.size(); j++ )
  145. {
  146. if( i == j )
  147. continue;
  148. auto bb_i = m_labels[i].m_bbox;
  149. auto bb_j = m_labels[j].m_bbox;
  150. bb_i.Inflate( 100000 );
  151. bb_j.Inflate( 100000 );
  152. VECTOR2I mtv = boxMtv( bb_i, bb_j );
  153. if( mtv.x || mtv.y )
  154. {
  155. m_labels[i].m_bbox.Move( -mtv );
  156. collisionsFound = true;
  157. }
  158. }
  159. }
  160. if( !collisionsFound )
  161. break;
  162. iterLimit--;
  163. }
  164. }
  165. class WX_SHAPE_TREE_ITEM_DATA : public wxClientData
  166. {
  167. public:
  168. WX_SHAPE_TREE_ITEM_DATA( PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT* item ) : m_item( item ){};
  169. PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT* m_item;
  170. };
  171. PNS_LOG_VIEWER_OVERLAY::PNS_LOG_VIEWER_OVERLAY( KIGFX::GAL* aGal )
  172. {
  173. m_labelMgr.reset( new LABEL_MANAGER( aGal ) );
  174. }
  175. void PNS_LOG_VIEWER_OVERLAY::AnnotatedPolyline( const SHAPE_LINE_CHAIN& aL, std::string name,
  176. bool aShowVertexNumbers )
  177. {
  178. Polyline( aL );
  179. if( aShowVertexNumbers)
  180. m_labelMgr->Add( aL, GetStrokeColor() );
  181. }
  182. void PNS_LOG_VIEWER_OVERLAY::AnnotatedPoint( const VECTOR2I p, int size, std::string name, bool aShowVertexNumbers )
  183. {
  184. Line( p + VECTOR2D( size, size ), p - VECTOR2D( size, size ) );
  185. Line( p + VECTOR2D( -size, size ), p - VECTOR2D( -size, size ) );
  186. //if( aShowVertexNumbers)
  187. // m_labelMgr->Add( aL, GetStrokeColor() );
  188. }
  189. void PNS_LOG_VIEWER_OVERLAY::Arc( const SHAPE_ARC& arc )
  190. {
  191. double radius = arc.GetRadius();
  192. double start_angle = DEG2RAD( arc.GetStartAngle() );
  193. double angle = DEG2RAD( arc.GetCentralAngle() );
  194. KIGFX::VIEW_OVERLAY::SetLineWidth( arc.GetWidth() / 10 );
  195. KIGFX::VIEW_OVERLAY::Arc( arc.GetCenter(), radius, start_angle, start_angle + angle );
  196. COLOR4D prevStrokeCol = KIGFX::VIEW_OVERLAY::GetStrokeColor();
  197. COLOR4D lightStrokeCol = prevStrokeCol.WithAlpha(0.5);
  198. KIGFX::VIEW_OVERLAY::SetStrokeColor( lightStrokeCol );
  199. KIGFX::VIEW_OVERLAY::SetLineWidth( arc.GetWidth() );
  200. KIGFX::VIEW_OVERLAY::Arc( arc.GetCenter(), radius, start_angle, start_angle + angle );
  201. KIGFX::VIEW_OVERLAY::SetStrokeColor( prevStrokeCol );
  202. }
  203. void PNS_LOG_VIEWER_OVERLAY::DrawAnnotations()
  204. {
  205. m_labelMgr->Redraw( this );
  206. }
  207. PNS_LOG_VIEWER_FRAME::PNS_LOG_VIEWER_FRAME( wxFrame* frame ) : PNS_LOG_VIEWER_FRAME_BASE( frame )
  208. {
  209. LoadSettings();
  210. createView( this, PCB_DRAW_PANEL_GAL::GAL_TYPE_OPENGL );
  211. m_viewSizer->Add( m_galPanel.get(), 1, wxEXPAND, 5 );
  212. Layout();
  213. Show( true );
  214. Maximize();
  215. Raise();
  216. auto settings = static_cast<KIGFX::PCB_RENDER_SETTINGS*>(
  217. m_galPanel->GetView()->GetPainter()->GetSettings() );
  218. settings->SetZoneDisplayMode( ZONE_DISPLAY_MODE::SHOW_ZONE_OUTLINE );
  219. m_listPopupMenu = new wxMenu( wxT( "" ) );
  220. m_listPopupMenu->Append( ID_LIST_COPY, wxT( "Copy selected geometry" ), wxT( "" ),
  221. wxITEM_NORMAL );
  222. m_listPopupMenu->Append( ID_LIST_SHOW_ALL, wxT( "Show all" ), wxT( "" ), wxITEM_NORMAL );
  223. m_listPopupMenu->Append( ID_LIST_SHOW_NONE, wxT( "Show none" ), wxT( "" ), wxITEM_NORMAL );
  224. m_itemList->Connect( m_itemList->GetId(), wxEVT_TREELIST_ITEM_CONTEXT_MENU,
  225. wxMouseEventHandler( PNS_LOG_VIEWER_FRAME::onListRightClick ), nullptr,
  226. this );
  227. //m_itemList->Connect(m_itemList->GetId(),wxEVT_LISTBOX,wxCommandEventHandler(PNS_LOG_VIEWER_FRAME::onListSelect),nullptr,this);
  228. m_itemList->Connect( m_itemList->GetId(), wxEVT_TREELIST_SELECTION_CHANGED,
  229. wxCommandEventHandler( PNS_LOG_VIEWER_FRAME::onListSelect ),
  230. nullptr, this );
  231. m_itemList->Connect( m_itemList->GetId(), wxEVT_TREELIST_ITEM_CHECKED,
  232. wxCommandEventHandler( PNS_LOG_VIEWER_FRAME::onListChecked ),
  233. nullptr, this );
  234. m_itemList->AppendColumn( "Type" );
  235. m_itemList->AppendColumn( "Value" );
  236. m_itemList->AppendColumn( "File" );
  237. m_itemList->AppendColumn( "Method" );
  238. m_itemList->AppendColumn( "Line" );
  239. m_overlay.reset( new PNS_LOG_VIEWER_OVERLAY ( m_galPanel->GetGAL() ) );
  240. m_galPanel->GetView()->Add( m_overlay.get() );
  241. }
  242. PNS_LOG_VIEWER_FRAME::~PNS_LOG_VIEWER_FRAME()
  243. {
  244. m_overlay = nullptr;
  245. }
  246. void PNS_LOG_VIEWER_FRAME::createUserTools()
  247. {
  248. }
  249. PNS_TEST_DEBUG_DECORATOR::STAGE* PNS_LOG_VIEWER_FRAME::getCurrentStage()
  250. {
  251. PNS_TEST_DEBUG_DECORATOR* dbgd = m_env->GetDebugDecorator();
  252. int count = dbgd->GetStageCount();
  253. int iter = m_rewindIter;
  254. if( count <= 0 )
  255. return nullptr;
  256. if( iter < 0 )
  257. iter = 0;
  258. if( iter >= count )
  259. iter = count - 1;
  260. return dbgd->GetStage( iter );
  261. }
  262. void PNS_LOG_VIEWER_FRAME::drawLoggedItems( int iter )
  263. {
  264. if( !m_env )
  265. return;
  266. PNS_TEST_DEBUG_DECORATOR::STAGE* st = getCurrentStage();
  267. if( !st )
  268. return;
  269. m_overlay.reset( new PNS_LOG_VIEWER_OVERLAY ( m_galPanel->GetGAL() ) );
  270. m_galPanel->GetView()->Add( m_overlay.get() );
  271. auto drawShapes = [&]( PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT* ent ) -> bool
  272. {
  273. bool isEnabled = ent->IsVisible();
  274. bool isSelected = false;
  275. if( !isEnabled )
  276. return true;
  277. for( auto& sh : ent->m_shapes )
  278. {
  279. COLOR4D color = ent->m_color;
  280. int lineWidth = ent->m_width;
  281. m_overlay->SetIsStroke( true );
  282. m_overlay->SetIsFill( false );
  283. if( isSelected )
  284. {
  285. color.Brighten( 0.5 );
  286. }
  287. m_overlay->SetStrokeColor( color );
  288. m_overlay->SetLineWidth( ent->m_width );
  289. switch( sh->Type() )
  290. {
  291. case SH_CIRCLE:
  292. {
  293. auto cir = static_cast<SHAPE_CIRCLE*>( sh );
  294. m_overlay->Circle( cir->GetCenter(), cir->GetRadius() );
  295. break;
  296. }
  297. case SH_RECT:
  298. {
  299. auto rect = static_cast<SHAPE_RECT*>( sh );
  300. m_overlay->Rectangle( rect->GetPosition(), rect->GetPosition() + rect->GetSize() );
  301. break;
  302. }
  303. case SH_LINE_CHAIN:
  304. {
  305. auto lc = static_cast<SHAPE_LINE_CHAIN*>( sh );
  306. m_overlay->AnnotatedPolyline( *lc, ent->m_name, ent->m_hasLabels && isSelected );
  307. break;
  308. }
  309. default:
  310. break;
  311. }
  312. }
  313. return true;
  314. };
  315. st->m_entries->IterateTree( drawShapes );
  316. m_overlay->DrawAnnotations();
  317. m_galPanel->GetView()->MarkDirty();
  318. m_galPanel->GetParent()->Refresh();
  319. }
  320. static BOARD* loadBoard( const std::string& filename )
  321. {
  322. PLUGIN::RELEASER pi( new PCB_IO );
  323. BOARD* brd = nullptr;
  324. try
  325. {
  326. brd = pi->Load( wxString( filename.c_str() ), nullptr, nullptr );
  327. }
  328. catch( const IO_ERROR& ioe )
  329. {
  330. return nullptr;
  331. }
  332. return brd;
  333. }
  334. void PNS_LOG_VIEWER_FRAME::SetLogFile( PNS_LOG_FILE* aLog )
  335. {
  336. m_logFile.reset( aLog );
  337. SetBoard( m_logFile->GetBoard() );
  338. m_env.reset( new PNS_TEST_ENVIRONMENT );
  339. m_env->SetMode( PNS::PNS_MODE_ROUTE_SINGLE );
  340. m_env->ReplayLog( m_logFile.get() );
  341. auto dbgd = m_env->GetDebugDecorator();
  342. int n_stages = dbgd->GetStageCount();
  343. m_rewindSlider->SetMax( n_stages - 1 );
  344. m_rewindSlider->SetValue( n_stages - 1 );
  345. m_rewindIter = n_stages - 1;
  346. auto extents = m_board->GetBoundingBox();
  347. BOX2D bbd;
  348. bbd.SetOrigin( extents.GetOrigin() );
  349. bbd.SetWidth( extents.GetWidth() );
  350. bbd.SetHeight( extents.GetHeight() );
  351. bbd.Inflate( std::min( bbd.GetWidth(), bbd.GetHeight() ) / 5 );
  352. m_galPanel->GetView()->SetViewport( bbd );
  353. drawLoggedItems( m_rewindIter );
  354. updateDumpPanel( m_rewindIter );
  355. }
  356. void PNS_LOG_VIEWER_FRAME::onReload( wxCommandEvent& event )
  357. {
  358. event.Skip();
  359. }
  360. void PNS_LOG_VIEWER_FRAME::onExit( wxCommandEvent& event )
  361. {
  362. event.Skip();
  363. }
  364. void PNS_LOG_VIEWER_FRAME::onListChecked( wxCommandEvent& event )
  365. {
  366. syncModel();
  367. drawLoggedItems( m_rewindIter );
  368. }
  369. void PNS_LOG_VIEWER_FRAME::onRewindScroll( wxScrollEvent& event )
  370. {
  371. m_rewindIter = event.GetPosition();
  372. drawLoggedItems( m_rewindIter );
  373. updateDumpPanel( m_rewindIter );
  374. char str[128];
  375. sprintf( str, "%d", m_rewindIter );
  376. m_rewindPos->SetValue( str );
  377. event.Skip();
  378. }
  379. void PNS_LOG_VIEWER_FRAME::onBtnRewindLeft( wxCommandEvent& event )
  380. {
  381. if( m_rewindIter > 0 )
  382. {
  383. m_rewindIter--;
  384. drawLoggedItems( m_rewindIter );
  385. updateDumpPanel( m_rewindIter );
  386. char str[128];
  387. sprintf( str, "%d", m_rewindIter );
  388. m_rewindPos->SetValue( str );
  389. }
  390. }
  391. void PNS_LOG_VIEWER_FRAME::onBtnRewindRight( wxCommandEvent& event )
  392. {
  393. auto dbgd = m_env->GetDebugDecorator();
  394. int count = dbgd->GetStageCount();
  395. if( m_rewindIter < count )
  396. {
  397. m_rewindIter++;
  398. drawLoggedItems( m_rewindIter );
  399. updateDumpPanel( m_rewindIter );
  400. char str[128];
  401. sprintf( str, "%d", m_rewindIter );
  402. m_rewindPos->SetValue( str );
  403. }
  404. }
  405. void PNS_LOG_VIEWER_FRAME::onRewindCountText( wxCommandEvent& event )
  406. {
  407. if( !m_env )
  408. return;
  409. int val = wxAtoi( m_rewindPos->GetValue() );
  410. auto dbgd = m_env->GetDebugDecorator();
  411. int count = dbgd->GetStageCount();
  412. if( val < 0 )
  413. val = 0;
  414. if( val >= count )
  415. val = count - 1;
  416. m_rewindIter = val;
  417. m_rewindSlider->SetValue( m_rewindIter );
  418. drawLoggedItems( m_rewindIter );
  419. updateDumpPanel( m_rewindIter );
  420. event.Skip();
  421. }
  422. void PNS_LOG_VIEWER_FRAME::syncModel()
  423. {
  424. for( wxTreeListItem item = m_itemList->GetFirstItem(); item.IsOk();
  425. item = m_itemList->GetNextItem( item ) )
  426. {
  427. WX_SHAPE_TREE_ITEM_DATA* idata =
  428. static_cast<WX_SHAPE_TREE_ITEM_DATA*>( m_itemList->GetItemData( item ) );
  429. if( idata )
  430. {
  431. bool checked = m_itemList->GetCheckedState( item ) == wxCHK_CHECKED;
  432. bool selected = m_itemList->IsSelected( item );
  433. idata->m_item->m_visible = checked || selected;
  434. idata->m_item->m_selected = selected;
  435. }
  436. }
  437. }
  438. void PNS_LOG_VIEWER_FRAME::onListRightClick( wxMouseEvent& event )
  439. {
  440. auto sel = m_itemList->GetPopupMenuSelectionFromUser( *m_listPopupMenu );
  441. switch( sel )
  442. {
  443. case ID_LIST_SHOW_NONE:
  444. m_itemList->CheckItemRecursively( m_itemList->GetRootItem(), wxCHK_UNCHECKED );
  445. syncModel();
  446. drawLoggedItems( m_rewindIter );
  447. break;
  448. case ID_LIST_SHOW_ALL:
  449. m_itemList->CheckItemRecursively( m_itemList->GetRootItem(), wxCHK_CHECKED );
  450. syncModel();
  451. drawLoggedItems( m_rewindIter );
  452. break;
  453. case ID_LIST_COPY:
  454. {
  455. wxString s;
  456. PNS_TEST_DEBUG_DECORATOR::STAGE* st = getCurrentStage();
  457. if( !st )
  458. return;
  459. auto formatShapes = [&]( PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT* ent ) -> bool
  460. {
  461. if( ent->m_selected )
  462. {
  463. for( auto sh : ent->m_shapes )
  464. {
  465. s += "// " + ent->m_name + "\n " + sh->Format() + "; \n";
  466. }
  467. }
  468. return true;
  469. };
  470. st->m_entries->IterateTree( formatShapes );
  471. if( wxTheClipboard->Open() )
  472. {
  473. // This data objects are held by the clipboard,
  474. // so do not delete them in the app.
  475. wxTheClipboard->SetData( new wxTextDataObject( s ) );
  476. wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
  477. wxTheClipboard->Close();
  478. }
  479. return;
  480. }
  481. }
  482. }
  483. void PNS_LOG_VIEWER_FRAME::onListSelect( wxCommandEvent& event )
  484. {
  485. syncModel();
  486. drawLoggedItems( m_rewindIter );
  487. }
  488. void PNS_LOG_VIEWER_FRAME::buildListTree( wxTreeListItem item,
  489. PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT* ent, int depth )
  490. {
  491. #ifdef EXTRA_VERBOSE
  492. for( int i = 0; i < depth * 2; i++ )
  493. printf( " " );
  494. if( ent->m_msg.length() )
  495. printf( "MSG: %s\n", ent->m_msg.c_str() );
  496. else
  497. printf( "SHAPES: %s [%d]\n", ent->m_name.c_str(), ent->m_children.size() );
  498. #endif
  499. wxTreeListItem ritem;
  500. printf("depth %d\n", depth );
  501. if( ent->m_msg.length() )
  502. {
  503. ritem = m_itemList->AppendItem( item, "Child" );
  504. m_itemList->SetItemText( ritem, 0, "Message" );
  505. m_itemList->SetItemText( ritem, 1, ent->m_msg );
  506. }
  507. else
  508. {
  509. ritem = m_itemList->AppendItem( item, "Child" );
  510. m_itemList->SetItemText( ritem, 0, "Shapes" );
  511. m_itemList->SetItemText( ritem, 1, ent->m_name );
  512. }
  513. m_itemList->SetItemText( ritem, 2, wxFileNameFromPath( ent->m_srcLoc.fileName ) );
  514. m_itemList->SetItemText( ritem, 3, ent->m_srcLoc.funcName );
  515. m_itemList->SetItemText( ritem, 4, wxString::Format("%d", ent->m_srcLoc.line ) );
  516. m_itemList->SetItemData( ritem, new WX_SHAPE_TREE_ITEM_DATA( ent ) );
  517. if( !ent->m_children.size() )
  518. return;
  519. for( auto child : ent->m_children )
  520. {
  521. buildListTree( ritem, child, depth + 1 );
  522. }
  523. }
  524. static void expandAllChildren( wxTreeListCtrl* tree )
  525. {
  526. wxTreeListItem child = tree->GetFirstItem ();
  527. while( child.IsOk() )
  528. {
  529. tree->Expand ( child );
  530. child = tree->GetNextItem( child );
  531. }
  532. }
  533. void PNS_LOG_VIEWER_FRAME::updateDumpPanel( int iter )
  534. {
  535. if( !m_env )
  536. return;
  537. auto dbgd = m_env->GetDebugDecorator();
  538. int count = dbgd->GetStageCount();
  539. wxArrayString dumpStrings;
  540. if( count <= 0 )
  541. return;
  542. if( iter < 0 )
  543. iter = 0;
  544. if( iter >= count )
  545. iter = count - 1;
  546. auto st = dbgd->GetStage( iter );
  547. auto rootItem = m_itemList->GetRootItem();
  548. m_itemList->DeleteAllItems();
  549. buildListTree( rootItem, st->m_entries );
  550. m_itemList->CheckItemRecursively( rootItem, wxCHK_UNCHECKED );
  551. expandAllChildren( m_itemList );
  552. m_itemList->Refresh();
  553. }
  554. int replay_main_func( int argc, char* argv[] )
  555. {
  556. auto frame = new PNS_LOG_VIEWER_FRAME( nullptr );
  557. // drcCreateTestsProviderClearance();
  558. // drcCreateTestsProviderEdgeClearance();
  559. if( argc >= 2 && std::string( argv[1] ) == "-h" )
  560. {
  561. printf( "PNS Log (Re)player. Allows to step through the log written by the ROUTER_TOOL "
  562. "in debug KiCad builds. " );
  563. printf( "Requires a board file with UUIDs and a matching log file. Both are written to "
  564. "/tmp when you press '0' during routing." );
  565. return 0;
  566. }
  567. if( argc < 3 )
  568. {
  569. printf( "Expected parameters: log_file.log board_file.dump\n" );
  570. return 0;
  571. }
  572. PNS_LOG_FILE* logFile = new PNS_LOG_FILE;
  573. logFile->Load( argv[1], argv[2] );
  574. frame->SetLogFile( logFile );
  575. //SetTopFrame( frame ); // wxApp gets a face.
  576. return 0;
  577. }
  578. static bool registered2 = UTILITY_REGISTRY::Register( {
  579. "replay",
  580. "PNS Log Player",
  581. replay_main_func,
  582. } );