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