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