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