]> git.saurik.com Git - wxWidgets.git/blob - src/motif/mdi.cpp
Review/simplify/cleanup MDI classes for all platforms and introduce base
[wxWidgets.git] / src / motif / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/mdi.cpp
3 // Purpose: MDI classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #include "wx/mdi.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/menu.h"
19 #include "wx/icon.h"
20 #include "wx/settings.h"
21 #endif
22
23 #ifdef __VMS__
24 #pragma message disable nosimpint
25 #endif
26 #include <Xm/Xm.h>
27 #include <Xm/BulletinB.h>
28 #include <Xm/Form.h>
29 #include <Xm/MainW.h>
30 #include <Xm/RowColumn.h>
31 #include <Xm/CascadeBG.h>
32 #include <Xm/Text.h>
33 #include <Xm/PushBG.h>
34 #include <Xm/AtomMgr.h>
35 #include <Xm/Protocols.h>
36 #ifdef __VMS__
37 #pragma message enable nosimpint
38 #endif
39
40 #include "wx/motif/private.h"
41
42 extern wxList wxModelessWindows;
43
44 // Implemented in frame.cpp
45 extern void wxFrameFocusProc(Widget workArea, XtPointer clientData,
46 XmAnyCallbackStruct *cbs);
47
48 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
49
50 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
51 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
52 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxNotebook)
53
54 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
55 EVT_SIZE(wxMDIParentFrame::OnSize)
56 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
57 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
58 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight)
59 END_EVENT_TABLE()
60
61 BEGIN_EVENT_TABLE(wxMDIClientWindow, wxNotebook)
62 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxMDIClientWindow::OnPageChanged)
63 END_EVENT_TABLE()
64
65
66 // Parent frame
67
68 void wxMDIParentFrame::Init()
69 {
70 m_activeMenuBar = NULL;
71 }
72
73 bool wxMDIParentFrame::Create(wxWindow *parent,
74 wxWindowID id,
75 const wxString& title,
76 const wxPoint& pos,
77 const wxSize& size,
78 long style,
79 const wxString& name)
80 {
81 if ( !wxFrame::Create(parent, id, title, pos, size, style, name) )
82 return false;
83
84 m_clientWindow = OnCreateClient();
85 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
86 return false;
87
88 int w, h;
89 GetClientSize(& w, & h);
90 m_clientWindow->SetSize(0, 0, w, h);
91 return true;
92 }
93
94 wxMDIParentFrame::~wxMDIParentFrame()
95 {
96 // Make sure we delete the client window last of all
97 RemoveChild(m_clientWindow);
98
99 DestroyChildren();
100
101 delete m_clientWindow;
102 m_clientWindow = NULL;
103 }
104
105 void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
106 {
107 m_frameMenuBar = menu_bar;
108
109 SetChildMenuBar(NULL);
110 }
111
112 void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event))
113 {
114 #if wxUSE_CONSTRAINTS
115 if (GetAutoLayout())
116 Layout();
117 #endif
118 int x = 0;
119 int y = 0;
120 int width, height;
121 GetClientSize(&width, &height);
122
123 if ( GetClientWindow() )
124 GetClientWindow()->SetSize(x, y, width, height);
125 }
126
127 void wxMDIParentFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
128 {
129 // Do nothing
130 }
131
132 // Set the child's menu into the parent frame
133 void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame* child)
134 {
135 wxMenuBar* oldMenuBar = m_activeMenuBar;
136
137 if (child == NULL) // No child: use parent frame
138 {
139 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar))
140 {
141 // if (m_activeMenuBar)
142 // m_activeMenuBar->DestroyMenuBar();
143
144 m_activeMenuBar = GetMenuBar();
145 m_activeMenuBar->CreateMenuBar(this);
146 /*
147 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
148 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
149 */
150 if (oldMenuBar && oldMenuBar->GetMainWidget())
151 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
152
153 }
154 }
155 else if (child->GetMenuBar() == NULL) // No child menu bar: use parent frame
156 {
157 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar))
158 {
159 // if (m_activeMenuBar)
160 // m_activeMenuBar->DestroyMenuBar();
161 m_activeMenuBar = GetMenuBar();
162 m_activeMenuBar->CreateMenuBar(this);
163 /*
164 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
165 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
166 */
167 if (oldMenuBar && oldMenuBar->GetMainWidget())
168 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
169 }
170 }
171 else // The child has a menubar
172 {
173 if (child->GetMenuBar() != m_activeMenuBar)
174 {
175 // if (m_activeMenuBar)
176 // m_activeMenuBar->DestroyMenuBar();
177
178 m_activeMenuBar = child->GetMenuBar();
179 m_activeMenuBar->CreateMenuBar(this);
180 /*
181 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
182 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
183 */
184 if (oldMenuBar && oldMenuBar->GetMainWidget())
185 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
186 }
187 }
188 }
189
190 // Redirect events to active child first
191 bool wxMDIParentFrame::ProcessEvent(wxEvent& event)
192 {
193 // Stops the same event being processed repeatedly
194 static wxEventType inEvent = wxEVT_NULL;
195 if (inEvent == event.GetEventType())
196 return false;
197
198 inEvent = event.GetEventType();
199
200 bool res = false;
201 if (m_currentChild && event.IsKindOf(CLASSINFO(wxCommandEvent)))
202 {
203 res = m_currentChild->HandleWindowEvent(event);
204 }
205
206 if (!res)
207 res = GetEventHandler()->wxEvtHandler::ProcessEvent(event);
208
209 inEvent = wxEVT_NULL;
210
211 return res;
212 }
213
214 // Responds to colour changes, and passes event on to children.
215 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
216 {
217 // TODO
218
219 // Propagate the event to the non-top-level children
220 wxFrame::OnSysColourChanged(event);
221 }
222
223 // Default menu selection behaviour - display a help string
224 void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent& event)
225 {
226 if (GetStatusBar())
227 {
228 if (event.GetMenuId() == -1)
229 SetStatusText(wxEmptyString);
230 else
231 {
232 wxMenuBar *menuBar = NULL;
233 if (GetActiveChild())
234 menuBar = GetActiveChild()->GetMenuBar();
235 else
236 menuBar = GetMenuBar();
237 if (menuBar)
238 {
239 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
240 if (!helpString.empty())
241 SetStatusText(helpString);
242 }
243 }
244 }
245 }
246
247 // Child frame
248
249 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
250 wxWindowID id,
251 const wxString& title,
252 const wxPoint& pos,
253 const wxSize& size,
254 long style,
255 const wxString& name)
256 {
257 SetName(name);
258 SetWindowStyleFlag(style);
259
260 if ( id > -1 )
261 m_windowId = id;
262 else
263 m_windowId = (int)NewControlId();
264
265 wxMDIClientWindow* clientWindow = parent->GetClientWindow();
266
267 wxCHECK_MSG( clientWindow, false, "Missing MDI client window." );
268
269 clientWindow->AddChild(this);
270
271 m_mdiParent = parent;
272 PreCreation();
273
274 int width = size.x;
275 int height = size.y;
276 if (width == -1)
277 width = 200; // TODO: give reasonable default
278 if (height == -1)
279 height = 200; // TODO: give reasonable default
280
281 // We're deactivating the old child
282 wxMDIChildFrame* oldActiveChild = parent->GetActiveChild();
283 if (oldActiveChild)
284 {
285 wxActivateEvent event(wxEVT_ACTIVATE, false, oldActiveChild->GetId());
286 event.SetEventObject( oldActiveChild );
287 oldActiveChild->HandleWindowEvent(event);
288 }
289
290 // This is the currently active child
291 parent->SetActiveChild((wxMDIChildFrame*) this);
292
293 // This time we'll try a bog-standard bulletin board for
294 // the 'frame'. A main window doesn't seem to work.
295
296 m_mainWidget = (WXWidget) XtVaCreateWidget("client",
297 xmBulletinBoardWidgetClass, (Widget) clientWindow->GetTopWidget(),
298 XmNmarginWidth, 0,
299 XmNmarginHeight, 0,
300 /*
301 XmNrightAttachment, XmATTACH_FORM,
302 XmNleftAttachment, XmATTACH_FORM,
303 XmNtopAttachment, XmATTACH_FORM,
304 XmNbottomAttachment, XmATTACH_FORM,
305 */
306 XmNresizePolicy, XmRESIZE_NONE,
307 NULL);
308
309 XtAddEventHandler((Widget) m_mainWidget, ExposureMask,False,
310 wxUniversalRepaintProc, (XtPointer) this);
311
312 PostCreation();
313 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
314
315 XtManageChild((Widget) m_mainWidget);
316
317 SetTitle(title);
318
319 clientWindow->AddPage(this, title, true);
320 clientWindow->Refresh();
321
322 // Positions the toolbar and status bar -- but we don't have any.
323 // PreResize();
324
325 wxModelessWindows.Append(this);
326 return true;
327 }
328
329
330 wxMDIChildFrame::~wxMDIChildFrame()
331 {
332 if (m_mainWidget)
333 XtRemoveEventHandler((Widget) m_mainWidget, ExposureMask,False,
334 wxUniversalRepaintProc, (XtPointer) this);
335
336 if (GetMDIParentFrame())
337 {
338 wxMDIParentFrame* parentFrame = GetMDIParentFrame();
339
340 if (parentFrame->GetActiveChild() == this)
341 parentFrame->SetActiveChild(NULL);
342 wxMDIClientWindow* clientWindow = parentFrame->GetClientWindow();
343
344 // Remove page if still there
345 {
346 int i = clientWindow->FindPage(this);
347
348 if (i != -1)
349 {
350 clientWindow->RemovePage(i);
351 clientWindow->Refresh();
352 }
353 }
354
355 // Set the selection to the first remaining page
356 if (clientWindow->GetPageCount() > 0)
357 {
358 wxMDIChildFrame* child = (wxMDIChildFrame*) clientWindow->GetPage(0);
359 parentFrame->SetActiveChild(child);
360 parentFrame->SetChildMenuBar(child);
361 }
362 else
363 {
364 parentFrame->SetActiveChild(NULL);
365 parentFrame->SetChildMenuBar(NULL);
366 }
367 }
368 }
369
370 bool wxMDIChildFrame::Show(bool show)
371 {
372 SetVisibleStatus( show );
373 return wxWindow::Show(show);
374 }
375
376 void wxMDIChildFrame::SetMenuBar(wxMenuBar *menuBar)
377 {
378 // Don't create the underlying menubar yet; need to recreate
379 // it every time the child is activated.
380 m_frameMenuBar = menuBar;
381
382 // We make the assumption that if you're setting the menubar,
383 // this is the currently active child.
384 GetMDIParentFrame()->SetChildMenuBar(this);
385 }
386
387 void wxMDIChildFrame::SetTitle(const wxString& title)
388 {
389 m_title = title;
390 wxMDIClientWindow* clientWindow = GetMDIParentFrame()->GetClientWindow();
391
392 int i = clientWindow->FindPage(this);
393 if (i != wxNOT_FOUND)
394 clientWindow->SetPageText(i, title);
395 }
396
397 void wxMDIChildFrame::Activate()
398 {
399 // TODO
400 }
401
402 // Client window
403
404 wxMDIClientWindow::~wxMDIClientWindow()
405 {
406 // By the time this destructor is called, the child frames will have been
407 // deleted and removed from the notebook/client window.
408 DestroyChildren();
409
410 m_mainWidget = (WXWidget) 0;
411 }
412
413 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
414 {
415 SetWindowStyleFlag(style);
416
417 if ( !wxNotebook::Create(parent, wxID_NOTEBOOK_CLIENT_AREA,
418 wxPoint(0, 0), wxSize(100, 100), 0) )
419 return false;
420
421 return true;
422 }
423
424 int wxMDIClientWindow::FindPage(const wxNotebookPage* page)
425 {
426 for (int i = GetPageCount() - 1; i >= 0; --i)
427 {
428 if (GetPage(i) == page)
429 return i;
430 }
431
432 return -1;
433 }
434
435 void wxMDIClientWindow::OnPageChanged(wxBookCtrlEvent& event)
436 {
437 // Notify child that it has been activated
438 if (event.GetOldSelection() != -1)
439 {
440 wxMDIChildFrame* oldChild = (wxMDIChildFrame*) GetPage(event.GetOldSelection());
441 if (oldChild)
442 {
443 wxActivateEvent event(wxEVT_ACTIVATE, false, oldChild->GetId());
444 event.SetEventObject( oldChild );
445 oldChild->HandleWindowEvent(event);
446 }
447 }
448 if (event.GetSelection() != -1)
449 {
450 wxMDIChildFrame* activeChild = (wxMDIChildFrame*) GetPage(event.GetSelection());
451 if (activeChild)
452 {
453 wxActivateEvent event(wxEVT_ACTIVATE, true, activeChild->GetId());
454 event.SetEventObject( activeChild );
455 activeChild->HandleWindowEvent(event);
456
457 if (activeChild->GetMDIParentFrame())
458 {
459 activeChild->GetMDIParentFrame()->SetActiveChild(activeChild);
460 activeChild->GetMDIParentFrame()->SetChildMenuBar(activeChild);
461 }
462 }
463 }
464 event.Skip();
465 }