| |
1 /* gtkellview.c |
| |
2 * Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org> |
| |
3 * |
| |
4 * This library is free software; you can redistribute it and/or |
| |
5 * modify it under the terms of the GNU Library General Public |
| |
6 * License as published by the Free Software Foundation; either |
| |
7 * version 2 of the License, or (at your option) any later version. |
| |
8 * |
| |
9 * This library is distributed in the hope that it will be useful, |
| |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| |
12 * Library General Public License for more details. |
| |
13 * |
| |
14 * You should have received a copy of the GNU Library General Public |
| |
15 * License along with this library; if not, write to the |
| |
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| |
17 * Boston, MA 02111-1307, USA. |
| |
18 */ |
| |
19 |
| |
20 /* |
| |
21 #include <config.h> |
| |
22 */ |
| |
23 #include "gtkcellview.h" |
| |
24 #include <gtk/gtkversion.h> |
| |
25 #if !GTK_CHECK_VERSION(2,6,0) |
| |
26 #if GTK_CHECK_VERSION(2,4,0) |
| |
27 #include <gtk/gtkcelllayout.h> |
| |
28 #else |
| |
29 #include "gtkcelllayout.h" |
| |
30 #endif |
| |
31 #include <gtk/gtksignal.h> |
| |
32 #include <gtk/gtkcellrenderertext.h> |
| |
33 #include <gtk/gtkcellrendererpixbuf.h> |
| |
34 #include <gobject/gmarshal.h> |
| |
35 |
| |
36 #define P_(x) (x) |
| |
37 |
| |
38 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo; |
| |
39 struct _GtkCellViewCellInfo |
| |
40 { |
| |
41 GtkCellRenderer *cell; |
| |
42 |
| |
43 gint requested_width; |
| |
44 gint real_width; |
| |
45 guint expand : 1; |
| |
46 guint pack : 1; |
| |
47 |
| |
48 GSList *attributes; |
| |
49 |
| |
50 GtkCellLayoutDataFunc func; |
| |
51 gpointer func_data; |
| |
52 GDestroyNotify destroy; |
| |
53 }; |
| |
54 |
| |
55 struct _GtkCellViewPrivate |
| |
56 { |
| |
57 GtkTreeModel *model; |
| |
58 GtkTreeRowReference *displayed_row; |
| |
59 GList *cell_list; |
| |
60 gint spacing; |
| |
61 |
| |
62 GdkColor background; |
| |
63 gboolean background_set; |
| |
64 }; |
| |
65 |
| |
66 |
| |
67 static void gtk_cell_view_class_init (GtkCellViewClass *klass); |
| |
68 static void gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface); |
| |
69 static void gtk_cell_view_get_property (GObject *object, |
| |
70 guint param_id, |
| |
71 GValue *value, |
| |
72 GParamSpec *pspec); |
| |
73 static void gtk_cell_view_set_property (GObject *object, |
| |
74 guint param_id, |
| |
75 const GValue *value, |
| |
76 GParamSpec *pspec); |
| |
77 static void gtk_cell_view_init (GtkCellView *cellview); |
| |
78 static void gtk_cell_view_finalize (GObject *object); |
| |
79 static void gtk_cell_view_style_set (GtkWidget *widget, |
| |
80 GtkStyle *previous_style); |
| |
81 static void gtk_cell_view_size_request (GtkWidget *widget, |
| |
82 GtkRequisition *requisition); |
| |
83 static void gtk_cell_view_size_allocate (GtkWidget *widget, |
| |
84 GtkAllocation *allocation); |
| |
85 static gboolean gtk_cell_view_expose (GtkWidget *widget, |
| |
86 GdkEventExpose *event); |
| |
87 static void gtk_cell_view_set_valuesv (GtkCellView *cellview, |
| |
88 GtkCellRenderer *renderer, |
| |
89 va_list args); |
| |
90 static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview, |
| |
91 GtkCellRenderer *renderer); |
| |
92 static void gtk_cell_view_set_cell_data (GtkCellView *cellview); |
| |
93 |
| |
94 |
| |
95 static void gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, |
| |
96 GtkCellRenderer *renderer, |
| |
97 gboolean expand); |
| |
98 static void gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, |
| |
99 GtkCellRenderer *renderer, |
| |
100 gboolean expand); |
| |
101 static void gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, |
| |
102 GtkCellRenderer *renderer, |
| |
103 const gchar *attribute, |
| |
104 gint column); |
| |
105 static void gtk_cell_view_cell_layout_clear (GtkCellLayout *layout); |
| |
106 static void gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, |
| |
107 GtkCellRenderer *renderer); |
| |
108 static void gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, |
| |
109 GtkCellRenderer *cell, |
| |
110 GtkCellLayoutDataFunc func, |
| |
111 gpointer func_data, |
| |
112 GDestroyNotify destroy); |
| |
113 static void gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, |
| |
114 GtkCellRenderer *cell, |
| |
115 gint position); |
| |
116 |
| |
117 |
| |
118 enum |
| |
119 { |
| |
120 PROP_0, |
| |
121 PROP_BACKGROUND, |
| |
122 PROP_BACKGROUND_GDK, |
| |
123 PROP_BACKGROUND_SET |
| |
124 }; |
| |
125 |
| |
126 static GtkObjectClass *parent_class = NULL; |
| |
127 |
| |
128 |
| |
129 GType |
| |
130 gtk_cell_view_get_type (void) |
| |
131 { |
| |
132 static GType cell_view_type = 0; |
| |
133 |
| |
134 if (!cell_view_type) |
| |
135 { |
| |
136 static const GTypeInfo cell_view_info = |
| |
137 { |
| |
138 sizeof (GtkCellViewClass), |
| |
139 NULL, /* base_init */ |
| |
140 NULL, /* base_finalize */ |
| |
141 (GClassInitFunc) gtk_cell_view_class_init, |
| |
142 NULL, /* class_finalize */ |
| |
143 NULL, /* class_data */ |
| |
144 sizeof (GtkCellView), |
| |
145 0, |
| |
146 (GInstanceInitFunc) gtk_cell_view_init |
| |
147 }; |
| |
148 |
| |
149 static const GInterfaceInfo cell_layout_info = |
| |
150 { |
| |
151 (GInterfaceInitFunc) gtk_cell_view_cell_layout_init, |
| |
152 NULL, |
| |
153 NULL |
| |
154 }; |
| |
155 |
| |
156 cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GaimGtkCellView", |
| |
157 &cell_view_info, 0); |
| |
158 |
| |
159 g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT, |
| |
160 &cell_layout_info); |
| |
161 } |
| |
162 |
| |
163 return cell_view_type; |
| |
164 } |
| |
165 |
| |
166 static void |
| |
167 gtk_cell_view_class_init (GtkCellViewClass *klass) |
| |
168 { |
| |
169 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
| |
170 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
| |
171 |
| |
172 parent_class = g_type_class_peek_parent (klass); |
| |
173 |
| |
174 gobject_class->get_property = gtk_cell_view_get_property; |
| |
175 gobject_class->set_property = gtk_cell_view_set_property; |
| |
176 gobject_class->finalize = gtk_cell_view_finalize; |
| |
177 |
| |
178 widget_class->expose_event = gtk_cell_view_expose; |
| |
179 widget_class->size_allocate = gtk_cell_view_size_allocate; |
| |
180 widget_class->size_request = gtk_cell_view_size_request; |
| |
181 widget_class->style_set = gtk_cell_view_style_set; |
| |
182 |
| |
183 /* properties */ |
| |
184 g_object_class_install_property (gobject_class, |
| |
185 PROP_BACKGROUND, |
| |
186 g_param_spec_string ("background", |
| |
187 P_("Background color name"), |
| |
188 P_("Background color as a string"), |
| |
189 NULL, |
| |
190 G_PARAM_WRITABLE)); |
| |
191 g_object_class_install_property (gobject_class, |
| |
192 PROP_BACKGROUND_GDK, |
| |
193 g_param_spec_boxed ("background_gdk", |
| |
194 P_("Background color"), |
| |
195 P_("Background color as a GdkColor"), |
| |
196 GDK_TYPE_COLOR, |
| |
197 G_PARAM_READABLE | G_PARAM_WRITABLE)); |
| |
198 |
| |
199 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE)) |
| |
200 |
| |
201 ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET, |
| |
202 P_("Background set"), |
| |
203 P_("Whether this tag affects the background color")); |
| |
204 } |
| |
205 |
| |
206 static void |
| |
207 gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface) |
| |
208 { |
| |
209 iface->pack_start = gtk_cell_view_cell_layout_pack_start; |
| |
210 iface->pack_end = gtk_cell_view_cell_layout_pack_end; |
| |
211 iface->clear = gtk_cell_view_cell_layout_clear; |
| |
212 iface->add_attribute = gtk_cell_view_cell_layout_add_attribute; |
| |
213 iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func; |
| |
214 iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes; |
| |
215 iface->reorder = gtk_cell_view_cell_layout_reorder; |
| |
216 } |
| |
217 |
| |
218 static void |
| |
219 gtk_cell_view_get_property (GObject *object, |
| |
220 guint param_id, |
| |
221 GValue *value, |
| |
222 GParamSpec *pspec) |
| |
223 { |
| |
224 GtkCellView *view = GTK_CELL_VIEW (object); |
| |
225 |
| |
226 switch (param_id) |
| |
227 { |
| |
228 case PROP_BACKGROUND_GDK: |
| |
229 { |
| |
230 GdkColor color; |
| |
231 |
| |
232 color = view->priv->background; |
| |
233 |
| |
234 g_value_set_boxed (value, &color); |
| |
235 } |
| |
236 break; |
| |
237 case PROP_BACKGROUND_SET: |
| |
238 g_value_set_boolean (value, view->priv->background_set); |
| |
239 break; |
| |
240 default: |
| |
241 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); |
| |
242 break; |
| |
243 } |
| |
244 } |
| |
245 |
| |
246 static void |
| |
247 gtk_cell_view_set_property (GObject *object, |
| |
248 guint param_id, |
| |
249 const GValue *value, |
| |
250 GParamSpec *pspec) |
| |
251 { |
| |
252 GtkCellView *view = GTK_CELL_VIEW (object); |
| |
253 |
| |
254 switch (param_id) |
| |
255 { |
| |
256 case PROP_BACKGROUND: |
| |
257 { |
| |
258 GdkColor color; |
| |
259 |
| |
260 if (!g_value_get_string (value)) |
| |
261 gtk_cell_view_set_background_color (view, NULL); |
| |
262 else if (gdk_color_parse (g_value_get_string (value), &color)) |
| |
263 gtk_cell_view_set_background_color (view, &color); |
| |
264 else |
| |
265 g_warning ("Don't know color `%s'", g_value_get_string (value)); |
| |
266 |
| |
267 g_object_notify (object, "background_gdk"); |
| |
268 } |
| |
269 break; |
| |
270 case PROP_BACKGROUND_GDK: |
| |
271 gtk_cell_view_set_background_color (view, g_value_get_boxed (value)); |
| |
272 break; |
| |
273 case PROP_BACKGROUND_SET: |
| |
274 view->priv->background_set = g_value_get_boolean (value); |
| |
275 break; |
| |
276 default: |
| |
277 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); |
| |
278 break; |
| |
279 } |
| |
280 } |
| |
281 |
| |
282 static void |
| |
283 gtk_cell_view_init (GtkCellView *cellview) |
| |
284 { |
| |
285 GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW); |
| |
286 |
| |
287 cellview->priv = g_new0(GtkCellViewPrivate,1); |
| |
288 } |
| |
289 |
| |
290 static void |
| |
291 gtk_cell_view_style_set (GtkWidget *widget, |
| |
292 GtkStyle *previous_style) |
| |
293 { |
| |
294 if (previous_style && GTK_WIDGET_REALIZED (widget)) |
| |
295 gdk_window_set_background (widget->window, |
| |
296 &widget->style->base[GTK_WIDGET_STATE (widget)]); |
| |
297 } |
| |
298 |
| |
299 static void |
| |
300 gtk_cell_view_finalize (GObject *object) |
| |
301 { |
| |
302 GtkCellView *cellview = GTK_CELL_VIEW (object); |
| |
303 |
| |
304 gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview)); |
| |
305 |
| |
306 if (cellview->priv->model) |
| |
307 g_object_unref (cellview->priv->model); |
| |
308 |
| |
309 if (cellview->priv->displayed_row) |
| |
310 gtk_tree_row_reference_free (cellview->priv->displayed_row); |
| |
311 |
| |
312 if (G_OBJECT_CLASS (parent_class)->finalize) |
| |
313 (* G_OBJECT_CLASS (parent_class)->finalize) (object); |
| |
314 |
| |
315 g_free (cellview->priv); |
| |
316 } |
| |
317 |
| |
318 static void |
| |
319 gtk_cell_view_size_request (GtkWidget *widget, |
| |
320 GtkRequisition *requisition) |
| |
321 { |
| |
322 GList *i; |
| |
323 gboolean first_cell = TRUE; |
| |
324 GtkCellView *cellview; |
| |
325 |
| |
326 cellview = GTK_CELL_VIEW (widget); |
| |
327 |
| |
328 requisition->width = 0; |
| |
329 requisition->height = 0; |
| |
330 |
| |
331 if (cellview->priv->displayed_row) |
| |
332 gtk_cell_view_set_cell_data (cellview); |
| |
333 |
| |
334 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
335 { |
| |
336 gint width, height; |
| |
337 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
338 |
| |
339 if (!info->cell->visible) |
| |
340 continue; |
| |
341 |
| |
342 if (!first_cell) |
| |
343 requisition->width += cellview->priv->spacing; |
| |
344 |
| |
345 gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL, |
| |
346 &width, &height); |
| |
347 |
| |
348 info->requested_width = width; |
| |
349 requisition->width += width; |
| |
350 requisition->height = MAX (requisition->height, height); |
| |
351 |
| |
352 first_cell = FALSE; |
| |
353 } |
| |
354 } |
| |
355 |
| |
356 static void |
| |
357 gtk_cell_view_size_allocate (GtkWidget *widget, |
| |
358 GtkAllocation *allocation) |
| |
359 { |
| |
360 GList *i; |
| |
361 gint expand_cell_count = 0; |
| |
362 gint full_requested_width = 0; |
| |
363 gint extra_space; |
| |
364 GtkCellView *cellview; |
| |
365 |
| |
366 widget->allocation = *allocation; |
| |
367 |
| |
368 cellview = GTK_CELL_VIEW (widget); |
| |
369 |
| |
370 /* checking how much extra space we have */ |
| |
371 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
372 { |
| |
373 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
374 |
| |
375 if (!info->cell->visible) |
| |
376 continue; |
| |
377 |
| |
378 if (info->expand) |
| |
379 expand_cell_count++; |
| |
380 |
| |
381 full_requested_width += info->requested_width; |
| |
382 } |
| |
383 |
| |
384 extra_space = widget->allocation.width - full_requested_width; |
| |
385 if (extra_space < 0) |
| |
386 extra_space = 0; |
| |
387 else if (extra_space > 0 && expand_cell_count > 0) |
| |
388 extra_space /= expand_cell_count; |
| |
389 |
| |
390 /* iterate list for PACK_START cells */ |
| |
391 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
392 { |
| |
393 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
394 |
| |
395 if (info->pack == GTK_PACK_END) |
| |
396 continue; |
| |
397 |
| |
398 if (!info->cell->visible) |
| |
399 continue; |
| |
400 |
| |
401 info->real_width = info->requested_width + (info->expand ? extra_space : 0); |
| |
402 } |
| |
403 |
| |
404 /* iterate list for PACK_END cells */ |
| |
405 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
406 { |
| |
407 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
408 |
| |
409 if (info->pack == GTK_PACK_START) |
| |
410 continue; |
| |
411 |
| |
412 if (!info->cell->visible) |
| |
413 continue; |
| |
414 |
| |
415 info->real_width = info->requested_width + (info->expand ? extra_space : 0); |
| |
416 } |
| |
417 } |
| |
418 |
| |
419 static gboolean |
| |
420 gtk_cell_view_expose (GtkWidget *widget, |
| |
421 GdkEventExpose *event) |
| |
422 { |
| |
423 GList *i; |
| |
424 GtkCellView *cellview; |
| |
425 GdkRectangle area; |
| |
426 GtkCellRendererState state; |
| |
427 gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL); |
| |
428 |
| |
429 cellview = GTK_CELL_VIEW (widget); |
| |
430 |
| |
431 if (! GTK_WIDGET_DRAWABLE (widget)) |
| |
432 return FALSE; |
| |
433 |
| |
434 /* "blank" background */ |
| |
435 if (cellview->priv->background_set) |
| |
436 { |
| |
437 GdkGC *gc; |
| |
438 |
| |
439 gc = gdk_gc_new (GTK_WIDGET (cellview)->window); |
| |
440 gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background); |
| |
441 |
| |
442 gdk_draw_rectangle (GTK_WIDGET (cellview)->window, |
| |
443 gc, |
| |
444 TRUE, |
| |
445 |
| |
446 /*0, 0,*/ |
| |
447 widget->allocation.x, |
| |
448 widget->allocation.y, |
| |
449 |
| |
450 widget->allocation.width, |
| |
451 widget->allocation.height); |
| |
452 |
| |
453 g_object_unref (G_OBJECT (gc)); |
| |
454 } |
| |
455 |
| |
456 /* set cell data (if available) */ |
| |
457 if (cellview->priv->displayed_row) |
| |
458 gtk_cell_view_set_cell_data (cellview); |
| |
459 else if (cellview->priv->model) |
| |
460 return FALSE; |
| |
461 |
| |
462 /* render cells */ |
| |
463 area = widget->allocation; |
| |
464 |
| |
465 /* we draw on our very own window, initialize x and y to zero */ |
| |
466 area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); |
| |
467 area.y = widget->allocation.y; |
| |
468 |
| |
469 if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) |
| |
470 state = GTK_CELL_RENDERER_PRELIT; |
| |
471 else |
| |
472 state = 0; |
| |
473 |
| |
474 /* PACK_START */ |
| |
475 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
476 { |
| |
477 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
478 |
| |
479 if (info->pack == GTK_PACK_END) |
| |
480 continue; |
| |
481 |
| |
482 if (!info->cell->visible) |
| |
483 continue; |
| |
484 |
| |
485 area.width = info->real_width; |
| |
486 if (rtl) |
| |
487 area.x -= area.width; |
| |
488 |
| |
489 gtk_cell_renderer_render (info->cell, |
| |
490 event->window, |
| |
491 widget, |
| |
492 /* FIXME! */ |
| |
493 &area, &area, &event->area, state); |
| |
494 |
| |
495 if (!rtl) |
| |
496 area.x += info->real_width; |
| |
497 } |
| |
498 |
| |
499 area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width); |
| |
500 |
| |
501 /* PACK_END */ |
| |
502 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
503 { |
| |
504 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
505 |
| |
506 if (info->pack == GTK_PACK_START) |
| |
507 continue; |
| |
508 |
| |
509 if (!info->cell->visible) |
| |
510 continue; |
| |
511 |
| |
512 area.width = info->real_width; |
| |
513 if (!rtl) |
| |
514 area.x -= area.width; |
| |
515 |
| |
516 gtk_cell_renderer_render (info->cell, |
| |
517 widget->window, |
| |
518 widget, |
| |
519 /* FIXME ! */ |
| |
520 &area, &area, &event->area, state); |
| |
521 if (rtl) |
| |
522 area.x += info->real_width; |
| |
523 } |
| |
524 |
| |
525 return FALSE; |
| |
526 } |
| |
527 |
| |
528 static GtkCellViewCellInfo * |
| |
529 gtk_cell_view_get_cell_info (GtkCellView *cellview, |
| |
530 GtkCellRenderer *renderer) |
| |
531 { |
| |
532 GList *i; |
| |
533 |
| |
534 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
535 { |
| |
536 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data; |
| |
537 |
| |
538 if (info->cell == renderer) |
| |
539 return info; |
| |
540 } |
| |
541 |
| |
542 return NULL; |
| |
543 } |
| |
544 |
| |
545 static void |
| |
546 gtk_cell_view_set_cell_data (GtkCellView *cellview) |
| |
547 { |
| |
548 GList *i; |
| |
549 GtkTreeIter iter; |
| |
550 GtkTreePath *path; |
| |
551 |
| |
552 g_return_if_fail (cellview->priv->displayed_row != NULL); |
| |
553 |
| |
554 path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row); |
| |
555 gtk_tree_model_get_iter (cellview->priv->model, &iter, path); |
| |
556 gtk_tree_path_free (path); |
| |
557 |
| |
558 for (i = cellview->priv->cell_list; i; i = i->next) |
| |
559 { |
| |
560 GSList *j; |
| |
561 GtkCellViewCellInfo *info = i->data; |
| |
562 |
| |
563 g_object_freeze_notify (G_OBJECT (info->cell)); |
| |
564 |
| |
565 for (j = info->attributes; j && j->next; j = j->next->next) |
| |
566 { |
| |
567 gchar *property = j->data; |
| |
568 gint column = GPOINTER_TO_INT (j->next->data); |
| |
569 GValue value = {0, }; |
| |
570 |
| |
571 gtk_tree_model_get_value (cellview->priv->model, &iter, |
| |
572 column, &value); |
| |
573 g_object_set_property (G_OBJECT (info->cell), |
| |
574 property, &value); |
| |
575 g_value_unset (&value); |
| |
576 } |
| |
577 |
| |
578 if (info->func) |
| |
579 (* info->func) (GTK_CELL_LAYOUT (cellview), |
| |
580 info->cell, |
| |
581 cellview->priv->model, |
| |
582 &iter, |
| |
583 info->func_data); |
| |
584 |
| |
585 g_object_thaw_notify (G_OBJECT (info->cell)); |
| |
586 } |
| |
587 } |
| |
588 |
| |
589 /* GtkCellLayout implementation */ |
| |
590 static void |
| |
591 gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, |
| |
592 GtkCellRenderer *renderer, |
| |
593 gboolean expand) |
| |
594 { |
| |
595 GtkCellViewCellInfo *info; |
| |
596 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
597 |
| |
598 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
599 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); |
| |
600 g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); |
| |
601 |
| |
602 g_object_ref (G_OBJECT (renderer)); |
| |
603 gtk_object_sink (GTK_OBJECT (renderer)); |
| |
604 |
| |
605 info = g_new0 (GtkCellViewCellInfo, 1); |
| |
606 info->cell = renderer; |
| |
607 info->expand = expand ? TRUE : FALSE; |
| |
608 info->pack = GTK_PACK_START; |
| |
609 |
| |
610 cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); |
| |
611 } |
| |
612 |
| |
613 static void |
| |
614 gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout, |
| |
615 GtkCellRenderer *renderer, |
| |
616 gboolean expand) |
| |
617 { |
| |
618 GtkCellViewCellInfo *info; |
| |
619 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
620 |
| |
621 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
622 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); |
| |
623 g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer)); |
| |
624 |
| |
625 g_object_ref (G_OBJECT (renderer)); |
| |
626 gtk_object_sink (GTK_OBJECT (renderer)); |
| |
627 |
| |
628 info = g_new0 (GtkCellViewCellInfo, 1); |
| |
629 info->cell = renderer; |
| |
630 info->expand = expand ? TRUE : FALSE; |
| |
631 info->pack = GTK_PACK_END; |
| |
632 |
| |
633 cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info); |
| |
634 } |
| |
635 |
| |
636 static void |
| |
637 gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout, |
| |
638 GtkCellRenderer *renderer, |
| |
639 const gchar *attribute, |
| |
640 gint column) |
| |
641 { |
| |
642 GtkCellViewCellInfo *info; |
| |
643 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
644 |
| |
645 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
646 info = gtk_cell_view_get_cell_info (cellview, renderer); |
| |
647 g_return_if_fail (info != NULL); |
| |
648 |
| |
649 info->attributes = g_slist_prepend (info->attributes, |
| |
650 GINT_TO_POINTER (column)); |
| |
651 info->attributes = g_slist_prepend (info->attributes, |
| |
652 g_strdup (attribute)); |
| |
653 } |
| |
654 |
| |
655 static void |
| |
656 gtk_cell_view_cell_layout_clear (GtkCellLayout *layout) |
| |
657 { |
| |
658 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
659 |
| |
660 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
661 |
| |
662 while (cellview->priv->cell_list) |
| |
663 { |
| |
664 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data; |
| |
665 |
| |
666 gtk_cell_view_cell_layout_clear_attributes (layout, info->cell); |
| |
667 g_object_unref (G_OBJECT (info->cell)); |
| |
668 g_free (info); |
| |
669 cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, |
| |
670 cellview->priv->cell_list); |
| |
671 } |
| |
672 } |
| |
673 |
| |
674 static void |
| |
675 gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout, |
| |
676 GtkCellRenderer *cell, |
| |
677 GtkCellLayoutDataFunc func, |
| |
678 gpointer func_data, |
| |
679 GDestroyNotify destroy) |
| |
680 { |
| |
681 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
682 GtkCellViewCellInfo *info; |
| |
683 |
| |
684 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
685 |
| |
686 info = gtk_cell_view_get_cell_info (cellview, cell); |
| |
687 g_return_if_fail (info != NULL); |
| |
688 |
| |
689 if (info->destroy) |
| |
690 { |
| |
691 GDestroyNotify d = info->destroy; |
| |
692 |
| |
693 info->destroy = NULL; |
| |
694 d (info->func_data); |
| |
695 } |
| |
696 |
| |
697 info->func = func; |
| |
698 info->func_data = func_data; |
| |
699 info->destroy = destroy; |
| |
700 } |
| |
701 |
| |
702 static void |
| |
703 gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout, |
| |
704 GtkCellRenderer *renderer) |
| |
705 { |
| |
706 GtkCellViewCellInfo *info; |
| |
707 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
708 GSList *list; |
| |
709 |
| |
710 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
711 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); |
| |
712 |
| |
713 info = gtk_cell_view_get_cell_info (cellview, renderer); |
| |
714 if (info != NULL) |
| |
715 { |
| |
716 list = info->attributes; |
| |
717 while (list && list->next) |
| |
718 { |
| |
719 g_free (list->data); |
| |
720 list = list->next->next; |
| |
721 } |
| |
722 |
| |
723 g_slist_free (info->attributes); |
| |
724 info->attributes = NULL; |
| |
725 } |
| |
726 } |
| |
727 |
| |
728 static void |
| |
729 gtk_cell_view_cell_layout_reorder (GtkCellLayout *layout, |
| |
730 GtkCellRenderer *cell, |
| |
731 gint position) |
| |
732 { |
| |
733 GList *link; |
| |
734 GtkCellViewCellInfo *info; |
| |
735 GtkCellView *cellview = GTK_CELL_VIEW (layout); |
| |
736 |
| |
737 g_return_if_fail (GTK_IS_CELL_VIEW (cellview)); |
| |
738 g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); |
| |
739 |
| |
740 info = gtk_cell_view_get_cell_info (cellview, cell); |
| |
741 |
| |
742 g_return_if_fail (info != NULL); |
| |
743 g_return_if_fail (position >= 0); |
| |
744 |
| |
745 link = g_list_find (cellview->priv->cell_list, info); |
| |
746 |
| |
747 g_return_if_fail (link != NULL); |
| |
748 |
| |
749 cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list, |
| |
750 link); |
| |
751 cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list, |
| |
752 info, position); |
| |
753 |
| |
754 gtk_widget_queue_draw (GTK_WIDGET (cellview)); |
| |
755 } |
| |
756 |
| |
757 /* public API */ |
| |
758 GtkWidget * |
| |
759 gtk_cell_view_new (void) |
| |
760 { |
| |
761 GtkCellView *cellview; |
| |
762 |
| |
763 cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL)); |
| |
764 |
| |
765 return GTK_WIDGET (cellview); |
| |
766 } |
| |
767 |
| |
768 GtkWidget * |
| |
769 gtk_cell_view_new_with_text (const gchar *text) |
| |
770 { |
| |
771 GtkCellView *cellview; |
| |
772 GtkCellRenderer *renderer; |
| |
773 GValue value = {0, }; |
| |
774 |
| |
775 cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); |
| |
776 |
| |
777 renderer = gtk_cell_renderer_text_new (); |
| |
778 gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), |
| |
779 renderer, TRUE); |
| |
780 |
| |
781 g_value_init (&value, G_TYPE_STRING); |
| |
782 g_value_set_string (&value, text); |
| |
783 gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL); |
| |
784 g_value_unset (&value); |
| |
785 |
| |
786 return GTK_WIDGET (cellview); |
| |
787 } |
| |
788 |
| |
789 GtkWidget * |
| |
790 gtk_cell_view_new_with_markup (const gchar *markup) |
| |
791 { |
| |
792 GtkCellView *cellview; |
| |
793 GtkCellRenderer *renderer; |
| |
794 GValue value = {0, }; |
| |
795 |
| |
796 cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); |
| |
797 |
| |
798 renderer = gtk_cell_renderer_text_new (); |
| |
799 gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), |
| |
800 renderer, TRUE); |
| |
801 |
| |
802 g_value_init (&value, G_TYPE_STRING); |
| |
803 g_value_set_string (&value, markup); |
| |
804 gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL); |
| |
805 g_value_unset (&value); |
| |
806 |
| |
807 return GTK_WIDGET (cellview); |
| |
808 } |
| |
809 |
| |
810 GtkWidget * |
| |
811 gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf) |
| |
812 { |
| |
813 GtkCellView *cellview; |
| |
814 GtkCellRenderer *renderer; |
| |
815 GValue value = {0, }; |
| |
816 |
| |
817 cellview = GTK_CELL_VIEW (gtk_cell_view_new ()); |
| |
818 |
| |
819 renderer = gtk_cell_renderer_pixbuf_new (); |
| |
820 gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview), |
| |
821 renderer, TRUE); |
| |
822 |
| |
823 g_value_init (&value, GDK_TYPE_PIXBUF); |
| |
824 g_value_set_object (&value, pixbuf); |
| |
825 gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL); |
| |
826 g_value_unset (&value); |
| |
827 |
| |
828 return GTK_WIDGET (cellview); |
| |
829 } |
| |
830 |
| |
831 void |
| |
832 gtk_cell_view_set_value (GtkCellView *cell_view, |
| |
833 GtkCellRenderer *renderer, |
| |
834 gchar *property, |
| |
835 GValue *value) |
| |
836 { |
| |
837 g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); |
| |
838 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); |
| |
839 |
| |
840 g_object_set_property (G_OBJECT (renderer), property, value); |
| |
841 |
| |
842 /* force resize and redraw */ |
| |
843 gtk_widget_queue_resize (GTK_WIDGET (cell_view)); |
| |
844 gtk_widget_queue_draw (GTK_WIDGET (cell_view)); |
| |
845 } |
| |
846 |
| |
847 static void |
| |
848 gtk_cell_view_set_valuesv (GtkCellView *cell_view, |
| |
849 GtkCellRenderer *renderer, |
| |
850 va_list args) |
| |
851 { |
| |
852 gchar *attribute; |
| |
853 GValue *value; |
| |
854 |
| |
855 attribute = va_arg (args, gchar *); |
| |
856 |
| |
857 while (attribute) |
| |
858 { |
| |
859 value = va_arg (args, GValue *); |
| |
860 gtk_cell_view_set_value (cell_view, renderer, attribute, value); |
| |
861 attribute = va_arg (args, gchar *); |
| |
862 } |
| |
863 } |
| |
864 |
| |
865 void |
| |
866 gtk_cell_view_set_values (GtkCellView *cell_view, |
| |
867 GtkCellRenderer *renderer, |
| |
868 ...) |
| |
869 { |
| |
870 va_list args; |
| |
871 |
| |
872 g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); |
| |
873 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); |
| |
874 g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer)); |
| |
875 |
| |
876 va_start (args, renderer); |
| |
877 gtk_cell_view_set_valuesv (cell_view, renderer, args); |
| |
878 va_end (args); |
| |
879 } |
| |
880 |
| |
881 void |
| |
882 gtk_cell_view_set_model (GtkCellView *cell_view, |
| |
883 GtkTreeModel *model) |
| |
884 { |
| |
885 g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); |
| |
886 g_return_if_fail (GTK_IS_TREE_MODEL (model)); |
| |
887 |
| |
888 if (cell_view->priv->model) |
| |
889 { |
| |
890 if (cell_view->priv->displayed_row) |
| |
891 gtk_tree_row_reference_free (cell_view->priv->displayed_row); |
| |
892 cell_view->priv->displayed_row = NULL; |
| |
893 |
| |
894 g_object_unref (G_OBJECT (cell_view->priv->model)); |
| |
895 cell_view->priv->model = NULL; |
| |
896 } |
| |
897 |
| |
898 cell_view->priv->model = model; |
| |
899 |
| |
900 if (cell_view->priv->model) |
| |
901 g_object_ref (G_OBJECT (cell_view->priv->model)); |
| |
902 } |
| |
903 |
| |
904 /** |
| |
905 * gtk_cell_view_set_displayed_row: |
| |
906 * @cell_view: a #GtkCellView |
| |
907 * @path: a #GtkTreePath or %NULL to unset. |
| |
908 * |
| |
909 * Sets the row of the model that is currently displayed |
| |
910 * by the #GtkCellView. If the path is unset, then the |
| |
911 * contents of the cellview "stick" at their last value; |
| |
912 * this is not normally a desired result, but may be |
| |
913 * a needed intermediate state if say, the model for |
| |
914 * the #GtkCellView becomes temporarily empty. |
| |
915 **/ |
| |
916 void |
| |
917 gtk_cell_view_set_displayed_row (GtkCellView *cell_view, |
| |
918 GtkTreePath *path) |
| |
919 { |
| |
920 g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); |
| |
921 g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model)); |
| |
922 |
| |
923 if (cell_view->priv->displayed_row) |
| |
924 gtk_tree_row_reference_free (cell_view->priv->displayed_row); |
| |
925 |
| |
926 if (path) |
| |
927 { |
| |
928 cell_view->priv->displayed_row = |
| |
929 gtk_tree_row_reference_new (cell_view->priv->model, path); |
| |
930 } |
| |
931 else |
| |
932 cell_view->priv->displayed_row = NULL; |
| |
933 |
| |
934 /* force resize and redraw */ |
| |
935 gtk_widget_queue_resize (GTK_WIDGET (cell_view)); |
| |
936 gtk_widget_queue_draw (GTK_WIDGET (cell_view)); |
| |
937 } |
| |
938 |
| |
939 GtkTreePath * |
| |
940 gtk_cell_view_get_displayed_row (GtkCellView *cell_view) |
| |
941 { |
| |
942 g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL); |
| |
943 |
| |
944 if (!cell_view->priv->displayed_row) |
| |
945 return NULL; |
| |
946 |
| |
947 return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row); |
| |
948 } |
| |
949 |
| |
950 gboolean |
| |
951 gtk_cell_view_get_size_of_row (GtkCellView *cell_view, |
| |
952 GtkTreePath *path, |
| |
953 GtkRequisition *requisition) |
| |
954 { |
| |
955 GtkTreeRowReference *tmp; |
| |
956 GtkRequisition req; |
| |
957 |
| |
958 g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE); |
| |
959 g_return_val_if_fail (path != NULL, FALSE); |
| |
960 g_return_val_if_fail (requisition != NULL, FALSE); |
| |
961 |
| |
962 tmp = cell_view->priv->displayed_row; |
| |
963 cell_view->priv->displayed_row = |
| |
964 gtk_tree_row_reference_new (cell_view->priv->model, path); |
| |
965 |
| |
966 gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition); |
| |
967 |
| |
968 gtk_tree_row_reference_free (cell_view->priv->displayed_row); |
| |
969 cell_view->priv->displayed_row = tmp; |
| |
970 |
| |
971 /* restore actual size info */ |
| |
972 gtk_cell_view_size_request (GTK_WIDGET (cell_view), &req); |
| |
973 |
| |
974 return TRUE; |
| |
975 } |
| |
976 |
| |
977 void |
| |
978 gtk_cell_view_set_background_color (GtkCellView *view, |
| |
979 const GdkColor *color) |
| |
980 { |
| |
981 g_return_if_fail (GTK_IS_CELL_VIEW (view)); |
| |
982 |
| |
983 if (color) |
| |
984 { |
| |
985 if (!view->priv->background_set) |
| |
986 { |
| |
987 view->priv->background_set = TRUE; |
| |
988 g_object_notify (G_OBJECT (view), "background_set"); |
| |
989 } |
| |
990 |
| |
991 view->priv->background = *color; |
| |
992 } |
| |
993 else |
| |
994 { |
| |
995 if (view->priv->background_set) |
| |
996 { |
| |
997 view->priv->background_set = FALSE; |
| |
998 g_object_notify (G_OBJECT (view), "background_set"); |
| |
999 } |
| |
1000 } |
| |
1001 } |
| |
1002 #endif /* Gtk 2.6 */ |