2 Copyright 2009 by Hans Baier
12 public double red
{ get; set; }
13 public double green
{ get; set; }
14 public double blue
{ get; set; }
15 public double alpha
{ get; set; }
17 public Color (double red
= 0.0, double green
= 0.0, double blue
= 0.0, double alpha
= 1.0) {
18 this
.red
= red
; this
.green
= green
; this
.blue
= blue
; this
.alpha
= alpha
;
21 public Cairo
.Color
copy () {
22 return new Cairo
.Color (red
, green
, blue
, alpha
);
25 public Color
.from_string (string webcolor
) {
26 set_from_string(webcolor
);
29 public Cairo
.Color
shade (double shade_factor
) {
30 Prolooks
.HSL hsl
= new Prolooks
.HSL ();
31 hsl
.from_cairo_color (this
);
33 hsl
.lightness
= Math
.fmin (hsl
.lightness
* shade_factor
, 1.0);
34 hsl
.lightness
= Math
.fmax (hsl
.lightness
, 0.0);
36 hsl
.saturation
= Math
.fmin (hsl
.saturation
* shade_factor
, 1.0);
37 hsl
.saturation
= Math
.fmax (hsl
.saturation
, 0.0);
39 return hsl
.to_cairo_color ();
42 public void set_to (Cairo
.Color a_color
) {
44 green
= a_color
.green
;
46 alpha
= a_color
.alpha
;
49 public void set_as_source_in (Cairo
.Context cr
) {
50 cr
.set_source_rgba (red
, green
, blue
, alpha
);
53 public void add_color_stop_to (Cairo
.Pattern p
, double offset
) {
54 p
.add_color_stop_rgba (offset
, red
, green
, blue
, alpha
);
57 public void set_from_string (string webcolor
) {
58 set_to(Prolooks
.gdk_color_to_cairo(Prolooks
.color_from_string(webcolor
)));
65 public enum ButtonState
{
70 public enum ButtonType
{
75 public static void set_line_width_from_device (Cairo
.Context cr
) {
77 cr
.device_to_user (ref ux
, ref uy
);
81 cr
.set_line_width (ux
);
84 public static Gdk
.Color
color_from_string (string webcolor
) {
86 Gdk
.Color
.parse(webcolor
, out color
);
90 public static string color_to_string (Gdk
.Color color
) {
91 var scale
= uint16.MAX
/ uint8.MAX
;
92 return "#%02x%02x%02x".printf (color
.red
/ scale
, color
.green
/ scale
, color
.blue
/ scale
);
95 public static Cairo
.Color
cairo_color_from_string (string webcolor
) {
96 return gdk_color_to_cairo(color_from_string(webcolor
));
99 public static void set_source_color (Cairo
.Context cr
, Gdk
.Color color
, double alpha
= 1.0) {
100 cr
.set_source_rgba((double)color
.red
/ (double)uint16.MAX
, (double)color
.green
/ (double)uint16.MAX
, (double)color
.blue
/ (double)uint16.MAX
, alpha
);
103 public static void gdk_color_to_cairo_color (Gdk
.Color color
, ref double red
, ref double green
, ref double blue
) {
104 red
= (double)color
.red
/ (double)uint16.MAX
;
105 green
= (double)color
.green
/ (double)uint16.MAX
;
106 blue
= (double)color
.blue
/ (double)uint16.MAX
;
109 public static Cairo
.Color
gdk_color_to_cairo (Gdk
.Color color
) {
110 double r
= 0, g
= 0, b
= 0;
111 gdk_color_to_cairo_color (color
, ref r
, ref g
, ref b
);
112 return new Cairo
.Color (r
, g
, b
);
115 public static Gdk
.Color
cairo_color_to_gdk (Cairo
.Color cairo_color
) {
116 Gdk
.Color color
= Gdk
.Color();
118 color
.red
= (uint16) (cairo_color
.red
* (double)uint16.MAX
);
119 color
.green
= (uint16) (cairo_color
.green
* (double)uint16.MAX
);
120 color
.blue
= (uint16) (cairo_color
.blue
* (double)uint16.MAX
);
125 public static void set_source_color_string (Cairo
.Context cr
, string color
, double alpha
= 1.0) {
126 set_source_color (cr
, color_from_string (color
), alpha
);
129 public static void add_color_stop (Cairo
.Pattern p
, double offset
, Gdk
.Color color
, double alpha
= 1.0) {
130 p
.add_color_stop_rgba (offset
, (double)color
.red
/ (double)uint16.MAX
, (double)color
.green
/ (double)uint16.MAX
, (double)color
.blue
/ (double)uint16.MAX
, alpha
);
133 public static void add_color_stop_str (Cairo
.Pattern p
, double offset
, string color
, double alpha
= 1.0) {
134 add_color_stop (p
, offset
, color_from_string (color
), alpha
);
137 public static Cairo
.Pattern
create_gradient (double x1
, double y1
, double x2
, double y2
, Gdk
.Color start
, Gdk
.Color stop
, double alpha_start
= 1.0, double alpha_stop
= 1.0) {
138 Cairo
.Pattern gradient
= new Cairo
.Pattern
.linear(x1
, y1
, x2
, y2
);
139 add_color_stop(gradient
, 0, start
, alpha_start
);
140 add_color_stop(gradient
, 1, stop
, alpha_stop
);
144 public static Cairo
.Pattern
create_gradient_str (double x1
, double y1
, double x2
, double y2
, string start
, string stop
, double alpha_start
= 1.0, double alpha_stop
= 1.0) {
145 return create_gradient (x1
, y1
, x2
, y2
, color_from_string (start
), color_from_string (stop
), alpha_start
, alpha_stop
);
148 public static void rounded_rect (Cairo
.Context cr
, double x
, double y
, double w
, double h
, double radius_x
=5, double radius_y
=5) {
149 // from mono moonlight aka mono silverlight
150 // test limits (without using multiplications)
151 // http://graphics.stanford.edu/courses/cs248-98-fall/Final/q1.html
152 double ARC_TO_BEZIER
= 0.55228475;
154 if (radius_x
> w
- radius_x
)
156 if (radius_y
> h
- radius_y
)
159 // approximate (quite close) the arc using a bezier curve
160 var c1
= ARC_TO_BEZIER
* radius_x
;
161 var c2
= ARC_TO_BEZIER
* radius_y
;
164 cr
.move_to ( x
+ radius_x
, y
);
165 cr
.rel_line_to ( w
- 2 * radius_x
, 0.0);
166 cr
.rel_curve_to ( c1
, 0.0, radius_x
, c2
, radius_x
, radius_y
);
167 cr
.rel_line_to ( 0, h
- 2 * radius_y
);
168 cr
.rel_curve_to ( 0.0, c2
, c1
- radius_x
, radius_y
, -radius_x
, radius_y
);
169 cr
.rel_line_to ( -w
+ 2 * radius_x
, 0);
170 cr
.rel_curve_to ( -c1
, 0, -radius_x
, -c2
, -radius_x
, -radius_y
);
171 cr
.rel_line_to (0, -h
+ 2 * radius_y
);
172 cr
.rel_curve_to (0.0, -c2
, radius_x
- c1
, -radius_y
, radius_x
, -radius_y
);
176 public static void background_gradient(Cairo
.Context cr
, double w
, double h
) {
177 // outside background
178 Color background_gradient_start
;
179 Color background_gradient_stop
;
180 Color
.parse("#bebdc2", out background_gradient_start
);
181 Color
.parse("#b1b4b9", out background_gradient_stop
);
183 cr
.rectangle (0, 0, w
, h
);
184 Cairo
.Pattern background_gradient
= new Cairo
.Pattern
.linear(0, 0, 0, h
);
185 add_color_stop(background_gradient
, 0, background_gradient_start
);
186 add_color_stop(background_gradient
, 1, background_gradient_stop
);
187 cr
.set_source (background_gradient
);
191 public static double modula(double number
, double divisor
) {
192 return (((int)number
% (int)divisor
) + (number
- (int)number
));
196 public double hue
{get; set;}
197 public double saturation
{get; set;}
198 public double lightness
{get; set;}
200 public string to_string() {
201 return "HSL (%f, %f, %f)".printf (hue
, saturation
, lightness
);
204 public Cairo
.Color
to_cairo_color() {
206 var hue_shift
= new
double[3];
207 var color_shift
= new
double[3];
212 if (lightness
<= 0.5)
213 m2
= lightness
* (1 + saturation
);
215 m2
= lightness
+ saturation
- lightness
* saturation
;
217 m1
= 2 * lightness
- m2
;
219 hue_shift
[0] = hue
+ 120;
221 hue_shift
[2] = hue
- 120;
223 color_shift
[0] = color_shift
[1] = color_shift
[2] = lightness
;
225 i
= (saturation
== 0) ?
3 : 0;
232 m3
= modula(m3
, 360);
234 m3
= 360 - modula(Math
.fabs(m3
), 360);
237 color_shift
[i
] = m1
+ (m2
- m1
) * m3
/ 60.0;
241 color_shift
[i
] = m1
+ (m2
- m1
) * (240 - m3
) / 60.0;
246 Cairo
.Color color
= new Cairo
.Color(color_shift
[0], color_shift
[1], color_shift
[2]);
251 public Gdk
.Color
to_gdk_color() {
252 return cairo_color_to_gdk(to_cairo_color());
255 public void from_gdk_color(Gdk
.Color color
) {
256 from_cairo_color(gdk_color_to_cairo(color
));
259 public void from_cairo_color(Cairo
.Color color
) {
260 double min
, max
, delta
;
262 double red
= color
.red
;
263 double green
= color
.green
;
264 double blue
= color
.blue
;
288 lightness
= (max
+ min
) / 2.0;
290 if (Math
.fabs(max
- min
) < 0.0001) {
294 if (lightness
<= 0.5)
295 saturation
= (max
- min
) / (max
+ min
);
297 saturation
= (max
- min
) / (2.0 - max
- min
);
302 hue
= (green
- blue
) / delta
;
303 else if (green
== max
)
304 hue
= 2.0 + (blue
- red
) / delta
;
305 else if (blue
== max
)
306 hue
= 4.0 + (red
- green
) / delta
;
316 public double hue
{get; set;}
317 public double saturation
{get; set;}
318 public double value
{get; set;}
320 public string to_string() {
321 return "HSV (%f, %f, %f)".printf (hue
, saturation
, value
);
324 public HSV
.for_gdk_color (Gdk
.Color color
) {
325 from_gdk_color (color
);
328 public HSV
.for_cairo_color (Cairo
.Color color
) {
329 from_cairo_color (color
);
332 public Cairo
.Color
to_cairo_color() {
333 double r
= 0.0, g
= 0.0, b
= 0.0;
338 hi
= (int) modula(Math
.floor(hue
/ 60.0), 6);
339 f
= hue
/ 60.0 - Math
.floor(hue
/ 60.0);
340 p
= value
* (1.0 - saturation
);
341 q
= value
* (1.0 - f
* saturation
);
342 t
= value
* (1.0 - (1.0 - f
) * saturation
);
345 case 0: r
= value
; g
= t
; b
= p
; break;
346 case 1: r
= q
; g
= value
; b
= p
; break;
347 case 2: r
= p
; g
= value
; b
= t
; break;
348 case 3: r
= p
; g
= q
; b
= value
; break;
349 case 4: r
= t
; g
= p
; b
= value
; break;
350 case 5: r
= value
; g
= p
; b
= q
; break;
354 Cairo
.Color color
= new Cairo
.Color(r
, g
, b
);
359 public Gdk
.Color
to_gdk_color() {
360 return cairo_color_to_gdk(to_cairo_color());
363 public void from_gdk_color(Gdk
.Color color
) {
364 from_cairo_color(gdk_color_to_cairo(color
));
367 public void from_cairo_color(Cairo
.Color color
) {
368 double min
, max
, delta
;
370 double red
= color
.red
;
371 double green
= color
.green
;
372 double blue
= color
.blue
;
398 if (Math
.fabs(max
- min
) < 0.0001)
408 saturation
= (max
- min
) / max
;
413 hue
= (green
- blue
) / delta
;
414 else if (green
== max
)
415 hue
= 2.0 + (blue
- red
) / delta
;
416 else if (blue
== max
)
417 hue
= 4.0 + (red
- green
) / delta
;
426 public static Gdk
.Color
shade_color(Gdk
.Color orig
, double shade_ratio
) {
427 HSL HSL
= new
HSL ();
428 HSL
.from_gdk_color (orig
);
430 HSL
.lightness
= Math
.fmin (HSL
.lightness
* shade_ratio
, 1.0);
431 HSL
.lightness
= Math
.fmax (HSL
.lightness
, 0.0);
433 HSL
.saturation
= Math
.fmin (HSL
.saturation
* shade_ratio
, 1.0);
434 HSL
.saturation
= Math
.fmax (HSL
.saturation
, 0.0);
436 Gdk
.Color result
= HSL
.to_gdk_color ();
441 public static Gdk
.Pixbuf
cairo_image_surface_to_pixbuf (Cairo
.ImageSurface surface
) {
442 if (surface
.get_format() != Cairo
.Format
.ARGB32
)
445 weak uchar[] knob_data
= surface
.get_data ();
447 for (int i
= 0; i
< surface
.get_height() * surface
.get_stride(); i
+= 4) {
448 uchar r
= knob_data
[i
+0];
449 uchar g
= knob_data
[i
+1];
450 uchar b
= knob_data
[i
+2];
451 uchar a
= knob_data
[i
+3];
453 //FIXME: Undo premultiplied alpha here
460 return new Gdk
.Pixbuf
.from_data (knob_data
, Gdk
.Colorspace
.RGB
, true, 8, surface
.get_width(), surface
.get_height(), surface
.get_stride() , null);
463 } // namespace Prolooks