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