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