1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: implementation of wxNotebook
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #pragma implementation "notebook.h"
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
30 #include <wx/string.h>
32 #include <wx/imaglist.h>
33 #include <wx/generic/notebook.h>
34 #include <wx/dcclient.h>
36 // ----------------------------------------------------------------------------
38 // ----------------------------------------------------------------------------
40 // check that the page index is valid
41 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 #if !USE_SHARED_LIBRARIES
48 BEGIN_EVENT_TABLE(wxNotebook
, wxControl
)
49 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange
)
50 EVT_SIZE(wxNotebook::OnSize
)
51 EVT_PAINT(wxNotebook::OnPaint
)
52 EVT_MOUSE_EVENTS(wxNotebook::OnMouseEvent
)
53 EVT_SET_FOCUS(wxNotebook::OnSetFocus
)
54 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey
)
55 // EVT_IDLE(wxNotebook::OnIdle)
58 IMPLEMENT_DYNAMIC_CLASS(wxNotebook
, wxControl
)
59 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent
, wxCommandEvent
)
62 // ============================================================================
64 // ============================================================================
66 // ----------------------------------------------------------------------------
67 // wxNotebook construction
68 // ----------------------------------------------------------------------------
70 // common part of all ctors
71 void wxNotebook::Init()
73 m_tabView
= (wxNotebookTabView
*) NULL
;
78 // default for dynamic class
79 wxNotebook::wxNotebook()
84 // the same arguments as for wxControl
85 wxNotebook::wxNotebook(wxWindow
*parent
,
94 Create(parent
, id
, pos
, size
, style
, name
);
98 bool wxNotebook::Create(wxWindow
*parent
,
103 const wxString
& name
)
108 m_windowId
= id
== -1 ? NewControlId() : id
;
110 // It's like a normal window...
111 if (!wxWindow::Create(parent
, id
, pos
, size
, style
|wxNO_BORDER
, name
))
114 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
116 SetTabView(new wxNotebookTabView(this));
122 wxNotebook::~wxNotebook()
127 // ----------------------------------------------------------------------------
128 // wxNotebook accessors
129 // ----------------------------------------------------------------------------
130 int wxNotebook::GetPageCount() const
132 return m_aPages
.Count();
135 int wxNotebook::GetRowCount() const
141 int wxNotebook::SetSelection(int nPage
)
146 wxASSERT( IS_VALID_PAGE(nPage
) );
148 wxNotebookPage
* pPage
= GetPage(nPage
);
150 m_tabView
->SetTabSelection((int) (long) pPage
);
156 void wxNotebook::AdvanceSelection(bool bForward
)
158 int nSel
= GetSelection();
159 int nMax
= GetPageCount() - 1;
161 SetSelection(nSel
== nMax
? 0 : nSel
+ 1);
163 SetSelection(nSel
== 0 ? nMax
: nSel
- 1);
166 bool wxNotebook::SetPageText(int nPage
, const wxString
& strText
)
168 wxASSERT( IS_VALID_PAGE(nPage
) );
170 wxNotebookPage
* page
= GetPage(nPage
);
173 m_tabView
->SetTabText((int) (long) page
, strText
);
181 wxString
wxNotebook::GetPageText(int nPage
) const
183 wxASSERT( IS_VALID_PAGE(nPage
) );
185 wxNotebookPage
* page
= ((wxNotebook
*)this)->GetPage(nPage
);
187 return m_tabView
->GetTabText((int) (long) page
);
189 return wxEmptyString
;
192 int wxNotebook::GetPageImage(int nPage
) const
194 wxASSERT( IS_VALID_PAGE(nPage
) );
200 bool wxNotebook::SetPageImage(int nPage
, int nImage
)
202 wxASSERT( IS_VALID_PAGE(nPage
) );
208 void wxNotebook::SetImageList(wxImageList
* imageList
)
210 m_pImageList
= imageList
;
214 // ----------------------------------------------------------------------------
215 // wxNotebook operations
216 // ----------------------------------------------------------------------------
218 // remove one page from the notebook and delete it
219 bool wxNotebook::DeletePage(int nPage
)
221 wxCHECK( IS_VALID_PAGE(nPage
), FALSE
);
223 if (m_nSelection
!= -1)
225 m_aPages
[m_nSelection
]->Show(FALSE
);
226 m_aPages
[m_nSelection
]->Lower();
229 wxNotebookPage
* pPage
= GetPage(nPage
);
230 m_tabView
->RemoveTab((int) (long) pPage
);
232 delete m_aPages
[nPage
];
233 m_aPages
.Remove(nPage
);
235 if (m_aPages
.GetCount() == 0)
238 m_tabView
->SetTabSelection(-1, FALSE
);
240 else if (m_nSelection
> -1)
243 m_tabView
->SetTabSelection((int) (long) GetPage(0), FALSE
);
244 if (m_nSelection
!= 0)
248 RefreshLayout(FALSE
);
253 bool wxNotebook::DeletePage(wxNotebookPage
* page
)
255 int pagePos
= FindPagePosition(page
);
257 return DeletePage(pagePos
);
262 // remove one page from the notebook
263 bool wxNotebook::RemovePage(int nPage
)
265 wxCHECK( IS_VALID_PAGE(nPage
), FALSE
);
267 m_aPages
[nPage
]->Show(FALSE
);
268 // m_aPages[nPage]->Lower();
270 wxNotebookPage
* pPage
= GetPage(nPage
);
271 m_tabView
->RemoveTab((int) (long) pPage
);
273 m_aPages
.Remove(nPage
);
275 if (m_aPages
.GetCount() == 0)
278 m_tabView
->SetTabSelection(-1, TRUE
);
280 else if (m_nSelection
> -1)
282 // Only change the selection if the page we
283 // deleted was the selection.
284 if (nPage
== m_nSelection
)
287 // Select the first tab. Generates a ChangePage.
288 m_tabView
->SetTabSelection((int) (long) GetPage(0), TRUE
);
292 // We must adjust which tab we think is selected.
293 // If greater than the page we deleted, it must be moved down
295 if (m_nSelection
> nPage
)
300 RefreshLayout(FALSE
);
305 bool wxNotebook::RemovePage(wxNotebookPage
* page
)
307 int pagePos
= FindPagePosition(page
);
309 return RemovePage(pagePos
);
314 // Find the position of the wxNotebookPage, -1 if not found.
315 int wxNotebook::FindPagePosition(wxNotebookPage
* page
) const
317 int nPageCount
= GetPageCount();
319 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
320 if (m_aPages
[nPage
] == page
)
326 bool wxNotebook::DeleteAllPages()
328 m_tabView
->ClearTabs(TRUE
);
330 int nPageCount
= GetPageCount();
332 for ( nPage
= 0; nPage
< nPageCount
; nPage
++ )
333 delete m_aPages
[nPage
];
340 // add a page to the notebook
341 bool wxNotebook::AddPage(wxNotebookPage
*pPage
,
342 const wxString
& strText
,
346 return InsertPage(GetPageCount(), pPage
, strText
, bSelect
, imageId
);
349 // same as AddPage() but does it at given position
350 bool wxNotebook::InsertPage(int nPage
,
351 wxNotebookPage
*pPage
,
352 const wxString
& strText
,
356 wxASSERT( pPage
!= NULL
);
357 wxCHECK( IS_VALID_PAGE(nPage
) || nPage
== GetPageCount(), FALSE
);
359 m_tabView
->AddTab((int) (long) pPage
, strText
);
363 // save the pointer to the page
364 m_aPages
.Insert(pPage
, nPage
);
368 // This will cause ChangePage to be called, via OnSelPage
369 m_tabView
->SetTabSelection((int) (long) pPage
, TRUE
);
372 // some page must be selected: either this one or the first one if there is
373 // still no selection
374 if ( m_nSelection
== -1 )
377 RefreshLayout(FALSE
);
382 // ----------------------------------------------------------------------------
383 // wxNotebook callbacks
384 // ----------------------------------------------------------------------------
386 // @@@ OnSize() is used for setting the font when it's called for the first
387 // time because doing it in ::Create() doesn't work (for unknown reasons)
388 void wxNotebook::OnSize(wxSizeEvent
& event
)
390 static bool s_bFirstTime
= TRUE
;
391 if ( s_bFirstTime
) {
392 // TODO: any first-time-size processing.
393 s_bFirstTime
= FALSE
;
398 // Processing continues to next OnSize
402 // This was supposed to cure the non-display of the notebook
403 // until the user resizes the window.
405 void wxNotebook::OnIdle(wxIdleEvent
& event
)
407 static bool s_bFirstTime
= TRUE
;
408 if ( s_bFirstTime
) {
410 wxSize sz(GetSize());
418 wxSize sz(GetSize());
419 wxSizeEvent sizeEvent(sz, GetId());
420 sizeEvent.SetEventObject(this);
421 GetEventHandler()->ProcessEvent(sizeEvent);
424 s_bFirstTime
= FALSE
;
429 // Implementation: calculate the layout of the view rect
430 // and resize the children if required
431 bool wxNotebook::RefreshLayout(bool force
)
435 wxRect oldRect
= m_tabView
->GetViewRect();
438 GetClientSize(& cw
, & ch
);
440 int tabHeight
= m_tabView
->GetTotalTabHeight();
443 rect
.y
= tabHeight
+ 4;
445 rect
.height
= ch
- 4 - rect
.y
;
447 m_tabView
->SetViewRect(rect
);
451 // Need to do it a 2nd time to get the tab height with
452 // the new view width, since changing the view width changes the
454 tabHeight
= m_tabView
->GetTotalTabHeight();
456 rect
.y
= tabHeight
+ 4;
458 rect
.height
= ch
- 4 - rect
.y
;
460 m_tabView
->SetViewRect(rect
);
464 if (!force
&& (rect
== oldRect
))
467 // fit the notebook page to the tab control's display area
469 unsigned int nCount
= m_aPages
.Count();
470 for ( unsigned int nPage
= 0; nPage
< nCount
; nPage
++ ) {
471 wxNotebookPage
*pPage
= m_aPages
[nPage
];
472 if (pPage
->IsShown())
474 wxRect clientRect
= GetAvailableClientSize();
475 pPage
->SetSize(clientRect
.x
, clientRect
.y
, clientRect
.width
, clientRect
.height
);
476 if ( pPage
->GetAutoLayout() )
485 void wxNotebook::OnSelChange(wxNotebookEvent
& event
)
487 // is it our tab control?
488 if ( event
.GetEventObject() == this )
490 if (event
.GetSelection() != m_nSelection
)
491 ChangePage(event
.GetOldSelection(), event
.GetSelection());
494 // we want to give others a chance to process this message as well
498 void wxNotebook::OnSetFocus(wxFocusEvent
& event
)
500 // set focus to the currently selected page if any
501 if ( m_nSelection
!= -1 )
502 m_aPages
[m_nSelection
]->SetFocus();
507 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent
& event
)
509 if ( event
.IsWindowChange() ) {
511 AdvanceSelection(event
.GetDirection());
514 // pass to the parent
516 event
.SetCurrentFocus(this);
517 GetParent()->ProcessEvent(event
);
522 // ----------------------------------------------------------------------------
523 // wxNotebook base class virtuals
524 // ----------------------------------------------------------------------------
526 // override these 2 functions to do nothing: everything is done in OnSize
528 void wxNotebook::SetConstraintSizes(bool /* recurse */)
530 // don't set the sizes of the pages - their correct size is not yet known
531 wxControl::SetConstraintSizes(FALSE
);
534 bool wxNotebook::DoPhase(int /* nPhase */)
539 void wxNotebook::Command(wxCommandEvent
& event
)
541 wxFAIL_MSG("wxNotebook::Command not implemented");
544 // ----------------------------------------------------------------------------
545 // wxNotebook helper functions
546 // ----------------------------------------------------------------------------
548 // hide the currently active panel and show the new one
549 void wxNotebook::ChangePage(int nOldSel
, int nSel
)
551 // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n";
552 wxASSERT( nOldSel
!= nSel
); // impossible
554 if ( nOldSel
!= -1 ) {
555 m_aPages
[nOldSel
]->Show(FALSE
);
556 m_aPages
[nOldSel
]->Lower();
559 wxNotebookPage
*pPage
= m_aPages
[nSel
];
561 wxRect clientRect
= GetAvailableClientSize();
562 pPage
->SetSize(clientRect
.x
, clientRect
.y
, clientRect
.width
, clientRect
.height
);
573 void wxNotebook::OnMouseEvent(wxMouseEvent
& event
)
576 m_tabView
->OnEvent(event
);
579 void wxNotebook::OnPaint(wxPaintEvent
& WXUNUSED(event
) )
586 wxRect
wxNotebook::GetAvailableClientSize()
589 GetClientSize(& cw
, & ch
);
591 int tabHeight
= m_tabView
->GetTotalTabHeight();
593 // TODO: these margins should be configurable.
596 rect
.y
= tabHeight
+ 6;
597 rect
.width
= cw
- 12;
598 rect
.height
= ch
- 4 - rect
.y
;
607 IMPLEMENT_CLASS(wxNotebookTabView
, wxTabView
)
609 wxNotebookTabView::wxNotebookTabView(wxNotebook
*notebook
, long style
): wxTabView(style
)
611 m_notebook
= notebook
;
613 m_notebook
->SetTabView(this);
615 SetWindow(m_notebook
);
618 wxNotebookTabView::~wxNotebookTabView(void)
622 // Called when a tab is activated
623 void wxNotebookTabView::OnTabActivate(int activateId
, int deactivateId
)
628 wxNotebookEvent
event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
, m_notebook
->GetId());
630 // Translate from wxTabView's ids (which aren't position-dependent)
631 // to wxNotebook's (which are).
632 wxNotebookPage
* pActive
= (wxNotebookPage
*) activateId
;
633 wxNotebookPage
* pDeactive
= (wxNotebookPage
*) deactivateId
;
635 int activatePos
= m_notebook
->FindPagePosition(pActive
);
636 int deactivatePos
= m_notebook
->FindPagePosition(pDeactive
);
638 event
.SetEventObject(m_notebook
);
639 event
.SetSelection(activatePos
);
640 event
.SetOldSelection(deactivatePos
);
641 m_notebook
->GetEventHandler()->ProcessEvent(event
);