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