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