/* This file is part of LED Pattern Editor.
*
* Copyright (C) 2010 Philipp Zabel
*
* LED Pattern Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LED Pattern Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LED Pattern Editor. If not, see .
*/
class LedPatternView : Gtk.DrawingArea {
public LedPatternRX51 pattern;
public double duration;
public LedPatternView (LedPatternRX51? _pattern = null) {
pattern = _pattern;
if (pattern != null)
pattern.changed.connect (update);
update_duration ();
}
public void update_duration () {
duration = 1.0;
if (pattern != null) {
while (pattern.duration > 1000 * duration) {
duration += 1.0;
}
}
}
public override bool expose_event (Gdk.EventExpose event) {
update_duration ();
var ctx = Gdk.cairo_create (window);
int height = allocation.height;
int width = allocation.width;
double pps = width / duration; // pixel per second
ctx.rectangle (event.area.x, event.area.y, event.area.width, event.area.height);
ctx.clip ();
ctx.set_source_rgb (0, 0, 0);
ctx.set_line_width (1.0);
ctx.set_line_join (Cairo.LineJoin.ROUND);
ctx.new_path ();
ctx.move_to (0, 0);
ctx.line_to (width, 0);
ctx.line_to (width, height);
ctx.line_to (0, height);
ctx.close_path ();
ctx.fill ();
ctx.set_source_rgb (0.33, 0.33, 0.33);
ctx.new_path ();
// 0%, 50%, 100%
ctx.move_to (0.5, 0.5);
ctx.line_to (width - 0.5, 0.5);
ctx.move_to (0.5, height / 2 - 0.5);
ctx.line_to (width - 0.5, height / 2 - 0.5);
ctx.move_to (0.5, height - 0.5);
ctx.line_to (width - 0.5, height - 0.5);
// 0s, 1s, 2s, 3s, 4s
for (double time = 0; time <= duration; time += 1.0) {
ctx.move_to (time * pps + 0.5, 0.5);
ctx.line_to (time * pps + 0.5, 139.5);
}
ctx.stroke ();
if (pattern != null) {
if (pattern.color1 != LedColor.OFF)
draw_pattern (ctx, width, height,
pattern.color1, pattern.engine1);
if (pattern.color2 != LedColor.OFF)
draw_pattern (ctx, width, height,
pattern.color2, pattern.engine2);
}
return true;
}
private void draw_pattern (Cairo.Context ctx, int width, int height, LedColor color,
List engine) {
double pps = width / duration; // pixel per second
ctx.new_path ();
ctx.set_operator (Cairo.Operator.ADD);
ctx.set_source_rgb ((LedColor.R in color) ? 1.0 : 0.0,
(LedColor.G in color) ? 1.0 : 0.0,
(LedColor.B in color) ? 1.0 : 0.0);
ctx.set_line_width (3.0);
double x = 0, y = 0;
foreach (LedCommand command in engine) {
x = command.time * pps/1000.0;
y = (255 - command.level) * (height - 1)/255.0;
switch (command.type) {
case CommandType.RAMP_WAIT:
case CommandType.TRIGGER:
x += command.duration * pps/1000.0;
y -= command.steps * (height - 1)/255.0;
if (y < 0)
y = 0;
if (y > (height - 1))
y = height - 1;
ctx.line_to (x, y);
break;
default:
ctx.line_to (x, y);
break;
}
}
ctx.stroke ();
ctx.set_source_rgb ((LedColor.R in color) ? 0.75 : 0.0,
(LedColor.G in color) ? 0.75 : 0.0,
(LedColor.B in color) ? 0.75 : 0.0);
ctx.set_line_width (1.0);
LedCommandRX51 last_command = null;
foreach (LedCommandRX51 command in engine) {
if (command.type == CommandType.END ||
command.type == CommandType.GO_TO_START) {
last_command = command;
break;
}
}
if (last_command == null)
return;
if (last_command.type == CommandType.END) {
ctx.new_path ();
ctx.move_to (x, y);
if (last_command.steps == -255) {
ctx.line_to (x, height - 0.5);
ctx.line_to (width - 0.5, height - 0.5);
} else {
ctx.line_to (width - 0.5, y);
}
ctx.stroke ();
}
var engine_duration = last_command.time + last_command.duration;
if (last_command.type == CommandType.GO_TO_START && engine_duration >= 3 * 0.49) {
ctx.new_path ();
for (double offset = engine_duration; (offset * pps/1000.0) <= width; offset += engine_duration) {
ctx.move_to (x, y);
foreach (LedCommand command in engine) {
x = (command.time + offset) * pps/1000.0;
y = (255 - command.level) * (height - 1)/255.0;
if (x >= width)
break;
switch (command.type) {
case CommandType.RAMP_WAIT:
case CommandType.TRIGGER:
x += command.duration * pps/1000.0;
y -= command.steps * (height - 1)/255.0;
if (y < 0)
y = 0;
if (y > (height - 1))
y = height - 1;
ctx.line_to (x, y);
break;
default:
ctx.line_to (x, y);
break;
}
}
}
ctx.stroke ();
}
if (last_command.type == CommandType.GO_TO_START && engine_duration < 3 * 0.49) {
ctx.new_path ();
ctx.move_to (x, y);
ctx.line_to (width - 0.5, y);
ctx.stroke ();
}
}
public void update () {
unowned Gdk.Region region = window.get_clip_region ();
// redraw the cairo canvas completely by exposing it
window.invalidate_region (region, true);
window.process_updates (true);
}
}