[gimp] app: move GimpDial's background drawing to a new parent class, GimpCircle



commit 98d6f44231ed03f380c62f01cb3553385bb0d02d
Author: Michael Natterer <mitch gimp org>
Date:   Mon May 26 09:23:55 2014 +0200

    app: move GimpDial's background drawing to a new parent class, GimpCircle
    
    so we can use that as a parent class for other circle/wheer interactions
    in other subclasses.

 app/widgets/Makefile.am       |    2 +
 app/widgets/gimpcircle.c      |  450 +++++++++++++++++++++++++++++++++++++++++
 app/widgets/gimpcircle.h      |   58 ++++++
 app/widgets/gimpdial.c        |  329 ++++--------------------------
 app/widgets/gimpdial.h        |    7 +-
 app/widgets/gimppropwidgets.c |    2 +-
 app/widgets/widgets-enums.c   |   58 +++---
 app/widgets/widgets-enums.h   |   22 +-
 app/widgets/widgets-types.h   |    1 +
 9 files changed, 596 insertions(+), 333 deletions(-)
---
diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am
index 83af774..7e45ba2 100644
--- a/app/widgets/Makefile.am
+++ b/app/widgets/Makefile.am
@@ -46,6 +46,8 @@ libappwidgets_a_sources = \
        gimpcellrendererdashes.h        \
        gimpcellrendererviewable.c      \
        gimpcellrendererviewable.h      \
+       gimpcircle.c                    \
+       gimpcircle.h                    \
        gimpchanneltreeview.c           \
        gimpchanneltreeview.h           \
        gimpclipboard.c                 \
