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