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