]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/mdi.cpp
Fix for #15520: wxRichTextCtrl: Drawing the selection doesn't respect its container...
[wxWidgets.git] / src / gtk1 / mdi.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
3cbab641 2// Name: src/gtk1/mdi.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
a81258be 5// Copyright: (c) 1998 Robert Roebling
65571936 6// Licence: wxWindows licence
c801d85f
KB
7/////////////////////////////////////////////////////////////////////////////
8
14f355c2
VS
9// For compilers that support precompilation, includes "wx.h".
10#include "wx/wxprec.h"
11
88a7a4e1
WS
12#if wxUSE_MDI
13
c801d85f 14#include "wx/mdi.h"
dcf924a3 15
88a7a4e1
WS
16#ifndef WX_PRECOMP
17 #include "wx/intl.h"
3b3dc801 18 #include "wx/menu.h"
fdf565fe 19 #include "wx/dialog.h"
88a7a4e1 20#endif
dcf924a3 21
88a7a4e1 22#include "wx/notebook.h"
3cbab641 23#include "wx/gtk1/private.h"
716b7364 24
16c1f79c
RR
25#include <glib.h>
26#include <gdk/gdk.h>
27#include <gtk/gtk.h>
3cbab641 28#include "wx/gtk1/win_gtk.h"
83624f79 29
6ca41e57
RR
30//-----------------------------------------------------------------------------
31// constants
32//-----------------------------------------------------------------------------
33
a0fdacee 34const int wxMENU_HEIGHT = 27;
6ca41e57 35
acfd422a
RR
36//-----------------------------------------------------------------------------
37// idle system
38//-----------------------------------------------------------------------------
39
40extern void wxapp_install_idle_handler();
41extern bool g_isIdle;
42
6ca41e57
RR
43//-----------------------------------------------------------------------------
44// globals
716b7364
RR
45//-----------------------------------------------------------------------------
46
5e014a0c
RR
47//-----------------------------------------------------------------------------
48// "switch_page"
49//-----------------------------------------------------------------------------
50
865bb325 51extern "C" {
f6bcfd97 52static void
7941ba11 53gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
e90196a5 54 GtkNotebookPage *page,
f6bcfd97
BP
55 gint WXUNUSED(page_num),
56 wxMDIParentFrame *parent )
5e014a0c 57{
f6bcfd97 58 if (g_isIdle)
5e014a0c
RR
59 wxapp_install_idle_handler();
60
e90196a5
RR
61 // send deactivate event to old child
62
5e014a0c 63 wxMDIChildFrame *child = parent->GetActiveChild();
e90196a5
RR
64 if (child)
65 {
b1d4dd7a 66 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
e90196a5 67 event1.SetEventObject( child);
937013e0 68 child->HandleWindowEvent( event1 );
e90196a5 69 }
f6bcfd97 70
e90196a5 71 // send activate event to new child
f6bcfd97 72
d2824cdb
VZ
73 wxMDIClientWindowBase * const client_window = parent->GetClientWindow();
74 if ( !client_window )
e90196a5
RR
75 return;
76
d2824cdb 77 child = NULL;
e90196a5 78
222ed1d6 79 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
e90196a5
RR
80 while (node)
81 {
b1d4dd7a 82 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
1631916e
CE
83 // CE: we come here in the destructor with a null child_frame - I think because
84 // gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page", (see below)
85 // isn't deleted early enough
86 if (!child_frame)
87 return ;
b1d4dd7a 88
e90196a5 89 if (child_frame->m_page == page)
f6bcfd97 90 {
e90196a5 91 child = child_frame;
f6bcfd97
BP
92 break;
93 }
b1d4dd7a 94 node = node->GetNext();
e90196a5 95 }
f6bcfd97 96
e90196a5
RR
97 if (!child)
98 return;
f6bcfd97 99
b1d4dd7a 100 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
e90196a5 101 event2.SetEventObject( child);
937013e0 102 child->HandleWindowEvent( event2 );
5e014a0c 103}
865bb325 104}
5e014a0c 105
6ca41e57
RR
106//-----------------------------------------------------------------------------
107// wxMDIParentFrame
33d0b396
RR
108//-----------------------------------------------------------------------------
109
c801d85f
KB
110IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
111
f6bcfd97 112void wxMDIParentFrame::Init()
c801d85f 113{
b1d4dd7a 114 m_justInserted = false;
d2824cdb 115 m_clientWindow = NULL;
ff7b1510 116}
c801d85f 117
f6bcfd97
BP
118bool wxMDIParentFrame::Create(wxWindow *parent,
119 wxWindowID id,
120 const wxString& title,
121 const wxPoint& pos,
122 const wxSize& size,
123 long style,
124 const wxString& name )
c801d85f 125{
6e42617a
VZ
126 if ( !wxFrame::Create( parent, id, title, pos, size, style, name ) )
127 return false;
a3622daa 128
6e42617a 129 m_clientWindow = OnCreateClient();
d2824cdb
VZ
130 if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
131 return false;
a3622daa 132
d2824cdb 133 return true;
ff7b1510 134}
c801d85f 135
716b7364 136void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
c801d85f 137{
83624f79 138 wxFrame::GtkOnSize( x, y, width, height );
a0fdacee 139
ab2b3dd4
RR
140 wxMDIChildFrame *child_frame = GetActiveChild();
141 if (!child_frame) return;
a0fdacee 142
ab2b3dd4
RR
143 wxMenuBar *menu_bar = child_frame->m_menuBar;
144 if (!menu_bar) return;
a2053b27 145 if (!menu_bar->m_widget) return;
a0fdacee 146
121a3581
RR
147 menu_bar->m_x = 0;
148 menu_bar->m_y = 0;
149 menu_bar->m_width = m_width;
150 menu_bar->m_height = wxMENU_HEIGHT;
f6bcfd97
BP
151 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
152 menu_bar->m_widget,
f03fc89f 153 0, 0, m_width, wxMENU_HEIGHT );
ab2b3dd4
RR
154}
155
156void wxMDIParentFrame::OnInternalIdle()
157{
158 /* if a an MDI child window has just been inserted
159 it has to be brought to the top in idle time. we
160 simply set the last notebook page active as new
161 pages can only be appended at the end */
162
163 if (m_justInserted)
83624f79 164 {
a2053b27 165 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
a0fdacee
VZ
166 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
167
147d6669 168 /* need to set the menubar of the child */
1d608029 169 wxMDIChildFrame *active_child_frame = GetActiveChild();
1b10056f 170 if (active_child_frame != NULL)
147d6669 171 {
1b10056f
RD
172 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
173 if (menu_bar)
174 {
175 menu_bar->m_width = m_width;
176 menu_bar->m_height = wxMENU_HEIGHT;
177 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
178 menu_bar->m_widget,
179 0, 0, m_width, wxMENU_HEIGHT );
61f09f56 180 menu_bar->Attach(active_child_frame);
1b10056f 181 }
147d6669 182 }
b1d4dd7a 183 m_justInserted = false;
a0fdacee 184 return;
83624f79 185 }
a0fdacee 186
ab2b3dd4 187 wxFrame::OnInternalIdle();
c626a8b7 188
ab2b3dd4 189 wxMDIChildFrame *active_child_frame = GetActiveChild();
b1d4dd7a 190 bool visible_child_menu = false;
a0fdacee 191
222ed1d6 192 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4 193 while (node)
83624f79 194 {
b1d4dd7a
RL
195 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
196
f6bcfd97 197 if ( child_frame )
a0fdacee 198 {
f6bcfd97
BP
199 wxMenuBar *menu_bar = child_frame->m_menuBar;
200 if ( menu_bar )
f03fc89f 201 {
f6bcfd97
BP
202 if (child_frame == active_child_frame)
203 {
b1d4dd7a 204 if (menu_bar->Show(true))
f6bcfd97
BP
205 {
206 menu_bar->m_width = m_width;
207 menu_bar->m_height = wxMENU_HEIGHT;
208 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
209 menu_bar->m_widget,
210 0, 0, m_width, wxMENU_HEIGHT );
61f09f56
VZ
211
212 // Attach() asserts if we call it for an already
213 // attached menu bar so don't do it if we're already
214 // associated with this frame (it would be nice to get
215 // rid of this check and ensure that this doesn't
216 // happen...)
217 if ( menu_bar->GetFrame() != child_frame )
218 menu_bar->Attach( child_frame );
f6bcfd97 219 }
b1d4dd7a 220 visible_child_menu = true;
f6bcfd97
BP
221 }
222 else
223 {
b1d4dd7a 224 if (menu_bar->Show(false))
f6bcfd97 225 {
61f09f56 226 menu_bar->Detach();
f6bcfd97
BP
227 }
228 }
f03fc89f 229 }
a0fdacee 230 }
f6bcfd97 231
b1d4dd7a 232 node = node->GetNext();
83624f79 233 }
a0fdacee 234
e27ce4e9 235 /* show/hide parent menu bar as required */
5bd9e519
RR
236 if ((m_frameMenuBar) &&
237 (m_frameMenuBar->IsShown() == visible_child_menu))
238 {
239 if (visible_child_menu)
f6bcfd97 240 {
b1d4dd7a 241 m_frameMenuBar->Show( false );
61f09f56 242 m_frameMenuBar->Detach();
f6bcfd97
BP
243 }
244 else
245 {
b1d4dd7a 246 m_frameMenuBar->Show( true );
61f09f56 247 m_frameMenuBar->Attach( this );
f6bcfd97
BP
248
249 m_frameMenuBar->m_width = m_width;
250 m_frameMenuBar->m_height = wxMENU_HEIGHT;
251 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
252 m_frameMenuBar->m_widget,
253 0, 0, m_width, wxMENU_HEIGHT );
254 }
5bd9e519 255 }
ff7b1510 256}
716b7364 257
ab2b3dd4
RR
258wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
259{
d2824cdb 260 if (!m_clientWindow) return NULL;
a0fdacee 261
a2053b27 262 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
d2824cdb 263 if (!notebook) return NULL;
a0fdacee 264
ab2b3dd4 265 gint i = gtk_notebook_get_current_page( notebook );
d2824cdb 266 if (i < 0) return NULL;
a0fdacee 267
ab2b3dd4 268 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
d2824cdb 269 if (!page) return NULL;
a0fdacee 270
222ed1d6 271 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
ab2b3dd4
RR
272 while (node)
273 {
b1d4dd7a
RL
274 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
275
9a83f860 276 wxASSERT_MSG( child_frame, wxT("child is not a wxMDIChildFrame") );
b1d4dd7a 277
ab2b3dd4
RR
278 if (child_frame->m_page == page)
279 return child_frame;
b1d4dd7a 280 node = node->GetNext();
ab2b3dd4 281 }
a0fdacee 282
d2824cdb 283 return NULL;
ff7b1510 284}
c801d85f 285
ab2b3dd4 286void wxMDIParentFrame::ActivateNext()
c801d85f 287{
83624f79 288 if (m_clientWindow)
a2053b27 289 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 290}
c801d85f 291
ab2b3dd4 292void wxMDIParentFrame::ActivatePrevious()
716b7364 293{
83624f79 294 if (m_clientWindow)
a2053b27 295 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
ff7b1510 296}
716b7364 297
c801d85f
KB
298//-----------------------------------------------------------------------------
299// wxMDIChildFrame
300//-----------------------------------------------------------------------------
301
cf4219e7 302IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
c626a8b7 303
cf4219e7 304BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
83624f79 305 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
f6bcfd97 306 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
716b7364
RR
307END_EVENT_TABLE()
308
d2824cdb 309void wxMDIChildFrame::Init()
c801d85f 310{
d2824cdb
VZ
311 m_menuBar = NULL;
312 m_page = NULL;
72c23f8e 313}
c801d85f
KB
314
315bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
debe6624 316 wxWindowID id, const wxString& title,
33d0b396 317 const wxPoint& WXUNUSED(pos), const wxSize& size,
debe6624 318 long style, const wxString& name )
c801d85f 319{
83624f79 320 m_title = title;
c626a8b7 321
83624f79 322 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
ff7b1510 323}
c801d85f 324
d2824cdb 325wxMDIChildFrame::~wxMDIChildFrame()
716b7364 326{
d2824cdb 327 delete m_menuBar;
716b7364 328}
c626a8b7 329
716b7364
RR
330void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
331{
223d09f6 332 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
5bd9e519 333
83624f79 334 m_menuBar = menu_bar;
a3622daa 335
83624f79 336 if (m_menuBar)
716b7364 337 {
f03fc89f 338 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
83624f79 339
5bd9e519 340 m_menuBar->SetParent( mdi_frame );
c626a8b7 341
ab2b3dd4 342 /* insert the invisible menu bar into the _parent_ mdi frame */
f6bcfd97
BP
343 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
344 m_menuBar->m_widget,
a2053b27 345 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
716b7364 346 }
ff7b1510 347}
cf4219e7 348
33b64e6f 349wxMenuBar *wxMDIChildFrame::GetMenuBar() const
cf4219e7 350{
83624f79 351 return m_menuBar;
ff7b1510 352}
c801d85f 353
d2824cdb
VZ
354GtkNotebook *wxMDIChildFrame::GTKGetNotebook() const
355{
356 wxMDIClientWindow * const
357 client = wxStaticCast(GetParent(), wxMDIClientWindow);
358 wxCHECK( client, NULL );
359
360 return GTK_NOTEBOOK(client->m_widget);
361}
362
ab2b3dd4 363void wxMDIChildFrame::Activate()
c801d85f 364{
d2824cdb
VZ
365 GtkNotebook * const notebook = GTKGetNotebook();
366 wxCHECK_RET( notebook, "no parent notebook?" );
367
9e691f46 368 gint pageno = gtk_notebook_page_num( notebook, m_widget );
adde8c98 369 gtk_notebook_set_page( notebook, pageno );
ff7b1510 370}
c801d85f 371
f6bcfd97
BP
372void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
373{
374}
375
376void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
9746a2ba 377{
f6bcfd97
BP
378#if wxUSE_STATUSBAR
379 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
722ed5be 380 if ( !ShowMenuHelp(event.GetMenuId()) )
f6bcfd97
BP
381 {
382 // we don't have any help text for this item, but may be the MDI frame
383 // does?
384 mdi_frame->OnMenuHighlight(event);
385 }
386#endif // wxUSE_STATUSBAR
387}
388
389void wxMDIChildFrame::SetTitle( const wxString &title )
390{
391 if ( title == m_title )
392 return;
393
394 m_title = title;
395
d2824cdb
VZ
396 GtkNotebook * const notebook = GTKGetNotebook();
397 wxCHECK_RET( notebook, "no parent notebook?" );
398
fab591c5 399 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
ff7b1510 400}
9746a2ba 401
ab2b3dd4
RR
402//-----------------------------------------------------------------------------
403// "size_allocate"
404//-----------------------------------------------------------------------------
405
865bb325 406extern "C" {
ab2b3dd4
RR
407static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
408{
acfd422a
RR
409 if (g_isIdle) wxapp_install_idle_handler();
410
a2053b27
RR
411 if ((win->m_x == alloc->x) &&
412 (win->m_y == alloc->y) &&
413 (win->m_width == alloc->width) &&
414 (win->m_height == alloc->height) &&
415 (win->m_sizeSet))
ab2b3dd4
RR
416 {
417 return;
418 }
419
420 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
421}
865bb325 422}
ab2b3dd4 423
6ca41e57
RR
424//-----------------------------------------------------------------------------
425// InsertChild callback for wxMDIClientWindow
426//-----------------------------------------------------------------------------
427
428static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
429{
72c23f8e 430 wxString s = child->GetTitle();
6636ef8d 431 if ( s.empty() ) s = _("MDI child");
6ca41e57 432
ed9b9841 433 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
83624f79 434 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
6ca41e57 435
a2053b27 436 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
83624f79 437 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
c626a8b7 438
a2053b27 439 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
c626a8b7 440
a2053b27 441 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
6ca41e57 442
83624f79 443 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
a0fdacee 444
f03fc89f 445 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
b1d4dd7a 446 parent_frame->m_justInserted = true;
6ca41e57
RR
447}
448
c801d85f
KB
449//-----------------------------------------------------------------------------
450// wxMDIClientWindow
451//-----------------------------------------------------------------------------
452
453IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
454
debe6624 455bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
c801d85f 456{
b1d4dd7a 457 m_needParent = true;
c626a8b7 458
83624f79 459 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
a3622daa 460
4dcaf11a 461 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
72c23f8e 462 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
4dcaf11a 463 {
223d09f6 464 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
b1d4dd7a 465 return false;
4dcaf11a 466 }
c801d85f 467
83624f79 468 m_widget = gtk_notebook_new();
a3622daa 469
5e014a0c
RR
470 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
471 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
472
83624f79 473 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
a3622daa 474
f03fc89f 475 m_parent->DoAddChild( this );
c626a8b7 476
83624f79 477 PostCreation();
a3622daa 478
b1d4dd7a 479 Show( true );
a3622daa 480
b1d4dd7a 481 return true;
ff7b1510 482}
c801d85f 483
dcf924a3 484#endif