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