1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Generic tabbed dialogs 
   4 // Author:      Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  22     #include "wx/settings.h" 
  24     #include "wx/dcclient.h" 
  33 #include "wx/listimpl.cpp" 
  35 WX_DEFINE_LIST(wxTabLayerList
) 
  37 // not defined: use old, square tab implementation (fills in tabs) 
  38 // defined: use new, rounded tab implementation (doesn't colour in tabs) 
  39 // #define wxUSE_NEW_METHOD 
  41 IMPLEMENT_DYNAMIC_CLASS(wxTabControl
, wxObject
) 
  43 // IMPLEMENT_DYNAMIC_CLASS(wxTabLayer, wxList) 
  45 wxTabControl::wxTabControl(wxTabView 
*v
) 
  58 wxTabControl::~wxTabControl(void) 
  62 void wxTabControl::OnDraw(wxDC
& dc
, bool lastInRow
) 
  64     // Old, but in some ways better (drawing opaque tabs) 
  65 #ifndef wxUSE_NEW_METHOD 
  69   // Top-left of tab view area 
  70   int viewX 
= m_view
->GetViewRect().x
; 
  71   int viewY 
= m_view
->GetViewRect().y
; 
  73   // Top-left of tab control 
  74   int tabX 
= GetX() + viewX
; 
  75   int tabY 
= GetY() + viewY
; 
  79     tabHeightInc 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
  83   dc
.SetPen(*wxTRANSPARENT_PEN
); 
  85   // Draw grey background 
  86   if (m_view
->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
  88     dc
.SetBrush(*m_view
->GetBackgroundBrush()); 
  90     // Add 1 because the pen is transparent. Under Motif, may be different. 
  92     dc
.DrawRectangle(tabX
, tabY
, (GetWidth()+1), (GetHeight() + tabHeightInc
)); 
  94     dc
.DrawRectangle(tabX
, tabY
, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc
)); 
  98   // Draw highlight and shadow 
  99   dc
.SetPen(*m_view
->GetHighlightPen()); 
 101   // Calculate the top of the tab beneath. It's the height of the tab, MINUS 
 102   // a bit if the tab below happens to be selected. Check. 
 103   wxTabControl 
*tabBeneath 
= NULL
; 
 104   int subtractThis 
= 0; 
 105   if (GetColPosition() > 0) 
 106     tabBeneath 
= m_view
->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition()); 
 107   if (tabBeneath 
&& tabBeneath
->IsSelected()) 
 108     subtractThis 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
 110   // Vertical highlight: if first tab, draw to bottom of view 
 111   if (tabX 
== m_view
->GetViewRect().x 
&& (m_view
->GetTabStyle() & wxTAB_STYLE_DRAW_BOX
)) 
 112     dc
.DrawLine(tabX
, tabY
, tabX
, (m_view
->GetViewRect().y 
+ m_view
->GetViewRect().height
)); 
 113   else if (tabX 
== m_view
->GetViewRect().x
) 
 114     // Not box drawing, just to top of view. 
 115     dc
.DrawLine(tabX
, tabY
, tabX
, (m_view
->GetViewRect().y
)); 
 117     dc
.DrawLine(tabX
, tabY
, tabX
, (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 119   dc
.DrawLine(tabX
, tabY
, (tabX 
+ GetWidth()), tabY
); 
 120   dc
.SetPen(*m_view
->GetShadowPen()); 
 122   // Test if we're outside the right-hand edge of the view area 
 123   if (((tabX 
+ GetWidth()) >= m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width
) && (m_view
->GetTabStyle() & wxTAB_STYLE_DRAW_BOX
)) 
 125     int bottomY 
= m_view
->GetViewRect().y 
+ m_view
->GetViewRect().height 
+ GetY() + m_view
->GetTabHeight() + m_view
->GetTopMargin(); 
 126     // Add a tab height since we wish to draw to the bottom of the view. 
 127     dc
.DrawLine((tabX 
+ GetWidth()), tabY
, 
 128       (tabX 
+ GetWidth()), bottomY
); 
 130     // Calculate the far-right of the view, since we don't wish to 
 132     int rightOfView 
= m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width 
+ 1; 
 134     // Draw the horizontal bit to connect to the view rectangle 
 135     dc
.DrawLine((wxMax((tabX 
+ GetWidth() - m_view
->GetHorizontalTabOffset()), rightOfView
)), (bottomY
-1), 
 136       (tabX 
+ GetWidth()), (bottomY
-1)); 
 138     // Draw black line to emphasize shadow 
 139     dc
.SetPen(*wxBLACK_PEN
); 
 140     dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), 
 141       (tabX 
+ GetWidth() + 1), bottomY
); 
 143     // Draw the horizontal bit to connect to the view rectangle 
 144     dc
.DrawLine((wxMax((tabX 
+ GetWidth() - m_view
->GetHorizontalTabOffset()), rightOfView
)), (bottomY
), 
 145       (tabX 
+ GetWidth() + 1), (bottomY
)); 
 151       // 25/5/97 UNLESS it's less than the max number of positions in this row 
 153       int topY 
= m_view
->GetViewRect().y 
- m_view
->GetTopMargin(); 
 155       int maxPositions 
= ((wxTabLayer 
*)m_view
->GetLayers().Item(0)->GetData())->GetCount(); 
 157       // Only down to the bottom of the tab, not to the top of the view 
 158       if ( GetRowPosition() < (maxPositions 
- 1) ) 
 159         topY 
= tabY 
+ GetHeight() + tabHeightInc
; 
 166       dc
.DrawLine((tabX 
+ GetWidth()), tabY
, (tabX 
+ GetWidth()), topY
); 
 167       // Draw black line to emphasize shadow 
 168       dc
.SetPen(*wxBLACK_PEN
); 
 169       dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), (tabX 
+ GetWidth() + 1), 
 174       // Calculate the top of the tab beneath. It's the height of the tab, MINUS 
 175       // a bit if the tab below (and next col along) happens to be selected. Check. 
 176       wxTabControl 
*tabBeneath 
= NULL
; 
 177       int subtractThis 
= 0; 
 178       if (GetColPosition() > 0) 
 179         tabBeneath 
= m_view
->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1); 
 180       if (tabBeneath 
&& tabBeneath
->IsSelected()) 
 181         subtractThis 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
 187       // Draw only to next tab down. 
 188       dc
.DrawLine((tabX 
+ GetWidth()), tabY
, 
 189          (tabX 
+ GetWidth()), (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 191       // Draw black line to emphasize shadow 
 192       dc
.SetPen(*wxBLACK_PEN
); 
 193       dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), (tabX 
+ GetWidth() + 1), 
 194          (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 198   // Draw centered text 
 199   int textY 
= tabY 
+ m_view
->GetVerticalTabTextSpacing() + tabHeightInc
; 
 202     dc
.SetFont(* m_view
->GetSelectedTabFont()); 
 204     dc
.SetFont(* GetFont()); 
 206   wxColour 
col(m_view
->GetTextColour()); 
 207   dc
.SetTextForeground(col
); 
 208   dc
.SetBackgroundMode(wxTRANSPARENT
); 
 209   long textWidth
, textHeight
; 
 210   dc
.GetTextExtent(GetLabel(), &textWidth
, &textHeight
); 
 212   int textX 
= (int)(tabX 
+ (GetWidth() - textWidth
)/2.0); 
 213   if (textX 
< (tabX 
+ 2)) 
 216   dc
.SetClippingRegion(tabX
, tabY
, GetWidth(), GetHeight()); 
 217   dc
.DrawText(GetLabel(), textX
, textY
); 
 218   dc
.DestroyClippingRegion(); 
 222     dc
.SetPen(*m_view
->GetHighlightPen()); 
 224     // Draw white highlight from the tab's left side to the left hand edge of the view 
 225     dc
.DrawLine(m_view
->GetViewRect().x
, (tabY 
+ GetHeight() + tabHeightInc
), 
 226      tabX
, (tabY 
+ GetHeight() + tabHeightInc
)); 
 228     // Draw white highlight from the tab's right side to the right hand edge of the view 
 229     dc
.DrawLine((tabX 
+ GetWidth()), (tabY 
+ GetHeight() + tabHeightInc
), 
 230      m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width
, (tabY 
+ GetHeight() + tabHeightInc
)); 
 233     // New HEL version with rounder tabs 
 240         tabInc 
= m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight(); 
 242     int tabLeft  
= GetX() + m_view
->GetViewRect().x
; 
 243     int tabTop   
= GetY() + m_view
->GetViewRect().y 
- tabInc
; 
 244     int tabRight 
= tabLeft 
+ m_view
->GetTabWidth(); 
 245     int left     
= m_view
->GetViewRect().x
; 
 246     int top      
= tabTop 
+ m_view
->GetTabHeight() + tabInc
; 
 247     int right    
= left 
+ m_view
->GetViewRect().width
; 
 248     int bottom   
= top 
+ m_view
->GetViewRect().height
; 
 252         // TAB is selected - draw TAB and the View's full outline 
 254         dc
.SetPen(*(m_view
->GetHighlightPen())); 
 257         pnts
[n
].x 
= left
;            pnts
[n
++].y 
= bottom
; 
 258         pnts
[n
].x 
= left
;             pnts
[n
++].y 
= top
; 
 259         pnts
[n
].x 
= tabLeft
;         pnts
[n
++].y 
= top
; 
 260         pnts
[n
].x 
= tabLeft
;            pnts
[n
++].y 
= tabTop 
+ 2; 
 261         pnts
[n
].x 
= tabLeft 
+ 2;        pnts
[n
++].y 
= tabTop
; 
 262         pnts
[n
].x 
= tabRight 
- 1;    pnts
[n
++].y 
= tabTop
; 
 263         dc
.DrawLines(n
, pnts
); 
 274         dc
.SetPen(*(m_view
->GetShadowPen())); 
 294         dc
.SetPen(*wxBLACK_PEN
); 
 336         // TAB is not selected - just draw TAB outline and RH edge 
 337         // if the TAB is the last in the row 
 339         int maxPositions 
= ((wxTabLayer
*)m_view
->GetLayers().Item(0)->GetData())->GetCount(); 
 340         wxTabControl
* tabBelow 
= 0; 
 341         wxTabControl
* tabBelowRight 
= 0; 
 342         if (GetColPosition() > 0) 
 344             tabBelow 
= m_view
->FindTabControlForPosition( 
 345                         GetColPosition() - 1, 
 349         if (!lastInRow 
&& GetColPosition() > 0) 
 351             tabBelowRight 
= m_view
->FindTabControlForPosition( 
 352                         GetColPosition() - 1, 
 357         float raisedTop 
= top 
- m_view
->GetTabSelectionHeight() + 
 358                             m_view
->GetTabHeight(); 
 360         dc
.SetPen(*(m_view
->GetHighlightPen())); 
 366         if (tabBelow 
&& tabBelow
->IsSelected()) 
 368             pnts
[n
++].y 
= (long)raisedTop
; 
 374         pnts
[n
].x 
= tabLeft
;            pnts
[n
++].y 
= tabTop 
+ 2; 
 375         pnts
[n
].x 
= tabLeft 
+ 2;        pnts
[n
++].y 
= tabTop
; 
 376         pnts
[n
].x 
= tabRight 
- 1;    pnts
[n
++].y 
= tabTop
; 
 377         dc
.DrawLines(n
, pnts
); 
 379         dc
.SetPen(*(m_view
->GetShadowPen())); 
 380         if (GetRowPosition() >= maxPositions 
- 1) 
 391                     (tabRight 
- m_view
->GetHorizontalTabOffset()), 
 397             if (tabBelowRight 
&& tabBelowRight
->IsSelected()) 
 417         dc
.SetPen(*wxBLACK_PEN
); 
 426         if (GetRowPosition() >= maxPositions 
- 1) 
 428             // draw right hand edge to bottom of view 
 438                     (tabRight 
- m_view
->GetHorizontalTabOffset()), 
 444             // draw right hand edge of TAB 
 445             if (tabBelowRight 
&& tabBelowRight
->IsSelected()) 
 449                         (long)(raisedTop 
- 1), 
 466     // Draw centered text 
 467     dc
.SetPen(*wxBLACK_PEN
); 
 470         dc
.SetFont(*(m_view
->GetSelectedTabFont())); 
 474         dc
.SetFont(*(GetFont())); 
 477     wxColour 
col(m_view
->GetTextColour()); 
 478     dc
.SetTextForeground(col
); 
 479     dc
.SetBackgroundMode(wxTRANSPARENT
); 
 480     long textWidth
, textHeight
; 
 481     dc
.GetTextExtent(GetLabel(), &textWidth
, &textHeight
); 
 483     float textX 
= (tabLeft 
+ tabRight 
- textWidth
) / 2; 
 484     float textY 
= (tabInc 
+ tabTop 
+ m_view
->GetVerticalTabTextSpacing()); 
 486     dc
.DrawText(GetLabel(), (long)textX
, (long)textY
); 
 490 bool wxTabControl::HitTest(int x
, int y
) const 
 492   // Top-left of tab control 
 493   int tabX1 
= GetX() + m_view
->GetViewRect().x
; 
 494   int tabY1 
= GetY() + m_view
->GetViewRect().y
; 
 497   int tabX2 
= tabX1 
+ GetWidth(); 
 498   int tabY2 
= tabY1 
+ GetHeight(); 
 500   if (x 
>= tabX1 
&& y 
>= tabY1 
&& x 
<= tabX2 
&& y 
<= tabY2
) 
 506 IMPLEMENT_DYNAMIC_CLASS(wxTabView
, wxObject
) 
 508 wxTabView::wxTabView(long style
) 
 514   m_tabSelectionHeight 
= m_tabHeight 
+ 2; 
 516   m_tabHorizontalOffset 
= 10; 
 517   m_tabHorizontalSpacing 
= 2; 
 518   m_tabVerticalTextSpacing 
= 3; 
 520   m_tabViewRect
.x 
= 20; 
 521   m_tabViewRect
.y 
= 20; 
 522   m_tabViewRect
.width 
= 300; 
 523   m_tabViewRect
.x 
= 300; 
 524   m_highlightColour 
= *wxWHITE
; 
 525   m_shadowColour 
= wxColour(128, 128, 128); 
 526   m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
); 
 527   m_textColour 
= *wxBLACK
; 
 528   m_highlightPen 
= wxWHITE_PEN
; 
 529   m_shadowPen 
= wxGREY_PEN
; 
 530   SetBackgroundColour(m_backgroundColour
); 
 531   m_tabFont 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 532   m_tabSelectedFont 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 533   m_window 
= (wxWindow 
*) NULL
; 
 536 wxTabView::~wxTabView() 
 541 // Automatically positions tabs 
 542 // TODO: this should just add the tab to a list, and then 
 543 // a layout function (e.g. Realize) should be called when all tabs have been added. 
 544 // The view rect could easily change as the view window is resized. 
 545 wxTabControl 
*wxTabView::AddTab(int id
, const wxString
& label
, wxTabControl 
*existingTab
) 
 547   // First, find which layer we should be adding to. 
 548   wxTabLayerList::compatibility_iterator node 
= m_layers
.GetLast(); 
 551     wxTabLayer 
*newLayer 
= new wxTabLayer
; 
 552     node 
= m_layers
.Append(newLayer
); 
 554   // Check if adding another tab control would go off the 
 555   // right-hand edge of the layer. 
 556   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node
->GetData(); 
 557   wxList::compatibility_iterator lastTabNode 
= tabLayer
->GetLast(); 
 560     wxTabControl 
*lastTab 
= (wxTabControl 
*)lastTabNode
->GetData(); 
 561     // Start another layer (row). 
 562     // Tricky choice: can't just check if will be overlapping the edge, because 
 563     // this happens anyway for 2nd and subsequent rows. 
 564     // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 566     if (((tabLayer 
== m_layers
.GetFirst()->GetData()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 567               > GetViewRect().width
)) || 
 568         ((tabLayer 
!= m_layers
.GetFirst()->GetData()) && (tabLayer
->GetCount() == ((wxTabLayer 
*)m_layers
.GetFirst()->GetData())->GetCount()))) 
 570       tabLayer 
= new wxTabLayer
; 
 571       m_layers
.Append(tabLayer
); 
 572       lastTabNode 
= wxList::compatibility_iterator(); 
 575   int layer 
= m_layers
.GetCount() - 1; 
 577   wxTabControl 
*tabControl 
= existingTab
; 
 579     tabControl 
= OnCreateTabControl(); 
 580   tabControl
->SetRowPosition(tabLayer
->GetCount()); 
 581   tabControl
->SetColPosition(layer
); 
 583   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 585     lastTab 
= (wxTabControl 
*)lastTabNode
->GetData(); 
 588   int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 589   // Offset from view top-left 
 590   int horizontalOffset 
= 0; 
 592     horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 594     horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 596   tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 597   tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 598   tabControl
->SetId(id
); 
 599   tabControl
->SetLabel(label
); 
 600   tabControl
->SetFont(* GetTabFont()); 
 602   tabLayer
->Append(tabControl
); 
 608 // Remove the tab without deleting the window 
 609 bool wxTabView::RemoveTab(int id
) 
 611   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 614     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 615     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 618       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 619       if (tab
->GetId() == id
) 
 621         if (id 
== m_tabSelection
) 
 624         layer
->Erase(tabNode
); 
 627         // The layout has changed 
 631       tabNode 
= tabNode
->GetNext(); 
 633     layerNode 
= layerNode
->GetNext(); 
 638 bool wxTabView::SetTabText(int id
, const wxString
& label
) 
 640     wxTabControl
* control 
= FindTabControlForId(id
); 
 643     control
->SetLabel(label
); 
 647 wxString 
wxTabView::GetTabText(int id
) const 
 649     wxTabControl
* control 
= FindTabControlForId(id
); 
 651       return wxEmptyString
; 
 653       return control
->GetLabel(); 
 656 // Returns the total height of the tabs component -- this may be several 
 657 // times the height of a tab, if there are several tab layers (rows). 
 658 int wxTabView::GetTotalTabHeight() 
 662   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 665     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 666     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 669       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 671       if (tab
->GetY() < minY
) 
 674       tabNode 
= tabNode
->GetNext(); 
 676     layerNode 
= layerNode
->GetNext(); 
 682 void wxTabView::ClearTabs(bool deleteTabs
) 
 684   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 687     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 688     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 691       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 694       wxList::compatibility_iterator next 
= tabNode
->GetNext(); 
 695       layer
->Erase(tabNode
); 
 698     wxTabLayerList::compatibility_iterator nextLayerNode 
= layerNode
->GetNext(); 
 700     m_layers
.Erase(layerNode
); 
 701     layerNode 
= nextLayerNode
; 
 708 // Layout tabs (optional, e.g. if resizing window) 
 709 void wxTabView::LayoutTabs(void) 
 711   // Make a list of the tab controls, deleting the wxTabLayers. 
 714   wxTabLayerList::compatibility_iterator layerNode 
= m_layers
.GetFirst(); 
 717     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->GetData(); 
 718     wxList::compatibility_iterator tabNode 
= layer
->GetFirst(); 
 721       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->GetData(); 
 722       controls
.Append(tab
); 
 723       wxList::compatibility_iterator next 
= tabNode
->GetNext(); 
 724       layer
->Erase(tabNode
); 
 727     wxTabLayerList::compatibility_iterator nextLayerNode 
= layerNode
->GetNext(); 
 729     m_layers
.Erase(layerNode
); 
 730     layerNode 
= nextLayerNode
; 
 733   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 735   wxTabLayer 
*currentLayer 
= new wxTabLayer
; 
 736   m_layers
.Append(currentLayer
); 
 738   wxList::compatibility_iterator node 
= controls
.GetFirst(); 
 741     wxTabControl 
*tabControl 
= (wxTabControl 
*)node
->GetData(); 
 744       // Start another layer (row). 
 745       // Tricky choice: can't just check if will be overlapping the edge, because 
 746       // this happens anyway for 2nd and subsequent rows. 
 747       // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 749       if (((currentLayer 
== m_layers
.GetFirst()->GetData()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 750                 > GetViewRect().width
)) || 
 751           ((currentLayer 
!= m_layers
.GetFirst()->GetData()) && (currentLayer
->GetCount() == ((wxTabLayer 
*)m_layers
.GetFirst()->GetData())->GetCount()))) 
 753        currentLayer 
= new wxTabLayer
; 
 754        m_layers
.Append(currentLayer
); 
 755        lastTab 
= (wxTabControl 
*) NULL
; 
 759     int layer 
= m_layers
.GetCount() - 1; 
 761     tabControl
->SetRowPosition(currentLayer
->GetCount()); 
 762     tabControl
->SetColPosition(layer
); 
 765     int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 766     // Offset from view top-left 
 767     int horizontalOffset 
= 0; 
 769       horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 771       horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 773     tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 774     tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 776     currentLayer
->Append(tabControl
); 
 777     lastTab 
= tabControl
; 
 779     node 
= node
->GetNext(); 
 782   // Move the selected tab to the bottom 
 783   wxTabControl 
*control 
= FindTabControlForId(m_tabSelection
); 
 785     MoveSelectionTab(control
); 
 790 void wxTabView::Draw(wxDC
& dc
) 
 792         // Don't draw anything if there are no tabs. 
 793         if (GetNumberOfTabs() == 0) 
 796     // Draw top margin area (beneath tabs and above view area) 
 797     if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
 799         dc
