]> git.saurik.com Git - wxWidgets.git/blame - src/motif/notebook.cpp
Got generic wxListCtrl, wxTreeCtrl working under Windows, wxNotebook almost;
[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 ) {
5dcf05ae
JS
403 /*
404 wxSize sz(GetSize());
405 sz.x ++;
406 SetSize(sz);
407 sz.x --;
408 SetSize(sz);
409 */
410
411 /*
c0ed460c
JS
412 wxSize sz(GetSize());
413 wxSizeEvent sizeEvent(sz, GetId());
414 sizeEvent.SetEventObject(this);
415 GetEventHandler()->ProcessEvent(sizeEvent);
416 Refresh();
5dcf05ae 417 */
c0ed460c
JS
418 s_bFirstTime = FALSE;
419 }
420 event.Skip();
421}
422
7fe7d506
JS
423// Implementation: calculate the layout of the view rect
424// and resize the children if required
425bool wxNotebook::RefreshLayout(bool force)
426{
4b5f3fe6
JS
427 if (m_tabView)
428 {
7fe7d506
JS
429 wxRect oldRect = m_tabView->GetViewRect();
430
4b5f3fe6
JS
431 int cw, ch;
432 GetClientSize(& cw, & ch);
433
434 int tabHeight = m_tabView->GetTotalTabHeight();
435 wxRect rect;
436 rect.x = 4;
437 rect.y = tabHeight + 4;
438 rect.width = cw - 8;
439 rect.height = ch - 4 - rect.y ;
440
441 m_tabView->SetViewRect(rect);
442
443 m_tabView->Layout();
444
445 // Need to do it a 2nd time to get the tab height with
446 // the new view width, since changing the view width changes the
447 // tab layout.
448 tabHeight = m_tabView->GetTotalTabHeight();
449 rect.x = 4;
450 rect.y = tabHeight + 4;
451 rect.width = cw - 8;
452 rect.height = ch - 4 - rect.y ;
453
454 m_tabView->SetViewRect(rect);
455
456 m_tabView->Layout();
7fe7d506
JS
457
458 if (!force && (rect == oldRect))
459 return FALSE;
4b5f3fe6
JS
460
461 // fit the notebook page to the tab control's display area
462
463 unsigned int nCount = m_aPages.Count();
464 for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) {
465 wxNotebookPage *pPage = m_aPages[nPage];
02800301
JS
466 if (pPage->IsShown())
467 {
468 wxRect clientRect = GetAvailableClientSize();
469 pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height);
470 if ( pPage->GetAutoLayout() )
471 pPage->Layout();
472 }
4b5f3fe6
JS
473 }
474 Refresh();
4bb6408c 475 }
7fe7d506 476 return TRUE;
4bb6408c
JS
477}
478
479void wxNotebook::OnSelChange(wxNotebookEvent& event)
480{
481 // is it our tab control?
482 if ( event.GetEventObject() == this )
7fe7d506
JS
483 {
484 if (event.GetSelection() != m_nSelection)
485 ChangePage(event.GetOldSelection(), event.GetSelection());
486 }
4bb6408c
JS
487
488 // we want to give others a chance to process this message as well
489 event.Skip();
490}
491
492void wxNotebook::OnSetFocus(wxFocusEvent& event)
493{
494 // set focus to the currently selected page if any
495 if ( m_nSelection != -1 )
496 m_aPages[m_nSelection]->SetFocus();
497
498 event.Skip();
499}
500
501void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
502{
503 if ( event.IsWindowChange() ) {
504 // change pages
505 AdvanceSelection(event.GetDirection());
506 }
507 else {
508 // pass to the parent
509 if ( GetParent() ) {
510 event.SetCurrentFocus(this);
511 GetParent()->ProcessEvent(event);
512 }
513 }
514}
515
516// ----------------------------------------------------------------------------
517// wxNotebook base class virtuals
518// ----------------------------------------------------------------------------
519
520// override these 2 functions to do nothing: everything is done in OnSize
521
522void wxNotebook::SetConstraintSizes(bool /* recurse */)
523{
524 // don't set the sizes of the pages - their correct size is not yet known
525 wxControl::SetConstraintSizes(FALSE);
526}
527
528bool wxNotebook::DoPhase(int /* nPhase */)
529{
530 return TRUE;
531}
532
533void wxNotebook::Command(wxCommandEvent& event)
534{
535 wxFAIL_MSG("wxNotebook::Command not implemented");
536}
537
538// ----------------------------------------------------------------------------
539// wxNotebook helper functions
540// ----------------------------------------------------------------------------
541
542// hide the currently active panel and show the new one
543void wxNotebook::ChangePage(int nOldSel, int nSel)
544{
7fe7d506 545 // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n";
4bb6408c
JS
546 wxASSERT( nOldSel != nSel ); // impossible
547
548 if ( nOldSel != -1 ) {
549 m_aPages[nOldSel]->Show(FALSE);
02800301 550 m_aPages[nOldSel]->Lower();
4bb6408c
JS
551 }
552
553 wxNotebookPage *pPage = m_aPages[nSel];
02800301
JS
554
555 wxRect clientRect = GetAvailableClientSize();
556 pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height);
557
4bb6408c 558 pPage->Show(TRUE);
02800301 559 pPage->Raise();
4bb6408c
JS
560 pPage->SetFocus();
561
02800301
JS
562 Refresh();
563
4bb6408c
JS
564 m_nSelection = nSel;
565}
566
4b5f3fe6 567void wxNotebook::ChangeFont(bool keepOriginalSize)
0d57be45 568{
4b5f3fe6 569 wxWindow::ChangeFont(keepOriginalSize);
0d57be45
JS
570}
571
572void wxNotebook::ChangeBackgroundColour()
573{
4b5f3fe6 574 wxWindow::ChangeBackgroundColour();
0d57be45
JS
575}
576
577void wxNotebook::ChangeForegroundColour()
578{
4b5f3fe6
JS
579 wxWindow::ChangeForegroundColour();
580}
581
582void wxNotebook::OnMouseEvent(wxMouseEvent& event)
583{
584 if (m_tabView)
585 m_tabView->OnEvent(event);
586}
587
588void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event) )
589{
590 wxPaintDC dc(this);
591 if (m_tabView)
592 m_tabView->Draw(dc);
593}
594
02800301
JS
595wxRect wxNotebook::GetAvailableClientSize()
596{
597 int cw, ch;
598 GetClientSize(& cw, & ch);
599
600 int tabHeight = m_tabView->GetTotalTabHeight();
601
602 // TODO: these margins should be configurable.
603 wxRect rect;
604 rect.x = 6;
605 rect.y = tabHeight + 6;
606 rect.width = cw - 12;
607 rect.height = ch - 4 - rect.y ;
608
609 return rect;
610}
611
4b5f3fe6
JS
612/*
613 * wxNotebookTabView
614 */
615
616IMPLEMENT_CLASS(wxNotebookTabView, wxTabView)
617
618wxNotebookTabView::wxNotebookTabView(wxNotebook *notebook, long style): wxTabView(style)
619{
620 m_notebook = notebook;
621
4b5f3fe6
JS
622 m_notebook->SetTabView(this);
623
624 SetWindow(m_notebook);
625}
626
627wxNotebookTabView::~wxNotebookTabView(void)
628{
4b5f3fe6
JS
629}
630
631// Called when a tab is activated
632void wxNotebookTabView::OnTabActivate(int activateId, int deactivateId)
633{
634 if (!m_notebook)
635 return;
02800301
JS
636
637 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_notebook->GetId());
02800301 638
621793f4
JS
639 // Translate from wxTabView's ids (which aren't position-dependent)
640 // to wxNotebook's (which are).
641 wxNotebookPage* pActive = (wxNotebookPage*) activateId;
642 wxNotebookPage* pDeactive = (wxNotebookPage*) deactivateId;
02800301 643
621793f4
JS
644 int activatePos = m_notebook->FindPagePosition(pActive);
645 int deactivatePos = m_notebook->FindPagePosition(pDeactive);
0d57be45 646
621793f4
JS
647 event.SetEventObject(m_notebook);
648 event.SetSelection(activatePos);
649 event.SetOldSelection(deactivatePos);
650 m_notebook->GetEventHandler()->ProcessEvent(event);
4b5f3fe6
JS
651}
652
4b5f3fe6 653