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