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