]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/mdi.cpp
Borland has only lfind
[wxWidgets.git] / src / gtk / mdi.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/mdi.cpp
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#if wxUSE_MDI
14
15#include "wx/mdi.h"
16
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
19 #include "wx/menu.h"
20 #include "wx/dialog.h"
21#endif
22
23#include "wx/notebook.h"
24#include "wx/gtk/private.h"
25
26#include <gtk/gtk.h>
27#include "wx/gtk/win_gtk.h"
28
29//-----------------------------------------------------------------------------
30// constants
31//-----------------------------------------------------------------------------
32
33const int wxMENU_HEIGHT = 27;
34
35//-----------------------------------------------------------------------------
36// globals
37//-----------------------------------------------------------------------------
38
39//-----------------------------------------------------------------------------
40// "switch_page"
41//-----------------------------------------------------------------------------
42
43extern "C" {
44static void
45gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
46 GtkNotebookPage *page,
47 gint WXUNUSED(page_num),
48 wxMDIParentFrame *parent )
49{
50 // send deactivate event to old child
51
52 wxMDIChildFrame *child = parent->GetActiveChild();
53 if (child)
54 {
55 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
56 event1.SetEventObject( child);
57 child->GetEventHandler()->ProcessEvent( event1 );
58 }
59
60 // send activate event to new child
61
62 wxMDIClientWindow *client_window = parent->GetClientWindow();
63 if (!client_window)
64 return;
65
66 child = (wxMDIChildFrame*) NULL;
67
68 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
69 while ( node )
70 {
71 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
72
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 )
77 {
78 child = child_frame;
79 break;
80 }
81 node = node->GetNext();
82 }
83
84 if (!child)
85 return;
86
87 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
88 event2.SetEventObject( child);
89 child->GetEventHandler()->ProcessEvent( event2 );
90}
91}
92
93//-----------------------------------------------------------------------------
94// wxMDIParentFrame
95//-----------------------------------------------------------------------------
96
97IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
98
99void wxMDIParentFrame::Init()
100{
101 m_justInserted = false;
102 m_clientWindow = (wxMDIClientWindow *) NULL;
103}
104
105wxMDIParentFrame::~wxMDIParentFrame()
106{
107}
108
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 )
116{
117 wxFrame::Create( parent, id, title, pos, size, style, name );
118
119 OnCreateClient();
120
121 return true;
122}
123
124void wxMDIParentFrame::GtkOnSize()
125{
126 wxFrame::GtkOnSize();
127
128 wxMDIChildFrame *child_frame = GetActiveChild();
129 if (!child_frame) return;
130
131 wxMenuBar *menu_bar = child_frame->m_menuBar;
132 if (!menu_bar) return;
133 if (!menu_bar->m_widget) return;
134
135 menu_bar->m_x = 0;
136 menu_bar->m_y = 0;
137 GTKDoGetSize(&menu_bar->m_width, NULL);
138 menu_bar->m_height = wxMENU_HEIGHT;
139 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
140 menu_bar->m_widget,
141 0, 0, menu_bar->m_width, menu_bar->m_height);
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)
152 {
153 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
154 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
155
156 /* need to set the menubar of the child */
157 wxMDIChildFrame *active_child_frame = GetActiveChild();
158 if (active_child_frame != NULL)
159 {
160 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
161 if (menu_bar)
162 {
163 GTKDoGetSize(&menu_bar->m_width, NULL);
164 menu_bar->m_height = wxMENU_HEIGHT;
165 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
166 menu_bar->m_widget,
167 0, 0, menu_bar->m_width, menu_bar->m_height);
168 menu_bar->SetInvokingWindow(active_child_frame);
169 }
170 }
171 m_justInserted = false;
172 return;
173 }
174
175 wxFrame::OnInternalIdle();
176
177 wxMDIChildFrame *active_child_frame = GetActiveChild();
178 bool visible_child_menu = false;
179
180 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
181 while (node)
182 {
183 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
184
185 if ( child_frame )
186 {
187 wxMenuBar *menu_bar = child_frame->m_menuBar;
188 if ( menu_bar )
189 {
190 if (child_frame == active_child_frame)
191 {
192 if (menu_bar->Show(true))
193 {
194 GTKDoGetSize(&menu_bar->m_width, NULL);
195 menu_bar->m_height = wxMENU_HEIGHT;
196 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
197 menu_bar->m_widget,
198 0, 0, menu_bar->m_width, menu_bar->m_height);
199 menu_bar->SetInvokingWindow( child_frame );
200 }
201 visible_child_menu = true;
202 }
203 else
204 {
205 if (menu_bar->Show(false))
206 {
207 menu_bar->UnsetInvokingWindow( child_frame );
208 }
209 }
210 }
211 }
212
213 node = node->GetNext();
214 }
215
216 /* show/hide parent menu bar as required */
217 if ((m_frameMenuBar) &&
218 (m_frameMenuBar->IsShown() == visible_child_menu))
219 {
220 if (visible_child_menu)
221 {
222 m_frameMenuBar->Show( false );
223 m_frameMenuBar->UnsetInvokingWindow( this );
224 }
225 else
226 {
227 m_frameMenuBar->Show( true );
228 m_frameMenuBar->SetInvokingWindow( this );
229
230 GTKDoGetSize(&m_frameMenuBar->m_width, NULL);
231 m_frameMenuBar->m_height = wxMENU_HEIGHT;
232 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
233 m_frameMenuBar->m_widget,
234 0, 0, m_frameMenuBar->m_width, m_frameMenuBar->m_height);
235 }
236 }
237}
238
239wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
240{
241 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
242
243 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
244 if (!notebook) return (wxMDIChildFrame*) NULL;
245
246 gint i = gtk_notebook_get_current_page( notebook );
247 if (i < 0) return (wxMDIChildFrame*) NULL;
248
249 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
250 if (!page) return (wxMDIChildFrame*) NULL;
251
252 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
253 while (node)
254 {
255 if ( wxPendingDelete.Member(node->GetData()) )
256 return (wxMDIChildFrame*) NULL;
257
258 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
259
260 if (!child_frame)
261 return (wxMDIChildFrame*) NULL;
262
263 if (child_frame->m_page == page)
264 return child_frame;
265
266 node = node->GetNext();
267 }
268
269 return (wxMDIChildFrame*) NULL;
270}
271
272wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
273{
274 return m_clientWindow;
275}
276
277wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
278{
279 m_clientWindow = new wxMDIClientWindow( this );
280 return m_clientWindow;
281}
282
283void wxMDIParentFrame::ActivateNext()
284{
285 if (m_clientWindow)
286 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
287}
288
289void wxMDIParentFrame::ActivatePrevious()
290{
291 if (m_clientWindow)
292 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
293}
294
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
307//-----------------------------------------------------------------------------
308// wxMDIChildFrame
309//-----------------------------------------------------------------------------
310
311IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
312
313BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
314 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
315 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
316END_EVENT_TABLE()
317
318wxMDIChildFrame::wxMDIChildFrame()
319{
320 m_menuBar = (wxMenuBar *) NULL;
321 m_page = (GtkNotebookPage *) NULL;
322}
323
324wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
325 wxWindowID id, const wxString& title,
326 const wxPoint& WXUNUSED(pos), const wxSize& size,
327 long style, const wxString& name )
328{
329 m_menuBar = (wxMenuBar *) NULL;
330 m_page = (GtkNotebookPage *) NULL;
331 Create( parent, id, title, wxDefaultPosition, size, style, name );
332}
333
334wxMDIChildFrame::~wxMDIChildFrame()
335{
336 if (m_menuBar)
337 delete m_menuBar;
338}
339
340bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
341 wxWindowID id, const wxString& title,
342 const wxPoint& WXUNUSED(pos), const wxSize& size,
343 long style, const wxString& name )
344{
345 m_title = title;
346
347 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
348}
349
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
363void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
364{
365 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
366}
367
368void wxMDIChildFrame::AddChild( wxWindowBase *child )
369{
370 wxWindow::AddChild(child);
371}
372
373void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
374{
375 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
376
377 m_menuBar = menu_bar;
378
379 if (m_menuBar)
380 {
381 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
382
383 m_menuBar->SetParent( mdi_frame );
384
385 /* insert the invisible menu bar into the _parent_ mdi frame */
386 int w;
387 mdi_frame->GTKDoGetSize(&w, NULL);
388 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
389 m_menuBar->m_widget,
390 0, 0, w, wxMENU_HEIGHT);
391 }
392}
393
394wxMenuBar *wxMDIChildFrame::GetMenuBar() const
395{
396 return m_menuBar;
397}
398
399void wxMDIChildFrame::Activate()
400{
401 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
402 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
403 gint pageno = gtk_notebook_page_num( notebook, m_widget );
404 gtk_notebook_set_current_page( notebook, pageno );
405}
406
407void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
408{
409}
410
411void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
412{
413#if wxUSE_STATUSBAR
414 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
415 if ( !ShowMenuHelp(event.GetMenuId()) )
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);
433 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
434}
435
436//-----------------------------------------------------------------------------
437// "size_allocate"
438//-----------------------------------------------------------------------------
439
440extern "C" {
441static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxMDIChildFrame *win )
442{
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))
448 {
449 return;
450 }
451
452 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
453}
454}
455
456//-----------------------------------------------------------------------------
457// InsertChild callback for wxMDIClientWindow
458//-----------------------------------------------------------------------------
459
460static void wxInsertChildInMDI(wxWindow* parent, wxWindow* child)
461{
462 wxMDIChildFrame* child_frame = wx_static_cast(wxMDIChildFrame*, child);
463 wxString s = child_frame->GetTitle();
464 if (s.IsNull()) s = _("MDI child");
465
466 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
467 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
468
469 g_signal_connect (child->m_widget, "size_allocate",
470 G_CALLBACK (gtk_page_size_callback), child);
471
472 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
473
474 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
475
476 child_frame->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
477
478 wxMDIParentFrame *parent_frame = wx_static_cast(wxMDIParentFrame*, parent->GetParent());
479 parent_frame->m_justInserted = true;
480}
481
482//-----------------------------------------------------------------------------
483// wxMDIClientWindow
484//-----------------------------------------------------------------------------
485
486IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
487
488wxMDIClientWindow::wxMDIClientWindow()
489{
490}
491
492wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
493{
494 CreateClient( parent, style );
495}
496
497wxMDIClientWindow::~wxMDIClientWindow()
498{
499
500}
501
502bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
503{
504 m_insertCallback = wxInsertChildInMDI;
505
506 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
507 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
508 {
509 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
510 return false;
511 }
512
513 m_widget = gtk_notebook_new();
514
515 g_signal_connect (m_widget, "switch_page",
516 G_CALLBACK (gtk_mdi_page_change_callback), parent);
517
518 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
519
520 m_parent->DoAddChild( this );
521
522 PostCreation();
523
524 Show( true );
525
526 return true;
527}
528
529#endif // wxUSE_MDI