[gtk+/native-layout-incubator-2] GtkCellRendererText now implements GtkCellSizeRequest and trades width-for-height when wrapping cell



commit 3b1fc8d54f0a06583252fedf89a5a19834cae8e3
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Wed Jun 30 11:22:33 2010 -0400

    GtkCellRendererText now implements GtkCellSizeRequest and trades width-for-height when wrapping cell text.

 gtk/gtkcellrenderertext.c |  200 ++++++++++++++++++++++++++++++++++++++------
 1 files changed, 172 insertions(+), 28 deletions(-)
---
diff --git a/gtk/gtkcellrenderertext.c b/gtk/gtkcellrenderertext.c
index 8060ade..c2df04b 100644
--- a/gtk/gtkcellrenderertext.c
+++ b/gtk/gtkcellrenderertext.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include "gtkcellrenderertext.h"
 #include "gtkeditable.h"
+#include "gtkcellsizerequest.h"
 #include "gtkentry.h"
 #include "gtkmarshalers.h"
 #include "gtkintl.h"
@@ -38,13 +39,6 @@ static void gtk_cell_renderer_text_set_property  (GObject                  *obje
 						  guint                     param_id,
 						  const GValue             *value,
 						  GParamSpec               *pspec);
-static void gtk_cell_renderer_text_get_size   (GtkCellRenderer          *cell,
-					       GtkWidget                *widget,
-					       GdkRectangle             *cell_area,
-					       gint                     *x_offset,
-					       gint                     *y_offset,
-					       gint                     *width,
-					       gint                     *height);
 static void gtk_cell_renderer_text_render     (GtkCellRenderer          *cell,
 					       GdkWindow                *window,
 					       GtkWidget                *widget,
@@ -61,6 +55,21 @@ static GtkCellEditable *gtk_cell_renderer_text_start_editing (GtkCellRenderer
 							      GdkRectangle         *cell_area,
 							      GtkCellRendererState  flags);
 
+static void       gtk_cell_renderer_text_cell_size_request_init (GtkCellSizeRequestIface  *iface);
+static void       gtk_cell_renderer_text_get_width              (GtkCellSizeRequest       *cell,
+							        GtkWidget                 *widget,
+							        gint                      *minimal_size,
+							        gint                      *natural_size);
+static void       gtk_cell_renderer_text_get_height            (GtkCellSizeRequest        *cell,
+							        GtkWidget                 *widget,
+							        gint                      *minimal_size,
+							        gint                      *natural_size);
+static void       gtk_cell_renderer_text_get_height_for_width  (GtkCellSizeRequest        *cell,
+								GtkWidget                 *widget,
+								gint                       width,
+								gint                      *minimum_height,
+								gint                      *natural_height);
+
 enum {
   EDITED,
   LAST_SIGNAL
@@ -150,7 +159,9 @@ struct _GtkCellRendererTextPrivate
   GtkWidget *entry;
 };
 
-G_DEFINE_TYPE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER)
+G_DEFINE_TYPE_WITH_CODE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_SIZE_REQUEST,
+                                                gtk_cell_renderer_text_cell_size_request_init))
 
 static void
 gtk_cell_renderer_text_init (GtkCellRendererText *celltext)
@@ -185,7 +196,6 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
   object_class->get_property = gtk_cell_renderer_text_get_property;
   object_class->set_property = gtk_cell_renderer_text_set_property;
 
-  cell_class->get_size = gtk_cell_renderer_text_get_size;
   cell_class->render = gtk_cell_renderer_text_render;
   cell_class->start_editing = gtk_cell_renderer_text_start_editing;
 
