KnobImageSource: add get_state_hash()
[libprolooks.git] / prolooks / TransportButton.vala
blob0d6566ee40557d9590d3d6f0d966e1e8888c9373
1 /*
2 Copyright 2009 by Hans Baier
3 License: LGPLv2+
4 */
6 using Gtk;
7 using Gdk;
9 namespace Prolooks {
11 public class TransportButton : ButtonBase {
13 public enum IconType {
14 STOP,
15 PLAY,
16 REC,
17 FAST_FORWARD,
18 FAST_BACKWARD,
19 TO_END,
20 TO_START
23 private IconType _icon_type;
24 [Description(nick="icon type", blurb="determines, which icon the button will display, also determines whether it works like a press or toggle button: REC and PLAY work as toggle buttons, all others als press buttons")]
25 public IconType icon_type {
26 get {
27 return _icon_type;
29 set {
30 if (value != _icon_type) {
31 switch (value) {
32 case IconType.REC:
33 case IconType.PLAY: button_type = ButtonType.TOGGLE_BUTTON; break;
34 case IconType.STOP:
35 case IconType.FAST_FORWARD:
36 case IconType.FAST_BACKWARD:
37 case IconType.TO_END:
38 case IconType.TO_START: button_type = ButtonType.PRESS_BUTTON; break;
39 default: GLib.assert_not_reached (); break;
41 _icon_type = value;
42 queue_draw ();
47 public static void icon_size (IconType type, out int width, out int height) {
48 switch (type) {
49 case IconType.STOP: width = 12; height = 11; break;
50 case IconType.REC: width = 13; height = 13; break;
51 case IconType.PLAY: width = 10; height = 17; break;
52 case IconType.FAST_FORWARD:
53 case IconType.FAST_BACKWARD: width = 11; height = 12; break;
54 case IconType.TO_END:
55 case IconType.TO_START: width = 10; height = 12; break;
56 default: GLib.assert_not_reached (); break;
60 construct {
61 add_events (Gdk.EventMask.BUTTON_PRESS_MASK
62 | Gdk.EventMask.BUTTON_RELEASE_MASK);
64 icon_type = IconType.PLAY;
65 set_size_request (30, 30);
68 public static void paint_stop_icon (Cairo.Context cr) {
69 Color stop_icon_color_center = shade_color(color_from_string ("#184b6a"), 1.4);
70 Color stop_icon_color_outside = shade_color(color_from_string ("#050f2a"), 1.4);
72 Cairo.Pattern pt = new Cairo.Pattern.radial (4.5, 4.5, 0, 4.5, 4.5, 3);
73 add_color_stop (pt, 0, stop_icon_color_center);
74 add_color_stop (pt, 1.0, stop_icon_color_outside);
75 cr.set_source (pt);
77 cr.rectangle (0.5, 0, 8, 8);
78 cr.fill ();
81 public static void paint_play_icon (Cairo.Context cr) {
82 Color play_icon_color_middle = color_from_string ("#4b9a0d");
83 Color play_icon_color_outside = color_from_string ("#2e4f18");
85 Cairo.Pattern pt = new Cairo.Pattern.radial (3.5, 7.5, 3, 3.5, 7.5, 10);
86 add_color_stop(pt, 0, play_icon_color_middle);
87 add_color_stop(pt, 1, play_icon_color_outside);
88 cr.set_source (pt);
90 cr.new_path();
91 cr.move_to (0.5, 0.5);
92 cr.line_to (7.5, 7.0);
93 cr.line_to (0.5, 13.5);
94 cr.close_path ();
95 cr.fill ();
99 public static void paint_rec_icon (Cairo.Context cr) {
100 Color rec_icon_color_middle = shade_color(color_from_string ("#8b2f20"), 1.4);
101 Color rec_icon_color_outside = shade_color(color_from_string ("#47090a"), 1.4);
103 Cairo.Pattern pt = new Cairo.Pattern.radial (5.0, 5.0, 0, 5.0, 5.0, 10);
104 add_color_stop(pt, 0, rec_icon_color_middle);
105 add_color_stop(pt, 1, rec_icon_color_outside);
106 cr.set_source (pt);
108 cr.arc (5.0, 5.0, 5.0, 0, 2.0 * Math.PI);
109 cr.fill ();
112 public static Color ff_icons_color = color_from_string ("#212121");
114 public static void paint_fast_forward_icon (Cairo.Context cr) {
115 set_source_color (cr, ff_icons_color);
117 cr.save ();
118 cr.translate (-1.0, -1.0);
119 cr.new_path();
120 cr.move_to (0, 0);
121 cr.line_to (5.5, 5.5);
122 cr.line_to (0, 11);
123 cr.close_path ();
124 cr.fill ();
126 cr.translate (5, 0);
127 cr.new_path();
128 cr.move_to (0, 0);
129 cr.line_to (5.5, 5.5);
130 cr.line_to (0, 11);
131 cr.close_path ();
132 cr.fill ();
133 cr.restore ();
136 public static void paint_fast_to_end_icon (Cairo.Context cr) {
137 set_source_color (cr, ff_icons_color);
138 cr.save ();
139 cr.translate (0.5, -1.0);
140 cr.new_path();
141 cr.move_to (0, 0);
142 cr.line_to (5.5, 5.5);
143 cr.line_to (0, 11);
144 cr.close_path ();
145 cr.fill ();
146 cr.translate (5, 0);
147 cr.rectangle (0, 0.75, 2, 9.5);
148 cr.fill ();
149 cr.restore ();
152 public static void paint_fast_backward_icon (Cairo.Context cr) {
153 cr.save ();
154 cr.scale (-1, 1);
155 cr.translate (-8, 0);
156 paint_fast_forward_icon (cr);
157 cr.restore ();
160 public static void paint_fast_to_start_icon (Cairo.Context cr) {
161 cr.save ();
162 cr.scale (-1, 1);
163 cr.translate (-7, 0);
164 paint_fast_to_end_icon (cr);
165 cr.restore ();
168 private void paint_icon (Cairo.Context cr) {
169 // icons
170 int w;
171 int h;
173 icon_size (icon_type, out w, out h);
175 cr.save ();
176 cr.translate (((allocation.width - 3) / 2.0) - (w / 2.0), ((allocation.height - 3) / 2.0) - (h / 2.0));
178 switch (icon_type) {
179 case IconType.STOP: paint_stop_icon (cr); break;
180 case IconType.REC: paint_rec_icon (cr); break;
181 case IconType.PLAY: paint_play_icon (cr); break;
182 case IconType.FAST_FORWARD: paint_fast_forward_icon (cr); break;
183 case IconType.FAST_BACKWARD: paint_fast_backward_icon (cr); break;
184 case IconType.TO_END: paint_fast_to_end_icon (cr); break;
185 case IconType.TO_START: paint_fast_to_start_icon (cr); break;
186 default: GLib.assert_not_reached (); break;
188 cr.restore ();
191 private Color pressed_color () {
192 Color pressed_color = color_from_string ("#c2c2c2");
193 switch (icon_type) {
194 case IconType.STOP: pressed_color = color_from_string ("#2d73a2"); break;
195 case IconType.REC: pressed_color = color_from_string ("#d46552"); break;
196 case IconType.PLAY: pressed_color = color_from_string ("#87bb36"); break;
197 case IconType.FAST_FORWARD:
198 case IconType.FAST_BACKWARD:
199 case IconType.TO_END:
200 case IconType.TO_START: pressed_color = color_from_string ("#636363"); break;
201 default: GLib.assert_not_reached (); break;
203 return pressed_color;
206 /* Widget is asked to draw itself */
207 public override bool expose_event (Gdk.EventExpose event) {
209 // Create a Cairo context
210 var cr = Gdk.cairo_create (this.window);
212 // Set clipping area in order to avoid unnecessary drawing
213 cr.rectangle (event.area.x, event.area.y,
214 event.area.width, event.area.height);
215 cr.clip ();
217 cr.set_line_width (1.0);
219 cr.set_source_rgba (0.0, 0.0, 0.0, 0.0);
220 cr.rectangle (0.0, 0.0, allocation.width, allocation.height);
221 cr.fill ();
223 set_source_color (cr, style.bg[(int)Gtk.StateType.NORMAL]);
224 cr.rectangle (0, 0, allocation.width, allocation.height);
225 cr.fill ();
227 // border line
228 set_source_color_string (cr, "#808080");
229 cr.move_to (2.5, 1.5);
230 cr.line_to (allocation.width - 2.5, 1.5);
231 cr.line_to (allocation.width - 1.5, 2.5);
232 cr.line_to (allocation.width - 1.5, allocation.height - 1.5);
233 cr.line_to (2.5, allocation.height - 1.5);
234 cr.line_to (1.5, allocation.height - 2.5);
235 cr.line_to (1.5, 2.5);
236 cr.line_to (2.5, 1.5);
237 cr.stroke();
239 // top / left shine line
240 set_source_color_string (cr, "#ffffff");
241 cr.move_to (allocation.width - 2.5, 2.5);
242 cr.line_to (2.5, 2.5);
243 cr.line_to (2.5, allocation.height - 3);
244 cr.stroke ();
246 // bottom / right shadow line
247 set_source_color_string (cr, "#c2c2c2");
248 cr.move_to (allocation.width - 2.5, 2.5);
249 cr.line_to (allocation.width - 2.5, allocation.height - 2.5);
250 cr.line_to (2.5, allocation.height - 2.5);
251 cr.stroke ();
253 // paint icon
254 cr.save ();
255 cr.translate (3, 3);
257 // button base color
258 if (button_state == ButtonState.PRESSED) {
259 set_source_color (cr, pressed_color ());
260 cr.rectangle (-1, -1, allocation.width - 3, allocation.height - 3);
261 } else {
262 set_source_color_string (cr, "#e4e4e4");
263 cr.rectangle ( 0, 0, allocation.width - 6, allocation.height - 6);
266 cr.fill ();
268 paint_icon (cr);
269 cr.restore ();
271 double shine_alpha_start = 0.8;
272 double shine_alpha_stop = 0.10;
273 // draw shine
275 // upper shine
276 Color shine_upper_gradient1 = color_from_string ("#ffffff");
277 Color shine_upper_gradient2 = color_from_string ("#c0c0c0");
278 Cairo.Pattern shine_upper = create_gradient (0, 0, 0, allocation.height / 2.0, shine_upper_gradient1, shine_upper_gradient2, shine_alpha_start, shine_alpha_stop);
279 cr.set_source (shine_upper);
280 cr.rectangle (0, 0, allocation.width, allocation.height / 2.0);
281 cr.fill ();
283 // shine line
284 if (button_state != ButtonState.PRESSED) {
285 set_source_color_string (cr, "#ffffff", shine_alpha_stop + 0.05);
286 cr.move_to (1, allocation.height / 2.0);
287 cr.line_to (allocation.width - 2, allocation.height / 2.0);
288 cr.stroke ();
291 // lower shine
292 Color shine_lower_gradient1 = color_from_string ("#a0a0a0");
293 Color shine_lower_gradient2 = color_from_string ("#a0a0a0");
294 Cairo.Pattern shine_lower = create_gradient (0, allocation.height / 2.0, 0, allocation.height, shine_lower_gradient1, shine_lower_gradient2, shine_alpha_stop, shine_alpha_start);
295 cr.set_source (shine_lower);
296 cr.rectangle (2, allocation.height / 2.0, allocation.width - 3, allocation.height / 2.0 - 2);
297 cr.fill ();
299 return false;
303 } // namespace Prolooks