Merge lp:~samuel-buffet/entertainer/volume_management into lp:entertainer
- volume_management
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Paul Hummer |
Approved revision: | 404 |
Merged at revision: | not available |
Proposed branch: | lp:~samuel-buffet/entertainer/volume_management |
Merge into: | lp:entertainer |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~samuel-buffet/entertainer/volume_management |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paul Hummer | Approve | ||
Review via email: mp+7992@code.launchpad.net |
Commit message
It's now possible to change the player's volume level.
Description of the change
Samuel Buffet (samuel-buffet) wrote : | # |
- 402. By Samuel Buffet
-
Merged with trunk 389.
- 403. By Samuel Buffet
-
Fixes after Paul's comments.
- 404. By Samuel Buffet
-
Merged with trunk 393.
Samuel Buffet (samuel-buffet) wrote : | # |
Devs,
I've pushed some modifications after Paul's comments.
new diff :
=== added file 'cfg/themes/
Binary files cfg/themes/
=== added file 'cfg/themes/
Binary files cfg/themes/
=== added file 'cfg/themes/
Binary files cfg/themes/
=== added file 'cfg/themes/
Binary files cfg/themes/
=== added file 'cfg/themes/
Binary files cfg/themes/
=== added file 'cfg/themes/
Binary files cfg/themes/
=== modified file 'entertainerlib
--- entertainerlib/
+++ entertainerlib/
@@ -18,6 +18,8 @@
PLAYER_
PLAYER_
PLAYER_
+ PLAYER_VOLUME_UP = 6
+ PLAYER_VOLUME_DOWN = 7
# Navigation events
NAVIGATE_UP = 20
=== modified file 'entertainerlib
--- entertainerlib/
+++ entertainerlib/
@@ -20,6 +20,7 @@
from entertainerlib.
from entertainerlib.
from entertainerlib.
+from entertainerlib.
from entertainerlib.
from entertainerlib.
@@ -92,6 +93,7 @@
+ self.player.
# Initialize menu overlay texture
@@ -101,6 +103,15 @@
+ self.volume_
+ self.stage.
+ self.volume_
+ self._on_
+ self.fade_
+ alpha = clutter.
+ clutter.
Paul Hummer (rockstar) : | # |
Preview Diff
1 | === added file 'cfg/themes/Black/images/volume.png' |
2 | Binary files cfg/themes/Black/images/volume.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume.png 2009-06-01 19:59:57 +0000 differ |
3 | === added file 'cfg/themes/Black/images/volume_filled.png' |
4 | Binary files cfg/themes/Black/images/volume_filled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume_filled.png 2009-06-01 19:25:27 +0000 differ |
5 | === added file 'cfg/themes/Black/images/volume_unfilled.png' |
6 | Binary files cfg/themes/Black/images/volume_unfilled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Black/images/volume_unfilled.png 2009-06-01 19:25:27 +0000 differ |
7 | === added file 'cfg/themes/Default/images/volume.png' |
8 | Binary files cfg/themes/Default/images/volume.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume.png 2009-06-01 19:59:57 +0000 differ |
9 | === added file 'cfg/themes/Default/images/volume_filled.png' |
10 | Binary files cfg/themes/Default/images/volume_filled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume_filled.png 2009-06-01 19:25:27 +0000 differ |
11 | === added file 'cfg/themes/Default/images/volume_unfilled.png' |
12 | Binary files cfg/themes/Default/images/volume_unfilled.png 1970-01-01 00:00:00 +0000 and cfg/themes/Default/images/volume_unfilled.png 2009-06-01 19:25:27 +0000 differ |
13 | === modified file 'entertainerlib/frontend/gui/user_event.py' |
14 | --- entertainerlib/frontend/gui/user_event.py 2009-05-06 03:40:22 +0000 |
15 | +++ entertainerlib/frontend/gui/user_event.py 2009-05-29 10:33:32 +0000 |
16 | @@ -18,6 +18,8 @@ |
17 | PLAYER_PREVIOUS = 3 |
18 | PLAYER_SKIP_FORWARD = 4 |
19 | PLAYER_SKIP_BACKWARD = 5 |
20 | + PLAYER_VOLUME_UP = 6 |
21 | + PLAYER_VOLUME_DOWN = 7 |
22 | |
23 | # Navigation events |
24 | NAVIGATE_UP = 20 |
25 | |
26 | === modified file 'entertainerlib/frontend/gui/user_interface.py' |
27 | --- entertainerlib/frontend/gui/user_interface.py 2009-06-03 01:54:03 +0000 |
28 | +++ entertainerlib/frontend/gui/user_interface.py 2009-06-27 10:51:35 +0000 |
29 | @@ -20,6 +20,7 @@ |
30 | from entertainerlib.frontend.gui.user_event import UserEvent |
31 | from entertainerlib.frontend.gui.widgets.menu_overlay import MenuOverlay |
32 | from entertainerlib.frontend.media_player import MediaPlayer |
33 | +from entertainerlib.frontend.gui.widgets.volume_indicator import VolumeIndicator |
34 | from entertainerlib.utils.configuration import Configuration |
35 | from entertainerlib.utils.logger import Logger |
36 | |
37 | @@ -92,6 +93,7 @@ |
38 | |
39 | self.player = MediaPlayer(self.stage, |
40 | self.config.get_stage_width(), self.config.get_stage_height()) |
41 | + self.player.connect("volume-changed", self._on_volume_changed) |
42 | |
43 | # Initialize menu overlay texture |
44 | self.overlay_status = False |
45 | @@ -102,6 +104,15 @@ |
46 | self.config.get_stage_width(), self.config.get_stage_height()) |
47 | self.stage.add(self.menu_overlay) |
48 | |
49 | + self.volume_indicator = VolumeIndicator() |
50 | + self.stage.add(self.volume_indicator) |
51 | + self.volume_indicator.connect("hidening", |
52 | + self._on_volume_indicator_hidening) |
53 | + self.fade_screen_timeline = clutter.Timeline(13, 26) |
54 | + alpha = clutter.Alpha(self.fade_screen_timeline, |
55 | + clutter.smoothstep_inc_func) |
56 | + self.fade_screen_behaviour = clutter.BehaviourOpacity(255, 0, alpha) |
57 | + |
58 | # Transition object. Handles effects between screen changes. |
59 | transition_factory = TransitionFactory(self._remove_from_stage) |
60 | self.transition = transition_factory.generate_transition() |
61 | @@ -140,6 +151,8 @@ |
62 | clutter.keysyms.c : UserEvent.PLAYER_SKIP_FORWARD, |
63 | clutter.keysyms.z : UserEvent.PLAYER_PREVIOUS, |
64 | clutter.keysyms.v : UserEvent.PLAYER_NEXT, |
65 | + clutter.keysyms.m : UserEvent.PLAYER_VOLUME_UP, |
66 | + clutter.keysyms.l : UserEvent.PLAYER_VOLUME_DOWN, |
67 | clutter.keysyms.q : UserEvent.QUIT_FRONTEND, |
68 | clutter.keysyms.Escape : UserEvent.QUIT_FRONTEND |
69 | }) |
70 | @@ -168,6 +181,8 @@ |
71 | UserEvent.PLAYER_SKIP_FORWARD : self._handle_player_skip_forward, |
72 | UserEvent.PLAYER_PREVIOUS : self._handle_player_previous, |
73 | UserEvent.PLAYER_NEXT : self._handle_player_next, |
74 | + UserEvent.PLAYER_VOLUME_UP : self._handle_player_volume_up, |
75 | + UserEvent.PLAYER_VOLUME_DOWN : self._handle_player_volume_down, |
76 | UserEvent.QUIT_FRONTEND : self._handle_quit_frontend |
77 | } |
78 | |
79 | @@ -394,6 +409,14 @@ |
80 | self.player.stop() |
81 | self.current.handle_user_event(event) |
82 | |
83 | + def _handle_player_volume_up(self, event): |
84 | + '''Handle UserEvent.PLAYER_VOLUME_UP.''' |
85 | + self.player.volume_up() |
86 | + |
87 | + def _handle_player_volume_down(self, event): |
88 | + '''Handle UserEvent.PLAYER_VOLUME_DOWN.''' |
89 | + self.player.volume_down() |
90 | + |
91 | def _handle_toggle_fullscreen(self, event): |
92 | '''Handle UserEvent.TOGGLE_FULLSCREEN.''' |
93 | self._toggle_fullscreen() |
94 | @@ -402,3 +425,18 @@ |
95 | '''Handle UserEvent.QUIT_FRONTEND.''' |
96 | self.confirm_exit() |
97 | |
98 | + def _on_volume_changed(self, event): |
99 | + """Show volume indicator and fade out the screen (if needed).""" |
100 | + if not self.volume_indicator.visible: |
101 | + if not self.fade_screen_behaviour.is_applied(self.current): |
102 | + self.fade_screen_behaviour.apply(self.current) |
103 | + self.fade_screen_behaviour.set_bounds(255, 50) |
104 | + self.fade_screen_timeline.start() |
105 | + |
106 | + self.volume_indicator.show_volume(self.player.volume) |
107 | + |
108 | + def _on_volume_indicator_hidening(self, event): |
109 | + """Restore previous screen opacity.""" |
110 | + self.fade_screen_behaviour.set_bounds(50, 255) |
111 | + self.fade_screen_timeline.start() |
112 | + |
113 | |
114 | === added file 'entertainerlib/frontend/gui/widgets/volume_indicator.py' |
115 | --- entertainerlib/frontend/gui/widgets/volume_indicator.py 1970-01-01 00:00:00 +0000 |
116 | +++ entertainerlib/frontend/gui/widgets/volume_indicator.py 2009-06-28 09:12:14 +0000 |
117 | @@ -0,0 +1,80 @@ |
118 | +# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2 |
119 | +"""A volume indicator widgets.""" |
120 | + |
121 | +import clutter |
122 | +import gobject |
123 | + |
124 | +from entertainerlib.frontend.gui.widgets.base import Base |
125 | + |
126 | +class VolumeIndicator(Base, clutter.Group): |
127 | + """Volume Indicator displaying player's volume level.""" |
128 | + __gsignals__ = { |
129 | + 'hidening' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), |
130 | + } |
131 | + |
132 | + def __init__(self): |
133 | + Base.__init__(self) |
134 | + clutter.Group.__init__(self) |
135 | + |
136 | + theme = self.config.theme |
137 | + filled = clutter.Texture(theme.getImage("volume_filled")) |
138 | + unfilled = clutter.Texture(theme.getImage("volume_unfilled")) |
139 | + volume = clutter.Texture(theme.getImage("volume")) |
140 | + self.add(volume) |
141 | + |
142 | + self._pokes = [] |
143 | + |
144 | + poke_width = filled.get_width() |
145 | + |
146 | + for i in range(20): |
147 | + poke_filled = clutter.CloneTexture(filled) |
148 | + poke_unfilled = clutter.CloneTexture(unfilled) |
149 | + poke_filled.set_position(volume.get_width() + i * poke_width, 0) |
150 | + poke_unfilled.set_position(volume.get_width() + i * poke_width, 0) |
151 | + self.add(poke_filled) |
152 | + self.add(poke_unfilled) |
153 | + self._pokes.append([poke_filled, poke_unfilled]) |
154 | + |
155 | + self._hide_timeout_key = None |
156 | + self.visible = False |
157 | + self.set_opacity(0) |
158 | + |
159 | + self.timeline = clutter.Timeline(13, 26) |
160 | + self.alpha = clutter.Alpha(self.timeline, clutter.smoothstep_inc_func) |
161 | + self.behaviour = clutter.BehaviourOpacity(255, 0, self.alpha) |
162 | + self.behaviour.apply(self) |
163 | + |
164 | + self.set_position(self.get_abs_x(0.35), self.get_abs_y(0.1)) |
165 | + |
166 | + def show_volume(self, volume): |
167 | + """Displays volume level using filled and unfilled pokes.""" |
168 | + self.raise_top() |
169 | + |
170 | + if self._hide_timeout_key is not None: |
171 | + gobject.source_remove(self._hide_timeout_key) |
172 | + self._hide_timeout_key = gobject.timeout_add(2000, |
173 | + self.animate_out) |
174 | + |
175 | + for index, pokes in enumerate(self._pokes): |
176 | + if index >= volume: |
177 | + pokes[0].set_opacity(0) |
178 | + pokes[1].set_opacity(255) |
179 | + else: |
180 | + pokes[0].set_opacity(255) |
181 | + pokes[1].set_opacity(0) |
182 | + |
183 | + if self.visible == True: |
184 | + return |
185 | + |
186 | + self.visible = True |
187 | + self.behaviour.set_bounds(0, 255) |
188 | + self.timeline.start() |
189 | + |
190 | + def animate_out(self): |
191 | + """Fades out.""" |
192 | + self.behaviour.set_bounds(255, 0) |
193 | + self.timeline.start() |
194 | + self.visible = False |
195 | + self.emit("hidening") |
196 | + return False |
197 | + |
198 | |
199 | === modified file 'entertainerlib/frontend/media_player.py' |
200 | --- entertainerlib/frontend/media_player.py 2009-05-26 17:32:56 +0000 |
201 | +++ entertainerlib/frontend/media_player.py 2009-06-27 11:00:55 +0000 |
202 | @@ -32,6 +32,7 @@ |
203 | 'skip-forward' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), |
204 | 'skip-backward' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), |
205 | 'position_changed' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), |
206 | + 'volume_changed' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ), |
207 | } |
208 | |
209 | # Ratio constants |
210 | @@ -64,6 +65,8 @@ |
211 | |
212 | self.video_texture = cluttergst.VideoTexture() |
213 | self.playbin = self.video_texture.get_playbin() |
214 | + self.playbin.set_property("volume", 0.5) |
215 | + self._volume = 10 |
216 | self.bus = self.playbin.get_bus() |
217 | self.bus.add_signal_watch() |
218 | self.bus.connect('message', self._on_gst_message) |
219 | @@ -91,6 +94,30 @@ |
220 | self.logger.error("Error: %(err)s, %(debug)s" % \ |
221 | {'err': err, 'debug': debug}) |
222 | |
223 | + def _get_volume(self): |
224 | + """volume property getter.""" |
225 | + return self._volume |
226 | + |
227 | + def _set_volume(self, volume): |
228 | + """volume property setter.""" |
229 | + self._volume = volume |
230 | + if self._volume > 20: |
231 | + self._volume = 20 |
232 | + if self._volume < 0: |
233 | + self._volume = 0 |
234 | + self.playbin.set_property("volume", self._volume / 20.0) |
235 | + self.emit("volume-changed") |
236 | + |
237 | + volume = property(_get_volume, _set_volume) |
238 | + |
239 | + def volume_up(self): |
240 | + """Increase player's volume level.""" |
241 | + self.volume = self._volume + 1 |
242 | + |
243 | + def volume_down(self): |
244 | + """Decrease player's volume level.""" |
245 | + self.volume = self._volume - 1 |
246 | + |
247 | def set_playlist(self, playlist): |
248 | '''Set new playlist to MediaPlayer.''' |
249 | if len(playlist) == 0: |
250 | |
251 | === modified file 'entertainerlib/tests/mock.py' |
252 | --- entertainerlib/tests/mock.py 2009-06-15 03:19:46 +0000 |
253 | +++ entertainerlib/tests/mock.py 2009-06-28 12:19:08 +0000 |
254 | @@ -1,6 +1,7 @@ |
255 | # Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2 |
256 | '''Test mock objects''' |
257 | # pylint: disable-msg=W0231 |
258 | +import clutter |
259 | import gobject |
260 | |
261 | from entertainerlib.frontend.backend_connection import BackendConnection |
262 | @@ -328,3 +329,10 @@ |
263 | self.y = 0 |
264 | self.time = 0 |
265 | |
266 | + |
267 | +class MockStage(clutter.Stage): |
268 | + '''Mock a clutter Stage.''' |
269 | + |
270 | + def __init__(self): |
271 | + clutter.Stage.__init__(self) |
272 | + |
273 | |
274 | === added file 'entertainerlib/tests/test_mediaplayer.py' |
275 | --- entertainerlib/tests/test_mediaplayer.py 1970-01-01 00:00:00 +0000 |
276 | +++ entertainerlib/tests/test_mediaplayer.py 2009-06-28 12:19:08 +0000 |
277 | @@ -0,0 +1,85 @@ |
278 | +# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2 |
279 | +"""Tests MediaPlayer""" |
280 | + |
281 | +import os |
282 | + |
283 | +from entertainerlib.frontend.media_player import MediaPlayer |
284 | +from entertainerlib.frontend.medialibrary.videos import VideoItem |
285 | +from entertainerlib.tests import EntertainerTest |
286 | +from entertainerlib.tests.mock import MockStage |
287 | + |
288 | +THIS_DIR = os.path.dirname(__file__) |
289 | + |
290 | +class MediaPlayerTest(EntertainerTest): |
291 | + """Test for entertainerlib.frontend.gui.widgets.volume_indicator""" |
292 | + |
293 | + def setUp(self): |
294 | + '''Set up the test.''' |
295 | + EntertainerTest.setUp(self) |
296 | + |
297 | + self.stage = MockStage() |
298 | + self.player = MediaPlayer(self.stage, 100, 100) |
299 | + self.video_item = VideoItem() |
300 | + self.video_item.set_filename( |
301 | + THIS_DIR + '/data/VideoThumbnailer/test.avi') |
302 | + self.player.set_media(self.video_item) |
303 | + |
304 | + def test_create(self): |
305 | + '''Test correct MediaPlayer initialization.''' |
306 | + self.assertTrue(isinstance(self.player, MediaPlayer)) |
307 | + |
308 | + def test_volume(self): |
309 | + '''Test the use of the volume property.''' |
310 | + self.player.volume = 10 |
311 | + self.assertEqual(self.player.volume, 10) |
312 | + self.player.volume = 99 |
313 | + self.assertEqual(self.player.volume, 20) |
314 | + self.player.volume = -10 |
315 | + self.assertEqual(self.player.volume, 0) |
316 | + |
317 | + def test_volumedown(self): |
318 | + '''Test the use of the volume_down method.''' |
319 | + self.player.volume = 10 |
320 | + self.player.volume_down() |
321 | + self.assertEqual(self.player.volume, 9) |
322 | + |
323 | + def test_volumeup(self): |
324 | + '''Test the use of the volume_up method.''' |
325 | + self.player.volume = 10 |
326 | + self.player.volume_up() |
327 | + self.assertEqual(self.player.volume, 11) |
328 | + |
329 | + def test_setmedia(self): |
330 | + '''Test the use of the set_media method.''' |
331 | + # The method is called during setUp. |
332 | + self.assertTrue(self.player.media is not None) |
333 | + |
334 | + def test_getmedia(self): |
335 | + '''Test the use of the get_media method.''' |
336 | + self.assertEqual(self.player.get_media(), self.video_item) |
337 | + |
338 | + def test_hasmedia(self): |
339 | + '''Test the use of the has_media method.''' |
340 | + self.assertTrue(self.player.has_media()) |
341 | + |
342 | + def test_getmediatype(self): |
343 | + '''Test the use of the get_media_type method.''' |
344 | + self.assertEqual(self.player.get_media_type(), |
345 | + self.video_item.get_type()) |
346 | + |
347 | + def test_playstop(self): |
348 | + '''Test the use of the play and stop methods.''' |
349 | + self.player.play() |
350 | + self.assertTrue(self.player.playing) |
351 | + self.player.stop() |
352 | + self.assertFalse(self.player.playing) |
353 | + |
354 | + def test_getmediatitle(self): |
355 | + '''Test the use of the get_media_title method.''' |
356 | + self.assertEqual(self.player.get_media_title(), |
357 | + THIS_DIR + '/data/VideoThumbnailer/test.avi') |
358 | + |
359 | + def test_getmediadurationstring(self): |
360 | + '''Test the use of the get_media_title method.''' |
361 | + self.assertEqual(self.player.get_media_duration_string(), "00:00") |
362 | + |
363 | |
364 | === added file 'entertainerlib/tests/test_volumeindicator.py' |
365 | --- entertainerlib/tests/test_volumeindicator.py 1970-01-01 00:00:00 +0000 |
366 | +++ entertainerlib/tests/test_volumeindicator.py 2009-06-28 12:19:08 +0000 |
367 | @@ -0,0 +1,24 @@ |
368 | +# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2 |
369 | +"""Tests VolumeIndicator""" |
370 | + |
371 | +from entertainerlib.frontend.gui.widgets.volume_indicator import VolumeIndicator |
372 | +from entertainerlib.tests import EntertainerTest |
373 | + |
374 | +class VolumeIndicatorTest(EntertainerTest): |
375 | + """Test for entertainerlib.frontend.gui.widgets.volume_indicator""" |
376 | + |
377 | + def setUp(self): |
378 | + '''Set up the test.''' |
379 | + EntertainerTest.setUp(self) |
380 | + |
381 | + self.indicator = VolumeIndicator() |
382 | + |
383 | + def test_create(self): |
384 | + '''Test correct VolumeIndicator initialization.''' |
385 | + self.assertTrue(isinstance(self.indicator, VolumeIndicator)) |
386 | + |
387 | + def test_show_volume(self): |
388 | + '''Test the use of the show_volume method.''' |
389 | + self.indicator.show_volume(5) |
390 | + self.assertTrue(self.indicator.visible) |
391 | + |
Devs,
With this branch it is now possible to change the volume level when playing a media. This is something important that was missing (I think).
To reach that goal, a "volume" property has been added to the media player.
A VolumeIndicator has also been created. It's themable and is displayed when we change the volume with a fade in effect while the screen is faded out at the same time.
The keys I've chosen to change the volume are l = volume down and m = volume up. If you prefer other keys just let me know.
The VolumeIndicator widget is not reactive right now (I'l do that in an other branch)
Samuel-