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"
34 #include "wx/arrimpl.cpp"
35 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray
)
36 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray
)
38 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE
)
39 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
)
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
)
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
)
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
)
43 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
)
44 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
)
45 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND
)
48 IMPLEMENT_CLASS(wxAuiNotebook
, wxControl
)
49 IMPLEMENT_CLASS(wxAuiTabCtrl
, wxControl
)
50 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent
, wxEvent
)
56 // This functions are here for this proof of concept
57 // and will be factored out later. See dockart.cpp
58 static wxColor
StepColour(const wxColor
& c
, int percent
)
60 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
61 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
62 (unsigned char)wxMin((g
*percent
)/100,255),
63 (unsigned char)wxMin((b
*percent
)/100,255));
66 // This functions are here for this proof of concept
67 // and will be factored out later. See dockart.cpp
68 static wxBitmap
BitmapFromBits(const unsigned char bits
[], int w
, int h
,
69 const wxColour
& color
)
71 wxImage img
= wxBitmap((const char*)bits
, w
, h
).ConvertToImage();
72 img
.Replace(0,0,0,123,123,123);
73 img
.Replace(255,255,255,color
.Red(),color
.Green(),color
.Blue());
74 img
.SetMaskColour(123,123,123);
78 static void DrawButtons(wxDC
& dc
,
81 const wxColour
& bkcolour
,
86 if (button_state
== wxAUI_BUTTON_STATE_PRESSED
)
92 if (button_state
== wxAUI_BUTTON_STATE_HOVER
||
93 button_state
== wxAUI_BUTTON_STATE_PRESSED
)
95 dc
.SetBrush(wxBrush(StepColour(bkcolour
, 120)));
96 dc
.SetPen(wxPen(StepColour(bkcolour
, 70)));
98 // draw the background behind the button
99 dc
.DrawRectangle(rect
.x
, rect
.y
, 15, 15);
102 // draw the button itself
103 dc
.DrawBitmap(bmp
, rect
.x
, rect
.y
, true);
106 static void IndentPressedBitmap(wxRect
* rect
, int button_state
)
108 if (button_state
== wxAUI_BUTTON_STATE_PRESSED
)
115 // chops the text so that it fits within |max_size| pixels.
116 // Also adds an elipsis if necessary
118 static wxString
ChopText(wxDC
& dc
, const wxString
& text
, int max_size
)
122 // first check if the text fits with no problems
123 dc
.GetTextExtent(text
, &x
, &y
);
127 size_t i
, len
= text
.Length();
128 size_t last_good_length
= 0;
129 for (i
= 0; i
< len
; ++i
)
131 wxString s
= text
.Left(i
);
134 dc
.GetTextExtent(s
, &x
, &y
);
138 last_good_length
= i
;
141 wxString ret
= text
.Left(last_good_length
);
147 // -- GUI helper classes and functions --
149 class wxAuiCommandCapture
: public wxEvtHandler
153 wxAuiCommandCapture() { m_last_id
= 0; }
154 int GetCommandId() const { return m_last_id
; }
156 bool ProcessEvent(wxEvent
& evt
)
158 if (evt
.GetEventType() == wxEVT_COMMAND_MENU_SELECTED
)
160 m_last_id
= evt
.GetId();
164 if (GetNextHandler())
165 return GetNextHandler()->ProcessEvent(evt
);
177 #if defined( __WXMAC__ )
178 static unsigned char close_bits
[]={
179 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
180 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
181 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
182 #elif defined( __WXGTK__)
183 static unsigned char close_bits
[]={
184 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
185 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
186 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
188 static unsigned char close_bits
[]={
189 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
190 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
191 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
194 static unsigned char left_bits
[] = {
195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
196 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
197 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
199 static unsigned char right_bits
[] = {
200 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
201 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
202 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
204 static unsigned char list_bits
[] = {
205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
206 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
214 // -- wxAuiDefaultTabArt class implementation --
216 wxAuiDefaultTabArt::wxAuiDefaultTabArt()
218 m_normal_font
= *wxNORMAL_FONT
;
219 m_selected_font
= *wxNORMAL_FONT
;
220 m_selected_font
.SetWeight(wxBOLD
);
221 m_measuring_font
= m_selected_font
;
223 m_fixed_tab_width
= 100;
224 m_tab_ctrl_height
= 0;
226 m_base_colour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
227 m_base_colour_pen
= wxPen(m_base_colour
);
228 m_base_colour_brush
= wxBrush(m_base_colour
);
230 m_active_close_bmp
= BitmapFromBits(close_bits
, 16, 16, *wxBLACK
);
231 m_disabled_close_bmp
= BitmapFromBits(close_bits
, 16, 16, wxColour(128,128,128));
233 m_active_left_bmp
= BitmapFromBits(left_bits
, 16, 16, *wxBLACK
);
234 m_disabled_left_bmp
= BitmapFromBits(left_bits
, 16, 16, wxColour(128,128,128));
236 m_active_right_bmp
= BitmapFromBits(right_bits
, 16, 16, *wxBLACK
);
237 m_disabled_right_bmp
= BitmapFromBits(right_bits
, 16, 16, wxColour(128,128,128));
239 m_active_windowlist_bmp
= BitmapFromBits(list_bits
, 16, 16, *wxBLACK
);
240 m_disabled_windowlist_bmp
= BitmapFromBits(list_bits
, 16, 16, wxColour(128,128,128));
245 wxAuiDefaultTabArt::~wxAuiDefaultTabArt()
249 wxAuiTabArt
* wxAuiDefaultTabArt::Clone()
251 return static_cast<wxAuiTabArt
*>(new wxAuiDefaultTabArt
);
254 void wxAuiDefaultTabArt::SetFlags(unsigned int flags
)
259 void wxAuiDefaultTabArt::SetSizingInfo(const wxSize
& tab_ctrl_size
,
262 m_fixed_tab_width
= 100;
264 int tot_width
= (int)tab_ctrl_size
.x
- GetIndentSize() - 4;
267 m_fixed_tab_width
= tot_width
/(int)tab_count
;
271 if (m_fixed_tab_width
< 100)
272 m_fixed_tab_width
= 100;
274 if (m_fixed_tab_width
> tot_width
/2)
275 m_fixed_tab_width
= tot_width
/2;
277 if (m_fixed_tab_width
> 220)
278 m_fixed_tab_width
= 220;
280 m_tab_ctrl_height
= tab_ctrl_size
.y
;
284 void wxAuiDefaultTabArt::DrawBackground(wxDC
& dc
,
285 wxWindow
* WXUNUSED(wnd
),
289 wxRect
r(rect
.x
, rect
.y
, rect
.width
+2, rect
.height
-2);
290 //wxColor start_colour = m_base_colour;
291 //wxColor end_colour = StepColour(start_colour, 110);
292 wxColor start_colour
= StepColour(m_base_colour
, 90);
293 wxColor end_colour
= StepColour(m_base_colour
, 110);
294 dc
.GradientFillLinear(r
, start_colour
, end_colour
, wxSOUTH
);
297 dc
.SetPen(*wxGREY_PEN
);
298 dc
.DrawLine(0, rect
.GetHeight()-4, rect
.GetWidth(), rect
.GetHeight()-4);
299 dc
.DrawLine(0, rect
.GetHeight()-1, rect
.GetWidth(), rect
.GetHeight()-1);
300 dc
.SetPen(wxPen(start_colour
));
301 dc
.DrawLine(0, rect
.GetHeight()-3, rect
.GetWidth(), rect
.GetHeight()-3);
302 dc
.DrawLine(0, rect
.GetHeight()-2, rect
.GetWidth(), rect
.GetHeight()-2);
306 // DrawTab() draws an individual tab.
309 // in_rect - rectangle the tab should be confined to
310 // caption - tab's caption
311 // active - whether or not the tab is active
312 // out_rect - actual output rectangle
313 // x_extent - the advance x; where the next tab should start
315 void wxAuiDefaultTabArt::DrawTab(wxDC
& dc
,
317 const wxRect
& in_rect
,
318 const wxString
& caption_text
,
319 const wxBitmap
& bitmap
,
321 int close_button_state
,
322 wxRect
* out_tab_rect
,
323 wxRect
* out_button_rect
,
326 wxCoord normal_textx
, normal_texty
;
327 wxCoord selected_textx
, selected_texty
;
328 wxCoord textx
, texty
;
330 // if the caption is empty, measure some temporary text
331 wxString caption
= caption_text
;
332 if (caption_text
.empty())
335 dc
.SetFont(m_selected_font
);
336 dc
.GetTextExtent(caption
, &selected_textx
, &selected_texty
);
338 dc
.SetFont(m_normal_font
);
339 dc
.GetTextExtent(caption
, &normal_textx
, &normal_texty
);
341 // figure out the size of the tab
342 wxSize tab_size
= GetTabSize(dc
,
350 wxCoord tab_height
= m_tab_ctrl_height
- 3;
351 wxCoord tab_width
= tab_size
.x
;
352 wxCoord tab_x
= in_rect
.x
;
353 wxCoord tab_y
= in_rect
.y
+ in_rect
.height
- tab_height
;
356 caption
= caption_text
;
358 dc
.SetClippingRegion(in_rect
);
362 // select pen, brush and font for the tab to be drawn
366 dc
.SetFont(m_selected_font
);
367 textx
= selected_textx
;
368 texty
= selected_texty
;
372 dc
.SetFont(m_normal_font
);
373 textx
= normal_textx
;
374 texty
= normal_texty
;
378 // create points that will make the tab outline
382 points
[0].y
= tab_y
+ tab_height
- 4;
384 points
[1].y
= tab_y
+ 2;
385 points
[2].x
= tab_x
+ 2;
387 points
[3].x
= tab_x
+ tab_width
- 2;
389 points
[4].x
= tab_x
+ tab_width
;
390 points
[4].y
= tab_y
+ 2;
391 points
[5].x
= tab_x
+ tab_width
;
392 points
[5].y
= tab_y
+ tab_height
- 4;
394 int drawn_tab_yoff
= points
[1].y
;
395 int drawn_tab_height
= points
[0].y
- points
[1].y
;
401 // move rectangle in a bit so that the inside border has
403 wxRect
r(tab_x
, tab_y
+1, tab_width
, tab_height
-3);
407 // draw base background color
408 dc
.SetPen(*wxWHITE_PEN
);
409 dc
.SetBrush(*wxWHITE_BRUSH
);
410 dc
.DrawRectangle(r
.x
, r
.y
, r
.width
-1, r
.height
-1);
412 // set rectangle down a bit for gradient drawing
413 r
.SetHeight(r
.GetHeight()/2);
416 // draw gradient background
417 wxColor start_color
= m_base_colour
;
418 wxColor end_color
= *wxWHITE
;
419 dc
.GradientFillLinear(r
, start_color
, end_color
, wxNORTH
);
424 wxRect
r(tab_x
, tab_y
+1, tab_width
, tab_height
-3);
426 // draw base background color for inactive tabs
427 dc
.SetPen(m_base_colour_pen
);
428 dc
.SetBrush(m_base_colour_brush
);
429 dc
.DrawRectangle(r
.x
, r
.y
, r
.width
-1, r
.height
-1);
431 // start the gradent up a bit and leave the inside border inset
432 // by a pixel for a 3D look. Only the top half of the inactive
433 // tab will have a slight gradient
438 // -- draw bottom gradient fill for glossy look
439 wxColor top_color
= m_base_colour
;
440 wxColor bottom_color
= StepColour(top_color
, 106);
441 dc
.GradientFillLinear(r
, bottom_color
, top_color
, wxNORTH
);
445 dc
.SetPen(*wxGREY_PEN
);
446 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
447 dc
.DrawPolygon(6, points
);
449 // there are two horizontal grey lines at the bottom of the tab control,
450 // this gets rid of the top one of those lines in the tab control
453 dc
.SetPen(m_base_colour_pen
);
454 dc
.DrawLine(points
[0].x
, points
[0].y
, points
[5].x
+1, points
[5].y
);
458 int text_offset
= tab_x
+ 8;
459 int close_button_width
= 0;
460 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
462 close_button_width
= m_active_close_bmp
.GetWidth();
468 int bitmap_offset
= tab_x
+ 8;
471 dc
.DrawBitmap(bitmap
,
473 drawn_tab_yoff
+ (drawn_tab_height
/2) - (bitmap
.GetHeight()/2) + 1,
476 text_offset
= bitmap_offset
+ bitmap
.GetWidth();
477 text_offset
+= 3; // bitmap padding
481 text_offset
= tab_x
+ 8;
485 wxString draw_text
= ChopText(dc
,
487 tab_width
- (text_offset
-tab_x
) - close_button_width
);
490 dc
.DrawText(draw_text
,
492 drawn_tab_yoff
+ (drawn_tab_height
)/2 - (texty
/2) - 1);
497 // draw close button if necessary
498 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
500 wxBitmap bmp
= m_disabled_close_bmp
;
502 if (close_button_state
== wxAUI_BUTTON_STATE_HOVER
||
503 close_button_state
== wxAUI_BUTTON_STATE_PRESSED
)
505 bmp
= m_active_close_bmp
;
508 wxRect
rect(tab_x
+ tab_width
- close_button_width
- 1,
509 tab_y
+ (tab_height
/2) - (bmp
.GetHeight()/2),
512 IndentPressedBitmap(&rect
, close_button_state
);
513 dc
.DrawBitmap(bmp
, rect
.x
, rect
.y
, true);
515 *out_button_rect
= rect
;
518 *out_tab_rect
= wxRect(tab_x
, tab_y
, tab_width
, tab_height
);
520 dc
.DestroyClippingRegion();
523 int wxAuiDefaultTabArt::GetIndentSize()
528 wxSize
wxAuiDefaultTabArt::GetTabSize(wxDC
& dc
,
529 wxWindow
* WXUNUSED(wnd
),
530 const wxString
& caption
,
531 const wxBitmap
& bitmap
,
532 bool WXUNUSED(active
),
533 int close_button_state
,
536 wxCoord measured_textx
, measured_texty
, tmp
;
538 dc
.SetFont(m_measuring_font
);
539 dc
.GetTextExtent(caption
, &measured_textx
, &measured_texty
);
541 dc
.GetTextExtent(wxT("ABCDEFXj"), &tmp
, &measured_texty
);
543 // add padding around the text
544 wxCoord tab_width
= measured_textx
;
545 wxCoord tab_height
= measured_texty
;
547 // if the close button is showing, add space for it
548 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
549 tab_width
+= m_active_close_bmp
.GetWidth() + 3;
551 // if there's a bitmap, add space for it
554 tab_width
+= bitmap
.GetWidth();
555 tab_width
+= 3; // right side bitmap padding
556 tab_height
= wxMax(tab_height
, bitmap
.GetHeight());
563 if (m_flags
& wxAUI_NB_TAB_FIXED_WIDTH
)
565 tab_width
= m_fixed_tab_width
;
568 *x_extent
= tab_width
;
570 return wxSize(tab_width
, tab_height
);
574 void wxAuiDefaultTabArt::DrawButton(wxDC
& dc
,
575 wxWindow
* WXUNUSED(wnd
),
576 const wxRect
& in_rect
,
580 const wxBitmap
& bitmap_override
,
586 if (bitmap_override
.IsOk())
588 bmp
= bitmap_override
;
594 case wxAUI_BUTTON_CLOSE
:
595 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
596 bmp
= m_disabled_close_bmp
;
598 bmp
= m_active_close_bmp
;
600 case wxAUI_BUTTON_LEFT
:
601 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
602 bmp
= m_disabled_left_bmp
;
604 bmp
= m_active_left_bmp
;
606 case wxAUI_BUTTON_RIGHT
:
607 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
608 bmp
= m_disabled_right_bmp
;
610 bmp
= m_active_right_bmp
;
612 case wxAUI_BUTTON_WINDOWLIST
:
613 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
614 bmp
= m_disabled_windowlist_bmp
;
616 bmp
= m_active_windowlist_bmp
;
626 if (orientation
== wxLEFT
)
628 rect
.SetX(in_rect
.x
);
629 rect
.SetY(((in_rect
.y
+ in_rect
.height
)/2) - (bmp
.GetHeight()/2));
630 rect
.SetWidth(bmp
.GetWidth());
631 rect
.SetHeight(bmp
.GetHeight());
635 rect
= wxRect(in_rect
.x
+ in_rect
.width
- bmp
.GetWidth(),
636 ((in_rect
.y
+ in_rect
.height
)/2) - (bmp
.GetHeight()/2),
637 bmp
.GetWidth(), bmp
.GetHeight());
640 IndentPressedBitmap(&rect
, button_state
);
641 dc
.DrawBitmap(bmp
, rect
.x
, rect
.y
, true);
647 int wxAuiDefaultTabArt::ShowWindowList(wxWindow
* wnd
,
648 const wxArrayString
& items
,
653 size_t i
, count
= items
.GetCount();
654 for (i
= 0; i
< count
; ++i
)
656 menuPopup
.AppendCheckItem(1000+i
, items
.Item(i
));
659 if (active_idx
!= -1)
661 menuPopup
.Check(1000+active_idx
, true);
664 // find out where to put the popup menu of window
665 // items. Subtract 100 for now to center the menu
666 // a bit, until a better mechanism can be implemented
667 wxPoint pt
= ::wxGetMousePosition();
668 pt
= wnd
->ScreenToClient(pt
);
674 // find out the screen coordinate at the bottom of the tab ctrl
675 wxRect cli_rect
= wnd
->GetClientRect();
676 pt
.y
= cli_rect
.y
+ cli_rect
.height
;
678 wxAuiCommandCapture
* cc
= new wxAuiCommandCapture
;
679 wnd
->PushEventHandler(cc
);
680 wnd
->PopupMenu(&menuPopup
, pt
);
681 int command
= cc
->GetCommandId();
682 wnd
->PopEventHandler(true);
690 int wxAuiDefaultTabArt::GetBestTabCtrlSize(wxWindow
* wnd
,
691 wxAuiNotebookPageArray
& pages
)
694 dc
.SetFont(m_measuring_font
);
697 size_t i
, page_count
= pages
.GetCount();
698 for (i
= 0; i
< page_count
; ++i
)
700 wxAuiNotebookPage
& page
= pages
.Item(i
);
702 // we don't use the caption text because we don't
703 // want tab heights to be different in the case
704 // of a very short piece of text on one tab and a very
705 // tall piece of text on another tab
707 wxSize s
= GetTabSize(dc
,
712 wxAUI_BUTTON_STATE_HIDDEN
,
714 max_y
= wxMax(max_y
, s
.y
);
720 void wxAuiDefaultTabArt::SetNormalFont(const wxFont
& font
)
722 m_normal_font
= font
;
725 void wxAuiDefaultTabArt::SetSelectedFont(const wxFont
& font
)
727 m_selected_font
= font
;
730 void wxAuiDefaultTabArt::SetMeasuringFont(const wxFont
& font
)
732 m_measuring_font
= font
;
736 // -- wxAuiSimpleTabArt class implementation --
738 wxAuiSimpleTabArt::wxAuiSimpleTabArt()
740 m_normal_font
= *wxNORMAL_FONT
;
741 m_selected_font
= *wxNORMAL_FONT
;
742 m_selected_font
.SetWeight(wxBOLD
);
743 m_measuring_font
= m_selected_font
;
746 m_fixed_tab_width
= 100;
748 wxColour base_colour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
750 wxColour background_colour
= StepColour(base_colour
, 95);
751 wxColour normaltab_colour
= base_colour
;
752 wxColour selectedtab_colour
= *wxWHITE
;
754 m_bkbrush
= wxBrush(background_colour
);
755 m_normal_bkbrush
= wxBrush(normaltab_colour
);
756 m_normal_bkpen
= wxPen(normaltab_colour
);
757 m_selected_bkbrush
= wxBrush(selectedtab_colour
);
758 m_selected_bkpen
= wxPen(selectedtab_colour
);
760 m_active_close_bmp
= BitmapFromBits(close_bits
, 16, 16, *wxBLACK
);
761 m_disabled_close_bmp
= BitmapFromBits(close_bits
, 16, 16, wxColour(128,128,128));
763 m_active_left_bmp
= BitmapFromBits(left_bits
, 16, 16, *wxBLACK
);
764 m_disabled_left_bmp
= BitmapFromBits(left_bits
, 16, 16, wxColour(128,128,128));
766 m_active_right_bmp
= BitmapFromBits(right_bits
, 16, 16, *wxBLACK
);
767 m_disabled_right_bmp
= BitmapFromBits(right_bits
, 16, 16, wxColour(128,128,128));
769 m_active_windowlist_bmp
= BitmapFromBits(list_bits
, 16, 16, *wxBLACK
);
770 m_disabled_windowlist_bmp
= BitmapFromBits(list_bits
, 16, 16, wxColour(128,128,128));
774 wxAuiSimpleTabArt::~wxAuiSimpleTabArt()
778 wxAuiTabArt
* wxAuiSimpleTabArt::Clone()
780 return static_cast<wxAuiTabArt
*>(new wxAuiSimpleTabArt
);
784 void wxAuiSimpleTabArt::SetFlags(unsigned int flags
)
789 void wxAuiSimpleTabArt::SetSizingInfo(const wxSize
& tab_ctrl_size
,
792 m_fixed_tab_width
= 100;
794 int tot_width
= (int)tab_ctrl_size
.x
- GetIndentSize() - 4;
797 m_fixed_tab_width
= tot_width
/(int)tab_count
;
801 if (m_fixed_tab_width
< 100)
802 m_fixed_tab_width
= 100;
804 if (m_fixed_tab_width
> tot_width
/2)
805 m_fixed_tab_width
= tot_width
/2;
807 if (m_fixed_tab_width
> 220)
808 m_fixed_tab_width
= 220;
811 void wxAuiSimpleTabArt::DrawBackground(wxDC
& dc
,
812 wxWindow
* WXUNUSED(wnd
),
816 dc
.SetBrush(m_bkbrush
);
817 dc
.SetPen(*wxTRANSPARENT_PEN
);
818 dc
.DrawRectangle(-1, -1, rect
.GetWidth()+2, rect
.GetHeight()+2);
821 dc
.SetPen(*wxGREY_PEN
);
822 dc
.DrawLine(0, rect
.GetHeight()-1, rect
.GetWidth(), rect
.GetHeight()-1);
826 // DrawTab() draws an individual tab.
829 // in_rect - rectangle the tab should be confined to
830 // caption - tab's caption
831 // active - whether or not the tab is active
832 // out_rect - actual output rectangle
833 // x_extent - the advance x; where the next tab should start
835 void wxAuiSimpleTabArt::DrawTab(wxDC
& dc
,
837 const wxRect
& in_rect
,
838 const wxString
& caption_text
,
839 const wxBitmap
& bitmap
,
841 int close_button_state
,
842 wxRect
* out_tab_rect
,
843 wxRect
* out_button_rect
,
846 wxCoord normal_textx
, normal_texty
;
847 wxCoord selected_textx
, selected_texty
;
848 wxCoord textx
, texty
;
850 // if the caption is empty, measure some temporary text
851 wxString caption
= caption_text
;
852 if (caption_text
.empty())
855 dc
.SetFont(m_selected_font
);
856 dc
.GetTextExtent(caption
, &selected_textx
, &selected_texty
);
858 dc
.SetFont(m_normal_font
);
859 dc
.GetTextExtent(caption
, &normal_textx
, &normal_texty
);
861 // figure out the size of the tab
862 wxSize tab_size
= GetTabSize(dc
,
870 wxCoord tab_height
= tab_size
.y
;
871 wxCoord tab_width
= tab_size
.x
;
872 wxCoord tab_x
= in_rect
.x
;
873 wxCoord tab_y
= in_rect
.y
+ in_rect
.height
- tab_height
;
875 caption
= caption_text
;
877 // select pen, brush and font for the tab to be drawn
881 dc
.SetPen(m_selected_bkpen
);
882 dc
.SetBrush(m_selected_bkbrush
);
883 dc
.SetFont(m_selected_font
);
884 textx
= selected_textx
;
885 texty
= selected_texty
;
889 dc
.SetPen(m_normal_bkpen
);
890 dc
.SetBrush(m_normal_bkbrush
);
891 dc
.SetFont(m_normal_font
);
892 textx
= normal_textx
;
893 texty
= normal_texty
;
901 points
[0].y
= tab_y
+ tab_height
- 1;
902 points
[1].x
= tab_x
+ tab_height
- 3;
903 points
[1].y
= tab_y
+ 2;
904 points
[2].x
= tab_x
+ tab_height
+ 3;
906 points
[3].x
= tab_x
+ tab_width
- 2;
908 points
[4].x
= tab_x
+ tab_width
;
909 points
[4].y
= tab_y
+ 2;
910 points
[5].x
= tab_x
+ tab_width
;
911 points
[5].y
= tab_y
+ tab_height
- 1;
912 points
[6] = points
[0];
914 dc
.SetClippingRegion(in_rect
);
916 dc
.DrawPolygon(6, points
);
918 dc
.SetPen(*wxGREY_PEN
);
920 //dc.DrawLines(active ? 6 : 7, points);
921 dc
.DrawLines(7, points
);
926 int close_button_width
= 0;
927 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
929 close_button_width
= m_active_close_bmp
.GetWidth();
930 text_offset
= tab_x
+ (tab_height
/2) + ((tab_width
-close_button_width
)/2) - (textx
/2);
934 text_offset
= tab_x
+ (tab_height
/3) + (tab_width
/2) - (textx
/2);
937 // set minimum text offset
938 if (text_offset
< tab_x
+ tab_height
)
939 text_offset
= tab_x
+ tab_height
;
941 // chop text if necessary
942 wxString draw_text
= ChopText(dc
,
944 tab_width
- (text_offset
-tab_x
) - close_button_width
);
947 dc
.DrawText(draw_text
,
949 (tab_y
+ tab_height
)/2 - (texty
/2) + 1);
952 // draw close button if necessary
953 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
957 bmp
= m_active_close_bmp
;
959 bmp
= m_disabled_close_bmp
;
961 wxRect
rect(tab_x
+ tab_width
- close_button_width
- 1,
962 tab_y
+ (tab_height
/2) - (bmp
.GetHeight()/2) + 1,
965 DrawButtons(dc
, rect
, bmp
, *wxWHITE
, close_button_state
);
967 *out_button_rect
= rect
;
971 *out_tab_rect
= wxRect(tab_x
, tab_y
, tab_width
, tab_height
);
973 dc
.DestroyClippingRegion();
976 int wxAuiSimpleTabArt::GetIndentSize()
981 wxSize
wxAuiSimpleTabArt::GetTabSize(wxDC
& dc
,
982 wxWindow
* WXUNUSED(wnd
),
983 const wxString
& caption
,
984 const wxBitmap
& WXUNUSED(bitmap
),
985 bool WXUNUSED(active
),
986 int close_button_state
,
989 wxCoord measured_textx
, measured_texty
;
991 dc
.SetFont(m_measuring_font
);
992 dc
.GetTextExtent(caption
, &measured_textx
, &measured_texty
);
994 wxCoord tab_height
= measured_texty
+ 4;
995 wxCoord tab_width
= measured_textx
+ tab_height
+ 5;
997 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
998 tab_width
+= m_active_close_bmp
.GetWidth();
1000 if (m_flags
& wxAUI_NB_TAB_FIXED_WIDTH
)
1002 tab_width
= m_fixed_tab_width
;
1005 *x_extent
= tab_width
- (tab_height
/2) - 1;
1007 return wxSize(tab_width
, tab_height
);
1011 void wxAuiSimpleTabArt::DrawButton(wxDC
& dc
,
1012 wxWindow
* WXUNUSED(wnd
),
1013 const wxRect
& in_rect
,
1017 const wxBitmap
& bitmap_override
,
1023 if (bitmap_override
.IsOk())
1025 bmp
= bitmap_override
;
1031 case wxAUI_BUTTON_CLOSE
:
1032 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
1033 bmp
= m_disabled_close_bmp
;
1035 bmp
= m_active_close_bmp
;
1037 case wxAUI_BUTTON_LEFT
:
1038 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
1039 bmp
= m_disabled_left_bmp
;
1041 bmp
= m_active_left_bmp
;
1043 case wxAUI_BUTTON_RIGHT
:
1044 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
1045 bmp
= m_disabled_right_bmp
;
1047 bmp
= m_active_right_bmp
;
1049 case wxAUI_BUTTON_WINDOWLIST
:
1050 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
1051 bmp
= m_disabled_windowlist_bmp
;
1053 bmp
= m_active_windowlist_bmp
;
1063 if (orientation
== wxLEFT
)
1065 rect
.SetX(in_rect
.x
);
1066 rect
.SetY(((in_rect
.y
+ in_rect
.height
)/2) - (bmp
.GetHeight()/2));
1067 rect
.SetWidth(bmp
.GetWidth());
1068 rect
.SetHeight(bmp
.GetHeight());
1072 rect
= wxRect(in_rect
.x
+ in_rect
.width
- bmp
.GetWidth(),
1073 ((in_rect
.y
+ in_rect
.height
)/2) - (bmp
.GetHeight()/2),
1074 bmp
.GetWidth(), bmp
.GetHeight());
1078 DrawButtons(dc
, rect
, bmp
, *wxWHITE
, button_state
);
1084 int wxAuiSimpleTabArt::ShowWindowList(wxWindow
* wnd
,
1085 const wxArrayString
& items
,
1090 size_t i
, count
= items
.GetCount();
1091 for (i
= 0; i
< count
; ++i
)
1093 menuPopup
.AppendCheckItem(1000+i
, items
.Item(i
));
1096 if (active_idx
!= -1)
1098 menuPopup
.Check(1000+active_idx
, true);
1101 // find out where to put the popup menu of window
1102 // items. Subtract 100 for now to center the menu
1103 // a bit, until a better mechanism can be implemented
1104 wxPoint pt
= ::wxGetMousePosition();
1105 pt
= wnd
->ScreenToClient(pt
);
1111 // find out the screen coordinate at the bottom of the tab ctrl
1112 wxRect cli_rect
= wnd
->GetClientRect();
1113 pt
.y
= cli_rect
.y
+ cli_rect
.height
;
1115 wxAuiCommandCapture
* cc
= new wxAuiCommandCapture
;
1116 wnd
->PushEventHandler(cc
);
1117 wnd
->PopupMenu(&menuPopup
, pt
);
1118 int command
= cc
->GetCommandId();
1119 wnd
->PopEventHandler(true);
1121 if (command
>= 1000)
1122 return command
-1000;
1127 int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow
* wnd
,
1128 wxAuiNotebookPageArray
& WXUNUSED(pages
))
1131 dc
.SetFont(m_measuring_font
);
1133 wxSize s
= GetTabSize(dc
,
1138 wxAUI_BUTTON_STATE_HIDDEN
,
1143 void wxAuiSimpleTabArt::SetNormalFont(const wxFont
& font
)
1145 m_normal_font
= font
;
1148 void wxAuiSimpleTabArt::SetSelectedFont(const wxFont
& font
)
1150 m_selected_font
= font
;
1153 void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont
& font
)
1155 m_measuring_font
= font
;
1161 // -- wxAuiTabContainer class implementation --
1164 // wxAuiTabContainer is a class which contains information about each
1165 // tab. It also can render an entire tab control to a specified DC.
1166 // It's not a window class itself, because this code will be used by
1167 // the wxFrameMananger, where it is disadvantageous to have separate
1168 // windows for each tab control in the case of "docked tabs"
1170 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
1171 // which can be used as a tab control in the normal sense.
1174 wxAuiTabContainer::wxAuiTabContainer()
1178 m_art
= new wxAuiDefaultTabArt
;
1180 AddButton(wxAUI_BUTTON_LEFT
, wxLEFT
);
1181 AddButton(wxAUI_BUTTON_RIGHT
, wxRIGHT
);
1182 AddButton(wxAUI_BUTTON_WINDOWLIST
, wxRIGHT
);
1183 AddButton(wxAUI_BUTTON_CLOSE
, wxRIGHT
);
1186 wxAuiTabContainer::~wxAuiTabContainer()
1191 void wxAuiTabContainer::SetArtProvider(wxAuiTabArt
* art
)
1198 m_art
->SetFlags(m_flags
);
1202 wxAuiTabArt
* wxAuiTabContainer::GetArtProvider() const
1207 void wxAuiTabContainer::SetFlags(unsigned int flags
)
1211 // check for new close button settings
1212 RemoveButton(wxAUI_BUTTON_LEFT
);
1213 RemoveButton(wxAUI_BUTTON_RIGHT
);
1214 RemoveButton(wxAUI_BUTTON_WINDOWLIST
);
1215 RemoveButton(wxAUI_BUTTON_CLOSE
);
1218 if (flags
& wxAUI_NB_SCROLL_BUTTONS
)
1220 AddButton(wxAUI_BUTTON_LEFT
, wxLEFT
);
1221 AddButton(wxAUI_BUTTON_RIGHT
, wxRIGHT
);
1224 if (flags
& wxAUI_NB_WINDOWLIST_BUTTON
)
1226 AddButton(wxAUI_BUTTON_WINDOWLIST
, wxRIGHT
);
1229 if (flags
& wxAUI_NB_CLOSE_BUTTON
)
1231 AddButton(wxAUI_BUTTON_CLOSE
, wxRIGHT
);
1236 m_art
->SetFlags(m_flags
);
1240 unsigned int wxAuiTabContainer::GetFlags() const
1246 void wxAuiTabContainer::SetNormalFont(const wxFont
& font
)
1248 m_art
->SetNormalFont(font
);
1251 void wxAuiTabContainer::SetSelectedFont(const wxFont
& font
)
1253 m_art
->SetSelectedFont(font
);
1256 void wxAuiTabContainer::SetMeasuringFont(const wxFont
& font
)
1258 m_art
->SetMeasuringFont(font
);
1261 void wxAuiTabContainer::SetRect(const wxRect
& rect
)
1267 m_art
->SetSizingInfo(rect
.GetSize(), m_pages
.GetCount());
1271 bool wxAuiTabContainer::AddPage(wxWindow
* page
,
1272 const wxAuiNotebookPage
& info
)
1274 wxAuiNotebookPage page_info
;
1276 page_info
.window
= page
;
1278 m_pages
.Add(page_info
);
1280 // let the art provider know how many pages we have
1283 m_art
->SetSizingInfo(m_rect
.GetSize(), m_pages
.GetCount());
1289 bool wxAuiTabContainer::InsertPage(wxWindow
* page
,
1290 const wxAuiNotebookPage
& info
,
1293 wxAuiNotebookPage page_info
;
1295 page_info
.window
= page
;
1297 if (idx
>= m_pages
.GetCount())
1298 m_pages
.Add(page_info
);
1300 m_pages
.Insert(page_info
, idx
);
1302 // let the art provider know how many pages we have
1305 m_art
->SetSizingInfo(m_rect
.GetSize(), m_pages
.GetCount());
1311 bool wxAuiTabContainer::MovePage(wxWindow
* page
,
1314 int idx
= GetIdxFromWindow(page
);
1318 // get page entry, make a copy of it
1319 wxAuiNotebookPage p
= GetPage(idx
);
1321 // remove old page entry
1324 // insert page where it should be
1325 InsertPage(page
, p
, new_idx
);
1330 bool wxAuiTabContainer::RemovePage(wxWindow
* wnd
)
1332 size_t i
, page_count
= m_pages
.GetCount();
1333 for (i
= 0; i
< page_count
; ++i
)
1335 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1336 if (page
.window
== wnd
)
1338 m_pages
.RemoveAt(i
);
1340 // let the art provider know how many pages we have
1343 m_art
->SetSizingInfo(m_rect
.GetSize(), m_pages
.GetCount());
1353 bool wxAuiTabContainer::SetActivePage(wxWindow
* wnd
)
1357 size_t i
, page_count
= m_pages
.GetCount();
1358 for (i
= 0; i
< page_count
; ++i
)
1360 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1361 if (page
.window
== wnd
)
1368 page
.active
= false;
1375 void wxAuiTabContainer::SetNoneActive()
1377 size_t i
, page_count
= m_pages
.GetCount();
1378 for (i
= 0; i
< page_count
; ++i
)
1380 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1381 page
.active
= false;
1385 bool wxAuiTabContainer::SetActivePage(size_t page
)
1387 if (page
>= m_pages
.GetCount())
1390 return SetActivePage(m_pages
.Item(page
).window
);
1393 int wxAuiTabContainer::GetActivePage() const
1395 size_t i
, page_count
= m_pages
.GetCount();
1396 for (i
= 0; i
< page_count
; ++i
)
1398 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1406 wxWindow
* wxAuiTabContainer::GetWindowFromIdx(size_t idx
) const
1408 if (idx
>= m_pages
.GetCount())
1411 return m_pages
[idx
].window
;
1414 int wxAuiTabContainer::GetIdxFromWindow(wxWindow
* wnd
) const
1416 size_t i
, page_count
= m_pages
.GetCount();
1417 for (i
= 0; i
< page_count
; ++i
)
1419 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1420 if (page
.window
== wnd
)
1426 wxAuiNotebookPage
& wxAuiTabContainer::GetPage(size_t idx
)
1428 wxASSERT_MSG(idx
< m_pages
.GetCount(), wxT("Invalid Page index"));
1430 return m_pages
[idx
];
1433 wxAuiNotebookPageArray
& wxAuiTabContainer::GetPages()
1438 size_t wxAuiTabContainer::GetPageCount() const
1440 return m_pages
.GetCount();
1443 void wxAuiTabContainer::AddButton(int id
,
1445 const wxBitmap
& normal_bitmap
,
1446 const wxBitmap
& disabled_bitmap
)
1448 wxAuiTabContainerButton button
;
1450 button
.bitmap
= normal_bitmap
;
1451 button
.dis_bitmap
= disabled_bitmap
;
1452 button
.location
= location
;
1453 button
.cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
1455 m_buttons
.Add(button
);
1458 void wxAuiTabContainer::RemoveButton(int id
)
1460 size_t i
, button_count
= m_buttons
.GetCount();
1462 for (i
= 0; i
< button_count
; ++i
)
1464 if (m_buttons
.Item(i
).id
== id
)
1466 m_buttons
.RemoveAt(i
);
1474 size_t wxAuiTabContainer::GetTabOffset() const
1476 return m_tab_offset
;
1479 void wxAuiTabContainer::SetTabOffset(size_t offset
)
1481 m_tab_offset
= offset
;
1487 // Render() renders the tab catalog to the specified DC
1488 // It is a virtual function and can be overridden to
1489 // provide custom drawing capabilities
1490 void wxAuiTabContainer::Render(wxDC
* raw_dc
, wxWindow
* wnd
)
1492 if (!raw_dc
|| !raw_dc
->IsOk())
1498 size_t page_count
= m_pages
.GetCount();
1499 size_t button_count
= m_buttons
.GetCount();
1501 // create off-screen bitmap
1502 bmp
.Create(m_rect
.GetWidth(), m_rect
.GetHeight());
1503 dc
.SelectObject(bmp
);
1508 // find out if size of tabs is larger than can be
1509 // afforded on screen
1510 int total_width
= 0;
1511 int visible_width
= 0;
1512 for (i
= 0; i
< page_count
; ++i
)
1514 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1516 // determine if a close button is on this tab
1517 bool close_button
= false;
1518 if ((m_flags
& wxAUI_NB_CLOSE_ON_ALL_TABS
) != 0 ||
1519 ((m_flags
& wxAUI_NB_CLOSE_ON_ACTIVE_TAB
) != 0 && page
.active
))
1521 close_button
= true;
1526 wxSize size
= m_art
->GetTabSize(dc
,
1532 wxAUI_BUTTON_STATE_NORMAL
:
1533 wxAUI_BUTTON_STATE_HIDDEN
,
1536 if (i
+1 < page_count
)
1537 total_width
+= x_extent
;
1539 total_width
+= size
.x
;
1541 if (i
>= m_tab_offset
)
1543 if (i
+1 < page_count
)
1544 visible_width
+= x_extent
;
1546 visible_width
+= size
.x
;
1550 if (total_width
> m_rect
.GetWidth() || m_tab_offset
!= 0)
1552 // show left/right buttons
1553 for (i
= 0; i
< button_count
; ++i
)
1555 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
1556 if (button
.id
== wxAUI_BUTTON_LEFT
||
1557 button
.id
== wxAUI_BUTTON_RIGHT
)
1559 button
.cur_state
&= ~wxAUI_BUTTON_STATE_HIDDEN
;
1565 // hide left/right buttons
1566 for (i
= 0; i
< button_count
; ++i
)
1568 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
1569 if (button
.id
== wxAUI_BUTTON_LEFT
||
1570 button
.id
== wxAUI_BUTTON_RIGHT
)
1572 button
.cur_state
|= wxAUI_BUTTON_STATE_HIDDEN
;
1577 // determine whether left button should be enabled
1578 for (i
= 0; i
< button_count
; ++i
)
1580 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
1581 if (button
.id
== wxAUI_BUTTON_LEFT
)
1583 if (m_tab_offset
== 0)
1584 button
.cur_state
|= wxAUI_BUTTON_STATE_DISABLED
;
1586 button
.cur_state
&= ~wxAUI_BUTTON_STATE_DISABLED
;
1588 if (button
.id
== wxAUI_BUTTON_RIGHT
)
1590 if (visible_width
< m_rect
.GetWidth() - ((int)button_count
*16))
1591 button
.cur_state
|= wxAUI_BUTTON_STATE_DISABLED
;
1593 button
.cur_state
&= ~wxAUI_BUTTON_STATE_DISABLED
;
1600 m_art
->DrawBackground(dc
, wnd
, m_rect
);
1603 int left_buttons_width
= 0;
1604 int right_buttons_width
= 0;
1608 // draw the buttons on the right side
1609 offset
= m_rect
.x
+ m_rect
.width
;
1610 for (i
= 0; i
< button_count
; ++i
)
1612 wxAuiTabContainerButton
& button
= m_buttons
.Item(button_count
- i
- 1);
1614 if (button
.location
!= wxRIGHT
)
1616 if (button
.cur_state
& wxAUI_BUTTON_STATE_HIDDEN
)
1619 wxRect button_rect
= m_rect
;
1620 button_rect
.SetY(1);
1621 button_rect
.SetWidth(offset
);
1623 m_art
->DrawButton(dc
,
1632 offset
-= button
.rect
.GetWidth();
1633 right_buttons_width
+= button
.rect
.GetWidth();
1640 // draw the buttons on the left side
1642 for (i
= 0; i
< button_count
; ++i
)
1644 wxAuiTabContainerButton
& button
= m_buttons
.Item(button_count
- i
- 1);
1646 if (button
.location
!= wxLEFT
)
1648 if (button
.cur_state
& wxAUI_BUTTON_STATE_HIDDEN
)
1651 wxRect
button_rect(offset
, 1, 1000, m_rect
.height
);
1653 m_art
->DrawButton(dc
,
1662 offset
+= button
.rect
.GetWidth();
1663 left_buttons_width
+= button
.rect
.GetWidth();
1666 offset
= left_buttons_width
;
1669 offset
+= m_art
->GetIndentSize();
1672 // prepare the tab-close-button array
1673 // make sure tab button entries which aren't used are marked as hidden
1674 for (i
= page_count
; i
< m_tab_close_buttons
.GetCount(); ++i
)
1675 m_tab_close_buttons
.Item(i
).cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1677 // make sure there are enough tab button entries to accommodate all tabs
1678 while (m_tab_close_buttons
.GetCount() < page_count
)
1680 wxAuiTabContainerButton tempbtn
;
1681 tempbtn
.id
= wxAUI_BUTTON_CLOSE
;
1682 tempbtn
.location
= wxCENTER
;
1683 tempbtn
.cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1684 m_tab_close_buttons
.Add(tempbtn
);
1688 // buttons before the tab offset must be set to hidden
1689 for (i
= 0; i
< m_tab_offset
; ++i
)
1691 m_tab_close_buttons
.Item(i
).cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1697 size_t active
= 999;
1698 int active_offset
= 0;
1702 wxRect rect
= m_rect
;
1704 rect
.height
= m_rect
.height
;
1706 for (i
= m_tab_offset
; i
< page_count
; ++i
)
1708 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1709 wxAuiTabContainerButton
& tab_button
= m_tab_close_buttons
.Item(i
);
1711 // determine if a close button is on this tab
1712 bool close_button
= false;
1713 if ((m_flags
& wxAUI_NB_CLOSE_ON_ALL_TABS
) != 0 ||
1714 ((m_flags
& wxAUI_NB_CLOSE_ON_ACTIVE_TAB
) != 0 && page
.active
))
1716 close_button
= true;
1717 if (tab_button
.cur_state
== wxAUI_BUTTON_STATE_HIDDEN
)
1719 tab_button
.id
= wxAUI_BUTTON_CLOSE
;
1720 tab_button
.cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
1721 tab_button
.location
= wxCENTER
;
1726 tab_button
.cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1730 rect
.width
= m_rect
.width
- right_buttons_width
- offset
- 2;
1732 if (rect
.width
<= 0)
1741 tab_button
.cur_state
,
1749 active_offset
= offset
;
1757 // make sure to deactivate buttons which are off the screen to the right
1758 for (++i
; i
< m_tab_close_buttons
.GetCount(); ++i
)
1760 m_tab_close_buttons
.Item(i
).cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1764 // draw the active tab again so it stands in the foreground
1765 if (active
>= m_tab_offset
&& active
< m_pages
.GetCount())
1767 wxAuiNotebookPage
& page
= m_pages
.Item(active
);
1769 wxAuiTabContainerButton
& tab_button
= m_tab_close_buttons
.Item(active
);
1771 // determine if a close button is on this tab
1772 bool close_button
= false;
1773 if ((m_flags
& wxAUI_NB_CLOSE_ON_ALL_TABS
) != 0 ||
1774 ((m_flags
& wxAUI_NB_CLOSE_ON_ACTIVE_TAB
) != 0 && page
.active
))
1776 close_button
= true;
1779 rect
.x
= active_offset
;
1786 tab_button
.cur_state
,
1793 raw_dc
->Blit(m_rect
.x
, m_rect
.y
,
1794 m_rect
.GetWidth(), m_rect
.GetHeight(),
1799 // TabHitTest() tests if a tab was hit, passing the window pointer
1800 // back if that condition was fulfilled. The function returns
1801 // true if a tab was hit, otherwise false
1802 bool wxAuiTabContainer::TabHitTest(int x
, int y
, wxWindow
** hit
) const
1804 if (!m_rect
.Contains(x
,y
))
1807 wxAuiTabContainerButton
* btn
= NULL
;
1808 if (ButtonHitTest(x
, y
, &btn
))
1810 if (m_buttons
.Index(*btn
) != wxNOT_FOUND
)
1814 size_t i
, page_count
= m_pages
.GetCount();
1816 for (i
= m_tab_offset
; i
< page_count
; ++i
)
1818 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1819 if (page
.rect
.Contains(x
,y
))
1830 // ButtonHitTest() tests if a button was hit. The function returns
1831 // true if a button was hit, otherwise false
1832 bool wxAuiTabContainer::ButtonHitTest(int x
, int y
,
1833 wxAuiTabContainerButton
** hit
) const
1835 if (!m_rect
.Contains(x
,y
))
1838 size_t i
, button_count
;
1841 button_count
= m_buttons
.GetCount();
1842 for (i
= 0; i
< button_count
; ++i
)
1844 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
1845 if (button
.rect
.Contains(x
,y
) &&
1846 !(button
.cur_state
& (wxAUI_BUTTON_STATE_HIDDEN
|
1847 wxAUI_BUTTON_STATE_DISABLED
)))
1855 button_count
= m_tab_close_buttons
.GetCount();
1856 for (i
= 0; i
< button_count
; ++i
)
1858 wxAuiTabContainerButton
& button
= m_tab_close_buttons
.Item(i
);
1859 if (button
.rect
.Contains(x
,y
) &&
1860 !(button
.cur_state
& (wxAUI_BUTTON_STATE_HIDDEN
|
1861 wxAUI_BUTTON_STATE_DISABLED
)))
1874 // the utility function ShowWnd() is the same as show,
1875 // except it handles wxAuiMDIChildFrame windows as well,
1876 // as the Show() method on this class is "unplugged"
1877 static void ShowWnd(wxWindow
* wnd
, bool show
)
1879 if (wnd
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
1881 wxAuiMDIChildFrame
* cf
= (wxAuiMDIChildFrame
*)wnd
;
1891 // DoShowHide() this function shows the active window, then
1892 // hides all of the other windows (in that order)
1893 void wxAuiTabContainer::DoShowHide()
1895 wxAuiNotebookPageArray
& pages
= GetPages();
1896 size_t i
, page_count
= pages
.GetCount();
1898 // show new active page first
1899 for (i
= 0; i
< page_count
; ++i
)
1901 wxAuiNotebookPage
& page
= pages
.Item(i
);
1904 ShowWnd(page
.window
, true);
1909 // hide all other pages
1910 for (i
= 0; i
< page_count
; ++i
)
1912 wxAuiNotebookPage
& page
= pages
.Item(i
);
1913 ShowWnd(page
.window
, page
.active
);
1922 // -- wxAuiTabCtrl class implementation --
1926 BEGIN_EVENT_TABLE(wxAuiTabCtrl
, wxControl
)
1927 EVT_PAINT(wxAuiTabCtrl::OnPaint
)
1928 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground
)
1929 EVT_SIZE(wxAuiTabCtrl::OnSize
)
1930 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown
)
1931 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp
)
1932 EVT_MOTION(wxAuiTabCtrl::OnMotion
)
1933 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow
)
1934 EVT_AUINOTEBOOK_BUTTON(-1, wxAuiTabCtrl::OnButton
)
1938 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow
* parent
,
1942 long style
) : wxControl(parent
, id
, pos
, size
, style
)
1944 m_click_pt
= wxDefaultPosition
;
1945 m_is_dragging
= false;
1946 m_hover_button
= NULL
;
1947 m_pressed_button
= NULL
;
1950 wxAuiTabCtrl::~wxAuiTabCtrl()
1954 void wxAuiTabCtrl::OnPaint(wxPaintEvent
&)
1958 dc
.SetFont(GetFont());
1960 if (GetPageCount() > 0)
1964 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
1968 void wxAuiTabCtrl::OnSize(wxSizeEvent
& evt
)
1970 wxSize s
= evt
.GetSize();
1971 wxRect
r(0, 0, s
.GetWidth(), s
.GetHeight());
1975 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent
& evt
)
1978 m_click_pt
= wxDefaultPosition
;
1979 m_is_dragging
= false;
1981 m_pressed_button
= NULL
;
1985 if (TabHitTest(evt
.m_x
, evt
.m_y
, &wnd
))
1987 int new_selection
= GetIdxFromWindow(wnd
);
1989 if (new_selection
!= GetActivePage())
1991 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
1992 e
.SetSelection(new_selection
);
1993 e
.SetOldSelection(GetActivePage());
1994 e
.SetEventObject(this);
1995 GetEventHandler()->ProcessEvent(e
);
1998 m_click_pt
.x
= evt
.m_x
;
1999 m_click_pt
.y
= evt
.m_y
;
2005 m_pressed_button
= m_hover_button
;
2006 m_pressed_button
->cur_state
= wxAUI_BUTTON_STATE_PRESSED
;
2012 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent
& evt
)
2014 if (GetCapture() == this)
2019 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
, m_windowId
);
2020 evt
.SetSelection(GetIdxFromWindow(m_click_tab
));
2021 evt
.SetOldSelection(evt
.GetSelection());
2022 evt
.SetEventObject(this);
2023 GetEventHandler()->ProcessEvent(evt
);
2027 if (m_pressed_button
)
2029 // make sure we're still clicking the button
2030 wxAuiTabContainerButton
* button
= NULL
;
2031 if (!ButtonHitTest(evt
.m_x
, evt
.m_y
, &button
))
2034 if (button
!= m_pressed_button
)
2036 m_pressed_button
= NULL
;
2043 if (!(m_pressed_button
->cur_state
& wxAUI_BUTTON_STATE_DISABLED
))
2045 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
, m_windowId
);
2046 evt
.SetInt(m_pressed_button
->id
);
2047 evt
.SetEventObject(this);
2048 GetEventHandler()->ProcessEvent(evt
);
2051 m_pressed_button
= NULL
;
2054 m_click_pt
= wxDefaultPosition
;
2055 m_is_dragging
= false;
2059 void wxAuiTabCtrl::OnMotion(wxMouseEvent
& evt
)
2061 wxPoint pos
= evt
.GetPosition();
2063 // check if the mouse is hovering above a button
2064 wxAuiTabContainerButton
* button
;
2065 if (ButtonHitTest(pos
.x
, pos
.y
, &button
))
2067 if (m_hover_button
&& button
!= m_hover_button
)
2069 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
2070 m_hover_button
= NULL
;
2075 if (button
->cur_state
!= wxAUI_BUTTON_STATE_HOVER
)
2077 button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
2080 m_hover_button
= button
;
2088 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
2089 m_hover_button
= NULL
;
2096 if (!evt
.LeftIsDown() || m_click_pt
== wxDefaultPosition
)
2101 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
, m_windowId
);
2102 evt
.SetSelection(GetIdxFromWindow(m_click_tab
));
2103 evt
.SetOldSelection(evt
.GetSelection());
2104 evt
.SetEventObject(this);
2105 GetEventHandler()->ProcessEvent(evt
);
2110 int drag_x_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_X
);
2111 int drag_y_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_Y
);
2113 if (abs(pos
.x
- m_click_pt
.x
) > drag_x_threshold
||
2114 abs(pos
.y
- m_click_pt
.y
) > drag_y_threshold
)
2116 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
, m_windowId
);
2117 evt
.SetSelection(GetIdxFromWindow(m_click_tab
));
2118 evt
.SetOldSelection(evt
.GetSelection());
2119 evt
.SetEventObject(this);
2120 GetEventHandler()->ProcessEvent(evt
);
2122 m_is_dragging
= true;
2126 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent
& WXUNUSED(event
))
2130 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
2131 m_hover_button
= NULL
;
2137 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent
& event
)
2139 int button
= event
.GetInt();
2141 if (button
== wxAUI_BUTTON_LEFT
|| button
== wxAUI_BUTTON_RIGHT
)
2143 if (button
== wxAUI_BUTTON_LEFT
)
2145 if (GetTabOffset() > 0)
2147 SetTabOffset(GetTabOffset()-1);
2154 SetTabOffset(GetTabOffset()+1);
2159 else if (button
== wxAUI_BUTTON_WINDOWLIST
)
2163 size_t i
, page_count
= m_pages
.GetCount();
2164 for (i
= 0; i
< page_count
; ++i
)
2166 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
2167 as
.Add(page
.caption
);
2170 int idx
= GetArtProvider()->ShowWindowList(this, as
, GetActivePage());
2174 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
2175 e
.SetSelection(idx
);
2176 e
.SetOldSelection(GetActivePage());
2177 e
.SetEventObject(this);
2178 GetEventHandler()->ProcessEvent(e
);
2187 // wxTabFrame is an interesting case. It's important that all child pages
2188 // of the multi-notebook control are all actually children of that control
2189 // (and not grandchildren). wxTabFrame facilitates this. There is one
2190 // instance of wxTabFrame for each tab control inside the multi-notebook.
2191 // It's important to know that wxTabFrame is not a real window, but it merely
2192 // used to capture the dimensions/positioning of the internal tab control and
2193 // it's managed page windows
2195 class wxTabFrame
: public wxWindow
2202 m_rect
= wxRect(0,0,200,200);
2203 m_tab_ctrl_height
= 20;
2206 void SetTabCtrlHeight(int h
)
2208 m_tab_ctrl_height
= h
;
2211 void DoSetSize(int x
, int y
,
2212 int width
, int height
,
2213 int WXUNUSED(sizeFlags
= wxSIZE_AUTO
))
2215 m_rect
= wxRect(x
, y
, width
, height
);
2219 void DoGetClientSize(int* x
, int* y
) const
2225 bool Show( bool WXUNUSED(show
= true) ) { return false; }
2232 m_tab_rect
= wxRect(m_rect
.x
, m_rect
.y
, m_rect
.width
, m_tab_ctrl_height
);
2233 m_tabs
->SetSize(m_rect
.x
, m_rect
.y
, m_rect
.width
, m_tab_ctrl_height
);
2234 m_tabs
->SetRect(wxRect(0, 0, m_rect
.width
, m_tab_ctrl_height
));
2238 wxAuiNotebookPageArray
& pages
= m_tabs
->GetPages();
2239 size_t i
, page_count
= pages
.GetCount();
2241 for (i
= 0; i
< page_count
; ++i
)
2243 wxAuiNotebookPage
& page
= pages
.Item(i
);
2244 page
.window
->SetSize(m_rect
.x
, m_rect
.y
+ m_tab_ctrl_height
,
2245 m_rect
.width
, m_rect
.height
- m_tab_ctrl_height
);
2247 if (page
.window
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
2249 wxAuiMDIChildFrame
* wnd
= (wxAuiMDIChildFrame
*)page
.window
;
2250 wnd
->ApplyMDIChildFrameRect();
2255 void DoGetSize(int* x
, int* y
) const
2258 *x
= m_rect
.GetWidth();
2260 *y
= m_rect
.GetHeight();
2272 wxAuiTabCtrl
* m_tabs
;
2273 int m_tab_ctrl_height
;
2280 // -- wxAuiNotebook class implementation --
2282 BEGIN_EVENT_TABLE(wxAuiNotebook
, wxControl
)
2283 //EVT_ERASE_BACKGROUND(wxAuiNotebook::OnEraseBackground)
2284 //EVT_SIZE(wxAuiNotebook::OnSize)
2285 //EVT_LEFT_DOWN(wxAuiNotebook::OnLeftDown)
2286 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus
)
2287 EVT_COMMAND_RANGE(10000, 10100,
2288 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
,
2289 wxAuiNotebook::OnTabClicked
)
2290 EVT_COMMAND_RANGE(10000, 10100,
2291 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
,
2292 wxAuiNotebook::OnTabBeginDrag
)
2293 EVT_COMMAND_RANGE(10000, 10100,
2294 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
,
2295 wxAuiNotebook::OnTabEndDrag
)
2296 EVT_COMMAND_RANGE(10000, 10100,
2297 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
,
2298 wxAuiNotebook::OnTabDragMotion
)
2299 EVT_COMMAND_RANGE(10000, 10100,
2300 wxEVT_COMMAND_AUINOTEBOOK_BUTTON
,
2301 wxAuiNotebook::OnTabButton
)
2304 wxAuiNotebook::wxAuiNotebook()
2307 m_tab_id_counter
= 10000;
2309 m_tab_ctrl_height
= 20;
2312 wxAuiNotebook::wxAuiNotebook(wxWindow
*parent
,
2316 long style
) : wxControl(parent
, id
, pos
, size
, style
)
2318 InitNotebook(style
);
2321 bool wxAuiNotebook::Create(wxWindow
* parent
,
2327 if (!wxControl::Create(parent
, id
, pos
, size
, style
))
2330 InitNotebook(style
);
2335 // InitNotebook() contains common initialization
2336 // code called by all constructors
2337 void wxAuiNotebook::InitNotebook(long style
)
2340 m_tab_id_counter
= 10000;
2342 m_tab_ctrl_height
= 20;
2343 m_flags
= (unsigned int)style
;
2345 m_normal_font
= *wxNORMAL_FONT
;
2346 m_selected_font
= *wxNORMAL_FONT
;
2347 m_selected_font
.SetWeight(wxBOLD
);
2349 SetArtProvider(new wxAuiDefaultTabArt
);
2351 m_dummy_wnd
= new wxWindow(this, wxID_ANY
, wxPoint(0,0), wxSize(0,0));
2352 m_dummy_wnd
->SetSize(200, 200);
2353 m_dummy_wnd
->Show(false);
2355 m_mgr
.SetManagedWindow(this);
2357 m_mgr
.AddPane(m_dummy_wnd
,
2358 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
2363 wxAuiNotebook::~wxAuiNotebook()
2368 void wxAuiNotebook::SetArtProvider(wxAuiTabArt
* art
)
2370 m_tabs
.SetArtProvider(art
);
2372 SetTabCtrlHeight(CalculateTabCtrlHeight());
2375 void wxAuiNotebook::SetTabCtrlHeight(int height
)
2377 // if the tab control height needs to change, update
2378 // all of our tab controls with the new height
2379 if (m_tab_ctrl_height
!= height
)
2381 wxAuiTabArt
* art
= m_tabs
.GetArtProvider();
2383 m_tab_ctrl_height
= height
;
2385 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2386 size_t i
, pane_count
= all_panes
.GetCount();
2387 for (i
= 0; i
< pane_count
; ++i
)
2389 wxAuiPaneInfo
& pane
= all_panes
.Item(i
);
2390 if (pane
.name
== wxT("dummy"))
2392 wxTabFrame
* tab_frame
= (wxTabFrame
*)pane
.window
;
2393 wxAuiTabCtrl
* tabctrl
= tab_frame
->m_tabs
;
2394 tab_frame
->SetTabCtrlHeight(m_tab_ctrl_height
);
2395 tabctrl
->SetArtProvider(art
->Clone());
2396 tab_frame
->DoSizing();
2401 int wxAuiNotebook::CalculateTabCtrlHeight()
2403 // find out new best tab height
2404 wxAuiTabArt
* art
= m_tabs
.GetArtProvider();
2406 return art
->GetBestTabCtrlSize(this, m_tabs
.GetPages());
2410 wxAuiTabArt
* wxAuiNotebook::GetArtProvider() const
2412 return m_tabs
.GetArtProvider();
2415 void wxAuiNotebook::SetWindowStyleFlag(long style
)
2417 wxControl::SetWindowStyleFlag(style
);
2419 m_flags
= (unsigned int)style
;
2421 // if the control is already initialized
2422 if (m_mgr
.GetManagedWindow() == (wxWindow
*)this)
2424 // let all of the tab children know about the new style
2426 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2427 size_t i
, pane_count
= all_panes
.GetCount();
2428 for (i
= 0; i
< pane_count
; ++i
)
2430 wxAuiPaneInfo
& pane
= all_panes
.Item(i
);
2431 if (pane
.name
== wxT("dummy"))
2433 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
2434 tabctrl
->SetFlags(m_flags
);
2442 bool wxAuiNotebook::AddPage(wxWindow
* page
,
2443 const wxString
& caption
,
2445 const wxBitmap
& bitmap
)
2447 return InsertPage(GetPageCount(), page
, caption
, select
, bitmap
);
2450 bool wxAuiNotebook::InsertPage(size_t page_idx
,
2452 const wxString
& caption
,
2454 const wxBitmap
& bitmap
)
2456 wxAuiNotebookPage info
;
2458 info
.caption
= caption
;
2459 info
.bitmap
= bitmap
;
2460 info
.active
= false;
2462 // if there are currently no tabs, the first added
2463 // tab must be active
2464 if (m_tabs
.GetPageCount() == 0)
2467 m_tabs
.InsertPage(page
, info
, page_idx
);
2469 wxAuiTabCtrl
* active_tabctrl
= GetActiveTabCtrl();
2470 if (page_idx
>= active_tabctrl
->GetPageCount())
2471 active_tabctrl
->AddPage(page
, info
);
2473 active_tabctrl
->InsertPage(page
, info
, page_idx
);
2475 SetTabCtrlHeight(CalculateTabCtrlHeight());
2477 active_tabctrl
->DoShowHide();
2481 int idx
= m_tabs
.GetIdxFromWindow(page
);
2482 wxASSERT_MSG(idx
!= -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()"));
2491 // DeletePage() removes a tab from the multi-notebook,
2492 // and destroys the window as well
2493 bool wxAuiNotebook::DeletePage(size_t page_idx
)
2495 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
2497 if (!RemovePage(page_idx
))
2500 // actually destroy the window now
2501 if (wnd
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
2503 // delete the child frame with pending delete, as is
2504 // customary with frame windows
2505 if (!wxPendingDelete
.Member(wnd
))
2506 wxPendingDelete
.Append(wnd
);
2518 // RemovePage() removes a tab from the multi-notebook,
2519 // but does not destroy the window
2520 bool wxAuiNotebook::RemovePage(size_t page_idx
)
2522 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
2523 wxWindow
* new_active
= NULL
;
2525 // find out which onscreen tab ctrl owns this tab
2528 if (!FindTab(wnd
, &ctrl
, &ctrl_idx
))
2531 // find a new page and set it as active
2532 int new_idx
= ctrl_idx
+1;
2533 if (new_idx
>= (int)ctrl
->GetPageCount())
2534 new_idx
= ctrl_idx
-1;
2536 if (new_idx
>= 0 && new_idx
< (int)ctrl
->GetPageCount())
2538 new_active
= ctrl
->GetWindowFromIdx(new_idx
);
2542 // set the active page to the first page that
2543 // isn't the one being deleted
2544 size_t i
, page_count
= m_tabs
.GetPageCount();
2545 for (i
= 0; i
< page_count
; ++i
)
2547 wxWindow
* w
= m_tabs
.GetWindowFromIdx(i
);
2550 new_active
= m_tabs
.GetWindowFromIdx(i
);
2556 // remove the tab from main catalog
2557 if (!m_tabs
.RemovePage(wnd
))
2560 // remove the tab from the onscreen tab ctrl
2561 ctrl
->RemovePage(wnd
);
2564 RemoveEmptyTabFrames();
2566 // set new active pane
2570 SetSelection(m_tabs
.GetIdxFromWindow(new_active
));
2576 // GetPageIndex() returns the index of the page, or -1 if the
2577 // page could not be located in the notebook
2578 int wxAuiNotebook::GetPageIndex(wxWindow
* page_wnd
) const
2580 return m_tabs
.GetIdxFromWindow(page_wnd
);
2585 // SetPageText() changes the tab caption of the specified page
2586 bool wxAuiNotebook::SetPageText(size_t page_idx
, const wxString
& text
)
2588 if (page_idx
>= m_tabs
.GetPageCount())
2591 // update our own tab catalog
2592 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
2593 page_info
.caption
= text
;
2595 // update what's on screen
2598 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
2600 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
2601 info
.caption
= text
;
2610 bool wxAuiNotebook::SetPageBitmap(size_t page_idx
, const wxBitmap
& bitmap
)
2612 if (page_idx
>= m_tabs
.GetPageCount())
2615 // update our own tab catalog
2616 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
2617 page_info
.bitmap
= bitmap
;
2619 // tab height might have changed
2620 SetTabCtrlHeight(CalculateTabCtrlHeight());
2622 // update what's on screen
2625 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
2627 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
2628 info
.bitmap
= bitmap
;
2637 // GetSelection() returns the index of the currently active page
2638 int wxAuiNotebook::GetSelection() const
2643 // SetSelection() sets the currently active page
2644 size_t wxAuiNotebook::SetSelection(size_t new_page
)
2646 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(new_page
);
2650 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
2651 evt
.SetSelection(new_page
);
2652 evt
.SetOldSelection(m_curpage
);
2653 evt
.SetEventObject(this);
2654 if (!GetEventHandler()->ProcessEvent(evt
) || evt
.IsAllowed())
2656 int old_curpage
= m_curpage
;
2657 m_curpage
= new_page
;
2659 // program allows the page change
2660 evt
.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
);
2661 (void)GetEventHandler()->ProcessEvent(evt
);
2666 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
2668 m_tabs
.SetActivePage(wnd
);
2670 ctrl
->SetActivePage(ctrl_idx
);
2677 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2678 size_t i
, pane_count
= all_panes
.GetCount();
2679 for (i
= 0; i
< pane_count
; ++i
)
2681 wxAuiPaneInfo
& pane
= all_panes
.Item(i
);
2682 if (pane
.name
== wxT("dummy"))
2684 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
2685 if (tabctrl
!= ctrl
)
2686 tabctrl
->SetSelectedFont(m_normal_font
);
2688 tabctrl
->SetSelectedFont(m_selected_font
);
2701 // GetPageCount() returns the total number of
2702 // pages managed by the multi-notebook
2703 size_t wxAuiNotebook::GetPageCount() const
2705 return m_tabs
.GetPageCount();
2708 // GetPage() returns the wxWindow pointer of the
2710 wxWindow
* wxAuiNotebook::GetPage(size_t page_idx
) const
2712 wxASSERT(page_idx
< m_tabs
.GetPageCount());
2714 return m_tabs
.GetWindowFromIdx(page_idx
);
2717 // DoSizing() performs all sizing operations in each tab control
2718 void wxAuiNotebook::DoSizing()
2720 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2721 size_t i
, pane_count
= all_panes
.GetCount();
2722 for (i
= 0; i
< pane_count
; ++i
)
2724 if (all_panes
.Item(i
).name
== wxT("dummy"))
2727 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
2728 tabframe
->DoSizing();
2732 // GetActiveTabCtrl() returns the active tab control. It is
2733 // called to determine which control gets new windows being added
2734 wxAuiTabCtrl
* wxAuiNotebook::GetActiveTabCtrl()
2736 if (m_curpage
>= 0 && m_curpage
< (int)m_tabs
.GetPageCount())
2741 // find the tab ctrl with the current page
2742 if (FindTab(m_tabs
.GetPage(m_curpage
).window
,
2749 // no current page, just find the first tab ctrl
2750 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2751 size_t i
, pane_count
= all_panes
.GetCount();
2752 for (i
= 0; i
< pane_count
; ++i
)
2754 if (all_panes
.Item(i
).name
== wxT("dummy"))
2757 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
2758 return tabframe
->m_tabs
;
2761 // If there is no tabframe at all, create one
2762 wxTabFrame
* tabframe
= new wxTabFrame
;
2763 tabframe
->SetTabCtrlHeight(m_tab_ctrl_height
);
2764 tabframe
->m_tabs
= new wxAuiTabCtrl(this,
2769 tabframe
->m_tabs
->SetFlags(m_flags
);
2770 tabframe
->m_tabs
->SetArtProvider(m_tabs
.GetArtProvider()->Clone());
2771 m_mgr
.AddPane(tabframe
,
2772 wxAuiPaneInfo().Center().CaptionVisible(false));
2776 return tabframe
->m_tabs
;
2779 // FindTab() finds the tab control that currently contains the window as well
2780 // as the index of the window in the tab control. It returns true if the
2781 // window was found, otherwise false.
2782 bool wxAuiNotebook::FindTab(wxWindow
* page
, wxAuiTabCtrl
** ctrl
, int* idx
)
2784 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2785 size_t i
, pane_count
= all_panes
.GetCount();
2786 for (i
= 0; i
< pane_count
; ++i
)
2788 if (all_panes
.Item(i
).name
== wxT("dummy"))
2791 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
2793 int page_idx
= tabframe
->m_tabs
->GetIdxFromWindow(page
);
2796 *ctrl
= tabframe
->m_tabs
;
2806 void wxAuiNotebook::OnEraseBackground(wxEraseEvent
&)
2810 void wxAuiNotebook::OnSize(wxSizeEvent
&)
2814 void wxAuiNotebook::OnTabClicked(wxCommandEvent
& command_evt
)
2816 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
2818 wxAuiTabCtrl
* ctrl
= (wxAuiTabCtrl
*)evt
.GetEventObject();
2819 wxASSERT(ctrl
!= NULL
);
2821 wxWindow
* wnd
= ctrl
->GetWindowFromIdx(evt
.GetSelection());
2822 wxASSERT(wnd
!= NULL
);
2824 int idx
= m_tabs
.GetIdxFromWindow(wnd
);
2825 wxASSERT(idx
!= -1);
2830 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent
&)
2835 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent
& evt
)
2837 wxPoint screen_pt
= ::wxGetMousePosition();
2838 wxPoint client_pt
= ScreenToClient(screen_pt
);
2841 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
2842 wxAuiTabCtrl
* dest_tabs
= GetTabCtrlFromPoint(client_pt
);
2844 if (dest_tabs
== src_tabs
)
2848 src_tabs
->SetCursor(wxCursor(wxCURSOR_ARROW
));
2851 // always hide the hint for inner-tabctrl drag
2854 // if tab moving is not allowed, leave
2855 if (!(m_flags
& wxAUI_NB_TAB_MOVE
))
2860 wxPoint pt
= dest_tabs
->ScreenToClient(screen_pt
);
2861 wxWindow
* dest_location_tab
;
2863 // this is an inner-tab drag/reposition
2864 if (dest_tabs
->TabHitTest(pt
.x
, pt
.y
, &dest_location_tab
))
2866 int src_idx
= evt
.GetSelection();
2867 int dest_idx
= dest_tabs
->GetIdxFromWindow(dest_location_tab
);
2869 // prevent jumpy drag
2870 if ((src_idx
== dest_idx
) || dest_idx
== -1 ||
2871 (src_idx
> dest_idx
&& m_last_drag_x
<= pt
.x
) ||
2872 (src_idx
< dest_idx
&& m_last_drag_x
>= pt
.x
))
2874 m_last_drag_x
= pt
.x
;
2879 wxWindow
* src_tab
= dest_tabs
->GetWindowFromIdx(src_idx
);
2880 dest_tabs
->MovePage(src_tab
, dest_idx
);
2881 dest_tabs
->SetActivePage((size_t)dest_idx
);
2882 dest_tabs
->DoShowHide();
2883 dest_tabs
->Refresh();
2884 m_last_drag_x
= pt
.x
;
2892 // if external drag is allowed, check if the tab is being dragged
2893 // over a different wxAuiNotebook control
2894 if (m_flags
& wxAUI_NB_TAB_EXTERNAL_MOVE
)
2896 wxWindow
* tab_ctrl
= ::wxFindWindowAtPoint(screen_pt
);
2898 // if we aren't over any window, stop here
2902 // make sure we are not over the hint window
2903 if (!tab_ctrl
->IsKindOf(CLASSINFO(wxFrame
)))
2907 if (tab_ctrl
->IsKindOf(CLASSINFO(wxAuiTabCtrl
)))
2909 tab_ctrl
= tab_ctrl
->GetParent();
2914 wxAuiNotebook
* nb
= (wxAuiNotebook
*)tab_ctrl
->GetParent();
2918 wxRect hint_rect
= tab_ctrl
->GetClientRect();
2919 tab_ctrl
->ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
2920 m_mgr
.ShowHint(hint_rect
);
2929 // we are either over a hint window, or not over a tab
2930 // window, and there is no where to drag to, so exit
2937 // if there are less than two panes, split can't happen, so leave
2938 if (m_tabs
.GetPageCount() < 2)
2941 // if tab moving is not allowed, leave
2942 if (!(m_flags
& wxAUI_NB_TAB_SPLIT
))
2948 src_tabs
->SetCursor(wxCursor(wxCURSOR_SIZING
));
2954 wxRect hint_rect
= dest_tabs
->GetRect();
2955 ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
2956 m_mgr
.ShowHint(hint_rect
);
2960 m_mgr
.DrawHintRect(m_dummy_wnd
, client_pt
, zero
);
2966 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent
& command_evt
)
2968 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
2973 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
2974 wxAuiTabCtrl
* dest_tabs
= NULL
;
2977 // set cursor back to an arrow
2978 src_tabs
->SetCursor(wxCursor(wxCURSOR_ARROW
));
2981 // get the mouse position, which will be used to determine the drop point
2982 wxPoint mouse_screen_pt
= ::wxGetMousePosition();
2983 wxPoint mouse_client_pt
= ScreenToClient(mouse_screen_pt
);
2987 // check for an external move
2988 if (m_flags
& wxAUI_NB_TAB_EXTERNAL_MOVE
)
2990 wxWindow
* tab_ctrl
= ::wxFindWindowAtPoint(mouse_screen_pt
);
2994 if (tab_ctrl
->IsKindOf(CLASSINFO(wxAuiTabCtrl
)))
2996 tab_ctrl
= tab_ctrl
->GetParent();
3001 wxAuiNotebook
* nb
= (wxAuiNotebook
*)tab_ctrl
->GetParent();
3005 // find out from the destination control
3006 // if it's ok to drop this tab here
3007 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND
, m_windowId
);
3008 e
.SetSelection(evt
.GetSelection());
3009 e
.SetOldSelection(evt
.GetSelection());
3010 e
.SetEventObject(this);
3011 e
.SetDragSource(this);
3012 e
.Veto(); // dropping must be explicitly approved by control owner
3014 nb
->GetEventHandler()->ProcessEvent(e
);
3018 // no answer or negative answer
3024 int src_idx
= evt
.GetSelection();
3025 wxWindow
* src_page
= src_tabs
->GetWindowFromIdx(src_idx
);
3027 // get main index of the page
3028 int main_idx
= m_tabs
.GetIdxFromWindow(src_page
);
3030 // make a copy of the page info
3031 wxAuiNotebookPage page_info
= m_tabs
.GetPage((size_t)main_idx
);
3033 // remove the page from the source notebook
3034 RemovePage(main_idx
);
3036 // reparent the page
3037 src_page
->Reparent(nb
);
3040 // found out the insert idx
3041 wxAuiTabCtrl
* dest_tabs
= (wxAuiTabCtrl
*)tab_ctrl
;
3042 wxPoint pt
= dest_tabs
->ScreenToClient(mouse_screen_pt
);
3044 wxWindow
* target
= NULL
;
3045 int insert_idx
= -1;
3046 dest_tabs
->TabHitTest(pt
.x
, pt
.y
, &target
);
3049 insert_idx
= dest_tabs
->GetIdxFromWindow(target
);
3053 // add the page to the new notebook
3054 if (insert_idx
== -1)
3055 insert_idx
= dest_tabs
->GetPageCount();
3056 dest_tabs
->InsertPage(page_info
.window
, page_info
, insert_idx
);
3057 nb
->m_tabs
.AddPage(page_info
.window
, page_info
);
3060 dest_tabs
->DoShowHide();
3061 dest_tabs
->Refresh();
3063 // set the selection in the destination tab control
3064 nb
->SetSelection(nb
->m_tabs
.GetIdxFromWindow(page_info
.window
));
3074 // only perform a tab split if it's allowed
3075 if ((m_flags
& wxAUI_NB_TAB_SPLIT
) && m_tabs
.GetPageCount() >= 2)
3077 // If the pointer is in an existing tab frame, do a tab insert
3078 wxWindow
* hit_wnd
= ::wxFindWindowAtPoint(mouse_screen_pt
);
3079 wxTabFrame
* tab_frame
= (wxTabFrame
*)GetTabFrameFromTabCtrl(hit_wnd
);
3080 int insert_idx
= -1;
3083 dest_tabs
= tab_frame
->m_tabs
;
3085 if (dest_tabs
== src_tabs
)
3089 wxPoint pt
= dest_tabs
->ScreenToClient(mouse_screen_pt
);
3090 wxWindow
* target
= NULL
;
3091 dest_tabs
->TabHitTest(pt
.x
, pt
.y
, &target
);
3094 insert_idx
= dest_tabs
->GetIdxFromWindow(target
);
3099 // If there is no tabframe at all, create one
3100 wxTabFrame
* new_tabs
= new wxTabFrame
;
3101 new_tabs
->SetTabCtrlHeight(m_tab_ctrl_height
);
3102 new_tabs
->m_tabs
= new wxAuiTabCtrl(this,
3107 new_tabs
->m_tabs
->SetArtProvider(m_tabs
.GetArtProvider()->Clone());
3108 new_tabs
->m_tabs
->SetFlags(m_flags
);
3110 m_mgr
.AddPane(new_tabs
,
3111 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3114 dest_tabs
= new_tabs
->m_tabs
;
3119 // remove the page from the source tabs
3120 wxAuiNotebookPage page_info
= src_tabs
->GetPage(evt
.GetSelection());
3121 page_info
.active
= false;
3122 src_tabs
->RemovePage(page_info
.window
);
3123 if (src_tabs
->GetPageCount() > 0)
3125 src_tabs
->SetActivePage((size_t)0);
3126 src_tabs
->DoShowHide();
3127 src_tabs
->Refresh();
3132 // add the page to the destination tabs
3133 if (insert_idx
== -1)
3134 insert_idx
= dest_tabs
->GetPageCount();
3135 dest_tabs
->InsertPage(page_info
.window
, page_info
, insert_idx
);
3137 if (src_tabs
->GetPageCount() == 0)
3139 RemoveEmptyTabFrames();
3143 dest_tabs
->DoShowHide();
3144 dest_tabs
->Refresh();
3146 SetSelection(m_tabs
.GetIdxFromWindow(page_info
.window
));
3152 wxAuiTabCtrl
* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint
& pt
)
3154 // if we've just removed the last tab from the source
3155 // tab set, the remove the tab control completely
3156 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
3157 size_t i
, pane_count
= all_panes
.GetCount();
3158 for (i
= 0; i
< pane_count
; ++i
)
3160 if (all_panes
.Item(i
).name
== wxT("dummy"))
3163 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
3164 if (tabframe
->m_tab_rect
.Contains(pt
))
3165 return tabframe
->m_tabs
;
3171 wxWindow
* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow
* tab_ctrl
)
3173 // if we've just removed the last tab from the source
3174 // tab set, the remove the tab control completely
3175 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
3176 size_t i
, pane_count
= all_panes
.GetCount();
3177 for (i
= 0; i
< pane_count
; ++i
)
3179 if (all_panes
.Item(i
).name
== wxT("dummy"))
3182 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
3183 if (tabframe
->m_tabs
== tab_ctrl
)
3192 void wxAuiNotebook::RemoveEmptyTabFrames()
3194 // if we've just removed the last tab from the source
3195 // tab set, the remove the tab control completely
3196 wxAuiPaneInfoArray all_panes
= m_mgr
.GetAllPanes();
3197 size_t i
, pane_count
= all_panes
.GetCount();
3198 for (i
= 0; i
< pane_count
; ++i
)
3200 if (all_panes
.Item(i
).name
== wxT("dummy"))
3203 wxTabFrame
* tab_frame
= (wxTabFrame
*)all_panes
.Item(i
).window
;
3204 if (tab_frame
->m_tabs
->GetPageCount() == 0)
3206 m_mgr
.DetachPane(tab_frame
);
3208 // use pending delete because sometimes during
3209 // window closing, refreshs are pending
3210 if (!wxPendingDelete
.Member(tab_frame
->m_tabs
))
3211 wxPendingDelete
.Append(tab_frame
->m_tabs
);
3212 //tab_frame->m_tabs->Destroy();
3219 // check to see if there is still a center pane;
3220 // if there isn't, make a frame the center pane
3221 wxAuiPaneInfoArray panes
= m_mgr
.GetAllPanes();
3222 pane_count
= panes
.GetCount();
3223 wxWindow
* first_good
= NULL
;
3224 bool center_found
= false;
3225 for (i
= 0; i
< pane_count
; ++i
)
3227 if (panes
.Item(i
).name
== wxT("dummy"))
3229 if (panes
.Item(i
).dock_direction
== wxAUI_DOCK_CENTRE
)
3230 center_found
= true;
3232 first_good
= panes
.Item(i
).window
;
3235 if (!center_found
&& first_good
)
3237 m_mgr
.GetPane(first_good
).Centre();
3243 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent
& evt
)
3245 int idx
= m_tabs
.GetIdxFromWindow(evt
.GetWindow());
3246 if (idx
!= -1 && idx
!= m_curpage
)
3253 void wxAuiNotebook::OnTabButton(wxCommandEvent
& command_evt
)
3255 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
3256 wxAuiTabCtrl
* tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
3258 int button_id
= evt
.GetInt();
3260 if (button_id
== wxAUI_BUTTON_CLOSE
)
3262 int selection
= tabs
->GetActivePage();
3264 if (selection
!= -1)
3266 wxWindow
* close_wnd
= tabs
->GetWindowFromIdx(selection
);
3269 // ask owner if it's ok to close the tab
3270 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE
, m_windowId
);
3271 e
.SetSelection(m_tabs
.GetIdxFromWindow(close_wnd
));
3272 e
.SetOldSelection(evt
.GetSelection());
3273 e
.SetEventObject(this);
3274 GetEventHandler()->ProcessEvent(e
);
3279 if (close_wnd
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
3285 int main_idx
= m_tabs
.GetIdxFromWindow(close_wnd
);
3286 DeletePage(main_idx
);