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