0
|
1 # taken from SnackMix -- now that's reusable code
|
|
2 from Tix import *
|
|
3 import time
|
|
4
|
|
5 class Fadable:
|
|
6 """Fading mixin: must mix in with a Tk widget (or something that has
|
|
7 'after' at least) This is currently used by VolumeBox and MixerTk.
|
|
8 It's probably too specialized to be used elsewhere, but could possibly
|
|
9 work with an Entry or a Meter, I guess.
|
|
10
|
|
11 var is a Tk variable that should be used to set and get the levels.
|
|
12 If use_fades is true, it will use fades to move between levels.
|
|
13 If key_bindings is true, it will install these keybindings:
|
|
14
|
|
15 Press a number to fade to that amount (e.g. '5' = 50%). Also,
|
|
16 '`' (grave) will fade to 0 and '0' will fade to 100%.
|
|
17
|
|
18 If mouse_bindings is true, the following mouse bindings will be
|
|
19 installed: Right clicking toggles muting. The mouse wheel will
|
|
20 raise or lower the volume. Shift-mouse wheeling will cause a more
|
|
21 precise volume adjustment. Control-mouse wheeling will cause a
|
|
22 longer fade."""
|
|
23 def __init__(self, var, wheel_step=5, use_fades=1, key_bindings=1,
|
|
24 mouse_bindings=1):
|
|
25 self.use_fades = use_fades # whether increase and decrease should fade
|
|
26 self.wheel_step = wheel_step # amount that increase and descrease should
|
|
27 # change volume (by default)
|
|
28
|
|
29 self.fade_start_level = 0
|
|
30 self.fade_end_level = 0
|
|
31 self.fade_start_time = 0
|
|
32 self.fade_length = 1
|
|
33 self.fade_step_time = 10
|
|
34 self.fade_var = var
|
|
35 self.fading = 0 # whether a fade is in progress
|
|
36
|
|
37 if key_bindings:
|
|
38 for k in range(1, 10):
|
|
39 self.bind("<Key-%d>" % k,
|
111
|
40 lambda evt, k=k: self.fade(k * 10.0))
|
0
|
41 self.bind("<Key-0>", lambda evt: self.fade(100))
|
|
42 self.bind("<grave>", lambda evt: self.fade(0))
|
|
43
|
|
44 # up / down arrows
|
|
45 self.bind("<Key-Up>", lambda evt: self.increase())
|
|
46 self.bind("<Key-Down>", lambda evt: self.decrease())
|
|
47
|
|
48 if mouse_bindings:
|
|
49 # right mouse button toggles muting
|
|
50 # self.bind('<3>', lambda evt: self.toggle_mute())
|
|
51 # "NOT ANY MORE!" - homer
|
|
52
|
|
53 # mouse wheel
|
|
54 self.bind('<4>', lambda evt: self.increase())
|
|
55 self.bind('<5>', lambda evt: self.decrease())
|
|
56
|
|
57 # modified mouse wheel
|
|
58 self.bind('<Shift-4>', lambda evt: self.increase(multiplier=0.2))
|
|
59 self.bind('<Shift-5>', lambda evt: self.decrease(multiplier=0.2))
|
|
60 self.bind('<Control-4>', lambda evt: self.increase(length=1))
|
|
61 self.bind('<Control-5>', lambda evt: self.decrease(length=1))
|
|
62
|
|
63 self.last_level = 0 # used for muting
|
|
64 def fade(self, value, length=0.5, step_time=10):
|
|
65 """Fade to value in length seconds with steps every step_time
|
|
66 seconds"""
|
|
67 self.fade_start_time = time.time()
|
|
68 self.fade_length = length
|
|
69
|
|
70 self.fade_start_level = self.fade_var.get()
|
|
71 self.fade_end_level = value
|
|
72
|
|
73 self.fade_step_time = step_time
|
111
|
74 self.fading = 1
|
|
75 self.do_fade()
|
0
|
76 def do_fade(self):
|
|
77 """Actually performs the fade for Fadable.fade. Shouldn't be called
|
|
78 directly."""
|
|
79 now = time.time()
|
|
80 elapsed = now - self.fade_start_time
|
|
81 complete = elapsed / self.fade_length
|
|
82 complete = min(1.0, complete)
|
|
83 diff = self.fade_end_level - self.fade_start_level
|
|
84 newlevel = (complete * diff) + self.fade_start_level
|
|
85 self.fade_var.set(newlevel)
|
|
86 if complete < 1:
|
|
87 self.after(self.fade_step_time, self.do_fade)
|
|
88 else:
|
|
89 self.fading = 0
|
|
90 def increase(self, multiplier=1, length=0.3):
|
|
91 """Increases the volume by multiplier * wheel_step. If use_fades is
|
|
92 true, it do this as a fade over length time."""
|
|
93 amount = self.wheel_step * multiplier
|
|
94 if self.fading:
|
|
95 newlevel = self.fade_end_level + amount
|
|
96 else:
|
|
97 newlevel = self.fade_var.get() + amount
|
|
98 newlevel = min(100, newlevel)
|
|
99 self.set_volume(newlevel, length)
|
|
100 def decrease(self, multiplier=1, length=0.3):
|
|
101 """Descreases the volume by multiplier * wheel_step. If use_fades
|
|
102 is true, it do this as a fade over length time."""
|
|
103 amount = self.wheel_step * multiplier
|
|
104 if self.fading:
|
|
105 newlevel = self.fade_end_level - amount
|
|
106 else:
|
|
107 newlevel = self.fade_var.get() - amount
|
|
108 newlevel = max(0, newlevel)
|
|
109 self.set_volume(newlevel, length)
|
|
110 def set_volume(self, newlevel, length=0.3):
|
|
111 """Sets the volume to newlevel, performing a fade of length if
|
|
112 use_fades is true."""
|
|
113 if self.use_fades:
|
|
114 self.fade(newlevel, length=length)
|
|
115 else:
|
|
116 self.fade_var.set(newlevel)
|
|
117 def toggle_mute(self):
|
|
118 """Toggles whether the volume is being muted."""
|
|
119 curlevel = self.fade_var.get()
|
|
120 if curlevel:
|
|
121 newlevel = 0
|
|
122 self.last_level = curlevel
|
|
123 self['bg'] = 'red' # TODO: let them choose these colors
|
|
124 else:
|
|
125 newlevel = self.last_level
|
|
126 self['bg'] = 'lightGray'
|
|
127
|
|
128 self.fade_var.set(newlevel)
|
|
129
|
|
130 if __name__ == "__main__":
|
|
131 class SubScale(Scale, Fadable):
|
|
132 def __init__(self, master, *args, **kw):
|
|
133 self.scale_var = DoubleVar()
|
|
134 kw['variable'] = self.scale_var
|
|
135 Scale.__init__(self, master, *args, **kw)
|
|
136 Fadable.__init__(self, var=self.scale_var)
|
|
137
|
|
138 root = Tk()
|
|
139 root.tk_focusFollowsMouse()
|
|
140 ss = SubScale(root, from_=100, to_=0,)
|
|
141 ss.pack()
|
|
142 mainloop()
|