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.

386 lines
12 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-2019 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. /* classes to display a layer list using a wxGrid.
  36. */
  37. class PCB_LAYER_SELECTOR: public LAYER_SELECTOR
  38. {
  39. public:
  40. PCB_LAYER_SELECTOR( PCB_BASE_FRAME* aFrame ) :
  41. LAYER_SELECTOR()
  42. {
  43. m_frame = aFrame;
  44. }
  45. protected:
  46. PCB_BASE_FRAME* m_frame;
  47. // Returns true if the layer id is enabled (i.e. is it should be displayed)
  48. bool isLayerEnabled( LAYER_NUM aLayer ) const override
  49. {
  50. return m_frame->GetBoard()->IsLayerEnabled( PCB_LAYER_ID( aLayer ) );
  51. }
  52. // Returns a color index from the layer id
  53. // Virtual function
  54. COLOR4D getLayerColor( LAYER_NUM aLayer ) const override
  55. {
  56. return m_frame->GetColorSettings()->GetColor( aLayer );
  57. }
  58. // Returns 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. * This class display a pcb layers list in a dialog,
  66. * to select one layer from this list
  67. */
  68. class PCB_ONE_LAYER_SELECTOR : public PCB_LAYER_SELECTOR,
  69. public DIALOG_LAYER_SELECTION_BASE
  70. {
  71. PCB_LAYER_ID m_layerSelected;
  72. LSET m_notAllowedLayersMask;
  73. BOARD* m_brd;
  74. std::vector<PCB_LAYER_ID> m_layersIdLeftColumn;
  75. std::vector<PCB_LAYER_ID> m_layersIdRightColumn;
  76. public:
  77. PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD * aBrd, PCB_LAYER_ID aDefaultLayer,
  78. LSET aNotAllowedLayersMask );
  79. LAYER_NUM GetLayerSelection() { return m_layerSelected; }
  80. private:
  81. // Event handlers
  82. void OnLeftGridCellClick( wxGridEvent& event ) override;
  83. void OnRightGridCellClick( wxGridEvent& event ) override;
  84. void buildList();
  85. };
  86. PCB_ONE_LAYER_SELECTOR::PCB_ONE_LAYER_SELECTOR( PCB_BASE_FRAME* aParent, BOARD* aBrd,
  87. PCB_LAYER_ID aDefaultLayer,
  88. LSET aNotAllowedLayersMask ) :
  89. PCB_LAYER_SELECTOR( aParent ),
  90. DIALOG_LAYER_SELECTION_BASE( aParent )
  91. {
  92. m_layerSelected = aDefaultLayer;
  93. m_notAllowedLayersMask = aNotAllowedLayersMask;
  94. m_brd = aBrd;
  95. m_leftGridLayers->SetCellHighlightPenWidth( 0 );
  96. m_rightGridLayers->SetCellHighlightPenWidth( 0 );
  97. m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
  98. m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
  99. buildList();
  100. Layout();
  101. GetSizer()->SetSizeHints( this );
  102. SetFocus();
  103. }
  104. void PCB_ONE_LAYER_SELECTOR::buildList()
  105. {
  106. wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
  107. int left_row = 0;
  108. int right_row = 0;
  109. wxString layername;
  110. for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq )
  111. {
  112. PCB_LAYER_ID layerid = *ui_seq;
  113. if( m_notAllowedLayersMask[layerid] )
  114. continue;
  115. wxColour fg = getLayerColor( layerid ).ToColour();
  116. wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
  117. wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
  118. wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
  119. layername = wxT( " " ) + getLayerName( layerid );
  120. if( IsCopperLayer( layerid ) )
  121. {
  122. if( left_row )
  123. m_leftGridLayers->AppendRows( 1 );
  124. m_leftGridLayers->SetCellBackgroundColour ( left_row, COLOR_COLNUM, color );
  125. m_leftGridLayers->SetCellValue( left_row, LAYERNAME_COLNUM, layername );
  126. if( m_layerSelected == layerid )
  127. m_leftGridLayers->SetCellValue( left_row, SELECT_COLNUM, "1" );
  128. m_layersIdLeftColumn.push_back( layerid );
  129. left_row++;
  130. }
  131. else
  132. {
  133. if( right_row )
  134. m_rightGridLayers->AppendRows( 1 );
  135. m_rightGridLayers->SetCellBackgroundColour( right_row, COLOR_COLNUM, color );
  136. m_rightGridLayers->SetCellValue( right_row, LAYERNAME_COLNUM, layername );
  137. if( m_layerSelected == layerid )
  138. m_rightGridLayers->SetCellValue( right_row, SELECT_COLNUM, "1" );
  139. m_layersIdRightColumn.push_back( layerid );
  140. right_row++;
  141. }
  142. }
  143. // Show only populated lists:
  144. if( left_row <= 0 )
  145. m_leftGridLayers->Show( false );
  146. if( right_row <= 0 )
  147. m_rightGridLayers->Show( false );
  148. // Now fix min grid layer name column size (it also sets a minimal size)
  149. m_leftGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
  150. m_rightGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
  151. }
  152. void PCB_ONE_LAYER_SELECTOR::OnLeftGridCellClick( wxGridEvent& event )
  153. {
  154. m_layerSelected = m_layersIdLeftColumn[ event.GetRow() ];
  155. EndModal( 1 );
  156. }
  157. void PCB_ONE_LAYER_SELECTOR::OnRightGridCellClick( wxGridEvent& event )
  158. {
  159. m_layerSelected = m_layersIdRightColumn[ event.GetRow() ];
  160. EndModal( 2 );
  161. }
  162. PCB_LAYER_ID PCB_BASE_FRAME::SelectLayer( PCB_LAYER_ID aDefaultLayer, LSET aNotAllowedLayersMask,
  163. wxPoint aDlgPosition )
  164. {
  165. PCB_ONE_LAYER_SELECTOR dlg( this, GetBoard(), aDefaultLayer, aNotAllowedLayersMask );
  166. if( aDlgPosition != wxDefaultPosition )
  167. {
  168. wxSize dlgSize = dlg.GetSize();
  169. aDlgPosition.x -= dlgSize.x/2;
  170. aDlgPosition.y -= dlgSize.y/2;
  171. dlg.SetPosition( aDlgPosition );
  172. }
  173. dlg.ShowModal();
  174. PCB_LAYER_ID layer = ToLAYER_ID( dlg.GetLayerSelection() );
  175. return layer;
  176. }
  177. /**
  178. * SELECT_COPPER_LAYERS_PAIR_DIALOG
  179. * displays a double pcb copper layers list in a dialog,
  180. * to select a layer pair from these lists
  181. */
  182. class SELECT_COPPER_LAYERS_PAIR_DIALOG: public PCB_LAYER_SELECTOR,
  183. public DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE
  184. {
  185. private:
  186. BOARD* m_brd;
  187. PCB_LAYER_ID m_frontLayer;
  188. PCB_LAYER_ID m_backLayer;
  189. int m_leftRowSelected;
  190. int m_rightRowSelected;
  191. std::vector<PCB_LAYER_ID> m_layersId;
  192. public:
  193. SELECT_COPPER_LAYERS_PAIR_DIALOG( PCB_BASE_FRAME* aParent, BOARD* aPcb,
  194. PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer );
  195. void GetLayerPair( PCB_LAYER_ID& aFrontLayer, PCB_LAYER_ID& aBackLayer )
  196. {
  197. aFrontLayer = m_frontLayer;
  198. aBackLayer = m_backLayer;
  199. }
  200. private:
  201. void OnLeftGridCellClick( wxGridEvent& event ) override;
  202. void OnRightGridCellClick( wxGridEvent& event ) override;
  203. void buildList();
  204. };
  205. int ROUTER_TOOL::SelectCopperLayerPair( const TOOL_EVENT& aEvent )
  206. {
  207. PCB_SCREEN* screen = frame()->GetScreen();
  208. SELECT_COPPER_LAYERS_PAIR_DIALOG dlg( frame(), frame()->GetBoard(), screen->m_Route_Layer_TOP,
  209. screen->m_Route_Layer_BOTTOM );
  210. if( dlg.ShowModal() == wxID_OK )
  211. {
  212. dlg.GetLayerPair( screen->m_Route_Layer_TOP, screen->m_Route_Layer_BOTTOM );
  213. // select the same layer for both layers is allowed (normal in some boards)
  214. // but could be a mistake. So display an info message
  215. if( screen->m_Route_Layer_TOP == screen->m_Route_Layer_BOTTOM )
  216. DisplayInfoMessage( frame(), _( "Warning: top and bottom layers are same." ) );
  217. }
  218. return 0;
  219. }
  220. SELECT_COPPER_LAYERS_PAIR_DIALOG::SELECT_COPPER_LAYERS_PAIR_DIALOG(
  221. PCB_BASE_FRAME* aParent, BOARD * aPcb, PCB_LAYER_ID aFrontLayer, PCB_LAYER_ID aBackLayer) :
  222. PCB_LAYER_SELECTOR( aParent ),
  223. DIALOG_COPPER_LAYER_PAIR_SELECTION_BASE( aParent )
  224. {
  225. m_frontLayer = aFrontLayer;
  226. m_backLayer = aBackLayer;
  227. m_leftRowSelected = 0;
  228. m_rightRowSelected = 0;
  229. m_brd = aPcb;
  230. m_leftGridLayers->SetCellHighlightPenWidth( 0 );
  231. m_rightGridLayers->SetCellHighlightPenWidth( 0 );
  232. m_leftGridLayers->SetColFormatBool( SELECT_COLNUM );
  233. m_rightGridLayers->SetColFormatBool( SELECT_COLNUM );
  234. buildList();
  235. SetFocus();
  236. GetSizer()->SetSizeHints( this );
  237. Center();
  238. }
  239. void SELECT_COPPER_LAYERS_PAIR_DIALOG::buildList()
  240. {
  241. wxColour bg = getLayerColor( LAYER_PCB_BACKGROUND ).ToColour();
  242. int row = 0;
  243. wxString layername;
  244. for( LSEQ ui_seq = m_brd->GetEnabledLayers().UIOrder(); ui_seq; ++ui_seq )
  245. {
  246. PCB_LAYER_ID layerid = *ui_seq;
  247. if( !IsCopperLayer( layerid ) )
  248. continue;
  249. wxColour fg = getLayerColor( layerid ).ToColour();
  250. wxColour color( wxColour::AlphaBlend( fg.Red(), bg.Red(), fg.Alpha() / 255.0 ),
  251. wxColour::AlphaBlend( fg.Green(), bg.Green(), fg.Alpha() / 255.0 ),
  252. wxColour::AlphaBlend( fg.Blue(), bg.Blue(), fg.Alpha() / 255.0 ) );
  253. layername = wxT( " " ) + getLayerName( layerid );
  254. if( row )
  255. m_leftGridLayers->AppendRows( 1 );
  256. m_leftGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
  257. m_leftGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
  258. m_layersId.push_back( layerid );
  259. if( m_frontLayer == layerid )
  260. {
  261. m_leftGridLayers->SetCellValue( row, SELECT_COLNUM, "1" );
  262. m_leftGridLayers->SetGridCursor( row, COLOR_COLNUM );
  263. m_leftRowSelected = row;
  264. }
  265. if( row )
  266. m_rightGridLayers->AppendRows( 1 );
  267. m_rightGridLayers->SetCellBackgroundColour( row, COLOR_COLNUM, color );
  268. m_rightGridLayers->SetCellValue( row, LAYERNAME_COLNUM, layername );
  269. if( m_backLayer == layerid )
  270. {
  271. m_rightGridLayers->SetCellValue( row, SELECT_COLNUM, "1" );
  272. m_rightRowSelected = row;
  273. }
  274. row++;
  275. }
  276. // Now fix min grid layer name column size (it also sets a minimal size)
  277. m_leftGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
  278. m_rightGridLayers->AutoSizeColumn( LAYERNAME_COLNUM );
  279. }
  280. void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnLeftGridCellClick( wxGridEvent& event )
  281. {
  282. int row = event.GetRow();
  283. PCB_LAYER_ID layer = m_layersId[row];
  284. if( m_frontLayer == layer )
  285. return;
  286. m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, wxEmptyString );
  287. m_frontLayer = layer;
  288. m_leftRowSelected = row;
  289. m_leftGridLayers->SetCellValue( m_leftRowSelected, SELECT_COLNUM, "1" );
  290. }
  291. void SELECT_COPPER_LAYERS_PAIR_DIALOG::OnRightGridCellClick( wxGridEvent& event )
  292. {
  293. int row = event.GetRow();
  294. PCB_LAYER_ID layer = m_layersId[row];
  295. if( m_backLayer == layer )
  296. return;
  297. m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, wxEmptyString );
  298. m_backLayer = layer;
  299. m_rightRowSelected = row;
  300. m_rightGridLayers->SetCellValue( m_rightRowSelected, SELECT_COLNUM, "1" );
  301. }