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