mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-20 05:50:11 +00:00
popover: Make it possible to not have an arrow
This will make popovers move flexible for other uses, such as the Emoji completion popup.
This commit is contained in:
parent
a841ff0316
commit
ec413357c6
@ -6456,6 +6456,8 @@ gtk_popover_set_constrain_to
|
||||
gtk_popover_get_constrain_to
|
||||
gtk_popover_set_autohide
|
||||
gtk_popover_get_autohide
|
||||
gtk_popover_set_has_arrow
|
||||
gtk_popover_get_has_arrow
|
||||
gtk_popover_set_default_widget
|
||||
gtk_popover_get_default_widget
|
||||
<SUBSECTION Standard>
|
||||
|
206
gtk/gtkpopover.c
206
gtk/gtkpopover.c
@ -154,6 +154,7 @@ typedef struct {
|
||||
guint surface_transform_changed_cb;
|
||||
GtkPositionType position;
|
||||
gboolean autohide;
|
||||
gboolean has_arrow;
|
||||
|
||||
GtkWidget *contents_widget;
|
||||
GtkCssNode *arrow_node;
|
||||
@ -175,6 +176,7 @@ enum {
|
||||
PROP_POSITION,
|
||||
PROP_AUTOHIDE,
|
||||
PROP_DEFAULT_WIDGET,
|
||||
PROP_HAS_ARROW,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@ -512,6 +514,7 @@ gtk_popover_init (GtkPopover *popover)
|
||||
priv->position = GTK_POS_TOP;
|
||||
priv->final_position = GTK_POS_TOP;
|
||||
priv->autohide = TRUE;
|
||||
priv->has_arrow = TRUE;
|
||||
|
||||
controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect_swapped (controller, "focus-in", G_CALLBACK (gtk_popover_focus_in), popover);
|
||||
@ -964,25 +967,32 @@ gtk_popover_update_shape (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkWidget *widget = GTK_WIDGET (popover);
|
||||
cairo_surface_t *cairo_surface;
|
||||
cairo_region_t *region;
|
||||
cairo_t *cr;
|
||||
|
||||
cairo_surface =
|
||||
gdk_surface_create_similar_surface (priv->surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
gdk_surface_get_width (priv->surface),
|
||||
gdk_surface_get_height (priv->surface));
|
||||
if (priv->has_arrow)
|
||||
{
|
||||
|
||||
cr = cairo_create (cairo_surface);
|
||||
gtk_popover_fill_border_path (popover, cr);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_t *cairo_surface;
|
||||
cairo_region_t *region;
|
||||
cairo_t *cr;
|
||||
|
||||
region = gdk_cairo_region_create_from_surface (cairo_surface);
|
||||
cairo_surface_destroy (cairo_surface);
|
||||
cairo_surface =
|
||||
gdk_surface_create_similar_surface (priv->surface,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
gdk_surface_get_width (priv->surface),
|
||||
gdk_surface_get_height (priv->surface));
|
||||
|
||||
gtk_widget_input_shape_combine_region (widget, region);
|
||||
cairo_region_destroy (region);
|
||||
cr = cairo_create (cairo_surface);
|
||||
gtk_popover_fill_border_path (popover, cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
region = gdk_cairo_region_create_from_surface (cairo_surface);
|
||||
cairo_surface_destroy (cairo_surface);
|
||||
|
||||
gtk_widget_input_shape_combine_region (widget, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
else
|
||||
gtk_widget_input_shape_combine_region (widget, NULL);
|
||||
}
|
||||
|
||||
static gint
|
||||
@ -1005,13 +1015,14 @@ get_minimal_size (GtkPopover *popover,
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkPositionType pos;
|
||||
gint minimal_size;
|
||||
int tail_gap_width = priv->has_arrow ? TAIL_GAP_WIDTH : 0;
|
||||
|
||||
minimal_size = 2 * get_border_radius (GTK_WIDGET (popover));
|
||||
pos = priv->position;
|
||||
|
||||
if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
|
||||
(orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
|
||||
minimal_size += TAIL_GAP_WIDTH;
|
||||
minimal_size += tail_gap_width;
|
||||
|
||||
return minimal_size;
|
||||
}
|
||||
@ -1028,9 +1039,10 @@ gtk_popover_measure (GtkWidget *widget,
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
int minimal_size;
|
||||
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
||||
|
||||
if (for_size >= 0)
|
||||
for_size -= TAIL_HEIGHT;
|
||||
for_size -= tail_height;
|
||||
|
||||
gtk_widget_measure (priv->contents_widget,
|
||||
orientation, for_size,
|
||||
@ -1041,8 +1053,8 @@ gtk_popover_measure (GtkWidget *widget,
|
||||
*minimum = MAX (*minimum, minimal_size);
|
||||
*natural = MAX (*natural, minimal_size);
|
||||
|
||||
*minimum += TAIL_HEIGHT;
|
||||
*natural += TAIL_HEIGHT;
|
||||
*minimum += tail_height;
|
||||
*natural += tail_height;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1054,6 +1066,7 @@ gtk_popover_size_allocate (GtkWidget *widget,
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkAllocation child_alloc;
|
||||
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
||||
|
||||
if (priv->surface)
|
||||
gtk_popover_move_resize (popover);
|
||||
@ -1061,27 +1074,27 @@ gtk_popover_size_allocate (GtkWidget *widget,
|
||||
switch (priv->final_position)
|
||||
{
|
||||
case GTK_POS_TOP:
|
||||
child_alloc.x = TAIL_HEIGHT / 2;
|
||||
child_alloc.x = tail_height / 2;
|
||||
child_alloc.y = 0;
|
||||
break;
|
||||
case GTK_POS_BOTTOM:
|
||||
child_alloc.x = TAIL_HEIGHT / 2;
|
||||
child_alloc.y = TAIL_HEIGHT;
|
||||
child_alloc.x = tail_height / 2;
|
||||
child_alloc.y = tail_height;
|
||||
break;
|
||||
case GTK_POS_LEFT:
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = TAIL_HEIGHT / 2;
|
||||
child_alloc.y = tail_height / 2;
|
||||
break;
|
||||
case GTK_POS_RIGHT:
|
||||
child_alloc.x = TAIL_HEIGHT;
|
||||
child_alloc.y = TAIL_HEIGHT / 2;
|
||||
child_alloc.x = tail_height;
|
||||
child_alloc.y = tail_height / 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
child_alloc.width = width - TAIL_HEIGHT;
|
||||
child_alloc.height = height - TAIL_HEIGHT;
|
||||
child_alloc.width = width - tail_height;
|
||||
child_alloc.height = height - tail_height;
|
||||
|
||||
gtk_widget_size_allocate (priv->contents_widget, &child_alloc, baseline);
|
||||
|
||||
@ -1095,53 +1108,55 @@ gtk_popover_snapshot (GtkWidget *widget,
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkStyleContext *context;
|
||||
GtkBorder border;
|
||||
cairo_t *cr;
|
||||
|
||||
gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot,
|
||||
&GRAPHENE_RECT_INIT (
|
||||
0, 0,
|
||||
gtk_widget_get_width (widget),
|
||||
gtk_widget_get_height (widget)
|
||||
));
|
||||
|
||||
/* Clip to the arrow shape */
|
||||
cairo_save (cr);
|
||||
|
||||
gtk_popover_apply_tail_path (popover, cr);
|
||||
|
||||
cairo_clip (cr);
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_save_to_node (context, priv->arrow_node);
|
||||
gtk_style_context_get_border (context, &border);
|
||||
|
||||
/* Render the arrow background */
|
||||
gtk_render_background (context, cr,
|
||||
0, 0,
|
||||
gtk_widget_get_width (widget),
|
||||
gtk_widget_get_height (widget));
|
||||
|
||||
/* Render the border of the arrow tip */
|
||||
if (border.bottom > 0)
|
||||
if (priv->has_arrow)
|
||||
{
|
||||
GdkRGBA *border_color;
|
||||
GtkStyleContext *context;
|
||||
GtkBorder border;
|
||||
cairo_t *cr;
|
||||
|
||||
gtk_style_context_get (context, "border-color", &border_color, NULL);
|
||||
cr = gtk_snapshot_append_cairo (snapshot,
|
||||
&GRAPHENE_RECT_INIT (
|
||||
0, 0,
|
||||
gtk_widget_get_width (widget),
|
||||
gtk_widget_get_height (widget)
|
||||
));
|
||||
|
||||
/* Clip to the arrow shape */
|
||||
cairo_save (cr);
|
||||
gtk_popover_apply_tail_path (popover, cr);
|
||||
gdk_cairo_set_source_rgba (cr, border_color);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_set_line_width (cr, border.bottom + 1);
|
||||
cairo_stroke (cr);
|
||||
gdk_rgba_free (border_color);
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_save_to_node (context, priv->arrow_node);
|
||||
gtk_style_context_get_border (context, &border);
|
||||
|
||||
/* Render the arrow background */
|
||||
gtk_render_background (context, cr,
|
||||
0, 0,
|
||||
gtk_widget_get_width (widget),
|
||||
gtk_widget_get_height (widget));
|
||||
|
||||
/* Render the border of the arrow tip */
|
||||
if (border.bottom > 0)
|
||||
{
|
||||
GdkRGBA *border_color;
|
||||
|
||||
gtk_style_context_get (context, "border-color", &border_color, NULL);
|
||||
gtk_popover_apply_tail_path (popover, cr);
|
||||
gdk_cairo_set_source_rgba (cr, border_color);
|
||||
|
||||
cairo_set_line_width (cr, border.bottom + 1);
|
||||
cairo_stroke (cr);
|
||||
gdk_rgba_free (border_color);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1174,6 +1189,10 @@ gtk_popover_set_property (GObject *object,
|
||||
gtk_popover_set_default_widget (popover, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_HAS_ARROW:
|
||||
gtk_popover_set_has_arrow (popover, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -1211,6 +1230,10 @@ gtk_popover_get_property (GObject *object,
|
||||
g_value_set_object (value, priv->default_widget);
|
||||
break;
|
||||
|
||||
case PROP_HAS_ARROW:
|
||||
g_value_set_boolean (value, priv->has_arrow);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -1303,6 +1326,13 @@ gtk_popover_class_init (GtkPopoverClass *klass)
|
||||
GTK_TYPE_WIDGET,
|
||||
GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
properties[PROP_HAS_ARROW] =
|
||||
g_param_spec_boolean ("has-arrow",
|
||||
P_("Has Arrow"),
|
||||
P_("Whether to draw an arrow"),
|
||||
TRUE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
|
||||
|
||||
signals[CLOSED] =
|
||||
@ -1770,3 +1800,47 @@ gtk_popover_get_contents_widget (GtkPopover *popover)
|
||||
|
||||
return priv->contents_widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_popover_set_has_arrow:
|
||||
* @popover: a #GtkPopover
|
||||
* @has_arrow: %TRUE to draw an arrow
|
||||
*
|
||||
* Sets whether this popover should draw an arrow
|
||||
* pointing at the widget it is relative to.
|
||||
*/
|
||||
void
|
||||
gtk_popover_set_has_arrow (GtkPopover *popover,
|
||||
gboolean has_arrow)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
g_return_if_fail (GTK_IS_POPOVER (popover));
|
||||
|
||||
if (priv->has_arrow == has_arrow)
|
||||
return;
|
||||
|
||||
priv->has_arrow = has_arrow;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_HAS_ARROW]);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (popover));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_popover_get_has_arrow:
|
||||
* @popover: a #GtkPopover
|
||||
*
|
||||
* Gets whether this popover is showing an arrow
|
||||
* pointing at the widget that it is relative to.
|
||||
*
|
||||
* Returns: whether the popover has an arrow
|
||||
*/
|
||||
gboolean
|
||||
gtk_popover_get_has_arrow (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_POPOVER (popover), TRUE);
|
||||
|
||||
return priv->has_arrow;
|
||||
}
|
||||
|
@ -94,6 +94,12 @@ void gtk_popover_set_autohide (GtkPopover *popover,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_popover_get_autohide (GtkPopover *popover);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_popover_set_has_arrow (GtkPopover *popover,
|
||||
gboolean has_arrow);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_popover_get_has_arrow (GtkPopover *popover);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_popover_popup (GtkPopover *popover);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
Loading…
Reference in New Issue
Block a user