gtk: Added GtkPanedView, a specialized GtkPaned.
authorMatt Birkholz <matt@birkholz.chandler.az.us>
Tue, 29 Jan 2013 19:29:27 +0000 (12:29 -0700)
committerMatt Birkholz <matt@birkholz.chandler.az.us>
Tue, 29 Jan 2013 19:29:27 +0000 (12:29 -0700)
doc/gtk/gtk.texinfo
src/gtk/Makefile-fragment
src/gtk/fix-demo.scm
src/gtk/gtk-shim.h
src/gtk/gtk-widget.scm
src/gtk/gtk.cdecl
src/gtk/gtk.pkg
src/gtk/gtkpanedview.c.stay [new file with mode: 0644]
src/gtk/gtkpanedview.h [new file with mode: 0644]
src/gtk/gtkscrolledview.c.stay
src/gtk/gtkscrolledview.h

index 7bde112e5b77de21e97f972c18c4abbbf59918fb..9d122721b50d40bf6e9907554978d16d7efac70b 100644 (file)
@@ -1576,6 +1576,33 @@ Returns @var{paned}'s first child, or @code{#f} if there is none.
 Returns @var{paned}'s second child, or @code{#f} if there is none.
 @end deffn
 
+@deffn Class <gtk-paned-view>
+A direct subclass of gtk-scrolled-view representing a reference to a
+GtkPanedView.  This is an extension to the Gtks, a specialization of
+GtkPaned that overrides its widget geometry protocol.
+
+A GtkPaned allows the user to shrink a child (or not!), displaying it
+in a smaller area than its minimum size normally allows.  If neither
+child is indicated as the shrinkable one, it is assumed both childen
+can be shrunk.  The geometry implementation completely ignores the
+natural size of the children, sizing and expanding them in proportion
+to their minimum sizes (until the divider's position is set).  It will
+truncate the ``beginning'' of a child that does not fit, displaying
+its ``end'' (per the writing direction).
+
+A GtkPanedView sizes/expands its children according to their natural
+sizes and respects their minimum sizes (while the position of its
+divider is unset, unless indicated as shrinkable).  If neither child
+is allowed to shrink, it is assumed neither child should be shrunk.
+The minimum size of the paned view allows for the minimum sizes of
+both children.
+
+The difference between paned windows and paned viewports can be
+observed by substituting @code{gtk-paned-new} and
+@code{gtk-paned-view-new} in the fix layout demo.  See @bref{Fix
+Demo}.
+@end deffn
+
 @node Gtk Scrolled Window, Scheme Widget, Gtk Paned, API Reference
 @section Gtk Scrolled Window
 
@@ -1610,10 +1637,8 @@ above and to the right.
 
 @deffn Class <gtk-scrolled-view>
 A direct subclass of gtk-scrolled-window representing a reference to a
-GtkScrolledView.
-
-This specialization of GtkScrolledWindow overrides the widget geometry
-protocol to work somewhat differently.
+GtkScrolledView.  This is an extension to the Gtks, a specialization
+of GtkScrolledWindow that overrides its widget geometry protocol.
 
 A GtkScrolledWindow is used to squeeze an overly large widget into a
 smaller space and allow the user to scroll it.  The geometry
@@ -1624,10 +1649,12 @@ size.
 A GtkScrolledView is used to stick scrollbars on a viewport.  Its
 natural size is the natural size of the viewport, plus scrollbars,
 frame, etc.  Using @code{gtk_widget_set_size_request} is unnecessary
-and interferes with resizing.  The difference can be observed by
-replacing @code{gtk-scrolled-view-new} with
-@code{gtk-scrolled-window-new} in the fix layout demo.
-See @bref{Fix Demo}.
+and interferes with resizing.
+
+The difference between a scrolled window and a scrolled viewport can
+be observed by substituting @code{gtk-scrolled-view-new} and
+@code{gtk-scrolled-window-new} in the fix layout demo.  See @bref{Fix
+Demo}.
 @end deffn
 
 @node Scheme Widget, Fix Layout, Gtk Scrolled Window, API Reference
index 1bab067ee351bad940343c7bbf17af64f101e2ea..18c0092d9a92f2a15c05411bc83d6a9be1b9d076 100644 (file)
@@ -59,9 +59,10 @@ install:
                 | ../microcode/scheme --library ../lib --batch-mode` = "c"; \
        then $(MAKE) install-liarc-bundle; fi
 
-gtk-shim.so: gtk-shim.o gtkscrolledview.o scmwidget.o gtkio.o $(SHIM_LOADER)
-       $(LINK_SHIM) gtk-shim.o gtkscrolledview.o scmwidget.o gtkio.o       \
-               `pkg-config --libs gtk+-3.0 gthread-2.0` $(SHIM_LIBS)
+gtk-shim.so: gtk-shim.o gtkpanedview.o gtkscrolledview.o scmwidget.o   \
+            gtkio.o $(SHIM_LOADER)
+       $(LINK_SHIM) gtk-shim.o gtkpanedview.o gtkscrolledview.o scmwidget.o \
+               gtkio.o `pkg-config --libs gtk+-3.0 gthread-2.0` $(SHIM_LIBS)
 
 gtkscrolledview.o: gtkscrolledview.c gtkscrolledview.h
        $(COMPILE_SHIM) `pkg-config --cflags gtk+-3.0` -c gtkscrolledview.c
@@ -69,6 +70,12 @@ gtkscrolledview.o: gtkscrolledview.c gtkscrolledview.h
 gtkscrolledview.c: gtkscrolledview.c.stay
        cp -p gtkscrolledview.c.stay gtkscrolledview.c
 
+gtkpanedview.o: gtkpanedview.c gtkpanedview.h
+       $(COMPILE_SHIM) `pkg-config --cflags gtk+-3.0` -c gtkpanedview.c
+
+gtkpanedview.c: gtkpanedview.c.stay
+       cp -p gtkpanedview.c.stay gtkpanedview.c
+
 scmwidget.o: scmwidget.c scmwidget.h
        $(COMPILE_SHIM) `pkg-config --cflags gtk+-3.0` -c scmwidget.c
 
index 22b7782cc852cc1bc08448ca157884b8c0f878cb..2eb28eed633066388bd989dfa98207850793032d 100644 (file)
@@ -40,17 +40,19 @@ USA.
         (layout1 (let ((l (make-demo-layout 200 200)))
                    (gtk-widget-set-hexpand l #t)
                    (gtk-widget-set-vexpand l #t)
+                   (set-scm-widget-minimum-size! l 40 40)
                    l))
         (layout2 (let ((l (make-demo-layout 200 300)))
                    (gtk-widget-set-hexpand l #t)
                    (gtk-widget-set-vexpand l #t)
+                   (set-scm-widget-minimum-size! l 40 60)
                    l))
-        (paned (gtk-paned-new 'vertical)))
+        (paned (gtk-paned-view-new 'vertical)))
 
     (gtk-container-add scroller1 layout1)
-    (gtk-paned-pack1 paned scroller1 'resize 'shrink)
+    (gtk-paned-pack1 paned scroller1 'resize #f)
     (gtk-container-add scroller2 layout2)
-    (gtk-paned-pack2 paned scroller2 'resize 'shrink)
+    (gtk-paned-pack2 paned scroller2 'resize #f)
     (gtk-container-add window paned)
     (gtk-widget-show-all window)
 
index 3c337542f0c1df6a1cb99351a73eb2f1c30ed73b..c80eb840d0aca088cd2376cf25238aa4b15ffcb7 100644 (file)
@@ -30,6 +30,7 @@ USA.
 
 #include <gtk/gtk.h>
 #include "scmwidget.h"
+#include "gtkpanedview.h"
 #include "gtkscrolledview.h"
 
 typedef unsigned int uint;
index c6bd4f5b791aa86e9fe959759e7e31805e096e35..90647d5da28aa6866fb62b9871119d1699d88191 100644 (file)
@@ -718,7 +718,7 @@ USA.
           operator))))
 
 (define-class (<gtk-scrolled-view> (constructor ()))
-  (<gtk-container>))
+  (<gtk-scrolled-window>))
 
 (define-guarantee gtk-scrolled-view "a <gtk-scrolled-view>")
 
@@ -733,19 +733,20 @@ USA.
 \f
 ;;; GtkPaneds
 
-(define-class (<gtk-paned> (constructor gtk-paned-new () (orientation)))
+(define-class (<gtk-paned> (constructor ()))
     (<gtk-container>)
   (child1 define standard accessor gtk-paned-get-child1 initial-value #f)
   (child2 define standard accessor gtk-paned-get-child2 initial-value #f))
 
-(define-method initialize-instance ((paned <gtk-paned>) orientation)
-  (call-next-method paned)
-  (let ((alien (gobject-alien paned))
-       (orient (->gtk-orientation orientation 'gtk-paned-new)))
-    (C-call "gtk_paned_new" alien orient)
-    (error-if-null alien "Could not create:" paned orient)
-    (C-call "g_object_ref_sink" alien alien))
-  (set-gtk-widget-destroy-callback! paned))
+(define (gtk-paned-new orientation)
+  (let ((orient (->gtk-orientation orientation 'gtk-paned-new))
+       (paned (make-gtk-paned)))
+    (let ((alien (gobject-alien paned)))
+      (C-call "gtk_paned_new" alien orient)
+      (error-if-null alien "Could not create:" paned orient)
+      (C-call "g_object_ref_sink" alien alien))
+    (set-gtk-widget-destroy-callback! paned)
+    paned))
 
 (define (gtk-paned-pack1 paned child1 resize? shrink?)
   (guarantee-gtk-widget child1 'gtk-paned-pack1)
@@ -766,6 +767,19 @@ USA.
   (container-add! paned child2)
   (C-call "gtk_paned_pack2" (gobject-alien paned) (gobject-alien child2)
          (if resize? 1 0) (if shrink? 1 0)))
+
+(define-class (<gtk-paned-view> (constructor ()))
+    (<gtk-paned>))
+
+(define (gtk-paned-view-new orientation)
+  (let ((orient (->gtk-orientation orientation 'gtk-paned-view-new))
+       (paned (make-gtk-paned-view)))
+    (let ((alien (gobject-alien paned)))
+      (C-call "gtk_paned_view_new" alien orient)
+      (error-if-null alien "Could not create:" paned)
+      (C-call "g_object_ref_sink" alien alien))
+    (set-gtk-widget-destroy-callback! paned)
+    paned))
 \f
 ;;; GtkWindows
 
index 1d2ab6c6d42d2c4ff3e5f9ba5b25545628a21be9..9203adcb73a38a6067ab7f65c13212592ab6c293 100644 (file)
@@ -99,6 +99,10 @@ USA.
 
 ;;; miscellaneous
 
+(extern (* GtkWidget)                  ;gtkpanedview.h
+       gtk_paned_view_new
+       (orientation GtkOrientation))
+
 (extern (* GtkWidget)                  ;gtkscrolledview.h
        gtk_scrolled_view_new
        (hadjustment (* GtkAdjustment))
index 609815cd388567f39f7b36c8cb471ba49846e29d..c3aa43dcd9450855a682e1fa7e6bb503fda97b85 100644 (file)
@@ -213,7 +213,8 @@ USA.
          guarantee-gtk-scrolled-view gtk-scrolled-view-new
          <gtk-paned> gtk-paned? gtk-paned-new
          gtk-paned-pack1 gtk-paned-pack2
-         gtk-paned-get-child1 gtk-paned-get-child2)
+         gtk-paned-get-child1 gtk-paned-get-child2
+         <gtk-paned-view> gtk-paned-view? gtk-paned-view-new)
   (import (gtk pango) make-pango-layout guarantee-pango-font-description))
 
 (define-package (gtk widget)
diff --git a/src/gtk/gtkpanedview.c.stay b/src/gtk/gtkpanedview.c.stay
new file mode 100644 (file)
index 0000000..9b6f04b
--- /dev/null
@@ -0,0 +1,612 @@
+/* -*-C-*-
+
+Copyright (C) 2013  Matthew Birkholz
+
+This file is part of MIT/GNU Scheme.
+
+MIT/GNU Scheme is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+MIT/GNU Scheme 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with MIT/GNU Scheme; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+USA.
+
+*/
+
+/* A specialized GtkPaned.  See documentation of <gtk-paned-view>. */
+
+#include "gtkpanedview.h"
+
+static void  gtk_paned_view_get_preferred_width   (GtkWidget           *widget,
+                                                  gint                *minimum_size,
+                                                  gint                *natural_size);
+static void  gtk_paned_view_get_preferred_height  (GtkWidget           *widget,
+                                                  gint                *minimum_size,
+                                                  gint                *natural_size);
+static void  gtk_paned_view_get_preferred_height_for_width
+                                                 (GtkWidget           *layout,
+                                                  gint                 width,
+                                                  gint                *minimum_height,
+                                                  gint                *natural_height);
+static void  gtk_paned_view_get_preferred_width_for_height
+                                                 (GtkWidget           *layout,
+                                                  gint                 width,
+                                                  gint                *minimum_height,
+                                                  gint                *natural_height);
+
+static void gtk_paned_view_size_allocate (GtkWidget *widget,
+                                         GtkAllocation *allocation);
+
+G_DEFINE_TYPE (GtkPanedView, gtk_paned_view,
+              GTK_TYPE_PANED)
+
+static void
+gtk_paned_view_class_init (GtkPanedViewClass *class)
+{
+  GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
+
+  widget_class->get_preferred_width = gtk_paned_view_get_preferred_width;
+  widget_class->get_preferred_height = gtk_paned_view_get_preferred_height;
+  widget_class->get_preferred_height_for_width = gtk_paned_view_get_preferred_height_for_width;
+  widget_class->get_preferred_width_for_height = gtk_paned_view_get_preferred_width_for_height;
+  widget_class->size_allocate = gtk_paned_view_size_allocate;
+}
+
+static void
+gtk_paned_view_init (GtkPanedView *paned_view)
+{
+  g_assert (GTK_PANED (paned_view) ->priv != NULL);
+}
+
+/**
+ * gtk_paned_view_new:
+ * @orientation: GTK_ORIENTATION_VERTICAL or GTK_ORIENTATION_HORIZONTAL.
+ *
+ * Creates a new paned view.
+ *
+ * Returns: a new paned view.
+ */
+GtkWidget*
+gtk_paned_view_new (GtkOrientation orientation)
+{
+  return (g_object_new (GTK_TYPE_PANED_VIEW,
+                       "orientation", orientation,
+                       NULL));
+}
+\f
+/* The rest of this file was copied from gtkpaned.c v3.6.0 with
+   minimal modification. */
+
+enum {
+  CHILD1,
+  CHILD2
+};
+
+struct _GtkPanedPrivate
+{
+  GtkPaned       *first_paned;
+  GtkWidget      *child1;
+  GtkWidget      *child2;
+  GdkWindow      *child1_window;
+  GdkWindow      *child2_window;
+  GtkWidget      *last_child1_focus;
+  GtkWidget      *last_child2_focus;
+  GtkWidget      *saved_focus;
+  GtkOrientation  orientation;
+
+  GdkCursorType  cursor_type;
+  GdkDevice     *grab_device;
+  GdkRectangle   handle_pos;
+  GdkWindow     *handle;
+
+  gint          child1_size;
+  gint          drag_pos;
+  gint          last_allocation;
+  gint          max_position;
+  gint          min_position;
+  gint          original_position;
+
+  guint32       grab_time;
+
+  guint         handle_prelit : 1;
+  guint         in_drag       : 1;
+  guint         in_recursion  : 1;
+  guint         child1_resize : 1;
+  guint         child1_shrink : 1;
+  guint         child2_resize : 1;
+  guint         child2_shrink : 1;
+  guint         position_set  : 1;
+};
+
+static void
+flip_child (GtkWidget     *widget,
+            GtkAllocation *child_pos)
+{
+  GtkAllocation allocation;
+  gint x, width;
+
+  gtk_widget_get_allocation (widget, &allocation);
+  x = allocation.x;
+  width = allocation.width;
+
+  child_pos->x = 2 * x + width - child_pos->x - child_pos->width;
+}
+
+static void
+gtk_paned_set_child_visible (GtkPaned  *paned,
+                             guint      id,
+                             gboolean   visible)
+{
+  GtkPanedPrivate *priv = paned->priv;
+  GtkWidget *child;
+
+  child = id == CHILD1 ? priv->child1 : priv->child2;
+
+  if (child == NULL)
+    return;
+
+  gtk_widget_set_child_visible (child, visible);
+
+  if (gtk_widget_get_mapped (GTK_WIDGET (paned)))
+    {
+      GdkWindow *window = id == CHILD1 ? priv->child1_window : priv->child2_window;
+
+      if (visible != gdk_window_is_visible (window))
+        {
+          if (visible)
+            gdk_window_show (window);
+          else
+            gdk_window_hide (window);
+        }
+    }
+}
+
+static void
+gtk_paned_child_allocate (GtkWidget           *child,
+                          GdkWindow           *child_window, /* can be NULL */
+                          const GtkAllocation *window_allocation,
+                          GtkAllocation       *child_allocation)
+{
+  if (child_window)
+    gdk_window_move_resize (child_window,
+                            window_allocation->x, window_allocation->y,
+                            window_allocation->width, window_allocation->height);
+
+  gtk_widget_size_allocate (child, child_allocation);
+}
+
+static void
+gtk_paned_calc_position (GtkPaned *paned,
+                         gint      allocation,
+                         gint      child1_min,
+                        gint      child1_nat,
+                         gint      child2_min,
+                        gint      child2_nat)
+{
+  GtkPanedPrivate *priv = paned->priv;
+  gint old_position;
+  gint old_min_position;
+  gint old_max_position;
+
+  old_position = priv->child1_size;
+  old_min_position = priv->min_position;
+  old_max_position = priv->max_position;
+
+  priv->min_position = priv->child1_shrink ? 0 : child1_min;
+
+  priv->max_position = allocation;
+  if (!priv->child2_shrink)
+    priv->max_position = MAX (1, priv->max_position - child2_min);
+  priv->max_position = MAX (priv->min_position, priv->max_position);
+
+  if (!priv->position_set)
+    {
+      if (priv->child1_resize && !priv->child2_resize)
+       priv->child1_size = MAX (0, allocation - child2_nat);
+      else if (!priv->child1_resize && priv->child2_resize)
+       priv->child1_size = child1_nat;
+      else if (child1_nat + child2_nat != 0)
+       priv->child1_size = allocation * ((gdouble)child1_nat / (child1_nat + child2_nat)) + 0.5;
+      else
+       priv->child1_size = allocation * 0.5 + 0.5;
+    }
+  else
+    {
+      /* If the position was set before the initial allocation.
+       * (priv->last_allocation <= 0) just clamp it and leave it.
+       */
+      if (priv->last_allocation > 0)
+       {
+         if (priv->child1_resize && !priv->child2_resize)
+           priv->child1_size += allocation - priv->last_allocation;
+         else if (!(!priv->child1_resize && priv->child2_resize))
+           priv->child1_size = allocation * ((gdouble) priv->child1_size / (priv->last_allocation)) + 0.5;
+       }
+    }
+
+  priv->child1_size = CLAMP (priv->child1_size,
+                             priv->min_position,
+                             priv->max_position);
+
+  if (priv->child1)
+    gtk_paned_set_child_visible (paned, 0, priv->child1_size != 0);
+  
+  if (priv->child2)
+    gtk_paned_set_child_visible (paned, 1, priv->child1_size != allocation); 
+
+  g_object_freeze_notify (G_OBJECT (paned));
+  if (priv->child1_size != old_position)
+    g_object_notify (G_OBJECT (paned), "position");
+  if (priv->min_position != old_min_position)
+    g_object_notify (G_OBJECT (paned), "min-position");
+  if (priv->max_position != old_max_position)
+    g_object_notify (G_OBJECT (paned), "max-position");
+  g_object_thaw_notify (G_OBJECT (paned));
+
+  priv->last_allocation = allocation;
+}
+
+static void
+gtk_paned_view_size_allocate (GtkWidget     *widget,
+                         GtkAllocation *allocation)
+{
+  GtkPaned *paned = GTK_PANED (widget);
+  GtkPanedPrivate *priv = paned->priv;
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
+      priv->child2 && gtk_widget_get_visible (priv->child2))
+    {
+      GtkAllocation child1_allocation, window1_allocation;
+      GtkAllocation child2_allocation, window2_allocation;
+      GtkAllocation priv_child1_allocation;
+      GdkRectangle old_handle_pos;
+      gint handle_size;
+
+      gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
+
+      old_handle_pos = priv->handle_pos;
+
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          gint child1_min_width, child1_nat_width;
+         gint child2_min_width, child2_nat_width;
+
+          gtk_widget_get_preferred_width_for_height (priv->child1,
+                                                     allocation->height,
+                                                     &child1_min_width, &child1_nat_width);
+          gtk_widget_get_preferred_width_for_height (priv->child2,
+                                                     allocation->height,
+                                                     &child2_min_width, &child2_nat_width);
+
+          gtk_paned_calc_position (paned,
+                                   MAX (1, allocation->width - handle_size),
+                                   child1_min_width, child1_nat_width,
+                                   child2_min_width, child2_nat_width);
+
+          priv->handle_pos.x = allocation->x + priv->child1_size;
+          priv->handle_pos.y = allocation->y;
+          priv->handle_pos.width = handle_size;
+          priv->handle_pos.height = allocation->height;
+
+          window1_allocation.height = window2_allocation.height = allocation->height;
+          window1_allocation.width = MAX (1, priv->child1_size);
+          window1_allocation.x = allocation->x;
+          window1_allocation.y = window2_allocation.y = allocation->y;
+
+          window2_allocation.x = window1_allocation.x + priv->child1_size + priv->handle_pos.width;
+          window2_allocation.width = MAX (1, allocation->x + allocation->width - window2_allocation.x);
+
+          if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL)
+            {
+              flip_child (widget, &(window2_allocation));
+              flip_child (widget, &(window1_allocation));
+              flip_child (widget, &(priv->handle_pos));
+            }
+
+          child1_allocation.x = child1_allocation.y = 0;
+          child1_allocation.width = window1_allocation.width;
+          child1_allocation.height = window1_allocation.height;
+          if (child1_min_width > child1_allocation.width)
+            {
+              if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_LTR)
+                child1_allocation.x -= child1_min_width - child1_allocation.width;
+              child1_allocation.width = child1_min_width;
+            }
+
+          child2_allocation.x = child2_allocation.y = 0;
+          child2_allocation.width = window2_allocation.width;
+          child2_allocation.height = window2_allocation.height;
+          if (child2_min_width > child2_allocation.width)
+            {
+              if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL)
+                child2_allocation.x -= child2_min_width - child2_allocation.width;
+              child2_allocation.width = child2_min_width;
+            }
+        }
+      else
+        {
+          gint child1_min_height, child1_nat_height;
+         gint child2_min_height, child2_nat_height;
+
+          gtk_widget_get_preferred_height_for_width (priv->child1,
+                                                     allocation->width,
+                                                     &child1_min_height,
+                                                    &child1_nat_height);
+          gtk_widget_get_preferred_height_for_width (priv->child2,
+                                                     allocation->width,
+                                                     &child2_min_height,
+                                                    &child2_nat_height);
+
+          gtk_paned_calc_position (paned,
+                                   MAX (1, allocation->height - handle_size),
+                                   child1_min_height, child1_nat_height,
+                                   child2_min_height, child2_nat_height);
+
+          priv->handle_pos.x = allocation->x;
+          priv->handle_pos.y = allocation->y + priv->child1_size;
+          priv->handle_pos.width = allocation->width;
+          priv->handle_pos.height = handle_size;
+
+          window1_allocation.width = window2_allocation.width = allocation->width;
+          window1_allocation.height = MAX (1, priv->child1_size);
+          window1_allocation.x = window2_allocation.x = allocation->x;
+          window1_allocation.y = allocation->y;
+
+          window2_allocation.y = window1_allocation.y + priv->child1_size + priv->handle_pos.height;
+          window2_allocation.height = MAX (1, allocation->y + allocation->height - window2_allocation.y);
+
+          child1_allocation.x = child1_allocation.y = 0;
+          child1_allocation.width = window1_allocation.width;
+          child1_allocation.height = window1_allocation.height;
+          if (child1_min_height > child1_allocation.height)
+            {
+              child1_allocation.y -= child1_min_height - child1_allocation.height;
+              child1_allocation.height = child1_min_height;
+            }
+
+          child2_allocation.x = child2_allocation.y = 0;
+          child2_allocation.width = window2_allocation.width;
+          child2_allocation.height = window2_allocation.height;
+          if (child2_min_height > child2_allocation.height)
+            child2_allocation.height = child2_min_height;
+        }
+
+      if (gtk_widget_get_mapped (widget) &&
+          (old_handle_pos.x != priv->handle_pos.x ||
+           old_handle_pos.y != priv->handle_pos.y ||
+           old_handle_pos.width != priv->handle_pos.width ||
+           old_handle_pos.height != priv->handle_pos.height))
+        {
+          GdkWindow *window;
+
+          window = gtk_widget_get_window (widget);
+          gdk_window_invalidate_rect (window, &old_handle_pos, FALSE);
+          gdk_window_invalidate_rect (window, &priv->handle_pos, FALSE);
+        }
+
+      if (gtk_widget_get_realized (widget))
+       {
+         if (gtk_widget_get_mapped (widget))
+           gdk_window_show (priv->handle);
+
+          if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+            {
+              gdk_window_move_resize (priv->handle,
+                                      priv->handle_pos.x,
+                                      priv->handle_pos.y,
+                                      handle_size,
+                                      priv->handle_pos.height);
+            }
+          else
+            {
+              gdk_window_move_resize (priv->handle,
+                                      priv->handle_pos.x,
+                                      priv->handle_pos.y,
+                                      priv->handle_pos.width,
+                                      handle_size);
+            }
+       }
+
+      /* Now allocate the childen, making sure, when resizing not to
+       * overlap the windows
+       */
+      gtk_widget_get_allocation (priv->child1, &priv_child1_allocation);
+      if (gtk_widget_get_mapped (widget) &&
+          ((priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
+            priv_child1_allocation.width < child1_allocation.width) ||
+
+           (priv->orientation == GTK_ORIENTATION_VERTICAL &&
+            priv_child1_allocation.height < child1_allocation.height)))
+       {
+          gtk_paned_child_allocate (priv->child2,
+                                    priv->child2_window,
+                                    &window2_allocation,
+                                    &child2_allocation);
+          gtk_paned_child_allocate (priv->child1,
+                                    priv->child1_window,
+                                    &window1_allocation,
+                                    &child1_allocation);
+       }
+      else
+       {
+          gtk_paned_child_allocate (priv->child1,
+                                    priv->child1_window,
+                                    &window1_allocation,
+                                    &child1_allocation);
+          gtk_paned_child_allocate (priv->child2,
+                                    priv->child2_window,
+                                    &window2_allocation,
+                                    &child2_allocation);
+       }
+    }
+  else
+    {
+      GtkAllocation window_allocation, child_allocation;
+
+      if (gtk_widget_get_realized (widget))
+       gdk_window_hide (priv->handle);
+
+      window_allocation.x = allocation->x;
+      window_allocation.y = allocation->y;
+      window_allocation.width = allocation->width;
+      window_allocation.height = allocation->height;
+      child_allocation.x = child_allocation.y = 0;
+      child_allocation.width = allocation->width;
+      child_allocation.height = allocation->height;
+
+      if (priv->child1 && gtk_widget_get_visible (priv->child1))
+        {
+          gtk_paned_set_child_visible (paned, 0, TRUE);
+          if (priv->child2)
+            gtk_paned_set_child_visible (paned, 1, FALSE);
+
+          gtk_paned_child_allocate (priv->child1,
+                                    priv->child1_window,
+                                    &window_allocation,
+                                    &child_allocation);
+        }
+      else if (priv->child2 && gtk_widget_get_visible (priv->child2))
+        {
+          gtk_paned_set_child_visible (paned, 1, TRUE);
+          if (priv->child1)
+            gtk_paned_set_child_visible (paned, 0, FALSE);
+
+          gtk_paned_child_allocate (priv->child2,
+                                    priv->child2_window,
+                                    &window_allocation,
+                                    &child_allocation);
+        }
+      else
+        {
+          if (priv->child1)
+            gtk_paned_set_child_visible (paned, 0, FALSE);
+          if (priv->child2)
+            gtk_paned_set_child_visible (paned, 1, FALSE);
+        }
+    }
+}
+
+static void
+get_preferred_size_for_size (GtkWidget      *widget,
+                             GtkOrientation  orientation,
+                             gint            size,
+                             gint           *minimum,
+                             gint           *natural)
+{
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    if (size < 0)
+      gtk_widget_get_preferred_width (widget, minimum, natural);
+    else
+      gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural);
+  else
+    if (size < 0)
+      gtk_widget_get_preferred_height (widget, minimum, natural);
+    else
+      gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural);
+}
+
+static void
+gtk_paned_view_get_preferred_size (GtkWidget      *widget,
+                              GtkOrientation  orientation,
+                              gint            size,
+                              gint           *minimum_size,
+                              gint           *natural_size)
+{
+  GtkPaned *paned = GTK_PANED (widget);
+  GtkPanedPrivate *priv = paned->priv;
+  gint child_min, child_nat;
+  gint minimum, natural;
+
+  minimum = 0;
+  natural = 0;
+
+  if (priv->child1 && gtk_widget_get_visible (priv->child1))
+    {
+      get_preferred_size_for_size (priv->child1, orientation, size, &child_min, &child_nat);
+      if (priv->child1_shrink && priv->orientation == orientation)
+        minimum += 0;
+      else
+        minimum += child_min;
+      natural += child_nat;
+    }
+
+  if (priv->child2 && gtk_widget_get_visible (priv->child2))
+    {
+      get_preferred_size_for_size (priv->child2, orientation, size, &child_min, &child_nat);
+
+      if (priv->orientation == orientation)
+        {
+          if (!priv->child2_shrink)
+            minimum += child_min;
+          natural += child_nat;
+        }
+      else
+        {
+          minimum = MAX (minimum, child_min);
+          natural = MAX (natural, child_nat);
+        }
+    }
+
+  if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
+      priv->child2 && gtk_widget_get_visible (priv->child2))
+    {
+      gint handle_size;
+
+      gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
+
+      if (priv->orientation == orientation)
+        {
+          minimum += handle_size;
+          natural += handle_size;
+        }
+    }
+
+  if (minimum_size)
+    *minimum_size = minimum;
+  if (natural_size)
+    *natural_size = natural;
+}
+
+static void
+gtk_paned_view_get_preferred_width (GtkWidget *widget,
+                                   gint      *minimum,
+                                   gint      *natural)
+{
+  gtk_paned_view_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural);
+}
+
+static void
+gtk_paned_view_get_preferred_height (GtkWidget *widget,
+                                    gint      *minimum,
+                                    gint      *natural)
+{
+  gtk_paned_view_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural);
+}
+
+static void
+gtk_paned_view_get_preferred_width_for_height (GtkWidget *widget,
+                                              gint       height,
+                                              gint      *minimum,
+                                              gint      *natural)
+{
+  gtk_paned_view_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
+}
+
+static void
+gtk_paned_view_get_preferred_height_for_width (GtkWidget *widget,
+                                              gint       width,
+                                              gint      *minimum,
+                                              gint      *natural)
+{
+  gtk_paned_view_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural);
+}
diff --git a/src/gtk/gtkpanedview.h b/src/gtk/gtkpanedview.h
new file mode 100644 (file)
index 0000000..9370b44
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-C-*-
+
+Copyright (C) 2013  Matthew Birkholz
+
+This file is part of MIT/GNU Scheme.
+
+MIT/GNU Scheme is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+MIT/GNU Scheme 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with MIT/GNU Scheme; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+USA.
+
+*/
+
+/* A specialized GtkPaned.  See documentation of <gtk-paned-view>. */
+
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_PANED_VIEW            (gtk_paned_view_get_type ())
+#define GTK_PANED_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PANED_VIEW, GtkPanedView))
+#define GTK_PANED_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PANED_VIEW, GtkPanedViewClass))
+#define GTK_IS_PANED_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PANED_VIEW))
+#define GTK_IS_PANED_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PANED_VIEW))
+#define GTK_PANED_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PANED_VIEW, GtkPanedViewClass))
+
+
+typedef struct _GtkPanedView           GtkPanedView;
+typedef struct _GtkPanedViewClass      GtkPanedViewClass;
+
+struct _GtkPanedView
+{
+  GtkPaned paned;
+};
+
+struct _GtkPanedViewClass
+{
+  GtkPanedClass parent_class;
+};
+
+
+GType          gtk_paned_view_get_type (void) G_GNUC_CONST;
+GtkWidget*     gtk_paned_view_new      (GtkOrientation orientation);
index 0967c1f363540bab99aab7c3c0312780fc0e42cd..54d71870662df56be6c7766137a1bdcd78dd3af3 100644 (file)
@@ -1,32 +1,30 @@
-#include "gtkscrolledview.h"
+/* -*-C-*-
 
-/**
- * SECTION:gtkscrolledview
- * @Short_description: Adds scrollbars to its child widget
- * @Title: GtkScrolledView
- * @See_also: #GtkScrollable, #GtkViewport, #GtkAdjustment
- *
- * #GtkScrolledView is a #GtkBin subclass: it's a container that
- * accepts a single child widget (a GtkScrollable) and adds an
- * optional beveled frame and scrollbars.
- *
- * The position of the scrollbars is controlled by the scroll
- * adjustments. See #GtkAdjustment for the fields in an adjustment.
- *
- * #GtkScrolledView is a #GtkScrolledWindow subclass that overrides
- * the geometry protocol to work as follows:
- *
- * A scrolled window (GtkScrolledWindow) is about squeezing an overly
- * large widget into a small space and allowing the user to scroll it.
- * It ignores the natural size of the problem widget, expecting a
- * gtk_widget_set_size_request to override (squeeze) it.
- *
- * A scrolled view (GtkScrolledView) is about sticking scrollbars on a
- * viewport -- a GtkScrollable.  Its natural size is the natural size
- * of the viewport, scrollbars and frame (with spacing).  Using
- * gtk_widget_set_size_request interferes with the natural sizing
- * (esp. shrinking of expandable viewports).
- */
+Copyright (C) 2012, 2013  Matthew Birkholz
+
+This file is part of MIT/GNU Scheme.
+
+MIT/GNU Scheme is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+MIT/GNU Scheme 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with MIT/GNU Scheme; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+USA.
+
+*/
+
+/* A specialized GtkScrolledWindow.  See documentation of
+   <gtk-scrolled-view>. */
+
+#include "gtkscrolledview.h"
 
 struct _GtkScrolledWindowPrivate
 {
index 5508728f3cfedf10ef3633c135b059e268e750d2..028adbc6a6c6242ed9c910d35140070013611545 100644 (file)
@@ -1,3 +1,29 @@
+/* -*-C-*-
+
+Copyright (C) 2012, 2013  Matthew Birkholz
+
+This file is part of MIT/GNU Scheme.
+
+MIT/GNU Scheme is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+MIT/GNU Scheme 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with MIT/GNU Scheme; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+USA.
+
+*/
+
+/* A specialized GtkScrolledWindow.  See documentation of
+   <gtk-scrolled-view>. */
+
 #include <gtk/gtk.h>
 
 #define GTK_TYPE_SCROLLED_VIEW            (gtk_scrolled_view_get_type ())