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 
55 static void shrinkFont( wxWindow* aControl, int aPointSize )
56 {
57  wxFont font = aControl->GetFont();
58  font.SetPointSize( aPointSize );
59  aControl->SetFont( font ); // need this?
60 }
61 
62 
63 int LAYER_WIDGET::encodeId( int aColumn, int aId )
64 {
65  int id = aId * LYR_COLUMN_COUNT + aColumn;
66  return id;
67 }
68 
69 
71 {
72  int id = aControlId / LYR_COLUMN_COUNT; // rounding is OK.
73  return id;
74 }
75 
76 
77 void LAYER_WIDGET::OnLeftDownLayers( wxMouseEvent& event )
78 {
79  int row;
80  LAYER_NUM layer;
81 
82  wxWindow* eventSource = (wxWindow*) event.GetEventObject();
83 
84  // if mouse event is coming from the m_LayerScrolledWindow and not one
85  // of its children, we have to find the row manually based on y coord.
86  if( eventSource == m_LayerScrolledWindow )
87  {
88  int y = event.GetY();
89 
90  wxArrayInt heights = m_LayersFlexGridSizer->GetRowHeights();
91 
92  int height = 0;
93 
94  int rowCount = GetLayerRowCount();
95  for( row = 0; row<rowCount; ++row )
96  {
97  if( y < height + heights[row] )
98  break;
99 
100  height += heights[row];
101  }
102 
103  if( row >= rowCount )
104  row = rowCount - 1;
105 
106  layer = getDecodedId( getLayerComp( row, 0 )->GetId() );
107  }
108 
109  else
110  {
111  // all nested controls on a given row will have their ID encoded with
112  // encodeId(), and the corresponding decoding is getDecodedId()
113  int id = eventSource->GetId();
114  layer = getDecodedId( id );
115  row = findLayerRow( layer );
116  }
117 
118  if( OnLayerSelect( layer ) ) // if client allows this change.
119  SelectLayerRow( row );
120 
121  passOnFocus();
122 }
123 
124 
125 void LAYER_WIDGET::OnRightDownLayer( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch, const wxString& aLayerName )
126 {
127  wxMenu menu;
128 
130  _( "Change Layer Color for " ) + aLayerName,
131  KiBitmap( setcolor_copper_xpm ) );
132  menu.AppendSeparator();
133 
134  OnLayerRightClick( menu );
135 
136  menu.Bind( wxEVT_COMMAND_MENU_SELECTED, [aColorSwatch]( wxCommandEvent& event ) {
137  if ( event.GetId() == ID_CHANGE_LAYER_COLOR ) {
138  aColorSwatch->GetNewSwatchColor();
139  } else {
140  event.Skip();
141  }
142  } );
143 
144  PopupMenu( &menu );
145  passOnFocus();
146 }
147 
148 
149 void LAYER_WIDGET::OnLayerSwatchChanged( wxCommandEvent& aEvent )
150 {
151  auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
152 
153  COLOR4D newColor = eventSource->GetSwatchColor();
154 
155  LAYER_NUM layer = getDecodedId( eventSource->GetId() );
156 
157  // tell the client code.
158  OnLayerColorChange( layer, newColor );
159 
160  // notify others
161  wxCommandEvent event( EVT_LAYER_COLOR_CHANGE );
162  wxPostEvent( this, event );
163 
164  passOnFocus();
165 }
166 
167 
168 void LAYER_WIDGET::OnLayerCheckBox( wxCommandEvent& event )
169 {
170  wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
171  LAYER_NUM layer = getDecodedId( eventSource->GetId() );
172  OnLayerVisible( layer, eventSource->IsChecked() );
173  passOnFocus();
174 }
175 
176 
177 void LAYER_WIDGET::OnRightDownRender( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch, const wxString& aRenderName )
178 {
179  wxMenu menu;
180 
182  _( "Change Render Color for " ) + aRenderName,
183  KiBitmap( setcolor_board_body_xpm ) );
184 
185  menu.Bind( wxEVT_COMMAND_MENU_SELECTED, [aColorSwatch]( wxCommandEvent& event ) {
186  if ( event.GetId() == ID_CHANGE_RENDER_COLOR ) {
187  aColorSwatch->GetNewSwatchColor();
188  } else {
189  event.Skip();
190  }
191  } );
192 
193  PopupMenu( &menu );
194  passOnFocus();
195 }
196 
197 
198 void LAYER_WIDGET::OnRenderSwatchChanged( wxCommandEvent& aEvent )
199 {
200  auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
201 
202  COLOR4D newColor = eventSource->GetSwatchColor();
203 
204  LAYER_NUM id = getDecodedId( eventSource->GetId() );
205 
206  if( id == LAYER_PCB_BACKGROUND )
207  {
208  // Update all swatch backgrounds
209  int count = GetLayerRowCount();
210  int row;
211  int col = 1; // bitmap button is column 1 in layers tab
212  for( row = 0; row < count; ++row )
213  {
214  COLOR_SWATCH* swatch = dynamic_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
215  if( swatch )
216  swatch->SetSwatchBackground( newColor );
217  }
218 
219  count = GetRenderRowCount();
220  col = 0; // bitmap button is column 0 in render tab
221  for( row = 0; row < count; ++row )
222  {
223  COLOR_SWATCH* swatch = dynamic_cast<COLOR_SWATCH*>( getRenderComp( row, col ) );
224  if( swatch )
225  swatch->SetSwatchBackground( newColor );
226  }
227  }
228 
229  // tell the client code.
230  OnRenderColorChange( id, newColor );
231 
232  passOnFocus();
233 }
234 
235 
236 void LAYER_WIDGET::OnRenderCheckBox( wxCommandEvent& event )
237 {
238  wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
239  LAYER_NUM id = getDecodedId( eventSource->GetId() );
240  OnRenderEnable( id, eventSource->IsChecked() );
241  passOnFocus();
242 }
243 
244 
245 void LAYER_WIDGET::OnTabChange( wxNotebookEvent& event )
246 {
247 // wxFocusEvent event( wxEVT_SET_FOCUS );
248 // m_FocusOwner->AddPendingEvent( event );
249 
250  passOnFocus(); // does not work in this context, probably because we have receive control here too early.
251 }
252 
253 
254 wxWindow* LAYER_WIDGET::getLayerComp( int aRow, int aColumn ) const
255 {
256  unsigned ndx = aRow * LYR_COLUMN_COUNT + aColumn;
257 
258  if( ndx < m_LayersFlexGridSizer->GetChildren().GetCount() )
259  return m_LayersFlexGridSizer->GetChildren()[ndx]->GetWindow();
260 
261  return NULL;
262 }
263 
264 
266 {
267  int count = GetLayerRowCount();
268 
269  for( int row = 0; row < count; ++row )
270  {
271  // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
272  wxWindow* w = getLayerComp( row, 0 );
273  wxASSERT( w );
274 
275  if( aLayer == getDecodedId( w->GetId() ))
276  return row;
277  }
278 
279  return -1;
280 }
281 
282 
283 wxWindow* LAYER_WIDGET::getRenderComp( int aRow, int aColumn ) const
284 {
285  int ndx = aRow * RND_COLUMN_COUNT + aColumn;
286 
287  if( (unsigned) ndx < m_RenderFlexGridSizer->GetChildren().GetCount() )
288  return m_RenderFlexGridSizer->GetChildren()[ndx]->GetWindow();
289 
290  return NULL;
291 }
292 
293 
294 int LAYER_WIDGET::findRenderRow( int aId ) const
295 {
296  int count = GetRenderRowCount();
297 
298  for( int row = 0; row < count; ++row )
299  {
300  // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
301  wxWindow* w = getRenderComp( row, 0 );
302  wxASSERT( w );
303 
304  if( aId == getDecodedId( w->GetId() ))
305  return row;
306  }
307 
308  return -1;
309 }
310 
311 
312 void LAYER_WIDGET::insertLayerRow( int aRow, const ROW& aSpec )
313 {
314  wxASSERT( aRow >= 0 );
315 
316  int col;
317  int index = aRow * LYR_COLUMN_COUNT;
318  const int flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
319 
320  // column 0
321  col = COLUMN_ICON_ACTIVE;
323  ROW_ICON_PROVIDER::STATE::OFF, encodeId( col, aSpec.id ) );
324  sbm->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
325  m_LayersFlexGridSizer->wxSizer::Insert( index+col, sbm, 0, flags );
326 
327  // column 1 (COLUMN_COLORBM)
328  col = COLUMN_COLORBM;
329 
330  auto bmb = new COLOR_SWATCH( m_LayerScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
332  bmb->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
333  bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnLayerSwatchChanged, this );
334  bmb->SetToolTip( _("Left double click or middle click for color change, right click for menu" ) );
335  m_LayersFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
336 
337  // column 2 (COLUMN_COLOR_LYR_CB)
338  col = COLUMN_COLOR_LYR_CB;
339  wxCheckBox* cb = new wxCheckBox( m_LayerScrolledWindow, encodeId( col, aSpec.id ), wxEmptyString );
340  cb->SetValue( aSpec.state );
341  cb->Bind( wxEVT_COMMAND_CHECKBOX_CLICKED, &LAYER_WIDGET::OnLayerCheckBox, this );
342  cb->SetToolTip( _( "Enable this for visibility" ) );
343  m_LayersFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
344 
345  // column 3 (COLUMN_COLOR_LYRNAME)
346  col = COLUMN_COLOR_LYRNAME;
347  wxStaticText* st = new wxStaticText( m_LayerScrolledWindow, encodeId( col, aSpec.id ), aSpec.rowName );
348  shrinkFont( st, m_PointSize );
349  st->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
350  st->SetToolTip( aSpec.tooltip );
351  m_LayersFlexGridSizer->wxSizer::Insert( index+col, st, 0, flags );
352 
353  // column 4 (COLUMN_ALPHA_INDICATOR)
356  ROW_ICON_PROVIDER::STATE::OFF, wxID_ANY );
357  m_LayersFlexGridSizer->wxSizer::Insert( index+col, sbm, 0, flags );
358 
359  // Bind right click eventhandler to all columns
360  wxString layerName( aSpec.rowName );
361 
362  sbm->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
363  OnRightDownLayer( aEvt, bmb, layerName );
364  } );
365  bmb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
366  OnRightDownLayer( aEvt, bmb, layerName );
367  } );
368  cb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
369  OnRightDownLayer( aEvt, bmb, layerName );
370  } );
371  st->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt ) {
372  OnRightDownLayer( aEvt, bmb, layerName );
373  } );
374 }
375 
376 
377 void LAYER_WIDGET::insertRenderRow( int aRow, const ROW& aSpec )
378 {
379  wxASSERT( aRow >= 0 );
380 
381  int col;
382  int index = aRow * RND_COLUMN_COUNT;
383  const int flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
384 
385  wxString renderName( aSpec.rowName );
386  wxCheckBox* cb = nullptr;
387 
388  // column 1
389  if( !aSpec.spacer )
390  {
391  col = 1;
392  cb = new wxCheckBox( m_RenderScrolledWindow, encodeId( col, aSpec.id ),
393  aSpec.rowName, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
394  shrinkFont( cb, m_PointSize );
395  cb->SetValue( aSpec.state );
396  cb->Enable( aSpec.changeable );
397  cb->Bind( wxEVT_COMMAND_CHECKBOX_CLICKED, &LAYER_WIDGET::OnRenderCheckBox, this );
398  cb->SetToolTip( aSpec.tooltip );
399  }
400 
401  // column 0
402  col = 0;
403  if( aSpec.color != COLOR4D::UNSPECIFIED )
404  {
405  auto bmb = new COLOR_SWATCH( m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
407  bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnRenderSwatchChanged, this );
408  bmb->SetToolTip( _( "Left double click or middle click for color change" ) );
409  m_RenderFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
410 
411  bmb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, renderName] ( wxMouseEvent& aEvt ) {
412  OnRightDownRender( aEvt, bmb, renderName );
413  } );
414  cb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, renderName] ( wxMouseEvent& aEvt ) {
415  OnRightDownRender( aEvt, bmb, renderName );
416  } );
417 
418  // could add a left click handler on the color button that toggles checkbox.
419  }
420  else // == -1, no color selection wanted
421  {
422  // need a place holder within the sizer to keep grid full.
423  wxPanel* invisible = new wxPanel( m_RenderScrolledWindow, encodeId( col, aSpec.id ) );
424  m_RenderFlexGridSizer->wxSizer::Insert( index+col, invisible, 0, flags );
425  }
426 
427  // Items have to be inserted in order
428  col = 1;
429 
430  if( aSpec.spacer )
431  {
432  wxPanel* invisible = new wxPanel( m_RenderScrolledWindow, wxID_ANY );
433  m_RenderFlexGridSizer->wxSizer::Insert( index+col, invisible, 0, flags );
434  }
435  else
436  {
437  m_RenderFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
438  }
439 }
440 
441 
443 {
444  m_FocusOwner->SetFocus();
445 }
446 
447 
448 //-----<public>-------------------------------------------------------
449 
450 LAYER_WIDGET::LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, wxWindowID id,
451  const wxPoint& pos, const wxSize& size, long style ) :
452  wxPanel( aParent, id, pos, size, style )
453 {
454  int indicatorSize = ConvertDialogToPixels( wxSize( 6, 6 ) ).x;
455  m_IconProvider = new ROW_ICON_PROVIDER( indicatorSize );
456 
457  int pointSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
458  int screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
459 
460  if( screenHeight <= 900 && pointSize >= indicatorSize )
461  pointSize = pointSize * 8 / 10;
462 
463  m_PointSize = pointSize;
464 
465  wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL );
466 
467  m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP );
468 
469  wxFont font = m_notebook->GetFont();
470 
471  // change the font size on the notebook's tabs to match aPointSize
472  font.SetPointSize( pointSize );
473  m_notebook->SetFont( font );
474  m_notebook->SetNormalFont( font );
475  m_notebook->SetSelectedFont( font );
476  m_notebook->SetMeasuringFont( font );
477 
478  m_LayerPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
479 
480  wxBoxSizer* bSizer3;
481  bSizer3 = new wxBoxSizer( wxVERTICAL );
482 
483  m_LayerScrolledWindow = new wxScrolledWindow( m_LayerPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
484  m_LayerScrolledWindow->SetScrollRate( 5, 5 );
485  m_LayersFlexGridSizer = new wxFlexGridSizer( 0, LYR_COLUMN_COUNT, 0, 1 );
486  m_LayersFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
487  m_LayersFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
488 
490  m_LayerScrolledWindow->Layout();
492  bSizer3->Add( m_LayerScrolledWindow, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 2 );
493 
494  m_LayerPanel->SetSizer( bSizer3 );
495  m_LayerPanel->Layout();
496  bSizer3->Fit( m_LayerPanel );
497  m_notebook->AddPage( m_LayerPanel, _( "Layers" ), true );
498  m_RenderingPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
499 
500  wxBoxSizer* bSizer4;
501  bSizer4 = new wxBoxSizer( wxVERTICAL );
502 
503  m_RenderScrolledWindow = new wxScrolledWindow( m_RenderingPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
504  m_RenderScrolledWindow->SetScrollRate( 5, 5 );
505  m_RenderFlexGridSizer = new wxFlexGridSizer( 0, RND_COLUMN_COUNT, 0, 1 );
506  m_RenderFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
507  m_RenderFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
508 
510  m_RenderScrolledWindow->Layout();
512  bSizer4->Add( m_RenderScrolledWindow, 1, wxALL|wxEXPAND, 5 );
513 
514  m_RenderingPanel->SetSizer( bSizer4 );
515  m_RenderingPanel->Layout();
516  bSizer4->Fit( m_RenderingPanel );
517  m_notebook->AddPage( m_RenderingPanel, _( "Items" ), false );
518 
519  boxSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
520 
521  SetSizer( boxSizer );
522 
523  m_FocusOwner = aFocusOwner;
524 
525  m_CurrentRow = -1; // hide the arrow initially
526 
527  // trap the tab changes so that we can call passOnFocus().
528  m_notebook->Bind( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &LAYER_WIDGET::OnTabChange, this );
529 
530  Layout();
531 }
532 
533 
535 {
536  delete m_IconProvider;
537 }
538 
539 
541 {
542  // size of m_LayerScrolledWindow --------------
543  wxArrayInt widths = m_LayersFlexGridSizer->GetColWidths();
544  int totWidth = 0;
545 
546  if( widths.GetCount() )
547  {
548  for( int i = 0; i < LYR_COLUMN_COUNT; ++i )
549  {
550  totWidth += widths[i] + m_LayersFlexGridSizer->GetHGap();
551  // printf("widths[%d]:%d\n", i, widths[i] );
552  }
553  }
554 
555  // Account for the parent's frame:
556  totWidth += 32;
557 
558 
559  /* The minimum height is a small size to properly force computation
560  * of the panel's scrollbars (otherwise it will assume it *has* all
561  * this space) */
562  unsigned totHeight = 32;
563 
564  wxSize layerz( totWidth, totHeight );
565 
566  layerz += m_LayerPanel->GetWindowBorderSize();
567 
568 
569  // size of m_RenderScrolledWindow --------------
570  widths = m_RenderFlexGridSizer->GetColWidths();
571  totWidth = 0;
572 
573  if( widths.GetCount() )
574  {
575  for( int i = 0; i < RND_COLUMN_COUNT; ++i )
576  {
577  totWidth += widths[i] + m_RenderFlexGridSizer->GetHGap();
578  // printf("widths[%d]:%d\n", i, widths[i] );
579  }
580  }
581  // account for the parent's frame, this one has void space of 10 PLUS a border:
582  totWidth += 32;
583 
584  // For totHeight re-use the previous small one
585  wxSize renderz( totWidth, totHeight );
586 
587  renderz += m_RenderingPanel->GetWindowBorderSize();
588 
589  wxSize clientz( std::max(renderz.x,layerz.x), std::max(renderz.y,layerz.y) );
590 
591  return clientz;
592 }
593 
594 
596 {
597  int controlCount = m_LayersFlexGridSizer->GetChildren().GetCount();
598  return controlCount / LYR_COLUMN_COUNT;
599 }
600 
601 
603 {
604  int controlCount = m_RenderFlexGridSizer->GetChildren().GetCount();
605  return controlCount / RND_COLUMN_COUNT;
606 }
607 
608 
610 {
611  int nextRow = GetLayerRowCount();
612  insertLayerRow( nextRow, aRow );
613  UpdateLayouts();
614 }
615 
616 
618 {
619  m_LayersFlexGridSizer->Clear( true );
620 }
621 
622 
624 {
625  int nextRow = GetRenderRowCount();
626  insertRenderRow( nextRow, aRow );
627  UpdateLayouts();
628 }
629 
630 
632 {
633  m_RenderFlexGridSizer->Clear( true );
634 }
635 
636 
638 {
639  // enable the layer tab at index 0
640  m_notebook->SetSelection( 0 );
641 
642  INDICATOR_ICON* oldIndicator = (INDICATOR_ICON*) getLayerComp( m_CurrentRow, 0 );
643  if( oldIndicator )
644  {
646  oldIndicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::DIMMED );
647  else
649  }
650 
651  INDICATOR_ICON* newIndicator = (INDICATOR_ICON*) getLayerComp( aRow, 0 );
652  if( newIndicator )
653  {
655 
656  // Make sure the desired layer row is visible.
657  // It seems that as of 2.8.2, setting the focus does this.
658  // I don't expect the scrolling to be needed at all because
659  // the minimum window size may end up being established so that the
660  // scroll bars will not be visible.
661  getLayerComp( aRow, 1 )->SetFocus();
662  }
663 
664  m_CurrentRow = aRow;
665 
666  // give the focus back to the app.
667  passOnFocus();
668 }
669 
670 
672 {
673  int row = findLayerRow( aLayer );
674  SelectLayerRow( row );
675 }
676 
677 
679 {
680  wxWindow* w = getLayerComp( m_CurrentRow, 0 );
681  if( w )
682  return getDecodedId( w->GetId() );
683 
684  return UNDEFINED_LAYER;
685 }
686 
687 
688 void LAYER_WIDGET::SetLayerVisible( LAYER_NUM aLayer, bool isVisible )
689 {
690  setLayerCheckbox( aLayer, isVisible );
691  OnLayerVisible( aLayer, isVisible );
692 }
693 
694 
695 void LAYER_WIDGET::setLayerCheckbox( LAYER_NUM aLayer, bool isVisible )
696 {
697  int row = findLayerRow( aLayer );
698  if( row >= 0 )
699  {
700  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
701  wxASSERT( cb );
702  cb->SetValue( isVisible ); // does not fire an event
703  }
704 }
705 
706 
708 {
709  int row = findLayerRow( aLayer );
710  if( row >= 0 )
711  {
712  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
713  wxASSERT( cb );
714  return cb->GetValue();
715  }
716  return false;
717 }
718 
719 
721 {
722  int row = findLayerRow( aLayer );
723  if( row >= 0 )
724  {
725  int col = 1; // bitmap button is column 1
726  auto swatch = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
727  wxASSERT( swatch );
728 
729  swatch->SetSwatchColor( aColor, false );
730  }
731 }
732 
733 
735 {
736  int row = findLayerRow( aLayer );
737  if( row >= 0 )
738  {
739  int col = 1; // bitmap button is column 1
740  auto swatch = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
741  wxASSERT( swatch );
742 
743  return swatch->GetSwatchColor();
744  }
745 
746  return COLOR4D::UNSPECIFIED; // it's caller fault, gave me a bad layer
747 }
748 
749 
750 void LAYER_WIDGET::SetRenderState( int aId, bool isSet )
751 {
752  int row = findRenderRow( aId );
753 
754  if( row >= 0 )
755  {
756  int col = 1; // checkbox is column 1
757  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
758  wxASSERT( cb );
759  cb->SetValue( isSet ); // does not fire an event
760  }
761 }
762 
763 
765 {
766  int row = findRenderRow( aId );
767 
768  if( row >= 0 )
769  {
770  int col = 1; // checkbox is column 1
771  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
772  wxASSERT( cb );
773  return cb->GetValue();
774  }
775 
776  return false; // the value of a non-existent row
777 }
778 
779 
781 {
782  m_LayersFlexGridSizer->Layout();
783  m_RenderFlexGridSizer->Layout();
784  m_LayerPanel->Layout();
785  m_RenderingPanel->Layout();
786  FitInside();
787 }
788 
789 
791 {
792  int rowCount = GetLayerRowCount();
793 
794  for( int row = 0; row < rowCount ; row++ )
795  {
797 
798  if( indicator )
799  {
801 
802  if( row == m_CurrentRow )
804  else if( useAlternateBitmap( row ) )
805  state = ROW_ICON_PROVIDER::STATE::DIMMED;
806  else
808 
809  indicator->SetIndicatorState( state );
810  }
811  }
812 }
813 
814 
815 #if defined(STAND_ALONE)
816 
817 #include <wx/aui/aui.h>
818 
819 
826 class MYFRAME : public wxFrame
827 {
828  // example of how to derive from LAYER_WIDGET in order to provide the
829  // abstract methods.
830  class MYLAYERS : public LAYER_WIDGET
831  {
832  public:
833  // your constructor could take a BOARD argument. here I leave it
834  // out because this source module wants to know nothing of BOARDs
835  // to maximize re-use.
836  MYLAYERS( wxWindow* aParent ) :
837  LAYER_WIDGET( aParent, aParent )
838  {
839  }
840 
841  void OnLayerColorChange( int aLayer, COLOR4D aColor )
842  {
843  printf( "OnLayerColorChange( aLayer:%d, aColor:%d )\n", aLayer, aColor );
844 
845  /* a test trigger only
846  if( aLayer == 2 )
847  {
848  ClearLayerRows();
849  printf(" GetLayerRowCount(): %d\n", GetLayerRowCount() );
850  }
851  */
852  }
853 
854  bool OnLayerSelect( LAYER_NUM aLayer )
855  {
856  printf( "OnLayerSelect( aLayer:%d )\n", aLayer );
857  return true;
858  }
859 
860  void OnLayerVisible( LAYER_NUM aLayer, bool isVisible, bool isFinal )
861  {
862  printf( "OnLayerVisible( aLayer:%d, isVisible:%d isFinal:%d)\n", aLayer, isVisible, isFinal );
863  }
864 
865  void OnRenderColorChange( int aId, COLOR4D aColor )
866  {
867  printf( "OnRenderColorChange( aId:%d, aColor:%d )\n", aId, aColor );
868  }
869 
870  void OnRenderEnable( int aId, bool isEnabled )
871  {
872  printf( "OnRenderEnable( aId:%d, isEnabled:%d )\n", aId, isEnabled );
873  }
874  };
875 
876 
877 public:
878  MYFRAME( wxWindow * parent ) :
879  wxFrame( parent, -1, wxT( "wxAUI Test" ), wxDefaultPosition,
880  wxSize( 800, 600 ), wxDEFAULT_FRAME_STYLE )
881  {
882  // notify wxAUI which frame to use
883  m_mgr.SetManagedWindow( this );
884 
885  MYLAYERS* lw = new MYLAYERS( this );
886 
887  // add some layer rows
888  static const LAYER_WIDGET::ROW layerRows[] = {
889  LAYER_WIDGET::ROW( wxT("layer 1"), 0, RED, wxT("RED"), false ),
890  LAYER_WIDGET::ROW( wxT("layer 2"), 1, GREEN, wxT("GREEN"), true ),
891  LAYER_WIDGET::ROW( wxT("brown_layer"), 2, BROWN, wxT("BROWN"), true ),
892  LAYER_WIDGET::ROW( wxT("layer_4_you"), 3, BLUE, wxT("BLUE"), false ),
893  };
894 
895  lw->AppendLayerRows( layerRows, DIM(layerRows) );
896 
897  // add some render rows
898  static const LAYER_WIDGET::ROW renderRows[] = {
899  LAYER_WIDGET::ROW( wxT("With Very Large Ears"), 0, COLOR4D::UNSPECIFIED, wxT("Spock here") ),
900  LAYER_WIDGET::ROW( wxT("With Legs"), 1, YELLOW ),
901  LAYER_WIDGET::ROW( wxT("With Oval Eyes"), 1, BROWN, wxT("My eyes are upon you") ),
902  };
903 
904  lw->AppendRenderRows( renderRows, DIM(renderRows) );
905 
906  lw->SelectLayerRow( 1 );
907 
908  wxAuiPaneInfo li;
909  li.MinSize( lw->GetBestSize() );
910  li.BestSize( lw->GetBestSize() );
911  li.Left();
912 // li.MaximizeButton( true );
913 // li.MinimizeButton( true );
914  li.CloseButton( false );
915  li.Caption( wxT( "Layers" ) );
916  m_mgr.AddPane( lw, li );
917 
918 
919  wxTextCtrl* text2 = new wxTextCtrl( this, -1, wxT( "Pane 2 - sample text" ),
920  wxDefaultPosition, wxSize( 200, 150 ),
921  wxNO_BORDER | wxTE_MULTILINE );
922  m_mgr.AddPane( text2, wxBOTTOM, wxT( "Pane Number Two" ) );
923 
924  wxTextCtrl* text3 = new wxTextCtrl( this, -1, wxT( "Main content window" ),
925  wxDefaultPosition, wxSize( 200, 150 ),
926  wxNO_BORDER | wxTE_MULTILINE );
927  m_mgr.AddPane( text3, wxCENTER );
928 
929  // tell the manager to "commit" all the changes just made
930  m_mgr.Update();
931  }
932 
933  ~MYFRAME()
934  {
935  // deinitialize the frame manager
936  m_mgr.UnInit();
937  }
938 
939 private:
940  wxAuiManager m_mgr;
941 };
942 
943 
944 // our normal wxApp-derived class, as usual
945 class MyApp : public wxApp
946 {
947 public:
948 
949  bool OnInit()
950  {
951  wxFrame* frame = new MYFRAME( NULL );
952 
953  SetTopWindow( frame );
954  frame->Show();
955  return true;
956  }
957 };
958 
959 DECLARE_APP( MyApp );
960 IMPLEMENT_APP( MyApp );
961 
962 #endif // STAND_ALONE
Definition: colors.h:57
#define COLUMN_COLOR_LYRNAME
Definition: layer_widget.h:55
#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:123
#define LYR_COLUMN_COUNT
Layer tab column count.
Definition: layer_widget.h:49
int m_CurrentRow
selected row of layer list
Definition: layer_widget.h:132
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:87
#define COLUMN_ALPHA_INDICATOR
Definition: layer_widget.h:56
int findRenderRow(int aId) const
bool spacer
if true, this row is a spacer
Definition: layer_widget.h:95
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:174
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:94
static const wxEventType EVT_LAYER_COLOR_CHANGE
Definition: layer_widget.h:119
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:128
wxFlexGridSizer * m_LayersFlexGridSizer
Definition: layer_widget.h:126
virtual bool useAlternateBitmap(int aRow)
Virtual Function useAlternateBitmap.
Definition: layer_widget.h:145
void SetSwatchBackground(KIGFX::COLOR4D aBackground)
Set the swatch background color.
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:50
wxFlexGridSizer * m_RenderFlexGridSizer
Definition: layer_widget.h:129
bool state
initial wxCheckBox state
Definition: layer_widget.h:92
void ClearLayerRows()
Function ClearLayerRows empties out the layer rows.
wxString tooltip
if not empty, use this tooltip on row
Definition: layer_widget.h:93
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)
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:78
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:91
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:52
int GetRenderRowCount() const
Function GetRenderRowCount returns the number of rows in the render tab.
void setLayerCheckbox(LAYER_NUM aLayer, bool isVisible)
#define COLUMN_COLORBM
Definition: layer_widget.h:53
void SetLayerColor(LAYER_NUM aLayer, COLOR4D aColor)
Function SetLayerColor changes the color of aLayer.
virtual bool AreArbitraryColorsAllowed()
Subclasses can override this to provide logic for allowing arbitrary color selection via wxColourPick...
Definition: layer_widget.h:151
wxPanel * m_RenderingPanel
Definition: layer_widget.h:127
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:125
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:131
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
LAYER_WIDGET(wxWindow *aParent, wxWindow *aFocusOwner, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL)
Constructor.
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:79
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:54
#define max(a, b)
Definition: auxiliary.h:86
wxString rowName
the prompt or layername
Definition: layer_widget.h:89
size_t i
Definition: json11.cpp:597
virtual COLOR4D getBackgroundLayerColor()
Subclasses can override this to provide accurate representation of transparent colour swatches...
Definition: layer_widget.h:157
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.
STATE
State constants to select the right icons
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:90
ROW_ICON_PROVIDER * m_IconProvider
Definition: layer_widget.h:135
wxPanel * m_LayerPanel
Definition: layer_widget.h:124
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