view UI/EquipmentAmountControl.cs @ 114:727c1b0e49a6

Fixes #115: Typing number for equipment amount doesn't update Okay button * Remove KeyDown capture code (AcceptButton functionality captures the key press first) * Add ProcessDialogKey method that uses ValueChanged helper class to determine whether the control changes when we force an update New functionality is that the values can be typed and changed by pressing Enter, then a second Enter will accept the changes and close the dialog. If no changes were made then pressing Enter once accepts changes and closes the dialog.
author IBBoard <dev@ibboard.co.uk>
date Thu, 24 Dec 2009 12:04:32 +0000
parents c1a3993297b1
children e00332dc1618
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using log4net;
using IBBoard.CustomMath;
using IBBoard.Lang;
using IBBoard.Limits;
using IBBoard.Windows.Forms.I18N;
using IBBoard.Windows.Forms.Util;
using IBBoard.WarFoundry.API;
using IBBoard.WarFoundry.API.Objects;
using IBBoard.WarFoundry.API.Util;

namespace IBBoard.WarFoundry.GUI.WinForms.UI
{
	public partial class EquipmentAmountControl : UserControl
	{
		private ILog log = LogManager.GetLogger(typeof(EquipmentAmountControl));
		private Unit unit;
		private UnitEquipmentItem equip;
		public event EventHandler ValueChanged;

		public EquipmentAmountControl()
		{
			InitializeComponent();
			ControlTranslator.TranslateControl(this);
		}

		public void SetUnit(Unit equipUnit)
		{
			unit = equipUnit;
			log.Debug("Set unit to: " + (unit == null ? "null" : unit.Name));
		}

		public void SetUnitEquipmentItem(UnitEquipmentItem unitEquipment)
		{
			equip = unitEquipment;
			log.Debug("Set equipment to: " + (equip == null ? "null" : equip.Name));
			SetWidgetValues();
		}

		private void OnValueChanged()
		{
			if (ValueChanged != null)
			{
				ValueChanged(this, new EventArgs());
			}
		}

		private void SetWidgetValues()
		{
			if (equip != null)
			{
				IgnoreWidgets();

				Enabled = true;

				log.Debug("Equipment update");
				bool equipIsRatioLimit = UnitEquipmentUtil.IsEquipmentRatioLimited(unit, equip);
				log.Debug("Equipment is ratio? " + (equipIsRatioLimit ? "yes" : "no"));
				double maxPercent = RoundPercentage(UnitEquipmentUtil.GetMaxEquipmentPercentage(unit, equip));
				maxPercent = Math.Max(0, maxPercent);
				log.Debug("Equipment max percentage: " + maxPercent);
				double minPercent = RoundPercentage(UnitEquipmentUtil.GetMinEquipmentPercentage(unit, equip));
				minPercent = Math.Max(0, minPercent);
				log.Debug("Equipment min percentage: " + minPercent);
				int maxNumber = UnitEquipmentUtil.GetMaxEquipmentCount(unit, equip);
				maxNumber = Math.Max(0, maxNumber);
				log.Debug("Equipment max count: " + maxNumber);
				int minNumber = UnitEquipmentUtil.GetMinEquipmentCount(unit, equip);
				minNumber = Math.Max(0, minNumber);
				log.Debug("Equipment min count: " + minNumber);

				SetUpDownControlMinMaxes(minPercent, maxPercent, minNumber, maxNumber);

				if (equipIsRatioLimit)
				{
					SetEquipmentAmountsFromPercentage(minPercent);
				}
				else
				{
					SetEquipmentAmountsFromNumber(minNumber);
				}

				rbEquipAll.Enabled = equipIsRatioLimit && maxPercent == 100;
				rbEquipAll.Checked = equipIsRatioLimit && minPercent == 100;
				log.Debug("rbEquipAll: " + (rbEquipAll.Enabled ? "enabled":"disabled") + " " + (rbEquipAll.Checked ? "checked" : "unchecked"));
				percentage.Enabled = equipIsRatioLimit && minPercent != 100;
				rbPercentage.Enabled = percentage.Enabled;
				rbPercentage.Checked = equipIsRatioLimit && !rbEquipAll.Checked;
				log.Debug("rbPercentage: " + (rbPercentage.Enabled ? "enabled" : "disabled") + " " + (rbPercentage.Checked ? "checked" : "unchecked"));
				numeric.Enabled = !equipIsRatioLimit || minPercent != 100;
				rbNumeric.Enabled = numeric.Enabled;
				rbNumeric.Checked = !equipIsRatioLimit;
				log.Debug("rbNumeric: " + (rbNumeric.Enabled ? "enabled" : "disabled") + " " + (rbNumeric.Checked ? "checked" : "unchecked"));
				SetUnitEquipmentItemAmount();

				ListenToWidgets();
			}
			else
			{
				log.Debug("Null equipment - no widget update");
				Enabled = false;
			}
		}

