10 static void aspect_bin_size_request(GtkWidget *, GtkRequisition *);
11 static void aspect_bin_size_allocate(GtkWidget *, GtkAllocation *);
12 static void aspect_bin_add(GtkContainer *, GtkWidget *);
13 static void aspect_bin_remove(GtkContainer *, GtkWidget *);
14 static void aspect_bin_forall(GtkContainer *, gboolean, GtkCallback, gpointer);
15 static GType aspect_bin_child_type(GtkContainer *);
17 static void aspect_bin_get_property(GObject *, guint, GValue *, GParamSpec *);
18 static void aspect_bin_set_property(GObject *, guint, const GValue *,
21 G_DEFINE_TYPE(AspectBin, aspect_bin, GTK_TYPE_CONTAINER)
23 static void aspect_bin_init(AspectBin *abin)
25 GTK_WIDGET_SET_FLAGS(abin, GTK_NO_WINDOW);
31 abin->constrain = FALSE;
35 static void aspect_bin_class_init(AspectBinClass *class)
37 GObjectClass *object_class = G_OBJECT_CLASS(class);
38 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
39 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(class);
41 widget_class->size_request = aspect_bin_size_request;
42 widget_class->size_allocate = aspect_bin_size_allocate;
44 container_class->add = aspect_bin_add;
45 container_class->remove = aspect_bin_remove;
46 container_class->forall = aspect_bin_forall;
47 container_class->child_type = aspect_bin_child_type;
49 object_class->set_property = aspect_bin_set_property;
50 object_class->get_property = aspect_bin_get_property;
52 g_object_class_install_property(object_class,
54 g_param_spec_boolean("fill",
56 "Allocate all remaining space to the side.",
59 g_object_class_install_property(object_class,
61 g_param_spec_boolean("constrain",
63 "Only expand the side to be as large as the body.",
68 GtkWidget *aspect_bin_new(void)
70 return GTK_WIDGET(g_object_new(ASPECT_BIN_TYPE, NULL));
73 static void aspect_bin_set_property(GObject *object,
78 AspectBin *abin = ASPECT_BIN(object);
82 abin->constrain = g_value_get_boolean(value);
83 gtk_widget_queue_resize(GTK_WIDGET(abin));
86 abin->fill = g_value_get_boolean(value);
87 gtk_widget_queue_resize(GTK_WIDGET(abin));
90 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
94 static void aspect_bin_get_property(GObject *object,
99 AspectBin *abin = ASPECT_BIN(object);
103 g_value_set_boolean(value, abin->constrain);
106 g_value_set_boolean(value, abin->fill);
109 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
113 static void aspect_bin_add(GtkContainer *container, GtkWidget *widget)
116 g_return_if_fail(IS_ASPECT_BIN(container));
117 abin = ASPECT_BIN(container);
120 aspect_bin_set_body(abin, widget, 1);
121 else if (!abin->side)
122 aspect_bin_set_side(abin, widget);
124 g_warning("AspectBin cannot have more than 2 children.\n");
127 static void aspect_bin_remove(GtkContainer *container, GtkWidget *child)
129 AspectBin *abin = ASPECT_BIN(container);
131 if (abin->body == child) {
132 aspect_bin_set_body(abin, NULL, 1);
133 } else if (abin->side == child) {
134 aspect_bin_set_side(abin, NULL);
138 static void aspect_bin_forall(GtkContainer *container,
139 gboolean include_internals,
140 GtkCallback callback,
141 gpointer callback_data)
143 AspectBin *abin = ASPECT_BIN(container);
144 g_return_if_fail(callback != NULL);
147 callback(abin->body, callback_data);
149 callback(abin->side, callback_data);
152 static GType aspect_bin_child_type(GtkContainer *container)
154 if (!ASPECT_BIN(container)->body || !ASPECT_BIN(container)->side)
155 return GTK_TYPE_WIDGET;
160 aspect_bin_size_request(GtkWidget *widget, GtkRequisition *requisition)
162 AspectBin *abin = ASPECT_BIN(widget);
163 GtkRequisition creq = {0}, areq = {0};
165 if (abin->side && GTK_WIDGET_VISIBLE(abin->side)) {
166 gtk_widget_size_request(abin->side, &creq);
169 if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) {
171 gtk_widget_size_request(abin->body, &areq);
172 wtmp = areq.height * abin->ratio + 0.5;
173 htmp = areq.width / abin->ratio + 0.5;
175 if (wtmp > areq.width) {
182 requisition->width = areq.width + creq.width;
183 requisition->height = MAX(areq.height, creq.height);
187 aspect_bin_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
189 AspectBin *abin = ASPECT_BIN(widget);
190 GtkRequisition creq = {0};
191 GtkAllocation csize = {0}, asize = {0};
193 /* First find the best fit for the body. */
194 if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) {
195 asize.height = allocation->height;
196 asize.width = asize.height * abin->ratio + 0.5;
198 if (asize.width > allocation->width) {
199 asize.width = allocation->width;
200 asize.height = asize.width / abin->ratio + 0.5;
204 /* Now try to fit the side. */
205 if (abin->side && GTK_WIDGET_VISIBLE(abin->side)) {
206 gtk_widget_get_child_requisition(abin->side, &creq);
208 if (allocation->width - asize.width < creq.width) {
209 /* It didn't fit, squish the constrained guy. */
210 asize.width = allocation->width - creq.width;
211 asize.height = asize.width / abin->ratio + 0.5;
214 csize.width = allocation->width - asize.width;
215 csize.x = asize.width;
217 if (abin->fill && abin->constrain) {
218 csize.height = asize.height;
219 } else if (abin->fill) {
220 csize.height = allocation->height;
222 csize.height = creq.height;
226 csize.y = (allocation->height - csize.height) * abin->align + 0.5;
227 asize.y = (allocation->height - asize.height) * abin->align + 0.5;
230 gtk_widget_size_allocate(abin->body, &asize);
232 gtk_widget_size_allocate(abin->side, &csize);
236 set_widget(GtkWidget **dest, GtkWidget *parent, GtkWidget *widget)
238 gboolean need_resize = FALSE;
244 need_resize |= GTK_WIDGET_VISIBLE(*dest);
245 gtk_widget_unparent(*dest);
250 gtk_widget_set_parent(widget, parent);
251 need_resize |= GTK_WIDGET_VISIBLE(widget);
254 return GTK_WIDGET_VISIBLE(parent) && need_resize;
257 void aspect_bin_set_body(AspectBin *abin, GtkWidget *widget, gfloat ratio)
259 g_return_if_fail(IS_ASPECT_BIN(abin));
260 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
261 g_return_if_fail(widget == NULL || widget->parent == NULL);
263 if (set_widget(&abin->body, GTK_WIDGET(abin), widget))
264 gtk_widget_queue_resize(GTK_WIDGET(abin));
267 void aspect_bin_set_side(AspectBin *abin, GtkWidget *widget)
269 g_return_if_fail(IS_ASPECT_BIN(abin));
270 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
271 g_return_if_fail(widget == NULL || widget->parent == NULL);
273 if (set_widget(&abin->side, GTK_WIDGET(abin), widget))
274 gtk_widget_queue_resize(GTK_WIDGET(abin));
277 GtkWidget *aspect_bin_get_body(AspectBin *abin)
279 g_return_val_if_fail(IS_ASPECT_BIN(abin), NULL);
283 GtkWidget *aspect_bin_get_side(AspectBin *abin)
285 g_return_val_if_fail(IS_ASPECT_BIN(abin), NULL);