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
);
1033 wxWindow
* new_active
= NULL
;
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 new_active
= ctrl
->GetWindowFromIdx(new_idx
);
1052 // set the active page to the first page that
1053 // isn't the one being deleted
1054 size_t i
, page_count
= m_tabs
.GetPageCount();
1055 for (i
= 0; i
< page_count
; ++i
)
1057 wxWindow
* w
= m_tabs
.GetWindowFromIdx(i
);
1060 new_active
= m_tabs
.GetWindowFromIdx(i
);
1066 // remove the tab from main catalog
1067 if (!m_tabs
.RemovePage(wnd
))
1070 // remove the tab from the onscreen tab ctrl
1071 ctrl
->RemovePage(wnd
);
1073 // actually destroy the window now
1074 if (wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1076 // delete the child frame with pending delete, as is
1077 // customary with frame windows
1078 if (!wxPendingDelete
.Member(wnd
))
1079 wxPendingDelete
.Append(wnd
);
1086 RemoveEmptyTabFrames();
1088 // set new active pane
1092 SetSelection(m_tabs
.GetIdxFromWindow(new_active
));
1100 // RemovePage() removes a tab from the multi-notebook,
1101 // but does not destroy the window
1102 bool wxAuiMultiNotebook::RemovePage(size_t page_idx
)
1104 // remove the tab from our own catalog
1105 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1106 if (!m_tabs
.RemovePage(wnd
))
1109 // remove the tab from the onscreen tab ctrl
1112 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1114 ctrl
->RemovePage(wnd
);
1121 // SetPageText() changes the tab caption of the specified page
1122 bool wxAuiMultiNotebook::SetPageText(size_t page_idx
, const wxString
& text
)
1124 if (page_idx
>= m_tabs
.GetPageCount())
1127 // update our own tab catalog
1128 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
1129 page_info
.caption
= text
;
1131 // update what's on screen
1134 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
1136 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
1137 info
.caption
= text
;
1145 // GetSelection() returns the index of the currently active page
1146 int wxAuiMultiNotebook::GetSelection() const
1151 // SetSelection() sets the currently active page
1152 size_t wxAuiMultiNotebook::SetSelection(size_t new_page
)
1154 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(new_page
);
1158 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
1159 evt
.SetSelection(new_page
);
1160 evt
.SetOldSelection(m_curpage
);
1161 evt
.SetEventObject(this);
1162 if (!GetEventHandler()->ProcessEvent(evt
) || evt
.IsAllowed())
1164 // program allows the page change
1165 evt
.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
);
1166 (void)GetEventHandler()->ProcessEvent(evt
);
1172 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1174 m_tabs
.SetActivePage(wnd
);
1176 ctrl
->SetActivePage(ctrl_idx
);
1180 int old_curpage
= m_curpage
;
1181 m_curpage
= new_page
;
1185 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1186 size_t i
, pane_count
= all_panes
.GetCount();
1187 for (i
= 0; i
< pane_count
; ++i
)
1189 wxPaneInfo
& pane
= all_panes
.Item(i
);
1190 if (pane
.name
== wxT("dummy"))
1192 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
1193 if (tabctrl
!= ctrl
)
1194 tabctrl
->SetSelectedFont(m_normal_font
);
1196 tabctrl
->SetSelectedFont(m_selected_font
);
1209 // GetPageCount() returns the total number of
1210 // pages managed by the multi-notebook
1211 size_t wxAuiMultiNotebook::GetPageCount() const
1213 return m_tabs
.GetPageCount();
1216 // GetPage() returns the wxWindow pointer of the
1218 wxWindow
* wxAuiMultiNotebook::GetPage(size_t page_idx
) const
1220 wxASSERT(page_idx
< m_tabs
.GetPageCount());
1222 return m_tabs
.GetWindowFromIdx(page_idx
);
1225 // DoSizing() performs all sizing operations in each tab control
1226 void wxAuiMultiNotebook::DoSizing()
1228 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1229 size_t i
, pane_count
= all_panes
.GetCount();
1230 for (i
= 0; i
< pane_count
; ++i
)
1232 if (all_panes
.Item(i
).name
== wxT("dummy"))
1235 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1236 tabframe
->DoSizing();
1240 // GetActiveTabCtrl() returns the active tab control. It is
1241 // called to determine which control gets new windows being added
1242 wxAuiTabCtrl
* wxAuiMultiNotebook::GetActiveTabCtrl()
1244 if (m_curpage
>= 0 && m_curpage
< (int)m_tabs
.GetPageCount())
1249 // find the tab ctrl with the current page
1250 if (FindTab(m_tabs
.GetPage(m_curpage
).window
,
1257 // no current page, just find the first tab ctrl
1258 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1259 size_t i
, pane_count
= all_panes
.GetCount();
1260 for (i
= 0; i
< pane_count
; ++i
)
1262 if (all_panes
.Item(i
).name
== wxT("dummy"))
1265 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1266 return tabframe
->m_tabs
;
1269 // If there is no tabframe at all, create one
1270 wxTabFrame
* tabframe
= new wxTabFrame
;
1271 tabframe
->SetTabCtrlHeight(m_tab_ctrl_height
);
1272 tabframe
->m_tabs
= new wxAuiTabCtrl(this,
1277 m_mgr
.AddPane(tabframe
,
1278 wxPaneInfo().Center().CaptionVisible(false));
1282 return tabframe
->m_tabs
;
1285 // FindTab() finds the tab control that currently contains the window as well
1286 // as the index of the window in the tab control. It returns true if the
1287 // window was found, otherwise false.
1288 bool wxAuiMultiNotebook::FindTab(wxWindow
* page
, wxAuiTabCtrl
** ctrl
, int* idx
)
1290 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1291 size_t i
, pane_count
= all_panes
.GetCount();
1292 for (i
= 0; i
< pane_count
; ++i
)
1294 if (all_panes
.Item(i
).name
== wxT("dummy"))
1297 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1299 int page_idx
= tabframe
->m_tabs
->GetIdxFromWindow(page
);
1302 *ctrl
= tabframe
->m_tabs
;
1312 void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent
&)
1316 void wxAuiMultiNotebook::OnSize(wxSizeEvent
&)
1320 void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent
& command_evt
)
1322 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1324 wxAuiTabCtrl
* ctrl
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1325 wxASSERT(ctrl
!= NULL
);
1327 wxWindow
* wnd
= ctrl
->GetWindowFromIdx(evt
.GetSelection());
1328 wxASSERT(wnd
!= NULL
);
1330 int idx
= m_tabs
.GetIdxFromWindow(wnd
);
1331 wxASSERT(idx
!= -1);
1336 void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent
&)
1340 void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent
& evt
)
1342 wxPoint screen_pt
= ::wxGetMousePosition();
1343 wxPoint client_pt
= ScreenToClient(screen_pt
);
1346 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1348 wxAuiTabCtrl
* tab_ctrl
= GetTabCtrlFromPoint(client_pt
);
1349 if (tab_ctrl
== src_tabs
)
1351 // inner-tabctrl dragging is not yet implemented
1358 wxRect hint_rect
= tab_ctrl
->GetRect();
1359 ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
1360 m_mgr
.ShowHint(hint_rect
);
1364 m_mgr
.DrawHintRect(m_dummy_wnd
, client_pt
, zero
);
1370 void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent
& command_evt
)
1372 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1377 // get the mouse position, which will be used to determine the drop point
1378 wxPoint mouse_screen_pt
= ::wxGetMousePosition();
1379 wxPoint mouse_client_pt
= ScreenToClient(mouse_screen_pt
);
1382 // the src tab control is the control that fired this event
1383 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1384 wxAuiTabCtrl
* dest_tabs
= NULL
;
1387 // If the pointer is in an existing tab frame, do a tab insert
1388 wxWindow
* hit_wnd
= ::wxFindWindowAtPoint(mouse_screen_pt
);
1389 wxTabFrame
* tab_frame
= (wxTabFrame
*)GetTabFrameFromTabCtrl(hit_wnd
);
1392 dest_tabs
= tab_frame
->m_tabs
;
1394 if (dest_tabs
== src_tabs
)
1399 // If there is no tabframe at all, create one
1400 wxTabFrame
* new_tabs
= new wxTabFrame
;
1401 new_tabs
->SetTabCtrlHeight(m_tab_ctrl_height
);
1402 new_tabs
->m_tabs
= new wxAuiTabCtrl(this,
1407 m_mgr
.AddPane(new_tabs
,
1408 wxPaneInfo().Bottom().CaptionVisible(false),
1411 dest_tabs
= new_tabs
->m_tabs
;
1416 // remove the page from the source tabs
1417 wxAuiNotebookPage page_info
= src_tabs
->GetPage(evt
.GetSelection());
1418 page_info
.active
= false;
1419 src_tabs
->RemovePage(page_info
.window
);
1420 if (src_tabs
->GetPageCount() > 0)
1422 src_tabs
->SetActivePage((size_t)0);
1423 src_tabs
->DoShowHide();
1424 src_tabs
->Refresh();
1429 // add the page to the destination tabs
1430 dest_tabs
->AddPage(page_info
.window
, page_info
);
1432 if (src_tabs
->GetPageCount() == 0)
1434 RemoveEmptyTabFrames();
1438 dest_tabs
->DoShowHide();
1439 dest_tabs
->Refresh();
1441 SetSelection(m_tabs
.GetIdxFromWindow(page_info
.window
));
1444 wxAuiTabCtrl
* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint
& pt
)
1446 // if we've just removed the last tab from the source
1447 // tab set, the remove the tab control completely
1448 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1449 size_t i
, pane_count
= all_panes
.GetCount();
1450 for (i
= 0; i
< pane_count
; ++i
)
1452 if (all_panes
.Item(i
).name
== wxT("dummy"))
1455 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1456 if (tabframe
->m_tab_rect
.Contains(pt
))
1457 return tabframe
->m_tabs
;
1463 wxWindow
* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow
* tab_ctrl
)
1465 // if we've just removed the last tab from the source
1466 // tab set, the remove the tab control completely
1467 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1468 size_t i
, pane_count
= all_panes
.GetCount();
1469 for (i
= 0; i
< pane_count
; ++i
)
1471 if (all_panes
.Item(i
).name
== wxT("dummy"))
1474 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1475 if (tabframe
->m_tabs
== tab_ctrl
)
1484 void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1486 bool must_update
= false;
1488 // if we've just removed the last tab from the source
1489 // tab set, the remove the tab control completely
1490 wxPaneInfoArray all_panes
= m_mgr
.GetAllPanes();
1491 size_t i
, pane_count
= all_panes
.GetCount();
1492 for (i
= 0; i
< pane_count
; ++i
)
1494 if (all_panes
.Item(i
).name
== wxT("dummy"))
1497 wxTabFrame
* tab_frame
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1498 if (tab_frame
->m_tabs
->GetPageCount() == 0)
1500 m_mgr
.DetachPane(tab_frame
);
1502 // use pending delete because sometimes during
1503 // window closing, refreshs are pending
1504 if (!wxPendingDelete
.Member(tab_frame
->m_tabs
))
1505 wxPendingDelete
.Append(tab_frame
->m_tabs
);
1506 //tab_frame->m_tabs->Destroy();
1514 // check to see if there is still a center pane;
1515 // if there isn't, make a frame the center pane
1516 wxPaneInfoArray panes
= m_mgr
.GetAllPanes();
1517 pane_count
= panes
.GetCount();
1518 wxWindow
* first_good
= NULL
;
1519 bool center_found
= false;
1520 for (i
= 0; i
< pane_count
; ++i
)
1522 if (panes
.Item(i
).name
== wxT("dummy"))
1524 if (panes
.Item(i
).dock_direction
== wxAUI_DOCK_CENTRE
)
1525 center_found
= true;
1527 first_good
= panes
.Item(i
).window
;
1530 if (!center_found
&& first_good
)
1532 m_mgr
.GetPane(first_good
).Centre();
1539 void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent
& evt
)
1541 int idx
= m_tabs
.GetIdxFromWindow(evt
.GetWindow());
1542 if (idx
!= -1 && idx
!= m_curpage
)
1549 void wxAuiMultiNotebook::OnTabButton(wxCommandEvent
& command_evt
)
1551 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1552 wxAuiTabCtrl
* tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1554 int button_id
= evt
.GetInt();
1556 if (button_id
== wxAuiButtonClose
)
1558 int selection
= tabs
->GetActivePage();
1560 if (selection
!= -1)
1562 wxWindow
* close_wnd
= tabs
->GetWindowFromIdx(selection
);
1564 if (close_wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1570 int main_idx
= m_tabs
.GetIdxFromWindow(close_wnd
);
1571 DeletePage(main_idx
);