Commit b38a096a authored by Matthias Clasen's avatar Matthias Clasen

GtkHeaderBar: optionally add a close button

Add a boolean property that controls whether a window close button
will be shown in the header bar or not. Doing this in the toolkit
will ensure consistency of the visual apperance.

https://bugzilla.gnome.org/show_bug.cgi?id=702971
parent f960cb19
......@@ -7667,6 +7667,8 @@ gtk_header_bar_set_custom_title
gtk_header_bar_get_custom_title
gtk_header_bar_pack_start
gtk_header_bar_pack_end
gtk_header_bar_set_show_close_button
gtk_header_bar_get_show_close_button
<SUBSECTION Standard>
GTK_TYPE_HEADER_BAR
......
......@@ -56,6 +56,8 @@ struct _GtkHeaderBarPrivate
GtkWidget *label_box;
GtkWidget *label_sizing_box;
GtkWidget *custom_title;
GtkWidget *close_button;
GtkWidget *separator;
gint spacing;
gint hpadding;
gint vpadding;
......@@ -77,7 +79,8 @@ enum {
PROP_CUSTOM_TITLE,
PROP_SPACING,
PROP_HPADDING,
PROP_VPADDING
PROP_VPADDING,
PROP_SHOW_CLOSE_BUTTON
};
enum {
......@@ -202,6 +205,57 @@ _gtk_header_bar_create_title_box (const char *title,
return label_box;
}
static void
close_button_clicked (GtkButton *button, gpointer data)
{
GtkWidget *toplevel;
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
gtk_window_close (GTK_WINDOW (toplevel));
}
static void
add_close_button (GtkHeaderBar *bar)
{
GtkHeaderBarPrivate *priv;
GtkWidget *button;
GIcon *icon;
GtkWidget *image;
GtkWidget *separator;
priv = gtk_header_bar_get_instance_private (bar);
button = gtk_button_new ();
icon = g_themed_icon_new ("window-close-symbolic");
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
g_object_unref (icon);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked",
G_CALLBACK (close_button_clicked), NULL);
gtk_widget_show_all (button);
gtk_widget_set_parent (button, GTK_WIDGET (bar));
separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
gtk_widget_show (separator);
gtk_widget_set_parent (separator, GTK_WIDGET (bar));
priv->separator = separator;
priv->close_button = button;
}
static void
remove_close_button (GtkHeaderBar *bar)
{
GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
gtk_widget_unparent (priv->separator);
gtk_widget_unparent (priv->close_button);
priv->separator = NULL;
priv->close_button = NULL;
}
static void
construct_label_box (GtkHeaderBar *bar)
{
......@@ -230,6 +284,8 @@ gtk_header_bar_init (GtkHeaderBar *bar)
priv->title = NULL;
priv->subtitle = NULL;
priv->custom_title = NULL;
priv->close_button = NULL;
priv->separator = NULL;
priv->children = NULL;
priv->spacing = DEFAULT_SPACING;
priv->hpadding = DEFAULT_HPADDING;
......@@ -328,6 +384,15 @@ gtk_header_bar_get_size (GtkWidget *widget,
nvis_children += 1;
}
if (priv->close_button != NULL)
{
if (add_child_size (priv->close_button, orientation, &minimum, &natural))
nvis_children += 1;
if (add_child_size (priv->separator, orientation, &minimum, &natural))
nvis_children += 1;
}
if (nvis_children > 0 && orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum += nvis_children * priv->spacing;
......@@ -408,6 +473,19 @@ gtk_header_bar_compute_size_for_orientation (GtkWidget *widget,
required_natural += child_natural;
}
if (priv->close_button != NULL)
{
gtk_widget_get_preferred_width (priv->close_button,
&child_size, &child_natural);
required_size += child_size;
required_natural += child_natural;
gtk_widget_get_preferred_width (priv->separator,
&child_size, &child_natural);
required_size += child_size;
required_natural += child_natural;
}
if (nvis_children > 0)
{
required_size += nvis_children * priv->spacing;
......@@ -526,6 +604,19 @@ gtk_header_bar_compute_size_for_opposing_orientation (GtkWidget *widget,
computed_natural = MAX (computed_natural, child_natural);
}
if (priv->close_button != NULL)
{
gtk_widget_get_preferred_height (priv->close_button,
&child_minimum, &child_natural);
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
gtk_widget_get_preferred_height (priv->separator,
&child_minimum, &child_natural);
computed_minimum = MAX (computed_minimum, child_minimum);
computed_natural = MAX (computed_natural, child_natural);
}
get_css_padding_and_border (widget, &css_borders);
computed_minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
......@@ -583,6 +674,9 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
gint nvis_children;
gint title_minimum_size;
gint title_natural_size;
gint close_button_width;
gint separator_width;
gint close_width;
gint side[2];
GList *l;
gint i;
......@@ -636,6 +730,23 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
}
width -= title_natural_size;
close_button_width = separator_width = close_width = 0;
if (priv->close_button != NULL)
{
gint min, nat;
gtk_widget_get_preferred_width_for_height (priv->close_button,
height,
&min, &nat);
close_button_width = nat;
gtk_widget_get_preferred_width_for_height (priv->separator,
height,
&min, &nat);
separator_width = nat;
close_width = close_button_width + separator_width + 2 * priv->spacing;
}
width -= close_width;
width = gtk_distribute_natural_allocation (MAX (0, width), nvis_children, sizes);
side[0] = side[1] = 0;
......@@ -646,7 +757,7 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
if (packing == GTK_PACK_START)
x = allocation->x + priv->hpadding + css_borders.left;
else
x = allocation->x + allocation->width - priv->hpadding - css_borders.right;
x = allocation->x + allocation->width - close_width - priv->hpadding - css_borders.right;
if (packing == GTK_PACK_START)
{
......@@ -700,6 +811,8 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
}
}
side[GTK_PACK_END] += close_width;
child_allocation.y = allocation->y + priv->vpadding + css_borders.top;
child_allocation.height = height;
......@@ -727,6 +840,23 @@ gtk_header_bar_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (priv->custom_title, &child_allocation);
else
gtk_widget_size_allocate (priv->label_box, &child_allocation);
if (priv->close_button)
{
if (direction == GTK_TEXT_DIR_RTL)
child_allocation.x = allocation->x + priv->hpadding + css_borders.left;
else
child_allocation.x = allocation->x + allocation->width - priv->hpadding - css_borders.right - close_button_width;
child_allocation.width = close_button_width;
gtk_widget_size_allocate (priv->close_button, &child_allocation);
if (direction == GTK_TEXT_DIR_RTL)
child_allocation.x = allocation->x + priv->hpadding + css_borders.left + close_button_width + priv->spacing;
else
child_allocation.x = allocation->x + allocation->width - priv->hpadding - css_borders.right - close_button_width - priv->spacing - separator_width;
child_allocation.width = separator_width;
gtk_widget_size_allocate (priv->separator, &child_allocation);
}
}
/**
......@@ -976,6 +1106,10 @@ gtk_header_bar_get_property (GObject *object,
g_value_set_int (value, priv->vpadding);
break;
case PROP_SHOW_CLOSE_BUTTON:
g_value_set_boolean (value, gtk_header_bar_get_show_close_button (bar));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -1020,6 +1154,10 @@ gtk_header_bar_set_property (GObject *object,
gtk_widget_queue_resize (GTK_WIDGET (bar));
break;
case PROP_SHOW_CLOSE_BUTTON:
gtk_header_bar_set_show_close_button (bar, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -1120,6 +1258,12 @@ gtk_header_bar_forall (GtkContainer *container,
if (include_internals && priv->label_box != NULL)
(* callback) (priv->label_box, callback_data);
if (include_internals && priv->close_button != NULL)
(* callback) (priv->close_button, callback_data);
if (include_internals && priv->separator != NULL)
(* callback) (priv->separator, callback_data);
children = priv->children;
while (children)
{
......@@ -1362,6 +1506,14 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
DEFAULT_VPADDING,
GTK_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SHOW_CLOSE_BUTTON,
g_param_spec_boolean ("show-close-button",
P_("Show Close button"),
P_("Whether to show a window close button"),
FALSE,
GTK_PARAM_READWRITE));
gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_FILLER);
}
......@@ -1433,3 +1585,61 @@ gtk_header_bar_new (void)
{
return GTK_WIDGET (g_object_new (GTK_TYPE_HEADER_BAR, NULL));
}
/**
* gtk_header_bar_get_show_close_button:
* @bar: a #GtkHeaderBar
*
* Returns whether this header bar shows a window close
* button.
*
* Returns: %TRUE if a window close button is shown
*
* Since: 3.10
*/
gboolean
gtk_header_bar_get_show_close_button (GtkHeaderBar *bar)
{
GtkHeaderBarPrivate *priv;
g_return_val_if_fail (GTK_IS_HEADER_BAR (bar), FALSE);
priv = gtk_header_bar_get_instance_private (bar);
return priv->close_button != NULL;
}
/**
* gtk_header_bar_set_show_close_button:
* @bar: a #GtkHeaderBar
* @setting: %TRUE to show a window close button
*
* Sets whether this header bar shows a window close
* button.
*
* Since: 3.10
*/
void
gtk_header_bar_set_show_close_button (GtkHeaderBar *bar,
gboolean setting)
{
GtkHeaderBarPrivate *priv;
g_return_if_fail (GTK_IS_HEADER_BAR (bar));
priv = gtk_header_bar_get_instance_private (bar);
setting = setting != FALSE;
if ((priv->close_button != NULL) == setting)
return;
if (setting)
add_close_button (bar);
else
remove_close_button (bar);
gtk_widget_queue_resize (GTK_WIDGET (bar));
g_object_notify (G_OBJECT (bar), "show-close-button");
}
......@@ -83,6 +83,13 @@ GDK_AVAILABLE_IN_3_10
void gtk_header_bar_pack_end (GtkHeaderBar *bar,
GtkWidget *child);
GDK_AVAILABLE_IN_3_10
gboolean gtk_header_bar_get_show_close_button (GtkHeaderBar *bar);
GDK_AVAILABLE_IN_3_10
void gtk_header_bar_set_show_close_button (GtkHeaderBar *bar,
gboolean setting);
G_END_DECLS
#endif /* __GTK_HEADER_BAR_H__ */
......@@ -17,7 +17,9 @@ main (int argc, char *argv[])
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (header), TRUE);
gtk_style_context_add_class (gtk_widget_get_style_context (header), "titlebar");
title = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (title), "<b>Welcome to Facebook - Log in, sign up or learn more</b>");
gtk_label_set_ellipsize (GTK_LABEL (title), PANGO_ELLIPSIZE_END);
......@@ -32,18 +34,6 @@ main (int argc, char *argv[])
gtk_container_add (GTK_CONTAINER (button), image);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), gtk_separator_new (GTK_ORIENTATION_VERTICAL));
button = gtk_button_new ();
icon = g_themed_icon_new ("window-close-symbolic");
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
g_object_unref (icon);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_close), window);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
button = gtk_button_new ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment