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.

453 lines
14 KiB

  1. /**
  2. * @file sel_layer.cpp
  3. * @brief minor dialogs for one layer selection and a layer pair selection.
  4. */
  5. /*
  6. * This program source code file is part of KiCad, a free EDA CAD application.
  7. *
  8. * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
  9. * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
  10. *
  11. * This program is free software: you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License as published by the
  13. * Free Software Foundation, either version 3 of the License, or (at your
  14. * option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along
  22. * with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. #include <confirm.h>
  25. #include <pcb_base_frame.h>
  26. #include <widgets/layer_box_selector.h>
  27. #include <board.h>
  28. #include <dialogs/dialog_layer_selection_base.h>
  29. #include <router/router_tool.h>
  30. #include <settings/color_settings.h>
  31. // Column position by function:
  32. #define SELECT_COLNUM 0
  33. #define COLOR_COLNUM 1
  34. #define LAYERNAME_COLNUM 2
  35. /*
  36. * Display a layer list using a wxGrid.
  37. */
  38. class PCB_LAYER_SELECTOR: public LAYER_SELECTOR
  39. {
  40. public:
  41. PCB_LAYER_SELECTOR( PCB_BASE_FRAME* aFrame ) :
  42. LAYER_SELECTOR()
  43. {
  44. m_frame = aFrame;
  45. }
  46. protected:
  47. PCB_BASE_FRAME* m_frame;
  48. ///< @return true if the layer id is enabled (i.e. is it should be displayed).
  49. bool isLayerEnabled( LAYER_NUM aLayer ) const override
  50. {
  51. return m_frame->GetBoard()->IsLayerEnabled( PCB_LAYER_ID( aLayer ) );
  52. }
  53. // Return the color index from the layer ID.
  54. COLOR4D getLayerColor( LAYER_NUM aLayer ) const override
  55. {
  56. return m_frame->GetColorSettings()->GetColor( aLayer );
  57. }
  58. // Return the name of the layer ID.
  59. wxString getLayerName( LAYER_NUM aLayer ) const override
  60. {
  61. return m_frame->GetBoard()->GetLayerName( ToLAYER_ID( aLayer ) );
  62. }
  63. };
  64. /**
  65. * Display a PCB layers list in a dialog to select one layer from this list.
  66. */
  67. class PCB_ONE_LAYER_SELECTOR : public PCB_LAYER_SELECTOR, public DIALOG_LAYER_SELECTION_BASE
  68. {
  69. public:
  70. PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD * aBrd, PCB_LAYER_ID aDefaultLayer,
  71. LSET aNotAllowedLayersMask, bool aHideCheckBoxes = false );
  72. ~PCB_ONE_LAYER_SELECTOR();
  73. LAYER_NUM GetLayerSelection() { return m_layerSelected; }
  74. private:
  75. // Event handlers
  76. void OnLeftGridCellClick( wxGridEvent& aEvent ) override;
  77. void OnRightGridCellClick( wxGridEvent& aEvent ) override;
  78. void OnMouseMove( wxUpdateUIEvent& aEvent ) override;
  79. // Will close the dialog on ESC key
  80. void onCharHook( wxKeyEvent& event );
  81. void buildList();
  82. PCB_LAYER_ID m_layerSelected;
  83. LSET m_notAllowedLayersMask;
  84. BOARD* m_brd;
  85. std::vector<PCB_LAYER_ID> m_layersIdLeftColumn;
  86. std::vector<PCB_LAYER_ID> m_layersIdRightColumn;
  87. };
  88. PCB_ONE_LAYER_SELECTOR::PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD* aBrd,
  89. PCB_LAYER_ID aDefaultLayer,
  90. LSET aNotAllowedLayersMask,
  91. bool aHideCheckBoxes ) :
  92. PCB_LAYER_SELECTOR( aParent ),
  93. DIALOG_LAYER_SELECTION_BASE( aParent )
  94. {
  95. m_useCalculatedSize = true;
  96. m_layerSelected = aDefaultLayer;
  97. m_notAllowedLayersMask = aNotAllowedLayersMask;
  98. m_brd = aBrd;
  99. m_leftGridLayers->SetCellHighlightPenWidth( 0 );
  100. m_rightGridLayers->SetCellHighlightPenWidth( 0 );
  101. m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
  102. m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
  103. buildList();
  104. if( aHideCheckBoxes )
  105. {
  106. m_leftGridLayers->HideCol( SELECT_COLNUM );
  107. m_rightGridLayers->HideCol( SELECT_COLNUM );
  108. }
  109. Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PCB_ONE_LAYER_SELECTOR::onCharHook ) );
  110. Layout();
  111. GetSizer()->SetSizeHints( this );
  112. SetFocus();
  113. }
  114. PCB_ONE_LAYER_SELECTOR::~PCB_ONE_LAYER_SELECTOR()
  115. {
  116. Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( PCB_ONE_LAYER_SELECTOR::onCharHook ) );
  117. }
  118. void PCB_ONE_LAYER_SELECTOR::OnMouseMove( wxUpdateUIEvent& aEvent )
  119. {
  120. /// We have to assign this in UpdateUI events because the wxGrid is not properly receiving
  121. /// MouseMove events. It seems to only get them on the edges. So, for now we use this
  122. /// workaround
  123. wxPoint mouse_pos = wxGetMousePosition();
  124. wxPoint left_pos = m_leftGridLayers->ScreenToClient( mouse_pos );
  125. wxPoint right_pos = m_rightGridLayers->ScreenToClient( mouse_pos );
  126. if( m_leftGridLayers->HitTest( left_pos ) == wxHT_WINDOW_INSIDE )
  127. {
  128. int row = m_leftGridLayers->YToRow( left_pos.y );
  129. if( row != wxNOT_FOUND && row < static_cast<int>( m_layersIdLeftColumn.size() ) )
  130. {
  131. m_layerSelected = m_layersIdLeftColumn[ row ];
  132. m_leftGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYERNAME_COLNUM);
  133. return;
  134. }
  135. }
  136. if( m_rightGridLayers->HitTest( right_pos ) == wxHT_WINDOW_INSIDE )
  137. {
  138. int row = m_rightGridLayers->YToRow( right_pos.y );
  139. if( row == wxNOT_FOUND || row >= static_cast<int>( m_layersIdRightColumn.size() ) )
  140. return;
  141. m_layerSelected = m_layersIdRightColumn[ row ];
  142. m_rightGridLayers->SelectBlock( row, LAYERNAME_COLNUM, row, LAYERNAME_COLNUM);
  143. }
  144. }
  145. void PCB_ONE_LAYER_SELECTOR::onCharHook( wxKeyEvent& event )
  146. {
  147. if( event.GetKeyCode() == WXK_ESCAPE )
  148. Close();
  149. }
  150. void PCB_ONE_LAYER_SELECTOR::buildList()
  151. {
  152. wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
  153. int left_row = 0;
  154. int right_row = 0;
  155. wxString layername;
  156. for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq )
  157. {
  158. PCB_LAYER_ID layerid = *ui_seq;
  159. if( m_notAllowedLayersMask[layerid] )
  160. continue;
  161. wxColour fg = getLayerColor( layerid ).ToColour();
  162. wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
  163. wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
  164. wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
  165. layername = wxT( " " ) + getLayerName( layerid );
  166. if( IsCopperLayer( layerid ) )
  167. {
  168. if( left_row )
  169. m_leftGridLayers->AppendRows( 1 );
  170. m_leftGridLayers->SetCellBackgroundColour ( left_row, COLOR_COLNUM, color );
  171. m_leftGridLayers->SetCellValue( left_row, LAYERNAME_COLNUM, layername );
  172. if( m_layerSelected == layerid )
  173. m_leftGridLayers->SetCellValue( left_row, SELECT_COLNUM, "1" );
  174. m_layersIdLeftColumn.push_back( layerid );
  175. left_row++;
  176. }
  177. else
  178. {
  179. if( right_row )
  180. m_rightGridLayers->AppendRows( 1 );
  181. m_rightGridLayers->SetCellBackgroundColour( right_row, COLOR_COLNUM, color );
  182. m_rightGridLayers->SetCellValue( right_row, LAYERNAME_COLNUM, layername );
  183. if( m_layerSelected == layerid )
  184. m_rightGridLayers->SetCellValue( right_row, SELECT_COLNUM, "1" );
  185. m_layersIdRightColumn.push_back( layerid );
  186. right_row++;
  187. }
  188. }
  189. // Show only populated lists:
  190. if( left_row <= 0 )
  191. m_leftGridLayers->Show( false );
  192. if( right_row <= 0 )
  193. m_rightGridLayers->Show( false );
  194. // Now fix min grid column size (it also sets a minimal size)
  195. m_leftGridLayers->AutoSizeColumns();
  196. m_rightGridLayers->AutoSizeColumns();
  197. }
  198. void PCB_ONE_LAYER_SELECTOR::OnLeftGridCellClick( wxGridEvent& event )
  199. {
  200. m_layerSelected = m_layersIdLeftColumn[ event.GetRow() ];
  201. if( IsQuasiModal() )
  202. EndQuasiModal( 1 );
  203. else
  204. EndDialog( 1 );
  205. }
  206. void PCB_ONE_LAYER_SELECTOR::OnRightGridCellClick( wxGridEvent& event )
  207. {
  208. m_layerSelected = m_layersIdRightColumn[ event.GetRow() ];
  209. if( IsQuasiModal() )
  210. EndQuasiModal( 2 );
  211. else
  212. EndDialog( 2 );
  213. }
  214. PCB_LAYER_ID PCB_BASE_FRAME::SelectOneLayer( PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask,
  215. wxPoint aDlgPosition )
  216. {
  217. PCB_ONE_LAYER_SELECTOR dlg( this, GetBoard(), aDefaultLayer, aNotAllowedLayersMask, true );
  218. if( aDlgPosition != wxDefaultPosition )
  219. {
  220. wxSize dlgSize = dlg.GetSize();
  221. aDlgPosition.x -= dlgSize.x/2;
  222. aDlgPosition.y -= dlgSize.y/2;
  223. dlg.SetPosition( aDlgPosition );
  224. }
  225. if( dlg.ShowModal() != wxID_CANCEL )
  226. return ToLAYER_ID( dlg.GetLayerSelection() );
  227. else
  228. return UNDEFINED_LAYER;
  229. }
  230. /**
  231. * Display a pair PCB copper layers list in a dialog to select a layer pair from these lists.
  232. */
  233. class SELECT_COPPER_LAYERS_PAIR_DIALOG: public PCB_LAYER_SELECTOR,
  234. public DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE
  235. {
  236. public:
  237. SELECT_COPPER_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* aParent, BOARD* aPcb,
  238. PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer );
  239. void GetLayerPair( PCB_LAYER_ID& aFrontLayer, PCB_LAYER_ID& aBackLayer )
  240. {
  241. aFrontLayer = m_frontLayer;
  242. aBackLayer = m_backLayer;
  243. }
  244. private:
  245. void OnLeftGridCellClick( wxGridEvent& event ) override;
  246. void OnRightGridCellClick( wxGridEvent& event ) override;
  247. void buildList();
  248. BOARD* m_brd;
  249. PCB_LAYER_ID m_frontLayer;
  250. PCB_LAYER_ID m_backLayer;
  251. int m_leftRowSelected;
  252. int m_rightRowSelected;
  253. std::vector<PCB_LAYER_ID> m_layersId;
  254. };
  255. int ROUTER_TOOL::SelectCopperLayerPair( const TOOL_EVENT& aEvent )
  256. {
  257. PCB_SCREEN* screen = frame()->GetScreen();
  258. SELECT_COPPER_LAYERS_PAIR_DIALOG dlg( frame(), frame()->GetBoard(), screen->m_Route_Layer_TOP,
  259. screen->m_Route_Layer_BOTTOM );
  260. if( dlg.ShowModal() == wxID_OK )
  261. {
  262. dlg.GetLayerPair( screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM );
  263. // select the same layer for both layers is allowed (normal in some boards)
  264. // but could be a mistake. So display an info message
  265. if( screen->m_Route_Layer_TOP == screen->m_Route_Layer_BOTTOM )
  266. DisplayInfoMessage( frame(), _( "Warning: top and bottom layers are same." ) );
  267. }
  268. return 0;
  269. }
  270. SELECT_COPPER_LAYERS_PAIR_DIALOG::SELECT_COPPER_LAYERS_PAIR_DIALOG(
  271. PCB_BASE_FRAME* aParent, BOARD * aPcb, PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer) :
  272. PCB_LAYER_SELECTOR( aParent ),
  273. DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( aParent )
  274. {
  275. m_frontLayer = aFrontLayer;
  276. m_backLayer = aBackLayer;
  277. m_leftRowSelected = 0;
  278. m_rightRowSelected = 0;
  279. m_brd = aPcb;
  280. m_leftGridLayers->SetCellHighlightPenWidth( 0 );
  281. m_rightGridLayers->SetCellHighlightPenWidth( 0 );
  282. m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
  283. m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
  284. buildList();
  285. SetFocus();
  286. GetSizer()->SetSizeHints( this );
  287. Center();
  288. }
  289. void SELECT_COPPER_LAYERS_PAIR_DIALOG::buildList()
  290. {
  291. wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
  292. int row = 0;
  293. wxString layername;
  294. for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq )
  295. {
  296. PCB_LAYER_ID layerid = *ui_seq;
  297. if( !IsCopperLayer( layerid ) )
  298. continue;
  299. wxColour fg = getLayerColor( layerid ).ToColour();
  300. wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
  301. wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
  302. wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
  303. layername = wxT( " " ) + getLayerName( layerid );
  304. if( row )
  305. m_leftGridLayers->AppendRows( 1 );
  306. m_leftGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
  307. m_leftGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
  308. m_layersId.push_back( layerid );
  309. if( m_frontLayer == layerid )
  310. {
  311. m_leftGridLayers->SetCellValue( row, SELECT_COLNUM, "1" );
  312. m_leftGridLayers->SetGridCursor( row, COLOR_COLNUM );
  313. m_leftRowSelected = row;
  314. }
  315. if( row )
  316. m_rightGridLayers->AppendRows( 1 );
  317. m_rightGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
  318. m_rightGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
  319. if( m_backLayer == layerid )
  320. {
  321. m_rightGridLayers->SetCellValue( row, SELECT_COLNUM, "1" );
  322. m_rightRowSelected = row;
  323. }
  324. row++;
  325. }
  326. // Now fix min grid layer name column size (it also sets a minimal size)
  327. m_leftGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
  328. m_rightGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
  329. }
  330. void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnLeftGridCellClick( wxGridEvent& event )
  331. {
  332. int row = event.GetRow();
  333. PCB_LAYER_ID layer = m_layersId[row];
  334. if( m_frontLayer == layer )
  335. return;
  336. m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, wxEmptyString );
  337. m_frontLayer = layer;
  338. m_leftRowSelected = row;
  339. m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, "1" );
  340. }
  341. void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnRightGridCellClick( wxGridEvent& event )
  342. {
  343. int row = event.GetRow();
  344. PCB_LAYER_ID layer = m_layersId[row];
  345. if( m_backLayer == layer )
  346. return;
  347. m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, wxEmptyString );
  348. m_backLayer = layer;
  349. m_rightRowSelected = row;
  350. m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, "1" );
  351. }