Apply [ 1710684 ] Fix wxAuiNotebook memory leak
[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 ~wxTabFrame()
2236 {
2237 wxDELETE(m_tabs);
2238 }
2239
2240 void SetTabCtrlHeight(int h)
2241 {
2242 m_tab_ctrl_height = h;
2243 }
2244
2245 void DoSetSize(int x, int y,
2246 int width, int height,
2247 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
2248 {
2249 m_rect = wxRect(x, y, width, height);
2250 DoSizing();
2251 }
2252
2253 void DoGetClientSize(int* x, int* y) const
2254 {
2255 *x = m_rect.width;
2256 *y = m_rect.height;
2257 }
2258
2259 bool Show( bool WXUNUSED(show = true) ) { return false; }
2260
2261 void DoSizing()
2262 {
2263 if (!m_tabs)
2264 return;
2265
2266 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2267 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2268 m_tabs->SetRect(wxRect(0, 0, m_rect.width, m_tab_ctrl_height));
2269 m_tabs->Refresh();
2270 m_tabs->Update();
2271
2272 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
2273 size_t i, page_count = pages.GetCount();
2274
2275 for (i = 0; i < page_count; ++i)
2276 {
2277 wxAuiNotebookPage& page = pages.Item(i);
2278 page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height,
2279 m_rect.width, m_rect.height - m_tab_ctrl_height);
2280
2281 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2282 {
2283 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
2284 wnd->ApplyMDIChildFrameRect();
2285 }
2286 }
2287 }
2288
2289 void DoGetSize(int* x, int* y) const
2290 {
2291 if (x)
2292 *x = m_rect.GetWidth();
2293 if (y)
2294 *y = m_rect.GetHeight();
2295 }
2296
2297 void Update()
2298 {
2299 // does nothing
2300 }
2301
2302 public:
2303
2304 wxRect m_rect;
2305 wxRect m_tab_rect;
2306 wxAuiTabCtrl* m_tabs;
2307 int m_tab_ctrl_height;
2308 };
2309
2310
2311 const int wxAuiBaseTabCtrlId = 5380;
2312
2313
2314 // -- wxAuiNotebook class implementation --
2315
2316 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
2317 EVT_SIZE(wxAuiNotebook::OnSize)
2318 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
2319 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2320 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
2321 wxAuiNotebook::OnTabClicked)
2322 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2323 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
2324 wxAuiNotebook::OnTabBeginDrag)
2325 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2326 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
2327 wxAuiNotebook::OnTabEndDrag)
2328 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2329 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
2330 wxAuiNotebook::OnTabDragMotion)
2331 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2332 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
2333 wxAuiNotebook::OnTabButton)
2334 END_EVENT_TABLE()
2335
2336 wxAuiNotebook::wxAuiNotebook()
2337 {
2338 m_curpage = -1;
2339 m_tab_id_counter = wxAuiBaseTabCtrlId;
2340 m_dummy_wnd = NULL;
2341 m_tab_ctrl_height = 20;
2342 m_requested_bmp_size = wxDefaultSize;
2343 m_requested_tabctrl_height = -1;
2344 }
2345
2346 wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
2347 wxWindowID id,
2348 const wxPoint& pos,
2349 const wxSize& size,
2350 long style) : wxControl(parent, id, pos, size, style)
2351 {
2352 m_dummy_wnd = NULL;
2353 m_requested_bmp_size = wxDefaultSize;
2354 m_requested_tabctrl_height = -1;
2355 InitNotebook(style);
2356 }
2357
2358 bool wxAuiNotebook::Create(wxWindow* parent,
2359 wxWindowID id,
2360 const wxPoint& pos,
2361 const wxSize& size,
2362 long style)
2363 {
2364 if (!wxControl::Create(parent, id, pos, size, style))
2365 return false;
2366
2367 InitNotebook(style);
2368
2369 return true;
2370 }
2371
2372 // InitNotebook() contains common initialization
2373 // code called by all constructors
2374 void wxAuiNotebook::InitNotebook(long style)
2375 {
2376 m_curpage = -1;
2377 m_tab_id_counter = wxAuiBaseTabCtrlId;
2378 m_dummy_wnd = NULL;
2379 m_flags = (unsigned int)style;
2380 m_tab_ctrl_height = 20;
2381
2382 m_normal_font = *wxNORMAL_FONT;
2383 m_selected_font = *wxNORMAL_FONT;
2384 m_selected_font.SetWeight(wxBOLD);
2385
2386 SetArtProvider(new wxAuiDefaultTabArt);
2387
2388 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
2389 m_dummy_wnd->SetSize(200, 200);
2390 m_dummy_wnd->Show(false);
2391
2392 m_mgr.SetManagedWindow(this);
2393 m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
2394 m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
2395
2396 m_mgr.AddPane(m_dummy_wnd,
2397 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
2398
2399 m_mgr.Update();
2400 }
2401
2402 wxAuiNotebook::~wxAuiNotebook()
2403 {
2404 m_mgr.UnInit();
2405 }
2406
2407 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
2408 {
2409 m_tabs.SetArtProvider(art);
2410
2411 UpdateTabCtrlHeight();
2412 }
2413
2414 // SetTabCtrlHeight() is the highest-level override of the
2415 // tab height. A call to this function effectively enforces a
2416 // specified tab ctrl height, overriding all other considerations,
2417 // such as text or bitmap height. It overrides any call to
2418 // SetUniformBitmapSize(). Specifying a height of -1 reverts
2419 // any previous call and returns to the default behavior
2420
2421 void wxAuiNotebook::SetTabCtrlHeight(int height)
2422 {
2423 m_requested_tabctrl_height = height;
2424
2425 // if window is already initialized, recalculate the tab height
2426 if (m_dummy_wnd)
2427 {
2428 UpdateTabCtrlHeight();
2429 }
2430 }
2431
2432
2433 // SetUniformBitmapSize() ensures that all tabs will have
2434 // the same height, even if some tabs don't have bitmaps
2435 // Passing wxDefaultSize to this function will instruct
2436 // the control to use dynamic tab height-- so when a tab
2437 // with a large bitmap is added, the tab ctrl's height will
2438 // automatically increase to accommodate the bitmap
2439
2440 void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
2441 {
2442 m_requested_bmp_size = size;
2443
2444 // if window is already initialized, recalculate the tab height
2445 if (m_dummy_wnd)
2446 {
2447 UpdateTabCtrlHeight();
2448 }
2449 }
2450
2451 // UpdateTabCtrlHeight() does the actual tab resizing. It's meant
2452 // to be used interally
2453 void wxAuiNotebook::UpdateTabCtrlHeight()
2454 {
2455 // get the tab ctrl height we will use
2456 int height = CalculateTabCtrlHeight();
2457
2458 // if the tab control height needs to change, update
2459 // all of our tab controls with the new height
2460 if (m_tab_ctrl_height != height)
2461 {
2462 wxAuiTabArt* art = m_tabs.GetArtProvider();
2463
2464 m_tab_ctrl_height = height;
2465
2466 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2467 size_t i, pane_count = all_panes.GetCount();
2468 for (i = 0; i < pane_count; ++i)
2469 {
2470 wxAuiPaneInfo& pane = all_panes.Item(i);
2471 if (pane.name == wxT("dummy"))
2472 continue;
2473 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
2474 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
2475 tab_frame->SetTabCtrlHeight(m_tab_ctrl_height);
2476 tabctrl->SetArtProvider(art->Clone());
2477 tab_frame->DoSizing();
2478 }
2479 }
2480 }
2481
2482 void wxAuiNotebook::UpdateHintWindowSize()
2483 {
2484 wxSize size = CalculateNewSplitSize();
2485
2486 // the placeholder hint window should be set to this size
2487 wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
2488 if (info.IsOk())
2489 {
2490 info.MinSize(size);
2491 info.BestSize(size);
2492 m_dummy_wnd->SetSize(size);
2493 }
2494 }
2495
2496
2497 // calculates the size of the new split
2498 wxSize wxAuiNotebook::CalculateNewSplitSize()
2499 {
2500 // count number of tab controls
2501 int tab_ctrl_count = 0;
2502 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2503 size_t i, pane_count = all_panes.GetCount();
2504 for (i = 0; i < pane_count; ++i)
2505 {
2506 wxAuiPaneInfo& pane = all_panes.Item(i);
2507 if (pane.name == wxT("dummy"))
2508 continue;
2509 tab_ctrl_count++;
2510 }
2511
2512 wxSize new_split_size;
2513
2514 // if there is only one tab control, the first split
2515 // should happen around the middle
2516 if (tab_ctrl_count < 2)
2517 {
2518 new_split_size = GetClientSize();
2519 new_split_size.x /= 2;
2520 new_split_size.y /= 2;
2521 }
2522 else
2523 {
2524 // this is in place of a more complicated calculation
2525 // that needs to be implemented
2526 new_split_size = wxSize(180,180);
2527 }
2528
2529 return new_split_size;
2530 }
2531
2532 int wxAuiNotebook::CalculateTabCtrlHeight()
2533 {
2534 // if a fixed tab ctrl height is specified,
2535 // just return that instead of calculating a
2536 // tab height
2537 if (m_requested_tabctrl_height != -1)
2538 return m_requested_tabctrl_height;
2539
2540 // find out new best tab height
2541 wxAuiTabArt* art = m_tabs.GetArtProvider();
2542
2543 return art->GetBestTabCtrlSize(this,
2544 m_tabs.GetPages(),
2545 m_requested_bmp_size);
2546 }
2547
2548
2549 wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
2550 {
2551 return m_tabs.GetArtProvider();
2552 }
2553
2554 void wxAuiNotebook::SetWindowStyleFlag(long style)
2555 {
2556 wxControl::SetWindowStyleFlag(style);
2557
2558 m_flags = (unsigned int)style;
2559
2560 // if the control is already initialized
2561 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
2562 {
2563 // let all of the tab children know about the new style
2564
2565 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2566 size_t i, pane_count = all_panes.GetCount();
2567 for (i = 0; i < pane_count; ++i)
2568 {
2569 wxAuiPaneInfo& pane = all_panes.Item(i);
2570 if (pane.name == wxT("dummy"))
2571 continue;
2572 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
2573 wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
2574 tabctrl->SetFlags(m_flags);
2575 tabframe->DoSizing();
2576 tabctrl->Refresh();
2577 tabctrl->Update();
2578 }
2579 }
2580 }
2581
2582
2583 bool wxAuiNotebook::AddPage(wxWindow* page,
2584 const wxString& caption,
2585 bool select,
2586 const wxBitmap& bitmap)
2587 {
2588 return InsertPage(GetPageCount(), page, caption, select, bitmap);
2589 }
2590
2591 bool wxAuiNotebook::InsertPage(size_t page_idx,
2592 wxWindow* page,
2593 const wxString& caption,
2594 bool select,
2595 const wxBitmap& bitmap)
2596 {
2597 wxAuiNotebookPage info;
2598 info.window = page;
2599 info.caption = caption;
2600 info.bitmap = bitmap;
2601 info.active = false;
2602
2603 // if there are currently no tabs, the first added
2604 // tab must be active
2605 if (m_tabs.GetPageCount() == 0)
2606 info.active = true;
2607
2608 m_tabs.InsertPage(page, info, page_idx);
2609
2610 // if that was the first page added, even if
2611 // select is false, it must become the "current page"
2612 // (though no select events will be fired)
2613 if (!select && m_tabs.GetPageCount() == 1)
2614 select = true;
2615 //m_curpage = GetPageIndex(page);
2616
2617 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
2618 if (page_idx >= active_tabctrl->GetPageCount())
2619 active_tabctrl->AddPage(page, info);
2620 else
2621 active_tabctrl->InsertPage(page, info, page_idx);
2622
2623 UpdateTabCtrlHeight();
2624 DoSizing();
2625 active_tabctrl->DoShowHide();
2626
2627 if (select)
2628 {
2629 SetSelectionToWindow(page);
2630 }
2631
2632 return true;
2633 }
2634
2635
2636 // DeletePage() removes a tab from the multi-notebook,
2637 // and destroys the window as well
2638 bool wxAuiNotebook::DeletePage(size_t page_idx)
2639 {
2640 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2641
2642 if (!RemovePage(page_idx))
2643 return false;
2644
2645 // actually destroy the window now
2646 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2647 {
2648 // delete the child frame with pending delete, as is
2649 // customary with frame windows
2650 if (!wxPendingDelete.Member(wnd))
2651 wxPendingDelete.Append(wnd);
2652 }
2653 else
2654 {
2655 wnd->Destroy();
2656 }
2657
2658 return true;
2659 }
2660
2661
2662
2663 // RemovePage() removes a tab from the multi-notebook,
2664 // but does not destroy the window
2665 bool wxAuiNotebook::RemovePage(size_t page_idx)
2666 {
2667 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2668 wxWindow* new_active = NULL;
2669
2670 // find out which onscreen tab ctrl owns this tab
2671 wxAuiTabCtrl* ctrl;
2672 int ctrl_idx;
2673 if (!FindTab(wnd, &ctrl, &ctrl_idx))
2674 return false;
2675
2676 // find a new page and set it as active
2677 int new_idx = ctrl_idx+1;
2678 if (new_idx >= (int)ctrl->GetPageCount())
2679 new_idx = ctrl_idx-1;
2680
2681 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
2682 {
2683 new_active = ctrl->GetWindowFromIdx(new_idx);
2684 }
2685 else
2686 {
2687 // set the active page to the first page that
2688 // isn't the one being deleted
2689 size_t i, page_count = m_tabs.GetPageCount();
2690 for (i = 0; i < page_count; ++i)
2691 {
2692 wxWindow* w = m_tabs.GetWindowFromIdx(i);
2693 if (wnd != w)
2694 {
2695 new_active = m_tabs.GetWindowFromIdx(i);
2696 break;
2697 }
2698 }
2699 }
2700
2701 // remove the tab from main catalog
2702 if (!m_tabs.RemovePage(wnd))
2703 return false;
2704
2705 // remove the tab from the onscreen tab ctrl
2706 ctrl->RemovePage(wnd);
2707
2708
2709 RemoveEmptyTabFrames();
2710
2711 // set new active pane
2712 if (new_active)
2713 {
2714 m_curpage = -1;
2715 SetSelectionToWindow(new_active);
2716 }
2717
2718 return true;
2719 }
2720
2721 // GetPageIndex() returns the index of the page, or -1 if the
2722 // page could not be located in the notebook
2723 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2724 {
2725 return m_tabs.GetIdxFromWindow(page_wnd);
2726 }
2727
2728
2729
2730 // SetPageText() changes the tab caption of the specified page
2731 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2732 {
2733 if (page_idx >= m_tabs.GetPageCount())
2734 return false;
2735
2736 // update our own tab catalog
2737 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2738 page_info.caption = text;
2739
2740 // update what's on screen
2741 wxAuiTabCtrl* ctrl;
2742 int ctrl_idx;
2743 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2744 {
2745 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2746 info.caption = text;
2747 ctrl->Refresh();
2748 ctrl->Update();
2749 }
2750
2751 return true;
2752 }
2753
2754 // returns the page caption
2755 wxString wxAuiNotebook::GetPageText(size_t page_idx) const
2756 {
2757 if (page_idx >= m_tabs.GetPageCount())
2758 return wxEmptyString;
2759
2760 // update our own tab catalog
2761 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2762 return page_info.caption;
2763 }
2764
2765 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2766 {
2767 if (page_idx >= m_tabs.GetPageCount())
2768 return false;
2769
2770 // update our own tab catalog
2771 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2772 page_info.bitmap = bitmap;
2773
2774 // tab height might have changed
2775 UpdateTabCtrlHeight();
2776
2777 // update what's on screen
2778 wxAuiTabCtrl* ctrl;
2779 int ctrl_idx;
2780 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2781 {
2782 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2783 info.bitmap = bitmap;
2784 ctrl->Refresh();
2785 ctrl->Update();
2786 }
2787
2788 return true;
2789 }
2790
2791 // returns the page bitmap
2792 wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const
2793 {
2794 if (page_idx >= m_tabs.GetPageCount())
2795 return wxBitmap();
2796
2797 // update our own tab catalog
2798 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2799 return page_info.bitmap;
2800 }
2801
2802 // GetSelection() returns the index of the currently active page
2803 int wxAuiNotebook::GetSelection() const
2804 {
2805 return m_curpage;
2806 }
2807
2808 // SetSelection() sets the currently active page
2809 size_t wxAuiNotebook::SetSelection(size_t new_page)
2810 {
2811 // don't change the page unless necessary
2812 if ((int)new_page == m_curpage)
2813 return m_curpage;
2814
2815 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
2816 if (!wnd)
2817 return m_curpage;
2818
2819 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2820 evt.SetSelection(new_page);
2821 evt.SetOldSelection(m_curpage);
2822 evt.SetEventObject(this);
2823 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
2824 {
2825 int old_curpage = m_curpage;
2826 m_curpage = new_page;
2827
2828 // program allows the page change
2829 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
2830 (void)GetEventHandler()->ProcessEvent(evt);
2831
2832
2833 wxAuiTabCtrl* ctrl;
2834 int ctrl_idx;
2835 if (FindTab(wnd, &ctrl, &ctrl_idx))
2836 {
2837 m_tabs.SetActivePage(wnd);
2838
2839 ctrl->SetActivePage(ctrl_idx);
2840 DoSizing();
2841 ctrl->DoShowHide();
2842
2843
2844
2845 // set fonts
2846 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2847 size_t i, pane_count = all_panes.GetCount();
2848 for (i = 0; i < pane_count; ++i)
2849 {
2850 wxAuiPaneInfo& pane = all_panes.Item(i);
2851 if (pane.name == wxT("dummy"))
2852 continue;
2853 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2854 if (tabctrl != ctrl)
2855 tabctrl->SetSelectedFont(m_normal_font);
2856 else
2857 tabctrl->SetSelectedFont(m_selected_font);
2858 tabctrl->Refresh();
2859 }
2860
2861 wnd->SetFocus();
2862
2863 return old_curpage;
2864 }
2865 }
2866
2867 return m_curpage;
2868 }
2869
2870 void wxAuiNotebook::SetSelectionToWindow(wxWindow *win)
2871 {
2872 const int idx = m_tabs.GetIdxFromWindow(win);
2873 wxCHECK_RET( idx != wxNOT_FOUND, _T("invalid notebook page") );
2874
2875 SetSelection(idx);
2876 }
2877
2878 // GetPageCount() returns the total number of
2879 // pages managed by the multi-notebook
2880 size_t wxAuiNotebook::GetPageCount() const
2881 {
2882 return m_tabs.GetPageCount();
2883 }
2884
2885 // GetPage() returns the wxWindow pointer of the
2886 // specified page
2887 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2888 {
2889 wxASSERT(page_idx < m_tabs.GetPageCount());
2890
2891 return m_tabs.GetWindowFromIdx(page_idx);
2892 }
2893
2894 // DoSizing() performs all sizing operations in each tab control
2895 void wxAuiNotebook::DoSizing()
2896 {
2897 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2898 size_t i, pane_count = all_panes.GetCount();
2899 for (i = 0; i < pane_count; ++i)
2900 {
2901 if (all_panes.Item(i).name == wxT("dummy"))
2902 continue;
2903
2904 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2905 tabframe->DoSizing();
2906 }
2907 }
2908
2909 // GetActiveTabCtrl() returns the active tab control. It is
2910 // called to determine which control gets new windows being added
2911 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
2912 {
2913 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
2914 {
2915 wxAuiTabCtrl* ctrl;
2916 int idx;
2917
2918 // find the tab ctrl with the current page
2919 if (FindTab(m_tabs.GetPage(m_curpage).window,
2920 &ctrl, &idx))
2921 {
2922 return ctrl;
2923 }
2924 }
2925
2926 // no current page, just find the first tab ctrl
2927 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2928 size_t i, pane_count = all_panes.GetCount();
2929 for (i = 0; i < pane_count; ++i)
2930 {
2931 if (all_panes.Item(i).name == wxT("dummy"))
2932 continue;
2933
2934 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2935 return tabframe->m_tabs;
2936 }
2937
2938 // If there is no tabframe at all, create one
2939 wxTabFrame* tabframe = new wxTabFrame;
2940 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
2941 tabframe->m_tabs = new wxAuiTabCtrl(this,
2942 m_tab_id_counter++,
2943 wxDefaultPosition,
2944 wxDefaultSize,
2945 wxNO_BORDER);
2946 tabframe->m_tabs->SetFlags(m_flags);
2947 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2948 m_mgr.AddPane(tabframe,
2949 wxAuiPaneInfo().Center().CaptionVisible(false));
2950
2951 m_mgr.Update();
2952
2953 return tabframe->m_tabs;
2954 }
2955
2956 // FindTab() finds the tab control that currently contains the window as well
2957 // as the index of the window in the tab control. It returns true if the
2958 // window was found, otherwise false.
2959 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2960 {
2961 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2962 size_t i, pane_count = all_panes.GetCount();
2963 for (i = 0; i < pane_count; ++i)
2964 {
2965 if (all_panes.Item(i).name == wxT("dummy"))
2966 continue;
2967
2968 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2969
2970 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2971 if (page_idx != -1)
2972 {
2973 *ctrl = tabframe->m_tabs;
2974 *idx = page_idx;
2975 return true;
2976 }
2977 }
2978
2979 return false;
2980 }
2981
2982 void wxAuiNotebook::Split(size_t page, int direction)
2983 {
2984 wxSize cli_size = GetClientSize();
2985
2986 // get the page's window pointer
2987 wxWindow* wnd = GetPage(page);
2988 if (!wnd)
2989 return;
2990
2991 // notebooks with 1 or less pages can't be split
2992 if (GetPageCount() < 2)
2993 return;
2994
2995 // find out which tab control the page currently belongs to
2996 wxAuiTabCtrl *src_tabs, *dest_tabs;
2997 int src_idx = -1;
2998 src_tabs = NULL;
2999 if (!FindTab(wnd, &src_tabs, &src_idx))
3000 return;
3001 if (!src_tabs || src_idx == -1)
3002 return;
3003
3004 // choose a split size
3005 wxSize split_size;
3006 if (GetPageCount() > 2)
3007 {
3008 split_size = CalculateNewSplitSize();
3009 }
3010 else
3011 {
3012 // because there are two panes, always split them
3013 // equally
3014 split_size = GetClientSize();
3015 split_size.x /= 2;
3016 split_size.y /= 2;
3017 }
3018
3019
3020 // create a new tab frame
3021 wxTabFrame* new_tabs = new wxTabFrame;
3022 new_tabs->m_rect = wxRect(wxPoint(0,0), split_size);
3023 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3024 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3025 m_tab_id_counter++,
3026 wxDefaultPosition,
3027 wxDefaultSize,
3028 wxNO_BORDER);
3029 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3030 new_tabs->m_tabs->SetFlags(m_flags);
3031 dest_tabs = new_tabs->m_tabs;
3032
3033 // create a pane info structure with the information
3034 // about where the pane should be added
3035 wxAuiPaneInfo pane_info = wxAuiPaneInfo().Bottom().CaptionVisible(false);
3036 wxPoint mouse_pt;
3037
3038 if (direction == wxLEFT)
3039 {
3040 pane_info.Left();
3041 mouse_pt = wxPoint(0, cli_size.y/2);
3042 }
3043 else if (direction == wxRIGHT)
3044 {
3045 pane_info.Right();
3046 mouse_pt = wxPoint(cli_size.x, cli_size.y/2);
3047 }
3048 else if (direction == wxTOP)
3049 {
3050 pane_info.Top();
3051 mouse_pt = wxPoint(cli_size.x/2, 0);
3052 }
3053 else if (direction == wxBOTTOM)
3054 {
3055 pane_info.Bottom();
3056 mouse_pt = wxPoint(cli_size.x/2, cli_size.y);
3057 }
3058
3059 m_mgr.AddPane(new_tabs, pane_info, mouse_pt);
3060 m_mgr.Update();
3061
3062 // remove the page from the source tabs
3063 wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx);
3064 page_info.active = false;
3065 src_tabs->RemovePage(page_info.window);
3066 if (src_tabs->GetPageCount() > 0)
3067 {
3068 src_tabs->SetActivePage((size_t)0);
3069 src_tabs->DoShowHide();
3070 src_tabs->Refresh();
3071 }
3072
3073
3074 // add the page to the destination tabs
3075 dest_tabs->InsertPage(page_info.window, page_info, 0);
3076
3077 if (src_tabs->GetPageCount() == 0)
3078 {
3079 RemoveEmptyTabFrames();
3080 }
3081
3082 DoSizing();
3083 dest_tabs->DoShowHide();
3084 dest_tabs->Refresh();
3085
3086 // force the set selection function reset the selection
3087 m_curpage = -1;
3088
3089 // set the active page to the one we just split off
3090 SetSelectionToPage(page_info);
3091
3092 UpdateHintWindowSize();
3093 }
3094
3095
3096 void wxAuiNotebook::OnSize(wxSizeEvent& evt)
3097 {
3098 UpdateHintWindowSize();
3099
3100 evt.Skip();
3101 }
3102
3103 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
3104 {
3105 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3106
3107 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
3108 wxASSERT(ctrl != NULL);
3109
3110 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
3111 wxASSERT(wnd != NULL);
3112
3113 SetSelectionToWindow(wnd);
3114 }
3115
3116 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
3117 {
3118 m_last_drag_x = 0;
3119 }
3120
3121 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
3122 {
3123 wxPoint screen_pt = ::wxGetMousePosition();
3124 wxPoint client_pt = ScreenToClient(screen_pt);
3125 wxPoint zero(0,0);
3126
3127 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3128 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
3129
3130 if (dest_tabs == src_tabs)
3131 {
3132 if (src_tabs)
3133 {
3134 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3135 }
3136
3137 // always hide the hint for inner-tabctrl drag
3138 m_mgr.HideHint();
3139
3140 // if tab moving is not allowed, leave
3141 if (!(m_flags & wxAUI_NB_TAB_MOVE))
3142 {
3143 return;
3144 }
3145
3146 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
3147 wxWindow* dest_location_tab;
3148
3149 // this is an inner-tab drag/reposition
3150 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
3151 {
3152 int src_idx = evt.GetSelection();
3153 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
3154
3155 // prevent jumpy drag
3156 if ((src_idx == dest_idx) || dest_idx == -1 ||
3157 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
3158 (src_idx < dest_idx && m_last_drag_x >= pt.x))
3159 {
3160 m_last_drag_x = pt.x;
3161 return;
3162 }
3163
3164
3165 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
3166 dest_tabs->MovePage(src_tab, dest_idx);
3167 dest_tabs->SetActivePage((size_t)dest_idx);
3168 dest_tabs->DoShowHide();
3169 dest_tabs->Refresh();
3170 m_last_drag_x = pt.x;
3171
3172 }
3173
3174 return;
3175 }
3176
3177
3178 // if external drag is allowed, check if the tab is being dragged
3179 // over a different wxAuiNotebook control
3180 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3181 {
3182 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
3183
3184 // if we aren't over any window, stop here
3185 if (!tab_ctrl)
3186 return;
3187
3188 // make sure we are not over the hint window
3189 if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
3190 {
3191 while (tab_ctrl)
3192 {
3193 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3194 break;
3195 tab_ctrl = tab_ctrl->GetParent();
3196 }
3197
3198 if (tab_ctrl)
3199 {
3200 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3201
3202 if (nb != this)
3203 {
3204 wxRect hint_rect = tab_ctrl->GetClientRect();
3205 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
3206 m_mgr.ShowHint(hint_rect);
3207 return;
3208 }
3209 }
3210 }
3211 else
3212 {
3213 if (!dest_tabs)
3214 {
3215 // we are either over a hint window, or not over a tab
3216 // window, and there is no where to drag to, so exit
3217 return;
3218 }
3219 }
3220 }
3221
3222
3223 // if there are less than two panes, split can't happen, so leave
3224 if (m_tabs.GetPageCount() < 2)
3225 return;
3226
3227 // if tab moving is not allowed, leave
3228 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
3229 return;
3230
3231
3232 if (src_tabs)
3233 {
3234 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
3235 }
3236
3237
3238 if (dest_tabs)
3239 {
3240 wxRect hint_rect = dest_tabs->GetRect();
3241 ClientToScreen(&hint_rect.x, &hint_rect.y);
3242 m_mgr.ShowHint(hint_rect);
3243 }
3244 else
3245 {
3246 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
3247 }
3248 }
3249
3250
3251
3252 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
3253 {
3254 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3255
3256 m_mgr.HideHint();
3257
3258
3259 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3260 wxCHECK_RET( src_tabs, _T("no source object?") );
3261
3262 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3263
3264 // get the mouse position, which will be used to determine the drop point
3265 wxPoint mouse_screen_pt = ::wxGetMousePosition();
3266 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
3267
3268
3269
3270 // check for an external move
3271 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3272 {
3273 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
3274
3275 while (tab_ctrl)
3276 {
3277 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3278 break;
3279 tab_ctrl = tab_ctrl->GetParent();
3280 }
3281
3282 if (tab_ctrl)
3283 {
3284 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3285
3286 if (nb != this)
3287 {
3288 // find out from the destination control
3289 // if it's ok to drop this tab here
3290 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
3291 e.SetSelection(evt.GetSelection());
3292 e.SetOldSelection(evt.GetSelection());
3293 e.SetEventObject(this);
3294 e.SetDragSource(this);
3295 e.Veto(); // dropping must be explicitly approved by control owner
3296
3297 nb->GetEventHandler()->ProcessEvent(e);
3298
3299 if (!e.IsAllowed())
3300 {
3301 // no answer or negative answer
3302 m_mgr.HideHint();
3303 return;
3304 }
3305
3306 // drop was allowed
3307 int src_idx = evt.GetSelection();
3308 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
3309
3310 // get main index of the page
3311 int main_idx = m_tabs.GetIdxFromWindow(src_page);
3312 wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no source page?") );
3313
3314
3315 // make a copy of the page info
3316 wxAuiNotebookPage page_info = m_tabs.GetPage(main_idx);
3317
3318 // remove the page from the source notebook
3319 RemovePage(main_idx);
3320
3321 // reparent the page
3322 src_page->Reparent(nb);
3323
3324
3325 // found out the insert idx
3326 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
3327 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3328
3329 wxWindow* target = NULL;
3330 int insert_idx = -1;
3331 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3332 if (target)
3333 {
3334 insert_idx = dest_tabs->GetIdxFromWindow(target);
3335 }
3336
3337
3338 // add the page to the new notebook
3339 if (insert_idx == -1)
3340 insert_idx = dest_tabs->GetPageCount();
3341 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3342 nb->m_tabs.AddPage(page_info.window, page_info);
3343
3344 nb->DoSizing();
3345 dest_tabs->DoShowHide();
3346 dest_tabs->Refresh();
3347
3348 // set the selection in the destination tab control
3349 nb->SetSelectionToPage(page_info);
3350
3351 return;
3352 }
3353 }
3354 }
3355
3356
3357
3358
3359 // only perform a tab split if it's allowed
3360 wxAuiTabCtrl* dest_tabs = NULL;
3361
3362 if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
3363 {
3364 // If the pointer is in an existing tab frame, do a tab insert
3365 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
3366 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
3367 int insert_idx = -1;
3368 if (tab_frame)
3369 {
3370 dest_tabs = tab_frame->m_tabs;
3371
3372 if (dest_tabs == src_tabs)
3373 return;
3374
3375
3376 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3377 wxWindow* target = NULL;
3378 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3379 if (target)
3380 {
3381 insert_idx = dest_tabs->GetIdxFromWindow(target);
3382 }
3383 }
3384 else
3385 {
3386 wxPoint zero(0,0);
3387 wxRect rect = m_mgr.CalculateHintRect(m_dummy_wnd,
3388 mouse_client_pt,
3389 zero);
3390 if (rect.IsEmpty())
3391 {
3392 // there is no suitable drop location here, exit out
3393 return;
3394 }
3395
3396 // If there is no tabframe at all, create one
3397 wxTabFrame* new_tabs = new wxTabFrame;
3398 new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
3399 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3400 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3401 m_tab_id_counter++,
3402 wxDefaultPosition,
3403 wxDefaultSize,
3404 wxNO_BORDER);
3405 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3406 new_tabs->m_tabs->SetFlags(m_flags);
3407
3408 m_mgr.AddPane(new_tabs,
3409 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3410 mouse_client_pt);
3411 m_mgr.Update();
3412 dest_tabs = new_tabs->m_tabs;
3413 }
3414
3415
3416
3417 // remove the page from the source tabs
3418 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
3419 page_info.active = false;
3420 src_tabs->RemovePage(page_info.window);
3421 if (src_tabs->GetPageCount() > 0)
3422 {
3423 src_tabs->SetActivePage((size_t)0);
3424 src_tabs->DoShowHide();
3425 src_tabs->Refresh();
3426 }
3427
3428
3429
3430 // add the page to the destination tabs
3431 if (insert_idx == -1)
3432 insert_idx = dest_tabs->GetPageCount();
3433 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3434
3435 if (src_tabs->GetPageCount() == 0)
3436 {
3437 RemoveEmptyTabFrames();
3438 }
3439
3440 DoSizing();
3441 dest_tabs->DoShowHide();
3442 dest_tabs->Refresh();
3443
3444 // force the set selection function reset the selection
3445 m_curpage = -1;
3446
3447 // set the active page to the one we just split off
3448 SetSelectionToPage(page_info);
3449
3450 UpdateHintWindowSize();
3451 }
3452 }
3453
3454
3455
3456 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
3457 {
3458 // if we've just removed the last tab from the source
3459 // tab set, the remove the tab control completely
3460 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3461 size_t i, pane_count = all_panes.GetCount();
3462 for (i = 0; i < pane_count; ++i)
3463 {
3464 if (all_panes.Item(i).name == wxT("dummy"))
3465 continue;
3466
3467 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3468 if (tabframe->m_tab_rect.Contains(pt))
3469 return tabframe->m_tabs;
3470 }
3471
3472 return NULL;
3473 }
3474
3475 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
3476 {
3477 // if we've just removed the last tab from the source
3478 // tab set, the remove the tab control completely
3479 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3480 size_t i, pane_count = all_panes.GetCount();
3481 for (i = 0; i < pane_count; ++i)
3482 {
3483 if (all_panes.Item(i).name == wxT("dummy"))
3484 continue;
3485
3486 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3487 if (tabframe->m_tabs == tab_ctrl)
3488 {
3489 return tabframe;
3490 }
3491 }
3492
3493 return NULL;
3494 }
3495
3496 void wxAuiNotebook::RemoveEmptyTabFrames()
3497 {
3498 // if we've just removed the last tab from the source
3499 // tab set, the remove the tab control completely
3500 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
3501 size_t i, pane_count = all_panes.GetCount();
3502 for (i = 0; i < pane_count; ++i)
3503 {
3504 if (all_panes.Item(i).name == wxT("dummy"))
3505 continue;
3506
3507 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
3508 if (tab_frame->m_tabs->GetPageCount() == 0)
3509 {
3510 m_mgr.DetachPane(tab_frame);
3511
3512 // use pending delete because sometimes during
3513 // window closing, refreshs are pending
3514 if (!wxPendingDelete.Member(tab_frame->m_tabs))
3515 wxPendingDelete.Append(tab_frame->m_tabs);
3516 //tab_frame->m_tabs->Destroy();
3517
3518 delete tab_frame;
3519 }
3520 }
3521
3522
3523 // check to see if there is still a center pane;
3524 // if there isn't, make a frame the center pane
3525 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
3526 pane_count = panes.GetCount();
3527 wxWindow* first_good = NULL;
3528 bool center_found = false;
3529 for (i = 0; i < pane_count; ++i)
3530 {
3531 if (panes.Item(i).name == wxT("dummy"))
3532 continue;
3533 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
3534 center_found = true;
3535 if (!first_good)
3536 first_good = panes.Item(i).window;
3537 }
3538
3539 if (!center_found && first_good)
3540 {
3541 m_mgr.GetPane(first_good).Centre();
3542 }
3543
3544 m_mgr.Update();
3545 }
3546
3547 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
3548 {
3549 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
3550 if (idx != -1 && idx != m_curpage)
3551 {
3552 SetSelection(idx);
3553 }
3554 }
3555
3556
3557 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
3558 {
3559 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3560 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3561
3562 int button_id = evt.GetInt();
3563
3564 if (button_id == wxAUI_BUTTON_CLOSE)
3565 {
3566 int selection = tabs->GetActivePage();
3567
3568 if (selection != -1)
3569 {
3570 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3571
3572
3573 // ask owner if it's ok to close the tab
3574 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3575 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3576 e.SetOldSelection(evt.GetSelection());
3577 e.SetEventObject(this);
3578 GetEventHandler()->ProcessEvent(e);
3579 if (!e.IsAllowed())
3580 return;
3581
3582
3583 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3584 {
3585 close_wnd->Close();
3586 }
3587 else
3588 {
3589 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3590 wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no page to delete?") );
3591
3592 DeletePage(main_idx);
3593 }
3594 }
3595 }
3596 }
3597
3598
3599
3600
3601 #endif // wxUSE_AUI