		private void IgnoreWidgets()
		{
			percentage.ValueChanged -= percentage_ValueChanged;
			numeric.ValueChanged -= numeric_ValueChanged;
			rbEquipAll.CheckedChanged -= rbEquipAll_CheckedChanged;
			rbNumeric.CheckedChanged -= radioCheckedChanged;
			rbPercentage.CheckedChanged -= radioCheckedChanged;
		}

		private void ListenToWidgets()
		{
			percentage.ValueChanged += percentage_ValueChanged;
			numeric.ValueChanged += numeric_ValueChanged;
			rbEquipAll.CheckedChanged += rbEquipAll_CheckedChanged;
			rbNumeric.CheckedChanged += radioCheckedChanged;
			rbPercentage.CheckedChanged += radioCheckedChanged;
		}

		private void SetUpDownControlMinMaxes(double minPercent, double maxPercent, int minNumber, int maxNumber)
		{
			SetUpDownControlMinMax(percentage, minPercent, maxPercent);
			SetUpDownControlMinMax(numeric, (decimal) minNumber, (decimal) maxNumber);
		}

		private void SetUpDownControlMinMax(NumericUpDown upDownControl, double min, double max)
		{
			SetUpDownControlMinMax(upDownControl, (decimal)min, (decimal)max);
		}

		private void SetUpDownControlMinMax(NumericUpDown upDownControl, decimal min, decimal max)
		{
			log.Debug("Set "+upDownControl.Name+" min and max to: "+min+", "+max);
			upDownControl.Minimum = min;
			upDownControl.Maximum = max;
		}

		private void rbEquipAll_CheckedChanged(object sender, EventArgs e)
		{
			bool equipAll = rbEquipAll.Checked;
			numeric.Enabled = !equipAll;
			percentage.Enabled = !equipAll;

			if (equipAll)
			{
				numeric.Value = unit.Size;
				percentage.Value = 100;
			}

			radioCheckedChanged(sender, e);
		}

		private void percentage_ValueChanged(object sender, EventArgs e)
		{
			PerformPercentageValueChanged();
		}

		private void PerformPercentageValueChanged()
		{
			log.Debug("Percentage value changed");
			SetNumericValueFromPercentage();
			rbEquipAll.Checked = (percentage.Value == 100 && !rbNumeric.Checked);
			OnValueChanged();
		}

		private void SetNumericValueFromPercentage()
		{
			numeric.ValueChanged -= numeric_ValueChanged;
			numeric.Value = CalculateNumericValueFromPercentage(percentage.Value);
			numeric.ValueChanged += numeric_ValueChanged;
		}

		private decimal CalculateNumericValueFromPercentage(decimal percent)
		{
			decimal calcedAmount = (decimal) IBBoard.CustomMath.IBBMath.Round((double)(unit.Size * (percent / 100)), equip.RoundNumberUp);
			log.Debug("Numeric value calculated from percentage: "+percent+"% -> "+calcedAmount);
			return Math.Min(Math.Max(calcedAmount, numeric.Minimum), numeric.Maximum);
		}

		private void numeric_ValueChanged(object sender, EventArgs e)
		{
			log.Debug("Numeric value changed");
			SetPercentageValueFromNumeric();
			OnValueChanged();
		}

		private void SetPercentageValueFromNumeric()
		{
			int number = (int)numeric.Value;
			percentage.ValueChanged -= percentage_ValueChanged;
			percentage.Value = CalcualtePercentageValueFromNumber(number);
			percentage.ValueChanged += percentage_ValueChanged;
		}

		private decimal CalcualtePercentageValueFromNumber(int number)
		{
			decimal calcedAmount =  (decimal) RoundPercentage(IBBoard.CustomMath.IBBMath.Percentage(number, unit.Size));
			log.Debug("Numeric value calculated from percentage: " + number + " -> " + calcedAmount+"%");
			return Math.Min(Math.Max(calcedAmount, percentage.Minimum), percentage.Maximum);
		}

		private double RoundPercentage(double percent)
		{
			return Math.Round(percent, 1);
		}

		public double EquipmentAmount
		{
			get
			{
				double val = 0;

				if (rbNumeric.Checked)
				{
					val = (double) numeric.Value;
				}
				else if (rbPercentage.Checked)
				{
					val = (double) percentage.Value;
				}
				else if (rbEquipAll.Checked)
				{
					val = 100;
				}
				else
				{
					val = 0;
				}

				return val;
			}
		}

		public bool IsRatioEquipmentAmount
		{
			get
			{
				return !rbNumeric.Checked;
			}
		}

