[gtksourceview/wip/compact-completion: 10/10] CompletionContainer: for the GtkTreeView sizing



commit 58670e13f054c5ea1ff5631126dc10876388cf2f
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Mon Apr 29 18:17:35 2013 +0200

    CompletionContainer: for the GtkTreeView sizing
    
    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.
    
    Note: gtk_builder_expose_object() is used, so GTK+ 3.8.0 is required (I don't
    know whether 3.7.12 is sufficient).

 configure.ac                                 |    2 +-
 docs/reference/Makefile.am                   |    1 +
 gtksourceview/Makefile.am                    |    2 +
 gtksourceview/gtksourcecompletion.c          |   22 ++-
 gtksourceview/gtksourcecompletion.ui         |    2 +-
 gtksourceview/gtksourcecompletioncontainer.c |  263 ++++++++++++++++++++++++++
 gtksourceview/gtksourcecompletioncontainer.h |   61 ++++++
 gtksourceview/gtksourcetypes-private.h       |    1 +
 po/POTFILES.in                               |    1 +
 9 files changed, 345 insertions(+), 10 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index ec2b0d9..fea9f5e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,7 +60,7 @@ AC_CHECK_HEADERS([unistd.h])
 GLIB_REQUIRED_VERSION=2.34.0
 GLIB_REQUIRED_VERSION_MACRO=GLIB_VERSION_2_34
 
-GTK_REQUIRED_VERSION=3.7.12
+GTK_REQUIRED_VERSION=3.8.0
 GDK_REQUIRED_VERSION_MACRO=GDK_VERSION_3_8
 
 LIBXML_REQUIRED_VERSION=2.6.0
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 0ca15ae..0ee0152 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -21,6 +21,7 @@ CFILE_GLOB = $(top_srcdir)/gtksourceview/*.c
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
 IGNORE_HFILES =                                        \
        config.h                                \
+       gtksourcecompletioncontainer.h          \
        gtksourcecompletionmodel.h              \
        gtksourcecompletion-private.h           \
        gtksourcecompletionwordsbuffer.h        \
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index bf91768..ab68829 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -46,6 +46,7 @@ libgtksourceview_headers =                    \
        gtksourceview.h
 
 libgtksourceview_private_headers = \
+       gtksourcecompletioncontainer.h          \
        gtksourcecompletionmodel.h              \
        gtksourcecompletion-private.h           \
        gtksourcecontextengine.h                \
@@ -65,6 +66,7 @@ libgtksourceview_private_headers = \
        gtktextregion.h
 
 libgtksourceview_private_c_files = \
+       gtksourcecompletioncontainer.c  \
        gtksourcecompletionmodel.c      \
        gtksourcecontextengine.c        \
        gtksourceengine.c               \
diff --git a/gtksourceview/gtksourcecompletion.c b/gtksourceview/gtksourcecompletion.c
index 7e454d5..40b94b3 100644
--- a/gtksourceview/gtksourcecompletion.c
+++ b/gtksourceview/gtksourcecompletion.c
@@ -81,14 +81,12 @@
 #include "gtksourcecompletioninfo.h"
 #include "gtksourcecompletionproposal.h"
 #include "gtksourcecompletionprovider.h"
+#include "gtksourcecompletioncontainer.h"
 #include "gtksourcebuffer.h"
 #include "gtksourceview.h"
 #include "gtksourceview-marshal.h"
 #include "gtksourceview-i18n.h"
 
-#define WINDOW_WIDTH 350
-#define WINDOW_HEIGHT 200
-
 #define GTK_SOURCE_COMPLETION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object),\
                                                  GTK_SOURCE_TYPE_COMPLETION,           \
                                                  GtkSourceCompletionPrivate))
@@ -2250,10 +2248,6 @@ init_main_window (GtkSourceCompletion *completion,
        gtk_window_set_attached_to (GTK_WINDOW (completion->priv->main_window),
                                    GTK_WIDGET (completion->priv->view));
 
-       gtk_widget_set_size_request (GTK_WIDGET (completion->priv->main_window),
-                                    WINDOW_WIDTH,
-                                    WINDOW_HEIGHT);
-
        g_signal_connect_after (completion->priv->main_window,
                                "configure-event",
                                G_CALLBACK (gtk_source_completion_configure_event),
@@ -2300,21 +2294,33 @@ init_info_window (GtkSourceCompletion *completion)
 static void
 gtk_source_completion_init (GtkSourceCompletion *completion)
 {
+       GError *error = NULL;
        GtkBuilder *builder = gtk_builder_new ();
+       GtkSourceCompletionContainer *container = _gtk_source_completion_container_new ();
+       g_object_ref_sink (container);
 
        completion->priv = GTK_SOURCE_COMPLETION_GET_PRIVATE (completion);
 
        gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
 
+       /* GtkSourceCompletionContainer is a private type. */
+       gtk_builder_expose_object (builder, "completion_container", G_OBJECT (container));
+
        gtk_builder_add_from_resource (builder,
                                       "/org/gnome/gtksourceview/ui/gtksourcecompletion.ui",
-                                      NULL);
+                                      &error);
+
+       if (error != NULL)
+       {
+               g_error ("Error while loading the completion UI: %s", error->message);
+       }
 
        init_tree_view (completion, builder);
        init_main_window (completion, builder);
        init_info_window (completion);
 
        g_object_unref (builder);
+       g_object_unref (container);
 }
 
 void
diff --git a/gtksourceview/gtksourcecompletion.ui b/gtksourceview/gtksourcecompletion.ui
index 5d869be..710af40 100644
--- a/gtksourceview/gtksourcecompletion.ui
+++ b/gtksourceview/gtksourcecompletion.ui
@@ -45,7 +45,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
         <property name="visible">True</property>
         <property name="orientation">vertical</property>
         <child>
-          <object class="GtkScrolledWindow" id="scrolled_window_completion">
+          <object class="GtkSourceCompletionContainer" id="completion_container">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <child>
diff --git a/gtksourceview/gtksourcecompletioncontainer.c b/gtksourceview/gtksourcecompletioncontainer.c
new file mode 100644
index 0000000..3680324
--- /dev/null
+++ b/gtksourceview/gtksourcecompletioncontainer.c
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcecompletioncontainer.c
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ */
+
+/*
+ * 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.
+ *
+ * The purpose is to have a compact completion window, with a certain size
+ * limit.
+ */
+
+#include "gtksourcecompletioncontainer.h"
+
+#define MAX_WIDTH  350
+#define MAX_HEIGHT 200
+
+struct _GtkSourceCompletionContainerPrivate
+{
+       /* The implementation assumes that the child doesn't need a viewport
+        * when it is added to the scrolled window. */
+       GtkWidget *child;
+       GtkWidget *scrolled_window;
+};
+
+G_DEFINE_TYPE (GtkSourceCompletionContainer, _gtk_source_completion_container, GTK_TYPE_BIN);
+
+#define GTK_SOURCE_COMPLETION_CONTAINER_GET_PRIVATE(object)                    \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((object),                                 \
+                                     GTK_SOURCE_TYPE_COMPLETION_CONTAINER,     \
+                                     GtkSourceCompletionContainerPrivate))
+
+/* 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)
+{
+       gint width;
+       GtkWidget *scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, NULL);
+       g_object_ref_sink (scrollbar);
+       gtk_widget_show (scrollbar);
+
+       gtk_widget_get_preferred_width (scrollbar, NULL, &width);
+
+       g_object_unref (scrollbar);
+
+       return width;
+}
+
+static gint
+get_horizontal_scrollbar_height (void)
+{
+       gint height;
+       GtkWidget *scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, NULL);
+       g_object_ref_sink (scrollbar);
+       gtk_widget_show (scrollbar);
+
+       gtk_widget_get_preferred_height (scrollbar, NULL, &height);
+
+       g_object_unref (scrollbar);
+
+       return height;
+}
+
+static void
+remove_scrolled_window (GtkSourceCompletionContainer *container)
+{
+       if (gtk_widget_get_parent (container->priv->child) != GTK_WIDGET (container))
+       {
+               gtk_container_remove (GTK_CONTAINER (container),
+                                     container->priv->scrolled_window);
+
+               gtk_container_remove (GTK_CONTAINER (container->priv->scrolled_window),
+                                     container->priv->child);
+
+               bin_container_add (GTK_CONTAINER (container),
+                                  container->priv->child);
+       }
+}
+
+static void
+add_scrolled_window (GtkSourceCompletionContainer *container)
+{
+       if (gtk_widget_get_parent (container->priv->child) != container->priv->scrolled_window)
+       {
+               gtk_container_remove (GTK_CONTAINER (container),
+                                     container->priv->child);
+
+               gtk_container_add (GTK_CONTAINER (container->priv->scrolled_window),
+                                  container->priv->child);
+
+               bin_container_add (GTK_CONTAINER (container),
+                                  container->priv->scrolled_window);
+       }
+}
+
+static void
+check_scrolled_window (GtkSourceCompletionContainer *container,
+                      GtkRequisition                child_size)
+{
+       if (child_size.width <= MAX_WIDTH &&
+           child_size.height <= MAX_HEIGHT)
+       {
+               remove_scrolled_window (container);
+       }
+       else
+       {
+               add_scrolled_window (container);
+       }
+}
+
+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)
+{
+       GtkRequisition nat_size;
+       gint width;
+       GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (widget);
+
+       gtk_widget_get_preferred_size (container->priv->child, 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, MAX_WIDTH);
+
+       if (min_width != NULL)
+       {
+               *min_width = width;
+       }
+
+       if (nat_width != NULL)
+       {
+               *nat_width = width;
+       }
+}
+
+static void
+_gtk_source_completion_container_get_preferred_height (GtkWidget *widget,
+                                                      gint      *min_height,
+                                                      gint      *nat_height)
+{
+       GtkRequisition nat_size;
+       gint height;
+       GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (widget);
+
+       gtk_widget_get_preferred_size (container->priv->child, NULL, &nat_size);
+       check_scrolled_window (container, nat_size);
+
+       height = nat_size.height;
+
+       if (MAX_WIDTH < nat_size.width)
+       {
+               height += get_horizontal_scrollbar_height ();
+       }
+
+       height = MIN (height, MAX_HEIGHT);
+
+       if (min_height != NULL)
+       {
+               *min_height = height;
+       }
+
+       if (nat_height != NULL)
+       {
+               *nat_height = height;
+       }
+}
+
+static void
+_gtk_source_completion_container_add (GtkContainer *gtk_container,
+                                     GtkWidget    *widget)
+{
+       GtkSourceCompletionContainer *container = GTK_SOURCE_COMPLETION_CONTAINER (gtk_container);
+
+       g_clear_object (&container->priv->child);
+       container->priv->child = g_object_ref (widget);
+
+       bin_container_add (gtk_container, widget);
+}
+
+static void
+_gtk_source_completion_container_init (GtkSourceCompletionContainer *container)
+{
+       container->priv = GTK_SOURCE_COMPLETION_CONTAINER_GET_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->child);
+
+       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;
+
+       g_type_class_add_private (object_class, sizeof (GtkSourceCompletionContainerPrivate));
+}
+
+GtkSourceCompletionContainer *
+_gtk_source_completion_container_new (void)
+{
+       return g_object_new (GTK_SOURCE_TYPE_COMPLETION_CONTAINER, NULL);
+}
diff --git a/gtksourceview/gtksourcecompletioncontainer.h b/gtksourceview/gtksourcecompletioncontainer.h
new file mode 100644
index 0000000..5e44ae1
--- /dev/null
+++ b/gtksourceview/gtksourcecompletioncontainer.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
+ * gtksourcecompletioncontainer.h
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ */
+
+#ifndef __GTK_SOURCE_COMPLETION_CONTAINER_H__
+#define __GTK_SOURCE_COMPLETION_CONTAINER_H__
+
+#include <gtk/gtk.h>
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_COMPLETION_CONTAINER             (_gtk_source_completion_container_get_type ())
+#define GTK_SOURCE_COMPLETION_CONTAINER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GTK_SOURCE_TYPE_COMPLETION_CONTAINER, GtkSourceCompletionContainer))
+#define GTK_SOURCE_COMPLETION_CONTAINER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
GTK_SOURCE_TYPE_COMPLETION_CONTAINER, GtkSourceCompletionContainerClass)
+#define GTK_SOURCE_IS_COMPLETION_CONTAINER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GTK_SOURCE_TYPE_COMPLETION_CONTAINER))
+#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;
+};
+
+struct _GtkSourceCompletionContainerClass
+{
+       GtkBinClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType           _gtk_source_completion_container_get_type              (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkSourceCompletionContainer *
+                _gtk_source_completion_container_new                   (void);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_COMPLETION_CONTAINER_H__ */
diff --git a/gtksourceview/gtksourcetypes-private.h b/gtksourceview/gtksourcetypes-private.h
index 475b294..6b88c2c 100644
--- a/gtksourceview/gtksourcetypes-private.h
+++ b/gtksourceview/gtksourcetypes-private.h
@@ -26,6 +26,7 @@
 
 G_BEGIN_DECLS
 
+typedef struct _GtkSourceCompletionContainer   GtkSourceCompletionContainer;
 typedef struct _GtkSourceCompletionModel       GtkSourceCompletionModel;
 typedef struct _GtkSourceContextEngine         GtkSourceContextEngine;
 typedef struct _GtkSourceEngine                        GtkSourceEngine;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8273b73..7143d65 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -110,6 +110,7 @@ data/styles/tango.xml
 gtksourceview/completion-providers/words/gtksourcecompletionwords.c
 gtksourceview/gtksourcebuffer.c
 gtksourceview/gtksourcecompletion.c
+gtksourceview/gtksourcecompletioncontainer.c
 gtksourceview/gtksourcecompletioncontext.c
 gtksourceview/gtksourcecompletioninfo.c
 gtksourceview/gtksourcecompletionitem.c


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