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