UltimateZoneBuilder/Source/Core/Controls/ArgumentsControl.cs

556 lines
17 KiB
C#
Executable file

#region ================== Namespaces
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.GZBuilder.Data;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.GZBuilder;
#endregion
namespace CodeImp.DoomBuilder.Controls
{
public partial class ArgumentsControl : UserControl
{
#region ================== Native stuff
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);
private const int WM_SETREDRAW = 11;
#endregion
#region ================== Enums
private enum ArgZeroMode
{
DEFAULT,
INT,
STRING,
}
#endregion
#region ================== Variables
private string arg0strval;
private bool havearg0str;
private int action;
private ArgumentInfo[] arginfo;
private ArgZeroMode argzeromode;
private Label[] labels;
private ArgumentBox[] args;
private ArgZeroMode Arg0Mode
{
get { return argzeromode; }
set
{
arg0label.Text = (value == ArgZeroMode.STRING ? arginfo[0].TitleStr : arginfo[0].Title) + ":";
argzeromode = value;
}
}
#endregion
#region ================== Constructor
public ArgumentsControl()
{
InitializeComponent();
Reset();
labels = new Label[] { arg0label, arg1label, arg2label, arg3label, arg4label };
args = new ArgumentBox[] { arg0, arg1, arg2, arg3, arg4 };
}
#endregion
#region ================== Setup
public void Reset()
{
// Only when running (this.DesignMode won't do when not this, but one of parent controls is in design mode)
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
// do nothing.
}
}
public void SetValue(Linedef l, bool first)
{
SetValue(l.Fields, l.Args, first);
}
public void SetValue(Thing t, bool first)
{
SetValue(t.Fields, t.Args, first);
}
private void SetValue(UniFields fields, int[] newargs, bool first)
{
if(first)
{
if(General.Map.UDMF)
{
arg0strval = fields.GetValue("arg0str", string.Empty);
havearg0str = !string.IsNullOrEmpty(arg0strval);
}
// Update arguments
for (int i = 0; i < args.Length; i++)
args[i].SetValue(newargs[i]);
}
else
{
if(General.Map.UDMF)
{
if(arg0strval != fields.GetValue("arg0str", string.Empty))
{
havearg0str = true;
arg0strval = string.Empty;
}
}
// Update arguments
for (int i = 0; i < args.Length; i++)
if (!string.IsNullOrEmpty(args[i].Text) && newargs[i] != args[i].GetResult(int.MinValue)) args[i].ClearValue();
}
}
#endregion
#region ================== Apply
public void Apply(Linedef l, int step)
{
//mxd. Script name/number handling
// We can't rely on control visibility here, because all controlls will be invisible if ArgumentsControl is invisible
// (for example, when a different tab is selected)
bool isacs = (Array.IndexOf(GZGeneral.ACS_SPECIALS, action) != -1);
switch(Arg0Mode)
{
// Apply arg0str
case ArgZeroMode.STRING:
if (isacs)
{
if (!string.IsNullOrEmpty(arg0named.Text))
l.Fields["arg0str"] = new UniValue(UniversalType.String, arg0named.Text);
}
else
{
if (!string.IsNullOrEmpty(arg0str.Text))
l.Fields["arg0str"] = new UniValue(UniversalType.String, arg0str.Text);
}
break;
// Apply script number
case ArgZeroMode.INT:
if (!isacs)
goto case ArgZeroMode.DEFAULT;
//
if(!string.IsNullOrEmpty(arg0int.Text))
{
if(arg0int.SelectedItem != null)
l.Args[0] = ((ScriptItem)((ColoredComboBoxItem)arg0int.SelectedItem).Value).Index;
else if(!int.TryParse(arg0int.Text.Trim(), out l.Args[0]))
l.Args[0] = 0;
if(l.Fields.ContainsKey("arg0str")) l.Fields.Remove("arg0str");
}
break;
// Apply classic arg
case ArgZeroMode.DEFAULT:
l.Args[0] = arg0.GetResult(l.Args[0], step);
if(l.Fields.ContainsKey("arg0str")) l.Fields.Remove("arg0str");
break;
default: throw new NotImplementedException("Unknown ArgZeroMode");
}
// Apply the rest of args
for (int i = 1; i < args.Length; i++)
l.Args[i] = args[i].GetResult(l.Args[i], step);
}
public void Apply(Thing t, int step)
{
//mxd. Script name/number handling
// We can't rely on control visibility here, because all controlls will be invisible if ArgumentsControl is invisible
// (for example, when a different tab is selected)
bool isacs = (Array.IndexOf(GZGeneral.ACS_SPECIALS, action) != -1);
switch (Arg0Mode)
{
// Apply arg0str
case ArgZeroMode.STRING:
if (isacs)
{
if (!string.IsNullOrEmpty(arg0named.Text))
t.Fields["arg0str"] = new UniValue(UniversalType.String, arg0named.Text);
}
else
{
if (!string.IsNullOrEmpty(arg0str.Text))
t.Fields["arg0str"] = new UniValue(UniversalType.String, arg0str.Text);
}
break;
// Apply script number
case ArgZeroMode.INT:
if (!isacs)
goto case ArgZeroMode.DEFAULT;
//
if (!string.IsNullOrEmpty(arg0int.Text))
{
if (arg0int.SelectedItem != null)
t.Args[0] = ((ScriptItem)((ColoredComboBoxItem)arg0int.SelectedItem).Value).Index;
else if (!int.TryParse(arg0int.Text.Trim(), out t.Args[0]))
t.Args[0] = 0;
if (t.Fields.ContainsKey("arg0str")) t.Fields.Remove("arg0str");
}
break;
// Apply classic arg
case ArgZeroMode.DEFAULT:
t.Args[0] = arg0.GetResult(t.Args[0], step);
if (t.Fields.ContainsKey("arg0str")) t.Fields.Remove("arg0str");
break;
default: throw new NotImplementedException("Unknown ArgZeroMode");
}
// Apply the rest of args
for (int i = 1; i < args.Length; i++)
t.Args[i] = args[i].GetResult(t.Args[i], step);
}
#endregion
#region ================== Update
public void UpdateAction(int action, bool setuponly)
{
UpdateAction(action, setuponly, null);
}
public void UpdateAction(int action, bool setuponly, ThingTypeInfo info)
{
// Update arguments
int showaction = 0;
ArgumentInfo[] oldarginfo = (arginfo != null ? (ArgumentInfo[])arginfo.Clone() : null); //mxd
// Only when action type is known
if(General.Map.Config.LinedefActions.ContainsKey(action)) showaction = action;
// Update argument infos
if((showaction == 0) && (info != null)) arginfo = info.Args;
else arginfo = General.Map.Config.LinedefActions[showaction].Args;
// Don't update action args when thing type is changed
if(info != null && showaction != 0 && this.action == showaction) return;
//mxd. Don't update action args when old and new argument infos match
if(arginfo != null && oldarginfo != null && ArgumentInfosMatch(arginfo, oldarginfo)) return;
// Change the argument descriptions
this.BeginUpdate();
for (int i = 0; i < args.Length; i++)
UpdateArgument(args[i], labels[i], arginfo[i]);
if(!setuponly)
{
// Apply action's or thing's default arguments
if(showaction != 0 || info != null)
{
for (int i = 0; i < args.Length; i++)
args[i].SetDefaultValue();
}
else //or set them to 0
{
for (int i = 0; i < args.Length; i++)
args[i].SetValue(0);
}
// arg0str currently can't have any default
arg0named.Text = arg0strval = " ";
arg0str.Text = arg0strval = " ";
}
// Store current action
this.action = showaction;
this.EndUpdate();
}
public void UpdateScriptControls()
{
// Update script-specific stuff
if (arginfo[0].Str)
{
bool isacs = (Array.IndexOf(GZGeneral.ACS_SPECIALS, action) != -1);
//mxd. Setup script numbers
arg0int.Location = new Point(arg0.Location.X, arg0.Location.Y + 2);
arg0int.Items.Clear();
// [ZZ] note: only do this if our action is acs.
if (isacs)
{
foreach (ScriptItem si in General.Map.NumberedScripts.Values)
arg0int.Items.Add(new ColoredComboBoxItem(si, si.IsInclude ? SystemColors.HotTrack : SystemColors.WindowText));
arg0int.DropDownWidth = Tools.GetDropDownWidth(arg0int);
}
//mxd. Setup script names
if (General.Map.UDMF)
{
// [ZZ] note: only do this if our action is acs.
if (isacs)
{
arg0named.Items.Clear();
arg0named.Location = arg0int.Location;
foreach (ScriptItem nsi in General.Map.NamedScripts.Values)
arg0named.Items.Add(new ColoredComboBoxItem(nsi, nsi.IsInclude ? SystemColors.HotTrack : SystemColors.WindowText));
arg0named.DropDownWidth = Tools.GetDropDownWidth(arg0named);
}
else
{
arg0str.Clear();
arg0str.Location = arg0int.Location;
}
}
else
{
arg0named.Visible = false;
arg0str.Visible = false;
cbuseargstr.Visible = false;
}
//
// Update script controls visibility
bool showarg0str = (General.Map.UDMF && havearg0str);
cbuseargstr.Visible = General.Map.UDMF;
cbuseargstr.Checked = showarg0str;
arg0named.Visible = showarg0str && isacs;
arg0str.Visible = showarg0str && !isacs;
arg0int.Visible = (!showarg0str && isacs);
arg0.Visible = (!showarg0str && !isacs);
// Update named script name
if(showarg0str)
{
Arg0Mode = ArgZeroMode.STRING;
arg0str.Text = arg0named.Text = arg0strval;
if (isacs && General.Map.NamedScripts.ContainsKey(arg0strval))
UpdateScriptArguments(General.Map.NamedScripts[arg0strval]);
}
// Update numbered script name
else if (isacs)
{
Arg0Mode = ArgZeroMode.INT;
int a0 = arg0.GetResult(0);
if(General.Map.NumberedScripts.ContainsKey(a0))
{
int i = 0;
foreach(ScriptItem item in General.Map.NumberedScripts.Values)
{
if(item.Index == a0)
{
arg0int.SelectedIndex = i;
UpdateScriptArguments(item);
break;
}
i++;
}
}
else
{
// Unknown script number...
arg0int.Text = a0.ToString();
}
}
}
else
{
arg0.Visible = true;
cbuseargstr.Visible = false;
arg0named.Visible = false;
arg0str.Visible = false;
arg0int.Visible = false;
cbuseargstr.Checked = false;
Arg0Mode = ArgZeroMode.DEFAULT;
}
}
private void UpdateArgument(ArgumentBox arg, Label label, ArgumentInfo info)
{
// Update labels
label.Text = info.Title + ":";
label.Enabled = info.Used;
arg.ForeColor = (label.Enabled ? SystemColors.WindowText : SystemColors.GrayText);
arg.Setup(info);
// Update tooltip
UpdateToolTip(label, info);
}
private void UpdateToolTip(Label label, ArgumentInfo info)
{
if(info.Used && !string.IsNullOrEmpty(info.ToolTip))
{
tooltip.SetToolTip(label, info.ToolTip);
label.Font = new Font(label.Font, FontStyle.Underline);
label.ForeColor = SystemColors.HotTrack;
}
else
{
tooltip.SetToolTip(label, null);
label.Font = new Font(label.Font, FontStyle.Regular);
label.ForeColor = SystemColors.WindowText;
}
}
private void UpdateScriptArguments(ScriptItem item)
{
if(item != null)
{
int first;
string[] argnames = item.GetArgumentsDescriptions(action, out first);
for(int i = first; i < labels.Length; i++)
{
if(!string.IsNullOrEmpty(argnames[i]))
{
labels[i].Text = argnames[i] + ":";
labels[i].Enabled = true;
labels[i].Font = new Font(labels[i].Font, FontStyle.Regular);
labels[i].ForeColor = SystemColors.WindowText;
}
else
{
labels[i].Text = arginfo[i].Title + ":";
labels[i].Enabled = arginfo[i].Used;
UpdateToolTip(labels[i], arginfo[i]);
}
args[i].ForeColor = (labels[i].Enabled ? SystemColors.WindowText : SystemColors.GrayText);
}
}
else
{
for(int i = 1; i < labels.Length; i++)
{
labels[i].Text = arginfo[i].Title + ":";
labels[i].Enabled = arginfo[i].Used;
UpdateToolTip(labels[i], arginfo[i]);
args[i].ForeColor = (labels[i].Enabled ? SystemColors.WindowText : SystemColors.GrayText);
}
}
}
//mxd
private static bool ArgumentInfosMatch(ArgumentInfo[] info1, ArgumentInfo[] info2)
{
if(info1.Length != info2.Length) return false;
bool haveusedargs = false; // Arguments should still be reset if all arguments are unused
for(int i = 0; i < info1.Length; i++)
{
if(info1[i].Used != info2[i].Used || info1[i].Type != info2[i].Type
|| info1[i].Title.ToUpperInvariant() != info2[i].Title.ToUpperInvariant())
return false;
haveusedargs |= info1[i].Used;
}
return haveusedargs;
}
#endregion
#region ================== Redraw control
private void BeginUpdate()
{
SendMessage(this.Parent.Handle, WM_SETREDRAW, false, 0);
}
private void EndUpdate()
{
SendMessage(this.Parent.Handle, WM_SETREDRAW, true, 0);
this.Parent.Refresh();
}
#endregion
#region ================== Events
private void cbuseargstr_CheckedChanged(object sender, EventArgs e)
{
if(!cbuseargstr.Visible) return;
bool isacs = (Array.IndexOf(GZGeneral.ACS_SPECIALS, action) != -1);
arg0named.Visible = (cbuseargstr.Checked && isacs);
arg0str.Visible = (cbuseargstr.Checked && !isacs);
arg0int.Visible = (!cbuseargstr.Checked && isacs);
arg0.Visible = (!cbuseargstr.Checked && !isacs);
Arg0Mode = (cbuseargstr.Checked ? ArgZeroMode.STRING : ArgZeroMode.INT);
}
private void arg0int_TextChanged(object sender, EventArgs e)
{
if(string.IsNullOrEmpty(arg0int.Text)) return;
ScriptItem item = null;
if(arg0int.SelectedIndex != -1)
{
item = ((ScriptItem)((ColoredComboBoxItem)arg0int.SelectedItem).Value);
}
else
{
int scriptindex;
if(int.TryParse(arg0int.Text, out scriptindex) && General.Map.NumberedScripts.ContainsKey(scriptindex))
item = General.Map.NumberedScripts[scriptindex];
}
UpdateScriptArguments(item);
}
private void arg0str_TextChanged(object sender, EventArgs e)
{
if(string.IsNullOrEmpty(arg0named.Text)) return;
ScriptItem item = null;
if(arg0named.SelectedIndex != -1)
{
item = ((ScriptItem)((ColoredComboBoxItem)arg0named.SelectedItem).Value);
}
else
{
string scriptname = arg0named.Text.Trim().ToLowerInvariant();
if(General.Map.NamedScripts.ContainsKey(scriptname))
item = General.Map.NamedScripts[scriptname];
}
UpdateScriptArguments(item);
}
#endregion
private void scriptnames_TextChanged(object sender, EventArgs e)
{
}
private void scriptnumbers_TextChanged(object sender, EventArgs e)
{
}
}
}