1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Generic tabbed dialogs 
   4 // Author:      Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13 #pragma implementation "tabg.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  26     #include "wx/settings.h" 
  28     #include "wx/dcclient.h" 
  37 #include "wx/listimpl.cpp" 
  39 WX_DEFINE_LIST(wxTabLayerList
); 
  41 // not defined: use old, square tab implementation (fills in tabs) 
  42 // defined: use new, rounded tab implementation (doesn't colour in tabs) 
  43 // #define wxUSE_NEW_METHOD 
  45 IMPLEMENT_DYNAMIC_CLASS(wxTabControl
, wxObject
) 
  47 // IMPLEMENT_DYNAMIC_CLASS(wxTabLayer, wxList) 
  49 wxTabControl::wxTabControl(wxTabView 
*v
) 
  62 wxTabControl::~wxTabControl(void) 
  66 void wxTabControl::OnDraw(wxDC
& dc
, bool lastInRow
) 
  68     // Old, but in some ways better (drawing opaque tabs) 
  69 #ifndef wxUSE_NEW_METHOD 
  73   // Top-left of tab view area 
  74   int viewX 
= m_view
->GetViewRect().x
; 
  75   int viewY 
= m_view
->GetViewRect().y
; 
  77   // Top-left of tab control 
  78   int tabX 
= GetX() + viewX
; 
  79   int tabY 
= GetY() + viewY
; 
  83     tabHeightInc 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
  87   dc
.SetPen(*wxTRANSPARENT_PEN
); 
  89   // Draw grey background 
  90   if (m_view
->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
  92     dc
.SetBrush(*m_view
->GetBackgroundBrush()); 
  94     // Add 1 because the pen is transparent. Under Motif, may be different. 
  96     dc
.DrawRectangle(tabX
, tabY
, (GetWidth()+1), (GetHeight() + tabHeightInc
)); 
  98     dc
.DrawRectangle(tabX
, tabY
, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc
)); 
 102   // Draw highlight and shadow 
 103   dc
.SetPen(*m_view
->GetHighlightPen()); 
 105   // Calculate the top of the tab beneath. It's the height of the tab, MINUS 
 106   // a bit if the tab below happens to be selected. Check. 
 107   wxTabControl 
*tabBeneath 
= NULL
; 
 108   int subtractThis 
= 0; 
 109   if (GetColPosition() > 0) 
 110     tabBeneath 
= m_view
->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition()); 
 111   if (tabBeneath 
&& tabBeneath
->IsSelected()) 
 112     subtractThis 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
 114   // Vertical highlight: if first tab, draw to bottom of view 
 115   if (tabX 
== m_view
->GetViewRect().x 
&& (m_view
->GetTabStyle() & wxTAB_STYLE_DRAW_BOX
)) 
 116     dc
.DrawLine(tabX
, tabY
, tabX
, (m_view
->GetViewRect().y 
+ m_view
->GetViewRect().height
)); 
 117   else if (tabX 
== m_view
->GetViewRect().x
) 
 118     // Not box drawing, just to top of view. 
 119     dc
.DrawLine(tabX
, tabY
, tabX
, (m_view
->GetViewRect().y
)); 
 121     dc
.DrawLine(tabX
, tabY
, tabX
, (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 123   dc
.DrawLine(tabX
, tabY
, (tabX 
+ GetWidth()), tabY
); 
 124   dc
.SetPen(*m_view
->GetShadowPen()); 
 126   // Test if we're outside the right-hand edge of the view area 
 127   if (((tabX 
+ GetWidth()) >= m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width
) && (m_view
->GetTabStyle() & wxTAB_STYLE_DRAW_BOX
)) 
 129     int bottomY 
= m_view
->GetViewRect().y 
+ m_view
->GetViewRect().height 
+ GetY() + m_view
->GetTabHeight() + m_view
->GetTopMargin(); 
 130     // Add a tab height since we wish to draw to the bottom of the view. 
 131     dc
.DrawLine((tabX 
+ GetWidth()), tabY
, 
 132       (tabX 
+ GetWidth()), bottomY
); 
 134     // Calculate the far-right of the view, since we don't wish to 
 136     int rightOfView 
= m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width 
+ 1; 
 138     // Draw the horizontal bit to connect to the view rectangle 
 139     dc
.DrawLine((wxMax((tabX 
+ GetWidth() - m_view
->GetHorizontalTabOffset()), rightOfView
)), (bottomY
-1), 
 140       (tabX 
+ GetWidth()), (bottomY
-1)); 
 142     // Draw black line to emphasize shadow 
 143     dc
.SetPen(*wxBLACK_PEN
); 
 144     dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), 
 145       (tabX 
+ GetWidth() + 1), bottomY
); 
 147     // Draw the horizontal bit to connect to the view rectangle 
 148     dc
.DrawLine((wxMax((tabX 
+ GetWidth() - m_view
->GetHorizontalTabOffset()), rightOfView
)), (bottomY
), 
 149       (tabX 
+ GetWidth() + 1), (bottomY
)); 
 155       // 25/5/97 UNLESS it's less than the max number of positions in this row 
 157       int topY 
= m_view
->GetViewRect().y 
- m_view
->GetTopMargin(); 
 159       int maxPositions 
= ((wxTabLayer 
*)m_view
->GetLayers().Item(0)->GetData())->GetCount(); 
 161       // Only down to the bottom of the tab, not to the top of the view 
 162       if ( GetRowPosition() < (maxPositions 
- 1) ) 
 163         topY 
= tabY 
+ GetHeight() + tabHeightInc
; 
 170       dc
.DrawLine((tabX 
+ GetWidth()), tabY
, (tabX 
+ GetWidth()), topY
); 
 171       // Draw black line to emphasize shadow 
 172       dc
.SetPen(*wxBLACK_PEN
); 
 173       dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), (tabX 
+ GetWidth() + 1), 
 178       // Calculate the top of the tab beneath. It's the height of the tab, MINUS 
 179       // a bit if the tab below (and next col along) happens to be selected. Check. 
 180       wxTabControl 
*tabBeneath 
= NULL
; 
 181       int subtractThis 
= 0; 
 182       if (GetColPosition() > 0) 
 183         tabBeneath 
= m_view
->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1); 
 184       if (tabBeneath 
&& tabBeneath
->IsSelected()) 
 185         subtractThis 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
 191       // Draw only to next tab down. 
 192       dc
.DrawLine((tabX 
+ GetWidth()), tabY
, 
 193          (tabX 
+ GetWidth()), (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 195       // Draw black line to emphasize shadow 
 196       dc
.SetPen(*wxBLACK_PEN
); 
 197       dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), (tabX 
+ GetWidth() + 1), 
 198          (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 202   // Draw centered text 
 203   int textY 
= tabY 
+ m_view
->GetVerticalTabTextSpacing() + tabHeightInc
; 
 206     dc
.SetFont(* m_view
->GetSelectedTabFont()); 
 208     dc
.SetFont(* GetFont()); 
 210   wxColour 
col(m_view
->GetTextColour()); 
 211   dc
.SetTextForeground(col
); 
 212   dc
.SetBackgroundMode(wxTRANSPARENT
); 
 213   long textWidth
, textHeight
; 
 214   dc
.GetTextExtent(GetLabel(), &textWidth
, &textHeight
); 
 216   int textX 
= (int)(tabX 
+ (GetWidth() - textWidth
)/2.0); 
 217   if (textX 
< (tabX 
+ 2)) 
 220   dc
.SetClippingRegion(tabX
, tabY
, GetWidth(), GetHeight()); 
 221   dc
.DrawText(GetLabel(), textX
, textY
); 
 222   dc
.DestroyClippingRegion(); 
 226     dc
.SetPen(*m_view
->GetHighlightPen()); 
 228     // Draw white highlight from the tab's left side to the left hand edge of the view 
 229     dc
.DrawLine(m_view
->GetViewRect().x
, (tabY 
+ GetHeight() + tabHeightInc
), 
 230      tabX
, (tabY 
+ GetHeight() + tabHeightInc
)); 
 232     // Draw white highlight from the tab's right side to the right hand edge of the view 
 233     dc
.DrawLine((tabX 
+ GetWidth()), (tabY 
+ GetHeight() + tabHeightInc
), 
 234      m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width
, (tabY 
+ GetHeight() + tabHeightInc
)); 
 237     // New HEL version with rounder tabs 
 244         tabInc 
= m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight(); 
 246     int tabLeft  
= GetX() + m_view
->GetViewRect().x
; 
 247     int tabTop   
= GetY() + m_view
->GetViewRect().y 
- tabInc
; 
 248     int tabRight 
= tabLeft 
+ m_view
->GetTabWidth(); 
 249     int left     
= m_view
->GetViewRect().x
; 
 250     int top      
= tabTop 
+ m_view
->GetTabHeight() + tabInc
; 
 251     int right    
= left 
+ m_view
->GetViewRect().width
; 
 252     int bottom   
= top 
+ m_view
->GetViewRect().height
; 
 256         // TAB is selected - draw TAB and the View's full outline 
 258         dc
.SetPen(*(m_view
->GetHighlightPen())); 
 261         pnts
[n
].x 
= left
;            pnts
[n
++].y 
= bottom
; 
 262         pnts
[n
].x 
= left
;             pnts
[n
++].y 
= top
; 
 263         pnts
[n
].x 
= tabLeft
;         pnts
[n
++].y 
= top
; 
 264         pnts
[n
].x 
= tabLeft
;            pnts
[n
++].y 
= tabTop 
+ 2; 
 265         pnts
[n
].x 
= tabLeft 
+ 2;        pnts
[n
++].y 
= tabTop
; 
 266         pnts
[n
].x 
= tabRight 
- 1;    pnts
[n
++].y 
= tabTop
; 
 267         dc
.DrawLines(n
, pnts
); 
 278         dc
.SetPen(*(m_view
->GetShadowPen())); 
 298         dc
.SetPen(*wxBLACK_PEN
); 
 340         // TAB is not selected - just draw TAB outline and RH edge 
 341         // if the TAB is the last in the row 
 343         int maxPositions 
= ((wxTabLayer
*)m_view
->GetLayers().Item(0)->GetData())->GetCount(); 
 344         wxTabControl
* tabBelow 
= 0; 
 345         wxTabControl
* tabBelowRight 
= 0; 
 346         if (GetColPosition() > 0) 
 348             tabBelow 
= m_view
->FindTabControlForPosition( 
 349                         GetColPosition() - 1, 
 353         if (!lastInRow 
&& GetColPosition() > 0) 
 355             tabBelowRight 
= m_view
->FindTabControlForPosition( 
 356                         GetColPosition() - 1, 
 361         float raisedTop 
= top 
- m_view
->GetTabSelectionHeight() + 
 362                             m_view
->GetTabHeight(); 
 364         dc
.SetPen(*(m_view
->GetHighlightPen())); 
 370         if (tabBelow 
&& tabBelow
->IsSelected()) 
 372             pnts
[n
++].y 
= (long)raisedTop
; 
 378         pnts
[n
].x 
= tabLeft
;            pnts
[n
++].y 
= tabTop 
+ 2; 
 379         pnts
[n
].x 
= tabLeft 
+ 2;        pnts
[n
++].y 
= tabTop
; 
 380         pnts
[n
].x 
= tabRight 
- 1;    pnts
[n
++].y 
= tabTop
; 
 381         dc
.DrawLines(n
, pnts
); 
 383         dc
.SetPen(*(m_view
->GetShadowPen())); 
 384         if (GetRowPosition() >= maxPositions 
- 1) 
 395                     (tabRight 
- m_view
->GetHorizontalTabOffset()), 
 401             if (tabBelowRight 
&& tabBelowRight
->IsSelected()) 
 421         dc
.SetPen(*wxBLACK_PEN
); 
 430         if (GetRowPosition() >= maxPositions 
- 1) 
 432             // draw right hand edge to bottom of view 
 442                     (tabRight 
- m_view
->GetHorizontalTabOffset()), 
 448             // draw right hand edge of TAB 
 449             if (tabBelowRight 
&& tabBelowRight
->IsSelected()) 
 453                         (long)(raisedTop 
- 1), 
 470     // Draw centered text 
 471     dc
.SetPen(*wxBLACK_PEN
); 
 474         dc
.SetFont(*(m_view
->GetSelectedTabFont())); 
 478         dc
.SetFont(*(GetFont())); 
 481     wxColour 
col(m_view
->GetTextColour()); 
 482     dc
.SetTextForeground(col
); 
 483     dc
.SetBackgroundMode(wxTRANSPARENT
); 
 484     long textWidth
, textHeight
; 
 485     dc
.GetTextExtent(GetLabel(), &textWidth
, &textHeight
); 
 487     float textX 
= (tabLeft 
+ tabRight 
- textWidth
) / 2; 
 488     float textY 
= (tabInc 
+ tabTop 
+ m_view
->GetVerticalTabTextSpacing()); 
 490     dc
.DrawText(GetLabel(), (long)textX
, (long)textY
); 
 494 bool wxTabControl::HitTest(int x
, int y
) const 
 496   // Top-left of tab control 
 497   int tabX1 
= GetX() + m_view
->GetViewRect().x
; 
 498   int tabY1 
= GetY() + m_view
->GetViewRect().y
; 
 501   int tabX2 
= tabX1 
+ GetWidth(); 
 502   int tabY2 
= tabY1 
+ GetHeight(); 
 504   if (x 
>= tabX1 
&& y 
>= tabY1 
&& x 
<= tabX2 
&& y 
<= tabY2
) 
 510 IMPLEMENT_DYNAMIC_CLASS(wxTabView
, wxObject
) 
 512 wxTabView::wxTabView(long style
) 
 518   m_tabSelectionHeight 
= m_tabHeight 
+ 2; 
 520   m_tabHorizontalOffset 
= 10; 
 521   m_tabHorizontalSpacing 
= 2; 
 522   m_tabVerticalTextSpacing 
= 3; 
 524   m_tabViewRect
.x 
= 20; 
 525   m_tabViewRect
.y 
= 20; 
 526   m_tabViewRect
.width 
= 300; 
 527   m_tabViewRect
.x 
= 300; 
 528   m_highlightColour 
= *wxWHITE
; 
 529   m_shadowColour 
= wxColour(128, 128, 128); 
 530   m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
); 
 531   m_textColour 
= *wxBLACK
; 
 532   m_highlightPen 
= wxWHITE_PEN
; 
 533   m_shadowPen 
= wxGREY_PEN
; 
 534   SetBackgroundColour(m_backgroundColour
); 
 535   m_tabFont 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 536   m_tabSelectedFont 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 537   m_window 
= (wxWindow 
*) NULL
; 
 540 wxTabView::~wxTabView() 
 545 // Automatically positions tabs 
 546 // TODO: this should just add the tab to a list, and then 
 547 // a layout function (e.g. Realize) should be called when all tabs have been added. 
 548 // The view rect could easily change as the view window is resized. 
 549 wxTabControl 
*wxTabView::AddTab(int id
, const wxString
& label
, wxTabControl 
*existingTab
) 
 551   // First, find which layer we should be adding to. 
 552   wxTabLayerList::compatibility_iterator node 
= m_layers
.GetLast(); 
 555     wxTabLayer 
*newLayer 
= new wxTabLayer
; 
 556     node 
= m_layers
.Append(newLayer
); 
 558   // Check if adding another tab control would go off the 
 559   // right-hand edge of the layer. 
 560   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node
->GetData(); 
 561   wxList::compatibility_iterator lastTabNode 
= tabLayer
->GetLast(); 
 564     wxTabControl 
*lastTab 
= (wxTabControl 
*)lastTabNode
->GetData(); 
 565     // Start another layer (row). 
 566     // Tricky choice: can't just check if will be overlapping the edge, because 
 567     // this happens anyway for 2nd and subsequent rows. 
 568     // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 570     if (((tabLayer 
== m_layers
.GetFirst()->GetData()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 571               > GetViewRect().width
)) || 
 572         ((tabLayer 
!= m_layers
.GetFirst()->GetData()) && (tabLayer
->GetCount() == ((wxTabLayer 
*)m_layers
.GetFirst()->GetData())->GetCount()))) 
 574       tabLayer 
= new wxTabLayer
; 
 575       m_layers
.Append(tabLayer
); 
 576       lastTabNode 
= wxList::compatibility_iterator(); 
 579   int layer 
= m_layers
.GetCount() - 1; 
 581   wxTabControl 
*tabControl 
= existingTab
; 
 583     tabControl 
= OnCreateTabControl(); 
 584   tabControl
->SetRowPosition(tabLayer
->GetCount()); 
 585   tabControl
->SetColPosition(layer
); 
 587   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 589     lastTab 
= (wxTabControl 
*)lastTabNode
->GetData(); 
 592   int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 593   // Offset from view top-left 
 594   int horizontalOffset 
= 0; 
 596     horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 598     horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 600   tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 601   tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 602   tabControl
->SetId(id
); 
 603   tabControl
->SetLabel(label
); 
 604   tabControl
->SetFont(* GetTabFont()); 
 606   tabLayer
->Append(tabControl
); 
 612 // Remove the tab without deleting the window 
 613 bool wxTabView::RemoveTab(int id
) 
 615   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 618     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 619     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 622       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 623       if (tab
->GetId() == id
) 
 625         if (id 
== m_tabSelection
) 
 628         layer
->Erase(tabNode
); 
 631         // The layout has changed 
 635       tabNode 
