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