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