]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/notebook.cpp
disable select root menu command when the root is hidden
[wxWidgets.git] / src / gtk / notebook.cpp
CommitLineData
53b28675 1/////////////////////////////////////////////////////////////////////////////
88a7a4e1 2// Name: src/gtk/notebook.cpp
53b28675
RR
3// Purpose:
4// Author: Robert Roebling
a81258be 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
65571936 7// Licence: wxWindows licence
53b28675
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
88a7a4e1
WS
13#if wxUSE_NOTEBOOK
14
53b28675 15#include "wx/notebook.h"
dcf924a3 16
88a7a4e1
WS
17#ifndef WX_PRECOMP
18 #include "wx/intl.h"
e4db172a 19 #include "wx/log.h"
de6185e2 20 #include "wx/utils.h"
246c5004 21 #include "wx/msgdlg.h"
0bca0373 22 #include "wx/bitmap.h"
88a7a4e1 23#endif
dcf924a3 24
53b28675 25#include "wx/imaglist.h"
c077ee94 26#include "wx/fontutil.h"
83624f79 27
9e691f46 28#include "wx/gtk/private.h"
83624f79 29#include "wx/gtk/win_gtk.h"
9e691f46 30
5e7e9e1b 31#include <gdk/gdkkeysyms.h>
b292e2f5 32
2e4df4bf
VZ
33// ----------------------------------------------------------------------------
34// events
35// ----------------------------------------------------------------------------
36
37DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
38DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
39
b292e2f5
RR
40//-----------------------------------------------------------------------------
41// data
42//-----------------------------------------------------------------------------
43
07b8d7ec 44extern bool g_blockEventsOnDrag;
53b28675 45
219f895a 46//-----------------------------------------------------------------------------
80a58c99 47// wxGtkNotebookPage
219f895a
RR
48//-----------------------------------------------------------------------------
49
07b8d7ec
VZ
50// VZ: this is rather ugly as we keep the pages themselves in an array (it
51// allows us to have quite a few functions implemented in the base class)
52// but the page data is kept in a separate list, so we must maintain them
53// in sync manually... of course, the list had been there before the base
54// class which explains it but it still would be nice to do something
55// about this one day
56
80a58c99 57class wxGtkNotebookPage: public wxObject
219f895a
RR
58{
59public:
c077ee94
RR
60 wxGtkNotebookPage()
61 {
62 m_image = -1;
63 m_page = (GtkNotebookPage *) NULL;
64 m_box = (GtkWidget *) NULL;
c077ee94 65 }
88d19775 66
c077ee94
RR
67 wxString m_text;
68 int m_image;
69 GtkNotebookPage *m_page;
70 GtkLabel *m_label;
71 GtkWidget *m_box; // in which the label and image are packed
219f895a
RR
72};
73
c077ee94 74
07b8d7ec 75#include "wx/listimpl.cpp"
28c91b7d 76WX_DEFINE_LIST(wxGtkNotebookPagesList)
07b8d7ec 77
c077ee94 78
ff829f3f 79//-----------------------------------------------------------------------------
5b011451 80// "switch_page"
ff829f3f
VZ
81//-----------------------------------------------------------------------------
82
865bb325 83extern "C" {
c9882624
RR
84static void gtk_notebook_page_changing_callback( GtkNotebook *widget,
85 GtkNotebookPage *WXUNUSED(gpage),
86 guint page,
87 wxNotebook *notebook )
ff829f3f 88{
c9882624 89 int old = gtk_notebook_get_current_page( widget );
36202885 90
c9882624 91 if ( !notebook->SendPageChangingEvent(page) )
36202885 92 {
c9882624
RR
93 // program doesn't allow the page change
94 g_signal_stop_emission_by_name(notebook->m_widget, "switch_page");
1d6fcbcc
VZ
95 }
96 else
97 {
c9882624
RR
98 // the page change event also reports the old page
99 notebook->m_oldSelection = old;
587ce561 100 }
c9882624
RR
101}
102}
ef44a621 103
c9882624
RR
104extern "C" {
105static void gtk_notebook_page_changed_callback( GtkNotebook *widget,
106 GtkNotebookPage *WXUNUSED(gpage),
107 guint page,
108 wxNotebook *notebook )
109{
110 int old = notebook->m_oldSelection;
111 notebook->SendPageChangedEvent( old );
ff829f3f 112}
865bb325 113}
ff829f3f 114
5b011451
RR
115//-----------------------------------------------------------------------------
116// "size_allocate"
117//-----------------------------------------------------------------------------
118
865bb325 119extern "C" {
33d0b396 120static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
caac5181 121{
a6aa9b1e 122 if (g_isIdle)
587ce561 123 wxapp_install_idle_handler();
6d693bb4 124
a2053b27
RR
125 if ((win->m_x == alloc->x) &&
126 (win->m_y == alloc->y) &&
127 (win->m_width == alloc->width) &&
128 (win->m_height == alloc->height))
b292e2f5 129 {
58dea4b0 130 return;
b292e2f5 131 }
a6aa9b1e 132
b292e2f5 133 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
f861258f 134
d7928388
RR
135 /* GTK 1.2 up to version 1.2.5 is broken so that we have to call allocate
136 here in order to make repositioning after resizing to take effect. */
137 if ((gtk_major_version == 1) &&
138 (gtk_minor_version == 2) &&
8712c6e7
VZ
139 (gtk_micro_version < 6) &&
140 (win->m_wxwindow) &&
141 (GTK_WIDGET_REALIZED(win->m_wxwindow)))
d7928388
RR
142 {
143 gtk_widget_size_allocate( win->m_wxwindow, alloc );
144 }
6d693bb4 145}
865bb325 146}
6d693bb4
RR
147
148//-----------------------------------------------------------------------------
149// "realize" from m_widget
150//-----------------------------------------------------------------------------
151
865bb325 152extern "C" {
a237731e 153static void
6d693bb4
RR
154gtk_notebook_realized_callback( GtkWidget * WXUNUSED(widget), wxWindow *win )
155{
156 if (g_isIdle)
157 wxapp_install_idle_handler();
158
d7928388
RR
159 /* GTK 1.2 up to version 1.2.5 is broken so that we have to call a queue_resize
160 here in order to make repositioning before showing to take effect. */
6d693bb4 161 gtk_widget_queue_resize( win->m_widget );
b292e2f5 162}
865bb325 163}
b292e2f5 164
6ca41e57
RR
165//-----------------------------------------------------------------------------
166// InsertChild callback for wxNotebook
167//-----------------------------------------------------------------------------
168
d7f1759a 169static void wxInsertChildInNotebook( wxNotebook* parent, wxWindow* child )
6ca41e57 170{
fff8475e
RD
171 // Hack Alert! (Part I): This sets the notebook as the parent of the child
172 // widget, and takes care of some details such as updating the state and
173 // style of the child to reflect its new location. We do this early
174 // because without it GetBestSize (which is used to set the initial size
175 // of controls if an explicit size is not given) will often report
176 // incorrect sizes since the widget's style context is not fully known.
177 // See bug #901694 for details
2ded391d 178 // (http://sourceforge.net/tracker/?func=detail&aid=901694&group_id=9863&atid=109863)
fff8475e
RD
179 gtk_widget_set_parent(child->m_widget, parent->m_widget);
180
181 // NOTE: This should be considered a temporary workaround until we can
182 // work out the details and implement delaying the setting of the initial
183 // size of widgets until the size is really needed.
6ca41e57
RR
184}
185
53b28675
RR
186//-----------------------------------------------------------------------------
187// wxNotebook
188//-----------------------------------------------------------------------------
189
53b28675
RR
190IMPLEMENT_DYNAMIC_CLASS(wxNotebook,wxControl)
191
b98d804b
RR
192BEGIN_EVENT_TABLE(wxNotebook, wxControl)
193 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
194END_EVENT_TABLE()
f861258f 195
ff829f3f 196void wxNotebook::Init()
53b28675 197{
b318dc42 198 m_padding = 0;
2b5f62a0 199
b292e2f5 200 m_imageList = (wxImageList *) NULL;
c9882624 201 m_oldSelection = -1;
de6185e2 202 m_themeEnabled = true;
ff829f3f
VZ
203}
204
205wxNotebook::wxNotebook()
206{
b292e2f5 207 Init();
ff7b1510 208}
53b28675 209
debe6624 210wxNotebook::wxNotebook( wxWindow *parent, wxWindowID id,
53b28675 211 const wxPoint& pos, const wxSize& size,
debe6624 212 long style, const wxString& name )
53b28675 213{
b292e2f5
RR
214 Init();
215 Create( parent, id, pos, size, style, name );
ff7b1510 216}
53b28675 217
ff829f3f 218wxNotebook::~wxNotebook()
53b28675 219{
b292e2f5 220 DeleteAllPages();
ff7b1510 221}
53b28675 222
debe6624 223bool wxNotebook::Create(wxWindow *parent, wxWindowID id,
07b8d7ec
VZ
224 const wxPoint& pos, const wxSize& size,
225 long style, const wxString& name )
53b28675 226{
de6185e2 227 m_needParent = true;
b292e2f5
RR
228 m_insertCallback = (wxInsertChildFunction)wxInsertChildInNotebook;
229
90f9b8ef
JS
230 if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
231 style |= wxBK_TOP;
232
4dcaf11a
RR
233 if (!PreCreation( parent, pos, size ) ||
234 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
235 {
223d09f6 236 wxFAIL_MSG( wxT("wxNoteBook creation failed") );
de6185e2 237 return false;
4dcaf11a
RR
238 }
239
ff829f3f 240
b292e2f5 241 m_widget = gtk_notebook_new();
53b28675 242
b292e2f5 243 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
caac5181 244
9fa72bd2 245 g_signal_connect (m_widget, "switch_page",
c9882624
RR
246 G_CALLBACK (gtk_notebook_page_changing_callback), this);
247
248 g_signal_connect_after (m_widget, "switch_page",
249 G_CALLBACK (gtk_notebook_page_changed_callback), this);
ff829f3f 250
f03fc89f 251 m_parent->DoAddChild( this );
ef44a621 252
df034cc6 253 if (m_windowStyle & wxBK_RIGHT)
8712c6e7 254 gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_RIGHT );
df034cc6 255 if (m_windowStyle & wxBK_LEFT)
8712c6e7 256 gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_LEFT );
df034cc6 257 if (m_windowStyle & wxBK_BOTTOM)
8712c6e7 258 gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_BOTTOM );
a3a7f879 259
abdeb9e7 260 PostCreation(size);
ff829f3f 261
9fa72bd2
MR
262 g_signal_connect (m_widget, "realize",
263 G_CALLBACK (gtk_notebook_realized_callback), this);
a6aa9b1e 264
de6185e2 265 return true;
ff7b1510 266}
53b28675 267
ff829f3f 268int wxNotebook::GetSelection() const
53b28675 269{
223d09f6 270 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
53b28675 271
c9882624 272 return gtk_notebook_get_current_page( GTK_NOTEBOOK(m_widget) );
ff7b1510 273}
53b28675 274
789d0a3d 275wxString wxNotebook::GetPageText( size_t page ) const
53b28675 276{
88a7a4e1 277 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid notebook") );
ef44a621 278
80a58c99 279 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
b292e2f5
RR
280 if (nb_page)
281 return nb_page->m_text;
282 else
88a7a4e1 283 return wxEmptyString;
ff7b1510 284}
53b28675 285
789d0a3d 286int wxNotebook::GetPageImage( size_t page ) const
53b28675 287{
223d09f6 288 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
a81258be 289
80a58c99 290 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
b292e2f5
RR
291 if (nb_page)
292 return nb_page->m_image;
293 else
587ce561 294 return -1;
ff7b1510 295}
53b28675 296
80a58c99 297wxGtkNotebookPage* wxNotebook::GetNotebookPage( int page ) const
53b28675 298{
80a58c99 299 wxCHECK_MSG( m_widget != NULL, (wxGtkNotebookPage*) NULL, wxT("invalid notebook") );
ff829f3f 300
07b8d7ec 301 wxCHECK_MSG( page < (int)m_pagesData.GetCount(), (wxGtkNotebookPage*) NULL, wxT("invalid notebook index") );
a6aa9b1e 302
07b8d7ec 303 return m_pagesData.Item(page)->GetData();
ff7b1510 304}
53b28675 305
1d6fcbcc 306int wxNotebook::DoSetSelection( size_t page, int flags )
53b28675 307{
223d09f6 308 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
a81258be 309
789d0a3d 310 wxCHECK_MSG( page < m_pagesData.GetCount(), -1, wxT("invalid notebook index") );
ff829f3f 311
587ce561 312 int selOld = GetSelection();
a6aa9b1e 313
1d6fcbcc 314 if ( !(flags & SetSelection_SendEvent) )
c9882624
RR
315 {
316 g_signal_handlers_disconnect_by_func (m_widget,
317 (gpointer) gtk_notebook_page_changing_callback,
318 this);
319
320 g_signal_handlers_disconnect_by_func (m_widget,
321 (gpointer) gtk_notebook_page_changed_callback,
322 this);
323 }
1d6fcbcc 324
38f1df7c 325 gtk_notebook_set_current_page( GTK_NOTEBOOK(m_widget), page );
ff829f3f 326
1d6fcbcc
VZ
327 if ( !(flags & SetSelection_SendEvent) )
328 {
c9882624 329 // reconnect to signals
f4322df6 330
c9882624
RR
331 g_signal_connect (m_widget, "switch_page",
332 G_CALLBACK (gtk_notebook_page_changing_callback), this);
333
334 g_signal_connect_after (m_widget, "switch_page",
335 G_CALLBACK (gtk_notebook_page_changed_callback), this);
1d6fcbcc 336 }
1d6fcbcc 337
07b8d7ec
VZ
338 wxNotebookPage *client = GetPage(page);
339 if ( client )
340 client->SetFocus();
b656febd 341
07b8d7ec 342 return selOld;
ff7b1510 343}
53b28675 344
789d0a3d 345bool wxNotebook::SetPageText( size_t page, const wxString &text )
53b28675 346{
de6185e2 347 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid notebook") );
a81258be 348
80a58c99 349 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
ef44a621 350
de6185e2 351 wxCHECK_MSG( nb_page, false, wxT("SetPageText: invalid page index") );
ff829f3f 352
3eb78d7e 353 nb_page->m_text = text;
ff829f3f 354
a7c12d28 355 gtk_label_set_text( nb_page->m_label, wxGTK_CONV( nb_page->m_text ) );
a6aa9b1e 356
de6185e2 357 return true;
ff7b1510 358}
53b28675 359
789d0a3d 360bool wxNotebook::SetPageImage( size_t page, int image )
53b28675 361{
3eb78d7e 362 /* HvdH 28-12-98: now it works, but it's a bit of a kludge */
f861258f 363
80a58c99 364 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
ef44a621 365
de6185e2 366 if (!nb_page) return false;
f861258f 367
3eb78d7e
RR
368 /* Optimization posibility: return immediately if image unchanged.
369 * Not enabled because it may break existing (stupid) code that
370 * manipulates the imagelist to cycle images */
f861258f 371
de6185e2 372 /* if (image == nb_page->m_image) return true; */
f861258f
VZ
373
374 /* For different cases:
3eb78d7e
RR
375 1) no image -> no image
376 2) image -> no image
377 3) no image -> image
378 4) image -> image */
f861258f 379
3eb78d7e 380 if (image == -1 && nb_page->m_image == -1)
de6185e2 381 return true; /* Case 1): Nothing to do. */
f861258f 382
bbe0af5b 383 GtkWidget *pixmapwid = (GtkWidget*) NULL;
f861258f
VZ
384
385 if (nb_page->m_image != -1)
3eb78d7e
RR
386 {
387 /* Case 2) or 4). There is already an image in the gtkhbox. Let's find it */
f861258f 388
2e14a116 389 GList *child = gtk_container_get_children(GTK_CONTAINER(nb_page->m_box));
279b5e2e 390 while (child)
8712c6e7 391 {
d41e1ab4 392 if (GTK_IS_IMAGE(child->data))
8712c6e7
VZ
393 {
394 pixmapwid = GTK_WIDGET(child->data);
395 break;
3eb78d7e 396 }
279b5e2e 397 child = child->next;
8712c6e7 398 }
f861258f 399
3eb78d7e 400 /* We should have the pixmap widget now */
f861258f
VZ
401 wxASSERT(pixmapwid != NULL);
402
403 if (image == -1)
8712c6e7 404 {
3eb78d7e
RR
405 /* If there's no new widget, just remove the old from the box */
406 gtk_container_remove(GTK_CONTAINER(nb_page->m_box), pixmapwid);
407 nb_page->m_image = -1;
53b28675 408
de6185e2 409 return true; /* Case 2) */
3eb78d7e
RR
410 }
411 }
f861258f 412
3eb78d7e
RR
413 /* Only cases 3) and 4) left */
414 wxASSERT( m_imageList != NULL ); /* Just in case */
f861258f 415
3eb78d7e 416 /* Construct the new pixmap */
49bf4e3e 417 const wxBitmap *bmp = m_imageList->GetBitmapPtr(image);
f861258f
VZ
418
419 if (pixmapwid == NULL)
3eb78d7e
RR
420 {
421 /* Case 3) No old pixmap. Create a new one and prepend it to the hbox */
d41e1ab4 422 pixmapwid = gtk_image_new_from_pixbuf(bmp->GetPixbuf());
f861258f 423
3eb78d7e 424 /* CHECKME: Are these pack flags okay? */
b318dc42 425 gtk_box_pack_start(GTK_BOX(nb_page->m_box), pixmapwid, FALSE, FALSE, m_padding);
3eb78d7e
RR
426 gtk_widget_show(pixmapwid);
427 }
f861258f 428 else
3eb78d7e
RR
429 {
430 /* Case 4) Simply replace the pixmap */
d41e1ab4 431 gtk_image_set_from_pixbuf((GtkImage*)pixmapwid, bmp->GetPixbuf());
3eb78d7e 432 }
f861258f 433
3eb78d7e 434 nb_page->m_image = image;
53b28675 435
de6185e2 436 return true;
ff7b1510 437}
53b28675
RR
438
439void wxNotebook::SetPageSize( const wxSize &WXUNUSED(size) )
440{
223d09f6 441 wxFAIL_MSG( wxT("wxNotebook::SetPageSize not implemented") );
ff7b1510 442}
53b28675 443
b318dc42 444void wxNotebook::SetPadding( const wxSize &padding )
53b28675 445{
b318dc42
JS
446 wxCHECK_RET( m_widget != NULL, wxT("invalid notebook") );
447
448 m_padding = padding.GetWidth();
449
450 int i;
451 for (i=0; i<int(GetPageCount()); i++)
452 {
453 wxGtkNotebookPage* nb_page = GetNotebookPage(i);
454 wxASSERT(nb_page != NULL);
455
456 if (nb_page->m_image != -1)
457 {
458 // gtk_box_set_child_packing sets padding on BOTH sides
459 // icon provides left padding, label provides center and right
460 int image = nb_page->m_image;
461 SetPageImage(i,-1);
462 SetPageImage(i,image);
463 }
464 wxASSERT(nb_page->m_label);
465 gtk_box_set_child_packing(GTK_BOX(nb_page->m_box),
466 GTK_WIDGET(nb_page->m_label),
467 FALSE, FALSE, m_padding, GTK_PACK_END);
468 }
ff7b1510 469}
53b28675 470
74e3313b 471void wxNotebook::SetTabSize(const wxSize& WXUNUSED(sz))
ca8b28f2 472{
223d09f6 473 wxFAIL_MSG( wxT("wxNotebook::SetTabSize not implemented") );
ca8b28f2
JS
474}
475
ff829f3f 476bool wxNotebook::DeleteAllPages()
53b28675 477{
de6185e2 478 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid notebook") );
a81258be 479
07b8d7ec
VZ
480 while (m_pagesData.GetCount() > 0)
481 DeletePage( m_pagesData.GetCount()-1 );
482
483 wxASSERT_MSG( GetPageCount() == 0, _T("all pages must have been deleted") );
ff829f3f 484
37144cf0 485 InvalidateBestSize();
10199e27 486 return wxNotebookBase::DeleteAllPages();
ff7b1510 487}
53b28675 488
acb69c13 489wxNotebookPage *wxNotebook::DoRemovePage( size_t page )
53b28675 490{
10199e27
VZ
491 wxNotebookPage *client = wxNotebookBase::DoRemovePage(page);
492 if ( !client )
493 return NULL;
fed46e72 494
07b8d7ec
VZ
495 gtk_widget_ref( client->m_widget );
496 gtk_widget_unrealize( client->m_widget );
9c862cfb
RR
497
498 // we don't need to unparent the client->m_widget; GTK+ will do
499 // that for us (and will throw a warning if we do it!)
07b8d7ec 500
587ce561 501 gtk_notebook_remove_page( GTK_NOTEBOOK(m_widget), page );
ff829f3f 502
222ed1d6
MB
503 wxGtkNotebookPage* p = GetNotebookPage(page);
504 m_pagesData.DeleteObject(p);
505 delete p;
ff829f3f 506
07b8d7ec 507 return client;
ff7b1510 508}
53b28675 509
789d0a3d 510bool wxNotebook::InsertPage( size_t position,
07b8d7ec
VZ
511 wxNotebookPage* win,
512 const wxString& text,
513 bool select,
514 int imageId )
53b28675 515{
de6185e2 516 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid notebook") );
a81258be 517
de6185e2 518 wxCHECK_MSG( win->GetParent() == this, false,
223d09f6 519 wxT("Can't add a page whose parent is not the notebook!") );
8aadf227 520
de6185e2 521 wxCHECK_MSG( position <= GetPageCount(), false,
07b8d7ec
VZ
522 _T("invalid page index in wxNotebookPage::InsertPage()") );
523
fff8475e
RD
524 // Hack Alert! (Part II): See above in wxInsertChildInNotebook callback
525 // why this has to be done. NOTE: using gtk_widget_unparent here does not
526 // work as it seems to undo too much and will cause errors in the
527 // gtk_notebook_insert_page below, so instead just clear the parent by
528 // hand here.
d7f1759a
RR
529 win->m_widget->parent = NULL;
530
a2d93e73 531 if (m_themeEnabled)
de6185e2 532 win->SetThemeEnabled(true);
a2d93e73 533
587ce561 534 GtkNotebook *notebook = GTK_NOTEBOOK(m_widget);
53b28675 535
b318dc42 536 wxGtkNotebookPage *nb_page = new wxGtkNotebookPage();
a6aa9b1e 537
07b8d7ec 538 if ( position == GetPageCount() )
b318dc42 539 m_pagesData.Append( nb_page );
587ce561 540 else
1c36a9d3 541 m_pagesData.Insert( position, nb_page );
a6aa9b1e 542
07b8d7ec 543 m_pages.Insert(win, position);
8aadf227 544
b318dc42 545 nb_page->m_box = gtk_hbox_new( FALSE, 1 );
d41e1ab4 546 gtk_container_set_border_width((GtkContainer*)nb_page->m_box, 2);
587ce561 547
9fa72bd2
MR
548 g_signal_connect (win->m_widget, "size_allocate",
549 G_CALLBACK (gtk_page_size_callback), win);
d1af991f 550
bd090f77 551 gtk_notebook_insert_page( notebook, win->m_widget, nb_page->m_box, position );
587ce561 552
b318dc42 553 nb_page->m_page = (GtkNotebookPage*) g_list_last(notebook->children)->data;
ef44a621 554
587ce561 555 /* set the label image */
b318dc42 556 nb_page->m_image = imageId;
a6aa9b1e 557
3eb78d7e 558 if (imageId != -1)
e4a81a2e 559 {
3eb78d7e
RR
560 wxASSERT( m_imageList != NULL );
561
49bf4e3e 562 const wxBitmap *bmp = m_imageList->GetBitmapPtr(imageId);
d41e1ab4 563 GtkWidget* pixmapwid = gtk_image_new_from_pixbuf(bmp->GetPixbuf());
b318dc42 564 gtk_box_pack_start(GTK_BOX(nb_page->m_box), pixmapwid, FALSE, FALSE, m_padding);
3eb78d7e
RR
565 gtk_widget_show(pixmapwid);
566 }
24d20a8f 567
587ce561 568 /* set the label text */
c077ee94 569
3ba6891d 570 nb_page->m_text = wxStripMenuCodes(text);
8e609c82 571 if (nb_page->m_text.empty()) nb_page->m_text = wxEmptyString;
279b5e2e 572
73e68c1d 573 nb_page->m_label = GTK_LABEL( gtk_label_new(wxGTK_CONV(nb_page->m_text)) );
b318dc42 574 gtk_box_pack_end( GTK_BOX(nb_page->m_box), GTK_WIDGET(nb_page->m_label), FALSE, FALSE, m_padding );
279b5e2e 575
97357eec
VS
576 /* apply current style */
577 GtkRcStyle *style = CreateWidgetStyle();
578 if ( style )
579 {
580 gtk_widget_modify_style(GTK_WIDGET(nb_page->m_label), style);
581 gtk_rc_style_unref(style);
88d19775
MR
582 }
583
587ce561 584 /* show the label */
b318dc42 585 gtk_widget_show( GTK_WIDGET(nb_page->m_label) );
f4322df6 586
07b8d7ec 587 if (select && (m_pagesData.GetCount() > 1))
587ce561 588 {
c9882624 589 SetSelection( position );
587ce561 590 }
741fd203 591
37144cf0 592 InvalidateBestSize();
de6185e2 593 return true;
ff7b1510 594}
53b28675 595
279b5e2e
VZ
596// helper for HitTest(): check if the point lies inside the given widget which
597// is the child of the notebook whose position and border size are passed as
598// parameters
599static bool
600IsPointInsideWidget(const wxPoint& pt, GtkWidget *w,
601 gint x, gint y, gint border = 0)
602{
603 return
604 (pt.x >= w->allocation.x - x - border) &&
605 (pt.x <= w->allocation.x - x + border + w->allocation.width) &&
606 (pt.y >= w->allocation.y - y - border) &&
607 (pt.y <= w->allocation.y - y + border + w->allocation.height);
608}
609
610int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
611{
612 const gint x = m_widget->allocation.x;
613 const gint y = m_widget->allocation.y;
614
615 const size_t count = GetPageCount();
f660b206
MR
616 size_t i = 0;
617
f660b206 618 GtkNotebook * notebook = GTK_NOTEBOOK(m_widget);
a5bb4f82 619 if (gtk_notebook_get_scrollable(notebook))
f660b206 620 i = g_list_position( notebook->children, notebook->first_tab );
f660b206
MR
621
622 for ( ; i < count; i++ )
279b5e2e
VZ
623 {
624 wxGtkNotebookPage* nb_page = GetNotebookPage(i);
625 GtkWidget *box = nb_page->m_box;
626
279b5e2e 627 const gint border = gtk_container_get_border_width(GTK_CONTAINER(box));
68567a96 628
279b5e2e
VZ
629 if ( IsPointInsideWidget(pt, box, x, y, border) )
630 {
631 // ok, we're inside this tab -- now find out where, if needed
632 if ( flags )
633 {
634 GtkWidget *pixmap = NULL;
635
2e14a116 636 GList *children = gtk_container_get_children(GTK_CONTAINER(box));
279b5e2e
VZ
637 for ( GList *child = children; child; child = child->next )
638 {
d41e1ab4 639 if (GTK_IS_IMAGE(child->data))
279b5e2e
VZ
640 {
641 pixmap = GTK_WIDGET(child->data);
642 break;
643 }
644 }
645
646 if ( children )
647 g_list_free(children);
648
649 if ( pixmap && IsPointInsideWidget(pt, pixmap, x, y) )
650 {
9804d540 651 *flags = wxBK_HITTEST_ONICON;
279b5e2e
VZ
652 }
653 else if ( IsPointInsideWidget(pt, GTK_WIDGET(nb_page->m_label), x, y) )
654 {
9804d540 655 *flags = wxBK_HITTEST_ONLABEL;
279b5e2e
VZ
656 }
657 else
658 {
9804d540 659 *flags = wxBK_HITTEST_ONITEM;
279b5e2e
VZ
660 }
661 }
662
663 return i;
664 }
665 }
666
667 if ( flags )
d0a84b63 668 {
9804d540 669 *flags = wxBK_HITTEST_NOWHERE;
d0a84b63
VZ
670 wxWindowBase * page = GetCurrentPage();
671 if ( page )
672 {
673 // rect origin is in notebook's parent coordinates
674 wxRect rect = page->GetRect();
675
676 // adjust it to the notebook's coordinates
677 wxPoint pos = GetPosition();
678 rect.x -= pos.x;
679 rect.y -= pos.y;
22a35096 680 if ( rect.Contains( pt ) )
9804d540 681 *flags |= wxBK_HITTEST_ONPAGE;
d0a84b63
VZ
682 }
683 }
279b5e2e
VZ
684
685 return wxNOT_FOUND;
686}
687
b98d804b
RR
688void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
689{
f861258f 690 if (event.IsWindowChange())
b98d804b 691 AdvanceSelection( event.GetDirection() );
f861258f 692 else
b98d804b
RR
693 event.Skip();
694}
695
93d38175
VS
696#if wxUSE_CONSTRAINTS
697
5a8c929e 698// override these 2 functions to do nothing: everything is done in OnSize
e3e65dac 699void wxNotebook::SetConstraintSizes( bool WXUNUSED(recurse) )
5a8c929e 700{
b292e2f5 701 // don't set the sizes of the pages - their correct size is not yet known
de6185e2 702 wxControl::SetConstraintSizes(false);
5a8c929e
VZ
703}
704
e3e65dac 705bool wxNotebook::DoPhase( int WXUNUSED(nPhase) )
5a8c929e 706{
de6185e2 707 return true;
5a8c929e
VZ
708}
709
93d38175
VS
710#endif
711
f40fdaa3 712void wxNotebook::DoApplyWidgetStyle(GtkRcStyle *style)
a81258be 713{
97357eec
VS
714 gtk_widget_modify_style(m_widget, style);
715 size_t cnt = m_pagesData.GetCount();
716 for (size_t i = 0; i < cnt; i++)
717 gtk_widget_modify_style(GTK_WIDGET(GetNotebookPage(i)->m_label), style);
a81258be
RR
718}
719
ef5c70f9 720GdkWindow *wxNotebook::GTKGetWindow(wxArrayGdkWindows& windows) const
58d1c1ae 721{
ef5c70f9
VZ
722 windows.push_back(m_widget->window);
723 windows.push_back(GTK_NOTEBOOK(m_widget)->event_window);
724
725 return NULL;
58d1c1ae
RR
726}
727
9d522606
RD
728// static
729wxVisualAttributes
730wxNotebook::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
731{
732 return GetDefaultAttributesFromGTKWidget(gtk_notebook_new);
733}
734
53b28675 735//-----------------------------------------------------------------------------
ff829f3f 736// wxNotebookEvent
53b28675
RR
737//-----------------------------------------------------------------------------
738
92976ab6 739IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
5b011451 740
a3a7f879 741#endif