diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index 5d88daefe5..d0b08c5c20 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -74,6 +74,7 @@ + diff --git a/OpenRA.Mods.Cnc/Widgets/CncMenuLogic.cs b/OpenRA.Mods.Cnc/Widgets/CncMenuLogic.cs index d0946b75cc..88589acc8f 100755 --- a/OpenRA.Mods.Cnc/Widgets/CncMenuLogic.cs +++ b/OpenRA.Mods.Cnc/Widgets/CncMenuLogic.cs @@ -40,6 +40,17 @@ namespace OpenRA.Mods.Cnc.Widgets mainMenu.GetWidget("SOLO_BUTTON").OnClick = StartSkirmishGame; mainMenu.GetWidget("MULTIPLAYER_BUTTON").OnClick = () => Menu = MenuType.Multiplayer; + + mainMenu.GetWidget("REPLAYS_BUTTON").OnClick = () => + { + Menu = MenuType.None; + Widget.OpenWindow("REPLAYBROWSER_PANEL", new Dictionary() + { + { "onExit", new Action(() => { Menu = MenuType.Main; Widget.CloseWindow(); }) }, + { "onStart", new Action(RemoveShellmapUI) } + }); + }; + mainMenu.GetWidget("SETTINGS_BUTTON").OnClick = () => Menu = MenuType.Settings; mainMenu.GetWidget("QUIT_BUTTON").OnClick = Game.Exit; @@ -74,15 +85,14 @@ namespace OpenRA.Mods.Cnc.Widgets settingsMenu.GetWidget("BACK_BUTTON").OnClick = () => Menu = MenuType.Main; } + void RemoveShellmapUI() + { + Widget.CloseWindow(); + Widget.RootWidget.RemoveChild(Widget.RootWidget.GetWidget("MENU_BACKGROUND")); + } + void OpenLobbyPanel() { - // Starting a game: remove all shellmap ui - Action onStart = () => - { - Widget.CloseWindow(); - Widget.RootWidget.RemoveChild(Widget.RootWidget.GetWidget("MENU_BACKGROUND")); - }; - // Quit the lobby: disconnect and restore menu Action onLobbyClose = () => { @@ -95,7 +105,7 @@ namespace OpenRA.Mods.Cnc.Widgets Game.OpenWindow("SERVER_LOBBY", new Dictionary() { { "onExit", onLobbyClose }, - { "onStart", onStart } + { "onStart", new Action(RemoveShellmapUI) } }); } diff --git a/OpenRA.Mods.Cnc/Widgets/CncReplayBrowserLogic.cs b/OpenRA.Mods.Cnc/Widgets/CncReplayBrowserLogic.cs new file mode 100644 index 0000000000..76b759dc53 --- /dev/null +++ b/OpenRA.Mods.Cnc/Widgets/CncReplayBrowserLogic.cs @@ -0,0 +1,112 @@ +#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.Drawing; +using System.IO; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Widgets; +using OpenRA.Mods.RA.Widgets.Delegates; + +namespace OpenRA.Mods.Cnc.Widgets +{ + public class CncReplayBrowserLogic : IWidgetDelegate + { + Widget widget; + + [ObjectCreator.UseCtor] + public CncReplayBrowserLogic([ObjectCreator.Param] Widget widget, + [ObjectCreator.Param] Action onExit, + [ObjectCreator.Param] Action onStart) + { + this.widget = widget; + + widget.GetWidget("CANCEL_BUTTON").OnClick = onExit; + + var rl = widget.GetWidget("REPLAY_LIST"); + var replayDir = Path.Combine(Platform.SupportDir, "Replays"); + + var template = widget.GetWidget("REPLAY_TEMPLATE"); + CurrentReplay = null; + + rl.RemoveChildren(); + if (Directory.Exists(replayDir)) + foreach (var replayFile in Directory.GetFiles(replayDir, "*.rep").Reverse()) + AddReplay(rl, replayFile, template); + + var watch = widget.GetWidget("WATCH_BUTTON"); + watch.IsDisabled = () => currentReplay == null; + watch.OnClick = () => + { + if (currentReplay != null) + { + Game.JoinReplay(CurrentReplay); + onStart(); + } + }; + + widget.GetWidget("REPLAY_INFO").IsVisible = () => currentReplay != null; + } + + Map MapFromSummary(ReplaySummary rs) + { + if (rs.LobbyInfo == null) + return null; + + var map = rs.LobbyInfo.GlobalSettings.Map; + if (!Game.modData.AvailableMaps.ContainsKey(map)) + return null; + + return Game.modData.AvailableMaps[map]; + } + + string currentReplay = null; + string CurrentReplay + { + get { return currentReplay; } + set + { + currentReplay = value; + if (currentReplay != null) + { + try + { + var summary = new ReplaySummary(currentReplay); + var mapStub = MapFromSummary(summary); + + widget.GetWidget("DURATION").GetText = + () => WidgetUtils.FormatTime(summary.Duration * 3 /* todo: 3:1 ratio isnt always true. */); + widget.GetWidget("MAP_PREVIEW").Map = () => mapStub; + widget.GetWidget("MAP_TITLE").GetText = + () => mapStub != null ? mapStub.Title : "(Unknown Map)"; + } + catch(Exception e) + { + Log.Write("debug", "Exception while parsing replay: {0}", e.ToString()); + currentReplay = null; + } + } + } + } + + void AddReplay(ScrollPanelWidget list, string filename, LabelWidget template) + { + var entry = template.Clone() as LabelWidget; + entry.Id = "REPLAY_"; + entry.GetText = () => " {0}".F(Path.GetFileName(filename)); + entry.GetBackground = () => (CurrentReplay == filename) ? "dialog2" : null; + entry.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; CurrentReplay = filename; return true; }; + entry.IsVisible = () => true; + list.AddChild(entry); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs index 56b197d226..8a8a3cd5c7 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs @@ -112,7 +112,7 @@ namespace OpenRA.Mods.RA.Widgets.Delegates } /* a maze of twisty little hacks,... */ - class ReplaySummary + public class ReplaySummary { public readonly int Duration; public readonly Session LobbyInfo; diff --git a/mods/cnc/chrome/mainmenu.yaml b/mods/cnc/chrome/mainmenu.yaml index f6ad8e2cdc..5bd068cc48 100644 --- a/mods/cnc/chrome/mainmenu.yaml +++ b/mods/cnc/chrome/mainmenu.yaml @@ -55,8 +55,8 @@ Container@MENU_BACKGROUND: Width:140 Height:35 Text:Settings - CncMenuButton@REPLAY_BUTTON: - Id:REPLAY_BUTTON + CncMenuButton@REPLAYS_BUTTON: + Id:REPLAYS_BUTTON X:450 Y:0 Width:140 diff --git a/mods/cnc/chrome/replaybrowser.yaml b/mods/cnc/chrome/replaybrowser.yaml new file mode 100644 index 0000000000..c06b101238 --- /dev/null +++ b/mods/cnc/chrome/replaybrowser.yaml @@ -0,0 +1,92 @@ +Container@REPLAYBROWSER_PANEL: + Id:REPLAYBROWSER_PANEL + Delegate:CncReplayBrowserLogic + X:(WINDOW_RIGHT - WIDTH)/2 + Y:(WINDOW_BOTTOM - 500)/2 + Width:740 + Height:535 + Children: + Label@TITLE: + Width:740 + Y:0-25 + Font:BigBold + Contrast:true + Align:Center + Text:Replay Viewer + Background@bg: + Width:740 + Height:500 + Background:panel-black + Children: + CncScrollPanel@REPLAY_LIST: + Id:REPLAY_LIST + X:15 + Y:50 + Width:390 + Height:300 + Children: + Label@REPLAY_TEMPLATE: + Id:REPLAY_TEMPLATE + Width:PARENT_RIGHT-28 + Height:25 + X:2 + Y:0 + Visible:false + Container@REPLAY_INFO: + Id:REPLAY_INFO + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Visible:false + Children: + MapPreview@MAP_PREVIEW: + Id:MAP_PREVIEW + X:PARENT_RIGHT-241 + Y:30 + Width:192 + Height:192 + Label@MAP_TITLE_LABEL: + Id:MAP_TITLE_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:250 + Align:Right + Width:70 + Height:20 + Text:Map: + Bold:True + Label@MAP_TITLE: + Id:MAP_TITLE + X:PARENT_RIGHT - 195 + Y:250 + Align:Left + Width:70 + Height:20 + Label@DURATION_LABEL: + Id:DURATION_LABEL + X:PARENT_RIGHT - 200 - WIDTH + Y:270 + Align:Right + Width:70 + Height:20 + Text:Duration: + Bold:True + Label@DURATION: + Id:DURATION + X:PARENT_RIGHT - 195 + Y:270 + Align:Left + Width:70 + Height:20 + CncMenuButton@WATCH_BUTTON: + Id:WATCH_BUTTON + X:0 + Y:499 + Width:140 + Height:35 + Text:Watch + CncMenuButton@CANCEL_BUTTON: + Id:CANCEL_BUTTON + X:600 + Y:499 + Width:140 + Height:35 + Text:Back \ No newline at end of file diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 17e95cf281..4df3099a0c 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -65,6 +65,7 @@ ChromeLayout: mods/cnc/chrome/directconnect.yaml mods/cnc/chrome/lobby.yaml mods/cnc/chrome/mapchooser.yaml + mods/cnc/chrome/replaybrowser.yaml mods/cnc/chrome/ingame.yaml Weapons: