]> git.0d.be Git - jack_mixer.git/blob - channel.py
Defaults to not displaying solo buttons for every output channels
[jack_mixer.git] / channel.py
1 #!/usr/bin/env python
2 #
3 # This file is part of jack_mixer
4 #
5 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
6 #  
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; version 2 of the License
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 import gtk
21 import gobject
22 import glib
23 import scale
24 import slider
25 import meter
26 import abspeak
27 import math
28 import random
29 from serialization import serialized_object
30
31 try:
32     import phat
33 except:
34     print "PHAT audio widgets not found, some features will not be available"
35     phat = None
36
37 import fpconst
38
39 class channel(gtk.VBox, serialized_object):
40     '''Widget with slider and meter used as base class for more specific channel widgets'''
41     def __init__(self, app, name, stereo):
42         gtk.VBox.__init__(self)
43         self.app = app
44         self.mixer = app.mixer
45         self.gui_factory = app.gui_factory
46         self._channel_name = name
47         self.stereo = stereo
48         self.meter_scale = self.gui_factory.get_default_meter_scale()
49         self.slider_scale = self.gui_factory.get_default_slider_scale()
50         self.slider_adjustment = slider.adjustment_dBFS(self.slider_scale, 0.0)
51         self.balance_adjustment = gtk.Adjustment(0.0, -1.0, 1.0, 0.02)
52         self.future_volume_midi_cc = None
53         self.future_balance_midi_cc = None
54
55     def get_channel_name(self):
56         return self._channel_name
57
58     label_name = None
59     channel = None
60     def set_channel_name(self, name):
61         self._channel_name = name
62         if self.label_name:
63             self.label_name.set_text(name)
64         if self.channel:
65             self.channel.name = name
66     channel_name = property(get_channel_name, set_channel_name)
67
68     def realize(self):
69         #print "Realizing channel \"%s\"" % self.channel_name
70
71         self.slider_adjustment.connect("volume-changed", self.on_volume_changed)
72         self.balance_adjustment.connect("value-changed", self.on_balance_changed)
73         self.connect('midi-event-received', self.on_midi_event_received)
74
75         self.slider = None
76         self.create_slider_widget()
77
78         if self.stereo:
79             self.meter = meter.stereo(self.meter_scale)
80         else:
81             self.meter = meter.mono(self.meter_scale)
82         self.on_vumeter_color_changed(self.gui_factory)
83
84         self.meter.set_events(gtk.gdk.SCROLL_MASK)
85
86         self.gui_factory.connect("default-meter-scale-changed", self.on_default_meter_scale_changed)
87         self.gui_factory.connect("default-slider-scale-changed", self.on_default_slider_scale_changed)
88         self.gui_factory.connect('vumeter-color-changed', self.on_vumeter_color_changed)
89         self.gui_factory.connect('vumeter-color-scheme-changed', self.on_vumeter_color_changed)
90         self.gui_factory.connect('use-custom-widgets-changed', self.on_custom_widgets_changed)
91
92         self.abspeak = abspeak.widget()
93         self.abspeak.connect("reset", self.on_abspeak_reset)
94         self.abspeak.connect("volume-adjust", self.on_abspeak_adjust)
95
96         self.volume_digits = gtk.Entry()
97         self.volume_digits.connect("key-press-event", self.on_volume_digits_key_pressed)
98         self.volume_digits.connect("focus-out-event", self.on_volume_digits_focus_out)
99
100         self.connect("key-press-event", self.on_key_pressed)
101         self.connect("scroll-event", self.on_scroll)
102
103     def unrealize(self):
104         #print "Unrealizing channel \"%s\"" % self.channel_name
105         pass
106
107     def create_balance_widget(self):
108         if self.gui_factory.use_custom_widgets and phat:
109             self.balance = phat.HFanSlider()
110             self.balance.set_default_value(0)
111             self.balance.set_adjustment(self.balance_adjustment)
112         else:
113             self.balance = gtk.HScale(self.balance_adjustment)
114             self.balance.set_draw_value(False)
115         self.pack_start(self.balance, False)
116         self.balance.show()
117
118     def create_slider_widget(self):
119         parent = None
120         if self.slider:
121             parent = self.slider.get_parent()
122             self.slider.destroy()
123         if self.gui_factory.use_custom_widgets:
124             self.slider = slider.CustomSliderWidget(self.slider_adjustment)
125         else:
126             self.slider = slider.GtkSlider(self.slider_adjustment)
127         if parent:
128             parent.pack_start(self.slider)
129             parent.reorder_child(self.slider, 0)
130         self.slider.show()
131
132     def on_default_meter_scale_changed(self, gui_factory, scale):
133         #print "Default meter scale change detected."
134         self.meter.set_scale(scale)
135
136     def on_default_slider_scale_changed(self, gui_factory, scale):
137         #print "Default slider scale change detected."
138         self.slider_scale = scale
139         self.slider_adjustment.set_scale(scale)
140         self.channel.set_midi_scale(self.slider_scale.scale)
141
142     def on_vumeter_color_changed(self, gui_factory, *args):
143         color = gui_factory.get_vumeter_color()
144         color_scheme = gui_factory.get_vumeter_color_scheme()
145         if color_scheme != 'solid':
146             self.meter.set_color(None)
147         else:
148             self.meter.set_color(gtk.gdk.color_parse(color))
149
150     def on_custom_widgets_changed(self, gui_factory, value):
151         self.balance.destroy()
152         self.create_balance_widget()
153         self.create_slider_widget()
154
155     def on_abspeak_adjust(self, abspeak, adjust):
156         #print "abspeak adjust %f" % adjust
157         self.slider_adjustment.set_value_db(self.slider_adjustment.get_value_db() + adjust)
158         self.channel.abspeak = None
159         #self.update_volume(False)   # We want to update gui even if actual decibels have not changed (scale wrap for example)
160
161     def on_abspeak_reset(self, abspeak):
162         #print "abspeak reset"
163         self.channel.abspeak = None
164
165     def on_volume_digits_key_pressed(self, widget, event):
166         if (event.keyval == gtk.keysyms.Return or event.keyval == gtk.keysyms.KP_Enter):
167             db_text = self.volume_digits.get_text()
168             try:
169                 db = float(db_text)
170                 #print "Volume digits confirmation \"%f dBFS\"" % db
171             except (ValueError), e:
172                 #print "Volume digits confirmation ignore, reset to current"
173                 self.update_volume(False)
174                 return
175             self.slider_adjustment.set_value_db(db)
176             #self.grab_focus()
177             #self.update_volume(False)   # We want to update gui even if actual decibels have not changed (scale wrap for example)
178
179     def on_volume_digits_focus_out(self, widget, event):
180         #print "volume digits focus out detected"
181         self.update_volume(False)
182
183     def read_meter(self):
184         if self.stereo:
185             meter_left, meter_right = self.channel.meter
186             self.meter.set_values(meter_left, meter_right)
187         else:
188             self.meter.set_value(self.channel.meter[0])
189
190         self.abspeak.set_peak(self.channel.abspeak)
191
192     def on_scroll(self, widget, event):
193         if event.direction == gtk.gdk.SCROLL_DOWN:
194             self.slider_adjustment.step_down()
195         elif event.direction == gtk.gdk.SCROLL_UP:
196             self.slider_adjustment.step_up()
197         return True
198
199     def update_volume(self, update_engine):
200         db = self.slider_adjustment.get_value_db()
201
202         db_text = "%.2f" % db
203         self.volume_digits.set_text(db_text)
204
205         if update_engine:
206             #print "Setting engine volume to " + db_text
207             self.channel.volume = db
208
209     def on_volume_changed(self, adjustment):
210         self.update_volume(True)
211
212     def on_balance_changed(self, adjustment):
213         balance = self.balance_adjustment.get_value()
214         #print "%s balance: %f" % (self.channel_name, balance)
215         self.channel.balance = balance
216
217     def on_key_pressed(self, widget, event):
218         if (event.keyval == gtk.keysyms.Up):
219             #print self.channel_name + " Up"
220             self.slider_adjustment.step_up()
221             return True
222         elif (event.keyval == gtk.keysyms.Down):
223             #print self.channel_name + " Down"
224             self.slider_adjustment.step_down()
225             return True
226
227         return False
228
229     def serialize(self, object_backend):
230         object_backend.add_property("volume", "%f" % self.slider_adjustment.get_value_db())
231         object_backend.add_property("balance", "%f" % self.balance_adjustment.get_value())
232
233         if self.channel.volume_midi_cc:
234             object_backend.add_property('volume_midi_cc', str(self.channel.volume_midi_cc))
235         if self.channel.balance_midi_cc:
236             object_backend.add_property('balance_midi_cc', str(self.channel.balance_midi_cc))
237
238     def unserialize_property(self, name, value):
239         if name == "volume":
240             self.slider_adjustment.set_value_db(float(value))
241             return True
242         if name == "balance":
243             self.balance_adjustment.set_value(float(value))
244             return True
245         if name == 'volume_midi_cc':
246             self.future_volume_midi_cc = int(value)
247             return True
248         if name == 'balance_midi_cc':
249             self.future_balance_midi_cc = int(value)
250             return True
251         return False
252
253     def on_midi_event_received(self, *args):
254         self.slider_adjustment.set_value_db(self.channel.volume)
255         self.balance_adjustment.set_value(self.channel.balance)
256
257     def midi_change_callback(self, *args):
258         # the changes are not applied directly to the widgets as they
259         # absolutely have to be done from the gtk thread.
260         self.emit('midi-event-received')
261
262 gobject.signal_new('midi-event-received', channel,
263                 gobject.SIGNAL_RUN_FIRST | gobject.SIGNAL_ACTION,
264                 gobject.TYPE_NONE, ())
265
266 class input_channel(channel):
267     def __init__(self, app, name, stereo):
268         channel.__init__(self, app, name, stereo)
269
270     def realize(self):
271         self.channel = self.mixer.add_channel(self.channel_name, self.stereo)
272         if self.channel == None:
273             raise Exception,"Cannot create a channel"
274         channel.realize(self)
275         if self.future_volume_midi_cc:
276             self.channel.volume_midi_cc = self.future_volume_midi_cc
277         if self.future_balance_midi_cc:
278             self.channel.balance_midi_cc = self.future_balance_midi_cc
279         self.channel.midi_scale = self.slider_scale.scale
280         self.channel.midi_change_callback = self.midi_change_callback
281
282         self.on_volume_changed(self.slider_adjustment)
283         self.on_balance_changed(self.balance_adjustment)
284
285         # vbox child at upper part
286         self.vbox = gtk.VBox()
287         self.pack_start(self.vbox, False)
288         self.label_name = gtk.Label()
289         self.label_name.set_text(self.channel_name)
290         self.label_name.set_size_request(0, -1)
291         self.label_name_event_box = gtk.EventBox()
292         self.label_name_event_box.connect("button-press-event", self.on_label_mouse)
293         self.label_name_event_box.add(self.label_name)
294         self.vbox.pack_start(self.label_name_event_box, True)
295 #         self.label_stereo = gtk.Label()
296 #         if self.stereo:
297 #             self.label_stereo.set_text("stereo")
298 #         else:
299 #             self.label_stereo.set_text("mono")
300 #         self.label_stereo.set_size_request(0, -1)
301 #         self.vbox.pack_start(self.label_stereo, True)
302
303         # hbox for mute and solo buttons
304         self.hbox_mutesolo = gtk.HBox()
305
306         self.mute = gtk.ToggleButton()
307         self.mute.set_label("M")
308         self.mute.set_active(self.channel.mute)
309         self.mute.connect("toggled", self.on_mute_toggled)
310         self.hbox_mutesolo.pack_start(self.mute, True)
311
312         self.solo = gtk.ToggleButton()
313         self.solo.set_label("S")
314         self.solo.set_active(self.channel.solo)
315         self.solo.connect("toggled", self.on_solo_toggled)
316         self.hbox_mutesolo.pack_start(self.solo, True)
317
318         self.vbox.pack_start(self.hbox_mutesolo, False)
319
320         frame = gtk.Frame()
321         frame.set_shadow_type(gtk.SHADOW_IN)
322         frame.add(self.abspeak);
323         self.pack_start(frame, False)
324
325         # hbox child at lower part
326         self.hbox = gtk.HBox()
327         self.hbox.pack_start(self.slider, True)
328         frame = gtk.Frame()
329         frame.set_shadow_type(gtk.SHADOW_IN)
330         frame.add(self.meter);
331         self.hbox.pack_start(frame, True)
332         frame = gtk.Frame()
333         frame.set_shadow_type(gtk.SHADOW_IN)
334         frame.add(self.hbox);
335         self.pack_start(frame, True)
336
337         self.volume_digits.set_size_request(0, -1)
338         self.pack_start(self.volume_digits, False)
339
340         self.create_balance_widget()
341
342     def add_control_group(self, channel):
343         control_group = ControlGroup(channel)
344         control_group.show_all()
345         self.vbox.pack_start(control_group, False)
346
347     def unrealize(self):
348         channel.unrealize(self)
349         self.channel.remove()
350         self.channel = False
351
352     channel_properties_dialog = None
353     def on_channel_properties(self):
354         if not self.channel_properties_dialog:
355             self.channel_properties_dialog = ChannelPropertiesDialog(self)
356         self.channel_properties_dialog.show()
357         self.channel_properties_dialog.present()
358
359     def on_label_mouse(self, widget, event):
360         if event.type == gtk.gdk._2BUTTON_PRESS:
361             if event.button == 1:
362                 self.on_channel_properties()
363
364     def on_mute_toggled(self, button):
365         self.channel.mute = self.mute.get_active()
366
367     def on_solo_toggled(self, button):
368         self.channel.solo = self.solo.get_active()
369
370     def serialization_name(self):
371         return input_channel_serialization_name()
372
373     def serialize(self, object_backend):
374         object_backend.add_property("name", self.channel_name)
375         if self.stereo:
376             object_backend.add_property("type", "stereo")
377         else:
378             object_backend.add_property("type", "mono")
379         channel.serialize(self, object_backend)
380
381     def unserialize_property(self, name, value):
382         if name == "name":
383             self.channel_name = str(value)
384             return True
385         if name == "type":
386             if value == "stereo":
387                 self.stereo = True
388                 return True
389             if value == "mono":
390                 self.stereo = False
391                 return True
392         return channel.unserialize_property(self, name, value)
393
394 def input_channel_serialization_name():
395     return "input_channel"
396
397
398 available_colours = [
399     ('#ef2929', '#cc0000', '#a40000'),
400     ('#729fcf', '#3465a4', '#204a87'),
401     ('#8aa234', '#73d216', '#4e9a06'),
402     ('#fce84f', '#edd400', '#c4a000'),
403     ('#fcaf3e', '#f57900', '#ce5c00'),
404     ('#e9b96e', '#c17d11', '#8f5902'),
405     ('#ad7fa8', '#75507b', '#5c3566'),
406 ]
407
408 class output_channel(channel):
409     colours = available_colours[:]
410     display_solo_buttons = False
411
412     def __init__(self, app, name, stereo):
413         channel.__init__(self, app, name, stereo)
414
415     def realize(self):
416         channel.realize(self)
417         self.channel = self.mixer.add_output_channel(self.channel_name, self.stereo)
418         if self.channel == None:
419             raise Exception,"Cannot create a channel"
420         channel.realize(self)
421
422         self.channel.midi_scale = self.slider_scale.scale
423         self.channel.midi_change_callback = self.midi_change_callback
424
425         self.on_volume_changed(self.slider_adjustment)
426         self.on_balance_changed(self.balance_adjustment)
427
428         # vbox child at upper part
429         self.vbox = gtk.VBox()
430         self.pack_start(self.vbox, False)
431         self.label_name = gtk.Label()
432         self.label_name.set_text(self.channel_name)
433         self.label_name.set_size_request(0, -1)
434         self.label_name_event_box = gtk.EventBox()
435         self.label_name_event_box.connect('button-press-event', self.on_label_mouse)
436         self.label_name_event_box.add(self.label_name)
437         if not self.colours:
438             self.colours = available_colours[:]
439         for color in self.colours:
440             self.color_tuple = [gtk.gdk.color_parse(color[x]) for x in range(3)]
441             self.colours.remove(color)
442             break
443         self.label_name_event_box.modify_bg(gtk.STATE_NORMAL, self.color_tuple[1])
444         self.vbox.pack_start(self.label_name_event_box, True)
445         frame = gtk.Frame()
446         frame.set_shadow_type(gtk.SHADOW_IN)
447         frame.add(self.abspeak);
448         self.vbox.pack_start(frame, False)
449
450         # hbox child at lower part
451         self.hbox = gtk.HBox()
452         self.hbox.pack_start(self.slider, True)
453         frame = gtk.Frame()
454         frame.set_shadow_type(gtk.SHADOW_IN)
455         frame.add(self.meter);
456         self.hbox.pack_start(frame, True)
457         frame = gtk.Frame()
458         frame.set_shadow_type(gtk.SHADOW_IN)
459         frame.add(self.hbox);
460         self.pack_start(frame, True)
461
462         self.volume_digits.set_size_request(0, -1)
463         self.pack_start(self.volume_digits, False)
464
465         self.create_balance_widget()
466
467     channel_properties_dialog = None
468     def on_channel_properties(self):
469         if not self.channel_properties_dialog:
470             self.channel_properties_dialog = OutputChannelPropertiesDialog(self)
471         self.channel_properties_dialog.show()
472         self.channel_properties_dialog.present()
473
474     def on_label_mouse(self, widget, event):
475         if event.type == gtk.gdk._2BUTTON_PRESS:
476             if event.button == 1:
477                 self.on_channel_properties()
478
479     def unrealize(self):
480         channel.unrealize(self)
481         self.channel = False
482
483     def serialization_name(self):
484         return output_channel_serialization_name()
485
486     def serialize(self, object_backend):
487         object_backend.add_property("name", self.channel_name)
488         if self.stereo:
489             object_backend.add_property("type", "stereo")
490         else:
491             object_backend.add_property("type", "mono")
492         channel.serialize(self, object_backend)
493
494     def unserialize_property(self, name, value):
495         if name == "name":
496             self.channel_name = str(value)
497             return True
498         if name == "type":
499             if value == "stereo":
500                 self.stereo = True
501                 return True
502             if value == "mono":
503                 self.stereo = False
504                 return True
505         return channel.unserialize_property(self, name, value)
506
507 def output_channel_serialization_name():
508     return "output_channel"
509
510 class main_mix(channel):
511     def __init__(self, app):
512         channel.__init__(self, app, "MAIN", True)
513
514     def realize(self):
515         channel.realize(self)
516         self.channel = self.mixer.main_mix_channel
517         self.channel.midi_scale = self.slider_scale.scale
518         self.channel.midi_change_callback = self.midi_change_callback
519
520         self.on_volume_changed(self.slider_adjustment)
521         self.on_balance_changed(self.balance_adjustment)
522
523         # vbox child at upper part
524         self.vbox = gtk.VBox()
525         self.pack_start(self.vbox, False)
526         self.label_name = gtk.Label()
527         self.label_name.set_text(self.channel_name)
528         self.label_name.set_size_request(0, -1)
529         self.vbox.pack_start(self.label_name, False)
530         frame = gtk.Frame()
531         frame.set_shadow_type(gtk.SHADOW_IN)
532         frame.add(self.abspeak);
533         self.vbox.pack_start(frame, False)
534
535         # hbox child at lower part
536         self.hbox = gtk.HBox()
537         self.hbox.pack_start(self.slider, True)
538         frame = gtk.Frame()
539         frame.set_shadow_type(gtk.SHADOW_IN)
540         frame.add(self.meter);
541         self.hbox.pack_start(frame, True)
542         frame = gtk.Frame()
543         frame.set_shadow_type(gtk.SHADOW_IN)
544         frame.add(self.hbox);
545         self.pack_start(frame, True)
546
547         self.volume_digits.set_size_request(0, -1)
548         self.pack_start(self.volume_digits, False)
549
550         self.create_balance_widget()
551
552     def unrealize(self):
553         channel.unrealize(self)
554         self.channel = False
555
556     def serialization_name(self):
557         return main_mix_serialization_name()
558
559 def main_mix_serialization_name():
560     return "main_mix_channel"
561
562
563 class ChannelPropertiesDialog(gtk.Dialog):
564     def __init__(self, parent):
565         self.channel = parent
566         self.mixer = self.channel.mixer
567         gtk.Dialog.__init__(self,
568                         'Channel "%s" Properties' % self.channel.channel_name,
569                         self.channel.gui_factory.topwindow)
570         self.create_ui()
571         self.fill_ui()
572
573         self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
574         self.add_button(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY)
575
576         self.connect('response', self.on_response_cb)
577         self.connect('delete-event', self.on_response_cb)
578
579     def create_frame(self, label, child):
580         frame = gtk.Frame('')
581         frame.set_border_width(3)
582         #frame.set_shadow_type(gtk.SHADOW_NONE)
583         frame.get_label_widget().set_markup('<b>%s</b>' % label)
584
585         alignment = gtk.Alignment(0, 0, 1, 1)
586         alignment.set_padding(0, 0, 12, 0)
587         frame.add(alignment)
588         alignment.add(child)
589
590         return frame
591
592     def create_ui(self):
593         vbox = gtk.VBox()
594         self.vbox.add(vbox)
595
596         table = gtk.Table(2, 2, False)
597         vbox.pack_start(self.create_frame('Properties', table))
598         table.set_row_spacings(5)
599         table.set_col_spacings(5)
600
601         table.attach(gtk.Label('Name'), 0, 1, 0, 1)
602         self.entry_name = gtk.Entry()
603         table.attach(self.entry_name, 1, 2, 0, 1)
604
605         table.attach(gtk.Label('Mode'), 0, 1, 1, 2)
606         self.mode_hbox = gtk.HBox()
607         table.attach(self.mode_hbox, 1, 2, 1, 2)
608         self.mono = gtk.RadioButton(label='Mono')
609         self.stereo = gtk.RadioButton(label='Stereo', group=self.mono)
610         self.mode_hbox.pack_start(self.mono)
611         self.mode_hbox.pack_start(self.stereo)
612
613         table = gtk.Table(2, 3, False)
614         vbox.pack_start(self.create_frame('MIDI Control Channels', table))
615         table.set_row_spacings(5)
616         table.set_col_spacings(5)
617
618         table.attach(gtk.Label('Volume'), 0, 1, 0, 1)
619         self.entry_volume_cc = gtk.Entry()
620         self.entry_volume_cc.set_editable(False)
621         self.entry_volume_cc.set_width_chars(3)
622         table.attach(self.entry_volume_cc, 1, 2, 0, 1)
623         self.button_sense_midi_volume = gtk.Button('Autoset')
624         self.button_sense_midi_volume.connect('clicked',
625                         self.on_sense_midi_volume_clicked)
626         table.attach(self.button_sense_midi_volume, 2, 3, 0, 1)
627
628         table.attach(gtk.Label('Balance'), 0, 1, 1, 2)
629         self.entry_balance_cc = gtk.Entry()
630         self.entry_balance_cc.set_width_chars(3)
631         self.entry_balance_cc.set_editable(False)
632         table.attach(self.entry_balance_cc, 1, 2, 1, 2)
633         self.button_sense_midi_balance = gtk.Button('Autoset')
634         self.button_sense_midi_balance.connect('clicked',
635                         self.on_sense_midi_balance_clicked)
636         table.attach(self.button_sense_midi_balance, 2, 3, 1, 2)
637
638         self.vbox.show_all()
639
640     def fill_ui(self):
641         self.entry_name.set_text(self.channel.channel_name)
642         if self.channel.channel.is_stereo:
643             self.stereo.set_active(True)
644         else:
645             self.mono.set_active(True)
646         self.mode_hbox.set_sensitive(False)
647         self.entry_volume_cc.set_text('%s' % self.channel.channel.volume_midi_cc)
648         self.entry_balance_cc.set_text('%s' % self.channel.channel.balance_midi_cc)
649
650     def sense_popup_dialog(self, entry):
651         window = gtk.Window(gtk.WINDOW_TOPLEVEL)
652         window.set_destroy_with_parent(True)
653         window.set_transient_for(self)
654         window.set_decorated(False)
655         window.set_modal(True)
656         window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
657         window.set_border_width(10)
658
659         vbox = gtk.VBox(10)
660         window.add(vbox)
661         window.timeout = 5
662         vbox.pack_start(gtk.Label('Please move the MIDI control you want to use for this function.'))
663         timeout_label = gtk.Label('This window will close in 5 seconds')
664         vbox.pack_start(timeout_label)
665         def close_sense_timeout(window, entry):
666             window.timeout -= 1
667             timeout_label.set_text('This window will close in %d seconds.' % window.timeout)
668             if window.timeout == 0:
669                 window.destroy()
670                 entry.set_text('%s' % self.mixer.last_midi_channel)
671                 return False
672             return True
673         window.show_all()
674         glib.timeout_add_seconds(1, close_sense_timeout, window, entry)
675
676     def on_sense_midi_volume_clicked(self, *args):
677         self.sense_popup_dialog(self.entry_volume_cc)
678
679     def on_sense_midi_balance_clicked(self, *args):
680         self.sense_popup_dialog(self.entry_balance_cc)
681
682     def on_response_cb(self, dlg, response_id, *args):
683         self.channel.channel_properties_dialog = None
684         self.destroy()
685         if response_id == gtk.RESPONSE_APPLY:
686             name = self.entry_name.get_text()
687             self.channel.channel_name = name
688             self.channel.channel.volume_midi_cc = int(self.entry_volume_cc.get_text())
689             self.channel.channel.balance_midi_cc = int(self.entry_balance_cc.get_text())
690
691
692 class NewChannelDialog(ChannelPropertiesDialog):
693     def __init__(self, parent, mixer):
694         gtk.Dialog.__init__(self, 'New Channel', parent)
695         self.mixer = mixer
696         self.create_ui()
697
698         self.stereo.set_active(True) # default to stereo
699
700         self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
701         self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
702
703     def get_result(self):
704         return {'name': self.entry_name.get_text(),
705                 'stereo': self.stereo.get_active(),
706                 'volume_cc': self.entry_volume_cc.get_text(),
707                 'balance_cc': self.entry_balance_cc.get_text()
708                }
709
710 class OutputChannelPropertiesDialog(ChannelPropertiesDialog):
711     def create_ui(self):
712         ChannelPropertiesDialog.create_ui(self)
713
714         vbox = gtk.VBox()
715         self.vbox.pack_start(self.create_frame('Input Channels', vbox))
716
717         self.display_solo_buttons = gtk.CheckButton('Display solo buttons')
718         vbox.pack_start(self.display_solo_buttons)
719
720         self.vbox.show_all()
721
722
723 class NewOutputChannelDialog(OutputChannelPropertiesDialog):
724     def __init__(self, parent, mixer):
725         gtk.Dialog.__init__(self, 'New Output Channel', parent)
726         self.mixer = mixer
727         self.create_ui()
728
729         # TODO: disable mode for output channels as mono output channels may
730         # not be correctly handled yet.
731         self.mode_hbox.set_sensitive(False)
732         self.stereo.set_active(True) # default to stereo
733
734         self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
735         self.add_button(gtk.STOCK_ADD, gtk.RESPONSE_OK)
736
737     def get_result(self):
738         return {'name': self.entry_name.get_text(),
739                 'stereo': self.stereo.get_active(),
740                 'volume_cc': self.entry_volume_cc.get_text(),
741                 'balance_cc': self.entry_balance_cc.get_text(),
742                 'display_solo_buttons': self.display_solo_buttons.get_active(),
743                }
744
745
746 class ControlGroup(gtk.Alignment):
747     def __init__(self, output_channel):
748         gtk.Alignment.__init__(self, 0.5, 0.5, 0, 0)
749         self.output_channel = output_channel
750
751         hbox = gtk.HBox()
752         self.add(hbox)
753
754         mute = gtk.ToggleButton()
755         mute.set_label("M")
756         #mute.set_active(self.channel.mute)
757         #mute.connect("toggled", self.on_mute_toggled)
758         hbox.pack_start(mute, False)
759
760         solo = gtk.ToggleButton()
761         solo.set_label("S")
762         #solo.set_active(self.channel.solo)
763         #solo.connect("toggled", self.on_solo_toggled)
764         if self.output_channel.display_solo_buttons:
765             hbox.pack_start(solo, True)
766
767         mute.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
768         mute.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
769         mute.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
770         solo.modify_bg(gtk.STATE_PRELIGHT, output_channel.color_tuple[0])
771         solo.modify_bg(gtk.STATE_NORMAL, output_channel.color_tuple[1])
772         solo.modify_bg(gtk.STATE_ACTIVE, output_channel.color_tuple[2])
773
774