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.

407 lines
14 KiB

  1. /**
  2. * @file swap_layers.cpp
  3. * @brief Dialog to swap layers.
  4. */
  5. #include <fctsys.h>
  6. #include <class_drawpanel.h>
  7. #include <confirm.h>
  8. #include <wxPcbStruct.h>
  9. #include <dialog_shim.h>
  10. #include <class_board.h>
  11. #include <class_track.h>
  12. #include <class_drawsegment.h>
  13. #include <pcbnew.h>
  14. #include <wx/statline.h>
  15. #define NO_CHANGE LAYER_ID(-3)
  16. enum swap_layer_id {
  17. ID_WINEDA_SWAPLAYERFRAME = 1800,
  18. ID_BUTTON_0,
  19. ID_TEXT_0 = ID_BUTTON_0 + LAYER_ID_COUNT
  20. };
  21. class SWAP_LAYERS_DIALOG : public DIALOG_SHIM
  22. {
  23. public:
  24. SWAP_LAYERS_DIALOG( PCB_BASE_FRAME* parent, LAYER_ID* aArray );
  25. // ~SWAP_LAYERS_DIALOG() { };
  26. private:
  27. PCB_BASE_FRAME* m_Parent;
  28. wxBoxSizer* OuterBoxSizer;
  29. wxBoxSizer* MainBoxSizer;
  30. wxFlexGridSizer* FlexColumnBoxSizer;
  31. wxStaticText* label;
  32. wxButton* Button;
  33. wxStaticText* text;
  34. wxStaticLine* Line;
  35. wxStdDialogButtonSizer* StdDialogButtonSizer;
  36. LAYER_ID* m_callers_nlayers; // DIM() is LAYER_ID_COUNT
  37. wxStaticText* layer_list[LAYER_ID_COUNT];
  38. void Sel_Layer( wxCommandEvent& event );
  39. void OnOkClick( wxCommandEvent& event );
  40. void OnCancelClick( wxCommandEvent& event );
  41. DECLARE_EVENT_TABLE()
  42. };
  43. BEGIN_EVENT_TABLE( SWAP_LAYERS_DIALOG, wxDialog )
  44. EVT_COMMAND_RANGE( ID_BUTTON_0, ID_BUTTON_0 + LAYER_ID_COUNT - 1,
  45. wxEVT_COMMAND_BUTTON_CLICKED, SWAP_LAYERS_DIALOG::Sel_Layer )
  46. EVT_BUTTON( wxID_OK, SWAP_LAYERS_DIALOG::OnOkClick )
  47. EVT_BUTTON( wxID_CANCEL, SWAP_LAYERS_DIALOG::OnCancelClick )
  48. END_EVENT_TABLE()
  49. SWAP_LAYERS_DIALOG::SWAP_LAYERS_DIALOG( PCB_BASE_FRAME* parent, LAYER_ID* aArray ) :
  50. DIALOG_SHIM( parent, -1, _( "Swap Layers:" ), wxPoint( -1, -1 ),
  51. wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
  52. m_callers_nlayers( aArray )
  53. {
  54. memset( layer_list, 0, sizeof( layer_list ) );
  55. BOARD* board = parent->GetBoard();
  56. OuterBoxSizer = NULL;
  57. MainBoxSizer = NULL;
  58. FlexColumnBoxSizer = NULL;
  59. label = NULL;
  60. Button = NULL;
  61. text = NULL;
  62. Line = NULL;
  63. StdDialogButtonSizer = NULL;
  64. m_Parent = parent;
  65. int item_ID;
  66. wxSize goodSize;
  67. /* Experimentation has shown that buttons in the Windows version can be
  68. * 20 pixels wide and 20 pixels high, but that they need to be 26 pixels
  69. * wide and 26 pixels high in the Linux version. (And although the
  70. * dimensions of those buttons could be set to 26 pixels wide and 26
  71. * pixels high in both of those versions, that would result in a dialog
  72. * box which would be excessively high in the Windows version.)
  73. */
  74. #ifdef __WINDOWS__
  75. int w = 20;
  76. int h = 20;
  77. #else
  78. int w = 26;
  79. int h = 26;
  80. #endif
  81. /* As currently implemented, the dimensions of the buttons in the Mac
  82. * version are also 26 pixels wide and 26 pixels high. If appropriate,
  83. * the above code should be modified as required in the event that those
  84. * buttons should be some other size in that version.
  85. */
  86. OuterBoxSizer = new wxBoxSizer( wxVERTICAL );
  87. SetSizer( OuterBoxSizer );
  88. MainBoxSizer = new wxBoxSizer( wxHORIZONTAL );
  89. OuterBoxSizer->Add( MainBoxSizer, 1, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
  90. for( unsigned layer = 0; layer < DIM( layer_list ); ++layer )
  91. {
  92. // Provide a vertical line to separate the two FlexGrid sizers
  93. if( layer == 32 )
  94. {
  95. Line = new wxStaticLine( this,
  96. -1,
  97. wxDefaultPosition,
  98. wxDefaultSize,
  99. wxLI_VERTICAL );
  100. MainBoxSizer->Add( Line, 0, wxGROW | wxLEFT | wxRIGHT, 5 );
  101. }
  102. // Provide a separate FlexGrid sizer for every sixteen sets of controls
  103. if( layer % 16 == 0 )
  104. {
  105. /* Each layer has an associated static text string (to identify
  106. * that layer), a button (for invoking a child dialog box to
  107. * change which layer that the layer is mapped to), and a second
  108. * static text string (to depict which layer that the layer has
  109. * been mapped to). Each of those items are placed into the left
  110. * hand column, middle column, and right hand column (respectively)
  111. * of the Flexgrid sizer, and the color of the second text string
  112. * is set to fuchsia or blue (to respectively indicate whether the
  113. * layer has been swapped to another layer or is not being swapped
  114. * at all). (Experimentation has shown that if a text control is
  115. * used to depict which layer that each layer is mapped to (instead
  116. * of a static text string), then those controls do not behave in
  117. * a fully satisfactory manner in the Linux version. Even when the
  118. * read-only attribute is specified for all of those controls, they
  119. * can still be selected when the arrow keys or Tab key is used
  120. * to step through all of the controls within the dialog box, and
  121. * directives to set the foreground color of the text of each such
  122. * control to blue (to indicate that the text is of a read-only
  123. * nature) are disregarded.)
  124. *
  125. * Specify a FlexGrid sizer with sixteen rows and three columns.
  126. */
  127. FlexColumnBoxSizer = new wxFlexGridSizer( 16, 3, 0, 0 );
  128. // Specify that all of the rows can be expanded.
  129. for( int jj = 0; jj < 16; jj++ )
  130. {
  131. FlexColumnBoxSizer->AddGrowableRow( jj );
  132. }
  133. // Specify that (just) the right-hand column can be expanded.
  134. FlexColumnBoxSizer->AddGrowableCol( 2 );
  135. MainBoxSizer->Add( FlexColumnBoxSizer, 1, wxGROW | wxTOP, 5 );
  136. }
  137. /* Provide a text string to identify this layer (with trailing spaces
  138. * within that string being purged).
  139. */
  140. label = new wxStaticText( this, wxID_STATIC, board->GetLayerName( LAYER_ID( layer ) ),
  141. wxDefaultPosition, wxDefaultSize,
  142. wxALIGN_RIGHT );
  143. FlexColumnBoxSizer->Add( label, 0,
  144. wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL |
  145. wxLEFT | wxBOTTOM,
  146. 5 );
  147. // Provide a button for this layer (which will invoke a child dialog box)
  148. item_ID = ID_BUTTON_0 + layer;
  149. Button = new wxButton( this, item_ID, wxT( "..." ), wxDefaultPosition,
  150. wxSize( w, h ), 0 );
  151. FlexColumnBoxSizer->Add( Button, 0,
  152. wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
  153. wxLEFT | wxBOTTOM, 5 );
  154. /* Provide another text string to specify which layer that this layer
  155. * is mapped to, set the initial text to "No Change" (to indicate that
  156. * this layer is currently unmapped to any other layer), and set the
  157. * foreground color of the text to blue (which also indicates that the
  158. * layer is currently unmapped to any other layer).
  159. */
  160. item_ID = ID_TEXT_0 + layer;
  161. /* When the first of these text strings is being added, determine
  162. * what size is necessary to to be able to display the longest
  163. * string without truncation. Then use that size as the
  164. * minimum size for all text strings. (If the minimum
  165. * size is not this size, strings can be truncated after
  166. * some other layer is selected.)
  167. */
  168. if( layer == 0 )
  169. {
  170. text = new wxStaticText( this, item_ID, board->GetLayerName( LAYER_ID( 0 ) ),
  171. wxDefaultPosition, wxDefaultSize, 0 );
  172. goodSize = text->GetSize();
  173. for( unsigned jj = 1; jj < DIM( layer_list ); ++jj )
  174. {
  175. text->SetLabel( board->GetLayerName( LAYER_ID( jj ) ) );
  176. if( goodSize.x < text->GetSize().x )
  177. goodSize.x = text->GetSize().x;
  178. }
  179. text->SetLabel( _( "No Change" ) );
  180. if( goodSize.x < text->GetSize().x )
  181. goodSize.x = text->GetSize().x;
  182. }
  183. else
  184. {
  185. text = new wxStaticText( this, item_ID, _( "No Change" ),
  186. wxDefaultPosition, wxDefaultSize, 0 );
  187. }
  188. text->SetMinSize( goodSize );
  189. FlexColumnBoxSizer->Add( text, 1,
  190. wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
  191. wxLEFT | wxRIGHT | wxBOTTOM, 5 );
  192. layer_list[layer] = text;
  193. }
  194. /* Provide spacers to occupy otherwise blank cells within the second
  195. * FlexGrid sizer. (Becuse there are three columns, three spacers
  196. * are thus required for each unused row.)
  197. for( int ii = 3 * NB_PCB_LAYERS; ii < 96; ii++ )
  198. {
  199. FlexColumnBoxSizer->Add( 5, h, 0, wxALIGN_CENTER_HORIZONTAL |
  200. wxALIGN_CENTER_VERTICAL | wxLEFT |
  201. wxRIGHT | wxBOTTOM, 5 );
  202. }
  203. */
  204. // Provide a line to separate the controls which have been provided so far
  205. // from the OK and Cancel buttons (which will be provided after this line)
  206. Line = new wxStaticLine( this, -1, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
  207. OuterBoxSizer->Add( Line, 0, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
  208. // Provide a StdDialogButtonSizer to accommodate the OK and Cancel buttons;
  209. // using that type of sizer results in those buttons being automatically
  210. // located in positions appropriate for each (OS) version of KiCad.
  211. StdDialogButtonSizer = new wxStdDialogButtonSizer;
  212. OuterBoxSizer->Add( StdDialogButtonSizer, 0, wxGROW | wxALL, 10 );
  213. Button = new wxButton( this, wxID_OK, _( "&OK" ), wxDefaultPosition, wxDefaultSize, 0 );
  214. Button->SetDefault();
  215. StdDialogButtonSizer->AddButton( Button );
  216. Button = new wxButton( this, wxID_CANCEL, _( "&Cancel" ),
  217. wxDefaultPosition, wxDefaultSize, 0 );
  218. StdDialogButtonSizer->AddButton( Button );
  219. StdDialogButtonSizer->Realize();
  220. // Resize the dialog
  221. if( GetSizer() )
  222. {
  223. GetSizer()->SetSizeHints( this );
  224. }
  225. Center();
  226. }
  227. void SWAP_LAYERS_DIALOG::Sel_Layer( wxCommandEvent& event )
  228. {
  229. int ii;
  230. ii = event.GetId();
  231. if( ii < ID_BUTTON_0 || ii >= ID_BUTTON_0 + LAYER_ID_COUNT )
  232. return;
  233. ii = event.GetId() - ID_BUTTON_0;
  234. LAYER_ID layer = m_callers_nlayers[ii];
  235. LSET notallowed_mask = IsCopperLayer( ii ) ? LSET::AllNonCuMask() : LSET::AllCuMask();
  236. layer = m_Parent->SelectLayer( layer == NO_CHANGE ? LAYER_ID( ii ): layer, notallowed_mask );
  237. if( !IsValidLayer( layer ) )
  238. return;
  239. if( layer != m_callers_nlayers[ii] )
  240. {
  241. m_callers_nlayers[ii] = layer;
  242. if( layer == NO_CHANGE || layer == ii )
  243. {
  244. layer_list[ii]->SetLabel( _( "No Change" ) );
  245. // Change the text color to blue (to highlight
  246. // that this layer is *not* being swapped)
  247. layer_list[ii]->SetForegroundColour( *wxBLUE );
  248. }
  249. else
  250. {
  251. layer_list[ii]->SetLabel( m_Parent->GetBoard()->GetLayerName( layer ) );
  252. // Change the text color to fuchsia (to highlight
  253. // that this layer *is* being swapped)
  254. layer_list[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
  255. }
  256. }
  257. }
  258. void SWAP_LAYERS_DIALOG::OnCancelClick( wxCommandEvent& event )
  259. {
  260. EndModal( -1 );
  261. }
  262. void SWAP_LAYERS_DIALOG::OnOkClick( wxCommandEvent& event )
  263. {
  264. EndModal( 1 );
  265. }
  266. void PCB_EDIT_FRAME::Swap_Layers( wxCommandEvent& event )
  267. {
  268. LAYER_ID new_layer[LAYER_ID_COUNT];
  269. for( unsigned i = 0; i < DIM( new_layer ); ++i )
  270. new_layer[i] = NO_CHANGE;
  271. SWAP_LAYERS_DIALOG dlg( this, new_layer );
  272. if( dlg.ShowModal() != 1 )
  273. return; // (Canceled dialog box returns -1 instead)
  274. // Change traces.
  275. for( TRACK* segm = GetBoard()->m_Track; segm; segm = segm->Next() )
  276. {
  277. OnModify();
  278. if( segm->Type() == PCB_VIA_T )
  279. {
  280. VIA* via = (VIA*) segm;
  281. if( via->GetViaType() == VIA_THROUGH )
  282. continue;
  283. LAYER_ID top_layer, bottom_layer;
  284. via->LayerPair( &top_layer, &bottom_layer );
  285. if( new_layer[bottom_layer] != NO_CHANGE )
  286. bottom_layer = new_layer[bottom_layer];
  287. if( new_layer[top_layer] != NO_CHANGE )
  288. top_layer = new_layer[top_layer];
  289. via->SetLayerPair( top_layer, bottom_layer );
  290. }
  291. else
  292. {
  293. int jj = segm->GetLayer();
  294. if( new_layer[jj] != NO_CHANGE )
  295. segm->SetLayer( new_layer[jj] );
  296. }
  297. }
  298. // Change zones.
  299. for( TRACK* segm = GetBoard()->m_Zone; segm; segm = segm->Next() )
  300. {
  301. OnModify();
  302. int jj = segm->GetLayer();
  303. if( new_layer[jj] != NO_CHANGE )
  304. segm->SetLayer( new_layer[jj] );
  305. }
  306. // Change other segments.
  307. for( EDA_ITEM* item = GetBoard()->m_Drawings; item; item = item->Next() )
  308. {
  309. if( item->Type() == PCB_LINE_T )
  310. {
  311. OnModify();
  312. DRAWSEGMENT* drawsegm = (DRAWSEGMENT*) item;
  313. int jj = drawsegm->GetLayer();
  314. if( new_layer[jj] != NO_CHANGE )
  315. drawsegm->SetLayer( new_layer[jj] );
  316. }
  317. }
  318. m_canvas->Refresh( true );
  319. }