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