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