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