summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2019-03-26 16:50:13 +0000
committerEmmanuele Bassi <ebassi@gnome.org>2019-03-26 17:43:53 +0000
commit9a4c19349e19b73237f55ac2d2a02bce784ebd4c (patch)
treed2cfefe014b9c9b0da576c9fa8c087216a4b219f
parent3389ddf6fc8ce84daa3b652bbbae749fbf02faa1 (diff)
downloadgtk+-9a4c19349e19b73237f55ac2d2a02bce784ebd4c.tar.gz
Add GtkFixedLayout
A layout manager for fixed positioning.
-rw-r--r--gtk/gtk.h1
-rw-r--r--gtk/gtkfixedlayout.c314
-rw-r--r--gtk/gtkfixedlayout.h50
-rw-r--r--gtk/meson.build2
4 files changed, 367 insertions, 0 deletions
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 6d1ca27b5f..ac96a15810 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -101,6 +101,7 @@
#include <gtk/gtkeventcontrollerscroll.h>
#include <gtk/gtkexpander.h>
#include <gtk/gtkfixed.h>
+#include <gtk/gtkfixedlayout.h>
#include <gtk/gtkfilechooser.h>
#include <gtk/gtkfilechooserbutton.h>
#include <gtk/gtkfilechooserdialog.h>
diff --git a/gtk/gtkfixedlayout.c b/gtk/gtkfixedlayout.c
new file mode 100644
index 0000000000..abddfb8849
--- /dev/null
+++ b/gtk/gtkfixedlayout.c
@@ -0,0 +1,314 @@
+/* gtkfixedlayout.c: Fixed positioning layout manager
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Copyright 2019 GNOME Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gtkfixedlayout
+ * @Short_description: A layout manager that allows positioning at fixed
+ * coordinates
+ * @Title: GtkFixedLayout
+ *
+ * #GtkFixedLayout is a layout manager which can place child widgets
+ * at fixed positions, and with fixed sizes.
+ *
+ * Most applications should never use this layout manager; fixed positioning
+ * and sizing requires constant recalculations on where children need to be
+ * positioned and sized. Other layout managers perform this kind of work
+ * internally so that application developers don't need to do it. Specifically,
+ * widgets positioned in a fixed layout manager will need to take into account:
+ *
+ * - Themes, which may change widget sizes.
+ *
+ * - Fonts other than the one you used to write the app will of course
+ * change the size of widgets containing text; keep in mind that
+ * users may use a larger font because of difficulty reading the
+ * default, or they may be using a different OS that provides different
+ * fonts.
+ *
+ * - Translation of text into other languages changes its size. Also,
+ * display of non-English text will use a different font in many
+ * cases.
+ *
+ * In addition, #GtkFixedLayout does not pay attention to text direction and
+ * thus may produce unwanted results if your app is run under right-to-left
+ * languages such as Hebrew or Arabic. That is: normally GTK will order
+ * containers appropriately depending on the text direction, e.g. to put labels
+ * to the right of the thing they label when using an RTL language;
+ * #GtkFixedLayout won't be able to do that for you.
+ *
+ * Finally, fixed positioning makes it kind of annoying to add/remove GUI
+ * elements, since you have to reposition all the other elements. This is a
+ * long-term maintenance problem for your application.
+ */
+
+#include "config.h"
+
+#include "gtkfixedlayout.h"
+
+#include "gtkintl.h"
+#include "gtklayoutchild.h"
+#include "gtkprivate.h"
+#include "gtkwidgetprivate.h"
+
+#include <graphene-gobject.h>
+
+struct _GtkFixedLayout
+{
+ GtkLayoutManager parent_instance;
+};
+
+struct _GtkFixedLayoutChild
+{
+ GtkLayoutChild parent_instance;
+
+ graphene_point_t position;
+};
+
+enum
+{
+ PROP_CHILD_POSITION = 1,
+
+ N_CHILD_PROPERTIES
+};
+
+static GParamSpec *child_props[N_CHILD_PROPERTIES];
+
+G_DEFINE_TYPE (GtkFixedLayoutChild, gtk_fixed_layout_child, GTK_TYPE_LAYOUT_CHILD)
+
+static void
+gtk_fixed_layout_child_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFixedLayoutChild *self = GTK_FIXED_LAYOUT_CHILD (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_CHILD_POSITION:
+ gtk_fixed_layout_child_set_position (self, g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_fixed_layout_child_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFixedLayoutChild *self = GTK_FIXED_LAYOUT_CHILD (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_CHILD_POSITION:
+ g_value_set_boxed (value, &self->position);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_fixed_layout_child_class_init (GtkFixedLayoutChildClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gtk_fixed_layout_child_set_property;
+ gobject_class->get_property = gtk_fixed_layout_child_get_property;
+
+ child_props[PROP_CHILD_POSITION] =
+ g_param_spec_boxed ("position",
+ P_("Position"),
+ P_("The position of a child of a fixed layout"),
+ GRAPHENE_TYPE_POINT,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (gobject_class, N_CHILD_PROPERTIES, child_props);
+}
+
+static void
+gtk_fixed_layout_child_init (GtkFixedLayoutChild *self)
+{
+}
+
+/**
+ * gtk_fixed_layout_child_set_position:
+ * @child: a #GtkFixedLayoutChild
+ * @position: the position of the child
+ *
+ * Sets the position of the child of a #GtkFixedLayout.
+ */
+void
+gtk_fixed_layout_child_set_position (GtkFixedLayoutChild *child,
+ const graphene_point_t *position)
+{
+ GtkLayoutManager *layout;
+
+ g_return_if_fail (GTK_IS_FIXED_LAYOUT_CHILD (child));
+ g_return_if_fail (position != NULL);
+
+ if (graphene_point_equal (&child->position, position))
+ return;
+
+ child->position = *position;
+
+ layout = gtk_layout_child_get_layout_manager (GTK_LAYOUT_CHILD (child));
+ gtk_layout_manager_layout_changed (layout);
+
+ g_object_notify_by_pspec (G_OBJECT (child), child_props[PROP_CHILD_POSITION]);
+}
+
+/**
+ * gtk_fixed_layout_child_get_position:
+ * @child: a #GtkFixedLayoutChild
+ * @position: (out caller-allocates): the position of the child
+ *
+ * Retrieves the position of the child of a #GtkFixedLayout.
+ */
+void
+gtk_fixed_layout_child_get_position (GtkFixedLayoutChild *child,
+ graphene_point_t *position)
+{
+ g_return_if_fail (GTK_IS_FIXED_LAYOUT_CHILD (child));
+ g_return_if_fail (position != NULL);
+
+ *position = child->position;
+}
+
+G_DEFINE_TYPE (GtkFixedLayout, gtk_fixed_layout, GTK_TYPE_LAYOUT_MANAGER)
+
+static void
+gtk_fixed_layout_measure (GtkLayoutManager *layout_manager,
+ GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ GtkFixedLayoutChild *child_info;
+ GtkWidget *child;
+ int minimum_size = 0;
+ int natural_size = 0;
+
+ for (child = _gtk_widget_get_first_child (widget);
+ child != NULL;
+ child = _gtk_widget_get_next_sibling (child))
+ {
+ int child_min = 0;
+ int child_nat = 0;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ child_info = GTK_FIXED_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (layout_manager, child));
+
+ gtk_widget_measure (child, orientation, -1, &child_min, &child_nat, NULL, NULL);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ minimum_size = MAX (minimum_size, child_info->position.x + child_min);
+ natural_size = MAX (natural_size, child_info->position.x + child_nat);
+ }
+ else
+ {
+ minimum_size = MAX (minimum_size, child_info->position.y + child_min);
+ natural_size = MAX (natural_size, child_info->position.y + child_nat);
+ }
+ }
+
+ if (minimum != NULL)
+ *minimum = minimum_size;
+ if (natural != NULL)
+ *natural = natural_size;
+}
+
+static void
+gtk_fixed_layout_allocate (GtkLayoutManager *layout_manager,
+ GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
+{
+ GtkFixedLayoutChild *child_info;
+ GtkWidget *child;
+
+ for (child = _gtk_widget_get_first_child (widget);
+ child != NULL;
+ child = _gtk_widget_get_next_sibling (child))
+ {
+ GtkRequisition child_req;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ child_info = GTK_FIXED_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (layout_manager, child));
+ gtk_widget_get_preferred_size (child, &child_req, NULL);
+
+ gtk_widget_size_allocate (child,
+ &(GtkAllocation) {
+ .x = child_info->position.x,
+ .y = child_info->position.y,
+ .width = child_req.width,
+ .height = child_req.height,
+ }, -1);
+ }
+}
+
+static GtkLayoutChild *
+gtk_fixed_layout_create_layout_child (GtkLayoutManager *manager,
+ GtkWidget *widget,
+ GtkWidget *for_child)
+{
+ return g_object_new (GTK_TYPE_FIXED_LAYOUT_CHILD,
+ "layout-manager", manager,
+ "child-widget", for_child,
+ NULL);
+}
+
+static void
+gtk_fixed_layout_class_init (GtkFixedLayoutClass *klass)
+{
+ GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (klass);
+
+ layout_class->measure = gtk_fixed_layout_measure;
+ layout_class->allocate = gtk_fixed_layout_allocate;
+ layout_class->create_layout_child = gtk_fixed_layout_create_layout_child;
+}
+
+static void
+gtk_fixed_layout_init (GtkFixedLayout *self)
+{
+}
+
+GtkLayoutManager *
+gtk_fixed_layout_new (void)
+{
+ return g_object_new (GTK_TYPE_FIXED_LAYOUT, NULL);
+}
diff --git a/gtk/gtkfixedlayout.h b/gtk/gtkfixedlayout.h
new file mode 100644
index 0000000000..8600091b19
--- /dev/null
+++ b/gtk/gtkfixedlayout.h
@@ -0,0 +1,50 @@
+/* gtkfixedlayout.h: Fixed positioning layout manager
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Copyright 2019 GNOME Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gtk/gtklayoutmanager.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_FIXED_LAYOUT (gtk_fixed_layout_get_type ())
+#define GTK_TYPE_FIXED_LAYOUT_CHILD (gtk_fixed_layout_child_get_type ())
+
+/* GtkFixedLayout */
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkFixedLayout, gtk_fixed_layout, GTK, FIXED_LAYOUT, GtkLayoutManager)
+
+GDK_AVAILABLE_IN_ALL
+GtkLayoutManager * gtk_fixed_layout_new (void);
+
+/* GtkFixedLayoutChild */
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkFixedLayoutChild, gtk_fixed_layout_child, GTK, FIXED_LAYOUT_CHILD, GtkLayoutChild)
+
+GDK_AVAILABLE_IN_ALL
+void gtk_fixed_layout_child_set_position (GtkFixedLayoutChild *child,
+ const graphene_point_t *position);
+GDK_AVAILABLE_IN_ALL
+void gtk_fixed_layout_child_get_position (GtkFixedLayoutChild *child,
+ graphene_point_t *position);
+
+G_END_DECLS
diff --git a/gtk/meson.build b/gtk/meson.build
index fd955607b7..44114fb23b 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -227,6 +227,7 @@ gtk_public_sources = files([
'gtkfilefilter.c',
'gtkfilterlistmodel.c',
'gtkfixed.c',
+ 'gtkfixedlayout.c',
'gtkflattenlistmodel.c',
'gtkflowbox.c',
'gtkfontbutton.c',
@@ -483,6 +484,7 @@ gtk_public_headers = files([
'gtkfilefilter.h',
'gtkfilterlistmodel.h',
'gtkfixed.h',
+ 'gtkfixedlayout.h',
'gtkflattenlistmodel.h',
'gtkflowbox.h',
'gtkfontbutton.h',