Plugin selector useability changes, fix mouse grab bug in plugin barcontroller, preve...
[ardour.git] / gtk2_ardour / tempo_dialog.cc
1 #include <cstdio> // for snprintf, grrr 
2
3 #include <gtkmm/stock.h>
4 #include <gtkmm2ext/utils.h>
5
6 #include "tempo_dialog.h"
7 #include "utils.h"
8
9 #include "i18n.h"
10
11 using namespace Gtk;
12 using namespace Gtkmm2ext;
13 using namespace ARDOUR;
14
15 TempoDialog::TempoDialog (TempoMap& map, jack_nframes_t frame, const string & action)
16         : ArdourDialog ("tempo dialog"),
17           bpm_frame (_("Beats per minute")),
18           ok_button (action),
19           cancel_button (_("Cancel")),
20           when_bar_label (_("Bar")),
21           when_beat_label (_("Beat")),
22           when_table (2, 2),
23           when_frame (_("Location"))
24 {
25         BBT_Time when;
26         Tempo tempo (map.tempo_at (frame));
27         map.bbt_time (frame, when);
28
29         init (when, tempo.beats_per_minute(), true);
30 }
31
32 TempoDialog::TempoDialog (TempoSection& section, const string & action)
33         : ArdourDialog ("tempo dialog"),
34           bpm_frame (_("Beats per minute")),
35           ok_button (action),
36           cancel_button (_("Cancel")),
37           when_bar_label (_("Bar")),
38           when_beat_label (_("Beat")),
39           when_table (2, 2),
40           when_frame (_("Location"))
41 {
42         init (section.start(), section.beats_per_minute(), section.movable());
43 }
44
45 void
46 TempoDialog::init (const BBT_Time& when, double bpm, bool movable)
47 {
48         snprintf (buf, sizeof (buf), "%.2f", bpm);
49         bpm_entry.set_text (buf);
50         bpm_entry.select_region (0, -1);
51         
52         hspacer1.set_border_width (5);
53         hspacer1.pack_start (bpm_entry, false, false);
54         vspacer1.set_border_width (5);
55         vspacer1.pack_start (hspacer1, false, false);
56
57         bpm_frame.add (vspacer1);
58
59         if (movable) {
60                 snprintf (buf, sizeof (buf), "%" PRIu32, when.bars);
61                 when_bar_entry.set_text (buf);
62                 snprintf (buf, sizeof (buf), "%" PRIu32, when.beats);
63                 when_beat_entry.set_text (buf);
64                 
65                 when_bar_entry.set_name ("MetricEntry");
66                 when_beat_entry.set_name ("MetricEntry");
67                 
68                 when_bar_label.set_name ("MetricLabel");
69                 when_beat_label.set_name ("MetricLabel");
70                 
71                 Gtkmm2ext::set_size_request_to_display_given_text (when_bar_entry, "999g", 5, 7);
72                 Gtkmm2ext::set_size_request_to_display_given_text (when_beat_entry, "999g", 5, 7);
73                 
74                 when_table.set_homogeneous (true);
75                 when_table.set_row_spacings (2);
76                 when_table.set_col_spacings (2);
77                 when_table.set_border_width (5);
78                 
79                 when_table.attach (when_bar_label, 0, 1, 0, 1, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
80                 when_table.attach (when_bar_entry, 0, 1, 1, 2, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
81                 
82                 when_table.attach (when_beat_label, 1, 2, 0, 1, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
83                 when_table.attach (when_beat_entry, 1, 2, 1, 2, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
84                 
85                 when_frame.set_name ("MetricDialogFrame");
86                 when_frame.add (when_table);
87
88                 get_vbox()->pack_start (when_frame, false, false);
89         }
90
91         bpm_frame.set_name ("MetricDialogFrame");
92         bpm_entry.set_name ("MetricEntry");
93
94         get_vbox()->pack_start (bpm_frame, false, false);
95         
96         add_button (Stock::CANCEL, RESPONSE_CANCEL);
97         add_button (Stock::APPLY, RESPONSE_ACCEPT);
98         set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
99         set_default_response (RESPONSE_ACCEPT);
100
101         get_vbox()->show_all();
102         bpm_entry.show();
103
104         set_name ("MetricDialog");
105         bpm_entry.signal_key_press_event().connect (mem_fun (*this, &TempoDialog::bpm_key_press), false);
106         bpm_entry.signal_activate().connect (bind (mem_fun (*this, &TempoDialog::response), RESPONSE_ACCEPT));
107         bpm_entry.signal_key_release_event().connect (mem_fun (*this, &TempoDialog::bpm_key_release));
108 }
109
110 bool
111 TempoDialog::bpm_key_press (GdkEventKey* ev)
112 {
113
114 switch (ev->keyval) { 
115
116  case GDK_0:
117  case GDK_1:
118  case GDK_2:
119  case GDK_3:
120  case GDK_4:
121  case GDK_5:
122  case GDK_6:
123  case GDK_7:
124  case GDK_8:
125  case GDK_9:
126  case GDK_KP_0:
127  case GDK_KP_1:
128  case GDK_KP_2:
129  case GDK_KP_3:
130  case GDK_KP_4:
131  case GDK_KP_5:
132  case GDK_KP_6:
133  case GDK_KP_7:
134  case GDK_KP_8:
135  case GDK_KP_9:
136  case GDK_period:
137  case GDK_comma:
138  case  GDK_KP_Delete:
139  case  GDK_KP_Enter:
140  case  GDK_Delete:
141  case  GDK_BackSpace:
142  case  GDK_Escape:
143  case  GDK_Return:
144  case  GDK_Home:
145  case  GDK_End:
146  case  GDK_Left:
147  case  GDK_Right:
148  case  GDK_Num_Lock:
149  case  GDK_Tab:
150     return FALSE;
151  default:
152       break;
153  }
154
155    return TRUE;
156 }
157
158 bool
159 TempoDialog::bpm_key_release (GdkEventKey* ev)
160 {
161         if (bpm_entry.get_text() != "") {
162                 set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
163         } else {
164                 set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
165         }
166         return false;
167 }
168
169 double 
170 TempoDialog::get_bpm ()
171 {
172         double bpm;
173         
174         if (sscanf (bpm_entry.get_text().c_str(), "%lf", &bpm) != 1) {
175                 return 0;
176         }
177
178         return bpm;
179 }       
180
181 bool
182 TempoDialog::get_bbt_time (BBT_Time& requested)
183 {
184         if (sscanf (when_bar_entry.get_text().c_str(), "%" PRIu32, &requested.bars) != 1) {
185                 return false;
186         }
187         
188         if (sscanf (when_beat_entry.get_text().c_str(), "%" PRIu32, &requested.beats) != 1) {
189                 return false;
190         }
191
192         return true;
193 }
194
195
196 MeterDialog::MeterDialog (TempoMap& map, jack_nframes_t frame, const string & action)
197         : ArdourDialog ("meter dialog"),
198           note_frame (_("Meter denominator")),
199           bpb_frame (_("Beats per bar")),
200           ok_button (action),
201           cancel_button (_("Cancel")),
202           when_bar_label (_("Bar")),
203           when_beat_label (_("Beat")),
204           when_frame (_("Location"))
205 {
206         BBT_Time when;
207         frame = map.round_to_bar(frame,0); 
208         Meter meter (map.meter_at(frame));
209
210         map.bbt_time (frame, when);
211         init (when, meter.beats_per_bar(), meter.note_divisor(), true);
212 }
213
214 MeterDialog::MeterDialog (MeterSection& section, const string & action)
215         : ArdourDialog ("meter dialog"),
216           note_frame (_("Meter denominator")),
217           bpb_frame (_("Beats per bar")),
218           ok_button (action),
219           cancel_button (_("Cancel")),
220           when_bar_label (_("Bar")),
221           when_beat_label (_("Beat")),
222           when_frame (_("Location"))
223 {
224         init (section.start(), section.beats_per_bar(), section.note_divisor(), section.movable());
225 }
226
227 void
228 MeterDialog::init (const BBT_Time& when, double bpb, double note_type, bool movable)
229 {
230         snprintf (buf, sizeof (buf), "%.2f", bpb);
231         bpb_entry.set_text (buf);
232         bpb_entry.select_region (0, -1);
233         Gtkmm2ext::set_size_request_to_display_given_text (bpb_entry, "999999g", 5, 5);
234
235         strings.push_back (_("whole (1)"));
236         strings.push_back (_("second (2)"));
237         strings.push_back (_("third (3)"));
238         strings.push_back (_("quarter (4)"));
239         strings.push_back (_("eighth (8)"));
240         strings.push_back (_("sixteenth (16)"));
241         strings.push_back (_("thirty-second (32)"));
242         
243         set_popdown_strings (note_types, strings);
244
245         if (note_type==1.0f)
246                 note_types.set_active_text (_("whole (1)"));
247         else if (note_type==2.0f)
248                 note_types.set_active_text (_("second (2)"));
249         else if (note_type==3.0f)
250                 note_types.set_active_text (_("third (3)"));
251         else if (note_type==4.0f)
252                 note_types.set_active_text (_("quarter (4)"));
253         else if (note_type==8.0f)
254                 note_types.set_active_text (_("eighth (8)"));
255         else if (note_type==16.0f)
256                 note_types.set_active_text (_("sixteenth (16)"));
257         else if (note_type==32.0f)
258                 note_types.set_active_text (_("thirty-second (32)"));
259         else
260                 note_types.set_active_text (_("quarter (4)"));
261                 
262         /* strings.back() just happens to be the longest one to display */
263         // GTK2FIX
264         //Gtkmm2ext::set_size_request_to_display_given_text (note_types, "thirty-second (32)", 7, 7);
265
266         hspacer1.set_border_width (5);
267         hspacer1.pack_start (note_types, false, false);
268         vspacer1.set_border_width (5);
269         vspacer1.pack_start (hspacer1, false, false);
270
271         hspacer2.set_border_width (5);
272         hspacer2.pack_start (bpb_entry, false, false);
273         vspacer2.set_border_width (5);
274         vspacer2.pack_start (hspacer2, false, false);
275
276         note_frame.add (vspacer1);
277         bpb_frame.add (vspacer2);
278
279         if (movable) {
280                 snprintf (buf, sizeof (buf), "%" PRIu32, when.bars);
281                 when_bar_entry.set_text (buf);
282                 snprintf (buf, sizeof (buf), "%" PRIu32, when.beats);
283                 when_beat_entry.set_text (buf);
284                 
285                 when_bar_entry.set_name ("MetricEntry");
286                 when_beat_entry.set_name ("MetricEntry");
287                 
288                 when_bar_label.set_name ("MetricLabel");
289                 when_beat_label.set_name ("MetricLabel");
290                 
291                 Gtkmm2ext::set_size_request_to_display_given_text (when_bar_entry, "999g", 5, 7);
292                 Gtkmm2ext::set_size_request_to_display_given_text (when_beat_entry, "999g", 5, 7);
293                 
294                 when_table.set_homogeneous (true);
295                 when_table.set_row_spacings (2);
296                 when_table.set_col_spacings (2);
297                 when_table.set_border_width (5);
298                 
299                 when_table.attach (when_bar_label, 0, 1, 0, 1, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
300                 when_table.attach (when_bar_entry, 0, 1, 1, 2, Gtk::AttachOptions(0), Gtk::FILL|Gtk::EXPAND);
301                 
302                 when_table.attach (when_beat_label, 1, 2, 0, 1, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
303                 when_table.attach (when_beat_entry, 1, 2, 1, 2, Gtk::AttachOptions(0), Gtk::AttachOptions(0));
304                 
305                 when_frame.set_name ("MetricDialogFrame");
306                 when_frame.add (when_table);
307                 
308                 get_vbox()->pack_start (when_frame, false, false);
309         }
310         get_vbox()->pack_start (bpb_frame, false, false);
311         get_vbox()->pack_start (note_frame, false, false);
312         
313         bpb_frame.set_name ("MetricDialogFrame");
314         note_frame.set_name ("MetricDialogFrame");
315         bpb_entry.set_name ("MetricEntry");
316
317         add_button (Stock::CANCEL, RESPONSE_CANCEL);
318         add_button (Stock::APPLY, RESPONSE_ACCEPT);
319         set_response_sensitive (RESPONSE_ACCEPT, false);
320         set_default_response (RESPONSE_ACCEPT);
321
322         get_vbox()->show_all ();
323         bpb_entry.show ();
324
325         set_name ("MetricDialog");
326         bpb_entry.signal_activate().connect (bind (mem_fun (*this, &MeterDialog::response), RESPONSE_ACCEPT));
327         bpb_entry.signal_key_release_event().connect (mem_fun (*this, &MeterDialog::bpb_key_release));
328         note_types.signal_changed().connect (mem_fun (*this, &MeterDialog::note_types_change));
329 }
330
331 bool
332 MeterDialog::bpb_key_press (GdkEventKey* ev)
333 {
334
335 switch (ev->keyval) { 
336
337  case GDK_0:
338  case GDK_1:
339  case GDK_2:
340  case GDK_3:
341  case GDK_4:
342  case GDK_5:
343  case GDK_6:
344  case GDK_7:
345  case GDK_8:
346  case GDK_9:
347  case GDK_KP_0:
348  case GDK_KP_1:
349  case GDK_KP_2:
350  case GDK_KP_3:
351  case GDK_KP_4:
352  case GDK_KP_5:
353  case GDK_KP_6:
354  case GDK_KP_7:
355  case GDK_KP_8:
356  case GDK_KP_9:
357  case GDK_period:
358  case GDK_comma:
359  case  GDK_KP_Delete:
360  case  GDK_KP_Enter:
361  case  GDK_Delete:
362  case  GDK_BackSpace:
363  case  GDK_Escape:
364  case  GDK_Return:
365  case  GDK_Home:
366  case  GDK_End:
367  case  GDK_Left:
368  case  GDK_Right:
369  case  GDK_Num_Lock:
370  case  GDK_Tab:
371     return FALSE;
372  default:
373       break;
374  }
375
376    return TRUE;
377 }
378
379 bool
380 MeterDialog::bpb_key_release (GdkEventKey* ev)
381 {
382         if (bpb_entry.get_text() != "") {
383                 set_response_sensitive (RESPONSE_ACCEPT, true);
384         } else {
385                 set_response_sensitive (RESPONSE_ACCEPT, false);
386         }
387         return false;
388 }
389
390 void
391 MeterDialog::note_types_change ()
392 {
393         set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
394 }
395
396 double
397 MeterDialog::get_bpb ()
398 {
399         double bpb = 0;
400         
401         if (sscanf (bpb_entry.get_text().c_str(), "%lf", &bpb) != 1) {
402                 return 0;
403         }
404
405         return bpb;
406 }
407         
408 double
409 MeterDialog::get_note_type ()
410 {
411         double note_type = 0;
412         vector<string>::iterator i;
413         string text = note_types.get_active_text();
414         
415         for (i = strings.begin(); i != strings.end(); ++i) {
416                 if (text == *i) {
417                         if (sscanf (text.c_str(), "%*[^0-9]%lf", &note_type) != 1) {
418                                 error << string_compose(_("garbaged note type entry (%1)"), text) << endmsg;
419                                 return 0;
420                         } else {
421                                 break;
422                         }
423                 }
424         } 
425         
426         if (i == strings.end()) {
427                 if (sscanf (text.c_str(), "%lf", &note_type) != 1) {
428                         error << string_compose(_("incomprehensible note type entry (%1)"), text) << endmsg;
429                         return 0;
430                 }
431         }
432
433         return note_type;
434 }
435
436 bool
437 MeterDialog::get_bbt_time (BBT_Time& requested)
438 {
439         requested.ticks = 0;
440
441         if (sscanf (when_bar_entry.get_text().c_str(), "%" PRIu32, &requested.bars) != 1) {
442                 return false;
443         }
444         
445         if (sscanf (when_beat_entry.get_text().c_str(), "%" PRIu32, &requested.beats) != 1) {
446                 return false;
447         }
448
449         return true;
450 }