layer_widget.cpp 27.4 KB
Newer Older
dickelbeck's avatar
dickelbeck committed
1 2

/*
3
 * This program source code file is part of KiCad, a free EDA CAD application.
dickelbeck's avatar
dickelbeck committed
4 5
 *
 * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6
 * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
dickelbeck's avatar
dickelbeck committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */



/*  This source module implements the layer visibility and selection widget
dickelbeck's avatar
dickelbeck committed
29
    @todo make the bitmapbutton a staticbitmap, and make dependent on the point size.
dickelbeck's avatar
dickelbeck committed
30 31 32
*/


33
//#define STAND_ALONE     1   // define to enable test program for LAYER_WIDGET
dickelbeck's avatar
dickelbeck committed
34

dickelbeck's avatar
dickelbeck committed
35

36
#include <layer_widget.h>
37

38 39 40
#include <macros.h>
#include <common.h>
#include <colors.h>
41
#include <wx/colour.h>
dickelbeck's avatar
dickelbeck committed
42

43 44 45
#define BUTT_SIZE_X             20
#define BUTT_SIZE_Y             18
#define BUTT_VOID               4
46

47
/* XPM
Dick Hollenbeck's avatar
Dick Hollenbeck committed
48
 * This bitmap is used for not selected layers
49
 */
dickelbeck's avatar
dickelbeck committed
50
static const char * clear_xpm[] = {
51
"10 14 1 1",
dickelbeck's avatar
dickelbeck committed
52
" 	c None",
53 54 55 56 57 58 59 60 61 62 63 64 65 66
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          ",
"          "};
dickelbeck's avatar
dickelbeck committed
67

68 69
/* XPM
 * This bitmap can be used to show a not selected layer
70
 * with special property (mainly not selected layers not in use in GerbView)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 */
static const char * clear_alternate_xpm[] = {
"10 14 4 1",
"       c None",
"X      c #008080",
"o      c GREEN",
"O      c #00B080",
"          ",
"          ",
"          ",
"          ",
"    X     ",
"   XXX    ",
"  XXXXX   ",
" OOOOOOO  ",
"  ooooo   ",
"   ooo    ",
"    o     ",
"          ",
"          ",
"          "};


/* XPM
 * This bitmap  is used for a normale selected layer
 */
dickelbeck's avatar
dickelbeck committed
97
static const char * rightarrow_xpm[] = {
98
"10 14 4 1",
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
"       c None",
"X      c #8080ff",
"o      c BLUE",
"O      c gray56",
"  X       ",
"  XX      ",
"  XXX     ",
"  XXXX    ",
"  XXXXX   ",
"  XXXXXX  ",
"  XXXXXXX ",
"  oooooooO",
"  ooooooO ",
"  oooooO  ",
"  ooooO   ",
"  oooO    ",
"  ooO     ",
"  oO      "};
dickelbeck's avatar
dickelbeck committed
117

118 119
/* XPM
 * This bitmap can be used to show the selected layer
120
 * with special property (mainly a layer in use in GerbView)
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
 */
static const char * rightarrow_alternate_xpm[] = {
"10 14 5 1",
"       c None",
".      c #00B000",
"X      c #8080ff",
"o      c BLUE",
"O      c gray56",
"..X       ",
"..XX      ",
"..XXX     ",
"..XXXX    ",
"..XXXXX   ",
"..XXXXXX  ",
"..XXXXXXX ",
"..oooooooO",
"..ooooooO ",
"..oooooO  ",
"..ooooO   ",
"..oooO    ",
"..ooO     ",
"..oO      "};

dickelbeck's avatar
dickelbeck committed
144 145 146 147 148 149

/**
 * Function makeColorTxt
 * returns a string containing the numeric value of the color.
 * in a form like 0x00000000.  (Color is currently an index, not RGB).
 */
150
static wxString makeColorTxt( EDA_COLOR_T aColor )
dickelbeck's avatar
dickelbeck committed
151
{
152 153 154
    wxString txt;
    txt.Printf( wxT("0x%08x"), aColor );
    return txt;
dickelbeck's avatar
dickelbeck committed
155 156
}

dickelbeck's avatar
dickelbeck committed
157

158 159 160 161
/**
 * Function shrinkFont
 * reduces the size of the wxFont associated with \a aControl
 */
dickelbeck's avatar
dickelbeck committed
162
static void shrinkFont( wxWindow* aControl, int aPointSize )
163 164
{
    wxFont font = aControl->GetFont();
dickelbeck's avatar
dickelbeck committed
165 166 167 168 169 170 171 172 173 174 175 176
    font.SetPointSize( aPointSize );
    aControl->SetFont( font );              // need this?
}


int LAYER_WIDGET::encodeId( int aColumn, int aId )
{
    int id = aId * LYR_COLUMN_COUNT + aColumn;
    return id;
}


177
LAYER_NUM LAYER_WIDGET::getDecodedId( int aControlId )
dickelbeck's avatar
dickelbeck committed
178 179 180
{
    int id = aControlId / LYR_COLUMN_COUNT;    // rounding is OK.
    return id;
181 182
}

dickelbeck's avatar
dickelbeck committed
183

