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