[PATCH] Add extended layout support for GtkViewport



This patch adds extended layout support for GtkViewport.  While natural
size support is easy (I would say natural...), adding
height-for-width/width-for-height support requires a new property.  The
property, however, is useful even without extended layout support.

The idea is that right now the viewport will never give an allocation to
the child that is narrower than the requisition.  However, it can be
useful to force the viewport to have only the vertical scrollbar (or
dually the horizontal scrollbar).  This is a great application of
height-for-width/width-for-height, because these extended layout hooks
are just what is needed to get the range of the single visible scrollbar.

The patch implements this and adds a test (which won't work unless the
GtkLabel patch is applied).

With these two patches, I *guess* that extended layout branch suits my
needs.  I might need to implement GtkExtendedLayout on GtkExpander, and
that's it.

Also, the "flow" behavior could indeed be implemented on GtkHBox with a
"wrap" property; I started working on a patch but it is more complicated
than I'd like for various reasons:

1) getting the algorithm right is already a mess;

2) to do it properly, it should be done in GtkVBox too (laying out in
multiple columns when you reach the bottom of the allocation); I don't
need this so I don't have very much the incentive;

3) then, does this mean that I need a new abstract class between GtkBox
and Gtk{H,V}Box?  Or that I need to implement the new behavior in the
two button box classes too?  This also reduces my willingness to do this.

4) Thinking more about it, it actually seems to me that the "flow"
concept is most similar to a GtkHButtonBox with left-edge packing, more
than to a GtkHBox.  So I'm a bit lost about where to implement it.  I'll
probably make my own container when time comes.

(Of course, I cannot really rely on something that is on a branch, so
I'll go on with my GtkManagedLayout for a while.  However, I'll eagerly
wait for GTK+ 2.16 so that I can get rid of it).

Paolo
2008-09-03  Paolo Bonzini  <bonzini gnu org>

	* gtk/gtk.symbols: Add new symbols for GtkViewportConstraint and
	its usage in gtk_viewport.
	* gtk/gtkenums.h: Add GtkViewportConstraint.
	* gtk/gtkviewport.h: Add a new GtkViewportConstraint field and
	its accessors.  Turn the existing shadow_type field into a bitfield.
	* gtk/gtkviewport.c: Add the corresponding property; use
	extended layout info.

	* tests/testextlayoutviewport.c: New.
	* tests/Makefile.am: Add rules for it.
---
 gtk/gtk.symbols               |    3 +
 gtk/gtkenums.h                |    8 +++
 gtk/gtkviewport.c             |  115 +++++++++++++++++++++++++++++++++++++++--
 gtk/gtkviewport.h             |   31 ++++++-----
 tests/Makefile.am             |    7 +++
 tests/testextlayoutviewport.c |   80 ++++++++++++++++++++++++++++
 7 files changed, 236 insertions(+), 18 deletions(-)
 create mode 100644 tests/testextlayoutviewport.c

diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 842148a..dc9f6a5 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -358,6 +358,7 @@ gtk_icon_theme_error_get_type G_GNUC_CONST
 gtk_toolbar_child_type_get_type G_GNUC_CONST
 gtk_toolbar_space_style_get_type G_GNUC_CONST
 gtk_toolbar_style_get_type G_GNUC_CONST
+gtk_viewport_constraint_get_type G_GNUC_CONST
 #endif
 #endif
 
@@ -4553,11 +4554,13 @@ gtk_vbutton_box_new
 #if IN_FILE(__GTK_VIEWPORT_C__)
 gtk_viewport_get_hadjustment
 gtk_viewport_get_shadow_type
+gtk_viewport_get_size_constraint
 gtk_viewport_get_type G_GNUC_CONST
 gtk_viewport_get_vadjustment
 gtk_viewport_new
 gtk_viewport_set_hadjustment
 gtk_viewport_set_shadow_type
+gtk_viewport_set_size_constraint
 gtk_viewport_set_vadjustment
 #endif
 #endif
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index eeb3ac7..c8cde2a 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -413,6 +413,14 @@ typedef enum
   GTK_UPDATE_DELAYED
 } GtkUpdateType;
 
+/* Viewport flags to constrain width or height */
+typedef enum
+{
+  GTK_VIEWPORT_CONSTRAIN_NONE,
+  GTK_VIEWPORT_CONSTRAIN_WIDTH,
+  GTK_VIEWPORT_CONSTRAIN_HEIGHT
+} GtkViewportConstraint;
+
 /* Generic visibility flags */
 typedef enum
 {
diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c
index 114415b..c504f33 100644
--- a/gtk/gtkviewport.c
+++ b/gtk/gtkviewport.c
@@ -28,6 +28,7 @@
 #include "gtkviewport.h"
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
+#include "gtkextendedlayout.h"
 #include "gtkprivate.h"
 #include "gtkalias.h"
 
@@ -35,7 +36,8 @@ enum {
   PROP_0,
   PROP_HADJUSTMENT,
   PROP_VADJUSTMENT,
-  PROP_SHADOW_TYPE
+  PROP_SHADOW_TYPE,
+  PROP_SIZE_CONSTRAINT
 };
 
 
@@ -125,6 +127,15 @@ gtk_viewport_class_init (GtkViewportClass *class)
 						      GTK_SHADOW_IN,
 						      GTK_PARAM_READWRITE));
 
