Index: games-frame.h
===================================================================
RCS file: /cvs/gnome/gnome-games/libgames-support/games-frame.h,v
retrieving revision 1.4
diff -u -p -r1.4 games-frame.h
--- games-frame.h	1 May 2004 11:41:02 -0000	1.4
+++ games-frame.h	20 Mar 2005 19:19:38 -0000
@@ -21,8 +21,6 @@
 #define __GAMES_FRAME_H__
 
 
-#include <gdk/gdk.h>
-#include <gtk/gtkbin.h>
 #include <gtk/gtkframe.h>
 
 #ifdef __cplusplus
@@ -43,21 +41,23 @@ typedef struct _GamesFrameClass  GamesFr
 
 struct _GamesFrame
 {
-  GtkFrame frame;
-
-  gint indent;
+  GtkFrame parent_instance;
 };
 
 struct _GamesFrameClass
 {
   GtkFrameClass parent_class;
+
+  /* Padding for future expansion */
+  void (* _games_reserved1) (void);
+  void (* _games_reserved2) (void);
+  void (* _games_reserved3) (void);
+  void (* _games_reserved4) (void);
 };
 
 
 GType      games_frame_get_type   (void) G_GNUC_CONST;
 GtkWidget* games_frame_new        (const gchar *label);
-void       games_frame_set        (GamesFrame  *bold_frame,
-                                   gint         indent);
 void       games_frame_set_label  (GamesFrame  *frame,
                                    const gchar *label);
 
Index: games-frame.c
===================================================================
RCS file: /cvs/gnome/gnome-games/libgames-support/games-frame.c,v
retrieving revision 1.5
diff -u -p -r1.5 games-frame.c
--- games-frame.c	1 May 2004 11:41:02 -0000	1.5
+++ games-frame.c	20 Mar 2005 19:19:38 -0000
@@ -21,33 +21,38 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include "config.h"
+#include <string.h>
 #include <gtk/gtk.h>
 #include "games-frame.h"
 
-enum {
-  PROP_0,
-  PROP_LABEL,
-  PROP_INDENT
-};
-
-static void games_frame_class_init   (GamesFrameClass *klass);
-static void games_frame_init         (GamesFrame      *frame);
-static void games_frame_set_property (GObject         *object,
-                                      guint            prop_id,
-                                      const GValue    *value,
-                                      GParamSpec      *pspec);
-static void games_frame_get_property (GObject         *object,
-                                      guint            prop_id,
-                                      GValue          *value,
-                                      GParamSpec      *pspec);
-static void games_frame_add          (GtkContainer   *container,
-                                      GtkWidget      *widget);
-
-#define MAX_INDENT 30
-#define MIN_INDENT 0
-#define DEFAULT_INDENT 4
+#define DEFAULT_LABEL_SPACING       6
+#define DEFAULT_LABEL_BOLD          TRUE
+
+#define GAMES_FRAME_INDENT_KEY       "games-frame-indent"
+#define GAMES_FRAME_IN_EXPANDER_KEY  "games-frame-in-expander"
+
+
+static void      games_frame_class_init          (GamesFrameClass *klass);
+static void      games_frame_init                (GamesFrame      *frame);
+
+static void      games_frame_size_request        (GtkWidget      *widget,
+                                                 GtkRequisition *requisition);
+static void      games_frame_size_allocate       (GtkWidget      *widget,
+                                                 GtkAllocation  *allocation);
+static void      games_frame_child_allocate      (GtkFrame       *frame,
+                                                 GtkAllocation  *allocation);
+static void      games_frame_style_set           (GtkWidget      *widget,
+                                                 GtkStyle       *previous);
+static gboolean  games_frame_expose_event        (GtkWidget      *widget,
+                                                 GdkEventExpose *event);
+static void      games_frame_label_widget_notify (GtkFrame       *frame);
+static gint      games_frame_get_indent          (GtkWidget      *widget);
+static gint      games_frame_get_label_spacing   (GtkFrame       *frame);
+
+
+static GtkVBoxClass *parent_class = NULL;
 
-static GtkFrameClass *parent_class = NULL;
 
 GType
 games_frame_get_type (void)
@@ -58,190 +63,311 @@ games_frame_get_type (void)
     {
       static const GTypeInfo frame_info =
       {
-	sizeof (GamesFrameClass),
-	NULL,		/* base_init */
-	NULL,		/* base_finalize */
-	(GClassInitFunc) games_frame_class_init,
-	NULL,		/* class_finalize */
-	NULL,		/* class_data */
-	sizeof (GamesFrame),
-	0,		/* n_preallocs */
-	(GInstanceInitFunc) games_frame_init,
+        sizeof (GamesFrameClass),
+        (GBaseInitFunc)     NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc)    games_frame_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data     */
+        sizeof (GamesFrame),
+        0,              /* n_preallocs    */
+        (GInstanceInitFunc) games_frame_init,
       };