184
wxBitmap LAYER_WIDGET::makeBitmap( EDA_COLOR_T aColor )
dickelbeck's avatar
dickelbeck committed
185
{
186 187 188 189 190
    // the bitmap will be BUTT_VOID*2 pixels smaller than the button, leaving a
    // border of BUTT_VOID pixels on each side.
    wxBitmap    bitmap( BUTT_SIZE_X - 2 * BUTT_VOID, BUTT_SIZE_Y - 2 * BUTT_VOID );
    wxBrush     brush;
    wxMemoryDC  iconDC;
dickelbeck's avatar
dickelbeck committed
191

192
    iconDC.SelectObject( bitmap );
dickelbeck's avatar
dickelbeck committed
193

194
    brush.SetColour( MakeColour( aColor ) );
195 196 197 198

#if wxCHECK_VERSION( 3, 0, 0 )
    brush.SetStyle( wxBRUSHSTYLE_SOLID );
#else
199
    brush.SetStyle( wxSOLID );
200 201
#endif

202
    iconDC.SetBrush( brush );
dickelbeck's avatar
dickelbeck committed
203

204
    iconDC.DrawRectangle( 0, 0, BUTT_SIZE_X - 2 * BUTT_VOID, BUTT_SIZE_Y - 2 * BUTT_VOID );
dickelbeck's avatar
dickelbeck committed
205

206 207
    return bitmap;
}
dickelbeck's avatar
dickelbeck committed
208

209

210
wxBitmapButton* LAYER_WIDGET::makeColorButton( wxWindow* aParent, EDA_COLOR_T aColor, int aID )
211 212 213 214
{
    // dynamically make a wxBitMap and brush it with the appropriate color,
    // then create a wxBitmapButton from it.
    wxBitmap bitmap = makeBitmap( aColor );
dickelbeck's avatar
dickelbeck committed
215

216
#ifndef __WXMAC__
217 218
    wxBitmapButton* ret = new wxBitmapButton( aParent, aID, bitmap,
        wxDefaultPosition, wxSize(BUTT_SIZE_X, BUTT_SIZE_Y), wxBORDER_RAISED );
219 220 221 222
#else
    wxBitmapButton* ret = new wxBitmapButton( aParent, aID, bitmap,
        wxDefaultPosition, wxSize(BUTT_SIZE_X, BUTT_SIZE_Y));
#endif
223 224 225 226
    // save the color value in the name, no where else to put it.
    ret->SetName( makeColorTxt( aColor ) );
    return ret;
}
dickelbeck's avatar
dickelbeck committed
227

228

229 230 231
void LAYER_WIDGET::OnLeftDownLayers( wxMouseEvent& event )
{
    int row;
232
    LAYER_NUM layer;
233

234
    wxWindow* eventSource = (wxWindow*) event.GetEventObject();
235

236 237 238
    // if mouse event is coming from the m_LayerScrolledWindow and not one
    // of its children, we have to find the row manually based on y coord.
    if( eventSource == m_LayerScrolledWindow )
239
    {
240
        int y = event.GetY();
241

242
        wxArrayInt heights = m_LayersFlexGridSizer->GetRowHeights();
dickelbeck's avatar
dickelbeck committed
243

244
        int height = 0;
dickelbeck's avatar
dickelbeck committed
245

246 247
        int rowCount = GetLayerRowCount();
        for( row = 0;  row<rowCount;  ++row )
dickelbeck's avatar
dickelbeck committed
248
        {
249 250
            if( y < height + heights[row] )
                break;
dickelbeck's avatar
dickelbeck committed
251

252
            height += heights[row];
dickelbeck's avatar
dickelbeck committed
253
        }
dickelbeck's avatar
dickelbeck committed
254

255 256
        if( row >= rowCount )
            row = rowCount - 1;
dickelbeck's avatar
dickelbeck committed
257

258
        layer = getDecodedId( getLayerComp( row, 0 )->GetId() );
dickelbeck's avatar
dickelbeck committed
259
    }
dickelbeck's avatar
dickelbeck committed
260

261
    else
dickelbeck's avatar
dickelbeck committed
262
    {
263 264
        // all nested controls on a given row will have their ID encoded with
        // encodeId(), and the corresponding decoding is getDecodedId()
dickelbeck's avatar
dickelbeck committed
265 266 267
        int id = eventSource->GetId();
        layer  = getDecodedId( id );
        row    = findLayerRow( layer );
268
    }
269

dickelbeck's avatar
dickelbeck committed
270
    if( OnLayerSelect( layer ) )    // if client allows this change.
271
        SelectLayerRow( row );
272 273

    passOnFocus();
274
}
275

276

277 278 279
void LAYER_WIDGET::OnMiddleDownLayerColor( wxMouseEvent& event )
{
    wxBitmapButton* eventSource = (wxBitmapButton*) event.GetEventObject();
280

281
    wxString colorTxt = eventSource->GetName();
282

283 284
    EDA_COLOR_T oldColor = ColorFromInt( strtoul( TO_UTF8(colorTxt), NULL, 0 ) );
    EDA_COLOR_T newColor = DisplayColorFrame( this, oldColor );
dickelbeck's avatar
dickelbeck committed
285

286 287 288
    if( newColor >= 0 )
    {
        eventSource->SetName( makeColorTxt( newColor ) );
dickelbeck's avatar
dickelbeck committed
289

290 291 292
        wxBitmap bm = makeBitmap( newColor );
        eventSource->SetBitmapLabel( bm );

293
        LAYER_NUM layer = getDecodedId( eventSource->GetId() );
294 295 296

        // tell the client code.
        OnLayerColorChange( layer, newColor );
dickelbeck's avatar
dickelbeck committed
297
    }
298 299

    passOnFocus();
300
}
dickelbeck's avatar
dickelbeck committed
301

