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