1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Generic tabbed dialogs 
   4 // Author:      Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "tabg.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  34 // not defined: use old, square tab implementation (fills in tabs) 
  35 // defined: use new, rounded tab implementation (doesn't colour in tabs) 
  36 // #define wxUSE_NEW_METHOD 
  38 IMPLEMENT_DYNAMIC_CLASS(wxTabControl
, wxObject
) 
  40 IMPLEMENT_DYNAMIC_CLASS(wxTabLayer
, wxList
) 
  42 wxTabControl::wxTabControl(wxTabView 
*v
) 
  55 wxTabControl::~wxTabControl(void) 
  59 void wxTabControl::OnDraw(wxDC
& dc
, bool lastInRow
) 
  61     // Old, but in some ways better (drawing opaque tabs) 
  62 #ifndef wxUSE_NEW_METHOD 
  66   // Top-left of tab view area 
  67   int viewX 
= m_view
->GetViewRect().x
; 
  68   int viewY 
= m_view
->GetViewRect().y
; 
  70   // Top-left of tab control 
  71   int tabX 
= GetX() + viewX
; 
  72   int tabY 
= GetY() + viewY
; 
  76     tabHeightInc 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
  80   dc
.SetPen(*wxTRANSPARENT_PEN
); 
  82   // Draw grey background 
  83   if (m_view
->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
  85     dc
.SetBrush(*m_view
->GetBackgroundBrush()); 
  87     // Add 1 because the pen is transparent. Under Motif, may be different. 
  89     dc
.DrawRectangle(tabX
, tabY
, (GetWidth()+1), (GetHeight() + tabHeightInc
)); 
  91     dc
.DrawRectangle(tabX
, tabY
, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc
)); 
  95   // Draw highlight and shadow 
  96   dc
.SetPen(*m_view
->GetHighlightPen()); 
  98   // Calculate the top of the tab beneath. It's the height of the tab, MINUS 
  99   // a bit if the tab below happens to be selected. Check. 
 100   wxTabControl 
*tabBeneath 
= NULL
; 
 101   int subtractThis 
= 0; 
 102   if (GetColPosition() > 0) 
 103     tabBeneath 
= m_view
->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition()); 
 104   if (tabBeneath 
&& tabBeneath
->IsSelected()) 
 105     subtractThis 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
 107   // Vertical highlight: if first tab, draw to bottom of view 
 108   if (tabX 
== m_view
->GetViewRect().x 
&& (m_view
->GetTabStyle() & wxTAB_STYLE_DRAW_BOX
)) 
 109     dc
.DrawLine(tabX
, tabY
, tabX
, (m_view
->GetViewRect().y 
+ m_view
->GetViewRect().height
)); 
 110   else if (tabX 
== m_view
->GetViewRect().x
) 
 111     // Not box drawing, just to top of view. 
 112     dc
.DrawLine(tabX
, tabY
, tabX
, (m_view
->GetViewRect().y
)); 
 114     dc
.DrawLine(tabX
, tabY
, tabX
, (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 116   dc
.DrawLine(tabX
, tabY
, (tabX 
+ GetWidth()), tabY
); 
 117   dc
.SetPen(*m_view
->GetShadowPen()); 
 119   // Test if we're outside the right-hand edge of the view area 
 120   if (((tabX 
+ GetWidth()) >= m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width
) && (m_view
->GetTabStyle() & wxTAB_STYLE_DRAW_BOX
)) 
 122     int bottomY 
= m_view
->GetViewRect().y 
+ m_view
->GetViewRect().height 
+ GetY() + m_view
->GetTabHeight() + m_view
->GetTopMargin(); 
 123     // Add a tab height since we wish to draw to the bottom of the view. 
 124     dc
.DrawLine((tabX 
+ GetWidth()), tabY
, 
 125       (tabX 
+ GetWidth()), bottomY
); 
 127     // Calculate the far-right of the view, since we don't wish to 
 129     int rightOfView 
= m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width 
+ 1; 
 131     // Draw the horizontal bit to connect to the view rectangle 
 132     dc
.DrawLine((wxMax((tabX 
+ GetWidth() - m_view
->GetHorizontalTabOffset()), rightOfView
)), (bottomY
-1), 
 133       (tabX 
+ GetWidth()), (bottomY
-1)); 
 135     // Draw black line to emphasize shadow 
 136     dc
.SetPen(*wxBLACK_PEN
); 
 137     dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), 
 138       (tabX 
+ GetWidth() + 1), bottomY
); 
 140     // Draw the horizontal bit to connect to the view rectangle 
 141     dc
.DrawLine((wxMax((tabX 
+ GetWidth() - m_view
->GetHorizontalTabOffset()), rightOfView
)), (bottomY
), 
 142       (tabX 
+ GetWidth() + 1), (bottomY
)); 
 148       // 25/5/97 UNLESS it's less than the max number of positions in this row 
 150       int topY 
= m_view
->GetViewRect().y 
- m_view
->GetTopMargin(); 
 152       int maxPositions 
= ((wxTabLayer 
*)m_view
->GetLayers().Nth(0)->Data())->Number(); 
 154       // Only down to the bottom of the tab, not to the top of the view 
 155       if ( GetRowPosition() < (maxPositions 
- 1) ) 
 156         topY 
= tabY 
+ GetHeight() + tabHeightInc
; 
 163       dc
.DrawLine((tabX 
+ GetWidth()), tabY
, (tabX 
+ GetWidth()), topY
); 
 164       // Draw black line to emphasize shadow 
 165       dc
.SetPen(*wxBLACK_PEN
); 
 166       dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), (tabX 
+ GetWidth() + 1), 
 171       // Calculate the top of the tab beneath. It's the height of the tab, MINUS 
 172       // a bit if the tab below (and next col along) happens to be selected. Check. 
 173       wxTabControl 
*tabBeneath 
= NULL
; 
 174       int subtractThis 
= 0; 
 175       if (GetColPosition() > 0) 
 176         tabBeneath 
= m_view
->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1); 
 177       if (tabBeneath 
&& tabBeneath
->IsSelected()) 
 178         subtractThis 
= (m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight()); 
 184       // Draw only to next tab down. 
 185       dc
.DrawLine((tabX 
+ GetWidth()), tabY
, 
 186          (tabX 
+ GetWidth()), (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 188       // Draw black line to emphasize shadow 
 189       dc
.SetPen(*wxBLACK_PEN
); 
 190       dc
.DrawLine((tabX 
+ GetWidth() + 1), (tabY
+1), (tabX 
+ GetWidth() + 1), 
 191          (tabY 
+ GetHeight() + tabHeightInc 
- subtractThis
)); 
 195   // Draw centered text 
 196   int textY 
= tabY 
+ m_view
->GetVerticalTabTextSpacing() + tabHeightInc
; 
 199     dc
.SetFont(* m_view
->GetSelectedTabFont()); 
 201     dc
.SetFont(* GetFont()); 
 203   wxColour 
col(m_view
->GetTextColour()); 
 204   dc
.SetTextForeground(col
); 
 205   dc
.SetBackgroundMode(wxTRANSPARENT
); 
 206   long textWidth
, textHeight
; 
 207   dc
.GetTextExtent(GetLabel(), &textWidth
, &textHeight
); 
 209   int textX 
= (int)(tabX 
+ (GetWidth() - textWidth
)/2.0); 
 210   if (textX 
< (tabX 
+ 2)) 
 213   dc
.SetClippingRegion(tabX
, tabY
, GetWidth(), GetHeight()); 
 214   dc
.DrawText(GetLabel(), textX
, textY
); 
 215   dc
.DestroyClippingRegion(); 
 219     dc
.SetPen(*m_view
->GetHighlightPen()); 
 221     // Draw white highlight from the tab's left side to the left hand edge of the view 
 222     dc
.DrawLine(m_view
->GetViewRect().x
, (tabY 
+ GetHeight() + tabHeightInc
), 
 223      tabX
, (tabY 
+ GetHeight() + tabHeightInc
)); 
 225     // Draw white highlight from the tab's right side to the right hand edge of the view 
 226     dc
.DrawLine((tabX 
+ GetWidth()), (tabY 
+ GetHeight() + tabHeightInc
), 
 227      m_view
->GetViewRect().x 
+ m_view
->GetViewRect().width
, (tabY 
+ GetHeight() + tabHeightInc
)); 
 230     // New HEL version with rounder tabs 
 237         tabInc 
= m_view
->GetTabSelectionHeight() - m_view
->GetTabHeight(); 
 239     int tabLeft  
= GetX() + m_view
->GetViewRect().x
; 
 240     int tabTop   
= GetY() + m_view
->GetViewRect().y 
- tabInc
; 
 241     int tabRight 
= tabLeft 
+ m_view
->GetTabWidth(); 
 242     int left     
= m_view
->GetViewRect().x
; 
 243     int top      
= tabTop 
+ m_view
->GetTabHeight() + tabInc
; 
 244     int right    
= left 
+ m_view
->GetViewRect().width
; 
 245     int bottom   
= top 
+ m_view
->GetViewRect().height
; 
 249         // TAB is selected - draw TAB and the View's full outline 
 251         dc
.SetPen(*(m_view
->GetHighlightPen())); 
 254         pnts
[n
].x 
= left
;            pnts
[n
++].y 
= bottom
; 
 255         pnts
[n
].x 
= left
;             pnts
[n
++].y 
= top
; 
 256         pnts
[n
].x 
= tabLeft
;         pnts
[n
++].y 
= top
; 
 257         pnts
[n
].x 
= tabLeft
;            pnts
[n
++].y 
= tabTop 
+ 2; 
 258         pnts
[n
].x 
= tabLeft 
+ 2;        pnts
[n
++].y 
= tabTop
; 
 259         pnts
[n
].x 
= tabRight 
- 1;    pnts
[n
++].y 
= tabTop
; 
 260         dc
.DrawLines(n
, pnts
); 
 271         dc
.SetPen(*(m_view
->GetShadowPen())); 
 291         dc
.SetPen(*wxBLACK_PEN
); 
 333         // TAB is not selected - just draw TAB outline and RH edge 
 334         // if the TAB is the last in the row 
 336         int maxPositions 
= ((wxTabLayer
*)m_view
->GetLayers().Nth(0)->Data())->Number(); 
 337         wxTabControl
* tabBelow 
= 0; 
 338         wxTabControl
* tabBelowRight 
= 0; 
 339         if (GetColPosition() > 0) 
 341             tabBelow 
= m_view
->FindTabControlForPosition( 
 342                         GetColPosition() - 1, 
 346         if (!lastInRow 
&& GetColPosition() > 0) 
 348             tabBelowRight 
= m_view
->FindTabControlForPosition( 
 349                         GetColPosition() - 1, 
 354         float raisedTop 
= top 
- m_view
->GetTabSelectionHeight() + 
 355                             m_view
->GetTabHeight(); 
 357         dc
.SetPen(*(m_view
->GetHighlightPen())); 
 363         if (tabBelow 
&& tabBelow
->IsSelected()) 
 365             pnts
[n
++].y 
= (long)raisedTop
; 
 371         pnts
[n
].x 
= tabLeft
;            pnts
[n
++].y 
= tabTop 
+ 2; 
 372         pnts
[n
].x 
= tabLeft 
+ 2;        pnts
[n
++].y 
= tabTop
; 
 373         pnts
[n
].x 
= tabRight 
- 1;    pnts
[n
++].y 
= tabTop
; 
 374         dc
.DrawLines(n
, pnts
); 
 376         dc
.SetPen(*(m_view
->GetShadowPen())); 
 377         if (GetRowPosition() >= maxPositions 
- 1) 
 388                     (tabRight 
- m_view
->GetHorizontalTabOffset()), 
 394             if (tabBelowRight 
&& tabBelowRight
->IsSelected()) 
 414         dc
.SetPen(*wxBLACK_PEN
); 
 423         if (GetRowPosition() >= maxPositions 
- 1) 
 425             // draw right hand edge to bottom of view 
 435                     (tabRight 
- m_view
->GetHorizontalTabOffset()), 
 441             // draw right hand edge of TAB 
 442             if (tabBelowRight 
&& tabBelowRight
->IsSelected()) 
 446                         (long)(raisedTop 
- 1), 
 463     // Draw centered text 
 464     dc
.SetPen(*wxBLACK_PEN
); 
 467         dc
.SetFont(*(m_view
->GetSelectedTabFont())); 
 471         dc
.SetFont(*(GetFont())); 
 474     wxColour 
col(m_view
->GetTextColour()); 
 475     dc
.SetTextForeground(col
); 
 476     dc
.SetBackgroundMode(wxTRANSPARENT
); 
 477     long textWidth
, textHeight
; 
 478     dc
.GetTextExtent(GetLabel(), &textWidth
, &textHeight
); 
 480     float textX 
= (tabLeft 
+ tabRight 
- textWidth
) / 2; 
 481     float textY 
= (tabInc 
+ tabTop 
+ m_view
->GetVerticalTabTextSpacing()); 
 483     dc
.DrawText(GetLabel(), (long)textX
, (long)textY
); 
 487 bool wxTabControl::HitTest(int x
, int y
) const 
 489   // Top-left of tab control 
 490   int tabX1 
= GetX() + m_view
->GetViewRect().x
; 
 491   int tabY1 
= GetY() + m_view
->GetViewRect().y
; 
 494   int tabX2 
= tabX1 
+ GetWidth(); 
 495   int tabY2 
= tabY1 
+ GetHeight(); 
 497   if (x 
>= tabX1 
&& y 
>= tabY1 
&& x 
<= tabX2 
&& y 
<= tabY2
) 
 503 IMPLEMENT_DYNAMIC_CLASS(wxTabView
, wxObject
) 
 505 wxTabView::wxTabView(long style
) 
 511   m_tabSelectionHeight 
= m_tabHeight 
+ 2; 
 513   m_tabHorizontalOffset 
= 10; 
 514   m_tabHorizontalSpacing 
= 2; 
 515   m_tabVerticalTextSpacing 
= 3; 
 517   m_tabViewRect
.x 
= 20; 
 518   m_tabViewRect
.y 
= 20; 
 519   m_tabViewRect
.width 
= 300; 
 520   m_tabViewRect
.x 
= 300; 
 521   m_highlightColour 
= *wxWHITE
; 
 522   m_shadowColour 
= wxColour(128, 128, 128); 
 523   m_backgroundColour 
= *wxLIGHT_GREY
; 
 524   m_textColour 
= *wxBLACK
; 
 525   m_highlightPen 
= wxWHITE_PEN
; 
 526   m_shadowPen 
= wxGREY_PEN
; 
 527   m_backgroundPen 
= wxLIGHT_GREY_PEN
; 
 528   m_backgroundBrush 
= wxLIGHT_GREY_BRUSH
; 
 529   m_tabFont 
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
); 
 530   m_tabSelectedFont 
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
); 
 531   m_window 
= (wxWindow 
*) NULL
; 
 534 wxTabView::~wxTabView() 
 539 // Automatically positions tabs 
 540 // TODO: this should just add the tab to a list, and then 
 541 // a layout function (e.g. Realize) should be called when all tabs have been added. 
 542 // The view rect could easily change as the view window is resized. 
 543 wxTabControl 
*wxTabView::AddTab(int id
, const wxString
& label
, wxTabControl 
*existingTab
) 
 545   // First, find which layer we should be adding to. 
 546   wxNode 
*node 
= m_layers
.Last(); 
 549     wxTabLayer 
*newLayer 
= new wxTabLayer
; 
 550     node 
= m_layers
.Append(newLayer
); 
 552   // Check if adding another tab control would go off the 
 553   // right-hand edge of the layer. 
 554   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node
->Data(); 
 555   wxNode 
*lastTabNode 
= tabLayer
->Last(); 
 558     wxTabControl 
*lastTab 
= (wxTabControl 
*)lastTabNode
->Data(); 
 559     // Start another layer (row). 
 560     // Tricky choice: can't just check if will be overlapping the edge, because 
 561     // this happens anyway for 2nd and subsequent rows. 
 562     // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 564     if (((tabLayer 
== m_layers
.First()->Data()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 565               > GetViewRect().width
)) || 
 566         ((tabLayer 
!= m_layers
.First()->Data()) && (tabLayer
->Number() == ((wxTabLayer 
*)m_layers
.First()->Data())->Number()))) 
 568       tabLayer 
= new wxTabLayer
; 
 569       m_layers
.Append(tabLayer
); 
 570       lastTabNode 
= (wxNode 
*) NULL
; 
 573   int layer 
= m_layers
.Number() - 1; 
 575   wxTabControl 
*tabControl 
= existingTab
; 
 577     tabControl 
= OnCreateTabControl(); 
 578   tabControl
->SetRowPosition(tabLayer
->Number()); 
 579   tabControl
->SetColPosition(layer
); 
 581   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 583     lastTab 
= (wxTabControl 
*)lastTabNode
->Data(); 
 586   int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 587   // Offset from view top-left 
 588   int horizontalOffset 
= 0; 
 590     horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 592     horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 594   tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 595   tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 596   tabControl
->SetId(id
); 
 597   tabControl
->SetLabel(label
); 
 598   tabControl
->SetFont(* GetTabFont()); 
 600   tabLayer
->Append(tabControl
); 
 606 // Remove the tab without deleting the window 
 607 bool wxTabView::RemoveTab(int id
) 
 609   wxNode 
*layerNode 
= m_layers
.First(); 
 612     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->Data(); 
 613     wxNode 
*tabNode 
= layer
->First(); 
 616       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->Data(); 
 617       if (tab
->GetId() == id
) 
 619         if (id 
== m_tabSelection
) 
 625         // The layout has changed 
 629       tabNode 
= tabNode
->Next(); 
 631     layerNode 
= layerNode
->Next(); 
 636 bool wxTabView::SetTabText(int id
, const wxString
& label
) 
 638     wxTabControl
* control 
= FindTabControlForId(id
); 
 641     control
->SetLabel(label
); 
 645 wxString 