dickelbeck's avatar
dickelbeck committed
302

303 304 305
void LAYER_WIDGET::OnLayerCheckBox( wxCommandEvent& event )
{
    wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
306
    LAYER_NUM layer = getDecodedId( eventSource->GetId() );
307
    OnLayerVisible( layer, eventSource->IsChecked() );
308
    passOnFocus();
309
}
dickelbeck's avatar
dickelbeck committed
310 311


312 313 314
void LAYER_WIDGET::OnMiddleDownRenderColor( wxMouseEvent& event )
{
    wxBitmapButton* eventSource = (wxBitmapButton*) event.GetEventObject();
dickelbeck's avatar
dickelbeck committed
315

316
    wxString colorTxt = eventSource->GetName();
dickelbeck's avatar
dickelbeck committed
317

318 319
    EDA_COLOR_T oldColor = ColorFromInt( strtoul( TO_UTF8(colorTxt), NULL, 0 ) );
    EDA_COLOR_T newColor = DisplayColorFrame( this, oldColor );
dickelbeck's avatar
dickelbeck committed
320

321 322 323
    if( newColor >= 0 )
    {
        eventSource->SetName( makeColorTxt( newColor ) );
dickelbeck's avatar
dickelbeck committed
324

325 326
        wxBitmap bm = makeBitmap( newColor );
        eventSource->SetBitmapLabel( bm );
dickelbeck's avatar
dickelbeck committed
327

328
        LAYER_NUM id = getDecodedId( eventSource->GetId() );
dickelbeck's avatar
dickelbeck committed
329

330 331
        // tell the client code.
        OnRenderColorChange( id, newColor );
dickelbeck's avatar
dickelbeck committed
332
    }
333
    passOnFocus();
334
}
dickelbeck's avatar
dickelbeck committed
335

336

337 338 339
void LAYER_WIDGET::OnRenderCheckBox( wxCommandEvent& event )
{
    wxCheckBox* eventSource = (wxCheckBox*) event.GetEventObject();
340
    LAYER_NUM id = getDecodedId( eventSource->GetId() );
341
    OnRenderEnable( id, eventSource->IsChecked() );
342
    passOnFocus();
343
}
dickelbeck's avatar
dickelbeck committed
344 345


346 347
void LAYER_WIDGET::OnTabChange( wxNotebookEvent& event )
{
348 349 350 351
//    wxFocusEvent    event( wxEVT_SET_FOCUS );
//    m_FocusOwner->AddPendingEvent( event );

    passOnFocus();      // does not work in this context, probably because we have receive control here too early.
352 353 354
}


355
wxWindow* LAYER_WIDGET::getLayerComp( int aRow, int aColumn ) const
356
{
357 358
    unsigned ndx = aRow * LYR_COLUMN_COUNT + aColumn;
    if( ndx < m_LayersFlexGridSizer->GetChildren().GetCount() )
359
        return m_LayersFlexGridSizer->GetChildren()[ndx]->GetWindow();
360 361
    return NULL;
}
dickelbeck's avatar
dickelbeck committed
362

363

364
int LAYER_WIDGET::findLayerRow( LAYER_NUM aLayer ) const
365 366 367
{
    int count = GetLayerRowCount();
    for( int row=0;  row<count;  ++row )
dickelbeck's avatar
dickelbeck committed
368
    {
369
        // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
370
        wxWindow* w = getLayerComp( row, 0 );
371
        wxASSERT( w );
dickelbeck's avatar
dickelbeck committed
372

373 374 375 376 377 378 379
        if( aLayer == getDecodedId( w->GetId() ))
            return row;
    }
    return -1;
}


380
wxWindow* LAYER_WIDGET::getRenderComp( int aRow, int aColumn ) const
381
{
382 383 384
    int ndx = aRow * RND_COLUMN_COUNT + aColumn;
    if( (unsigned) ndx < m_RenderFlexGridSizer->GetChildren().GetCount() )
        return m_RenderFlexGridSizer->GetChildren()[ndx]->GetWindow();
385 386 387 388
    return NULL;
}


389
int LAYER_WIDGET::findRenderRow( int aId ) const
390 391 392 393 394
{
    int count = GetRenderRowCount();
    for( int row=0;  row<count;  ++row )
    {
        // column 0 in the layer scroll window has a wxStaticBitmap, get its ID.
395
        wxWindow* w = getRenderComp( row, 0 );
396 397 398
        wxASSERT( w );

        if( aId == getDecodedId( w->GetId() ))
399 400 401 402
            return row;
    }
    return -1;
}
dickelbeck's avatar
dickelbeck committed
403

404

405 406
void LAYER_WIDGET::insertLayerRow( int aRow, const ROW& aSpec )
{
407
    wxASSERT( aRow >= 0 );
408 409 410 411 412 413 414 415

    int         col;
    int         index = aRow * LYR_COLUMN_COUNT;
    const int   flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;

    // column 0
    col = 0;
    wxStaticBitmap* sbm = new wxStaticBitmap( m_LayerScrolledWindow, encodeId( col, aSpec.id ),
416 417
                            useAlternateBitmap(aRow) ? *m_BlankAlternateBitmap : *m_BlankBitmap,
                            wxDefaultPosition, m_BitmapSize );
418
    sbm->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnLeftDownLayers ), NULL, this );
