boxgadget: Add
Adds a GtkBoxGadget that is a Gadget that behaves like a GtkBox. Use this gadget to implement the notebook base gadget.
This commit is contained in:
@ -365,6 +365,7 @@ gtk_private_h_sources = \
|
||||
gtkbitmaskprivateimpl.h \
|
||||
gtkbookmarksmanager.h \
|
||||
gtkboxprivate.h \
|
||||
gtkboxgadgetprivate.h \
|
||||
gtkbuilderprivate.h \
|
||||
gtkbuiltiniconprivate.h \
|
||||
gtkbuttonprivate.h \
|
||||
@ -600,6 +601,7 @@ gtk_base_c_sources = \
|
||||
gtkbookmarksmanager.c \
|
||||
gtkborder.c \
|
||||
gtkbox.c \
|
||||
gtkboxgadget.c \
|
||||
gtkbuildable.c \
|
||||
gtkbuilder.c \
|
||||
gtkbuilderparser.c \
|
||||
|
||||
511
gtk/gtkboxgadget.c
Normal file
511
gtk/gtkboxgadget.c
Normal file
@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Copyright © 2015 Red Hat Inc.
|
||||
*
|
||||
* 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 "gtkboxgadgetprivate.h"
|
||||
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
typedef struct _GtkBoxGadgetPrivate GtkBoxGadgetPrivate;
|
||||
struct _GtkBoxGadgetPrivate {
|
||||
GtkOrientation orientation;
|
||||
GArray *children;
|
||||
};
|
||||
|
||||
typedef gboolean (* ComputeExpandFunc) (GObject *object, GtkOrientation orientation);
|
||||
|
||||
typedef struct _GtkBoxGadgetChild GtkBoxGadgetChild;
|
||||
struct _GtkBoxGadgetChild {
|
||||
GObject *object;
|
||||
ComputeExpandFunc compute_expand;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkBoxGadget, gtk_box_gadget, GTK_TYPE_CSS_GADGET,
|
||||
G_ADD_PRIVATE (GtkBoxGadget))
|
||||
|
||||
static gboolean
|
||||
gtk_box_gadget_child_is_visible (GObject *child)
|
||||
{
|
||||
if (GTK_IS_WIDGET (child))
|
||||
return gtk_widget_get_visible (GTK_WIDGET (child));
|
||||
else
|
||||
return gtk_css_gadget_get_visible (GTK_CSS_GADGET (child));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_measure_child (GObject *child,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum,
|
||||
gint *natural,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline)
|
||||
{
|
||||
if (GTK_IS_WIDGET (child))
|
||||
{
|
||||
_gtk_widget_get_preferred_size_for_size (GTK_WIDGET (child),
|
||||
orientation,
|
||||
for_size,
|
||||
minimum, natural,
|
||||
minimum_baseline, natural_baseline);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_css_gadget_get_preferred_size (GTK_CSS_GADGET (child),
|
||||
orientation,
|
||||
for_size,
|
||||
minimum, natural,
|
||||
minimum_baseline, natural_baseline);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_distribute (GtkBoxGadget *gadget,
|
||||
gint size,
|
||||
GtkRequestedSize *sizes)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
|
||||
guint i, n_expand;
|
||||
|
||||
n_expand = 0;
|
||||
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
gtk_box_gadget_measure_child (child->object,
|
||||
priv->orientation,
|
||||
-1,
|
||||
&sizes[i].minimum_size, &sizes[i].natural_size,
|
||||
NULL, NULL);
|
||||
if (gtk_box_gadget_child_is_visible (child->object) &&
|
||||
child->compute_expand (child->object, priv->orientation))
|
||||
n_expand++;
|
||||
size -= sizes[i].minimum_size;
|
||||
}
|
||||
|
||||
g_assert (size >= 0);
|
||||
|
||||
size = gtk_distribute_natural_allocation (size, priv->children->len, sizes);
|
||||
|
||||
if (size <= 0 || n_expand == 0)
|
||||
return;
|
||||
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
if (!gtk_box_gadget_child_is_visible (child->object) ||
|
||||
!child->compute_expand (child->object, priv->orientation))
|
||||
continue;
|
||||
|
||||
sizes[i].minimum_size += size / n_expand;
|
||||
/* distribute all pixels, even if there's a remainder */
|
||||
size -= size / n_expand;
|
||||
n_expand--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_measure_orientation (GtkCssGadget *gadget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum,
|
||||
gint *natural,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
|
||||
gint child_min, child_nat;
|
||||
guint i;
|
||||
|
||||
*minimum = 0;
|
||||
*natural = 0;
|
||||
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
gtk_box_gadget_measure_child (child->object,
|
||||
orientation,
|
||||
for_size,
|
||||
&child_min, &child_nat,
|
||||
NULL, NULL);
|
||||
|
||||
*minimum += child_min;
|
||||
*natural += child_nat;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_measure_opposite (GtkCssGadget *gadget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum,
|
||||
gint *natural,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
|
||||
int child_min, child_nat, child_min_baseline, child_nat_baseline;
|
||||
int total_min, above_min, below_min, total_nat, above_nat, below_nat;
|
||||
GtkRequestedSize *sizes;
|
||||
guint i;
|
||||
|
||||
if (for_size >= 0)
|
||||
{
|
||||
sizes = g_newa (GtkRequestedSize, priv->children->len);
|
||||
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), for_size, sizes);
|
||||
}
|
||||
|
||||
above_min = below_min = above_nat = below_nat = -1;
|
||||
total_min = total_nat = 0;
|
||||
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
gtk_box_gadget_measure_child (child->object,
|
||||
orientation,
|
||||
for_size >= 0 ? sizes[i].minimum_size : for_size,
|
||||
&child_min, &child_nat,
|
||||
&child_min_baseline, &child_nat_baseline);
|
||||
|
||||
if (child_min_baseline >= 0)
|
||||
{
|
||||
above_min = MAX (above_min, child_min - child_min_baseline);
|
||||
below_min = MAX (below_min, child_min_baseline);
|
||||
above_nat = MAX (above_nat, child_nat - child_nat_baseline);
|
||||
below_nat = MAX (below_nat, child_nat_baseline);
|
||||
}
|
||||
else
|
||||
{
|
||||
total_min = MAX (total_min, child_min);
|
||||
total_nat = MAX (total_nat, child_nat);
|
||||
}
|
||||
}
|
||||
|
||||
if (above_min >= 0)
|
||||
{
|
||||
total_min = MAX (total_min, above_min + below_min);
|
||||
total_nat = MAX (total_nat, above_nat + below_nat);
|
||||
/* assume GTK_BASELINE_POSITION_CENTER for now */
|
||||
*minimum_baseline = above_min + (total_min - (above_min + below_min)) / 2;
|
||||
*natural_baseline = above_nat + (total_nat - (above_nat + below_nat)) / 2;
|
||||
}
|
||||
|
||||
*minimum = total_min;
|
||||
*natural = total_nat;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_get_preferred_size (GtkCssGadget *gadget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum,
|
||||
gint *natural,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
|
||||
|
||||
if (priv->orientation == orientation)
|
||||
gtk_box_gadget_measure_orientation (gadget, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
|
||||
else
|
||||
gtk_box_gadget_measure_opposite (gadget, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_allocate_child (GObject *child,
|
||||
GtkAllocation *allocation,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip)
|
||||
{
|
||||
if (GTK_IS_WIDGET (child))
|
||||
{
|
||||
gtk_widget_size_allocate_with_baseline (GTK_WIDGET (child),
|
||||
allocation,
|
||||
baseline);
|
||||
gtk_widget_get_clip (GTK_WIDGET (child), out_clip);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_css_gadget_allocate (GTK_CSS_GADGET (child),
|
||||
allocation,
|
||||
baseline,
|
||||
out_clip);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_allocate (GtkCssGadget *gadget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
|
||||
GtkRequestedSize *sizes;
|
||||
GtkAllocation child_allocation, child_clip;
|
||||
guint i;
|
||||
|
||||
child_allocation = *allocation;
|
||||
sizes = g_newa (GtkRequestedSize, priv->children->len);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->width, sizes);
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
child_allocation.width = sizes[i].minimum_size;
|
||||
gtk_box_gadget_allocate_child (child->object, &child_allocation, baseline, &child_clip);
|
||||
if (i == 0)
|
||||
*out_clip = child_clip;
|
||||
else
|
||||
gdk_rectangle_union (out_clip, &child_clip, out_clip);
|
||||
child_allocation.x += sizes[i].minimum_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->height, sizes);
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
child_allocation.height = sizes[i].minimum_size;
|
||||
gtk_box_gadget_allocate_child (child->object, &child_allocation, -1, &child_clip);
|
||||
if (i == 0)
|
||||
*out_clip = child_clip;
|
||||
else
|
||||
gdk_rectangle_union (out_clip, &child_clip, out_clip);
|
||||
child_allocation.y += sizes[i].minimum_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_box_gadget_draw (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
|
||||
guint i;
|
||||
|
||||
for (i = 0 ; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
if (GTK_IS_WIDGET (child->object))
|
||||
{
|
||||
gtk_container_propagate_draw (GTK_CONTAINER (gtk_css_gadget_get_owner (gadget)),
|
||||
GTK_WIDGET (child->object),
|
||||
cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_css_gadget_draw (GTK_CSS_GADGET (child->object),
|
||||
cr);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_finalize (GObject *object)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (object));
|
||||
|
||||
g_array_free (priv->children, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gtk_box_gadget_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_class_init (GtkBoxGadgetClass *klass)
|
||||
{
|
||||
GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gtk_box_gadget_finalize;
|
||||
|
||||
gadget_class->get_preferred_size = gtk_box_gadget_get_preferred_size;
|
||||
gadget_class->allocate = gtk_box_gadget_allocate;
|
||||
gadget_class->draw = gtk_box_gadget_draw;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_clear_child (gpointer data)
|
||||
{
|
||||
GtkBoxGadgetChild *child = data;
|
||||
|
||||
g_object_unref (child->object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_init (GtkBoxGadget *gadget)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
|
||||
|
||||
priv->children = g_array_new (FALSE, FALSE, sizeof (GtkBoxGadgetChild));
|
||||
g_array_set_clear_func (priv->children, gtk_box_gadget_clear_child);
|
||||
}
|
||||
|
||||
GtkCssGadget *
|
||||
gtk_box_gadget_new_for_node (GtkCssNode *node,
|
||||
GtkWidget *owner)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_BOX_GADGET,
|
||||
"node", node,
|
||||
"owner", owner,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GtkCssGadget *
|
||||
gtk_box_gadget_new (const char *name,
|
||||
GtkWidget *owner,
|
||||
GtkCssGadget *parent,
|
||||
GtkCssGadget *next_sibling)
|
||||
{
|
||||
GtkCssNode *node;
|
||||
GtkCssGadget *result;
|
||||
|
||||
node = gtk_css_node_new ();
|
||||
gtk_css_node_set_name (node, g_intern_string (name));
|
||||
if (parent)
|
||||
gtk_css_node_insert_before (gtk_css_gadget_get_node (parent),
|
||||
node,
|
||||
next_sibling ? gtk_css_gadget_get_node (next_sibling) : NULL);
|
||||
|
||||
result = gtk_box_gadget_new_for_node (node, owner);
|
||||
|
||||
g_object_unref (node);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_box_gadget_set_orientation (GtkBoxGadget *gadget,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
|
||||
|
||||
priv->orientation = orientation;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_box_gadget_insert_object (GtkBoxGadget *gadget,
|
||||
int pos,
|
||||
GObject *object,
|
||||
ComputeExpandFunc compute_expand_func)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
|
||||
GtkBoxGadgetChild child;
|
||||
|
||||
child.object = g_object_ref (object);
|
||||
child.compute_expand = compute_expand_func;
|
||||
|
||||
if (pos < 0 || pos >= priv->children->len)
|
||||
g_array_append_val (priv->children, child);
|
||||
else
|
||||
g_array_insert_val (priv->children, pos, child);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_box_gadget_insert_widget (GtkBoxGadget *gadget,
|
||||
int pos,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
gtk_box_gadget_insert_object (gadget,
|
||||
pos,
|
||||
G_OBJECT (widget),
|
||||
(ComputeExpandFunc) gtk_widget_compute_expand);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_box_gadget_remove_object (GtkBoxGadget *gadget,
|
||||
GObject *object)
|
||||
{
|
||||
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < priv->children->len; i++)
|
||||
{
|
||||
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
|
||||
|
||||
if (child->object == object)
|
||||
{
|
||||
g_array_remove_index (priv->children, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_box_gadget_remove_widget (GtkBoxGadget *gadget,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
gtk_box_gadget_remove_object (gadget, G_OBJECT (widget));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
only_horizontal (GObject *object,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
return orientation == GTK_ORIENTATION_HORIZONTAL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
only_vertical (GObject *object,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
return orientation == GTK_ORIENTATION_VERTICAL;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget,
|
||||
int pos,
|
||||
GtkCssGadget *cssgadget,
|
||||
gboolean hexpand,
|
||||
gboolean vexpand)
|
||||
{
|
||||
gtk_box_gadget_insert_object (gadget,
|
||||
pos,
|
||||
G_OBJECT (cssgadget),
|
||||
hexpand ? (vexpand ? (ComputeExpandFunc) gtk_true : only_horizontal)
|
||||
: (vexpand ? only_vertical : (ComputeExpandFunc) gtk_false));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
|
||||
GtkCssGadget *cssgadget)
|
||||
{
|
||||
gtk_box_gadget_remove_object (gadget, G_OBJECT (cssgadget));
|
||||
}
|
||||
|
||||
74
gtk/gtkboxgadgetprivate.h
Normal file
74
gtk/gtkboxgadgetprivate.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright © 2015 Red Hat Inc.
|
||||
*
|
||||
* 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_BOX_GADGET_PRIVATE_H__
|
||||
#define __GTK_BOX_GADGET_PRIVATE_H__
|
||||
|
||||
#include "gtk/gtkcssgadgetprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_BOX_GADGET (gtk_box_gadget_get_type ())
|
||||
#define GTK_BOX_GADGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_BOX_GADGET, GtkBoxGadget))
|
||||
#define GTK_BOX_GADGET_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass))
|
||||
#define GTK_IS_BOX_GADGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_BOX_GADGET))
|
||||
#define GTK_IS_BOX_GADGET_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_BOX_GADGET))
|
||||
#define GTK_BOX_GADGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass))
|
||||
|
||||
typedef struct _GtkBoxGadget GtkBoxGadget;
|
||||
typedef struct _GtkBoxGadgetClass GtkBoxGadgetClass;
|
||||
|
||||
struct _GtkBoxGadget
|
||||
{
|
||||
GtkCssGadget parent;
|
||||
};
|
||||
|
||||
struct _GtkBoxGadgetClass
|
||||
{
|
||||
GtkCssGadgetClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_box_gadget_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkCssGadget * gtk_box_gadget_new (const char *name,
|
||||
GtkWidget *owner,
|
||||
GtkCssGadget *parent,
|
||||
GtkCssGadget *next_sibling);
|
||||
GtkCssGadget * gtk_box_gadget_new_for_node (GtkCssNode *node,
|
||||
GtkWidget *owner);
|
||||
|
||||
void gtk_box_gadget_set_orientation (GtkBoxGadget *gadget,
|
||||
GtkOrientation orientation);
|
||||
|
||||
void gtk_box_gadget_insert_widget (GtkBoxGadget *gadget,
|
||||
int pos,
|
||||
GtkWidget *widget);
|
||||
void gtk_box_gadget_remove_widget (GtkBoxGadget *gadget,
|
||||
GtkWidget *widget);
|
||||
void gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget,
|
||||
int pos,
|
||||
GtkCssGadget *cssgadget,
|
||||
gboolean hexpand,
|
||||
gboolean vexpand);
|
||||
void gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
|
||||
GtkCssGadget *cssgadget);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_BOX_GADGET_PRIVATE_H__ */
|
||||
@ -43,6 +43,7 @@
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidgetpath.h"
|
||||
#include "gtkboxgadgetprivate.h"
|
||||
#include "gtkcsscustomgadgetprivate.h"
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtksizerequest.h"
|
||||
@ -521,26 +522,6 @@ static gboolean gtk_notebook_draw_stack (GtkCssGadget *gadget,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
static void gtk_notebook_measure_contents (GtkCssGadget *gadget,
|
||||
GtkOrientation orientation,
|
||||
gint for_size,
|
||||
gint *minimum,
|
||||
gint *natural,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline,
|
||||
gpointer data);
|
||||
static void gtk_notebook_allocate_contents (GtkCssGadget *gadget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip,
|
||||
gpointer data);
|
||||
static gboolean gtk_notebook_draw_contents (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
|
||||
/*** GtkNotebook Private Functions ***/
|
||||
static void gtk_notebook_redraw_tabs (GtkNotebook *notebook);
|
||||
@ -603,6 +584,8 @@ static void gtk_notebook_menu_label_unparent (GtkWidget *widget,
|
||||
static void gtk_notebook_menu_detacher (GtkWidget *widget,
|
||||
GtkMenu *menu);
|
||||
|
||||
static void gtk_notebook_update_tab_pos (GtkNotebook *notebook);
|
||||
|
||||
/*** GtkNotebook Private Setters ***/
|
||||
static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
|
||||
gboolean overload,
|
||||
@ -1350,14 +1333,10 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
|
||||
|
||||
widget_node = gtk_widget_get_css_node (GTK_WIDGET (notebook));
|
||||
priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
|
||||
GTK_WIDGET (notebook),
|
||||
gtk_notebook_measure_contents,
|
||||
gtk_notebook_allocate_contents,
|
||||
gtk_notebook_draw_contents,
|
||||
NULL,
|
||||
NULL);
|
||||
priv->gadget = gtk_box_gadget_new_for_node (widget_node,
|
||||
GTK_WIDGET (notebook));
|
||||
gtk_css_gadget_add_class (priv->gadget, GTK_STYLE_CLASS_FRAME);
|
||||
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
priv->stack_gadget = gtk_css_custom_gadget_new ("stack",
|
||||
GTK_WIDGET (notebook),
|
||||
@ -1369,6 +1348,7 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
NULL,
|
||||
NULL);
|
||||
gtk_css_gadget_set_state (priv->stack_gadget, gtk_css_node_get_state (widget_node));
|
||||
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), -1, priv->stack_gadget, TRUE, TRUE);
|
||||
|
||||
priv->header_gadget = gtk_css_custom_gadget_new ("header",
|
||||
GTK_WIDGET (notebook),
|
||||
@ -1381,6 +1361,8 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
NULL);
|
||||
gtk_css_gadget_add_class (priv->header_gadget, GTK_STYLE_CLASS_TOP);
|
||||
gtk_css_gadget_set_state (priv->header_gadget, gtk_css_node_get_state (widget_node));
|
||||
gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
|
||||
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
|
||||
|
||||
priv->tabs_node = gtk_css_node_new ();
|
||||
gtk_css_node_set_name (priv->tabs_node, I_("tabs"));
|
||||
@ -1995,7 +1977,7 @@ gtk_notebook_realize (GtkWidget *widget)
|
||||
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
|
||||
gtk_notebook_get_event_window_position (notebook, &event_window_pos);
|
||||
gtk_css_gadget_get_border_allocation (priv->header_gadget, &event_window_pos, NULL);
|
||||
|
||||
window = gtk_widget_get_parent_window (widget);
|
||||
gtk_widget_set_window (widget, window);
|
||||
@ -2280,115 +2262,6 @@ gtk_notebook_measure_stack (GtkCssGadget *gadget,
|
||||
}
|
||||
}
|
||||
|
||||
static GtkOrientation
|
||||
get_orientation_from_tab_pos (GtkNotebook *notebook)
|
||||
{
|
||||
GtkPositionType tab_pos = notebook->priv->tab_pos;
|
||||
|
||||
if (tab_pos == GTK_POS_LEFT || tab_pos == GTK_POS_RIGHT)
|
||||
return GTK_ORIENTATION_HORIZONTAL;
|
||||
else
|
||||
return GTK_ORIENTATION_VERTICAL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_distribute_content_size (GtkNotebook *notebook,
|
||||
gint size,
|
||||
gint *header_size,
|
||||
gint *stack_size)
|
||||
{
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GtkOrientation orientation = get_orientation_from_tab_pos (notebook);
|
||||
GtkRequestedSize request[2];
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
*header_size = -1;
|
||||
*stack_size = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_css_gadget_get_preferred_size (priv->header_gadget,
|
||||
orientation,
|
||||
-1,
|
||||
&request[0].minimum_size, &request[0].natural_size,
|
||||
NULL, NULL);
|
||||
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
|
||||
orientation,
|
||||
-1,
|
||||
&request[1].minimum_size, &request[1].natural_size,
|
||||
NULL, NULL);
|
||||
|
||||
size = gtk_distribute_natural_allocation (size - request[0].minimum_size - request[1].minimum_size,
|
||||
G_N_ELEMENTS (request),
|
||||
request);
|
||||
|
||||
*header_size = request[0].minimum_size;
|
||||
*stack_size = request[1].minimum_size + size;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_measure_contents (GtkCssGadget *gadget,
|
||||
GtkOrientation orientation,
|
||||
gint size,
|
||||
gint *minimum,
|
||||
gint *natural,
|
||||
gint *minimum_baseline,
|
||||
gint *natural_baseline,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
gint stack_min, stack_nat, header_min, header_nat;
|
||||
|
||||
if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook))
|
||||
{
|
||||
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
|
||||
orientation,
|
||||
size,
|
||||
minimum, natural,
|
||||
NULL, NULL);
|
||||
|
||||
}
|
||||
else if (orientation == get_orientation_from_tab_pos (notebook))
|
||||
{
|
||||
gtk_css_gadget_get_preferred_size (priv->header_gadget,
|
||||
orientation,
|
||||
size,
|
||||
&header_min, &header_nat,
|
||||
NULL, NULL);
|
||||
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
|
||||
orientation,
|
||||
size,
|
||||
&stack_min, &stack_nat,
|
||||
NULL, NULL);
|
||||
|
||||
*minimum = header_min + stack_min;
|
||||
*natural = header_nat + stack_nat;
|
||||
}
|
||||
else
|
||||
{
|
||||
gint header_size, stack_size;
|
||||
|
||||
gtk_notebook_distribute_content_size (notebook, size, &header_size, &stack_size);
|
||||
|
||||
gtk_css_gadget_get_preferred_size (priv->header_gadget,
|
||||
orientation,
|
||||
header_size,
|
||||
&header_min, &header_nat,
|
||||
NULL, NULL);
|
||||
gtk_css_gadget_get_preferred_size (priv->stack_gadget,
|
||||
orientation,
|
||||
stack_size,
|
||||
&stack_min, &stack_nat,
|
||||
NULL, NULL);
|
||||
|
||||
*minimum = MAX (header_min, stack_min);
|
||||
*natural = MAX (header_nat, stack_nat);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_get_preferred_width_for_height (GtkWidget *widget,
|
||||
gint height,
|
||||
@ -2517,89 +2390,6 @@ gtk_notebook_allocate_stack (GtkCssGadget *gadget,
|
||||
gtk_widget_get_clip (priv->cur_page->child, out_clip);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_allocate_contents (GtkCssGadget *gadget,
|
||||
const GtkAllocation *allocation,
|
||||
int baseline,
|
||||
GtkAllocation *out_clip,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GtkAllocation stack_allocation, header_allocation;
|
||||
|
||||
stack_allocation = *allocation;
|
||||
|
||||
if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook))
|
||||
{
|
||||
gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, out_clip);
|
||||
if (gtk_widget_get_realized (widget))
|
||||
gdk_window_hide (priv->event_window);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkAllocation stack_clip, header_clip;
|
||||
|
||||
header_allocation = stack_allocation;
|
||||
|
||||
switch (get_effective_tab_pos (notebook))
|
||||
{
|
||||
case GTK_POS_TOP:
|
||||
gtk_notebook_distribute_content_size (notebook,
|
||||
stack_allocation.height,
|
||||
&header_allocation.height,
|
||||
&stack_allocation.height);
|
||||
stack_allocation.y += header_allocation.height;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
gtk_notebook_distribute_content_size (notebook,
|
||||
stack_allocation.height,
|
||||
&header_allocation.height,
|
||||
&stack_allocation.height);
|
||||
header_allocation.y += stack_allocation.height;
|
||||
break;
|
||||
|
||||
case GTK_POS_LEFT:
|
||||
gtk_notebook_distribute_content_size (notebook,
|
||||
stack_allocation.width,
|
||||
&header_allocation.width,
|
||||
&stack_allocation.width);
|
||||
stack_allocation.x += header_allocation.width;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
gtk_notebook_distribute_content_size (notebook,
|
||||
stack_allocation.width,
|
||||
&header_allocation.width,
|
||||
&stack_allocation.width);
|
||||
header_allocation.x += stack_allocation.width;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_css_gadget_allocate (priv->header_gadget, &header_allocation, -1, &header_clip);
|
||||
gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, &stack_clip);
|
||||
|
||||
gdk_rectangle_union (&stack_clip, &header_clip, out_clip);
|
||||
|
||||
if (gtk_widget_get_realized (widget))
|
||||
{
|
||||
GtkAllocation position;
|
||||
gtk_css_gadget_get_border_allocation (priv->header_gadget, &position, NULL);
|
||||
gdk_window_move_resize (priv->event_window,
|
||||
position.x, position.y,
|
||||
position.width, position.height);
|
||||
if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
|
||||
gdk_window_show_unraised (priv->event_window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
@ -2616,6 +2406,22 @@ gtk_notebook_size_allocate (GtkWidget *widget,
|
||||
&clip);
|
||||
|
||||
gtk_widget_set_clip (widget, &clip);
|
||||
|
||||
if (gtk_widget_get_realized (widget))
|
||||
{
|
||||
GdkRectangle position;
|
||||
|
||||
if (gtk_notebook_get_event_window_position (notebook, &position))
|
||||
{
|
||||
gdk_window_move_resize (priv->event_window,
|
||||
position.x, position.y,
|
||||
position.width, position.height);
|
||||
if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
|
||||
gdk_window_show_unraised (priv->event_window);
|
||||
}
|
||||
else
|
||||
gdk_window_hide (priv->event_window);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -2639,40 +2445,6 @@ gtk_notebook_draw_stack (GtkCssGadget *gadget,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_notebook_draw_contents (GtkCssGadget *gadget,
|
||||
cairo_t *cr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GdkWindow *window;
|
||||
|
||||
window = gtk_widget_get_window (widget);
|
||||
if (gtk_cairo_should_draw_window (cr, window))
|
||||
{
|
||||
gtk_css_gadget_draw (priv->stack_gadget, cr);
|
||||
|
||||
if (priv->show_tabs && gtk_notebook_has_current_page (notebook))
|
||||
gtk_css_gadget_draw (priv->header_gadget, cr);
|
||||
}
|
||||
|
||||
if (gtk_notebook_has_current_page (notebook) && priv->operation == DRAG_OPERATION_REORDER &&
|
||||
gtk_cairo_should_draw_window (cr, priv->drag_window))
|
||||
{
|
||||
gtk_notebook_draw_tab (notebook,
|
||||
priv->cur_page,
|
||||
cr);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_notebook_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
@ -4800,19 +4572,22 @@ page_visible_cb (GtkWidget *child,
|
||||
gtk_widget_set_visible (parent, gtk_widget_get_visible (child));
|
||||
}
|
||||
|
||||
if (priv->cur_page == page &&
|
||||
!gtk_widget_get_visible (child))
|
||||
if (priv->cur_page == page)
|
||||
{
|
||||
list = g_list_find (priv->children, priv->cur_page);
|
||||
if (list)
|
||||
if (!gtk_widget_get_visible (child))
|
||||
{
|
||||
next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
|
||||
if (!next)
|
||||
next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
|
||||
}
|
||||
list = g_list_find (priv->children, priv->cur_page);
|
||||
if (list)
|
||||
{
|
||||
next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
|
||||
if (!next)
|
||||
next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
|
||||
}
|
||||
|
||||
if (next)
|
||||
gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
|
||||
if (next)
|
||||
gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
|
||||
}
|
||||
gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs && gtk_notebook_has_current_page (notebook));
|
||||
}
|
||||
|
||||
if (!gtk_notebook_has_current_page (notebook) && gtk_widget_get_visible (child))
|
||||
@ -6632,6 +6407,7 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
|
||||
priv->cur_page = page;
|
||||
gtk_css_node_set_state (page->cssnode,
|
||||
gtk_css_node_get_state (page->cssnode) | GTK_STATE_FLAG_ACTIVE);
|
||||
gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs);
|
||||
|
||||
if (!priv->focus_tab ||
|
||||
priv->focus_tab->data != (gpointer) priv->cur_page)
|
||||
@ -7418,11 +7194,14 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
|
||||
else
|
||||
gtk_widget_hide (page->tab_label);
|
||||
}
|
||||
gtk_css_gadget_set_visible (priv->header_gadget,
|
||||
gtk_notebook_has_current_page (notebook));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
|
||||
gtk_notebook_update_labels (notebook);
|
||||
gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < N_ACTION_WIDGETS; i++)
|
||||
@ -7431,6 +7210,7 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
|
||||
gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
|
||||
}
|
||||
|
||||
gtk_notebook_update_tab_pos (notebook);
|
||||
gtk_widget_reset_style (GTK_WIDGET (notebook));
|
||||
gtk_widget_queue_resize (GTK_WIDGET (notebook));
|
||||
|
||||
@ -7476,6 +7256,34 @@ gtk_notebook_update_tab_pos (GtkNotebook *notebook)
|
||||
else
|
||||
gtk_css_gadget_remove_class (priv->header_gadget, tab_pos_names[i]);
|
||||
}
|
||||
|
||||
gtk_box_gadget_remove_gadget (GTK_BOX_GADGET (priv->gadget), priv->header_gadget);
|
||||
switch (tab_pos)
|
||||
{
|
||||
case GTK_POS_TOP:
|
||||
if (priv->show_tabs)
|
||||
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
|
||||
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
if (priv->show_tabs)
|
||||
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
|
||||
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
|
||||
break;
|
||||
|
||||
case GTK_POS_LEFT:
|
||||
if (priv->show_tabs)
|
||||
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
|
||||
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
if (priv->show_tabs)
|
||||
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
|
||||
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user