Rating widget: turn rating into a property
[cinaest] / src / rating-widget.vala
index 70b27f4..cafb73a 100644 (file)
 using Gtk;
 
 public class RatingWidget : DrawingArea {
-       private int rating;
+       private int _rating;
        private bool button_pressed;
        private Gdk.Color active_color;
        private Gdk.Color disabled_color;
 
+       public int rating {
+               get {
+                       return _rating;
+               }
+               set {
+                       if (_rating == value)
+                               return;
+
+                       _rating = value;
+
+                       unowned Gdk.Region region = this.window.get_clip_region ();
+                       // redraw the cairo canvas completely by exposing it
+                       this.window.invalidate_region (region, true);
+                       this.window.process_updates (true);
+               }
+       }
+
        public RatingWidget () {
                var style = Gtk.rc_get_style_by_paths (this.get_settings (), "GtkButton", null, typeof (Gtk.Button));
                if (!style.lookup_color ("ActiveTextColor", out active_color))
@@ -40,19 +57,28 @@ public class RatingWidget : DrawingArea {
 
        public override bool expose_event (Gdk.EventExpose event) {
                var cr = Gdk.cairo_create (this.window);
+               var radius = double.min (this.allocation.width / 20,
+                                        this.allocation.height / 2);
                cr.rectangle (event.area.x, event.area.y, event.area.width, event.area.height);
                cr.clip ();
 
-               for (int i = 0; i < 10; i++) {
-                       draw_star (cr, i, (i >= rating) ? disabled_color : active_color);
-               }
+               cr.save ();
+               cr.rectangle (radius * rating / 5.0, 0, this.allocation.width - radius * rating / 5.0, this.allocation.height);
+               cr.clip ();
+               for (int i = rating/10; i < 10; i++)
+                       draw_star (cr, i, radius, disabled_color);
+               cr.restore ();
+
+               cr.new_path ();
+               cr.rectangle (0, 0, radius * rating / 5.0, this.allocation.height);
+               cr.clip ();
+               for (int i = 0; i < (rating+5)/10; i++)
+                       draw_star (cr, i, radius, active_color);
 
                return false;
        }
 
-       private void draw_star (Cairo.Context cr, int n, Gdk.Color color) {
-               var radius = double.min (this.allocation.width / 20,
-                                        this.allocation.height / 2);
+       private void draw_star (Cairo.Context cr, int n, double radius, Gdk.Color color) {
                var x = radius * (2 * n + 1);
                var y = this.allocation.height / 2;
 
@@ -73,7 +99,7 @@ public class RatingWidget : DrawingArea {
 
        public override bool button_press_event (Gdk.EventButton event) {
                button_pressed = true;
-               rate (10 * event.x / this.allocation.width);
+               rate (event.x);
 
                return false;
        }
@@ -86,26 +112,26 @@ public class RatingWidget : DrawingArea {
 
        public override bool motion_notify_event (Gdk.EventMotion event) {
                if (button_pressed)
-                       rate (10 * event.x / this.allocation.width);
+                       rate (event.x);
 
                return false;
        }
 
-       private void rate (double r) {
-               if (r <= 0)
-                       rating = 0;
-               else
-                       rating = (int) r + 1;
-               if (rating > 10)
-                       rating = 10;
-
-               unowned Gdk.Region region = this.window.get_clip_region ();
-               // redraw the cairo canvas completely by exposing it
-               this.window.invalidate_region (region, true);
-               this.window.process_updates (true);
-       }
-
-       public int get_rating () {
-               return rating;
+       private void rate (double x) {
+               int r;
+
+               x = 10 * x / this.allocation.width;
+               if (x <= 0) {
+                       r = 0;
+               } else {
+                       int star = (int) x;
+                       r = 10 * (star + 1);
+                       x -= star;
+                       if (x <= 0.333)
+                               r -= 5;
+                       if (r > 100)
+                               r = 100;
+               }
+               rating = r;
        }
 }