2 * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include <gtk/gtklabel.h>
25 #include <gtk/gtkdrawingarea.h>
27 static GtkContainerClass *parent_class = 0;
30 labcon_size_request(GtkWidget *w, GtkRequisition *req)
32 LabCon *l = LABCON(w);
34 GtkRequisition l_rec, c_rec;
36 l_rec.width = c_rec.width = l_rec.height = c_rec.height = 0;
39 if (GTK_WIDGET_VISIBLE(l->label))
40 gtk_widget_size_request(l->label, &l_rec);
42 if (GTK_WIDGET_VISIBLE(l->image))
43 gtk_widget_size_request(l->image, &l_rec);
45 if (GTK_WIDGET_VISIBLE(l->child))
46 gtk_widget_size_request(l->child, &c_rec);
49 width = LABCON(l->leader)->label_width;
50 width = MAX(width, l_rec.width);
52 req->height = MAX(l_rec.height, c_rec.height) +
53 (GTK_CONTAINER(l)->border_width * 2);
54 req->width = width + c_rec.width + l->spacing +
55 (GTK_CONTAINER(l)->border_width * 2);
59 labcon_size_allocate(GtkWidget *w, GtkAllocation *all)
63 LabCon *leader, *l = LABCON(w);
64 GtkRequisition l_rec, c_rec, ll_rec;
69 l_rec.width = c_rec.width = l_rec.height = c_rec.height = 0;
71 label = (l->label != 0) ? l->label : l->image;
73 if (GTK_WIDGET_VISIBLE(label))
74 gtk_widget_get_child_requisition(label, &l_rec);
75 if (GTK_WIDGET_VISIBLE(l->child))
76 gtk_widget_get_child_requisition(l->child, &c_rec);
79 * Make sure the height is non-zero and leaves the border.
81 w_all.x = all->x + GTK_CONTAINER(l)->border_width;
82 w_all.y = all->y + GTK_CONTAINER(l)->border_width;
83 w_all.height = MAX(1, (gint) all->height -
84 (gint) (GTK_CONTAINER(l)->border_width * 2));
87 leader = LABCON(l->leader);
90 gtk_widget_get_child_requisition(leader->label, &ll_rec);
92 gtk_widget_get_child_requisition(leader->image, &ll_rec);
94 if (ll_rec.width < l_rec.width) {
96 gtk_widget_set_size_request(leader->label,
97 l_rec.width, ll_rec.height);
99 gtk_widget_set_size_request(leader->image,
100 l_rec.width, ll_rec.height);
103 leader->label_width = MAX(l_rec.width, leader->label_width);
104 l_rec.width = leader->label_width;
106 for (i = 0; i < leader->group_used - 1; i++) {
107 if (LABCON(leader->group[i])->label)
108 gtk_widget_get_child_requisition(LABCON(leader->group[i])->label,
111 gtk_widget_get_child_requisition(LABCON(leader->group[i])->image,
113 if (ll_rec.width < l_rec.width) {
114 if (LABCON(leader->group[i])->label)
115 gtk_widget_set_size_request(LABCON(leader->group[i])->label,
116 l_rec.width, ll_rec.height);
118 gtk_widget_set_size_request(LABCON(leader->group[i])->image,
119 l_rec.width, ll_rec.height);
123 l->label_width = l_rec.width;
125 if (l->pos == GTK_POS_LEFT) {
127 * Position the label on the left of the child.
131 * Calculate the allocation for the label widget.
133 w_all.width = l_rec.width;
134 gtk_widget_size_allocate(label, &w_all);
137 * Calculate the allocation for the child widget. The child widget
138 * is expanded to fill the remaining space.
140 w_all.x += w_all.width + l->spacing;
141 w_all.width = all->width - (l_rec.width + l->spacing);
142 gtk_widget_size_allocate(l->child, &w_all);
145 * Position the label on the right of the child.
149 * Calculate the allocation for the child widget. The child widget
150 * is expanded to fill the remaining space.
152 w_all.width = all->width - (l_rec.width + l->spacing);
153 gtk_widget_size_allocate(l->child, &w_all);
156 * Calculate the allocation for the label widget.
158 w_all.x += w_all.width + l->spacing;
159 w_all.width = l_rec.width;
160 gtk_widget_size_allocate(label, &w_all);
165 labcon_forall(GtkContainer *c, gboolean include_internals,
166 GtkCallback callback, gpointer callback_data)
168 LabCon *l = LABCON(c);
171 (*callback)(l->label, callback_data);
173 (*callback)(l->image, callback_data);
174 (*callback)(l->child, callback_data);
178 labcon_remove(GtkContainer *c, GtkWidget *w)
181 LabCon *l = LABCON(c);
184 * Make sure that the group list has been deallocated so we don't
188 if (l->group_size > 0) {
189 for (i = 0; i < l->group_used; i++)
190 LABCON(l->group[i])->leader = 0;
191 l->group_size = l->group_used = 0;
199 labcon_class_init(gpointer g_class, gpointer class_data)
201 GtkWidgetClass *wc = GTK_WIDGET_CLASS(g_class);
202 LabConClass *lc = LABCON_CLASS(g_class);
203 GtkContainerClass *cc = GTK_CONTAINER_CLASS(g_class);
205 wc->size_request = labcon_size_request;
206 wc->size_allocate = labcon_size_allocate;
208 cc->remove = labcon_remove;
209 cc->forall = labcon_forall;
211 parent_class = g_type_class_peek_parent(lc);
215 labcon_init(GTypeInstance *instance, gpointer g_class)
217 LabCon *l = LABCON(instance);
219 GTK_WIDGET_SET_FLAGS(l, GTK_NO_WINDOW);
220 gtk_widget_set_redraw_on_allocate(GTK_WIDGET(l), FALSE);
223 l->image = l->label = l->child = 0;
225 l->align = LABCON_ALIGN_LEFT;
226 l->pos = GTK_POS_LEFT;
229 l->group_size = l->group_used = 0;
233 draw_pixbuf(GtkWidget *w, GdkEventExpose *event, gpointer data)
235 GdkPixbuf *p = GDK_PIXBUF(data);
238 wd = gdk_pixbuf_get_width(p);
239 ht = gdk_pixbuf_get_height(p);
241 x = (w->allocation.width >> 1) - (wd >> 1);
242 y = (w->allocation.height >> 1) - (ht >> 1);
243 gdk_draw_pixbuf(w->window, w->style->fg_gc[GTK_WIDGET_STATE(w)],
244 p, 0, 0, x, y, wd, ht, GDK_RGB_DITHER_NONE, 0, 0);
249 /**********************************************************************
253 **********************************************************************/
256 labcon_get_type(void)
258 static GType labcon_type = 0;
261 static const GTypeInfo labcon_info = {
262 sizeof (LabConClass), /* class_size */
264 0, /* base_finalize */
265 labcon_class_init, /* class_init */
266 0, /* class_finalize */
268 sizeof(LabCon), /* instance_size */
270 labcon_init, /* instance_init */
274 labcon_type = g_type_register_static(GTK_TYPE_CONTAINER, "LabCon",
282 labcon_new_label(const gchar *label, LabConAlignment align,
283 GtkPositionType pos, guint spacing,
284 GtkWidget *child, GtkWidget *group)
286 LabCon *l, *leader = LABCON(group);
288 g_return_val_if_fail(GTK_IS_WIDGET(child), NULL);
290 g_return_val_if_fail(GTK_IS_WIDGET(group), NULL);
291 g_return_val_if_fail(IS_LABCON(group), NULL);
294 l = g_object_new(labcon_get_type(), NULL);
296 l->spacing = spacing;
299 l->label = gtk_label_new(label);
301 case LABCON_ALIGN_LEFT:
302 gtk_misc_set_alignment(GTK_MISC(l->label), 0.0, 0.5);
304 case LABCON_ALIGN_RIGHT:
305 gtk_misc_set_alignment(GTK_MISC(l->label), 1.0, 0.5);
307 case LABCON_ALIGN_CENTER:
308 gtk_misc_set_alignment(GTK_MISC(l->label), 0.5, 0.5);
313 * Go back until we get the group leader.
315 if (group && LABCON(group)->leader)
316 l->leader = LABCON(group)->leader;
322 * Add this widget to the group which should have all the same
325 leader = LABCON(l->leader);
326 if (leader->group_size == leader->group_used) {
327 if (leader->group_size == 0)
328 leader->group = (GtkWidget **) g_malloc(sizeof(GtkWidget *) * 4);
330 leader->group = (GtkWidget **)
331 g_realloc(leader->group,
332 sizeof(GtkWidget *) * (leader->group_size + 4));
333 leader->group_size += 4;
335 leader->group[leader->group_used++] = GTK_WIDGET(l);
338 gtk_widget_set_parent(l->label, GTK_WIDGET(l));
339 gtk_widget_show(l->label);
341 gtk_widget_set_parent(l->child, GTK_WIDGET(l));
342 gtk_widget_show(l->child);
345 return GTK_WIDGET(l);
349 labcon_new_label_defaults(const gchar *label, GtkWidget *child,
352 return labcon_new_label(label, LABCON_ALIGN_RIGHT, GTK_POS_LEFT, 5,
357 labcon_new_pixbuf(const GdkPixbuf *pixbuf, LabConAlignment align,
358 GtkPositionType pos, guint spacing,
359 GtkWidget *child, GtkWidget *group)
361 LabCon *l, *leader = LABCON(group);
363 g_return_val_if_fail(GTK_IS_WIDGET(child), NULL);
365 g_return_val_if_fail(GTK_IS_WIDGET(group), NULL);
366 g_return_val_if_fail(IS_LABCON(group), NULL);
369 l = g_object_new(labcon_get_type(), NULL);
372 l->spacing = spacing;
377 * Make the drawing area just big enough to hold the pixbuf at
380 l->image = gtk_drawing_area_new();
381 gtk_widget_set_size_request(l->image,
382 gdk_pixbuf_get_width(l->pixbuf),
383 gdk_pixbuf_get_height(l->pixbuf));
384 g_signal_connect(G_OBJECT(l->image), "expose_event",
385 G_CALLBACK(draw_pixbuf), (gpointer) l->pixbuf);
388 * Go back until we get the group leader.
390 if (group && LABCON(group)->leader)
391 l->leader = LABCON(group)->leader;
397 * Add this widget to the group which should have all the same
398 * width labels or pixbufs.
400 leader = LABCON(l->leader);
401 if (leader->group_size == leader->group_used) {
402 if (leader->group_size == 0)
403 leader->group = (GtkWidget **) g_malloc(sizeof(GtkWidget *) * 4);
405 leader->group = (GtkWidget **)
406 g_realloc(leader->group,
407 sizeof(GtkWidget *) * (leader->group_size + 4));
408 leader->group_size += 4;
410 leader->group[leader->group_used++] = GTK_WIDGET(l);
413 gtk_widget_set_parent(l->image, GTK_WIDGET(l));
414 gtk_widget_show(l->image);
416 gtk_widget_set_parent(l->child, GTK_WIDGET(l));
417 gtk_widget_show(l->child);
420 return GTK_WIDGET(l);
424 labcon_new_pixbuf_defaults(const GdkPixbuf *pixbuf, GtkWidget *child,
427 return labcon_new_pixbuf(pixbuf, LABCON_ALIGN_RIGHT, GTK_POS_LEFT, 5,
432 labcon_get_pixbuf(LabCon *l)
434 g_return_val_if_fail(IS_LABCON(l), 0);
436 return l ? l->pixbuf : 0;
440 labcon_get_image(LabCon *l)
442 g_return_val_if_fail(IS_LABCON(l), 0);
444 return l ? l->image : 0;
448 labcon_get_label(LabCon *l)
450 g_return_val_if_fail(IS_LABCON(l), 0);
452 return l ? l->label : 0;
456 labcon_get_child(LabCon *l)
458 g_return_val_if_fail(IS_LABCON(l), 0);
460 return l ? l->child : 0;