419
    m_LayersFlexGridSizer->wxSizer::Insert( index+col, sbm, 0, flags );
420

421 422
    // column 1 (COLUMN_COLORBM)
    col = COLUMN_COLORBM;
423 424 425 426
    wxBitmapButton* bmb = makeColorButton( m_LayerScrolledWindow, aSpec.color, encodeId( col, aSpec.id ) );
    bmb->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnLeftDownLayers ), NULL, this );
    bmb->Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnMiddleDownLayerColor ), NULL, this );
    bmb->SetToolTip( _("Left click to select, middle click for color change, right click for menu" ) );
427
    m_LayersFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
428

429 430
    // column 2 (COLUMN_COLOR_LYR_CB)
    col = COLUMN_COLOR_LYR_CB;
431 432 433 434
    wxCheckBox* cb = new wxCheckBox( m_LayerScrolledWindow, encodeId( col, aSpec.id ), wxEmptyString );
    cb->SetValue( aSpec.state );
    cb->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( LAYER_WIDGET::OnLayerCheckBox ), NULL, this );
    cb->SetToolTip( _( "Enable this for visibility" ) );
435
    m_LayersFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
436

437 438
    // column 3 (COLUMN_COLOR_LYRNAME)
    col = COLUMN_COLOR_LYRNAME;
439 440 441 442 443
    wxStaticText* st = new wxStaticText( m_LayerScrolledWindow, encodeId( col, aSpec.id ), aSpec.rowName );
    shrinkFont( st, m_PointSize );
    st->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnLeftDownLayers ), NULL, this );
    st->SetToolTip( aSpec.tooltip );
    m_LayersFlexGridSizer->wxSizer::Insert( index+col, st, 0, flags );
444
}
dickelbeck's avatar
dickelbeck committed
445

446

447 448
void LAYER_WIDGET::insertRenderRow( int aRow, const ROW& aSpec )
{
449
    wxASSERT( aRow >= 0 );
dickelbeck's avatar
dickelbeck committed
450

451 452 453
    int         col;
    int         index = aRow * RND_COLUMN_COUNT;
    const int   flags = wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT;
dickelbeck's avatar
dickelbeck committed
454

455 456 457 458
    // column 0
    col = 0;
    if( aSpec.color != -1 )
    {
dickelbeck's avatar
dickelbeck committed
459 460
        wxBitmapButton* bmb = makeColorButton( m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ) );
        bmb->Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnMiddleDownRenderColor ), NULL, this );
461
        bmb->SetToolTip( _( "Middle click for color change" ) );
462
        m_RenderFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
463 464 465

        // could add a left click handler on the color button that toggles checkbox.
    }
466
    else    // == -1, no color selection wanted
467 468
    {
        // need a place holder within the sizer to keep grid full.
469
        wxPanel* invisible = new wxPanel( m_RenderScrolledWindow, encodeId( col, aSpec.id ) );
470
        m_RenderFlexGridSizer->wxSizer::Insert( index+col, invisible, 0, flags );
dickelbeck's avatar
dickelbeck committed
471 472
    }

473 474 475 476
    // column 1
    col = 1;
    wxCheckBox* cb = new wxCheckBox( m_RenderScrolledWindow, encodeId( col, aSpec.id ),
                        aSpec.rowName, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT );
dickelbeck's avatar
dickelbeck committed
477
    shrinkFont( cb, m_PointSize );
478
    cb->SetValue( aSpec.state );
479 480 481
    cb->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED,
        wxCommandEventHandler( LAYER_WIDGET::OnRenderCheckBox ), NULL, this );
    cb->SetToolTip( aSpec.tooltip );
482
    m_RenderFlexGridSizer->wxSizer::Insert( index+col, cb, 0, flags );
483
}
dickelbeck's avatar
dickelbeck committed
484

dickelbeck's avatar
dickelbeck committed
485

486 487
void LAYER_WIDGET::passOnFocus()
{
488
    m_FocusOwner->SetFocus();
489 490 491
}


492
//-----<public>-------------------------------------------------------
dickelbeck's avatar
dickelbeck committed
493

dickelbeck's avatar
dickelbeck committed
494 495 496
LAYER_WIDGET::LAYER_WIDGET( wxWindow* aParent, wxWindow* aFocusOwner, int aPointSize,
        wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) :
    wxPanel( aParent, id, pos, size, style )
497
{
498
    wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL );
dickelbeck's avatar
dickelbeck committed
499 500 501 502

    m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP );

    wxFont font = m_notebook->GetFont();
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

    if( aPointSize == -1 )
    {
        m_PointSize = font.GetPointSize();
    }
    else
    {
        m_PointSize = aPointSize;

        // change the font size on the notebook's tabs to match aPointSize
        font.SetPointSize( aPointSize );
        m_notebook->SetFont( font );
        m_notebook->SetNormalFont( font );
        m_notebook->SetSelectedFont( font );
        m_notebook->SetMeasuringFont( font );
    }
