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