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