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