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