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