1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2010-2021 KiCad Developers, see change_log.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #ifndef LAYERWIDGET_H_
26 #define LAYERWIDGET_H_
27 
28 #include <wx/intl.h>
29 #include <wx/statbmp.h>
30 #include <wx/string.h>
31 #include <wx/aui/auibook.h>
32 #include <wx/notebook.h>
33 #include <wx/sizer.h>
34 #include <wx/gdicmn.h>
35 #include <wx/scrolwin.h>
36 #include <wx/font.h>
37 #include <wx/colour.h>
38 #include <wx/settings.h>
39 #include <wx/panel.h>
40 #include <wx/bitmap.h>
41 #include <wx/image.h>
42 #include <wx/icon.h>
43 #include <layer_ids.h>
44 #include <gal/color4d.h>
45 #include <widgets/color_swatch.h>
46 #include <widgets/indicator_icon.h>
47 
48 #define LYR_COLUMN_COUNT        5           ///< Layer tab column count
49 #define RND_COLUMN_COUNT        2           ///< Rendering tab column count
50 
51 #define COLUMN_ICON_ACTIVE 0
52 #define COLUMN_COLORBM 1
53 #define COLUMN_COLOR_LYR_CB 2
54 #define COLUMN_COLOR_LYRNAME 3
55 #define COLUMN_ALPHA_INDICATOR 4
56 
57 using KIGFX::COLOR4D;
58 
59 /**
60  * Manage a list of layers with the notion of a "current" layer, and layer specific visibility
61  * control.
62  *
63  * You must derive from it to use it so you can implement the abstract functions which receive
64  * the events.  Each layer is given its own color, and that color can be changed within the UI
65  * provided here.  This widget knows nothing of the client code, meaning it has no knowledge of
66  * a BOARD or anything.  To use it you must derive from this class and implement the abstract
67  * functions:
68  * <p> void OnLayerColorChange( int aLayer, int aColor );
69  * <p> bool OnLayerSelect( int aLayer );
70  * <p> void OnLayerVisible( int aLayer, bool isVisible );
71  * <p> void OnRenderColorChange( int id, int aColor );
72  * <p> void OnRenderEnable( int id, bool isEnabled );
73  *
74  * @note Even if designed toward layers, it is used to contain other stuff, too (the second page
75  * in pcbnew contains render items, for example).
76  */
77 class LAYER_WIDGET : public wxPanel
78 {
79 public:
80     /**
81      * Provide all the data needed to add a row to a LAYER_WIDGET.  This is
82      * part of the public API for a LAYER_WIDGET.
83      */
84     struct ROW
85     {
86         wxString    rowName;      ///< the prompt or layername
87         int         id;           ///< either a layer or "visible element" id
88         COLOR4D     color;        ///< COLOR4D::UNSPECIFIED if none.
89         bool        state;        ///< initial wxCheckBox state
90         wxString    tooltip;      ///< if not empty, use this tooltip on row
91         bool        changeable;   ///< if true, the state can be changed
92         bool        spacer;       ///< if true, this row is a spacer
93         COLOR4D     defaultColor; ///< The default color for the row
94 
95         ROW( const wxString& aRowName, int aId, const COLOR4D& aColor = COLOR4D::UNSPECIFIED,
96              const wxString& aTooltip = wxEmptyString, bool aState = true,
97              bool aChangeable = true, const COLOR4D& aDefaultColor = COLOR4D::UNSPECIFIED )
98         {
99             rowName = aRowName;
100             id      = aId;
101             color   = aColor;
102             state   = aState;
103             tooltip = aTooltip;
104             changeable = aChangeable;
105             spacer = false;
106             defaultColor = aDefaultColor;
107         }
108 
ROWROW109         ROW()
110         {
111             id = 0;
112             color = COLOR4D::UNSPECIFIED;
113             state = true;
114             changeable = true;
115             spacer = true;
116             defaultColor = COLOR4D::UNSPECIFIED;
117         }
118     };
119 
120     static const wxEventType EVT_LAYER_COLOR_CHANGE;
121 
122 public:
123 
124     /**
125      * @param aParent is the parent window.
126      * @param aFocusOwner is the window that should be sent the focus after.
127      * @param id is the wxWindow id ( default = wxID_ANY).
128      * @param pos is the window position.
129      * @param size is the window size.
130      * @param style is the window style.
131      */
132     LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, wxWindowID id = wxID_ANY,
133                   const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
134                   long style = wxTAB_TRAVERSAL );
135 
136     virtual ~LAYER_WIDGET();
137 
138     /**
139      * Set the string that is used for determining the smallest string displayed in the layer's tab.
140      */
SetSmallestLayerString(const wxString & aString)141     void SetSmallestLayerString( const wxString& aString )
142     {
143         m_smallestLayerString = aString;
144     }
145 
146     /**
147      * Return the preferred minimum size, taking into consideration the dynamic content.
148      *
149      * Nothing in wxWidgets was reliable enough so this overrides one of their functions.
150      */
151     wxSize GetBestSize() const;
152 
153     /**
154      * Return the number of rows in the layer tab.
155      */
156     int GetLayerRowCount() const;
157 
158     /**
159      * Return the number of rows in the render tab.
160      */
161     int GetRenderRowCount() const;
162 
163     /**
164      * Append a new row in the layer portion of the widget.
165      *
166      * The user must ensure that ROW::id is unique for all existing rows on Windows.
167      */
168     void AppendLayerRow( const ROW& aRow );
169 
170     /**
171      * Append new rows in the layer portion of the widget.
172      *
173      * The user must ensure that ROW::id is unique for all existing rows on Windows.
174      */
AppendLayerRows(const ROW * aRowsArray,int aRowCount)175     void AppendLayerRows( const ROW* aRowsArray, int aRowCount )
176     {
177         for( int row=0;  row<aRowCount;  ++row )
178             AppendLayerRow( aRowsArray[row] );
179 
180         UpdateLayouts();
181     }
182 
183     /**
184      * Empty out the layer rows.
185      */
186     void ClearLayerRows();
187 
188     /**
189      * Append a new row in the render portion of the widget.
190      *
191      * The user must ensure that ROW::id is unique for all existing rows on Windows.
192      */
193     void AppendRenderRow( const ROW& aRow );
194 
195     /**
196      * Append new rows in the render portion of the widget.
197      *
198      * The user must ensure that ROW::id is unique for all existing rows on Windows.
199      */
AppendRenderRows(const ROW * aRowsArray,int aRowCount)200     void AppendRenderRows( const ROW* aRowsArray, int aRowCount )
201     {
202         for( int row=0;  row<aRowCount;  ++row )
203             AppendRenderRow( aRowsArray[row] );
204 
205         UpdateLayouts();
206     }
207 
208     /**
209      * Empty out the render rows.
210      */
211     void ClearRenderRows();
212 
213     /**
214      * Change the row selection in the layer list to the given row.
215      */
216     void SelectLayerRow( int aRow );
217 
218     /**
219      * Change the row selection in the layer list to \a aLayer provided.
220      */
221     void SelectLayer( LAYER_NUM aLayer );
222 
223     /**
224      * Return the selected layer or -1 if none.
225      */
226     LAYER_NUM GetSelectedLayer();
227 
228     /**
229      * Set \a aLayer visible or not.  This does not invoke OnLayerVisible().
230      */
231     void SetLayerVisible( LAYER_NUM aLayer, bool isVisible );
232 
233     /**
234      * Return the visible state of the layer ROW associated with \a aLayer id.
235      */
236     bool IsLayerVisible( LAYER_NUM aLayer );
237 
238     /**
239      * Change the color of \a aLayer
240      */
241     void SetLayerColor( LAYER_NUM aLayer, const COLOR4D& aColor );
242 
243     /**
244      * Return the color of the layer ROW associated with \a aLayer id.
245      */
246     COLOR4D GetLayerColor( LAYER_NUM aLayer ) const;
247 
248     /**
249      * Set the state of the checkbox associated with \a aId within the Render tab group of the
250      * widget.
251      *
252      * This does not fire an event, i.e. does not invoke OnRenderEnable().
253      *
254      * @param aId is the same unique id used when adding a ROW to the Render tab.
255      * @param isSet is the new checkbox state.
256      */
257     void SetRenderState( int aId, bool isSet );
258 
259     /**
260      * Return the state of the checkbox associated with \a aId.
261      *
262      * @return true if checked, else false.
263      */
264     bool GetRenderState( int aId );
265 
266     void UpdateLayouts();
267 
268     /**
269      * Update all layer manager icons (layers only).
270      *
271      * Useful when loading a file or clearing a layer because they change,
272      * and the indicator arrow icon needs to be updated
273      */
274     void UpdateLayerIcons();
275 
276 /*  did not help:
277     void Freeze()
278     {
279         LAYER_PANEL_BASE::Freeze();
280         m_LayerScrolledWindow->Freeze();
281         m_RenderScrolledWindow->Freeze();
282     }
283 
284     void Thaw()
285     {
286         m_RenderScrolledWindow->Thaw();
287         m_LayerScrolledWindow->Thaw();
288         LAYER_PANEL_BASE::Thaw();
289     }
290 */
291 
292     //-----<abstract functions>-------------------------------------------
293 
294     /**
295      * Notify client code about a layer color change.
296      *
297      * Derived objects will handle this accordingly.
298      *
299      * @param aLayer is the board layer to change.
300      * @param aColor is the new color.
301      */
302     virtual void OnLayerColorChange( int aLayer, const COLOR4D& aColor ) = 0;
303 
304     /**
305      * Notify client code whenever the user selects a different layer.
306      *
307      * Derived classes will handle this accordingly, and can deny the change by returning false.
308      *
309      * @param aLayer is the board layer to select.
310      */
311     virtual bool OnLayerSelect( int aLayer ) = 0;
312 
313     /**
314      * Notify client code about a layer visibility change.
315      *
316      * @param aLayer is the board layer to select.
317      * @param isVisible is the new visible state.
318      * @param isFinal is true when this is the last of potentially several such calls, and can
319      *                be used to decide when to update the screen only one time instead of
320      *                several times in the midst of a multiple layer change.
321      */
322     virtual void OnLayerVisible( LAYER_NUM aLayer, bool isVisible, bool isFinal = true ) = 0;
323 
324     /**
325      * Notify client code about a layer being right-clicked.
326      *
327      * @param aMenu is the right-click menu containing layer-scoped options.
328      */
329     virtual void OnLayerRightClick( wxMenu& aMenu ) = 0;
330 
331     /**
332      * Notify client code whenever the user changes a rendering color.
333      *
334      * @param aId is the same id that was established in a Rendering row via the AddRenderRow()
335      *            function.
336      * @param aColor is the new color.
337      */
338     virtual void OnRenderColorChange( int aId, const COLOR4D& aColor ) = 0;
339 
340     /**
341      * Notify client code whenever the user changes an rendering enable in one of the rendering
342      * checkboxes.
343      *
344      * @param aId is the same id that was established in a Rendering row via the AddRenderRow()
345      *            function.
346      * @param isEnabled is the state of the checkbox, true if checked.
347      */
348     virtual void OnRenderEnable( int aId, bool isEnabled ) = 0;
349 
350 protected:
351     /**
352      * @return true if bitmaps shown in Render layer list
353      * are alternate bitmaps, or false if they are "normal" bitmaps
354      * This is a virtual function because Pcbnew uses normal bitmaps
355      * but GerbView uses both bitmaps
356      * (alternate bitmaps to show layers in use, normal for others)
357      */
useAlternateBitmap(int aRow)358     virtual bool useAlternateBitmap(int aRow) { return false; }
359 
360     /**
361      * Subclasses can override this to provide accurate representation
362      * of transparent color swatches.
363      */
getBackgroundLayerColor()364     virtual COLOR4D getBackgroundLayerColor() { return COLOR4D::BLACK; }
365 
366     /**
367      * Allow saving a layer index within a control as its wxControl id.
368      *
369      * To do so in a way that all child wxControl ids within a wxWindow are unique, since this
370      * is required by Windows.
371      *
372      * @see getDecodedId()
373      */
374     static int encodeId( int aColumn, int aId );
375 
376     /**
377      * Decode \a aControlId to original un-encoded value.
378      *
379      * This holds if encodedId was called with a LAYER_NUM (this box is used for other things
380      * than layers, too).
381      */
382     static LAYER_NUM getDecodedId( int aControlId );
383 
384     void OnLeftDownLayers( wxMouseEvent& event );
385 
386     /**
387      * Called when user right-clicks a layer.
388      */
389     void OnRightDownLayer( wxMouseEvent& event, COLOR_SWATCH* aColorSwatch,
390                            const wxString& aLayerName );
391 
392     /**
393      * Called when a user changes a swatch color.
394      */
395     void OnLayerSwatchChanged( wxCommandEvent& aEvent );
396 
397     /**
398      * Handle the "is layer visible" checkbox and propagates the event to the client's
399      * notification function.
400      */
401     void OnLayerCheckBox( wxCommandEvent& event );
402 
403     /**
404      * Notify when user right-clicks a render option.
405      */
406     void OnRightDownRender( wxMouseEvent& aEvent, COLOR_SWATCH* aColorSwatch,
407                             const wxString& aRenderName );
408 
409     /**
410      * Called when user has changed the swatch color of a render entry.
411      */
412     void OnRenderSwatchChanged( wxCommandEvent& aEvent );
413 
414     void OnRenderCheckBox( wxCommandEvent& event );
415 
416     void OnTabChange( wxNotebookEvent& event );
417 
418 
419     /**
420      * Return the component within the m_LayersFlexGridSizer at @a aRow and @a aCol
421      * or NULL if these parameters are out of range.
422      *
423      * @param aRow is the row index
424      * @param aColumn is the column
425      * @return the component installed within the sizer at given grid coordinate.
426      */
427     wxWindow* getLayerComp( int aRow, int aColumn ) const;
428     wxWindow* getRenderComp( int aRow, int aColumn ) const;
429 
430     /**
431      * Return the row index that \a aLayer resides in, or -1 if not found.
432      */
433     int findLayerRow( LAYER_NUM aLayer ) const;
434     int findRenderRow( int aId ) const;
435 
436     /**
437      * Append or insert a new row in the layer portion of the widget.
438      */
439     void insertLayerRow( int aRow, const ROW& aSpec );
440 
441     void insertRenderRow( int aRow, const ROW& aSpec );
442 
443     void setLayerCheckbox( LAYER_NUM aLayer, bool isVisible );
444 
445     void updateLayerRow( int aRow, const wxString& aName );
446 
447     /**
448      * Give away the keyboard focus up to the main parent window.
449      */
450     void passOnFocus();
451 
452     // popup menu ids.
453     enum POPUP_ID
454     {
455         ID_CHANGE_LAYER_COLOR = wxID_HIGHEST,
456         ID_CHANGE_RENDER_COLOR,
457         ID_LAST_VALUE
458     };
459 
460     wxNotebook*         m_notebook;
461     wxPanel*            m_LayerPanel;
462     wxScrolledWindow*   m_LayerScrolledWindow;
463     wxFlexGridSizer*    m_LayersFlexGridSizer;
464     wxPanel*            m_RenderingPanel;
465     wxScrolledWindow*   m_RenderScrolledWindow;
466     wxFlexGridSizer*    m_RenderFlexGridSizer;
467 
468     wxWindow*           m_FocusOwner;
469     int                 m_CurrentRow;           ///< selected row of layer list
470     int                 m_PointSize;
471 
472     ROW_ICON_PROVIDER*  m_IconProvider;
473 
474     wxString            m_smallestLayerString;
475 };
476 
477 #endif // LAYERWIDGET_H_
478