context: #region Copyright & License Information
  /*
   * Copyright 2007-2015 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.Collections.Generic;
  using System.Drawing;
  using System.Linq;
  using OpenRA.Graphics;
  using OpenRA.Mods.Common.Orders;
  using OpenRA.Mods.Common.Traits;
  using OpenRA.Network;
  using OpenRA.Widgets;
  
  namespace OpenRA.Mods.Common.Widgets
  {
  	public class ProductionIcon
  	{
  		public ActorInfo Actor;
  		public string Name;
  		public Hotkey Hotkey;
  		public Sprite Sprite;
  		public PaletteReference Palette;
  		public float2 Pos;
  		public List<ProductionItem> Queued;
  	}
  
  	public class ProductionPaletteWidget : Widget
  	{
  		public enum ReadyTextStyleOptions { Solid, AlternatingColor, Blinking }
  		public readonly ReadyTextStyleOptions ReadyTextStyle = ReadyTextStyleOptions.AlternatingColor;
  		public readonly Color ReadyTextAltColor = Color.Gold;
  		public readonly int Columns = 3;
  		public readonly int2 IconSize = new int2(64, 48);
  		public readonly int2 IconMargin = int2.Zero;
  		public readonly int2 IconSpriteOffset = int2.Zero;
  
  		public readonly string TabClick = null;
  		public readonly string DisabledTabClick = null;
  		public readonly string TooltipContainer;
  		public readonly string TooltipTemplate = "PRODUCTION_TOOLTIP";
  
  		[Translate] public readonly string ReadyText = "";
  		[Translate] public readonly string HoldText = "";
  
  		public int DisplayedIconCount { get; private set; }
  		public int TotalIconCount { get; private set; }
  		public event Action<int, int> OnIconCountChanged = (a, b) => { };
  
  		public ProductionIcon TooltipIcon { get; private set; }
  		public readonly World World;
  		readonly OrderManager orderManager;
  
  		public int MinimumRows = 4;
  		public int MaximumRows = int.MaxValue;
  
  		public int IconRowOffset = 0;
  		public int MaxIconRowOffset = int.MaxValue;
  
  		Lazy<TooltipContainerWidget> tooltipContainer;
  		ProductionQueue currentQueue;
  
  		public ProductionQueue CurrentQueue
  		{
  			get { return currentQueue; }
  			set { currentQueue = value; RefreshIcons(); }
  		}
  
  		public override Rectangle EventBounds { get { return eventBounds; } }
  		Dictionary<Rectangle, ProductionIcon> icons = new Dictionary<Rectangle, ProductionIcon>();
  		Animation cantBuild, clock;
  		Rectangle eventBounds = Rectangle.Empty;
  		readonly WorldRenderer worldRenderer;
  		SpriteFont overlayFont;
  		float2 holdOffset, readyOffset, timeOffset, queuedOffset;
  
  		[ObjectCreator.UseCtor]
  		public ProductionPaletteWidget(OrderManager orderManager, World world, WorldRenderer worldRenderer)
  		{
  			this.orderManager = orderManager;
  			this.World = world;
  			this.worldRenderer = worldRenderer;
  			tooltipContainer = Exts.Lazy(() =>
  				Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
  
  			cantBuild = new Animation(world, "clock");
  			cantBuild.PlayFetchIndex("idle", () => 0);
  			clock = new Animation(world, "clock");
  		}
  
  		public void ScrollDown()
  		{
  			if (CanScrollDown)
  				IconRowOffset++;
  		}
  
  		public bool CanScrollDown
  		{
  			get
  			{
  				var totalRows = (TotalIconCount + Columns - 1) / Columns;
  
  				return IconRowOffset < totalRows - MaxIconRowOffset;
  			}
  		}
  
  		public void ScrollUp()
  		{
  			if (CanScrollUp)
  				IconRowOffset--;
  		}
  
  		public bool CanScrollUp
  		{
  			get { return IconRowOffset > 0; }
  		}
  
  		public void ScrollToTop()
  		{
  			IconRowOffset = 0;
  		}
  
  		public IEnumerable<ActorInfo> AllBuildables
  		{
  			get
  			{
  				if (CurrentQueue == null)
  					return Enumerable.Empty<ActorInfo>();
  
  				return CurrentQueue.AllItems().OrderBy(a => a.Traits.Get<BuildableInfo>().BuildPaletteOrder);
  			}
  		}
  
  		public override void Tick()
  		{
  			TotalIconCount = AllBuildables.Count();
  
  			if (CurrentQueue != null && !CurrentQueue.Actor.IsInWorld)
  				CurrentQueue = null;
  
  			if (CurrentQueue != null)
  				RefreshIcons();
  		}
  
  		public override void MouseEntered()
  		{
  			if (TooltipContainer != null)
  				tooltipContainer.Value.SetTooltip(TooltipTemplate,
  					new WidgetArgs() { { "palette", this } });
  		}
  
  		public override void MouseExited()
  		{
  			if (TooltipContainer != null)
  				tooltipContainer.Value.RemoveTooltip();
  		}
  
  		public override bool HandleMouseInput(MouseInput mi)
  		{
  			var icon = icons.Where(i => i.Key.Contains(mi.Location))
  				.Select(i => i.Value).FirstOrDefault();
  
  			if (mi.Event == MouseInputEvent.Move)
  				TooltipIcon = icon;
  
  			if (icon == null)
  				return false;
  
  			// Only support left and right clicks
  			if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right)
  				return false;
  
  			// Eat mouse-up events
  			if (mi.Event != MouseInputEvent.Down)
  				return true;
  
  			return HandleEvent(icon, mi.Button == MouseButton.Left, mi.Modifiers.HasModifier(Modifiers.Shift));
  		}
  
  		protected bool PickUpCompletedBuildingIcon(ProductionIcon icon, ProductionItem item)
  		{
  			var actor = World.Map.Rules.Actors[icon.Name];
  
  			if (item != null && item.Done && actor.Traits.Contains<BuildingInfo>())
  			{
  				World.OrderGenerator = new PlaceBuildingOrderGenerator(CurrentQueue, icon.Name);
  				return true;
  			}
  
  			return false;
  		}
  
  		public void PickUpCompletedBuilding()
  		{
  			foreach (var icon in icons.Values)
  			{
  				var item = icon.Queued.FirstOrDefault();
  				if (PickUpCompletedBuildingIcon(icon, item))
  					break;
  			}
  		}
  
  		bool HandleLeftClick(ProductionItem item, ProductionIcon icon, bool handleMultiple)
  		{
  			if (PickUpCompletedBuildingIcon(icon, item))
  			{
  				Sound.Play(TabClick);
  				return true;
  			}
  
  			if (item != null && item.Paused)
  			{
  				// Resume a paused item
  				Sound.Play(TabClick);
  				World.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, icon.Name, false));
  				return true;
  			}
  
  			if (CurrentQueue.BuildableItems().Any(a => a.Name == icon.Name))
  			{
  				// Queue a new item
  				Sound.Play(TabClick);
  				Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.QueuedAudio, World.LocalPlayer.Faction.InternalName);
  				World.IssueOrder(Order.StartProduction(CurrentQueue.Actor, icon.Name,
  					handleMultiple ? 5 : 1));
  				return true;
  			}
  
  			return false;
  		}
  
  		bool HandleRightClick(ProductionItem item, ProductionIcon icon, bool handleMultiple)
  		{
  			if (item == null)
  				return false;
  
  			Sound.Play(TabClick);
  
  			if (item.Paused || item.Done || item.TotalCost == item.RemainingCost)
  			{
  				// Instant cancel of things we have not started yet and things that are finished
  				Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.CancelledAudio, World.LocalPlayer.Faction.InternalName);
  				World.IssueOrder(Order.CancelProduction(CurrentQueue.Actor, icon.Name,
  					handleMultiple ? 5 : 1));
  			}
  			else
  			{
  				// Pause an existing item
  				Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.OnHoldAudio, World.LocalPlayer.Faction.InternalName);
  				World.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, icon.Name, true));
  			}
  
  			return true;
  		}
  
  		bool HandleEvent(ProductionIcon icon, bool isLeftClick, bool handleMultiple)
  		{
  			var item = icon.Queued.FirstOrDefault();
  			var handled = isLeftClick ? HandleLeftClick(item, icon, handleMultiple)
  				: HandleRightClick(item, icon, handleMultiple);
  
  			if (!handled)
  				Sound.Play(DisabledTabClick);
  
  			return true;
  		}
  
  		public override bool HandleKeyPress(KeyInput e)
  		{
  			if (e.Event == KeyInputEvent.Up || CurrentQueue == null)
  				return false;
  
  			var hotkey = Hotkey.FromKeyInput(e);
  			var toBuild = icons.Values.FirstOrDefault(i => i.Hotkey == hotkey);
  			return toBuild != null ? HandleEvent(toBuild, true, false) : false;
  		}
  
  		public void RefreshIcons()
  		{
  			icons = new Dictionary<Rectangle, ProductionIcon>();
  			var producer = CurrentQueue != null ? CurrentQueue.MostLikelyProducer() : default(TraitPair<Production>);
  			if (CurrentQueue == null || producer.Trait == null)
  			{
  
gt: 				if (DisplayedIconCount != 0)