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