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