[gtksourceview/wip/fix-completion-sizing-2] CompletionContainer sizing fixes



commit b37c7dbbb00c7c9e710c5a4b0ee7d4a9eb38830d
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Mon Jun 2 19:31:23 2014 +0200

    CompletionContainer sizing fixes
    
    The previous implementation subclassed GtkBin and added/removed the
    scrolled window during the size requisition, which is probably one of
    the problem. Now the CompletionContainer is a subclass of
    GtkScrolledWindow, so the scrolled window is always there, with an
    automatic policy.
    
    Another source of bug is that the code to know whether a
    scrollbar is needed was buggy and not consistent between
    get_preferred_width() and get_preferred_height(). It should now be
    fixed.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=720823

 gtksourceview/gtksourcecompletioncontainer.c |  233 +++++++-------------------
 gtksourceview/gtksourcecompletioncontainer.h |    7 +-
 2 files changed, 65 insertions(+), 175 deletions(-)
---
diff --git a/gtksourceview/gtksourcecompletioncontainer.c b/gtksourceview/gtksourcecompletioncontainer.c
index 2a305f8..8a81442 100644
--- a/gtksourceview/gtksourcecompletioncontainer.c
+++ b/gtksourceview/gtksourcecompletioncontainer.c
@@ -2,7 +2,7 @@
 /* gtksourcecompletioncontainer.c
  * This file is part of GtkSourceView
  *
- * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ * Copyright (C) 2013, 2014 - Sébastien Wilmet <swilmet gnome org>
  *
  * GtkSourceView is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,14 +20,11 @@
  */
 
 /*
- * Custom container for the sizing of the GtkTreeView containing the completion
- * proposals. When the GtkTreeView exceeds a certain size, the container adds
- * the GtkTreeView inside a scrolled window. When the GtkTreeView is small
- * enough, no scrolled window is needed, and the container fits the natural size
- * of the GtkTreeView.
- *
- * If the tree view is always in the scrolled window, there are sometimes some
- * sizing issues.
+ * Custom sizing of the scrolled window containing the GtkTreeView containing
+ * the completion proposals. If the GtkTreeView is small enough, the scrolled
+ * window returns the natural size of the GtkTreeView. If it exceeds a certain
+ * size, the scrolled window returns a smaller size, with the height at a row
+ * boundary of the GtkTreeView (plus the size of the scrollbar(s) if needed).
  *
  * The purpose is to have a compact completion window, with a certain size
  * limit.
@@ -38,13 +35,9 @@
 #define UNREALIZED_WIDTH  350
 #define MAX_HEIGHT        180
 
-struct _GtkSourceCompletionContainerPrivate
-{
-       GtkTreeView *tree_view;
-       GtkWidget *scrolled_window;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceCompletionContainer, _gtk_source_completion_container, GTK_TYPE_BIN);
+G_DEFINE_TYPE (GtkSourceCompletionContainer,
+              _gtk_source_completion_container,
+              GTK_TYPE_SCROLLED_WINDOW);
 
 static gint
 get_max_width (GtkSourceCompletionContainer *container)
@@ -70,14 +63,6 @@ get_max_width (GtkSourceCompletionContainer *container)
        return UNREALIZED_WIDTH;
 }
 
-/* gtk_container_add() is overridden. This function calls the GtkBin's add(). */
-static void
-bin_container_add (GtkContainer *container,
-                  GtkWidget    *widget)
-{
-       GTK_CONTAINER_CLASS (_gtk_source_completion_container_parent_class)->add (container, widget);
-}
-
 static gint
 get_vertical_scrollbar_width (void)
 {
@@ -89,7 +74,6 @@ get_vertical_scrollbar_width (void)
        gtk_widget_get_preferred_width (scrollbar, NULL, &width);
 
        g_object_unref (scrollbar);
-
        return width;
 }
 
@@ -104,95 +88,61 @@ get_horizontal_scrollbar_height (void)
        gtk_widget_get_preferred_height (scrollbar, NULL, &height);
 
        g_object_unref (scrollbar);
-
        return height;
 }
 
-static void
-remove_scrolled_window (GtkSourceCompletionContainer *container)
+/* This condition is used at several places, and it is important that it is the
+ * same condition. So a function is better.
+ */
+static gboolean
+needs_vertical_scrollbar (gint child_natural_height)
 {
-       GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (container->priv->tree_view));
-
-       if (parent != GTK_WIDGET (container))
-       {
-               gtk_container_remove (GTK_CONTAINER (container),
-                                     container->priv->scrolled_window);
-
-               gtk_container_remove (GTK_CONTAINER (container->priv->scrolled_window),
-                                     GTK_WIDGET (container->priv->tree_view));
-
-               bin_container_add (GTK_CONTAINER (container),
-                                  GTK_WIDGET (container->priv->tree_view));
-       }
+       return MAX_HEIGHT < child_natural_height;
 }
 
 static void
