diff --git a/OpenRA.Game/Widgets/GridLayout.cs b/OpenRA.Game/Widgets/GridLayout.cs index fcb8efca20..4eabd3ed44 100644 --- a/OpenRA.Game/Widgets/GridLayout.cs +++ b/OpenRA.Game/Widgets/GridLayout.cs @@ -41,6 +41,11 @@ namespace OpenRA.Widgets widget.ContentHeight = Math.Max(widget.ContentHeight, pos.Y + widget.ItemSpacing + w.Bounds.Height); } + + public void AdjustChildren() + { + + } } } diff --git a/OpenRA.Game/Widgets/ListLayout.cs b/OpenRA.Game/Widgets/ListLayout.cs index 69d3526da5..83779fc4ce 100644 --- a/OpenRA.Game/Widgets/ListLayout.cs +++ b/OpenRA.Game/Widgets/ListLayout.cs @@ -21,8 +21,18 @@ namespace OpenRA.Widgets if (widget.Children.Count == 0) widget.ContentHeight = widget.ItemSpacing; - w.Bounds.Y += widget.ContentHeight; + w.Bounds.Y = widget.ContentHeight; widget.ContentHeight += w.Bounds.Height + widget.ItemSpacing; } + + public void AdjustChildren() + { + widget.ContentHeight = widget.ItemSpacing; + foreach (var w in widget.Children) + { + w.Bounds.Y = widget.ContentHeight; + widget.ContentHeight += w.Bounds.Height + widget.ItemSpacing; + } + } } } diff --git a/OpenRA.Game/Widgets/ScrollPanelWidget.cs b/OpenRA.Game/Widgets/ScrollPanelWidget.cs index 365670a007..185a41cfed 100644 --- a/OpenRA.Game/Widgets/ScrollPanelWidget.cs +++ b/OpenRA.Game/Widgets/ScrollPanelWidget.cs @@ -14,7 +14,7 @@ using OpenRA.Graphics; namespace OpenRA.Widgets { - public interface ILayout { void AdjustChild(Widget w); } + public interface ILayout { void AdjustChild(Widget w); void AdjustChildren(); } public class ScrollPanelWidget : Widget { @@ -50,6 +50,25 @@ namespace OpenRA.Widgets base.AddChild(child); } + public override void RemoveChild(Widget child) + { + base.RemoveChild(child); + Layout.AdjustChildren(); + Scroll(0); + } + + public void ReplaceChild(Widget oldChild, Widget newChild) + { + + oldChild.Removed(); + newChild.Parent = this; + Children[Children.IndexOf(oldChild)] = newChild; + Layout.AdjustChildren(); + Scroll(0); + } + + + public override void DrawOuter() { if (!IsVisible()) diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index 75dab0dd9d..9f2aaf3acc 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -325,21 +325,24 @@ namespace OpenRA.Mods.RA.Widgets.Logic void UpdatePlayerList() { - // This causes problems for people who are in the process of editing their names (the widgets vanish from beneath them) - // Todo: handle this nicer - Players.RemoveChildren(); - + var idx = 0; foreach (var kv in orderManager.LobbyInfo.Slots) { var key = kv.Key; var slot = kv.Value; var client = orderManager.LobbyInfo.ClientInSlot(key); - Widget template; + Widget template = null; + + // get template for possible reuse + if (idx < Players.Children.Count) + template = Players.Children [idx]; // Empty slot if (client == null) { - template = EmptySlotTemplate.Clone(); + if (template == null || template.Id != EmptySlotTemplate.Id) + template = EmptySlotTemplate.Clone(); + Func getText = () => slot.Closed ? "Closed" : "Open"; var ready = orderManager.LocalClient.IsReady; @@ -367,7 +370,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic else if ((client.Index == orderManager.LocalClient.Index) || (client.Bot != null && Game.IsHost)) { - template = EditablePlayerTemplate.Clone(); + if (template == null || template.Id != EditablePlayerTemplate.Id) + template = EditablePlayerTemplate.Clone(); + var botReady = client.Bot != null && Game.IsHost && orderManager.LocalClient.IsReady; var ready = botReady || client.IsReady; @@ -422,7 +427,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic } else { // Non-editable player in slot - template = NonEditablePlayerTemplate.Clone(); + if (template == null || template.Id != NonEditablePlayerTemplate.Id) + template = NonEditablePlayerTemplate.Clone(); + template.Get("NAME").GetText = () => client.Name; if (client.IsAdmin) template.Get("NAME").Font = "Bold"; @@ -449,20 +456,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic } template.IsVisible = () => true; - Players.AddChild(template); + + if (idx >= Players.Children.Count) + Players.AddChild(template); + else if (Players.Children[idx].Id != template.Id) + Players.ReplaceChild(Players.Children[idx], template); + + idx++; } // Add spectators foreach (var client in orderManager.LobbyInfo.Clients.Where(client => client.Slot == null)) { - Widget template; + Widget template = null; var c = client; var ready = c.IsReady; + // get template for possible reuse + if (idx < Players.Children.Count) + template = Players.Children[idx]; + // Editable spectator if (c.Index == orderManager.LocalClient.Index) { - template = EditableSpectatorTemplate.Clone(); + if (template == null || template.Id != EditableSpectatorTemplate.Id) + template = EditableSpectatorTemplate.Clone(); + var name = template.Get("NAME"); name.IsDisabled = () => ready; LobbyUtils.SetupNameWidget(orderManager, c, name); @@ -481,7 +500,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic // Non-editable spectator else { - template = NonEditableSpectatorTemplate.Clone(); + if (template == null || template.Id != NonEditableSpectatorTemplate.Id) + template = NonEditableSpectatorTemplate.Clone(); + template.Get("NAME").GetText = () => c.Name; if (client.IsAdmin) template.Get("NAME").Font = "Bold"; @@ -497,19 +518,40 @@ namespace OpenRA.Mods.RA.Widgets.Logic } template.IsVisible = () => true; - Players.AddChild(template); + + if (idx >= Players.Children.Count) + Players.AddChild(template); + else if (Players.Children[idx].Id != template.Id) + Players.ReplaceChild(Players.Children[idx], template); + + idx++; } + // Spectate button if (orderManager.LocalClient.Slot != null) { - var spec = NewSpectatorTemplate.Clone(); + Widget spec = null; + if (idx < Players.Children.Count) + spec = Players.Children[idx]; + if (spec == null || spec.Id != NewSpectatorTemplate.Id) + spec = NewSpectatorTemplate.Clone(); + var btn = spec.Get("SPECTATE"); btn.OnClick = () => orderManager.IssueOrder(Order.Command("spectate")); btn.IsDisabled = () => orderManager.LocalClient.IsReady; spec.IsVisible = () => true; - Players.AddChild(spec); + + if (idx >= Players.Children.Count) + Players.AddChild(spec); + else if (Players.Children[idx].Id != spec.Id) + Players.ReplaceChild(Players.Children[idx], spec); + + idx++; } + + while (Players.Children.Count > idx) + Players.RemoveChild(Players.Children[idx]); } void CycleReady()