[gtk+/gtk-style-context] Add Gtk9Slice



commit 7479a6f3a673730b2b734bbf7de12b64c841a004
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Sep 24 21:42:18 2010 +0200

    Add Gtk9Slice
    
    This is a private boxed object to contain information about a border image
    in order to render it in a size independent way.

 gtk/Makefile.am |    2 +
 gtk/gtk9slice.c |  351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtk9slice.h |   59 +++++++++
 3 files changed, 412 insertions(+), 0 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index ce66c32..86384dc 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -360,6 +360,7 @@ gtk_semi_private_h_sources =    \
 
 # GTK+ header files that don't get installed
 gtk_private_h_sources =		\
+	gtk9slice.h 		\
 	gtkquery.h		\
 	gtksearchengine.h	\
 	gtksearchenginesimple.h	\
@@ -410,6 +411,7 @@ gtk_private_h_sources =		\
 
 # GTK+ C sources to build the library from
 gtk_base_c_sources =            \
+	gtk9slice.c		\
 	gtkquery.c		\
 	gtksearchengine.c	\
 	gtksearchenginesimple.c	\
diff --git a/gtk/gtk9slice.c b/gtk/gtk9slice.c
new file mode 100644
index 0000000..9bfdafb
--- /dev/null
+++ b/gtk/gtk9slice.c
@@ -0,0 +1,351 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2010 Carlos Garnacho <carlosg gnome org>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "gtk9slice.h"
+
+enum {
+  BORDER_LEFT,
+  BORDER_MIDDLE,
+  BORDER_RIGHT,
+  BORDER_LAST,
+  BORDER_TOP = BORDER_LEFT,
+  BORDER_BOTTOM = BORDER_RIGHT
+};
+
+enum {
+  SIDE_TOP,
+  SIDE_RIGHT,
+  SIDE_BOTTOM,
+  SIDE_LEFT
+};
+
+struct Gtk9Slice
+{
+  cairo_surface_t *surfaces[BORDER_LAST][BORDER_LAST];
+  GtkSliceSideModifier modifiers[4];
+  gdouble distances[4];
+  gint ref_count;
+};
+
+G_DEFINE_BOXED_TYPE (Gtk9Slice, gtk_9slice,
+                     gtk_9slice_ref, gtk_9slice_unref)
+
+
+Gtk9Slice *
+gtk_9slice_new (GdkPixbuf            *pixbuf,
+                gdouble               distance_top,
+                gdouble               distance_bottom,
+                gdouble               distance_left,
+                gdouble               distance_right,
+                GtkSliceSideModifier  vertical_modifier,
+                GtkSliceSideModifier  horizontal_modifier)
+{
+  Gtk9Slice *slice;
+  cairo_surface_t *surface;
+  gint width, height;
+  cairo_t *cr;
+
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+  slice = g_slice_new0 (Gtk9Slice);
+  slice->ref_count = 1;
+
+  slice->distances[SIDE_TOP] = distance_top;
+  slice->distances[SIDE_BOTTOM] = distance_bottom;
+  slice->distances[SIDE_LEFT] = distance_left;
+  slice->distances[SIDE_RIGHT] = distance_right;
+
+  slice->modifiers[SIDE_TOP] = slice->modifiers[SIDE_BOTTOM] = horizontal_modifier;
+  slice->modifiers[SIDE_LEFT] = slice->modifiers[SIDE_RIGHT] = vertical_modifier;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  /* Get an image surface from the pixbuf */
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+  cr = cairo_create (surface);
+
+  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+
+  /* Top /left corner */
+  slice->surfaces[BORDER_LEFT][BORDER_TOP] = cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
+                                                                           distance_left, distance_top);
+  cairo_create (slice->surfaces[BORDER_LEFT][BORDER_TOP]);
+
+  cairo_set_source_surface (cr, surface, 0, 0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+
+  /* Top/right corner */
+  slice->surfaces[BORDER_RIGHT][BORDER_TOP] = cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
+                                                                            distance_right, distance_top);
+  cairo_create (slice->surfaces[BORDER_RIGHT][BORDER_TOP]);
+
+  cairo_set_source_surface (cr, surface, - width + distance_right, 0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+
+  /* Bottom/left corner */
+  slice->surfaces[BORDER_LEFT][BORDER_BOTTOM] = cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
+                                                                              distance_left, distance_bottom);
+  cairo_create (slice->surfaces[BORDER_LEFT][BORDER_BOTTOM]);
+
+  cairo_set_source_surface (cr, surface, 0, - height + distance_bottom);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+
+  /* Bottom/right corner */
+  slice->surfaces[BORDER_RIGHT][BORDER_BOTTOM] = cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
+                                                                               distance_right, distance_bottom);
+  cairo_create (slice->surfaces[BORDER_RIGHT][BORDER_BOTTOM]);
+
+  cairo_set_source_surface (cr, surface, - width + distance_right, - height + distance_bottom);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+
+  /* Top side */
+  slice->surfaces[BORDER_MIDDLE][BORDER_TOP] = cairo_surface_create_similar (surface,
+                                                                             CAIRO_CONTENT_COLOR_ALPHA,
+                                                                             width - distance_left - distance_right,
+                                                                             distance_top);
+  cairo_create (slice->surfaces[BORDER_MIDDLE][BORDER_TOP]);
+  cairo_set_source_surface (cr, surface, - distance_left, 0);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  /* Bottom side */
+  slice->surfaces[BORDER_MIDDLE][BORDER_BOTTOM] = cairo_surface_create_similar (surface,
+                                                                                CAIRO_CONTENT_COLOR_ALPHA,
+                                                                                width - distance_left - distance_right,
+                                                                                distance_bottom);
+  cairo_create (slice->surfaces[BORDER_MIDDLE][BORDER_BOTTOM]);
+  cairo_set_source_surface (cr, surface, - distance_left, - height + distance_bottom);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  /* Left side */
+  slice->surfaces[BORDER_LEFT][BORDER_MIDDLE] = cairo_surface_create_similar (surface,
+                                                                              CAIRO_CONTENT_COLOR_ALPHA,
+                                                                              distance_left,
+                                                                              height - distance_top - distance_bottom);
+  cairo_create (slice->surfaces[BORDER_LEFT][BORDER_MIDDLE]);
+  cairo_set_source_surface (cr, surface, 0, - distance_top);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  /* Right side */
+  slice->surfaces[BORDER_RIGHT][BORDER_MIDDLE] = cairo_surface_create_similar (surface,
+                                                                               CAIRO_CONTENT_COLOR_ALPHA,
+                                                                               distance_right,
+                                                                               height - distance_top - distance_bottom);
+  cairo_create (slice->surfaces[BORDER_RIGHT][BORDER_MIDDLE]);
+  cairo_set_source_surface (cr, surface, - width + distance_right, - distance_top);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  /* Center */
+  slice->surfaces[BORDER_MIDDLE][BORDER_MIDDLE] = cairo_surface_create_similar (surface,
+                                                                                CAIRO_CONTENT_COLOR_ALPHA,
+                                                                                width - distance_left - distance_right,
+                                                                                height - distance_top - distance_bottom);
+  cairo_create (slice->surfaces[BORDER_MIDDLE][BORDER_MIDDLE]);
+  cairo_set_source_surface (cr, surface, - distance_left, - distance_top);
+  cairo_paint (cr);
+  cairo_destroy (cr);
+
+  return slice;
+}
+
+static void
+render_border (cairo_t              *cr,
+               cairo_surface_t      *surface,
+               gdouble               x,
+               gdouble               y,
+               gdouble               width,
+               gdouble               height,
+               GtkSliceSideModifier  modifier)
+{
+  cairo_pattern_t *pattern;
+  cairo_matrix_t matrix;
+
+  cairo_save (cr);
+
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_clip (cr);
+
+  pattern = cairo_pattern_create_for_surface (surface);
+
+  cairo_matrix_init_translate (&matrix, - x, - y);
+
+  if (modifier == GTK_SLICE_REPEAT)
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+  else
+    {
+      gint w;
+
+      w = cairo_image_surface_get_width (surface);
+      cairo_matrix_scale (&matrix, width / w, 0);
+    }
+
+  cairo_pattern_set_matrix (pattern, &matrix);
+  cairo_set_source (cr, pattern);
+
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+
+  cairo_restore (cr);
+}
+
+static void
+render_corner (cairo_t         *cr,
+               cairo_surface_t *surface,
+               gdouble          x,
+               gdouble          y,
+               gdouble          width,
+               gdouble          height)
+{
+  cairo_save (cr);
+
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_clip (cr);
+
+  cairo_set_source_surface (cr, surface, x, y);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_fill (cr);
+
+  cairo_restore (cr);
+}
+
+void
+gtk_9slice_render (Gtk9Slice *slice,
+                   cairo_t   *cr,
+                   gdouble    x,
+                   gdouble    y,
+                   gdouble    width,
+                   gdouble    height)
+{
+  int img_width, img_height;
+  cairo_surface_t *surface;
+
+  cairo_save (cr);
+
+  /* Top side */
+  surface = slice->surfaces[BORDER_MIDDLE][BORDER_TOP];
+  img_height = cairo_image_surface_get_height (surface);
+
+  render_border (cr, surface,
+                 x + slice->distances[SIDE_LEFT], y,
+                 (gdouble) width - slice->distances[SIDE_LEFT] - slice->distances[SIDE_RIGHT],
+                 (gdouble) img_height,
+                 slice->modifiers[SIDE_TOP]);
+
+  /* Bottom side */
+  surface = slice->surfaces[BORDER_MIDDLE][BORDER_BOTTOM];
+  img_height = cairo_image_surface_get_height (surface);
+
+  render_border (cr, surface,
+                 x + slice->distances[SIDE_LEFT], y + height - img_height,
+                 (gdouble) width - slice->distances[SIDE_LEFT] - slice->distances[SIDE_RIGHT],
+                 (gdouble) img_height,
+                 slice->modifiers[SIDE_BOTTOM]);
+
+  /* Left side */
+  surface = slice->surfaces[BORDER_LEFT][BORDER_MIDDLE];
+  img_width = cairo_image_surface_get_width (surface);
+
+  render_border (cr, surface,
+                 x, y + slice->distances[SIDE_TOP],
+                 (gdouble) img_width,
+                 (gdouble) height - slice->distances[SIDE_TOP] - slice->distances[SIDE_BOTTOM],
+                 slice->modifiers[SIDE_LEFT]);
+
+  /* Right side */
+  surface = slice->surfaces[BORDER_RIGHT][BORDER_MIDDLE];
+  img_width = cairo_image_surface_get_width (surface);
+
+  render_border (cr, surface,
+                 x + width - img_width, y + slice->distances[SIDE_TOP],
+                 (gdouble) img_width, height - slice->distances[SIDE_TOP] - slice->distances[SIDE_BOTTOM],
+                 slice->modifiers[SIDE_RIGHT]);
+
+  /* Top/Left corner */
+  surface = slice->surfaces[BORDER_LEFT][BORDER_TOP];
+  img_width = cairo_image_surface_get_width (surface);
+  img_height = cairo_image_surface_get_height (surface);
+  render_corner (cr, surface, x, y, (gdouble) img_width, (gdouble) img_height);
+
+  /* Top/right corner */
+  surface = slice->surfaces[BORDER_RIGHT][BORDER_TOP];
+  img_width = cairo_image_surface_get_width (surface);
+  img_height = cairo_image_surface_get_height (surface);
+  render_corner (cr, surface, x + width - img_width, y,
+                 (gdouble) img_width, (gdouble) img_height);
+
+  /* Bottom/left corner */
+  surface = slice->surfaces[BORDER_LEFT][BORDER_BOTTOM];
+  img_width = cairo_image_surface_get_width (surface);
+  img_height = cairo_image_surface_get_height (surface);
+  render_corner (cr, surface, x, y + height - img_height,
+                 (gdouble) img_width, (gdouble) img_height);
+
+  /* Bottom/right corner */
+  surface = slice->surfaces[BORDER_RIGHT][BORDER_BOTTOM];
+  img_width = cairo_image_surface_get_width (surface);
+  img_height = cairo_image_surface_get_height (surface);
+  render_corner (cr, surface, x + width - img_width, y + height - img_height,
+                 (gdouble) img_width, (gdouble) img_height);
+
+  cairo_restore (cr);
+}
+
+Gtk9Slice *
+gtk_9slice_ref (Gtk9Slice *slice)
+{
+  g_return_val_if_fail (slice != NULL, NULL);
+
+  slice->ref_count++;
+  return slice;
+}
+
+void
+gtk_9slice_unref (Gtk9Slice *slice)
+{
+  g_return_if_fail (slice != NULL);
+
+  slice->ref_count--;
+
+  if (slice->ref_count == 0)
+    {
+      gint i, j;
+
+      for (i = 0; i < BORDER_LAST; i++)
+        for (j = 0; j < BORDER_LAST; j++)
+          cairo_surface_destroy (slice->surfaces[i][j]);
+
+      g_slice_free (Gtk9Slice, slice);
+    }
+}
diff --git a/gtk/gtk9slice.h b/gtk/gtk9slice.h
new file mode 100644
index 0000000..28d998b
--- /dev/null
+++ b/gtk/gtk9slice.h
@@ -0,0 +1,59 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2010 Carlos Garnacho <carlosg gnome org>
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_9SLICE_H__
+#define __GTK_9SLICE_H__
+
+#include "gtktimeline.h"
+
+G_BEGIN_DECLS
+
+/* Dummy typedefs */
+typedef struct Gtk9Slice Gtk9Slice;
+
+#define GTK_TYPE_9SLICE (gtk_9slice_get_type ())
+
+typedef enum {
+  GTK_SLICE_REPEAT,
+  GTK_SLICE_STRETCH
+} GtkSliceSideModifier;
+
+GType gtk_9slice_get_type (void) G_GNUC_CONST;
+
+Gtk9Slice * gtk_9slice_new (GdkPixbuf            *pixbuf,
+                            gdouble               distance_top,
+                            gdouble               distance_bottom,
+                            gdouble               distance_left,
+                            gdouble               distance_right,
+                            GtkSliceSideModifier  vertical_modifier,
+                            GtkSliceSideModifier  horizontal_modifier);
+
+Gtk9Slice * gtk_9slice_ref   (Gtk9Slice *slice);
+void        gtk_9slice_unref (Gtk9Slice *slice);
+
+void gtk_9slice_render (Gtk9Slice *slice,
+                        cairo_t   *cr,
+                        gdouble    x,
+                        gdouble    y,
+                        gdouble    width,
+                        gdouble    height);
+
+G_END_DECLS
+
+#endif /* __GTK_9SLICE_H__ */



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