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