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