1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "mdi.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
19 #if wxUSE_MDI_ARCHITECTURE
21 #include "wx/dialog.h"
24 #include "wx/gtk/private.h"
29 #include "wx/gtk/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
35 const int wxMENU_HEIGHT
= 27;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 extern void wxapp_install_idle_handler();
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 extern wxList wxPendingDelete
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
55 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
56 GtkNotebookPage
*page
,
57 gint
WXUNUSED(page_num
),
58 wxMDIParentFrame
*parent
)
61 wxapp_install_idle_handler();
63 // send deactivate event to old child
65 wxMDIChildFrame
*child
= parent
->GetActiveChild();
68 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
69 event1
.SetEventObject( child
);
70 child
->GetEventHandler()->ProcessEvent( event1
);
73 // send activate event to new child
75 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
79 child
= (wxMDIChildFrame
*) NULL
;
81 wxWindowList::compatibility_iterator node
= client_window
->GetChildren().GetFirst();
84 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
86 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
88 if (child_frame
->m_page
== page
)
93 node
= node
->GetNext();
99 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
100 event2
.SetEventObject( child
);
101 child
->GetEventHandler()->ProcessEvent( event2
);
104 //-----------------------------------------------------------------------------
106 //-----------------------------------------------------------------------------
108 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
110 void wxMDIParentFrame::Init()
112 m_justInserted
= false;
113 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
116 wxMDIParentFrame::~wxMDIParentFrame()
120 bool wxMDIParentFrame::Create(wxWindow
*parent
,
122 const wxString
& title
,
126 const wxString
& name
)
128 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
135 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
137 wxFrame::GtkOnSize( x
, y
, width
, height
);
139 wxMDIChildFrame
*child_frame
= GetActiveChild();
140 if (!child_frame
) return;
142 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
143 if (!menu_bar
) return;
144 if (!menu_bar
->m_widget
) return;
148 menu_bar
->m_width
= m_width
;
149 menu_bar
->m_height
= wxMENU_HEIGHT
;
150 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
152 0, 0, m_width
, wxMENU_HEIGHT
);
155 void wxMDIParentFrame::OnInternalIdle()
157 /* if a an MDI child window has just been inserted
158 it has to be brought to the top in idle time. we
159 simply set the last notebook page active as new
160 pages can only be appended at the end */
164 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
165 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
167 m_justInserted
= false;
171 wxFrame::OnInternalIdle();
173 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
174 bool visible_child_menu
= false;
176 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
179 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
183 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
186 if (child_frame
== active_child_frame
)
188 if (menu_bar
->Show(true))
190 menu_bar
->m_width
= m_width
;
191 menu_bar
->m_height
= wxMENU_HEIGHT
;
192 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
194 0, 0, m_width
, wxMENU_HEIGHT
);
195 menu_bar
->SetInvokingWindow( child_frame
);
197 visible_child_menu
= true;
201 if (menu_bar
->Show(false))
203 menu_bar
->UnsetInvokingWindow( child_frame
);
209 node
= node
->GetNext();
212 /* show/hide parent menu bar as required */
213 if ((m_frameMenuBar
) &&
214 (m_frameMenuBar
->IsShown() == visible_child_menu
))
216 if (visible_child_menu
)
218 m_frameMenuBar
->Show( false );
219 m_frameMenuBar
->UnsetInvokingWindow( this );
223 m_frameMenuBar
->Show( true );
224 m_frameMenuBar
->SetInvokingWindow( this );
226 m_frameMenuBar
->m_width
= m_width
;
227 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
228 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
229 m_frameMenuBar
->m_widget
,
230 0, 0, m_width
, wxMENU_HEIGHT
);
235 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
237 wxFrame::DoGetClientSize( width
, height
);
240 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
242 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
244 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
245 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
247 gint i
= gtk_notebook_get_current_page( notebook
);
248 if (i
< 0) return (wxMDIChildFrame
*) NULL
;
250 GtkNotebookPage
* page
= (GtkNotebookPage
*) (g_list_nth(notebook
->children
,i
)->data
);
251 if (!page
) return (wxMDIChildFrame
*) NULL
;
253 wxWindowList::compatibility_iterator node
= m_clientWindow
->GetChildren().GetFirst();
256 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
258 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
260 if (child_frame
->m_page
== page
)
262 node
= node
->GetNext();
265 return (wxMDIChildFrame
*) NULL
;
268 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
270 return m_clientWindow
;
273 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
275 m_clientWindow
= new wxMDIClientWindow( this );
276 return m_clientWindow
;
279 void wxMDIParentFrame::ActivateNext()
282 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
285 void wxMDIParentFrame::ActivatePrevious()
288 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
291 //-----------------------------------------------------------------------------
293 //-----------------------------------------------------------------------------
295 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
297 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
298 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
299 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
302 wxMDIChildFrame::wxMDIChildFrame()
304 m_menuBar
= (wxMenuBar
*) NULL
;
305 m_page
= (GtkNotebookPage
*) NULL
;
308 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
309 wxWindowID id
, const wxString
& title
,
310 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
311 long style
, const wxString
& name
)
313 m_menuBar
= (wxMenuBar
*) NULL
;
314 m_page
= (GtkNotebookPage
*) NULL
;
315 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
318 wxMDIChildFrame::~wxMDIChildFrame()
324 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
325 wxWindowID id
, const wxString
& title
,
326 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
327 long style
, const wxString
& name
)
331 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
334 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
336 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
339 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
341 wxWindow::DoSetClientSize( width
, height
);
344 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
346 wxWindow::DoGetClientSize( width
, height
);
349 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
351 wxWindow::AddChild(child
);
354 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
356 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
358 m_menuBar
= menu_bar
;
362 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
364 m_menuBar
->SetParent( mdi_frame
);
366 /* insert the invisible menu bar into the _parent_ mdi frame */
367 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
369 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
373 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
378 void wxMDIChildFrame::Activate()
380 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
381 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
382 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
383 gtk_notebook_set_page( notebook
, pageno
);
386 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
390 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
393 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
394 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
396 // we don't have any help text for this item, but may be the MDI frame
398 mdi_frame
->OnMenuHighlight(event
);
400 #endif // wxUSE_STATUSBAR
403 void wxMDIChildFrame::SetTitle( const wxString
&title
)
405 if ( title
== m_title
)
410 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
411 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
412 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
415 //-----------------------------------------------------------------------------
417 //-----------------------------------------------------------------------------
419 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
421 if (g_isIdle
) wxapp_install_idle_handler();
423 if ((win
->m_x
== alloc
->x
) &&
424 (win
->m_y
== alloc
->y
) &&
425 (win
->m_width
== alloc
->width
) &&
426 (win
->m_height
== alloc
->height
) &&
432 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
435 //-----------------------------------------------------------------------------
436 // InsertChild callback for wxMDIClientWindow
437 //-----------------------------------------------------------------------------
439 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
441 wxString s
= child
->m_title
;
442 if (s
.IsNull()) s
= _("MDI child");
444 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
445 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
447 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
448 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
450 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
452 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
454 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
456 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
457 parent_frame
->m_justInserted
= true;
460 //-----------------------------------------------------------------------------
462 //-----------------------------------------------------------------------------
464 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
466 wxMDIClientWindow::wxMDIClientWindow()
470 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
472 CreateClient( parent
, style
);
475 wxMDIClientWindow::~wxMDIClientWindow()
479 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
483 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
485 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
486 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
488 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
492 m_widget
= gtk_notebook_new();
494 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
495 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
497 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
499 m_parent
->DoAddChild( this );