Hi clutter community,

Here is a new actor for clutter: clutter-circle.
You can draw circle, arc, plain or empty with this actor.

Here is a screenshot for this actor:
http://txzone.net/blog/public/noya_bar_spectrum.png

A bug have been filled for him:
http://bugzilla.o-hand.com/show_bug.cgi?id=1302

Any remark are welcome !

Regards,

Mathieu
#include <clutter/clutter.h>
#include "clutter-circle.h"

#ifndef CLUTTER_PARAM_READWRITE
#define CLUTTER_PARAM_READWRITE \
         G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
#endif


G_DEFINE_TYPE (ClutterCircle, clutter_circle, CLUTTER_TYPE_ACTOR);

enum
{
  PROP_0,
  PROP_COLOR,
  PROP_ANGLE_START,
  PROP_ANGLE_STOP,
  PROP_WIDTH,
  PROP_RADIUS,
};

#define CLUTTER_CIRCLE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_CIRCLE, ClutterCirclePrivate))

struct _ClutterCirclePrivate
{
  ClutterColor color;
  ClutterFixed angle_start;
  ClutterFixed angle_stop;
  ClutterFixed width;
  ClutterFixed radius;
};

static void
cc_cogl_path_arc (ClutterFixed center_x,
		ClutterFixed center_y,
		ClutterFixed radius_x,
		ClutterFixed radius_y,
		ClutterAngle angle_1,
		ClutterAngle angle_2,
		ClutterAngle angle_step,
		guint        move_first)
{
	ClutterAngle a     = 0x0;
	ClutterFixed cosa  = 0x0;
	ClutterFixed sina  = 0x0;
	ClutterFixed px    = 0x0;
	ClutterFixed py    = 0x0;

	/* Fix invalid angles */

	if (angle_1 == angle_2 || angle_step == 0x0)
		return;

	if (angle_step < 0x0)
		angle_step = -angle_step;

	/* Walk the arc by given step */

	a = angle_1;
	while (a != angle_2)
	{
		cosa = clutter_cosi (a);
		sina = clutter_sini (a);

		px = center_x + CFX_MUL (cosa, radius_x);
		py = center_y + CFX_MUL (sina, radius_y);

		if (a == angle_1 && move_first)
			cogl_path_move_to (px, py);
		else
			cogl_path_line_to (px, py);

		if (G_LIKELY (angle_2 > angle_1))
		{
			a += angle_step;
			if (a > angle_2)
				a = angle_2;
		}
		else
		{
			a -= angle_step;
			if (a < angle_2)
				a = angle_2;
		}
	}

	/* Make sure the final point is drawn */

	cosa = clutter_cosi (angle_2);
	sina = clutter_sini (angle_2);

	px = center_x + CFX_MUL (cosa, radius_x);
	py = center_y + CFX_MUL (sina, radius_y);

	cogl_path_line_to (px, py);
}

static void
clutter_circle_paint (ClutterActor *self)
{
	ClutterFixed				dw, dh;
	ClutterCircle				*circle = CLUTTER_CIRCLE(self);
	ClutterCirclePrivate		*priv;
	ClutterGeometry				geom;
	ClutterColor				tmp_col;
	ClutterFixed				precision = 2;

	circle = CLUTTER_CIRCLE(self);
	priv = circle->priv;

	clutter_actor_get_allocation_geometry (self, &geom);

	tmp_col.red   = priv->color.red;
	tmp_col.green = priv->color.green;
	tmp_col.blue  = priv->color.blue;
	tmp_col.alpha = clutter_actor_get_paint_opacity (self)
		* priv->color.alpha
		/ 255;

	cogl_color (&tmp_col);

	if ( priv->radius == 0 )
		clutter_circle_set_radius(circle, geom.width);

	dw = CLUTTER_INT_TO_FIXED(geom.width) >> 1;
	dh = CLUTTER_INT_TO_FIXED(geom.height) >> 1;

	cogl_path_move_to(dw, dh);
	cc_cogl_path_arc(dw, dh,
		CLUTTER_INT_TO_FIXED(priv->radius),
		CLUTTER_INT_TO_FIXED(priv->radius),
		CLUTTER_ANGLE_FROM_DEG(priv->angle_start + 270),
		CLUTTER_ANGLE_FROM_DEG(priv->angle_stop + 270),
		precision, 1
	);

	if ( priv->width != 0 )
	{
		cc_cogl_path_arc(dw, dh,
			CLUTTER_INT_TO_FIXED(priv->radius + priv->width),
			CLUTTER_INT_TO_FIXED(priv->radius + priv->width),
			CLUTTER_ANGLE_FROM_DEG(priv->angle_stop + 270),
			CLUTTER_ANGLE_FROM_DEG(priv->angle_start + 270),
			precision, 0
		);
	}
	cogl_path_close();

	/* fill path
	 */
	cogl_path_fill();

	/* and stroke border
	 */
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glLineWidth(1.5);

	cogl_path_stroke();

	glDisable(GL_LINE_SMOOTH);

}

