/* canvas.c generated by valac 0.56.19, the Vala compiler
 * generated from canvas.vala, do not modify */

/*
 * Copyright (c) 2025 focus-timer contributors
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * Authors: Kamil Prusko <kamilprusko@gmail.com>
 */

#include <gtk/gtk.h>
#include <glib.h>
#include <float.h>
#include <math.h>
#include <gsk/gsk.h>
#include <glib-object.h>
#include "ft_ui.h"
#include <graphene-gobject.h>
#include <string.h>
#include <gdk/gdk.h>

#define FT_CANVAS_EPSILON 0.00001
#if !defined(VALA_STRICT_C)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
#elif defined(__clang__) && (__clang_major__ >= 16)
#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#endif
#endif

typedef struct _FtCanvas FtCanvas;
typedef struct _FtCanvasClass FtCanvasClass;
typedef struct _FtCanvasPrivate FtCanvasPrivate;
enum  {
	FT_CANVAS_0_PROPERTY,
	FT_CANVAS_X_SCALE_PROPERTY,
	FT_CANVAS_Y_SCALE_PROPERTY,
	FT_CANVAS_X_ORIGIN_PROPERTY,
	FT_CANVAS_Y_ORIGIN_PROPERTY,
	FT_CANVAS_NUM_PROPERTIES
};
static GParamSpec* ft_canvas_properties[FT_CANVAS_NUM_PROPERTIES];
#define _gsk_transform_unref0(var) ((var == NULL) ? NULL : (var = (gsk_transform_unref (var), NULL)))
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
typedef struct _FtCanvasLayout FtCanvasLayout;
typedef struct _FtCanvasLayoutClass FtCanvasLayoutClass;
typedef struct _FtCanvasLayoutChild FtCanvasLayoutChild;
typedef struct _FtCanvasLayoutChildClass FtCanvasLayoutChildClass;
typedef struct _FtCanvasLayoutChildPrivate FtCanvasLayoutChildPrivate;
#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);

struct _FtCanvas {
	GtkWidget parent_instance;
	FtCanvasPrivate * priv;
};

struct _FtCanvasClass {
	GtkWidgetClass parent_class;
};

struct _FtCanvasPrivate {
	gfloat _x_scale;
	gfloat _y_scale;
	gint _x_origin;
	gint _y_origin;
	GskTransform* transform;
	GskTransform* transform_inv;
};

struct _FtCanvasLayoutChild {
	GtkLayoutChild parent_instance;
	FtCanvasLayoutChildPrivate * priv;
	graphene_rect_t range;
	GdkRectangle absolute_bounds;
};

struct _FtCanvasLayoutChildClass {
	GtkLayoutChildClass parent_class;
};

static gint FtCanvas_private_offset;
static gpointer ft_canvas_parent_class = NULL;

static void ft_canvas_invalidate_transform (FtCanvas* self);
static void ft_canvas_queue_resize_children (FtCanvas* self);
static void ft_canvas_set_origin (FtCanvas* self,
                           gint x_origin,
                           gint y_origin);
VALA_EXTERN void ft_canvas_update_origin (FtCanvas* self);
static void ft_canvas_update_transform (FtCanvas* self);
VALA_EXTERN FtCanvasLayoutChild* ft_canvas_get_layout_child (FtCanvas* self,
                                                 GtkWidget* child);
static void ft_canvas_real_dispose (GObject* base);
static void ft_canvas_finalize (GObject * obj);
static GType ft_canvas_get_type_once (void);
static void _vala_ft_canvas_get_property (GObject * object,
                                   guint property_id,
                                   GValue * value,
                                   GParamSpec * pspec);
static void _vala_ft_canvas_set_property (GObject * object,
                                   guint property_id,
                                   const GValue * value,
                                   GParamSpec * pspec);

static inline gpointer
ft_canvas_get_instance_private (FtCanvas* self)
{
	return G_STRUCT_MEMBER_P (self, FtCanvas_private_offset);
}

