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 
= *wxLIGHT_GREY
; 
 531   m_textColour 
= *wxBLACK
; 
 532   m_highlightPen 
= wxWHITE_PEN
; 
 533   m_shadowPen 
= wxGREY_PEN
; 
 534   m_backgroundPen 
= wxLIGHT_GREY_PEN
; 
 535   m_backgroundBrush 
= wxLIGHT_GREY_BRUSH
; 
 536   m_tabFont 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 537   m_tabSelectedFont 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 538   m_window 
= (wxWindow 
*) NULL
; 
 541 wxTabView::~wxTabView() 
 546 // Automatically positions tabs 
 547 // TODO: this should just add the tab to a list, and then 
 548 // a layout function (e.g. Realize) should be called when all tabs have been added. 
 549 // The view rect could easily change as the view window is resized. 
 550 wxTabControl 
*wxTabView::AddTab(int id
, const wxString
& label
, wxTabControl 
*existingTab
) 
 552   // First, find which layer we should be adding to. 
 553   wxTabLayerList::compatibility_iterator node 
= m_layers
.GetLast(); 
 556     wxTabLayer 
*newLayer 
= new wxTabLayer
; 
 557     node 
= m_layers
.Append(newLayer
); 
 559   // Check if adding another tab control would go off the 
 560   // right-hand edge of the layer. 
 561   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node
->GetData(); 
 562   wxList::compatibility_iterator lastTabNode 
= tabLayer
->GetLast(); 
 565     wxTabControl 
*lastTab 
= (wxTabControl 
*)lastTabNode
->GetData(); 
 566     // Start another layer (row). 
 567     // Tricky choice: can't just check if will be overlapping the edge, because 
 568     // this happens anyway for 2nd and subsequent rows. 
 569     // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 571     if (((tabLayer 
== m_layers
.GetFirst()->GetData()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 572               > GetViewRect().width
)) || 
 573         ((tabLayer 
!= m_layers
.GetFirst()->GetData()) && (tabLayer
->GetCount() == ((wxTabLayer 
*)m_layers
.GetFirst()->GetData())->GetCount()))) 
 575       tabLayer 
= new wxTabLayer
; 
 576       m_layers
.Append(tabLayer
); 
 577       lastTabNode 
= wxList::compatibility_iterator(); 
 580   int layer 
= m_layers
.GetCount() - 1; 
 582   wxTabControl 
*tabControl 
= existingTab
; 
 584     tabControl 
= OnCreateTabControl(); 
 585   tabControl
->SetRowPosition(tabLayer
->GetCount()); 
 586   tabControl
->SetColPosition(layer
); 
 588   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 590     lastTab 
= (wxTabControl 
*)lastTabNode
->GetData(); 
 593   int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 594   // Offset from view top-left 
 595   int horizontalOffset 
= 0; 
 597     horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 599     horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 601   tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 602   tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 603   tabControl
->SetId(id
); 
 604   tabControl
->SetLabel(label
); 
 605   tabControl
->SetFont(* GetTabFont()); 
 607   tabLayer
->Append(tabControl
); 
 613 // Remove the tab without deleting the window 
 614 bool wxTabView::RemoveTab(int id
) 
 616   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 619     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 620     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 623       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 624       if (tab
->GetId() == id
) 
 626         if (id 
== m_tabSelection
) 
 629         layer
->Erase(tabNode
); 
 632         // The layout has changed 
 636       tabNode 
= tabNode
->GetNext(); 
 638     layerNode 
= layerNode
->GetNext(); 
 643 bool wxTabView::SetTabText(int id
, const wxString
& label
) 
 645     wxTabControl
* control 
= FindTabControlForId(id
); 
 648     control
->SetLabel(label
); 
 652 wxString 
wxTabView::GetTabText(int id
) const 
 654     wxTabControl
* control 
= FindTabControlForId(id
); 
 656       return wxEmptyString
; 
 658       return control
->GetLabel(); 
 661 // Returns the total height of the tabs component -- this may be several 
 662 // times the height of a tab, if there are several tab layers (rows). 
 663 int wxTabView::GetTotalTabHeight() 
 667   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 670     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 671     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 674       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 676       if (tab
->GetY() < minY
) 
 679       tabNode 
