backported crash fix for wxFrame::Iconize() from 2.2
[wxWidgets.git] / src / mac / notebmac.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: notebook.cpp
3 // Purpose: implementation of wxNotebook
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
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/mac/uma.h>
28 // ----------------------------------------------------------------------------
29 // macros
30 // ----------------------------------------------------------------------------
31
32 // check that the page index is valid
33 #define IS_VALID_PAGE(nPage) (((nPage) >= 0) && ((nPage) < GetPageCount()))
34
35 #ifdef __WXMAC_X__
36 // I got these values for Mac OS X from the Appearance mgr docs. (Mark Newsam)
37 const short kwxMacTabLeftMargin = 20 ;
38 const short kwxMacTabTopMargin = 38 ;
39 const short kwxMacTabRightMargin = 20 ;
40 const short kwxMacTabBottomMargin = 12 ;
41 #else
42 const short kwxMacTabLeftMargin = 16 ;
43 const short kwxMacTabTopMargin = 30 ;
44 const short kwxMacTabRightMargin = 16 ;
45 const short kwxMacTabBottomMargin = 16 ;
46 #endif
47
48 // ----------------------------------------------------------------------------
49 // event table
50 // ----------------------------------------------------------------------------
51
52 #if !USE_SHARED_LIBRARIES
53 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
54 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
55
56 BEGIN_EVENT_TABLE(wxNotebook, wxControl)
57 EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
58
59 EVT_SIZE(wxNotebook::OnSize)
60 EVT_SET_FOCUS(wxNotebook::OnSetFocus)
61 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
62 END_EVENT_TABLE()
63
64 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
65 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent)
66 #endif
67
68 // ============================================================================
69 // implementation
70 // ============================================================================
71
72 // ----------------------------------------------------------------------------
73 // wxNotebook construction
74 // ----------------------------------------------------------------------------
75
76 // common part of all ctors
77 void wxNotebook::Init()
78 {
79 #ifdef __WXMAC_X__
80 m_macHorizontalBorder = 7;
81 m_macVerticalBorder = 8;
82 #endif
83 m_nSelection = -1;
84 }
85
86 // default for dynamic class
87 wxNotebook::wxNotebook()
88 {
89 Init();
90 }
91
92 // the same arguments as for wxControl
93 wxNotebook::wxNotebook(wxWindow *parent,
94 wxWindowID id,
95 const wxPoint& pos,
96 const wxSize& size,
97 long style,
98 const wxString& name)
99 {
100 Init();
101
102 Create(parent, id, pos, size, style, name);
103 }
104
105 // Create() function
106 bool wxNotebook::Create(wxWindow *parent,
107 wxWindowID id,
108 const wxPoint& pos,
109 const wxSize& size,
110 long style,
111 const wxString& name)
112 {
113 Rect bounds ;
114 Str255 title ;
115
116 MacPreControlCreate( parent , id , "" , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ;
117
118 m_macControl = UMANewControl( parent->GetMacRootWindow() , &bounds , title , false , 0 , 0 , 1,
119 kControlTabSmallProc , (long) this ) ;
120
121 MacPostControlCreate() ;
122 return TRUE ;
123 }
124
125 // dtor
126 wxNotebook::~wxNotebook()
127 {
128 m_macControl = NULL ;
129 }
130
131 // ----------------------------------------------------------------------------
132 // wxNotebook accessors
133 // ----------------------------------------------------------------------------
134
135 void wxNotebook::SetPadding(const wxSize& padding)
136 {
137 }
138
139 void wxNotebook::SetTabSize(const wxSize& sz)
140 {
141 }
142
143 void wxNotebook::SetPageSize(const wxSize& size)
144 {
145 }
146
147 int wxNotebook::SetSelection(int nPage)
148 {
149 wxASSERT( IS_VALID_PAGE(nPage) );
150
151 ChangePage(m_nSelection, nPage);
152 SetControlValue( m_macControl , m_nSelection + 1 ) ;
153
154 return m_nSelection;
155 }
156
157 bool wxNotebook::SetPageText(int nPage, const wxString& strText)
158 {
159 wxASSERT( IS_VALID_PAGE(nPage) );
160
161 wxNotebookPage *page = m_pages[nPage];
162 page->SetLabel(strText);
163 MacSetupTabs();
164
165 return true;
166 }
167
168 wxString wxNotebook::GetPageText(int nPage) const
169 {
170 wxASSERT( IS_VALID_PAGE(nPage) );
171
172 wxNotebookPage *page = m_pages[nPage];
173 return page->GetLabel();
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 // ----------------------------------------------------------------------------
193 // wxNotebook operations
194 // ----------------------------------------------------------------------------
195
196 // remove one page from the notebook, without deleting the window
197 wxNotebookPage* wxNotebook::DoRemovePage(int nPage)
198 {
199 wxCHECK( IS_VALID_PAGE(nPage), NULL );
200 wxNotebookPage* page = m_pages[nPage] ;
201 m_pages.Remove(nPage);
202
203 MacSetupTabs();
204
205 if(m_nSelection >= GetPageCount()) {
206 m_nSelection = GetPageCount() - 1;
207 }
208 if(m_nSelection >= 0) {
209 m_pages[m_nSelection]->Show(true);
210 }
211 return page;
212 }
213
214 // remove all pages
215 bool wxNotebook::DeleteAllPages()
216 {
217 // TODO: delete native widget pages
218
219 WX_CLEAR_ARRAY(m_pages) ;
220 MacSetupTabs();
221
222 return TRUE;
223 }
224
225
226 // same as AddPage() but does it at given position
227 bool wxNotebook::InsertPage(int nPage,
228 wxNotebookPage *pPage,
229 const wxString& strText,
230 bool bSelect,
231 int imageId)
232 {
233 wxASSERT( pPage != NULL );
234 wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), FALSE );
235
236 pPage->SetLabel(strText);
237
238 // save the pointer to the page
239 m_pages.Insert(pPage, nPage);
240
241 MacSetupTabs();
242
243 if ( bSelect ) {
244 m_nSelection = nPage;
245 }
246 else if ( m_nSelection == -1 ) {
247 m_nSelection = 0;
248 }
249 else if (m_nSelection >= nPage) {
250 m_nSelection++;
251 }
252 // don't show pages by default (we'll need to adjust their size first)
253 pPage->Show( false ) ;
254
255 int h, w;
256 GetSize(&w, &h);
257 pPage->SetSize(kwxMacTabLeftMargin, kwxMacTabTopMargin,
258 w - kwxMacTabLeftMargin - kwxMacTabRightMargin,
259 h - kwxMacTabTopMargin - kwxMacTabBottomMargin );
260 if ( pPage->GetAutoLayout() ) {
261 pPage->Layout();
262 }
263
264 return true;
265 }
266
267 /* Added by Mark Newsam
268 * When a page is added or deleted to the notebook this function updates
269 * information held in the m_macControl so that it matches the order
270 * the user would expect.
271 */
272 void wxNotebook::MacSetupTabs()
273 {
274 SetControlMaximum( m_macControl , GetPageCount() ) ;
275
276 wxNotebookPage *page;
277 ControlTabInfoRec info;
278 Boolean enabled = true;
279 for(int ii = 0; ii < GetPageCount(); ii++)
280 {
281 page = m_pages[ii];
282 info.version = 0;
283 info.iconSuiteID = 0;
284 #if TARGET_CARBON
285 c2pstrcpy( (StringPtr) info.name , page->GetLabel() ) ;
286 #else
287 strcpy( (char *) info.name , page->GetLabel() ) ;
288 c2pstr( (char *) info.name ) ;
289 #endif
290 SetControlData( m_macControl, ii+1, kControlTabInfoTag,
291 sizeof( ControlTabInfoRec) , (char*) &info ) ;
292 SetControlData( m_macControl, ii+1, kControlTabEnabledFlagTag,
293 sizeof( Boolean ), (Ptr)&enabled );
294 }
295 Rect bounds;
296 GetControlBounds(m_macControl, &bounds);
297 InvalWindowRect(GetMacRootWindow(), &bounds);
298 }
299
300 // ----------------------------------------------------------------------------
301 // wxNotebook callbacks
302 // ----------------------------------------------------------------------------
303
304 // @@@ OnSize() is used for setting the font when it's called for the first
305 // time because doing it in ::Create() doesn't work (for unknown reasons)
306 void wxNotebook::OnSize(wxSizeEvent& event)
307 {
308 static bool s_bFirstTime = TRUE;
309 if ( s_bFirstTime ) {
310 // TODO: any first-time-size processing.
311 s_bFirstTime = FALSE;
312 }
313
314 // TODO: all this may or may not be necessary for your platform
315
316 // emulate page change (it's esp. important to do it first time because
317 // otherwise our page would stay invisible)
318 int nSel = m_nSelection;
319 m_nSelection = -1;
320 SetSelection(nSel);
321
322 // fit the notebook page to the tab control's display area
323 int w, h;
324 GetSize(&w, &h);
325
326 unsigned int nCount = m_pages.Count();
327 for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) {
328 wxNotebookPage *pPage = m_pages[nPage];
329 pPage->SetSize(kwxMacTabLeftMargin, kwxMacTabTopMargin,
330 w - kwxMacTabLeftMargin - kwxMacTabRightMargin,
331 h - kwxMacTabTopMargin - kwxMacTabBottomMargin );
332 if ( pPage->GetAutoLayout() ) {
333 pPage->Layout();
334 }
335 }
336
337 // Processing continues to next OnSize
338 event.Skip();
339 }
340
341 void wxNotebook::OnSelChange(wxNotebookEvent& event)
342 {
343 // is it our tab control?
344 if ( event.GetEventObject() == this )
345 ChangePage(event.GetOldSelection(), event.GetSelection());
346
347 // we want to give others a chance to process this message as well
348 event.Skip();
349 }
350
351 void wxNotebook::OnSetFocus(wxFocusEvent& event)
352 {
353 // set focus to the currently selected page if any
354 if ( m_nSelection != -1 )
355 m_pages[m_nSelection]->SetFocus();
356
357 event.Skip();
358 }
359
360 void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
361 {
362 if ( event.IsWindowChange() ) {
363 // change pages
364 AdvanceSelection(event.GetDirection());
365 }
366 else {
367 // pass to the parent
368 if ( GetParent() ) {
369 event.SetCurrentFocus(this);
370 GetParent()->ProcessEvent(event);
371 }
372 }
373 }
374
375 // ----------------------------------------------------------------------------
376 // wxNotebook base class virtuals
377 // ----------------------------------------------------------------------------
378
379 // override these 2 functions to do nothing: everything is done in OnSize
380
381 void wxNotebook::SetConstraintSizes(bool /* recurse */)
382 {
383 // don't set the sizes of the pages - their correct size is not yet known
384 wxControl::SetConstraintSizes(FALSE);
385 }
386
387 bool wxNotebook::DoPhase(int /* nPhase */)
388 {
389 return TRUE;
390 }
391
392 void wxNotebook::Command(wxCommandEvent& event)
393 {
394 wxFAIL_MSG("wxNotebook::Command not implemented");
395 }
396
397 // ----------------------------------------------------------------------------
398 // wxNotebook helper functions
399 // ----------------------------------------------------------------------------
400
401 // hide the currently active panel and show the new one
402 void wxNotebook::ChangePage(int nOldSel, int nSel)
403 {
404 // it's not an error (the message may be generated by the tab control itself)
405 // and it may happen - just do nothing
406 if ( nSel == nOldSel )
407 {
408 wxNotebookPage *pPage = m_pages[nSel];
409 pPage->Show(FALSE);
410 pPage->Show(TRUE);
411 pPage->SetFocus();
412 return;
413 }
414
415 // Hide previous page
416 if ( nOldSel != -1 ) {
417 m_pages[nOldSel]->Show(FALSE);
418 }
419
420 wxNotebookPage *pPage = m_pages[nSel];
421 pPage->Show(TRUE);
422 pPage->SetFocus();
423
424 m_nSelection = nSel;
425 }
426
427 void wxNotebook::MacHandleControlClick( ControlHandle control , SInt16 controlpart )
428 {
429 wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_windowId , ::GetControlValue(m_macControl) - 1, m_nSelection);
430 event.SetEventObject(this);
431
432 ProcessEvent(event);
433 }
434