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