mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
bfd57379bb
Added, Map Analysis mode: added "Edit Thing..." option to "Unknown Thing" and "Obsolete Thing" error check results. Added: a warning is now displayed when a thing has both voxel and model attached. Changed, Thing/Linedef Info panels: unknown ACS script names/numbers are now shown in red. Fixed, Edit Things window, UDMF: unneeded undo was created when opening the window. Re-fixed: in some cases invalid sectors were created after dragging map elements when using "Merge Dragged Geometry" and "Replace with Dragged Geometry" drag modes, when at least one of dragged linedef was facing into an enclosed void area (previous fix entirely disabled the associated logic).
501 lines
14 KiB
C#
501 lines
14 KiB
C#
#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;
|
|
|
|
#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,
|
|
SCRIPT_NUMBER,
|
|
SCRIPT_NAME,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
private string arg0str;
|
|
private bool havearg0str;
|
|
private int action;
|
|
private ArgumentInfo[] arginfo;
|
|
private ArgZeroMode argzeromode;
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor
|
|
|
|
public ArgumentsControl()
|
|
{
|
|
InitializeComponent();
|
|
|
|
// 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)
|
|
{
|
|
//mxd. Setup script numbers
|
|
scriptnumbers.Location = new Point(arg0.Location.X, arg0.Location.Y + 2);
|
|
foreach(ScriptItem si in General.Map.NumberedScripts.Values)
|
|
scriptnumbers.Items.Add(new ColoredComboBoxItem(si, si.IsInclude ? SystemColors.HotTrack : SystemColors.WindowText));
|
|
scriptnumbers.DropDownWidth = Tools.GetDropDownWidth(scriptnumbers);
|
|
|
|
//mxd. Setup script names
|
|
if(General.Map.UDMF)
|
|
{
|
|
scriptnames.Location = scriptnumbers.Location;
|
|
foreach(ScriptItem nsi in General.Map.NamedScripts.Values)
|
|
scriptnames.Items.Add(new ColoredComboBoxItem(nsi, nsi.IsInclude ? SystemColors.HotTrack : SystemColors.WindowText));
|
|
scriptnames.DropDownWidth = Tools.GetDropDownWidth(scriptnames);
|
|
}
|
|
else
|
|
{
|
|
scriptnames.Visible = false;
|
|
cbuseargstr.Visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Setup
|
|
|
|
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[] args, bool first)
|
|
{
|
|
if(first)
|
|
{
|
|
if(General.Map.UDMF)
|
|
{
|
|
arg0str = fields.GetValue("arg0str", string.Empty);
|
|
havearg0str = !string.IsNullOrEmpty(arg0str);
|
|
}
|
|
|
|
// Update arguments
|
|
arg0.SetValue(args[0]);
|
|
arg1.SetValue(args[1]);
|
|
arg2.SetValue(args[2]);
|
|
arg3.SetValue(args[3]);
|
|
arg4.SetValue(args[4]);
|
|
}
|
|
else
|
|
{
|
|
if(General.Map.UDMF)
|
|
{
|
|
if(arg0str != fields.GetValue("arg0str", string.Empty))
|
|
{
|
|
havearg0str = true;
|
|
arg0str = string.Empty;
|
|
}
|
|
}
|
|
|
|
// Update arguments
|
|
if(!string.IsNullOrEmpty(arg0.Text) && args[0] != arg0.GetResult(int.MinValue)) arg0.ClearValue();
|
|
if(!string.IsNullOrEmpty(arg1.Text) && args[1] != arg1.GetResult(int.MinValue)) arg1.ClearValue();
|
|
if(!string.IsNullOrEmpty(arg2.Text) && args[2] != arg2.GetResult(int.MinValue)) arg2.ClearValue();
|
|
if(!string.IsNullOrEmpty(arg3.Text) && args[3] != arg3.GetResult(int.MinValue)) arg3.ClearValue();
|
|
if(!string.IsNullOrEmpty(arg4.Text) && args[4] != arg4.GetResult(int.MinValue)) arg4.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)
|
|
switch(argzeromode)
|
|
{
|
|
// Apply arg0str
|
|
case ArgZeroMode.SCRIPT_NAME:
|
|
if(!string.IsNullOrEmpty(scriptnames.Text))
|
|
l.Fields["arg0str"] = new UniValue(UniversalType.String, scriptnames.Text);
|
|
break;
|
|
|
|
// Apply script number
|
|
case ArgZeroMode.SCRIPT_NUMBER:
|
|
if(!string.IsNullOrEmpty(scriptnumbers.Text))
|
|
{
|
|
if(scriptnumbers.SelectedItem != null)
|
|
l.Args[0] = ((ScriptItem)((ColoredComboBoxItem)scriptnumbers.SelectedItem).Value).Index;
|
|
else if(!int.TryParse(scriptnumbers.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
|
|
l.Args[1] = arg1.GetResult(l.Args[1], step);
|
|
l.Args[2] = arg2.GetResult(l.Args[2], step);
|
|
l.Args[3] = arg3.GetResult(l.Args[3], step);
|
|
l.Args[4] = arg4.GetResult(l.Args[4], 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)
|
|
switch(argzeromode)
|
|
{
|
|
// Apply arg0str
|
|
case ArgZeroMode.SCRIPT_NAME:
|
|
if(!string.IsNullOrEmpty(scriptnames.Text))
|
|
t.Fields["arg0str"] = new UniValue(UniversalType.String, scriptnames.Text);
|
|
break;
|
|
|
|
// Apply script number
|
|
case ArgZeroMode.SCRIPT_NUMBER:
|
|
if(!string.IsNullOrEmpty(scriptnumbers.Text))
|
|
{
|
|
if(scriptnumbers.SelectedItem != null)
|
|
t.Args[0] = ((ScriptItem)((ColoredComboBoxItem)scriptnumbers.SelectedItem).Value).Index;
|
|
else if(!int.TryParse(scriptnumbers.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
|
|
t.Args[1] = arg1.GetResult(t.Args[1], step);
|
|
t.Args[2] = arg2.GetResult(t.Args[2], step);
|
|
t.Args[3] = arg3.GetResult(t.Args[3], step);
|
|
t.Args[4] = arg4.GetResult(t.Args[4], 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();
|
|
|
|
UpdateArgument(arg0, arg0label, arginfo[0]);
|
|
UpdateArgument(arg1, arg1label, arginfo[1]);
|
|
UpdateArgument(arg2, arg2label, arginfo[2]);
|
|
UpdateArgument(arg3, arg3label, arginfo[3]);
|
|
UpdateArgument(arg4, arg4label, arginfo[4]);
|
|
|
|
if(!setuponly)
|
|
{
|
|
// Apply action's or thing's default arguments
|
|
if(showaction != 0 || info != null)
|
|
{
|
|
arg0.SetDefaultValue();
|
|
arg1.SetDefaultValue();
|
|
arg2.SetDefaultValue();
|
|
arg3.SetDefaultValue();
|
|
arg4.SetDefaultValue();
|
|
}
|
|
else //or set them to 0
|
|
{
|
|
arg0.SetValue(0);
|
|
arg1.SetValue(0);
|
|
arg2.SetValue(0);
|
|
arg3.SetValue(0);
|
|
arg4.SetValue(0);
|
|
}
|
|
}
|
|
|
|
// Store current action
|
|
this.action = showaction;
|
|
|
|
this.EndUpdate();
|
|
}
|
|
|
|
public void UpdateScriptControls()
|
|
{
|
|
// Update script-specific stuff
|
|
if(Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, action) != -1)
|
|
{
|
|
// Update script controls visibility
|
|
bool shownamedscripts = (General.Map.UDMF && havearg0str);
|
|
cbuseargstr.Visible = General.Map.UDMF;
|
|
cbuseargstr.Checked = shownamedscripts;
|
|
scriptnames.Visible = shownamedscripts;
|
|
scriptnumbers.Visible = !shownamedscripts;
|
|
|
|
// Update named script name
|
|
if(shownamedscripts)
|
|
{
|
|
argzeromode = ArgZeroMode.SCRIPT_NAME;
|
|
if(General.Map.NamedScripts.ContainsKey(arg0str))
|
|
{
|
|
scriptnames.SelectedText = arg0str;
|
|
UpdateScriptArguments(General.Map.NamedScripts[arg0str]);
|
|
}
|
|
else
|
|
{
|
|
// Unknown script name
|
|
scriptnames.Text = arg0str;
|
|
arg0label.Text = "Script Name:";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Update numbered script name
|
|
argzeromode = ArgZeroMode.SCRIPT_NUMBER;
|
|
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)
|
|
{
|
|
scriptnumbers.SelectedIndex = i;
|
|
UpdateScriptArguments(item);
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Unknown script number...
|
|
scriptnumbers.Text = a0.ToString();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cbuseargstr.Visible = false;
|
|
scriptnames.Visible = false;
|
|
scriptnumbers.Visible = false;
|
|
cbuseargstr.Checked = false;
|
|
argzeromode = ArgZeroMode.DEFAULT;
|
|
}
|
|
|
|
arg0.Visible = (argzeromode == 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)
|
|
{
|
|
Label[] labels = { arg0label, arg1label, arg2label, arg3label, arg4label };
|
|
ArgumentBox[] args = { arg0, arg1, arg2, arg3, arg4 };
|
|
if(item != null)
|
|
{
|
|
string[] argnames = item.GetArgumentsDescriptions(action);
|
|
for(int i = 0; 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 = 0; 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 != info1[2].Used || info1[i].Type != info1[2].Type
|
|
|| info1[i].Title.ToUpperInvariant() != info2[i].Title.ToUpperInvariant())
|
|
return false;
|
|
|
|
haveusedargs |= (info1[i].Used || info1[2].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;
|
|
scriptnames.Visible = cbuseargstr.Checked;
|
|
scriptnumbers.Visible = !cbuseargstr.Checked;
|
|
arg0label.Text = (cbuseargstr.Checked ? "Script Name:" : "Script Number:");
|
|
argzeromode = (cbuseargstr.Checked ? ArgZeroMode.SCRIPT_NAME : ArgZeroMode.SCRIPT_NUMBER);
|
|
}
|
|
|
|
private void scriptnumbers_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if(string.IsNullOrEmpty(scriptnumbers.Text)) return;
|
|
ScriptItem item = null;
|
|
if(scriptnumbers.SelectedIndex != -1)
|
|
{
|
|
item = ((ScriptItem)((ColoredComboBoxItem)scriptnumbers.SelectedItem).Value);
|
|
}
|
|
else
|
|
{
|
|
int scriptindex;
|
|
if(int.TryParse(scriptnumbers.Text, out scriptindex) && General.Map.NumberedScripts.ContainsKey(scriptindex))
|
|
item = General.Map.NumberedScripts[scriptindex];
|
|
}
|
|
|
|
UpdateScriptArguments(item);
|
|
}
|
|
|
|
private void scriptnames_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if(string.IsNullOrEmpty(scriptnames.Text)) return;
|
|
ScriptItem item = null;
|
|
if(scriptnames.SelectedIndex != -1)
|
|
{
|
|
item = ((ScriptItem)((ColoredComboBoxItem)scriptnames.SelectedItem).Value);
|
|
}
|
|
else
|
|
{
|
|
string scriptname = scriptnames.Text.Trim().ToLowerInvariant();
|
|
if(General.Map.NamedScripts.ContainsKey(scriptname))
|
|
item = General.Map.NamedScripts[scriptname];
|
|
}
|
|
|
|
UpdateScriptArguments(item);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|