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