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