static void
ft_canvas_invalidate_transform (FtCanvas* self)
{
	g_return_if_fail (self != NULL);
	_gsk_transform_unref0 (self->priv->transform);
	self->priv->transform = NULL;
	_gsk_transform_unref0 (self->priv->transform_inv);
	self->priv->transform_inv = NULL;
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static void
ft_canvas_queue_resize_children (FtCanvas* self)
{
	g_return_if_fail (self != NULL);
	{
		GtkWidget* child = NULL;
		GtkWidget* _tmp0_;
		GtkWidget* _tmp1_;
		_tmp0_ = gtk_widget_get_first_child ((GtkWidget*) self);
		_tmp1_ = _g_object_ref0 (_tmp0_);
		child = _tmp1_;
		{
			gboolean _tmp2_ = FALSE;
			_tmp2_ = TRUE;
			while (TRUE) {
				GtkWidget* _tmp6_;
				GtkWidget* _tmp7_;
				if (!_tmp2_) {
					GtkWidget* _tmp3_;
					GtkWidget* _tmp4_;
					GtkWidget* _tmp5_;
					_tmp3_ = child;
					_tmp4_ = gtk_widget_get_next_sibling (_tmp3_);
					_tmp5_ = _g_object_ref0 (_tmp4_);
					_g_object_unref0 (child);
					child = _tmp5_;
				}
				_tmp2_ = FALSE;
				_tmp6_ = child;
				if (!(_tmp6_ != NULL)) {
					break;
				}
				_tmp7_ = child;
				gtk_widget_queue_resize (_tmp7_);
			}
		}
		_g_object_unref0 (child);
	}
}

/**
         * Set-up the value space. We only need `x-scale` and `y-scale`.
         */
void
ft_canvas_set_scale (FtCanvas* self,
                     gfloat x_scale,
                     gfloat y_scale)
{
	gboolean x_scale_changed = FALSE;
	gboolean y_scale_changed = FALSE;
	gboolean _tmp0_ = FALSE;
	g_return_if_fail (self != NULL);
	_vala_return_if_fail (isfinite (x_scale), "x_scale.is_finite ()");
	_vala_return_if_fail (isfinite (y_scale), "y_scale.is_finite ()");
	x_scale_changed = x_scale != self->priv->_x_scale;
	y_scale_changed = y_scale != self->priv->_y_scale;
	self->priv->_x_scale = x_scale;
	self->priv->_y_scale = y_scale;
	if (x_scale_changed) {
		g_object_notify ((GObject*) self, "x-scale");
	}
	if (y_scale_changed) {
		g_object_notify ((GObject*) self, "y-scale");
	}
	if (x_scale_changed) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = y_scale_changed;
	}
	if (_tmp0_) {
		ft_canvas_invalidate_transform (self);
		gtk_widget_queue_resize ((GtkWidget*) self);
		ft_canvas_queue_resize_children (self);
	}
}

static void
ft_canvas_set_origin (FtCanvas* self,
                      gint x_origin,
                      gint y_origin)
{
	gboolean x_origin_changed = FALSE;
	gboolean y_origin_changed = FALSE;
	gboolean _tmp0_ = FALSE;
	g_return_if_fail (self != NULL);
	x_origin_changed = x_origin != self->priv->_x_origin;
	y_origin_changed = y_origin != self->priv->_y_origin;
	self->priv->_x_origin = x_origin;
	self->priv->_y_origin = y_origin;
	if (x_origin_changed) {
		g_object_notify ((GObject*) self, "x-origin");
	}
	if (y_origin_changed) {
		g_object_notify ((GObject*) self, "y-origin");
	}
	if (x_origin_changed) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = y_origin_changed;
	}
	if (_tmp0_) {
		ft_canvas_invalidate_transform (self);
	}
}

