diff --git a/OpenRA.Game/GameRules/Rules.cs b/OpenRA.Game/GameRules/Rules.cs index 76ea3d9516..235375e57d 100755 --- a/OpenRA.Game/GameRules/Rules.cs +++ b/OpenRA.Game/GameRules/Rules.cs @@ -51,6 +51,6 @@ namespace OpenRA return y.ToDictionaryWithConflictLog(kv => kv.Key.ToLowerInvariant(), kv => f(kv, yy), "LoadYamlRules", null, null); } - public static IEnumerable> InstalledMusic { get { return Music.Where( m => m.Value.Exists ); } } + public static IEnumerable> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } } } } diff --git a/OpenRA.Game/GameRules/Settings.cs b/OpenRA.Game/GameRules/Settings.cs index 7cea47e7d3..bd4b6c15d1 100644 --- a/OpenRA.Game/GameRules/Settings.cs +++ b/OpenRA.Game/GameRules/Settings.cs @@ -100,9 +100,11 @@ namespace OpenRA.GameRules public float SoundVolume = 0.5f; public float MusicVolume = 0.5f; public float VideoVolume = 0.5f; + public bool Shuffle = false; public bool Repeat = false; public bool MapMusic = true; + public string Engine = "AL"; public string Device = null; diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index c76ff2c534..ac48cabe2f 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -97,7 +97,6 @@ - @@ -109,6 +108,7 @@ + diff --git a/OpenRA.Mods.Cnc/Widgets/Logic/CncInstallMusicLogic.cs b/OpenRA.Mods.Cnc/Widgets/Logic/CncInstallMusicLogic.cs new file mode 100644 index 0000000000..75dc4501ba --- /dev/null +++ b/OpenRA.Mods.Cnc/Widgets/Logic/CncInstallMusicLogic.cs @@ -0,0 +1,59 @@ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.GameRules; +using OpenRA.Mods.RA.Widgets.Logic; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Cnc.Widgets.Logic +{ + public class CncInstallMusicLogic + { + [ObjectCreator.UseCtor] + public CncInstallMusicLogic(Widget widget, Action onExit) + { + var installButton = widget.GetOrNull("INSTALL_BUTTON"); + if (installButton != null) + { + Action afterInstall = () => + { + try + { + var path = new string[] { Platform.SupportDir, "Content", WidgetUtils.ActiveModId() }.Aggregate(Path.Combine); + FileSystem.Mount(Path.Combine(path, "scores.mix")); + FileSystem.Mount(Path.Combine(path, "transit.mix")); + + Rules.Music.Do(m => m.Value.Reload()); + + var musicPlayerLogic = (MusicPlayerLogic)installButton.Parent.LogicObject; + musicPlayerLogic.BuildMusicTable(); + } + catch (Exception e) + { + Log.Write("debug", "Mounting the new mixfile and rebuild of scores list failed:\n{0}", e); + } + }; + + installButton.OnClick = () => + Ui.OpenWindow("INSTALL_MUSIC_PANEL", new WidgetArgs() { + { "afterInstall", afterInstall }, + { "filesToCopy", new[] { "SCORES.MIX" } }, + { "filesToExtract", new[] { "transit.mix" } }, + }); + installButton.IsVisible = () => Rules.InstalledMusic.ToArray().Length < 3; // HACK around music being split between transit.mix and scores.mix + } + } + } +} diff --git a/OpenRA.Mods.Cnc/Widgets/Logic/CncMusicPlayerLogic.cs b/OpenRA.Mods.Cnc/Widgets/Logic/CncMusicPlayerLogic.cs deleted file mode 100644 index 14adc49af9..0000000000 --- a/OpenRA.Mods.Cnc/Widgets/Logic/CncMusicPlayerLogic.cs +++ /dev/null @@ -1,186 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System; -using System.IO; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.GameRules; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Cnc.Widgets.Logic -{ - public class CncMusicPlayerLogic - { - bool installed; - MusicInfo currentSong = null; - Widget panel; - MusicInfo[] music; - MusicInfo[] random; - - ScrollItemWidget itemTemplate; - - [ObjectCreator.UseCtor] - public CncMusicPlayerLogic(Widget widget, Action onExit) - { - panel = widget.Get("MUSIC_PANEL"); - - var ml = panel.Get("MUSIC_LIST"); - itemTemplate = ml.Get("MUSIC_TEMPLATE"); - - BuildMusicTable(ml); - - currentSong = Sound.CurrentMusic ?? GetNextSong(); - installed = Rules.Music.Where(m => m.Value.Exists).Any(); - Func noMusic = () => !installed; - - panel.Get("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; - - Action afterInstall = () => - { - // Mount the new mixfile and rebuild the scores list - try - { - var path = new string[] { Platform.SupportDir, "Content", "cnc" }.Aggregate(Path.Combine); - FileSystem.Mount(Path.Combine(path, "scores.mix")); - FileSystem.Mount(Path.Combine(path, "transit.mix")); - Rules.Music.Do(m => m.Value.Reload()); - } - catch (Exception) { } - - installed = Rules.Music.Where(m => m.Value.Exists).Any(); - BuildMusicTable(ml); - }; - - var installButton = panel.Get("INSTALL_BUTTON"); - installButton.OnClick = () => - Ui.OpenWindow("INSTALL_MUSIC_PANEL", new WidgetArgs() { - { "afterInstall", afterInstall }, - { "filesToCopy", new [] { "SCORES.MIX" } }, - { "filesToExtract", new [] { "transit.mix" } }, - }); - installButton.IsVisible = () => music.Length < 3; // Hack around music being split between transit.mix and scores.mix - - panel.Get("NO_MUSIC_LABEL").IsVisible = noMusic; - - var playButton = panel.Get("BUTTON_PLAY"); - playButton.OnClick = Play; - playButton.IsDisabled = noMusic; - - var pauseButton = panel.Get("BUTTON_PAUSE"); - pauseButton.OnClick = Pause; - pauseButton.IsDisabled = noMusic; - - var stopButton = panel.Get("BUTTON_STOP"); - stopButton.OnClick = Stop; - stopButton.IsDisabled = noMusic; - - var nextButton = panel.Get("BUTTON_NEXT"); - nextButton.OnClick = () => { currentSong = GetNextSong(); Play(); }; - nextButton.IsDisabled = noMusic; - - var prevButton = panel.Get("BUTTON_PREV"); - prevButton.OnClick = () => { currentSong = GetPrevSong(); Play(); }; - prevButton.IsDisabled = noMusic; - - var shuffleCheckbox = panel.Get("SHUFFLE"); - shuffleCheckbox.IsChecked = () => Game.Settings.Sound.Shuffle; - shuffleCheckbox.OnClick = () => Game.Settings.Sound.Shuffle ^= true; - - var repeatCheckbox = panel.Get("REPEAT"); - repeatCheckbox.IsChecked = () => Game.Settings.Sound.Repeat; - repeatCheckbox.OnClick = () => Game.Settings.Sound.Repeat ^= true; - - panel.Get("TIME_LABEL").GetText = () => (currentSong == null) ? "" : - "{0:D2}:{1:D2} / {2:D2}:{3:D2}".F((int)Sound.MusicSeekPosition / 60, (int)Sound.MusicSeekPosition % 60, - currentSong.Length / 60, currentSong.Length % 60); - panel.Get("TITLE_LABEL").GetText = () => (currentSong == null) ? "" : currentSong.Title; - - var musicSlider = panel.Get("MUSIC_SLIDER"); - musicSlider.OnChange += x => Sound.MusicVolume = x; - musicSlider.Value = Sound.MusicVolume; - } - - void BuildMusicTable(Widget list) - { - music = Rules.Music.Where(a => a.Value.Exists).Select(a => a.Value).ToArray(); - random = music.Shuffle(Game.CosmeticRandom).ToArray(); - - list.RemoveChildren(); - foreach (var s in music) - { - var song = s; - if (currentSong == null) - currentSong = song; - - var item = ScrollItemWidget.Setup(itemTemplate, () => currentSong == song, () => { currentSong = song; Play(); }); - item.Get("TITLE").GetText = () => song.Title; - item.Get("LENGTH").GetText = () => SongLengthLabel(song); - list.AddChild(item); - } - } - - void Play() - { - if (currentSong == null) - return; - - Sound.PlayMusicThen(currentSong, () => - { - if (!Game.Settings.Sound.Repeat) - currentSong = GetNextSong(); - Play(); - }); - - panel.Get("BUTTON_PLAY").Visible = false; - panel.Get("BUTTON_PAUSE").Visible = true; - } - - void Pause() - { - Sound.PauseMusic(); - panel.Get("BUTTON_PAUSE").Visible = false; - panel.Get("BUTTON_PLAY").Visible = true; - } - - void Stop() - { - Sound.StopMusic(); - panel.Get("BUTTON_PAUSE").Visible = false; - panel.Get("BUTTON_PLAY").Visible = true; - } - - string SongLengthLabel(MusicInfo song) - { - return "{0:D1}:{1:D2}".F(song.Length / 60, song.Length % 60); - } - - MusicInfo GetNextSong() - { - if (!music.Any()) - return null; - - var songs = Game.Settings.Sound.Shuffle ? random : music; - return songs.SkipWhile(m => m != currentSong) - .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); - } - - MusicInfo GetPrevSong() - { - if (!music.Any()) - return null; - - var songs = Game.Settings.Sound.Shuffle ? random : music; - return songs.Reverse().SkipWhile(m => m != currentSong) - .Skip(1).FirstOrDefault() ?? songs.Reverse().FirstOrDefault(); - } - } -} diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs index 48fc33b2f7..fd0655034f 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameMenuLogic.cs @@ -31,7 +31,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic widget.Get("MUSIC").OnClick = () => { widget.Visible = false; - Ui.OpenWindow("MUSIC_MENU", new WidgetArgs { { "onExit", () => { widget.Visible = true; } } }); + Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs { { "onExit", () => { widget.Visible = true; } } }); }; widget.Get("RESUME").OnClick = () => onExit(); diff --git a/OpenRA.Mods.RA/Widgets/Logic/MainMenuButtonsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MainMenuButtonsLogic.cs index c4b590304b..51ac053e50 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/MainMenuButtonsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/MainMenuButtonsLogic.cs @@ -46,7 +46,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic widget.Get("MAINMENU_BUTTON_MUSIC").OnClick = () => { Menu = MenuType.None; - Ui.OpenWindow("MUSIC_MENU", new WidgetArgs() + Ui.OpenWindow("MUSIC_PANEL", new WidgetArgs() { { "onExit", () => Menu = MenuType.Main } }); diff --git a/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs index 1b7ab442b4..4fb5f5039a 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs @@ -9,102 +9,145 @@ #endregion using System; -using System.Collections.Generic; -using System.Drawing; +using System.IO; using System.Linq; using OpenRA.FileFormats; -using OpenRA.Support; +using OpenRA.GameRules; +using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets.Logic { public class MusicPlayerLogic { - string CurrentSong = null; - Widget bg; + bool installed; + MusicInfo currentSong = null; + MusicInfo[] music; + MusicInfo[] random; + ScrollPanelWidget musicList; - public void Play(string song) - { - CurrentSong = song; - if (CurrentSong == null) return; - - Sound.PlayMusicThen(Rules.Music[CurrentSong], - () => Play( Game.Settings.Sound.Repeat ? CurrentSong : GetNextSong() )); - } + ScrollItemWidget itemTemplate; [ObjectCreator.UseCtor] - public MusicPlayerLogic(Action onExit) + public MusicPlayerLogic(Widget widget, Action onExit) { - bg = Ui.Root.Get("MUSIC_MENU"); - CurrentSong = GetNextSong(); + var panel = widget.Get("MUSIC_PANEL"); - bg.Get( "BUTTON_PAUSE" ).IsVisible = () => Sound.MusicPlaying; - bg.Get( "BUTTON_PLAY" ).IsVisible = () => !Sound.MusicPlaying; + musicList = panel.Get("MUSIC_LIST"); + itemTemplate = musicList.Get("MUSIC_TEMPLATE"); - bg.Get("BUTTON_CLOSE").OnClick = - () => { Game.Settings.Save(); Ui.CloseWindow(); onExit(); }; + BuildMusicTable(); - bg.Get("BUTTON_INSTALL").IsVisible = () => false; + Func noMusic = () => !installed; + panel.Get("NO_MUSIC_LABEL").IsVisible = noMusic; - bg.Get("BUTTON_PLAY").OnClick = () => Play( CurrentSong ); - bg.Get("BUTTON_PAUSE").OnClick = Sound.PauseMusic; - bg.Get("BUTTON_STOP").OnClick = Sound.StopMusic; - bg.Get("BUTTON_NEXT").OnClick = () => Play( GetNextSong() ); - bg.Get("BUTTON_PREV").OnClick = () => Play( GetPrevSong() ); + var playButton = panel.Get("BUTTON_PLAY"); + playButton.OnClick = Play; + playButton.IsDisabled = noMusic; + playButton.IsVisible = () => !Sound.MusicPlaying; - var shuffleCheckbox = bg.Get("SHUFFLE"); + var pauseButton = panel.Get("BUTTON_PAUSE"); + pauseButton.OnClick = Sound.PauseMusic; + pauseButton.IsDisabled = noMusic; + pauseButton.IsVisible = () => Sound.MusicPlaying; + + var stopButton = panel.Get("BUTTON_STOP"); + stopButton.OnClick = Sound.StopMusic; + stopButton.IsDisabled = noMusic; + + var nextButton = panel.Get("BUTTON_NEXT"); + nextButton.OnClick = () => { currentSong = GetNextSong(); Play(); }; + nextButton.IsDisabled = noMusic; + + var prevButton = panel.Get("BUTTON_PREV"); + prevButton.OnClick = () => { currentSong = GetPrevSong(); Play(); }; + prevButton.IsDisabled = noMusic; + + var shuffleCheckbox = panel.Get("SHUFFLE"); shuffleCheckbox.IsChecked = () => Game.Settings.Sound.Shuffle; shuffleCheckbox.OnClick = () => Game.Settings.Sound.Shuffle ^= true; - var repeatCheckbox = bg.Get("REPEAT"); + var repeatCheckbox = panel.Get("REPEAT"); repeatCheckbox.IsChecked = () => Game.Settings.Sound.Repeat; repeatCheckbox.OnClick = () => Game.Settings.Sound.Repeat ^= true; - bg.Get("TIME").GetText = () => - { - if (CurrentSong == null) - return ""; - return "{0} / {1}".F( - WidgetUtils.FormatTimeSeconds( (int)Sound.MusicSeekPosition ), - WidgetUtils.FormatTimeSeconds( Rules.Music[CurrentSong].Length )); - }; + panel.Get("TIME_LABEL").GetText = () => (currentSong == null) ? "" : + "{0:D2}:{1:D2} / {2:D2}:{3:D2}".F((int)Sound.MusicSeekPosition / 60, (int)Sound.MusicSeekPosition % 60, + currentSong.Length / 60, currentSong.Length % 60); - var ml = bg.Get("MUSIC_LIST"); - var itemTemplate = ml.Get("MUSIC_TEMPLATE"); + var musicSlider = panel.Get("MUSIC_SLIDER"); + musicSlider.OnChange += x => Sound.MusicVolume = x; + musicSlider.Value = Sound.MusicVolume; - if (!Rules.InstalledMusic.Any()) - { - itemTemplate.IsVisible = () => true; - itemTemplate.Get("TITLE").GetText = () => "No Music Installed"; - itemTemplate.Get("TITLE").Align = TextAlign.Center; - } - - foreach (var kv in Rules.InstalledMusic) - { - var song = kv.Key; - var item = ScrollItemWidget.Setup(itemTemplate, - () => CurrentSong == song, - () => Play( song )); - item.Get("TITLE").GetText = () => Rules.Music[song].Title; - item.Get("LENGTH").GetText = - () => WidgetUtils.FormatTimeSeconds( Rules.Music[song].Length ); - ml.AddChild(item); - } + panel.Get("BACK_BUTTON").OnClick = () => { Game.Settings.Save(); Ui.CloseWindow(); onExit(); }; } - string ChooseSong( IEnumerable songs ) + public void BuildMusicTable() { - if (!songs.Any()) + music = Rules.InstalledMusic.Select(a => a.Value).ToArray(); + random = music.Shuffle(Game.CosmeticRandom).ToArray(); + currentSong = Sound.CurrentMusic; + if (currentSong == null && music.Any()) + currentSong = Game.Settings.Sound.Shuffle ? random.First() : music.First(); + + musicList.RemoveChildren(); + foreach (var s in music) + { + var song = s; + if (currentSong == null) + currentSong = song; + + // TODO: We leak the currentSong MusicInfo across map load, so compare the Filename instead. + var item = ScrollItemWidget.Setup(song.Filename, itemTemplate, () => currentSong.Filename == song.Filename, () => { currentSong = song; Play(); }); + item.Get("TITLE").GetText = () => song.Title; + item.Get("LENGTH").GetText = () => SongLengthLabel(song); + musicList.AddChild(item); + } + + if (currentSong != null) + musicList.ScrollToItem(currentSong.Filename); + + installed = Rules.InstalledMusic.Any(); + } + + void Play() + { + if (currentSong == null) + return; + + musicList.ScrollToItem(currentSong.Filename); + + Sound.PlayMusicThen(currentSong, () => + { + if (!Game.Settings.Sound.Repeat) + currentSong = GetNextSong(); + Play(); + }); + } + + string SongLengthLabel(MusicInfo song) + { + return "{0:D1}:{1:D2}".F(song.Length / 60, song.Length % 60); + } + + MusicInfo GetNextSong() + { + if (!music.Any()) return null; - if (Game.Settings.Sound.Shuffle) - return songs.Random(Game.CosmeticRandom); - - return songs.SkipWhile(m => m != CurrentSong) + var songs = Game.Settings.Sound.Shuffle ? random : music; + return songs.SkipWhile(m => m != currentSong) .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); } - string GetNextSong() { return ChooseSong( Rules.InstalledMusic.Select( a => a.Key ) ); } - string GetPrevSong() { return ChooseSong( Rules.InstalledMusic.Select( a => a.Key ).Reverse() ); } + MusicInfo GetPrevSong() + { + if (!music.Any()) + return null; + + var songs = Game.Settings.Sound.Shuffle ? random : music; + return songs.Reverse().SkipWhile(m => m != currentSong) + .Skip(1).FirstOrDefault() ?? songs.Reverse().FirstOrDefault(); + } } } diff --git a/mods/cnc/chrome/music.yaml b/mods/cnc/chrome/music.yaml index 7308735078..5f379826bc 100644 --- a/mods/cnc/chrome/music.yaml +++ b/mods/cnc/chrome/music.yaml @@ -1,5 +1,5 @@ Container@MUSIC_PANEL: - Logic:CncMusicPlayerLogic + Logic:MusicPlayerLogic X:(WINDOW_RIGHT - WIDTH)/2 Y:(WINDOW_BOTTOM - 400)/2 Width:360 @@ -39,15 +39,6 @@ Container@MUSIC_PANEL: X:PARENT_RIGHT-60 Align:Right Height:25 - Label@NO_MUSIC_LABEL: - X:15 - Y:147 - Width:330 - Height:25 - Font:Bold - Align:Center - Visible:false - Text:No Music Installed Container@LABEL_CONTAINER: X:25 Y:5 @@ -130,23 +121,16 @@ Container@MUSIC_PANEL: Width:16 Height:16 ImageCollection:music - ImageName:next + ImageName:next Slider@MUSIC_SLIDER: X:145 Y:3 Width:185 Height:20 Ticks:5 - Label@TITLE_LABEL: - X:(PARENT_RIGHT-WIDTH)/2 - Y:305 - Width:140 - Height:25 - Align:Center - Font:Bold Label@TIME_LABEL: X:(PARENT_RIGHT-WIDTH)/2 - Y:325 + Y:315 Width:140 Height:25 Align:Center @@ -163,6 +147,15 @@ Container@MUSIC_PANEL: Width:70 Height:20 Text:Loop + Label@NO_MUSIC_LABEL: + X:15 + Y:147 + Width:330 + Height:25 + Font:Bold + Align:Center + Visible:false + Text:No Music Installed Button@BACK_BUTTON: Key:escape X:0 @@ -171,6 +164,7 @@ Container@MUSIC_PANEL: Height:35 Text:Back Button@INSTALL_BUTTON: + Logic:CncInstallMusicLogic X:220 Y:399 Width:140 @@ -249,3 +243,4 @@ Container@INSTALL_MUSIC_PANEL: Width:140 Height:35 Text:Retry + diff --git a/mods/ra/chrome/musicplayer.yaml b/mods/ra/chrome/musicplayer.yaml index e37c415888..75b090afdd 100644 --- a/mods/ra/chrome/musicplayer.yaml +++ b/mods/ra/chrome/musicplayer.yaml @@ -1,41 +1,68 @@ -Background@MUSIC_MENU: +Background@MUSIC_PANEL: Logic:MusicPlayerLogic X:(WINDOW_RIGHT - WIDTH)/2 - Y:(WINDOW_BOTTOM - HEIGHT)/2 - Width: 450 - Height: 250 - Visible: true + Y:(WINDOW_BOTTOM - 400)/2 + Width:360 + Height:450 Children: - Label@SETTINGS_LABEL_TITLE: - X:0 - Y:20 - Width:450 - Height:25 - Text:Music - Align:Center - Font:Bold - Button@BUTTON_INSTALL: - X:20 - Y:PARENT_BOTTOM - 45 - Width:160 - Height:25 - Text:Install Music - Font:Bold - Button@BUTTON_CLOSE: - X:PARENT_RIGHT - 180 - Y:PARENT_BOTTOM - 45 - Width:160 - Height:25 - Text:Close - Font:Bold - Key:escape - Container@BUTTONS: - X:PARENT_RIGHT - 150 - Y:50 + ScrollPanel@MUSIC_LIST: + X:15 + Y:45 + Width:330 + Height:275 Children: + ScrollItem@MUSIC_TEMPLATE: + Width:PARENT_RIGHT-27 + Height:25 + X:2 + Y:0 + Visible:false + Children: + Label@TITLE: + X:10 + Width:PARENT_RIGHT-50 + Height:25 + Label@LENGTH: + Width:50 + X:PARENT_RIGHT-60 + Align:Right + Height:25 + Container@LABEL_CONTAINER: + X:25 + Y:15 + Width:330 + Children: + Label@TITLE: + Width:100 + Height:25 + Text:Track + Align:Center + Font:Bold + Label@TYPE: + X:PARENT_RIGHT-85 + Height:25 + Width:50 + Text:Length + Align:Right + Font:Bold + Container@BUTTONS: + X:15 + Y:PARENT_BOTTOM-HEIGHT-85 + Width:170 + Children: + Button@BUTTON_PREV: + Width:25 + Height:25 + Children: + Image@IMAGE_PREV: + X:0 + Y:0 + Width:25 + Height:25 + ImageCollection:music + ImageName:prev Button@BUTTON_PLAY: X:35 - Y:0 Width:25 Height:25 Children: @@ -49,7 +76,6 @@ Background@MUSIC_MENU: Button@BUTTON_PAUSE: Visible:false X:35 - Y:0 Width:25 Height:25 Children: @@ -62,7 +88,6 @@ Background@MUSIC_MENU: ImageName:pause Button@BUTTON_STOP: X:70 - Y:0 Width:25 Height:25 Children: @@ -75,7 +100,6 @@ Background@MUSIC_MENU: ImageName:stop Button@BUTTON_NEXT: X:105 - Y:0 Width:25 Height:25 Children: @@ -86,57 +110,45 @@ Background@MUSIC_MENU: Height:25 ImageCollection:music ImageName:next - Button@BUTTON_PREV: - X:0 - Y:0 - Width:25 - Height:25 - Children: - Image@IMAGE_PREV: - X:0 - Y:0 - Width:25 - Height:25 - ImageCollection:music - ImageName:prev - Label@TIME: - X:PARENT_RIGHT - 150 - Y:75 + Slider@MUSIC_SLIDER: + X:145 + Y:3 + Width:175 + Height:20 + Ticks:5 + Label@TIME_LABEL: + X:(PARENT_RIGHT-WIDTH)/2 + Y:330 Width:140 Height:25 - Align: Center - ScrollPanel@MUSIC_LIST: - X:10 - Y:50 - Width:280 - Height:140 - Children: - ScrollItem@MUSIC_TEMPLATE: - Width:PARENT_RIGHT-27 - Height:25 - X:2 - Y:0 - Visible:false - Children: - Label@TITLE: - X:5 - Width:PARENT_RIGHT - 10 - Height:PARENT_BOTTOM - Align: Left - Label@LENGTH: - X:5 - Width:PARENT_RIGHT - 10 - Height:PARENT_BOTTOM - Align: Right + Align:Center + Font:Bold Checkbox@SHUFFLE: - X:PARENT_RIGHT - 150 - Y:110 - Width:100 + X:15 + Y:335 + Width:85 Height:20 Text:Shuffle Checkbox@REPEAT: - X:PARENT_RIGHT - 150 - Y:140 - Width:100 + X:PARENT_RIGHT-15-WIDTH + Y:335 + Width:70 Height:20 - Text:Loop \ No newline at end of file + Text:Loop + Label@NO_MUSIC_LABEL: + X:15 + Y:147 + Width:330 + Height:25 + Font:Bold + Align:Center + Visible:false + Text:No Music Installed + Button@BACK_BUTTON: + X:PARENT_RIGHT - 180 + Y:PARENT_BOTTOM - 45 + Width:160 + Height:25 + Text:Close + Font:Bold + Key:escape \ No newline at end of file