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