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