1 /* Fo
2  * fo-area-normal.c: Normal block-area object
3  *
4  * Copyright (C) 2001 Sun Microsystems
5  * Copyright (C) 2007-2009 Menteith Consulting Ltd
6  *
7  * See COPYING for the status of this software.
8  */
9 
10 #include "fo-utils.h"
11 #include "fo-area.h"
12 #include "fo-area-area.h"
13 #include "fo-area-area-private.h"
14 #include "fo-area-normal.h"
15 
16 struct _FoAreaNormal
17 {
18   FoAreaArea parent_instance;
19 };
20 
21 struct _FoAreaNormalClass
22 {
23   FoAreaAreaClass parent_class;
24 };
25 
26 static void fo_area_normal_class_init  (FoAreaNormalClass *klass);
27 static void fo_area_normal_finalize    (GObject           *object);
28 
29 static void fo_area_normal_debug_dump_properties (FoArea *area,
30 							      gint depth);
31 static FoArea* fo_area_normal_size_request (FoArea *child);
32 
33 static gpointer parent_class;
34 
35 GType
fo_area_normal_get_type(void)36 fo_area_normal_get_type (void)
37 {
38   static GType object_type = 0;
39 
40   if (!object_type)
41     {
42       static const GTypeInfo object_info =
43       {
44         sizeof (FoAreaNormalClass),
45         (GBaseInitFunc) NULL,
46         (GBaseFinalizeFunc) NULL,
47         (GClassInitFunc) fo_area_normal_class_init,
48         NULL,           /* class_finalize */
49         NULL,           /* class_data */
50         sizeof (FoAreaNormal),
51         0,              /* n_preallocs */
52         NULL,		/* instance_init */
53 	NULL		/* value_table */
54       };
55 
56       object_type = g_type_register_static (FO_TYPE_AREA_AREA,
57                                             "FoAreaNormal",
58                                             &object_info, 0);
59     }
60 
61   return object_type;
62 }
63 
64 static void
fo_area_normal_class_init(FoAreaNormalClass * klass)65 fo_area_normal_class_init (FoAreaNormalClass *klass)
66 {
67   GObjectClass *object_class = G_OBJECT_CLASS (klass);
68 
69   parent_class = g_type_class_peek_parent (klass);
70 
71   object_class->finalize = fo_area_normal_finalize;
72 
73   FO_AREA_CLASS (klass)->debug_dump_properties = fo_area_normal_debug_dump_properties;
74   FO_AREA_CLASS (klass)->size_request = fo_area_normal_size_request;
75 }
76 
77 static void
fo_area_normal_finalize(GObject * object)78 fo_area_normal_finalize (GObject *object)
79 {
80   FoAreaNormal *fo_area_normal;
81 
82   fo_area_normal = FO_AREA_NORMAL (object);
83 
84   G_OBJECT_CLASS (parent_class)->finalize (object);
85 }
86 
87 
88 /**
89  * fo_area_normal_new:
90  *
91  * Creates a new #FoAreaNormal initialized to default value.
92  *
93  * Return value: the new #FoAreaNormal
94  **/
95 FoArea*
fo_area_normal_new(void)96 fo_area_normal_new (void)
97 {
98   return FO_AREA (g_object_new (fo_area_normal_get_type (), NULL));
99 }
100 
101 
102 void
fo_area_normal_debug_dump_properties(FoArea * area,gint depth)103 fo_area_normal_debug_dump_properties (FoArea *area, gint depth)
104 {
105   FoAreaNormal *normal;
106   gchar *indent = g_strnfill (depth * 2, ' ');
107 
108   g_return_if_fail (area != NULL);
109   g_return_if_fail (FO_IS_AREA_NORMAL (area));
110 
111   normal = FO_AREA_NORMAL (area);
112 
113   g_free (indent);
114   FO_AREA_CLASS (parent_class)->debug_dump_properties (area, depth + 1);
115 }
116 
117 FoArea*
fo_area_normal_add_child(FoArea * parent,FoArea * child)118 fo_area_normal_add_child (FoArea *parent, FoArea *child)
119 {
120   g_return_val_if_fail (parent != NULL, NULL);
121   g_return_val_if_fail (FO_IS_AREA_NORMAL (parent), NULL);
122   g_return_val_if_fail (child != NULL, NULL);
123 
124   return fo_area_real_add_child (parent, child);
125 }
126 
127 /**
128  * fo_area_normal_size_request:
129  * @child: Child area
130  *
131  * Check that the parent area of @child has sufficient space for
132  * @child.  If not enough space, request that the parent has
133  * sufficient space allocated for it, then adjust @child and its
134  * siblings as necessary to fit into the resized parent area.
135  *
136  * Return value: Pointer to the last area generated from @child after
137  * any reallocation and resizing
138  **/
139 FoArea*
fo_area_normal_size_request(FoArea * child)140 fo_area_normal_size_request (FoArea *child)
141 {
142   FoArea *use_child_area;
143   FoArea *parent;
144   gdouble total_child_height = 0;
145   gdouble normal_child_available_bpdim;
146   gdouble child_height;
147   gdouble child_space_before, child_space_after;
148 
149   g_return_val_if_fail (child != NULL, NULL);
150   g_return_val_if_fail (FO_IS_AREA_AREA (child), NULL);
151   g_return_val_if_fail (!FO_AREA_IS_ROOT (child), NULL);
152   g_return_val_if_fail (FO_IS_AREA_AREA (fo_area_parent (child)), NULL);
153 
154   child_height = fo_area_area_get_height (child);
155   child_space_before = fo_area_area_get_space_before (child);
156   child_space_after = fo_area_area_get_space_after (child);
157 
158   parent = fo_area_parent (child);
159   normal_child_available_bpdim = fo_area_get_child_available_bpdim (parent);
160 
161 #if defined(LIBFO_DEBUG) && 0
162   g_message ("normal_size_request (%p):: parent: %s; generated by: %s; available_height: %f",
163 	     child,
164 	     fo_object_debug_sprintf (parent),
165 	     fo_object_debug_sprintf (parent->generated_by),
166 	     normal_child_available_bpdim);
167   g_message ("normal_size_request (%p):: child: %s; generated by: %s; height: %f; space_before: %f; space_after: %f",
168 	     child,
169 	     fo_object_debug_sprintf (child),
170 	     fo_object_debug_sprintf (child->generated_by),
171 	     child_height,
172 	     child_space_before,
173 	     child_space_after);
174 #endif
175 
176   fo_area_children_foreach (parent,
177 			    G_TRAVERSE_ALL,
178 			    &fo_area_accumulate_height,
179 			    &total_child_height);
180 #if defined(LIBFO_DEBUG) && 0
181   g_message ("normal_size_request (%p):: child total: %f",
182 	     child,
183 	     total_child_height);
184 #endif
185 
186   fo_area_area_set_height (parent,
187 			   total_child_height +
188 			   fo_area_area_get_border_before (parent) +
189 			   fo_area_area_get_padding_before (parent) +
190 			   fo_area_area_get_padding_after (parent) +
191 			   fo_area_area_get_border_after (parent));
192 
193   /* Don't bother doing a size_request if still fit within
194      available height */
195   if (normal_child_available_bpdim < fo_area_area_get_height (parent))
196   {
197     parent = fo_area_size_request (parent);
198     normal_child_available_bpdim =
199       MAX (fo_area_get_available_height (parent) -
200 	   fo_area_area_get_border_before (parent) -
201 	   fo_area_area_get_padding_before (parent) -
202 	   fo_area_area_get_padding_after (parent) -
203 	   fo_area_area_get_border_after (parent),
204 	   0);
205     fo_area_set_child_available_bpdim (parent,
206 				       normal_child_available_bpdim);
207 #if defined(LIBFO_DEBUG) && 0
208     g_message ("normal_size_request (%p):: new parent: %s; generated by: %s; available_height: %f",
209 	       child,
210 	       fo_object_debug_sprintf (parent),
211 	       fo_object_debug_sprintf (parent->generated_by),
212 	       normal_child_available_bpdim);
213 #endif
214   }
215 
216   total_child_height = 0;
217   fo_area_children_foreach (parent,
218 			    G_TRAVERSE_ALL,
219 			    &fo_area_accumulate_height,
220 			    &total_child_height);
221 
222 #if defined(LIBFO_DEBUG) && 0
223   g_message ("normal_size_request (%p):: new child total: %f",
224 	     child,
225 	     total_child_height);
226 #endif
227 
228   fo_area_set_next_x (parent,
229 		      fo_area_area_get_border_start (parent) +
230 		      fo_area_area_get_padding_start (parent));
231   fo_area_set_next_y (parent,
232 		      - (fo_area_area_get_border_before (parent) +
233 			 fo_area_area_get_padding_before (parent)));
234 
235   if (total_child_height <= normal_child_available_bpdim)
236     {
237       use_child_area = fo_area_first_child (parent);
238 
239       while (use_child_area)
240 	{
241 	  fo_area_area_set_x (use_child_area,
242 			      fo_area_get_next_x (parent) +
243 			      fo_area_area_get_start_indent (use_child_area) -
244 			      fo_area_area_get_x (parent));
245 	  fo_area_area_set_y (use_child_area,
246 			      fo_area_get_next_y (parent));
247 	  fo_area_set_next_x (parent, 0);
248 	  fo_area_set_next_y (parent,
249 			      fo_area_get_next_y (parent) -
250 			      fo_area_area_get_height (use_child_area));
251 	  fo_area_set_available_height (child,
252 					fo_area_area_get_height (use_child_area));
253 	  fo_area_set_available_width (child,
254 				       fo_area_get_child_available_ipdim (parent));
255 
256 	  use_child_area = fo_area_next_sibling (use_child_area);
257 	}
258 
259 #if defined(LIBFO_DEBUG) && 0
260       g_message ("normal_size_request (%p):: return:: parent->last: %s; generated by: %s",
261 		 child,
262 		 fo_object_debug_sprintf (fo_area_last_child (parent)),
263 		 fo_object_debug_sprintf (fo_area_last_child (parent->generated_by)));
264 #endif
265       return fo_area_last_child (parent);
266     }
267   else
268     {
269       use_child_area = fo_area_first_child (parent);
270 
271       while (use_child_area)
272 	{
273 	  if (normal_child_available_bpdim >=
274 	      fo_area_area_get_height (use_child_area))
275 	    {
276 	      fo_area_area_set_x (use_child_area,
277 				  fo_area_get_next_x (parent) +
278 				  fo_area_area_get_start_indent (use_child_area));
279 	      fo_area_area_set_y (use_child_area,
280 				  fo_area_get_next_y (parent));
281 	      fo_area_set_next_x (parent, 0);
282 	      fo_area_set_next_y (parent,
283 				  fo_area_get_next_y (parent) -
284 				  fo_area_area_get_height (use_child_area));
285 	      fo_area_set_available_height (child,
286 					    fo_area_area_get_height (use_child_area));
287 	      fo_area_set_available_width (child,
288 					   fo_area_get_child_available_ipdim (parent));
289 
290 	      use_child_area = fo_area_next_sibling (use_child_area);
291 	    }
292 	  else
293 	    {
294 #if defined(LIBFO_DEBUG) && 1
295 	      g_message ("normal_size_request:: splitting:: child: %s; generated by: %s",
296 			 fo_object_debug_sprintf (use_child_area),
297 			 fo_object_debug_sprintf (use_child_area->generated_by));
298 #endif
299 	      use_child_area = fo_area_split_before_height (use_child_area,
300 							    normal_child_available_bpdim -
301 							    fo_area_area_get_height (parent));
302 	      parent = fo_area_parent (use_child_area);
303 	      normal_child_available_bpdim = fo_area_get_child_available_bpdim (parent);
304 	    }
305 	}
306 
307 #if defined(LIBFO_DEBUG) && 0
308       g_message ("normal_size_request (%p):: total > available:: return:: parent->last: %s; generated by: %s",
309 		 child,
310 		 fo_object_debug_sprintf (fo_area_last_child (parent)),
311 		 fo_object_debug_sprintf (fo_area_last_child (parent->generated_by)));
312 #endif
313       return fo_area_last_child (parent);
314     }
315 }
316 
317