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