]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Improve wxMenu docs
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
72c23f8e 2// Name: src/gtk/mdi.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
a81258be
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
88a7a4e1
WS
13#if wxUSE_MDI
14
c801d85f 15#include "wx/mdi.h"
dcf924a3 16
88a7a4e1
WS
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
3b3dc801 19 #include "wx/menu.h"
88a7a4e1 20#endif
dcf924a3 21
fab591c5 22#include "wx/gtk/private.h"
716b7364 23
5e014a0c
RR
24//-----------------------------------------------------------------------------
25// "switch_page"
26//-----------------------------------------------------------------------------
27
865bb325 28extern "C" {
f6bcfd97 29static void
7941ba11 30gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 31 GtkNotebookPage *page,
f6bcfd97
BP
32 gint WXUNUSED(page_num),
33 wxMDIParentFrame *parent )
5e014a0c 34{
e90196a5
RR
35 // send deactivate event to old child
36
5e014a0c 37 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
38 if (child)
39 {
b1d4dd7a 40 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5 41 event1.SetEventObject( child);
937013e0 42 child->HandleWindowEvent( event1 );
e90196a5 43 }
f6bcfd97 44
e90196a5 45 // send activate event to new child
f6bcfd97 46
e90196a5
RR
47 wxMDIClientWindow *client_window = parent->GetClientWindow();
48 if (!client_window)
49 return;
50
51 child = (wxMDIChildFrame*) NULL;
52
222ed1d6 53 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
af6c0f1d 54 while ( node )
e90196a5 55 {
b1d4dd7a 56 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
b1d4dd7a 57
af6c0f1d
VZ
58 // child_frame can be NULL when this is called from dtor, probably
59 // because g_signal_connect (m_widget, "switch_page", (see below)
60 // isn't deleted early enough
61 if ( child_frame && child_frame->m_page == page )
f6bcfd97 62 {
e90196a5 63 child = child_frame;
f6bcfd97
BP
64 break;
65 }
b1d4dd7a 66 node = node->GetNext();
e90196a5 67 }
f6bcfd97 68
e90196a5
RR
69 if (!child)
70 return;
f6bcfd97 71
b1d4dd7a 72 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5 73 event2.SetEventObject( child);
937013e0 74 child->HandleWindowEvent( event2 );
5e014a0c 75}
865bb325 76}
5e014a0c 77
6ca41e57
RR
78//-----------------------------------------------------------------------------
79// wxMDIParentFrame
33d0b396
RR
80//-----------------------------------------------------------------------------
81
c801d85f
KB
82IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
83
f6bcfd97 84void wxMDIParentFrame::Init()
c801d85f 85{
b1d4dd7a 86 m_justInserted = false;
83624f79 87 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 88}
c801d85f 89
ab2b3dd4 90wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 91{
ff7b1510 92}
c801d85f 93
f6bcfd97
BP
94bool wxMDIParentFrame::Create(wxWindow *parent,
95 wxWindowID id,
96 const wxString& title,
97 const wxPoint& pos,
98 const wxSize& size,
99 long style,
100 const wxString& name )
c801d85f 101{
6e42617a
VZ
102 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
103 return false;
a3622daa 104
6e42617a 105 m_clientWindow = OnCreateClient();
a3622daa 106
6e42617a 107 return m_clientWindow != NULL;
ff7b1510 108}
c801d85f 109
ab2b3dd4
RR
110void wxMDIParentFrame::OnInternalIdle()
111{
112 /* if a an MDI child window has just been inserted
113 it has to be brought to the top in idle time. we
114 simply set the last notebook page active as new
115 pages can only be appended at the end */
116
117 if (m_justInserted)
83624f79 118 {
a2053b27 119 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
38f1df7c 120 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
a0fdacee 121
147d6669 122 /* need to set the menubar of the child */
1d608029 123 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 124 if (active_child_frame != NULL)
147d6669 125 {
1b10056f
RD
126 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
127 if (menu_bar)
128 {
1b10056f
RD
129 menu_bar->SetInvokingWindow(active_child_frame);
130 }
147d6669 131 }
b1d4dd7a 132 m_justInserted = false;
a0fdacee 133 return;
83624f79 134 }
a0fdacee 135
ab2b3dd4 136 wxFrame::OnInternalIdle();
c626a8b7 137
ab2b3dd4 138 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 139 bool visible_child_menu = false;
a0fdacee 140
222ed1d6 141 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 142 while (node)
83624f79 143 {
b1d4dd7a
RL
144 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
145
f6bcfd97 146 if ( child_frame )
a0fdacee 147 {
f6bcfd97
BP
148 wxMenuBar *menu_bar = child_frame->m_menuBar;
149 if ( menu_bar )
f03fc89f 150 {
f6bcfd97
BP
151 if (child_frame == active_child_frame)
152 {
b1d4dd7a 153 if (menu_bar->Show(true))
f6bcfd97 154 {
f6bcfd97
BP
155 menu_bar->SetInvokingWindow( child_frame );
156 }
b1d4dd7a 157 visible_child_menu = true;
f6bcfd97
BP
158 }
159 else
160 {
b1d4dd7a 161 if (menu_bar->Show(false))
f6bcfd97
BP
162 {
163 menu_bar->UnsetInvokingWindow( child_frame );
164 }
165 }
f03fc89f 166 }
a0fdacee 167 }
f6bcfd97 168
b1d4dd7a 169 node = node->GetNext();
83624f79 170 }
a0fdacee 171
e27ce4e9 172 /* show/hide parent menu bar as required */
5bd9e519
RR
173 if ((m_frameMenuBar) &&
174 (m_frameMenuBar->IsShown() == visible_child_menu))
175 {
176 if (visible_child_menu)
f6bcfd97 177 {
b1d4dd7a 178 m_frameMenuBar->Show( false );
f6bcfd97
BP
179 m_frameMenuBar->UnsetInvokingWindow( this );
180 }
181 else
182 {
b1d4dd7a 183 m_frameMenuBar->Show( true );
f6bcfd97 184 m_frameMenuBar->SetInvokingWindow( this );
cca410b3
PC
185 }
186 }
187}
f6bcfd97 188
cca410b3
PC
189void wxMDIParentFrame::DoGetClientSize(int* width, int* height) const
190{
191 wxFrame::DoGetClientSize(width, height);
192
193 if (height)
194 {
195 wxMDIChildFrame* active_child_frame = GetActiveChild();
196 if (active_child_frame)
197 {
198 wxMenuBar* menubar = active_child_frame->m_menuBar;
199 if (menubar && menubar->IsShown())
200 {
201 GtkRequisition req;
202 gtk_widget_size_request(menubar->m_widget, &req);
203 *height -= req.height;
204 if (*height < 0) *height = 0;
205 }
f6bcfd97 206 }
5bd9e519 207 }
ff7b1510 208}
716b7364 209
ab2b3dd4
RR
210wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
211{
212 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 213
a2053b27 214 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 215 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee 216
ab2b3dd4
RR
217 gint i = gtk_notebook_get_current_page( notebook );
218 if (i < 0) return (wxMDIChildFrame*) NULL;
f4322df6 219
ab2b3dd4
RR
220 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
221 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 222
222ed1d6 223 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
224 while (node)
225 {
3811dacb
RR
226 if ( wxPendingDelete.Member(node->GetData()) )
227 return (wxMDIChildFrame*) NULL;
f4322df6 228
b1d4dd7a
RL
229 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
230
3811dacb
RR
231 if (!child_frame)
232 return (wxMDIChildFrame*) NULL;
b1d4dd7a 233
ab2b3dd4
RR
234 if (child_frame->m_page == page)
235 return child_frame;
f4322df6 236
b1d4dd7a 237 node = node->GetNext();
ab2b3dd4 238 }
a0fdacee 239
ab2b3dd4 240 return (wxMDIChildFrame*) NULL;
ff7b1510 241}
c801d85f 242
ab2b3dd4 243wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 244{
83624f79 245 return m_clientWindow;
ff7b1510 246}
c801d85f 247
ab2b3dd4 248wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 249{
6e42617a 250 return new wxMDIClientWindow( this );
ff7b1510 251}
c801d85f 252
ab2b3dd4 253void wxMDIParentFrame::ActivateNext()
c801d85f 254{
83624f79 255 if (m_clientWindow)
a2053b27 256 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 257}
c801d85f 258
ab2b3dd4 259void wxMDIParentFrame::ActivatePrevious()
716b7364 260{
83624f79 261 if (m_clientWindow)
a2053b27 262 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 263}
716b7364 264
c801d85f
KB
265//-----------------------------------------------------------------------------
266// wxMDIChildFrame
267//-----------------------------------------------------------------------------
268
cf4219e7 269IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 270
cf4219e7 271BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 272 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 273 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
274END_EVENT_TABLE()
275
ab2b3dd4 276wxMDIChildFrame::wxMDIChildFrame()
c801d85f 277{
83624f79
RR
278 m_menuBar = (wxMenuBar *) NULL;
279 m_page = (GtkNotebookPage *) NULL;
ff7b1510 280}
c801d85f
KB
281
282wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 283 wxWindowID id, const wxString& title,
33d0b396 284 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 285 long style, const wxString& name )
c801d85f 286{
83624f79
RR
287 m_menuBar = (wxMenuBar *) NULL;
288 m_page = (GtkNotebookPage *) NULL;
289 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 290}
c801d85f 291
ab2b3dd4 292wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 293{
83624f79 294 if (m_menuBar)
83624f79 295 delete m_menuBar;
002626c5
PC
296
297 // wxMDIClientWindow does not get redrawn properly after last child is removed
298 if (m_parent && m_parent->GetChildren().size() <= 1)
299 gtk_widget_queue_draw(m_parent->m_widget);
72c23f8e 300}
c801d85f
KB
301
302bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 303 wxWindowID id, const wxString& title,
33d0b396 304 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 305 long style, const wxString& name )
c801d85f 306{
83624f79 307 m_title = title;
c626a8b7 308
83624f79 309 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 310}
c801d85f 311
3811dacb
RR
312bool wxMDIChildFrame::Destroy()
313{
314 // delayed destruction: the frame will be deleted during
315 // the next idle loop iteration.
316 // I'm not sure if delayed destruction really makes so
317 // much sense for MDI child frames, actually, but hiding
318 // it doesn't make any sense.
319 if ( !wxPendingDelete.Member(this) )
320 wxPendingDelete.Append(this);
321
322 return true;
323}
324
ac0c857a
RR
325void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
326{
327 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
328}
329
7a903311 330void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 331{
7a903311 332 wxWindow::AddChild(child);
716b7364 333}
c626a8b7 334
716b7364
RR
335void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
336{
223d09f6 337 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 338
83624f79 339 m_menuBar = menu_bar;
a3622daa 340
83624f79 341 if (m_menuBar)
716b7364 342 {
f03fc89f 343 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 344
5bd9e519 345 m_menuBar->SetParent( mdi_frame );
c626a8b7 346
ab2b3dd4 347 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
348 m_menuBar->Show(false);
349 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
350 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
351
352 gulong handler_id = g_signal_handler_find(
353 m_menuBar->m_widget,
354 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
355 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
356 0, NULL, NULL, m_menuBar);
357 if (handler_id != 0)
358 g_signal_handler_disconnect(m_menuBar->m_widget, handler_id);
359 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 360 }
ff7b1510 361}
cf4219e7 362
33b64e6f 363wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 364{
83624f79 365 return m_menuBar;
ff7b1510 366}
c801d85f 367
ab2b3dd4 368void wxMDIChildFrame::Activate()
c801d85f 369{
adde8c98 370 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 371 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 372 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 373 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 374}
c801d85f 375
f6bcfd97
BP
376void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
377{
378}
379
380void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 381{
f6bcfd97
BP
382#if wxUSE_STATUSBAR
383 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 384 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
385 {
386 // we don't have any help text for this item, but may be the MDI frame
387 // does?
388 mdi_frame->OnMenuHighlight(event);
389 }
390#endif // wxUSE_STATUSBAR
391}
392
393void wxMDIChildFrame::SetTitle( const wxString &title )
394{
395 if ( title == m_title )
396 return;
397
398 m_title = title;
399
400 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
401 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 402 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 403}
9746a2ba 404
6ca41e57
RR
405//-----------------------------------------------------------------------------
406// InsertChild callback for wxMDIClientWindow
407//-----------------------------------------------------------------------------
408
c821db16 409static void wxInsertChildInMDI(wxWindow* parent, wxWindow* child)
6ca41e57 410{
c821db16
PC
411 wxMDIChildFrame* child_frame = wx_static_cast(wxMDIChildFrame*, child);
412 wxString s = child_frame->GetTitle();
83624f79 413 if (s.IsNull()) s = _("MDI child");
6ca41e57 414
ed9b9841 415 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 416 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 417
a2053b27 418 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 419
a2053b27 420 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 421
c821db16 422 child_frame->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 423
c821db16 424 wxMDIParentFrame *parent_frame = wx_static_cast(wxMDIParentFrame*, parent->GetParent());
b1d4dd7a 425 parent_frame->m_justInserted = true;
6ca41e57
RR
426}
427
c801d85f
KB
428//-----------------------------------------------------------------------------
429// wxMDIClientWindow
430//-----------------------------------------------------------------------------
431
432IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
433
ab2b3dd4 434wxMDIClientWindow::wxMDIClientWindow()
c801d85f 435{
ff7b1510 436}
c801d85f 437
debe6624 438wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 439{
83624f79 440 CreateClient( parent, style );
ff7b1510 441}
c801d85f 442
ab2b3dd4 443wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 444{
1631916e 445
ff7b1510 446}
c801d85f 447
debe6624 448bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 449{
c821db16 450 m_insertCallback = wxInsertChildInMDI;
a3622daa 451
4dcaf11a 452 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
72c23f8e 453 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 454 {
223d09f6 455 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 456 return false;
4dcaf11a 457 }
c801d85f 458
83624f79 459 m_widget = gtk_notebook_new();
a3622daa 460
9fa72bd2
MR
461 g_signal_connect (m_widget, "switch_page",
462 G_CALLBACK (gtk_mdi_page_change_callback), parent);
5e014a0c 463
83624f79 464 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 465
f03fc89f 466 m_parent->DoAddChild( this );
c626a8b7 467
83624f79 468 PostCreation();
a3622daa 469
b1d4dd7a 470 Show( true );
a3622daa 471
b1d4dd7a 472 return true;
ff7b1510 473}
c801d85f 474
e8375af8 475#endif // wxUSE_MDI