]> git.draconx.ca Git - aspectbin.git/blob - aspectbin.c
Rename the "child" member to "body" for less confusion.
[aspectbin.git] / aspectbin.c
1 #include <stdio.h>
2 #include "aspectbin.h"
3
4 static void aspect_bin_size_request(GtkWidget *, GtkRequisition *);
5 static void aspect_bin_size_allocate(GtkWidget *, GtkAllocation *);
6 static void aspect_bin_remove(GtkContainer *, GtkWidget *);
7 static void aspect_bin_forall(GtkContainer *, gboolean, GtkCallback, gpointer);
8
9 G_DEFINE_TYPE(AspectBin, aspect_bin, GTK_TYPE_BIN)
10
11 static void aspect_bin_init(AspectBin *abin)
12 {
13         abin->body      = NULL;
14         abin->ratio     = 1;
15         abin->constrain = FALSE;
16         abin->align     = 0;
17 }
18
19 static void aspect_bin_class_init(AspectBinClass *class)
20 {
21         GtkWidgetClass    *widget_class    = GTK_WIDGET_CLASS(class);
22         GtkContainerClass *container_class = GTK_CONTAINER_CLASS(class);
23
24         widget_class->size_request  = aspect_bin_size_request;
25         widget_class->size_allocate = aspect_bin_size_allocate;
26
27         container_class->remove = aspect_bin_remove;
28         container_class->forall = aspect_bin_forall;
29 }
30
31 GtkWidget *aspect_bin_new(void)
32 {
33         return GTK_WIDGET(g_object_new(ASPECT_BIN_TYPE, NULL));
34 }
35
36 static void aspect_bin_remove(GtkContainer *container, GtkWidget *child)
37 {
38         AspectBin *abin = ASPECT_BIN(container);
39
40         if (abin->body == child) {
41                 aspect_bin_set_body_widget(abin, NULL, 1);
42         } else {
43                 GTK_CONTAINER_CLASS(aspect_bin_parent_class)->remove
44                         (container, child);
45         }
46 }
47
48 static void aspect_bin_forall(GtkContainer *container,
49                               gboolean      include_internals,
50                               GtkCallback   callback,
51                               gpointer      callback_data)
52 {
53         AspectBin *abin = ASPECT_BIN(container);
54         GtkBin     *bin = GTK_BIN(container);
55
56         if (bin->child)
57                 callback(bin->child, callback_data);
58         
59         if (abin->body)
60                 callback(abin->body, callback_data);
61 }
62
63 static void
64 aspect_bin_size_request(GtkWidget *widget, GtkRequisition *requisition)
65 {
66         AspectBin *abin = ASPECT_BIN(widget);
67         GtkBin    *bin  = GTK_BIN(widget);
68         GtkRequisition creq = {0}, areq = {0};
69
70         if (bin->child && GTK_WIDGET_VISIBLE(bin->child)) {
71                 gtk_widget_size_request(bin->child, &creq);
72         }
73
74         if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) {
75                 int wtmp, htmp;
76                 gtk_widget_size_request(abin->body, &areq);
77                 wtmp = areq.height * abin->ratio + 0.5;
78                 htmp = areq.width  / abin->ratio + 0.5;
79
80                 if (wtmp > areq.width) {
81                         areq.width  = wtmp;
82                 } else {
83                         areq.height = htmp;
84                 }
85         }
86
87         requisition->width  = areq.width + creq.width;
88         requisition->height = MAX(areq.height, creq.height);
89 }
90
91 static void
92 aspect_bin_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
93 {
94         AspectBin *abin = ASPECT_BIN(widget);
95         GtkBin    *bin  = GTK_BIN(widget);
96         GtkRequisition creq = {0};
97         GtkAllocation csize = {0}, asize = {0};
98         
99         /* First find the best fit for the constrained child. */
100         if (abin->body && GTK_WIDGET_VISIBLE(abin->body)) {
101                 asize.height = allocation->height;
102                 asize.width  = asize.height * abin->ratio + 0.5;
103
104                 if (asize.width > allocation->width) {
105                         asize.width  = allocation->width;
106                         asize.height = asize.width / abin->ratio + 0.5;
107                 }
108         }
109
110         /* Now try to fit the other child. */
111         if (bin->child && GTK_WIDGET_VISIBLE(bin->child)) {
112                 gtk_widget_get_child_requisition(bin->child, &creq);
113
114                 if (allocation->width - asize.width < creq.width) {
115                         /* It didn't fit, squish the constrained guy. */
116                         asize.width  = allocation->width - creq.width;
117                         asize.height = asize.width / abin->ratio + 0.5;
118                 }
119
120                 csize.width  = allocation->width - asize.width;
121                 csize.height = MIN(allocation->height, creq.height);
122                 if (abin->constrain) {
123                         csize.height = MAX(csize.height, asize.height);
124                 }
125                 csize.x = asize.width;
126         }
127
128         csize.y = (allocation->height - csize.height) * abin->align + 0.5;
129         asize.y = (allocation->height - asize.height) * abin->align + 0.5;
130
131         if (bin->child)
132                 gtk_widget_size_allocate(bin->child, &csize);
133         if (abin->body)
134                 gtk_widget_size_allocate(abin->body, &asize);
135 }
136
137 void
138 aspect_bin_set_body_widget(AspectBin *abin, GtkWidget *widget, gfloat ratio)
139 {
140         gboolean need_resize = FALSE;
141
142         g_return_if_fail(IS_ASPECT_BIN(abin));
143         g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
144         g_return_if_fail(widget == NULL || widget->parent == NULL);
145
146         if (abin->body == widget)
147                 return;
148         
149         if (abin->body) {
150                 need_resize |= GTK_WIDGET_VISIBLE(abin->body);
151                 gtk_widget_unparent(abin->body);
152         }
153
154         abin->body = widget;
155         if (widget) {
156                 gtk_widget_set_parent(widget, GTK_WIDGET(abin));
157                 need_resize |= GTK_WIDGET_VISIBLE(widget);
158         }
159
160         if (GTK_WIDGET_VISIBLE(abin) && need_resize)
161                 gtk_widget_queue_resize(GTK_WIDGET(abin));
162 }