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