]> git.saurik.com Git - wxWidgets.git/blame - src/aui/auibook.cpp
generate middle click events (patch 1521314)
[wxWidgets.git] / src / aui / auibook.cpp
CommitLineData
cd05bf23 1///////////////////////////////////////////////////////////////////////////////
4444d148 2// Name: src/aui/auibook.cpp
cd05bf23
BW
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
189da67c 23#include "wx/aui/auibook.h"
cd05bf23
BW
24
25#ifndef WX_PRECOMP
4444d148 26 #include "wx/settings.h"
03265113 27 #include "wx/image.h"
cd05bf23
BW
28#endif
29
4444d148
WS
30#include "wx/aui/tabmdi.h"
31#include "wx/dcbuffer.h"
32
cd05bf23
BW
33#include "wx/arrimpl.cpp"
34WX_DEFINE_OBJARRAY(wxAuiNotebookPageArray)
35WX_DEFINE_OBJARRAY(wxAuiTabContainerButtonArray)
36
37DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING)
38DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED)
39DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BUTTON)
40DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG)
41DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG)
42DEFINE_EVENT_TYPE(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION)
43
44
45
46IMPLEMENT_DYNAMIC_CLASS(wxAuiNotebookEvent, wxEvent)
47
48// -- wxAuiTabContainer class implementation --
49
50
51// wxAuiTabContainer is a class which contains information about each
52// tab. It also can render an entire tab control to a specified DC.
53// It's not a window class itself, because this code will be used by
54// the wxFrameMananger, where it is disadvantageous to have separate
55// windows for each tab control in the case of "docked tabs"
56
57// A derived class, wxAuiTabCtrl, is an actual wxWindow-derived window
58// which can be used as a tab control in the normal sense.
59
60
61// This functions are here for this proof of concept
62// and will be factored out later. See dockart.cpp
63static wxColor StepColour(const wxColor& c, int percent)
64{
65 int r = c.Red(), g = c.Green(), b = c.Blue();
66 return wxColour((unsigned char)wxMin((r*percent)/100,255),
67 (unsigned char)wxMin((g*percent)/100,255),
68 (unsigned char)wxMin((b*percent)/100,255));
69}
70
71// This functions are here for this proof of concept
72// and will be factored out later. See dockart.cpp
73static wxBitmap BitmapFromBits(const unsigned char bits[], int w, int h,
74 const wxColour& color)
75{
76 wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage();
77 img.Replace(255,255,255,123,123,123);
78 img.Replace(0,0,0,color.Red(),color.Green(),color.Blue());
79 img.SetMaskColour(123,123,123);
80 return wxBitmap(img);
81}
82
83static void DrawButton(wxDC& dc,
84 const wxRect& _rect,
85 const wxBitmap& bmp,
86 const wxColour& bkcolour,
87 int button_state)
88{
89 wxRect rect = _rect;
90
91 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
92 {
93 rect.x++;
94 rect.y++;
95 }
96
97 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
98 button_state == wxAUI_BUTTON_STATE_PRESSED)
99 {
100 dc.SetBrush(wxBrush(StepColour(bkcolour, 120)));
101 dc.SetPen(wxPen(StepColour(bkcolour, 70)));
102
103 // draw the background behind the button
104 dc.DrawRectangle(rect.x, rect.y, 15, 15);
105 }
106
107 // draw the button itself
108 dc.DrawBitmap(bmp, rect.x, rect.y, true);
109}
110
111
112
113
114wxAuiTabContainer::wxAuiTabContainer()
115{
116 m_normal_font = *wxNORMAL_FONT;
117 m_selected_font = *wxNORMAL_FONT;
118 m_selected_font.SetWeight(wxBOLD);
119 m_measuring_font = m_selected_font;
4444d148 120
cd05bf23 121 wxColour base_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
4444d148 122
cd05bf23
BW
123 wxColour background_colour = StepColour(base_colour, 95);
124 wxColour normaltab_colour = base_colour;
125 wxColour selectedtab_colour = *wxWHITE;
4444d148 126
cd05bf23
BW
127 m_bkbrush = wxBrush(background_colour);
128 m_normal_bkbrush = wxBrush(normaltab_colour);
129 m_normal_bkpen = wxPen(normaltab_colour);
130 m_selected_bkbrush = wxBrush(selectedtab_colour);
131 m_selected_bkpen = wxPen(selectedtab_colour);
132}
133
fe498448
BW
134wxAuiTabContainer::~wxAuiTabContainer()
135{
136}
137
cd05bf23
BW
138void wxAuiTabContainer::SetNormalFont(const wxFont& font)
139{
140 m_normal_font = font;
141}
142
143void wxAuiTabContainer::SetSelectedFont(const wxFont& font)
144{
145 m_selected_font = font;
146}
147
148void wxAuiTabContainer::SetMeasuringFont(const wxFont& font)
149{
150 m_measuring_font = font;
151}
152
153void wxAuiTabContainer::SetRect(const wxRect& rect)
154{
155 m_rect = rect;
156}
157
158bool wxAuiTabContainer::AddPage(wxWindow* page,
159 const wxAuiNotebookPage& info)
160{
161 wxAuiNotebookPage page_info;
162 page_info = info;
163 page_info.window = page;
4444d148 164
cd05bf23
BW
165 m_pages.Add(page_info);
166
167 return true;
168}
169
170bool wxAuiTabContainer::InsertPage(wxWindow* page,
171 const wxAuiNotebookPage& info,
172 size_t idx)
173{
174 wxAuiNotebookPage page_info;
175 page_info = info;
176 page_info.window = page;
4444d148 177
cd05bf23
BW
178 if (idx >= m_pages.GetCount())
179 m_pages.Add(page_info);
180 else
181 m_pages.Insert(page_info, idx);
182
183 return true;
184}
185
186bool wxAuiTabContainer::RemovePage(wxWindow* wnd)
187{
188 size_t i, page_count = m_pages.GetCount();
189 for (i = 0; i < page_count; ++i)
190 {
191 wxAuiNotebookPage& page = m_pages.Item(i);
192 if (page.window == wnd)
193 {
194 m_pages.RemoveAt(i);
195 return true;
196 }
197 }
4444d148 198
cd05bf23
BW
199 return false;
200}
201
202bool wxAuiTabContainer::SetActivePage(wxWindow* wnd)
203{
204 bool found = false;
4444d148 205
cd05bf23
BW
206 size_t i, page_count = m_pages.GetCount();
207 for (i = 0; i < page_count; ++i)
208 {
209 wxAuiNotebookPage& page = m_pages.Item(i);
210 if (page.window == wnd)
211 {
212 page.active = true;
213 found = true;
214 }
215 else
216 {
217 page.active = false;
218 }
219 }
4444d148 220
cd05bf23
BW
221 return found;
222}
223
224void wxAuiTabContainer::SetNoneActive()
225{
226 size_t i, page_count = m_pages.GetCount();
227 for (i = 0; i < page_count; ++i)
228 {
229 wxAuiNotebookPage& page = m_pages.Item(i);
230 page.active = false;
231 }
232}
233
234bool wxAuiTabContainer::SetActivePage(size_t page)
235{
236 if (page >= m_pages.GetCount())
237 return false;
4444d148 238
cd05bf23
BW
239 return SetActivePage(m_pages.Item(page).window);
240}
4444d148 241
cd05bf23
BW
242int wxAuiTabContainer::GetActivePage() const
243{
244 size_t i, page_count = m_pages.GetCount();
245 for (i = 0; i < page_count; ++i)
246 {
247 wxAuiNotebookPage& page = m_pages.Item(i);
248 if (page.active)
249 return i;
250 }
4444d148 251
cd05bf23
BW
252 return -1;
253}
254
255wxWindow* wxAuiTabContainer::GetWindowFromIdx(size_t idx) const
256{
257 if (idx >= m_pages.GetCount())
258 return NULL;
4444d148 259
cd05bf23
BW
260 return m_pages[idx].window;
261}
262
263int wxAuiTabContainer::GetIdxFromWindow(wxWindow* wnd) const
264{
265 size_t i, page_count = m_pages.GetCount();
266 for (i = 0; i < page_count; ++i)
267 {
268 wxAuiNotebookPage& page = m_pages.Item(i);
269 if (page.window == wnd)
270 return i;
271 }
272 return -1;
273}
274
275wxAuiNotebookPage& wxAuiTabContainer::GetPage(size_t idx)
276{
277 wxASSERT_MSG(idx < m_pages.GetCount(), wxT("Invalid Page index"));
278
279 return m_pages[idx];
280}
281
282wxAuiNotebookPageArray& wxAuiTabContainer::GetPages()
283{
284 return m_pages;
285}
286
287size_t wxAuiTabContainer::GetPageCount() const
288{
289 return m_pages.GetCount();
290}
291
292void wxAuiTabContainer::AddButton(int id, const wxBitmap& bmp)
293{
294 wxAuiTabContainerButton button;
295 button.id = id;
296 button.bitmap = bmp;
297 button.cur_state = wxAUI_BUTTON_STATE_NORMAL;
4444d148 298
cd05bf23
BW
299 m_buttons.Add(button);
300}
301
302
303
304// DrawTab() draws an individual tab.
305// As it is virtual it may be overridden.
306//
307// dc - output dc
308// in_rect - rectangle the tab should be confined to
309// caption - tab's caption
310// active - whether or not the tab is active
311// out_rect - actual output rectangle
312// x_extent - the advance x; where the next tab should start
313
314void wxAuiTabContainer::DrawTab(wxDC* dc,
315 const wxRect& in_rect,
f169e95d 316 const wxString& caption_text,
cd05bf23
BW
317 bool active,
318 wxRect* out_rect,
319 int* x_extent)
320{
321 wxCoord normal_textx, normal_texty;
322 wxCoord selected_textx, selected_texty;
323 wxCoord measured_textx, measured_texty;
324 wxCoord textx, texty;
4444d148
WS
325
326
9d59bf68 327 // if the caption is empty, measure some temporary text
f169e95d 328 wxString caption = caption_text;
17da5410 329 if (caption_text.empty())
9d59bf68
BW
330 caption = wxT("Xj");
331
cd05bf23
BW
332 // measure text
333 dc->SetFont(m_measuring_font);
334 dc->GetTextExtent(caption, &measured_textx, &measured_texty);
4444d148 335
cd05bf23
BW
336 dc->SetFont(m_selected_font);
337 dc->GetTextExtent(caption, &selected_textx, &selected_texty);
4444d148 338
cd05bf23
BW
339 dc->SetFont(m_normal_font);
340 dc->GetTextExtent(caption, &normal_textx, &normal_texty);
341
f169e95d 342 caption = caption_text;
4444d148 343
cd05bf23
BW
344 wxCoord tab_height = measured_texty + 4;
345 wxCoord tab_width = measured_textx + tab_height + 5;
346 wxCoord tab_x = in_rect.x;
347 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
4444d148
WS
348
349
cd05bf23 350 // select pen, brush and font for the tab to be drawn
4444d148 351
cd05bf23
BW
352 if (active)
353 {
354 dc->SetPen(m_selected_bkpen);
355 dc->SetBrush(m_selected_bkbrush);
356 dc->SetFont(m_selected_font);
357 textx = selected_textx;
358 texty = selected_texty;
359 }
360 else
361 {
362 dc->SetPen(m_normal_bkpen);
363 dc->SetBrush(m_normal_bkbrush);
364 dc->SetFont(m_normal_font);
365 textx = normal_textx;
366 texty = normal_texty;
367 }
4444d148
WS
368
369
cd05bf23 370 // -- draw line --
4444d148 371
cd05bf23
BW
372 wxPoint points[7];
373 points[0].x = tab_x;
374 points[0].y = tab_y + tab_height - 1;
375 points[1].x = tab_x + tab_height - 3;
376 points[1].y = tab_y + 2;
377 points[2].x = tab_x + tab_height + 3;
378 points[2].y = tab_y;
379 points[3].x = tab_x + tab_width - 2;
380 points[3].y = tab_y;
381 points[4].x = tab_x + tab_width;
382 points[4].y = tab_y + 2;
383 points[5].x = tab_x + tab_width;
384 points[5].y = tab_y + tab_height - 1;
385 points[6] = points[0];
386
387
388 dc->DrawPolygon(6, points);
4444d148 389
cd05bf23 390 dc->SetPen(*wxGREY_PEN);
4444d148 391
cd05bf23
BW
392 //dc->DrawLines(active ? 6 : 7, points);
393 dc->DrawLines(7, points);
4444d148 394
cd05bf23 395 // -- draw text --
4444d148
WS
396
397 dc->DrawText(caption,
398 tab_x + (tab_height/3) + (tab_width/2) - (textx/2),
cd05bf23 399 tab_y + tab_height - texty - 2);
4444d148 400
cd05bf23
BW
401 *out_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
402 *x_extent = tab_width - (tab_height/2) - 1;
403}
404
405
406// Render() renders the tab catalog to the specified DC
407// It is a virtual function and can be overridden to
408// provide custom drawing capabilities
409void wxAuiTabContainer::Render(wxDC* raw_dc)
4444d148 410{
cd05bf23
BW
411 wxMemoryDC dc;
412 wxBitmap bmp;
413 bmp.Create(m_rect.GetWidth(), m_rect.GetHeight());
414 dc.SelectObject(bmp);
4444d148 415
cd05bf23
BW
416 // draw background
417 dc.SetBrush(m_bkbrush);
418 dc.SetPen(*wxTRANSPARENT_PEN);
419 dc.DrawRectangle(-1, -1, m_rect.GetWidth()+2, m_rect.GetHeight()+2);
4444d148 420
cd05bf23
BW
421 // draw base line
422 dc.SetPen(*wxGREY_PEN);
423 dc.DrawLine(0, m_rect.GetHeight()-1, m_rect.GetWidth(), m_rect.GetHeight()-1);
4444d148
WS
424
425
cd05bf23
BW
426 size_t i, page_count = m_pages.GetCount();
427 int offset = 0;
428
429 size_t active = 999;
430 int active_offset = 0;
4444d148 431
cd05bf23
BW
432 int x_extent = 0;
433 wxRect rect = m_rect;
434 rect.y = 0;
435 rect.width = 1000;
436 rect.height = m_rect.height;
4444d148 437
cd05bf23
BW
438 for (i = 0; i < page_count; ++i)
439 {
440 wxAuiNotebookPage& page = m_pages.Item(i);
4444d148 441
cd05bf23 442 rect.x = offset;
4444d148 443
cd05bf23
BW
444 DrawTab(&dc,
445 rect,
446 page.caption,
447 page.active,
448 &page.rect,
449 &x_extent);
4444d148 450
cd05bf23
BW
451 if (page.active)
452 {
453 active = i;
454 active_offset = offset;
455 }
4444d148 456
cd05bf23
BW
457 offset += x_extent;
458 }
4444d148 459
cd05bf23
BW
460 // draw the active tab again so it stands in the foreground
461 if (active < m_pages.GetCount())
462 {
463 wxAuiNotebookPage& page = m_pages.Item(active);
464
465 rect.x = active_offset;
466 DrawTab(&dc,
467 rect,
468 page.caption,
469 page.active,
470 &page.rect,
471 &x_extent);
472 }
4444d148 473
cd05bf23
BW
474 // draw the buttons
475 offset = m_rect.x + m_rect.width;
476 size_t button_count = m_buttons.GetCount();
477 for (i = 0; i < button_count; ++i)
478 {
479 wxAuiTabContainerButton& button = m_buttons.Item(button_count - i - 1);
4444d148 480
cd05bf23
BW
481 wxRect button_rect(offset - button.bitmap.GetWidth(), 1,
482 button.bitmap.GetWidth(), button.bitmap.GetHeight());
4444d148 483
cd05bf23 484 button.rect = button_rect;
4444d148 485
cd05bf23
BW
486 DrawButton(dc, button.rect, button.bitmap,
487 m_bkbrush.GetColour(),
488 button.cur_state);
4444d148 489
cd05bf23
BW
490 offset -= button.bitmap.GetWidth();
491 }
4444d148
WS
492
493
cd05bf23
BW
494 raw_dc->Blit(m_rect.x, m_rect.y, m_rect.GetWidth(), m_rect.GetHeight(), &dc, 0, 0);
495}
496
497
498// TabHitTest() tests if a tab was hit, passing the window pointer
499// back if that condition was fulfilled. The function returns
500// true if a tab was hit, otherwise false
501bool wxAuiTabContainer::TabHitTest(int x, int y, wxWindow** hit) const
502{
503 if (!m_rect.Inside(x,y))
504 return false;
4444d148 505
cd05bf23 506 size_t i, page_count = m_pages.GetCount();
4444d148 507
cd05bf23
BW
508 for (i = 0; i < page_count; ++i)
509 {
510 wxAuiNotebookPage& page = m_pages.Item(i);
511 if (page.rect.Inside(x,y))
512 {
513 *hit = page.window;
514 return true;
515 }
516 }
4444d148 517
cd05bf23
BW
518 return false;
519}
520
521// ButtonHitTest() tests if a button was hit. The function returns
522// true if a button was hit, otherwise false
523bool wxAuiTabContainer::ButtonHitTest(int x, int y,
524 wxAuiTabContainerButton** hit) const
525{
526 if (!m_rect.Inside(x,y))
527 return false;
4444d148 528
cd05bf23 529 size_t i, button_count = m_buttons.GetCount();
4444d148 530
cd05bf23
BW
531 for (i = 0; i < button_count; ++i)
532 {
533 wxAuiTabContainerButton& button = m_buttons.Item(i);
534 if (button.rect.Inside(x,y))
535 {
536 *hit = &button;
537 return true;
538 }
539 }
4444d148 540
cd05bf23
BW
541 return false;
542}
543
544
545
546// the utility function ShowWnd() is the same as show,
547// except it handles wxTabMDIChildFrame windows as well,
548// as the Show() method on this class is "unplugged"
549static void ShowWnd(wxWindow* wnd, bool show)
550{
551 if (wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
552 {
553 wxTabMDIChildFrame* cf = (wxTabMDIChildFrame*)wnd;
554 cf->DoShow(show);
555 }
556 else
557 {
558 wnd->Show(show);
559 }
560}
561
562
563// DoShowHide() this function shows the active window, then
564// hides all of the other windows (in that order)
565void wxAuiTabContainer::DoShowHide()
566{
567 wxAuiNotebookPageArray& pages = GetPages();
568 size_t i, page_count = pages.GetCount();
569
570 // show new active page first
571 for (i = 0; i < page_count; ++i)
572 {
573 wxAuiNotebookPage& page = pages.Item(i);
574 if (page.active)
575 {
576 ShowWnd(page.window, true);
577 break;
578 }
579 }
580
581 // hide all other pages
582 for (i = 0; i < page_count; ++i)
583 {
584 wxAuiNotebookPage& page = pages.Item(i);
585 ShowWnd(page.window, page.active);
586 }
587}
588
589
590
591
592
593
594// -- wxAuiTabCtrl class implementation --
595
596
597const int wxAuiButtonClose = 101;
598
599BEGIN_EVENT_TABLE(wxAuiTabCtrl, wxControl)
600 EVT_PAINT(wxAuiTabCtrl::OnPaint)
601 EVT_ERASE_BACKGROUND(wxAuiTabCtrl::OnEraseBackground)
602 EVT_SIZE(wxAuiTabCtrl::OnSize)
603 EVT_LEFT_DOWN(wxAuiTabCtrl::OnLeftDown)
604 EVT_LEFT_UP(wxAuiTabCtrl::OnLeftUp)
605 EVT_MOTION(wxAuiTabCtrl::OnMotion)
606 EVT_LEAVE_WINDOW(wxAuiTabCtrl::OnLeaveWindow)
607END_EVENT_TABLE()
608
609
610wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
611 wxWindowID id,
612 const wxPoint& pos,
613 const wxSize& size,
4444d148 614 long style) : wxControl(parent, id, pos, size, style)
cd05bf23
BW
615{
616 m_click_pt = wxDefaultPosition;
617 m_is_dragging = false;
618 m_hover_button = NULL;
4444d148
WS
619
620 // FIXME: copied from dockart-- needs to put in a common place
cd05bf23
BW
621 static unsigned char close_bits[]={
622 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
623 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
624 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
4444d148 625
cd05bf23
BW
626 AddButton(101, BitmapFromBits(close_bits, 16, 16, *wxBLACK));
627}
628
629
630void wxAuiTabCtrl::OnPaint(wxPaintEvent&)
631{
632 wxPaintDC dc(this);
4444d148 633
cd05bf23 634 dc.SetFont(GetFont());
4444d148 635
cd05bf23
BW
636 if (GetPageCount() > 0)
637 Render(&dc);
638}
639
640void wxAuiTabCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
641{
642}
643
644void wxAuiTabCtrl::OnSize(wxSizeEvent& evt)
645{
646 wxSize s = evt.GetSize();
647 wxRect r(0, 0, s.GetWidth(), s.GetHeight());
648 SetRect(r);
649}
650
651void wxAuiTabCtrl::OnLeftDown(wxMouseEvent& evt)
652{
653 CaptureMouse();
654 m_click_pt = wxDefaultPosition;
655 m_is_dragging = false;
656 m_click_tab = -1;
4444d148 657
cd05bf23
BW
658 wxWindow* wnd;
659 if (TabHitTest(evt.m_x, evt.m_y, &wnd))
660 {
661 wxAuiNotebookEvent e(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
662 e.SetSelection(GetIdxFromWindow(wnd));
663 e.SetOldSelection(GetActivePage());
664 e.SetEventObject(this);
665 GetEventHandler()->ProcessEvent(e);
4444d148 666
cd05bf23
BW
667 m_click_pt.x = evt.m_x;
668 m_click_pt.y = evt.m_y;
669 m_click_tab = e.GetSelection();
670 }
4444d148 671
cd05bf23
BW
672 if (m_hover_button)
673 {
674 m_hover_button->cur_state = wxAUI_BUTTON_STATE_PRESSED;
675 Refresh();
676 Update();
677 }
678}
679
680void wxAuiTabCtrl::OnLeftUp(wxMouseEvent&)
681{
682 if (GetCapture() == this)
683 ReleaseMouse();
4444d148 684
cd05bf23
BW
685 if (m_is_dragging)
686 {
687 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, m_windowId);
688 evt.SetSelection(m_click_tab);
689 evt.SetOldSelection(m_click_tab);
690 evt.SetEventObject(this);
691 GetEventHandler()->ProcessEvent(evt);
692 return;
693 }
4444d148 694
cd05bf23
BW
695 if (m_hover_button)
696 {
697 m_hover_button->cur_state = wxAUI_BUTTON_STATE_HOVER;
698 Refresh();
699 Update();
4444d148 700
cd05bf23
BW
701 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, m_windowId);
702 evt.SetInt(m_hover_button->id);
703 evt.SetEventObject(this);
704 GetEventHandler()->ProcessEvent(evt);
705 }
4444d148 706
cd05bf23
BW
707 m_click_pt = wxDefaultPosition;
708 m_is_dragging = false;
709 m_click_tab = -1;
710}
711
712void wxAuiTabCtrl::OnMotion(wxMouseEvent& evt)
713{
714 wxPoint pos = evt.GetPosition();
715
716 // check if the mouse is hovering above a button
717 wxAuiTabContainerButton* button;
718 if (ButtonHitTest(pos.x, pos.y, &button))
719 {
720 if (button->cur_state != wxAUI_BUTTON_STATE_HOVER)
721 {
722 button->cur_state = wxAUI_BUTTON_STATE_HOVER;
723 Refresh();
724 Update();
725 m_hover_button = button;
726 return;
727 }
728 }
729 else
730 {
731 if (m_hover_button)
732 {
733 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
734 m_hover_button = NULL;
735 Refresh();
736 Update();
737 }
738 }
4444d148
WS
739
740
cd05bf23
BW
741 if (!evt.LeftIsDown() || m_click_pt == wxDefaultPosition)
742 return;
4444d148 743
cd05bf23
BW
744 if (m_is_dragging)
745 {
746 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, m_windowId);
747 evt.SetSelection(m_click_tab);
748 evt.SetOldSelection(m_click_tab);
749 evt.SetEventObject(this);
750 GetEventHandler()->ProcessEvent(evt);
751 return;
4444d148
WS
752 }
753
754
cd05bf23
BW
755 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
756 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
757
758 if (abs(pos.x - m_click_pt.x) > drag_x_threshold ||
759 abs(pos.y - m_click_pt.y) > drag_y_threshold)
760 {
761 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, m_windowId);
762 evt.SetSelection(m_click_tab);
763 evt.SetOldSelection(m_click_tab);
764 evt.SetEventObject(this);
765 GetEventHandler()->ProcessEvent(evt);
4444d148 766
cd05bf23
BW
767 m_is_dragging = true;
768 }
769}
770
771void wxAuiTabCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
772{
773 if (m_hover_button)
774 {
775 m_hover_button->cur_state = wxAUI_BUTTON_STATE_NORMAL;
776 m_hover_button = NULL;
777 Refresh();
778 Update();
779 }
780}
781
782
783// wxTabFrame is an interesting case. It's important that all child pages
784// of the multi-notebook control are all actually children of that control
785// (and not grandchildren). wxTabFrame facilitates this. There is one
786// instance of wxTabFrame for each tab control inside the multi-notebook.
787// It's important to know that wxTabFrame is not a real window, but it merely
788// used to capture the dimensions/positioning of the internal tab control and
789// it's managed page windows
790
791class wxTabFrame : public wxWindow
792{
793public:
794
795 wxTabFrame()
796 {
797 m_tabs = NULL;
798 m_rect = wxRect(0,0,200,200);
da5e85d9
BW
799 m_tab_ctrl_height = 20;
800 }
4444d148 801
da5e85d9
BW
802 void SetTabCtrlHeight(int h)
803 {
804 m_tab_ctrl_height = h;
cd05bf23 805 }
4444d148 806
cd05bf23
BW
807 void DoSetSize(int x, int y,
808 int width, int height,
809 int WXUNUSED(sizeFlags = wxSIZE_AUTO))
810 {
811 m_rect = wxRect(x, y, width, height);
812 DoSizing();
813 }
4444d148 814
cd05bf23
BW
815 void DoGetClientSize(int* x, int* y) const
816 {
817 *x = m_rect.width;
818 *y = m_rect.height;
819 }
4f450f41
RD
820
821 bool Show( bool WXUNUSED(show = true) ) { return false; }
4444d148 822
cd05bf23
BW
823 void DoSizing()
824 {
825 if (!m_tabs)
826 return;
4444d148 827
da5e85d9 828 int tab_height = wxMin(m_rect.height, m_tab_ctrl_height);
cd05bf23
BW
829 m_tab_rect = wxRect(m_rect.x, m_rect.y, m_rect.width, tab_height);
830 m_tabs->SetSize(m_rect.x, m_rect.y, m_rect.width, tab_height);
831 m_tabs->SetRect(wxRect(0, 0, m_rect.width, tab_height));
832 m_tabs->Refresh();
9d59bf68 833 m_tabs->Update();
4444d148 834
cd05bf23
BW
835 wxAuiNotebookPageArray& pages = m_tabs->GetPages();
836 size_t i, page_count = pages.GetCount();
4444d148 837
cd05bf23
BW
838 for (i = 0; i < page_count; ++i)
839 {
840 wxAuiNotebookPage& page = pages.Item(i);
841 page.window->SetSize(m_rect.x, m_rect.y+tab_height, m_rect.width, m_rect.height-tab_height);
4444d148 842
cd05bf23
BW
843 if (page.window->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
844 {
845 wxTabMDIChildFrame* wnd = (wxTabMDIChildFrame*)page.window;
846 wnd->ApplyMDIChildFrameRect();
847 }
848 }
849 }
850
134e83cb
BW
851 void DoGetSize(int* x, int* y) const
852 {
853 if (x)
854 *x = m_rect.GetWidth();
855 if (y)
856 *y = m_rect.GetHeight();
857 }
4444d148 858
134e83cb
BW
859 void Update()
860 {
861 // does nothing
862 }
4444d148 863
cd05bf23
BW
864public:
865
866 wxRect m_rect;
867 wxRect m_tab_rect;
868 wxAuiTabCtrl* m_tabs;
da5e85d9 869 int m_tab_ctrl_height;
cd05bf23
BW
870};
871
872
873
874
875
876// -- wxAuiMultiNotebook class implementation --
877
878BEGIN_EVENT_TABLE(wxAuiMultiNotebook, wxControl)
879 //EVT_ERASE_BACKGROUND(wxAuiMultiNotebook::OnEraseBackground)
880 //EVT_SIZE(wxAuiMultiNotebook::OnSize)
881 //EVT_LEFT_DOWN(wxAuiMultiNotebook::OnLeftDown)
882 EVT_CHILD_FOCUS(wxAuiMultiNotebook::OnChildFocus)
883 EVT_COMMAND_RANGE(10000, 10100,
884 wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING,
885 wxAuiMultiNotebook::OnTabClicked)
886 EVT_COMMAND_RANGE(10000, 10100,
887 wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG,
4444d148 888 wxAuiMultiNotebook::OnTabBeginDrag)
cd05bf23
BW
889 EVT_COMMAND_RANGE(10000, 10100,
890 wxEVT_COMMAND_AUINOTEBOOK_END_DRAG,
4444d148 891 wxAuiMultiNotebook::OnTabEndDrag)
cd05bf23
BW
892 EVT_COMMAND_RANGE(10000, 10100,
893 wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION,
894 wxAuiMultiNotebook::OnTabDragMotion)
895 EVT_COMMAND_RANGE(10000, 10100,
896 wxEVT_COMMAND_AUINOTEBOOK_BUTTON,
897 wxAuiMultiNotebook::OnTabButton)
898END_EVENT_TABLE()
899
900wxAuiMultiNotebook::wxAuiMultiNotebook()
901{
902 m_curpage = -1;
903 m_tab_id_counter = 10000;
904 m_dummy_wnd = NULL;
da5e85d9 905 m_tab_ctrl_height = 20;
cd05bf23
BW
906}
907
908wxAuiMultiNotebook::wxAuiMultiNotebook(wxWindow *parent,
909 wxWindowID id,
910 const wxPoint& pos,
911 const wxSize& size,
912 long style) : wxControl(parent, id, pos, size, style)
913{
914 InitNotebook();
915}
916
917bool wxAuiMultiNotebook::Create(wxWindow* parent,
918 wxWindowID id,
919 const wxPoint& pos,
920 const wxSize& size,
921 long style)
922{
923 if (!wxControl::Create(parent, id, pos, size, style))
924 return false;
4444d148 925
cd05bf23 926 InitNotebook();
4444d148 927
cd05bf23
BW
928 return true;
929}
930
931// InitNotebook() contains common initialization
932// code called by all constructors
933void wxAuiMultiNotebook::InitNotebook()
934{
da5e85d9
BW
935 m_curpage = -1;
936 m_tab_id_counter = 10000;
937 m_dummy_wnd = NULL;
938 m_tab_ctrl_height = 20;
4444d148 939
cd05bf23
BW
940 m_normal_font = *wxNORMAL_FONT;
941 m_selected_font = *wxNORMAL_FONT;
942 m_selected_font.SetWeight(wxBOLD);
4444d148 943
da5e85d9
BW
944 // choose a default for the tab height
945 wxClientDC dc(this);
946 int tx, ty;
947 dc.SetFont(m_selected_font);
948 dc.GetTextExtent(wxT("ABCDEFGHhijklm"), &tx, &ty);
949 m_tab_ctrl_height = (ty*150)/100;
4444d148
WS
950
951 m_dummy_wnd = new wxWindow(this, wxID_ANY, wxPoint(0,0), wxSize(0,0));
cd05bf23
BW
952 m_dummy_wnd->SetSize(200, 200);
953 m_dummy_wnd->Show(false);
4444d148 954
cd05bf23 955 m_mgr.SetManagedWindow(this);
4444d148 956
cd05bf23
BW
957 m_mgr.AddPane(m_dummy_wnd,
958 wxPaneInfo().Name(wxT("dummy")).Bottom().Show(false));
4444d148 959
cd05bf23
BW
960 m_mgr.Update();
961}
962
963wxAuiMultiNotebook::~wxAuiMultiNotebook()
964{
965 m_mgr.UnInit();
966}
967
968bool wxAuiMultiNotebook::AddPage(wxWindow* page,
969 const wxString& caption,
970 bool select,
971 const wxBitmap& bitmap)
972{
973 return InsertPage(GetPageCount(), page, caption, select, bitmap);
974}
4444d148 975
cd05bf23
BW
976bool wxAuiMultiNotebook::InsertPage(size_t page_idx,
977 wxWindow* page,
978 const wxString& caption,
979 bool select,
980 const wxBitmap& bitmap)
981{
982 wxAuiNotebookPage info;
983 info.window = page;
984 info.caption = caption;
985 info.bitmap = bitmap;
986 info.active = false;
987
988 // if there are currently no tabs, the first added
989 // tab must be active
990 if (m_tabs.GetPageCount() == 0)
991 info.active = true;
992
993 m_tabs.InsertPage(page, info, page_idx);
994
995 wxAuiTabCtrl* active_tabctrl = GetActiveTabCtrl();
996 if (page_idx >= active_tabctrl->GetPageCount())
997 active_tabctrl->AddPage(page, info);
998 else
999 active_tabctrl->InsertPage(page, info, page_idx);
4444d148 1000
cd05bf23
BW
1001 DoSizing();
1002 active_tabctrl->DoShowHide();
4444d148 1003
cd05bf23
BW
1004 if (select)
1005 {
1006 int idx = m_tabs.GetIdxFromWindow(page);
1007 wxASSERT_MSG(idx != -1, wxT("Invalid Page index returned on wxAuiMultiNotebook::InsertPage()"));
4444d148 1008
cd05bf23
BW
1009 SetSelection(idx);
1010 }
4444d148 1011
cd05bf23
BW
1012 return true;
1013}
1014
1015
1016// DeletePage() removes a tab from the multi-notebook,
1017// and destroys the window as well
1018bool wxAuiMultiNotebook::DeletePage(size_t page_idx)
1019{
4444d148
WS
1020 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1021
1022
cd05bf23
BW
1023 // find out which onscreen tab ctrl owns this tab
1024 wxAuiTabCtrl* ctrl;
1025 int ctrl_idx;
1026 if (!FindTab(wnd, &ctrl, &ctrl_idx))
1027 return false;
4444d148 1028
cd05bf23
BW
1029 // find a new page and set it as active
1030 int new_idx = ctrl_idx+1;
1031 if (new_idx >= (int)ctrl->GetPageCount())
1032 new_idx = ctrl_idx-1;
4444d148 1033
cd05bf23
BW
1034 if (new_idx >= 0 && new_idx < (int)ctrl->GetPageCount())
1035 {
1036 wxWindow* new_wnd = ctrl->GetWindowFromIdx(new_idx);
1037 int main_idx = m_tabs.GetIdxFromWindow(new_wnd);
1038 wxASSERT(main_idx != -1);
1039 SetSelection(main_idx);
1040 }
1041 else
1042 {
1043 // set the active page to the first page that
1044 // isn't the one being deleted
1045 bool found = false;
1046 size_t i, page_count = m_tabs.GetPageCount();
1047 for (i = 0; i < page_count; ++i)
1048 {
1049 wxWindow* w = m_tabs.GetWindowFromIdx(i);
1050 if (wnd != w)
1051 {
1052 found = true;
1053 SetSelection(i);
1054 break;
1055 }
1056 }
4444d148 1057
cd05bf23
BW
1058 if (!found)
1059 m_curpage = -1;
1060 }
4444d148
WS
1061
1062
cd05bf23
BW
1063 // remove the tab from main catalog
1064 if (!m_tabs.RemovePage(wnd))
1065 return false;
4444d148 1066
cd05bf23
BW
1067 // remove the tab from the onscreen tab ctrl
1068 ctrl->RemovePage(wnd);
4444d148 1069
cd05bf23
BW
1070 // actually destroy the window now
1071 if (wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1072 {
1073 // delete the child frame with pending delete, as is
1074 // customary with frame windows
1075 if (!wxPendingDelete.Member(wnd))
1076 wxPendingDelete.Append(wnd);
1077 }
1078 else
1079 {
1080 wnd->Destroy();
1081 }
4444d148 1082
cd05bf23 1083 RemoveEmptyTabFrames();
4444d148 1084
cd05bf23
BW
1085 return true;
1086}
1087
1088
1089
1090// RemovePage() removes a tab from the multi-notebook,
1091// but does not destroy the window
1092bool wxAuiMultiNotebook::RemovePage(size_t page_idx)
1093{
1094 // remove the tab from our own catalog
1095 wxWindow* wnd = m_tabs.GetWindowFromIdx(page_idx);
1096 if (!m_tabs.RemovePage(wnd))
1097 return false;
4444d148 1098
cd05bf23
BW
1099 // remove the tab from the onscreen tab ctrl
1100 wxAuiTabCtrl* ctrl;
1101 int ctrl_idx;
1102 if (FindTab(wnd, &ctrl, &ctrl_idx))
1103 {
1104 ctrl->RemovePage(wnd);
1105 return true;
1106 }
4444d148 1107
cd05bf23
BW
1108 return false;
1109}
1110
1111// SetPageText() changes the tab caption of the specified page
1112bool wxAuiMultiNotebook::SetPageText(size_t page_idx, const wxString& text)
4444d148 1113{
cd05bf23
BW
1114 if (page_idx >= m_tabs.GetPageCount())
1115 return false;
4444d148 1116
cd05bf23
BW
1117 // update our own tab catalog
1118 wxAuiNotebookPage& page_info = m_tabs.GetPage(page_idx);
1119 page_info.caption = text;
4444d148 1120
cd05bf23
BW
1121 // update what's on screen
1122 wxAuiTabCtrl* ctrl;
1123 int ctrl_idx;
1124 if (FindTab(page_info.window, &ctrl, &ctrl_idx))
1125 {
1126 wxAuiNotebookPage& info = ctrl->GetPage(ctrl_idx);
1127 info.caption = text;
1128 ctrl->Refresh();
639a4f7b 1129 ctrl->Update();
cd05bf23 1130 }
4444d148 1131
cd05bf23
BW
1132 return true;
1133}
1134
1135// GetSelection() returns the index of the currently active page
1136int wxAuiMultiNotebook::GetSelection() const
1137{
1138 return m_curpage;
1139}
1140
1141// SetSelection() sets the currently active page
1142size_t wxAuiMultiNotebook::SetSelection(size_t new_page)
1143{
1144 wxWindow* wnd = m_tabs.GetWindowFromIdx(new_page);
1145 if (!wnd)
1146 return m_curpage;
4444d148 1147
cd05bf23
BW
1148 wxAuiNotebookEvent evt(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, m_windowId);
1149 evt.SetSelection(new_page);
1150 evt.SetOldSelection(m_curpage);
1151 evt.SetEventObject(this);
1152 if (!GetEventHandler()->ProcessEvent(evt) || evt.IsAllowed())
1153 {
1154 // program allows the page change
1155 evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED);
1156 (void)GetEventHandler()->ProcessEvent(evt);
1157
1158
1159
1160 wxAuiTabCtrl* ctrl;
1161 int ctrl_idx;
1162 if (FindTab(wnd, &ctrl, &ctrl_idx))
4444d148 1163 {
cd05bf23 1164 m_tabs.SetActivePage(wnd);
4444d148 1165
cd05bf23
BW
1166 ctrl->SetActivePage(ctrl_idx);
1167 DoSizing();
1168 ctrl->DoShowHide();
4444d148 1169
cd05bf23
BW
1170 int old_curpage = m_curpage;
1171 m_curpage = new_page;
1172
1173
1174 // set fonts
1175 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1176 size_t i, pane_count = all_panes.GetCount();
1177 for (i = 0; i < pane_count; ++i)
1178 {
1179 wxPaneInfo& pane = all_panes.Item(i);
1180 if (pane.name == wxT("dummy"))
1181 continue;
1182 wxAuiTabCtrl* tabctrl = ((wxTabFrame*)pane.window)->m_tabs;
1183 if (tabctrl != ctrl)
1184 tabctrl->SetSelectedFont(m_normal_font);
1185 else
1186 tabctrl->SetSelectedFont(m_selected_font);
1187 tabctrl->Refresh();
1188 }
1189
1190 wnd->SetFocus();
4444d148 1191
cd05bf23
BW
1192 return old_curpage;
1193 }
1194 }
1195
1196 return m_curpage;
1197}
1198
1199// GetPageCount() returns the total number of
1200// pages managed by the multi-notebook
1201size_t wxAuiMultiNotebook::GetPageCount() const
1202{
1203 return m_tabs.GetPageCount();
1204}
1205
1206// GetPage() returns the wxWindow pointer of the
1207// specified page
1208wxWindow* wxAuiMultiNotebook::GetPage(size_t page_idx) const
1209{
1210 wxASSERT(page_idx < m_tabs.GetPageCount());
4444d148 1211
cd05bf23
BW
1212 return m_tabs.GetWindowFromIdx(page_idx);
1213}
1214
1215// DoSizing() performs all sizing operations in each tab control
1216void wxAuiMultiNotebook::DoSizing()
1217{
1218 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1219 size_t i, pane_count = all_panes.GetCount();
1220 for (i = 0; i < pane_count; ++i)
1221 {
1222 if (all_panes.Item(i).name == wxT("dummy"))
1223 continue;
1224
1225 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1226 tabframe->DoSizing();
1227 }
1228}
1229
1230// GetActiveTabCtrl() returns the active tab control. It is
1231// called to determine which control gets new windows being added
1232wxAuiTabCtrl* wxAuiMultiNotebook::GetActiveTabCtrl()
1233{
1234 if (m_curpage >= 0 && m_curpage < (int)m_tabs.GetPageCount())
1235 {
1236 wxAuiTabCtrl* ctrl;
1237 int idx;
4444d148 1238
cd05bf23
BW
1239 // find the tab ctrl with the current page
1240 if (FindTab(m_tabs.GetPage(m_curpage).window,
1241 &ctrl, &idx))
4444d148 1242 {
cd05bf23
BW
1243 return ctrl;
1244 }
1245 }
4444d148 1246
cd05bf23
BW
1247 // no current page, just find the first tab ctrl
1248 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1249 size_t i, pane_count = all_panes.GetCount();
1250 for (i = 0; i < pane_count; ++i)
1251 {
1252 if (all_panes.Item(i).name == wxT("dummy"))
1253 continue;
4444d148 1254
cd05bf23
BW
1255 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1256 return tabframe->m_tabs;
1257 }
4444d148 1258
cd05bf23
BW
1259 // If there is no tabframe at all, create one
1260 wxTabFrame* tabframe = new wxTabFrame;
da5e85d9 1261 tabframe->SetTabCtrlHeight(m_tab_ctrl_height);
cd05bf23
BW
1262 tabframe->m_tabs = new wxAuiTabCtrl(this,
1263 m_tab_id_counter++,
1264 wxDefaultPosition,
1265 wxDefaultSize,
1266 wxNO_BORDER);
1267 m_mgr.AddPane(tabframe,
4444d148
WS
1268 wxPaneInfo().Center().CaptionVisible(false));
1269
cd05bf23 1270 m_mgr.Update();
4444d148 1271
cd05bf23
BW
1272 return tabframe->m_tabs;
1273}
1274
1275// FindTab() finds the tab control that currently contains the window as well
1276// as the index of the window in the tab control. It returns true if the
1277// window was found, otherwise false.
1278bool wxAuiMultiNotebook::FindTab(wxWindow* page, wxAuiTabCtrl** ctrl, int* idx)
1279{
1280 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1281 size_t i, pane_count = all_panes.GetCount();
1282 for (i = 0; i < pane_count; ++i)
1283 {
1284 if (all_panes.Item(i).name == wxT("dummy"))
1285 continue;
4444d148 1286
cd05bf23 1287 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
4444d148 1288
cd05bf23
BW
1289 int page_idx = tabframe->m_tabs->GetIdxFromWindow(page);
1290 if (page_idx != -1)
1291 {
1292 *ctrl = tabframe->m_tabs;
1293 *idx = page_idx;
1294 return true;
1295 }
1296 }
4444d148 1297
cd05bf23
BW
1298 return false;
1299}
1300
1301
1302void wxAuiMultiNotebook::OnEraseBackground(wxEraseEvent&)
1303{
1304}
1305
1306void wxAuiMultiNotebook::OnSize(wxSizeEvent&)
1307{
1308}
1309
1310void wxAuiMultiNotebook::OnTabClicked(wxCommandEvent& command_evt)
1311{
1312 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
4444d148 1313
cd05bf23
BW
1314 wxAuiTabCtrl* ctrl = (wxAuiTabCtrl*)evt.GetEventObject();
1315 wxASSERT(ctrl != NULL);
4444d148 1316
cd05bf23
BW
1317 wxWindow* wnd = ctrl->GetWindowFromIdx(evt.GetSelection());
1318 wxASSERT(wnd != NULL);
4444d148 1319
cd05bf23
BW
1320 int idx = m_tabs.GetIdxFromWindow(wnd);
1321 wxASSERT(idx != -1);
4444d148 1322
cd05bf23
BW
1323 SetSelection(idx);
1324}
1325
1326void wxAuiMultiNotebook::OnTabBeginDrag(wxCommandEvent&)
1327{
1328}
1329
1330void wxAuiMultiNotebook::OnTabDragMotion(wxCommandEvent& evt)
1331{
1332 wxPoint screen_pt = ::wxGetMousePosition();
1333 wxPoint client_pt = ScreenToClient(screen_pt);
1334 wxPoint zero(0,0);
4444d148 1335
cd05bf23 1336 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4444d148 1337
cd05bf23
BW
1338 wxAuiTabCtrl* tab_ctrl = GetTabCtrlFromPoint(client_pt);
1339 if (tab_ctrl == src_tabs)
1340 {
1341 // inner-tabctrl dragging is not yet implemented
1342 m_mgr.HideHint();
1343 return;
1344 }
4444d148 1345
cd05bf23
BW
1346 if (tab_ctrl)
1347 {
1348 wxRect hint_rect = tab_ctrl->GetRect();
1349 ClientToScreen(&hint_rect.x, &hint_rect.y);
1350 m_mgr.ShowHint(hint_rect);
1351 }
1352 else
1353 {
1354 m_mgr.DrawHintRect(m_dummy_wnd, client_pt, zero);
1355 }
1356}
1357
1358
1359
1360void wxAuiMultiNotebook::OnTabEndDrag(wxCommandEvent& command_evt)
1361{
1362 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1363
1364 m_mgr.HideHint();
4444d148 1365
cd05bf23
BW
1366
1367 // get the mouse position, which will be used to determine the drop point
1368 wxPoint mouse_screen_pt = ::wxGetMousePosition();
1369 wxPoint mouse_client_pt = ScreenToClient(mouse_screen_pt);
1370
1371
1372 // the src tab control is the control that fired this event
1373 wxAuiTabCtrl* src_tabs = (wxAuiTabCtrl*)evt.GetEventObject();
1374 wxAuiTabCtrl* dest_tabs = NULL;
4444d148 1375
cd05bf23
BW
1376
1377 // If the pointer is in an existing tab frame, do a tab insert
1378 wxWindow* hit_wnd = ::wxFindWindowAtPoint(mouse_screen_pt);
1379 wxTabFrame* tab_frame = (wxTabFrame*)GetTabFrameFromTabCtrl(hit_wnd);
1380 if (tab_frame)
1381 {
1382 dest_tabs = tab_frame->m_tabs;
4444d148 1383
cd05bf23
BW
1384 if (dest_tabs == src_tabs)
1385 return;
1386 }
1387 else
1388 {
1389 // If there is no tabframe at all, create one
1390 wxTabFrame* new_tabs = new wxTabFrame;
da5e85d9 1391 new_tabs->SetTabCtrlHeight(m_tab_ctrl_height);
cd05bf23
BW
1392 new_tabs->m_tabs = new wxAuiTabCtrl(this,
1393 m_tab_id_counter++,
1394 wxDefaultPosition,
1395 wxDefaultSize,
1396 wxNO_BORDER);
1397 m_mgr.AddPane(new_tabs,
1398 wxPaneInfo().Bottom().CaptionVisible(false),
1399 mouse_client_pt);
1400 m_mgr.Update();
1401 dest_tabs = new_tabs->m_tabs;
1402 }
4444d148
WS
1403
1404
1405
cd05bf23
BW
1406 // remove the page from the source tabs
1407 wxAuiNotebookPage page_info = src_tabs->GetPage(evt.GetSelection());
1408 page_info.active = false;
1409 src_tabs->RemovePage(page_info.window);
1410 if (src_tabs->GetPageCount() > 0)
1411 {
1412 src_tabs->SetActivePage((size_t)0);
1413 src_tabs->DoShowHide();
1414 src_tabs->Refresh();
1415 }
1416
4444d148
WS
1417
1418
cd05bf23
BW
1419 // add the page to the destination tabs
1420 dest_tabs->AddPage(page_info.window, page_info);
4444d148 1421
cd05bf23 1422 if (src_tabs->GetPageCount() == 0)
4444d148 1423 {
cd05bf23
BW
1424 RemoveEmptyTabFrames();
1425 }
4444d148 1426
cd05bf23
BW
1427 DoSizing();
1428 dest_tabs->DoShowHide();
1429 dest_tabs->Refresh();
1430
1431 SetSelection(m_tabs.GetIdxFromWindow(page_info.window));
1432}
1433
1434wxAuiTabCtrl* wxAuiMultiNotebook::GetTabCtrlFromPoint(const wxPoint& pt)
1435{
1436 // if we've just removed the last tab from the source
1437 // tab set, the remove the tab control completely
1438 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1439 size_t i, pane_count = all_panes.GetCount();
1440 for (i = 0; i < pane_count; ++i)
1441 {
1442 if (all_panes.Item(i).name == wxT("dummy"))
1443 continue;
4444d148 1444
cd05bf23
BW
1445 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1446 if (tabframe->m_tab_rect.Inside(pt))
1447 return tabframe->m_tabs;
1448 }
4444d148 1449
cd05bf23
BW
1450 return NULL;
1451}
1452
1453wxWindow* wxAuiMultiNotebook::GetTabFrameFromTabCtrl(wxWindow* tab_ctrl)
1454{
1455 // if we've just removed the last tab from the source
1456 // tab set, the remove the tab control completely
1457 wxPaneInfoArray& all_panes = m_mgr.GetAllPanes();
1458 size_t i, pane_count = all_panes.GetCount();
1459 for (i = 0; i < pane_count; ++i)
1460 {
1461 if (all_panes.Item(i).name == wxT("dummy"))
1462 continue;
4444d148 1463
cd05bf23
BW
1464 wxTabFrame* tabframe = (wxTabFrame*)all_panes.Item(i).window;
1465 if (tabframe->m_tabs == tab_ctrl)
1466 {
1467 return tabframe;
1468 }
1469 }
4444d148 1470
cd05bf23
BW
1471 return NULL;
1472}
1473
1474void wxAuiMultiNotebook::RemoveEmptyTabFrames()
1475{
1476 bool must_update = false;
4444d148 1477
cd05bf23
BW
1478 // if we've just removed the last tab from the source
1479 // tab set, the remove the tab control completely
1480 wxPaneInfoArray all_panes = m_mgr.GetAllPanes();
1481 size_t i, pane_count = all_panes.GetCount();
1482 for (i = 0; i < pane_count; ++i)
1483 {
1484 if (all_panes.Item(i).name == wxT("dummy"))
1485 continue;
1486
1487 wxTabFrame* tab_frame = (wxTabFrame*)all_panes.Item(i).window;
1488 if (tab_frame->m_tabs->GetPageCount() == 0)
1489 {
1490 m_mgr.DetachPane(tab_frame);
4444d148 1491
cd05bf23
BW
1492 // use pending delete because sometimes during
1493 // window closing, refreshs are pending
1494 if (!wxPendingDelete.Member(tab_frame->m_tabs))
4444d148 1495 wxPendingDelete.Append(tab_frame->m_tabs);
cd05bf23 1496 //tab_frame->m_tabs->Destroy();
4444d148 1497
cd05bf23
BW
1498 delete tab_frame;
1499 must_update = true;
1500 }
1501 }
4444d148
WS
1502
1503
cd05bf23
BW
1504 // check to see if there is still a center pane;
1505 // if there isn't, make a frame the center pane
1506 wxPaneInfoArray panes = m_mgr.GetAllPanes();
1507 pane_count = panes.GetCount();
1508 wxWindow* first_good = NULL;
1509 bool center_found = false;
1510 for (i = 0; i < pane_count; ++i)
1511 {
1512 if (panes.Item(i).name == wxT("dummy"))
1513 continue;
1514 if (panes.Item(i).dock_direction == wxAUI_DOCK_CENTRE)
1515 center_found = true;
1516 if (!first_good)
1517 first_good = panes.Item(i).window;
1518 }
1519
1520 if (!center_found && first_good)
1521 {
1522 m_mgr.GetPane(first_good).Centre();
1523 must_update = true;
1524 }
1525
4444d148 1526 m_mgr.Update();
cd05bf23
BW
1527}
1528
1529void wxAuiMultiNotebook::OnChildFocus(wxChildFocusEvent& evt)
1530{
1531 int idx = m_tabs.GetIdxFromWindow(evt.GetWindow());
1532 if (idx != -1 && idx != m_curpage)
1533 {
4444d148 1534 SetSelection(idx);
cd05bf23
BW
1535 }
1536}
1537
1538
1539void wxAuiMultiNotebook::OnTabButton(wxCommandEvent& command_evt)
1540{
1541 wxAuiNotebookEvent& evt = (wxAuiNotebookEvent&)command_evt;
1542 wxAuiTabCtrl* tabs = (wxAuiTabCtrl*)evt.GetEventObject();
4444d148 1543
cd05bf23 1544 int button_id = evt.GetInt();
4444d148 1545
cd05bf23
BW
1546 if (button_id == wxAuiButtonClose)
1547 {
1548 int selection = tabs->GetActivePage();
4444d148 1549
cd05bf23
BW
1550 if (selection != -1)
1551 {
1552 wxWindow* close_wnd = tabs->GetWindowFromIdx(selection);
4444d148 1553
cd05bf23
BW
1554 if (close_wnd->IsKindOf(CLASSINFO(wxTabMDIChildFrame)))
1555 {
1556 close_wnd->Close();
1557 }
1558 else
1559 {
1560 int main_idx = m_tabs.GetIdxFromWindow(close_wnd);
1561 DeletePage(main_idx);
1562 }
1563 }
1564 }
1565}
1566
1567
1568
1569
1570#endif // wxUSE_AUI