Compare commits

...

2 Commits

Author SHA1 Message Date
Emmanuele Bassi
109593ab18 WIP: Implement Scrollable in GtkFixed 2019-04-01 18:02:48 +01:00
Emmanuele Bassi
7b17f6fede WIP: Additional API for GtkLayout 2019-04-01 18:02:22 +01:00
3 changed files with 326 additions and 15 deletions

View File

@@ -75,10 +75,12 @@
#include "gtkfixed.h"
#include "gtkadjustment.h"
#include "gtkcontainerprivate.h"
#include "gtkfixedlayout.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkscrollable.h"
#include "gtkwidgetprivate.h"
static void gtk_fixed_add (GtkContainer *container,
@@ -92,19 +94,252 @@ static GType gtk_fixed_child_type (GtkContainer *container);
typedef struct {
GtkLayoutManager *layout;
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
/* GtkScrollablePolicy needs to be checked when
* driving the scrollable adjustment values */
GtkScrollablePolicy hscroll_policy;
GtkScrollablePolicy vscroll_policy;
} GtkFixedPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GtkFixed, gtk_fixed, GTK_TYPE_CONTAINER)
enum {
PROP_0,
/* GtkFixed properties */
N_PROPERTIES,
/* GtkScrollable properties */
PROP_HADJUSTMENT = N_PROPERTIES,
PROP_VADJUSTMENT,
PROP_HSCROLL_POLICY,
PROP_VSCROLL_POLICY
};
G_DEFINE_TYPE_WITH_CODE (GtkFixed, gtk_fixed, GTK_TYPE_CONTAINER,
G_ADD_PRIVATE (GtkFixed)
G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
static void
gtk_fixed_adjustment_changed (GtkFixed *self)
{
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
double scroll_x = 0;
double scroll_y = 0;
GskTransform *transform;
if (priv->hadjustment)
scroll_x = gtk_adjustment_get_value (priv->hadjustment) * -1.0;
if (priv->vadjustment)
scroll_y = gtk_adjustment_get_value (priv->vadjustment) * -1.0;
transform = NULL;
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (scroll_x, scroll_y));
gtk_fixed_layout_set_child_transform (GTK_FIXED_LAYOUT (priv->layout), transform);
gsk_transform_unref (transform);
}
static void
gtk_fixed_set_adjustment_values (GtkFixed *self,
GtkOrientation orientation,
GtkAdjustment *adjustment)
{
GtkAllocation allocation;
double old_value;
double new_value;
double size;
gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
old_value = gtk_adjustment_get_value (adjustment);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
size = MAX (allocation.width, gtk_adjustment_get_upper (adjustment));
else
size = MAX (allocation.height, gtk_adjustment_get_upper (adjustment));
g_object_set (adjustment,
"lower", 0.0,
"upper", size,
"page-size", size,
"step-increment", size * 0.1,
"page-increment", size * 0.9,
NULL);
new_value = MAX (old_value, 0);
if (!G_APPROX_VALUE (new_value, old_value, 0.001))
gtk_adjustment_set_value (adjustment, new_value);
}
static void
gtk_fixed_finalize (GObject *gobject)
{
GtkFixed *self = GTK_FIXED (gobject);
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
g_clear_object (&priv->hadjustment);
g_clear_object (&priv->vadjustment);
G_OBJECT_CLASS (gtk_fixed_parent_class)->finalize (gobject);
}
static void
gtk_fixed_set_hadjustment (GtkFixed *self,
GtkAdjustment *adjustment)
{
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
if (adjustment && priv->hadjustment == adjustment)
return;
if (priv->hadjustment != NULL)
{
g_signal_handlers_disconnect_by_func (priv->hadjustment,
gtk_fixed_adjustment_changed,
self);
g_object_unref (priv->hadjustment);
}
if (adjustment == NULL)
adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
g_signal_connect_swapped (adjustment, "value-changed",
G_CALLBACK (gtk_fixed_adjustment_changed),
self);
priv->hadjustment = g_object_ref_sink (adjustment);
gtk_fixed_set_adjustment_values (self, GTK_ORIENTATION_HORIZONTAL, priv->hadjustment);
g_object_notify (G_OBJECT (self), "hadjustment");
}
static void
gtk_fixed_set_vadjustment (GtkFixed *self,
GtkAdjustment *adjustment)
{
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
if (adjustment && priv->vadjustment == adjustment)
return;
if (priv->vadjustment != NULL)
{
g_signal_handlers_disconnect_by_func (priv->vadjustment,
gtk_fixed_adjustment_changed,
self);
g_object_unref (priv->vadjustment);
}
if (adjustment == NULL)
adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
g_signal_connect_swapped (adjustment, "value-changed",
G_CALLBACK (gtk_fixed_adjustment_changed),
self);
priv->vadjustment = g_object_ref_sink (adjustment);
gtk_fixed_set_adjustment_values (self, GTK_ORIENTATION_VERTICAL, priv->vadjustment);
g_object_notify (G_OBJECT (self), "vadjustment");
}
static void
gtk_fixed_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkFixed *self = GTK_FIXED (gobject);
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
switch (prop_id)
{
case PROP_HADJUSTMENT:
g_value_set_object (value, priv->hadjustment);
break;
case PROP_VADJUSTMENT:
g_value_set_object (value, priv->vadjustment);
break;
case PROP_HSCROLL_POLICY:
g_value_set_enum (value, priv->hscroll_policy);
break;
case PROP_VSCROLL_POLICY:
g_value_set_enum (value, priv->vscroll_policy);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_fixed_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkFixed *self = GTK_FIXED (gobject);
GtkFixedPrivate *priv = gtk_fixed_get_instance_private (self);
switch (prop_id)
{
case PROP_HADJUSTMENT:
gtk_fixed_set_hadjustment (self, g_value_get_object (value));
break;
case PROP_VADJUSTMENT:
gtk_fixed_set_vadjustment (self, g_value_get_object (value));
break;
case PROP_HSCROLL_POLICY:
if (priv->hscroll_policy != g_value_get_enum (value))
{
priv->hscroll_policy = g_value_get_enum (value);
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (gobject, pspec);
}
break;
case PROP_VSCROLL_POLICY:
if (priv->vscroll_policy != g_value_get_enum (value))
{
priv->vscroll_policy = g_value_get_enum (value);
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (gobject, pspec);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_fixed_class_init (GtkFixedClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
gobject_class->set_property = gtk_fixed_set_property;
gobject_class->get_property = gtk_fixed_get_property;
gobject_class->finalize = gtk_fixed_finalize;
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;
/* Scrollable interface */
g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment");
g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy");
g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy");
}
static GType
@@ -121,6 +356,7 @@ gtk_fixed_init (GtkFixed *self)
gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
priv->layout = gtk_fixed_layout_new ();
gtk_fixed_layout_set_minimum_size (GTK_FIXED_LAYOUT (priv->layout), -1, -1);
gtk_widget_set_layout_manager (GTK_WIDGET (self), priv->layout);
}

View File

@@ -71,6 +71,11 @@
struct _GtkFixedLayout
{
GtkLayoutManager parent_instance;
int min_width;
int min_height;
GskTransform *child_transform;
};
struct _GtkFixedLayoutChild
@@ -229,7 +234,8 @@ gtk_fixed_layout_measure (GtkLayoutManager *layout_manager,
{
int child_min = 0, child_nat = 0;
int child_min_opp = 0, child_nat_opp = 0;
graphene_rect_t min_rect, nat_rect;
graphene_rect_t nat_rect;
GskTransform *transform = NULL;
if (!gtk_widget_get_visible (child))
continue;
@@ -243,23 +249,16 @@ gtk_fixed_layout_measure (GtkLayoutManager *layout_manager,
&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,
transform = gsk_transform_transform (transform, child_info->position);
gsk_transform_transform_bounds (transform,
&GRAPHENE_RECT_INIT (0.f, 0.f, child_nat, child_nat_opp),
&nat_rect);
gsk_transform_unref (transform);
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);
}
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);
}
natural_size = MAX (natural_size, nat_rect.origin.y + nat_rect.size.height);
}
if (minimum != NULL)
@@ -275,7 +274,9 @@ gtk_fixed_layout_allocate (GtkLayoutManager *layout_manager,
int height,
int baseline)
{
GtkFixedLayout *self = GTK_FIXED_LAYOUT (layout_manager);
GtkFixedLayoutChild *child_info;
GskTransform *transform;
GtkWidget *child;
for (child = _gtk_widget_get_first_child (widget);
@@ -290,11 +291,17 @@ gtk_fixed_layout_allocate (GtkLayoutManager *layout_manager,
child_info = GTK_FIXED_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (layout_manager, child));
gtk_widget_get_preferred_size (child, &child_req, NULL);
transform = NULL;
transform = gsk_transform_transform (transform, self->child_transform);
transform = gsk_transform_transform (transform, child_info->position);
gtk_widget_allocate (child,
child_req.width,
child_req.height,
-1,
child_info->position);
transform);
gsk_transform_unref (transform);
}
}
@@ -329,3 +336,56 @@ gtk_fixed_layout_new (void)
{
return g_object_new (GTK_TYPE_FIXED_LAYOUT, NULL);
}
void
gtk_fixed_layout_set_minimum_size (GtkFixedLayout *layout,
int min_width,
int min_height)
{
g_return_if_fail (GTK_IS_FIXED_LAYOUT (layout));
if (layout->min_width != min_width)
layout->min_width = min_width;
if (layout->min_height != min_height)
layout->min_height = min_height;
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout));
}
void
gtk_fixed_layout_get_minimum_size (GtkFixedLayout *layout,
int *min_width,
int *min_height)
{
g_return_if_fail (GTK_IS_FIXED_LAYOUT (layout));
if (min_width != NULL)
*min_width = layout->min_width;
if (min_height != NULL)
*min_height = layout->min_height;
}
void
gtk_fixed_layout_set_child_transform (GtkFixedLayout *layout,
GskTransform *transform)
{
g_return_if_fail (GTK_IS_FIXED_LAYOUT (layout));
if (layout->child_transform == transform)
return;
gsk_transform_unref (layout->child_transform);
layout->child_transform = gsk_transform_ref (transform);
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout));
}
GskTransform *
gtk_fixed_layout_get_child_transform (GtkFixedLayout *layout)
{
g_return_val_if_fail (GTK_IS_FIXED_LAYOUT (layout), NULL);
return layout->child_transform;
}

View File

@@ -20,6 +20,7 @@
#pragma once
#include <gsk/gsk.h>
#include <gtk/gtklayoutmanager.h>
G_BEGIN_DECLS
@@ -35,6 +36,20 @@ G_DECLARE_FINAL_TYPE (GtkFixedLayout, gtk_fixed_layout, GTK, FIXED_LAYOUT, GtkLa
GDK_AVAILABLE_IN_ALL
GtkLayoutManager * gtk_fixed_layout_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_fixed_layout_set_minimum_size (GtkFixedLayout *layout,
int min_width,
int min_height);
GDK_AVAILABLE_IN_ALL
void gtk_fixed_layout_get_minimum_size (GtkFixedLayout *layout,
int *min_width,
int *min_height);
GDK_AVAILABLE_IN_ALL
void gtk_fixed_layout_set_child_transform (GtkFixedLayout *layout,
GskTransform *transform);
GDK_AVAILABLE_IN_ALL
GskTransform * gtk_fixed_layout_get_child_transform (GtkFixedLayout *layout);
/* GtkFixedLayoutChild */
GDK_AVAILABLE_IN_ALL