]> git.saurik.com Git - wxWidgets.git/blob - src/aui/auibook.cpp
d1a4585e2e282f93eeb01db8c385bc9271088b1e
[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 if (rect.width <= 0)
1628 break;
1629
1630
1631
1632
1633 m_art->DrawTab(dc,
1634 wnd,
1635 rect,
1636 page.caption,
1637 page.active,
1638 tab_button.cur_state,
1639 &page.rect,
1640 &tab_button.rect,
1641 &x_extent);
1642
1643 if (page.active)
1644 {
1645 active = i;
1646 active_offset = offset;
1647 active_rect = rect;
1648 }
1649
1650 offset += x_extent;
1651 }
1652
1653 // draw the active tab again so it stands in the foreground
1654 if (active >= m_tab_offset && active < m_pages.GetCount())
1655 {
1656 wxAuiNotebookPage& page = m_pages.Item(active);
1657
1658 wxAuiTabContainerButton& tab_button = m_tab_close_buttons.Item(active);
1659
1660 // determine if a close button is on this tab
1661 bool close_button = false;
1662 if ((m_flags & wxAUI_NB_CLOSE_ON_ALL_TABS) != 0 ||
1663 ((m_flags & wxAUI_NB_CLOSE_ON_ACTIVE_TAB) != 0 && page.active))
1664 {
1665 close_button = true;
1666 }
1667
1668 rect.x = active_offset;
1669 m_art->DrawTab(dc,
1670 wnd,
1671 active_rect,
1672 page.caption,
1673 page.active,
1674 tab_button.cur_state,
1675 &page.rect,
1676 &tab_button.rect,
1677 &x_extent);
1678 }
1679
1680
1681 raw_dc->Blit(m_rect.x, m_rect.y,
1682 m_rect.GetWidth(), m_rect.GetHeight(),
1683 &dc, 0, 0);
1684 }
1685
1686
1687 // TabHitTest() tests if a tab was hit, passing the window pointer
1688 // back if that condition was fulfilled. The function returns
1689 // true if a tab was hit, otherwise false
1690 bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
1691 {
1692 if (!m_rect.Contains(x,y))
1693 return false;
1694
1695 wxAuiTabContainerButton* btn = NULL;
1696 if (ButtonHitTest(x, y, &btn))
1697 {
1698 if (m_buttons.Index(*btn) != wxNOT_FOUND)
1699 return false;
1700 }
1701
1702 size_t i, page_count = m_pages.GetCount();
1703
1704 for (i = m_tab_offset; i < page_count; ++i)
1705 {
1706 wxAuiNotebookPage& page = m_pages.Item(i);
1707 if (page.rect.Contains(x,y))
1708 {
1709 if (hit)
1710 *hit = page.window;
1711 return true;
1712 }
1713 }
1714
1715 return false;
1716 }
1717
1718 // ButtonHitTest() tests if a button was hit. The function returns
1719 // true if a button was hit, otherwise false
1720 bool wxAuiTabContainer::ButtonHitTest(int x, int y,
1721 wxAuiTabContainerButton** hit) const
1722 {
1723 if (!m_rect.Contains(x,y))
1724 return false;
1725
1726 size_t i, button_count;
1727
1728
1729 button_count = m_buttons.GetCount();
1730 for (i = 0; i < button_count; ++i)
1731 {
1732 wxAuiTabContainerButton& button = m_buttons.Item(i);
1733 if (button.rect.Contains(x,y))
1734 {
1735 if (hit)
1736 *hit = &button;
1737 return true;
1738 }
1739 }
1740
1741 button_count = m_tab_close_buttons.GetCount();
1742 for (i = 0; i < button_count; ++i)
1743 {
1744 wxAuiTabContainerButton& button = m_tab_close_buttons.Item(i);
1745 if (button.rect.Contains(x,y))
1746 {
1747 if (hit)
1748 *hit = &button;
1749 return true;
1750 }
1751 }
1752
1753 return false;
1754 }
1755
1756
1757
1758 // the utility function ShowWnd() is the same as show,
1759 // except it handles wxAuiMDIChildFrame windows as well,
1760 // as the Show() method on this class is "unplugged"
1761 static void ShowWnd(wxWindow* wnd, bool show)
1762 {
1763 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
1764 {
1765 wxAuiMDIChildFrame* cf = (wxAuiMDIChildFrame*)wnd;
1766 cf->DoShow(show);
1767 }
1768 else
1769 {
1770 wnd->Show(show);
1771 }
1772 }
1773
1774
1775 // DoShowHide() this function shows the active window, then
1776 // hides all of the other windows (in that order)
1777 void wxAuiTabContainer::DoShowHide()
1778 {
1779 wxAuiNotebookPageArray& pages = GetPages();
1780 size_t i, page_count = pages.GetCount();
1781
1782 // show new active page first
1783 for (i = 0; i < page_count; ++i)
1784 {
1785 wxAuiNotebookPage& page = pages.Item(i);
1786 if (page.active)
1787 {
1788 ShowWnd(page.window, true);
1789 break;
1790 }
1791 }
1792
1793 // hide all other pages
1794 for (i = 0; i < page_count; ++i)
1795 {
1796 wxAuiNotebookPage& page = pages.Item(i);
1797 ShowWnd(page.window, page.active);
1798 }
1799 }
1800
1801
1802
1803
1804
1805
1806 // -- wxAuiTabCtrl class implementation --
1807
1808
1809
1810 BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
1811 EVT_PAINT(wxAuiTabCtrl::OnPaint)
1812 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
1813 EVT_SIZE(wxAuiTabCtrl::OnSize)
1814 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
1815 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
1816 EVT_MOTION(wxAuiTabCtrl::OnMotion)
1817 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
1818 EVT_AUINOTEBOOK_BUTTON(-1, wxAuiTabCtrl::OnButton)
1819 END_EVENT_TABLE()
1820
1821
1822 wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
1823 wxWindowID id,
1824 const wxPoint& pos,
1825 const wxSize& size,
1826 long style) : wxControl(parent, id, pos, size, style)
1827 {
1828 m_click_pt = wxDefaultPosition;
1829 m_is_dragging = false;
1830 m_hover_button = NULL;
1831 }
1832
1833 wxAuiTabCtrl::~wxAuiTabCtrl()
1834 {
1835 }
1836
1837 void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
1838 {
1839 wxPaintDC dc(this);
1840
1841 dc.SetFont(GetFont());
1842
1843 if (GetPageCount() > 0)
1844 Render(&dc, this);
1845 }
1846
1847 void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
1848 {
1849 }
1850
1851 void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
1852 {
1853 wxSize s = evt.GetSize();
1854 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
1855 SetRect(r);
1856 }
1857
1858 void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
1859 {
1860 CaptureMouse();
1861 m_click_pt = wxDefaultPosition;
1862 m_is_dragging = false;
1863 m_click_tab = NULL;
1864
1865 wxWindow* wnd;
1866 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
1867 {
1868 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1869 e.SetSelection(GetIdxFromWindow(wnd));
1870 e.SetOldSelection(GetActivePage());
1871 e.SetEventObject(this);
1872 GetEventHandler()->ProcessEvent(e);
1873
1874 m_click_pt.x = evt.m_x;
1875 m_click_pt.y = evt.m_y;
1876 m_click_tab = wnd;
1877 }
1878
1879 if (m_hover_button)
1880 {
1881 m_hover_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
1882 Refresh();
1883 Update();
1884 }
1885 }
1886
1887 void wxAuiTabCtrl::OnLeftUp(wxMouseEvent&)
1888 {
1889 if (GetCapture() == this)
1890 ReleaseMouse();
1891
1892 if (m_is_dragging)
1893 {
1894 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
1895 evt.SetSelection(GetIdxFromWindow(m_click_tab));
1896 evt.SetOldSelection(evt.GetSelection());
1897 evt.SetEventObject(this);
1898 GetEventHandler()->ProcessEvent(evt);
1899 return;
1900 }
1901
1902 if (m_hover_button)
1903 {
1904 m_hover_button->cur_state = wxAUI_BUTTON_STATE_HOVER;
1905 Refresh();
1906 Update();
1907
1908 if (!(m_hover_button->cur_state & wxAUI_BUTTON_STATE_DISABLED))
1909 {
1910 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
1911 evt.SetInt(m_hover_button->id);
1912 evt.SetEventObject(this);
1913 GetEventHandler()->ProcessEvent(evt);
1914 }
1915 }
1916
1917 m_click_pt = wxDefaultPosition;
1918 m_is_dragging = false;
1919 m_click_tab = NULL;
1920 }
1921
1922 void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
1923 {
1924 wxPoint pos = evt.GetPosition();
1925
1926 // check if the mouse is hovering above a button
1927 wxAuiTabContainerButton* button;
1928 if (ButtonHitTest(pos.x, pos.y, &button))
1929 {
1930 if (m_hover_button && button != m_hover_button)
1931 {
1932 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1933 m_hover_button = NULL;
1934 Refresh();
1935 Update();
1936 }
1937
1938 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
1939 {
1940 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
1941 Refresh();
1942 Update();
1943 m_hover_button = button;
1944 return;
1945 }
1946 }
1947 else
1948 {
1949 if (m_hover_button)
1950 {
1951 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1952 m_hover_button = NULL;
1953 Refresh();
1954 Update();
1955 }
1956 }
1957
1958
1959 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
1960 return;
1961
1962 if (m_is_dragging)
1963 {
1964 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
1965 evt.SetSelection(GetIdxFromWindow(m_click_tab));
1966 evt.SetOldSelection(evt.GetSelection());
1967 evt.SetEventObject(this);
1968 GetEventHandler()->ProcessEvent(evt);
1969 return;
1970 }
1971
1972
1973 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
1974 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
1975
1976 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
1977 abs(pos.y - m_click_pt.y) > drag_y_threshold)
1978 {
1979 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
1980 evt.SetSelection(GetIdxFromWindow(m_click_tab));
1981 evt.SetOldSelection(evt.GetSelection());
1982 evt.SetEventObject(this);
1983 GetEventHandler()->ProcessEvent(evt);
1984
1985 m_is_dragging = true;
1986 }
1987 }
1988
1989 void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
1990 {
1991 if (m_hover_button)
1992 {
1993 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
1994 m_hover_button = NULL;
1995 Refresh();
1996 Update();
1997 }
1998 }
1999
2000 void wxAuiTabCtrl::OnButton(wxAuiNotebookEvent& event)
2001 {
2002 int button = event.GetInt();
2003
2004 if (button == wxAUI_BUTTON_LEFT || button == wxAUI_BUTTON_RIGHT)
2005 {
2006 if (button == wxAUI_BUTTON_LEFT)
2007 {
2008 if (GetTabOffset() > 0)
2009 {
2010 SetTabOffset(GetTabOffset()-1);
2011 Refresh();
2012 Update();
2013 }
2014 }
2015 else
2016 {
2017 SetTabOffset(GetTabOffset()+1);
2018 Refresh();
2019 Update();
2020 }
2021 }
2022 else if (button == wxAUI_BUTTON_WINDOWLIST)
2023 {
2024 wxArrayString as;
2025
2026 size_t i, page_count = m_pages.GetCount();
2027 for (i = 0; i < page_count; ++i)
2028 {
2029 wxAuiNotebookPage& page = m_pages.Item(i);
2030 as.Add(page.caption);
2031 }
2032
2033 int idx = GetArtProvider()->ShowWindowList(this, as, GetActivePage());
2034
2035 if (idx != -1)
2036 {
2037 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2038 e.SetSelection(idx);
2039 e.SetOldSelection(GetActivePage());
2040 e.SetEventObject(this);
2041 GetEventHandler()->ProcessEvent(e);
2042 }
2043 }
2044 else
2045 {
2046 event.Skip();
2047 }
2048 }
2049
2050 // wxTabFrame is an interesting case. It's important that all child pages
2051 // of the multi-notebook control are all actually children of that control
2052 // (and not grandchildren). wxTabFrame facilitates this. There is one
2053 // instance of wxTabFrame for each tab control inside the multi-notebook.
2054 // It's important to know that wxTabFrame is not a real window, but it merely
2055 // used to capture the dimensions/positioning of the internal tab control and
2056 // it's managed page windows
2057
2058 class wxTabFrame : public wxWindow
2059 {
2060 public:
2061
2062 wxTabFrame()
2063 {
2064 m_tabs = NULL;
2065 m_rect = wxRect(0,0,200,200);
2066 m_tab_ctrl_height = 20;
2067 }
2068
2069 void SetTabCtrlHeight(int h)
2070 {
2071 m_tab_ctrl_height = h;
2072 }
2073
2074 void DoSetSize(int x, int y,
2075 int width, int height,
2076 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
2077 {
2078 m_rect = wxRect(x, y, width, height);
2079 DoSizing();
2080 }
2081
2082 void DoGetClientSize(int* x, int* y) const
2083 {
2084 *x = m_rect.width;
2085 *y = m_rect.height;
2086 }
2087
2088 bool Show( bool WXUNUSED(show = true) ) { return false; }
2089
2090 void DoSizing()
2091 {
2092 if (!m_tabs)
2093 return;
2094
2095 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2096 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, m_tab_ctrl_height);
2097 m_tabs->SetRect(wxRect(0, 0, m_rect.width, m_tab_ctrl_height));
2098 m_tabs->Refresh();
2099 m_tabs->Update();
2100
2101 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
2102 size_t i, page_count = pages.GetCount();
2103
2104 for (i = 0; i < page_count; ++i)
2105 {
2106 wxAuiNotebookPage& page = pages.Item(i);
2107 page.window->SetSize(m_rect.x, m_rect.y + m_tab_ctrl_height,
2108 m_rect.width, m_rect.height - m_tab_ctrl_height);
2109
2110 if (page.window->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2111 {
2112 wxAuiMDIChildFrame* wnd = (wxAuiMDIChildFrame*)page.window;
2113 wnd->ApplyMDIChildFrameRect();
2114 }
2115 }
2116 }
2117
2118 void DoGetSize(int* x, int* y) const
2119 {
2120 if (x)
2121 *x = m_rect.GetWidth();
2122 if (y)
2123 *y = m_rect.GetHeight();
2124 }
2125
2126 void Update()
2127 {
2128 // does nothing
2129 }
2130
2131 public:
2132
2133 wxRect m_rect;
2134 wxRect m_tab_rect;
2135 wxAuiTabCtrl* m_tabs;
2136 int m_tab_ctrl_height;
2137 };
2138
2139
2140
2141
2142
2143 // -- wxAuiNotebook class implementation --
2144
2145 BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
2146 //EVT_ERASE_BACKGROUND(wxAuiNotebook::OnEraseBackground)
2147 //EVT_SIZE(wxAuiNotebook::OnSize)
2148 //EVT_LEFT_DOWN(wxAuiNotebook::OnLeftDown)
2149 EVT_CHILD_FOCUS(wxAuiNotebook::OnChildFocus)
2150 EVT_COMMAND_RANGE(10000, 10100,
2151 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
2152 wxAuiNotebook::OnTabClicked)
2153 EVT_COMMAND_RANGE(10000, 10100,
2154 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
2155 wxAuiNotebook::OnTabBeginDrag)
2156 EVT_COMMAND_RANGE(10000, 10100,
2157 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
2158 wxAuiNotebook::OnTabEndDrag)
2159 EVT_COMMAND_RANGE(10000, 10100,
2160 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
2161 wxAuiNotebook::OnTabDragMotion)
2162 EVT_COMMAND_RANGE(10000, 10100,
2163 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
2164 wxAuiNotebook::OnTabButton)
2165 END_EVENT_TABLE()
2166
2167 wxAuiNotebook::wxAuiNotebook()
2168 {
2169 m_curpage = -1;
2170 m_tab_id_counter = 10000;
2171 m_dummy_wnd = NULL;
2172 m_tab_ctrl_height = 20;
2173 }
2174
2175 wxAuiNotebook::wxAuiNotebook(wxWindow *parent,
2176 wxWindowID id,
2177 const wxPoint& pos,
2178 const wxSize& size,
2179 long style) : wxControl(parent, id, pos, size, style)
2180 {
2181 InitNotebook(style);
2182 }
2183
2184 bool wxAuiNotebook::Create(wxWindow* parent,
2185 wxWindowID id,
2186 const wxPoint& pos,
2187 const wxSize& size,
2188 long style)
2189 {
2190 if (!wxControl::Create(parent, id, pos, size, style))
2191 return false;
2192
2193 InitNotebook(style);
2194
2195 return true;
2196 }
2197
2198 // InitNotebook() contains common initialization
2199 // code called by all constructors
2200 void wxAuiNotebook::InitNotebook(long style)
2201 {
2202 m_curpage = -1;
2203 m_tab_id_counter = 10000;
2204 m_dummy_wnd = NULL;
2205 m_tab_ctrl_height = 20;
2206 m_flags = (unsigned int)style;
2207
2208 m_normal_font = *wxNORMAL_FONT;
2209 m_selected_font = *wxNORMAL_FONT;
2210 m_selected_font.SetWeight(wxBOLD);
2211
2212 SetArtProvider(new wxAuiDefaultTabArt);
2213
2214 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
2215 m_dummy_wnd->SetSize(200, 200);
2216 m_dummy_wnd->Show(false);
2217
2218 m_mgr.SetManagedWindow(this);
2219
2220 m_mgr.AddPane(m_dummy_wnd,
2221 wxAuiPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
2222
2223 m_mgr.Update();
2224 }
2225
2226 wxAuiNotebook::~wxAuiNotebook()
2227 {
2228 m_mgr.UnInit();
2229 }
2230
2231 void wxAuiNotebook::SetArtProvider(wxAuiTabArt* art)
2232 {
2233 m_tabs.SetArtProvider(art);
2234
2235 // choose a default for the tab height
2236 m_tab_ctrl_height = art->GetBestTabCtrlSize(this);
2237
2238 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2239 size_t i, pane_count = all_panes.GetCount();
2240 for (i = 0; i < pane_count; ++i)
2241 {
2242 wxAuiPaneInfo& pane = all_panes.Item(i);
2243 if (pane.name == wxT("dummy"))
2244 continue;
2245 wxTabFrame* tab_frame = (wxTabFrame*)pane.window;
2246 wxAuiTabCtrl* tabctrl = tab_frame->m_tabs;
2247 tab_frame->SetTabCtrlHeight(m_tab_ctrl_height);
2248 tabctrl->SetArtProvider(art->Clone());
2249 tab_frame->DoSizing();
2250 }
2251
2252 }
2253
2254 wxAuiTabArt* wxAuiNotebook::GetArtProvider()
2255 {
2256 return m_tabs.GetArtProvider();
2257 }
2258
2259 void wxAuiNotebook::SetWindowStyleFlag(long style)
2260 {
2261 wxControl::SetWindowStyleFlag(style);
2262
2263 m_flags = (unsigned int)style;
2264
2265 // if the control is already initialized
2266 if (m_mgr.GetManagedWindow() == (wxWindow*)this)
2267 {
2268 // let all of the tab children know about the new style
2269
2270 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2271 size_t i, pane_count = all_panes.GetCount();
2272 for (i = 0; i < pane_count; ++i)
2273 {
2274 wxAuiPaneInfo& pane = all_panes.Item(i);
2275 if (pane.name == wxT("dummy"))
2276 continue;
2277 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2278 tabctrl->SetFlags(m_flags);
2279 tabctrl->Refresh();
2280 tabctrl->Update();
2281 }
2282 }
2283 }
2284
2285
2286 bool wxAuiNotebook::AddPage(wxWindow* page,
2287 const wxString& caption,
2288 bool select,
2289 const wxBitmap& bitmap)
2290 {
2291 return InsertPage(GetPageCount(), page, caption, select, bitmap);
2292 }
2293
2294 bool wxAuiNotebook::InsertPage(size_t page_idx,
2295 wxWindow* page,
2296 const wxString& caption,
2297 bool select,
2298 const wxBitmap& bitmap)
2299 {
2300 wxAuiNotebookPage info;
2301 info.window = page;
2302 info.caption = caption;
2303 info.bitmap = bitmap;
2304 info.active = false;
2305
2306 // if there are currently no tabs, the first added
2307 // tab must be active
2308 if (m_tabs.GetPageCount() == 0)
2309 info.active = true;
2310
2311 m_tabs.InsertPage(page, info, page_idx);
2312
2313 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
2314 if (page_idx >= active_tabctrl->GetPageCount())
2315 active_tabctrl->AddPage(page, info);
2316 else
2317 active_tabctrl->InsertPage(page, info, page_idx);
2318
2319 DoSizing();
2320 active_tabctrl->DoShowHide();
2321
2322 if (select)
2323 {
2324 int idx = m_tabs.GetIdxFromWindow(page);
2325 wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiNotebook::InsertPage()"));
2326
2327 SetSelection(idx);
2328 }
2329
2330 return true;
2331 }
2332
2333
2334 // DeletePage() removes a tab from the multi-notebook,
2335 // and destroys the window as well
2336 bool wxAuiNotebook::DeletePage(size_t page_idx)
2337 {
2338 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2339
2340 if (!RemovePage(page_idx))
2341 return false;
2342
2343
2344 // actually destroy the window now
2345 if (wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
2346 {
2347 // delete the child frame with pending delete, as is
2348 // customary with frame windows
2349 if (!wxPendingDelete.Member(wnd))
2350 wxPendingDelete.Append(wnd);
2351 }
2352 else
2353 {
2354 wnd->Destroy();
2355 }
2356
2357 return true;
2358 }
2359
2360
2361
2362 // RemovePage() removes a tab from the multi-notebook,
2363 // but does not destroy the window
2364 bool wxAuiNotebook::RemovePage(size_t page_idx)
2365 {
2366 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
2367 wxWindow* new_active = NULL;
2368
2369 // find out which onscreen tab ctrl owns this tab
2370 wxAuiTabCtrl* ctrl;
2371 int ctrl_idx;
2372 if (!FindTab(wnd, &ctrl, &ctrl_idx))
2373 return false;
2374
2375 // find a new page and set it as active
2376 int new_idx = ctrl_idx+1;
2377 if (new_idx >= (int)ctrl->GetPageCount())
2378 new_idx = ctrl_idx-1;
2379
2380 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
2381 {
2382 new_active = ctrl->GetWindowFromIdx(new_idx);
2383 }
2384 else
2385 {
2386 // set the active page to the first page that
2387 // isn't the one being deleted
2388 size_t i, page_count = m_tabs.GetPageCount();
2389 for (i = 0; i < page_count; ++i)
2390 {
2391 wxWindow* w = m_tabs.GetWindowFromIdx(i);
2392 if (wnd != w)
2393 {
2394 new_active = m_tabs.GetWindowFromIdx(i);
2395 break;
2396 }
2397 }
2398 }
2399
2400 // remove the tab from main catalog
2401 if (!m_tabs.RemovePage(wnd))
2402 return false;
2403
2404 // remove the tab from the onscreen tab ctrl
2405 ctrl->RemovePage(wnd);
2406
2407
2408 RemoveEmptyTabFrames();
2409
2410 // set new active pane
2411 if (new_active)
2412 {
2413 m_curpage = -1;
2414 SetSelection(m_tabs.GetIdxFromWindow(new_active));
2415 }
2416
2417 return true;
2418 }
2419
2420 // SetPageText() changes the tab caption of the specified page
2421 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2422 {
2423 if (page_idx >= m_tabs.GetPageCount())
2424 return false;
2425
2426 // update our own tab catalog
2427 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2428 page_info.caption = text;
2429
2430 // update what's on screen
2431 wxAuiTabCtrl* ctrl;
2432 int ctrl_idx;
2433 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2434 {
2435 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2436 info.caption = text;
2437 ctrl->Refresh();
2438 ctrl->Update();
2439 }
2440
2441 return true;
2442 }
2443
2444 // GetSelection() returns the index of the currently active page
2445 int wxAuiNotebook::GetSelection() const
2446 {
2447 return m_curpage;
2448 }
2449
2450 // SetSelection() sets the currently active page
2451 size_t wxAuiNotebook::SetSelection(size_t new_page)
2452 {
2453 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
2454 if (!wnd)
2455 return m_curpage;
2456
2457 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2458 evt.SetSelection(new_page);
2459 evt.SetOldSelection(m_curpage);
2460 evt.SetEventObject(this);
2461 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
2462 {
2463 // program allows the page change
2464 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
2465 (void)GetEventHandler()->ProcessEvent(evt);
2466
2467
2468
2469 wxAuiTabCtrl* ctrl;
2470 int ctrl_idx;
2471 if (FindTab(wnd, &ctrl, &ctrl_idx))
2472 {
2473 m_tabs.SetActivePage(wnd);
2474
2475 ctrl->SetActivePage(ctrl_idx);
2476 DoSizing();
2477 ctrl->DoShowHide();
2478
2479 int old_curpage = m_curpage;
2480 m_curpage = new_page;
2481
2482
2483 // set fonts
2484 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2485 size_t i, pane_count = all_panes.GetCount();
2486 for (i = 0; i < pane_count; ++i)
2487 {
2488 wxAuiPaneInfo& pane = all_panes.Item(i);
2489 if (pane.name == wxT("dummy"))
2490 continue;
2491 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2492 if (tabctrl != ctrl)
2493 tabctrl->SetSelectedFont(m_normal_font);
2494 else
2495 tabctrl->SetSelectedFont(m_selected_font);
2496 tabctrl->Refresh();
2497 }
2498
2499 wnd->SetFocus();
2500
2501 return old_curpage;
2502 }
2503 }
2504
2505 return m_curpage;
2506 }
2507
2508 // GetPageCount() returns the total number of
2509 // pages managed by the multi-notebook
2510 size_t wxAuiNotebook::GetPageCount() const
2511 {
2512 return m_tabs.GetPageCount();
2513 }
2514
2515 // GetPage() returns the wxWindow pointer of the
2516 // specified page
2517 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2518 {
2519 wxASSERT(page_idx < m_tabs.GetPageCount());
2520
2521 return m_tabs.GetWindowFromIdx(page_idx);
2522 }
2523
2524 // DoSizing() performs all sizing operations in each tab control
2525 void wxAuiNotebook::DoSizing()
2526 {
2527 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2528 size_t i, pane_count = all_panes.GetCount();
2529 for (i = 0; i < pane_count; ++i)
2530 {
2531 if (all_panes.Item(i).name == wxT("dummy"))
2532 continue;
2533
2534 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2535 tabframe->DoSizing();
2536 }
2537 }
2538
2539 // GetActiveTabCtrl() returns the active tab control. It is
2540 // called to determine which control gets new windows being added
2541 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
2542 {
2543 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
2544 {
2545 wxAuiTabCtrl* ctrl;
2546 int idx;
2547
2548 // find the tab ctrl with the current page
2549 if (FindTab(m_tabs.GetPage(m_curpage).window,
2550 &ctrl, &idx))
2551 {
2552 return ctrl;
2553 }
2554 }
2555
2556 // no current page, just find the first tab ctrl
2557 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2558 size_t i, pane_count = all_panes.GetCount();
2559 for (i = 0; i < pane_count; ++i)
2560 {
2561 if (all_panes.Item(i).name == wxT("dummy"))
2562 continue;
2563
2564 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2565 return tabframe->m_tabs;
2566 }
2567
2568 // If there is no tabframe at all, create one
2569 wxTabFrame* tabframe = new wxTabFrame;
2570 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
2571 tabframe->m_tabs = new wxAuiTabCtrl(this,
2572 m_tab_id_counter++,
2573 wxDefaultPosition,
2574 wxDefaultSize,
2575 wxNO_BORDER);
2576 tabframe->m_tabs->SetFlags(m_flags);
2577 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2578 m_mgr.AddPane(tabframe,
2579 wxAuiPaneInfo().Center().CaptionVisible(false));
2580
2581 m_mgr.Update();
2582
2583 return tabframe->m_tabs;
2584 }
2585
2586 // FindTab() finds the tab control that currently contains the window as well
2587 // as the index of the window in the tab control. It returns true if the
2588 // window was found, otherwise false.
2589 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2590 {
2591 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2592 size_t i, pane_count = all_panes.GetCount();
2593 for (i = 0; i < pane_count; ++i)
2594 {
2595 if (all_panes.Item(i).name == wxT("dummy"))
2596 continue;
2597
2598 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2599
2600 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2601 if (page_idx != -1)
2602 {
2603 *ctrl = tabframe->m_tabs;
2604 *idx = page_idx;
2605 return true;
2606 }
2607 }
2608
2609 return false;
2610 }
2611
2612
2613 void wxAuiNotebook::OnEraseBackground(wxEraseEvent&)
2614 {
2615 }
2616
2617 void wxAuiNotebook::OnSize(wxSizeEvent&)
2618 {
2619 }
2620
2621 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
2622 {
2623 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2624
2625 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2626 wxASSERT(ctrl != NULL);
2627
2628 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
2629 wxASSERT(wnd != NULL);
2630
2631 int idx = m_tabs.GetIdxFromWindow(wnd);
2632 wxASSERT(idx != -1);
2633
2634 SetSelection(idx);
2635 }
2636
2637 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
2638 {
2639 m_last_drag_x = 0;
2640 }
2641
2642 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
2643 {
2644 wxPoint screen_pt = ::wxGetMousePosition();
2645 wxPoint client_pt = ScreenToClient(screen_pt);
2646 wxPoint zero(0,0);
2647
2648 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2649 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
2650
2651 if (dest_tabs == src_tabs)
2652 {
2653 if (src_tabs)
2654 {
2655 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2656 }
2657
2658 // always hide the hint for inner-tabctrl drag
2659 m_mgr.HideHint();
2660
2661 // if tab moving is not allowed, leave
2662 if (!(m_flags & wxAUI_NB_TAB_MOVE))
2663 {
2664 return;
2665 }
2666
2667 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
2668 wxWindow* dest_location_tab;
2669
2670 // this is an inner-tab drag/reposition
2671 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
2672 {
2673 int src_idx = evt.GetSelection();
2674 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
2675
2676 // prevent jumpy drag
2677 if ((src_idx == dest_idx) || dest_idx == -1 ||
2678 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
2679 (src_idx < dest_idx && m_last_drag_x >= pt.x))
2680 {
2681 m_last_drag_x = pt.x;
2682 return;
2683 }
2684
2685
2686 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
2687 dest_tabs->MovePage(src_tab, dest_idx);
2688 dest_tabs->SetActivePage((size_t)dest_idx);
2689 dest_tabs->DoShowHide();
2690 dest_tabs->Refresh();
2691 m_last_drag_x = pt.x;
2692
2693 }
2694
2695 return;
2696 }
2697
2698
2699 // if external drag is allowed, check if the tab is being dragged
2700 // over a different wxAuiNotebook control
2701 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2702 {
2703 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
2704
2705 // make sure we are not over the hint window
2706 if (tab_ctrl && !tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
2707 {
2708 while (tab_ctrl)
2709 {
2710 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
2711 break;
2712 tab_ctrl = tab_ctrl->GetParent();
2713 }
2714
2715 if (tab_ctrl)
2716 {
2717 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2718
2719 if (nb != this)
2720 {
2721 wxRect hint_rect = tab_ctrl->GetRect();
2722 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
2723 m_mgr.ShowHint(hint_rect);
2724 return;
2725 }
2726
2727 }
2728 }
2729 }
2730
2731
2732 // if tab moving is not allowed, leave
2733 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
2734 {
2735 return;
2736 }
2737
2738
2739 if (src_tabs)
2740 {
2741 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
2742 }
2743
2744
2745 if (dest_tabs)
2746 {
2747 wxRect hint_rect = dest_tabs->GetRect();
2748 ClientToScreen(&hint_rect.x, &hint_rect.y);
2749 m_mgr.ShowHint(hint_rect);
2750 }
2751 else
2752 {
2753 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
2754 }
2755 }
2756
2757
2758
2759 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
2760 {
2761 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2762
2763 m_mgr.HideHint();
2764
2765
2766 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2767 wxAuiTabCtrl* dest_tabs = NULL;
2768 if (src_tabs)
2769 {
2770 // set cursor back to an arrow
2771 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2772 }
2773
2774 // get the mouse position, which will be used to determine the drop point
2775 wxPoint mouse_screen_pt = ::wxGetMousePosition();
2776 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
2777
2778
2779
2780 // check for an external move
2781 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2782 {
2783 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
2784
2785 while (tab_ctrl)
2786 {
2787 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
2788 break;
2789 tab_ctrl = tab_ctrl->GetParent();
2790 }
2791
2792 if (tab_ctrl)
2793 {
2794 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2795
2796 if (nb != this)
2797 {
2798 // find out from the destination control
2799 // if it's ok to drop this tab here
2800 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
2801 e.SetSelection(evt.GetSelection());
2802 e.SetOldSelection(evt.GetSelection());
2803 e.SetEventObject(this);
2804 e.SetDragSource(this);
2805 e.Veto(); // dropping must be explicitly approved by control owner
2806
2807 nb->GetEventHandler()->ProcessEvent(e);
2808
2809 if (!e.IsAllowed())
2810 {
2811 // no answer or negative answer
2812 m_mgr.HideHint();
2813 return;
2814 }
2815
2816 // drop was allowed
2817 int src_idx = evt.GetSelection();
2818 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
2819
2820 // get main index of the page
2821 int main_idx = m_tabs.GetIdxFromWindow(src_page);
2822
2823 // make a copy of the page info
2824 wxAuiNotebookPage page_info = m_tabs.GetPage((size_t)main_idx);
2825
2826 // remove the page from the source notebook
2827 RemovePage(main_idx);
2828
2829 // reparent the page
2830 src_page->Reparent(nb);
2831
2832
2833 // found out the insert idx
2834 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
2835 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2836
2837 wxWindow* target = NULL;
2838 int insert_idx = -1;
2839 dest_tabs->TabHitTest(pt.x, pt.y, &target);
2840 if (target)
2841 {
2842 insert_idx = dest_tabs->GetIdxFromWindow(target);
2843 }
2844
2845
2846 // add the page to the new notebook
2847 if (insert_idx == -1)
2848 insert_idx = dest_tabs->GetPageCount();
2849 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2850 nb->m_tabs.AddPage(page_info.window, page_info);
2851
2852 nb->DoSizing();
2853 dest_tabs->DoShowHide();
2854 dest_tabs->Refresh();
2855
2856 // set the selection in the destination tab control
2857 nb->SetSelection(nb->m_tabs.GetIdxFromWindow(page_info.window));
2858
2859 return;
2860 }
2861 }
2862 }
2863
2864
2865
2866
2867 // only perform a tab split if it's allowed
2868 if (m_flags & wxAUI_NB_TAB_SPLIT)
2869 {
2870 // If the pointer is in an existing tab frame, do a tab insert
2871 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
2872 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
2873 int insert_idx = -1;
2874 if (tab_frame)
2875 {
2876 dest_tabs = tab_frame->m_tabs;
2877
2878 if (dest_tabs == src_tabs)
2879 return;
2880
2881
2882 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
2883 wxWindow* target = NULL;
2884 dest_tabs->TabHitTest(pt.x, pt.y, &target);
2885 if (target)
2886 {
2887 insert_idx = dest_tabs->GetIdxFromWindow(target);
2888 }
2889 }
2890 else
2891 {
2892 // If there is no tabframe at all, create one
2893 wxTabFrame* new_tabs = new wxTabFrame;
2894 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
2895 new_tabs->m_tabs = new wxAuiTabCtrl(this,
2896 m_tab_id_counter++,
2897 wxDefaultPosition,
2898 wxDefaultSize,
2899 wxNO_BORDER);
2900 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2901 new_tabs->m_tabs->SetFlags(m_flags);
2902
2903 m_mgr.AddPane(new_tabs,
2904 wxAuiPaneInfo().Bottom().CaptionVisible(false),
2905 mouse_client_pt);
2906 m_mgr.Update();
2907 dest_tabs = new_tabs->m_tabs;
2908 }
2909
2910
2911
2912 // remove the page from the source tabs
2913 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
2914 page_info.active = false;
2915 src_tabs->RemovePage(page_info.window);
2916 if (src_tabs->GetPageCount() > 0)
2917 {
2918 src_tabs->SetActivePage((size_t)0);
2919 src_tabs->DoShowHide();
2920 src_tabs->Refresh();
2921 }
2922
2923
2924
2925 // add the page to the destination tabs
2926 if (insert_idx == -1)
2927 insert_idx = dest_tabs->GetPageCount();
2928 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
2929
2930 if (src_tabs->GetPageCount() == 0)
2931 {
2932 RemoveEmptyTabFrames();
2933 }
2934
2935 DoSizing();
2936 dest_tabs->DoShowHide();
2937 dest_tabs->Refresh();
2938
2939 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
2940 }
2941 }
2942
2943
2944
2945 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
2946 {
2947 // if we've just removed the last tab from the source
2948 // tab set, the remove the tab control completely
2949 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2950 size_t i, pane_count = all_panes.GetCount();
2951 for (i = 0; i < pane_count; ++i)
2952 {
2953 if (all_panes.Item(i).name == wxT("dummy"))
2954 continue;
2955
2956 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2957 if (tabframe->m_tab_rect.Contains(pt))
2958 return tabframe->m_tabs;
2959 }
2960
2961 return NULL;
2962 }
2963
2964 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
2965 {
2966 // if we've just removed the last tab from the source
2967 // tab set, the remove the tab control completely
2968 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2969 size_t i, pane_count = all_panes.GetCount();
2970 for (i = 0; i < pane_count; ++i)
2971 {
2972 if (all_panes.Item(i).name == wxT("dummy"))
2973 continue;
2974
2975 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2976 if (tabframe->m_tabs == tab_ctrl)
2977 {
2978 return tabframe;
2979 }
2980 }
2981
2982 return NULL;
2983 }
2984
2985 void wxAuiNotebook::RemoveEmptyTabFrames()
2986 {
2987 // if we've just removed the last tab from the source
2988 // tab set, the remove the tab control completely
2989 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
2990 size_t i, pane_count = all_panes.GetCount();
2991 for (i = 0; i < pane_count; ++i)
2992 {
2993 if (all_panes.Item(i).name == wxT("dummy"))
2994 continue;
2995
2996 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
2997 if (tab_frame->m_tabs->GetPageCount() == 0)
2998 {
2999 m_mgr.DetachPane(tab_frame);
3000
3001 // use pending delete because sometimes during
3002 // window closing, refreshs are pending
3003 if (!wxPendingDelete.Member(tab_frame->m_tabs))
3004 wxPendingDelete.Append(tab_frame->m_tabs);
3005 //tab_frame->m_tabs->Destroy();
3006
3007 delete tab_frame;
3008 }
3009 }
3010
3011
3012 // check to see if there is still a center pane;
3013 // if there isn't, make a frame the center pane
3014 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
3015 pane_count = panes.GetCount();
3016 wxWindow* first_good = NULL;
3017 bool center_found = false;
3018 for (i = 0; i < pane_count; ++i)
3019 {
3020 if (panes.Item(i).name == wxT("dummy"))
3021 continue;
3022 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
3023 center_found = true;
3024 if (!first_good)
3025 first_good = panes.Item(i).window;
3026 }
3027
3028 if (!center_found && first_good)
3029 {
3030 m_mgr.GetPane(first_good).Centre();
3031 }
3032
3033 m_mgr.Update();
3034 }
3035
3036 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
3037 {
3038 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
3039 if (idx != -1 && idx != m_curpage)
3040 {
3041 SetSelection(idx);
3042 }
3043 }
3044
3045
3046 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
3047 {
3048 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3049 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3050
3051 int button_id = evt.GetInt();
3052
3053 if (button_id == wxAUI_BUTTON_CLOSE)
3054 {
3055 int selection = tabs->GetActivePage();
3056
3057 if (selection != -1)
3058 {
3059 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3060
3061
3062 // ask owner if it's ok to close the tab
3063 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3064 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3065 e.SetOldSelection(evt.GetSelection());
3066 e.SetEventObject(this);
3067 GetEventHandler()->ProcessEvent(e);
3068 if (!e.IsAllowed())
3069 return;
3070
3071
3072 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3073 {
3074 close_wnd->Close();
3075 }
3076 else
3077 {
3078 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3079 DeletePage(main_idx);
3080 }
3081 }
3082 }
3083 }
3084
3085
3086
3087
3088 #endif // wxUSE_AUI