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