libyui-gtk  2.44.5
 All Classes Functions
ygtkratiobox.c
1 /********************************************************************
2  * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
3  ********************************************************************/
4 
5 /* YGtkRatioBox container */
6 // check the header file for information about this container
7 
8 #include <yui/Libyui_config.h>
9 #include <math.h>
10 #include "ygtkratiobox.h"
11 
12 G_DEFINE_ABSTRACT_TYPE (YGtkRatioBox, ygtk_ratio_box, GTK_TYPE_CONTAINER)
13 
14 static void ygtk_ratio_box_init (YGtkRatioBox *box)
15 {
16  gtk_widget_set_has_window (GTK_WIDGET(box), FALSE);
17  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE);
18 }
19 
20 static GType ygtk_ratio_box_child_type (GtkContainer* container)
21 { return GTK_TYPE_WIDGET; }
22 
23 void ygtk_ratio_box_pack (YGtkRatioBox *box, GtkWidget *child, gfloat ratio)
24 {
25  YGtkRatioBoxChild* child_info;
26  child_info = g_new (YGtkRatioBoxChild, 1);
27  child_info->widget = child;
28  child_info->ratio = ratio;
29 
30  box->children = g_list_append (box->children, child_info);
31 
32  gtk_widget_freeze_child_notify (child);
33  gtk_widget_set_parent (child, GTK_WIDGET (box));
34  gtk_widget_thaw_child_notify (child);
35 }
36 
37 static YGtkRatioBoxChild *ygtk_ratio_get_child_info (YGtkRatioBox *box, GtkWidget *child)
38 {
39  YGtkRatioBoxChild *i = NULL;
40  GList *list;
41  for (list = box->children; list; list = list->next) {
42  i = (YGtkRatioBoxChild*) list->data;
43  if (i->widget == child)
44  break;
45  }
46  if (!list)
47  return NULL;
48  return i;
49 }
50 
51 static void ygtk_ratio_box_add (GtkContainer *container, GtkWidget *child)
52 {
53  ygtk_ratio_box_pack (YGTK_RATIO_BOX (container), child, 1.0);
54 }
55 
56 static void ygtk_ratio_box_remove (GtkContainer *container, GtkWidget *widget)
57 {
58  YGtkRatioBox* box = YGTK_RATIO_BOX (container);
59 
60  GList* child = box->children;
61  for (child = box->children; child; child = child->next) {
62  YGtkRatioBoxChild *box_child = (YGtkRatioBoxChild*) child->data;
63  if (box_child->widget == widget) {
64  gboolean was_visible = gtk_widget_get_visible (widget);
65  gtk_widget_unparent (widget);
66 
67  box->children = g_list_remove_link (box->children, child);
68  g_list_free (child);
69  g_free (box_child);
70 
71  if (was_visible)
72  gtk_widget_queue_resize (GTK_WIDGET (container));
73  break;
74  }
75  }
76 }
77 
78 static void ygtk_ratio_box_forall (GtkContainer *container, gboolean include_internals,
79  GtkCallback callback, gpointer callback_data)
80 {
81  g_return_if_fail (callback != NULL);
82 
83  YGtkRatioBox* box = YGTK_RATIO_BOX (container);
84 
85  GList* children = box->children;
86  while (children) {
87  YGtkRatioBoxChild* child = (YGtkRatioBoxChild*) children->data;
88  children = children->next;
89  (* callback) (child->widget, callback_data);
90  }
91 }
92 
93 /* We put size_request and _allocate in the same functions for both
94  orientations because it's just easier to maintain having the
95  logic in the same place. */
96 static void ygtk_ratio_box_get_preferred_size (GtkWidget *widget,
97  GtkRequisition *requisition,
98  GtkOrientation orientation)
99 {
100  requisition->width = requisition->height = 0;
101 
102  YGtkRatioBox* box = YGTK_RATIO_BOX (widget);
103  gint children_nb = 0;
104  GList *i;
105  for (i = box->children; i; i = i->next) {
106  YGtkRatioBoxChild* child = i->data;
107  if (!gtk_widget_get_visible (child->widget))
108  continue;
109 
110  GtkRequisition min_child_req;
111  GtkRequisition nat_child_req;
112  gtk_widget_get_preferred_size (child->widget, &min_child_req, &nat_child_req);
113  if (orientation == GTK_ORIENTATION_HORIZONTAL)
114  requisition->height = MAX (requisition->height, min_child_req.height);
115  else
116  requisition->width = MAX (requisition->width, min_child_req.width);
117  children_nb++;
118  }
119  gint spacing = children_nb ? box->spacing*(children_nb-1) : 0;
120  if (orientation == GTK_ORIENTATION_HORIZONTAL)
121  requisition->width += spacing;
122  else
123  requisition->height += spacing;
124 
125  int border = gtk_container_get_border_width(GTK_CONTAINER (box));
126  requisition->width += border*2;
127  requisition->height += border*2;
128 }
129 
130 static void ygtk_ratio_box_size_allocate (GtkWidget *widget,
131  GtkAllocation *allocation,
132  GtkOrientation orientation)
133 {
134  YGtkRatioBox* box = YGTK_RATIO_BOX (widget);
135 
136  gfloat ratios_sum = 0;
137  gint children_nb = 0;
138 
139  GList* i;
140  for (i = box->children; i; i = i->next) {
141  YGtkRatioBoxChild* child = i->data;
142  if (!gtk_widget_get_visible (child->widget))
143  continue;
144 
145  ratios_sum += child->ratio;
146  children_nb++;
147  }
148 
149  gint spacing = children_nb ? box->spacing*(children_nb-1) : 0;
150 
151  int border = gtk_container_get_border_width(GTK_CONTAINER (box));
152  int x = allocation->x + border, y = allocation->y + border,
153  width = allocation->width - border*2, height = allocation->height - border*2;
154 
155  gint length;
156  if (orientation == GTK_ORIENTATION_HORIZONTAL)
157  length = width - spacing;
158  else
159  length = height - spacing;
160  gint child_pos = 0;
161 
162  for (i = box->children; i; i = i->next) {
163  YGtkRatioBoxChild* child = i->data;
164  if (!gtk_widget_get_visible (child->widget))
165  continue;
166 
167  //GtkRequisition min_child_req;
168  //GtkRequisition nat_child_req;
169  //gtk_widget_get_preferred_size (child->widget, &min_child_req, &nat_child_req);
170 
171  gint child_length = (child->ratio * length) / ratios_sum;
172  if (!i->next) // last takes rest (any residual length)
173  child_length = length - child_pos;
174 
175  GtkAllocation child_alloc;
176  if (orientation == GTK_ORIENTATION_HORIZONTAL) {
177  child_alloc.x = x + child_pos;
178  child_alloc.y = y;
179  child_alloc.width = child_length;
180  child_alloc.height = height;
181  }
182  else { // GTK_ORIENTATION_VERTICAL
183  child_alloc.x = x;
184  child_alloc.y = y + child_pos;
185  child_alloc.width = width;
186  child_alloc.height = child_length;
187  }
188  child_alloc.width = MAX (child_alloc.width, 1);
189  child_alloc.height = MAX (child_alloc.height, 1);
190 
191  gtk_widget_size_allocate (child->widget, &child_alloc);
192  child_pos += child_length + box->spacing;
193  }
194 }
195 
196 void ygtk_ratio_box_set_child_packing (YGtkRatioBox *box, GtkWidget *child, gfloat ratio)
197 {
198  YGtkRatioBoxChild *child_info;
199  child_info = ygtk_ratio_get_child_info (box, child);
200  if (child_info) {
201  gtk_widget_freeze_child_notify (child);
202  child_info->ratio = ratio;
203  if (gtk_widget_get_visible (child) && gtk_widget_get_visible (GTK_WIDGET(box)))
204  gtk_widget_queue_resize (child);
205 
206  gtk_widget_thaw_child_notify (child);
207  }
208 }
209 
210 void ygtk_ratio_box_set_spacing (YGtkRatioBox *box, guint spacing)
211 {
212  box->spacing = spacing;
213 }
214 
215 static void ygtk_ratio_box_class_init (YGtkRatioBoxClass *klass)
216 {
217  ygtk_ratio_box_parent_class = (GtkContainerClass*) g_type_class_peek_parent (klass);
218 
219  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
220  container_class->add = ygtk_ratio_box_add;
221  container_class->remove = ygtk_ratio_box_remove;
222  container_class->forall = ygtk_ratio_box_forall;
223  container_class->child_type = ygtk_ratio_box_child_type;
224 }
225 
226 //** RatioHBox
227 
228 G_DEFINE_TYPE (YGtkRatioHBox, ygtk_ratio_hbox, YGTK_TYPE_RATIO_BOX)
229 
230 static void ygtk_ratio_hbox_init (YGtkRatioHBox *box)
231 { }
232 
233 static void ygtk_ratio_hbox_get_preferred_size (GtkWidget *widget,
234  GtkRequisition *requisition)
235 { ygtk_ratio_box_get_preferred_size (widget, requisition, GTK_ORIENTATION_HORIZONTAL); }
236 
237 static void
238 ygtk_ratio_hbox_get_preferred_width (GtkWidget *widget,
239  gint *minimal_width,
240  gint *natural_width)
241 {
242  GtkRequisition requisition;
243  ygtk_ratio_hbox_get_preferred_size (widget, &requisition);
244  *minimal_width = *natural_width = requisition.width;
245 }
246 
247 static void
248 ygtk_ratio_hbox_get_preferred_height (GtkWidget *widget,
249  gint *minimal_height,
250  gint *natural_height)
251 {
252  GtkRequisition requisition;
253  ygtk_ratio_hbox_get_preferred_size (widget, &requisition);
254  *minimal_height = *natural_height = requisition.height;
255 }
256 
257 static void ygtk_ratio_hbox_size_allocate (GtkWidget *widget,
258  GtkAllocation *allocation)
259 { ygtk_ratio_box_size_allocate (widget, allocation, GTK_ORIENTATION_HORIZONTAL); }
260 
261 GtkWidget* ygtk_ratio_hbox_new (gint spacing)
262 {
263  YGtkRatioBox* box = (YGtkRatioBox*) g_object_new (YGTK_TYPE_RATIO_HBOX, NULL);
264  box->spacing = spacing;
265  return GTK_WIDGET (box);
266 }
267 
268 static void ygtk_ratio_hbox_class_init (YGtkRatioHBoxClass *klass)
269 {
270  ygtk_ratio_hbox_parent_class = (YGtkRatioBoxClass*) g_type_class_peek_parent (klass);
271 
272  GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
273  widget_class->get_preferred_width = ygtk_ratio_hbox_get_preferred_width;
274  widget_class->get_preferred_height = ygtk_ratio_hbox_get_preferred_height;
275 
276  widget_class->size_allocate = ygtk_ratio_hbox_size_allocate;
277 }
278 
279 //** RatioVBox
280 
281 G_DEFINE_TYPE (YGtkRatioVBox, ygtk_ratio_vbox, YGTK_TYPE_RATIO_BOX)
282 
283 static void ygtk_ratio_vbox_init (YGtkRatioVBox *box)
284 { }
285 
286 static void ygtk_ratio_vbox_get_preferred_size (GtkWidget *widget,
287  GtkRequisition *requisition)
288 { ygtk_ratio_box_get_preferred_size (widget, requisition, GTK_ORIENTATION_VERTICAL); }
289 
290 static void
291 ygtk_ratio_vbox_get_preferred_width (GtkWidget *widget,
292  gint *minimal_width,
293  gint *natural_width)
294 {
295  GtkRequisition requisition;
296  ygtk_ratio_vbox_get_preferred_size (widget, &requisition);
297  *minimal_width = *natural_width = requisition.width;
298 }
299 
300 static void
301 ygtk_ratio_vbox_get_preferred_height (GtkWidget *widget,
302  gint *minimal_height,
303  gint *natural_height)
304 {
305  GtkRequisition requisition;
306  ygtk_ratio_vbox_get_preferred_size (widget, &requisition);
307  *minimal_height = *natural_height = requisition.height;
308 }
309 
310 static void ygtk_ratio_vbox_size_allocate (GtkWidget *widget,
311  GtkAllocation *allocation)
312 { ygtk_ratio_box_size_allocate (widget, allocation, GTK_ORIENTATION_VERTICAL); }
313 
314 GtkWidget* ygtk_ratio_vbox_new (gint spacing)
315 {
316  YGtkRatioBox* box = (YGtkRatioBox*) g_object_new (YGTK_TYPE_RATIO_VBOX, NULL);
317  box->spacing = spacing;
318  return GTK_WIDGET (box);
319 }
320 
321 static void ygtk_ratio_vbox_class_init (YGtkRatioVBoxClass *klass)
322 {
323  ygtk_ratio_vbox_parent_class = g_type_class_peek_parent (klass);
324 
325  GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
326  widget_class->get_preferred_width = ygtk_ratio_vbox_get_preferred_width;
327  widget_class->get_preferred_height = ygtk_ratio_vbox_get_preferred_height;
328  widget_class->size_allocate = ygtk_ratio_vbox_size_allocate;
329 }
330 
331 //** YGtkAdjSize
332 
333 G_DEFINE_TYPE (YGtkAdjSize, ygtk_adj_size, GTK_TYPE_BIN)
334 
335 static void ygtk_adj_size_init (YGtkAdjSize *adj_size)
336 {
337  gtk_widget_set_has_window(GTK_WIDGET(adj_size), FALSE);
338  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (adj_size), FALSE);
339 }
340 
341 static void ygtk_adj_size_get_preferred_size (
342  GtkWidget *widget, GtkRequisition *requisition)
343 {
344  GtkWidget *child = gtk_bin_get_child(GTK_BIN (widget));
345 
346  requisition->width = requisition->height = 0;
347  if (child && gtk_widget_get_visible((child))) {
348  gtk_widget_get_preferred_size(child, NULL, requisition);
349 
350  guint border = gtk_container_get_border_width(GTK_CONTAINER (widget));
351  requisition->width += border * 2;
352  requisition->height += border * 2;
353 
354  YGtkAdjSize *adj_size = YGTK_ADJ_SIZE (widget);
355  if (adj_size->min_size_cb) {
356  guint min_width, min_height;
357  adj_size->min_size_cb (&min_width, &min_height, adj_size->min_size_data);
358  requisition->width = MAX (requisition->width, min_width);
359  requisition->height = MAX (requisition->height, min_height);
360  }
361  requisition->width = MAX (requisition->width, adj_size->min_width);
362  requisition->height = MAX (requisition->height, adj_size->min_height);
363 
364  if (adj_size->max_width)
365  requisition->width = MIN (requisition->width, adj_size->max_width);
366  if (adj_size->max_height)
367  requisition->height = MIN (requisition->height, adj_size->max_height);
368 
369  if (adj_size->only_expand) {
370  adj_size->min_width = requisition->width;
371  adj_size->min_height = requisition->height;
372  }
373  }
374 }
375 
376 static void
377 ygtk_adj_size_get_preferred_width (GtkWidget *widget,
378  gint *minimal_width,
379  gint *natural_width)
380 {
381  GtkRequisition requisition;
382  ygtk_adj_size_get_preferred_size (widget, &requisition);
383  *minimal_width = *natural_width = requisition.width;
384 }
385 
386 static void
387 ygtk_adj_size_get_preferred_height (GtkWidget *widget,
388  gint *minimal_height,
389  gint *natural_height)
390 {
391  GtkRequisition requisition;
392  ygtk_adj_size_get_preferred_size (widget, &requisition);
393  *minimal_height = *natural_height = requisition.height;
394 }
395 
396 static void ygtk_adj_size_size_allocate (GtkWidget *widget,
397  GtkAllocation *allocation)
398 {
399  GtkWidget *child = gtk_bin_get_child(GTK_BIN (widget));
400  if (child && gtk_widget_get_visible (child)) {
401  GtkAllocation child_alloc = *allocation;
402  guint border = gtk_container_get_border_width(GTK_CONTAINER (widget));
403  child_alloc.x += border;
404  child_alloc.y += border;
405  child_alloc.width -= border * 2;
406  child_alloc.height -= border * 2;
407  child_alloc.width = MAX (child_alloc.width, 1);
408  child_alloc.height = MAX (child_alloc.height, 1);
409  gtk_widget_size_allocate (child, &child_alloc);
410  }
411  GTK_WIDGET_CLASS (ygtk_adj_size_parent_class)->size_allocate (widget, allocation);
412 }
413 
414 GtkWidget* ygtk_adj_size_new (void)
415 {
416  return GTK_WIDGET (g_object_new (YGTK_TYPE_ADJ_SIZE, NULL));
417 }
418 
419 void ygtk_adj_size_set_min (YGtkAdjSize *adj_size, guint min_width, guint min_height)
420 {
421  adj_size->min_width = min_width;
422  adj_size->min_height = min_height;
423 }
424 
425 void ygtk_adj_size_set_max (YGtkAdjSize *adj_size, guint max_width, guint max_height)
426 {
427  adj_size->max_width = max_width;
428  adj_size->max_height = max_height;
429 }
430 
431 void ygtk_adj_size_set_min_cb (YGtkAdjSize *adj_size, LimitSizeCb min_size_cb, gpointer data)
432 {
433  adj_size->min_size_cb = min_size_cb;
434  adj_size->min_size_data = data;
435 }
436 
437 void ygtk_adj_size_set_only_expand (YGtkAdjSize *adj_size, gboolean only_expand)
438 {
439  adj_size->only_expand = only_expand;
440 }
441 
442 static void ygtk_adj_size_class_init (YGtkAdjSizeClass *klass)
443 {
444  ygtk_adj_size_parent_class = g_type_class_peek_parent (klass);
445 
446  GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
447  widget_class->get_preferred_width = ygtk_adj_size_get_preferred_width;
448  widget_class->get_preferred_height = ygtk_adj_size_get_preferred_height;
449  widget_class->size_allocate = ygtk_adj_size_size_allocate;
450 }
451