@@ -1362,7 +1372,7 @@ add_attr (PangoAttrList  *attr_list,
 static PangoLayout*
 get_layout (GtkCellRendererText *celltext,
             GtkWidget           *widget,
-            gboolean             will_render,
+            GdkRectangle        *cell_area,
             GtkCellRendererState flags)
 {
   PangoAttrList *attr_list;
@@ -1381,7 +1391,7 @@ get_layout (GtkCellRendererText *celltext,
 
   pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph);
 
-  if (will_render)
+  if (cell_area)
     {
       /* Add options that affect appearance but not size */
       
@@ -1449,7 +1459,12 @@ get_layout (GtkCellRendererText *celltext,
 
   if (priv->wrap_width != -1)
     {
-      pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE);
+      if (cell_area)
+	pango_layout_set_width (layout, 
+				(cell_area->width - GTK_CELL_RENDERER (celltext)->xpad * 2) * PANGO_SCALE);
+      else
+	pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE);
+
       pango_layout_set_wrap (layout, priv->wrap_mode);
     }
   else
@@ -1479,6 +1494,7 @@ get_layout (GtkCellRendererText *celltext,
   return layout;
 }
 
+
 static void
 get_size (GtkCellRenderer *cell,
 	  GtkWidget       *widget,
@@ -1537,7 +1553,7 @@ get_size (GtkCellRenderer *cell,
   if (layout)
     g_object_ref (layout);
   else
-    layout = get_layout (celltext, widget, FALSE, 0);
+    layout = get_layout (celltext, widget, NULL, 0);
 
   pango_layout_get_pixel_extents (layout, NULL, &rect);
 
@@ -1594,20 +1610,6 @@ get_size (GtkCellRenderer *cell,
   g_object_unref (layout);
 }
 
-
-static void
-gtk_cell_renderer_text_get_size (GtkCellRenderer *cell,
-				 GtkWidget       *widget,
-				 GdkRectangle    *cell_area,
-				 gint            *x_offset,
-				 gint            *y_offset,
-				 gint            *width,
-				 gint            *height)
-{
-  get_size (cell, widget, cell_area, NULL,
-	    x_offset, y_offset, width, height);
-}
-
 static void
 gtk_cell_renderer_text_render (GtkCellRenderer      *cell,
 			       GdkDrawable          *window,
@@ -1627,7 +1629,7 @@ gtk_cell_renderer_text_render (GtkCellRenderer      *cell,
 
   priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
 
-  layout = get_layout (celltext, widget, TRUE, flags);
+  layout = get_layout (celltext, widget, cell_area, flags);
   get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL);
 
   if (!cell->sensitive) 
@@ -1930,5 +1932,147 @@ gtk_cell_renderer_text_set_fixed_height_from_font (GtkCellRendererText *renderer
     }
 }
 
+static void
+gtk_cell_renderer_text_cell_size_request_init (GtkCellSizeRequestIface *iface)
+{
+  iface->get_width            = gtk_cell_renderer_text_get_width;
+  iface->get_height           = gtk_cell_renderer_text_get_height;
+  iface->get_height_for_width = gtk_cell_renderer_text_get_height_for_width;
+}
+
+static void
+gtk_cell_renderer_text_get_width (GtkCellSizeRequest *cell,
+				  GtkWidget          *widget,
+				  gint               *minimum_size,
+				  gint               *natural_size)
+{
+  GtkCellRendererTextPrivate *priv;
+  GtkCellRendererText        *celltext;
+  PangoLayout                *layout;
+  PangoContext               *context;
+  PangoFontMetrics           *metrics;
+  PangoRectangle              rect;
+  gint char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width, xpad;
+
+  /* "width-chars" Hard-coded minimum width:
+   *    - minimum size should be MAX (width-chars, strlen ("..."));
+   *    - natural size should be MAX (width-chars, strlen (label->text));
+   *
+   * "wrap-width" User specified natural wrap width
+   *    - minimum size should be MAX (width-chars, 0)
+   *    - natural size should be MIN (wrap-width, strlen (label->text))
+   */
+
+  celltext = GTK_CELL_RENDERER_TEXT (cell);
+  priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
+  xpad = GTK_CELL_RENDERER (cell)->xpad;
+
+  layout = get_layout (celltext, widget, NULL, 0);
+
+  /* Get the layout with the text possibly wrapping at wrap_width */
+  pango_layout_get_pixel_extents (layout, NULL, &rect);
+  guess_width = rect.width;
+
+  /* Fetch the length of the complete unwrapped text */
+  pango_layout_set_width (layout, -1);
+  pango_layout_get_extents (layout, NULL, &rect);
+  text_width = rect.width;
+
+  /* Fetch the average size of a charachter */
+  context = pango_layout_get_context (layout);
+  metrics = pango_context_get_metrics (context, widget->style->font_desc, 
+				       pango_context_get_language (context));
+  
+  char_width = pango_font_metrics_get_approximate_char_width (metrics);
+  digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
+  char_pixels = MAX (char_width, digit_width);
+
+  pango_font_metrics_unref (metrics);
+  g_object_unref (layout);
+
+  /* enforce minimum width for ellipsized labels at ~3 chars */
+  if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE)
+    ellipsize_chars = 3;
+  else
+    ellipsize_chars = 0;
+  
+  if (minimum_size)
+    {
+      if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->width_chars > 0)
+	*minimum_size = 
+	  xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, ellipsize_chars));
+	/* If no width-chars set, minimum for wrapping text will be the wrap-width */
+      else if (priv->wrap_width > -1)
+	*minimum_size = xpad * 2 + rect.x + priv->wrap_width;
+      else
+	*minimum_size = xpad * 2 + rect.x + guess_width;
+    }
+
+  if (natural_size)
+    {
+      if (priv->wrap_width > -1)
+	*natural_size = xpad * 2 + 
+	  MIN (priv->wrap_width, PANGO_PIXELS (text_width));
+      else /* Natural size is full text here regardless of ellipsize */
+	*natural_size = xpad * 2 + 
+	  MAX ((PANGO_PIXELS (char_width) * priv->width_chars), PANGO_PIXELS (text_width));
+    }
+}
+
+static void
+gtk_cell_renderer_text_get_height_for_width (GtkCellSizeRequest *cell,
+					     GtkWidget          *widget,
+					     gint                width,
+					     gint               *minimum_height,
+					     gint               *natural_height)
+{
+  GtkCellRendererTextPrivate *priv;
+  GtkCellRendererText        *celltext;
+  PangoLayout                *layout;
+  gint                        text_height, xpad, ypad;
+
+
+  celltext = GTK_CELL_RENDERER_TEXT (cell);
+  priv = GTK_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
+
+  xpad = GTK_CELL_RENDERER (cell)->xpad;
+  ypad = GTK_CELL_RENDERER (cell)->ypad;
+
+  layout = get_layout (celltext, widget, FALSE, 0);
+
+  pango_layout_set_width (layout, (width - xpad * 2) * PANGO_SCALE);
+  pango_layout_get_pixel_size (layout, NULL, &text_height);
+
+  if (minimum_height)
+    *minimum_height = text_height + ypad * 2;
+
+  if (natural_height)
+    *natural_height = text_height + ypad * 2;
+
+  g_object_unref (layout);
+}
+
+static void
+gtk_cell_renderer_text_get_height (GtkCellSizeRequest *cell,
+				   GtkWidget          *widget,
+				   gint               *minimum_size,
+				   gint               *natural_size)
+{
+  gint min_width;
+
+  /* Thankfully cell renderers dont rotate, so they only have to do
+   * height-for-width and not the opposite. Here we have only to return
+   * the height for the base minimum width of the renderer.
+   *
+   * Note this code path wont be followed by GtkTreeView which is
+   * height-for-width specifically.
+   */
+  gtk_cell_size_request_get_width (cell, widget, &min_width, NULL);
+  gtk_cell_renderer_text_get_height_for_width (cell, widget, min_width,
+					       minimum_size, natural_size);
+}
+
+
+
 #define __GTK_CELL_RENDERER_TEXT_C__
 #include "gtkaliasdef.c"



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