[cairo] [PATCH 5/6] demos: Add new demo program, "scale"

Søren Sandmann sandmann at cs.au.dk
Fri Nov 23 20:15:30 PST 2012


From: Søren Sandmann Pedersen <ssp at redhat.com>

This program allows interactively scaling and rotating images with
using various filters and repeat modes. It uses
pixman_filter_create_separate_convolution() to generate the filters.
---
 demos/Makefile.am |    6 +-
 demos/scale.c     |  431 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 demos/scale.ui    |  302 +++++++++++++++++++++++++++++++++++++
 3 files changed, 737 insertions(+), 2 deletions(-)
 create mode 100644 demos/scale.c
 create mode 100644 demos/scale.ui

diff --git a/demos/Makefile.am b/demos/Makefile.am
index f324f5f..ffb7a6b 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -22,9 +22,10 @@ DEMOS =				\
 	quad2quad		\
 	checkerboard		\
 	srgb-trap-test		\
-	srgb-test
+	srgb-test		\
+	scale
 
-EXTRA_DIST = parrot.c parrot.jpg
+EXTRA_DIST = parrot.c parrot.jpg scale.ui
 
 gradient_test_SOURCES = gradient-test.c $(GTK_UTILS)
 alpha_test_SOURCES = alpha-test.c $(GTK_UTILS)
@@ -39,6 +40,7 @@ tri_test_SOURCES = tri-test.c $(GTK_UTILS)
 checkerboard_SOURCES = checkerboard.c $(GTK_UTILS)
 srgb_test_SOURCES = srgb-test.c $(GTK_UTILS)
 srgb_trap_test_SOURCES = srgb-trap-test.c $(GTK_UTILS)
+scale_SOURCES = scale.c $(GTK_UTILS)
 
 noinst_PROGRAMS = $(DEMOS)
 