.SetPen(*wxTRANSPARENT_PEN
); 
 800         dc
.SetBrush(*GetBackgroundBrush()); 
 802         // Add 1 because the pen is transparent. Under Motif, may be different. 
 805                 (m_tabViewRect
.y 
- m_topMargin
), 
 806                 (m_tabViewRect
.width 
+ 1), 
 811     // Draw layers in reverse order 
 812     wxTabLayerList::compatibility_iterator node 
= m_layers
.GetLast(); 
 815         wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->GetData(); 
 816         wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
 819             wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
 820             control
->OnDraw(dc
, (!node2
->GetNext())); 
 821             node2 
= node2
->GetNext(); 
 824         node 
= node
->GetPrevious(); 
 828 #ifndef wxUSE_NEW_METHOD 
 829     if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX
) 
 831         dc
.SetPen(* GetShadowPen()); 
 835                 (GetViewRect().x 
+ 1), 
 836                 (GetViewRect().y 
+ GetViewRect().height
), 
 837                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 838                 (GetViewRect().y 
+ GetViewRect().height
) 
 843                 (GetViewRect().x 
+ GetViewRect().width
), 
 844                 (GetViewRect().y 
- GetTopMargin() + 1), 
 845                 (GetViewRect().x 
+ GetViewRect().width
), 
 846                 (GetViewRect().y 
+ GetViewRect().height
) 
 849         dc
.SetPen(* wxBLACK_PEN
); 
 854                 (GetViewRect().y 
+ GetViewRect().height 
+ 1), 
 855 #if defined(__WXMOTIF__) 
 856                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 858                 (GetViewRect().x 
+ GetViewRect().width 
+ 2), 
 861                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 866                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 867                 (GetViewRect().y 
- GetTopMargin()), 
 868                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 869                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 875 // Process mouse event, return false if we didn't process it 
 876 bool wxTabView::OnEvent(wxMouseEvent
& event
) 
 878   if (!event
.LeftDown()) 
 882   event
.GetPosition(&x
, &y
); 
 884   wxTabControl 
*hitControl 
= (wxTabControl 
*) NULL
; 
 886   wxTabLayerList::compatibility_iterator node 
= m_layers
.GetFirst(); 
 889     wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->GetData(); 
 890     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
 893       wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
 894       if (control
->HitTest((int)x
, (int)y
)) 
 896         hitControl 
= control
; 
 897         node 
= wxTabLayerList::compatibility_iterator(); 
 898         node2 
= wxList::compatibility_iterator(); 
 901         node2 
= node2
->GetNext(); 
 905       node 
= node
->GetNext(); 
 911   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 913   if (hitControl 
== currentTab
) 
 916   ChangeTab(hitControl
); 
 921 bool wxTabView::ChangeTab(wxTabControl 
*control
) 
 923   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 926     oldTab 
= currentTab
->GetId(); 
 928   if (control 
== currentTab
) 
 931   if (m_layers
.GetCount() == 0) 
 934   if (!OnTabPreActivate(control
->GetId(), oldTab
)) 
 937   // Move the tab to the bottom 
 938   MoveSelectionTab(control
); 
 941     currentTab
->SetSelected(false); 
 943   control
->SetSelected(true); 
 944   m_tabSelection 
= control
->GetId(); 
 946   OnTabActivate(control
->GetId(), oldTab
); 
 948   // Leave window refresh for the implementing window 
 953 // Move the selected tab to the bottom layer, if necessary, 
 954 // without calling app activation code 
 955 bool wxTabView::MoveSelectionTab(wxTabControl 
*control
) 
 957   if (m_layers
.GetCount() == 0) 
 960   wxTabLayer 
*firstLayer 
= (wxTabLayer 
*)m_layers
.GetFirst()->GetData(); 
 962   // Find what column this tab is at, so we can swap with the one at the bottom. 
 963   // If we're on the bottom layer, then no need to swap. 
 964   if (!firstLayer
->Member(control
)) 
 968     wxList::compatibility_iterator thisNode 
= FindTabNodeAndColumn(control
, &col
); 
 971     wxList::compatibility_iterator otherNode 
= firstLayer
->Item(col
); 
 975     // If this is already in the bottom layer, return now 
 976     if (otherNode 
== thisNode
) 
 979     wxTabControl 
*otherTab 
= (wxTabControl 
*)otherNode
->GetData(); 
 981     // We now have pointers to the tab to be changed to, 
 982     // and the tab on the first layer. Swap tab structures and 
 985     int thisX 
= control
->GetX(); 
 986     int thisY 
= control
->GetY(); 
 987     int thisColPos 
= control
->GetColPosition(); 
 988     int otherX 
= otherTab
->GetX(); 
 989     int otherY 
= otherTab
->GetY(); 
 990     int otherColPos 
= otherTab
->GetColPosition(); 
 992     control
->SetPosition(otherX
, otherY
); 
 993     control
->SetColPosition(otherColPos
); 
 994     otherTab
->SetPosition(thisX
, thisY
); 
 995     otherTab
->SetColPosition(thisColPos
); 
 997     // Swap the data for the nodes 
 998     thisNode
->SetData(otherTab
); 
 999     otherNode
->SetData(control
); 
1004 // Called when a tab is activated 
1005 void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/) 
1009 void wxTabView::SetHighlightColour(const wxColour
& col
) 
1011   m_highlightColour 
= col
; 
1012   m_highlightPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1015 void wxTabView::SetShadowColour(const wxColour
& col
) 
1017   m_shadowColour 
= col
; 
1018   m_shadowPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1021 void wxTabView::SetBackgroundColour(const wxColour
& col
) 
1023   m_backgroundColour 
= col
; 
1024   m_backgroundPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1025   m_backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(col
, wxSOLID
); 
1028 // this may be called with sel = zero (which doesn't match any page) 
1029 // when wxMotif deletes a page 
1030 // so return the first tab... 
1032 void wxTabView::SetTabSelection(int sel
, bool activateTool
) 
1034   if ( sel
==m_tabSelection 
) 
1037   int oldSel 
= m_tabSelection
; 
1038   wxTabControl 
*control 
= FindTabControlForId(sel
); 
1039   if (sel 
== 0) sel
=control
->GetId(); 
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 // this may be called with zero (which doesn't match any page) 
1067 // so return the first control... 
1068 wxTabControl 
*wxTabView::FindTabControlForId(int id
) const 
1070   wxTabLayerList::compatibility_iterator node1 
= m_layers
.GetFirst(); 
1073     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->GetData(); 
1074     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
1077       wxTabControl 
*control 
= (wxTabControl 
*)node2
->GetData(); 
1078       if (control
->GetId() == id 
|| id 
== 0) 
1080       node2 
= node2
->GetNext(); 
1082     node1 
= node1
->GetNext(); 
1084   return (wxTabControl 
*) NULL
; 
1087 // Find tab control for layer, position (starting from zero) 
1088 wxTabControl 
*wxTabView::FindTabControlForPosition(int layer
, int position
) const 
1090   wxTabLayerList::compatibility_iterator node1 
= m_layers
.Item(layer
); 
1092     return (wxTabControl 
*) NULL
; 
1093   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node1
->GetData(); 
1094   wxList::compatibility_iterator node2 
= tabLayer
->Item(position
); 
1096     return (wxTabControl 
*) NULL
; 
1097   return (wxTabControl 
*)node2
->GetData(); 
1100 // Find the node and the column at which this control is positioned. 
1101 wxList::compatibility_iterator 
wxTabView::FindTabNodeAndColumn(wxTabControl 
*control
, int *col
) const 
1103   wxTabLayerList::compatibility_iterator node1 
= m_layers
.GetFirst(); 
1106     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->GetData(); 
1108     wxList::compatibility_iterator node2 
= layer
->GetFirst(); 
1111       wxTabControl 
*cnt 
= (wxTabControl 
*)node2
->GetData(); 
1117       node2 
= node2
->GetNext(); 
1120     node1 
= node1
->GetNext(); 
1122   return wxList::compatibility_iterator(); 
1125 int wxTabView::CalculateTabWidth(int noTabs
, bool adjustView
) 
1127   m_tabWidth 
= (int)((m_tabViewRect
.width 
- ((noTabs 
- 1)*GetHorizontalTabSpacing()))/noTabs
); 
1130     m_tabViewRect
.width 
= noTabs
*m_tabWidth 
+ ((noTabs
-1)*GetHorizontalTabSpacing()); 
1139 IMPLEMENT_CLASS(wxTabbedDialog
, wxDialog
) 
1141 BEGIN_EVENT_TABLE(wxTabbedDialog
, wxDialog
) 
1142     EVT_CLOSE(wxTabbedDialog::OnCloseWindow
) 
1143     EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent
) 
1144     EVT_PAINT(wxTabbedDialog::OnPaint
) 
1147 wxTabbedDialog::wxTabbedDialog(wxWindow 
*parent
, wxWindowID id
, 
1148     const wxString
& title
, 
1149     const wxPoint
& pos
, const wxSize
& size
, 
1150     long windowStyle
, const wxString
& name
): 
1151    wxDialog(parent
, id
, title
, pos
, size
, windowStyle
, name
) 
1153   m_tabView 
= (wxTabView 
*) NULL
; 
1156 wxTabbedDialog::~wxTabbedDialog(void) 
1162 void wxTabbedDialog::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
) ) 
1167 void wxTabbedDialog::OnMouseEvent(wxMouseEvent
& event 
) 
1170     m_tabView
->OnEvent(event
); 
1173 void wxTabbedDialog::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1177         m_tabView
->Draw(dc
); 
1184 IMPLEMENT_CLASS(wxTabbedPanel
, wxPanel
) 
1186 BEGIN_EVENT_TABLE(wxTabbedPanel
, wxPanel
) 
1187     EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent
) 
1188     EVT_PAINT(wxTabbedPanel::OnPaint
) 
1191 wxTabbedPanel::wxTabbedPanel(wxWindow 
*parent
, wxWindowID id
, const wxPoint
& pos
, 
1192    const wxSize
& size
, long windowStyle
, const wxString
& name
): 
1193    wxPanel(parent
, id
, pos
, size
, windowStyle
, name
) 
1195   m_tabView 
= (wxTabView 
*) NULL
; 
1198 wxTabbedPanel::~wxTabbedPanel(void) 
1203 void wxTabbedPanel::OnMouseEvent(wxMouseEvent
& event
) 
1206     m_tabView
->OnEvent(event
); 
1209 void wxTabbedPanel::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1213         m_tabView
->Draw(dc
); 
1220 IMPLEMENT_CLASS(wxPanelTabView
, wxTabView
) 
1222 wxPanelTabView::wxPanelTabView(wxPanel 
*pan
, long style
) 
1226   m_currentWindow 
= (wxWindow 
*) NULL
; 
1228   if (m_panel
->IsKindOf(CLASSINFO(wxTabbedDialog
))) 
1229     ((wxTabbedDialog 
*)m_panel
)->SetTabView(this); 
1230   else if (m_panel
->IsKindOf(CLASSINFO(wxTabbedPanel
))) 
1231     ((wxTabbedPanel 
*)m_panel
)->SetTabView(this); 
1236 wxPanelTabView::~wxPanelTabView(void) 
1241 // Called when a tab is activated 
1242 void wxPanelTabView::OnTabActivate(int activateId
, int deactivateId
) 
1247   wxWindow 
*oldWindow 
= ((deactivateId 
== -1) ? 0 : GetTabWindow(deactivateId
)); 
1248   wxWindow 
*newWindow 
= GetTabWindow(activateId
); 
1251     oldWindow
->Show(false); 
1253     newWindow
->Show(true); 
1259 void wxPanelTabView::AddTabWindow(int id
, wxWindow 
*window
) 
1261   wxASSERT(m_tabWindows
.find(id
) == m_tabWindows
.end()); 
1262   m_tabWindows
[id
] = window
; 
1263   window
->Show(false); 
1266 wxWindow 
*wxPanelTabView::GetTabWindow(int id
) const 
1268   wxIntToWindowHashMap::const_iterator it 
= m_tabWindows
.find(id
); 
1269   return it 
== m_tabWindows
.end() ? NULL 
: it
->second
; 
1272 void wxPanelTabView::ClearWindows(bool deleteWindows
) 
1275     WX_CLEAR_HASH_MAP(wxIntToWindowHashMap
, m_tabWindows
); 
1276   m_tabWindows
.clear(); 
1279 void wxPanelTabView::ShowWindowForTab(int id
) 
1281   wxWindow 
*newWindow 
= GetTabWindow(id
); 
1282   if (newWindow 
== m_currentWindow
) 
1284   if (m_currentWindow
) 
1285     m_currentWindow
->Show(false); 
1286   newWindow
->Show(true); 
1287   newWindow
->Refresh(); 
1290 #endif // wxUSE_TAB_DIALOG