Added background colour again
[wxWidgets.git] / src / gtk / notebook.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: notebook.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "notebook.h"
12 #endif
13
14 #include "wx/notebook.h"
15 #include "wx/panel.h"
16 #include "wx/utils.h"
17 #include "wx/imaglist.h"
18 #include "wx/intl.h"
19 #include "wx/log.h"
20
21 //-----------------------------------------------------------------------------
22 // wxNotebookPage
23 //-----------------------------------------------------------------------------
24
25 class wxNotebookPage: public wxObject
26 {
27 public:
28 wxNotebookPage()
29 {
30 m_id = -1;
31 m_text = "";
32 m_image = -1;
33 m_page = (GtkNotebookPage *) NULL;
34 m_client = (wxWindow *) NULL;
35 m_parent = (GtkNotebook *) NULL;
36 m_box = (GtkWidget *) NULL;
37 }
38
39 //private:
40 int m_id;
41 wxString m_text;
42 int m_image;
43 GtkNotebookPage *m_page;
44 GtkLabel *m_label;
45 wxWindow *m_client;
46 GtkNotebook *m_parent;
47 GtkWidget *m_box; // in which the label and image are packed
48 };
49
50 //-----------------------------------------------------------------------------
51 // "switch_page"
52 //-----------------------------------------------------------------------------
53
54 static void gtk_notebook_page_change_callback(GtkNotebook *WXUNUSED(widget),
55 GtkNotebookPage *WXUNUSED(page),
56 gint nPage,
57 gpointer data)
58 {
59 wxNotebook *notebook = (wxNotebook *)data;
60
61 int old = notebook->GetSelection();
62
63 // TODO: emulate PAGE_CHANGING event
64
65 wxNotebookEvent event( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
66 notebook->GetId(), nPage, old );
67 event.SetEventObject( notebook );
68 notebook->GetEventHandler()->ProcessEvent( event );
69 }
70
71 //-----------------------------------------------------------------------------
72 // "size_allocate"
73 //-----------------------------------------------------------------------------
74
75 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
76 {
77 if (win->GetAutoLayout()) win->Layout();
78
79 if ((win->m_x == alloc->x) &&
80 (win->m_y == alloc->y) &&
81 (win->m_width == alloc->width) &&
82 (win->m_height == alloc->height))
83 {
84 return;
85 }
86
87 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
88 }
89
90 //-----------------------------------------------------------------------------
91 // wxNotebook
92 //-----------------------------------------------------------------------------
93
94 IMPLEMENT_DYNAMIC_CLASS(wxNotebook,wxControl)
95
96 void wxNotebook::Init()
97 {
98 m_imageList = (wxImageList *) NULL;
99 m_pages.DeleteContents( TRUE );
100 m_idHandler = 0;
101 }
102
103 wxNotebook::wxNotebook()
104 {
105 Init();
106 }
107
108 wxNotebook::wxNotebook( wxWindow *parent, wxWindowID id,
109 const wxPoint& pos, const wxSize& size,
110 long style, const wxString& name )
111 {
112 Init();
113 Create( parent, id, pos, size, style, name );
114 }
115
116 wxNotebook::~wxNotebook()
117 {
118 // don't generate change page events any more
119 if (m_idHandler != 0)
120 gtk_signal_disconnect(GTK_OBJECT(m_widget), m_idHandler);
121
122 DeleteAllPages();
123 }
124
125 bool wxNotebook::Create(wxWindow *parent, wxWindowID id,
126 const wxPoint& pos, const wxSize& size,
127 long style, const wxString& name )
128 {
129 m_needParent = TRUE;
130
131 PreCreation( parent, id, pos, size, style, name );
132
133 m_widget = gtk_notebook_new();
134
135 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
136
137 m_idHandler = gtk_signal_connect
138 (
139 GTK_OBJECT(m_widget), "switch_page",
140 GTK_SIGNAL_FUNC(gtk_notebook_page_change_callback),
141 (gpointer)this
142 );
143
144 PostCreation();
145
146 Show( TRUE );
147
148 return TRUE;
149 }
150
151 int wxNotebook::GetSelection() const
152 {
153 wxCHECK_MSG( m_widget != NULL, -1, "invalid notebook" );
154
155 if (m_pages.Number() == 0) return -1;
156
157 GtkNotebookPage *g_page = GTK_NOTEBOOK(m_widget)->cur_page;
158
159 wxNotebookPage *page = (wxNotebookPage *) NULL;
160
161 wxNode *node = m_pages.First();
162 while (node)
163 {
164 page = (wxNotebookPage*)node->Data();
165 if (page->m_page == g_page)
166 break;
167 node = node->Next();
168 }
169
170 wxCHECK_MSG( node != NULL, -1, "wxNotebook: no selection?" );
171
172 return page->m_id;
173 }
174
175 int wxNotebook::GetPageCount() const
176 {
177 return m_pages.Number();
178 }
179
180 int wxNotebook::GetRowCount() const
181 {
182 return 1;
183 }
184
185 wxString wxNotebook::GetPageText( int page ) const
186 {
187 wxCHECK_MSG( m_widget != NULL, "", "invalid notebook" );
188
189 wxNotebookPage* nb_page = GetNotebookPage(page);
190 if (nb_page)
191 return nb_page->m_text;
192 else
193 return "";
194 }
195
196 int wxNotebook::GetPageImage( int page ) const
197 {
198 wxCHECK_MSG( m_widget != NULL, 0, "invalid notebook" );
199
200 wxNotebookPage* nb_page = GetNotebookPage(page);
201 if (nb_page)
202 return nb_page->m_image;
203 else
204 return 0;
205 }
206
207 wxNotebookPage* wxNotebook::GetNotebookPage(int page) const
208 {
209 wxCHECK_MSG( m_widget != NULL, (wxNotebookPage*)NULL, "invalid notebook" );
210
211 wxNotebookPage *nb_page = (wxNotebookPage *) NULL;
212
213 wxNode *node = m_pages.First();
214 while (node)
215 {
216 nb_page = (wxNotebookPage*)node->Data();
217 if (nb_page->m_id == page)
218 return nb_page;
219 node = node->Next();
220 }
221
222 wxLogDebug( "Notebook page %d not found!", page );
223
224 return (wxNotebookPage *) NULL;
225 }
226
227 int wxNotebook::SetSelection( int page )
228 {
229 wxCHECK_MSG( m_widget != NULL, -1, "invalid notebook" );
230
231 int selOld = GetSelection();
232 wxNotebookPage* nb_page = GetNotebookPage(page);
233
234 if (!nb_page) return -1;
235
236 int page_num = 0;
237 GList *child = GTK_NOTEBOOK(m_widget)->children;
238 while (child)
239 {
240 if (nb_page->m_page == (GtkNotebookPage*)child->data) break;
241 page_num++;
242 child = child->next;
243 }
244
245 if (!child) return -1;
246
247 gtk_notebook_set_page( GTK_NOTEBOOK(m_widget), page_num );
248
249 return selOld;
250 }
251
252 void wxNotebook::AdvanceSelection( bool bForward )
253 {
254 wxCHECK_RET( m_widget != NULL, "invalid notebook" );
255
256 int sel = GetSelection();
257 int max = GetPageCount();
258
259 if (bForward)
260 SetSelection( sel == max ? 0 : sel + 1 );
261 else
262 SetSelection( sel == 0 ? max : sel - 1 );
263 }
264
265 void wxNotebook::SetImageList( wxImageList* imageList )
266 {
267 m_imageList = imageList;
268 }
269
270 bool wxNotebook::SetPageText( int page, const wxString &text )
271 {
272 wxCHECK_MSG( m_widget != NULL, FALSE, "invalid notebook" );
273
274 wxNotebookPage* nb_page = GetNotebookPage(page);
275
276 if (!nb_page) return FALSE;
277
278 nb_page->m_text = text;
279
280 return TRUE;
281 }
282
283 bool wxNotebook::SetPageImage( int page, int image )
284 {
285 wxNotebookPage* nb_page = GetNotebookPage(page);
286
287 if (!nb_page) return FALSE;
288
289 nb_page->m_image = image;
290
291 return TRUE;
292 }
293
294 void wxNotebook::SetPageSize( const wxSize &WXUNUSED(size) )
295 {
296 wxFAIL_MSG( "wxNotebook::SetPageSize not implemented" );
297 }
298
299 void wxNotebook::SetPadding( const wxSize &WXUNUSED(padding) )
300 {
301 wxFAIL_MSG( "wxNotebook::SetPadding not implemented" );
302 }
303
304 bool wxNotebook::DeleteAllPages()
305 {
306 wxCHECK_MSG( m_widget != NULL, FALSE, "invalid notebook" );
307
308 wxNode *page_node = m_pages.First();
309 while (page_node)
310 {
311 wxNotebookPage *page = (wxNotebookPage*)page_node->Data();
312
313 DeletePage( page->m_id );
314
315 page_node = m_pages.First();
316 }
317
318 return TRUE;
319 }
320
321 bool wxNotebook::DeletePage( int page )
322 {
323 wxNotebookPage* nb_page = GetNotebookPage(page);
324 if (!nb_page) return FALSE;
325
326 int page_num = 0;
327 GList *child = GTK_NOTEBOOK(m_widget)->children;
328 while (child)
329 {
330 if (nb_page->m_page == (GtkNotebookPage*)child->data) break;
331 page_num++;
332 child = child->next;
333 }
334
335 wxASSERT( child );
336
337 delete nb_page->m_client;
338
339 // Amazingly, this is not necessary
340 // gtk_notebook_remove_page( GTK_NOTEBOOK(m_widget), page_num );
341
342 m_pages.DeleteObject( nb_page );
343
344 return TRUE;
345 }
346
347 bool wxNotebook::AddPage(wxWindow* win, const wxString& text,
348 bool bSelect, int imageId)
349 {
350 wxCHECK_MSG( m_widget != NULL, FALSE, "invalid notebook" );
351
352 // we've created the notebook page in AddChild(). Now we just have to set
353 // the caption for the page and set the others parameters.
354
355 wxNotebookPage *page = (wxNotebookPage *) NULL;
356
357 wxNode *node = m_pages.First();
358 while (node)
359 {
360 page = (wxNotebookPage*)node->Data();
361 if ( page->m_client == win ) break;
362 node = node->Next();
363 }
364
365 wxCHECK_MSG( page != NULL, FALSE, "Can't add a page whose parent is not the notebook!" );
366
367 if (imageId != -1)
368 {
369 wxASSERT( m_imageList != NULL );
370
371 const wxBitmap *bmp = m_imageList->GetBitmap(imageId);
372 GdkPixmap *pixmap = bmp->GetPixmap();
373 GdkBitmap *mask = (GdkBitmap*) NULL;
374 if ( bmp->GetMask() )
375 {
376 mask = bmp->GetMask()->GetBitmap();
377 }
378
379 GtkWidget *pixmapwid = gtk_pixmap_new (pixmap, mask );
380
381 gtk_box_pack_start(GTK_BOX(page->m_box), pixmapwid, FALSE, FALSE, 3);
382
383 gtk_widget_show(pixmapwid);
384 }
385
386 // then set the attributes
387 page->m_text = text;
388 if (page->m_text.IsEmpty()) page->m_text = "";
389 page->m_image = imageId;
390 page->m_label = (GtkLabel *)gtk_label_new(page->m_text);
391 gtk_box_pack_start( GTK_BOX(page->m_box), (GtkWidget *)page->m_label, FALSE, FALSE, 3);
392
393 // @@@: what does this do? do we still need it?
394 // gtk_misc_set_alignment(GTK_MISC(page->m_label), 0.0, 0.5);
395
396 gtk_widget_show((GtkWidget *)page->m_label);
397
398 if (bSelect) SetSelection(GetPageCount());
399
400 return TRUE;
401 }
402
403 wxWindow *wxNotebook::GetPage( int page ) const
404 {
405 wxCHECK_MSG( m_widget != NULL, (wxWindow*) NULL, "invalid notebook" );
406
407 wxNotebookPage* nb_page = GetNotebookPage(page);
408 if (!nb_page)
409 return (wxWindow *) NULL;
410 else
411 return nb_page->m_client;
412 }
413
414 void wxNotebook::AddChild( wxWindow *win )
415 {
416 wxCHECK_RET( m_widget != NULL, "invalid notebook" );
417
418 m_children.Append(win);
419
420 wxNotebookPage *page = new wxNotebookPage();
421
422 page->m_id = GetPageCount();
423
424 page->m_box = gtk_hbox_new (FALSE, 0);
425 gtk_container_border_width(GTK_CONTAINER(page->m_box), 2);
426
427 page->m_client = win;
428 gtk_notebook_append_page( GTK_NOTEBOOK(m_widget), win->m_widget, page->m_box );
429
430 page->m_page =
431 (GtkNotebookPage*) (g_list_last(GTK_NOTEBOOK(m_widget)->children)->data);
432
433 page->m_parent = GTK_NOTEBOOK(m_widget);
434
435 gtk_signal_connect( GTK_OBJECT(win->m_widget), "size_allocate",
436 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)win );
437
438 if (!page->m_page)
439 {
440 wxLogFatalError( "Notebook page creation error" );
441 return;
442 }
443
444 m_pages.Append( page );
445 }
446
447 // override these 2 functions to do nothing: everything is done in OnSize
448 void wxNotebook::SetConstraintSizes( bool WXUNUSED(recurse) )
449 {
450 // don't set the sizes of the pages - their correct size is not yet known
451 wxControl::SetConstraintSizes(FALSE);
452 }
453
454 bool wxNotebook::DoPhase( int WXUNUSED(nPhase) )
455 {
456 return TRUE;
457 }
458
459 void wxNotebook::SetFont( const wxFont &font )
460 {
461 wxCHECK_RET( m_widget != NULL, "invalid notebook" );
462
463 wxControl::SetFont( font );
464
465 gtk_widget_set_style( m_widget, m_widgetStyle );
466 }
467
468 void wxNotebook::SetBackgroundColour( const wxColour &colour )
469 {
470 wxCHECK_RET( m_widget != NULL, "invalid notebook" );
471
472 wxControl::SetBackgroundColour( colour );
473
474 if (!m_backgroundColour.Ok()) return;
475
476 gtk_widget_set_style( m_widget, m_widgetStyle );
477 }
478
479 //-----------------------------------------------------------------------------
480 // wxNotebookEvent
481 //-----------------------------------------------------------------------------
482
483 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent)
484