diff --git a/demos/scale.c b/demos/scale.c
new file mode 100644
index 0000000..9100ff7
--- /dev/null
+++ b/demos/scale.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2012, Red Hat, Inc.
+ * Copyright 2012, Soren Sandmann
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Soren Sandmann <soren.sandmann at gmail.com>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <math.h>
+#include <gtk/gtk.h>
+#include <pixman.h>
+#include <stdlib.h>
+#include "gtk-utils.h"
+
+typedef struct
+{
+    GtkBuilder *        builder;
+    pixman_image_t *	original;
+    GtkAdjustment *     scale_x_adjustment;
+    GtkAdjustment *     scale_y_adjustment;
+    GtkAdjustment *     rotate_adjustment;
+    int                 scaled_width;
+    int                 scaled_height;
+} app_t;
+
+static GtkWidget *
+get_widget (app_t *app, const char *name)
+{
+    GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (app->builder, name));
+
+    if (!widget)
+        g_error ("Widget %s not found\n", name);
+
+    return widget;
+}
+
+static double
+min4 (double a, double b, double c, double d)
+{
+    double m1, m2;
+
+    m1 = MIN (a, b);
+    m2 = MIN (c, d);
+    return MIN (m1, m2);
+}
+
+static double
+max4 (double a, double b, double c, double d)
+{
+    double m1, m2;
+
+    m1 = MAX (a, b);
+    m2 = MAX (c, d);
+    return MAX (m1, m2);
+}
+
+static void
+compute_extents (pixman_f_transform_t *trans, double *sx, double *sy)
+{
+    double min_x, max_x, min_y, max_y;
+    pixman_f_vector_t v[4] =
+    {
+	{ { 1, 1, 1 } },
+	{ { -1, 1, 1 } },
+	{ { -1, -1, 1 } },
+	{ { 1, -1, 1 } },
+    };
+
+    pixman_f_transform_point (trans, &v[0]);
+    pixman_f_transform_point (trans, &v[1]);
+    pixman_f_transform_point (trans, &v[2]);
+    pixman_f_transform_point (trans, &v[3]);
+
+    min_x = min4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]);
+    max_x = max4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]);
+    min_y = min4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]);
+    max_y = max4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]);
+
+    *sx = (max_x - min_x) / 2.0;
+    *sy = (max_y - min_y) / 2.0;
+}
+
+typedef struct
+{
+    char		name [20];
+    pixman_kernel_t	value;
+} named_int_t;
+
+static const named_int_t filters[] =
+{
+    { "Box",			PIXMAN_KERNEL_BOX },
+    { "Impulse",		PIXMAN_KERNEL_IMPULSE },
+    { "Linear",			PIXMAN_KERNEL_LINEAR },
+    { "Cubic",			PIXMAN_KERNEL_CUBIC },
+    { "Lanczos2",		PIXMAN_KERNEL_LANCZOS2 },
+    { "Lanczos3",		PIXMAN_KERNEL_LANCZOS3 },
+    { "Lanczos3 Stretched",	PIXMAN_KERNEL_LANCZOS3_STRETCHED },
+    { "Gaussian",		PIXMAN_KERNEL_GAUSSIAN },
+};
+
+static const named_int_t repeats[] =
+{
+    { "None",                   PIXMAN_REPEAT_NONE },
+    { "Normal",                 PIXMAN_REPEAT_NORMAL },
+    { "Reflect",                PIXMAN_REPEAT_REFLECT },
+    { "Pad",                    PIXMAN_REPEAT_PAD },
+};
+
+static pixman_kernel_t
+get_value (app_t *app, const named_int_t table[], const char *box_name)
+{
+    GtkComboBox *box = GTK_COMBO_BOX (get_widget (app, box_name));
+
+    return table[gtk_combo_box_get_active (box)].value;
+}
+
+static void
+copy_to_counterpart (app_t *app, GObject *object)
+{
+    static const char *xy_map[] =
+    {
+	"reconstruct_x_combo_box", "reconstruct_y_combo_box",
+	"sample_x_combo_box",      "sample_y_combo_box",
+	"scale_x_adjustment",      "scale_y_adjustment",
+    };
+    GObject *counterpart = NULL;
+    int i;
+
+    for (i = 0; i < G_N_ELEMENTS (xy_map); i += 2)
+    {
+	GObject *x = gtk_builder_get_object (app->builder, xy_map[i]);
+	GObject *y = gtk_builder_get_object (app->builder, xy_map[i + 1]);
+
+	if (object == x)
+	    counterpart = y;
+	if (object == y)
+	    counterpart = x;
+    }
+
+    if (!counterpart)
+	return;
+    
+    if (GTK_IS_COMBO_BOX (counterpart))
+    {
+	gtk_combo_box_set_active (
+	    GTK_COMBO_BOX (counterpart),
+	    gtk_combo_box_get_active (
+		GTK_COMBO_BOX (object)));
+    }
+    else if (GTK_IS_ADJUSTMENT (counterpart))
+    {
+	gtk_adjustment_set_value (
+	    GTK_ADJUSTMENT (counterpart),
+	    gtk_adjustment_get_value (
+		GTK_ADJUSTMENT (object)));
+    }
+}
+
+static double
+to_scale (double v)
+{
+    return pow (1.15, v);
+}
+
+static void
+rescale (GtkWidget *may_be_null, app_t *app)
+{
+    pixman_f_transform_t ftransform;
+    pixman_transform_t transform;
+    double new_width, new_height;
+    double fscale_x, fscale_y;
+    double rotation;
+    pixman_fixed_t *params;
+    int n_params;
+    double sx, sy;
+
+    pixman_f_transform_init_identity (&ftransform);
+
+    if (may_be_null && gtk_toggle_button_get_active (
+	    GTK_TOGGLE_BUTTON (get_widget (app, "lock_checkbutton"))))
+    {
+	copy_to_counterpart (app, G_OBJECT (may_be_null));
+    }
+    
+    fscale_x = gtk_adjustment_get_value (app->scale_x_adjustment);
+    fscale_y = gtk_adjustment_get_value (app->scale_y_adjustment);
+    rotation = gtk_adjustment_get_value (app->rotate_adjustment);
+
+    fscale_x = to_scale (fscale_x);
+    fscale_y = to_scale (fscale_y);
+    
+    new_width = pixman_image_get_width (app->original) * fscale_x;
+    new_height = pixman_image_get_height (app->original) * fscale_y;
+
+    pixman_f_transform_scale (&ftransform, NULL, fscale_x, fscale_y);
+
+    pixman_f_transform_translate (&ftransform, NULL, - new_width / 2.0, - new_height / 2.0);
+
+    rotation = (rotation / 360.0) * 2 * M_PI;
+    pixman_f_transform_rotate (&ftransform, NULL, cos (rotation), sin (rotation));
+
+    pixman_f_transform_translate (&ftransform, NULL, new_width / 2.0, new_height / 2.0);
+
+    pixman_f_transform_invert (&ftransform, &ftransform);
+
+    compute_extents (&ftransform, &sx, &sy);
+    
+    pixman_transform_from_pixman_f_transform (&transform, &ftransform);
+    pixman_image_set_transform (app->original, &transform);
+
+    params = pixman_filter_create_separable_convolution (
+        &n_params,
+        sx * 65536.0 + 0.5,
+	sy * 65536.0 + 0.5,
+	get_value (app, filters, "reconstruct_x_combo_box"),
+	get_value (app, filters, "reconstruct_y_combo_box"),
+	get_value (app, filters, "sample_x_combo_box"),
+	get_value (app, filters, "sample_y_combo_box"),
+        4, 4);
+
+    pixman_image_set_filter (app->original, PIXMAN_FILTER_SEPARABLE_CONVOLUTION, params, n_params);
+
+    pixman_image_set_repeat (
+        app->original, get_value (app, repeats, "repeat_combo_box"));
+    
+    free (params);
+
+    app->scaled_width = ceil (new_width);
+    app->scaled_height = ceil (new_height);
+    
+    gtk_widget_set_size_request (
+        get_widget (app, "drawing_area"), new_width + 0.5, new_height + 0.5);
+
+    gtk_widget_queue_draw (
+        get_widget (app, "drawing_area"));
+}
+
+static gboolean
+on_expose (GtkWidget *da, GdkEvent *event, gpointer data)
+{
+    app_t *app = data;
+    GdkRectangle *area = &event->expose.area;
+    cairo_surface_t *surface;
+    pixman_image_t *tmp;
+    cairo_t *cr;
+    uint32_t *pixels;
+
+    pixels = calloc (1, area->width * area->height * 4);
+    tmp = pixman_image_create_bits (
+        PIXMAN_a8r8g8b8, area->width, area->height, pixels, area->width * 4);
+
+    if (area->x < app->scaled_width && area->y < app->scaled_height)
+    {
+        pixman_image_composite (
+            PIXMAN_OP_SRC,
+            app->original, NULL, tmp,
+            area->x, area->y, 0, 0, 0, 0,
+            app->scaled_width - area->x, app->scaled_height - area->y);
+    }
+
+    surface = cairo_image_surface_create_for_data (
+        (uint8_t *)pixels, CAIRO_FORMAT_ARGB32,
+        area->width, area->height, area->width * 4);
+
+    cr = gdk_cairo_create (da->window);
+
+    cairo_set_source_surface (cr, surface, area->x, area->y);
+
+    cairo_paint (cr);
+
+    cairo_destroy (cr);
+    cairo_surface_destroy (surface);
+    free (pixels);
+    pixman_image_unref (tmp);
+
+    return TRUE;
+}
+
+static void
+set_up_combo_box (app_t *app, const char *box_name,
+                  int n_entries, const named_int_t table[])
+{
+    GtkWidget *widget = get_widget (app, box_name);
+    GtkListStore *model;
+    GtkCellRenderer *cell;
+    int i;
+
+    model = gtk_list_store_new (1, G_TYPE_STRING);
+    
+    cell = gtk_cell_renderer_text_new ();
+    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE);
+    gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), cell,
+				    "text", 0,
+				    NULL);
+
+    gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (model));
+    
+    for (i = 0; i < n_entries; ++i)
+    {
+	const named_int_t *info = &(table[i]);
+	GtkTreeIter iter;
+
+	gtk_list_store_append (model, &iter);
+	gtk_list_store_set (model, &iter, 0, info->name, -1);
+    }
+
+    gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+
+    g_signal_connect (widget, "changed", G_CALLBACK (rescale), app);
+}
+
+static void
+set_up_filter_box (app_t *app, const char *box_name)
+{
+    set_up_combo_box (app, box_name, G_N_ELEMENTS (filters), filters);
+}
+
+static char *
+format_value (GtkWidget *widget, double value)
+{
+    return g_strdup_printf ("%.4f", to_scale (value));
+}
+
+static app_t *
+app_new (pixman_image_t *original)
+{
+    GtkWidget *widget;
+    app_t *app = g_malloc (sizeof *app);
+    GError *err = NULL;
+
+    app->builder = gtk_builder_new ();
+    app->original = original;
+
+    if (!gtk_builder_add_from_file (app->builder, "scale.ui", &err))
+	g_error ("Could not read file scale.ui: %s", err->message);
+
+    app->scale_x_adjustment =
+        GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "scale_x_adjustment"));
+    app->scale_y_adjustment =
+        GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "scale_y_adjustment"));
+    app->rotate_adjustment =
+        GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "rotate_adjustment"));
+
+    g_signal_connect (app->scale_x_adjustment, "value_changed", G_CALLBACK (rescale), app);
+    g_signal_connect (app->scale_y_adjustment, "value_changed", G_CALLBACK (rescale), app);
+    g_signal_connect (app->rotate_adjustment, "value_changed", G_CALLBACK (rescale), app);
+    
+    widget = get_widget (app, "scale_x_scale");
+    gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL);
+    g_signal_connect (widget, "format_value", G_CALLBACK (format_value), app);
+    widget = get_widget (app, "scale_y_scale");
+    gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL);
+    g_signal_connect (widget, "format_value", G_CALLBACK (format_value), app);
+    widget = get_widget (app, "rotate_scale");
+    gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL);
+
+    widget = get_widget (app, "drawing_area");
+    g_signal_connect (widget, "expose_event", G_CALLBACK (on_expose), app);
+
+    set_up_filter_box (app, "reconstruct_x_combo_box");
+    set_up_filter_box (app, "reconstruct_y_combo_box");
+    set_up_filter_box (app, "sample_x_combo_box");
+    set_up_filter_box (app, "sample_y_combo_box");
+
+    set_up_combo_box (
+        app, "repeat_combo_box", G_N_ELEMENTS (repeats), repeats);
+
+    g_signal_connect (
+	gtk_builder_get_object (app->builder, "lock_checkbutton"),
+	"toggled", G_CALLBACK (rescale), app);
+    
+    rescale (NULL, app);
+    
+    return app;
+}
+
+int
+main (int argc, char **argv)
+{
+    GtkWidget *window;
+    pixman_image_t *image;
+    app_t *app;
+    
+    gtk_init (&argc, &argv);
+
+    if (argc < 2)
+    {
+	printf ("%s <image file>\n", argv[0]);
+	return -1;
+    }
+
+    if (!(image = pixman_image_from_file (argv[1], PIXMAN_a8r8g8b8)))
+    {
+	printf ("Could not load image \"%s\"\n", argv[1]);
+	return -1;
+    }
+
+    app = app_new (image);
+    
+    window = get_widget (app, "main");
+
+    g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL);
+    
+    gtk_window_set_default_size (GTK_WINDOW (window), 1024, 768);
+    
+    gtk_widget_show_all (window);
+    
+    gtk_main ();
+
+    return 0;
+}
diff --git a/demos/scale.ui b/demos/scale.ui
new file mode 100644
index 0000000..f7c0c80
--- /dev/null
+++ b/demos/scale.ui
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkAdjustment" id="rotate_adjustment">
+    <property name="lower">-180</property>
+    <property name="upper">190</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="page_size">10</property>
+  </object>
+  <object class="GtkAdjustment" id="scale_y_adjustment">
+    <property name="lower">-32</property>
+    <property name="upper">42</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="page_size">10</property>
+  </object>
+  <object class="GtkAdjustment" id="scale_x_adjustment">
+    <property name="lower">-32</property>
+    <property name="upper">42</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="page_size">10</property>
+  </object>
+  <object class="GtkWindow" id="main">
+    <child>
+      <object class="GtkHBox" id="u">
+        <property name="visible">True</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolledwindow1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkViewport" id="viewport1">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkDrawingArea" id="drawing_area">
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="box1">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkHBox" id="box2">
+                <property name="visible">True</property>
+                <property name="homogeneous">True</property>
+                <child>
+                  <object class="GtkVBox" id="box3">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes"><b>Scale X</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVScale" id="scale_x_scale">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="adjustment">scale_x_adjustment</property>
+                        <property name="fill_level">32</property>
+                        <property name="value_pos">right</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="box4">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes"><b>Scale Y</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVScale" id="scale_y_scale">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="adjustment">scale_y_adjustment</property>
+                        <property name="fill_level">32</property>
+                        <property name="value_pos">right</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="box5">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes"><b>Rotate</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVScale" id="rotate_scale">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="adjustment">rotate_adjustment</property>
+                        <property name="fill_level">180</property>
+                        <property name="value_pos">right</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="padding">6</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="box6">
+                <property name="visible">True</property>
+		<child>
+		  <object class="GtkCheckButton"
+			  id="lock_checkbutton">
+		    <property name="label" translatable="yes">Lock X and Y Dimensions</property>
+		    <property name="xalign">0.0</property>
+		  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">6</property>
+                    <property name="position">1</property>
+                  </packing>
+		</child>
+                <child>
+                  <object class="GtkTable" id="grid1">
+                    <property name="visible">True</property>
+                    <property name="column_spacing">8</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes"><b>Reconstruct X:</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label5">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes"><b>Reconstruct Y:</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label6">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes"><b>Sample X:</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label7">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes"><b>Sample Y:</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label8">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes"><b>Repeat:</b></property>
+                        <property name="use_markup">True</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="reconstruct_x_combo_box">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="reconstruct_y_combo_box">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="sample_x_combo_box">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="sample_y_combo_box">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="repeat_combo_box">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">4</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="padding">6</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
-- 
1.7.4



More information about the cairo mailing list