]> git.saurik.com Git - wxWidgets.git/blame - src/aui/auibook.cpp
added wxTo/FromString() overloads for wxFont (1st part of patch 1760073)
[wxWidgets.git] / src / aui / auibook.cpp
CommitLineData
cd05bf23 1///////////////////////////////////////////////////////////////////////////////
4444d148 2// Name: src/aui/auibook.cpp
cd05bf23
BW
3// Purpose: wxaui: wx advanced user interface - notebook
4// Author: Benjamin I. Williams
5// Modified by:
6// Created: 2006-06-28
7// Copyright: (C) Copyright 2006, Kirix Corporation, All Rights Reserved
8// Licence: wxWindows Library Licence, Version 3.1
9///////////////////////////////////////////////////////////////////////////////
10
11// ----------------------------------------------------------------------------
12// headers
13// ----------------------------------------------------------------------------
14
15#include "wx/wxprec.h"
16
17#ifdef __BORLANDC__
18 #pragma hdrstop
19#endif
20
21#if wxUSE_AUI
22
189da67c 23#include "wx/aui/auibook.h"
cd05bf23
BW
24
25#ifndef WX_PRECOMP
4444d148 26 #include "wx/settings.h"
03265113 27 #include "wx/image.h"
c58ba15f 28 #include "wx/menu.h"
cd05bf23
BW
29#endif
30
4444d148
WS
31#include "wx/aui/tabmdi.h"
32#include "wx/dcbuffer.h"
33
a51dc103
JS
34#ifdef __WXMAC__
35#include "wx/mac/carbon/private.h"
36#endif
37
cd05bf23
BW
38#include "wx/arrimpl.cpp"
39WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
40WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
41
3fd8c988 42DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE)
cd05bf23
BW
43DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING)
44DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
45DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
46DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
47DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
48DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
5d3aeb0f 49DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND)
69f5e420
BW
50DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP)
51DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN)
52DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP)
53DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN)
cd05bf23
BW
54
55
0ce53f32 56IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
5d3aeb0f 57IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl)
cd05bf23
BW
58IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
59
cd05bf23
BW
60
61
cd05bf23
BW
62
63
a500c7ed
BW
64// these functions live in dockart.cpp -- they'll eventually
65// be moved to a new utility cpp file
cd05bf23 66
a500c7ed
BW
67wxColor wxAuiStepColour(const wxColor& c, int percent);
68
69wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h,
70 const wxColour& color);
71
72wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size);
cd05bf23 73
b0d17f7c
BW
74static void DrawButtons(wxDC& dc,
75 const wxRect& _rect,
76 const wxBitmap& bmp,
77 const wxColour& bkcolour,
78 int button_state)
cd05bf23
BW
79{
80 wxRect rect = _rect;
81
82 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
83 {
84 rect.x++;
85 rect.y++;
86 }
87
88 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
89 button_state == wxAUI_BUTTON_STATE_PRESSED)
90 {
a500c7ed 91 dc.SetBrush(wxBrush(wxAuiStepColour(bkcolour, 120)));
8096c425 92 dc.SetPen(wxPen(wxAuiStepColour(bkcolour, 75)));
cd05bf23
BW
93
94 // draw the background behind the button
95 dc.DrawRectangle(rect.x, rect.y, 15, 15);
96 }
97
98 // draw the button itself
99 dc.DrawBitmap(bmp, rect.x, rect.y, true);
100}
101
b0d17f7c
BW
102static void IndentPressedBitmap(wxRect* rect, int button_state)
103{
104 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
105 {
106 rect->x++;
107 rect->y++;
108 }
109}
110
b0d17f7c
BW
111
112
113// -- GUI helper classes and functions --
114
115class wxAuiCommandCapture : public wxEvtHandler
116{
117public:
7baac3cb 118
b0d17f7c
BW
119 wxAuiCommandCapture() { m_last_id = 0; }
120 int GetCommandId() const { return m_last_id; }
121
122 bool ProcessEvent(wxEvent& evt)
123 {
124 if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
125 {
126 m_last_id = evt.GetId();
127 return true;
128 }
7baac3cb 129
b0d17f7c
BW
130 if (GetNextHandler())
131 return GetNextHandler()->ProcessEvent(evt);
132
133 return false;
134 }
7baac3cb 135
b0d17f7c
BW
136private:
137 int m_last_id;
138};
139
140
141// -- bitmaps --
142
143#if defined( __WXMAC__ )
144 static unsigned char close_bits[]={
145 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
146 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
147 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
7baac3cb
VZ
148#elif defined( __WXGTK__)
149 static unsigned char close_bits[]={
150 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
151 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
152 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
b0d17f7c
BW
153#else
154 static unsigned char close_bits[]={
8896cb72
BW
155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
156 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
b0d17f7c
BW
158#endif
159
160static unsigned char left_bits[] = {
161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
162 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
163 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
164
165static unsigned char right_bits[] = {
166 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
167 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
168 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
169
170static unsigned char list_bits[] = {
171 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
172 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
173 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
174
175
176
177
178
179
180// -- wxAuiDefaultTabArt class implementation --
181
182wxAuiDefaultTabArt::wxAuiDefaultTabArt()
183{
184 m_normal_font = *wxNORMAL_FONT;
185 m_selected_font = *wxNORMAL_FONT;
186 m_selected_font.SetWeight(wxBOLD);
187 m_measuring_font = m_selected_font;
7baac3cb 188
b0d17f7c 189 m_fixed_tab_width = 100;
2b9aac33 190 m_tab_ctrl_height = 0;
b0d17f7c 191
003cf4ef
BW
192#ifdef __WXMAC__
193 wxBrush toolbarbrush;
194 toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground );
195 wxColor base_colour = toolbarbrush.GetColour();
196#else
197 wxColor base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
198#endif
199
3f7fce73
BW
200 // the base_colour is too pale to use as our base colour,
201 // so darken it a bit --
202 if ((255-base_colour.Red()) +
203 (255-base_colour.Green()) +
204 (255-base_colour.Blue()) < 60)
205 {
206 base_colour = wxAuiStepColour(base_colour, 92);
207 }
c58ba15f 208
003cf4ef 209 m_base_colour = base_colour;
8096c425 210 wxColor border_colour = wxAuiStepColour(base_colour, 75);
7baac3cb 211
8096c425 212 m_border_pen = wxPen(border_colour);
1750e8e2
BW
213 m_base_colour_pen = wxPen(m_base_colour);
214 m_base_colour_brush = wxBrush(m_base_colour);
7baac3cb 215
a500c7ed
BW
216 m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
217 m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
7baac3cb 218
a500c7ed
BW
219 m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
220 m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
7baac3cb 221
a500c7ed
BW
222 m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
223 m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
7baac3cb 224
a500c7ed
BW
225 m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
226 m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
7baac3cb 227
b0d17f7c
BW
228 m_flags = 0;
229}
230
231wxAuiDefaultTabArt::~wxAuiDefaultTabArt()
232{
233}
234
235wxAuiTabArt* wxAuiDefaultTabArt::Clone()
236{
700614e0
JS
237 wxAuiDefaultTabArt* art = new wxAuiDefaultTabArt;
238 art->SetNormalFont(m_normal_font);
239 art->SetSelectedFont(m_selected_font);
240 art->SetMeasuringFont(m_measuring_font);
241
242 return art;
b0d17f7c
BW
243}
244
245void wxAuiDefaultTabArt::SetFlags(unsigned int flags)
246{
247 m_flags = flags;
248}
249
250void wxAuiDefaultTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
251 size_t tab_count)
252{
253 m_fixed_tab_width = 100;
7baac3cb 254
69685ee0 255 int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
c58ba15f 256
97ac2d5e
BW
257 if (m_flags & wxAUI_NB_CLOSE_BUTTON)
258 tot_width -= m_active_close_bmp.GetWidth();
259 if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
260 tot_width -= m_active_windowlist_bmp.GetWidth();
261
b0d17f7c
BW
262 if (tab_count > 0)
263 {
264 m_fixed_tab_width = tot_width/(int)tab_count;
265 }
7baac3cb
VZ
266
267
b0d17f7c
BW
268 if (m_fixed_tab_width < 100)
269 m_fixed_tab_width = 100;
7baac3cb 270
b0d17f7c
BW
271 if (m_fixed_tab_width > tot_width/2)
272 m_fixed_tab_width = tot_width/2;
7baac3cb 273
b0d17f7c
BW
274 if (m_fixed_tab_width > 220)
275 m_fixed_tab_width = 220;
7baac3cb 276
2b9aac33 277 m_tab_ctrl_height = tab_ctrl_size.y;
b0d17f7c 278}
7baac3cb
VZ
279
280
b0d17f7c
BW
281void wxAuiDefaultTabArt::DrawBackground(wxDC& dc,
282 wxWindow* WXUNUSED(wnd),
283 const wxRect& rect)
284{
285 // draw background
003cf4ef 286 wxRect r(rect.x, rect.y, rect.width+2, rect.height-3);
a500c7ed 287 wxColor top_color = wxAuiStepColour(m_base_colour, 90);
8096c425 288 wxColor bottom_color = wxAuiStepColour(m_base_colour, 170);
6a93539e 289 dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
7baac3cb 290
b0d17f7c 291 // draw base lines
003cf4ef
BW
292 int y = rect.GetHeight();
293 int w = rect.GetWidth();
294 dc.SetPen(m_border_pen);
6a93539e
BW
295 dc.SetBrush(m_base_colour_brush);
296 dc.DrawRectangle(-1, y-4, w+2, 4);
b0d17f7c
BW
297}
298
299
300// DrawTab() draws an individual tab.
301//
302// dc - output dc
303// in_rect - rectangle the tab should be confined to
304// caption - tab's caption
305// active - whether or not the tab is active
306// out_rect - actual output rectangle
307// x_extent - the advance x; where the next tab should start
308
309void wxAuiDefaultTabArt::DrawTab(wxDC& dc,
310 wxWindow* wnd,
793d4365 311 const wxAuiNotebookPage& page,
b0d17f7c 312 const wxRect& in_rect,
b0d17f7c
BW
313 int close_button_state,
314 wxRect* out_tab_rect,
315 wxRect* out_button_rect,
316 int* x_extent)
317{
318 wxCoord normal_textx, normal_texty;
319 wxCoord selected_textx, selected_texty;
cedd7b22 320 wxCoord texty;
7baac3cb 321
b0d17f7c 322 // if the caption is empty, measure some temporary text
793d4365
BW
323 wxString caption = page.caption;
324 if (caption.empty())
b0d17f7c 325 caption = wxT("Xj");
7baac3cb 326
b0d17f7c
BW
327 dc.SetFont(m_selected_font);
328 dc.GetTextExtent(caption, &selected_textx, &selected_texty);
7baac3cb 329
b0d17f7c
BW
330 dc.SetFont(m_normal_font);
331 dc.GetTextExtent(caption, &normal_textx, &normal_texty);
7baac3cb 332
b0d17f7c 333 // figure out the size of the tab
2b9aac33
BW
334 wxSize tab_size = GetTabSize(dc,
335 wnd,
793d4365
BW
336 page.caption,
337 page.bitmap,
338 page.active,
2b9aac33
BW
339 close_button_state,
340 x_extent);
341
342 wxCoord tab_height = m_tab_ctrl_height - 3;
b0d17f7c
BW
343 wxCoord tab_width = tab_size.x;
344 wxCoord tab_x = in_rect.x;
345 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
346
347
793d4365 348 caption = page.caption;
b0d17f7c 349
b0d17f7c
BW
350
351 // select pen, brush and font for the tab to be drawn
352
793d4365 353 if (page.active)
b0d17f7c 354 {
b0d17f7c 355 dc.SetFont(m_selected_font);
b0d17f7c
BW
356 texty = selected_texty;
357 }
cedd7b22 358 else
b0d17f7c 359 {
b0d17f7c 360 dc.SetFont(m_normal_font);
b0d17f7c
BW
361 texty = normal_texty;
362 }
363
7baac3cb 364
7c508bca 365 // create points that will make the tab outline
7baac3cb 366
519337de
BW
367 int clip_width = tab_width;
368 if (tab_x + clip_width > in_rect.x + in_rect.width)
369 clip_width = (in_rect.x + in_rect.width) - tab_x;
7baac3cb 370
8096c425 371/*
003cf4ef 372 wxPoint clip_points[6];
519337de
BW
373 clip_points[0] = wxPoint(tab_x, tab_y+tab_height-3);
374 clip_points[1] = wxPoint(tab_x, tab_y+2);
375 clip_points[2] = wxPoint(tab_x+2, tab_y);
376 clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y);
377 clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2);
378 clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3);
003cf4ef 379
eab9751b 380 // FIXME: these ports don't provide wxRegion ctor from array of points
0197bcdd 381#if !defined(__WXDFB__) && !defined(__WXCOCOA__)
003cf4ef 382 // set the clipping region for the tab --
7baac3cb 383 wxRegion clipping_region(WXSIZEOF(clip_points), clip_points);
003cf4ef 384 dc.SetClippingRegion(clipping_region);
0197bcdd 385#endif // !wxDFB && !wxCocoa
8096c425
BW
386*/
387 // since the above code above doesn't play well with WXDFB or WXCOCOA,
388 // we'll just use a rectangle for the clipping region for now --
389 dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3);
003cf4ef 390
c58ba15f 391
003cf4ef
BW
392 wxPoint border_points[6];
393 border_points[0] = wxPoint(tab_x, tab_y+tab_height-4);
394 border_points[1] = wxPoint(tab_x, tab_y+2);
395 border_points[2] = wxPoint(tab_x+2, tab_y);
396 border_points[3] = wxPoint(tab_x+tab_width-2, tab_y);
397 border_points[4] = wxPoint(tab_x+tab_width, tab_y+2);
398 border_points[5] = wxPoint(tab_x+tab_width, tab_y+tab_height-4);
399
7baac3cb 400
003cf4ef
BW
401 int drawn_tab_yoff = border_points[1].y;
402 int drawn_tab_height = border_points[0].y - border_points[1].y;
403
2b9aac33 404
793d4365 405 if (page.active)
003cf4ef 406 {
7baac3cb
VZ
407 // draw active tab
408
1750e8e2 409 // draw base background color
003cf4ef
BW
410 wxRect r(tab_x, tab_y, tab_width, tab_height);
411 dc.SetPen(m_base_colour_pen);
412 dc.SetBrush(m_base_colour_brush);
8096c425 413 dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4);
7baac3cb 414
003cf4ef 415 // this white helps fill out the gradient at the top of the tab
1750e8e2
BW
416 dc.SetPen(*wxWHITE_PEN);
417 dc.SetBrush(*wxWHITE_BRUSH);
8096c425 418 dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4);
7baac3cb 419
003cf4ef
BW
420 // these two points help the rounded corners appear more antialiased
421 dc.SetPen(m_base_colour_pen);
6a93539e
BW
422 dc.DrawPoint(r.x+2, r.y+1);
423 dc.DrawPoint(r.x+r.width-2, r.y+1);
7baac3cb 424
1750e8e2
BW
425 // set rectangle down a bit for gradient drawing
426 r.SetHeight(r.GetHeight()/2);
003cf4ef
BW
427 r.x += 2;
428 r.width -= 2;
1750e8e2 429 r.y += r.height;
6a93539e 430 r.y -= 2;
7baac3cb 431
1750e8e2 432 // draw gradient background
6a93539e
BW
433 wxColor top_color = *wxWHITE;
434 wxColor bottom_color = m_base_colour;
435 dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
b0d17f7c 436 }
cedd7b22 437 else
1750e8e2
BW
438 {
439 // draw inactive tab
7baac3cb 440
1750e8e2 441 wxRect r(tab_x, tab_y+1, tab_width, tab_height-3);
7baac3cb 442
1750e8e2
BW
443 // start the gradent up a bit and leave the inside border inset
444 // by a pixel for a 3D look. Only the top half of the inactive
445 // tab will have a slight gradient
6a93539e
BW
446 r.x += 3;
447 r.y++;
448 r.width -= 4;
1750e8e2 449 r.height /= 2;
6a93539e 450 r.height--;
c58ba15f 451
6a93539e 452 // -- draw top gradient fill for glossy look
1750e8e2 453 wxColor top_color = m_base_colour;
8096c425 454 wxColor bottom_color = wxAuiStepColour(top_color, 160);
1750e8e2 455 dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
c58ba15f 456
6a93539e
BW
457 r.y += r.height;
458 r.y--;
c58ba15f 459
6a93539e
BW
460 // -- draw bottom fill for glossy look
461 top_color = m_base_colour;
462 bottom_color = m_base_colour;
463 dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
1750e8e2 464 }
7baac3cb
VZ
465
466 // draw tab outline
003cf4ef 467 dc.SetPen(m_border_pen);
b0d17f7c 468 dc.SetBrush(*wxTRANSPARENT_BRUSH);
7baac3cb
VZ
469 dc.DrawPolygon(WXSIZEOF(border_points), border_points);
470
7c508bca
BW
471 // there are two horizontal grey lines at the bottom of the tab control,
472 // this gets rid of the top one of those lines in the tab control
793d4365 473 if (page.active)
b0d17f7c 474 {
6a93539e
BW
475 dc.SetPen(m_base_colour_pen);
476 dc.DrawLine(border_points[0].x+1,
003cf4ef 477 border_points[0].y,
6a93539e 478 border_points[5].x,
003cf4ef 479 border_points[5].y);
b0d17f7c 480 }
7baac3cb 481
b0d17f7c 482
2b9aac33 483 int text_offset = tab_x + 8;
b0d17f7c 484 int close_button_width = 0;
b0d17f7c
BW
485 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
486 {
487 close_button_width = m_active_close_bmp.GetWidth();
488 }
7baac3cb
VZ
489
490
793d4365 491 if (page.bitmap.IsOk())
2b9aac33
BW
492 {
493 int bitmap_offset = tab_x + 8;
7baac3cb 494
2b9aac33 495 // draw bitmap
793d4365 496 dc.DrawBitmap(page.bitmap,
2b9aac33 497 bitmap_offset,
793d4365 498 drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
2b9aac33 499 true);
7baac3cb 500
793d4365 501 text_offset = bitmap_offset + page.bitmap.GetWidth();
2b9aac33
BW
502 text_offset += 3; // bitmap padding
503 }
cedd7b22 504 else
2b9aac33
BW
505 {
506 text_offset = tab_x + 8;
507 }
7baac3cb 508
b0d17f7c 509
a500c7ed 510 wxString draw_text = wxAuiChopText(dc,
b0d17f7c
BW
511 caption,
512 tab_width - (text_offset-tab_x) - close_button_width);
7baac3cb 513
b0d17f7c
BW
514 // draw tab text
515 dc.DrawText(draw_text,
516 text_offset,
2b9aac33 517 drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1);
b0d17f7c
BW
518
519
520
521
522 // draw close button if necessary
523 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
524 {
525 wxBitmap bmp = m_disabled_close_bmp;
526
527 if (close_button_state == wxAUI_BUTTON_STATE_HOVER ||
528 close_button_state == wxAUI_BUTTON_STATE_PRESSED)
529 {
530 bmp = m_active_close_bmp;
531 }
7baac3cb 532
b0d17f7c
BW
533 wxRect rect(tab_x + tab_width - close_button_width - 1,
534 tab_y + (tab_height/2) - (bmp.GetHeight()/2),
535 close_button_width,
536 tab_height);
537 IndentPressedBitmap(&rect, close_button_state);
538 dc.DrawBitmap(bmp, rect.x, rect.y, true);
7baac3cb 539
b0d17f7c
BW
540 *out_button_rect = rect;
541 }
7baac3cb 542
b0d17f7c 543 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
7baac3cb 544
b0d17f7c
BW
545 dc.DestroyClippingRegion();
546}
547
548int wxAuiDefaultTabArt::GetIndentSize()
549{
550 return 5;
551}
552
553wxSize wxAuiDefaultTabArt::GetTabSize(wxDC& dc,
554 wxWindow* WXUNUSED(wnd),
555 const wxString& caption,
2b9aac33 556 const wxBitmap& bitmap,
b0d17f7c
BW
557 bool WXUNUSED(active),
558 int close_button_state,
559 int* x_extent)
560{
561 wxCoord measured_textx, measured_texty, tmp;
7baac3cb 562
b0d17f7c
BW
563 dc.SetFont(m_measuring_font);
564 dc.GetTextExtent(caption, &measured_textx, &measured_texty);
7baac3cb 565
b0d17f7c 566 dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty);
7baac3cb 567
213e64e9 568 // add padding around the text
2b9aac33
BW
569 wxCoord tab_width = measured_textx;
570 wxCoord tab_height = measured_texty;
b0d17f7c 571
2b9aac33 572 // if the close button is showing, add space for it
b0d17f7c 573 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
213e64e9 574 tab_width += m_active_close_bmp.GetWidth() + 3;
b0d17f7c 575
2b9aac33
BW
576 // if there's a bitmap, add space for it
577 if (bitmap.IsOk())
578 {
579 tab_width += bitmap.GetWidth();
580 tab_width += 3; // right side bitmap padding
581 tab_height = wxMax(tab_height, bitmap.GetHeight());
582 }
583
584 // add padding
585 tab_width += 16;
586 tab_height += 10;
b0d17f7c
BW
587
588 if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
589 {
590 tab_width = m_fixed_tab_width;
591 }
7baac3cb 592
b0d17f7c 593 *x_extent = tab_width;
7baac3cb 594
b0d17f7c
BW
595 return wxSize(tab_width, tab_height);
596}
597
598
599void wxAuiDefaultTabArt::DrawButton(wxDC& dc,
600 wxWindow* WXUNUSED(wnd),
601 const wxRect& in_rect,
602 int bitmap_id,
603 int button_state,
604 int orientation,
b0d17f7c
BW
605 wxRect* out_rect)
606{
607 wxBitmap bmp;
608 wxRect rect;
7baac3cb 609
793d4365 610 switch (bitmap_id)
b0d17f7c 611 {
793d4365
BW
612 case wxAUI_BUTTON_CLOSE:
613 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
614 bmp = m_disabled_close_bmp;
cedd7b22 615 else
793d4365
BW
616 bmp = m_active_close_bmp;
617 break;
618 case wxAUI_BUTTON_LEFT:
619 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
620 bmp = m_disabled_left_bmp;
cedd7b22 621 else
793d4365
BW
622 bmp = m_active_left_bmp;
623 break;
624 case wxAUI_BUTTON_RIGHT:
625 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
626 bmp = m_disabled_right_bmp;
cedd7b22 627 else
793d4365
BW
628 bmp = m_active_right_bmp;
629 break;
630 case wxAUI_BUTTON_WINDOWLIST:
631 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
632 bmp = m_disabled_windowlist_bmp;
cedd7b22 633 else
793d4365
BW
634 bmp = m_active_windowlist_bmp;
635 break;
b0d17f7c 636 }
cd05bf23 637
793d4365 638
b0d17f7c
BW
639 if (!bmp.IsOk())
640 return;
7baac3cb 641
b0d17f7c 642 rect = in_rect;
7baac3cb 643
b0d17f7c
BW
644 if (orientation == wxLEFT)
645 {
646 rect.SetX(in_rect.x);
647 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
648 rect.SetWidth(bmp.GetWidth());
649 rect.SetHeight(bmp.GetHeight());
650 }
cedd7b22 651 else
b0d17f7c
BW
652 {
653 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
654 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
655 bmp.GetWidth(), bmp.GetHeight());
656 }
7baac3cb 657
b0d17f7c
BW
658 IndentPressedBitmap(&rect, button_state);
659 dc.DrawBitmap(bmp, rect.x, rect.y, true);
7baac3cb 660
b0d17f7c
BW
661 *out_rect = rect;
662}
cd05bf23
BW
663
664
793d4365
BW
665int wxAuiDefaultTabArt::ShowDropDown(wxWindow* wnd,
666 const wxAuiNotebookPageArray& pages,
667 int active_idx)
b0d17f7c 668{
c58ba15f 669 wxMenu menuPopup;
3f69756e 670
793d4365 671 size_t i, count = pages.GetCount();
b0d17f7c
BW
672 for (i = 0; i < count; ++i)
673 {
793d4365 674 const wxAuiNotebookPage& page = pages.Item(i);
d51beb88
BW
675 wxString caption = page.caption;
676
677 // if there is no caption, make it a space. This will prevent
678 // an assert in the menu code.
679 if (caption.IsEmpty())
680 caption = wxT(" ");
681
682 menuPopup.AppendCheckItem(1000+i, caption);
b0d17f7c 683 }
7baac3cb 684
b0d17f7c
BW
685 if (active_idx != -1)
686 {
687 menuPopup.Check(1000+active_idx, true);
688 }
7baac3cb 689
7f1e1468 690 // find out where to put the popup menu of window items
b0d17f7c
BW
691 wxPoint pt = ::wxGetMousePosition();
692 pt = wnd->ScreenToClient(pt);
7baac3cb 693
b0d17f7c
BW
694 // find out the screen coordinate at the bottom of the tab ctrl
695 wxRect cli_rect = wnd->GetClientRect();
696 pt.y = cli_rect.y + cli_rect.height;
7baac3cb 697
b0d17f7c
BW
698 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
699 wnd->PushEventHandler(cc);
700 wnd->PopupMenu(&menuPopup, pt);
701 int command = cc->GetCommandId();
702 wnd->PopEventHandler(true);
7baac3cb 703
b0d17f7c
BW
704 if (command >= 1000)
705 return command-1000;
7baac3cb 706
b0d17f7c
BW
707 return -1;
708}
3f69756e 709
2b9aac33 710int wxAuiDefaultTabArt::GetBestTabCtrlSize(wxWindow* wnd,
793d4365 711 const wxAuiNotebookPageArray& pages,
9fbb7d80 712 const wxSize& required_bmp_size)
b0d17f7c
BW
713{
714 wxClientDC dc(wnd);
715 dc.SetFont(m_measuring_font);
7baac3cb 716
9fbb7d80
BW
717 // sometimes a standard bitmap size needs to be enforced, especially
718 // if some tabs have bitmaps and others don't. This is important because
719 // it prevents the tab control from resizing when tabs are added.
720 wxBitmap measure_bmp;
721 if (required_bmp_size.IsFullySpecified())
722 {
723 measure_bmp.Create(required_bmp_size.x,
724 required_bmp_size.y);
725 }
c58ba15f 726
9fbb7d80 727
2b9aac33
BW
728 int max_y = 0;
729 size_t i, page_count = pages.GetCount();
730 for (i = 0; i < page_count; ++i)
731 {
732 wxAuiNotebookPage& page = pages.Item(i);
733
9fbb7d80
BW
734 wxBitmap bmp;
735 if (measure_bmp.IsOk())
736 bmp = measure_bmp;
cedd7b22 737 else
9fbb7d80
BW
738 bmp = page.bitmap;
739
2b9aac33
BW
740 // we don't use the caption text because we don't
741 // want tab heights to be different in the case
742 // of a very short piece of text on one tab and a very
743 // tall piece of text on another tab
744 int x_ext = 0;
745 wxSize s = GetTabSize(dc,
746 wnd,
747 wxT("ABCDEFGHIj"),
9fbb7d80 748 bmp,
2b9aac33
BW
749 true,
750 wxAUI_BUTTON_STATE_HIDDEN,
751 &x_ext);
c58ba15f 752
2b9aac33
BW
753 max_y = wxMax(max_y, s.y);
754 }
7baac3cb 755
2b9aac33 756 return max_y+2;
b0d17f7c
BW
757}
758
759void wxAuiDefaultTabArt::SetNormalFont(const wxFont& font)
760{
761 m_normal_font = font;
762}
763
764void wxAuiDefaultTabArt::SetSelectedFont(const wxFont& font)
765{
766 m_selected_font = font;
767}
768
769void wxAuiDefaultTabArt::SetMeasuringFont(const wxFont& font)
770{
771 m_measuring_font = font;
772}
773
774
775// -- wxAuiSimpleTabArt class implementation --
776
777wxAuiSimpleTabArt::wxAuiSimpleTabArt()
cd05bf23
BW
778{
779 m_normal_font = *wxNORMAL_FONT;
780 m_selected_font = *wxNORMAL_FONT;
781 m_selected_font.SetWeight(wxBOLD);
782 m_measuring_font = m_selected_font;
4444d148 783
b0d17f7c
BW
784 m_flags = 0;
785 m_fixed_tab_width = 100;
786
cd05bf23 787 wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
4444d148 788
8096c425 789 wxColour background_colour = base_colour;
cd05bf23
BW
790 wxColour normaltab_colour = base_colour;
791 wxColour selectedtab_colour = *wxWHITE;
4444d148 792
cd05bf23
BW
793 m_bkbrush = wxBrush(background_colour);
794 m_normal_bkbrush = wxBrush(normaltab_colour);
795 m_normal_bkpen = wxPen(normaltab_colour);
796 m_selected_bkbrush = wxBrush(selectedtab_colour);
797 m_selected_bkpen = wxPen(selectedtab_colour);
7baac3cb 798
a500c7ed
BW
799 m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
800 m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
7baac3cb 801
a500c7ed
BW
802 m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
803 m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
7baac3cb 804
a500c7ed
BW
805 m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
806 m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
7baac3cb 807
a500c7ed
BW
808 m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
809 m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
7baac3cb 810
cd05bf23
BW
811}
812
b0d17f7c 813wxAuiSimpleTabArt::~wxAuiSimpleTabArt()
488e50ee
BW
814{
815}
816
b0d17f7c
BW
817wxAuiTabArt* wxAuiSimpleTabArt::Clone()
818{
819 return static_cast<wxAuiTabArt*>(new wxAuiSimpleTabArt);
820}
821
822
823void wxAuiSimpleTabArt::SetFlags(unsigned int flags)
824{
825 m_flags = flags;
826}
827
828void wxAuiSimpleTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
829 size_t tab_count)
830{
831 m_fixed_tab_width = 100;
7baac3cb 832
69685ee0 833 int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
97ac2d5e
BW
834
835 if (m_flags & wxAUI_NB_CLOSE_BUTTON)
836 tot_width -= m_active_close_bmp.GetWidth();
837 if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
838 tot_width -= m_active_windowlist_bmp.GetWidth();
839
b0d17f7c
BW
840 if (tab_count > 0)
841 {
842 m_fixed_tab_width = tot_width/(int)tab_count;
843 }
7baac3cb
VZ
844
845
b0d17f7c
BW
846 if (m_fixed_tab_width < 100)
847 m_fixed_tab_width = 100;
7baac3cb 848
b0d17f7c
BW
849 if (m_fixed_tab_width > tot_width/2)
850 m_fixed_tab_width = tot_width/2;
7baac3cb 851
b0d17f7c
BW
852 if (m_fixed_tab_width > 220)
853 m_fixed_tab_width = 220;
854}
855
856void wxAuiSimpleTabArt::DrawBackground(wxDC& dc,
857 wxWindow* WXUNUSED(wnd),
858 const wxRect& rect)
3f69756e
BW
859{
860 // draw background
a6b0e5bd
BW
861 dc.SetBrush(m_bkbrush);
862 dc.SetPen(*wxTRANSPARENT_PEN);
863 dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
3f69756e
BW
864
865 // draw base line
a6b0e5bd
BW
866 dc.SetPen(*wxGREY_PEN);
867 dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
3f69756e
BW
868}
869
4953f8cf 870
3f69756e
BW
871// DrawTab() draws an individual tab.
872//
873// dc - output dc
874// in_rect - rectangle the tab should be confined to
875// caption - tab's caption
876// active - whether or not the tab is active
877// out_rect - actual output rectangle
878// x_extent - the advance x; where the next tab should start
879
b0d17f7c
BW
880void wxAuiSimpleTabArt::DrawTab(wxDC& dc,
881 wxWindow* wnd,
793d4365 882 const wxAuiNotebookPage& page,
b0d17f7c 883 const wxRect& in_rect,
b0d17f7c
BW
884 int close_button_state,
885 wxRect* out_tab_rect,
886 wxRect* out_button_rect,
887 int* x_extent)
3f69756e
BW
888{
889 wxCoord normal_textx, normal_texty;
890 wxCoord selected_textx, selected_texty;
3f69756e 891 wxCoord textx, texty;
7baac3cb 892
3f69756e 893 // if the caption is empty, measure some temporary text
793d4365
BW
894 wxString caption = page.caption;
895 if (caption.empty())
3f69756e 896 caption = wxT("Xj");
7baac3cb 897
a6b0e5bd
BW
898 dc.SetFont(m_selected_font);
899 dc.GetTextExtent(caption, &selected_textx, &selected_texty);
7baac3cb 900
a6b0e5bd
BW
901 dc.SetFont(m_normal_font);
902 dc.GetTextExtent(caption, &normal_textx, &normal_texty);
7baac3cb 903
a4c8fc23 904 // figure out the size of the tab
2b9aac33
BW
905 wxSize tab_size = GetTabSize(dc,
906 wnd,
793d4365
BW
907 page.caption,
908 page.bitmap,
909 page.active,
2b9aac33
BW
910 close_button_state,
911 x_extent);
3f69756e 912
a4c8fc23
BW
913 wxCoord tab_height = tab_size.y;
914 wxCoord tab_width = tab_size.x;
3f69756e
BW
915 wxCoord tab_x = in_rect.x;
916 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
917
793d4365 918 caption = page.caption;
b965ffff 919
3f69756e
BW
920 // select pen, brush and font for the tab to be drawn
921
793d4365 922 if (page.active)
3f69756e 923 {
a6b0e5bd
BW
924 dc.SetPen(m_selected_bkpen);
925 dc.SetBrush(m_selected_bkbrush);
926 dc.SetFont(m_selected_font);
3f69756e
BW
927 textx = selected_textx;
928 texty = selected_texty;
929 }
cedd7b22 930 else
3f69756e 931 {
a6b0e5bd
BW
932 dc.SetPen(m_normal_bkpen);
933 dc.SetBrush(m_normal_bkbrush);
934 dc.SetFont(m_normal_font);
3f69756e
BW
935 textx = normal_textx;
936 texty = normal_texty;
937 }
938
939
940 // -- draw line --
941
942 wxPoint points[7];
943 points[0].x = tab_x;
944 points[0].y = tab_y + tab_height - 1;
945 points[1].x = tab_x + tab_height - 3;
946 points[1].y = tab_y + 2;
947 points[2].x = tab_x + tab_height + 3;
948 points[2].y = tab_y;
949 points[3].x = tab_x + tab_width - 2;
950 points[3].y = tab_y;
951 points[4].x = tab_x + tab_width;
952 points[4].y = tab_y + 2;
953 points[5].x = tab_x + tab_width;
954 points[5].y = tab_y + tab_height - 1;
955 points[6] = points[0];
956
b0d17f7c 957 dc.SetClippingRegion(in_rect);
3f69756e 958
7baac3cb 959 dc.DrawPolygon(WXSIZEOF(points) - 1, points);
3f69756e 960
a6b0e5bd 961 dc.SetPen(*wxGREY_PEN);
3f69756e 962
7baac3cb
VZ
963 //dc.DrawLines(active ? WXSIZEOF(points) - 1 : WXSIZEOF(points), points);
964 dc.DrawLines(WXSIZEOF(points), points);
3f69756e 965
3f69756e 966
702b1c7e
BW
967 int text_offset;
968
969 int close_button_width = 0;
41b76acd 970 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
702b1c7e
BW
971 {
972 close_button_width = m_active_close_bmp.GetWidth();
973 text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2);
974 }
cedd7b22 975 else
702b1c7e
BW
976 {
977 text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2);
978 }
7baac3cb 979
b0d17f7c
BW
980 // set minimum text offset
981 if (text_offset < tab_x + tab_height)
982 text_offset = tab_x + tab_height;
983
984 // chop text if necessary
a500c7ed 985 wxString draw_text = wxAuiChopText(dc,
b0d17f7c
BW
986 caption,
987 tab_width - (text_offset-tab_x) - close_button_width);
702b1c7e
BW
988
989 // draw tab text
b0d17f7c 990 dc.DrawText(draw_text,
702b1c7e 991 text_offset,
a4c8fc23 992 (tab_y + tab_height)/2 - (texty/2) + 1);
3f69756e 993
702b1c7e
BW
994
995 // draw close button if necessary
41b76acd 996 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
702b1c7e
BW
997 {
998 wxBitmap bmp;
793d4365 999 if (page.active)
702b1c7e 1000 bmp = m_active_close_bmp;
cedd7b22 1001 else
702b1c7e 1002 bmp = m_disabled_close_bmp;
7baac3cb 1003
0b3d6ff9
BW
1004 wxRect rect(tab_x + tab_width - close_button_width - 1,
1005 tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
1006 close_button_width,
1007 tab_height - 1);
b0d17f7c 1008 DrawButtons(dc, rect, bmp, *wxWHITE, close_button_state);
7baac3cb 1009
41b76acd 1010 *out_button_rect = rect;
702b1c7e
BW
1011 }
1012
1013
41b76acd 1014 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
7baac3cb 1015
b0d17f7c 1016 dc.DestroyClippingRegion();
3f69756e
BW
1017}
1018
b0d17f7c
BW
1019int wxAuiSimpleTabArt::GetIndentSize()
1020{
1021 return 0;
1022}
3f69756e 1023
b0d17f7c
BW
1024wxSize wxAuiSimpleTabArt::GetTabSize(wxDC& dc,
1025 wxWindow* WXUNUSED(wnd),
1026 const wxString& caption,
2b9aac33 1027 const wxBitmap& WXUNUSED(bitmap),
b0d17f7c
BW
1028 bool WXUNUSED(active),
1029 int close_button_state,
1030 int* x_extent)
4953f8cf
BW
1031{
1032 wxCoord measured_textx, measured_texty;
7baac3cb 1033
a6b0e5bd
BW
1034 dc.SetFont(m_measuring_font);
1035 dc.GetTextExtent(caption, &measured_textx, &measured_texty);
7baac3cb 1036
4953f8cf
BW
1037 wxCoord tab_height = measured_texty + 4;
1038 wxCoord tab_width = measured_textx + tab_height + 5;
1039
41b76acd 1040 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
702b1c7e 1041 tab_width += m_active_close_bmp.GetWidth();
7baac3cb 1042
b0d17f7c
BW
1043 if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
1044 {
1045 tab_width = m_fixed_tab_width;
1046 }
7baac3cb 1047
4953f8cf
BW
1048 *x_extent = tab_width - (tab_height/2) - 1;
1049
1050 return wxSize(tab_width, tab_height);
1051}
1052
1053
b0d17f7c
BW
1054void wxAuiSimpleTabArt::DrawButton(wxDC& dc,
1055 wxWindow* WXUNUSED(wnd),
1056 const wxRect& in_rect,
1057 int bitmap_id,
1058 int button_state,
1059 int orientation,
b0d17f7c 1060 wxRect* out_rect)
4953f8cf
BW
1061{
1062 wxBitmap bmp;
1063 wxRect rect;
7baac3cb 1064
793d4365 1065 switch (bitmap_id)
4953f8cf 1066 {
793d4365
BW
1067 case wxAUI_BUTTON_CLOSE:
1068 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1069 bmp = m_disabled_close_bmp;
cedd7b22 1070 else
793d4365
BW
1071 bmp = m_active_close_bmp;
1072 break;
1073 case wxAUI_BUTTON_LEFT:
1074 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1075 bmp = m_disabled_left_bmp;
cedd7b22 1076 else
793d4365
BW
1077 bmp = m_active_left_bmp;
1078 break;
1079 case wxAUI_BUTTON_RIGHT:
1080 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1081 bmp = m_disabled_right_bmp;
cedd7b22 1082 else
793d4365
BW
1083 bmp = m_active_right_bmp;
1084 break;
1085 case wxAUI_BUTTON_WINDOWLIST:
1086 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1087 bmp = m_disabled_windowlist_bmp;
cedd7b22 1088 else
793d4365
BW
1089 bmp = m_active_windowlist_bmp;
1090 break;
4953f8cf
BW
1091 }
1092
1093 if (!bmp.IsOk())
1094 return;
7baac3cb 1095
4953f8cf 1096 rect = in_rect;
7baac3cb 1097
4953f8cf
BW
1098 if (orientation == wxLEFT)
1099 {
25d7497c
BW
1100 rect.SetX(in_rect.x);
1101 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
4953f8cf
BW
1102 rect.SetWidth(bmp.GetWidth());
1103 rect.SetHeight(bmp.GetHeight());
1104 }
cedd7b22 1105 else
4953f8cf 1106 {
25d7497c
BW
1107 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
1108 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
4953f8cf
BW
1109 bmp.GetWidth(), bmp.GetHeight());
1110 }
7baac3cb
VZ
1111
1112
b0d17f7c 1113 DrawButtons(dc, rect, bmp, *wxWHITE, button_state);
7baac3cb 1114
4953f8cf
BW
1115 *out_rect = rect;
1116}
1117
1118
793d4365
BW
1119int wxAuiSimpleTabArt::ShowDropDown(wxWindow* wnd,
1120 const wxAuiNotebookPageArray& pages,
1121 int active_idx)
01372b8f 1122{
c58ba15f 1123 wxMenu menuPopup;
01372b8f 1124
793d4365 1125 size_t i, count = pages.GetCount();
01372b8f
BW
1126 for (i = 0; i < count; ++i)
1127 {
793d4365
BW
1128 const wxAuiNotebookPage& page = pages.Item(i);
1129 menuPopup.AppendCheckItem(1000+i, page.caption);
01372b8f 1130 }
7baac3cb 1131
01372b8f
BW
1132 if (active_idx != -1)
1133 {
1134 menuPopup.Check(1000+active_idx, true);
1135 }
7baac3cb 1136
01372b8f
BW
1137 // find out where to put the popup menu of window
1138 // items. Subtract 100 for now to center the menu
1139 // a bit, until a better mechanism can be implemented
1140 wxPoint pt = ::wxGetMousePosition();
1141 pt = wnd->ScreenToClient(pt);
1142 if (pt.x < 100)
1143 pt.x = 0;
cedd7b22 1144 else
01372b8f 1145 pt.x -= 100;
7baac3cb 1146
01372b8f
BW
1147 // find out the screen coordinate at the bottom of the tab ctrl
1148 wxRect cli_rect = wnd->GetClientRect();
1149 pt.y = cli_rect.y + cli_rect.height;
7baac3cb 1150
01372b8f
BW
1151 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
1152 wnd->PushEventHandler(cc);
1153 wnd->PopupMenu(&menuPopup, pt);
1154 int command = cc->GetCommandId();
1155 wnd->PopEventHandler(true);
7baac3cb 1156
01372b8f
BW
1157 if (command >= 1000)
1158 return command-1000;
7baac3cb 1159
01372b8f
BW
1160 return -1;
1161}
1162
2b9aac33 1163int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow* wnd,
793d4365 1164 const wxAuiNotebookPageArray& WXUNUSED(pages),
9fbb7d80 1165 const wxSize& WXUNUSED(required_bmp_size))
a4c8fc23
BW
1166{
1167 wxClientDC dc(wnd);
1168 dc.SetFont(m_measuring_font);
1169 int x_ext = 0;
a6b0e5bd 1170 wxSize s = GetTabSize(dc,
01372b8f
BW
1171 wnd,
1172 wxT("ABCDEFGHIj"),
2b9aac33 1173 wxNullBitmap,
01372b8f
BW
1174 true,
1175 wxAUI_BUTTON_STATE_HIDDEN,
1176 &x_ext);
a4c8fc23
BW
1177 return s.y+3;
1178}
4953f8cf 1179
b0d17f7c 1180void wxAuiSimpleTabArt::SetNormalFont(const wxFont& font)
3f69756e
BW
1181{
1182 m_normal_font = font;
1183}
1184
b0d17f7c 1185void wxAuiSimpleTabArt::SetSelectedFont(const wxFont& font)
3f69756e
BW
1186{
1187 m_selected_font = font;
1188}
1189
b0d17f7c 1190void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont& font)
3f69756e
BW
1191{
1192 m_measuring_font = font;
1193}
1194
1195
1196
1197
3f69756e
BW
1198// -- wxAuiTabContainer class implementation --
1199
1200
1201// wxAuiTabContainer is a class which contains information about each
1202// tab. It also can render an entire tab control to a specified DC.
1203// It's not a window class itself, because this code will be used by
1204// the wxFrameMananger, where it is disadvantageous to have separate
1205// windows for each tab control in the case of "docked tabs"
1206
1207// A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
1208// which can be used as a tab control in the normal sense.
1209
1210
1211wxAuiTabContainer::wxAuiTabContainer()
1212{
4953f8cf 1213 m_tab_offset = 0;
702b1c7e 1214 m_flags = 0;
a3a5df9d 1215 m_art = new wxAuiDefaultTabArt;
7baac3cb
VZ
1216
1217 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
01372b8f
BW
1218 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
1219 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
4953f8cf 1220 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
3f69756e
BW
1221}
1222
fe498448
BW
1223wxAuiTabContainer::~wxAuiTabContainer()
1224{
3f69756e
BW
1225 delete m_art;
1226}
1227
a3a5df9d 1228void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art)
3f69756e
BW
1229{
1230 delete m_art;
1231 m_art = art;
7baac3cb 1232
b0d17f7c
BW
1233 if (m_art)
1234 {
1235 m_art->SetFlags(m_flags);
1236 }
3f69756e
BW
1237}
1238
e0dc13d4 1239wxAuiTabArt* wxAuiTabContainer::GetArtProvider() const
3f69756e
BW
1240{
1241 return m_art;
fe498448
BW
1242}
1243
702b1c7e
BW
1244void wxAuiTabContainer::SetFlags(unsigned int flags)
1245{
1246 m_flags = flags;
7baac3cb 1247
41b76acd 1248 // check for new close button settings
7baac3cb 1249 RemoveButton(wxAUI_BUTTON_LEFT);
01372b8f
BW
1250 RemoveButton(wxAUI_BUTTON_RIGHT);
1251 RemoveButton(wxAUI_BUTTON_WINDOWLIST);
41b76acd 1252 RemoveButton(wxAUI_BUTTON_CLOSE);
7baac3cb
VZ
1253
1254
01372b8f
BW
1255 if (flags & wxAUI_NB_SCROLL_BUTTONS)
1256 {
7baac3cb 1257 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
01372b8f
BW
1258 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
1259 }
1260
1261 if (flags & wxAUI_NB_WINDOWLIST_BUTTON)
1262 {
1263 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
1264 }
7baac3cb 1265
41b76acd
BW
1266 if (flags & wxAUI_NB_CLOSE_BUTTON)
1267 {
1268 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
1269 }
7baac3cb 1270
b0d17f7c
BW
1271 if (m_art)
1272 {
1273 m_art->SetFlags(m_flags);
1274 }
702b1c7e
BW
1275}
1276
1277unsigned int wxAuiTabContainer::GetFlags() const
1278{
1279 return m_flags;
1280}
1281
1282
cd05bf23
BW
1283void wxAuiTabContainer::SetNormalFont(const wxFont& font)
1284{
3f69756e 1285 m_art->SetNormalFont(font);
cd05bf23
BW
1286}
1287
1288void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
1289{
3f69756e 1290 m_art->SetSelectedFont(font);
cd05bf23
BW
1291}
1292
1293void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
1294{
3f69756e 1295 m_art->SetMeasuringFont(font);
cd05bf23
BW
1296}
1297
1298void wxAuiTabContainer::SetRect(const wxRect& rect)
1299{
1300 m_rect = rect;
7baac3cb 1301
b0d17f7c
BW
1302 if (m_art)
1303 {
1304 m_art->SetSizingInfo(rect.GetSize(), m_pages.GetCount());
1305 }
cd05bf23
BW
1306}
1307
1308bool wxAuiTabContainer::AddPage(wxWindow* page,
1309 const wxAuiNotebookPage& info)
1310{
1311 wxAuiNotebookPage page_info;
1312 page_info = info;
1313 page_info.window = page;
4444d148 1314
cd05bf23
BW
1315 m_pages.Add(page_info);
1316
b0d17f7c
BW
1317 // let the art provider know how many pages we have
1318 if (m_art)
1319 {
1320 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1321 }
7baac3cb 1322
cd05bf23
BW
1323 return true;
1324}
1325
1326bool wxAuiTabContainer::InsertPage(wxWindow* page,
1327 const wxAuiNotebookPage& info,
1328 size_t idx)
1329{
1330 wxAuiNotebookPage page_info;
1331 page_info = info;
1332 page_info.window = page;
4444d148 1333
cd05bf23
BW
1334 if (idx >= m_pages.GetCount())
1335 m_pages.Add(page_info);
cedd7b22 1336 else
cd05bf23
BW
1337 m_pages.Insert(page_info, idx);
1338
b0d17f7c
BW
1339 // let the art provider know how many pages we have
1340 if (m_art)
1341 {
1342 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1343 }
7baac3cb 1344
cd05bf23
BW
1345 return true;
1346}
1347
2fadbbfd
BW
1348bool wxAuiTabContainer::MovePage(wxWindow* page,
1349 size_t new_idx)
1350{
1351 int idx = GetIdxFromWindow(page);
1352 if (idx == -1)
1353 return false;
7baac3cb 1354
2fadbbfd
BW
1355 // get page entry, make a copy of it
1356 wxAuiNotebookPage p = GetPage(idx);
7baac3cb 1357
2fadbbfd
BW
1358 // remove old page entry
1359 RemovePage(page);
7baac3cb 1360
2fadbbfd
BW
1361 // insert page where it should be
1362 InsertPage(page, p, new_idx);
7baac3cb 1363
2fadbbfd
BW
1364 return true;
1365}
1366
cd05bf23
BW
1367bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
1368{
1369 size_t i, page_count = m_pages.GetCount();
1370 for (i = 0; i < page_count; ++i)
1371 {
1372 wxAuiNotebookPage& page = m_pages.Item(i);
1373 if (page.window == wnd)
1374 {
1375 m_pages.RemoveAt(i);
7baac3cb 1376
b0d17f7c
BW
1377 // let the art provider know how many pages we have
1378 if (m_art)
1379 {
1380 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1381 }
7baac3cb 1382
cd05bf23
BW
1383 return true;
1384 }
1385 }
4444d148 1386
cd05bf23
BW
1387 return false;
1388}
1389
1390bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
1391{
1392 bool found = false;
4444d148 1393
cd05bf23
BW
1394 size_t i, page_count = m_pages.GetCount();
1395 for (i = 0; i < page_count; ++i)
1396 {
1397 wxAuiNotebookPage& page = m_pages.Item(i);
1398 if (page.window == wnd)
1399 {
1400 page.active = true;
1401 found = true;
1402 }
cedd7b22 1403 else
cd05bf23
BW
1404 {
1405 page.active = false;
1406 }
1407 }
4444d148 1408
cd05bf23
BW
1409 return found;
1410}
1411
1412void wxAuiTabContainer::SetNoneActive()
1413{
1414 size_t i, page_count = m_pages.GetCount();
1415 for (i = 0; i < page_count; ++i)
1416 {
1417 wxAuiNotebookPage& page = m_pages.Item(i);
1418 page.active = false;
1419 }
1420}
1421
1422bool wxAuiTabContainer::SetActivePage(size_t page)
1423{
1424 if (page >= m_pages.GetCount())
1425 return false;
4444d148 1426
cd05bf23
BW
1427 return SetActivePage(m_pages.Item(page).window);
1428}
4444d148 1429
cd05bf23
BW
1430int wxAuiTabContainer::GetActivePage() const
1431{
1432 size_t i, page_count = m_pages.GetCount();
1433 for (i = 0; i < page_count; ++i)
1434 {
1435 wxAuiNotebookPage& page = m_pages.Item(i);
1436 if (page.active)
1437 return i;
1438 }
4444d148 1439
cd05bf23
BW
1440 return -1;
1441}
1442
1443wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
1444{
1445 if (idx >= m_pages.GetCount())
1446 return NULL;
4444d148 1447
cd05bf23
BW
1448 return m_pages[idx].window;
1449}
1450
1451int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
1452{
849c353a
VZ
1453 const size_t page_count = m_pages.GetCount();
1454 for ( size_t i = 0; i < page_count; ++i )
cd05bf23
BW
1455 {
1456 wxAuiNotebookPage& page = m_pages.Item(i);
1457 if (page.window == wnd)
1458 return i;
1459 }
849c353a 1460 return wxNOT_FOUND;
cd05bf23
BW
1461}
1462
1463wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
1464{
1465 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
1466
1467 return m_pages[idx];
1468}
1469
c3e016e4
JS
1470const wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx) const
1471{
1472 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
1473
1474 return m_pages[idx];
1475}
1476
cd05bf23
BW
1477wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
1478{
1479 return m_pages;
1480}
1481
1482size_t wxAuiTabContainer::GetPageCount() const
1483{
1484 return m_pages.GetCount();
1485}
1486
4953f8cf
BW
1487void wxAuiTabContainer::AddButton(int id,
1488 int location,
1489 const wxBitmap& normal_bitmap,
1490 const wxBitmap& disabled_bitmap)
cd05bf23
BW
1491{
1492 wxAuiTabContainerButton button;
1493 button.id = id;
4953f8cf
BW
1494 button.bitmap = normal_bitmap;
1495 button.dis_bitmap = disabled_bitmap;
b6418695 1496 button.location = location;
cd05bf23 1497 button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
4444d148 1498
cd05bf23
BW
1499 m_buttons.Add(button);
1500}
1501
41b76acd
BW
1502void wxAuiTabContainer::RemoveButton(int id)
1503{
1504 size_t i, button_count = m_buttons.GetCount();
1505
1506 for (i = 0; i < button_count; ++i)
1507 {
1508 if (m_buttons.Item(i).id == id)
1509 {
1510 m_buttons.RemoveAt(i);
1511 return;
1512 }
1513 }
1514}
1515
1516
1517
4953f8cf
BW
1518size_t wxAuiTabContainer::GetTabOffset() const
1519{
1520 return m_tab_offset;
1521}
cd05bf23 1522
4953f8cf
BW
1523void wxAuiTabContainer::SetTabOffset(size_t offset)
1524{
1525 m_tab_offset = offset;
1526}
cd05bf23 1527
b0d17f7c
BW
1528
1529
1530
cd05bf23
BW
1531// Render() renders the tab catalog to the specified DC
1532// It is a virtual function and can be overridden to
1533// provide custom drawing capabilities
01372b8f 1534void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd)
4444d148 1535{
a9eeb510
BW
1536 if (!raw_dc || !raw_dc->IsOk())
1537 return;
1538
cd05bf23
BW
1539 wxMemoryDC dc;
1540 wxBitmap bmp;
4953f8cf
BW
1541 size_t i;
1542 size_t page_count = m_pages.GetCount();
1543 size_t button_count = m_buttons.GetCount();
1544
1545 // create off-screen bitmap
cd05bf23
BW
1546 bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
1547 dc.SelectObject(bmp);
4444d148 1548
a9eeb510
BW
1549 if (!dc.IsOk())
1550 return;
4953f8cf
BW
1551
1552 // find out if size of tabs is larger than can be
1553 // afforded on screen
1554 int total_width = 0;
25d7497c 1555 int visible_width = 0;
4953f8cf
BW
1556 for (i = 0; i < page_count; ++i)
1557 {
1558 wxAuiNotebookPage& page = m_pages.Item(i);
7baac3cb 1559
702b1c7e
BW
1560 // determine if a close button is on this tab
1561 bool close_button = false;
1562 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1563 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1564 {
1565 close_button = true;
1566 }
7baac3cb
VZ
1567
1568
4953f8cf 1569 int x_extent = 0;
a6b0e5bd 1570 wxSize size = m_art->GetTabSize(dc,
01372b8f 1571 wnd,
41b76acd 1572 page.caption,
2b9aac33 1573 page.bitmap,
41b76acd
BW
1574 page.active,
1575 close_button ?
1576 wxAUI_BUTTON_STATE_NORMAL :
1577 wxAUI_BUTTON_STATE_HIDDEN,
1578 &x_extent);
7baac3cb 1579
4953f8cf
BW
1580 if (i+1 < page_count)
1581 total_width += x_extent;
cedd7b22 1582 else
4953f8cf 1583 total_width += size.x;
7baac3cb 1584
25d7497c
BW
1585 if (i >= m_tab_offset)
1586 {
1587 if (i+1 < page_count)
1588 visible_width += x_extent;
cedd7b22 1589 else
25d7497c
BW
1590 visible_width += size.x;
1591 }
4953f8cf 1592 }
7baac3cb 1593
b0d17f7c 1594 if (total_width > m_rect.GetWidth() || m_tab_offset != 0)
4953f8cf
BW
1595 {
1596 // show left/right buttons
1597 for (i = 0; i < button_count; ++i)
1598 {
1599 wxAuiTabContainerButton& button = m_buttons.Item(i);
1600 if (button.id == wxAUI_BUTTON_LEFT ||
1601 button.id == wxAUI_BUTTON_RIGHT)
1602 {
1603 button.cur_state &= ~wxAUI_BUTTON_STATE_HIDDEN;
1604 }
1605 }
1606 }
cedd7b22 1607 else
4953f8cf
BW
1608 {
1609 // hide left/right buttons
1610 for (i = 0; i < button_count; ++i)
1611 {
1612 wxAuiTabContainerButton& button = m_buttons.Item(i);
1613 if (button.id == wxAUI_BUTTON_LEFT ||
1614 button.id == wxAUI_BUTTON_RIGHT)
1615 {
1616 button.cur_state |= wxAUI_BUTTON_STATE_HIDDEN;
1617 }
1618 }
1619 }
1620
25d7497c
BW
1621 // determine whether left button should be enabled
1622 for (i = 0; i < button_count; ++i)
1623 {
1624 wxAuiTabContainerButton& button = m_buttons.Item(i);
1625 if (button.id == wxAUI_BUTTON_LEFT)
1626 {
1627 if (m_tab_offset == 0)
1628 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
cedd7b22 1629 else
25d7497c
BW
1630 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
1631 }
1632 if (button.id == wxAUI_BUTTON_RIGHT)
1633 {
1634 if (visible_width < m_rect.GetWidth() - ((int)button_count*16))
1635 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
cedd7b22 1636 else
25d7497c
BW
1637 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
1638 }
1639 }
1640
4953f8cf
BW
1641
1642
1643 // draw background
a6b0e5bd 1644 m_art->DrawBackground(dc, wnd, m_rect);
4444d148 1645
4953f8cf
BW
1646 // draw buttons
1647 int left_buttons_width = 0;
1648 int right_buttons_width = 0;
7baac3cb 1649
cd05bf23 1650 int offset = 0;
b6418695
BW
1651
1652 // draw the buttons on the right side
1653 offset = m_rect.x + m_rect.width;
b6418695
BW
1654 for (i = 0; i < button_count; ++i)
1655 {
1656 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
7baac3cb 1657
b6418695
BW
1658 if (button.location != wxRIGHT)
1659 continue;
4953f8cf
BW
1660 if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
1661 continue;
7baac3cb 1662
4953f8cf
BW
1663 wxRect button_rect = m_rect;
1664 button_rect.SetY(1);
1665 button_rect.SetWidth(offset);
1666
a6b0e5bd 1667 m_art->DrawButton(dc,
01372b8f 1668 wnd,
4953f8cf
BW
1669 button_rect,
1670 button.id,
1671 button.cur_state,
1672 wxRIGHT,
4953f8cf
BW
1673 &button.rect);
1674
1675 offset -= button.rect.GetWidth();
1676 right_buttons_width += button.rect.GetWidth();
b6418695
BW
1677 }
1678
1679
1680
1681 offset = 0;
7baac3cb 1682
b6418695
BW
1683 // draw the buttons on the left side
1684
1685 for (i = 0; i < button_count; ++i)
1686 {
1687 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
7baac3cb 1688
b6418695
BW
1689 if (button.location != wxLEFT)
1690 continue;
4953f8cf
BW
1691 if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
1692 continue;
7baac3cb 1693
4953f8cf
BW
1694 wxRect button_rect(offset, 1, 1000, m_rect.height);
1695
a6b0e5bd 1696 m_art->DrawButton(dc,
01372b8f 1697 wnd,
4953f8cf
BW
1698 button_rect,
1699 button.id,
1700 button.cur_state,
1701 wxLEFT,
4953f8cf 1702 &button.rect);
7baac3cb 1703
4953f8cf
BW
1704 offset += button.rect.GetWidth();
1705 left_buttons_width += button.rect.GetWidth();
b6418695
BW
1706 }
1707
4953f8cf 1708 offset = left_buttons_width;
7baac3cb 1709
b0d17f7c 1710 if (offset == 0)
7baac3cb
VZ
1711 offset += m_art->GetIndentSize();
1712
1713
41b76acd 1714 // prepare the tab-close-button array
049333c2
BW
1715 // make sure tab button entries which aren't used are marked as hidden
1716 for (i = page_count; i < m_tab_close_buttons.GetCount(); ++i)
1717 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
7baac3cb 1718
049333c2 1719 // make sure there are enough tab button entries to accommodate all tabs
41b76acd
BW
1720 while (m_tab_close_buttons.GetCount() < page_count)
1721 {
1722 wxAuiTabContainerButton tempbtn;
1723 tempbtn.id = wxAUI_BUTTON_CLOSE;
1724 tempbtn.location = wxCENTER;
1725 tempbtn.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1726 m_tab_close_buttons.Add(tempbtn);
1727 }
7baac3cb
VZ
1728
1729
4abf84fb 1730 // buttons before the tab offset must be set to hidden
41b76acd
BW
1731 for (i = 0; i < m_tab_offset; ++i)
1732 {
41b76acd
BW
1733 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1734 }
7baac3cb
VZ
1735
1736
b6418695 1737 // draw the tabs
cd05bf23
BW
1738
1739 size_t active = 999;
1740 int active_offset = 0;
b0d17f7c 1741 wxRect active_rect;
4444d148 1742
cd05bf23
BW
1743 int x_extent = 0;
1744 wxRect rect = m_rect;
1745 rect.y = 0;
cd05bf23 1746 rect.height = m_rect.height;
4444d148 1747
4953f8cf 1748 for (i = m_tab_offset; i < page_count; ++i)
cd05bf23
BW
1749 {
1750 wxAuiNotebookPage& page = m_pages.Item(i);
41b76acd 1751 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i);
4444d148 1752
702b1c7e 1753 // determine if a close button is on this tab
702b1c7e
BW
1754 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1755 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1756 {
41b76acd
BW
1757 if (tab_button.cur_state == wxAUI_BUTTON_STATE_HIDDEN)
1758 {
1759 tab_button.id = wxAUI_BUTTON_CLOSE;
1760 tab_button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
1761 tab_button.location = wxCENTER;
1762 }
1763 }
cedd7b22 1764 else
41b76acd
BW
1765 {
1766 tab_button.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
702b1c7e
BW
1767 }
1768
cd05bf23 1769 rect.x = offset;
b0d17f7c
BW
1770 rect.width = m_rect.width - right_buttons_width - offset - 2;
1771
47b6bebb
BW
1772 if (rect.width <= 0)
1773 break;
1774
a6b0e5bd 1775 m_art->DrawTab(dc,
01372b8f 1776 wnd,
793d4365 1777 page,
01372b8f 1778 rect,
01372b8f
BW
1779 tab_button.cur_state,
1780 &page.rect,
1781 &tab_button.rect,
1782 &x_extent);
4444d148 1783
cd05bf23
BW
1784 if (page.active)
1785 {
1786 active = i;
1787 active_offset = offset;
b0d17f7c 1788 active_rect = rect;
cd05bf23 1789 }
7baac3cb 1790
cd05bf23
BW
1791 offset += x_extent;
1792 }
4444d148 1793
4abf84fb
BW
1794
1795 // make sure to deactivate buttons which are off the screen to the right
1796 for (++i; i < m_tab_close_buttons.GetCount(); ++i)
1797 {
1798 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1799 }
1800
1801
cd05bf23 1802 // draw the active tab again so it stands in the foreground
4953f8cf 1803 if (active >= m_tab_offset && active < m_pages.GetCount())
cd05bf23
BW
1804 {
1805 wxAuiNotebookPage& page = m_pages.Item(active);
1806
41b76acd
BW
1807 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(active);
1808
cd05bf23 1809 rect.x = active_offset;
a6b0e5bd 1810 m_art->DrawTab(dc,
01372b8f 1811 wnd,
793d4365 1812 page,
b0d17f7c 1813 active_rect,
01372b8f
BW
1814 tab_button.cur_state,
1815 &page.rect,
1816 &tab_button.rect,
1817 &x_extent);
cd05bf23 1818 }
4444d148 1819
7baac3cb 1820
4953f8cf
BW
1821 raw_dc->Blit(m_rect.x, m_rect.y,
1822 m_rect.GetWidth(), m_rect.GetHeight(),
1823 &dc, 0, 0);
cd05bf23
BW
1824}
1825
1826
1827// TabHitTest() tests if a tab was hit, passing the window pointer
1828// back if that condition was fulfilled. The function returns
1829// true if a tab was hit, otherwise false
1830bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
1831{
22a35096 1832 if (!m_rect.Contains(x,y))
cd05bf23 1833 return false;
7baac3cb 1834
41b76acd
BW
1835 wxAuiTabContainerButton* btn = NULL;
1836 if (ButtonHitTest(x, y, &btn))
1837 {
1838 if (m_buttons.Index(*btn) != wxNOT_FOUND)
1839 return false;
1840 }
4444d148 1841
cd05bf23 1842 size_t i, page_count = m_pages.GetCount();
4444d148 1843
4953f8cf 1844 for (i = m_tab_offset; i < page_count; ++i)
cd05bf23
BW
1845 {
1846 wxAuiNotebookPage& page = m_pages.Item(i);
22a35096 1847 if (page.rect.Contains(x,y))
cd05bf23 1848 {
4953f8cf
BW
1849 if (hit)
1850 *hit = page.window;
cd05bf23
BW
1851 return true;
1852 }
1853 }
4444d148 1854
cd05bf23
BW
1855 return false;
1856}
1857
1858// ButtonHitTest() tests if a button was hit. The function returns
1859// true if a button was hit, otherwise false
1860bool wxAuiTabContainer::ButtonHitTest(int x, int y,
1861 wxAuiTabContainerButton** hit) const
1862{
22a35096 1863 if (!m_rect.Contains(x,y))
cd05bf23 1864 return false;
4444d148 1865
41b76acd 1866 size_t i, button_count;
7baac3cb
VZ
1867
1868
41b76acd 1869 button_count = m_buttons.GetCount();
cd05bf23
BW
1870 for (i = 0; i < button_count; ++i)
1871 {
1872 wxAuiTabContainerButton& button = m_buttons.Item(i);
9b405ab3
BW
1873 if (button.rect.Contains(x,y) &&
1874 !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN |
1875 wxAUI_BUTTON_STATE_DISABLED)))
cd05bf23 1876 {
4953f8cf
BW
1877 if (hit)
1878 *hit = &button;
cd05bf23
BW
1879 return true;
1880 }
1881 }
7baac3cb 1882
41b76acd
BW
1883 button_count = m_tab_close_buttons.GetCount();
1884 for (i = 0; i < button_count; ++i)
1885 {
1886 wxAuiTabContainerButton& button = m_tab_close_buttons.Item(i);
9b405ab3
BW
1887 if (button.rect.Contains(x,y) &&
1888 !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN |
1889 wxAUI_BUTTON_STATE_DISABLED)))
41b76acd
BW
1890 {
1891 if (hit)
1892 *hit = &button;
1893 return true;
1894 }
1895 }
7baac3cb 1896
cd05bf23
BW
1897 return false;
1898}
1899
1900
1901
1902// the utility function ShowWnd() is the same as show,
a3a5df9d 1903// except it handles wxAuiMDIChildFrame windows as well,
cd05bf23
BW
1904// as the Show() method on this class is "unplugged"
1905static void ShowWnd(wxWindow* wnd, bool show)
1906{
a3a5df9d 1907 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
cd05bf23 1908 {
a3a5df9d 1909 wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
cd05bf23
BW
1910 cf->DoShow(show);
1911 }
cedd7b22 1912 else
cd05bf23
BW
1913 {
1914 wnd->Show(show);
1915 }
1916}
1917
1918
1919// DoShowHide() this function shows the active window, then
1920// hides all of the other windows (in that order)
1921void wxAuiTabContainer::DoShowHide()
1922{
1923 wxAuiNotebookPageArray& pages = GetPages();
1924 size_t i, page_count = pages.GetCount();
1925
1926 // show new active page first
1927 for (i = 0; i < page_count; ++i)
1928 {
1929 wxAuiNotebookPage& page = pages.Item(i);
1930 if (page.active)
1931 {
1932 ShowWnd(page.window, true);
1933 break;
1934 }
1935 }
1936
1937 // hide all other pages
1938 for (i = 0; i < page_count; ++i)
1939 {
1940 wxAuiNotebookPage& page = pages.Item(i);
badcaaaf
BW
1941 if (!page.active)
1942 ShowWnd(page.window, false);
cd05bf23
BW
1943 }
1944}
1945
1946
1947
1948
1949
1950
1951// -- wxAuiTabCtrl class implementation --
1952
1953
cd05bf23
BW
1954
1955BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
1956 EVT_PAINT(wxAuiTabCtrl::OnPaint)
1957 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
1958 EVT_SIZE(wxAuiTabCtrl::OnSize)
1959 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
72d5e8d9 1960 EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDown)
cd05bf23 1961 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
69f5e420
BW
1962 EVT_MIDDLE_DOWN(wxAuiTabCtrl::OnMiddleDown)
1963 EVT_MIDDLE_UP(wxAuiTabCtrl::OnMiddleUp)
1964 EVT_RIGHT_DOWN(wxAuiTabCtrl::OnRightDown)
1965 EVT_RIGHT_UP(wxAuiTabCtrl::OnRightUp)
cd05bf23
BW
1966 EVT_MOTION(wxAuiTabCtrl::OnMotion)
1967 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
c58ba15f 1968 EVT_AUINOTEBOOK_BUTTON(wxID_ANY, wxAuiTabCtrl::OnButton)
cd05bf23
BW
1969END_EVENT_TABLE()
1970
1971
1972wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
1973 wxWindowID id,
1974 const wxPoint& pos,
1975 const wxSize& size,
4444d148 1976 long style) : wxControl(parent, id, pos, size, style)
cd05bf23
BW
1977{
1978 m_click_pt = wxDefaultPosition;
1979 m_is_dragging = false;
1980 m_hover_button = NULL;
9b3f654a 1981 m_pressed_button = NULL;
cd05bf23
BW
1982}
1983
26da5e4f
BW
1984wxAuiTabCtrl::~wxAuiTabCtrl()
1985{
1986}
cd05bf23
BW
1987
1988void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
1989{
1990 wxPaintDC dc(this);
4444d148 1991
cd05bf23 1992 dc.SetFont(GetFont());
4444d148 1993
cd05bf23 1994 if (GetPageCount() > 0)
01372b8f 1995 Render(&dc, this);
cd05bf23
BW
1996}
1997
1998void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
1999{
2000}
2001
2002void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
2003{
2004 wxSize s = evt.GetSize();
2005 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
2006 SetRect(r);
2007}
2008
2009void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
2010{
2011 CaptureMouse();
2012 m_click_pt = wxDefaultPosition;
2013 m_is_dragging = false;
08c068a4 2014 m_click_tab = NULL;
9b3f654a 2015 m_pressed_button = NULL;
4444d148 2016
760d3542 2017
cd05bf23
BW
2018 wxWindow* wnd;
2019 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
9b405ab3 2020 {
049333c2 2021 int new_selection = GetIdxFromWindow(wnd);
7baac3cb 2022
68fd4f2c
BW
2023 // wxAuiNotebooks always want to receive this event
2024 // even if the tab is already active, because they may
2025 // have multiple tab controls
2026 if (new_selection != GetActivePage() ||
2027 GetParent()->IsKindOf(CLASSINFO(wxAuiNotebook)))
049333c2
BW
2028 {
2029 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2030 e.SetSelection(new_selection);
2031 e.SetOldSelection(GetActivePage());
2032 e.SetEventObject(this);
2033 GetEventHandler()->ProcessEvent(e);
2034 }
4444d148 2035
cd05bf23
BW
2036 m_click_pt.x = evt.m_x;
2037 m_click_pt.y = evt.m_y;
08c068a4 2038 m_click_tab = wnd;
cd05bf23 2039 }
7baac3cb 2040
cd05bf23
BW
2041 if (m_hover_button)
2042 {
9b3f654a
BW
2043 m_pressed_button = m_hover_button;
2044 m_pressed_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
cd05bf23
BW
2045 Refresh();
2046 Update();
2047 }
2048}
2049
9b3f654a 2050void wxAuiTabCtrl::OnLeftUp(wxMouseEvent& evt)
cd05bf23
BW
2051{
2052 if (GetCapture() == this)
2053 ReleaseMouse();
4444d148 2054
cd05bf23
BW
2055 if (m_is_dragging)
2056 {
d16619f8 2057 m_is_dragging = false;
cedd7b22 2058
cd05bf23 2059 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
08c068a4
BW
2060 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2061 evt.SetOldSelection(evt.GetSelection());
cd05bf23
BW
2062 evt.SetEventObject(this);
2063 GetEventHandler()->ProcessEvent(evt);
cedd7b22 2064
cd05bf23
BW
2065 return;
2066 }
4444d148 2067
9b3f654a 2068 if (m_pressed_button)
cd05bf23 2069 {
9b3f654a
BW
2070 // make sure we're still clicking the button
2071 wxAuiTabContainerButton* button = NULL;
2072 if (!ButtonHitTest(evt.m_x, evt.m_y, &button))
2073 return;
7baac3cb 2074
9b3f654a
BW
2075 if (button != m_pressed_button)
2076 {
2077 m_pressed_button = NULL;
2078 return;
2079 }
2080
cd05bf23
BW
2081 Refresh();
2082 Update();
4444d148 2083
9b3f654a 2084 if (!(m_pressed_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
25d7497c
BW
2085 {
2086 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
9b362935 2087 evt.SetSelection(GetIdxFromWindow(m_click_tab));
9b3f654a 2088 evt.SetInt(m_pressed_button->id);
25d7497c
BW
2089 evt.SetEventObject(this);
2090 GetEventHandler()->ProcessEvent(evt);
2091 }
7baac3cb 2092
9b3f654a 2093 m_pressed_button = NULL;
cd05bf23 2094 }
4444d148 2095
cd05bf23
BW
2096 m_click_pt = wxDefaultPosition;
2097 m_is_dragging = false;
08c068a4 2098 m_click_tab = NULL;
cd05bf23
BW
2099}
2100
69f5e420
BW
2101void wxAuiTabCtrl::OnMiddleUp(wxMouseEvent& evt)
2102{
2103 wxWindow* wnd = NULL;
2104 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2105 return;
2106
2107 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
2108 e.SetEventObject(this);
2109 e.SetSelection(GetIdxFromWindow(wnd));
2110 GetEventHandler()->ProcessEvent(e);
2111}
2112
2113void wxAuiTabCtrl::OnMiddleDown(wxMouseEvent& evt)
2114{
2115 wxWindow* wnd = NULL;
2116 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2117 return;
2118
2119 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
2120 e.SetEventObject(this);
2121 e.SetSelection(GetIdxFromWindow(wnd));
2122 GetEventHandler()->ProcessEvent(e);
2123}
2124
2125void wxAuiTabCtrl::OnRightUp(wxMouseEvent& evt)
2126{
2127 wxWindow* wnd = NULL;
2128 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2129 return;
2130
2131 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
2132 e.SetEventObject(this);
2133 e.SetSelection(GetIdxFromWindow(wnd));
2134 GetEventHandler()->ProcessEvent(e);
2135}
2136
2137void wxAuiTabCtrl::OnRightDown(wxMouseEvent& evt)
2138{
2139 wxWindow* wnd = NULL;
2140 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2141 return;
2142
2143 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
2144 e.SetEventObject(this);
2145 e.SetSelection(GetIdxFromWindow(wnd));
2146 GetEventHandler()->ProcessEvent(e);
2147}
2148
cd05bf23
BW
2149void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
2150{
2151 wxPoint pos = evt.GetPosition();
2152
2153 // check if the mouse is hovering above a button
2154 wxAuiTabContainerButton* button;
2155 if (ButtonHitTest(pos.x, pos.y, &button))
2156 {
b6418695
BW
2157 if (m_hover_button && button != m_hover_button)
2158 {
2159 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2160 m_hover_button = NULL;
2161 Refresh();
2162 Update();
2163 }
7baac3cb 2164
cd05bf23
BW
2165 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
2166 {
2167 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
2168 Refresh();
2169 Update();
2170 m_hover_button = button;
2171 return;
2172 }
2173 }
cedd7b22 2174 else
cd05bf23
BW
2175 {
2176 if (m_hover_button)
2177 {
2178 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2179 m_hover_button = NULL;
2180 Refresh();
2181 Update();
2182 }
2183 }
4444d148
WS
2184
2185
cd05bf23
BW
2186 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
2187 return;
4444d148 2188
cd05bf23
BW
2189 if (m_is_dragging)
2190 {
2191 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
08c068a4
BW
2192 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2193 evt.SetOldSelection(evt.GetSelection());
cd05bf23
BW
2194 evt.SetEventObject(this);
2195 GetEventHandler()->ProcessEvent(evt);
2196 return;
4444d148
WS
2197 }
2198
2199
cd05bf23
BW
2200 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
2201 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
2202
2203 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
2204 abs(pos.y - m_click_pt.y) > drag_y_threshold)
2205 {
2206 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
08c068a4
BW
2207 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2208 evt.SetOldSelection(evt.GetSelection());
cd05bf23
BW
2209 evt.SetEventObject(this);
2210 GetEventHandler()->ProcessEvent(evt);
4444d148 2211
cd05bf23
BW
2212 m_is_dragging = true;
2213 }
2214}
2215
2216void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
2217{
2218 if (m_hover_button)
2219 {
2220 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2221 m_hover_button = NULL;
2222 Refresh();
2223 Update();
2224 }
2225}
2226
4953f8cf
BW
2227void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
2228{
2229 int button = event.GetInt();
7baac3cb 2230
4953f8cf
BW
2231 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
2232 {
2233 if (button == wxAUI_BUTTON_LEFT)
2234 {
2235 if (GetTabOffset() > 0)
2236 {
2237 SetTabOffset(GetTabOffset()-1);
2238 Refresh();
2239 Update();
2240 }
2241 }
cedd7b22 2242 else
4953f8cf
BW
2243 {
2244 SetTabOffset(GetTabOffset()+1);
2245 Refresh();
2246 Update();
2247 }
01372b8f 2248 }
cedd7b22 2249 else if (button == wxAUI_BUTTON_WINDOWLIST)
01372b8f 2250 {
793d4365 2251 int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage());
7baac3cb 2252
01372b8f
BW
2253 if (idx != -1)
2254 {
2255 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2256 e.SetSelection(idx);
2257 e.SetOldSelection(GetActivePage());
2258 e.SetEventObject(this);
2259 GetEventHandler()->ProcessEvent(e);
2260 }
4953f8cf 2261 }
cedd7b22 2262 else
4953f8cf
BW
2263 {
2264 event.Skip();
2265 }
2266}
cd05bf23
BW
2267
2268// wxTabFrame is an interesting case. It's important that all child pages
2269// of the multi-notebook control are all actually children of that control
2270// (and not grandchildren). wxTabFrame facilitates this. There is one
2271// instance of wxTabFrame for each tab control inside the multi-notebook.
2272// It's important to know that wxTabFrame is not a real window, but it merely
2273// used to capture the dimensions/positioning of the internal tab control and
2274// it's managed page windows
2275
2276class wxTabFrame : public wxWindow
2277{
2278public:
2279
2280 wxTabFrame()
2281 {
2282 m_tabs = NULL;
2283 m_rect = wxRect(0,0,200,200);
da5e85d9
BW
2284 m_tab_ctrl_height = 20;
2285 }
4444d148 2286
cedd7b22
PC
2287 ~wxTabFrame()
2288 {
2289 wxDELETE(m_tabs);
2290 }
bd4e0834 2291
da5e85d9
BW
2292 void SetTabCtrlHeight(int h)
2293 {
2294 m_tab_ctrl_height = h;
cd05bf23 2295 }
4444d148 2296
cedd7b22 2297protected:
cd05bf23
BW
2298 void DoSetSize(int x, int y,
2299 int width, int height,
2300 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
2301 {
2302 m_rect = wxRect(x, y, width, height);
2303 DoSizing();
2304 }
4444d148 2305
cd05bf23
BW
2306 void DoGetClientSize(int* x, int* y) const
2307 {
2308 *x = m_rect.width;
2309 *y = m_rect.height;
2310 }
4f450f41 2311
cedd7b22 2312public:
4f450f41 2313 bool Show( bool WXUNUSED(show = true) ) { return false; }
4444d148 2314
cd05bf23
BW
2315 void DoSizing()
2316 {
2317 if (!m_tabs)
2318 return;
4444d148 2319
b0d17f7c
BW
2320 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2321 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2322 m_tabs->SetRect(wxRect(0, 0, m_rect.width, m_tab_ctrl_height));
cd05bf23 2323 m_tabs->Refresh();
9d59bf68 2324 m_tabs->Update();
4444d148 2325
cd05bf23
BW
2326 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
2327 size_t i, page_count = pages.GetCount();
4444d148 2328
cd05bf23
BW
2329 for (i = 0; i < page_count; ++i)
2330 {
2331 wxAuiNotebookPage& page = pages.Item(i);
b0d17f7c
BW
2332 page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height,
2333 m_rect.width, m_rect.height - m_tab_ctrl_height);
4444d148 2334
a3a5df9d 2335 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
cd05bf23 2336 {
a3a5df9d 2337 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
cd05bf23
BW
2338 wnd->ApplyMDIChildFrameRect();
2339 }
2340 }
2341 }
2342
cedd7b22 2343protected:
134e83cb
BW
2344 void DoGetSize(int* x, int* y) const
2345 {
2346 if (x)
2347 *x = m_rect.GetWidth();
2348 if (y)
2349 *y = m_rect.GetHeight();
2350 }
4444d148 2351
cedd7b22 2352public:
134e83cb
BW
2353 void Update()
2354 {
2355 // does nothing
2356 }
4444d148 2357
cd05bf23
BW
2358 wxRect m_rect;
2359 wxRect m_tab_rect;
2360 wxAuiTabCtrl* m_tabs;
da5e85d9 2361 int m_tab_ctrl_height;
cd05bf23
BW
2362};
2363
2364
7ebc40e8 2365const int wxAuiBaseTabCtrlId = 5380;
cd05bf23
BW
2366
2367
a3a5df9d 2368// -- wxAuiNotebook class implementation --
cd05bf23 2369
a3a5df9d 2370BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
9fbb7d80 2371 EVT_SIZE(wxAuiNotebook::OnSize)
a3a5df9d 2372 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
7ebc40e8 2373 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
cd05bf23 2374 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
a3a5df9d 2375 wxAuiNotebook::OnTabClicked)
7ebc40e8 2376 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
cd05bf23 2377 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
a3a5df9d 2378 wxAuiNotebook::OnTabBeginDrag)
7ebc40e8 2379 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
cd05bf23 2380 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
a3a5df9d 2381 wxAuiNotebook::OnTabEndDrag)
7ebc40e8 2382 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
cd05bf23 2383 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
a3a5df9d 2384 wxAuiNotebook::OnTabDragMotion)
7ebc40e8 2385 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
cd05bf23 2386 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
a3a5df9d 2387 wxAuiNotebook::OnTabButton)
69f5e420
BW
2388 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2389 wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN,
2390 wxAuiNotebook::OnTabMiddleDown)
2391 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2392 wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP,
2393 wxAuiNotebook::OnTabMiddleUp)
2394 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2395 wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN,
2396 wxAuiNotebook::OnTabRightDown)
2397 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2398 wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
2399 wxAuiNotebook::OnTabRightUp)
cd05bf23
BW
2400END_EVENT_TABLE()
2401
a3a5df9d 2402wxAuiNotebook::wxAuiNotebook()
cd05bf23
BW
2403{
2404 m_curpage = -1;
7ebc40e8 2405 m_tab_id_counter = wxAuiBaseTabCtrlId;
cd05bf23 2406 m_dummy_wnd = NULL;
da5e85d9 2407 m_tab_ctrl_height = 20;
9fbb7d80 2408 m_requested_bmp_size = wxDefaultSize;
ca0d4407 2409 m_requested_tabctrl_height = -1;
cd05bf23
BW
2410}
2411
a3a5df9d 2412wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
cd05bf23
BW
2413 wxWindowID id,
2414 const wxPoint& pos,
2415 const wxSize& size,
2416 long style) : wxControl(parent, id, pos, size, style)
2417{
9fbb7d80
BW
2418 m_dummy_wnd = NULL;
2419 m_requested_bmp_size = wxDefaultSize;
ca0d4407 2420 m_requested_tabctrl_height = -1;
702b1c7e 2421 InitNotebook(style);
cd05bf23
BW
2422}
2423
a3a5df9d 2424bool wxAuiNotebook::Create(wxWindow* parent,
cd05bf23
BW
2425 wxWindowID id,
2426 const wxPoint& pos,
2427 const wxSize& size,
2428 long style)
2429{
2430 if (!wxControl::Create(parent, id, pos, size, style))
2431 return false;
4444d148 2432
702b1c7e 2433 InitNotebook(style);
4444d148 2434
cd05bf23
BW
2435 return true;
2436}
2437
2438// InitNotebook() contains common initialization
2439// code called by all constructors
a3a5df9d 2440void wxAuiNotebook::InitNotebook(long style)
cd05bf23 2441{
da5e85d9 2442 m_curpage = -1;
7ebc40e8 2443 m_tab_id_counter = wxAuiBaseTabCtrlId;
da5e85d9 2444 m_dummy_wnd = NULL;
702b1c7e 2445 m_flags = (unsigned int)style;
ca0d4407 2446 m_tab_ctrl_height = 20;
c58ba15f 2447
cd05bf23
BW
2448 m_normal_font = *wxNORMAL_FONT;
2449 m_selected_font = *wxNORMAL_FONT;
2450 m_selected_font.SetWeight(wxBOLD);
4444d148 2451
b0d17f7c 2452 SetArtProvider(new wxAuiDefaultTabArt);
4444d148
WS
2453
2454 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
cd05bf23
BW
2455 m_dummy_wnd->SetSize(200, 200);
2456 m_dummy_wnd->Show(false);
4444d148 2457
cd05bf23 2458 m_mgr.SetManagedWindow(this);
a6b7a521
VZ
2459 m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
2460 m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
4444d148 2461
cd05bf23 2462 m_mgr.AddPane(m_dummy_wnd,
9fbb7d80 2463 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
4444d148 2464
cd05bf23
BW
2465 m_mgr.Update();
2466}
2467
a3a5df9d 2468wxAuiNotebook::~wxAuiNotebook()
cd05bf23
BW
2469{
2470 m_mgr.UnInit();
2471}
2472
a3a5df9d 2473void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
3f69756e
BW
2474{
2475 m_tabs.SetArtProvider(art);
7baac3cb 2476
ca0d4407 2477 UpdateTabCtrlHeight();
2b9aac33
BW
2478}
2479
ca0d4407
BW
2480// SetTabCtrlHeight() is the highest-level override of the
2481// tab height. A call to this function effectively enforces a
2482// specified tab ctrl height, overriding all other considerations,
2483// such as text or bitmap height. It overrides any call to
2484// SetUniformBitmapSize(). Specifying a height of -1 reverts
2485// any previous call and returns to the default behavior
2486
2487void wxAuiNotebook::SetTabCtrlHeight(int height)
2488{
2489 m_requested_tabctrl_height = height;
c58ba15f 2490
ca0d4407
BW
2491 // if window is already initialized, recalculate the tab height
2492 if (m_dummy_wnd)
2493 {
2494 UpdateTabCtrlHeight();
2495 }
2496}
2497
2498
2499// SetUniformBitmapSize() ensures that all tabs will have
2500// the same height, even if some tabs don't have bitmaps
2501// Passing wxDefaultSize to this function will instruct
2502// the control to use dynamic tab height-- so when a tab
2503// with a large bitmap is added, the tab ctrl's height will
2504// automatically increase to accommodate the bitmap
2505
9fbb7d80
BW
2506void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
2507{
2508 m_requested_bmp_size = size;
c58ba15f 2509
9fbb7d80 2510 // if window is already initialized, recalculate the tab height
dbbe02ea
BW
2511 if (m_dummy_wnd)
2512 {
ca0d4407 2513 UpdateTabCtrlHeight();
dbbe02ea 2514 }
9fbb7d80
BW
2515}
2516
ca0d4407
BW
2517// UpdateTabCtrlHeight() does the actual tab resizing. It's meant
2518// to be used interally
2519void wxAuiNotebook::UpdateTabCtrlHeight()
2b9aac33 2520{
ca0d4407
BW
2521 // get the tab ctrl height we will use
2522 int height = CalculateTabCtrlHeight();
c58ba15f 2523
2b9aac33
BW
2524 // if the tab control height needs to change, update
2525 // all of our tab controls with the new height
2526 if (m_tab_ctrl_height != height)
b0d17f7c 2527 {
2b9aac33 2528 wxAuiTabArt* art = m_tabs.GetArtProvider();
7baac3cb 2529
2b9aac33 2530 m_tab_ctrl_height = height;
7baac3cb 2531
2b9aac33
BW
2532 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2533 size_t i, pane_count = all_panes.GetCount();
2534 for (i = 0; i < pane_count; ++i)
2535 {
2536 wxAuiPaneInfo& pane = all_panes.Item(i);
2537 if (pane.name == wxT("dummy"))
2538 continue;
2539 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
2540 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
2541 tab_frame->SetTabCtrlHeight(m_tab_ctrl_height);
2542 tabctrl->SetArtProvider(art->Clone());
2543 tab_frame->DoSizing();
2544 }
b0d17f7c 2545 }
3f69756e
BW
2546}
2547
9fbb7d80
BW
2548void wxAuiNotebook::UpdateHintWindowSize()
2549{
2550 wxSize size = CalculateNewSplitSize();
c58ba15f 2551
9fbb7d80
BW
2552 // the placeholder hint window should be set to this size
2553 wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
2554 if (info.IsOk())
2555 {
2556 info.MinSize(size);
2557 info.BestSize(size);
2558 m_dummy_wnd->SetSize(size);
2559 }
2560}
2561
2562
2563// calculates the size of the new split
2564wxSize wxAuiNotebook::CalculateNewSplitSize()
2565{
2566 // count number of tab controls
2567 int tab_ctrl_count = 0;
2568 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2569 size_t i, pane_count = all_panes.GetCount();
2570 for (i = 0; i < pane_count; ++i)
2571 {
2572 wxAuiPaneInfo& pane = all_panes.Item(i);
2573 if (pane.name == wxT("dummy"))
2574 continue;
2575 tab_ctrl_count++;
2576 }
2577
2578 wxSize new_split_size;
c58ba15f 2579
9fbb7d80
BW
2580 // if there is only one tab control, the first split
2581 // should happen around the middle
2582 if (tab_ctrl_count < 2)
2583 {
2584 new_split_size = GetClientSize();
2585 new_split_size.x /= 2;
2586 new_split_size.y /= 2;
2587 }
cedd7b22 2588 else
9fbb7d80
BW
2589 {
2590 // this is in place of a more complicated calculation
2591 // that needs to be implemented
2592 new_split_size = wxSize(180,180);
2593 }
c58ba15f 2594
9fbb7d80
BW
2595 return new_split_size;
2596}
2597
2b9aac33
BW
2598int wxAuiNotebook::CalculateTabCtrlHeight()
2599{
ca0d4407
BW
2600 // if a fixed tab ctrl height is specified,
2601 // just return that instead of calculating a
2602 // tab height
2603 if (m_requested_tabctrl_height != -1)
2604 return m_requested_tabctrl_height;
c58ba15f 2605
2b9aac33
BW
2606 // find out new best tab height
2607 wxAuiTabArt* art = m_tabs.GetArtProvider();
7baac3cb 2608
9fbb7d80
BW
2609 return art->GetBestTabCtrlSize(this,
2610 m_tabs.GetPages(),
2611 m_requested_bmp_size);
2b9aac33
BW
2612}
2613
2614
e0dc13d4 2615wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
3f69756e
BW
2616{
2617 return m_tabs.GetArtProvider();
2618}
2619
0ce53f32
BW
2620void wxAuiNotebook::SetWindowStyleFlag(long style)
2621{
2622 wxControl::SetWindowStyleFlag(style);
7baac3cb 2623
0ce53f32 2624 m_flags = (unsigned int)style;
7baac3cb 2625
0ce53f32
BW
2626 // if the control is already initialized
2627 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
2628 {
2629 // let all of the tab children know about the new style
7baac3cb 2630
0ce53f32
BW
2631 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2632 size_t i, pane_count = all_panes.GetCount();
2633 for (i = 0; i < pane_count; ++i)
2634 {
2635 wxAuiPaneInfo& pane = all_panes.Item(i);
2636 if (pane.name == wxT("dummy"))
2637 continue;
97ac2d5e
BW
2638 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
2639 wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
0ce53f32 2640 tabctrl->SetFlags(m_flags);
97ac2d5e 2641 tabframe->DoSizing();
0ce53f32
BW
2642 tabctrl->Refresh();
2643 tabctrl->Update();
2644 }
2645 }
2646}
2647
2648
a3a5df9d 2649bool wxAuiNotebook::AddPage(wxWindow* page,
cd05bf23
BW
2650 const wxString& caption,
2651 bool select,
2652 const wxBitmap& bitmap)
2653{
2654 return InsertPage(GetPageCount(), page, caption, select, bitmap);
2655}
4444d148 2656
a3a5df9d 2657bool wxAuiNotebook::InsertPage(size_t page_idx,
cd05bf23
BW
2658 wxWindow* page,
2659 const wxString& caption,
2660 bool select,
2661 const wxBitmap& bitmap)
2662{
2663 wxAuiNotebookPage info;
2664 info.window = page;
2665 info.caption = caption;
2666 info.bitmap = bitmap;
2667 info.active = false;
2668
2669 // if there are currently no tabs, the first added
2670 // tab must be active
2671 if (m_tabs.GetPageCount() == 0)
2672 info.active = true;
2673
2674 m_tabs.InsertPage(page, info, page_idx);
2675
298773ec
BW
2676 // if that was the first page added, even if
2677 // select is false, it must become the "current page"
2678 // (though no select events will be fired)
2679 if (!select && m_tabs.GetPageCount() == 1)
092d7f88
BW
2680 select = true;
2681 //m_curpage = GetPageIndex(page);
298773ec 2682
cd05bf23
BW
2683 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
2684 if (page_idx >= active_tabctrl->GetPageCount())
2685 active_tabctrl->AddPage(page, info);
cedd7b22 2686 else
cd05bf23 2687 active_tabctrl->InsertPage(page, info, page_idx);
4444d148 2688
ca0d4407 2689 UpdateTabCtrlHeight();
cd05bf23
BW
2690 DoSizing();
2691 active_tabctrl->DoShowHide();
4444d148 2692
cd05bf23
BW
2693 if (select)
2694 {
849c353a 2695 SetSelectionToWindow(page);
cd05bf23 2696 }
4444d148 2697
cd05bf23
BW
2698 return true;
2699}
2700
2701
2702// DeletePage() removes a tab from the multi-notebook,
2703// and destroys the window as well
a3a5df9d 2704bool wxAuiNotebook::DeletePage(size_t page_idx)
7baac3cb 2705{
fd749f4a
BW
2706 if (page_idx >= m_tabs.GetPageCount())
2707 return false;
cedd7b22 2708
4444d148 2709 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
cedd7b22 2710
fd749f4a
BW
2711 // hide the window in advance, as this will
2712 // prevent flicker
2713 ShowWnd(wnd, false);
5d3aeb0f
BW
2714
2715 if (!RemovePage(page_idx))
2716 return false;
2717
5d3aeb0f
BW
2718 // actually destroy the window now
2719 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2720 {
2721 // delete the child frame with pending delete, as is
2722 // customary with frame windows
2723 if (!wxPendingDelete.Member(wnd))
2724 wxPendingDelete.Append(wnd);
2725 }
cedd7b22 2726 else
5d3aeb0f
BW
2727 {
2728 wnd->Destroy();
2729 }
7baac3cb 2730
5d3aeb0f 2731 return true;
cd05bf23
BW
2732}
2733
2734
2735
2736// RemovePage() removes a tab from the multi-notebook,
2737// but does not destroy the window
a3a5df9d 2738bool wxAuiNotebook::RemovePage(size_t page_idx)
cd05bf23 2739{
9b362935
BW
2740 // save active window pointer
2741 wxWindow* active_wnd = NULL;
2742 if (m_curpage >= 0)
2743 active_wnd = m_tabs.GetWindowFromIdx(m_curpage);
cedd7b22 2744
9b362935 2745 // save pointer of window being deleted
cd05bf23 2746 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
5d3aeb0f 2747 wxWindow* new_active = NULL;
4444d148 2748
13aaa50f
BW
2749 // make sure we found the page
2750 if (!wnd)
2751 return false;
cedd7b22 2752
5d3aeb0f 2753 // find out which onscreen tab ctrl owns this tab
cd05bf23
BW
2754 wxAuiTabCtrl* ctrl;
2755 int ctrl_idx;
5d3aeb0f
BW
2756 if (!FindTab(wnd, &ctrl, &ctrl_idx))
2757 return false;
2758
13aaa50f
BW
2759 bool is_curpage = (m_curpage == (int)page_idx);
2760 bool is_active_in_split = ctrl->GetPage(ctrl_idx).active;
5d3aeb0f 2761
4444d148 2762
5d3aeb0f
BW
2763 // remove the tab from main catalog
2764 if (!m_tabs.RemovePage(wnd))
2765 return false;
2766
2767 // remove the tab from the onscreen tab ctrl
2768 ctrl->RemovePage(wnd);
2769
13aaa50f
BW
2770 if (is_active_in_split)
2771 {
2772 int ctrl_new_page_count = (int)ctrl->GetPageCount();
cedd7b22 2773
13aaa50f
BW
2774 if (ctrl_idx >= ctrl_new_page_count)
2775 ctrl_idx = ctrl_new_page_count-1;
cedd7b22 2776
13aaa50f
BW
2777 if (ctrl_idx >= 0 && ctrl_idx < (int)ctrl->GetPageCount())
2778 {
2779 // set new page as active in the tab split
2780 ctrl->SetActivePage(ctrl_idx);
cedd7b22 2781
13aaa50f
BW
2782 // if the page deleted was the current page for the
2783 // entire tab control, then record the window
2784 // pointer of the new active page for activation
2785 if (is_curpage)
2786 {
2787 new_active = ctrl->GetWindowFromIdx(ctrl_idx);
2788 }
2789 }
2790 }
cedd7b22 2791 else
9b362935
BW
2792 {
2793 // we are not deleting the active page, so keep it the same
2794 new_active = active_wnd;
2795 }
13aaa50f 2796
cedd7b22 2797
13aaa50f
BW
2798 if (!new_active)
2799 {
2800 // we haven't yet found a new page to active,
2801 // so select the next page from the main tab
2802 // catalogue
cedd7b22 2803
13aaa50f
BW
2804 if (page_idx < m_tabs.GetPageCount())
2805 {
2806 new_active = m_tabs.GetPage(page_idx).window;
2807 }
cedd7b22 2808
13aaa50f
BW
2809 if (!new_active && m_tabs.GetPageCount() > 0)
2810 {
2811 new_active = m_tabs.GetPage(0).window;
2812 }
2813 }
5d3aeb0f 2814
cedd7b22 2815
5d3aeb0f
BW
2816 RemoveEmptyTabFrames();
2817
2818 // set new active pane
2819 if (new_active)
2820 {
2821 m_curpage = -1;
849c353a 2822 SetSelectionToWindow(new_active);
5d3aeb0f 2823 }
cedd7b22 2824
5d3aeb0f 2825 return true;
cd05bf23
BW
2826}
2827
e0dc13d4
BW
2828// GetPageIndex() returns the index of the page, or -1 if the
2829// page could not be located in the notebook
2830int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2831{
2832 return m_tabs.GetIdxFromWindow(page_wnd);
2833}
2834
2835
2836
cd05bf23 2837// SetPageText() changes the tab caption of the specified page
a3a5df9d 2838bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
4444d148 2839{
cd05bf23
BW
2840 if (page_idx >= m_tabs.GetPageCount())
2841 return false;
4444d148 2842
cd05bf23
BW
2843 // update our own tab catalog
2844 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2845 page_info.caption = text;
4444d148 2846
cd05bf23
BW
2847 // update what's on screen
2848 wxAuiTabCtrl* ctrl;
2849 int ctrl_idx;
2850 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2851 {
2852 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2853 info.caption = text;
2854 ctrl->Refresh();
639a4f7b 2855 ctrl->Update();
cd05bf23 2856 }
4444d148 2857
cd05bf23
BW
2858 return true;
2859}
2860
c3e016e4
JS
2861// returns the page caption
2862wxString wxAuiNotebook::GetPageText(size_t page_idx) const
2863{
2864 if (page_idx >= m_tabs.GetPageCount())
2865 return wxEmptyString;
2866
2867 // update our own tab catalog
2868 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2869 return page_info.caption;
2870}
e0dc13d4
BW
2871
2872bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2873{
2874 if (page_idx >= m_tabs.GetPageCount())
2875 return false;
7baac3cb 2876
e0dc13d4
BW
2877 // update our own tab catalog
2878 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2879 page_info.bitmap = bitmap;
7baac3cb 2880
e0dc13d4 2881 // tab height might have changed
ca0d4407 2882 UpdateTabCtrlHeight();
7baac3cb 2883
e0dc13d4
BW
2884 // update what's on screen
2885 wxAuiTabCtrl* ctrl;
2886 int ctrl_idx;
2887 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2888 {
2889 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2890 info.bitmap = bitmap;
2891 ctrl->Refresh();
2892 ctrl->Update();
2893 }
7baac3cb 2894
e0dc13d4
BW
2895 return true;
2896}
2897
c3e016e4
JS
2898// returns the page bitmap
2899wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const
2900{
2901 if (page_idx >= m_tabs.GetPageCount())
2902 return wxBitmap();
2903
2904 // update our own tab catalog
2905 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2906 return page_info.bitmap;
2907}
e0dc13d4 2908
cd05bf23 2909// GetSelection() returns the index of the currently active page
a3a5df9d 2910int wxAuiNotebook::GetSelection() const
cd05bf23
BW
2911{
2912 return m_curpage;
2913}
2914
2915// SetSelection() sets the currently active page
a3a5df9d 2916size_t wxAuiNotebook::SetSelection(size_t new_page)
cd05bf23 2917{
68fd4f2c 2918 // don't change the page unless necessary
c58ba15f 2919 if ((int)new_page == m_curpage)
68fd4f2c 2920 return m_curpage;
c58ba15f 2921
cd05bf23
BW
2922 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
2923 if (!wnd)
2924 return m_curpage;
4444d148 2925
cd05bf23
BW
2926 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2927 evt.SetSelection(new_page);
2928 evt.SetOldSelection(m_curpage);
2929 evt.SetEventObject(this);
7ebc40e8 2930 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
cd05bf23 2931 {
049333c2
BW
2932 int old_curpage = m_curpage;
2933 m_curpage = new_page;
7baac3cb 2934
cd05bf23
BW
2935 // program allows the page change
2936 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
7ebc40e8 2937 (void)GetEventHandler()->ProcessEvent(evt);
cd05bf23
BW
2938
2939
cd05bf23
BW
2940 wxAuiTabCtrl* ctrl;
2941 int ctrl_idx;
2942 if (FindTab(wnd, &ctrl, &ctrl_idx))
4444d148 2943 {
cd05bf23 2944 m_tabs.SetActivePage(wnd);
4444d148 2945
cd05bf23
BW
2946 ctrl->SetActivePage(ctrl_idx);
2947 DoSizing();
2948 ctrl->DoShowHide();
4444d148 2949
cd05bf23
BW
2950
2951
2952 // set fonts
a3a5df9d 2953 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
2954 size_t i, pane_count = all_panes.GetCount();
2955 for (i = 0; i < pane_count; ++i)
2956 {
a3a5df9d 2957 wxAuiPaneInfo& pane = all_panes.Item(i);
cd05bf23
BW
2958 if (pane.name == wxT("dummy"))
2959 continue;
2960 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2961 if (tabctrl != ctrl)
2962 tabctrl->SetSelectedFont(m_normal_font);
cedd7b22 2963 else
cd05bf23
BW
2964 tabctrl->SetSelectedFont(m_selected_font);
2965 tabctrl->Refresh();
2966 }
2967
2968 wnd->SetFocus();
4444d148 2969
cd05bf23
BW
2970 return old_curpage;
2971 }
2972 }
2973
2974 return m_curpage;
2975}
2976
849c353a
VZ
2977void wxAuiNotebook::SetSelectionToWindow(wxWindow *win)
2978{
2979 const int idx = m_tabs.GetIdxFromWindow(win);
2980 wxCHECK_RET( idx != wxNOT_FOUND, _T("invalid notebook page") );
2981
2982 SetSelection(idx);
2983}
2984
cd05bf23
BW
2985// GetPageCount() returns the total number of
2986// pages managed by the multi-notebook
a3a5df9d 2987size_t wxAuiNotebook::GetPageCount() const
cd05bf23
BW
2988{
2989 return m_tabs.GetPageCount();
2990}
2991
2992// GetPage() returns the wxWindow pointer of the
2993// specified page
a3a5df9d 2994wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
cd05bf23
BW
2995{
2996 wxASSERT(page_idx < m_tabs.GetPageCount());
4444d148 2997
cd05bf23
BW
2998 return m_tabs.GetWindowFromIdx(page_idx);
2999}
3000
3001// DoSizing() performs all sizing operations in each tab control
a3a5df9d 3002void wxAuiNotebook::DoSizing()
cd05bf23 3003{
a3a5df9d 3004 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
3005 size_t i, pane_count = all_panes.GetCount();
3006 for (i = 0; i < pane_count; ++i)
3007 {
3008 if (all_panes.Item(i).name == wxT("dummy"))
3009 continue;
3010
3011 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3012 tabframe->DoSizing();
3013 }
3014}
3015
3016// GetActiveTabCtrl() returns the active tab control. It is
3017// called to determine which control gets new windows being added
a3a5df9d 3018wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
cd05bf23
BW
3019{
3020 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
3021 {
3022 wxAuiTabCtrl* ctrl;
3023 int idx;
4444d148 3024
cd05bf23
BW
3025 // find the tab ctrl with the current page
3026 if (FindTab(m_tabs.GetPage(m_curpage).window,
3027 &ctrl, &idx))
4444d148 3028 {
cd05bf23
BW
3029 return ctrl;
3030 }
3031 }
4444d148 3032
cd05bf23 3033 // no current page, just find the first tab ctrl
a3a5df9d 3034 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
3035 size_t i, pane_count = all_panes.GetCount();
3036 for (i = 0; i < pane_count; ++i)
3037 {
3038 if (all_panes.Item(i).name == wxT("dummy"))
3039 continue;
4444d148 3040
cd05bf23
BW
3041 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3042 return tabframe->m_tabs;
3043 }
4444d148 3044
cd05bf23
BW
3045 // If there is no tabframe at all, create one
3046 wxTabFrame* tabframe = new wxTabFrame;
da5e85d9 3047 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
cd05bf23
BW
3048 tabframe->m_tabs = new wxAuiTabCtrl(this,
3049 m_tab_id_counter++,
3050 wxDefaultPosition,
3051 wxDefaultSize,
3052 wxNO_BORDER);
702b1c7e 3053 tabframe->m_tabs->SetFlags(m_flags);
b0d17f7c 3054 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
cd05bf23 3055 m_mgr.AddPane(tabframe,
a3a5df9d 3056 wxAuiPaneInfo().Center().CaptionVisible(false));
4444d148 3057
cd05bf23 3058 m_mgr.Update();
4444d148 3059
cd05bf23
BW
3060 return tabframe->m_tabs;
3061}
3062
3063// FindTab() finds the tab control that currently contains the window as well
3064// as the index of the window in the tab control. It returns true if the
3065// window was found, otherwise false.
a3a5df9d 3066bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
cd05bf23 3067{
a3a5df9d 3068 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
3069 size_t i, pane_count = all_panes.GetCount();
3070 for (i = 0; i < pane_count; ++i)
3071 {
3072 if (all_panes.Item(i).name == wxT("dummy"))
3073 continue;
4444d148 3074
cd05bf23 3075 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
4444d148 3076
cd05bf23
BW
3077 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
3078 if (page_idx != -1)
3079 {
3080 *ctrl = tabframe->m_tabs;
3081 *idx = page_idx;
3082 return true;
3083 }
3084 }
4444d148 3085
cd05bf23
BW
3086 return false;
3087}
3088
d606b6e9
BW
3089void wxAuiNotebook::Split(size_t page, int direction)
3090{
3091 wxSize cli_size = GetClientSize();
54a8a78e 3092
d606b6e9
BW
3093 // get the page's window pointer
3094 wxWindow* wnd = GetPage(page);
3095 if (!wnd)
3096 return;
54a8a78e 3097
d606b6e9
BW
3098 // notebooks with 1 or less pages can't be split
3099 if (GetPageCount() < 2)
3100 return;
54a8a78e 3101
d606b6e9
BW
3102 // find out which tab control the page currently belongs to
3103 wxAuiTabCtrl *src_tabs, *dest_tabs;
3104 int src_idx = -1;
3105 src_tabs = NULL;
3106 if (!FindTab(wnd, &src_tabs, &src_idx))
3107 return;
3108 if (!src_tabs || src_idx == -1)
3109 return;
54a8a78e 3110
d606b6e9
BW
3111 // choose a split size
3112 wxSize split_size;
3113 if (GetPageCount() > 2)
3114 {
3115 split_size = CalculateNewSplitSize();
3116 }
cedd7b22 3117 else
d606b6e9
BW
3118 {
3119 // because there are two panes, always split them
3120 // equally
3121 split_size = GetClientSize();
3122 split_size.x /= 2;
3123 split_size.y /= 2;
3124 }
54a8a78e
VZ
3125
3126
d606b6e9
BW
3127 // create a new tab frame
3128 wxTabFrame* new_tabs = new wxTabFrame;
3129 new_tabs->m_rect = wxRect(wxPoint(0,0), split_size);
3130 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3131 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3132 m_tab_id_counter++,
3133 wxDefaultPosition,
3134 wxDefaultSize,
3135 wxNO_BORDER);
3136 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3137 new_tabs->m_tabs->SetFlags(m_flags);
3138 dest_tabs = new_tabs->m_tabs;
3139
3140 // create a pane info structure with the information
3141 // about where the pane should be added
3142 wxAuiPaneInfo pane_info = wxAuiPaneInfo().Bottom().CaptionVisible(false);
3143 wxPoint mouse_pt;
54a8a78e 3144
d606b6e9
BW
3145 if (direction == wxLEFT)
3146 {
3147 pane_info.Left();
3148 mouse_pt = wxPoint(0, cli_size.y/2);
3149 }
cedd7b22 3150 else if (direction == wxRIGHT)
d606b6e9
BW
3151 {
3152 pane_info.Right();
3153 mouse_pt = wxPoint(cli_size.x, cli_size.y/2);
3154 }
cedd7b22 3155 else if (direction == wxTOP)
d606b6e9
BW
3156 {
3157 pane_info.Top();
3158 mouse_pt = wxPoint(cli_size.x/2, 0);
3159 }
cedd7b22 3160 else if (direction == wxBOTTOM)
d606b6e9
BW
3161 {
3162 pane_info.Bottom();
3163 mouse_pt = wxPoint(cli_size.x/2, cli_size.y);
3164 }
54a8a78e 3165
d606b6e9
BW
3166 m_mgr.AddPane(new_tabs, pane_info, mouse_pt);
3167 m_mgr.Update();
54a8a78e 3168
d606b6e9
BW
3169 // remove the page from the source tabs
3170 wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx);
3171 page_info.active = false;
3172 src_tabs->RemovePage(page_info.window);
3173 if (src_tabs->GetPageCount() > 0)
3174 {
3175 src_tabs->SetActivePage((size_t)0);
3176 src_tabs->DoShowHide();
3177 src_tabs->Refresh();
3178 }
3179
3180
3181 // add the page to the destination tabs
3182 dest_tabs->InsertPage(page_info.window, page_info, 0);
3183
3184 if (src_tabs->GetPageCount() == 0)
3185 {
3186 RemoveEmptyTabFrames();
3187 }
3188
3189 DoSizing();
3190 dest_tabs->DoShowHide();
3191 dest_tabs->Refresh();
3192
3193 // force the set selection function reset the selection
3194 m_curpage = -1;
54a8a78e 3195
d606b6e9 3196 // set the active page to the one we just split off
849c353a 3197 SetSelectionToPage(page_info);
54a8a78e 3198
d606b6e9
BW
3199 UpdateHintWindowSize();
3200}
3201
3202
9fbb7d80 3203void wxAuiNotebook::OnSize(wxSizeEvent& evt)
cd05bf23 3204{
9fbb7d80 3205 UpdateHintWindowSize();
c58ba15f 3206
9fbb7d80 3207 evt.Skip();
cd05bf23
BW
3208}
3209
a3a5df9d 3210void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
cd05bf23
BW
3211{
3212 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
4444d148 3213
cd05bf23
BW
3214 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
3215 wxASSERT(ctrl != NULL);
4444d148 3216
cd05bf23
BW
3217 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
3218 wxASSERT(wnd != NULL);
4444d148 3219
849c353a 3220 SetSelectionToWindow(wnd);
cd05bf23
BW
3221}
3222
a3a5df9d 3223void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
cd05bf23 3224{
08c068a4 3225 m_last_drag_x = 0;
cd05bf23
BW
3226}
3227
a3a5df9d 3228void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
cd05bf23
BW
3229{
3230 wxPoint screen_pt = ::wxGetMousePosition();
3231 wxPoint client_pt = ScreenToClient(screen_pt);
3232 wxPoint zero(0,0);
4444d148 3233
cd05bf23 3234 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
08c068a4 3235 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
7baac3cb 3236
08c068a4 3237 if (dest_tabs == src_tabs)
cd05bf23 3238 {
3941df70
BW
3239 if (src_tabs)
3240 {
3241 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3242 }
7baac3cb 3243
08c068a4 3244 // always hide the hint for inner-tabctrl drag
cd05bf23 3245 m_mgr.HideHint();
7baac3cb 3246
695c0088
BW
3247 // if tab moving is not allowed, leave
3248 if (!(m_flags & wxAUI_NB_TAB_MOVE))
3249 {
3250 return;
3251 }
7baac3cb 3252
08c068a4
BW
3253 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
3254 wxWindow* dest_location_tab;
7baac3cb 3255
08c068a4
BW
3256 // this is an inner-tab drag/reposition
3257 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
3258 {
3259 int src_idx = evt.GetSelection();
3260 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
7baac3cb 3261
08c068a4
BW
3262 // prevent jumpy drag
3263 if ((src_idx == dest_idx) || dest_idx == -1 ||
3264 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
3265 (src_idx < dest_idx && m_last_drag_x >= pt.x))
3266 {
3267 m_last_drag_x = pt.x;
3268 return;
3269 }
3270
3271
3272 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
3273 dest_tabs->MovePage(src_tab, dest_idx);
3274 dest_tabs->SetActivePage((size_t)dest_idx);
3275 dest_tabs->DoShowHide();
3276 dest_tabs->Refresh();
3277 m_last_drag_x = pt.x;
3278
3279 }
7baac3cb 3280
cd05bf23
BW
3281 return;
3282 }
4444d148 3283
695c0088 3284
5d3aeb0f
BW
3285 // if external drag is allowed, check if the tab is being dragged
3286 // over a different wxAuiNotebook control
3287 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3288 {
3289 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
7baac3cb 3290
87e5fe69
BW
3291 // if we aren't over any window, stop here
3292 if (!tab_ctrl)
3293 return;
7baac3cb 3294
13d0b605 3295 // make sure we are not over the hint window
87e5fe69 3296 if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
5d3aeb0f 3297 {
13d0b605 3298 while (tab_ctrl)
5d3aeb0f 3299 {
13d0b605
BW
3300 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3301 break;
3302 tab_ctrl = tab_ctrl->GetParent();
5d3aeb0f 3303 }
7baac3cb 3304
13d0b605
BW
3305 if (tab_ctrl)
3306 {
3307 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
7baac3cb 3308
13d0b605
BW
3309 if (nb != this)
3310 {
87e5fe69 3311 wxRect hint_rect = tab_ctrl->GetClientRect();
13d0b605
BW
3312 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
3313 m_mgr.ShowHint(hint_rect);
3314 return;
3315 }
87e5fe69
BW
3316 }
3317 }
cedd7b22 3318 else
87e5fe69
BW
3319 {
3320 if (!dest_tabs)
3321 {
3322 // we are either over a hint window, or not over a tab
3323 // window, and there is no where to drag to, so exit
3324 return;
13d0b605 3325 }
5d3aeb0f
BW
3326 }
3327 }
3328
3329
69685ee0
BW
3330 // if there are less than two panes, split can't happen, so leave
3331 if (m_tabs.GetPageCount() < 2)
3332 return;
7baac3cb 3333
695c0088
BW
3334 // if tab moving is not allowed, leave
3335 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
695c0088 3336 return;
695c0088 3337
3941df70
BW
3338
3339 if (src_tabs)
3340 {
3341 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
3342 }
7baac3cb
VZ
3343
3344
08c068a4 3345 if (dest_tabs)
cd05bf23 3346 {
08c068a4 3347 wxRect hint_rect = dest_tabs->GetRect();
cd05bf23
BW
3348 ClientToScreen(&hint_rect.x, &hint_rect.y);
3349 m_mgr.ShowHint(hint_rect);
3350 }
cedd7b22 3351 else
cd05bf23
BW
3352 {
3353 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
3354 }
3355}
3356
3357
3358
a3a5df9d 3359void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
cd05bf23
BW
3360{
3361 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3362
3363 m_mgr.HideHint();
4444d148 3364
7baac3cb 3365
3941df70 3366 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
54a8a78e
VZ
3367 wxCHECK_RET( src_tabs, _T("no source object?") );
3368
3369 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
7baac3cb 3370
cd05bf23
BW
3371 // get the mouse position, which will be used to determine the drop point
3372 wxPoint mouse_screen_pt = ::wxGetMousePosition();
3373 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
3374
3375
4444d148 3376
5d3aeb0f
BW
3377 // check for an external move
3378 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
cd05bf23 3379 {
5d3aeb0f 3380 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
7baac3cb 3381
5d3aeb0f 3382 while (tab_ctrl)
c69532f7 3383 {
5d3aeb0f
BW
3384 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3385 break;
3386 tab_ctrl = tab_ctrl->GetParent();
c69532f7 3387 }
7baac3cb 3388
5d3aeb0f
BW
3389 if (tab_ctrl)
3390 {
3391 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
7baac3cb 3392
5d3aeb0f
BW
3393 if (nb != this)
3394 {
3395 // find out from the destination control
3396 // if it's ok to drop this tab here
3397 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
3398 e.SetSelection(evt.GetSelection());
3399 e.SetOldSelection(evt.GetSelection());
3400 e.SetEventObject(this);
3401 e.SetDragSource(this);
3402 e.Veto(); // dropping must be explicitly approved by control owner
7baac3cb 3403
5d3aeb0f 3404 nb->GetEventHandler()->ProcessEvent(e);
7baac3cb 3405
5d3aeb0f
BW
3406 if (!e.IsAllowed())
3407 {
3408 // no answer or negative answer
3409 m_mgr.HideHint();
3410 return;
3411 }
7baac3cb 3412
5d3aeb0f
BW
3413 // drop was allowed
3414 int src_idx = evt.GetSelection();
3415 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
7baac3cb 3416
884a369a
JS
3417 // Check that it's not an impossible parent relationship
3418 wxWindow* p = nb;
3419 while (p && !p->IsTopLevel())
3420 {
3421 if (p == src_page)
3422 {
3423 return;
3424 }
3425 p = p->GetParent();
3426 }
3427
5d3aeb0f
BW
3428 // get main index of the page
3429 int main_idx = m_tabs.GetIdxFromWindow(src_page);
849c353a
VZ
3430 wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no source page?") );
3431
7baac3cb 3432
5d3aeb0f 3433 // make a copy of the page info
849c353a 3434 wxAuiNotebookPage page_info = m_tabs.GetPage(main_idx);
7baac3cb 3435
5d3aeb0f
BW
3436 // remove the page from the source notebook
3437 RemovePage(main_idx);
7baac3cb 3438
5d3aeb0f
BW
3439 // reparent the page
3440 src_page->Reparent(nb);
7baac3cb
VZ
3441
3442
5d3aeb0f
BW
3443 // found out the insert idx
3444 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
3445 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3446
3447 wxWindow* target = NULL;
3448 int insert_idx = -1;
3449 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3450 if (target)
3451 {
3452 insert_idx = dest_tabs->GetIdxFromWindow(target);
3453 }
702b1c7e 3454
7baac3cb 3455
5d3aeb0f
BW
3456 // add the page to the new notebook
3457 if (insert_idx == -1)
3458 insert_idx = dest_tabs->GetPageCount();
3459 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3460 nb->m_tabs.AddPage(page_info.window, page_info);
3461
3462 nb->DoSizing();
3463 dest_tabs->DoShowHide();
3464 dest_tabs->Refresh();
7baac3cb 3465
5d3aeb0f 3466 // set the selection in the destination tab control
849c353a 3467 nb->SetSelectionToPage(page_info);
5d3aeb0f
BW
3468
3469 return;
3470 }
3471 }
cd05bf23 3472 }
4444d148
WS
3473
3474
3475
5d3aeb0f
BW
3476
3477 // only perform a tab split if it's allowed
54a8a78e
VZ
3478 wxAuiTabCtrl* dest_tabs = NULL;
3479
69685ee0 3480 if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
cd05bf23 3481 {
5d3aeb0f
BW
3482 // If the pointer is in an existing tab frame, do a tab insert
3483 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
3484 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
3485 int insert_idx = -1;
3486 if (tab_frame)
3487 {
3488 dest_tabs = tab_frame->m_tabs;
cd05bf23 3489
5d3aeb0f
BW
3490 if (dest_tabs == src_tabs)
3491 return;
7baac3cb
VZ
3492
3493
5d3aeb0f
BW
3494 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3495 wxWindow* target = NULL;
3496 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3497 if (target)
3498 {
3499 insert_idx = dest_tabs->GetIdxFromWindow(target);
3500 }
3501 }
54a8a78e 3502 else
5d3aeb0f 3503 {
ce15b45f
BW
3504 wxPoint zero(0,0);
3505 wxRect rect = m_mgr.CalculateHintRect(m_dummy_wnd,
3506 mouse_client_pt,
3507 zero);
3508 if (rect.IsEmpty())
3509 {
3510 // there is no suitable drop location here, exit out
3511 return;
3512 }
7baac3cb 3513
5d3aeb0f
BW
3514 // If there is no tabframe at all, create one
3515 wxTabFrame* new_tabs = new wxTabFrame;
9fbb7d80 3516 new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
5d3aeb0f
BW
3517 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3518 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3519 m_tab_id_counter++,
3520 wxDefaultPosition,
3521 wxDefaultSize,
3522 wxNO_BORDER);
b0d17f7c 3523 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
5d3aeb0f
BW
3524 new_tabs->m_tabs->SetFlags(m_flags);
3525
3526 m_mgr.AddPane(new_tabs,
3527 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3528 mouse_client_pt);
3529 m_mgr.Update();
3530 dest_tabs = new_tabs->m_tabs;
3531 }
4444d148
WS
3532
3533
4444d148 3534
5d3aeb0f
BW
3535 // remove the page from the source tabs
3536 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
3537 page_info.active = false;
3538 src_tabs->RemovePage(page_info.window);
3539 if (src_tabs->GetPageCount() > 0)
3540 {
3541 src_tabs->SetActivePage((size_t)0);
3542 src_tabs->DoShowHide();
3543 src_tabs->Refresh();
3544 }
4444d148 3545
cd05bf23 3546
5d3aeb0f
BW
3547
3548 // add the page to the destination tabs
3549 if (insert_idx == -1)
3550 insert_idx = dest_tabs->GetPageCount();
3551 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3552
3553 if (src_tabs->GetPageCount() == 0)
3554 {
3555 RemoveEmptyTabFrames();
3556 }
3557
3558 DoSizing();
3559 dest_tabs->DoShowHide();
3560 dest_tabs->Refresh();
3561
68fd4f2c
BW
3562 // force the set selection function reset the selection
3563 m_curpage = -1;
c58ba15f 3564
68fd4f2c 3565 // set the active page to the one we just split off
849c353a 3566 SetSelectionToPage(page_info);
c58ba15f 3567
9fbb7d80 3568 UpdateHintWindowSize();
5d3aeb0f 3569 }
cd05bf23
BW
3570}
3571
3941df70
BW
3572
3573
a3a5df9d 3574wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
cd05bf23
BW
3575{
3576 // if we've just removed the last tab from the source
3577 // tab set, the remove the tab control completely
a3a5df9d 3578 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
3579 size_t i, pane_count = all_panes.GetCount();
3580 for (i = 0; i < pane_count; ++i)
3581 {
3582 if (all_panes.Item(i).name == wxT("dummy"))
3583 continue;
4444d148 3584
cd05bf23 3585 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
22a35096 3586 if (tabframe->m_tab_rect.Contains(pt))
cd05bf23
BW
3587 return tabframe->m_tabs;
3588 }
4444d148 3589
cd05bf23
BW
3590 return NULL;
3591}
3592
a3a5df9d 3593wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
cd05bf23
BW
3594{
3595 // if we've just removed the last tab from the source
3596 // tab set, the remove the tab control completely
a3a5df9d 3597 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
3598 size_t i, pane_count = all_panes.GetCount();
3599 for (i = 0; i < pane_count; ++i)
3600 {
3601 if (all_panes.Item(i).name == wxT("dummy"))
3602 continue;
4444d148 3603
cd05bf23
BW
3604 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3605 if (tabframe->m_tabs == tab_ctrl)
3606 {
3607 return tabframe;
3608 }
3609 }
4444d148 3610
cd05bf23
BW
3611 return NULL;
3612}
3613
a3a5df9d 3614void wxAuiNotebook::RemoveEmptyTabFrames()
cd05bf23 3615{
cd05bf23
BW
3616 // if we've just removed the last tab from the source
3617 // tab set, the remove the tab control completely
a3a5df9d 3618 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
cd05bf23
BW
3619 size_t i, pane_count = all_panes.GetCount();
3620 for (i = 0; i < pane_count; ++i)
3621 {
3622 if (all_panes.Item(i).name == wxT("dummy"))
3623 continue;
3624
3625 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
3626 if (tab_frame->m_tabs->GetPageCount() == 0)
3627 {
3628 m_mgr.DetachPane(tab_frame);
4444d148 3629
cd05bf23
BW
3630 // use pending delete because sometimes during
3631 // window closing, refreshs are pending
3632 if (!wxPendingDelete.Member(tab_frame->m_tabs))
4444d148 3633 wxPendingDelete.Append(tab_frame->m_tabs);
cedd7b22 3634
13aaa50f 3635 tab_frame->m_tabs = NULL;
4444d148 3636
cd05bf23 3637 delete tab_frame;
cd05bf23
BW
3638 }
3639 }
4444d148
WS
3640
3641
cd05bf23
BW
3642 // check to see if there is still a center pane;
3643 // if there isn't, make a frame the center pane
a3a5df9d 3644 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
cd05bf23
BW
3645 pane_count = panes.GetCount();
3646 wxWindow* first_good = NULL;
3647 bool center_found = false;
3648 for (i = 0; i < pane_count; ++i)
3649 {
3650 if (panes.Item(i).name == wxT("dummy"))
3651 continue;
3652 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
3653 center_found = true;
3654 if (!first_good)
3655 first_good = panes.Item(i).window;
3656 }
3657
3658 if (!center_found && first_good)
3659 {
3660 m_mgr.GetPane(first_good).Centre();
cd05bf23
BW
3661 }
3662
4444d148 3663 m_mgr.Update();
cd05bf23
BW
3664}
3665
a3a5df9d 3666void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
cd05bf23 3667{
d16619f8
BW
3668 // if we're dragging a tab, don't change the current selection.
3669 // This code prevents a bug that used to happen when the hint window
3670 // was hidden. In the bug, the focus would return to the notebook
3671 // child, which would then enter this handler and call
3672 // SetSelection, which is not desired turn tab dragging.
cedd7b22 3673
d16619f8
BW
3674 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3675 size_t i, pane_count = all_panes.GetCount();
3676 for (i = 0; i < pane_count; ++i)
3677 {
3678 wxAuiPaneInfo& pane = all_panes.Item(i);
3679 if (pane.name == wxT("dummy"))
3680 continue;
3681 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
3682 if (tabframe->m_tabs->IsDragging())
3683 return;
3684 }
3685
3686
3687 // change the tab selection to the child
3688 // which was focused
cd05bf23
BW
3689 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
3690 if (idx != -1 && idx != m_curpage)
3691 {
4444d148 3692 SetSelection(idx);
cd05bf23
BW
3693 }
3694}
3695
3696
a3a5df9d 3697void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
cd05bf23
BW
3698{
3699 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3700 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4444d148 3701
cd05bf23 3702 int button_id = evt.GetInt();
4444d148 3703
4953f8cf 3704 if (button_id == wxAUI_BUTTON_CLOSE)
cd05bf23 3705 {
9b362935 3706 int selection = evt.GetSelection();
4444d148 3707
94473fa8
BW
3708 if (selection == -1)
3709 {
3710 // if the close button is to the right, use the active
3711 // page selection to determine which page to close
3712 selection = GetSelection();
3713 }
884a369a 3714
cd05bf23
BW
3715 if (selection != -1)
3716 {
3717 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
4444d148 3718
3fd8c988
BW
3719 // ask owner if it's ok to close the tab
3720 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3721 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3722 e.SetOldSelection(evt.GetSelection());
3723 e.SetEventObject(this);
7ebc40e8 3724 GetEventHandler()->ProcessEvent(e);
3fd8c988
BW
3725 if (!e.IsAllowed())
3726 return;
3727
3728
a3a5df9d 3729 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
cd05bf23
BW
3730 {
3731 close_wnd->Close();
3732 }
760fdb67 3733 else
cd05bf23
BW
3734 {
3735 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
760fdb67
VZ
3736 wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no page to delete?") );
3737
cd05bf23
BW
3738 DeletePage(main_idx);
3739 }
3740 }
3741 }
3742}
3743
69f5e420
BW
3744
3745void wxAuiNotebook::OnTabMiddleDown(wxCommandEvent& evt)
3746{
3747 // patch event through to owner
3748 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3749 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3750
3751 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
3752 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3753 e.SetEventObject(this);
3754 GetEventHandler()->ProcessEvent(e);
3755}
3756
3757void wxAuiNotebook::OnTabMiddleUp(wxCommandEvent& evt)
3758{
3759 // if the wxAUI_NB_MIDDLE_CLICK_CLOSE is specified, middle
3760 // click should act like a tab close action. However, first
3761 // give the owner an opportunity to handle the middle up event
3762 // for custom action
cedd7b22 3763
69f5e420
BW
3764 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3765 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3766
3767 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
3768 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3769 e.SetEventObject(this);
3770 if (GetEventHandler()->ProcessEvent(e))
3771 return;
3772 if (!e.IsAllowed())
3773 return;
cedd7b22 3774
69f5e420
BW
3775 // check if we are supposed to close on middle-up
3776 if ((m_flags & wxAUI_NB_MIDDLE_CLICK_CLOSE) == 0)
3777 return;
cedd7b22 3778
69f5e420
BW
3779 // simulate the user pressing the close button on the tab
3780 evt.SetInt(wxAUI_BUTTON_CLOSE);
3781 OnTabButton(evt);
3782}
3783
3784void wxAuiNotebook::OnTabRightDown(wxCommandEvent& evt)
3785{
3786 // patch event through to owner
3787 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3788 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3789
3790 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
3791 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3792 e.SetEventObject(this);
3793 GetEventHandler()->ProcessEvent(e);
3794}
3795
3796void wxAuiNotebook::OnTabRightUp(wxCommandEvent& evt)
3797{
3798 // patch event through to owner
3799 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3800 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3801
3802 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
3803 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3804 e.SetEventObject(this);
3805 GetEventHandler()->ProcessEvent(e);
3806}
3807
fc17828a
JS
3808// Sets the normal font
3809void wxAuiNotebook::SetNormalFont(const wxFont& font)
3810{
3811 m_normal_font = font;
3812 GetArtProvider()->SetNormalFont(font);
3813}
3814
3815// Sets the selected tab font
3816void wxAuiNotebook::SetSelectedFont(const wxFont& font)
3817{
3818 m_selected_font = font;
3819 GetArtProvider()->SetSelectedFont(font);
3820}
3821
3822// Sets the measuring font
3823void wxAuiNotebook::SetMeasuringFont(const wxFont& font)
3824{
3825 GetArtProvider()->SetMeasuringFont(font);
3826}
3827
3828// Sets the tab font
3829bool wxAuiNotebook::SetFont(const wxFont& font)
3830{
3831 wxControl::SetFont(font);
cd05bf23 3832
fc17828a
JS
3833 wxFont normalFont(font);
3834 wxFont selectedFont(normalFont);
3835 selectedFont.SetWeight(wxBOLD);
3836
3837 SetNormalFont(normalFont);
3838 SetSelectedFont(selectedFont);
3839 SetMeasuringFont(selectedFont);
3840
3841 return true;
3842}
3843
3844// Gets the tab control height
3845int wxAuiNotebook::GetTabCtrlHeight() const
3846{
3847 return m_tab_ctrl_height;
3848}
3849
3850// Gets the height of the notebook for a given page height
3851int wxAuiNotebook::GetHeightForPageHeight(int pageHeight)
3852{
3853 UpdateTabCtrlHeight();
3854
3855 int tabCtrlHeight = GetTabCtrlHeight();
3856 int decorHeight = 2;
3857 return tabCtrlHeight + pageHeight + decorHeight;
3858}
cd05bf23
BW
3859
3860
3861#endif // wxUSE_AUI