void
ft_canvas_update_origin (FtCanvas* self)
{
	FtCanvasLayout* layout = NULL;
	GtkLayoutManager* _tmp0_;
	GtkLayoutManager* _tmp1_;
	FtCanvasLayout* _tmp2_;
	gint x_origin = 0;
	gint y_origin = 0;
	FtCanvasLayout* _tmp3_;
	gint _tmp4_ = 0;
	gint _tmp5_ = 0;
	gboolean _tmp6_;
	g_return_if_fail (self != NULL);
	_tmp0_ = gtk_widget_get_layout_manager ((GtkWidget*) self);
	_tmp1_ = _tmp0_;
	_tmp2_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, FT_TYPE_CANVAS_LAYOUT, FtCanvasLayout));
	layout = _tmp2_;
	_tmp3_ = layout;
	_tmp6_ = ft_canvas_layout_calculate_origin (_tmp3_, (GtkWidget*) self, &_tmp4_, &_tmp5_);
	x_origin = _tmp4_;
	y_origin = _tmp5_;
	if (_tmp6_) {
		ft_canvas_set_origin (self, x_origin, y_origin);
	}
	_g_object_unref0 (layout);
}

static gpointer
_gsk_transform_ref0 (gpointer self)
{
	return self ? gsk_transform_ref (self) : NULL;
}

static void
ft_canvas_update_transform (FtCanvas* self)
{
	gboolean _tmp0_ = FALSE;
	g_return_if_fail (self != NULL);
	if (((gdouble) fabsf (self->priv->_x_scale)) > FT_CANVAS_EPSILON) {
		_tmp0_ = ((gdouble) fabsf (self->priv->_y_scale)) > FT_CANVAS_EPSILON;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		GskTransform* transform = NULL;
		GskTransform* _tmp1_;
		GskTransform* _tmp2_;
		GskTransform* _tmp3_;
		GskTransform* _tmp4_;
		graphene_point_t _tmp5_ = {0};
		GskTransform* _tmp6_;
		GskTransform* _tmp7_;
		GskTransform* _tmp8_;
		GskTransform* _tmp9_;
		GskTransform* _tmp10_;
		_tmp1_ = gsk_transform_new ();
		transform = _tmp1_;
		_tmp2_ = transform;
		transform = NULL;
		_tmp3_ = gsk_transform_scale (_tmp2_, 1.0f / self->priv->_x_scale, (-1.0f) / self->priv->_y_scale);
		_gsk_transform_unref0 (transform);
		transform = _tmp3_;
		_tmp4_ = transform;
		transform = NULL;
		memset (&_tmp5_, 0, sizeof (graphene_point_t));
		_tmp5_.x = (gfloat) (-self->priv->_x_origin);
		_tmp5_.y = (gfloat) (-self->priv->_y_origin);
		_tmp6_ = gsk_transform_translate (_tmp4_, &_tmp5_);
		_gsk_transform_unref0 (transform);
		transform = _tmp6_;
		_tmp7_ = transform;
		_tmp8_ = _gsk_transform_ref0 (_tmp7_);
		_gsk_transform_unref0 (self->priv->transform);
		self->priv->transform = _tmp8_;
		_tmp9_ = transform;
		transform = NULL;
		_tmp10_ = gsk_transform_invert (_tmp9_);
		_gsk_transform_unref0 (self->priv->transform_inv);
		self->priv->transform_inv = _tmp10_;
		_gsk_transform_unref0 (transform);
	} else {
		_gsk_transform_unref0 (self->priv->transform);
		self->priv->transform = NULL;
		_gsk_transform_unref0 (self->priv->transform_inv);
		self->priv->transform_inv = NULL;
	}
}

/**
         * Transform point from widget coordinates to value coordinates
         */
void
ft_canvas_transform_point (FtCanvas* self,
                           graphene_point_t* point,
                           graphene_point_t* result)
{
	GskTransform* _tmp0_;
	graphene_point_t _tmp1_ = {0};
	GskTransform* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (point != NULL);
	_tmp0_ = self->priv->transform;
	if (_tmp0_ == NULL) {
		ft_canvas_update_transform (self);
	}
	_tmp2_ = self->priv->transform;
	if (_tmp2_ != NULL) {
		GskTransform* _tmp3_;
		graphene_point_t _tmp4_;
		graphene_point_t _tmp5_ = {0};
		_tmp3_ = self->priv->transform;
		_tmp4_ = *point;
		gsk_transform_transform_point (_tmp3_, &_tmp4_, &_tmp5_);
		_tmp1_ = _tmp5_;
	} else {
		graphene_point_t _tmp6_;
		_tmp6_ = *point;
		_tmp1_ = _tmp6_;
	}
	*result = _tmp1_;
	return;
}

