]> git.saurik.com Git - wxWidgets.git/blob - src/motif/notebook.cpp
Corrections to Forty Thieves; wxMemoryDC problem temporarily sorted
[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 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
413 // Implementation: calculate the layout of the view rect
414 // and resize the children if required
415 bool wxNotebook::RefreshLayout(bool force)
416 {
417 if (m_tabView)
418 {
419 wxRect oldRect = m_tabView->GetViewRect();
420
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();
447
448 if (!force && (rect == oldRect))
449 return FALSE;
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];
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 }
463 }
464 Refresh();
465 }
466 return TRUE;
467 }
468
469 void wxNotebook::OnSelChange(wxNotebookEvent& event)
470 {
471 // is it our tab control?
472 if ( event.GetEventObject() == this )
473 {
474 if (event.GetSelection() != m_nSelection)
475 ChangePage(event.GetOldSelection(), event.GetSelection());
476 }
477
478 // we want to give others a chance to process this message as well
479 event.Skip();
480 }
481
482 void 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
491 void 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
512 void 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
518 bool wxNotebook::DoPhase(int /* nPhase */)
519 {
520 return TRUE;
521 }
522
523 void 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
533 void wxNotebook::ChangePage(int nOldSel, int nSel)
534 {
535 // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n";
536 wxASSERT( nOldSel != nSel ); // impossible
537
538 if ( nOldSel != -1 ) {
539 m_aPages[nOldSel]->Show(FALSE);
540 m_aPages[nOldSel]->Lower();
541 }
542
543 wxNotebookPage *pPage = m_aPages[nSel];
544
545 wxRect clientRect = GetAvailableClientSize();
546 pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height);
547
548 pPage->Show(TRUE);
549 pPage->Raise();
550 pPage->SetFocus();
551
552 Refresh();
553
554 m_nSelection = nSel;
555 }
556
557 void wxNotebook::ChangeFont(bool keepOriginalSize)
558 {
559 wxWindow::ChangeFont(keepOriginalSize);
560 }
561
562 void wxNotebook::ChangeBackgroundColour()
563 {
564 wxWindow::ChangeBackgroundColour();
565 }
566
567 void wxNotebook::ChangeForegroundColour()
568 {
569 wxWindow::ChangeForegroundColour();
570 }
571
572 void wxNotebook::OnMouseEvent(wxMouseEvent& event)
573 {
574 if (m_tabView)
575 m_tabView->OnEvent(event);
576 }
577
578 void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event) )
579 {
580 wxPaintDC dc(this);
581 if (m_tabView)
582 m_tabView->Draw(dc);
583 }
584
585 wxRect 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
602 /*
603 * wxNotebookTabView
604 */
605
606 IMPLEMENT_CLASS(wxNotebookTabView, wxTabView)
607
608 wxNotebookTabView::wxNotebookTabView(wxNotebook *notebook, long style): wxTabView(style)
609 {
610 m_notebook = notebook;
611
612 m_notebook->SetTabView(this);
613
614 SetWindow(m_notebook);
615 }
616
617 wxNotebookTabView::~wxNotebookTabView(void)
618 {
619 }
620
621 // Called when a tab is activated
622 void wxNotebookTabView::OnTabActivate(int activateId, int deactivateId)
623 {
624 if (!m_notebook)
625 return;
626
627 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_notebook->GetId());
628
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;
633
634 int activatePos = m_notebook->FindPagePosition(pActive);
635 int deactivatePos = m_notebook->FindPagePosition(pDeactive);
636
637 event.SetEventObject(m_notebook);
638 event.SetSelection(activatePos);
639 event.SetOldSelection(deactivatePos);
640 m_notebook->GetEventHandler()->ProcessEvent(event);
641 }
642
643