Reworked track settings.
[demorecorder] / src / DbMonitorWidget.vala
1 /*  Demo Recorder for MAEMO 5
2 *   Copyright (C) 2010 Dru Moore <usr@dru-id.co.uk>
3 *   This program is free software; you can redistribute it and/or modify
4 *   it under the terms of the GNU General Public License version 2,
5 *   or (at your option) any later version, as published by the Free
6 *   Software Foundation
7 *
8 *   This program is distributed in the hope that it will be useful,
9 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *   GNU General Public License for more details
12 *
13 *   You should have received a copy of the GNU General Public
14 *   License along with this program; if not, write to the
15 *   Free Software Foundation, Inc.,
16 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 */
18 namespace IdWorks {
19
20 public class DbMonitorWidget : Gtk.Widget {
21   
22   public static enum Layout {
23     VERTICAL = 0,
24     HORIZONTAL
25   }
26   
27   private static const int BORDER_WIDTH = 4;
28   private static const int BORDER_HEIGHT = 4;
29   //private Pango.Layout layout;
30   private static const double MIN_VALUE = 0.0;
31   private static const double MAX_VALUE = 1.5;
32   
33   private static const double ZERO_VALUE = 1.0;
34   
35   private double peak;
36   private double decay;
37   public void set_peak(double val) {
38     this.peak = (MAX_VALUE > val) ? val : MAX_VALUE;
39     this.redraw_canvas();
40   }
41   public void set_decay(double val) {
42     this.decay = (MAX_VALUE > val) ? val : MAX_VALUE;
43     this.redraw_canvas();
44   }
45   private Layout layout = Layout.VERTICAL;
46   public void set_layout(Layout layout) {
47     this.layout = layout;
48   }
49   
50   construct {
51     // nothing TODO
52   }
53   
54   /*
55   * This method Gtk+ is calling on a widget to ask
56   * the widget how large it wishes to be. It's not guaranteed
57   * that Gtk+ will actually give this size to the widget.
58   */
59   public override void size_request (out Gtk.Requisition requisition) {
60     requisition.width = (Layout.VERTICAL == this.layout) ? 40 : 250;
61     requisition.height = (Layout.VERTICAL == this.layout) ? 250 : 40;
62   }
63   
64   /*
65   * This method gets called by Gtk+ when the actual size is known
66   * and the widget is told how much space could actually be allocated.
67   * It is called every time the widget size changes, for example when the
68   * user resizes the window.
69   */
70   public override void size_allocate (Gdk.Rectangle allocation) {
71     // The base method will save the allocation and move/resize the
72     // widget's GDK window if the widget is already realized.
73     base.size_allocate (allocation);
74     
75     // Move/resize other realized windows if necessary
76   }
77   
78   private void redraw_canvas () {
79     if (null == this.window) {
80       return;
81     }    
82     unowned Gdk.Region region = this.window.get_clip_region ();
83     // redraw the cairo canvas completely by exposing it
84     this.window.invalidate_region (region, true);
85     this.window.process_updates (true);
86   }
87   
88   private void draw() {
89     // Cairo context to draw on
90     Cairo.Context cr = Gdk.cairo_create (this.window);
91     // In this example, draw a rectangle in the foreground color
92     Gdk.cairo_set_source_color (cr, this.style.fg[this.state]);
93     cr.rectangle (BORDER_WIDTH, BORDER_HEIGHT,
94                   this.allocation.width - 2 * BORDER_WIDTH,
95                   this.allocation.height - 2 * BORDER_HEIGHT);
96                   cr.set_line_width (1.0);
97                   //cr.set_line_join (LineJoin.ROUND);
98                   cr.stroke ();
99                   
100     // draw the bar for the peak level
101     if (0.0 < this.peak) {
102       if (Layout.VERTICAL == this.layout) {
103         cr.rectangle (BORDER_WIDTH
104         , (this.allocation.height - 2 * BORDER_HEIGHT) - ( (this.allocation.height - 2 * BORDER_HEIGHT) / (MAX_VALUE - MIN_VALUE) ) * this.peak
105         , this.allocation.width - 2 * BORDER_WIDTH
106         , (((this.allocation.height - 2 * BORDER_HEIGHT) / (MAX_VALUE - MIN_VALUE)) * this.peak) + BORDER_HEIGHT
107         );
108       }
109       else {
110         cr.rectangle (BORDER_WIDTH
111         , BORDER_HEIGHT
112         , (((this.allocation.width - 2 * BORDER_WIDTH) / (MAX_VALUE - MIN_VALUE)) * this.peak) + BORDER_WIDTH
113         , this.allocation.height - 2 * BORDER_HEIGHT
114         );
115       }
116       cr.set_line_width (2.0);
117       cr.fill();
118     }
119     
120     // draw a line for the decay level
121     if (0.0 < this.decay) {
122       if (Layout.VERTICAL == this.layout) {
123         cr.rectangle (BORDER_WIDTH
124         , (this.allocation.height - 2 * BORDER_HEIGHT) - ( (this.allocation.height - 2 * BORDER_HEIGHT) / (MAX_VALUE - MIN_VALUE) ) * this.decay
125         , this.allocation.width - 2 * BORDER_WIDTH
126         , BORDER_HEIGHT
127         );
128       }
129       else {
130         cr.rectangle ((((this.allocation.width - 2 * BORDER_WIDTH) / (MAX_VALUE - MIN_VALUE)) * this.decay) + BORDER_WIDTH
131         , BORDER_HEIGHT
132         , BORDER_WIDTH
133         , this.allocation.height - 2 * BORDER_HEIGHT
134         );
135       }
136       cr.set_line_width (2.0);
137       cr.fill();
138     }
139     
140     // draw 0 db marker
141     if (Layout.VERTICAL == this.layout) {
142       cr.rectangle (0
143       , (this.allocation.height) - ( (this.allocation.height) / (MAX_VALUE - MIN_VALUE) ) * ZERO_VALUE
144       , this.allocation.width
145       , 1
146       );
147     }
148     else {
149       cr.rectangle ((((this.allocation.width) / (MAX_VALUE - MIN_VALUE)) * ZERO_VALUE)
150       , 0
151       , 1
152       , this.allocation.height
153       );
154     }
155     cr.set_line_width (1.0);
156     cr.fill();
157     
158   }
159   
160   /*
161   * This method is responsible for creating GDK (windowing system)
162   * resources. In this example we will create a new GDK window which we
163   * then draw on.
164   */
165   public override void realize () {
166     // Create a new Gdk.Window which we can draw on.
167     // Also say that we want to receive exposure events by setting
168     // the event_mask
169     var attrs = Gdk.WindowAttr () {
170       window_type = Gdk.WindowType.CHILD,
171       wclass = Gdk.WindowClass.INPUT_OUTPUT,
172       event_mask = get_events () | Gdk.EventMask.EXPOSURE_MASK
173     };
174     this.window = new Gdk.Window (get_parent_window (), attrs, 0);
175     this.window.move_resize (this.allocation.x, this.allocation.y,
176                              this.allocation.width, this.allocation.height);
177                              
178     // Associate the GDK window with ourselves, Gtk+ needs a reference
179     // between the widget and the GDK window
180     this.window.set_user_data (this);
181     
182     // Attach the style to the GDK window. A style contains colors and
183     // GC contexts used for drawing
184     this.style = this.style.attach (this.window);
185     
186     // The default color of the background should be what
187     // the style (theme engine) tells us
188     this.style.set_background (this.window, Gtk.StateType.NORMAL);
189     
190     // Set an internal flag telling that we're realized
191     set_flags (Gtk.WidgetFlags.REALIZED);
192   }
193   
194   /*
195   * This method is called when the widget is asked to draw itself.
196   * Remember that this will be called a lot of times, so it's usually
197   * a good idea to write this code as optimized as it can be, don't
198   * create any resources in here.
199   */
200   public override bool expose_event (Gdk.EventExpose event) {
201     this.draw();
202     return true;
203   }
204   
205   /*
206   * This method is responsible for freeing the GDK resources.
207   */
208   public override void unrealize () {
209     // The base method will de-associate the GDK window we created in
210     // method 'realize' with ourselves.
211     base.unrealize ();
212     
213     // De-associate other windows with 'set_user_data (null)' if necessary
214   }
215   
216 }
217
218 }