]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/mdi.cpp
Implemented tearoff menus, please see my posting to wxwin-developers.
[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"
1a5a8367 20#include <wx/intl.h>
716b7364 21
83624f79
RR
22#include "glib.h"
23#include "gdk/gdk.h"
24#include "gtk/gtk.h"
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
6ca41e57
RR
46//-----------------------------------------------------------------------------
47// wxMDIParentFrame
33d0b396
RR
48//-----------------------------------------------------------------------------
49
c801d85f
KB
50IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
51
716b7364
RR
52BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
53END_EVENT_TABLE()
54
ab2b3dd4 55wxMDIParentFrame::wxMDIParentFrame()
c801d85f 56{
ab2b3dd4 57 m_justInserted = FALSE;
83624f79 58 m_clientWindow = (wxMDIClientWindow *) NULL;
ff7b1510 59}
c801d85f
KB
60
61wxMDIParentFrame::wxMDIParentFrame( wxWindow *parent,
debe6624 62 wxWindowID id, const wxString& title,
c801d85f 63 const wxPoint& pos, const wxSize& size,
debe6624 64 long style, const wxString& name )
c801d85f 65{
ab2b3dd4 66 m_justInserted = FALSE;
83624f79 67 m_clientWindow = (wxMDIClientWindow *) NULL;
83624f79 68 Create( parent, id, title, pos, size, style, name );
ff7b1510 69}
c801d85f 70
ab2b3dd4 71wxMDIParentFrame::~wxMDIParentFrame()
c801d85f 72{
ff7b1510 73}
c801d85f
KB
74
75bool wxMDIParentFrame::Create( wxWindow *parent,
debe6624 76 wxWindowID id, const wxString& title,
c801d85f 77 const wxPoint& pos, const wxSize& size,
debe6624 78 long style, const wxString& name )
c801d85f 79{
83624f79 80 wxFrame::Create( parent, id, title, pos, size, style, name );
a3622daa 81
83624f79 82 OnCreateClient();
a3622daa 83
83624f79 84 return TRUE;
ff7b1510 85}
c801d85f 86
716b7364 87void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 88{
83624f79 89 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 90
ab2b3dd4
RR
91 wxMDIChildFrame *child_frame = GetActiveChild();
92 if (!child_frame) return;
a0fdacee 93
ab2b3dd4
RR
94 wxMenuBar *menu_bar = child_frame->m_menuBar;
95 if (!menu_bar) return;
a2053b27 96 if (!menu_bar->m_widget) return;
a0fdacee 97
121a3581
RR
98 menu_bar->m_x = 0;
99 menu_bar->m_y = 0;
100 menu_bar->m_width = m_width;
101 menu_bar->m_height = wxMENU_HEIGHT;
fdd3ed7a 102 gtk_myfixed_set_size( GTK_MYFIXED(m_mainWidget),
a2053b27 103 menu_bar->m_widget,
f03fc89f 104 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
105}
106
107void wxMDIParentFrame::OnInternalIdle()
108{
109 /* if a an MDI child window has just been inserted
110 it has to be brought to the top in idle time. we
111 simply set the last notebook page active as new
112 pages can only be appended at the end */
113
114 if (m_justInserted)
83624f79 115 {
a2053b27 116 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
117 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
118
119 m_justInserted = FALSE;
120 return;
83624f79 121 }
a0fdacee 122
ab2b3dd4 123 wxFrame::OnInternalIdle();
c626a8b7 124
ab2b3dd4 125 wxMDIChildFrame *active_child_frame = GetActiveChild();
a260fe6a 126 bool visible_child_menu = FALSE;
a0fdacee 127
f03fc89f 128 wxNode *node = m_clientWindow->GetChildren().First();
ab2b3dd4 129 while (node)
83624f79 130 {
ab2b3dd4 131 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
5bd9e519 132 wxMenuBar *menu_bar = child_frame->m_menuBar;
a0fdacee
VZ
133 if (child_frame->m_menuBar)
134 {
135 if (child_frame == active_child_frame)
f03fc89f 136 {
5bd9e519
RR
137 if (menu_bar->Show(TRUE))
138 {
139 menu_bar->m_width = m_width;
140 menu_bar->m_height = wxMENU_HEIGHT;
141 gtk_myfixed_set_size( GTK_MYFIXED(m_mainWidget),
142 menu_bar->m_widget,
143 0, 0, m_width, wxMENU_HEIGHT );
144 menu_bar->SetInvokingWindow( child_frame );
145 }
146 visible_child_menu = TRUE;
f03fc89f 147 }
a0fdacee 148 else
5bd9e519
RR
149 {
150 if (menu_bar->Show(FALSE))
151 {
152 menu_bar->UnsetInvokingWindow( child_frame );
153 }
154 }
a0fdacee 155 }
ab2b3dd4 156 node = node->Next();
83624f79 157 }
a0fdacee 158
e27ce4e9 159 /* show/hide parent menu bar as required */
5bd9e519
RR
160 if ((m_frameMenuBar) &&
161 (m_frameMenuBar->IsShown() == visible_child_menu))
162 {
163 if (visible_child_menu)
164 {
165 m_frameMenuBar->Show( FALSE );
166 m_frameMenuBar->UnsetInvokingWindow( this );
167 }
168 else
169 {
170 m_frameMenuBar->Show( TRUE );
171 m_frameMenuBar->SetInvokingWindow( this );
172
173 m_frameMenuBar->m_width = m_width;
174 m_frameMenuBar->m_height = wxMENU_HEIGHT;
175 gtk_myfixed_set_size( GTK_MYFIXED(m_mainWidget),
176 m_frameMenuBar->m_widget,
177 0, 0, m_width, wxMENU_HEIGHT );
178 }
179 }
ff7b1510 180}
716b7364
RR
181
182void wxMDIParentFrame::GetClientSize(int *width, int *height ) const
c801d85f 183{
83624f79 184 wxFrame::GetClientSize( width, height );
ff7b1510 185}
c801d85f 186
ab2b3dd4
RR
187wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
188{
189 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
a0fdacee 190
a2053b27 191 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
ab2b3dd4 192 if (!notebook) return (wxMDIChildFrame*) NULL;
a0fdacee
VZ
193
194#if (GTK_MINOR_VERSION > 0)
ab2b3dd4 195 gint i = gtk_notebook_get_current_page( notebook );
a0fdacee
VZ
196#else
197 gint i = gtk_notebook_current_page( notebook );
198#endif
ab2b3dd4 199 if (i < 0) return (wxMDIChildFrame*) NULL;
a0fdacee 200
ab2b3dd4
RR
201 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
202 if (!page) return (wxMDIChildFrame*) NULL;
a0fdacee 203
f03fc89f 204 wxNode *node = m_clientWindow->GetChildren().First();
ab2b3dd4
RR
205 while (node)
206 {
207 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
208 if (child_frame->m_page == page)
209 return child_frame;
210 node = node->Next();
211 }
a0fdacee 212
ab2b3dd4 213 return (wxMDIChildFrame*) NULL;
ff7b1510 214}
c801d85f 215
ab2b3dd4 216wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
c801d85f 217{
83624f79 218 return m_clientWindow;
ff7b1510 219}
c801d85f 220
ab2b3dd4 221wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
c801d85f 222{
83624f79
RR
223 m_clientWindow = new wxMDIClientWindow( this );
224 return m_clientWindow;
ff7b1510 225}
c801d85f 226
ab2b3dd4 227void wxMDIParentFrame::ActivateNext()
c801d85f 228{
83624f79 229 if (m_clientWindow)
a2053b27 230 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 231}
c801d85f 232
ab2b3dd4 233void wxMDIParentFrame::ActivatePrevious()
716b7364 234{
83624f79 235 if (m_clientWindow)
a2053b27 236 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 237}
716b7364
RR
238
239void wxMDIParentFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
c801d85f 240{
ff7b1510 241}
c801d85f
KB
242
243void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent& WXUNUSED(event) )
244{
ff7b1510 245}
c801d85f
KB
246
247//-----------------------------------------------------------------------------
248// wxMDIChildFrame
249//-----------------------------------------------------------------------------
250
cf4219e7 251IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 252
cf4219e7 253BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 254 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
716b7364
RR
255END_EVENT_TABLE()
256
ab2b3dd4 257wxMDIChildFrame::wxMDIChildFrame()
c801d85f 258{
83624f79
RR
259 m_menuBar = (wxMenuBar *) NULL;
260 m_page = (GtkNotebookPage *) NULL;
ff7b1510 261}
c801d85f
KB
262
263wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
debe6624 264 wxWindowID id, const wxString& title,
33d0b396 265 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 266 long style, const wxString& name )
c801d85f 267{
83624f79
RR
268 m_menuBar = (wxMenuBar *) NULL;
269 m_page = (GtkNotebookPage *) NULL;
270 Create( parent, id, title, wxDefaultPosition, size, style, name );
ff7b1510 271}
c801d85f 272
ab2b3dd4 273wxMDIChildFrame::~wxMDIChildFrame()
c801d85f 274{
83624f79 275 if (m_menuBar)
83624f79 276 delete m_menuBar;
ff7b1510 277}
c801d85f
KB
278
279bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 280 wxWindowID id, const wxString& title,
33d0b396 281 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 282 long style, const wxString& name )
c801d85f 283{
83624f79 284 m_title = title;
c626a8b7 285
83624f79 286 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 287}
c801d85f 288
cf4219e7 289void wxMDIChildFrame::GetClientSize( int *width, int *height ) const
c801d85f 290{
83624f79 291 wxWindow::GetClientSize( width, height );
cf4219e7 292}
9746a2ba 293
cf4219e7 294void wxMDIChildFrame::AddChild( wxWindow *child )
716b7364 295{
83624f79 296 wxWindow::AddChild( child );
716b7364 297}
c626a8b7 298
716b7364
RR
299void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
300{
5bd9e519
RR
301 wxASSERT_MSG( m_menuBar == NULL, _T("Only one menubar allowed") );
302
83624f79 303 m_menuBar = menu_bar;
a3622daa 304
83624f79 305 if (m_menuBar)
716b7364 306 {
f03fc89f 307 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 308
5bd9e519 309 m_menuBar->SetParent( mdi_frame );
c626a8b7 310
ab2b3dd4 311 /* insert the invisible menu bar into the _parent_ mdi frame */
fdd3ed7a 312 gtk_myfixed_put( GTK_MYFIXED(mdi_frame->m_mainWidget),
a2053b27
RR
313 m_menuBar->m_widget,
314 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 315 }
ff7b1510 316}
cf4219e7 317
33b64e6f 318wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 319{
83624f79 320 return m_menuBar;
ff7b1510 321}
c801d85f 322
ab2b3dd4 323void wxMDIChildFrame::Activate()
c801d85f 324{
adde8c98
RR
325#if (GTK_MINOR_VERSION > 0)
326 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
97560ce3 327 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
adde8c98
RR
328 gint pageno = gtk_notebook_page_num( notebook, m_page->child );
329 gtk_notebook_set_page( notebook, pageno );
97560ce3
RS
330#else
331 // the only way I can see to do this under gtk+ 1.0.X would
332 // be to keep track of page numbers, start at first and
333 // do "next" enough times to get to this page number - messy
334 // - J. Russell Smyth
335#endif
ff7b1510 336}
c801d85f 337
9746a2ba
RR
338void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
339{
ff7b1510 340}
9746a2ba 341
ab2b3dd4
RR
342//-----------------------------------------------------------------------------
343// "size_allocate"
344//-----------------------------------------------------------------------------
345
346static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
347{
acfd422a
RR
348 if (g_isIdle) wxapp_install_idle_handler();
349
a2053b27
RR
350 if ((win->m_x == alloc->x) &&
351 (win->m_y == alloc->y) &&
352 (win->m_width == alloc->width) &&
353 (win->m_height == alloc->height) &&
354 (win->m_sizeSet))
ab2b3dd4
RR
355 {
356 return;
357 }
358
359 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
360}
361
6ca41e57
RR
362//-----------------------------------------------------------------------------
363// InsertChild callback for wxMDIClientWindow
364//-----------------------------------------------------------------------------
365
366static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
367{
83624f79
RR
368 wxString s = child->m_title;
369 if (s.IsNull()) s = _("MDI child");
6ca41e57 370
ed9b9841 371 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 372 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 373
a2053b27 374 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 375 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 376
a2053b27 377 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 378
a2053b27 379 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 380
83624f79 381 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 382
f03fc89f 383 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
ab2b3dd4 384 parent_frame->m_justInserted = TRUE;
6ca41e57
RR
385}
386
c801d85f
KB
387//-----------------------------------------------------------------------------
388// wxMDIClientWindow
389//-----------------------------------------------------------------------------
390
391IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
392
ab2b3dd4 393wxMDIClientWindow::wxMDIClientWindow()
c801d85f 394{
ff7b1510 395}
c801d85f 396
debe6624 397wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
c801d85f 398{
83624f79 399 CreateClient( parent, style );
ff7b1510 400}
c801d85f 401
ab2b3dd4 402wxMDIClientWindow::~wxMDIClientWindow()
c801d85f 403{
ff7b1510 404}
c801d85f 405
debe6624 406bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 407{
83624f79 408 m_needParent = TRUE;
c626a8b7 409
83624f79 410 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 411
83624f79 412 PreCreation( parent, -1, wxPoint(10,10), wxSize(100,100), style, "wxMDIClientWindow" );
c801d85f 413
83624f79 414 m_widget = gtk_notebook_new();
a3622daa 415
83624f79 416 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 417
f03fc89f 418 m_parent->DoAddChild( this );
c626a8b7 419
83624f79 420 PostCreation();
a3622daa 421
83624f79 422 Show( TRUE );
a3622daa 423
83624f79 424 return TRUE;
ff7b1510 425}
c801d85f 426
dcf924a3 427#endif