1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/aui/auibook.cpp
3 // Purpose:     wxaui: wx advanced user interface - notebook
4 // Author:      Benjamin I. Williams
5 // Modified by: Jens Lody
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/dcclient.h"
28     #include "wx/dcmemory.h"
29 #endif
30 
31 #include "wx/aui/tabmdi.h"
32 
33 #ifdef __WXMAC__
34 #include "wx/osx/private.h"
35 #endif
36 
37 #include "wx/arrimpl.cpp"
38 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
39 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
40 
41 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEvent);
42 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEvent);
43 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_PAGE_CHANGING, wxAuiNotebookEvent);
44 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEvent);
45 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_BUTTON, wxAuiNotebookEvent);
46 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_BEGIN_DRAG, wxAuiNotebookEvent);
47 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_END_DRAG, wxAuiNotebookEvent);
48 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_CANCEL_DRAG, wxAuiNotebookEvent);
49 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_DRAG_MOTION, wxAuiNotebookEvent);
50 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_ALLOW_DND, wxAuiNotebookEvent);
51 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_BG_DCLICK, wxAuiNotebookEvent);
52 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_DRAG_DONE, wxAuiNotebookEvent);
53 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_TAB_MIDDLE_UP, wxAuiNotebookEvent);
54 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_TAB_MIDDLE_DOWN, wxAuiNotebookEvent);
55 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_TAB_RIGHT_UP, wxAuiNotebookEvent);
56 wxDEFINE_EVENT(wxEVT_AUINOTEBOOK_TAB_RIGHT_DOWN, wxAuiNotebookEvent);
57 
IMPLEMENT_CLASS(wxAuiNotebook,wxControl)58 IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
59 IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl)
60 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxBookCtrlEvent)
61 
62 
63 // -- wxAuiTabContainer class implementation --
64 
65 
66 // wxAuiTabContainer is a class which contains information about each
67 // tab.  It also can render an entire tab control to a specified DC.
68 // It's not a window class itself, because this code will be used by
69 // the wxFrameMananger, where it is disadvantageous to have separate
70 // windows for each tab control in the case of "docked tabs"
71 
72 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
73 // which can be used as a tab control in the normal sense.
74 
75 
76 wxAuiTabContainer::wxAuiTabContainer()
77 {
78     m_tabOffset = 0;
79     m_flags = 0;
80     m_art = new wxAuiDefaultTabArt;
81 
82     AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
83     AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
84     AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
85     AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
86 }
87 
~wxAuiTabContainer()88 wxAuiTabContainer::~wxAuiTabContainer()
89 {
90     delete m_art;
91 }
92 
SetArtProvider(wxAuiTabArt * art)93 void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art)
94 {
95     delete m_art;
96     m_art = art;
97 
98     if (m_art)
99     {
100         m_art->SetFlags(m_flags);
101     }
102 }
103 
GetArtProvider() const104 wxAuiTabArt* wxAuiTabContainer::GetArtProvider() const
105 {
106     return m_art;
107 }
108 
SetFlags(unsigned int flags)109 void wxAuiTabContainer::SetFlags(unsigned int flags)
110 {
111     m_flags = flags;
112 
113     // check for new close button settings
114     RemoveButton(wxAUI_BUTTON_LEFT);
115     RemoveButton(wxAUI_BUTTON_RIGHT);
116     RemoveButton(wxAUI_BUTTON_WINDOWLIST);
117     RemoveButton(wxAUI_BUTTON_CLOSE);
118 
119 
120     if (flags & wxAUI_NB_SCROLL_BUTTONS)
121     {
122         AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
123         AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
124     }
125 
126     if (flags & wxAUI_NB_WINDOWLIST_BUTTON)
127     {
128         AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
129     }
130 
131     if (flags & wxAUI_NB_CLOSE_BUTTON)
132     {
133         AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
134     }
135 
136     if (m_art)
137     {
138         m_art->SetFlags(m_flags);
139     }
140 }
141 
GetFlags() const142 unsigned int wxAuiTabContainer::GetFlags() const
143 {
144     return m_flags;
145 }
146 
147 
SetNormalFont(const wxFont & font)148 void wxAuiTabContainer::SetNormalFont(const wxFont& font)
149 {
150     m_art->SetNormalFont(font);
151 }
152 
SetSelectedFont(const wxFont & font)153 void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
154 {
155     m_art->SetSelectedFont(font);
156 }
157 
SetMeasuringFont(const wxFont & font)158 void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
159 {
160     m_art->SetMeasuringFont(font);
161 }
162 
SetColour(const wxColour & colour)163 void wxAuiTabContainer::SetColour(const wxColour& colour)
164 {
165     m_art->SetColour(colour);
166 }
167 
SetActiveColour(const wxColour & colour)168 void wxAuiTabContainer::SetActiveColour(const wxColour& colour)
169 {
170     m_art->SetActiveColour(colour);
171 }
172 
SetRect(const wxRect & rect)173 void wxAuiTabContainer::SetRect(const wxRect& rect)
174 {
175     m_rect = rect;
176 
177     if (m_art)
178     {
179         m_art->SetSizingInfo(rect.GetSize(), m_pages.GetCount());
180     }
181 }
182 
AddPage(wxWindow * page,const wxAuiNotebookPage & info)183 bool wxAuiTabContainer::AddPage(wxWindow* page,
184                                 const wxAuiNotebookPage& info)
185 {
186     wxAuiNotebookPage page_info;
187     page_info = info;
188     page_info.window = page;
189 
190     m_pages.Add(page_info);
191 
192     // let the art provider know how many pages we have
193     if (m_art)
194     {
195         m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
196     }
197 
198     return true;
199 }
200 
InsertPage(wxWindow * page,const wxAuiNotebookPage & info,size_t idx)201 bool wxAuiTabContainer::InsertPage(wxWindow* page,
202                                    const wxAuiNotebookPage& info,
203                                    size_t idx)
204 {
205     wxAuiNotebookPage page_info;
206     page_info = info;
207     page_info.window = page;
208 
209     if (idx >= m_pages.GetCount())
210         m_pages.Add(page_info);
211     else
212         m_pages.Insert(page_info, idx);
213 
214     // let the art provider know how many pages we have
215     if (m_art)
216     {
217         m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
218     }
219 
220     return true;
221 }
222 
MovePage(wxWindow * page,size_t new_idx)223 bool wxAuiTabContainer::MovePage(wxWindow* page,
224                                  size_t new_idx)
225 {
226     int idx = GetIdxFromWindow(page);
227     if (idx == -1)
228         return false;
229 
230     // get page entry, make a copy of it
231     wxAuiNotebookPage p = GetPage(idx);
232 
233     // remove old page entry
234     RemovePage(page);
235 
236     // insert page where it should be
237     InsertPage(page, p, new_idx);
238 
239     return true;
240 }
241 
RemovePage(wxWindow * wnd)242 bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
243 {
244     size_t i, page_count = m_pages.GetCount();
245     for (i = 0; i < page_count; ++i)
246     {
247         wxAuiNotebookPage& page = m_pages.Item(i);
248         if (page.window == wnd)
249         {
250             m_pages.RemoveAt(i);
251 
252             // let the art provider know how many pages we have
253             if (m_art)
254             {
255                 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
256             }
257 
258             return true;
259         }
260     }
261 
262     return false;
263 }
264 
SetActivePage(wxWindow * wnd)265 bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
266 {
267     bool found = false;
268 
269     size_t i, page_count = m_pages.GetCount();
270     for (i = 0; i < page_count; ++i)
271     {
272         wxAuiNotebookPage& page = m_pages.Item(i);
273         if (page.window == wnd)
274         {
275             page.active = true;
276             found = true;
277         }
278         else
279         {
280             page.active = false;
281         }
282     }
283 
284     return found;
285 }
286 
SetNoneActive()287 void wxAuiTabContainer::SetNoneActive()
288 {
289     size_t i, page_count = m_pages.GetCount();
290     for (i = 0; i < page_count; ++i)
291     {
292         wxAuiNotebookPage& page = m_pages.Item(i);
293         page.active = false;
294     }
295 }
296 
SetActivePage(size_t page)297 bool wxAuiTabContainer::SetActivePage(size_t page)
298 {
299     if (page >= m_pages.GetCount())
300         return false;
301 
302     return SetActivePage(m_pages.Item(page).window);
303 }
304 
GetActivePage() const305 int wxAuiTabContainer::GetActivePage() const
306 {
307     size_t i, page_count = m_pages.GetCount();
308     for (i = 0; i < page_count; ++i)
309     {
310         wxAuiNotebookPage& page = m_pages.Item(i);
311         if (page.active)
312             return i;
313     }
314 
315     return -1;
316 }
317 
GetWindowFromIdx(size_t idx) const318 wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
319 {
320     if (idx >= m_pages.GetCount())
321         return NULL;
322 
323     return m_pages[idx].window;
324 }
325 
GetIdxFromWindow(wxWindow * wnd) const326 int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
327 {
328     const size_t page_count = m_pages.GetCount();
329     for ( size_t i = 0; i < page_count; ++i )
330     {
331         wxAuiNotebookPage& page = m_pages.Item(i);
332         if (page.window == wnd)
333             return i;
334     }
335     return wxNOT_FOUND;
336 }
337 
GetPage(size_t idx)338 wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
339 {
340     wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
341 
342     return m_pages[idx];
343 }
344 
GetPage(size_t idx) const345 const wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx) const
346 {
347     wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
348 
349     return m_pages[idx];
350 }
351 
GetPages()352 wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
353 {
354     return m_pages;
355 }
356 
GetPageCount() const357 size_t wxAuiTabContainer::GetPageCount() const
358 {
359     return m_pages.GetCount();
360 }
361 
AddButton(int id,int location,const wxBitmap & normalBitmap,const wxBitmap & disabledBitmap)362 void wxAuiTabContainer::AddButton(int id,
363                                   int location,
364                                   const wxBitmap& normalBitmap,
365                                   const wxBitmap& disabledBitmap)
366 {
367     wxAuiTabContainerButton button;
368     button.id = id;
369     button.bitmap = normalBitmap;
370     button.disBitmap = disabledBitmap;
371     button.location = location;
372     button.curState = wxAUI_BUTTON_STATE_NORMAL;
373 
374     m_buttons.Add(button);
375 }
376 
RemoveButton(int id)377 void wxAuiTabContainer::RemoveButton(int id)
378 {
379     size_t i, button_count = m_buttons.GetCount();
380 
381     for (i = 0; i < button_count; ++i)
382     {
383         if (m_buttons.Item(i).id == id)
384         {
385             m_buttons.RemoveAt(i);
386             return;
387         }
388     }
389 }
390 
391 
392 
GetTabOffset() const393 size_t wxAuiTabContainer::GetTabOffset() const
394 {
395     return m_tabOffset;
396 }
397 
SetTabOffset(size_t offset)398 void wxAuiTabContainer::SetTabOffset(size_t offset)
399 {
400     m_tabOffset = offset;
401 }
402 
403 
404 
405 
406 // Render() renders the tab catalog to the specified DC
407 // It is a virtual function and can be overridden to
408 // provide custom drawing capabilities
Render(wxDC * raw_dc,wxWindow * wnd)409 void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd)
410 {
411     if (!raw_dc || !raw_dc->IsOk())
412         return;
413 
414     wxMemoryDC dc;
415 
416     // use the same layout direction as the window DC uses to ensure that the
417     // text is rendered correctly
418     dc.SetLayoutDirection(raw_dc->GetLayoutDirection());
419 
420     wxBitmap bmp;
421     size_t i;
422     size_t page_count = m_pages.GetCount();
423     size_t button_count = m_buttons.GetCount();
424 
425     // create off-screen bitmap
426     bmp.Create(m_rect.GetWidth(), m_rect.GetHeight(),*raw_dc);
427     dc.SelectObject(bmp);
428 
429     if (!dc.IsOk())
430         return;
431 
432     // find out if size of tabs is larger than can be
433     // afforded on screen
434     int total_width = 0;
435     int visible_width = 0;
436     for (i = 0; i < page_count; ++i)
437     {
438         wxAuiNotebookPage& page = m_pages.Item(i);
439 
440         // determine if a close button is on this tab
441         bool close_button = false;
442         if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
443             ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
444         {
445             close_button = true;
446         }
447 
448 
449         int x_extent = 0;
450         wxSize size = m_art->GetTabSize(dc,
451                             wnd,
452                             page.caption,
453                             page.bitmap,
454                             page.active,
455                             close_button ?
456                               wxAUI_BUTTON_STATE_NORMAL :
457                               wxAUI_BUTTON_STATE_HIDDEN,
458                             &x_extent);
459 
460         if (i+1 < page_count)
461             total_width += x_extent;
462         else
463             total_width += size.x;
464 
465         if (i >= m_tabOffset)
466         {
467             if (i+1 < page_count)
468                 visible_width += x_extent;
469             else
470                 visible_width += size.x;
471         }
472     }
473 
474     if (total_width > m_rect.GetWidth() || m_tabOffset != 0)
475     {
476         // show left/right buttons
477         for (i = 0; i < button_count; ++i)
478         {
479             wxAuiTabContainerButton& button = m_buttons.Item(i);
480             if (button.id == wxAUI_BUTTON_LEFT ||
481                 button.id == wxAUI_BUTTON_RIGHT)
482             {
483                 button.curState &= ~wxAUI_BUTTON_STATE_HIDDEN;
484             }
485         }
486     }
487     else
488     {
489         // hide left/right buttons
490         for (i = 0; i < button_count; ++i)
491         {
492             wxAuiTabContainerButton& button = m_buttons.Item(i);
493             if (button.id == wxAUI_BUTTON_LEFT ||
494                 button.id == wxAUI_BUTTON_RIGHT)
495             {
496                 button.curState |= wxAUI_BUTTON_STATE_HIDDEN;
497             }
498         }
499     }
500 
501     // determine whether left button should be enabled
502     for (i = 0; i < button_count; ++i)
503     {
504         wxAuiTabContainerButton& button = m_buttons.Item(i);
505         if (button.id == wxAUI_BUTTON_LEFT)
506         {
507             if (m_tabOffset == 0)
508                 button.curState |= wxAUI_BUTTON_STATE_DISABLED;
509             else
510                 button.curState &= ~wxAUI_BUTTON_STATE_DISABLED;
511         }
512         if (button.id == wxAUI_BUTTON_RIGHT)
513         {
514             if (visible_width < m_rect.GetWidth() - ((int)button_count*16))
515                 button.curState |= wxAUI_BUTTON_STATE_DISABLED;
516             else
517                 button.curState &= ~wxAUI_BUTTON_STATE_DISABLED;
518         }
519     }
520 
521 
522 
523     // draw background
524     m_art->DrawBackground(dc, wnd, m_rect);
525 
526     // draw buttons
527     int left_buttons_width = 0;
528     int right_buttons_width = 0;
529 
530     // draw the buttons on the right side
531     int offset = m_rect.x + m_rect.width;
532     for (i = 0; i < button_count; ++i)
533     {
534         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
535 
536         if (button.location != wxRIGHT)
537             continue;
538         if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
539             continue;
540 
541         wxRect button_rect = m_rect;
542         button_rect.SetY(1);
543         button_rect.SetWidth(offset);
544 
545         m_art->DrawButton(dc,
546                           wnd,
547                           button_rect,
548                           button.id,
549                           button.curState,
550                           wxRIGHT,
551                           &button.rect);
552 
553         offset -= button.rect.GetWidth();
554         right_buttons_width += button.rect.GetWidth();
555     }
556 
557 
558 
559     offset = 0;
560 
561     // draw the buttons on the left side
562 
563     for (i = 0; i < button_count; ++i)
564     {
565         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
566 
567         if (button.location != wxLEFT)
568             continue;
569         if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
570             continue;
571 
572         wxRect button_rect(offset, 1, 1000, m_rect.height);
573 
574         m_art->DrawButton(dc,
575                           wnd,
576                           button_rect,
577                           button.id,
578                           button.curState,
579                           wxLEFT,
580                           &button.rect);
581 
582         offset += button.rect.GetWidth();
583         left_buttons_width += button.rect.GetWidth();
584     }
585 
586     offset = left_buttons_width;
587 
588     if (offset == 0)
589         offset += m_art->GetIndentSize();
590 
591 
592     // prepare the tab-close-button array
593     // make sure tab button entries which aren't used are marked as hidden
594     for (i = page_count; i < m_tabCloseButtons.GetCount(); ++i)
595         m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
596 
597     // make sure there are enough tab button entries to accommodate all tabs
598     while (m_tabCloseButtons.GetCount() < page_count)
599     {
600         wxAuiTabContainerButton tempbtn;
601         tempbtn.id = wxAUI_BUTTON_CLOSE;
602         tempbtn.location = wxCENTER;
603         tempbtn.curState = wxAUI_BUTTON_STATE_HIDDEN;
604         m_tabCloseButtons.Add(tempbtn);
605     }
606 
607 
608     // buttons before the tab offset must be set to hidden
609     for (i = 0; i < m_tabOffset; ++i)
610     {
611         m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
612     }
613 
614 
615     // draw the tabs
616 
617     size_t active = 999;
618     int active_offset = 0;
619     wxRect active_rect;
620 
621     int x_extent = 0;
622     wxRect rect = m_rect;
623     rect.y = 0;
624     rect.height = m_rect.height;
625 
626     for (i = m_tabOffset; i < page_count; ++i)
627     {
628         wxAuiNotebookPage& page = m_pages.Item(i);
629         wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(i);
630 
631         // determine if a close button is on this tab
632         if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
633             ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
634         {
635             if (tab_button.curState == wxAUI_BUTTON_STATE_HIDDEN)
636             {
637                 tab_button.id = wxAUI_BUTTON_CLOSE;
638                 tab_button.curState = wxAUI_BUTTON_STATE_NORMAL;
639                 tab_button.location = wxCENTER;
640             }
641         }
642         else
643         {
644             tab_button.curState = wxAUI_BUTTON_STATE_HIDDEN;
645         }
646 
647         rect.x = offset;
648         rect.width = m_rect.width - right_buttons_width - offset - 2;
649 
650         if (rect.width <= 0)
651             break;
652 
653         m_art->DrawTab(dc,
654                        wnd,
655                        page,
656                        rect,
657                        tab_button.curState,
658                        &page.rect,
659                        &tab_button.rect,
660                        &x_extent);
661 
662         if (page.active)
663         {
664             active = i;
665             active_offset = offset;
666             active_rect = rect;
667         }
668 
669         offset += x_extent;
670     }
671 
672 
673     // make sure to deactivate buttons which are off the screen to the right
674     for (++i; i < m_tabCloseButtons.GetCount(); ++i)
675     {
676         m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
677     }
678 
679 
680     // draw the active tab again so it stands in the foreground
681     if (active >= m_tabOffset && active < m_pages.GetCount())
682     {
683         wxAuiNotebookPage& page = m_pages.Item(active);
684 
685         wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(active);
686 
687         rect.x = active_offset;
688         m_art->DrawTab(dc,
689                        wnd,
690                        page,
691                        active_rect,
692                        tab_button.curState,
693                        &page.rect,
694                        &tab_button.rect,
695                        &x_extent);
696     }
697 
698 
699     raw_dc->Blit(m_rect.x, m_rect.y,
700                  m_rect.GetWidth(), m_rect.GetHeight(),
701                  &dc, 0, 0);
702 }
703 
704 // Is the tab visible?
IsTabVisible(int tabPage,int tabOffset,wxDC * dc,wxWindow * wnd)705 bool wxAuiTabContainer::IsTabVisible(int tabPage, int tabOffset, wxDC* dc, wxWindow* wnd)
706 {
707     if (!dc || !dc->IsOk())
708         return false;
709 
710     size_t i;
711     size_t page_count = m_pages.GetCount();
712     size_t button_count = m_buttons.GetCount();
713 
714     // Hasn't been rendered yet; assume it's visible
715     if (m_tabCloseButtons.GetCount() < page_count)
716         return true;
717 
718     // First check if both buttons are disabled - if so, there's no need to
719     // check further for visibility.
720     int arrowButtonVisibleCount = 0;
721     for (i = 0; i < button_count; ++i)
722     {
723         wxAuiTabContainerButton& button = m_buttons.Item(i);
724         if (button.id == wxAUI_BUTTON_LEFT ||
725             button.id == wxAUI_BUTTON_RIGHT)
726         {
727             if ((button.curState & wxAUI_BUTTON_STATE_HIDDEN) == 0)
728                 arrowButtonVisibleCount ++;
729         }
730     }
731 
732     // Tab must be visible
733     if (arrowButtonVisibleCount == 0)
734         return true;
735 
736     // If tab is less than the given offset, it must be invisible by definition
737     if (tabPage < tabOffset)
738         return false;
739 
740     // draw buttons
741     int left_buttons_width = 0;
742     int right_buttons_width = 0;
743 
744     // calculate size of the buttons on the right side
745     int offset = m_rect.x + m_rect.width;
746     for (i = 0; i < button_count; ++i)
747     {
748         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
749 
750         if (button.location != wxRIGHT)
751             continue;
752         if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
753             continue;
754 
755         offset -= button.rect.GetWidth();
756         right_buttons_width += button.rect.GetWidth();
757     }
758 
759     offset = 0;
760 
761     // calculate size of the buttons on the left side
762     for (i = 0; i < button_count; ++i)
763     {
764         wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
765 
766         if (button.location != wxLEFT)
767             continue;
768         if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
769             continue;
770 
771         offset += button.rect.GetWidth();
772         left_buttons_width += button.rect.GetWidth();
773     }
774 
775     offset = left_buttons_width;
776 
777     if (offset == 0)
778         offset += m_art->GetIndentSize();
779 
780     wxRect active_rect;
781 
782     wxRect rect = m_rect;
783     rect.y = 0;
784     rect.height = m_rect.height;
785 
786     // See if the given page is visible at the given tab offset (effectively scroll position)
787     for (i = tabOffset; i < page_count; ++i)
788     {
789         wxAuiNotebookPage& page = m_pages.Item(i);
790         wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(i);
791 
792         rect.x = offset;
793         rect.width = m_rect.width - right_buttons_width - offset - 2;
794 
795         if (rect.width <= 0)
796             return false; // haven't found the tab, and we've run out of space, so return false
797 
798         int x_extent = 0;
799         m_art->GetTabSize(*dc,
800                             wnd,
801                             page.caption,
802                             page.bitmap,
803                             page.active,
804                             tab_button.curState,
805                             &x_extent);
806 
807         offset += x_extent;
808 
809         if (i == (size_t) tabPage)
810         {
811             // If not all of the tab is visible, and supposing there's space to display it all,
812             // we could do better so we return false.
813             if (((m_rect.width - right_buttons_width - offset - 2) <= 0) && ((m_rect.width - right_buttons_width - left_buttons_width) > x_extent))
814                 return false;
815             else
816                 return true;
817         }
818     }
819 
820     // Shouldn't really get here, but if it does, assume the tab is visible to prevent
821     // further looping in calling code.
822     return true;
823 }
824 
825 // Make the tab visible if it wasn't already
MakeTabVisible(int tabPage,wxWindow * win)826 void wxAuiTabContainer::MakeTabVisible(int tabPage, wxWindow* win)
827 {
828     wxClientDC dc(win);
829     if (!IsTabVisible(tabPage, GetTabOffset(), & dc, win))
830     {
831         int i;
832         for (i = 0; i < (int) m_pages.GetCount(); i++)
833         {
834             if (IsTabVisible(tabPage, i, & dc, win))
835             {
836                 SetTabOffset(i);
837                 win->Refresh();
838                 return;
839             }
840         }
841     }
842 }
843 
844 // TabHitTest() tests if a tab was hit, passing the window pointer
845 // back if that condition was fulfilled.  The function returns
846 // true if a tab was hit, otherwise false
TabHitTest(int x,int y,wxWindow ** hit) const847 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
848 {
849     if (!m_rect.Contains(x,y))
850         return false;
851 
852     wxAuiTabContainerButton* btn = NULL;
853     if (ButtonHitTest(x, y, &btn) && !(btn->curState & wxAUI_BUTTON_STATE_DISABLED))
854     {
855         if (m_buttons.Index(*btn) != wxNOT_FOUND)
856             return false;
857     }
858 
859     size_t i, page_count = m_pages.GetCount();
860 
861     for (i = m_tabOffset; i < page_count; ++i)
862     {
863         wxAuiNotebookPage& page = m_pages.Item(i);
864         if (page.rect.Contains(x,y))
865         {
866             if (hit)
867                 *hit = page.window;
868             return true;
869         }
870     }
871 
872     return false;
873 }
874 
875 // ButtonHitTest() tests if a button was hit. The function returns
876 // true if a button was hit, otherwise false
ButtonHitTest(int x,int y,wxAuiTabContainerButton ** hit) const877 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
878                                       wxAuiTabContainerButton** hit) const
879 {
880     if (!m_rect.Contains(x,y))
881         return false;
882 
883     size_t i, button_count;
884 
885 
886     button_count = m_buttons.GetCount();
887     for (i = 0; i < button_count; ++i)
888     {
889         wxAuiTabContainerButton& button = m_buttons.Item(i);
890         if (button.rect.Contains(x,y) &&
891             !(button.curState & wxAUI_BUTTON_STATE_HIDDEN ))
892         {
893             if (hit)
894                 *hit = &button;
895             return true;
896         }
897     }
898 
899     button_count = m_tabCloseButtons.GetCount();
900     for (i = 0; i < button_count; ++i)
901     {
902         wxAuiTabContainerButton& button = m_tabCloseButtons.Item(i);
903         if (button.rect.Contains(x,y) &&
904             !(button.curState & (wxAUI_BUTTON_STATE_HIDDEN |
905                                    wxAUI_BUTTON_STATE_DISABLED)))
906         {
907             if (hit)
908                 *hit = &button;
909             return true;
910         }
911     }
912 
913     return false;
914 }
915 
916 
917 
918 // the utility function ShowWnd() is the same as show,
919 // except it handles wxAuiMDIChildFrame windows as well,
920 // as the Show() method on this class is "unplugged"
ShowWnd(wxWindow * wnd,bool show)921 static void ShowWnd(wxWindow* wnd, bool show)
922 {
923 #if wxUSE_MDI
924     if (wxDynamicCast(wnd, wxAuiMDIChildFrame))
925     {
926         wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
927         cf->DoShow(show);
928     }
929     else
930 #endif
931     {
932         wnd->Show(show);
933     }
934 }
935 
936 
937 // DoShowHide() this function shows the active window, then
938 // hides all of the other windows (in that order)
DoShowHide()939 void wxAuiTabContainer::DoShowHide()
940 {
941     wxAuiNotebookPageArray& pages = GetPages();
942     size_t i, page_count = pages.GetCount();
943 
944     // show new active page first
945     for (i = 0; i < page_count; ++i)
946     {
947         wxAuiNotebookPage& page = pages.Item(i);
948         if (page.active)
949         {
950             ShowWnd(page.window, true);
951             break;
952         }
953     }
954 
955     // hide all other pages
956     for (i = 0; i < page_count; ++i)
957     {
958         wxAuiNotebookPage& page = pages.Item(i);
959         if (!page.active)
960             ShowWnd(page.window, false);
961     }
962 }
963 
964 
965 
966 
967 
968 
969 // -- wxAuiTabCtrl class implementation --
970 
971 
972 
BEGIN_EVENT_TABLE(wxAuiTabCtrl,wxControl)973 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
974     EVT_PAINT(wxAuiTabCtrl::OnPaint)
975     EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
976     EVT_SIZE(wxAuiTabCtrl::OnSize)
977     EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
978     EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDClick)
979     EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
980     EVT_MIDDLE_DOWN(wxAuiTabCtrl::OnMiddleDown)
981     EVT_MIDDLE_UP(wxAuiTabCtrl::OnMiddleUp)
982     EVT_RIGHT_DOWN(wxAuiTabCtrl::OnRightDown)
983     EVT_RIGHT_UP(wxAuiTabCtrl::OnRightUp)
984     EVT_MOTION(wxAuiTabCtrl::OnMotion)
985     EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
986     EVT_AUINOTEBOOK_BUTTON(wxID_ANY, wxAuiTabCtrl::OnButton)
987     EVT_SET_FOCUS(wxAuiTabCtrl::OnSetFocus)
988     EVT_KILL_FOCUS(wxAuiTabCtrl::OnKillFocus)
989     EVT_CHAR(wxAuiTabCtrl::OnChar)
990     EVT_MOUSE_CAPTURE_LOST(wxAuiTabCtrl::OnCaptureLost)
991 END_EVENT_TABLE()
992 
993 
994 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
995                            wxWindowID id,
996                            const wxPoint& pos,
997                            const wxSize& size,
998                            long style) : wxControl(parent, id, pos, size, style)
999 {
1000     SetName(wxT("wxAuiTabCtrl"));
1001     m_clickPt = wxDefaultPosition;
1002     m_isDragging = false;
1003     m_hoverButton = NULL;
1004     m_pressedButton = NULL;
1005 }
1006 
~wxAuiTabCtrl()1007 wxAuiTabCtrl::~wxAuiTabCtrl()
1008 {
1009 }
1010 
OnPaint(wxPaintEvent &)1011 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
1012 {
1013     wxPaintDC dc(this);
1014 
1015     dc.SetFont(GetFont());
1016 
1017     if (GetPageCount() > 0)
1018         Render(&dc, this);
1019 }
1020 
OnEraseBackground(wxEraseEvent & WXUNUSED (evt))1021 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
1022 {
1023 }
1024 
OnSize(wxSizeEvent & evt)1025 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
1026 {
1027     wxSize s = evt.GetSize();
1028     wxRect r(0, 0, s.GetWidth(), s.GetHeight());
1029     SetRect(r);
1030 }
1031 
OnLeftDown(wxMouseEvent & evt)1032 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
1033 {
1034     CaptureMouse();
1035     m_clickPt = wxDefaultPosition;
1036     m_isDragging = false;
1037     m_clickTab = NULL;
1038     m_pressedButton = NULL;
1039 
1040 
1041     wxWindow* wnd;
1042     if (TabHitTest(evt.m_x, evt.m_y, &wnd))
1043     {
1044         int new_selection = GetIdxFromWindow(wnd);
1045 
1046         // wxAuiNotebooks always want to receive this event
1047         // even if the tab is already active, because they may
1048         // have multiple tab controls
1049         if ((new_selection != GetActivePage() ||
1050             wxDynamicCast(GetParent(), wxAuiNotebook)) && !m_hoverButton)
1051         {
1052             wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1053             e.SetSelection(new_selection);
1054             e.SetOldSelection(GetActivePage());
1055             e.SetEventObject(this);
1056             GetEventHandler()->ProcessEvent(e);
1057         }
1058 
1059         m_clickPt.x = evt.m_x;
1060         m_clickPt.y = evt.m_y;
1061         m_clickTab = wnd;
1062     }
1063 
1064     if (m_hoverButton)
1065     {
1066         m_pressedButton = m_hoverButton;
1067         m_pressedButton->curState = wxAUI_BUTTON_STATE_PRESSED;
1068         Refresh();
1069         Update();
1070     }
1071 }
1072 
OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED (event))1073 void wxAuiTabCtrl::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
1074 {
1075     if (m_isDragging)
1076     {
1077         m_isDragging = false;
1078 
1079         wxAuiNotebookEvent evt(wxEVT_AUINOTEBOOK_CANCEL_DRAG, m_windowId);
1080         evt.SetSelection(GetIdxFromWindow(m_clickTab));
1081         evt.SetOldSelection(evt.GetSelection());
1082         evt.SetEventObject(this);
1083         GetEventHandler()->ProcessEvent(evt);
1084     }
1085 }
1086 
OnLeftUp(wxMouseEvent & evt)1087 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent& evt)
1088 {
1089     if (GetCapture() == this)
1090         ReleaseMouse();
1091 
1092     if (m_isDragging)
1093     {
1094         m_isDragging = false;
1095 
1096         wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_END_DRAG, m_windowId);
1097         e.SetSelection(GetIdxFromWindow(m_clickTab));
1098         e.SetOldSelection(e.GetSelection());
1099         e.SetEventObject(this);
1100         GetEventHandler()->ProcessEvent(e);
1101 
1102         return;
1103     }
1104 
1105     if (m_pressedButton)
1106     {
1107         // make sure we're still clicking the button
1108         wxAuiTabContainerButton* button = NULL;
1109         if (!ButtonHitTest(evt.m_x, evt.m_y, &button) ||
1110             button->curState & wxAUI_BUTTON_STATE_DISABLED)
1111             return;
1112 
1113         if (button != m_pressedButton)
1114         {
1115             m_pressedButton = NULL;
1116             return;
1117         }
1118 
1119         Refresh();
1120         Update();
1121 
1122         if (!(m_pressedButton->curState & wxAUI_BUTTON_STATE_DISABLED))
1123         {
1124             wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_BUTTON, m_windowId);
1125             e.SetSelection(GetIdxFromWindow(m_clickTab));
1126             e.SetInt(m_pressedButton->id);
1127             e.SetEventObject(this);
1128             GetEventHandler()->ProcessEvent(e);
1129         }
1130 
1131         m_pressedButton = NULL;
1132     }
1133 
1134     m_clickPt = wxDefaultPosition;
1135     m_isDragging = false;
1136     m_clickTab = NULL;
1137 }
1138 
OnMiddleUp(wxMouseEvent & evt)1139 void wxAuiTabCtrl::OnMiddleUp(wxMouseEvent& evt)
1140 {
1141     wxWindow* wnd = NULL;
1142     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1143         return;
1144 
1145     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
1146     e.SetEventObject(this);
1147     e.SetSelection(GetIdxFromWindow(wnd));
1148     GetEventHandler()->ProcessEvent(e);
1149 }
1150 
OnMiddleDown(wxMouseEvent & evt)1151 void wxAuiTabCtrl::OnMiddleDown(wxMouseEvent& evt)
1152 {
1153     wxWindow* wnd = NULL;
1154     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1155         return;
1156 
1157     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
1158     e.SetEventObject(this);
1159     e.SetSelection(GetIdxFromWindow(wnd));
1160     GetEventHandler()->ProcessEvent(e);
1161 }
1162 
OnRightUp(wxMouseEvent & evt)1163 void wxAuiTabCtrl::OnRightUp(wxMouseEvent& evt)
1164 {
1165     wxWindow* wnd = NULL;
1166     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1167         return;
1168 
1169     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
1170     e.SetEventObject(this);
1171     e.SetSelection(GetIdxFromWindow(wnd));
1172     GetEventHandler()->ProcessEvent(e);
1173 }
1174 
OnRightDown(wxMouseEvent & evt)1175 void wxAuiTabCtrl::OnRightDown(wxMouseEvent& evt)
1176 {
1177     wxWindow* wnd = NULL;
1178     if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1179         return;
1180 
1181     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
1182     e.SetEventObject(this);
1183     e.SetSelection(GetIdxFromWindow(wnd));
1184     GetEventHandler()->ProcessEvent(e);
1185 }
1186 
OnLeftDClick(wxMouseEvent & evt)1187 void wxAuiTabCtrl::OnLeftDClick(wxMouseEvent& evt)
1188 {
1189     wxWindow* wnd;
1190     wxAuiTabContainerButton* button;
1191     if (!TabHitTest(evt.m_x, evt.m_y, &wnd) && !ButtonHitTest(evt.m_x, evt.m_y, &button))
1192     {
1193         wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_BG_DCLICK, m_windowId);
1194         e.SetEventObject(this);
1195         GetEventHandler()->ProcessEvent(e);
1196     }
1197 }
1198 
OnMotion(wxMouseEvent & evt)1199 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
1200 {
1201     wxPoint pos = evt.GetPosition();
1202 
1203     // check if the mouse is hovering above a button
1204     wxAuiTabContainerButton* button;
1205     if (ButtonHitTest(pos.x, pos.y, &button) && !(button->curState & wxAUI_BUTTON_STATE_DISABLED))
1206     {
1207         if (m_hoverButton && button != m_hoverButton)
1208         {
1209             m_hoverButton->curState = wxAUI_BUTTON_STATE_NORMAL;
1210             m_hoverButton = NULL;
1211             Refresh();
1212             Update();
1213         }
1214 
1215         if (button->curState != wxAUI_BUTTON_STATE_HOVER)
1216         {
1217             button->curState = wxAUI_BUTTON_STATE_HOVER;
1218             Refresh();
1219             Update();
1220 
1221             m_hoverButton = button;
1222             return;
1223         }
1224     }
1225     else
1226     {
1227         if (m_hoverButton)
1228         {
1229             m_hoverButton->curState = wxAUI_BUTTON_STATE_NORMAL;
1230             m_hoverButton = NULL;
1231             Refresh();
1232             Update();
1233         }
1234     }
1235 
1236 #if wxUSE_TOOLTIPS
1237     wxWindow* wnd = NULL;
1238     if (evt.Moving() && TabHitTest(evt.m_x, evt.m_y, &wnd))
1239     {
1240         wxString tooltip(m_pages[GetIdxFromWindow(wnd)].tooltip);
1241 
1242         // If the text changes, set it else, keep old, to avoid
1243         // 'moving tooltip' effect
1244         if (GetToolTipText() != tooltip)
1245             SetToolTip(tooltip);
1246     }
1247     else
1248         UnsetToolTip();
1249 #endif // wxUSE_TOOLTIPS
1250 
1251     if (!evt.LeftIsDown() || m_clickPt == wxDefaultPosition)
1252         return;
1253 
1254     if (m_isDragging)
1255     {
1256         wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_DRAG_MOTION, m_windowId);
1257         e.SetSelection(GetIdxFromWindow(m_clickTab));
1258         e.SetOldSelection(e.GetSelection());
1259         e.SetEventObject(this);
1260         GetEventHandler()->ProcessEvent(e);
1261         return;
1262     }
1263 
1264 
1265     int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
1266     int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
1267 
1268     if (abs(pos.x - m_clickPt.x) > drag_x_threshold ||
1269         abs(pos.y - m_clickPt.y) > drag_y_threshold)
1270     {
1271         wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
1272         e.SetSelection(GetIdxFromWindow(m_clickTab));
1273         e.SetOldSelection(e.GetSelection());
1274         e.SetEventObject(this);
1275         GetEventHandler()->ProcessEvent(e);
1276 
1277         m_isDragging = true;
1278     }
1279 }
1280 
OnLeaveWindow(wxMouseEvent & WXUNUSED (event))1281 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
1282 {
1283     if (m_hoverButton)
1284     {
1285         m_hoverButton->curState = wxAUI_BUTTON_STATE_NORMAL;
1286         m_hoverButton = NULL;
1287         Refresh();
1288         Update();
1289     }
1290 }
1291 
OnButton(wxAuiNotebookEvent & event)1292 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
1293 {
1294     int button = event.GetInt();
1295 
1296     if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
1297     {
1298         if (button == wxAUI_BUTTON_LEFT)
1299         {
1300             if (GetTabOffset() > 0)
1301             {
1302                 SetTabOffset(GetTabOffset()-1);
1303                 Refresh();
1304                 Update();
1305             }
1306         }
1307         else
1308         {
1309             SetTabOffset(GetTabOffset()+1);
1310             Refresh();
1311             Update();
1312         }
1313     }
1314     else if (button == wxAUI_BUTTON_WINDOWLIST)
1315     {
1316         int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage());
1317 
1318         if (idx != -1)
1319         {
1320             wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1321             e.SetSelection(idx);
1322             e.SetOldSelection(GetActivePage());
1323             e.SetEventObject(this);
1324             GetEventHandler()->ProcessEvent(e);
1325         }
1326     }
1327     else
1328     {
1329         event.Skip();
1330     }
1331 }
1332 
OnSetFocus(wxFocusEvent & WXUNUSED (event))1333 void wxAuiTabCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event))
1334 {
1335     Refresh();
1336 }
1337 
OnKillFocus(wxFocusEvent & WXUNUSED (event))1338 void wxAuiTabCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event))
1339 {
1340     Refresh();
1341 }
1342 
OnChar(wxKeyEvent & event)1343 void wxAuiTabCtrl::OnChar(wxKeyEvent& event)
1344 {
1345     if (GetActivePage() == -1)
1346     {
1347         event.Skip();
1348         return;
1349     }
1350 
1351     // We can't leave tab processing to the system; on Windows, tabs and keys
1352     // get eaten by the system and not processed properly if we specify both
1353     // wxTAB_TRAVERSAL and wxWANTS_CHARS. And if we specify just wxTAB_TRAVERSAL,
1354     // we don't key arrow key events.
1355 
1356     int key = event.GetKeyCode();
1357 
1358     if (key == WXK_NUMPAD_PAGEUP)
1359         key = WXK_PAGEUP;
1360     if (key == WXK_NUMPAD_PAGEDOWN)
1361         key = WXK_PAGEDOWN;
1362     if (key == WXK_NUMPAD_HOME)
1363         key = WXK_HOME;
1364     if (key == WXK_NUMPAD_END)
1365         key = WXK_END;
1366     if (key == WXK_NUMPAD_LEFT)
1367         key = WXK_LEFT;
1368     if (key == WXK_NUMPAD_RIGHT)
1369         key = WXK_RIGHT;
1370 
1371     if (key == WXK_TAB || key == WXK_PAGEUP || key == WXK_PAGEDOWN)
1372     {
1373         bool bCtrlDown = event.ControlDown();
1374         bool bShiftDown = event.ShiftDown();
1375 
1376         bool bForward = (key == WXK_TAB && !bShiftDown) || (key == WXK_PAGEDOWN);
1377         bool bWindowChange = (key == WXK_PAGEUP) || (key == WXK_PAGEDOWN) || bCtrlDown;
1378         bool bFromTab = (key == WXK_TAB);
1379 
1380         if (bFromTab && !bWindowChange)
1381         {
1382             // Handle ordinary tabs via Navigate. This is needed at least for wxGTK to tab properly.
1383             Navigate(bForward ? wxNavigationKeyEvent::IsForward : wxNavigationKeyEvent::IsBackward);
1384             return;
1385         }
1386 
1387         wxAuiNotebook* nb = wxDynamicCast(GetParent(), wxAuiNotebook);
1388         if (!nb)
1389         {
1390             event.Skip();
1391             return;
1392         }
1393 
1394         wxNavigationKeyEvent keyEvent;
1395         keyEvent.SetDirection(bForward);
1396         keyEvent.SetWindowChange(bWindowChange);
1397         keyEvent.SetFromTab(bFromTab);
1398         keyEvent.SetEventObject(nb);
1399 
1400         if (!nb->GetEventHandler()->ProcessEvent(keyEvent))
1401         {
1402             // Not processed? Do an explicit tab into the page.
1403             wxWindow* win = GetWindowFromIdx(GetActivePage());
1404             if (win)
1405                 win->SetFocus();
1406         }
1407         return;
1408     }
1409 
1410     if (m_pages.GetCount() < 2)
1411     {
1412         event.Skip();
1413         return;
1414     }
1415 
1416     int newPage = -1;
1417 
1418     int forwardKey, backwardKey;
1419     if (GetLayoutDirection() == wxLayout_RightToLeft)
1420     {
1421         forwardKey = WXK_LEFT;
1422         backwardKey = WXK_RIGHT;
1423     }
1424     else
1425      {
1426         forwardKey = WXK_RIGHT;
1427         backwardKey = WXK_LEFT;
1428     }
1429 
1430     if (key == forwardKey)
1431     {
1432         if (m_pages.GetCount() > 1)
1433         {
1434             if (GetActivePage() == -1)
1435                 newPage = 0;
1436             else if (GetActivePage() < (int) (m_pages.GetCount() - 1))
1437                 newPage = GetActivePage() + 1;
1438         }
1439     }
1440     else if (key == backwardKey)
1441     {
1442         if (m_pages.GetCount() > 1)
1443         {
1444             if (GetActivePage() == -1)
1445                 newPage = (int) (m_pages.GetCount() - 1);
1446             else if (GetActivePage() > 0)
1447                 newPage = GetActivePage() - 1;
1448         }
1449     }
1450     else if (key == WXK_HOME)
1451     {
1452         newPage = 0;
1453     }
1454     else if (key == WXK_END)
1455     {
1456         newPage = (int) (m_pages.GetCount() - 1);
1457     }
1458     else
1459         event.Skip();
1460 
1461     if (newPage != -1)
1462     {
1463         wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1464         e.SetSelection(newPage);
1465         e.SetOldSelection(newPage);
1466         e.SetEventObject(this);
1467         this->GetEventHandler()->ProcessEvent(e);
1468     }
1469     else
1470         event.Skip();
1471 }
1472 
1473 // wxTabFrame is an interesting case.  It's important that all child pages
1474 // of the multi-notebook control are all actually children of that control
1475 // (and not grandchildren).  wxTabFrame facilitates this.  There is one
1476 // instance of wxTabFrame for each tab control inside the multi-notebook.
1477 // It's important to know that wxTabFrame is not a real window, but it merely
1478 // used to capture the dimensions/positioning of the internal tab control and
1479 // it's managed page windows
1480 
1481 class wxTabFrame : public wxWindow
1482 {
1483 public:
1484 
wxTabFrame()1485     wxTabFrame()
1486     {
1487         m_tabs = NULL;
1488         m_rect = wxRect(0,0,200,200);
1489         m_tabCtrlHeight = 20;
1490     }
1491 
~wxTabFrame()1492     ~wxTabFrame()
1493     {
1494         wxDELETE(m_tabs);
1495     }
1496 
SetTabCtrlHeight(int h)1497     void SetTabCtrlHeight(int h)
1498     {
1499         m_tabCtrlHeight = h;
1500     }
1501 
1502 protected:
DoSetSize(int x,int y,int width,int height,int WXUNUSED (sizeFlags=wxSIZE_AUTO))1503     void DoSetSize(int x, int y,
1504                    int width, int height,
1505                    int WXUNUSED(sizeFlags = wxSIZE_AUTO))
1506     {
1507         m_rect = wxRect(x, y, width, height);
1508         DoSizing();
1509     }
1510 
DoGetClientSize(int * x,int * y) const1511     void DoGetClientSize(int* x, int* y) const
1512     {
1513         *x = m_rect.width;
1514         *y = m_rect.height;
1515     }
1516 
1517 public:
Show(bool WXUNUSED (show=true))1518     bool Show( bool WXUNUSED(show = true) ) { return false; }
1519 
DoSizing()1520     void DoSizing()
1521     {
1522         if (!m_tabs)
1523             return;
1524 
1525         if (m_tabs->IsFrozen() || m_tabs->GetParent()->IsFrozen())
1526             return;
1527 
1528         m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tabCtrlHeight);
1529         if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM)
1530         {
1531             m_tab_rect = wxRect (m_rect.x, m_rect.y + m_rect.height - m_tabCtrlHeight, m_rect.width, m_tabCtrlHeight);
1532             m_tabs->SetSize     (m_rect.x, m_rect.y + m_rect.height - m_tabCtrlHeight, m_rect.width, m_tabCtrlHeight);
1533             m_tabs->SetRect     (wxRect(0, 0, m_rect.width, m_tabCtrlHeight));
1534         }
1535         else //TODO: if (GetFlags() & wxAUI_NB_TOP)
1536         {
1537             m_tab_rect = wxRect (m_rect.x, m_rect.y, m_rect.width, m_tabCtrlHeight);
1538             m_tabs->SetSize     (m_rect.x, m_rect.y, m_rect.width, m_tabCtrlHeight);
1539             m_tabs->SetRect     (wxRect(0, 0,        m_rect.width, m_tabCtrlHeight));
1540         }
1541         // TODO: else if (GetFlags() & wxAUI_NB_LEFT){}
1542         // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){}
1543 
1544         m_tabs->Refresh();
1545         m_tabs->Update();
1546 
1547         wxAuiNotebookPageArray& pages = m_tabs->GetPages();
1548         size_t i, page_count = pages.GetCount();
1549 
1550         for (i = 0; i < page_count; ++i)
1551         {
1552             wxAuiNotebookPage& page = pages.Item(i);
1553             int border_space = m_tabs->GetArtProvider()->GetAdditionalBorderSpace(page.window);
1554 
1555             int height = m_rect.height - m_tabCtrlHeight - border_space;
1556             if ( height < 0 )
1557             {
1558                 // avoid passing negative height to wxWindow::SetSize(), this
1559                 // results in assert failures/GTK+ warnings
1560                 height = 0;
1561             }
1562             int width = m_rect.width - 2 * border_space;
1563             if (width < 0)
1564                 width = 0;
1565 
1566             if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM)
1567             {
1568                 page.window->SetSize(m_rect.x + border_space,
1569                                      m_rect.y + border_space,
1570                                      width,
1571                                      height);
1572             }
1573             else //TODO: if (GetFlags() & wxAUI_NB_TOP)
1574             {
1575                 page.window->SetSize(m_rect.x + border_space,
1576                                      m_rect.y + m_tabCtrlHeight,
1577                                      width,
1578                                      height);
1579             }
1580             // TODO: else if (GetFlags() & wxAUI_NB_LEFT){}
1581             // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){}
1582 
1583 #if wxUSE_MDI
1584             if (wxDynamicCast(page.window, wxAuiMDIChildFrame))
1585             {
1586                 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
1587                 wnd->ApplyMDIChildFrameRect();
1588             }
1589 #endif
1590         }
1591     }
1592 
1593 protected:
DoGetSize(int * x,int * y) const1594     void DoGetSize(int* x, int* y) const
1595     {
1596         if (x)
1597             *x = m_rect.GetWidth();
1598         if (y)
1599             *y = m_rect.GetHeight();
1600     }
1601 
1602 public:
Update()1603     void Update()
1604     {
1605         // does nothing
1606     }
1607 
1608     wxRect m_rect;
1609     wxRect m_tab_rect;
1610     wxAuiTabCtrl* m_tabs;
1611     int m_tabCtrlHeight;
1612 };
1613 
1614 
1615 const int wxAuiBaseTabCtrlId = 5380;
1616 
1617 
1618 // -- wxAuiNotebook class implementation --
1619 
1620 #define EVT_AUI_RANGE(id1, id2, event, func) \
1621     wx__DECLARE_EVT2(event, id1, id2, wxAuiNotebookEventHandler(func))
1622 
BEGIN_EVENT_TABLE(wxAuiNotebook,wxControl)1623 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
1624     EVT_SIZE(wxAuiNotebook::OnSize)
1625     EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocusNotebook)
1626     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1627                       wxEVT_AUINOTEBOOK_PAGE_CHANGING,
1628                       wxAuiNotebook::OnTabClicked)
1629     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1630                       wxEVT_AUINOTEBOOK_BEGIN_DRAG,
1631                       wxAuiNotebook::OnTabBeginDrag)
1632     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1633                       wxEVT_AUINOTEBOOK_END_DRAG,
1634                       wxAuiNotebook::OnTabEndDrag)
1635     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1636                       wxEVT_AUINOTEBOOK_CANCEL_DRAG,
1637                       wxAuiNotebook::OnTabCancelDrag)
1638     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1639                       wxEVT_AUINOTEBOOK_DRAG_MOTION,
1640                       wxAuiNotebook::OnTabDragMotion)
1641     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1642                       wxEVT_AUINOTEBOOK_BUTTON,
1643                       wxAuiNotebook::OnTabButton)
1644     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1645                       wxEVT_AUINOTEBOOK_TAB_MIDDLE_DOWN,
1646                       wxAuiNotebook::OnTabMiddleDown)
1647     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1648                       wxEVT_AUINOTEBOOK_TAB_MIDDLE_UP,
1649                       wxAuiNotebook::OnTabMiddleUp)
1650     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1651                       wxEVT_AUINOTEBOOK_TAB_RIGHT_DOWN,
1652                       wxAuiNotebook::OnTabRightDown)
1653     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1654                       wxEVT_AUINOTEBOOK_TAB_RIGHT_UP,
1655                       wxAuiNotebook::OnTabRightUp)
1656     EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1657                       wxEVT_AUINOTEBOOK_BG_DCLICK,
1658                       wxAuiNotebook::OnTabBgDClick)
1659     EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKeyNotebook)
1660 END_EVENT_TABLE()
1661 
1662 void wxAuiNotebook::Init()
1663 {
1664     m_curPage = -1;
1665     m_tabIdCounter = wxAuiBaseTabCtrlId;
1666     m_dummyWnd = NULL;
1667     m_tabCtrlHeight = 20;
1668     m_requestedBmpSize = wxDefaultSize;
1669     m_requestedTabCtrlHeight = -1;
1670 }
1671 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)1672 bool wxAuiNotebook::Create(wxWindow* parent,
1673                            wxWindowID id,
1674                            const wxPoint& pos,
1675                            const wxSize& size,
1676                            long style)
1677 {
1678     if (!wxControl::Create(parent, id, pos, size, style))
1679         return false;
1680 
1681     InitNotebook(style);
1682 
1683     return true;
1684 }
1685 
1686 // InitNotebook() contains common initialization
1687 // code called by all constructors
InitNotebook(long style)1688 void wxAuiNotebook::InitNotebook(long style)
1689 {
1690     SetName(wxT("wxAuiNotebook"));
1691     m_curPage = -1;
1692     m_tabIdCounter = wxAuiBaseTabCtrlId;
1693     m_dummyWnd = NULL;
1694     m_flags = (unsigned int)style;
1695     m_tabCtrlHeight = 20;
1696 
1697     m_normalFont = *wxNORMAL_FONT;
1698     m_selectedFont = *wxNORMAL_FONT;
1699     m_selectedFont.SetWeight(wxBOLD);
1700 
1701     SetArtProvider(new wxAuiDefaultTabArt);
1702 
1703     m_dummyWnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
1704     m_dummyWnd->SetSize(200, 200);
1705     m_dummyWnd->Show(false);
1706 
1707     m_mgr.SetManagedWindow(this);
1708     m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
1709     m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
1710 
1711     m_mgr.AddPane(m_dummyWnd,
1712               wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
1713 
1714     m_mgr.Update();
1715 }
1716 
~wxAuiNotebook()1717 wxAuiNotebook::~wxAuiNotebook()
1718 {
1719     // Indicate we're deleting pages
1720     SendDestroyEvent();
1721 
1722     while ( GetPageCount() > 0 )
1723         DeletePage(0);
1724 
1725     m_mgr.UnInit();
1726 }
1727 
SetArtProvider(wxAuiTabArt * art)1728 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
1729 {
1730     m_tabs.SetArtProvider(art);
1731 
1732     // Update the height and do nothing else if it did something but otherwise
1733     // (i.e. if the new art provider uses the same height as the old one) we
1734     // need to manually set the art provider for all tabs ourselves.
1735     if ( !UpdateTabCtrlHeight() )
1736     {
1737         wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1738         const size_t pane_count = all_panes.GetCount();
1739         for (size_t i = 0; i < pane_count; ++i)
1740         {
1741             wxAuiPaneInfo& pane = all_panes.Item(i);
1742             if (pane.name == wxT("dummy"))
1743                 continue;
1744             wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
1745             wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
1746             tabctrl->SetArtProvider(art->Clone());
1747         }
1748     }
1749 }
1750 
1751 // SetTabCtrlHeight() is the highest-level override of the
1752 // tab height.  A call to this function effectively enforces a
1753 // specified tab ctrl height, overriding all other considerations,
1754 // such as text or bitmap height.  It overrides any call to
1755 // SetUniformBitmapSize().  Specifying a height of -1 reverts
1756 // any previous call and returns to the default behaviour
1757 
SetTabCtrlHeight(int height)1758 void wxAuiNotebook::SetTabCtrlHeight(int height)
1759 {
1760     m_requestedTabCtrlHeight = height;
1761 
1762     // if window is already initialized, recalculate the tab height
1763     if (m_dummyWnd)
1764     {
1765         UpdateTabCtrlHeight();
1766     }
1767 }
1768 
1769 
1770 // SetUniformBitmapSize() ensures that all tabs will have
1771 // the same height, even if some tabs don't have bitmaps
1772 // Passing wxDefaultSize to this function will instruct
1773 // the control to use dynamic tab height-- so when a tab
1774 // with a large bitmap is added, the tab ctrl's height will
1775 // automatically increase to accommodate the bitmap
1776 
SetUniformBitmapSize(const wxSize & size)1777 void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
1778 {
1779     m_requestedBmpSize = size;
1780 
1781     // if window is already initialized, recalculate the tab height
1782     if (m_dummyWnd)
1783     {
1784         UpdateTabCtrlHeight();
1785     }
1786 }
1787 
1788 // UpdateTabCtrlHeight() does the actual tab resizing. It's meant
1789 // to be used internally
UpdateTabCtrlHeight()1790 bool wxAuiNotebook::UpdateTabCtrlHeight()
1791 {
1792     // get the tab ctrl height we will use
1793     int height = CalculateTabCtrlHeight();
1794 
1795     // if the tab control height needs to change, update
1796     // all of our tab controls with the new height
1797     if (m_tabCtrlHeight == height)
1798         return false;
1799 
1800     wxAuiTabArt* art = m_tabs.GetArtProvider();
1801 
1802     m_tabCtrlHeight = height;
1803 
1804     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1805     size_t i, pane_count = all_panes.GetCount();
1806     for (i = 0; i < pane_count; ++i)
1807     {
1808         wxAuiPaneInfo& pane = all_panes.Item(i);
1809         if (pane.name == wxT("dummy"))
1810             continue;
1811         wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
1812         wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
1813         tab_frame->SetTabCtrlHeight(m_tabCtrlHeight);
1814         tabctrl->SetArtProvider(art->Clone());
1815         tab_frame->DoSizing();
1816     }
1817 
1818     return true;
1819 }
1820 
UpdateHintWindowSize()1821 void wxAuiNotebook::UpdateHintWindowSize()
1822 {
1823     wxSize size = CalculateNewSplitSize();
1824 
1825     // the placeholder hint window should be set to this size
1826     wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
1827     if (info.IsOk())
1828     {
1829         info.MinSize(size);
1830         info.BestSize(size);
1831         m_dummyWnd->SetSize(size);
1832     }
1833 }
1834 
1835 
1836 // calculates the size of the new split
CalculateNewSplitSize()1837 wxSize wxAuiNotebook::CalculateNewSplitSize()
1838 {
1839     // count number of tab controls
1840     int tab_ctrl_count = 0;
1841     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1842     size_t i, pane_count = all_panes.GetCount();
1843     for (i = 0; i < pane_count; ++i)
1844     {
1845         wxAuiPaneInfo& pane = all_panes.Item(i);
1846         if (pane.name == wxT("dummy"))
1847             continue;
1848         tab_ctrl_count++;
1849     }
1850 
1851     wxSize new_split_size;
1852 
1853     // if there is only one tab control, the first split
1854     // should happen around the middle
1855     if (tab_ctrl_count < 2)
1856     {
1857         new_split_size = GetClientSize();
1858         new_split_size.x /= 2;
1859         new_split_size.y /= 2;
1860     }
1861     else
1862     {
1863         // this is in place of a more complicated calculation
1864         // that needs to be implemented
1865         new_split_size = wxSize(180,180);
1866     }
1867 
1868     return new_split_size;
1869 }
1870 
CalculateTabCtrlHeight()1871 int wxAuiNotebook::CalculateTabCtrlHeight()
1872 {
1873     // if a fixed tab ctrl height is specified,
1874     // just return that instead of calculating a
1875     // tab height
1876     if (m_requestedTabCtrlHeight != -1)
1877         return m_requestedTabCtrlHeight;
1878 
1879     // find out new best tab height
1880     wxAuiTabArt* art = m_tabs.GetArtProvider();
1881 
1882     return art->GetBestTabCtrlSize(this,
1883                                    m_tabs.GetPages(),
1884                                    m_requestedBmpSize);
1885 }
1886 
1887 
GetArtProvider() const1888 wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
1889 {
1890     return m_tabs.GetArtProvider();
1891 }
1892 
SetWindowStyleFlag(long style)1893 void wxAuiNotebook::SetWindowStyleFlag(long style)
1894 {
1895     wxControl::SetWindowStyleFlag(style);
1896 
1897     m_flags = (unsigned int)style;
1898 
1899     // if the control is already initialized
1900     if (m_mgr.GetManagedWindow() == (wxWindow*)this)
1901     {
1902         // let all of the tab children know about the new style
1903 
1904         wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1905         size_t i, pane_count = all_panes.GetCount();
1906         for (i = 0; i < pane_count; ++i)
1907         {
1908             wxAuiPaneInfo& pane = all_panes.Item(i);
1909             if (pane.name == wxT("dummy"))
1910                 continue;
1911             wxTabFrame* tabframe = (wxTabFrame*)pane.window;
1912             wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
1913             tabctrl->SetFlags(m_flags);
1914             tabframe->DoSizing();
1915             tabctrl->Refresh();
1916             tabctrl->Update();
1917         }
1918     }
1919 }
1920 
1921 
AddPage(wxWindow * page,const wxString & caption,bool select,const wxBitmap & bitmap)1922 bool wxAuiNotebook::AddPage(wxWindow* page,
1923                             const wxString& caption,
1924                             bool select,
1925                             const wxBitmap& bitmap)
1926 {
1927     return InsertPage(GetPageCount(), page, caption, select, bitmap);
1928 }
1929 
InsertPage(size_t page_idx,wxWindow * page,const wxString & caption,bool select,const wxBitmap & bitmap)1930 bool wxAuiNotebook::InsertPage(size_t page_idx,
1931                                wxWindow* page,
1932                                const wxString& caption,
1933                                bool select,
1934                                const wxBitmap& bitmap)
1935 {
1936     wxASSERT_MSG(page, wxT("page pointer must be non-NULL"));
1937     if (!page)
1938         return false;
1939 
1940     page->Reparent(this);
1941 
1942     wxAuiNotebookPage info;
1943     info.window = page;
1944     info.caption = caption;
1945     info.bitmap = bitmap;
1946     info.active = false;
1947 
1948     // if there are currently no tabs, the first added
1949     // tab must be active
1950     if (m_tabs.GetPageCount() == 0)
1951         info.active = true;
1952 
1953     m_tabs.InsertPage(page, info, page_idx);
1954 
1955     // if that was the first page added, even if
1956     // select is false, it must become the "current page"
1957     // (though no select events will be fired)
1958     if (!select && m_tabs.GetPageCount() == 1)
1959         select = true;
1960         //m_curPage = GetPageIndex(page);
1961 
1962     wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
1963     if (page_idx >= active_tabctrl->GetPageCount())
1964         active_tabctrl->AddPage(page, info);
1965     else
1966         active_tabctrl->InsertPage(page, info, page_idx);
1967 
1968     UpdateTabCtrlHeight();
1969     DoSizing();
1970     active_tabctrl->DoShowHide();
1971 
1972     // adjust selected index
1973     if(m_curPage >= (int) page_idx)
1974         m_curPage++;
1975 
1976     if (select)
1977     {
1978         SetSelectionToWindow(page);
1979     }
1980 
1981     return true;
1982 }
1983 
1984 
1985 // DeletePage() removes a tab from the multi-notebook,
1986 // and destroys the window as well
DeletePage(size_t page_idx)1987 bool wxAuiNotebook::DeletePage(size_t page_idx)
1988 {
1989     if (page_idx >= m_tabs.GetPageCount())
1990         return false;
1991 
1992     wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1993 
1994     // hide the window in advance, as this will
1995     // prevent flicker
1996     ShowWnd(wnd, false);
1997 
1998     if (!RemovePage(page_idx))
1999         return false;
2000 
2001 #if wxUSE_MDI
2002     // actually destroy the window now
2003     if (wxDynamicCast(wnd, wxAuiMDIChildFrame))
2004     {
2005         // delete the child frame with pending delete, as is
2006         // customary with frame windows
2007         if (!wxPendingDelete.Member(wnd))
2008             wxPendingDelete.Append(wnd);
2009     }
2010     else
2011 #endif
2012     {
2013         wnd->Destroy();
2014     }
2015 
2016     return true;
2017 }
2018 
2019 
2020 
2021 // RemovePage() removes a tab from the multi-notebook,
2022 // but does not destroy the window
RemovePage(size_t page_idx)2023 bool wxAuiNotebook::RemovePage(size_t page_idx)
2024 {
2025     // save active window pointer
2026     wxWindow* active_wnd = NULL;
2027     if (m_curPage >= 0)
2028         active_wnd = m_tabs.GetWindowFromIdx(m_curPage);
2029 
2030     // save pointer of window being deleted
2031     wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2032     wxWindow* new_active = NULL;
2033 
2034     // make sure we found the page
2035     if (!wnd)
2036         return false;
2037 
2038     // find out which onscreen tab ctrl owns this tab
2039     wxAuiTabCtrl* ctrl;
2040     int ctrl_idx;
2041     if (!FindTab(wnd, &ctrl, &ctrl_idx))
2042         return false;
2043 
2044     bool is_curpage = (m_curPage == (int)page_idx);
2045     bool is_active_in_split = ctrl->GetPage(ctrl_idx).active;
2046 
2047 
2048     // remove the tab from main catalog
2049     if (!m_tabs.RemovePage(wnd))
2050         return false;
2051 
2052     // remove the tab from the onscreen tab ctrl
2053     ctrl->RemovePage(wnd);
2054 
2055     if (is_active_in_split)
2056     {
2057         int ctrl_new_page_count = (int)ctrl->GetPageCount();
2058 
2059         if (ctrl_idx >= ctrl_new_page_count)
2060             ctrl_idx = ctrl_new_page_count-1;
2061 
2062         if (ctrl_idx >= 0 && ctrl_idx < (int)ctrl->GetPageCount())
2063         {
2064             // set new page as active in the tab split
2065             ctrl->SetActivePage(ctrl_idx);
2066 
2067             // if the page deleted was the current page for the
2068             // entire tab control, then record the window
2069             // pointer of the new active page for activation
2070             if (is_curpage)
2071             {
2072                 new_active = ctrl->GetWindowFromIdx(ctrl_idx);
2073             }
2074         }
2075     }
2076     else
2077     {
2078         // we are not deleting the active page, so keep it the same
2079         new_active = active_wnd;
2080     }
2081 
2082 
2083     if (!new_active)
2084     {
2085         // we haven't yet found a new page to active,
2086         // so select the next page from the main tab
2087         // catalogue
2088 
2089         if (page_idx < m_tabs.GetPageCount())
2090         {
2091             new_active = m_tabs.GetPage(page_idx).window;
2092         }
2093 
2094         if (!new_active && m_tabs.GetPageCount() > 0)
2095         {
2096             new_active = m_tabs.GetPage(0).window;
2097         }
2098     }
2099 
2100 
2101     RemoveEmptyTabFrames();
2102 
2103     m_curPage = wxNOT_FOUND;
2104 
2105     // set new active pane unless we're being destroyed anyhow
2106     if (new_active && !m_isBeingDeleted)
2107         SetSelectionToWindow(new_active);
2108 
2109     return true;
2110 }
2111 
2112 // GetPageIndex() returns the index of the page, or -1 if the
2113 // page could not be located in the notebook
GetPageIndex(wxWindow * page_wnd) const2114 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2115 {
2116     return m_tabs.GetIdxFromWindow(page_wnd);
2117 }
2118 
2119 
2120 
2121 // SetPageText() changes the tab caption of the specified page
SetPageText(size_t page_idx,const wxString & text)2122 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2123 {
2124     if (page_idx >= m_tabs.GetPageCount())
2125         return false;
2126 
2127     // update our own tab catalog
2128     wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2129     page_info.caption = text;
2130 
2131     // update what's on screen
2132     wxAuiTabCtrl* ctrl;
2133     int ctrl_idx;
2134     if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2135     {
2136         wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2137         info.caption = text;
2138         ctrl->Refresh();
2139         ctrl->Update();
2140     }
2141 
2142     return true;
2143 }
2144 
2145 // returns the page caption
GetPageText(size_t page_idx) const2146 wxString wxAuiNotebook::GetPageText(size_t page_idx) const
2147 {
2148     if (page_idx >= m_tabs.GetPageCount())
2149         return wxEmptyString;
2150 
2151     // update our own tab catalog
2152     const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2153     return page_info.caption;
2154 }
2155 
SetPageToolTip(size_t page_idx,const wxString & text)2156 bool wxAuiNotebook::SetPageToolTip(size_t page_idx, const wxString& text)
2157 {
2158     if (page_idx >= m_tabs.GetPageCount())
2159         return false;
2160 
2161     // update our own tab catalog
2162     wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2163     page_info.tooltip = text;
2164 
2165     wxAuiTabCtrl* ctrl;
2166     int ctrl_idx;
2167     if (!FindTab(page_info.window, &ctrl, &ctrl_idx))
2168         return false;
2169 
2170     wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2171     info.tooltip = text;
2172 
2173     // NB: we don't update the tooltip if it is already being displayed, it
2174     //     typically never happens, no need to code that
2175     return true;
2176 }
2177 
GetPageToolTip(size_t page_idx) const2178 wxString wxAuiNotebook::GetPageToolTip(size_t page_idx) const
2179 {
2180     if (page_idx >= m_tabs.GetPageCount())
2181         return wxString();
2182 
2183     const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2184     return page_info.tooltip;
2185 }
2186 
SetPageBitmap(size_t page_idx,const wxBitmap & bitmap)2187 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2188 {
2189     if (page_idx >= m_tabs.GetPageCount())
2190         return false;
2191 
2192     // update our own tab catalog
2193     wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2194     page_info.bitmap = bitmap;
2195 
2196     // tab height might have changed
2197     UpdateTabCtrlHeight();
2198 
2199     // update what's on screen
2200     wxAuiTabCtrl* ctrl;
2201     int ctrl_idx;
2202     if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2203     {
2204         wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2205         info.bitmap = bitmap;
2206         ctrl->Refresh();
2207         ctrl->Update();
2208     }
2209 
2210     return true;
2211 }
2212 
2213 // returns the page bitmap
GetPageBitmap(size_t page_idx) const2214 wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const
2215 {
2216     if (page_idx >= m_tabs.GetPageCount())
2217         return wxBitmap();
2218 
2219     // update our own tab catalog
2220     const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2221     return page_info.bitmap;
2222 }
2223 
2224 // GetSelection() returns the index of the currently active page
GetSelection() const2225 int wxAuiNotebook::GetSelection() const
2226 {
2227     return m_curPage;
2228 }
2229 
2230 // SetSelection() sets the currently active page
SetSelection(size_t new_page)2231 int wxAuiNotebook::SetSelection(size_t new_page)
2232 {
2233     return DoModifySelection(new_page, true);
2234 }
2235 
SetSelectionToWindow(wxWindow * win)2236 void wxAuiNotebook::SetSelectionToWindow(wxWindow *win)
2237 {
2238     const int idx = m_tabs.GetIdxFromWindow(win);
2239     wxCHECK_RET( idx != wxNOT_FOUND, wxT("invalid notebook page") );
2240 
2241 
2242     // since a tab was clicked, let the parent know that we received
2243     // the focus, even if we will assign that focus immediately
2244     // to the child tab in the SetSelection call below
2245     // (the child focus event will also let wxAuiManager, if any,
2246     // know that the notebook control has been activated)
2247 
2248     wxWindow* parent = GetParent();
2249     if (parent)
2250     {
2251         wxChildFocusEvent eventFocus(this);
2252         parent->GetEventHandler()->ProcessEvent(eventFocus);
2253     }
2254 
2255 
2256     SetSelection(idx);
2257 }
2258 
2259 // GetPageCount() returns the total number of
2260 // pages managed by the multi-notebook
GetPageCount() const2261 size_t wxAuiNotebook::GetPageCount() const
2262 {
2263     return m_tabs.GetPageCount();
2264 }
2265 
2266 // GetPage() returns the wxWindow pointer of the
2267 // specified page
GetPage(size_t page_idx) const2268 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2269 {
2270     wxASSERT(page_idx < m_tabs.GetPageCount());
2271 
2272     return m_tabs.GetWindowFromIdx(page_idx);
2273 }
2274 
2275 // DoSizing() performs all sizing operations in each tab control
DoSizing()2276 void wxAuiNotebook::DoSizing()
2277 {
2278     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2279     size_t i, pane_count = all_panes.GetCount();
2280     for (i = 0; i < pane_count; ++i)
2281     {
2282         if (all_panes.Item(i).name == wxT("dummy"))
2283             continue;
2284 
2285         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2286         tabframe->DoSizing();
2287     }
2288 }
2289 
2290 // GetActiveTabCtrl() returns the active tab control.  It is
2291 // called to determine which control gets new windows being added
GetActiveTabCtrl()2292 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
2293 {
2294     if (m_curPage >= 0 && m_curPage < (int)m_tabs.GetPageCount())
2295     {
2296         wxAuiTabCtrl* ctrl;
2297         int idx;
2298 
2299         // find the tab ctrl with the current page
2300         if (FindTab(m_tabs.GetPage(m_curPage).window,
2301                     &ctrl, &idx))
2302         {
2303             return ctrl;
2304         }
2305     }
2306 
2307     // no current page, just find the first tab ctrl
2308     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2309     size_t i, pane_count = all_panes.GetCount();
2310     for (i = 0; i < pane_count; ++i)
2311     {
2312         if (all_panes.Item(i).name == wxT("dummy"))
2313             continue;
2314 
2315         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2316         return tabframe->m_tabs;
2317     }
2318 
2319     // If there is no tabframe at all, create one
2320     wxTabFrame* tabframe = new wxTabFrame;
2321     tabframe->SetTabCtrlHeight(m_tabCtrlHeight);
2322     tabframe->m_tabs = new wxAuiTabCtrl(this,
2323                                         m_tabIdCounter++,
2324                                         wxDefaultPosition,
2325                                         wxDefaultSize,
2326                                         wxNO_BORDER|wxWANTS_CHARS);
2327     tabframe->m_tabs->SetFlags(m_flags);
2328     tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2329     m_mgr.AddPane(tabframe,
2330                   wxAuiPaneInfo().Center().CaptionVisible(false));
2331 
2332     m_mgr.Update();
2333 
2334     return tabframe->m_tabs;
2335 }
2336 
2337 // FindTab() finds the tab control that currently contains the window as well
2338 // as the index of the window in the tab control.  It returns true if the
2339 // window was found, otherwise false.
FindTab(wxWindow * page,wxAuiTabCtrl ** ctrl,int * idx)2340 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2341 {
2342     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2343     size_t i, pane_count = all_panes.GetCount();
2344     for (i = 0; i < pane_count; ++i)
2345     {
2346         if (all_panes.Item(i).name == wxT("dummy"))
2347             continue;
2348 
2349         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2350 
2351         int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2352         if (page_idx != -1)
2353         {
2354             *ctrl = tabframe->m_tabs;
2355             *idx = page_idx;
2356             return true;
2357         }
2358     }
2359 
2360     return false;
2361 }
2362 
Split(size_t page,int direction)2363 void wxAuiNotebook::Split(size_t page, int direction)
2364 {
2365     wxSize cli_size = GetClientSize();
2366 
2367     // get the page's window pointer
2368     wxWindow* wnd = GetPage(page);
2369     if (!wnd)
2370         return;
2371 
2372     // notebooks with 1 or less pages can't be split
2373     if (GetPageCount() < 2)
2374         return;
2375 
2376     // find out which tab control the page currently belongs to
2377     wxAuiTabCtrl *src_tabs, *dest_tabs;
2378     int src_idx = -1;
2379     src_tabs = NULL;
2380     if (!FindTab(wnd, &src_tabs, &src_idx))
2381         return;
2382     if (!src_tabs || src_idx == -1)
2383         return;
2384 
2385     // choose a split size
2386     wxSize split_size;
2387     if (GetPageCount() > 2)
2388     {
2389         split_size = CalculateNewSplitSize();
2390     }
2391     else
2392     {
2393         // because there are two panes, always split them
2394         // equally
2395         split_size = GetClientSize();
2396         split_size.x /= 2;
2397         split_size.y /= 2;
2398     }
2399 
2400 
2401     // create a new tab frame
2402     wxTabFrame* new_tabs = new wxTabFrame;
2403     new_tabs->m_rect = wxRect(wxPoint(0,0), split_size);
2404     new_tabs->SetTabCtrlHeight(m_tabCtrlHeight);
2405     new_tabs->m_tabs = new wxAuiTabCtrl(this,
2406                                         m_tabIdCounter++,
2407                                         wxDefaultPosition,
2408                                         wxDefaultSize,
2409                                         wxNO_BORDER|wxWANTS_CHARS);
2410     new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2411     new_tabs->m_tabs->SetFlags(m_flags);
2412     dest_tabs = new_tabs->m_tabs;
2413 
2414     // create a pane info structure with the information
2415     // about where the pane should be added
2416     wxAuiPaneInfo paneInfo = wxAuiPaneInfo().Bottom().CaptionVisible(false);
2417     wxPoint mouse_pt;
2418 
2419     if (direction == wxLEFT)
2420     {
2421         paneInfo.Left();
2422         mouse_pt = wxPoint(0, cli_size.y/2);
2423     }
2424     else if (direction == wxRIGHT)
2425     {
2426         paneInfo.Right();
2427         mouse_pt = wxPoint(cli_size.x, cli_size.y/2);
2428     }
2429     else if (direction == wxTOP)
2430     {
2431         paneInfo.Top();
2432         mouse_pt = wxPoint(cli_size.x/2, 0);
2433     }
2434     else if (direction == wxBOTTOM)
2435     {
2436         paneInfo.Bottom();
2437         mouse_pt = wxPoint(cli_size.x/2, cli_size.y);
2438     }
2439 
2440     m_mgr.AddPane(new_tabs, paneInfo, mouse_pt);
2441     m_mgr.Update();
2442 
2443     // remove the page from the source tabs
2444     wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx);
2445     page_info.active = false;
2446     src_tabs->RemovePage(page_info.window);
2447     if (src_tabs->GetPageCount() > 0)
2448     {
2449         src_tabs->SetActivePage((size_t)0);
2450         src_tabs->DoShowHide();
2451         src_tabs->Refresh();
2452     }
2453 
2454 
2455     // add the page to the destination tabs
2456     dest_tabs->InsertPage(page_info.window, page_info, 0);
2457 
2458     if (src_tabs->GetPageCount() == 0)
2459     {
2460         RemoveEmptyTabFrames();
2461     }
2462 
2463     DoSizing();
2464     dest_tabs->DoShowHide();
2465     dest_tabs->Refresh();
2466 
2467     // force the set selection function reset the selection
2468     m_curPage = -1;
2469 
2470     // set the active page to the one we just split off
2471     SetSelectionToPage(page_info);
2472 
2473     UpdateHintWindowSize();
2474 }
2475 
2476 
OnSize(wxSizeEvent & evt)2477 void wxAuiNotebook::OnSize(wxSizeEvent& evt)
2478 {
2479     UpdateHintWindowSize();
2480 
2481     evt.Skip();
2482 }
2483 
OnTabClicked(wxAuiNotebookEvent & evt)2484 void wxAuiNotebook::OnTabClicked(wxAuiNotebookEvent& evt)
2485 {
2486     wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2487     wxASSERT(ctrl != NULL);
2488 
2489     wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
2490     wxASSERT(wnd != NULL);
2491 
2492     SetSelectionToWindow(wnd);
2493 }
2494 
OnTabBgDClick(wxAuiNotebookEvent & evt)2495 void wxAuiNotebook::OnTabBgDClick(wxAuiNotebookEvent& evt)
2496 {
2497     // select the tab ctrl which received the db click
2498     int selection;
2499     wxWindow* wnd;
2500     wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2501     if (   (ctrl != NULL)
2502         && ((selection = ctrl->GetActivePage()) != wxNOT_FOUND)
2503         && ((wnd = ctrl->GetWindowFromIdx(selection)) != NULL))
2504     {
2505         SetSelectionToWindow(wnd);
2506     }
2507 
2508     // notify owner that the tabbar background has been double-clicked
2509     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_BG_DCLICK, m_windowId);
2510     e.SetEventObject(this);
2511     GetEventHandler()->ProcessEvent(e);
2512 }
2513 
OnTabBeginDrag(wxAuiNotebookEvent &)2514 void wxAuiNotebook::OnTabBeginDrag(wxAuiNotebookEvent&)
2515 {
2516     m_lastDragX = 0;
2517 }
2518 
OnTabDragMotion(wxAuiNotebookEvent & evt)2519 void wxAuiNotebook::OnTabDragMotion(wxAuiNotebookEvent& evt)
2520 {
2521     wxPoint screen_pt = ::wxGetMousePosition();
2522     wxPoint client_pt = ScreenToClient(screen_pt);
2523     wxPoint zero(0,0);
2524 
2525     wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2526     wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
2527 
2528     if (dest_tabs == src_tabs)
2529     {
2530         if (src_tabs)
2531         {
2532             src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2533         }
2534 
2535         // always hide the hint for inner-tabctrl drag
2536         m_mgr.HideHint();
2537 
2538         // if tab moving is not allowed, leave
2539         if (!(m_flags & wxAUI_NB_TAB_MOVE))
2540         {
2541             return;
2542         }
2543 
2544         wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
2545         wxWindow* dest_location_tab;
2546 
2547         // this is an inner-tab drag/reposition
2548         if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
2549         {
2550             int src_idx = evt.GetSelection();
2551             int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
2552 
2553             // prevent jumpy drag
2554             if ((src_idx == dest_idx) || dest_idx == -1 ||
2555                 (src_idx > dest_idx && m_lastDragX <= pt.x) ||
2556                 (src_idx < dest_idx && m_lastDragX >= pt.x))
2557             {
2558                 m_lastDragX = pt.x;
2559                 return;
2560             }
2561 
2562 
2563             wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
2564             dest_tabs->MovePage(src_tab, dest_idx);
2565             m_tabs.MovePage(m_tabs.GetPage(src_idx).window, dest_idx);
2566             dest_tabs->SetActivePage((size_t)dest_idx);
2567             dest_tabs->DoShowHide();
2568             dest_tabs->Refresh();
2569             m_lastDragX = pt.x;
2570 
2571         }
2572 
2573         return;
2574     }
2575 
2576 
2577     // if external drag is allowed, check if the tab is being dragged
2578     // over a different wxAuiNotebook control
2579     if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2580     {
2581         wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
2582 
2583         // if we aren't over any window, stop here
2584         if (!tab_ctrl)
2585             return;
2586 
2587         // make sure we are not over the hint window
2588         if (!wxDynamicCast(tab_ctrl, wxFrame))
2589         {
2590             while (tab_ctrl)
2591             {
2592                 if (wxDynamicCast(tab_ctrl, wxAuiTabCtrl))
2593                     break;
2594                 tab_ctrl = tab_ctrl->GetParent();
2595             }
2596 
2597             if (tab_ctrl)
2598             {
2599                 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2600 
2601                 if (nb != this)
2602                 {
2603                     wxRect hint_rect = tab_ctrl->GetClientRect();
2604                     tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
2605                     m_mgr.ShowHint(hint_rect);
2606                     return;
2607                 }
2608             }
2609         }
2610         else
2611         {
2612             if (!dest_tabs)
2613             {
2614                 // we are either over a hint window, or not over a tab
2615                 // window, and there is no where to drag to, so exit
2616                 return;
2617             }
2618         }
2619     }
2620 
2621 
2622     // if there are less than two panes, split can't happen, so leave
2623     if (m_tabs.GetPageCount() < 2)
2624         return;
2625 
2626     // if tab moving is not allowed, leave
2627     if (!(m_flags & wxAUI_NB_TAB_SPLIT))
2628         return;
2629 
2630 
2631     if (src_tabs)
2632     {
2633         src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
2634     }
2635 
2636 
2637     if (dest_tabs)
2638     {
2639         wxRect hint_rect = dest_tabs->GetRect();
2640         ClientToScreen(&hint_rect.x, &hint_rect.y);
2641         m_mgr.ShowHint(hint_rect);
2642     }
2643     else
2644     {
2645         m_mgr.DrawHintRect(m_dummyWnd, client_pt, zero);
2646     }
2647 }
2648 
2649 
2650 
OnTabEndDrag(wxAuiNotebookEvent & evt)2651 void wxAuiNotebook::OnTabEndDrag(wxAuiNotebookEvent& evt)
2652 {
2653     m_mgr.HideHint();
2654 
2655 
2656     wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2657     wxCHECK_RET( src_tabs, wxT("no source object?") );
2658 
2659     src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2660 
2661     // get the mouse position, which will be used to determine the drop point
2662     wxPoint mouse_screen_pt = ::wxGetMousePosition();
2663     wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
2664 
2665 
2666 
2667     // check for an external move
2668     if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2669     {
2670         wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
2671 
2672         while (tab_ctrl)
2673         {
2674             if (wxDynamicCast(tab_ctrl, wxAuiTabCtrl))
2675                 break;
2676             tab_ctrl = tab_ctrl->GetParent();
2677         }
2678 
2679         if (tab_ctrl)
2680         {
2681             wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2682 
2683             if (nb != this)
2684             {
2685                 // find out from the destination control
2686                 // if it's ok to drop this tab here
2687                 wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_ALLOW_DND, m_windowId);
2688                 e.SetSelection(evt.GetSelection());
2689                 e.SetOldSelection(evt.GetSelection());
2690                 e.SetEventObject(this);
2691                 e.SetDragSource(this);
2692                 e.Veto(); // dropping must be explicitly approved by control owner
2693 
2694                 nb->GetEventHandler()->ProcessEvent(e);
2695 
2696                 if (!e.IsAllowed())
2697                 {
2698                     // no answer or negative answer
2699                     m_mgr.HideHint();
2700                     return;
2701                 }
2702 
2703                 // drop was allowed
2704                 int src_idx = evt.GetSelection();
2705                 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
2706 
2707                 // Check that it's not an impossible parent relationship
2708                 wxWindow* p = nb;
2709                 while (p && !p->IsTopLevel())
2710                 {
2711                     if (p == src_page)
2712                     {
2713                         return;
2714                     }
2715                     p = p->GetParent();
2716                 }
2717 
2718                 // get main index of the page
2719                 int main_idx = m_tabs.GetIdxFromWindow(src_page);
2720                 wxCHECK_RET( main_idx != wxNOT_FOUND, wxT("no source page?") );
2721 
2722 
2723                 // make a copy of the page info
2724                 wxAuiNotebookPage page_info = m_tabs.GetPage(main_idx);
2725 
2726                 // remove the page from the source notebook
2727                 RemovePage(main_idx);
2728 
2729                 // reparent the page
2730                 src_page->Reparent(nb);
2731 
2732 
2733                 // found out the insert idx
2734                 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
2735                 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2736 
2737                 wxWindow* target = NULL;
2738                 int insert_idx = -1;
2739                 dest_tabs->TabHitTest(pt.x, pt.y, &target);
2740                 if (target)
2741                 {
2742                     insert_idx = dest_tabs->GetIdxFromWindow(target);
2743                 }
2744 
2745 
2746                 // add the page to the new notebook
2747                 if (insert_idx == -1)
2748                     insert_idx = dest_tabs->GetPageCount();
2749                 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2750                 nb->m_tabs.InsertPage(page_info.window, page_info, insert_idx);
2751 
2752                 nb->DoSizing();
2753                 dest_tabs->SetActivePage(insert_idx);
2754                 dest_tabs->DoShowHide();
2755                 dest_tabs->Refresh();
2756 
2757                 // set the selection in the destination tab control
2758                 nb->DoModifySelection(insert_idx, false);
2759 
2760                 // notify owner that the tab has been dragged
2761                 wxAuiNotebookEvent e2(wxEVT_AUINOTEBOOK_DRAG_DONE, m_windowId);
2762                 e2.SetSelection(evt.GetSelection());
2763                 e2.SetOldSelection(evt.GetSelection());
2764                 e2.SetEventObject(this);
2765                 GetEventHandler()->ProcessEvent(e2);
2766 
2767                 return;
2768             }
2769         }
2770     }
2771 
2772 
2773 
2774 
2775     // only perform a tab split if it's allowed
2776     wxAuiTabCtrl* dest_tabs = NULL;
2777 
2778     if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
2779     {
2780         // If the pointer is in an existing tab frame, do a tab insert
2781         wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
2782         wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
2783         int insert_idx = -1;
2784         if (tab_frame)
2785         {
2786             dest_tabs = tab_frame->m_tabs;
2787 
2788             if (dest_tabs == src_tabs)
2789             {
2790                 m_curPage = evt.GetSelection();
2791                 return;
2792             }
2793 
2794             wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2795             wxWindow* target = NULL;
2796             dest_tabs->TabHitTest(pt.x, pt.y, &target);
2797             if (target)
2798             {
2799                 insert_idx = dest_tabs->GetIdxFromWindow(target);
2800             }
2801         }
2802         else
2803         {
2804             wxPoint zero(0,0);
2805             wxRect rect = m_mgr.CalculateHintRect(m_dummyWnd,
2806                                                   mouse_client_pt,
2807                                                   zero);
2808             if (rect.IsEmpty())
2809             {
2810                 // there is no suitable drop location here, exit out
2811                 return;
2812             }
2813 
2814             // If there is no tabframe at all, create one
2815             wxTabFrame* new_tabs = new wxTabFrame;
2816             new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
2817             new_tabs->SetTabCtrlHeight(m_tabCtrlHeight);
2818             new_tabs->m_tabs = new wxAuiTabCtrl(this,
2819                                                 m_tabIdCounter++,
2820                                                 wxDefaultPosition,
2821                                                 wxDefaultSize,
2822                                                 wxNO_BORDER|wxWANTS_CHARS);
2823             new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2824             new_tabs->m_tabs->SetFlags(m_flags);
2825 
2826             m_mgr.AddPane(new_tabs,
2827                           wxAuiPaneInfo().Bottom().CaptionVisible(false),
2828                           mouse_client_pt);
2829             m_mgr.Update();
2830             dest_tabs = new_tabs->m_tabs;
2831         }
2832 
2833 
2834 
2835         // remove the page from the source tabs
2836         wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
2837         page_info.active = false;
2838         src_tabs->RemovePage(page_info.window);
2839         if (src_tabs->GetPageCount() > 0)
2840         {
2841             src_tabs->SetActivePage((size_t)0);
2842             src_tabs->DoShowHide();
2843             src_tabs->Refresh();
2844         }
2845 
2846 
2847 
2848         // add the page to the destination tabs
2849         if (insert_idx == -1)
2850             insert_idx = dest_tabs->GetPageCount();
2851         dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2852 
2853         if (src_tabs->GetPageCount() == 0)
2854         {
2855             RemoveEmptyTabFrames();
2856         }
2857 
2858         DoSizing();
2859         dest_tabs->DoShowHide();
2860         dest_tabs->Refresh();
2861 
2862         // force the set selection function reset the selection
2863         m_curPage = -1;
2864 
2865         // set the active page to the one we just split off
2866         SetSelectionToPage(page_info);
2867 
2868         UpdateHintWindowSize();
2869     }
2870 
2871     // notify owner that the tab has been dragged
2872     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_DRAG_DONE, m_windowId);
2873     e.SetSelection(evt.GetSelection());
2874     e.SetOldSelection(evt.GetSelection());
2875     e.SetEventObject(this);
2876     GetEventHandler()->ProcessEvent(e);
2877 }
2878 
2879 
2880 
OnTabCancelDrag(wxAuiNotebookEvent & command_evt)2881 void wxAuiNotebook::OnTabCancelDrag(wxAuiNotebookEvent& command_evt)
2882 {
2883     wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2884 
2885     m_mgr.HideHint();
2886 
2887     wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2888     wxCHECK_RET( src_tabs, wxT("no source object?") );
2889 
2890     src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2891 }
2892 
GetTabCtrlFromPoint(const wxPoint & pt)2893 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
2894 {
2895     // if we've just removed the last tab from the source
2896     // tab set, the remove the tab control completely
2897     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2898     size_t i, pane_count = all_panes.GetCount();
2899     for (i = 0; i < pane_count; ++i)
2900     {
2901         if (all_panes.Item(i).name == wxT("dummy"))
2902             continue;
2903 
2904         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2905         if (tabframe->m_tab_rect.Contains(pt))
2906             return tabframe->m_tabs;
2907     }
2908 
2909     return NULL;
2910 }
2911 
GetTabFrameFromTabCtrl(wxWindow * tab_ctrl)2912 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
2913 {
2914     // if we've just removed the last tab from the source
2915     // tab set, the remove the tab control completely
2916     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2917     size_t i, pane_count = all_panes.GetCount();
2918     for (i = 0; i < pane_count; ++i)
2919     {
2920         if (all_panes.Item(i).name == wxT("dummy"))
2921             continue;
2922 
2923         wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2924         if (tabframe->m_tabs == tab_ctrl)
2925         {
2926             return tabframe;
2927         }
2928     }
2929 
2930     return NULL;
2931 }
2932 
RemoveEmptyTabFrames()2933 void wxAuiNotebook::RemoveEmptyTabFrames()
2934 {
2935     // if we've just removed the last tab from the source
2936     // tab set, the remove the tab control completely
2937     wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
2938     size_t i, pane_count = all_panes.GetCount();
2939     for (i = 0; i < pane_count; ++i)
2940     {
2941         if (all_panes.Item(i).name == wxT("dummy"))
2942             continue;
2943 
2944         wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
2945         if (tab_frame->m_tabs->GetPageCount() == 0)
2946         {
2947             m_mgr.DetachPane(tab_frame);
2948 
2949             // use pending delete because sometimes during
2950             // window closing, refreshs are pending
2951             if (!wxPendingDelete.Member(tab_frame->m_tabs))
2952                 wxPendingDelete.Append(tab_frame->m_tabs);
2953 
2954             tab_frame->m_tabs = NULL;
2955 
2956             delete tab_frame;
2957         }
2958     }
2959 
2960 
2961     // check to see if there is still a center pane;
2962     // if there isn't, make a frame the center pane
2963     wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
2964     pane_count = panes.GetCount();
2965     wxWindow* first_good = NULL;
2966     bool center_found = false;
2967     for (i = 0; i < pane_count; ++i)
2968     {
2969         if (panes.Item(i).name == wxT("dummy"))
2970             continue;
2971         if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
2972             center_found = true;
2973         if (!first_good)
2974             first_good = panes.Item(i).window;
2975     }
2976 
2977     if (!center_found && first_good)
2978     {
2979         m_mgr.GetPane(first_good).Centre();
2980     }
2981 
2982     if (!m_isBeingDeleted)
2983         m_mgr.Update();
2984 }
2985 
OnChildFocusNotebook(wxChildFocusEvent & evt)2986 void wxAuiNotebook::OnChildFocusNotebook(wxChildFocusEvent& evt)
2987 {
2988     evt.Skip();
2989 
2990     // if we're dragging a tab, don't change the current selection.
2991     // This code prevents a bug that used to happen when the hint window
2992     // was hidden.  In the bug, the focus would return to the notebook
2993     // child, which would then enter this handler and call
2994     // SetSelection, which is not desired turn tab dragging.
2995 
2996     wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2997     size_t i, pane_count = all_panes.GetCount();
2998     for (i = 0; i < pane_count; ++i)
2999     {
3000         wxAuiPaneInfo& pane = all_panes.Item(i);
3001         if (pane.name == wxT("dummy"))
3002             continue;
3003         wxTabFrame* tabframe = (wxTabFrame*)pane.window;
3004         if (tabframe->m_tabs->IsDragging())
3005             return;
3006     }
3007 
3008 
3009     // find the page containing the focused child
3010     wxWindow* win = evt.GetWindow();
3011     while ( win )
3012     {
3013         // pages have the notebook as the parent, so stop when we reach one
3014         // (and also stop in the impossible case of no parent at all)
3015         wxWindow* const parent = win->GetParent();
3016         if ( !parent || parent == this )
3017             break;
3018 
3019         win = parent;
3020     }
3021 
3022     // change the tab selection to this page
3023     int idx = m_tabs.GetIdxFromWindow(win);
3024     if (idx != -1 && idx != m_curPage)
3025     {
3026         SetSelection(idx);
3027     }
3028 }
3029 
OnNavigationKeyNotebook(wxNavigationKeyEvent & event)3030 void wxAuiNotebook::OnNavigationKeyNotebook(wxNavigationKeyEvent& event)
3031 {
3032     if ( event.IsWindowChange() ) {
3033         // change pages
3034         // FIXME: the problem with this is that if we have a split notebook,
3035         // we selection may go all over the place.
3036         AdvanceSelection(event.GetDirection());
3037     }
3038     else {
3039         // we get this event in 3 cases
3040         //
3041         // a) one of our pages might have generated it because the user TABbed
3042         // out from it in which case we should propagate the event upwards and
3043         // our parent will take care of setting the focus to prev/next sibling
3044         //
3045         // or
3046         //
3047         // b) the parent panel wants to give the focus to us so that we
3048         // forward it to our selected page. We can't deal with this in
3049         // OnSetFocus() because we don't know which direction the focus came
3050         // from in this case and so can't choose between setting the focus to
3051         // first or last panel child
3052         //
3053         // or
3054         //
3055         // c) we ourselves (see MSWTranslateMessage) generated the event
3056         //
3057         wxWindow * const parent = GetParent();
3058 
3059         // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
3060         const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
3061         const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
3062 
3063         if ( isFromParent || isFromSelf )
3064         {
3065             // no, it doesn't come from child, case (b) or (c): forward to a
3066             // page but only if direction is backwards (TAB) or from ourselves,
3067             if ( GetSelection() != wxNOT_FOUND &&
3068                     (!event.GetDirection() || isFromSelf) )
3069             {
3070                 // so that the page knows that the event comes from it's parent
3071                 // and is being propagated downwards
3072                 event.SetEventObject(this);
3073 
3074                 wxWindow *page = GetPage(GetSelection());
3075                 if ( !page->GetEventHandler()->ProcessEvent(event) )
3076                 {
3077                     page->SetFocus();
3078                 }
3079                 //else: page manages focus inside it itself
3080             }
3081             else // otherwise set the focus to the notebook itself
3082             {
3083                 SetFocus();
3084             }
3085         }
3086         else
3087         {
3088             // it comes from our child, case (a), pass to the parent, but only
3089             // if the direction is forwards. Otherwise set the focus to the
3090             // notebook itself. The notebook is always the 'first' control of a
3091             // page.
3092             if ( !event.GetDirection() )
3093             {
3094                 SetFocus();
3095             }
3096             else if ( parent )
3097             {
3098                 event.SetCurrentFocus(this);
3099                 parent->GetEventHandler()->ProcessEvent(event);
3100             }
3101         }
3102     }
3103 }
3104 
OnTabButton(wxAuiNotebookEvent & evt)3105 void wxAuiNotebook::OnTabButton(wxAuiNotebookEvent& evt)
3106 {
3107     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3108 
3109     int button_id = evt.GetInt();
3110 
3111     if (button_id == wxAUI_BUTTON_CLOSE)
3112     {
3113         int selection = evt.GetSelection();
3114 
3115         if (selection == -1)
3116         {
3117             // if the close button is to the right, use the active
3118             // page selection to determine which page to close
3119             selection = tabs->GetActivePage();
3120         }
3121 
3122         if (selection != -1)
3123         {
3124             wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3125 
3126             // ask owner if it's ok to close the tab
3127             wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3128             e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3129             const int idx = m_tabs.GetIdxFromWindow(close_wnd);
3130             e.SetSelection(idx);
3131             e.SetOldSelection(evt.GetSelection());
3132             e.SetEventObject(this);
3133             GetEventHandler()->ProcessEvent(e);
3134             if (!e.IsAllowed())
3135                 return;
3136 
3137 
3138 #if wxUSE_MDI
3139             if (wxDynamicCast(close_wnd, wxAuiMDIChildFrame))
3140             {
3141                 close_wnd->Close();
3142             }
3143             else
3144 #endif
3145             {
3146                 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3147                 wxCHECK_RET( main_idx != wxNOT_FOUND, wxT("no page to delete?") );
3148 
3149                 DeletePage(main_idx);
3150             }
3151 
3152             // notify owner that the tab has been closed
3153             wxAuiNotebookEvent e2(wxEVT_AUINOTEBOOK_PAGE_CLOSED, m_windowId);
3154             e2.SetSelection(idx);
3155             e2.SetEventObject(this);
3156             GetEventHandler()->ProcessEvent(e2);
3157         }
3158     }
3159 }
3160 
3161 
OnTabMiddleDown(wxAuiNotebookEvent & evt)3162 void wxAuiNotebook::OnTabMiddleDown(wxAuiNotebookEvent& evt)
3163 {
3164     // patch event through to owner
3165     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3166     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3167 
3168     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
3169     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3170     e.SetEventObject(this);
3171     GetEventHandler()->ProcessEvent(e);
3172 }
3173 
OnTabMiddleUp(wxAuiNotebookEvent & evt)3174 void wxAuiNotebook::OnTabMiddleUp(wxAuiNotebookEvent& evt)
3175 {
3176     // if the wxAUI_NB_MIDDLE_CLICK_CLOSE is specified, middle
3177     // click should act like a tab close action.  However, first
3178     // give the owner an opportunity to handle the middle up event
3179     // for custom action
3180 
3181     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3182     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3183 
3184     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
3185     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3186     e.SetEventObject(this);
3187     if (GetEventHandler()->ProcessEvent(e))
3188         return;
3189     if (!e.IsAllowed())
3190         return;
3191 
3192     // check if we are supposed to close on middle-up
3193     if ((m_flags & wxAUI_NB_MIDDLE_CLICK_CLOSE) == 0)
3194         return;
3195 
3196     // simulate the user pressing the close button on the tab
3197     evt.SetInt(wxAUI_BUTTON_CLOSE);
3198     OnTabButton(evt);
3199 }
3200 
OnTabRightDown(wxAuiNotebookEvent & evt)3201 void wxAuiNotebook::OnTabRightDown(wxAuiNotebookEvent& evt)
3202 {
3203     // patch event through to owner
3204     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3205     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3206 
3207     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
3208     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3209     e.SetEventObject(this);
3210     GetEventHandler()->ProcessEvent(e);
3211 }
3212 
OnTabRightUp(wxAuiNotebookEvent & evt)3213 void wxAuiNotebook::OnTabRightUp(wxAuiNotebookEvent& evt)
3214 {
3215     // patch event through to owner
3216     wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3217     wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3218 
3219     wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
3220     e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3221     e.SetEventObject(this);
3222     GetEventHandler()->ProcessEvent(e);
3223 }
3224 
3225 // Sets the normal font
SetNormalFont(const wxFont & font)3226 void wxAuiNotebook::SetNormalFont(const wxFont& font)
3227 {
3228     m_normalFont = font;
3229     GetArtProvider()->SetNormalFont(font);
3230 }
3231 
3232 // Sets the selected tab font
SetSelectedFont(const wxFont & font)3233 void wxAuiNotebook::SetSelectedFont(const wxFont& font)
3234 {
3235     m_selectedFont = font;
3236     GetArtProvider()->SetSelectedFont(font);
3237 }
3238 
3239 // Sets the measuring font
SetMeasuringFont(const wxFont & font)3240 void wxAuiNotebook::SetMeasuringFont(const wxFont& font)
3241 {
3242     GetArtProvider()->SetMeasuringFont(font);
3243 }
3244 
3245 // Sets the tab font
SetFont(const wxFont & font)3246 bool wxAuiNotebook::SetFont(const wxFont& font)
3247 {
3248     wxControl::SetFont(font);
3249 
3250     wxFont normalFont(font);
3251     wxFont selectedFont(normalFont);
3252     selectedFont.SetWeight(wxBOLD);
3253 
3254     SetNormalFont(normalFont);
3255     SetSelectedFont(selectedFont);
3256     SetMeasuringFont(selectedFont);
3257 
3258     return true;
3259 }
3260 
3261 // Gets the tab control height
GetTabCtrlHeight() const3262 int wxAuiNotebook::GetTabCtrlHeight() const
3263 {
3264     return m_tabCtrlHeight;
3265 }
3266 
3267 // Gets the height of the notebook for a given page height
GetHeightForPageHeight(int pageHeight)3268 int wxAuiNotebook::GetHeightForPageHeight(int pageHeight)
3269 {
3270     UpdateTabCtrlHeight();
3271 
3272     int tabCtrlHeight = GetTabCtrlHeight();
3273     int decorHeight = 2;
3274     return tabCtrlHeight + pageHeight + decorHeight;
3275 }
3276 
3277 // Shows the window menu
ShowWindowMenu()3278 bool wxAuiNotebook::ShowWindowMenu()
3279 {
3280     wxAuiTabCtrl* tabCtrl = GetActiveTabCtrl();
3281 
3282     int idx = tabCtrl->GetArtProvider()->ShowDropDown(tabCtrl, tabCtrl->GetPages(), tabCtrl->GetActivePage());
3283 
3284     if (idx != -1)
3285     {
3286         wxAuiNotebookEvent e(wxEVT_AUINOTEBOOK_PAGE_CHANGING, tabCtrl->GetId());
3287         e.SetSelection(idx);
3288         e.SetOldSelection(tabCtrl->GetActivePage());
3289         e.SetEventObject(tabCtrl);
3290         GetEventHandler()->ProcessEvent(e);
3291 
3292         return true;
3293     }
3294     else
3295         return false;
3296 }
3297 
DoThaw()3298 void wxAuiNotebook::DoThaw()
3299 {
3300     DoSizing();
3301 
3302     wxBookCtrlBase::DoThaw();
3303 }
3304 
SetPageSize(const wxSize & WXUNUSED (size))3305 void wxAuiNotebook::SetPageSize (const wxSize& WXUNUSED(size))
3306 {
3307     wxFAIL_MSG("Not implemented for wxAuiNotebook");
3308 }
3309 
HitTest(const wxPoint & WXUNUSED (pt),long * WXUNUSED (flags)) const3310 int wxAuiNotebook::HitTest (const wxPoint& WXUNUSED(pt), long* WXUNUSED(flags)) const
3311 {
3312     wxFAIL_MSG("Not implemented for wxAuiNotebook");
3313     return wxNOT_FOUND;
3314 }
3315 
GetPageImage(size_t WXUNUSED (n)) const3316 int wxAuiNotebook::GetPageImage(size_t WXUNUSED(n)) const
3317 {
3318     wxFAIL_MSG("Not implemented for wxAuiNotebook");
3319     return -1;
3320 }
3321 
SetPageImage(size_t n,int imageId)3322 bool wxAuiNotebook::SetPageImage(size_t n, int imageId)
3323 {
3324     return SetPageBitmap(n, GetImageList()->GetBitmap(imageId));
3325 }
3326 
ChangeSelection(size_t n)3327 int wxAuiNotebook::ChangeSelection(size_t n)
3328 {
3329     return DoModifySelection(n, false);
3330 }
3331 
AddPage(wxWindow * page,const wxString & text,bool select,int imageId)3332 bool wxAuiNotebook::AddPage(wxWindow *page, const wxString &text, bool select,
3333                             int imageId)
3334 {
3335     if(HasImageList())
3336     {
3337         return AddPage(page, text, select, GetImageList()->GetBitmap(imageId));
3338     }
3339     else
3340     {
3341         return AddPage(page, text, select, wxNullBitmap);
3342     }
3343 }
3344 
DeleteAllPages()3345 bool wxAuiNotebook::DeleteAllPages()
3346 {
3347     size_t count = GetPageCount();
3348     for(size_t i = 0; i < count; i++)
3349     {
3350         DeletePage(0);
3351     }
3352     return true;
3353 }
3354 
InsertPage(size_t index,wxWindow * page,const wxString & text,bool select,int imageId)3355 bool wxAuiNotebook::InsertPage(size_t index, wxWindow *page,
3356                                const wxString &text, bool select,
3357                                int imageId)
3358 {
3359     if(HasImageList())
3360     {
3361         return InsertPage(index, page, text, select,
3362                           GetImageList()->GetBitmap(imageId));
3363     }
3364     else
3365     {
3366         return InsertPage(index, page, text, select, wxNullBitmap);
3367     }
3368 }
3369 
DoModifySelection(size_t n,bool events)3370 int wxAuiNotebook::DoModifySelection(size_t n, bool events)
3371 {
3372     wxWindow* wnd = m_tabs.GetWindowFromIdx(n);
3373     if (!wnd)
3374         return m_curPage;
3375 
3376     // don't change the page unless necessary;
3377     // however, clicking again on a tab should give it the focus.
3378     if ((int)n == m_curPage)
3379     {
3380         wxAuiTabCtrl* ctrl;
3381         int ctrl_idx;
3382         if (FindTab(wnd, &ctrl, &ctrl_idx))
3383         {
3384             if (FindFocus() != ctrl)
3385                 ctrl->SetFocus();
3386         }
3387         return m_curPage;
3388     }
3389 
3390     bool vetoed = false;
3391 
3392     wxAuiNotebookEvent evt(wxEVT_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
3393 
3394     if(events)
3395     {
3396         evt.SetSelection(n);
3397         evt.SetOldSelection(m_curPage);
3398         evt.SetEventObject(this);
3399         GetEventHandler()->ProcessEvent(evt);
3400         vetoed = !evt.IsAllowed();
3401     }
3402 
3403     if (!vetoed)
3404     {
3405         int old_curpage = m_curPage;
3406         m_curPage = n;
3407 
3408         // program allows the page change
3409         if(events)
3410         {
3411             evt.SetEventType(wxEVT_AUINOTEBOOK_PAGE_CHANGED);
3412             (void)GetEventHandler()->ProcessEvent(evt);
3413         }
3414 
3415 
3416         wxAuiTabCtrl* ctrl;
3417         int ctrl_idx;
3418         if (FindTab(wnd, &ctrl, &ctrl_idx))
3419         {
3420             m_tabs.SetActivePage(wnd);
3421 
3422             ctrl->SetActivePage(ctrl_idx);
3423             DoSizing();
3424             ctrl->DoShowHide();
3425 
3426             ctrl->MakeTabVisible(ctrl_idx, ctrl);
3427 
3428             // set fonts
3429             wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3430             size_t i, pane_count = all_panes.GetCount();
3431             for (i = 0; i < pane_count; ++i)
3432             {
3433                 wxAuiPaneInfo& pane = all_panes.Item(i);
3434                 if (pane.name == wxT("dummy"))
3435                     continue;
3436                 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
3437                 if (tabctrl != ctrl)
3438                     tabctrl->SetSelectedFont(m_normalFont);
3439                 else
3440                     tabctrl->SetSelectedFont(m_selectedFont);
3441                 tabctrl->Refresh();
3442             }
3443 
3444             // Set the focus to the page if we're not currently focused on the tab.
3445             // This is Firefox-like behaviour.
3446             if (wnd->IsShownOnScreen() && FindFocus() != ctrl)
3447                 wnd->SetFocus();
3448 
3449             return old_curpage;
3450         }
3451     }
3452 
3453     return m_curPage;
3454 }
3455 
3456 
3457 #endif // wxUSE_AUI
3458