]> git.saurik.com Git - wxWidgets.git/blame - src/generic/notebook.cpp
documented wxHW_NO_SELECTION
[wxWidgets.git] / src / generic / notebook.cpp
CommitLineData
1e6d9499
JS
1///////////////////////////////////////////////////////////////////////////////
2// Name: notebook.cpp
3// Purpose: implementation of wxNotebook
4// Author: Julian Smart
5// Modified by:
6// Created: 17/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19#ifdef __GNUG__
20#pragma implementation "notebook.h"
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27#pragma hdrstop
28#endif
29
ed58dbea
RR
30#include "wx/string.h"
31#include "wx/log.h"
32#include "wx/settings.h"
33#include "wx/generic/imaglist.h"
34#include "wx/notebook.h"
35#include "wx/dcclient.h"
00dd3b18 36#include "wx/generic/tabg.h"
1e6d9499
JS
37
38// ----------------------------------------------------------------------------
39// macros
40// ----------------------------------------------------------------------------
41
42// check that the page index is valid
43#define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
44
45// ----------------------------------------------------------------------------
46// event table
47// ----------------------------------------------------------------------------
48
2e4df4bf
VZ
49DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
50DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
51
1e6d9499
JS
52BEGIN_EVENT_TABLE(wxNotebook, wxControl)
53 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
54 EVT_SIZE(wxNotebook::OnSize)
55 EVT_PAINT(wxNotebook::OnPaint)
56 EVT_MOUSE_EVENTS(wxNotebook::OnMouseEvent)
57 EVT_SET_FOCUS(wxNotebook::OnSetFocus)
58 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
f60d0f94 59// EVT_IDLE(wxNotebook::OnIdle)
1e6d9499
JS
60END_EVENT_TABLE()
61
62IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
63IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent)
1e6d9499
JS
64
65// ============================================================================
66// implementation
67// ============================================================================
68
00dd3b18
MB
69// ============================================================================
70// Private class
71// ============================================================================
72
73// This reuses wxTabView to draw the tabs.
74class WXDLLEXPORT wxNotebookTabView: public wxTabView
75{
76DECLARE_DYNAMIC_CLASS(wxNotebookTabView)
77public:
78 wxNotebookTabView(wxNotebook* notebook, long style = wxTAB_STYLE_DRAW_BOX | wxTAB_STYLE_COLOUR_INTERIOR);
79 ~wxNotebookTabView(void);
80
81 // Called when a tab is activated
82 virtual void OnTabActivate(int activateId, int deactivateId);
83 // Allows vetoing
84 virtual bool OnTabPreActivate(int activateId, int deactivateId);
85
86protected:
87 wxNotebook* m_notebook;
88};
89
1e6d9499
JS
90// ----------------------------------------------------------------------------
91// wxNotebook construction
92// ----------------------------------------------------------------------------
93
94// common part of all ctors
95void wxNotebook::Init()
96{
97 m_tabView = (wxNotebookTabView*) NULL;
1e6d9499
JS
98 m_nSelection = -1;
99}
100
101// default for dynamic class
102wxNotebook::wxNotebook()
103{
104 Init();
105}
106
107// the same arguments as for wxControl
108wxNotebook::wxNotebook(wxWindow *parent,
109 wxWindowID id,
110 const wxPoint& pos,
111 const wxSize& size,
112 long style,
113 const wxString& name)
114{
115 Init();
116
117 Create(parent, id, pos, size, style, name);
118}
119
120// Create() function
121bool wxNotebook::Create(wxWindow *parent,
122 wxWindowID id,
123 const wxPoint& pos,
124 const wxSize& size,
125 long style,
126 const wxString& name)
127{
128 // base init
129 SetName(name);
130
131 m_windowId = id == -1 ? NewControlId() : id;
132
133 // It's like a normal window...
f60d0f94 134 if (!wxWindow::Create(parent, id, pos, size, style|wxNO_BORDER, name))
1e6d9499
JS
135 return FALSE;
136
a756f210 137 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
f60d0f94 138
1e6d9499
JS
139 SetTabView(new wxNotebookTabView(this));
140
141 return TRUE;
142}
143
144// dtor
145wxNotebook::~wxNotebook()
146{
147 delete m_tabView;
148}
149
150// ----------------------------------------------------------------------------
151// wxNotebook accessors
152// ----------------------------------------------------------------------------
1e6d9499
JS
153int wxNotebook::GetRowCount() const
154{
155 // TODO
156 return 0;
157}
158
159int wxNotebook::SetSelection(int nPage)
160{
161 if (nPage == -1)
162 return 0;
163
164 wxASSERT( IS_VALID_PAGE(nPage) );
165
aeab10d0
JS
166#if defined (__WIN16__)
167 m_tabView->SetTabSelection(nPage);
168#else
1e6d9499
JS
169 wxNotebookPage* pPage = GetPage(nPage);
170
171 m_tabView->SetTabSelection((int) (long) pPage);
aeab10d0 172#endif
1e6d9499
JS
173 // TODO
174 return 0;
175}
176
45f22d48 177#if 0
1e6d9499
JS
178void wxNotebook::AdvanceSelection(bool bForward)
179{
180 int nSel = GetSelection();
181 int nMax = GetPageCount() - 1;
182 if ( bForward )
183 SetSelection(nSel == nMax ? 0 : nSel + 1);
184 else
185 SetSelection(nSel == 0 ? nMax : nSel - 1);
186}
45f22d48 187#endif
1e6d9499
JS
188
189bool wxNotebook::SetPageText(int nPage, const wxString& strText)
190{
191 wxASSERT( IS_VALID_PAGE(nPage) );
aeab10d0
JS
192#if defined (__WIN16__)
193 m_tabView->SetTabText(nPage, strText);
194 Refresh();
195 return TRUE;
196#else
1e6d9499
JS
197 wxNotebookPage* page = GetPage(nPage);
198 if (page)
199 {
200 m_tabView->SetTabText((int) (long) page, strText);
201 Refresh();
202 return TRUE;
203 }
aeab10d0 204#endif
1e6d9499
JS
205 return FALSE;
206}
207
208wxString wxNotebook::GetPageText(int nPage) const
209{
210 wxASSERT( IS_VALID_PAGE(nPage) );
211
aeab10d0
JS
212#if defined (__WIN16__)
213 return m_tabView->GetTabText(nPage);
214#else
1e6d9499
JS
215 wxNotebookPage* page = ((wxNotebook*)this)->GetPage(nPage);
216 if (page)
217 return m_tabView->GetTabText((int) (long) page);
218 else
219 return wxEmptyString;
aeab10d0 220#endif
1e6d9499
JS
221}
222
223int wxNotebook::GetPageImage(int nPage) const
224{
225 wxASSERT( IS_VALID_PAGE(nPage) );
226
227 // TODO
228 return 0;
229}
230
231bool wxNotebook::SetPageImage(int nPage, int nImage)
232{
233 wxASSERT( IS_VALID_PAGE(nPage) );
234
235 // TODO
236 return FALSE;
237}
238
9806a47c
JS
239// set the size (the same for all pages)
240void wxNotebook::SetPageSize(const wxSize& size)
241{
242 // TODO
243}
244
245// set the padding between tabs (in pixels)
246void wxNotebook::SetPadding(const wxSize& padding)
247{
248 // TODO
249}
250
251// set the size of the tabs for wxNB_FIXEDWIDTH controls
252void wxNotebook::SetTabSize(const wxSize& sz)
253{
254 // TODO
255}
256
1e6d9499
JS
257// ----------------------------------------------------------------------------
258// wxNotebook operations
259// ----------------------------------------------------------------------------
260
261// remove one page from the notebook and delete it
262bool wxNotebook::DeletePage(int nPage)
263{
264 wxCHECK( IS_VALID_PAGE(nPage), FALSE );
265
266 if (m_nSelection != -1)
267 {
45f22d48
JS
268 m_pages[m_nSelection]->Show(FALSE);
269 m_pages[m_nSelection]->Lower();
1e6d9499
JS
270 }
271
272 wxNotebookPage* pPage = GetPage(nPage);
aeab10d0
JS
273#if defined (__WIN16__)
274 m_tabView->RemoveTab(nPage);
275#else
1e6d9499 276 m_tabView->RemoveTab((int) (long) pPage);
aeab10d0 277#endif
1e6d9499 278
45f22d48
JS
279 m_pages.Remove(pPage);
280 delete pPage;
1e6d9499 281
45f22d48 282 if (m_pages.GetCount() == 0)
1e6d9499
JS
283 {
284 m_nSelection = -1;
285 m_tabView->SetTabSelection(-1, FALSE);
286 }
287 else if (m_nSelection > -1)
288 {
289 m_nSelection = -1;
aeab10d0
JS
290#if defined (__WIN16__)
291 m_tabView->SetTabSelection(0, FALSE);
292#else
1e6d9499 293 m_tabView->SetTabSelection((int) (long) GetPage(0), FALSE);
aeab10d0 294#endif
1e6d9499
JS
295 if (m_nSelection != 0)
296 ChangePage(-1, 0);
297 }
298
299 RefreshLayout(FALSE);
300
301 return TRUE;
302}
303
304bool wxNotebook::DeletePage(wxNotebookPage* page)
305{
306 int pagePos = FindPagePosition(page);
307 if (pagePos > -1)
308 return DeletePage(pagePos);
309 else
310 return FALSE;
311}
312
313// remove one page from the notebook
314bool wxNotebook::RemovePage(int nPage)
315{
316 wxCHECK( IS_VALID_PAGE(nPage), FALSE );
317
45f22d48
JS
318 m_pages[nPage]->Show(FALSE);
319 // m_pages[nPage]->Lower();
1e6d9499
JS
320
321 wxNotebookPage* pPage = GetPage(nPage);
aeab10d0
JS
322#if defined (__WIN16__)
323 m_tabView->RemoveTab(nPage);
324#else
1e6d9499 325 m_tabView->RemoveTab((int) (long) pPage);
aeab10d0 326#endif
1e6d9499 327
45f22d48 328 m_pages.Remove(pPage);
1e6d9499 329
45f22d48 330 if (m_pages.GetCount() == 0)
1e6d9499
JS
331 {
332 m_nSelection = -1;
333 m_tabView->SetTabSelection(-1, TRUE);
334 }
335 else if (m_nSelection > -1)
336 {
337 // Only change the selection if the page we
338 // deleted was the selection.
339 if (nPage == m_nSelection)
340 {
341 m_nSelection = -1;
342 // Select the first tab. Generates a ChangePage.
343 m_tabView->SetTabSelection((int) (long) GetPage(0), TRUE);
344 }
345 else
346 {
347 // We must adjust which tab we think is selected.
348 // If greater than the page we deleted, it must be moved down
349 // a notch.
350 if (m_nSelection > nPage)
351 m_nSelection -- ;
352 }
353 }
354
355 RefreshLayout(FALSE);
356
357 return TRUE;
358}
359
360bool wxNotebook::RemovePage(wxNotebookPage* page)
361{
362 int pagePos = FindPagePosition(page);
363 if (pagePos > -1)
364 return RemovePage(pagePos);
365 else
366 return FALSE;
367}
368
369// Find the position of the wxNotebookPage, -1 if not found.
370int wxNotebook::FindPagePosition(wxNotebookPage* page) const
371{
372 int nPageCount = GetPageCount();
373 int nPage;
374 for ( nPage = 0; nPage < nPageCount; nPage++ )
45f22d48 375 if (m_pages[nPage] == page)
1e6d9499
JS
376 return nPage;
377 return -1;
378}
379
380// remove all pages
381bool wxNotebook::DeleteAllPages()
382{
383 m_tabView->ClearTabs(TRUE);
384
385 int nPageCount = GetPageCount();
386 int nPage;
387 for ( nPage = 0; nPage < nPageCount; nPage++ )
45f22d48 388 delete m_pages[nPage];
1e6d9499 389
45f22d48 390 m_pages.Clear();
1e6d9499
JS
391
392 return TRUE;
393}
394
1e6d9499
JS
395// same as AddPage() but does it at given position
396bool wxNotebook::InsertPage(int nPage,
397 wxNotebookPage *pPage,
398 const wxString& strText,
399 bool bSelect,
400 int imageId)
401{
402 wxASSERT( pPage != NULL );
403 wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), FALSE );
404
aeab10d0
JS
405// For 16 bit integers (tabs limited to 32768)
406#if defined (__WIN16__)
407 m_tabView->AddTab(nPage, strText);
408#else
1e6d9499 409 m_tabView->AddTab((int) (long) pPage, strText);
aeab10d0 410#endif
1e6d9499
JS
411 if (!bSelect)
412 pPage->Show(FALSE);
413
414 // save the pointer to the page
45f22d48 415 m_pages.Insert(pPage, nPage);
1e6d9499
JS
416
417 if (bSelect)
418 {
419 // This will cause ChangePage to be called, via OnSelPage
aeab10d0
JS
420#if defined (__WIN16__)
421 m_tabView->SetTabSelection(nPage, TRUE);
422#else
1e6d9499 423 m_tabView->SetTabSelection((int) (long) pPage, TRUE);
aeab10d0 424#endif
1e6d9499
JS
425 }
426
427 // some page must be selected: either this one or the first one if there is
428 // still no selection
429 if ( m_nSelection == -1 )
430 ChangePage(-1, 0);
431
432 RefreshLayout(FALSE);
433
434 return TRUE;
435}
436
437// ----------------------------------------------------------------------------
438// wxNotebook callbacks
439// ----------------------------------------------------------------------------
440
441// @@@ OnSize() is used for setting the font when it's called for the first
442// time because doing it in ::Create() doesn't work (for unknown reasons)
443void wxNotebook::OnSize(wxSizeEvent& event)
444{
445 static bool s_bFirstTime = TRUE;
446 if ( s_bFirstTime ) {
447 // TODO: any first-time-size processing.
448 s_bFirstTime = FALSE;
449 }
450
451 RefreshLayout();
452
453 // Processing continues to next OnSize
454 event.Skip();
455}
456
457// This was supposed to cure the non-display of the notebook
458// until the user resizes the window.
459// What's going on?
460void wxNotebook::OnIdle(wxIdleEvent& event)
461{
462 static bool s_bFirstTime = TRUE;
463 if ( s_bFirstTime ) {
464 /*
465 wxSize sz(GetSize());
466 sz.x ++;
467 SetSize(sz);
468 sz.x --;
469 SetSize(sz);
470 */
471
472 /*
473 wxSize sz(GetSize());
474 wxSizeEvent sizeEvent(sz, GetId());
475 sizeEvent.SetEventObject(this);
476 GetEventHandler()->ProcessEvent(sizeEvent);
477 Refresh();
478 */
479 s_bFirstTime = FALSE;
480 }
481 event.Skip();
482}
483
484// Implementation: calculate the layout of the view rect
485// and resize the children if required
486bool wxNotebook::RefreshLayout(bool force)
487{
488 if (m_tabView)
489 {
490 wxRect oldRect = m_tabView->GetViewRect();
491
492 int cw, ch;
493 GetClientSize(& cw, & ch);
494
495 int tabHeight = m_tabView->GetTotalTabHeight();
496 wxRect rect;
497 rect.x = 4;
498 rect.y = tabHeight + 4;
499 rect.width = cw - 8;
500 rect.height = ch - 4 - rect.y ;
2e4df4bf 501
1e6d9499
JS
502 m_tabView->SetViewRect(rect);
503
25889d3c 504 m_tabView->LayoutTabs();
1e6d9499
JS
505
506 // Need to do it a 2nd time to get the tab height with
507 // the new view width, since changing the view width changes the
508 // tab layout.
509 tabHeight = m_tabView->GetTotalTabHeight();
510 rect.x = 4;
511 rect.y = tabHeight + 4;
512 rect.width = cw - 8;
513 rect.height = ch - 4 - rect.y ;
2e4df4bf 514
1e6d9499
JS
515 m_tabView->SetViewRect(rect);
516
25889d3c 517 m_tabView->LayoutTabs();
1e6d9499
JS
518
519 if (!force && (rect == oldRect))
520 return FALSE;
521
522 // fit the notebook page to the tab control's display area
523
45f22d48 524 unsigned int nCount = m_pages.Count();
1e6d9499 525 for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) {
45f22d48 526 wxNotebookPage *pPage = m_pages[nPage];
10d1f413 527 wxRect clientRect = GetAvailableClientSize();
1e6d9499
JS
528 if (pPage->IsShown())
529 {
1e6d9499
JS
530 pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height);
531 if ( pPage->GetAutoLayout() )
532 pPage->Layout();
533 }
10d1f413
MB
534 // MBN: this is probably just hiding a problem under the carpet,
535 // but: with OpenMotif 2.2 (not Lesstif), not moving the window
536 // may cause the tabs to be not clickable.
537 else
538 {
539 pPage->Move(clientRect.x, clientRect.y);
540 }
1e6d9499
JS
541 }
542 Refresh();
543 }
544 return TRUE;
545}
546
547void wxNotebook::OnSelChange(wxNotebookEvent& event)
548{
549 // is it our tab control?
550 if ( event.GetEventObject() == this )
551 {
552 if (event.GetSelection() != m_nSelection)
553 ChangePage(event.GetOldSelection(), event.GetSelection());
554 }
555
556 // we want to give others a chance to process this message as well
557 event.Skip();
558}
559
560void wxNotebook::OnSetFocus(wxFocusEvent& event)
561{
562 // set focus to the currently selected page if any
563 if ( m_nSelection != -1 )
45f22d48 564 m_pages[m_nSelection]->SetFocus();
1e6d9499
JS
565
566 event.Skip();
567}
568
569void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
570{
571 if ( event.IsWindowChange() ) {
572 // change pages
573 AdvanceSelection(event.GetDirection());
574 }
575 else {
576 // pass to the parent
577 if ( GetParent() ) {
578 event.SetCurrentFocus(this);
579 GetParent()->ProcessEvent(event);
580 }
581 }
582}
583
584// ----------------------------------------------------------------------------
585// wxNotebook base class virtuals
586// ----------------------------------------------------------------------------
587
588// override these 2 functions to do nothing: everything is done in OnSize
589
590void wxNotebook::SetConstraintSizes(bool /* recurse */)
591{
592 // don't set the sizes of the pages - their correct size is not yet known
593 wxControl::SetConstraintSizes(FALSE);
594}
595
596bool wxNotebook::DoPhase(int /* nPhase */)
597{
598 return TRUE;
599}
600
af111fc3 601void wxNotebook::Command(wxCommandEvent& WXUNUSED(event))
1e6d9499
JS
602{
603 wxFAIL_MSG("wxNotebook::Command not implemented");
604}
605
606// ----------------------------------------------------------------------------
607// wxNotebook helper functions
608// ----------------------------------------------------------------------------
609
610// hide the currently active panel and show the new one
611void wxNotebook::ChangePage(int nOldSel, int nSel)
612{
613 // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n";
614 wxASSERT( nOldSel != nSel ); // impossible
615
616 if ( nOldSel != -1 ) {
45f22d48
JS
617 m_pages[nOldSel]->Show(FALSE);
618 m_pages[nOldSel]->Lower();
1e6d9499
JS
619 }
620
45f22d48 621 wxNotebookPage *pPage = m_pages[nSel];
1e6d9499
JS
622
623 wxRect clientRect = GetAvailableClientSize();
624 pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height);
625
f6bcfd97
BP
626 Refresh();
627
1e6d9499
JS
628 pPage->Show(TRUE);
629 pPage->Raise();
630 pPage->SetFocus();
631
1e6d9499
JS
632 m_nSelection = nSel;
633}
634
635void wxNotebook::OnMouseEvent(wxMouseEvent& event)
636{
637 if (m_tabView)
638 m_tabView->OnEvent(event);
639}
640
641void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event) )
642{
643 wxPaintDC dc(this);
644 if (m_tabView)
645 m_tabView->Draw(dc);
646}
647
648wxRect wxNotebook::GetAvailableClientSize()
649{
650 int cw, ch;
651 GetClientSize(& cw, & ch);
652
653 int tabHeight = m_tabView->GetTotalTabHeight();
654
655 // TODO: these margins should be configurable.
656 wxRect rect;
657 rect.x = 6;
658 rect.y = tabHeight + 6;
659 rect.width = cw - 12;
660 rect.height = ch - 4 - rect.y ;
661
662 return rect;
663}
664
665/*
666 * wxNotebookTabView
667 */
2e4df4bf 668
1e6d9499
JS
669IMPLEMENT_CLASS(wxNotebookTabView, wxTabView)
670
671wxNotebookTabView::wxNotebookTabView(wxNotebook *notebook, long style): wxTabView(style)
672{
673 m_notebook = notebook;
674
675 m_notebook->SetTabView(this);
676
677 SetWindow(m_notebook);
678}
679
680wxNotebookTabView::~wxNotebookTabView(void)
681{
682}
683
684// Called when a tab is activated
685void wxNotebookTabView::OnTabActivate(int activateId, int deactivateId)
686{
687 if (!m_notebook)
688 return;
689
690 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_notebook->GetId());
691
aeab10d0
JS
692#if defined (__WIN16__)
693 int activatePos = activateId;
694 int deactivatePos = deactivateId;
695#else
1e6d9499
JS
696 // Translate from wxTabView's ids (which aren't position-dependent)
697 // to wxNotebook's (which are).
698 wxNotebookPage* pActive = (wxNotebookPage*) activateId;
699 wxNotebookPage* pDeactive = (wxNotebookPage*) deactivateId;
700
701 int activatePos = m_notebook->FindPagePosition(pActive);
702 int deactivatePos = m_notebook->FindPagePosition(pDeactive);
703
aeab10d0 704#endif
1e6d9499
JS
705 event.SetEventObject(m_notebook);
706 event.SetSelection(activatePos);
707 event.SetOldSelection(deactivatePos);
708 m_notebook->GetEventHandler()->ProcessEvent(event);
709}
710
1c507b17
JS
711// Allows Vetoing
712bool wxNotebookTabView::OnTabPreActivate(int activateId, int deactivateId)
713{
714 bool retval = TRUE;
715
716 if (m_notebook)
717 {
718 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_notebook->GetId());
719
720#if defined (__WIN16__)
721 int activatePos = activateId;
722 int deactivatePos = deactivateId;
723#else
724 // Translate from wxTabView's ids (which aren't position-dependent)
725 // to wxNotebook's (which are).
726 wxNotebookPage* pActive = (wxNotebookPage*) activateId;
727 wxNotebookPage* pDeactive = (wxNotebookPage*) deactivateId;
728
729 int activatePos = m_notebook->FindPagePosition(pActive);
730 int deactivatePos = m_notebook->FindPagePosition(pDeactive);
731
732#endif
733 event.SetEventObject(m_notebook);
734 event.SetSelection(activatePos);
735 event.SetOldSelection(deactivatePos);
736 if (m_notebook->GetEventHandler()->ProcessEvent(event))
737 {
738 retval = event.IsAllowed();
739 }
740 }
741 return retval;
742}
1e6d9499 743