]> git.saurik.com Git - wxWidgets.git/blob - src/aui/auibook.cpp
wxAuiMDI* patches through images to 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() const
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() const
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 // GetPageIndex() returns the index of the page, or -1 if the
2552 // page could not be located in the notebook
2553 int wxAuiNotebook::GetPageIndex(wxWindow* page_wnd) const
2554 {
2555 return m_tabs.GetIdxFromWindow(page_wnd);
2556 }
2557
2558
2559
2560 // SetPageText() changes the tab caption of the specified page
2561 bool wxAuiNotebook::SetPageText(size_t page_idx, const wxString& text)
2562 {
2563 if (page_idx >= m_tabs.GetPageCount())
2564 return false;
2565
2566 // update our own tab catalog
2567 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2568 page_info.caption = text;
2569
2570 // update what's on screen
2571 wxAuiTabCtrl* ctrl;
2572 int ctrl_idx;
2573 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2574 {
2575 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2576 info.caption = text;
2577 ctrl->Refresh();
2578 ctrl->Update();
2579 }
2580
2581 return true;
2582 }
2583
2584
2585 bool wxAuiNotebook::SetPageBitmap(size_t page_idx, const wxBitmap& bitmap)
2586 {
2587 if (page_idx >= m_tabs.GetPageCount())
2588 return false;
2589
2590 // update our own tab catalog
2591 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
2592 page_info.bitmap = bitmap;
2593
2594 // tab height might have changed
2595 SetTabCtrlHeight(CalculateTabCtrlHeight());
2596
2597 // update what's on screen
2598 wxAuiTabCtrl* ctrl;
2599 int ctrl_idx;
2600 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
2601 {
2602 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
2603 info.bitmap = bitmap;
2604 ctrl->Refresh();
2605 ctrl->Update();
2606 }
2607
2608 return true;
2609 }
2610
2611
2612 // GetSelection() returns the index of the currently active page
2613 int wxAuiNotebook::GetSelection() const
2614 {
2615 return m_curpage;
2616 }
2617
2618 // SetSelection() sets the currently active page
2619 size_t wxAuiNotebook::SetSelection(size_t new_page)
2620 {
2621 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
2622 if (!wnd)
2623 return m_curpage;
2624
2625 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
2626 evt.SetSelection(new_page);
2627 evt.SetOldSelection(m_curpage);
2628 evt.SetEventObject(this);
2629 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
2630 {
2631 // program allows the page change
2632 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
2633 (void)GetEventHandler()->ProcessEvent(evt);
2634
2635
2636
2637 wxAuiTabCtrl* ctrl;
2638 int ctrl_idx;
2639 if (FindTab(wnd, &ctrl, &ctrl_idx))
2640 {
2641 m_tabs.SetActivePage(wnd);
2642
2643 ctrl->SetActivePage(ctrl_idx);
2644 DoSizing();
2645 ctrl->DoShowHide();
2646
2647 int old_curpage = m_curpage;
2648 m_curpage = new_page;
2649
2650
2651 // set fonts
2652 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2653 size_t i, pane_count = all_panes.GetCount();
2654 for (i = 0; i < pane_count; ++i)
2655 {
2656 wxAuiPaneInfo& pane = all_panes.Item(i);
2657 if (pane.name == wxT("dummy"))
2658 continue;
2659 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
2660 if (tabctrl != ctrl)
2661 tabctrl->SetSelectedFont(m_normal_font);
2662 else
2663 tabctrl->SetSelectedFont(m_selected_font);
2664 tabctrl->Refresh();
2665 }
2666
2667 wnd->SetFocus();
2668
2669 return old_curpage;
2670 }
2671 }
2672
2673 return m_curpage;
2674 }
2675
2676 // GetPageCount() returns the total number of
2677 // pages managed by the multi-notebook
2678 size_t wxAuiNotebook::GetPageCount() const
2679 {
2680 return m_tabs.GetPageCount();
2681 }
2682
2683 // GetPage() returns the wxWindow pointer of the
2684 // specified page
2685 wxWindow* wxAuiNotebook::GetPage(size_t page_idx) const
2686 {
2687 wxASSERT(page_idx < m_tabs.GetPageCount());
2688
2689 return m_tabs.GetWindowFromIdx(page_idx);
2690 }
2691
2692 // DoSizing() performs all sizing operations in each tab control
2693 void wxAuiNotebook::DoSizing()
2694 {
2695 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2696 size_t i, pane_count = all_panes.GetCount();
2697 for (i = 0; i < pane_count; ++i)
2698 {
2699 if (all_panes.Item(i).name == wxT("dummy"))
2700 continue;
2701
2702 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2703 tabframe->DoSizing();
2704 }
2705 }
2706
2707 // GetActiveTabCtrl() returns the active tab control. It is
2708 // called to determine which control gets new windows being added
2709 wxAuiTabCtrl* wxAuiNotebook::GetActiveTabCtrl()
2710 {
2711 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
2712 {
2713 wxAuiTabCtrl* ctrl;
2714 int idx;
2715
2716 // find the tab ctrl with the current page
2717 if (FindTab(m_tabs.GetPage(m_curpage).window,
2718 &ctrl, &idx))
2719 {
2720 return ctrl;
2721 }
2722 }
2723
2724 // no current page, just find the first tab ctrl
2725 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2726 size_t i, pane_count = all_panes.GetCount();
2727 for (i = 0; i < pane_count; ++i)
2728 {
2729 if (all_panes.Item(i).name == wxT("dummy"))
2730 continue;
2731
2732 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2733 return tabframe->m_tabs;
2734 }
2735
2736 // If there is no tabframe at all, create one
2737 wxTabFrame* tabframe = new wxTabFrame;
2738 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
2739 tabframe->m_tabs = new wxAuiTabCtrl(this,
2740 m_tab_id_counter++,
2741 wxDefaultPosition,
2742 wxDefaultSize,
2743 wxNO_BORDER);
2744 tabframe->m_tabs->SetFlags(m_flags);
2745 tabframe->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
2746 m_mgr.AddPane(tabframe,
2747 wxAuiPaneInfo().Center().CaptionVisible(false));
2748
2749 m_mgr.Update();
2750
2751 return tabframe->m_tabs;
2752 }
2753
2754 // FindTab() finds the tab control that currently contains the window as well
2755 // as the index of the window in the tab control. It returns true if the
2756 // window was found, otherwise false.
2757 bool wxAuiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
2758 {
2759 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
2760 size_t i, pane_count = all_panes.GetCount();
2761 for (i = 0; i < pane_count; ++i)
2762 {
2763 if (all_panes.Item(i).name == wxT("dummy"))
2764 continue;
2765
2766 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
2767
2768 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
2769 if (page_idx != -1)
2770 {
2771 *ctrl = tabframe->m_tabs;
2772 *idx = page_idx;
2773 return true;
2774 }
2775 }
2776
2777 return false;
2778 }
2779
2780
2781 void wxAuiNotebook::OnEraseBackground(wxEraseEvent&)
2782 {
2783 }
2784
2785 void wxAuiNotebook::OnSize(wxSizeEvent&)
2786 {
2787 }
2788
2789 void wxAuiNotebook::OnTabClicked(wxCommandEvent& command_evt)
2790 {
2791 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2792
2793 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
2794 wxASSERT(ctrl != NULL);
2795
2796 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
2797 wxASSERT(wnd != NULL);
2798
2799 int idx = m_tabs.GetIdxFromWindow(wnd);
2800 wxASSERT(idx != -1);
2801
2802 SetSelection(idx);
2803 }
2804
2805 void wxAuiNotebook::OnTabBeginDrag(wxCommandEvent&)
2806 {
2807 m_last_drag_x = 0;
2808 }
2809
2810 void wxAuiNotebook::OnTabDragMotion(wxCommandEvent& evt)
2811 {
2812 wxPoint screen_pt = ::wxGetMousePosition();
2813 wxPoint client_pt = ScreenToClient(screen_pt);
2814 wxPoint zero(0,0);
2815
2816 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2817 wxAuiTabCtrl* dest_tabs = GetTabCtrlFromPoint(client_pt);
2818
2819 if (dest_tabs == src_tabs)
2820 {
2821 if (src_tabs)
2822 {
2823 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2824 }
2825
2826 // always hide the hint for inner-tabctrl drag
2827 m_mgr.HideHint();
2828
2829 // if tab moving is not allowed, leave
2830 if (!(m_flags & wxAUI_NB_TAB_MOVE))
2831 {
2832 return;
2833 }
2834
2835 wxPoint pt = dest_tabs->ScreenToClient(screen_pt);
2836 wxWindow* dest_location_tab;
2837
2838 // this is an inner-tab drag/reposition
2839 if (dest_tabs->TabHitTest(pt.x, pt.y, &dest_location_tab))
2840 {
2841 int src_idx = evt.GetSelection();
2842 int dest_idx = dest_tabs->GetIdxFromWindow(dest_location_tab);
2843
2844 // prevent jumpy drag
2845 if ((src_idx == dest_idx) || dest_idx == -1 ||
2846 (src_idx > dest_idx && m_last_drag_x <= pt.x) ||
2847 (src_idx < dest_idx && m_last_drag_x >= pt.x))
2848 {
2849 m_last_drag_x = pt.x;
2850 return;
2851 }
2852
2853
2854 wxWindow* src_tab = dest_tabs->GetWindowFromIdx(src_idx);
2855 dest_tabs->MovePage(src_tab, dest_idx);
2856 dest_tabs->SetActivePage((size_t)dest_idx);
2857 dest_tabs->DoShowHide();
2858 dest_tabs->Refresh();
2859 m_last_drag_x = pt.x;
2860
2861 }
2862
2863 return;
2864 }
2865
2866
2867 // if external drag is allowed, check if the tab is being dragged
2868 // over a different wxAuiNotebook control
2869 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2870 {
2871 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(screen_pt);
2872
2873 // if we aren't over any window, stop here
2874 if (!tab_ctrl)
2875 return;
2876
2877 // make sure we are not over the hint window
2878 if (!tab_ctrl->IsKindOf(CLASSINFO(wxFrame)))
2879 {
2880 while (tab_ctrl)
2881 {
2882 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
2883 break;
2884 tab_ctrl = tab_ctrl->GetParent();
2885 }
2886
2887 if (tab_ctrl)
2888 {
2889 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2890
2891 if (nb != this)
2892 {
2893 wxRect hint_rect = tab_ctrl->GetClientRect();
2894 tab_ctrl->ClientToScreen(&hint_rect.x, &hint_rect.y);
2895 m_mgr.ShowHint(hint_rect);
2896 return;
2897 }
2898 }
2899 }
2900 else
2901 {
2902 if (!dest_tabs)
2903 {
2904 // we are either over a hint window, or not over a tab
2905 // window, and there is no where to drag to, so exit
2906 return;
2907 }
2908 }
2909 }
2910
2911
2912 // if there are less than two panes, split can't happen, so leave
2913 if (m_tabs.GetPageCount() < 2)
2914 return;
2915
2916 // if tab moving is not allowed, leave
2917 if (!(m_flags & wxAUI_NB_TAB_SPLIT))
2918 return;
2919
2920
2921 if (src_tabs)
2922 {
2923 src_tabs->SetCursor(wxCursor(wxCURSOR_SIZING));
2924 }
2925
2926
2927 if (dest_tabs)
2928 {
2929 wxRect hint_rect = dest_tabs->GetRect();
2930 ClientToScreen(&hint_rect.x, &hint_rect.y);
2931 m_mgr.ShowHint(hint_rect);
2932 }
2933 else
2934 {
2935 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
2936 }
2937 }
2938
2939
2940
2941 void wxAuiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
2942 {
2943 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
2944
2945 m_mgr.HideHint();
2946
2947
2948 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
2949 wxAuiTabCtrl* dest_tabs = NULL;
2950 if (src_tabs)
2951 {
2952 // set cursor back to an arrow
2953 src_tabs->SetCursor(wxCursor(wxCURSOR_ARROW));
2954 }
2955
2956 // get the mouse position, which will be used to determine the drop point
2957 wxPoint mouse_screen_pt = ::wxGetMousePosition();
2958 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
2959
2960
2961
2962 // check for an external move
2963 if (m_flags & wxAUI_NB_TAB_EXTERNAL_MOVE)
2964 {
2965 wxWindow* tab_ctrl = ::wxFindWindowAtPoint(mouse_screen_pt);
2966
2967 while (tab_ctrl)
2968 {
2969 if (tab_ctrl->IsKindOf(CLASSINFO(wxAuiTabCtrl)))
2970 break;
2971 tab_ctrl = tab_ctrl->GetParent();
2972 }
2973
2974 if (tab_ctrl)
2975 {
2976 wxAuiNotebook* nb = (wxAuiNotebook*)tab_ctrl->GetParent();
2977
2978 if (nb != this)
2979 {
2980 // find out from the destination control
2981 // if it's ok to drop this tab here
2982 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, m_windowId);
2983 e.SetSelection(evt.GetSelection());
2984 e.SetOldSelection(evt.GetSelection());
2985 e.SetEventObject(this);
2986 e.SetDragSource(this);
2987 e.Veto(); // dropping must be explicitly approved by control owner
2988
2989 nb->GetEventHandler()->ProcessEvent(e);
2990
2991 if (!e.IsAllowed())
2992 {
2993 // no answer or negative answer
2994 m_mgr.HideHint();
2995 return;
2996 }
2997
2998 // drop was allowed
2999 int src_idx = evt.GetSelection();
3000 wxWindow* src_page = src_tabs->GetWindowFromIdx(src_idx);
3001
3002 // get main index of the page
3003 int main_idx = m_tabs.GetIdxFromWindow(src_page);
3004
3005 // make a copy of the page info
3006 wxAuiNotebookPage page_info = m_tabs.GetPage((size_t)main_idx);
3007
3008 // remove the page from the source notebook
3009 RemovePage(main_idx);
3010
3011 // reparent the page
3012 src_page->Reparent(nb);
3013
3014
3015 // found out the insert idx
3016 wxAuiTabCtrl* dest_tabs = (wxAuiTabCtrl*)tab_ctrl;
3017 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3018
3019 wxWindow* target = NULL;
3020 int insert_idx = -1;
3021 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3022 if (target)
3023 {
3024 insert_idx = dest_tabs->GetIdxFromWindow(target);
3025 }
3026
3027
3028 // add the page to the new notebook
3029 if (insert_idx == -1)
3030 insert_idx = dest_tabs->GetPageCount();
3031 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3032 nb->m_tabs.AddPage(page_info.window, page_info);
3033
3034 nb->DoSizing();
3035 dest_tabs->DoShowHide();
3036 dest_tabs->Refresh();
3037
3038 // set the selection in the destination tab control
3039 nb->SetSelection(nb->m_tabs.GetIdxFromWindow(page_info.window));
3040
3041 return;
3042 }
3043 }
3044 }
3045
3046
3047
3048
3049 // only perform a tab split if it's allowed
3050 if ((m_flags & wxAUI_NB_TAB_SPLIT) && m_tabs.GetPageCount() >= 2)
3051 {
3052 // If the pointer is in an existing tab frame, do a tab insert
3053 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
3054 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
3055 int insert_idx = -1;
3056 if (tab_frame)
3057 {
3058 dest_tabs = tab_frame->m_tabs;
3059
3060 if (dest_tabs == src_tabs)
3061 return;
3062
3063
3064 wxPoint pt = dest_tabs->ScreenToClient(mouse_screen_pt);
3065 wxWindow* target = NULL;
3066 dest_tabs->TabHitTest(pt.x, pt.y, &target);
3067 if (target)
3068 {
3069 insert_idx = dest_tabs->GetIdxFromWindow(target);
3070 }
3071 }
3072 else
3073 {
3074 // If there is no tabframe at all, create one
3075 wxTabFrame* new_tabs = new wxTabFrame;
3076 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
3077 new_tabs->m_tabs = new wxAuiTabCtrl(this,
3078 m_tab_id_counter++,
3079 wxDefaultPosition,
3080 wxDefaultSize,
3081 wxNO_BORDER);
3082 new_tabs->m_tabs->SetArtProvider(m_tabs.GetArtProvider()->Clone());
3083 new_tabs->m_tabs->SetFlags(m_flags);
3084
3085 m_mgr.AddPane(new_tabs,
3086 wxAuiPaneInfo().Bottom().CaptionVisible(false),
3087 mouse_client_pt);
3088 m_mgr.Update();
3089 dest_tabs = new_tabs->m_tabs;
3090 }
3091
3092
3093
3094 // remove the page from the source tabs
3095 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
3096 page_info.active = false;
3097 src_tabs->RemovePage(page_info.window);
3098 if (src_tabs->GetPageCount() > 0)
3099 {
3100 src_tabs->SetActivePage((size_t)0);
3101 src_tabs->DoShowHide();
3102 src_tabs->Refresh();
3103 }
3104
3105
3106
3107 // add the page to the destination tabs
3108 if (insert_idx == -1)
3109 insert_idx = dest_tabs->GetPageCount();
3110 dest_tabs->InsertPage(page_info.window, page_info, insert_idx);
3111
3112 if (src_tabs->GetPageCount() == 0)
3113 {
3114 RemoveEmptyTabFrames();
3115 }
3116
3117 DoSizing();
3118 dest_tabs->DoShowHide();
3119 dest_tabs->Refresh();
3120
3121 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
3122 }
3123 }
3124
3125
3126
3127 wxAuiTabCtrl* wxAuiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
3128 {
3129 // if we've just removed the last tab from the source
3130 // tab set, the remove the tab control completely
3131 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3132 size_t i, pane_count = all_panes.GetCount();
3133 for (i = 0; i < pane_count; ++i)
3134 {
3135 if (all_panes.Item(i).name == wxT("dummy"))
3136 continue;
3137
3138 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3139 if (tabframe->m_tab_rect.Contains(pt))
3140 return tabframe->m_tabs;
3141 }
3142
3143 return NULL;
3144 }
3145
3146 wxWindow* wxAuiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
3147 {
3148 // if we've just removed the last tab from the source
3149 // tab set, the remove the tab control completely
3150 wxAuiPaneInfoArray& all_panes = m_mgr.GetAllPanes();
3151 size_t i, pane_count = all_panes.GetCount();
3152 for (i = 0; i < pane_count; ++i)
3153 {
3154 if (all_panes.Item(i).name == wxT("dummy"))
3155 continue;
3156
3157 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
3158 if (tabframe->m_tabs == tab_ctrl)
3159 {
3160 return tabframe;
3161 }
3162 }
3163
3164 return NULL;
3165 }
3166
3167 void wxAuiNotebook::RemoveEmptyTabFrames()
3168 {
3169 // if we've just removed the last tab from the source
3170 // tab set, the remove the tab control completely
3171 wxAuiPaneInfoArray all_panes = m_mgr.GetAllPanes();
3172 size_t i, pane_count = all_panes.GetCount();
3173 for (i = 0; i < pane_count; ++i)
3174 {
3175 if (all_panes.Item(i).name == wxT("dummy"))
3176 continue;
3177
3178 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
3179 if (tab_frame->m_tabs->GetPageCount() == 0)
3180 {
3181 m_mgr.DetachPane(tab_frame);
3182
3183 // use pending delete because sometimes during
3184 // window closing, refreshs are pending
3185 if (!wxPendingDelete.Member(tab_frame->m_tabs))
3186 wxPendingDelete.Append(tab_frame->m_tabs);
3187 //tab_frame->m_tabs->Destroy();
3188
3189 delete tab_frame;
3190 }
3191 }
3192
3193
3194 // check to see if there is still a center pane;
3195 // if there isn't, make a frame the center pane
3196 wxAuiPaneInfoArray panes = m_mgr.GetAllPanes();
3197 pane_count = panes.GetCount();
3198 wxWindow* first_good = NULL;
3199 bool center_found = false;
3200 for (i = 0; i < pane_count; ++i)
3201 {
3202 if (panes.Item(i).name == wxT("dummy"))
3203 continue;
3204 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
3205 center_found = true;
3206 if (!first_good)
3207 first_good = panes.Item(i).window;
3208 }
3209
3210 if (!center_found && first_good)
3211 {
3212 m_mgr.GetPane(first_good).Centre();
3213 }
3214
3215 m_mgr.Update();
3216 }
3217
3218 void wxAuiNotebook::OnChildFocus(wxChildFocusEvent& evt)
3219 {
3220 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
3221 if (idx != -1 && idx != m_curpage)
3222 {
3223 SetSelection(idx);
3224 }
3225 }
3226
3227
3228 void wxAuiNotebook::OnTabButton(wxCommandEvent& command_evt)
3229 {
3230 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
3231 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
3232
3233 int button_id = evt.GetInt();
3234
3235 if (button_id == wxAUI_BUTTON_CLOSE)
3236 {
3237 int selection = tabs->GetActivePage();
3238
3239 if (selection != -1)
3240 {
3241 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
3242
3243
3244 // ask owner if it's ok to close the tab
3245 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, m_windowId);
3246 e.SetSelection(m_tabs.GetIdxFromWindow(close_wnd));
3247 e.SetOldSelection(evt.GetSelection());
3248 e.SetEventObject(this);
3249 GetEventHandler()->ProcessEvent(e);
3250 if (!e.IsAllowed())
3251 return;
3252
3253
3254 if (close_wnd->IsKindOf(CLASSINFO(wxAuiMDIChildFrame)))
3255 {
3256 close_wnd->Close();
3257 }
3258 else
3259 {
3260 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
3261 DeletePage(main_idx);
3262 }
3263 }
3264 }
3265 }
3266
3267
3268
3269
3270 #endif // wxUSE_AUI