]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/frame.cpp
wxMSW update for CW, wxMac updated
[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
56 // in order to be able to give size events on show
57 m_frameMenuBar = NULL;
58 m_frameStatusBar = NULL;
59 m_iconized = FALSE;
60 m_isShown = FALSE;
61 }
62
63 bool wxFrame::Create(wxWindow *parent,
64 wxWindowID id,
65 const wxString& title,
66 const wxPoint& pos,
67 const wxSize& size,
68 long style,
69 const wxString& name)
70 {
71 if (!parent)
72 wxTopLevelWindows.Append(this);
73
74 SetName(name);
75 m_windowStyle = style;
76 m_frameMenuBar = NULL;
77 m_isShown = FALSE;
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 return TRUE;
151 }
152
153 wxFrame::~wxFrame()
154 {
155 wxTopLevelWindows.DeleteObject(this);
156
157 if (m_frameStatusBar)
158 delete m_frameStatusBar;
159 if (m_frameMenuBar)
160 delete m_frameMenuBar;
161
162 /* Check if it's the last top-level window */
163
164 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
165 {
166 wxTheApp->SetTopWindow(NULL);
167
168 if (wxTheApp->GetExitOnFrameDelete())
169 {
170 wxTheApp->ExitMainLoop() ;
171 }
172 }
173
174 wxModelessWindows.DeleteObject(this);
175 }
176
177
178 void wxFrame::Iconize(bool iconize)
179 {
180 // TODO
181 }
182
183 // Equivalent to maximize/restore in Windows
184 void wxFrame::Maximize(bool maximize)
185 {
186 // TODO
187 }
188
189 bool wxFrame::IsIconized() const
190 {
191 // TODO
192 return FALSE;
193 }
194
195 // Is the frame maximized?
196 bool wxFrame::IsMaximized(void) const
197 {
198 // TODO
199 return FALSE;
200 }
201
202 void wxFrame::SetIcon(const wxIcon& icon)
203 {
204 m_icon = icon;
205 // TODO
206 }
207
208 wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
209 const wxString& name)
210 {
211 wxStatusBar *statusBar = NULL;
212
213 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 17),
214 style, name);
215
216 // Set the height according to the font and the border size
217 // we shouldn't do this on the mac, because we have to fit the grow box
218 /*
219 wxClientDC dc(statusBar);
220 dc.SetFont(statusBar->GetFont());
221
222 long x, y;
223 dc.GetTextExtent("X", &x, &y);
224
225 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
226
227 statusBar->SetSize(-1, -1, 100, height);
228
229 */
230
231 statusBar->SetFieldsCount(number);
232 return statusBar;
233 }
234
235 wxStatusBar* wxFrame::CreateStatusBar(int number, long style, wxWindowID id,
236 const wxString& name)
237 {
238 // Calling CreateStatusBar twice is an error.
239 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE,
240 "recreating status bar in wxFrame" );
241
242 m_frameStatusBar = OnCreateStatusBar(number, style, id,
243 name);
244 if ( m_frameStatusBar )
245 {
246 PositionStatusBar();
247 return m_frameStatusBar;
248 }
249 else
250 return NULL;
251 }
252
253 void wxFrame::SetStatusText(const wxString& text, int number)
254 {
255 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set text for" );
256
257 m_frameStatusBar->SetStatusText(text, number);
258 }
259
260 void wxFrame::SetStatusWidths(int n, const int widths_field[])
261 {
262 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set widths for" );
263
264 m_frameStatusBar->SetStatusWidths(n, widths_field);
265 PositionStatusBar();
266 }
267
268 void wxFrame::PositionStatusBar()
269 {
270 if (m_frameStatusBar )
271 {
272 int w, h;
273 GetClientSize(&w, &h);
274 int sw, sh;
275 m_frameStatusBar->GetSize(&sw, &sh);
276
277 // Since we wish the status bar to be directly under the client area,
278 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
279 m_frameStatusBar->SetSize(0, h, w, sh);
280 }
281 }
282
283 void wxFrame::SetMenuBar(wxMenuBar *menuBar)
284 {
285 if (!menuBar)
286 {
287 m_frameMenuBar = NULL;
288 return;
289 }
290
291 m_frameMenuBar = menuBar;
292 // TODO : we move this into the app code
293 m_frameMenuBar->MacInstallMenuBar() ;
294 }
295
296 void wxFrame::Fit()
297 {
298 // Work out max. size
299 wxNode *node = GetChildren().First();
300 int max_width = 0;
301 int max_height = 0;
302 while (node)
303 {
304 // Find a child that's a subwindow, but not a dialog box.
305 wxWindow *win = (wxWindow *)node->Data();
306
307 if (!win->IsKindOf(CLASSINFO(wxFrame)) &&
308 !win->IsKindOf(CLASSINFO(wxDialog)))
309 {
310 int width, height;
311 int x, y;
312 win->GetSize(&width, &height);
313 win->GetPosition(&x, &y);
314
315 if ((x + width) > max_width)
316 max_width = x + width;
317 if ((y + height) > max_height)
318 max_height = y + height;
319 }
320 node = node->Next();
321 }
322 SetClientSize(max_width, max_height);
323 }
324
325 // Responds to colour changes, and passes event on to children.
326 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
327 {
328 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
329 Refresh();
330
331 if ( m_frameStatusBar )
332 {
333 wxSysColourChangedEvent event2;
334 event2.SetEventObject( m_frameStatusBar );
335 m_frameStatusBar->ProcessEvent(event2);
336 }
337
338 // Propagate the event to the non-top-level children
339 wxWindow::OnSysColourChanged(event);
340 }
341
342 // Default resizing behaviour - if only ONE subwindow,
343 // resize to client rectangle size
344 void wxFrame::OnIdle(wxIdleEvent& WXUNUSED(event) )
345 {
346 DoMenuUpdates();
347 }
348
349
350 // update all menus
351 void wxFrame::DoMenuUpdates()
352 {
353 wxMenuBar* bar = GetMenuBar();
354
355 if ( bar != NULL )
356 {
357 int nCount = bar->GetMenuCount();
358 for (int n = 0; n < nCount; n++)
359 DoMenuUpdates(bar->GetMenu(n), (wxWindow*) NULL);
360 }
361 }
362
363 // update a menu and all submenus recursively
364 void wxFrame::DoMenuUpdates(wxMenu* menu, wxWindow* WXUNUSED(focusWin))
365 {
366 wxEvtHandler* evtHandler = GetEventHandler();
367 wxMenuItemList::Node* node = menu->GetMenuItems().GetFirst();
368 while (node)
369 {
370 wxMenuItem* item = node->GetData();
371 if ( !item->IsSeparator() )
372 {
373 wxWindowID id = item->GetId();
374 wxUpdateUIEvent event(id);
375 event.SetEventObject( this );
376
377 if (evtHandler->ProcessEvent(event))
378 {
379 if (event.GetSetText())
380 menu->SetLabel(id, event.GetText());
381 if (event.GetSetChecked())
382 menu->Check(id, event.GetChecked());
383 if (event.GetSetEnabled())
384 menu->Enable(id, event.GetEnabled());
385 }
386
387 if (item->GetSubMenu())
388 DoMenuUpdates(item->GetSubMenu(), (wxWindow*) NULL);
389 }
390 node = node->GetNext();
391 }
392 }
393
394 void wxFrame::OnSize(wxSizeEvent& event)
395 {
396 // if we're using constraints - do use them
397 #if wxUSE_CONSTRAINTS
398 if ( GetAutoLayout() ) {
399 Layout();
400 return;
401 }
402 #endif
403
404 // do we have _exactly_ one child?
405 wxWindow *child = NULL;
406 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
407 {
408 wxWindow *win = (wxWindow *)node->Data();
409 if ( !win->IsKindOf(CLASSINFO(wxFrame)) &&
410 !win->IsKindOf(CLASSINFO(wxDialog)) &&
411 (win != GetStatusBar())
412 #if wxUSE_TOOLBAR
413 &&
414 (win != GetToolBar())
415 #endif
416 )
417 {
418 if ( child )
419 return; // it's our second subwindow - nothing to do
420 child = win;
421 }
422 }
423
424 if ( child ) {
425 // we have exactly one child - set it's size to fill the whole frame
426 int clientW, clientH;
427 GetClientSize(&clientW, &clientH);
428
429 int x = 0;
430 int y = 0;
431
432 child->SetSize(x, y, clientW, clientH);
433 }
434 }
435
436 // Default activation behaviour - set the focus for the first child
437 // subwindow found.
438 void wxFrame::OnActivate(wxActivateEvent& event)
439 {
440 for(wxNode *node = GetChildren().First(); node; node = node->Next())
441 {
442 // Find a child that's a subwindow, but not a dialog box.
443 wxWindow *child = (wxWindow *)node->Data();
444 if (!child->IsKindOf(CLASSINFO(wxFrame)) &&
445 !child->IsKindOf(CLASSINFO(wxDialog)))
446 {
447 child->SetFocus();
448 return;
449 }
450 }
451 }
452
453 // The default implementation for the close window event.
454 void wxFrame::OnCloseWindow(wxCloseEvent& event)
455 {
456 this->Destroy();
457 }
458
459 // Destroy the window (delayed, if a managed window)
460 bool wxFrame::Destroy()
461 {
462 if (!wxPendingDelete.Member(this))
463 wxPendingDelete.Append(this);
464 return TRUE;
465 }
466
467 // Default menu selection behaviour - display a help string
468 void wxFrame::OnMenuHighlight(wxMenuEvent& event)
469 {
470 if (GetStatusBar())
471 {
472 if (event.GetMenuId() == -1)
473 SetStatusText("");
474 else
475 {
476 wxMenuBar *menuBar = GetMenuBar();
477 if (menuBar)
478 {
479 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
480 if (helpString != "")
481 SetStatusText(helpString);
482 }
483 }
484 }
485 }
486
487 wxMenuBar *wxFrame::GetMenuBar() const
488 {
489 return m_frameMenuBar;
490 }
491
492
493 // Call this to simulate a menu command
494 void wxFrame::Command(int id)
495 {
496 ProcessCommand(id);
497 }
498
499 void wxFrame::ProcessCommand(int id)
500 {
501 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
502 commandEvent.SetInt( id );
503 commandEvent.SetEventObject( this );
504
505 wxMenuBar *bar = GetMenuBar() ;
506 if (!bar)
507 return;
508
509 /* TODO: check the menu item if required
510 wxMenuItem *item = bar->FindItemForId(id) ;
511 if (item && item->IsCheckable())
512 {
513 bar->Check(id,!bar->Checked(id)) ;
514 }
515 */
516
517 GetEventHandler()->ProcessEvent(commandEvent);
518 }
519
520 // Checks if there is a toolbar, and returns the first free client position
521 wxPoint wxFrame::GetClientAreaOrigin() const
522 {
523 wxPoint pt(0, 0);
524 #if wxUSE_TOOLBAR
525 if (GetToolBar())
526 {
527 int w, h;
528 GetToolBar()->GetSize(& w, & h);
529
530 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
531 {
532 pt.x += w;
533 }
534 else
535 {
536 pt.y += h;
537 }
538 }
539 #endif
540 return pt;
541 }
542
543 void wxFrame::DoGetClientSize(int *x, int *y) const
544 {
545 wxWindow::DoGetClientSize( x , y ) ;
546
547 if ( GetStatusBar() )
548 {
549 int statusX, statusY;
550 GetStatusBar()->GetClientSize(&statusX, &statusY);
551 *y -= statusY;
552 }
553
554 wxPoint pt(GetClientAreaOrigin());
555 *y -= pt.y;
556 *x -= pt.x;
557 }
558
559 void wxFrame::DoSetClientSize(int clientwidth, int clientheight)
560 {
561 int currentclientwidth , currentclientheight ;
562 int currentwidth , currentheight ;
563
564 GetClientSize( &currentclientwidth , &currentclientheight ) ;
565 GetSize( &currentwidth , &currentheight ) ;
566
567 // find the current client size
568
569 // Find the difference between the entire window (title bar and all)
570 // and the client area; add this to the new client size to move the
571 // window
572
573 DoSetSize( -1 , -1 , currentwidth + clientwidth - currentclientwidth ,
574 currentheight + clientheight - currentclientheight , wxSIZE_USE_EXISTING ) ;
575 }
576
577
578 #if wxUSE_TOOLBAR
579 wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name)
580 {
581 wxCHECK_MSG( m_frameToolBar == NULL, FALSE,
582 "recreating toolbar in wxFrame" );
583
584 wxToolBar* toolBar = OnCreateToolBar(style, id, name);
585 if (toolBar)
586 {
587 SetToolBar(toolBar);
588 PositionToolBar();
589 return toolBar;
590 }
591 else
592 {
593 return NULL;
594 }
595 }
596
597 wxToolBar* wxFrame::OnCreateToolBar(long style, wxWindowID id, const wxString& name)
598 {
599 return new wxToolBar(this, id, wxDefaultPosition, wxDefaultSize, style, name);
600 }
601
602 void wxFrame::PositionToolBar()
603 {
604 int cw, ch;
605
606 // TODO: we actually need to use the low-level client size, before
607 // the toolbar/status bar were added.
608 // So DEFINITELY replace the line below with something appropriate.
609
610 // GetClientSize(& cw, &ch);
611
612 cw = m_width ;
613 ch = m_height ;
614
615 if ( GetStatusBar() )
616 {
617 int statusX, statusY;
618 GetStatusBar()->GetClientSize(&statusX, &statusY);
619 ch -= statusY;
620 }
621
622 if (GetToolBar())
623 {
624 int tw, th;
625 GetToolBar()->GetSize(& tw, & th);
626
627 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
628 {
629 // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
630 // means, pretend we don't have toolbar/status bar, so we
631 // have the original client size.
632 GetToolBar()->SetSize(0, 0, tw, ch, wxSIZE_NO_ADJUSTMENTS);
633 }
634 else
635 {
636 // Use the 'real' position
637 GetToolBar()->SetSize(0, 0, cw, th, wxSIZE_NO_ADJUSTMENTS);
638 }
639 }
640 }
641 #endif