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
;
302 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
303 wxWindowID id
, const wxString
& title
,
304 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
305 long style
, const wxString
& name
)
307 m_menuBar
= (wxMenuBar
*) NULL
;
308 m_page
= (GtkNotebookPage
*) NULL
;
309 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
312 wxMDIChildFrame::~wxMDIChildFrame()
318 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
319 wxWindowID id
, const wxString
& title
,
320 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
321 long style
, const wxString
& name
)
325 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
328 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
330 wxWindow::DoGetClientSize( width
, height
);
333 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
335 wxWindow::AddChild(child
);
338 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
340 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
342 m_menuBar
= menu_bar
;
346 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
348 m_menuBar
->SetParent( mdi_frame
);
350 /* insert the invisible menu bar into the _parent_ mdi frame */
351 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
353 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
357 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
362 void wxMDIChildFrame::Activate()
364 #if defined(__WXGTK20__) || (GTK_MINOR_VERSION > 0)
365 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
366 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
367 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
368 gtk_notebook_set_page( notebook
, pageno
);
370 // the only way I can see to do this under gtk+ 1.0.X would
371 // be to keep track of page numbers, start at first and
372 // do "next" enough times to get to this page number - messy
373 // - J. Russell Smyth
377 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
381 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
384 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
385 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
387 // we don't have any help text for this item, but may be the MDI frame
389 mdi_frame
->OnMenuHighlight(event
);
391 #endif // wxUSE_STATUSBAR
394 void wxMDIChildFrame::SetTitle( const wxString
&title
)
396 if ( title
== m_title
)
401 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
402 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
403 gtk_notebook_set_tab_label_text(notebook
, m_widget
, title
.mbc_str());
406 //-----------------------------------------------------------------------------
408 //-----------------------------------------------------------------------------
410 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
412 if (g_isIdle
) wxapp_install_idle_handler();
414 if ((win
->m_x
== alloc
->x
) &&
415 (win
->m_y
== alloc
->y
) &&
416 (win
->m_width
== alloc
->width
) &&
417 (win
->m_height
== alloc
->height
) &&
423 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
426 //-----------------------------------------------------------------------------
427 // InsertChild callback for wxMDIClientWindow
428 //-----------------------------------------------------------------------------
430 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
432 wxString s
= child
->m_title
;
433 if (s
.IsNull()) s
= _("MDI child");
435 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
436 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
438 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
439 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
441 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
443 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
445 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
447 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
448 parent_frame
->m_justInserted
= TRUE
;
451 //-----------------------------------------------------------------------------
453 //-----------------------------------------------------------------------------
455 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
457 wxMDIClientWindow::wxMDIClientWindow()
461 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
463 CreateClient( parent
, style
);
466 wxMDIClientWindow::~wxMDIClientWindow()
470 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
474 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
476 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
477 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
479 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
483 m_widget
= gtk_notebook_new();
485 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
486 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
488 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
490 m_parent
->DoAddChild( this );