		private void SetUnitEquipmentItemAmount()
		{
			double equipAmountNum = UnitEquipmentUtil.GetEquipmentAmount(unit, equip);

			if (equipAmountNum > 0)
			{
				bool isRatio = UnitEquipmentUtil.GetEquipmentAmountIsRatio(unit, equip);

				if (isRatio)
				{
					SetEquipmentAmountsFromPercentage(equipAmountNum);

					if (equipAmountNum == 100)
					{
						rbEquipAll.Checked = true;
					}
					else
					{
						rbPercentage.Checked = true;
					}
				}
				else
				{
					int equipAmount = (int) equipAmountNum;
					SetEquipmentAmountsFromNumber(equipAmount);
					rbNumeric.Checked = true;
				}
			}
		}

		private void SetEquipmentAmountsFromPercentage(double equipAmount)
		{
			log.Debug("Set equipment amount from percentage: " + equipAmount);
			decimal decEquipAmount = (decimal) equipAmount;

			if (decEquipAmount > percentage.Maximum)
			{
				string percentageTooLarge = Translation.GetTranslation("equipPercentageTooLarge", "the current percentage ({0}%) was larger than the maximum for the equipment item ({1}%) - the maximum value will be used instead", equipAmount, percentage.Maximum);
				string percentageTooLargeTitle = Translation.GetTranslation("equipPercentageTooLargeTitle", "equipment percentage too large");
				MessageBox.Show(ParentForm, percentageTooLarge, percentageTooLargeTitle);
				decEquipAmount = percentage.Maximum;
				log.Debug("Limited equipment amount to " + decEquipAmount);
				OnValueChanged();
			}
			else if (decEquipAmount < percentage.Minimum)
			{
				string percentageTooSmall = Translation.GetTranslation("equipPercentageTooSmall", "the current percentage ({0}%) was smaller than the minimum for the equipment item ({1}%) - the minimum value will be used instead", equipAmount, percentage.Minimum);
				string percentageTooSmallTitle = Translation.GetTranslation("equipPercentageTooSmallTitle", "equipment percentage too small");
				MessageBox.Show(ParentForm, percentageTooSmall, percentageTooSmallTitle);
				decEquipAmount = percentage.Minimum;
				log.Debug("Limited equipment amount to " + decEquipAmount);
				OnValueChanged();
			}

			numeric.Value = CalculateNumericValueFromPercentage(decEquipAmount);
			percentage.Value = decEquipAmount;
		}

		private void SetEquipmentAmountsFromNumber(int equipAmount)
		{
			log.Debug("Set equipment percentage from amount: " + equipAmount);

			if (equipAmount > numeric.Maximum)
			{
				string amountTooLarge = Translation.GetTranslation("equipNumberTooLarge", "the current amount ({0}) was larger than the maximum for the equipment item ({1}) - the maximum value will be used instead", equipAmount, numeric.Maximum);
				string amountTooLargeTitle = Translation.GetTranslation("equipNumberTooLargeTitle", "equipment amount too large");
				MessageBox.Show(ParentForm, amountTooLarge, amountTooLargeTitle);
				equipAmount = (int)numeric.Maximum;
				log.Debug("Limited equipment amount to " + equipAmount);
				OnValueChanged();
			}
			else if (equipAmount < numeric.Minimum)
			{
				string amountTooSmall = Translation.GetTranslation("equipNumberTooSmall", "the current amount ({0}) was smaller than the minimum for the equipment item ({1}) - the minimum value will be used instead", equipAmount, numeric.Minimum);
				string amountTooSmallTitle = Translation.GetTranslation("equipNumberTooSmallTitle", "equipment amount too small");
				MessageBox.Show(ParentForm, amountTooSmall, amountTooSmallTitle);
				equipAmount = (int) numeric.Minimum;
				log.Debug("Limited equipment amount to " + equipAmount);
				OnValueChanged();
			}

			percentage.Value = CalcualtePercentageValueFromNumber(equipAmount);
			numeric.Value = equipAmount;
		}

		private void radioCheckedChanged(object sender, EventArgs e)
		{
			OnValueChanged();
		}

		protected override bool ProcessDialogKey(Keys keyData)
		{
			bool processed = false;

			if (keyData == Keys.Enter)
			{
				if (numeric.Focused)
				{
					processed = ForceUpDownControlUpdate(numeric);
				}
				else if (percentage.Focused)
				{
					processed = ForceUpDownControlUpdate(percentage);
				}
			}

			if (!processed)
			{
				processed = base.ProcessDialogKey(keyData);
			}

			return processed;
		}

		private bool ForceUpDownControlUpdate(NumericUpDown control)
		{
			ControlValueChangedChecker checker = new ControlValueChangedChecker();
			control.ValueChanged += checker.ValueChanged;
			decimal val = control.Value;
			control.ValueChanged -= checker.ValueChanged;
			return checker.valueChanged;
		}
	}
}