]> git.saurik.com Git - wxWidgets.git/blob - src/aui/auibook.cpp
don't compile in wxCheckWin32Permission() when it's not used (as in cygwin builds...
[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_CHANGING)
39 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
43 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
44
45
46 IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
47 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
48
49
50
51
52
53 // This functions are here for this proof of concept
54 // and will be factored out later. See dockart.cpp
55 static wxColor StepColour(const wxColor& c, int percent)
56 {
57 int r = c.Red(), g = c.Green(), b = c.Blue();
58 return wxColour((unsigned char)wxMin((r*percent)/100,255),
59 (unsigned char)wxMin((g*percent)/100,255),
60 (unsigned char)wxMin((b*percent)/100,255));
61 }
62
63 // This functions are here for this proof of concept
64 // and will be factored out later. See dockart.cpp
65 static wxBitmap BitmapFromBits(const unsigned char bits[], int w, int h,
66 const wxColour& color)
67 {
68 wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage();
69 img.Replace(0,0,0,123,123,123);
70 img.Replace(255,255,255,color.Red(),color.Green(),color.Blue());
71 img.SetMaskColour(123,123,123);
72 return wxBitmap(img);
73 }
74
75 static void DrawButtonS(wxDC& dc,
76 const wxRect& _rect,
77 const wxBitmap& bmp,
78 const wxColour& bkcolour,
79 int button_state)
80 {
81 wxRect rect = _rect;
82
83 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
84 {
85 rect.x++;
86 rect.y++;
87 }
88
89 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
90 button_state == wxAUI_BUTTON_STATE_PRESSED)
91 {
92 dc.SetBrush(wxBrush(StepColour(bkcolour, 120)));
93 dc.SetPen(wxPen(StepColour(bkcolour, 70)));
94
95 // draw the background behind the button
96 dc.DrawRectangle(rect.x, rect.y, 15, 15);
97 }
98
99 // draw the button itself
100 dc.DrawBitmap(bmp, rect.x, rect.y, true);
101 }
102
103
104
105
106
107 // -- wxAuiDefaultTabArt class implementation --
108
109 wxAuiDefaultTabArt::wxAuiDefaultTabArt()
110 {
111 m_normal_font = *wxNORMAL_FONT;
112 m_selected_font = *wxNORMAL_FONT;
113 m_selected_font.SetWeight(wxBOLD);
114 m_measuring_font = m_selected_font;
115
116 wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
117
118 wxColour background_colour = StepColour(base_colour, 95);
119 wxColour normaltab_colour = base_colour;
120 wxColour selectedtab_colour = *wxWHITE;
121
122 m_bkbrush = wxBrush(background_colour);
123 m_normal_bkbrush = wxBrush(normaltab_colour);
124 m_normal_bkpen = wxPen(normaltab_colour);
125 m_selected_bkbrush = wxBrush(selectedtab_colour);
126 m_selected_bkpen = wxPen(selectedtab_colour);
127
128
129 #if defined( __WXMAC__ )
130 static unsigned char close_bits[]={
131 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
132 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
133 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
134 #elif defined( __WXGTK__)
135 static unsigned char close_bits[]={
136 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
137 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
138 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
139 #else
140 static unsigned char close_bits[]={
141 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
142 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
143 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
144 #endif
145
146 static unsigned char left_bits[] = {
147 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
148 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
150
151 static unsigned char right_bits[] = {
152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
153 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
155
156 static unsigned char list_bits[] = {
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
158 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
160
161
162 m_active_close_bmp = BitmapFromBits(close_bits, 16, 16, *wxBLACK);
163 m_disabled_close_bmp = BitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
164
165 m_active_left_bmp = BitmapFromBits(left_bits, 16, 16, *wxBLACK);
166 m_disabled_left_bmp = BitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
167
168 m_active_right_bmp = BitmapFromBits(right_bits, 16, 16, *wxBLACK);
169 m_disabled_right_bmp = BitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
170
171 m_active_windowlist_bmp = BitmapFromBits(list_bits, 16, 16, *wxBLACK);
172 m_disabled_windowlist_bmp = BitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
173
174 }
175
176 wxAuiDefaultTabArt::~wxAuiDefaultTabArt()
177 {
178 }
179
180 void wxAuiDefaultTabArt::DrawBackground(wxDC* dc,
181 wxWindow* WXUNUSED(wnd),
182 const wxRect& rect)
183 {
184 // draw background
185 dc->SetBrush(m_bkbrush);
186 dc->SetPen(*wxTRANSPARENT_PEN);
187 dc->DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
188
189 // draw base line
190 dc->SetPen(*wxGREY_PEN);
191 dc->DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
192 }
193
194
195 // DrawTab() draws an individual tab.
196 //
197 // dc - output dc
198 // in_rect - rectangle the tab should be confined to
199 // caption - tab's caption
200 // active - whether or not the tab is active
201 // out_rect - actual output rectangle
202 // x_extent - the advance x; where the next tab should start
203
204 void wxAuiDefaultTabArt::DrawTab(wxDC* dc,
205 wxWindow* wnd,
206 const wxRect& in_rect,
207 const wxString& caption_text,
208 bool active,
209 int close_button_state,
210 wxRect* out_tab_rect,
211 wxRect* out_button_rect,
212 int* x_extent)
213 {
214 wxCoord normal_textx, normal_texty;
215 wxCoord selected_textx, selected_texty;
216 wxCoord textx, texty;
217
218 // if the caption is empty, measure some temporary text
219 wxString caption = caption_text;
220 if (caption_text.empty())
221 caption = wxT("Xj");
222
223 dc->SetFont(m_selected_font);
224 dc->GetTextExtent(caption, &selected_textx, &selected_texty);
225
226 dc->SetFont(m_normal_font);
227 dc->GetTextExtent(caption, &normal_textx, &normal_texty);
228
229 // figure out the size of the tab
230 wxSize tab_size = GetTabSize(dc, wnd, caption, active, close_button_state, x_extent);
231
232 wxCoord tab_height = tab_size.y;
233 wxCoord tab_width = tab_size.x;
234 wxCoord tab_x = in_rect.x;
235 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
236
237 // select pen, brush and font for the tab to be drawn
238
239 if (active)
240 {
241 dc->SetPen(m_selected_bkpen);
242 dc->SetBrush(m_selected_bkbrush);
243 dc->SetFont(m_selected_font);
244 textx = selected_textx;
245 texty = selected_texty;
246 }
247 else
248 {
249 dc->SetPen(m_normal_bkpen);
250 dc->SetBrush(m_normal_bkbrush);
251 dc->SetFont(m_normal_font);
252 textx = normal_textx;
253 texty = normal_texty;
254 }
255
256
257 // -- draw line --
258
259 wxPoint points[7];
260 points[0].x = tab_x;
261 points[0].y = tab_y + tab_height - 1;
262 points[1].x = tab_x + tab_height - 3;
263 points[1].y = tab_y + 2;
264 points[2].x = tab_x + tab_height + 3;
265 points[2].y = tab_y;
266 points[3].x = tab_x + tab_width - 2;
267 points[3].y = tab_y;
268 points[4].x = tab_x + tab_width;
269 points[4].y = tab_y + 2;
270 points[5].x = tab_x + tab_width;
271 points[5].y = tab_y + tab_height - 1;
272 points[6] = points[0];
273
274
275 dc->DrawPolygon(6, points);
276
277 dc->SetPen(*wxGREY_PEN);
278
279 //dc->DrawLines(active ? 6 : 7, points);
280 dc->DrawLines(7, points);
281
282
283 int text_offset;
284
285 int close_button_width = 0;
286 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
287 {
288 close_button_width = m_active_close_bmp.GetWidth();
289 text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2);
290 }
291 else
292 {
293 text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2);
294 }
295
296
297 // draw tab text
298 dc->DrawText(caption,
299 text_offset,
300 (tab_y + tab_height)/2 - (texty/2) + 1);
301
302
303 // draw close button if necessary
304 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
305 {
306 wxBitmap bmp;
307 if (active)
308 bmp = m_active_close_bmp;
309 else
310 bmp = m_disabled_close_bmp;
311
312 wxRect rect(tab_x + tab_width - close_button_width - 1,
313 tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
314 close_button_width,
315 tab_height - 1);
316 DrawButtonS(*dc, rect, bmp, *wxWHITE, close_button_state);
317
318 *out_button_rect = rect;
319 }
320
321
322 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
323 }
324
325
326 wxSize wxAuiDefaultTabArt::GetTabSize(wxDC* dc,
327 wxWindow* WXUNUSED(wnd),
328 const wxString& caption,
329 bool WXUNUSED(active),
330 int close_button_state,
331 int* x_extent)
332 {
333 wxCoord measured_textx, measured_texty;
334
335 dc->SetFont(m_measuring_font);
336 dc->GetTextExtent(caption, &measured_textx, &measured_texty);
337
338 wxCoord tab_height = measured_texty + 4;
339 wxCoord tab_width = measured_textx + tab_height + 5;
340
341 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
342 tab_width += m_active_close_bmp.GetWidth();
343
344 *x_extent = tab_width - (tab_height/2) - 1;
345
346 return wxSize(tab_width, tab_height);
347 }
348
349
350 void wxAuiDefaultTabArt::DrawButton(
351 wxDC* dc,
352 wxWindow* WXUNUSED(wnd),
353 const wxRect& in_rect,
354 int bitmap_id,
355 int button_state,
356 int orientation,
357 const wxBitmap& bitmap_override,
358 wxRect* out_rect)
359 {
360 wxBitmap bmp;
361 wxRect rect;
362
363 if (bitmap_override.IsOk())
364 {
365 bmp = bitmap_override;
366 }
367 else
368 {
369 switch (bitmap_id)
370 {
371 case wxAUI_BUTTON_CLOSE:
372 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
373 bmp = m_disabled_close_bmp;
374 else
375 bmp = m_active_close_bmp;
376 break;
377 case wxAUI_BUTTON_LEFT:
378 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
379 bmp = m_disabled_left_bmp;
380 else
381 bmp = m_active_left_bmp;
382 break;
383 case wxAUI_BUTTON_RIGHT:
384 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
385 bmp = m_disabled_right_bmp;
386 else
387 bmp = m_active_right_bmp;
388 break;
389 case wxAUI_BUTTON_WINDOWLIST:
390 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
391 bmp = m_disabled_windowlist_bmp;
392 else
393 bmp = m_active_windowlist_bmp;
394 break;
395 }
396 }
397
398 if (!bmp.IsOk())
399 return;
400
401 rect = in_rect;
402
403 if (orientation == wxLEFT)
404 {
405 rect.SetX(in_rect.x);
406 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
407 rect.SetWidth(bmp.GetWidth());
408 rect.SetHeight(bmp.GetHeight());
409 }
410 else
411 {
412 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
413 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
414 bmp.GetWidth(), bmp.GetHeight());
415 }
416
417
418 DrawButtonS(*dc, rect, bmp, *wxWHITE, button_state);
419
420 *out_rect = rect;
421 }
422
423
424
425
426 // -- GUI helper classes and functions --
427
428 class wxAuiCommandCapture : public wxEvtHandler
429 {
430 public:
431
432 wxAuiCommandCapture() { m_last_id = 0; }
433 int GetCommandId() const { return m_last_id; }
434
435 bool ProcessEvent(wxEvent& evt)
436 {
437 if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
438 {
439 m_last_id = evt.GetId();
440 return true;
441 }
442
443 if (GetNextHandler())
444 return GetNextHandler()->ProcessEvent(evt);
445
446 return false;
447 }
448
449 private:
450 int m_last_id;
451 };
452
453
454
455 int wxAuiDefaultTabArt::ShowWindowList(wxWindow* wnd,
456 const wxArrayString& items,
457 int active_idx)
458 {
459 wxMenu menuPopup;
460
461 size_t i, count = items.GetCount();
462 for (i = 0; i < count; ++i)
463 {
464 menuPopup.AppendCheckItem(1000+i, items.Item(i));
465 }
466
467 if (active_idx != -1)
468 {
469 menuPopup.Check(1000+active_idx, true);
470 }
471
472 // find out where to put the popup menu of window
473 // items. Subtract 100 for now to center the menu
474 // a bit, until a better mechanism can be implemented
475 wxPoint pt = ::wxGetMousePosition();
476 pt = wnd->ScreenToClient(pt);
477 if (pt.x < 100)
478 pt.x = 0;
479 else
480 pt.x -= 100;
481
482 // find out the screen coordinate at the bottom of the tab ctrl
483 wxRect cli_rect = wnd->GetClientRect();
484 pt.y = cli_rect.y + cli_rect.height;
485
486 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
487 wnd->PushEventHandler(cc);
488 wnd->PopupMenu(&menuPopup, pt);
489 int command = cc->GetCommandId();
490 wnd->PopEventHandler(true);
491
492 if (command >= 1000)
493 return command-1000;
494
495 return -1;
496 }
497
498 int wxAuiDefaultTabArt::GetBestTabCtrlSize(wxWindow* wnd)
499 {
500 wxClientDC dc(wnd);
501 dc.SetFont(m_measuring_font);
502 int x_ext = 0;
503 wxSize s = GetTabSize(&dc,
504 wnd,
505 wxT("ABCDEFGHIj"),
506 true,
507 wxAUI_BUTTON_STATE_HIDDEN,
508 &x_ext);
509 return s.y+3;
510 }
511
512 void wxAuiDefaultTabArt::SetNormalFont(const wxFont& font)
513 {
514 m_normal_font = font;
515 }
516
517 void wxAuiDefaultTabArt::SetSelectedFont(const wxFont& font)
518 {
519 m_selected_font = font;
520 }
521
522 void wxAuiDefaultTabArt::SetMeasuringFont(const wxFont& font)
523 {
524 m_measuring_font = font;
525 }
526
527
528
529
530
531
532 // -- wxAuiTabContainer class implementation --
533
534
535 // wxAuiTabContainer is a class which contains information about each
536 // tab. It also can render an entire tab control to a specified DC.
537 // It's not a window class itself, because this code will be used by
538 // the wxFrameMananger, where it is disadvantageous to have separate
539 // windows for each tab control in the case of "docked tabs"
540
541 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
542 // which can be used as a tab control in the normal sense.
543
544
545 wxAuiTabContainer::wxAuiTabContainer()
546 {
547 m_tab_offset = 0;
548 m_flags = 0;
549 m_art = new wxAuiDefaultTabArt;
550
551 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
552 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
553 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
554 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
555 }
556
557 wxAuiTabContainer::~wxAuiTabContainer()
558 {
559 delete m_art;
560 }
561
562 void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art)
563 {
564 delete m_art;
565 m_art = art;
566 }
567
568 wxAuiTabArt* wxAuiTabContainer::GetArtProvider()
569 {
570 return m_art;
571 }
572
573 void wxAuiTabContainer::SetFlags(unsigned int flags)
574 {
575 m_flags = flags;
576
577 // check for new close button settings
578 RemoveButton(wxAUI_BUTTON_LEFT);
579 RemoveButton(wxAUI_BUTTON_RIGHT);
580 RemoveButton(wxAUI_BUTTON_WINDOWLIST);
581 RemoveButton(wxAUI_BUTTON_CLOSE);
582
583
584 if (flags & wxAUI_NB_SCROLL_BUTTONS)
585 {
586 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
587 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
588 }
589
590 if (flags & wxAUI_NB_WINDOWLIST_BUTTON)
591 {
592 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
593 }
594
595 if (flags & wxAUI_NB_CLOSE_BUTTON)
596 {
597 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
598 }
599 }
600
601 unsigned int wxAuiTabContainer::GetFlags() const
602 {
603 return m_flags;
604 }
605
606
607 void wxAuiTabContainer::SetNormalFont(const wxFont& font)
608 {
609 m_art->SetNormalFont(font);
610 }
611
612 void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
613 {
614 m_art->SetSelectedFont(font);
615 }
616
617 void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
618 {
619 m_art->SetMeasuringFont(font);
620 }
621
622 void wxAuiTabContainer::SetRect(const wxRect& rect)
623 {
624 m_rect = rect;
625 }
626
627 bool wxAuiTabContainer::AddPage(wxWindow* page,
628 const wxAuiNotebookPage& info)
629 {
630 wxAuiNotebookPage page_info;
631 page_info = info;
632 page_info.window = page;
633
634 m_pages.Add(page_info);
635
636 return true;
637 }
638
639 bool wxAuiTabContainer::InsertPage(wxWindow* page,
640 const wxAuiNotebookPage& info,
641 size_t idx)
642 {
643 wxAuiNotebookPage page_info;
644 page_info = info;
645 page_info.window = page;
646
647 if (idx >= m_pages.GetCount())
648 m_pages.Add(page_info);
649 else
650 m_pages.Insert(page_info, idx);
651
652 return true;
653 }
654
655 bool wxAuiTabContainer::MovePage(wxWindow* page,
656 size_t new_idx)
657 {
658 int idx = GetIdxFromWindow(page);
659 if (idx == -1)
660 return false;
661
662 // get page entry, make a copy of it
663 wxAuiNotebookPage p = GetPage(idx);
664
665 // remove old page entry
666 RemovePage(page);
667
668 // insert page where it should be
669 InsertPage(page, p, new_idx);
670
671 return true;
672 }
673
674 bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
675 {
676 size_t i, page_count = m_pages.GetCount();
677 for (i = 0; i < page_count; ++i)
678 {
679 wxAuiNotebookPage& page = m_pages.Item(i);
680 if (page.window == wnd)
681 {
682 m_pages.RemoveAt(i);
683 return true;
684 }
685 }
686
687 return false;
688 }
689
690 bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
691 {
692 bool found = false;
693
694 size_t i, page_count = m_pages.GetCount();
695 for (i = 0; i < page_count; ++i)
696 {
697 wxAuiNotebookPage& page = m_pages.Item(i);
698 if (page.window == wnd)
699 {
700 page.active = true;
701 found = true;
702 }
703 else
704 {
705 page.active = false;
706 }
707 }
708
709 return found;
710 }
711
712 void wxAuiTabContainer::SetNoneActive()
713 {
714 size_t i, page_count = m_pages.GetCount();
715 for (i = 0; i < page_count; ++i)
716 {
717 wxAuiNotebookPage& page = m_pages.Item(i);
718 page.active = false;
719 }
720 }
721
722 bool wxAuiTabContainer::SetActivePage(size_t page)
723 {
724 if (page >= m_pages.GetCount())
725 return false;
726
727 return SetActivePage(m_pages.Item(page).window);
728 }
729
730 int wxAuiTabContainer::GetActivePage() const
731 {
732 size_t i, page_count = m_pages.GetCount();
733 for (i = 0; i < page_count; ++i)
734 {
735 wxAuiNotebookPage& page = m_pages.Item(i);
736 if (page.active)
737 return i;
738 }
739
740 return -1;
741 }
742
743 wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
744 {
745 if (idx >= m_pages.GetCount())
746 return NULL;
747
748 return m_pages[idx].window;
749 }
750
751 int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
752 {
753 size_t i, page_count = m_pages.GetCount();
754 for (i = 0; i < page_count; ++i)
755 {
756 wxAuiNotebookPage& page = m_pages.Item(i);
757 if (page.window == wnd)
758 return i;
759 }
760 return -1;
761 }
762
763 wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
764 {
765 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
766
767 return m_pages[idx];
768 }
769
770 wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
771 {
772 return m_pages;
773 }
774
775 size_t wxAuiTabContainer::GetPageCount() const
776 {
777 return m_pages.GetCount();
778 }
779
780 void wxAuiTabContainer::AddButton(int id,
781 int location,
782 const wxBitmap& normal_bitmap,
783 const wxBitmap& disabled_bitmap)
784 {
785 wxAuiTabContainerButton button;
786 button.id = id;
787 button.bitmap = normal_bitmap;
788 button.dis_bitmap = disabled_bitmap;
789 button.location = location;
790 button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
791
792 m_buttons.Add(button);
793 }
794
795 void wxAuiTabContainer::RemoveButton(int id)
796 {
797 size_t i, button_count = m_buttons.GetCount();
798
799 for (i = 0; i < button_count; ++i)
800 {
801 if (m_buttons.Item(i).id == id)
802 {
803 m_buttons.RemoveAt(i);
804 return;
805 }
806 }
807 }
808
809
810
811 size_t wxAuiTabContainer::GetTabOffset() const
812 {
813 return m_tab_offset;
814 }
815
816 void wxAuiTabContainer::SetTabOffset(size_t offset)
817 {
818 m_tab_offset = offset;
819 }
820
821 // Render() renders the tab catalog to the specified DC
822 // It is a virtual function and can be overridden to
823 // provide custom drawing capabilities
824 void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd)
825 {
826 wxMemoryDC dc;
827 wxBitmap bmp;
828 size_t i;
829 size_t page_count = m_pages.GetCount();
830 size_t button_count = m_buttons.GetCount();
831
832 // create off-screen bitmap
833 bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
834 dc.SelectObject(bmp);
835
836
837 // find out if size of tabs is larger than can be
838 // afforded on screen
839 int total_width = 0;
840 int visible_width = 0;
841 for (i = 0; i < page_count; ++i)
842 {
843 wxAuiNotebookPage& page = m_pages.Item(i);
844
845 // determine if a close button is on this tab
846 bool close_button = false;
847 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
848 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
849 {
850 close_button = true;
851 }
852
853
854 int x_extent = 0;
855 wxSize size = m_art->GetTabSize(&dc,
856 wnd,
857 page.caption,
858 page.active,
859 close_button ?
860 wxAUI_BUTTON_STATE_NORMAL :
861 wxAUI_BUTTON_STATE_HIDDEN,
862 &x_extent);
863
864 if (i+1 < page_count)
865 total_width += x_extent;
866 else
867 total_width += size.x;
868
869 if (i >= m_tab_offset)
870 {
871 if (i+1 < page_count)
872 visible_width += x_extent;
873 else
874 visible_width += size.x;
875 }
876 }
877
878 if (total_width > m_rect.GetWidth() - 20 || m_tab_offset != 0)
879 {
880 // show left/right buttons
881 for (i = 0; i < button_count; ++i)
882 {
883 wxAuiTabContainerButton& button = m_buttons.Item(i);
884 if (button.id == wxAUI_BUTTON_LEFT ||
885 button.id == wxAUI_BUTTON_RIGHT)
886 {
887 button.cur_state &= ~wxAUI_BUTTON_STATE_HIDDEN;
888 }
889 }
890 }
891 else
892 {
893 // hide left/right buttons
894 for (i = 0; i < button_count; ++i)
895 {
896 wxAuiTabContainerButton& button = m_buttons.Item(i);
897 if (button.id == wxAUI_BUTTON_LEFT ||
898 button.id == wxAUI_BUTTON_RIGHT)
899 {
900 button.cur_state |= wxAUI_BUTTON_STATE_HIDDEN;
901 }
902 }
903 }
904
905 // determine whether left button should be enabled
906 for (i = 0; i < button_count; ++i)
907 {
908 wxAuiTabContainerButton& button = m_buttons.Item(i);
909 if (button.id == wxAUI_BUTTON_LEFT)
910 {
911 if (m_tab_offset == 0)
912 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
913 else
914 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
915 }
916 if (button.id == wxAUI_BUTTON_RIGHT)
917 {
918 if (visible_width < m_rect.GetWidth() - ((int)button_count*16))
919 button.cur_state |= wxAUI_BUTTON_STATE_DISABLED;
920 else
921 button.cur_state &= ~wxAUI_BUTTON_STATE_DISABLED;
922 }
923 }
924
925
926
927 // draw background
928 m_art->DrawBackground(&dc, wnd, m_rect);
929
930 // draw buttons
931 int left_buttons_width = 0;
932 int right_buttons_width = 0;
933
934 int offset = 0;
935
936 // draw the buttons on the right side
937 offset = m_rect.x + m_rect.width;
938 for (i = 0; i < button_count; ++i)
939 {
940 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
941
942 if (button.location != wxRIGHT)
943 continue;
944 if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
945 continue;
946
947 wxRect button_rect = m_rect;
948 button_rect.SetY(1);
949 button_rect.SetWidth(offset);
950
951 m_art->DrawButton(&dc,
952 wnd,
953 button_rect,
954 button.id,
955 button.cur_state,
956 wxRIGHT,
957 wxNullBitmap,
958 &button.rect);
959
960 offset -= button.rect.GetWidth();
961 right_buttons_width += button.rect.GetWidth();
962 }
963
964
965
966 offset = 0;
967
968 // draw the buttons on the left side
969
970 for (i = 0; i < button_count; ++i)
971 {
972 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
973
974 if (button.location != wxLEFT)
975 continue;
976 if (button.cur_state & wxAUI_BUTTON_STATE_HIDDEN)
977 continue;
978
979 wxRect button_rect(offset, 1, 1000, m_rect.height);
980
981 m_art->DrawButton(&dc,
982 wnd,
983 button_rect,
984 button.id,
985 button.cur_state,
986 wxLEFT,
987 wxNullBitmap,
988 &button.rect);
989
990 offset += button.rect.GetWidth();
991 left_buttons_width += button.rect.GetWidth();
992 }
993
994 offset = left_buttons_width;
995
996 // set a clipping region to the tabs don't draw over the buttons
997 dc.SetClippingRegion(left_buttons_width, 0,
998 m_rect.GetWidth() - right_buttons_width - left_buttons_width - 2,
999 m_rect.GetHeight());
1000
1001
1002
1003 // prepare the tab-close-button array
1004 while (m_tab_close_buttons.GetCount() < page_count)
1005 {
1006 wxAuiTabContainerButton tempbtn;
1007 tempbtn.id = wxAUI_BUTTON_CLOSE;
1008 tempbtn.location = wxCENTER;
1009 tempbtn.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1010 m_tab_close_buttons.Add(tempbtn);
1011 }
1012
1013 for (i = 0; i < m_tab_offset; ++i)
1014 {
1015 // buttons before the tab offset must be set to hidden
1016 m_tab_close_buttons.Item(i).cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1017 }
1018
1019
1020 // draw the tabs
1021
1022 size_t active = 999;
1023 int active_offset = 0;
1024
1025 int x_extent = 0;
1026 wxRect rect = m_rect;
1027 rect.y = 0;
1028 rect.width = 1000;
1029 rect.height = m_rect.height;
1030
1031 for (i = m_tab_offset; i < page_count; ++i)
1032 {
1033 wxAuiNotebookPage& page = m_pages.Item(i);
1034 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(i);
1035
1036 // determine if a close button is on this tab
1037 bool close_button = false;
1038 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1039 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1040 {
1041 close_button = true;
1042 if (tab_button.cur_state == wxAUI_BUTTON_STATE_HIDDEN)
1043 {
1044 tab_button.id = wxAUI_BUTTON_CLOSE;
1045 tab_button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
1046 tab_button.location = wxCENTER;
1047 }
1048 }
1049 else
1050 {
1051 tab_button.cur_state = wxAUI_BUTTON_STATE_HIDDEN;
1052 }
1053
1054 rect.x = offset;
1055
1056 m_art->DrawTab(&dc,
1057 wnd,
1058 rect,
1059 page.caption,
1060 page.active,
1061 tab_button.cur_state,
1062 &page.rect,
1063 &tab_button.rect,
1064 &x_extent);
1065
1066 if (page.active)
1067 {
1068 active = i;
1069 active_offset = offset;
1070 }
1071
1072 offset += x_extent;
1073 }
1074
1075 // draw the active tab again so it stands in the foreground
1076 if (active >= m_tab_offset && active < m_pages.GetCount())
1077 {
1078 wxAuiNotebookPage& page = m_pages.Item(active);
1079
1080 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(active);
1081
1082 // determine if a close button is on this tab
1083 bool close_button = false;
1084 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1085 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1086 {
1087 close_button = true;
1088 }
1089
1090 rect.x = active_offset;
1091 m_art->DrawTab(&dc,
1092 wnd,
1093 rect,
1094 page.caption,
1095 page.active,
1096 tab_button.cur_state,
1097 &page.rect,
1098 &tab_button.rect,
1099 &x_extent);
1100 }
1101
1102 dc.DestroyClippingRegion();
1103
1104 raw_dc->Blit(m_rect.x, m_rect.y,
1105 m_rect.GetWidth(), m_rect.GetHeight(),
1106 &dc, 0, 0);
1107 }
1108
1109
1110 // TabHitTest() tests if a tab was hit, passing the window pointer
1111 // back if that condition was fulfilled. The function returns
1112 // true if a tab was hit, otherwise false
1113 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
1114 {
1115 if (!m_rect.Contains(x,y))
1116 return false;
1117
1118 wxAuiTabContainerButton* btn = NULL;
1119 if (ButtonHitTest(x, y, &btn))
1120 {
1121 if (m_buttons.Index(*btn) != wxNOT_FOUND)
1122 return false;
1123 }
1124
1125 size_t i, page_count = m_pages.GetCount();
1126
1127 for (i = m_tab_offset; i < page_count; ++i)
1128 {
1129 wxAuiNotebookPage& page = m_pages.Item(i);
1130 if (page.rect.Contains(x,y))
1131 {
1132 if (hit)
1133 *hit = page.window;
1134 return true;
1135 }
1136 }
1137
1138 return false;
1139 }
1140
1141 // ButtonHitTest() tests if a button was hit. The function returns
1142 // true if a button was hit, otherwise false
1143 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
1144 wxAuiTabContainerButton** hit) const
1145 {
1146 if (!m_rect.Contains(x,y))
1147 return false;
1148
1149 size_t i, button_count;
1150
1151
1152 button_count = m_buttons.GetCount();
1153 for (i = 0; i < button_count; ++i)
1154 {
1155 wxAuiTabContainerButton& button = m_buttons.Item(i);
1156 if (button.rect.Contains(x,y))
1157 {
1158 if (hit)
1159 *hit = &button;
1160 return true;
1161 }
1162 }
1163
1164 button_count = m_tab_close_buttons.GetCount();
1165 for (i = 0; i < button_count; ++i)
1166 {
1167 wxAuiTabContainerButton& button = m_tab_close_buttons.Item(i);
1168 if (button.rect.Contains(x,y))
1169 {
1170 if (hit)
1171 *hit = &button;
1172 return true;
1173 }
1174 }
1175
1176 return false;
1177 }
1178
1179
1180
1181 // the utility function ShowWnd() is the same as show,
1182 // except it handles wxAuiMDIChildFrame windows as well,
1183 // as the Show() method on this class is "unplugged"
1184 static void ShowWnd(wxWindow* wnd, bool show)
1185 {
1186 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1187 {
1188 wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
1189 cf->DoShow(show);
1190 }
1191 else
1192 {
1193 wnd->Show(show);
1194 }
1195 }
1196
1197
1198 // DoShowHide() this function shows the active window, then
1199 // hides all of the other windows (in that order)
1200 void wxAuiTabContainer::DoShowHide()
1201 {
1202 wxAuiNotebookPageArray& pages = GetPages();
1203 size_t i, page_count = pages.GetCount();
1204
1205 // show new active page first
1206 for (i = 0; i < page_count; ++i)
1207 {
1208 wxAuiNotebookPage& page = pages.Item(i);
1209 if (page.active)
1210 {
1211 ShowWnd(page.window, true);
1212 break;
1213 }
1214 }
1215
1216 // hide all other pages
1217 for (i = 0; i < page_count; ++i)
1218 {
1219 wxAuiNotebookPage& page = pages.Item(i);
1220 ShowWnd(page.window, page.active);
1221 }
1222 }
1223
1224
1225
1226
1227
1228
1229 // -- wxAuiTabCtrl class implementation --
1230
1231
1232
1233 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
1234 EVT_PAINT(wxAuiTabCtrl::OnPaint)
1235 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
1236 EVT_SIZE(wxAuiTabCtrl::OnSize)
1237 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
1238 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
1239 EVT_MOTION(wxAuiTabCtrl::OnMotion)
1240 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
1241 EVT_AUINOTEBOOK_BUTTON(-1, wxAuiTabCtrl::OnButton)
1242 END_EVENT_TABLE()
1243
1244
1245 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
1246 wxWindowID id,
1247 const wxPoint& pos,
1248 const wxSize& size,
1249 long style) : wxControl(parent, id, pos, size, style)
1250 {
1251 m_click_pt = wxDefaultPosition;
1252 m_is_dragging = false;
1253 m_hover_button = NULL;
1254 }
1255
1256 wxAuiTabCtrl::~wxAuiTabCtrl()
1257 {
1258 }
1259
1260 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
1261 {
1262 wxPaintDC dc(this);
1263
1264 dc.SetFont(GetFont());
1265
1266 if (GetPageCount() > 0)
1267 Render(&dc, this);
1268 }
1269
1270 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
1271 {
1272 }
1273
1274 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
1275 {
1276 wxSize s = evt.GetSize();
1277 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
1278 SetRect(r);
1279 }
1280
1281 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
1282 {
1283 CaptureMouse();
1284 m_click_pt = wxDefaultPosition;
1285 m_is_dragging = false;
1286 m_click_tab = NULL;
1287
1288 wxWindow* wnd;
1289 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
1290 {
1291 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1292 e.SetSelection(GetIdxFromWindow(wnd));
1293 e.SetOldSelection(GetActivePage());
1294 e.SetEventObject(this);
1295 GetEventHandler()->ProcessEvent(e);
1296
1297 m_click_pt.x = evt.m_x;
1298 m_click_pt.y = evt.m_y;
1299 m_click_tab = wnd;
1300 }
1301
1302 if (m_hover_button)
1303 {
1304 m_hover_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
1305 Refresh();
1306 Update();
1307 }
1308 }
1309
1310 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent&)
1311 {
1312 if (GetCapture() == this)
1313 ReleaseMouse();
1314
1315 if (m_is_dragging)
1316 {
1317 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
1318 evt.SetSelection(GetIdxFromWindow(m_click_tab));
1319 evt.SetOldSelection(evt.GetSelection());
1320 evt.SetEventObject(this);
1321 GetEventHandler()->ProcessEvent(evt);
1322 return;
1323 }
1324
1325 if (m_hover_button)
1326 {
1327 m_hover_button->cur_state = wxAUI_BUTTON_STATE_HOVER;
1328 Refresh();
1329 Update();
1330
1331 if (!(m_hover_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
1332 {
1333 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
1334 evt.SetInt(m_hover_button->id);
1335 evt.SetEventObject(this);
1336 GetEventHandler()->ProcessEvent(evt);
1337 }
1338 }
1339
1340 m_click_pt = wxDefaultPosition;
1341 m_is_dragging = false;
1342 m_click_tab = NULL;
1343 }
1344
1345 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
1346 {
1347 wxPoint pos = evt.GetPosition();
1348
1349 // check if the mouse is hovering above a button
1350 wxAuiTabContainerButton* button;
1351 if (ButtonHitTest(pos.x, pos.y, &button))
1352 {
1353 if (m_hover_button && button != m_hover_button)
1354 {
1355 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1356 m_hover_button = NULL;
1357 Refresh();
1358 Update();
1359 }
1360
1361 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
1362 {
1363 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
1364 Refresh();
1365 Update();
1366 m_hover_button = button;
1367 return;
1368 }
1369 }
1370 else
1371 {
1372 if (m_hover_button)
1373 {
1374 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1375 m_hover_button = NULL;
1376 Refresh();
1377 Update();
1378 }
1379 }
1380
1381
1382 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
1383 return;
1384
1385 if (m_is_dragging)
1386 {
1387 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
1388 evt.SetSelection(GetIdxFromWindow(m_click_tab));
1389 evt.SetOldSelection(evt.GetSelection());
1390 evt.SetEventObject(this);
1391 GetEventHandler()->ProcessEvent(evt);
1392 return;
1393 }
1394
1395
1396 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
1397 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
1398
1399 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
1400 abs(pos.y - m_click_pt.y) > drag_y_threshold)
1401 {
1402 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
1403 evt.SetSelection(GetIdxFromWindow(m_click_tab));
1404 evt.SetOldSelection(evt.GetSelection());
1405 evt.SetEventObject(this);
1406 GetEventHandler()->ProcessEvent(evt);
1407
1408 m_is_dragging = true;
1409 }
1410 }
1411
1412 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
1413 {
1414 if (m_hover_button)
1415 {
1416 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1417 m_hover_button = NULL;
1418 Refresh();
1419 Update();
1420 }
1421 }
1422
1423 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
1424 {
1425 int button = event.GetInt();
1426
1427 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
1428 {
1429 if (button == wxAUI_BUTTON_LEFT)
1430 {
1431 if (GetTabOffset() > 0)
1432 {
1433 SetTabOffset(GetTabOffset()-1);
1434 Refresh();
1435 Update();
1436 }
1437 }
1438 else
1439 {
1440 SetTabOffset(GetTabOffset()+1);
1441 Refresh();
1442 Update();
1443 }
1444 }
1445 else if (button == wxAUI_BUTTON_WINDOWLIST)
1446 {
1447 wxArrayString as;
1448
1449 size_t i, page_count = m_pages.GetCount();
1450 for (i = 0; i < page_count; ++i)
1451 {
1452 wxAuiNotebookPage& page = m_pages.Item(i);
1453 as.Add(page.caption);
1454 }
1455
1456 int idx = GetArtProvider()->ShowWindowList(this, as, GetActivePage());
1457
1458 if (idx != -1)
1459 {
1460 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1461 e.SetSelection(idx);
1462 e.SetOldSelection(GetActivePage());
1463 e.SetEventObject(this);
1464 GetEventHandler()->ProcessEvent(e);
1465 }
1466 }
1467 else
1468 {
1469 event.Skip();
1470 }
1471 }
1472
1473 // wxTabFrame is an interesting case. It's important that all child pages
1474 // of the multi-notebook control are all actually children of that control
1475 // (and not grandchildren). wxTabFrame facilitates this. There is one
1476 // instance of wxTabFrame for each tab control inside the multi-notebook.
1477 // It's important to know that wxTabFrame is not a real window, but it merely
1478 // used to capture the dimensions/positioning of the internal tab control and
1479 // it's managed page windows
1480
1481 class wxTabFrame : public wxWindow
1482 {
1483 public:
1484
1485 wxTabFrame()
1486 {
1487 m_tabs = NULL;
1488 m_rect = wxRect(0,0,200,200);
1489 m_tab_ctrl_height = 20;
1490 }
1491
1492 void SetTabCtrlHeight(int h)
1493 {
1494 m_tab_ctrl_height = h;
1495 }
1496
1497 void DoSetSize(int x, int y,
1498 int width, int height,
1499 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
1500 {
1501 m_rect = wxRect(x, y, width, height);
1502 DoSizing();
1503 }
1504
1505 void DoGetClientSize(int* x, int* y) const
1506 {
1507 *x = m_rect.width;
1508 *y = m_rect.height;
1509 }
1510
1511 bool Show( bool WXUNUSED(show = true) ) { return false; }
1512
1513 void DoSizing()
1514 {
1515 if (!m_tabs)
1516 return;
1517
1518 int tab_height = wxMin(m_rect.height, m_tab_ctrl_height);
1519 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, tab_height);
1520 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, tab_height);
1521 m_tabs->SetRect(wxRect(0, 0, m_rect.width, tab_height));
1522 m_tabs->Refresh();
1523 m_tabs->Update();
1524
1525 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
1526 size_t i, page_count = pages.GetCount();
1527
1528 for (i = 0; i < page_count; ++i)
1529 {
1530 wxAuiNotebookPage& page = pages.Item(i);
1531 page.window->SetSize(m_rect.x, m_rect.y+tab_height,
1532 m_rect.width, m_rect.height-tab_height);
1533
1534 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1535 {
1536 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
1537 wnd->ApplyMDIChildFrameRect();
1538 }
1539 }
1540 }
1541
1542 void DoGetSize(int* x, int* y) const
1543 {
1544 if (x)
1545 *x = m_rect.GetWidth();
1546 if (y)
1547 *y = m_rect.GetHeight();
1548 }
1549
1550 void Update()
1551 {
1552 // does nothing
1553 }
1554
1555 public:
1556
1557 wxRect m_rect;
1558 wxRect m_tab_rect;
1559 wxAuiTabCtrl* m_tabs;
1560 int m_tab_ctrl_height;
1561 };
1562
1563
1564
1565
1566
1567 // -- wxAuiNotebook class implementation --
1568
1569 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
1570 //EVT_ERASE_BACKGROUND(wxAuiNotebook::OnEraseBackground)
1571 //EVT_SIZE(wxAuiNotebook::OnSize)
1572 //EVT_LEFT_DOWN(wxAuiNotebook::OnLeftDown)
1573 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
1574 EVT_COMMAND_RANGE(10000, 10100,
1575 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
1576 wxAuiNotebook::OnTabClicked)
1577 EVT_COMMAND_RANGE(10000, 10100,
1578 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
1579 wxAuiNotebook::OnTabBeginDrag)
1580 EVT_COMMAND_RANGE(10000, 10100,
1581 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
1582 wxAuiNotebook::OnTabEndDrag)
1583 EVT_COMMAND_RANGE(10000, 10100,
1584 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
1585 wxAuiNotebook::OnTabDragMotion)
1586 EVT_COMMAND_RANGE(10000, 10100,
1587 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
1588 wxAuiNotebook::OnTabButton)
1589 END_EVENT_TABLE()
1590
1591 wxAuiNotebook::wxAuiNotebook()
1592 {
1593 m_curpage = -1;
1594 m_tab_id_counter = 10000;
1595 m_dummy_wnd = NULL;
1596 m_tab_ctrl_height = 20;
1597 }
1598
1599 wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
1600 wxWindowID id,
1601 const wxPoint& pos,
1602 const wxSize& size,
1603 long style) : wxControl(parent, id, pos, size, style)
1604 {
1605 InitNotebook(style);
1606 }
1607
1608 bool wxAuiNotebook::Create(wxWindow* parent,
1609 wxWindowID id,
1610 const wxPoint& pos,
1611 const wxSize& size,
1612 long style)
1613 {
1614 if (!wxControl::Create(parent, id, pos, size, style))
1615 return false;
1616
1617 InitNotebook(style);
1618
1619 return true;
1620 }
1621
1622 // InitNotebook() contains common initialization
1623 // code called by all constructors
1624 void wxAuiNotebook::InitNotebook(long style)
1625 {
1626 m_curpage = -1;
1627 m_tab_id_counter = 10000;
1628 m_dummy_wnd = NULL;
1629 m_tab_ctrl_height = 20;
1630 m_flags = (unsigned int)style;
1631
1632 m_normal_font = *wxNORMAL_FONT;
1633 m_selected_font = *wxNORMAL_FONT;
1634 m_selected_font.SetWeight(wxBOLD);
1635
1636 // choose a default for the tab height
1637 m_tab_ctrl_height = m_tabs.GetArtProvider()->GetBestTabCtrlSize(this);
1638
1639 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
1640 m_dummy_wnd->SetSize(200, 200);
1641 m_dummy_wnd->Show(false);
1642
1643 m_mgr.SetManagedWindow(this);
1644
1645 m_mgr.AddPane(m_dummy_wnd,
1646 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
1647
1648 m_mgr.Update();
1649 }
1650
1651 wxAuiNotebook::~wxAuiNotebook()
1652 {
1653 m_mgr.UnInit();
1654 }
1655
1656 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
1657 {
1658 m_tabs.SetArtProvider(art);
1659 }
1660
1661 wxAuiTabArt* wxAuiNotebook::GetArtProvider()
1662 {
1663 return m_tabs.GetArtProvider();
1664 }
1665
1666 void wxAuiNotebook::SetWindowStyleFlag(long style)
1667 {
1668 wxControl::SetWindowStyleFlag(style);
1669
1670 m_flags = (unsigned int)style;
1671
1672 // if the control is already initialized
1673 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
1674 {
1675 // let all of the tab children know about the new style
1676
1677 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1678 size_t i, pane_count = all_panes.GetCount();
1679 for (i = 0; i < pane_count; ++i)
1680 {
1681 wxAuiPaneInfo& pane = all_panes.Item(i);
1682 if (pane.name == wxT("dummy"))
1683 continue;
1684 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
1685 tabctrl->SetFlags(m_flags);
1686 tabctrl->Refresh();
1687 tabctrl->Update();
1688 }
1689 }
1690 }
1691
1692
1693 bool wxAuiNotebook::AddPage(wxWindow* page,
1694 const wxString& caption,
1695 bool select,
1696 const wxBitmap& bitmap)
1697 {
1698 return InsertPage(GetPageCount(), page, caption, select, bitmap);
1699 }
1700
1701 bool wxAuiNotebook::InsertPage(size_t page_idx,
1702 wxWindow* page,
1703 const wxString& caption,
1704 bool select,
1705 const wxBitmap& bitmap)
1706 {
1707 wxAuiNotebookPage info;
1708 info.window = page;
1709 info.caption = caption;
1710 info.bitmap = bitmap;
1711 info.active = false;
1712
1713 // if there are currently no tabs, the first added
1714 // tab must be active
1715 if (m_tabs.GetPageCount() == 0)
1716 info.active = true;
1717
1718 m_tabs.InsertPage(page, info, page_idx);
1719
1720 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
1721 if (page_idx >= active_tabctrl->GetPageCount())
1722 active_tabctrl->AddPage(page, info);
1723 else
1724 active_tabctrl->InsertPage(page, info, page_idx);
1725
1726 DoSizing();
1727 active_tabctrl->DoShowHide();
1728
1729 if (select)
1730 {
1731 int idx = m_tabs.GetIdxFromWindow(page);
1732 wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()"));
1733
1734 SetSelection(idx);
1735 }
1736
1737 return true;
1738 }
1739
1740
1741 // DeletePage() removes a tab from the multi-notebook,
1742 // and destroys the window as well
1743 bool wxAuiNotebook::DeletePage(size_t page_idx)
1744 {
1745 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1746 wxWindow* new_active = NULL;
1747
1748 // find out which onscreen tab ctrl owns this tab
1749 wxAuiTabCtrl* ctrl;
1750 int ctrl_idx;
1751 if (!FindTab(wnd, &ctrl, &ctrl_idx))
1752 return false;
1753
1754 // find a new page and set it as active
1755 int new_idx = ctrl_idx+1;
1756 if (new_idx >= (int)ctrl->GetPageCount())
1757 new_idx = ctrl_idx-1;
1758
1759 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
1760 {
1761 new_active = ctrl->GetWindowFromIdx(new_idx);
1762 }
1763 else
1764 {
1765 // set the active page to the first page that
1766 // isn't the one being deleted
1767 size_t i, page_count = m_tabs.GetPageCount();
1768 for (i = 0; i < page_count; ++i)
1769 {
1770 wxWindow* w = m_tabs.GetWindowFromIdx(i);
1771 if (wnd != w)
1772 {
1773 new_active = m_tabs.GetWindowFromIdx(i);
1774 break;
1775 }
1776 }
1777 }
1778
1779 // remove the tab from main catalog
1780 if (!m_tabs.RemovePage(wnd))
1781 return false;
1782
1783 // remove the tab from the onscreen tab ctrl
1784 ctrl->RemovePage(wnd);
1785
1786 // actually destroy the window now
1787 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1788 {
1789 // delete the child frame with pending delete, as is
1790 // customary with frame windows
1791 if (!wxPendingDelete.Member(wnd))
1792 wxPendingDelete.Append(wnd);
1793 }
1794 else
1795 {
1796 wnd->Destroy();
1797 }
1798
1799 RemoveEmptyTabFrames();
1800
1801 // set new active pane
1802 if (new_active)
1803 {
1804 m_curpage = -1;
1805 SetSelection(m_tabs.GetIdxFromWindow(new_active));
1806 }
1807
1808 return true;
1809 }
1810
1811
1812
1813 // RemovePage() removes a tab from the multi-notebook,
1814 // but does not destroy the window
1815 bool wxAuiNotebook::RemovePage(size_t page_idx)
1816 {
1817 // remove the tab from our own catalog
1818 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1819 if (!m_tabs.RemovePage(wnd))
1820 return false;
1821
1822 // remove the tab from the onscreen tab ctrl
1823 wxAuiTabCtrl* ctrl;
1824 int ctrl_idx;
1825 if (FindTab(wnd, &ctrl, &ctrl_idx))
1826 {
1827 ctrl->RemovePage(wnd);
1828 return true;
1829 }
1830
1831 return false;
1832 }
1833
1834 // SetPageText() changes the tab caption of the specified page
1835 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
1836 {
1837 if (page_idx >= m_tabs.GetPageCount())
1838 return false;
1839
1840 // update our own tab catalog
1841 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
1842 page_info.caption = text;
1843
1844 // update what's on screen
1845 wxAuiTabCtrl* ctrl;
1846 int ctrl_idx;
1847 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
1848 {
1849 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
1850 info.caption = text;
1851 ctrl->Refresh();
1852 ctrl->Update();
1853 }
1854
1855 return true;
1856 }
1857
1858 // GetSelection() returns the index of the currently active page
1859 int wxAuiNotebook::GetSelection() const
1860 {
1861 return m_curpage;
1862 }
1863
1864 // SetSelection() sets the currently active page
1865 size_t wxAuiNotebook::SetSelection(size_t new_page)
1866 {
1867 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
1868 if (!wnd)
1869 return m_curpage;
1870
1871 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1872 evt.SetSelection(new_page);
1873 evt.SetOldSelection(m_curpage);
1874 evt.SetEventObject(this);
1875 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
1876 {
1877 // program allows the page change
1878 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
1879 (void)GetEventHandler()->ProcessEvent(evt);
1880
1881
1882
1883 wxAuiTabCtrl* ctrl;
1884 int ctrl_idx;
1885 if (FindTab(wnd, &ctrl, &ctrl_idx))
1886 {
1887 m_tabs.SetActivePage(wnd);
1888
1889 ctrl->SetActivePage(ctrl_idx);
1890 DoSizing();
1891 ctrl->DoShowHide();
1892
1893 int old_curpage = m_curpage;
1894 m_curpage = new_page;
1895
1896
1897 // set fonts
1898 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1899 size_t i, pane_count = all_panes.GetCount();
1900 for (i = 0; i < pane_count; ++i)
1901 {
1902 wxAuiPaneInfo& pane = all_panes.Item(i);
1903 if (pane.name == wxT("dummy"))
1904 continue;
1905 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
1906 if (tabctrl != ctrl)
1907 tabctrl->SetSelectedFont(m_normal_font);
1908 else
1909 tabctrl->SetSelectedFont(m_selected_font);
1910 tabctrl->Refresh();
1911 }
1912
1913 wnd->SetFocus();
1914
1915 return old_curpage;
1916 }
1917 }
1918
1919 return m_curpage;
1920 }
1921
1922 // GetPageCount() returns the total number of
1923 // pages managed by the multi-notebook
1924 size_t wxAuiNotebook::GetPageCount() const
1925 {
1926 return m_tabs.GetPageCount();
1927 }
1928
1929 // GetPage() returns the wxWindow pointer of the
1930 // specified page
1931 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
1932 {
1933 wxASSERT(page_idx < m_tabs.GetPageCount());
1934
1935 return m_tabs.GetWindowFromIdx(page_idx);
1936 }
1937
1938 // DoSizing() performs all sizing operations in each tab control
1939 void wxAuiNotebook::DoSizing()
1940 {
1941 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1942 size_t i, pane_count = all_panes.GetCount();
1943 for (i = 0; i < pane_count; ++i)
1944 {
1945 if (all_panes.Item(i).name == wxT("dummy"))
1946 continue;
1947
1948 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1949 tabframe->DoSizing();
1950 }
1951 }
1952
1953 // GetActiveTabCtrl() returns the active tab control. It is
1954 // called to determine which control gets new windows being added
1955 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
1956 {
1957 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
1958 {
1959 wxAuiTabCtrl* ctrl;
1960 int idx;
1961
1962 // find the tab ctrl with the current page
1963 if (FindTab(m_tabs.GetPage(m_curpage).window,
1964 &ctrl, &idx))
1965 {
1966 return ctrl;
1967 }
1968 }
1969
1970 // no current page, just find the first tab ctrl
1971 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1972 size_t i, pane_count = all_panes.GetCount();
1973 for (i = 0; i < pane_count; ++i)
1974 {
1975 if (all_panes.Item(i).name == wxT("dummy"))
1976 continue;
1977
1978 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1979 return tabframe->m_tabs;
1980 }
1981
1982 // If there is no tabframe at all, create one
1983 wxTabFrame* tabframe = new wxTabFrame;
1984 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
1985 tabframe->m_tabs = new wxAuiTabCtrl(this,
1986 m_tab_id_counter++,
1987 wxDefaultPosition,
1988 wxDefaultSize,
1989 wxNO_BORDER);
1990 tabframe->m_tabs->SetFlags(m_flags);
1991 m_mgr.AddPane(tabframe,
1992 wxAuiPaneInfo().Center().CaptionVisible(false));
1993
1994 m_mgr.Update();
1995
1996 return tabframe->m_tabs;
1997 }
1998
1999 // FindTab() finds the tab control that currently contains the window as well
2000 // as the index of the window in the tab control. It returns true if the
2001 // window was found, otherwise false.
2002 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2003 {
2004 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2005 size_t i, pane_count = all_panes.GetCount();
2006 for (i = 0; i < pane_count; ++i)
2007 {
2008 if (all_panes.Item(i).name == wxT("dummy"))
2009 continue;
2010
2011 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2012
2013 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2014 if (page_idx != -1)
2015 {
2016 *ctrl = tabframe->m_tabs;
2017 *idx = page_idx;
2018 return true;
2019 }
2020 }
2021
2022 return false;
2023 }
2024
2025
2026 void wxAuiNotebook::OnEraseBackground(wxEraseEvent&)
2027 {
2028 }
2029
2030 void wxAuiNotebook::OnSize(wxSizeEvent&)
2031 {
2032 }
2033
2034 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
2035 {
2036 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2037
2038 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2039 wxASSERT(ctrl != NULL);
2040
2041 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
2042 wxASSERT(wnd != NULL);
2043
2044 int idx = m_tabs.GetIdxFromWindow(wnd);
2045 wxASSERT(idx != -1);
2046
2047 SetSelection(idx);
2048 }
2049
2050 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
2051 {
2052 m_last_drag_x = 0;
2053 }
2054
2055 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
2056 {
2057 wxPoint screen_pt = ::wxGetMousePosition();
2058 wxPoint client_pt = ScreenToClient(screen_pt);
2059 wxPoint zero(0,0);
2060
2061 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2062
2063 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
2064 if (dest_tabs == src_tabs)
2065 {
2066 if (src_tabs)
2067 {
2068 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2069 }
2070
2071 // always hide the hint for inner-tabctrl drag
2072 m_mgr.HideHint();
2073
2074 // if tab moving is not allowed, leave
2075 if (!(m_flags & wxAUI_NB_TAB_MOVE))
2076 {
2077 return;
2078 }
2079
2080 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
2081 wxWindow* dest_location_tab;
2082
2083 // this is an inner-tab drag/reposition
2084 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
2085 {
2086 int src_idx = evt.GetSelection();
2087 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
2088
2089 // prevent jumpy drag
2090 if ((src_idx == dest_idx) || dest_idx == -1 ||
2091 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
2092 (src_idx < dest_idx && m_last_drag_x >= pt.x))
2093 {
2094 m_last_drag_x = pt.x;
2095 return;
2096 }
2097
2098
2099 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
2100 dest_tabs->MovePage(src_tab, dest_idx);
2101 dest_tabs->SetActivePage((size_t)dest_idx);
2102 dest_tabs->DoShowHide();
2103 dest_tabs->Refresh();
2104 m_last_drag_x = pt.x;
2105
2106 }
2107
2108 return;
2109 }
2110
2111
2112 // if tab moving is not allowed, leave
2113 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
2114 {
2115 return;
2116 }
2117
2118
2119 if (src_tabs)
2120 {
2121 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
2122 }
2123
2124
2125 if (dest_tabs)
2126 {
2127 wxRect hint_rect = dest_tabs->GetRect();
2128 ClientToScreen(&hint_rect.x, &hint_rect.y);
2129 m_mgr.ShowHint(hint_rect);
2130 }
2131 else
2132 {
2133 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
2134 }
2135 }
2136
2137
2138
2139 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
2140 {
2141 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2142
2143 m_mgr.HideHint();
2144
2145 // if tab moving is not allowed, leave
2146 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
2147 {
2148 return;
2149 }
2150
2151 // set cursor back to an arrow
2152 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2153 if (src_tabs)
2154 {
2155 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2156 }
2157
2158 // get the mouse position, which will be used to determine the drop point
2159 wxPoint mouse_screen_pt = ::wxGetMousePosition();
2160 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
2161
2162
2163 // the src tab control is the control that fired this event
2164 wxAuiTabCtrl* dest_tabs = NULL;
2165
2166
2167 // If the pointer is in an existing tab frame, do a tab insert
2168 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
2169 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
2170 int insert_idx = -1;
2171 if (tab_frame)
2172 {
2173 dest_tabs = tab_frame->m_tabs;
2174
2175 if (dest_tabs == src_tabs)
2176 return;
2177
2178
2179 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2180 wxWindow* target = NULL;
2181 dest_tabs->TabHitTest(pt.x, pt.y, &target);
2182 if (target)
2183 {
2184 insert_idx = dest_tabs->GetIdxFromWindow(target);
2185 }
2186 }
2187 else
2188 {
2189 // If there is no tabframe at all, create one
2190 wxTabFrame* new_tabs = new wxTabFrame;
2191 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
2192 new_tabs->m_tabs = new wxAuiTabCtrl(this,
2193 m_tab_id_counter++,
2194 wxDefaultPosition,
2195 wxDefaultSize,
2196 wxNO_BORDER);
2197 new_tabs->m_tabs->SetFlags(m_flags);
2198
2199 m_mgr.AddPane(new_tabs,
2200 wxAuiPaneInfo().Bottom().CaptionVisible(false),
2201 mouse_client_pt);
2202 m_mgr.Update();
2203 dest_tabs = new_tabs->m_tabs;
2204 }
2205
2206
2207
2208 // remove the page from the source tabs
2209 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
2210 page_info.active = false;
2211 src_tabs->RemovePage(page_info.window);
2212 if (src_tabs->GetPageCount() > 0)
2213 {
2214 src_tabs->SetActivePage((size_t)0);
2215 src_tabs->DoShowHide();
2216 src_tabs->Refresh();
2217 }
2218
2219
2220
2221 // add the page to the destination tabs
2222 if (insert_idx == -1)
2223 insert_idx = dest_tabs->GetPageCount();
2224 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2225
2226 if (src_tabs->GetPageCount() == 0)
2227 {
2228 RemoveEmptyTabFrames();
2229 }
2230
2231 DoSizing();
2232 dest_tabs->DoShowHide();
2233 dest_tabs->Refresh();
2234
2235 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
2236 }
2237
2238
2239
2240 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
2241 {
2242 // if we've just removed the last tab from the source
2243 // tab set, the remove the tab control completely
2244 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2245 size_t i, pane_count = all_panes.GetCount();
2246 for (i = 0; i < pane_count; ++i)
2247 {
2248 if (all_panes.Item(i).name == wxT("dummy"))
2249 continue;
2250
2251 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2252 if (tabframe->m_tab_rect.Contains(pt))
2253 return tabframe->m_tabs;
2254 }
2255
2256 return NULL;
2257 }
2258
2259 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
2260 {
2261 // if we've just removed the last tab from the source
2262 // tab set, the remove the tab control completely
2263 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2264 size_t i, pane_count = all_panes.GetCount();
2265 for (i = 0; i < pane_count; ++i)
2266 {
2267 if (all_panes.Item(i).name == wxT("dummy"))
2268 continue;
2269
2270 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2271 if (tabframe->m_tabs == tab_ctrl)
2272 {
2273 return tabframe;
2274 }
2275 }
2276
2277 return NULL;
2278 }
2279
2280 void wxAuiNotebook::RemoveEmptyTabFrames()
2281 {
2282 // if we've just removed the last tab from the source
2283 // tab set, the remove the tab control completely
2284 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
2285 size_t i, pane_count = all_panes.GetCount();
2286 for (i = 0; i < pane_count; ++i)
2287 {
2288 if (all_panes.Item(i).name == wxT("dummy"))
2289 continue;
2290
2291 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
2292 if (tab_frame->m_tabs->GetPageCount() == 0)
2293 {
2294 m_mgr.DetachPane(tab_frame);
2295
2296 // use pending delete because sometimes during
2297 // window closing, refreshs are pending
2298 if (!wxPendingDelete.Member(tab_frame->m_tabs))
2299 wxPendingDelete.Append(tab_frame->m_tabs);
2300 //tab_frame->m_tabs->Destroy();
2301
2302 delete tab_frame;
2303 }
2304 }
2305
2306
2307 // check to see if there is still a center pane;
2308 // if there isn't, make a frame the center pane
2309 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
2310 pane_count = panes.GetCount();
2311 wxWindow* first_good = NULL;
2312 bool center_found = false;
2313 for (i = 0; i < pane_count; ++i)
2314 {
2315 if (panes.Item(i).name == wxT("dummy"))
2316 continue;
2317 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
2318 center_found = true;
2319 if (!first_good)
2320 first_good = panes.Item(i).window;
2321 }
2322
2323 if (!center_found && first_good)
2324 {
2325 m_mgr.GetPane(first_good).Centre();
2326 }
2327
2328 m_mgr.Update();
2329 }
2330
2331 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
2332 {
2333 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
2334 if (idx != -1 && idx != m_curpage)
2335 {
2336 SetSelection(idx);
2337 }
2338 }
2339
2340
2341 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
2342 {
2343 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2344 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2345
2346 int button_id = evt.GetInt();
2347
2348 if (button_id == wxAUI_BUTTON_CLOSE)
2349 {
2350 int selection = tabs->GetActivePage();
2351
2352 if (selection != -1)
2353 {
2354 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
2355
2356 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2357 {
2358 close_wnd->Close();
2359 }
2360 else
2361 {
2362 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
2363 DeletePage(main_idx);
2364 }
2365 }
2366 }
2367 }
2368
2369
2370
2371
2372 #endif // wxUSE_AUI