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