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