4 static void aspect_bin_size_request(GtkWidget *, GtkRequisition *);
5 static void aspect_bin_size_allocate(GtkWidget *, GtkAllocation *);
6 static void aspect_bin_add(GtkContainer *, GtkWidget *);
7 static void aspect_bin_remove(GtkContainer *, GtkWidget *);
8 static void aspect_bin_forall(GtkContainer *, gboolean, GtkCallback, gpointer);
9 static GType aspect_bin_child_type(GtkContainer *);
11 G_DEFINE_TYPE(AspectBin, aspect_bin, GTK_TYPE_CONTAINER)
13 static void aspect_bin_init(AspectBin *abin)
15 GTK_WIDGET_SET_FLAGS(abin, GTK_NO_WINDOW);
21 abin->constrain = FALSE;
24 static void aspect_bin_class_init(AspectBinClass *class)
26 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
27 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(class);
29 widget_class->size_request = aspect_bin_size_request;
30 widget_class->size_allocate = aspect_bin_size_allocate;
32 container_class->add = aspect_bin_add;
33 container_class->remove = aspect_bin_remove;
34 container_class->forall = aspect_bin_forall;
35 container_class->child_type = aspect_bin_child_type;
38 GtkWidget *aspect_bin_new(void)
40 return GTK_WIDGET(g_object_new(ASPECT_BIN_TYPE, NULL));
43 static void aspect_bin_add(GtkContainer *container, GtkWidget *widget)
46 g_return_if_fail(IS_ASPECT_BIN(container));
47 abin = ASPECT_BIN(container);
50 aspect_bin_set_body(abin, widget, 1);
52 aspect_bin_set_side(abin, widget);
54 g_warning("AspectBin cannot have more than 2 children.\n");
57 static void aspect_bin_remove(GtkContainer *container, GtkWidget *child)
59 AspectBin *abin = ASPECT_BIN(container);
61 if (abin->body == child) {
62 aspect_bin_set_body(abin, NULL, 1);
63 } else if (abin->side == child) {
64 aspect_bin_set_side(abin, NULL);
68 static void aspect_bin_forall(GtkContainer *container,
69 gboolean include_internals,
71 gpointer callback_data)
73 AspectBin *abin = ASPECT_BIN(container);
74 g_return_if_fail(callback != NULL);
77 callback(abin->body, callback_data);
79 callback(abin->side, callback_data);
82 static GType aspect_bin_child_type(GtkContainer *container)
84 if (!ASPECT_BIN(container)->body || !ASPECT_BIN(container)->side)
85 return GTK_TYPE_WIDGET;
90 aspect_bin_size_request(GtkWidget *widget, GtkRequisition *requisition)
92 AspectBin *abin = ASPECT_BIN(widget);
93 GtkRequisition creq = {0}, areq = {0};
95 if (abin->side && GTK_WIDGET_VISIBLE(abin->side)) {
96 gtk_widget_size_request(abin->side, &creq);
99 if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) {
101 gtk_widget_size_request(abin->body, &areq);
102 wtmp = areq.height * abin->ratio + 0.5;
103 htmp = areq.width / abin->ratio + 0.5;
105 if (wtmp > areq.width) {
112 requisition->width = areq.width + creq.width;
113 requisition->height = MAX(areq.height, creq.height);
117 aspect_bin_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
119 AspectBin *abin = ASPECT_BIN(widget);
120 GtkRequisition creq = {0};
121 GtkAllocation csize = {0}, asize = {0};
123 /* First find the best fit for the body. */
124 if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) {
125 asize.height = allocation->height;
126 asize.width = asize.height * abin->ratio + 0.5;
128 if (asize.width > allocation->width) {
129 asize.width = allocation->width;
130 asize.height = asize.width / abin->ratio + 0.5;
134 /* Now try to fit the side. */
135 if (abin->side && GTK_WIDGET_VISIBLE(abin->side)) {
136 gtk_widget_get_child_requisition(abin->side, &creq);
138 if (allocation->width - asize.width < creq.width) {
139 /* It didn't fit, squish the constrained guy. */
140 asize.width = allocation->width - creq.width;
141 asize.height = asize.width / abin->ratio + 0.5;
144 csize.width = allocation->width - asize.width;
145 csize.height = MIN(allocation->height, creq.height);
146 if (abin->constrain) {
147 csize.height = MAX(csize.height, asize.height);
149 csize.x = asize.width;
152 csize.y = (allocation->height - csize.height) * abin->align + 0.5;
153 asize.y = (allocation->height - asize.height) * abin->align + 0.5;
156 gtk_widget_size_allocate(abin->body, &asize);
158 gtk_widget_size_allocate(abin->side, &csize);
162 set_widget(GtkWidget **dest, GtkWidget *parent, GtkWidget *widget)
164 gboolean need_resize = FALSE;
170 need_resize |= GTK_WIDGET_VISIBLE(*dest);
171 gtk_widget_unparent(*dest);
176 gtk_widget_set_parent(widget, parent);
177 need_resize |= GTK_WIDGET_VISIBLE(widget);
180 return GTK_WIDGET_VISIBLE(parent) && need_resize;
183 void aspect_bin_set_body(AspectBin *abin, GtkWidget *widget, gfloat ratio)
185 g_return_if_fail(IS_ASPECT_BIN(abin));
186 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
187 g_return_if_fail(widget == NULL || widget->parent == NULL);
189 if (set_widget(&abin->body, GTK_WIDGET(abin), widget))
190 gtk_widget_queue_resize(GTK_WIDGET(abin));
193 void aspect_bin_set_side(AspectBin *abin, GtkWidget *widget)
195 g_return_if_fail(IS_ASPECT_BIN(abin));
196 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
197 g_return_if_fail(widget == NULL || widget->parent == NULL);
199 if (set_widget(&abin->side, GTK_WIDGET(abin), widget))
200 gtk_widget_queue_resize(GTK_WIDGET(abin));