]> git.saurik.com Git - wxWidgets.git/blob - src/motif/mdi.cpp
Various small fixes and tweaks
[wxWidgets.git] / src / motif / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifdef __GNUG__
13 #pragma implementation "mdi.h"
14 #endif
15
16 #include "wx/mdi.h"
17 #include "wx/menu.h"
18 #include "wx/settings.h"
19
20 #ifdef __VMS__
21 #pragma message disable nosimpint
22 #endif
23 #include <Xm/Xm.h>
24 #include <Xm/BulletinB.h>
25 #include <Xm/Form.h>
26 #include <Xm/MainW.h>
27 #include <Xm/RowColumn.h>
28 #include <Xm/CascadeBG.h>
29 #include <Xm/Text.h>
30 #include <Xm/PushBG.h>
31 #include <Xm/AtomMgr.h>
32 #include <Xm/Protocols.h>
33 #ifdef __VMS__
34 #pragma message enable nosimpint
35 #endif
36
37 #include "wx/motif/private.h"
38
39 extern wxList wxModelessWindows;
40
41 // Implemented in frame.cpp
42 extern void wxFrameFocusProc(Widget workArea, XtPointer clientData,
43 XmAnyCallbackStruct *cbs);
44
45 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
46
47 #if !USE_SHARED_LIBRARY
48 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
49 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
50 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxNotebook)
51
52 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
53 EVT_SIZE(wxMDIParentFrame::OnSize)
54 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
55 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
56 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight)
57 END_EVENT_TABLE()
58
59 BEGIN_EVENT_TABLE(wxMDIClientWindow, wxNotebook)
60 EVT_SCROLL(wxMDIClientWindow::OnScroll)
61 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxMDIClientWindow::OnPageChanged)
62 END_EVENT_TABLE()
63
64 #endif // USE_SHARED_LIBRARY
65
66 // Parent frame
67
68 wxMDIParentFrame::wxMDIParentFrame()
69 {
70 m_clientWindow = (wxMDIClientWindow*) NULL;
71 m_activeChild = (wxMDIChildFrame*) NULL;
72 m_activeMenuBar = (wxMenuBar*) NULL;
73 }
74
75 bool wxMDIParentFrame::Create(wxWindow *parent,
76 wxWindowID id,
77 const wxString& title,
78 const wxPoint& pos,
79 const wxSize& size,
80 long style,
81 const wxString& name)
82 {
83 m_clientWindow = (wxMDIClientWindow*) NULL;
84 m_activeChild = (wxMDIChildFrame*) NULL;
85 m_activeMenuBar = (wxMenuBar*) NULL;
86
87 bool success = wxFrame::Create(parent, id, title, pos, size, style, name);
88 if (success)
89 {
90 // TODO: app cannot override OnCreateClient since
91 // wxMDIParentFrame::OnCreateClient will still be called
92 // (we're in the constructor). How to resolve?
93
94 m_clientWindow = OnCreateClient();
95
96 // Uses own style for client style
97 m_clientWindow->CreateClient(this, GetWindowStyleFlag());
98
99 int w, h;
100 GetClientSize(& w, & h);
101 m_clientWindow->SetSize(0, 0, w, h);
102 return TRUE;
103 }
104 else
105 return FALSE;
106 }
107
108 wxMDIParentFrame::~wxMDIParentFrame()
109 {
110 // Make sure we delete the client window last of all
111 RemoveChild(m_clientWindow);
112
113 DestroyChildren();
114
115 delete m_clientWindow;
116 m_clientWindow = NULL;
117 }
118
119 void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
120 {
121 m_frameMenuBar = menu_bar;
122
123 SetChildMenuBar((wxMDIChildFrame*) NULL);
124 }
125
126 void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event))
127 {
128 #if wxUSE_CONSTRAINTS
129 if (GetAutoLayout())
130 Layout();
131 #endif
132 int x = 0;
133 int y = 0;
134 int width, height;
135 GetClientSize(&width, &height);
136
137 if ( GetClientWindow() )
138 GetClientWindow()->SetSize(x, y, width, height);
139 }
140
141 void wxMDIParentFrame::DoGetClientSize(int *width, int *height) const
142 {
143 wxFrame::DoGetClientSize(width, height);
144 }
145
146 void wxMDIParentFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
147 {
148 // Do nothing
149 }
150
151 // Returns the active MDI child window
152 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
153 {
154 return m_activeChild;
155 }
156
157 // Create the client window class (don't Create the window,
158 // just return a new class)
159 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
160 {
161 return new wxMDIClientWindow ;
162 }
163
164 // Set the child's menu into the parent frame
165 void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame* child)
166 {
167 wxMenuBar* oldMenuBar = m_activeMenuBar;
168
169 if (child == (wxMDIChildFrame*) NULL) // No child: use parent frame
170 {
171 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar))
172 {
173 // if (m_activeMenuBar)
174 // m_activeMenuBar->DestroyMenuBar();
175
176 m_activeMenuBar = GetMenuBar();
177 m_activeMenuBar->CreateMenuBar(this);
178 /*
179 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
180 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
181 */
182 if (oldMenuBar && oldMenuBar->GetMainWidget())
183 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
184
185 }
186 }
187 else if (child->GetMenuBar() == (wxMenuBar*) NULL) // No child menu bar: use parent frame
188 {
189 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar))
190 {
191 // if (m_activeMenuBar)
192 // m_activeMenuBar->DestroyMenuBar();
193 m_activeMenuBar = GetMenuBar();
194 m_activeMenuBar->CreateMenuBar(this);
195 /*
196 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
197 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
198 */
199 if (oldMenuBar && oldMenuBar->GetMainWidget())
200 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
201 }
202 }
203 else // The child has a menubar
204 {
205 if (child->GetMenuBar() != m_activeMenuBar)
206 {
207 // if (m_activeMenuBar)
208 // m_activeMenuBar->DestroyMenuBar();
209
210 m_activeMenuBar = child->GetMenuBar();
211 m_activeMenuBar->CreateMenuBar(this);
212 /*
213 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
214 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
215 */
216 if (oldMenuBar && oldMenuBar->GetMainWidget())
217 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
218 }
219 }
220 }
221
222 // Redirect events to active child first
223 bool wxMDIParentFrame::ProcessEvent(wxEvent& event)
224 {
225 // Stops the same event being processed repeatedly
226 static wxEventType inEvent = wxEVT_NULL;
227 if (inEvent == event.GetEventType())
228 return FALSE;
229
230 inEvent = event.GetEventType();
231
232 bool res = FALSE;
233 if (m_activeChild && event.IsKindOf(CLASSINFO(wxCommandEvent)))
234 {
235 res = m_activeChild->GetEventHandler()->ProcessEvent(event);
236 }
237
238 if (!res)
239 res = GetEventHandler()->wxEvtHandler::ProcessEvent(event);
240
241 inEvent = wxEVT_NULL;
242
243 return res;
244 }
245
246 void wxMDIParentFrame::DoSetSize(int x, int y,
247 int width, int height,
248 int sizeFlags)
249 {
250 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
251 }
252
253 void wxMDIParentFrame::DoSetClientSize(int width, int height)
254 {
255 wxWindow::DoSetClientSize(width, height);
256 }
257
258 // Responds to colour changes, and passes event on to children.
259 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
260 {
261 // TODO
262
263 // Propagate the event to the non-top-level children
264 wxFrame::OnSysColourChanged(event);
265 }
266
267 // MDI operations
268 void wxMDIParentFrame::Cascade()
269 {
270 // TODO
271 }
272
273 void wxMDIParentFrame::Tile()
274 {
275 // TODO
276 }
277
278 void wxMDIParentFrame::ArrangeIcons()
279 {
280 // TODO
281 }
282
283 void wxMDIParentFrame::ActivateNext()
284 {
285 // TODO
286 }
287
288 void wxMDIParentFrame::ActivatePrevious()
289 {
290 // TODO
291 }
292
293 // Default menu selection behaviour - display a help string
294 void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent& event)
295 {
296 if (GetStatusBar())
297 {
298 if (event.GetMenuId() == -1)
299 SetStatusText("");
300 else
301 {
302 wxMenuBar *menuBar = (wxMenuBar*) NULL;
303 if (GetActiveChild())
304 menuBar = GetActiveChild()->GetMenuBar();
305 else
306 menuBar = GetMenuBar();
307 if (menuBar)
308 {
309 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
310 if (helpString != "")
311 SetStatusText(helpString);
312 }
313 }
314 }
315 }
316
317 // Child frame
318
319 wxMDIChildFrame::wxMDIChildFrame()
320 {
321 m_mdiParentFrame = (wxMDIParentFrame*) NULL;
322 }
323
324 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
325 wxWindowID id,
326 const wxString& title,
327 const wxPoint& pos,
328 const wxSize& size,
329 long style,
330 const wxString& name)
331 {
332 SetName(name);
333 SetWindowStyleFlag(style);
334
335 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
336 m_foregroundColour = *wxBLACK;
337 m_font = wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
338
339 if ( id > -1 )
340 m_windowId = id;
341 else
342 m_windowId = (int)NewControlId();
343
344 wxMDIClientWindow* clientWindow = parent->GetClientWindow();
345
346 wxASSERT_MSG( (clientWindow != (wxWindow*) NULL), "Missing MDI client window.");
347
348 if (clientWindow) clientWindow->AddChild(this);
349
350 SetMDIParentFrame(parent);
351
352 int width = size.x;
353 int height = size.y;
354 if (width == -1)
355 width = 200; // TODO: give reasonable default
356 if (height == -1)
357 height = 200; // TODO: give reasonable default
358
359 // We're deactivating the old child
360 wxMDIChildFrame* oldActiveChild = parent->GetActiveChild();
361 if (oldActiveChild)
362 {
363 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldActiveChild->GetId());
364 event.SetEventObject( oldActiveChild );
365 oldActiveChild->GetEventHandler()->ProcessEvent(event);
366 }
367
368 // This is the currently active child
369 parent->SetActiveChild((wxMDIChildFrame*) this);
370
371 // This time we'll try a bog-standard bulletin board for
372 // the 'frame'. A main window doesn't seem to work.
373
374 m_mainWidget = (WXWidget) XtVaCreateWidget("client",
375 xmBulletinBoardWidgetClass, (Widget) clientWindow->GetTopWidget(),
376 XmNmarginWidth, 0,
377 XmNmarginHeight, 0,
378 /*
379 XmNrightAttachment, XmATTACH_FORM,
380 XmNleftAttachment, XmATTACH_FORM,
381 XmNtopAttachment, XmATTACH_FORM,
382 XmNbottomAttachment, XmATTACH_FORM,
383 */
384 XmNresizePolicy, XmRESIZE_NONE,
385 NULL);
386
387 XtAddEventHandler((Widget) m_mainWidget, ExposureMask,FALSE,
388 wxUniversalRepaintProc, (XtPointer) this);
389
390 SetCanAddEventHandler(TRUE);
391 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
392
393 ChangeBackgroundColour();
394
395 XtManageChild((Widget) m_mainWidget);
396
397 SetTitle(title);
398
399 clientWindow->AddPage(this, title, TRUE);
400 clientWindow->Refresh();
401
402 // Positions the toolbar and status bar -- but we don't have any.
403 // PreResize();
404
405 wxModelessWindows.Append(this);
406 return TRUE;
407 }
408
409
410 wxMDIChildFrame::~wxMDIChildFrame()
411 {
412 if (m_mainWidget)
413 XtRemoveEventHandler((Widget) m_mainWidget, ExposureMask,FALSE,
414 wxUniversalRepaintProc, (XtPointer) this);
415
416 if (GetMDIParentFrame())
417 {
418 wxMDIParentFrame* parentFrame = GetMDIParentFrame();
419
420 if (parentFrame->GetActiveChild() == this)
421 parentFrame->SetActiveChild((wxMDIChildFrame*) NULL);
422 wxMDIClientWindow* clientWindow = parentFrame->GetClientWindow();
423
424 // Remove page if still there
425 if (clientWindow->RemovePage(this))
426 clientWindow->Refresh();
427
428 // Set the selection to the first remaining page
429 if (clientWindow->GetPageCount() > 0)
430 {
431 wxMDIChildFrame* child = (wxMDIChildFrame*) clientWindow->GetPage(0);
432 parentFrame->SetActiveChild(child);
433 parentFrame->SetChildMenuBar(child);
434 }
435 else
436 {
437 parentFrame->SetActiveChild((wxMDIChildFrame*) NULL);
438 parentFrame->SetChildMenuBar((wxMDIChildFrame*) NULL);
439 }
440 }
441 }
442
443 #if 0
444 // Implementation: intercept and act upon raise and lower commands.
445 void wxMDIChildFrame::OnRaise()
446 {
447 wxMDIParentFrame* parentFrame = (wxMDIParentFrame*) GetParent() ;
448 wxMDIChildFrame* oldActiveChild = parentFrame->GetActiveChild();
449 parentFrame->SetActiveChild(this);
450
451 if (oldActiveChild)
452 {
453 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldActiveChild->GetId());
454 event.SetEventObject( oldActiveChild );
455 oldActiveChild->GetEventHandler()->ProcessEvent(event);
456 }
457
458 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, this->GetId());
459 event.SetEventObject( this );
460 this->GetEventHandler()->ProcessEvent(event);
461 }
462
463 void wxMDIChildFrame::OnLower()
464 {
465 wxMDIParentFrame* parentFrame = (wxMDIParentFrame*) GetParent() ;
466 wxMDIChildFrame* oldActiveChild = parentFrame->GetActiveChild();
467
468 if (oldActiveChild == this)
469 {
470 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldActiveChild->GetId());
471 event.SetEventObject( oldActiveChild );
472 oldActiveChild->GetEventHandler()->ProcessEvent(event);
473 }
474 // TODO: unfortunately we don't now know which is the top-most child,
475 // so make the active child NULL.
476 parentFrame->SetActiveChild((wxMDIChildFrame*) NULL);
477 }
478 #endif
479
480 // Set the client size (i.e. leave the calculation of borders etc.
481 // to wxWindows)
482 void wxMDIChildFrame::DoSetClientSize(int width, int height)
483 {
484 wxWindow::DoSetClientSize(width, height);
485 }
486
487 void wxMDIChildFrame::DoGetClientSize(int* width, int* height) const
488 {
489 wxWindow::DoGetSize(width, height);
490 }
491
492 void wxMDIChildFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags)
493 {
494 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
495 }
496
497 void wxMDIChildFrame::DoGetSize(int* width, int* height) const
498 {
499 wxWindow::DoGetSize(width, height);
500 }
501
502 void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
503 {
504 wxWindow::DoGetPosition(x, y);
505 }
506
507 bool wxMDIChildFrame::Show(bool show)
508 {
509 m_visibleStatus = show; /* show-&-hide fix */
510 return wxWindow::Show(show);
511 }
512
513 void wxMDIChildFrame::SetMenuBar(wxMenuBar *menuBar)
514 {
515 // Don't create the underlying menubar yet; need to recreate
516 // it every time the child is activated.
517 m_frameMenuBar = menuBar;
518
519 // We make the assumption that if you're setting the menubar,
520 // this is the currently active child.
521 GetMDIParentFrame()->SetChildMenuBar(this);
522 }
523
524 // Set icon
525 void wxMDIChildFrame::SetIcon(const wxIcon& icon)
526 {
527 m_icon = icon;
528 if (m_icon.Ok())
529 {
530 // Not appropriate since there are no icons in
531 // a tabbed window
532 }
533 }
534
535 void wxMDIChildFrame::SetTitle(const wxString& title)
536 {
537 m_title = title;
538 wxMDIClientWindow* clientWindow = GetMDIParentFrame()->GetClientWindow();
539 int pageNo = clientWindow->FindPagePosition(this);
540 if (pageNo > -1)
541 clientWindow->SetPageText(pageNo, title);
542 }
543
544 // MDI operations
545 void wxMDIChildFrame::Maximize()
546 {
547 // TODO
548 }
549
550 void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize))
551 {
552 // TODO
553 }
554
555 bool wxMDIChildFrame::IsIconized() const
556 {
557 return FALSE;
558 }
559
560 // Is it maximized? Always maximized under Motif, using the
561 // tabbed MDI implementation.
562 bool wxMDIChildFrame::IsMaximized(void) const
563 {
564 return TRUE;
565 }
566
567 void wxMDIChildFrame::Restore()
568 {
569 // TODO
570 }
571
572 void wxMDIChildFrame::Activate()
573 {
574 // TODO
575 }
576
577 void wxMDIChildFrame::CaptureMouse()
578 {
579 wxWindow::CaptureMouse();
580 }
581
582 void wxMDIChildFrame::ReleaseMouse()
583 {
584 wxWindow::ReleaseMouse();
585 }
586
587 void wxMDIChildFrame::Raise()
588 {
589 wxWindow::Raise();
590 }
591
592 void wxMDIChildFrame::Lower(void)
593 {
594 wxWindow::Raise();
595 }
596
597 void wxMDIChildFrame::SetSizeHints(int WXUNUSED(minW), int WXUNUSED(minH), int WXUNUSED(maxW), int WXUNUSED(maxH), int WXUNUSED(incW), int WXUNUSED(incH))
598 {
599 }
600
601 // Client window
602
603 wxMDIClientWindow::wxMDIClientWindow()
604 {
605 }
606
607 wxMDIClientWindow::~wxMDIClientWindow()
608 {
609 // By the time this destructor is called, the child frames will have been
610 // deleted and removed from the notebook/client window.
611 DestroyChildren();
612
613 m_mainWidget = (WXWidget) 0;
614 }
615
616 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
617 {
618 SetWindowStyleFlag(style);
619
620 // m_windowParent = parent;
621 // m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
622
623 bool success = wxNotebook::Create(parent, wxID_NOTEBOOK_CLIENT_AREA, wxPoint(0, 0), wxSize(100, 100), 0);
624 if (success)
625 {
626 wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL);
627 wxFont selFont(10, wxSWISS, wxNORMAL, wxBOLD);
628 GetTabView()->SetTabFont(font);
629 GetTabView()->SetSelectedTabFont(selFont);
630 GetTabView()->SetTabSize(120, 18);
631 GetTabView()->SetTabSelectionHeight(20);
632 return TRUE;
633 }
634 else
635 return FALSE;
636 }
637
638 void wxMDIClientWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
639 {
640 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
641 }
642
643 void wxMDIClientWindow::DoSetClientSize(int width, int height)
644 {
645 wxWindow::DoSetClientSize(width, height);
646 }
647
648 void wxMDIClientWindow::DoGetClientSize(int *width, int *height) const
649 {
650 wxWindow::DoGetClientSize(width, height);
651 }
652
653 void wxMDIClientWindow::DoGetSize(int *width, int *height) const
654 {
655 wxWindow::DoGetSize(width, height);
656 }
657
658 void wxMDIClientWindow::DoGetPosition(int *x, int *y) const
659 {
660 wxWindow::DoGetPosition(x, y);
661 }
662
663 // Explicitly call default scroll behaviour
664 void wxMDIClientWindow::OnScroll(wxScrollEvent& WXUNUSED(event))
665 {
666 Default(); // Default processing
667 }
668
669 void wxMDIClientWindow::OnPageChanged(wxNotebookEvent& event)
670 {
671 // Notify child that it has been activated
672 if (event.GetOldSelection() != -1)
673 {
674 wxMDIChildFrame* oldChild = (wxMDIChildFrame*) GetPage(event.GetOldSelection());
675 if (oldChild)
676 {
677 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldChild->GetId());
678 event.SetEventObject( oldChild );
679 oldChild->GetEventHandler()->ProcessEvent(event);
680 }
681 }
682 if (event.GetSelection() != -1)
683 {
684 wxMDIChildFrame* activeChild = (wxMDIChildFrame*) GetPage(event.GetSelection());
685 if (activeChild)
686 {
687 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, activeChild->GetId());
688 event.SetEventObject( activeChild );
689 activeChild->GetEventHandler()->ProcessEvent(event);
690
691 if (activeChild->GetMDIParentFrame())
692 {
693 activeChild->GetMDIParentFrame()->SetActiveChild(activeChild);
694 activeChild->GetMDIParentFrame()->SetChildMenuBar(activeChild);
695 }
696 }
697 }
698 event.Skip();
699 }