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