= tabNode
->GetNext(); 
 681     layerNode 
= layerNode
->GetNext(); 
 687 void wxTabView::ClearTabs(bool deleteTabs
) 
 689   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 692     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 693     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 696       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 699       wxList::compatibility_iterator next 
= tabNode
->GetNext(); 
 700       layer
->Erase(tabNode
); 
 703     wxTabLayerList::compatibility_iterator nextLayerNode 
= layerNode
->GetNext(); 
 705     m_layers
.Erase(layerNode
); 
 706     layerNode 
= nextLayerNode
; 
 713 // Layout tabs (optional, e.g. if resizing window) 
 714 void wxTabView::LayoutTabs(void) 
 716   // Make a list of the tab controls, deleting the wxTabLayers. 
 719   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 722     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 723     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 726       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 727       controls
.Append(tab
); 
 728       wxList::compatibility_iterator next 
= tabNode
->GetNext(); 
 729       layer
->Erase(tabNode
); 
 732     wxTabLayerList::compatibility_iterator nextLayerNode 
= layerNode
->GetNext(); 
 734     m_layers
.Erase(layerNode
); 
 735     layerNode 
= nextLayerNode
; 
 738   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 740   wxTabLayer 
*currentLayer 
= new wxTabLayer
; 
 741   m_layers
.Append(currentLayer
); 
 743   wxList::compatibility_iterator node 
= controls
.GetFirst(); 
 746     wxTabControl 
*tabControl 
= (wxTabControl 
*)node
->GetData(); 
 749       // Start another layer (row). 
 750       // Tricky choice: can't just check if will be overlapping the edge, because 
 751       // this happens anyway for 2nd and subsequent rows. 
 752       // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 754       if (((currentLayer 
== m_layers
.GetFirst()->GetData()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 755                 > GetViewRect().width
)) || 
 756           ((currentLayer 
!= m_layers
.GetFirst()->GetData()) && (currentLayer
->GetCount() == ((wxTabLayer 
*)m_layers
.GetFirst()->GetData())->GetCount()))) 
 758        currentLayer 
= new wxTabLayer
; 
 759        m_layers
.Append(currentLayer
); 
 760        lastTab 
= (wxTabControl 
*) NULL
; 
 764     int layer 
= m_layers
.GetCount() - 1; 
 766     tabControl
->SetRowPosition(currentLayer
->GetCount()); 
 767     tabControl
->SetColPosition(layer
); 
 770     int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 771     // Offset from view top-left 
 772     int horizontalOffset 
= 0; 
 774       horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 776       horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 778     tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 779     tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 781     currentLayer
->Append(tabControl
); 
 782     lastTab 
= tabControl
; 
 784     node 
= node
->GetNext(); 
 787   // Move the selected tab to the bottom 
 788   wxTabControl 
*control 
= FindTabControlForId(m_tabSelection
); 
 790     MoveSelectionTab(control
); 
 795 void wxTabView::Draw(wxDC
& dc
) 
 797         // Don't draw anything if there are no tabs. 
 798         if (GetNumberOfTabs() == 0) 
 801     // Draw top margin area (beneath tabs and above view area) 
 802     if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
 804         dc
.SetPen(*wxTRANSPARENT_PEN
); 
 805         dc
.SetBrush(*GetBackgroundBrush()); 
 807         // Add 1 because the pen is transparent. Under Motif, may be different. 
 810                 (m_tabViewRect
.y 
- m_topMargin
), 
 811                 (m_tabViewRect
.width 
+ 1), 
 816     // Draw layers in reverse order 
 817     wxTabLayerList::compatibility_iterator node 
= m_layers
.GetLast(); 
 820         wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->GetData(); 
 821         wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
 824             wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
 825             control
->OnDraw(dc
, (!node2
->GetNext())); 
 826             node2 
= node2
->GetNext(); 
 829         node 
= node
->GetPrevious(); 
 833 #ifndef wxUSE_NEW_METHOD 
 834     if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX
) 
 836         dc
.SetPen(* GetShadowPen()); 
 840                 (GetViewRect().x 
+ 1), 
 841                 (GetViewRect().y 
+ GetViewRect().height
), 
 842                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 843                 (GetViewRect().y 
+ GetViewRect().height
) 
 848                 (GetViewRect().x 
+ GetViewRect().width
), 
 849                 (GetViewRect().y 
- GetTopMargin() + 1), 
 850                 (GetViewRect().x 
+ GetViewRect().width
), 
 851                 (GetViewRect().y 
+ GetViewRect().height
) 
 854         dc
.SetPen(* wxBLACK_PEN
); 
 859                 (GetViewRect().y 
+ GetViewRect().height 
+ 1), 
 860 #if defined(__WXMOTIF__) 
 861                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 863                 (GetViewRect().x 
+ GetViewRect().width 
+ 2), 
 866                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 871                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 872                 (GetViewRect().y 
- GetTopMargin()), 
 873                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 874                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 880 // Process mouse event, return FALSE if we didn't process it 
 881 bool wxTabView::OnEvent(wxMouseEvent
& event
) 
 883   if (!event
.LeftDown()) 
 887   event
.GetPosition(&x
, &y
); 
 889   wxTabControl 
*hitControl 
= (wxTabControl 
*) NULL
; 
 891   wxTabLayerList::compatibility_iterator node 
= m_layers
.GetFirst(); 
 894     wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->GetData(); 
 895     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
 898       wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
 899       if (control
->HitTest((int)x
, (int)y
)) 
 901         hitControl 
= control
; 
 902         node 
= wxTabLayerList::compatibility_iterator(); 
 903         node2 
= wxList::compatibility_iterator(); 
 906         node2 
= node2
->GetNext(); 
 910       node 
= node
->GetNext(); 
 916   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 918   if (hitControl 
== currentTab
) 
 921   ChangeTab(hitControl
); 
 926 bool wxTabView::ChangeTab(wxTabControl 
*control
) 
 928   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 931     oldTab 
= currentTab
->GetId(); 
 933   if (control 
== currentTab
) 
 936   if (m_layers
.GetCount() == 0) 
 939   if (!OnTabPreActivate(control
->GetId(), oldTab
)) 
 942   // Move the tab to the bottom 
 943   MoveSelectionTab(control
); 
 946     currentTab
->SetSelected(FALSE
); 
 948   control
->SetSelected(TRUE
); 
 949   m_tabSelection 
= control
->GetId(); 
 951   OnTabActivate(control
->GetId(), oldTab
); 
 953   // Leave window refresh for the implementing window 
 958 // Move the selected tab to the bottom layer, if necessary, 
 959 // without calling app activation code 
 960 bool wxTabView::MoveSelectionTab(wxTabControl 
*control
) 
 962   if (m_layers
.GetCount() == 0) 
 965   wxTabLayer 
*firstLayer 
= (wxTabLayer 
*)m_layers
.GetFirst()->GetData(); 
 967   // Find what column this tab is at, so we can swap with the one at the bottom. 
 968   // If we're on the bottom layer, then no need to swap. 
 969   if (!firstLayer
->Member(control
)) 
 973     wxList::compatibility_iterator thisNode 
= FindTabNodeAndColumn(control
, &col
); 
 976     wxList::compatibility_iterator otherNode 
= firstLayer
->Item(col
); 
 980     // If this is already in the bottom layer, return now 
 981     if (otherNode 
== thisNode
) 
 984     wxTabControl 
*otherTab 
= (wxTabControl 
*)otherNode
->GetData(); 
 986     // We now have pointers to the tab to be changed to, 
 987     // and the tab on the first layer. Swap tab structures and 
 990     int thisX 
= control
->GetX(); 
 991     int thisY 
= control
->GetY(); 
 992     int thisColPos 
= control
->GetColPosition(); 
 993     int otherX 
= otherTab
->GetX(); 
 994     int otherY 
= otherTab
->GetY(); 
 995     int otherColPos 
= otherTab
->GetColPosition(); 
 997     control
->SetPosition(otherX
, otherY
); 
 998     control
->SetColPosition(otherColPos
); 
 999     otherTab
->SetPosition(thisX
, thisY
); 
1000     otherTab
->SetColPosition(thisColPos
); 
1002     // Swap the data for the nodes 
1003     thisNode
->SetData(otherTab
); 
1004     otherNode
->SetData(control
); 
1009 // Called when a tab is activated 
1010 void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/) 
1014 void wxTabView::SetHighlightColour(const wxColour
& col
) 
1016   m_highlightColour 
= col
; 
1017   m_highlightPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1020 void wxTabView::SetShadowColour(const wxColour
& col
) 
1022   m_shadowColour 
= col
; 
1023   m_shadowPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1026 void wxTabView::SetBackgroundColour(const wxColour
& col
) 
1028   m_backgroundColour 
= col
; 
1029   m_backgroundPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1030   m_backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(col
, wxSOLID
); 
1033 void wxTabView::SetTabSelection(int sel
, bool activateTool
) 
1035   if ( sel
==m_tabSelection 
) 
1038   int oldSel 
= m_tabSelection
; 
1039   wxTabControl 
*control 
= FindTabControlForId(sel
); 
1040   wxTabControl 
*oldControl 
= FindTabControlForId(m_tabSelection
); 
1042   if (!OnTabPreActivate(sel
, oldSel
)) 
1046     control
->SetSelected((sel 
!= -1)); // TODO ?? 
1049     wxFAIL_MSG(_("Could not find tab for id")); 
1054     oldControl
->SetSelected(FALSE
); 
1056   m_tabSelection 
= sel
; 
1059     MoveSelectionTab(control
); 
1062     OnTabActivate(sel
, oldSel
); 
1065 // Find tab control for id 
1066 wxTabControl 
*wxTabView::FindTabControlForId(int id
) const 
1068   wxTabLayerList::compatibility_iterator node1 
= m_layers
.GetFirst(); 
1071     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->GetData(); 
1072     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
1075       wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
1076       if (control
->GetId() == id
) 
1078       node2 
= node2
->GetNext(); 
1080     node1 
= node1
->GetNext(); 
1082   return (wxTabControl 
*) NULL
; 
1085 // Find tab control for layer, position (starting from zero) 
1086 wxTabControl 
*wxTabView::FindTabControlForPosition(int layer
, int position
) const 
1088   wxTabLayerList::compatibility_iterator node1 
= m_layers
.Item(layer
); 
1090     return (wxTabControl 
*) NULL
; 
1091   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node1
->GetData(); 
1092   wxList::compatibility_iterator node2 
= tabLayer
->Item(position
); 
1094     return (wxTabControl 
*) NULL
; 
1095   return (wxTabControl 
*)node2
->GetData(); 
1098 // Find the node and the column at which this control is positioned. 
1099 wxList::compatibility_iterator 
wxTabView::FindTabNodeAndColumn(wxTabControl 
*control
, int *col
) const 
1101   wxTabLayerList::compatibility_iterator node1 
= m_layers
.GetFirst(); 
1104     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->GetData(); 
1106     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
1109       wxTabControl 
*cnt 
= (wxTabControl 
*)node2
->GetData(); 
1115       node2 
= node2
->GetNext(); 
1118     node1 
= node1
->GetNext(); 
1120   return wxList::compatibility_iterator(); 
1123 int wxTabView::CalculateTabWidth(int noTabs
, bool adjustView
) 
1125   m_tabWidth 
= (int)((m_tabViewRect
.width 
- ((noTabs 
- 1)*GetHorizontalTabSpacing()))/noTabs
); 
1128     m_tabViewRect
.width 
= noTabs
*m_tabWidth 
+ ((noTabs
-1)*GetHorizontalTabSpacing()); 
1137 IMPLEMENT_CLASS(wxTabbedDialog
, wxDialog
) 
1139 BEGIN_EVENT_TABLE(wxTabbedDialog
, wxDialog
) 
1140     EVT_CLOSE(wxTabbedDialog::OnCloseWindow
) 
1141     EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent
) 
1142     EVT_PAINT(wxTabbedDialog::OnPaint
) 
1145 wxTabbedDialog::wxTabbedDialog(wxWindow 
*parent
, wxWindowID id
, 
1146     const wxString
& title
, 
1147     const wxPoint
& pos
, const wxSize
& size
, 
1148     long windowStyle
, const wxString
& name
): 
1149    wxDialog(parent
, id
, title
, pos
, size
, windowStyle
, name
) 
1151   m_tabView 
= (wxTabView 
*) NULL
; 
1154 wxTabbedDialog::~wxTabbedDialog(void) 
1160 void wxTabbedDialog::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
) ) 
1165 void wxTabbedDialog::OnMouseEvent(wxMouseEvent
& event 
) 
1168     m_tabView
->OnEvent(event
); 
1171 void wxTabbedDialog::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1175         m_tabView
->Draw(dc
); 
1182 IMPLEMENT_CLASS(wxTabbedPanel
, wxPanel
) 
1184 BEGIN_EVENT_TABLE(wxTabbedPanel
, wxPanel
) 
1185     EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent
) 
1186     EVT_PAINT(wxTabbedPanel::OnPaint
) 
1189 wxTabbedPanel::wxTabbedPanel(wxWindow 
*parent
, wxWindowID id
, const wxPoint
& pos
, 
1190    const wxSize
& size
, long windowStyle
, const wxString
& name
): 
1191    wxPanel(parent
, id
, pos
, size
, windowStyle
, name
) 
1193   m_tabView 
= (wxTabView 
*) NULL
; 
1196 wxTabbedPanel::~wxTabbedPanel(void) 
1201 void wxTabbedPanel::OnMouseEvent(wxMouseEvent
& event
) 
1204     m_tabView
->OnEvent(event
); 
1207 void wxTabbedPanel::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1211         m_tabView
->Draw(dc
); 
1218 IMPLEMENT_CLASS(wxPanelTabView
, wxTabView
) 
1220 wxPanelTabView::wxPanelTabView(wxPanel 
*pan
, long style
) 
1224   m_currentWindow 
= (wxWindow 
*) NULL
; 
1226   if (m_panel
->IsKindOf(CLASSINFO(wxTabbedDialog
))) 
1227     ((wxTabbedDialog 
*)m_panel
)->SetTabView(this); 
1228   else if (m_panel
->IsKindOf(CLASSINFO(wxTabbedPanel
))) 
1229     ((wxTabbedPanel 
*)m_panel
)->SetTabView(this); 
1234 wxPanelTabView::~wxPanelTabView(void) 
1239 // Called when a tab is activated 
1240 void wxPanelTabView::OnTabActivate(int activateId
, int deactivateId
) 
1245   wxWindow 
*oldWindow 
= ((deactivateId 
== -1) ? 0 : GetTabWindow(deactivateId
)); 
1246   wxWindow 
*newWindow 
= GetTabWindow(activateId
); 
1249     oldWindow
->Show(FALSE
); 
1251     newWindow
->Show(TRUE
); 
1257 void wxPanelTabView::AddTabWindow(int id
, wxWindow 
*window
) 
1259   wxASSERT(m_tabWindows
.find(id
) == m_tabWindows
.end()); 
1260   m_tabWindows
[id
] = window
; 
1261   window
->Show(FALSE
); 
1264 wxWindow 
*wxPanelTabView::GetTabWindow(int id
) const 
1266   wxIntToWindowHashMap::const_iterator it 
= m_tabWindows
.find(id
); 
1267   return it 
== m_tabWindows
.end() ? NULL 
: it
->second
; 
1270 void wxPanelTabView::ClearWindows(bool deleteWindows
) 
1273     WX_CLEAR_HASH_MAP(wxIntToWindowHashMap
, m_tabWindows
); 
1274   m_tabWindows
.clear(); 
1277 void wxPanelTabView::ShowWindowForTab(int id
) 
1279   wxWindow 
*newWindow 
= GetTabWindow(id
); 
1280   if (newWindow 
== m_currentWindow
) 
1282   if (m_currentWindow
) 
1283     m_currentWindow
->Show(FALSE
); 
1284   newWindow
->Show(TRUE
); 
1285   newWindow
->Refresh(); 
1288 #endif // wxUSE_TAB_DIALOG