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