#region Copyright & License Information /* * Copyright 2007-2019 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, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Widgets; namespace OpenRA.Mods.Common.UpdateRules.Rules { public class ReformatChromeProvider : UpdateRule { public override string Name { get { return "Reformat UI image definitions."; } } public override string Description { get { return "The format of the chrome.yaml file defining image regions for the UI has\n" + "changed to support additional metadata fields. "; } } readonly List overrideLocations = new List(); readonly List panelLocations = new List(); public override IEnumerable AfterUpdate(ModData modData) { if (overrideLocations.Any()) yield return "Region-specific image overrides are no longer supported. The following definitions must be replaced:\n" + UpdateUtils.FormatMessageList(overrideLocations); if (panelLocations.Any()) yield return "The following definitions appear to be panels, but could not be converted to the new PanelRegion format.\n" + "You may wish to define PanelRegion/PanelSides manually to reduce duplication:\n" + UpdateUtils.FormatMessageList(panelLocations); overrideLocations.Clear(); panelLocations.Clear(); } readonly string[] edgeKeys = { "corner-tl", "corner-tr", "corner-bl", "corner-br", "border-t", "border-b", "border-l", "border-r" }; bool ExtractPanelDefinition(MiniYamlNode chromeProviderNode, MiniYamlNode regionsNode) { var cNode = regionsNode.LastChildMatching("background"); var hasCenter = cNode != null; var hasEdges = edgeKeys.Any(k => regionsNode.LastChildMatching(k) != null); // Not a panel if (!hasCenter && !hasEdges) return true; // Panels may define just the background if (hasCenter && !hasEdges) { var bgRect = cNode.NodeValue(); chromeProviderNode.AddNode("PanelRegion", new[] { bgRect.X, bgRect.Y, 0, 0, bgRect.Width, bgRect.Height, 0, 0 }); chromeProviderNode.AddNode("PanelSides", PanelSides.Center); regionsNode.RemoveNode(cNode); return true; } // Panels may define just the edges, or edges plus background var tlNode = regionsNode.LastChildMatching("corner-tl"); if (tlNode == null) return false; var tlRect = tlNode.NodeValue(); var tNode = regionsNode.LastChildMatching("border-t"); if (tNode == null) return false; var tRect = tNode.NodeValue(); if (tRect.Left != tlRect.Right || tRect.Top != tlRect.Top || tRect.Bottom != tlRect.Bottom) return false; var trNode = regionsNode.LastChildMatching("corner-tr"); if (trNode == null) return false; var trRect = trNode.NodeValue(); if (trRect.Left != tRect.Right || trRect.Top != tRect.Top || trRect.Bottom != tRect.Bottom) return false; var lNode = regionsNode.LastChildMatching("border-l"); if (lNode == null) return false; var lRect = lNode.NodeValue(); if (lRect.Left != tlRect.Left || lRect.Top != tlRect.Bottom || lRect.Right != tlRect.Right) return false; var rNode = regionsNode.LastChildMatching("border-r"); if (rNode == null) return false; var rRect = rNode.NodeValue(); if (rRect.Left != trRect.Left || rRect.Top != trRect.Bottom || rRect.Bottom != lRect.Bottom || rRect.Right != trRect.Right) return false; var blNode = regionsNode.LastChildMatching("corner-bl"); if (blNode == null) return false; var blRect = blNode.NodeValue(); if (blRect.Left != lRect.Left || blRect.Top != lRect.Bottom || blRect.Right != lRect.Right) return false; var bNode = regionsNode.LastChildMatching("border-b"); if (bNode == null) return false; var bRect = bNode.NodeValue(); if (bRect.Left != blRect.Right || bRect.Top != blRect.Top || bRect.Bottom != blRect.Bottom || bRect.Right != tRect.Right) return false; var brNode = regionsNode.LastChildMatching("corner-br"); if (brNode == null) return false; var brRect = brNode.NodeValue(); if (brRect.Left != bRect.Right || brRect.Top != bRect.Top || brRect.Bottom != bRect.Bottom || brRect.Right != rRect.Right) return false; // Background definition may be omitted if (hasCenter) { var bgRect = cNode.NodeValue(); if (bgRect.Left != lRect.Right || bgRect.Top != lRect.Top || bgRect.Bottom != lRect.Bottom || bgRect.Right != tRect.Right) return false; } // Define the short-form panel region chromeProviderNode.AddNode("PanelRegion", new[] { tlRect.X, tlRect.Y, tlRect.Width, tlRect.Height, trRect.Left - tlRect.Right, blRect.Top - tlRect.Bottom, brRect.Width, brRect.Height }); if (!hasCenter) chromeProviderNode.AddNode("PanelSides", PanelSides.Edges); // Remove the now redundant regions regionsNode.RemoveNode(tlNode); regionsNode.RemoveNode(tNode); regionsNode.RemoveNode(trNode); regionsNode.RemoveNode(lNode); regionsNode.RemoveNode(rNode); regionsNode.RemoveNode(blNode); regionsNode.RemoveNode(bNode); regionsNode.RemoveNode(brNode); if (cNode != null) regionsNode.RemoveNode(cNode); return true; } public override IEnumerable UpdateChromeProviderNode(ModData modData, MiniYamlNode chromeProviderNode) { // Migrate image rectangles var regionsNode = new MiniYamlNode("Regions", ""); foreach (var n in chromeProviderNode.Value.Nodes) { if (n.Key == "Inherits") continue; // Reformat region as a list regionsNode.AddNode(n.Key, n.NodeValue()); if (n.Value.Nodes.Any()) overrideLocations.Add("{0}.{1} ({2})".F(chromeProviderNode.Key, n.Key, chromeProviderNode.Location.Filename)); } chromeProviderNode.Value.Nodes.RemoveAll(n => n.Key != "Inherits"); // Migrate image definition chromeProviderNode.AddNode(new MiniYamlNode("Image", chromeProviderNode.Value.Value)); chromeProviderNode.Value.Value = ""; if (!ExtractPanelDefinition(chromeProviderNode, regionsNode)) panelLocations.Add("{0} ({1})".F(chromeProviderNode.Key, chromeProviderNode.Location.Filename)); if (regionsNode.Value.Nodes.Any()) chromeProviderNode.AddNode(regionsNode); yield break; } } }