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
)
52 // This functions are here for this proof of concept
53 // and will be factored out later. See dockart.cpp
54 static wxColor
StepColour(const wxColor
& c
, int percent
)
56 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
57 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
58 (unsigned char)wxMin((g
*percent
)/100,255),
59 (unsigned char)wxMin((b
*percent
)/100,255));
62 // This functions are here for this proof of concept
63 // and will be factored out later. See dockart.cpp
64 static wxBitmap
BitmapFromBits(const unsigned char bits
[], int w
, int h
,
65 const wxColour
& color
)
67 wxImage img
= wxBitmap((const char*)bits
, w
, h
).ConvertToImage();
68 img
.Replace(0,0,0,123,123,123);
69 img
.Replace(255,255,255,color
.Red(),color
.Green(),color
.Blue());
70 img
.SetMaskColour(123,123,123);
74 static void DrawButton(wxDC
& dc
,
77 const wxColour
& bkcolour
,
82 if (button_state
== wxAUI_BUTTON_STATE_PRESSED
)
88 if (button_state
== wxAUI_BUTTON_STATE_HOVER
||
89 button_state
== wxAUI_BUTTON_STATE_PRESSED
)
91 dc
.SetBrush(wxBrush(StepColour(bkcolour
, 120)));
92 dc
.SetPen(wxPen(StepColour(bkcolour
, 70)));
94 // draw the background behind the button
95 dc
.DrawRectangle(rect
.x
, rect
.y
, 15, 15);
98 // draw the button itself
99 dc
.DrawBitmap(bmp
, rect
.x
, rect
.y
, true);
106 // -- wxDefaultTabArt class implementation --
108 wxDefaultTabArt::wxDefaultTabArt()
110 m_normal_font
= *wxNORMAL_FONT
;
111 m_selected_font
= *wxNORMAL_FONT
;
112 m_selected_font
.SetWeight(wxBOLD
);
113 m_measuring_font
= m_selected_font
;
115 wxColour base_colour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
117 wxColour background_colour
= StepColour(base_colour
, 95);
118 wxColour normaltab_colour
= base_colour
;
119 wxColour selectedtab_colour
= *wxWHITE
;
121 m_bkbrush
= wxBrush(background_colour
);
122 m_normal_bkbrush
= wxBrush(normaltab_colour
);
123 m_normal_bkpen
= wxPen(normaltab_colour
);
124 m_selected_bkbrush
= wxBrush(selectedtab_colour
);
125 m_selected_bkpen
= wxPen(selectedtab_colour
);
128 void wxDefaultTabArt::DrawBackground(
133 dc
->SetBrush(m_bkbrush
);
134 dc
->SetPen(*wxTRANSPARENT_PEN
);
135 dc
->DrawRectangle(-1, -1, rect
.GetWidth()+2, rect
.GetHeight()+2);
138 dc
->SetPen(*wxGREY_PEN
);
139 dc
->DrawLine(0, rect
.GetHeight()-1, rect
.GetWidth(), rect
.GetHeight()-1);
142 // DrawTab() draws an individual tab.
145 // in_rect - rectangle the tab should be confined to
146 // caption - tab's caption
147 // active - whether or not the tab is active
148 // out_rect - actual output rectangle
149 // x_extent - the advance x; where the next tab should start
151 void wxDefaultTabArt::DrawTab(wxDC
* dc
,
152 const wxRect
& in_rect
,
153 const wxString
& caption_text
,
158 wxCoord normal_textx
, normal_texty
;
159 wxCoord selected_textx
, selected_texty
;
160 wxCoord measured_textx
, measured_texty
;
161 wxCoord textx
, texty
;
164 // if the caption is empty, measure some temporary text
165 wxString caption
= caption_text
;
166 if (caption_text
.empty())
170 dc
->SetFont(m_measuring_font
);
171 dc
->GetTextExtent(caption
, &measured_textx
, &measured_texty
);
173 dc
->SetFont(m_selected_font
);
174 dc
->GetTextExtent(caption
, &selected_textx
, &selected_texty
);
176 dc
->SetFont(m_normal_font
);
177 dc
->GetTextExtent(caption
, &normal_textx
, &normal_texty
);
179 caption
= caption_text
;
181 wxCoord tab_height
= measured_texty
+ 4;
182 wxCoord tab_width
= measured_textx
+ tab_height
+ 5;
183 wxCoord tab_x
= in_rect
.x
;
184 wxCoord tab_y
= in_rect
.y
+ in_rect
.height
- tab_height
;
187 // select pen, brush and font for the tab to be drawn
191 dc
->SetPen(m_selected_bkpen
);
192 dc
->SetBrush(m_selected_bkbrush
);
193 dc
->SetFont(m_selected_font
);
194 textx
= selected_textx
;
195 texty
= selected_texty
;
199 dc
->SetPen(m_normal_bkpen
);
200 dc
->SetBrush(m_normal_bkbrush
);
201 dc
->SetFont(m_normal_font
);
202 textx
= normal_textx
;
203 texty
= normal_texty
;
211 points
[0].y
= tab_y
+ tab_height
- 1;
212 points
[1].x
= tab_x
+ tab_height
- 3;
213 points
[1].y
= tab_y
+ 2;
214 points
[2].x
= tab_x
+ tab_height
+ 3;
216 points
[3].x
= tab_x
+ tab_width
- 2;
218 points
[4].x
= tab_x
+ tab_width
;
219 points
[4].y
= tab_y
+ 2;
220 points
[5].x
= tab_x
+ tab_width
;
221 points
[5].y
= tab_y
+ tab_height
- 1;
222 points
[6] = points
[0];
225 dc
->DrawPolygon(6, points
);
227 dc
->SetPen(*wxGREY_PEN
);
229 //dc->DrawLines(active ? 6 : 7, points);
230 dc
->DrawLines(7, points
);
234 dc
->DrawText(caption
,
235 tab_x
+ (tab_height
/3) + (tab_width
/2) - (textx
/2),
236 tab_y
+ tab_height
- texty
- 2);
238 *out_rect
= wxRect(tab_x
, tab_y
, tab_width
, tab_height
);
239 *x_extent
= tab_width
- (tab_height
/2) - 1;
243 void wxDefaultTabArt::SetNormalFont(const wxFont
& font
)
245 m_normal_font
= font
;
248 void wxDefaultTabArt::SetSelectedFont(const wxFont
& font
)
250 m_selected_font
= font
;
253 void wxDefaultTabArt::SetMeasuringFont(const wxFont
& font
)
255 m_measuring_font
= font
;
263 // -- wxAuiTabContainer class implementation --
266 // wxAuiTabContainer is a class which contains information about each
267 // tab. It also can render an entire tab control to a specified DC.
268 // It's not a window class itself, because this code will be used by
269 // the wxFrameMananger, where it is disadvantageous to have separate
270 // windows for each tab control in the case of "docked tabs"
272 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
273 // which can be used as a tab control in the normal sense.
276 wxAuiTabContainer::wxAuiTabContainer()
278 m_art
= new wxDefaultTabArt
;
281 wxAuiTabContainer::~wxAuiTabContainer()
286 void wxAuiTabContainer::SetArtProvider(wxTabArt
* art
)
292 wxTabArt
* wxAuiTabContainer::GetArtProvider()
297 void wxAuiTabContainer::SetNormalFont(const wxFont
& font
)
299 m_art
->SetNormalFont(font
);
302 void wxAuiTabContainer::SetSelectedFont(const wxFont
& font
)
304 m_art
->SetSelectedFont(font
);
307 void wxAuiTabContainer::SetMeasuringFont(const wxFont
& font
)
309 m_art
->SetMeasuringFont(font
);
312 void wxAuiTabContainer::SetRect(const wxRect
& rect
)
317 bool wxAuiTabContainer::AddPage(wxWindow
* page
,
318 const wxAuiNotebookPage
& info
)
320 wxAuiNotebookPage page_info
;
322 page_info
.window
= page
;
324 m_pages
.Add(page_info
);
329 bool wxAuiTabContainer::InsertPage(wxWindow
* page
,
330 const wxAuiNotebookPage
& info
,
333 wxAuiNotebookPage page_info
;
335 page_info
.window
= page
;
337 if (idx
>= m_pages
.GetCount())
338 m_pages
.Add(page_info
);
340 m_pages
.Insert(page_info
, idx
);
345 bool wxAuiTabContainer::RemovePage(wxWindow
* wnd
)
347 size_t i
, page_count
= m_pages
.GetCount();
348 for (i
= 0; i
< page_count
; ++i
)
350 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
351 if (page
.window
== wnd
)
361 bool wxAuiTabContainer::SetActivePage(wxWindow
* wnd
)
365 size_t i
, page_count
= m_pages
.GetCount();
366 for (i
= 0; i
< page_count
; ++i
)
368 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
369 if (page
.window
== wnd
)
383 void wxAuiTabContainer::SetNoneActive()
385 size_t i
, page_count
= m_pages
.GetCount();
386 for (i
= 0; i
< page_count
; ++i
)
388 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
393 bool wxAuiTabContainer::SetActivePage(size_t page
)
395 if (page
>= m_pages
.GetCount())
398 return SetActivePage(m_pages
.Item(page
).window
);
401 int wxAuiTabContainer::GetActivePage() const
403 size_t i
, page_count
= m_pages
.GetCount();
404 for (i
= 0; i
< page_count
; ++i
)
406 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
414 wxWindow
* wxAuiTabContainer::GetWindowFromIdx(size_t idx
) const
416 if (idx
>= m_pages
.GetCount())
419 return m_pages
[idx
].window
;
422 int wxAuiTabContainer::GetIdxFromWindow(wxWindow
* wnd
) const
424 size_t i
, page_count
= m_pages
.GetCount();
425 for (i
= 0; i
< page_count
; ++i
)
427 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
428 if (page
.window
== wnd
)
434 wxAuiNotebookPage
& wxAuiTabContainer::GetPage(size_t idx
)
436 wxASSERT_MSG(idx
< m_pages
.GetCount(), wxT("Invalid Page index"));
441 wxAuiNotebookPageArray
& wxAuiTabContainer::GetPages()
446 size_t wxAuiTabContainer::GetPageCount() const
448 return m_pages
.GetCount();
451 void wxAuiTabContainer::AddButton(int id
, const wxBitmap
& bmp
)
453 wxAuiTabContainerButton button
;
456 button
.cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
458 m_buttons
.Add(button
);
463 // Render() renders the tab catalog to the specified DC
464 // It is a virtual function and can be overridden to
465 // provide custom drawing capabilities
466 void wxAuiTabContainer::Render(wxDC
* raw_dc
)
470 bmp
.Create(m_rect
.GetWidth(), m_rect
.GetHeight());
471 dc
.SelectObject(bmp
);
474 m_art
->DrawBackground(&dc
, m_rect
);
476 size_t i
, page_count
= m_pages
.GetCount();
480 int active_offset
= 0;
483 wxRect rect
= m_rect
;
486 rect
.height
= m_rect
.height
;
488 for (i
= 0; i
< page_count
; ++i
)
490 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
504 active_offset
= offset
;
510 // draw the active tab again so it stands in the foreground
511 if (active
< m_pages
.GetCount())
513 wxAuiNotebookPage
& page
= m_pages
.Item(active
);
515 rect
.x
= active_offset
;
525 offset
= m_rect
.x
+ m_rect
.width
;
526 size_t button_count
= m_buttons
.GetCount();
527 for (i
= 0; i
< button_count
; ++i
)
529 wxAuiTabContainerButton
& button
= m_buttons
.Item(button_count
- i
- 1);
531 wxRect
button_rect(offset
- button
.bitmap
.GetWidth(), 1,
532 button
.bitmap
.GetWidth(), button
.bitmap
.GetHeight());
534 button
.rect
= button_rect
;
536 DrawButton(dc
, button
.rect
, button
.bitmap
,
537 //m_bkbrush.GetColour(),
541 offset
-= button
.bitmap
.GetWidth();
545 raw_dc
->Blit(m_rect
.x
, m_rect
.y
, m_rect
.GetWidth(), m_rect
.GetHeight(), &dc
, 0, 0);
549 // TabHitTest() tests if a tab was hit, passing the window pointer
550 // back if that condition was fulfilled. The function returns
551 // true if a tab was hit, otherwise false
552 bool wxAuiTabContainer::TabHitTest(int x
, int y
, wxWindow
** hit
) const
554 if (!m_rect
.Contains(x
,y
))
557 size_t i
, page_count
= m_pages
.GetCount();
559 for (i
= 0; i
< page_count
; ++i
)
561 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
562 if (page
.rect
.Contains(x
,y
))
572 // ButtonHitTest() tests if a button was hit. The function returns
573 // true if a button was hit, otherwise false
574 bool wxAuiTabContainer::ButtonHitTest(int x
, int y
,
575 wxAuiTabContainerButton
** hit
) const
577 if (!m_rect
.Contains(x
,y
))
580 size_t i
, button_count
= m_buttons
.GetCount();
582 for (i
= 0; i
< button_count
; ++i
)
584 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
585 if (button
.rect
.Contains(x
,y
))
597 // the utility function ShowWnd() is the same as show,
598 // except it handles wxTabMDIChildFrame windows as well,
599 // as the Show() method on this class is "unplugged"
600 static void ShowWnd(wxWindow
* wnd
, bool show
)
602 if (wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
604 wxTabMDIChildFrame
* cf
= (wxTabMDIChildFrame
*)wnd
;
614 // DoShowHide() this function shows the active window, then
615 // hides all of the other windows (in that order)
616 void wxAuiTabContainer::DoShowHide()
618 wxAuiNotebookPageArray
& pages
= GetPages();
619 size_t i
, page_count
= pages
.GetCount();
621 // show new active page first
622 for (i
= 0; i
< page_count
; ++i
)
624 wxAuiNotebookPage
& page
= pages
.Item(i
);
627 ShowWnd(page
.window
, true);
632 // hide all other pages
633 for (i
= 0; i
< page_count
; ++i
)
635 wxAuiNotebookPage
& page
= pages
.Item(i
);
636 ShowWnd(page
.window
, page
.active
);
645 // -- wxAuiTabCtrl class implementation --
648 const int wxAuiButtonClose
= 101;
650 BEGIN_EVENT_TABLE(wxAuiTabCtrl
, wxControl
)
651 EVT_PAINT(wxAuiTabCtrl::OnPaint
)
652 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground
)
653 EVT_SIZE(wxAuiTabCtrl::OnSize
)
654 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown
)
655 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp
)
656 EVT_MOTION(wxAuiTabCtrl::OnMotion
)
657 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow
)
661 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow
* parent
,
665 long style
) : wxControl(parent
, id
, pos
, size
, style
)
667 m_click_pt
= wxDefaultPosition
;
668 m_is_dragging
= false;
669 m_hover_button
= NULL
;
671 // FIXME: copied from dockart-- needs to put in a common place
672 #if defined( __WXMAC__ )
673 static unsigned char close_bits
[]={
674 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
675 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
676 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
677 #elif defined( __WXGTK__)
678 static unsigned char close_bits
[]={
679 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
680 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
681 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
683 static unsigned char close_bits
[]={
684 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
685 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
686 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
689 AddButton(101, BitmapFromBits(close_bits
, 16, 16, *wxBLACK
));
693 void wxAuiTabCtrl::OnPaint(wxPaintEvent
&)
697 dc
.SetFont(GetFont());
699 if (GetPageCount() > 0)
703 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
707 void wxAuiTabCtrl::OnSize(wxSizeEvent
& evt
)
709 wxSize s
= evt
.GetSize();
710 wxRect
r(0, 0, s
.GetWidth(), s
.GetHeight());
714 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent
& evt
)
717 m_click_pt
= wxDefaultPosition
;
718 m_is_dragging
= false;
722 if (TabHitTest(evt
.m_x
, evt
.m_y
, &wnd
))
724 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
725 e
.SetSelection(GetIdxFromWindow(wnd
));
726 e
.SetOldSelection(GetActivePage());
727 e
.SetEventObject(this);
728 GetEventHandler()->ProcessEvent(e
);
730 m_click_pt
.x
= evt
.m_x
;
731 m_click_pt
.y
= evt
.m_y
;
732 m_click_tab
= e
.GetSelection();
737 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_PRESSED
;
743 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent
&)
745 if (GetCapture() == this)
750 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
, m_windowId
);
751 evt
.SetSelection(m_click_tab
);
752 evt
.SetOldSelection(m_click_tab
);
753 evt
.SetEventObject(this);
754 GetEventHandler()->ProcessEvent(evt
);
760 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
764 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
, m_windowId
);
765 evt
.SetInt(m_hover_button
->id
);
766 evt
.SetEventObject(this);
767 GetEventHandler()->ProcessEvent(evt
);
770 m_click_pt
= wxDefaultPosition
;
771 m_is_dragging
= false;
775 void wxAuiTabCtrl::OnMotion(wxMouseEvent
& evt
)
777 wxPoint pos
= evt
.GetPosition();
779 // check if the mouse is hovering above a button
780 wxAuiTabContainerButton
* button
;
781 if (ButtonHitTest(pos
.x
, pos
.y
, &button
))
783 if (button
->cur_state
!= wxAUI_BUTTON_STATE_HOVER
)
785 button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
788 m_hover_button
= button
;
796 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
797 m_hover_button
= NULL
;
804 if (!evt
.LeftIsDown() || m_click_pt
== wxDefaultPosition
)
809 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
, m_windowId
);
810 evt
.SetSelection(m_click_tab
);
811 evt
.SetOldSelection(m_click_tab
);
812 evt
.SetEventObject(this);
813 GetEventHandler()->ProcessEvent(evt
);
818 int drag_x_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_X
);
819 int drag_y_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_Y
);
821 if (abs(pos
.x
- m_click_pt
.x
) > drag_x_threshold
||
822 abs(pos
.y
- m_click_pt
.y
) > drag_y_threshold
)
824 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
, m_windowId
);
825 evt
.SetSelection(m_click_tab
);
826 evt
.SetOldSelection(m_click_tab
);
827 evt
.SetEventObject(this);
828 GetEventHandler()->ProcessEvent(evt
);
830 m_is_dragging
= true;
834 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent
& WXUNUSED(event
))
838 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
839 m_hover_button
= NULL
;
846 // wxTabFrame is an interesting case. It's important that all child pages
847 // of the multi-notebook control are all actually children of that control
848 // (and not grandchildren). wxTabFrame facilitates this. There is one
849 // instance of wxTabFrame for each tab control inside the multi-notebook.
850 // It's important to know that wxTabFrame is not a real window, but it merely
851 // used to capture the dimensions/positioning of the internal tab control and
852 // it's managed page windows
854 class wxTabFrame
: public wxWindow
861 m_rect
= wxRect(0,0,200,200);
862 m_tab_ctrl_height
= 20;
865 void SetTabCtrlHeight(int h
)
867 m_tab_ctrl_height
= h
;
870 void DoSetSize(int x
, int y
,
871 int width
, int height
,
872 int WXUNUSED(sizeFlags
= wxSIZE_AUTO
))
874 m_rect
= wxRect(x
, y
, width
, height
);
878 void DoGetClientSize(int* x
, int* y
) const
884 bool Show( bool WXUNUSED(show
= true) ) { return false; }
891 int tab_height
= wxMin(m_rect
.height
, m_tab_ctrl_height
);
892 m_tab_rect
= wxRect(m_rect
.x
, m_rect
.y
, m_rect
.width
, tab_height
);
893 m_tabs
->SetSize(m_rect
.x
, m_rect
.y
, m_rect
.width
, tab_height
);
894 m_tabs
->SetRect(wxRect(0, 0, m_rect
.width
, tab_height
));
898 wxAuiNotebookPageArray
& pages
= m_tabs
->GetPages();
899 size_t i
, page_count
= pages
.GetCount();
901 for (i
= 0; i
< page_count
; ++i
)
903 wxAuiNotebookPage
& page
= pages
.Item(i
);
904 page
.window
->SetSize(m_rect
.x
, m_rect
.y
+tab_height
, m_rect
.width
, m_rect
.height
-tab_height
);
906 if (page
.window
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
908 wxTabMDIChildFrame
* wnd
= (wxTabMDIChildFrame
*)page
.window
;
909 wnd
->ApplyMDIChildFrameRect();
914 void DoGetSize(int* x
, int* y
) const
917 *x
= m_rect
.GetWidth();
919 *y
= m_rect
.GetHeight();
931 wxAuiTabCtrl
* m_tabs
;
932 int m_tab_ctrl_height
;
939 // -- wxAuiMultiNotebook class implementation --
941 BEGIN_EVENT_TABLE(wxAuiMultiNotebook
, wxControl
)
942 //EVT_ERASE_BACKGROUND(wxAuiMultiNotebook::OnEraseBackground)
943 //EVT_SIZE(wxAuiMultiNotebook::OnSize)
944 //EVT_LEFT_DOWN(wxAuiMultiNotebook::OnLeftDown)
945 EVT_CHILD_FOCUS(wxAuiMultiNotebook::OnChildFocus
)
946 EVT_COMMAND_RANGE(10000, 10100,
947 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
,
948 wxAuiMultiNotebook::OnTabClicked
)
949 EVT_COMMAND_RANGE(10000, 10100,
950 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
,
951 wxAuiMultiNotebook::OnTabBeginDrag
)
952 EVT_COMMAND_RANGE(10000, 10100,
953 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
,
954 wxAuiMultiNotebook::OnTabEndDrag
)
955 EVT_COMMAND_RANGE(10000, 10100,
956 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
,
957 wxAuiMultiNotebook::OnTabDragMotion
)
958 EVT_COMMAND_RANGE(10000, 10100,
959 wxEVT_COMMAND_AUINOTEBOOK_BUTTON
,
960 wxAuiMultiNotebook::OnTabButton
)
963 wxAuiMultiNotebook::wxAuiMultiNotebook()
966 m_tab_id_counter
= 10000;
968 m_tab_ctrl_height
= 20;
971 wxAuiMultiNotebook::wxAuiMultiNotebook(wxWindow
*parent
,
975 long style
) : wxControl(parent
, id
, pos
, size
, style
)
980 bool wxAuiMultiNotebook::Create(wxWindow
* parent
,
986 if (!wxControl::Create(parent
, id
, pos
, size
, style
))
994 // InitNotebook() contains common initialization
995 // code called by all constructors
996 void wxAuiMultiNotebook::InitNotebook()
999 m_tab_id_counter
= 10000;
1001 m_tab_ctrl_height
= 20;
1003 m_normal_font
= *wxNORMAL_FONT
;
1004 m_selected_font
= *wxNORMAL_FONT
;
1005 m_selected_font
.SetWeight(wxBOLD
);
1007 // choose a default for the tab height
1008 wxClientDC
dc(this);
1010 dc
.SetFont(m_selected_font
);
1011 dc
.GetTextExtent(wxT("ABCDEFGHhijklm"), &tx
, &ty
);
1012 m_tab_ctrl_height
= (ty
*150)/100;
1014 m_dummy_wnd
= new wxWindow(this, wxID_ANY
, wxPoint(0,0), wxSize(0,0));
1015 m_dummy_wnd
->SetSize(200, 200);
1016 m_dummy_wnd
->Show(false);
1018 m_mgr
.SetManagedWindow(this);
1020 m_mgr
.AddPane(m_dummy_wnd
,
1021 wxPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
1026 wxAuiMultiNotebook::~wxAuiMultiNotebook()
1031 void wxAuiMultiNotebook::SetArtProvider(wxTabArt
* art
)
1033 m_tabs
.SetArtProvider(art
);
1036 wxTabArt
* wxAuiMultiNotebook::GetArtProvider()
1038 return m_tabs
.GetArtProvider();
1041 bool wxAuiMultiNotebook::AddPage(wxWindow
* page
,
1042 const wxString
& caption
,
1044 const wxBitmap
& bitmap
)
1046 return InsertPage(GetPageCount(), page
, caption
, select
, bitmap
);
1049 bool wxAuiMultiNotebook::InsertPage(size_t page_idx
,
1051 const wxString
& caption
,
1053 const wxBitmap
& bitmap
)
1055 wxAuiNotebookPage info
;
1057 info
.caption
= caption
;
1058 info
.bitmap
= bitmap
;
1059 info
.active
= false;
1061 // if there are currently no tabs, the first added
1062 // tab must be active
1063 if (m_tabs
.GetPageCount() == 0)
1066 m_tabs
.InsertPage(page
, info
, page_idx
);
1068 wxAuiTabCtrl
* active_tabctrl
= GetActiveTabCtrl();
1069 if (page_idx
>= active_tabctrl
->GetPageCount())
1070 active_tabctrl
->AddPage(page
, info
);
1072 active_tabctrl
->InsertPage(page
, info
, page_idx
);
1075 active_tabctrl
->DoShowHide();
1079 int idx
= m_tabs
.GetIdxFromWindow(page
);
1080 wxASSERT_MSG(idx
!= -1, wxT("Invalid Page index returned on wxAuiMultiNotebook::InsertPage()"));
1089 // DeletePage() removes a tab from the multi-notebook,
1090 // and destroys the window as well
1091 bool wxAuiMultiNotebook::DeletePage(size_t page_idx
)
1093 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1094 wxWindow
* new_active
= NULL
;
1096 // find out which onscreen tab ctrl owns this tab
1099 if (!FindTab(wnd
, &ctrl
, &ctrl_idx
))
1102 // find a new page and set it as active
1103 int new_idx
= ctrl_idx
+1;
1104 if (new_idx
>= (int)ctrl
->GetPageCount())
1105 new_idx
= ctrl_idx
-1;
1107 if (new_idx
>= 0 && new_idx
< (int)ctrl
->GetPageCount())
1109 new_active
= ctrl
->GetWindowFromIdx(new_idx
);
1113 // set the active page to the first page that
1114 // isn't the one being deleted
1115 size_t i
, page_count
= m_tabs
.GetPageCount();
1116 for (i
= 0; i
< page_count
; ++i
)
1118 wxWindow
* w
= m_tabs
.GetWindowFromIdx(i
);
1121 new_active
= m_tabs
.GetWindowFromIdx(i
);
1127 // remove the tab from main catalog
1128 if (!m_tabs
.RemovePage(wnd
))
1131 // remove the tab from the onscreen tab ctrl
1132 ctrl
->RemovePage(wnd
);
1134 // actually destroy the window now
1135 if (wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1137 // delete the child frame with pending delete, as is
1138 // customary with frame windows
1139 if (!wxPendingDelete
.Member(wnd
))
1140 wxPendingDelete
.Append(wnd
);
1147 RemoveEmptyTabFrames();
1149 // set new active pane
1153 SetSelection(m_tabs
.GetIdxFromWindow(new_active
));
1161 // RemovePage() removes a tab from the multi-notebook,
1162 // but does not destroy the window
1163 bool wxAuiMultiNotebook::RemovePage(size_t page_idx
)
1165 // remove the tab from our own catalog
1166 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1167 if (!m_tabs
.RemovePage(wnd
))
1170 // remove the tab from the onscreen tab ctrl
1173 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1175 ctrl
->RemovePage(wnd
);
1182 // SetPageText() changes the tab caption of the specified page
1183 bool wxAuiMultiNotebook::SetPageText(size_t page_idx
, const wxString
& text
)
1185 if (page_idx
>= m_tabs
.GetPageCount())
1188 // update our own tab catalog
1189 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
1190 page_info
.caption
= text
;
1192 // update what's on screen
1195 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
1197 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
1198 info
.caption
= text
;
1206 // GetSelection() returns the index of the currently active page
1207 int wxAuiMultiNotebook::GetSelection() const
1212 // SetSelection() sets the currently active page
1213 size_t wxAuiMultiNotebook::SetSelection(size_t new_page
)
1215 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(new_page
);
1219 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
1220 evt
.SetSelection(new_page
);
1221 evt
.SetOldSelection(m_curpage
);
1222 evt
.SetEventObject(this);
1223 if (!GetEventHandler()->ProcessEvent(evt
) || evt
.IsAllowed())
1225 // program allows the page change
1226 evt
.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
);
1227 (void)GetEventHandler()->ProcessEvent(evt
);
1233 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1235 m_tabs
.SetActivePage(wnd
);
1237 ctrl
->SetActivePage(ctrl_idx
);
1241 int old_curpage
= m_curpage
;
1242 m_curpage
= new_page
;
1246 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1247 size_t i
, pane_count
= all_panes
.GetCount();
1248 for (i
= 0; i
< pane_count
; ++i
)
1250 wxPaneInfo
& pane
= all_panes
.Item(i
);
1251 if (pane
.name
== wxT("dummy"))
1253 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
1254 if (tabctrl
!= ctrl
)
1255 tabctrl
->SetSelectedFont(m_normal_font
);
1257 tabctrl
->SetSelectedFont(m_selected_font
);
1270 // GetPageCount() returns the total number of
1271 // pages managed by the multi-notebook
1272 size_t wxAuiMultiNotebook::GetPageCount() const
1274 return m_tabs
.GetPageCount();
1277 // GetPage() returns the wxWindow pointer of the
1279 wxWindow
* wxAuiMultiNotebook::GetPage(size_t page_idx
) const
1281 wxASSERT(page_idx
< m_tabs
.GetPageCount());
1283 return m_tabs
.GetWindowFromIdx(page_idx
);
1286 // DoSizing() performs all sizing operations in each tab control
1287 void wxAuiMultiNotebook::DoSizing()
1289 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1290 size_t i
, pane_count
= all_panes
.GetCount();
1291 for (i
= 0; i
< pane_count
; ++i
)
1293 if (all_panes
.Item(i
).name
== wxT("dummy"))
1296 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1297 tabframe
->DoSizing();
1301 // GetActiveTabCtrl() returns the active tab control. It is
1302 // called to determine which control gets new windows being added
1303 wxAuiTabCtrl
* wxAuiMultiNotebook::GetActiveTabCtrl()
1305 if (m_curpage
>= 0 && m_curpage
< (int)m_tabs
.GetPageCount())
1310 // find the tab ctrl with the current page
1311 if (FindTab(m_tabs
.GetPage(m_curpage
).window
,
1318 // no current page, just find the first tab ctrl
1319 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1320 size_t i
, pane_count
= all_panes
.GetCount();
1321 for (i
= 0; i
< pane_count
; ++i
)
1323 if (all_panes
.Item(i
).name
== wxT("dummy"))
1326 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1327 return tabframe
->m_tabs
;
1330 // If there is no tabframe at all, create one
1331 wxTabFrame
* tabframe
= new wxTabFrame
;
1332 tabframe
->SetTabCtrlHeight(m_tab_ctrl_height
);
1333 tabframe
->m_tabs
= new wxAuiTabCtrl(this,
1338 m_mgr
.AddPane(tabframe
,
1339 wxPaneInfo().Center().CaptionVisible(false));
1343 return tabframe
->m_tabs
;
1346 // FindTab() finds the tab control that currently contains the window as well
1347 // as the index of the window in the tab control. It returns true if the
1348 // window was found, otherwise false.
1349 bool wxAuiMultiNotebook::FindTab(wxWindow
* page
, wxAuiTabCtrl
** ctrl
, int* idx
)
1351 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1352 size_t i
, pane_count
= all_panes
.GetCount();
1353 for (i
= 0; i
< pane_count
; ++i
)
1355 if (all_panes
.Item(i
).name
== wxT("dummy"))
1358 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1360 int page_idx
= tabframe
->m_tabs
->GetIdxFromWindow(page
);
1363 *ctrl
= tabframe
->m_tabs
;
1373 void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent
&)
1377 void wxAuiMultiNotebook::OnSize(wxSizeEvent
&)
1381 void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent
& command_evt
)
1383 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1385 wxAuiTabCtrl
* ctrl
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1386 wxASSERT(ctrl
!= NULL
);
1388 wxWindow
* wnd
= ctrl
->GetWindowFromIdx(evt
.GetSelection());
1389 wxASSERT(wnd
!= NULL
);
1391 int idx
= m_tabs
.GetIdxFromWindow(wnd
);
1392 wxASSERT(idx
!= -1);
1397 void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent
&)
1401 void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent
& evt
)
1403 wxPoint screen_pt
= ::wxGetMousePosition();
1404 wxPoint client_pt
= ScreenToClient(screen_pt
);
1407 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1409 wxAuiTabCtrl
* tab_ctrl
= GetTabCtrlFromPoint(client_pt
);
1410 if (tab_ctrl
== src_tabs
)
1412 // inner-tabctrl dragging is not yet implemented
1419 wxRect hint_rect
= tab_ctrl
->GetRect();
1420 ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
1421 m_mgr
.ShowHint(hint_rect
);
1425 m_mgr
.DrawHintRect(m_dummy_wnd
, client_pt
, zero
);
1431 void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent
& command_evt
)
1433 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1438 // get the mouse position, which will be used to determine the drop point
1439 wxPoint mouse_screen_pt
= ::wxGetMousePosition();
1440 wxPoint mouse_client_pt
= ScreenToClient(mouse_screen_pt
);
1443 // the src tab control is the control that fired this event
1444 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1445 wxAuiTabCtrl
* dest_tabs
= NULL
;
1448 // If the pointer is in an existing tab frame, do a tab insert
1449 wxWindow
* hit_wnd
= ::wxFindWindowAtPoint(mouse_screen_pt
);
1450 wxTabFrame
* tab_frame
= (wxTabFrame
*)GetTabFrameFromTabCtrl(hit_wnd
);
1453 dest_tabs
= tab_frame
->m_tabs
;
1455 if (dest_tabs
== src_tabs
)
1460 // If there is no tabframe at all, create one
1461 wxTabFrame
* new_tabs
= new wxTabFrame
;
1462 new_tabs
->SetTabCtrlHeight(m_tab_ctrl_height
);
1463 new_tabs
->m_tabs
= new wxAuiTabCtrl(this,
1468 m_mgr
.AddPane(new_tabs
,
1469 wxPaneInfo().Bottom().CaptionVisible(false),
1472 dest_tabs
= new_tabs
->m_tabs
;
1477 // remove the page from the source tabs
1478 wxAuiNotebookPage page_info
= src_tabs
->GetPage(evt
.GetSelection());
1479 page_info
.active
= false;
1480 src_tabs
->RemovePage(page_info
.window
);
1481 if (src_tabs
->GetPageCount() > 0)
1483 src_tabs
->SetActivePage((size_t)0);
1484 src_tabs
->DoShowHide();
1485 src_tabs
->Refresh();
1490 // add the page to the destination tabs
1491 dest_tabs
->AddPage(page_info
.window
, page_info
);
1493 if (src_tabs
->GetPageCount() == 0)
1495 RemoveEmptyTabFrames();
1499 dest_tabs
->DoShowHide();
1500 dest_tabs
->Refresh();
1502 SetSelection(m_tabs
.GetIdxFromWindow(page_info
.window
));
1505 wxAuiTabCtrl
* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint
& pt
)
1507 // if we've just removed the last tab from the source
1508 // tab set, the remove the tab control completely
1509 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1510 size_t i
, pane_count
= all_panes
.GetCount();
1511 for (i
= 0; i
< pane_count
; ++i
)
1513 if (all_panes
.Item(i
).name
== wxT("dummy"))
1516 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1517 if (tabframe
->m_tab_rect
.Contains(pt
))
1518 return tabframe
->m_tabs
;
1524 wxWindow
* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow
* tab_ctrl
)
1526 // if we've just removed the last tab from the source
1527 // tab set, the remove the tab control completely
1528 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1529 size_t i
, pane_count
= all_panes
.GetCount();
1530 for (i
= 0; i
< pane_count
; ++i
)
1532 if (all_panes
.Item(i
).name
== wxT("dummy"))
1535 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1536 if (tabframe
->m_tabs
== tab_ctrl
)
1545 void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1547 bool must_update
= false;
1549 // if we've just removed the last tab from the source
1550 // tab set, the remove the tab control completely
1551 wxPaneInfoArray all_panes
= m_mgr
.GetAllPanes();
1552 size_t i
, pane_count
= all_panes
.GetCount();
1553 for (i
= 0; i
< pane_count
; ++i
)
1555 if (all_panes
.Item(i
).name
== wxT("dummy"))
1558 wxTabFrame
* tab_frame
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1559 if (tab_frame
->m_tabs
->GetPageCount() == 0)
1561 m_mgr
.DetachPane(tab_frame
);
1563 // use pending delete because sometimes during
1564 // window closing, refreshs are pending
1565 if (!wxPendingDelete
.Member(tab_frame
->m_tabs
))
1566 wxPendingDelete
.Append(tab_frame
->m_tabs
);
1567 //tab_frame->m_tabs->Destroy();
1575 // check to see if there is still a center pane;
1576 // if there isn't, make a frame the center pane
1577 wxPaneInfoArray panes
= m_mgr
.GetAllPanes();
1578 pane_count
= panes
.GetCount();
1579 wxWindow
* first_good
= NULL
;
1580 bool center_found
= false;
1581 for (i
= 0; i
< pane_count
; ++i
)
1583 if (panes
.Item(i
).name
== wxT("dummy"))
1585 if (panes
.Item(i
).dock_direction
== wxAUI_DOCK_CENTRE
)
1586 center_found
= true;
1588 first_good
= panes
.Item(i
).window
;
1591 if (!center_found
&& first_good
)
1593 m_mgr
.GetPane(first_good
).Centre();
1600 void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent
& evt
)
1602 int idx
= m_tabs
.GetIdxFromWindow(evt
.GetWindow());
1603 if (idx
!= -1 && idx
!= m_curpage
)
1610 void wxAuiMultiNotebook::OnTabButton(wxCommandEvent
& command_evt
)
1612 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1613 wxAuiTabCtrl
* tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1615 int button_id
= evt
.GetInt();
1617 if (button_id
== wxAuiButtonClose
)
1619 int selection
= tabs
->GetActivePage();
1621 if (selection
!= -1)
1623 wxWindow
* close_wnd
= tabs
->GetWindowFromIdx(selection
);
1625 if (close_wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1631 int main_idx
= m_tabs
.GetIdxFromWindow(close_wnd
);
1632 DeletePage(main_idx
);