/**
         * Transform point from value coordinates to widget coordinates
         */
void
ft_canvas_transform_point_inv (FtCanvas* self,
                               graphene_point_t* point,
                               graphene_point_t* result)
{
	GskTransform* _tmp0_;
	graphene_point_t _tmp1_ = {0};
	GskTransform* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (point != NULL);
	_tmp0_ = self->priv->transform_inv;
	if (_tmp0_ == NULL) {
		ft_canvas_update_transform (self);
	}
	_tmp2_ = self->priv->transform_inv;
	if (_tmp2_ != NULL) {
		GskTransform* _tmp3_;
		graphene_point_t _tmp4_;
		graphene_point_t _tmp5_ = {0};
		_tmp3_ = self->priv->transform_inv;
		_tmp4_ = *point;
		gsk_transform_transform_point (_tmp3_, &_tmp4_, &_tmp5_);
		_tmp1_ = _tmp5_;
	} else {
		graphene_point_t _tmp6_;
		_tmp6_ = *point;
		_tmp1_ = _tmp6_;
	}
	*result = _tmp1_;
	return;
}

void
ft_canvas_calculate_range (FtCanvas* self,
                           gfloat* x_from,
                           gfloat* x_to,
                           gfloat* y_from,
                           gfloat* y_to)
{
	gfloat _vala_x_from = 0.0F;
	gfloat _vala_x_to = 0.0F;
	gfloat _vala_y_from = 0.0F;
	gfloat _vala_y_to = 0.0F;
	FtCanvasLayout* layout = NULL;
	GtkLayoutManager* _tmp0_;
	GtkLayoutManager* _tmp1_;
	FtCanvasLayout* _tmp2_;
	graphene_rect_t range = {0};
	graphene_rect_t _tmp3_ = {0};
	graphene_rect_t _tmp4_;
	graphene_point_t _tmp5_;
	graphene_rect_t _tmp6_;
	graphene_point_t _tmp7_;
	graphene_rect_t _tmp8_;
	graphene_size_t _tmp9_;
	graphene_rect_t _tmp10_;
	graphene_point_t _tmp11_;
	graphene_rect_t _tmp12_;
	graphene_point_t _tmp13_;
	graphene_rect_t _tmp14_;
	graphene_size_t _tmp15_;
	g_return_if_fail (self != NULL);
	_tmp0_ = gtk_widget_get_layout_manager ((GtkWidget*) self);
	_tmp1_ = _tmp0_;
	_tmp2_ = _g_object_ref0 (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, FT_TYPE_CANVAS_LAYOUT, FtCanvasLayout));
	layout = _tmp2_;
	ft_canvas_layout_calculate_range (layout, (GtkWidget*) self, &_tmp3_);
	range = _tmp3_;
	_tmp4_ = range;
	_tmp5_ = _tmp4_.origin;
	_vala_x_from = _tmp5_.x;
	_tmp6_ = range;
	_tmp7_ = _tmp6_.origin;
	_tmp8_ = range;
	_tmp9_ = _tmp8_.size;
	_vala_x_to = _tmp7_.x + _tmp9_.width;
	_tmp10_ = range;
	_tmp11_ = _tmp10_.origin;
	_vala_y_from = _tmp11_.y;
	_tmp12_ = range;
	_tmp13_ = _tmp12_.origin;
	_tmp14_ = range;
	_tmp15_ = _tmp14_.size;
	_vala_y_to = _tmp13_.y + _tmp15_.height;
	_g_object_unref0 (layout);
	if (x_from) {
		*x_from = _vala_x_from;
	}
	if (x_to) {
		*x_to = _vala_x_to;
	}
	if (y_from) {
		*y_from = _vala_y_from;
	}
	if (y_to) {
		*y_to = _vala_y_to;
	}
}

/**
         * Get the layout child for a widget (for advanced usage)
         */
