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