* uint32 -> jack_nframes_t works
[jackpanel.git] / jackpanel / Display.vala
blob17bac82b8a4ae4bba19533e445b1a7dce135d11b
1 using Gtk;
2 using Gdk;
3 using Prolooks;
5 namespace Jackpanel {
7 public class Display : DisplayBase {
8 private string _time;
9 public string time {
10 get { return _time; }
11 set {
12 if (_time != value) {
13 _time = value;
14 queue_draw ();
19 private string _time_alt;
20 public string time_alt {
21 get { return _time_alt; }
22 set {
23 if (_time_alt != value) {
24 _time_alt = value;
25 queue_draw ();
30 private double realtime_x;
31 private double realtime_y;
32 private double realtime_w;
33 private double realtime_h;
35 public signal void toggle_realtime_requested (bool new_state);
36 public bool realtime { get; set; }
39 private double xruns_x;
40 private double xruns_y;
41 private double xruns_w;
42 private double xruns_h;
43 private uint32 _xruns;
45 public signal void reset_xruns_requested ();
46 public uint32 xruns {
47 get {
48 return _xruns;
50 set {
51 if (_xruns != value) {
52 _xruns = value;
53 queue_draw ();
58 static jack_nframes_t[] sample_rates = { 22050, 32000, 44100, 48000, 96000, 192000 };
59 private jack_nframes_t _sample_rate;
60 public jack_nframes_t sample_rate {
61 get {
62 return _sample_rate;
64 set {
65 if (_sample_rate != value) {
66 _sample_rate = value;
67 queue_draw ();
71 public signal void sample_rate_changed (jack_nframes_t new_sample_rate);
72 private double sample_rate_x;
73 private double sample_rate_y;
74 private double sample_rate_w;
75 private double sample_rate_h;
76 private Menu sample_rate_menu;
78 private jack_nframes_t _buffer_size;
79 public jack_nframes_t buffer_size {
80 get {
81 return _buffer_size;
83 set {
84 if (_buffer_size != value) {
85 _buffer_size = value;
86 queue_draw ();
91 static uint[] buffer_sizes = { 16, 32, 64, 128, 256, 512, 1024, 2048 };
92 public signal void buffer_size_changed (jack_nframes_t new_buffer_size);
93 private double buffer_size_x;
94 private double buffer_size_y;
95 private double buffer_size_w;
96 private double buffer_size_h;
97 private Menu buffer_size_menu;
100 public Display () {
101 width = 182;
102 height = 49;
103 _time = "00:00:00";
104 set_size_request (width, height);
108 private double popup_triangle_width () { return 7.0; }
110 public void draw_popup_triangle (Cairo.Context cr, double x, double y) {
111 cr.save ();
112 set_source_from_color_string (cr, "#b3b6af");
113 cr.new_path ();
114 cr.move_to (x, y);
115 cr.line_to (x + popup_triangle_width (), y);
116 cr.line_to (x + popup_triangle_width () / 2.0, y + 4);
117 cr.close_path ();
118 cr.fill ();
119 cr.restore ();
122 protected override bool draw_contents (Cairo.Context cr, Gdk.EventExpose event) {
123 double padding = 3;
124 double font_size = 16;
125 double smaller_font_size = font_size - 4;
126 double x = 0;
127 double y = font_size;
129 ///////////////////////////// ABOVE
130 // show time text
131 text (cr, time, padding + x, y, font_size);
133 Cairo.TextExtents ext = Cairo.TextExtents();
134 cr.text_extents (time_alt, ref ext);
136 // show alt text right justified
137 text (cr, time_alt, inner_width - ext.x_advance - ext.x_bearing - padding, y, font_size);
139 ////////////////////////////// LINES
140 // draw lines
141 Color line_color;
142 Color.parse (text_color_default, out line_color);
143 set_source_from_color (cr, line_color, 0.5);
145 /* shows text boundaries for visual debugging: left bound
146 cr.move_to (x, y + ext.y_bearing);
147 cr.rel_line_to (0, ext.height);
148 cr.stroke();
151 cr.text_extents (time, ref ext);
152 // clock time separator line
153 var vline_x = padding + x + ext.x_advance + ext.x_bearing + padding + 1;
155 cr.move_to (vline_x, padding);
156 cr.rel_line_to (0, inner_height - 2 * padding + 1);
157 cr.stroke();
159 var hline_y = padding + ext.height + padding + 2;
161 // vertical separator line
162 cr.move_to (padding, hline_y);
163 cr.rel_line_to (width - 20, 0);
164 cr.stroke();
166 ////////////////////////////// BELOW
167 var y_text_below = 0.5 + hline_y + smaller_font_size;
169 // Realtime
170 string rt = "RT";
171 cr.text_extents (rt, ref ext);
172 if (realtime) {
173 text (cr, rt, padding, y_text_below, smaller_font_size);
176 realtime_x = padding;
177 realtime_y = y_text_below - ext.height;
178 realtime_w = ext.x_advance;
179 realtime_h = ext.height + ext.y_bearing;
182 var x_after_rt = padding + ext.x_advance;
184 // Xruns
185 string xruns_str = "X: %u".printf (xruns);
186 cr.text_extents (xruns_str, ref ext);
187 if (xruns == 0) {
188 text (cr, xruns_str, x_after_rt, y_text_below, smaller_font_size);
189 } else {
190 text (cr, xruns_str, x_after_rt, y_text_below, smaller_font_size, "#ff0000");
193 xruns_x = x_after_rt;
194 xruns_y = y_text_below - ext.height;
195 xruns_w = vline_x - x_after_rt;
196 xruns_h = ext.height;
198 /* debug rect
199 set_source_from_color_string (cr, "#ff0000");
200 cr.rectangle (xruns_x, xruns_y, xruns_w, xruns_h);
201 cr.stroke ();
204 // buffer size
205 string buffer_size_str = "%2.1fms".printf (buffer_size*1000.0/(double)sample_rate);
207 cr.text_extents (buffer_size_str, ref ext);
208 var y_popup_triangle = y_text_below - ext.height + 1.0;
210 buffer_size_x = vline_x + padding;
211 buffer_size_y = y_popup_triangle;
212 buffer_size_w = ext.x_advance + ext.x_bearing + popup_triangle_width ();
213 buffer_size_h = ext.height;
214 text (cr, buffer_size_str, buffer_size_x, y_text_below, smaller_font_size);
215 draw_popup_triangle (cr, buffer_size_x + ext.x_advance + ext.x_bearing + 1.0, y_popup_triangle);
217 // sample_rate
218 string sample_rate_str = "%u".printf (sample_rate);
219 cr.text_extents (sample_rate_str, ref ext);
221 sample_rate_x = inner_width - ext.x_advance - ext.x_bearing - padding - 1 - popup_triangle_width ();
222 sample_rate_y = y_popup_triangle;
223 sample_rate_w = ext.x_advance + ext.x_bearing + popup_triangle_width ();
224 sample_rate_h = ext.height;
225 text (cr, sample_rate_str, sample_rate_x, y_text_below, smaller_font_size);
226 draw_popup_triangle (cr, inner_width - popup_triangle_width () - padding, y_popup_triangle);
228 return false;
231 private bool is_in_rect (double x, double y, double r_x, double r_y, double r_w, double r_h) {
232 x -= inner_x;
233 y -= inner_y;
234 return (r_x <= x) && (x <= r_x + r_w)
235 && (r_y <= y) && (y <= r_y + r_h);
238 public override bool button_press_event (Gdk.EventButton event) {
239 if (event.type == EventType.BUTTON_PRESS) {
240 if (is_in_rect (event.x, event.y, sample_rate_x, sample_rate_y, sample_rate_w, sample_rate_h)) {
241 sample_rate_menu = new Menu();
242 for (int i = 0; i < sample_rates.length; i++) {
243 var item = new MenuItem.with_label ("%u".printf (sample_rates[i]));
244 item.activate += (item) => {
245 string rate_str = ((Gtk.Label)((Gtk.Item)item).get_child ()).get_text();
246 var new_rate = (jack_nframes_t) rate_str.to_ulong ();
247 if (new_rate != sample_rate) {
248 sample_rate_changed (new_rate);
251 sample_rate_menu.append (item);
254 sample_rate_menu.popup (null, null, null, 3, event.time);
255 sample_rate_menu.show_all();
256 return true;
258 if (is_in_rect (event.x, event.y, buffer_size_x, buffer_size_y, buffer_size_w, buffer_size_h)) {
259 buffer_size_menu = new Menu ();
260 for (int i = 0; i < buffer_sizes.length; i++) {
261 var item = new MenuItem.with_label ("%2.1fms".printf (buffer_sizes[i]*1000.0/(double)sample_rate));
262 item.user_data = &buffer_sizes[i];
263 item.activate += (item) => {
264 buffer_size_changed (*((jack_nframes_t *)item.user_data));
266 buffer_size_menu.append (item);
269 buffer_size_menu.popup (null, null, null, 3, event.time);
270 buffer_size_menu.show_all();
271 return true;
275 if (event.type == EventType.BUTTON_PRESS && event.button == 1) {
276 if (is_in_rect (event.x, event.y, realtime_x, realtime_y, realtime_w, realtime_h)) {
277 toggle_realtime_requested (!realtime);
280 if (is_in_rect (event.x, event.y, xruns_x, xruns_y, xruns_w, xruns_h)) {
281 reset_xruns_requested ();
284 return false;
287 private bool was_in_realtime_rect;
289 /* Mouse pointer moved over widget */
290 public override bool motion_notify_event (Gdk.EventMotion event) {
292 var cr = Gdk.cairo_create (this.window);
294 if (is_in_rect (event.x, event.y, realtime_x, realtime_y, realtime_w, realtime_h)) {
295 was_in_realtime_rect = true;
296 set_source_from_color_string (cr, text_color_default, 0.1);
297 cr.rectangle (realtime_x, realtime_y, realtime_w, realtime_h);
298 cr.fill ();
299 } else {
300 if (was_in_realtime_rect) {
301 queue_draw ();
305 return false;
310 } //namespace Jackpanel