diff options
Diffstat (limited to 'gtk/gtkpopover.c')
-rw-r--r-- | gtk/gtkpopover.c | 145 |
1 files changed, 117 insertions, 28 deletions
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 6d10169073..b00cdd3827 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -83,14 +83,15 @@ * to differentiate from plain popovers. * * When styling a popover directly, the popover node should usually - * not have any background. + * not have any background. The visible part of the popover can have a shadow. + * To specify it in CSS, set the box-shadow of the contents node. * * Note that, in order to accomplish appropriate arrow visuals, #GtkPopover uses * custom drawing for the arrow node. This makes it possible for the arrow to * change its shape dynamically, but it also limits the possibilities of styling * it using CSS. In particular, the arrow gets drawn over the content node's - * border so they look like one shape, which means that the border-width of - * the content node and the arrow node should be the same. The arrow also does + * shadow border so they look like one shape, which means that the border width + * of the content node and the arrow node should be the same. The arrow also does * not support any border shape other than solid, no border-radius, only one * border width (border-bottom-width is used) and no box-shadow. */ @@ -126,6 +127,7 @@ #include "gtkstylecontextprivate.h" #include "gtkroundedboxprivate.h" #include "gsk/gskroundedrectprivate.h" +#include "gtkcssshadowvalueprivate.h" #define MNEMONICS_DELAY 300 /* ms */ @@ -436,6 +438,8 @@ create_popup_layout (GtkPopover *popover) GdkAnchorHints anchor_hints; GdkPopupLayout *layout; GtkWidget *parent; + GtkCssStyle *style; + GtkBorder shadow_width; parent = gtk_widget_get_parent (GTK_WIDGET (popover)); gtk_widget_get_surface_allocation (parent, &rect); @@ -447,6 +451,9 @@ create_popup_layout (GtkPopover *popover) rect.height = priv->pointing_to.height; } + style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget))); + gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width); + switch (priv->position) { case GTK_POS_LEFT: @@ -553,6 +560,11 @@ create_popup_layout (GtkPopover *popover) layout = gdk_popup_layout_new (&rect, parent_anchor, surface_anchor); gdk_popup_layout_set_anchor_hints (layout, anchor_hints); + gdk_popup_layout_set_shadow_width (layout, + shadow_width.left, + shadow_width.right, + shadow_width.top, + shadow_width.bottom); if (priv->x_offset || priv->y_offset) gdk_popup_layout_set_offset (layout, priv->x_offset, priv->y_offset); @@ -570,9 +582,7 @@ present_popup (GtkPopover *popover) layout = create_popup_layout (popover); gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &nat); - if (gdk_popup_present (GDK_POPUP (priv->surface), - nat.width, nat.height, - layout)) + if (gdk_popup_present (GDK_POPUP (priv->surface), nat.width, nat.height, layout)) { update_popover_layout (popover, layout, nat.width, nat.height); return TRUE; @@ -871,6 +881,15 @@ node_style_changed_cb (GtkCssNode *node, } static void +contents_css_changed (GtkGizmo *contents, + GtkCssStyleChange *change) +{ + if (change == NULL || + gtk_css_style_change_changes_property (change, GTK_CSS_PROPERTY_BOX_SHADOW)) + gtk_widget_queue_resize (gtk_widget_get_parent (GTK_WIDGET (contents))); +} + +static void gtk_popover_init (GtkPopover *popover) { GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); @@ -905,6 +924,7 @@ gtk_popover_init (GtkPopover *popover) priv->contents_widget = gtk_gizmo_new ("contents", NULL, NULL, NULL, NULL, (GtkGizmoFocusFunc)gtk_widget_focus_child, (GtkGizmoGrabFocusFunc)gtk_widget_grab_focus_child); + gtk_gizmo_set_css_changed_func (GTK_GIZMO (priv->contents_widget), contents_css_changed); gtk_widget_set_layout_manager (priv->contents_widget, gtk_bin_layout_new ()); gtk_widget_set_parent (priv->contents_widget, GTK_WIDGET (popover)); gtk_widget_set_overflow (priv->contents_widget, GTK_OVERFLOW_HIDDEN); @@ -1107,6 +1127,7 @@ gtk_popover_get_gap_coords (GtkPopover *popover, int popover_width, popover_height; GtkCssStyle *style; GtkWidget *parent; + GtkBorder shadow_width; popover_width = gtk_widget_get_allocated_width (widget); popover_height = gtk_widget_get_allocated_height (widget); @@ -1132,20 +1153,27 @@ gtk_popover_get_gap_coords (GtkPopover *popover, border_right = _gtk_css_number_value_get (style->border->border_right_width, 100); border_bottom = _gtk_css_number_value_get (style->border->border_bottom_width, 100); - if (pos == GTK_POS_BOTTOM || pos == GTK_POS_RIGHT) + gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width); + + if (pos == GTK_POS_BOTTOM) + { + tip = shadow_width.top; + base = tip + TAIL_HEIGHT + border_top; + } + else if (pos == GTK_POS_RIGHT) { - tip = 0; - base = TAIL_HEIGHT + border_top; + tip = shadow_width.left; + base = tip + TAIL_HEIGHT + border_top; } else if (pos == GTK_POS_TOP) { - base = popover_height - border_bottom - TAIL_HEIGHT; - tip = popover_height; + tip = popover_height - shadow_width.bottom; + base = tip - border_bottom - TAIL_HEIGHT; } else if (pos == GTK_POS_LEFT) { - base = popover_width - border_right - TAIL_HEIGHT; - tip = popover_width; + tip = popover_width - shadow_width.right; + base = tip - border_right - TAIL_HEIGHT; } else g_assert_not_reached (); @@ -1286,7 +1314,31 @@ gtk_popover_update_shape (GtkPopover *popover) cairo_region_destroy (region); } else - gdk_surface_set_input_region (priv->surface, NULL); + { + GtkCssNode *content_css_node; + GtkCssStyle *style; + GtkBorder shadow_width; + cairo_rectangle_int_t input_rect; + cairo_region_t *region; + + content_css_node = + gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)); + style = gtk_css_node_get_style (content_css_node); + gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width); + + input_rect.x = shadow_width.left; + input_rect.y = shadow_width.top; + input_rect.width = + gdk_surface_get_width (priv->surface) - + (shadow_width.left + shadow_width.right); + input_rect.height = + gdk_surface_get_height (priv->surface) - + (shadow_width.top + shadow_width.bottom); + + region = cairo_region_create_rectangle (&input_rect); + gdk_surface_set_input_region (priv->surface, region); + cairo_region_destroy (region); + } } static int @@ -1306,14 +1358,22 @@ get_minimal_size (GtkPopover *popover, GtkPositionType pos; int minimal_size; int tail_gap_width = priv->has_arrow ? TAIL_GAP_WIDTH : 0; + int min_width, min_height; - minimal_size = 2 * get_border_radius (GTK_WIDGET (popover)); + minimal_size = 2 * get_border_radius (GTK_WIDGET (priv->contents_widget)); 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; + gtk_widget_get_size_request (GTK_WIDGET (popover), &min_width, &min_height); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + minimal_size = MAX (minimal_size, min_width); + else + minimal_size = MAX (minimal_size, min_height); + return minimal_size; } @@ -1330,10 +1390,15 @@ gtk_popover_measure (GtkWidget *widget, GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); int minimal_size; int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0; + GtkCssStyle *style; + GtkBorder shadow_width; if (for_size >= 0) for_size -= tail_height; + style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget))); + gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width); + gtk_widget_measure (priv->contents_widget, orientation, for_size, minimum, natural, @@ -1343,8 +1408,22 @@ gtk_popover_measure (GtkWidget *widget, *minimum = MAX (*minimum, minimal_size); *natural = MAX (*natural, minimal_size); - *minimum += tail_height; - *natural += tail_height; + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + *minimum += shadow_width.left + shadow_width.right; + *natural += shadow_width.left + shadow_width.right; + } + else + { + *minimum += shadow_width.top + shadow_width.bottom; + *natural += shadow_width.top + shadow_width.bottom; + } + + if (POS_IS_VERTICAL (priv->position) == (orientation == GTK_ORIENTATION_VERTICAL)) + { + *minimum += tail_height; + *natural += tail_height; + } } static void @@ -1357,32 +1436,42 @@ gtk_popover_size_allocate (GtkWidget *widget, GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); GtkAllocation child_alloc; int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0; + GtkCssStyle *style; + GtkBorder shadow_width; + + style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget))); + gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width); switch (priv->final_position) { case GTK_POS_TOP: - child_alloc.x = tail_height / 2; - child_alloc.y = 0; + child_alloc.x = shadow_width.left; + child_alloc.y = shadow_width.top; + child_alloc.width = width - (shadow_width.left + shadow_width.right); + child_alloc.height = height - (shadow_width.top + shadow_width.bottom + tail_height); break; case GTK_POS_BOTTOM: - child_alloc.x = tail_height / 2; - child_alloc.y = tail_height; + child_alloc.x = shadow_width.left; + child_alloc.y = shadow_width.top + tail_height; + child_alloc.width = width - (shadow_width.left + shadow_width.right); + child_alloc.height = height - (shadow_width.top + shadow_width.bottom + tail_height); break; case GTK_POS_LEFT: - child_alloc.x = 0; - child_alloc.y = tail_height / 2; + child_alloc.x = shadow_width.left; + child_alloc.y = shadow_width.top; + child_alloc.width = width - (shadow_width.left + shadow_width.right + tail_height); + child_alloc.height = height - (shadow_width.top + shadow_width.bottom); break; case GTK_POS_RIGHT: - child_alloc.x = tail_height; - child_alloc.y = tail_height / 2; + child_alloc.x = shadow_width.left + tail_height; + child_alloc.y = shadow_width.top; + child_alloc.width = width - (shadow_width.left + shadow_width.right + tail_height); + child_alloc.height = height - (shadow_width.top + shadow_width.bottom); break; default: break; } - child_alloc.width = width - tail_height; - child_alloc.height = height - tail_height; - gtk_widget_size_allocate (priv->contents_widget, &child_alloc, baseline); if (priv->surface) |