wxTabView::GetTabText(int id
) const 
 647     wxTabControl
* control 
= FindTabControlForId(id
); 
 649       return wxEmptyString
; 
 651       return control
->GetLabel(); 
 654 // Returns the total height of the tabs component -- this may be several 
 655 // times the height of a tab, if there are several tab layers (rows). 
 656 int wxTabView::GetTotalTabHeight() 
 660   wxNode 
*layerNode 
= m_layers
.First(); 
 663     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->Data(); 
 664     wxNode 
*tabNode 
= layer
->First(); 
 667       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->Data(); 
 669       if (tab
->GetY() < minY
) 
 672       tabNode 
= tabNode
->Next(); 
 674     layerNode 
= layerNode
->Next(); 
 680 void wxTabView::ClearTabs(bool deleteTabs
) 
 682   wxNode 
*layerNode 
= m_layers
.First(); 
 685     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->Data(); 
 686     wxNode 
*tabNode 
= layer
->First(); 
 689       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->Data(); 
 692       wxNode 
*next 
= tabNode
->Next(); 
 696     wxNode 
*nextLayerNode 
= layerNode
->Next(); 
 699     layerNode 
= nextLayerNode
; 
 706 // Layout tabs (optional, e.g. if resizing window) 
 707 void wxTabView::LayoutTabs(void) 
 709   // Make a list of the tab controls, deleting the wxTabLayers. 
 712   wxNode 
*layerNode 
= m_layers
.First(); 
 715     wxTabLayer 
*layer 
= (wxTabLayer 
*)layerNode
->Data(); 
 716     wxNode 
*tabNode 
= layer
->First(); 
 719       wxTabControl 
*tab 
= (wxTabControl 
*)tabNode
->Data(); 
 720       controls
.Append(tab
); 
 721       wxNode 
*next 
= tabNode
->Next(); 
 725     wxNode 
*nextLayerNode 
= layerNode
->Next(); 
 728     layerNode 
= nextLayerNode
; 
 731   wxTabControl 
*lastTab 
= (wxTabControl 
*) NULL
; 
 733   wxTabLayer 
*currentLayer 
= new wxTabLayer
; 
 734   m_layers
.Append(currentLayer
); 
 736   wxNode 
*node 
= controls
.First(); 
 739     wxTabControl 
*tabControl 
= (wxTabControl 
*)node
->Data(); 
 742       // Start another layer (row). 
 743       // Tricky choice: can't just check if will be overlapping the edge, because 
 744       // this happens anyway for 2nd and subsequent rows. 
 745       // Should check this for 1st row, and then subsequent rows should not exceed 1st 
 747       if (((currentLayer 
== m_layers
.First()->Data()) && ((lastTab
->GetX() + 2*lastTab
->GetWidth() + GetHorizontalTabSpacing()) 
 748                 > GetViewRect().width
)) || 
 749           ((currentLayer 
!= m_layers
.First()->Data()) && (currentLayer
->Number() == ((wxTabLayer 
*)m_layers
.First()->Data())->Number()))) 
 751        currentLayer 
= new wxTabLayer
; 
 752        m_layers
.Append(currentLayer
); 
 753        lastTab 
= (wxTabControl 
*) NULL
; 
 757     int layer 
= m_layers
.Number() - 1; 
 759     tabControl
->SetRowPosition(currentLayer
->Number()); 
 760     tabControl
->SetColPosition(layer
); 
 763     int verticalOffset 
= (- GetTopMargin()) - ((layer
+1)*GetTabHeight()); 
 764     // Offset from view top-left 
 765     int horizontalOffset 
= 0; 
 767       horizontalOffset 
= layer
*GetHorizontalTabOffset(); 
 769       horizontalOffset 
= lastTab
->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); 
 771     tabControl
->SetPosition(horizontalOffset
, verticalOffset
); 
 772     tabControl
->SetSize(GetTabWidth(), GetTabHeight()); 
 774     currentLayer
->Append(tabControl
); 
 775     lastTab 
= tabControl
; 
 780   // Move the selected tab to the bottom 
 781   wxTabControl 
*control 
= FindTabControlForId(m_tabSelection
); 
 783     MoveSelectionTab(control
); 
 788 void wxTabView::Draw(wxDC
& dc
) 
 790         // Don't draw anything if there are no tabs. 
 791         if (GetNumberOfTabs() == 0) 
 794     // Draw top margin area (beneath tabs and above view area) 
 795     if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR
) 
 797         dc
.SetPen(*wxTRANSPARENT_PEN
); 
 798         dc
