added middle-click close to wxAuiNotebook
[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 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
2071 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2072 evt.SetOldSelection(evt.GetSelection());
2073 evt.SetEventObject(this);
2074 GetEventHandler()->ProcessEvent(evt);
2075 return;
2076 }
2077
2078 if (m_pressed_button)
2079 {
2080 // make sure we're still clicking the button
2081 wxAuiTabContainerButton* button = NULL;
2082 if (!ButtonHitTest(evt.m_x, evt.m_y, &button))
2083 return;
2084
2085 if (button != m_pressed_button)
2086 {
2087 m_pressed_button = NULL;
2088 return;
2089 }
2090
2091 Refresh();
2092 Update();
2093
2094 if (!(m_pressed_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
2095 {
2096 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
2097 evt.SetInt(m_pressed_button->id);
2098 evt.SetEventObject(this);
2099 GetEventHandler()->ProcessEvent(evt);
2100 }
2101
2102 m_pressed_button = NULL;
2103 }
2104
2105 m_click_pt = wxDefaultPosition;
2106 m_is_dragging = false;
2107 m_click_tab = NULL;
2108 }
2109
2110 void wxAuiTabCtrl::OnMiddleUp(wxMouseEvent& evt)
2111 {
2112 wxWindow* wnd = NULL;
2113 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2114 return;
2115
2116 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
2117 e.SetEventObject(this);
2118 e.SetSelection(GetIdxFromWindow(wnd));
2119 GetEventHandler()->ProcessEvent(e);
2120 }
2121
2122 void wxAuiTabCtrl::OnMiddleDown(wxMouseEvent& evt)
2123 {
2124 wxWindow* wnd = NULL;
2125 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2126 return;
2127
2128 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
2129 e.SetEventObject(this);
2130 e.SetSelection(GetIdxFromWindow(wnd));
2131 GetEventHandler()->ProcessEvent(e);
2132 }
2133
2134 void wxAuiTabCtrl::OnRightUp(wxMouseEvent& evt)
2135 {
2136 wxWindow* wnd = NULL;
2137 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2138 return;
2139
2140 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
2141 e.SetEventObject(this);
2142 e.SetSelection(GetIdxFromWindow(wnd));
2143 GetEventHandler()->ProcessEvent(e);
2144 }
2145
2146 void wxAuiTabCtrl::OnRightDown(wxMouseEvent& evt)
2147 {
2148 wxWindow* wnd = NULL;
2149 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
2150 return;
2151
2152 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
2153 e.SetEventObject(this);
2154 e.SetSelection(GetIdxFromWindow(wnd));
2155 GetEventHandler()->ProcessEvent(e);
2156 }
2157
2158 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
2159 {
2160 wxPoint pos = evt.GetPosition();
2161
2162 // check if the mouse is hovering above a button
2163 wxAuiTabContainerButton* button;
2164 if (ButtonHitTest(pos.x, pos.y, &button))
2165 {
2166 if (m_hover_button && button != m_hover_button)
2167 {
2168 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2169 m_hover_button = NULL;
2170 Refresh();
2171 Update();
2172 }
2173
2174 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
2175 {
2176 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
2177 Refresh();
2178 Update();
2179 m_hover_button = button;
2180 return;
2181 }
2182 }
2183 else
2184 {
2185 if (m_hover_button)
2186 {
2187 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2188 m_hover_button = NULL;
2189 Refresh();
2190 Update();
2191 }
2192 }
2193
2194
2195 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
2196 return;
2197
2198 if (m_is_dragging)
2199 {
2200 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
2201 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2202 evt.SetOldSelection(evt.GetSelection());
2203 evt.SetEventObject(this);
2204 GetEventHandler()->ProcessEvent(evt);
2205 return;
2206 }
2207
2208
2209 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
2210 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
2211
2212 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
2213 abs(pos.y - m_click_pt.y) > drag_y_threshold)
2214 {
2215 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
2216 evt.SetSelection(GetIdxFromWindow(m_click_tab));
2217 evt.SetOldSelection(evt.GetSelection());
2218 evt.SetEventObject(this);
2219 GetEventHandler()->ProcessEvent(evt);
2220
2221 m_is_dragging = true;
2222 }
2223 }
2224
2225 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
2226 {
2227 if (m_hover_button)
2228 {
2229 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
2230 m_hover_button = NULL;
2231 Refresh();
2232 Update();
2233 }
2234 }
2235
2236 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
2237 {
2238 int button = event.GetInt();
2239
2240 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
2241 {
2242 if (button == wxAUI_BUTTON_LEFT)
2243 {
2244 if (GetTabOffset() > 0)
2245 {
2246 SetTabOffset(GetTabOffset()-1);
2247 Refresh();
2248 Update();
2249 }
2250 }
2251 else
2252 {
2253 SetTabOffset(GetTabOffset()+1);
2254 Refresh();
2255 Update();
2256 }
2257 }
2258 else if (button == wxAUI_BUTTON_WINDOWLIST)
2259 {
2260 int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage());
2261
2262 if (idx != -1)
2263 {
2264 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2265 e.SetSelection(idx);
2266 e.SetOldSelection(GetActivePage());
2267 e.SetEventObject(this);
2268 GetEventHandler()->ProcessEvent(e);
2269 }
2270 }
2271 else
2272 {
2273 event.Skip();
2274 }
2275 }
2276
2277 // wxTabFrame is an interesting case. It's important that all child pages
2278 // of the multi-notebook control are all actually children of that control
2279 // (and not grandchildren). wxTabFrame facilitates this. There is one
2280 // instance of wxTabFrame for each tab control inside the multi-notebook.
2281 // It's important to know that wxTabFrame is not a real window, but it merely
2282 // used to capture the dimensions/positioning of the internal tab control and
2283 // it's managed page windows
2284
2285 class wxTabFrame : public wxWindow
2286 {
2287 public:
2288
2289 wxTabFrame()
2290 {
2291 m_tabs = NULL;
2292 m_rect = wxRect(0,0,200,200);
2293 m_tab_ctrl_height = 20;
2294 }
2295
2296 ~wxTabFrame()
2297 {
2298 wxDELETE(m_tabs);
2299 }
2300
2301 void SetTabCtrlHeight(int h)
2302 {
2303 m_tab_ctrl_height = h;
2304 }
2305
2306 void DoSetSize(int x, int y,
2307 int width, int height,
2308 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
2309 {
2310 m_rect = wxRect(x, y, width, height);
2311 DoSizing();
2312 }
2313
2314 void DoGetClientSize(int* x, int* y) const
2315 {
2316 *x = m_rect.width;
2317 *y = m_rect.height;
2318 }
2319
2320 bool Show( bool WXUNUSED(show = true) ) { return false; }
2321
2322 void DoSizing()
2323 {
2324 if (!m_tabs)
2325 return;
2326
2327 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2328 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2329 m_tabs->SetRect(wxRect(0, 0, m_rect.width, m_tab_ctrl_height));
2330 m_tabs->Refresh();
2331 m_tabs->Update();
2332
2333 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
2334 size_t i, page_count = pages.GetCount();
2335
2336 for (i = 0; i < page_count; ++i)
2337 {
2338 wxAuiNotebookPage& page = pages.Item(i);
2339 page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height,
2340 m_rect.width, m_rect.height - m_tab_ctrl_height);
2341
2342 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2343 {
2344 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
2345 wnd->ApplyMDIChildFrameRect();
2346 }
2347 }
2348 }
2349
2350 void DoGetSize(int* x, int* y) const
2351 {
2352 if (x)
2353 *x = m_rect.GetWidth();
2354 if (y)
2355 *y = m_rect.GetHeight();
2356 }
2357
2358 void Update()
2359 {
2360 // does nothing
2361 }
2362
2363 public:
2364
2365 wxRect m_rect;
2366 wxRect m_tab_rect;
2367 wxAuiTabCtrl* m_tabs;
2368 int m_tab_ctrl_height;
2369 };
2370
2371
2372 const int wxAuiBaseTabCtrlId = 5380;
2373
2374
2375 // -- wxAuiNotebook class implementation --
2376
2377 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
2378 EVT_SIZE(wxAuiNotebook::OnSize)
2379 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
2380 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2381 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
2382 wxAuiNotebook::OnTabClicked)
2383 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2384 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
2385 wxAuiNotebook::OnTabBeginDrag)
2386 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2387 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
2388 wxAuiNotebook::OnTabEndDrag)
2389 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2390 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
2391 wxAuiNotebook::OnTabDragMotion)
2392 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2393 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
2394 wxAuiNotebook::OnTabButton)
2395 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2396 wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN,
2397 wxAuiNotebook::OnTabMiddleDown)
2398 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2399 wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP,
2400 wxAuiNotebook::OnTabMiddleUp)
2401 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2402 wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN,
2403 wxAuiNotebook::OnTabRightDown)
2404 EVT_COMMAND_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
2405 wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
2406 wxAuiNotebook::OnTabRightUp)
2407 END_EVENT_TABLE()
2408
2409 wxAuiNotebook::wxAuiNotebook()
2410 {
2411 m_curpage = -1;
2412 m_tab_id_counter = wxAuiBaseTabCtrlId;
2413 m_dummy_wnd = NULL;
2414 m_tab_ctrl_height = 20;
2415 m_requested_bmp_size = wxDefaultSize;
2416 m_requested_tabctrl_height = -1;
2417 }
2418
2419 wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
2420 wxWindowID id,
2421 const wxPoint& pos,
2422 const wxSize& size,
2423 long style) : wxControl(parent, id, pos, size, style)
2424 {
2425 m_dummy_wnd = NULL;
2426 m_requested_bmp_size = wxDefaultSize;
2427 m_requested_tabctrl_height = -1;
2428 InitNotebook(style);
2429 }
2430
2431 bool wxAuiNotebook::Create(wxWindow* parent,
2432 wxWindowID id,
2433 const wxPoint& pos,
2434 const wxSize& size,
2435 long style)
2436 {
2437 if (!wxControl::Create(parent, id, pos, size, style))
2438 return false;
2439
2440 InitNotebook(style);
2441
2442 return true;
2443 }
2444
2445 // InitNotebook() contains common initialization
2446 // code called by all constructors
2447 void wxAuiNotebook::InitNotebook(long style)
2448 {
2449 m_curpage = -1;
2450 m_tab_id_counter = wxAuiBaseTabCtrlId;
2451 m_dummy_wnd = NULL;
2452 m_flags = (unsigned int)style;
2453 m_tab_ctrl_height = 20;
2454
2455 m_normal_font = *wxNORMAL_FONT;
2456 m_selected_font = *wxNORMAL_FONT;
2457 m_selected_font.SetWeight(wxBOLD);
2458
2459 SetArtProvider(new wxAuiDefaultTabArt);
2460
2461 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
2462 m_dummy_wnd->SetSize(200, 200);
2463 m_dummy_wnd->Show(false);
2464
2465 m_mgr.SetManagedWindow(this);
2466 m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
2467 m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
2468
2469 m_mgr.AddPane(m_dummy_wnd,
2470 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
2471
2472 m_mgr.Update();
2473 }
2474
2475 wxAuiNotebook::~wxAuiNotebook()
2476 {
2477 m_mgr.UnInit();
2478 }
2479
2480 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
2481 {
2482 m_tabs.SetArtProvider(art);
2483
2484 UpdateTabCtrlHeight();
2485 }
2486
2487 // SetTabCtrlHeight() is the highest-level override of the
2488 // tab height. A call to this function effectively enforces a
2489 // specified tab ctrl height, overriding all other considerations,
2490 // such as text or bitmap height. It overrides any call to
2491 // SetUniformBitmapSize(). Specifying a height of -1 reverts
2492 // any previous call and returns to the default behavior
2493
2494 void wxAuiNotebook::SetTabCtrlHeight(int height)
2495 {
2496 m_requested_tabctrl_height = height;
2497
2498 // if window is already initialized, recalculate the tab height
2499 if (m_dummy_wnd)
2500 {
2501 UpdateTabCtrlHeight();
2502 }
2503 }
2504
2505
2506 // SetUniformBitmapSize() ensures that all tabs will have
2507 // the same height, even if some tabs don't have bitmaps
2508 // Passing wxDefaultSize to this function will instruct
2509 // the control to use dynamic tab height-- so when a tab
2510 // with a large bitmap is added, the tab ctrl's height will
2511 // automatically increase to accommodate the bitmap
2512
2513 void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
2514 {
2515 m_requested_bmp_size = size;
2516
2517 // if window is already initialized, recalculate the tab height
2518 if (m_dummy_wnd)
2519 {
2520 UpdateTabCtrlHeight();
2521 }
2522 }
2523
2524 // UpdateTabCtrlHeight() does the actual tab resizing. It's meant
2525 // to be used interally
2526 void wxAuiNotebook::UpdateTabCtrlHeight()
2527 {
2528 // get the tab ctrl height we will use
2529 int height = CalculateTabCtrlHeight();
2530
2531 // if the tab control height needs to change, update
2532 // all of our tab controls with the new height
2533 if (m_tab_ctrl_height != height)
2534 {
2535 wxAuiTabArt* art = m_tabs.GetArtProvider();
2536
2537 m_tab_ctrl_height = height;
2538
2539 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2540 size_t i, pane_count = all_panes.GetCount();
2541 for (i = 0; i < pane_count; ++i)
2542 {
2543 wxAuiPaneInfo& pane = all_panes.Item(i);
2544 if (pane.name == wxT("dummy"))
2545 continue;
2546 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
2547 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
2548 tab_frame->SetTabCtrlHeight(m_tab_ctrl_height);
2549 tabctrl->SetArtProvider(art->Clone());
2550 tab_frame->DoSizing();
2551 }
2552 }
2553 }
2554
2555 void wxAuiNotebook::UpdateHintWindowSize()
2556 {
2557 wxSize size = CalculateNewSplitSize();
2558
2559 // the placeholder hint window should be set to this size
2560 wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
2561 if (info.IsOk())
2562 {
2563 info.MinSize(size);
2564 info.BestSize(size);
2565 m_dummy_wnd->SetSize(size);
2566 }
2567 }
2568
2569
2570 // calculates the size of the new split
2571 wxSize wxAuiNotebook::CalculateNewSplitSize()
2572 {
2573 // count number of tab controls
2574 int tab_ctrl_count = 0;
2575 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2576 size_t i, pane_count = all_panes.GetCount();
2577 for (i = 0; i < pane_count; ++i)
2578 {
2579 wxAuiPaneInfo& pane = all_panes.Item(i);
2580 if (pane.name == wxT("dummy"))
2581 continue;
2582 tab_ctrl_count++;
2583 }
2584
2585 wxSize new_split_size;
2586
2587 // if there is only one tab control, the first split
2588 // should happen around the middle
2589 if (tab_ctrl_count < 2)
2590 {
2591 new_split_size = GetClientSize();
2592 new_split_size.x /= 2;
2593 new_split_size.y /= 2;
2594 }
2595 else
2596 {
2597 // this is in place of a more complicated calculation
2598 // that needs to be implemented
2599 new_split_size = wxSize(180,180);
2600 }
2601
2602 return new_split_size;
2603 }
2604
2605 int wxAuiNotebook::CalculateTabCtrlHeight()
2606 {
2607 // if a fixed tab ctrl height is specified,
2608 // just return that instead of calculating a
2609 // tab height
2610 if (m_requested_tabctrl_height != -1)
2611 return m_requested_tabctrl_height;
2612
2613 // find out new best tab height
2614 wxAuiTabArt* art = m_tabs.GetArtProvider();
2615
2616 return art->GetBestTabCtrlSize(this,
2617 m_tabs.GetPages(),
2618 m_requested_bmp_size);
2619 }
2620
2621
2622 wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
2623 {
2624 return m_tabs.GetArtProvider();
2625 }
2626
2627 void wxAuiNotebook::SetWindowStyleFlag(long style)
2628 {
2629 wxControl::SetWindowStyleFlag(style);
2630
2631 m_flags = (unsigned int)style;
2632
2633 // if the control is already initialized
2634 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
2635 {
2636 // let all of the tab children know about the new style
2637
2638 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2639 size_t i, pane_count = all_panes.GetCount();
2640 for (i = 0; i < pane_count; ++i)
2641 {
2642 wxAuiPaneInfo& pane = all_panes.Item(i);
2643 if (pane.name == wxT("dummy"))
2644 continue;
2645 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
2646 wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
2647 tabctrl->SetFlags(m_flags);
2648 tabframe->DoSizing();
2649 tabctrl->Refresh();
2650 tabctrl->Update();
2651 }
2652 }
2653 }
2654
2655
2656 bool wxAuiNotebook::AddPage(wxWindow* page,
2657 const wxString& caption,
2658 bool select,
2659 const wxBitmap& bitmap)
2660 {
2661 return InsertPage(GetPageCount(), page, caption, select, bitmap);
2662 }
2663
2664 bool wxAuiNotebook::InsertPage(size_t page_idx,
2665 wxWindow* page,
2666 const wxString& caption,
2667 bool select,
2668 const wxBitmap& bitmap)
2669 {
2670 wxAuiNotebookPage info;
2671 info.window = page;
2672 info.caption = caption;
2673 info.bitmap = bitmap;
2674 info.active = false;
2675
2676 // if there are currently no tabs, the first added
2677 // tab must be active
2678 if (m_tabs.GetPageCount() == 0)
2679 info.active = true;
2680
2681 m_tabs.InsertPage(page, info, page_idx);
2682
2683 // if that was the first page added, even if
2684 // select is false, it must become the "current page"
2685 // (though no select events will be fired)
2686 if (!select && m_tabs.GetPageCount() == 1)
2687 select = true;
2688 //m_curpage = GetPageIndex(page);
2689
2690 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
2691 if (page_idx >= active_tabctrl->GetPageCount())
2692 active_tabctrl->AddPage(page, info);
2693 else
2694 active_tabctrl->InsertPage(page, info, page_idx);
2695
2696 UpdateTabCtrlHeight();
2697 DoSizing();
2698 active_tabctrl->DoShowHide();
2699
2700 if (select)
2701 {
2702 SetSelectionToWindow(page);
2703 }
2704
2705 return true;
2706 }
2707
2708
2709 // DeletePage() removes a tab from the multi-notebook,
2710 // and destroys the window as well
2711 bool wxAuiNotebook::DeletePage(size_t page_idx)
2712 {
2713 if (page_idx >= m_tabs.GetPageCount())
2714 return false;
2715
2716 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2717
2718 // hide the window in advance, as this will
2719 // prevent flicker
2720 ShowWnd(wnd, false);
2721
2722 if (!RemovePage(page_idx))
2723 return false;
2724
2725 // actually destroy the window now
2726 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2727 {
2728 // delete the child frame with pending delete, as is
2729 // customary with frame windows
2730 if (!wxPendingDelete.Member(wnd))
2731 wxPendingDelete.Append(wnd);
2732 }
2733 else
2734 {
2735 wnd->Destroy();
2736 }
2737
2738 return true;
2739 }
2740
2741
2742
2743 // RemovePage() removes a tab from the multi-notebook,
2744 // but does not destroy the window
2745 bool wxAuiNotebook::RemovePage(size_t page_idx)
2746 {
2747 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2748 wxWindow* new_active = NULL;
2749
2750 // make sure we found the page
2751 if (!wnd)
2752 return false;
2753
2754 // find out which onscreen tab ctrl owns this tab
2755 wxAuiTabCtrl* ctrl;
2756 int ctrl_idx;
2757 if (!FindTab(wnd, &ctrl, &ctrl_idx))
2758 return false;
2759
2760 bool is_curpage = (m_curpage == (int)page_idx);
2761 bool is_active_in_split = ctrl->GetPage(ctrl_idx).active;
2762
2763
2764 // remove the tab from main catalog
2765 if (!m_tabs.RemovePage(wnd))
2766 return false;
2767
2768 // remove the tab from the onscreen tab ctrl
2769 ctrl->RemovePage(wnd);
2770
2771 if (is_active_in_split)
2772 {
2773 int ctrl_new_page_count = (int)ctrl->GetPageCount();
2774
2775 if (ctrl_idx >= ctrl_new_page_count)
2776 ctrl_idx = ctrl_new_page_count-1;
2777
2778 if (ctrl_idx >= 0 && ctrl_idx < (int)ctrl->GetPageCount())
2779 {
2780 // set new page as active in the tab split
2781 ctrl->SetActivePage(ctrl_idx);
2782
2783 // if the page deleted was the current page for the
2784 // entire tab control, then record the window
2785 // pointer of the new active page for activation
2786 if (is_curpage)
2787 {
2788 new_active = ctrl->GetWindowFromIdx(ctrl_idx);
2789 }
2790 }
2791 }
2792
2793
2794 if (!new_active)
2795 {
2796 // we haven't yet found a new page to active,
2797 // so select the next page from the main tab
2798 // catalogue
2799
2800 if (page_idx < m_tabs.GetPageCount())
2801 {
2802 new_active = m_tabs.GetPage(page_idx).window;
2803 }
2804
2805 if (!new_active && m_tabs.GetPageCount() > 0)
2806 {
2807 new_active = m_tabs.GetPage(0).window;
2808 }
2809 }
2810
2811
2812 RemoveEmptyTabFrames();
2813
2814 // set new active pane
2815 if (new_active)
2816 {
2817 m_curpage = -1;
2818 SetSelectionToWindow(new_active);
2819 }
2820
2821 return true;
2822 }
2823
2824 // GetPageIndex() returns the index of the page, or -1 if the
2825 // page could not be located in the notebook
2826 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2827 {
2828 return m_tabs.GetIdxFromWindow(page_wnd);
2829 }
2830
2831
2832
2833 // SetPageText() changes the tab caption of the specified page
2834 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2835 {
2836 if (page_idx >= m_tabs.GetPageCount())
2837 return false;
2838
2839 // update our own tab catalog
2840 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2841 page_info.caption = text;
2842
2843 // update what's on screen
2844 wxAuiTabCtrl* ctrl;
2845 int ctrl_idx;
2846 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2847 {
2848 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2849 info.caption = text;
2850 ctrl->Refresh();
2851 ctrl->Update();
2852 }
2853
2854 return true;
2855 }
2856
2857 // returns the page caption
2858 wxString wxAuiNotebook::GetPageText(size_t page_idx) const
2859 {
2860 if (page_idx >= m_tabs.GetPageCount())
2861 return wxEmptyString;
2862
2863 // update our own tab catalog
2864 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2865 return page_info.caption;
2866 }
2867
2868 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2869 {
2870 if (page_idx >= m_tabs.GetPageCount())
2871 return false;
2872
2873 // update our own tab catalog
2874 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2875 page_info.bitmap = bitmap;
2876
2877 // tab height might have changed
2878 UpdateTabCtrlHeight();
2879
2880 // update what's on screen
2881 wxAuiTabCtrl* ctrl;
2882 int ctrl_idx;
2883 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2884 {
2885 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2886 info.bitmap = bitmap;
2887 ctrl->Refresh();
2888 ctrl->Update();
2889 }
2890
2891 return true;
2892 }
2893
2894 // returns the page bitmap
2895 wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const
2896 {
2897 if (page_idx >= m_tabs.GetPageCount())
2898 return wxBitmap();
2899
2900 // update our own tab catalog
2901 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2902 return page_info.bitmap;
2903 }
2904
2905 // GetSelection() returns the index of the currently active page
2906 int wxAuiNotebook::GetSelection() const
2907 {
2908 return m_curpage;
2909 }
2910
2911 // SetSelection() sets the currently active page
2912 size_t wxAuiNotebook::SetSelection(size_t new_page)
2913 {
2914 // don't change the page unless necessary
2915 if ((int)new_page == m_curpage)
2916 return m_curpage;
2917
2918 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
2919 if (!wnd)
2920 return m_curpage;
2921
2922 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2923 evt.SetSelection(new_page);
2924 evt.SetOldSelection(m_curpage);
2925 evt.SetEventObject(this);
2926 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
2927 {
2928 int old_curpage = m_curpage;
2929 m_curpage = new_page;
2930
2931 // program allows the page change
2932 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
2933 (void)GetEventHandler()->ProcessEvent(evt);
2934
2935
2936 wxAuiTabCtrl* ctrl;
2937 int ctrl_idx;
2938 if (FindTab(wnd, &ctrl, &ctrl_idx))
2939 {
2940 m_tabs.SetActivePage(wnd);
2941
2942 ctrl->SetActivePage(ctrl_idx);
2943 DoSizing();
2944 ctrl->DoShowHide();
2945
2946
2947
2948 // set fonts
2949 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2950 size_t i, pane_count = all_panes.GetCount();
2951 for (i = 0; i < pane_count; ++i)
2952 {
2953 wxAuiPaneInfo& pane = all_panes.Item(i);
2954 if (pane.name == wxT("dummy"))
2955 continue;
2956 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2957 if (tabctrl != ctrl)
2958 tabctrl->SetSelectedFont(m_normal_font);
2959 else
2960 tabctrl->SetSelectedFont(m_selected_font);
2961 tabctrl->Refresh();
2962 }
2963
2964 wnd->SetFocus();
2965
2966 return old_curpage;
2967 }
2968 }
2969
2970 return m_curpage;
2971 }
2972
2973 void wxAuiNotebook::SetSelectionToWindow(wxWindow *win)
2974 {
2975 const int idx = m_tabs.GetIdxFromWindow(win);
2976 wxCHECK_RET( idx != wxNOT_FOUND, _T("invalid notebook page") );
2977
2978 SetSelection(idx);
2979 }
2980
2981 // GetPageCount() returns the total number of
2982 // pages managed by the multi-notebook
2983 size_t wxAuiNotebook::GetPageCount() const
2984 {
2985 return m_tabs.GetPageCount();
2986 }
2987
2988 // GetPage() returns the wxWindow pointer of the
2989 // specified page
2990 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2991 {
2992 wxASSERT(page_idx < m_tabs.GetPageCount());
2993
2994 return m_tabs.GetWindowFromIdx(page_idx);
2995 }
2996
2997 // DoSizing() performs all sizing operations in each tab control
2998 void wxAuiNotebook::DoSizing()
2999 {
3000 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3001 size_t i, pane_count = all_panes.GetCount();
3002 for (i = 0; i < pane_count; ++i)
3003 {
3004 if (all_panes.Item(i).name == wxT("dummy"))
3005 continue;
3006
3007 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3008 tabframe->DoSizing();
3009 }
3010 }
3011
3012 // GetActiveTabCtrl() returns the active tab control. It is
3013 // called to determine which control gets new windows being added
3014 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
3015 {
3016 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
3017 {
3018 wxAuiTabCtrl* ctrl;
3019 int idx;
3020
3021 // find the tab ctrl with the current page
3022 if (FindTab(m_tabs.GetPage(m_curpage).window,
3023 &ctrl, &idx))
3024 {
3025 return ctrl;
3026 }
3027 }
3028
3029 // no current page, just find the first tab ctrl
3030 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3031 size_t i, pane_count = all_panes.GetCount();
3032 for (i = 0; i < pane_count; ++i)
3033 {
3034 if (all_panes.Item(i).name == wxT("dummy"))
3035 continue;
3036
3037 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3038 return tabframe->m_tabs;
3039 }
3040
3041 // If there is no tabframe at all, create one
3042 wxTabFrame* tabframe = new wxTabFrame;
3043 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
3044 tabframe->m_tabs = new wxAuiTabCtrl(this,
3045 m_tab_id_counter++,
3046 wxDefaultPosition,
3047 wxDefaultSize,
3048 wxNO_BORDER);
3049 tabframe->m_tabs->SetFlags(m_flags);
3050 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3051 m_mgr.AddPane(tabframe,
3052 wxAuiPaneInfo().Center().CaptionVisible(false));
3053
3054 m_mgr.Update();
3055
3056 return tabframe->m_tabs;
3057 }
3058
3059 // FindTab() finds the tab control that currently contains the window as well
3060 // as the index of the window in the tab control. It returns true if the
3061 // window was found, otherwise false.
3062 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
3063 {
3064 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3065 size_t i, pane_count = all_panes.GetCount();
3066 for (i = 0; i < pane_count; ++i)
3067 {
3068 if (all_panes.Item(i).name == wxT("dummy"))
3069 continue;
3070
3071 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3072
3073 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
3074 if (page_idx != -1)
3075 {
3076 *ctrl = tabframe->m_tabs;
3077 *idx = page_idx;
3078 return true;
3079 }
3080 }
3081
3082 return false;
3083 }
3084
3085 void wxAuiNotebook::Split(size_t page, int direction)
3086 {
3087 wxSize cli_size = GetClientSize();
3088
3089 // get the page's window pointer
3090 wxWindow* wnd = GetPage(page);
3091 if (!wnd)
3092 return;
3093
3094 // notebooks with 1 or less pages can't be split
3095 if (GetPageCount() < 2)
3096 return;
3097
3098 // find out which tab control the page currently belongs to
3099 wxAuiTabCtrl *src_tabs, *dest_tabs;
3100 int src_idx = -1;
3101 src_tabs = NULL;
3102 if (!FindTab(wnd, &src_tabs, &src_idx))
3103 return;
3104 if (!src_tabs || src_idx == -1)
3105 return;
3106
3107 // choose a split size
3108 wxSize split_size;
3109 if (GetPageCount() > 2)
3110 {
3111 split_size = CalculateNewSplitSize();
3112 }
3113 else
3114 {
3115 // because there are two panes, always split them
3116 // equally
3117 split_size = GetClientSize();
3118 split_size.x /= 2;
3119 split_size.y /= 2;
3120 }
3121
3122
3123 // create a new tab frame
3124 wxTabFrame* new_tabs = new wxTabFrame;
3125 new_tabs->m_rect = wxRect(wxPoint(0,0), split_size);
3126 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3127 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3128 m_tab_id_counter++,
3129 wxDefaultPosition,
3130 wxDefaultSize,
3131 wxNO_BORDER);
3132 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3133 new_tabs->m_tabs->SetFlags(m_flags);
3134 dest_tabs = new_tabs->m_tabs;
3135
3136 // create a pane info structure with the information
3137 // about where the pane should be added
3138 wxAuiPaneInfo pane_info = wxAuiPaneInfo().Bottom().CaptionVisible(false);
3139 wxPoint mouse_pt;
3140
3141 if (direction == wxLEFT)
3142 {
3143 pane_info.Left();
3144 mouse_pt = wxPoint(0, cli_size.y/2);
3145 }
3146 else if (direction == wxRIGHT)
3147 {
3148 pane_info.Right();
3149 mouse_pt = wxPoint(cli_size.x, cli_size.y/2);
3150 }
3151 else if (direction == wxTOP)
3152 {
3153 pane_info.Top();
3154 mouse_pt = wxPoint(cli_size.x/2, 0);
3155 }
3156 else if (direction == wxBOTTOM)
3157 {
3158 pane_info.Bottom();
3159 mouse_pt = wxPoint(cli_size.x/2, cli_size.y);
3160 }
3161
3162 m_mgr.AddPane(new_tabs, pane_info, mouse_pt);
3163 m_mgr.Update();
3164
3165 // remove the page from the source tabs
3166 wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx);
3167 page_info.active = false;
3168 src_tabs->RemovePage(page_info.window);
3169 if (src_tabs->GetPageCount() > 0)
3170 {
3171 src_tabs->SetActivePage((size_t)0);
3172 src_tabs->DoShowHide();
3173 src_tabs->Refresh();
3174 }
3175
3176
3177 // add the page to the destination tabs
3178 dest_tabs->InsertPage(page_info.window, page_info, 0);
3179
3180 if (src_tabs->GetPageCount() == 0)
3181 {
3182 RemoveEmptyTabFrames();
3183 }
3184
3185 DoSizing();
3186 dest_tabs->DoShowHide();
3187 dest_tabs->Refresh();
3188
3189 // force the set selection function reset the selection
3190 m_curpage = -1;
3191
3192 // set the active page to the one we just split off
3193 SetSelectionToPage(page_info);
3194
3195 UpdateHintWindowSize();
3196 }
3197
3198
3199 void wxAuiNotebook::OnSize(wxSizeEvent& evt)
3200 {
3201 UpdateHintWindowSize();
3202
3203 evt.Skip();
3204 }
3205
3206 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
3207 {
3208 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3209
3210 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
3211 wxASSERT(ctrl != NULL);
3212
3213 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
3214 wxASSERT(wnd != NULL);
3215
3216 SetSelectionToWindow(wnd);
3217 }
3218
3219 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
3220 {
3221 m_last_drag_x = 0;
3222 }
3223
3224 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
3225 {
3226 wxPoint screen_pt = ::wxGetMousePosition();
3227 wxPoint client_pt = ScreenToClient(screen_pt);
3228 wxPoint zero(0,0);
3229
3230 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3231 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
3232
3233 if (dest_tabs == src_tabs)
3234 {
3235 if (src_tabs)
3236 {
3237 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3238 }
3239
3240 // always hide the hint for inner-tabctrl drag
3241 m_mgr.HideHint();
3242
3243 // if tab moving is not allowed, leave
3244 if (!(m_flags & wxAUI_NB_TAB_MOVE))
3245 {
3246 return;
3247 }
3248
3249 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
3250 wxWindow* dest_location_tab;
3251
3252 // this is an inner-tab drag/reposition
3253 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
3254 {
3255 int src_idx = evt.GetSelection();
3256 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
3257
3258 // prevent jumpy drag
3259 if ((src_idx == dest_idx) || dest_idx == -1 ||
3260 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
3261 (src_idx < dest_idx && m_last_drag_x >= pt.x))
3262 {
3263 m_last_drag_x = pt.x;
3264 return;
3265 }
3266
3267
3268 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
3269 dest_tabs->MovePage(src_tab, dest_idx);
3270 dest_tabs->SetActivePage((size_t)dest_idx);
3271 dest_tabs->DoShowHide();
3272 dest_tabs->Refresh();
3273 m_last_drag_x = pt.x;
3274
3275 }
3276
3277 return;
3278 }
3279
3280
3281 // if external drag is allowed, check if the tab is being dragged
3282 // over a different wxAuiNotebook control
3283 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3284 {
3285 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
3286
3287 // if we aren't over any window, stop here
3288 if (!tab_ctrl)
3289 return;
3290
3291 // make sure we are not over the hint window
3292 if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
3293 {
3294 while (tab_ctrl)
3295 {
3296 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3297 break;
3298 tab_ctrl = tab_ctrl->GetParent();
3299 }
3300
3301 if (tab_ctrl)
3302 {
3303 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3304
3305 if (nb != this)
3306 {
3307 wxRect hint_rect = tab_ctrl->GetClientRect();
3308 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
3309 m_mgr.ShowHint(hint_rect);
3310 return;
3311 }
3312 }
3313 }
3314 else
3315 {
3316 if (!dest_tabs)
3317 {
3318 // we are either over a hint window, or not over a tab
3319 // window, and there is no where to drag to, so exit
3320 return;
3321 }
3322 }
3323 }
3324
3325
3326 // if there are less than two panes, split can't happen, so leave
3327 if (m_tabs.GetPageCount() < 2)
3328 return;
3329
3330 // if tab moving is not allowed, leave
3331 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
3332 return;
3333
3334
3335 if (src_tabs)
3336 {
3337 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
3338 }
3339
3340
3341 if (dest_tabs)
3342 {
3343 wxRect hint_rect = dest_tabs->GetRect();
3344 ClientToScreen(&hint_rect.x, &hint_rect.y);
3345 m_mgr.ShowHint(hint_rect);
3346 }
3347 else
3348 {
3349 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
3350 }
3351 }
3352
3353
3354
3355 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
3356 {
3357 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3358
3359 m_mgr.HideHint();
3360
3361
3362 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3363 wxCHECK_RET( src_tabs, _T("no source object?") );
3364
3365 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
3366
3367 // get the mouse position, which will be used to determine the drop point
3368 wxPoint mouse_screen_pt = ::wxGetMousePosition();
3369 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
3370
3371
3372
3373 // check for an external move
3374 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
3375 {
3376 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
3377
3378 while (tab_ctrl)
3379 {
3380 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
3381 break;
3382 tab_ctrl = tab_ctrl->GetParent();
3383 }
3384
3385 if (tab_ctrl)
3386 {
3387 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
3388
3389 if (nb != this)
3390 {
3391 // find out from the destination control
3392 // if it's ok to drop this tab here
3393 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
3394 e.SetSelection(evt.GetSelection());
3395 e.SetOldSelection(evt.GetSelection());
3396 e.SetEventObject(this);
3397 e.SetDragSource(this);
3398 e.Veto(); // dropping must be explicitly approved by control owner
3399
3400 nb->GetEventHandler()->ProcessEvent(e);
3401
3402 if (!e.IsAllowed())
3403 {
3404 // no answer or negative answer
3405 m_mgr.HideHint();
3406 return;
3407 }
3408
3409 // drop was allowed
3410 int src_idx = evt.GetSelection();
3411 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
3412
3413 // get main index of the page
3414 int main_idx = m_tabs.GetIdxFromWindow(src_page);
3415 wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no source page?") );
3416
3417
3418 // make a copy of the page info
3419 wxAuiNotebookPage page_info = m_tabs.GetPage(main_idx);
3420
3421 // remove the page from the source notebook
3422 RemovePage(main_idx);
3423
3424 // reparent the page
3425 src_page->Reparent(nb);
3426
3427
3428 // found out the insert idx
3429 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
3430 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3431
3432 wxWindow* target = NULL;
3433 int insert_idx = -1;
3434 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3435 if (target)
3436 {
3437 insert_idx = dest_tabs->GetIdxFromWindow(target);
3438 }
3439
3440
3441 // add the page to the new notebook
3442 if (insert_idx == -1)
3443 insert_idx = dest_tabs->GetPageCount();
3444 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3445 nb->m_tabs.AddPage(page_info.window, page_info);
3446
3447 nb->DoSizing();
3448 dest_tabs->DoShowHide();
3449 dest_tabs->Refresh();
3450
3451 // set the selection in the destination tab control
3452 nb->SetSelectionToPage(page_info);
3453
3454 return;
3455 }
3456 }
3457 }
3458
3459
3460
3461
3462 // only perform a tab split if it's allowed
3463 wxAuiTabCtrl* dest_tabs = NULL;
3464
3465 if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
3466 {
3467 // If the pointer is in an existing tab frame, do a tab insert
3468 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
3469 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
3470 int insert_idx = -1;
3471 if (tab_frame)
3472 {
3473 dest_tabs = tab_frame->m_tabs;
3474
3475 if (dest_tabs == src_tabs)
3476 return;
3477
3478
3479 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3480 wxWindow* target = NULL;
3481 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3482 if (target)
3483 {
3484 insert_idx = dest_tabs->GetIdxFromWindow(target);
3485 }
3486 }
3487 else
3488 {
3489 wxPoint zero(0,0);
3490 wxRect rect = m_mgr.CalculateHintRect(m_dummy_wnd,
3491 mouse_client_pt,
3492 zero);
3493 if (rect.IsEmpty())
3494 {
3495 // there is no suitable drop location here, exit out
3496 return;
3497 }
3498
3499 // If there is no tabframe at all, create one
3500 wxTabFrame* new_tabs = new wxTabFrame;
3501 new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
3502 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3503 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3504 m_tab_id_counter++,
3505 wxDefaultPosition,
3506 wxDefaultSize,
3507 wxNO_BORDER);
3508 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3509 new_tabs->m_tabs->SetFlags(m_flags);
3510
3511 m_mgr.AddPane(new_tabs,
3512 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3513 mouse_client_pt);
3514 m_mgr.Update();
3515 dest_tabs = new_tabs->m_tabs;
3516 }
3517
3518
3519
3520 // remove the page from the source tabs
3521 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
3522 page_info.active = false;
3523 src_tabs->RemovePage(page_info.window);
3524 if (src_tabs->GetPageCount() > 0)
3525 {
3526 src_tabs->SetActivePage((size_t)0);
3527 src_tabs->DoShowHide();
3528 src_tabs->Refresh();
3529 }
3530
3531
3532
3533 // add the page to the destination tabs
3534 if (insert_idx == -1)
3535 insert_idx = dest_tabs->GetPageCount();
3536 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3537
3538 if (src_tabs->GetPageCount() == 0)
3539 {
3540 RemoveEmptyTabFrames();
3541 }
3542
3543 DoSizing();
3544 dest_tabs->DoShowHide();
3545 dest_tabs->Refresh();
3546
3547 // force the set selection function reset the selection
3548 m_curpage = -1;
3549
3550 // set the active page to the one we just split off
3551 SetSelectionToPage(page_info);
3552
3553 UpdateHintWindowSize();
3554 }
3555 }
3556
3557
3558
3559 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
3560 {
3561 // if we've just removed the last tab from the source
3562 // tab set, the remove the tab control completely
3563 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3564 size_t i, pane_count = all_panes.GetCount();
3565 for (i = 0; i < pane_count; ++i)
3566 {
3567 if (all_panes.Item(i).name == wxT("dummy"))
3568 continue;
3569
3570 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3571 if (tabframe->m_tab_rect.Contains(pt))
3572 return tabframe->m_tabs;
3573 }
3574
3575 return NULL;
3576 }
3577
3578 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
3579 {
3580 // if we've just removed the last tab from the source
3581 // tab set, the remove the tab control completely
3582 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3583 size_t i, pane_count = all_panes.GetCount();
3584 for (i = 0; i < pane_count; ++i)
3585 {
3586 if (all_panes.Item(i).name == wxT("dummy"))
3587 continue;
3588
3589 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3590 if (tabframe->m_tabs == tab_ctrl)
3591 {
3592 return tabframe;
3593 }
3594 }
3595
3596 return NULL;
3597 }
3598
3599 void wxAuiNotebook::RemoveEmptyTabFrames()
3600 {
3601 // if we've just removed the last tab from the source
3602 // tab set, the remove the tab control completely
3603 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
3604 size_t i, pane_count = all_panes.GetCount();
3605 for (i = 0; i < pane_count; ++i)
3606 {
3607 if (all_panes.Item(i).name == wxT("dummy"))
3608 continue;
3609
3610 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
3611 if (tab_frame->m_tabs->GetPageCount() == 0)
3612 {
3613 m_mgr.DetachPane(tab_frame);
3614
3615 // use pending delete because sometimes during
3616 // window closing, refreshs are pending
3617 if (!wxPendingDelete.Member(tab_frame->m_tabs))
3618 wxPendingDelete.Append(tab_frame->m_tabs);
3619
3620 tab_frame->m_tabs = NULL;
3621
3622 delete tab_frame;
3623 }
3624 }
3625
3626
3627 // check to see if there is still a center pane;
3628 // if there isn't, make a frame the center pane
3629 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
3630 pane_count = panes.GetCount();
3631 wxWindow* first_good = NULL;
3632 bool center_found = false;
3633 for (i = 0; i < pane_count; ++i)
3634 {
3635 if (panes.Item(i).name == wxT("dummy"))
3636 continue;
3637 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
3638 center_found = true;
3639 if (!first_good)
3640 first_good = panes.Item(i).window;
3641 }
3642
3643 if (!center_found && first_good)
3644 {
3645 m_mgr.GetPane(first_good).Centre();
3646 }
3647
3648 m_mgr.Update();
3649 }
3650
3651 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
3652 {
3653 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
3654 if (idx != -1 && idx != m_curpage)
3655 {
3656 SetSelection(idx);
3657 }
3658 }
3659
3660
3661 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
3662 {
3663 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3664 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3665
3666 int button_id = evt.GetInt();
3667
3668 if (button_id == wxAUI_BUTTON_CLOSE)
3669 {
3670 int selection = tabs->GetActivePage();
3671
3672 if (selection != -1)
3673 {
3674 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3675
3676
3677 // ask owner if it's ok to close the tab
3678 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3679 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3680 e.SetOldSelection(evt.GetSelection());
3681 e.SetEventObject(this);
3682 GetEventHandler()->ProcessEvent(e);
3683 if (!e.IsAllowed())
3684 return;
3685
3686
3687 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3688 {
3689 close_wnd->Close();
3690 }
3691 else
3692 {
3693 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3694 wxCHECK_RET( main_idx != wxNOT_FOUND, _T("no page to delete?") );
3695
3696 DeletePage(main_idx);
3697 }
3698 }
3699 }
3700 }
3701
3702
3703 void wxAuiNotebook::OnTabMiddleDown(wxCommandEvent& evt)
3704 {
3705 // patch event through to owner
3706 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3707 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3708
3709 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
3710 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3711 e.SetEventObject(this);
3712 GetEventHandler()->ProcessEvent(e);
3713 }
3714
3715 void wxAuiNotebook::OnTabMiddleUp(wxCommandEvent& evt)
3716 {
3717 // if the wxAUI_NB_MIDDLE_CLICK_CLOSE is specified, middle
3718 // click should act like a tab close action. However, first
3719 // give the owner an opportunity to handle the middle up event
3720 // for custom action
3721
3722 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3723 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3724
3725 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
3726 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3727 e.SetEventObject(this);
3728 if (GetEventHandler()->ProcessEvent(e))
3729 return;
3730 if (!e.IsAllowed())
3731 return;
3732
3733 // check if we are supposed to close on middle-up
3734 if ((m_flags & wxAUI_NB_MIDDLE_CLICK_CLOSE) == 0)
3735 return;
3736
3737 // simulate the user pressing the close button on the tab
3738 evt.SetInt(wxAUI_BUTTON_CLOSE);
3739 OnTabButton(evt);
3740 }
3741
3742 void wxAuiNotebook::OnTabRightDown(wxCommandEvent& evt)
3743 {
3744 // patch event through to owner
3745 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3746 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3747
3748 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
3749 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3750 e.SetEventObject(this);
3751 GetEventHandler()->ProcessEvent(e);
3752 }
3753
3754 void wxAuiNotebook::OnTabRightUp(wxCommandEvent& evt)
3755 {
3756 // patch event through to owner
3757 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3758 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3759
3760 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
3761 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3762 e.SetEventObject(this);
3763 GetEventHandler()->ProcessEvent(e);
3764 }
3765
3766 // Sets the normal font
3767 void wxAuiNotebook::SetNormalFont(const wxFont& font)
3768 {
3769 m_normal_font = font;
3770 GetArtProvider()->SetNormalFont(font);
3771 }
3772
3773 // Sets the selected tab font
3774 void wxAuiNotebook::SetSelectedFont(const wxFont& font)
3775 {
3776 m_selected_font = font;
3777 GetArtProvider()->SetSelectedFont(font);
3778 }
3779
3780 // Sets the measuring font
3781 void wxAuiNotebook::SetMeasuringFont(const wxFont& font)
3782 {
3783 GetArtProvider()->SetMeasuringFont(font);
3784 }
3785
3786 // Sets the tab font
3787 bool wxAuiNotebook::SetFont(const wxFont& font)
3788 {
3789 wxControl::SetFont(font);
3790
3791 wxFont normalFont(font);
3792 wxFont selectedFont(normalFont);
3793 selectedFont.SetWeight(wxBOLD);
3794
3795 SetNormalFont(normalFont);
3796 SetSelectedFont(selectedFont);
3797 SetMeasuringFont(selectedFont);
3798
3799 return true;
3800 }
3801
3802 // Gets the tab control height
3803 int wxAuiNotebook::GetTabCtrlHeight() const
3804 {
3805 return m_tab_ctrl_height;
3806 }
3807
3808 // Gets the height of the notebook for a given page height
3809 int wxAuiNotebook::GetHeightForPageHeight(int pageHeight)
3810 {
3811 UpdateTabCtrlHeight();
3812
3813 int tabCtrlHeight = GetTabCtrlHeight();
3814 int decorHeight = 2;
3815 return tabCtrlHeight + pageHeight + decorHeight;
3816 }
3817
3818
3819 #endif // wxUSE_AUI