wxAuiNotebook minor tab art interface cleanups
[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 #endif
29
30 #include "wx/aui/tabmdi.h"
31 #include "wx/dcbuffer.h"
32 #include "wx/menu.h"
33
34 #ifdef __WXMAC__
35 #include "wx/mac/carbon/private.h"
36 #endif
37
38 #include "wx/arrimpl.cpp"
39 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
40 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
41
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE)
43 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING)
44 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
45 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
46 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
47 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
48 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
49 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND)
50
51
52 IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
53 IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl)
54 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
55
56
57
58
59
60 // these functions live in dockart.cpp -- they'll eventually
61 // be moved to a new utility cpp file
62
63 wxColor wxAuiStepColour(const wxColor& c, int percent);
64
65 wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h,
66 const wxColour& color);
67
68 wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size);
69
70 static void DrawButtons(wxDC& dc,
71 const wxRect& _rect,
72 const wxBitmap& bmp,
73 const wxColour& bkcolour,
74 int button_state)
75 {
76 wxRect rect = _rect;
77
78 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
79 {
80 rect.x++;
81 rect.y++;
82 }
83
84 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
85 button_state == wxAUI_BUTTON_STATE_PRESSED)
86 {
87 dc.SetBrush(wxBrush(wxAuiStepColour(bkcolour, 120)));
88 dc.SetPen(wxPen(wxAuiStepColour(bkcolour, 75)));
89
90 // draw the background behind the button
91 dc.DrawRectangle(rect.x, rect.y, 15, 15);
92 }
93
94 // draw the button itself
95 dc.DrawBitmap(bmp, rect.x, rect.y, true);
96 }
97
98 static void IndentPressedBitmap(wxRect* rect, int button_state)
99 {
100 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
101 {
102 rect->x++;
103 rect->y++;
104 }
105 }
106
107
108
109 // -- GUI helper classes and functions --
110
111 class wxAuiCommandCapture : public wxEvtHandler
112 {
113 public:
114
115 wxAuiCommandCapture() { m_last_id = 0; }
116 int GetCommandId() const { return m_last_id; }
117
118 bool ProcessEvent(wxEvent& evt)
119 {
120 if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
121 {
122 m_last_id = evt.GetId();
123 return true;
124 }
125
126 if (GetNextHandler())
127 return GetNextHandler()->ProcessEvent(evt);
128
129 return false;
130 }
131
132 private:
133 int m_last_id;
134 };
135
136
137 // -- bitmaps --
138
139 #if defined( __WXMAC__ )
140 static unsigned char close_bits[]={
141 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
142 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
143 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
144 #elif defined( __WXGTK__)
145 static unsigned char close_bits[]={
146 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
147 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
148 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
149 #else
150 static unsigned char close_bits[]={
151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
152 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
154 #endif
155
156 static unsigned char left_bits[] = {
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
158 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
160
161 static unsigned char right_bits[] = {
162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
163 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
164 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
165
166 static unsigned char list_bits[] = {
167 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
168 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
170
171
172
173
174
175
176 // -- wxAuiDefaultTabArt class implementation --
177
178 wxAuiDefaultTabArt::wxAuiDefaultTabArt()
179 {
180 m_normal_font = *wxNORMAL_FONT;
181 m_selected_font = *wxNORMAL_FONT;
182 m_selected_font.SetWeight(wxBOLD);
183 m_measuring_font = m_selected_font;
184
185 m_fixed_tab_width = 100;
186 m_tab_ctrl_height = 0;
187
188 #ifdef __WXMAC__
189 wxBrush toolbarbrush;
190 toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground );
191 wxColor base_colour = toolbarbrush.GetColour();
192 #else
193 wxColor base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
194 #endif
195
196 // the base_colour is too pale to use as our base colour,
197 // so darken it a bit --
198 if ((255-base_colour.Red()) +
199 (255-base_colour.Green()) +
200 (255-base_colour.Blue()) < 60)
201 {
202 base_colour = wxAuiStepColour(base_colour, 92);
203 }
204
205 m_base_colour = base_colour;
206 wxColor border_colour = wxAuiStepColour(base_colour, 75);
207
208 m_border_pen = wxPen(border_colour);
209 m_base_colour_pen = wxPen(m_base_colour);
210 m_base_colour_brush = wxBrush(m_base_colour);
211
212 m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
213 m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
214
215 m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
216 m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
217
218 m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
219 m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
220
221 m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
222 m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
223
224 m_flags = 0;
225 }
226
227 wxAuiDefaultTabArt::~wxAuiDefaultTabArt()
228 {
229 }
230
231 wxAuiTabArt* wxAuiDefaultTabArt::Clone()
232 {
233 return static_cast<wxAuiTabArt*>(new wxAuiDefaultTabArt);
234 }
235
236 void wxAuiDefaultTabArt::SetFlags(unsigned int flags)
237 {
238 m_flags = flags;
239 }
240
241 void wxAuiDefaultTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
242 size_t tab_count)
243 {
244 m_fixed_tab_width = 100;
245
246 int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
247
248 if (m_flags & wxAUI_NB_CLOSE_BUTTON)
249 tot_width -= m_active_close_bmp.GetWidth();
250 if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
251 tot_width -= m_active_windowlist_bmp.GetWidth();
252
253 if (tab_count > 0)
254 {
255 m_fixed_tab_width = tot_width/(int)tab_count;
256 }
257
258
259 if (m_fixed_tab_width < 100)
260 m_fixed_tab_width = 100;
261
262 if (m_fixed_tab_width > tot_width/2)
263 m_fixed_tab_width = tot_width/2;
264
265 if (m_fixed_tab_width > 220)
266 m_fixed_tab_width = 220;
267
268 m_tab_ctrl_height = tab_ctrl_size.y;
269 }
270
271
272 void wxAuiDefaultTabArt::DrawBackground(wxDC& dc,
273 wxWindow* WXUNUSED(wnd),
274 const wxRect& rect)
275 {
276 // draw background
277 wxRect r(rect.x, rect.y, rect.width+2, rect.height-3);
278 wxColor top_color = wxAuiStepColour(m_base_colour, 90);
279 wxColor bottom_color = wxAuiStepColour(m_base_colour, 170);
280 dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
281
282 // draw base lines
283 int y = rect.GetHeight();
284 int w = rect.GetWidth();
285 dc.SetPen(m_border_pen);
286 dc.SetBrush(m_base_colour_brush);
287 dc.DrawRectangle(-1, y-4, w+2, 4);
288 }
289
290
291 // DrawTab() draws an individual tab.
292 //
293 // dc - output dc
294 // in_rect - rectangle the tab should be confined to
295 // caption - tab's caption
296 // active - whether or not the tab is active
297 // out_rect - actual output rectangle
298 // x_extent - the advance x; where the next tab should start
299
300 void wxAuiDefaultTabArt::DrawTab(wxDC& dc,
301 wxWindow* wnd,
302 const wxAuiNotebookPage& page,
303 const wxRect& in_rect,
304 int close_button_state,
305 wxRect* out_tab_rect,
306 wxRect* out_button_rect,
307 int* x_extent)
308 {
309 wxCoord normal_textx, normal_texty;
310 wxCoord selected_textx, selected_texty;
311 wxCoord textx, texty;
312
313 // if the caption is empty, measure some temporary text
314 wxString caption = page.caption;
315 if (caption.empty())
316 caption = wxT("Xj");
317
318 dc.SetFont(m_selected_font);
319 dc.GetTextExtent(caption, &selected_textx, &selected_texty);
320
321 dc.SetFont(m_normal_font);
322 dc.GetTextExtent(caption, &normal_textx, &normal_texty);
323
324 // figure out the size of the tab
325 wxSize tab_size = GetTabSize(dc,
326 wnd,
327 page.caption,
328 page.bitmap,
329 page.active,
330 close_button_state,
331 x_extent);
332
333 wxCoord tab_height = m_tab_ctrl_height - 3;
334 wxCoord tab_width = tab_size.x;
335 wxCoord tab_x = in_rect.x;
336 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
337
338
339 caption = page.caption;
340
341
342 // select pen, brush and font for the tab to be drawn
343
344 if (page.active)
345 {
346 dc.SetFont(m_selected_font);
347 textx = selected_textx;
348 texty = selected_texty;
349 }
350 else
351 {
352 dc.SetFont(m_normal_font);
353 textx = normal_textx;
354 texty = normal_texty;
355 }
356
357
358 // create points that will make the tab outline
359
360 int clip_width = tab_width;
361 if (tab_x + clip_width > in_rect.x + in_rect.width)
362 clip_width = (in_rect.x + in_rect.width) - tab_x;
363
364 /*
365 wxPoint clip_points[6];
366 clip_points[0] = wxPoint(tab_x, tab_y+tab_height-3);
367 clip_points[1] = wxPoint(tab_x, tab_y+2);
368 clip_points[2] = wxPoint(tab_x+2, tab_y);
369 clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y);
370 clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2);
371 clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3);
372
373 // FIXME: these ports don't provide wxRegion ctor from array of points
374 #if !defined(__WXDFB__) && !defined(__WXCOCOA__)
375 // set the clipping region for the tab --
376 wxRegion clipping_region(WXSIZEOF(clip_points), clip_points);
377 dc.SetClippingRegion(clipping_region);
378 #endif // !wxDFB && !wxCocoa
379 */
380 // since the above code above doesn't play well with WXDFB or WXCOCOA,
381 // we'll just use a rectangle for the clipping region for now --
382 dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3);
383
384
385 wxPoint border_points[6];
386 border_points[0] = wxPoint(tab_x, tab_y+tab_height-4);
387 border_points[1] = wxPoint(tab_x, tab_y+2);
388 border_points[2] = wxPoint(tab_x+2, tab_y);
389 border_points[3] = wxPoint(tab_x+tab_width-2, tab_y);
390 border_points[4] = wxPoint(tab_x+tab_width, tab_y+2);
391 border_points[5] = wxPoint(tab_x+tab_width, tab_y+tab_height-4);
392
393
394 int drawn_tab_yoff = border_points[1].y;
395 int drawn_tab_height = border_points[0].y - border_points[1].y;
396
397
398 if (page.active)
399 {
400 // draw active tab
401
402 // draw base background color
403 wxRect r(tab_x, tab_y, tab_width, tab_height);
404 dc.SetPen(m_base_colour_pen);
405 dc.SetBrush(m_base_colour_brush);
406 dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4);
407
408 // this white helps fill out the gradient at the top of the tab
409 dc.SetPen(*wxWHITE_PEN);
410 dc.SetBrush(*wxWHITE_BRUSH);
411 dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4);
412
413 // these two points help the rounded corners appear more antialiased
414 dc.SetPen(m_base_colour_pen);
415 dc.DrawPoint(r.x+2, r.y+1);
416 dc.DrawPoint(r.x+r.width-2, r.y+1);
417
418 // set rectangle down a bit for gradient drawing
419 r.SetHeight(r.GetHeight()/2);
420 r.x += 2;
421 r.width -= 2;
422 r.y += r.height;
423 r.y -= 2;
424
425 // draw gradient background
426 wxColor top_color = *wxWHITE;
427 wxColor bottom_color = m_base_colour;
428 dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
429 }
430 else
431 {
432 // draw inactive tab
433
434 wxRect r(tab_x, tab_y+1, tab_width, tab_height-3);
435
436 // start the gradent up a bit and leave the inside border inset
437 // by a pixel for a 3D look. Only the top half of the inactive
438 // tab will have a slight gradient
439 r.x += 3;
440 r.y++;
441 r.width -= 4;
442 r.height /= 2;
443 r.height--;
444
445 // -- draw top gradient fill for glossy look
446 wxColor top_color = m_base_colour;
447 wxColor bottom_color = wxAuiStepColour(top_color, 160);
448 dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
449
450 r.y += r.height;
451 r.y--;
452
453 // -- draw bottom fill for glossy look
454 top_color = m_base_colour;
455 bottom_color = m_base_colour;
456 dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
457 }
458
459 // draw tab outline
460 dc.SetPen(m_border_pen);
461 dc.SetBrush(*wxTRANSPARENT_BRUSH);
462 dc.DrawPolygon(WXSIZEOF(border_points), border_points);
463
464 // there are two horizontal grey lines at the bottom of the tab control,
465 // this gets rid of the top one of those lines in the tab control
466 if (page.active)
467 {
468 wxColor start_color = m_base_colour;
469 dc.SetPen(m_base_colour_pen);
470 dc.DrawLine(border_points[0].x+1,
471 border_points[0].y,
472 border_points[5].x,
473 border_points[5].y);
474 }
475
476
477 int text_offset = tab_x + 8;
478 int close_button_width = 0;
479 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
480 {
481 close_button_width = m_active_close_bmp.GetWidth();
482 }
483
484
485 if (page.bitmap.IsOk())
486 {
487 int bitmap_offset = tab_x + 8;
488
489 // draw bitmap
490 dc.DrawBitmap(page.bitmap,
491 bitmap_offset,
492 drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
493 true);
494
495 text_offset = bitmap_offset + page.bitmap.GetWidth();
496 text_offset += 3; // bitmap padding
497 }
498 else
499 {
500 text_offset = tab_x + 8;
501 }
502
503
504 wxString draw_text = wxAuiChopText(dc,
505 caption,
506 tab_width - (text_offset-tab_x) - close_button_width);
507
508 // draw tab text
509 dc.DrawText(draw_text,
510 text_offset,
511 drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1);
512
513
514
515
516 // draw close button if necessary
517 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
518 {
519 wxBitmap bmp = m_disabled_close_bmp;
520
521 if (close_button_state == wxAUI_BUTTON_STATE_HOVER ||
522 close_button_state == wxAUI_BUTTON_STATE_PRESSED)
523 {
524 bmp = m_active_close_bmp;
525 }
526
527 wxRect rect(tab_x + tab_width - close_button_width - 1,
528 tab_y + (tab_height/2) - (bmp.GetHeight()/2),
529 close_button_width,
530 tab_height);
531 IndentPressedBitmap(&rect, close_button_state);
532 dc.DrawBitmap(bmp, rect.x, rect.y, true);
533
534 *out_button_rect = rect;
535 }
536
537 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
538
539 dc.DestroyClippingRegion();
540 }
541
542 int wxAuiDefaultTabArt::GetIndentSize()
543 {
544 return 5;
545 }
546
547 wxSize wxAuiDefaultTabArt::GetTabSize(wxDC& dc,
548 wxWindow* WXUNUSED(wnd),
549 const wxString& caption,
550 const wxBitmap& bitmap,
551 bool WXUNUSED(active),
552 int close_button_state,
553 int* x_extent)
554 {
555 wxCoord measured_textx, measured_texty, tmp;
556
557 dc.SetFont(m_measuring_font);
558 dc.GetTextExtent(caption, &measured_textx, &measured_texty);
559
560 dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty);
561
562 // add padding around the text
563 wxCoord tab_width = measured_textx;
564 wxCoord tab_height = measured_texty;
565
566 // if the close button is showing, add space for it
567 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
568 tab_width += m_active_close_bmp.GetWidth() + 3;
569
570 // if there's a bitmap, add space for it
571 if (bitmap.IsOk())
572 {
573 tab_width += bitmap.GetWidth();
574 tab_width += 3; // right side bitmap padding
575 tab_height = wxMax(tab_height, bitmap.GetHeight());
576 }
577
578 // add padding
579 tab_width += 16;
580 tab_height += 10;
581
582 if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
583 {
584 tab_width = m_fixed_tab_width;
585 }
586
587 *x_extent = tab_width;
588
589 return wxSize(tab_width, tab_height);
590 }
591
592
593 void wxAuiDefaultTabArt::DrawButton(wxDC& dc,
594 wxWindow* WXUNUSED(wnd),
595 const wxRect& in_rect,
596 int bitmap_id,
597 int button_state,
598 int orientation,
599 wxRect* out_rect)
600 {
601 wxBitmap bmp;
602 wxRect rect;
603
604 switch (bitmap_id)
605 {
606 case wxAUI_BUTTON_CLOSE:
607 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
608 bmp = m_disabled_close_bmp;
609 else
610 bmp = m_active_close_bmp;
611 break;
612 case wxAUI_BUTTON_LEFT:
613 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
614 bmp = m_disabled_left_bmp;
615 else
616 bmp = m_active_left_bmp;
617 break;
618 case wxAUI_BUTTON_RIGHT:
619 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
620 bmp = m_disabled_right_bmp;
621 else
622 bmp = m_active_right_bmp;
623 break;
624 case wxAUI_BUTTON_WINDOWLIST:
625 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
626 bmp = m_disabled_windowlist_bmp;
627 else
628 bmp = m_active_windowlist_bmp;
629 break;
630 }
631
632
633 if (!bmp.IsOk())
634 return;
635
636 rect = in_rect;
637
638 if (orientation == wxLEFT)
639 {
640 rect.SetX(in_rect.x);
641 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
642 rect.SetWidth(bmp.GetWidth());
643 rect.SetHeight(bmp.GetHeight());
644 }
645 else
646 {
647 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
648 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
649 bmp.GetWidth(), bmp.GetHeight());
650 }
651
652 IndentPressedBitmap(&rect, button_state);
653 dc.DrawBitmap(bmp, rect.x, rect.y, true);
654
655 *out_rect = rect;
656 }
657
658
659 int wxAuiDefaultTabArt::ShowDropDown(wxWindow* wnd,
660 const wxAuiNotebookPageArray& pages,
661 int active_idx)
662 {
663 wxMenu menuPopup;
664
665 size_t i, count = pages.GetCount();
666 for (i = 0; i < count; ++i)
667 {
668 const wxAuiNotebookPage& page = pages.Item(i);
669 menuPopup.AppendCheckItem(1000+i, page.caption);
670 }
671
672 if (active_idx != -1)
673 {
674 menuPopup.Check(1000+active_idx, true);
675 }
676
677 // find out where to put the popup menu of window items
678 wxPoint pt = ::wxGetMousePosition();
679 pt = wnd->ScreenToClient(pt);
680
681 // find out the screen coordinate at the bottom of the tab ctrl
682 wxRect cli_rect = wnd->GetClientRect();
683 pt.y = cli_rect.y + cli_rect.height;
684
685 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
686 wnd->PushEventHandler(cc);
687 wnd->PopupMenu(&menuPopup, pt);
688 int command = cc->GetCommandId();
689 wnd->PopEventHandler(true);
690
691 if (command >= 1000)
692 return command-1000;
693
694 return -1;
695 }
696
697 int wxAuiDefaultTabArt::GetBestTabCtrlSize(wxWindow* wnd,
698 const wxAuiNotebookPageArray& pages,
699 const wxSize& required_bmp_size)
700 {
701 wxClientDC dc(wnd);
702 dc.SetFont(m_measuring_font);
703
704 // sometimes a standard bitmap size needs to be enforced, especially
705 // if some tabs have bitmaps and others don't. This is important because
706 // it prevents the tab control from resizing when tabs are added.
707 wxBitmap measure_bmp;
708 if (required_bmp_size.IsFullySpecified())
709 {
710 measure_bmp.Create(required_bmp_size.x,
711 required_bmp_size.y);
712 }
713
714
715 int max_y = 0;
716 size_t i, page_count = pages.GetCount();
717 for (i = 0; i < page_count; ++i)
718 {
719 wxAuiNotebookPage& page = pages.Item(i);
720
721 wxBitmap bmp;
722 if (measure_bmp.IsOk())
723 bmp = measure_bmp;
724 else
725 bmp = page.bitmap;
726
727 // we don't use the caption text because we don't
728 // want tab heights to be different in the case
729 // of a very short piece of text on one tab and a very
730 // tall piece of text on another tab
731 int x_ext = 0;
732 wxSize s = GetTabSize(dc,
733 wnd,
734 wxT("ABCDEFGHIj"),
735 bmp,
736 true,
737 wxAUI_BUTTON_STATE_HIDDEN,
738 &x_ext);
739
740 max_y = wxMax(max_y, s.y);
741 }
742
743 return max_y+2;
744 }
745
746 void wxAuiDefaultTabArt::SetNormalFont(const wxFont& font)
747 {
748 m_normal_font = font;
749 }
750
751 void wxAuiDefaultTabArt::SetSelectedFont(const wxFont& font)
752 {
753 m_selected_font = font;
754 }
755
756 void wxAuiDefaultTabArt::SetMeasuringFont(const wxFont& font)
757 {
758 m_measuring_font = font;
759 }
760
761
762 // -- wxAuiSimpleTabArt class implementation --
763
764 wxAuiSimpleTabArt::wxAuiSimpleTabArt()
765 {
766 m_normal_font = *wxNORMAL_FONT;
767 m_selected_font = *wxNORMAL_FONT;
768 m_selected_font.SetWeight(wxBOLD);
769 m_measuring_font = m_selected_font;
770
771 m_flags = 0;
772 m_fixed_tab_width = 100;
773
774 wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
775
776 wxColour background_colour = base_colour;
777 wxColour normaltab_colour = base_colour;
778 wxColour selectedtab_colour = *wxWHITE;
779
780 m_bkbrush = wxBrush(background_colour);
781 m_normal_bkbrush = wxBrush(normaltab_colour);
782 m_normal_bkpen = wxPen(normaltab_colour);
783 m_selected_bkbrush = wxBrush(selectedtab_colour);
784 m_selected_bkpen = wxPen(selectedtab_colour);
785
786 m_active_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
787 m_disabled_close_bmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
788
789 m_active_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
790 m_disabled_left_bmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
791
792 m_active_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
793 m_disabled_right_bmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
794
795 m_active_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
796 m_disabled_windowlist_bmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
797
798 }
799
800 wxAuiSimpleTabArt::~wxAuiSimpleTabArt()
801 {
802 }
803
804 wxAuiTabArt* wxAuiSimpleTabArt::Clone()
805 {
806 return static_cast<wxAuiTabArt*>(new wxAuiSimpleTabArt);
807 }
808
809
810 void wxAuiSimpleTabArt::SetFlags(unsigned int flags)
811 {
812 m_flags = flags;
813 }
814
815 void wxAuiSimpleTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
816 size_t tab_count)
817 {
818 m_fixed_tab_width = 100;
819
820 int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
821
822 if (m_flags & wxAUI_NB_CLOSE_BUTTON)
823 tot_width -= m_active_close_bmp.GetWidth();
824 if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
825 tot_width -= m_active_windowlist_bmp.GetWidth();
826
827 if (tab_count > 0)
828 {
829 m_fixed_tab_width = tot_width/(int)tab_count;
830 }
831
832
833 if (m_fixed_tab_width < 100)
834 m_fixed_tab_width = 100;
835
836 if (m_fixed_tab_width > tot_width/2)
837 m_fixed_tab_width = tot_width/2;
838
839 if (m_fixed_tab_width > 220)
840 m_fixed_tab_width = 220;
841 }
842
843 void wxAuiSimpleTabArt::DrawBackground(wxDC& dc,
844 wxWindow* WXUNUSED(wnd),
845 const wxRect& rect)
846 {
847 // draw background
848 dc.SetBrush(m_bkbrush);
849 dc.SetPen(*wxTRANSPARENT_PEN);
850 dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
851
852 // draw base line
853 dc.SetPen(*wxGREY_PEN);
854 dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
855 }
856
857
858 // DrawTab() draws an individual tab.
859 //
860 // dc - output dc
861 // in_rect - rectangle the tab should be confined to
862 // caption - tab's caption
863 // active - whether or not the tab is active
864 // out_rect - actual output rectangle
865 // x_extent - the advance x; where the next tab should start
866
867 void wxAuiSimpleTabArt::DrawTab(wxDC& dc,
868 wxWindow* wnd,
869 const wxAuiNotebookPage& page,
870 const wxRect& in_rect,
871 int close_button_state,
872 wxRect* out_tab_rect,
873 wxRect* out_button_rect,
874 int* x_extent)
875 {
876 wxCoord normal_textx, normal_texty;
877 wxCoord selected_textx, selected_texty;
878 wxCoord textx, texty;
879
880 // if the caption is empty, measure some temporary text
881 wxString caption = page.caption;
882 if (caption.empty())
883 caption = wxT("Xj");
884
885 dc.SetFont(m_selected_font);
886 dc.GetTextExtent(caption, &selected_textx, &selected_texty);
887
888 dc.SetFont(m_normal_font);
889 dc.GetTextExtent(caption, &normal_textx, &normal_texty);
890
891 // figure out the size of the tab
892 wxSize tab_size = GetTabSize(dc,
893 wnd,
894 page.caption,
895 page.bitmap,
896 page.active,
897 close_button_state,
898 x_extent);
899
900 wxCoord tab_height = tab_size.y;
901 wxCoord tab_width = tab_size.x;
902 wxCoord tab_x = in_rect.x;
903 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
904
905 caption = page.caption;
906
907 // select pen, brush and font for the tab to be drawn
908
909 if (page.active)
910 {
911 dc.SetPen(m_selected_bkpen);
912 dc.SetBrush(m_selected_bkbrush);
913 dc.SetFont(m_selected_font);
914 textx = selected_textx;
915 texty = selected_texty;
916 }
917 else
918 {
919 dc.SetPen(m_normal_bkpen);
920 dc.SetBrush(m_normal_bkbrush);
921 dc.SetFont(m_normal_font);
922 textx = normal_textx;
923 texty = normal_texty;
924 }
925
926
927 // -- draw line --
928
929 wxPoint points[7];
930 points[0].x = tab_x;
931 points[0].y = tab_y + tab_height - 1;
932 points[1].x = tab_x + tab_height - 3;
933 points[1].y = tab_y + 2;
934 points[2].x = tab_x + tab_height + 3;
935 points[2].y = tab_y;
936 points[3].x = tab_x + tab_width - 2;
937 points[3].y = tab_y;
938 points[4].x = tab_x + tab_width;
939 points[4].y = tab_y + 2;
940 points[5].x = tab_x + tab_width;
941 points[5].y = tab_y + tab_height - 1;
942 points[6] = points[0];
943
944 dc.SetClippingRegion(in_rect);
945
946 dc.DrawPolygon(WXSIZEOF(points) - 1, points);
947
948 dc.SetPen(*wxGREY_PEN);
949
950 //dc.DrawLines(active ? WXSIZEOF(points) - 1 : WXSIZEOF(points), points);
951 dc.DrawLines(WXSIZEOF(points), points);
952
953
954 int text_offset;
955
956 int close_button_width = 0;
957 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
958 {
959 close_button_width = m_active_close_bmp.GetWidth();
960 text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2);
961 }
962 else
963 {
964 text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2);
965 }
966
967 // set minimum text offset
968 if (text_offset < tab_x + tab_height)
969 text_offset = tab_x + tab_height;
970
971 // chop text if necessary
972 wxString draw_text = wxAuiChopText(dc,
973 caption,
974 tab_width - (text_offset-tab_x) - close_button_width);
975
976 // draw tab text
977 dc.DrawText(draw_text,
978 text_offset,
979 (tab_y + tab_height)/2 - (texty/2) + 1);
980
981
982 // draw close button if necessary
983 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
984 {
985 wxBitmap bmp;
986 if (page.active)
987 bmp = m_active_close_bmp;
988 else
989 bmp = m_disabled_close_bmp;
990
991 wxRect rect(tab_x + tab_width - close_button_width - 1,
992 tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
993 close_button_width,
994 tab_height - 1);
995 DrawButtons(dc, rect, bmp, *wxWHITE, close_button_state);
996
997 *out_button_rect = rect;
998 }
999
1000
1001 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
1002
1003 dc.DestroyClippingRegion();
1004 }
1005
1006 int wxAuiSimpleTabArt::GetIndentSize()
1007 {
1008 return 0;
1009 }
1010
1011 wxSize wxAuiSimpleTabArt::GetTabSize(wxDC& dc,
1012 wxWindow* WXUNUSED(wnd),
1013 const wxString& caption,
1014 const wxBitmap& WXUNUSED(bitmap),
1015 bool WXUNUSED(active),
1016 int close_button_state,
1017 int* x_extent)
1018 {
1019 wxCoord measured_textx, measured_texty;
1020
1021 dc.SetFont(m_measuring_font);
1022 dc.GetTextExtent(caption, &measured_textx, &measured_texty);
1023
1024 wxCoord tab_height = measured_texty + 4;
1025 wxCoord tab_width = measured_textx + tab_height + 5;
1026
1027 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1028 tab_width += m_active_close_bmp.GetWidth();
1029
1030 if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
1031 {
1032 tab_width = m_fixed_tab_width;
1033 }
1034
1035 *x_extent = tab_width - (tab_height/2) - 1;
1036
1037 return wxSize(tab_width, tab_height);
1038 }
1039
1040
1041 void wxAuiSimpleTabArt::DrawButton(wxDC& dc,
1042 wxWindow* WXUNUSED(wnd),
1043 const wxRect& in_rect,
1044 int bitmap_id,
1045 int button_state,
1046 int orientation,
1047 wxRect* out_rect)
1048 {
1049 wxBitmap bmp;
1050 wxRect rect;
1051
1052 switch (bitmap_id)
1053 {
1054 case wxAUI_BUTTON_CLOSE:
1055 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1056 bmp = m_disabled_close_bmp;
1057 else
1058 bmp = m_active_close_bmp;
1059 break;
1060 case wxAUI_BUTTON_LEFT:
1061 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1062 bmp = m_disabled_left_bmp;
1063 else
1064 bmp = m_active_left_bmp;
1065 break;
1066 case wxAUI_BUTTON_RIGHT:
1067 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1068 bmp = m_disabled_right_bmp;
1069 else
1070 bmp = m_active_right_bmp;
1071 break;
1072 case wxAUI_BUTTON_WINDOWLIST:
1073 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1074 bmp = m_disabled_windowlist_bmp;
1075 else
1076 bmp = m_active_windowlist_bmp;
1077 break;
1078 }
1079
1080 if (!bmp.IsOk())
1081 return;
1082
1083 rect = in_rect;
1084
1085 if (orientation == wxLEFT)
1086 {
1087 rect.SetX(in_rect.x);
1088 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
1089 rect.SetWidth(bmp.GetWidth());
1090 rect.SetHeight(bmp.GetHeight());
1091 }
1092 else
1093 {
1094 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
1095 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
1096 bmp.GetWidth(), bmp.GetHeight());
1097 }
1098
1099
1100 DrawButtons(dc, rect, bmp, *wxWHITE, button_state);
1101
1102 *out_rect = rect;
1103 }
1104
1105
1106 int wxAuiSimpleTabArt::ShowDropDown(wxWindow* wnd,
1107 const wxAuiNotebookPageArray& pages,
1108 int active_idx)
1109 {
1110 wxMenu menuPopup;
1111
1112 size_t i, count = pages.GetCount();
1113 for (i = 0; i < count; ++i)
1114 {
1115 const wxAuiNotebookPage& page = pages.Item(i);
1116 menuPopup.AppendCheckItem(1000+i, page.caption);
1117 }
1118
1119 if (active_idx != -1)
1120 {
1121 menuPopup.Check(1000+active_idx, true);
1122 }
1123
1124 // find out where to put the popup menu of window
1125 // items. Subtract 100 for now to center the menu
1126 // a bit, until a better mechanism can be implemented
1127 wxPoint pt = ::wxGetMousePosition();
1128 pt = wnd->ScreenToClient(pt);
1129 if (pt.x < 100)
1130 pt.x = 0;
1131 else
1132 pt.x -= 100;
1133
1134 // find out the screen coordinate at the bottom of the tab ctrl
1135 wxRect cli_rect = wnd->GetClientRect();
1136 pt.y = cli_rect.y + cli_rect.height;
1137
1138 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
1139 wnd->PushEventHandler(cc);
1140 wnd->PopupMenu(&menuPopup, pt);
1141 int command = cc->GetCommandId();
1142 wnd->PopEventHandler(true);
1143
1144 if (command >= 1000)
1145 return command-1000;
1146
1147 return -1;
1148 }
1149
1150 int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow* wnd,
1151 const wxAuiNotebookPageArray& WXUNUSED(pages),
1152 const wxSize& WXUNUSED(required_bmp_size))
1153 {
1154 wxClientDC dc(wnd);
1155 dc.SetFont(m_measuring_font);
1156 int x_ext = 0;
1157 wxSize s = GetTabSize(dc,
1158 wnd,
1159 wxT("ABCDEFGHIj"),
1160 wxNullBitmap,
1161 true,
1162 wxAUI_BUTTON_STATE_HIDDEN,
1163 &x_ext);
1164 return s.y+3;
1165 }
1166
1167 void wxAuiSimpleTabArt::SetNormalFont(const wxFont& font)
1168 {
1169 m_normal_font = font;
1170 }
1171
1172 void wxAuiSimpleTabArt::SetSelectedFont(const wxFont& font)
1173 {
1174 m_selected_font = font;
1175 }
1176
1177 void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont& font)
1178 {
1179 m_measuring_font = font;
1180 }
1181
1182
1183
1184
1185 // -- wxAuiTabContainer class implementation --
1186
1187
1188 // wxAuiTabContainer is a class which contains information about each
1189 // tab. It also can render an entire tab control to a specified DC.
1190 // It's not a window class itself, because this code will be used by
1191 // the wxFrameMananger, where it is disadvantageous to have separate
1192 // windows for each tab control in the case of "docked tabs"
1193
1194 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
1195 // which can be used as a tab control in the normal sense.
1196
1197
1198 wxAuiTabContainer::wxAuiTabContainer()
1199 {
1200 m_tab_offset = 0;
1201 m_flags = 0;
1202 m_art = new wxAuiDefaultTabArt;
1203
1204 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
1205 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
1206 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
1207 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
1208 }
1209
1210 wxAuiTabContainer::~wxAuiTabContainer()
1211 {
1212 delete m_art;
1213 }
1214
1215 void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art)
1216 {
1217 delete m_art;
1218 m_art = art;
1219
1220 if (m_art)
1221 {
1222 m_art->SetFlags(m_flags);
1223 }
1224 }
1225
1226 wxAuiTabArt* wxAuiTabContainer::GetArtProvider() const
1227 {
1228 return m_art;
1229 }
1230
1231 void wxAuiTabContainer::SetFlags(unsigned int flags)
1232 {
1233 m_flags = flags;
1234
1235 // check for new close button settings
1236 RemoveButton(wxAUI_BUTTON_LEFT);
1237 RemoveButton(wxAUI_BUTTON_RIGHT);
1238 RemoveButton(wxAUI_BUTTON_WINDOWLIST);
1239 RemoveButton(wxAUI_BUTTON_CLOSE);
1240
1241
1242 if (flags & wxAUI_NB_SCROLL_BUTTONS)
1243 {
1244 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
1245 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
1246 }
1247
1248 if (flags & wxAUI_NB_WINDOWLIST_BUTTON)
1249 {
1250 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
1251 }
1252
1253 if (flags & wxAUI_NB_CLOSE_BUTTON)
1254 {
1255 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
1256 }
1257
1258 if (m_art)
1259 {
1260 m_art->SetFlags(m_flags);
1261 }
1262 }
1263
1264 unsigned int wxAuiTabContainer::GetFlags() const
1265 {
1266 return m_flags;
1267 }
1268
1269
1270 void wxAuiTabContainer::SetNormalFont(const wxFont& font)
1271 {
1272 m_art->SetNormalFont(font);
1273 }
1274
1275 void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
1276 {
1277 m_art->SetSelectedFont(font);
1278 }
1279
1280 void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
1281 {
1282 m_art->SetMeasuringFont(font);
1283 }
1284
1285 void wxAuiTabContainer::SetRect(const wxRect& rect)
1286 {
1287 m_rect = rect;
1288
1289 if (m_art)
1290 {
1291 m_art->SetSizingInfo(rect.GetSize(), m_pages.GetCount());
1292 }
1293 }
1294
1295 bool wxAuiTabContainer::AddPage(wxWindow* page,
1296 const wxAuiNotebookPage& info)
1297 {
1298 wxAuiNotebookPage page_info;
1299 page_info = info;
1300 page_info.window = page;
1301
1302 m_pages.Add(page_info);
1303
1304 // let the art provider know how many pages we have
1305 if (m_art)
1306 {
1307 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1308 }
1309
1310 return true;
1311 }
1312
1313 bool wxAuiTabContainer::InsertPage(wxWindow* page,
1314 const wxAuiNotebookPage& info,
1315 size_t idx)
1316 {
1317 wxAuiNotebookPage page_info;
1318 page_info = info;
1319 page_info.window = page;
1320
1321 if (idx >= m_pages.GetCount())
1322 m_pages.Add(page_info);
1323 else
1324 m_pages.Insert(page_info, idx);
1325
1326 // let the art provider know how many pages we have
1327 if (m_art)
1328 {
1329 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1330 }
1331
1332 return true;
1333 }
1334
1335 bool wxAuiTabContainer::MovePage(wxWindow* page,
1336 size_t new_idx)
1337 {
1338 int idx = GetIdxFromWindow(page);
1339 if (idx == -1)
1340 return false;
1341
1342 // get page entry, make a copy of it
1343 wxAuiNotebookPage p = GetPage(idx);
1344
1345 // remove old page entry
1346 RemovePage(page);
1347
1348 // insert page where it should be
1349 InsertPage(page, p, new_idx);
1350
1351 return true;
1352 }
1353
1354 bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
1355 {
1356 size_t i, page_count = m_pages.GetCount();
1357 for (i = 0; i < page_count; ++i)
1358 {
1359 wxAuiNotebookPage& page = m_pages.Item(i);
1360 if (page.window == wnd)
1361 {
1362 m_pages.RemoveAt(i);
1363
1364 // let the art provider know how many pages we have
1365 if (m_art)
1366 {
1367 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
1368 }
1369
1370 return true;
1371 }
1372 }
1373
1374 return false;
1375 }
1376
1377 bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
1378 {
1379 bool found = false;
1380
1381 size_t i, page_count = m_pages.GetCount();
1382 for (i = 0; i < page_count; ++i)
1383 {
1384 wxAuiNotebookPage& page = m_pages.Item(i);
1385 if (page.window == wnd)
1386 {
1387 page.active = true;
1388 found = true;
1389 }
1390 else
1391 {
1392 page.active = false;
1393 }
1394 }
1395
1396 return found;
1397 }
1398
1399 void wxAuiTabContainer::SetNoneActive()
1400 {
1401 size_t i, page_count = m_pages.GetCount();
1402 for (i = 0; i < page_count; ++i)
1403 {
1404 wxAuiNotebookPage& page = m_pages.Item(i);
1405 page.active = false;
1406 }
1407 }
1408
1409 bool wxAuiTabContainer::SetActivePage(size_t page)
1410 {
1411 if (page >= m_pages.GetCount())
1412 return false;
1413
1414 return SetActivePage(m_pages.Item(page).window);
1415 }
1416
1417 int wxAuiTabContainer::GetActivePage() const
1418 {
1419 size_t i, page_count = m_pages.GetCount();
1420 for (i = 0; i < page_count; ++i)
1421 {
1422 wxAuiNotebookPage& page = m_pages.Item(i);
1423 if (page.active)
1424 return i;
1425 }
1426
1427 return -1;
1428 }
1429
1430 wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
1431 {
1432 if (idx >= m_pages.GetCount())
1433 return NULL;
1434
1435 return m_pages[idx].window;
1436 }
1437
1438 int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
1439 {
1440 size_t i, page_count = m_pages.GetCount();
1441 for (i = 0; i < page_count; ++i)
1442 {
1443 wxAuiNotebookPage& page = m_pages.Item(i);
1444 if (page.window == wnd)
1445 return i;
1446 }
1447 return -1;
1448 }
1449
1450 wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
1451 {
1452 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
1453
1454 return m_pages[idx];
1455 }
1456
1457 wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
1458 {
1459 return m_pages;
1460 }
1461
1462 size_t wxAuiTabContainer::GetPageCount() const
1463 {
1464 return m_pages.GetCount();
1465 }
1466
1467 void wxAuiTabContainer::AddButton(int id,
1468 int location,
1469 const wxBitmap& normal_bitmap,
1470 const wxBitmap& disabled_bitmap)
1471 {
1472 wxAuiTabContainerButton button;
1473 button.id = id;
1474 button.bitmap = normal_bitmap;
1475 button.dis_bitmap = disabled_bitmap;
1476 button.location = location;
1477 button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
1478
1479 m_buttons.Add(button);
1480 }
1481
1482 void wxAuiTabContainer::RemoveButton(int id)
1483 {
1484 size_t i, button_count = m_buttons.GetCount();
1485
1486 for (i = 0; i < button_count; ++i)
1487 {
1488 if (m_buttons.Item(i).id == id)
1489 {
1490 m_buttons.RemoveAt(i);
1491 return;
1492 }
1493 }
1494 }
1495
1496
1497
1498 size_t wxAuiTabContainer::GetTabOffset() const
1499 {
1500 return m_tab_offset;
1501 }
1502
1503 void wxAuiTabContainer::SetTabOffset(size_t offset)
1504 {
1505 m_tab_offset = offset;
1506 }
1507
1508
1509
1510
1511 // Render() renders the tab catalog to the specified DC
1512 // It is a virtual function and can be overridden to
1513 // provide custom drawing capabilities
1514 void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd)
1515 {
1516 if (!raw_dc || !raw_dc->IsOk())
1517 return;
1518
1519 wxMemoryDC dc;
1520 wxBitmap bmp;
1521 size_t i;
1522 size_t page_count = m_pages.GetCount();
1523 size_t button_count = m_buttons.GetCount();
1524
1525 // create off-screen bitmap
1526 bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
1527 dc.SelectObject(bmp);
1528
1529 if (!dc.IsOk())
1530 return;
1531
1532 // find out if size of tabs is larger than can be
1533 // afforded on screen
1534 int total_width = 0;
1535 int visible_width = 0;
1536 for (i = 0; i < page_count; ++i)
1537 {
1538 wxAuiNotebookPage& page = m_pages.Item(i);
1539
1540 // determine if a close button is on this tab
1541 bool close_button = false;
1542 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1543 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1544 {
1545 close_button = true;
1546 }
1547
1548
1549 int x_extent = 0;
1550 wxSize size = m_art->GetTabSize(dc,
1551 wnd,
1552 page.caption,
1553 page.bitmap,
1554 page.active,
1555 close_button ?
1556 wxAUI_BUTTON_STATE_NORMAL :
1557 wxAUI_BUTTON_STATE_HIDDEN,
1558 &x_extent);
1559
1560 if (i+1 < page_count)
1561 total_width += x_extent;
1562 else
1563 total_width += size.x;
1564
1565 if (i >= m_tab_offset)
1566 {
1567 if (i+1 < page_count)
1568 visible_width += x_extent;
1569 else
1570 visible_width += size.x;
1571 }
1572 }
1573
1574 if (total_width > m_rect.GetWidth() || m_tab_offset != 0)
1575 {
1576 // show left/right buttons
1577 for (i = 0; i < button_count; ++i)
1578 {
1579 wxAuiTabContainerButton& button = m_buttons.Item(i);
1580 if (button.id == wxAUI_BUTTON_LEFT ||
1581 button.id == wxAUI_BUTTON_RIGHT)
1582 {
1583 button.cur_state &= ~wxAUI_BUTTON_STATE_HIDDEN;
1584 }
1585 }
1586 }
1587 else
1588 {
1589 // hide left/right buttons
1590 for (i = 0; i < button_count; ++i)
1591 {
1592 wxAuiTabContainerButton& button = m_buttons.Item(i);
1593 if (button.id == wxAUI_BUTTON_LEFT ||
1594 button.id == wxAUI_BUTTON_RIGHT)
1595 {
1596 button.cur_state |= wxAUI_BUTTON_STATE_HIDDEN;
1597 }
1598 }
1599 }
1600
1601 // determine whether left button should be enabled
1602 for (i = 0; i < button_count; ++i)
1603 {
1604 wxAuiTabContainerButton& button = m_buttons.Item(i);
1605 if (button.id == wxAUI_BUTTON_LEFT)
1606 {
1607 if (m_tab_offset == 0)
1608 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
1609 else
1610 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
1611 }
1612 if (button.id == wxAUI_BUTTON_RIGHT)
1613 {
1614 if (visible_width < m_rect.GetWidth() - ((int)button_count*16))
1615 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
1616 else
1617 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
1618 }
1619 }
1620
1621
1622
1623 // draw background
1624 m_art->DrawBackground(dc, wnd, m_rect);
1625
1626 // draw buttons
1627 int left_buttons_width = 0;
1628 int right_buttons_width = 0;
1629
1630 int offset = 0;
1631
1632 // draw the buttons on the right side
1633 offset = m_rect.x + m_rect.width;
1634 for (i = 0; i < button_count; ++i)
1635 {
1636 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
1637
1638 if (button.location != wxRIGHT)
1639 continue;
1640 if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
1641 continue;
1642
1643 wxRect button_rect = m_rect;
1644 button_rect.SetY(1);
1645 button_rect.SetWidth(offset);
1646
1647 m_art->DrawButton(dc,
1648 wnd,
1649 button_rect,
1650 button.id,
1651 button.cur_state,
1652 wxRIGHT,
1653 &button.rect);
1654
1655 offset -= button.rect.GetWidth();
1656 right_buttons_width += button.rect.GetWidth();
1657 }
1658
1659
1660
1661 offset = 0;
1662
1663 // draw the buttons on the left side
1664
1665 for (i = 0; i < button_count; ++i)
1666 {
1667 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
1668
1669 if (button.location != wxLEFT)
1670 continue;
1671 if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
1672 continue;
1673
1674 wxRect button_rect(offset, 1, 1000, m_rect.height);
1675
1676 m_art->DrawButton(dc,
1677 wnd,
1678 button_rect,
1679 button.id,
1680 button.cur_state,
1681 wxLEFT,
1682 &button.rect);
1683
1684 offset += button.rect.GetWidth();
1685 left_buttons_width += button.rect.GetWidth();
1686 }
1687
1688 offset = left_buttons_width;
1689
1690 if (offset == 0)
1691 offset += m_art->GetIndentSize();
1692
1693
1694 // prepare the tab-close-button array
1695 // make sure tab button entries which aren't used are marked as hidden
1696 for (i = page_count; i < m_tab_close_buttons.GetCount(); ++i)
1697 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1698
1699 // make sure there are enough tab button entries to accommodate all tabs
1700 while (m_tab_close_buttons.GetCount() < page_count)
1701 {
1702 wxAuiTabContainerButton tempbtn;
1703 tempbtn.id = wxAUI_BUTTON_CLOSE;
1704 tempbtn.location = wxCENTER;
1705 tempbtn.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1706 m_tab_close_buttons.Add(tempbtn);
1707 }
1708
1709
1710 // buttons before the tab offset must be set to hidden
1711 for (i = 0; i < m_tab_offset; ++i)
1712 {
1713 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1714 }
1715
1716
1717 // draw the tabs
1718
1719 size_t active = 999;
1720 int active_offset = 0;
1721 wxRect active_rect;
1722
1723 int x_extent = 0;
1724 wxRect rect = m_rect;
1725 rect.y = 0;
1726 rect.height = m_rect.height;
1727
1728 for (i = m_tab_offset; i < page_count; ++i)
1729 {
1730 wxAuiNotebookPage& page = m_pages.Item(i);
1731 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i);
1732
1733 // determine if a close button is on this tab
1734 bool close_button = false;
1735 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1736 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1737 {
1738 close_button = true;
1739 if (tab_button.cur_state == wxAUI_BUTTON_STATE_HIDDEN)
1740 {
1741 tab_button.id = wxAUI_BUTTON_CLOSE;
1742 tab_button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
1743 tab_button.location = wxCENTER;
1744 }
1745 }
1746 else
1747 {
1748 tab_button.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1749 }
1750
1751 rect.x = offset;
1752 rect.width = m_rect.width - right_buttons_width - offset - 2;
1753
1754 if (rect.width <= 0)
1755 break;
1756
1757 m_art->DrawTab(dc,
1758 wnd,
1759 page,
1760 rect,
1761 tab_button.cur_state,
1762 &page.rect,
1763 &tab_button.rect,
1764 &x_extent);
1765
1766 if (page.active)
1767 {
1768 active = i;
1769 active_offset = offset;
1770 active_rect = rect;
1771 }
1772
1773 offset += x_extent;
1774 }
1775
1776
1777 // make sure to deactivate buttons which are off the screen to the right
1778 for (++i; i < m_tab_close_buttons.GetCount(); ++i)
1779 {
1780 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1781 }
1782
1783
1784 // draw the active tab again so it stands in the foreground
1785 if (active >= m_tab_offset && active < m_pages.GetCount())
1786 {
1787 wxAuiNotebookPage& page = m_pages.Item(active);
1788
1789 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(active);
1790
1791 // determine if a close button is on this tab
1792 bool close_button = false;
1793 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1794 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1795 {
1796 close_button = true;
1797 }
1798
1799 rect.x = active_offset;
1800 m_art->DrawTab(dc,
1801 wnd,
1802 page,
1803 active_rect,
1804 tab_button.cur_state,
1805 &page.rect,
1806 &tab_button.rect,
1807 &x_extent);
1808 }
1809
1810
1811 raw_dc->Blit(m_rect.x, m_rect.y,
1812 m_rect.GetWidth(), m_rect.GetHeight(),
1813 &dc, 0, 0);
1814 }
1815
1816
1817 // TabHitTest() tests if a tab was hit, passing the window pointer
1818 // back if that condition was fulfilled. The function returns
1819 // true if a tab was hit, otherwise false
1820 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
1821 {
1822 if (!m_rect.Contains(x,y))
1823 return false;
1824
1825 wxAuiTabContainerButton* btn = NULL;
1826 if (ButtonHitTest(x, y, &btn))
1827 {
1828 if (m_buttons.Index(*btn) != wxNOT_FOUND)
1829 return false;
1830 }
1831
1832 size_t i, page_count = m_pages.GetCount();
1833
1834 for (i = m_tab_offset; i < page_count; ++i)
1835 {
1836 wxAuiNotebookPage& page = m_pages.Item(i);
1837 if (page.rect.Contains(x,y))
1838 {
1839 if (hit)
1840 *hit = page.window;
1841 return true;
1842 }
1843 }
1844
1845 return false;
1846 }
1847
1848 // ButtonHitTest() tests if a button was hit. The function returns
1849 // true if a button was hit, otherwise false
1850 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
1851 wxAuiTabContainerButton** hit) const
1852 {
1853 if (!m_rect.Contains(x,y))
1854 return false;
1855
1856 size_t i, button_count;
1857
1858
1859 button_count = m_buttons.GetCount();
1860 for (i = 0; i < button_count; ++i)
1861 {
1862 wxAuiTabContainerButton& button = m_buttons.Item(i);
1863 if (button.rect.Contains(x,y) &&
1864 !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN |
1865 wxAUI_BUTTON_STATE_DISABLED)))
1866 {
1867 if (hit)
1868 *hit = &button;
1869 return true;
1870 }
1871 }
1872
1873 button_count = m_tab_close_buttons.GetCount();
1874 for (i = 0; i < button_count; ++i)
1875 {
1876 wxAuiTabContainerButton& button = m_tab_close_buttons.Item(i);
1877 if (button.rect.Contains(x,y) &&
1878 !(button.cur_state & (wxAUI_BUTTON_STATE_HIDDEN |
1879 wxAUI_BUTTON_STATE_DISABLED)))
1880 {
1881 if (hit)
1882 *hit = &button;
1883 return true;
1884 }
1885 }
1886
1887 return false;
1888 }
1889
1890
1891
1892 // the utility function ShowWnd() is the same as show,
1893 // except it handles wxAuiMDIChildFrame windows as well,
1894 // as the Show() method on this class is "unplugged"
1895 static void ShowWnd(wxWindow* wnd, bool show)
1896 {
1897 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1898 {
1899 wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
1900 cf->DoShow(show);
1901 }
1902 else
1903 {
1904 wnd->Show(show);
1905 }
1906 }
1907
1908
1909 // DoShowHide() this function shows the active window, then
1910 // hides all of the other windows (in that order)
1911 void wxAuiTabContainer::DoShowHide()
1912 {
1913 wxAuiNotebookPageArray& pages = GetPages();
1914 size_t i, page_count = pages.GetCount();
1915
1916 // show new active page first
1917 for (i = 0; i < page_count; ++i)
1918 {
1919 wxAuiNotebookPage& page = pages.Item(i);
1920 if (page.active)
1921 {
1922 ShowWnd(page.window, true);
1923 break;
1924 }
1925 }
1926
1927 // hide all other pages
1928 for (i = 0; i < page_count; ++i)
1929 {
1930 wxAuiNotebookPage& page = pages.Item(i);
1931 ShowWnd(page.window, page.active);
1932 }
1933 }
1934
1935
1936
1937
1938
1939
1940 // -- wxAuiTabCtrl class implementation --
1941
1942
1943
1944 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
1945 EVT_PAINT(wxAuiTabCtrl::OnPaint)
1946 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
1947 EVT_SIZE(wxAuiTabCtrl::OnSize)
1948 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
1949 EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDown)
1950 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
1951 EVT_MOTION(wxAuiTabCtrl::OnMotion)
1952 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
1953 EVT_AUINOTEBOOK_BUTTON(-1, wxAuiTabCtrl::OnButton)
1954 END_EVENT_TABLE()
1955
1956
1957 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
1958 wxWindowID id,
1959 const wxPoint& pos,
1960 const wxSize& size,
1961 long style) : wxControl(parent, id, pos, size, style)
1962 {
1963 m_click_pt = wxDefaultPosition;
1964 m_is_dragging = false;
1965 m_hover_button = NULL;
1966 m_pressed_button = NULL;
1967 }
1968
1969 wxAuiTabCtrl::~wxAuiTabCtrl()
1970 {
1971 }
1972
1973 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
1974 {
1975 wxPaintDC dc(this);
1976
1977 dc.SetFont(GetFont());
1978
1979 if (GetPageCount() > 0)
1980 Render(&dc, this);
1981 }
1982
1983 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
1984 {
1985 }
1986
1987 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
1988 {
1989 wxSize s = evt.GetSize();
1990 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
1991 SetRect(r);
1992 }
1993
1994 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
1995 {
1996 CaptureMouse();
1997 m_click_pt = wxDefaultPosition;
1998 m_is_dragging = false;
1999 m_click_tab = NULL;
2000 m_pressed_button = NULL;
2001
2002
2003 wxWindow* wnd;
2004 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
2005 {
2006 int new_selection = GetIdxFromWindow(wnd);
2007
2008 if (new_selection != GetActivePage())
2009 {
2010 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2011 e.SetSelection(new_selection);
2012 e.SetOldSelection(GetActivePage());
2013 e.SetEventObject(this);
2014 GetEventHandler()->ProcessEvent(e);
2015 }
2016
2017 m_click_pt.x = evt.m_x;
2018 m_click_pt.y = evt.m_y;
2019 m_click_tab = wnd;
2020 }
2021
2022 if (m_hover_button)
2023 {
2024 m_pressed_button = m_hover_button;
2025 m_pressed_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
2026 Refresh();
2027 Update();
2028 }
2029 }
2030
2031 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent& evt)
2032 {
2033 if (GetCapture() == this)
2034 ReleaseMouse();
2035
2036 if (m_is_dragging)
2037 {
2038 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
2039 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2040 evt.SetOldSelection(evt.GetSelection());
2041 evt.SetEventObject(this);
2042 GetEventHandler()->ProcessEvent(evt);
2043 return;
2044 }
2045
2046 if (m_pressed_button)
2047 {
2048 // make sure we're still clicking the button
2049 wxAuiTabContainerButton* button = NULL;
2050 if (!ButtonHitTest(evt.m_x, evt.m_y, &button))
2051 return;
2052
2053 if (button != m_pressed_button)
2054 {
2055 m_pressed_button = NULL;
2056 return;
2057 }
2058
2059 Refresh();
2060 Update();
2061
2062 if (!(m_pressed_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
2063 {
2064 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
2065 evt.SetInt(m_pressed_button->id);
2066 evt.SetEventObject(this);
2067 GetEventHandler()->ProcessEvent(evt);
2068 }
2069
2070 m_pressed_button = NULL;
2071 }
2072
2073 m_click_pt = wxDefaultPosition;
2074 m_is_dragging = false;
2075 m_click_tab = NULL;
2076 }
2077
2078 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
2079 {
2080 wxPoint pos = evt.GetPosition();
2081
2082 // check if the mouse is hovering above a button
2083 wxAuiTabContainerButton* button;
2084 if (ButtonHitTest(pos.x, pos.y, &button))
2085 {
2086 if (m_hover_button && button != m_hover_button)
2087 {
2088 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2089 m_hover_button = NULL;
2090 Refresh();
2091 Update();
2092 }
2093
2094 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
2095 {
2096 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
2097 Refresh();
2098 Update();
2099 m_hover_button = button;
2100 return;
2101 }
2102 }
2103 else
2104 {
2105 if (m_hover_button)
2106 {
2107 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2108 m_hover_button = NULL;
2109 Refresh();
2110 Update();
2111 }
2112 }
2113
2114
2115 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
2116 return;
2117
2118 if (m_is_dragging)
2119 {
2120 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
2121 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2122 evt.SetOldSelection(evt.GetSelection());
2123 evt.SetEventObject(this);
2124 GetEventHandler()->ProcessEvent(evt);
2125 return;
2126 }
2127
2128
2129 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
2130 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
2131
2132 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
2133 abs(pos.y - m_click_pt.y) > drag_y_threshold)
2134 {
2135 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
2136 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2137 evt.SetOldSelection(evt.GetSelection());
2138 evt.SetEventObject(this);
2139 GetEventHandler()->ProcessEvent(evt);
2140
2141 m_is_dragging = true;
2142 }
2143 }
2144
2145 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
2146 {
2147 if (m_hover_button)
2148 {
2149 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2150 m_hover_button = NULL;
2151 Refresh();
2152 Update();
2153 }
2154 }
2155
2156 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
2157 {
2158 int button = event.GetInt();
2159
2160 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
2161 {
2162 if (button == wxAUI_BUTTON_LEFT)
2163 {
2164 if (GetTabOffset() > 0)
2165 {
2166 SetTabOffset(GetTabOffset()-1);
2167 Refresh();
2168 Update();
2169 }
2170 }
2171 else
2172 {
2173 SetTabOffset(GetTabOffset()+1);
2174 Refresh();
2175 Update();
2176 }
2177 }
2178 else if (button == wxAUI_BUTTON_WINDOWLIST)
2179 {
2180 int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage());
2181
2182 if (idx != -1)
2183 {
2184 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2185 e.SetSelection(idx);
2186 e.SetOldSelection(GetActivePage());
2187 e.SetEventObject(this);
2188 GetEventHandler()->ProcessEvent(e);
2189 }
2190 }
2191 else
2192 {
2193 event.Skip();
2194 }
2195 }
2196
2197 // wxTabFrame is an interesting case. It's important that all child pages
2198 // of the multi-notebook control are all actually children of that control
2199 // (and not grandchildren). wxTabFrame facilitates this. There is one
2200 // instance of wxTabFrame for each tab control inside the multi-notebook.
2201 // It's important to know that wxTabFrame is not a real window, but it merely
2202 // used to capture the dimensions/positioning of the internal tab control and
2203 // it's managed page windows
2204
2205 class wxTabFrame : public wxWindow
2206 {
2207 public:
2208
2209 wxTabFrame()
2210 {
2211 m_tabs = NULL;
2212 m_rect = wxRect(0,0,200,200);
2213 m_tab_ctrl_height = 20;
2214 }
2215
2216 void SetTabCtrlHeight(int h)
2217 {
2218 m_tab_ctrl_height = h;
2219 }
2220
2221 void DoSetSize(int x, int y,
2222 int width, int height,
2223 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
2224 {
2225 m_rect = wxRect(x, y, width, height);
2226 DoSizing();
2227 }
2228
2229 void DoGetClientSize(int* x, int* y) const
2230 {
2231 *x = m_rect.width;
2232 *y = m_rect.height;
2233 }
2234
2235 bool Show( bool WXUNUSED(show = true) ) { return false; }
2236
2237 void DoSizing()
2238 {
2239 if (!m_tabs)
2240 return;
2241
2242 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2243 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2244 m_tabs->SetRect(wxRect(0, 0, m_rect.width, m_tab_ctrl_height));
2245 m_tabs->Refresh();
2246 m_tabs->Update();
2247
2248 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
2249 size_t i, page_count = pages.GetCount();
2250
2251 for (i = 0; i < page_count; ++i)
2252 {
2253 wxAuiNotebookPage& page = pages.Item(i);
2254 page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height,
2255 m_rect.width, m_rect.height - m_tab_ctrl_height);
2256
2257 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2258 {
2259 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
2260 wnd->ApplyMDIChildFrameRect();
2261 }
2262 }
2263 }
2264
2265 void DoGetSize(int* x, int* y) const
2266 {
2267 if (x)
2268 *x = m_rect.GetWidth();
2269 if (y)
2270 *y = m_rect.GetHeight();
2271 }
2272
2273 void Update()
2274 {
2275 // does nothing
2276 }
2277
2278 public:
2279
2280 wxRect m_rect;
2281 wxRect m_tab_rect;
2282 wxAuiTabCtrl* m_tabs;
2283 int m_tab_ctrl_height;
2284 };
2285
2286
2287 const int wxAuiBaseTabCtrlId = 5380;
2288
2289
2290 // -- wxAuiNotebook class implementation --
2291
2292 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
2293 EVT_SIZE(wxAuiNotebook::OnSize)
2294 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
2295 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2296 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
2297 wxAuiNotebook::OnTabClicked)
2298 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2299 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
2300 wxAuiNotebook::OnTabBeginDrag)
2301 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2302 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
2303 wxAuiNotebook::OnTabEndDrag)
2304 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2305 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
2306 wxAuiNotebook::OnTabDragMotion)
2307 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2308 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
2309 wxAuiNotebook::OnTabButton)
2310 END_EVENT_TABLE()
2311
2312 wxAuiNotebook::wxAuiNotebook()
2313 {
2314 m_curpage = -1;
2315 m_tab_id_counter = wxAuiBaseTabCtrlId;
2316 m_dummy_wnd = NULL;
2317 m_tab_ctrl_height = 20;
2318 m_requested_bmp_size = wxDefaultSize;
2319 m_requested_tabctrl_height = -1;
2320 }
2321
2322 wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
2323 wxWindowID id,
2324 const wxPoint& pos,
2325 const wxSize& size,
2326 long style) : wxControl(parent, id, pos, size, style)
2327 {
2328 m_dummy_wnd = NULL;
2329 m_requested_bmp_size = wxDefaultSize;
2330 m_requested_tabctrl_height = -1;
2331 InitNotebook(style);
2332 }
2333
2334 bool wxAuiNotebook::Create(wxWindow* parent,
2335 wxWindowID id,
2336 const wxPoint& pos,
2337 const wxSize& size,
2338 long style)
2339 {
2340 if (!wxControl::Create(parent, id, pos, size, style))
2341 return false;
2342
2343 InitNotebook(style);
2344
2345 return true;
2346 }
2347
2348 // InitNotebook() contains common initialization
2349 // code called by all constructors
2350 void wxAuiNotebook::InitNotebook(long style)
2351 {
2352 m_curpage = -1;
2353 m_tab_id_counter = wxAuiBaseTabCtrlId;
2354 m_dummy_wnd = NULL;
2355 m_flags = (unsigned int)style;
2356 m_tab_ctrl_height = 20;
2357
2358 m_normal_font = *wxNORMAL_FONT;
2359 m_selected_font = *wxNORMAL_FONT;
2360 m_selected_font.SetWeight(wxBOLD);
2361
2362 SetArtProvider(new wxAuiDefaultTabArt);
2363
2364 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
2365 m_dummy_wnd->SetSize(200, 200);
2366 m_dummy_wnd->Show(false);
2367
2368 m_mgr.SetManagedWindow(this);
2369 m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
2370 m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
2371
2372 m_mgr.AddPane(m_dummy_wnd,
2373 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
2374
2375 m_mgr.Update();
2376 }
2377
2378 wxAuiNotebook::~wxAuiNotebook()
2379 {
2380 m_mgr.UnInit();
2381 }
2382
2383 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
2384 {
2385 m_tabs.SetArtProvider(art);
2386
2387 UpdateTabCtrlHeight();
2388 }
2389
2390 // SetTabCtrlHeight() is the highest-level override of the
2391 // tab height. A call to this function effectively enforces a
2392 // specified tab ctrl height, overriding all other considerations,
2393 // such as text or bitmap height. It overrides any call to
2394 // SetUniformBitmapSize(). Specifying a height of -1 reverts
2395 // any previous call and returns to the default behavior
2396
2397 void wxAuiNotebook::SetTabCtrlHeight(int height)
2398 {
2399 m_requested_tabctrl_height = height;
2400
2401 // if window is already initialized, recalculate the tab height
2402 if (m_dummy_wnd)
2403 {
2404 UpdateTabCtrlHeight();
2405 }
2406 }
2407
2408
2409 // SetUniformBitmapSize() ensures that all tabs will have
2410 // the same height, even if some tabs don't have bitmaps
2411 // Passing wxDefaultSize to this function will instruct
2412 // the control to use dynamic tab height-- so when a tab
2413 // with a large bitmap is added, the tab ctrl's height will
2414 // automatically increase to accommodate the bitmap
2415
2416 void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
2417 {
2418 m_requested_bmp_size = size;
2419
2420 // if window is already initialized, recalculate the tab height
2421 if (m_dummy_wnd)
2422 {
2423 UpdateTabCtrlHeight();
2424 }
2425 }
2426
2427 // UpdateTabCtrlHeight() does the actual tab resizing. It's meant
2428 // to be used interally
2429 void wxAuiNotebook::UpdateTabCtrlHeight()
2430 {
2431 // get the tab ctrl height we will use
2432 int height = CalculateTabCtrlHeight();
2433
2434 // if the tab control height needs to change, update
2435 // all of our tab controls with the new height
2436 if (m_tab_ctrl_height != height)
2437 {
2438 wxAuiTabArt* art = m_tabs.GetArtProvider();
2439
2440 m_tab_ctrl_height = height;
2441
2442 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2443 size_t i, pane_count = all_panes.GetCount();
2444 for (i = 0; i < pane_count; ++i)
2445 {
2446 wxAuiPaneInfo& pane = all_panes.Item(i);
2447 if (pane.name == wxT("dummy"))
2448 continue;
2449 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
2450 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
2451 tab_frame->SetTabCtrlHeight(m_tab_ctrl_height);
2452 tabctrl->SetArtProvider(art->Clone());
2453 tab_frame->DoSizing();
2454 }
2455 }
2456 }
2457
2458 void wxAuiNotebook::UpdateHintWindowSize()
2459 {
2460 wxSize size = CalculateNewSplitSize();
2461
2462 // the placeholder hint window should be set to this size
2463 wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
2464 if (info.IsOk())
2465 {
2466 info.MinSize(size);
2467 info.BestSize(size);
2468 m_dummy_wnd->SetSize(size);
2469 }
2470 }
2471
2472
2473 // calculates the size of the new split
2474 wxSize wxAuiNotebook::CalculateNewSplitSize()
2475 {
2476 // count number of tab controls
2477 int tab_ctrl_count = 0;
2478 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2479 size_t i, pane_count = all_panes.GetCount();
2480 for (i = 0; i < pane_count; ++i)
2481 {
2482 wxAuiPaneInfo& pane = all_panes.Item(i);
2483 if (pane.name == wxT("dummy"))
2484 continue;
2485 tab_ctrl_count++;
2486 }
2487
2488 wxSize new_split_size;
2489
2490 // if there is only one tab control, the first split
2491 // should happen around the middle
2492 if (tab_ctrl_count < 2)
2493 {
2494 new_split_size = GetClientSize();
2495 new_split_size.x /= 2;
2496 new_split_size.y /= 2;
2497 }
2498 else
2499 {
2500 // this is in place of a more complicated calculation
2501 // that needs to be implemented
2502 new_split_size = wxSize(180,180);
2503 }
2504
2505 return new_split_size;
2506 }
2507
2508 int wxAuiNotebook::CalculateTabCtrlHeight()
2509 {
2510 // if a fixed tab ctrl height is specified,
2511 // just return that instead of calculating a
2512 // tab height
2513 if (m_requested_tabctrl_height != -1)
2514 return m_requested_tabctrl_height;
2515
2516 // find out new best tab height
2517 wxAuiTabArt* art = m_tabs.GetArtProvider();
2518
2519 return art->GetBestTabCtrlSize(this,
2520 m_tabs.GetPages(),
2521 m_requested_bmp_size);
2522 }
2523
2524
2525 wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
2526 {
2527 return m_tabs.GetArtProvider();
2528 }
2529
2530 void wxAuiNotebook::SetWindowStyleFlag(long style)
2531 {
2532 wxControl::SetWindowStyleFlag(style);
2533
2534 m_flags = (unsigned int)style;
2535
2536 // if the control is already initialized
2537 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
2538 {
2539 // let all of the tab children know about the new style
2540
2541 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2542 size_t i, pane_count = all_panes.GetCount();
2543 for (i = 0; i < pane_count; ++i)
2544 {
2545 wxAuiPaneInfo& pane = all_panes.Item(i);
2546 if (pane.name == wxT("dummy"))
2547 continue;
2548 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
2549 wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
2550 tabctrl->SetFlags(m_flags);
2551 tabframe->DoSizing();
2552 tabctrl->Refresh();
2553 tabctrl->Update();
2554 }
2555 }
2556 }
2557
2558
2559 bool wxAuiNotebook::AddPage(wxWindow* page,
2560 const wxString& caption,
2561 bool select,
2562 const wxBitmap& bitmap)
2563 {
2564 return InsertPage(GetPageCount(), page, caption, select, bitmap);
2565 }
2566
2567 bool wxAuiNotebook::InsertPage(size_t page_idx,
2568 wxWindow* page,
2569 const wxString& caption,
2570 bool select,
2571 const wxBitmap& bitmap)
2572 {
2573 wxAuiNotebookPage info;
2574 info.window = page;
2575 info.caption = caption;
2576 info.bitmap = bitmap;
2577 info.active = false;
2578
2579 // if there are currently no tabs, the first added
2580 // tab must be active
2581 if (m_tabs.GetPageCount() == 0)
2582 info.active = true;
2583
2584 m_tabs.InsertPage(page, info, page_idx);
2585
2586 // if that was the first page added, even if
2587 // select is false, it must become the "current page"
2588 // (though no select events will be fired)
2589 if (!select && m_tabs.GetPageCount() == 1)
2590 m_curpage = GetPageIndex(page);
2591
2592 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
2593 if (page_idx >= active_tabctrl->GetPageCount())
2594 active_tabctrl->AddPage(page, info);
2595 else
2596 active_tabctrl->InsertPage(page, info, page_idx);
2597
2598 UpdateTabCtrlHeight();
2599 DoSizing();
2600 active_tabctrl->DoShowHide();
2601
2602 if (select)
2603 {
2604 int idx = m_tabs.GetIdxFromWindow(page);
2605 wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()"));
2606
2607 SetSelection(idx);
2608 }
2609
2610 return true;
2611 }
2612
2613
2614 // DeletePage() removes a tab from the multi-notebook,
2615 // and destroys the window as well
2616 bool wxAuiNotebook::DeletePage(size_t page_idx)
2617 {
2618 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2619
2620 if (!RemovePage(page_idx))
2621 return false;
2622
2623 // actually destroy the window now
2624 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2625 {
2626 // delete the child frame with pending delete, as is
2627 // customary with frame windows
2628 if (!wxPendingDelete.Member(wnd))
2629 wxPendingDelete.Append(wnd);
2630 }
2631 else
2632 {
2633 wnd->Destroy();
2634 }
2635
2636 return true;
2637 }
2638
2639
2640
2641 // RemovePage() removes a tab from the multi-notebook,
2642 // but does not destroy the window
2643 bool wxAuiNotebook::RemovePage(size_t page_idx)
2644 {
2645 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2646 wxWindow* new_active = NULL;
2647
2648 // find out which onscreen tab ctrl owns this tab
2649 wxAuiTabCtrl* ctrl;
2650 int ctrl_idx;
2651 if (!FindTab(wnd, &ctrl, &ctrl_idx))
2652 return false;
2653
2654 // find a new page and set it as active
2655 int new_idx = ctrl_idx+1;
2656 if (new_idx >= (int)ctrl->GetPageCount())
2657 new_idx = ctrl_idx-1;
2658
2659 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
2660 {
2661 new_active = ctrl->GetWindowFromIdx(new_idx);
2662 }
2663 else
2664 {
2665 // set the active page to the first page that
2666 // isn't the one being deleted
2667 size_t i, page_count = m_tabs.GetPageCount();
2668 for (i = 0; i < page_count; ++i)
2669 {
2670 wxWindow* w = m_tabs.GetWindowFromIdx(i);
2671 if (wnd != w)
2672 {
2673 new_active = m_tabs.GetWindowFromIdx(i);
2674 break;
2675 }
2676 }
2677 }
2678
2679 // remove the tab from main catalog
2680 if (!m_tabs.RemovePage(wnd))
2681 return false;
2682
2683 // remove the tab from the onscreen tab ctrl
2684 ctrl->RemovePage(wnd);
2685
2686
2687 RemoveEmptyTabFrames();
2688
2689 // set new active pane
2690 if (new_active)
2691 {
2692 m_curpage = -1;
2693 SetSelection(m_tabs.GetIdxFromWindow(new_active));
2694 }
2695
2696 return true;
2697 }
2698
2699 // GetPageIndex() returns the index of the page, or -1 if the
2700 // page could not be located in the notebook
2701 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2702 {
2703 return m_tabs.GetIdxFromWindow(page_wnd);
2704 }
2705
2706
2707
2708 // SetPageText() changes the tab caption of the specified page
2709 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2710 {
2711 if (page_idx >= m_tabs.GetPageCount())
2712 return false;
2713
2714 // update our own tab catalog
2715 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2716 page_info.caption = text;
2717
2718 // update what's on screen
2719 wxAuiTabCtrl* ctrl;
2720 int ctrl_idx;
2721 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2722 {
2723 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2724 info.caption = text;
2725 ctrl->Refresh();
2726 ctrl->Update();
2727 }
2728
2729 return true;
2730 }
2731
2732
2733 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2734 {
2735 if (page_idx >= m_tabs.GetPageCount())
2736 return false;
2737
2738 // update our own tab catalog
2739 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2740 page_info.bitmap = bitmap;
2741
2742 // tab height might have changed
2743 UpdateTabCtrlHeight();
2744
2745 // update what's on screen
2746 wxAuiTabCtrl* ctrl;
2747 int ctrl_idx;
2748 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2749 {
2750 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2751 info.bitmap = bitmap;
2752 ctrl->Refresh();
2753 ctrl->Update();
2754 }
2755
2756 return true;
2757 }
2758
2759
2760 // GetSelection() returns the index of the currently active page
2761 int wxAuiNotebook::GetSelection() const
2762 {
2763 return m_curpage;
2764 }
2765
2766 // SetSelection() sets the currently active page
2767 size_t wxAuiNotebook::SetSelection(size_t new_page)
2768 {
2769 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
2770 if (!wnd)
2771 return m_curpage;
2772
2773 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2774 evt.SetSelection(new_page);
2775 evt.SetOldSelection(m_curpage);
2776 evt.SetEventObject(this);
2777 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
2778 {
2779 int old_curpage = m_curpage;
2780 m_curpage = new_page;
2781
2782 // program allows the page change
2783 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
2784 (void)GetEventHandler()->ProcessEvent(evt);
2785
2786
2787 wxAuiTabCtrl* ctrl;
2788 int ctrl_idx;
2789 if (FindTab(wnd, &ctrl, &ctrl_idx))
2790 {
2791 m_tabs.SetActivePage(wnd);
2792
2793 ctrl->SetActivePage(ctrl_idx);
2794 DoSizing();
2795 ctrl->DoShowHide();
2796
2797
2798
2799 // set fonts
2800 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2801 size_t i, pane_count = all_panes.GetCount();
2802 for (i = 0; i < pane_count; ++i)
2803 {
2804 wxAuiPaneInfo& pane = all_panes.Item(i);
2805 if (pane.name == wxT("dummy"))
2806 continue;
2807 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2808 if (tabctrl != ctrl)
2809 tabctrl->SetSelectedFont(m_normal_font);
2810 else
2811 tabctrl->SetSelectedFont(m_selected_font);
2812 tabctrl->Refresh();
2813 }
2814
2815 wnd->SetFocus();
2816
2817 return old_curpage;
2818 }
2819 }
2820
2821 return m_curpage;
2822 }
2823
2824 // GetPageCount() returns the total number of
2825 // pages managed by the multi-notebook
2826 size_t wxAuiNotebook::GetPageCount() const
2827 {
2828 return m_tabs.GetPageCount();
2829 }
2830
2831 // GetPage() returns the wxWindow pointer of the
2832 // specified page
2833 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2834 {
2835 wxASSERT(page_idx < m_tabs.GetPageCount());
2836
2837 return m_tabs.GetWindowFromIdx(page_idx);
2838 }
2839
2840 // DoSizing() performs all sizing operations in each tab control
2841 void wxAuiNotebook::DoSizing()
2842 {
2843 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2844 size_t i, pane_count = all_panes.GetCount();
2845 for (i = 0; i < pane_count; ++i)
2846 {
2847 if (all_panes.Item(i).name == wxT("dummy"))
2848 continue;
2849
2850 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2851 tabframe->DoSizing();
2852 }
2853 }
2854
2855 // GetActiveTabCtrl() returns the active tab control. It is
2856 // called to determine which control gets new windows being added
2857 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
2858 {
2859 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
2860 {
2861 wxAuiTabCtrl* ctrl;
2862 int idx;
2863
2864 // find the tab ctrl with the current page
2865 if (FindTab(m_tabs.GetPage(m_curpage).window,
2866 &ctrl, &idx))
2867 {
2868 return ctrl;
2869 }
2870 }
2871
2872 // no current page, just find the first tab ctrl
2873 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2874 size_t i, pane_count = all_panes.GetCount();
2875 for (i = 0; i < pane_count; ++i)
2876 {
2877 if (all_panes.Item(i).name == wxT("dummy"))
2878 continue;
2879
2880 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2881 return tabframe->m_tabs;
2882 }
2883
2884 // If there is no tabframe at all, create one
2885 wxTabFrame* tabframe = new wxTabFrame;
2886 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
2887 tabframe->m_tabs = new wxAuiTabCtrl(this,
2888 m_tab_id_counter++,
2889 wxDefaultPosition,
2890 wxDefaultSize,
2891 wxNO_BORDER);
2892 tabframe->m_tabs->SetFlags(m_flags);
2893 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2894 m_mgr.AddPane(tabframe,
2895 wxAuiPaneInfo().Center().CaptionVisible(false));
2896
2897 m_mgr.Update();
2898
2899 return tabframe->m_tabs;
2900 }
2901
2902 // FindTab() finds the tab control that currently contains the window as well
2903 // as the index of the window in the tab control. It returns true if the
2904 // window was found, otherwise false.
2905 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2906 {
2907 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2908 size_t i, pane_count = all_panes.GetCount();
2909 for (i = 0; i < pane_count; ++i)
2910 {
2911 if (all_panes.Item(i).name == wxT("dummy"))
2912 continue;
2913
2914 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2915
2916 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2917 if (page_idx != -1)
2918 {
2919 *ctrl = tabframe->m_tabs;
2920 *idx = page_idx;
2921 return true;
2922 }
2923 }
2924
2925 return false;
2926 }
2927
2928 void wxAuiNotebook::OnSize(wxSizeEvent& evt)
2929 {
2930 UpdateHintWindowSize();
2931
2932 evt.Skip();
2933 }
2934
2935 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
2936 {
2937 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2938
2939 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2940 wxASSERT(ctrl != NULL);
2941
2942 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
2943 wxASSERT(wnd != NULL);
2944
2945 int idx = m_tabs.GetIdxFromWindow(wnd);
2946 wxASSERT(idx != -1);
2947
2948 SetSelection(idx);
2949 }
2950
2951 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
2952 {
2953 m_last_drag_x = 0;
2954 }
2955
2956 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
2957 {
2958 wxPoint screen_pt = ::wxGetMousePosition();
2959 wxPoint client_pt = ScreenToClient(screen_pt);
2960 wxPoint zero(0,0);
2961
2962 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2963 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
2964
2965 if (dest_tabs == src_tabs)
2966 {
2967 if (src_tabs)
2968 {
2969 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2970 }
2971
2972 // always hide the hint for inner-tabctrl drag
2973 m_mgr.HideHint();
2974
2975 // if tab moving is not allowed, leave
2976 if (!(m_flags & wxAUI_NB_TAB_MOVE))
2977 {
2978 return;
2979 }
2980
2981 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
2982 wxWindow* dest_location_tab;
2983
2984 // this is an inner-tab drag/reposition
2985 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
2986 {
2987 int src_idx = evt.GetSelection();
2988 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
2989
2990 // prevent jumpy drag
2991 if ((src_idx == dest_idx) || dest_idx == -1 ||
2992 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
2993 (src_idx < dest_idx && m_last_drag_x >= pt.x))
2994 {
2995 m_last_drag_x = pt.x;
2996 return;
2997 }
2998
2999
3000 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
3001 dest_tabs->MovePage(src_tab, dest_idx);
3002 dest_tabs->SetActivePage((size_t)dest_idx);
3003 dest_tabs->DoShowHide();
3004 dest_tabs->Refresh();
3005 m_last_drag_x = pt.x;
3006
3007 }
3008
3009 return;
3010 }
3011
3012
3013 // if external drag is allowed, check if the tab is being dragged
3014 // over a different wxAuiNotebook control
3015 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3016 {
3017 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
3018
3019 // if we aren't over any window, stop here
3020 if (!tab_ctrl)
3021 return;
3022
3023 // make sure we are not over the hint window
3024 if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
3025 {
3026 while (tab_ctrl)
3027 {
3028 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3029 break;
3030 tab_ctrl = tab_ctrl->GetParent();
3031 }
3032
3033 if (tab_ctrl)
3034 {
3035 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3036
3037 if (nb != this)
3038 {
3039 wxRect hint_rect = tab_ctrl->GetClientRect();
3040 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
3041 m_mgr.ShowHint(hint_rect);
3042 return;
3043 }
3044 }
3045 }
3046 else
3047 {
3048 if (!dest_tabs)
3049 {
3050 // we are either over a hint window, or not over a tab
3051 // window, and there is no where to drag to, so exit
3052 return;
3053 }
3054 }
3055 }
3056
3057
3058 // if there are less than two panes, split can't happen, so leave
3059 if (m_tabs.GetPageCount() < 2)
3060 return;
3061
3062 // if tab moving is not allowed, leave
3063 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
3064 return;
3065
3066
3067 if (src_tabs)
3068 {
3069 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
3070 }
3071
3072
3073 if (dest_tabs)
3074 {
3075 wxRect hint_rect = dest_tabs->GetRect();
3076 ClientToScreen(&hint_rect.x, &hint_rect.y);
3077 m_mgr.ShowHint(hint_rect);
3078 }
3079 else
3080 {
3081 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
3082 }
3083 }
3084
3085
3086
3087 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
3088 {
3089 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3090
3091 m_mgr.HideHint();
3092
3093
3094 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3095 wxAuiTabCtrl* dest_tabs = NULL;
3096 if (src_tabs)
3097 {
3098 // set cursor back to an arrow
3099 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3100 }
3101
3102 // get the mouse position, which will be used to determine the drop point
3103 wxPoint mouse_screen_pt = ::wxGetMousePosition();
3104 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
3105
3106
3107
3108 // check for an external move
3109 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3110 {
3111 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
3112
3113 while (tab_ctrl)
3114 {
3115 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3116 break;
3117 tab_ctrl = tab_ctrl->GetParent();
3118 }
3119
3120 if (tab_ctrl)
3121 {
3122 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3123
3124 if (nb != this)
3125 {
3126 // find out from the destination control
3127 // if it's ok to drop this tab here
3128 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
3129 e.SetSelection(evt.GetSelection());
3130 e.SetOldSelection(evt.GetSelection());
3131 e.SetEventObject(this);
3132 e.SetDragSource(this);
3133 e.Veto(); // dropping must be explicitly approved by control owner
3134
3135 nb->GetEventHandler()->ProcessEvent(e);
3136
3137 if (!e.IsAllowed())
3138 {
3139 // no answer or negative answer
3140 m_mgr.HideHint();
3141 return;
3142 }
3143
3144 // drop was allowed
3145 int src_idx = evt.GetSelection();
3146 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
3147
3148 // get main index of the page
3149 int main_idx = m_tabs.GetIdxFromWindow(src_page);
3150
3151 // make a copy of the page info
3152 wxAuiNotebookPage page_info = m_tabs.GetPage((size_t)main_idx);
3153
3154 // remove the page from the source notebook
3155 RemovePage(main_idx);
3156
3157 // reparent the page
3158 src_page->Reparent(nb);
3159
3160
3161 // found out the insert idx
3162 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
3163 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3164
3165 wxWindow* target = NULL;
3166 int insert_idx = -1;
3167 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3168 if (target)
3169 {
3170 insert_idx = dest_tabs->GetIdxFromWindow(target);
3171 }
3172
3173
3174 // add the page to the new notebook
3175 if (insert_idx == -1)
3176 insert_idx = dest_tabs->GetPageCount();
3177 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3178 nb->m_tabs.AddPage(page_info.window, page_info);
3179
3180 nb->DoSizing();
3181 dest_tabs->DoShowHide();
3182 dest_tabs->Refresh();
3183
3184 // set the selection in the destination tab control
3185 nb->SetSelection(nb->m_tabs.GetIdxFromWindow(page_info.window));
3186
3187 return;
3188 }
3189 }
3190 }
3191
3192
3193
3194
3195 // only perform a tab split if it's allowed
3196 if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
3197 {
3198 // If the pointer is in an existing tab frame, do a tab insert
3199 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
3200 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
3201 int insert_idx = -1;
3202 if (tab_frame)
3203 {
3204 dest_tabs = tab_frame->m_tabs;
3205
3206 if (dest_tabs == src_tabs)
3207 return;
3208
3209
3210 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3211 wxWindow* target = NULL;
3212 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3213 if (target)
3214 {
3215 insert_idx = dest_tabs->GetIdxFromWindow(target);
3216 }
3217 }
3218 else
3219 {
3220 wxPoint zero(0,0);
3221 wxRect rect = m_mgr.CalculateHintRect(m_dummy_wnd,
3222 mouse_client_pt,
3223 zero);
3224 if (rect.IsEmpty())
3225 {
3226 // there is no suitable drop location here, exit out
3227 return;
3228 }
3229
3230 // If there is no tabframe at all, create one
3231 wxTabFrame* new_tabs = new wxTabFrame;
3232 new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
3233 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3234 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3235 m_tab_id_counter++,
3236 wxDefaultPosition,
3237 wxDefaultSize,
3238 wxNO_BORDER);
3239 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3240 new_tabs->m_tabs->SetFlags(m_flags);
3241
3242 m_mgr.AddPane(new_tabs,
3243 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3244 mouse_client_pt);
3245 m_mgr.Update();
3246 dest_tabs = new_tabs->m_tabs;
3247 }
3248
3249
3250
3251 // remove the page from the source tabs
3252 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
3253 page_info.active = false;
3254 src_tabs->RemovePage(page_info.window);
3255 if (src_tabs->GetPageCount() > 0)
3256 {
3257 src_tabs->SetActivePage((size_t)0);
3258 src_tabs->DoShowHide();
3259 src_tabs->Refresh();
3260 }
3261
3262
3263
3264 // add the page to the destination tabs
3265 if (insert_idx == -1)
3266 insert_idx = dest_tabs->GetPageCount();
3267 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3268
3269 if (src_tabs->GetPageCount() == 0)
3270 {
3271 RemoveEmptyTabFrames();
3272 }
3273
3274 DoSizing();
3275 dest_tabs->DoShowHide();
3276 dest_tabs->Refresh();
3277
3278 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
3279
3280 UpdateHintWindowSize();
3281 }
3282 }
3283
3284
3285
3286 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
3287 {
3288 // if we've just removed the last tab from the source
3289 // tab set, the remove the tab control completely
3290 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3291 size_t i, pane_count = all_panes.GetCount();
3292 for (i = 0; i < pane_count; ++i)
3293 {
3294 if (all_panes.Item(i).name == wxT("dummy"))
3295 continue;
3296
3297 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3298 if (tabframe->m_tab_rect.Contains(pt))
3299 return tabframe->m_tabs;
3300 }
3301
3302 return NULL;
3303 }
3304
3305 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
3306 {
3307 // if we've just removed the last tab from the source
3308 // tab set, the remove the tab control completely
3309 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3310 size_t i, pane_count = all_panes.GetCount();
3311 for (i = 0; i < pane_count; ++i)
3312 {
3313 if (all_panes.Item(i).name == wxT("dummy"))
3314 continue;
3315
3316 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3317 if (tabframe->m_tabs == tab_ctrl)
3318 {
3319 return tabframe;
3320 }
3321 }
3322
3323 return NULL;
3324 }
3325
3326 void wxAuiNotebook::RemoveEmptyTabFrames()
3327 {
3328 // if we've just removed the last tab from the source
3329 // tab set, the remove the tab control completely
3330 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
3331 size_t i, pane_count = all_panes.GetCount();
3332 for (i = 0; i < pane_count; ++i)
3333 {
3334 if (all_panes.Item(i).name == wxT("dummy"))
3335 continue;
3336
3337 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
3338 if (tab_frame->m_tabs->GetPageCount() == 0)
3339 {
3340 m_mgr.DetachPane(tab_frame);
3341
3342 // use pending delete because sometimes during
3343 // window closing, refreshs are pending
3344 if (!wxPendingDelete.Member(tab_frame->m_tabs))
3345 wxPendingDelete.Append(tab_frame->m_tabs);
3346 //tab_frame->m_tabs->Destroy();
3347
3348 delete tab_frame;
3349 }
3350 }
3351
3352
3353 // check to see if there is still a center pane;
3354 // if there isn't, make a frame the center pane
3355 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
3356 pane_count = panes.GetCount();
3357 wxWindow* first_good = NULL;
3358 bool center_found = false;
3359 for (i = 0; i < pane_count; ++i)
3360 {
3361 if (panes.Item(i).name == wxT("dummy"))
3362 continue;
3363 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
3364 center_found = true;
3365 if (!first_good)
3366 first_good = panes.Item(i).window;
3367 }
3368
3369 if (!center_found && first_good)
3370 {
3371 m_mgr.GetPane(first_good).Centre();
3372 }
3373
3374 m_mgr.Update();
3375 }
3376
3377 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
3378 {
3379 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
3380 if (idx != -1 && idx != m_curpage)
3381 {
3382 SetSelection(idx);
3383 }
3384 }
3385
3386
3387 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
3388 {
3389 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3390 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3391
3392 int button_id = evt.GetInt();
3393
3394 if (button_id == wxAUI_BUTTON_CLOSE)
3395 {
3396 int selection = tabs->GetActivePage();
3397
3398 if (selection != -1)
3399 {
3400 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3401
3402
3403 // ask owner if it's ok to close the tab
3404 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3405 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3406 e.SetOldSelection(evt.GetSelection());
3407 e.SetEventObject(this);
3408 GetEventHandler()->ProcessEvent(e);
3409 if (!e.IsAllowed())
3410 return;
3411
3412
3413 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3414 {
3415 close_wnd->Close();
3416 }
3417 else
3418 {
3419 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3420 DeletePage(main_idx);
3421 }
3422 }
3423 }
3424 }
3425
3426
3427
3428
3429 #endif // wxUSE_AUI