-add_scrolled_window (GtkSourceCompletionContainer *container)
+get_width (GtkSourceCompletionContainer *container,
+          gint                         *container_width,
+          gint                         *child_available_width)
 {
-       GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (container->priv->tree_view));
+       GtkWidget *child;
+       GtkRequisition nat_size;
+       gint width;
+       gint scrollbar_width = 0;
 
-       if (parent != container->priv->scrolled_window)
-       {
-               gtk_container_remove (GTK_CONTAINER (container),
-                                     GTK_WIDGET (container->priv->tree_view));
+       child = gtk_bin_get_child (GTK_BIN (container));
+       gtk_widget_get_preferred_size (child, NULL, &nat_size);
 
-               gtk_container_add (GTK_CONTAINER (container->priv->scrolled_window),
-                                  GTK_WIDGET (container->priv->tree_view));
+       width = nat_size.width;
 
-               bin_container_add (GTK_CONTAINER (container),
-                                  container->priv->scrolled_window);
+       if (needs_vertical_scrollbar (nat_size.height))
+       {
+               scrollbar_width = get_vertical_scrollbar_width ();
+               width += scrollbar_width;
        }
-}
 
-static void
-check_scrolled_window (GtkSourceCompletionContainer *container,
-                      GtkRequisition                child_size)
-{
-       if (child_size.width <= get_max_width (container) &&
-           child_size.height <= MAX_HEIGHT)
+       width = MIN (width, get_max_width (container));
+
+       if (container_width != NULL)
        {
-               remove_scrolled_window (container);
+               *container_width = width;
        }
-       else
+
+       if (child_available_width != NULL)
        {
-               add_scrolled_window (container);
+               *child_available_width = width - scrollbar_width;
        }
 }
 
