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.

348 lines
11 KiB

  1. /**
  2. * @file sel_layer.cpp
  3. * @brief Set up the basic primitives for Layer control.
  4. */
  5. #include <fctsys.h>
  6. #include <common.h>
  7. #include <class_drawpanel.h>
  8. #include <confirm.h>
  9. #include <wxBasePcbFrame.h>
  10. #include <pcbcommon.h>
  11. #include <class_board.h>
  12. enum layer_sel_id {
  13. ID_LAYER_SELECT_TOP = 1800,
  14. ID_LAYER_SELECT_BOTTOM,
  15. ID_LAYER_SELECT
  16. };
  17. class SELECT_LAYER_DIALOG : public wxDialog
  18. {
  19. private:
  20. PCB_BASE_FRAME* m_Parent;
  21. wxRadioBox* m_LayerList;
  22. LAYER_NUM m_LayerId[int(NB_PCB_LAYERS) + 1]; // One extra element for "(Deselect)" radiobutton
  23. public:
  24. // Constructor and destructor
  25. SELECT_LAYER_DIALOG( PCB_BASE_FRAME* parent, LAYER_NUM default_layer,
  26. LAYER_NUM min_layer, LAYER_NUM max_layer, bool null_layer );
  27. ~SELECT_LAYER_DIALOG() { };
  28. private:
  29. void OnLayerSelected( wxCommandEvent& event );
  30. void OnCancelClick( wxCommandEvent& event );
  31. DECLARE_EVENT_TABLE()
  32. };
  33. BEGIN_EVENT_TABLE( SELECT_LAYER_DIALOG, wxDialog )
  34. EVT_BUTTON( wxID_OK, SELECT_LAYER_DIALOG::OnLayerSelected )
  35. EVT_BUTTON( wxID_CANCEL, SELECT_LAYER_DIALOG::OnCancelClick )
  36. EVT_RADIOBOX( ID_LAYER_SELECT, SELECT_LAYER_DIALOG::OnLayerSelected )
  37. END_EVENT_TABLE()
  38. /** Install the dialog box for layer selection
  39. * @param default_layer = Preselection (NB_PCB_LAYERS for "(Deselect)" layer)
  40. * @param min_layer = min layer value (-1 if no min value)
  41. * @param max_layer = max layer value (-1 if no max value)
  42. * @param null_layer = display a "(Deselect)" radiobutton (when set to true)
  43. * @return new layer value (NB_PCB_LAYERS when "(Deselect)" radiobutton selected),
  44. * or -1 if canceled
  45. *
  46. * Providing the option to also display a "(Deselect)" radiobutton makes the
  47. * "Swap Layers" command (and GerbView's "Export to Pcbnew" command) more "user
  48. * friendly", by permitting any layer to be "deselected" immediately after its
  49. * corresponding radiobutton has been clicked on. (It would otherwise be
  50. * necessary to first cancel the "Select Layer:" dialog box (invoked after a
  51. * different radiobutton is clicked on) prior to then clicking on the
  52. * "Deselect"
  53. * button provided within the "Swap Layers:" or "Layer selection:" dialog box).
  54. */
  55. LAYER_NUM PCB_BASE_FRAME::SelectLayer( LAYER_NUM default_layer,
  56. LAYER_NUM min_layer,
  57. LAYER_NUM max_layer,
  58. bool null_layer )
  59. {
  60. SELECT_LAYER_DIALOG* frame = new SELECT_LAYER_DIALOG( this,
  61. default_layer,
  62. min_layer,
  63. max_layer,
  64. null_layer );
  65. LAYER_NUM layer = frame->ShowModal();
  66. frame->Destroy();
  67. return layer;
  68. }
  69. /*
  70. * The "OK" and "Cancel" buttons are positioned (in a horizontal line)
  71. * beneath the "Layer" radiobox, unless that contains only one column of
  72. * radiobuttons, in which case they are positioned (in a vertical line)
  73. * to the right of that radiobox.
  74. */
  75. SELECT_LAYER_DIALOG::SELECT_LAYER_DIALOG( PCB_BASE_FRAME* parent,
  76. LAYER_NUM default_layer, LAYER_NUM min_layer,
  77. LAYER_NUM max_layer, bool null_layer ) :
  78. wxDialog( parent, -1, _( "Select Layer:" ), wxPoint( -1, -1 ),
  79. wxSize( 470, 250 ),
  80. DIALOG_STYLE )
  81. {
  82. BOARD* board = parent->GetBoard();
  83. wxButton* Button;
  84. LAYER_NUM ii;
  85. wxString LayerList[NB_PCB_LAYERS + 1]; // One extra element for "(Deselect)"
  86. // radiobutton
  87. int LayerCount, LayerSelect = -1;
  88. m_Parent = parent;
  89. // Build the layer list
  90. LayerCount = 0;
  91. LAYER_MSK Masque_Layer = g_TabAllCopperLayerMask[board->GetCopperLayerCount() - 1];
  92. Masque_Layer |= ALL_NO_CU_LAYERS;
  93. for( ii = FIRST_LAYER; ii < NB_PCB_LAYERS; ++ii )
  94. {
  95. m_LayerId[ii] = FIRST_LAYER;
  96. if( GetLayerMask( ii ) & Masque_Layer )
  97. {
  98. if( min_layer > ii )
  99. continue;
  100. if( ( max_layer >= 0 ) && ( max_layer < ii ) )
  101. break;
  102. LayerList[LayerCount] = board->GetLayerName( ii );
  103. if( ii == default_layer )
  104. LayerSelect = LayerCount;
  105. m_LayerId[LayerCount] = ii;
  106. LayerCount++;
  107. }
  108. }
  109. // When appropriate, also provide a "(Deselect)" radiobutton
  110. if( null_layer )
  111. {
  112. LayerList[LayerCount] = _( "(Deselect)" );
  113. if( NB_PCB_LAYERS == default_layer )
  114. LayerSelect = LayerCount;
  115. m_LayerId[LayerCount] = NB_PCB_LAYERS;
  116. LayerCount++;
  117. }
  118. m_LayerList = new wxRadioBox( this, ID_LAYER_SELECT, _( "Layer" ),
  119. wxPoint( -1, -1 ), wxSize( -1, -1 ),
  120. LayerCount, LayerList,
  121. (LayerCount < 8) ? LayerCount : 8,
  122. wxRA_SPECIFY_ROWS );
  123. if( LayerSelect >= 0 )
  124. m_LayerList->SetSelection( LayerSelect );
  125. wxBoxSizer* FrameBoxSizer = new wxBoxSizer( wxHORIZONTAL );
  126. SetSizer( FrameBoxSizer );
  127. FrameBoxSizer->Add( m_LayerList, 0, wxALIGN_TOP | wxALL, 5 );
  128. wxBoxSizer* ButtonBoxSizer = new wxBoxSizer( wxVERTICAL );
  129. FrameBoxSizer->Add( ButtonBoxSizer, 0, wxALIGN_BOTTOM | wxALL, 0 );
  130. Button = new wxButton( this, wxID_OK, _( "OK" ) );
  131. Button->SetDefault();
  132. ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
  133. Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
  134. ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
  135. SetFocus();
  136. GetSizer()->SetSizeHints( this );
  137. Center();
  138. }
  139. void SELECT_LAYER_DIALOG::OnLayerSelected( wxCommandEvent& event )
  140. {
  141. int ii = m_LayerId[m_LayerList->GetSelection()];
  142. EndModal( ii );
  143. }
  144. void SELECT_LAYER_DIALOG::OnCancelClick( wxCommandEvent& event )
  145. {
  146. EndModal( -1 );
  147. }
  148. /*********************************************/
  149. /* Dialog for the selecting pairs of layers. */
  150. /*********************************************/
  151. class SELECT_LAYERS_PAIR_DIALOG : public wxDialog
  152. {
  153. private:
  154. PCB_BASE_FRAME* m_Parent;
  155. wxRadioBox* m_LayerListTOP;
  156. wxRadioBox* m_LayerListBOTTOM;
  157. LAYER_NUM m_LayerId[NB_COPPER_LAYERS];
  158. public: SELECT_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* parent );
  159. ~SELECT_LAYERS_PAIR_DIALOG() { };
  160. private:
  161. void OnOkClick( wxCommandEvent& event );
  162. void OnCancelClick( wxCommandEvent& event );
  163. DECLARE_EVENT_TABLE()
  164. };
  165. BEGIN_EVENT_TABLE( SELECT_LAYERS_PAIR_DIALOG, wxDialog )
  166. EVT_BUTTON( wxID_OK, SELECT_LAYERS_PAIR_DIALOG::OnOkClick )
  167. EVT_BUTTON( wxID_CANCEL, SELECT_LAYERS_PAIR_DIALOG::OnCancelClick )
  168. END_EVENT_TABLE()
  169. /* Display a list of two copper layers for selection of a pair of layers
  170. * for auto-routing, vias ...
  171. */
  172. void PCB_BASE_FRAME::SelectLayerPair()
  173. {
  174. // Check whether more than one copper layer has been enabled for the
  175. // current PCB file, as Layer Pairs can only meaningfully be defined
  176. // within PCB files which contain at least two copper layers.
  177. if( GetBoard()->GetCopperLayerCount() < 2 )
  178. {
  179. wxString InfoMsg;
  180. InfoMsg = _( "Less than two copper layers are being used." );
  181. InfoMsg << wxT( "\n" ) << _( "Hence layer pairs cannot be specified." );
  182. DisplayInfoMessage( this, InfoMsg );
  183. return;
  184. }
  185. SELECT_LAYERS_PAIR_DIALOG* frame = new SELECT_LAYERS_PAIR_DIALOG( this );
  186. int result = frame->ShowModal();
  187. frame->Destroy();
  188. m_canvas->MoveCursorToCrossHair();
  189. // if user changed colors and we are in high contrast mode, then redraw
  190. // because the PAD_SMD pads may change color.
  191. if( result >= 0 && DisplayOpt.ContrastModeDisplay )
  192. {
  193. RefreshCanvas();
  194. }
  195. }
  196. SELECT_LAYERS_PAIR_DIALOG::SELECT_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* parent ) :
  197. wxDialog( parent, -1, _( "Select Layer Pair:" ), wxPoint( -1, -1 ),
  198. wxSize( 470, 250 ), DIALOG_STYLE )
  199. {
  200. BOARD* board = parent->GetBoard();
  201. wxButton* Button;
  202. wxString LayerList[NB_COPPER_LAYERS];
  203. LAYER_NUM LayerTopSelect = FIRST_LAYER, LayerBottomSelect = FIRST_LAYER;
  204. m_Parent = parent;
  205. PCB_SCREEN* screen = (PCB_SCREEN*) m_Parent->GetScreen();
  206. LAYER_MSK Masque_Layer = g_TabAllCopperLayerMask[board->GetCopperLayerCount() - 1];
  207. Masque_Layer |= ALL_NO_CU_LAYERS;
  208. LAYER_NUM LayerCount = FIRST_LAYER;
  209. for( LAYER_NUM ii = FIRST_COPPER_LAYER; ii < NB_COPPER_LAYERS; ++ii )
  210. {
  211. m_LayerId[ii] = FIRST_LAYER;
  212. if( (GetLayerMask( ii ) & Masque_Layer) )
  213. {
  214. LayerList[LayerCount] = board->GetLayerName( ii );
  215. if( ii == screen->m_Route_Layer_TOP )
  216. LayerTopSelect = LayerCount;
  217. if( ii == screen->m_Route_Layer_BOTTOM )
  218. LayerBottomSelect = LayerCount;
  219. m_LayerId[LayerCount] = ii;
  220. ++LayerCount;
  221. }
  222. }
  223. m_LayerListTOP = new wxRadioBox( this, ID_LAYER_SELECT_TOP,
  224. _( "Top Layer" ),
  225. wxPoint( -1, -1 ), wxSize( -1, -1 ),
  226. LayerCount, LayerList,
  227. (LayerCount < 8) ? LayerCount : 8,
  228. wxRA_SPECIFY_ROWS );
  229. m_LayerListTOP->SetSelection( LayerTopSelect );
  230. m_LayerListBOTTOM = new wxRadioBox( this, ID_LAYER_SELECT_BOTTOM,
  231. _( "Bottom Layer" ),
  232. wxPoint( -1, -1 ), wxSize( -1, -1 ),
  233. LayerCount, LayerList,
  234. (LayerCount < 8) ? LayerCount : 8,
  235. wxRA_SPECIFY_ROWS );
  236. m_LayerListBOTTOM->SetSelection( LayerBottomSelect );
  237. wxBoxSizer* FrameBoxSizer = new wxBoxSizer( wxVERTICAL );
  238. SetSizer( FrameBoxSizer );
  239. wxBoxSizer* RadioBoxSizer = new wxBoxSizer( wxHORIZONTAL );
  240. FrameBoxSizer->Add( RadioBoxSizer, 0, wxALIGN_LEFT | wxALL, 0 );
  241. wxBoxSizer* ButtonBoxSizer = new wxBoxSizer( wxHORIZONTAL );
  242. FrameBoxSizer->Add( ButtonBoxSizer, 0, wxALIGN_RIGHT | wxALL, 0 );
  243. RadioBoxSizer->Add( m_LayerListTOP, 0, wxALIGN_TOP | wxALL, 5 );
  244. RadioBoxSizer->Add( m_LayerListBOTTOM, 0, wxALIGN_TOP | wxALL, 5 );
  245. Button = new wxButton( this, wxID_OK, _( "OK" ) );
  246. Button->SetDefault();
  247. ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
  248. Button = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
  249. ButtonBoxSizer->Add( Button, 0, wxGROW | wxALL, 5 );
  250. SetFocus();
  251. GetSizer()->SetSizeHints( this );
  252. Center();
  253. }
  254. void SELECT_LAYERS_PAIR_DIALOG::OnOkClick( wxCommandEvent& event )
  255. {
  256. // select the same layer for top and bottom is allowed (normal in some
  257. // boards)
  258. // but could be a mistake. So display an info message
  259. if( m_LayerId[m_LayerListTOP->GetSelection()] == m_LayerId[m_LayerListBOTTOM->GetSelection()] )
  260. DisplayInfoMessage( this,
  261. _( "Warning: The Top Layer and Bottom Layer are same." ) );
  262. PCB_SCREEN* screen = (PCB_SCREEN*) m_Parent->GetScreen();
  263. screen->m_Route_Layer_TOP = m_LayerId[m_LayerListTOP->GetSelection()];
  264. screen->m_Route_Layer_BOTTOM = m_LayerId[m_LayerListBOTTOM->GetSelection()];
  265. EndModal( 0 );
  266. }
  267. void SELECT_LAYERS_PAIR_DIALOG::OnCancelClick( wxCommandEvent& event )
  268. {
  269. EndModal( -1 );
  270. }