]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/frame.cpp
5a95ac9097692e320a1deb4e203e48418191feea
[wxWidgets.git] / src / mac / carbon / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: frame.cpp
3 // Purpose: wxFrame
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "frame.h"
14 #endif
15
16 #include "wx/frame.h"
17 #include "wx/statusbr.h"
18 #include "wx/toolbar.h"
19 #include "wx/menuitem.h"
20 #include "wx/menu.h"
21 #include "wx/dcclient.h"
22 #include "wx/dialog.h"
23 #include "wx/settings.h"
24 #include "wx/app.h"
25
26 #include <wx/mac/uma.h>
27
28 extern wxList wxModelessWindows;
29 extern wxList wxPendingDelete;
30
31 #if !USE_SHARED_LIBRARY
32 BEGIN_EVENT_TABLE(wxFrame, wxWindow)
33 EVT_SIZE(wxFrame::OnSize)
34 EVT_ACTIVATE(wxFrame::OnActivate)
35 EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight)
36 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged)
37 EVT_IDLE(wxFrame::OnIdle)
38 EVT_CLOSE(wxFrame::OnCloseWindow)
39 END_EVENT_TABLE()
40
41 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxWindow)
42 #endif
43
44 #if wxUSE_NATIVE_STATUSBAR
45 bool wxFrame::m_useNativeStatusBar = TRUE;
46 #else
47 bool wxFrame::m_useNativeStatusBar = FALSE;
48 #endif
49
50 wxFrame::wxFrame()
51 {
52 #if wxUSE_TOOLBAR
53 m_frameToolBar = NULL ;
54 #endif
55 m_macShown = false ;
56 // in order to be able to give size events on show
57 m_frameMenuBar = NULL;
58 m_frameStatusBar = NULL;
59
60 m_windowParent = NULL;
61 m_iconized = FALSE;
62 }
63
64 bool wxFrame::Create(wxWindow *parent,
65 wxWindowID id,
66 const wxString& title,
67 const wxPoint& pos,
68 const wxSize& size,
69 long style,
70 const wxString& name)
71 {
72 if (!parent)
73 wxTopLevelWindows.Append(this);
74
75 SetName(name);
76 m_windowStyle = style;
77 m_frameMenuBar = NULL;
78
79 #if wxUSE_TOOLBAR
80 m_frameToolBar = NULL ;
81 #endif
82 m_frameStatusBar = NULL;
83
84 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
85
86 if ( id > -1 )
87 m_windowId = id;
88 else
89 m_windowId = (int)NewControlId();
90
91 if (parent) parent->AddChild(this);
92
93 wxModelessWindows.Append(this);
94
95 // create frame.
96
97 Rect theBoundsRect;
98
99 m_x = (int)pos.x;
100 m_y = (int)pos.y;
101 if ( m_y < 50 )
102 m_y = 50 ;
103 if ( m_x < 20 )
104 m_x = 20 ;
105
106 m_width = size.x;
107 if (m_width == -1)
108 m_width = 20;
109 m_height = size.y;
110 if (m_height == -1)
111 m_height = 20;
112
113 m_macWindowData = new MacWindowData() ;
114
115 ::SetRect(&theBoundsRect, m_x, m_y, m_x + m_width, m_y + m_height);
116
117 WindowClass wclass = kDocumentWindowClass ;
118 WindowAttributes attr = kWindowNoAttributes ;
119
120 if ( ( m_windowStyle & wxMINIMIZE_BOX ) || ( m_windowStyle & wxMAXIMIZE_BOX ) )
121 {
122 attr |= kWindowFullZoomAttribute ;
123 attr |= kWindowResizableAttribute ;
124 }
125 if ( m_windowStyle & wxSTAY_ON_TOP )
126 {
127 wclass = kFloatingWindowClass ;
128
129 // if ( m_windowStyle & wxCAPTION )
130 // attr |= kHasPaletteTitlebarMask ;
131 }
132 else
133 {
134 }
135 if ( m_windowStyle & wxSYSTEM_MENU )
136 {
137 attr |= kWindowCloseBoxAttribute ;
138 }
139 UMACreateNewWindow( wclass , attr , &theBoundsRect , &m_macWindowData->m_macWindow ) ;
140 wxAssociateWinWithMacWindow( m_macWindowData->m_macWindow , this ) ;
141 wxString label ;
142 if( wxApp::s_macDefaultEncodingIsPC )
143 label = wxMacMakeMacStringFromPC( title ) ;
144 else
145 label = title ;
146 UMASetWTitleC( m_macWindowData->m_macWindow , label ) ;
147 UMACreateRootControl( m_macWindowData->m_macWindow , &m_macWindowData->m_macRootControl ) ;
148 m_macWindowData->m_macWindowBackgroundTheme = kThemeBrushDocumentWindowBackground ;
149 m_macWindowData->m_macFocus = NULL ;
150 m_macShown = false ;
151 return TRUE;
152 }
153
154 wxFrame::~wxFrame()
155 {
156 wxTopLevelWindows.DeleteObject(this);
157
158 if (m_frameStatusBar)
159 delete m_frameStatusBar;
160 if (m_frameMenuBar)
161 delete m_frameMenuBar;
162
163 /* Check if it's the last top-level window */
164
165 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
166 {
167 wxTheApp->SetTopWindow(NULL);
168
169 if (wxTheApp->GetExitOnFrameDelete())
170 {
171 wxTheApp->ExitMainLoop() ;
172 }
173 }
174
175 wxModelessWindows.DeleteObject(this);
176 }
177
178
179 void wxFrame::Iconize(bool iconize)
180 {
181 // TODO
182 }
183
184 // Equivalent to maximize/restore in Windows
185 void wxFrame::Maximize(bool maximize)
186 {
187 // TODO
188 }
189
190 bool wxFrame::IsIconized() const
191 {
192 // TODO
193 return FALSE;
194 }
195
196 // Is the frame maximized?
197 bool wxFrame::IsMaximized(void) const
198 {
199 // TODO
200 return FALSE;
201 }
202
203 void wxFrame::SetIcon(const wxIcon& icon)
204 {
205 m_icon = icon;
206 // TODO
207 }
208
209 wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
210 const wxString& name)
211 {
212 wxStatusBar *statusBar = NULL;
213
214 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 17),
215 style, name);
216
217 // Set the height according to the font and the border size
218 // we shouldn't do this on the mac, because we have to fit the grow box
219 /*
220 wxClientDC dc(statusBar);
221 dc.SetFont(statusBar->GetFont());
222
223 long x, y;
224 dc.GetTextExtent("X", &x, &y);
225
226 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
227
228 statusBar->SetSize(-1, -1, 100, height);
229
230 */
231
232 statusBar->SetFieldsCount(number);
233 return statusBar;
234 }
235
236 wxStatusBar* wxFrame::CreateStatusBar(int number, long style, wxWindowID id,
237 const wxString& name)
238 {
239 // Calling CreateStatusBar twice is an error.
240 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE,
241 "recreating status bar in wxFrame" );
242
243 m_frameStatusBar = OnCreateStatusBar(number, style, id,
244 name);
245 if ( m_frameStatusBar )
246 {
247 PositionStatusBar();
248 return m_frameStatusBar;
249 }
250 else
251 return NULL;
252 }
253
254 void wxFrame::SetStatusText(const wxString& text, int number)
255 {
256 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set text for" );
257
258 m_frameStatusBar->SetStatusText(text, number);
259 }
260
261 void wxFrame::SetStatusWidths(int n, const int widths_field[])
262 {
263 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set widths for" );
264
265 m_frameStatusBar->SetStatusWidths(n, widths_field);
266 PositionStatusBar();
267 }
268
269 void wxFrame::PositionStatusBar()
270 {
271 if (m_frameStatusBar )
272 {
273 int w, h;
274 GetClientSize(&w, &h);
275 int sw, sh;
276 m_frameStatusBar->GetSize(&sw, &sh);
277
278 // Since we wish the status bar to be directly under the client area,
279 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
280 m_frameStatusBar->SetSize(0, h, w, sh);
281 }
282 }
283
284 void wxFrame::SetMenuBar(wxMenuBar *menuBar)
285 {
286 if (!menuBar)
287 {
288 m_frameMenuBar = NULL;
289 return;
290 }
291
292 m_frameMenuBar = menuBar;
293 // TODO : we move this into the app code
294 m_frameMenuBar->MacInstallMenuBar() ;
295 }
296
297 void wxFrame::Fit()
298 {
299 // Work out max. size
300 wxNode *node = GetChildren().First();
301 int max_width = 0;
302 int max_height = 0;
303 while (node)
304 {
305 // Find a child that's a subwindow, but not a dialog box.
306 wxWindow *win = (wxWindow *)node->Data();
307
308 if (!win->IsKindOf(CLASSINFO(wxFrame)) &&
309 !win->IsKindOf(CLASSINFO(wxDialog)))
310 {
311 int width, height;
312 int x, y;
313 win->GetSize(&width, &height);
314 win->GetPosition(&x, &y);
315
316 if ((x + width) > max_width)
317 max_width = x + width;
318 if ((y + height) > max_height)
319 max_height = y + height;
320 }
321 node = node->Next();
322 }
323 SetClientSize(max_width, max_height);
324 }
325
326 // Responds to colour changes, and passes event on to children.
327 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
328 {
329 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
330 Refresh();
331
332 if ( m_frameStatusBar )
333 {
334 wxSysColourChangedEvent event2;
335 event2.SetEventObject( m_frameStatusBar );
336 m_frameStatusBar->ProcessEvent(event2);
337 }
338
339 // Propagate the event to the non-top-level children
340 wxWindow::OnSysColourChanged(event);
341 }
342
343 // Default resizing behaviour - if only ONE subwindow,
344 // resize to client rectangle size
345 void wxFrame::OnSize(wxSizeEvent& event)
346 {
347 // if we're using constraints - do use them
348 #if wxUSE_CONSTRAINTS
349 if ( GetAutoLayout() ) {
350 Layout();
351 return;
352 }
353 #endif
354
355 // do we have _exactly_ one child?
356 wxWindow *child = NULL;
357 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
358 {
359 wxWindow *win = (wxWindow *)node->Data();
360 if ( !win->IsKindOf(CLASSINFO(wxFrame)) &&
361 !win->IsKindOf(CLASSINFO(wxDialog)) &&
362 (win != GetStatusBar())
363 #if wxUSE_TOOLBAR
364 &&
365 (win != GetToolBar())
366 #endif
367 )
368 {
369 if ( child )
370 return; // it's our second subwindow - nothing to do
371 child = win;
372 }
373 }
374
375 if ( child ) {
376 // we have exactly one child - set it's size to fill the whole frame
377 int clientW, clientH;
378 GetClientSize(&clientW, &clientH);
379
380 int x = 0;
381 int y = 0;
382
383 child->SetSize(x, y, clientW, clientH);
384 }
385 }
386
387 // Default activation behaviour - set the focus for the first child
388 // subwindow found.
389 void wxFrame::OnActivate(wxActivateEvent& event)
390 {
391 for(wxNode *node = GetChildren().First(); node; node = node->Next())
392 {
393 // Find a child that's a subwindow, but not a dialog box.
394 wxWindow *child = (wxWindow *)node->Data();
395 if (!child->IsKindOf(CLASSINFO(wxFrame)) &&
396 !child->IsKindOf(CLASSINFO(wxDialog)))
397 {
398 child->SetFocus();
399 return;
400 }
401 }
402 }
403
404 // The default implementation for the close window event.
405 void wxFrame::OnCloseWindow(wxCloseEvent& event)
406 {
407 this->Destroy();
408 }
409
410 // Destroy the window (delayed, if a managed window)
411 bool wxFrame::Destroy()
412 {
413 if (!wxPendingDelete.Member(this))
414 wxPendingDelete.Append(this);
415 return TRUE;
416 }
417
418 // Default menu selection behaviour - display a help string
419 void wxFrame::OnMenuHighlight(wxMenuEvent& event)
420 {
421 if (GetStatusBar())
422 {
423 if (event.GetMenuId() == -1)
424 SetStatusText("");
425 else
426 {
427 wxMenuBar *menuBar = GetMenuBar();
428 if (menuBar)
429 {
430 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
431 if (helpString != "")
432 SetStatusText(helpString);
433 }
434 }
435 }
436 }
437
438 wxMenuBar *wxFrame::GetMenuBar() const
439 {
440 return m_frameMenuBar;
441 }
442
443
444 // Call this to simulate a menu command
445 void wxFrame::Command(int id)
446 {
447 ProcessCommand(id);
448 }
449
450 void wxFrame::ProcessCommand(int id)
451 {
452 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
453 commandEvent.SetInt( id );
454 commandEvent.SetEventObject( this );
455
456 wxMenuBar *bar = GetMenuBar() ;
457 if (!bar)
458 return;
459
460 /* TODO: check the menu item if required
461 wxMenuItem *item = bar->FindItemForId(id) ;
462 if (item && item->IsCheckable())
463 {
464 bar->Check(id,!bar->Checked(id)) ;
465 }
466 */
467
468 GetEventHandler()->ProcessEvent(commandEvent);
469 }
470
471 // Checks if there is a toolbar, and returns the first free client position
472 wxPoint wxFrame::GetClientAreaOrigin() const
473 {
474 wxPoint pt(0, 0);
475 #if wxUSE_TOOLBAR
476 if (GetToolBar())
477 {
478 int w, h;
479 GetToolBar()->GetSize(& w, & h);
480
481 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
482 {
483 pt.x += w;
484 }
485 else
486 {
487 pt.y += h;
488 }
489 }
490 #endif
491 return pt;
492 }
493
494 void wxFrame::GetClientSize(int *x, int *y) const
495 {
496 wxWindow::GetClientSize( x , y ) ;
497
498 if ( GetStatusBar() )
499 {
500 int statusX, statusY;
501 GetStatusBar()->GetClientSize(&statusX, &statusY);
502 *y -= statusY;
503 }
504
505 wxPoint pt(GetClientAreaOrigin());
506 *y -= pt.y;
507 *x -= pt.x;
508 }
509
510 void wxFrame::DoSetClientSize(int clientwidth, int clientheight)
511 {
512 int currentclientwidth , currentclientheight ;
513 int currentwidth , currentheight ;
514
515 GetClientSize( &currentclientwidth , &currentclientheight ) ;
516 GetSize( &currentwidth , &currentheight ) ;
517
518 // find the current client size
519
520 // Find the difference between the entire window (title bar and all)
521 // and the client area; add this to the new client size to move the
522 // window
523
524 DoSetSize( -1 , -1 , currentwidth + clientwidth - currentclientwidth ,
525 currentheight + clientheight - currentclientheight , wxSIZE_USE_EXISTING ) ;
526 }
527
528
529 #if wxUSE_TOOLBAR
530 wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name)
531 {
532 wxCHECK_MSG( m_frameToolBar == NULL, FALSE,
533 "recreating toolbar in wxFrame" );
534
535 wxToolBar* toolBar = OnCreateToolBar(style, id, name);
536 if (toolBar)
537 {
538 SetToolBar(toolBar);
539 PositionToolBar();
540 return toolBar;
541 }
542 else
543 {
544 return NULL;
545 }
546 }
547
548 wxToolBar* wxFrame::OnCreateToolBar(long style, wxWindowID id, const wxString& name)
549 {
550 return new wxToolBar(this, id, wxDefaultPosition, wxDefaultSize, style, name);
551 }
552
553 void wxFrame::PositionToolBar()
554 {
555 int cw, ch;
556
557 // TODO: we actually need to use the low-level client size, before
558 // the toolbar/status bar were added.
559 // So DEFINITELY replace the line below with something appropriate.
560
561 // GetClientSize(& cw, &ch);
562
563 cw = m_width ;
564 ch = m_height ;
565
566 if ( GetStatusBar() )
567 {
568 int statusX, statusY;
569 GetStatusBar()->GetClientSize(&statusX, &statusY);
570 ch -= statusY;
571 }
572
573 if (GetToolBar())
574 {
575 int tw, th;
576 GetToolBar()->GetSize(& tw, & th);
577
578 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
579 {
580 // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
581 // means, pretend we don't have toolbar/status bar, so we
582 // have the original client size.
583 GetToolBar()->SetSize(0, 0, tw, ch, wxSIZE_NO_ADJUSTMENTS);
584 }
585 else
586 {
587 // Use the 'real' position
588 GetToolBar()->SetSize(0, 0, cw, th, wxSIZE_NO_ADJUSTMENTS);
589 }
590 }
591 }
592 #endif