diff --git a/Build/Plugins/PropertiesDock.dll b/Build/Plugins/PropertiesDock.dll index b5cf4a46..c21b458a 100644 Binary files a/Build/Plugins/PropertiesDock.dll and b/Build/Plugins/PropertiesDock.dll differ diff --git a/Build/Plugins/PropertiesDock.pdb b/Build/Plugins/PropertiesDock.pdb deleted file mode 100644 index e8cbabed..00000000 Binary files a/Build/Plugins/PropertiesDock.pdb and /dev/null differ diff --git a/Source/Plugins/PropertiesDock/BuilderPlug.cs b/Source/Plugins/PropertiesDock/BuilderPlug.cs index e2bc19de..7790085a 100644 --- a/Source/Plugins/PropertiesDock/BuilderPlug.cs +++ b/Source/Plugins/PropertiesDock/BuilderPlug.cs @@ -38,7 +38,9 @@ namespace CodeImp.DoomBuilder.PropertiesDock // This is called after a map has been successfully opened public override void OnMapOpenEnd() { - if(propertiesDocker == null) { + MapElementsData.Init(); + + if(propertiesDocker == null) { propertiesDocker = new PropertiesDocker(); docker = new Docker("propertiesdockerpanel", "Properties", propertiesDocker); General.Interface.AddDocker(docker); diff --git a/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.Designer.cs b/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.Designer.cs index a5c37c0c..864477dc 100644 --- a/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.Designer.cs +++ b/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.Designer.cs @@ -29,14 +29,18 @@ this.tabPage1 = new System.Windows.Forms.TabPage(); this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); this.tabPage2 = new System.Windows.Forms.TabPage(); - this.textBox1 = new System.Windows.Forms.TextBox(); this.propertyGrid2 = new System.Windows.Forms.PropertyGrid(); this.tabPage3 = new System.Windows.Forms.TabPage(); this.propertyGrid3 = new System.Windows.Forms.PropertyGrid(); + this.gbCustomFields = new System.Windows.Forms.GroupBox(); + this.cbFieldType = new System.Windows.Forms.ComboBox(); + this.bAddField = new System.Windows.Forms.Button(); + this.tbFieldName = new System.Windows.Forms.TextBox(); this.tabControl.SuspendLayout(); this.tabPage1.SuspendLayout(); this.tabPage2.SuspendLayout(); this.tabPage3.SuspendLayout(); + this.gbCustomFields.SuspendLayout(); this.SuspendLayout(); // // tabControl @@ -48,10 +52,10 @@ this.tabControl.Controls.Add(this.tabPage2); this.tabControl.Controls.Add(this.tabPage3); this.tabControl.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.tabControl.Location = new System.Drawing.Point(3, 3); + this.tabControl.Location = new System.Drawing.Point(3, 56); this.tabControl.Name = "tabControl"; this.tabControl.SelectedIndex = 0; - this.tabControl.Size = new System.Drawing.Size(266, 288); + this.tabControl.Size = new System.Drawing.Size(266, 341); this.tabControl.TabIndex = 0; // // tabPage1 @@ -60,7 +64,7 @@ this.tabPage1.Location = new System.Drawing.Point(4, 23); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(258, 261); + this.tabPage1.Size = new System.Drawing.Size(258, 314); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "tabPage1"; this.tabPage1.UseVisualStyleBackColor = true; @@ -73,7 +77,7 @@ this.propertyGrid1.HelpVisible = false; this.propertyGrid1.Location = new System.Drawing.Point(6, 6); this.propertyGrid1.Name = "propertyGrid1"; - this.propertyGrid1.Size = new System.Drawing.Size(246, 249); + this.propertyGrid1.Size = new System.Drawing.Size(246, 302); this.propertyGrid1.TabIndex = 0; this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid1_PropertyValueChanged); // @@ -83,21 +87,11 @@ this.tabPage2.Location = new System.Drawing.Point(4, 23); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(258, 261); + this.tabPage2.Size = new System.Drawing.Size(258, 308); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "tabPage2"; this.tabPage2.UseVisualStyleBackColor = true; // - // textBox1 - // - this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBox1.Location = new System.Drawing.Point(3, 293); - this.textBox1.Multiline = true; - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(266, 104); - this.textBox1.TabIndex = 1; - // // propertyGrid2 // this.propertyGrid2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -106,7 +100,7 @@ this.propertyGrid2.HelpVisible = false; this.propertyGrid2.Location = new System.Drawing.Point(6, 6); this.propertyGrid2.Name = "propertyGrid2"; - this.propertyGrid2.Size = new System.Drawing.Size(246, 249); + this.propertyGrid2.Size = new System.Drawing.Size(246, 296); this.propertyGrid2.TabIndex = 1; this.propertyGrid2.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid2_PropertyValueChanged); // @@ -115,7 +109,7 @@ this.tabPage3.Controls.Add(this.propertyGrid3); this.tabPage3.Location = new System.Drawing.Point(4, 23); this.tabPage3.Name = "tabPage3"; - this.tabPage3.Size = new System.Drawing.Size(258, 261); + this.tabPage3.Size = new System.Drawing.Size(258, 308); this.tabPage3.TabIndex = 2; this.tabPage3.Text = "tabPage3"; this.tabPage3.UseVisualStyleBackColor = true; @@ -128,15 +122,61 @@ this.propertyGrid3.HelpVisible = false; this.propertyGrid3.Location = new System.Drawing.Point(6, 6); this.propertyGrid3.Name = "propertyGrid3"; - this.propertyGrid3.Size = new System.Drawing.Size(246, 249); + this.propertyGrid3.Size = new System.Drawing.Size(246, 296); this.propertyGrid3.TabIndex = 1; this.propertyGrid3.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid3_PropertyValueChanged); // + // gbCustomFields + // + this.gbCustomFields.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gbCustomFields.Controls.Add(this.tbFieldName); + this.gbCustomFields.Controls.Add(this.bAddField); + this.gbCustomFields.Controls.Add(this.cbFieldType); + this.gbCustomFields.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + this.gbCustomFields.Location = new System.Drawing.Point(3, 3); + this.gbCustomFields.Name = "gbCustomFields"; + this.gbCustomFields.Size = new System.Drawing.Size(266, 47); + this.gbCustomFields.TabIndex = 1; + this.gbCustomFields.TabStop = false; + this.gbCustomFields.Text = "Add custom field:"; + // + // cbFieldType + // + this.cbFieldType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cbFieldType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbFieldType.FormattingEnabled = true; + this.cbFieldType.Location = new System.Drawing.Point(148, 19); + this.cbFieldType.Name = "cbFieldType"; + this.cbFieldType.Size = new System.Drawing.Size(80, 22); + this.cbFieldType.TabIndex = 0; + // + // bAddField + // + this.bAddField.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.bAddField.Image = global::CodeImp.DoomBuilder.PropertiesDock.Properties.Resources.Add; + this.bAddField.Location = new System.Drawing.Point(232, 19); + this.bAddField.Name = "bAddField"; + this.bAddField.Size = new System.Drawing.Size(28, 23); + this.bAddField.TabIndex = 1; + this.bAddField.UseVisualStyleBackColor = true; + this.bAddField.Click += new System.EventHandler(this.bAddField_Click); + // + // tbFieldName + // + this.tbFieldName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tbFieldName.Location = new System.Drawing.Point(10, 20); + this.tbFieldName.Name = "tbFieldName"; + this.tbFieldName.Size = new System.Drawing.Size(134, 20); + this.tbFieldName.TabIndex = 3; + // // PropertiesDocker // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.Controls.Add(this.textBox1); + this.Controls.Add(this.gbCustomFields); this.Controls.Add(this.tabControl); this.Font = new System.Drawing.Font("Arial Narrow", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); this.Name = "PropertiesDocker"; @@ -145,8 +185,9 @@ this.tabPage1.ResumeLayout(false); this.tabPage2.ResumeLayout(false); this.tabPage3.ResumeLayout(false); + this.gbCustomFields.ResumeLayout(false); + this.gbCustomFields.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } @@ -155,10 +196,13 @@ private System.Windows.Forms.TabControl tabControl; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; - private System.Windows.Forms.PropertyGrid propertyGrid1; - private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.PropertyGrid propertyGrid1; private System.Windows.Forms.PropertyGrid propertyGrid2; private System.Windows.Forms.TabPage tabPage3; private System.Windows.Forms.PropertyGrid propertyGrid3; + private System.Windows.Forms.GroupBox gbCustomFields; + private System.Windows.Forms.Button bAddField; + private System.Windows.Forms.ComboBox cbFieldType; + private System.Windows.Forms.TextBox tbFieldName; } } diff --git a/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.cs b/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.cs index 7bac3006..3b7486db 100644 --- a/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.cs +++ b/Source/Plugins/PropertiesDock/Controls/PropertiesDocker.cs @@ -16,12 +16,24 @@ namespace CodeImp.DoomBuilder.PropertiesDock private TabPage page3; private string currentMode; + private static PropertiesDocker me; public PropertiesDocker() { InitializeComponent(); + me = this; page2 = tabControl.TabPages[1]; page3 = tabControl.TabPages[2]; + + if (!General.Map.UDMF) { + gbCustomFields.Visible = false; + tabControl.Top = 3; + } else { + //todo: add "Delete field" button + + //todo: sort this out... + //cbFieldType.Items.AddRange(General.Types.GetCustomUseAttributes()); + } } //SHOW HIGHLIGHT INFO @@ -34,12 +46,13 @@ namespace CodeImp.DoomBuilder.PropertiesDock } public void ShowThingInfo(Thing t) { - + propertyGrid1.SelectedObject = new ThingInfo(t); + viewThings(1, t.Index, true); } public void ShowVertexInfo(Vertex v) { propertyGrid1.SelectedObject = new VertexInfo(v); - viewVertices(true); + viewVertices(1, v.Index, true); } public void OnHighlightLost() { @@ -47,9 +60,28 @@ namespace CodeImp.DoomBuilder.PropertiesDock } //SHOW SELECTION INFO + private void showSelectedThingsInfo() { + //anything selected? + List things = (List)General.Map.Map.GetSelectedThings(true); + + if (things.Count > 0) { + ThingInfo[] infos = new ThingInfo[things.Count]; + int i = 0; + + foreach (Thing t in things) { + infos[i++] = new ThingInfo(t); + } + + propertyGrid1.SelectedObjects = infos; + viewThings(things.Count, things.Count == 1 ? things[0].Index : -1, true); + } else { + viewThings(-1, -1, false); + } + } + private void showSelectedVerticesInfo() { //anything selected? - ICollection verts = General.Map.Map.GetSelectedVertices(true); + List verts = (List)General.Map.Map.GetSelectedVertices(true); if (verts.Count > 0) { VertexInfo[] infos = new VertexInfo[verts.Count]; @@ -60,30 +92,52 @@ namespace CodeImp.DoomBuilder.PropertiesDock } propertyGrid1.SelectedObjects = infos; - viewVertices(true); + viewVertices(verts.Count, verts.Count == 1 ? verts[0].Index : -1, true); } else { - //propertyGrid1.SelectedObjects = null; - viewVertices(false); + viewVertices(-1, -1, false); } } //PANELS UPDATE - private void viewVertices(bool enabled) { - propertyGrid1.Enabled = enabled; - tabControl.TabPages[0].Text = "Vertex:"; + private void viewVertices(int count, int index, bool enabled) { + updateTabs(enabled, false); - if (tabControl.TabPages.Count > 1) { - tabControl.TabPages.Remove(page2); - tabControl.TabPages.Remove(page3); + if(count != -1) + tabControl.TabPages[0].Text = count > 1 ? count + " vertices:" : "Vertex "+index+":"; + } + + private void viewThings(int count, int index, bool enabled) { + updateTabs(enabled, false); + + if (count != -1) + tabControl.TabPages[0].Text = count > 1 ? count + " things:" : "Thing " + index + ":"; + } + + private void updateTabs(bool enabled, bool showAllTabs) { + if (showAllTabs) { + if (tabControl.TabPages.Count == 1) { + tabControl.TabPages.Add(page2); + tabControl.TabPages.Add(page3); + } + propertyGrid2.Enabled = enabled; + propertyGrid3.Enabled = enabled; + + } else { + if (tabControl.TabPages.Count == 3) { + tabControl.TabPages.Remove(page2); + tabControl.TabPages.Remove(page3); + } } + propertyGrid1.Enabled = enabled; } //util public void ChangeEditMode(string name) { - textBox1.AppendText("Mode Changed to " + name + Environment.NewLine); + //textBox1.AppendText("Mode Changed to " + name + Environment.NewLine); if (name == "ThingsMode") { currentMode = name; + showSelectedThingsInfo(); } else if (name == "SectorsMode") { currentMode = name; @@ -105,6 +159,12 @@ namespace CodeImp.DoomBuilder.PropertiesDock ChangeEditMode(currentMode); } + public static void Refresh() { + me.propertyGrid1.Refresh(); + me.propertyGrid2.Refresh(); + me.propertyGrid3.Refresh(); + } + private void saveChanges() { if (currentMode == "ThingsMode" && propertyGrid1.Enabled) { applyThingChanges(); @@ -120,7 +180,7 @@ namespace CodeImp.DoomBuilder.PropertiesDock } private void applyThingChanges() { - throw new NotImplementedException(); + //throw new NotImplementedException(); } private void applySectorChanges() { @@ -168,5 +228,26 @@ namespace CodeImp.DoomBuilder.PropertiesDock private void propertyGrid3_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) { saveChanges(); } + + private void bAddField_Click(object sender, EventArgs e) { + PropertyGrid g = null; + + if (tbFieldName.Text.Length > 0) { + if (tabControl.SelectedIndex == 0) { + g = propertyGrid1; + } else if (tabControl.SelectedIndex == 1) { + g = propertyGrid2; + } else if (tabControl.SelectedIndex == 2) { + g = propertyGrid3; + } + } + + if (g != null && g.Enabled && g.SelectedObjects.Length > 0) { + foreach (object o in g.SelectedObjects) { + //todo: set correct type + ((IMapElementInfo)o).AddCustomProperty(tbFieldName.Text, typeof(string)); + } + } + } } } diff --git a/Source/Plugins/PropertiesDock/Data/MapElementsData.cs b/Source/Plugins/PropertiesDock/Data/MapElementsData.cs new file mode 100644 index 00000000..08ae5468 --- /dev/null +++ b/Source/Plugins/PropertiesDock/Data/MapElementsData.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using CodeImp.DoomBuilder.Config; + +namespace CodeImp.DoomBuilder.PropertiesDock { + public static class MapElementsData { + + public static Dictionary ThingTypeDescriptions { get { return thingTypeDescriptions;}} + private static Dictionary thingTypeDescriptions; + + public static void Init() { + //thing types + thingTypeDescriptions = new Dictionary(); + + foreach (ThingCategory tc in General.Map.Data.ThingCategories) { + foreach (ThingTypeInfo ti in tc.Things) { + thingTypeDescriptions.Add(ti.Index, ti.Title); + } + } + } + } +} diff --git a/Source/Plugins/PropertiesDock/Data/PropertyBag.cs b/Source/Plugins/PropertiesDock/Data/PropertyBag.cs new file mode 100644 index 00000000..0bf7ce03 --- /dev/null +++ b/Source/Plugins/PropertiesDock/Data/PropertyBag.cs @@ -0,0 +1,979 @@ +/******************************************************************** + * + * PropertyBag.cs + * -------------- + * Copyright (C) 2002 Tony Allowatt + * Last Update: 12/14/2002 + * + * THE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT WARRANTY + * OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF THIS + * SOFTWARE. + * + * Public types defined in this file: + * ---------------------------------- + * namespace Flobbster.Windows.Forms + * class PropertySpec + * class PropertySpecEventArgs + * delegate PropertySpecEventHandler + * class PropertyBag + * class PropertyBag.PropertySpecCollection + * class PropertyTable + * + ********************************************************************/ + +using System; +using System.Collections; +using System.ComponentModel; +using System.Drawing.Design; + +namespace CodeImp.DoomBuilder.PropertiesDock { + /// + /// Represents a single property in a PropertySpec. + /// + public class PropertySpec { + private Attribute[] attributes; + private string category; + private object defaultValue; + private string description; + private string editor; + private string name; + private string type; + private string typeConverter; + private object currentValue; //mxd + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + public PropertySpec(string name, string type) : this(name, type, null, null, null) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + public PropertySpec(string name, Type type) : + this(name, type.AssemblyQualifiedName, null, null, null) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + public PropertySpec(string name, string type, string category) : this(name, type, category, null, null) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// + public PropertySpec(string name, Type type, string category) : + this(name, type.AssemblyQualifiedName, category, null, null) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + public PropertySpec(string name, string type, string category, string description) : + this(name, type, category, description, null) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + public PropertySpec(string name, Type type, string category, string description) : + this(name, type.AssemblyQualifiedName, category, description, null) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + public PropertySpec(string name, string type, string category, string description, object defaultValue) { + this.name = name; + this.type = type; + this.category = category; + this.description = description; + this.defaultValue = defaultValue; + this.attributes = null; + this.currentValue = defaultValue; //mxd + } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + public PropertySpec(string name, Type type, string category, string description, object defaultValue) : + this(name, type.AssemblyQualifiedName, category, description, defaultValue) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The fully qualified name of the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The fully qualified name of the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, string type, string category, string description, object defaultValue, + string editor, string typeConverter) + : this(name, type, category, description, defaultValue) { + this.editor = editor; + this.typeConverter = typeConverter; + } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The fully qualified name of the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The fully qualified name of the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, Type type, string category, string description, object defaultValue, + string editor, string typeConverter) : + this(name, type.AssemblyQualifiedName, category, description, defaultValue, editor, typeConverter) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The Type that represents the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The fully qualified name of the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, string type, string category, string description, object defaultValue, + Type editor, string typeConverter) : + this(name, type, category, description, defaultValue, editor.AssemblyQualifiedName, + typeConverter) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The Type that represents the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The fully qualified name of the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, Type type, string category, string description, object defaultValue, + Type editor, string typeConverter) : + this(name, type.AssemblyQualifiedName, category, description, defaultValue, + editor.AssemblyQualifiedName, typeConverter) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The fully qualified name of the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The Type that represents the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, string type, string category, string description, object defaultValue, + string editor, Type typeConverter) : + this(name, type, category, description, defaultValue, editor, typeConverter.AssemblyQualifiedName) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The fully qualified name of the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The Type that represents the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, Type type, string category, string description, object defaultValue, + string editor, Type typeConverter) : + this(name, type.AssemblyQualifiedName, category, description, defaultValue, editor, + typeConverter.AssemblyQualifiedName) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// The fully qualified name of the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The Type that represents the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The Type that represents the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, string type, string category, string description, object defaultValue, + Type editor, Type typeConverter) : + this(name, type, category, description, defaultValue, editor.AssemblyQualifiedName, + typeConverter.AssemblyQualifiedName) { } + + /// + /// Initializes a new instance of the PropertySpec class. + /// + /// The name of the property displayed in the property grid. + /// A Type that represents the type of the property. + /// The category under which the property is displayed in the + /// property grid. + /// A string that is displayed in the help area of the + /// property grid. + /// The default value of the property, or null if there is + /// no default value. + /// The Type that represents the type of the editor for this + /// property. This type must derive from UITypeEditor. + /// The Type that represents the type of the type + /// converter for this property. This type must derive from TypeConverter. + public PropertySpec(string name, Type type, string category, string description, object defaultValue, + Type editor, Type typeConverter) : + this(name, type.AssemblyQualifiedName, category, description, defaultValue, + editor.AssemblyQualifiedName, typeConverter.AssemblyQualifiedName) { } + + /// + /// Gets or sets a collection of additional Attributes for this property. This can + /// be used to specify attributes beyond those supported intrinsically by the + /// PropertySpec class, such as ReadOnly and Browsable. + /// + public Attribute[] Attributes { + get { return attributes; } + set { attributes = value; } + } + + /// + /// Gets or sets the category name of this property. + /// + public string Category { + get { return category; } + set { category = value; } + } + + /// + /// Gets or sets the fully qualified name of the type converter + /// type for this property. + /// + public string ConverterTypeName { + get { return typeConverter; } + set { typeConverter = value; } + } + + /// + /// Gets or sets the default value of this property. + /// + public object DefaultValue { + get { return defaultValue; } + set { defaultValue = value; } + } + + //mxd + /// + /// Gets or sets the value of this property. + /// + public object Value { + get { return currentValue; } + set { currentValue = value; } + } + + /// + /// Gets or sets the help text description of this property. + /// + public string Description { + get { return description; } + set { description = value; } + } + + /// + /// Gets or sets the fully qualified name of the editor type for + /// this property. + /// + public string EditorTypeName { + get { return editor; } + set { editor = value; } + } + + /// + /// Gets or sets the name of this property. + /// + public string Name { + get { return name; } + set { name = value; } + } + + /// + /// Gets or sets the fully qualfied name of the type of this + /// property. + /// + public string TypeName { + get { return type; } + set { type = value; } + } + } + + /// + /// Provides data for the GetValue and SetValue events of the PropertyBag class. + /// + public class PropertySpecEventArgs : EventArgs { + private PropertySpec property; + private object val; + + /// + /// Initializes a new instance of the PropertySpecEventArgs class. + /// + /// The PropertySpec that represents the property whose + /// value is being requested or set. + /// The current value of the property. + public PropertySpecEventArgs(PropertySpec property, object val) { + this.property = property; + this.val = val; + } + + /// + /// Gets the PropertySpec that represents the property whose value is being + /// requested or set. + /// + public PropertySpec Property { + get { return property; } + } + + /// + /// Gets or sets the current value of the property. + /// + public object Value { + get { return val; } + set { val = value; } + } + } + + /// + /// Represents the method that will handle the GetValue and SetValue events of the + /// PropertyBag class. + /// + public delegate void PropertySpecEventHandler(object sender, PropertySpecEventArgs e); + + /// + /// Represents a collection of custom properties that can be selected into a + /// PropertyGrid to provide functionality beyond that of the simple reflection + /// normally used to query an object's properties. + /// + public class PropertyBag : ICustomTypeDescriptor { + #region PropertySpecCollection class definition + /// + /// Encapsulates a collection of PropertySpec objects. + /// + [Serializable] + public class PropertySpecCollection : IList { + private ArrayList innerArray; + + /// + /// Initializes a new instance of the PropertySpecCollection class. + /// + public PropertySpecCollection() { + innerArray = new ArrayList(); + } + + /// + /// Gets the number of elements in the PropertySpecCollection. + /// + /// + /// The number of elements contained in the PropertySpecCollection. + /// + public int Count { + get { return innerArray.Count; } + } + + /// + /// Gets a value indicating whether the PropertySpecCollection has a fixed size. + /// + /// + /// true if the PropertySpecCollection has a fixed size; otherwise, false. + /// + public bool IsFixedSize { + get { return false; } + } + + /// + /// Gets a value indicating whether the PropertySpecCollection is read-only. + /// + public bool IsReadOnly { + get { return false; } + } + + /// + /// Gets a value indicating whether access to the collection is synchronized (thread-safe). + /// + /// + /// true if access to the PropertySpecCollection is synchronized (thread-safe); otherwise, false. + /// + public bool IsSynchronized { + get { return false; } + } + + /// + /// Gets an object that can be used to synchronize access to the collection. + /// + /// + /// An object that can be used to synchronize access to the collection. + /// + object ICollection.SyncRoot { + get { return null; } + } + + /// + /// Gets or sets the element at the specified index. + /// In C#, this property is the indexer for the PropertySpecCollection class. + /// + /// The zero-based index of the element to get or set. + /// + /// The element at the specified index. + /// + public PropertySpec this[int index] { + get { return (PropertySpec)innerArray[index]; } + set { innerArray[index] = value; } + } + + /// + /// Adds a PropertySpec to the end of the PropertySpecCollection. + /// + /// The PropertySpec to be added to the end of the PropertySpecCollection. + /// The PropertySpecCollection index at which the value has been added. + public int Add(PropertySpec value) { + int index = innerArray.Add(value); + + return index; + } + + /// + /// Adds the elements of an array of PropertySpec objects to the end of the PropertySpecCollection. + /// + /// The PropertySpec array whose elements should be added to the end of the + /// PropertySpecCollection. + public void AddRange(PropertySpec[] array) { + innerArray.AddRange(array); + } + + /// + /// Removes all elements from the PropertySpecCollection. + /// + public void Clear() { + innerArray.Clear(); + } + + /// + /// Determines whether a PropertySpec is in the PropertySpecCollection. + /// + /// The PropertySpec to locate in the PropertySpecCollection. The element to locate + /// can be a null reference (Nothing in Visual Basic). + /// true if item is found in the PropertySpecCollection; otherwise, false. + public bool Contains(PropertySpec item) { + return innerArray.Contains(item); + } + + /// + /// Determines whether a PropertySpec with the specified name is in the PropertySpecCollection. + /// + /// The name of the PropertySpec to locate in the PropertySpecCollection. + /// true if item is found in the PropertySpecCollection; otherwise, false. + public bool Contains(string name) { + foreach (PropertySpec spec in innerArray) + if (spec.Name == name) + return true; + + return false; + } + + /// + /// Copies the entire PropertySpecCollection to a compatible one-dimensional Array, starting at the + /// beginning of the target array. + /// + /// The one-dimensional Array that is the destination of the elements copied + /// from PropertySpecCollection. The Array must have zero-based indexing. + public void CopyTo(PropertySpec[] array) { + innerArray.CopyTo(array); + } + + /// + /// Copies the PropertySpecCollection or a portion of it to a one-dimensional array. + /// + /// The one-dimensional Array that is the destination of the elements copied + /// from the collection. + /// The zero-based index in array at which copying begins. + public void CopyTo(PropertySpec[] array, int index) { + innerArray.CopyTo(array, index); + } + + /// + /// Returns an enumerator that can iterate through the PropertySpecCollection. + /// + /// An IEnumerator for the entire PropertySpecCollection. + public IEnumerator GetEnumerator() { + return innerArray.GetEnumerator(); + } + + /// + /// Searches for the specified PropertySpec and returns the zero-based index of the first + /// occurrence within the entire PropertySpecCollection. + /// + /// The PropertySpec to locate in the PropertySpecCollection. + /// The zero-based index of the first occurrence of value within the entire PropertySpecCollection, + /// if found; otherwise, -1. + public int IndexOf(PropertySpec value) { + return innerArray.IndexOf(value); + } + + /// + /// Searches for the PropertySpec with the specified name and returns the zero-based index of + /// the first occurrence within the entire PropertySpecCollection. + /// + /// The name of the PropertySpec to locate in the PropertySpecCollection. + /// The zero-based index of the first occurrence of value within the entire PropertySpecCollection, + /// if found; otherwise, -1. + public int IndexOf(string name) { + int i = 0; + + foreach (PropertySpec spec in innerArray) { + if (spec.Name == name) + return i; + + i++; + } + + return -1; + } + + /// + /// Inserts a PropertySpec object into the PropertySpecCollection at the specified index. + /// + /// The zero-based index at which value should be inserted. + /// The PropertySpec to insert. + public void Insert(int index, PropertySpec value) { + innerArray.Insert(index, value); + } + + /// + /// Removes the first occurrence of a specific object from the PropertySpecCollection. + /// + /// The PropertySpec to remove from the PropertySpecCollection. + public void Remove(PropertySpec obj) { + innerArray.Remove(obj); + } + + /// + /// Removes the property with the specified name from the PropertySpecCollection. + /// + /// The name of the PropertySpec to remove from the PropertySpecCollection. + public void Remove(string name) { + int index = IndexOf(name); + RemoveAt(index); + } + + /// + /// Removes the object at the specified index of the PropertySpecCollection. + /// + /// The zero-based index of the element to remove. + public void RemoveAt(int index) { + innerArray.RemoveAt(index); + } + + /// + /// Copies the elements of the PropertySpecCollection to a new PropertySpec array. + /// + /// A PropertySpec array containing copies of the elements of the PropertySpecCollection. + public PropertySpec[] ToArray() { + return (PropertySpec[])innerArray.ToArray(typeof(PropertySpec)); + } + + #region Explicit interface implementations for ICollection and IList + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + void ICollection.CopyTo(Array array, int index) { + CopyTo((PropertySpec[])array, index); + } + + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + int IList.Add(object value) { + return Add((PropertySpec)value); + } + + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + bool IList.Contains(object obj) { + return Contains((PropertySpec)obj); + } + + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + object IList.this[int index] { + get { + return ((PropertySpecCollection)this)[index]; + } + set { + ((PropertySpecCollection)this)[index] = (PropertySpec)value; + } + } + + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + int IList.IndexOf(object obj) { + return IndexOf((PropertySpec)obj); + } + + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + void IList.Insert(int index, object value) { + Insert(index, (PropertySpec)value); + } + + /// + /// This member supports the .NET Framework infrastructure and is not intended to be used directly from your code. + /// + void IList.Remove(object value) { + Remove((PropertySpec)value); + } + #endregion + } + #endregion + #region PropertySpecDescriptor class definition + private class PropertySpecDescriptor : PropertyDescriptor { + private PropertyBag bag; + private PropertySpec item; + + public PropertySpecDescriptor(PropertySpec item, PropertyBag bag, string name, Attribute[] attrs) : + base(name, attrs) { + this.bag = bag; + this.item = item; + } + + public override Type ComponentType { + get { return item.GetType(); } + } + + public override bool IsReadOnly { + get { return (Attributes.Matches(ReadOnlyAttribute.Yes)); } + } + + public override Type PropertyType { + get { return Type.GetType(item.TypeName); } + } + + public override bool CanResetValue(object component) { + if (item.DefaultValue == null) + return false; + else + return !this.GetValue(component).Equals(item.DefaultValue); + } + + public override object GetValue(object component) { + // Have the property bag raise an event to get the current value + // of the property. + + PropertySpecEventArgs e = new PropertySpecEventArgs(item, null); + bag.OnGetValue(e); + return e.Value; + } + + public override void ResetValue(object component) { + SetValue(component, item.DefaultValue); + } + + public override void SetValue(object component, object value) { + // Have the property bag raise an event to set the current value + // of the property. + + PropertySpecEventArgs e = new PropertySpecEventArgs(item, value); + bag.OnSetValue(e); + } + + public override bool ShouldSerializeValue(object component) { + object val = this.GetValue(component); + + if (item.DefaultValue == null && val == null) + return false; + else if (item.DefaultValue != null && val == null)//mxd + return true; + else + return !val.Equals(item.DefaultValue); + } + } + #endregion + + private string defaultProperty; + protected PropertySpecCollection properties; //mxd + + /// + /// Initializes a new instance of the PropertyBag class. + /// + public PropertyBag() { + defaultProperty = null; + properties = new PropertySpecCollection(); + } + + /// + /// Gets or sets the name of the default property in the collection. + /// + public string DefaultProperty { + get { return defaultProperty; } + set { defaultProperty = value; } + } + + /// + /// Gets the collection of properties contained within this PropertyBag. + /// + public PropertySpecCollection Properties { + get { return properties; } + } + + /// + /// Occurs when a PropertyGrid requests the value of a property. + /// + public event PropertySpecEventHandler GetValue; + + /// + /// Occurs when the user changes the value of a property in a PropertyGrid. + /// + public event PropertySpecEventHandler SetValue; + + /// + /// Raises the GetValue event. + /// + /// A PropertySpecEventArgs that contains the event data. + protected virtual void OnGetValue(PropertySpecEventArgs e) { + if (GetValue != null) + GetValue(this, e); + } + + /// + /// Raises the SetValue event. + /// + /// A PropertySpecEventArgs that contains the event data. + protected virtual void OnSetValue(PropertySpecEventArgs e) { + //mxd + e.Property.Value = e.Value; + + if (SetValue != null) + SetValue(this, e); + } + + #region ICustomTypeDescriptor explicit interface definitions + // Most of the functions required by the ICustomTypeDescriptor are + // merely pssed on to the default TypeDescriptor for this type, + // which will do something appropriate. The exceptions are noted + // below. + AttributeCollection ICustomTypeDescriptor.GetAttributes() { + return TypeDescriptor.GetAttributes(this, true); + } + + string ICustomTypeDescriptor.GetClassName() { + return TypeDescriptor.GetClassName(this, true); + } + + string ICustomTypeDescriptor.GetComponentName() { + return TypeDescriptor.GetComponentName(this, true); + } + + TypeConverter ICustomTypeDescriptor.GetConverter() { + return TypeDescriptor.GetConverter(this, true); + } + + EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { + return TypeDescriptor.GetDefaultEvent(this, true); + } + + PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { + // This function searches the property list for the property + // with the same name as the DefaultProperty specified, and + // returns a property descriptor for it. If no property is + // found that matches DefaultProperty, a null reference is + // returned instead. + + PropertySpec propertySpec = null; + if (defaultProperty != null) { + int index = properties.IndexOf(defaultProperty); + propertySpec = properties[index]; + } + + if (propertySpec != null) + return new PropertySpecDescriptor(propertySpec, this, propertySpec.Name, null); + else + return null; + } + + object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { + return TypeDescriptor.GetEditor(this, editorBaseType, true); + } + + EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { + return TypeDescriptor.GetEvents(this, true); + } + + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { + return TypeDescriptor.GetEvents(this, attributes, true); + } + + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() { + return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]); + } + + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) { + // Rather than passing this function on to the default TypeDescriptor, + // which would return the actual properties of PropertyBag, I construct + // a list here that contains property descriptors for the elements of the + // Properties list in the bag. + + ArrayList props = new ArrayList(); + + foreach (PropertySpec property in properties) { + ArrayList attrs = new ArrayList(); + + // If a category, description, editor, or type converter are specified + // in the PropertySpec, create attributes to define that relationship. + if (property.Category != null) + attrs.Add(new CategoryAttribute(property.Category)); + + if (property.Description != null) + attrs.Add(new DescriptionAttribute(property.Description)); + + if (property.EditorTypeName != null) + attrs.Add(new EditorAttribute(property.EditorTypeName, typeof(UITypeEditor))); + + if (property.ConverterTypeName != null) + attrs.Add(new TypeConverterAttribute(property.ConverterTypeName)); + + // Additionally, append the custom attributes associated with the + // PropertySpec, if any. + if (property.Attributes != null) + attrs.AddRange(property.Attributes); + + Attribute[] attrArray = (Attribute[])attrs.ToArray(typeof(Attribute)); + + // Create a new property descriptor for the property item, and add + // it to the list. + PropertySpecDescriptor pd = new PropertySpecDescriptor(property, + this, property.Name, attrArray); + props.Add(pd); + } + + // Convert the list of PropertyDescriptors to a collection that the + // ICustomTypeDescriptor can use, and return it. + PropertyDescriptor[] propArray = (PropertyDescriptor[])props.ToArray( + typeof(PropertyDescriptor)); + return new PropertyDescriptorCollection(propArray); + } + + object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) { + return this; + } + #endregion + } + + /// + /// An extension of PropertyBag that manages a table of property values, in + /// addition to firing events when property values are requested or set. + /// + public class PropertyTable : PropertyBag { + private Hashtable propValues; + + /// + /// Initializes a new instance of the PropertyTable class. + /// + public PropertyTable() { + propValues = new Hashtable(); + } + + /// + /// Gets or sets the value of the property with the specified name. + ///