.SetBrush(*GetBackgroundBrush()); 
 800         // Add 1 because the pen is transparent. Under Motif, may be different. 
 803                 (m_tabViewRect
.y 
- m_topMargin
), 
 804                 (m_tabViewRect
.width 
+ 1), 
 809     // Draw layers in reverse order 
 810     wxNode 
*node 
= m_layers
.Last(); 
 813         wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->Data(); 
 814         wxNode 
*node2 
= layer
->First(); 
 817             wxTabControl 
*control 
= (wxTabControl 
*)node2
->Data(); 
 818             control
->OnDraw(dc
, (node2
->Next() == NULL
)); 
 819             node2 
= node2
->Next(); 
 822         node 
= node
->Previous(); 
 826 #ifndef wxUSE_NEW_METHOD 
 827     if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX
) 
 829         dc
.SetPen(* GetShadowPen()); 
 833                 (GetViewRect().x 
+ 1), 
 834                 (GetViewRect().y 
+ GetViewRect().height
), 
 835                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 836                 (GetViewRect().y 
+ GetViewRect().height
) 
 841                 (GetViewRect().x 
+ GetViewRect().width
), 
 842                 (GetViewRect().y 
- GetTopMargin() + 1), 
 843                 (GetViewRect().x 
+ GetViewRect().width
), 
 844                 (GetViewRect().y 
+ GetViewRect().height
) 
 847         dc
.SetPen(* wxBLACK_PEN
); 
 852                 (GetViewRect().y 
+ GetViewRect().height 
+ 1), 
 853 #if defined(__WXMOTIF__) 
 854                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 856                 (GetViewRect().x 
+ GetViewRect().width 
+ 2), 
 859                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 864                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 865                 (GetViewRect().y 
- GetTopMargin()), 
 866                 (GetViewRect().x 
+ GetViewRect().width 
+ 1), 
 867                 (GetViewRect().y 
+ GetViewRect().height 
+ 1) 
 873 // Process mouse event, return FALSE if we didn't process it 
 874 bool wxTabView::OnEvent(wxMouseEvent
& event
) 
 876   if (!event
.LeftDown()) 
 880   event
.GetPosition(&x
, &y
); 
 882   wxTabControl 
*hitControl 
= (wxTabControl 
*) NULL
; 
 884   wxNode 
*node 
= m_layers
.First(); 
 887     wxTabLayer 
*layer 
= (wxTabLayer 
*)node
->Data(); 
 888     wxNode 
*node2 
= layer
->First(); 
 891       wxTabControl 
*control 
= (wxTabControl 
*)node2
->Data(); 
 892       if (control
->HitTest((int)x
, (int)y
)) 
 894         hitControl 
= control
; 
 895         node 
= (wxNode 
*) NULL
; 
 896         node2 
= (wxNode 
*) NULL
; 
 899         node2 
= node2
->Next(); 
 909   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 911   if (hitControl 
== currentTab
) 
 914   ChangeTab(hitControl
); 
 919 bool wxTabView::ChangeTab(wxTabControl 
*control
) 
 921   wxTabControl 
*currentTab 
= FindTabControlForId(m_tabSelection
); 
 924     oldTab 
= currentTab
->GetId(); 
 926   if (control 
== currentTab
) 
 929   if (m_layers
.Number() == 0) 
 932   if (!OnTabPreActivate(control
->GetId(), oldTab
)) 
 935   // Move the tab to the bottom 
 936   MoveSelectionTab(control
); 
 939     currentTab
->SetSelected(FALSE
); 
 941   control
->SetSelected(TRUE
); 
 942   m_tabSelection 
= control
->GetId(); 
 944   OnTabActivate(control
->GetId(), oldTab
); 
 946   // Leave window refresh for the implementing window 
 951 // Move the selected tab to the bottom layer, if necessary, 
 952 // without calling app activation code 
 953 bool wxTabView::MoveSelectionTab(wxTabControl 
*control
) 
 955   if (m_layers
.Number() == 0) 
 958   wxTabLayer 
*firstLayer 
= (wxTabLayer 
*)m_layers
.First()->Data(); 
 960   // Find what column this tab is at, so we can swap with the one at the bottom. 
 961   // If we're on the bottom layer, then no need to swap. 
 962   if (!firstLayer
->Member(control
)) 
 966     wxNode 
*thisNode 
= FindTabNodeAndColumn(control
, &col
); 
 969     wxNode 
*otherNode 
= firstLayer
->Nth(col
); 
 973     // If this is already in the bottom layer, return now 
 974     if (otherNode 
== thisNode
) 
 977     wxTabControl 
