]> git.saurik.com Git - wxWidgets.git/blob - src/aui/auibook.cpp
aui notebook button enabling/disabling implemented
[wxWidgets.git] / src / aui / auibook.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/auibook.cpp
3 // Purpose: wxaui: wx advanced user interface - notebook
4 // Author: Benjamin I. Williams
5 // Modified by:
6 // Created: 2006-06-28
7 // Copyright: (C) Copyright 2006, Kirix Corporation, All Rights Reserved
8 // Licence: wxWindows Library Licence, Version 3.1
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ----------------------------------------------------------------------------
12 // headers
13 // ----------------------------------------------------------------------------
14
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #if wxUSE_AUI
22
23 #include "wx/aui/auibook.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/settings.h"
27 #include "wx/image.h"
28 #endif
29
30 #include "wx/aui/tabmdi.h"
31 #include "wx/dcbuffer.h"
32
33 #include "wx/arrimpl.cpp"
34 WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
35 WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
36
37 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING)
38 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
39 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
40 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
41 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
42 DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
43
44
45
46 IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
47
48
49
50
51
52 // This functions are here for this proof of concept
53 // and will be factored out later. See dockart.cpp
54 static wxColor StepColour(const wxColor& c, int percent)
55 {
56 int r = c.Red(), g = c.Green(), b = c.Blue();
57 return wxColour((unsigned char)wxMin((r*percent)/100,255),
58 (unsigned char)wxMin((g*percent)/100,255),
59 (unsigned char)wxMin((b*percent)/100,255));
60 }
61
62 // This functions are here for this proof of concept
63 // and will be factored out later. See dockart.cpp
64 static wxBitmap BitmapFromBits(const unsigned char bits[], int w, int h,
65 const wxColour& color)
66 {
67 wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage();
68 img.Replace(0,0,0,123,123,123);
69 img.Replace(255,255,255,color.Red(),color.Green(),color.Blue());
70 img.SetMaskColour(123,123,123);
71 return wxBitmap(img);
72 }
73
74 static void DrawButtonS(wxDC& dc,
75 const wxRect& _rect,
76 const wxBitmap& bmp,
77 const wxColour& bkcolour,
78 int button_state)
79 {
80 wxRect rect = _rect;
81
82 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
83 {
84 rect.x++;
85 rect.y++;
86 }
87
88 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
89 button_state == wxAUI_BUTTON_STATE_PRESSED)
90 {
91 dc.SetBrush(wxBrush(StepColour(bkcolour, 120)));
92 dc.SetPen(wxPen(StepColour(bkcolour, 70)));
93
94 // draw the background behind the button
95 dc.DrawRectangle(rect.x, rect.y, 15, 15);
96 }
97
98 // draw the button itself
99 dc.DrawBitmap(bmp, rect.x, rect.y, true);
100 }
101
102
103
104
105
106 // -- wxDefaultTabArt class implementation --
107
108 wxDefaultTabArt::wxDefaultTabArt()
109 {
110 m_normal_font = *wxNORMAL_FONT;
111 m_selected_font = *wxNORMAL_FONT;
112 m_selected_font.SetWeight(wxBOLD);
113 m_measuring_font = m_selected_font;
114
115 wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
116
117 wxColour background_colour = StepColour(base_colour, 95);
118 wxColour normaltab_colour = base_colour;
119 wxColour selectedtab_colour = *wxWHITE;
120
121 m_bkbrush = wxBrush(background_colour);
122 m_normal_bkbrush = wxBrush(normaltab_colour);
123 m_normal_bkpen = wxPen(normaltab_colour);
124 m_selected_bkbrush = wxBrush(selectedtab_colour);
125 m_selected_bkpen = wxPen(selectedtab_colour);
126
127
128 #if defined( __WXMAC__ )
129 static unsigned char close_bits[]={
130 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
131 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
132 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
133 #elif defined( __WXGTK__)
134 static unsigned char close_bits[]={
135 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
136 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
137 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
138 #else
139 static unsigned char close_bits[]={
140 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
141 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
142 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
143 #endif
144
145 static unsigned char left_bits[] = {
146 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
147 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
149
150 static unsigned char right_bits[] = {
151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
152 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
154
155 m_active_close_bmp = BitmapFromBits(close_bits, 16, 16, *wxBLACK);
156 m_disabled_close_bmp = BitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
157
158 m_active_left_bmp = BitmapFromBits(left_bits, 16, 16, *wxBLACK);
159 m_disabled_left_bmp = BitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
160
161 m_active_right_bmp = BitmapFromBits(right_bits, 16, 16, *wxBLACK);
162 m_disabled_right_bmp = BitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
163 }
164
165 wxDefaultTabArt::~wxDefaultTabArt()
166 {
167 }
168
169 void wxDefaultTabArt::DrawBackground(wxDC* dc,
170 const wxRect& rect)
171 {
172 // draw background
173 dc->SetBrush(m_bkbrush);
174 dc->SetPen(*wxTRANSPARENT_PEN);
175 dc->DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
176
177 // draw base line
178 dc->SetPen(*wxGREY_PEN);
179 dc->DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
180 }
181
182
183 // DrawTab() draws an individual tab.
184 //
185 // dc - output dc
186 // in_rect - rectangle the tab should be confined to
187 // caption - tab's caption
188 // active - whether or not the tab is active
189 // out_rect - actual output rectangle
190 // x_extent - the advance x; where the next tab should start
191
192 void wxDefaultTabArt::DrawTab(wxDC* dc,
193 const wxRect& in_rect,
194 const wxString& caption_text,
195 bool active,
196 wxRect* out_rect,
197 int* x_extent)
198 {
199 wxCoord normal_textx, normal_texty;
200 wxCoord selected_textx, selected_texty;
201 wxCoord measured_textx, measured_texty;
202 wxCoord textx, texty;
203
204
205 // if the caption is empty, measure some temporary text
206 wxString caption = caption_text;
207 if (caption_text.empty())
208 caption = wxT("Xj");
209
210 // measure text
211 dc->SetFont(m_measuring_font);
212 dc->GetTextExtent(caption, &measured_textx, &measured_texty);
213
214 dc->SetFont(m_selected_font);
215 dc->GetTextExtent(caption, &selected_textx, &selected_texty);
216
217 dc->SetFont(m_normal_font);
218 dc->GetTextExtent(caption, &normal_textx, &normal_texty);
219
220 caption = caption_text;
221
222 wxCoord tab_height = measured_texty + 4;
223 wxCoord tab_width = measured_textx + tab_height + 5;
224 wxCoord tab_x = in_rect.x;
225 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
226
227
228 // select pen, brush and font for the tab to be drawn
229
230 if (active)
231 {
232 dc->SetPen(m_selected_bkpen);
233 dc->SetBrush(m_selected_bkbrush);
234 dc->SetFont(m_selected_font);
235 textx = selected_textx;
236 texty = selected_texty;
237 }
238 else
239 {
240 dc->SetPen(m_normal_bkpen);
241 dc->SetBrush(m_normal_bkbrush);
242 dc->SetFont(m_normal_font);
243 textx = normal_textx;
244 texty = normal_texty;
245 }
246
247
248 // -- draw line --
249
250 wxPoint points[7];
251 points[0].x = tab_x;
252 points[0].y = tab_y + tab_height - 1;
253 points[1].x = tab_x + tab_height - 3;
254 points[1].y = tab_y + 2;
255 points[2].x = tab_x + tab_height + 3;
256 points[2].y = tab_y;
257 points[3].x = tab_x + tab_width - 2;
258 points[3].y = tab_y;
259 points[4].x = tab_x + tab_width;
260 points[4].y = tab_y + 2;
261 points[5].x = tab_x + tab_width;
262 points[5].y = tab_y + tab_height - 1;
263 points[6] = points[0];
264
265
266 dc->DrawPolygon(6, points);
267
268 dc->SetPen(*wxGREY_PEN);
269
270 //dc->DrawLines(active ? 6 : 7, points);
271 dc->DrawLines(7, points);
272
273 // -- draw text --
274
275 dc->DrawText(caption,
276 tab_x + (tab_height/3) + (tab_width/2) - (textx/2),
277 tab_y + tab_height - texty - 2);
278
279 *out_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
280 *x_extent = tab_width - (tab_height/2) - 1;
281 }
282
283
284 wxSize wxDefaultTabArt::GetTabSize(wxDC* dc,
285 const wxString& caption,
286 bool WXUNUSED(active),
287 int* x_extent)
288 {
289 wxCoord measured_textx, measured_texty;
290
291 dc->SetFont(m_measuring_font);
292 dc->GetTextExtent(caption, &measured_textx, &measured_texty);
293
294 wxCoord tab_height = measured_texty + 4;
295 wxCoord tab_width = measured_textx + tab_height + 5;
296
297 *x_extent = tab_width - (tab_height/2) - 1;
298
299 return wxSize(tab_width, tab_height);
300 }
301
302
303 void wxDefaultTabArt::DrawButton(
304 wxDC* dc,
305 const wxRect& in_rect,
306 int bitmap_id,
307 int button_state,
308 int orientation,
309 const wxBitmap& bitmap_override,
310 wxRect* out_rect)
311 {
312 wxBitmap bmp;
313 wxRect rect;
314
315 if (bitmap_override.IsOk())
316 {
317 bmp = bitmap_override;
318 }
319 else
320 {
321 switch (bitmap_id)
322 {
323 case wxAUI_BUTTON_CLOSE:
324 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
325 bmp = m_disabled_close_bmp;
326 else
327 bmp = m_active_close_bmp;
328 break;
329 case wxAUI_BUTTON_LEFT:
330 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
331 bmp = m_disabled_left_bmp;
332 else
333 bmp = m_active_left_bmp;
334 break;
335 case wxAUI_BUTTON_RIGHT:
336 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
337 bmp = m_disabled_right_bmp;
338 else
339 bmp = m_active_right_bmp;
340 break;
341 }
342 }
343
344 if (!bmp.IsOk())
345 return;
346
347 rect = in_rect;
348
349 if (orientation == wxLEFT)
350 {
351 rect.SetX(in_rect.x);
352 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
353 rect.SetWidth(bmp.GetWidth());
354 rect.SetHeight(bmp.GetHeight());
355 }
356 else
357 {
358 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
359 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
360 bmp.GetWidth(), bmp.GetHeight());
361 }
362
363
364 DrawButtonS(*dc, rect, bmp, *wxWHITE, button_state);
365
366 *out_rect = rect;
367 }
368
369
370
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
956 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
957 {
958 wxPaintDC dc(this);
959
960 dc.SetFont(GetFont());
961
962 if (GetPageCount() > 0)
963 Render(&dc);
964 }
965
966 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
967 {
968 }
969
970 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
971 {
972 wxSize s = evt.GetSize();
973 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
974 SetRect(r);
975 }
976
977 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
978 {
979 CaptureMouse();
980 m_click_pt = wxDefaultPosition;
981 m_is_dragging = false;
982 m_click_tab = -1;
983
984 wxWindow* wnd;
985 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
986 {
987 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
988 e.SetSelection(GetIdxFromWindow(wnd));
989 e.SetOldSelection(GetActivePage());
990 e.SetEventObject(this);
991 GetEventHandler()->ProcessEvent(e);
992
993 m_click_pt.x = evt.m_x;
994 m_click_pt.y = evt.m_y;
995 m_click_tab = e.GetSelection();
996 }
997
998 if (m_hover_button)
999 {
1000 m_hover_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
1001 Refresh();
1002 Update();
1003 }
1004 }
1005
1006 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent&)
1007 {
1008 if (GetCapture() == this)
1009 ReleaseMouse();
1010
1011 if (m_is_dragging)
1012 {
1013 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
1014 evt.SetSelection(m_click_tab);
1015 evt.SetOldSelection(m_click_tab);
1016 evt.SetEventObject(this);
1017 GetEventHandler()->ProcessEvent(evt);
1018 return;
1019 }
1020
1021 if (m_hover_button)
1022 {
1023 m_hover_button->cur_state = wxAUI_BUTTON_STATE_HOVER;
1024 Refresh();
1025 Update();
1026
1027 if (!(m_hover_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
1028 {
1029 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
1030 evt.SetInt(m_hover_button->id);
1031 evt.SetEventObject(this);
1032 GetEventHandler()->ProcessEvent(evt);
1033 }
1034 }
1035
1036 m_click_pt = wxDefaultPosition;
1037 m_is_dragging = false;
1038 m_click_tab = -1;
1039 }
1040
1041 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
1042 {
1043 wxPoint pos = evt.GetPosition();
1044
1045 // check if the mouse is hovering above a button
1046 wxAuiTabContainerButton* button;
1047 if (ButtonHitTest(pos.x, pos.y, &button))
1048 {
1049 if (m_hover_button && button != m_hover_button)
1050 {
1051 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1052 m_hover_button = NULL;
1053 Refresh();
1054 Update();
1055 }
1056
1057 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
1058 {
1059 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
1060 Refresh();
1061 Update();
1062 m_hover_button = button;
1063 return;
1064 }
1065 }
1066 else
1067 {
1068 if (m_hover_button)
1069 {
1070 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1071 m_hover_button = NULL;
1072 Refresh();
1073 Update();
1074 }
1075 }
1076
1077
1078 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
1079 return;
1080
1081 if (m_is_dragging)
1082 {
1083 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
1084 evt.SetSelection(m_click_tab);
1085 evt.SetOldSelection(m_click_tab);
1086 evt.SetEventObject(this);
1087 GetEventHandler()->ProcessEvent(evt);
1088 return;
1089 }
1090
1091
1092 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
1093 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
1094
1095 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
1096 abs(pos.y - m_click_pt.y) > drag_y_threshold)
1097 {
1098 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
1099 evt.SetSelection(m_click_tab);
1100 evt.SetOldSelection(m_click_tab);
1101 evt.SetEventObject(this);
1102 GetEventHandler()->ProcessEvent(evt);
1103
1104 m_is_dragging = true;
1105 }
1106 }
1107
1108 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
1109 {
1110 if (m_hover_button)
1111 {
1112 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1113 m_hover_button = NULL;
1114 Refresh();
1115 Update();
1116 }
1117 }
1118
1119 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
1120 {
1121 int button = event.GetInt();
1122
1123 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
1124 {
1125 if (button == wxAUI_BUTTON_LEFT)
1126 {
1127 if (GetTabOffset() > 0)
1128 {
1129 SetTabOffset(GetTabOffset()-1);
1130 Refresh();
1131 Update();
1132 }
1133 }
1134 else
1135 {
1136 SetTabOffset(GetTabOffset()+1);
1137 Refresh();
1138 Update();
1139 }
1140 }
1141 else
1142 {
1143 event.Skip();
1144 }
1145 }
1146
1147 // wxTabFrame is an interesting case. It's important that all child pages
1148 // of the multi-notebook control are all actually children of that control
1149 // (and not grandchildren). wxTabFrame facilitates this. There is one
1150 // instance of wxTabFrame for each tab control inside the multi-notebook.
1151 // It's important to know that wxTabFrame is not a real window, but it merely
1152 // used to capture the dimensions/positioning of the internal tab control and
1153 // it's managed page windows
1154
1155 class wxTabFrame : public wxWindow
1156 {
1157 public:
1158
1159 wxTabFrame()
1160 {
1161 m_tabs = NULL;
1162 m_rect = wxRect(0,0,200,200);
1163 m_tab_ctrl_height = 20;
1164 }
1165
1166 void SetTabCtrlHeight(int h)
1167 {
1168 m_tab_ctrl_height = h;
1169 }
1170
1171 void DoSetSize(int x, int y,
1172 int width, int height,
1173 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
1174 {
1175 m_rect = wxRect(x, y, width, height);
1176 DoSizing();
1177 }
1178
1179 void DoGetClientSize(int* x, int* y) const
1180 {
1181 *x = m_rect.width;
1182 *y = m_rect.height;
1183 }
1184
1185 bool Show( bool WXUNUSED(show = true) ) { return false; }
1186
1187 void DoSizing()
1188 {
1189 if (!m_tabs)
1190 return;
1191
1192 int tab_height = wxMin(m_rect.height, m_tab_ctrl_height);
1193 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, tab_height);
1194 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, tab_height);
1195 m_tabs->SetRect(wxRect(0, 0, m_rect.width, tab_height));
1196 m_tabs->Refresh();
1197 m_tabs->Update();
1198
1199 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
1200 size_t i, page_count = pages.GetCount();
1201
1202 for (i = 0; i < page_count; ++i)
1203 {
1204 wxAuiNotebookPage& page = pages.Item(i);
1205 page.window->SetSize(m_rect.x, m_rect.y+tab_height, m_rect.width, m_rect.height-tab_height);
1206
1207 if (page.window->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1208 {
1209 wxTabMDIChildFrame* wnd = (wxTabMDIChildFrame*)page.window;
1210 wnd->ApplyMDIChildFrameRect();
1211 }
1212 }
1213 }
1214
1215 void DoGetSize(int* x, int* y) const
1216 {
1217 if (x)
1218 *x = m_rect.GetWidth();
1219 if (y)
1220 *y = m_rect.GetHeight();
1221 }
1222
1223 void Update()
1224 {
1225 // does nothing
1226 }
1227
1228 public:
1229
1230 wxRect m_rect;
1231 wxRect m_tab_rect;
1232 wxAuiTabCtrl* m_tabs;
1233 int m_tab_ctrl_height;
1234 };
1235
1236
1237
1238
1239
1240 // -- wxAuiMultiNotebook class implementation --
1241
1242 BEGIN_EVENT_TABLE(wxAuiMultiNotebook, wxControl)
1243 //EVT_ERASE_BACKGROUND(wxAuiMultiNotebook::OnEraseBackground)
1244 //EVT_SIZE(wxAuiMultiNotebook::OnSize)
1245 //EVT_LEFT_DOWN(wxAuiMultiNotebook::OnLeftDown)
1246 EVT_CHILD_FOCUS(wxAuiMultiNotebook::OnChildFocus)
1247 EVT_COMMAND_RANGE(10000, 10100,
1248 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
1249 wxAuiMultiNotebook::OnTabClicked)
1250 EVT_COMMAND_RANGE(10000, 10100,
1251 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
1252 wxAuiMultiNotebook::OnTabBeginDrag)
1253 EVT_COMMAND_RANGE(10000, 10100,
1254 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
1255 wxAuiMultiNotebook::OnTabEndDrag)
1256 EVT_COMMAND_RANGE(10000, 10100,
1257 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
1258 wxAuiMultiNotebook::OnTabDragMotion)
1259 EVT_COMMAND_RANGE(10000, 10100,
1260 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
1261 wxAuiMultiNotebook::OnTabButton)
1262 END_EVENT_TABLE()
1263
1264 wxAuiMultiNotebook::wxAuiMultiNotebook()
1265 {
1266 m_curpage = -1;
1267 m_tab_id_counter = 10000;
1268 m_dummy_wnd = NULL;
1269 m_tab_ctrl_height = 20;
1270 }
1271
1272 wxAuiMultiNotebook::wxAuiMultiNotebook(wxWindow *parent,
1273 wxWindowID id,
1274 const wxPoint& pos,
1275 const wxSize& size,
1276 long style) : wxControl(parent, id, pos, size, style)
1277 {
1278 InitNotebook();
1279 }
1280
1281 bool wxAuiMultiNotebook::Create(wxWindow* parent,
1282 wxWindowID id,
1283 const wxPoint& pos,
1284 const wxSize& size,
1285 long style)
1286 {
1287 if (!wxControl::Create(parent, id, pos, size, style))
1288 return false;
1289
1290 InitNotebook();
1291
1292 return true;
1293 }
1294
1295 // InitNotebook() contains common initialization
1296 // code called by all constructors
1297 void wxAuiMultiNotebook::InitNotebook()
1298 {
1299 m_curpage = -1;
1300 m_tab_id_counter = 10000;
1301 m_dummy_wnd = NULL;
1302 m_tab_ctrl_height = 20;
1303
1304 m_normal_font = *wxNORMAL_FONT;
1305 m_selected_font = *wxNORMAL_FONT;
1306 m_selected_font.SetWeight(wxBOLD);
1307
1308 // choose a default for the tab height
1309 wxClientDC dc(this);
1310 int tx, ty;
1311 dc.SetFont(m_selected_font);
1312 dc.GetTextExtent(wxT("ABCDEFGHhijklm"), &tx, &ty);
1313 m_tab_ctrl_height = (ty*150)/100;
1314
1315 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
1316 m_dummy_wnd->SetSize(200, 200);
1317 m_dummy_wnd->Show(false);
1318
1319 m_mgr.SetManagedWindow(this);
1320
1321 m_mgr.AddPane(m_dummy_wnd,
1322 wxPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
1323
1324 m_mgr.Update();
1325 }
1326
1327 wxAuiMultiNotebook::~wxAuiMultiNotebook()
1328 {
1329 m_mgr.UnInit();
1330 }
1331
1332 void wxAuiMultiNotebook::SetArtProvider(wxTabArt* art)
1333 {
1334 m_tabs.SetArtProvider(art);
1335 }
1336
1337 wxTabArt* wxAuiMultiNotebook::GetArtProvider()
1338 {
1339 return m_tabs.GetArtProvider();
1340 }
1341
1342 bool wxAuiMultiNotebook::AddPage(wxWindow* page,
1343 const wxString& caption,
1344 bool select,
1345 const wxBitmap& bitmap)
1346 {
1347 return InsertPage(GetPageCount(), page, caption, select, bitmap);
1348 }
1349
1350 bool wxAuiMultiNotebook::InsertPage(size_t page_idx,
1351 wxWindow* page,
1352 const wxString& caption,
1353 bool select,
1354 const wxBitmap& bitmap)
1355 {
1356 wxAuiNotebookPage info;
1357 info.window = page;
1358 info.caption = caption;
1359 info.bitmap = bitmap;
1360 info.active = false;
1361
1362 // if there are currently no tabs, the first added
1363 // tab must be active
1364 if (m_tabs.GetPageCount() == 0)
1365 info.active = true;
1366
1367 m_tabs.InsertPage(page, info, page_idx);
1368
1369 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
1370 if (page_idx >= active_tabctrl->GetPageCount())
1371 active_tabctrl->AddPage(page, info);
1372 else
1373 active_tabctrl->InsertPage(page, info, page_idx);
1374
1375 DoSizing();
1376 active_tabctrl->DoShowHide();
1377
1378 if (select)
1379 {
1380 int idx = m_tabs.GetIdxFromWindow(page);
1381 wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiMultiNotebook::InsertPage()"));
1382
1383 SetSelection(idx);
1384 }
1385
1386 return true;
1387 }
1388
1389
1390 // DeletePage() removes a tab from the multi-notebook,
1391 // and destroys the window as well
1392 bool wxAuiMultiNotebook::DeletePage(size_t page_idx)
1393 {
1394 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1395 wxWindow* new_active = NULL;
1396
1397 // find out which onscreen tab ctrl owns this tab
1398 wxAuiTabCtrl* ctrl;
1399 int ctrl_idx;
1400 if (!FindTab(wnd, &ctrl, &ctrl_idx))
1401 return false;
1402
1403 // find a new page and set it as active
1404 int new_idx = ctrl_idx+1;
1405 if (new_idx >= (int)ctrl->GetPageCount())
1406 new_idx = ctrl_idx-1;
1407
1408 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
1409 {
1410 new_active = ctrl->GetWindowFromIdx(new_idx);
1411 }
1412 else
1413 {
1414 // set the active page to the first page that
1415 // isn't the one being deleted
1416 size_t i, page_count = m_tabs.GetPageCount();
1417 for (i = 0; i < page_count; ++i)
1418 {
1419 wxWindow* w = m_tabs.GetWindowFromIdx(i);
1420 if (wnd != w)
1421 {
1422 new_active = m_tabs.GetWindowFromIdx(i);
1423 break;
1424 }
1425 }
1426 }
1427
1428 // remove the tab from main catalog
1429 if (!m_tabs.RemovePage(wnd))
1430 return false;
1431
1432 // remove the tab from the onscreen tab ctrl
1433 ctrl->RemovePage(wnd);
1434
1435 // actually destroy the window now
1436 if (wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1437 {
1438 // delete the child frame with pending delete, as is
1439 // customary with frame windows
1440 if (!wxPendingDelete.Member(wnd))
1441 wxPendingDelete.Append(wnd);
1442 }
1443 else
1444 {
1445 wnd->Destroy();
1446 }
1447
1448 RemoveEmptyTabFrames();
1449
1450 // set new active pane
1451 if (new_active)
1452 {
1453 m_curpage = -1;
1454 SetSelection(m_tabs.GetIdxFromWindow(new_active));
1455 }
1456
1457 return true;
1458 }
1459
1460
1461
1462 // RemovePage() removes a tab from the multi-notebook,
1463 // but does not destroy the window
1464 bool wxAuiMultiNotebook::RemovePage(size_t page_idx)
1465 {
1466 // remove the tab from our own catalog
1467 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1468 if (!m_tabs.RemovePage(wnd))
1469 return false;
1470
1471 // remove the tab from the onscreen tab ctrl
1472 wxAuiTabCtrl* ctrl;
1473 int ctrl_idx;
1474 if (FindTab(wnd, &ctrl, &ctrl_idx))
1475 {
1476 ctrl->RemovePage(wnd);
1477 return true;
1478 }
1479
1480 return false;
1481 }
1482
1483 // SetPageText() changes the tab caption of the specified page
1484 bool wxAuiMultiNotebook::SetPageText(size_t page_idx, const wxString& text)
1485 {
1486 if (page_idx >= m_tabs.GetPageCount())
1487 return false;
1488
1489 // update our own tab catalog
1490 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
1491 page_info.caption = text;
1492
1493 // update what's on screen
1494 wxAuiTabCtrl* ctrl;
1495 int ctrl_idx;
1496 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
1497 {
1498 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
1499 info.caption = text;
1500 ctrl->Refresh();
1501 ctrl->Update();
1502 }
1503
1504 return true;
1505 }
1506
1507 // GetSelection() returns the index of the currently active page
1508 int wxAuiMultiNotebook::GetSelection() const
1509 {
1510 return m_curpage;
1511 }
1512
1513 // SetSelection() sets the currently active page
1514 size_t wxAuiMultiNotebook::SetSelection(size_t new_page)
1515 {
1516 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
1517 if (!wnd)
1518 return m_curpage;
1519
1520 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1521 evt.SetSelection(new_page);
1522 evt.SetOldSelection(m_curpage);
1523 evt.SetEventObject(this);
1524 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
1525 {
1526 // program allows the page change
1527 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
1528 (void)GetEventHandler()->ProcessEvent(evt);
1529
1530
1531
1532 wxAuiTabCtrl* ctrl;
1533 int ctrl_idx;
1534 if (FindTab(wnd, &ctrl, &ctrl_idx))
1535 {
1536 m_tabs.SetActivePage(wnd);
1537
1538 ctrl->SetActivePage(ctrl_idx);
1539 DoSizing();
1540 ctrl->DoShowHide();
1541
1542 int old_curpage = m_curpage;
1543 m_curpage = new_page;
1544
1545
1546 // set fonts
1547 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1548 size_t i, pane_count = all_panes.GetCount();
1549 for (i = 0; i < pane_count; ++i)
1550 {
1551 wxPaneInfo& pane = all_panes.Item(i);
1552 if (pane.name == wxT("dummy"))
1553 continue;
1554 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
1555 if (tabctrl != ctrl)
1556 tabctrl->SetSelectedFont(m_normal_font);
1557 else
1558 tabctrl->SetSelectedFont(m_selected_font);
1559 tabctrl->Refresh();
1560 }
1561
1562 wnd->SetFocus();
1563
1564 return old_curpage;
1565 }
1566 }
1567
1568 return m_curpage;
1569 }
1570
1571 // GetPageCount() returns the total number of
1572 // pages managed by the multi-notebook
1573 size_t wxAuiMultiNotebook::GetPageCount() const
1574 {
1575 return m_tabs.GetPageCount();
1576 }
1577
1578 // GetPage() returns the wxWindow pointer of the
1579 // specified page
1580 wxWindow* wxAuiMultiNotebook::GetPage(size_t page_idx) const
1581 {
1582 wxASSERT(page_idx < m_tabs.GetPageCount());
1583
1584 return m_tabs.GetWindowFromIdx(page_idx);
1585 }
1586
1587 // DoSizing() performs all sizing operations in each tab control
1588 void wxAuiMultiNotebook::DoSizing()
1589 {
1590 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1591 size_t i, pane_count = all_panes.GetCount();
1592 for (i = 0; i < pane_count; ++i)
1593 {
1594 if (all_panes.Item(i).name == wxT("dummy"))
1595 continue;
1596
1597 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1598 tabframe->DoSizing();
1599 }
1600 }
1601
1602 // GetActiveTabCtrl() returns the active tab control. It is
1603 // called to determine which control gets new windows being added
1604 wxAuiTabCtrl* wxAuiMultiNotebook::GetActiveTabCtrl()
1605 {
1606 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
1607 {
1608 wxAuiTabCtrl* ctrl;
1609 int idx;
1610
1611 // find the tab ctrl with the current page
1612 if (FindTab(m_tabs.GetPage(m_curpage).window,
1613 &ctrl, &idx))
1614 {
1615 return ctrl;
1616 }
1617 }
1618
1619 // no current page, just find the first tab ctrl
1620 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1621 size_t i, pane_count = all_panes.GetCount();
1622 for (i = 0; i < pane_count; ++i)
1623 {
1624 if (all_panes.Item(i).name == wxT("dummy"))
1625 continue;
1626
1627 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1628 return tabframe->m_tabs;
1629 }
1630
1631 // If there is no tabframe at all, create one
1632 wxTabFrame* tabframe = new wxTabFrame;
1633 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
1634 tabframe->m_tabs = new wxAuiTabCtrl(this,
1635 m_tab_id_counter++,
1636 wxDefaultPosition,
1637 wxDefaultSize,
1638 wxNO_BORDER);
1639 m_mgr.AddPane(tabframe,
1640 wxPaneInfo().Center().CaptionVisible(false));
1641
1642 m_mgr.Update();
1643
1644 return tabframe->m_tabs;
1645 }
1646
1647 // FindTab() finds the tab control that currently contains the window as well
1648 // as the index of the window in the tab control. It returns true if the
1649 // window was found, otherwise false.
1650 bool wxAuiMultiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
1651 {
1652 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1653 size_t i, pane_count = all_panes.GetCount();
1654 for (i = 0; i < pane_count; ++i)
1655 {
1656 if (all_panes.Item(i).name == wxT("dummy"))
1657 continue;
1658
1659 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1660
1661 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
1662 if (page_idx != -1)
1663 {
1664 *ctrl = tabframe->m_tabs;
1665 *idx = page_idx;
1666 return true;
1667 }
1668 }
1669
1670 return false;
1671 }
1672
1673
1674 void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent&)
1675 {
1676 }
1677
1678 void wxAuiMultiNotebook::OnSize(wxSizeEvent&)
1679 {
1680 }
1681
1682 void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent& command_evt)
1683 {
1684 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1685
1686 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
1687 wxASSERT(ctrl != NULL);
1688
1689 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
1690 wxASSERT(wnd != NULL);
1691
1692 int idx = m_tabs.GetIdxFromWindow(wnd);
1693 wxASSERT(idx != -1);
1694
1695 SetSelection(idx);
1696 }
1697
1698 void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent&)
1699 {
1700 }
1701
1702 void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent& evt)
1703 {
1704 wxPoint screen_pt = ::wxGetMousePosition();
1705 wxPoint client_pt = ScreenToClient(screen_pt);
1706 wxPoint zero(0,0);
1707
1708 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1709
1710 wxAuiTabCtrl* tab_ctrl = GetTabCtrlFromPoint(client_pt);
1711 if (tab_ctrl == src_tabs)
1712 {
1713 // inner-tabctrl dragging is not yet implemented
1714 m_mgr.HideHint();
1715 return;
1716 }
1717
1718 if (tab_ctrl)
1719 {
1720 wxRect hint_rect = tab_ctrl->GetRect();
1721 ClientToScreen(&hint_rect.x, &hint_rect.y);
1722 m_mgr.ShowHint(hint_rect);
1723 }
1724 else
1725 {
1726 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
1727 }
1728 }
1729
1730
1731
1732 void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
1733 {
1734 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1735
1736 m_mgr.HideHint();
1737
1738
1739 // get the mouse position, which will be used to determine the drop point
1740 wxPoint mouse_screen_pt = ::wxGetMousePosition();
1741 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
1742
1743
1744 // the src tab control is the control that fired this event
1745 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1746 wxAuiTabCtrl* dest_tabs = NULL;
1747
1748
1749 // If the pointer is in an existing tab frame, do a tab insert
1750 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
1751 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
1752 if (tab_frame)
1753 {
1754 dest_tabs = tab_frame->m_tabs;
1755
1756 if (dest_tabs == src_tabs)
1757 return;
1758 }
1759 else
1760 {
1761 // If there is no tabframe at all, create one
1762 wxTabFrame* new_tabs = new wxTabFrame;
1763 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
1764 new_tabs->m_tabs = new wxAuiTabCtrl(this,
1765 m_tab_id_counter++,
1766 wxDefaultPosition,
1767 wxDefaultSize,
1768 wxNO_BORDER);
1769 m_mgr.AddPane(new_tabs,
1770 wxPaneInfo().Bottom().CaptionVisible(false),
1771 mouse_client_pt);
1772 m_mgr.Update();
1773 dest_tabs = new_tabs->m_tabs;
1774 }
1775
1776
1777
1778 // remove the page from the source tabs
1779 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
1780 page_info.active = false;
1781 src_tabs->RemovePage(page_info.window);
1782 if (src_tabs->GetPageCount() > 0)
1783 {
1784 src_tabs->SetActivePage((size_t)0);
1785 src_tabs->DoShowHide();
1786 src_tabs->Refresh();
1787 }
1788
1789
1790
1791 // add the page to the destination tabs
1792 dest_tabs->AddPage(page_info.window, page_info);
1793
1794 if (src_tabs->GetPageCount() == 0)
1795 {
1796 RemoveEmptyTabFrames();
1797 }
1798
1799 DoSizing();
1800 dest_tabs->DoShowHide();
1801 dest_tabs->Refresh();
1802
1803 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
1804 }
1805
1806 wxAuiTabCtrl* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
1807 {
1808 // if we've just removed the last tab from the source
1809 // tab set, the remove the tab control completely
1810 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1811 size_t i, pane_count = all_panes.GetCount();
1812 for (i = 0; i < pane_count; ++i)
1813 {
1814 if (all_panes.Item(i).name == wxT("dummy"))
1815 continue;
1816
1817 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1818 if (tabframe->m_tab_rect.Contains(pt))
1819 return tabframe->m_tabs;
1820 }
1821
1822 return NULL;
1823 }
1824
1825 wxWindow* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
1826 {
1827 // if we've just removed the last tab from the source
1828 // tab set, the remove the tab control completely
1829 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1830 size_t i, pane_count = all_panes.GetCount();
1831 for (i = 0; i < pane_count; ++i)
1832 {
1833 if (all_panes.Item(i).name == wxT("dummy"))
1834 continue;
1835
1836 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1837 if (tabframe->m_tabs == tab_ctrl)
1838 {
1839 return tabframe;
1840 }
1841 }
1842
1843 return NULL;
1844 }
1845
1846 void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1847 {
1848 // if we've just removed the last tab from the source
1849 // tab set, the remove the tab control completely
1850 wxPaneInfoArray all_panes = m_mgr.GetAllPanes();
1851 size_t i, pane_count = all_panes.GetCount();
1852 for (i = 0; i < pane_count; ++i)
1853 {
1854 if (all_panes.Item(i).name == wxT("dummy"))
1855 continue;
1856
1857 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
1858 if (tab_frame->m_tabs->GetPageCount() == 0)
1859 {
1860 m_mgr.DetachPane(tab_frame);
1861
1862 // use pending delete because sometimes during
1863 // window closing, refreshs are pending
1864 if (!wxPendingDelete.Member(tab_frame->m_tabs))
1865 wxPendingDelete.Append(tab_frame->m_tabs);
1866 //tab_frame->m_tabs->Destroy();
1867
1868 delete tab_frame;
1869 }
1870 }
1871
1872
1873 // check to see if there is still a center pane;
1874 // if there isn't, make a frame the center pane
1875 wxPaneInfoArray panes = m_mgr.GetAllPanes();
1876 pane_count = panes.GetCount();
1877 wxWindow* first_good = NULL;
1878 bool center_found = false;
1879 for (i = 0; i < pane_count; ++i)
1880 {
1881 if (panes.Item(i).name == wxT("dummy"))
1882 continue;
1883 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
1884 center_found = true;
1885 if (!first_good)
1886 first_good = panes.Item(i).window;
1887 }
1888
1889 if (!center_found && first_good)
1890 {
1891 m_mgr.GetPane(first_good).Centre();
1892 }
1893
1894 m_mgr.Update();
1895 }
1896
1897 void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent& evt)
1898 {
1899 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
1900 if (idx != -1 && idx != m_curpage)
1901 {
1902 SetSelection(idx);
1903 }
1904 }
1905
1906
1907 void wxAuiMultiNotebook::OnTabButton(wxCommandEvent& command_evt)
1908 {
1909 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1910 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1911
1912 int button_id = evt.GetInt();
1913
1914 if (button_id == wxAUI_BUTTON_CLOSE)
1915 {
1916 int selection = tabs->GetActivePage();
1917
1918 if (selection != -1)
1919 {
1920 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
1921
1922 if (close_wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1923 {
1924 close_wnd->Close();
1925 }
1926 else
1927 {
1928 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
1929 DeletePage(main_idx);
1930 }
1931 }
1932 }
1933 }
1934
1935
1936
1937
1938 #endif // wxUSE_AUI