]> git.saurik.com Git - wxWidgets.git/blob - src/aui/auibook.cpp
3d423f25e68c51f035079e0d3091bfcbe3d4b676
[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: Jens Lody
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/clientdc.h"
28 #endif
29
30 #include "wx/aui/tabmdi.h"
31
32 #ifdef __WXMAC__
33 #include "wx/osx/private.h"
34 #endif
35
36 #include "wx/arrimpl.cpp"
37 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
38 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
39
40 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEvent);
41 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEvent);
42 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, wxAuiNotebookEvent);
43 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEvent);
44 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, wxAuiNotebookEvent);
45 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, wxAuiNotebookEvent);
46 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEvent);
47 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG, wxAuiNotebookEvent);
48 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, wxAuiNotebookEvent);
49 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, wxAuiNotebookEvent);
50 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, wxAuiNotebookEvent);
51 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, wxAuiNotebookEvent);
52 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, wxAuiNotebookEvent);
53 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, wxAuiNotebookEvent);
54 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, wxAuiNotebookEvent);
55 wxDEFINE_EVENT(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, wxAuiNotebookEvent);
56
57 IMPLEMENT_CLASS(wxAuiNotebook, wxControl)
58 IMPLEMENT_CLASS(wxAuiTabCtrl, wxControl)
59 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxBookCtrlEvent)
60
61
62 // -- wxAuiTabContainer class implementation --
63
64
65 // wxAuiTabContainer is a class which contains information about each
66 // tab. It also can render an entire tab control to a specified DC.
67 // It's not a window class itself, because this code will be used by
68 // the wxFrameMananger, where it is disadvantageous to have separate
69 // windows for each tab control in the case of "docked tabs"
70
71 // A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
72 // which can be used as a tab control in the normal sense.
73
74
75 wxAuiTabContainer::wxAuiTabContainer()
76 {
77 m_tabOffset = 0;
78 m_flags = 0;
79 m_art = new wxAuiDefaultTabArt;
80
81 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
82 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
83 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
84 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
85 }
86
87 wxAuiTabContainer::~wxAuiTabContainer()
88 {
89 delete m_art;
90 }
91
92 void wxAuiTabContainer::SetArtProvider(wxAuiTabArt* art)
93 {
94 delete m_art;
95 m_art = art;
96
97 if (m_art)
98 {
99 m_art->SetFlags(m_flags);
100 }
101 }
102
103 wxAuiTabArt* wxAuiTabContainer::GetArtProvider() const
104 {
105 return m_art;
106 }
107
108 void wxAuiTabContainer::SetFlags(unsigned int flags)
109 {
110 m_flags = flags;
111
112 // check for new close button settings
113 RemoveButton(wxAUI_BUTTON_LEFT);
114 RemoveButton(wxAUI_BUTTON_RIGHT);
115 RemoveButton(wxAUI_BUTTON_WINDOWLIST);
116 RemoveButton(wxAUI_BUTTON_CLOSE);
117
118
119 if (flags & wxAUI_NB_SCROLL_BUTTONS)
120 {
121 AddButton(wxAUI_BUTTON_LEFT, wxLEFT);
122 AddButton(wxAUI_BUTTON_RIGHT, wxRIGHT);
123 }
124
125 if (flags & wxAUI_NB_WINDOWLIST_BUTTON)
126 {
127 AddButton(wxAUI_BUTTON_WINDOWLIST, wxRIGHT);
128 }
129
130 if (flags & wxAUI_NB_CLOSE_BUTTON)
131 {
132 AddButton(wxAUI_BUTTON_CLOSE, wxRIGHT);
133 }
134
135 if (m_art)
136 {
137 m_art->SetFlags(m_flags);
138 }
139 }
140
141 unsigned int wxAuiTabContainer::GetFlags() const
142 {
143 return m_flags;
144 }
145
146
147 void wxAuiTabContainer::SetNormalFont(const wxFont& font)
148 {
149 m_art->SetNormalFont(font);
150 }
151
152 void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
153 {
154 m_art->SetSelectedFont(font);
155 }
156
157 void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
158 {
159 m_art->SetMeasuringFont(font);
160 }
161
162 void wxAuiTabContainer::SetColour(const wxColour& colour)
163 {
164 m_art->SetColour(colour);
165 }
166
167 void wxAuiTabContainer::SetActiveColour(const wxColour& colour)
168 {
169 m_art->SetActiveColour(colour);
170 }
171
172 void wxAuiTabContainer::SetRect(const wxRect& rect)
173 {
174 m_rect = rect;
175
176 if (m_art)
177 {
178 m_art->SetSizingInfo(rect.GetSize(), m_pages.GetCount());
179 }
180 }
181
182 bool wxAuiTabContainer::AddPage(wxWindow* page,
183 const wxAuiNotebookPage& info)
184 {
185 wxAuiNotebookPage page_info;
186 page_info = info;
187 page_info.window = page;
188
189 m_pages.Add(page_info);
190
191 // let the art provider know how many pages we have
192 if (m_art)
193 {
194 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
195 }
196
197 return true;
198 }
199
200 bool wxAuiTabContainer::InsertPage(wxWindow* page,
201 const wxAuiNotebookPage& info,
202 size_t idx)
203 {
204 wxAuiNotebookPage page_info;
205 page_info = info;
206 page_info.window = page;
207
208 if (idx >= m_pages.GetCount())
209 m_pages.Add(page_info);
210 else
211 m_pages.Insert(page_info, idx);
212
213 // let the art provider know how many pages we have
214 if (m_art)
215 {
216 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
217 }
218
219 return true;
220 }
221
222 bool wxAuiTabContainer::MovePage(wxWindow* page,
223 size_t new_idx)
224 {
225 int idx = GetIdxFromWindow(page);
226 if (idx == -1)
227 return false;
228
229 // get page entry, make a copy of it
230 wxAuiNotebookPage p = GetPage(idx);
231
232 // remove old page entry
233 RemovePage(page);
234
235 // insert page where it should be
236 InsertPage(page, p, new_idx);
237
238 return true;
239 }
240
241 bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
242 {
243 size_t i, page_count = m_pages.GetCount();
244 for (i = 0; i < page_count; ++i)
245 {
246 wxAuiNotebookPage& page = m_pages.Item(i);
247 if (page.window == wnd)
248 {
249 m_pages.RemoveAt(i);
250
251 // let the art provider know how many pages we have
252 if (m_art)
253 {
254 m_art->SetSizingInfo(m_rect.GetSize(), m_pages.GetCount());
255 }
256
257 return true;
258 }
259 }
260
261 return false;
262 }
263
264 bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
265 {
266 bool found = false;
267
268 size_t i, page_count = m_pages.GetCount();
269 for (i = 0; i < page_count; ++i)
270 {
271 wxAuiNotebookPage& page = m_pages.Item(i);
272 if (page.window == wnd)
273 {
274 page.active = true;
275 found = true;
276 }
277 else
278 {
279 page.active = false;
280 }
281 }
282
283 return found;
284 }
285
286 void wxAuiTabContainer::SetNoneActive()
287 {
288 size_t i, page_count = m_pages.GetCount();
289 for (i = 0; i < page_count; ++i)
290 {
291 wxAuiNotebookPage& page = m_pages.Item(i);
292 page.active = false;
293 }
294 }
295
296 bool wxAuiTabContainer::SetActivePage(size_t page)
297 {
298 if (page >= m_pages.GetCount())
299 return false;
300
301 return SetActivePage(m_pages.Item(page).window);
302 }
303
304 int wxAuiTabContainer::GetActivePage() const
305 {
306 size_t i, page_count = m_pages.GetCount();
307 for (i = 0; i < page_count; ++i)
308 {
309 wxAuiNotebookPage& page = m_pages.Item(i);
310 if (page.active)
311 return i;
312 }
313
314 return -1;
315 }
316
317 wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
318 {
319 if (idx >= m_pages.GetCount())
320 return NULL;
321
322 return m_pages[idx].window;
323 }
324
325 int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
326 {
327 const size_t page_count = m_pages.GetCount();
328 for ( size_t i = 0; i < page_count; ++i )
329 {
330 wxAuiNotebookPage& page = m_pages.Item(i);
331 if (page.window == wnd)
332 return i;
333 }
334 return wxNOT_FOUND;
335 }
336
337 wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
338 {
339 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
340
341 return m_pages[idx];
342 }
343
344 const wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx) const
345 {
346 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
347
348 return m_pages[idx];
349 }
350
351 wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
352 {
353 return m_pages;
354 }
355
356 size_t wxAuiTabContainer::GetPageCount() const
357 {
358 return m_pages.GetCount();
359 }
360
361 void wxAuiTabContainer::AddButton(int id,
362 int location,
363 const wxBitmap& normalBitmap,
364 const wxBitmap& disabledBitmap)
365 {
366 wxAuiTabContainerButton button;
367 button.id = id;
368 button.bitmap = normalBitmap;
369 button.disBitmap = disabledBitmap;
370 button.location = location;
371 button.curState = wxAUI_BUTTON_STATE_NORMAL;
372
373 m_buttons.Add(button);
374 }
375
376 void wxAuiTabContainer::RemoveButton(int id)
377 {
378 size_t i, button_count = m_buttons.GetCount();
379
380 for (i = 0; i < button_count; ++i)
381 {
382 if (m_buttons.Item(i).id == id)
383 {
384 m_buttons.RemoveAt(i);
385 return;
386 }
387 }
388 }
389
390
391
392 size_t wxAuiTabContainer::GetTabOffset() const
393 {
394 return m_tabOffset;
395 }
396
397 void wxAuiTabContainer::SetTabOffset(size_t offset)
398 {
399 m_tabOffset = offset;
400 }
401
402
403
404
405 // Render() renders the tab catalog to the specified DC
406 // It is a virtual function and can be overridden to
407 // provide custom drawing capabilities
408 void wxAuiTabContainer::Render(wxDC* raw_dc, wxWindow* wnd)
409 {
410 if (!raw_dc || !raw_dc->IsOk())
411 return;
412
413 wxMemoryDC dc;
414
415 // use the same layout direction as the window DC uses to ensure that the
416 // text is rendered correctly
417 dc.SetLayoutDirection(raw_dc->GetLayoutDirection());
418
419 wxBitmap bmp;
420 size_t i;
421 size_t page_count = m_pages.GetCount();
422 size_t button_count = m_buttons.GetCount();
423
424 // create off-screen bitmap
425 bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
426 dc.SelectObject(bmp);
427
428 if (!dc.IsOk())
429 return;
430
431 // find out if size of tabs is larger than can be
432 // afforded on screen
433 int total_width = 0;
434 int visible_width = 0;
435 for (i = 0; i < page_count; ++i)
436 {
437 wxAuiNotebookPage& page = m_pages.Item(i);
438
439 // determine if a close button is on this tab
440 bool close_button = false;
441 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
442 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
443 {
444 close_button = true;
445 }
446
447
448 int x_extent = 0;
449 wxSize size = m_art->GetTabSize(dc,
450 wnd,
451 page.caption,
452 page.bitmap,
453 page.active,
454 close_button ?
455 wxAUI_BUTTON_STATE_NORMAL :
456 wxAUI_BUTTON_STATE_HIDDEN,
457 &x_extent);
458
459 if (i+1 < page_count)
460 total_width += x_extent;
461 else
462 total_width += size.x;
463
464 if (i >= m_tabOffset)
465 {
466 if (i+1 < page_count)
467 visible_width += x_extent;
468 else
469 visible_width += size.x;
470 }
471 }
472
473 if (total_width > m_rect.GetWidth() || m_tabOffset != 0)
474 {
475 // show left/right buttons
476 for (i = 0; i < button_count; ++i)
477 {
478 wxAuiTabContainerButton& button = m_buttons.Item(i);
479 if (button.id == wxAUI_BUTTON_LEFT ||
480 button.id == wxAUI_BUTTON_RIGHT)
481 {
482 button.curState &= ~wxAUI_BUTTON_STATE_HIDDEN;
483 }
484 }
485 }
486 else
487 {
488 // hide left/right buttons
489 for (i = 0; i < button_count; ++i)
490 {
491 wxAuiTabContainerButton& button = m_buttons.Item(i);
492 if (button.id == wxAUI_BUTTON_LEFT ||
493 button.id == wxAUI_BUTTON_RIGHT)
494 {
495 button.curState |= wxAUI_BUTTON_STATE_HIDDEN;
496 }
497 }
498 }
499
500 // determine whether left button should be enabled
501 for (i = 0; i < button_count; ++i)
502 {
503 wxAuiTabContainerButton& button = m_buttons.Item(i);
504 if (button.id == wxAUI_BUTTON_LEFT)
505 {
506 if (m_tabOffset == 0)
507 button.curState |= wxAUI_BUTTON_STATE_DISABLED;
508 else
509 button.curState &= ~wxAUI_BUTTON_STATE_DISABLED;
510 }
511 if (button.id == wxAUI_BUTTON_RIGHT)
512 {
513 if (visible_width < m_rect.GetWidth() - ((int)button_count*16))
514 button.curState |= wxAUI_BUTTON_STATE_DISABLED;
515 else
516 button.curState &= ~wxAUI_BUTTON_STATE_DISABLED;
517 }
518 }
519
520
521
522 // draw background
523 m_art->DrawBackground(dc, wnd, m_rect);
524
525 // draw buttons
526 int left_buttons_width = 0;
527 int right_buttons_width = 0;
528
529 int offset = 0;
530
531 // draw the buttons on the right side
532 offset = m_rect.x + m_rect.width;
533 for (i = 0; i < button_count; ++i)
534 {
535 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
536
537 if (button.location != wxRIGHT)
538 continue;
539 if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
540 continue;
541
542 wxRect button_rect = m_rect;
543 button_rect.SetY(1);
544 button_rect.SetWidth(offset);
545
546 m_art->DrawButton(dc,
547 wnd,
548 button_rect,
549 button.id,
550 button.curState,
551 wxRIGHT,
552 &button.rect);
553
554 offset -= button.rect.GetWidth();
555 right_buttons_width += button.rect.GetWidth();
556 }
557
558
559
560 offset = 0;
561
562 // draw the buttons on the left side
563
564 for (i = 0; i < button_count; ++i)
565 {
566 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
567
568 if (button.location != wxLEFT)
569 continue;
570 if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
571 continue;
572
573 wxRect button_rect(offset, 1, 1000, m_rect.height);
574
575 m_art->DrawButton(dc,
576 wnd,
577 button_rect,
578 button.id,
579 button.curState,
580 wxLEFT,
581 &button.rect);
582
583 offset += button.rect.GetWidth();
584 left_buttons_width += button.rect.GetWidth();
585 }
586
587 offset = left_buttons_width;
588
589 if (offset == 0)
590 offset += m_art->GetIndentSize();
591
592
593 // prepare the tab-close-button array
594 // make sure tab button entries which aren't used are marked as hidden
595 for (i = page_count; i < m_tabCloseButtons.GetCount(); ++i)
596 m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
597
598 // make sure there are enough tab button entries to accommodate all tabs
599 while (m_tabCloseButtons.GetCount() < page_count)
600 {
601 wxAuiTabContainerButton tempbtn;
602 tempbtn.id = wxAUI_BUTTON_CLOSE;
603 tempbtn.location = wxCENTER;
604 tempbtn.curState = wxAUI_BUTTON_STATE_HIDDEN;
605 m_tabCloseButtons.Add(tempbtn);
606 }
607
608
609 // buttons before the tab offset must be set to hidden
610 for (i = 0; i < m_tabOffset; ++i)
611 {
612 m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
613 }
614
615
616 // draw the tabs
617
618 size_t active = 999;
619 int active_offset = 0;
620 wxRect active_rect;
621
622 int x_extent = 0;
623 wxRect rect = m_rect;
624 rect.y = 0;
625 rect.height = m_rect.height;
626
627 for (i = m_tabOffset; i < page_count; ++i)
628 {
629 wxAuiNotebookPage& page = m_pages.Item(i);
630 wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(i);
631
632 // determine if a close button is on this tab
633 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
634 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
635 {
636 if (tab_button.curState == wxAUI_BUTTON_STATE_HIDDEN)
637 {
638 tab_button.id = wxAUI_BUTTON_CLOSE;
639 tab_button.curState = wxAUI_BUTTON_STATE_NORMAL;
640 tab_button.location = wxCENTER;
641 }
642 }
643 else
644 {
645 tab_button.curState = wxAUI_BUTTON_STATE_HIDDEN;
646 }
647
648 rect.x = offset;
649 rect.width = m_rect.width - right_buttons_width - offset - 2;
650
651 if (rect.width <= 0)
652 break;
653
654 m_art->DrawTab(dc,
655 wnd,
656 page,
657 rect,
658 tab_button.curState,
659 &page.rect,
660 &tab_button.rect,
661 &x_extent);
662
663 if (page.active)
664 {
665 active = i;
666 active_offset = offset;
667 active_rect = rect;
668 }
669
670 offset += x_extent;
671 }
672
673
674 // make sure to deactivate buttons which are off the screen to the right
675 for (++i; i < m_tabCloseButtons.GetCount(); ++i)
676 {
677 m_tabCloseButtons.Item(i).curState = wxAUI_BUTTON_STATE_HIDDEN;
678 }
679
680
681 // draw the active tab again so it stands in the foreground
682 if (active >= m_tabOffset && active < m_pages.GetCount())
683 {
684 wxAuiNotebookPage& page = m_pages.Item(active);
685
686 wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(active);
687
688 rect.x = active_offset;
689 m_art->DrawTab(dc,
690 wnd,
691 page,
692 active_rect,
693 tab_button.curState,
694 &page.rect,
695 &tab_button.rect,
696 &x_extent);
697 }
698
699
700 raw_dc->Blit(m_rect.x, m_rect.y,
701 m_rect.GetWidth(), m_rect.GetHeight(),
702 &dc, 0, 0);
703 }
704
705 // Is the tab visible?
706 bool wxAuiTabContainer::IsTabVisible(int tabPage, int tabOffset, wxDC* dc, wxWindow* wnd)
707 {
708 if (!dc || !dc->IsOk())
709 return false;
710
711 size_t i;
712 size_t page_count = m_pages.GetCount();
713 size_t button_count = m_buttons.GetCount();
714
715 // Hasn't been rendered yet; assume it's visible
716 if (m_tabCloseButtons.GetCount() < page_count)
717 return true;
718
719 // First check if both buttons are disabled - if so, there's no need to
720 // check further for visibility.
721 int arrowButtonVisibleCount = 0;
722 for (i = 0; i < button_count; ++i)
723 {
724 wxAuiTabContainerButton& button = m_buttons.Item(i);
725 if (button.id == wxAUI_BUTTON_LEFT ||
726 button.id == wxAUI_BUTTON_RIGHT)
727 {
728 if ((button.curState & wxAUI_BUTTON_STATE_HIDDEN) == 0)
729 arrowButtonVisibleCount ++;
730 }
731 }
732
733 // Tab must be visible
734 if (arrowButtonVisibleCount == 0)
735 return true;
736
737 // If tab is less than the given offset, it must be invisible by definition
738 if (tabPage < tabOffset)
739 return false;
740
741 // draw buttons
742 int left_buttons_width = 0;
743 int right_buttons_width = 0;
744
745 int offset = 0;
746
747 // calculate size of the buttons on the right side
748 offset = m_rect.x + m_rect.width;
749 for (i = 0; i < button_count; ++i)
750 {
751 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
752
753 if (button.location != wxRIGHT)
754 continue;
755 if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
756 continue;
757
758 offset -= button.rect.GetWidth();
759 right_buttons_width += button.rect.GetWidth();
760 }
761
762 offset = 0;
763
764 // calculate size of the buttons on the left side
765 for (i = 0; i < button_count; ++i)
766 {
767 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
768
769 if (button.location != wxLEFT)
770 continue;
771 if (button.curState & wxAUI_BUTTON_STATE_HIDDEN)
772 continue;
773
774 offset += button.rect.GetWidth();
775 left_buttons_width += button.rect.GetWidth();
776 }
777
778 offset = left_buttons_width;
779
780 if (offset == 0)
781 offset += m_art->GetIndentSize();
782
783 wxRect active_rect;
784
785 wxRect rect = m_rect;
786 rect.y = 0;
787 rect.height = m_rect.height;
788
789 // See if the given page is visible at the given tab offset (effectively scroll position)
790 for (i = tabOffset; i < page_count; ++i)
791 {
792 wxAuiNotebookPage& page = m_pages.Item(i);
793 wxAuiTabContainerButton& tab_button = m_tabCloseButtons.Item(i);
794
795 rect.x = offset;
796 rect.width = m_rect.width - right_buttons_width - offset - 2;
797
798 if (rect.width <= 0)
799 return false; // haven't found the tab, and we've run out of space, so return false
800
801 int x_extent = 0;
802 m_art->GetTabSize(*dc,
803 wnd,
804 page.caption,
805 page.bitmap,
806 page.active,
807 tab_button.curState,
808 &x_extent);
809
810 offset += x_extent;
811
812 if (i == (size_t) tabPage)
813 {
814 // If not all of the tab is visible, and supposing there's space to display it all,
815 // we could do better so we return false.
816 if (((m_rect.width - right_buttons_width - offset - 2) <= 0) && ((m_rect.width - right_buttons_width - left_buttons_width) > x_extent))
817 return false;
818 else
819 return true;
820 }
821 }
822
823 // Shouldn't really get here, but if it does, assume the tab is visible to prevent
824 // further looping in calling code.
825 return true;
826 }
827
828 // Make the tab visible if it wasn't already
829 void wxAuiTabContainer::MakeTabVisible(int tabPage, wxWindow* win)
830 {
831 wxClientDC dc(win);
832 if (!IsTabVisible(tabPage, GetTabOffset(), & dc, win))
833 {
834 int i;
835 for (i = 0; i < (int) m_pages.GetCount(); i++)
836 {
837 if (IsTabVisible(tabPage, i, & dc, win))
838 {
839 SetTabOffset(i);
840 win->Refresh();
841 return;
842 }
843 }
844 }
845 }
846
847 // TabHitTest() tests if a tab was hit, passing the window pointer
848 // back if that condition was fulfilled. The function returns
849 // true if a tab was hit, otherwise false
850 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
851 {
852 if (!m_rect.Contains(x,y))
853 return false;
854
855 wxAuiTabContainerButton* btn = NULL;
856 if (ButtonHitTest(x, y, &btn) && !(btn->curState & wxAUI_BUTTON_STATE_DISABLED))
857 {
858 if (m_buttons.Index(*btn) != wxNOT_FOUND)
859 return false;
860 }
861
862 size_t i, page_count = m_pages.GetCount();
863
864 for (i = m_tabOffset; i < page_count; ++i)
865 {
866 wxAuiNotebookPage& page = m_pages.Item(i);
867 if (page.rect.Contains(x,y))
868 {
869 if (hit)
870 *hit = page.window;
871 return true;
872 }
873 }
874
875 return false;
876 }
877
878 // ButtonHitTest() tests if a button was hit. The function returns
879 // true if a button was hit, otherwise false
880 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
881 wxAuiTabContainerButton** hit) const
882 {
883 if (!m_rect.Contains(x,y))
884 return false;
885
886 size_t i, button_count;
887
888
889 button_count = m_buttons.GetCount();
890 for (i = 0; i < button_count; ++i)
891 {
892 wxAuiTabContainerButton& button = m_buttons.Item(i);
893 if (button.rect.Contains(x,y) &&
894 !(button.curState & wxAUI_BUTTON_STATE_HIDDEN ))
895 {
896 if (hit)
897 *hit = &button;
898 return true;
899 }
900 }
901
902 button_count = m_tabCloseButtons.GetCount();
903 for (i = 0; i < button_count; ++i)
904 {
905 wxAuiTabContainerButton& button = m_tabCloseButtons.Item(i);
906 if (button.rect.Contains(x,y) &&
907 !(button.curState & (wxAUI_BUTTON_STATE_HIDDEN |
908 wxAUI_BUTTON_STATE_DISABLED)))
909 {
910 if (hit)
911 *hit = &button;
912 return true;
913 }
914 }
915
916 return false;
917 }
918
919
920
921 // the utility function ShowWnd() is the same as show,
922 // except it handles wxAuiMDIChildFrame windows as well,
923 // as the Show() method on this class is "unplugged"
924 static void ShowWnd(wxWindow* wnd, bool show)
925 {
926 #if wxUSE_MDI
927 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
928 {
929 wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
930 cf->DoShow(show);
931 }
932 else
933 #endif
934 {
935 wnd->Show(show);
936 }
937 }
938
939
940 // DoShowHide() this function shows the active window, then
941 // hides all of the other windows (in that order)
942 void wxAuiTabContainer::DoShowHide()
943 {
944 wxAuiNotebookPageArray& pages = GetPages();
945 size_t i, page_count = pages.GetCount();
946
947 // show new active page first
948 for (i = 0; i < page_count; ++i)
949 {
950 wxAuiNotebookPage& page = pages.Item(i);
951 if (page.active)
952 {
953 ShowWnd(page.window, true);
954 break;
955 }
956 }
957
958 // hide all other pages
959 for (i = 0; i < page_count; ++i)
960 {
961 wxAuiNotebookPage& page = pages.Item(i);
962 if (!page.active)
963 ShowWnd(page.window, false);
964 }
965 }
966
967
968
969
970
971
972 // -- wxAuiTabCtrl class implementation --
973
974
975
976 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
977 EVT_PAINT(wxAuiTabCtrl::OnPaint)
978 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
979 EVT_SIZE(wxAuiTabCtrl::OnSize)
980 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
981 EVT_LEFT_DCLICK(wxAuiTabCtrl::OnLeftDClick)
982 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
983 EVT_MIDDLE_DOWN(wxAuiTabCtrl::OnMiddleDown)
984 EVT_MIDDLE_UP(wxAuiTabCtrl::OnMiddleUp)
985 EVT_RIGHT_DOWN(wxAuiTabCtrl::OnRightDown)
986 EVT_RIGHT_UP(wxAuiTabCtrl::OnRightUp)
987 EVT_MOTION(wxAuiTabCtrl::OnMotion)
988 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
989 EVT_AUINOTEBOOK_BUTTON(wxID_ANY, wxAuiTabCtrl::OnButton)
990 EVT_SET_FOCUS(wxAuiTabCtrl::OnSetFocus)
991 EVT_KILL_FOCUS(wxAuiTabCtrl::OnKillFocus)
992 EVT_CHAR(wxAuiTabCtrl::OnChar)
993 EVT_MOUSE_CAPTURE_LOST(wxAuiTabCtrl::OnCaptureLost)
994 END_EVENT_TABLE()
995
996
997 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
998 wxWindowID id,
999 const wxPoint& pos,
1000 const wxSize& size,
1001 long style) : wxControl(parent, id, pos, size, style)
1002 {
1003 SetName(wxT("wxAuiTabCtrl"));
1004 m_clickPt = wxDefaultPosition;
1005 m_isDragging = false;
1006 m_hoverButton = NULL;
1007 m_pressedButton = NULL;
1008 }
1009
1010 wxAuiTabCtrl::~wxAuiTabCtrl()
1011 {
1012 }
1013
1014 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
1015 {
1016 wxPaintDC dc(this);
1017
1018 dc.SetFont(GetFont());
1019
1020 if (GetPageCount() > 0)
1021 Render(&dc, this);
1022 }
1023
1024 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
1025 {
1026 }
1027
1028 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
1029 {
1030 wxSize s = evt.GetSize();
1031 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
1032 SetRect(r);
1033 }
1034
1035 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
1036 {
1037 CaptureMouse();
1038 m_clickPt = wxDefaultPosition;
1039 m_isDragging = false;
1040 m_clickTab = NULL;
1041 m_pressedButton = NULL;
1042
1043
1044 wxWindow* wnd;
1045 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
1046 {
1047 int new_selection = GetIdxFromWindow(wnd);
1048
1049 // wxAuiNotebooks always want to receive this event
1050 // even if the tab is already active, because they may
1051 // have multiple tab controls
1052 if (new_selection != GetActivePage() ||
1053 GetParent()->IsKindOf(CLASSINFO(wxAuiNotebook)))
1054 {
1055 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1056 e.SetSelection(new_selection);
1057 e.SetOldSelection(GetActivePage());
1058 e.SetEventObject(this);
1059 GetEventHandler()->ProcessEvent(e);
1060 }
1061
1062 m_clickPt.x = evt.m_x;
1063 m_clickPt.y = evt.m_y;
1064 m_clickTab = wnd;
1065 }
1066
1067 if (m_hoverButton)
1068 {
1069 m_pressedButton = m_hoverButton;
1070 m_pressedButton->curState = wxAUI_BUTTON_STATE_PRESSED;
1071 Refresh();
1072 Update();
1073 }
1074 }
1075
1076 void wxAuiTabCtrl::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
1077 {
1078 if (m_isDragging)
1079 {
1080 m_isDragging = false;
1081
1082 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG, m_windowId);
1083 evt.SetSelection(GetIdxFromWindow(m_clickTab));
1084 evt.SetOldSelection(evt.GetSelection());
1085 evt.SetEventObject(this);
1086 GetEventHandler()->ProcessEvent(evt);
1087 }
1088 }
1089
1090 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent& evt)
1091 {
1092 if (GetCapture() == this)
1093 ReleaseMouse();
1094
1095 if (m_isDragging)
1096 {
1097 m_isDragging = false;
1098
1099 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
1100 evt.SetSelection(GetIdxFromWindow(m_clickTab));
1101 evt.SetOldSelection(evt.GetSelection());
1102 evt.SetEventObject(this);
1103 GetEventHandler()->ProcessEvent(evt);
1104
1105 return;
1106 }
1107
1108 if (m_pressedButton)
1109 {
1110 // make sure we're still clicking the button
1111 wxAuiTabContainerButton* button = NULL;
1112 if (!ButtonHitTest(evt.m_x, evt.m_y, &button) ||
1113 button->curState & wxAUI_BUTTON_STATE_DISABLED)
1114 return;
1115
1116 if (button != m_pressedButton)
1117 {
1118 m_pressedButton = NULL;
1119 return;
1120 }
1121
1122 Refresh();
1123 Update();
1124
1125 if (!(m_pressedButton->curState & wxAUI_BUTTON_STATE_DISABLED))
1126 {
1127 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
1128 evt.SetSelection(GetIdxFromWindow(m_clickTab));
1129 evt.SetInt(m_pressedButton->id);
1130 evt.SetEventObject(this);
1131 GetEventHandler()->ProcessEvent(evt);
1132 }
1133
1134 m_pressedButton = NULL;
1135 }
1136
1137 m_clickPt = wxDefaultPosition;
1138 m_isDragging = false;
1139 m_clickTab = NULL;
1140 }
1141
1142 void wxAuiTabCtrl::OnMiddleUp(wxMouseEvent& evt)
1143 {
1144 wxWindow* wnd = NULL;
1145 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1146 return;
1147
1148 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
1149 e.SetEventObject(this);
1150 e.SetSelection(GetIdxFromWindow(wnd));
1151 GetEventHandler()->ProcessEvent(e);
1152 }
1153
1154 void wxAuiTabCtrl::OnMiddleDown(wxMouseEvent& evt)
1155 {
1156 wxWindow* wnd = NULL;
1157 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1158 return;
1159
1160 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
1161 e.SetEventObject(this);
1162 e.SetSelection(GetIdxFromWindow(wnd));
1163 GetEventHandler()->ProcessEvent(e);
1164 }
1165
1166 void wxAuiTabCtrl::OnRightUp(wxMouseEvent& evt)
1167 {
1168 wxWindow* wnd = NULL;
1169 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1170 return;
1171
1172 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
1173 e.SetEventObject(this);
1174 e.SetSelection(GetIdxFromWindow(wnd));
1175 GetEventHandler()->ProcessEvent(e);
1176 }
1177
1178 void wxAuiTabCtrl::OnRightDown(wxMouseEvent& evt)
1179 {
1180 wxWindow* wnd = NULL;
1181 if (!TabHitTest(evt.m_x, evt.m_y, &wnd))
1182 return;
1183
1184 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
1185 e.SetEventObject(this);
1186 e.SetSelection(GetIdxFromWindow(wnd));
1187 GetEventHandler()->ProcessEvent(e);
1188 }
1189
1190 void wxAuiTabCtrl::OnLeftDClick(wxMouseEvent& evt)
1191 {
1192 wxWindow* wnd;
1193 wxAuiTabContainerButton* button;
1194 if (!TabHitTest(evt.m_x, evt.m_y, &wnd) && !ButtonHitTest(evt.m_x, evt.m_y, &button))
1195 {
1196 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, m_windowId);
1197 e.SetEventObject(this);
1198 GetEventHandler()->ProcessEvent(e);
1199 }
1200 }
1201
1202 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
1203 {
1204 wxPoint pos = evt.GetPosition();
1205
1206 // check if the mouse is hovering above a button
1207 wxAuiTabContainerButton* button;
1208 if (ButtonHitTest(pos.x, pos.y, &button) && !(button->curState & wxAUI_BUTTON_STATE_DISABLED))
1209 {
1210 if (m_hoverButton && button != m_hoverButton)
1211 {
1212 m_hoverButton->curState = wxAUI_BUTTON_STATE_NORMAL;
1213 m_hoverButton = NULL;
1214 Refresh();
1215 Update();
1216 }
1217
1218 if (button->curState != wxAUI_BUTTON_STATE_HOVER)
1219 {
1220 button->curState = wxAUI_BUTTON_STATE_HOVER;
1221 Refresh();
1222 Update();
1223
1224 m_hoverButton = button;
1225 return;
1226 }
1227 }
1228 else
1229 {
1230 if (m_hoverButton)
1231 {
1232 m_hoverButton->curState = wxAUI_BUTTON_STATE_NORMAL;
1233 m_hoverButton = NULL;
1234 Refresh();
1235 Update();
1236 }
1237 }
1238
1239
1240 if (!evt.LeftIsDown() || m_clickPt == wxDefaultPosition)
1241 return;
1242
1243 if (m_isDragging)
1244 {
1245 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
1246 evt.SetSelection(GetIdxFromWindow(m_clickTab));
1247 evt.SetOldSelection(evt.GetSelection());
1248 evt.SetEventObject(this);
1249 GetEventHandler()->ProcessEvent(evt);
1250 return;
1251 }
1252
1253
1254 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
1255 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
1256
1257 if (abs(pos.x - m_clickPt.x) > drag_x_threshold ||
1258 abs(pos.y - m_clickPt.y) > drag_y_threshold)
1259 {
1260 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
1261 evt.SetSelection(GetIdxFromWindow(m_clickTab));
1262 evt.SetOldSelection(evt.GetSelection());
1263 evt.SetEventObject(this);
1264 GetEventHandler()->ProcessEvent(evt);
1265
1266 m_isDragging = true;
1267 }
1268 }
1269
1270 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
1271 {
1272 if (m_hoverButton)
1273 {
1274 m_hoverButton->curState = wxAUI_BUTTON_STATE_NORMAL;
1275 m_hoverButton = NULL;
1276 Refresh();
1277 Update();
1278 }
1279 }
1280
1281 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
1282 {
1283 int button = event.GetInt();
1284
1285 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
1286 {
1287 if (button == wxAUI_BUTTON_LEFT)
1288 {
1289 if (GetTabOffset() > 0)
1290 {
1291 SetTabOffset(GetTabOffset()-1);
1292 Refresh();
1293 Update();
1294 }
1295 }
1296 else
1297 {
1298 SetTabOffset(GetTabOffset()+1);
1299 Refresh();
1300 Update();
1301 }
1302 }
1303 else if (button == wxAUI_BUTTON_WINDOWLIST)
1304 {
1305 int idx = GetArtProvider()->ShowDropDown(this, m_pages, GetActivePage());
1306
1307 if (idx != -1)
1308 {
1309 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1310 e.SetSelection(idx);
1311 e.SetOldSelection(GetActivePage());
1312 e.SetEventObject(this);
1313 GetEventHandler()->ProcessEvent(e);
1314 }
1315 }
1316 else
1317 {
1318 event.Skip();
1319 }
1320 }
1321
1322 void wxAuiTabCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event))
1323 {
1324 Refresh();
1325 }
1326
1327 void wxAuiTabCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event))
1328 {
1329 Refresh();
1330 }
1331
1332 void wxAuiTabCtrl::OnChar(wxKeyEvent& event)
1333 {
1334 if (GetActivePage() == -1)
1335 {
1336 event.Skip();
1337 return;
1338 }
1339
1340 // We can't leave tab processing to the system; on Windows, tabs and keys
1341 // get eaten by the system and not processed properly if we specify both
1342 // wxTAB_TRAVERSAL and wxWANTS_CHARS. And if we specify just wxTAB_TRAVERSAL,
1343 // we don't key arrow key events.
1344
1345 int key = event.GetKeyCode();
1346
1347 if (key == WXK_NUMPAD_PAGEUP)
1348 key = WXK_PAGEUP;
1349 if (key == WXK_NUMPAD_PAGEDOWN)
1350 key = WXK_PAGEDOWN;
1351 if (key == WXK_NUMPAD_HOME)
1352 key = WXK_HOME;
1353 if (key == WXK_NUMPAD_END)
1354 key = WXK_END;
1355 if (key == WXK_NUMPAD_LEFT)
1356 key = WXK_LEFT;
1357 if (key == WXK_NUMPAD_RIGHT)
1358 key = WXK_RIGHT;
1359
1360 if (key == WXK_TAB || key == WXK_PAGEUP || key == WXK_PAGEDOWN)
1361 {
1362 bool bCtrlDown = event.ControlDown();
1363 bool bShiftDown = event.ShiftDown();
1364
1365 bool bForward = (key == WXK_TAB && !bShiftDown) || (key == WXK_PAGEDOWN);
1366 bool bWindowChange = (key == WXK_PAGEUP) || (key == WXK_PAGEDOWN) || bCtrlDown;
1367 bool bFromTab = (key == WXK_TAB);
1368
1369 wxAuiNotebook* nb = wxDynamicCast(GetParent(), wxAuiNotebook);
1370 if (!nb)
1371 {
1372 event.Skip();
1373 return;
1374 }
1375
1376 wxNavigationKeyEvent keyEvent;
1377 keyEvent.SetDirection(bForward);
1378 keyEvent.SetWindowChange(bWindowChange);
1379 keyEvent.SetFromTab(bFromTab);
1380 keyEvent.SetEventObject(nb);
1381
1382 if (!nb->GetEventHandler()->ProcessEvent(keyEvent))
1383 {
1384 // Not processed? Do an explicit tab into the page.
1385 wxWindow* win = GetWindowFromIdx(GetActivePage());
1386 if (win)
1387 win->SetFocus();
1388 }
1389 return;
1390 }
1391
1392 if (m_pages.GetCount() < 2)
1393 {
1394 event.Skip();
1395 return;
1396 }
1397
1398 int newPage = -1;
1399
1400 int forwardKey, backwardKey;
1401 if (GetLayoutDirection() == wxLayout_RightToLeft)
1402 {
1403 forwardKey = WXK_LEFT;
1404 backwardKey = WXK_RIGHT;
1405 }
1406 else
1407 {
1408 forwardKey = WXK_RIGHT;
1409 backwardKey = WXK_LEFT;
1410 }
1411
1412 if (key == forwardKey)
1413 {
1414 if (m_pages.GetCount() > 1)
1415 {
1416 if (GetActivePage() == -1)
1417 newPage = 0;
1418 else if (GetActivePage() < (int) (m_pages.GetCount() - 1))
1419 newPage = GetActivePage() + 1;
1420 }
1421 }
1422 else if (key == backwardKey)
1423 {
1424 if (m_pages.GetCount() > 1)
1425 {
1426 if (GetActivePage() == -1)
1427 newPage = (int) (m_pages.GetCount() - 1);
1428 else if (GetActivePage() > 0)
1429 newPage = GetActivePage() - 1;
1430 }
1431 }
1432 else if (key == WXK_HOME)
1433 {
1434 newPage = 0;
1435 }
1436 else if (key == WXK_END)
1437 {
1438 newPage = (int) (m_pages.GetCount() - 1);
1439 }
1440 else
1441 event.Skip();
1442
1443 if (newPage != -1)
1444 {
1445 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1446 e.SetSelection(newPage);
1447 e.SetOldSelection(newPage);
1448 e.SetEventObject(this);
1449 this->GetEventHandler()->ProcessEvent(e);
1450 }
1451 else
1452 event.Skip();
1453 }
1454
1455 // wxTabFrame is an interesting case. It's important that all child pages
1456 // of the multi-notebook control are all actually children of that control
1457 // (and not grandchildren). wxTabFrame facilitates this. There is one
1458 // instance of wxTabFrame for each tab control inside the multi-notebook.
1459 // It's important to know that wxTabFrame is not a real window, but it merely
1460 // used to capture the dimensions/positioning of the internal tab control and
1461 // it's managed page windows
1462
1463 class wxTabFrame : public wxWindow
1464 {
1465 public:
1466
1467 wxTabFrame()
1468 {
1469 m_tabs = NULL;
1470 m_rect = wxRect(0,0,200,200);
1471 m_tabCtrlHeight = 20;
1472 }
1473
1474 ~wxTabFrame()
1475 {
1476 wxDELETE(m_tabs);
1477 }
1478
1479 void SetTabCtrlHeight(int h)
1480 {
1481 m_tabCtrlHeight = h;
1482 }
1483
1484 protected:
1485 void DoSetSize(int x, int y,
1486 int width, int height,
1487 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
1488 {
1489 m_rect = wxRect(x, y, width, height);
1490 DoSizing();
1491 }
1492
1493 void DoGetClientSize(int* x, int* y) const
1494 {
1495 *x = m_rect.width;
1496 *y = m_rect.height;
1497 }
1498
1499 public:
1500 bool Show( bool WXUNUSED(show = true) ) { return false; }
1501
1502 void DoSizing()
1503 {
1504 if (!m_tabs)
1505 return;
1506
1507 if (m_tabs->IsFrozen() || m_tabs->GetParent()->IsFrozen())
1508 return;
1509
1510 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tabCtrlHeight);
1511 if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM)
1512 {
1513 m_tab_rect = wxRect (m_rect.x, m_rect.y + m_rect.height - m_tabCtrlHeight, m_rect.width, m_tabCtrlHeight);
1514 m_tabs->SetSize (m_rect.x, m_rect.y + m_rect.height - m_tabCtrlHeight, m_rect.width, m_tabCtrlHeight);
1515 m_tabs->SetRect (wxRect(0, 0, m_rect.width, m_tabCtrlHeight));
1516 }
1517 else //TODO: if (GetFlags() & wxAUI_NB_TOP)
1518 {
1519 m_tab_rect = wxRect (m_rect.x, m_rect.y, m_rect.width, m_tabCtrlHeight);
1520 m_tabs->SetSize (m_rect.x, m_rect.y, m_rect.width, m_tabCtrlHeight);
1521 m_tabs->SetRect (wxRect(0, 0, m_rect.width, m_tabCtrlHeight));
1522 }
1523 // TODO: else if (GetFlags() & wxAUI_NB_LEFT){}
1524 // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){}
1525
1526 m_tabs->Refresh();
1527 m_tabs->Update();
1528
1529 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
1530 size_t i, page_count = pages.GetCount();
1531
1532 for (i = 0; i < page_count; ++i)
1533 {
1534 int height = m_rect.height - m_tabCtrlHeight;
1535 if ( height < 0 )
1536 {
1537 // avoid passing negative height to wxWindow::SetSize(), this
1538 // results in assert failures/GTK+ warnings
1539 height = 0;
1540 }
1541
1542 wxAuiNotebookPage& page = pages.Item(i);
1543 if (m_tabs->GetFlags() & wxAUI_NB_BOTTOM)
1544 {
1545 page.window->SetSize(m_rect.x, m_rect.y, m_rect.width, height);
1546 }
1547 else //TODO: if (GetFlags() & wxAUI_NB_TOP)
1548 {
1549 page.window->SetSize(m_rect.x, m_rect.y + m_tabCtrlHeight,
1550 m_rect.width, height);
1551 }
1552 // TODO: else if (GetFlags() & wxAUI_NB_LEFT){}
1553 // TODO: else if (GetFlags() & wxAUI_NB_RIGHT){}
1554
1555 #if wxUSE_MDI
1556 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1557 {
1558 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
1559 wnd->ApplyMDIChildFrameRect();
1560 }
1561 #endif
1562 }
1563 }
1564
1565 protected:
1566 void DoGetSize(int* x, int* y) const
1567 {
1568 if (x)
1569 *x = m_rect.GetWidth();
1570 if (y)
1571 *y = m_rect.GetHeight();
1572 }
1573
1574 public:
1575 void Update()
1576 {
1577 // does nothing
1578 }
1579
1580 wxRect m_rect;
1581 wxRect m_tab_rect;
1582 wxAuiTabCtrl* m_tabs;
1583 int m_tabCtrlHeight;
1584 };
1585
1586
1587 const int wxAuiBaseTabCtrlId = 5380;
1588
1589
1590 // -- wxAuiNotebook class implementation --
1591
1592 #define EVT_AUI_RANGE(id1, id2, event, func) \
1593 wx__DECLARE_EVT2(event, id1, id2, wxAuiNotebookEventHandler(func))
1594
1595 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
1596 EVT_SIZE(wxAuiNotebook::OnSize)
1597 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocusNotebook)
1598 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1599 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
1600 wxAuiNotebook::OnTabClicked)
1601 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1602 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
1603 wxAuiNotebook::OnTabBeginDrag)
1604 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1605 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
1606 wxAuiNotebook::OnTabEndDrag)
1607 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1608 wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG,
1609 wxAuiNotebook::OnTabCancelDrag)
1610 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1611 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
1612 wxAuiNotebook::OnTabDragMotion)
1613 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1614 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
1615 wxAuiNotebook::OnTabButton)
1616 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1617 wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN,
1618 wxAuiNotebook::OnTabMiddleDown)
1619 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1620 wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP,
1621 wxAuiNotebook::OnTabMiddleUp)
1622 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1623 wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN,
1624 wxAuiNotebook::OnTabRightDown)
1625 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1626 wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
1627 wxAuiNotebook::OnTabRightUp)
1628 EVT_AUI_RANGE(wxAuiBaseTabCtrlId, wxAuiBaseTabCtrlId+500,
1629 wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK,
1630 wxAuiNotebook::OnTabBgDClick)
1631 EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKeyNotebook)
1632 END_EVENT_TABLE()
1633
1634 void wxAuiNotebook::Init()
1635 {
1636 m_curPage = -1;
1637 m_tabIdCounter = wxAuiBaseTabCtrlId;
1638 m_dummyWnd = NULL;
1639 m_tabCtrlHeight = 20;
1640 m_requestedBmpSize = wxDefaultSize;
1641 m_requestedTabCtrlHeight = -1;
1642 }
1643
1644 bool wxAuiNotebook::Create(wxWindow* parent,
1645 wxWindowID id,
1646 const wxPoint& pos,
1647 const wxSize& size,
1648 long style)
1649 {
1650 if (!wxControl::Create(parent, id, pos, size, style))
1651 return false;
1652
1653 InitNotebook(style);
1654
1655 return true;
1656 }
1657
1658 // InitNotebook() contains common initialization
1659 // code called by all constructors
1660 void wxAuiNotebook::InitNotebook(long style)
1661 {
1662 SetName(wxT("wxAuiNotebook"));
1663 m_curPage = -1;
1664 m_tabIdCounter = wxAuiBaseTabCtrlId;
1665 m_dummyWnd = NULL;
1666 m_flags = (unsigned int)style;
1667 m_tabCtrlHeight = 20;
1668
1669 m_normalFont = *wxNORMAL_FONT;
1670 m_selectedFont = *wxNORMAL_FONT;
1671 m_selectedFont.SetWeight(wxBOLD);
1672
1673 SetArtProvider(new wxAuiDefaultTabArt);
1674
1675 m_dummyWnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
1676 m_dummyWnd->SetSize(200, 200);
1677 m_dummyWnd->Show(false);
1678
1679 m_mgr.SetManagedWindow(this);
1680 m_mgr.SetFlags(wxAUI_MGR_DEFAULT);
1681 m_mgr.SetDockSizeConstraint(1.0, 1.0); // no dock size constraint
1682
1683 m_mgr.AddPane(m_dummyWnd,
1684 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().CaptionVisible(false).Show(false));
1685
1686 m_mgr.Update();
1687 }
1688
1689 wxAuiNotebook::~wxAuiNotebook()
1690 {
1691 // Indicate we're deleting pages
1692 SendDestroyEvent();
1693
1694 while ( GetPageCount() > 0 )
1695 DeletePage(0);
1696
1697 m_mgr.UnInit();
1698 }
1699
1700 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
1701 {
1702 m_tabs.SetArtProvider(art);
1703
1704 // Update the height and do nothing else if it did something but otherwise
1705 // (i.e. if the new art provider uses the same height as the old one) we
1706 // need to manually set the art provider for all tabs ourselves.
1707 if ( !UpdateTabCtrlHeight() )
1708 {
1709 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1710 const size_t pane_count = all_panes.GetCount();
1711 for (size_t i = 0; i < pane_count; ++i)
1712 {
1713 wxAuiPaneInfo& pane = all_panes.Item(i);
1714 if (pane.name == wxT("dummy"))
1715 continue;
1716 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
1717 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
1718 tabctrl->SetArtProvider(art->Clone());
1719 }
1720 }
1721 }
1722
1723 // SetTabCtrlHeight() is the highest-level override of the
1724 // tab height. A call to this function effectively enforces a
1725 // specified tab ctrl height, overriding all other considerations,
1726 // such as text or bitmap height. It overrides any call to
1727 // SetUniformBitmapSize(). Specifying a height of -1 reverts
1728 // any previous call and returns to the default behaviour
1729
1730 void wxAuiNotebook::SetTabCtrlHeight(int height)
1731 {
1732 m_requestedTabCtrlHeight = height;
1733
1734 // if window is already initialized, recalculate the tab height
1735 if (m_dummyWnd)
1736 {
1737 UpdateTabCtrlHeight();
1738 }
1739 }
1740
1741
1742 // SetUniformBitmapSize() ensures that all tabs will have
1743 // the same height, even if some tabs don't have bitmaps
1744 // Passing wxDefaultSize to this function will instruct
1745 // the control to use dynamic tab height-- so when a tab
1746 // with a large bitmap is added, the tab ctrl's height will
1747 // automatically increase to accommodate the bitmap
1748
1749 void wxAuiNotebook::SetUniformBitmapSize(const wxSize& size)
1750 {
1751 m_requestedBmpSize = size;
1752
1753 // if window is already initialized, recalculate the tab height
1754 if (m_dummyWnd)
1755 {
1756 UpdateTabCtrlHeight();
1757 }
1758 }
1759
1760 // UpdateTabCtrlHeight() does the actual tab resizing. It's meant
1761 // to be used internally
1762 bool wxAuiNotebook::UpdateTabCtrlHeight()
1763 {
1764 // get the tab ctrl height we will use
1765 int height = CalculateTabCtrlHeight();
1766
1767 // if the tab control height needs to change, update
1768 // all of our tab controls with the new height
1769 if (m_tabCtrlHeight == height)
1770 return false;
1771
1772 wxAuiTabArt* art = m_tabs.GetArtProvider();
1773
1774 m_tabCtrlHeight = height;
1775
1776 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1777 size_t i, pane_count = all_panes.GetCount();
1778 for (i = 0; i < pane_count; ++i)
1779 {
1780 wxAuiPaneInfo& pane = all_panes.Item(i);
1781 if (pane.name == wxT("dummy"))
1782 continue;
1783 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
1784 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
1785 tab_frame->SetTabCtrlHeight(m_tabCtrlHeight);
1786 tabctrl->SetArtProvider(art->Clone());
1787 tab_frame->DoSizing();
1788 }
1789
1790 return true;
1791 }
1792
1793 void wxAuiNotebook::UpdateHintWindowSize()
1794 {
1795 wxSize size = CalculateNewSplitSize();
1796
1797 // the placeholder hint window should be set to this size
1798 wxAuiPaneInfo& info = m_mgr.GetPane(wxT("dummy"));
1799 if (info.IsOk())
1800 {
1801 info.MinSize(size);
1802 info.BestSize(size);
1803 m_dummyWnd->SetSize(size);
1804 }
1805 }
1806
1807
1808 // calculates the size of the new split
1809 wxSize wxAuiNotebook::CalculateNewSplitSize()
1810 {
1811 // count number of tab controls
1812 int tab_ctrl_count = 0;
1813 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1814 size_t i, pane_count = all_panes.GetCount();
1815 for (i = 0; i < pane_count; ++i)
1816 {
1817 wxAuiPaneInfo& pane = all_panes.Item(i);
1818 if (pane.name == wxT("dummy"))
1819 continue;
1820 tab_ctrl_count++;
1821 }
1822
1823 wxSize new_split_size;
1824
1825 // if there is only one tab control, the first split
1826 // should happen around the middle
1827 if (tab_ctrl_count < 2)
1828 {
1829 new_split_size = GetClientSize();
1830 new_split_size.x /= 2;
1831 new_split_size.y /= 2;
1832 }
1833 else
1834 {
1835 // this is in place of a more complicated calculation
1836 // that needs to be implemented
1837 new_split_size = wxSize(180,180);
1838 }
1839
1840 return new_split_size;
1841 }
1842
1843 int wxAuiNotebook::CalculateTabCtrlHeight()
1844 {
1845 // if a fixed tab ctrl height is specified,
1846 // just return that instead of calculating a
1847 // tab height
1848 if (m_requestedTabCtrlHeight != -1)
1849 return m_requestedTabCtrlHeight;
1850
1851 // find out new best tab height
1852 wxAuiTabArt* art = m_tabs.GetArtProvider();
1853
1854 return art->GetBestTabCtrlSize(this,
1855 m_tabs.GetPages(),
1856 m_requestedBmpSize);
1857 }
1858
1859
1860 wxAuiTabArt* wxAuiNotebook::GetArtProvider() const
1861 {
1862 return m_tabs.GetArtProvider();
1863 }
1864
1865 void wxAuiNotebook::SetWindowStyleFlag(long style)
1866 {
1867 wxControl::SetWindowStyleFlag(style);
1868
1869 m_flags = (unsigned int)style;
1870
1871 // if the control is already initialized
1872 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
1873 {
1874 // let all of the tab children know about the new style
1875
1876 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1877 size_t i, pane_count = all_panes.GetCount();
1878 for (i = 0; i < pane_count; ++i)
1879 {
1880 wxAuiPaneInfo& pane = all_panes.Item(i);
1881 if (pane.name == wxT("dummy"))
1882 continue;
1883 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
1884 wxAuiTabCtrl* tabctrl = tabframe->m_tabs;
1885 tabctrl->SetFlags(m_flags);
1886 tabframe->DoSizing();
1887 tabctrl->Refresh();
1888 tabctrl->Update();
1889 }
1890 }
1891 }
1892
1893
1894 bool wxAuiNotebook::AddPage(wxWindow* page,
1895 const wxString& caption,
1896 bool select,
1897 const wxBitmap& bitmap)
1898 {
1899 return InsertPage(GetPageCount(), page, caption, select, bitmap);
1900 }
1901
1902 bool wxAuiNotebook::InsertPage(size_t page_idx,
1903 wxWindow* page,
1904 const wxString& caption,
1905 bool select,
1906 const wxBitmap& bitmap)
1907 {
1908 wxASSERT_MSG(page, wxT("page pointer must be non-NULL"));
1909 if (!page)
1910 return false;
1911
1912 page->Reparent(this);
1913
1914 wxAuiNotebookPage info;
1915 info.window = page;
1916 info.caption = caption;
1917 info.bitmap = bitmap;
1918 info.active = false;
1919
1920 // if there are currently no tabs, the first added
1921 // tab must be active
1922 if (m_tabs.GetPageCount() == 0)
1923 info.active = true;
1924
1925 m_tabs.InsertPage(page, info, page_idx);
1926
1927 // if that was the first page added, even if
1928 // select is false, it must become the "current page"
1929 // (though no select events will be fired)
1930 if (!select && m_tabs.GetPageCount() == 1)
1931 select = true;
1932 //m_curPage = GetPageIndex(page);
1933
1934 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
1935 if (page_idx >= active_tabctrl->GetPageCount())
1936 active_tabctrl->AddPage(page, info);
1937 else
1938 active_tabctrl->InsertPage(page, info, page_idx);
1939
1940 UpdateTabCtrlHeight();
1941 DoSizing();
1942 active_tabctrl->DoShowHide();
1943
1944 // adjust selected index
1945 if(m_curPage >= (int) page_idx)
1946 m_curPage++;
1947
1948 if (select)
1949 {
1950 SetSelectionToWindow(page);
1951 }
1952
1953 return true;
1954 }
1955
1956
1957 // DeletePage() removes a tab from the multi-notebook,
1958 // and destroys the window as well
1959 bool wxAuiNotebook::DeletePage(size_t page_idx)
1960 {
1961 if (page_idx >= m_tabs.GetPageCount())
1962 return false;
1963
1964 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1965
1966 // hide the window in advance, as this will
1967 // prevent flicker
1968 ShowWnd(wnd, false);
1969
1970 if (!RemovePage(page_idx))
1971 return false;
1972
1973 #if wxUSE_MDI
1974 // actually destroy the window now
1975 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1976 {
1977 // delete the child frame with pending delete, as is
1978 // customary with frame windows
1979 if (!wxPendingDelete.Member(wnd))
1980 wxPendingDelete.Append(wnd);
1981 }
1982 else
1983 #endif
1984 {
1985 wnd->Destroy();
1986 }
1987
1988 return true;
1989 }
1990
1991
1992
1993 // RemovePage() removes a tab from the multi-notebook,
1994 // but does not destroy the window
1995 bool wxAuiNotebook::RemovePage(size_t page_idx)
1996 {
1997 // save active window pointer
1998 wxWindow* active_wnd = NULL;
1999 if (m_curPage >= 0)
2000 active_wnd = m_tabs.GetWindowFromIdx(m_curPage);
2001
2002 // save pointer of window being deleted
2003 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2004 wxWindow* new_active = NULL;
2005
2006 // make sure we found the page
2007 if (!wnd)
2008 return false;
2009
2010 // find out which onscreen tab ctrl owns this tab
2011 wxAuiTabCtrl* ctrl;
2012 int ctrl_idx;
2013 if (!FindTab(wnd, &ctrl, &ctrl_idx))
2014 return false;
2015
2016 bool is_curpage = (m_curPage == (int)page_idx);
2017 bool is_active_in_split = ctrl->GetPage(ctrl_idx).active;
2018
2019
2020 // remove the tab from main catalog
2021 if (!m_tabs.RemovePage(wnd))
2022 return false;
2023
2024 // remove the tab from the onscreen tab ctrl
2025 ctrl->RemovePage(wnd);
2026
2027 if (is_active_in_split)
2028 {
2029 int ctrl_new_page_count = (int)ctrl->GetPageCount();
2030
2031 if (ctrl_idx >= ctrl_new_page_count)
2032 ctrl_idx = ctrl_new_page_count-1;
2033
2034 if (ctrl_idx >= 0 && ctrl_idx < (int)ctrl->GetPageCount())
2035 {
2036 // set new page as active in the tab split
2037 ctrl->SetActivePage(ctrl_idx);
2038
2039 // if the page deleted was the current page for the
2040 // entire tab control, then record the window
2041 // pointer of the new active page for activation
2042 if (is_curpage)
2043 {
2044 new_active = ctrl->GetWindowFromIdx(ctrl_idx);
2045 }
2046 }
2047 }
2048 else
2049 {
2050 // we are not deleting the active page, so keep it the same
2051 new_active = active_wnd;
2052 }
2053
2054
2055 if (!new_active)
2056 {
2057 // we haven't yet found a new page to active,
2058 // so select the next page from the main tab
2059 // catalogue
2060
2061 if (page_idx < m_tabs.GetPageCount())
2062 {
2063 new_active = m_tabs.GetPage(page_idx).window;
2064 }
2065
2066 if (!new_active && m_tabs.GetPageCount() > 0)
2067 {
2068 new_active = m_tabs.GetPage(0).window;
2069 }
2070 }
2071
2072
2073 RemoveEmptyTabFrames();
2074
2075 m_curPage = wxNOT_FOUND;
2076
2077 // set new active pane unless we're being destroyed anyhow
2078 if (new_active && !m_isBeingDeleted)
2079 SetSelectionToWindow(new_active);
2080
2081 return true;
2082 }
2083
2084 // GetPageIndex() returns the index of the page, or -1 if the
2085 // page could not be located in the notebook
2086 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2087 {
2088 return m_tabs.GetIdxFromWindow(page_wnd);
2089 }
2090
2091
2092
2093 // SetPageText() changes the tab caption of the specified page
2094 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2095 {
2096 if (page_idx >= m_tabs.GetPageCount())
2097 return false;
2098
2099 // update our own tab catalog
2100 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2101 page_info.caption = text;
2102
2103 // update what's on screen
2104 wxAuiTabCtrl* ctrl;
2105 int ctrl_idx;
2106 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2107 {
2108 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2109 info.caption = text;
2110 ctrl->Refresh();
2111 ctrl->Update();
2112 }
2113
2114 return true;
2115 }
2116
2117 // returns the page caption
2118 wxString wxAuiNotebook::GetPageText(size_t page_idx) const
2119 {
2120 if (page_idx >= m_tabs.GetPageCount())
2121 return wxEmptyString;
2122
2123 // update our own tab catalog
2124 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2125 return page_info.caption;
2126 }
2127
2128 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2129 {
2130 if (page_idx >= m_tabs.GetPageCount())
2131 return false;
2132
2133 // update our own tab catalog
2134 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2135 page_info.bitmap = bitmap;
2136
2137 // tab height might have changed
2138 UpdateTabCtrlHeight();
2139
2140 // update what's on screen
2141 wxAuiTabCtrl* ctrl;
2142 int ctrl_idx;
2143 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2144 {
2145 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2146 info.bitmap = bitmap;
2147 ctrl->Refresh();
2148 ctrl->Update();
2149 }
2150
2151 return true;
2152 }
2153
2154 // returns the page bitmap
2155 wxBitmap wxAuiNotebook::GetPageBitmap(size_t page_idx) const
2156 {
2157 if (page_idx >= m_tabs.GetPageCount())
2158 return wxBitmap();
2159
2160 // update our own tab catalog
2161 const wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2162 return page_info.bitmap;
2163 }
2164
2165 // GetSelection() returns the index of the currently active page
2166 int wxAuiNotebook::GetSelection() const
2167 {
2168 return m_curPage;
2169 }
2170
2171 // SetSelection() sets the currently active page
2172 int wxAuiNotebook::SetSelection(size_t new_page)
2173 {
2174 return DoModifySelection(new_page, true);
2175 }
2176
2177 void wxAuiNotebook::SetSelectionToWindow(wxWindow *win)
2178 {
2179 const int idx = m_tabs.GetIdxFromWindow(win);
2180 wxCHECK_RET( idx != wxNOT_FOUND, wxT("invalid notebook page") );
2181
2182
2183 // since a tab was clicked, let the parent know that we received
2184 // the focus, even if we will assign that focus immediately
2185 // to the child tab in the SetSelection call below
2186 // (the child focus event will also let wxAuiManager, if any,
2187 // know that the notebook control has been activated)
2188
2189 wxWindow* parent = GetParent();
2190 if (parent)
2191 {
2192 wxChildFocusEvent eventFocus(this);
2193 parent->GetEventHandler()->ProcessEvent(eventFocus);
2194 }
2195
2196
2197 SetSelection(idx);
2198 }
2199
2200 // GetPageCount() returns the total number of
2201 // pages managed by the multi-notebook
2202 size_t wxAuiNotebook::GetPageCount() const
2203 {
2204 return m_tabs.GetPageCount();
2205 }
2206
2207 // GetPage() returns the wxWindow pointer of the
2208 // specified page
2209 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2210 {
2211 wxASSERT(page_idx < m_tabs.GetPageCount());
2212
2213 return m_tabs.GetWindowFromIdx(page_idx);
2214 }
2215
2216 // DoSizing() performs all sizing operations in each tab control
2217 void wxAuiNotebook::DoSizing()
2218 {
2219 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2220 size_t i, pane_count = all_panes.GetCount();
2221 for (i = 0; i < pane_count; ++i)
2222 {
2223 if (all_panes.Item(i).name == wxT("dummy"))
2224 continue;
2225
2226 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2227 tabframe->DoSizing();
2228 }
2229 }
2230
2231 // GetActiveTabCtrl() returns the active tab control. It is
2232 // called to determine which control gets new windows being added
2233 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
2234 {
2235 if (m_curPage >= 0 && m_curPage < (int)m_tabs.GetPageCount())
2236 {
2237 wxAuiTabCtrl* ctrl;
2238 int idx;
2239
2240 // find the tab ctrl with the current page
2241 if (FindTab(m_tabs.GetPage(m_curPage).window,
2242 &ctrl, &idx))
2243 {
2244 return ctrl;
2245 }
2246 }
2247
2248 // no current page, just find the first tab ctrl
2249 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2250 size_t i, pane_count = all_panes.GetCount();
2251 for (i = 0; i < pane_count; ++i)
2252 {
2253 if (all_panes.Item(i).name == wxT("dummy"))
2254 continue;
2255
2256 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2257 return tabframe->m_tabs;
2258 }
2259
2260 // If there is no tabframe at all, create one
2261 wxTabFrame* tabframe = new wxTabFrame;
2262 tabframe->SetTabCtrlHeight(m_tabCtrlHeight);
2263 tabframe->m_tabs = new wxAuiTabCtrl(this,
2264 m_tabIdCounter++,
2265 wxDefaultPosition,
2266 wxDefaultSize,
2267 wxNO_BORDER|wxWANTS_CHARS);
2268 tabframe->m_tabs->SetFlags(m_flags);
2269 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2270 m_mgr.AddPane(tabframe,
2271 wxAuiPaneInfo().Center().CaptionVisible(false));
2272
2273 m_mgr.Update();
2274
2275 return tabframe->m_tabs;
2276 }
2277
2278 // FindTab() finds the tab control that currently contains the window as well
2279 // as the index of the window in the tab control. It returns true if the
2280 // window was found, otherwise false.
2281 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2282 {
2283 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2284 size_t i, pane_count = all_panes.GetCount();
2285 for (i = 0; i < pane_count; ++i)
2286 {
2287 if (all_panes.Item(i).name == wxT("dummy"))
2288 continue;
2289
2290 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2291
2292 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2293 if (page_idx != -1)
2294 {
2295 *ctrl = tabframe->m_tabs;
2296 *idx = page_idx;
2297 return true;
2298 }
2299 }
2300
2301 return false;
2302 }
2303
2304 void wxAuiNotebook::Split(size_t page, int direction)
2305 {
2306 wxSize cli_size = GetClientSize();
2307
2308 // get the page's window pointer
2309 wxWindow* wnd = GetPage(page);
2310 if (!wnd)
2311 return;
2312
2313 // notebooks with 1 or less pages can't be split
2314 if (GetPageCount() < 2)
2315 return;
2316
2317 // find out which tab control the page currently belongs to
2318 wxAuiTabCtrl *src_tabs, *dest_tabs;
2319 int src_idx = -1;
2320 src_tabs = NULL;
2321 if (!FindTab(wnd, &src_tabs, &src_idx))
2322 return;
2323 if (!src_tabs || src_idx == -1)
2324 return;
2325
2326 // choose a split size
2327 wxSize split_size;
2328 if (GetPageCount() > 2)
2329 {
2330 split_size = CalculateNewSplitSize();
2331 }
2332 else
2333 {
2334 // because there are two panes, always split them
2335 // equally
2336 split_size = GetClientSize();
2337 split_size.x /= 2;
2338 split_size.y /= 2;
2339 }
2340
2341
2342 // create a new tab frame
2343 wxTabFrame* new_tabs = new wxTabFrame;
2344 new_tabs->m_rect = wxRect(wxPoint(0,0), split_size);
2345 new_tabs->SetTabCtrlHeight(m_tabCtrlHeight);
2346 new_tabs->m_tabs = new wxAuiTabCtrl(this,
2347 m_tabIdCounter++,
2348 wxDefaultPosition,
2349 wxDefaultSize,
2350 wxNO_BORDER|wxWANTS_CHARS);
2351 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2352 new_tabs->m_tabs->SetFlags(m_flags);
2353 dest_tabs = new_tabs->m_tabs;
2354
2355 // create a pane info structure with the information
2356 // about where the pane should be added
2357 wxAuiPaneInfo paneInfo = wxAuiPaneInfo().Bottom().CaptionVisible(false);
2358 wxPoint mouse_pt;
2359
2360 if (direction == wxLEFT)
2361 {
2362 paneInfo.Left();
2363 mouse_pt = wxPoint(0, cli_size.y/2);
2364 }
2365 else if (direction == wxRIGHT)
2366 {
2367 paneInfo.Right();
2368 mouse_pt = wxPoint(cli_size.x, cli_size.y/2);
2369 }
2370 else if (direction == wxTOP)
2371 {
2372 paneInfo.Top();
2373 mouse_pt = wxPoint(cli_size.x/2, 0);
2374 }
2375 else if (direction == wxBOTTOM)
2376 {
2377 paneInfo.Bottom();
2378 mouse_pt = wxPoint(cli_size.x/2, cli_size.y);
2379 }
2380
2381 m_mgr.AddPane(new_tabs, paneInfo, mouse_pt);
2382 m_mgr.Update();
2383
2384 // remove the page from the source tabs
2385 wxAuiNotebookPage page_info = src_tabs->GetPage(src_idx);
2386 page_info.active = false;
2387 src_tabs->RemovePage(page_info.window);
2388 if (src_tabs->GetPageCount() > 0)
2389 {
2390 src_tabs->SetActivePage((size_t)0);
2391 src_tabs->DoShowHide();
2392 src_tabs->Refresh();
2393 }
2394
2395
2396 // add the page to the destination tabs
2397 dest_tabs->InsertPage(page_info.window, page_info, 0);
2398
2399 if (src_tabs->GetPageCount() == 0)
2400 {
2401 RemoveEmptyTabFrames();
2402 }
2403
2404 DoSizing();
2405 dest_tabs->DoShowHide();
2406 dest_tabs->Refresh();
2407
2408 // force the set selection function reset the selection
2409 m_curPage = -1;
2410
2411 // set the active page to the one we just split off
2412 SetSelectionToPage(page_info);
2413
2414 UpdateHintWindowSize();
2415 }
2416
2417
2418 void wxAuiNotebook::OnSize(wxSizeEvent& evt)
2419 {
2420 UpdateHintWindowSize();
2421
2422 evt.Skip();
2423 }
2424
2425 void wxAuiNotebook::OnTabClicked(wxAuiNotebookEvent& evt)
2426 {
2427 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2428 wxASSERT(ctrl != NULL);
2429
2430 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
2431 wxASSERT(wnd != NULL);
2432
2433 SetSelectionToWindow(wnd);
2434 }
2435
2436 void wxAuiNotebook::OnTabBgDClick(wxAuiNotebookEvent& WXUNUSED(evt))
2437 {
2438 // notify owner that the tabbar background has been double-clicked
2439 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, m_windowId);
2440 e.SetEventObject(this);
2441 GetEventHandler()->ProcessEvent(e);
2442 }
2443
2444 void wxAuiNotebook::OnTabBeginDrag(wxAuiNotebookEvent&)
2445 {
2446 m_lastDragX = 0;
2447 }
2448
2449 void wxAuiNotebook::OnTabDragMotion(wxAuiNotebookEvent& evt)
2450 {
2451 wxPoint screen_pt = ::wxGetMousePosition();
2452 wxPoint client_pt = ScreenToClient(screen_pt);
2453 wxPoint zero(0,0);
2454
2455 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2456 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
2457
2458 if (dest_tabs == src_tabs)
2459 {
2460 if (src_tabs)
2461 {
2462 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2463 }
2464
2465 // always hide the hint for inner-tabctrl drag
2466 m_mgr.HideHint();
2467
2468 // if tab moving is not allowed, leave
2469 if (!(m_flags & wxAUI_NB_TAB_MOVE))
2470 {
2471 return;
2472 }
2473
2474 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
2475 wxWindow* dest_location_tab;
2476
2477 // this is an inner-tab drag/reposition
2478 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
2479 {
2480 int src_idx = evt.GetSelection();
2481 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
2482
2483 // prevent jumpy drag
2484 if ((src_idx == dest_idx) || dest_idx == -1 ||
2485 (src_idx > dest_idx && m_lastDragX <= pt.x) ||
2486 (src_idx < dest_idx && m_lastDragX >= pt.x))
2487 {
2488 m_lastDragX = pt.x;
2489 return;
2490 }
2491
2492
2493 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
2494 dest_tabs->MovePage(src_tab, dest_idx);
2495 dest_tabs->SetActivePage((size_t)dest_idx);
2496 dest_tabs->DoShowHide();
2497 dest_tabs->Refresh();
2498 m_lastDragX = pt.x;
2499
2500 }
2501
2502 return;
2503 }
2504
2505
2506 // if external drag is allowed, check if the tab is being dragged
2507 // over a different wxAuiNotebook control
2508 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2509 {
2510 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
2511
2512 // if we aren't over any window, stop here
2513 if (!tab_ctrl)
2514 return;
2515
2516 // make sure we are not over the hint window
2517 if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
2518 {
2519 while (tab_ctrl)
2520 {
2521 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
2522 break;
2523 tab_ctrl = tab_ctrl->GetParent();
2524 }
2525
2526 if (tab_ctrl)
2527 {
2528 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2529
2530 if (nb != this)
2531 {
2532 wxRect hint_rect = tab_ctrl->GetClientRect();
2533 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
2534 m_mgr.ShowHint(hint_rect);
2535 return;
2536 }
2537 }
2538 }
2539 else
2540 {
2541 if (!dest_tabs)
2542 {
2543 // we are either over a hint window, or not over a tab
2544 // window, and there is no where to drag to, so exit
2545 return;
2546 }
2547 }
2548 }
2549
2550
2551 // if there are less than two panes, split can't happen, so leave
2552 if (m_tabs.GetPageCount() < 2)
2553 return;
2554
2555 // if tab moving is not allowed, leave
2556 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
2557 return;
2558
2559
2560 if (src_tabs)
2561 {
2562 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
2563 }
2564
2565
2566 if (dest_tabs)
2567 {
2568 wxRect hint_rect = dest_tabs->GetRect();
2569 ClientToScreen(&hint_rect.x, &hint_rect.y);
2570 m_mgr.ShowHint(hint_rect);
2571 }
2572 else
2573 {
2574 m_mgr.DrawHintRect(m_dummyWnd, client_pt, zero);
2575 }
2576 }
2577
2578
2579
2580 void wxAuiNotebook::OnTabEndDrag(wxAuiNotebookEvent& evt)
2581 {
2582 m_mgr.HideHint();
2583
2584
2585 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2586 wxCHECK_RET( src_tabs, wxT("no source object?") );
2587
2588 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2589
2590 // get the mouse position, which will be used to determine the drop point
2591 wxPoint mouse_screen_pt = ::wxGetMousePosition();
2592 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
2593
2594
2595
2596 // check for an external move
2597 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2598 {
2599 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
2600
2601 while (tab_ctrl)
2602 {
2603 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
2604 break;
2605 tab_ctrl = tab_ctrl->GetParent();
2606 }
2607
2608 if (tab_ctrl)
2609 {
2610 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2611
2612 if (nb != this)
2613 {
2614 // find out from the destination control
2615 // if it's ok to drop this tab here
2616 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
2617 e.SetSelection(evt.GetSelection());
2618 e.SetOldSelection(evt.GetSelection());
2619 e.SetEventObject(this);
2620 e.SetDragSource(this);
2621 e.Veto(); // dropping must be explicitly approved by control owner
2622
2623 nb->GetEventHandler()->ProcessEvent(e);
2624
2625 if (!e.IsAllowed())
2626 {
2627 // no answer or negative answer
2628 m_mgr.HideHint();
2629 return;
2630 }
2631
2632 // drop was allowed
2633 int src_idx = evt.GetSelection();
2634 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
2635
2636 // Check that it's not an impossible parent relationship
2637 wxWindow* p = nb;
2638 while (p && !p->IsTopLevel())
2639 {
2640 if (p == src_page)
2641 {
2642 return;
2643 }
2644 p = p->GetParent();
2645 }
2646
2647 // get main index of the page
2648 int main_idx = m_tabs.GetIdxFromWindow(src_page);
2649 wxCHECK_RET( main_idx != wxNOT_FOUND, wxT("no source page?") );
2650
2651
2652 // make a copy of the page info
2653 wxAuiNotebookPage page_info = m_tabs.GetPage(main_idx);
2654
2655 // remove the page from the source notebook
2656 RemovePage(main_idx);
2657
2658 // reparent the page
2659 src_page->Reparent(nb);
2660
2661
2662 // found out the insert idx
2663 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
2664 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2665
2666 wxWindow* target = NULL;
2667 int insert_idx = -1;
2668 dest_tabs->TabHitTest(pt.x, pt.y, &target);
2669 if (target)
2670 {
2671 insert_idx = dest_tabs->GetIdxFromWindow(target);
2672 }
2673
2674
2675 // add the page to the new notebook
2676 if (insert_idx == -1)
2677 insert_idx = dest_tabs->GetPageCount();
2678 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2679 nb->m_tabs.AddPage(page_info.window, page_info);
2680
2681 nb->DoSizing();
2682 dest_tabs->DoShowHide();
2683 dest_tabs->Refresh();
2684
2685 // set the selection in the destination tab control
2686 nb->SetSelectionToPage(page_info);
2687
2688 // notify owner that the tab has been dragged
2689 wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId);
2690 e2.SetSelection(evt.GetSelection());
2691 e2.SetOldSelection(evt.GetSelection());
2692 e2.SetEventObject(this);
2693 GetEventHandler()->ProcessEvent(e2);
2694
2695 return;
2696 }
2697 }
2698 }
2699
2700
2701
2702
2703 // only perform a tab split if it's allowed
2704 wxAuiTabCtrl* dest_tabs = NULL;
2705
2706 if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
2707 {
2708 // If the pointer is in an existing tab frame, do a tab insert
2709 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
2710 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
2711 int insert_idx = -1;
2712 if (tab_frame)
2713 {
2714 dest_tabs = tab_frame->m_tabs;
2715
2716 if (dest_tabs == src_tabs)
2717 return;
2718
2719
2720 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2721 wxWindow* target = NULL;
2722 dest_tabs->TabHitTest(pt.x, pt.y, &target);
2723 if (target)
2724 {
2725 insert_idx = dest_tabs->GetIdxFromWindow(target);
2726 }
2727 }
2728 else
2729 {
2730 wxPoint zero(0,0);
2731 wxRect rect = m_mgr.CalculateHintRect(m_dummyWnd,
2732 mouse_client_pt,
2733 zero);
2734 if (rect.IsEmpty())
2735 {
2736 // there is no suitable drop location here, exit out
2737 return;
2738 }
2739
2740 // If there is no tabframe at all, create one
2741 wxTabFrame* new_tabs = new wxTabFrame;
2742 new_tabs->m_rect = wxRect(wxPoint(0,0), CalculateNewSplitSize());
2743 new_tabs->SetTabCtrlHeight(m_tabCtrlHeight);
2744 new_tabs->m_tabs = new wxAuiTabCtrl(this,
2745 m_tabIdCounter++,
2746 wxDefaultPosition,
2747 wxDefaultSize,
2748 wxNO_BORDER|wxWANTS_CHARS);
2749 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2750 new_tabs->m_tabs->SetFlags(m_flags);
2751
2752 m_mgr.AddPane(new_tabs,
2753 wxAuiPaneInfo().Bottom().CaptionVisible(false),
2754 mouse_client_pt);
2755 m_mgr.Update();
2756 dest_tabs = new_tabs->m_tabs;
2757 }
2758
2759
2760
2761 // remove the page from the source tabs
2762 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
2763 page_info.active = false;
2764 src_tabs->RemovePage(page_info.window);
2765 if (src_tabs->GetPageCount() > 0)
2766 {
2767 src_tabs->SetActivePage((size_t)0);
2768 src_tabs->DoShowHide();
2769 src_tabs->Refresh();
2770 }
2771
2772
2773
2774 // add the page to the destination tabs
2775 if (insert_idx == -1)
2776 insert_idx = dest_tabs->GetPageCount();
2777 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2778
2779 if (src_tabs->GetPageCount() == 0)
2780 {
2781 RemoveEmptyTabFrames();
2782 }
2783
2784 DoSizing();
2785 dest_tabs->DoShowHide();
2786 dest_tabs->Refresh();
2787
2788 // force the set selection function reset the selection
2789 m_curPage = -1;
2790
2791 // set the active page to the one we just split off
2792 SetSelectionToPage(page_info);
2793
2794 UpdateHintWindowSize();
2795 }
2796
2797 // notify owner that the tab has been dragged
2798 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, m_windowId);
2799 e.SetSelection(evt.GetSelection());
2800 e.SetOldSelection(evt.GetSelection());
2801 e.SetEventObject(this);
2802 GetEventHandler()->ProcessEvent(e);
2803 }
2804
2805
2806
2807 void wxAuiNotebook::OnTabCancelDrag(wxAuiNotebookEvent& command_evt)
2808 {
2809 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2810
2811 m_mgr.HideHint();
2812
2813 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2814 wxCHECK_RET( src_tabs, wxT("no source object?") );
2815
2816 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2817 }
2818
2819 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
2820 {
2821 // if we've just removed the last tab from the source
2822 // tab set, the remove the tab control completely
2823 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2824 size_t i, pane_count = all_panes.GetCount();
2825 for (i = 0; i < pane_count; ++i)
2826 {
2827 if (all_panes.Item(i).name == wxT("dummy"))
2828 continue;
2829
2830 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2831 if (tabframe->m_tab_rect.Contains(pt))
2832 return tabframe->m_tabs;
2833 }
2834
2835 return NULL;
2836 }
2837
2838 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
2839 {
2840 // if we've just removed the last tab from the source
2841 // tab set, the remove the tab control completely
2842 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2843 size_t i, pane_count = all_panes.GetCount();
2844 for (i = 0; i < pane_count; ++i)
2845 {
2846 if (all_panes.Item(i).name == wxT("dummy"))
2847 continue;
2848
2849 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2850 if (tabframe->m_tabs == tab_ctrl)
2851 {
2852 return tabframe;
2853 }
2854 }
2855
2856 return NULL;
2857 }
2858
2859 void wxAuiNotebook::RemoveEmptyTabFrames()
2860 {
2861 // if we've just removed the last tab from the source
2862 // tab set, the remove the tab control completely
2863 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
2864 size_t i, pane_count = all_panes.GetCount();
2865 for (i = 0; i < pane_count; ++i)
2866 {
2867 if (all_panes.Item(i).name == wxT("dummy"))
2868 continue;
2869
2870 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
2871 if (tab_frame->m_tabs->GetPageCount() == 0)
2872 {
2873 m_mgr.DetachPane(tab_frame);
2874
2875 // use pending delete because sometimes during
2876 // window closing, refreshs are pending
2877 if (!wxPendingDelete.Member(tab_frame->m_tabs))
2878 wxPendingDelete.Append(tab_frame->m_tabs);
2879
2880 tab_frame->m_tabs = NULL;
2881
2882 delete tab_frame;
2883 }
2884 }
2885
2886
2887 // check to see if there is still a center pane;
2888 // if there isn't, make a frame the center pane
2889 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
2890 pane_count = panes.GetCount();
2891 wxWindow* first_good = NULL;
2892 bool center_found = false;
2893 for (i = 0; i < pane_count; ++i)
2894 {
2895 if (panes.Item(i).name == wxT("dummy"))
2896 continue;
2897 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
2898 center_found = true;
2899 if (!first_good)
2900 first_good = panes.Item(i).window;
2901 }
2902
2903 if (!center_found && first_good)
2904 {
2905 m_mgr.GetPane(first_good).Centre();
2906 }
2907
2908 if (!m_isBeingDeleted)
2909 m_mgr.Update();
2910 }
2911
2912 void wxAuiNotebook::OnChildFocusNotebook(wxChildFocusEvent& evt)
2913 {
2914 evt.Skip();
2915
2916 // if we're dragging a tab, don't change the current selection.
2917 // This code prevents a bug that used to happen when the hint window
2918 // was hidden. In the bug, the focus would return to the notebook
2919 // child, which would then enter this handler and call
2920 // SetSelection, which is not desired turn tab dragging.
2921
2922 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2923 size_t i, pane_count = all_panes.GetCount();
2924 for (i = 0; i < pane_count; ++i)
2925 {
2926 wxAuiPaneInfo& pane = all_panes.Item(i);
2927 if (pane.name == wxT("dummy"))
2928 continue;
2929 wxTabFrame* tabframe = (wxTabFrame*)pane.window;
2930 if (tabframe->m_tabs->IsDragging())
2931 return;
2932 }
2933
2934
2935 // change the tab selection to the child
2936 // which was focused
2937 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
2938 if (idx != -1 && idx != m_curPage)
2939 {
2940 SetSelection(idx);
2941 }
2942 }
2943
2944 void wxAuiNotebook::OnNavigationKeyNotebook(wxNavigationKeyEvent& event)
2945 {
2946 if ( event.IsWindowChange() ) {
2947 // change pages
2948 // FIXME: the problem with this is that if we have a split notebook,
2949 // we selection may go all over the place.
2950 AdvanceSelection(event.GetDirection());
2951 }
2952 else {
2953 // we get this event in 3 cases
2954 //
2955 // a) one of our pages might have generated it because the user TABbed
2956 // out from it in which case we should propagate the event upwards and
2957 // our parent will take care of setting the focus to prev/next sibling
2958 //
2959 // or
2960 //
2961 // b) the parent panel wants to give the focus to us so that we
2962 // forward it to our selected page. We can't deal with this in
2963 // OnSetFocus() because we don't know which direction the focus came
2964 // from in this case and so can't choose between setting the focus to
2965 // first or last panel child
2966 //
2967 // or
2968 //
2969 // c) we ourselves (see MSWTranslateMessage) generated the event
2970 //
2971 wxWindow * const parent = GetParent();
2972
2973 // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
2974 const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
2975 const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
2976
2977 if ( isFromParent || isFromSelf )
2978 {
2979 // no, it doesn't come from child, case (b) or (c): forward to a
2980 // page but only if direction is backwards (TAB) or from ourselves,
2981 if ( GetSelection() != wxNOT_FOUND &&
2982 (!event.GetDirection() || isFromSelf) )
2983 {
2984 // so that the page knows that the event comes from it's parent
2985 // and is being propagated downwards
2986 event.SetEventObject(this);
2987
2988 wxWindow *page = GetPage(GetSelection());
2989 if ( !page->GetEventHandler()->ProcessEvent(event) )
2990 {
2991 page->SetFocus();
2992 }
2993 //else: page manages focus inside it itself
2994 }
2995 else // otherwise set the focus to the notebook itself
2996 {
2997 SetFocus();
2998 }
2999 }
3000 else
3001 {
3002 // it comes from our child, case (a), pass to the parent, but only
3003 // if the direction is forwards. Otherwise set the focus to the
3004 // notebook itself. The notebook is always the 'first' control of a
3005 // page.
3006 if ( !event.GetDirection() )
3007 {
3008 SetFocus();
3009 }
3010 else if ( parent )
3011 {
3012 event.SetCurrentFocus(this);
3013 parent->GetEventHandler()->ProcessEvent(event);
3014 }
3015 }
3016 }
3017 }
3018
3019 void wxAuiNotebook::OnTabButton(wxAuiNotebookEvent& evt)
3020 {
3021 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3022
3023 int button_id = evt.GetInt();
3024
3025 if (button_id == wxAUI_BUTTON_CLOSE)
3026 {
3027 int selection = evt.GetSelection();
3028
3029 if (selection == -1)
3030 {
3031 // if the close button is to the right, use the active
3032 // page selection to determine which page to close
3033 selection = tabs->GetActivePage();
3034 }
3035
3036 if (selection != -1)
3037 {
3038 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3039
3040 // ask owner if it's ok to close the tab
3041 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3042 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3043 const int idx = m_tabs.GetIdxFromWindow(close_wnd);
3044 e.SetSelection(idx);
3045 e.SetOldSelection(evt.GetSelection());
3046 e.SetEventObject(this);
3047 GetEventHandler()->ProcessEvent(e);
3048 if (!e.IsAllowed())
3049 return;
3050
3051
3052 #if wxUSE_MDI
3053 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3054 {
3055 close_wnd->Close();
3056 }
3057 else
3058 #endif
3059 {
3060 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3061 wxCHECK_RET( main_idx != wxNOT_FOUND, wxT("no page to delete?") );
3062
3063 DeletePage(main_idx);
3064 }
3065
3066 // notify owner that the tab has been closed
3067 wxAuiNotebookEvent e2(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, m_windowId);
3068 e2.SetSelection(idx);
3069 e2.SetEventObject(this);
3070 GetEventHandler()->ProcessEvent(e2);
3071 }
3072 }
3073 }
3074
3075
3076 void wxAuiNotebook::OnTabMiddleDown(wxAuiNotebookEvent& evt)
3077 {
3078 // patch event through to owner
3079 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3080 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3081
3082 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, m_windowId);
3083 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3084 e.SetEventObject(this);
3085 GetEventHandler()->ProcessEvent(e);
3086 }
3087
3088 void wxAuiNotebook::OnTabMiddleUp(wxAuiNotebookEvent& evt)
3089 {
3090 // if the wxAUI_NB_MIDDLE_CLICK_CLOSE is specified, middle
3091 // click should act like a tab close action. However, first
3092 // give the owner an opportunity to handle the middle up event
3093 // for custom action
3094
3095 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3096 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3097
3098 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, m_windowId);
3099 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3100 e.SetEventObject(this);
3101 if (GetEventHandler()->ProcessEvent(e))
3102 return;
3103 if (!e.IsAllowed())
3104 return;
3105
3106 // check if we are supposed to close on middle-up
3107 if ((m_flags & wxAUI_NB_MIDDLE_CLICK_CLOSE) == 0)
3108 return;
3109
3110 // simulate the user pressing the close button on the tab
3111 evt.SetInt(wxAUI_BUTTON_CLOSE);
3112 OnTabButton(evt);
3113 }
3114
3115 void wxAuiNotebook::OnTabRightDown(wxAuiNotebookEvent& evt)
3116 {
3117 // patch event through to owner
3118 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3119 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3120
3121 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, m_windowId);
3122 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3123 e.SetEventObject(this);
3124 GetEventHandler()->ProcessEvent(e);
3125 }
3126
3127 void wxAuiNotebook::OnTabRightUp(wxAuiNotebookEvent& evt)
3128 {
3129 // patch event through to owner
3130 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3131 wxWindow* wnd = tabs->GetWindowFromIdx(evt.GetSelection());
3132
3133 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, m_windowId);
3134 e.SetSelection(m_tabs.GetIdxFromWindow(wnd));
3135 e.SetEventObject(this);
3136 GetEventHandler()->ProcessEvent(e);
3137 }
3138
3139 // Sets the normal font
3140 void wxAuiNotebook::SetNormalFont(const wxFont& font)
3141 {
3142 m_normalFont = font;
3143 GetArtProvider()->SetNormalFont(font);
3144 }
3145
3146 // Sets the selected tab font
3147 void wxAuiNotebook::SetSelectedFont(const wxFont& font)
3148 {
3149 m_selectedFont = font;
3150 GetArtProvider()->SetSelectedFont(font);
3151 }
3152
3153 // Sets the measuring font
3154 void wxAuiNotebook::SetMeasuringFont(const wxFont& font)
3155 {
3156 GetArtProvider()->SetMeasuringFont(font);
3157 }
3158
3159 // Sets the tab font
3160 bool wxAuiNotebook::SetFont(const wxFont& font)
3161 {
3162 wxControl::SetFont(font);
3163
3164 wxFont normalFont(font);
3165 wxFont selectedFont(normalFont);
3166 selectedFont.SetWeight(wxBOLD);
3167
3168 SetNormalFont(normalFont);
3169 SetSelectedFont(selectedFont);
3170 SetMeasuringFont(selectedFont);
3171
3172 return true;
3173 }
3174
3175 // Gets the tab control height
3176 int wxAuiNotebook::GetTabCtrlHeight() const
3177 {
3178 return m_tabCtrlHeight;
3179 }
3180
3181 // Gets the height of the notebook for a given page height
3182 int wxAuiNotebook::GetHeightForPageHeight(int pageHeight)
3183 {
3184 UpdateTabCtrlHeight();
3185
3186 int tabCtrlHeight = GetTabCtrlHeight();
3187 int decorHeight = 2;
3188 return tabCtrlHeight + pageHeight + decorHeight;
3189 }
3190
3191 // Advances the selection, generation page selection events
3192 void wxAuiNotebook::AdvanceSelection(bool forward)
3193 {
3194 if (GetPageCount() <= 1)
3195 return;
3196
3197 int currentSelection = GetSelection();
3198
3199 if (forward)
3200 {
3201 if (currentSelection == (int) (GetPageCount() - 1))
3202 return;
3203 else if (currentSelection == -1)
3204 currentSelection = 0;
3205 else
3206 currentSelection ++;
3207 }
3208 else
3209 {
3210 if (currentSelection <= 0)
3211 return;
3212 else
3213 currentSelection --;
3214 }
3215
3216 SetSelection(currentSelection);
3217 }
3218
3219 // Shows the window menu
3220 bool wxAuiNotebook::ShowWindowMenu()
3221 {
3222 wxAuiTabCtrl* tabCtrl = GetActiveTabCtrl();
3223
3224 int idx = tabCtrl->GetArtProvider()->ShowDropDown(tabCtrl, tabCtrl->GetPages(), tabCtrl->GetActivePage());
3225
3226 if (idx != -1)
3227 {
3228 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl->GetId());
3229 e.SetSelection(idx);
3230 e.SetOldSelection(tabCtrl->GetActivePage());
3231 e.SetEventObject(tabCtrl);
3232 GetEventHandler()->ProcessEvent(e);
3233
3234 return true;
3235 }
3236 else
3237 return false;
3238 }
3239
3240 void wxAuiNotebook::Thaw()
3241 {
3242 DoSizing();
3243
3244 wxControl::Thaw();
3245 }
3246
3247 void wxAuiNotebook::SetPageSize (const wxSize& WXUNUSED(size))
3248 {
3249 wxFAIL_MSG("Not implemented for wxAuiNotebook");
3250 }
3251
3252 int wxAuiNotebook::HitTest (const wxPoint& WXUNUSED(pt), long* WXUNUSED(flags)) const
3253 {
3254 wxFAIL_MSG("Not implemented for wxAuiNotebook");
3255 return wxNOT_FOUND;
3256 }
3257
3258 int wxAuiNotebook::GetPageImage(size_t WXUNUSED(n)) const
3259 {
3260 wxFAIL_MSG("Not implemented for wxAuiNotebook");
3261 return -1;
3262 }
3263
3264 bool wxAuiNotebook::SetPageImage(size_t n, int imageId)
3265 {
3266 return SetPageBitmap(n, GetImageList()->GetBitmap(imageId));
3267 }
3268
3269 wxWindow* wxAuiNotebook::GetCurrentPage () const
3270 {
3271 const int sel = GetSelection();
3272
3273 return sel == wxNOT_FOUND ? NULL : GetPage(sel);
3274 }
3275
3276 int wxAuiNotebook::ChangeSelection(size_t n)
3277 {
3278 return DoModifySelection(n, false);
3279 }
3280
3281 bool wxAuiNotebook::AddPage(wxWindow *page, const wxString &text, bool select,
3282 int imageId)
3283 {
3284 if(HasImageList())
3285 {
3286 return AddPage(page, text, select, GetImageList()->GetBitmap(imageId));
3287 }
3288 else
3289 {
3290 return AddPage(page, text, select, wxNullBitmap);
3291 }
3292 }
3293
3294 bool wxAuiNotebook::DeleteAllPages()
3295 {
3296 size_t count = GetPageCount();
3297 for(size_t i = 0; i < count; i++)
3298 {
3299 DeletePage(0);
3300 }
3301 return true;
3302 }
3303
3304 bool wxAuiNotebook::InsertPage(size_t index, wxWindow *page,
3305 const wxString &text, bool select,
3306 int imageId)
3307 {
3308 if(HasImageList())
3309 {
3310 return InsertPage(index, page, text, select,
3311 GetImageList()->GetBitmap(imageId));
3312 }
3313 else
3314 {
3315 return InsertPage(index, page, text, select, wxNullBitmap);
3316 }
3317 }
3318
3319 int wxAuiNotebook::DoModifySelection(size_t n, bool events)
3320 {
3321 wxWindow* wnd = m_tabs.GetWindowFromIdx(n);
3322 if (!wnd)
3323 return m_curPage;
3324
3325 // don't change the page unless necessary;
3326 // however, clicking again on a tab should give it the focus.
3327 if ((int)n == m_curPage)
3328 {
3329 wxAuiTabCtrl* ctrl;
3330 int ctrl_idx;
3331 if (FindTab(wnd, &ctrl, &ctrl_idx))
3332 {
3333 if (FindFocus() != ctrl)
3334 ctrl->SetFocus();
3335 }
3336 return m_curPage;
3337 }
3338
3339 bool vetoed = false;
3340
3341 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
3342
3343 if(events)
3344 {
3345 evt.SetSelection(n);
3346 evt.SetOldSelection(m_curPage);
3347 evt.SetEventObject(this);
3348 GetEventHandler()->ProcessEvent(evt);
3349 vetoed = !evt.IsAllowed();
3350 }
3351
3352 if (!vetoed)
3353 {
3354 int old_curpage = m_curPage;
3355 m_curPage = n;
3356
3357 // program allows the page change
3358 if(events)
3359 {
3360 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
3361 (void)GetEventHandler()->ProcessEvent(evt);
3362 }
3363
3364
3365 wxAuiTabCtrl* ctrl;
3366 int ctrl_idx;
3367 if (FindTab(wnd, &ctrl, &ctrl_idx))
3368 {
3369 m_tabs.SetActivePage(wnd);
3370
3371 ctrl->SetActivePage(ctrl_idx);
3372 DoSizing();
3373 ctrl->DoShowHide();
3374
3375 ctrl->MakeTabVisible(ctrl_idx, ctrl);
3376
3377 // set fonts
3378 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3379 size_t i, pane_count = all_panes.GetCount();
3380 for (i = 0; i < pane_count; ++i)
3381 {
3382 wxAuiPaneInfo& pane = all_panes.Item(i);
3383 if (pane.name == wxT("dummy"))
3384 continue;
3385 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
3386 if (tabctrl != ctrl)
3387 tabctrl->SetSelectedFont(m_normalFont);
3388 else
3389 tabctrl->SetSelectedFont(m_selectedFont);
3390 tabctrl->Refresh();
3391 }
3392
3393 // Set the focus to the page if we're not currently focused on the tab.
3394 // This is Firefox-like behaviour.
3395 if (wnd->IsShownOnScreen() && FindFocus() != ctrl)
3396 wnd->SetFocus();
3397
3398 return old_curpage;
3399 }
3400 }
3401
3402 return m_curPage;
3403 }
3404
3405
3406 #endif // wxUSE_AUI