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