inline FtCanvasLayoutChild*
ft_canvas_get_layout_child (FtCanvas* self,
                            GtkWidget* child)
{
	GtkLayoutManager* _tmp0_ = NULL;
	GtkLayoutManager* _tmp1_;
	GtkLayoutManager* _tmp2_;
	GtkLayoutChild* _tmp3_ = NULL;
	FtCanvasLayoutChild* result;
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (child != NULL, NULL);
	_tmp1_ = gtk_widget_get_layout_manager ((GtkWidget*) self);
	_tmp2_ = _tmp1_;
	_tmp0_ = _tmp2_;
	_tmp3_ = NULL;
	if (_tmp0_ != NULL) {
		GtkLayoutChild* _tmp4_;
		_tmp4_ = gtk_layout_manager_get_layout_child (_tmp0_, child);
		_tmp3_ = _tmp4_;
	}
	result = G_TYPE_CHECK_INSTANCE_CAST (_tmp3_, FT_TYPE_CANVAS_LAYOUT_CHILD, FtCanvasLayoutChild);
	return result;
}

/**
         * Add a widget to the canvas at the given position
         */
void
ft_canvas_add_child (FtCanvas* self,
                     GtkWidget* child,
                     gfloat x,
                     gfloat y)
{
	FtCanvasLayoutChild* layout_child = NULL;
	FtCanvasLayoutChild* _tmp0_;
	FtCanvasLayoutChild* _tmp1_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (child != NULL);
	gtk_widget_set_parent (child, (GtkWidget*) self);
	_tmp0_ = ft_canvas_get_layout_child (self, child);
	_tmp1_ = _g_object_ref0 (_tmp0_);
	layout_child = _tmp1_;
	ft_canvas_layout_child_set_x (layout_child, x);
	ft_canvas_layout_child_set_y (layout_child, y);
	gtk_widget_queue_resize ((GtkWidget*) self);
	_g_object_unref0 (layout_child);
}

/**
         * Remove a widget from the canvas
         */
void
ft_canvas_remove_child (FtCanvas* self,
                        GtkWidget* child)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (child != NULL);
	gtk_widget_unparent (child);
	gtk_widget_queue_resize ((GtkWidget*) self);
}

/**
         * Set the position of a widget in the canvas
         */
void
ft_canvas_set_child_position (FtCanvas* self,
                              GtkWidget* child,
                              gfloat x,
                              gfloat y)
{
	FtCanvasLayoutChild* layout_child = NULL;
	FtCanvasLayoutChild* _tmp0_;
	FtCanvasLayoutChild* _tmp1_;
	FtCanvasLayoutChild* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (child != NULL);
	_tmp0_ = ft_canvas_get_layout_child (self, child);
	_tmp1_ = _g_object_ref0 (_tmp0_);
	layout_child = _tmp1_;
	_tmp2_ = layout_child;
	if (_tmp2_ != NULL) {
		FtCanvasLayoutChild* _tmp3_;
		FtCanvasLayoutChild* _tmp4_;
		_tmp3_ = layout_child;
		ft_canvas_layout_child_set_x (_tmp3_, x);
		_tmp4_ = layout_child;
		ft_canvas_layout_child_set_y (_tmp4_, y);
	}
	gtk_widget_queue_resize ((GtkWidget*) self);
	_g_object_unref0 (layout_child);
}

/**
         * Get the position of a widget in the canvas
         */
