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.

464 lines
14 KiB

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