[gtk/layout-manager-transform-demo: 3/3] Add another layout manager demo
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/layout-manager-transform-demo: 3/3] Add another layout manager demo
- Date: Thu, 3 Sep 2020 14:09:32 +0000 (UTC)
commit acc2516b3c06091ccb1d5e0238a385c7c41ba46a
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Aug 27 07:16:38 2020 -0400
Add another layout manager demo
This demo uses transforms to place icons on a sphere.
demos/gtk-demo/demo.gresource.xml | 11 +
demos/gtk-demo/demo2layout.c | 204 +++++++++++++
demos/gtk-demo/demo2layout.h | 16 ++
demos/gtk-demo/demo2widget.c | 172 +++++++++++
demos/gtk-demo/demo2widget.h | 11 +
demos/gtk-demo/four_point_transform.c | 90 ++++++
demos/gtk-demo/four_point_transform.h | 13 +
demos/gtk-demo/layoutmanager.c | 2 +-
demos/gtk-demo/layoutmanager2.c | 198 +++++++++++++
demos/gtk-demo/meson.build | 7 +-
demos/gtk-demo/singular_value_decomposition.c | 396 ++++++++++++++++++++++++++
demos/gtk-demo/singular_value_decomposition.h | 17 ++
12 files changed, 1135 insertions(+), 2 deletions(-)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index d9084a96ae..7c9c657f5e 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -136,6 +136,16 @@
<file>demochild.h</file>
<file>demochild.c</file>
</gresource>
+ <gresource prefix="/layoutmanager2">
+ <file>demo2layout.h</file>
+ <file>demo2layout.c</file>
+ <file>demo2widget.h</file>
+ <file>demo2widget.c</file>
+ <file>four_point_transform.h</file>
+ <file>four_point_transform.c</file>
+ <file>singular_value_decomposition.h</file>
+ <file>singular_value_decomposition.c</file>
+ </gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
<file>listview_filebrowser.css</file>
@@ -219,6 +229,7 @@
<file>images.c</file>
<file>infobar.c</file>
<file>layoutmanager.c</file>
+ <file>layoutmanager2.c</file>
<file>links.c</file>
<file>listbox.c</file>
<file>listbox2.c</file>
diff --git a/demos/gtk-demo/demo2layout.c b/demos/gtk-demo/demo2layout.c
new file mode 100644
index 0000000000..fb0dc5a9f8
--- /dev/null
+++ b/demos/gtk-demo/demo2layout.c
@@ -0,0 +1,204 @@
+#include "demo2layout.h"
+#include "four_point_transform.h"
+
+struct _Demo2Layout
+{
+ GtkLayoutManager parent_instance;
+
+ float position;
+ float offset;
+};
+
+struct _Demo2LayoutClass
+{
+ GtkLayoutManagerClass parent_class;
+};
+
+G_DEFINE_TYPE (Demo2Layout, demo2_layout, GTK_TYPE_LAYOUT_MANAGER)
+
+static void
+demo2_layout_measure (GtkLayoutManager *layout_manager,
+ GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ GtkWidget *child;
+ int minimum_size = 0;
+ int natural_size = 0;
+
+ for (child = gtk_widget_get_first_child (widget);
+ child != NULL;
+ child = gtk_widget_get_next_sibling (child))
+ {
+ int child_min = 0, child_nat = 0;
+
+ if (!gtk_widget_should_layout (child))
+ continue;
+
+ gtk_widget_measure (child, orientation, -1,
+ &child_min, &child_nat,
+ NULL, NULL);
+ minimum_size = MAX (minimum_size, child_min);
+ natural_size = MAX (natural_size, child_nat);
+ }
+
+ *minimum = minimum_size;
+ *natural = 3 * natural_size;
+}
+
+
+#define RADIANS(angle) ((angle)*M_PI/180.0);
+
+/* Spherical coordinates */
+#define SX(r,t,p) ((r) * sin (t) * cos (p))
+#define SZ(r,t,p) ((r) * sin (t) * sin (p))
+#define SY(r,t,p) ((r) * cos (t))
+
+static double
+map_offset (double x)
+{
+ x = fmod (x, 180.0);
+ if (x < 0.0)
+ x += 180.0;
+
+ return x;
+}
+
+static void
+demo2_layout_allocate (GtkLayoutManager *layout_manager,
+ GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ GtkWidget *child;
+ GtkRequisition child_req;
+ int i, j, k;
+ float x0, y0;
+ float w, h;
+ graphene_point3d_t p1, p2, p3, p4;
+ graphene_point3d_t q1, q2, q3, q4;
+ double t_1, t_2, p_1, p_2;
+ double r;
+ graphene_matrix_t m;
+ GskTransform *transform;
+ double position = DEMO2_LAYOUT (layout_manager)->position;
+ double offset = DEMO2_LAYOUT (layout_manager)->offset;
+
+ /* for simplicity, assume all children are the same size */
+ gtk_widget_get_preferred_size (gtk_widget_get_first_child (widget), &child_req, NULL);
+ w = child_req.width;
+ h = child_req.height;
+
+ r = 300;
+ x0 = y0 = 300;
+
+ for (child = gtk_widget_get_first_child (widget), i = 0;
+ child != NULL;
+ child = gtk_widget_get_next_sibling (child), i++)
+ {
+ j = i / 36;
+ k = i % 36;
+
+ gtk_widget_set_child_visible (child, FALSE);
+
+ graphene_point3d_init (&p1, 0., 0., 1.);
+ graphene_point3d_init (&p2, w, 0., 1.);
+ graphene_point3d_init (&p3, 0., h, 1.);
+ graphene_point3d_init (&p4, w, h, 1.);
+
+ t_1 = RADIANS (map_offset (offset + 10 * j));
+ t_2 = RADIANS (map_offset (offset + 10 * (j + 1)));
+ p_1 = RADIANS (position + 10 * k);
+ p_2 = RADIANS (position + 10 * (k + 1));
+
+ if (t_2 < t_1)
+ continue;
+
+ if (SZ (r, t_1, p_1) > 0 ||
+ SZ (r, t_2, p_1) > 0 ||
+ SZ (r, t_1, p_2) > 0 ||
+ SZ (r, t_2, p_2) > 0)
+ continue;
+
+ gtk_widget_set_child_visible (child, TRUE);
+
+ graphene_point3d_init (&q1, x0 + SX (r, t_1, p_1), y0 + SY (r, t_1, p_1), SZ (r, t_1, p_1));
+ graphene_point3d_init (&q2, x0 + SX (r, t_2, p_1), y0 + SY (r, t_2, p_1), SZ (r, t_2, p_1));
+ graphene_point3d_init (&q3, x0 + SX (r, t_1, p_2), y0 + SY (r, t_1, p_2), SZ (r, t_1, p_2));
+ graphene_point3d_init (&q4, x0 + SX (r, t_2, p_2), y0 + SY (r, t_2, p_2), SZ (r, t_2, p_2));
+
+ /* Get a matrix that moves p1 -> q1, p2 -> q2, ... */
+ perspective_3d (&p1, &p2, &p3, &p4,
+ &q1, &q2, &q3, &q4,
+ &m);
+
+ transform = gsk_transform_matrix (NULL, &m);
+
+ /* Since our matrix was built for transforming points with z = 1,
+ * prepend a translation to the z = 1 plane.
+ */
+ transform = gsk_transform_translate_3d (transform,
+ &GRAPHENE_POINT3D_INIT (0, 0, 1));
+
+ gtk_widget_allocate (child, w, h, -1, transform);
+ }
+}
+
+static GtkSizeRequestMode
+demo2_layout_get_request_mode (GtkLayoutManager *layout_manager,
+ GtkWidget *widget)
+{
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+
+static void
+demo2_layout_class_init (Demo2LayoutClass *klass)
+{
+ GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (klass);
+
+ layout_class->get_request_mode = demo2_layout_get_request_mode;
+ layout_class->measure = demo2_layout_measure;
+ layout_class->allocate = demo2_layout_allocate;
+}
+
+static void
+demo2_layout_init (Demo2Layout *self)
+{
+}
+
+GtkLayoutManager *
+demo2_layout_new (void)
+{
+ return g_object_new (DEMO2_TYPE_LAYOUT, NULL);
+}
+
+void
+demo2_layout_set_position (Demo2Layout *layout,
+ float position)
+{
+ layout->position = position;
+}
+
+float
+demo2_layout_get_position (Demo2Layout *layout)
+{
+ return layout->position;
+}
+
+void
+demo2_layout_set_offset (Demo2Layout *layout,
+ float offset)
+{
+ layout->offset = offset;
+}
+
+float
+demo2_layout_get_offset (Demo2Layout *layout)
+{
+ return layout->offset;
+}
diff --git a/demos/gtk-demo/demo2layout.h b/demos/gtk-demo/demo2layout.h
new file mode 100644
index 0000000000..4bb84ab241
--- /dev/null
+++ b/demos/gtk-demo/demo2layout.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define DEMO2_TYPE_LAYOUT (demo2_layout_get_type ())
+
+G_DECLARE_FINAL_TYPE (Demo2Layout, demo2_layout, DEMO2, LAYOUT, GtkLayoutManager)
+
+GtkLayoutManager * demo2_layout_new (void);
+
+void demo2_layout_set_position (Demo2Layout *layout,
+ float position);
+float demo2_layout_get_position (Demo2Layout *layout);
+void demo2_layout_set_offset (Demo2Layout *layout,
+ float offset);
+float demo2_layout_get_offset (Demo2Layout *layout);
diff --git a/demos/gtk-demo/demo2widget.c b/demos/gtk-demo/demo2widget.c
new file mode 100644
index 0000000000..4b1aebadb5
--- /dev/null
+++ b/demos/gtk-demo/demo2widget.c
@@ -0,0 +1,172 @@
+#include "demo2widget.h"
+#include "demo2layout.h"
+
+struct _Demo2Widget
+{
+ GtkWidget parent_instance;
+
+ gint64 start_time;
+ gint64 end_time;
+ float start_position;
+ float end_position;
+ float start_offset;
+ float end_offset;
+ gboolean animating;
+};
+
+struct _Demo2WidgetClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (Demo2Widget, demo2_widget, GTK_TYPE_WIDGET)
+
+static void
+demo2_widget_init (Demo2Widget *self)
+{
+ gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
+}
+
+static void
+demo2_widget_dispose (GObject *object)
+{
+ GtkWidget *child;
+
+ while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))))
+ gtk_widget_unparent (child);
+
+ G_OBJECT_CLASS (demo2_widget_parent_class)->dispose (object);
+}
+
+/* From clutter-easing.c, based on Robert Penner's
+ * infamous easing equations, MIT license.
+ */
+static double
+ease_out_cubic (double t)
+{
+ double p = t - 1;
+
+ return p * p * p + 1;
+}
+
+static gboolean
+update_position (GtkWidget *widget,
+ GdkFrameClock *clock,
+ gpointer data)
+{
+ Demo2Widget *self = DEMO2_WIDGET (widget);
+ Demo2Layout *layout = DEMO2_LAYOUT (gtk_widget_get_layout_manager (widget));
+ gint64 now;
+ double t;
+
+ now = gdk_frame_clock_get_frame_time (clock);
+
+ if (now >= self->end_time)
+ {
+ self->animating = FALSE;
+
+ return G_SOURCE_REMOVE;
+ }
+
+ t = (now - self->start_time) / (double) (self->end_time - self->start_time);
+
+ t = ease_out_cubic (t);
+
+ demo2_layout_set_position (layout, self->start_position + t * (self->end_position - self->start_position));
+ demo2_layout_set_offset (layout, self->start_offset + t * (self->end_offset - self->start_offset));
+ gtk_widget_queue_allocate (widget);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+rotate_sphere (GtkWidget *widget,
+ const char *action,
+ GVariant *parameters)
+{
+ Demo2Widget *self = DEMO2_WIDGET (widget);
+ Demo2Layout *layout = DEMO2_LAYOUT (gtk_widget_get_layout_manager (widget));
+ GtkOrientation orientation;
+ int direction;
+
+ g_variant_get (parameters, "(ii)", &orientation, &direction);
+
+ self->end_position = self->start_position = demo2_layout_get_position (layout);
+ self->end_offset = self->start_offset = demo2_layout_get_offset (layout);
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ self->end_position += 10 * direction;
+ else
+ self->end_offset += 10 * direction;
+ self->start_time = g_get_monotonic_time ();
+ self->end_time = self->start_time + 0.5 * G_TIME_SPAN_SECOND;
+
+ if (!self->animating)
+ {
+ gtk_widget_add_tick_callback (widget, update_position, NULL, NULL);
+ self->animating = TRUE;
+ }
+}
+
+static void
+demo2_widget_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ GtkWidget *child;
+
+ for (child = gtk_widget_get_first_child (widget);
+ child != NULL;
+ child = gtk_widget_get_next_sibling (child))
+ {
+ /* our layout manager sets this for children that are out of view */
+ if (!gtk_widget_get_child_visible (child))
+ continue;
+
+ gtk_widget_snapshot_child (widget, child, snapshot);
+ }
+}
+
+static void
+demo2_widget_class_init (Demo2WidgetClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+ object_class->dispose = demo2_widget_dispose;
+
+ widget_class->snapshot = demo2_widget_snapshot;
+
+ gtk_widget_class_install_action (widget_class, "rotate", "(ii)", rotate_sphere);
+
+ gtk_widget_class_add_binding_action (widget_class,
+ GDK_KEY_Left, 0,
+ "rotate",
+ "(ii)", GTK_ORIENTATION_HORIZONTAL, -1);
+ gtk_widget_class_add_binding_action (widget_class,
+ GDK_KEY_Right, 0,
+ "rotate",
+ "(ii)", GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_widget_class_add_binding_action (widget_class,
+ GDK_KEY_Up, 0,
+ "rotate",
+ "(ii)", GTK_ORIENTATION_VERTICAL, 1);
+ gtk_widget_class_add_binding_action (widget_class,
+ GDK_KEY_Down, 0,
+ "rotate",
+ "(ii)", GTK_ORIENTATION_VERTICAL, -1);
+
+ /* here is where we use our custom layout manager */
+ gtk_widget_class_set_layout_manager_type (widget_class, DEMO2_TYPE_LAYOUT);
+}
+
+GtkWidget *
+demo2_widget_new (void)
+{
+ return g_object_new (DEMO2_TYPE_WIDGET, NULL);
+}
+
+void
+demo2_widget_add_child (Demo2Widget *self,
+ GtkWidget *child)
+{
+ gtk_widget_set_parent (child, GTK_WIDGET (self));
+}
diff --git a/demos/gtk-demo/demo2widget.h b/demos/gtk-demo/demo2widget.h
new file mode 100644
index 0000000000..54529f95c1
--- /dev/null
+++ b/demos/gtk-demo/demo2widget.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define DEMO2_TYPE_WIDGET (demo2_widget_get_type ())
+G_DECLARE_FINAL_TYPE (Demo2Widget, demo2_widget, DEMO2, WIDGET, GtkWidget)
+
+GtkWidget * demo2_widget_new (void);
+
+void demo2_widget_add_child (Demo2Widget *self,
+ GtkWidget *child);
diff --git a/demos/gtk-demo/four_point_transform.c b/demos/gtk-demo/four_point_transform.c
new file mode 100644
index 0000000000..9df10ef163
--- /dev/null
+++ b/demos/gtk-demo/four_point_transform.c
@@ -0,0 +1,90 @@
+#include "four_point_transform.h"
+#include "singular_value_decomposition.h"
+
+/* Make a 4x4 matrix that maps
+ * e1 -> p1
+ * e2 -> p3
+ * e3 -> p3
+ * (1,1,1,0) -> p4
+ */
+static void
+unit_to (graphene_point3d_t *p1,
+ graphene_point3d_t *p2,
+ graphene_point3d_t *p3,
+ graphene_point3d_t *p4,
+ graphene_matrix_t *m)
+{
+ graphene_vec3_t v1, v2, v3, v4;
+ graphene_vec4_t vv1, vv2, vv3, vv4, p;
+ graphene_matrix_t u, s;
+ float v[16] = { 0., };
+ double A[16];
+ double U[16];
+ double S[4];
+ double V[16];
+ double B[4];
+ double x[4];
+ int i, j;
+
+ graphene_point3d_to_vec3 (p1, &v1);
+ graphene_point3d_to_vec3 (p2, &v2);
+ graphene_point3d_to_vec3 (p3, &v3);
+ graphene_point3d_to_vec3 (p4, &v4);
+
+ graphene_vec4_init_from_vec3 (&vv1, &v1, 1.);
+ graphene_vec4_init_from_vec3 (&vv2, &v2, 1.);
+ graphene_vec4_init_from_vec3 (&vv3, &v3, 1.);
+ graphene_vec4_init_from_vec3 (&vv4, &v4, 1.);
+
+ graphene_vec4_init (&p, 0., 0., 0., 1.);
+
+ graphene_matrix_init_from_vec4 (&u, &vv1, &vv2, &vv3, &p);
+
+ /* solve x * u = vv4 */
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ A[j * 4 + i] = graphene_matrix_get_value (&u, i, j);
+
+ B[0] = graphene_vec4_get_x (&vv4);
+ B[1] = graphene_vec4_get_y (&vv4);
+ B[2] = graphene_vec4_get_z (&vv4);
+ B[3] = graphene_vec4_get_w (&vv4);
+
+ singular_value_decomposition (A, 4, 4, U, S, V);
+ singular_value_decomposition_solve (U, S, V, 4, 4, B, x);
+
+ v[ 0] = x[0];
+ v[ 5] = x[1];
+ v[10] = x[2];
+ v[15] = 1;
+
+ graphene_matrix_init_from_float (&s, (const float *)&v);
+ graphene_matrix_multiply (&s, &u, m);
+}
+
+/* Make a 4x4 matrix that maps
+ * p1 -> q1
+ * p2 -> q2
+ * p3 -> q3
+ * p4 -> q4
+ */
+void
+perspective_3d (graphene_point3d_t *p1,
+ graphene_point3d_t *p2,
+ graphene_point3d_t *p3,
+ graphene_point3d_t *p4,
+ graphene_point3d_t *q1,
+ graphene_point3d_t *q2,
+ graphene_point3d_t *q3,
+ graphene_point3d_t *q4,
+ graphene_matrix_t *m)
+{
+ graphene_matrix_t a, a_inv, b;
+
+ unit_to (p1, p2, p3, p4, &a);
+ unit_to (q1, q2, q3, q4, &b);
+
+ graphene_matrix_inverse (&a, &a_inv);
+ graphene_matrix_multiply (&a_inv, &b, m);
+}
diff --git a/demos/gtk-demo/four_point_transform.h b/demos/gtk-demo/four_point_transform.h
new file mode 100644
index 0000000000..44b73c21b5
--- /dev/null
+++ b/demos/gtk-demo/four_point_transform.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <graphene.h>
+
+void perspective_3d (graphene_point3d_t *p1,
+ graphene_point3d_t *p2,
+ graphene_point3d_t *p3,
+ graphene_point3d_t *p4,
+ graphene_point3d_t *q1,
+ graphene_point3d_t *q2,
+ graphene_point3d_t *q3,
+ graphene_point3d_t *q4,
+ graphene_matrix_t *m);
diff --git a/demos/gtk-demo/layoutmanager.c b/demos/gtk-demo/layoutmanager.c
index e01d7c981e..b07c453798 100644
--- a/demos/gtk-demo/layoutmanager.c
+++ b/demos/gtk-demo/layoutmanager.c
@@ -1,4 +1,4 @@
-/* Layout Manager
+/* Layout Manager/Transition
*
* This demo shows a simple example of a custom layout manager
* and a widget using it. The layout manager places the children
diff --git a/demos/gtk-demo/layoutmanager2.c b/demos/gtk-demo/layoutmanager2.c
new file mode 100644
index 0000000000..c6bccdcc0a
--- /dev/null
+++ b/demos/gtk-demo/layoutmanager2.c
@@ -0,0 +1,198 @@
+/* Layout Manager/Transformation
+ *
+ * This demo shows how to use transforms in a nontrivial
+ * way with a custom layout manager. The layout manager places
+ * icons on a sphere that can be rotated using arrow keys.
+ */
+
+#include <gtk/gtk.h>
+
+#include "demo2widget.h"
+#include "demo2layout.h"
+#include "demochild.h"
+
+GtkWidget *
+do_layoutmanager2 (GtkWidget *parent)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window)
+ {
+ GtkWidget *widget;
+ GtkWidget *child;
+ const char *name[] = {
+ "action-unavailable-symbolic",
+ "address-book-new-symbolic",
+ "application-exit-symbolic",
+ "appointment-new-symbolic",
+ "bookmark-new-symbolic",
+ "call-start-symbolic",
+ "call-stop-symbolic",
+ "camera-switch-symbolic",
+ "chat-message-new-symbolic",
+ "color-select-symbolic",
+ "contact-new-symbolic",
+ "document-edit-symbolic",
+ "document-new-symbolic",
+ "document-open-recent-symbolic",
+ "document-open-symbolic",
+ "document-page-setup-symbolic",
+ "document-print-preview-symbolic",
+ "document-print-symbolic",
+ "document-properties-symbolic",
+ "document-revert-symbolic-rtl",
+ "document-revert-symbolic",
+ "document-save-as-symbolic",
+ "document-save-symbolic",
+ "document-send-symbolic",
+ "edit-clear-all-symbolic",
+ "edit-clear-symbolic-rtl",
+ "edit-clear-symbolic",
+ "edit-copy-symbolic",
+ "edit-cut-symbolic",
+ "edit-delete-symbolic",
+ "edit-find-replace-symbolic",
+ "edit-find-symbolic",
+ "edit-paste-symbolic",
+ "edit-redo-symbolic-rtl",
+ "edit-redo-symbolic",
+ "edit-select-all-symbolic",
+ "edit-select-symbolic",
+ "edit-undo-symbolic-rtl",
+ "edit-undo-symbolic",
+ "error-correct-symbolic",
+ "find-location-symbolic",
+ "folder-new-symbolic",
+ "font-select-symbolic",
+ "format-indent-less-symbolic-rtl",
+ "format-indent-less-symbolic",
+ "format-indent-more-symbolic-rtl",
+ "format-indent-more-symbolic",
+ "format-justify-center-symbolic",
+ "format-justify-fill-symbolic",
+ "format-justify-left-symbolic",
+ "format-justify-right-symbolic",
+ "format-text-bold-symbolic",
+ "format-text-direction-symbolic-rtl",
+ "format-text-direction-symbolic",
+ "format-text-italic-symbolic",
+ "format-text-strikethrough-symbolic",
+ "format-text-underline-symbolic",
+ "go-bottom-symbolic",
+ "go-down-symbolic",
+ "go-first-symbolic-rtl",
+ "go-first-symbolic",
+ "go-home-symbolic",
+ "go-jump-symbolic-rtl",
+ "go-jump-symbolic",
+ "go-last-symbolic-rtl",
+ "go-last-symbolic",
+ "go-next-symbolic-rtl",
+ "go-next-symbolic",
+ "go-previous-symbolic-rtl",
+ "go-previous-symbolic",
+ "go-top-symbolic",
+ "go-up-symbolic",
+ "help-about-symbolic",
+ "insert-image-symbolic",
+ "insert-link-symbolic",
+ "insert-object-symbolic",
+ "insert-text-symbolic",
+ "list-add-symbolic",
+ "list-remove-all-symbolic",
+ "list-remove-symbolic",
+ "mail-forward-symbolic",
+ "mail-mark-important-symbolic",
+ "mail-mark-junk-symbolic",
+ "mail-mark-notjunk-symbolic",
+ "mail-message-new-symbolic",
+ "mail-reply-all-symbolic",
+ "mail-reply-sender-symbolic",
+ "mail-send-receive-symbolic",
+ "mail-send-symbolic",
+ "mark-location-symbolic",
+ "media-eject-symbolic",
+ "media-playback-pause-symbolic",
+ "media-playback-start-symbolic",
+ "media-playback-stop-symbolic",
+ "media-record-symbolic"
+ "media-seek-backward-symbolic",
+ "media-seek-forward-symbolic",
+ "media-skip-backward-symbolic",
+ "media-skip-forward-symbolic",
+ "media-view-subtitles-symbolic",
+ "object-flip-horizontal-symbolic",
+ "object-flip-vertical-symbolic",
+ "object-rotate-left-symbolic",
+ "object-rotate-right-symbolic",
+ "object-select-symbolic",
+ "open-menu-symbolic",
+ "process-stop-symbolic",
+ "send-to-symbolic",
+ "sidebar-hide-symbolic",
+ "sidebar-show-symbolic",
+ "star-new-symbolic",
+ "system-log-out-symbolic",
+ "system-reboot-symbolic",
+ "system-run-symbolic",
+ "system-search-symbolic",
+ "system-shutdown-symbolic",
+ "system-switch-user-symbolic",
+ "tab-new-symbolic",
+ "tools-check-spelling-symbolic",
+ "value-decrease-symbolic",
+ "value-increase-symbolic",
+ "view-app-grid-symbolic",
+ "view-conceal-symbolic",
+ "view-continuous-symbolic",
+ "view-dual-symbolic",
+ "view-fullscreen-symbolic",
+ "view-grid-symbolic",
+ "view-list-bullet-symbolic",
+ "view-list-ordered-symbolic",
+ "view-list-symbolic",
+ "view-mirror-symbolic",
+ "view-more-horizontal-symbolic",
+ "view-more-symbolic",
+ "view-paged-symbolic",
+ "view-pin-symbolic",
+ "view-refresh-symbolic",
+ "view-restore-symbolic",
+ "view-reveal-symbolic",
+ "view-sort-ascending-symbolic",
+ "view-sort-descending-symbolic",
+ "zoom-fit-best-symbolic",
+ "zoom-in-symbolic",
+ "zoom-original-symbolic",
+ "zoom-out-symbolic",
+ };
+ int i;
+
+ window = gtk_window_new ();
+ gtk_window_set_title (GTK_WINDOW (window), "Layout Manager—Transformation");
+ gtk_window_set_default_size (GTK_WINDOW (window), 600, 620);
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
+
+ widget = demo2_widget_new ();
+
+ for (i = 0; i < 18 * 36; i++)
+ {
+ child = gtk_image_new_from_icon_name (name[i % G_N_ELEMENTS (name)]);
+ gtk_widget_set_margin_start (child, 4);
+ gtk_widget_set_margin_end (child, 4);
+ gtk_widget_set_margin_top (child, 4);
+ gtk_widget_set_margin_bottom (child, 4);
+ demo2_widget_add_child (DEMO2_WIDGET (widget), child);
+ }
+
+ gtk_window_set_child (GTK_WINDOW (window), widget);
+ }
+
+ if (!gtk_widget_get_visible (window))
+ gtk_widget_show (window);
+ else
+ gtk_window_destroy (GTK_WINDOW (window));
+
+ return window;
+
+}
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 2ef7a443aa..05b32c6f46 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -39,6 +39,7 @@ demos = files([
'images.c',
'infobar.c',
'layoutmanager.c',
+ 'layoutmanager2.c',
'links.c',
'listbox.c',
'listbox2.c',
@@ -103,7 +104,11 @@ extra_demo_sources = files(['main.c',
'demotaggedentry.c',
'demochild.c',
'demolayout.c',
- 'demowidget.c'])
+ 'demowidget.c',
+ 'demo2layout.c',
+ 'singular_value_decomposition.c',
+ 'four_point_transform.c',
+ 'demo2widget.c'])
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')
diff --git a/demos/gtk-demo/singular_value_decomposition.c b/demos/gtk-demo/singular_value_decomposition.c
new file mode 100644
index 0000000000..05d04d0667
--- /dev/null
+++ b/demos/gtk-demo/singular_value_decomposition.c
@@ -0,0 +1,396 @@
+#include <string.h>
+#include <float.h>
+#include <math.h>
+#include <glib.h>
+
+/* See Golub and Reinsch,
+ * "Handbook for Automatic Computation vol II - Linear Algebra",
+ * Springer, 1971
+ */
+
+
+#define MAX_ITERATION_COUNT 30
+
+static void
+householder_reduction (double *A,
+ int nrows,
+ int ncols,
+ double *U,
+ double *V,
+ double *diagonal,
+ double *superdiagonal)
+{
+ int i, j, k, ip1;
+ double s, s2, si, scale;
+ double *pu, *pui, *pv, *pvi;
+ double half_norm_squared;
+
+ memcpy (U, A, sizeof (double) * nrows * ncols);
+
+ diagonal[0] = 0.0;
+ s = 0.0;
+ scale = 0.0;
+ for (i = 0, pui = U, ip1 = 1;
+ i < ncols;
+ pui += ncols, i++, ip1++)
+ {
+ superdiagonal[i] = scale * s;
+
+ for (j = i, pu = pui, scale = 0.0;
+ j < nrows;
+ j++, pu += ncols)
+ scale += fabs( *(pu + i) );
+
+ if (scale > 0.0)
+ {
+ for (j = i, pu = pui, s2 = 0.0; j < nrows; j++, pu += ncols)
+ {
+ *(pu + i) /= scale;
+ s2 += *(pu + i) * *(pu + i);
+ }
+ s = *(pui + i) < 0.0 ? sqrt (s2) : -sqrt (s2);
+ half_norm_squared = *(pui + i) * s - s2;
+ *(pui + i) -= s;
+
+ for (j = ip1; j < ncols; j++)
+ {
+ for (k = i, si = 0.0, pu = pui; k < nrows; k++, pu += ncols)
+ si += *(pu + i) * *(pu + j);
+ si /= half_norm_squared;
+ for (k = i, pu = pui; k < nrows; k++, pu += ncols)
+ *(pu + j) += si * *(pu + i);
+ }
+ }
+ for (j = i, pu = pui; j < nrows; j++, pu += ncols)
+ *(pu + i) *= scale;
+ diagonal[i] = s * scale;
+ s = 0.0;
+ scale = 0.0;
+ if (i >= nrows || i == ncols - 1)
+ continue;
+ for (j = ip1; j < ncols; j++)
+ scale += fabs (*(pui + j));
+ if (scale > 0.0)
+ {
+ for (j = ip1, s2 = 0.0; j < ncols; j++)
+ {
+ *(pui + j) /= scale;
+ s2 += *(pui + j) * *(pui + j);
+ }
+ s = *(pui + ip1) < 0.0 ? sqrt (s2) : -sqrt (s2);
+ half_norm_squared = *(pui + ip1) * s - s2;
+ *(pui + ip1) -= s;
+ for (k = ip1; k < ncols; k++)
+ superdiagonal[k] = *(pui + k) / half_norm_squared;
+ if (i < (nrows - 1))
+ {
+ for (j = ip1, pu = pui + ncols; j < nrows; j++, pu += ncols)
+ {
+ for (k = ip1, si = 0.0; k < ncols; k++)
+ si += *(pui + k) * *(pu + k);
+ for (k = ip1; k < ncols; k++)
+ *(pu + k) += si * superdiagonal[k];
+ }
+ }
+ for (k = ip1; k < ncols; k++)
+ *(pui + k) *= scale;
+ }
+ }
+
+ pui = U + ncols * (ncols - 2);
+ pvi = V + ncols * (ncols - 1);
+ *(pvi + ncols - 1) = 1.0;
+ s = superdiagonal[ncols - 1];
+ pvi -= ncols;
+ for (i = ncols - 2, ip1 = ncols - 1;
+ i >= 0;
+ i--, pui -= ncols, pvi -= ncols, ip1--)
+ {
+ if (s != 0.0)
+ {
+ pv = pvi + ncols;
+ for (j = ip1; j < ncols; j++, pv += ncols)
+ *(pv + i) = ( *(pui + j) / *(pui + ip1) ) / s;
+ for (j = ip1; j < ncols; j++)
+ {
+ si = 0.0;
+ for (k = ip1, pv = pvi + ncols; k < ncols; k++, pv += ncols)
+ si += *(pui + k) * *(pv + j);
+ for (k = ip1, pv = pvi + ncols; k < ncols; k++, pv += ncols)
+ *(pv + j) += si * *(pv + i);
+ }
+ }
+ pv = pvi + ncols;
+ for (j = ip1; j < ncols; j++, pv += ncols)
+ {
+ *(pvi + j) = 0.0;
+ *(pv + i) = 0.0;
+ }
+ *(pvi + i) = 1.0;
+ s = superdiagonal[i];
+ }
+
+ pui = U + ncols * (ncols - 1);
+ for (i = ncols - 1, ip1 = ncols;
+ i >= 0;
+ ip1 = i, i--, pui -= ncols)
+ {
+ s = diagonal[i];
+ for (j = ip1; j < ncols; j++)
+ *(pui + j) = 0.0;
+ if (s != 0.0)
+ {
+ for (j = ip1; j < ncols; j++)
+ {
+ si = 0.0;
+ pu = pui + ncols;
+ for (k = ip1; k < nrows; k++, pu += ncols)
+ si += *(pu + i) * *(pu + j);
+ si = (si / *(pui + i)) / s;
+ for (k = i, pu = pui; k < nrows; k++, pu += ncols)
+ *(pu + j) += si * *(pu + i);
+ }
+ for (j = i, pu = pui; j < nrows; j++, pu += ncols)
+ *(pu + i) /= s;
+ }
+ else
+ for (j = i, pu = pui; j < nrows; j++, pu += ncols)
+ *(pu + i) = 0.0;
+ *(pui + i) += 1.0;
+ }
+}
+
+static int
+givens_reduction (int nrows,
+ int ncols,
+ double *U,
+ double *V,
+ double *diagonal,
+ double *superdiagonal)
+{
+ double epsilon;
+ double c, s;
+ double f,g,h;
+ double x,y,z;
+ double *pu, *pv;
+ int i,j,k,m;
+ int rotation_test;
+ int iteration_count;
+
+ for (i = 0, x = 0.0; i < ncols; i++)
+ {
+ y = fabs (diagonal[i]) + fabs (superdiagonal[i]);
+ if (x < y)
+ x = y;
+ }
+ epsilon = x * DBL_EPSILON;
+ for (k = ncols - 1; k >= 0; k--)
+ {
+ iteration_count = 0;
+ while (1)
+ {
+ rotation_test = 1;
+ for (m = k; m >= 0; m--)
+ {
+ if (fabs (superdiagonal[m]) <= epsilon)
+ {
+ rotation_test = 0;
+ break;
+ }
+ if (fabs (diagonal[m-1]) <= epsilon)
+ break;
+ }
+ if (rotation_test)
+ {
+ c = 0.0;
+ s = 1.0;
+ for (i = m; i <= k; i++)
+ {
+ f = s * superdiagonal[i];
+ superdiagonal[i] *= c;
+ if (fabs (f) <= epsilon)
+ break;
+ g = diagonal[i];
+ h = sqrt (f*f + g*g);
+ diagonal[i] = h;
+ c = g / h;
+ s = -f / h;
+ for (j = 0, pu = U; j < nrows; j++, pu += ncols)
+ {
+ y = *(pu + m - 1);
+ z = *(pu + i);
+ *(pu + m - 1 ) = y * c + z * s;
+ *(pu + i) = -y * s + z * c;
+ }
+ }
+ }
+ z = diagonal[k];
+ if (m == k)
+ {
+ if (z < 0.0)
+ {
+ diagonal[k] = -z;
+ for (j = 0, pv = V; j < ncols; j++, pv += ncols)
+ *(pv + k) = - *(pv + k);
+ }
+ break;
+ }
+ else
+ {
+ if (iteration_count >= MAX_ITERATION_COUNT)
+ return -1;
+ iteration_count++;
+ x = diagonal[m];
+ y = diagonal[k-1];
+ g = superdiagonal[k-1];
+ h = superdiagonal[k];
+ f = ((y - z) * ( y + z ) + (g - h) * (g + h))/(2.0 * h * y);
+ g = sqrt (f * f + 1.0);
+ if (f < 0.0)
+ g = -g;
+ f = ((x - z) * (x + z) + h * (y / (f + g) - h)) / x;
+ c = 1.0;
+ s = 1.0;
+ for (i = m + 1; i <= k; i++)
+ {
+ g = superdiagonal[i];
+ y = diagonal[i];
+ h = s * g;
+ g *= c;
+ z = sqrt (f * f + h * h);
+ superdiagonal[i-1] = z;
+ c = f / z;
+ s = h / z;
+ f = x * c + g * s;
+ g = -x * s + g * c;
+ h = y * s;
+ y *= c;
+ for (j = 0, pv = V; j < ncols; j++, pv += ncols)
+ {
+ x = *(pv + i - 1);
+ z = *(pv + i);
+ *(pv + i - 1) = x * c + z * s;
+ *(pv + i) = -x * s + z * c;
+ }
+ z = sqrt (f * f + h * h);
+ diagonal[i - 1] = z;
+ if (z != 0.0)
+ {
+ c = f / z;
+ s = h / z;
+ }
+ f = c * g + s * y;
+ x = -s * g + c * y;
+ for (j = 0, pu = U; j < nrows; j++, pu += ncols)
+ {
+ y = *(pu + i - 1);
+ z = *(pu + i);
+ *(pu + i - 1) = c * y + s * z;
+ *(pu + i) = -s * y + c * z;
+ }
+ }
+ superdiagonal[m] = 0.0;
+ superdiagonal[k] = f;
+ diagonal[k] = x;
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+sort_singular_values (int nrows,
+ int ncols,
+ double *S,
+ double *U,
+ double *V)
+{
+ int i, j, max_index;
+ double temp;
+ double *p1, *p2;
+
+ for (i = 0; i < ncols - 1; i++)
+ {
+ max_index = i;
+ for (j = i + 1; j < ncols; j++)
+ if (S[j] > S[max_index])
+ max_index = j;
+ if (max_index == i)
+ continue;
+ temp = S[i];
+ S[i] = S[max_index];
+ S[max_index] = temp;
+ p1 = U + max_index;
+ p2 = U + i;
+ for (j = 0; j < nrows; j++, p1 += ncols, p2 += ncols)
+ {
+ temp = *p1;
+ *p1 = *p2;
+ *p2 = temp;
+ }
+ p1 = V + max_index;
+ p2 = V + i;
+ for (j = 0; j < ncols; j++, p1 += ncols, p2 += ncols)
+ {
+ temp = *p1;
+ *p1 = *p2;
+ *p2 = temp;
+ }
+ }
+}
+
+int
+singular_value_decomposition (double *A,
+ int nrows,
+ int ncols,
+ double *U,
+ double *S,
+ double *V)
+{
+ double *superdiagonal;
+
+ superdiagonal = g_alloca (sizeof (double) * ncols);
+
+ if (nrows < ncols)
+ return -1;
+
+ householder_reduction (A, nrows, ncols, U, V, S, superdiagonal);
+
+ if (givens_reduction (nrows, ncols, U, V, S, superdiagonal) < 0)
+ return -1;
+
+ sort_singular_values (nrows, ncols, S, U, V);
+
+ return 0;
+}
+
+void
+singular_value_decomposition_solve (double *U,
+ double *S,
+ double *V,
+ int nrows,
+ int ncols,
+ double *B,
+ double *x)
+{
+ int i, j, k;
+ double *pu, *pv;
+ double d;
+ double tolerance;
+
+ tolerance = DBL_EPSILON * S[0] * (double) ncols;
+
+ for ( i = 0, pv = V; i < ncols; i++, pv += ncols)
+ {
+ x[i] = 0.0;
+ for (j = 0; j < ncols; j++)
+ {
+ if (S[j] > tolerance)
+ {
+ for (k = 0, d = 0.0, pu = U; k < nrows; k++, pu += ncols)
+ d += *(pu + j) * B[k];
+ x[i] += d * *(pv + j) / S[j];
+ }
+ }
+ }
+}
diff --git a/demos/gtk-demo/singular_value_decomposition.h b/demos/gtk-demo/singular_value_decomposition.h
new file mode 100644
index 0000000000..9b4c65a2a6
--- /dev/null
+++ b/demos/gtk-demo/singular_value_decomposition.h
@@ -0,0 +1,17 @@
+#pragma once
+
+int singular_value_decomposition (double *A,
+ int nrows,
+ int ncols,
+ double *U,
+ double *S,
+ double *V);
+
+void singular_value_decomposition_solve (double *U,
+ double *S,
+ double *V,
+ int nrows,
+ int ncols,
+ double *B,
+ double *x);
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]