void
ft_canvas_get_child_position (FtCanvas* self,
                              GtkWidget* child,
                              gfloat* x,
                              gfloat* y)
{
	gfloat _vala_x = 0.0F;
	gfloat _vala_y = 0.0F;
	FtCanvasLayoutChild* layout_child = NULL;
	FtCanvasLayoutChild* _tmp0_;
	FtCanvasLayoutChild* _tmp1_;
	FtCanvasLayoutChild* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (child != NULL);
	_tmp0_ = ft_canvas_get_layout_child (self, child);
	_tmp1_ = _g_object_ref0 (_tmp0_);
	layout_child = _tmp1_;
	_tmp2_ = layout_child;
	if (_tmp2_ != NULL) {
		FtCanvasLayoutChild* _tmp3_;
		gfloat _tmp4_;
		gfloat _tmp5_;
		FtCanvasLayoutChild* _tmp6_;
		gfloat _tmp7_;
		gfloat _tmp8_;
		_tmp3_ = layout_child;
		_tmp4_ = ft_canvas_layout_child_get_x (_tmp3_);
		_tmp5_ = _tmp4_;
		_vala_x = _tmp5_;
		_tmp6_ = layout_child;
		_tmp7_ = ft_canvas_layout_child_get_y (_tmp6_);
		_tmp8_ = _tmp7_;
		_vala_y = _tmp8_;
	} else {
		_vala_x = 0.0f;
		_vala_y = 0.0f;
	}
	_g_object_unref0 (layout_child);
	if (x) {
		*x = _vala_x;
	}
	if (y) {
		*y = _vala_y;
	}
}

/**
         * Set the origin offset of a widget
         */
void
ft_canvas_set_child_origin (FtCanvas* self,
                            GtkWidget* child,
                            gint x_origin,
                            gint y_origin)
{
	FtCanvasLayoutChild* layout_child = NULL;
	FtCanvasLayoutChild* _tmp0_;
	FtCanvasLayoutChild* _tmp1_;
	FtCanvasLayoutChild* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (child != NULL);
	_tmp0_ = ft_canvas_get_layout_child (self, child);
	_tmp1_ = _g_object_ref0 (_tmp0_);
	layout_child = _tmp1_;
	_tmp2_ = layout_child;
	if (_tmp2_ != NULL) {
		FtCanvasLayoutChild* _tmp3_;
		FtCanvasLayoutChild* _tmp4_;
		_tmp3_ = layout_child;
		ft_canvas_layout_child_set_x_origin (_tmp3_, x_origin);
		_tmp4_ = layout_child;
		ft_canvas_layout_child_set_y_origin (_tmp4_, y_origin);
	}
	_g_object_unref0 (layout_child);
}

/**
         * Set value range of a widget
         */
void
ft_canvas_set_child_range (FtCanvas* self,
                           GtkWidget* child,
                           gfloat x_from,
                           gfloat x_to,
                           gfloat y_from,
                           gfloat y_to)
{
	FtCanvasLayoutChild* layout_child = NULL;
	FtCanvasLayoutChild* _tmp0_;
	FtCanvasLayoutChild* _tmp1_;
	FtCanvasLayoutChild* _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (child != NULL);
	_tmp0_ = ft_canvas_get_layout_child (self, child);
	_tmp1_ = _g_object_ref0 (_tmp0_);
	layout_child = _tmp1_;
	_tmp2_ = layout_child;
	if (_tmp2_ != NULL) {
		FtCanvasLayoutChild* _tmp3_;
		FtCanvasLayoutChild* _tmp4_;
		_tmp3_ = layout_child;
		memset (&_tmp3_->range, 0, sizeof (graphene_rect_t));
		_tmp4_ = layout_child;
		graphene_rect_init (&_tmp4_->range, x_from, y_from, x_to - x_from, y_to - y_from);
	}
	_g_object_unref0 (layout_child);
}

static void
ft_canvas_real_dispose (GObject* base)
{
	FtCanvas * self;
	GtkWidget* child = NULL;
	self = (FtCanvas*) base;
	while (TRUE) {
		GtkWidget* _tmp0_;
		GtkWidget* _tmp1_;
		GtkWidget* _tmp2_;
		GtkWidget* _tmp3_;
		_tmp0_ = gtk_widget_get_first_child ((GtkWidget*) self);
		_tmp1_ = _g_object_ref0 (_tmp0_);
		_g_object_unref0 (child);
		child = _tmp1_;
		_tmp2_ = child;
		if (!(_tmp2_ != NULL)) {
			break;
		}
		_tmp3_ = child;
		gtk_widget_unparent (_tmp3_);
	}
	_gsk_transform_unref0 (self->priv->transform);
	self->priv->transform = NULL;
	_gsk_transform_unref0 (self->priv->transform_inv);
	self->priv->transform_inv = NULL;
	G_OBJECT_CLASS (ft_canvas_parent_class)->dispose ((GObject*) G_TYPE_CHECK_INSTANCE_CAST (self, gtk_widget_get_type (), GtkWidget));
	_g_object_unref0 (child);
}

