]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/notebook.cpp
fixed deadlock when calling wxPostEvent() from worker thread
[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
8253c7fd 165//-----------------------------------------------------------------------------
8712c6e7 166// "key_press_event"
8253c7fd
RR
167//-----------------------------------------------------------------------------
168
865bb325 169extern "C" {
a237731e
MR
170static gboolean
171gtk_notebook_key_press_callback( GtkWidget *widget,
172 GdkEventKey *gdk_event,
173 wxNotebook *notebook )
8253c7fd 174{
14819684 175 // don't need to install idle handler, its done from "event" signal
8253c7fd 176
3c4e4af6 177 if (!notebook->m_hasVMT) return FALSE;
8253c7fd 178 if (g_blockEventsOnDrag) return FALSE;
88d19775 179
3c4e4af6
RR
180 /* win is a control: tab can be propagated up */
181 if ((gdk_event->keyval == GDK_Left) || (gdk_event->keyval == GDK_Right))
182 {
183 int page;
184 int nMax = notebook->GetPageCount();
185 if ( nMax-- ) // decrement it to get the last valid index
186 {
187 int nSel = notebook->GetSelection();
188
189 // change selection wrapping if it becomes invalid
190 page = (gdk_event->keyval != GDK_Left) ? nSel == nMax ? 0
191 : nSel + 1
192 : nSel == 0 ? nMax
193 : nSel - 1;
194 }
195 else // notebook is empty, no next page
196 {
197 return FALSE;
198 }
88d19775 199
38f1df7c 200 gtk_notebook_set_current_page( GTK_NOTEBOOK(widget), page );
88d19775 201
3c4e4af6
RR
202 return TRUE;
203 }
8253c7fd
RR
204
205 /* win is a control: tab can be propagated up */
206 if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab))
207 {
3c4e4af6 208 int sel = notebook->GetSelection();
461573cc
RR
209 if (sel == -1)
210 return TRUE;
3c4e4af6 211 wxGtkNotebookPage *nb_page = notebook->GetNotebookPage(sel);
b318dc42 212 wxCHECK_MSG( nb_page, FALSE, _T("invalid selection in wxNotebook") );
8253c7fd
RR
213
214 wxNavigationKeyEvent event;
3c4e4af6 215 event.SetEventObject( notebook );
8253c7fd
RR
216 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
217 event.SetDirection( (gdk_event->keyval == GDK_Tab) );
218 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
88d19775 219 event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) ||
3c4e4af6
RR
220 (gdk_event->keyval == GDK_Left) || (gdk_event->keyval == GDK_Right) );
221 event.SetCurrentFocus( notebook );
07b8d7ec 222
3c4e4af6 223 wxNotebookPage *client = notebook->GetPage(sel);
07b8d7ec 224 if ( !client->GetEventHandler()->ProcessEvent( event ) )
8253c7fd 225 {
07b8d7ec 226 client->SetFocus();
8253c7fd 227 }
8712c6e7 228
8253c7fd
RR
229 return TRUE;
230 }
8712c6e7 231
8253c7fd
RR
232 return FALSE;
233}
865bb325 234}
8253c7fd 235
6ca41e57
RR
236//-----------------------------------------------------------------------------
237// InsertChild callback for wxNotebook
238//-----------------------------------------------------------------------------
239
d7f1759a 240static void wxInsertChildInNotebook( wxNotebook* parent, wxWindow* child )
6ca41e57 241{
fff8475e
RD
242 // Hack Alert! (Part I): This sets the notebook as the parent of the child
243 // widget, and takes care of some details such as updating the state and
244 // style of the child to reflect its new location. We do this early
245 // because without it GetBestSize (which is used to set the initial size
246 // of controls if an explicit size is not given) will often report
247 // incorrect sizes since the widget's style context is not fully known.
248 // See bug #901694 for details
2ded391d 249 // (http://sourceforge.net/tracker/?func=detail&aid=901694&group_id=9863&atid=109863)
fff8475e
RD
250 gtk_widget_set_parent(child->m_widget, parent->m_widget);
251
252 // NOTE: This should be considered a temporary workaround until we can
253 // work out the details and implement delaying the setting of the initial
254 // size of widgets until the size is really needed.
6ca41e57
RR
255}
256
53b28675
RR
257//-----------------------------------------------------------------------------
258// wxNotebook
259//-----------------------------------------------------------------------------
260
53b28675
RR
261IMPLEMENT_DYNAMIC_CLASS(wxNotebook,wxControl)
262
b98d804b
RR
263BEGIN_EVENT_TABLE(wxNotebook, wxControl)
264 EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
265END_EVENT_TABLE()
f861258f 266
ff829f3f 267void wxNotebook::Init()
53b28675 268{
b318dc42 269 m_padding = 0;
2b5f62a0 270
b292e2f5 271 m_imageList = (wxImageList *) NULL;
c9882624 272 m_oldSelection = -1;
de6185e2 273 m_themeEnabled = true;
ff829f3f
VZ
274}
275
276wxNotebook::wxNotebook()
277{
b292e2f5 278 Init();
ff7b1510 279}
53b28675 280
debe6624 281wxNotebook::wxNotebook( wxWindow *parent, wxWindowID id,
53b28675 282 const wxPoint& pos, const wxSize& size,
debe6624 283 long style, const wxString& name )
53b28675 284{
b292e2f5
RR
285 Init();
286 Create( parent, id, pos, size, style, name );
ff7b1510 287}
53b28675 288
ff829f3f 289wxNotebook::~wxNotebook()
53b28675 290{
b292e2f5 291 DeleteAllPages();
ff7b1510 292}
53b28675 293
debe6624 294bool wxNotebook::Create(wxWindow *parent, wxWindowID id,
07b8d7ec
VZ
295 const wxPoint& pos, const wxSize& size,
296 long style, const wxString& name )
53b28675 297{
de6185e2
WS
298 m_needParent = true;
299 m_acceptsFocus = true;
b292e2f5
RR
300 m_insertCallback = (wxInsertChildFunction)wxInsertChildInNotebook;
301
90f9b8ef
JS
302 if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
303 style |= wxBK_TOP;
304
4dcaf11a
RR
305 if (!PreCreation( parent, pos, size ) ||
306 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
307 {
223d09f6 308 wxFAIL_MSG( wxT("wxNoteBook creation failed") );
de6185e2 309 return false;
4dcaf11a
RR
310 }
311
ff829f3f 312
b292e2f5 313 m_widget = gtk_notebook_new();
53b28675 314
b292e2f5 315 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
caac5181 316
9fa72bd2 317 g_signal_connect (m_widget, "switch_page",
c9882624
RR
318 G_CALLBACK (gtk_notebook_page_changing_callback), this);
319
320 g_signal_connect_after (m_widget, "switch_page",
321 G_CALLBACK (gtk_notebook_page_changed_callback), this);
ff829f3f 322
f03fc89f 323 m_parent->DoAddChild( this );
ef44a621 324
df034cc6 325 if (m_windowStyle & wxBK_RIGHT)
8712c6e7 326 gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_RIGHT );
df034cc6 327 if (m_windowStyle & wxBK_LEFT)
8712c6e7 328 gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_LEFT );
df034cc6 329 if (m_windowStyle & wxBK_BOTTOM)
8712c6e7 330 gtk_notebook_set_tab_pos( GTK_NOTEBOOK(m_widget), GTK_POS_BOTTOM );
a3a7f879 331
9fa72bd2
MR
332 g_signal_connect (m_widget, "key_press_event",
333 G_CALLBACK (gtk_notebook_key_press_callback), this);
8253c7fd 334
abdeb9e7 335 PostCreation(size);
ff829f3f 336
9fa72bd2
MR
337 g_signal_connect (m_widget, "realize",
338 G_CALLBACK (gtk_notebook_realized_callback), this);
a6aa9b1e 339
de6185e2 340 return true;
ff7b1510 341}
53b28675 342
ff829f3f 343int wxNotebook::GetSelection() const
53b28675 344{
223d09f6 345 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
53b28675 346
c9882624 347 return gtk_notebook_get_current_page( GTK_NOTEBOOK(m_widget) );
ff7b1510 348}
53b28675 349
789d0a3d 350wxString wxNotebook::GetPageText( size_t page ) const
53b28675 351{
88a7a4e1 352 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid notebook") );
ef44a621 353
80a58c99 354 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
b292e2f5
RR
355 if (nb_page)
356 return nb_page->m_text;
357 else
88a7a4e1 358 return wxEmptyString;
ff7b1510 359}
53b28675 360
789d0a3d 361int wxNotebook::GetPageImage( size_t page ) const
53b28675 362{
223d09f6 363 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
a81258be 364
80a58c99 365 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
b292e2f5
RR
366 if (nb_page)
367 return nb_page->m_image;
368 else
587ce561 369 return -1;
ff7b1510 370}
53b28675 371
80a58c99 372wxGtkNotebookPage* wxNotebook::GetNotebookPage( int page ) const
53b28675 373{
80a58c99 374 wxCHECK_MSG( m_widget != NULL, (wxGtkNotebookPage*) NULL, wxT("invalid notebook") );
ff829f3f 375
07b8d7ec 376 wxCHECK_MSG( page < (int)m_pagesData.GetCount(), (wxGtkNotebookPage*) NULL, wxT("invalid notebook index") );
a6aa9b1e 377
07b8d7ec 378 return m_pagesData.Item(page)->GetData();
ff7b1510 379}
53b28675 380
1d6fcbcc 381int wxNotebook::DoSetSelection( size_t page, int flags )
53b28675 382{
223d09f6 383 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid notebook") );
a81258be 384
789d0a3d 385 wxCHECK_MSG( page < m_pagesData.GetCount(), -1, wxT("invalid notebook index") );
ff829f3f 386
587ce561 387 int selOld = GetSelection();
a6aa9b1e 388
1d6fcbcc 389 if ( !(flags & SetSelection_SendEvent) )
c9882624
RR
390 {
391 g_signal_handlers_disconnect_by_func (m_widget,
392 (gpointer) gtk_notebook_page_changing_callback,
393 this);
394
395 g_signal_handlers_disconnect_by_func (m_widget,
396 (gpointer) gtk_notebook_page_changed_callback,
397 this);
398 }
1d6fcbcc 399
38f1df7c 400 gtk_notebook_set_current_page( GTK_NOTEBOOK(m_widget), page );
ff829f3f 401
1d6fcbcc
VZ
402 if ( !(flags & SetSelection_SendEvent) )
403 {
c9882624
RR
404 // reconnect to signals
405
406 g_signal_connect (m_widget, "switch_page",
407 G_CALLBACK (gtk_notebook_page_changing_callback), this);
408
409 g_signal_connect_after (m_widget, "switch_page",
410 G_CALLBACK (gtk_notebook_page_changed_callback), this);
1d6fcbcc 411 }
1d6fcbcc 412
07b8d7ec
VZ
413 wxNotebookPage *client = GetPage(page);
414 if ( client )
415 client->SetFocus();
b656febd 416
07b8d7ec 417 return selOld;
ff7b1510 418}
53b28675 419
789d0a3d 420bool wxNotebook::SetPageText( size_t page, const wxString &text )
53b28675 421{
de6185e2 422 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid notebook") );
a81258be 423
80a58c99 424 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
ef44a621 425
de6185e2 426 wxCHECK_MSG( nb_page, false, wxT("SetPageText: invalid page index") );
ff829f3f 427
3eb78d7e 428 nb_page->m_text = text;
ff829f3f 429
a7c12d28 430 gtk_label_set_text( nb_page->m_label, wxGTK_CONV( nb_page->m_text ) );
a6aa9b1e 431
de6185e2 432 return true;
ff7b1510 433}
53b28675 434
789d0a3d 435bool wxNotebook::SetPageImage( size_t page, int image )
53b28675 436{
3eb78d7e 437 /* HvdH 28-12-98: now it works, but it's a bit of a kludge */
f861258f 438
80a58c99 439 wxGtkNotebookPage* nb_page = GetNotebookPage(page);
ef44a621 440
de6185e2 441 if (!nb_page) return false;
f861258f 442
3eb78d7e
RR
443 /* Optimization posibility: return immediately if image unchanged.
444 * Not enabled because it may break existing (stupid) code that
445 * manipulates the imagelist to cycle images */
f861258f 446
de6185e2 447 /* if (image == nb_page->m_image) return true; */
f861258f
VZ
448
449 /* For different cases:
3eb78d7e
RR
450 1) no image -> no image
451 2) image -> no image
452 3) no image -> image
453 4) image -> image */
f861258f 454
3eb78d7e 455 if (image == -1 && nb_page->m_image == -1)
de6185e2 456 return true; /* Case 1): Nothing to do. */
f861258f 457
bbe0af5b 458 GtkWidget *pixmapwid = (GtkWidget*) NULL;
f861258f
VZ
459
460 if (nb_page->m_image != -1)
3eb78d7e
RR
461 {
462 /* Case 2) or 4). There is already an image in the gtkhbox. Let's find it */
f861258f 463
2e14a116 464 GList *child = gtk_container_get_children(GTK_CONTAINER(nb_page->m_box));
279b5e2e 465 while (child)
8712c6e7 466 {
d41e1ab4 467 if (GTK_IS_IMAGE(child->data))
8712c6e7
VZ
468 {
469 pixmapwid = GTK_WIDGET(child->data);
470 break;
3eb78d7e 471 }
279b5e2e 472 child = child->next;
8712c6e7 473 }
f861258f 474
3eb78d7e 475 /* We should have the pixmap widget now */
f861258f
VZ
476 wxASSERT(pixmapwid != NULL);
477
478 if (image == -1)
8712c6e7 479 {
3eb78d7e
RR
480 /* If there's no new widget, just remove the old from the box */
481 gtk_container_remove(GTK_CONTAINER(nb_page->m_box), pixmapwid);
482 nb_page->m_image = -1;
53b28675 483
de6185e2 484 return true; /* Case 2) */
3eb78d7e
RR
485 }
486 }
f861258f 487
3eb78d7e
RR
488 /* Only cases 3) and 4) left */
489 wxASSERT( m_imageList != NULL ); /* Just in case */
f861258f 490
3eb78d7e 491 /* Construct the new pixmap */
49bf4e3e 492 const wxBitmap *bmp = m_imageList->GetBitmapPtr(image);
f861258f
VZ
493
494 if (pixmapwid == NULL)
3eb78d7e
RR
495 {
496 /* Case 3) No old pixmap. Create a new one and prepend it to the hbox */
d41e1ab4 497 pixmapwid = gtk_image_new_from_pixbuf(bmp->GetPixbuf());
f861258f 498
3eb78d7e 499 /* CHECKME: Are these pack flags okay? */
b318dc42 500 gtk_box_pack_start(GTK_BOX(nb_page->m_box), pixmapwid, FALSE, FALSE, m_padding);
3eb78d7e
RR
501 gtk_widget_show(pixmapwid);
502 }
f861258f 503 else
3eb78d7e
RR
504 {
505 /* Case 4) Simply replace the pixmap */
d41e1ab4 506 gtk_image_set_from_pixbuf((GtkImage*)pixmapwid, bmp->GetPixbuf());
3eb78d7e 507 }
f861258f 508
3eb78d7e 509 nb_page->m_image = image;
53b28675 510
de6185e2 511 return true;
ff7b1510 512}
53b28675
RR
513
514void wxNotebook::SetPageSize( const wxSize &WXUNUSED(size) )
515{
223d09f6 516 wxFAIL_MSG( wxT("wxNotebook::SetPageSize not implemented") );
ff7b1510 517}
53b28675 518
b318dc42 519void wxNotebook::SetPadding( const wxSize &padding )
53b28675 520{
b318dc42
JS
521 wxCHECK_RET( m_widget != NULL, wxT("invalid notebook") );
522
523 m_padding = padding.GetWidth();
524
525 int i;
526 for (i=0; i<int(GetPageCount()); i++)
527 {
528 wxGtkNotebookPage* nb_page = GetNotebookPage(i);
529 wxASSERT(nb_page != NULL);
530
531 if (nb_page->m_image != -1)
532 {
533 // gtk_box_set_child_packing sets padding on BOTH sides
534 // icon provides left padding, label provides center and right
535 int image = nb_page->m_image;
536 SetPageImage(i,-1);
537 SetPageImage(i,image);
538 }
539 wxASSERT(nb_page->m_label);
540 gtk_box_set_child_packing(GTK_BOX(nb_page->m_box),
541 GTK_WIDGET(nb_page->m_label),
542 FALSE, FALSE, m_padding, GTK_PACK_END);
543 }
ff7b1510 544}
53b28675 545
74e3313b 546void wxNotebook::SetTabSize(const wxSize& WXUNUSED(sz))
ca8b28f2 547{
223d09f6 548 wxFAIL_MSG( wxT("wxNotebook::SetTabSize not implemented") );
ca8b28f2
JS
549}
550
ff829f3f 551bool wxNotebook::DeleteAllPages()
53b28675 552{
de6185e2 553 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid notebook") );
a81258be 554
07b8d7ec
VZ
555 while (m_pagesData.GetCount() > 0)
556 DeletePage( m_pagesData.GetCount()-1 );
557
558 wxASSERT_MSG( GetPageCount() == 0, _T("all pages must have been deleted") );
ff829f3f 559
37144cf0 560 InvalidateBestSize();
10199e27 561 return wxNotebookBase::DeleteAllPages();
ff7b1510 562}
53b28675 563
acb69c13 564wxNotebookPage *wxNotebook::DoRemovePage( size_t page )
53b28675 565{
10199e27
VZ
566 wxNotebookPage *client = wxNotebookBase::DoRemovePage(page);
567 if ( !client )
568 return NULL;
fed46e72 569
07b8d7ec
VZ
570 gtk_widget_ref( client->m_widget );
571 gtk_widget_unrealize( client->m_widget );
9c862cfb
RR
572
573 // we don't need to unparent the client->m_widget; GTK+ will do
574 // that for us (and will throw a warning if we do it!)
07b8d7ec 575
587ce561 576 gtk_notebook_remove_page( GTK_NOTEBOOK(m_widget), page );
ff829f3f 577
222ed1d6
MB
578 wxGtkNotebookPage* p = GetNotebookPage(page);
579 m_pagesData.DeleteObject(p);
580 delete p;
ff829f3f 581
07b8d7ec 582 return client;
ff7b1510 583}
53b28675 584
789d0a3d 585bool wxNotebook::InsertPage( size_t position,
07b8d7ec
VZ
586 wxNotebookPage* win,
587 const wxString& text,
588 bool select,
589 int imageId )
53b28675 590{
de6185e2 591 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid notebook") );
a81258be 592
de6185e2 593 wxCHECK_MSG( win->GetParent() == this, false,
223d09f6 594 wxT("Can't add a page whose parent is not the notebook!") );
8aadf227 595
de6185e2 596 wxCHECK_MSG( position <= GetPageCount(), false,
07b8d7ec
VZ
597 _T("invalid page index in wxNotebookPage::InsertPage()") );
598
fff8475e
RD
599 // Hack Alert! (Part II): See above in wxInsertChildInNotebook callback
600 // why this has to be done. NOTE: using gtk_widget_unparent here does not
601 // work as it seems to undo too much and will cause errors in the
602 // gtk_notebook_insert_page below, so instead just clear the parent by
603 // hand here.
d7f1759a
RR
604 win->m_widget->parent = NULL;
605
a2d93e73 606 if (m_themeEnabled)
de6185e2 607 win->SetThemeEnabled(true);
a2d93e73 608
587ce561 609 GtkNotebook *notebook = GTK_NOTEBOOK(m_widget);
53b28675 610
b318dc42 611 wxGtkNotebookPage *nb_page = new wxGtkNotebookPage();
a6aa9b1e 612
07b8d7ec 613 if ( position == GetPageCount() )
b318dc42 614 m_pagesData.Append( nb_page );
587ce561 615 else
1c36a9d3 616 m_pagesData.Insert( position, nb_page );
a6aa9b1e 617
07b8d7ec 618 m_pages.Insert(win, position);
8aadf227 619
b318dc42 620 nb_page->m_box = gtk_hbox_new( FALSE, 1 );
d41e1ab4 621 gtk_container_set_border_width((GtkContainer*)nb_page->m_box, 2);
587ce561 622
9fa72bd2
MR
623 g_signal_connect (win->m_widget, "size_allocate",
624 G_CALLBACK (gtk_page_size_callback), win);
d1af991f 625
bd090f77 626 gtk_notebook_insert_page( notebook, win->m_widget, nb_page->m_box, position );
587ce561 627
b318dc42 628 nb_page->m_page = (GtkNotebookPage*) g_list_last(notebook->children)->data;
ef44a621 629
587ce561 630 /* set the label image */
b318dc42 631 nb_page->m_image = imageId;
a6aa9b1e 632
3eb78d7e 633 if (imageId != -1)
e4a81a2e 634 {
3eb78d7e
RR
635 wxASSERT( m_imageList != NULL );
636
49bf4e3e 637 const wxBitmap *bmp = m_imageList->GetBitmapPtr(imageId);
d41e1ab4 638 GtkWidget* pixmapwid = gtk_image_new_from_pixbuf(bmp->GetPixbuf());
b318dc42 639 gtk_box_pack_start(GTK_BOX(nb_page->m_box), pixmapwid, FALSE, FALSE, m_padding);
3eb78d7e
RR
640 gtk_widget_show(pixmapwid);
641 }
24d20a8f 642
587ce561 643 /* set the label text */
c077ee94 644
3ba6891d 645 nb_page->m_text = wxStripMenuCodes(text);
8e609c82 646 if (nb_page->m_text.empty()) nb_page->m_text = wxEmptyString;
279b5e2e 647
73e68c1d 648 nb_page->m_label = GTK_LABEL( gtk_label_new(wxGTK_CONV(nb_page->m_text)) );
b318dc42 649 gtk_box_pack_end( GTK_BOX(nb_page->m_box), GTK_WIDGET(nb_page->m_label), FALSE, FALSE, m_padding );
279b5e2e 650
97357eec
VS
651 /* apply current style */
652 GtkRcStyle *style = CreateWidgetStyle();
653 if ( style )
654 {
655 gtk_widget_modify_style(GTK_WIDGET(nb_page->m_label), style);
656 gtk_rc_style_unref(style);
88d19775
MR
657 }
658
587ce561 659 /* show the label */
b318dc42 660 gtk_widget_show( GTK_WIDGET(nb_page->m_label) );
c9882624 661
07b8d7ec 662 if (select && (m_pagesData.GetCount() > 1))
587ce561 663 {
c9882624 664 SetSelection( position );
587ce561 665 }
741fd203 666
37144cf0 667 InvalidateBestSize();
de6185e2 668 return true;
ff7b1510 669}
53b28675 670
279b5e2e
VZ
671// helper for HitTest(): check if the point lies inside the given widget which
672// is the child of the notebook whose position and border size are passed as
673// parameters
674static bool
675IsPointInsideWidget(const wxPoint& pt, GtkWidget *w,
676 gint x, gint y, gint border = 0)
677{
678 return
679 (pt.x >= w->allocation.x - x - border) &&
680 (pt.x <= w->allocation.x - x + border + w->allocation.width) &&
681 (pt.y >= w->allocation.y - y - border) &&
682 (pt.y <= w->allocation.y - y + border + w->allocation.height);
683}
684
685int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
686{
687 const gint x = m_widget->allocation.x;
688 const gint y = m_widget->allocation.y;
689
690 const size_t count = GetPageCount();
f660b206
MR
691 size_t i = 0;
692
f660b206 693 GtkNotebook * notebook = GTK_NOTEBOOK(m_widget);
a5bb4f82 694 if (gtk_notebook_get_scrollable(notebook))
f660b206 695 i = g_list_position( notebook->children, notebook->first_tab );
f660b206
MR
696
697 for ( ; i < count; i++ )
279b5e2e
VZ
698 {
699 wxGtkNotebookPage* nb_page = GetNotebookPage(i);
700 GtkWidget *box = nb_page->m_box;
701
279b5e2e 702 const gint border = gtk_container_get_border_width(GTK_CONTAINER(box));
68567a96 703
279b5e2e
VZ
704 if ( IsPointInsideWidget(pt, box, x, y, border) )
705 {
706 // ok, we're inside this tab -- now find out where, if needed
707 if ( flags )
708 {
709 GtkWidget *pixmap = NULL;
710
2e14a116 711 GList *children = gtk_container_get_children(GTK_CONTAINER(box));
279b5e2e
VZ
712 for ( GList *child = children; child; child = child->next )
713 {
d41e1ab4 714 if (GTK_IS_IMAGE(child->data))
279b5e2e
VZ
715 {
716 pixmap = GTK_WIDGET(child->data);
717 break;
718 }
719 }
720
721 if ( children )
722 g_list_free(children);
723
724 if ( pixmap && IsPointInsideWidget(pt, pixmap, x, y) )
725 {
9804d540 726 *flags = wxBK_HITTEST_ONICON;
279b5e2e
VZ
727 }
728 else if ( IsPointInsideWidget(pt, GTK_WIDGET(nb_page->m_label), x, y) )
729 {
9804d540 730 *flags = wxBK_HITTEST_ONLABEL;
279b5e2e
VZ
731 }
732 else
733 {
9804d540 734 *flags = wxBK_HITTEST_ONITEM;
279b5e2e
VZ
735 }
736 }
737
738 return i;
739 }
740 }
741
742 if ( flags )
d0a84b63 743 {
9804d540 744 *flags = wxBK_HITTEST_NOWHERE;
d0a84b63
VZ
745 wxWindowBase * page = GetCurrentPage();
746 if ( page )
747 {
748 // rect origin is in notebook's parent coordinates
749 wxRect rect = page->GetRect();
750
751 // adjust it to the notebook's coordinates
752 wxPoint pos = GetPosition();
753 rect.x -= pos.x;
754 rect.y -= pos.y;
22a35096 755 if ( rect.Contains( pt ) )
9804d540 756 *flags |= wxBK_HITTEST_ONPAGE;
d0a84b63
VZ
757 }
758 }
279b5e2e
VZ
759
760 return wxNOT_FOUND;
761}
762
b98d804b
RR
763void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
764{
f861258f 765 if (event.IsWindowChange())
b98d804b 766 AdvanceSelection( event.GetDirection() );
f861258f 767 else
b98d804b
RR
768 event.Skip();
769}
770
93d38175
VS
771#if wxUSE_CONSTRAINTS
772
5a8c929e 773// override these 2 functions to do nothing: everything is done in OnSize
e3e65dac 774void wxNotebook::SetConstraintSizes( bool WXUNUSED(recurse) )
5a8c929e 775{
b292e2f5 776 // don't set the sizes of the pages - their correct size is not yet known
de6185e2 777 wxControl::SetConstraintSizes(false);
5a8c929e
VZ
778}
779
e3e65dac 780bool wxNotebook::DoPhase( int WXUNUSED(nPhase) )
5a8c929e 781{
de6185e2 782 return true;
5a8c929e
VZ
783}
784
93d38175
VS
785#endif
786
f40fdaa3 787void wxNotebook::DoApplyWidgetStyle(GtkRcStyle *style)
a81258be 788{
97357eec
VS
789 gtk_widget_modify_style(m_widget, style);
790 size_t cnt = m_pagesData.GetCount();
791 for (size_t i = 0; i < cnt; i++)
792 gtk_widget_modify_style(GTK_WIDGET(GetNotebookPage(i)->m_label), style);
a81258be
RR
793}
794
ef5c70f9 795GdkWindow *wxNotebook::GTKGetWindow(wxArrayGdkWindows& windows) const
58d1c1ae 796{
ef5c70f9
VZ
797 windows.push_back(m_widget->window);
798 windows.push_back(GTK_NOTEBOOK(m_widget)->event_window);
799
800 return NULL;
58d1c1ae
RR
801}
802
9d522606
RD
803// static
804wxVisualAttributes
805wxNotebook::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
806{
807 return GetDefaultAttributesFromGTKWidget(gtk_notebook_new);
808}
809
53b28675 810//-----------------------------------------------------------------------------
ff829f3f 811// wxNotebookEvent
53b28675
RR
812//-----------------------------------------------------------------------------
813
92976ab6 814IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
5b011451 815
a3a7f879 816#endif