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