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"
21 #include "wx/gtk/private.h"
26 #include "wx/gtk/win_gtk.h"
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 const int wxMENU_HEIGHT
= 27;
34 //-----------------------------------------------------------------------------
36 //-----------------------------------------------------------------------------
38 extern void wxapp_install_idle_handler();
41 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
45 extern wxList wxPendingDelete
;
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
52 gtk_mdi_page_change_callback( GtkNotebook
*WXUNUSED(widget
),
53 GtkNotebookPage
*page
,
54 gint
WXUNUSED(page_num
),
55 wxMDIParentFrame
*parent
)
58 wxapp_install_idle_handler();
60 // send deactivate event to old child
62 wxMDIChildFrame
*child
= parent
->GetActiveChild();
65 wxActivateEvent
event1( wxEVT_ACTIVATE
, false, child
->GetId() );
66 event1
.SetEventObject( child
);
67 child
->GetEventHandler()->ProcessEvent( event1
);
70 // send activate event to new child
72 wxMDIClientWindow
*client_window
= parent
->GetClientWindow();
76 child
= (wxMDIChildFrame
*) NULL
;
78 wxWindowList::Node
*node
= client_window
->GetChildren().GetFirst();
81 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
83 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
85 if (child_frame
->m_page
== page
)
90 node
= node
->GetNext();
96 wxActivateEvent
event2( wxEVT_ACTIVATE
, true, child
->GetId() );
97 event2
.SetEventObject( child
);
98 child
->GetEventHandler()->ProcessEvent( event2
);
101 //-----------------------------------------------------------------------------
103 //-----------------------------------------------------------------------------
105 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
,wxFrame
)
107 void wxMDIParentFrame::Init()
109 m_justInserted
= false;
110 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
113 wxMDIParentFrame::~wxMDIParentFrame()
117 bool wxMDIParentFrame::Create(wxWindow
*parent
,
119 const wxString
& title
,
123 const wxString
& name
)
125 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
132 void wxMDIParentFrame::GtkOnSize( int x
, int y
, int width
, int height
)
134 wxFrame::GtkOnSize( x
, y
, width
, height
);
136 wxMDIChildFrame
*child_frame
= GetActiveChild();
137 if (!child_frame
) return;
139 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
140 if (!menu_bar
) return;
141 if (!menu_bar
->m_widget
) return;
145 menu_bar
->m_width
= m_width
;
146 menu_bar
->m_height
= wxMENU_HEIGHT
;
147 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
149 0, 0, m_width
, wxMENU_HEIGHT
);
152 void wxMDIParentFrame::OnInternalIdle()
154 /* if a an MDI child window has just been inserted
155 it has to be brought to the top in idle time. we
156 simply set the last notebook page active as new
157 pages can only be appended at the end */
161 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
162 gtk_notebook_set_page( notebook
, g_list_length( notebook
->children
) - 1 );
164 m_justInserted
= false;
168 wxFrame::OnInternalIdle();
170 wxMDIChildFrame
*active_child_frame
= GetActiveChild();
171 bool visible_child_menu
= false;
173 wxWindowList::Node
*node
= m_clientWindow
->GetChildren().GetFirst();
176 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
180 wxMenuBar
*menu_bar
= child_frame
->m_menuBar
;
183 if (child_frame
== active_child_frame
)
185 if (menu_bar
->Show(true))
187 menu_bar
->m_width
= m_width
;
188 menu_bar
->m_height
= wxMENU_HEIGHT
;
189 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
191 0, 0, m_width
, wxMENU_HEIGHT
);
192 menu_bar
->SetInvokingWindow( child_frame
);
194 visible_child_menu
= true;
198 if (menu_bar
->Show(false))
200 menu_bar
->UnsetInvokingWindow( child_frame
);
206 node
= node
->GetNext();
209 /* show/hide parent menu bar as required */
210 if ((m_frameMenuBar
) &&
211 (m_frameMenuBar
->IsShown() == visible_child_menu
))
213 if (visible_child_menu
)
215 m_frameMenuBar
->Show( false );
216 m_frameMenuBar
->UnsetInvokingWindow( this );
220 m_frameMenuBar
->Show( true );
221 m_frameMenuBar
->SetInvokingWindow( this );
223 m_frameMenuBar
->m_width
= m_width
;
224 m_frameMenuBar
->m_height
= wxMENU_HEIGHT
;
225 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
226 m_frameMenuBar
->m_widget
,
227 0, 0, m_width
, wxMENU_HEIGHT
);
232 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
234 wxFrame::DoGetClientSize( width
, height
);
237 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
239 if (!m_clientWindow
) return (wxMDIChildFrame
*) NULL
;
241 GtkNotebook
*notebook
= GTK_NOTEBOOK(m_clientWindow
->m_widget
);
242 if (!notebook
) return (wxMDIChildFrame
*) NULL
;
244 gint i
= gtk_notebook_get_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 wxWindowList::Node
*node
= m_clientWindow
->GetChildren().GetFirst();
253 wxMDIChildFrame
*child_frame
= wxDynamicCast( node
->GetData(), wxMDIChildFrame
);
255 wxASSERT_MSG( child_frame
, _T("child is not a wxMDIChildFrame") );
257 if (child_frame
->m_page
== page
)
259 node
= node
->GetNext();
262 return (wxMDIChildFrame
*) NULL
;
265 wxMDIClientWindow
*wxMDIParentFrame::GetClientWindow() const
267 return m_clientWindow
;
270 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
272 m_clientWindow
= new wxMDIClientWindow( this );
273 return m_clientWindow
;
276 void wxMDIParentFrame::ActivateNext()
279 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
282 void wxMDIParentFrame::ActivatePrevious()
285 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow
->m_widget
) );
288 //-----------------------------------------------------------------------------
290 //-----------------------------------------------------------------------------
292 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
,wxFrame
)
294 BEGIN_EVENT_TABLE(wxMDIChildFrame
, wxFrame
)
295 EVT_ACTIVATE(wxMDIChildFrame::OnActivate
)
296 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight
)
299 wxMDIChildFrame::wxMDIChildFrame()
301 m_menuBar
= (wxMenuBar
*) NULL
;
302 m_page
= (GtkNotebookPage
*) NULL
;
305 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame
*parent
,
306 wxWindowID id
, const wxString
& title
,
307 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
308 long style
, const wxString
& name
)
310 m_menuBar
= (wxMenuBar
*) NULL
;
311 m_page
= (GtkNotebookPage
*) NULL
;
312 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
315 wxMDIChildFrame::~wxMDIChildFrame()
321 bool wxMDIChildFrame::Create( wxMDIParentFrame
*parent
,
322 wxWindowID id
, const wxString
& title
,
323 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
324 long style
, const wxString
& name
)
328 return wxWindow::Create( parent
->GetClientWindow(), id
, wxDefaultPosition
, size
, style
, name
);
331 void wxMDIChildFrame::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
333 wxWindow::DoSetSize( x
, y
, width
, height
, sizeFlags
);
336 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
338 wxWindow::DoSetClientSize( width
, height
);
341 void wxMDIChildFrame::DoGetClientSize( int *width
, int *height
) const
343 wxWindow::DoGetClientSize( width
, height
);
346 void wxMDIChildFrame::AddChild( wxWindowBase
*child
)
348 wxWindow::AddChild(child
);
351 void wxMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
353 wxASSERT_MSG( m_menuBar
== NULL
, wxT("Only one menubar allowed") );
355 m_menuBar
= menu_bar
;
359 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
361 m_menuBar
->SetParent( mdi_frame
);
363 /* insert the invisible menu bar into the _parent_ mdi frame */
364 gtk_pizza_put( GTK_PIZZA(mdi_frame
->m_mainWidget
),
366 0, 0, mdi_frame
->m_width
, wxMENU_HEIGHT
);
370 wxMenuBar
*wxMDIChildFrame::GetMenuBar() const
375 void wxMDIChildFrame::Activate()
377 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
378 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
379 gint pageno
= gtk_notebook_page_num( notebook
, m_widget
);
380 gtk_notebook_set_page( notebook
, pageno
);
383 void wxMDIChildFrame::OnActivate( wxActivateEvent
& WXUNUSED(event
) )
387 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent
& event
)
390 wxMDIParentFrame
*mdi_frame
= (wxMDIParentFrame
*)m_parent
->GetParent();
391 if ( !ShowMenuHelp(mdi_frame
->GetStatusBar(), event
.GetMenuId()) )
393 // we don't have any help text for this item, but may be the MDI frame
395 mdi_frame
->OnMenuHighlight(event
);
397 #endif // wxUSE_STATUSBAR
400 void wxMDIChildFrame::SetTitle( const wxString
&title
)
402 if ( title
== m_title
)
407 wxMDIParentFrame
* parent
= (wxMDIParentFrame
*) GetParent();
408 GtkNotebook
* notebook
= GTK_NOTEBOOK(parent
->m_widget
);
409 gtk_notebook_set_tab_label_text(notebook
, m_widget
, wxGTK_CONV( title
) );
412 //-----------------------------------------------------------------------------
414 //-----------------------------------------------------------------------------
416 static void gtk_page_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxWindow
*win
)
418 if (g_isIdle
) wxapp_install_idle_handler();
420 if ((win
->m_x
== alloc
->x
) &&
421 (win
->m_y
== alloc
->y
) &&
422 (win
->m_width
== alloc
->width
) &&
423 (win
->m_height
== alloc
->height
) &&
429 win
->SetSize( alloc
->x
, alloc
->y
, alloc
->width
, alloc
->height
);
432 //-----------------------------------------------------------------------------
433 // InsertChild callback for wxMDIClientWindow
434 //-----------------------------------------------------------------------------
436 static void wxInsertChildInMDI( wxMDIClientWindow
* parent
, wxMDIChildFrame
* child
)
438 wxString s
= child
->m_title
;
439 if (s
.IsNull()) s
= _("MDI child");
441 GtkWidget
*label_widget
= gtk_label_new( s
.mbc_str() );
442 gtk_misc_set_alignment( GTK_MISC(label_widget
), 0.0, 0.5 );
444 gtk_signal_connect( GTK_OBJECT(child
->m_widget
), "size_allocate",
445 GTK_SIGNAL_FUNC(gtk_page_size_callback
), (gpointer
)child
);
447 GtkNotebook
*notebook
= GTK_NOTEBOOK(parent
->m_widget
);
449 gtk_notebook_append_page( notebook
, child
->m_widget
, label_widget
);
451 child
->m_page
= (GtkNotebookPage
*) (g_list_last(notebook
->children
)->data
);
453 wxMDIParentFrame
*parent_frame
= (wxMDIParentFrame
*) parent
->GetParent();
454 parent_frame
->m_justInserted
= true;
457 //-----------------------------------------------------------------------------
459 //-----------------------------------------------------------------------------
461 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
,wxWindow
)
463 wxMDIClientWindow::wxMDIClientWindow()
467 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame
*parent
, long style
)
469 CreateClient( parent
, style
);
472 wxMDIClientWindow::~wxMDIClientWindow()
476 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame
*parent
, long style
)
480 m_insertCallback
= (wxInsertChildFunction
)wxInsertChildInMDI
;
482 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
483 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("wxMDIClientWindow") ))
485 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
489 m_widget
= gtk_notebook_new();
491 gtk_signal_connect( GTK_OBJECT(m_widget
), "switch_page",
492 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback
), (gpointer
)parent
);
494 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget
), 1 );
496 m_parent
->DoAddChild( this );