diff options
author | Matthias Clasen <mclasen@redhat.com> | 2014-02-08 22:14:51 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-02-08 22:14:51 -0500 |
commit | 14ba1280ce1424497be2fb797807a362d14956b3 (patch) | |
tree | bbf880070c11891e56e82b4404ceccee6cd349f8 /gtk/gtkpopover.c | |
parent | 9822d510a68e01db4468db7629d4e7fb40e7abcc (diff) | |
download | gtk+-14ba1280ce1424497be2fb797807a362d14956b3.tar.gz |
Improve popover positioning
Improve the algorithm to determing popover placement:
If it fits in the preferred direction or its opposite,
do that, otherwise use the direction that causes the least
of the popover to be cut off.
Diffstat (limited to 'gtk/gtkpopover.c')
-rw-r--r-- | gtk/gtkpopover.c | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 6c18d4536a..0f445b0e5c 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -639,14 +639,30 @@ _gtk_popover_update_child_visible (GtkPopover *popover) gtk_widget_set_child_visible (GTK_WIDGET (popover), TRUE); } +static GtkPositionType +opposite_position (GtkPositionType pos) +{ + switch (pos) + { + default: + case GTK_POS_LEFT: return GTK_POS_RIGHT; + case GTK_POS_RIGHT: return GTK_POS_LEFT; + case GTK_POS_TOP: return GTK_POS_BOTTOM; + case GTK_POS_BOTTOM: return GTK_POS_TOP; + } +} + static void gtk_popover_update_position (GtkPopover *popover) { GtkAllocation window_alloc; GdkRectangle rect; GtkPopoverPrivate *priv; - GtkPositionType pos; GtkRequisition req; + GtkPositionType pos; + gint overshoot[4]; + gint i; + gint best; priv = popover->priv; @@ -660,17 +676,33 @@ gtk_popover_update_position (GtkPopover *popover) gtk_popover_get_pointed_to_coords (popover, &rect); pos = get_effective_position (popover, priv->preferred_position); - /* Check whether there's enough room on the - * preferred side, move to the opposite one if not. - */ - if (pos == GTK_POS_TOP && rect.y < req.height) - priv->final_position = GTK_POS_BOTTOM; - else if (pos == GTK_POS_BOTTOM && rect.y > window_alloc.height - req.height) - priv->final_position = GTK_POS_TOP; - else if (pos == GTK_POS_LEFT && rect.x < req.width) - priv->final_position = get_effective_position (popover, GTK_POS_RIGHT); - else if (pos == GTK_POS_RIGHT && rect.x > window_alloc.width - req.width) - priv->final_position = get_effective_position (popover, GTK_POS_LEFT); + overshoot[GTK_POS_TOP] = req.height - rect.y; + overshoot[GTK_POS_BOTTOM] = rect.y + rect.height + req.height - window_alloc.height; + overshoot[GTK_POS_LEFT] = req.width - rect.x; + overshoot[GTK_POS_RIGHT] = rect.x + rect.width + req.width - window_alloc.width; + + if (overshoot[pos] <= 0) + { + priv->final_position = pos; + } + else if (overshoot[opposite_position (pos)] <= 0) + { + priv->final_position = opposite_position (pos); + } + else + { + best = G_MAXINT; + pos = 0; + for (i = 0; i < 4; i++) + { + if (overshoot[i] < best) + { + pos = i; + best = overshoot[i]; + } + } + priv->final_position = pos; + } _gtk_window_set_popover_position (priv->window, GTK_WIDGET (popover), priv->final_position, &rect); |