mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 10:50:10 +00:00
themingengine: Implement 'dotted' and 'dashed'
This commit is contained in:
parent
34a62d779b
commit
1b9e15485e
@ -246,6 +246,102 @@ _gtk_rounded_box_path (const GtkRoundedBox *box,
|
||||
G_PI / 2, G_PI);
|
||||
}
|
||||
|
||||
double
|
||||
_gtk_rounded_box_guess_length (const GtkRoundedBox *box,
|
||||
GtkCssSide side)
|
||||
{
|
||||
double length;
|
||||
GtkCssCorner before, after;
|
||||
|
||||
before = side;
|
||||
after = (side + 1) % 4;
|
||||
|
||||
if (side & 1)
|
||||
length = box->box.height
|
||||
- box->corner[before].vertical
|
||||
- box->corner[after].vertical;
|
||||
else
|
||||
length = box->box.width
|
||||
- box->corner[before].horizontal
|
||||
- box->corner[after].horizontal;
|
||||
|
||||
length += G_PI * 0.125 * (box->corner[before].horizontal
|
||||
+ box->corner[before].vertical
|
||||
+ box->corner[after].horizontal
|
||||
+ box->corner[after].vertical);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_rounded_box_path_side (const GtkRoundedBox *box,
|
||||
cairo_t *cr,
|
||||
GtkCssSide side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case GTK_CSS_TOP:
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
|
||||
box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
|
||||
box->corner[GTK_CSS_TOP_LEFT].horizontal,
|
||||
box->corner[GTK_CSS_TOP_LEFT].vertical,
|
||||
5 * G_PI / 4, 3 * G_PI / 2);
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
|
||||
box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
|
||||
box->corner[GTK_CSS_TOP_RIGHT].horizontal,
|
||||
box->corner[GTK_CSS_TOP_RIGHT].vertical,
|
||||
- G_PI / 2, -G_PI / 4);
|
||||
break;
|
||||
case GTK_CSS_RIGHT:
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
|
||||
box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
|
||||
box->corner[GTK_CSS_TOP_RIGHT].horizontal,
|
||||
box->corner[GTK_CSS_TOP_RIGHT].vertical,
|
||||
- G_PI / 4, 0);
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
|
||||
box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
|
||||
box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
|
||||
box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
|
||||
0, G_PI / 4);
|
||||
break;
|
||||
case GTK_CSS_BOTTOM:
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
|
||||
box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
|
||||
box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
|
||||
box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
|
||||
G_PI / 4, G_PI / 2);
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
|
||||
box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
|
||||
box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
|
||||
box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
|
||||
G_PI / 2, 3 * G_PI / 4);
|
||||
break;
|
||||
case GTK_CSS_LEFT:
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
|
||||
box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
|
||||
box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
|
||||
box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
|
||||
3 * G_PI / 4, G_PI);
|
||||
_cairo_ellipsis (cr,
|
||||
box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
|
||||
box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
|
||||
box->corner[GTK_CSS_TOP_LEFT].horizontal,
|
||||
box->corner[GTK_CSS_TOP_LEFT].vertical,
|
||||
G_PI, 5 * G_PI / 4);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_rounded_box_path_top (const GtkRoundedBox *outer,
|
||||
const GtkRoundedBox *inner,
|
||||
|
@ -56,8 +56,14 @@ void _gtk_rounded_box_move (GtkRoundedBox
|
||||
double dx,
|
||||
double dy);
|
||||
|
||||
double _gtk_rounded_box_guess_length (const GtkRoundedBox *box,
|
||||
GtkCssSide side);
|
||||
|
||||
void _gtk_rounded_box_path (const GtkRoundedBox *box,
|
||||
cairo_t *cr);
|
||||
void _gtk_rounded_box_path_side (const GtkRoundedBox *box,
|
||||
cairo_t *cr,
|
||||
GtkCssSide side);
|
||||
void _gtk_rounded_box_path_top (const GtkRoundedBox *outer,
|
||||
const GtkRoundedBox *inner,
|
||||
cairo_t *cr);
|
||||
|
@ -1434,6 +1434,158 @@ render_frame_fill (cairo_t *cr,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_stroke_style (cairo_t *cr,
|
||||
double line_width,
|
||||
GtkBorderStyle style,
|
||||
double length)
|
||||
{
|
||||
double segments[2];
|
||||
double n;
|
||||
|
||||
cairo_set_line_width (cr, line_width);
|
||||
|
||||
if (style == GTK_BORDER_STYLE_DOTTED)
|
||||
{
|
||||
n = round (0.5 * length / line_width);
|
||||
|
||||
segments[0] = 0;
|
||||
segments[1] = n ? length / n : 2;
|
||||
cairo_set_dash (cr, segments, G_N_ELEMENTS (segments), 0);
|
||||
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
|
||||
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = length / line_width;
|
||||
/* Optimize the common case of an integer-sized rectangle
|
||||
* Again, we care about focus rectangles.
|
||||
*/
|
||||
if (n == nearbyint (n))
|
||||
{
|
||||
segments[0] = 1;
|
||||
segments[1] = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = round ((1. / 3) * n);
|
||||
|
||||
segments[0] = n ? (1. / 3) * length / n : 1;
|
||||
segments[1] = 2 * segments[1];
|
||||
}
|
||||
cairo_set_dash (cr, segments, G_N_ELEMENTS (segments), 0);
|
||||
|
||||
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
|
||||
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
get_border_side (GtkBorder *border,
|
||||
GtkCssSide side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case GTK_CSS_TOP:
|
||||
return border->top;
|
||||
case GTK_CSS_RIGHT:
|
||||
return border->right;
|
||||
case GTK_CSS_BOTTOM:
|
||||
return border->bottom;
|
||||
case GTK_CSS_LEFT:
|
||||
return border->left;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
render_frame_stroke (cairo_t *cr,
|
||||
GtkRoundedBox *border_box,
|
||||
GtkBorder *border,
|
||||
GdkRGBA colors[4],
|
||||
guint hidden_side,
|
||||
GtkBorderStyle stroke_style)
|
||||
{
|
||||
gboolean different_colors, different_borders;
|
||||
GtkRoundedBox stroke_box;
|
||||
guint i;
|
||||
|
||||
different_colors = !gdk_rgba_equal (&colors[0], &colors[1]) ||
|
||||
!gdk_rgba_equal (&colors[0], &colors[2]) ||
|
||||
!gdk_rgba_equal (&colors[0], &colors[3]);
|
||||
different_borders = border->top != border->right ||
|
||||
border->top != border->bottom ||
|
||||
border->top != border->left;
|
||||
|
||||
stroke_box = *border_box;
|
||||
_gtk_rounded_box_shrink (&stroke_box,
|
||||
border->top / 2.0,
|
||||
border->right / 2.0,
|
||||
border->bottom / 2.0,
|
||||
border->left / 2.0);
|
||||
|
||||
if (!different_colors && !different_borders && hidden_side == 0)
|
||||
{
|
||||
double length = 0;
|
||||
|
||||
/* FAST PATH:
|
||||
* Mostly expected to trigger for focus rectangles */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
length += _gtk_rounded_box_guess_length (&stroke_box, i);
|
||||
_gtk_rounded_box_path_side (&stroke_box, cr, i);
|
||||
}
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &colors[0]);
|
||||
set_stroke_style (cr, border->top, stroke_style, length);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkRoundedBox padding_box;
|
||||
|
||||
padding_box = *border_box;
|
||||
_gtk_rounded_box_path (&padding_box, cr);
|
||||
_gtk_rounded_box_shrink (&padding_box,
|
||||
border->top,
|
||||
border->right,
|
||||
border->bottom,
|
||||
border->left);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (hidden_side & (1 << i))
|
||||
continue;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
if (i == 0)
|
||||
_gtk_rounded_box_path_top (border_box, &padding_box, cr);
|
||||
else if (i == 1)
|
||||
_gtk_rounded_box_path_right (border_box, &padding_box, cr);
|
||||
else if (i == 2)
|
||||
_gtk_rounded_box_path_bottom (border_box, &padding_box, cr);
|
||||
else if (i == 3)
|
||||
_gtk_rounded_box_path_left (border_box, &padding_box, cr);
|
||||
cairo_clip (cr);
|
||||
|
||||
_gtk_rounded_box_path_side (&stroke_box, cr, i);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &colors[i]);
|
||||
set_stroke_style (cr,
|
||||
get_border_side (border, i),
|
||||
stroke_style,
|
||||
_gtk_rounded_box_guess_length (&stroke_box, i));
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
render_frame_internal (GtkThemingEngine *engine,
|
||||
cairo_t *cr,
|
||||
@ -1539,6 +1691,19 @@ render_frame_internal (GtkThemingEngine *engine,
|
||||
break;
|
||||
case GTK_BORDER_STYLE_DOTTED:
|
||||
case GTK_BORDER_STYLE_DASHED:
|
||||
{
|
||||
guint dont_draw = hidden_side;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
if (border_style[j] == border_style[i])
|
||||
hidden_side |= (1 << j);
|
||||
else
|
||||
dont_draw |= (1 << j);
|
||||
}
|
||||
|
||||
render_frame_stroke (cr, &border_box, &border, colors, dont_draw, border_style[i]);
|
||||
}
|
||||
break;
|
||||
case GTK_BORDER_STYLE_DOUBLE:
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user