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