1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/auibook.cpp
3 // Purpose: wxaui: wx advanced user interface - notebook
4 // Author: Benjamin I. Williams
7 // Copyright: (C) Copyright 2006, Kirix Corporation, All Rights Reserved
8 // Licence: wxWindows Library Licence, Version 3.1
9 ///////////////////////////////////////////////////////////////////////////////
11 // ----------------------------------------------------------------------------
13 // ----------------------------------------------------------------------------
15 #include "wx/wxprec.h"
23 #include "wx/aui/auibook.h"
26 #include "wx/settings.h"
30 #include "wx/aui/tabmdi.h"
31 #include "wx/dcbuffer.h"
33 #include "wx/arrimpl.cpp"
34 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray
)
35 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray
)
37 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
)
38 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
)
39 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
)
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
)
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
)
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
)
46 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent
, wxEvent
)
48 // -- wxAuiTabContainer class implementation --
51 // wxAuiTabContainer is a class which contains information about each
52 // tab. It also can render an entire tab control to a specified DC.
53 // It's not a window class itself, because this code will be used by
54 // the wxFrameMananger, where it is disadvantageous to have separate
55 // windows for each tab control in the case of "docked tabs"
57 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
58 // which can be used as a tab control in the normal sense.
61 // This functions are here for this proof of concept
62 // and will be factored out later. See dockart.cpp
63 static wxColor
StepColour(const wxColor
& c
, int percent
)
65 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
66 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
67 (unsigned char)wxMin((g
*percent
)/100,255),
68 (unsigned char)wxMin((b
*percent
)/100,255));
71 // This functions are here for this proof of concept
72 // and will be factored out later. See dockart.cpp
73 static wxBitmap
BitmapFromBits(const unsigned char bits
[], int w
, int h
,
74 const wxColour
& color
)
76 wxImage img
= wxBitmap((const char*)bits
, w
, h
).ConvertToImage();
77 img
.Replace(0,0,0,123,123,123);
78 img
.Replace(255,255,255,color
.Red(),color
.Green(),color
.Blue());
79 img
.SetMaskColour(123,123,123);
83 static void DrawButton(wxDC
& dc
,
86 const wxColour
& bkcolour
,
91 if (button_state
== wxAUI_BUTTON_STATE_PRESSED
)
97 if (button_state
== wxAUI_BUTTON_STATE_HOVER
||
98 button_state
== wxAUI_BUTTON_STATE_PRESSED
)
100 dc
.SetBrush(wxBrush(StepColour(bkcolour
, 120)));
101 dc
.SetPen(wxPen(StepColour(bkcolour
, 70)));
103 // draw the background behind the button
104 dc
.DrawRectangle(rect
.x
, rect
.y
, 15, 15);
107 // draw the button itself
108 dc
.DrawBitmap(bmp
, rect
.x
, rect
.y
, true);
114 wxAuiTabContainer::wxAuiTabContainer()
116 m_normal_font
= *wxNORMAL_FONT
;
117 m_selected_font
= *wxNORMAL_FONT
;
118 m_selected_font
.SetWeight(wxBOLD
);
119 m_measuring_font
= m_selected_font
;
121 wxColour base_colour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
123 wxColour background_colour
= StepColour(base_colour
, 95);
124 wxColour normaltab_colour
= base_colour
;
125 wxColour selectedtab_colour
= *wxWHITE
;
127 m_bkbrush
= wxBrush(background_colour
);
128 m_normal_bkbrush
= wxBrush(normaltab_colour
);
129 m_normal_bkpen
= wxPen(normaltab_colour
);
130 m_selected_bkbrush
= wxBrush(selectedtab_colour
);
131 m_selected_bkpen
= wxPen(selectedtab_colour
);
134 wxAuiTabContainer::~wxAuiTabContainer()
138 void wxAuiTabContainer::SetNormalFont(const wxFont
& font
)
140 m_normal_font
= font
;
143 void wxAuiTabContainer::SetSelectedFont(const wxFont
& font
)
145 m_selected_font
= font
;
148 void wxAuiTabContainer::SetMeasuringFont(const wxFont
& font
)
150 m_measuring_font
= font
;
153 void wxAuiTabContainer::SetRect(const wxRect
& rect
)
158 bool wxAuiTabContainer::AddPage(wxWindow
* page
,
159 const wxAuiNotebookPage
& info
)
161 wxAuiNotebookPage page_info
;
163 page_info
.window
= page
;
165 m_pages
.Add(page_info
);
170 bool wxAuiTabContainer::InsertPage(wxWindow
* page
,
171 const wxAuiNotebookPage
& info
,
174 wxAuiNotebookPage page_info
;
176 page_info
.window
= page
;
178 if (idx
>= m_pages
.GetCount())
179 m_pages
.Add(page_info
);
181 m_pages
.Insert(page_info
, idx
);
186 bool wxAuiTabContainer::RemovePage(wxWindow
* wnd
)
188 size_t i
, page_count
= m_pages
.GetCount();
189 for (i
= 0; i
< page_count
; ++i
)
191 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
192 if (page
.window
== wnd
)
202 bool wxAuiTabContainer::SetActivePage(wxWindow
* wnd
)
206 size_t i
, page_count
= m_pages
.GetCount();
207 for (i
= 0; i
< page_count
; ++i
)
209 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
210 if (page
.window
== wnd
)
224 void wxAuiTabContainer::SetNoneActive()
226 size_t i
, page_count
= m_pages
.GetCount();
227 for (i
= 0; i
< page_count
; ++i
)
229 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
234 bool wxAuiTabContainer::SetActivePage(size_t page
)
236 if (page
>= m_pages
.GetCount())
239 return SetActivePage(m_pages
.Item(page
).window
);
242 int wxAuiTabContainer::GetActivePage() const
244 size_t i
, page_count
= m_pages
.GetCount();
245 for (i
= 0; i
< page_count
; ++i
)
247 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
255 wxWindow
* wxAuiTabContainer::GetWindowFromIdx(size_t idx
) const
257 if (idx
>= m_pages
.GetCount())
260 return m_pages
[idx
].window
;
263 int wxAuiTabContainer::GetIdxFromWindow(wxWindow
* wnd
) const
265 size_t i
, page_count
= m_pages
.GetCount();
266 for (i
= 0; i
< page_count
; ++i
)
268 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
269 if (page
.window
== wnd
)
275 wxAuiNotebookPage
& wxAuiTabContainer::GetPage(size_t idx
)
277 wxASSERT_MSG(idx
< m_pages
.GetCount(), wxT("Invalid Page index"));
282 wxAuiNotebookPageArray
& wxAuiTabContainer::GetPages()
287 size_t wxAuiTabContainer::GetPageCount() const
289 return m_pages
.GetCount();
292 void wxAuiTabContainer::AddButton(int id
, const wxBitmap
& bmp
)
294 wxAuiTabContainerButton button
;
297 button
.cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
299 m_buttons
.Add(button
);
304 // DrawTab() draws an individual tab.
305 // As it is virtual it may be overridden.
308 // in_rect - rectangle the tab should be confined to
309 // caption - tab's caption
310 // active - whether or not the tab is active
311 // out_rect - actual output rectangle
312 // x_extent - the advance x; where the next tab should start
314 void wxAuiTabContainer::DrawTab(wxDC
* dc
,
315 const wxRect
& in_rect
,
316 const wxString
& caption_text
,
321 wxCoord normal_textx
, normal_texty
;
322 wxCoord selected_textx
, selected_texty
;
323 wxCoord measured_textx
, measured_texty
;
324 wxCoord textx
, texty
;
327 // if the caption is empty, measure some temporary text
328 wxString caption
= caption_text
;
329 if (caption_text
.empty())
333 dc
->SetFont(m_measuring_font
);
334 dc
->GetTextExtent(caption
, &measured_textx
, &measured_texty
);
336 dc
->SetFont(m_selected_font
);
337 dc
->GetTextExtent(caption
, &selected_textx
, &selected_texty
);
339 dc
->SetFont(m_normal_font
);
340 dc
->GetTextExtent(caption
, &normal_textx
, &normal_texty
);
342 caption
= caption_text
;
344 wxCoord tab_height
= measured_texty
+ 4;
345 wxCoord tab_width
= measured_textx
+ tab_height
+ 5;
346 wxCoord tab_x
= in_rect
.x
;
347 wxCoord tab_y
= in_rect
.y
+ in_rect
.height
- tab_height
;
350 // select pen, brush and font for the tab to be drawn
354 dc
->SetPen(m_selected_bkpen
);
355 dc
->SetBrush(m_selected_bkbrush
);
356 dc
->SetFont(m_selected_font
);
357 textx
= selected_textx
;
358 texty
= selected_texty
;
362 dc
->SetPen(m_normal_bkpen
);
363 dc
->SetBrush(m_normal_bkbrush
);
364 dc
->SetFont(m_normal_font
);
365 textx
= normal_textx
;
366 texty
= normal_texty
;
374 points
[0].y
= tab_y
+ tab_height
- 1;
375 points
[1].x
= tab_x
+ tab_height
- 3;
376 points
[1].y
= tab_y
+ 2;
377 points
[2].x
= tab_x
+ tab_height
+ 3;
379 points
[3].x
= tab_x
+ tab_width
- 2;
381 points
[4].x
= tab_x
+ tab_width
;
382 points
[4].y
= tab_y
+ 2;
383 points
[5].x
= tab_x
+ tab_width
;
384 points
[5].y
= tab_y
+ tab_height
- 1;
385 points
[6] = points
[0];
388 dc
->DrawPolygon(6, points
);
390 dc
->SetPen(*wxGREY_PEN
);
392 //dc->DrawLines(active ? 6 : 7, points);
393 dc
->DrawLines(7, points
);
397 dc
->DrawText(caption
,
398 tab_x
+ (tab_height
/3) + (tab_width
/2) - (textx
/2),
399 tab_y
+ tab_height
- texty
- 2);
401 *out_rect
= wxRect(tab_x
, tab_y
, tab_width
, tab_height
);
402 *x_extent
= tab_width
- (tab_height
/2) - 1;
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
409 void wxAuiTabContainer::Render(wxDC
* raw_dc
)
413 bmp
.Create(m_rect
.GetWidth(), m_rect
.GetHeight());
414 dc
.SelectObject(bmp
);
417 dc
.SetBrush(m_bkbrush
);
418 dc
.SetPen(*wxTRANSPARENT_PEN
);
419 dc
.DrawRectangle(-1, -1, m_rect
.GetWidth()+2, m_rect
.GetHeight()+2);
422 dc
.SetPen(*wxGREY_PEN
);
423 dc
.DrawLine(0, m_rect
.GetHeight()-1, m_rect
.GetWidth(), m_rect
.GetHeight()-1);
426 size_t i
, page_count
= m_pages
.GetCount();
430 int active_offset
= 0;
433 wxRect rect
= m_rect
;
436 rect
.height
= m_rect
.height
;
438 for (i
= 0; i
< page_count
; ++i
)
440 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
454 active_offset
= offset
;
460 // draw the active tab again so it stands in the foreground
461 if (active
< m_pages
.GetCount())
463 wxAuiNotebookPage
& page
= m_pages
.Item(active
);
465 rect
.x
= active_offset
;
475 offset
= m_rect
.x
+ m_rect
.width
;
476 size_t button_count
= m_buttons
.GetCount();
477 for (i
= 0; i
< button_count
; ++i
)
479 wxAuiTabContainerButton
& button
= m_buttons
.Item(button_count
- i
- 1);
481 wxRect
button_rect(offset
- button
.bitmap
.GetWidth(), 1,
482 button
.bitmap
.GetWidth(), button
.bitmap
.GetHeight());
484 button
.rect
= button_rect
;
486 DrawButton(dc
, button
.rect
, button
.bitmap
,
487 m_bkbrush
.GetColour(),
490 offset
-= button
.bitmap
.GetWidth();
494 raw_dc
->Blit(m_rect
.x
, m_rect
.y
, m_rect
.GetWidth(), m_rect
.GetHeight(), &dc
, 0, 0);
498 // TabHitTest() tests if a tab was hit, passing the window pointer
499 // back if that condition was fulfilled. The function returns
500 // true if a tab was hit, otherwise false
501 bool wxAuiTabContainer::TabHitTest(int x
, int y
, wxWindow
** hit
) const
503 if (!m_rect
.Contains(x
,y
))
506 size_t i
, page_count
= m_pages
.GetCount();
508 for (i
= 0; i
< page_count
; ++i
)
510 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
511 if (page
.rect
.Contains(x
,y
))
521 // ButtonHitTest() tests if a button was hit. The function returns
522 // true if a button was hit, otherwise false
523 bool wxAuiTabContainer::ButtonHitTest(int x
, int y
,
524 wxAuiTabContainerButton
** hit
) const
526 if (!m_rect
.Contains(x
,y
))
529 size_t i
, button_count
= m_buttons
.GetCount();
531 for (i
= 0; i
< button_count
; ++i
)
533 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
534 if (button
.rect
.Contains(x
,y
))
546 // the utility function ShowWnd() is the same as show,
547 // except it handles wxTabMDIChildFrame windows as well,
548 // as the Show() method on this class is "unplugged"
549 static void ShowWnd(wxWindow
* wnd
, bool show
)
551 if (wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
553 wxTabMDIChildFrame
* cf
= (wxTabMDIChildFrame
*)wnd
;
563 // DoShowHide() this function shows the active window, then
564 // hides all of the other windows (in that order)
565 void wxAuiTabContainer::DoShowHide()
567 wxAuiNotebookPageArray
& pages
= GetPages();
568 size_t i
, page_count
= pages
.GetCount();
570 // show new active page first
571 for (i
= 0; i
< page_count
; ++i
)
573 wxAuiNotebookPage
& page
= pages
.Item(i
);
576 ShowWnd(page
.window
, true);
581 // hide all other pages
582 for (i
= 0; i
< page_count
; ++i
)
584 wxAuiNotebookPage
& page
= pages
.Item(i
);
585 ShowWnd(page
.window
, page
.active
);
594 // -- wxAuiTabCtrl class implementation --
597 const int wxAuiButtonClose
= 101;
599 BEGIN_EVENT_TABLE(wxAuiTabCtrl
, wxControl
)
600 EVT_PAINT(wxAuiTabCtrl::OnPaint
)
601 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground
)
602 EVT_SIZE(wxAuiTabCtrl::OnSize
)
603 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown
)
604 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp
)
605 EVT_MOTION(wxAuiTabCtrl::OnMotion
)
606 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow
)
610 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow
* parent
,
614 long style
) : wxControl(parent
, id
, pos
, size
, style
)
616 m_click_pt
= wxDefaultPosition
;
617 m_is_dragging
= false;
618 m_hover_button
= NULL
;
620 // FIXME: copied from dockart-- needs to put in a common place
621 #if defined( __WXMAC__ )
622 static unsigned char close_bits
[]={
623 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
624 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
625 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
626 #elif defined( __WXGTK__)
627 static unsigned char close_bits
[]={
628 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
629 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
630 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
632 static unsigned char close_bits
[]={
633 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
634 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
635 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
638 AddButton(101, BitmapFromBits(close_bits
, 16, 16, *wxBLACK
));
642 void wxAuiTabCtrl::OnPaint(wxPaintEvent
&)
646 dc
.SetFont(GetFont());
648 if (GetPageCount() > 0)
652 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
656 void wxAuiTabCtrl::OnSize(wxSizeEvent
& evt
)
658 wxSize s
= evt
.GetSize();
659 wxRect
r(0, 0, s
.GetWidth(), s
.GetHeight());
663 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent
& evt
)
666 m_click_pt
= wxDefaultPosition
;
667 m_is_dragging
= false;
671 if (TabHitTest(evt
.m_x
, evt
.m_y
, &wnd
))
673 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
674 e
.SetSelection(GetIdxFromWindow(wnd
));
675 e
.SetOldSelection(GetActivePage());
676 e
.SetEventObject(this);
677 GetEventHandler()->ProcessEvent(e
);
679 m_click_pt
.x
= evt
.m_x
;
680 m_click_pt
.y
= evt
.m_y
;
681 m_click_tab
= e
.GetSelection();
686 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_PRESSED
;
692 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent
&)
694 if (GetCapture() == this)
699 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
, m_windowId
);
700 evt
.SetSelection(m_click_tab
);
701 evt
.SetOldSelection(m_click_tab
);
702 evt
.SetEventObject(this);
703 GetEventHandler()->ProcessEvent(evt
);
709 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
713 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
, m_windowId
);
714 evt
.SetInt(m_hover_button
->id
);
715 evt
.SetEventObject(this);
716 GetEventHandler()->ProcessEvent(evt
);
719 m_click_pt
= wxDefaultPosition
;
720 m_is_dragging
= false;
724 void wxAuiTabCtrl::OnMotion(wxMouseEvent
& evt
)
726 wxPoint pos
= evt
.GetPosition();
728 // check if the mouse is hovering above a button
729 wxAuiTabContainerButton
* button
;
730 if (ButtonHitTest(pos
.x
, pos
.y
, &button
))
732 if (button
->cur_state
!= wxAUI_BUTTON_STATE_HOVER
)
734 button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
737 m_hover_button
= button
;
745 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
746 m_hover_button
= NULL
;
753 if (!evt
.LeftIsDown() || m_click_pt
== wxDefaultPosition
)
758 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
, m_windowId
);
759 evt
.SetSelection(m_click_tab
);
760 evt
.SetOldSelection(m_click_tab
);
761 evt
.SetEventObject(this);
762 GetEventHandler()->ProcessEvent(evt
);
767 int drag_x_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_X
);
768 int drag_y_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_Y
);
770 if (abs(pos
.x
- m_click_pt
.x
) > drag_x_threshold
||
771 abs(pos
.y
- m_click_pt
.y
) > drag_y_threshold
)
773 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
, m_windowId
);
774 evt
.SetSelection(m_click_tab
);
775 evt
.SetOldSelection(m_click_tab
);
776 evt
.SetEventObject(this);
777 GetEventHandler()->ProcessEvent(evt
);
779 m_is_dragging
= true;
783 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent
& WXUNUSED(event
))
787 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
788 m_hover_button
= NULL
;
795 // wxTabFrame is an interesting case. It's important that all child pages
796 // of the multi-notebook control are all actually children of that control
797 // (and not grandchildren). wxTabFrame facilitates this. There is one
798 // instance of wxTabFrame for each tab control inside the multi-notebook.
799 // It's important to know that wxTabFrame is not a real window, but it merely
800 // used to capture the dimensions/positioning of the internal tab control and
801 // it's managed page windows
803 class wxTabFrame
: public wxWindow
810 m_rect
= wxRect(0,0,200,200);
811 m_tab_ctrl_height
= 20;
814 void SetTabCtrlHeight(int h
)
816 m_tab_ctrl_height
= h
;
819 void DoSetSize(int x
, int y
,
820 int width
, int height
,
821 int WXUNUSED(sizeFlags
= wxSIZE_AUTO
))
823 m_rect
= wxRect(x
, y
, width
, height
);
827 void DoGetClientSize(int* x
, int* y
) const
833 bool Show( bool WXUNUSED(show
= true) ) { return false; }
840 int tab_height
= wxMin(m_rect
.height
, m_tab_ctrl_height
);
841 m_tab_rect
= wxRect(m_rect
.x
, m_rect
.y
, m_rect
.width
, tab_height
);
842 m_tabs
->SetSize(m_rect
.x
, m_rect
.y
, m_rect
.width
, tab_height
);
843 m_tabs
->SetRect(wxRect(0, 0, m_rect
.width
, tab_height
));
847 wxAuiNotebookPageArray
& pages
= m_tabs
->GetPages();
848 size_t i
, page_count
= pages
.GetCount();
850 for (i
= 0; i
< page_count
; ++i
)
852 wxAuiNotebookPage
& page
= pages
.Item(i
);
853 page
.window
->SetSize(m_rect
.x
, m_rect
.y
+tab_height
, m_rect
.width
, m_rect
.height
-tab_height
);
855 if (page
.window
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
857 wxTabMDIChildFrame
* wnd
= (wxTabMDIChildFrame
*)page
.window
;
858 wnd
->ApplyMDIChildFrameRect();
863 void DoGetSize(int* x
, int* y
) const
866 *x
= m_rect
.GetWidth();
868 *y
= m_rect
.GetHeight();
880 wxAuiTabCtrl
* m_tabs
;
881 int m_tab_ctrl_height
;
888 // -- wxAuiMultiNotebook class implementation --
890 BEGIN_EVENT_TABLE(wxAuiMultiNotebook
, wxControl
)
891 //EVT_ERASE_BACKGROUND(wxAuiMultiNotebook::OnEraseBackground)
892 //EVT_SIZE(wxAuiMultiNotebook::OnSize)
893 //EVT_LEFT_DOWN(wxAuiMultiNotebook::OnLeftDown)
894 EVT_CHILD_FOCUS(wxAuiMultiNotebook::OnChildFocus
)
895 EVT_COMMAND_RANGE(10000, 10100,
896 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
,
897 wxAuiMultiNotebook::OnTabClicked
)
898 EVT_COMMAND_RANGE(10000, 10100,
899 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
,
900 wxAuiMultiNotebook::OnTabBeginDrag
)
901 EVT_COMMAND_RANGE(10000, 10100,
902 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
,
903 wxAuiMultiNotebook::OnTabEndDrag
)
904 EVT_COMMAND_RANGE(10000, 10100,
905 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
,
906 wxAuiMultiNotebook::OnTabDragMotion
)
907 EVT_COMMAND_RANGE(10000, 10100,
908 wxEVT_COMMAND_AUINOTEBOOK_BUTTON
,
909 wxAuiMultiNotebook::OnTabButton
)
912 wxAuiMultiNotebook::wxAuiMultiNotebook()
915 m_tab_id_counter
= 10000;
917 m_tab_ctrl_height
= 20;
920 wxAuiMultiNotebook::wxAuiMultiNotebook(wxWindow
*parent
,
924 long style
) : wxControl(parent
, id
, pos
, size
, style
)
929 bool wxAuiMultiNotebook::Create(wxWindow
* parent
,
935 if (!wxControl::Create(parent
, id
, pos
, size
, style
))
943 // InitNotebook() contains common initialization
944 // code called by all constructors
945 void wxAuiMultiNotebook::InitNotebook()
948 m_tab_id_counter
= 10000;
950 m_tab_ctrl_height
= 20;
952 m_normal_font
= *wxNORMAL_FONT
;
953 m_selected_font
= *wxNORMAL_FONT
;
954 m_selected_font
.SetWeight(wxBOLD
);
956 // choose a default for the tab height
959 dc
.SetFont(m_selected_font
);
960 dc
.GetTextExtent(wxT("ABCDEFGHhijklm"), &tx
, &ty
);
961 m_tab_ctrl_height
= (ty
*150)/100;
963 m_dummy_wnd
= new wxWindow(this, wxID_ANY
, wxPoint(0,0), wxSize(0,0));
964 m_dummy_wnd
->SetSize(200, 200);
965 m_dummy_wnd
->Show(false);
967 m_mgr
.SetManagedWindow(this);
969 m_mgr
.AddPane(m_dummy_wnd
,
970 wxPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
975 wxAuiMultiNotebook::~wxAuiMultiNotebook()
980 bool wxAuiMultiNotebook::AddPage(wxWindow
* page
,
981 const wxString
& caption
,
983 const wxBitmap
& bitmap
)
985 return InsertPage(GetPageCount(), page
, caption
, select
, bitmap
);
988 bool wxAuiMultiNotebook::InsertPage(size_t page_idx
,
990 const wxString
& caption
,
992 const wxBitmap
& bitmap
)
994 wxAuiNotebookPage info
;
996 info
.caption
= caption
;
997 info
.bitmap
= bitmap
;
1000 // if there are currently no tabs, the first added
1001 // tab must be active
1002 if (m_tabs
.GetPageCount() == 0)
1005 m_tabs
.InsertPage(page
, info
, page_idx
);
1007 wxAuiTabCtrl
* active_tabctrl
= GetActiveTabCtrl();
1008 if (page_idx
>= active_tabctrl
->GetPageCount())
1009 active_tabctrl
->AddPage(page
, info
);
1011 active_tabctrl
->InsertPage(page
, info
, page_idx
);
1014 active_tabctrl
->DoShowHide();
1018 int idx
= m_tabs
.GetIdxFromWindow(page
);
1019 wxASSERT_MSG(idx
!= -1, wxT("Invalid Page index returned on wxAuiMultiNotebook::InsertPage()"));
1028 // DeletePage() removes a tab from the multi-notebook,
1029 // and destroys the window as well
1030 bool wxAuiMultiNotebook::DeletePage(size_t page_idx
)
1032 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1035 // find out which onscreen tab ctrl owns this tab
1038 if (!FindTab(wnd
, &ctrl
, &ctrl_idx
))
1041 // find a new page and set it as active
1042 int new_idx
= ctrl_idx
+1;
1043 if (new_idx
>= (int)ctrl
->GetPageCount())
1044 new_idx
= ctrl_idx
-1;
1046 if (new_idx
>= 0 && new_idx
< (int)ctrl
->GetPageCount())
1048 wxWindow
* new_wnd
= ctrl
->GetWindowFromIdx(new_idx
);
1049 int main_idx
= m_tabs
.GetIdxFromWindow(new_wnd
);
1050 wxASSERT(main_idx
!= -1);
1051 SetSelection(main_idx
);
1055 // set the active page to the first page that
1056 // isn't the one being deleted
1058 size_t i
, page_count
= m_tabs
.GetPageCount();
1059 for (i
= 0; i
< page_count
; ++i
)
1061 wxWindow
* w
= m_tabs
.GetWindowFromIdx(i
);
1075 // remove the tab from main catalog
1076 if (!m_tabs
.RemovePage(wnd
))
1079 // remove the tab from the onscreen tab ctrl
1080 ctrl
->RemovePage(wnd
);
1082 // actually destroy the window now
1083 if (wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1085 // delete the child frame with pending delete, as is
1086 // customary with frame windows
1087 if (!wxPendingDelete
.Member(wnd
))
1088 wxPendingDelete
.Append(wnd
);
1095 RemoveEmptyTabFrames();
1102 // RemovePage() removes a tab from the multi-notebook,
1103 // but does not destroy the window
1104 bool wxAuiMultiNotebook::RemovePage(size_t page_idx
)
1106 // remove the tab from our own catalog
1107 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1108 if (!m_tabs
.RemovePage(wnd
))
1111 // remove the tab from the onscreen tab ctrl
1114 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1116 ctrl
->RemovePage(wnd
);
1123 // SetPageText() changes the tab caption of the specified page
1124 bool wxAuiMultiNotebook::SetPageText(size_t page_idx
, const wxString
& text
)
1126 if (page_idx
>= m_tabs
.GetPageCount())
1129 // update our own tab catalog
1130 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
1131 page_info
.caption
= text
;
1133 // update what's on screen
1136 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
1138 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
1139 info
.caption
= text
;
1147 // GetSelection() returns the index of the currently active page
1148 int wxAuiMultiNotebook::GetSelection() const
1153 // SetSelection() sets the currently active page
1154 size_t wxAuiMultiNotebook::SetSelection(size_t new_page
)
1156 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(new_page
);
1160 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
1161 evt
.SetSelection(new_page
);
1162 evt
.SetOldSelection(m_curpage
);
1163 evt
.SetEventObject(this);
1164 if (!GetEventHandler()->ProcessEvent(evt
) || evt
.IsAllowed())
1166 // program allows the page change
1167 evt
.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
);
1168 (void)GetEventHandler()->ProcessEvent(evt
);
1174 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1176 m_tabs
.SetActivePage(wnd
);
1178 ctrl
->SetActivePage(ctrl_idx
);
1182 int old_curpage
= m_curpage
;
1183 m_curpage
= new_page
;
1187 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1188 size_t i
, pane_count
= all_panes
.GetCount();
1189 for (i
= 0; i
< pane_count
; ++i
)
1191 wxPaneInfo
& pane
= all_panes
.Item(i
);
1192 if (pane
.name
== wxT("dummy"))
1194 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
1195 if (tabctrl
!= ctrl
)
1196 tabctrl
->SetSelectedFont(m_normal_font
);
1198 tabctrl
->SetSelectedFont(m_selected_font
);
1211 // GetPageCount() returns the total number of
1212 // pages managed by the multi-notebook
1213 size_t wxAuiMultiNotebook::GetPageCount() const
1215 return m_tabs
.GetPageCount();
1218 // GetPage() returns the wxWindow pointer of the
1220 wxWindow
* wxAuiMultiNotebook::GetPage(size_t page_idx
) const
1222 wxASSERT(page_idx
< m_tabs
.GetPageCount());
1224 return m_tabs
.GetWindowFromIdx(page_idx
);
1227 // DoSizing() performs all sizing operations in each tab control
1228 void wxAuiMultiNotebook::DoSizing()
1230 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1231 size_t i
, pane_count
= all_panes
.GetCount();
1232 for (i
= 0; i
< pane_count
; ++i
)
1234 if (all_panes
.Item(i
).name
== wxT("dummy"))
1237 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1238 tabframe
->DoSizing();
1242 // GetActiveTabCtrl() returns the active tab control. It is
1243 // called to determine which control gets new windows being added
1244 wxAuiTabCtrl
* wxAuiMultiNotebook::GetActiveTabCtrl()
1246 if (m_curpage
>= 0 && m_curpage
< (int)m_tabs
.GetPageCount())
1251 // find the tab ctrl with the current page
1252 if (FindTab(m_tabs
.GetPage(m_curpage
).window
,
1259 // no current page, just find the first tab ctrl
1260 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1261 size_t i
, pane_count
= all_panes
.GetCount();
1262 for (i
= 0; i
< pane_count
; ++i
)
1264 if (all_panes
.Item(i
).name
== wxT("dummy"))
1267 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1268 return tabframe
->m_tabs
;
1271 // If there is no tabframe at all, create one
1272 wxTabFrame
* tabframe
= new wxTabFrame
;
1273 tabframe
->SetTabCtrlHeight(m_tab_ctrl_height
);
1274 tabframe
->m_tabs
= new wxAuiTabCtrl(this,
1279 m_mgr
.AddPane(tabframe
,
1280 wxPaneInfo().Center().CaptionVisible(false));
1284 return tabframe
->m_tabs
;
1287 // FindTab() finds the tab control that currently contains the window as well
1288 // as the index of the window in the tab control. It returns true if the
1289 // window was found, otherwise false.
1290 bool wxAuiMultiNotebook::FindTab(wxWindow
* page
, wxAuiTabCtrl
** ctrl
, int* idx
)
1292 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1293 size_t i
, pane_count
= all_panes
.GetCount();
1294 for (i
= 0; i
< pane_count
; ++i
)
1296 if (all_panes
.Item(i
).name
== wxT("dummy"))
1299 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1301 int page_idx
= tabframe
->m_tabs
->GetIdxFromWindow(page
);
1304 *ctrl
= tabframe
->m_tabs
;
1314 void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent
&)
1318 void wxAuiMultiNotebook::OnSize(wxSizeEvent
&)
1322 void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent
& command_evt
)
1324 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1326 wxAuiTabCtrl
* ctrl
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1327 wxASSERT(ctrl
!= NULL
);
1329 wxWindow
* wnd
= ctrl
->GetWindowFromIdx(evt
.GetSelection());
1330 wxASSERT(wnd
!= NULL
);
1332 int idx
= m_tabs
.GetIdxFromWindow(wnd
);
1333 wxASSERT(idx
!= -1);
1338 void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent
&)
1342 void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent
& evt
)
1344 wxPoint screen_pt
= ::wxGetMousePosition();
1345 wxPoint client_pt
= ScreenToClient(screen_pt
);
1348 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1350 wxAuiTabCtrl
* tab_ctrl
= GetTabCtrlFromPoint(client_pt
);
1351 if (tab_ctrl
== src_tabs
)
1353 // inner-tabctrl dragging is not yet implemented
1360 wxRect hint_rect
= tab_ctrl
->GetRect();
1361 ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
1362 m_mgr
.ShowHint(hint_rect
);
1366 m_mgr
.DrawHintRect(m_dummy_wnd
, client_pt
, zero
);
1372 void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent
& command_evt
)
1374 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1379 // get the mouse position, which will be used to determine the drop point
1380 wxPoint mouse_screen_pt
= ::wxGetMousePosition();
1381 wxPoint mouse_client_pt
= ScreenToClient(mouse_screen_pt
);
1384 // the src tab control is the control that fired this event
1385 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1386 wxAuiTabCtrl
* dest_tabs
= NULL
;
1389 // If the pointer is in an existing tab frame, do a tab insert
1390 wxWindow
* hit_wnd
= ::wxFindWindowAtPoint(mouse_screen_pt
);
1391 wxTabFrame
* tab_frame
= (wxTabFrame
*)GetTabFrameFromTabCtrl(hit_wnd
);
1394 dest_tabs
= tab_frame
->m_tabs
;
1396 if (dest_tabs
== src_tabs
)
1401 // If there is no tabframe at all, create one
1402 wxTabFrame
* new_tabs
= new wxTabFrame
;
1403 new_tabs
->SetTabCtrlHeight(m_tab_ctrl_height
);
1404 new_tabs
->m_tabs
= new wxAuiTabCtrl(this,
1409 m_mgr
.AddPane(new_tabs
,
1410 wxPaneInfo().Bottom().CaptionVisible(false),
1413 dest_tabs
= new_tabs
->m_tabs
;
1418 // remove the page from the source tabs
1419 wxAuiNotebookPage page_info
= src_tabs
->GetPage(evt
.GetSelection());
1420 page_info
.active
= false;
1421 src_tabs
->RemovePage(page_info
.window
);
1422 if (src_tabs
->GetPageCount() > 0)
1424 src_tabs
->SetActivePage((size_t)0);
1425 src_tabs
->DoShowHide();
1426 src_tabs
->Refresh();
1431 // add the page to the destination tabs
1432 dest_tabs
->AddPage(page_info
.window
, page_info
);
1434 if (src_tabs
->GetPageCount() == 0)
1436 RemoveEmptyTabFrames();
1440 dest_tabs
->DoShowHide();
1441 dest_tabs
->Refresh();
1443 SetSelection(m_tabs
.GetIdxFromWindow(page_info
.window
));
1446 wxAuiTabCtrl
* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint
& pt
)
1448 // if we've just removed the last tab from the source
1449 // tab set, the remove the tab control completely
1450 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1451 size_t i
, pane_count
= all_panes
.GetCount();
1452 for (i
= 0; i
< pane_count
; ++i
)
1454 if (all_panes
.Item(i
).name
== wxT("dummy"))
1457 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1458 if (tabframe
->m_tab_rect
.Contains(pt
))
1459 return tabframe
->m_tabs
;
1465 wxWindow
* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow
* tab_ctrl
)
1467 // if we've just removed the last tab from the source
1468 // tab set, the remove the tab control completely
1469 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1470 size_t i
, pane_count
= all_panes
.GetCount();
1471 for (i
= 0; i
< pane_count
; ++i
)
1473 if (all_panes
.Item(i
).name
== wxT("dummy"))
1476 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1477 if (tabframe
->m_tabs
== tab_ctrl
)
1486 void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1488 bool must_update
= false;
1490 // if we've just removed the last tab from the source
1491 // tab set, the remove the tab control completely
1492 wxPaneInfoArray all_panes
= m_mgr
.GetAllPanes();
1493 size_t i
, pane_count
= all_panes
.GetCount();
1494 for (i
= 0; i
< pane_count
; ++i
)
1496 if (all_panes
.Item(i
).name
== wxT("dummy"))
1499 wxTabFrame
* tab_frame
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1500 if (tab_frame
->m_tabs
->GetPageCount() == 0)
1502 m_mgr
.DetachPane(tab_frame
);
1504 // use pending delete because sometimes during
1505 // window closing, refreshs are pending
1506 if (!wxPendingDelete
.Member(tab_frame
->m_tabs
))
1507 wxPendingDelete
.Append(tab_frame
->m_tabs
);
1508 //tab_frame->m_tabs->Destroy();
1516 // check to see if there is still a center pane;
1517 // if there isn't, make a frame the center pane
1518 wxPaneInfoArray panes
= m_mgr
.GetAllPanes();
1519 pane_count
= panes
.GetCount();
1520 wxWindow
* first_good
= NULL
;
1521 bool center_found
= false;
1522 for (i
= 0; i
< pane_count
; ++i
)
1524 if (panes
.Item(i
).name
== wxT("dummy"))
1526 if (panes
.Item(i
).dock_direction
== wxAUI_DOCK_CENTRE
)
1527 center_found
= true;
1529 first_good
= panes
.Item(i
).window
;
1532 if (!center_found
&& first_good
)
1534 m_mgr
.GetPane(first_good
).Centre();
1541 void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent
& evt
)
1543 int idx
= m_tabs
.GetIdxFromWindow(evt
.GetWindow());
1544 if (idx
!= -1 && idx
!= m_curpage
)
1551 void wxAuiMultiNotebook::OnTabButton(wxCommandEvent
& command_evt
)
1553 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1554 wxAuiTabCtrl
* tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1556 int button_id
= evt
.GetInt();
1558 if (button_id
== wxAuiButtonClose
)
1560 int selection
= tabs
->GetActivePage();
1562 if (selection
!= -1)
1564 wxWindow
* close_wnd
= tabs
->GetWindowFromIdx(selection
);
1566 if (close_wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1572 int main_idx
= m_tabs
.GetIdxFromWindow(close_wnd
);
1573 DeletePage(main_idx
);