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