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