diff --git a/app/widgets/gimpcircle.c b/app/widgets/gimpcircle.c
new file mode 100644
index 0000000..1648dfe
--- /dev/null
+++ b/app/widgets/gimpcircle.c
@@ -0,0 +1,450 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpcircle.c
+ * Copyright (C) 2014 Michael Natterer <mitch gimp org>
+ *
+ * Based on code from the color-rotate plug-in
+ * Copyright (C) 1997-1999 Sven Anders (anderss fmi uni-passau de)
+ *                         Based on code from Pavel Grinfeld (pavel ml com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpmath/gimpmath.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "gimpcircle.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_SIZE,
+  PROP_BORDER_WIDTH,
+  PROP_BACKGROUND
+};
+
+
+struct _GimpCirclePrivate
+{
+  gint                  size;
+  gint                  border_width;
+  GimpCircleBackground  background;
+
+  GdkWindow            *event_window;
+  guint                 has_grab : 1;
+};
+
+
+static void        gimp_circle_dispose         (GObject              *object);
+static void        gimp_circle_set_property    (GObject              *object,
+                                                guint                 property_id,
+                                                const GValue         *value,
+                                                GParamSpec           *pspec);
+static void        gimp_circle_get_property    (GObject              *object,
+                                                guint                 property_id,
+                                                GValue               *value,
+                                                GParamSpec           *pspec);
+
+static void        gimp_circle_realize         (GtkWidget            *widget);
+static void        gimp_circle_unrealize       (GtkWidget            *widget);
+static void        gimp_circle_map             (GtkWidget            *widget);
+static void        gimp_circle_unmap           (GtkWidget            *widget);
+static void        gimp_circle_size_request    (GtkWidget            *widget,
+                                                GtkRequisition       *requisition);
+static void        gimp_circle_size_allocate   (GtkWidget            *widget,
+                                                GtkAllocation        *allocation);
+static gboolean    gimp_circle_expose_event    (GtkWidget            *widget,
+                                                GdkEventExpose       *event);
+
+static void        gimp_circle_background_hsv  (gdouble               angle,
+                                                gdouble               distance,
+                                                guchar               *rgb);
+
+static void        gimp_circle_draw_background (cairo_t              *cr,
+                                                gint                  size,
+                                                GimpCircleBackground  background);
+
+
+G_DEFINE_TYPE (GimpCircle, gimp_circle, GTK_TYPE_WIDGET)
+
+#define parent_class gimp_circle_parent_class
+
+
+static void
+gimp_circle_class_init (GimpCircleClass *klass)
+{
+  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose              = gimp_circle_dispose;
+  object_class->get_property         = gimp_circle_get_property;
+  object_class->set_property         = gimp_circle_set_property;
+
+  widget_class->realize              = gimp_circle_realize;
+  widget_class->unrealize            = gimp_circle_unrealize;
+  widget_class->map                  = gimp_circle_map;
+  widget_class->unmap                = gimp_circle_unmap;
+  widget_class->size_request         = gimp_circle_size_request;
+  widget_class->size_allocate        = gimp_circle_size_allocate;
+  widget_class->expose_event         = gimp_circle_expose_event;
+
+  g_object_class_install_property (object_class, PROP_SIZE,
+                                   g_param_spec_int ("size",
+                                                     NULL, NULL,
+                                                     32, 1024, 96,
+                                                     GIMP_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class, PROP_BORDER_WIDTH,
+                                   g_param_spec_int ("border-width",
+                                                     NULL, NULL,
+                                                     0, 64, 0,
+                                                     GIMP_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class, PROP_BACKGROUND,
+                                   g_param_spec_enum ("background",
+                                                      NULL, NULL,
+                                                      GIMP_TYPE_CIRCLE_BACKGROUND,
+                                                      GIMP_CIRCLE_BACKGROUND_HSV,
+                                                      GIMP_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT));
+
+  g_type_class_add_private (klass, sizeof (GimpCirclePrivate));
+}
+
+static void
+gimp_circle_init (GimpCircle *circle)
+{
+  circle->priv = G_TYPE_INSTANCE_GET_PRIVATE (circle,
+                                              GIMP_TYPE_CIRCLE,
+                                              GimpCirclePrivate);
+
+  gtk_widget_set_has_window (GTK_WIDGET (circle), FALSE);
+}
+
+static void
+gimp_circle_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gimp_circle_set_property (GObject      *object,
+                          guint         property_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  GimpCircle *circle = GIMP_CIRCLE (object);
+
+  switch (property_id)
+    {
+    case PROP_SIZE:
+      circle->priv->size = g_value_get_int (value);
+      gtk_widget_queue_resize (GTK_WIDGET (circle));
+      break;
+
+    case PROP_BORDER_WIDTH:
+      circle->priv->border_width = g_value_get_int (value);
+      gtk_widget_queue_resize (GTK_WIDGET (circle));
+      break;
+
+    case PROP_BACKGROUND:
+      circle->priv->background = g_value_get_enum (value);
+      gtk_widget_queue_draw (GTK_WIDGET (circle));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_circle_get_property (GObject    *object,
+                          guint       property_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  GimpCircle *circle = GIMP_CIRCLE (object);
+
+  switch (property_id)
+    {
+    case PROP_SIZE:
+      g_value_set_int (value, circle->priv->size);
+      break;
+
+    case PROP_BORDER_WIDTH:
+      g_value_set_int (value, circle->priv->border_width);
+      break;
+
+    case PROP_BACKGROUND:
+      g_value_set_enum (value, circle->priv->background);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_circle_realize (GtkWidget *widget)
+{
+  GimpCircle    *circle = GIMP_CIRCLE (widget);
+  GtkAllocation  allocation;
+  GdkWindowAttr  attributes;
+  gint           attributes_mask;
+
+  GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x           = allocation.x;
+  attributes.y           = allocation.y;
+  attributes.width       = allocation.width;
+  attributes.height      = allocation.height;
+  attributes.wclass      = GDK_INPUT_ONLY;
+  attributes.event_mask  = gtk_widget_get_events (widget);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  circle->priv->event_window = gdk_window_new (gtk_widget_get_window (widget),
+                                               &attributes, attributes_mask);
+  gdk_window_set_user_data (circle->priv->event_window, circle);
+}
+
+static void
+gimp_circle_unrealize (GtkWidget *widget)
+{
+  GimpCircle *circle = GIMP_CIRCLE (widget);
+
+  if (circle->priv->event_window)
+    {
+      gdk_window_set_user_data (circle->priv->event_window, NULL);
+      gdk_window_destroy (circle->priv->event_window);
+      circle->priv->event_window = NULL;
+    }
+
+  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
+}
+
+static void
+gimp_circle_map (GtkWidget *widget)
+{
+  GimpCircle *circle = GIMP_CIRCLE (widget);
+
+  GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+  if (circle->priv->event_window)
+    gdk_window_show (circle->priv->event_window);
+}
+
+static void
+gimp_circle_unmap (GtkWidget *widget)
+{
+  GimpCircle *circle = GIMP_CIRCLE (widget);
+
+  if (circle->priv->has_grab)
+    {
+      gtk_grab_remove (widget);
+      circle->priv->has_grab = FALSE;
+    }
+
+  if (circle->priv->event_window)
+    gdk_window_hide (circle->priv->event_window);
+
+  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+static void
+gimp_circle_size_request (GtkWidget      *widget,
+                        GtkRequisition *requisition)
+{
+  GimpCircle *circle = GIMP_CIRCLE (widget);
+
+  requisition->width  = 2 * circle->priv->border_width + circle->priv->size;
+  requisition->height = 2 * circle->priv->border_width + circle->priv->size;
+}
+
+static void
+gimp_circle_size_allocate (GtkWidget     *widget,
+                           GtkAllocation *allocation)
+{
+  GimpCircle *circle = GIMP_CIRCLE (widget);
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  if (gtk_widget_get_realized (widget))
+    gdk_window_move_resize (circle->priv->event_window,
+                            allocation->x,
+                            allocation->y,
+                            allocation->width,
+                            allocation->height);
+}
+
+static gboolean
+gimp_circle_expose_event (GtkWidget      *widget,
+                          GdkEventExpose *event)
+{
+  GimpCircle *circle = GIMP_CIRCLE (widget);
+
+  if (gtk_widget_is_drawable (widget))
+    {
+      GtkAllocation  allocation;
+      gint           size = circle->priv->size;
+      cairo_t       *cr;
+
+      cr = gdk_cairo_create (event->window);
+      gdk_cairo_region (cr, event->region);
+      cairo_clip (cr);
+
+      gtk_widget_get_allocation (widget, &allocation);
+
+      cairo_translate (cr,
+                       allocation.x + (allocation.width  - size) / 2,
+                       allocation.y + (allocation.height - size) / 2);
+
+      gimp_circle_draw_background (cr, size, circle->priv->background);
+
+      cairo_destroy (cr);
+    }
+
+  return FALSE;
+}
+
+
+/*  public functions  */
+
+GtkWidget *
+gimp_circle_new (void)
+{
+  return g_object_new (GIMP_TYPE_CIRCLE, NULL);
+}
+
+
+/*  private functions  */
+
+static void
+gimp_circle_background_hsv (gdouble  angle,
+                            gdouble  distance,
+                            guchar  *rgb)
+{
+  gdouble v = 1 - sqrt (distance) / 4; /* it just looks nicer this way */
+
+  gimp_hsv_to_rgb4 (rgb, angle / (2.0 * G_PI), distance, v);
+}
+
+static gdouble
+get_angle_and_distance (gdouble  center_x,
+                        gdouble  center_y,
+                        gdouble  radius,
+                        gdouble  x,
+                        gdouble  y,
+                        gdouble *distance)
+{
+  gdouble angle = atan2 (center_y - y,
+                         x - center_x);
+
+  if (angle < 0)
+    angle += 2 * G_PI;
+
+  if (distance)
+    *distance = sqrt ((SQR (x - center_x) +
+                       SQR (y - center_y)) / SQR (radius));
+
+  return angle;
+}
+
+static void
+gimp_circle_draw_background (cairo_t              *cr,
+                             gint                  size,
+                             GimpCircleBackground  background)
+{
+  cairo_save (cr);
+
+  if (background == GIMP_CIRCLE_BACKGROUND_PLAIN)
+    {
+      cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0 - 1.5, 0.0, 2 * G_PI);
+
+      cairo_set_line_width (cr, 3.0);
+      cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
+      cairo_stroke_preserve (cr);
+
+      cairo_set_line_width (cr, 1.0);
+      cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
+      cairo_stroke (cr);
+    }
+  else
+    {
+      cairo_surface_t *surface;
+      guchar          *data;
+      gint             stride;
+      gint             x, y;
+
+      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size);
+
+      data   = cairo_image_surface_get_data (surface);
+      stride = cairo_image_surface_get_stride (surface);
+
+      for (y = 0; y < size; y++)
+        {
+          for (x = 0; x < size; x++)
+            {
+              gdouble angle;
+              gdouble distance;
+              guchar  rgb[3] = { 0, };
+
+              angle = get_angle_and_distance (size / 2.0, size / 2.0, size / 2.0,
+                                              x, y,
+                                              &distance);
+
+              switch (background)
+                {
+                case GIMP_CIRCLE_BACKGROUND_HSV:
+                  gimp_circle_background_hsv (angle, distance, rgb);
+                  break;
+
+                default:
+                  break;
+                }
+
+              GIMP_CAIRO_ARGB32_SET_PIXEL (data + y * stride + x * 4,
+                                           rgb[0], rgb[1], rgb[2], 255);
+            }
+        }
+
+      cairo_surface_mark_dirty (surface);
+      cairo_set_source_surface (cr, surface, 0.0, 0.0);
+      cairo_surface_destroy (surface);
+
+      cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0, 0.0, 2 * G_PI);
+      cairo_clip (cr);
+
+      cairo_paint (cr);
+    }
+
+  cairo_restore (cr);
+}
diff --git a/app/widgets/gimpcircle.h b/app/widgets/gimpcircle.h
new file mode 100644
index 0000000..e320cf7
--- /dev/null
+++ b/app/widgets/gimpcircle.h
@@ -0,0 +1,58 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpcircle.h
+ * Copyright (C) 2014 Michael Natterer <mitch gimp org>
+ *
+ * Based on code from the color-rotate plug-in
+ * Copyright (C) 1997-1999 Sven Anders (anderss fmi uni-passau de)
+ *                         Based on code from Pavel Grinfeld (pavel ml com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_CIRCLE_H__
+#define __GIMP_CIRCLE_H__
+
+
+#define GIMP_TYPE_CIRCLE            (gimp_circle_get_type ())
+#define GIMP_CIRCLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CIRCLE, GimpCircle))
+#define GIMP_CIRCLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CIRCLE, GimpCircleClass))
+#define GIMP_IS_CIRCLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_CIRCLE))
+#define GIMP_IS_CIRCLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CIRCLE))
+#define GIMP_CIRCLE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CIRCLE, GimpCircleClass))
+
+
+typedef struct _GimpCirclePrivate GimpCirclePrivate;
+typedef struct _GimpCircleClass   GimpCircleClass;
+
+struct _GimpCircle
+{
+  GtkWidget        parent_instance;
+
+  GimpCirclePrivate *priv;
+};
+
+struct _GimpCircleClass
+{
+  GtkWidgetClass  parent_class;
+};
+
+
+GType          gimp_circle_get_type          (void) G_GNUC_CONST;
+
+GtkWidget    * gimp_circle_new               (void);
+
+
+#endif /* __GIMP_CIRCLE_H__ */
diff --git a/app/widgets/gimpdial.c b/app/widgets/gimpdial.c
index 182c296..69197bd 100644
--- a/app/widgets/gimpdial.c
+++ b/app/widgets/gimpdial.c
@@ -44,9 +44,6 @@
 enum
 {
   PROP_0,
-  PROP_SIZE,
-  PROP_BORDER_WIDTH,
-  PROP_BACKGROUND,
   PROP_DRAW_BETA,
   PROP_ALPHA,
   PROP_BETA,
@@ -63,19 +60,14 @@ typedef enum
 
 struct _GimpDialPrivate
 {
-  gint                size;
-  gint                border_width;
-  GimpDialBackground  background;
-  gboolean            draw_beta;
-
-  gdouble             alpha;
-  gdouble             beta;
-  gboolean            clockwise;
-
-  GdkWindow        *event_window;
-  DialTarget        target;
-  gdouble           last_angle;
-  guint             has_grab : 1;
+  gdouble     alpha;
+  gdouble     beta;
+  gboolean    clockwise;
+  gboolean    draw_beta;
+
+  DialTarget  target;
+  gdouble     last_angle;
+  guint       has_grab : 1;
 };
 
 
@@ -89,14 +81,6 @@ static void        gimp_dial_get_property         (GObject            *object,
                                                    GValue             *value,
                                                    GParamSpec         *pspec);
 
-static void        gimp_dial_realize              (GtkWidget          *widget);
-static void        gimp_dial_unrealize            (GtkWidget          *widget);
-static void        gimp_dial_map                  (GtkWidget          *widget);
-static void        gimp_dial_unmap                (GtkWidget          *widget);
-static void        gimp_dial_size_request         (GtkWidget          *widget,
-                                                   GtkRequisition     *requisition);
-static void        gimp_dial_size_allocate        (GtkWidget          *widget,
-                                                   GtkAllocation      *allocation);
 static gboolean    gimp_dial_expose_event         (GtkWidget          *widget,
                                                    GdkEventExpose     *event);
 static gboolean    gimp_dial_button_press_event   (GtkWidget          *widget,
@@ -106,13 +90,6 @@ static gboolean    gimp_dial_button_release_event (GtkWidget          *widget,
 static gboolean    gimp_dial_motion_notify_event  (GtkWidget          *widget,
                                                    GdkEventMotion     *mevent);
 
-static void        gimp_dial_background_hsv       (gdouble             angle,
-                                                   gdouble             distance,
-                                                   guchar             *rgb);
-
-static void        gimp_dial_draw_background      (cairo_t            *cr,
-                                                   gint                size,
-                                                   GimpDialBackground  background);
 static void        gimp_dial_draw_arrows          (cairo_t            *cr,
                                                    gint                size,
                                                    gdouble             alpha,
@@ -121,7 +98,7 @@ static void        gimp_dial_draw_arrows          (cairo_t            *cr,
                                                    gboolean            draw_beta);
 
 
-G_DEFINE_TYPE (GimpDial, gimp_dial, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE (GimpDial, gimp_dial, GIMP_TYPE_CIRCLE)
 
 #define parent_class gimp_dial_parent_class
 
@@ -136,46 +113,11 @@ gimp_dial_class_init (GimpDialClass *klass)
   object_class->get_property         = gimp_dial_get_property;
   object_class->set_property         = gimp_dial_set_property;
 
-  widget_class->realize              = gimp_dial_realize;
-  widget_class->unrealize            = gimp_dial_unrealize;
-  widget_class->map                  = gimp_dial_map;
-  widget_class->unmap                = gimp_dial_unmap;
-  widget_class->size_request         = gimp_dial_size_request;
-  widget_class->size_allocate        = gimp_dial_size_allocate;
   widget_class->expose_event         = gimp_dial_expose_event;
   widget_class->button_press_event   = gimp_dial_button_press_event;
   widget_class->button_release_event = gimp_dial_button_release_event;
   widget_class->motion_notify_event  = gimp_dial_motion_notify_event;
 
-  g_object_class_install_property (object_class, PROP_SIZE,
-                                   g_param_spec_int ("size",
-                                                     NULL, NULL,
-                                                     32, 1024, 96,
-                                                     GIMP_PARAM_READWRITE |
-                                                     G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (object_class, PROP_BORDER_WIDTH,
-                                   g_param_spec_int ("border-width",
-                                                     NULL, NULL,
-                                                     0, 64, 0,
-                                                     GIMP_PARAM_READWRITE |
-                                                     G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (object_class, PROP_BACKGROUND,
-                                   g_param_spec_enum ("background",
-                                                      NULL, NULL,
-                                                      GIMP_TYPE_DIAL_BACKGROUND,
-                                                      GIMP_DIAL_BACKGROUND_HSV,
-                                                      GIMP_PARAM_READWRITE |
-                                                      G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (object_class, PROP_DRAW_BETA,
-                                   g_param_spec_boolean ("draw-beta",
-                                                         NULL, NULL,
-                                                         TRUE,
-                                                         GIMP_PARAM_READWRITE |
-                                                         G_PARAM_CONSTRUCT));
-
   g_object_class_install_property (object_class, PROP_ALPHA,
                                    g_param_spec_double ("alpha",
                                                         NULL, NULL,
@@ -197,6 +139,13 @@ gimp_dial_class_init (GimpDialClass *klass)
                                                          GIMP_PARAM_READWRITE |
                                                          G_PARAM_CONSTRUCT));
 
+  g_object_class_install_property (object_class, PROP_DRAW_BETA,
+                                   g_param_spec_boolean ("draw-beta",
+                                                         NULL, NULL,
+                                                         TRUE,
+                                                         GIMP_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT));
+
   g_type_class_add_private (klass, sizeof (GimpDialPrivate));
 }
 
@@ -207,7 +156,6 @@ gimp_dial_init (GimpDial *dial)
                                             GIMP_TYPE_DIAL,
                                             GimpDialPrivate);
 
-  gtk_widget_set_has_window (GTK_WIDGET (dial), FALSE);
   gtk_widget_add_events (GTK_WIDGET (dial),
                          GDK_BUTTON_PRESS_MASK   |
                          GDK_BUTTON_RELEASE_MASK |
@@ -230,26 +178,6 @@ gimp_dial_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case PROP_SIZE:
-      dial->priv->size = g_value_get_int (value);
-      gtk_widget_queue_resize (GTK_WIDGET (dial));
-      break;
-
-    case PROP_BORDER_WIDTH:
-      dial->priv->border_width = g_value_get_int (value);
-      gtk_widget_queue_resize (GTK_WIDGET (dial));
-      break;
-
-    case PROP_BACKGROUND:
-      dial->priv->background = g_value_get_enum (value);
-      gtk_widget_queue_draw (GTK_WIDGET (dial));
-      break;
-
-    case PROP_DRAW_BETA:
-      dial->priv->draw_beta = g_value_get_boolean (value);
-      gtk_widget_queue_draw (GTK_WIDGET (dial));
-      break;
-
     case PROP_ALPHA:
       dial->priv->alpha = g_value_get_double (value);
       gtk_widget_queue_draw (GTK_WIDGET (dial));
@@ -265,6 +193,11 @@ gimp_dial_set_property (GObject      *object,
       gtk_widget_queue_draw (GTK_WIDGET (dial));
       break;
 
+    case PROP_DRAW_BETA:
+      dial->priv->draw_beta = g_value_get_boolean (value);
+      gtk_widget_queue_draw (GTK_WIDGET (dial));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -281,22 +214,6 @@ gimp_dial_get_property (GObject    *object,
 
   switch (property_id)
     {
-    case PROP_SIZE:
-      g_value_set_int (value, dial->priv->size);
-      break;
-
-    case PROP_BORDER_WIDTH:
-      g_value_set_int (value, dial->priv->border_width);
-      break;
-
-    case PROP_BACKGROUND:
-      g_value_set_enum (value, dial->priv->background);
-      break;
-
-    case PROP_DRAW_BETA:
-      g_value_set_boolean (value, dial->priv->draw_beta);
-      break;
-
     case PROP_ALPHA:
       g_value_set_double (value, dial->priv->alpha);
       break;
@@ -309,136 +226,45 @@ gimp_dial_get_property (GObject    *object,
       g_value_set_boolean (value, dial->priv->clockwise);
       break;
 
+    case PROP_DRAW_BETA:
+      g_value_set_boolean (value, dial->priv->draw_beta);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
     }
 }
 
-static void
-gimp_dial_realize (GtkWidget *widget)
-{
-  GimpDial      *dial = GIMP_DIAL (widget);
-  GtkAllocation  allocation;
-  GdkWindowAttr  attributes;
-  gint           attributes_mask;
-
-  GTK_WIDGET_CLASS (parent_class)->realize (widget);
-
-  gtk_widget_get_allocation (widget, &allocation);
-
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x           = allocation.x;
-  attributes.y           = allocation.y;
-  attributes.width       = allocation.width;
-  attributes.height      = allocation.height;
-  attributes.wclass      = GDK_INPUT_ONLY;
-  attributes.event_mask  = gtk_widget_get_events (widget);
-
-  attributes_mask = GDK_WA_X | GDK_WA_Y;
-
-  dial->priv->event_window = gdk_window_new (gtk_widget_get_window (widget),
-                                             &attributes, attributes_mask);
-  gdk_window_set_user_data (dial->priv->event_window, dial);
-}
-
-static void
-gimp_dial_unrealize (GtkWidget *widget)
-{
-  GimpDial *dial = GIMP_DIAL (widget);
-
-  if (dial->priv->event_window)
-    {
-      gdk_window_set_user_data (dial->priv->event_window, NULL);
-      gdk_window_destroy (dial->priv->event_window);
-      dial->priv->event_window = NULL;
-    }
-
-  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
-}
-
-static void
-gimp_dial_map (GtkWidget *widget)
-{
-  GimpDial *dial = GIMP_DIAL (widget);
-
-  GTK_WIDGET_CLASS (parent_class)->map (widget);
-
-  if (dial->priv->event_window)
-    gdk_window_show (dial->priv->event_window);
-}
-
-static void
-gimp_dial_unmap (GtkWidget *widget)
-{
-  GimpDial *dial = GIMP_DIAL (widget);
-
-  if (dial->priv->has_grab)
-    {
-      gtk_grab_remove (widget);
-      dial->priv->has_grab = FALSE;
-    }
-
-  if (dial->priv->event_window)
-    gdk_window_hide (dial->priv->event_window);
-
-  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
-}
-
-static void
-gimp_dial_size_request (GtkWidget      *widget,
-                        GtkRequisition *requisition)
-{
-  GimpDial *dial = GIMP_DIAL (widget);
-
-  requisition->width  = 2 * dial->priv->border_width + dial->priv->size;
-  requisition->height = 2 * dial->priv->border_width + dial->priv->size;
-}
-
-static void
-gimp_dial_size_allocate (GtkWidget     *widget,
-                         GtkAllocation *allocation)
-{
-  GimpDial *dial = GIMP_DIAL (widget);
-
-  gtk_widget_set_allocation (widget, allocation);
-
-  if (gtk_widget_get_realized (widget))
-    gdk_window_move_resize (dial->priv->event_window,
-                            allocation->x,
-                            allocation->y,
-                            allocation->width,
-                            allocation->height);
-}
-
 static gboolean
 gimp_dial_expose_event (GtkWidget      *widget,
                         GdkEventExpose *event)
 {
   GimpDial *dial = GIMP_DIAL (widget);
 
+  GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+
   if (gtk_widget_is_drawable (widget))
     {
       GtkAllocation  allocation;
-      gint           size         = dial->priv->size;
-      gint           border_width = dial->priv->border_width;
+      gint           size;
       cairo_t       *cr;
       gint           x, y;
 
+      g_object_get (widget,
+                    "size", &size,
+                    NULL);
+
       cr = gdk_cairo_create (event->window);
       gdk_cairo_region (cr, event->region);
       cairo_clip (cr);
 
       gtk_widget_get_allocation (widget, &allocation);
 
-      x = (allocation.width  - 2 * border_width - size) / 2;
-      y = (allocation.height - 2 * border_width - size) / 2;
-
       cairo_translate (cr,
-                       allocation.x + border_width + x,
-                       allocation.y + border_width + y);
+                       allocation.x + (allocation.width  - size) / 2,
+                       allocation.y + (allocation.height - size) / 2);
 
-      gimp_dial_draw_background (cr, size, dial->priv->background);
       gimp_dial_draw_arrows (cr, size,
                              dial->priv->alpha, dial->priv->beta,
                              dial->priv->clockwise,
@@ -500,12 +326,16 @@ gimp_dial_button_press_event (GtkWidget      *widget,
       bevent->button == 1)
     {
       GtkAllocation allocation;
-      gint          size = dial->priv->size;
+      gint          size;
       gdouble       center_x;
       gdouble       center_y;
       gdouble       angle;
       gdouble       distance;
 
+      g_object_get (widget,
+                    "size", &size,
+                    NULL);
+
       gtk_grab_add (widget);
       dial->priv->has_grab = TRUE;
 
@@ -627,87 +457,6 @@ gimp_dial_new (void)
 /*  private functions  */
 
 static void
-gimp_dial_background_hsv (gdouble  angle,
-                          gdouble  distance,
-                          guchar  *rgb)
-{
-  gdouble v = 1 - sqrt (distance) / 4; /* it just looks nicer this way */
-
-  gimp_hsv_to_rgb4 (rgb, angle / (2.0 * G_PI), distance, v);
-}
-
-static void
-gimp_dial_draw_background (cairo_t            *cr,
-                           gint                size,
-                           GimpDialBackground  background)
-{
-  cairo_save (cr);
-
-  if (background == GIMP_DIAL_BACKGROUND_PLAIN)
-    {
-      cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0 - 1.5, 0.0, 2 * G_PI);
-
-      cairo_set_line_width (cr, 3.0);
-      cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
-      cairo_stroke_preserve (cr);
-
-      cairo_set_line_width (cr, 1.0);
-      cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
-      cairo_stroke (cr);
-    }
-  else
-    {
-      cairo_surface_t *surface;
-      guchar          *data;
-      gint             stride;
-      gint             x, y;
-
-      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size);
-
-      data   = cairo_image_surface_get_data (surface);
-      stride = cairo_image_surface_get_stride (surface);
-
-      for (y = 0; y < size; y++)
-        {
-          for (x = 0; x < size; x++)
-            {
-              gdouble angle;
-              gdouble distance;
-              guchar  rgb[3] = { 0, };
-
-              angle = get_angle_and_distance (size / 2.0, size / 2.0, size / 2.0,
-                                              x, y,
-                                              &distance);
-
-              switch (background)
-                {
-                case GIMP_DIAL_BACKGROUND_HSV:
-                  gimp_dial_background_hsv (angle, distance, rgb);
-                  break;
-
-                default:
-                  break;
-                }
-
-              GIMP_CAIRO_ARGB32_SET_PIXEL (data + y * stride + x * 4,
-                                           rgb[0], rgb[1], rgb[2], 255);
-            }
-        }
-
-      cairo_surface_mark_dirty (surface);
-      cairo_set_source_surface (cr, surface, 0.0, 0.0);
-      cairo_surface_destroy (surface);
-
-      cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0, 0.0, 2 * G_PI);
-      cairo_clip (cr);
-
-      cairo_paint (cr);
-    }
-
-  cairo_restore (cr);
-}
-
-static void
 gimp_dial_draw_arrows (cairo_t  *cr,
                        gint      size,
                        gdouble   alpha,
diff --git a/app/widgets/gimpdial.h b/app/widgets/gimpdial.h
index c32066a..2192482 100644
--- a/app/widgets/gimpdial.h
+++ b/app/widgets/gimpdial.h
@@ -26,6 +26,9 @@
 #define __GIMP_DIAL_H__
 
 
+#include "gimpcircle.h"
+
+
 #define GIMP_TYPE_DIAL            (gimp_dial_get_type ())
 #define GIMP_DIAL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_DIAL, GimpDial))
 #define GIMP_DIAL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_DIAL, GimpDialClass))
@@ -39,14 +42,14 @@ typedef struct _GimpDialClass   GimpDialClass;
 
 struct _GimpDial
 {
-  GtkWidget        parent_instance;
+  GimpCircle       parent_instance;
 
   GimpDialPrivate *priv;
 };
 
 struct _GimpDialClass
 {
-  GtkWidgetClass  parent_class;
+  GimpCircleClass  parent_class;
 };
 
 
diff --git a/app/widgets/gimppropwidgets.c b/app/widgets/gimppropwidgets.c
index d877933..d6638fc 100644
--- a/app/widgets/gimppropwidgets.c
+++ b/app/widgets/gimppropwidgets.c
@@ -810,8 +810,8 @@ gimp_prop_angle_dial_new (GObject     *config,
   g_object_set (dial,
                 "size",         32,
                 "border-width", 0,
+                "background",   GIMP_CIRCLE_BACKGROUND_PLAIN,
                 "draw-beta",    FALSE,
-                "background",   GIMP_DIAL_BACKGROUND_PLAIN,
                 NULL);
 
   set_param_spec (G_OBJECT (dial), dial, param_spec);
diff --git a/app/widgets/widgets-enums.c b/app/widgets/widgets-enums.c
index 368da01..1f882e0 100644
--- a/app/widgets/widgets-enums.c
+++ b/app/widgets/widgets-enums.c
@@ -38,6 +38,35 @@ gimp_active_color_get_type (void)
 }
 
 GType
+gimp_circle_background_get_type (void)
+{
+  static const GEnumValue values[] =
+  {
+    { GIMP_CIRCLE_BACKGROUND_PLAIN, "GIMP_CIRCLE_BACKGROUND_PLAIN", "plain" },
+    { GIMP_CIRCLE_BACKGROUND_HSV, "GIMP_CIRCLE_BACKGROUND_HSV", "hsv" },
+    { 0, NULL, NULL }
+  };
+
+  static const GimpEnumDesc descs[] =
+  {
+    { GIMP_CIRCLE_BACKGROUND_PLAIN, NC_("circle-background", "Plain"), NULL },
+    { GIMP_CIRCLE_BACKGROUND_HSV, NC_("circle-background", "HSV"), NULL },
+    { 0, NULL, NULL }
+  };
+
+  static GType type = 0;
+
+  if (G_UNLIKELY (! type))
+    {
+      type = g_enum_register_static ("GimpCircleBackground", values);
+      gimp_type_set_translation_context (type, "circle-background");
+      gimp_enum_set_value_descriptions (type, descs);
+    }
+
+  return type;
+}
+
+GType
 gimp_color_dialog_state_get_type (void)
 {
   static const GEnumValue values[] =
@@ -164,35 +193,6 @@ gimp_color_pick_state_get_type (void)
 }
 
 GType
-gimp_dial_background_get_type (void)
-{
-  static const GEnumValue values[] =
-  {
-    { GIMP_DIAL_BACKGROUND_PLAIN, "GIMP_DIAL_BACKGROUND_PLAIN", "plain" },
-    { GIMP_DIAL_BACKGROUND_HSV, "GIMP_DIAL_BACKGROUND_HSV", "hsv" },
-    { 0, NULL, NULL }
-  };
-
-  static const GimpEnumDesc descs[] =
-  {
-    { GIMP_DIAL_BACKGROUND_PLAIN, NC_("dial-background", "Plain"), NULL },
-    { GIMP_DIAL_BACKGROUND_HSV, NC_("dial-background", "HSV"), NULL },
-    { 0, NULL, NULL }
-  };
-
-  static GType type = 0;
-
-  if (G_UNLIKELY (! type))
-    {
-      type = g_enum_register_static ("GimpDialBackground", values);
-      gimp_type_set_translation_context (type, "dial-background");
-      gimp_enum_set_value_descriptions (type, descs);
-    }
-
-  return type;
-}
-
-GType
 gimp_histogram_scale_get_type (void)
 {
   static const GEnumValue values[] =
diff --git a/app/widgets/widgets-enums.h b/app/widgets/widgets-enums.h
index 3286b39..f3c6ebd 100644
--- a/app/widgets/widgets-enums.h
+++ b/app/widgets/widgets-enums.h
@@ -34,6 +34,17 @@ typedef enum
 } GimpActiveColor;
 
 
+#define GIMP_TYPE_CIRCLE_BACKGROUND (gimp_circle_background_get_type ())
+
+GType gimp_circle_background_get_type (void) G_GNUC_CONST;
+
+typedef enum
+{
+  GIMP_CIRCLE_BACKGROUND_PLAIN, /*< desc="Plain" >*/
+  GIMP_CIRCLE_BACKGROUND_HSV    /*< desc="HSV"   >*/
+} GimpCircleBackground;
+
+
 #define GIMP_TYPE_COLOR_DIALOG_STATE (gimp_color_dialog_state_get_type ())
 
 GType gimp_color_dialog_state_get_type (void) G_GNUC_CONST;
@@ -83,17 +94,6 @@ typedef enum
 } GimpColorPickState;
 
 
-#define GIMP_TYPE_DIAL_BACKGROUND (gimp_dial_background_get_type ())
-
-GType gimp_dial_background_get_type (void) G_GNUC_CONST;
-
-typedef enum
-{
-  GIMP_DIAL_BACKGROUND_PLAIN, /*< desc="Plain" >*/
-  GIMP_DIAL_BACKGROUND_HSV    /*< desc="HSV"   >*/
-} GimpDialBackground;
-
-
 #define GIMP_TYPE_HISTOGRAM_SCALE (gimp_histogram_scale_get_type ())
 
 GType gimp_histogram_scale_get_type (void) G_GNUC_CONST;
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index 42f1f72..6651b88 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -156,6 +156,7 @@ typedef struct _GimpPdbDialog                GimpPdbDialog;
 typedef struct _GimpActionEditor             GimpActionEditor;
 typedef struct _GimpActionView               GimpActionView;
 typedef struct _GimpBlobEditor               GimpBlobEditor;
+typedef struct _GimpCircle                   GimpCircle;
 typedef struct _GimpColorBar                 GimpColorBar;
 typedef struct _GimpColorDisplayEditor       GimpColorDisplayEditor;
 typedef struct _GimpColorFrame               GimpColorFrame;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]