+  g_object_class_install_property (gobject_class,
+                                   PROP_SIZE_CONSTRAINT,
+                                   g_param_spec_enum ("size-constraint",
+						      P_("Size constraint"),
+						      P_("Determines whether the viewport constrains the width or height of its child"),
+						      GTK_TYPE_VIEWPORT_CONSTRAINT,
+						      GTK_VIEWPORT_CONSTRAIN_NONE,
+						      GTK_PARAM_READWRITE));
+
   widget_class->set_scroll_adjustments_signal =
     g_signal_new (I_("set_scroll_adjustments"),
 		  G_OBJECT_CLASS_TYPE (gobject_class),
@@ -158,6 +169,9 @@ gtk_viewport_set_property (GObject         *object,
     case PROP_SHADOW_TYPE:
       gtk_viewport_set_shadow_type (viewport, g_value_get_enum (value));
       break;
+    case PROP_SIZE_CONSTRAINT:
+      gtk_viewport_set_size_constraint (viewport, g_value_get_enum (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -185,6 +199,9 @@ gtk_viewport_get_property (GObject         *object,
     case PROP_SHADOW_TYPE:
       g_value_set_enum (value, viewport->shadow_type);
       break;
+    case PROP_SIZE_CONSTRAINT:
+      g_value_set_enum (value, viewport->size_constraint);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -200,6 +217,8 @@ gtk_viewport_init (GtkViewport *viewport)
   gtk_container_set_resize_mode (GTK_CONTAINER (viewport), GTK_RESIZE_QUEUE);
   
   viewport->shadow_type = GTK_SHADOW_IN;
+  viewport->size_constraint = GTK_VIEWPORT_CONSTRAIN_NONE;
+
   viewport->view_window = NULL;
   viewport->bin_window = NULL;
   viewport->hadjustment = NULL;
@@ -348,6 +367,50 @@ viewport_reclamp_adjustment (GtkAdjustment *adjustment,
 }
 
 static void
+viewport_child_size_request (GtkViewport   	  *viewport,
+			     GtkWidget     	  *child,
+			     GtkRequisition	  *requisition,
+			     GtkChildSizeRequest   size_request_func)
+{
+  GtkExtendedLayoutFeatures features = 0;
+  gboolean width_for_height;
+  gboolean height_for_width;
+ 
+  if (GTK_IS_EXTENDED_LAYOUT (child))
+    features = gtk_extended_layout_get_features ((GtkExtendedLayout*) child);
+
+  width_for_height = (viewport->size_constraint == GTK_VIEWPORT_CONSTRAIN_HEIGHT &&
+		      (features & GTK_EXTENDED_LAYOUT_WIDTH_FOR_HEIGHT));
+  height_for_width = (viewport->size_constraint == GTK_VIEWPORT_CONSTRAIN_WIDTH &&
+		      (features & GTK_EXTENDED_LAYOUT_HEIGHT_FOR_WIDTH));
+
+  if (height_for_width || width_for_height)
+    {
+      GtkAllocation view_allocation;
+      viewport_get_view_allocation (viewport, &view_allocation);
+      if (height_for_width)
+        {
+          requisition->width = view_allocation.width;
+          requisition->height = gtk_extended_layout_get_height_for_width (
+            (GtkExtendedLayout*) child, view_allocation.width);
+        }
+
+      else
+        {
+          requisition->width = gtk_extended_layout_get_width_for_height (
+            (GtkExtendedLayout*) child, view_allocation.height);
+          requisition->height = view_allocation.height;
+        }
+    }
+
+  else if (features & GTK_EXTENDED_LAYOUT_NATURAL_SIZE)
+    gtk_extended_layout_get_natural_size ((GtkExtendedLayout*) child, requisition);
+
+  else 
+    size_request_func (child, requisition, (GtkWidget *) viewport);
+}
+
+static void
 viewport_set_hadjustment_values (GtkViewport *viewport,
 				 gboolean    *value_changed)
 {
@@ -373,7 +436,8 @@ viewport_set_hadjustment_values (GtkViewport *viewport,
     {
       GtkRequisition child_requisition;
       
-      gtk_widget_get_child_requisition (bin->child, &child_requisition);
+      viewport_child_size_request (viewport, bin->child, &child_requisition,
+				   (GtkChildSizeRequest) gtk_widget_get_child_requisition);
       hadjustment->upper = MAX (child_requisition.width, view_allocation.width);
     }
   else
@@ -410,7 +474,8 @@ viewport_set_vadjustment_values (GtkViewport *viewport,
     {
       GtkRequisition child_requisition;
       
-      gtk_widget_get_child_requisition (bin->child, &child_requisition);
+      viewport_child_size_request (viewport, bin->child, &child_requisition,
+				   (GtkChildSizeRequest) gtk_widget_get_child_requisition);
       vadjustment->upper = MAX (child_requisition.height, view_allocation.height);
     }
   else
@@ -547,6 +612,45 @@ gtk_viewport_get_shadow_type (GtkViewport *viewport)
   return viewport->shadow_type;
 }
 
+
+/** 
+ * gtk_viewport_set_size_constraint:
+ * @viewport: a #GtkViewport.
+ * @type: the new size constraint.
+ *
+ * Sets the size constraint of the viewport.
+ **/ 
+void
+gtk_viewport_set_size_constraint (GtkViewport   *viewport,
+			          GtkViewportConstraint  type)
+{
+  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
+
+  if ((GtkViewportConstraint) viewport->size_constraint != type)
+    {
+      viewport->size_constraint = type;
+      gtk_widget_queue_resize (GTK_WIDGET (viewport));
+      g_object_notify (G_OBJECT (viewport), "size-constraint");
+    }
+}
+
+/**
+ * gtk_viewport_get_size_constraint:
+ * @viewport: a #GtkViewport
+ *
+ * Gets the shadow type of the #GtkViewport. See
+ * gtk_viewport_set_size_constraint().
+ 
+ * Return value: the size constraint
+ **/
+GtkViewportConstraint
+gtk_viewport_get_size_constraint (GtkViewport *viewport)
+{
+  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), GTK_VIEWPORT_CONSTRAIN_NONE);
+
+  return viewport->size_constraint;
+}
+
 static void
 gtk_viewport_realize (GtkWidget *widget)
 {
@@ -720,7 +824,10 @@ gtk_viewport_size_request (GtkWidget      *widget,
 
   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
     {
-      gtk_widget_size_request (bin->child, &child_requisition);
+      viewport_child_size_request (GTK_VIEWPORT (widget), bin->child,
+				   &child_requisition,
+				   (GtkChildSizeRequest) gtk_widget_size_request);
+
       requisition->width += child_requisition.width;
       requisition->height += child_requisition.height;
     }
diff --git a/gtk/gtkviewport.h b/gtk/gtkviewport.h
index 8b64f17..b07382a 100644
--- a/gtk/gtkviewport.h
+++ b/gtk/gtkviewport.h
@@ -51,7 +51,9 @@ struct _GtkViewport
 {
   GtkBin bin;
 
-  GtkShadowType shadow_type;
+  guint shadow_type : 3;
+  guint size_constraint : 2;
+
   GdkWindow *view_window;
   GdkWindow *bin_window;
   GtkAdjustment *hadjustment;
@@ -68,18 +70,21 @@ struct _GtkViewportClass
 };
 
 
-GType          gtk_viewport_get_type        (void) G_GNUC_CONST;
-GtkWidget*     gtk_viewport_new             (GtkAdjustment *hadjustment,
-					     GtkAdjustment *vadjustment);
-GtkAdjustment* gtk_viewport_get_hadjustment (GtkViewport   *viewport);
-GtkAdjustment* gtk_viewport_get_vadjustment (GtkViewport   *viewport);
-void           gtk_viewport_set_hadjustment (GtkViewport   *viewport,
-					     GtkAdjustment *adjustment);
-void           gtk_viewport_set_vadjustment (GtkViewport   *viewport,
-					     GtkAdjustment *adjustment);
-void           gtk_viewport_set_shadow_type (GtkViewport   *viewport,
-					     GtkShadowType  type);
-GtkShadowType  gtk_viewport_get_shadow_type (GtkViewport   *viewport);
+GType                 gtk_viewport_get_type            (void) G_GNUC_CONST;
+GtkWidget*            gtk_viewport_new                 (GtkAdjustment *hadjustment,
+							GtkAdjustment *vadjustment);
+GtkAdjustment*        gtk_viewport_get_hadjustment     (GtkViewport   *viewport);
+GtkAdjustment*        gtk_viewport_get_vadjustment     (GtkViewport   *viewport);
+void                  gtk_viewport_set_hadjustment     (GtkViewport   *viewport,
+							GtkAdjustment *adjustment);
+void                  gtk_viewport_set_vadjustment     (GtkViewport   *viewport,
+							GtkAdjustment *adjustment);
+void                  gtk_viewport_set_shadow_type     (GtkViewport   *viewport,
+							GtkShadowType  type);
+GtkShadowType         gtk_viewport_get_shadow_type     (GtkViewport   *viewport);
+void                  gtk_viewport_set_size_constraint (GtkViewport   *viewport,
+							GtkViewportConstraint  type);
+GtkViewportConstraint gtk_viewport_get_size_constraint (GtkViewport   *viewport);
 
 
 G_END_DECLS
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 99c19e6..1338dd8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -45,6 +45,7 @@ noinst_PROGRAMS =			\
 	testellipsise			\
 	testentrycompletion 		\
 	testextendedlayout 		\
+	testextlayoutviewport 		\
 	testfilechooser			\
 	testfilechooserbutton		\
 	testgtk				\
@@ -111,6 +112,7 @@ testdnd_DEPENDENCIES = $(TEST_DEPS)
 testellipsise_DEPENDENCIES = $(TEST_DEPS)
 testentrycompletion_DEPENDENCIES = $(TEST_DEPS)
 testextendedlayout_DEPENDENCIES = $(TEST_DEPS)
+testextlayoutviewport_DEPENDENCIES = $(TEST_DEPS)
 testfilechooser_DEPENDENCIES = $(TEST_DEPS)
 testfilechooserbutton_DEPENDENCIES = $(TEST_DEPS)
 testgtk_DEPENDENCIES = $(TEST_DEPS)
@@ -167,6 +169,7 @@ testdnd_LDADD = $(LDADDS)
 testellipsise_LDADD = $(LDADDS)
 testentrycompletion_LDADD = $(LDADDS)
 testextendedlayout_LDADD = $(LDADDS)
+testextlayoutviewport_LDADD = $(LDADDS)
 testfilechooser_LDADD = $(LDADDS)
 testfilechooserbutton_LDADD = $(LDADDS)
 testgtk_LDADD = $(LDADDS)
@@ -230,6 +234,9 @@ testentrycompletion_SOURCES = 	\
 testextendedlayout_SOURCES = 	\
 	testextendedlayout.c
 
+testextlayoutviewport_SOURCES = 	\
+	testextlayoutviewport.c
+
 testfilechooser_SOURCES = 	\
 	prop-editor.c		\
 	testfilechooser.c 	
diff --git a/tests/testextlayoutviewport.c b/tests/testextlayoutviewport.c
new file mode 100644
index 0000000..724e816
--- /dev/null
+++ b/tests/testextlayoutviewport.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ * Author: Paolo Bonzini <bonzini gnu org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <gtk/gtk.h>
+
+static void
+option_cb (GtkToggleButton *option,
+	   GtkWidget *viewport)
+{
+  gboolean active = gtk_toggle_button_get_active (option);
+
+  gtk_viewport_set_size_constraint (GTK_VIEWPORT (viewport),
+				    active ? GTK_VIEWPORT_CONSTRAIN_HEIGHT
+					   : GTK_VIEWPORT_CONSTRAIN_WIDTH);
+
+  gtk_label_set_angle (GTK_LABEL (gtk_bin_get_child (GTK_BIN (viewport))),
+		       active ? 90 : 0);
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+  GtkWidget *window;
+  GtkWidget *scrolled_window, *viewport, *label, *vbox, *option;
+  
+  gtk_init (&argc, &argv);
+  
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (G_OBJECT (window), "delete-event",
+		    G_CALLBACK (gtk_main_quit), NULL);
+  
+  vbox = gtk_vbox_new (FALSE, 4);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  
+  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+  
+  viewport = gtk_viewport_new (NULL, NULL);
+  gtk_viewport_set_size_constraint (GTK_VIEWPORT (viewport),
+				    GTK_VIEWPORT_CONSTRAIN_WIDTH);
+  gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
+  
+#define STR "This is a test %# This is a test % # This is a test % #$ "
+  label = gtk_label_new (STR STR STR STR STR STR STR STR STR STR STR STR STR
+			 STR STR STR STR STR STR STR STR STR STR STR STR STR
+			 STR STR STR STR STR STR STR STR STR STR STR STR STR
+			 STR STR STR STR STR STR STR STR STR STR STR STR STR);
+
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_label_set_full_size (GTK_LABEL (label), TRUE);
+  gtk_misc_set_alignment (&(GTK_LABEL (label)->misc), 0.0, 0.0);
+  gtk_container_add (GTK_CONTAINER (viewport), label);
+
+  option = gtk_check_button_new_with_label ("Horizontal scrollbar");
+  g_signal_connect (G_OBJECT (option), "toggled", G_CALLBACK (option_cb), viewport);
+  
+  gtk_box_pack_end (GTK_BOX (vbox), option, FALSE, FALSE, 0);
+  
+  gtk_widget_show_all (window);
+  gtk_main ();
+  return 0;
+}
-- 
1.5.5



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]