FtCanvas*
ft_canvas_construct (GType object_type)
{
	FtCanvas * self = NULL;
	self = (FtCanvas*) g_object_new (object_type, NULL);
	return self;
}

FtCanvas*
ft_canvas_new (void)
{
	return ft_canvas_construct (FT_TYPE_CANVAS);
}

gfloat
ft_canvas_get_x_scale (FtCanvas* self)
{
	gfloat result;
	g_return_val_if_fail (self != NULL, -1.0F);
	result = self->priv->_x_scale;
	return result;
}

void
ft_canvas_set_x_scale (FtCanvas* self,
                       gfloat value)
{
	g_return_if_fail (self != NULL);
	if (self->priv->_x_scale == value) {
		return;
	}
	self->priv->_x_scale = value;
	ft_canvas_invalidate_transform (self);
	gtk_widget_queue_resize ((GtkWidget*) self);
	ft_canvas_queue_resize_children (self);
	g_object_notify_by_pspec ((GObject *) self, ft_canvas_properties[FT_CANVAS_X_SCALE_PROPERTY]);
}

gfloat
ft_canvas_get_y_scale (FtCanvas* self)
{
	gfloat result;
	g_return_val_if_fail (self != NULL, -1.0F);
	result = self->priv->_y_scale;
	return result;
}

void
ft_canvas_set_y_scale (FtCanvas* self,
                       gfloat value)
{
	g_return_if_fail (self != NULL);
	if (self->priv->_y_scale == value) {
		return;
	}
	self->priv->_y_scale = value;
	ft_canvas_invalidate_transform (self);
	gtk_widget_queue_resize ((GtkWidget*) self);
	ft_canvas_queue_resize_children (self);
	g_object_notify_by_pspec ((GObject *) self, ft_canvas_properties[FT_CANVAS_Y_SCALE_PROPERTY]);
}

gint
ft_canvas_get_x_origin (FtCanvas* self)
{
	gint result;
	g_return_val_if_fail (self != NULL, -1);
	result = self->priv->_x_origin;
	return result;
}

gint
ft_canvas_get_y_origin (FtCanvas* self)
{
	gint result;
	g_return_val_if_fail (self != NULL, -1);
	result = self->priv->_y_origin;
	return result;
}

static void
ft_canvas_class_init (FtCanvasClass * klass,
                      gpointer klass_data)
{
	ft_canvas_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &FtCanvas_private_offset);
	((GObjectClass *) klass)->dispose = (void (*) (GObject*)) ft_canvas_real_dispose;
	G_OBJECT_CLASS (klass)->get_property = _vala_ft_canvas_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_ft_canvas_set_property;
	G_OBJECT_CLASS (klass)->finalize = ft_canvas_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_CANVAS_X_SCALE_PROPERTY, ft_canvas_properties[FT_CANVAS_X_SCALE_PROPERTY] = g_param_spec_float ("x-scale", "x-scale", "x-scale", -G_MAXFLOAT, G_MAXFLOAT, 0.0F, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_CANVAS_Y_SCALE_PROPERTY, ft_canvas_properties[FT_CANVAS_Y_SCALE_PROPERTY] = g_param_spec_float ("y-scale", "y-scale", "y-scale", -G_MAXFLOAT, G_MAXFLOAT, 0.0F, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	/**
	         * Offset between top-left corner and an origin point.
	         */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_CANVAS_X_ORIGIN_PROPERTY, ft_canvas_properties[FT_CANVAS_X_ORIGIN_PROPERTY] = g_param_spec_int ("x-origin", "x-origin", "x-origin", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY));
	/**
	         * Offset between top-left corner and an origin point.
	         */
	g_object_class_install_property (G_OBJECT_CLASS (klass), FT_CANVAS_Y_ORIGIN_PROPERTY, ft_canvas_properties[FT_CANVAS_Y_ORIGIN_PROPERTY] = g_param_spec_int ("y-origin", "y-origin", "y-origin", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY));
	gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (klass), "canvas");
	gtk_widget_class_set_layout_manager_type (GTK_WIDGET_CLASS (klass), FT_TYPE_CANVAS_LAYOUT);
}

