]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Applied Kevin Hock's combobox patch for text update events
[wxWidgets.git] / src / gtk / mdi.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: mdi.cpp
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 10#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
c801d85f
KB
11#pragma implementation "mdi.h"
12#endif
13
14f355c2
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
c801d85f 17#include "wx/mdi.h"
1631916e 18#include "wx/notebook.h"
dcf924a3 19
efd17a1d 20#if wxUSE_MDI
dcf924a3 21
e3e65dac 22#include "wx/dialog.h"
cf4219e7 23#include "wx/menu.h"
3096bd2f 24#include "wx/intl.h"
fab591c5 25#include "wx/gtk/private.h"
716b7364 26
16c1f79c
RR
27#include <glib.h>
28#include <gdk/gdk.h>
29#include <gtk/gtk.h>
83624f79
RR
30#include "wx/gtk/win_gtk.h"
31
6ca41e57
RR
32//-----------------------------------------------------------------------------
33// constants
34//-----------------------------------------------------------------------------
35
a0fdacee 36const int wxMENU_HEIGHT = 27;
6ca41e57 37
acfd422a
RR
38//-----------------------------------------------------------------------------
39// idle system
40//-----------------------------------------------------------------------------
41
42extern void wxapp_install_idle_handler();
43extern bool g_isIdle;
44
6ca41e57
RR
45//-----------------------------------------------------------------------------
46// globals
716b7364
RR
47//-----------------------------------------------------------------------------
48
49extern wxList wxPendingDelete;
c801d85f 50
5e014a0c
RR
51//-----------------------------------------------------------------------------
52// "switch_page"
53//-----------------------------------------------------------------------------
54
f6bcfd97 55static void
7941ba11 56gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 57 GtkNotebookPage *page,
f6bcfd97
BP
58 gint WXUNUSED(page_num),
59 wxMDIParentFrame *parent )
5e014a0c 60{
f6bcfd97 61 if (g_isIdle)
5e014a0c
RR
62 wxapp_install_idle_handler();
63
e90196a5
RR
64 // send deactivate event to old child
65
5e014a0c 66 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
67 if (child)
68 {
b1d4dd7a 69 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5
RR
70 event1.SetEventObject( child);
71 child->GetEventHandler()->ProcessEvent( event1 );
72 }
f6bcfd97 73
e90196a5 74 // send activate event to new child
f6bcfd97 75
e90196a5
RR
76 wxMDIClientWindow *client_window = parent->GetClientWindow();
77 if (!client_window)
78 return;
79
80 child = (wxMDIChildFrame*) NULL;
81
222ed1d6 82 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
e90196a5
RR
83 while (node)
84 {
b1d4dd7a 85 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
1631916e
CE
86 // CE: we come here in the destructor with a null child_frame - I think because
87 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
88 // isn't deleted early enough
89 if (!child_frame)
90 return ;
b1d4dd7a 91
e90196a5 92 if (child_frame->m_page == page)
f6bcfd97 93 {
e90196a5 94 child = child_frame;
f6bcfd97
BP
95 break;
96 }
b1d4dd7a 97 node = node->GetNext();
e90196a5 98 }
f6bcfd97 99
e90196a5
RR
100 if (!child)
101 return;
f6bcfd97 102
b1d4dd7a 103 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5
RR
104 event2.SetEventObject( child);
105 child->GetEventHandler()->ProcessEvent( event2 );
5e014a0c
RR
106}
107
6ca41e57
RR
108//-----------------------------------------------------------------------------
109// wxMDIParentFrame
33d0b396
RR
110//-----------------------------------------------------------------------------
111
c801d85f
KB
112IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
113
f6bcfd97 114void wxMDIParentFrame::Init()
c801d85f 115{
b1d4dd7a 116 m_justInserted = false;
83624f79 117 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 118}
c801d85f 119
ab2b3dd4 120wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 121{
ff7b1510 122}
c801d85f 123
f6bcfd97
BP
124bool wxMDIParentFrame::Create(wxWindow *parent,
125 wxWindowID id,
126 const wxString& title,
127 const wxPoint& pos,
128 const wxSize& size,
129 long style,
130 const wxString& name )
c801d85f 131{
83624f79 132 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 133
83624f79 134 OnCreateClient();
a3622daa 135
b1d4dd7a 136 return true;
ff7b1510 137}
c801d85f 138
716b7364 139void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 140{
83624f79 141 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 142
ab2b3dd4
RR
143 wxMDIChildFrame *child_frame = GetActiveChild();
144 if (!child_frame) return;
a0fdacee 145
ab2b3dd4
RR
146 wxMenuBar *menu_bar = child_frame->m_menuBar;
147 if (!menu_bar) return;
a2053b27 148 if (!menu_bar->m_widget) return;
a0fdacee 149
121a3581
RR
150 menu_bar->m_x = 0;
151 menu_bar->m_y = 0;
152 menu_bar->m_width = m_width;
153 menu_bar->m_height = wxMENU_HEIGHT;
f6bcfd97
BP
154 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
155 menu_bar->m_widget,
f03fc89f 156 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
157}
158
159void wxMDIParentFrame::OnInternalIdle()
160{
161 /* if a an MDI child window has just been inserted
162 it has to be brought to the top in idle time. we
163 simply set the last notebook page active as new
164 pages can only be appended at the end */
165
166 if (m_justInserted)
83624f79 167 {
a2053b27 168 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
169 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
170
1d608029
CE
171 /* need to set the menubar of the child */
172 wxMDIChildFrame *active_child_frame = GetActiveChild();
173 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
174 menu_bar->m_width = m_width;
175 menu_bar->m_height = wxMENU_HEIGHT;
176 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
177 menu_bar->m_widget,
178 0, 0, m_width, wxMENU_HEIGHT );
179 menu_bar->SetInvokingWindow(active_child_frame);
180
b1d4dd7a 181 m_justInserted = false;
a0fdacee 182 return;
83624f79 183 }
a0fdacee 184
ab2b3dd4 185 wxFrame::OnInternalIdle();
c626a8b7 186
ab2b3dd4 187 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 188 bool visible_child_menu = false;
a0fdacee 189
222ed1d6 190 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 191 while (node)
83624f79 192 {
b1d4dd7a
RL
193 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
194
f6bcfd97 195 if ( child_frame )
a0fdacee 196 {
f6bcfd97
BP
197 wxMenuBar *menu_bar = child_frame->m_menuBar;
198 if ( menu_bar )
f03fc89f 199 {
f6bcfd97
BP
200 if (child_frame == active_child_frame)
201 {
b1d4dd7a 202 if (menu_bar->Show(true))
f6bcfd97
BP
203 {
204 menu_bar->m_width = m_width;
205 menu_bar->m_height = wxMENU_HEIGHT;
206 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
207 menu_bar->m_widget,
208 0, 0, m_width, wxMENU_HEIGHT );
209 menu_bar->SetInvokingWindow( child_frame );
210 }
b1d4dd7a 211 visible_child_menu = true;
f6bcfd97
BP
212 }
213 else
214 {
b1d4dd7a 215 if (menu_bar->Show(false))
f6bcfd97
BP
216 {
217 menu_bar->UnsetInvokingWindow( child_frame );
218 }
219 }
f03fc89f 220 }
a0fdacee 221 }
f6bcfd97 222
b1d4dd7a 223 node = node->GetNext();
83624f79 224 }
a0fdacee 225
e27ce4e9 226 /* show/hide parent menu bar as required */
5bd9e519
RR
227 if ((m_frameMenuBar) &&
228 (m_frameMenuBar->IsShown() == visible_child_menu))
229 {
230 if (visible_child_menu)
f6bcfd97 231 {
b1d4dd7a 232 m_frameMenuBar->Show( false );
f6bcfd97
BP
233 m_frameMenuBar->UnsetInvokingWindow( this );
234 }
235 else
236 {
b1d4dd7a 237 m_frameMenuBar->Show( true );
f6bcfd97
BP
238 m_frameMenuBar->SetInvokingWindow( this );
239
240 m_frameMenuBar->m_width = m_width;
241 m_frameMenuBar->m_height = wxMENU_HEIGHT;
242 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
243 m_frameMenuBar->m_widget,
244 0, 0, m_width, wxMENU_HEIGHT );
245 }
5bd9e519 246 }
ff7b1510 247}
716b7364 248
40d432c4 249void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
c801d85f 250{
40d432c4 251 wxFrame::DoGetClientSize( width, height );
ff7b1510 252}
c801d85f 253
ab2b3dd4
RR
254wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
255{
256 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 257
a2053b27 258 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 259 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee 260
ab2b3dd4
RR
261 gint i = gtk_notebook_get_current_page( notebook );
262 if (i < 0) return (wxMDIChildFrame*) NULL;
a0fdacee 263
ab2b3dd4
RR
264 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
265 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 266
222ed1d6 267 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
268 while (node)
269 {
b1d4dd7a
RL
270 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
271
272 wxASSERT_MSG( child_frame, _T("child is not a wxMDIChildFrame") );
273
ab2b3dd4
RR
274 if (child_frame->m_page == page)
275 return child_frame;
b1d4dd7a 276 node = node->GetNext();
ab2b3dd4 277 }
a0fdacee 278
ab2b3dd4 279 return (wxMDIChildFrame*) NULL;
ff7b1510 280}
c801d85f 281
ab2b3dd4 282wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 283{
83624f79 284 return m_clientWindow;
ff7b1510 285}
c801d85f 286
ab2b3dd4 287wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 288{
83624f79
RR
289 m_clientWindow = new wxMDIClientWindow( this );
290 return m_clientWindow;
ff7b1510 291}
c801d85f 292
ab2b3dd4 293void wxMDIParentFrame::ActivateNext()
c801d85f 294{
83624f79 295 if (m_clientWindow)
a2053b27 296 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 297}
c801d85f 298
ab2b3dd4 299void wxMDIParentFrame::ActivatePrevious()
716b7364 300{
83624f79 301 if (m_clientWindow)
a2053b27 302 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 303}
716b7364 304
c801d85f
KB
305//-----------------------------------------------------------------------------
306// wxMDIChildFrame
307//-----------------------------------------------------------------------------
308
cf4219e7 309IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 310
cf4219e7 311BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 312 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 313 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
314END_EVENT_TABLE()
315
ab2b3dd4 316wxMDIChildFrame::wxMDIChildFrame()
c801d85f 317{
83624f79
RR
318 m_menuBar = (wxMenuBar *) NULL;
319 m_page = (GtkNotebookPage *) NULL;
ff7b1510 320}
c801d85f
KB
321
322wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 323 wxWindowID id, const wxString& title,
33d0b396 324 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 325 long style, const wxString& name )
c801d85f 326{
83624f79
RR
327 m_menuBar = (wxMenuBar *) NULL;
328 m_page = (GtkNotebookPage *) NULL;
329 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 330}
c801d85f 331
ab2b3dd4 332wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 333{
83624f79 334 if (m_menuBar)
83624f79 335 delete m_menuBar;
1631916e 336}
c801d85f
KB
337
338bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 339 wxWindowID id, const wxString& title,
33d0b396 340 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 341 long style, const wxString& name )
c801d85f 342{
83624f79 343 m_title = title;
c626a8b7 344
83624f79 345 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 346}
c801d85f 347
ac0c857a
RR
348void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
349{
350 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
351}
352
353void wxMDIChildFrame::DoSetClientSize(int width, int height)
354{
355 wxWindow::DoSetClientSize( width, height );
356}
357
40d432c4 358void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
c801d85f 359{
40d432c4 360 wxWindow::DoGetClientSize( width, height );
cf4219e7 361}
9746a2ba 362
7a903311 363void wxMDIChildFrame::AddChild( wxWindowBase *child )
716b7364 364{
7a903311 365 wxWindow::AddChild(child);
716b7364 366}
c626a8b7 367
716b7364
RR
368void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
369{
223d09f6 370 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 371
83624f79 372 m_menuBar = menu_bar;
a3622daa 373
83624f79 374 if (m_menuBar)
716b7364 375 {
f03fc89f 376 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 377
5bd9e519 378 m_menuBar->SetParent( mdi_frame );
c626a8b7 379
ab2b3dd4 380 /* insert the invisible menu bar into the _parent_ mdi frame */
f6bcfd97
BP
381 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
382 m_menuBar->m_widget,
a2053b27 383 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 384 }
ff7b1510 385}
cf4219e7 386
33b64e6f 387wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 388{
83624f79 389 return m_menuBar;
ff7b1510 390}
c801d85f 391
ab2b3dd4 392void wxMDIChildFrame::Activate()
c801d85f 393{
adde8c98 394 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 395 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
9e691f46 396 gint pageno = gtk_notebook_page_num( notebook, m_widget );
adde8c98 397 gtk_notebook_set_page( notebook, pageno );
ff7b1510 398}
c801d85f 399
f6bcfd97
BP
400void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
401{
402}
403
404void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 405{
f6bcfd97
BP
406#if wxUSE_STATUSBAR
407 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
408 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
409 {
410 // we don't have any help text for this item, but may be the MDI frame
411 // does?
412 mdi_frame->OnMenuHighlight(event);
413 }
414#endif // wxUSE_STATUSBAR
415}
416
417void wxMDIChildFrame::SetTitle( const wxString &title )
418{
419 if ( title == m_title )
420 return;
421
422 m_title = title;
423
424 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
425 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
fab591c5 426 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 427}
9746a2ba 428
ab2b3dd4
RR
429//-----------------------------------------------------------------------------
430// "size_allocate"
431//-----------------------------------------------------------------------------
432
433static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
434{
acfd422a
RR
435 if (g_isIdle) wxapp_install_idle_handler();
436
a2053b27
RR
437 if ((win->m_x == alloc->x) &&
438 (win->m_y == alloc->y) &&
439 (win->m_width == alloc->width) &&
440 (win->m_height == alloc->height) &&
441 (win->m_sizeSet))
ab2b3dd4
RR
442 {
443 return;
444 }
445
446 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
447}
448
6ca41e57
RR
449//-----------------------------------------------------------------------------
450// InsertChild callback for wxMDIClientWindow
451//-----------------------------------------------------------------------------
452
453static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
454{
83624f79
RR
455 wxString s = child->m_title;
456 if (s.IsNull()) s = _("MDI child");
6ca41e57 457
ed9b9841 458 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 459 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 460
a2053b27 461 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 462 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 463
a2053b27 464 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 465
a2053b27 466 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 467
83624f79 468 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 469
f03fc89f 470 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
b1d4dd7a 471 parent_frame->m_justInserted = true;
6ca41e57
RR
472}
473
c801d85f
KB
474//-----------------------------------------------------------------------------
475// wxMDIClientWindow
476//-----------------------------------------------------------------------------
477
478IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
479
ab2b3dd4 480wxMDIClientWindow::wxMDIClientWindow()
c801d85f 481{
ff7b1510 482}
c801d85f 483
debe6624 484wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 485{
83624f79 486 CreateClient( parent, style );
ff7b1510 487}
c801d85f 488
ab2b3dd4 489wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 490{
1631916e 491
ff7b1510 492}
c801d85f 493
debe6624 494bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 495{
b1d4dd7a 496 m_needParent = true;
c626a8b7 497
83624f79 498 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 499
4dcaf11a 500 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
223d09f6 501 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 502 {
223d09f6 503 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 504 return false;
4dcaf11a 505 }
c801d85f 506
83624f79 507 m_widget = gtk_notebook_new();
a3622daa 508
5e014a0c
RR
509 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
510 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
511
83624f79 512 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 513
f03fc89f 514 m_parent->DoAddChild( this );
c626a8b7 515
83624f79 516 PostCreation();
a3622daa 517
b1d4dd7a 518 Show( true );
a3622daa 519
b1d4dd7a 520 return true;
ff7b1510 521}
c801d85f 522
dcf924a3 523#endif