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