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