KiCad PCB EDA Suite
layer_widget.cpp
Go to the documentation of this file.
1 
2 /*
3  * This program source code file is part of KiCad, a free EDA CAD application.
4  *
5  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 
27 
28 /* This source module implements the layer visibility and selection widget
29  @todo make bitmap size dependent on the point size.
30 */
31 
32 
33 //#define STAND_ALONE 1 // define to enable test program for LAYER_WIDGET
34 
35 
36 #include <layer_widget.h>
37 
38 #include <macros.h>
39 #include <common.h>
40 
41 #include <widgets/indicator_icon.h>
42 
43 #include <algorithm>
44 
45 #include <menus_helpers.h>
46 
47 
48 const wxEventType LAYER_WIDGET::EVT_LAYER_COLOR_CHANGE = wxNewEventType();
49 
50 /*
51  * Icon providers for the row icons
52  */
53 static ROW_ICON_PROVIDER defaultRowIcons( false );
55 
60 static void shrinkFont( wxWindow* aControl, int aPointSize )
61 {
62  wxFont font = aControl->GetFont();
63  font.SetPointSize( aPointSize );
64  aControl->SetFont( font ); // need this?
65 }
66 
67 
68 int LAYER_WIDGET::encodeId( int aColumn, int aId )
69 {
70  int id = aId * LYR_COLUMN_COUNT + aColumn;
71  return id;
72 }
73 
74 
76 {
77  int id = aControlId / LYR_COLUMN_COUNT; // rounding is OK.
78  return id;
79 }
80 
81 
82 void LAYER_WIDGET::OnLeftDownLayers( wxMouseEvent& event )
83 {
84  int row;
85  LAYER_NUM layer;
86 
87  wxWindow* eventSource = (wxWindow*) event.GetEventObject();
88 
89  // if mouse event is coming from the m_LayerScrolledWindow and not one
90  // of its children, we have to find the row manually based on y coord.
91  if( eventSource == m_LayerScrolledWindow )
92  {
93  int y = event.GetY();
94 
95  wxArrayInt heights = m_LayersFlexGridSizer->GetRowHeights();
96 
97  int height = 0;
98 
99  int rowCount = GetLayerRowCount();
100  for( row = 0; row<rowCount; ++row )
101  {
102  if( y < height + heights[row] )
103  break;
104 
105  height += heights[row];
106  }
107 
108  if( row >= rowCount )
109  row = rowCount - 1;
110 
111  layer = getDecodedId( getLayerComp( row, 0 )->GetId() );
112  }
113 
114  else
115  {
116  // all nested controls on a given row will have their ID encoded with
117  // encodeId(), and the corresponding decoding is getDecodedId()
118  int id = eventSource->GetId();
119  layer = getDecodedId( id );
120  row = findLayerRow( layer );
121  }
122 
123  if( OnLayerSelect( layer ) ) // if client allows this change.
124  SelectLayerRow( row );
125 
126  passOnFocus();
127 }
128 
129 
130 void LAYER_WIDGET::OnRightDownLayer( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch, const wxString& aLayerName )
131 {
132  wxMenu menu;
133 
135  _( "Change Layer Color for " ) + aLayerName,
136  KiBitmap( setcolor_copper_xpm ) );
137  menu.AppendSeparator();
138 
139  OnLayerRightClick( menu );
140 
141  menu.Bind( wxEVT_COMMAND_MENU_SELECTED, [this, aColorSwatch]( wxCommandEvent& event ) {
142  if ( event.GetId() == ID_CHANGE_LAYER_COLOR ) {
143  aColorSwatch->GetNewSwatchColor();
144  } else {
145  event.Skip();
146  }
147  } );
148 
149  PopupMenu( &menu );
150  passOnFocus();
151 }
152 
153 
154 void LAYER_WIDGET::OnLayerSwatchChanged( wxCommandEvent& aEvent )
155 {
156  auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
157 
158  COLOR4D newColor = eventSource->GetSwatchColor();
159 
160  LAYER_NUM layer = getDecodedId( eventSource->GetId() );
161 
162  // tell the client code.
163  OnLayerColorChange( layer, newColor );
164 
165  // notify others
166  wxCommandEvent event( EVT_LAYER_COLOR_CHANGE );
167  wxPostEvent( this, event );
168 
169  passOnFocus();
170 }
171 
172 
173 void LAYER_WIDGET::OnLayerCheckBox( wxCommandEvent& event )
174 {
175  wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
176  LAYER_NUM layer = getDecodedId( eventSource->GetId() );
177  OnLayerVisible( layer, eventSource->IsChecked() );
178  passOnFocus();
179 }
180 
181 
182 void LAYER_WIDGET::OnRightDownRender( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch, const wxString& aRenderName )
183 {
184  wxMenu menu;
185 
187  _( "Change Render Color for " ) + aRenderName,
188  KiBitmap( setcolor_board_body_xpm ) );
189 
190  menu.Bind( wxEVT_COMMAND_MENU_SELECTED, [this, aColorSwatch]( wxCommandEvent& event ) {
191  if ( event.GetId() == ID_CHANGE_RENDER_COLOR ) {
192  aColorSwatch->GetNewSwatchColor();
193  } else {
194  event.Skip();
195  }
196  } );
197 
198  PopupMenu( &menu );
199  passOnFocus();
200 }
201 
202 
203 void LAYER_WIDGET::OnRenderSwatchChanged( wxCommandEvent& aEvent )
204 {
205  auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
206 
207  COLOR4D newColor = eventSource->GetSwatchColor();
208 
209  LAYER_NUM id = getDecodedId( eventSource->GetId() );
210 
211  // tell the client code.
212  OnRenderColorChange( id, newColor );
213 
214  passOnFocus();
215 }
216 
217 
218 void LAYER_WIDGET::OnRenderCheckBox( wxCommandEvent& event )
219 {
220  wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
221  LAYER_NUM id = getDecodedId( eventSource->GetId() );
222  OnRenderEnable( id, eventSource->IsChecked() );
223  passOnFocus();
224 }
225 
226 
227 void LAYER_WIDGET::OnTabChange( wxNotebookEvent& event )
228 {
229 // wxFocusEvent event( wxEVT_SET_FOCUS );
230 // m_FocusOwner->AddPendingEvent( event );
231 
232  passOnFocus(); // does not work in this context, probably because we have receive control here too early.
233 }
234 
235 
236 wxWindow* LAYER_WIDGET::getLayerComp( int aRow, int aColumn ) const
237 {
238  unsigned ndx = aRow * LYR_COLUMN_COUNT + aColumn;
239 
240  if( ndx < m_LayersFlexGridSizer->GetChildren().GetCount() )
241  return m_LayersFlexGridSizer->GetChildren()[ndx]->GetWindow();
242 
243  return NULL;
244 }
245 
246 
248 {
249  int count = GetLayerRowCount();
250 
251  for( int row = 0; row < count; ++row )
252  {
253  // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
254  wxWindow* w = getLayerComp( row, 0 );
255  wxASSERT( w );
256 
257  if( aLayer == getDecodedId( w->GetId() ))
258  return row;
259  }
260 
261  return -1;
262 }
263 
264 
265 wxWindow* LAYER_WIDGET::getRenderComp( int aRow, int aColumn ) const
266 {
267  int ndx = aRow * RND_COLUMN_COUNT + aColumn;
268 
269  if( (unsigned) ndx < m_RenderFlexGridSizer->GetChildren().GetCount() )
270  return m_RenderFlexGridSizer->GetChildren()[ndx]->GetWindow();
271 
272  return NULL;
273 }
274 
275 
276 int LAYER_WIDGET::findRenderRow( int aId ) const
277 {
278  int count = GetRenderRowCount();
279 
280  for( int row = 0; row < count; ++row )
281  {
282  // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
283  wxWindow* w = getRenderComp( row, 0 );
284  wxASSERT( w );
285 
286  if( aId == getDecodedId( w->GetId() ))
287  return row;
288  }
289 
290  return -1;
291 }
292 
293 
294 void LAYER_WIDGET::insertLayerRow( int aRow, const ROW& aSpec )
295 {
296  wxASSERT( aRow >= 0 );
297 
298  int col;
299  int index = aRow * LYR_COLUMN_COUNT;
300  const int flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
301 
302  auto& iconProvider = useAlternateBitmap(aRow) ? alternativeRowIcons : defaultRowIcons;
303 
304  // column 0
305  col = COLUMN_ICON_ACTIVE;
306  auto sbm = new INDICATOR_ICON( m_LayerScrolledWindow, iconProvider,
308  encodeId( col, aSpec.id ) );
309  sbm->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
310  m_LayersFlexGridSizer->wxSizer::Insert( index+col, sbm, 0, flags );
311 
312  // column 1 (COLUMN_COLORBM)
313  col = COLUMN_COLORBM;
314 
315  auto bmb = new COLOR_SWATCH( m_LayerScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
317  bmb->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
318  bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnLayerSwatchChanged, this );
319  bmb->SetToolTip( _("Left double click or middle click for color change, right click for menu" ) );
320  m_LayersFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
321 
322  // column 2 (COLUMN_COLOR_LYR_CB)
323  col = COLUMN_COLOR_LYR_CB;
324  wxCheckBox* cb = new wxCheckBox( m_LayerScrolledWindow, encodeId( col, aSpec.id ), wxEmptyString );
325  cb->SetValue( aSpec.state );
326  cb->Bind( wxEVT_COMMAND_CHECKBOX_CLICKED, &LAYER_WIDGET::OnLayerCheckBox, this );
327  cb->SetToolTip( _( "Enable this for visibility" ) );
328  m_LayersFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
329 
330  // column 3 (COLUMN_COLOR_LYRNAME)
331  col = COLUMN_COLOR_LYRNAME;
332  wxStaticText* st = new wxStaticText( m_LayerScrolledWindow, encodeId( col, aSpec.id ), aSpec.rowName );
333  shrinkFont( st, m_PointSize );
334  st->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
335  st->SetToolTip( aSpec.tooltip );
336  m_LayersFlexGridSizer->wxSizer::Insert( index+col, st, 0, flags );
337 
338  // Bind right click eventhandler to all columns
339  wxString layerName( aSpec.rowName );
340 
341  sbm->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
342  OnRightDownLayer( aEvt, bmb, layerName );
343  } );
344  bmb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
345  OnRightDownLayer( aEvt, bmb, layerName );
346  } );
347  cb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
348  OnRightDownLayer( aEvt, bmb, layerName );
349  } );
350  st->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
351  OnRightDownLayer( aEvt, bmb, layerName );
352  } );
353 }
354 
355 
356 void LAYER_WIDGET::insertRenderRow( int aRow, const ROW& aSpec )
357 {
358  wxASSERT( aRow >= 0 );
359 
360  int col;
361  int index = aRow * RND_COLUMN_COUNT;
362  const int flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
363 
364  wxString renderName( aSpec.rowName );
365 
366  // column 1
367  col = 1;
368  wxCheckBox* cb = new wxCheckBox( m_RenderScrolledWindow, encodeId( col, aSpec.id ),
369  aSpec.rowName, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
370  shrinkFont( cb, m_PointSize );
371  cb->SetValue( aSpec.state );
372  cb->Enable( aSpec.changeable );
373  cb->Bind( wxEVT_COMMAND_CHECKBOX_CLICKED, &LAYER_WIDGET::OnRenderCheckBox, this );
374  cb->SetToolTip( aSpec.tooltip );
375 
376  // column 0
377  col = 0;
378  if( aSpec.color != COLOR4D::UNSPECIFIED )
379  {
380  auto bmb = new COLOR_SWATCH( m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
382  bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnRenderSwatchChanged, this );
383  bmb->SetToolTip( _( "Left double click or middle click for color change" ) );
384  m_RenderFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
385 
386  bmb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, renderName] ( wxMouseEvent& aEvt ) {
387  OnRightDownRender( aEvt, bmb, renderName );
388  } );
389  cb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, renderName] ( wxMouseEvent& aEvt ) {
390  OnRightDownRender( aEvt, bmb, renderName );
391  } );
392 
393  // could add a left click handler on the color button that toggles checkbox.
394  }
395  else // == -1, no color selection wanted
396  {
397  // need a place holder within the sizer to keep grid full.
398  wxPanel* invisible = new wxPanel( m_RenderScrolledWindow, encodeId( col, aSpec.id ) );
399  m_RenderFlexGridSizer->wxSizer::Insert( index+col, invisible, 0, flags );
400  }
401 
402  // Items have to be inserted in order
403  col = 1;
404  m_RenderFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
405 }
406 
407 
409 {
410  m_FocusOwner->SetFocus();
411 }
412 
413 
414 //-----<public>-------------------------------------------------------
415 
416 LAYER_WIDGET::LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, int aPointSize,
417  wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) :
418  wxPanel( aParent, id, pos, size, style )
419 {
420  wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL );
421 
422  m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP );
423 
424  wxFont font = m_notebook->GetFont();
425 
426  if( aPointSize == -1 )
427  {
428  m_PointSize = font.GetPointSize();
429  }
430  else
431  {
432  m_PointSize = aPointSize;
433 
434  // change the font size on the notebook's tabs to match aPointSize
435  font.SetPointSize( aPointSize );
436  m_notebook->SetFont( font );
437  m_notebook->SetNormalFont( font );
438  m_notebook->SetSelectedFont( font );
439  m_notebook->SetMeasuringFont( font );
440  }
441 
442  m_LayerPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
443 
444  wxBoxSizer* bSizer3;
445  bSizer3 = new wxBoxSizer( wxVERTICAL );
446 
447  m_LayerScrolledWindow = new wxScrolledWindow( m_LayerPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
448  m_LayerScrolledWindow->SetScrollRate( 5, 5 );
449  m_LayersFlexGridSizer = new wxFlexGridSizer( 0, 4, 0, 1 );
450  m_LayersFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
451  m_LayersFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
452 
454  m_LayerScrolledWindow->Layout();
456  bSizer3->Add( m_LayerScrolledWindow, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 2 );
457 
458  m_LayerPanel->SetSizer( bSizer3 );
459  m_LayerPanel->Layout();
460  bSizer3->Fit( m_LayerPanel );
461  m_notebook->AddPage( m_LayerPanel, _( "Layer" ), true );
462  m_RenderingPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
463 
464  wxBoxSizer* bSizer4;
465  bSizer4 = new wxBoxSizer( wxVERTICAL );
466 
467  m_RenderScrolledWindow = new wxScrolledWindow( m_RenderingPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
468  m_RenderScrolledWindow->SetScrollRate( 5, 5 );
469  m_RenderFlexGridSizer = new wxFlexGridSizer( 0, 2, 0, 1 );
470  m_RenderFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
471  m_RenderFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
472 
474  m_RenderScrolledWindow->Layout();
476  bSizer4->Add( m_RenderScrolledWindow, 1, wxALL|wxEXPAND, 5 );
477 
478  m_RenderingPanel->SetSizer( bSizer4 );
479  m_RenderingPanel->Layout();
480  bSizer4->Fit( m_RenderingPanel );
481  m_notebook->AddPage( m_RenderingPanel, _( "Render" ), false );
482 
483  boxSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
484 
485  SetSizer( boxSizer );
486 
487  m_FocusOwner = aFocusOwner;
488 
489  m_CurrentRow = -1; // hide the arrow initially
490 
491  // trap the tab changes so that we can call passOnFocus().
492  m_notebook->Bind( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &LAYER_WIDGET::OnTabChange, this );
493 
494  Layout();
495 }
496 
497 
499 {
500 }
501 
502 
504 {
505  // size of m_LayerScrolledWindow --------------
506  wxArrayInt widths = m_LayersFlexGridSizer->GetColWidths();
507  int totWidth = 0;
508 
509  if( widths.GetCount() )
510  {
511  for( int i = 0; i < LYR_COLUMN_COUNT; ++i )
512  {
513  totWidth += widths[i] + m_LayersFlexGridSizer->GetHGap();
514  // printf("widths[%d]:%d\n", i, widths[i] );
515  }
516  }
517 
518  // Account for the parent's frame:
519  totWidth += 10;
520 
521 
522  /* The minimum height is a small size to properly force computation
523  * of the panel's scrollbars (otherwise it will assume it *has* all
524  * this space) */
525  unsigned totHeight = 32;
526 
527  wxSize layerz( totWidth, totHeight );
528 
529  layerz += m_LayerPanel->GetWindowBorderSize();
530 
531 
532  // size of m_RenderScrolledWindow --------------
533  widths = m_RenderFlexGridSizer->GetColWidths();
534  totWidth = 0;
535 
536  if( widths.GetCount() )
537  {
538  for( int i = 0; i < RND_COLUMN_COUNT; ++i )
539  {
540  totWidth += widths[i] + m_RenderFlexGridSizer->GetHGap();
541  // printf("widths[%d]:%d\n", i, widths[i] );
542  }
543  }
544  // account for the parent's frame, this one has void space of 10 PLUS a border:
545  totWidth += 20;
546 
547  // For totHeight re-use the previous small one
548  wxSize renderz( totWidth, totHeight );
549 
550  renderz += m_RenderingPanel->GetWindowBorderSize();
551 
552  wxSize clientz( std::max(renderz.x,layerz.x), std::max(renderz.y,layerz.y) );
553 
554  return clientz;
555 }
556 
557 
559 {
560  int controlCount = m_LayersFlexGridSizer->GetChildren().GetCount();
561  return controlCount / LYR_COLUMN_COUNT;
562 }
563 
564 
566 {
567  int controlCount = m_RenderFlexGridSizer->GetChildren().GetCount();
568  return controlCount / RND_COLUMN_COUNT;
569 }
570 
571 
573 {
574  int nextRow = GetLayerRowCount();
575  insertLayerRow( nextRow, aRow );
576  UpdateLayouts();
577 }
578 
579 
581 {
582  m_LayersFlexGridSizer->Clear( true );
583 }
584 
585 
587 {
588  int nextRow = GetRenderRowCount();
589  insertRenderRow( nextRow, aRow );
590  UpdateLayouts();
591 }
592 
593 
595 {
596  m_RenderFlexGridSizer->Clear( true );
597 }
598 
599 
601 {
602  // enable the layer tab at index 0
603  m_notebook->SetSelection( 0 );
604 
605  INDICATOR_ICON* oldIndicator = (INDICATOR_ICON*) getLayerComp( m_CurrentRow, 0 );
606  if( oldIndicator )
608 
609  INDICATOR_ICON* newIndicator = (INDICATOR_ICON*) getLayerComp( aRow, 0 );
610  if( newIndicator )
611  {
613 
614  // Make sure the desired layer row is visible.
615  // It seems that as of 2.8.2, setting the focus does this.
616  // I don't expect the scrolling to be needed at all because
617  // the minimum window size may end up being established so that the
618  // scroll bars will not be visible.
619  getLayerComp( aRow, 1 )->SetFocus();
620  }
621 
622  m_CurrentRow = aRow;
623 
624  // give the focus back to the app.
625  passOnFocus();
626 }
627 
628 
630 {
631  int row = findLayerRow( aLayer );
632  SelectLayerRow( row );
633 }
634 
635 
637 {
638  wxWindow* w = getLayerComp( m_CurrentRow, 0 );
639  if( w )
640  return getDecodedId( w->GetId() );
641 
642  return UNDEFINED_LAYER;
643 }
644 
645 
646 void LAYER_WIDGET::SetLayerVisible( LAYER_NUM aLayer, bool isVisible )
647 {
648  int row = findLayerRow( aLayer );
649  if( row >= 0 )
650  {
651  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
652  wxASSERT( cb );
653  cb->SetValue( isVisible ); // does not fire an event
654  }
655 }
656 
657 
659 {
660  int row = findLayerRow( aLayer );
661  if( row >= 0 )
662  {
663  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
664  wxASSERT( cb );
665  return cb->GetValue();
666  }
667  return false;
668 }
669 
670 
672 {
673  int row = findLayerRow( aLayer );
674  if( row >= 0 )
675  {
676  int col = 1; // bitmap button is column 1
677  auto bmb = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
678  wxASSERT( bmb );
679 
680  bmb->SetSwatchColor( aColor, false );
681  }
682 }
683 
684 
686 {
687  int row = findLayerRow( aLayer );
688  if( row >= 0 )
689  {
690  int col = 1; // bitmap button is column 1
691  wxBitmapButton* bmb = (wxBitmapButton*) getLayerComp( row, col );
692  wxASSERT( bmb );
693 
694  wxString colorTxt = bmb->GetName();
695  return ColorFromInt( strtoul( TO_UTF8(colorTxt), NULL, 0 ) );
696  }
697 
698  return COLOR4D::UNSPECIFIED; // it's caller fault, gave me a bad layer
699 }
700 
701 
702 void LAYER_WIDGET::SetRenderState( int aId, bool isSet )
703 {
704  int row = findRenderRow( aId );
705 
706  if( row >= 0 )
707  {
708  int col = 1; // checkbox is column 1
709  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
710  wxASSERT( cb );
711  cb->SetValue( isSet ); // does not fire an event
712  }
713 }
714 
715 
717 {
718  int row = findRenderRow( aId );
719 
720  if( row >= 0 )
721  {
722  int col = 1; // checkbox is column 1
723  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
724  wxASSERT( cb );
725  return cb->GetValue();
726  }
727 
728  return false; // the value of a non-existent row
729 }
730 
731 
733 {
734  m_LayersFlexGridSizer->Layout();
735  m_RenderFlexGridSizer->Layout();
736  m_LayerPanel->Layout();
737  m_RenderingPanel->Layout();
738  FitInside();
739 }
740 
741 
743 {
744  int rowCount = GetLayerRowCount();
745 
746  for( int row = 0; row < rowCount ; row++ )
747  {
749 
750  if( indicator )
751  {
752  auto state = ( row == m_CurrentRow ) ? ROW_ICON_PROVIDER::STATE::ON
754  indicator->SetIndicatorState( state );
755  }
756  }
757 }
758 
759 
760 #if defined(STAND_ALONE)
761 
762 #include <wx/aui/aui.h>
763 
764 
771 class MYFRAME : public wxFrame
772 {
773  // example of how to derive from LAYER_WIDGET in order to provide the
774  // abstract methods.
775  class MYLAYERS : public LAYER_WIDGET
776  {
777  public:
778  // your constructor could take a BOARD argument. here I leave it
779  // out because this source module wants to know nothing of BOARDs
780  // to maximize re-use.
781  MYLAYERS( wxWindow* aParent ) :
782  LAYER_WIDGET( aParent, aParent )
783  {
784  }
785 
786  void OnLayerColorChange( int aLayer, COLOR4D aColor )
787  {
788  printf( "OnLayerColorChange( aLayer:%d, aColor:%d )\n", aLayer, aColor );
789 
790  /* a test trigger only
791  if( aLayer == 2 )
792  {
793  ClearLayerRows();
794  printf(" GetLayerRowCount(): %d\n", GetLayerRowCount() );
795  }
796  */
797  }
798 
799  bool OnLayerSelect( LAYER_NUM aLayer )
800  {
801  printf( "OnLayerSelect( aLayer:%d )\n", aLayer );
802  return true;
803  }
804 
805  void OnLayerVisible( LAYER_NUM aLayer, bool isVisible, bool isFinal )
806  {
807  printf( "OnLayerVisible( aLayer:%d, isVisible:%d isFinal:%d)\n", aLayer, isVisible, isFinal );
808  }
809 
810  void OnRenderColorChange( int aId, COLOR4D aColor )
811  {
812  printf( "OnRenderColorChange( aId:%d, aColor:%d )\n", aId, aColor );
813  }
814 
815  void OnRenderEnable( int aId, bool isEnabled )
816  {
817  printf( "OnRenderEnable( aId:%d, isEnabled:%d )\n", aId, isEnabled );
818  }
819  };
820 
821 
822 public:
823  MYFRAME( wxWindow * parent ) :
824  wxFrame( parent, -1, wxT( "wxAUI Test" ), wxDefaultPosition,
825  wxSize( 800, 600 ), wxDEFAULT_FRAME_STYLE )
826  {
827  // notify wxAUI which frame to use
828  m_mgr.SetManagedWindow( this );
829 
830  MYLAYERS* lw = new MYLAYERS( this );
831 
832  // add some layer rows
833  static const LAYER_WIDGET::ROW layerRows[] = {
834  LAYER_WIDGET::ROW( wxT("layer 1"), 0, RED, wxT("RED"), false ),
835  LAYER_WIDGET::ROW( wxT("layer 2"), 1, GREEN, wxT("GREEN"), true ),
836  LAYER_WIDGET::ROW( wxT("brown_layer"), 2, BROWN, wxT("BROWN"), true ),
837  LAYER_WIDGET::ROW( wxT("layer_4_you"), 3, BLUE, wxT("BLUE"), false ),
838  };
839 
840  lw->AppendLayerRows( layerRows, DIM(layerRows) );
841 
842  // add some render rows
843  static const LAYER_WIDGET::ROW renderRows[] = {
844  LAYER_WIDGET::ROW( wxT("With Very Large Ears"), 0, COLOR4D::UNSPECIFIED, wxT("Spock here") ),
845  LAYER_WIDGET::ROW( wxT("With Legs"), 1, YELLOW ),
846  LAYER_WIDGET::ROW( wxT("With Oval Eyes"), 1, BROWN, wxT("My eyes are upon you") ),
847  };
848 
849  lw->AppendRenderRows( renderRows, DIM(renderRows) );
850 
851  lw->SelectLayerRow( 1 );
852 
853  wxAuiPaneInfo li;
854  li.MinSize( lw->GetBestSize() );
855  li.BestSize( lw->GetBestSize() );
856  li.Left();
857 // li.MaximizeButton( true );
858 // li.MinimizeButton( true );
859  li.CloseButton( false );
860  li.Caption( wxT( "Layers" ) );
861  m_mgr.AddPane( lw, li );
862 
863 
864  wxTextCtrl* text2 = new wxTextCtrl( this, -1, wxT( "Pane 2 - sample text" ),
865  wxDefaultPosition, wxSize( 200, 150 ),
866  wxNO_BORDER | wxTE_MULTILINE );
867  m_mgr.AddPane( text2, wxBOTTOM, wxT( "Pane Number Two" ) );
868 
869  wxTextCtrl* text3 = new wxTextCtrl( this, -1, wxT( "Main content window" ),
870  wxDefaultPosition, wxSize( 200, 150 ),
871  wxNO_BORDER | wxTE_MULTILINE );
872  m_mgr.AddPane( text3, wxCENTER );
873 
874  // tell the manager to "commit" all the changes just made
875  m_mgr.Update();
876  }
877 
878  ~MYFRAME()
879  {
880  // deinitialize the frame manager
881  m_mgr.UnInit();
882  }
883 
884 private:
885  wxAuiManager m_mgr;
886 };
887 
888 
889 // our normal wxApp-derived class, as usual
890 class MyApp : public wxApp
891 {
892 public:
893 
894  bool OnInit()
895  {
896  wxFrame* frame = new MYFRAME( NULL );
897 
898  SetTopWindow( frame );
899  frame->Show();
900  return true;
901  }
902 };
903 
904 DECLARE_APP( MyApp );
905 IMPLEMENT_APP( MyApp );
906 
907 #endif // STAND_ALONE
Definition: colors.h:57
#define COLUMN_COLOR_LYRNAME
Definition: layer_widget.h:54
#define DIM(x)
of elements in an array
Definition: macros.h:98
void OnLeftDownLayers(wxMouseEvent &event)
void SetIndicatorState(ICON_ID aIconId)
Sets the row indiciator to the given state.
wxAuiNotebook * m_notebook
Definition: layer_widget.h:110
#define LYR_COLUMN_COUNT
Layer tab column count.
Definition: layer_widget.h:48
int m_CurrentRow
selected row of layer list
Definition: layer_widget.h:119
void insertRenderRow(int aRow, const ROW &aSpec)
Icon provider for the "standard" row indicators, for example in layer selection lists.
Struct ROW provides all the data needed to add a row to a LAYER_WIDGET.
Definition: layer_widget.h:85
int findRenderRow(int aId) const
virtual void OnRenderColorChange(int aId, COLOR4D aColor)=0
Function OnRenderColorChange is called to notify client code whenever the user changes a rendering co...
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Function AddMenuItem is an inline helper function to create and insert a menu item with an icon into ...
Definition: bitmap.cpp:55
EDA_COLOR_T ColorFromInt(int aColor)
Checked cast. Use only when necessary (usually I/O)
Definition: colors.h:81
bool GetRenderState(int aId)
Function GetRenderState returns the state of the checkbox associated with aId.
void UpdateLayouts()
virtual void OnLayerVisible(LAYER_NUM aLayer, bool isVisible, bool isFinal=true)=0
Function OnLayerVisible is called to notify client code about a layer visibility change.
void OnTabChange(wxNotebookEvent &event)
bool changeable
if true, the state can be changed
Definition: layer_widget.h:92
static const wxEventType EVT_LAYER_COLOR_CHANGE
Definition: layer_widget.h:106
COLOR4D GetLayerColor(LAYER_NUM aLayer) const
Function GetLayerColor returns the color of the layer ROW associated with aLayer id.
#define OFF
wxScrolledWindow * m_RenderScrolledWindow
Definition: layer_widget.h:115
wxFlexGridSizer * m_LayersFlexGridSizer
Definition: layer_widget.h:113
virtual bool useAlternateBitmap(int aRow)
Virtual Function useAlternateBitmap.
Definition: layer_widget.h:130
int findLayerRow(LAYER_NUM aLayer) const
Function findLayerRow returns the row index that aLayer resides in, or -1 if not found.
static void shrinkFont(wxWindow *aControl, int aPointSize)
Function shrinkFont reduces the size of the wxFont associated with aControl.
wxSize GetBestSize() const
Function GetBestSize returns the preferred minimum size, taking into consideration the dynamic conten...
void ClearRenderRows()
Function ClearRenderRows empties out the render rows.
#define RND_COLUMN_COUNT
Rendering tab column count.
Definition: layer_widget.h:49
wxFlexGridSizer * m_RenderFlexGridSizer
Definition: layer_widget.h:116
bool state
initial wxCheckBox state
Definition: layer_widget.h:90
void ClearLayerRows()
Function ClearLayerRows empties out the layer rows.
wxString tooltip
if not empty, use this tooltip on row
Definition: layer_widget.h:91
This file contains miscellaneous commonly used macros and functions.
virtual void OnLayerColorChange(int aLayer, COLOR4D aColor)=0
Function OnLayerColorChange is called to notify client code about a layer color change.
void OnRenderCheckBox(wxCommandEvent &event)
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
void OnLayerCheckBox(wxCommandEvent &event)
Function OnLayerCheckBox handles the "is layer visible" checkbox and propogates the event to the clie...
void AppendRenderRow(const ROW &aRow)
Function AppendRenderRow appends a new row in the render portion of the widget.
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:36
static int encodeId(int aColumn, int aId)
Function encodeId is here to allow saving a layer index within a control as its wxControl id...
COLOR4D color
COLOR4D::UNSPECIFIED if none.
Definition: layer_widget.h:89
void OnRightDownRender(wxMouseEvent &aEvent, COLOR_SWATCH *aColorSwatch, const wxString &aRenderName)
Function OnRightDownRender Called when user right-clicks a render option.
Class representing a row indicator icon for use in places like the layer widget.
#define COLUMN_ICON_ACTIVE
Definition: layer_widget.h:51
int GetRenderRowCount() const
Function GetRenderRowCount returns the number of rows in the render tab.
#define COLUMN_COLORBM
Definition: layer_widget.h:52
void SetLayerColor(LAYER_NUM aLayer, COLOR4D aColor)
Function SetLayerColor changes the color of aLayer.
static ROW_ICON_PROVIDER alternativeRowIcons(true)
virtual bool AreArbitraryColorsAllowed()
Subclasses can override this to provide logic for allowing arbitrary color selection via wxColourPick...
Definition: layer_widget.h:136
wxPanel * m_RenderingPanel
Definition: layer_widget.h:114
void AppendLayerRow(const ROW &aRow)
Function AppendLayerRow appends a new row in the layer portion of the widget.
void UpdateLayerIcons()
Function UpdateLayerIcons Update all layer manager icons (layers only) Useful when loading a file or ...
wxScrolledWindow * m_LayerScrolledWindow
Definition: layer_widget.h:112
virtual void OnRenderEnable(int aId, bool isEnabled)=0
Function OnRenderEnable is called to notify client code whenever the user changes an rendering enable...
wxWindow * getLayerComp(int aRow, int aColumn) const
Function getLayerComp returns the component within the m_LayersFlexGridSizer at aRow and aCol or NULL...
Definition: colors.h:60
int GetLayerRowCount() const
Function GetLayerRowCount returns the number of rows in the layer tab.
void SelectLayerRow(int aRow)
Function SelectLayerRow changes the row selection in the layer list to the given row.
void OnRenderSwatchChanged(wxCommandEvent &aEvent)
Function OnRenderSwatchChanged Called when user has changed the swatch color of a render entry...
static LAYER_NUM getDecodedId(int aControlId)
Function getDecodedId decodes aControlId to original un-encoded value.
virtual ~LAYER_WIDGET()
wxWindow * m_FocusOwner
Definition: layer_widget.h:118
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
void passOnFocus()
Function passOnFocus gives away the keyboard focus up to the main parent window.
LAYER_NUM GetSelectedLayer()
Function GetSelectedLayer returns the selected layer or -1 if none.
bool IsLayerVisible(LAYER_NUM aLayer)
Function IsLayerVisible returns the visible state of the layer ROW associated with aLayer id...
Class LAYER_WIDGET is abstract and is used to manage a list of layers, with the notion of a "current"...
Definition: layer_widget.h:77
static ROW_ICON_PROVIDER defaultRowIcons(false)
Definition: colors.h:58
void OnRightDownLayer(wxMouseEvent &event, COLOR_SWATCH *aColorSwatch, const wxString &aLayerName)
Function OnRightDownLayer Called when user right-clicks a layer.
#define COLUMN_COLOR_LYR_CB
Definition: layer_widget.h:53
#define max(a, b)
Definition: auxiliary.h:86
wxString rowName
the prompt or layername
Definition: layer_widget.h:87
IMPLEMENT_APP(APP_KICAD)
Class representing a simple color swatch, of the kind used to set layer colors.
Definition: color_swatch.h:38
The common library.
virtual void OnLayerRightClick(wxMenu &aMenu)=0
Function OnLayerRightClick is called to notify client code about a layer being right-clicked.
void GetNewSwatchColor()
Prompt for a new colour, using the colour picker dialog.
void insertLayerRow(int aRow, const ROW &aSpec)
Function insertLayerRow appends or inserts a new row in the layer portion of the widget.
#define ON
void SetLayerVisible(LAYER_NUM aLayer, bool isVisible)
Function SetLayerVisible sets aLayer visible or not.
void OnLayerSwatchChanged(wxCommandEvent &aEvent)
Function OnSwatchChanged() is called when a user changes a swatch color.
virtual bool OnLayerSelect(int aLayer)=0
Function OnLayerSelect is called to notify client code whenever the user selects a different layer...
void SetRenderState(int aId, bool isSet)
Function SetRenderState sets the state of the checkbox associated with aId within the Render tab grou...
Definition: colors.h:68
void SelectLayer(LAYER_NUM aLayer)
Function SelectLayer changes the row selection in the layer list to aLayer provided.
int id
either a layer or "visible element" id
Definition: layer_widget.h:88
wxPanel * m_LayerPanel
Definition: layer_widget.h:111
LAYER_WIDGET(wxWindow *aParent, wxWindow *aFocusOwner, int aPointSize=-1, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL)
Constructor.
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
wxWindow * getRenderComp(int aRow, int aColumn) const
Definition: colors.h:62