*otherTab 
= (wxTabControl 
*)otherNode
->Data(); 
 979     // We now have pointers to the tab to be changed to, 
 980     // and the tab on the first layer. Swap tab structures and 
 983     int thisX 
= control
->GetX(); 
 984     int thisY 
= control
->GetY(); 
 985     int thisColPos 
= control
->GetColPosition(); 
 986     int otherX 
= otherTab
->GetX(); 
 987     int otherY 
= otherTab
->GetY(); 
 988     int otherColPos 
= otherTab
->GetColPosition(); 
 990     control
->SetPosition(otherX
, otherY
); 
 991     control
->SetColPosition(otherColPos
); 
 992     otherTab
->SetPosition(thisX
, thisY
); 
 993     otherTab
->SetColPosition(thisColPos
); 
 995     // Swap the data for the nodes 
 996     thisNode
->SetData(otherTab
); 
 997     otherNode
->SetData(control
); 
1002 // Called when a tab is activated 
1003 void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/) 
1007 void wxTabView::SetHighlightColour(const wxColour
& col
) 
1009   m_highlightColour 
= col
; 
1010   m_highlightPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1013 void wxTabView::SetShadowColour(const wxColour
& col
) 
1015   m_shadowColour 
= col
; 
1016   m_shadowPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1019 void wxTabView::SetBackgroundColour(const wxColour
& col
) 
1021   m_backgroundColour 
= col
; 
1022   m_backgroundPen 
= wxThePenList
->FindOrCreatePen(col
, 1, wxSOLID
); 
1023   m_backgroundBrush 
= wxTheBrushList
->FindOrCreateBrush(col
, wxSOLID
); 
1026 void wxTabView::SetTabSelection(int sel
, bool activateTool
) 
1028   if ( sel
==m_tabSelection 
) 
1031   int oldSel 
= m_tabSelection
; 
1032   wxTabControl 
*control 
= FindTabControlForId(sel
); 
1033   wxTabControl 
*oldControl 
= FindTabControlForId(m_tabSelection
); 
1035   if (!OnTabPreActivate(sel
, oldSel
)) 
1039     control
->SetSelected((sel 
!= -1)); // TODO ?? 
1042     wxFAIL_MSG(_("Could not find tab for id")); 
1047     oldControl
->SetSelected(FALSE
); 
1049   m_tabSelection 
= sel
; 
1052     MoveSelectionTab(control
); 
1055     OnTabActivate(sel
, oldSel
); 
1058 // Find tab control for id 
1059 wxTabControl 
*wxTabView::FindTabControlForId(int id
) const 
1061   wxNode 
*node1 
= m_layers
.First(); 
1064     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->Data(); 
1065     wxNode 
*node2 
= layer
->First(); 
1068       wxTabControl 
*control 
= (wxTabControl 
*)node2
->Data(); 
1069       if (control
->GetId() == id
) 
1071       node2 
= node2
->Next(); 
1073     node1 
= node1
->Next(); 
1075   return (wxTabControl 
*) NULL
; 
1078 // Find tab control for layer, position (starting from zero) 
1079 wxTabControl 
*wxTabView::FindTabControlForPosition(int layer
, int position
) const 
1081   wxNode 
*node1 
= m_layers
.Nth(layer
); 
1083     return (wxTabControl 
*) NULL
; 
1084   wxTabLayer 
*tabLayer 
= (wxTabLayer 
*)node1
->Data(); 
1085   wxNode 
*node2 
= tabLayer
->Nth(position
); 
1087     return (wxTabControl 
*) NULL
; 
1088   return (wxTabControl 
*)node2
->Data(); 
1091 // Find the node and the column at which this control is positioned. 
1092 wxNode 
*wxTabView::FindTabNodeAndColumn(wxTabControl 
*control
, int *col
) const 
1094   wxNode 
*node1 
= m_layers
.First(); 
1097     wxTabLayer 
*layer 
= (wxTabLayer 
*)node1
->Data(); 
1099     wxNode 
*node2 
= layer
->First(); 
1102       wxTabControl 
*cnt 
= (wxTabControl 
*)node2
->Data(); 
1108       node2 
= node2
->Next(); 
1111     node1 
= node1
->Next(); 
1113   return (wxNode 
*) NULL
; 
1116 int wxTabView::CalculateTabWidth(int noTabs
, bool adjustView
) 
1118   m_tabWidth 
= (int)((m_tabViewRect
.width 
- ((noTabs 
- 1)*GetHorizontalTabSpacing()))/noTabs
); 
1121     m_tabViewRect
.width 
= noTabs
*m_tabWidth 
+ ((noTabs
-1)*GetHorizontalTabSpacing()); 
1130 IMPLEMENT_CLASS(wxTabbedDialog
, wxDialog
) 
1132 BEGIN_EVENT_TABLE(wxTabbedDialog
, wxDialog
) 
1133     EVT_CLOSE(wxTabbedDialog::OnCloseWindow
) 
1134     EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent
) 
1135     EVT_PAINT(wxTabbedDialog::OnPaint
) 
1138 wxTabbedDialog::wxTabbedDialog(wxWindow 
*parent
, wxWindowID id
, 
1139     const wxString
& title
, 
1140     const wxPoint
& pos
, const wxSize
& size
, 
1141     long windowStyle
, const wxString
& name
): 
1142    wxDialog(parent
, id
, title
, pos
, size
, windowStyle
, name
) 
1144   m_tabView 
= (wxTabView 
*) NULL
; 
1147 wxTabbedDialog::~wxTabbedDialog(void) 
1153 void wxTabbedDialog::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
) ) 
1158 void wxTabbedDialog::OnMouseEvent(wxMouseEvent
& event 
) 
1161     m_tabView
->OnEvent(event
); 
1164 void wxTabbedDialog::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1168         m_tabView
->Draw(dc
); 
1175 IMPLEMENT_CLASS(wxTabbedPanel
, wxPanel
) 
1177 BEGIN_EVENT_TABLE(wxTabbedPanel
, wxPanel
) 
1178     EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent
) 
1179     EVT_PAINT(wxTabbedPanel::OnPaint
) 
1182 wxTabbedPanel::wxTabbedPanel(wxWindow 
*parent
, wxWindowID id
, const wxPoint
& pos
, 
1183    const wxSize
& size
, long windowStyle
, const wxString
& name
): 
1184    wxPanel(parent
, id
, pos
, size
, windowStyle
, name
) 
1186   m_tabView 
= (wxTabView 
*) NULL
; 
1189 wxTabbedPanel::~wxTabbedPanel(void) 
1194 void wxTabbedPanel::OnMouseEvent(wxMouseEvent
& event
) 
1197     m_tabView
->OnEvent(event
); 
1200 void wxTabbedPanel::OnPaint(wxPaintEvent
& WXUNUSED(event
) ) 
1204         m_tabView
->Draw(dc
); 
1211 IMPLEMENT_CLASS(wxPanelTabView
, wxTabView
) 
1213 wxPanelTabView::wxPanelTabView(wxPanel 
*pan
, long style
): wxTabView(style
), m_tabWindows(wxKEY_INTEGER
) 
1216   m_currentWindow 
= (wxWindow 
*) NULL
; 
1218   if (m_panel
->IsKindOf(CLASSINFO(wxTabbedDialog
))) 
1219     ((wxTabbedDialog 
*)m_panel
)->SetTabView(this); 
1220   else if (m_panel
->IsKindOf(CLASSINFO(wxTabbedPanel
))) 
1221     ((wxTabbedPanel 
*)m_panel
)->SetTabView(this); 
1226 wxPanelTabView::~wxPanelTabView(void) 
1231 // Called when a tab is activated 
1232 void wxPanelTabView::OnTabActivate(int activateId
, int deactivateId
) 
1237   wxWindow 
*oldWindow 
= ((deactivateId 
== -1) ? 0 : GetTabWindow(deactivateId
)); 
1238   wxWindow 
*newWindow 
= GetTabWindow(activateId
); 
1241     oldWindow
->Show(FALSE
); 
1243     newWindow
->Show(TRUE
); 
1249 void wxPanelTabView::AddTabWindow(int id
, wxWindow 
*window
) 
1251   m_tabWindows
.Append((long)id
, window
); 
1252   window
->Show(FALSE
); 
1255 wxWindow 
*wxPanelTabView::GetTabWindow(int id
) const 
1257   wxNode 
*node 
= m_tabWindows
.Find((long)id
); 
1259     return (wxWindow 
*) NULL
; 
1260   return (wxWindow 
*)node
->Data(); 
1263 void wxPanelTabView::ClearWindows(bool deleteWindows
) 
1266     m_tabWindows
.DeleteContents(TRUE
); 
1267   m_tabWindows
.Clear(); 
1268   m_tabWindows
.DeleteContents(FALSE
); 
1271 void wxPanelTabView::ShowWindowForTab(int id
) 
1273   wxWindow 
*newWindow 
= GetTabWindow(id
); 
1274   if (newWindow 
== m_currentWindow
) 
1276   if (m_currentWindow
) 
1277     m_currentWindow
->Show(FALSE
); 
1278   newWindow
->Show(TRUE
); 
1279   newWindow
->Refresh();