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