ThorwilKnobImageSource: make lamp color themeable
[libprolooks.git] / prolooks / ThorwilKnobImageSource.vala
blobd74b1f465379184f71d578b01bea6db4b903cf39
1 using Gtk;
2 using Cairo;
4 namespace Prolooks {
5 class ThorwilKnobImageSource : DrawingArea, IKnobImageSource {
6 public double knob_width { get; set; }
7 public double knob_height { get; set; }
9 private HSV lamp_hsv;
10 private Gdk.Color _lamp_color;
12 public Gdk.Color lamp_color {
13 get {
14 return _lamp_color;
17 set {
18 _lamp_color = value;
19 lamp_hsv = new HSV.for_gdk_color (value);
23 public double get_knob_width () {
24 return knob_width;
27 public double get_knob_height () {
28 return knob_height;
31 public double get_line_width () {
32 return 0.0;
35 public double get_radius () {
36 return knob_width / 2.0;
39 public string to_string () {
40 return "ThorwilKnobImageSource: Dimens: (%f, %f); radius: %f; lamp-hue: %f".printf (
41 get_knob_width (),
42 get_knob_height (),
43 get_radius (),
44 lamp_hsv.hue);
47 construct {
48 knob_width = 40;
49 knob_height = 40;
50 set_size_request ((int)(phases * knob_width), (int) (knob_height));
51 lamp_color = color_from_string ("#b9feff");
54 public override bool expose_event (Gdk.EventExpose event) {
55 var cr = Gdk.cairo_create (this.window);
56 // Set clipping area in order to avoid unnecessary drawing
57 Gdk.cairo_rectangle (cr, event.area);
58 cr.clip ();
60 cr.set_source_rgba(0.75, 0.75, 0.75, 0);
62 cr.rectangle(0, 0, phases * knob_width, 4 * knob_height);
63 cr.fill();
65 for (int variant = 0; variant < 1; variant++) {
66 // x/y = the middle of the knob
67 var x = get_radius();
68 var y = knob_height * (variant + 0.5);
69 paint_knobs (cr, (KnobMode)variant, x, y);
72 return true;
75 public void paint_knob (Cairo.Context cr, KnobMode knob_mode, int phase, double lwidth, double radius, double x, double y) {
76 var width = 105.0;
77 var height = 105.0;
78 var xc = width / 2.0;
79 var yc = height / 2.0;
81 var start_angle = 0.0;
82 var end_angle = 0.0;
83 var value_angle = 0.0;
85 // Draw out the triangle using absolute coordinates
86 var value = phase * 1.0 / (phases - 1);
88 if (knob_mode != KnobMode.ENDLESS) {
89 start_angle = (180 - 45) * Math.PI / 180;
90 end_angle = (360 + 45) * Math.PI / 180;
91 } else {
92 start_angle = (270) * Math.PI / 180;
93 end_angle = (270 + 360) * Math.PI / 180;
96 value_angle = start_angle + value * (end_angle - start_angle);
98 var value_x = Math.cos(value_angle);
99 var value_y = Math.sin(value_angle);
100 var start_angle_x = Math.cos(start_angle);
101 var start_angle_y = Math.sin(start_angle);
102 var end_angle_x = Math.cos(end_angle);
103 var end_angle_y = Math.sin(end_angle);
105 cr.save ();
106 cr.translate (x, 0);
107 cr.scale (2.0 * radius / width, 2.0 * radius / height);
108 cr.translate (-xc, 0);
110 // KnobRim
111 cr.set_source (create_gradient_str (32, 16, 75, 16, "#d4c8b9", "#ae977b"));
112 cr.set_line_width (2.0);
113 cr.arc (xc, yc, 31.5, 0.0, 2 * Math.PI);
114 cr.stroke ();
116 var progress_width = 20.0;
117 var progress_radius = 40.0;
118 var progress_radius_inner = progress_radius - progress_width / 2.0;
119 var progress_radius_outer = progress_radius + progress_width / 2.0;
120 var knob_disc_radius = progress_radius_inner - 5.0;
122 // ProgressBackground
123 cr.set_source (create_gradient_str (20, 20, 89, 87, "#2f2f4c", "#090a0d"));
124 cr.set_line_width (progress_width);
125 cr.arc (xc, yc, progress_radius, start_angle, end_angle);
126 cr.stroke ();
128 // ProgressLamp
129 lamp_hsv.saturation = 0.27;
130 lamp_hsv.value = 1.0;
131 var lamp_bright = lamp_hsv.to_gdk_color ();
132 lamp_hsv.saturation = 0.66;
133 lamp_hsv.value = 0.67;
134 var lamp_dark = lamp_hsv.to_gdk_color ();
136 cr.set_source (create_gradient (20, 20, 89, 87, lamp_bright, lamp_dark));
137 cr.set_line_width (progress_width);
138 cr.arc (xc, yc, progress_radius, start_angle, value_angle);
139 cr.stroke ();
141 // ProgressShadow
142 // TODO (Performace ?)
144 cr.set_line_cap (LineCap.ROUND);
145 var progress_rim_width = 2.0;
146 cr.set_line_width (progress_rim_width);
148 // ProgressBeginRim
149 cr.set_source (create_gradient_str (18, 79, 35, 79, "#dfd5c9", "#dfd5c9", 1.0, 0.0));
150 cr.move_to (xc + progress_radius_outer * start_angle_x,
151 yc + progress_radius_outer * start_angle_y);
152 cr.line_to (xc + progress_radius_inner * start_angle_x,
153 yc + progress_radius_inner * start_angle_y);
154 cr.stroke ();
156 // ProgressEndRim
157 set_source_color_string (cr, "#b3a190");
158 cr.move_to (xc + progress_radius_outer * end_angle_x,
159 yc + progress_radius_outer * end_angle_y);
160 cr.line_to (xc + progress_radius_inner * end_angle_x,
161 yc + progress_radius_inner * end_angle_y);
162 cr.stroke ();
164 // ProgressRim
165 cr.set_source (create_gradient_str (95, 6, 5, 44, "#dfd5c9", "#b0a090"));
166 cr.arc (xc, yc, progress_radius_outer, start_angle, end_angle);
167 cr.stroke ();
169 cr.set_line_cap (LineCap.BUTT);
171 // ProgressLampReflection
172 // TODO?: blur 2.0
173 cr.set_source (create_gradient (20, 20, 89, 87, lamp_bright, lamp_dark, 0.25, 0.25));
174 cr.set_line_width (progress_width);
175 cr.arc (xc, yc, progress_radius, start_angle, value_angle + Math.PI / 180.0);
176 cr.stroke ();
178 // ProgressBackgroundShine
180 Cairo.Pattern progress_shine = create_gradient_str (89, 73, 34, 16, "#ffffff", "#ffffff", 0.3, 0.04);
181 progress_shine.add_color_stop_rgba (0.5, 1.0, 1.0, 1.0, 0.0);
182 progress_shine.add_color_stop_rgba (0.75, 1.0, 1.0, 1.0, 0.3);
184 cr.set_source (progress_shine);
185 cr.set_line_width (progress_width);
186 cr.arc (xc, yc, progress_radius, start_angle, end_angle);
187 cr.stroke ();
189 // KnobShadow
190 // TODO?: blur 2.0
192 cr.set_line_width (progress_rim_width);
193 cr.set_source (create_gradient_str (86, 77, 38, 25, "#151928", "#151928", 1.0, 0.5));
194 cr.arc (xc, yc, progress_radius_inner, 0, 2 * Math.PI);
195 cr.stroke ();
198 // KnobRimPlain
199 cr.set_line_width (1.0);
200 cr.set_source_rgb (0.0, 0.0, 0.0);
201 cr.arc (xc, yc, progress_radius_inner, 0, 2 * Math.PI);
202 cr.set_source (create_gradient_str (35, 31, 75, 72, "#68625c", "#44494b"));
203 cr.fill ();
204 cr.set_source_rgb (0, 0, 0);
205 cr.arc (xc, yc, progress_radius_inner, 0, 2 * Math.PI);
206 cr.stroke ();
208 // KnobDiscBackground
209 cr.set_source (create_gradient_str (42, 34, 68, 70, "#e7ecef", "#9cafb8"));
210 cr.arc (xc, yc, knob_disc_radius, 0, 2 * Math.PI);
211 cr.fill ();
212 cr.set_line_width (2.0);
214 double degrees = Math.PI / 180.0;
216 // KnobRimShadow
217 // TODO
219 // KnobShineBright
220 cr.set_source (create_gradient_str (38, 34, 70, 68, "#ffffff", "#caddf2", 0.2, 0.2));
221 cr.move_to (xc,yc);
222 cr.arc (xc, yc, knob_disc_radius - 1, -154 * degrees, -120 * degrees);
223 cr.move_to (xc,yc);
224 cr.arc (xc, yc, knob_disc_radius - 1, Math.PI / 2.0 - 60 * degrees, Math.PI / 2.0 - 29 * degrees);
225 cr.fill ();
227 // KnobShineDark
228 cr.set_source (create_gradient_str (50, 40, 62, 60, "#a1adb6", "#47535c", 0.07, 0.15));
229 cr.move_to (xc,yc);
230 cr.arc (xc, yc, knob_disc_radius - 1, - 67 * degrees, - 27 * degrees);
231 cr.move_to (xc,yc);
232 cr.arc (xc, yc, knob_disc_radius - 1, Math.PI - 67 * degrees, Math.PI- 27 * degrees);
233 cr.fill ();
235 // KnobShineRipples
236 Cairo.Pattern knob_ripples = new Cairo.Pattern.radial (xc, yc, 0, xc, yc, 4);
237 add_color_stop_str (knob_ripples, 0.0, "#e7ecef", 0.05);
238 add_color_stop_str (knob_ripples, 0.5, "#58717d", 0.05);
239 add_color_stop_str (knob_ripples, 0.75, "#d1d9de", 0.05);
240 add_color_stop_str (knob_ripples, 1.0, "#5d7682", 0.05);
241 knob_ripples.set_extend(Cairo.Extend.REPEAT);
243 cr.set_line_width (0.0);
244 cr.set_source (knob_ripples);
245 cr.arc (xc, yc, knob_disc_radius, 0, 2 * Math.PI);
246 cr.fill ();
248 cr.save();
250 cr.translate (xc + knob_disc_radius * value_x,
251 yc + knob_disc_radius * value_y);
253 cr.rotate (value_angle - Math.PI);
255 // KnobIndicatorBay
256 cr.set_source (create_gradient_str (16, -2, 9, 13, "#e7ecef", "#9cafb8", 0.8, 0.8));
257 cr.move_to (0, 4);
258 cr.line_to (17, 4);
259 cr.curve_to (19, 4, 21, 2, 21, 0);
260 cr.curve_to (21, -2, 19, -4, 17, -4);
261 cr.line_to (0, -4);
262 cr.close_path();
263 cr.fill();
265 // KnobIndicator
266 cr.set_source (create_gradient_str (9, -2, 9, 2, "#68625c", "#44494b"));
267 cr.move_to (0, 2);
268 cr.line_to (16, 2);
269 cr.curve_to (17, 2, 18, 1, 18, 0);
270 cr.curve_to (18, -1, 17, -2, 16, -2);
271 cr.line_to (0, -2);
272 cr.close_path();
273 cr.fill();
275 cr.restore ();
277 // KnobDiscRim
278 cr.set_line_width (2.0);
279 cr.set_source (create_gradient_str (38, 32, 70, 67, "#3d3d3d", "#000000"));
280 cr.arc (xc, yc, knob_disc_radius, 0, 2 * Math.PI);
281 cr.stroke ();
283 cr.restore ();
286 } // namespace Prolooks