]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Second part of #15224 fix: AddRows, AddColumns (dghart)
[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 5// Copyright: (c) 1998 Robert Roebling
65571936 6// Licence: wxWindows licence
c801d85f
KB
7/////////////////////////////////////////////////////////////////////////////
8
14f355c2
VS
9// For compilers that support precompilation, includes "wx.h".
10#include "wx/wxprec.h"
11
88a7a4e1
WS
12#if wxUSE_MDI
13
c801d85f 14#include "wx/mdi.h"
dcf924a3 15
88a7a4e1
WS
16#ifndef WX_PRECOMP
17 #include "wx/intl.h"
3b3dc801 18 #include "wx/menu.h"
88a7a4e1 19#endif
dcf924a3 20
fab591c5 21#include "wx/gtk/private.h"
716b7364 22
5e014a0c
RR
23//-----------------------------------------------------------------------------
24// "switch_page"
25//-----------------------------------------------------------------------------
26
865bb325 27extern "C" {
f6bcfd97 28static void
385e8575 29switch_page(GtkNotebook* widget, GtkNotebookPage*, guint page_num, wxMDIParentFrame* parent)
5e014a0c 30{
e90196a5
RR
31 // send deactivate event to old child
32
5e014a0c 33 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
34 if (child)
35 {
b1d4dd7a 36 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5 37 event1.SetEventObject( child);
937013e0 38 child->HandleWindowEvent( event1 );
e90196a5 39 }
f6bcfd97 40
e90196a5 41 // send activate event to new child
f6bcfd97 42
d2824cdb
VZ
43 wxMDIClientWindowBase *client_window = parent->GetClientWindow();
44 if ( !client_window )
e90196a5
RR
45 return;
46
d2824cdb 47 child = NULL;
385e8575 48 GtkWidget* page = gtk_notebook_get_nth_page(widget, page_num);
e90196a5 49
222ed1d6 50 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
af6c0f1d 51 while ( node )
e90196a5 52 {
b1d4dd7a 53 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
b1d4dd7a 54
af6c0f1d
VZ
55 // child_frame can be NULL when this is called from dtor, probably
56 // because g_signal_connect (m_widget, "switch_page", (see below)
57 // isn't deleted early enough
385e8575 58 if (child_frame && child_frame->m_widget == page)
f6bcfd97 59 {
e90196a5 60 child = child_frame;
f6bcfd97
BP
61 break;
62 }
b1d4dd7a 63 node = node->GetNext();
e90196a5 64 }
f6bcfd97 65
e90196a5
RR
66 if (!child)
67 return;
f6bcfd97 68
b1d4dd7a 69 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5 70 event2.SetEventObject( child);
937013e0 71 child->HandleWindowEvent( event2 );
5e014a0c 72}
865bb325 73}
5e014a0c 74
6ca41e57
RR
75//-----------------------------------------------------------------------------
76// wxMDIParentFrame
33d0b396
RR
77//-----------------------------------------------------------------------------
78
c801d85f
KB
79IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
80
f6bcfd97 81void wxMDIParentFrame::Init()
c801d85f 82{
b1d4dd7a 83 m_justInserted = false;
ff7b1510 84}
c801d85f 85
f6bcfd97
BP
86bool wxMDIParentFrame::Create(wxWindow *parent,
87 wxWindowID id,
88 const wxString& title,
89 const wxPoint& pos,
90 const wxSize& size,
91 long style,
92 const wxString& name )
c801d85f 93{
6e42617a
VZ
94 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
95 return false;
a3622daa 96
6e42617a 97 m_clientWindow = OnCreateClient();
d2824cdb
VZ
98 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
99 return false;
a3622daa 100
d2824cdb 101 return true;
ff7b1510 102}
c801d85f 103
ab2b3dd4
RR
104void wxMDIParentFrame::OnInternalIdle()
105{
d2824cdb 106 /* if a MDI child window has just been inserted
ab2b3dd4
RR
107 it has to be brought to the top in idle time. we
108 simply set the last notebook page active as new
109 pages can only be appended at the end */
110
111 if (m_justInserted)
83624f79 112 {
a2053b27 113 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
385e8575 114 gtk_notebook_set_current_page(notebook, -1);
a0fdacee 115
147d6669 116 /* need to set the menubar of the child */
1d608029 117 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 118 if (active_child_frame != NULL)
147d6669 119 {
1b10056f
RD
120 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
121 if (menu_bar)
122 {
6abf7b63 123 menu_bar->Attach(active_child_frame);
1b10056f 124 }
147d6669 125 }
b1d4dd7a 126 m_justInserted = false;
a0fdacee 127 return;
83624f79 128 }
a0fdacee 129
ab2b3dd4 130 wxFrame::OnInternalIdle();
c626a8b7 131
ab2b3dd4 132 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 133 bool visible_child_menu = false;
a0fdacee 134
222ed1d6 135 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 136 while (node)
83624f79 137 {
b1d4dd7a
RL
138 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
139
f6bcfd97 140 if ( child_frame )
a0fdacee 141 {
f6bcfd97
BP
142 wxMenuBar *menu_bar = child_frame->m_menuBar;
143 if ( menu_bar )
f03fc89f 144 {
f6bcfd97
BP
145 if (child_frame == active_child_frame)
146 {
b1d4dd7a 147 if (menu_bar->Show(true))
f6bcfd97 148 {
6abf7b63
VZ
149 // Attach() asserts if we call it for an already
150 // attached menu bar so don't do it if we're already
151 // associated with this frame (it would be nice to get
152 // rid of this check and ensure that this doesn't
153 // happen...)
154 if ( menu_bar->GetFrame() != child_frame )
155 menu_bar->Attach( child_frame );
f6bcfd97 156 }
b1d4dd7a 157 visible_child_menu = true;
f6bcfd97
BP
158 }
159 else
160 {
b1d4dd7a 161 if (menu_bar->Show(false))
f6bcfd97 162 {
6abf7b63 163 menu_bar->Detach();
f6bcfd97
BP
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 );
6abf7b63 179 m_frameMenuBar->Detach();
f6bcfd97
BP
180 }
181 else
182 {
b1d4dd7a 183 m_frameMenuBar->Show( true );
6abf7b63 184 m_frameMenuBar->Attach( 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
b0d053c1 193 if (!m_useCachedClientSize && height)
cca410b3
PC
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;
1897abe1 202 gtk_widget_get_preferred_height(menubar->m_widget, NULL, &req.height);
cca410b3
PC
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{
d2824cdb 212 if (!m_clientWindow) return NULL;
a0fdacee 213
a2053b27 214 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
d2824cdb 215 if (!notebook) return NULL;
a0fdacee 216
ab2b3dd4 217 gint i = gtk_notebook_get_current_page( notebook );
d2824cdb 218 if (i < 0) return NULL;
f4322df6 219
385e8575 220 GtkWidget* page = gtk_notebook_get_nth_page(notebook, i);
d2824cdb 221 if (!page) return NULL;
a0fdacee 222
222ed1d6 223 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
224 while (node)
225 {
3811dacb 226 if ( wxPendingDelete.Member(node->GetData()) )
d2824cdb 227 return NULL;
f4322df6 228
b1d4dd7a
RL
229 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
230
3811dacb 231 if (!child_frame)
d2824cdb 232 return NULL;
b1d4dd7a 233
385e8575 234 if (child_frame->m_widget == page)
ab2b3dd4 235 return child_frame;
f4322df6 236
b1d4dd7a 237 node = node->GetNext();
ab2b3dd4 238 }
a0fdacee 239
d2824cdb 240 return NULL;
ff7b1510 241}
c801d85f 242
ab2b3dd4 243void wxMDIParentFrame::ActivateNext()
c801d85f 244{
83624f79 245 if (m_clientWindow)
a2053b27 246 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 247}
c801d85f 248
ab2b3dd4 249void wxMDIParentFrame::ActivatePrevious()
716b7364 250{
83624f79 251 if (m_clientWindow)
a2053b27 252 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 253}
716b7364 254
c801d85f
KB
255//-----------------------------------------------------------------------------
256// wxMDIChildFrame
257//-----------------------------------------------------------------------------
258
cf4219e7 259IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 260
cf4219e7 261BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 262 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 263 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
264END_EVENT_TABLE()
265
d2824cdb 266void wxMDIChildFrame::Init()
c801d85f 267{
d2824cdb 268 m_menuBar = NULL;
ff7b1510 269}
c801d85f 270
d2824cdb
VZ
271bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
272 wxWindowID id,
273 const wxString& title,
274 const wxPoint& WXUNUSED(pos),
275 const wxSize& size,
276 long style,
277 const wxString& name)
c801d85f 278{
d2824cdb
VZ
279 m_mdiParent = parent;
280 m_title = title;
281
282 return wxWindow::Create(parent->GetClientWindow(), id,
283 wxDefaultPosition, size,
284 style, name);
ff7b1510 285}
c801d85f 286
ab2b3dd4 287wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 288{
d2824cdb 289 delete m_menuBar;
002626c5
PC
290
291 // wxMDIClientWindow does not get redrawn properly after last child is removed
292 if (m_parent && m_parent->GetChildren().size() <= 1)
293 gtk_widget_queue_draw(m_parent->m_widget);
72c23f8e 294}
c801d85f 295
3ec3c160
PC
296void wxMDIChildFrame::GTKHandleRealized()
297{
298 // since m_widget is not a GtkWindow, must bypass wxTopLevelWindowGTK
299 wxTopLevelWindowBase::GTKHandleRealized();
300}
301
716b7364
RR
302void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
303{
d2824cdb 304 wxASSERT_MSG( m_menuBar == NULL, "Only one menubar allowed" );
5bd9e519 305
83624f79 306 m_menuBar = menu_bar;
a3622daa 307
83624f79 308 if (m_menuBar)
716b7364 309 {
f03fc89f 310 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 311
5bd9e519 312 m_menuBar->SetParent( mdi_frame );
c626a8b7 313
ab2b3dd4 314 /* insert the invisible menu bar into the _parent_ mdi frame */
cca410b3
PC
315 m_menuBar->Show(false);
316 gtk_box_pack_start(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, false, false, 0);
317 gtk_box_reorder_child(GTK_BOX(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0);
cca410b3 318 gtk_widget_set_size_request(m_menuBar->m_widget, -1, -1);
716b7364 319 }
ff7b1510 320}
cf4219e7 321
33b64e6f 322wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 323{
83624f79 324 return m_menuBar;
ff7b1510 325}
c801d85f 326
d2824cdb
VZ
327GtkNotebook *wxMDIChildFrame::GTKGetNotebook() const
328{
329 wxMDIClientWindow * const
330 client = wxStaticCast(GetParent(), wxMDIClientWindow);
331 wxCHECK( client, NULL );
332
333 return GTK_NOTEBOOK(client->m_widget);
334}
335
ab2b3dd4 336void wxMDIChildFrame::Activate()
c801d85f 337{
d2824cdb
VZ
338 GtkNotebook * const notebook = GTKGetNotebook();
339 wxCHECK_RET( notebook, "no parent notebook?" );
340
9e691f46 341 gint pageno = gtk_notebook_page_num( notebook, m_widget );
38f1df7c 342 gtk_notebook_set_current_page( notebook, pageno );
ff7b1510 343}
c801d85f 344
f6bcfd97
BP
345void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
346{
347}
348
349void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 350{
f6bcfd97
BP
351#if wxUSE_STATUSBAR
352 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 353 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
354 {
355 // we don't have any help text for this item, but may be the MDI frame
356 // does?
357 mdi_frame->OnMenuHighlight(event);
358 }
359#endif // wxUSE_STATUSBAR
360}
361
362void wxMDIChildFrame::SetTitle( const wxString &title )
363{
364 if ( title == m_title )
365 return;
366
367 m_title = title;
368
d2824cdb
VZ
369 GtkNotebook * const notebook = GTKGetNotebook();
370 wxCHECK_RET( notebook, "no parent notebook?" );
fab591c5 371 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 372}
9746a2ba 373
c801d85f
KB
374//-----------------------------------------------------------------------------
375// wxMDIClientWindow
376//-----------------------------------------------------------------------------
377
d2824cdb 378IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
c801d85f 379
5a0a15cf
FM
380wxMDIClientWindow::~wxMDIClientWindow()
381{
382 // disconnect our handler because our ~wxWindow (which is going to be called
383 // after this dtor) will call DestroyChildren(); in turns our children
384 // ~wxWindow dtors will call wxWindow::Show(false) and this will generate
385 // a call to gtk_mdi_page_change_callback with an invalid parent
386 // (because gtk_mdi_page_change_callback expects a wxMDIClientWindow but
387 // at that point of the dtor chain we are a simple wxWindow!)
385e8575 388 g_signal_handlers_disconnect_by_func(m_widget, (void*)switch_page, GetParent());
5a0a15cf
FM
389}
390
d2824cdb 391bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
c801d85f 392{
d2824cdb
VZ
393 if ( !PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
394 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
395 style, wxDefaultValidator, "wxMDIClientWindow" ))
4dcaf11a 396 {
d2824cdb 397 wxFAIL_MSG( "wxMDIClientWindow creation failed" );
b1d4dd7a 398 return false;
4dcaf11a 399 }
c801d85f 400
83624f79 401 m_widget = gtk_notebook_new();
9ff9d30c 402 g_object_ref(m_widget);
a3622daa 403
385e8575 404 g_signal_connect(m_widget, "switch_page", G_CALLBACK(switch_page), parent);
5e014a0c 405
83624f79 406 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 407
f03fc89f 408 m_parent->DoAddChild( this );
c626a8b7 409
83624f79 410 PostCreation();
a3622daa 411
b1d4dd7a 412 Show( true );
a3622daa 413
b1d4dd7a 414 return true;
ff7b1510 415}
c801d85f 416
d2824cdb
VZ
417void wxMDIClientWindow::AddChildGTK(wxWindowGTK* child)
418{
419 wxMDIChildFrame* child_frame = static_cast<wxMDIChildFrame*>(child);
420 wxString s = child_frame->GetTitle();
421 if ( s.empty() )
422 s = _("MDI child");
423
424 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
425 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
426
427 GtkNotebook* notebook = GTK_NOTEBOOK(m_widget);
428
429 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
430
d2824cdb
VZ
431 wxMDIParentFrame* parent_frame = static_cast<wxMDIParentFrame*>(GetParent());
432 parent_frame->m_justInserted = true;
433}
434
e8375af8 435#endif // wxUSE_MDI