dickelbeck's avatar
dickelbeck committed
519 520 521 522 523 524 525 526 527 528

    m_LayerPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );

    wxBoxSizer* bSizer3;
    bSizer3 = new wxBoxSizer( wxVERTICAL );

    m_LayerScrolledWindow = new wxScrolledWindow( m_LayerPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
    m_LayerScrolledWindow->SetScrollRate( 5, 5 );
    m_LayersFlexGridSizer = new wxFlexGridSizer( 0, 4, 0, 1 );
    m_LayersFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
529
    m_LayersFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );
dickelbeck's avatar
dickelbeck committed
530 531 532 533 534 535 536 537 538

    m_LayerScrolledWindow->SetSizer( m_LayersFlexGridSizer );
    m_LayerScrolledWindow->Layout();
    m_LayersFlexGridSizer->Fit( m_LayerScrolledWindow );
    bSizer3->Add( m_LayerScrolledWindow, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxTOP, 2 );

    m_LayerPanel->SetSizer( bSizer3 );
    m_LayerPanel->Layout();
    bSizer3->Fit( m_LayerPanel );
539
    m_notebook->AddPage( m_LayerPanel, _( "Layer" ), true );
dickelbeck's avatar
dickelbeck committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
    m_RenderingPanel = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );

    wxBoxSizer* bSizer4;
    bSizer4 = new wxBoxSizer( wxVERTICAL );

    m_RenderScrolledWindow = new wxScrolledWindow( m_RenderingPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
    m_RenderScrolledWindow->SetScrollRate( 5, 5 );
    m_RenderFlexGridSizer = new wxFlexGridSizer( 0, 2, 0, 1 );
    m_RenderFlexGridSizer->SetFlexibleDirection( wxHORIZONTAL );
    m_RenderFlexGridSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_NONE );

    m_RenderScrolledWindow->SetSizer( m_RenderFlexGridSizer );
    m_RenderScrolledWindow->Layout();
    m_RenderFlexGridSizer->Fit( m_RenderScrolledWindow );
    bSizer4->Add( m_RenderScrolledWindow, 1, wxALL|wxEXPAND, 5 );

    m_RenderingPanel->SetSizer( bSizer4 );
    m_RenderingPanel->Layout();
    bSizer4->Fit( m_RenderingPanel );
559
    m_notebook->AddPage( m_RenderingPanel, _( "Render" ), false );
dickelbeck's avatar
dickelbeck committed
560 561 562 563 564

    boxSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );

    SetSizer( boxSizer );

565
    m_FocusOwner = aFocusOwner;
566

dickelbeck's avatar
dickelbeck committed
567
    m_CurrentRow = -1;  // hide the arrow initially
dickelbeck's avatar
dickelbeck committed
568

569
    m_RightArrowBitmap = new wxBitmap( rightarrow_xpm );
570
    m_RightArrowAlternateBitmap = new wxBitmap( rightarrow_alternate_xpm );
dickelbeck's avatar
dickelbeck committed
571

572
    m_BlankBitmap = new wxBitmap( clear_xpm );     // translucent
573
    m_BlankAlternateBitmap = new wxBitmap( clear_alternate_xpm );
574
    m_BitmapSize = wxSize(m_BlankBitmap->GetWidth(), m_BlankBitmap->GetHeight());
dickelbeck's avatar
dickelbeck committed
575

576 577
    // trap the tab changes so that we can call passOnFocus().
    m_notebook->Connect( -1, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
578
        wxNotebookEventHandler( LAYER_WIDGET::OnTabChange ), NULL, this );
dickelbeck's avatar
dickelbeck committed
579 580

    Layout();
581
}
dickelbeck's avatar
dickelbeck committed
582 583


584 585 586 587 588 589
wxSize LAYER_WIDGET::GetBestSize() const
{
    // size of m_LayerScrolledWindow --------------
    wxArrayInt widths = m_LayersFlexGridSizer->GetColWidths();
    int totWidth = 0;
    if( widths.GetCount() )
dickelbeck's avatar
dickelbeck committed
590
    {
591
        for( int i=0;  i<LYR_COLUMN_COUNT;  ++i )
dickelbeck's avatar
dickelbeck committed
592 593
        {
            totWidth += widths[i] + m_LayersFlexGridSizer->GetHGap();
dickelbeck's avatar
dickelbeck committed
594
            // printf("widths[%d]:%d\n", i, widths[i] );
dickelbeck's avatar
dickelbeck committed
595
        }
596 597 598
    }
    // Account for the parent's frame:
    totWidth += 10;
dickelbeck's avatar
dickelbeck committed
599

600

601 602 603 604
    /* The minimum height is a small size to properly force computation
     * of the panel's scrollbars (otherwise it will assume it *has* all
     * this space) */
    unsigned totHeight = 32;
dickelbeck's avatar
dickelbeck committed
605

606
    wxSize layerz( totWidth, totHeight );
dickelbeck's avatar
dickelbeck committed
607

608 609
    layerz += m_LayerPanel->GetWindowBorderSize();

dickelbeck's avatar
dickelbeck committed
610

611 612 613 614 615 616
    // size of m_RenderScrolledWindow --------------
    widths = m_RenderFlexGridSizer->GetColWidths();
    totWidth = 0;
    if( widths.GetCount() )
    {
        for( int i=0;  i<RND_COLUMN_COUNT;  ++i )
dickelbeck's avatar
dickelbeck committed
617 618 619 620
        {
            totWidth += widths[i] + m_RenderFlexGridSizer->GetHGap();
            // printf("widths[%d]:%d\n", i, widths[i] );
        }
621 622 623 624
    }
    // account for the parent's frame, this one has void space of 10 PLUS a border:
    totWidth += 20;

625
    // For totHeight re-use the previous small one
626
    wxSize renderz( totWidth, totHeight );
dickelbeck's avatar
dickelbeck committed
627

628 629
    renderz += m_RenderingPanel->GetWindowBorderSize();

630
    wxSize clientz( std::max(renderz.x,layerz.x), std::max(renderz.y,layerz.y) );
631 632

    return clientz;
633
}
dickelbeck's avatar
dickelbeck committed
634 635


