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