-static GtkSizeRequestMode
-_gtk_source_completion_container_get_request_mode (GtkWidget *widget)
-{
-       return GTK_SIZE_REQUEST_CONSTANT_SIZE;
-}
-
 static void
 _gtk_source_completion_container_get_preferred_width (GtkWidget *widget,
                                                      gint      *min_width,
                                                      gint      *nat_width)
 {
        GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (widget);
-       GtkRequisition nat_size;
        gint width;
 
-       /* FIXME sometimes the returned height (nat_size.height) is 0. Maybe a
-        * bug in GtkTreeView. If there are sizing problems, or if there are
-        * problems with the scrolled window, a workaround would be to compute
-        * the height manually, like it is done in get_preferred_height() below.
-        */
-       gtk_widget_get_preferred_size (GTK_WIDGET (container->priv->tree_view),
-                                      NULL,
-                                      &nat_size);
-
-       check_scrolled_window (container, nat_size);
-
-       width = nat_size.width;
-
-       if (MAX_HEIGHT < nat_size.height)
-       {
-               width += get_vertical_scrollbar_width ();
-       }
-
-       width = MIN (width, get_max_width (container));
+       get_width (container, &width, NULL);
 
        if (min_width != NULL)
        {
@@ -208,11 +158,15 @@ _gtk_source_completion_container_get_preferred_width (GtkWidget *widget,
 static gint
 get_row_height (GtkSourceCompletionContainer *container)
 {
-       GList *columns = gtk_tree_view_get_columns (container->priv->tree_view);
+       GtkWidget *tree_view;
+       GList *columns;
        GList *l;
        gint max_row_height = 0;
        gint vertical_separator = 0;
 
+       tree_view = gtk_bin_get_child (GTK_BIN (container));
+       columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (tree_view));
+
        for (l = columns; l != NULL; l = l->next)
        {
                GtkTreeViewColumn *column = l->data;
@@ -226,14 +180,13 @@ get_row_height (GtkSourceCompletionContainer *container)
                }
        }
 
-       gtk_widget_style_get (GTK_WIDGET (container->priv->tree_view),
+       gtk_widget_style_get (tree_view,
                              "vertical-separator", &vertical_separator,
                              NULL);
 
        max_row_height += vertical_separator;
 
        g_list_free (columns);
-
        return max_row_height;
 }
 
@@ -244,59 +197,37 @@ _gtk_source_completion_container_get_preferred_height (GtkWidget *widget,
                                                       gint      *nat_height)
 {
        GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (widget);
-       GtkTreeModel *model;
+       GtkWidget *child;
        GtkRequisition nat_size;
-       gint nb_rows = 0;
-       gint row_height = 0;
+       gint total_height;
        gint scrollbar_height = 0;
-       gint total_height = 0;
-       gint ret_height = 0;
-
-       if (min_height != NULL)
-       {
-               *min_height = 0;
-       }
-
-       if (nat_height != NULL)
-       {
-               *nat_height = 0;
-       }
-
-       model = gtk_tree_view_get_model (container->priv->tree_view);
-
-       if (model == NULL)
-       {
-               return;
-       }
+       gint child_available_width;
+       gint ret_height;
 
-       row_height = get_row_height (container);
+       child = gtk_bin_get_child (GTK_BIN (container));
+       gtk_widget_get_preferred_size (child, NULL, &nat_size);
 
-       nb_rows = gtk_tree_model_iter_n_children (model, NULL);
+       total_height = nat_size.height;
 
-       total_height = nb_rows * row_height;
+       get_width (container, NULL, &child_available_width);
 
-       gtk_widget_get_preferred_size (GTK_WIDGET (container->priv->tree_view),
-                                      NULL,
-                                      &nat_size);
-
-       check_scrolled_window (container, nat_size);
-
-       if (get_max_width (container) < nat_size.width)
+       /* Needs horizontal scrollbar */
+       if (child_available_width < nat_size.width)
        {
                scrollbar_height = get_horizontal_scrollbar_height ();
                total_height += scrollbar_height;
        }
 
-       if (total_height <= MAX_HEIGHT)
+       if (needs_vertical_scrollbar (nat_size.height))
        {
-               ret_height = total_height;
+               gint row_height = get_row_height (container);
+               gint nb_rows_allowed = MAX_HEIGHT / row_height;
+
+               ret_height = nb_rows_allowed * row_height + scrollbar_height;
        }
        else
        {
-               gint height_available_for_rows = MAX_HEIGHT - scrollbar_height;
-               gint nb_rows_allowed = height_available_for_rows / row_height;
-
-               ret_height = nb_rows_allowed * row_height + scrollbar_height;
+               ret_height = total_height;
        }
 
        if (min_height != NULL)
@@ -311,55 +242,17 @@ _gtk_source_completion_container_get_preferred_height (GtkWidget *widget,
 }
 
 static void
-_gtk_source_completion_container_add (GtkContainer *gtk_container,
-                                     GtkWidget    *widget)
-{
-       GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (gtk_container);
-
-       g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
-       g_clear_object (&container->priv->tree_view);
-       container->priv->tree_view = GTK_TREE_VIEW (widget);
-       g_object_ref (container->priv->tree_view);
-
-       bin_container_add (gtk_container, widget);
-}
-
-static void
-_gtk_source_completion_container_init (GtkSourceCompletionContainer *container)
-{
-       container->priv = _gtk_source_completion_container_get_instance_private (container);
-
-       container->priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-       g_object_ref_sink (container->priv->scrolled_window);
-       gtk_widget_show (container->priv->scrolled_window);
-}
-
-static void
-_gtk_source_completion_container_finalize (GObject *object)
-{
-       GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (object);
-
-       g_clear_object (&container->priv->scrolled_window);
-       g_clear_object (&container->priv->tree_view);
-
-       G_OBJECT_CLASS (_gtk_source_completion_container_parent_class)->finalize (object);
-}
-
-static void
 _gtk_source_completion_container_class_init (GtkSourceCompletionContainerClass *klass)
 {
-       GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-       GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 
-       object_class->finalize = _gtk_source_completion_container_finalize;
-
-       widget_class->get_request_mode = _gtk_source_completion_container_get_request_mode;
        widget_class->get_preferred_width = _gtk_source_completion_container_get_preferred_width;
        widget_class->get_preferred_height = _gtk_source_completion_container_get_preferred_height;
+}
 
-       container_class->add = _gtk_source_completion_container_add;
+static void
+_gtk_source_completion_container_init (GtkSourceCompletionContainer *container)
+{
 }
 
 GtkSourceCompletionContainer *
diff --git a/gtksourceview/gtksourcecompletioncontainer.h b/gtksourceview/gtksourcecompletioncontainer.h
index 5e44ae1..2c26fa5 100644
--- a/gtksourceview/gtksourcecompletioncontainer.h
+++ b/gtksourceview/gtksourcecompletioncontainer.h
@@ -34,19 +34,16 @@ G_BEGIN_DECLS
 #define GTK_SOURCE_IS_COMPLETION_CONTAINER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GTK_SOURCE_TYPE_COMPLETION_CONTAINER))
 #define GTK_SOURCE_COMPLETION_CONTAINER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GTK_SOURCE_TYPE_COMPLETION_CONTAINER, GtkSourceCompletionContainerClass))
 
-typedef struct _GtkSourceCompletionContainerPrivate    GtkSourceCompletionContainerPrivate;
 typedef struct _GtkSourceCompletionContainerClass      GtkSourceCompletionContainerClass;
 
 struct _GtkSourceCompletionContainer
 {
-       GtkBin parent;
-
-       GtkSourceCompletionContainerPrivate *priv;
+       GtkScrolledWindow parent;
 };
 
 struct _GtkSourceCompletionContainerClass
 {
-       GtkBinClass parent_class;
+       GtkScrolledWindowClass parent_class;
 };
 
 G_GNUC_INTERNAL


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