636 637 638 639 640
int LAYER_WIDGET::GetLayerRowCount() const
{
    int controlCount = m_LayersFlexGridSizer->GetChildren().GetCount();
    return controlCount / LYR_COLUMN_COUNT;
}
dickelbeck's avatar
dickelbeck committed
641

dickelbeck's avatar
dickelbeck committed
642

643 644 645 646 647
int LAYER_WIDGET::GetRenderRowCount() const
{
    int controlCount = m_RenderFlexGridSizer->GetChildren().GetCount();
    return controlCount / RND_COLUMN_COUNT;
}
dickelbeck's avatar
dickelbeck committed
648

dickelbeck's avatar
dickelbeck committed
649

650 651 652 653
void LAYER_WIDGET::AppendLayerRow( const ROW& aRow )
{
    int nextRow = GetLayerRowCount();
    insertLayerRow( nextRow, aRow );
654
    UpdateLayouts();
655
}
dickelbeck's avatar
dickelbeck committed
656

dickelbeck's avatar
dickelbeck committed
657

658 659
void LAYER_WIDGET::ClearLayerRows()
{
660
    m_LayersFlexGridSizer->Clear( true );
661
}
dickelbeck's avatar
dickelbeck committed
662

dickelbeck's avatar
dickelbeck committed
663

664 665 666 667
void LAYER_WIDGET::AppendRenderRow( const ROW& aRow )
{
    int nextRow = GetRenderRowCount();
    insertRenderRow( nextRow, aRow );
668
    UpdateLayouts();
669
}
dickelbeck's avatar
dickelbeck committed
670

dickelbeck's avatar
dickelbeck committed
671

672 673
void LAYER_WIDGET::ClearRenderRows()
{
674
    m_RenderFlexGridSizer->Clear( true );
675
}
dickelbeck's avatar
dickelbeck committed
676 677


678 679 680
void LAYER_WIDGET::SelectLayerRow( int aRow )
{
    // enable the layer tab at index 0
681
    m_notebook->SetSelection( 0 );
dickelbeck's avatar
dickelbeck committed
682

683
    wxStaticBitmap* oldbm = (wxStaticBitmap*) getLayerComp( m_CurrentRow, 0 );
684
    if( oldbm )
685
        oldbm->SetBitmap( useAlternateBitmap(m_CurrentRow) ? *m_BlankAlternateBitmap : *m_BlankBitmap );
686

687
    wxStaticBitmap* newbm = (wxStaticBitmap*) getLayerComp( aRow, 0 );
688
    if( newbm )
dickelbeck's avatar
dickelbeck committed
689
    {
690
        newbm->SetBitmap( useAlternateBitmap(aRow) ? *m_RightArrowAlternateBitmap : *m_RightArrowBitmap );
691 692

        // Make sure the desired layer row is visible.
693 694 695 696
        // It seems that as of 2.8.2, setting the focus does this.
        // I don't expect the scrolling to be needed at all because
        // the minimum window size may end up being established so that the
        // scroll bars will not be visible.
697
        getLayerComp( aRow, 1 )->SetFocus();
dickelbeck's avatar
dickelbeck committed
698
    }
699

700 701
    m_CurrentRow = aRow;

702 703
    // give the focus back to the app.
    passOnFocus();
704
}
dickelbeck's avatar
dickelbeck committed
705

dickelbeck's avatar
dickelbeck committed
706

707
void LAYER_WIDGET::SelectLayer( LAYER_NUM aLayer )
708 709 710 711 712 713
{
    int row = findLayerRow( aLayer );
    SelectLayerRow( row );
}


714
LAYER_NUM LAYER_WIDGET::GetSelectedLayer()
715
{
716 717 718
    wxWindow* w = getLayerComp( m_CurrentRow, 0 );
    if( w )
        return getDecodedId( w->GetId() );
719

720
    return UNDEFINED_LAYER;
721
}
dickelbeck's avatar
dickelbeck committed
722 723


724
void LAYER_WIDGET::SetLayerVisible( LAYER_NUM aLayer, bool isVisible )
725 726 727
{
    int row = findLayerRow( aLayer );
    if( row >= 0 )
dickelbeck's avatar
dickelbeck committed
728
    {
729
        wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
730 731
        wxASSERT( cb );
        cb->SetValue( isVisible );      // does not fire an event
dickelbeck's avatar
dickelbeck committed
732
    }
733
}
dickelbeck's avatar
dickelbeck committed
734

735

736
bool LAYER_WIDGET::IsLayerVisible( LAYER_NUM aLayer )
737 738 739 740
{
    int row = findLayerRow( aLayer );
    if( row >= 0 )
    {
741
        wxCheckBox* cb = (wxCheckBox*) getLayerComp( row, COLUMN_COLOR_LYR_CB );
742 743 744 745 746 747 748
        wxASSERT( cb );
        return cb->GetValue();
    }
    return false;
}


