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-2021 KiCad Developers, see AUTHORS.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 <bitmaps.h>
39 #include <macros.h>
40 #include <menus_helpers.h>
41 #include <widgets/indicator_icon.h>
43 #include <wx/checkbox.h>
44 
45 #include <algorithm>
46 
47 
48 const wxEventType LAYER_WIDGET::EVT_LAYER_COLOR_CHANGE = wxNewEventType();
49 
50 
54 static void shrinkFont( wxWindow* aControl, int aPointSize )
55 {
56  wxFont font = aControl->GetFont();
57  font.SetPointSize( aPointSize );
58  aControl->SetFont( font ); // need this?
59 }
60 
61 
62 int LAYER_WIDGET::encodeId( int aColumn, int aId )
63 {
64  int id = aId * LYR_COLUMN_COUNT + aColumn;
65  return id;
66 }
67 
68 
70 {
71  int id = aControlId / LYR_COLUMN_COUNT; // rounding is OK.
72  return id;
73 }
74 
75 
76 void LAYER_WIDGET::OnLeftDownLayers( wxMouseEvent& event )
77 {
78  int row;
79  LAYER_NUM layer;
80 
81  wxWindow* eventSource = (wxWindow*) event.GetEventObject();
82 
83  // if mouse event is coming from the m_LayerScrolledWindow and not one
84  // of its children, we have to find the row manually based on y coord.
85  if( eventSource == m_LayerScrolledWindow )
86  {
87  int y = event.GetY();
88 
89  wxArrayInt heights = m_LayersFlexGridSizer->GetRowHeights();
90 
91  int height = 0;
92 
93  int rowCount = GetLayerRowCount();
94 
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  else
109  {
110  // all nested controls on a given row will have their ID encoded with
111  // encodeId(), and the corresponding decoding is getDecodedId()
112  int id = eventSource->GetId();
113  layer = getDecodedId( id );
114  row = findLayerRow( layer );
115  }
116 
117  if( OnLayerSelect( layer ) ) // if client allows this change.
118  SelectLayerRow( row );
119 
120  passOnFocus();
121 }
122 
123 
124 void LAYER_WIDGET::OnRightDownLayer( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch,
125  const wxString& aLayerName )
126 {
127  wxMenu menu;
128 
130  _( "Change Layer Color for" ) + wxS( " " ) + aLayerName,
132  menu.AppendSeparator();
133 
134  OnLayerRightClick( menu );
135 
136  menu.Bind( wxEVT_COMMAND_MENU_SELECTED, [aColorSwatch]( wxCommandEvent& event )
137  {
138  if( event.GetId() == ID_CHANGE_LAYER_COLOR )
139  {
140  aColorSwatch->GetNewSwatchColor();
141  }
142  else
143  {
144  event.Skip();
145  }
146  } );
147 
148  PopupMenu( &menu );
149  passOnFocus();
150 }
151 
152 
153 void LAYER_WIDGET::OnLayerSwatchChanged( wxCommandEvent& aEvent )
154 {
155  COLOR_SWATCH* eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
156  COLOR4D newColor = eventSource->GetSwatchColor();
157  LAYER_NUM layer = getDecodedId( eventSource->GetId() );
158 
159  // tell the client code.
160  OnLayerColorChange( layer, newColor );
161 
162  // notify others
163  wxCommandEvent event( EVT_LAYER_COLOR_CHANGE );
164  wxPostEvent( this, event );
165 
166  passOnFocus();
167 }
168 
169 
170 void LAYER_WIDGET::OnLayerCheckBox( wxCommandEvent& event )
171 {
172  wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
173  LAYER_NUM layer = getDecodedId( eventSource->GetId() );
174  OnLayerVisible( layer, eventSource->IsChecked() );
175  passOnFocus();
176 }
177 
178 
179 void LAYER_WIDGET::OnRightDownRender( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch,
180  const wxString& aRenderName )
181 {
182  wxMenu menu;
183 
185  _( "Change Render Color for" ) + wxS( " " )+ aRenderName,
187 
188  menu.Bind( wxEVT_COMMAND_MENU_SELECTED,
189  [aColorSwatch]( wxCommandEvent& event )
190  {
191  if( event.GetId() == ID_CHANGE_RENDER_COLOR )
192  aColorSwatch->GetNewSwatchColor();
193  else
194  event.Skip();
195  } );
196 
197  PopupMenu( &menu );
198  passOnFocus();
199 }
200 
201 
202 void LAYER_WIDGET::OnRenderSwatchChanged( wxCommandEvent& aEvent )
203 {
204  auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
205 
206  COLOR4D newColor = eventSource->GetSwatchColor();
207 
208  LAYER_NUM id = getDecodedId( eventSource->GetId() );
209 
210  if( id == LAYER_PCB_BACKGROUND )
211  {
212  // Update all swatch backgrounds
213  int count = GetLayerRowCount();
214  int row;
215  int col = 1; // bitmap button is column 1 in layers tab
216 
217  for( row = 0; row < count; ++row )
218  {
219  COLOR_SWATCH* swatch = dynamic_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
220 
221  if( swatch )
222  swatch->SetSwatchBackground( newColor );
223  }
224 
225  count = GetRenderRowCount();
226  col = 0; // bitmap button is column 0 in render tab
227 
228  for( row = 0; row < count; ++row )
229  {
230  COLOR_SWATCH* swatch = dynamic_cast<COLOR_SWATCH*>( getRenderComp( row, col ) );
231 
232  if( swatch )
233  swatch->SetSwatchBackground( newColor );
234  }
235  }
236 
237  // tell the client code.
238  OnRenderColorChange( id, newColor );
239 
240  passOnFocus();
241 }
242 
243 
244 void LAYER_WIDGET::OnRenderCheckBox( wxCommandEvent& event )
245 {
246  wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
247  LAYER_NUM id = getDecodedId( eventSource->GetId() );
248  OnRenderEnable( id, eventSource->IsChecked() );
249  passOnFocus();
250 }
251 
252 
253 void LAYER_WIDGET::OnTabChange( wxNotebookEvent& event )
254 {
255 // wxFocusEvent event( wxEVT_SET_FOCUS );
256 // m_FocusOwner->AddPendingEvent( event );
257 
258  // Does not work in this context, probably because we have receive control here too early.
259  passOnFocus();
260 }
261 
262 
263 wxWindow* LAYER_WIDGET::getLayerComp( int aRow, int aColumn ) const
264 {
265  unsigned ndx = aRow * LYR_COLUMN_COUNT + aColumn;
266 
267  if( ndx < m_LayersFlexGridSizer->GetChildren().GetCount() )
268  return m_LayersFlexGridSizer->GetChildren()[ndx]->GetWindow();
269 
270  return nullptr;
271 }
272 
273 
275 {
276  int count = GetLayerRowCount();
277 
278  for( int row = 0; row < count; ++row )
279  {
280  // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
281  wxWindow* w = getLayerComp( row, 0 );
282  wxASSERT( w );
283 
284  if( aLayer == getDecodedId( w->GetId() ) )
285  return row;
286  }
287 
288  return -1;
289 }
290 
291 
292 wxWindow* LAYER_WIDGET::getRenderComp( int aRow, int aColumn ) const
293 {
294  int ndx = aRow * RND_COLUMN_COUNT + aColumn;
295 
296  if( (unsigned) ndx < m_RenderFlexGridSizer->GetChildren().GetCount() )
297  return m_RenderFlexGridSizer->GetChildren()[ndx]->GetWindow();
298 
299  return nullptr;
300 }
301 
302 
303 int LAYER_WIDGET::findRenderRow( int aId ) const
304 {
305  int count = GetRenderRowCount();
306 
307  for( int row = 0; row < count; ++row )
308  {
309  // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
310  wxWindow* w = getRenderComp( row, 0 );
311  wxASSERT( w );
312 
313  if( aId == getDecodedId( w->GetId() ) )
314  return row;
315  }
316 
317  return -1;
318 }
319 
320 
321 void LAYER_WIDGET::insertLayerRow( int aRow, const ROW& aSpec )
322 {
323  wxASSERT( aRow >= 0 );
324 
325  int col;
326  int index = aRow * LYR_COLUMN_COUNT;
327  const int flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
328 
329  // column 0
330  col = COLUMN_ICON_ACTIVE;
332  ROW_ICON_PROVIDER::STATE::OFF, encodeId( col, aSpec.id ) );
333  sbm->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
334  m_LayersFlexGridSizer->wxSizer::Insert( index+col, sbm, 0, flags );
335 
336  // column 1 (COLUMN_COLORBM)
337  col = COLUMN_COLORBM;
338 
339  auto bmb = new COLOR_SWATCH( m_LayerScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
341  bmb->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
342  bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnLayerSwatchChanged, this );
343  bmb->SetToolTip( _("Left double click or middle click for color change, right click for "
344  "menu" ) );
345  m_LayersFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
346 
347  // column 2 (COLUMN_COLOR_LYR_CB)
348  col = COLUMN_COLOR_LYR_CB;
349  wxCheckBox* cb = new wxCheckBox( m_LayerScrolledWindow, encodeId( col, aSpec.id ),
350  wxEmptyString );
351  cb->SetValue( aSpec.state );
352  cb->Bind( wxEVT_COMMAND_CHECKBOX_CLICKED, &LAYER_WIDGET::OnLayerCheckBox, this );
353  cb->SetToolTip( _( "Enable this for visibility" ) );
354  m_LayersFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
355 
356  // column 3 (COLUMN_COLOR_LYRNAME)
357  col = COLUMN_COLOR_LYRNAME;
359  encodeId( col, aSpec.id ),
360  aSpec.rowName, wxDefaultPosition,
361  wxDefaultSize,
362  wxST_ELLIPSIZE_MIDDLE );
363  shrinkFont( st, m_PointSize );
364  st->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
365  st->SetToolTip( aSpec.tooltip );
367  m_LayersFlexGridSizer->wxSizer::Insert( index+col, st, 0, flags | wxEXPAND );
368 
369  // column 4 (COLUMN_ALPHA_INDICATOR)
372  ROW_ICON_PROVIDER::STATE::OFF, wxID_ANY );
373  m_LayersFlexGridSizer->wxSizer::Insert( index+col, sbm, 0, flags );
374 
375  // Bind right click eventhandler to all columns
376  wxString layerName( aSpec.rowName );
377 
378  sbm->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt )
379  {
380  OnRightDownLayer( aEvt, bmb, layerName );
381  } );
382  bmb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt )
383  {
384  OnRightDownLayer( aEvt, bmb, layerName );
385  } );
386  cb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt )
387  {
388  OnRightDownLayer( aEvt, bmb, layerName );
389  } );
390  st->Bind( wxEVT_RIGHT_DOWN, [this, bmb, layerName] ( wxMouseEvent& aEvt )
391  {
392  OnRightDownLayer( aEvt, bmb, layerName );
393  } );
394 }
395 
396 
397 void LAYER_WIDGET::updateLayerRow( int aRow, const wxString& aName )
398 {
399  wxStaticText* label = dynamic_cast<wxStaticText*>( getLayerComp( aRow, COLUMN_COLOR_LYRNAME ) );
400 
401  if( label )
402  label->SetLabel( aName );
403 
404  INDICATOR_ICON* indicator = (INDICATOR_ICON*) getLayerComp( aRow, 0 );
405 
406  if( indicator )
407  {
408  if( aRow == m_CurrentRow )
410  if( useAlternateBitmap( aRow ) )
411  indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::DIMMED );
412  else
413  indicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::OFF );
414  }
415 }
416 
417 
418 void LAYER_WIDGET::insertRenderRow( int aRow, const ROW& aSpec )
419 {
420  wxASSERT( aRow >= 0 );
421 
422  int col;
423  int index = aRow * RND_COLUMN_COUNT;
424  const int flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
425 
426  wxString renderName( aSpec.rowName );
427  wxCheckBox* cb = nullptr;
428 
429  // column 1
430  if( !aSpec.spacer )
431  {
432  col = 1;
433  cb = new wxCheckBox( m_RenderScrolledWindow, encodeId( col, aSpec.id ),
434  aSpec.rowName, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
435  shrinkFont( cb, m_PointSize );
436  cb->SetValue( aSpec.state );
437  cb->Enable( aSpec.changeable );
438  cb->Bind( wxEVT_COMMAND_CHECKBOX_CLICKED, &LAYER_WIDGET::OnRenderCheckBox, this );
439  cb->SetToolTip( aSpec.tooltip );
440  }
441 
442  // column 0
443  col = 0;
444 
445  if( aSpec.color != COLOR4D::UNSPECIFIED )
446  {
447  auto bmb = new COLOR_SWATCH( m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
449  bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnRenderSwatchChanged, this );
450  bmb->SetToolTip( _( "Left double click or middle click for color change" ) );
451  m_RenderFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
452 
453  bmb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, renderName] ( wxMouseEvent& aEvt ) {
454  OnRightDownRender( aEvt, bmb, renderName );
455  } );
456  cb->Bind( wxEVT_RIGHT_DOWN, [this, bmb, renderName] ( wxMouseEvent& aEvt ) {
457  OnRightDownRender( aEvt, bmb, renderName );
458  } );
459 
460  // could add a left click handler on the color button that toggles checkbox.
461  }
462  else // == -1, no color selection wanted
463  {
464  // need a place holder within the sizer to keep grid full.
465  wxPanel* invisible = new wxPanel( m_RenderScrolledWindow, encodeId( col, aSpec.id ) );
466  m_RenderFlexGridSizer->wxSizer::Insert( index+col, invisible, 0, flags );
467  }
468 
469  // Items have to be inserted in order
470  col = 1;
471 
472  if( aSpec.spacer )
473  {
474  wxPanel* invisible = new wxPanel( m_RenderScrolledWindow, wxID_ANY );
475  m_RenderFlexGridSizer->wxSizer::Insert( index+col, invisible, 0, flags );
476  }
477  else
478  {
479  m_RenderFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
480  }
481 }
482 
483 
485 {
486  m_FocusOwner->SetFocus();
487 }
488 
489 
490 LAYER_WIDGET::LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, wxWindowID id,
491  const wxPoint& pos, const wxSize& size, long style ) :
492  wxPanel( aParent, id, pos, size, style ),
493  m_smallestLayerString( "M...M" )
494 {
495  int indicatorSize = ConvertDialogToPixels( wxSize( 6, 6 ) ).x;
496  m_IconProvider = new ROW_ICON_PROVIDER( indicatorSize );
497 
498  int pointSize = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ).GetPointSize();
499  int screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
500 
501  if( screenHeight <= 900 && pointSize >= indicatorSize )
502  pointSize = pointSize * 8 / 10;
503 
504  m_PointSize = pointSize;
505 
506  wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
507 
508  m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP );
509 
510  wxFont font = m_notebook->GetFont();
511 
512  // change the font size on the notebook's tabs to match aPointSize
513  font.SetPointSize( pointSize );
514  m_notebook->SetFont( font );
515 
516  m_LayerPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize,
517  wxTAB_TRAVERSAL );
518 
519  wxBoxSizer* layerPanelSizer;
520  layerPanelSizer = new wxBoxSizer( wxVERTICAL );
521 
522  m_LayerScrolledWindow = new wxScrolledWindow( m_LayerPanel, wxID_ANY, wxDefaultPosition,
523  wxDefaultSize, wxNO_BORDER );
524  m_LayerScrolledWindow->SetScrollRate( 5, 5 );
525  m_LayersFlexGridSizer = new wxFlexGridSizer( 0, LYR_COLUMN_COUNT, 0, 1 );
526  m_LayersFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
527  m_LayersFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
528 
529  // Make column 3 growable/stretchable
530  m_LayersFlexGridSizer->AddGrowableCol( 3, 1 );
531 
533  m_LayerScrolledWindow->Layout();
535  layerPanelSizer->Add( m_LayerScrolledWindow, 1, wxBOTTOM | wxEXPAND | wxLEFT | wxTOP, 2 );
536 
537  m_LayerPanel->SetSizer( layerPanelSizer );
538  m_LayerPanel->Layout();
539  layerPanelSizer->Fit( m_LayerPanel );
540  m_notebook->AddPage( m_LayerPanel, _( "Layers" ), true );
541  m_RenderingPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize,
542  wxTAB_TRAVERSAL );
543 
544  wxBoxSizer* renderPanelSizer;
545  renderPanelSizer = new wxBoxSizer( wxVERTICAL );
546 
547  m_RenderScrolledWindow = new wxScrolledWindow( m_RenderingPanel, wxID_ANY, wxDefaultPosition,
548  wxDefaultSize, wxNO_BORDER );
549  m_RenderScrolledWindow->SetScrollRate( 5, 5 );
550  m_RenderFlexGridSizer = new wxFlexGridSizer( 0, RND_COLUMN_COUNT, 0, 1 );
551  m_RenderFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
552  m_RenderFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
553 
555  m_RenderScrolledWindow->Layout();
557  renderPanelSizer->Add( m_RenderScrolledWindow, 1, wxALL | wxEXPAND, 5 );
558 
559  m_RenderingPanel->SetSizer( renderPanelSizer );
560  m_RenderingPanel->Layout();
561  renderPanelSizer->Fit( m_RenderingPanel );
562  m_notebook->AddPage( m_RenderingPanel, _( "Items" ), false );
563 
564  mainSizer->Add( m_notebook, 1, wxEXPAND, 5 );
565 
566  SetSizer( mainSizer );
567 
568  m_FocusOwner = aFocusOwner;
569 
570  m_CurrentRow = -1; // hide the arrow initially
571 
572  // trap the tab changes so that we can call passOnFocus().
573  m_notebook->Bind( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &LAYER_WIDGET::OnTabChange, this );
574 
575  Layout();
576 }
577 
578 
580 {
581  delete m_IconProvider;
582 }
583 
584 
586 {
587  // size of m_LayerScrolledWindow --------------
588  wxArrayInt widths = m_LayersFlexGridSizer->GetColWidths();
589  int totWidth = 0;
590 
591  if( widths.GetCount() )
592  {
593  for( int i = 0; i < LYR_COLUMN_COUNT; ++i )
594  {
595  totWidth += widths[i] + m_LayersFlexGridSizer->GetHGap();
596  }
597  }
598 
599  // Account for the parent's frame:
600  totWidth += 15;
601 
602  /* The minimum height is a small size to properly force computation
603  * of the panel's scrollbars (otherwise it will assume it *has* all
604  * this space) */
605  unsigned totHeight = 32;
606 
607  wxSize layerz( totWidth, totHeight );
608 
609  layerz += m_LayerPanel->GetWindowBorderSize();
610 
611  // size of m_RenderScrolledWindow --------------
612  widths = m_RenderFlexGridSizer->GetColWidths();
613  totWidth = 0;
614 
615  if( widths.GetCount() )
616  {
617  for( int i = 0; i < RND_COLUMN_COUNT; ++i )
618  {
619  totWidth += widths[i] + m_RenderFlexGridSizer->GetHGap();
620  }
621  }
622 
623  // account for the parent's frame, this one has void space of 10 PLUS a border:
624  totWidth += 15;
625 
626  // For totHeight re-use the previous small one
627  wxSize renderz( totWidth, totHeight );
628 
629  renderz += m_RenderingPanel->GetWindowBorderSize();
630 
631  wxSize clientz( std::max(renderz.x,layerz.x), std::max(renderz.y,layerz.y) );
632 
633  return clientz;
634 }
635 
636 
638 {
639  int controlCount = m_LayersFlexGridSizer->GetChildren().GetCount();
640  return controlCount / LYR_COLUMN_COUNT;
641 }
642 
643 
645 {
646  int controlCount = m_RenderFlexGridSizer->GetChildren().GetCount();
647  return controlCount / RND_COLUMN_COUNT;
648 }
649 
650 
652 {
653  int nextRow = GetLayerRowCount();
654  insertLayerRow( nextRow, aRow );
655 }
656 
657 
659 {
660  m_LayersFlexGridSizer->Clear( true );
661 }
662 
663 
665 {
666  int nextRow = GetRenderRowCount();
667  insertRenderRow( nextRow, aRow );
668 }
669 
670 
672 {
673  m_RenderFlexGridSizer->Clear( true );
674 }
675 
676 
678 {
679  // enable the layer tab at index 0
680  m_notebook->SetSelection( 0 );
681 
682  INDICATOR_ICON* oldIndicator = (INDICATOR_ICON*) getLayerComp( m_CurrentRow, 0 );
683 
684  if( oldIndicator )
685  {
687  oldIndicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::DIMMED );
688  else
689  oldIndicator->SetIndicatorState( ROW_ICON_PROVIDER::STATE::OFF );
690  }
691 
692  INDICATOR_ICON* newIndicator = (INDICATOR_ICON*) getLayerComp( aRow, 0 );
693 
694  if( newIndicator )
695  {
697 
698  // Make sure the desired layer row is visible.
699  // It seems that as of 2.8.2, setting the focus does this.
700  // I don't expect the scrolling to be needed at all because
701  // the minimum window size may end up being established so that the
702  // scroll bars will not be visible.
703  getLayerComp( aRow, 1 )->SetFocus();
704  }
705 
706  m_CurrentRow = aRow;
707 
708  // give the focus back to the app.
709  passOnFocus();
710 }
711 
712 
714 {
715  int row = findLayerRow( aLayer );
716  SelectLayerRow( row );
717 }
718 
719 
721 {
722  wxWindow* w = getLayerComp( m_CurrentRow, 0 );
723 
724  if( w )
725  return getDecodedId( w->GetId() );
726 
727  return UNDEFINED_LAYER;
728 }
729 
730 
731 void LAYER_WIDGET::SetLayerVisible( LAYER_NUM aLayer, bool isVisible )
732 {
733  setLayerCheckbox( aLayer, isVisible );
734  OnLayerVisible( aLayer, isVisible );
735 }
736 
737 
738 void LAYER_WIDGET::setLayerCheckbox( LAYER_NUM aLayer, bool isVisible )
739 {
740  int row = findLayerRow( aLayer );
741 
742  if( row >= 0 )
743  {
744  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
745  wxASSERT( cb );
746  cb->SetValue( isVisible ); // does not fire an event
747  }
748 }
749 
750 
752 {
753  int row = findLayerRow( aLayer );
754 
755  if( row >= 0 )
756  {
757  wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
758  wxASSERT( cb );
759  return cb->GetValue();
760  }
761 
762  return false;
763 }
764 
765 
766 void LAYER_WIDGET::SetLayerColor( LAYER_NUM aLayer, const COLOR4D& aColor )
767 {
768  int row = findLayerRow( aLayer );
769 
770  if( row >= 0 )
771  {
772  int col = 1; // bitmap button is column 1
773  auto swatch = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
774  wxASSERT( swatch );
775 
776  swatch->SetSwatchColor( aColor, false );
777  }
778 }
779 
780 
782 {
783  int row = findLayerRow( aLayer );
784 
785  if( row >= 0 )
786  {
787  int col = 1; // bitmap button is column 1
788  auto swatch = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
789  wxASSERT( swatch );
790 
791  return swatch->GetSwatchColor();
792  }
793 
794  return COLOR4D::UNSPECIFIED; // it's caller fault, gave me a bad layer
795 }
796 
797 
798 void LAYER_WIDGET::SetRenderState( int aId, bool isSet )
799 {
800  int row = findRenderRow( aId );
801 
802  if( row >= 0 )
803  {
804  int col = 1; // checkbox is column 1
805  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
806  wxASSERT( cb );
807  cb->SetValue( isSet ); // does not fire an event
808  }
809 }
810 
811 
813 {
814  int row = findRenderRow( aId );
815 
816  if( row >= 0 )
817  {
818  int col = 1; // checkbox is column 1
819  wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
820  wxASSERT( cb );
821  return cb->GetValue();
822  }
823 
824  return false; // the value of a non-existent row
825 }
826 
827 
829 {
830  m_LayersFlexGridSizer->Layout();
831  m_RenderFlexGridSizer->Layout();
832  m_LayerPanel->Layout();
833  m_RenderingPanel->Layout();
834  FitInside();
835 }
836 
837 
839 {
840  int rowCount = GetLayerRowCount();
841 
842  for( int row = 0; row < rowCount ; row++ )
843  {
845 
846  if( indicator )
847  {
849 
850  if( row == m_CurrentRow )
852  else if( useAlternateBitmap( row ) )
853  state = ROW_ICON_PROVIDER::STATE::DIMMED;
854  else
855  state = ROW_ICON_PROVIDER::STATE::OFF;
856 
857  indicator->SetIndicatorState( state );
858  }
859  }
860 }
COLOR4D defaultColor
The default color for the row.
Definition: layer_widget.h:93
#define COLUMN_COLOR_LYRNAME
Definition: layer_widget.h:54
void OnLeftDownLayers(wxMouseEvent &event)
void SetIndicatorState(ICON_ID aIconId)
Set the row indicator to the given state.
int findLayerRow(LAYER_NUM aLayer) const
Return the row index that aLayer resides in, or -1 if not found.
#define LYR_COLUMN_COUNT
Layer tab column count.
Definition: layer_widget.h:48
int m_CurrentRow
selected row of layer list
Definition: layer_widget.h:469
virtual void OnLayerColorChange(int aLayer, const COLOR4D &aColor)=0
Notify client code about a layer color change.
void insertRenderRow(int aRow, const ROW &aSpec)
wxSize GetBestSize() const
Return the preferred minimum size, taking into consideration the dynamic content.
Icon provider for the "standard" row indicators, for example in layer selection lists.
KIGFX::COLOR4D GetSwatchColor() const
wxString m_smallestLayerString
Definition: layer_widget.h:474
Provide all the data needed to add a row to a LAYER_WIDGET.
Definition: layer_widget.h:84
#define ON
#define COLUMN_ALPHA_INDICATOR
Definition: layer_widget.h:55
bool spacer
if true, this row is a spacer
Definition: layer_widget.h:92
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
Definition: bitmap.cpp:257
void SetMinimumStringLength(const wxString &aString)
Set the string that is used for determining the requested size of the control.
bool GetRenderState(int aId)
Return the state of the checkbox associated with aId.
void UpdateLayouts()
virtual void OnLayerVisible(LAYER_NUM aLayer, bool isVisible, bool isFinal=true)=0
Notify client code about a layer visibility change.
wxNotebook * m_notebook
Definition: layer_widget.h:460
void OnTabChange(wxNotebookEvent &event)
bool changeable
if true, the state can be changed
Definition: layer_widget.h:91
static const wxEventType EVT_LAYER_COLOR_CHANGE
Definition: layer_widget.h:120
int LAYER_NUM
This can be replaced with int and removed.
Definition: layer_ids.h:40
wxScrolledWindow * m_RenderScrolledWindow
Definition: layer_widget.h:465
wxFlexGridSizer * m_LayersFlexGridSizer
Definition: layer_widget.h:463
virtual bool useAlternateBitmap(int aRow)
Definition: layer_widget.h:358
int findRenderRow(int aId) const
wxWindow * getLayerComp(int aRow, int aColumn) const
Return the component within the m_LayersFlexGridSizer at aRow and aCol or NULL if these parameters ar...
static void shrinkFont(wxWindow *aControl, int aPointSize)
Reduce the size of the wxFont associated with aControl.
void updateLayerRow(int aRow, const wxString &aName)
COLOR4D GetLayerColor(LAYER_NUM aLayer) const
Return the color of the layer ROW associated with aLayer id.
void ClearRenderRows()
Empty out the render rows.
#define RND_COLUMN_COUNT
Rendering tab column count.
Definition: layer_widget.h:49
wxFlexGridSizer * m_RenderFlexGridSizer
Definition: layer_widget.h:466
bool state
initial wxCheckBox state
Definition: layer_widget.h:89
virtual void OnRenderColorChange(int aId, const COLOR4D &aColor)=0
Notify client code whenever the user changes a rendering color.
void ClearLayerRows()
Empty out the layer rows.
wxString tooltip
if not empty, use this tooltip on row
Definition: layer_widget.h:90
This file contains miscellaneous commonly used macros and functions.
void OnRenderCheckBox(wxCommandEvent &event)
void OnLayerCheckBox(wxCommandEvent &event)
Handle the "is layer visible" checkbox and propagates the event to the client's notification function...
void AppendRenderRow(const ROW &aRow)
Append a new row in the render portion of the widget.
static int encodeId(int aColumn, int aId)
Allow saving a layer index within a control as its wxControl id.
COLOR4D color
COLOR4D::UNSPECIFIED if none.
Definition: layer_widget.h:88
void OnRightDownRender(wxMouseEvent &aEvent, COLOR_SWATCH *aColorSwatch, const wxString &aRenderName)
Notify 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:51
void setLayerCheckbox(LAYER_NUM aLayer, bool isVisible)
#define COLUMN_COLORBM
Definition: layer_widget.h:52
wxWindow * getRenderComp(int aRow, int aColumn) const
wxPanel * m_RenderingPanel
Definition: layer_widget.h:464
void AppendLayerRow(const ROW &aRow)
Append a new row in the layer portion of the widget.
void UpdateLayerIcons()
Update all layer manager icons (layers only).
wxScrolledWindow * m_LayerScrolledWindow
Definition: layer_widget.h:462
virtual void OnRenderEnable(int aId, bool isEnabled)=0
Notify client code whenever the user changes an rendering enable in one of the rendering checkboxes.
#define _(s)
void SelectLayerRow(int aRow)
Change the row selection in the layer list to the given row.
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
void SetLayerColor(LAYER_NUM aLayer, const COLOR4D &aColor)
Change the color of aLayer.
void OnRenderSwatchChanged(wxCommandEvent &aEvent)
Called when user has changed the swatch color of a render entry.
static LAYER_NUM getDecodedId(int aControlId)
Decode aControlId to original un-encoded value.
virtual ~LAYER_WIDGET()
wxWindow * m_FocusOwner
Definition: layer_widget.h:468
LAYER_WIDGET(wxWindow *aParent, wxWindow *aFocusOwner, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL)
int GetLayerRowCount() const
Return the number of rows in the layer tab.
A version of a wxStaticText control that will request a smaller size than the full string.
void passOnFocus()
Give away the keyboard focus up to the main parent window.
LAYER_NUM GetSelectedLayer()
Return the selected layer or -1 if none.
bool IsLayerVisible(LAYER_NUM aLayer)
Return the visible state of the layer ROW associated with aLayer id.
void OnRightDownLayer(wxMouseEvent &event, COLOR_SWATCH *aColorSwatch, const wxString &aLayerName)
Called when user right-clicks a layer.
#define COLUMN_COLOR_LYR_CB
Definition: layer_widget.h:53
wxString rowName
the prompt or layername
Definition: layer_widget.h:86
virtual COLOR4D getBackgroundLayerColor()
Subclasses can override this to provide accurate representation of transparent color swatches.
Definition: layer_widget.h:364
A simple color swatch of the kind used to set layer colors.
Definition: color_swatch.h:56
virtual void OnLayerRightClick(wxMenu &aMenu)=0
Notify client code about a layer being right-clicked.
STATE
< State constants to select the right icons
PCB background color.
Definition: layer_ids.h:215
void GetNewSwatchColor()
Prompt for a new colour, using the colour picker dialog.
int GetRenderRowCount() const
Return the number of rows in the render tab.
void insertLayerRow(int aRow, const ROW &aSpec)
Append or insert a new row in the layer portion of the widget.
void SetLayerVisible(LAYER_NUM aLayer, bool isVisible)
Set aLayer visible or not.
void OnLayerSwatchChanged(wxCommandEvent &aEvent)
Called when a user changes a swatch color.
virtual bool OnLayerSelect(int aLayer)=0
Notify client code whenever the user selects a different layer.
void SetRenderState(int aId, bool isSet)
Set the state of the checkbox associated with aId within the Render tab group of the widget.
void SelectLayer(LAYER_NUM aLayer)
Change the row selection in the layer list to aLayer provided.
int id
either a layer or "visible element" id
Definition: layer_widget.h:87
ROW_ICON_PROVIDER * m_IconProvider
Definition: layer_widget.h:472
void SetSwatchBackground(const KIGFX::COLOR4D &aBackground)
Set the swatch background color.
wxPanel * m_LayerPanel
Definition: layer_widget.h:461
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103