forked from AuroraMiddleware/gtk
Merge branch 'fixed-layout' into 'master'
Add GtkFixedLayout See merge request GNOME/gtk!668
This commit is contained in:
commit
e5722367b3
@ -196,7 +196,7 @@ edit_label_done (GtkWidget *entry, gpointer data)
|
||||
GtkWidget *label;
|
||||
int x, y;
|
||||
|
||||
gtk_container_child_get (GTK_CONTAINER (fixed), entry, "x", &x, "y", &y, NULL);
|
||||
gtk_fixed_get_child_position (GTK_FIXED (fixed), entry, &x, &y);
|
||||
|
||||
label = GTK_WIDGET (g_object_get_data (G_OBJECT (entry), "label"));
|
||||
gtk_label_set_text (GTK_LABEL (label), gtk_editable_get_text (GTK_EDITABLE (entry)));
|
||||
@ -210,7 +210,7 @@ edit_cb (GtkWidget *child)
|
||||
GtkWidget *fixed = gtk_widget_get_parent (child);
|
||||
int x, y;
|
||||
|
||||
gtk_container_child_get (GTK_CONTAINER (fixed), child, "x", &x, "y", &y, NULL);
|
||||
gtk_fixed_get_child_position (GTK_FIXED (fixed), child, &x, &y);
|
||||
|
||||
if (GTK_IS_LABEL (child))
|
||||
{
|
||||
|
@ -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>
|
||||
|
295
gtk/gtkfixed.c
295
gtk/gtkfixed.c
@ -76,37 +76,11 @@
|
||||
#include "gtkfixed.h"
|
||||
|
||||
#include "gtkcontainerprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkfixedlayout.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
} GtkFixedChild;
|
||||
|
||||
enum {
|
||||
CHILD_PROP_0,
|
||||
CHILD_PROP_X,
|
||||
CHILD_PROP_Y
|
||||
};
|
||||
|
||||
static GQuark child_data_quark = 0;
|
||||
|
||||
static void gtk_fixed_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline);
|
||||
|
||||
|
||||
static void gtk_fixed_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
static void gtk_fixed_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
static void gtk_fixed_remove (GtkContainer *container,
|
||||
@ -116,63 +90,21 @@ static void gtk_fixed_forall (GtkContainer *container,
|
||||
gpointer callback_data);
|
||||
static GType gtk_fixed_child_type (GtkContainer *container);
|
||||
|
||||
static void gtk_fixed_set_child_property (GtkContainer *container,
|
||||
GtkWidget *child,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gtk_fixed_get_child_property (GtkContainer *container,
|
||||
GtkWidget *child,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
typedef struct {
|
||||
GtkLayoutManager *layout;
|
||||
} GtkFixedPrivate;
|
||||
|
||||
G_DEFINE_TYPE (GtkFixed, gtk_fixed, GTK_TYPE_CONTAINER)
|
||||
|
||||
static GtkFixedChild *
|
||||
get_fixed_child (GtkWidget *widget)
|
||||
{
|
||||
g_assert (GTK_IS_FIXED (gtk_widget_get_parent (widget)));
|
||||
|
||||
return (GtkFixedChild *) g_object_get_qdata (G_OBJECT (widget), child_data_quark);
|
||||
}
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkFixed, gtk_fixed, GTK_TYPE_CONTAINER)
|
||||
|
||||
static void
|
||||
gtk_fixed_class_init (GtkFixedClass *class)
|
||||
gtk_fixed_class_init (GtkFixedClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class;
|
||||
GtkContainerClass *container_class;
|
||||
|
||||
widget_class = (GtkWidgetClass*) class;
|
||||
container_class = (GtkContainerClass*) class;
|
||||
|
||||
widget_class->measure = gtk_fixed_measure;
|
||||
widget_class->size_allocate = gtk_fixed_size_allocate;
|
||||
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
|
||||
|
||||
container_class->add = gtk_fixed_add;
|
||||
container_class->remove = gtk_fixed_remove;
|
||||
container_class->forall = gtk_fixed_forall;
|
||||
container_class->child_type = gtk_fixed_child_type;
|
||||
container_class->set_child_property = gtk_fixed_set_child_property;
|
||||
container_class->get_child_property = gtk_fixed_get_child_property;
|
||||
|
||||
gtk_container_class_install_child_property (container_class,
|
||||
CHILD_PROP_X,
|
||||
g_param_spec_int ("x",
|
||||
P_("X position"),
|
||||
P_("X position of child widget"),
|
||||
G_MININT, G_MAXINT, 0,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
gtk_container_class_install_child_property (container_class,
|
||||
CHILD_PROP_Y,
|
||||
g_param_spec_int ("y",
|
||||
P_("Y position"),
|
||||
P_("Y position of child widget"),
|
||||
G_MININT, G_MAXINT, 0,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
child_data_quark = g_quark_from_static_string ("gtk-fixed-child-data");
|
||||
}
|
||||
|
||||
static GType
|
||||
@ -182,9 +114,14 @@ gtk_fixed_child_type (GtkContainer *container)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_fixed_init (GtkFixed *fixed)
|
||||
gtk_fixed_init (GtkFixed *self)
|
||||
{
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (fixed), FALSE);
|
||||
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
|
||||
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
|
||||
|
||||
priv->layout = gtk_fixed_layout_new ();
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self), priv->layout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,48 +152,56 @@ gtk_fixed_put (GtkFixed *fixed,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkFixedChild *child_info;
|
||||
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (fixed);
|
||||
GtkFixedLayoutChild *child_info;
|
||||
GskTransform *transform = NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_FIXED (fixed));
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (_gtk_widget_get_parent (widget) == NULL);
|
||||
|
||||
child_info = g_new (GtkFixedChild, 1);
|
||||
child_info->x = x;
|
||||
child_info->y = y;
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (widget), child_data_quark, child_info, g_free);
|
||||
gtk_widget_set_parent (widget, GTK_WIDGET (fixed));
|
||||
|
||||
child_info = GTK_FIXED_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout, widget));
|
||||
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (x, y));
|
||||
gtk_fixed_layout_child_set_position (child_info, transform);
|
||||
gsk_transform_unref (transform);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_fixed_move_internal (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
GtkFixedChild *child,
|
||||
gint x,
|
||||
gint y)
|
||||
/**
|
||||
* gtk_fixed_get_child_position:
|
||||
* @fixed: a #GtkFixed
|
||||
* @widget: a child of @fixed
|
||||
* @x: (out): the horizontal position of the @widget
|
||||
* @y: (out): the vertical position of the @widget
|
||||
*
|
||||
* Retrieves the position of the given child #GtkWidget in the given
|
||||
* #GtkFixed container.
|
||||
*/
|
||||
void
|
||||
gtk_fixed_get_child_position (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
gint *x,
|
||||
gint *y)
|
||||
{
|
||||
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (fixed);
|
||||
GtkFixedLayoutChild *child_info;
|
||||
float pos_x = 0.f, pos_y = 0.f;
|
||||
GskTransform *transform;
|
||||
|
||||
g_return_if_fail (GTK_IS_FIXED (fixed));
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (fixed));
|
||||
|
||||
gtk_widget_freeze_child_notify (widget);
|
||||
child_info = GTK_FIXED_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout, widget));
|
||||
transform = gtk_fixed_layout_child_get_position (child_info);
|
||||
gsk_transform_to_translate (transform, &pos_x, &pos_y);
|
||||
|
||||
if (child->x != x)
|
||||
{
|
||||
child->x = x;
|
||||
gtk_widget_child_notify (widget, "x");
|
||||
}
|
||||
|
||||
if (child->y != y)
|
||||
{
|
||||
child->y = y;
|
||||
gtk_widget_child_notify (widget, "y");
|
||||
}
|
||||
|
||||
gtk_widget_thaw_child_notify (widget);
|
||||
|
||||
if (gtk_widget_get_visible (widget) &&
|
||||
gtk_widget_get_visible (GTK_WIDGET (fixed)))
|
||||
gtk_widget_queue_resize (GTK_WIDGET (fixed));
|
||||
if (x != NULL)
|
||||
*x = floorf (pos_x);
|
||||
if (y != NULL)
|
||||
*y = floorf (pos_y);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,131 +219,19 @@ gtk_fixed_move (GtkFixed *fixed,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (fixed);
|
||||
GtkFixedLayoutChild *child_info;
|
||||
GskTransform *transform = NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_FIXED (fixed));
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (fixed));
|
||||
|
||||
gtk_fixed_move_internal (fixed, widget, get_fixed_child (widget), x, y);
|
||||
}
|
||||
child_info = GTK_FIXED_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout, widget));
|
||||
|
||||
static void
|
||||
gtk_fixed_set_child_property (GtkContainer *container,
|
||||
GtkWidget *child,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkFixed *fixed = GTK_FIXED (container);
|
||||
GtkFixedChild *fixed_child = get_fixed_child (child);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case CHILD_PROP_X:
|
||||
gtk_fixed_move_internal (fixed,
|
||||
child,
|
||||
fixed_child,
|
||||
g_value_get_int (value),
|
||||
fixed_child->y);
|
||||
break;
|
||||
case CHILD_PROP_Y:
|
||||
gtk_fixed_move_internal (fixed,
|
||||
child,
|
||||
fixed_child,
|
||||
fixed_child->x,
|
||||
g_value_get_int (value));
|
||||
break;
|
||||
default:
|
||||
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_fixed_get_child_property (GtkContainer *container,
|
||||
GtkWidget *child,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkFixedChild *fixed_child = get_fixed_child (child);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case CHILD_PROP_X:
|
||||
g_value_set_int (value, fixed_child->x);
|
||||
break;
|
||||
case CHILD_PROP_Y:
|
||||
g_value_set_int (value, fixed_child->y);
|
||||
break;
|
||||
default:
|
||||
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_fixed_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
int child_min, child_nat;
|
||||
GtkWidget *child;
|
||||
GtkFixedChild *child_info;
|
||||
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
child_info = get_fixed_child (child);
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
gtk_widget_measure (child, orientation, -1, &child_min, &child_nat, NULL, NULL);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
*minimum = MAX (*minimum, child_info->x + child_min);
|
||||
*natural = MAX (*natural, child_info->x + child_nat);
|
||||
}
|
||||
else /* VERTICAL */
|
||||
{
|
||||
*minimum = MAX (*minimum, child_info->y + child_min);
|
||||
*natural = MAX (*natural, child_info->y + child_nat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_fixed_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkWidget *child;
|
||||
GtkFixedChild *child_info;
|
||||
GtkAllocation child_allocation;
|
||||
GtkRequisition child_requisition;
|
||||
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
child_info = get_fixed_child (child);
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
gtk_widget_get_preferred_size (child, &child_requisition, NULL);
|
||||
child_allocation.x = child_info->x;
|
||||
child_allocation.y = child_info->y;
|
||||
|
||||
child_allocation.width = child_requisition.width;
|
||||
child_allocation.height = child_requisition.height;
|
||||
gtk_widget_size_allocate (child, &child_allocation, -1);
|
||||
}
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (x, y));
|
||||
gtk_fixed_layout_child_set_position (child_info, transform);
|
||||
gsk_transform_unref (transform);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -62,20 +62,24 @@ struct _GtkFixedClass
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_fixed_get_type (void) G_GNUC_CONST;
|
||||
GType gtk_fixed_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget* gtk_fixed_new (void);
|
||||
GtkWidget* gtk_fixed_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_fixed_put (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
gint x,
|
||||
gint y);
|
||||
void gtk_fixed_put (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
gint x,
|
||||
gint y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_fixed_move (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
void gtk_fixed_move (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
gint x,
|
||||
gint y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_fixed_get_child_position (GtkFixed *fixed,
|
||||
GtkWidget *widget,
|
||||
gint *x,
|
||||
gint *y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
331
gtk/gtkfixedlayout.c
Normal file
331
gtk/gtkfixedlayout.c
Normal file
@ -0,0 +1,331 @@
|
||||
/* 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;
|
||||
|
||||
GskTransform *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_finalize (GObject *gobject)
|
||||
{
|
||||
GtkFixedLayoutChild *self = GTK_FIXED_LAYOUT_CHILD (gobject);
|
||||
|
||||
gsk_transform_unref (self->position);
|
||||
|
||||
G_OBJECT_CLASS (gtk_fixed_layout_child_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
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;
|
||||
gobject_class->finalize = gtk_fixed_layout_child_finalize;
|
||||
|
||||
child_props[PROP_CHILD_POSITION] =
|
||||
g_param_spec_boxed ("position",
|
||||
P_("Position"),
|
||||
P_("The position of a child of a fixed layout"),
|
||||
GSK_TYPE_TRANSFORM,
|
||||
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: a #GskTransform
|
||||
*
|
||||
* Sets the transformation of the child of a #GtkFixedLayout.
|
||||
*/
|
||||
void
|
||||
gtk_fixed_layout_child_set_position (GtkFixedLayoutChild *child,
|
||||
GskTransform *position)
|
||||
{
|
||||
GtkLayoutManager *layout;
|
||||
|
||||
g_return_if_fail (GTK_IS_FIXED_LAYOUT_CHILD (child));
|
||||
|
||||
child->position = gsk_transform_transform (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
|
||||
*
|
||||
* Retrieves the transformation of the child of a #GtkFixedLayout.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GskTransform
|
||||
*/
|
||||
GskTransform *
|
||||
gtk_fixed_layout_child_get_position (GtkFixedLayoutChild *child)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FIXED_LAYOUT_CHILD (child), NULL);
|
||||
|
||||
return 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, child_nat = 0;
|
||||
int child_min_opp = 0, child_nat_opp = 0;
|
||||
graphene_rect_t min_rect, nat_rect;
|
||||
|
||||
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);
|
||||
gtk_widget_measure (child, OPPOSITE_ORIENTATION (orientation), -1,
|
||||
&child_min_opp, &child_nat_opp,
|
||||
NULL, NULL);
|
||||
|
||||
gsk_transform_transform_bounds (child_info->position,
|
||||
&GRAPHENE_RECT_INIT (0.f, 0.f, child_min, child_min_opp),
|
||||
&min_rect);
|
||||
gsk_transform_transform_bounds (child_info->position,
|
||||
&GRAPHENE_RECT_INIT (0.f, 0.f, child_nat, child_nat_opp),
|
||||
&nat_rect);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
minimum_size = MAX (minimum_size, min_rect.origin.x + min_rect.size.width);
|
||||
natural_size = MAX (natural_size, nat_rect.origin.x + nat_rect.size.width);
|
||||
}
|
||||
else
|
||||
{
|
||||
minimum_size = MAX (minimum_size, min_rect.origin.y + min_rect.size.height);
|
||||
natural_size = MAX (natural_size, nat_rect.origin.y + nat_rect.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
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_allocate (child,
|
||||
child_req.width,
|
||||
child_req.height,
|
||||
-1,
|
||||
child_info->position);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
49
gtk/gtkfixedlayout.h
Normal file
49
gtk/gtkfixedlayout.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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,
|
||||
GskTransform *position);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskTransform * gtk_fixed_layout_child_get_position (GtkFixedLayoutChild *child);
|
||||
|
||||
G_END_DECLS
|
@ -66,8 +66,6 @@ static GtkSizeRequestMode
|
||||
gtk_layout_manager_real_get_request_mode (GtkLayoutManager *manager,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, get_request_mode);
|
||||
|
||||
return GTK_SIZE_REQUEST_CONSTANT_SIZE;
|
||||
}
|
||||
|
||||
@ -285,12 +283,19 @@ gtk_layout_manager_layout_changed (GtkLayoutManager *manager)
|
||||
gtk_widget_queue_resize (priv->widget);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_layout_child (GtkWidget *widget,
|
||||
GtkWidget *old_parent,
|
||||
GtkLayoutManager *self)
|
||||
/*< private >
|
||||
* gtk_layout_manager_remove_layout_child:
|
||||
* @manager: a #GtkLayoutManager
|
||||
* @widget: a #GtkWidget
|
||||
*
|
||||
* Removes the #GtkLayoutChild associated with @widget from the
|
||||
* given #GtkLayoutManager, if any is set.
|
||||
*/
|
||||
void
|
||||
gtk_layout_manager_remove_layout_child (GtkLayoutManager *manager,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (self);
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (manager);
|
||||
|
||||
if (priv->layout_children != NULL)
|
||||
{
|
||||
@ -298,8 +303,6 @@ remove_layout_child (GtkWidget *widget,
|
||||
if (g_hash_table_size (priv->layout_children) == 0)
|
||||
g_clear_pointer (&priv->layout_children, g_hash_table_unref);
|
||||
}
|
||||
|
||||
g_signal_handlers_disconnect_by_func (widget, remove_layout_child, self);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,7 +377,6 @@ gtk_layout_manager_get_layout_child (GtkLayoutManager *manager,
|
||||
g_assert (g_type_is_a (G_OBJECT_TYPE (res), GTK_TYPE_LAYOUT_CHILD));
|
||||
|
||||
g_hash_table_insert (priv->layout_children, child, res);
|
||||
g_signal_connect (child, "parent-set", G_CALLBACK (remove_layout_child), manager);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -7,4 +7,7 @@ G_BEGIN_DECLS
|
||||
void gtk_layout_manager_set_widget (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
void gtk_layout_manager_remove_layout_child (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -3209,6 +3209,9 @@ gtk_widget_unparent (GtkWidget *widget)
|
||||
if (old_parent->priv->children_observer)
|
||||
gtk_list_list_model_item_removed (old_parent->priv->children_observer, old_prev_sibling);
|
||||
|
||||
if (old_parent->priv->layout_manager)
|
||||
gtk_layout_manager_remove_layout_child (old_parent->priv->layout_manager, widget);
|
||||
|
||||
/* Now that the parent pointer is nullified and the unroot vfunc already
|
||||
* called, go ahead and unset the parent window, if we are unparenting
|
||||
* an embedded GtkWindow the window will become toplevel again and root
|
||||
|
@ -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',
|
||||
|
@ -77,6 +77,7 @@ test_type (gconstpointer data)
|
||||
/* These can't be freely constructed/destroyed */
|
||||
if (g_type_is_a (type, GTK_TYPE_APPLICATION) ||
|
||||
g_type_is_a (type, GDK_TYPE_PIXBUF_LOADER) ||
|
||||
g_type_is_a (type, GTK_TYPE_LAYOUT_CHILD) ||
|
||||
#ifdef G_OS_UNIX
|
||||
g_type_is_a (type, GTK_TYPE_PRINT_JOB) ||
|
||||
#endif
|
||||
|
@ -370,6 +370,7 @@ test_type (gconstpointer data)
|
||||
/* These can't be freely constructed/destroyed */
|
||||
if (g_type_is_a (type, GTK_TYPE_APPLICATION) ||
|
||||
g_type_is_a (type, GDK_TYPE_PIXBUF_LOADER) ||
|
||||
g_type_is_a (type, GTK_TYPE_LAYOUT_CHILD) ||
|
||||
#ifdef G_OS_UNIX
|
||||
g_type_is_a (type, GTK_TYPE_PRINT_JOB) ||
|
||||
#endif
|
||||
|
@ -72,6 +72,11 @@ test_finalize_object (gconstpointer data)
|
||||
NULL);
|
||||
g_object_unref (list_store);
|
||||
}
|
||||
else if (g_type_is_a (test_type, GTK_TYPE_LAYOUT_CHILD))
|
||||
{
|
||||
g_test_skip ("Skipping GtkLayoutChild type");
|
||||
return;
|
||||
}
|
||||
else
|
||||
object = g_object_new (test_type, NULL);
|
||||
g_assert (G_IS_OBJECT (object));
|
||||
|
Loading…
Reference in New Issue
Block a user