Quelle gtkcenterbox.c
Sprache: C
/*
* Copyright ( c ) 2017 Timm B ä der < mail @ baedert . org >
*
* This program 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 program 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 program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* Author : Timm B ä der < mail @ baedert . org >
*/
/**
* GtkCenterBox :
*
* Arranges three children in a row , keeping the middle child
* centered as well as possible .
*
* < picture >
* < source srcset = " centerbox - dark . png " media = " ( prefers - color - scheme : dark ) " >
* < img alt = " An example GtkCenterBox " src = " centerbox . png " >
* < / picture >
*
* To add children to ` GtkCenterBox ` , use [ method @ Gtk . CenterBox . set_start_widget ] ,
* [ method @ Gtk . CenterBox . set_center_widget ] and
* [ method @ Gtk . CenterBox . set_end_widget ] .
*
* The sizing and positioning of children can be influenced with the
* align and expand properties of the children .
*
* # GtkCenterBox as GtkBuildable
*
* The ` GtkCenterBox ` implementation of the ` GtkBuildable ` interface
* supports placing children in the 3 positions by specifying “ start ” , “ center ”
* or “ end ” as the “ type ” attribute of a ` < child > ` element .
*
* # CSS nodes
*
* ` GtkCenterBox ` uses a single CSS node with the name “ box ” ,
*
* The first child of the ` GtkCenterBox ` will be allocated depending on the
* text direction , i . e . in left - to - right layouts it will be allocated on the
* left and in right - to - left layouts on the right .
*
* In vertical orientation , the nodes of the children are arranged from top to
* bottom .
*
* # Accessibility
*
* Until GTK 4 . 10 , ` GtkCenterBox ` used the [ enum @ Gtk . AccessibleRole . group ] role .
*
* Starting from GTK 4 . 12 , ` GtkCenterBox ` uses the [ enum @ Gtk . AccessibleRole . generic ]
* role .
*/
#include "config.h"
#include "gtkcenterbox.h"
#include "gtkcenterlayout.h"
#include "gtkwidgetprivate.h"
#include "gtkorientable.h"
#include "gtkbuildable.h"
#include "gtkbuilderprivate.h"
#include "gtksizerequest.h"
#include "gtktypebuiltins.h"
#include "gtkprivate.h"
struct _GtkCenterBox
{
GtkWidget parent_instance;
GtkWidget *start_widget;
GtkWidget *center_widget;
GtkWidget *end_widget;
};
struct _GtkCenterBoxClass
{
GtkWidgetClass parent_class;
};
enum {
PROP_0,
PROP_START_WIDGET,
PROP_CENTER_WIDGET,
PROP_END_WIDGET,
PROP_BASELINE_POSITION,
PROP_SHRINK_CENTER_LAST,
/* GtkOrientable */
PROP_ORIENTATION,
LAST_PROP,
};
static GParamSpec *props[LAST_PROP] = { NULL, };
static GtkBuildableIface *parent_buildable_iface;
static void gtk_center_box_buildable_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkCenterBox, gtk_center_box, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_center_box_buildable_init))
static void
gtk_center_box_buildable_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const char *type)
{
if (g_strcmp0 (type, "start" ) == 0 )
{
gtk_buildable_child_deprecation_warning (buildable, builder, "start" , "start-widget" );
gtk_center_box_set_start_widget (GTK_CENTER_BOX (buildable), GTK_WIDGET (child));
}
else if (g_strcmp0 (type, "center" ) == 0 )
{
gtk_buildable_child_deprecation_warning (buildable, builder, "center" , "center-widget" );
gtk_center_box_set_center_widget (GTK_CENTER_BOX (buildable), GTK_WIDGET (child));
}
else if (g_strcmp0 (type, "end" ) == 0 )
{
gtk_buildable_child_deprecation_warning (buildable, builder, "end" , "end-widget" );
gtk_center_box_set_end_widget (GTK_CENTER_BOX (buildable), GTK_WIDGET (child));
}
else
{
parent_buildable_iface->add_child (buildable, builder, child, type);
}
}
static void
gtk_center_box_buildable_init (GtkBuildableIface *iface)
{
parent_buildable_iface = g_type_interface_peek_parent (iface);
iface->add_child = gtk_center_box_buildable_add_child;
}
static void
gtk_center_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkCenterBox *self = GTK_CENTER_BOX (object);
GtkLayoutManager *layout = gtk_widget_get_layout_manager (GTK_WIDGET (object));
switch (prop_id)
{
case PROP_BASELINE_POSITION:
gtk_center_box_set_baseline_position (self, g_value_get_enum (value));
break ;
case PROP_ORIENTATION:
{
GtkOrientation orientation = g_value_get_enum (value);
GtkOrientation current = gtk_center_layout_get_orientation (GTK_CENTER_LAYOUT (layout));
if (current != orientation)
{
gtk_center_layout_set_orientation (GTK_CENTER_LAYOUT (layout), orientation);
gtk_widget_update_orientation (GTK_WIDGET (self), orientation);
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (object, props[PROP_ORIENTATION]);
}
}
break ;
case PROP_START_WIDGET:
gtk_center_box_set_start_widget (self, GTK_WIDGET (g_value_get_object (value)));
break ;
case PROP_CENTER_WIDGET:
gtk_center_box_set_center_widget (self, GTK_WIDGET (g_value_get_object (value)));
break ;
case PROP_END_WIDGET:
gtk_center_box_set_end_widget (self, GTK_WIDGET (g_value_get_object (value)));
break ;
case PROP_SHRINK_CENTER_LAST:
gtk_center_box_set_shrink_center_last (self, g_value_get_boolean (value));
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break ;
}
}
static void
gtk_center_box_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkCenterBox *self = GTK_CENTER_BOX (object);
GtkLayoutManager *layout = gtk_widget_get_layout_manager (GTK_WIDGET (object));
switch (prop_id)
{
case PROP_BASELINE_POSITION:
g_value_set_enum (value, gtk_center_layout_get_baseline_position (GTK_CENTER_LAYOUT (layout)));
break ;
case PROP_ORIENTATION:
g_value_set_enum (value, gtk_center_layout_get_orientation (GTK_CENTER_LAYOUT (layout)));
break ;
case PROP_START_WIDGET:
g_value_set_object (value, self->start_widget);
break ;
case PROP_CENTER_WIDGET:
g_value_set_object (value, self->center_widget);
break ;
case PROP_END_WIDGET:
g_value_set_object (value, self->end_widget);
break ;
case PROP_SHRINK_CENTER_LAST:
g_value_set_boolean (value, gtk_center_layout_get_shrink_center_last (GTK_CENTER_LAYOUT (layout)));
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break ;
}
}
static void
gtk_center_box_dispose (GObject *object)
{
GtkCenterBox *self = GTK_CENTER_BOX (object);
g_clear_pointer (&self->start_widget, gtk_widget_unparent);
g_clear_pointer (&self->center_widget, gtk_widget_unparent);
g_clear_pointer (&self->end_widget, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_center_box_parent_class)->dispose (object);
}
static void
gtk_center_box_class_init (GtkCenterBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gpointer iface;
object_class->set_property = gtk_center_box_set_property;
object_class->get_property = gtk_center_box_get_property;
object_class->dispose = gtk_center_box_dispose;
/**
* GtkCenterBox : baseline - position :
*
* The position of the baseline aligned widget if extra space is available .
*/
props[PROP_BASELINE_POSITION] =
g_param_spec_enum ("baseline-position" , NULL, NULL,
GTK_TYPE_BASELINE_POSITION,
GTK_BASELINE_POSITION_CENTER,
G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkCenterBox : start - widget :
*
* The widget that is placed at the start position .
*
* In vertical orientation , the start position is at the top .
* In horizontal orientation , the start position is at the leading
* edge with respect to the text direction .
*
* Since : 4 . 10
*/
props[PROP_START_WIDGET] =
g_param_spec_object ("start-widget" , NULL, NULL,
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkCenterBox : center - widget :
*
* The widget that is placed at the center position .
*
* Since : 4 . 10
*/
props[PROP_CENTER_WIDGET] =
g_param_spec_object ("center-widget" , NULL, NULL,
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkCenterBox : end - widget :
*
* The widget that is placed at the end position .
*
* In vertical orientation , the end position is at the bottom .
* In horizontal orientation , the end position is at the trailing
* edge with respect to the text direction .
*
* Since : 4 . 10
*/
props[PROP_END_WIDGET] =
g_param_spec_object ("end-widget" , NULL, NULL,
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkCenterBox : shrink - center - last :
*
* Whether to shrink the center widget after other children .
*
* By default , when there ' s no space to give all three children their
* natural widths , the start and end widgets start shrinking and the
* center child keeps natural width until they reach minimum width .
*
* If false , start and end widgets keep natural width and the
* center widget starts shrinking instead .
*
* Since : 4 . 12
*/
props[PROP_SHRINK_CENTER_LAST] =
g_param_spec_boolean ("shrink-center-last" , NULL, NULL,
TRUE ,
G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
/* GtkOrientable */
iface = g_type_default_interface_peek (GTK_TYPE_ORIENTABLE);
props[PROP_ORIENTATION] =
g_param_spec_override ("orientation" ,
g_object_interface_find_property (iface, "orientation" ));
g_object_class_install_properties (object_class, LAST_PROP, props);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CENTER_LAYOUT);
gtk_widget_class_set_css_name (widget_class, I_("box" ));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GENERIC);
}
static void
gtk_center_box_init (GtkCenterBox *self)
{
self->start_widget = NULL;
self->center_widget = NULL;
self->end_widget = NULL;
}
/**
* gtk_center_box_new :
*
* Creates a new ` GtkCenterBox ` .
*
* Returns : the new ` GtkCenterBox `
*/
GtkWidget *
gtk_center_box_new (void )
{
return GTK_WIDGET (g_object_new (GTK_TYPE_CENTER_BOX, NULL));
}
/**
* gtk_center_box_set_start_widget :
* @ self : a center box
* @ child : ( nullable ) : the new start widget
*
* Sets the start widget .
*
* To remove the existing start widget , pass ` NULL ` .
*/
void
gtk_center_box_set_start_widget (GtkCenterBox *self,
GtkWidget *child)
{
GtkLayoutManager *layout_manager;
g_return_if_fail (GTK_IS_CENTER_BOX (self));
g_return_if_fail (child == NULL || self->start_widget == child || gtk_widget_get_parent (child) == NULL);
if (self->start_widget == child)
return ;
if (self->start_widget)
gtk_widget_unparent (self->start_widget);
self->start_widget = child;
if (child)
gtk_widget_insert_after (child, GTK_WIDGET (self), NULL);
layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
gtk_center_layout_set_start_widget (GTK_CENTER_LAYOUT (layout_manager), child);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_START_WIDGET]);
}
/**
* gtk_center_box_set_center_widget :
* @ self : a center box
* @ child : ( nullable ) : the new center widget
*
* Sets the center widget .
*
* To remove the existing center widget , pass ` NULL ` .
*/
void
gtk_center_box_set_center_widget (GtkCenterBox *self,
GtkWidget *child)
{
GtkLayoutManager *layout_manager;
g_return_if_fail (GTK_IS_CENTER_BOX (self));
g_return_if_fail (child == NULL || self->center_widget == child || gtk_widget_get_parent (child) == NULL);
if (self->center_widget == child)
return ;
if (self->center_widget)
gtk_widget_unparent (self->center_widget);
self->center_widget = child;
if (child)
gtk_widget_insert_after (child, GTK_WIDGET (self), self->start_widget);
layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
gtk_center_layout_set_center_widget (GTK_CENTER_LAYOUT (layout_manager), child);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CENTER_WIDGET]);
}
/**
* gtk_center_box_set_end_widget :
* @ self : a center box
* @ child : ( nullable ) : the new end widget
*
* Sets the end widget .
*
* To remove the existing end widget , pass ` NULL ` .
*/
void
gtk_center_box_set_end_widget (GtkCenterBox *self,
GtkWidget *child)
{
GtkLayoutManager *layout_manager;
g_return_if_fail (GTK_IS_CENTER_BOX (self));
g_return_if_fail (child == NULL || self->end_widget == child || gtk_widget_get_parent (child) == NULL);
if (self->end_widget == child)
return ;
if (self->end_widget)
gtk_widget_unparent (self->end_widget);
self->end_widget = child;
if (child)
gtk_widget_insert_before (child, GTK_WIDGET (self), NULL);
layout_manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
gtk_center_layout_set_end_widget (GTK_CENTER_LAYOUT (layout_manager), child);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_END_WIDGET]);
}
/**
* gtk_center_box_get_start_widget :
* @ self : a center box
*
* Gets the start widget .
*
* Returns : ( transfer none ) ( nullable ) : the start widget
*/
GtkWidget *
gtk_center_box_get_start_widget (GtkCenterBox *self)
{
return self->start_widget;
}
/**
* gtk_center_box_get_center_widget :
* @ self : a center box
*
* Gets the center widget .
*
* Returns : ( transfer none ) ( nullable ) : the center widget
*/
GtkWidget *
gtk_center_box_get_center_widget (GtkCenterBox *self)
{
return self->center_widget;
}
/**
* gtk_center_box_get_end_widget :
* @ self : a center box
*
* Gets the end widget .
*
* Returns : ( transfer none ) ( nullable ) : the end widget
*/
GtkWidget *
gtk_center_box_get_end_widget (GtkCenterBox *self)
{
return self->end_widget;
}
/**
* gtk_center_box_set_baseline_position :
* @ self : a center box
* @ position : the baseline position
*
* Sets the baseline position of a center box .
*
* This affects only horizontal boxes with at least one baseline
* aligned child . If there is more vertical space available than
* requested , and the baseline is not allocated by the parent then
* @ position is used to allocate the baseline with respect to the
* extra space available .
*/
void
gtk_center_box_set_baseline_position (GtkCenterBox *self,
GtkBaselinePosition position)
{
GtkBaselinePosition current_position;
GtkLayoutManager *layout;
g_return_if_fail (GTK_IS_CENTER_BOX (self));
layout = gtk_widget_get_layout_manager (GTK_WIDGET (self));
current_position = gtk_center_layout_get_baseline_position (GTK_CENTER_LAYOUT (layout));
if (current_position != position)
{
gtk_center_layout_set_baseline_position (GTK_CENTER_LAYOUT (layout), position);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_BASELINE_POSITION]);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
}
/**
* gtk_center_box_get_baseline_position :
* @ self : a center box
*
* Gets the baseline position of the center box .
*
* See [ method @ Gtk . CenterBox . set_baseline_position ] .
*
* Returns : the baseline position
*/
GtkBaselinePosition
gtk_center_box_get_baseline_position (GtkCenterBox *self)
{
GtkLayoutManager *layout;
g_return_val_if_fail (GTK_IS_CENTER_BOX (self), GTK_BASELINE_POSITION_CENTER);
layout = gtk_widget_get_layout_manager (GTK_WIDGET (self));
return gtk_center_layout_get_baseline_position (GTK_CENTER_LAYOUT (layout));
}
/**
* gtk_center_box_set_shrink_center_last :
* @ self : a cener box
* @ shrink_center_last : whether to shrink the center widget after others
*
* Sets whether to shrink the center widget after other children .
*
* By default , when there ' s no space to give all three children their
* natural widths , the start and end widgets start shrinking and the
* center child keeps natural width until they reach minimum width .
*
* If @ shrink_center_last is false , start and end widgets keep natural
* width and the center widget starts shrinking instead .
*
* Since : 4 . 12
*/
void
gtk_center_box_set_shrink_center_last (GtkCenterBox *self,
gboolean shrink_center_last)
{
GtkLayoutManager *layout;
gboolean current_shrink_center_last;
g_return_if_fail (GTK_IS_CENTER_BOX (self));
shrink_center_last = !!shrink_center_last;
layout = gtk_widget_get_layout_manager (GTK_WIDGET (self));
current_shrink_center_last = gtk_center_layout_get_shrink_center_last (GTK_CENTER_LAYOUT (layout));
if (current_shrink_center_last != shrink_center_last)
{
gtk_center_layout_set_shrink_center_last (GTK_CENTER_LAYOUT (layout), shrink_center_last);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHRINK_CENTER_LAST]);
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
}
/**
* gtk_center_box_get_shrink_center_last :
* @ self : a center box
*
* Gets whether the center widget shrinks after other children .
*
* Returns : whether to shrink the center widget after others
*
* Since : 4 . 12
*/
gboolean
gtk_center_box_get_shrink_center_last (GtkCenterBox *self)
{
GtkLayoutManager *layout;
g_return_val_if_fail (GTK_IS_CENTER_BOX (self), FALSE );
layout = gtk_widget_get_layout_manager (GTK_WIDGET (self));
return gtk_center_layout_get_shrink_center_last (GTK_CENTER_LAYOUT (layout));
}
Messung V0.5 in Prozent C=97 H=91 G=93
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland
2026-07-09