]> git.saurik.com Git - wxWidgets.git/blob - src/aui/auibook.cpp
wxaui multi-notebook now uses a tab art provider which allows for dynamically switcha...
[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
33 #include "wx/arrimpl.cpp"
34 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
35 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
36
37 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING)
38 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
39 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
43
44
45
46 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
47
48
49
50
51
52 // This functions are here for this proof of concept
53 // and will be factored out later. See dockart.cpp
54 static wxColor StepColour(const wxColor& c, int percent)
55 {
56 int r = c.Red(), g = c.Green(), b = c.Blue();
57 return wxColour((unsigned char)wxMin((r*percent)/100,255),
58 (unsigned char)wxMin((g*percent)/100,255),
59 (unsigned char)wxMin((b*percent)/100,255));
60 }
61
62 // This functions are here for this proof of concept
63 // and will be factored out later. See dockart.cpp
64 static wxBitmap BitmapFromBits(const unsigned char bits[], int w, int h,
65 const wxColour& color)
66 {
67 wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage();
68 img.Replace(0,0,0,123,123,123);
69 img.Replace(255,255,255,color.Red(),color.Green(),color.Blue());
70 img.SetMaskColour(123,123,123);
71 return wxBitmap(img);
72 }
73
74 static void DrawButton(wxDC& dc,
75 const wxRect& _rect,
76 const wxBitmap& bmp,
77 const wxColour& bkcolour,
78 int button_state)
79 {
80 wxRect rect = _rect;
81
82 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
83 {
84 rect.x++;
85 rect.y++;
86 }
87
88 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
89 button_state == wxAUI_BUTTON_STATE_PRESSED)
90 {
91 dc.SetBrush(wxBrush(StepColour(bkcolour, 120)));
92 dc.SetPen(wxPen(StepColour(bkcolour, 70)));
93
94 // draw the background behind the button
95 dc.DrawRectangle(rect.x, rect.y, 15, 15);
96 }
97
98 // draw the button itself
99 dc.DrawBitmap(bmp, rect.x, rect.y, true);
100 }
101
102
103
104
105
106 // -- wxDefaultTabArt class implementation --
107
108 wxDefaultTabArt::wxDefaultTabArt()
109 {
110 m_normal_font = *wxNORMAL_FONT;
111 m_selected_font = *wxNORMAL_FONT;
112 m_selected_font.SetWeight(wxBOLD);
113 m_measuring_font = m_selected_font;
114
115 wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
116
117 wxColour background_colour = StepColour(base_colour, 95);
118 wxColour normaltab_colour = base_colour;
119 wxColour selectedtab_colour = *wxWHITE;
120
121 m_bkbrush = wxBrush(background_colour);
122 m_normal_bkbrush = wxBrush(normaltab_colour);
123 m_normal_bkpen = wxPen(normaltab_colour);
124 m_selected_bkbrush = wxBrush(selectedtab_colour);
125 m_selected_bkpen = wxPen(selectedtab_colour);
126 }
127
128 void wxDefaultTabArt::DrawBackground(
129 wxDC* dc,
130 const wxRect& rect)
131 {
132 // draw background
133 dc->SetBrush(m_bkbrush);
134 dc->SetPen(*wxTRANSPARENT_PEN);
135 dc->DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
136
137 // draw base line
138 dc->SetPen(*wxGREY_PEN);
139 dc->DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
140 }
141
142 // DrawTab() draws an individual tab.
143 //
144 // dc - output dc
145 // in_rect - rectangle the tab should be confined to
146 // caption - tab's caption
147 // active - whether or not the tab is active
148 // out_rect - actual output rectangle
149 // x_extent - the advance x; where the next tab should start
150
151 void wxDefaultTabArt::DrawTab(wxDC* dc,
152 const wxRect& in_rect,
153 const wxString& caption_text,
154 bool active,
155 wxRect* out_rect,
156 int* x_extent)
157 {
158 wxCoord normal_textx, normal_texty;
159 wxCoord selected_textx, selected_texty;
160 wxCoord measured_textx, measured_texty;
161 wxCoord textx, texty;
162
163
164 // if the caption is empty, measure some temporary text
165 wxString caption = caption_text;
166 if (caption_text.empty())
167 caption = wxT("Xj");
168
169 // measure text
170 dc->SetFont(m_measuring_font);
171 dc->GetTextExtent(caption, &measured_textx, &measured_texty);
172
173 dc->SetFont(m_selected_font);
174 dc->GetTextExtent(caption, &selected_textx, &selected_texty);
175
176 dc->SetFont(m_normal_font);
177 dc->GetTextExtent(caption, &normal_textx, &normal_texty);
178
179 caption = caption_text;
180
181 wxCoord tab_height = measured_texty + 4;
182 wxCoord tab_width = measured_textx + tab_height + 5;
183 wxCoord tab_x = in_rect.x;
184 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
185
186
187 // select pen, brush and font for the tab to be drawn
188
189 if (active)
190 {
191 dc->SetPen(m_selected_bkpen);
192 dc->SetBrush(m_selected_bkbrush);
193 dc->SetFont(m_selected_font);
194 textx = selected_textx;
195 texty = selected_texty;
196 }
197 else
198 {
199 dc->SetPen(m_normal_bkpen);
200 dc->SetBrush(m_normal_bkbrush);
201 dc->SetFont(m_normal_font);
202 textx = normal_textx;
203 texty = normal_texty;
204 }
205
206
207 // -- draw line --
208
209 wxPoint points[7];
210 points[0].x = tab_x;
211 points[0].y = tab_y + tab_height - 1;
212 points[1].x = tab_x + tab_height - 3;
213 points[1].y = tab_y + 2;
214 points[2].x = tab_x + tab_height + 3;
215 points[2].y = tab_y;
216 points[3].x = tab_x + tab_width - 2;
217 points[3].y = tab_y;
218 points[4].x = tab_x + tab_width;
219 points[4].y = tab_y + 2;
220 points[5].x = tab_x + tab_width;
221 points[5].y = tab_y + tab_height - 1;
222 points[6] = points[0];
223
224
225 dc->DrawPolygon(6, points);
226
227 dc->SetPen(*wxGREY_PEN);
228
229 //dc->DrawLines(active ? 6 : 7, points);
230 dc->DrawLines(7, points);
231
232 // -- draw text --
233
234 dc->DrawText(caption,
235 tab_x + (tab_height/3) + (tab_width/2) - (textx/2),
236 tab_y + tab_height - texty - 2);
237
238 *out_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
239 *x_extent = tab_width - (tab_height/2) - 1;
240 }
241
242
243 void wxDefaultTabArt::SetNormalFont(const wxFont& font)
244 {
245 m_normal_font = font;
246 }
247
248 void wxDefaultTabArt::SetSelectedFont(const wxFont& font)
249 {
250 m_selected_font = font;
251 }
252
253 void wxDefaultTabArt::SetMeasuringFont(const wxFont& font)
254 {
255 m_measuring_font = font;
256 }
257
258
259
260
261
262
263 // -- wxAuiTabContainer class implementation --
264
265
266 // wxAuiTabContainer is a class which contains information about each
267 // tab. It also can render an entire tab control to a specified DC.
268 // It's not a window class itself, because this code will be used by
269 // the wxFrameMananger, where it is disadvantageous to have separate
270 // windows for each tab control in the case of "docked tabs"
271
272 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
273 // which can be used as a tab control in the normal sense.
274
275
276 wxAuiTabContainer::wxAuiTabContainer()
277 {
278 m_art = new wxDefaultTabArt;
279 }
280
281 wxAuiTabContainer::~wxAuiTabContainer()
282 {
283 delete m_art;
284 }
285
286 void wxAuiTabContainer::SetArtProvider(wxTabArt* art)
287 {
288 delete m_art;
289 m_art = art;
290 }
291
292 wxTabArt* wxAuiTabContainer::GetArtProvider()
293 {
294 return m_art;
295 }
296
297 void wxAuiTabContainer::SetNormalFont(const wxFont& font)
298 {
299 m_art->SetNormalFont(font);
300 }
301
302 void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
303 {
304 m_art->SetSelectedFont(font);
305 }
306
307 void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
308 {
309 m_art->SetMeasuringFont(font);
310 }
311
312 void wxAuiTabContainer::SetRect(const wxRect& rect)
313 {
314 m_rect = rect;
315 }
316
317 bool wxAuiTabContainer::AddPage(wxWindow* page,
318 const wxAuiNotebookPage& info)
319 {
320 wxAuiNotebookPage page_info;
321 page_info = info;
322 page_info.window = page;
323
324 m_pages.Add(page_info);
325
326 return true;
327 }
328
329 bool wxAuiTabContainer::InsertPage(wxWindow* page,
330 const wxAuiNotebookPage& info,
331 size_t idx)
332 {
333 wxAuiNotebookPage page_info;
334 page_info = info;
335 page_info.window = page;
336
337 if (idx >= m_pages.GetCount())
338 m_pages.Add(page_info);
339 else
340 m_pages.Insert(page_info, idx);
341
342 return true;
343 }
344
345 bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
346 {
347 size_t i, page_count = m_pages.GetCount();
348 for (i = 0; i < page_count; ++i)
349 {
350 wxAuiNotebookPage& page = m_pages.Item(i);
351 if (page.window == wnd)
352 {
353 m_pages.RemoveAt(i);
354 return true;
355 }
356 }
357
358 return false;
359 }
360
361 bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
362 {
363 bool found = false;
364
365 size_t i, page_count = m_pages.GetCount();
366 for (i = 0; i < page_count; ++i)
367 {
368 wxAuiNotebookPage& page = m_pages.Item(i);
369 if (page.window == wnd)
370 {
371 page.active = true;
372 found = true;
373 }
374 else
375 {
376 page.active = false;
377 }
378 }
379
380 return found;
381 }
382
383 void wxAuiTabContainer::SetNoneActive()
384 {
385 size_t i, page_count = m_pages.GetCount();
386 for (i = 0; i < page_count; ++i)
387 {
388 wxAuiNotebookPage& page = m_pages.Item(i);
389 page.active = false;
390 }
391 }
392
393 bool wxAuiTabContainer::SetActivePage(size_t page)
394 {
395 if (page >= m_pages.GetCount())
396 return false;
397
398 return SetActivePage(m_pages.Item(page).window);
399 }
400
401 int wxAuiTabContainer::GetActivePage() const
402 {
403 size_t i, page_count = m_pages.GetCount();
404 for (i = 0; i < page_count; ++i)
405 {
406 wxAuiNotebookPage& page = m_pages.Item(i);
407 if (page.active)
408 return i;
409 }
410
411 return -1;
412 }
413
414 wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
415 {
416 if (idx >= m_pages.GetCount())
417 return NULL;
418
419 return m_pages[idx].window;
420 }
421
422 int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
423 {
424 size_t i, page_count = m_pages.GetCount();
425 for (i = 0; i < page_count; ++i)
426 {
427 wxAuiNotebookPage& page = m_pages.Item(i);
428 if (page.window == wnd)
429 return i;
430 }
431 return -1;
432 }
433
434 wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
435 {
436 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
437
438 return m_pages[idx];
439 }
440
441 wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
442 {
443 return m_pages;
444 }
445
446 size_t wxAuiTabContainer::GetPageCount() const
447 {
448 return m_pages.GetCount();
449 }
450
451 void wxAuiTabContainer::AddButton(int id, const wxBitmap& bmp)
452 {
453 wxAuiTabContainerButton button;
454 button.id = id;
455 button.bitmap = bmp;
456 button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
457
458 m_buttons.Add(button);
459 }
460
461
462
463 // Render() renders the tab catalog to the specified DC
464 // It is a virtual function and can be overridden to
465 // provide custom drawing capabilities
466 void wxAuiTabContainer::Render(wxDC* raw_dc)
467 {
468 wxMemoryDC dc;
469 wxBitmap bmp;
470 bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
471 dc.SelectObject(bmp);
472
473
474 m_art->DrawBackground(&dc, m_rect);
475
476 size_t i, page_count = m_pages.GetCount();
477 int offset = 0;
478
479 size_t active = 999;
480 int active_offset = 0;
481
482 int x_extent = 0;
483 wxRect rect = m_rect;
484 rect.y = 0;
485 rect.width = 1000;
486 rect.height = m_rect.height;
487
488 for (i = 0; i < page_count; ++i)
489 {
490 wxAuiNotebookPage& page = m_pages.Item(i);
491
492 rect.x = offset;
493
494 m_art->DrawTab(&dc,
495 rect,
496 page.caption,
497 page.active,
498 &page.rect,
499 &x_extent);
500
501 if (page.active)
502 {
503 active = i;
504 active_offset = offset;
505 }
506
507 offset += x_extent;
508 }
509
510 // draw the active tab again so it stands in the foreground
511 if (active < m_pages.GetCount())
512 {
513 wxAuiNotebookPage& page = m_pages.Item(active);
514
515 rect.x = active_offset;
516 m_art->DrawTab(&dc,
517 rect,
518 page.caption,
519 page.active,
520 &page.rect,
521 &x_extent);
522 }
523
524 // draw the buttons
525 offset = m_rect.x + m_rect.width;
526 size_t button_count = m_buttons.GetCount();
527 for (i = 0; i < button_count; ++i)
528 {
529 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
530
531 wxRect button_rect(offset - button.bitmap.GetWidth(), 1,
532 button.bitmap.GetWidth(), button.bitmap.GetHeight());
533
534 button.rect = button_rect;
535
536 DrawButton(dc, button.rect, button.bitmap,
537 //m_bkbrush.GetColour(),
538 *wxWHITE,
539 button.cur_state);
540
541 offset -= button.bitmap.GetWidth();
542 }
543
544
545 raw_dc->Blit(m_rect.x, m_rect.y, m_rect.GetWidth(), m_rect.GetHeight(), &dc, 0, 0);
546 }
547
548
549 // TabHitTest() tests if a tab was hit, passing the window pointer
550 // back if that condition was fulfilled. The function returns
551 // true if a tab was hit, otherwise false
552 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
553 {
554 if (!m_rect.Contains(x,y))
555 return false;
556
557 size_t i, page_count = m_pages.GetCount();
558
559 for (i = 0; i < page_count; ++i)
560 {
561 wxAuiNotebookPage& page = m_pages.Item(i);
562 if (page.rect.Contains(x,y))
563 {
564 *hit = page.window;
565 return true;
566 }
567 }
568
569 return false;
570 }
571
572 // ButtonHitTest() tests if a button was hit. The function returns
573 // true if a button was hit, otherwise false
574 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
575 wxAuiTabContainerButton** hit) const
576 {
577 if (!m_rect.Contains(x,y))
578 return false;
579
580 size_t i, button_count = m_buttons.GetCount();
581
582 for (i = 0; i < button_count; ++i)
583 {
584 wxAuiTabContainerButton& button = m_buttons.Item(i);
585 if (button.rect.Contains(x,y))
586 {
587 *hit = &button;
588 return true;
589 }
590 }
591
592 return false;
593 }
594
595
596
597 // the utility function ShowWnd() is the same as show,
598 // except it handles wxTabMDIChildFrame windows as well,
599 // as the Show() method on this class is "unplugged"
600 static void ShowWnd(wxWindow* wnd, bool show)
601 {
602 if (wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
603 {
604 wxTabMDIChildFrame* cf = (wxTabMDIChildFrame*)wnd;
605 cf->DoShow(show);
606 }
607 else
608 {
609 wnd->Show(show);
610 }
611 }
612
613
614 // DoShowHide() this function shows the active window, then
615 // hides all of the other windows (in that order)
616 void wxAuiTabContainer::DoShowHide()
617 {
618 wxAuiNotebookPageArray& pages = GetPages();
619 size_t i, page_count = pages.GetCount();
620
621 // show new active page first
622 for (i = 0; i < page_count; ++i)
623 {
624 wxAuiNotebookPage& page = pages.Item(i);
625 if (page.active)
626 {
627 ShowWnd(page.window, true);
628 break;
629 }
630 }
631
632 // hide all other pages
633 for (i = 0; i < page_count; ++i)
634 {
635 wxAuiNotebookPage& page = pages.Item(i);
636 ShowWnd(page.window, page.active);
637 }
638 }
639
640
641
642
643
644
645 // -- wxAuiTabCtrl class implementation --
646
647
648 const int wxAuiButtonClose = 101;
649
650 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
651 EVT_PAINT(wxAuiTabCtrl::OnPaint)
652 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
653 EVT_SIZE(wxAuiTabCtrl::OnSize)
654 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
655 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
656 EVT_MOTION(wxAuiTabCtrl::OnMotion)
657 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
658 END_EVENT_TABLE()
659
660
661 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
662 wxWindowID id,
663 const wxPoint& pos,
664 const wxSize& size,
665 long style) : wxControl(parent, id, pos, size, style)
666 {
667 m_click_pt = wxDefaultPosition;
668 m_is_dragging = false;
669 m_hover_button = NULL;
670
671 // FIXME: copied from dockart-- needs to put in a common place
672 #if defined( __WXMAC__ )
673 static unsigned char close_bits[]={
674 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
675 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
676 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
677 #elif defined( __WXGTK__)
678 static unsigned char close_bits[]={
679 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
680 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
681 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
682 #else
683 static unsigned char close_bits[]={
684 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
685 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
686 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
687 #endif
688
689 AddButton(101, BitmapFromBits(close_bits, 16, 16, *wxBLACK));
690 }
691
692
693 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
694 {
695 wxPaintDC dc(this);
696
697 dc.SetFont(GetFont());
698
699 if (GetPageCount() > 0)
700 Render(&dc);
701 }
702
703 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
704 {
705 }
706
707 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
708 {
709 wxSize s = evt.GetSize();
710 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
711 SetRect(r);
712 }
713
714 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
715 {
716 CaptureMouse();
717 m_click_pt = wxDefaultPosition;
718 m_is_dragging = false;
719 m_click_tab = -1;
720
721 wxWindow* wnd;
722 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
723 {
724 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
725 e.SetSelection(GetIdxFromWindow(wnd));
726 e.SetOldSelection(GetActivePage());
727 e.SetEventObject(this);
728 GetEventHandler()->ProcessEvent(e);
729
730 m_click_pt.x = evt.m_x;
731 m_click_pt.y = evt.m_y;
732 m_click_tab = e.GetSelection();
733 }
734
735 if (m_hover_button)
736 {
737 m_hover_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
738 Refresh();
739 Update();
740 }
741 }
742
743 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent&)
744 {
745 if (GetCapture() == this)
746 ReleaseMouse();
747
748 if (m_is_dragging)
749 {
750 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
751 evt.SetSelection(m_click_tab);
752 evt.SetOldSelection(m_click_tab);
753 evt.SetEventObject(this);
754 GetEventHandler()->ProcessEvent(evt);
755 return;
756 }
757
758 if (m_hover_button)
759 {
760 m_hover_button->cur_state = wxAUI_BUTTON_STATE_HOVER;
761 Refresh();
762 Update();
763
764 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
765 evt.SetInt(m_hover_button->id);
766 evt.SetEventObject(this);
767 GetEventHandler()->ProcessEvent(evt);
768 }
769
770 m_click_pt = wxDefaultPosition;
771 m_is_dragging = false;
772 m_click_tab = -1;
773 }
774
775 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
776 {
777 wxPoint pos = evt.GetPosition();
778
779 // check if the mouse is hovering above a button
780 wxAuiTabContainerButton* button;
781 if (ButtonHitTest(pos.x, pos.y, &button))
782 {
783 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
784 {
785 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
786 Refresh();
787 Update();
788 m_hover_button = button;
789 return;
790 }
791 }
792 else
793 {
794 if (m_hover_button)
795 {
796 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
797 m_hover_button = NULL;
798 Refresh();
799 Update();
800 }
801 }
802
803
804 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
805 return;
806
807 if (m_is_dragging)
808 {
809 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
810 evt.SetSelection(m_click_tab);
811 evt.SetOldSelection(m_click_tab);
812 evt.SetEventObject(this);
813 GetEventHandler()->ProcessEvent(evt);
814 return;
815 }
816
817
818 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
819 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
820
821 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
822 abs(pos.y - m_click_pt.y) > drag_y_threshold)
823 {
824 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
825 evt.SetSelection(m_click_tab);
826 evt.SetOldSelection(m_click_tab);
827 evt.SetEventObject(this);
828 GetEventHandler()->ProcessEvent(evt);
829
830 m_is_dragging = true;
831 }
832 }
833
834 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
835 {
836 if (m_hover_button)
837 {
838 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
839 m_hover_button = NULL;
840 Refresh();
841 Update();
842 }
843 }
844
845
846 // wxTabFrame is an interesting case. It's important that all child pages
847 // of the multi-notebook control are all actually children of that control
848 // (and not grandchildren). wxTabFrame facilitates this. There is one
849 // instance of wxTabFrame for each tab control inside the multi-notebook.
850 // It's important to know that wxTabFrame is not a real window, but it merely
851 // used to capture the dimensions/positioning of the internal tab control and
852 // it's managed page windows
853
854 class wxTabFrame : public wxWindow
855 {
856 public:
857
858 wxTabFrame()
859 {
860 m_tabs = NULL;
861 m_rect = wxRect(0,0,200,200);
862 m_tab_ctrl_height = 20;
863 }
864
865 void SetTabCtrlHeight(int h)
866 {
867 m_tab_ctrl_height = h;
868 }
869
870 void DoSetSize(int x, int y,
871 int width, int height,
872 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
873 {
874 m_rect = wxRect(x, y, width, height);
875 DoSizing();
876 }
877
878 void DoGetClientSize(int* x, int* y) const
879 {
880 *x = m_rect.width;
881 *y = m_rect.height;
882 }
883
884 bool Show( bool WXUNUSED(show = true) ) { return false; }
885
886 void DoSizing()
887 {
888 if (!m_tabs)
889 return;
890
891 int tab_height = wxMin(m_rect.height, m_tab_ctrl_height);
892 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, tab_height);
893 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, tab_height);
894 m_tabs->SetRect(wxRect(0, 0, m_rect.width, tab_height));
895 m_tabs->Refresh();
896 m_tabs->Update();
897
898 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
899 size_t i, page_count = pages.GetCount();
900
901 for (i = 0; i < page_count; ++i)
902 {
903 wxAuiNotebookPage& page = pages.Item(i);
904 page.window->SetSize(m_rect.x, m_rect.y+tab_height, m_rect.width, m_rect.height-tab_height);
905
906 if (page.window->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
907 {
908 wxTabMDIChildFrame* wnd = (wxTabMDIChildFrame*)page.window;
909 wnd->ApplyMDIChildFrameRect();
910 }
911 }
912 }
913
914 void DoGetSize(int* x, int* y) const
915 {
916 if (x)
917 *x = m_rect.GetWidth();
918 if (y)
919 *y = m_rect.GetHeight();
920 }
921
922 void Update()
923 {
924 // does nothing
925 }
926
927 public:
928
929 wxRect m_rect;
930 wxRect m_tab_rect;
931 wxAuiTabCtrl* m_tabs;
932 int m_tab_ctrl_height;
933 };
934
935
936
937
938
939 // -- wxAuiMultiNotebook class implementation --
940
941 BEGIN_EVENT_TABLE(wxAuiMultiNotebook, wxControl)
942 //EVT_ERASE_BACKGROUND(wxAuiMultiNotebook::OnEraseBackground)
943 //EVT_SIZE(wxAuiMultiNotebook::OnSize)
944 //EVT_LEFT_DOWN(wxAuiMultiNotebook::OnLeftDown)
945 EVT_CHILD_FOCUS(wxAuiMultiNotebook::OnChildFocus)
946 EVT_COMMAND_RANGE(10000, 10100,
947 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
948 wxAuiMultiNotebook::OnTabClicked)
949 EVT_COMMAND_RANGE(10000, 10100,
950 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
951 wxAuiMultiNotebook::OnTabBeginDrag)
952 EVT_COMMAND_RANGE(10000, 10100,
953 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
954 wxAuiMultiNotebook::OnTabEndDrag)
955 EVT_COMMAND_RANGE(10000, 10100,
956 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
957 wxAuiMultiNotebook::OnTabDragMotion)
958 EVT_COMMAND_RANGE(10000, 10100,
959 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
960 wxAuiMultiNotebook::OnTabButton)
961 END_EVENT_TABLE()
962
963 wxAuiMultiNotebook::wxAuiMultiNotebook()
964 {
965 m_curpage = -1;
966 m_tab_id_counter = 10000;
967 m_dummy_wnd = NULL;
968 m_tab_ctrl_height = 20;
969 }
970
971 wxAuiMultiNotebook::wxAuiMultiNotebook(wxWindow *parent,
972 wxWindowID id,
973 const wxPoint& pos,
974 const wxSize& size,
975 long style) : wxControl(parent, id, pos, size, style)
976 {
977 InitNotebook();
978 }
979
980 bool wxAuiMultiNotebook::Create(wxWindow* parent,
981 wxWindowID id,
982 const wxPoint& pos,
983 const wxSize& size,
984 long style)
985 {
986 if (!wxControl::Create(parent, id, pos, size, style))
987 return false;
988
989 InitNotebook();
990
991 return true;
992 }
993
994 // InitNotebook() contains common initialization
995 // code called by all constructors
996 void wxAuiMultiNotebook::InitNotebook()
997 {
998 m_curpage = -1;
999 m_tab_id_counter = 10000;
1000 m_dummy_wnd = NULL;
1001 m_tab_ctrl_height = 20;
1002
1003 m_normal_font = *wxNORMAL_FONT;
1004 m_selected_font = *wxNORMAL_FONT;
1005 m_selected_font.SetWeight(wxBOLD);
1006
1007 // choose a default for the tab height
1008 wxClientDC dc(this);
1009 int tx, ty;
1010 dc.SetFont(m_selected_font);
1011 dc.GetTextExtent(wxT("ABCDEFGHhijklm"), &tx, &ty);
1012 m_tab_ctrl_height = (ty*150)/100;
1013
1014 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
1015 m_dummy_wnd->SetSize(200, 200);
1016 m_dummy_wnd->Show(false);
1017
1018 m_mgr.SetManagedWindow(this);
1019
1020 m_mgr.AddPane(m_dummy_wnd,
1021 wxPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
1022
1023 m_mgr.Update();
1024 }
1025
1026 wxAuiMultiNotebook::~wxAuiMultiNotebook()
1027 {
1028 m_mgr.UnInit();
1029 }
1030
1031 void wxAuiMultiNotebook::SetArtProvider(wxTabArt* art)
1032 {
1033 m_tabs.SetArtProvider(art);
1034 }
1035
1036 wxTabArt* wxAuiMultiNotebook::GetArtProvider()
1037 {
1038 return m_tabs.GetArtProvider();
1039 }
1040
1041 bool wxAuiMultiNotebook::AddPage(wxWindow* page,
1042 const wxString& caption,
1043 bool select,
1044 const wxBitmap& bitmap)
1045 {
1046 return InsertPage(GetPageCount(), page, caption, select, bitmap);
1047 }
1048
1049 bool wxAuiMultiNotebook::InsertPage(size_t page_idx,
1050 wxWindow* page,
1051 const wxString& caption,
1052 bool select,
1053 const wxBitmap& bitmap)
1054 {
1055 wxAuiNotebookPage info;
1056 info.window = page;
1057 info.caption = caption;
1058 info.bitmap = bitmap;
1059 info.active = false;
1060
1061 // if there are currently no tabs, the first added
1062 // tab must be active
1063 if (m_tabs.GetPageCount() == 0)
1064 info.active = true;
1065
1066 m_tabs.InsertPage(page, info, page_idx);
1067
1068 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
1069 if (page_idx >= active_tabctrl->GetPageCount())
1070 active_tabctrl->AddPage(page, info);
1071 else
1072 active_tabctrl->InsertPage(page, info, page_idx);
1073
1074 DoSizing();
1075 active_tabctrl->DoShowHide();
1076
1077 if (select)
1078 {
1079 int idx = m_tabs.GetIdxFromWindow(page);
1080 wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiMultiNotebook::InsertPage()"));
1081
1082 SetSelection(idx);
1083 }
1084
1085 return true;
1086 }
1087
1088
1089 // DeletePage() removes a tab from the multi-notebook,
1090 // and destroys the window as well
1091 bool wxAuiMultiNotebook::DeletePage(size_t page_idx)
1092 {
1093 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1094 wxWindow* new_active = NULL;
1095
1096 // find out which onscreen tab ctrl owns this tab
1097 wxAuiTabCtrl* ctrl;
1098 int ctrl_idx;
1099 if (!FindTab(wnd, &ctrl, &ctrl_idx))
1100 return false;
1101
1102 // find a new page and set it as active
1103 int new_idx = ctrl_idx+1;
1104 if (new_idx >= (int)ctrl->GetPageCount())
1105 new_idx = ctrl_idx-1;
1106
1107 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
1108 {
1109 new_active = ctrl->GetWindowFromIdx(new_idx);
1110 }
1111 else
1112 {
1113 // set the active page to the first page that
1114 // isn't the one being deleted
1115 size_t i, page_count = m_tabs.GetPageCount();
1116 for (i = 0; i < page_count; ++i)
1117 {
1118 wxWindow* w = m_tabs.GetWindowFromIdx(i);
1119 if (wnd != w)
1120 {
1121 new_active = m_tabs.GetWindowFromIdx(i);
1122 break;
1123 }
1124 }
1125 }
1126
1127 // remove the tab from main catalog
1128 if (!m_tabs.RemovePage(wnd))
1129 return false;
1130
1131 // remove the tab from the onscreen tab ctrl
1132 ctrl->RemovePage(wnd);
1133
1134 // actually destroy the window now
1135 if (wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1136 {
1137 // delete the child frame with pending delete, as is
1138 // customary with frame windows
1139 if (!wxPendingDelete.Member(wnd))
1140 wxPendingDelete.Append(wnd);
1141 }
1142 else
1143 {
1144 wnd->Destroy();
1145 }
1146
1147 RemoveEmptyTabFrames();
1148
1149 // set new active pane
1150 if (new_active)
1151 {
1152 m_curpage = -1;
1153 SetSelection(m_tabs.GetIdxFromWindow(new_active));
1154 }
1155
1156 return true;
1157 }
1158
1159
1160
1161 // RemovePage() removes a tab from the multi-notebook,
1162 // but does not destroy the window
1163 bool wxAuiMultiNotebook::RemovePage(size_t page_idx)
1164 {
1165 // remove the tab from our own catalog
1166 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1167 if (!m_tabs.RemovePage(wnd))
1168 return false;
1169
1170 // remove the tab from the onscreen tab ctrl
1171 wxAuiTabCtrl* ctrl;
1172 int ctrl_idx;
1173 if (FindTab(wnd, &ctrl, &ctrl_idx))
1174 {
1175 ctrl->RemovePage(wnd);
1176 return true;
1177 }
1178
1179 return false;
1180 }
1181
1182 // SetPageText() changes the tab caption of the specified page
1183 bool wxAuiMultiNotebook::SetPageText(size_t page_idx, const wxString& text)
1184 {
1185 if (page_idx >= m_tabs.GetPageCount())
1186 return false;
1187
1188 // update our own tab catalog
1189 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
1190 page_info.caption = text;
1191
1192 // update what's on screen
1193 wxAuiTabCtrl* ctrl;
1194 int ctrl_idx;
1195 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
1196 {
1197 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
1198 info.caption = text;
1199 ctrl->Refresh();
1200 ctrl->Update();
1201 }
1202
1203 return true;
1204 }
1205
1206 // GetSelection() returns the index of the currently active page
1207 int wxAuiMultiNotebook::GetSelection() const
1208 {
1209 return m_curpage;
1210 }
1211
1212 // SetSelection() sets the currently active page
1213 size_t wxAuiMultiNotebook::SetSelection(size_t new_page)
1214 {
1215 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
1216 if (!wnd)
1217 return m_curpage;
1218
1219 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1220 evt.SetSelection(new_page);
1221 evt.SetOldSelection(m_curpage);
1222 evt.SetEventObject(this);
1223 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
1224 {
1225 // program allows the page change
1226 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
1227 (void)GetEventHandler()->ProcessEvent(evt);
1228
1229
1230
1231 wxAuiTabCtrl* ctrl;
1232 int ctrl_idx;
1233 if (FindTab(wnd, &ctrl, &ctrl_idx))
1234 {
1235 m_tabs.SetActivePage(wnd);
1236
1237 ctrl->SetActivePage(ctrl_idx);
1238 DoSizing();
1239 ctrl->DoShowHide();
1240
1241 int old_curpage = m_curpage;
1242 m_curpage = new_page;
1243
1244
1245 // set fonts
1246 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1247 size_t i, pane_count = all_panes.GetCount();
1248 for (i = 0; i < pane_count; ++i)
1249 {
1250 wxPaneInfo& pane = all_panes.Item(i);
1251 if (pane.name == wxT("dummy"))
1252 continue;
1253 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
1254 if (tabctrl != ctrl)
1255 tabctrl->SetSelectedFont(m_normal_font);
1256 else
1257 tabctrl->SetSelectedFont(m_selected_font);
1258 tabctrl->Refresh();
1259 }
1260
1261 wnd->SetFocus();
1262
1263 return old_curpage;
1264 }
1265 }
1266
1267 return m_curpage;
1268 }
1269
1270 // GetPageCount() returns the total number of
1271 // pages managed by the multi-notebook
1272 size_t wxAuiMultiNotebook::GetPageCount() const
1273 {
1274 return m_tabs.GetPageCount();
1275 }
1276
1277 // GetPage() returns the wxWindow pointer of the
1278 // specified page
1279 wxWindow* wxAuiMultiNotebook::GetPage(size_t page_idx) const
1280 {
1281 wxASSERT(page_idx < m_tabs.GetPageCount());
1282
1283 return m_tabs.GetWindowFromIdx(page_idx);
1284 }
1285
1286 // DoSizing() performs all sizing operations in each tab control
1287 void wxAuiMultiNotebook::DoSizing()
1288 {
1289 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1290 size_t i, pane_count = all_panes.GetCount();
1291 for (i = 0; i < pane_count; ++i)
1292 {
1293 if (all_panes.Item(i).name == wxT("dummy"))
1294 continue;
1295
1296 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1297 tabframe->DoSizing();
1298 }
1299 }
1300
1301 // GetActiveTabCtrl() returns the active tab control. It is
1302 // called to determine which control gets new windows being added
1303 wxAuiTabCtrl* wxAuiMultiNotebook::GetActiveTabCtrl()
1304 {
1305 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
1306 {
1307 wxAuiTabCtrl* ctrl;
1308 int idx;
1309
1310 // find the tab ctrl with the current page
1311 if (FindTab(m_tabs.GetPage(m_curpage).window,
1312 &ctrl, &idx))
1313 {
1314 return ctrl;
1315 }
1316 }
1317
1318 // no current page, just find the first tab ctrl
1319 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1320 size_t i, pane_count = all_panes.GetCount();
1321 for (i = 0; i < pane_count; ++i)
1322 {
1323 if (all_panes.Item(i).name == wxT("dummy"))
1324 continue;
1325
1326 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1327 return tabframe->m_tabs;
1328 }
1329
1330 // If there is no tabframe at all, create one
1331 wxTabFrame* tabframe = new wxTabFrame;
1332 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
1333 tabframe->m_tabs = new wxAuiTabCtrl(this,
1334 m_tab_id_counter++,
1335 wxDefaultPosition,
1336 wxDefaultSize,
1337 wxNO_BORDER);
1338 m_mgr.AddPane(tabframe,
1339 wxPaneInfo().Center().CaptionVisible(false));
1340
1341 m_mgr.Update();
1342
1343 return tabframe->m_tabs;
1344 }
1345
1346 // FindTab() finds the tab control that currently contains the window as well
1347 // as the index of the window in the tab control. It returns true if the
1348 // window was found, otherwise false.
1349 bool wxAuiMultiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
1350 {
1351 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1352 size_t i, pane_count = all_panes.GetCount();
1353 for (i = 0; i < pane_count; ++i)
1354 {
1355 if (all_panes.Item(i).name == wxT("dummy"))
1356 continue;
1357
1358 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1359
1360 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
1361 if (page_idx != -1)
1362 {
1363 *ctrl = tabframe->m_tabs;
1364 *idx = page_idx;
1365 return true;
1366 }
1367 }
1368
1369 return false;
1370 }
1371
1372
1373 void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent&)
1374 {
1375 }
1376
1377 void wxAuiMultiNotebook::OnSize(wxSizeEvent&)
1378 {
1379 }
1380
1381 void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent& command_evt)
1382 {
1383 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1384
1385 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
1386 wxASSERT(ctrl != NULL);
1387
1388 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
1389 wxASSERT(wnd != NULL);
1390
1391 int idx = m_tabs.GetIdxFromWindow(wnd);
1392 wxASSERT(idx != -1);
1393
1394 SetSelection(idx);
1395 }
1396
1397 void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent&)
1398 {
1399 }
1400
1401 void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent& evt)
1402 {
1403 wxPoint screen_pt = ::wxGetMousePosition();
1404 wxPoint client_pt = ScreenToClient(screen_pt);
1405 wxPoint zero(0,0);
1406
1407 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1408
1409 wxAuiTabCtrl* tab_ctrl = GetTabCtrlFromPoint(client_pt);
1410 if (tab_ctrl == src_tabs)
1411 {
1412 // inner-tabctrl dragging is not yet implemented
1413 m_mgr.HideHint();
1414 return;
1415 }
1416
1417 if (tab_ctrl)
1418 {
1419 wxRect hint_rect = tab_ctrl->GetRect();
1420 ClientToScreen(&hint_rect.x, &hint_rect.y);
1421 m_mgr.ShowHint(hint_rect);
1422 }
1423 else
1424 {
1425 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
1426 }
1427 }
1428
1429
1430
1431 void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
1432 {
1433 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1434
1435 m_mgr.HideHint();
1436
1437
1438 // get the mouse position, which will be used to determine the drop point
1439 wxPoint mouse_screen_pt = ::wxGetMousePosition();
1440 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
1441
1442
1443 // the src tab control is the control that fired this event
1444 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1445 wxAuiTabCtrl* dest_tabs = NULL;
1446
1447
1448 // If the pointer is in an existing tab frame, do a tab insert
1449 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
1450 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
1451 if (tab_frame)
1452 {
1453 dest_tabs = tab_frame->m_tabs;
1454
1455 if (dest_tabs == src_tabs)
1456 return;
1457 }
1458 else
1459 {
1460 // If there is no tabframe at all, create one
1461 wxTabFrame* new_tabs = new wxTabFrame;
1462 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
1463 new_tabs->m_tabs = new wxAuiTabCtrl(this,
1464 m_tab_id_counter++,
1465 wxDefaultPosition,
1466 wxDefaultSize,
1467 wxNO_BORDER);
1468 m_mgr.AddPane(new_tabs,
1469 wxPaneInfo().Bottom().CaptionVisible(false),
1470 mouse_client_pt);
1471 m_mgr.Update();
1472 dest_tabs = new_tabs->m_tabs;
1473 }
1474
1475
1476
1477 // remove the page from the source tabs
1478 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
1479 page_info.active = false;
1480 src_tabs->RemovePage(page_info.window);
1481 if (src_tabs->GetPageCount() > 0)
1482 {
1483 src_tabs->SetActivePage((size_t)0);
1484 src_tabs->DoShowHide();
1485 src_tabs->Refresh();
1486 }
1487
1488
1489
1490 // add the page to the destination tabs
1491 dest_tabs->AddPage(page_info.window, page_info);
1492
1493 if (src_tabs->GetPageCount() == 0)
1494 {
1495 RemoveEmptyTabFrames();
1496 }
1497
1498 DoSizing();
1499 dest_tabs->DoShowHide();
1500 dest_tabs->Refresh();
1501
1502 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
1503 }
1504
1505 wxAuiTabCtrl* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
1506 {
1507 // if we've just removed the last tab from the source
1508 // tab set, the remove the tab control completely
1509 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1510 size_t i, pane_count = all_panes.GetCount();
1511 for (i = 0; i < pane_count; ++i)
1512 {
1513 if (all_panes.Item(i).name == wxT("dummy"))
1514 continue;
1515
1516 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1517 if (tabframe->m_tab_rect.Contains(pt))
1518 return tabframe->m_tabs;
1519 }
1520
1521 return NULL;
1522 }
1523
1524 wxWindow* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
1525 {
1526 // if we've just removed the last tab from the source
1527 // tab set, the remove the tab control completely
1528 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1529 size_t i, pane_count = all_panes.GetCount();
1530 for (i = 0; i < pane_count; ++i)
1531 {
1532 if (all_panes.Item(i).name == wxT("dummy"))
1533 continue;
1534
1535 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1536 if (tabframe->m_tabs == tab_ctrl)
1537 {
1538 return tabframe;
1539 }
1540 }
1541
1542 return NULL;
1543 }
1544
1545 void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1546 {
1547 bool must_update = false;
1548
1549 // if we've just removed the last tab from the source
1550 // tab set, the remove the tab control completely
1551 wxPaneInfoArray all_panes = m_mgr.GetAllPanes();
1552 size_t i, pane_count = all_panes.GetCount();
1553 for (i = 0; i < pane_count; ++i)
1554 {
1555 if (all_panes.Item(i).name == wxT("dummy"))
1556 continue;
1557
1558 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
1559 if (tab_frame->m_tabs->GetPageCount() == 0)
1560 {
1561 m_mgr.DetachPane(tab_frame);
1562
1563 // use pending delete because sometimes during
1564 // window closing, refreshs are pending
1565 if (!wxPendingDelete.Member(tab_frame->m_tabs))
1566 wxPendingDelete.Append(tab_frame->m_tabs);
1567 //tab_frame->m_tabs->Destroy();
1568
1569 delete tab_frame;
1570 must_update = true;
1571 }
1572 }
1573
1574
1575 // check to see if there is still a center pane;
1576 // if there isn't, make a frame the center pane
1577 wxPaneInfoArray panes = m_mgr.GetAllPanes();
1578 pane_count = panes.GetCount();
1579 wxWindow* first_good = NULL;
1580 bool center_found = false;
1581 for (i = 0; i < pane_count; ++i)
1582 {
1583 if (panes.Item(i).name == wxT("dummy"))
1584 continue;
1585 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
1586 center_found = true;
1587 if (!first_good)
1588 first_good = panes.Item(i).window;
1589 }
1590
1591 if (!center_found && first_good)
1592 {
1593 m_mgr.GetPane(first_good).Centre();
1594 must_update = true;
1595 }
1596
1597 m_mgr.Update();
1598 }
1599
1600 void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent& evt)
1601 {
1602 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
1603 if (idx != -1 && idx != m_curpage)
1604 {
1605 SetSelection(idx);
1606 }
1607 }
1608
1609
1610 void wxAuiMultiNotebook::OnTabButton(wxCommandEvent& command_evt)
1611 {
1612 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1613 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1614
1615 int button_id = evt.GetInt();
1616
1617 if (button_id == wxAuiButtonClose)
1618 {
1619 int selection = tabs->GetActivePage();
1620
1621 if (selection != -1)
1622 {
1623 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
1624
1625 if (close_wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1626 {
1627 close_wnd->Close();
1628 }
1629 else
1630 {
1631 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
1632 DeletePage(main_idx);
1633 }
1634 }
1635 }
1636 }
1637
1638
1639
1640
1641 #endif // wxUSE_AUI