/* This file is part of Cinaest. * * Copyright (C) 2010 Philipp Zabel * * Cinaest 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. * * Cinaest 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 Cinaest. If not, see . */ using Gtk; public class RatingWidget : DrawingArea { 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)) Gdk.Color.parse ("white", out active_color); if (!style.lookup_color ("DisabledTextColor", out disabled_color)) Gdk.Color.parse ("black", out disabled_color); add_events (Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK); set_size_request (640, 70); } 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 (); 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, double radius, Gdk.Color color) { var x = radius * (2 * n + 1); var y = this.allocation.height / 2; cr.set_source_rgb (color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0); cr.new_path (); for (int i = 0; i <= 10; i++) { double r = radius * (5 + 8 * (i % 2)) / 13.0; double a = x + r * Math.cos (i * 2*Math.PI/10.0 + Math.PI/2.0); double b = y + r * Math.sin (i * 2*Math.PI/10.0 + Math.PI/2.0); if (i == 0) cr.move_to (a, b); else cr.line_to (a, b); } cr.close_path (); cr.fill_preserve (); } public override bool button_press_event (Gdk.EventButton event) { button_pressed = true; rate (event.x); return false; } public override bool button_release_event (Gdk.EventButton event) { button_pressed = false; return false; } public override bool motion_notify_event (Gdk.EventMotion event) { if (button_pressed) rate (event.x); return false; } 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; } }