/* 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) { ctx.new_path (); if (pattern.led_map == "r") { ctx.set_source_rgb (1, 0, 0); } else if (pattern.led_map == "g") { ctx.set_source_rgb (0, 1, 0); } else if (pattern.led_map == "b") { ctx.set_source_rgb (0, 0, 1); } else if (pattern.led_map == "rg") { ctx.set_source_rgb (1, 1, 0); } else if (pattern.led_map == "rb") { ctx.set_source_rgb (1, 0, 1); } else if (pattern.led_map == "gb") { ctx.set_source_rgb (0, 1, 1); } else if (pattern.led_map == "rgb") { ctx.set_source_rgb (1, 1, 1); } else { ctx.set_source_rgb (0.75, 0.75, 0.75); } ctx.set_line_width (3.0); double x = 0, y = 0; foreach (LedCommand command in pattern.engine1) { x = command.time * pps/1000.0; y = (255 - command.level) * (height - 1)/255.0; switch (command.type) { case CommandType.RAMP_WAIT: 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 (pattern.led_map == "r") { ctx.set_source_rgb (0.75, 0, 0); } else if (pattern.led_map == "g") { ctx.set_source_rgb (0, 0.75, 0); } else if (pattern.led_map == "b") { ctx.set_source_rgb (0, 0, 0.75); } else if (pattern.led_map == "rg") { ctx.set_source_rgb (0.75, 0.75, 0); } else if (pattern.led_map == "rb") { ctx.set_source_rgb (0.75, 0, 0.75); } else if (pattern.led_map == "gb") { ctx.set_source_rgb (0, 0.75, 0.75); } else if (pattern.led_map == "rgb") { ctx.set_source_rgb (0.75, 0.75, 0.75); } else { ctx.set_source_rgb (0.66, 0.66, 0.66); } ctx.set_line_width (1.0); CommandType type = CommandType.UNKNOWN; int steps = 0; foreach (LedCommandRX51 command in pattern.engine1) { if (command.type == CommandType.END || command.type == CommandType.GO_TO_START) { type = command.type; steps = command.steps; break; } } if (type == CommandType.END) { ctx.new_path (); ctx.move_to (x, y); if (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 (); } if (type == CommandType.GO_TO_START && pattern.duration >= 3 * 0.49) { ctx.new_path (); for (double offset = pattern.duration; (offset * pps/1000.0) <= width; offset += pattern.duration) { ctx.move_to (x, y); foreach (LedCommand command in pattern.engine1) { 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: 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 (type == CommandType.GO_TO_START && pattern.duration < 3 * 0.49) { ctx.new_path (); ctx.move_to (x, y); ctx.line_to (width - 0.5, y); ctx.stroke (); } } return true; } 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); } }