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(255,255,255,123,123,123);
78 img
.Replace(0,0,0,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
,
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
;
329 if (_caption
.IsEmpty())
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
);
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
.Inside(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
.Inside(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
.Inside(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
.Inside(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 static unsigned char close_bits
[]={
622 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
623 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
624 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
626 AddButton(101, BitmapFromBits(close_bits
, 16, 16, *wxBLACK
));
630 void wxAuiTabCtrl::OnPaint(wxPaintEvent
&)
634 dc
.SetFont(GetFont());
636 if (GetPageCount() > 0)
640 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
644 void wxAuiTabCtrl::OnSize(wxSizeEvent
& evt
)
646 wxSize s
= evt
.GetSize();
647 wxRect
r(0, 0, s
.GetWidth(), s
.GetHeight());
651 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent
& evt
)
654 m_click_pt
= wxDefaultPosition
;
655 m_is_dragging
= false;
659 if (TabHitTest(evt
.m_x
, evt
.m_y
, &wnd
))
661 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
662 e
.SetSelection(GetIdxFromWindow(wnd
));
663 e
.SetOldSelection(GetActivePage());
664 e
.SetEventObject(this);
665 GetEventHandler()->ProcessEvent(e
);
667 m_click_pt
.x
= evt
.m_x
;
668 m_click_pt
.y
= evt
.m_y
;
669 m_click_tab
= e
.GetSelection();
674 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_PRESSED
;
680 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent
&)
682 if (GetCapture() == this)
687 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
, m_windowId
);
688 evt
.SetSelection(m_click_tab
);
689 evt
.SetOldSelection(m_click_tab
);
690 evt
.SetEventObject(this);
691 GetEventHandler()->ProcessEvent(evt
);
697 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
701 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
, m_windowId
);
702 evt
.SetInt(m_hover_button
->id
);
703 evt
.SetEventObject(this);
704 GetEventHandler()->ProcessEvent(evt
);
707 m_click_pt
= wxDefaultPosition
;
708 m_is_dragging
= false;
712 void wxAuiTabCtrl::OnMotion(wxMouseEvent
& evt
)
714 wxPoint pos
= evt
.GetPosition();
716 // check if the mouse is hovering above a button
717 wxAuiTabContainerButton
* button
;
718 if (ButtonHitTest(pos
.x
, pos
.y
, &button
))
720 if (button
->cur_state
!= wxAUI_BUTTON_STATE_HOVER
)
722 button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
725 m_hover_button
= button
;
733 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
734 m_hover_button
= NULL
;
741 if (!evt
.LeftIsDown() || m_click_pt
== wxDefaultPosition
)
746 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
, m_windowId
);
747 evt
.SetSelection(m_click_tab
);
748 evt
.SetOldSelection(m_click_tab
);
749 evt
.SetEventObject(this);
750 GetEventHandler()->ProcessEvent(evt
);
755 int drag_x_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_X
);
756 int drag_y_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_Y
);
758 if (abs(pos
.x
- m_click_pt
.x
) > drag_x_threshold
||
759 abs(pos
.y
- m_click_pt
.y
) > drag_y_threshold
)
761 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
, m_windowId
);
762 evt
.SetSelection(m_click_tab
);
763 evt
.SetOldSelection(m_click_tab
);
764 evt
.SetEventObject(this);
765 GetEventHandler()->ProcessEvent(evt
);
767 m_is_dragging
= true;
771 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent
& WXUNUSED(event
))
775 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
776 m_hover_button
= NULL
;
783 // wxTabFrame is an interesting case. It's important that all child pages
784 // of the multi-notebook control are all actually children of that control
785 // (and not grandchildren). wxTabFrame facilitates this. There is one
786 // instance of wxTabFrame for each tab control inside the multi-notebook.
787 // It's important to know that wxTabFrame is not a real window, but it merely
788 // used to capture the dimensions/positioning of the internal tab control and
789 // it's managed page windows
791 class wxTabFrame
: public wxWindow
798 m_rect
= wxRect(0,0,200,200);
799 m_tab_ctrl_height
= 20;
802 void SetTabCtrlHeight(int h
)
804 m_tab_ctrl_height
= h
;
807 void DoSetSize(int x
, int y
,
808 int width
, int height
,
809 int WXUNUSED(sizeFlags
= wxSIZE_AUTO
))
811 m_rect
= wxRect(x
, y
, width
, height
);
815 void DoGetClientSize(int* x
, int* y
) const
821 bool Show( bool WXUNUSED(show
= true) ) { return false; }
828 int tab_height
= wxMin(m_rect
.height
, m_tab_ctrl_height
);
829 m_tab_rect
= wxRect(m_rect
.x
, m_rect
.y
, m_rect
.width
, tab_height
);
830 m_tabs
->SetSize(m_rect
.x
, m_rect
.y
, m_rect
.width
, tab_height
);
831 m_tabs
->SetRect(wxRect(0, 0, m_rect
.width
, tab_height
));
835 wxAuiNotebookPageArray
& pages
= m_tabs
->GetPages();
836 size_t i
, page_count
= pages
.GetCount();
838 for (i
= 0; i
< page_count
; ++i
)
840 wxAuiNotebookPage
& page
= pages
.Item(i
);
841 page
.window
->SetSize(m_rect
.x
, m_rect
.y
+tab_height
, m_rect
.width
, m_rect
.height
-tab_height
);
843 if (page
.window
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
845 wxTabMDIChildFrame
* wnd
= (wxTabMDIChildFrame
*)page
.window
;
846 wnd
->ApplyMDIChildFrameRect();
851 void DoGetSize(int* x
, int* y
) const
854 *x
= m_rect
.GetWidth();
856 *y
= m_rect
.GetHeight();
868 wxAuiTabCtrl
* m_tabs
;
869 int m_tab_ctrl_height
;
876 // -- wxAuiMultiNotebook class implementation --
878 BEGIN_EVENT_TABLE(wxAuiMultiNotebook
, wxControl
)
879 //EVT_ERASE_BACKGROUND(wxAuiMultiNotebook::OnEraseBackground)
880 //EVT_SIZE(wxAuiMultiNotebook::OnSize)
881 //EVT_LEFT_DOWN(wxAuiMultiNotebook::OnLeftDown)
882 EVT_CHILD_FOCUS(wxAuiMultiNotebook::OnChildFocus
)
883 EVT_COMMAND_RANGE(10000, 10100,
884 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
,
885 wxAuiMultiNotebook::OnTabClicked
)
886 EVT_COMMAND_RANGE(10000, 10100,
887 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
,
888 wxAuiMultiNotebook::OnTabBeginDrag
)
889 EVT_COMMAND_RANGE(10000, 10100,
890 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
,
891 wxAuiMultiNotebook::OnTabEndDrag
)
892 EVT_COMMAND_RANGE(10000, 10100,
893 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
,
894 wxAuiMultiNotebook::OnTabDragMotion
)
895 EVT_COMMAND_RANGE(10000, 10100,
896 wxEVT_COMMAND_AUINOTEBOOK_BUTTON
,
897 wxAuiMultiNotebook::OnTabButton
)
900 wxAuiMultiNotebook::wxAuiMultiNotebook()
903 m_tab_id_counter
= 10000;
905 m_tab_ctrl_height
= 20;
908 wxAuiMultiNotebook::wxAuiMultiNotebook(wxWindow
*parent
,
912 long style
) : wxControl(parent
, id
, pos
, size
, style
)
917 bool wxAuiMultiNotebook::Create(wxWindow
* parent
,
923 if (!wxControl::Create(parent
, id
, pos
, size
, style
))
931 // InitNotebook() contains common initialization
932 // code called by all constructors
933 void wxAuiMultiNotebook::InitNotebook()
936 m_tab_id_counter
= 10000;
938 m_tab_ctrl_height
= 20;
940 m_normal_font
= *wxNORMAL_FONT
;
941 m_selected_font
= *wxNORMAL_FONT
;
942 m_selected_font
.SetWeight(wxBOLD
);
944 // choose a default for the tab height
947 dc
.SetFont(m_selected_font
);
948 dc
.GetTextExtent(wxT("ABCDEFGHhijklm"), &tx
, &ty
);
949 m_tab_ctrl_height
= (ty
*150)/100;
951 m_dummy_wnd
= new wxWindow(this, wxID_ANY
, wxPoint(0,0), wxSize(0,0));
952 m_dummy_wnd
->SetSize(200, 200);
953 m_dummy_wnd
->Show(false);
955 m_mgr
.SetManagedWindow(this);
957 m_mgr
.AddPane(m_dummy_wnd
,
958 wxPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
963 wxAuiMultiNotebook::~wxAuiMultiNotebook()
968 bool wxAuiMultiNotebook::AddPage(wxWindow
* page
,
969 const wxString
& caption
,
971 const wxBitmap
& bitmap
)
973 return InsertPage(GetPageCount(), page
, caption
, select
, bitmap
);
976 bool wxAuiMultiNotebook::InsertPage(size_t page_idx
,
978 const wxString
& caption
,
980 const wxBitmap
& bitmap
)
982 wxAuiNotebookPage info
;
984 info
.caption
= caption
;
985 info
.bitmap
= bitmap
;
988 // if there are currently no tabs, the first added
989 // tab must be active
990 if (m_tabs
.GetPageCount() == 0)
993 m_tabs
.InsertPage(page
, info
, page_idx
);
995 wxAuiTabCtrl
* active_tabctrl
= GetActiveTabCtrl();
996 if (page_idx
>= active_tabctrl
->GetPageCount())
997 active_tabctrl
->AddPage(page
, info
);
999 active_tabctrl
->InsertPage(page
, info
, page_idx
);
1002 active_tabctrl
->DoShowHide();
1006 int idx
= m_tabs
.GetIdxFromWindow(page
);
1007 wxASSERT_MSG(idx
!= -1, wxT("Invalid Page index returned on wxAuiMultiNotebook::InsertPage()"));
1016 // DeletePage() removes a tab from the multi-notebook,
1017 // and destroys the window as well
1018 bool wxAuiMultiNotebook::DeletePage(size_t page_idx
)
1020 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1023 // find out which onscreen tab ctrl owns this tab
1026 if (!FindTab(wnd
, &ctrl
, &ctrl_idx
))
1029 // find a new page and set it as active
1030 int new_idx
= ctrl_idx
+1;
1031 if (new_idx
>= (int)ctrl
->GetPageCount())
1032 new_idx
= ctrl_idx
-1;
1034 if (new_idx
>= 0 && new_idx
< (int)ctrl
->GetPageCount())
1036 wxWindow
* new_wnd
= ctrl
->GetWindowFromIdx(new_idx
);
1037 int main_idx
= m_tabs
.GetIdxFromWindow(new_wnd
);
1038 wxASSERT(main_idx
!= -1);
1039 SetSelection(main_idx
);
1043 // set the active page to the first page that
1044 // isn't the one being deleted
1046 size_t i
, page_count
= m_tabs
.GetPageCount();
1047 for (i
= 0; i
< page_count
; ++i
)
1049 wxWindow
* w
= m_tabs
.GetWindowFromIdx(i
);
1063 // remove the tab from main catalog
1064 if (!m_tabs
.RemovePage(wnd
))
1067 // remove the tab from the onscreen tab ctrl
1068 ctrl
->RemovePage(wnd
);
1070 // actually destroy the window now
1071 if (wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1073 // delete the child frame with pending delete, as is
1074 // customary with frame windows
1075 if (!wxPendingDelete
.Member(wnd
))
1076 wxPendingDelete
.Append(wnd
);
1083 RemoveEmptyTabFrames();
1090 // RemovePage() removes a tab from the multi-notebook,
1091 // but does not destroy the window
1092 bool wxAuiMultiNotebook::RemovePage(size_t page_idx
)
1094 // remove the tab from our own catalog
1095 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
1096 if (!m_tabs
.RemovePage(wnd
))
1099 // remove the tab from the onscreen tab ctrl
1102 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1104 ctrl
->RemovePage(wnd
);
1111 // SetPageText() changes the tab caption of the specified page
1112 bool wxAuiMultiNotebook::SetPageText(size_t page_idx
, const wxString
& text
)
1114 if (page_idx
>= m_tabs
.GetPageCount())
1117 // update our own tab catalog
1118 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
1119 page_info
.caption
= text
;
1121 // update what's on screen
1124 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
1126 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
1127 info
.caption
= text
;
1135 // GetSelection() returns the index of the currently active page
1136 int wxAuiMultiNotebook::GetSelection() const
1141 // SetSelection() sets the currently active page
1142 size_t wxAuiMultiNotebook::SetSelection(size_t new_page
)
1144 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(new_page
);
1148 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
1149 evt
.SetSelection(new_page
);
1150 evt
.SetOldSelection(m_curpage
);
1151 evt
.SetEventObject(this);
1152 if (!GetEventHandler()->ProcessEvent(evt
) || evt
.IsAllowed())
1154 // program allows the page change
1155 evt
.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
);
1156 (void)GetEventHandler()->ProcessEvent(evt
);
1162 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
1164 m_tabs
.SetActivePage(wnd
);
1166 ctrl
->SetActivePage(ctrl_idx
);
1170 int old_curpage
= m_curpage
;
1171 m_curpage
= new_page
;
1175 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1176 size_t i
, pane_count
= all_panes
.GetCount();
1177 for (i
= 0; i
< pane_count
; ++i
)
1179 wxPaneInfo
& pane
= all_panes
.Item(i
);
1180 if (pane
.name
== wxT("dummy"))
1182 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
1183 if (tabctrl
!= ctrl
)
1184 tabctrl
->SetSelectedFont(m_normal_font
);
1186 tabctrl
->SetSelectedFont(m_selected_font
);
1199 // GetPageCount() returns the total number of
1200 // pages managed by the multi-notebook
1201 size_t wxAuiMultiNotebook::GetPageCount() const
1203 return m_tabs
.GetPageCount();
1206 // GetPage() returns the wxWindow pointer of the
1208 wxWindow
* wxAuiMultiNotebook::GetPage(size_t page_idx
) const
1210 wxASSERT(page_idx
< m_tabs
.GetPageCount());
1212 return m_tabs
.GetWindowFromIdx(page_idx
);
1215 // DoSizing() performs all sizing operations in each tab control
1216 void wxAuiMultiNotebook::DoSizing()
1218 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1219 size_t i
, pane_count
= all_panes
.GetCount();
1220 for (i
= 0; i
< pane_count
; ++i
)
1222 if (all_panes
.Item(i
).name
== wxT("dummy"))
1225 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1226 tabframe
->DoSizing();
1230 // GetActiveTabCtrl() returns the active tab control. It is
1231 // called to determine which control gets new windows being added
1232 wxAuiTabCtrl
* wxAuiMultiNotebook::GetActiveTabCtrl()
1234 if (m_curpage
>= 0 && m_curpage
< (int)m_tabs
.GetPageCount())
1239 // find the tab ctrl with the current page
1240 if (FindTab(m_tabs
.GetPage(m_curpage
).window
,
1247 // no current page, just find the first tab ctrl
1248 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1249 size_t i
, pane_count
= all_panes
.GetCount();
1250 for (i
= 0; i
< pane_count
; ++i
)
1252 if (all_panes
.Item(i
).name
== wxT("dummy"))
1255 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1256 return tabframe
->m_tabs
;
1259 // If there is no tabframe at all, create one
1260 wxTabFrame
* tabframe
= new wxTabFrame
;
1261 tabframe
->SetTabCtrlHeight(m_tab_ctrl_height
);
1262 tabframe
->m_tabs
= new wxAuiTabCtrl(this,
1267 m_mgr
.AddPane(tabframe
,
1268 wxPaneInfo().Center().CaptionVisible(false));
1272 return tabframe
->m_tabs
;
1275 // FindTab() finds the tab control that currently contains the window as well
1276 // as the index of the window in the tab control. It returns true if the
1277 // window was found, otherwise false.
1278 bool wxAuiMultiNotebook::FindTab(wxWindow
* page
, wxAuiTabCtrl
** ctrl
, int* idx
)
1280 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1281 size_t i
, pane_count
= all_panes
.GetCount();
1282 for (i
= 0; i
< pane_count
; ++i
)
1284 if (all_panes
.Item(i
).name
== wxT("dummy"))
1287 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1289 int page_idx
= tabframe
->m_tabs
->GetIdxFromWindow(page
);
1292 *ctrl
= tabframe
->m_tabs
;
1302 void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent
&)
1306 void wxAuiMultiNotebook::OnSize(wxSizeEvent
&)
1310 void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent
& command_evt
)
1312 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1314 wxAuiTabCtrl
* ctrl
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1315 wxASSERT(ctrl
!= NULL
);
1317 wxWindow
* wnd
= ctrl
->GetWindowFromIdx(evt
.GetSelection());
1318 wxASSERT(wnd
!= NULL
);
1320 int idx
= m_tabs
.GetIdxFromWindow(wnd
);
1321 wxASSERT(idx
!= -1);
1326 void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent
&)
1330 void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent
& evt
)
1332 wxPoint screen_pt
= ::wxGetMousePosition();
1333 wxPoint client_pt
= ScreenToClient(screen_pt
);
1336 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1338 wxAuiTabCtrl
* tab_ctrl
= GetTabCtrlFromPoint(client_pt
);
1339 if (tab_ctrl
== src_tabs
)
1341 // inner-tabctrl dragging is not yet implemented
1348 wxRect hint_rect
= tab_ctrl
->GetRect();
1349 ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
1350 m_mgr
.ShowHint(hint_rect
);
1354 m_mgr
.DrawHintRect(m_dummy_wnd
, client_pt
, zero
);
1360 void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent
& command_evt
)
1362 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1367 // get the mouse position, which will be used to determine the drop point
1368 wxPoint mouse_screen_pt
= ::wxGetMousePosition();
1369 wxPoint mouse_client_pt
= ScreenToClient(mouse_screen_pt
);
1372 // the src tab control is the control that fired this event
1373 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1374 wxAuiTabCtrl
* dest_tabs
= NULL
;
1377 // If the pointer is in an existing tab frame, do a tab insert
1378 wxWindow
* hit_wnd
= ::wxFindWindowAtPoint(mouse_screen_pt
);
1379 wxTabFrame
* tab_frame
= (wxTabFrame
*)GetTabFrameFromTabCtrl(hit_wnd
);
1382 dest_tabs
= tab_frame
->m_tabs
;
1384 if (dest_tabs
== src_tabs
)
1389 // If there is no tabframe at all, create one
1390 wxTabFrame
* new_tabs
= new wxTabFrame
;
1391 new_tabs
->SetTabCtrlHeight(m_tab_ctrl_height
);
1392 new_tabs
->m_tabs
= new wxAuiTabCtrl(this,
1397 m_mgr
.AddPane(new_tabs
,
1398 wxPaneInfo().Bottom().CaptionVisible(false),
1401 dest_tabs
= new_tabs
->m_tabs
;
1406 // remove the page from the source tabs
1407 wxAuiNotebookPage page_info
= src_tabs
->GetPage(evt
.GetSelection());
1408 page_info
.active
= false;
1409 src_tabs
->RemovePage(page_info
.window
);
1410 if (src_tabs
->GetPageCount() > 0)
1412 src_tabs
->SetActivePage((size_t)0);
1413 src_tabs
->DoShowHide();
1414 src_tabs
->Refresh();
1419 // add the page to the destination tabs
1420 dest_tabs
->AddPage(page_info
.window
, page_info
);
1422 if (src_tabs
->GetPageCount() == 0)
1424 RemoveEmptyTabFrames();
1428 dest_tabs
->DoShowHide();
1429 dest_tabs
->Refresh();
1431 SetSelection(m_tabs
.GetIdxFromWindow(page_info
.window
));
1434 wxAuiTabCtrl
* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint
& pt
)
1436 // if we've just removed the last tab from the source
1437 // tab set, the remove the tab control completely
1438 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1439 size_t i
, pane_count
= all_panes
.GetCount();
1440 for (i
= 0; i
< pane_count
; ++i
)
1442 if (all_panes
.Item(i
).name
== wxT("dummy"))
1445 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1446 if (tabframe
->m_tab_rect
.Inside(pt
))
1447 return tabframe
->m_tabs
;
1453 wxWindow
* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow
* tab_ctrl
)
1455 // if we've just removed the last tab from the source
1456 // tab set, the remove the tab control completely
1457 wxPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
1458 size_t i
, pane_count
= all_panes
.GetCount();
1459 for (i
= 0; i
< pane_count
; ++i
)
1461 if (all_panes
.Item(i
).name
== wxT("dummy"))
1464 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1465 if (tabframe
->m_tabs
== tab_ctrl
)
1474 void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1476 bool must_update
= false;
1478 // if we've just removed the last tab from the source
1479 // tab set, the remove the tab control completely
1480 wxPaneInfoArray all_panes
= m_mgr
.GetAllPanes();
1481 size_t i
, pane_count
= all_panes
.GetCount();
1482 for (i
= 0; i
< pane_count
; ++i
)
1484 if (all_panes
.Item(i
).name
== wxT("dummy"))
1487 wxTabFrame
* tab_frame
= (wxTabFrame
*)all_panes
.Item(i
).window
;
1488 if (tab_frame
->m_tabs
->GetPageCount() == 0)
1490 m_mgr
.DetachPane(tab_frame
);
1492 // use pending delete because sometimes during
1493 // window closing, refreshs are pending
1494 if (!wxPendingDelete
.Member(tab_frame
->m_tabs
))
1495 wxPendingDelete
.Append(tab_frame
->m_tabs
);
1496 //tab_frame->m_tabs->Destroy();
1504 // check to see if there is still a center pane;
1505 // if there isn't, make a frame the center pane
1506 wxPaneInfoArray panes
= m_mgr
.GetAllPanes();
1507 pane_count
= panes
.GetCount();
1508 wxWindow
* first_good
= NULL
;
1509 bool center_found
= false;
1510 for (i
= 0; i
< pane_count
; ++i
)
1512 if (panes
.Item(i
).name
== wxT("dummy"))
1514 if (panes
.Item(i
).dock_direction
== wxAUI_DOCK_CENTRE
)
1515 center_found
= true;
1517 first_good
= panes
.Item(i
).window
;
1520 if (!center_found
&& first_good
)
1522 m_mgr
.GetPane(first_good
).Centre();
1529 void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent
& evt
)
1531 int idx
= m_tabs
.GetIdxFromWindow(evt
.GetWindow());
1532 if (idx
!= -1 && idx
!= m_curpage
)
1539 void wxAuiMultiNotebook::OnTabButton(wxCommandEvent
& command_evt
)
1541 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
1542 wxAuiTabCtrl
* tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
1544 int button_id
= evt
.GetInt();
1546 if (button_id
== wxAuiButtonClose
)
1548 int selection
= tabs
->GetActivePage();
1550 if (selection
!= -1)
1552 wxWindow
* close_wnd
= tabs
->GetWindowFromIdx(selection
);
1554 if (close_wnd
->IsKindOf(CLASSINFO(wxTabMDIChildFrame
)))
1560 int main_idx
= m_tabs
.GetIdxFromWindow(close_wnd
);
1561 DeletePage(main_idx
);