/* Demo Recorder for MAEMO 5 * Copyright (C) 2010 Dru Moore * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ namespace IdWorks { public class DbMonitorWidget : Gtk.Widget { public static enum Layout { VERTICAL = 0, HORIZONTAL } private static const int BORDER_WIDTH = 4; private static const int BORDER_HEIGHT = 4; //private Pango.Layout layout; private static const double MIN_VALUE = 0.0; private static const double MAX_VALUE = 1.5; private static const double ZERO_VALUE = 1.0; private double peak; private double decay; public void set_peak(double val) { this.peak = (MAX_VALUE > val) ? val : MAX_VALUE; this.redraw_canvas(); } public void set_decay(double val) { this.decay = (MAX_VALUE > val) ? val : MAX_VALUE; this.redraw_canvas(); } private Layout layout = Layout.VERTICAL; public void set_layout(Layout layout) { this.layout = layout; } construct { // nothing TODO } /* * This method Gtk+ is calling on a widget to ask * the widget how large it wishes to be. It's not guaranteed * that Gtk+ will actually give this size to the widget. */ public override void size_request (out Gtk.Requisition requisition) { requisition.width = (Layout.VERTICAL == this.layout) ? 40 : 250; requisition.height = (Layout.VERTICAL == this.layout) ? 250 : 40; } /* * This method gets called by Gtk+ when the actual size is known * and the widget is told how much space could actually be allocated. * It is called every time the widget size changes, for example when the * user resizes the window. */ public override void size_allocate (Gdk.Rectangle allocation) { // The base method will save the allocation and move/resize the // widget's GDK window if the widget is already realized. base.size_allocate (allocation); // Move/resize other realized windows if necessary } private void redraw_canvas () { if (null == this.window) { return; } unowned Gdk.Region region = this.window.get_clip_region (); // redraw the cairo canvas completely by exposing it this.window.invalidate_region (region, true); this.window.process_updates (true); } private void draw() { // Cairo context to draw on Cairo.Context cr = Gdk.cairo_create (this.window); // In this example, draw a rectangle in the foreground color Gdk.cairo_set_source_color (cr, this.style.fg[this.state]); cr.rectangle (BORDER_WIDTH, BORDER_HEIGHT, this.allocation.width - 2 * BORDER_WIDTH, this.allocation.height - 2 * BORDER_HEIGHT); cr.set_line_width (1.0); //cr.set_line_join (LineJoin.ROUND); cr.stroke (); // draw the bar for the peak level if (0.0 < this.peak) { if (Layout.VERTICAL == this.layout) { cr.rectangle (BORDER_WIDTH , (this.allocation.height - 2 * BORDER_HEIGHT) - ( (this.allocation.height - 2 * BORDER_HEIGHT) / (MAX_VALUE - MIN_VALUE) ) * this.peak , this.allocation.width - 2 * BORDER_WIDTH , (((this.allocation.height - 2 * BORDER_HEIGHT) / (MAX_VALUE - MIN_VALUE)) * this.peak) + BORDER_HEIGHT ); } else { cr.rectangle (BORDER_WIDTH , BORDER_HEIGHT , (((this.allocation.width - 2 * BORDER_WIDTH) / (MAX_VALUE - MIN_VALUE)) * this.peak) + BORDER_WIDTH , this.allocation.height - 2 * BORDER_HEIGHT ); } cr.set_line_width (2.0); cr.fill(); } // draw a line for the decay level if (0.0 < this.decay) { if (Layout.VERTICAL == this.layout) { cr.rectangle (BORDER_WIDTH , (this.allocation.height - 2 * BORDER_HEIGHT) - ( (this.allocation.height - 2 * BORDER_HEIGHT) / (MAX_VALUE - MIN_VALUE) ) * this.decay , this.allocation.width - 2 * BORDER_WIDTH , BORDER_HEIGHT ); } else { cr.rectangle ((((this.allocation.width - 2 * BORDER_WIDTH) / (MAX_VALUE - MIN_VALUE)) * this.decay) + BORDER_WIDTH , BORDER_HEIGHT , BORDER_WIDTH , this.allocation.height - 2 * BORDER_HEIGHT ); } cr.set_line_width (2.0); cr.fill(); } // draw 0 db marker if (Layout.VERTICAL == this.layout) { cr.rectangle (0 , (this.allocation.height) - ( (this.allocation.height) / (MAX_VALUE - MIN_VALUE) ) * ZERO_VALUE , this.allocation.width , 1 ); } else { cr.rectangle ((((this.allocation.width) / (MAX_VALUE - MIN_VALUE)) * ZERO_VALUE) , 0 , 1 , this.allocation.height ); } cr.set_line_width (1.0); cr.fill(); } /* * This method is responsible for creating GDK (windowing system) * resources. In this example we will create a new GDK window which we * then draw on. */ public override void realize () { // Create a new Gdk.Window which we can draw on. // Also say that we want to receive exposure events by setting // the event_mask var attrs = Gdk.WindowAttr () { window_type = Gdk.WindowType.CHILD, wclass = Gdk.WindowClass.INPUT_OUTPUT, event_mask = get_events () | Gdk.EventMask.EXPOSURE_MASK }; this.window = new Gdk.Window (get_parent_window (), attrs, 0); this.window.move_resize (this.allocation.x, this.allocation.y, this.allocation.width, this.allocation.height); // Associate the GDK window with ourselves, Gtk+ needs a reference // between the widget and the GDK window this.window.set_user_data (this); // Attach the style to the GDK window. A style contains colors and // GC contexts used for drawing this.style = this.style.attach (this.window); // The default color of the background should be what // the style (theme engine) tells us this.style.set_background (this.window, Gtk.StateType.NORMAL); // Set an internal flag telling that we're realized set_flags (Gtk.WidgetFlags.REALIZED); } /* * This method is called when the widget is asked to draw itself. * Remember that this will be called a lot of times, so it's usually * a good idea to write this code as optimized as it can be, don't * create any resources in here. */ public override bool expose_event (Gdk.EventExpose event) { this.draw(); return true; } /* * This method is responsible for freeing the GDK resources. */ public override void unrealize () { // The base method will de-associate the GDK window we created in // method 'realize' with ourselves. base.unrealize (); // De-associate other windows with 'set_user_data (null)' if necessary } } }