[gtk+/touch-selections] GtkBubbleWindow: rework how drawing is done
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/touch-selections] GtkBubbleWindow: rework how drawing is done
- Date: Tue, 5 Mar 2013 17:19:36 +0000 (UTC)
commit 7f36b9665a528c5539933e9ee665e68ff25c31e9
Author: Cosimo Cecchi <cosimoc gnome org>
Date: Tue Mar 5 11:13:54 2013 -0500
GtkBubbleWindow: rework how drawing is done
Use gtk_render_frame_gap(), refactoring the code fetching coordinates to
be usable by it. This allows for rounded corners in the window shape.
gtk/gtkbubblewindow.c | 271 +++++++++++++++++++++++++++++++++++++++----------
1 files changed, 217 insertions(+), 54 deletions(-)
---
diff --git a/gtk/gtkbubblewindow.c b/gtk/gtkbubblewindow.c
index 454c630..f2ef2ec 100644
--- a/gtk/gtkbubblewindow.c
+++ b/gtk/gtkbubblewindow.c
@@ -216,50 +216,166 @@ gtk_bubble_window_get_pointed_to_coords (GtkBubbleWindow *window,
}
static void
-gtk_bubble_window_apply_tail_path (GtkBubbleWindow *window,
- cairo_t *cr,
- GtkAllocation *allocation)
+gtk_bubble_window_get_gap_coords (GtkBubbleWindow *window,
+ gint *initial_x_out,
+ gint *initial_y_out,
+ gint *tip_x_out,
+ gint *tip_y_out,
+ gint *final_x_out,
+ gint *final_y_out,
+ GtkPositionType *gap_side_out)
{
GtkBubbleWindowPrivate *priv = window->priv;
gint base, tip, x, y;
+ gint initial_x, initial_y;
+ gint tip_x, tip_y;
+ gint final_x, final_y;
+ GtkPositionType gap_side;
+ GtkAllocation allocation;
gtk_bubble_window_get_pointed_to_coords (window, &x, &y, NULL);
+ gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
+
+ base = tip = 0;
+ gap_side = GTK_POS_LEFT;
if (priv->final_position == GTK_POS_BOTTOM ||
priv->final_position == GTK_POS_RIGHT)
{
base = TAIL_HEIGHT;
tip = 0;
+
+ gap_side = (priv->final_position == GTK_POS_BOTTOM) ? GTK_POS_TOP : GTK_POS_LEFT;
}
else if (priv->final_position == GTK_POS_TOP)
{
- base = allocation->height - TAIL_HEIGHT;
- tip = allocation->height;
+ base = allocation.height - TAIL_HEIGHT;
+ tip = allocation.height;
+ gap_side = GTK_POS_BOTTOM;
}
else if (priv->final_position == GTK_POS_LEFT)
{
- base = allocation->width - TAIL_HEIGHT;
- tip = allocation->width;
+ base = allocation.width - TAIL_HEIGHT;
+ tip = allocation.width;
+ gap_side = GTK_POS_RIGHT;
}
if (POS_IS_VERTICAL (priv->final_position))
{
- cairo_move_to (cr, CLAMP (x - priv->win_x - TAIL_GAP_WIDTH / 2,
- 0, allocation->width - TAIL_GAP_WIDTH), base);
- cairo_line_to (cr, CLAMP (x - priv->win_x, 0, allocation->width), tip);
- cairo_line_to (cr, CLAMP (x - priv->win_x + TAIL_GAP_WIDTH / 2,
- TAIL_GAP_WIDTH, allocation->width), base);
+ initial_x = CLAMP (x - priv->win_x - TAIL_GAP_WIDTH / 2,
+ 0, allocation.width - TAIL_GAP_WIDTH);
+ initial_y = base;
+
+ tip_x = CLAMP (x - priv->win_x, 0, allocation.width);
+ tip_y = tip;
+
+ final_x = CLAMP (x - priv->win_x + TAIL_GAP_WIDTH / 2,
+ TAIL_GAP_WIDTH, allocation.width);
+ final_y = base;
}
else
{
- cairo_move_to (cr, base,
- CLAMP (y - priv->win_y - TAIL_GAP_WIDTH / 2,
- 0, allocation->height - TAIL_GAP_WIDTH));
- cairo_line_to (cr, tip, CLAMP (y - priv->win_y, 0, allocation->height));
- cairo_line_to (cr, base,
- CLAMP (y - priv->win_y + TAIL_GAP_WIDTH / 2,
- TAIL_GAP_WIDTH, allocation->height));
+ initial_x = base;
+ initial_y = CLAMP (y - priv->win_y - TAIL_GAP_WIDTH / 2,
+ 0, allocation.height - TAIL_GAP_WIDTH);
+
+ tip_x = tip;
+ tip_y = CLAMP (y - priv->win_y, 0, allocation.height);
+
+ final_x = base;
+ final_y = CLAMP (y - priv->win_y + TAIL_GAP_WIDTH / 2,
+ TAIL_GAP_WIDTH, allocation.height);
+ }
+
+ if (initial_x_out)
+ *initial_x_out = initial_x;
+ if (initial_y_out)
+ *initial_y_out = initial_y;
+
+ if (tip_x_out)
+ *tip_x_out = tip_x;
+ if (tip_y_out)
+ *tip_y_out = tip_y;
+
+ if (final_x_out)
+ *final_x_out = final_x;
+ if (final_y_out)
+ *final_y_out = final_y;
+
+ if (gap_side_out)
+ *gap_side_out = gap_side;
+}
+
+static void
+gtk_bubble_window_get_rect_coords (GtkBubbleWindow *window,
+ gint *x1_out,
+ gint *y1_out,
+ gint *x2_out,
+ gint *y2_out)
+{
+ GtkBubbleWindowPrivate *priv = window->priv;
+ gint x1, x2, y1, y2;
+ GtkAllocation allocation;
+
+ x1 = y1 = x2 = y2 = 0;
+ gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
+
+ if (priv->final_position == GTK_POS_TOP)
+ {
+ x1 = 0;
+ y1 = 0;
+ x2 = allocation.width;
+ y2 = allocation.height - TAIL_HEIGHT;
+ }
+ else if (priv->final_position == GTK_POS_BOTTOM)
+ {
+ x1 = 0;
+ y1 = TAIL_HEIGHT;
+ x2 = allocation.width;
+ y2 = allocation.height;
+ }
+ else if (priv->final_position == GTK_POS_LEFT)
+ {
+ x1 = 0;
+ y1 = 0;
+ x2 = allocation.width - TAIL_HEIGHT;
+ y2 = allocation.height;
+ }
+ else if (priv->final_position == GTK_POS_RIGHT)
+ {
+ x1 = TAIL_HEIGHT;
+ y1 = 0;
+ x2 = allocation.width;
+ y2 = allocation.height;
}
+
+ if (x1_out)
+ *x1_out = x1;
+ if (y1_out)
+ *y1_out = y1;
+ if (x2_out)
+ *x2_out = x2;
+ if (y2_out)
+ *y2_out = y2;
+}
+
+static void
+gtk_bubble_window_apply_tail_path (GtkBubbleWindow *window,
+ cairo_t *cr)
+{
+ gint initial_x, initial_y;
+ gint tip_x, tip_y;
+ gint final_x, final_y;
+
+ gtk_bubble_window_get_gap_coords (window,
+ &initial_x, &initial_y,
+ &tip_x, &tip_y,
+ &final_x, &final_y,
+ NULL);
+
+ cairo_move_to (cr, initial_x, initial_y);
+ cairo_line_to (cr, tip_x, tip_y);
+ cairo_line_to (cr, final_x, final_y);
}
static void
@@ -268,39 +384,41 @@ gtk_bubble_window_apply_border_path (GtkBubbleWindow *window,
{
GtkBubbleWindowPrivate *priv;
GtkAllocation allocation;
+ gint x1, y1, x2, y2;
priv = window->priv;
gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
- gtk_bubble_window_apply_tail_path (window, cr, &allocation);
+ gtk_bubble_window_apply_tail_path (window, cr);
+ gtk_bubble_window_get_rect_coords (window, &x1, &y1, &x2, &y2);
if (priv->final_position == GTK_POS_TOP)
{
- cairo_line_to (cr, allocation.width, allocation.height - TAIL_HEIGHT);
- cairo_line_to (cr, allocation.width, 0);
- cairo_line_to (cr, 0, 0);
- cairo_line_to (cr, 0, allocation.height - TAIL_HEIGHT);
+ cairo_line_to (cr, x2, y2);
+ cairo_line_to (cr, x2, y1);
+ cairo_line_to (cr, x1, y1);
+ cairo_line_to (cr, x1, y2);
}
else if (priv->final_position == GTK_POS_BOTTOM)
{
- cairo_line_to (cr, allocation.width, TAIL_HEIGHT);
- cairo_line_to (cr, allocation.width, allocation.height);
- cairo_line_to (cr, 0, allocation.height);
- cairo_line_to (cr, 0, TAIL_HEIGHT);
+ cairo_line_to (cr, x2, y1);
+ cairo_line_to (cr, x2, y2);
+ cairo_line_to (cr, x1, y2);
+ cairo_line_to (cr, x1, y1);
}
else if (priv->final_position == GTK_POS_LEFT)
{
- cairo_line_to (cr, allocation.width - TAIL_HEIGHT, allocation.height);
- cairo_line_to (cr, 0, allocation.height);
- cairo_line_to (cr, 0, 0);
- cairo_line_to (cr, allocation.width - TAIL_HEIGHT, 0);
+ cairo_line_to (cr, x2, y2);
+ cairo_line_to (cr, x1, y2);
+ cairo_line_to (cr, x1, y1);
+ cairo_line_to (cr, x2, y1);
}
else if (priv->final_position == GTK_POS_RIGHT)
{
- cairo_line_to (cr, TAIL_HEIGHT, 0);
- cairo_line_to (cr, allocation.width, 0);
- cairo_line_to (cr, allocation.width, allocation.height);
- cairo_line_to (cr, TAIL_HEIGHT, allocation.height);
+ cairo_line_to (cr, x1, y1);
+ cairo_line_to (cr, x2, y1);
+ cairo_line_to (cr, x2, y2);
+ cairo_line_to (cr, x1, y2);
}
cairo_close_path (cr);
@@ -401,15 +519,18 @@ gtk_bubble_window_draw (GtkWidget *widget,
GtkStyleContext *context;
GtkAllocation allocation;
GtkWidget *child;
- GdkRGBA *border;
+ GtkBorder border;
+ GdkRGBA border_color;
+ gint rect_x1, rect_x2, rect_y1, rect_y2;
+ gint initial_x, initial_y, final_x, final_y;
+ gint gap_start, gap_end;
+ GtkPositionType gap_side;
+ GtkStateFlags state;
- cairo_save (cr);
context = gtk_widget_get_style_context (widget);
+ state = gtk_widget_get_state_flags (widget);
gtk_widget_get_allocation (widget, &allocation);
- gtk_render_background (context, cr, 0, 0,
- allocation.width, allocation.height);
-
if (gtk_widget_is_composited (widget))
{
cairo_save (cr);
@@ -417,31 +538,73 @@ gtk_bubble_window_draw (GtkWidget *widget,
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_paint (cr);
cairo_restore (cr);
+ }
+
+ gtk_bubble_window_get_rect_coords (GTK_BUBBLE_WINDOW (widget),
+ &rect_x1, &rect_y1,
+ &rect_x2, &rect_y2);
+
+ /* Render the rect background */
+ gtk_render_background (context, cr,
+ rect_x1, rect_y1,
+ rect_x2 - rect_x1, rect_y2 - rect_y1);
+
+ gtk_bubble_window_get_gap_coords (GTK_BUBBLE_WINDOW (widget),
+ &initial_x, &initial_y,
+ NULL, NULL,
+ &final_x, &final_y,
+ &gap_side);
- gtk_bubble_window_apply_border_path (GTK_BUBBLE_WINDOW (widget), cr);
- cairo_clip (cr);
+ if (POS_IS_VERTICAL (gap_side))
+ {
+ gap_start = initial_x;
+ gap_end = final_x;
+ }
+ else
+ {
+ gap_start = initial_y;
+ gap_end = final_y;
}
- gtk_render_background (context, cr, 0, 0,
+ /* Now render the frame, without the gap for the arrow tip */
+ gtk_render_frame_gap (context, cr,
+ rect_x1, rect_y1,
+ rect_x2 - rect_x1, rect_y2 - rect_y1,
+ gap_side,
+ gap_start, gap_end);
+
+ /* Clip to the arrow shape */
+ cairo_save (cr);
+
+ gtk_bubble_window_apply_tail_path (GTK_BUBBLE_WINDOW (widget), cr);
+ cairo_clip (cr);
+
+ /* Render the arrow background */
+ gtk_render_background (context, cr,
+ 0, 0,
allocation.width, allocation.height);
- gtk_style_context_get (context, gtk_widget_get_state_flags (widget),
- GTK_STYLE_PROPERTY_BORDER_COLOR, &border,
- NULL);
+ /* Render the border of the arrow tip */
+ gtk_style_context_get_border (context, state, &border);
- gtk_bubble_window_apply_border_path (GTK_BUBBLE_WINDOW (widget), cr);
- gdk_cairo_set_source_rgba (cr, border);
- cairo_stroke (cr);
+ if (border.bottom > 0)
+ {
+ gtk_style_context_get_border_color (context, state, &border_color);
+ gtk_bubble_window_apply_tail_path (GTK_BUBBLE_WINDOW (widget), cr);
+ gdk_cairo_set_source_rgba (cr, &border_color);
+
+ cairo_set_line_width (cr, border.bottom);
+ cairo_stroke (cr);
+ }
+
+ /* We're done */
+ cairo_restore (cr);
child = gtk_bin_get_child (GTK_BIN (widget));
if (child)
gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
- cairo_restore (cr);
-
- gdk_rgba_free (border);
-
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]