]> git.saurik.com Git - wxWidgets.git/blame - src/mac/frame.cpp
fixed (rare but fatal) bug in wxWindowDisabler
[wxWidgets.git] / src / mac / frame.cpp
CommitLineData
e9576ca5
SC
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
519cb848
SC
26#include <wx/mac/uma.h>
27
e9576ca5
SC
28extern wxList wxModelessWindows;
29extern wxList wxPendingDelete;
30
e9576ca5
SC
31BEGIN_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)
38END_EVENT_TABLE()
39
40IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxWindow)
e9576ca5
SC
41
42#if wxUSE_NATIVE_STATUSBAR
43bool wxFrame::m_useNativeStatusBar = TRUE;
44#else
45bool wxFrame::m_useNativeStatusBar = FALSE;
46#endif
47
48wxFrame::wxFrame()
49{
519cb848 50#if wxUSE_TOOLBAR
e9576ca5 51 m_frameToolBar = NULL ;
519cb848 52#endif
e7549107 53
519cb848 54 // in order to be able to give size events on show
e9576ca5
SC
55 m_frameMenuBar = NULL;
56 m_frameStatusBar = NULL;
e9576ca5 57 m_iconized = FALSE;
51abe921 58 m_isShown = FALSE;
e9576ca5
SC
59}
60
61bool 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;
51abe921 75 m_isShown = FALSE;
519cb848
SC
76
77#if wxUSE_TOOLBAR
e9576ca5 78 m_frameToolBar = NULL ;
519cb848 79#endif
e9576ca5
SC
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
519cb848
SC
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 ;
519cb848 148 return TRUE;
e9576ca5
SC
149}
150
151wxFrame::~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 {
519cb848 168 wxTheApp->ExitMainLoop() ;
e9576ca5
SC
169 }
170 }
171
172 wxModelessWindows.DeleteObject(this);
173}
174
e9576ca5
SC
175
176void wxFrame::Iconize(bool iconize)
177{
178 // TODO
179}
180
181// Equivalent to maximize/restore in Windows
182void wxFrame::Maximize(bool maximize)
183{
184 // TODO
185}
186
187bool wxFrame::IsIconized() const
188{
189 // TODO
190 return FALSE;
191}
192
193// Is the frame maximized?
194bool wxFrame::IsMaximized(void) const
195{
196 // TODO
197 return FALSE;
198}
199
e9576ca5
SC
200void wxFrame::SetIcon(const wxIcon& icon)
201{
202 m_icon = icon;
203 // TODO
204}
205
206wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
207 const wxString& name)
208{
209 wxStatusBar *statusBar = NULL;
210
519cb848 211 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 17),
e9576ca5
SC
212 style, name);
213
214 // Set the height according to the font and the border size
519cb848
SC
215 // we shouldn't do this on the mac, because we have to fit the grow box
216 /*
e9576ca5
SC
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
519cb848
SC
227 */
228
e9576ca5
SC
229 statusBar->SetFieldsCount(number);
230 return statusBar;
231}
232
233wxStatusBar* 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
251void 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
258void 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
266void wxFrame::PositionStatusBar()
267{
519cb848
SC
268 if (m_frameStatusBar )
269 {
e9576ca5
SC
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);
519cb848 278 }
e9576ca5
SC
279}
280
281void wxFrame::SetMenuBar(wxMenuBar *menuBar)
282{
283 if (!menuBar)
284 {
285 m_frameMenuBar = NULL;
286 return;
287 }
288
289 m_frameMenuBar = menuBar;
519cb848
SC
290 // TODO : we move this into the app code
291 m_frameMenuBar->MacInstallMenuBar() ;
e9576ca5
SC
292}
293
294void 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.
324void 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
6418cb93
SC
342void wxFrame::OnIdle(wxIdleEvent& WXUNUSED(event) )
343{
344 DoMenuUpdates();
345}
346
347
348// update all menus
349void 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
362void 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
e9576ca5
SC
392void 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)) &&
519cb848
SC
409 (win != GetStatusBar())
410#if wxUSE_TOOLBAR
411 &&
412 (win != GetToolBar())
413#endif
414 )
e9576ca5
SC
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.
436void 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
e3065973 451// The default implementation for the close window event.
e9576ca5
SC
452void wxFrame::OnCloseWindow(wxCloseEvent& event)
453{
e3065973 454 this->Destroy();
e9576ca5
SC
455}
456
457// Destroy the window (delayed, if a managed window)
458bool 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
466void 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
485wxMenuBar *wxFrame::GetMenuBar() const
486{
487 return m_frameMenuBar;
488}
489
e9576ca5
SC
490
491// Call this to simulate a menu command
492void wxFrame::Command(int id)
493{
494 ProcessCommand(id);
495}
496
497void wxFrame::ProcessCommand(int id)
498{
519cb848 499 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
e9576ca5
SC
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
519cb848 515 GetEventHandler()->ProcessEvent(commandEvent);
e9576ca5
SC
516}
517
518// Checks if there is a toolbar, and returns the first free client position
519wxPoint wxFrame::GetClientAreaOrigin() const
520{
521 wxPoint pt(0, 0);
519cb848 522#if wxUSE_TOOLBAR
e9576ca5
SC
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 }
519cb848 537#endif
e9576ca5
SC
538 return pt;
539}
540
7c74e7fe 541void wxFrame::DoGetClientSize(int *x, int *y) const
e9576ca5 542{
7c74e7fe 543 wxWindow::DoGetClientSize( x , y ) ;
519cb848
SC
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;
e9576ca5
SC
555}
556
519cb848 557void wxFrame::DoSetClientSize(int clientwidth, int clientheight)
e9576ca5 558{
519cb848
SC
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 ) ;
e9576ca5
SC
573}
574
519cb848
SC
575
576#if wxUSE_TOOLBAR
e9576ca5
SC
577wxToolBar* 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
595wxToolBar* wxFrame::OnCreateToolBar(long style, wxWindowID id, const wxString& name)
596{
597 return new wxToolBar(this, id, wxDefaultPosition, wxDefaultSize, style, name);
598}
599
600void 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
519cb848
SC
608 // GetClientSize(& cw, &ch);
609
610 cw = m_width ;
611 ch = m_height ;
e9576ca5
SC
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}
519cb848 639#endif