In C#, this property is the indexer of the PropertyTable class.

+ ///
+ public object this[string key] { + get { return propValues[key]; } + set { propValues[key] = value; } + } + + /// + /// This member overrides PropertyBag.OnGetValue. + /// + protected override void OnGetValue(PropertySpecEventArgs e) { + e.Value = propValues[e.Property.Name]; + base.OnGetValue(e); + } + + /// + /// This member overrides PropertyBag.OnSetValue. + /// + protected override void OnSetValue(PropertySpecEventArgs e) { + propValues[e.Property.Name] = e.Value; + base.OnSetValue(e); + } + } +} diff --git a/Source/Plugins/PropertiesDock/Info/IMapElementInfo.cs b/Source/Plugins/PropertiesDock/Info/IMapElementInfo.cs index c7e6bd42..624ca45a 100644 --- a/Source/Plugins/PropertiesDock/Info/IMapElementInfo.cs +++ b/Source/Plugins/PropertiesDock/Info/IMapElementInfo.cs @@ -6,5 +6,7 @@ using System.Text; namespace CodeImp.DoomBuilder.PropertiesDock { interface IMapElementInfo { void ApplyChanges(); + void AddCustomProperty(string name, Type type); + void RemoveCustomProperty(string name); } } diff --git a/Source/Plugins/PropertiesDock/Info/ThingInfo.cs b/Source/Plugins/PropertiesDock/Info/ThingInfo.cs new file mode 100644 index 00000000..f51c1a08 --- /dev/null +++ b/Source/Plugins/PropertiesDock/Info/ThingInfo.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using CodeImp.DoomBuilder.Map; +using System.Globalization; + +namespace CodeImp.DoomBuilder.PropertiesDock { + public class ThingInfo : IMapElementInfo { + + [TypeConverterAttribute(typeof(ThingTypeConverter)), CategoryAttribute("General"), DefaultValueAttribute(0)] + public int Type { get { return type; } set { type = value; } } + private int type; + + private Thing thing; + + public ThingInfo(Thing t) { + thing = t; + type = t.Type; + } + + public void ApplyChanges() { + + } + + public void AddCustomProperty(string name, Type type) { + //properties.Add(new PropertySpec(name + ":", value.GetType(), "Custom properties:")); + } + + public void RemoveCustomProperty(string name) { + /*string n = name.ToUpperInvariant().Trim(); + foreach (PropertySpec ps in properties) { + string cn = ps.Name.ToUpperInvariant(); + if (cn.IndexOf(n) == 0 && cn.Length == n.Length + 1) { + properties.Remove(name); + return; + } + }*/ + } + } + + public class ThingTypeConverter : TypeConverter { + + public override bool CanConvertTo(ITypeDescriptorContext context, System.Type destinationType) { + if (destinationType == typeof(int)) + return true; + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, System.Type destinationType) { + if (destinationType == typeof(System.String) && value is int) { + int type = (int)value; + if (MapElementsData.ThingTypeDescriptions.ContainsKey(type)) { + return type + " - " + MapElementsData.ThingTypeDescriptions[type]; + } + + return type + " - Unknown Thing"; + } + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType) { + if (sourceType == typeof(string)) + return true; + return base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { + if (value is string) { + int type = 0; + if (!int.TryParse((string)value, out type)) { + //throw new ArgumentException("'" + (string)value + "' is not a valid Thing type"); + General.ShowErrorMessage("'" + (string)value + "' is not a valid Thing type", System.Windows.Forms.MessageBoxButtons.OK); + } + return type; + } + return base.ConvertFrom(context, culture, value); + } + } +} diff --git a/Source/Plugins/PropertiesDock/Info/VertexInfo.cs b/Source/Plugins/PropertiesDock/Info/VertexInfo.cs index e1165ed1..623facbe 100644 --- a/Source/Plugins/PropertiesDock/Info/VertexInfo.cs +++ b/Source/Plugins/PropertiesDock/Info/VertexInfo.cs @@ -6,29 +6,51 @@ using System.Text; using CodeImp.DoomBuilder.Map; namespace CodeImp.DoomBuilder.PropertiesDock { - public class VertexInfo : IMapElementInfo { - [CategoryAttribute("Position"), DefaultValueAttribute(0f)] - public float X { get { return x; } set { x = value; } } - private float x; + + public class VertexInfo : PropertyBag, IMapElementInfo { + /*[CategoryAttribute("Position"), DefaultValueAttribute(0f)] + public float X { get { return x; } set { x = value; } }*/ + //private float x; - [CategoryAttribute("Position"), DefaultValueAttribute(0f)] - public float Y { get { return y; } set { y = value; } } - private float y; + /*[CategoryAttribute("Position"), DefaultValueAttribute(0f)] + public float Y { get { return y; } set { y = value; } }*/ + //private float y; + + //public PropertyBag Properties { get { return properties; } } + //private PropertyBag properties; private Vertex vertex; - public VertexInfo(Vertex v) { + public VertexInfo(Vertex v) : base() { vertex = v; - x = v.Position.x; - y = v.Position.y; + //x = v.Position.x; + //y = v.Position.y; + //properties = new PropertyBag(); + properties.Add(new PropertySpec("X:", typeof(float), "Position:", null, v.Position.x)); + properties.Add(new PropertySpec("Y:", typeof(float), "Position:", null, v.Position.y)); } public void ApplyChanges() { float min = (float)General.Map.FormatInterface.MinCoordinate; float max = (float)General.Map.FormatInterface.MaxCoordinate; - vertex.Move(new CodeImp.DoomBuilder.Geometry.Vector2D(General.Clamp(x, min, max), General.Clamp(y, min, max))); + vertex.Move(new CodeImp.DoomBuilder.Geometry.Vector2D(General.Clamp((float)properties[0].Value, min, max), General.Clamp((float)properties[1].Value, min, max))); //todo: add custom fields support } + + public void AddCustomProperty(string name, Type type) { + properties.Add(new PropertySpec(name + ":", type, "Custom properties:")); + } + + public void RemoveCustomProperty(string name){ + string n = name.ToUpperInvariant().Trim(); + foreach (PropertySpec ps in properties) { + string cn = ps.Name.ToUpperInvariant(); + if (cn.IndexOf(n) == 0 && cn.Length == n.Length + 1) { + properties.Remove(name); + return; + } + } + } } } diff --git a/Source/Plugins/PropertiesDock/Properties/Resources.Designer.cs b/Source/Plugins/PropertiesDock/Properties/Resources.Designer.cs new file mode 100644 index 00000000..6fc6cbb8 --- /dev/null +++ b/Source/Plugins/PropertiesDock/Properties/Resources.Designer.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// +// Этот код создан программой. +// Исполняемая версия:2.0.50727.4927 +// +// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае +// повторной генерации кода. +// +//------------------------------------------------------------------------------ + +namespace CodeImp.DoomBuilder.PropertiesDock.Properties { + using System; + + + /// + /// Класс ресурса со строгой типизацией для поиска локализованных строк и т.д. + /// + // Этот класс создан автоматически классом StronglyTypedResourceBuilder + // с помощью такого средства, как ResGen или Visual Studio. + // Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen + // с параметром /str или перестройте свой проект VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Возвращает кэшированный экземпляр ResourceManager, использованный этим классом. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeImp.DoomBuilder.PropertiesDock.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Перезаписывает свойство CurrentUICulture текущего потока для всех + /// обращений к ресурсу с помощью этого класса ресурса со строгой типизацией. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap Add { + get { + object obj = ResourceManager.GetObject("Add", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Remove { + get { + object obj = ResourceManager.GetObject("Remove", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Source/Plugins/PropertiesDock/Properties/Resources.resx b/Source/Plugins/PropertiesDock/Properties/Resources.resx new file mode 100644 index 00000000..00a8973d --- /dev/null +++ b/Source/Plugins/PropertiesDock/Properties/Resources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\Add.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Remove.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Source/Plugins/PropertiesDock/PropertiesDock.csproj b/Source/Plugins/PropertiesDock/PropertiesDock.csproj index 34291d18..e88d90f6 100644 --- a/Source/Plugins/PropertiesDock/PropertiesDock.csproj +++ b/Source/Plugins/PropertiesDock/PropertiesDock.csproj @@ -50,10 +50,18 @@ PropertiesDocker.cs + + + + + True + True + Resources.resx + @@ -66,6 +74,16 @@ PropertiesDocker.cs + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + +