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