UltimateZoneBuilder/Source/Core/Windows/ThingEditForm.cs
MaxED 5cb573d938 GZDoom Builder 1.11:
Enhanced scripting workflow.
Thing and linedef arguments can now have default value in configuration files.
Fixed laggy visual camera movement on systems with big uptime.
Fixed incorrect alignment of Things with "hangs" flag in GZDoom Visual mode.
Fixed Editor crash when nodebuilder fails to build map. A window with error description will be shown instead.
Doom light levels were used even in maps in non-doom map format.

Tag Explorer plugin:
Elements list wasn't updated when map element was deleted.
Pugin wasn't disposed properly, which may led to Doom Builder 2 crash on map close.
Fixed plugin crash after opening another map.
Fixed unresponsive text entry in Filter text box.
Fixed plugin crash when Doom Builder can't determmine thing category ("UNKNOWN" category will be used instead).
2012-07-10 10:20:45 +00:00

508 lines
No EOL
18 KiB
C#

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.IO;
using System.IO;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Controls;
using CodeImp.DoomBuilder.GZBuilder.Data;
#endregion
namespace CodeImp.DoomBuilder.Windows
{
/// <summary>
/// Dialog window that allows viewing and editing of Thing properties.
/// </summary>
public partial class ThingEditForm : DelayedForm
{
#region ================== Variables
private ICollection<Thing> things;
private ThingTypeInfo thinginfo;
private bool preventchanges = false;
//mxd
private Vector2D initialPosition; //initial position of a thing used to fill posX and posY fields
#endregion
#region ================== Properties
#endregion
#region ================== Constructor
// Constructor
public ThingEditForm()
{
// Initialize
InitializeComponent();
// Fill flags list
foreach(KeyValuePair<string, string> tf in General.Map.Config.ThingFlags)
flags.Add(tf.Value, tf.Key);
// Fill actions list
action.GeneralizedCategories = General.Map.Config.GenActionCategories;
action.AddInfo(General.Map.Config.SortedLinedefActions.ToArray());
// Fill universal fields list
fieldslist.ListFixedFields(General.Map.Config.ThingFields);
// Initialize custom fields editor
fieldslist.Setup("thing");
// Custom fields?
if(!General.Map.FormatInterface.HasCustomFields)
tabs.TabPages.Remove(tabcustom);
// Tag/Effects?
if(!General.Map.FormatInterface.HasThingAction && !General.Map.FormatInterface.HasThingTag)
tabs.TabPages.Remove(tabeffects);
// Thing height?
height.Visible = General.Map.FormatInterface.HasThingHeight;
heightlabel.Visible = General.Map.FormatInterface.HasThingHeight;
// Setup types list
thingtype.Setup();
}
// This sets up the form to edit the given things
public void Setup(ICollection<Thing> things)
{
Thing ft;
preventchanges = true;
// Keep this list
this.things = things;
if(things.Count > 1) this.Text = "Edit Things (" + things.Count + ")";
////////////////////////////////////////////////////////////////////////
// Set all options to the first thing properties
////////////////////////////////////////////////////////////////////////
ft = General.GetByIndex(things, 0);
// Set type
thingtype.SelectType(ft.Type);
// Flags
foreach(CheckBox c in flags.Checkboxes)
if(ft.Flags.ContainsKey(c.Tag.ToString())) c.Checked = ft.Flags[c.Tag.ToString()];
// Coordination
angle.Text = ft.AngleDoom.ToString();
height.Text = ((int)ft.Position.z).ToString();
//mxd
initialPosition = ft.Position;
posX.Text = ((int)ft.Position.x).ToString();
posY.Text = ((int)ft.Position.y).ToString();
posX.ButtonStep = General.Map.Grid.GridSize;
posY.ButtonStep = General.Map.Grid.GridSize;
//mxd. setup arg0str
arg0str.Location = arg0.Location;
// Custom fields
fieldslist.SetValues(ft.Fields, true);
// Action/tags
action.Value = ft.Action;
tag.Text = ft.Tag.ToString();
arg0.SetValue(ft.Args[0]);
arg1.SetValue(ft.Args[1]);
arg2.SetValue(ft.Args[2]);
arg3.SetValue(ft.Args[3]);
arg4.SetValue(ft.Args[4]);
////////////////////////////////////////////////////////////////////////
// Now go for all lines and change the options when a setting is different
////////////////////////////////////////////////////////////////////////
// Go for all things
foreach(Thing t in things)
{
// Type does not match?
if((thingtype.GetSelectedInfo() != null) &&
(thingtype.GetSelectedInfo().Index != t.Type))
thingtype.ClearSelectedType();
// Flags
foreach(CheckBox c in flags.Checkboxes)
{
if(t.Flags.ContainsKey(c.Tag.ToString()))
{
if(t.Flags[c.Tag.ToString()] != c.Checked)
{
c.ThreeState = true;
c.CheckState = CheckState.Indeterminate;
}
}
}
// Coordination
if(t.AngleDoom.ToString() != angle.Text) angle.Text = "";
if(((int)t.Position.z).ToString() != height.Text) height.Text = "";
// Action/tags
if(t.Action != action.Value) action.Empty = true;
if(t.Tag.ToString() != tag.Text) tag.Text = "";
if(t.Args[0] != arg0.GetResult(-1)) arg0.ClearValue();
if(t.Args[1] != arg1.GetResult(-1)) arg1.ClearValue();
if(t.Args[2] != arg2.GetResult(-1)) arg2.ClearValue();
if(t.Args[3] != arg3.GetResult(-1)) arg3.ClearValue();
if(t.Args[4] != arg4.GetResult(-1)) arg4.ClearValue();
// Custom fields
fieldslist.SetValues(t.Fields, false);
}
preventchanges = false;
}
//mxd
private void setNumberedScripts(Thing t) {
arg0str.Items.Clear();
if (General.Map.NumberedScripts.Count > 0) {
foreach (ScriptItem si in General.Map.NumberedScripts) {
arg0str.Items.Add(si);
if (si.Index == t.Args[0])
arg0str.SelectedIndex = arg0str.Items.Count - 1;
}
//script number is not among known scripts...
if (arg0str.SelectedIndex == -1 && t.Args[0] > 0) {
arg0str.Items.Add(new ScriptItem(t.Args[0], "Script " + t.Args[0]));
arg0str.SelectedIndex = arg0str.Items.Count - 1;
}
} else if (t.Args[0] > 0) {
arg0str.Items.Add(new ScriptItem(t.Args[0], "Script " + t.Args[0]));
arg0str.SelectedIndex = 0;
}
}
//mxd
private void setNamedScripts(string selectedValue) {
arg0str.Items.Clear();
//update arg0str items
if (General.Map.NamedScripts.Count > 0) {
//dbg
GZBuilder.GZGeneral.Trace("Got " + General.Map.NamedScripts.Count + " script names");
ScriptItem[] sn = new ScriptItem[General.Map.NamedScripts.Count];
General.Map.NamedScripts.CopyTo(sn, 0);
arg0str.Items.AddRange(sn);
for(int i = 0; i < sn.Length; i++){
if (sn[i].Name == selectedValue) {
arg0str.SelectedIndex = i;
break;
}
}
//int index = General.Map.NamedScripts.IndexOf(selectedValue);
//if (index != -1)
//arg0str.SelectedIndex = index;
} else {
arg0str.Text = selectedValue;
}
}
#endregion
#region ================== Interface
// This finds a new (unused) tag
private void newtag_Click(object sender, EventArgs e)
{
tag.Text = General.Map.Map.GetNewTag().ToString();
}
// Selected type changes
private void thingtype_OnTypeChanged(ThingTypeInfo value)
{
thinginfo = value;
// Update preview image
if(thinginfo != null)
{
if(thinginfo.Sprite.ToLowerInvariant().StartsWith(DataManager.INTERNAL_PREFIX) &&
(thinginfo.Sprite.Length > DataManager.INTERNAL_PREFIX.Length))
{
General.DisplayZoomedImage(spritetex, General.Map.Data.GetSpriteImage(thinginfo.Sprite).GetBitmap());
}
else if((thinginfo.Sprite.Length <= 8) && (thinginfo.Sprite.Length > 0))
{
General.DisplayZoomedImage(spritetex, General.Map.Data.GetSpriteImage(thinginfo.Sprite).GetPreview());
}
else
{
spritetex.BackgroundImage = null;
}
}
else
{
spritetex.BackgroundImage = null;
}
// Update arguments
action_ValueChanges(this, EventArgs.Empty);
}
// Action changes
private void action_ValueChanges(object sender, EventArgs e)
{
int showaction = 0;
ArgumentInfo[] arginfo;
// Only when line type is known, otherwise use the thing arguments
if(General.Map.Config.LinedefActions.ContainsKey(action.Value)) showaction = action.Value;
if((showaction == 0) && (thinginfo != null)) arginfo = thinginfo.Args; else arginfo = General.Map.Config.LinedefActions[showaction].Args;
// Change the argument descriptions
arg0label.Text = arginfo[0].Title + ":";
arg1label.Text = arginfo[1].Title + ":";
arg2label.Text = arginfo[2].Title + ":";
arg3label.Text = arginfo[3].Title + ":";
arg4label.Text = arginfo[4].Title + ":";
arg0label.Enabled = arginfo[0].Used;
arg1label.Enabled = arginfo[1].Used;
arg2label.Enabled = arginfo[2].Used;
arg3label.Enabled = arginfo[3].Used;
arg4label.Enabled = arginfo[4].Used;
if(arg0label.Enabled) arg0.ForeColor = SystemColors.WindowText; else arg0.ForeColor = SystemColors.GrayText;
if(arg1label.Enabled) arg1.ForeColor = SystemColors.WindowText; else arg1.ForeColor = SystemColors.GrayText;
if(arg2label.Enabled) arg2.ForeColor = SystemColors.WindowText; else arg2.ForeColor = SystemColors.GrayText;
if(arg3label.Enabled) arg3.ForeColor = SystemColors.WindowText; else arg3.ForeColor = SystemColors.GrayText;
if(arg4label.Enabled) arg4.ForeColor = SystemColors.WindowText; else arg4.ForeColor = SystemColors.GrayText;
arg0.Setup(arginfo[0]);
arg1.Setup(arginfo[1]);
arg2.Setup(arginfo[2]);
arg3.Setup(arginfo[3]);
arg4.Setup(arginfo[4]);
// Zero all arguments when linedef action 0 (normal) is chosen
if(!preventchanges && (showaction == 0))
{
//mxd
arg0.SetDefaultValue();
arg1.SetDefaultValue();
arg2.SetDefaultValue();
arg3.SetDefaultValue();
arg4.SetDefaultValue();
}
//update arg0str
if (Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, showaction) != -1) {
arg0str.Visible = true;
if (General.Map.UDMF && fieldslist.GetValue("arg0str") != null) {
cbArgStr.Visible = true;
cbArgStr.Checked = true;
setNamedScripts((string)fieldslist.GetValue("arg0str"));
} else { //use script numbers
cbArgStr.Visible = General.Map.UDMF;
cbArgStr.Checked = false;
Thing t = General.GetByIndex(things, 0);
setNumberedScripts(t);
}
} else {
cbArgStr.Checked = false;
cbArgStr.Visible = false;
arg0str.Visible = false;
}
}
// Browse Action clicked
private void browseaction_Click(object sender, EventArgs e)
{
action.Value = ActionBrowserForm.BrowseAction(this, action.Value);
}
// Angle text changes
private void angle_TextChanged(object sender, EventArgs e)
{
anglecontrol.Value = angle.GetResult(int.MinValue);
}
// Angle control clicked
private void anglecontrol_ButtonClicked(object sender, EventArgs e)
{
angle.Text = anglecontrol.Value.ToString();
}
// Apply clicked
private void apply_Click(object sender, EventArgs e)
{
List<string> defaultflags = new List<string>();
string undodesc = "thing";
// Verify the tag
if(General.Map.FormatInterface.HasThingTag && ((tag.GetResult(0) < General.Map.FormatInterface.MinTag) || (tag.GetResult(0) > General.Map.FormatInterface.MaxTag)))
{
General.ShowWarningMessage("Thing tag must be between " + General.Map.FormatInterface.MinTag + " and " + General.Map.FormatInterface.MaxTag + ".", MessageBoxButtons.OK);
return;
}
// Verify the type
if(((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType)))
{
General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK);
return;
}
// Verify the action
if(General.Map.FormatInterface.HasThingAction && ((action.Value < General.Map.FormatInterface.MinAction) || (action.Value > General.Map.FormatInterface.MaxAction)))
{
General.ShowWarningMessage("Thing action must be between " + General.Map.FormatInterface.MinAction + " and " + General.Map.FormatInterface.MaxAction + ".", MessageBoxButtons.OK);
return;
}
// Make undo
if(things.Count > 1) undodesc = things.Count + " things";
General.Map.UndoRedo.CreateUndo("Edit " + undodesc);
//mxd
Vector2D delta = new Vector2D((float)posX.GetResult((int)initialPosition.x) - initialPosition.x, (float)posY.GetResult((int)initialPosition.y) - initialPosition.y);
bool hasAcs = Array.IndexOf(GZBuilder.GZGeneral.ACS_SPECIALS, action.Value) != -1;
bool hasArg0str = General.Map.UDMF && !action.Empty && hasAcs && arg0str.Text.Length > 0;
// Go for all the things
foreach(Thing t in things)
{
// Thing type index
t.Type = General.Clamp(thingtype.GetResult(t.Type), General.Map.FormatInterface.MinThingType, General.Map.FormatInterface.MaxThingType);
// Coordination
t.Rotate(angle.GetResult(t.AngleDoom));
//mxd
//t.Move(t.Position.x, t.Position.y, (float)height.GetResult((int)t.Position.z));
t.Move(t.Position.x + delta.x, t.Position.y + delta.y, (float)height.GetResult((int)t.Position.z));
// Apply all flags
foreach(CheckBox c in flags.Checkboxes)
{
if(c.CheckState == CheckState.Checked) t.SetFlag(c.Tag.ToString(), true);
else if(c.CheckState == CheckState.Unchecked) t.SetFlag(c.Tag.ToString(), false);
}
// Action/tags
t.Tag = tag.GetResult(t.Tag);
if(!action.Empty) t.Action = action.Value;
//mxd
if (hasAcs && !cbArgStr.Checked) {
if(arg0str.SelectedItem != null)
t.Args[0] = ((ScriptItem)arg0str.SelectedItem).Index;
else if(!int.TryParse(arg0str.Text.Trim(), out t.Args[0]))
t.Args[0] = 0;
} else {
t.Args[0] = arg0.GetResult(t.Args[0]);
}
t.Args[1] = arg1.GetResult(t.Args[1]);
t.Args[2] = arg2.GetResult(t.Args[2]);
t.Args[3] = arg3.GetResult(t.Args[3]);
t.Args[4] = arg4.GetResult(t.Args[4]);
// Custom fields
fieldslist.Apply(t.Fields);
//mxd. apply arg0str
if (hasArg0str && cbArgStr.Checked) {
if (t.Fields.ContainsKey("arg0str"))
t.Fields["arg0str"].Value = arg0str.Text;
else
t.Fields.Add("arg0str", new UniValue(2, arg0str.Text));
} else if (t.Fields.ContainsKey("arg0str")) {
t.Fields.Remove("arg0str");
}
// Update settings
t.UpdateConfiguration();
}
// Set as defaults
foreach(CheckBox c in flags.Checkboxes)
if(c.CheckState == CheckState.Checked) defaultflags.Add(c.Tag.ToString());
General.Settings.DefaultThingType = thingtype.GetResult(General.Settings.DefaultThingType);
General.Settings.DefaultThingAngle = Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90);
General.Settings.SetDefaultThingFlags(defaultflags);
// Done
General.Map.IsChanged = true;
this.DialogResult = DialogResult.OK;
this.Close();
}
// Cancel clicked
private void cancel_Click(object sender, EventArgs e)
{
// Be gone
this.DialogResult = DialogResult.Cancel;
this.Close();
}
//mxd
private void cbArgStr_CheckedChanged(object sender, EventArgs e) {
arg0str.Text = "";
if (cbArgStr.Checked){
setNamedScripts((string)fieldslist.GetValue("arg0str"));
} else if (!cbArgStr.Checked) {
setNumberedScripts(General.GetByIndex(things, 0));
}
arg0label.Text = cbArgStr.Checked ? "Script name:" : "Script number:";
}
//mxd
private void arg0str_Leave(object sender, EventArgs e) {
if(cbArgStr.Checked) fieldslist.SetValue("arg0str", arg0str.Text, CodeImp.DoomBuilder.Types.UniversalType.String);
}
//mxd
private void fieldslist_OnFieldValueChanged(string fieldname) {
if (cbArgStr.Checked && fieldname == "arg0str")
arg0str.Text = (string)fieldslist.GetValue(fieldname);
}
// Help
private void ThingEditForm_HelpRequested(object sender, HelpEventArgs hlpevent)
{
General.ShowHelp("w_thingeditor.html");
hlpevent.Handled = true;
}
#endregion
}
}