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