static void
ft_canvas_instance_init (FtCanvas * self,
                         gpointer klass)
{
	self->priv = ft_canvas_get_instance_private (self);
	self->priv->_x_scale = 1.0f;
	self->priv->_y_scale = 1.0f;
	self->priv->_x_origin = 0;
	self->priv->_y_origin = 0;
	self->priv->transform = NULL;
	self->priv->transform_inv = NULL;
}

static void
ft_canvas_finalize (GObject * obj)
{
	FtCanvas * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, FT_TYPE_CANVAS, FtCanvas);
	_gsk_transform_unref0 (self->priv->transform);
	_gsk_transform_unref0 (self->priv->transform_inv);
	G_OBJECT_CLASS (ft_canvas_parent_class)->finalize (obj);
}

/**
     * A container for placing widgets at given coordinates in a user-defined value space.
     * Value space is defined by `x-scale` and `y-scale`. `Canvas` will stretch to accommodate all
     * children. Then it's expected that parent widget will position the canvas, using `transform`
     * for alignment.
     *
     * There is no sub-pixel accuracy here. Items positions are rounded to nearest pixels.
     *
     * Unlike in GTK+, the y-coordinates increase when going up (like in typical charts).
     * Items are positioned from bottom-left corner.
     * Worth a read: https://docs.gtk.org/gtk4/coordinates.html
     */
static GType
ft_canvas_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (FtCanvasClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) ft_canvas_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (FtCanvas), 0, (GInstanceInitFunc) ft_canvas_instance_init, NULL };
	GType ft_canvas_type_id;
	ft_canvas_type_id = g_type_register_static (gtk_widget_get_type (), "FtCanvas", &g_define_type_info, 0);
	FtCanvas_private_offset = g_type_add_instance_private (ft_canvas_type_id, sizeof (FtCanvasPrivate));
	return ft_canvas_type_id;
}

GType
ft_canvas_get_type (void)
{
	static volatile gsize ft_canvas_type_id__once = 0;
	if (g_once_init_enter (&ft_canvas_type_id__once)) {
		GType ft_canvas_type_id;
		ft_canvas_type_id = ft_canvas_get_type_once ();
		g_once_init_leave (&ft_canvas_type_id__once, ft_canvas_type_id);
	}
	return ft_canvas_type_id__once;
}

static void
_vala_ft_canvas_get_property (GObject * object,
                              guint property_id,
                              GValue * value,
                              GParamSpec * pspec)
{
	FtCanvas * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, FT_TYPE_CANVAS, FtCanvas);
	switch (property_id) {
		case FT_CANVAS_X_SCALE_PROPERTY:
		g_value_set_float (value, ft_canvas_get_x_scale (self));
		break;
		case FT_CANVAS_Y_SCALE_PROPERTY:
		g_value_set_float (value, ft_canvas_get_y_scale (self));
		break;
		case FT_CANVAS_X_ORIGIN_PROPERTY:
		g_value_set_int (value, ft_canvas_get_x_origin (self));
		break;
		case FT_CANVAS_Y_ORIGIN_PROPERTY:
		g_value_set_int (value, ft_canvas_get_y_origin (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_ft_canvas_set_property (GObject * object,
                              guint property_id,
                              const GValue * value,
                              GParamSpec * pspec)
{
	FtCanvas * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, FT_TYPE_CANVAS, FtCanvas);
	switch (property_id) {
		case FT_CANVAS_X_SCALE_PROPERTY:
		ft_canvas_set_x_scale (self, g_value_get_float (value));
		break;
		case FT_CANVAS_Y_SCALE_PROPERTY:
		ft_canvas_set_y_scale (self, g_value_get_float (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

