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