-      
-      frame_type =
-	g_type_register_static (GTK_TYPE_FRAME, "GamesFrame",
-				&frame_info, 0);
+
+      frame_type = g_type_register_static (GTK_TYPE_FRAME,
+                                           "GamesFrame",
+                                           &frame_info, 0);
     }
   
   return frame_type;
 }
 
 static void
-games_frame_class_init (GamesFrameClass *class)
+games_frame_class_init (GamesFrameClass *klass)
 {
-  GObjectClass *gobject_class;
-  GtkFrameClass *frame_class;
-  GtkContainerClass *container_class;
-  
-  parent_class = g_type_class_peek_parent (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkFrameClass  *frame_class  = GTK_FRAME_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
 
-  gobject_class = (GObjectClass*) class;
-  frame_class = (GtkFrameClass*) class;
-  container_class = (GtkContainerClass*) class;
-
-  gobject_class->set_property = games_frame_set_property;
-  gobject_class->get_property = games_frame_get_property;
-
-  container_class->add = games_frame_add;
-
-  /* FIXME
-  g_object_class_install_property (gobject_class,
-                                   PROP_INDENT,
-                                   g_param_spec_int ("indent",
-                                                       _("Horizontal offset"),
-                                                       _("X offset of the child in chars"),
-                                                       0.0, 100, 4,
-                                                       G_PARAM_READABLE | G_PARAM_WRITABLE ));
-  */
-  g_object_class_install_property (gobject_class,
-                                   PROP_INDENT,
-                                   g_param_spec_int ("indent",
-                                                       "Horizontal offset",
-                                                       "X offset of the child in chars",
-                                                       MIN_INDENT, MAX_INDENT, DEFAULT_INDENT,
-                                                       G_PARAM_READABLE | G_PARAM_WRITABLE ));
+  widget_class->size_request  = games_frame_size_request;
+  widget_class->size_allocate = games_frame_size_allocate;
+  widget_class->style_set     = games_frame_style_set;
+  widget_class->expose_event  = games_frame_expose_event;
+
+  frame_class->compute_child_allocation = games_frame_child_allocate;
+
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_boolean ("label-bold",
+                                                                 NULL, NULL,
+                                                                 DEFAULT_LABEL_BOLD,
+                                                                 G_PARAM_READABLE));
+  gtk_widget_class_install_style_property (widget_class,
+                                           g_param_spec_int ("label-spacing",
+                                                             NULL, NULL,
+                                                             0,
+                                                             G_MAXINT,
+                                                             DEFAULT_LABEL_SPACING,
+                                                             G_PARAM_READABLE));
 }
 
+
 static void
 games_frame_init (GamesFrame *frame)
 {
-  frame->indent = DEFAULT_INDENT;
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+  g_signal_connect (frame, "notify::label-widget",
+                    G_CALLBACK (games_frame_label_widget_notify),
+                    NULL);
 }
 
 static void
-games_frame_set_property (GObject         *object,
-                          guint            prop_id,
-                          const GValue    *value,
-                          GParamSpec      *pspec)
+games_frame_size_request (GtkWidget      *widget,
+                         GtkRequisition *requisition)
 {
-  GamesFrame *frame = GAMES_FRAME (object);
-  
-  switch (prop_id)
+  GtkFrame       *frame = GTK_FRAME (widget);
+  GtkBin         *bin   = GTK_BIN (widget);
+  GtkRequisition  child_requisition;
+
+  if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
+    {
+      gtk_widget_size_request (frame->label_widget, requisition);
+    }
+  else
     {
-      /* g_object_notify is handled by the _frame_set function */
-    case PROP_LABEL:
-      games_frame_set_label (frame, g_value_get_string (value));
-      break;
-     case PROP_INDENT:
-      games_frame_set (frame, g_value_get_int (value));
-      break;
-    default:
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
+      requisition->width  = 0;
+      requisition->height = 0;
+    }
+
+  requisition->height += games_frame_get_label_spacing (frame);
+
+  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+    {
+      gint indent = games_frame_get_indent (widget);
+
+      gtk_widget_size_request (bin->child, &child_requisition);
+
+      requisition->width = MAX (requisition->width,
+                                child_requisition.width + indent);
+      requisition->height += child_requisition.height;
     }
+
+  requisition->width  += 2 * GTK_CONTAINER (widget)->border_width;
+  requisition->height += 2 * GTK_CONTAINER (widget)->border_width;
 }
 
 static void
