The Big Commit (tm): Remove Cairo.Color and most of Gdk.Color usage from libprolooks
[libprolooks.git] / src / SimpleKnobImageSource.vala
blob432fcbe442a6729b95dbda03cfd077207b0a5e03
1 using Gtk;
2 using Cairo;
4 namespace Prolooks {
5 protected class SimpleKnobImageSource : DrawingArea, IKnobImageSource {
6 public double knob_width { get; set; }
7 public double knob_height { get; set; }
8 public double x { get; set; }
9 public double y { get; set; }
10 public Gdk.RGBA led_color { get; set; }
12 public double get_knob_width () {
13 return knob_width;
16 public double get_knob_height () {
17 return knob_height;
20 public double get_line_width () {
21 return knob_width / 10;
24 public double get_radius () {
25 return knob_width / 2 - get_line_width ();
28 public string to_string () {
29 return "SimpleKnobImageSource: Dimens: (%f, %f); linewidth: %f; radius: %f; led-color: %s".printf (
30 get_knob_width (),
31 get_knob_height (),
32 get_line_width (),
33 get_radius (),
34 led_color.to_string());
37 construct {
38 knob_width = 40;
39 knob_height = 40;
40 x = knob_width / 2;
41 y = knob_height / 2;
42 set_size_request (phases * (int)knob_width, variants * (int)knob_height);
43 led_color = rgba_from_string ("#ff7f00");
44 draw.connect(on_draw);
47 public bool on_draw (Cairo.Context cr) {
48 cr.set_source_rgba(0.75, 0.75, 0.75, 0);
49 cr.rectangle(0, 0, phases * knob_width, 4 * knob_height);
50 cr.fill();
52 for (int variant = 0; variant <= variants; variant++) {
53 // x/y = the middle of the knob
54 var x = knob_width / 2;
55 var y = knob_height * (variant + 0.5);
56 paint_knobs (cr, (KnobMode)variant, x, y);
59 return true;
62 public void paint_knob (Cairo.Context cr, KnobMode knob_mode, int phase, double lwidth, double radius, double x, double y) {
63 var radiusminus2 = radius - lwidth;
64 var radiusminus3 = radius - lwidth * 3 / 2;
65 var value = 0.7;
67 var sangle = 0.0;
68 var eangle = 0.0;
69 var vangle = 0.0;
70 var nleds = 0.0;
72 // Draw out the triangle using absolute coordinates
73 value = phase * 1.0 / (phases - 1);
74 if (knob_mode != KnobMode.ENDLESS) {
75 sangle = (180 - 45) * Math.PI / 180;
76 eangle = (360 + 45) * Math.PI / 180;
77 nleds = 31;
78 } else {
79 sangle = (270) * Math.PI / 180;
80 eangle = (270 + 360) * Math.PI / 180;
81 nleds = 32;
84 vangle = sangle + value * (eangle - sangle);
85 var c = Math.cos(vangle);
86 var s = Math.sin(vangle);
88 var midled = (nleds - 1) / 2;
89 var midphase = (phases - 1) / 2;
90 var thresholdP = midled + 1 + ((phase - midphase - 1) * 1.0 * (nleds - midled - 2) / (phases - midphase - 2));
91 var thresholdN = midled - 1 - ((midphase - 1 - phase) * 1.0 * (nleds - midled - 2) / (midphase - 1));
93 var spacing = Math.PI / nleds;
94 for (var led = 0; led < nleds; led++) {
95 var adelta = 0.0;
97 if (knob_mode == KnobMode.ENDLESS) {
98 adelta = (eangle - sangle) / (nleds);
99 } else {
100 adelta = (eangle - sangle - spacing) / (nleds - 1);
103 var lit = false;
104 var glowlit = false;
105 var glowval = 0.5;
106 var hilite = false;
107 var lvalue = led * 1.0 / (nleds - 1);
108 var pvalue = phase * 1.0 / (phases - 1);
110 if (knob_mode == KnobMode.ENDLESS) {
111 // XXXKF works only for phases = 2 * leds
112 var exled = phase / 2.0;
113 lit = (led == exled) || (phase == (phases - 1) && led == 0);
114 glowlit = led == (exled + 0.5) || led == (exled - 0.5);
115 glowval = 0.8;
116 hilite = (phase % ((phases - 1) / 4)) == 0;
119 if (knob_mode == KnobMode.POSITIVE) {
120 lit = (pvalue == 1.0) || pvalue > lvalue;
123 if (knob_mode == KnobMode.BIPOLAR) {
124 if (led == midled) {
125 lit = (phase == midphase);
126 //glowlit = (phase < midphase && thresholdN >= midled - 1) || (phase > midphase and thresholdP <= midled + 1)
127 glowlit = false;
128 hilite = true;
129 } else if (led > midled && phase > midphase) {
130 // led = [midled + 1, nleds - 1];
131 // phase = [midphase + 1, phases - 1];
132 lit = led <= thresholdP;
133 glowlit = led <= thresholdP + 1;
134 glowval = 0.4;
135 } else if (led < midled && phase < midphase) {
136 lit = led >= thresholdN;
137 glowlit = led >= thresholdN - 1;
138 glowval = 0.4;
139 } else {
140 lit = false;
144 if (knob_mode == KnobMode.NEGATIVE) {
145 lit = pvalue == 0 || pvalue < lvalue;
148 if (!lit) {
149 if (!glowlit) {
150 cr.set_source_rgb(0, 0, 0);
151 } else {
152 Gdk.cairo_set_source_rgba(cr, rgba_shade (led_color, glowval));
154 } else {
155 if (hilite) {
156 cr.set_source_rgb(1, 1, 0);
157 } else {
158 Gdk.cairo_set_source_rgba(cr, led_color);
162 cr.set_line_width(3);
163 cr.arc(x, y, radius, sangle + adelta * led, sangle + adelta * led + spacing);
164 cr.stroke();
167 // knob fill
168 var grad = new Cairo.Pattern.linear(x - radius / 2, y - radius / 2, x + radius / 2, y + radius / 2);
169 grad.add_color_stop_rgb(0.0, 0.5, 0.5, 0.5);
170 grad.add_color_stop_rgb(1.0, 0.8, 0.8, 0.8);
171 cr.set_source(grad);
172 cr.set_line_width(2);
173 cr.arc(x, y, radiusminus2, 0, 2 * Math.PI);
174 cr.fill();
176 // knob fill
177 grad = new Cairo.Pattern.linear(x - radius / 2, y - radius / 2, x + radius / 2, y + radius / 2);
178 grad.add_color_stop_rgb(0.0, 0.8, 0.8, 0.8);
179 grad.add_color_stop_rgb(1.0, 0.5, 0.5, 0.5);
180 cr.set_source(grad);
181 cr.arc(x, y, radiusminus3, 0, 2 * Math.PI);
182 cr.fill();
184 // knob border
185 cr.set_source_rgb(0, 0, 0);
186 cr.set_line_width(2);
187 cr.arc(x, y, radiusminus2, 0, 2 * Math.PI);
188 cr.stroke();
190 // knob line
191 cr.set_source_rgba(0, 0, 0, 0.5);
192 cr.set_line_width(1);
193 var mtx = Matrix (0,0,0,0,0,0);
194 cr.get_matrix(out mtx);
195 cr.translate(x + radiusminus2 * c, y + radiusminus2 * s);
196 cr.rotate(vangle);
197 cr.move_to(0, 0);
198 cr.line_to(-radius/2, 0);
199 cr.stroke();
200 cr.set_matrix(mtx);
202 // knob shine
203 cr.set_source_rgba (1, 1, 1, 0.15);
204 cr.new_path();
205 cr.arc_negative(x, y, radiusminus3, -Math.PI / 6.0, Math.PI);
206 cr.close_path();
207 cr.fill();
210 } // namespace Prolooks