749
void LAYER_WIDGET::SetLayerColor( LAYER_NUM aLayer, EDA_COLOR_T aColor )
750 751 752 753 754
{
    int row = findLayerRow( aLayer );
    if( row >= 0 )
    {
        int col = 1;    // bitmap button is column 1
755
        wxBitmapButton* bmb = (wxBitmapButton*) getLayerComp( row, col );
756 757 758 759 760 761 762 763 764 765
        wxASSERT( bmb );

        wxBitmap bm = makeBitmap( aColor );

        bmb->SetBitmapLabel( bm );
        bmb->SetName( makeColorTxt( aColor ) ); // save color value in name as string
    }
}


766
EDA_COLOR_T LAYER_WIDGET::GetLayerColor( LAYER_NUM aLayer ) const
767 768 769 770 771
{
    int row = findLayerRow( aLayer );
    if( row >= 0 )
    {
        int col = 1;    // bitmap button is column 1
772
        wxBitmapButton* bmb = (wxBitmapButton*) getLayerComp( row, col );
773 774 775
        wxASSERT( bmb );

        wxString colorTxt = bmb->GetName();
776
        return ColorFromInt( strtoul( TO_UTF8(colorTxt), NULL, 0 ) );
777 778
    }

779
    return UNSPECIFIED_COLOR;   // it's caller fault, gave me a bad layer
780 781 782 783 784 785 786 787 788
}


void LAYER_WIDGET::SetRenderState( int aId, bool isSet )
{
    int row = findRenderRow( aId );
    if( row >= 0 )
    {
        int col = 1;    // checkbox is column 1
789
        wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
790 791 792 793 794 795 796 797 798 799 800 801
        wxASSERT( cb );
        cb->SetValue( isSet );  // does not fire an event
    }
}


bool LAYER_WIDGET::GetRenderState( int aId )
{
    int row = findRenderRow( aId );
    if( row >= 0 )
    {
        int col = 1;    // checkbox is column 1
802
        wxCheckBox* cb = (wxCheckBox*) getRenderComp( row, col );
803 804 805 806 807 808 809
        wxASSERT( cb );
        return cb->GetValue();
    }
    return false;   // the value of a non-existent row
}


810 811 812 813
void LAYER_WIDGET::UpdateLayouts()
{
    m_LayersFlexGridSizer->Layout();
    m_RenderFlexGridSizer->Layout();
814 815
    m_LayerPanel->Layout();
    m_RenderingPanel->Layout();
816
    FitInside();
817
}
dickelbeck's avatar
dickelbeck committed
818 819 820

#if defined(STAND_ALONE)

821 822 823
#include <wx/aui/aui.h>


dickelbeck's avatar
dickelbeck committed
824 825 826 827 828 829
/**
 * Class MYFRAME
 * is a test class here to exercise the LAYER_WIDGET and explore use cases.
 * @see http://www.kirix.com/labs/wxaui/screenshots.html
 * for ideas.
 */
dickelbeck's avatar
dickelbeck committed
830 831
class MYFRAME : public wxFrame
{
dickelbeck's avatar
dickelbeck committed
832 833
    // example of how to derive from LAYER_WIDGET in order to provide the
    // abstract methods.
dickelbeck's avatar
dickelbeck committed
834 835 836
    class MYLAYERS : public LAYER_WIDGET
    {
    public:
dickelbeck's avatar
dickelbeck committed
837 838 839
        // your constructor could take a BOARD argument.  here I leave it
        // out because this source module wants to know nothing of BOARDs
        // to maximize re-use.
840 841
        MYLAYERS( wxWindow* aParent ) :
            LAYER_WIDGET( aParent, aParent  )
dickelbeck's avatar
dickelbeck committed
842 843 844
        {
        }

Dick Hollenbeck's avatar
Dick Hollenbeck committed
845
        void OnLayerColorChange( int aLayer, EDA_COLOR_T aColor )
dickelbeck's avatar
dickelbeck committed
846
        {
dickelbeck's avatar
dickelbeck committed
847
            printf( "OnLayerColorChange( aLayer:%d, aColor:%d )\n", aLayer, aColor );
dickelbeck's avatar
dickelbeck committed
848

dickelbeck's avatar
dickelbeck committed
849
            /* a test trigger only
dickelbeck's avatar
dickelbeck committed
850 851 852 853 854
            if( aLayer == 2 )
            {
                ClearLayerRows();
                printf(" GetLayerRowCount(): %d\n", GetLayerRowCount() );
            }
dickelbeck's avatar
dickelbeck committed
855
            */
dickelbeck's avatar
dickelbeck committed
856 857
        }

858
        bool OnLayerSelect( LAYER aLayer )
dickelbeck's avatar
dickelbeck committed
859
        {
dickelbeck's avatar
dickelbeck committed
860
            printf( "OnLayerSelect( aLayer:%d )\n", aLayer );
dickelbeck's avatar
dickelbeck committed
861 862
            return true;
        }
dickelbeck's avatar
dickelbeck committed
863

864
        void OnLayerVisible( LAYER aLayer, bool isVisible, bool isFinal )
dickelbeck's avatar
dickelbeck committed
865
        {
866
            printf( "OnLayerVisible( aLayer:%d, isVisible:%d isFinal:%d)\n", aLayer, isVisible, isFinal );
dickelbeck's avatar
dickelbeck committed
867
        }
dickelbeck's avatar
dickelbeck committed
868

869
        void OnRenderColorChange( int aId, EDA_COLOR_T aColor )
dickelbeck's avatar
dickelbeck committed
870 871 872 873 874 875 876 877
        {
            printf( "OnRenderColorChange( aId:%d, aColor:%d )\n", aId, aColor );
        }