= tabNode
->GetNext(); 
 637     layerNode 
= layerNode
->GetNext(); 
 642 bool wxTabView::SetTabText(int id
, const wxString
& label
) 
 644     wxTabControl
* control 
= FindTabControlForId(id
); 
 647     control
->SetLabel(label
); 
 651 wxString 
wxTabView::GetTabText(int id
) const 
 653     wxTabControl
* control 
= FindTabControlForId(id
); 
 655       return wxEmptyString
; 
 657       return control
->GetLabel(); 
 660 // Returns the total height of the tabs component -- this may be several 
 661 // times the height of a tab, if there are several tab layers (rows). 
 662 int wxTabView::GetTotalTabHeight() 
 666   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 669     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 670     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 673       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 675       if (tab
->GetY() < minY
) 
 678       tabNode 
= tabNode
->GetNext(); 
 680     layerNode 
= layerNode
->GetNext(); 
 686 void wxTabView::ClearTabs(bool deleteTabs
) 
 688   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 691     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 692     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 695       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 698       wxList::compatibility_iterator next 
= tabNode
->GetNext(); 
 699       layer
->Erase(tabNode
); 
 702     wxTabLayerList::compatibility_iterator nextLayerNode 
= layerNode
->GetNext(); 
 704     m_layers
.Erase(layerNode
); 
 705     layerNode 
= nextLayerNode
; 
 712 // Layout tabs (optional, e.g. if resizing window) 
 713 void wxTabView::LayoutTabs(void) 
 715   // Make a list of the tab controls, deleting the wxTabLayers. 
 718   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 721     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 722     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 725       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 726       controls
.Append(tab
); 
 727       wxList::compatibility_iterator next 
= tabNode
->GetNext(); 
 728       layer
->Erase(tabNode
); 
 731     wxTabLayerList::compatibility_iterator nextLayerNode 
= layerNode
->GetNext(); 
 733     m_layers
.Erase(layerNode
); 
 734     layerNode 
= nextLayerNode
; 
 737   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 739   wxTabLayer 
*currentLayer 
= new wxTabLayer
; 
 740   m_layers
.Append(currentLayer
); 
 742   wxList::compatibility_iterator node 
= controls
.GetFirst(); 
 745     wxTabControl 
*tabControl 
= (wxTabControl 
*)node
->GetData(); 
 748       // Start another layer (row). 
 749       // Tricky choice: can't just check if will be overlapping the edge, because 
 750       // this happens anyway for 2nd and subsequent rows. 
 751       // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 753       if (((currentLayer 
== m_layers
.GetFirst()->GetData()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 754                 > GetViewRect().width
)) || 
 755           ((currentLayer 
!= m_layers
.GetFirst()->GetData()) && (currentLayer
->GetCount() == ((wxTabLayer 
*)m_layers
.GetFirst()->GetData())->GetCount()))) 
 757        currentLayer 
= new wxTabLayer
; 
 758        m_layers
.Append(currentLayer
); 
 759        lastTab 
= (wxTabControl 
*) NULL
; 
 763     int layer 
= m_layers
.GetCount() - 1; 
 765     tabControl
->SetRowPosition(currentLayer
->GetCount()); 
 766     tabControl
->SetColPosition(layer
); 
 769     int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 770     // Offset from view top-left 
 771     int horizontalOffset 
= 0; 
 773       horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 775       horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 777     tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 778     tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 780     currentLayer
->Append(tabControl
); 
 781     lastTab 
= tabControl
; 
 783     node 
= node
->GetNext(); 
 786   // Move the selected tab to the bottom 
 787   wxTabControl 
*control 
= FindTabControlForId(m_tabSelection
); 
 789     MoveSelectionTab(control
); 
 794 void wxTabView::Draw(wxDC
& dc
) 
 796         // Don't draw anything if there are no tabs. 
 797         if (GetNumberOfTabs() == 0) 
 800     // Draw top margin area (beneath tabs and above view area) 
 801     if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
 803         dc
.SetPen(*wxTRANSPARENT_PEN
); 
 804         dc