void
clutter_circle_set_angle_start (ClutterCircle *circle,
                                guint          angle)
{
	ClutterCirclePrivate *priv;

	g_return_if_fail (CLUTTER_IS_CIRCLE (circle));
	priv = circle->priv;

	if (priv->angle_start != angle)
	{
		g_object_ref (circle);

		priv->angle_start = angle;

		if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (circle)))
			clutter_actor_queue_redraw (CLUTTER_ACTOR (circle));

		g_object_notify (G_OBJECT (circle), "angle-start");
		g_object_unref (circle);
	}
}

void
clutter_circle_set_angle_stop (ClutterCircle *circle,
                                guint          angle)
{
	ClutterCirclePrivate *priv;

	g_return_if_fail (CLUTTER_IS_CIRCLE (circle));
	priv = circle->priv;

	if (priv->angle_stop != angle)
	{
		g_object_ref (circle);

		priv->angle_stop = angle;

		if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (circle)))
			clutter_actor_queue_redraw (CLUTTER_ACTOR (circle));

		g_object_notify (G_OBJECT (circle), "angle-stop");
		g_object_unref (circle);
	}
}

void
clutter_circle_set_width (ClutterCircle *circle,
                                guint          width)
{
	ClutterCirclePrivate *priv;

	g_return_if_fail (CLUTTER_IS_CIRCLE (circle));
	priv = circle->priv;

	if (priv->width != width)
	{
		g_object_ref (circle);

		priv->width = width;

		if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (circle)))
			clutter_actor_queue_redraw (CLUTTER_ACTOR (circle));

		g_object_notify (G_OBJECT (circle), "width");
		g_object_unref (circle);
	}
}

void
clutter_circle_set_radius (ClutterCircle *circle,
                                guint          radius)
{
	ClutterCirclePrivate *priv;

	g_return_if_fail (CLUTTER_IS_CIRCLE (circle));
	priv = circle->priv;

	if (priv->radius != radius)
	{
		g_object_ref (circle);

		priv->radius = radius;

		if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (circle)))
			clutter_actor_queue_redraw (CLUTTER_ACTOR (circle));

		g_object_notify (G_OBJECT (circle), "radius");
		g_object_unref (circle);
	}
}

