1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "mdi.h"
16 #if wxUSE_MDI_ARCHITECTURE
18 #include "wx/dialog.h"
25 #include "wx/gtk/win_gtk.h"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 const int wxMENU_HEIGHT
= 27;
33 //-----------------------------------------------------------------------------
35 //-----------------------------------------------------------------------------
37 extern void wxapp_install_idle_handler();
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
44 extern wxList wxPendingDelete
;
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
51 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
52 GtkNotebookPage
*page
,
53 gint
WXUNUSED(page_num
),
54 wxMDIParentFrame
*parent
)
57 wxapp_install_idle_handler();
59 // send deactivate event to old child
61 wxMDIChildFrame
*child
= parent
->GetActiveChild();
64 wxActivateEvent
event1( wxEVT_ACTIVATE
, FALSE
, child
->GetId() );
65 event1
.SetEventObject( child
);
66 child
->GetEventHandler()->ProcessEvent( event1
);
69 // send activate event to new child
71 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
75 child
= (wxMDIChildFrame
*) NULL
;
77 wxNode
*node
= client_window
->GetChildren().First();
80 wxMDIChildFrame
*child_frame
= (wxMDIChildFrame
*)node
->Data();
81 if (child_frame
->m_page
== page
)
92 wxActivateEvent
event2( wxEVT_ACTIVATE
, TRUE
, child
->GetId() );
93 event2
.SetEventObject( child
);
94 child
->GetEventHandler()->ProcessEvent( event2
);
97 //-----------------------------------------------------------------------------
99 //-----------------------------------------------------------------------------
101 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
103 void wxMDIParentFrame::Init()
105 m_justInserted
= FALSE
;
106 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
109 wxMDIParentFrame::~wxMDIParentFrame()
113 bool wxMDIParentFrame::Create(wxWindow
*parent
,
115 const wxString
& title
,
119 const wxString
& name
)
121 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
128 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
130 wxFrame::GtkOnSize( x
, y
, width
, height
);
132 wxMDIChildFrame
*child_frame
= GetActiveChild();
133 if (!child_frame
) return;
135 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
136 if (!menu_bar
) return;
137 if (!menu_bar
->m_widget
) return;
141 menu_bar
->m_width
= m_width
;
142 menu_bar
->m_height
= wxMENU_HEIGHT
;
143 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
145 0, 0, m_width
, wxMENU_HEIGHT
);
148 void wxMDIParentFrame::OnInternalIdle()
150 /* if a an MDI child window has just been inserted
151 it has to be brought to the top in idle time. we
152 simply set the last notebook page active as new
153 pages can only be appended at the end */
157 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
158 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
160 m_justInserted
= FALSE
;
164 wxFrame::OnInternalIdle();
166 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
167 bool visible_child_menu
= FALSE
;
169 wxNode
*node
= m_clientWindow
->GetChildren().First();
172 wxObject
*child
= node
->Data();
173 wxMDIChildFrame
*child_frame
= wxDynamicCast(child
, wxMDIChildFrame
);
176 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
179 if (child_frame
== active_child_frame
)
181 if (menu_bar
->Show(TRUE
))
183 menu_bar
->m_width
= m_width
;
184 menu_bar
->m_height
= wxMENU_HEIGHT
;
185 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
187 0, 0, m_width
, wxMENU_HEIGHT
);
188 menu_bar
->SetInvokingWindow( child_frame
);
190 visible_child_menu
= TRUE
;
194 if (menu_bar
->Show(FALSE
))
196 menu_bar
->UnsetInvokingWindow( child_frame
);
205 /* show/hide parent menu bar as required */
206 if ((m_frameMenuBar
) &&
207 (m_frameMenuBar
->IsShown() == visible_child_menu
))
209 if (visible_child_menu
)
211 m_frameMenuBar
->Show( FALSE
);
212 m_frameMenuBar
->UnsetInvokingWindow( this );
216 m_frameMenuBar
->Show( TRUE
);
217 m_frameMenuBar
->SetInvokingWindow( this );
219 m_frameMenuBar
->m_width
= m_width
;
220 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
221 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
222 m_frameMenuBar
->m_widget
,
223 0, 0, m_width
, wxMENU_HEIGHT
);
228 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
230 wxFrame::DoGetClientSize( width
, height
);
233 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
235 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
237 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
238 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
240 #if (GTK_MINOR_VERSION > 0)
241 gint i
= gtk_notebook_get_current_page( notebook
);
243 gint i
= gtk_notebook_current_page( notebook
);
245 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
247 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
248 if (!page
) return (wxMDIChildFrame
*) NULL
;
250 wxNode
*node
= m_clientWindow
->GetChildren().First();
253 wxMDIChildFrame
*child_frame
= (wxMDIChildFrame
*)node
->Data();
254 if (child_frame
->m_page
== page
)
259 return (wxMDIChildFrame
*) NULL
;
262 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
264 return m_clientWindow
;
267 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
269 m_clientWindow
= new wxMDIClientWindow( this );
270 return m_clientWindow
;
273 void wxMDIParentFrame::ActivateNext()
276 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
279 void wxMDIParentFrame::ActivatePrevious()
282 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
285 //-----------------------------------------------------------------------------
287 //-----------------------------------------------------------------------------
289 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
291 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
292 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
293 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
296 wxMDIChildFrame::wxMDIChildFrame()
298 m_menuBar
= (wxMenuBar
*) NULL
;
299 m_page
= (GtkNotebookPage
*) NULL
;
303 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
304 wxWindowID id
, const wxString
& title
,
305 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
306 long style
, const wxString
& name
)
308 m_menuBar
= (wxMenuBar
*) NULL
;
309 m_page
= (GtkNotebookPage
*) NULL
;
311 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
314 wxMDIChildFrame::~wxMDIChildFrame()
320 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
321 wxWindowID id
, const wxString
& title
,
322 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
323 long style
, const wxString
& name
)
327 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
330 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
332 wxWindow::DoGetClientSize( width
, height
);
335 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
337 wxWindow::AddChild(child
);
340 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
342 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
344 m_menuBar
= menu_bar
;
348 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
350 m_menuBar
->SetParent( mdi_frame
);
352 /* insert the invisible menu bar into the _parent_ mdi frame */
353 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
355 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
359 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
364 void wxMDIChildFrame::Activate()
366 #if (GTK_MINOR_VERSION > 0)
367 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
368 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
369 gint pageno
= gtk_notebook_page_num( notebook
, m_page
->child
);
370 gtk_notebook_set_page( notebook
, pageno
);
372 // the only way I can see to do this under gtk+ 1.0.X would
373 // be to keep track of page numbers, start at first and
374 // do "next" enough times to get to this page number - messy
375 // - J. Russell Smyth
379 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
383 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
386 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
387 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
389 // we don't have any help text for this item, but may be the MDI frame
391 mdi_frame
->OnMenuHighlight(event
);
393 #endif // wxUSE_STATUSBAR
396 void wxMDIChildFrame::SetTitle( const wxString
&title
)
398 if ( title
== m_title
)
403 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
404 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
405 gtk_notebook_set_tab_label_text(notebook
, m_page
->child
, title
.mbc_str());
408 //-----------------------------------------------------------------------------
410 //-----------------------------------------------------------------------------
412 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
414 if (g_isIdle
) wxapp_install_idle_handler();
416 if ((win
->m_x
== alloc
->x
) &&
417 (win
->m_y
== alloc
->y
) &&
418 (win
->m_width
== alloc
->width
) &&
419 (win
->m_height
== alloc
->height
) &&
425 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
428 //-----------------------------------------------------------------------------
429 // InsertChild callback for wxMDIClientWindow
430 //-----------------------------------------------------------------------------
432 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
434 wxString s
= child
->m_title
;
435 if (s
.IsNull()) s
= _("MDI child");
437 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
438 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
440 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
441 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
443 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
445 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
447 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
449 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
450 parent_frame
->m_justInserted
= TRUE
;
453 //-----------------------------------------------------------------------------
455 //-----------------------------------------------------------------------------
457 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
459 wxMDIClientWindow::wxMDIClientWindow()
463 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
465 CreateClient( parent
, style
);
468 wxMDIClientWindow::~wxMDIClientWindow()
472 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
476 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
478 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
479 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
481 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
485 m_widget
= gtk_notebook_new();
487 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
488 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
490 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
492 m_parent
->DoAddChild( this );