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