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();
1671 // prepare the tab-close-button array
1672 while (m_tab_close_buttons
.GetCount() > page_count
)
1673 m_tab_close_buttons
.RemoveAt(m_tab_close_buttons
.GetCount()-1);
1675 while (m_tab_close_buttons
.GetCount() < page_count
)
1677 wxAuiTabContainerButton tempbtn
;
1678 tempbtn
.id
= wxAUI_BUTTON_CLOSE
;
1679 tempbtn
.location
= wxCENTER
;
1680 tempbtn
.cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1681 m_tab_close_buttons
.Add(tempbtn
);
1685 // buttons before the tab offset must be set to hidden
1686 for (i
= 0; i
< m_tab_offset
; ++i
)
1688 m_tab_close_buttons
.Item(i
).cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1694 size_t active
= 999;
1695 int active_offset
= 0;
1699 wxRect rect
= m_rect
;
1701 rect
.height
= m_rect
.height
;
1703 for (i
= m_tab_offset
; i
< page_count
; ++i
)
1705 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1706 wxAuiTabContainerButton
& tab_button
= m_tab_close_buttons
.Item(i
);
1708 // determine if a close button is on this tab
1709 bool close_button
= false;
1710 if ((m_flags
& wxAUI_NB_CLOSE_ON_ALL_TABS
) != 0 ||
1711 ((m_flags
& wxAUI_NB_CLOSE_ON_ACTIVE_TAB
) != 0 && page
.active
))
1713 close_button
= true;
1714 if (tab_button
.cur_state
== wxAUI_BUTTON_STATE_HIDDEN
)
1716 tab_button
.id
= wxAUI_BUTTON_CLOSE
;
1717 tab_button
.cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
1718 tab_button
.location
= wxCENTER
;
1723 tab_button
.cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1727 rect
.width
= m_rect
.width
- right_buttons_width
- offset
- 2;
1729 if (rect
.width
<= 0)
1738 tab_button
.cur_state
,
1746 active_offset
= offset
;
1754 // make sure to deactivate buttons which are off the screen to the right
1755 for (++i
; i
< m_tab_close_buttons
.GetCount(); ++i
)
1757 m_tab_close_buttons
.Item(i
).cur_state
= wxAUI_BUTTON_STATE_HIDDEN
;
1761 // draw the active tab again so it stands in the foreground
1762 if (active
>= m_tab_offset
&& active
< m_pages
.GetCount())
1764 wxAuiNotebookPage
& page
= m_pages
.Item(active
);
1766 wxAuiTabContainerButton
& tab_button
= m_tab_close_buttons
.Item(active
);
1768 // determine if a close button is on this tab
1769 bool close_button
= false;
1770 if ((m_flags
& wxAUI_NB_CLOSE_ON_ALL_TABS
) != 0 ||
1771 ((m_flags
& wxAUI_NB_CLOSE_ON_ACTIVE_TAB
) != 0 && page
.active
))
1773 close_button
= true;
1776 rect
.x
= active_offset
;
1783 tab_button
.cur_state
,
1790 raw_dc
->Blit(m_rect
.x
, m_rect
.y
,
1791 m_rect
.GetWidth(), m_rect
.GetHeight(),
1796 // TabHitTest() tests if a tab was hit, passing the window pointer
1797 // back if that condition was fulfilled. The function returns
1798 // true if a tab was hit, otherwise false
1799 bool wxAuiTabContainer::TabHitTest(int x
, int y
, wxWindow
** hit
) const
1801 if (!m_rect
.Contains(x
,y
))
1804 wxAuiTabContainerButton
* btn
= NULL
;
1805 if (ButtonHitTest(x
, y
, &btn
))
1807 if (m_buttons
.Index(*btn
) != wxNOT_FOUND
)
1811 size_t i
, page_count
= m_pages
.GetCount();
1813 for (i
= m_tab_offset
; i
< page_count
; ++i
)
1815 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
1816 if (page
.rect
.Contains(x
,y
))
1827 // ButtonHitTest() tests if a button was hit. The function returns
1828 // true if a button was hit, otherwise false
1829 bool wxAuiTabContainer::ButtonHitTest(int x
, int y
,
1830 wxAuiTabContainerButton
** hit
) const
1832 if (!m_rect
.Contains(x
,y
))
1835 size_t i
, button_count
;
1838 button_count
= m_buttons
.GetCount();
1839 for (i
= 0; i
< button_count
; ++i
)
1841 wxAuiTabContainerButton
& button
= m_buttons
.Item(i
);
1842 if (button
.rect
.Contains(x
,y
) &&
1843 !(button
.cur_state
& (wxAUI_BUTTON_STATE_HIDDEN
|
1844 wxAUI_BUTTON_STATE_DISABLED
)))
1852 button_count
= m_tab_close_buttons
.GetCount();
1853 for (i
= 0; i
< button_count
; ++i
)
1855 wxAuiTabContainerButton
& button
= m_tab_close_buttons
.Item(i
);
1856 if (button
.rect
.Contains(x
,y
) &&
1857 !(button
.cur_state
& (wxAUI_BUTTON_STATE_HIDDEN
|
1858 wxAUI_BUTTON_STATE_DISABLED
)))
1871 // the utility function ShowWnd() is the same as show,
1872 // except it handles wxAuiMDIChildFrame windows as well,
1873 // as the Show() method on this class is "unplugged"
1874 static void ShowWnd(wxWindow
* wnd
, bool show
)
1876 if (wnd
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
1878 wxAuiMDIChildFrame
* cf
= (wxAuiMDIChildFrame
*)wnd
;
1888 // DoShowHide() this function shows the active window, then
1889 // hides all of the other windows (in that order)
1890 void wxAuiTabContainer::DoShowHide()
1892 wxAuiNotebookPageArray
& pages
= GetPages();
1893 size_t i
, page_count
= pages
.GetCount();
1895 // show new active page first
1896 for (i
= 0; i
< page_count
; ++i
)
1898 wxAuiNotebookPage
& page
= pages
.Item(i
);
1901 ShowWnd(page
.window
, true);
1906 // hide all other pages
1907 for (i
= 0; i
< page_count
; ++i
)
1909 wxAuiNotebookPage
& page
= pages
.Item(i
);
1910 ShowWnd(page
.window
, page
.active
);
1919 // -- wxAuiTabCtrl class implementation --
1923 BEGIN_EVENT_TABLE(wxAuiTabCtrl
, wxControl
)
1924 EVT_PAINT(wxAuiTabCtrl::OnPaint
)
1925 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground
)
1926 EVT_SIZE(wxAuiTabCtrl::OnSize
)
1927 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown
)
1928 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp
)
1929 EVT_MOTION(wxAuiTabCtrl::OnMotion
)
1930 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow
)
1931 EVT_AUINOTEBOOK_BUTTON(-1, wxAuiTabCtrl::OnButton
)
1935 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow
* parent
,
1939 long style
) : wxControl(parent
, id
, pos
, size
, style
)
1941 m_click_pt
= wxDefaultPosition
;
1942 m_is_dragging
= false;
1943 m_hover_button
= NULL
;
1944 m_pressed_button
= NULL
;
1947 wxAuiTabCtrl::~wxAuiTabCtrl()
1951 void wxAuiTabCtrl::OnPaint(wxPaintEvent
&)
1955 dc
.SetFont(GetFont());
1957 if (GetPageCount() > 0)
1961 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
1965 void wxAuiTabCtrl::OnSize(wxSizeEvent
& evt
)
1967 wxSize s
= evt
.GetSize();
1968 wxRect
r(0, 0, s
.GetWidth(), s
.GetHeight());
1972 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent
& evt
)
1975 m_click_pt
= wxDefaultPosition
;
1976 m_is_dragging
= false;
1978 m_pressed_button
= NULL
;
1982 if (TabHitTest(evt
.m_x
, evt
.m_y
, &wnd
))
1984 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
1985 e
.SetSelection(GetIdxFromWindow(wnd
));
1986 e
.SetOldSelection(GetActivePage());
1987 e
.SetEventObject(this);
1988 GetEventHandler()->ProcessEvent(e
);
1990 m_click_pt
.x
= evt
.m_x
;
1991 m_click_pt
.y
= evt
.m_y
;
1997 m_pressed_button
= m_hover_button
;
1998 m_pressed_button
->cur_state
= wxAUI_BUTTON_STATE_PRESSED
;
2004 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent
& evt
)
2006 if (GetCapture() == this)
2011 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
, m_windowId
);
2012 evt
.SetSelection(GetIdxFromWindow(m_click_tab
));
2013 evt
.SetOldSelection(evt
.GetSelection());
2014 evt
.SetEventObject(this);
2015 GetEventHandler()->ProcessEvent(evt
);
2019 if (m_pressed_button
)
2021 // make sure we're still clicking the button
2022 wxAuiTabContainerButton
* button
= NULL
;
2023 if (!ButtonHitTest(evt
.m_x
, evt
.m_y
, &button
))
2026 if (button
!= m_pressed_button
)
2028 m_pressed_button
= NULL
;
2035 if (!(m_pressed_button
->cur_state
& wxAUI_BUTTON_STATE_DISABLED
))
2037 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON
, m_windowId
);
2038 evt
.SetInt(m_pressed_button
->id
);
2039 evt
.SetEventObject(this);
2040 GetEventHandler()->ProcessEvent(evt
);
2043 m_pressed_button
= NULL
;
2046 m_click_pt
= wxDefaultPosition
;
2047 m_is_dragging
= false;
2051 void wxAuiTabCtrl::OnMotion(wxMouseEvent
& evt
)
2053 wxPoint pos
= evt
.GetPosition();
2055 // check if the mouse is hovering above a button
2056 wxAuiTabContainerButton
* button
;
2057 if (ButtonHitTest(pos
.x
, pos
.y
, &button
))
2059 if (m_hover_button
&& button
!= m_hover_button
)
2061 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
2062 m_hover_button
= NULL
;
2067 if (button
->cur_state
!= wxAUI_BUTTON_STATE_HOVER
)
2069 button
->cur_state
= wxAUI_BUTTON_STATE_HOVER
;
2072 m_hover_button
= button
;
2080 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
2081 m_hover_button
= NULL
;
2088 if (!evt
.LeftIsDown() || m_click_pt
== wxDefaultPosition
)
2093 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
, m_windowId
);
2094 evt
.SetSelection(GetIdxFromWindow(m_click_tab
));
2095 evt
.SetOldSelection(evt
.GetSelection());
2096 evt
.SetEventObject(this);
2097 GetEventHandler()->ProcessEvent(evt
);
2102 int drag_x_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_X
);
2103 int drag_y_threshold
= wxSystemSettings::GetMetric(wxSYS_DRAG_Y
);
2105 if (abs(pos
.x
- m_click_pt
.x
) > drag_x_threshold
||
2106 abs(pos
.y
- m_click_pt
.y
) > drag_y_threshold
)
2108 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
, m_windowId
);
2109 evt
.SetSelection(GetIdxFromWindow(m_click_tab
));
2110 evt
.SetOldSelection(evt
.GetSelection());
2111 evt
.SetEventObject(this);
2112 GetEventHandler()->ProcessEvent(evt
);
2114 m_is_dragging
= true;
2118 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent
& WXUNUSED(event
))
2122 m_hover_button
->cur_state
= wxAUI_BUTTON_STATE_NORMAL
;
2123 m_hover_button
= NULL
;
2129 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent
& event
)
2131 int button
= event
.GetInt();
2133 if (button
== wxAUI_BUTTON_LEFT
|| button
== wxAUI_BUTTON_RIGHT
)
2135 if (button
== wxAUI_BUTTON_LEFT
)
2137 if (GetTabOffset() > 0)
2139 SetTabOffset(GetTabOffset()-1);
2146 SetTabOffset(GetTabOffset()+1);
2151 else if (button
== wxAUI_BUTTON_WINDOWLIST
)
2155 size_t i
, page_count
= m_pages
.GetCount();
2156 for (i
= 0; i
< page_count
; ++i
)
2158 wxAuiNotebookPage
& page
= m_pages
.Item(i
);
2159 as
.Add(page
.caption
);
2162 int idx
= GetArtProvider()->ShowWindowList(this, as
, GetActivePage());
2166 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
2167 e
.SetSelection(idx
);
2168 e
.SetOldSelection(GetActivePage());
2169 e
.SetEventObject(this);
2170 GetEventHandler()->ProcessEvent(e
);
2179 // wxTabFrame is an interesting case. It's important that all child pages
2180 // of the multi-notebook control are all actually children of that control
2181 // (and not grandchildren). wxTabFrame facilitates this. There is one
2182 // instance of wxTabFrame for each tab control inside the multi-notebook.
2183 // It's important to know that wxTabFrame is not a real window, but it merely
2184 // used to capture the dimensions/positioning of the internal tab control and
2185 // it's managed page windows
2187 class wxTabFrame
: public wxWindow
2194 m_rect
= wxRect(0,0,200,200);
2195 m_tab_ctrl_height
= 20;
2198 void SetTabCtrlHeight(int h
)
2200 m_tab_ctrl_height
= h
;
2203 void DoSetSize(int x
, int y
,
2204 int width
, int height
,
2205 int WXUNUSED(sizeFlags
= wxSIZE_AUTO
))
2207 m_rect
= wxRect(x
, y
, width
, height
);
2211 void DoGetClientSize(int* x
, int* y
) const
2217 bool Show( bool WXUNUSED(show
= true) ) { return false; }
2224 m_tab_rect
= wxRect(m_rect
.x
, m_rect
.y
, m_rect
.width
, m_tab_ctrl_height
);
2225 m_tabs
->SetSize(m_rect
.x
, m_rect
.y
, m_rect
.width
, m_tab_ctrl_height
);
2226 m_tabs
->SetRect(wxRect(0, 0, m_rect
.width
, m_tab_ctrl_height
));
2230 wxAuiNotebookPageArray
& pages
= m_tabs
->GetPages();
2231 size_t i
, page_count
= pages
.GetCount();
2233 for (i
= 0; i
< page_count
; ++i
)
2235 wxAuiNotebookPage
& page
= pages
.Item(i
);
2236 page
.window
->SetSize(m_rect
.x
, m_rect
.y
+ m_tab_ctrl_height
,
2237 m_rect
.width
, m_rect
.height
- m_tab_ctrl_height
);
2239 if (page
.window
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
2241 wxAuiMDIChildFrame
* wnd
= (wxAuiMDIChildFrame
*)page
.window
;
2242 wnd
->ApplyMDIChildFrameRect();
2247 void DoGetSize(int* x
, int* y
) const
2250 *x
= m_rect
.GetWidth();
2252 *y
= m_rect
.GetHeight();
2264 wxAuiTabCtrl
* m_tabs
;
2265 int m_tab_ctrl_height
;
2272 // -- wxAuiNotebook class implementation --
2274 BEGIN_EVENT_TABLE(wxAuiNotebook
, wxControl
)
2275 //EVT_ERASE_BACKGROUND(wxAuiNotebook::OnEraseBackground)
2276 //EVT_SIZE(wxAuiNotebook::OnSize)
2277 //EVT_LEFT_DOWN(wxAuiNotebook::OnLeftDown)
2278 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus
)
2279 EVT_COMMAND_RANGE(10000, 10100,
2280 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
,
2281 wxAuiNotebook::OnTabClicked
)
2282 EVT_COMMAND_RANGE(10000, 10100,
2283 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG
,
2284 wxAuiNotebook::OnTabBeginDrag
)
2285 EVT_COMMAND_RANGE(10000, 10100,
2286 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG
,
2287 wxAuiNotebook::OnTabEndDrag
)
2288 EVT_COMMAND_RANGE(10000, 10100,
2289 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION
,
2290 wxAuiNotebook::OnTabDragMotion
)
2291 EVT_COMMAND_RANGE(10000, 10100,
2292 wxEVT_COMMAND_AUINOTEBOOK_BUTTON
,
2293 wxAuiNotebook::OnTabButton
)
2296 wxAuiNotebook::wxAuiNotebook()
2299 m_tab_id_counter
= 10000;
2301 m_tab_ctrl_height
= 20;
2304 wxAuiNotebook::wxAuiNotebook(wxWindow
*parent
,
2308 long style
) : wxControl(parent
, id
, pos
, size
, style
)
2310 InitNotebook(style
);
2313 bool wxAuiNotebook::Create(wxWindow
* parent
,
2319 if (!wxControl::Create(parent
, id
, pos
, size
, style
))
2322 InitNotebook(style
);
2327 // InitNotebook() contains common initialization
2328 // code called by all constructors
2329 void wxAuiNotebook::InitNotebook(long style
)
2332 m_tab_id_counter
= 10000;
2334 m_tab_ctrl_height
= 20;
2335 m_flags
= (unsigned int)style
;
2337 m_normal_font
= *wxNORMAL_FONT
;
2338 m_selected_font
= *wxNORMAL_FONT
;
2339 m_selected_font
.SetWeight(wxBOLD
);
2341 SetArtProvider(new wxAuiDefaultTabArt
);
2343 m_dummy_wnd
= new wxWindow(this, wxID_ANY
, wxPoint(0,0), wxSize(0,0));
2344 m_dummy_wnd
->SetSize(200, 200);
2345 m_dummy_wnd
->Show(false);
2347 m_mgr
.SetManagedWindow(this);
2349 m_mgr
.AddPane(m_dummy_wnd
,
2350 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
2355 wxAuiNotebook::~wxAuiNotebook()
2360 void wxAuiNotebook::SetArtProvider(wxAuiTabArt
* art
)
2362 m_tabs
.SetArtProvider(art
);
2364 SetTabCtrlHeight(CalculateTabCtrlHeight());
2367 void wxAuiNotebook::SetTabCtrlHeight(int height
)
2369 // if the tab control height needs to change, update
2370 // all of our tab controls with the new height
2371 if (m_tab_ctrl_height
!= height
)
2373 wxAuiTabArt
* art
= m_tabs
.GetArtProvider();
2375 m_tab_ctrl_height
= height
;
2377 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2378 size_t i
, pane_count
= all_panes
.GetCount();
2379 for (i
= 0; i
< pane_count
; ++i
)
2381 wxAuiPaneInfo
& pane
= all_panes
.Item(i
);
2382 if (pane
.name
== wxT("dummy"))
2384 wxTabFrame
* tab_frame
= (wxTabFrame
*)pane
.window
;
2385 wxAuiTabCtrl
* tabctrl
= tab_frame
->m_tabs
;
2386 tab_frame
->SetTabCtrlHeight(m_tab_ctrl_height
);
2387 tabctrl
->SetArtProvider(art
->Clone());
2388 tab_frame
->DoSizing();
2393 int wxAuiNotebook::CalculateTabCtrlHeight()
2395 // find out new best tab height
2396 wxAuiTabArt
* art
= m_tabs
.GetArtProvider();
2398 return art
->GetBestTabCtrlSize(this, m_tabs
.GetPages());
2402 wxAuiTabArt
* wxAuiNotebook::GetArtProvider() const
2404 return m_tabs
.GetArtProvider();
2407 void wxAuiNotebook::SetWindowStyleFlag(long style
)
2409 wxControl::SetWindowStyleFlag(style
);
2411 m_flags
= (unsigned int)style
;
2413 // if the control is already initialized
2414 if (m_mgr
.GetManagedWindow() == (wxWindow
*)this)
2416 // let all of the tab children know about the new style
2418 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2419 size_t i
, pane_count
= all_panes
.GetCount();
2420 for (i
= 0; i
< pane_count
; ++i
)
2422 wxAuiPaneInfo
& pane
= all_panes
.Item(i
);
2423 if (pane
.name
== wxT("dummy"))
2425 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
2426 tabctrl
->SetFlags(m_flags
);
2434 bool wxAuiNotebook::AddPage(wxWindow
* page
,
2435 const wxString
& caption
,
2437 const wxBitmap
& bitmap
)
2439 return InsertPage(GetPageCount(), page
, caption
, select
, bitmap
);
2442 bool wxAuiNotebook::InsertPage(size_t page_idx
,
2444 const wxString
& caption
,
2446 const wxBitmap
& bitmap
)
2448 wxAuiNotebookPage info
;
2450 info
.caption
= caption
;
2451 info
.bitmap
= bitmap
;
2452 info
.active
= false;
2454 // if there are currently no tabs, the first added
2455 // tab must be active
2456 if (m_tabs
.GetPageCount() == 0)
2459 m_tabs
.InsertPage(page
, info
, page_idx
);
2461 wxAuiTabCtrl
* active_tabctrl
= GetActiveTabCtrl();
2462 if (page_idx
>= active_tabctrl
->GetPageCount())
2463 active_tabctrl
->AddPage(page
, info
);
2465 active_tabctrl
->InsertPage(page
, info
, page_idx
);
2467 SetTabCtrlHeight(CalculateTabCtrlHeight());
2469 active_tabctrl
->DoShowHide();
2473 int idx
= m_tabs
.GetIdxFromWindow(page
);
2474 wxASSERT_MSG(idx
!= -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()"));
2483 // DeletePage() removes a tab from the multi-notebook,
2484 // and destroys the window as well
2485 bool wxAuiNotebook::DeletePage(size_t page_idx
)
2487 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
2489 if (!RemovePage(page_idx
))
2493 // actually destroy the window now
2494 if (wnd
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
2496 // delete the child frame with pending delete, as is
2497 // customary with frame windows
2498 if (!wxPendingDelete
.Member(wnd
))
2499 wxPendingDelete
.Append(wnd
);
2511 // RemovePage() removes a tab from the multi-notebook,
2512 // but does not destroy the window
2513 bool wxAuiNotebook::RemovePage(size_t page_idx
)
2515 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(page_idx
);
2516 wxWindow
* new_active
= NULL
;
2518 // find out which onscreen tab ctrl owns this tab
2521 if (!FindTab(wnd
, &ctrl
, &ctrl_idx
))
2524 // find a new page and set it as active
2525 int new_idx
= ctrl_idx
+1;
2526 if (new_idx
>= (int)ctrl
->GetPageCount())
2527 new_idx
= ctrl_idx
-1;
2529 if (new_idx
>= 0 && new_idx
< (int)ctrl
->GetPageCount())
2531 new_active
= ctrl
->GetWindowFromIdx(new_idx
);
2535 // set the active page to the first page that
2536 // isn't the one being deleted
2537 size_t i
, page_count
= m_tabs
.GetPageCount();
2538 for (i
= 0; i
< page_count
; ++i
)
2540 wxWindow
* w
= m_tabs
.GetWindowFromIdx(i
);
2543 new_active
= m_tabs
.GetWindowFromIdx(i
);
2549 // remove the tab from main catalog
2550 if (!m_tabs
.RemovePage(wnd
))
2553 // remove the tab from the onscreen tab ctrl
2554 ctrl
->RemovePage(wnd
);
2557 RemoveEmptyTabFrames();
2559 // set new active pane
2563 SetSelection(m_tabs
.GetIdxFromWindow(new_active
));
2569 // GetPageIndex() returns the index of the page, or -1 if the
2570 // page could not be located in the notebook
2571 int wxAuiNotebook::GetPageIndex(wxWindow
* page_wnd
) const
2573 return m_tabs
.GetIdxFromWindow(page_wnd
);
2578 // SetPageText() changes the tab caption of the specified page
2579 bool wxAuiNotebook::SetPageText(size_t page_idx
, const wxString
& text
)
2581 if (page_idx
>= m_tabs
.GetPageCount())
2584 // update our own tab catalog
2585 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
2586 page_info
.caption
= text
;
2588 // update what's on screen
2591 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
2593 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
2594 info
.caption
= text
;
2603 bool wxAuiNotebook::SetPageBitmap(size_t page_idx
, const wxBitmap
& bitmap
)
2605 if (page_idx
>= m_tabs
.GetPageCount())
2608 // update our own tab catalog
2609 wxAuiNotebookPage
& page_info
= m_tabs
.GetPage(page_idx
);
2610 page_info
.bitmap
= bitmap
;
2612 // tab height might have changed
2613 SetTabCtrlHeight(CalculateTabCtrlHeight());
2615 // update what's on screen
2618 if (FindTab(page_info
.window
, &ctrl
, &ctrl_idx
))
2620 wxAuiNotebookPage
& info
= ctrl
->GetPage(ctrl_idx
);
2621 info
.bitmap
= bitmap
;
2630 // GetSelection() returns the index of the currently active page
2631 int wxAuiNotebook::GetSelection() const
2636 // SetSelection() sets the currently active page
2637 size_t wxAuiNotebook::SetSelection(size_t new_page
)
2639 wxWindow
* wnd
= m_tabs
.GetWindowFromIdx(new_page
);
2643 wxAuiNotebookEvent
evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING
, m_windowId
);
2644 evt
.SetSelection(new_page
);
2645 evt
.SetOldSelection(m_curpage
);
2646 evt
.SetEventObject(this);
2647 if (!GetEventHandler()->ProcessEvent(evt
) || evt
.IsAllowed())
2649 // program allows the page change
2650 evt
.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED
);
2651 (void)GetEventHandler()->ProcessEvent(evt
);
2657 if (FindTab(wnd
, &ctrl
, &ctrl_idx
))
2659 m_tabs
.SetActivePage(wnd
);
2661 ctrl
->SetActivePage(ctrl_idx
);
2665 int old_curpage
= m_curpage
;
2666 m_curpage
= new_page
;
2670 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2671 size_t i
, pane_count
= all_panes
.GetCount();
2672 for (i
= 0; i
< pane_count
; ++i
)
2674 wxAuiPaneInfo
& pane
= all_panes
.Item(i
);
2675 if (pane
.name
== wxT("dummy"))
2677 wxAuiTabCtrl
* tabctrl
= ((wxTabFrame
*)pane
.window
)->m_tabs
;
2678 if (tabctrl
!= ctrl
)
2679 tabctrl
->SetSelectedFont(m_normal_font
);
2681 tabctrl
->SetSelectedFont(m_selected_font
);
2694 // GetPageCount() returns the total number of
2695 // pages managed by the multi-notebook
2696 size_t wxAuiNotebook::GetPageCount() const
2698 return m_tabs
.GetPageCount();
2701 // GetPage() returns the wxWindow pointer of the
2703 wxWindow
* wxAuiNotebook::GetPage(size_t page_idx
) const
2705 wxASSERT(page_idx
< m_tabs
.GetPageCount());
2707 return m_tabs
.GetWindowFromIdx(page_idx
);
2710 // DoSizing() performs all sizing operations in each tab control
2711 void wxAuiNotebook::DoSizing()
2713 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2714 size_t i
, pane_count
= all_panes
.GetCount();
2715 for (i
= 0; i
< pane_count
; ++i
)
2717 if (all_panes
.Item(i
).name
== wxT("dummy"))
2720 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
2721 tabframe
->DoSizing();
2725 // GetActiveTabCtrl() returns the active tab control. It is
2726 // called to determine which control gets new windows being added
2727 wxAuiTabCtrl
* wxAuiNotebook::GetActiveTabCtrl()
2729 if (m_curpage
>= 0 && m_curpage
< (int)m_tabs
.GetPageCount())
2734 // find the tab ctrl with the current page
2735 if (FindTab(m_tabs
.GetPage(m_curpage
).window
,
2742 // no current page, just find the first tab ctrl
2743 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2744 size_t i
, pane_count
= all_panes
.GetCount();
2745 for (i
= 0; i
< pane_count
; ++i
)
2747 if (all_panes
.Item(i
).name
== wxT("dummy"))
2750 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
2751 return tabframe
->m_tabs
;
2754 // If there is no tabframe at all, create one
2755 wxTabFrame
* tabframe
= new wxTabFrame
;
2756 tabframe
->SetTabCtrlHeight(m_tab_ctrl_height
);
2757 tabframe
->m_tabs
= new wxAuiTabCtrl(this,
2762 tabframe
->m_tabs
->SetFlags(m_flags
);
2763 tabframe
->m_tabs
->SetArtProvider(m_tabs
.GetArtProvider()->Clone());
2764 m_mgr
.AddPane(tabframe
,
2765 wxAuiPaneInfo().Center().CaptionVisible(false));
2769 return tabframe
->m_tabs
;
2772 // FindTab() finds the tab control that currently contains the window as well
2773 // as the index of the window in the tab control. It returns true if the
2774 // window was found, otherwise false.
2775 bool wxAuiNotebook::FindTab(wxWindow
* page
, wxAuiTabCtrl
** ctrl
, int* idx
)
2777 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
2778 size_t i
, pane_count
= all_panes
.GetCount();
2779 for (i
= 0; i
< pane_count
; ++i
)
2781 if (all_panes
.Item(i
).name
== wxT("dummy"))
2784 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
2786 int page_idx
= tabframe
->m_tabs
->GetIdxFromWindow(page
);
2789 *ctrl
= tabframe
->m_tabs
;
2799 void wxAuiNotebook::OnEraseBackground(wxEraseEvent
&)
2803 void wxAuiNotebook::OnSize(wxSizeEvent
&)
2807 void wxAuiNotebook::OnTabClicked(wxCommandEvent
& command_evt
)
2809 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
2811 wxAuiTabCtrl
* ctrl
= (wxAuiTabCtrl
*)evt
.GetEventObject();
2812 wxASSERT(ctrl
!= NULL
);
2814 wxWindow
* wnd
= ctrl
->GetWindowFromIdx(evt
.GetSelection());
2815 wxASSERT(wnd
!= NULL
);
2817 int idx
= m_tabs
.GetIdxFromWindow(wnd
);
2818 wxASSERT(idx
!= -1);
2823 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent
&)
2828 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent
& evt
)
2830 wxPoint screen_pt
= ::wxGetMousePosition();
2831 wxPoint client_pt
= ScreenToClient(screen_pt
);
2834 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
2835 wxAuiTabCtrl
* dest_tabs
= GetTabCtrlFromPoint(client_pt
);
2837 if (dest_tabs
== src_tabs
)
2841 src_tabs
->SetCursor(wxCursor(wxCURSOR_ARROW
));
2844 // always hide the hint for inner-tabctrl drag
2847 // if tab moving is not allowed, leave
2848 if (!(m_flags
& wxAUI_NB_TAB_MOVE
))
2853 wxPoint pt
= dest_tabs
->ScreenToClient(screen_pt
);
2854 wxWindow
* dest_location_tab
;
2856 // this is an inner-tab drag/reposition
2857 if (dest_tabs
->TabHitTest(pt
.x
, pt
.y
, &dest_location_tab
))
2859 int src_idx
= evt
.GetSelection();
2860 int dest_idx
= dest_tabs
->GetIdxFromWindow(dest_location_tab
);
2862 // prevent jumpy drag
2863 if ((src_idx
== dest_idx
) || dest_idx
== -1 ||
2864 (src_idx
> dest_idx
&& m_last_drag_x
<= pt
.x
) ||
2865 (src_idx
< dest_idx
&& m_last_drag_x
>= pt
.x
))
2867 m_last_drag_x
= pt
.x
;
2872 wxWindow
* src_tab
= dest_tabs
->GetWindowFromIdx(src_idx
);
2873 dest_tabs
->MovePage(src_tab
, dest_idx
);
2874 dest_tabs
->SetActivePage((size_t)dest_idx
);
2875 dest_tabs
->DoShowHide();
2876 dest_tabs
->Refresh();
2877 m_last_drag_x
= pt
.x
;
2885 // if external drag is allowed, check if the tab is being dragged
2886 // over a different wxAuiNotebook control
2887 if (m_flags
& wxAUI_NB_TAB_EXTERNAL_MOVE
)
2889 wxWindow
* tab_ctrl
= ::wxFindWindowAtPoint(screen_pt
);
2891 // if we aren't over any window, stop here
2895 // make sure we are not over the hint window
2896 if (!tab_ctrl
->IsKindOf(CLASSINFO(wxFrame
)))
2900 if (tab_ctrl
->IsKindOf(CLASSINFO(wxAuiTabCtrl
)))
2902 tab_ctrl
= tab_ctrl
->GetParent();
2907 wxAuiNotebook
* nb
= (wxAuiNotebook
*)tab_ctrl
->GetParent();
2911 wxRect hint_rect
= tab_ctrl
->GetClientRect();
2912 tab_ctrl
->ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
2913 m_mgr
.ShowHint(hint_rect
);
2922 // we are either over a hint window, or not over a tab
2923 // window, and there is no where to drag to, so exit
2930 // if there are less than two panes, split can't happen, so leave
2931 if (m_tabs
.GetPageCount() < 2)
2934 // if tab moving is not allowed, leave
2935 if (!(m_flags
& wxAUI_NB_TAB_SPLIT
))
2941 src_tabs
->SetCursor(wxCursor(wxCURSOR_SIZING
));
2947 wxRect hint_rect
= dest_tabs
->GetRect();
2948 ClientToScreen(&hint_rect
.x
, &hint_rect
.y
);
2949 m_mgr
.ShowHint(hint_rect
);
2953 m_mgr
.DrawHintRect(m_dummy_wnd
, client_pt
, zero
);
2959 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent
& command_evt
)
2961 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
2966 wxAuiTabCtrl
* src_tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
2967 wxAuiTabCtrl
* dest_tabs
= NULL
;
2970 // set cursor back to an arrow
2971 src_tabs
->SetCursor(wxCursor(wxCURSOR_ARROW
));
2974 // get the mouse position, which will be used to determine the drop point
2975 wxPoint mouse_screen_pt
= ::wxGetMousePosition();
2976 wxPoint mouse_client_pt
= ScreenToClient(mouse_screen_pt
);
2980 // check for an external move
2981 if (m_flags
& wxAUI_NB_TAB_EXTERNAL_MOVE
)
2983 wxWindow
* tab_ctrl
= ::wxFindWindowAtPoint(mouse_screen_pt
);
2987 if (tab_ctrl
->IsKindOf(CLASSINFO(wxAuiTabCtrl
)))
2989 tab_ctrl
= tab_ctrl
->GetParent();
2994 wxAuiNotebook
* nb
= (wxAuiNotebook
*)tab_ctrl
->GetParent();
2998 // find out from the destination control
2999 // if it's ok to drop this tab here
3000 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND
, m_windowId
);
3001 e
.SetSelection(evt
.GetSelection());
3002 e
.SetOldSelection(evt
.GetSelection());
3003 e
.SetEventObject(this);
3004 e
.SetDragSource(this);
3005 e
.Veto(); // dropping must be explicitly approved by control owner
3007 nb
->GetEventHandler()->ProcessEvent(e
);
3011 // no answer or negative answer
3017 int src_idx
= evt
.GetSelection();
3018 wxWindow
* src_page
= src_tabs
->GetWindowFromIdx(src_idx
);
3020 // get main index of the page
3021 int main_idx
= m_tabs
.GetIdxFromWindow(src_page
);
3023 // make a copy of the page info
3024 wxAuiNotebookPage page_info
= m_tabs
.GetPage((size_t)main_idx
);
3026 // remove the page from the source notebook
3027 RemovePage(main_idx
);
3029 // reparent the page
3030 src_page
->Reparent(nb
);
3033 // found out the insert idx
3034 wxAuiTabCtrl
* dest_tabs
= (wxAuiTabCtrl
*)tab_ctrl
;
3035 wxPoint pt
= dest_tabs
->ScreenToClient(mouse_screen_pt
);
3037 wxWindow
* target
= NULL
;
3038 int insert_idx
= -1;
3039 dest_tabs
->TabHitTest(pt
.x
, pt
.y
, &target
);
3042 insert_idx
= dest_tabs
->GetIdxFromWindow(target
);
3046 // add the page to the new notebook
3047 if (insert_idx
== -1)
3048 insert_idx
= dest_tabs
->GetPageCount();
3049 dest_tabs
->InsertPage(page_info
.window
, page_info
, insert_idx
);
3050 nb
->m_tabs
.AddPage(page_info
.window
, page_info
);
3053 dest_tabs
->DoShowHide();
3054 dest_tabs
->Refresh();
3056 // set the selection in the destination tab control
3057 nb
->SetSelection(nb
->m_tabs
.GetIdxFromWindow(page_info
.window
));
3067 // only perform a tab split if it's allowed
3068 if ((m_flags
& wxAUI_NB_TAB_SPLIT
) && m_tabs
.GetPageCount() >= 2)
3070 // If the pointer is in an existing tab frame, do a tab insert
3071 wxWindow
* hit_wnd
= ::wxFindWindowAtPoint(mouse_screen_pt
);
3072 wxTabFrame
* tab_frame
= (wxTabFrame
*)GetTabFrameFromTabCtrl(hit_wnd
);
3073 int insert_idx
= -1;
3076 dest_tabs
= tab_frame
->m_tabs
;
3078 if (dest_tabs
== src_tabs
)
3082 wxPoint pt
= dest_tabs
->ScreenToClient(mouse_screen_pt
);
3083 wxWindow
* target
= NULL
;
3084 dest_tabs
->TabHitTest(pt
.x
, pt
.y
, &target
);
3087 insert_idx
= dest_tabs
->GetIdxFromWindow(target
);
3092 // If there is no tabframe at all, create one
3093 wxTabFrame
* new_tabs
= new wxTabFrame
;
3094 new_tabs
->SetTabCtrlHeight(m_tab_ctrl_height
);
3095 new_tabs
->m_tabs
= new wxAuiTabCtrl(this,
3100 new_tabs
->m_tabs
->SetArtProvider(m_tabs
.GetArtProvider()->Clone());
3101 new_tabs
->m_tabs
->SetFlags(m_flags
);
3103 m_mgr
.AddPane(new_tabs
,
3104 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3107 dest_tabs
= new_tabs
->m_tabs
;
3112 // remove the page from the source tabs
3113 wxAuiNotebookPage page_info
= src_tabs
->GetPage(evt
.GetSelection());
3114 page_info
.active
= false;
3115 src_tabs
->RemovePage(page_info
.window
);
3116 if (src_tabs
->GetPageCount() > 0)
3118 src_tabs
->SetActivePage((size_t)0);
3119 src_tabs
->DoShowHide();
3120 src_tabs
->Refresh();
3125 // add the page to the destination tabs
3126 if (insert_idx
== -1)
3127 insert_idx
= dest_tabs
->GetPageCount();
3128 dest_tabs
->InsertPage(page_info
.window
, page_info
, insert_idx
);
3130 if (src_tabs
->GetPageCount() == 0)
3132 RemoveEmptyTabFrames();
3136 dest_tabs
->DoShowHide();
3137 dest_tabs
->Refresh();
3139 SetSelection(m_tabs
.GetIdxFromWindow(page_info
.window
));
3145 wxAuiTabCtrl
* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint
& pt
)
3147 // if we've just removed the last tab from the source
3148 // tab set, the remove the tab control completely
3149 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
3150 size_t i
, pane_count
= all_panes
.GetCount();
3151 for (i
= 0; i
< pane_count
; ++i
)
3153 if (all_panes
.Item(i
).name
== wxT("dummy"))
3156 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
3157 if (tabframe
->m_tab_rect
.Contains(pt
))
3158 return tabframe
->m_tabs
;
3164 wxWindow
* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow
* tab_ctrl
)
3166 // if we've just removed the last tab from the source
3167 // tab set, the remove the tab control completely
3168 wxAuiPaneInfoArray
& all_panes
= m_mgr
.GetAllPanes();
3169 size_t i
, pane_count
= all_panes
.GetCount();
3170 for (i
= 0; i
< pane_count
; ++i
)
3172 if (all_panes
.Item(i
).name
== wxT("dummy"))
3175 wxTabFrame
* tabframe
= (wxTabFrame
*)all_panes
.Item(i
).window
;
3176 if (tabframe
->m_tabs
== tab_ctrl
)
3185 void wxAuiNotebook::RemoveEmptyTabFrames()
3187 // if we've just removed the last tab from the source
3188 // tab set, the remove the tab control completely
3189 wxAuiPaneInfoArray all_panes
= m_mgr
.GetAllPanes();
3190 size_t i
, pane_count
= all_panes
.GetCount();
3191 for (i
= 0; i
< pane_count
; ++i
)
3193 if (all_panes
.Item(i
).name
== wxT("dummy"))
3196 wxTabFrame
* tab_frame
= (wxTabFrame
*)all_panes
.Item(i
).window
;
3197 if (tab_frame
->m_tabs
->GetPageCount() == 0)
3199 m_mgr
.DetachPane(tab_frame
);
3201 // use pending delete because sometimes during
3202 // window closing, refreshs are pending
3203 if (!wxPendingDelete
.Member(tab_frame
->m_tabs
))
3204 wxPendingDelete
.Append(tab_frame
->m_tabs
);
3205 //tab_frame->m_tabs->Destroy();
3212 // check to see if there is still a center pane;
3213 // if there isn't, make a frame the center pane
3214 wxAuiPaneInfoArray panes
= m_mgr
.GetAllPanes();
3215 pane_count
= panes
.GetCount();
3216 wxWindow
* first_good
= NULL
;
3217 bool center_found
= false;
3218 for (i
= 0; i
< pane_count
; ++i
)
3220 if (panes
.Item(i
).name
== wxT("dummy"))
3222 if (panes
.Item(i
).dock_direction
== wxAUI_DOCK_CENTRE
)
3223 center_found
= true;
3225 first_good
= panes
.Item(i
).window
;
3228 if (!center_found
&& first_good
)
3230 m_mgr
.GetPane(first_good
).Centre();
3236 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent
& evt
)
3238 int idx
= m_tabs
.GetIdxFromWindow(evt
.GetWindow());
3239 if (idx
!= -1 && idx
!= m_curpage
)
3246 void wxAuiNotebook::OnTabButton(wxCommandEvent
& command_evt
)
3248 wxAuiNotebookEvent
& evt
= (wxAuiNotebookEvent
&)command_evt
;
3249 wxAuiTabCtrl
* tabs
= (wxAuiTabCtrl
*)evt
.GetEventObject();
3251 int button_id
= evt
.GetInt();
3253 if (button_id
== wxAUI_BUTTON_CLOSE
)
3255 int selection
= tabs
->GetActivePage();
3257 if (selection
!= -1)
3259 wxWindow
* close_wnd
= tabs
->GetWindowFromIdx(selection
);
3262 // ask owner if it's ok to close the tab
3263 wxAuiNotebookEvent
e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE
, m_windowId
);
3264 e
.SetSelection(m_tabs
.GetIdxFromWindow(close_wnd
));
3265 e
.SetOldSelection(evt
.GetSelection());
3266 e
.SetEventObject(this);
3267 GetEventHandler()->ProcessEvent(e
);
3272 if (close_wnd
->IsKindOf(CLASSINFO(wxAuiMDIChildFrame
)))
3278 int main_idx
= m_tabs
.GetIdxFromWindow(close_wnd
);
3279 DeletePage(main_idx
);