diff options
author | Benjamin Otte <otte@redhat.com> | 2022-06-01 05:53:44 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2022-06-29 23:53:18 +0200 |
commit | 0e49a24aecab26d1fdce2466ff6e4aea26a66927 (patch) | |
tree | 46446117746c6bc6ad2903f0ed0da3faf1aee385 | |
parent | 7536513ef82aa52d00d5fa90492239d0727bf942 (diff) | |
download | gtk+-0e49a24aecab26d1fdce2466ff6e4aea26a66927.tar.gz |
Add GtkCanvas
A canvas is awidget that allows placing widgets onto the canvas using
sophisticated relationships expressed via points, sizes and boxes.
This is all very experimental.
-rw-r--r-- | demos/gtk-demo/canvas_puzzle.c | 79 | ||||
-rw-r--r-- | gtk/gtk.h | 5 | ||||
-rw-r--r-- | gtk/gtkcanvas.c | 427 | ||||
-rw-r--r-- | gtk/gtkcanvas.h | 55 | ||||
-rw-r--r-- | gtk/gtkcanvasbox.c | 286 | ||||
-rw-r--r-- | gtk/gtkcanvasbox.h | 58 | ||||
-rw-r--r-- | gtk/gtkcanvasboxprivate.h | 54 | ||||
-rw-r--r-- | gtk/gtkcanvasitem.c | 353 | ||||
-rw-r--r-- | gtk/gtkcanvasitem.h | 57 | ||||
-rw-r--r-- | gtk/gtkcanvasitemprivate.h | 20 | ||||
-rw-r--r-- | gtk/gtkcanvaslayout.h | 91 | ||||
-rw-r--r-- | gtk/gtkcanvaspoint.c | 297 | ||||
-rw-r--r-- | gtk/gtkcanvaspoint.h | 65 | ||||
-rw-r--r-- | gtk/gtkcanvaspointprivate.h | 52 | ||||
-rw-r--r-- | gtk/gtkcanvassize.c | 392 | ||||
-rw-r--r-- | gtk/gtkcanvassize.h | 66 | ||||
-rw-r--r-- | gtk/gtkcanvassizeprivate.h | 56 | ||||
-rw-r--r-- | gtk/gtktypes.h | 5 | ||||
-rw-r--r-- | gtk/meson.build | 10 |
19 files changed, 2428 insertions, 0 deletions
diff --git a/demos/gtk-demo/canvas_puzzle.c b/demos/gtk-demo/canvas_puzzle.c new file mode 100644 index 0000000000..8fae9fa177 --- /dev/null +++ b/demos/gtk-demo/canvas_puzzle.c @@ -0,0 +1,79 @@ +/* Canvas/Intro + * + * GtkCanvas is a very powerful canvas widget. Here is + * a simple Hello World demo to get accustomed to how + * it works. + */ + +#include <gtk/gtk.h> + +#define WIDTH 400 +#define HEIGHT 300 + +static void +bind_item (GtkListItemFactory *factory, + GtkCanvasItem *ci) +{ + GtkCanvasPoint *point; + GtkCanvasSize *size; + GtkCanvasBox *box; + + widget = gtk_picture_new_for_paintable (gtk_canvas_item_get_item (ci)); + gtk_canvas_item_set_widget (ci, widget); + + /* Also cener the item, so we do something interesting */ + point = gtk_canvas_point_new (WIDTH / 2.0, HEIGHT / 2.0); + size = gtk_canvas_size_new_measure_item (ci, GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN); + box = gtk_canvas_box_new (point, size, 0.5, 0.5); + gtk_canvas_item_set_bounds (ci, box); + gtk_canvas_box_free (box); + gtk_canvas_size_free (size); + gtk_canvas_point_free (point); +} + +GtkWidget * +do_canvas_intro (GtkWidget *do_widget) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkWidget *canvas, *widget; + GListStore *store; + GtkListItemFactory *factory; + + window = gtk_window_new (); + gtk_window_set_display (GTK_WINDOW (window), + gtk_widget_get_display (do_widget)); + gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT); + g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); + + /* GtkCanvas manages its items using an external list. + * We do a very simple thing and put the widgets in the list + * that the canvas should display. + */ + store = g_list_store_new (GTK_TYPE_WIDGET); + widget = gtk_label_new ("Hello World"); + g_list_store_append (store, widget); + + /* GtkCanvas maps the items from the list to the canvas using factories. + * Set up a simple factory here that just maps the widget directly + * onto the canvas. + */ + factory = gtk_signal_list_item_factory_new (); + g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL); + + /* Create the canvas. + * We hand it the factory and the model, and then everything happens by itself. + */ + canvas = gtk_canvas_new (G_LIST_MODEL (store), factory); + gtk_window_set_child (GTK_WINDOW (window), canvas); + } + + if (!gtk_widget_get_visible (window)) + gtk_widget_show (window); + else + gtk_window_destroy (GTK_WINDOW (window)); + + return window; +} @@ -59,6 +59,11 @@ #include <gtk/gtkbuilderscope.h> #include <gtk/gtkbutton.h> #include <gtk/gtkcalendar.h> +#include <gtk/gtkcanvas.h> +#include <gtk/gtkcanvasbox.h> +#include <gtk/gtkcanvasitem.h> +#include <gtk/gtkcanvaspoint.h> +#include <gtk/gtkcanvassize.h> #include <gtk/gtkcellarea.h> #include <gtk/gtkcellareabox.h> #include <gtk/gtkcellareacontext.h> diff --git a/gtk/gtkcanvas.c b/gtk/gtkcanvas.c new file mode 100644 index 0000000000..18770f5906 --- /dev/null +++ b/gtk/gtkcanvas.c @@ -0,0 +1,427 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#include "config.h" + +#include "gtkcanvas.h" + +#include "gtkcanvasbox.h" +#include "gtkcanvasitemprivate.h" +#include "gtkintl.h" +#include "gtklistitemfactory.h" +#include "gtkwidgetprivate.h" + +#define GDK_ARRAY_NAME gtk_canvas_items +#define GDK_ARRAY_TYPE_NAME GtkCanvasItems +#define GDK_ARRAY_ELEMENT_TYPE GtkCanvasItem * +#define GDK_ARRAY_FREE_FUNC g_object_unref +#include "gdk/gdkarrayimpl.c" + +/** + * GtkCanvas: + * + * `GtkCanvas` is a widget that allows developers to place a list of items + * using their own method. + * + * ![An example GtkCanvas](canvas.png) + */ + +struct _GtkCanvas +{ + GtkWidget parent_instance; + + GListModel *model; + GtkListItemFactory *factory; + + GtkCanvasItems items; +}; + +enum +{ + PROP_0, + PROP_FACTORY, + PROP_MODEL, + + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (GtkCanvas, gtk_canvas, GTK_TYPE_WIDGET) + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +gtk_canvas_clear_factory (GtkCanvas *self) +{ + if (self->factory == NULL) + return; + + g_clear_object (&self->factory); +} + +static void +gtk_canvas_remove_items (GtkCanvas *self, + guint pos, + guint n_items) +{ + guint i; + + /* We first run the factory code on all items, so that the + * factory code can reference the items. + * Only then do we get rid of them. + */ + for (i = pos; i < pos + n_items; i++) + { + gtk_canvas_item_teardown (gtk_canvas_items_get (&self->items, i), self->factory); + } +} + +static void +gtk_canvas_add_items (GtkCanvas *self, + guint pos, + guint n_items) +{ + guint i; + + /* We first create all the items and then run the factory code + * on them, so that the factory code can reference the items. + */ + for (i = pos; i < pos + n_items; i++) + { + *gtk_canvas_items_index (&self->items, i) = gtk_canvas_item_new (self, + g_list_model_get_item (self->model, i)); + } + for (i = pos; i < pos + n_items; i++) + { + gtk_canvas_item_setup (gtk_canvas_items_get (&self->items, i), self->factory); + } +} + +static void +gtk_canvas_items_changed_cb (GListModel *model, + guint pos, + guint removed, + guint added, + GtkCanvas *self) +{ + gtk_canvas_remove_items (self, pos, removed); + + gtk_canvas_items_splice (&self->items, pos, removed, FALSE, NULL, added); + + gtk_canvas_add_items (self, pos, added); +} + +static void +gtk_canvas_clear_model (GtkCanvas *self) +{ + if (self->model == NULL) + return; + + g_signal_handlers_disconnect_by_func (self->model, + gtk_canvas_items_changed_cb, + self); + g_clear_object (&self->model); +} + +static void +gtk_canvas_dispose (GObject *object) +{ + GtkCanvas *self = GTK_CANVAS (object); + + gtk_canvas_clear_model (self); + gtk_canvas_clear_factory (self); + + G_OBJECT_CLASS (gtk_canvas_parent_class)->dispose (object); +} + +static void +gtk_canvas_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkCanvas *self = GTK_CANVAS (object); + + switch (property_id) + { + case PROP_FACTORY: + g_value_set_object (value, self->factory); + break; + + case PROP_MODEL: + g_value_set_object (value, self->model); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_canvas_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCanvas *self = GTK_CANVAS (object); + + switch (property_id) + { + case PROP_FACTORY: + gtk_canvas_set_factory (self, g_value_get_object (value)); + break; + + case PROP_MODEL: + gtk_canvas_set_model (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_canvas_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkCanvas *self = GTK_CANVAS (widget); + gsize i; + + for (i = 0; i < gtk_canvas_items_get_size (&self->items); i++) + { + GtkCanvasItem *ci = gtk_canvas_items_get (&self->items, i); + GtkWidget *child = gtk_canvas_item_get_widget (ci); + graphene_rect_t rect; + int x, y, w, h; + + if (child == NULL) + continue; + + if (!gtk_canvas_box_eval (gtk_canvas_item_get_bounds (ci), &rect)) + rect = *graphene_rect_zero (); + + if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) + { + gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL); + w = MAX (w, ceil (rect.size.width)); + gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL); + h = MAX (h, ceil (rect.size.height)); + } + else + { + gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL); + h = MAX (h, ceil (rect.size.height)); + gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL); + w = MAX (w, ceil (rect.size.width)); + } + + /* FIXME: Adapt to growing rect */ + x = round (rect.origin.x); + y = round (rect.origin.y); + + gtk_widget_size_allocate (child, &(GtkAllocation) { x, y, w, h }, -1); + } +} + +static void +gtk_canvas_class_init (GtkCanvasClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + widget_class->size_allocate = gtk_canvas_allocate; + + gobject_class->dispose = gtk_canvas_dispose; + gobject_class->get_property = gtk_canvas_get_property; + gobject_class->set_property = gtk_canvas_set_property; + + /** + * GtkCanvas:factory: (attributes org.gtk.Property.get=gtk_canvas_get_factory org.gtk.Property.set=gtk_canvas_set_factory) + * + * The factory used to set up canvasitems from items in the model. + */ + properties[PROP_FACTORY] = + g_param_spec_object ("factory", NULL, NULL, + GTK_TYPE_LIST_ITEM_FACTORY, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GtkCanvas:model: (attributes org.gtk.Property.get=gtk_canvas_get_model org.gtk.Property.set=gtk_canvas_set_model) + * + * The model with the items to display + */ + properties[PROP_MODEL] = + g_param_spec_object ("model", NULL, NULL, + G_TYPE_LIST_MODEL, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, N_PROPS, properties); + + gtk_widget_class_set_css_name (widget_class, I_("canvas")); +} + +static void +gtk_canvas_init (GtkCanvas *self) +{ +} + +/** + * gtk_canvas_new: + * @model: (nullable) (transfer full): the model to use + * @factory: (nullable) (transfer full): The factory to populate items with + * + * Creates a new `GtkCanvas` that uses the given @factory for + * mapping items to widgets. + * + * The function takes ownership of the + * arguments, so you can write code like + * ```c + * canvas = gtk_canvas_new (create_model (), + * gtk_builder_list_item_factory_new_from_resource ("/resource.ui")); + * ``` + * + * Returns: a new `GtkCanvas` using the given @model and @factory + */ +GtkWidget * +gtk_canvas_new (GListModel *model, + GtkListItemFactory *factory) +{ + GtkWidget *result; + + g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL); + g_return_val_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory), NULL); + + result = g_object_new (GTK_TYPE_CANVAS, + "factory", factory, + "model", model, + NULL); + + g_clear_object (&model); + g_clear_object (&factory); + + return result; +} + +/** + * gtk_canvas_set_factory: (attributes org.gtk.Method.set_property=factory) + * @self: a `GtkCanvas` + * @factory: (nullable) (transfer none): the factory to use + * + * Sets the `GtkListItemFactory` to use for populating canvas items. + */ +void +gtk_canvas_set_factory (GtkCanvas *self, + GtkListItemFactory *factory) +{ + guint n_items; + + g_return_if_fail (GTK_IS_CANVAS (self)); + g_return_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory)); + + if (self->factory == factory) + return; + + n_items = self->model ? g_list_model_get_n_items (G_LIST_MODEL (self->model)) : 0; + gtk_canvas_remove_items (self, 0, n_items); + + g_set_object (&self->factory, factory); + gtk_canvas_items_splice (&self->items, 0, n_items, FALSE, NULL, n_items); + + gtk_canvas_add_items (self, 0, n_items); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]); +} + +/** + * gtk_canvas_get_factory: (attributes org.gtk.Method.get_property=factory) + * @self: a `GtkCanvas` + * + * Gets the factory that's currently used to populate canvas items. + * + * Returns: (nullable) (transfer none): The factory in use + */ +GtkListItemFactory * +gtk_canvas_get_factory (GtkCanvas *self) +{ + g_return_val_if_fail (GTK_IS_CANVAS (self), NULL); + + return self->factory; +} + +/** + * gtk_canvas_set_model: (attributes org.gtk.Method.set_property=model) + * @self: a `GtkCanvas` + * @model: (nullable) (transfer none): the model to use + * + * Sets the model containing the items to populate the canvas with. + */ +void +gtk_canvas_set_model (GtkCanvas *self, + GListModel *model) +{ + g_return_if_fail (GTK_IS_CANVAS (self)); + g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model)); + + if (self->model == model) + return; + + gtk_canvas_clear_model (self); + + if (model) + { + guint added; + + self->model = g_object_ref (model); + + g_signal_connect (model, + "items-changed", + G_CALLBACK (gtk_canvas_items_changed_cb), + self); + + added = g_list_model_get_n_items (G_LIST_MODEL (model)); + gtk_canvas_items_splice (&self->items, 0, gtk_canvas_items_get_size (&self->items), FALSE, NULL, added); + gtk_canvas_add_items (self, 0, added); + } + else + { + gtk_canvas_items_clear (&self->items); + } + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]); +} + +/** + * gtk_canvas_get_model: (attributes org.gtk.Method.get_property=model) + * @self: a `GtkCanvas` + * + * Gets the model that's currently used for the displayed items. + * + * Returns: (nullable) (transfer none): The model in use + */ +GListModel * +gtk_canvas_get_model (GtkCanvas *self) +{ + g_return_val_if_fail (GTK_IS_CANVAS (self), NULL); + + return self->model; +} + diff --git a/gtk/gtkcanvas.h b/gtk/gtkcanvas.h new file mode 100644 index 0000000000..d8425997a3 --- /dev/null +++ b/gtk/gtkcanvas.h @@ -0,0 +1,55 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_CANVAS_H__ +#define __GTK_CANVAS_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtktypes.h> +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_CANVAS (gtk_canvas_get_type ()) + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkCanvas, gtk_canvas, GTK, CANVAS, GtkWidget) + +GDK_AVAILABLE_IN_ALL +GtkWidget * gtk_canvas_new (GListModel *children, + GtkListItemFactory *factory); + +GDK_AVAILABLE_IN_ALL +void gtk_canvas_set_model (GtkCanvas *self, + GListModel *children); +GDK_AVAILABLE_IN_ALL +GListModel * gtk_canvas_get_model (GtkCanvas *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_set_factory (GtkCanvas *self, + GtkListItemFactory *factory); +GDK_AVAILABLE_IN_ALL +GtkListItemFactory* gtk_canvas_get_factory (GtkCanvas *self); + + +G_END_DECLS + +#endif /* __GTK_CANVAS_H__ */ diff --git a/gtk/gtkcanvasbox.c b/gtk/gtkcanvasbox.c new file mode 100644 index 0000000000..4260990d78 --- /dev/null +++ b/gtk/gtkcanvasbox.c @@ -0,0 +1,286 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + + +/** + * GtkCanvasBox: + * + * `GtkCanvasBox` describes an axis-aligned rectangular box inside + * a `GtkCanvas`. + * + * A box can have no size and be just a single point. + */ + +#include "config.h" + +#include "gtkcanvasboxprivate.h" + +#include "gtkcanvaspointprivate.h" +#include "gtkcanvassizeprivate.h" + +/* {{{ Boilerplate */ + +struct _GtkCanvasBoxClass +{ + const char *type_name; + + void (* copy) (GtkCanvasBox *self, + const GtkCanvasBox *source); + void (* finish) (GtkCanvasBox *self); + gboolean (* eval) (const GtkCanvasBox *self, + graphene_rect_t *rect); +}; + +G_DEFINE_BOXED_TYPE (GtkCanvasBox, gtk_canvas_box, + gtk_canvas_box_copy, + gtk_canvas_box_free) + +static gpointer +gtk_canvas_box_alloc (const GtkCanvasBoxClass *class) +{ + GtkCanvasBox *self = g_slice_new (GtkCanvasBox); + + self->class = class; + + return self; +} + +void +gtk_canvas_box_init_copy (GtkCanvasBox *self, + const GtkCanvasBox *source) +{ + self->class = source->class; + self->class->copy (self, source); +} + +void +gtk_canvas_box_finish (GtkCanvasBox *self) +{ + self->class->finish (self); +} + +/* }}} */ +/* {{{ POINTS */ + +static void +gtk_canvas_box_points_copy (GtkCanvasBox *box, + const GtkCanvasBox *source_box) +{ + GtkCanvasBoxPoints *self = &box->points; + const GtkCanvasBoxPoints *source = &source_box->points; + + gtk_canvas_point_init_copy (&self->point1, &source->point1); + gtk_canvas_point_init_copy (&self->point2, &source->point2); +} + +static void +gtk_canvas_box_points_finish (GtkCanvasBox *box) +{ + GtkCanvasBoxPoints *self = &box->points; + + gtk_canvas_point_finish (&self->point1); + gtk_canvas_point_finish (&self->point2); +} + +static gboolean +gtk_canvas_box_points_eval (const GtkCanvasBox *box, + graphene_rect_t *rect) +{ + const GtkCanvasBoxPoints *self = &box->points; + float x1, x2, y1, y2; + + if (!gtk_canvas_point_eval (&self->point1, &x1, &y1) || + !gtk_canvas_point_eval (&self->point2, &x2, &y2)) + return FALSE; + + graphene_rect_init (rect, x1, y1, x2 - x1, y2 - y1); + return TRUE; +} + +static const GtkCanvasBoxClass GTK_CANVAS_BOX_POINTS_CLASS = +{ + "GtkCanvasBoxPoints", + gtk_canvas_box_points_copy, + gtk_canvas_box_points_finish, + gtk_canvas_box_points_eval, +}; + +/** + * gtk_canvas_box_new_points: + * @point1: the first point + * @point2: the second point + * + * Creates a new box describing the rectangle between the two + * points + * + * Returns: a new box + **/ +GtkCanvasBox * +gtk_canvas_box_new_points (const GtkCanvasPoint *point1, + const GtkCanvasPoint *point2) +{ + GtkCanvasBoxPoints *self; + + g_return_val_if_fail (point1 != NULL, NULL); + g_return_val_if_fail (point2 != NULL, NULL); + + self = gtk_canvas_box_alloc (>K_CANVAS_BOX_POINTS_CLASS); + + gtk_canvas_point_init_copy (&self->point1, point1); + gtk_canvas_point_init_copy (&self->point2, point2); + + return (GtkCanvasBox *) self; +} + +/* }}} */ +/* {{{ SIZE */ + +static void +gtk_canvas_box_size_copy (GtkCanvasBox *box, + const GtkCanvasBox *source_box) +{ + const GtkCanvasBoxSize *source = &source_box->size; + + gtk_canvas_box_init (box, &source->point, &source->size, source->origin_x, source->origin_y); +} + +static void +gtk_canvas_box_size_finish (GtkCanvasBox *box) +{ + GtkCanvasBoxSize *self = &box->size; + + gtk_canvas_point_finish (&self->point); + gtk_canvas_size_finish (&self->size); +} + +static gboolean +gtk_canvas_box_size_eval (const GtkCanvasBox *box, + graphene_rect_t *rect) +{ + const GtkCanvasBoxSize *self = &box->size; + float x, y, width, height; + + if (!gtk_canvas_point_eval (&self->point, &x, &y) || + !gtk_canvas_size_eval (&self->size, &width, &height)) + return FALSE; + + graphene_rect_init (rect, + x - width * self->origin_x, + y - height * self->origin_y, + width, height); + + return TRUE; +} + +static const GtkCanvasBoxClass GTK_CANVAS_BOX_SIZE_CLASS = +{ + "GtkCanvasBoxSize", + gtk_canvas_box_size_copy, + gtk_canvas_box_size_finish, + gtk_canvas_box_size_eval, +}; + +void +gtk_canvas_box_init (GtkCanvasBox *box, + const GtkCanvasPoint *point, + const GtkCanvasSize *size, + float origin_x, + float origin_y) +{ + GtkCanvasBoxSize *self = &box->size; + + self->class = >K_CANVAS_BOX_SIZE_CLASS; + + gtk_canvas_point_init_copy (&self->point, point); + gtk_canvas_size_init_copy (&self->size, size); + self->origin_x = origin_x; + self->origin_y = origin_y; +} + +/** + * gtk_canvas_box_new: + * @point: the origin point of the box + * @size: size of the box + * @origin_x: x coordinate of origin + * @origin_y: y coordinate of origin + * + * Creates a new box of the given size relative to the given point. + * The origin describes where in the box the point is located. + * (0, 0) means the point describes the top left of the box, (1, 1) + * describes the bottom right, and (0.5, 0.5) is the center. + * + * Returns: a new box + **/ +GtkCanvasBox * +gtk_canvas_box_new (const GtkCanvasPoint *point, + const GtkCanvasSize *size, + float origin_x, + float origin_y) +{ + GtkCanvasBox *self; + + g_return_val_if_fail (point != NULL, NULL); + g_return_val_if_fail (size != NULL, NULL); + + self = gtk_canvas_box_alloc (>K_CANVAS_BOX_SIZE_CLASS); + + gtk_canvas_box_init (self, point, size, origin_x, origin_y); + + return self; +} + +/* }}} */ +/* {{{ PUBLIC API */ + +GtkCanvasBox * +gtk_canvas_box_copy (const GtkCanvasBox *self) +{ + GtkCanvasBox *copy; + + g_return_val_if_fail (self != NULL, NULL); + + copy = gtk_canvas_box_alloc (self->class); + + gtk_canvas_box_init_copy (copy, self); + + return copy; +} + +void +gtk_canvas_box_free (GtkCanvasBox *self) +{ + gtk_canvas_box_finish (self); + + g_slice_free (GtkCanvasBox, self); +} + +gboolean +gtk_canvas_box_eval (const GtkCanvasBox *self, + graphene_rect_t *rect) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (rect != NULL, FALSE); + + if (self->class->eval (self, rect)) + return TRUE; + + *rect = *graphene_rect_zero (); + return FALSE; +} + diff --git a/gtk/gtkcanvasbox.h b/gtk/gtkcanvasbox.h new file mode 100644 index 0000000000..4211ca323c --- /dev/null +++ b/gtk/gtkcanvasbox.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + + +#ifndef __GTK_CANVAS_BOX_H__ +#define __GTK_CANVAS_BOX_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtktypes.h> +#include <graphene.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_CANVAS_BOX (gtk_canvas_box_get_type ()) + +GDK_AVAILABLE_IN_ALL +GType gtk_canvas_box_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_ALL +GtkCanvasBox * gtk_canvas_box_copy (const GtkCanvasBox *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_box_free (GtkCanvasBox *self); + +GDK_AVAILABLE_IN_ALL +gboolean gtk_canvas_box_eval (const GtkCanvasBox *self, + graphene_rect_t *rect) G_GNUC_WARN_UNUSED_RESULT; + +GDK_AVAILABLE_IN_ALL +GtkCanvasBox * gtk_canvas_box_new (const GtkCanvasPoint *point, + const GtkCanvasSize *size, + float origin_x, + float origin_y); +GDK_AVAILABLE_IN_ALL +GtkCanvasBox * gtk_canvas_box_new_points (const GtkCanvasPoint *point1, + const GtkCanvasPoint *point2); + +G_END_DECLS + +#endif /* __GTK_BOX_H__ */ diff --git a/gtk/gtkcanvasboxprivate.h b/gtk/gtkcanvasboxprivate.h new file mode 100644 index 0000000000..f28610c38d --- /dev/null +++ b/gtk/gtkcanvasboxprivate.h @@ -0,0 +1,54 @@ +#ifndef __GTK_CANVAS_BOX_PRIVATE_H__ +#define __GTK_CANVAS_BOX_PRIVATE_H__ + +#include "gtkcanvasbox.h" + +#include "gtkcanvaspointprivate.h" +#include "gtkcanvassizeprivate.h" + +G_BEGIN_DECLS + +typedef struct _GtkCanvasBoxClass GtkCanvasBoxClass; +typedef struct _GtkCanvasBoxPoints GtkCanvasBoxPoints; +typedef struct _GtkCanvasBoxSize GtkCanvasBoxSize; + +struct _GtkCanvasBoxPoints +{ + const GtkCanvasBoxClass *class; + + GtkCanvasPoint point1; + GtkCanvasPoint point2; +}; + +struct _GtkCanvasBoxSize +{ + const GtkCanvasBoxClass *class; + + GtkCanvasPoint point; + GtkCanvasSize size; + float origin_x; + float origin_y; +}; + +struct _GtkCanvasBox +{ + union { + const GtkCanvasBoxClass *class; + GtkCanvasBoxPoints points; + GtkCanvasBoxSize size; + }; +}; + + +void gtk_canvas_box_init (GtkCanvasBox *self, + const GtkCanvasPoint *point, + const GtkCanvasSize *size, + float origin_x, + float origin_y); +void gtk_canvas_box_init_copy (GtkCanvasBox *self, + const GtkCanvasBox *source); +void gtk_canvas_box_finish (GtkCanvasBox *self); + +G_END_DECLS + +#endif /* __GTK_CANVAS_BOX_PRIVATE_H__ */ diff --git a/gtk/gtkcanvasitem.c b/gtk/gtkcanvasitem.c new file mode 100644 index 0000000000..1a56374a9b --- /dev/null +++ b/gtk/gtkcanvasitem.c @@ -0,0 +1,353 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#include "config.h" + +#include "gtkcanvasitemprivate.h" + +#include "gtkcanvas.h" +#include "gtkcanvasboxprivate.h" +#include "gtkcanvaspointprivate.h" +#include "gtkcanvassizeprivate.h" +#include "gtkintl.h" +#include "gtklistitemfactoryprivate.h" +#include "gtkwidget.h" + +/** + * GtkCanvasItem: + * + * `GtkCanvasItem` holds all information relevant for placing a widget + * onto the canvas. + */ + +struct _GtkCanvasItem +{ + GObject parent_instance; + + GtkCanvas *canvas; + gpointer item; + GtkWidget *widget; + GtkCanvasBox bounds; +}; + +enum +{ + PROP_0, + PROP_BOUNDS, + PROP_CANVAS, + PROP_ITEM, + PROP_WIDGET, + + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (GtkCanvasItem, gtk_canvas_item, G_TYPE_OBJECT) + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +gtk_canvas_item_dispose (GObject *object) +{ + GtkCanvasItem *self = GTK_CANVAS_ITEM (object); + + /* holds a reference */ + g_assert (self->canvas == NULL); + /* must have been deleted in teardown */ + g_assert (self->item == NULL); + g_assert (self->widget == NULL); + + gtk_canvas_box_finish (&self->bounds); + + G_OBJECT_CLASS (gtk_canvas_item_parent_class)->dispose (object); +} + +static void +gtk_canvas_item_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkCanvasItem *self = GTK_CANVAS_ITEM (object); + + switch (property_id) + { + case PROP_BOUNDS: + g_value_set_boxed (value, &self->bounds); + break; + + case PROP_CANVAS: + g_value_set_object (value, self->canvas); + break; + + case PROP_ITEM: + g_value_set_object (value, self->item); + break; + + case PROP_WIDGET: + g_value_set_object (value, self->widget); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_canvas_item_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCanvasItem *self = GTK_CANVAS_ITEM (object); + + switch (property_id) + { + case PROP_BOUNDS: + gtk_canvas_item_set_bounds (self, g_value_get_boxed (value)); + break; + + case PROP_WIDGET: + gtk_canvas_item_set_widget (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_canvas_item_class_init (GtkCanvasItemClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gtk_canvas_item_dispose; + gobject_class->get_property = gtk_canvas_item_get_property; + gobject_class->set_property = gtk_canvas_item_set_property; + + /** + * GtkCanvasItem:bounds: (attributes org.gtk.Property.get=gtk_canvas_item_get_bounds org.gtk.Property.set=gtk_canvas_item_set_bounds) + * + * The bounds to place the widget into. + */ + properties[PROP_BOUNDS] = + g_param_spec_boxed ("bounds", NULL, NULL, + GTK_TYPE_CANVAS_BOX, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GtkCanvasItem:canvas: (attributes org.gtk.Property.get=gtk_canvas_item_get_canvas org.gtk.Property.set=gtk_canvas_item_set_canvas) + * + * The canvas this item belongs to or %NULL if the canvas has been destroyed + */ + properties[PROP_CANVAS] = + g_param_spec_object ("canvas", NULL, NULL, + GTK_TYPE_CANVAS, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GtkCanvasItem:item: (attributes org.gtk.Property.get=gtk_canvas_item_get_item org.gtk.Property.set=gtk_canvas_item_set_item) + * + * The item represented by this canvas item. + */ + properties[PROP_ITEM] = + g_param_spec_object ("item", NULL, NULL, + G_TYPE_OBJECT, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GtkCanvasItem:widget: (attributes org.gtk.Property.get=gtk_canvas_item_get_widget org.gtk.Property.set=gtk_canvas_item_set_widget) + * + * The widget managed. + */ + properties[PROP_WIDGET] = + g_param_spec_object ("widget", NULL, NULL, + GTK_TYPE_WIDGET, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, N_PROPS, properties); +} + +static void +gtk_canvas_item_init (GtkCanvasItem *self) +{ + GtkCanvasPoint point; + GtkCanvasSize size; + + gtk_canvas_point_init (&point, 0, 0); + gtk_canvas_size_init_measure_item (&size, self, GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT); + gtk_canvas_box_init (&self->bounds, &point, &size, 0, 0); + gtk_canvas_size_finish (&size); + gtk_canvas_point_finish (&point); +} + +GtkCanvasItem * +gtk_canvas_item_new (GtkCanvas *canvas, + gpointer item) +{ + GtkCanvasItem *self; + + self = g_object_new (GTK_TYPE_CANVAS_ITEM, + NULL); + + /* no reference, the canvas references us */ + self->canvas = canvas; + /* transfer full */ + self->item = item; + + return self; +} + +/** + * gtk_canvas_item_get_canvas: (attributes org.gtk.Method.get_property=canvas) + * @self: a `GtkCanvasItem` + * + * Gets the canvas this item belongs to. + * + * If the canvas has discarded this item, this property willbe set to %NULL. + * + * Returns: (nullable) (transfer none): The canvas + */ +GtkCanvas * +gtk_canvas_item_get_canvas (GtkCanvasItem *self) +{ + g_return_val_if_fail (GTK_IS_CANVAS_ITEM (self), NULL); + + return self->canvas; +} + +/** + * gtk_canvas_item_get_item: (attributes org.gtk.Method.get_property=item) + * @self: a `GtkCanvasItem` + * + * Gets the item that is associated with this canvasitem or %NULL if the canvas has + * discarded this canvasitem. + * + * Returns: (transfer none) (nullable) (type GObject): The item. + */ +gpointer +gtk_canvas_item_get_item (GtkCanvasItem *self) +{ + g_return_val_if_fail (GTK_IS_CANVAS_ITEM (self), NULL); + + return self->item; +} + +/** + * gtk_canvas_item_set_bounds: (attributes org.gtk.Method.set_property=bounds) + * @self: a `GtkCanvasItem` + * @bounds: (transfer none): the bounds to allocate the widget in + * + * Sets the box to allocate the widget into. + */ +void +gtk_canvas_item_set_bounds (GtkCanvasItem *self, + const GtkCanvasBox *bounds) +{ + g_return_if_fail (GTK_IS_CANVAS_ITEM (self)); + g_return_if_fail (bounds != NULL); + + gtk_canvas_box_init_copy (&self->bounds, bounds); + if (self->canvas) + gtk_widget_queue_allocate (GTK_WIDGET (self->canvas)); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BOUNDS]); +} + +/** + * gtk_canvas_item_get_bounds: (attributes org.gtk.Method.get_property=bounds) + * @self: a `GtkCanvasItem` + * + * Gets the bounds that are used to allocate the widget + * + * Returns: (transfer none): The bounds + */ +const GtkCanvasBox * +gtk_canvas_item_get_bounds (GtkCanvasItem *self) +{ + g_return_val_if_fail (GTK_IS_CANVAS_ITEM (self), NULL); + + return &self->bounds; +} + +/** + * gtk_canvas_item_set_widget: (attributes org.gtk.Method.set_property=widget) + * @self: a `GtkCanvasItem` + * @widget: (nullable) (transfer none): the widget to use + * + * Sets the widget to be displayed by this item. + */ +void +gtk_canvas_item_set_widget (GtkCanvasItem *self, + GtkWidget *widget) +{ + g_return_if_fail (GTK_IS_CANVAS_ITEM (self)); + g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget)); + + if (self->widget == widget) + return; + + if (self->widget) + { + if (self->canvas) + gtk_widget_unparent (self->widget); + g_object_unref (self->widget); + } + + self->widget = g_object_ref_sink (widget); + + if (self->canvas) + { + /* FIXME: Put in right spot */ + gtk_widget_set_parent (widget, GTK_WIDGET (self->canvas)); + } + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WIDGET]); +} + +/** + * gtk_canvas_item_get_widget: (attributes org.gtk.Method.get_property=widget) + * @self: a `GtkCanvasItem` + * + * Gets the widget that's currently displayed by this canvasitem + * + * Returns: (nullable) (transfer none): The widget in use + */ +GtkWidget * +gtk_canvas_item_get_widget (GtkCanvasItem *self) +{ + g_return_val_if_fail (GTK_IS_CANVAS_ITEM (self), NULL); + + return self->widget; +} + +void +gtk_canvas_item_setup (GtkCanvasItem *self, + GtkListItemFactory *factory) +{ + gtk_list_item_factory_setup (factory, G_OBJECT (self), TRUE, NULL, NULL); +} + +void +gtk_canvas_item_teardown (GtkCanvasItem *self, + GtkListItemFactory *factory) +{ + gtk_list_item_factory_teardown (factory, G_OBJECT (self), TRUE, NULL, NULL); +} diff --git a/gtk/gtkcanvasitem.h b/gtk/gtkcanvasitem.h new file mode 100644 index 0000000000..15f3ae7bf4 --- /dev/null +++ b/gtk/gtkcanvasitem.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_CANVAS_ITEM_H__ +#define __GTK_CANVAS_ITEM_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtktypes.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_CANVAS_ITEM (gtk_canvas_item_get_type ()) + +/* GtkCanvasItem */ + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkCanvasItem, gtk_canvas_item, GTK, CANVAS_ITEM, GObject) + +GDK_AVAILABLE_IN_ALL +GtkCanvas * gtk_canvas_item_get_canvas (GtkCanvasItem *self); +GDK_AVAILABLE_IN_ALL +gpointer gtk_canvas_item_get_item (GtkCanvasItem *self); + +GDK_AVAILABLE_IN_ALL +void gtk_canvas_item_set_widget (GtkCanvasItem *self, + GtkWidget *widget); +GDK_AVAILABLE_IN_ALL +GtkWidget * gtk_canvas_item_get_widget (GtkCanvasItem *self); + +GDK_AVAILABLE_IN_ALL +void gtk_canvas_item_set_bounds (GtkCanvasItem *self, + const GtkCanvasBox *box); +GDK_AVAILABLE_IN_ALL +const GtkCanvasBox * gtk_canvas_item_get_bounds (GtkCanvasItem *self); + +G_END_DECLS + +#endif /* __GTK_CANVAS_ITEM_H__ */ diff --git a/gtk/gtkcanvasitemprivate.h b/gtk/gtkcanvasitemprivate.h new file mode 100644 index 0000000000..f22916e925 --- /dev/null +++ b/gtk/gtkcanvasitemprivate.h @@ -0,0 +1,20 @@ +#ifndef __GTK_CANVAS_ITEM_PRIVATE_H__ +#define __GTK_CANVAS_ITEM_PRIVATE_H__ + +#include "gtkcanvasitem.h" + +G_BEGIN_DECLS + +GtkCanvasItem * gtk_canvas_item_new (GtkCanvas *canvas, + gpointer item); + +void gtk_canvas_item_clear_canvas (GtkCanvasItem *self); + +void gtk_canvas_item_setup (GtkCanvasItem *self, + GtkListItemFactory *factory); +void gtk_canvas_item_teardown (GtkCanvasItem *self, + GtkListItemFactory *factory); + +G_END_DECLS + +#endif /* __GTK_CANVAS_ITEM_PRIVATE_H__ */ diff --git a/gtk/gtkcanvaslayout.h b/gtk/gtkcanvaslayout.h new file mode 100644 index 0000000000..c85e64ba2a --- /dev/null +++ b/gtk/gtkcanvaslayout.h @@ -0,0 +1,91 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_CANVAS_H__ +#define __GTK_CANVAS_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtklayoutmanager.h> + +G_BEGIN_DECLS + +struct _GtkPosition { + float relative; + float absolute; +}; + +#define GTK_TYPE_CANVAS_LAYOUT (gtk_canvas_layout_get_type ()) +#define GTK_TYPE_CANVAS_LAYOUT_CHILD (gtk_canvas_layout_child_get_type ()) + +/* GtkCanvasLayout */ + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkCanvasLayout, gtk_canvas_layout, GTK, CANVAS_LAYOUT, GtkLayoutManager) + +GDK_AVAILABLE_IN_ALL +GtkLayoutManager * gtk_canvas_layout_new (void); + +/* GtkCanvasLayoutChild */ + +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkCanvasLayoutChild, gtk_canvas_layout_child, GTK, CANVAS_LAYOUT_CHILD, GtkLayoutChild) + +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_x (GtkCanvasLayoutChild *self, + const GtkPosition *position); +GDK_AVAILABLE_IN_ALL +const GtkPosition * gtk_canvas_layout_child_get_x (GtkCanvasLayoutChild *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_y (GtkCanvasLayoutChild *self, + const GtkPosition *position); +GDK_AVAILABLE_IN_ALL +const GtkPosition * gtk_canvas_layout_child_get_y (GtkCanvasLayoutChild *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_origin_x (GtkCanvasLayoutChild *self, + const GtkPosition *position); +GDK_AVAILABLE_IN_ALL +const GtkPosition * gtk_canvas_layout_child_get_origin_x (GtkCanvasLayoutChild *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_origin_y (GtkCanvasLayoutChild *self, + const GtkPosition *position); +GDK_AVAILABLE_IN_ALL +const GtkPosition * gtk_canvas_layout_child_get_origin_y (GtkCanvasLayoutChild *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_transform (GtkCanvasLayoutChild *self, + GskTransform *transform); +GDK_AVAILABLE_IN_ALL +const GskTransform * gtk_canvas_layout_child_get_transform (GtkCanvasLayoutChild *self); + +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_hpolicy (GtkCanvasLayoutChild *self, + GtkScrollablePolicy policy); +GDK_AVAILABLE_IN_ALL +GtkScrollablePolicy gtk_canvas_layout_child_get_hpolicy (GtkCanvasLayoutChild *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_layout_child_set_vpolicy (GtkCanvasLayoutChild *self, + GtkScrollablePolicy policy); +GDK_AVAILABLE_IN_ALL +GtkScrollablePolicy gtk_canvas_layout_child_get_vpolicy (GtkCanvasLayoutChild *self); + +G_END_DECLS + +#endif /* __GTK_CANVAS_H__ */ diff --git a/gtk/gtkcanvaspoint.c b/gtk/gtkcanvaspoint.c new file mode 100644 index 0000000000..df812b5cf4 --- /dev/null +++ b/gtk/gtkcanvaspoint.c @@ -0,0 +1,297 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + + +/** + * GtkCanvasPoint: + * + * `GtkCanvasPoint` describes a point in a `GtkCanvas`. + */ + +#include "config.h" + +#include "gtkcanvaspointprivate.h" + +#include "gtkcanvasbox.h" + +/* {{{ Boilerplate */ + +struct _GtkCanvasPointClass +{ + const char *type_name; + + void (* copy) (GtkCanvasPoint *self, + const GtkCanvasPoint *source); + void (* finish) (GtkCanvasPoint *self); + gboolean (* eval) (const GtkCanvasPoint *self, + float *x, + float *y); +}; + +G_DEFINE_BOXED_TYPE (GtkCanvasPoint, gtk_canvas_point, + gtk_canvas_point_copy, + gtk_canvas_point_free) + +static gpointer +gtk_canvas_point_alloc (const GtkCanvasPointClass *class) +{ + GtkCanvasPoint *self = g_slice_new (GtkCanvasPoint); + + self->class = class; + + return self; +} + +void +gtk_canvas_point_init_copy (GtkCanvasPoint *self, + const GtkCanvasPoint *source) +{ + self->class = source->class; + self->class->copy (self, source); +} + +void +gtk_canvas_point_finish (GtkCanvasPoint *self) +{ + self->class->finish (self); +} + +/* }}} */ +/* {{{ OFFSET */ + +static void +gtk_canvas_point_offset_copy (GtkCanvasPoint *point, + const GtkCanvasPoint *source_point) +{ + GtkCanvasPointOffset *self = &point->offset; + const GtkCanvasPointOffset *source = &source_point->offset; + + *self = *source; + + if (source->other) + self->other = gtk_canvas_point_copy (source->other); +} + +static void +gtk_canvas_point_offset_finish (GtkCanvasPoint *point) +{ + GtkCanvasPointOffset *self = &point->offset; + + if (self->other) + gtk_canvas_point_free (self->other); +} + +static gboolean +gtk_canvas_point_offset_eval (const GtkCanvasPoint *point, + float *x, + float *y) +{ + const GtkCanvasPointOffset *self = &point->offset; + + if (self->other != NULL) + { + if (!gtk_canvas_point_eval (self->other, x, y)) + return FALSE; + + *x += self->dx; + *y += self->dy; + } + else + { + *x = self->dx; + *y = self->dy; + } + + return TRUE; +} + +static const GtkCanvasPointClass GTK_CANVAS_POINT_OFFSET_CLASS = +{ + "GtkCanvasPointOffset", + gtk_canvas_point_offset_copy, + gtk_canvas_point_offset_finish, + gtk_canvas_point_offset_eval, +}; + +void +gtk_canvas_point_init (GtkCanvasPoint *point, + float x, + float y) +{ + GtkCanvasPointOffset *self = &point->offset; + + self->class = >K_CANVAS_POINT_OFFSET_CLASS; + + self->other = NULL; + self->dx = x; + self->dy = y; +} + +/** + * gtk_canvas_point_new: + * @x: x coordinate + * @y: y coordinate + * + * Creates a new point at the given coordinate. + * + * Returns: a new point + **/ +GtkCanvasPoint * +gtk_canvas_point_new (float x, + float y) +{ + GtkCanvasPoint *self; + + self = gtk_canvas_point_alloc (>K_CANVAS_POINT_OFFSET_CLASS); + + gtk_canvas_point_init (self, x, y); + + return self; +} + +/* }}} */ +/* {{{ BOX */ + +static void +gtk_canvas_point_box_copy (GtkCanvasPoint *point, + const GtkCanvasPoint *source_point) +{ + GtkCanvasPointBox *self = &point->box; + const GtkCanvasPointBox *source = &source_point->box; + + *self = *source; + + self->box = gtk_canvas_box_copy (source->box); +} + +static void +gtk_canvas_point_box_finish (GtkCanvasPoint *point) +{ + GtkCanvasPointBox *self = &point->box; + + gtk_canvas_box_free (self->box); +} + +static gboolean +gtk_canvas_point_box_eval (const GtkCanvasPoint *point, + float *x, + float *y) +{ + const GtkCanvasPointBox *self = &point->box; + graphene_rect_t rect; + + if (!gtk_canvas_box_eval (self->box, &rect)) + return FALSE; + + *x = rect.origin.x + self->offset_x + self->origin_x * rect.size.width; + *y = rect.origin.y + self->offset_y + self->origin_y * rect.size.height; + + return TRUE; +} + +static const GtkCanvasPointClass GTK_CANVAS_POINT_BOX_CLASS = +{ + "GtkCanvasPointBox", + gtk_canvas_point_box_copy, + gtk_canvas_point_box_finish, + gtk_canvas_point_box_eval, +}; + +/** + * gtk_canvas_point_new_from_box: + * @box: a box + * @origin_x: x coordinate of box origin + * @origin_y: y coordinate of box origin + * @offset_x: offset in x direction + * @offset_y: offset in y direction + * + * Creates a point relative to the given box. + * + * The origin describes where in the box the point is, with + * (0, 0) being the top left and (1, 1) being the bottom right + * corner of the box. + * + * The offset is then added to the origin. It may be negative. + * + * Returns: a new point + **/ +GtkCanvasPoint * +gtk_canvas_point_new_from_box (const GtkCanvasBox *box, + float origin_x, + float origin_y, + float offset_x, + float offset_y) +{ + GtkCanvasPointBox *self; + + g_return_val_if_fail (box != NULL, NULL); + + self = gtk_canvas_point_alloc (>K_CANVAS_POINT_BOX_CLASS); + + self->box = gtk_canvas_box_copy (box); + self->origin_x = origin_x; + self->origin_y = origin_y; + self->offset_x = offset_x; + self->offset_y = offset_y; + + return (GtkCanvasPoint *) self; +} + +/* }}} */ +/* {{{ PUBLIC API */ + +GtkCanvasPoint * +gtk_canvas_point_copy (const GtkCanvasPoint *self) +{ + GtkCanvasPoint *copy; + + g_return_val_if_fail (self != NULL, NULL); + + copy = gtk_canvas_point_alloc (self->class); + + gtk_canvas_point_init_copy (copy, self); + + return copy; +} + +void +gtk_canvas_point_free (GtkCanvasPoint *self) +{ + gtk_canvas_point_finish (self); + + g_slice_free (GtkCanvasPoint, self); +} + +gboolean +gtk_canvas_point_eval (const GtkCanvasPoint *self, + float *x, + float *y) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (x != NULL, FALSE); + g_return_val_if_fail (y != NULL, FALSE); + + if (self->class->eval (self, x, y)) + return TRUE; + + *x = 0; + *y = 0; + return FALSE; +} + diff --git a/gtk/gtkcanvaspoint.h b/gtk/gtkcanvaspoint.h new file mode 100644 index 0000000000..5a35ba3423 --- /dev/null +++ b/gtk/gtkcanvaspoint.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + + +#ifndef __GTK_CANVAS_POINT_H__ +#define __GTK_CANVAS_POINT_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtktypes.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_CANVAS_POINT (gtk_canvas_point_get_type ()) + +GDK_AVAILABLE_IN_ALL +GType gtk_canvas_point_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_ALL +GtkCanvasPoint * gtk_canvas_point_copy (const GtkCanvasPoint *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_point_free (GtkCanvasPoint *self); + +GDK_AVAILABLE_IN_ALL +gboolean gtk_canvas_point_eval (const GtkCanvasPoint *self, + float *x, + float *y) G_GNUC_WARN_UNUSED_RESULT; + +GDK_AVAILABLE_IN_ALL +GtkCanvasPoint * gtk_canvas_point_new (float x, + float y); +GDK_AVAILABLE_IN_ALL +GtkCanvasPoint * gtk_canvas_point_new_from_box (const GtkCanvasBox *box, + float origin_x, + float origin_y, + float offset_x, + float offset_y); +GDK_AVAILABLE_IN_ALL +GtkCanvasPoint * gtk_canvas_point_new_from_item (GtkCanvasItem *item, + float origin_x, + float origin_y, + float offset_x, + float offset_y); + +G_END_DECLS + +#endif /* __GTK_POINT_H__ */ diff --git a/gtk/gtkcanvaspointprivate.h b/gtk/gtkcanvaspointprivate.h new file mode 100644 index 0000000000..1d10efa6b3 --- /dev/null +++ b/gtk/gtkcanvaspointprivate.h @@ -0,0 +1,52 @@ +#ifndef __GTK_CANVAS_POINT_PRIVATE_H__ +#define __GTK_CANVAS_POINT_PRIVATE_H__ + +#include "gtkcanvaspoint.h" + +G_BEGIN_DECLS + +typedef struct _GtkCanvasPointClass GtkCanvasPointClass; +typedef struct _GtkCanvasPointBox GtkCanvasPointBox; +typedef struct _GtkCanvasPointItem GtkCanvasPointItem; +typedef struct _GtkCanvasPointOffset GtkCanvasPointOffset; + +struct _GtkCanvasPointBox +{ + const GtkCanvasPointClass *class; + + GtkCanvasBox *box; + float origin_x; + float origin_y; + float offset_x; + float offset_y; +}; + +struct _GtkCanvasPointOffset +{ + const GtkCanvasPointClass *class; + + GtkCanvasPoint *other; + float dx; + float dy; +}; + +struct _GtkCanvasPoint +{ + union { + const GtkCanvasPointClass *class; + GtkCanvasPointBox box; + GtkCanvasPointOffset offset; + }; +}; + + +void gtk_canvas_point_init (GtkCanvasPoint * point, + float x, + float y); +void gtk_canvas_point_init_copy (GtkCanvasPoint *self, + const GtkCanvasPoint *source); +void gtk_canvas_point_finish (GtkCanvasPoint *self); + +G_END_DECLS + +#endif /* __GTK_CANVAS_POINT_PRIVATE_H__ */ diff --git a/gtk/gtkcanvassize.c b/gtk/gtkcanvassize.c new file mode 100644 index 0000000000..b67b870eec --- /dev/null +++ b/gtk/gtkcanvassize.c @@ -0,0 +1,392 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + + +/** + * GtkCanvasSize: + * + * `GtkCanvasSize` describes a size in a `GtkCanvas`. + */ + +#include "config.h" + +#include "gtkcanvassizeprivate.h" + +#include "gtkcanvasbox.h" +#include "gtkcanvasitem.h" +#include "gtkwidget.h" + +/* {{{ Boilerplate */ + +struct _GtkCanvasSizeClass +{ + const char *type_name; + + void (* copy) (GtkCanvasSize *self, + const GtkCanvasSize *source); + void (* finish) (GtkCanvasSize *self); + gboolean (* eval) (const GtkCanvasSize *self, + float *width, + float *height); +}; + +G_DEFINE_BOXED_TYPE (GtkCanvasSize, gtk_canvas_size, + gtk_canvas_size_copy, + gtk_canvas_size_free) + +static gpointer +gtk_canvas_size_alloc (const GtkCanvasSizeClass *class) +{ + GtkCanvasSize *self = g_slice_new (GtkCanvasSize); + + self->class = class; + + return self; +} + +void +gtk_canvas_size_init_copy (GtkCanvasSize *self, + const GtkCanvasSize *source) +{ + self->class = source->class; + self->class->copy (self, source); +} + +void +gtk_canvas_size_finish (GtkCanvasSize *self) +{ + self->class->finish (self); +} + +/* }}} */ +/* {{{ ABSOLUTE */ + +static void +gtk_canvas_size_absolute_copy (GtkCanvasSize *size, + const GtkCanvasSize *source_size) +{ + GtkCanvasSizeAbsolute *self = &size->absolute; + const GtkCanvasSizeAbsolute *source = &source_size->absolute; + + *self = *source; +} + +static void +gtk_canvas_size_absolute_finish (GtkCanvasSize *size) +{ +} + +static gboolean +gtk_canvas_size_absolute_eval (const GtkCanvasSize *size, + float *width, + float *height) +{ + const GtkCanvasSizeAbsolute *self = &size->absolute; + + *width = self->width; + *height = self->height; + + return TRUE; +} + +static const GtkCanvasSizeClass GTK_CANVAS_SIZE_ABSOLUTE_CLASS = +{ + "GtkCanvasSizeAbsolute", + gtk_canvas_size_absolute_copy, + gtk_canvas_size_absolute_finish, + gtk_canvas_size_absolute_eval, +}; + +/** + * gtk_canvas_size_new: + * @width: width of the size + * @height: height of the size + * + * Creates a new size with the given dimensions + * + * Returns: a new size + **/ +GtkCanvasSize * +gtk_canvas_size_new (float width, + float height) +{ + GtkCanvasSizeAbsolute *self; + + self = gtk_canvas_size_alloc (>K_CANVAS_SIZE_ABSOLUTE_CLASS); + self->width = width; + self->height = height; + + return (GtkCanvasSize *) self; +} + +/* }}} */ +/* {{{ BOX */ + +static void +gtk_canvas_size_box_copy (GtkCanvasSize *size, + const GtkCanvasSize *source_size) +{ + GtkCanvasSizeBox *self = &size->box; + const GtkCanvasSizeBox *source = &source_size->box; + + *self = *source; + + self->box = gtk_canvas_box_copy (source->box); +} + +static void +gtk_canvas_size_box_finish (GtkCanvasSize *size) +{ + GtkCanvasSizeBox *self = &size->box; + + gtk_canvas_box_free (self->box); +} + +static gboolean +gtk_canvas_size_box_eval (const GtkCanvasSize *size, + float *width, + float *height) +{ + const GtkCanvasSizeBox *self = &size->box; + graphene_rect_t rect; + + if (!gtk_canvas_box_eval (self->box, &rect)) + return FALSE; + + *width = rect.size.width; + *height = rect.size.height; + + return TRUE; +} + +static const GtkCanvasSizeClass GTK_CANVAS_SIZE_BOX_CLASS = +{ + "GtkCanvasSizeBox", + gtk_canvas_size_box_copy, + gtk_canvas_size_box_finish, + gtk_canvas_size_box_eval, +}; + +/** + * gtk_canvas_size_new_from_box: + * @box: a box + * + * Creates a size for the given box. + * + * Returns: a new size + **/ +GtkCanvasSize * +gtk_canvas_size_new_from_box (const GtkCanvasBox *box) +{ + GtkCanvasSizeBox *self; + + g_return_val_if_fail (box != NULL, NULL); + + self = gtk_canvas_size_alloc (>K_CANVAS_SIZE_BOX_CLASS); + + /* FIXME: We could potentially just copy the box's size here */ + self->box = gtk_canvas_box_copy (box); + + return (GtkCanvasSize *) self; +} + +/* }}} */ +/* {{{ MEASURE */ + +static void +gtk_canvas_size_measure_copy (GtkCanvasSize *size, + const GtkCanvasSize *source_size) +{ + const GtkCanvasSizeMeasure *source = &source_size->measure; + + gtk_canvas_size_init_measure_item (size, source->item, source->measure); +} + +static void +gtk_canvas_size_measure_finish (GtkCanvasSize *size) +{ +} + +static gboolean +gtk_canvas_size_measure_eval (const GtkCanvasSize *size, + float *width, + float *height) +{ + const GtkCanvasSizeMeasure *self = &size->measure; + GtkWidget *widget; + int w, h; + + if (self->item == NULL) + return FALSE; + + widget = gtk_canvas_item_get_widget (self->item); + if (widget == NULL) + { + *width = 0; + *height = 0; + return TRUE; + } + + if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) + { + switch (self->measure) + { + case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN: + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL); + break; + case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_NAT: + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, NULL, &w, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, &h, NULL, NULL, NULL); + break; + case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_MIN: + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, &w, NULL, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, NULL, &h, NULL, NULL); + break; + case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT: + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, NULL, &w, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, w, NULL, &h, NULL, NULL); + break; + default: + g_assert_not_reached (); + w = h = 0; + break; + } + } + else + { + switch (self->measure) + { + case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN: + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL); + break; + case GTK_CANVAS_ITEM_MEASURE_MIN_FOR_NAT: + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, NULL, &h, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, &w, NULL, NULL, NULL); + break; + case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_MIN: + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, &h, NULL, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, NULL, &w, NULL, NULL); + break; + case GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT: + gtk_widget_measure (widget, GTK_ORIENTATION_VERTICAL, -1, NULL, &h, NULL, NULL); + gtk_widget_measure (widget, GTK_ORIENTATION_HORIZONTAL, h, NULL, &w, NULL, NULL); + break; + default: + g_assert_not_reached (); + w = h = 0; + break; + } + } + + *width = w; + *height = h; + + return TRUE; +} + +static const GtkCanvasSizeClass GTK_CANVAS_SIZE_MEASURE_CLASS = +{ + "GtkCanvasSizeMeasure", + gtk_canvas_size_measure_copy, + gtk_canvas_size_measure_finish, + gtk_canvas_size_measure_eval, +}; + +void +gtk_canvas_size_init_measure_item (GtkCanvasSize *size, + GtkCanvasItem *item, + GtkCanvasItemMeasurement measure) +{ + GtkCanvasSizeMeasure *self = &size->measure; + + self->class = >K_CANVAS_SIZE_MEASURE_CLASS; + + self->item = item; + self->measure = measure; +} + +/** + * gtk_canvas_size_new_measure_item: + * @item: the item + * @measure: how to measure the item + * + * Measures the widget of @item with the given method to determine + * a size. + * + * Returns: a new size + **/ +GtkCanvasSize * +gtk_canvas_size_new_measure_item (GtkCanvasItem *item, + GtkCanvasItemMeasurement measure) +{ + GtkCanvasSize *self; + + g_return_val_if_fail (GTK_IS_CANVAS_ITEM (item), NULL); + + self = gtk_canvas_size_alloc (>K_CANVAS_SIZE_MEASURE_CLASS); + + gtk_canvas_size_init_measure_item (self, item, measure); + + return self; +} + +/* }}} */ +/* {{{ PUBLIC API */ + +GtkCanvasSize * +gtk_canvas_size_copy (const GtkCanvasSize *self) +{ + GtkCanvasSize *copy; + + g_return_val_if_fail (self != NULL, NULL); + + copy = gtk_canvas_size_alloc (self->class); + + gtk_canvas_size_init_copy (copy, self); + + return copy; +} + +void +gtk_canvas_size_free (GtkCanvasSize *self) +{ + gtk_canvas_size_finish (self); + + g_slice_free (GtkCanvasSize, self); +} + +gboolean +gtk_canvas_size_eval (const GtkCanvasSize *self, + float *width, + float *height) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (width != NULL, FALSE); + g_return_val_if_fail (height != NULL, FALSE); + + if (self->class->eval (self, width, height)) + return TRUE; + + *width = 0; + *height = 0; + return FALSE; +} + diff --git a/gtk/gtkcanvassize.h b/gtk/gtkcanvassize.h new file mode 100644 index 0000000000..63a9903e6a --- /dev/null +++ b/gtk/gtkcanvassize.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * 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.1 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, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + + +#ifndef __GTK_CANVAS_SIZE_H__ +#define __GTK_CANVAS_SIZE_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtktypes.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_CANVAS_SIZE (gtk_canvas_size_get_type ()) + +GDK_AVAILABLE_IN_ALL +GType gtk_canvas_size_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_ALL +GtkCanvasSize * gtk_canvas_size_copy (const GtkCanvasSize *self); +GDK_AVAILABLE_IN_ALL +void gtk_canvas_size_free (GtkCanvasSize *self); + +GDK_AVAILABLE_IN_ALL +gboolean gtk_canvas_size_eval (const GtkCanvasSize *self, + float *width, + float *height) G_GNUC_WARN_UNUSED_RESULT; + +GDK_AVAILABLE_IN_ALL +GtkCanvasSize * gtk_canvas_size_new (float width, + float height); +GDK_AVAILABLE_IN_ALL +GtkCanvasSize * gtk_canvas_size_new_from_box (const GtkCanvasBox *box); + +typedef enum { + GTK_CANVAS_ITEM_MEASURE_MIN_FOR_MIN, + GTK_CANVAS_ITEM_MEASURE_MIN_FOR_NAT, + GTK_CANVAS_ITEM_MEASURE_NAT_FOR_MIN, + GTK_CANVAS_ITEM_MEASURE_NAT_FOR_NAT +} GtkCanvasItemMeasurement; + +GDK_AVAILABLE_IN_ALL +GtkCanvasSize * gtk_canvas_size_new_measure_item (GtkCanvasItem *item, + GtkCanvasItemMeasurement measure); + +G_END_DECLS + +#endif /* __GTK_SIZE_H__ */ diff --git a/gtk/gtkcanvassizeprivate.h b/gtk/gtkcanvassizeprivate.h new file mode 100644 index 0000000000..83e14800fa --- /dev/null +++ b/gtk/gtkcanvassizeprivate.h @@ -0,0 +1,56 @@ +#ifndef __GTK_CANVAS_SIZE_PRIVATE_H__ +#define __GTK_CANVAS_SIZE_PRIVATE_H__ + +#include "gtkcanvassize.h" + +G_BEGIN_DECLS + +typedef struct _GtkCanvasSizeClass GtkCanvasSizeClass; +typedef struct _GtkCanvasSizeAbsolute GtkCanvasSizeAbsolute; +typedef struct _GtkCanvasSizeBox GtkCanvasSizeBox; +typedef struct _GtkCanvasSizeMeasure GtkCanvasSizeMeasure; + +struct _GtkCanvasSizeAbsolute +{ + const GtkCanvasSizeClass *class; + + float width; + float height; +}; + +struct _GtkCanvasSizeBox +{ + const GtkCanvasSizeClass *class; + + GtkCanvasBox *box; +}; + +struct _GtkCanvasSizeMeasure +{ + const GtkCanvasSizeClass *class; + + GtkCanvasItem *item; + GtkCanvasItemMeasurement measure; +}; + +struct _GtkCanvasSize +{ + union { + const GtkCanvasSizeClass *class; + GtkCanvasSizeAbsolute absolute; + GtkCanvasSizeBox box; + GtkCanvasSizeMeasure measure; + }; +}; + + +void gtk_canvas_size_init_measure_item (GtkCanvasSize *self, + GtkCanvasItem *item, + GtkCanvasItemMeasurement measure); +void gtk_canvas_size_init_copy (GtkCanvasSize *self, + const GtkCanvasSize *source); +void gtk_canvas_size_finish (GtkCanvasSize *self); + +G_END_DECLS + +#endif /* __GTK_CANVAS_SIZE_PRIVATE_H__ */ diff --git a/gtk/gtktypes.h b/gtk/gtktypes.h index 71afde94b0..0bfe629a89 100644 --- a/gtk/gtktypes.h +++ b/gtk/gtktypes.h @@ -37,6 +37,11 @@ typedef struct _GtkAdjustment GtkAdjustment; typedef struct _GtkBitset GtkBitset; typedef struct _GtkBuilder GtkBuilder; typedef struct _GtkBuilderScope GtkBuilderScope; +typedef struct _GtkCanvas GtkCanvas; +typedef struct _GtkCanvasBox GtkCanvasBox; +typedef struct _GtkCanvasItem GtkCanvasItem; +typedef struct _GtkCanvasPoint GtkCanvasPoint; +typedef struct _GtkCanvasSize GtkCanvasSize; typedef struct _GtkCssStyleChange GtkCssStyleChange; typedef struct _GtkEventController GtkEventController; typedef struct _GtkGesture GtkGesture; diff --git a/gtk/meson.build b/gtk/meson.build index 2e404f2ac4..63f01bbea8 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -182,6 +182,11 @@ gtk_public_sources = files([ 'gtkbuilderscope.c', 'gtkbutton.c', 'gtkcalendar.c', + 'gtkcanvas.c', + 'gtkcanvasbox.c', + 'gtkcanvasitem.c', + 'gtkcanvaspoint.c', + 'gtkcanvassize.c', 'gtkcellarea.c', 'gtkcellareabox.c', 'gtkcellareacontext.c', @@ -473,6 +478,11 @@ gtk_public_headers = files([ 'gtkbuilderscope.h', 'gtkbutton.h', 'gtkcalendar.h', + 'gtkcanvas.h', + 'gtkcanvasbox.h', + 'gtkcanvasitem.h', + 'gtkcanvaspoint.h', + 'gtkcanvassize.h', 'gtkcenterbox.h', 'gtkcenterlayout.h', 'gtkcellarea.h', |