.SetBrush(*GetBackgroundBrush()); 
 806         // Add 1 because the pen is transparent. Under Motif, may be different. 
 809                 (m_tabViewRect
.y 
- m_topMargin
), 
 810                 (m_tabViewRect
.width 
+ 1), 
 815     // Draw layers in reverse order 
 816     wxTabLayerList::compatibility_iterator node 
= m_layers
.GetLast(); 
 819         wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->GetData(); 
 820         wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
 823             wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
 824             control
->OnDraw(dc
, (!node2
->GetNext())); 
 825             node2 
= node2
->GetNext(); 
 828         node 
= node
->GetPrevious(); 
 832 #ifndef wxUSE_NEW_METHOD 
 833     if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX
) 
 835         dc
.SetPen(* GetShadowPen()); 
 839                 (GetViewRect().x 
+ 1), 
 840                 (GetViewRect().y 
+ GetViewRect().height
), 
 841                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 842                 (GetViewRect().y 
+ GetViewRect().height
) 
 847                 (GetViewRect().x 
+ GetViewRect().width
), 
 848                 (GetViewRect().y 
- GetTopMargin() + 1), 
 849                 (GetViewRect().x 
+ GetViewRect().width
), 
 850                 (GetViewRect().y 
+ GetViewRect().height
) 
 853         dc
.SetPen(* wxBLACK_PEN
); 
 858                 (GetViewRect().y 
+ GetViewRect().height 
+ 1), 
 859 #if defined(__WXMOTIF__) 
 860                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 862                 (GetViewRect().x 
+ GetViewRect().width 
+ 2), 
 865                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 870                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 871                 (GetViewRect().y 
- GetTopMargin()), 
 872                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 873                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 879 // Process mouse event, return false if we didn't process it 
 880 bool wxTabView::OnEvent(wxMouseEvent
& event
) 
 882   if (!event
.LeftDown()) 
 886   event
.GetPosition(&x
, &y
); 
 888   wxTabControl 
*hitControl 
= (wxTabControl 
*) NULL
; 
 890   wxTabLayerList::compatibility_iterator node 
= m_layers
.GetFirst(); 
 893     wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->GetData(); 
 894     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
 897       wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
 898       if (control
->HitTest((int)x
, (int)y
)) 
 900         hitControl 
= control
; 
 901         node 
= wxTabLayerList::compatibility_iterator(); 
 902         node2 
= wxList::compatibility_iterator(); 
 905         node2 
= node2
->GetNext(); 
 909       node 
= node
->GetNext(); 
 915   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 917   if (hitControl 
== currentTab
) 
 920   ChangeTab(hitControl
); 
 925 bool wxTabView::ChangeTab(wxTabControl 
*control
) 
 927   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 930     oldTab 
= currentTab
->GetId(); 
 932   if (control 
== currentTab
) 
 935   if (m_layers
.GetCount() == 0) 
 938   if (!OnTabPreActivate(control
->GetId(), oldTab
)) 
 941   // Move the tab to the bottom 
 942   MoveSelectionTab(control
); 
 945     currentTab
->SetSelected(false); 
 947   control
->SetSelected(true); 
 948   m_tabSelection 
= control
->GetId(); 
 950   OnTabActivate(control
->GetId(), oldTab
); 
 952   // Leave window refresh for the implementing window 
 957 // Move the selected tab to the bottom layer, if necessary, 
 958 // without calling app activation code 
 959 bool wxTabView::MoveSelectionTab(wxTabControl 
*control
) 
 961   if (m_layers
.GetCount() == 0) 
 964   wxTabLayer 
*firstLayer 
= (wxTabLayer 
*)m_layers
.GetFirst()->GetData(); 
 966   // Find what column this tab is at, so we can swap with the one at the bottom. 
 967   // If we're on the bottom layer, then no need to swap. 
 968   if (!firstLayer
->Member(control
)) 
 972     wxList::compatibility_iterator thisNode 
= FindTabNodeAndColumn(control
, &col
); 
 975     wxList::compatibility_iterator otherNode 
= firstLayer
->Item(col
); 
 979     // If this is already in the bottom layer, return now 
 980     if (otherNode 
== thisNode
) 
 983     wxTabControl 
*otherTab 
= (wxTabControl 
*)otherNode
->GetData(); 
 985     // We now have pointers to the tab to be changed to, 
 986     // and the tab on the first layer. Swap tab structures and 
 989     int thisX 