        void OnRenderEnable( int aId, bool isEnabled )
        {
            printf( "OnRenderEnable( aId:%d, isEnabled:%d )\n", aId, isEnabled );
        }
dickelbeck's avatar
dickelbeck committed
878 879 880
    };


dickelbeck's avatar
dickelbeck committed
881
public:
dickelbeck's avatar
dickelbeck committed
882
    MYFRAME( wxWindow * parent ) :
883
        wxFrame( parent, -1, wxT( "wxAUI Test" ), wxDefaultPosition,
dickelbeck's avatar
dickelbeck committed
884
            wxSize( 800, 600 ), wxDEFAULT_FRAME_STYLE )
dickelbeck's avatar
dickelbeck committed
885 886 887 888
    {
        // notify wxAUI which frame to use
        m_mgr.SetManagedWindow( this );

889
        MYLAYERS* lw = new MYLAYERS( this );
dickelbeck's avatar
dickelbeck committed
890

891
        // add some layer rows
892
        static const LAYER_WIDGET::ROW layerRows[] = {
893 894 895 896
            LAYER_WIDGET::ROW( wxT("layer 1"), 0, RED, wxT("RED"), false ),
            LAYER_WIDGET::ROW( wxT("layer 2"), 1, GREEN, wxT("GREEN"), true ),
            LAYER_WIDGET::ROW( wxT("brown_layer"), 2, BROWN, wxT("BROWN"), true ),
            LAYER_WIDGET::ROW( wxT("layer_4_you"), 3, BLUE, wxT("BLUE"), false ),
897 898 899
        };

        lw->AppendLayerRows( layerRows, DIM(layerRows) );
dickelbeck's avatar
dickelbeck committed
900

901
        // add some render rows
902
        static const LAYER_WIDGET::ROW renderRows[] = {
903
            LAYER_WIDGET::ROW( wxT("With Very Large Ears"), 0, -1, wxT("Spock here") ),
904
            LAYER_WIDGET::ROW( wxT("With Legs"), 1, YELLOW ),
905
            LAYER_WIDGET::ROW( wxT("With Oval Eyes"), 1, BROWN, wxT("My eyes are upon you") ),
906 907 908
        };

        lw->AppendRenderRows( renderRows, DIM(renderRows) );
dickelbeck's avatar
dickelbeck committed
909 910

        lw->SelectLayerRow( 1 );
dickelbeck's avatar
dickelbeck committed
911

dickelbeck's avatar
dickelbeck committed
912
        wxAuiPaneInfo li;
dickelbeck's avatar
dickelbeck committed
913 914
        li.MinSize( lw->GetBestSize() );
        li.BestSize( lw->GetBestSize() );
dickelbeck's avatar
dickelbeck committed
915
        li.Left();
dickelbeck's avatar
dickelbeck committed
916 917
//        li.MaximizeButton( true );
//        li.MinimizeButton( true );
dickelbeck's avatar
dickelbeck committed
918 919
        li.CloseButton( false );
        li.Caption( wxT( "Layers" ) );
dickelbeck's avatar
dickelbeck committed
920 921
        m_mgr.AddPane( lw, li );

dickelbeck's avatar
dickelbeck committed
922

923
        wxTextCtrl* text2 = new wxTextCtrl( this, -1, wxT( "Pane 2 - sample text" ),
dickelbeck's avatar
dickelbeck committed
924 925
                                            wxDefaultPosition, wxSize( 200, 150 ),
                                            wxNO_BORDER | wxTE_MULTILINE );
dickelbeck's avatar
dickelbeck committed
926
        m_mgr.AddPane( text2, wxBOTTOM, wxT( "Pane Number Two" ) );
dickelbeck's avatar
dickelbeck committed
927

928
        wxTextCtrl* text3 = new wxTextCtrl( this, -1, wxT( "Main content window" ),
dickelbeck's avatar
dickelbeck committed
929 930
                                            wxDefaultPosition, wxSize( 200, 150 ),
                                            wxNO_BORDER | wxTE_MULTILINE );
dickelbeck's avatar
dickelbeck committed
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
        m_mgr.AddPane( text3, wxCENTER );

        // tell the manager to "commit" all the changes just made
        m_mgr.Update();
    }

    ~MYFRAME()
    {
        // deinitialize the frame manager
        m_mgr.UnInit();
    }

private:
    wxAuiManager m_mgr;
};


// our normal wxApp-derived class, as usual
949 950
class MyApp : public wxApp
{
dickelbeck's avatar
dickelbeck committed
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
public:

    bool OnInit()
    {
        wxFrame* frame = new MYFRAME( NULL );

        SetTopWindow( frame );
        frame->Show();
        return true;
    }
};

DECLARE_APP( MyApp );
IMPLEMENT_APP( MyApp );

dickelbeck's avatar
dickelbeck committed
966
#endif  // STAND_ALONE