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