static void
clutter_circle_set_property (GObject      *object,
				guint         prop_id,
				const GValue *value,
				GParamSpec   *pspec)
{
  ClutterCircle *circle = CLUTTER_CIRCLE(object);

  switch (prop_id)
    {
    case PROP_COLOR:
      clutter_circle_set_color (circle, g_value_get_boxed (value));
      break;
	case PROP_ANGLE_START:
	  clutter_circle_set_angle_start (circle, g_value_get_uint (value));
	  break;
	case PROP_ANGLE_STOP:
	  clutter_circle_set_angle_stop (circle, g_value_get_uint (value));
	  break;
	case PROP_WIDTH:
	  clutter_circle_set_width (circle, g_value_get_uint (value));
	  break;
	case PROP_RADIUS:
	  clutter_circle_set_radius (circle, g_value_get_uint (value));
	  break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
clutter_circle_get_property (GObject    *object,
				guint       prop_id,
				GValue     *value,
				GParamSpec *pspec)
{
  ClutterCircle *circle = CLUTTER_CIRCLE(object);
  ClutterColor      color;

  switch (prop_id)
    {
    case PROP_COLOR:
      clutter_circle_get_color (circle, &color);
      g_value_set_boxed (value, &color);
      break;
    case PROP_ANGLE_START:
      g_value_set_uint (value, circle->priv->angle_start);
	  break;
    case PROP_ANGLE_STOP:
      g_value_set_uint (value, circle->priv->angle_stop);
	  break;
    case PROP_WIDTH:
      g_value_set_uint (value, circle->priv->width);
	  break;
    case PROP_RADIUS:
      g_value_set_uint (value, circle->priv->radius);
	  break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}


static void
clutter_circle_finalize (GObject *object)
{
  G_OBJECT_CLASS (clutter_circle_parent_class)->finalize (object);
}

static void
clutter_circle_dispose (GObject *object)
{
  G_OBJECT_CLASS (clutter_circle_parent_class)->dispose (object);
}


static void
clutter_circle_class_init (ClutterCircleClass *klass)
{
  GObjectClass        *gobject_class = G_OBJECT_CLASS (klass);
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);

  actor_class->paint        = clutter_circle_paint;

  gobject_class->finalize     = clutter_circle_finalize;
  gobject_class->dispose      = clutter_circle_dispose;
  gobject_class->set_property = clutter_circle_set_property;
  gobject_class->get_property = clutter_circle_get_property;

  /**
   * ClutterCircle:color:
   *
   * The color of the circle.
   */
  g_object_class_install_property (gobject_class,
                                   PROP_COLOR,
                                   g_param_spec_boxed ("color",
                                                       "Color",
                                                       "The color of the circle",
                                                       CLUTTER_TYPE_COLOR,
                                                       CLUTTER_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_ANGLE_START,
                                   g_param_spec_uint ("angle-start",
                                                       "Start Angle",
                                                       "The start of angle",
													   0, G_MAXUINT,
													   0,
                                                       CLUTTER_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_ANGLE_STOP,
                                   g_param_spec_uint ("angle-stop",
                                                       "End Angle",
                                                       "The end of angle",
													   0, G_MAXUINT,
													   0,
                                                       CLUTTER_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_WIDTH,
                                   g_param_spec_uint ("width",
                                                       "Width",
                                                       "Width",
													   0, G_MAXUINT,
													   0,
                                                       CLUTTER_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_RADIUS,
                                   g_param_spec_uint ("radius",
                                                       "Radius",
                                                       "Radius",
													   0, G_MAXUINT,
													   0,
                                                       CLUTTER_PARAM_READWRITE));
#if 0
  /**
   * ClutterCircle:border-color:
   *
   * The color of the border of the circle.
   *
   * Since: 0.2
   */
  g_object_class_install_property (gobject_class,
                                   PROP_BORDER_COLOR,
                                   g_param_spec_boxed ("border-color",
                                                       "Border Color",
                                                       "The color of the border of the circle",
                                                       CLUTTER_TYPE_COLOR,
                                                       CLUTTER_PARAM_READWRITE));
  /**
   * ClutterCircle:border-width:
   *
   * The width of the border of the circle, in pixels.
   *
   * Since: 0.2
   */
  g_object_class_install_property (gobject_class,
                                   PROP_BORDER_WIDTH,
                                   g_param_spec_uint ("border-width",
                                                      "Border Width",
                                                      "The width of the border of the circle",
                                                      0, G_MAXUINT,
                                                      0,
                                                      CLUTTER_PARAM_READWRITE));
  /**
   * ClutterCircle:has-border:
   *
   * Whether the #ClutterCircle should be displayed with a border.
   *
   * Since: 0.2
   */
  g_object_class_install_property (gobject_class,
                                   PROP_HAS_BORDER,
                                   g_param_spec_boolean ("has-border",
                                                         "Has Border",
                                                         "Whether the circle should have a border",
                                                         FALSE,
                                                         CLUTTER_PARAM_READWRITE));

#endif
  g_type_class_add_private (gobject_class, sizeof (ClutterCirclePrivate));
}

static void
clutter_circle_init (ClutterCircle *self)
{
  ClutterCirclePrivate *priv;

  self->priv = priv = CLUTTER_CIRCLE_GET_PRIVATE (self);

  priv->color.red = 0xff;
  priv->color.green = 0xff;
  priv->color.blue = 0xff;
  priv->color.alpha = 0xff;

  priv->angle_start = 0;
  priv->angle_stop = 0;
  priv->width = 0;
  priv->radius = 0;
}

/**
 * clutter_circle_new:
 *
 * Creates a new #ClutterActor with a rectangular shape.
 *
 * Return value: a new #ClutterActor
 */
ClutterActor*
clutter_circle_new (void)
{
  return g_object_new (CLUTTER_TYPE_CIRCLE, NULL);
}

/**
 * clutter_circle_new_with_color:
 * @color: a #ClutterColor
 *
 * Creates a new #ClutterActor with a rectangular shape
 * and of the given @color.
 *
 * Return value: a new #ClutterActor
 */
ClutterActor *
clutter_circle_new_with_color (const ClutterColor *color)
{
  return g_object_new (CLUTTER_TYPE_CIRCLE,
		       "color", color,
		       NULL);
}

/**
 * clutter_circle_get_color:
 * @circle: a #ClutterCircle
 * @color: return location for a #ClutterColor
 *
 * Retrieves the color of @circle.
 */
void
clutter_circle_get_color (ClutterCircle *circle,
			     ClutterColor     *color)
{
  ClutterCirclePrivate *priv;

  g_return_if_fail (CLUTTER_IS_CIRCLE (circle));
  g_return_if_fail (color != NULL);

  priv = circle->priv;

  color->red = priv->color.red;
  color->green = priv->color.green;
  color->blue = priv->color.blue;
  color->alpha = priv->color.alpha;
}

/**
 * clutter_circle_set_color:
 * @circle: a #ClutterCircle
 * @color: a #ClutterColor
 *
 * Sets the color of @circle.
 */
void
clutter_circle_set_color (ClutterCircle   *circle,
			     const ClutterColor *color)
{
  ClutterCirclePrivate *priv;

  g_return_if_fail (CLUTTER_IS_CIRCLE (circle));
  g_return_if_fail (color != NULL);

  g_object_ref (circle);

  priv = circle->priv;

  priv->color.red = color->red;
  priv->color.green = color->green;
  priv->color.blue = color->blue;
  priv->color.alpha = color->alpha;

#if 0
  /* FIXME - appears to be causing border to always get drawn */
  if (clutter_color_equal (&priv->color, &priv->border_color))
    priv->has_border = FALSE;
  else
    priv->has_border = TRUE;
#endif

  if (CLUTTER_ACTOR_IS_VISIBLE (circle))
    clutter_actor_queue_redraw (CLUTTER_ACTOR (circle));

  g_object_notify (G_OBJECT (circle), "color");
  g_object_unref (circle);
}

#ifndef _HAVE_CLUTTER_CIRCLE_H
#define _HAVE_CLUTTER_CIRCLE_H

#include <glib-object.h>
#include <clutter/clutter-actor.h>
#include <clutter/clutter-color.h>

G_BEGIN_DECLS

#define CLUTTER_TYPE_CIRCLE clutter_circle_get_type()

#define CLUTTER_CIRCLE(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
  CLUTTER_TYPE_CIRCLE, ClutterCircle))

#define CLUTTER_CIRCLE_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST ((klass), \
  CLUTTER_TYPE_CIRCLE, ClutterCircleClass))

#define CLUTTER_IS_CIRCLE(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
  CLUTTER_TYPE_CIRCLE))

