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