-games_frame_get_property (GObject         *object,
-                          guint            prop_id,
-                          GValue          *value,
-                          GParamSpec      *pspec)
+games_frame_size_allocate (GtkWidget     *widget,
+                          GtkAllocation *allocation)
 {
-  GamesFrame *frame = GAMES_FRAME (object);
-  
-  switch (prop_id)
+  GtkFrame *frame = GTK_FRAME (widget);
+  GtkBin   *bin   = GTK_BIN (widget);
+
+  widget->allocation = *allocation;
+
+  games_frame_child_allocate (frame, &frame->child_allocation);
+
+  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+    gtk_widget_size_allocate (bin->child, &frame->child_allocation);
+
+  if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
     {
-    case PROP_INDENT:
-      g_value_set_int (value, frame->indent);
-      break;
-    default:
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
+      GtkAllocation   label_allocation;
+      GtkRequisition  label_requisition;
+      gint            border = GTK_CONTAINER (widget)->border_width;
+
+      gtk_widget_get_child_requisition (frame->label_widget,
+                                        &label_requisition);
+
+      label_allocation.x      = allocation->x + border;
+      label_allocation.y      = allocation->y + border;
+      label_allocation.width  = MAX (label_requisition.width,
+                                     allocation->width - 2 * border);
+      label_allocation.height = label_requisition.height;
+
+      gtk_widget_size_allocate (frame->label_widget, &label_allocation);
     }
 }
 
-GtkWidget*
-games_frame_new (const gchar *label)
+static void
+games_frame_child_allocate (GtkFrame      *frame,
+                           GtkAllocation *child_allocation)
 {
-  GtkWidget *frame;
-  gchar *markup;
+  GtkWidget     *widget     = GTK_WIDGET (frame);
+  GtkAllocation *allocation = &widget->allocation;
+  gint           border     = GTK_CONTAINER (frame)->border_width;
+  gint           spacing    = 0;
+  gint           indent     = games_frame_get_indent (widget);
 
-  frame = g_object_new (GAMES_TYPE_FRAME, NULL);
+  if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
+    {
+      GtkRequisition  child_requisition;
 
-  markup = g_strdup_printf ("<span weight=\"bold\">%s</span>", label);
-  gtk_frame_set_label (GTK_FRAME (frame), markup);
-  g_free (markup);
-  gtk_label_set_use_markup (GTK_LABEL (gtk_frame_get_label_widget (GTK_FRAME (frame))),
-                            TRUE);
-  gtk_misc_set_alignment (GTK_MISC (gtk_frame_get_label_widget (GTK_FRAME (frame))),
-                          0, 0.5);
-  gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
+      gtk_widget_get_child_requisition (frame->label_widget,
+                                        &child_requisition);
+      spacing += child_requisition.height;
+    }
 
-  return frame;
+  spacing += games_frame_get_label_spacing (frame);
+
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+    child_allocation->x    = border + indent;
+  else
+    child_allocation->x    = border;
+
+  child_allocation->y      = border + spacing;
+  child_allocation->width  = MAX (1,
+                                  allocation->width - 2 * border - indent);
+  child_allocation->height = MAX (1,
+                                  allocation->height -
+                                  child_allocation->y - border);
+
+  child_allocation->x += allocation->x;
+  child_allocation->y += allocation->y;
 }
 
-void
-games_frame_set (GamesFrame *frame,
-                 gint          indent)
+static void
+games_frame_style_set (GtkWidget *widget,
+                      GtkStyle  *previous)
 {
-  g_return_if_fail (IS_GAMES_FRAME (frame));
-  
-  indent = CLAMP (indent, MIN_INDENT, MAX_INDENT);
-  
-  if (   (frame->indent != indent))
+  /*  font changes invalidate the indentation  */
+  g_object_set_data (G_OBJECT (widget), GAMES_FRAME_INDENT_KEY, NULL);
+
+  /*  for "label_bold"  */
+  games_frame_label_widget_notify (GTK_FRAME (widget));
+}
+
+static gboolean
+games_frame_expose_event (GtkWidget      *widget,
+                         GdkEventExpose *event)
+{
+  if (GTK_WIDGET_DRAWABLE (widget))
     {
-      g_object_freeze_notify (G_OBJECT (frame));
+      GtkWidgetClass *widget_class = g_type_class_peek_parent (parent_class);
+
+      return widget_class->expose_event (widget, event);
+    }
 
-      if (frame->indent != indent)
+  return FALSE;
+}
+
+static void
+games_frame_label_widget_notify (GtkFrame *frame)
+{
+  if (frame->label_widget)
+    {
+      GtkLabel *label = NULL;
+
+      if (GTK_IS_LABEL (frame->label_widget))
         {
-          frame->indent = indent;
-          g_object_notify (G_OBJECT (frame), "indent");
+          label = GTK_LABEL (frame->label_widget);
+
+          gtk_misc_set_alignment (GTK_MISC (label),
+                                  frame->label_xalign, frame->label_yalign);
+        }
+      else if (GTK_IS_BIN (frame->label_widget))
+        {
+          GtkWidget *child = gtk_bin_get_child (GTK_BIN (frame->label_widget));
+
+          if (GTK_IS_LABEL (child))
+            label = GTK_LABEL (child);
         }
-      g_object_thaw_notify (G_OBJECT (frame));
 
-      gtk_widget_queue_resize (GTK_WIDGET (frame));
+      if (label)
+        {
+          PangoAttrList  *attrs = pango_attr_list_new ();
+          PangoAttribute *attr;
+          gboolean        bold;
+
+          gtk_widget_style_get (GTK_WIDGET (frame), "label_bold", &bold, NULL);
+
+          attr = pango_attr_weight_new (bold ?
+                                        PANGO_WEIGHT_BOLD :
+                                        PANGO_WEIGHT_NORMAL);
+          attr->start_index = 0;
+          attr->end_index   = -1;
+          pango_attr_list_insert (attrs, attr);
+
+          gtk_label_set_attributes (label, attrs);
+
+          pango_attr_list_unref (attrs);
+        }
     }
 }
 
