]> git.saurik.com Git - wxWidgets.git/blob - src/motif/notebook.cpp
Redid parts of wxScroledWindow
[wxWidgets.git] / src / motif / 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 #include <wx/string.h>
24 #include <wx/log.h>
25 #include <wx/imaglist.h>
26 #include <wx/notebook.h>
27 #include <wx/dcclient.h>
28
29 #include <Xm/Xm.h>
30 #include <wx/motif/private.h>
31
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
44 BEGIN_EVENT_TABLE(wxNotebook, wxControl)
45 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
46 EVT_SIZE(wxNotebook::OnSize)
47 EVT_PAINT(wxNotebook::OnPaint)
48 EVT_MOUSE_EVENTS(wxNotebook::OnMouseEvent)
49 EVT_SET_FOCUS(wxNotebook::OnSetFocus)
50 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
51 EVT_IDLE(wxNotebook::OnIdle)
52 END_EVENT_TABLE()
53
54 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
55 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent)
56 #endif
57
58 // ============================================================================
59 // implementation
60 // ============================================================================
61
62 // ----------------------------------------------------------------------------
63 // wxNotebook construction
64 // ----------------------------------------------------------------------------
65
66 // common part of all ctors
67 void wxNotebook::Init()
68 {
69 m_tabView = (wxNotebookTabView*) NULL;
70 m_pImageList = NULL;
71 m_nSelection = -1;
72 }
73
74 // default for dynamic class
75 wxNotebook::wxNotebook()
76 {
77 Init();
78 }
79
80 // the same arguments as for wxControl
81 wxNotebook::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
94 bool 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);
103
104 m_windowId = id == -1 ? NewControlId() : id;
105
106 // It's like a normal window...
107 if (!wxWindow::Create(parent, id, pos, size, style, name))
108 return FALSE;
109
110 SetTabView(new wxNotebookTabView(this));
111
112 return TRUE;
113 }
114
115 // dtor
116 wxNotebook::~wxNotebook()
117 {
118 delete m_tabView;
119 }
120
121 // ----------------------------------------------------------------------------
122 // wxNotebook accessors
123 // ----------------------------------------------------------------------------
124 int wxNotebook::GetPageCount() const
125 {
126 return m_aPages.Count();
127 }
128
129 int wxNotebook::GetRowCount() const
130 {
131 // TODO
132 return 0;
133 }
134
135 int wxNotebook::SetSelection(int nPage)
136 {
137 if (nPage == -1)
138 return 0;
139
140 wxASSERT( IS_VALID_PAGE(nPage) );
141
142 wxNotebookPage* pPage = GetPage(nPage);
143
144 m_tabView->SetTabSelection((int) (long) pPage);
145
146 // TODO
147 return 0;
148 }
149
150 void 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
160 bool wxNotebook::SetPageText(int nPage, const wxString& strText)
161 {
162 wxASSERT( IS_VALID_PAGE(nPage) );
163
164 wxNotebookPage* page = GetPage(nPage);
165 if (page)
166 {
167 m_tabView->SetTabText((int) (long) page, strText);
168 Refresh();
169 return TRUE;
170 }
171
172 return FALSE;
173 }
174
175 wxString wxNotebook::GetPageText(int nPage) const
176 {
177 wxASSERT( IS_VALID_PAGE(nPage) );
178
179 wxNotebookPage* page = ((wxNotebook*)this)->GetPage(nPage);
180 if (page)
181 return m_tabView->GetTabText((int) (long) page);
182 else
183 return wxEmptyString;
184 }
185
186 int wxNotebook::GetPageImage(int nPage) const
187 {
188 wxASSERT( IS_VALID_PAGE(nPage) );
189
190 // TODO
191 return 0;
192 }
193
194 bool wxNotebook::SetPageImage(int nPage, int nImage)
195 {
196 wxASSERT( IS_VALID_PAGE(nPage) );
197
198 // TODO
199 return FALSE;
200 }
201
202 void wxNotebook::SetImageList(wxImageList* imageList)
203 {
204 m_pImageList = imageList;
205 // TODO
206 }
207
208 // ----------------------------------------------------------------------------
209 // wxNotebook operations
210 // ----------------------------------------------------------------------------
211
212 // remove one page from the notebook and delete it
213 bool wxNotebook::DeletePage(int nPage)
214 {
215 wxCHECK( IS_VALID_PAGE(nPage), FALSE );
216
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);
225
226 delete m_aPages[nPage];
227 m_aPages.Remove(nPage);
228
229 if (m_aPages.GetCount() == 0)
230 {
231 m_nSelection = -1;
232 m_tabView->SetTabSelection(-1, FALSE);
233 }
234 else if (m_nSelection > -1)
235 {
236 m_nSelection = -1;
237 m_tabView->SetTabSelection((int) (long) GetPage(0), FALSE);
238 if (m_nSelection != 0)
239 ChangePage(-1, 0);
240 }
241
242 RefreshLayout(FALSE);
243
244 return TRUE;
245 }
246
247 bool 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
257 bool wxNotebook::RemovePage(int nPage)
258 {
259 wxCHECK( IS_VALID_PAGE(nPage), FALSE );
260
261 m_aPages[nPage]->Show(FALSE);
262 // m_aPages[nPage]->Lower();
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;
272 m_tabView->SetTabSelection(-1, TRUE);
273 }
274 else if (m_nSelection > -1)
275 {
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 }
292 }
293
294 RefreshLayout(FALSE);
295
296 return TRUE;
297 }
298
299 bool 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.
309 int 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;
317 }
318
319 // remove all pages
320 bool wxNotebook::DeleteAllPages()
321 {
322 m_tabView->ClearTabs(TRUE);
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
335 bool 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
344 bool 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
353 m_tabView->AddTab((int) (long) pPage, strText);
354 if (!bSelect)
355 pPage->Show(FALSE);
356
357 // save the pointer to the page
358 m_aPages.Insert(pPage, nPage);
359
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
367 // still no selection
368 if ( m_nSelection == -1 )
369 ChangePage(-1, 0);
370
371 RefreshLayout(FALSE);
372
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)
382 void 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
390 RefreshLayout();
391
392 // Processing continues to next OnSize
393 event.Skip();
394 }
395
396 // This was supposed to cure the non-display of the notebook
397 // until the user resizes the window.
398 // What's going on?
399 void wxNotebook::OnIdle(wxIdleEvent& event)
400 {
401 static bool s_bFirstTime = TRUE;
402 if ( s_bFirstTime ) {
403 /*
404 wxSize sz(GetSize());
405 sz.x ++;
406 SetSize(sz);
407 sz.x --;
408 SetSize(sz);
409 */
410
411 /*
412 wxSize sz(GetSize());
413 wxSizeEvent sizeEvent(sz, GetId());
414 sizeEvent.SetEventObject(this);
415 GetEventHandler()->ProcessEvent(sizeEvent);
416 Refresh();
417 */
418 s_bFirstTime = FALSE;
419 }
420 event.Skip();
421 }
422
423 // Implementation: calculate the layout of the view rect
424 // and resize the children if required
425 bool wxNotebook::RefreshLayout(bool force)
426 {
427 if (m_tabView)
428 {
429 wxRect oldRect = m_tabView->GetViewRect();
430
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();
457
458 if (!force && (rect == oldRect))
459 return FALSE;
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];
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 }
473 }
474 Refresh();
475 }
476 return TRUE;
477 }
478
479 void wxNotebook::OnSelChange(wxNotebookEvent& event)
480 {
481 // is it our tab control?
482 if ( event.GetEventObject() == this )
483 {
484 if (event.GetSelection() != m_nSelection)
485 ChangePage(event.GetOldSelection(), event.GetSelection());
486 }
487
488 // we want to give others a chance to process this message as well
489 event.Skip();
490 }
491
492 void 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
501 void 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
522 void 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
528 bool wxNotebook::DoPhase(int /* nPhase */)
529 {
530 return TRUE;
531 }
532
533 void 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
543 void wxNotebook::ChangePage(int nOldSel, int nSel)
544 {
545 // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n";
546 wxASSERT( nOldSel != nSel ); // impossible
547
548 if ( nOldSel != -1 ) {
549 m_aPages[nOldSel]->Show(FALSE);
550 m_aPages[nOldSel]->Lower();
551 }
552
553 wxNotebookPage *pPage = m_aPages[nSel];
554
555 wxRect clientRect = GetAvailableClientSize();
556 pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height);
557
558 pPage->Show(TRUE);
559 pPage->Raise();
560 pPage->SetFocus();
561
562 Refresh();
563
564 m_nSelection = nSel;
565 }
566
567 void wxNotebook::ChangeFont(bool keepOriginalSize)
568 {
569 wxWindow::ChangeFont(keepOriginalSize);
570 }
571
572 void wxNotebook::ChangeBackgroundColour()
573 {
574 wxWindow::ChangeBackgroundColour();
575 }
576
577 void wxNotebook::ChangeForegroundColour()
578 {
579 wxWindow::ChangeForegroundColour();
580 }
581
582 void wxNotebook::OnMouseEvent(wxMouseEvent& event)
583 {
584 if (m_tabView)
585 m_tabView->OnEvent(event);
586 }
587
588 void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event) )
589 {
590 wxPaintDC dc(this);
591 if (m_tabView)
592 m_tabView->Draw(dc);
593 }
594
595 wxRect 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
612 /*
613 * wxNotebookTabView
614 */
615
616 IMPLEMENT_CLASS(wxNotebookTabView, wxTabView)
617
618 wxNotebookTabView::wxNotebookTabView(wxNotebook *notebook, long style): wxTabView(style)
619 {
620 m_notebook = notebook;
621
622 m_notebook->SetTabView(this);
623
624 SetWindow(m_notebook);
625 }
626
627 wxNotebookTabView::~wxNotebookTabView(void)
628 {
629 }
630
631 // Called when a tab is activated
632 void wxNotebookTabView::OnTabActivate(int activateId, int deactivateId)
633 {
634 if (!m_notebook)
635 return;
636
637 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_notebook->GetId());
638
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;
643
644 int activatePos = m_notebook->FindPagePosition(pActive);
645 int deactivatePos = m_notebook->FindPagePosition(pDeactive);
646
647 event.SetEventObject(m_notebook);
648 event.SetSelection(activatePos);
649 event.SetOldSelection(deactivatePos);
650 m_notebook->GetEventHandler()->ProcessEvent(event);
651 }
652
653