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