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