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