Merge pull request #650 from Hixie/theme
Trivial documentation for files in theme/.
diff --git a/examples/game/lib/sound.dart b/examples/game/lib/sound.dart
index e502f6b..5e50e7f 100644
--- a/examples/game/lib/sound.dart
+++ b/examples/game/lib/sound.dart
@@ -149,6 +149,7 @@
SoundTrackBufferingCallback onBufferingUpdate;
bool loop;
double time;
+ double volume;
}
SoundTrackPlayer _sharedSoundTrackPlayer;
diff --git a/examples/game/lib/sound_manager.dart b/examples/game/lib/sound_manager.dart
new file mode 100644
index 0000000..90c03a9
--- /dev/null
+++ b/examples/game/lib/sound_manager.dart
@@ -0,0 +1,238 @@
+part of sprites;
+
+enum SoundFadeMode {
+ crossFade,
+ fadeOutThenPlay,
+ fadeOutThenFadeIn,
+}
+
+enum SoundEventSimultaneousPolicy {
+ dontPlay,
+ stopOldest,
+}
+
+enum SoundEventMinimumOverlapPolicy {
+ dontPlay,
+ delay,
+}
+
+class SoundEvent {
+ SoundEvent(SoundEffect effect) {
+ effects = [effect];
+ }
+
+ SoundEvent.withList(this.effects);
+
+ List<SoundEffect> effects;
+ double pitchVariance = 0.0;
+ double volumeVariance = 0.0;
+ double panVariance = 0.0;
+
+ SoundEventSimultaneousPolicy simultaneousLimitPolicy = SoundEventSimultaneousPolicy.stopOldest;
+ int simultaneousLimit = 0;
+
+ SoundEventMinimumOverlapPolicy minimumOverlapPolicy = SoundEventMinimumOverlapPolicy.dontPlay;
+ double minimumOverlap = 0.0;
+}
+
+class _PlayingSoundEvent {
+ SoundEvent event;
+ SoundEffectStream stream;
+ int startTime;
+}
+
+SoundManager _sharedSoundManager;
+
+class SoundManager {
+
+ static SoundManager sharedInstance() {
+ if (_sharedSoundManager == null) {
+ _sharedSoundManager = new SoundManager();
+ }
+ return _sharedSoundManager;
+ }
+
+ static void purgeSharedInstance() {
+ if (_sharedSoundManager == null) return;
+ _sharedSoundManager._running = false;
+ _sharedSoundManager = null;
+ }
+
+ SoundManager() {
+ new Timer.periodic(new Duration(milliseconds:10), _update);
+ }
+
+ Map<SoundEvent, List<_PlayingSoundEvent>> _playingEvents = {};
+ SoundTrack _backgroundMusicTrack;
+
+ SoundEffectPlayer _effectPlayer = SoundEffectPlayer.sharedInstance();
+ SoundTrackPlayer _trackPlayer = SoundTrackPlayer.sharedInstance();
+ ActionController actions = new ActionController();
+
+ bool enableBackgroundMusic;
+ bool enableSoundEffects;
+
+ bool _running = true;
+ int _lastTimeStamp;
+
+ void playEvent(SoundEvent evt, [double volume = 1.0, double pitch = 1.0, double pan = 0.0]) {
+ List<_PlayingSoundEvent> playingList = _playingEvents[evt];
+ if (playingList == null) playingList = [];
+
+ // Check simultaneousLimit
+ if (evt.simultaneousLimit != 0 && evt.simultaneousLimit >= playingList.length) {
+ // We have too many sounds playing
+ if (evt.simultaneousLimitPolicy == SoundEventSimultaneousPolicy.dontPlay) {
+ // Skip this sound event
+ return;
+ } else {
+ // Stop the oldest sound
+ _effectPlayer.stop(playingList[0].stream);
+ }
+ }
+
+ // Check for overlap
+ int playTime = new DateTime.now().millisecondsSinceEpoch;
+
+ if (evt.minimumOverlap != 0.0 && playingList.length > 0) {
+ int overlap = playTime - playingList.last.startTime;
+ if (overlap.toDouble() / 1000.0 < evt.minimumOverlap) {
+ // Sounds are overlapping
+ if (evt.minimumOverlapPolicy == SoundEventMinimumOverlapPolicy.dontPlay) {
+ return;
+ } else {
+ // TODO: try to play the sound a little bit later
+ return;
+ }
+ }
+ }
+
+ // Create a new entry for the event
+ _PlayingSoundEvent newPlaying = new _PlayingSoundEvent();
+ newPlaying.startTime = playTime;
+ newPlaying.event = evt;
+
+ // Pick a sound effect to play
+ SoundEffect effect = evt.effects.elementAt(randomInt(evt.effects.length));
+
+ // Add the entry
+ playingList.add(newPlaying);
+
+ // Play the event
+ newPlaying.stream = _effectPlayer.play(
+ effect,
+ false,
+ (volume + evt.volumeVariance * randomSignedDouble()).clamp(0.0, 2.0),
+ (pitch + evt.pitchVariance * randomSignedDouble()).clamp(0.5, 2.0),
+ (pan + evt.panVariance * randomSignedDouble()).clamp(-1.0, 1.0),
+ (SoundEffectStream s) {
+ // Completion callback - remove the entry
+ playingList.remove(newPlaying);
+ }
+ );
+ }
+
+ void stopAllEvents([double fadeDuration]) {
+ for (List<_PlayingSoundEvent> playingList in _playingEvents) {
+ for (_PlayingSoundEvent playing in playingList) {
+ if (fadeDuration > 0.0) {
+ // Fade out and stop
+ ActionTween fadeOut = new ActionTween((a) => playing.stream.volume = a, playing.stream.volume, 0.0, fadeDuration);
+ ActionCallFunction stop = new ActionCallFunction(() { _effectPlayer.stop(playing.stream); });
+ ActionSequence seq = new ActionSequence([fadeOut, stop]);
+ actions.run(seq);
+ }
+ else {
+ // Stop right away
+ _effectPlayer.stop(playing.stream);
+ }
+ }
+ }
+ }
+
+ void playBackgroundMusic(SoundTrack track, [double fadeDuration = 0.0, SoundFadeMode fadeMode = SoundFadeMode.fadeOutThenPlay]) {
+ double fadeInDuration = 0.0;
+ double fadeInDelay = 0.0;
+ double fadeOutDuration = 0.0;
+
+ // Calculate durations
+ if (fadeDuration > 0.0) {
+ if (fadeMode == SoundFadeMode.crossFade) {
+ fadeOutDuration = fadeDuration;
+ fadeInDuration = fadeDuration;
+ } else if (fadeMode == SoundFadeMode.fadeOutThenPlay) {
+ fadeOutDuration = fadeDuration;
+ fadeInDelay = fadeDuration;
+ } else if (fadeMode == SoundFadeMode.fadeOutThenFadeIn) {
+ fadeOutDuration = fadeDuration / 2.0;
+ fadeInDuration = fadeDuration / 2.0;
+ fadeInDelay = fadeDuration / 2.0;
+ }
+ }
+
+ if (_backgroundMusicTrack != null) {
+ // Stop the current track
+ if (fadeOutDuration == 0.0) {
+ _trackPlayer.stop(_backgroundMusicTrack);
+ } else {
+ ActionTween fadeOut = new ActionTween((a) => _backgroundMusicTrack.volume = a, _backgroundMusicTrack.volume, 0.0, fadeOutDuration);
+ ActionCallFunction stop = new ActionCallFunction(() { _trackPlayer.stop(_backgroundMusicTrack); });
+ ActionSequence seq = new ActionSequence([fadeOut, stop]);
+ actions.run(seq);
+ }
+ } else {
+ fadeInDelay = 0.0;
+ }
+
+ // Fade in new sound
+ if (fadeInDelay == 0.0) {
+ _fadeInTrack(track, fadeInDuration);
+ } else {
+ ActionDelay delay = new ActionDelay(fadeInDelay);
+ ActionCallFunction fadeInCall = new ActionCallFunction(() {
+ _fadeInTrack(track, fadeInDuration);
+ });
+ ActionSequence seq = new ActionSequence([delay, fadeInCall]);
+ actions.run(seq);
+ }
+ }
+
+ void _fadeInTrack(SoundTrack track, double duration) {
+ _backgroundMusicTrack = track;
+
+ if (duration == 0.0) {
+ _trackPlayer.play(track);
+ } else {
+ _trackPlayer.play(track, true, 0.0);
+ actions.run(new ActionTween((a) => track.volume = a, 0.0, 1.0, duration));
+ }
+ }
+
+ void stopBackgroundMusic([double fadeDuration = 0.0]) {
+ if (fadeDuration == 0.0) {
+ _trackPlayer.stop(_backgroundMusicTrack);
+ } else {
+ ActionTween fadeOut = new ActionTween(
+ (a) => _backgroundMusicTrack.volume = a,
+ _backgroundMusicTrack.volume, 0.0, fadeDuration);
+ ActionCallFunction stopCall = new ActionCallFunction(() {
+ _trackPlayer.stop(_backgroundMusicTrack);
+ });
+ ActionSequence seq = new ActionSequence([fadeOut, stopCall]);
+ actions.run(seq);
+ }
+
+ _backgroundMusicTrack = null;
+ }
+
+ void _update(Timer timer) {
+ int delta = 0;
+ int timestamp = new DateTime.now().millisecondsSinceEpoch;
+ if (_lastTimeStamp != null) {
+ delta = timestamp - _lastTimeStamp;
+ }
+ _lastTimeStamp = timestamp;
+
+ actions.step(delta / 1000.0);
+ }
+}
diff --git a/examples/game/lib/sprites.dart b/examples/game/lib/sprites.dart
index 155dcc2..6522290 100644
--- a/examples/game/lib/sprites.dart
+++ b/examples/game/lib/sprites.dart
@@ -31,6 +31,7 @@
part 'node_with_size.dart';
part 'particle_system.dart';
part 'sound.dart';
+part 'sound_manager.dart';
part 'sprite.dart';
part 'spritesheet.dart';
part 'sprite_box.dart';
diff --git a/packages/flutter/lib/mojo/README.md b/packages/flutter/lib/mojo/README.md
new file mode 100644
index 0000000..80683fa
--- /dev/null
+++ b/packages/flutter/lib/mojo/README.md
@@ -0,0 +1,7 @@
+This directory contains code for exposing mojo services to Sky apps.
+For example, keyboard.dart wraps the mojo keyboard service in a more
+convenient Dart class.
+
+Files in this directory (and its subdirectories) only depend on core
+Dart libraries, `dart:sky`, `dart:sky.internals`, the 'mojo' package,
+the 'mojo_services' package, and `../base/*`.