Example #1
0
File: gtkrender.c Project: Vort/gtk
/*
 * gtk_render_content_path:
 * @context: style context to get style information from
 * @cr: cairo context to add path to
 * @x: x coordinate of CSS box
 * @y: y coordinate of CSS box
 * @width: width of CSS box
 * @height: height of CSS box
 *
 * Adds the path of the content box to @cr for a given border box.
 * This function respects rounded corners.
 *
 * This is useful if you are drawing content that is supposed to
 * fill the whole content area, like the color buttons in
 * #GtkColorChooserDialog.
 **/
void
gtk_render_content_path (GtkStyleContext *context,
                         cairo_t         *cr,
                         double           x,
                         double           y,
                         double           width,
                         double           height)
{
  GtkRoundedBox box;

  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
  g_return_if_fail (cr != NULL);

  _gtk_rounded_box_init_rect (&box, x, y, width, height);
  _gtk_rounded_box_apply_border_radius_for_style (&box, gtk_style_context_lookup_style (context), 0);

  _gtk_rounded_box_shrink (&box,
                           _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100)
                           + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_TOP), 100),
                           _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100)
                           + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_RIGHT), 100),
                           _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100)
                           + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_BOTTOM), 100),
                           _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100)
                           + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_PADDING_LEFT), 100));

  _gtk_rounded_box_path (&box, cr);
}
Example #2
0
static void
_gtk_theming_background_paint_color (GtkThemingBackground *bg,
                                     cairo_t              *cr,
                                     const GdkRGBA        *bg_color,
                                     GtkCssValue          *background_image)
{
  gint n_values = _gtk_css_array_value_get_n_values (background_image);
  GtkCssArea clip = _gtk_css_area_value_get 
    (_gtk_css_array_value_get_nth 
     (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_CLIP), 
      n_values - 1));

  _gtk_rounded_box_path (&bg->boxes[clip], cr);
  gdk_cairo_set_source_rgba (cr, bg_color);
  cairo_fill (cr);
}
Example #3
0
static void
_gtk_theming_background_paint_color (GtkThemingBackground *bg,
                                     cairo_t              *cr,
                                     GtkCssValue          *background_image)
{
  GtkRoundedBox clip_box;
  gint n_values = _gtk_css_array_value_get_n_values (background_image);
  GtkCssArea clip = _gtk_css_area_value_get 
    (_gtk_css_array_value_get_nth 
     (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_CLIP), 
      n_values - 1));

  clip_box = bg->border_box;
  _gtk_theming_background_apply_clip (bg, &clip_box, clip);

  cairo_save (cr);
  _gtk_rounded_box_path (&clip_box, cr);
  cairo_clip (cr);

  gdk_cairo_set_source_rgba (cr, &bg->bg_color);
  cairo_paint (cr);

  cairo_restore (cr);
}
Example #4
0
static void
render_frame_stroke (cairo_t       *cr,
                     GtkRoundedBox *border_box,
                     const double   border_width[4],
                     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_width[0] != border_width[1] ||
                      border_width[0] != border_width[2] ||
                      border_width[0] != border_width[3] ;

  stroke_box = *border_box;
  _gtk_rounded_box_shrink (&stroke_box,
                           border_width[GTK_CSS_TOP] / 2.0,
                           border_width[GTK_CSS_RIGHT] / 2.0,
                           border_width[GTK_CSS_BOTTOM] / 2.0,
                           border_width[GTK_CSS_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 (&stroke_box, cr);
      gdk_cairo_set_source_rgba (cr, &colors[0]);
      set_stroke_style (cr, border_width[0], stroke_style, length);
      cairo_stroke (cr);
    }
  else
    {
      GtkRoundedBox padding_box;

      padding_box = *border_box;
      _gtk_rounded_box_shrink (&padding_box,
                               border_width[GTK_CSS_TOP],
                               border_width[GTK_CSS_RIGHT],
                               border_width[GTK_CSS_BOTTOM],
                               border_width[GTK_CSS_LEFT]);

      for (i = 0; i < 4; i++)
        {
          if (hidden_side & (1 << i))
            continue;

          if (border_width[i] == 0)
            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,
                            border_width[i],
                            stroke_style,
                            _gtk_rounded_box_guess_length (&stroke_box, i));
          cairo_stroke (cr);

          cairo_restore (cr);
        }
    }
}
Example #5
0
static void
render_frame_fill (cairo_t       *cr,
                   GtkRoundedBox *border_box,
                   const double   border_width[4],
                   GdkRGBA        colors[4],
                   guint          hidden_side)
{
  GtkRoundedBox padding_box;
  guint i, j;

  padding_box = *border_box;
  _gtk_rounded_box_shrink (&padding_box,
                           border_width[GTK_CSS_TOP],
                           border_width[GTK_CSS_RIGHT],
                           border_width[GTK_CSS_BOTTOM],
                           border_width[GTK_CSS_LEFT]);

  if (hidden_side == 0 &&
      gdk_rgba_equal (&colors[0], &colors[1]) &&
      gdk_rgba_equal (&colors[0], &colors[2]) &&
      gdk_rgba_equal (&colors[0], &colors[3]))
    {
      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++) 
        {
          if (hidden_side & (1 << i))
            continue;

          for (j = 0; j < 4; j++)
            { 
              if (hidden_side & (1 << 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);
        }
    }
}
Example #6
0
static void
_gtk_theming_background_paint_layer (GtkThemingBackground *bg,
                                     guint                 idx,
                                     cairo_t              *cr)
{
  GtkCssRepeatStyle hrepeat, vrepeat;
  const GtkCssValue *pos, *repeat;
  GtkCssImage *image;
  const GtkRoundedBox *origin;
  double image_width, image_height;
  double width, height;

  pos = _gtk_css_array_value_get_nth (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_POSITION), idx);
  repeat = _gtk_css_array_value_get_nth (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_REPEAT), idx);
  hrepeat = _gtk_css_background_repeat_value_get_x (repeat);
  vrepeat = _gtk_css_background_repeat_value_get_y (repeat);
  image = _gtk_css_image_value_get_image (
              _gtk_css_array_value_get_nth (
                  _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_IMAGE),
                  idx));
  origin = &bg->boxes[
               _gtk_css_area_value_get (
                   _gtk_css_array_value_get_nth (
                       _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_ORIGIN),
                       idx))];
  width = origin->box.width;
  height = origin->box.height;

  if (image == NULL || width <= 0 || height <= 0)
    return;

  _gtk_css_bg_size_value_compute_size (_gtk_css_array_value_get_nth (_gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_SIZE), idx),
                                       image,
                                       width,
                                       height,
                                       &image_width,
                                       &image_height);

  if (image_width <= 0 || image_height <= 0)
    return;

  /* optimization */
  if (image_width == width)
    hrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT;
  if (image_height == height)
    vrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT;


  cairo_save (cr);

  _gtk_rounded_box_path (
      &bg->boxes[
          _gtk_css_area_value_get (
              _gtk_css_array_value_get_nth (
                  _gtk_style_context_peek_property (bg->context, GTK_CSS_PROPERTY_BACKGROUND_CLIP),
                  idx))],
      cr);
  cairo_clip (cr);


  cairo_translate (cr, origin->box.x, origin->box.y);

  if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT && vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT)
    {
      cairo_translate (cr,
                       _gtk_css_position_value_get_x (pos, width - image_width),
                       _gtk_css_position_value_get_y (pos, height - image_height));
      /* shortcut for normal case */
      _gtk_css_image_draw (image, cr, image_width, image_height);
    }
  else
    {
      int surface_width, surface_height;
      cairo_rectangle_t fill_rect;
      cairo_surface_t *surface;
      cairo_t *cr2;

      /* If ‘background-repeat’ is ‘round’ for one (or both) dimensions,
       * there is a second step. The UA must scale the image in that
       * dimension (or both dimensions) so that it fits a whole number of
       * times in the background positioning area. In the case of the width
       * (height is analogous):
       *
       * If X ≠ 0 is the width of the image after step one and W is the width
       * of the background positioning area, then the rounded width
       * X' = W / round(W / X) where round() is a function that returns the
       * nearest natural number (integer greater than zero). 
       *
       * If ‘background-repeat’ is ‘round’ for one dimension only and if
       * ‘background-size’ is ‘auto’ for the other dimension, then there is
       * a third step: that other dimension is scaled so that the original
       * aspect ratio is restored. 
       */
      if (hrepeat == GTK_CSS_REPEAT_STYLE_ROUND)
        {
          double n = round (width / image_width);

          n = MAX (1, n);

          if (vrepeat != GTK_CSS_REPEAT_STYLE_ROUND
              /* && vsize == auto (it is by default) */)
            image_height *= width / (image_width * n);
          image_width = width / n;
        }
      if (vrepeat == GTK_CSS_REPEAT_STYLE_ROUND)
        {
          double n = round (height / image_height);

          n = MAX (1, n);

          if (hrepeat != GTK_CSS_REPEAT_STYLE_ROUND
              /* && hsize == auto (it is by default) */)
            image_width *= height / (image_height * n);
          image_height = height / n;
        }

      /* if hrepeat or vrepeat is 'space', we create a somewhat larger surface
       * to store the extra space. */
      if (hrepeat == GTK_CSS_REPEAT_STYLE_SPACE)
        {
          double n = floor (width / image_width);
          surface_width = n ? round (width / n) : 0;
        }
      else
        surface_width = round (image_width);

      if (vrepeat == GTK_CSS_REPEAT_STYLE_SPACE)
        {
          double n = floor (height / image_height);
          surface_height = n ? round (height / n) : 0;
        }
      else
        surface_height = round (image_height);

      surface = cairo_surface_create_similar (cairo_get_target (cr),
                                              CAIRO_CONTENT_COLOR_ALPHA,
                                              surface_width, surface_height);
      cr2 = cairo_create (surface);
      cairo_translate (cr2,
                       0.5 * (surface_width - image_width),
                       0.5 * (surface_height - image_height));
      _gtk_css_image_draw (image, cr2, image_width, image_height);
      cairo_destroy (cr2);

      cairo_set_source_surface (cr, surface,
                                _gtk_css_position_value_get_x (pos, width - image_width),
                                _gtk_css_position_value_get_y (pos, height - image_height));
      cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
      cairo_surface_destroy (surface);

      if (hrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT)
        {
          fill_rect.x = _gtk_css_position_value_get_x (pos, width - image_width);
          fill_rect.width = image_width;
        }
      else
        {
          fill_rect.x = 0;
          fill_rect.width = width;
        }

      if (vrepeat == GTK_CSS_REPEAT_STYLE_NO_REPEAT)
        {
          fill_rect.y = _gtk_css_position_value_get_y (pos, height - image_height);
          fill_rect.height = image_height;
        }
      else
        {
          fill_rect.y = 0;
          fill_rect.height = height;
        }

      cairo_rectangle (cr, fill_rect.x, fill_rect.y,
                       fill_rect.width, fill_rect.height);
      cairo_fill (cr);
    }


  cairo_restore (cr);
}
Example #7
0
static gboolean
swatch_draw (GtkWidget *widget,
             cairo_t   *cr)
{
  GtkColorSwatch *swatch = (GtkColorSwatch*)widget;
  GtkThemingBackground background;
  gdouble width, height;
  GtkStyleContext *context;
  GtkStateFlags state;
  GtkIconTheme *theme;
  GtkIconInfo *icon_info = NULL;

  theme = gtk_icon_theme_get_default ();
  context = gtk_widget_get_style_context (widget);
  state = gtk_widget_get_state_flags (widget);
  width = gtk_widget_get_allocated_width (widget);
  height = gtk_widget_get_allocated_height (widget);

  cairo_save (cr);

  gtk_style_context_save (context);
  gtk_style_context_set_state (context, state);

  _gtk_theming_background_init_from_context (&background, context,
                                             0, 0, width, height,
                                             GTK_JUNCTION_NONE);

  if (swatch->priv->has_color)
    {
      cairo_pattern_t *pattern;
      cairo_matrix_t matrix;

      if (swatch->priv->use_alpha)
        {
          cairo_save (cr);

          _gtk_rounded_box_path (&background.padding_box, cr);
          cairo_clip_preserve (cr);

          cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
          cairo_fill_preserve (cr);

          pattern = _gtk_color_chooser_get_checkered_pattern ();
          cairo_matrix_init_scale (&matrix, 0.125, 0.125);
          cairo_pattern_set_matrix (pattern, &matrix);

          cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
          cairo_mask (cr, pattern);
          cairo_pattern_destroy (pattern);

          cairo_restore (cr);

          background.bg_color = swatch->priv->color;
        }
      else
        {
          background.bg_color = swatch->priv->color;
          background.bg_color.alpha = 1.0;
        }

      _gtk_theming_background_render (&background, cr);
    }
  else
    _gtk_theming_background_render (&background, cr);

  gtk_render_frame (context, cr,
                    0, 0, width, height);

  if (gtk_widget_has_visible_focus (widget))
    {
      cairo_set_line_width (cr, 2);
      if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5)
        cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
      else
        cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
        _gtk_rounded_box_shrink (&background.padding_box, 3, 3, 3, 3);
        _gtk_rounded_box_path (&background.padding_box, cr);
        cairo_stroke (cr);
    }

  if (swatch->priv->icon)
    {
      icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16,
                                              GTK_ICON_LOOKUP_GENERIC_FALLBACK
                                              | GTK_ICON_LOOKUP_USE_BUILTIN);
    }
  else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
    {
      GdkRGBA bg, border;
      GtkBorder border_width;
      GIcon *gicon;

      gtk_style_context_add_class (context, "color-active-badge");
      _gtk_theming_background_init_from_context (&background, context,
                                                 (width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2,
                                                 2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS,
                                                 GTK_JUNCTION_NONE);

      if (_gtk_theming_background_has_background_image (&background))
        {
          _gtk_theming_background_render (&background, cr);
        }
      else
        {
          gtk_style_context_get_background_color (context, state, &bg);
          gtk_style_context_get_border_color (context, state, &border);
          gtk_style_context_get_border (context, state, &border_width);

          cairo_new_sub_path (cr);
          cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI);
          cairo_close_path (cr);
          gdk_cairo_set_source_rgba (cr, &bg);
          cairo_fill_preserve (cr);

          gdk_cairo_set_source_rgba (cr, &border);
          cairo_set_line_width (cr, border_width.left);
          cairo_stroke (cr);

          gicon = g_themed_icon_new ("object-select-symbolic");
          /* fallback for themes that don't have object-select-symbolic */
          g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");

          icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
                                                      GTK_ICON_LOOKUP_GENERIC_FALLBACK
                                                      | GTK_ICON_LOOKUP_USE_BUILTIN);
          g_object_unref (gicon);
        }
    }

  if (icon_info != NULL)
    {
      GdkPixbuf *pixbuf;

      pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context,
                                                        NULL, NULL);

      if (pixbuf != NULL)
        {
          gtk_render_icon (context, cr, pixbuf,
                           (width - gdk_pixbuf_get_width (pixbuf)) / 2,
                           (height - gdk_pixbuf_get_height (pixbuf)) / 2);
          g_object_unref (pixbuf);
        }

      g_object_unref (icon_info);
    }

  cairo_restore (cr);
  gtk_style_context_restore (context);

  return FALSE;
}