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