a4f74445a15c59e7940cb0419e0bf804ddd177ea
[led-pattern-ed] / src / led-pattern-view.vala
1 /* This file is part of LED Pattern Editor.
2  *
3  * Copyright (C) 2010 Philipp Zabel
4  *
5  * LED Pattern Editor is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * LED Pattern Editor is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with LED Pattern Editor. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 class LedPatternView : Gtk.DrawingArea {
20         public LedPatternRX51 pattern;
21         public double duration;
22
23         public LedPatternView (LedPatternRX51? _pattern = null) {
24                 pattern = _pattern;
25                 if (pattern != null)
26                         pattern.changed.connect (update);
27                 update_duration ();
28         }
29
30         public void update_duration () {
31                 duration = 1.0;
32                 if (pattern != null) {
33                         while (pattern.duration > 1000 * duration) {
34                                 duration += 1.0;
35                         }
36                 }
37         }
38
39         public override bool expose_event (Gdk.EventExpose event) {
40
41                 update_duration ();
42
43                 var ctx = Gdk.cairo_create (window);
44                 int height = allocation.height;
45                 int width = allocation.width;
46                 double pps = width / duration; // pixel per second
47
48                 ctx.rectangle (event.area.x, event.area.y, event.area.width, event.area.height);
49                 ctx.clip ();
50
51                 ctx.set_source_rgb (0, 0, 0);
52                 ctx.set_line_width (1.0);
53
54                 ctx.set_line_join (Cairo.LineJoin.ROUND);
55
56                 ctx.new_path ();
57                 ctx.move_to (0, 0);
58                 ctx.line_to (width, 0);
59                 ctx.line_to (width, height);
60                 ctx.line_to (0, height);
61                 ctx.close_path ();
62                 ctx.fill ();
63
64                 ctx.set_source_rgb (0.33, 0.33, 0.33);
65                 ctx.new_path ();
66
67                 // 0%, 50%, 100%
68                 ctx.move_to (0.5, 0.5);
69                 ctx.line_to (width - 0.5, 0.5);
70
71                 ctx.move_to (0.5, height / 2 - 0.5);
72                 ctx.line_to (width - 0.5, height / 2 - 0.5);
73
74                 ctx.move_to (0.5, height - 0.5);
75                 ctx.line_to (width - 0.5, height - 0.5);
76
77                 // 0s, 1s, 2s, 3s, 4s
78                 for (double time = 0; time <= duration; time += 1.0) {
79                         ctx.move_to (time * pps + 0.5, 0.5);
80                         ctx.line_to (time * pps + 0.5, 139.5);
81                 }
82                 ctx.stroke ();
83
84                 if (pattern != null) {
85                         ctx.new_path ();
86
87                         if (pattern.led_map == "r") {
88                                 ctx.set_source_rgb (1, 0, 0);
89                         } else if (pattern.led_map == "g") {
90                                 ctx.set_source_rgb (0, 1, 0);
91                         } else if (pattern.led_map == "b") {
92                                 ctx.set_source_rgb (0, 0, 1);
93                         } else if (pattern.led_map == "rg") {
94                                 ctx.set_source_rgb (1, 1, 0);
95                         } else if (pattern.led_map == "rb") {
96                                 ctx.set_source_rgb (1, 0, 1);
97                         } else if (pattern.led_map == "gb") {
98                                 ctx.set_source_rgb (0, 1, 1);
99                         } else if (pattern.led_map == "rgb") {
100                                 ctx.set_source_rgb (1, 1, 1);
101                         } else {
102                                 ctx.set_source_rgb (0.75, 0.75, 0.75);
103                         }
104                         ctx.set_line_width (3.0);
105
106                         double x = 0, y = 0;
107                         foreach (LedCommand command in pattern.engine1) {
108                                 x = command.time * pps/1000.0;
109                                 y = (255 - command.level) * (height - 1)/255.0;
110                                 switch (command.type) {
111                                 case CommandType.RAMP_WAIT:
112                                         x += command.duration * pps/1000.0;
113                                         y -= command.steps * (height - 1)/255.0;
114                                         if (y < 0)
115                                                 y = 0;
116                                         if (y > (height - 1))
117                                                 y = height - 1;
118                                         ctx.line_to (x, y);
119                                         break;
120                                 default:
121                                         ctx.line_to (x, y);
122                                         break;
123                                 }
124                         }
125                         ctx.stroke ();
126
127                         if (pattern.led_map == "r") {
128                                 ctx.set_source_rgb (0.75, 0, 0);
129                         } else if (pattern.led_map == "g") {
130                                 ctx.set_source_rgb (0, 0.75, 0);
131                         } else if (pattern.led_map == "b") {
132                                 ctx.set_source_rgb (0, 0, 0.75);
133                         } else if (pattern.led_map == "rg") {
134                                 ctx.set_source_rgb (0.75, 0.75, 0);
135                         } else if (pattern.led_map == "rb") {
136                                 ctx.set_source_rgb (0.75, 0, 0.75);
137                         } else if (pattern.led_map == "gb") {
138                                 ctx.set_source_rgb (0, 0.75, 0.75);
139                         } else if (pattern.led_map == "rgb") {
140                                 ctx.set_source_rgb (0.75, 0.75, 0.75);
141                         } else {
142                                 ctx.set_source_rgb (0.66, 0.66, 0.66);
143                         }
144                         ctx.set_line_width (1.0);
145
146                         CommandType type = CommandType.UNKNOWN;
147                         foreach (LedCommandRX51 command in pattern.engine1) {
148                                 if (command.type == CommandType.STOP ||
149                                     command.type == CommandType.REPEAT) {
150                                         type = command.type;
151                                         break;
152                                 }
153                         }
154
155                         if (type == CommandType.STOP) {
156                                 ctx.new_path ();
157
158                                 ctx.move_to (x, y);
159                                 ctx.line_to (width - 0.5, y);
160
161                                 ctx.stroke ();
162                         }
163                         if (type == CommandType.REPEAT && pattern.duration > 0.0) {
164                                 ctx.new_path ();
165
166                                 for (double offset = pattern.duration; (offset * pps/1000.0) <= width; offset += pattern.duration) {
167                                         ctx.move_to (x, y);
168                                         foreach (LedCommand command in pattern.engine1) {
169                                                 x = (command.time + offset) * pps/1000.0;
170                                                 y = (255 - command.level) * (height - 1)/255.0;
171                                                 if (x >= width)
172                                                         break;
173                                                 switch (command.type) {
174                                                 case CommandType.RAMP_WAIT:
175                                                         x += command.duration * pps/1000.0;
176                                                         y -= command.steps * (height - 1)/255.0;
177                                                         if (y < 0)
178                                                                 y = 0;
179                                                         if (y > (height - 1))
180                                                                 y = height - 1;
181                                                         ctx.line_to (x, y);
182                                                         break;
183                                                 default:
184                                                         ctx.line_to (x, y);
185                                                         break;
186                                                 }
187                                         }
188                                 }
189
190                                 ctx.stroke ();
191                         }
192                         if (type == CommandType.REPEAT && pattern.duration == 0.0) {
193                                 ctx.new_path ();
194
195
196                                 ctx.move_to (x, y);
197                                 ctx.line_to (width - 0.5, y);
198
199                                 ctx.stroke ();
200                         }
201                 }
202                 return true;
203         }
204
205         public void update () {
206                 unowned Gdk.Region region = window.get_clip_region ();
207
208                 // redraw the cairo canvas completely by exposing it
209                 window.invalidate_region (region, true);
210                 window.process_updates (true);
211         }
212 }