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