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, int aPointSize,
451  wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) :
452  wxPanel( aParent, id, pos, size, style )
453 {
454  wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL );
455 
456  m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP );
457 
458  wxFont font = m_notebook->GetFont();
459 
460  if( aPointSize == -1 )
461  {
462  m_PointSize = font.GetPointSize();
463  }
464  else
465  {
466  m_PointSize = aPointSize;
467 
468  // change the font size on the notebook's tabs to match aPointSize
469  font.SetPointSize( aPointSize );
470  m_notebook->SetFont( font );
471  m_notebook->SetNormalFont( font );
472  m_notebook->SetSelectedFont( font );
473  m_notebook->SetMeasuringFont( font );
474  }
475 
476  int indicatorSize = ConvertDialogToPixels( wxSize( 6, 6 ) ).x;
477  m_IconProvider = new ROW_ICON_PROVIDER( indicatorSize );
478 
479  m_LayerPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
480 
481  wxBoxSizer* bSizer3;
482  bSizer3 = new wxBoxSizer( wxVERTICAL );
483 
484  m_LayerScrolledWindow = new wxScrolledWindow( m_LayerPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
485  m_LayerScrolledWindow->SetScrollRate( 5, 5 );
486  m_LayersFlexGridSizer = new wxFlexGridSizer( 0, LYR_COLUMN_COUNT, 0, 1 );
487  m_LayersFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
488  m_LayersFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
489 
491  m_LayerScrolledWindow->Layout();
493  bSizer3->Add( m_LayerScrolledWindow, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 2 );
494 
495  m_LayerPanel->SetSizer( bSizer3 );
496  m_LayerPanel->Layout();
497  bSizer3->Fit( m_LayerPanel );
498  m_notebook->AddPage( m_LayerPanel, _( "Layers" ), true );
499  m_RenderingPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
500 
501  wxBoxSizer* bSizer4;
502  bSizer4 = new wxBoxSizer( wxVERTICAL );
503 
504  m_RenderScrolledWindow = new wxScrolledWindow( m_RenderingPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
505  m_RenderScrolledWindow->SetScrollRate( 5, 5 );
506  m_RenderFlexGridSizer = new wxFlexGridSizer( 0, RND_COLUMN_COUNT, 0, 1 );
507  m_RenderFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
508  m_RenderFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
509 
511  m_RenderScrolledWindow->Layout();
513  bSizer4->Add( m_RenderScrolledWindow, 1, wxALL|wxEXPAND, 5 );
514 
515  m_RenderingPanel->SetSizer( bSizer4 );
516  m_RenderingPanel->Layout();
517  bSizer4->Fit( m_RenderingPanel );
518  m_notebook->AddPage( m_RenderingPanel, _( "Items" ), false );
519 
520  boxSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
521 
522  SetSizer( boxSizer );
523 
524  m_FocusOwner = aFocusOwner;
525 
526  m_CurrentRow = -1; // hide the arrow initially
527 
528  // trap the tab changes so that we can call passOnFocus().
529  m_notebook->Bind( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &LAYER_WIDGET::OnTabChange, this );
530 
531  Layout();
532 }
533 
534 
536 {
537  delete m_IconProvider;
538 }
539 
540 
542 {
543  // size of m_LayerScrolledWindow --------------
544  wxArrayInt widths = m_LayersFlexGridSizer->GetColWidths();
545  int totWidth = 0;
546 
547  if( widths.GetCount() )
548  {
549  for( int i = 0; i < LYR_COLUMN_COUNT; ++i )
550  {
551  totWidth += widths[i] + m_LayersFlexGridSizer->GetHGap();
552  // printf("widths[%d]:%d\n", i, widths[i] );
553  }
554  }
555 
556  // Account for the parent's frame:
557  totWidth += 32;
558 
559 
560  /* The minimum height is a small size to properly force computation
561  * of the panel's scrollbars (otherwise it will assume it *has* all
562  * this space) */
563  unsigned totHeight = 32;
564 
565  wxSize layerz( totWidth, totHeight );
566 
567  layerz += m_LayerPanel->GetWindowBorderSize();
568 
569 
570  // size of m_RenderScrolledWindow --------------
571  widths = m_RenderFlexGridSizer->GetColWidths();
572  totWidth = 0;
573 
574  if( widths.GetCount() )
575  {
576  for( int i = 0; i < RND_COLUMN_COUNT; ++i )
577  {
578  totWidth += widths[i] + m_RenderFlexGridSizer->GetHGap();
579  // printf("widths[%d]:%d\n", i, widths[i] );
580  }
581  }
582  // account for the parent's frame, this one has void space of 10 PLUS a border:
583  totWidth += 32;
584 
585  // For totHeight re-use the previous small one
586  wxSize renderz( totWidth, totHeight );
587 
588  renderz += m_RenderingPanel->GetWindowBorderSize();
589 
590  wxSize clientz( std::max(renderz.x,layerz.x), std::max(renderz.y,layerz.y) );
591 
592  return clientz;
593 }
594 
595 
597 {
598  int controlCount = m_LayersFlexGridSizer->GetChildren().GetCount();
599  return controlCount / LYR_COLUMN_COUNT;
600 }
601 
602 
604 {
605  int controlCount = m_RenderFlexGridSizer->GetChildren().GetCount();
606  return controlCount / RND_COLUMN_COUNT;
607 }
608 
609 
611 {
612  int nextRow = GetLayerRowCount();
613  insertLayerRow( nextRow, aRow );
614  UpdateLayouts();
615 }
616 
617 
619 {
620  m_LayersFlexGridSizer->Clear( true );
621 }
622 
623 
625 {
626  int nextRow = GetRenderRowCount();
627  insertRenderRow( nextRow, aRow );
628  UpdateLayouts();
629 }
630 
631 
633 {
634  m_RenderFlexGridSizer->Clear( true );
635 }
636 
637 
639 {
640  // enable the layer tab at index 0
641  m_notebook->SetSelection( 0 );
642 
643  INDICATOR_ICON* oldIndicator = (INDICATOR_ICON*) getLayerComp( m_CurrentRow, 0 );
644  if( oldIndicator )
645  {
647  oldIndicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::DIMMED );
648  else
650  }
651 
652  INDICATOR_ICON* newIndicator = (INDICATOR_ICON*) getLayerComp( aRow, 0 );
653  if( newIndicator )
654  {
656 
657  // Make sure the desired layer row is visible.
658  // It seems that as of 2.8.2, setting the focus does this.
659  // I don't expect the scrolling to be needed at all because
660  // the minimum window size may end up being established so that the
661  // scroll bars will not be visible.
662  getLayerComp( aRow, 1 )->SetFocus();
663  }
664 
665  m_CurrentRow = aRow;
666 
667  // give the focus back to the app.
668  passOnFocus();
669 }
670 
671 
673 {
674  int row = findLayerRow( aLayer );
675  SelectLayerRow( row );
676 }
677 
678 
680 {
681  wxWindow* w = getLayerComp( m_CurrentRow, 0 );
682  if( w )
683  return getDecodedId( w->GetId() );
684 
685  return UNDEFINED_LAYER;
686 }
687 
688 
689 void LAYER_WIDGET::SetLayerVisible( LAYER_NUM aLayer, bool isVisible )
690 {
691  setLayerCheckbox( aLayer, isVisible );
692  OnLayerVisible( aLayer, isVisible );
693 }
694 
695 
696 void LAYER_WIDGET::setLayerCheckbox( LAYER_NUM aLayer, bool isVisible )
697 {
698  int row = findLayerRow( aLayer );
699  if( row >= 0 )
700  {
701  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
702  wxASSERT( cb );
703  cb->SetValue( isVisible ); // does not fire an event
704  }
705 }
706 
707 
709 {
710  int row = findLayerRow( aLayer );
711  if( row >= 0 )
712  {
713  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
714  wxASSERT( cb );
715  return cb->GetValue();
716  }
717  return false;
718 }
719 
720 
722 {
723  int row = findLayerRow( aLayer );
724  if( row >= 0 )
725  {
726  int col = 1; // bitmap button is column 1
727  auto swatch = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
728  wxASSERT( swatch );
729 
730  swatch->SetSwatchColor( aColor, false );
731  }
732 }
733 
734 
736 {
737  int row = findLayerRow( aLayer );
738  if( row >= 0 )
739  {
740  int col = 1; // bitmap button is column 1
741  auto swatch = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
742  wxASSERT( swatch );
743 
744  return swatch->GetSwatchColor();
745  }
746 
747  return COLOR4D::UNSPECIFIED; // it's caller fault, gave me a bad layer
748 }
749 
750 
751 void LAYER_WIDGET::SetRenderState( int aId, bool isSet )
752 {
753  int row = findRenderRow( aId );
754 
755  if( row >= 0 )
756  {
757  int col = 1; // checkbox is column 1
758  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
759  wxASSERT( cb );
760  cb->SetValue( isSet ); // does not fire an event
761  }
762 }
763 
764 
766 {
767  int row = findRenderRow( aId );
768 
769  if( row >= 0 )
770  {
771  int col = 1; // checkbox is column 1
772  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
773  wxASSERT( cb );
774  return cb->GetValue();
775  }
776 
777  return false; // the value of a non-existent row
778 }
779 
780 
782 {
783  m_LayersFlexGridSizer->Layout();
784  m_RenderFlexGridSizer->Layout();
785  m_LayerPanel->Layout();
786  m_RenderingPanel->Layout();
787  FitInside();
788 }
789 
790 
792 {
793  int rowCount = GetLayerRowCount();
794 
795  for( int row = 0; row < rowCount ; row++ )
796  {
798 
799  if( indicator )
800  {
802 
803  if( row == m_CurrentRow )
805  else if( useAlternateBitmap( row ) )
806  state = ROW_ICON_PROVIDER::STATE::DIMMED;
807  else
809 
810  indicator->SetIndicatorState( state );
811  }
812  }
813 }
814 
815 
816 #if defined(STAND_ALONE)
817 
818 #include <wx/aui/aui.h>
819 
820 
827 class MYFRAME : public wxFrame
828 {
829  // example of how to derive from LAYER_WIDGET in order to provide the
830  // abstract methods.
831  class MYLAYERS : public LAYER_WIDGET
832  {
833  public:
834  // your constructor could take a BOARD argument. here I leave it
835  // out because this source module wants to know nothing of BOARDs
836  // to maximize re-use.
837  MYLAYERS( wxWindow* aParent ) :
838  LAYER_WIDGET( aParent, aParent )
839  {
840  }
841 
842  void OnLayerColorChange( int aLayer, COLOR4D aColor )
843  {
844  printf( "OnLayerColorChange( aLayer:%d, aColor:%d )\n", aLayer, aColor );
845 
846  /* a test trigger only
847  if( aLayer == 2 )
848  {
849  ClearLayerRows();
850  printf(" GetLayerRowCount(): %d\n", GetLayerRowCount() );
851  }
852  */
853  }
854 
855  bool OnLayerSelect( LAYER_NUM aLayer )
856  {
857  printf( "OnLayerSelect( aLayer:%d )\n", aLayer );
858  return true;
859  }
860 
861  void OnLayerVisible( LAYER_NUM aLayer, bool isVisible, bool isFinal )
862  {
863  printf( "OnLayerVisible( aLayer:%d, isVisible:%d isFinal:%d)\n", aLayer, isVisible, isFinal );
864  }
865 
866  void OnRenderColorChange( int aId, COLOR4D aColor )
867  {
868  printf( "OnRenderColorChange( aId:%d, aColor:%d )\n", aId, aColor );
869  }
870 
871  void OnRenderEnable( int aId, bool isEnabled )
872  {
873  printf( "OnRenderEnable( aId:%d, isEnabled:%d )\n", aId, isEnabled );
874  }
875  };
876 
877 
878 public:
879  MYFRAME( wxWindow * parent ) :
880  wxFrame( parent, -1, wxT( "wxAUI Test" ), wxDefaultPosition,
881  wxSize( 800, 600 ), wxDEFAULT_FRAME_STYLE )
882  {
883  // notify wxAUI which frame to use
884  m_mgr.SetManagedWindow( this );
885 
886  MYLAYERS* lw = new MYLAYERS( this );
887 
888  // add some layer rows
889  static const LAYER_WIDGET::ROW layerRows[] = {
890  LAYER_WIDGET::ROW( wxT("layer 1"), 0, RED, wxT("RED"), false ),
891  LAYER_WIDGET::ROW( wxT("layer 2"), 1, GREEN, wxT("GREEN"), true ),
892  LAYER_WIDGET::ROW( wxT("brown_layer"), 2, BROWN, wxT("BROWN"), true ),
893  LAYER_WIDGET::ROW( wxT("layer_4_you"), 3, BLUE, wxT("BLUE"), false ),
894  };
895 
896  lw->AppendLayerRows( layerRows, DIM(layerRows) );
897 
898  // add some render rows
899  static const LAYER_WIDGET::ROW renderRows[] = {
900  LAYER_WIDGET::ROW( wxT("With Very Large Ears"), 0, COLOR4D::UNSPECIFIED, wxT("Spock here") ),
901  LAYER_WIDGET::ROW( wxT("With Legs"), 1, YELLOW ),
902  LAYER_WIDGET::ROW( wxT("With Oval Eyes"), 1, BROWN, wxT("My eyes are upon you") ),
903  };
904 
905  lw->AppendRenderRows( renderRows, DIM(renderRows) );
906 
907  lw->SelectLayerRow( 1 );
908 
909  wxAuiPaneInfo li;
910  li.MinSize( lw->GetBestSize() );
911  li.BestSize( lw->GetBestSize() );
912  li.Left();
913 // li.MaximizeButton( true );
914 // li.MinimizeButton( true );
915  li.CloseButton( false );
916  li.Caption( wxT( "Layers" ) );
917  m_mgr.AddPane( lw, li );
918 
919 
920  wxTextCtrl* text2 = new wxTextCtrl( this, -1, wxT( "Pane 2 - sample text" ),
921  wxDefaultPosition, wxSize( 200, 150 ),
922  wxNO_BORDER | wxTE_MULTILINE );
923  m_mgr.AddPane( text2, wxBOTTOM, wxT( "Pane Number Two" ) );
924 
925  wxTextCtrl* text3 = new wxTextCtrl( this, -1, wxT( "Main content window" ),
926  wxDefaultPosition, wxSize( 200, 150 ),
927  wxNO_BORDER | wxTE_MULTILINE );
928  m_mgr.AddPane( text3, wxCENTER );
929 
930  // tell the manager to "commit" all the changes just made
931  m_mgr.Update();
932  }
933 
934  ~MYFRAME()
935  {
936  // deinitialize the frame manager
937  m_mgr.UnInit();
938  }
939 
940 private:
941  wxAuiManager m_mgr;
942 };
943 
944 
945 // our normal wxApp-derived class, as usual
946 class MyApp : public wxApp
947 {
948 public:
949 
950  bool OnInit()
951  {
952  wxFrame* frame = new MYFRAME( NULL );
953 
954  SetTopWindow( frame );
955  frame->Show();
956  return true;
957  }
958 };
959 
960 DECLARE_APP( MyApp );
961 IMPLEMENT_APP( MyApp );
962 
963 #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.
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
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