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