]> Pileus Git - ~andy/gtk/blob - gtk/gtkbin.c
Added documentation, implemented gtk_extended_layout_is_height_for_width() where...
[~andy/gtk] / gtk / gtkbin.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include "gtkbin.h"
29 #include "gtkextendedlayout.h"
30 #include "gtkintl.h"
31 #include "gtkalias.h"
32
33 static void gtk_bin_add         (GtkContainer   *container,
34                                  GtkWidget      *widget);
35 static void gtk_bin_remove      (GtkContainer   *container,
36                                  GtkWidget      *widget);
37 static void gtk_bin_forall      (GtkContainer   *container,
38                                  gboolean       include_internals,
39                                  GtkCallback     callback,
40                                  gpointer        callback_data);
41 static GType gtk_bin_child_type (GtkContainer   *container);
42
43
44 static void     gtk_bin_extended_layout_init  (GtkExtendedLayoutIface *iface);
45 static gboolean gtk_bin_is_height_for_width   (GtkExtendedLayout      *layout);
46 static void     gtk_bin_get_width_for_height  (GtkExtendedLayout      *layout,
47                                                gint                    height,
48                                                gint                   *minimum_width,
49                                                gint                   *natural_width);
50 static void     gtk_bin_get_height_for_width  (GtkExtendedLayout      *layout,
51                                                gint                    width,
52                                                gint                   *minimum_height,
53                                                gint                   *natural_height);
54
55 static GtkExtendedLayoutIface *parent_extended_layout_iface;
56
57 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkBin, gtk_bin, GTK_TYPE_CONTAINER,
58                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
59                                                          gtk_bin_extended_layout_init))
60
61 static void
62 gtk_bin_class_init (GtkBinClass *class)
63 {
64   GtkContainerClass *container_class;
65
66   container_class = (GtkContainerClass*) class;
67
68   container_class->add = gtk_bin_add;
69   container_class->remove = gtk_bin_remove;
70   container_class->forall = gtk_bin_forall;
71   container_class->child_type = gtk_bin_child_type;
72 }
73
74 static void
75 gtk_bin_init (GtkBin *bin)
76 {
77   gtk_widget_set_has_window (GTK_WIDGET (bin), FALSE);
78
79   bin->child = NULL;
80 }
81
82
83 static GType
84 gtk_bin_child_type (GtkContainer *container)
85 {
86   if (!GTK_BIN (container)->child)
87     return GTK_TYPE_WIDGET;
88   else
89     return G_TYPE_NONE;
90 }
91
92 static void
93 gtk_bin_add (GtkContainer *container,
94              GtkWidget    *child)
95 {
96   GtkBin *bin = GTK_BIN (container);
97
98   if (bin->child != NULL)
99     {
100       g_warning ("Attempting to add a widget with type %s to a %s, "
101                  "but as a GtkBin subclass a %s can only contain one widget at a time; "
102                  "it already contains a widget of type %s",
103                  g_type_name (G_OBJECT_TYPE (child)),
104                  g_type_name (G_OBJECT_TYPE (bin)),
105                  g_type_name (G_OBJECT_TYPE (bin)),
106                  g_type_name (G_OBJECT_TYPE (bin->child)));
107       return;
108     }
109
110   gtk_widget_set_parent (child, GTK_WIDGET (bin));
111   bin->child = child;
112 }
113
114 static void
115 gtk_bin_remove (GtkContainer *container,
116                 GtkWidget    *child)
117 {
118   GtkBin *bin = GTK_BIN (container);
119   gboolean widget_was_visible;
120
121   g_return_if_fail (bin->child == child);
122
123   widget_was_visible = gtk_widget_get_visible (child);
124   
125   gtk_widget_unparent (child);
126   bin->child = NULL;
127   
128   /* queue resize regardless of gtk_widget_get_visible (container),
129    * since that's what is needed by toplevels, which derive from GtkBin.
130    */
131   if (widget_was_visible)
132     gtk_widget_queue_resize (GTK_WIDGET (container));
133 }
134
135 static void
136 gtk_bin_forall (GtkContainer *container,
137                 gboolean      include_internals,
138                 GtkCallback   callback,
139                 gpointer      callback_data)
140 {
141   GtkBin *bin = GTK_BIN (container);
142
143   if (bin->child)
144     (* callback) (bin->child, callback_data);
145 }
146
147
148 /* GtkBin widgets define the padding and borders independantly so
149  * we cannot provide a generic get_desired_size() for the same reason
150  * we never implemented size_request() here.
151  *
152  * But for cases where the GtkBin class's padding is constant and
153  * does not vary based on allocation (most cases), we can at least 
154  * deduce a common code path for the get_width_for_height()/get_height_for_width()
155  * cases by using the delta of the base size requsts.
156  */
157 static void 
158 gtk_bin_extended_layout_init (GtkExtendedLayoutIface *iface)
159 {
160   parent_extended_layout_iface = g_type_interface_peek_parent (iface);
161
162   iface->is_height_for_width   = gtk_bin_is_height_for_width;
163   iface->get_width_for_height  = gtk_bin_get_width_for_height;
164   iface->get_height_for_width  = gtk_bin_get_height_for_width;
165 }
166
167 static gboolean 
168 gtk_bin_is_height_for_width (GtkExtendedLayout      *layout)
169 {
170   GtkBin *bin = GTK_BIN (layout);
171
172   if (bin->child)
173     return gtk_extended_layout_is_height_for_width (GTK_EXTENDED_LAYOUT (bin->child));
174
175   return TRUE;
176 }
177
178 static void
179 get_child_padding_delta (GtkBin         *bin,
180                          gint           *delta_h,
181                          gint           *delta_v)
182 {
183   gint hmin, vmin, child_hmin, child_vmin;
184
185   gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (bin), &hmin, NULL);
186   gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (bin), &vmin, NULL);
187
188   gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (bin->child), &child_hmin, NULL);
189   gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (bin->child), &child_vmin, NULL);
190
191   *delta_h = hmin - child_hmin;
192   *delta_v = vmin - child_vmin;
193 }
194
195 static void 
196 gtk_bin_get_width_for_height (GtkExtendedLayout      *layout,
197                               gint                    height,
198                               gint                   *minimum_width,
199                               gint                   *natural_width)
200 {
201   GtkBin *bin = GTK_BIN (layout);
202   gint    hdelta, vdelta, child_min, child_nat;
203
204   if (bin->child)
205     {
206       get_child_padding_delta (bin, &hdelta, &vdelta);
207       
208       gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (bin->child),
209                                                 height - vdelta,
210                                                 &child_min, &child_nat);
211       
212       if (minimum_width)
213         *minimum_width = child_min + hdelta;
214       
215       if (natural_width)
216         *natural_width = child_nat + hdelta;
217     }
218   else
219     GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, minimum_width, natural_width);
220 }
221
222 static void
223 gtk_bin_get_height_for_width  (GtkExtendedLayout      *layout,
224                                gint                    width,
225                                gint                   *minimum_height,
226                                gint                   *natural_height)
227 {
228   GtkBin *bin = GTK_BIN (layout);
229   gint    hdelta, vdelta, child_min, child_nat;
230
231   if (bin->child)
232     {
233       get_child_padding_delta (bin, &hdelta, &vdelta);
234       
235       gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (bin->child),
236                                                 width - hdelta,
237                                                 &child_min, &child_nat);
238       
239       if (minimum_height)
240         *minimum_height = child_min + vdelta;
241       
242       if (natural_height)
243         *natural_height = child_nat + vdelta;
244     }
245   else
246     GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, minimum_height, natural_height);
247 }
248
249
250 /**
251  * gtk_bin_get_child:
252  * @bin: a #GtkBin
253  * 
254  * Gets the child of the #GtkBin, or %NULL if the bin contains
255  * no child widget. The returned widget does not have a reference
256  * added, so you do not need to unref it.
257  *
258  * Return value: (transfer none): pointer to child of the #GtkBin
259  **/
260 GtkWidget*
261 gtk_bin_get_child (GtkBin *bin)
262 {
263   g_return_val_if_fail (GTK_IS_BIN (bin), NULL);
264
265   return bin->child;
266 }
267
268 #define __GTK_BIN_C__
269 #include "gtkaliasdef.c"