#define CLUTTER_IS_CIRCLE_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
  CLUTTER_TYPE_CIRCLE))

#define CLUTTER_CIRCLE_GET_CLASS(obj) \
  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
  CLUTTER_TYPE_CIRCLE, ClutterCircleClass))

typedef struct _ClutterCircle        ClutterCircle;
typedef struct _ClutterCircleClass   ClutterCircleClass;
typedef struct _ClutterCirclePrivate ClutterCirclePrivate;

struct _ClutterCircle
{
  ClutterActor           parent;

  /*< private >*/
  ClutterCirclePrivate *priv;
}; 

struct _ClutterCircleClass 
{
  ClutterActorClass parent_class;

  /* padding for future expansion */
  void (*_clutter_circle1) (void);
  void (*_clutter_circle2) (void);
  void (*_clutter_circle3) (void);
  void (*_clutter_circle4) (void);
};

GType clutter_circle_get_type (void) G_GNUC_CONST;

ClutterActor *clutter_circle_new              (void);
ClutterActor *clutter_circle_new_with_color   (const ClutterColor *color);

void          clutter_circle_get_color        (ClutterCircle   *circle,
                                                  ClutterColor       *color);
void          clutter_circle_set_color        (ClutterCircle   *circle,
						  const ClutterColor *color);
void clutter_circle_set_angle_start (ClutterCircle *circle,
                                guint          angle);
void clutter_circle_set_angle_stop (ClutterCircle *circle,
                                guint          angle);
void clutter_circle_set_width (ClutterCircle *circle,
                                guint          width);
void clutter_circle_set_radius (ClutterCircle *circle,
                                guint          radius);

G_END_DECLS

#endif

Attachment: signature.asc
Description: Digital signature

Reply via email to