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