= control
->GetX(); 
 990     int thisY 
= control
->GetY(); 
 991     int thisColPos 
= control
->GetColPosition(); 
 992     int otherX 
= otherTab
->GetX(); 
 993     int otherY 
= otherTab
->GetY(); 
 994     int otherColPos 
= otherTab
->GetColPosition(); 
 996     control
->SetPosition(otherX
, otherY
); 
 997     control
->SetColPosition(otherColPos
); 
 998     otherTab
->SetPosition(thisX
, thisY
); 
 999     otherTab
->SetColPosition(thisColPos
); 
1001     // Swap the data for the nodes 
1002     thisNode
->SetData(otherTab
); 
1003     otherNode
->SetData(control
); 
1008 // Called when a tab is activated 
1009 void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/) 
1013 void wxTabView::SetHighlightColour(const wxColour
& col
) 
1015   m_highlightColour 
= col
; 
1016   m_highlightPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1019 void wxTabView::SetShadowColour(const wxColour
& col
) 
1021   m_shadowColour 
= col
; 
1022   m_shadowPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1025 void wxTabView::SetBackgroundColour(const wxColour
& col
) 
1027   m_backgroundColour 
= col
; 
1028   m_backgroundPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1029   m_backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(col
, wxSOLID
); 
1032 void wxTabView::SetTabSelection(int sel
, bool activateTool
) 
1034   if ( sel
==m_tabSelection 
) 
1037   int oldSel 
= m_tabSelection
; 
1038   wxTabControl 
*control 
= FindTabControlForId(sel
); 
1039   wxTabControl 
*oldControl 
= FindTabControlForId(m_tabSelection
); 
1041   if (!OnTabPreActivate(sel
, oldSel
)) 
1045     control
->SetSelected((sel 
!= -1)); // TODO ?? 
1048     wxFAIL_MSG(_("Could not find tab for id")); 
1053     oldControl
->SetSelected(false); 
1055   m_tabSelection 
= sel
; 
1058     MoveSelectionTab(control
); 
1061     OnTabActivate(sel
, oldSel
); 
1064 // Find tab control for id 
1065 wxTabControl 
*wxTabView::FindTabControlForId(int id
) const 
1067   wxTabLayerList::compatibility_iterator node1 
= m_layers
.GetFirst(); 
1070     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->GetData(); 
1071     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
1074       wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
1075       if (control
->GetId() == id
) 
1077       node2 
= node2
->GetNext(); 
1079     node1 
= node1
->GetNext(); 
1081   return (wxTabControl 
*) NULL
; 
1084 // Find tab control for layer, position (starting from zero) 
1085 wxTabControl 
*wxTabView::FindTabControlForPosition(int layer
, int position
) const 
1087   wxTabLayerList::compatibility_iterator node1 
= m_layers
.Item(layer
); 
1089     return (wxTabControl 
*) NULL
; 
1090   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node1
->GetData(); 
1091   wxList::compatibility_iterator node2 
= tabLayer
->Item(position
); 
1093     return (wxTabControl 
*) NULL
; 
1094   return (wxTabControl 
*)node2
->GetData(); 
1097 // Find the node and the column at which this control is positioned. 
1098 wxList::compatibility_iterator 
wxTabView::FindTabNodeAndColumn(wxTabControl 
*control
, int *col
) const 
1100   wxTabLayerList::compatibility_iterator node1 
= m_layers
.GetFirst(); 
1103     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->GetData(); 
1105     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
1108       wxTabControl 
*cnt 
= (wxTabControl 
*)node2
->GetData(); 
1114       node2 
= node2
->GetNext(); 
1117     node1 
= node1
->GetNext(); 
1119   return wxList::compatibility_iterator(); 
1122 int wxTabView::CalculateTabWidth(int noTabs
, bool adjustView
) 
1124   m_tabWidth 
= (int)((m_tabViewRect
.width 
- ((noTabs 
- 1)*GetHorizontalTabSpacing()))/noTabs
); 
1127     m_tabViewRect
.width 
= noTabs
*m_tabWidth 
+ ((noTabs
-1)*GetHorizontalTabSpacing()); 
1136 IMPLEMENT_CLASS(wxTabbedDialog
, wxDialog
) 
1138 BEGIN_EVENT_TABLE(wxTabbedDialog
, wxDialog
) 
1139     EVT_CLOSE(wxTabbedDialog::OnCloseWindow
) 
1140     EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent
) 
1141     EVT_PAINT(wxTabbedDialog::OnPaint
) 
1144 wxTabbedDialog::wxTabbedDialog(wxWindow 
*parent
, wxWindowID id
, 
1145     const wxString
& title
, 
1146     const wxPoint
& pos
, const wxSize
& size
, 
1147     long windowStyle
, const wxString
& name
): 
1148    wxDialog(parent
, id
, title
, pos
, size
, windowStyle
, name
) 
1150   m_tabView 
= (wxTabView 
*) NULL
; 
1153 wxTabbedDialog::~wxTabbedDialog(void) 
1159 void wxTabbedDialog::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
) ) 
1164 void wxTabbedDialog::OnMouseEvent(wxMouseEvent
& event 
) 
1167     m_tabView
->OnEvent(event
); 
1170 void wxTabbedDialog::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1174         m_tabView
->Draw(dc
); 
1181 IMPLEMENT_CLASS(wxTabbedPanel
, wxPanel
) 
1183 BEGIN_EVENT_TABLE(wxTabbedPanel
, wxPanel
) 
1184     EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent
) 
1185     EVT_PAINT(wxTabbedPanel::OnPaint
) 
1188 wxTabbedPanel::wxTabbedPanel(wxWindow 
*parent
, wxWindowID id
, const wxPoint
& pos
, 
1189    const wxSize
& size
, long windowStyle
, const wxString
& name
): 
1190    wxPanel(parent
, id
, pos
, size
, windowStyle
, name
) 
1192   m_tabView 
= (wxTabView 
*) NULL
; 
1195 wxTabbedPanel::~wxTabbedPanel(void) 
1200 void wxTabbedPanel::OnMouseEvent(wxMouseEvent
& event
) 
1203     m_tabView
->OnEvent(event
); 
1206 void wxTabbedPanel::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1210         m_tabView
->Draw(dc
); 
1217 IMPLEMENT_CLASS(wxPanelTabView
, wxTabView
) 
1219 wxPanelTabView::wxPanelTabView(wxPanel 
*pan
, long style
) 
1223   m_currentWindow 
= (wxWindow 
*) NULL
; 
1225   if (m_panel
->IsKindOf(CLASSINFO(wxTabbedDialog
))) 
1226     ((wxTabbedDialog 
*)m_panel
)->SetTabView(this); 
1227   else if (m_panel
->IsKindOf(CLASSINFO(wxTabbedPanel
))) 
1228     ((wxTabbedPanel 
*)m_panel
)->SetTabView(this); 
1233 wxPanelTabView::~wxPanelTabView(void) 
1238 // Called when a tab is activated 
1239 void wxPanelTabView::OnTabActivate(int activateId
, int deactivateId
) 
1244   wxWindow 
*oldWindow 
= ((deactivateId 
== -1) ? 0 : GetTabWindow(deactivateId
)); 
1245   wxWindow 
*newWindow 
= GetTabWindow(activateId
); 
1248     oldWindow
->Show(false); 
1250     newWindow
->Show(true); 
1256 void wxPanelTabView::AddTabWindow(int id
, wxWindow 
*window
) 
1258   wxASSERT(m_tabWindows
.find(id
) == m_tabWindows
.end()); 
1259   m_tabWindows
[id
] = window
; 
1260   window
->Show(false); 
1263 wxWindow 
*wxPanelTabView::GetTabWindow(int id
) const 
1265   wxIntToWindowHashMap::const_iterator it 
= m_tabWindows
.find(id
); 
1266   return it 
== m_tabWindows
.end() ? NULL 
: it
->second
; 
1269 void wxPanelTabView::ClearWindows(bool deleteWindows
) 
1272     WX_CLEAR_HASH_MAP(wxIntToWindowHashMap
, m_tabWindows
); 
1273   m_tabWindows
.clear(); 
1276 void wxPanelTabView::ShowWindowForTab(int id
) 
1278   wxWindow 
*newWindow 
= GetTabWindow(id
); 
1279   if (newWindow 
== m_currentWindow
) 
1281   if (m_currentWindow
) 
1282     m_currentWindow
->Show(false); 
1283   newWindow
->Show(true); 
1284   newWindow
->Refresh(); 
1287 #endif // wxUSE_TAB_DIALOG