-static void
-games_frame_add (GtkContainer *container,
-                 GtkWidget    *child)
+static gint
+games_frame_get_indent (GtkWidget *widget)
 {
-  GtkBin *bin = GTK_BIN (container);
-  GtkWidget *hbox;
-  GtkWidget *space_label;
-  gchar *label_string;
-  gint indent;
+  gint width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
+                                                   GAMES_FRAME_INDENT_KEY));
+
+  if (! width)
+    {
+      PangoLayout *layout;
 
-  g_return_if_fail (GTK_IS_WIDGET (child));
+      /*  the HIG suggests to use four spaces so do just that  */
+      layout = gtk_widget_create_pango_layout (widget, "    ");
+      pango_layout_get_pixel_size (layout, &width, NULL);
+      g_object_unref (layout);
+
+      g_object_set_data (G_OBJECT (widget),
+                         GAMES_FRAME_INDENT_KEY, GINT_TO_POINTER (width));
+    }
+
+  return width;
+}
+
+static gint
+games_frame_get_label_spacing (GtkFrame *frame)
+{
+  gint spacing = 0;
 
-  if (bin->child != NULL)
+  if ((frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget)) ||
+      (g_object_get_data (G_OBJECT (frame), GAMES_FRAME_IN_EXPANDER_KEY)))
     {
-      g_warning ("Attempting to add a widget with type %s to a %s, "
-                 "but as a GtkBin subclass a %s can only contain one widget at a time; "
-                 "it already contains a widget of type %s",
-                 g_type_name (G_OBJECT_TYPE (child)),
-                 g_type_name (G_OBJECT_TYPE (bin)),
-                 g_type_name (G_OBJECT_TYPE (bin)),
-                 g_type_name (G_OBJECT_TYPE (bin->child)));
-      return;
+      gtk_widget_style_get (GTK_WIDGET (frame),
+                            "label_spacing", &spacing,
+                            NULL);
     }
 
-  hbox = gtk_hbox_new (FALSE, 0);
-  gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
-  indent = GAMES_FRAME (container)->indent;
+  return spacing;
+}
 
-  label_string = g_strnfill (indent, ' ');
-  space_label = gtk_label_new (label_string);
-  g_free (label_string);
-  gtk_box_pack_start (GTK_BOX (hbox), space_label, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (hbox), child, TRUE, TRUE, 0);
+/**
+ * games_frame_new:
+ * @label: text to set as the frame's title label (or %NULL for no title)
+ *
+ * Creates a #GamesFrame widget. A #GamesFrame is a HIG-compliant
+ * variant of #GtkFrame. It doesn't render a frame at all but
+ * otherwise behaves like a frame. The frame's title is rendered in
+ * bold and the frame content is indented as suggested by the GNOME 
+ * HIG (see http://developer.gnome.org/projects/gup/hig/).
+ *
+ * Return value: a new #GamesFrame widget
+ *
+ * Since: GNOME-GAMES 2.11
+ **/
+GtkWidget *
+games_frame_new (const gchar *label)
+{
+  GtkWidget *frame;
+  gboolean   expander = FALSE;
 
-  gtk_widget_unparent (GTK_WIDGET (hbox));
-  gtk_widget_set_parent (GTK_WIDGET (hbox), GTK_WIDGET (bin));
-  bin->child = hbox;
+  /*  somewhat hackish, should perhaps be an object property of GamesFrame  */
+  if (label && strcmp (label, "<expander>") == 0)
+    {
+      expander = TRUE;
+      label    = NULL;
+    }
+
+  frame = g_object_new (GAMES_TYPE_FRAME,
+                        "label", label,
+                        NULL);
+
+  if (expander)
+    g_object_set_data (G_OBJECT (frame),
+                       GAMES_FRAME_IN_EXPANDER_KEY, (gpointer) TRUE);
+
+  return frame;
 }
 
 void
