1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/aui/auibook.cpp
3 // Purpose:     wxaui: wx advanced user interface - notebook
4 // Author:      Benjamin I. Williams
5 // Modified by:
6 // Created:     2006-06-28
7 // Copyright:   (C) Copyright 2006, Kirix Corporation, All Rights Reserved
8 // Licence:     wxWindows Library Licence, Version 3.1
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ----------------------------------------------------------------------------
12 // headers
13 // ----------------------------------------------------------------------------
14 
15 #include "wx/wxprec.h"
16 
17 #ifdef __BORLANDC__
18     #pragma hdrstop
19 #endif
20 
21 #if wxUSE_AUI
22 
23 #include "wx/aui/auibook.h"
24 
25 #ifndef WX_PRECOMP
26     #include "wx/settings.h"
27     #include "wx/image.h"
28     #include "wx/menu.h"
29 #endif
30 
31 #include "wx/aui/tabmdi.h"
32 #include "wx/dcbuffer.h"
33 #include "wx/log.h"
34 
35 #ifdef __WXMSW__
36 #include  "wx/msw/private.h"
37 #endif
38 
39 #ifdef __WXMAC__
40 #include "wx/mac/carbon/private.h"
41 #endif
42 
43 #ifdef __WXGTK__
44 #include <gtk/gtk.h>
45 #include "wx/gtk/win_gtk.h"
46 #endif
47 
48 #include "wx/arrimpl.cpp"
49 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
50 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
51 
52 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE)
53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED)
54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING)
55 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
56 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
57 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
58 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
59 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
60 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND)
61 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK)
62 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE)
63 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP)
64 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN)
65 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP)
66 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN)
67 
68 
69 IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
70 IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl)
71 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
72 
73 
74 
75 
76 // these functions live in dockart.cpp -- they'll eventually
77 // be moved to a new utility cpp file
78 
79 wxColor wxAuiStepColour(const wxColor& c, int percent);
80 
81 wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h,
82                              const wxColour& color);
83 
84 wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size);
85 
DrawButtons(wxDC & dc,const wxRect & _rect,const wxBitmap & bmp,const wxColour & bkcolour,int button_state)86 static void DrawButtons(wxDC& dc,
87                         const wxRect& _rect,
88                         const wxBitmap& bmp,
89                         const wxColour& bkcolour,
90                         int button_state)
91 {
92     wxRect rect = _rect;
93 
94     if (button_state == wxAUI_BUTTON_STATE_PRESSED)
95     {
96         rect.x++;
97         rect.y++;
98     }
99 
100     if (button_state == wxAUI_BUTTON_STATE_HOVER ||
101         button_state == wxAUI_BUTTON_STATE_PRESSED)
102     {
103         dc.SetBrush(wxBrush(wxAuiStepColour(bkcolour, 120)));
104         dc.SetPen(wxPen(wxAuiStepColour(bkcolour, 75)));
105 
106         // draw the background behind the button
107         dc.DrawRectangle(rect.x, rect.y, 15, 15);
108     }
109 
110     // draw the button itself
111     dc.DrawBitmap(bmp, rect.x, rect.y, true);
112 }
113 
IndentPressedBitmap(wxRect * rect,int button_state)114 static void IndentPressedBitmap(wxRect* rect, int button_state)
115 {
116     if (button_state == wxAUI_BUTTON_STATE_PRESSED)
117     {
118         rect->x++;
119         rect->y++;
120     }
121 }
122 
DrawFocusRect(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)123 static void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
124 {
125 #ifdef __WXMSW__
126     wxUnusedVar(win);
127     wxUnusedVar(flags);
128 
129     RECT rc;
130     wxCopyRectToRECT(rect, rc);
131 
132     ::DrawFocusRect(GetHdcOf(dc), &rc);
133 
134 #elif defined(__WXGTK20__)
135     GdkWindow* gdk_window = dc.GetGDKWindow();
136     wxASSERT_MSG( gdk_window,
137                   wxT("cannot draw focus rectangle on wxDC of this type") );
138 
139     GtkStateType state;
140     //if (flags & wxCONTROL_SELECTED)
141     //    state = GTK_STATE_SELECTED;
142     //else
143         state = GTK_STATE_NORMAL;
144 
145     gtk_paint_focus( win->m_widget->style,
146                      gdk_window,
147                      state,
148                      NULL,
149                      win->m_wxwindow,
150                      NULL,
151                      dc.LogicalToDeviceX(rect.x),
152                      dc.LogicalToDeviceY(rect.y),
153                      rect.width,
154                      rect.height );
155 #elif (defined(__WXMAC__))
156 
157 #if wxMAC_USE_CORE_GRAPHICS
158     {
159         CGRect cgrect = CGRectMake( rect.x , rect.y , rect.width, rect.height ) ;
160 
161 #if 0
162         Rect bounds ;
163         win->GetPeer()->GetRect( &bounds ) ;
164 
165         wxLogDebug(wxT("Focus rect %d, %d, %d, %d"), rect.x, rect.y, rect.width, rect.height);
166         wxLogDebug(wxT("Peer rect %d, %d, %d, %d"), bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
167 #endif
168 
169         HIThemeFrameDrawInfo info ;
170         memset( &info, 0 , sizeof(info) ) ;
171 
172         info.version = 0 ;
173         info.kind = 0 ;
174         info.state = kThemeStateActive;
175         info.isFocused = true ;
176 
177         CGContextRef cgContext = (CGContextRef) win->MacGetCGContextRef() ;
178         wxASSERT( cgContext ) ;
179 
180         HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ;
181     }
182  #else
183     {
184         Rect r;
185         r.left = rect.x; r.top = rect.y; r.right = rect.GetRight(); r.bottom = rect.GetBottom();
186         wxTopLevelWindowMac* top = win->MacGetTopLevelWindow();
187         if ( top )
188         {
189             wxPoint pt(0, 0) ;
190             wxMacControl::Convert( &pt , win->GetPeer() , top->GetPeer() ) ;
191             OffsetRect( &r , pt.x , pt.y ) ;
192         }
193 
194         DrawThemeFocusRect( &r , true ) ;
195     }
196 #endif
197 #else
198     wxUnusedVar(win);
199     wxUnusedVar(flags);
200 
201     // draw the pixels manually because the "dots" in wxPen with wxDOT style
202     // may be short traits and not really dots
203     //
204     // note that to behave in the same manner as DrawRect(), we must exclude
205     // the bottom and right borders from the rectangle
206     wxCoord x1 = rect.GetLeft(),
207             y1 = rect.GetTop(),
208             x2 = rect.GetRight(),
209             y2 = rect.GetBottom();
210 
211     dc.SetPen(*wxBLACK_PEN);
212 
213 #ifdef __WXMAC__
214     dc.SetLogicalFunction(wxCOPY);
215 #else
216     // this seems to be closer than what Windows does than wxINVERT although
217     // I'm still not sure if it's correct
218     dc.SetLogicalFunction(wxAND_REVERSE);
219 #endif
220 
221     wxCoord z;
222     for ( z = x1 + 1; z < x2; z += 2 )
223         dc.DrawPoint(z, rect.GetTop());
224 
225     wxCoord shift = z == x2 ? 0 : 1;
226     for ( z = y1 + shift; z < y2; z += 2 )
227         dc.DrawPoint(x2, z);
228 
229     shift = z == y2 ? 0 : 1;
230     for ( z = x2 - shift; z > x1; z -= 2 )
231         dc.DrawPoint(z, y2);
232 
233     shift = z == x1 ? 0 : 1;
234     for ( z = y2 - shift; z > y1; z -= 2 )
235         dc.DrawPoint(x1, z);
236 
237     dc.SetLogicalFunction(wxCOPY);
238 #endif
239 }
240 
241 
242 // -- GUI helper classes and functions --
243 
244 class wxAuiCommandCapture : public wxEvtHandler
245 {
246 public:
247 
wxAuiCommandCapture()248     wxAuiCommandCapture() { m_last_id = 0; }
GetCommandId() const249     int GetCommandId() const { return m_last_id; }
250 
ProcessEvent(wxEvent & evt)251     bool ProcessEvent(wxEvent& evt)
252     {
253         if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
254         {
255             m_last_id = evt.GetId();
256             return true;
257         }
258 
259         if (GetNextHandler())
260             return GetNextHandler()->ProcessEvent(evt);
261 
262         return false;
263     }
264 
265 private:
266     int m_last_id;
267 };
268 
269 
270 // -- bitmaps --
271 
272 #if defined( __WXMAC__ )
273  static unsigned char close_bits[]={
274      0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
275      0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
276      0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
277 #elif defined( __WXGTK__)
278  static unsigned char close_bits[]={
279      0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
280      0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
281      0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
282 #else
283  static unsigned char close_bits[]={
284      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
285      0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
286      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
287 #endif
288 
289 static unsigned char left_bits[] = {
290    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
291    0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
292    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
293 
294 static unsigned char right_bits[] = {
295    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
296    0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
297    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
298 
299 static unsigned char list_bits[] = {
300    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
301    0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
302    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
303 
304 
305 
306 
307 
308 
309 // -- wxAuiDefaultTabArt class implementation --
310 
wxAuiDefaultTabArt()311 wxAuiDefaultTabArt::wxAuiDefaultTabArt()
312 {
313     m_normal_font = *wxNORMAL_FONT;
314     m_selected_font = *wxNORMAL_FONT;
315     m_selected_font.SetWeight(wxBOLD);
316     m_measuring_font = m_selected_font;
317 
318     m_fixed_tab_width = 100;
319     m_tab_ctrl_height = 0;
320 
321 #ifdef __WXMAC__
322     wxBrush toolbarbrush;
323     toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground );
324     wxColor base_colour = toolbarbrush.GetColour();
325 #else
326     wxColor base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
327 #endif
328 
329     // the base_colour is too pale to use as our base colour,
330     // so darken it a bit --
331     if ((255-base_colour.Red()) +
332         (255-base_colour.Green()) +
333         (255-base_colour.Blue()) < 60)
334     {
335         base_colour = wxAuiStepColour(base_colour, 92);
336     }
337 
338     m_base_colour = base_colour;
339     wxColor border_colour = wxAuiStepColour(base_colour, 75);
340 
341     m_border_pen = wxPen(border_colour);
342     m_base_colour_pen = wxPen(m_base_colour);
343     m_base_colour_brush = wxBrush(m_base_colour);
344 
345     m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
346     m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
347 
348     m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
349     m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
350 
351     m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
352     m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
353 
354     m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
355     m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
356 
357     m_flags = 0;
358 }
359 
~wxAuiDefaultTabArt()360 wxAuiDefaultTabArt::~wxAuiDefaultTabArt()
361 {
362 }
363 
Clone()364 wxAuiTabArt* wxAuiDefaultTabArt::Clone()
365 {
366     wxAuiDefaultTabArt* art = new wxAuiDefaultTabArt;
367     art->SetNormalFont(m_normal_font);
368     art->SetSelectedFont(m_selected_font);
369     art->SetMeasuringFont(m_measuring_font);
370 
371     return art;
372 }
373 
SetFlags(unsigned int flags)374 void wxAuiDefaultTabArt::SetFlags(unsigned int flags)
375 {
376     m_flags = flags;
377 }
378 
SetSizingInfo(const wxSize & tab_ctrl_size,size_t tab_count)379 void wxAuiDefaultTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
380                                        size_t tab_count)
381 {
382     m_fixed_tab_width = 100;
383 
384     int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
385 
386     if (m_flags & wxAUI_NB_CLOSE_BUTTON)
387         tot_width -= m_active_close_bmp.GetWidth();
388     if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
389         tot_width -= m_active_windowlist_bmp.GetWidth();
390 
391     if (tab_count > 0)
392     {
393         m_fixed_tab_width = tot_width/(int)tab_count;
394     }
395 
396 
397     if (m_fixed_tab_width < 100)
398         m_fixed_tab_width = 100;
399 
400     if (m_fixed_tab_width > tot_width/2)
401         m_fixed_tab_width = tot_width/2;
402 
403     if (m_fixed_tab_width > 220)
404         m_fixed_tab_width = 220;
405 
406     m_tab_ctrl_height = tab_ctrl_size.y;
407 }
408 
409 
DrawBackground(wxDC & dc,wxWindow * WXUNUSED (wnd),const wxRect & rect)410 void wxAuiDefaultTabArt::DrawBackground(wxDC& dc,
411                                         wxWindow* WXUNUSED(wnd),
412                                         const wxRect& rect)
413 {
414     // draw background
415    wxColor top_color       = wxAuiStepColour(m_base_colour, 90);
416    wxColor bottom_color   = wxAuiStepColour(m_base_colour, 170);
417    wxRect r;
418 
419    if (m_flags &wxAUI_NB_BOTTOM)
420        r = wxRect(rect.x, rect.y, rect.width+2, rect.height);
421    // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
422    // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
423    else //for wxAUI_NB_TOP
424        r = wxRect(rect.x, rect.y, rect.width+2, rect.height-3);
425     dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
426 
427    // draw base lines
428    dc.SetPen(m_border_pen);
429    int y = rect.GetHeight();
430    int w = rect.GetWidth();
431 
432    if (m_flags &wxAUI_NB_BOTTOM)
433    {
434        dc.SetBrush(wxBrush(bottom_color));
435        dc.DrawRectangle(-1, 0, w+2, 4);
436    }
437    // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
438    // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
439    else //for wxAUI_NB_TOP
440    {
441        dc.SetBrush(m_base_colour_brush);
442        dc.DrawRectangle(-1, y-4, w+2, 4);
443    }
444 }
445 
446 
447 // DrawTab() draws an individual tab.
448 //
449 // dc       - output dc
450 // in_rect  - rectangle the tab should be confined to
451 // caption  - tab's caption
452 // active   - whether or not the tab is active
453 // out_rect - actual output rectangle
454 // x_extent - the advance x; where the next tab should start
455 
DrawTab(wxDC & dc,wxWindow * wnd,const wxAuiNotebookPage & page,const wxRect & in_rect,int close_button_state,wxRect * out_tab_rect,wxRect * out_button_rect,int * x_extent)456 void wxAuiDefaultTabArt::DrawTab(wxDC& dc,
457                                  wxWindow* wnd,
458                                  const wxAuiNotebookPage& page,
459                                  const wxRect& in_rect,
460                                  int close_button_state,
461                                  wxRect* out_tab_rect,
462                                  wxRect* out_button_rect,
463                                  int* x_extent)
464 {
465     wxCoord normal_textx, normal_texty;
466     wxCoord selected_textx, selected_texty;
467     wxCoord texty;
468 
469     // if the caption is empty, measure some temporary text
470     wxString caption = page.caption;
471     if (caption.empty())
472         caption = wxT("Xj");
473 
474     dc.SetFont(m_selected_font);
475     dc.GetTextExtent(caption, &selected_textx, &selected_texty);
476 
477     dc.SetFont(m_normal_font);
478     dc.GetTextExtent(caption, &normal_textx, &normal_texty);
479 
480     // figure out the size of the tab
481     wxSize tab_size = GetTabSize(dc,
482                                  wnd,
483                                  page.caption,
484                                  page.bitmap,
485                                  page.active,
486                                  close_button_state,
487                                  x_extent);
488 
489     wxCoord tab_height = m_tab_ctrl_height - 3;
490     wxCoord tab_width = tab_size.x;
491     wxCoord tab_x = in_rect.x;
492     wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
493 
494 
495     caption = page.caption;
496 
497 
498     // select pen, brush and font for the tab to be drawn
499 
500     if (page.active)
501     {
502         dc.SetFont(m_selected_font);
503         texty = selected_texty;
504     }
505      else
506     {
507         dc.SetFont(m_normal_font);
508         texty = normal_texty;
509     }
510 
511 
512     // create points that will make the tab outline
513 
514     int clip_width = tab_width;
515     if (tab_x + clip_width > in_rect.x + in_rect.width)
516         clip_width = (in_rect.x + in_rect.width) - tab_x;
517 
518 /*
519     wxPoint clip_points[6];
520     clip_points[0] = wxPoint(tab_x,              tab_y+tab_height-3);
521     clip_points[1] = wxPoint(tab_x,              tab_y+2);
522     clip_points[2] = wxPoint(tab_x+2,            tab_y);
523     clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y);
524     clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2);
525     clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3);
526 
527     // FIXME: these ports don't provide wxRegion ctor from array of points
528 #if !defined(__WXDFB__) && !defined(__WXCOCOA__)
529     // set the clipping region for the tab --
530     wxRegion clipping_region(WXSIZEOF(clip_points), clip_points);
531     dc.SetClippingRegion(clipping_region);
532 #endif // !wxDFB && !wxCocoa
533 */
534     // since the above code above doesn't play well with WXDFB or WXCOCOA,
535     // we'll just use a rectangle for the clipping region for now --
536     dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3);
537 
538 
539     wxPoint border_points[6];
540     if (m_flags &wxAUI_NB_BOTTOM)
541     {
542        border_points[0] = wxPoint(tab_x,             tab_y);
543        border_points[1] = wxPoint(tab_x,             tab_y+tab_height-6);
544        border_points[2] = wxPoint(tab_x+2,           tab_y+tab_height-4);
545        border_points[3] = wxPoint(tab_x+tab_width-2, tab_y+tab_height-4);
546        border_points[4] = wxPoint(tab_x+tab_width,   tab_y+tab_height-6);
547        border_points[5] = wxPoint(tab_x+tab_width,   tab_y);
548     }
549     else //if (m_flags & wxAUI_NB_TOP) {}
550     {
551        border_points[0] = wxPoint(tab_x,             tab_y+tab_height-4);
552        border_points[1] = wxPoint(tab_x,             tab_y+2);
553        border_points[2] = wxPoint(tab_x+2,           tab_y);
554        border_points[3] = wxPoint(tab_x+tab_width-2, tab_y);
555        border_points[4] = wxPoint(tab_x+tab_width,   tab_y+2);
556        border_points[5] = wxPoint(tab_x+tab_width,   tab_y+tab_height-4);
557     }
558     // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
559     // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
560 
561     int drawn_tab_yoff = border_points[1].y;
562     int drawn_tab_height = border_points[0].y - border_points[1].y;
563 
564 
565     if (page.active)
566     {
567         // draw active tab
568 
569         // draw base background color
570         wxRect r(tab_x, tab_y, tab_width, tab_height);
571         dc.SetPen(m_base_colour_pen);
572         dc.SetBrush(m_base_colour_brush);
573         dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4);
574 
575         // this white helps fill out the gradient at the top of the tab
576         dc.SetPen(*wxWHITE_PEN);
577         dc.SetBrush(*wxWHITE_BRUSH);
578         dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4);
579 
580         // these two points help the rounded corners appear more antialiased
581         dc.SetPen(m_base_colour_pen);
582         dc.DrawPoint(r.x+2, r.y+1);
583         dc.DrawPoint(r.x+r.width-2, r.y+1);
584 
585         // set rectangle down a bit for gradient drawing
586         r.SetHeight(r.GetHeight()/2);
587         r.x += 2;
588         r.width -= 2;
589         r.y += r.height;
590         r.y -= 2;
591 
592         // draw gradient background
593         wxColor top_color = *wxWHITE;
594         wxColor bottom_color = m_base_colour;
595         dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
596     }
597      else
598     {
599         // draw inactive tab
600 
601         wxRect r(tab_x, tab_y+1, tab_width, tab_height-3);
602 
603         // start the gradent up a bit and leave the inside border inset
604         // by a pixel for a 3D look.  Only the top half of the inactive
605         // tab will have a slight gradient
606         r.x += 3;
607         r.y++;
608         r.width -= 4;
609         r.height /= 2;
610         r.height--;
611 
612         // -- draw top gradient fill for glossy look
613         wxColor top_color = m_base_colour;
614         wxColor bottom_color = wxAuiStepColour(top_color, 160);
615         dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
616 
617         r.y += r.height;
618         r.y--;
619 
620         // -- draw bottom fill for glossy look
621         top_color = m_base_colour;
622         bottom_color = m_base_colour;
623         dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
624     }
625 
626     // draw tab outline
627     dc.SetPen(m_border_pen);
628     dc.SetBrush(*wxTRANSPARENT_BRUSH);
629     dc.DrawPolygon(WXSIZEOF(border_points), border_points);
630 
631     // there are two horizontal grey lines at the bottom of the tab control,
632     // this gets rid of the top one of those lines in the tab control
633     if (page.active)
634     {
635        if (m_flags &wxAUI_NB_BOTTOM)
636            dc.SetPen(wxPen(wxColour(wxAuiStepColour(m_base_colour, 170))));
637        // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
638        // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
639        else //for wxAUI_NB_TOP
640            dc.SetPen(m_base_colour_pen);
641         dc.DrawLine(border_points[0].x+1,
642                     border_points[0].y,
643                     border_points[5].x,
644                     border_points[5].y);
645     }
646 
647 
648     int text_offset = tab_x + 8;
649     int close_button_width = 0;
650     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
651     {
652         close_button_width = m_active_close_bmp.GetWidth();
653     }
654 
655 
656     int bitmap_offset = 0;
657     if (page.bitmap.IsOk())
658     {
659         bitmap_offset = tab_x + 8;
660 
661         // draw bitmap
662         dc.DrawBitmap(page.bitmap,
663                       bitmap_offset,
664                       drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
665                       true);
666 
667         text_offset = bitmap_offset + page.bitmap.GetWidth();
668         text_offset += 3; // bitmap padding
669     }
670      else
671     {
672         text_offset = tab_x + 8;
673     }
674 
675 
676     wxString draw_text = wxAuiChopText(dc,
677                           caption,
678                           tab_width - (text_offset-tab_x) - close_button_width);
679 
680     // draw tab text
681     dc.DrawText(draw_text,
682                 text_offset,
683                 drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1);
684 
685     // draw close button if necessary
686     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
687     {
688         wxBitmap bmp = m_disabled_close_bmp;
689 
690         if (close_button_state == wxAUI_BUTTON_STATE_HOVER ||
691             close_button_state == wxAUI_BUTTON_STATE_PRESSED)
692         {
693             bmp = m_active_close_bmp;
694         }
695 
696         int offsetY = tab_y-1;
697         if (m_flags & wxAUI_NB_BOTTOM)
698             offsetY = 1;
699 
700         wxRect rect(tab_x + tab_width - close_button_width - 1,
701                     offsetY + (tab_height/2) - (bmp.GetHeight()/2),
702                     close_button_width,
703                     tab_height);
704 
705         IndentPressedBitmap(&rect, close_button_state);
706         dc.DrawBitmap(bmp, rect.x, rect.y, true);
707 
708         *out_button_rect = rect;
709     }
710 
711     *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
712 
713 #ifndef __WXMAC__
714     // draw focus rectangle
715     if (page.active && (wnd->FindFocus() == wnd))
716     {
717         wxRect focusRectText(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1),
718             selected_textx, selected_texty);
719 
720         wxRect focusRect;
721         wxRect focusRectBitmap;
722 
723         if (page.bitmap.IsOk())
724             focusRectBitmap = wxRect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
725                                             page.bitmap.GetWidth(), page.bitmap.GetHeight());
726 
727         if (page.bitmap.IsOk() && draw_text.IsEmpty())
728             focusRect = focusRectBitmap;
729         else if (!page.bitmap.IsOk() && !draw_text.IsEmpty())
730             focusRect = focusRectText;
731         else if (page.bitmap.IsOk() && !draw_text.IsEmpty())
732             focusRect = focusRectText.Union(focusRectBitmap);
733 
734         focusRect.Inflate(2, 2);
735 
736         DrawFocusRect(wnd, dc, focusRect, 0);
737     }
738 #endif
739 
740     dc.DestroyClippingRegion();
741 }
742 
GetIndentSize()743 int wxAuiDefaultTabArt::GetIndentSize()
744 {
745     return 5;
746 }
747 
GetTabSize(wxDC & dc,wxWindow * WXUNUSED (wnd),const wxString & caption,const wxBitmap & bitmap,bool WXUNUSED (active),int close_button_state,int * x_extent)748 wxSize wxAuiDefaultTabArt::GetTabSize(wxDC& dc,
749                                       wxWindow* WXUNUSED(wnd),
750                                       const wxString& caption,
751                                       const wxBitmap& bitmap,
752                                       bool WXUNUSED(active),
753                                       int close_button_state,
754                                       int* x_extent)
755 {
756     wxCoord measured_textx, measured_texty, tmp;
757 
758     dc.SetFont(m_measuring_font);
759     dc.GetTextExtent(caption, &measured_textx, &measured_texty);
760 
761     dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty);
762 
763     // add padding around the text
764     wxCoord tab_width = measured_textx;
765     wxCoord tab_height = measured_texty;
766 
767     // if the close button is showing, add space for it
768     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
769         tab_width += m_active_close_bmp.GetWidth() + 3;
770 
771     // if there's a bitmap, add space for it
772     if (bitmap.IsOk())
773     {
774         tab_width += bitmap.GetWidth();
775         tab_width += 3; // right side bitmap padding
776         tab_height = wxMax(tab_height, bitmap.GetHeight());
777     }
778 
779     // add padding
780     tab_width += 16;
781     tab_height += 10;
782 
783     if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
784     {
785         tab_width = m_fixed_tab_width;
786     }
787 
788     *x_extent = tab_width;
789 
790     return wxSize(tab_width, tab_height);
791 }
792 
793 
DrawButton(wxDC & dc,wxWindow * WXUNUSED (wnd),const wxRect & in_rect,int bitmap_id,int button_state,int orientation,wxRect * out_rect)794 void wxAuiDefaultTabArt::DrawButton(wxDC& dc,
795                                     wxWindow* WXUNUSED(wnd),
796                                     const wxRect& in_rect,
797                                     int bitmap_id,
798                                     int button_state,
799                                     int orientation,
800                                     wxRect* out_rect)
801 {
802     wxBitmap bmp;
803     wxRect rect;
804 
805     switch (bitmap_id)
806     {
807         case wxAUI_BUTTON_CLOSE:
808             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
809                 bmp = m_disabled_close_bmp;
810                  else
811                 bmp = m_active_close_bmp;
812             break;
813         case wxAUI_BUTTON_LEFT:
814             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
815                 bmp = m_disabled_left_bmp;
816                  else
817                 bmp = m_active_left_bmp;
818             break;
819         case wxAUI_BUTTON_RIGHT:
820             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
821                 bmp = m_disabled_right_bmp;
822                  else
823                 bmp = m_active_right_bmp;
824             break;
825         case wxAUI_BUTTON_WINDOWLIST:
826             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
827                 bmp = m_disabled_windowlist_bmp;
828                  else
829                 bmp = m_active_windowlist_bmp;
830             break;
831     }
832 
833 
834     if (!bmp.IsOk())
835         return;
836 
837     rect = in_rect;
838 
839     if (orientation == wxLEFT)
840     {
841         rect.SetX(in_rect.x);
842         rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
843         rect.SetWidth(bmp.GetWidth());
844         rect.SetHeight(bmp.GetHeight());
845     }
846      else
847     {
848         rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
849                       ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
850                       bmp.GetWidth(), bmp.GetHeight());
851     }
852 
853     IndentPressedBitmap(&rect, button_state);
854     dc.DrawBitmap(bmp, rect.x, rect.y, true);
855 
856     *out_rect = rect;
857 }
858 
859 
ShowDropDown(wxWindow * wnd,const wxAuiNotebookPageArray & pages,int active_idx)860 int wxAuiDefaultTabArt::ShowDropDown(wxWindow* wnd,
861                                      const wxAuiNotebookPageArray& pages,
862                                      int active_idx)
863 {
864     wxMenu menuPopup;
865 
866     size_t i, count = pages.GetCount();
867     for (i = 0; i < count; ++i)
868     {
869         const wxAuiNotebookPage& page = pages.Item(i);
870         wxString caption = page.caption;
871 
872         // if there is no caption, make it a space.  This will prevent
873         // an assert in the menu code.
874         if (caption.IsEmpty())
875             caption = wxT(" ");
876 
877         menuPopup.AppendCheckItem(1000+i, caption);
878     }
879 
880     if (active_idx != -1)
881     {
882         menuPopup.Check(1000+active_idx, true);
883     }
884 
885     // find out where to put the popup menu of window items
886     wxPoint pt = ::wxGetMousePosition();
887     pt = wnd->ScreenToClient(pt);
888 
889     // find out the screen coordinate at the bottom of the tab ctrl
890     wxRect cli_rect = wnd->GetClientRect();
891     pt.y = cli_rect.y + cli_rect.height;
892 
893     wxAuiCommandCapture* cc = new wxAuiCommandCapture;
894     wnd->PushEventHandler(cc);
895     wnd->PopupMenu(&menuPopup, pt);
896     int command = cc->GetCommandId();
897     wnd->PopEventHandler(true);
898 
899     if (command >= 1000)
900         return command-1000;
901 
902     return -1;
903 }
904 
GetBestTabCtrlSize(wxWindow * wnd,const wxAuiNotebookPageArray & pages,const wxSize & required_bmp_size)905 int wxAuiDefaultTabArt::GetBestTabCtrlSize(wxWindow* wnd,
906                                            const wxAuiNotebookPageArray& pages,
907                                            const wxSize& required_bmp_size)
908 {
909     wxClientDC dc(wnd);
910     dc.SetFont(m_measuring_font);
911 
912     // sometimes a standard bitmap size needs to be enforced, especially
913     // if some tabs have bitmaps and others don't.  This is important because
914     // it prevents the tab control from resizing when tabs are added.
915     wxBitmap measure_bmp;
916     if (required_bmp_size.IsFullySpecified())
917     {
918         measure_bmp.Create(required_bmp_size.x,
919                            required_bmp_size.y);
920     }
921 
922 
923     int max_y = 0;
924     size_t i, page_count = pages.GetCount();
925     for (i = 0; i < page_count; ++i)
926     {
927         wxAuiNotebookPage& page = pages.Item(i);
928 
929         wxBitmap bmp;
930         if (measure_bmp.IsOk())
931             bmp = measure_bmp;
932              else
933             bmp = page.bitmap;
934 
935         // we don't use the caption text because we don't
936         // want tab heights to be different in the case
937         // of a very short piece of text on one tab and a very
938         // tall piece of text on another tab
939         int x_ext = 0;
940         wxSize s = GetTabSize(dc,
941                               wnd,
942                               wxT("ABCDEFGHIj"),
943                               bmp,
944                               true,
945                               wxAUI_BUTTON_STATE_HIDDEN,
946                               &x_ext);
947 
948         max_y = wxMax(max_y, s.y);
949     }
950 
951     return max_y+2;
952 }
953 
SetNormalFont(const wxFont & font)954 void wxAuiDefaultTabArt::SetNormalFont(const wxFont& font)
955 {
956     m_normal_font = font;
957 }
958 
SetSelectedFont(const wxFont & font)959 void wxAuiDefaultTabArt::SetSelectedFont(const wxFont& font)
960 {
961     m_selected_font = font;
962 }
963 
SetMeasuringFont(const wxFont & font)964 void wxAuiDefaultTabArt::SetMeasuringFont(const wxFont& font)
965 {
966     m_measuring_font = font;
967 }
968 
969 
970 // -- wxAuiSimpleTabArt class implementation --
971 
wxAuiSimpleTabArt()972 wxAuiSimpleTabArt::wxAuiSimpleTabArt()
973 {
974     m_normal_font = *wxNORMAL_FONT;
975     m_selected_font = *wxNORMAL_FONT;
976     m_selected_font.SetWeight(wxBOLD);
977     m_measuring_font = m_selected_font;
978 
979     m_flags = 0;
980     m_fixed_tab_width = 100;
981 
982     wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
983 
984     wxColour background_colour = base_colour;
985     wxColour normaltab_colour = base_colour;
986     wxColour selectedtab_colour = *wxWHITE;
987 
988     m_bkbrush = wxBrush(background_colour);
989     m_normal_bkbrush = wxBrush(normaltab_colour);
990     m_normal_bkpen = wxPen(normaltab_colour);
991     m_selected_bkbrush = wxBrush(selectedtab_colour);
992     m_selected_bkpen = wxPen(selectedtab_colour);
993 
994     m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
995     m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
996 
997     m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
998     m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
999 
1000     m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
1001     m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
1002 
1003     m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
1004     m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
1005 
1006 }
1007 
~wxAuiSimpleTabArt()1008 wxAuiSimpleTabArt::~wxAuiSimpleTabArt()
1009 {
1010 }
1011 
Clone()1012 wxAuiTabArt* wxAuiSimpleTabArt::Clone()
1013 {
1014     return wx_static_cast(wxAuiTabArt*, new wxAuiSimpleTabArt);
1015 }
1016 
1017 
SetFlags(unsigned int flags)1018 void wxAuiSimpleTabArt::SetFlags(unsigned int flags)
1019 {
1020     m_flags = flags;
1021 }
1022 
SetSizingInfo(const wxSize & tab_ctrl_size,size_t tab_count)1023 void wxAuiSimpleTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
1024                                       size_t tab_count)
1025 {
1026     m_fixed_tab_width = 100;
1027 
1028     int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
1029 
1030     if (m_flags & wxAUI_NB_CLOSE_BUTTON)
1031         tot_width -= m_active_close_bmp.GetWidth();
1032     if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
1033         tot_width -= m_active_windowlist_bmp.GetWidth();
1034 
1035     if (tab_count > 0)
1036     {
1037         m_fixed_tab_width = tot_width/(int)tab_count;
1038     }
1039 
1040 
1041     if (m_fixed_tab_width < 100)
1042         m_fixed_tab_width = 100;
1043 
1044     if (m_fixed_tab_width > tot_width/2)
1045         m_fixed_tab_width = tot_width/2;
1046 
1047     if (m_fixed_tab_width > 220)
1048         m_fixed_tab_width = 220;
1049 }
1050 
DrawBackground(wxDC & dc,wxWindow * WXUNUSED (wnd),const wxRect & rect)1051 void wxAuiSimpleTabArt::DrawBackground(wxDC& dc,
1052                                        wxWindow* WXUNUSED(wnd),
1053                                        const wxRect& rect)
1054 {
1055     // draw background
1056     dc.SetBrush(m_bkbrush);
1057     dc.SetPen(*wxTRANSPARENT_PEN);
1058     dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
1059 
1060     // draw base line
1061     dc.SetPen(*wxGREY_PEN);
1062     dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
1063 }
1064 
1065 
1066 // DrawTab() draws an individual tab.
1067 //
1068 // dc       - output dc
1069 // in_rect  - rectangle the tab should be confined to
1070 // caption  - tab's caption
1071 // active   - whether or not the tab is active
1072 // out_rect - actual output rectangle
1073 // x_extent - the advance x; where the next tab should start
1074 
DrawTab(wxDC & dc,wxWindow * wnd,const wxAuiNotebookPage & page,const wxRect & in_rect,int close_button_state,wxRect * out_tab_rect,wxRect * out_button_rect,int * x_extent)1075 void wxAuiSimpleTabArt::DrawTab(wxDC& dc,
1076                                 wxWindow* wnd,
1077                                 const wxAuiNotebookPage& page,
1078                                 const wxRect& in_rect,
1079                                 int close_button_state,
1080                                 wxRect* out_tab_rect,
1081                                 wxRect* out_button_rect,
1082                                 int* x_extent)
1083 {
1084     wxCoord normal_textx, normal_texty;
1085     wxCoord selected_textx, selected_texty;
1086     wxCoord textx, texty;
1087 
1088     // if the caption is empty, measure some temporary text
1089     wxString caption = page.caption;
1090     if (caption.empty())
1091         caption = wxT("Xj");
1092 
1093     dc.SetFont(m_selected_font);
1094     dc.GetTextExtent(caption, &selected_textx, &selected_texty);
1095 
1096     dc.SetFont(m_normal_font);
1097     dc.GetTextExtent(caption, &normal_textx, &normal_texty);
1098 
1099     // figure out the size of the tab
1100     wxSize tab_size = GetTabSize(dc,
1101                                  wnd,
1102                                  page.caption,
1103                                  page.bitmap,
1104                                  page.active,
1105                                  close_button_state,
1106                                  x_extent);
1107 
1108     wxCoord tab_height = tab_size.y;
1109     wxCoord tab_width = tab_size.x;
1110     wxCoord tab_x = in_rect.x;
1111     wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
1112 
1113     caption = page.caption;
1114 
1115     // select pen, brush and font for the tab to be drawn
1116 
1117     if (page.active)
1118     {
1119         dc.SetPen(m_selected_bkpen);
1120         dc.SetBrush(m_selected_bkbrush);
1121         dc.SetFont(m_selected_font);
1122         textx = selected_textx;
1123         texty = selected_texty;
1124     }
1125      else
1126     {
1127         dc.SetPen(m_normal_bkpen);
1128         dc.SetBrush(m_normal_bkbrush);
1129         dc.SetFont(m_normal_font);
1130         textx = normal_textx;
1131         texty = normal_texty;
1132     }
1133 
1134 
1135     // -- draw line --
1136 
1137     wxPoint points[7];
1138     points[0].x = tab_x;
1139     points[0].y = tab_y + tab_height - 1;
1140     points[1].x = tab_x + tab_height - 3;
1141     points[1].y = tab_y + 2;
1142     points[2].x = tab_x + tab_height + 3;
1143     points[2].y = tab_y;
1144     points[3].x = tab_x + tab_width - 2;
1145     points[3].y = tab_y;
1146     points[4].x = tab_x + tab_width;
1147     points[4].y = tab_y + 2;
1148     points[5].x = tab_x + tab_width;
1149     points[5].y = tab_y + tab_height - 1;
1150     points[6] = points[0];
1151 
1152     dc.SetClippingRegion(in_rect);
1153 
1154     dc.DrawPolygon(WXSIZEOF(points) - 1, points);
1155 
1156     dc.SetPen(*wxGREY_PEN);
1157 
1158     //dc.DrawLines(active ? WXSIZEOF(points) - 1 : WXSIZEOF(points), points);
1159     dc.DrawLines(WXSIZEOF(points), points);
1160 
1161 
1162     int text_offset;
1163 
1164     int close_button_width = 0;
1165     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1166     {
1167         close_button_width = m_active_close_bmp.GetWidth();
1168         text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2);
1169     }
1170      else
1171     {
1172         text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2);
1173     }
1174 
1175     // set minimum text offset
1176     if (text_offset < tab_x + tab_height)
1177         text_offset = tab_x + tab_height;
1178 
1179     // chop text if necessary
1180     wxString draw_text = wxAuiChopText(dc,
1181                           caption,
1182                           tab_width - (text_offset-tab_x) - close_button_width);
1183 
1184     // draw tab text
1185     dc.DrawText(draw_text,
1186                  text_offset,
1187                  (tab_y + tab_height)/2 - (texty/2) + 1);
1188 
1189 
1190 #ifndef __WXMAC__
1191     // draw focus rectangle
1192     if (page.active && (wnd->FindFocus() == wnd))
1193     {
1194         wxRect focusRect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1),
1195             selected_textx, selected_texty);
1196 
1197         focusRect.Inflate(2, 2);
1198 
1199         DrawFocusRect(wnd, dc, focusRect, 0);
1200     }
1201 #endif
1202 
1203     // draw close button if necessary
1204     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1205     {
1206         wxBitmap bmp;
1207         if (page.active)
1208             bmp = m_active_close_bmp;
1209              else
1210             bmp = m_disabled_close_bmp;
1211 
1212         wxRect rect(tab_x + tab_width - close_button_width - 1,
1213                     tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
1214                     close_button_width,
1215                     tab_height - 1);
1216         DrawButtons(dc, rect, bmp, *wxWHITE, close_button_state);
1217 
1218         *out_button_rect = rect;
1219     }
1220 
1221 
1222     *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
1223 
1224     dc.DestroyClippingRegion();
1225 }
1226 
GetIndentSize()1227 int wxAuiSimpleTabArt::GetIndentSize()
1228 {
1229     return 0;
1230 }
1231 
GetTabSize(wxDC & dc,wxWindow * WXUNUSED (wnd),const wxString & caption,const wxBitmap & WXUNUSED (bitmap),bool WXUNUSED (active),int close_button_state,int * x_extent)1232 wxSize wxAuiSimpleTabArt::GetTabSize(wxDC& dc,
1233                                      wxWindow* WXUNUSED(wnd),
1234                                      const wxString& caption,
1235                                      const wxBitmap& WXUNUSED(bitmap),
1236                                      bool WXUNUSED(active),
1237                                      int close_button_state,
1238                                      int* x_extent)
1239 {
1240     wxCoord measured_textx, measured_texty;
1241 
1242     dc.SetFont(m_measuring_font);
1243     dc.GetTextExtent(caption, &measured_textx, &measured_texty);
1244 
1245     wxCoord tab_height = measured_texty + 4;
1246     wxCoord tab_width = measured_textx + tab_height + 5;
1247 
1248     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1249         tab_width += m_active_close_bmp.GetWidth();
1250 
1251     if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
1252     {
1253         tab_width = m_fixed_tab_width;
1254     }
1255 
1256     *x_extent = tab_width - (tab_height/2) - 1;
1257 
1258     return wxSize(tab_width, tab_height);
1259 }
1260 
1261 
DrawButton(wxDC & dc,wxWindow * WXUNUSED (wnd),const wxRect & in_rect,int bitmap_id,int button_state,int orientation,wxRect * out_rect)1262 void wxAuiSimpleTabArt::DrawButton(wxDC& dc,
1263                                    wxWindow* WXUNUSED(wnd),
1264                                    const wxRect& in_rect,
1265                                    int bitmap_id,
1266                                    int button_state,
1267                                    int orientation,
1268                                    wxRect* out_rect)
1269 {
1270     wxBitmap bmp;
1271     wxRect rect;
1272 
1273     switch (bitmap_id)
1274     {
1275         case wxAUI_BUTTON_CLOSE:
1276             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1277                 bmp = m_disabled_close_bmp;
1278                  else
1279                 bmp = m_active_close_bmp;
1280             break;
1281         case wxAUI_BUTTON_LEFT:
1282             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1283                 bmp = m_disabled_left_bmp;
1284                  else
1285                 bmp = m_active_left_bmp;
1286             break;
1287         case wxAUI_BUTTON_RIGHT:
1288             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1289                 bmp = m_disabled_right_bmp;
1290                  else
1291                 bmp = m_active_right_bmp;
1292             break;
1293         case wxAUI_BUTTON_WINDOWLIST:
1294             if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1295                 bmp = m_disabled_windowlist_bmp;
1296                  else
1297                 bmp = m_active_windowlist_bmp;
1298             break;
1299     }
1300 
1301     if (!bmp.IsOk())
1302         return;
1303 
1304     rect = in_rect;
1305 
1306     if (orientation == wxLEFT)
1307     {
1308         rect.SetX(in_rect.x);
1309         rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
1310         rect.SetWidth(bmp.GetWidth());
1311         rect.SetHeight(bmp.GetHeight());
1312     }
1313      else
1314     {
1315         rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
1316                       ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
1317                       bmp.GetWidth(), bmp.GetHeight());
1318     }
1319 
1320 
1321     DrawButtons(dc, rect, bmp, *wxWHITE, button_state);
1322 
1323     *out_rect = rect;
1324 }
1325 
1326 
ShowDropDown(wxWindow * wnd,const wxAuiNotebookPageArray & pages,int active_idx)1327 int wxAuiSimpleTabArt::ShowDropDown(wxWindow* wnd,
1328                                     const wxAuiNotebookPageArray& pages,
1329                                     int active_idx)
1330 {
1331     wxMenu menuPopup;
1332 
1333     size_t i, count = pages.GetCount();
1334     for (i = 0; i < count; ++i)
1335     {
1336         const wxAuiNotebookPage& page = pages.Item(i);
1337         menuPopup.AppendCheckItem(1000+i, page.caption);
1338     }
1339 
1340     if (active_idx != -1)
1341     {
1342         menuPopup.Check(1000+active_idx, true);
1343     }
1344 
1345     // find out where to put the popup menu of window
1346     // items.  Subtract 100 for now to center the menu
1347     // a bit, until a better mechanism can be implemented
1348     wxPoint pt = ::wxGetMousePosition();
1349     pt = wnd->ScreenToClient(pt);
1350     if (pt.x < 100)
1351         pt.x = 0;
1352          else
1353         pt.x -= 100;
1354 
1355     // find out the screen coordinate at the bottom of the tab ctrl
1356     wxRect cli_rect = wnd->GetClientRect();
1357     pt.y = cli_rect.y + cli_rect.height;
1358 
1359     wxAuiCommandCapture* cc = new wxAuiCommandCapture;
1360     wnd->PushEventHandler(cc);
1361     wnd->PopupMenu(&menuPopup, pt);
1362     int command = cc->GetCommandId();
1363     wnd->PopEventHandler(true);
1364 
1365     if (command >= 1000)
1366         return command-1000;
1367 
1368     return -1;
1369 }
1370 
GetBestTabCtrlSize(wxWindow * wnd,const wxAuiNotebookPageArray & WXUNUSED (pages),const wxSize & WXUNUSED (required_bmp_size))1371 int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow* wnd,
1372                                           const wxAuiNotebookPageArray& WXUNUSED(pages),
1373                                           const wxSize& WXUNUSED(required_bmp_size))
1374 {
1375     wxClientDC dc(wnd);
1376     dc.SetFont(m_measuring_font);
1377     int x_ext = 0;
1378     wxSize s = GetTabSize(dc,
1379                           wnd,
1380                           wxT("ABCDEFGHIj"),
1381                           wxNullBitmap,
1382                           true,
1383                           wxAUI_BUTTON_STATE_HIDDEN,
1384                           &x_ext);
1385     return s.y+3;
1386 }
1387 
SetNormalFont(const wxFont & font)1388 void wxAuiSimpleTabArt::SetNormalFont(const wxFont& font)
1389 {
1390     m_normal_font = font;
1391 }
1392 
SetSelectedFont(const wxFont & font)1393 void wxAuiSimpleTabArt::SetSelectedFont(const wxFont& font)
1394 {
1395     m_selected_font = font;
1396 }
1397 
SetMeasuringFont(const wxFont & font)1398 void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont& font)
1399 {
1400     m_measuring_font = font;
1401 }
1402 
1403 
1404 
1405 
1406 // -- wxAuiTabContainer class implementation --
1407 
1408 
1409 // wxAuiTabContainer is a class which contains information about each
1410 // tab.  It also can render an entire tab control to a specified DC.
1411 // It's not a window class itself, because this code will be used by
1412 // the wxFrameMananger, where it is disadvantageous to have separate
1413 // windows for each tab control in the case of "docked tabs"
1414 
1415 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
1416 // which can be used as a tab control in the normal sense.
1417 
1418 
wxAuiTabContainer()1419 wxAuiTabContainer::wxAuiTabContainer()
1420 {
1421     m_tab_offset = 0;
1422     m_flags = 0;
1423     m_art = new wxAuiDefaultTabArt;
1424 
1425     AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
1426     AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
1427     AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
1428     AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
1429 }
1430 
~wxAuiTabContainer()1431 wxAuiTabContainer::~wxAuiTabContainer()
1432 {
1433     delete m_art;
1434 }
1435 
SetArtProvider(wxAuiTabArt * art)1436 void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art)
1437 {
1438     delete m_art;
1439     m_art = art;
1440 
1441     if (m_art)
1442     {
1443         m_art->SetFlags(m_flags);
1444     }
1445 }
1446 
GetArtProvider() const1447 wxAuiTabArt* wxAuiTabContainer::GetArtProvider() const
1448 {
1449     return m_art;
1450 }
1451 
SetFlags(unsigned int flags)1452 void wxAuiTabContainer::SetFlags(unsigned int flags)
1453 {
1454     m_flags = flags;
1455 
1456     // check for new close button settings
1457     RemoveButton(wxAUI_BUTTON_LEFT);
1458     RemoveButton(wxAUI_BUTTON_RIGHT);
1459     RemoveButton(wxAUI_BUTTON_WINDOWLIST);
1460     RemoveButton(wxAUI_BUTTON_CLOSE);
1461 
1462 
1463     if (flags & wxAUI_NB_SCROLL_BUTTONS)
1464     {
1465         AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
1466         AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
1467     }
1468 
1469     if (flags & wxAUI_NB_WINDOWLIST_BUTTON)
1470     {
1471         AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
1472     }
1473 
1474     if (flags & wxAUI_NB_CLOSE_BUTTON)
1475     {
1476         AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
1477     }
1478 
1479     if (m_art)
1480     {
1481         m_art->SetFlags(m_flags);
1482     }
1483 }
1484 
GetFlags() const1485 unsigned int wxAuiTabContainer::GetFlags() const
1486 {
1487     return m_flags;
1488 }
1489 
1490 
SetNormalFont(const wxFont & font)1491 void wxAuiTabContainer::SetNormalFont(const wxFont& font)
1492 {
1493     m_art->SetNormalFont(font);
1494 }
1495 
SetSelectedFont(const wxFont & font)1496 void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
1497 {
1498     m_art->SetSelectedFont(font);
1499 }
1500 
SetMeasuringFont(const wxFont & font)1501 void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
1502 {
1503     m_art->SetMeasuringFont(font);
1504 }
1505 
SetRect(const wxRect & rect)1506 void wxAuiTabContainer::SetRect(const wxRect& rect)
1507 {
1508     m_rect = rect;
1509 
1510     if (m_art)
1511     {
1512         m_art->SetSizingInfo(rect.GetSize(), m_pages.GetCount());
1513     }
1514 }
1515 
AddPage(wxWindow * page,const wxAuiNotebookPage & info)1516 bool wxAuiTabContainer::AddPage(wxWindow* page,
1517                                 const wxAuiNotebookPage& info)
1518 {
1519     wxAuiNotebookPage page_info;
1520     page_info = info;
1521     page_info.window = page;
1522 
1523     m_pages.Add(page_info);
1524 
1525     // let the art provider know how many pages we have
1526     if (m_art)
1527     {
1528         m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1529     }
1530 
1531     return true;
1532 }
1533 
InsertPage(wxWindow * page,const wxAuiNotebookPage & info,size_t idx)1534 bool wxAuiTabContainer::InsertPage(wxWindow* page,
1535                                    const wxAuiNotebookPage& info,
1536                                    size_t idx)
1537 {
1538     wxAuiNotebookPage page_info;
1539     page_info = info;
1540     page_info.window = page;
1541 
1542     if (idx >= m_pages.GetCount())
1543         m_pages.Add(page_info);
1544          else
1545         m_pages.Insert(page_info, idx);
1546 
1547     // let the art provider know how many pages we have
1548     if (m_art)
1549     {
1550         m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1551     }
1552 
1553     return true;
1554 }
1555 
MovePage(wxWindow * page,size_t new_idx)1556 bool wxAuiTabContainer::MovePage(wxWindow* page,
1557                                  size_t new_idx)
1558 {
1559     int idx = GetIdxFromWindow(page);
1560     if (idx == -1)
1561         return false;
1562 
1563     // get page entry, make a copy of it
1564     wxAuiNotebookPage p = GetPage(idx);
1565 
1566     // remove old page entry
1567     RemovePage(page);
1568 
1569     // insert page where it should be
1570     InsertPage(page, p, new_idx);
1571 
1572     return true;
1573 }
1574 
RemovePage(wxWindow * wnd)1575 bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
1576 {
1577     size_t i, page_count = m_pages.GetCount();
1578     for (i = 0; i < page_count; ++i)
1579     {
1580         wxAuiNotebookPage& page = m_pages.Item(i);
1581         if (page.window == wnd)
1582         {
1583             m_pages.RemoveAt(i);
1584 
1585             // let the art provider know how many pages we have
1586             if (m_art)
1587             {
1588                 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1589             }
1590 
1591             return true;
1592         }
1593     }
1594 
1595     return false;
1596 }
1597 
SetActivePage(wxWindow * wnd)1598 bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
1599 {
1600     bool found = false;
1601 
1602     size_t i, page_count = m_pages.GetCount();
1603     for (i = 0; i < page_count; ++i)
1604     {
1605         wxAuiNotebookPage& page = m_pages.Item(i);
1606         if (page.window == wnd)
1607         {
1608             page.active = true;
1609             found = true;
1610         }
1611          else
1612         {
1613             page.active = false;
1614         }
1615     }
1616 
1617     return found;
1618 }
1619 
SetNoneActive()1620 void wxAuiTabContainer::SetNoneActive()
1621 {
1622     size_t i, page_count = m_pages.GetCount();
1623     for (i = 0; i < page_count; ++i)
1624     {
1625         wxAuiNotebookPage& page = m_pages.Item(i);
1626         page.active = false;
1627     }
1628 }
1629 
SetActivePage(size_t page)1630 bool wxAuiTabContainer::SetActivePage(size_t page)
1631 {
1632     if (page >= m_pages.GetCount())
1633         return false;
1634 
1635     return SetActivePage(m_pages.Item(page).window);
1636 }
1637 
GetActivePage() const1638 int wxAuiTabContainer::GetActivePage() const
1639 {
1640     size_t i, page_count = m_pages.GetCount();
1641     for (i = 0; i < page_count; ++i)
1642     {
1643         wxAuiNotebookPage& page = m_pages.Item(i);
1644         if (page.active)
1645             return i;
1646     }
1647 
1648     return -1;
1649 }
1650 
GetWindowFromIdx(size_t idx) const1651 wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
1652 {
1653     if (idx >= m_pages.GetCount())
1654         return NULL;
1655 
1656     return m_pages[idx].window;
1657 }
1658 
GetIdxFromWindow(wxWindow * wnd) const1659 int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
1660 {
1661     size_t i, page_count = m_pages.GetCount();
1662     for (i = 0; i < page_count; ++i)
1663     {
1664         wxAuiNotebookPage& page = m_pages.Item(i);
1665         if (page.window == wnd)
1666             return i;
1667     }
1668     return -1;
1669 }
1670 
GetPage(size_t idx)1671 wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
1672 {
1673     wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
1674 
1675     return m_pages[idx];
1676 }
1677 
GetPage(size_t idx) const1678 const wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx) const
1679 {
1680     wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
1681 
1682     return m_pages[idx];
1683 }
1684 
GetPages()1685 wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
1686 {
1687     return m_pages;
1688 }
1689 
GetPageCount() const1690 size_t wxAuiTabContainer::GetPageCount() const
1691 {
1692     return m_pages.GetCount();
1693 }
1694 
AddButton(int id,int location,const wxBitmap & normal_bitmap,const wxBitmap & disabled_bitmap)1695 void wxAuiTabContainer::AddButton(int id,
1696                                   int location,
1697                                   const wxBitmap& normal_bitmap,
1698                                   const wxBitmap& disabled_bitmap)
1699 {
1700     wxAuiTabContainerButton button;
1701     button.id = id;
1702     button.bitmap = normal_bitmap;
1703     button.dis_bitmap = disabled_bitmap;
1704     button.location = location;
1705     button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
1706 
1707     m_buttons.Add(button);
1708 }
1709 
RemoveButton(int id)1710 void wxAuiTabContainer::RemoveButton(int id)
1711 {
1712     size_t i, button_count = m_buttons.GetCount();
1713 
1714     for (i = 0; i < button_count; ++i)
1715     {
1716         if (m_buttons.Item(i).id == id)
1717         {
1718             m_buttons.RemoveAt(i);
1719             return;
1720         }
1721     }
1722 }
1723 
1724 
1725 
GetTabOffset() const1726 size_t wxAuiTabContainer::GetTabOffset() const
1727 {
1728     return m_tab_offset;
1729 }
1730 
SetTabOffset(size_t offset)1731 void wxAuiTabContainer::SetTabOffset(size_t offset)
1732 {
1733     m_tab_offset = offset;
1734 }
1735 
1736 
1737 
1738 
1739 // Render() renders the tab catalog to the specified DC
1740 // It is a virtual function and can be overridden to
1741 // provide custom drawing capabilities
Render(wxDC * raw_dc,wxWindow * wnd)1742 void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd)
1743 {
1744     if (!raw_dc || !raw_dc->IsOk())
1745         return;
1746 
1747     wxMemoryDC dc;
1748 
1749     // use the same layout direction as the window DC uses to ensure that the
1750     // text is rendered correctly
1751     dc.SetLayoutDirection(raw_dc->GetLayoutDirection());
1752 
1753     wxBitmap bmp;
1754     size_t i;
1755     size_t page_count = m_pages.GetCount();
1756     size_t button_count = m_buttons.GetCount();
1757 
1758     // create off-screen bitmap
1759     bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
1760     dc.SelectObject(bmp);
1761 
1762     if (!dc.IsOk())
1763         return;
1764 
1765     // find out if size of tabs is larger than can be
1766     // afforded on screen
1767     int total_width = 0;
1768     int visible_width = 0;
1769 
1770     for (i = 0; i < page_count; ++i)
1771     {
1772         wxAuiNotebookPage& page = m_pages.Item(i);
1773 
1774         // determine if a close button is on this tab
1775         bool close_button = false;
1776         if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1777             ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1778         {
1779             close_button = true;
1780         }
1781 
1782 
1783         int x_extent = 0;
1784         wxSize size = m_art->GetTabSize(dc,
1785                             wnd,
1786                             page.caption,
1787                             page.bitmap,
1788                             page.active,
1789                             close_button ?
1790                               wxAUI_BUTTON_STATE_NORMAL :
1791                               wxAUI_BUTTON_STATE_HIDDEN,
1792                             &x_extent);
1793 
1794         if (i+1 < page_count)
1795             total_width += x_extent;
1796              else
1797             total_width += size.x;
1798 
1799         if (i >= m_tab_offset)
1800         {
1801             if (i+1 < page_count)
1802                 visible_width += x_extent;
1803                  else
1804                 visible_width += size.x;
1805         }
1806     }
1807 
1808     if (total_width > m_rect.GetWidth() || m_tab_offset != 0)
1809     {
1810         // show left/right buttons
1811         for (i = 0; i < button_count; ++i)
1812         {
1813             wxAuiTabContainerButton& button = m_buttons.Item(i);
1814             if (button.id == wxAUI_BUTTON_LEFT ||
1815                 button.id == wxAUI_BUTTON_RIGHT)
1816             {
1817                 button.cur_state &= ~wxAUI_BUTTON_STATE_HIDDEN;
1818             }
1819         }
1820     }
1821      else
1822     {
1823         // hide left/right buttons
1824         for (i = 0; i < button_count; ++i)
1825         {
1826             wxAuiTabContainerButton& button = m_buttons.Item(i);
1827             if (button.id == wxAUI_BUTTON_LEFT ||
1828                 button.id == wxAUI_BUTTON_RIGHT)
1829             {
1830                 button.cur_state |= wxAUI_BUTTON_STATE_HIDDEN;
1831             }
1832         }
1833     }
1834 
1835     // determine whether left button should be enabled
1836     for (i = 0; i < button_count; ++i)
1837     {
1838         wxAuiTabContainerButton& button = m_buttons.Item(i);
1839         if (button.id == wxAUI_BUTTON_LEFT)
1840         {
1841             if (m_tab_offset == 0)
1842                 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
1843                  else
1844                 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
1845         }
1846         if (button.id == wxAUI_BUTTON_RIGHT)
1847         {
1848             if (visible_width < m_rect.GetWidth() - ((int)button_count*16))
1849                 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
1850                  else
1851                 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
1852         }
1853     }
1854 
1855 
1856 
1857     // draw background
1858     m_art->DrawBackground(dc, wnd, m_rect);
1859 
1860     // draw buttons
1861     int left_buttons_width = 0;
1862     int right_buttons_width = 0;
1863 
1864     int offset = 0;
1865 
1866     // draw the buttons on the right side
1867     offset = m_rect.x + m_rect.width;
1868     for (i = 0; i < button_count; ++i)
1869     {
1870         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
1871 
1872         if (button.location != wxRIGHT)
1873             continue;
1874         if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
1875             continue;
1876 
1877         wxRect button_rect = m_rect;
1878         button_rect.SetY(1);
1879         button_rect.SetWidth(offset);
1880 
1881         m_art->DrawButton(dc,
1882                           wnd,
1883                           button_rect,
1884                           button.id,
1885                           button.cur_state,
1886                           wxRIGHT,
1887                           &button.rect);
1888 
1889         offset -= button.rect.GetWidth();
1890         right_buttons_width += button.rect.GetWidth();
1891     }
1892 
1893 
1894 
1895     offset = 0;
1896 
1897     // draw the buttons on the left side
1898 
1899     for (i = 0; i < button_count; ++i)
1900     {
1901         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
1902 
1903         if (button.location != wxLEFT)
1904             continue;
1905         if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
1906             continue;
1907 
1908         wxRect button_rect(offset, 1, 1000, m_rect.height);
1909 
1910         m_art->DrawButton(dc,
1911                           wnd,
1912                           button_rect,
1913                           button.id,
1914                           button.cur_state,
1915                           wxLEFT,
1916                           &button.rect);
1917 
1918         offset += button.rect.GetWidth();
1919         left_buttons_width += button.rect.GetWidth();
1920     }
1921 
1922     offset = left_buttons_width;
1923 
1924     if (offset == 0)
1925         offset += m_art->GetIndentSize();
1926 
1927 
1928     // prepare the tab-close-button array
1929     // make sure tab button entries which aren't used are marked as hidden
1930     for (i = page_count; i < m_tab_close_buttons.GetCount(); ++i)
1931         m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1932 
1933     // make sure there are enough tab button entries to accommodate all tabs
1934     while (m_tab_close_buttons.GetCount() < page_count)
1935     {
1936         wxAuiTabContainerButton tempbtn;
1937         tempbtn.id = wxAUI_BUTTON_CLOSE;
1938         tempbtn.location = wxCENTER;
1939         tempbtn.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1940         m_tab_close_buttons.Add(tempbtn);
1941     }
1942 
1943 
1944     // buttons before the tab offset must be set to hidden
1945     for (i = 0; i < m_tab_offset; ++i)
1946     {
1947         m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1948     }
1949 
1950 
1951     // draw the tabs
1952 
1953     size_t active = 999;
1954     int active_offset = 0;
1955     wxRect active_rect;
1956     wxRect active_focus_rect;
1957 
1958     int x_extent = 0;
1959     wxRect rect = m_rect;
1960     rect.y = 0;
1961     rect.height = m_rect.height;
1962 
1963     for (i = m_tab_offset; i < page_count; ++i)
1964     {
1965         wxAuiNotebookPage& page = m_pages.Item(i);
1966         wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i);
1967 
1968         // determine if a close button is on this tab
1969         if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1970             ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1971         {
1972             if (tab_button.cur_state == wxAUI_BUTTON_STATE_HIDDEN)
1973             {
1974                 tab_button.id = wxAUI_BUTTON_CLOSE;
1975                 tab_button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
1976                 tab_button.location = wxCENTER;
1977             }
1978         }
1979          else
1980         {
1981             tab_button.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1982         }
1983 
1984         rect.x = offset;
1985         rect.width = m_rect.width - right_buttons_width - offset - 2;
1986 
1987         if (rect.width <= 0)
1988             break;
1989 
1990         m_art->DrawTab(dc,
1991                        wnd,
1992                        page,
1993                        rect,
1994                        tab_button.cur_state,
1995                        &page.rect,
1996                        &tab_button.rect,
1997                        &x_extent);
1998 
1999         if (page.active)
2000         {
2001             active = i;
2002             active_offset = offset;
2003             active_rect = rect;
2004             active_focus_rect = rect;
2005             active_focus_rect.width = x_extent;
2006         }
2007 
2008         offset += x_extent;
2009     }
2010 
2011 
2012     // make sure to deactivate buttons which are off the screen to the right
2013     for (++i; i < m_tab_close_buttons.GetCount(); ++i)
2014     {
2015         m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
2016     }
2017 
2018 
2019     // draw the active tab again so it stands in the foreground
2020     if (active >= m_tab_offset && active < m_pages.GetCount())
2021     {
2022         wxAuiNotebookPage& page = m_pages.Item(active);
2023 
2024         wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(active);
2025 
2026         rect.x = active_offset;
2027         m_art->DrawTab(dc,
2028                        wnd,
2029                        page,
2030                        active_rect,
2031                        tab_button.cur_state,
2032                        &page.rect,
2033                        &tab_button.rect,
2034                        &x_extent);
2035     }
2036 
2037 
2038     raw_dc->Blit(m_rect.x, m_rect.y,
2039                  m_rect.GetWidth(), m_rect.GetHeight(),
2040                  &dc, 0, 0);
2041 
2042 #ifdef __WXMAC__
2043     // On Mac, need to draw the focus rect directly to the window
2044     if (wnd && (wnd->FindFocus() == wnd) && (active >= m_tab_offset && active < m_pages.GetCount()))
2045     {
2046         wxRect focusRect(active_focus_rect);
2047         focusRect.Inflate(-6, -6);
2048         DrawFocusRect(wnd, * raw_dc, focusRect, 0);
2049     }
2050 #endif
2051 }
2052 
2053 // Is the tab visible?
IsTabVisible(int tabPage,int tabOffset,wxDC * dc,wxWindow * wnd)2054 bool wxAuiTabContainer::IsTabVisible(int tabPage, int tabOffset, wxDC* dc, wxWindow* wnd)
2055 {
2056     if (!dc || !dc->IsOk())
2057         return false;
2058 
2059     size_t i;
2060     size_t page_count = m_pages.GetCount();
2061     size_t button_count = m_buttons.GetCount();
2062 
2063     // Hasn't been rendered yet; assume it's visible
2064     if (m_tab_close_buttons.GetCount() < page_count)
2065         return true;
2066 
2067     // First check if both buttons are disabled - if so, there's no need to
2068     // check further for visibility.
2069     int arrowButtonVisibleCount = 0;
2070     for (i = 0; i < button_count; ++i)
2071     {
2072         wxAuiTabContainerButton& button = m_buttons.Item(i);
2073         if (button.id == wxAUI_BUTTON_LEFT ||
2074             button.id == wxAUI_BUTTON_RIGHT)
2075         {
2076             if ((button.cur_state & wxAUI_BUTTON_STATE_HIDDEN) == 0)
2077                 arrowButtonVisibleCount ++;
2078         }
2079     }
2080 
2081     // Tab must be visible
2082     if (arrowButtonVisibleCount == 0)
2083         return true;
2084 
2085     // If tab is less than the given offset, it must be invisible by definition
2086     if (tabPage < tabOffset)
2087         return false;
2088 
2089     // draw buttons
2090     int left_buttons_width = 0;
2091     int right_buttons_width = 0;
2092 
2093     int offset = 0;
2094 
2095     // calculate size of the buttons on the right side
2096     offset = m_rect.x + m_rect.width;
2097     for (i = 0; i < button_count; ++i)
2098     {
2099         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
2100 
2101         if (button.location != wxRIGHT)
2102             continue;
2103         if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
2104             continue;
2105 
2106         offset -= button.rect.GetWidth();
2107         right_buttons_width += button.rect.GetWidth();
2108     }
2109 
2110     offset = 0;
2111 
2112     // calculate size of the buttons on the left side
2113     for (i = 0; i < button_count; ++i)
2114     {
2115         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
2116 
2117         if (button.location != wxLEFT)
2118             continue;
2119         if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
2120             continue;
2121 
2122         offset += button.rect.GetWidth();
2123         left_buttons_width += button.rect.GetWidth();
2124     }
2125 
2126     offset = left_buttons_width;
2127 
2128     if (offset == 0)
2129         offset += m_art->GetIndentSize();
2130 
2131     wxRect active_rect;
2132 
2133     wxRect rect = m_rect;
2134     rect.y = 0;
2135     rect.height = m_rect.height;
2136 
2137     // See if the given page is visible at the given tab offset (effectively scroll position)
2138     for (i = tabOffset; i < page_count; ++i)
2139     {
2140         wxAuiNotebookPage& page = m_pages.Item(i);
2141         wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i);
2142 
2143         rect.x = offset;
2144         rect.width = m_rect.width - right_buttons_width - offset - 2;
2145 
2146         if (rect.width <= 0)
2147             return false; // haven't found the tab, and we've run out of space, so return false
2148 
2149         int x_extent = 0;
2150         wxSize size = m_art->GetTabSize(*dc,
2151                             wnd,
2152                             page.caption,
2153                             page.bitmap,
2154                             page.active,
2155                             tab_button.cur_state,
2156                             &x_extent);
2157 
2158         offset += x_extent;
2159 
2160         if (i == (size_t) tabPage)
2161         {
2162             // If not all of the tab is visible, and supposing there's space to display it all,
2163             // we could do better so we return false.
2164             if (((m_rect.width - right_buttons_width - offset - 2) <= 0) && ((m_rect.width - right_buttons_width - left_buttons_width) > x_extent))
2165                 return false;
2166             else
2167                 return true;
2168         }
2169     }
2170 
2171     // Shouldn't really get here, but if it does, assume the tab is visible to prevent
2172     // further looping in calling code.
2173     return true;
2174 }
2175 
2176 // Make the tab visible if it wasn't already
MakeTabVisible(int tabPage,wxWindow * win)2177 void wxAuiTabContainer::MakeTabVisible(int tabPage, wxWindow* win)
2178 {
2179     wxClientDC dc(win);
2180     if (!IsTabVisible(tabPage, GetTabOffset(), & dc, win))
2181     {
2182         int i;
2183         for (i = 0; i < (int) m_pages.GetCount(); i++)
2184         {
2185             if (IsTabVisible(tabPage, i, & dc, win))
2186             {
2187                 SetTabOffset(i);
2188                 win->Refresh();
2189                 return;
2190             }
2191         }
2192     }
2193 }
2194 
2195 // TabHitTest() tests if a tab was hit, passing the window pointer
2196 // back if that condition was fulfilled.  The function returns
2197 // true if a tab was hit, otherwise false
TabHitTest(int x,int y,wxWindow ** hit) const2198 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
2199 {
2200     if (!m_rect.Contains(x,y))
2201         return false;
2202 
2203     wxAuiTabContainerButton* btn = NULL;
2204     if (ButtonHitTest(x, y, &btn) && !(btn->cur_state & wxAUI_BUTTON_STATE_DISABLED))
2205     {
2206         if (m_buttons.Index(*btn) != wxNOT_FOUND)
2207             return false;
2208     }
2209 
2210     size_t i, page_count = m_pages.GetCount();
2211 
2212     for (i = m_tab_offset; i < page_count; ++i)
2213     {
2214         wxAuiNotebookPage& page = m_pages.Item(i);
2215         if (page.rect.Contains(x,y))
2216         {
2217             if (hit)
2218                 *hit = page.window;
2219             return true;
2220         }
2221     }
2222 
2223     return false;
2224 }
2225 
2226 // ButtonHitTest() tests if a button was hit. The function returns
2227 // true if a button was hit, otherwise false
ButtonHitTest(int x,int y,wxAuiTabContainerButton ** hit) const2228 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
2229                                       wxAuiTabContainerButton** hit) const
2230 {
2231     if (!m_rect.Contains(x,y))
2232         return false;
2233 
2234     size_t i, button_count;
2235 
2236 
2237     button_count = m_buttons.GetCount();
2238     for (i = 0; i < button_count; ++i)
2239     {
2240         wxAuiTabContainerButton& button = m_buttons.Item(i);
2241         if (button.rect.Contains(x,y) &&
2242             !(button.cur_state & wxAUI_BUTTON_STATE_HIDDEN ))
2243         {
2244             if (hit)
2245                 *hit = &button;
2246             return true;
2247         }
2248     }
2249 
2250     button_count = m_tab_close_buttons.GetCount();
2251     for (i = 0; i < button_count; ++i)
2252     {
2253         wxAuiTabContainerButton& button = m_tab_close_buttons.Item(i);
2254         if (button.rect.Contains(x,y) &&
2255             !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN |
2256                                    wxAUI_BUTTON_STATE_DISABLED)))
2257         {
2258             if (hit)
2259                 *hit = &button;
2260             return true;
2261         }
2262     }
2263 
2264     return false;
2265 }
2266 
2267 
2268 
2269 // the utility function ShowWnd() is the same as show,
2270 // except it handles wxAuiMDIChildFrame windows as well,
2271 // as the Show() method on this class is "unplugged"
ShowWnd(wxWindow * wnd,bool show)2272 static void ShowWnd(wxWindow* wnd, bool show)
2273 {
2274 #if wxUSE_MDI
2275     if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2276     {
2277         wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
2278         cf->DoShow(show);
2279     }
2280     else
2281 #endif
2282     {
2283         wnd->Show(show);
2284     }
2285 }
2286 
2287 
2288 // DoShowHide() this function shows the active window, then
2289 // hides all of the other windows (in that order)
DoShowHide()2290 void wxAuiTabContainer::DoShowHide()
2291 {
2292     wxAuiNotebookPageArray& pages = GetPages();
2293     size_t i, page_count = pages.GetCount();
2294 
2295     // show new active page first
2296     for (i = 0; i < page_count; ++i)
2297     {
2298         wxAuiNotebookPage& page = pages.Item(i);
2299         if (page.active)
2300         {
2301             ShowWnd(page.window, true);
2302             break;
2303         }
2304     }
2305 
2306     // hide all other pages
2307     for (i = 0; i < page_count; ++i)
2308     {
2309         wxAuiNotebookPage& page = pages.Item(i);
2310         if (!page.active)
2311             ShowWnd(page.window, false);
2312     }
2313 }
2314 
2315 
2316 
2317 
2318 
2319 
2320 // -- wxAuiTabCtrl class implementation --
2321 
2322 
2323 
BEGIN_EVENT_TABLE(wxAuiTabCtrl,wxControl)2324 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
2325     EVT_PAINT(wxAuiTabCtrl::OnPaint)
2326     EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
2327     EVT_SIZE(wxAuiTabCtrl::OnSize)
2328     EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
2329     EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDClick)
2330     EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
2331     EVT_MIDDLE_DOWN(wxAuiTabCtrl::OnMiddleDown)
2332     EVT_MIDDLE_UP(wxAuiTabCtrl::OnMiddleUp)
2333     EVT_RIGHT_DOWN(wxAuiTabCtrl::OnRightDown)
2334     EVT_RIGHT_UP(wxAuiTabCtrl::OnRightUp)
2335     EVT_MOTION(wxAuiTabCtrl::OnMotion)
2336     EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
2337     EVT_AUINOTEBOOK_BUTTON(wxID_ANY, wxAuiTabCtrl::OnButton)
2338     EVT_SET_FOCUS(wxAuiTabCtrl::OnSetFocus)
2339     EVT_KILL_FOCUS(wxAuiTabCtrl::OnKillFocus)
2340     EVT_CHAR(wxAuiTabCtrl::OnChar)
2341     EVT_MOUSE_CAPTURE_LOST(wxAuiTabCtrl::OnCaptureLost)
2342 END_EVENT_TABLE()
2343 
2344 
2345 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
2346                            wxWindowID id,
2347                            const wxPoint& pos,
2348                            const wxSize& size,
2349                            long style) : wxControl(parent, id, pos, size, style)
2350 {
2351     m_click_pt = wxDefaultPosition;
2352     m_is_dragging = false;
2353     m_hover_button = NULL;
2354     m_pressed_button = NULL;
2355 }
2356 
~wxAuiTabCtrl()2357 wxAuiTabCtrl::~wxAuiTabCtrl()
2358 {
2359 }
2360 
OnPaint(wxPaintEvent &)2361 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
2362 {
2363     wxPaintDC dc(this);
2364 
2365     dc.SetFont(GetFont());
2366 
2367     if (GetPageCount() > 0)
2368         Render(&dc, this);
2369 }
2370 
OnEraseBackground(wxEraseEvent & WXUNUSED (evt))2371 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
2372 {
2373 }
2374 
OnSize(wxSizeEvent & evt)2375 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
2376 {
2377     wxSize s = evt.GetSize();
2378     wxRect r(0, 0, s.GetWidth(), s.GetHeight());
2379     SetRect(r);
2380 }
2381 
OnLeftDown(wxMouseEvent & evt)2382 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
2383 {
2384     CaptureMouse();
2385     m_click_pt = wxDefaultPosition;
2386     m_is_dragging = false;
2387     m_click_tab = NULL;
2388     m_pressed_button = NULL;
2389 
2390 
2391     wxWindow* wnd;
2392     if (TabHitTest(evt.m_x, evt.m_y, &wnd))
2393     {
2394         int new_selection = GetIdxFromWindow(wnd);
2395 
2396         // wxAuiNotebooks always want to receive this event
2397         // even if the tab is already active, because they may
2398         // have multiple tab controls
2399         if (new_selection != GetActivePage() ||
2400             GetParent()->IsKindOf(CLASSINFO(wxAuiNotebook)))
2401         {
2402             wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2403             e.SetSelection(new_selection);
2404             e.SetOldSelection(GetActivePage());
2405             e.SetEventObject(this);
2406             GetEventHandler()->ProcessEvent(e);
2407         }
2408 
2409         m_click_pt.x = evt.m_x;
2410         m_click_pt.y = evt.m_y;
2411         m_click_tab = wnd;
2412     }
2413 
2414     if (m_hover_button)
2415     {
2416         m_pressed_button = m_hover_button;
2417         m_pressed_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
2418         Refresh();
2419         Update();
2420     }
2421 }
2422 
OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED (event))2423 void wxAuiTabCtrl::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
2424 {
2425 }
2426 
OnLeftUp(wxMouseEvent & evt)2427 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent& evt)
2428 {
2429     if (GetCapture() == this)
2430         ReleaseMouse();
2431 
2432     if (m_is_dragging)
2433     {
2434         m_is_dragging = false;
2435 
2436         wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
2437         evt.SetSelection(GetIdxFromWindow(m_click_tab));
2438         evt.SetOldSelection(evt.GetSelection());
2439         evt.SetEventObject(this);
2440         GetEventHandler()->ProcessEvent(evt);
2441 
2442         return;
2443     }
2444 
2445     if (m_pressed_button)
2446     {
2447         // make sure we're still clicking the button
2448         wxAuiTabContainerButton* button = NULL;
2449         if (!ButtonHitTest(evt.m_x, evt.m_y, &button) ||
2450             button->cur_state & wxAUI_BUTTON_STATE_DISABLED)
2451             return;
2452 
2453         if (button != m_pressed_button)
2454         {
2455             m_pressed_button = NULL;
2456             return;
2457         }
2458 
2459         Refresh();
2460         Update();
2461 
2462         if (!(m_pressed_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
2463         {
2464             wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
2465             evt.SetSelection(GetIdxFromWindow(m_click_tab));
2466             evt.SetInt(m_pressed_button->id);
2467             evt.SetEventObject(this);
2468             GetEventHandler()->ProcessEvent(evt);
2469         }
2470 
2471         m_pressed_button = NULL;
2472     }
2473 
2474     m_click_pt = wxDefaultPosition;
2475     m_is_dragging = false;
2476     m_click_tab = NULL;
2477 }
2478 
OnMiddleUp(wxMouseEvent & evt)2479 void wxAuiTabCtrl::OnMiddleUp(wxMouseEvent& evt)
2480 {
2481     wxWindow* wnd = NULL;
2482     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2483         return;
2484 
2485     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
2486     e.SetEventObject(this);
2487     e.SetSelection(GetIdxFromWindow(wnd));
2488     GetEventHandler()->ProcessEvent(e);
2489 }
2490 
OnMiddleDown(wxMouseEvent & evt)2491 void wxAuiTabCtrl::OnMiddleDown(wxMouseEvent& evt)
2492 {
2493     wxWindow* wnd = NULL;
2494     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2495         return;
2496 
2497     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
2498     e.SetEventObject(this);
2499     e.SetSelection(GetIdxFromWindow(wnd));
2500     GetEventHandler()->ProcessEvent(e);
2501 }
2502 
OnRightUp(wxMouseEvent & evt)2503 void wxAuiTabCtrl::OnRightUp(wxMouseEvent& evt)
2504 {
2505     wxWindow* wnd = NULL;
2506     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2507         return;
2508 
2509     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
2510     e.SetEventObject(this);
2511     e.SetSelection(GetIdxFromWindow(wnd));
2512     GetEventHandler()->ProcessEvent(e);
2513 }
2514 
OnRightDown(wxMouseEvent & evt)2515 void wxAuiTabCtrl::OnRightDown(wxMouseEvent& evt)
2516 {
2517     wxWindow* wnd = NULL;
2518     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2519         return;
2520 
2521     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
2522     e.SetEventObject(this);
2523     e.SetSelection(GetIdxFromWindow(wnd));
2524     GetEventHandler()->ProcessEvent(e);
2525 }
2526 
OnLeftDClick(wxMouseEvent & evt)2527 void wxAuiTabCtrl::OnLeftDClick(wxMouseEvent& evt)
2528 {
2529     wxWindow* wnd;
2530     wxAuiTabContainerButton* button;
2531     if (!TabHitTest(evt.m_x, evt.m_y, &wnd) && !ButtonHitTest(evt.m_x, evt.m_y, &button))
2532     {
2533         wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, m_windowId);
2534         e.SetEventObject(this);
2535         GetEventHandler()->ProcessEvent(e);
2536     }
2537 }
2538 
OnMotion(wxMouseEvent & evt)2539 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
2540 {
2541     wxPoint pos = evt.GetPosition();
2542 
2543     // check if the mouse is hovering above a button
2544     wxAuiTabContainerButton* button;
2545     if (ButtonHitTest(pos.x, pos.y, &button) && !(button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
2546     {
2547         if (m_hover_button && button != m_hover_button)
2548         {
2549             m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2550             m_hover_button = NULL;
2551             Refresh();
2552             Update();
2553         }
2554 
2555         if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
2556         {
2557             button->cur_state = wxAUI_BUTTON_STATE_HOVER;
2558             Refresh();
2559             Update();
2560             m_hover_button = button;
2561             return;
2562         }
2563     }
2564      else
2565     {
2566         if (m_hover_button)
2567         {
2568             m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2569             m_hover_button = NULL;
2570             Refresh();
2571             Update();
2572         }
2573     }
2574 
2575 
2576     if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
2577         return;
2578 
2579     if (m_is_dragging)
2580     {
2581         wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
2582         evt.SetSelection(GetIdxFromWindow(m_click_tab));
2583         evt.SetOldSelection(evt.GetSelection());
2584         evt.SetEventObject(this);
2585         GetEventHandler()->ProcessEvent(evt);
2586         return;
2587     }
2588 
2589 
2590     int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
2591     int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
2592 
2593     if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
2594         abs(pos.y - m_click_pt.y) > drag_y_threshold)
2595     {
2596         wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
2597         evt.SetSelection(GetIdxFromWindow(m_click_tab));
2598         evt.SetOldSelection(evt.GetSelection());
2599         evt.SetEventObject(this);
2600         GetEventHandler()->ProcessEvent(evt);
2601 
2602         m_is_dragging = true;
2603     }
2604 }
2605 
OnLeaveWindow(wxMouseEvent & WXUNUSED (event))2606 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
2607 {
2608     if (m_hover_button)
2609     {
2610         m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2611         m_hover_button = NULL;
2612         Refresh();
2613         Update();
2614     }
2615 }
2616 
OnButton(wxAuiNotebookEvent & event)2617 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
2618 {
2619     int button = event.GetInt();
2620 
2621     if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
2622     {
2623         if (button == wxAUI_BUTTON_LEFT)
2624         {
2625             if (GetTabOffset() > 0)
2626             {
2627                 SetTabOffset(GetTabOffset()-1);
2628                 Refresh();
2629                 Update();
2630             }
2631         }
2632          else
2633         {
2634             SetTabOffset(GetTabOffset()+1);
2635             Refresh();
2636             Update();
2637         }
2638     }
2639      else if (button == wxAUI_BUTTON_WINDOWLIST)
2640     {
2641         int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage());
2642 
2643         if (idx != -1)
2644         {
2645             wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2646             e.SetSelection(idx);
2647             e.SetOldSelection(GetActivePage());
2648             e.SetEventObject(this);
2649             GetEventHandler()->ProcessEvent(e);
2650         }
2651     }
2652      else
2653     {
2654         event.Skip();
2655     }
2656 }
2657 
OnSetFocus(wxFocusEvent & WXUNUSED (event))2658 void wxAuiTabCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event))
2659 {
2660     Refresh();
2661 }
2662 
OnKillFocus(wxFocusEvent & WXUNUSED (event))2663 void wxAuiTabCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event))
2664 {
2665     Refresh();
2666 }
2667 
OnChar(wxKeyEvent & event)2668 void wxAuiTabCtrl::OnChar(wxKeyEvent& event)
2669 {
2670     if (GetActivePage() == -1)
2671     {
2672         event.Skip();
2673         return;
2674     }
2675 
2676     // We can't leave tab processing to the system; on Windows, tabs and keys
2677     // get eaten by the system and not processed properly if we specify both
2678     // wxTAB_TRAVERSAL and wxWANTS_CHARS. And if we specify just wxTAB_TRAVERSAL,
2679     // we don't key arrow key events.
2680 
2681     int key = event.GetKeyCode();
2682 
2683     if (key == WXK_NUMPAD_PAGEUP)
2684         key = WXK_PAGEUP;
2685     if (key == WXK_NUMPAD_PAGEDOWN)
2686         key = WXK_PAGEDOWN;
2687     if (key == WXK_NUMPAD_HOME)
2688         key = WXK_HOME;
2689     if (key == WXK_NUMPAD_END)
2690         key = WXK_END;
2691     if (key == WXK_NUMPAD_LEFT)
2692         key = WXK_LEFT;
2693     if (key == WXK_NUMPAD_RIGHT)
2694         key = WXK_RIGHT;
2695 
2696     if (key == WXK_TAB || key == WXK_PAGEUP || key == WXK_PAGEDOWN)
2697     {
2698         bool bCtrlDown = event.ControlDown();
2699         bool bShiftDown = event.ShiftDown();
2700 
2701         bool bForward = (key == WXK_TAB && !bShiftDown) || (key == WXK_PAGEDOWN);
2702         bool bWindowChange = (key == WXK_PAGEUP) || (key == WXK_PAGEDOWN) || bCtrlDown;
2703         bool bFromTab = (key == WXK_TAB);
2704 
2705         wxAuiNotebook* nb = wxDynamicCast(GetParent(), wxAuiNotebook);
2706         if (!nb)
2707         {
2708             event.Skip();
2709             return;
2710         }
2711 
2712         wxNavigationKeyEvent keyEvent;
2713         keyEvent.SetDirection(bForward);
2714         keyEvent.SetWindowChange(bWindowChange);
2715         keyEvent.SetFromTab(bFromTab);
2716         keyEvent.SetEventObject(nb);
2717 
2718         if (!nb->GetEventHandler()->ProcessEvent(keyEvent))
2719         {
2720             // Not processed? Do an explicit tab into the page.
2721             wxWindow* win = GetWindowFromIdx(GetActivePage());
2722             if (win)
2723                 win->SetFocus();
2724         }
2725         return;
2726     }
2727 
2728     if (m_pages.GetCount() < 2)
2729     {
2730         event.Skip();
2731         return;
2732     }
2733 
2734     int newPage = -1;
2735 
2736     int forwardKey, backwardKey;
2737     if (GetLayoutDirection() == wxLayout_RightToLeft)
2738     {
2739         forwardKey = WXK_LEFT;
2740         backwardKey = WXK_RIGHT;
2741     }
2742     else
2743      {
2744         forwardKey = WXK_RIGHT;
2745         backwardKey = WXK_LEFT;
2746     }
2747 
2748     if (key == forwardKey)
2749     {
2750         if (m_pages.GetCount() > 1)
2751         {
2752             if (GetActivePage() == -1)
2753                 newPage = 0;
2754             else if (GetActivePage() < (int) (m_pages.GetCount() - 1))
2755                 newPage = GetActivePage() + 1;
2756         }
2757     }
2758     else if (key == backwardKey)
2759     {
2760         if (m_pages.GetCount() > 1)
2761         {
2762             if (GetActivePage() == -1)
2763                 newPage = (int) (m_pages.GetCount() - 1);
2764             else if (GetActivePage() > 0)
2765                 newPage = GetActivePage() - 1;
2766         }
2767     }
2768     else if (key == WXK_HOME)
2769     {
2770         newPage = 0;
2771     }
2772     else if (key == WXK_END)
2773     {
2774         newPage = (int) (m_pages.GetCount() - 1);
2775     }
2776     else
2777         event.Skip();
2778 
2779     if (newPage != -1)
2780     {
2781         wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2782         e.SetSelection(newPage);
2783         e.SetOldSelection(newPage);
2784         e.SetEventObject(this);
2785         this->GetEventHandler()->ProcessEvent(e);
2786     }
2787     else
2788         event.Skip();
2789 }
2790 
2791 // wxTabFrame is an interesting case.  It's important that all child pages
2792 // of the multi-notebook control are all actually children of that control
2793 // (and not grandchildren).  wxTabFrame facilitates this.  There is one
2794 // instance of wxTabFrame for each tab control inside the multi-notebook.
2795 // It's important to know that wxTabFrame is not a real window, but it merely
2796 // used to capture the dimensions/positioning of the internal tab control and
2797 // it's managed page windows
2798 
2799 class wxTabFrame : public wxWindow
2800 {
2801 public:
2802 
wxTabFrame()2803     wxTabFrame()
2804     {
2805         m_tabs = NULL;
2806         m_rect = wxRect(0,0,200,200);
2807         m_tab_ctrl_height = 20;
2808     }
2809 
~wxTabFrame()2810     ~wxTabFrame()
2811     {
2812         wxDELETE(m_tabs);
2813     }
2814 
SetTabCtrlHeight(int h)2815     void SetTabCtrlHeight(int h)
2816     {
2817         m_tab_ctrl_height = h;
2818     }
2819 
DoSetSize(int x,int y,int width,int height,int WXUNUSED (sizeFlags=wxSIZE_AUTO))2820     void DoSetSize(int x, int y,
2821                    int width, int height,
2822                    int WXUNUSED(sizeFlags = wxSIZE_AUTO))
2823     {
2824         m_rect = wxRect(x, y, width, height);
2825         DoSizing();
2826     }
2827 
DoGetClientSize(int * x,int * y) const2828     void DoGetClientSize(int* x, int* y) const
2829     {
2830         *x = m_rect.width;
2831         *y = m_rect.height;
2832     }
2833 
Show(bool WXUNUSED (show=true))2834     bool Show( bool WXUNUSED(show = true) ) { return false; }
2835 
DoSizing()2836     void DoSizing()
2837     {
2838         if (!m_tabs)
2839             return;
2840 
2841         if (m_tabs->IsFrozen() || m_tabs->GetParent()->IsFrozen())
2842             return;
2843 
2844         if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM)
2845         {
2846             m_tab_rect = wxRect (m_rect.x, m_rect.y + m_rect.height - m_tab_ctrl_height, m_rect.width, m_tab_ctrl_height);
2847             m_tabs->SetSize     (m_rect.x, m_rect.y + m_rect.height - m_tab_ctrl_height, m_rect.width, m_tab_ctrl_height);
2848             m_tabs->SetRect     (wxRect(0, 0, m_rect.width, m_tab_ctrl_height));
2849         }
2850         else //TODO: if (GetFlags() & wxAUI_NB_TOP)
2851         {
2852             m_tab_rect = wxRect (m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2853             m_tabs->SetSize     (m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2854             m_tabs->SetRect     (wxRect(0, 0,        m_rect.width, m_tab_ctrl_height));
2855         }
2856         // TODO: else if (GetFlags() & wxAUI_NB_LEFT){}
2857         // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){}
2858 
2859         m_tabs->Refresh();
2860         m_tabs->Update();
2861 
2862         wxAuiNotebookPageArray& pages = m_tabs->GetPages();
2863         size_t i, page_count = pages.GetCount();
2864 
2865         for (i = 0; i < page_count; ++i)
2866         {
2867             wxAuiNotebookPage& page = pages.Item(i);
2868             if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM)
2869             {
2870                page.window->SetSize(m_rect.x, m_rect.y,
2871                                     m_rect.width, m_rect.height - m_tab_ctrl_height);
2872             }
2873             else //TODO: if (GetFlags() & wxAUI_NB_TOP)
2874             {
2875                 page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height,
2876                                     m_rect.width, m_rect.height - m_tab_ctrl_height);
2877             }
2878             // TODO: else if (GetFlags() & wxAUI_NB_LEFT){}
2879             // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){}
2880 
2881 #if wxUSE_MDI
2882             if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2883             {
2884                 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
2885                 wnd->ApplyMDIChildFrameRect();
2886             }
2887 #endif
2888         }
2889     }
2890 
DoGetSize(int * x,int * y) const2891     void DoGetSize(int* x, int* y) const
2892     {
2893         if (x)
2894             *x = m_rect.GetWidth();
2895         if (y)
2896             *y = m_rect.GetHeight();
2897     }
2898 
Update()2899     void Update()
2900     {
2901         // does nothing
2902     }
2903 
2904 public:
2905 
2906     wxRect m_rect;
2907     wxRect m_tab_rect;
2908     wxAuiTabCtrl* m_tabs;
2909     int m_tab_ctrl_height;
2910 };
2911 
2912 
2913 const int wxAuiBaseTabCtrlId = 5380;
2914 
2915 
2916 // -- wxAuiNotebook class implementation --
2917 
BEGIN_EVENT_TABLE(wxAuiNotebook,wxControl)2918 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
2919     EVT_SIZE(wxAuiNotebook::OnSize)
2920     EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
2921     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2922                       wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
2923                       wxAuiNotebook::OnTabClicked)
2924     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2925                       wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
2926                       wxAuiNotebook::OnTabBeginDrag)
2927     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2928                       wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
2929                       wxAuiNotebook::OnTabEndDrag)
2930     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2931                       wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
2932                       wxAuiNotebook::OnTabDragMotion)
2933     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2934                       wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
2935                       wxAuiNotebook::OnTabButton)
2936     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2937                       wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN,
2938                       wxAuiNotebook::OnTabMiddleDown)
2939     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2940                       wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP,
2941                       wxAuiNotebook::OnTabMiddleUp)
2942     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2943                       wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN,
2944                       wxAuiNotebook::OnTabRightDown)
2945     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2946                       wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
2947                       wxAuiNotebook::OnTabRightUp)
2948     EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2949                       wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK,
2950                       wxAuiNotebook::OnTabBgDClick)
2951     EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKey)
2952 END_EVENT_TABLE()
2953 
2954 wxAuiNotebook::wxAuiNotebook()
2955 {
2956     m_curpage = -1;
2957     m_tab_id_counter = wxAuiBaseTabCtrlId;
2958     m_dummy_wnd = NULL;
2959     m_tab_ctrl_height = 20;
2960     m_requested_bmp_size = wxDefaultSize;
2961     m_requested_tabctrl_height = -1;
2962 }
2963 
wxAuiNotebook(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)2964 wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
2965                              wxWindowID id,
2966                              const wxPoint& pos,
2967                              const wxSize& size,
2968                              long style) : wxControl(parent, id, pos, size, style)
2969 {
2970     m_dummy_wnd = NULL;
2971     m_requested_bmp_size = wxDefaultSize;
2972     m_requested_tabctrl_height = -1;
2973     InitNotebook(style);
2974 }
2975 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)2976 bool wxAuiNotebook::Create(wxWindow* parent,
2977                            wxWindowID id,
2978                            const wxPoint& pos,
2979                            const wxSize& size,
2980                            long style)
2981 {
2982     if (!wxControl::Create(parent, id, pos, size, style))
2983         return false;
2984 
2985     InitNotebook(style);
2986 
2987     return true;
2988 }
2989 
2990 // InitNotebook() contains common initialization
2991 // code called by all constructors
InitNotebook(long style)2992 void wxAuiNotebook::InitNotebook(long style)
2993 {
2994     m_curpage = -1;
2995     m_tab_id_counter = wxAuiBaseTabCtrlId;
2996     m_dummy_wnd = NULL;
2997     m_flags = (unsigned int)style;
2998     m_tab_ctrl_height = 20;
2999 
3000     m_normal_font = *wxNORMAL_FONT;
3001     m_selected_font = *wxNORMAL_FONT;
3002     m_selected_font.SetWeight(wxBOLD);
3003 
3004     SetArtProvider(new wxAuiDefaultTabArt);
3005 
3006     m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
3007     m_dummy_wnd->SetSize(200, 200);
3008     m_dummy_wnd->Show(false);
3009 
3010     m_mgr.SetManagedWindow(this);
3011     m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
3012     m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
3013 
3014     m_mgr.AddPane(m_dummy_wnd,
3015               wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
3016 
3017     m_mgr.Update();
3018 }
3019 
~wxAuiNotebook()3020 wxAuiNotebook::~wxAuiNotebook()
3021 {
3022     // Indicate we're deleting pages
3023     m_isBeingDeleted = true;
3024 
3025     while ( GetPageCount() > 0 )
3026         DeletePage(0);
3027 
3028     m_mgr.UnInit();
3029 }
3030 
SetArtProvider(wxAuiTabArt * art)3031 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
3032 {
3033     m_tabs.SetArtProvider(art);
3034 
3035     UpdateTabCtrlHeight();
3036 }
3037 
3038 // SetTabCtrlHeight() is the highest-level override of the
3039 // tab height.  A call to this function effectively enforces a
3040 // specified tab ctrl height, overriding all other considerations,
3041 // such as text or bitmap height.  It overrides any call to
3042 // SetUniformBitmapSize().  Specifying a height of -1 reverts
3043 // any previous call and returns to the default behavior
3044 
SetTabCtrlHeight(int height)3045 void wxAuiNotebook::SetTabCtrlHeight(int height)
3046 {
3047     m_requested_tabctrl_height = height;
3048 
3049     // if window is already initialized, recalculate the tab height
3050     if (m_dummy_wnd)
3051     {
3052         UpdateTabCtrlHeight();
3053     }
3054 }
3055 
3056 
3057 // SetUniformBitmapSize() ensures that all tabs will have
3058 // the same height, even if some tabs don't have bitmaps
3059 // Passing wxDefaultSize to this function will instruct
3060 // the control to use dynamic tab height-- so when a tab
3061 // with a large bitmap is added, the tab ctrl's height will
3062 // automatically increase to accommodate the bitmap
3063 
SetUniformBitmapSize(const wxSize & size)3064 void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
3065 {
3066     m_requested_bmp_size = size;
3067 
3068     // if window is already initialized, recalculate the tab height
3069     if (m_dummy_wnd)
3070     {
3071         UpdateTabCtrlHeight();
3072     }
3073 }
3074 
3075 // UpdateTabCtrlHeight() does the actual tab resizing. It's meant
3076 // to be used interally
UpdateTabCtrlHeight()3077 void wxAuiNotebook::UpdateTabCtrlHeight()
3078 {
3079     // get the tab ctrl height we will use
3080     int height = CalculateTabCtrlHeight();
3081 
3082     // if the tab control height needs to change, update
3083     // all of our tab controls with the new height
3084     if (m_tab_ctrl_height != height)
3085     {
3086         wxAuiTabArt* art = m_tabs.GetArtProvider();
3087 
3088         m_tab_ctrl_height = height;
3089 
3090         wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3091         size_t i, pane_count = all_panes.GetCount();
3092         for (i = 0; i < pane_count; ++i)
3093         {
3094             wxAuiPaneInfo& pane = all_panes.Item(i);
3095             if (pane.name == wxT("dummy"))
3096                 continue;
3097             wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
3098             wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
3099             tab_frame->SetTabCtrlHeight(m_tab_ctrl_height);
3100             tabctrl->SetArtProvider(art->Clone());
3101             tab_frame->DoSizing();
3102         }
3103     }
3104 }
3105 
UpdateHintWindowSize()3106 void wxAuiNotebook::UpdateHintWindowSize()
3107 {
3108     wxSize size = CalculateNewSplitSize();
3109 
3110     // the placeholder hint window should be set to this size
3111     wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
3112     if (info.IsOk())
3113     {
3114         info.MinSize(size);
3115         info.BestSize(size);
3116         m_dummy_wnd->SetSize(size);
3117     }
3118 }
3119 
3120 
3121 // calculates the size of the new split
CalculateNewSplitSize()3122 wxSize wxAuiNotebook::CalculateNewSplitSize()
3123 {
3124     // count number of tab controls
3125     int tab_ctrl_count = 0;
3126     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3127     size_t i, pane_count = all_panes.GetCount();
3128     for (i = 0; i < pane_count; ++i)
3129     {
3130         wxAuiPaneInfo& pane = all_panes.Item(i);
3131         if (pane.name == wxT("dummy"))
3132             continue;
3133         tab_ctrl_count++;
3134     }
3135 
3136     wxSize new_split_size;
3137 
3138     // if there is only one tab control, the first split
3139     // should happen around the middle
3140     if (tab_ctrl_count < 2)
3141     {
3142         new_split_size = GetClientSize();
3143         new_split_size.x /= 2;
3144         new_split_size.y /= 2;
3145     }
3146      else
3147     {
3148         // this is in place of a more complicated calculation
3149         // that needs to be implemented
3150         new_split_size = wxSize(180,180);
3151     }
3152 
3153     return new_split_size;
3154 }
3155 
CalculateTabCtrlHeight()3156 int wxAuiNotebook::CalculateTabCtrlHeight()
3157 {
3158     // if a fixed tab ctrl height is specified,
3159     // just return that instead of calculating a
3160     // tab height
3161     if (m_requested_tabctrl_height != -1)
3162         return m_requested_tabctrl_height;
3163 
3164     // find out new best tab height
3165     wxAuiTabArt* art = m_tabs.GetArtProvider();
3166 
3167     return art->GetBestTabCtrlSize(this,
3168                                    m_tabs.GetPages(),
3169                                    m_requested_bmp_size);
3170 }
3171 
3172 
GetArtProvider() const3173 wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
3174 {
3175     return m_tabs.GetArtProvider();
3176 }
3177 
SetWindowStyleFlag(long style)3178 void wxAuiNotebook::SetWindowStyleFlag(long style)
3179 {
3180     wxControl::SetWindowStyleFlag(style);
3181 
3182     m_flags = (unsigned int)style;
3183 
3184     // if the control is already initialized
3185     if (m_mgr.GetManagedWindow() == (wxWindow*)this)
3186     {
3187         // let all of the tab children know about the new style
3188 
3189         wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3190         size_t i, pane_count = all_panes.GetCount();
3191         for (i = 0; i < pane_count; ++i)
3192         {
3193             wxAuiPaneInfo& pane = all_panes.Item(i);
3194             if (pane.name == wxT("dummy"))
3195                 continue;
3196             wxTabFrame* tabframe = (wxTabFrame*)pane.window;
3197             wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
3198             tabctrl->SetFlags(m_flags);
3199             tabframe->DoSizing();
3200             tabctrl->Refresh();
3201             tabctrl->Update();
3202         }
3203     }
3204 }
3205 
3206 
AddPage(wxWindow * page,const wxString & caption,bool select,const wxBitmap & bitmap)3207 bool wxAuiNotebook::AddPage(wxWindow* page,
3208                             const wxString& caption,
3209                             bool select,
3210                             const wxBitmap& bitmap)
3211 {
3212     return InsertPage(GetPageCount(), page, caption, select, bitmap);
3213 }
3214 
InsertPage(size_t page_idx,wxWindow * page,const wxString & caption,bool select,const wxBitmap & bitmap)3215 bool wxAuiNotebook::InsertPage(size_t page_idx,
3216                                wxWindow* page,
3217                                const wxString& caption,
3218                                bool select,
3219                                const wxBitmap& bitmap)
3220 {
3221     wxASSERT_MSG(page, wxT("page pointer must be non-NULL"));
3222     if (!page)
3223         return false;
3224 
3225     page->Reparent(this);
3226 
3227     wxAuiNotebookPage info;
3228     info.window = page;
3229     info.caption = caption;
3230     info.bitmap = bitmap;
3231     info.active = false;
3232 
3233     // if there are currently no tabs, the first added
3234     // tab must be active
3235     if (m_tabs.GetPageCount() == 0)
3236         info.active = true;
3237 
3238     m_tabs.InsertPage(page, info, page_idx);
3239 
3240     // if that was the first page added, even if
3241     // select is false, it must become the "current page"
3242     // (though no select events will be fired)
3243     if (!select && m_tabs.GetPageCount() == 1)
3244         select = true;
3245         //m_curpage = GetPageIndex(page);
3246 
3247     wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
3248     if (page_idx >= active_tabctrl->GetPageCount())
3249         active_tabctrl->AddPage(page, info);
3250          else
3251         active_tabctrl->InsertPage(page, info, page_idx);
3252 
3253     UpdateTabCtrlHeight();
3254     DoSizing();
3255     active_tabctrl->DoShowHide();
3256 
3257     // adjust selected index
3258     if(m_curpage >= (int) page_idx)
3259         m_curpage++;
3260 
3261     if (select)
3262     {
3263         int idx = m_tabs.GetIdxFromWindow(page);
3264         wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()"));
3265 
3266         SetSelection(idx);
3267     }
3268 
3269     return true;
3270 }
3271 
3272 
3273 // DeletePage() removes a tab from the multi-notebook,
3274 // and destroys the window as well
DeletePage(size_t page_idx)3275 bool wxAuiNotebook::DeletePage(size_t page_idx)
3276 {
3277     if (page_idx >= m_tabs.GetPageCount())
3278         return false;
3279 
3280     wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
3281 
3282     // hide the window in advance, as this will
3283     // prevent flicker
3284     if ( !IsBeingDeleted() )
3285         ShowWnd(wnd, false);
3286 
3287     if (!RemovePage(page_idx))
3288         return false;
3289 
3290     // actually destroy the window now
3291 #if wxUSE_MDI
3292     if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3293     {
3294         // delete the child frame with pending delete, as is
3295         // customary with frame windows
3296         if (!wxPendingDelete.Member(wnd))
3297             wxPendingDelete.Append(wnd);
3298     }
3299     else
3300 #endif
3301     {
3302         wnd->Destroy();
3303     }
3304 
3305     return true;
3306 }
3307 
3308 
3309 
3310 // RemovePage() removes a tab from the multi-notebook,
3311 // but does not destroy the window
RemovePage(size_t page_idx)3312 bool wxAuiNotebook::RemovePage(size_t page_idx)
3313 {
3314     // save active window pointer
3315     wxWindow* active_wnd = NULL;
3316     if (m_curpage >= 0)
3317         active_wnd = m_tabs.GetWindowFromIdx(m_curpage);
3318 
3319     // save pointer of window being deleted
3320     wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
3321     wxWindow* new_active = NULL;
3322 
3323     // make sure we found the page
3324     if (!wnd)
3325         return false;
3326 
3327     // find out which onscreen tab ctrl owns this tab
3328     wxAuiTabCtrl* ctrl;
3329     int ctrl_idx;
3330     if (!FindTab(wnd, &ctrl, &ctrl_idx))
3331         return false;
3332 
3333     bool is_curpage = (m_curpage == (int)page_idx);
3334     bool is_active_in_split = ctrl->GetPage(ctrl_idx).active;
3335 
3336 
3337     // remove the tab from main catalog
3338     if (!m_tabs.RemovePage(wnd))
3339         return false;
3340 
3341     // remove the tab from the onscreen tab ctrl
3342     ctrl->RemovePage(wnd);
3343 
3344     if (is_active_in_split)
3345     {
3346         int ctrl_new_page_count = (int)ctrl->GetPageCount();
3347 
3348         if (ctrl_idx >= ctrl_new_page_count)
3349             ctrl_idx = ctrl_new_page_count-1;
3350 
3351         if (ctrl_idx >= 0 && ctrl_idx < (int)ctrl->GetPageCount())
3352         {
3353             // set new page as active in the tab split
3354             ctrl->SetActivePage(ctrl_idx);
3355 
3356             // if the page deleted was the current page for the
3357             // entire tab control, then record the window
3358             // pointer of the new active page for activation
3359             if (is_curpage)
3360             {
3361                 new_active = ctrl->GetWindowFromIdx(ctrl_idx);
3362             }
3363         }
3364     }
3365      else
3366     {
3367         // we are not deleting the active page, so keep it the same
3368         new_active = active_wnd;
3369     }
3370 
3371 
3372     if (!new_active)
3373     {
3374         // we haven't yet found a new page to active,
3375         // so select the next page from the main tab
3376         // catalogue
3377 
3378         if (page_idx < m_tabs.GetPageCount())
3379         {
3380             new_active = m_tabs.GetPage(page_idx).window;
3381         }
3382 
3383         if (!new_active && m_tabs.GetPageCount() > 0)
3384         {
3385             new_active = m_tabs.GetPage(0).window;
3386         }
3387     }
3388 
3389 
3390     RemoveEmptyTabFrames();
3391 
3392     // set new active pane
3393     m_curpage = -1;
3394     if (new_active && !m_isBeingDeleted)
3395     {
3396         SetSelection(m_tabs.GetIdxFromWindow(new_active));
3397     }
3398 
3399     return true;
3400 }
3401 
3402 // GetPageIndex() returns the index of the page, or -1 if the
3403 // page could not be located in the notebook
GetPageIndex(wxWindow * page_wnd) const3404 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
3405 {
3406     return m_tabs.GetIdxFromWindow(page_wnd);
3407 }
3408 
3409 
3410 
3411 // SetPageText() changes the tab caption of the specified page
SetPageText(size_t page_idx,const wxString & text)3412 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
3413 {
3414     if (page_idx >= m_tabs.GetPageCount())
3415         return false;
3416 
3417     // update our own tab catalog
3418     wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
3419     page_info.caption = text;
3420 
3421     // update what's on screen
3422     wxAuiTabCtrl* ctrl;
3423     int ctrl_idx;
3424     if (FindTab(page_info.window, &ctrl, &ctrl_idx))
3425     {
3426         wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
3427         info.caption = text;
3428         ctrl->Refresh();
3429         ctrl->Update();
3430     }
3431 
3432     return true;
3433 }
3434 
3435 // returns the page caption
GetPageText(size_t page_idx) const3436 wxString wxAuiNotebook::GetPageText(size_t page_idx) const
3437 {
3438     if (page_idx >= m_tabs.GetPageCount())
3439         return wxEmptyString;
3440 
3441     // update our own tab catalog
3442     const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
3443     return page_info.caption;
3444 }
3445 
SetPageBitmap(size_t page_idx,const wxBitmap & bitmap)3446 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
3447 {
3448     if (page_idx >= m_tabs.GetPageCount())
3449         return false;
3450 
3451     // update our own tab catalog
3452     wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
3453     page_info.bitmap = bitmap;
3454 
3455     // tab height might have changed
3456     UpdateTabCtrlHeight();
3457 
3458     // update what's on screen
3459     wxAuiTabCtrl* ctrl;
3460     int ctrl_idx;
3461     if (FindTab(page_info.window, &ctrl, &ctrl_idx))
3462     {
3463         wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
3464         info.bitmap = bitmap;
3465         ctrl->Refresh();
3466         ctrl->Update();
3467     }
3468 
3469     return true;
3470 }
3471 
3472 // returns the page bitmap
GetPageBitmap(size_t page_idx) const3473 wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const
3474 {
3475     if (page_idx >= m_tabs.GetPageCount())
3476         return wxBitmap();
3477 
3478     // update our own tab catalog
3479     const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
3480     return page_info.bitmap;
3481 }
3482 
3483 // GetSelection() returns the index of the currently active page
GetSelection() const3484 int wxAuiNotebook::GetSelection() const
3485 {
3486     return m_curpage;
3487 }
3488 
3489 // SetSelection() sets the currently active page
SetSelection(size_t new_page)3490 size_t wxAuiNotebook::SetSelection(size_t new_page)
3491 {
3492     wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
3493     if (!wnd)
3494         return m_curpage;
3495 
3496     // don't change the page unless necessary;
3497     // however, clicking again on a tab should give it the focus.
3498     if ((int)new_page == m_curpage)
3499     {
3500         wxAuiTabCtrl* ctrl;
3501         int ctrl_idx;
3502         if (FindTab(wnd, &ctrl, &ctrl_idx))
3503         {
3504             if (FindFocus() != ctrl)
3505                 ctrl->SetFocus();
3506         }
3507         return m_curpage;
3508     }
3509 
3510     wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
3511     evt.SetSelection(new_page);
3512     evt.SetOldSelection(m_curpage);
3513     evt.SetEventObject(this);
3514     if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
3515     {
3516         int old_curpage = m_curpage;
3517         m_curpage = new_page;
3518 
3519         // program allows the page change
3520         evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
3521         (void)GetEventHandler()->ProcessEvent(evt);
3522 
3523 
3524         wxAuiTabCtrl* ctrl;
3525         int ctrl_idx;
3526         if (FindTab(wnd, &ctrl, &ctrl_idx))
3527         {
3528             m_tabs.SetActivePage(wnd);
3529 
3530             ctrl->SetActivePage(ctrl_idx);
3531             DoSizing();
3532             ctrl->DoShowHide();
3533 
3534             ctrl->MakeTabVisible(ctrl_idx, ctrl);
3535 
3536             // set fonts
3537             wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3538             size_t i, pane_count = all_panes.GetCount();
3539             for (i = 0; i < pane_count; ++i)
3540             {
3541                 wxAuiPaneInfo& pane = all_panes.Item(i);
3542                 if (pane.name == wxT("dummy"))
3543                     continue;
3544                 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
3545                 if (tabctrl != ctrl)
3546                     tabctrl->SetSelectedFont(m_normal_font);
3547                      else
3548                     tabctrl->SetSelectedFont(m_selected_font);
3549                 tabctrl->Refresh();
3550             }
3551 
3552             // Set the focus to the page if we're not currently focused on the tab.
3553             // This is Firefox-like behaviour.
3554             if (wnd->IsShownOnScreen() && FindFocus() != ctrl)
3555                 wnd->SetFocus();
3556 
3557             return old_curpage;
3558         }
3559     }
3560 
3561     return m_curpage;
3562 }
3563 
3564 // GetPageCount() returns the total number of
3565 // pages managed by the multi-notebook
GetPageCount() const3566 size_t wxAuiNotebook::GetPageCount() const
3567 {
3568     return m_tabs.GetPageCount();
3569 }
3570 
3571 // GetPage() returns the wxWindow pointer of the
3572 // specified page
GetPage(size_t page_idx) const3573 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
3574 {
3575     wxASSERT(page_idx < m_tabs.GetPageCount());
3576 
3577     return m_tabs.GetWindowFromIdx(page_idx);
3578 }
3579 
3580 // DoSizing() performs all sizing operations in each tab control
DoSizing()3581 void wxAuiNotebook::DoSizing()
3582 {
3583     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3584     size_t i, pane_count = all_panes.GetCount();
3585     for (i = 0; i < pane_count; ++i)
3586     {
3587         if (all_panes.Item(i).name == wxT("dummy"))
3588             continue;
3589 
3590         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3591         tabframe->DoSizing();
3592     }
3593 }
3594 
3595 // GetActiveTabCtrl() returns the active tab control.  It is
3596 // called to determine which control gets new windows being added
GetActiveTabCtrl()3597 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
3598 {
3599     if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
3600     {
3601         wxAuiTabCtrl* ctrl;
3602         int idx;
3603 
3604         // find the tab ctrl with the current page
3605         if (FindTab(m_tabs.GetPage(m_curpage).window,
3606                     &ctrl, &idx))
3607         {
3608             return ctrl;
3609         }
3610     }
3611 
3612     // no current page, just find the first tab ctrl
3613     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3614     size_t i, pane_count = all_panes.GetCount();
3615     for (i = 0; i < pane_count; ++i)
3616     {
3617         if (all_panes.Item(i).name == wxT("dummy"))
3618             continue;
3619 
3620         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3621         return tabframe->m_tabs;
3622     }
3623 
3624     // If there is no tabframe at all, create one
3625     wxTabFrame* tabframe = new wxTabFrame;
3626     tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
3627     tabframe->m_tabs = new wxAuiTabCtrl(this,
3628                                         m_tab_id_counter++,
3629                                         wxDefaultPosition,
3630                                         wxDefaultSize,
3631                                         wxNO_BORDER|wxWANTS_CHARS);
3632     tabframe->m_tabs->SetFlags(m_flags);
3633     tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3634     m_mgr.AddPane(tabframe,
3635                   wxAuiPaneInfo().Center().CaptionVisible(false));
3636 
3637     m_mgr.Update();
3638 
3639     return tabframe->m_tabs;
3640 }
3641 
3642 // FindTab() finds the tab control that currently contains the window as well
3643 // as the index of the window in the tab control.  It returns true if the
3644 // window was found, otherwise false.
FindTab(wxWindow * page,wxAuiTabCtrl ** ctrl,int * idx)3645 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
3646 {
3647     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3648     size_t i, pane_count = all_panes.GetCount();
3649     for (i = 0; i < pane_count; ++i)
3650     {
3651         if (all_panes.Item(i).name == wxT("dummy"))
3652             continue;
3653 
3654         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3655 
3656         int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
3657         if (page_idx != -1)
3658         {
3659             *ctrl = tabframe->m_tabs;
3660             *idx = page_idx;
3661             return true;
3662         }
3663     }
3664 
3665     return false;
3666 }
3667 
Split(size_t page,int direction)3668 void wxAuiNotebook::Split(size_t page, int direction)
3669 {
3670     wxSize cli_size = GetClientSize();
3671 
3672     // get the page's window pointer
3673     wxWindow* wnd = GetPage(page);
3674     if (!wnd)
3675         return;
3676 
3677     // notebooks with 1 or less pages can't be split
3678     if (GetPageCount() < 2)
3679         return;
3680 
3681     // find out which tab control the page currently belongs to
3682     wxAuiTabCtrl *src_tabs, *dest_tabs;
3683     int src_idx = -1;
3684     src_tabs = NULL;
3685     if (!FindTab(wnd, &src_tabs, &src_idx))
3686         return;
3687     if (!src_tabs || src_idx == -1)
3688         return;
3689 
3690     // choose a split size
3691     wxSize split_size;
3692     if (GetPageCount() > 2)
3693     {
3694         split_size = CalculateNewSplitSize();
3695     }
3696      else
3697     {
3698         // because there are two panes, always split them
3699         // equally
3700         split_size = GetClientSize();
3701         split_size.x /= 2;
3702         split_size.y /= 2;
3703     }
3704 
3705 
3706     // create a new tab frame
3707     wxTabFrame* new_tabs = new wxTabFrame;
3708     new_tabs->m_rect = wxRect(wxPoint(0,0), split_size);
3709     new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3710     new_tabs->m_tabs = new wxAuiTabCtrl(this,
3711                                         m_tab_id_counter++,
3712                                         wxDefaultPosition,
3713                                         wxDefaultSize,
3714                                         wxNO_BORDER|wxWANTS_CHARS);
3715     new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3716     new_tabs->m_tabs->SetFlags(m_flags);
3717     dest_tabs = new_tabs->m_tabs;
3718 
3719     // create a pane info structure with the information
3720     // about where the pane should be added
3721     wxAuiPaneInfo pane_info = wxAuiPaneInfo().Bottom().CaptionVisible(false);
3722     wxPoint mouse_pt;
3723 
3724     if (direction == wxLEFT)
3725     {
3726         pane_info.Left();
3727         mouse_pt = wxPoint(0, cli_size.y/2);
3728     }
3729      else if (direction == wxRIGHT)
3730     {
3731         pane_info.Right();
3732         mouse_pt = wxPoint(cli_size.x, cli_size.y/2);
3733     }
3734      else if (direction == wxTOP)
3735     {
3736         pane_info.Top();
3737         mouse_pt = wxPoint(cli_size.x/2, 0);
3738     }
3739      else if (direction == wxBOTTOM)
3740     {
3741         pane_info.Bottom();
3742         mouse_pt = wxPoint(cli_size.x/2, cli_size.y);
3743     }
3744 
3745     m_mgr.AddPane(new_tabs, pane_info, mouse_pt);
3746     m_mgr.Update();
3747 
3748     // remove the page from the source tabs
3749     wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx);
3750     page_info.active = false;
3751     src_tabs->RemovePage(page_info.window);
3752     if (src_tabs->GetPageCount() > 0)
3753     {
3754         src_tabs->SetActivePage((size_t)0);
3755         src_tabs->DoShowHide();
3756         src_tabs->Refresh();
3757     }
3758 
3759 
3760     // add the page to the destination tabs
3761     dest_tabs->InsertPage(page_info.window, page_info, 0);
3762 
3763     if (src_tabs->GetPageCount() == 0)
3764     {
3765         RemoveEmptyTabFrames();
3766     }
3767 
3768     DoSizing();
3769     dest_tabs->DoShowHide();
3770     dest_tabs->Refresh();
3771 
3772     // force the set selection function reset the selection
3773     m_curpage = -1;
3774 
3775     // set the active page to the one we just split off
3776     SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
3777 
3778     UpdateHintWindowSize();
3779 }
3780 
3781 
OnSize(wxSizeEvent & evt)3782 void wxAuiNotebook::OnSize(wxSizeEvent& evt)
3783 {
3784     UpdateHintWindowSize();
3785 
3786     evt.Skip();
3787 }
3788 
OnTabClicked(wxCommandEvent & command_evt)3789 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
3790 {
3791     wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3792 
3793     wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
3794     wxASSERT(ctrl != NULL);
3795 
3796     wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
3797     wxASSERT(wnd != NULL);
3798 
3799     int idx = m_tabs.GetIdxFromWindow(wnd);
3800     wxASSERT(idx != -1);
3801 
3802 
3803     // since a tab was clicked, let the parent know that we received
3804     // the focus, even if we will assign that focus immediately
3805     // to the child tab in the SetSelection call below
3806     // (the child focus event will also let wxAuiManager, if any,
3807     // know that the notebook control has been activated)
3808 
3809     wxWindow* parent = GetParent();
3810     if (parent)
3811     {
3812         wxChildFocusEvent eventFocus(this);
3813         parent->GetEventHandler()->ProcessEvent(eventFocus);
3814     }
3815 
3816 
3817     SetSelection(idx);
3818 }
3819 
OnTabBgDClick(wxCommandEvent & WXUNUSED (evt))3820 void wxAuiNotebook::OnTabBgDClick(wxCommandEvent& WXUNUSED(evt))
3821 {
3822     // notify owner that the tabbar background has been double-clicked
3823     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, m_windowId);
3824     e.SetEventObject(this);
3825     GetEventHandler()->ProcessEvent(e);
3826 }
3827 
OnTabBeginDrag(wxCommandEvent &)3828 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
3829 {
3830     m_last_drag_x = 0;
3831 }
3832 
OnTabDragMotion(wxCommandEvent & evt)3833 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
3834 {
3835     wxPoint screen_pt = ::wxGetMousePosition();
3836     wxPoint client_pt = ScreenToClient(screen_pt);
3837     wxPoint zero(0,0);
3838 
3839     wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3840     wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
3841 
3842     if (dest_tabs == src_tabs)
3843     {
3844         if (src_tabs)
3845         {
3846             src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3847         }
3848 
3849         // always hide the hint for inner-tabctrl drag
3850         m_mgr.HideHint();
3851 
3852         // if tab moving is not allowed, leave
3853         if (!(m_flags & wxAUI_NB_TAB_MOVE))
3854         {
3855             return;
3856         }
3857 
3858         wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
3859         wxWindow* dest_location_tab;
3860 
3861         // this is an inner-tab drag/reposition
3862         if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
3863         {
3864             int src_idx = evt.GetSelection();
3865             int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
3866 
3867             // prevent jumpy drag
3868             if ((src_idx == dest_idx) || dest_idx == -1 ||
3869                 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
3870                 (src_idx < dest_idx && m_last_drag_x >= pt.x))
3871             {
3872                 m_last_drag_x = pt.x;
3873                 return;
3874             }
3875 
3876 
3877             wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
3878             dest_tabs->MovePage(src_tab, dest_idx);
3879             dest_tabs->SetActivePage((size_t)dest_idx);
3880             dest_tabs->DoShowHide();
3881             dest_tabs->Refresh();
3882             m_last_drag_x = pt.x;
3883 
3884         }
3885 
3886         return;
3887     }
3888 
3889 
3890     // if external drag is allowed, check if the tab is being dragged
3891     // over a different wxAuiNotebook control
3892     if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3893     {
3894         wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
3895 
3896         // if we aren't over any window, stop here
3897         if (!tab_ctrl)
3898             return;
3899 
3900         // make sure we are not over the hint window
3901         if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
3902         {
3903             while (tab_ctrl)
3904             {
3905                 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3906                     break;
3907                 tab_ctrl = tab_ctrl->GetParent();
3908             }
3909 
3910             if (tab_ctrl)
3911             {
3912                 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3913 
3914                 if (nb != this)
3915                 {
3916                     wxRect hint_rect = tab_ctrl->GetClientRect();
3917                     tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
3918                     m_mgr.ShowHint(hint_rect);
3919                     return;
3920                 }
3921             }
3922         }
3923          else
3924         {
3925             if (!dest_tabs)
3926             {
3927                 // we are either over a hint window, or not over a tab
3928                 // window, and there is no where to drag to, so exit
3929                 return;
3930             }
3931         }
3932     }
3933 
3934 
3935     // if there are less than two panes, split can't happen, so leave
3936     if (m_tabs.GetPageCount() < 2)
3937         return;
3938 
3939     // if tab moving is not allowed, leave
3940     if (!(m_flags & wxAUI_NB_TAB_SPLIT))
3941         return;
3942 
3943 
3944     if (src_tabs)
3945     {
3946         src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
3947     }
3948 
3949 
3950     if (dest_tabs)
3951     {
3952         wxRect hint_rect = dest_tabs->GetRect();
3953         ClientToScreen(&hint_rect.x, &hint_rect.y);
3954         m_mgr.ShowHint(hint_rect);
3955     }
3956      else
3957     {
3958         m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
3959     }
3960 }
3961 
3962 
3963 
OnTabEndDrag(wxCommandEvent & command_evt)3964 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
3965 {
3966     wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3967 
3968     m_mgr.HideHint();
3969 
3970 
3971     wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3972     wxAuiTabCtrl* dest_tabs = NULL;
3973     if (src_tabs)
3974     {
3975         // set cursor back to an arrow
3976         src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3977     }
3978 
3979     // get the mouse position, which will be used to determine the drop point
3980     wxPoint mouse_screen_pt = ::wxGetMousePosition();
3981     wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
3982 
3983 
3984 
3985     // check for an external move
3986     if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3987     {
3988         wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
3989 
3990         while (tab_ctrl)
3991         {
3992             if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3993                 break;
3994             tab_ctrl = tab_ctrl->GetParent();
3995         }
3996 
3997         if (tab_ctrl)
3998         {
3999             wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
4000 
4001             if (nb != this)
4002             {
4003                 // find out from the destination control
4004                 // if it's ok to drop this tab here
4005                 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
4006                 e.SetSelection(evt.GetSelection());
4007                 e.SetOldSelection(evt.GetSelection());
4008                 e.SetEventObject(this);
4009                 e.SetDragSource(this);
4010                 e.Veto(); // dropping must be explicitly approved by control owner
4011 
4012                 nb->GetEventHandler()->ProcessEvent(e);
4013 
4014                 if (!e.IsAllowed())
4015                 {
4016                     // no answer or negative answer
4017                     m_mgr.HideHint();
4018                     return;
4019                 }
4020 
4021                 // drop was allowed
4022                 int src_idx = evt.GetSelection();
4023                 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
4024 
4025                 // Check that it's not an impossible parent relationship
4026                 wxWindow* p = nb;
4027                 while (p && !p->IsTopLevel())
4028                 {
4029                     if (p == src_page)
4030                     {
4031                         return;
4032                     }
4033                     p = p->GetParent();
4034                 }
4035 
4036                 // get main index of the page
4037                 int main_idx = m_tabs.GetIdxFromWindow(src_page);
4038 
4039                 // make a copy of the page info
4040                 wxAuiNotebookPage page_info = m_tabs.GetPage((size_t)main_idx);
4041 
4042                 // remove the page from the source notebook
4043                 RemovePage(main_idx);
4044 
4045                 // reparent the page
4046                 src_page->Reparent(nb);
4047 
4048 
4049                 // found out the insert idx
4050                 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
4051                 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
4052 
4053                 wxWindow* target = NULL;
4054                 int insert_idx = -1;
4055                 dest_tabs->TabHitTest(pt.x, pt.y, &target);
4056                 if (target)
4057                 {
4058                     insert_idx = dest_tabs->GetIdxFromWindow(target);
4059                 }
4060 
4061 
4062                 // add the page to the new notebook
4063                 if (insert_idx == -1)
4064                     insert_idx = dest_tabs->GetPageCount();
4065                 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
4066                 nb->m_tabs.AddPage(page_info.window, page_info);
4067 
4068                 nb->DoSizing();
4069                 dest_tabs->DoShowHide();
4070                 dest_tabs->Refresh();
4071 
4072                 // set the selection in the destination tab control
4073                 nb->SetSelection(nb->m_tabs.GetIdxFromWindow(page_info.window));
4074 
4075                 // notify owner that the tab has been dragged
4076                 wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId);
4077                 e2.SetSelection(evt.GetSelection());
4078                 e2.SetOldSelection(evt.GetSelection());
4079                 e2.SetEventObject(this);
4080                 GetEventHandler()->ProcessEvent(e2);
4081 
4082                 return;
4083             }
4084         }
4085     }
4086 
4087 
4088 
4089 
4090     // only perform a tab split if it's allowed
4091     if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
4092     {
4093         // If the pointer is in an existing tab frame, do a tab insert
4094         wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
4095         wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
4096         int insert_idx = -1;
4097         if (tab_frame)
4098         {
4099             dest_tabs = tab_frame->m_tabs;
4100 
4101             if (dest_tabs == src_tabs)
4102                 return;
4103 
4104 
4105             wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
4106             wxWindow* target = NULL;
4107             dest_tabs->TabHitTest(pt.x, pt.y, &target);
4108             if (target)
4109             {
4110                 insert_idx = dest_tabs->GetIdxFromWindow(target);
4111             }
4112         }
4113         else
4114         {
4115             wxPoint zero(0,0);
4116             wxRect rect = m_mgr.CalculateHintRect(m_dummy_wnd,
4117                                                   mouse_client_pt,
4118                                                   zero);
4119             if (rect.IsEmpty())
4120             {
4121                 // there is no suitable drop location here, exit out
4122                 return;
4123             }
4124 
4125             // If there is no tabframe at all, create one
4126             wxTabFrame* new_tabs = new wxTabFrame;
4127             new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
4128             new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
4129             new_tabs->m_tabs = new wxAuiTabCtrl(this,
4130                                                 m_tab_id_counter++,
4131                                                 wxDefaultPosition,
4132                                                 wxDefaultSize,
4133                                                 wxNO_BORDER|wxWANTS_CHARS);
4134             new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
4135             new_tabs->m_tabs->SetFlags(m_flags);
4136 
4137             m_mgr.AddPane(new_tabs,
4138                           wxAuiPaneInfo().Bottom().CaptionVisible(false),
4139                           mouse_client_pt);
4140             m_mgr.Update();
4141             dest_tabs = new_tabs->m_tabs;
4142         }
4143 
4144 
4145 
4146         // remove the page from the source tabs
4147         wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
4148         page_info.active = false;
4149         src_tabs->RemovePage(page_info.window);
4150         if (src_tabs->GetPageCount() > 0)
4151         {
4152             src_tabs->SetActivePage((size_t)0);
4153             src_tabs->DoShowHide();
4154             src_tabs->Refresh();
4155         }
4156 
4157 
4158 
4159         // add the page to the destination tabs
4160         if (insert_idx == -1)
4161             insert_idx = dest_tabs->GetPageCount();
4162         dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
4163 
4164         if (src_tabs->GetPageCount() == 0)
4165         {
4166             RemoveEmptyTabFrames();
4167         }
4168 
4169         DoSizing();
4170         dest_tabs->DoShowHide();
4171         dest_tabs->Refresh();
4172 
4173         // force the set selection function reset the selection
4174         m_curpage = -1;
4175 
4176         // set the active page to the one we just split off
4177         SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
4178 
4179         UpdateHintWindowSize();
4180     }
4181 
4182     // notify owner that the tab has been dragged
4183     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId);
4184     e.SetSelection(evt.GetSelection());
4185     e.SetOldSelection(evt.GetSelection());
4186     e.SetEventObject(this);
4187     GetEventHandler()->ProcessEvent(e);
4188 }
4189 
4190 
4191 
GetTabCtrlFromPoint(const wxPoint & pt)4192 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
4193 {
4194     // if we've just removed the last tab from the source
4195     // tab set, the remove the tab control completely
4196     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
4197     size_t i, pane_count = all_panes.GetCount();
4198     for (i = 0; i < pane_count; ++i)
4199     {
4200         if (all_panes.Item(i).name == wxT("dummy"))
4201             continue;
4202 
4203         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
4204         if (tabframe->m_tab_rect.Contains(pt))
4205             return tabframe->m_tabs;
4206     }
4207 
4208     return NULL;
4209 }
4210 
GetTabFrameFromTabCtrl(wxWindow * tab_ctrl)4211 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
4212 {
4213     // if we've just removed the last tab from the source
4214     // tab set, the remove the tab control completely
4215     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
4216     size_t i, pane_count = all_panes.GetCount();
4217     for (i = 0; i < pane_count; ++i)
4218     {
4219         if (all_panes.Item(i).name == wxT("dummy"))
4220             continue;
4221 
4222         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
4223         if (tabframe->m_tabs == tab_ctrl)
4224         {
4225             return tabframe;
4226         }
4227     }
4228 
4229     return NULL;
4230 }
4231 
RemoveEmptyTabFrames()4232 void wxAuiNotebook::RemoveEmptyTabFrames()
4233 {
4234     // if we've just removed the last tab from the source
4235     // tab set, the remove the tab control completely
4236     wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
4237     size_t i, pane_count = all_panes.GetCount();
4238     for (i = 0; i < pane_count; ++i)
4239     {
4240         if (all_panes.Item(i).name == wxT("dummy"))
4241             continue;
4242 
4243         wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
4244         if (tab_frame->m_tabs->GetPageCount() == 0)
4245         {
4246             m_mgr.DetachPane(tab_frame);
4247 
4248             // use pending delete because sometimes during
4249             // window closing, refreshs are pending
4250             if (!wxPendingDelete.Member(tab_frame->m_tabs))
4251                 wxPendingDelete.Append(tab_frame->m_tabs);
4252 
4253             tab_frame->m_tabs = NULL;
4254 
4255             delete tab_frame;
4256         }
4257     }
4258 
4259 
4260     // check to see if there is still a center pane;
4261     // if there isn't, make a frame the center pane
4262     wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
4263     pane_count = panes.GetCount();
4264     wxWindow* first_good = NULL;
4265     bool center_found = false;
4266     for (i = 0; i < pane_count; ++i)
4267     {
4268         if (panes.Item(i).name == wxT("dummy"))
4269             continue;
4270         if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
4271             center_found = true;
4272         if (!first_good)
4273             first_good = panes.Item(i).window;
4274     }
4275 
4276     if (!center_found && first_good)
4277     {
4278         m_mgr.GetPane(first_good).Centre();
4279     }
4280 
4281     if (!m_isBeingDeleted)
4282         m_mgr.Update();
4283 }
4284 
OnChildFocus(wxChildFocusEvent & evt)4285 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
4286 {
4287     // if we're dragging a tab, don't change the current selection.
4288     // This code prevents a bug that used to happen when the hint window
4289     // was hidden.  In the bug, the focus would return to the notebook
4290     // child, which would then enter this handler and call
4291     // SetSelection, which is not desired turn tab dragging.
4292 
4293     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
4294     size_t i, pane_count = all_panes.GetCount();
4295     for (i = 0; i < pane_count; ++i)
4296     {
4297         wxAuiPaneInfo& pane = all_panes.Item(i);
4298         if (pane.name == wxT("dummy"))
4299             continue;
4300         wxTabFrame* tabframe = (wxTabFrame*)pane.window;
4301         if (tabframe->m_tabs->IsDragging())
4302             return;
4303     }
4304 
4305 
4306     // change the tab selection to the child
4307     // which was focused
4308     int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
4309     if (idx != -1 && idx != m_curpage)
4310     {
4311         SetSelection(idx);
4312     }
4313 }
4314 
OnNavigationKey(wxNavigationKeyEvent & event)4315 void wxAuiNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
4316 {
4317     if ( event.IsWindowChange() ) {
4318         // change pages
4319         // FIXME: the problem with this is that if we have a split notebook,
4320         // we selection may go all over the place.
4321         AdvanceSelection(event.GetDirection());
4322     }
4323     else {
4324         // we get this event in 3 cases
4325         //
4326         // a) one of our pages might have generated it because the user TABbed
4327         // out from it in which case we should propagate the event upwards and
4328         // our parent will take care of setting the focus to prev/next sibling
4329         //
4330         // or
4331         //
4332         // b) the parent panel wants to give the focus to us so that we
4333         // forward it to our selected page. We can't deal with this in
4334         // OnSetFocus() because we don't know which direction the focus came
4335         // from in this case and so can't choose between setting the focus to
4336         // first or last panel child
4337         //
4338         // or
4339         //
4340         // c) we ourselves (see MSWTranslateMessage) generated the event
4341         //
4342         wxWindow * const parent = GetParent();
4343 
4344         // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
4345         const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
4346         const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
4347 
4348         if ( isFromParent || isFromSelf )
4349         {
4350             // no, it doesn't come from child, case (b) or (c): forward to a
4351             // page but only if direction is backwards (TAB) or from ourselves,
4352             if ( GetSelection() != wxNOT_FOUND &&
4353                     (!event.GetDirection() || isFromSelf) )
4354             {
4355                 // so that the page knows that the event comes from it's parent
4356                 // and is being propagated downwards
4357                 event.SetEventObject(this);
4358 
4359                 wxWindow *page = GetPage(GetSelection());
4360                 if ( !page->GetEventHandler()->ProcessEvent(event) )
4361                 {
4362                     page->SetFocus();
4363                 }
4364                 //else: page manages focus inside it itself
4365             }
4366             else // otherwise set the focus to the notebook itself
4367             {
4368                 SetFocus();
4369             }
4370         }
4371         else
4372         {
4373             // it comes from our child, case (a), pass to the parent, but only
4374             // if the direction is forwards. Otherwise set the focus to the
4375             // notebook itself. The notebook is always the 'first' control of a
4376             // page.
4377             if ( !event.GetDirection() )
4378             {
4379                 SetFocus();
4380             }
4381             else if ( parent )
4382             {
4383                 event.SetCurrentFocus(this);
4384                 parent->GetEventHandler()->ProcessEvent(event);
4385             }
4386         }
4387     }
4388 }
4389 
OnTabButton(wxCommandEvent & command_evt)4390 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
4391 {
4392     wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
4393     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4394 
4395     int button_id = evt.GetInt();
4396 
4397     if (button_id == wxAUI_BUTTON_CLOSE)
4398     {
4399         int selection = evt.GetSelection();
4400 
4401         if (selection == -1)
4402         {
4403             // if the close button is to the right, use the active
4404             // page selection to determine which page to close
4405             selection = tabs->GetActivePage();
4406         }
4407 
4408         if (selection != -1)
4409         {
4410             wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
4411 
4412             // ask owner if it's ok to close the tab
4413             wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
4414             const int idx = m_tabs.GetIdxFromWindow(close_wnd);
4415             e.SetSelection(idx);
4416             e.SetOldSelection(evt.GetSelection());
4417             e.SetEventObject(this);
4418             GetEventHandler()->ProcessEvent(e);
4419             if (!e.IsAllowed())
4420                 return;
4421 
4422 
4423 #if wxUSE_MDI
4424             if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
4425             {
4426                 close_wnd->Close();
4427             }
4428             else
4429 #endif
4430             {
4431                 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
4432                 DeletePage(main_idx);
4433             }
4434 
4435             // notify owner that the tab has been closed
4436             wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, m_windowId);
4437             e2.SetSelection(idx);
4438             e2.SetEventObject(this);
4439             GetEventHandler()->ProcessEvent(e2);
4440         }
4441     }
4442 }
4443 
OnTabMiddleDown(wxCommandEvent & evt)4444 void wxAuiNotebook::OnTabMiddleDown(wxCommandEvent& evt)
4445 {
4446     // patch event through to owner
4447     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4448     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
4449 
4450     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
4451     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
4452     e.SetEventObject(this);
4453     GetEventHandler()->ProcessEvent(e);
4454 }
4455 
OnTabMiddleUp(wxCommandEvent & evt)4456 void wxAuiNotebook::OnTabMiddleUp(wxCommandEvent& evt)
4457 {
4458     // if the wxAUI_NB_MIDDLE_CLICK_CLOSE is specified, middle
4459     // click should act like a tab close action.  However, first
4460     // give the owner an opportunity to handle the middle up event
4461     // for custom action
4462 
4463     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4464     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
4465 
4466     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
4467     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
4468     e.SetEventObject(this);
4469     if (GetEventHandler()->ProcessEvent(e))
4470         return;
4471     if (!e.IsAllowed())
4472         return;
4473 
4474     // check if we are supposed to close on middle-up
4475     if ((m_flags & wxAUI_NB_MIDDLE_CLICK_CLOSE) == 0)
4476         return;
4477 
4478     // simulate the user pressing the close button on the tab
4479     evt.SetInt(wxAUI_BUTTON_CLOSE);
4480     OnTabButton(evt);
4481 }
4482 
OnTabRightDown(wxCommandEvent & evt)4483 void wxAuiNotebook::OnTabRightDown(wxCommandEvent& evt)
4484 {
4485     // patch event through to owner
4486     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4487     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
4488 
4489     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
4490     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
4491     e.SetEventObject(this);
4492     GetEventHandler()->ProcessEvent(e);
4493 }
4494 
OnTabRightUp(wxCommandEvent & evt)4495 void wxAuiNotebook::OnTabRightUp(wxCommandEvent& evt)
4496 {
4497     // patch event through to owner
4498     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4499     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
4500 
4501     wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
4502     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
4503     e.SetEventObject(this);
4504     GetEventHandler()->ProcessEvent(e);
4505 }
4506 
4507 
4508 
4509 // Sets the normal font
SetNormalFont(const wxFont & font)4510 void wxAuiNotebook::SetNormalFont(const wxFont& font)
4511 {
4512     m_normal_font = font;
4513     GetArtProvider()->SetNormalFont(font);
4514 }
4515 
4516 // Sets the selected tab font
SetSelectedFont(const wxFont & font)4517 void wxAuiNotebook::SetSelectedFont(const wxFont& font)
4518 {
4519     m_selected_font = font;
4520     GetArtProvider()->SetSelectedFont(font);
4521 }
4522 
4523 // Sets the measuring font
SetMeasuringFont(const wxFont & font)4524 void wxAuiNotebook::SetMeasuringFont(const wxFont& font)
4525 {
4526     GetArtProvider()->SetMeasuringFont(font);
4527 }
4528 
4529 // Sets the tab font
SetFont(const wxFont & font)4530 bool wxAuiNotebook::SetFont(const wxFont& font)
4531 {
4532     wxControl::SetFont(font);
4533 
4534     wxFont normalFont(font);
4535     wxFont selectedFont(normalFont);
4536     selectedFont.SetWeight(wxBOLD);
4537 
4538     SetNormalFont(normalFont);
4539     SetSelectedFont(selectedFont);
4540     SetMeasuringFont(selectedFont);
4541 
4542     return true;
4543 }
4544 
4545 // Gets the tab control height
GetTabCtrlHeight() const4546 int wxAuiNotebook::GetTabCtrlHeight() const
4547 {
4548     return m_tab_ctrl_height;
4549 }
4550 
4551 // Gets the height of the notebook for a given page height
GetHeightForPageHeight(int pageHeight)4552 int wxAuiNotebook::GetHeightForPageHeight(int pageHeight)
4553 {
4554     UpdateTabCtrlHeight();
4555 
4556     int tabCtrlHeight = GetTabCtrlHeight();
4557     int decorHeight = 2;
4558     return tabCtrlHeight + pageHeight + decorHeight;
4559 }
4560 
4561 // Advances the selection, generation page selection events
AdvanceSelection(bool forward)4562 void wxAuiNotebook::AdvanceSelection(bool forward)
4563 {
4564     if (GetPageCount() <= 1)
4565         return;
4566 
4567     int currentSelection = GetSelection();
4568 
4569     if (forward)
4570     {
4571         if (currentSelection == (int) (GetPageCount() - 1))
4572             return;
4573         else if (currentSelection == -1)
4574             currentSelection = 0;
4575         else
4576             currentSelection ++;
4577     }
4578     else
4579     {
4580         if (currentSelection <= 0)
4581             return;
4582         else
4583             currentSelection --;
4584     }
4585 
4586     SetSelection(currentSelection);
4587 }
4588 
4589 // Shows the window menu
ShowWindowMenu()4590 bool wxAuiNotebook::ShowWindowMenu()
4591 {
4592     wxAuiTabCtrl* tabCtrl = GetActiveTabCtrl();
4593 
4594     int idx = tabCtrl->GetArtProvider()->ShowDropDown(tabCtrl, tabCtrl->GetPages(), tabCtrl->GetActivePage());
4595 
4596     if (idx != -1)
4597     {
4598         wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl->GetId());
4599         e.SetSelection(idx);
4600         e.SetOldSelection(tabCtrl->GetActivePage());
4601         e.SetEventObject(tabCtrl);
4602         GetEventHandler()->ProcessEvent(e);
4603 
4604         return true;
4605     }
4606     else
4607         return false;
4608 }
4609 
4610 #endif // wxUSE_AUI
4611