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