You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1419 lines
46 KiB
1419 lines
46 KiB
12 years ago
|
/* The TdeGtk Theming Engine for Gtk+.
|
||
|
* Copyright (C) 2011 Canonical Ltd
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free
|
||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||
|
* MA 02110-1301, USA.
|
||
|
*
|
||
|
* Authored by Andrea Cimitan <andrea.cimitan@canonical.com>
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <cairo.h>
|
||
|
#include <gtk/gtk.h>
|
||
|
|
||
|
#include "gtkroundedboxprivate.h"
|
||
|
#include "raico-blur.h"
|
||
|
#include "tdegtk-cairo-support.h"
|
||
|
#include "tdegtk-support.h"
|
||
|
#include "tdegtk-types.h"
|
||
|
|
||
|
/* apply default color */
|
||
|
static void
|
||
|
apply_default_color (GdkRGBA *colors[4],
|
||
|
GdkRGBA *default_color)
|
||
|
{
|
||
|
gint i;
|
||
|
|
||
|
for (i = 0; i < 4; i++)
|
||
|
if (tdegtk_gdk_rgba_is_default (colors[i]))
|
||
|
*colors[i] = *default_color;
|
||
|
}
|
||
|
|
||
|
/* set the border sides to 0 using hidden_side */
|
||
|
static void
|
||
|
hide_border_sides (GtkBorder *border,
|
||
|
guint hidden_side)
|
||
|
{
|
||
|
if (hidden_side & SIDE_TOP)
|
||
|
border->top = 0;
|
||
|
if (hidden_side & SIDE_RIGHT)
|
||
|
border->right = 0;
|
||
|
if (hidden_side & SIDE_BOTTOM)
|
||
|
border->bottom = 0;
|
||
|
if (hidden_side & SIDE_LEFT)
|
||
|
border->left = 0;
|
||
|
}
|
||
|
|
||
|
/* shrink coordinate using GtkBorder */
|
||
|
static void
|
||
|
shrink_with_border (GtkBorder *border,
|
||
|
gdouble *x,
|
||
|
gdouble *y,
|
||
|
gdouble *width,
|
||
|
gdouble *height)
|
||
|
{
|
||
|
*x += border->left;
|
||
|
*y += border->top;
|
||
|
*width -= border->left + border->right;
|
||
|
*height -= border->top + border->bottom;
|
||
|
}
|
||
|
|
||
|
/* draw the background */
|
||
|
static void
|
||
|
draw_background (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GdkRGBA bg_color;
|
||
|
GtkBorder border;
|
||
|
GtkRoundedBox border_box;
|
||
|
GtkStateFlags state;
|
||
|
cairo_pattern_t *bg_pat;
|
||
|
gdouble progress;
|
||
|
gboolean running;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"background-image", &bg_pat,
|
||
|
NULL);
|
||
|
gtk_theming_engine_get_background_color (engine, state, &bg_color);
|
||
|
gtk_theming_engine_get_border (engine, state, &border);
|
||
|
|
||
|
hide_border_sides (&border, hidden_side);
|
||
|
|
||
|
running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
|
||
|
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_translate (cr, x, y);
|
||
|
|
||
|
/* clear cr if we can draw directly on the background */
|
||
|
if (gtk_theming_engine_has_class (engine, "background"))
|
||
|
{
|
||
|
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
|
||
|
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||
|
cairo_paint (cr);
|
||
|
}
|
||
|
|
||
|
if (running)
|
||
|
{
|
||
|
GdkRGBA other_bg;
|
||
|
GtkStateFlags other_state;
|
||
|
cairo_pattern_t *new_pat = NULL;
|
||
|
cairo_pattern_t *other_pat;
|
||
|
|
||
|
if (state & GTK_STATE_FLAG_PRELIGHT)
|
||
|
{
|
||
|
other_state = state & ~(GTK_STATE_FLAG_PRELIGHT);
|
||
|
|
||
|
/* useful math function to use for a pulse loop animation could be
|
||
|
* progress = 1 - MAX (1 - fabs ((progress - 0.5)*2), 0);
|
||
|
* but we need to handle the not-running case (once animation finished),
|
||
|
* otherwise the last frame will be the PRELIGHT at full opacity. */
|
||
|
progress = 1 - progress;
|
||
|
}
|
||
|
else
|
||
|
other_state = state | GTK_STATE_FLAG_PRELIGHT;
|
||
|
|
||
|
gtk_theming_engine_get (engine, other_state,
|
||
|
"background-image", &other_pat,
|
||
|
NULL);
|
||
|
gtk_theming_engine_get_background_color (engine, other_state, &other_bg);
|
||
|
|
||
|
if (bg_pat && other_pat)
|
||
|
{
|
||
|
/* two patterns */
|
||
|
cairo_pattern_type_t type, other_type;
|
||
|
gint n0, n1;
|
||
|
|
||
|
cairo_pattern_get_color_stop_count (bg_pat, &n0);
|
||
|
cairo_pattern_get_color_stop_count (other_pat, &n1);
|
||
|
type = cairo_pattern_get_type (bg_pat);
|
||
|
other_type = cairo_pattern_get_type (other_pat);
|
||
|
|
||
|
if (type == other_type && n0 == n1)
|
||
|
{
|
||
|
/* two similar patterns, blend them point by point */
|
||
|
gdouble offset0, red0, green0, blue0, alpha0;
|
||
|
gdouble offset1, red1, green1, blue1, alpha1;
|
||
|
gdouble x00, x01, y00, y01, x10, x11, y10, y11;
|
||
|
gdouble r00, r01, r10, r11;
|
||
|
gint i;
|
||
|
|
||
|
if (type == CAIRO_PATTERN_TYPE_LINEAR)
|
||
|
{
|
||
|
cairo_pattern_get_linear_points (bg_pat, &x00, &y00, &x01, &y01);
|
||
|
cairo_pattern_get_linear_points (other_pat, &x10, &y10, &x11, &y11);
|
||
|
|
||
|
new_pat = cairo_pattern_create_linear (x00 + (x10 - x00) * progress,
|
||
|
y00 + (y10 - y00) * progress,
|
||
|
x01 + (x11 - x01) * progress,
|
||
|
y01 + (y11 - y01) * progress);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cairo_pattern_get_radial_circles (bg_pat, &x00, &y00, &r00, &x01, &y01, &r01);
|
||
|
cairo_pattern_get_radial_circles (other_pat, &x10, &y10, &r10, &x11, &y11, &r11);
|
||
|
|
||
|
new_pat = cairo_pattern_create_radial (x00 + (x10 - x00) * progress,
|
||
|
y00 + (y10 - y00) * progress,
|
||
|
r00 + (r10 - r00) * progress,
|
||
|
x01 + (x11 - x01) * progress,
|
||
|
y01 + (y11 - y01) * progress,
|
||
|
r01 + (r11 - r01) * progress);
|
||
|
}
|
||
|
|
||
|
cairo_pattern_set_filter (new_pat, CAIRO_FILTER_FAST);
|
||
|
i = 0;
|
||
|
|
||
|
while (i < n0 && i < n1)
|
||
|
{
|
||
|
cairo_pattern_get_color_stop_rgba (bg_pat, i,
|
||
|
&offset0,
|
||
|
&red0, &green0, &blue0,
|
||
|
&alpha0);
|
||
|
cairo_pattern_get_color_stop_rgba (other_pat, i,
|
||
|
&offset1,
|
||
|
&red1, &green1, &blue1,
|
||
|
&alpha1);
|
||
|
cairo_pattern_add_color_stop_rgba (new_pat,
|
||
|
offset0 + ((offset1 - offset0) * progress),
|
||
|
red0 + ((red1 - red0) * progress),
|
||
|
green0 + ((green1 - green0) * progress),
|
||
|
blue0 + ((blue1 - blue0) * progress),
|
||
|
alpha0 + ((alpha1 - alpha0) * progress));
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* two different patterns, paint them with alpha */
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_reset_clip (cr);
|
||
|
cairo_rectangle (cr, 0, 0, width, height);
|
||
|
cairo_clip (cr);
|
||
|
|
||
|
cairo_push_group (cr);
|
||
|
|
||
|
cairo_scale (cr, width, height);
|
||
|
|
||
|
cairo_set_source (cr, other_pat);
|
||
|
cairo_paint_with_alpha (cr, progress);
|
||
|
|
||
|
cairo_set_source (cr, bg_pat);
|
||
|
cairo_paint_with_alpha (cr, 1.0 - progress);
|
||
|
|
||
|
new_pat = cairo_pop_group (cr);
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
}
|
||
|
}
|
||
|
else if (bg_pat || other_pat)
|
||
|
{
|
||
|
/* only one pattern, blend it with a color */
|
||
|
const GdkRGBA *c;
|
||
|
cairo_pattern_t *p;
|
||
|
gdouble x0, y0, x1, y1, r0, r1;
|
||
|
gint n, i;
|
||
|
|
||
|
if (bg_pat)
|
||
|
{
|
||
|
p = bg_pat;
|
||
|
c = &other_bg;
|
||
|
progress = 1 - progress;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p = other_pat;
|
||
|
c = &bg_color;
|
||
|
}
|
||
|
|
||
|
if (cairo_pattern_get_type (p) == CAIRO_PATTERN_TYPE_LINEAR)
|
||
|
{
|
||
|
cairo_pattern_get_linear_points (p, &x0, &y0, &x1, &y1);
|
||
|
new_pat = cairo_pattern_create_linear (x0, y0, x1, y1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cairo_pattern_get_radial_circles (p, &x0, &y0, &r0, &x1, &y1, &r1);
|
||
|
new_pat = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1);
|
||
|
}
|
||
|
|
||
|
cairo_pattern_get_color_stop_count (p, &n);
|
||
|
|
||
|
for (i = 0; i < n; i++)
|
||
|
{
|
||
|
gdouble red1, green1, blue1, alpha1;
|
||
|
gdouble offset;
|
||
|
|
||
|
cairo_pattern_get_color_stop_rgba (p, i,
|
||
|
&offset,
|
||
|
&red1, &green1, &blue1,
|
||
|
&alpha1);
|
||
|
cairo_pattern_add_color_stop_rgba (new_pat, offset,
|
||
|
c->red + ((red1 - c->red) * progress),
|
||
|
c->green + ((green1 - c->green) * progress),
|
||
|
c->blue + ((blue1 - c->blue) * progress),
|
||
|
c->alpha + ((alpha1 - c->alpha) * progress));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* just colors, create a new pattern blending them */
|
||
|
new_pat = cairo_pattern_create_rgba (CLAMP (bg_color.red + ((other_bg.red - bg_color.red) * progress), 0, 1),
|
||
|
CLAMP (bg_color.green + ((other_bg.green - bg_color.green) * progress), 0, 1),
|
||
|
CLAMP (bg_color.blue + ((other_bg.blue - bg_color.blue) * progress), 0, 1),
|
||
|
CLAMP (bg_color.alpha + ((other_bg.alpha - bg_color.alpha) * progress), 0, 1));
|
||
|
}
|
||
|
|
||
|
if (new_pat)
|
||
|
{
|
||
|
/* replace pattern to use */
|
||
|
cairo_pattern_destroy (bg_pat);
|
||
|
bg_pat = new_pat;
|
||
|
}
|
||
|
|
||
|
if (other_pat)
|
||
|
cairo_pattern_destroy (other_pat);
|
||
|
}
|
||
|
|
||
|
/* create the path to fill */
|
||
|
_gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
|
||
|
_gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
|
||
|
_gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
|
||
|
if (bg_pat)
|
||
|
{
|
||
|
/* pattern */
|
||
|
cairo_scale (cr, width, height);
|
||
|
cairo_set_source (cr, bg_pat);
|
||
|
cairo_scale (cr, 1.0 / width, 1.0 / height);
|
||
|
}
|
||
|
else
|
||
|
/* one color */
|
||
|
gdk_cairo_set_source_rgba (cr, &bg_color);
|
||
|
|
||
|
cairo_fill (cr);
|
||
|
|
||
|
if (bg_pat)
|
||
|
cairo_pattern_destroy (bg_pat);
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
}
|
||
|
|
||
|
/* draw the inner glow */
|
||
|
static void
|
||
|
draw_glow (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GdkRGBA *glow_color;
|
||
|
GtkBorder border;
|
||
|
GtkRoundedBox border_box, padding_box;
|
||
|
GtkStateFlags state;
|
||
|
cairo_t *cr_surface;
|
||
|
cairo_surface_t *surface;
|
||
|
gint bradius = 0;
|
||
|
raico_blur_t* blur = NULL;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"-tdegtk-glow-radius", &bradius,
|
||
|
"-tdegtk-glow-color", &glow_color,
|
||
|
NULL);
|
||
|
|
||
|
if (bradius <= 0)
|
||
|
goto end_draw_glow;
|
||
|
|
||
|
gtk_theming_engine_get_border (engine, state, &border);
|
||
|
|
||
|
hide_border_sides (&border, hidden_side);
|
||
|
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_translate (cr, x, y);
|
||
|
|
||
|
/* create the path to clip */
|
||
|
_gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
|
||
|
_gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
|
||
|
_gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
|
||
|
cairo_clip (cr);
|
||
|
|
||
|
/* create the surface to blur */
|
||
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||
|
width + bradius * 2,
|
||
|
height + bradius * 2);
|
||
|
cr_surface = cairo_create (surface);
|
||
|
|
||
|
/* create the path on the surface to blur */
|
||
|
_gtk_rounded_box_move (&border_box, bradius, bradius);
|
||
|
padding_box = border_box;
|
||
|
_gtk_rounded_box_shrink (&padding_box, border.top * 2, border.right * 2, border.bottom * 2, border.left * 2);
|
||
|
|
||
|
cairo_set_fill_rule (cr_surface, CAIRO_FILL_RULE_EVEN_ODD);
|
||
|
|
||
|
gdk_cairo_set_source_rgba (cr_surface, glow_color);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr_surface);
|
||
|
_gtk_rounded_box_path (&padding_box, cr_surface);
|
||
|
cairo_fill (cr_surface);
|
||
|
|
||
|
/* create and apply raico blur */
|
||
|
blur = raico_blur_create ();
|
||
|
raico_blur_set_radius (blur, bradius);
|
||
|
raico_blur_apply (blur, surface);
|
||
|
|
||
|
/* paint the blurred surface to cr */
|
||
|
cairo_set_source_surface (cr, surface, - bradius, - bradius);
|
||
|
cairo_paint (cr);
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
|
||
|
cairo_surface_destroy (surface);
|
||
|
cairo_destroy (cr_surface);
|
||
|
|
||
|
end_draw_glow:
|
||
|
gdk_rgba_free (glow_color);
|
||
|
}
|
||
|
|
||
|
/* draw a repeated texture */
|
||
|
static void
|
||
|
draw_texture (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GtkStateFlags state;
|
||
|
GValue value = { 0, };
|
||
|
cairo_pattern_t *texture = NULL;
|
||
|
cairo_surface_t *surface = NULL;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get_property (engine, "-tdegtk-background-texture", state, &value);
|
||
|
|
||
|
if (!G_VALUE_HOLDS_BOXED (&value))
|
||
|
return;
|
||
|
|
||
|
texture = g_value_dup_boxed (&value);
|
||
|
g_value_unset (&value);
|
||
|
|
||
|
if (texture != NULL)
|
||
|
cairo_pattern_get_surface (texture, &surface);
|
||
|
|
||
|
if (surface != NULL)
|
||
|
{
|
||
|
GtkBorder border;
|
||
|
GtkRoundedBox border_box;
|
||
|
cairo_pattern_t *pat;
|
||
|
|
||
|
gtk_theming_engine_get_border (engine, state, &border);
|
||
|
|
||
|
hide_border_sides (&border, hidden_side);
|
||
|
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_translate (cr, x, y);
|
||
|
|
||
|
/* create the path to fill */
|
||
|
_gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
|
||
|
_gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
|
||
|
_gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
|
||
|
pat = cairo_pattern_create_for_surface (surface);
|
||
|
cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
|
||
|
cairo_set_source (cr, pat);
|
||
|
|
||
|
cairo_fill (cr);
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
|
||
|
cairo_pattern_destroy (pat);
|
||
|
}
|
||
|
|
||
|
if (texture != NULL)
|
||
|
cairo_pattern_destroy (texture);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tdegtk_cairo_draw_background (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GtkBorder *outer_border;
|
||
|
GtkStateFlags state;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"-tdegtk-outer-stroke-width", &outer_border,
|
||
|
NULL);
|
||
|
|
||
|
hide_border_sides (outer_border, hidden_side);
|
||
|
|
||
|
shrink_with_border (outer_border, &x, &y, &width, &height);
|
||
|
|
||
|
/* first layer, background */
|
||
|
draw_background (engine, cr,
|
||
|
x, y,
|
||
|
width, height,
|
||
|
hidden_side, junction);
|
||
|
|
||
|
/* second layer, glow */
|
||
|
draw_glow (engine, cr,
|
||
|
x, y,
|
||
|
width, height,
|
||
|
hidden_side, junction);
|
||
|
|
||
|
/* third layer, texture */
|
||
|
draw_texture (engine, cr,
|
||
|
x, y,
|
||
|
width, height,
|
||
|
hidden_side, junction);
|
||
|
|
||
|
gtk_border_free (outer_border);
|
||
|
}
|
||
|
|
||
|
/* shade a color */
|
||
|
static void
|
||
|
color_shade (const GdkRGBA *color,
|
||
|
gdouble factor,
|
||
|
GdkRGBA *color_return)
|
||
|
{
|
||
|
GtkSymbolicColor *literal, *shade;
|
||
|
|
||
|
literal = gtk_symbolic_color_new_literal (color);
|
||
|
shade = gtk_symbolic_color_new_shade (literal, factor);
|
||
|
gtk_symbolic_color_unref (literal);
|
||
|
|
||
|
gtk_symbolic_color_resolve (shade, NULL, color_return);
|
||
|
gtk_symbolic_color_unref (shade);
|
||
|
}
|
||
|
|
||
|
/* draw the border */
|
||
|
static void
|
||
|
draw_border (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GdkRGBA *colors[4];
|
||
|
GtkBorder border;
|
||
|
GtkBorderStyle border_style;
|
||
|
GtkRoundedBox border_box, padding_box;
|
||
|
GtkStateFlags state;
|
||
|
cairo_pattern_t *border_pat;
|
||
|
gboolean running;
|
||
|
gdouble progress;
|
||
|
static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
|
||
|
guint i, j;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"border-style", &border_style,
|
||
|
"border-top-color", &colors[0],
|
||
|
"border-right-color", &colors[1],
|
||
|
"border-bottom-color", &colors[2],
|
||
|
"border-left-color", &colors[3],
|
||
|
"-tdegtk-border-gradient", &border_pat,
|
||
|
NULL);
|
||
|
gtk_theming_engine_get_border (engine, state, &border);
|
||
|
|
||
|
hide_border_sides (&border, hidden_side);
|
||
|
|
||
|
running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
|
||
|
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_translate (cr, x, y);
|
||
|
|
||
|
if (running)
|
||
|
{
|
||
|
GtkStateFlags other_state;
|
||
|
cairo_pattern_t *new_pat = NULL;
|
||
|
cairo_pattern_t *other_pat;
|
||
|
|
||
|
if (state & GTK_STATE_FLAG_PRELIGHT)
|
||
|
{
|
||
|
other_state = state & ~(GTK_STATE_FLAG_PRELIGHT);
|
||
|
progress = 1 - progress;
|
||
|
}
|
||
|
else
|
||
|
other_state = state | GTK_STATE_FLAG_PRELIGHT;
|
||
|
|
||
|
gtk_theming_engine_get (engine, other_state,
|
||
|
"-tdegtk-border-gradient", &other_pat,
|
||
|
NULL);
|
||
|
|
||
|
if (border_pat && other_pat)
|
||
|
{
|
||
|
/* two patterns */
|
||
|
cairo_pattern_type_t type, other_type;
|
||
|
gint n0, n1;
|
||
|
|
||
|
cairo_pattern_get_color_stop_count (border_pat, &n0);
|
||
|
cairo_pattern_get_color_stop_count (other_pat, &n1);
|
||
|
type = cairo_pattern_get_type (border_pat);
|
||
|
other_type = cairo_pattern_get_type (other_pat);
|
||
|
|
||
|
if (type == other_type && n0 == n1)
|
||
|
{
|
||
|
/* two similar patterns, blend them point by point */
|
||
|
gdouble offset0, red0, green0, blue0, alpha0;
|
||
|
gdouble offset1, red1, green1, blue1, alpha1;
|
||
|
gdouble x00, x01, y00, y01, x10, x11, y10, y11;
|
||
|
gdouble r00, r01, r10, r11;
|
||
|
gint i;
|
||
|
|
||
|
if (type == CAIRO_PATTERN_TYPE_LINEAR)
|
||
|
{
|
||
|
cairo_pattern_get_linear_points (border_pat, &x00, &y00, &x01, &y01);
|
||
|
cairo_pattern_get_linear_points (other_pat, &x10, &y10, &x11, &y11);
|
||
|
|
||
|
new_pat = cairo_pattern_create_linear (x00 + (x10 - x00) * progress,
|
||
|
y00 + (y10 - y00) * progress,
|
||
|
x01 + (x11 - x01) * progress,
|
||
|
y01 + (y11 - y01) * progress);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cairo_pattern_get_radial_circles (border_pat, &x00, &y00, &r00, &x01, &y01, &r01);
|
||
|
cairo_pattern_get_radial_circles (other_pat, &x10, &y10, &r10, &x11, &y11, &r11);
|
||
|
|
||
|
new_pat = cairo_pattern_create_radial (x00 + (x10 - x00) * progress,
|
||
|
y00 + (y10 - y00) * progress,
|
||
|
r00 + (r10 - r00) * progress,
|
||
|
x01 + (x11 - x01) * progress,
|
||
|
y01 + (y11 - y01) * progress,
|
||
|
r01 + (r11 - r01) * progress);
|
||
|
}
|
||
|
|
||
|
cairo_pattern_set_filter (new_pat, CAIRO_FILTER_FAST);
|
||
|
i = 0;
|
||
|
|
||
|
while (i < n0 && i < n1)
|
||
|
{
|
||
|
cairo_pattern_get_color_stop_rgba (border_pat, i,
|
||
|
&offset0,
|
||
|
&red0, &green0, &blue0,
|
||
|
&alpha0);
|
||
|
cairo_pattern_get_color_stop_rgba (other_pat, i,
|
||
|
&offset1,
|
||
|
&red1, &green1, &blue1,
|
||
|
&alpha1);
|
||
|
cairo_pattern_add_color_stop_rgba (new_pat,
|
||
|
offset0 + ((offset1 - offset0) * progress),
|
||
|
red0 + ((red1 - red0) * progress),
|
||
|
green0 + ((green1 - green0) * progress),
|
||
|
blue0 + ((blue1 - blue0) * progress),
|
||
|
alpha0 + ((alpha1 - alpha0) * progress));
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* two different patterns, paint them with alpha */
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_reset_clip (cr);
|
||
|
cairo_rectangle (cr, 0, 0, width, height);
|
||
|
cairo_clip (cr);
|
||
|
|
||
|
cairo_push_group (cr);
|
||
|
|
||
|
cairo_scale (cr, width, height);
|
||
|
|
||
|
cairo_set_source (cr, other_pat);
|
||
|
cairo_paint_with_alpha (cr, progress);
|
||
|
|
||
|
cairo_set_source (cr, border_pat);
|
||
|
cairo_paint_with_alpha (cr, 1.0 - progress);
|
||
|
|
||
|
new_pat = cairo_pop_group (cr);
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
}
|
||
|
}
|
||
|
else if (border_pat || other_pat)
|
||
|
{
|
||
|
/* one pattern, blend it with a color */
|
||
|
const GdkRGBA *c;
|
||
|
cairo_pattern_t *p;
|
||
|
gdouble x0, y0, x1, y1, r0, r1;
|
||
|
gint n, i;
|
||
|
|
||
|
if (border_pat)
|
||
|
{
|
||
|
GdkRGBA other_color;
|
||
|
|
||
|
gtk_theming_engine_get_border_color (engine, other_state, &other_color);
|
||
|
|
||
|
p = border_pat;
|
||
|
c = &other_color;
|
||
|
progress = 1 - progress;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GdkRGBA border_color;
|
||
|
|
||
|
gtk_theming_engine_get_border_color (engine, state, &border_color);
|
||
|
|
||
|
p = other_pat;
|
||
|
c = &border_color;
|
||
|
}
|
||
|
|
||
|
if (cairo_pattern_get_type (p) == CAIRO_PATTERN_TYPE_LINEAR)
|
||
|
{
|
||
|
cairo_pattern_get_linear_points (p, &x0, &y0, &x1, &y1);
|
||
|
new_pat = cairo_pattern_create_linear (x0, y0, x1, y1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cairo_pattern_get_radial_circles (p, &x0, &y0, &r0, &x1, &y1, &r1);
|
||
|
new_pat = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1);
|
||
|
}
|
||
|
|
||
|
cairo_pattern_get_color_stop_count (p, &n);
|
||
|
|
||
|
for (i = 0; i < n; i++)
|
||
|
{
|
||
|
gdouble red1, green1, blue1, alpha1;
|
||
|
gdouble offset;
|
||
|
|
||
|
cairo_pattern_get_color_stop_rgba (p, i,
|
||
|
&offset,
|
||
|
&red1, &green1, &blue1,
|
||
|
&alpha1);
|
||
|
cairo_pattern_add_color_stop_rgba (new_pat, offset,
|
||
|
c->red + ((red1 - c->red) * progress),
|
||
|
c->green + ((green1 - c->green) * progress),
|
||
|
c->blue + ((blue1 - c->blue) * progress),
|
||
|
c->alpha + ((alpha1 - c->alpha) * progress));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* just colors, create new colors blending them */
|
||
|
GdkRGBA *other_colors[4];
|
||
|
|
||
|
gtk_theming_engine_get (engine, other_state,
|
||
|
"border-top-color", &other_colors[0],
|
||
|
"border-right-color", &other_colors[1],
|
||
|
"border-bottom-color", &other_colors[2],
|
||
|
"border-left-color", &other_colors[3],
|
||
|
NULL);
|
||
|
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
colors[i]->red = CLAMP (colors[i]->red + ((other_colors[i]->red - colors[i]->red) * progress), 0, 1);
|
||
|
colors[i]->green = CLAMP (colors[i]->green + ((other_colors[i]->green - colors[i]->green) * progress), 0, 1);
|
||
|
colors[i]->blue = CLAMP (colors[i]->blue + ((other_colors[i]->blue - colors[i]->blue) * progress), 0, 1);
|
||
|
colors[i]->alpha = CLAMP (colors[i]->alpha + ((other_colors[i]->alpha - colors[i]->alpha) * progress), 0, 1);
|
||
|
gdk_rgba_free (other_colors[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (new_pat)
|
||
|
{
|
||
|
/* replace pattern to use */
|
||
|
cairo_pattern_destroy (border_pat);
|
||
|
border_pat = new_pat;
|
||
|
}
|
||
|
|
||
|
if (other_pat)
|
||
|
cairo_pattern_destroy (other_pat);
|
||
|
}
|
||
|
|
||
|
switch (border_style)
|
||
|
{
|
||
|
default:
|
||
|
g_assert_not_reached ();
|
||
|
case GTK_BORDER_STYLE_NONE:
|
||
|
case GTK_BORDER_STYLE_SOLID:
|
||
|
break;
|
||
|
case GTK_BORDER_STYLE_INSET:
|
||
|
color_shade (colors[1], 1.8, colors[1]);
|
||
|
color_shade (colors[2], 1.8, colors[2]);
|
||
|
break;
|
||
|
case GTK_BORDER_STYLE_OUTSET:
|
||
|
color_shade (colors[0], 1.8, colors[0]);
|
||
|
color_shade (colors[3], 1.8, colors[3]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* create the path to fill */
|
||
|
_gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
|
||
|
_gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
|
||
|
padding_box = border_box;
|
||
|
_gtk_rounded_box_shrink (&padding_box, border.top, border.right, border.bottom, border.left);
|
||
|
|
||
|
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
|
||
|
|
||
|
switch (border_style)
|
||
|
{
|
||
|
default:
|
||
|
g_assert_not_reached ();
|
||
|
case GTK_BORDER_STYLE_NONE:
|
||
|
break;
|
||
|
case GTK_BORDER_STYLE_SOLID:
|
||
|
case GTK_BORDER_STYLE_INSET:
|
||
|
case GTK_BORDER_STYLE_OUTSET:
|
||
|
|
||
|
if (border_pat)
|
||
|
{
|
||
|
/* pattern */
|
||
|
cairo_scale (cr, width, height);
|
||
|
cairo_set_source (cr, border_pat);
|
||
|
cairo_scale (cr, 1.0 / width, 1.0 / height);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
_gtk_rounded_box_path (&padding_box, cr);
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
else if (gdk_rgba_equal (colors[0], colors[1]) &&
|
||
|
gdk_rgba_equal (colors[0], colors[2]) &&
|
||
|
gdk_rgba_equal (colors[0], colors[3]))
|
||
|
{
|
||
|
/* one color */
|
||
|
gdk_cairo_set_source_rgba (cr, colors[0]);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
_gtk_rounded_box_path (&padding_box, cr);
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
/* different colors */
|
||
|
if (hidden_side & current_side[i])
|
||
|
continue;
|
||
|
|
||
|
for (j = 0; j < 4; j++)
|
||
|
{
|
||
|
if (hidden_side & current_side[j])
|
||
|
continue;
|
||
|
|
||
|
if (i == j ||
|
||
|
gdk_rgba_equal (colors[i], colors[j]))
|
||
|
{
|
||
|
/* we were already painted when i == j */
|
||
|
if (i > j)
|
||
|
break;
|
||
|
|
||
|
if (j == 0)
|
||
|
_gtk_rounded_box_path_top (&border_box, &padding_box, cr);
|
||
|
else if (j == 1)
|
||
|
_gtk_rounded_box_path_right (&border_box, &padding_box, cr);
|
||
|
else if (j == 2)
|
||
|
_gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
|
||
|
else if (j == 3)
|
||
|
_gtk_rounded_box_path_left (&border_box, &padding_box, cr);
|
||
|
}
|
||
|
}
|
||
|
/* we were already painted when i == j */
|
||
|
if (i > j)
|
||
|
continue;
|
||
|
|
||
|
gdk_cairo_set_source_rgba (cr, colors[i]);
|
||
|
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
|
||
|
if (border_pat)
|
||
|
cairo_pattern_destroy (border_pat);
|
||
|
|
||
|
for (i = 0; i < 4; i++)
|
||
|
gdk_rgba_free (colors[i]);
|
||
|
}
|
||
|
|
||
|
/* draw the inner stroke */
|
||
|
static void
|
||
|
draw_inner_stroke (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GdkRGBA *colors[4];
|
||
|
GdkRGBA *inner_stroke_color;
|
||
|
GtkBorder *inner_border;
|
||
|
GtkRoundedBox border_box, padding_box;
|
||
|
GtkStateFlags state;
|
||
|
cairo_pattern_t *inner_stroke_pat;
|
||
|
static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
|
||
|
guint i, j;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"-tdegtk-inner-stroke-color", &inner_stroke_color,
|
||
|
"-tdegtk-inner-stroke-top-color", &colors[0],
|
||
|
"-tdegtk-inner-stroke-right-color", &colors[1],
|
||
|
"-tdegtk-inner-stroke-bottom-color", &colors[2],
|
||
|
"-tdegtk-inner-stroke-left-color", &colors[3],
|
||
|
"-tdegtk-inner-stroke-gradient", &inner_stroke_pat,
|
||
|
"-tdegtk-inner-stroke-width", &inner_border,
|
||
|
NULL);
|
||
|
|
||
|
hide_border_sides (inner_border, hidden_side);
|
||
|
|
||
|
if (tdegtk_gtk_border_is_zero (inner_border))
|
||
|
goto end_draw_inner_stroke;
|
||
|
|
||
|
apply_default_color (colors, inner_stroke_color);
|
||
|
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_translate (cr, x, y);
|
||
|
|
||
|
/* create the path to fill */
|
||
|
_gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
|
||
|
_gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
|
||
|
padding_box = border_box;
|
||
|
_gtk_rounded_box_shrink (&padding_box, inner_border->top,
|
||
|
inner_border->right,
|
||
|
inner_border->bottom,
|
||
|
inner_border->left);
|
||
|
|
||
|
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
|
||
|
|
||
|
if (inner_stroke_pat)
|
||
|
{
|
||
|
/* pattern */
|
||
|
cairo_scale (cr, width, height);
|
||
|
cairo_set_source (cr, inner_stroke_pat);
|
||
|
cairo_scale (cr, 1.0 / width, 1.0 / height);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
_gtk_rounded_box_path (&padding_box, cr);
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
else if (gdk_rgba_equal (colors[0], colors[1]) &&
|
||
|
gdk_rgba_equal (colors[0], colors[2]) &&
|
||
|
gdk_rgba_equal (colors[0], colors[3]))
|
||
|
{
|
||
|
/* one color */
|
||
|
gdk_cairo_set_source_rgba (cr, colors[0]);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
_gtk_rounded_box_path (&padding_box, cr);
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* different colors */
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
if (hidden_side & current_side[i])
|
||
|
continue;
|
||
|
|
||
|
for (j = 0; j < 4; j++)
|
||
|
{
|
||
|
if (hidden_side & current_side[j])
|
||
|
continue;
|
||
|
|
||
|
if (i == j ||
|
||
|
gdk_rgba_equal (colors[i], colors[j]))
|
||
|
{
|
||
|
/* we were already painted when i == j */
|
||
|
if (i > j)
|
||
|
break;
|
||
|
|
||
|
if (j == 0)
|
||
|
_gtk_rounded_box_path_top (&border_box, &padding_box, cr);
|
||
|
else if (j == 1)
|
||
|
_gtk_rounded_box_path_right (&border_box, &padding_box, cr);
|
||
|
else if (j == 2)
|
||
|
_gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
|
||
|
else if (j == 3)
|
||
|
_gtk_rounded_box_path_left (&border_box, &padding_box, cr);
|
||
|
}
|
||
|
}
|
||
|
/* we were already painted when i == j */
|
||
|
if (i > j)
|
||
|
continue;
|
||
|
|
||
|
gdk_cairo_set_source_rgba (cr, colors[i]);
|
||
|
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
|
||
|
end_draw_inner_stroke:
|
||
|
gtk_border_free (inner_border);
|
||
|
|
||
|
if (inner_stroke_pat != NULL)
|
||
|
cairo_pattern_destroy (inner_stroke_pat);
|
||
|
|
||
|
gdk_rgba_free (inner_stroke_color);
|
||
|
|
||
|
for (i = 0; i < 4; i++)
|
||
|
gdk_rgba_free (colors[i]);
|
||
|
}
|
||
|
|
||
|
/* draw the outer stroke */
|
||
|
static void
|
||
|
draw_outer_stroke (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GdkRGBA *outer_stroke_color;
|
||
|
GdkRGBA *colors[4];
|
||
|
GtkBorder *outer_border;
|
||
|
GtkRoundedBox border_box, padding_box;
|
||
|
GtkStateFlags state;
|
||
|
cairo_pattern_t *outer_stroke_pat;
|
||
|
static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
|
||
|
guint i, j;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"-tdegtk-outer-stroke-color", &outer_stroke_color,
|
||
|
"-tdegtk-outer-stroke-top-color", &colors[0],
|
||
|
"-tdegtk-outer-stroke-right-color", &colors[1],
|
||
|
"-tdegtk-outer-stroke-bottom-color", &colors[2],
|
||
|
"-tdegtk-outer-stroke-left-color", &colors[3],
|
||
|
"-tdegtk-outer-stroke-gradient", &outer_stroke_pat,
|
||
|
"-tdegtk-outer-stroke-width", &outer_border,
|
||
|
NULL);
|
||
|
|
||
|
hide_border_sides (outer_border, hidden_side);
|
||
|
|
||
|
if (tdegtk_gtk_border_is_zero (outer_border))
|
||
|
goto end_draw_outer_stroke;
|
||
|
|
||
|
apply_default_color (colors, outer_stroke_color);
|
||
|
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_translate (cr, x, y);
|
||
|
|
||
|
/* create the path to fill */
|
||
|
_gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
|
||
|
_gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
|
||
|
padding_box = border_box;
|
||
|
_gtk_rounded_box_shrink (&padding_box, outer_border->top,
|
||
|
outer_border->right,
|
||
|
outer_border->bottom,
|
||
|
outer_border->left);
|
||
|
|
||
|
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
|
||
|
|
||
|
if (outer_stroke_pat)
|
||
|
{
|
||
|
/* pattern */
|
||
|
cairo_scale (cr, width, height);
|
||
|
cairo_set_source (cr, outer_stroke_pat);
|
||
|
cairo_scale (cr, 1.0 / width, 1.0 / height);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
_gtk_rounded_box_path (&padding_box, cr);
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
else if (gdk_rgba_equal (colors[0], colors[1]) &&
|
||
|
gdk_rgba_equal (colors[0], colors[2]) &&
|
||
|
gdk_rgba_equal (colors[0], colors[3]))
|
||
|
{
|
||
|
/* one color */
|
||
|
gdk_cairo_set_source_rgba (cr, colors[0]);
|
||
|
|
||
|
_gtk_rounded_box_path (&border_box, cr);
|
||
|
_gtk_rounded_box_path (&padding_box, cr);
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* different colors */
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
if (hidden_side & current_side[i])
|
||
|
continue;
|
||
|
|
||
|
for (j = 0; j < 4; j++)
|
||
|
{
|
||
|
if (hidden_side & current_side[j])
|
||
|
continue;
|
||
|
|
||
|
if (i == j ||
|
||
|
gdk_rgba_equal (colors[i], colors[j]))
|
||
|
{
|
||
|
/* we were already painted when i == j */
|
||
|
if (i > j)
|
||
|
break;
|
||
|
|
||
|
if (j == 0)
|
||
|
_gtk_rounded_box_path_top (&border_box, &padding_box, cr);
|
||
|
else if (j == 1)
|
||
|
_gtk_rounded_box_path_right (&border_box, &padding_box, cr);
|
||
|
else if (j == 2)
|
||
|
_gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
|
||
|
else if (j == 3)
|
||
|
_gtk_rounded_box_path_left (&border_box, &padding_box, cr);
|
||
|
}
|
||
|
}
|
||
|
/* we were already painted when i == j */
|
||
|
if (i > j)
|
||
|
continue;
|
||
|
|
||
|
gdk_cairo_set_source_rgba (cr, colors[i]);
|
||
|
|
||
|
cairo_fill (cr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
|
||
|
end_draw_outer_stroke:
|
||
|
gtk_border_free (outer_border);
|
||
|
|
||
|
if (outer_stroke_pat != NULL)
|
||
|
cairo_pattern_destroy (outer_stroke_pat);
|
||
|
|
||
|
gdk_rgba_free (outer_stroke_color);
|
||
|
|
||
|
for (i = 0; i < 4; i++)
|
||
|
gdk_rgba_free (colors[i]);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tdegtk_cairo_draw_frame (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
guint hidden_side,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
GtkBorder border;
|
||
|
GtkBorder *outer_border;
|
||
|
GtkStateFlags state;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"-tdegtk-outer-stroke-width", &outer_border,
|
||
|
NULL);
|
||
|
gtk_theming_engine_get_border (engine, state, &border);
|
||
|
|
||
|
hide_border_sides (&border, hidden_side);
|
||
|
hide_border_sides (outer_border, hidden_side);
|
||
|
|
||
|
if (!tdegtk_gtk_border_is_zero (outer_border))
|
||
|
{
|
||
|
/* first layer, outer stroke */
|
||
|
draw_outer_stroke (engine, cr,
|
||
|
x, y,
|
||
|
width, height,
|
||
|
hidden_side, junction);
|
||
|
|
||
|
shrink_with_border (outer_border, &x, &y, &width, &height);
|
||
|
}
|
||
|
|
||
|
/* second layer, inner stroke */
|
||
|
draw_inner_stroke (engine, cr,
|
||
|
x + border.left, y + border.top,
|
||
|
width - (border.left + border.right), height - (border.top + border.bottom),
|
||
|
hidden_side, junction);
|
||
|
|
||
|
/* third layer, border */
|
||
|
draw_border (engine, cr,
|
||
|
x, y,
|
||
|
width, height,
|
||
|
hidden_side, junction);
|
||
|
|
||
|
gtk_border_free (outer_border);
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
tdegtk_cairo_draw_from_texture (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height)
|
||
|
{
|
||
|
GtkStateFlags state;
|
||
|
GValue value = { 0, };
|
||
|
cairo_pattern_t *texture = NULL;
|
||
|
cairo_surface_t *surface = NULL;
|
||
|
gboolean retval = FALSE;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get_property (engine, "background-image", state, &value);
|
||
|
|
||
|
if (!G_VALUE_HOLDS_BOXED (&value))
|
||
|
return FALSE;
|
||
|
|
||
|
texture = g_value_dup_boxed (&value);
|
||
|
g_value_unset (&value);
|
||
|
|
||
|
if (texture != NULL)
|
||
|
cairo_pattern_get_surface (texture, &surface);
|
||
|
|
||
|
if (surface != NULL)
|
||
|
{
|
||
|
cairo_save (cr);
|
||
|
|
||
|
cairo_scale (cr, width / cairo_image_surface_get_width (surface),
|
||
|
height / cairo_image_surface_get_height (surface));
|
||
|
cairo_set_source_surface (cr, surface, x, y);
|
||
|
|
||
|
cairo_paint (cr);
|
||
|
|
||
|
cairo_restore (cr);
|
||
|
|
||
|
retval = TRUE;
|
||
|
}
|
||
|
|
||
|
if (texture != NULL)
|
||
|
cairo_pattern_destroy (texture);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tdegtk_cairo_round_rect (cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
gint radius,
|
||
|
guint sides,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
radius = CLAMP (radius, 0, MIN (width / 2, height / 2));
|
||
|
|
||
|
if (sides & SIDE_RIGHT)
|
||
|
{
|
||
|
if (radius == 0 ||
|
||
|
(junction & GTK_JUNCTION_CORNER_TOPRIGHT))
|
||
|
cairo_move_to (cr, x + width, y);
|
||
|
else
|
||
|
{
|
||
|
cairo_new_sub_path (cr);
|
||
|
|
||
|
cairo_arc (cr, x + width - radius, y + radius, radius, - G_PI / 4, 0);
|
||
|
}
|
||
|
|
||
|
if (radius == 0 ||
|
||
|
(junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
|
||
|
cairo_line_to (cr, x + width, y + height);
|
||
|
else
|
||
|
cairo_arc (cr, x + width - radius, y + height - radius, radius, 0, G_PI / 4);
|
||
|
}
|
||
|
|
||
|
if (sides & SIDE_BOTTOM)
|
||
|
{
|
||
|
if (radius != 0 &&
|
||
|
! (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
|
||
|
{
|
||
|
if ((sides & SIDE_RIGHT) == 0)
|
||
|
cairo_new_sub_path (cr);
|
||
|
|
||
|
cairo_arc (cr, x + width - radius, y + height - radius, radius, G_PI / 4, G_PI / 2);
|
||
|
}
|
||
|
else if ((sides & SIDE_RIGHT) == 0)
|
||
|
cairo_move_to (cr, x + width, y + height);
|
||
|
|
||
|
if (radius == 0 ||
|
||
|
(junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
|
||
|
cairo_line_to (cr, x, y + height);
|
||
|
else
|
||
|
cairo_arc (cr, x + radius, y + height - radius, radius, G_PI / 2, 3 * (G_PI / 4));
|
||
|
}
|
||
|
else
|
||
|
cairo_move_to (cr, x, y + height);
|
||
|
|
||
|
if (sides & SIDE_LEFT)
|
||
|
{
|
||
|
if (radius != 0 &&
|
||
|
! (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
|
||
|
{
|
||
|
if ((sides & SIDE_BOTTOM) == 0)
|
||
|
cairo_new_sub_path (cr);
|
||
|
|
||
|
cairo_arc (cr, x + radius, y + height - radius, radius, 3 * (G_PI / 4), G_PI);
|
||
|
}
|
||
|
else if ((sides & SIDE_BOTTOM) == 0)
|
||
|
cairo_move_to (cr, x, y + height);
|
||
|
|
||
|
if (radius == 0 ||
|
||
|
(junction & GTK_JUNCTION_CORNER_TOPLEFT))
|
||
|
cairo_line_to (cr, x, y);
|
||
|
else
|
||
|
cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI + G_PI / 4);
|
||
|
}
|
||
|
|
||
|
if (sides & SIDE_TOP)
|
||
|
{
|
||
|
if (radius != 0 &&
|
||
|
! (junction & GTK_JUNCTION_CORNER_TOPLEFT))
|
||
|
{
|
||
|
if ((sides & SIDE_LEFT) == 0)
|
||
|
cairo_new_sub_path (cr);
|
||
|
|
||
|
cairo_arc (cr, x + radius, y + radius, radius, 5 * (G_PI / 4), 3 * (G_PI / 2));
|
||
|
}
|
||
|
else if ((sides & SIDE_LEFT) == 0)
|
||
|
cairo_move_to (cr, x, y);
|
||
|
|
||
|
if (radius == 0 ||
|
||
|
(junction & GTK_JUNCTION_CORNER_TOPRIGHT))
|
||
|
cairo_line_to (cr, x + width, y);
|
||
|
else
|
||
|
cairo_arc (cr, x + width - radius, y + radius, radius, 3 * (G_PI / 2), - G_PI / 4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tdegtk_cairo_round_rect_inner (cairo_t *cr,
|
||
|
gdouble x,
|
||
|
gdouble y,
|
||
|
gdouble width,
|
||
|
gdouble height,
|
||
|
gint radius,
|
||
|
guint sides,
|
||
|
GtkJunctionSides junction)
|
||
|
{
|
||
|
gdouble line_width;
|
||
|
|
||
|
line_width = cairo_get_line_width (cr);
|
||
|
|
||
|
/* center the rounded rectangle using line_width */
|
||
|
tdegtk_cairo_round_rect (cr, x + line_width / 2.0,
|
||
|
y + line_width / 2.0,
|
||
|
width - line_width,
|
||
|
height - line_width,
|
||
|
radius, sides, junction);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tdegtk_cairo_set_source_border (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble width,
|
||
|
gdouble height)
|
||
|
{
|
||
|
GdkRGBA border_color;
|
||
|
GtkBorderStyle border_style;
|
||
|
GtkStateFlags state;
|
||
|
cairo_pattern_t *border_pat;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"border-style", &border_style,
|
||
|
"-tdegtk-border-gradient", &border_pat,
|
||
|
NULL);
|
||
|
gtk_theming_engine_get_border_color (engine, state, &border_color);
|
||
|
|
||
|
if (border_pat)
|
||
|
{
|
||
|
/* pattern */
|
||
|
cairo_scale (cr, width, height);
|
||
|
cairo_set_source (cr, border_pat);
|
||
|
cairo_scale (cr, 1.0 / width, 1.0 / height);
|
||
|
}
|
||
|
else
|
||
|
/* one color */
|
||
|
gdk_cairo_set_source_rgba (cr, &border_color);
|
||
|
|
||
|
if (border_pat != NULL)
|
||
|
cairo_pattern_destroy (border_pat);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
tdegtk_cairo_set_source_inner_stroke (GtkThemingEngine *engine,
|
||
|
cairo_t *cr,
|
||
|
gdouble width,
|
||
|
gdouble height)
|
||
|
{
|
||
|
GdkRGBA *inner_stroke_color;
|
||
|
GtkStateFlags state;
|
||
|
cairo_pattern_t *inner_stroke_pat;
|
||
|
|
||
|
state = gtk_theming_engine_get_state (engine);
|
||
|
|
||
|
gtk_theming_engine_get (engine, state,
|
||
|
"-tdegtk-inner-stroke-color", &inner_stroke_color,
|
||
|
"-tdegtk-inner-stroke-gradient", &inner_stroke_pat,
|
||
|
NULL);
|
||
|
|
||
|
if (inner_stroke_pat)
|
||
|
{
|
||
|
/* pattern */
|
||
|
cairo_scale (cr, width, height);
|
||
|
cairo_set_source (cr, inner_stroke_pat);
|
||
|
cairo_scale (cr, 1.0 / width, 1.0 / height);
|
||
|
}
|
||
|
else
|
||
|
/* one color */
|
||
|
gdk_cairo_set_source_rgba (cr, inner_stroke_color);
|
||
|
|
||
|
if (inner_stroke_pat != NULL)
|
||
|
cairo_pattern_destroy (inner_stroke_pat);
|
||
|
|
||
|
gdk_rgba_free (inner_stroke_color);
|
||
|
}
|