]> git.saurik.com Git - wxWidgets.git/blob - src/osx/notebook_osx.cpp
No changes, just use wxRecursionGuard instead of manual boolean flag.
[wxWidgets.git] / src / osx / notebook_osx.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/notebook_osx.cpp
3 // Purpose: implementation of wxNotebook
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #if wxUSE_NOTEBOOK
14
15 #include "wx/notebook.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/string.h"
19 #include "wx/log.h"
20 #include "wx/app.h"
21 #include "wx/image.h"
22 #endif
23
24 #include "wx/string.h"
25 #include "wx/imaglist.h"
26 #include "wx/osx/private.h"
27
28
29 // check that the page index is valid
30 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
31
32 BEGIN_EVENT_TABLE(wxNotebook, wxBookCtrlBase)
33 EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, wxNotebook::OnSelChange)
34
35 EVT_SIZE(wxNotebook::OnSize)
36 EVT_SET_FOCUS(wxNotebook::OnSetFocus)
37 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
38 END_EVENT_TABLE()
39
40 bool wxNotebook::Create( wxWindow *parent,
41 wxWindowID id,
42 const wxPoint& pos,
43 const wxSize& size,
44 long style,
45 const wxString& name )
46 {
47 DontCreatePeer();
48
49 if (! (style & wxBK_ALIGN_MASK))
50 style |= wxBK_TOP;
51
52 if ( !wxNotebookBase::Create( parent, id, pos, size, style, name ) )
53 return false;
54
55 SetPeer(wxWidgetImpl::CreateTabView(this,parent, id, pos, size, style, GetExtraStyle() ));
56
57 MacPostControlCreate( pos, size );
58
59 return true ;
60 }
61
62 // dtor
63 wxNotebook::~wxNotebook()
64 {
65 }
66
67 // ----------------------------------------------------------------------------
68 // wxNotebook accessors
69 // ----------------------------------------------------------------------------
70
71 void wxNotebook::SetPadding(const wxSize& WXUNUSED(padding))
72 {
73 // unsupported by OS
74 }
75
76 void wxNotebook::SetTabSize(const wxSize& WXUNUSED(sz))
77 {
78 // unsupported by OS
79 }
80
81 void wxNotebook::SetPageSize(const wxSize& size)
82 {
83 SetSize( CalcSizeFromPage( size ) );
84 }
85
86 wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
87 {
88 return DoGetSizeFromClientSize( sizePage );
89 }
90
91 int wxNotebook::DoSetSelection(size_t nPage, int flags)
92 {
93 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("DoSetSelection: invalid notebook page") );
94
95 if ( m_selection == wxNOT_FOUND || nPage != (size_t)m_selection )
96 {
97 if ( flags & SetSelection_SendEvent )
98 {
99 if ( !SendPageChangingEvent(nPage) )
100 {
101 // vetoed by program
102 return m_selection;
103 }
104 //else: program allows the page change
105
106 SendPageChangedEvent(m_selection, nPage);
107 }
108
109 ChangePage(m_selection, nPage);
110 }
111 //else: no change
112
113 return m_selection;
114 }
115
116 bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
117 {
118 wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("SetPageText: invalid notebook page") );
119
120 wxNotebookPage *page = m_pages[nPage];
121 page->SetLabel(wxStripMenuCodes(strText));
122 MacSetupTabs();
123
124 return true;
125 }
126
127 wxString wxNotebook::GetPageText(size_t nPage) const
128 {
129 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("GetPageText: invalid notebook page") );
130
131 wxNotebookPage *page = m_pages[nPage];
132
133 return page->GetLabel();
134 }
135
136 int wxNotebook::GetPageImage(size_t nPage) const
137 {
138 wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("GetPageImage: invalid notebook page") );
139
140 return m_images[nPage];
141 }
142
143 bool wxNotebook::SetPageImage(size_t nPage, int nImage)
144 {
145 wxCHECK_MSG( IS_VALID_PAGE(nPage), false,
146 wxT("SetPageImage: invalid notebook page") );
147 wxCHECK_MSG( HasImageList() && nImage < GetImageList()->GetImageCount(), false,
148 wxT("SetPageImage: invalid image index") );
149
150 if ( nImage != m_images[nPage] )
151 {
152 // if the item didn't have an icon before or, on the contrary, did have
153 // it but has lost it now, its size will change - but if the icon just
154 // changes, it won't
155 m_images[nPage] = nImage;
156
157 MacSetupTabs() ;
158 }
159
160 return true;
161 }
162
163 // ----------------------------------------------------------------------------
164 // wxNotebook operations
165 // ----------------------------------------------------------------------------
166
167 // remove one page from the notebook, without deleting the window
168 wxNotebookPage* wxNotebook::DoRemovePage(size_t nPage)
169 {
170 wxCHECK_MSG( IS_VALID_PAGE(nPage), NULL,
171 wxT("DoRemovePage: invalid notebook page") );
172
173 wxNotebookPage* page = m_pages[nPage] ;
174 m_pages.RemoveAt(nPage);
175 m_images.RemoveAt(nPage);
176
177 MacSetupTabs();
178
179 if ( m_selection >= (int)nPage )
180 {
181 if ( GetPageCount() == 0 )
182 m_selection = wxNOT_FOUND;
183 else
184 m_selection = m_selection ? m_selection - 1 : 0;
185
186 GetPeer()->SetValue( m_selection + 1 ) ;
187 }
188
189 if (m_selection >= 0)
190 m_pages[m_selection]->Show(true);
191
192 InvalidateBestSize();
193
194 return page;
195 }
196
197 // remove all pages
198 bool wxNotebook::DeleteAllPages()
199 {
200 WX_CLEAR_ARRAY(m_pages);
201 m_images.clear();
202 MacSetupTabs();
203 m_selection = wxNOT_FOUND ;
204 InvalidateBestSize();
205
206 return true;
207 }
208
209 // same as AddPage() but does it at given position
210 bool wxNotebook::InsertPage(size_t nPage,
211 wxNotebookPage *pPage,
212 const wxString& strText,
213 bool bSelect,
214 int imageId )
215 {
216 if ( !wxNotebookBase::InsertPage( nPage, pPage, strText, bSelect, imageId ) )
217 return false;
218
219 wxASSERT_MSG( pPage->GetParent() == this, wxT("notebook pages must have notebook as parent") );
220
221 // don't show pages by default (we'll need to adjust their size first)
222 pPage->Show( false ) ;
223
224 pPage->SetLabel( wxStripMenuCodes(strText) );
225
226 m_images.Insert( imageId, nPage );
227
228 MacSetupTabs();
229
230 wxRect rect = GetPageRect() ;
231 pPage->SetSize( rect );
232 if ( pPage->GetAutoLayout() )
233 pPage->Layout();
234
235 // now deal with the selection
236 // ---------------------------
237
238 // if the inserted page is before the selected one, we must update the
239 // index of the selected page
240
241 if ( int(nPage) <= m_selection )
242 {
243 m_selection++;
244
245 // while this still is the same page showing, we need to update the tabs
246 GetPeer()->SetValue( m_selection + 1 ) ;
247 }
248
249 DoSetSelectionAfterInsertion(nPage, bSelect);
250
251 InvalidateBestSize();
252
253 return true;
254 }
255
256 int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
257 {
258 return GetPeer()->TabHitTest(pt,flags);
259 }
260
261 // Added by Mark Newsam
262 // When a page is added or deleted to the notebook this function updates
263 // information held in the control so that it matches the order
264 // the user would expect.
265 //
266 void wxNotebook::MacSetupTabs()
267 {
268 GetPeer()->SetupTabs(*this);
269 Refresh();
270 }
271
272 wxRect wxNotebook::GetPageRect() const
273 {
274 wxSize size = GetClientSize() ;
275
276 return wxRect( 0 , 0 , size.x , size.y ) ;
277 }
278
279 // ----------------------------------------------------------------------------
280 // wxNotebook callbacks
281 // ----------------------------------------------------------------------------
282
283 // @@@ OnSize() is used for setting the font when it's called for the first
284 // time because doing it in ::Create() doesn't work (for unknown reasons)
285 void wxNotebook::OnSize(wxSizeEvent& event)
286 {
287 unsigned int nCount = m_pages.Count();
288 wxRect rect = GetPageRect() ;
289
290 for ( unsigned int nPage = 0; nPage < nCount; nPage++ )
291 {
292 wxNotebookPage *pPage = m_pages[nPage];
293 pPage->SetSize(rect, wxSIZE_FORCE_EVENT);
294 }
295
296 #if 0 // deactivate r65078 for the moment
297 // If the selected page is hidden at this point, the notebook
298 // has become visible for the first time after creation, and
299 // we postponed showing the page in ChangePage().
300 // So show the selected page now.
301 if ( m_selection != wxNOT_FOUND )
302 {
303 wxNotebookPage *pPage = m_pages[m_selection];
304 if ( !pPage->IsShown() )
305 {
306 pPage->Show( true );
307 pPage->SetFocus();
308 }
309 }
310 #endif
311
312 // Processing continues to next OnSize
313 event.Skip();
314 }
315
316 void wxNotebook::OnSelChange(wxBookCtrlEvent& event)
317 {
318 // is it our tab control?
319 if ( event.GetEventObject() == this )
320 ChangePage(event.GetOldSelection(), event.GetSelection());
321
322 // we want to give others a chance to process this message as well
323 event.Skip();
324 }
325
326 void wxNotebook::OnSetFocus(wxFocusEvent& event)
327 {
328 // set focus to the currently selected page if any
329 if ( m_selection != wxNOT_FOUND )
330 m_pages[m_selection]->SetFocus();
331
332 event.Skip();
333 }
334
335 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
336 {
337 if ( event.IsWindowChange() )
338 {
339 // change pages
340 AdvanceSelection( event.GetDirection() );
341 }
342 else
343 {
344 // we get this event in 2 cases
345 //
346 // a) one of our pages might have generated it because the user TABbed
347 // out from it in which case we should propagate the event upwards and
348 // our parent will take care of setting the focus to prev/next sibling
349 //
350 // or
351 //
352 // b) the parent panel wants to give the focus to us so that we
353 // forward it to our selected page. We can't deal with this in
354 // OnSetFocus() because we don't know which direction the focus came
355 // from in this case and so can't choose between setting the focus to
356 // first or last panel child
357 wxWindow *parent = GetParent();
358
359 // the cast is here to fix a GCC ICE
360 if ( ((wxWindow*)event.GetEventObject()) == parent )
361 {
362 // no, it doesn't come from child, case (b): forward to a page
363 if ( m_selection != wxNOT_FOUND )
364 {
365 // so that the page knows that the event comes from it's parent
366 // and is being propagated downwards
367 event.SetEventObject( this );
368
369 wxWindow *page = m_pages[m_selection];
370 if ( !page->HandleWindowEvent( event ) )
371 {
372 page->SetFocus();
373 }
374 //else: page manages focus inside it itself
375 }
376 else
377 {
378 // we have no pages - still have to give focus to _something_
379 SetFocus();
380 }
381 }
382 else
383 {
384 // it comes from our child, case (a), pass to the parent
385 if ( parent )
386 {
387 event.SetCurrentFocus( this );
388 parent->HandleWindowEvent( event );
389 }
390 }
391 }
392 }
393
394 // ----------------------------------------------------------------------------
395 // wxNotebook base class virtuals
396 // ----------------------------------------------------------------------------
397
398 #if wxUSE_CONSTRAINTS
399
400 // override these 2 functions to do nothing: everything is done in OnSize
401
402 void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
403 {
404 // don't set the sizes of the pages - their correct size is not yet known
405 wxControl::SetConstraintSizes( false );
406 }
407
408 bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
409 {
410 return true;
411 }
412
413 #endif // wxUSE_CONSTRAINTS
414
415 void wxNotebook::Command(wxCommandEvent& WXUNUSED(event))
416 {
417 wxFAIL_MSG(wxT("wxNotebook::Command not implemented"));
418 }
419
420 // ----------------------------------------------------------------------------
421 // wxNotebook helper functions
422 // ----------------------------------------------------------------------------
423
424 // hide the currently active panel and show the new one
425 void wxNotebook::ChangePage(int nOldSel, int nSel)
426 {
427 if (nOldSel == nSel)
428 return;
429
430 if ( nOldSel != wxNOT_FOUND )
431 m_pages[nOldSel]->Show( false );
432
433 if ( nSel != wxNOT_FOUND )
434 {
435 wxNotebookPage *pPage = m_pages[nSel];
436 #if 0 // deactivate r65078 for the moment
437 if ( IsShownOnScreen() )
438 {
439 pPage->Show( true );
440 pPage->SetFocus();
441 }
442 else
443 {
444 // Postpone Show() until the control is actually shown.
445 // Otherwise this forces the containing toplevel window
446 // to show, even if it's just being created and called
447 // AddPage() without intent to show the window yet.
448 // We Show() the selected page in our OnSize handler,
449 // unless it already is shown.
450 }
451 #else
452 pPage->Show( true );
453 pPage->SetFocus();
454 #endif
455 }
456
457 m_selection = nSel;
458 GetPeer()->SetValue( m_selection + 1 ) ;
459 }
460
461 bool wxNotebook::OSXHandleClicked( double WXUNUSED(timestampsec) )
462 {
463 bool status = false ;
464
465 SInt32 newSel = GetPeer()->GetValue() - 1 ;
466 if ( newSel != m_selection )
467 {
468 wxBookCtrlEvent changing(
469 wxEVT_NOTEBOOK_PAGE_CHANGING, m_windowId,
470 newSel , m_selection );
471 changing.SetEventObject( this );
472 HandleWindowEvent( changing );
473
474 if ( changing.IsAllowed() )
475 {
476 wxBookCtrlEvent event(
477 wxEVT_NOTEBOOK_PAGE_CHANGED, m_windowId,
478 newSel, m_selection );
479 event.SetEventObject( this );
480 HandleWindowEvent( event );
481
482 m_selection = newSel;
483 }
484 else
485 {
486 GetPeer()->SetValue( m_selection + 1 ) ;
487 }
488
489 status = true ;
490 }
491
492 return status ;
493 }
494
495 #endif