From 158144dd75643827d15bbf673c3cd920a4ac068f Mon Sep 17 00:00:00 2001 From: Ahmet Sait Date: Sat, 11 May 2024 22:01:20 +0300 Subject: [PATCH] Improve & use the new `FlagsEditor` for all flags Turns out Scintilla had a custom editor for flags called `FlagsEnumConverter` before. Unaware of the first one, I wrote a new one called `FlagsEditor` for `ChangeHistory` enum. I may be biased but it turned out pretty good so I think it would be cool to use it for all flags. --- Scintilla.NET/FlagsConverter.cs | 75 +++++++++ Scintilla.NET/FlagsEditor.cs | 136 +--------------- Scintilla.NET/FlagsEditorControl.Designer.cs | 126 +++++++++++++++ Scintilla.NET/FlagsEditorControl.cs | 160 +++++++++++++++++++ Scintilla.NET/FlagsEditorControl.resx | 120 ++++++++++++++ Scintilla.NET/Helpers.cs | 8 + Scintilla.NET/Scintilla.cs | 17 +- 7 files changed, 502 insertions(+), 140 deletions(-) create mode 100644 Scintilla.NET/FlagsConverter.cs create mode 100644 Scintilla.NET/FlagsEditorControl.Designer.cs create mode 100644 Scintilla.NET/FlagsEditorControl.cs create mode 100644 Scintilla.NET/FlagsEditorControl.resx diff --git a/Scintilla.NET/FlagsConverter.cs b/Scintilla.NET/FlagsConverter.cs new file mode 100644 index 0000000..87c8ae8 --- /dev/null +++ b/Scintilla.NET/FlagsConverter.cs @@ -0,0 +1,75 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace ScintillaNET; + +internal class FlagsConverter : TypeConverter +{ + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (value is Enum valueEnum && destinationType == typeof(string)) + { + Type enumType = valueEnum.GetType(); + ulong valueBits = Convert.ToUInt64(valueEnum); + if (valueBits == 0) + { + return Enum.ToObject(enumType, 0).ToString(); + } + ulong bits = 0; + StringBuilder sb = new StringBuilder(); + void Add(Enum item, ulong itemBits) + { + if (itemBits != 0 && valueEnum.HasFlag(item)) + { + bits |= itemBits; + if (sb.Length > 0) + sb.Append(" | "); + sb.Append(item); + } + } + foreach (Enum item in Enum.GetValues(enumType)) + { + ulong itemBits = Convert.ToUInt64(item); + if (Helpers.PopCount(itemBits) == 1) + Add(item, itemBits); + } + foreach (Enum item in Enum.GetValues(enumType)) + { + ulong itemBits = Convert.ToUInt64(item); + if (Helpers.PopCount(itemBits) > 1 && (bits & itemBits) != itemBits) + Add(item, itemBits); + } + return sb.ToString(); + } + return base.ConvertTo(context, culture, value, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string str) + { + Type t = context.PropertyDescriptor.PropertyType; + ulong bits = 0; + var nameList = str.Split('|').Select(x => x.Trim()); + foreach (var name in nameList) + { + bits |= Convert.ToUInt64(Enum.Parse(t, name)); + } + return Enum.ToObject(t, bits); + } + return base.ConvertFrom(context, culture, value); + } +} diff --git a/Scintilla.NET/FlagsEditor.cs b/Scintilla.NET/FlagsEditor.cs index a40fdfb..2ff613e 100644 --- a/Scintilla.NET/FlagsEditor.cs +++ b/Scintilla.NET/FlagsEditor.cs @@ -1,156 +1,26 @@ using System; -using System.Collections; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing.Design; -using System.Globalization; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; using System.Windows.Forms.Design; namespace ScintillaNET; -internal class FlagsConverter : TypeConverter -{ - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value is Enum e && destinationType == typeof(string)) - { - if (Convert.ToUInt64(e) == 0) - { - return Enum.ToObject(e.GetType(), 0).ToString(); - } - StringBuilder sb = new StringBuilder(); - foreach (Enum item in Enum.GetValues(e.GetType())) - { - if (Convert.ToUInt64(item) != 0 && e.HasFlag(item)) - { - if (sb.Length > 0) - sb.Append(" | "); - sb.Append(item); - } - } - return sb.ToString(); - } - return base.ConvertTo(context, culture, value, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string str) - { - Type t = context.PropertyDescriptor.PropertyType; - ulong bits = 0; - var nameList = str.Split('|').Select(x => x.Trim()); - foreach (var name in nameList) - { - bits |= Convert.ToUInt64(Enum.Parse(t, name)); - } - return Enum.ToObject(t, bits); - } - return base.ConvertFrom(context, culture, value); - } -} - internal class FlagsEditor : UITypeEditor { public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) => UITypeEditorEditStyle.DropDown; public override bool IsDropDownResizable => true; - private int inCheck = 0; - - private static ulong CombineEnumList(IEnumerable checkedList) - { - ulong bits = 0; - foreach (var item in checkedList) - { - bits |= Convert.ToUInt64(item); - } - return bits; - } - public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { if (value is Enum e && context.PropertyDescriptor.Attributes.OfType().Any()) { IWindowsFormsEditorService svc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); - Type enumType = e.GetType(); - CheckedListBox checkedListBox = new() { - Dock = DockStyle.Fill, - CheckOnClick = true, - }; - checkedListBox.ItemCheck += (object sender, ItemCheckEventArgs e) => { - if (inCheck > 0) - return; - inCheck++; - try - { - ulong bits = CombineEnumList(checkedListBox.CheckedItems); - ulong change = Convert.ToUInt64(checkedListBox.Items[e.Index]); - if (e.NewValue == CheckState.Checked) - bits |= change; - else if (e.NewValue == CheckState.Unchecked) - bits &= ~change; - Enum enumFinal = (Enum)Enum.ToObject(enumType, bits); - for (int i = 0; i < checkedListBox.Items.Count; i++) - { - Enum itemValue = (Enum)checkedListBox.Items[i]; - checkedListBox.SetItemChecked(i, enumFinal.HasFlag(itemValue)); - } - } - finally - { - inCheck--; - } - }; - inCheck++; - try - { - foreach (Enum item in Enum.GetValues(enumType)) - { - if (Convert.ToUInt64(item) != 0) - checkedListBox.Items.Add(item, e.HasFlag(item)); - } - } - finally - { - inCheck--; - } - Button okBtton = new() { - Dock = DockStyle.Bottom, - AutoSize = true, - AutoSizeMode = AutoSizeMode.GrowAndShrink, - UseVisualStyleBackColor = true, - }; - UserControl userControl = new(); - userControl.Controls.Add(checkedListBox); - userControl.Controls.Add(okBtton); - okBtton.Text = NativeMethods.GetMessageBoxString(0); // OK - okBtton.Click += (object sender, EventArgs e) => { - ulong bits = 0; - foreach (Enum item in checkedListBox.CheckedItems) - { - bits |= Convert.ToUInt64(item); - } - value = Enum.ToObject(enumType, bits); - svc.CloseDropDown(); - }; - svc.DropDownControl(userControl); - return value; + var control = new FlagsEditorControl(svc, e); + svc.DropDownControl(control); + return control.Value; } else return base.EditValue(context, provider, value); diff --git a/Scintilla.NET/FlagsEditorControl.Designer.cs b/Scintilla.NET/FlagsEditorControl.Designer.cs new file mode 100644 index 0000000..5b74b8a --- /dev/null +++ b/Scintilla.NET/FlagsEditorControl.Designer.cs @@ -0,0 +1,126 @@ +namespace ScintillaNET; + +partial class FlagsEditorControl +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.flowLayoutPanel_CheckBoxList = new System.Windows.Forms.FlowLayoutPanel(); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.button_Ok = new System.Windows.Forms.Button(); + this.button_Cancel = new System.Windows.Forms.Button(); + this.tableLayoutPanel.SuspendLayout(); + this.SuspendLayout(); + // + // flowLayoutPanel_CheckBoxList + // + this.flowLayoutPanel_CheckBoxList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel_CheckBoxList.AutoScroll = true; + this.flowLayoutPanel_CheckBoxList.AutoSize = true; + this.flowLayoutPanel_CheckBoxList.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel.SetColumnSpan(this.flowLayoutPanel_CheckBoxList, 2); + this.flowLayoutPanel_CheckBoxList.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanel_CheckBoxList.Location = new System.Drawing.Point(0, 0); + this.flowLayoutPanel_CheckBoxList.Margin = new System.Windows.Forms.Padding(0); + this.flowLayoutPanel_CheckBoxList.Name = "flowLayoutPanel_CheckBoxList"; + this.flowLayoutPanel_CheckBoxList.Size = new System.Drawing.Size(150, 124); + this.flowLayoutPanel_CheckBoxList.TabIndex = 0; + this.flowLayoutPanel_CheckBoxList.WrapContents = false; + // + // tableLayoutPanel + // + this.tableLayoutPanel.AutoSize = true; + this.tableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel.ColumnCount = 2; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel.Controls.Add(this.flowLayoutPanel_CheckBoxList, 0, 0); + this.tableLayoutPanel.Controls.Add(this.button_Ok, 0, 1); + this.tableLayoutPanel.Controls.Add(this.button_Cancel, 1, 1); + this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 2; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.Size = new System.Drawing.Size(150, 150); + this.tableLayoutPanel.TabIndex = 0; + // + // button_Ok + // + this.button_Ok.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.button_Ok.AutoSize = true; + this.button_Ok.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.button_Ok.Location = new System.Drawing.Point(0, 124); + this.button_Ok.Margin = new System.Windows.Forms.Padding(0); + this.button_Ok.Name = "button_Ok"; + this.button_Ok.Size = new System.Drawing.Size(75, 26); + this.button_Ok.TabIndex = 1; + this.button_Ok.Text = "OK"; + this.button_Ok.UseVisualStyleBackColor = true; + this.button_Ok.Click += new System.EventHandler(this.button_Ok_Click); + // + // button_Cancel + // + this.button_Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.button_Cancel.AutoSize = true; + this.button_Cancel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.button_Cancel.Location = new System.Drawing.Point(75, 124); + this.button_Cancel.Margin = new System.Windows.Forms.Padding(0); + this.button_Cancel.Name = "button_Cancel"; + this.button_Cancel.Size = new System.Drawing.Size(75, 26); + this.button_Cancel.TabIndex = 1; + this.button_Cancel.Text = "Cancel"; + this.button_Cancel.UseVisualStyleBackColor = true; + this.button_Cancel.Click += new System.EventHandler(this.button_Cancel_Click); + // + // FlagsEditorControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.tableLayoutPanel); + this.Name = "FlagsEditorControl"; + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel_CheckBoxList; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.Button button_Ok; + private System.Windows.Forms.Button button_Cancel; +} diff --git a/Scintilla.NET/FlagsEditorControl.cs b/Scintilla.NET/FlagsEditorControl.cs new file mode 100644 index 0000000..649c50f --- /dev/null +++ b/Scintilla.NET/FlagsEditorControl.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace ScintillaNET; + +internal partial class FlagsEditorControl : UserControl +{ + public FlagsEditorControl() + { + InitializeComponent(); + button_Ok.Text = NativeMethods.GetMessageBoxString(0); + button_Cancel.Text = NativeMethods.GetMessageBoxString(1); + } + + private readonly Type enumType; + private readonly Enum initialValue; + public Enum Value { get; protected set; } + + private IWindowsFormsEditorService editorService; + + private int inCheck; + + public FlagsEditorControl(IWindowsFormsEditorService editorService, Enum value) : this() + { + this.editorService = editorService; + + enumType = value.GetType(); + Value = initialValue = value; + + inCheck++; + try + { + ulong allBits = CalculateEnumAllValue(enumType); + bool hasAll = false; + ulong valueBits = Convert.ToUInt64(Value); + foreach (string itemName in Enum.GetNames(enumType)) + { + Enum item = (Enum)Enum.Parse(enumType, itemName); + ulong itemBits = Convert.ToUInt64(item); + if (itemBits == allBits) + hasAll = true; + if (itemBits != 0) + { + var checkBox = new CheckBox() { + Text = itemName, + CheckState = CheckStateFromBits(itemBits, valueBits), + AutoSize = true, + Tag = item, + Margin = new Padding(3, 0, 3, 0), + Padding = Padding.Empty, + UseVisualStyleBackColor = true, + }; + checkBox.CheckStateChanged += checkBox_CheckStateChanged; + flowLayoutPanel_CheckBoxList.Controls.Add(checkBox); + } + } + if (!hasAll) + { + var checkBox = new CheckBox() { + Text = "All", + CheckState = CheckStateFromBits(allBits, valueBits), + AutoSize = true, + Tag = (Enum)Enum.ToObject(enumType, allBits), + Margin = new Padding(3, 0, 3, 0), + Padding = Padding.Empty, + UseVisualStyleBackColor = true, + }; + checkBox.CheckStateChanged += checkBox_CheckStateChanged; + flowLayoutPanel_CheckBoxList.Controls.Add(checkBox); + } + this.AutoSize = true; + } + finally + { + inCheck--; + } + } + + private static ulong CalculateEnumAllValue(Type enumType) + { + ulong all = 0; + foreach (Enum bits in Enum.GetValues(enumType)) + { + all |= Convert.ToUInt64(bits); + } + return all; + } + + private static ulong CombineEnumBits(IEnumerable checkBoxList) + { + ulong bits = 0; + foreach (CheckBox checkBox in checkBoxList.Where(c => c.CheckState == CheckState.Checked)) + { + bits |= Convert.ToUInt64(checkBox.Tag); + } + return bits; + } + + private void checkBox_CheckStateChanged(object sender, EventArgs e) + { + if (inCheck > 0) + return; + inCheck++; + try + { + var checkTarget = (CheckBox)sender; + var checkBoxList = flowLayoutPanel_CheckBoxList.Controls.OfType(); + ulong valueBits = CombineEnumBits(checkBoxList); + ulong changedBits = Convert.ToUInt64(checkTarget.Tag); + if (checkTarget.CheckState == CheckState.Checked) + valueBits |= changedBits; + else if (checkTarget.CheckState == CheckState.Unchecked) + valueBits &= ~changedBits; + Value = (Enum)Enum.ToObject(enumType, valueBits); + foreach (CheckBox checkBox in checkBoxList) + { + var itemBits = Convert.ToUInt64(checkBox.Tag); + checkBox.CheckState = CheckStateFromBits(itemBits, valueBits); + } + } + finally + { + inCheck--; + } + } + + private static CheckState CheckStateFromBits(ulong itemBits, ulong valueBits) + { + return (itemBits & valueBits) == itemBits ? CheckState.Checked : (itemBits & valueBits) == 0 ? CheckState.Unchecked : CheckState.Indeterminate; + } + + protected override bool ProcessDialogKey(Keys keyData) + { + if (keyData == Keys.Return) + { + button_Ok_Click(button_Ok, EventArgs.Empty); + return true; + } + if (keyData == Keys.Escape) + { + button_Cancel_Click(button_Cancel, EventArgs.Empty); + return true; + } + return base.ProcessDialogKey(keyData); + } + + private void button_Ok_Click(object sender, EventArgs e) + { + editorService.CloseDropDown(); + } + + private void button_Cancel_Click(object sender, EventArgs e) + { + Value = initialValue; + editorService.CloseDropDown(); + } +} diff --git a/Scintilla.NET/FlagsEditorControl.resx b/Scintilla.NET/FlagsEditorControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Scintilla.NET/FlagsEditorControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Scintilla.NET/Helpers.cs b/Scintilla.NET/Helpers.cs index ff93402..931d9ba 100644 --- a/Scintilla.NET/Helpers.cs +++ b/Scintilla.NET/Helpers.cs @@ -1159,6 +1159,14 @@ public static int TranslateKeys(Keys keys) return keyDefinition; } + // https://stackoverflow.com/questions/2709430/count-number-of-bits-in-a-64-bit-long-big-integer/2709523#2709523 + public static ulong PopCount(ulong i) + { + i = i - ((i >> 1) & 0x5555555555555555UL); + i = (i & 0x3333333333333333UL) + ((i >> 2) & 0x3333333333333333UL); + return (((i + (i >> 4)) & 0xF0F0F0F0F0F0F0FUL) * 0x101010101010101UL) >> 56; + } + #endregion Methods #region Types diff --git a/Scintilla.NET/Scintilla.cs b/Scintilla.NET/Scintilla.cs index 9192bba..9fd904c 100644 --- a/Scintilla.NET/Scintilla.cs +++ b/Scintilla.NET/Scintilla.cs @@ -3895,7 +3895,8 @@ public Char AutoCTypeSeparator [DefaultValue(AutomaticFold.None)] [Category("Behavior")] [Description("Options for allowing the control to automatically handle folding.")] - [TypeConverter(typeof(FlagsEnumTypeConverter.FlagsEnumConverter))] + [Editor(typeof(FlagsEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(FlagsConverter))] public AutomaticFold AutomaticFold { get @@ -4336,11 +4337,11 @@ public int CaretWidth /// /// Gets or sets whether Scintilla should keep track of document change history and in which ways it should display the difference. /// - [Editor(typeof(FlagsEditor), typeof(UITypeEditor))] - [TypeConverter(typeof(FlagsConverter))] [DefaultValue(ChangeHistory.Disabled)] [Category("Change History")] [Description("Controls whether Scintilla should keep track of document change history and in which ways it should display the difference.")] + [Editor(typeof(FlagsEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(FlagsConverter))] public ChangeHistory ChangeHistory { get @@ -5086,7 +5087,8 @@ public LineEndType LineEndTypesActive [DefaultValue(LineEndType.Default)] [Category("Line Endings")] [Description("Line endings types interpreted by the control.")] - [TypeConverter(typeof(FlagsEnumTypeConverter.FlagsEnumConverter))] + [Editor(typeof(FlagsEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(FlagsConverter))] public LineEndType LineEndTypesAllowed { get @@ -5166,7 +5168,6 @@ public int MainSelection [Description("The margins collection.")] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [TypeConverter(typeof(ExpandableObjectConverter))] public MarginCollection Margins { get; private set; } /// @@ -6354,7 +6355,8 @@ public WhitespaceMode ViewWhitespace [DefaultValue(VirtualSpace.None)] [Category("Behavior")] [Description("Options for allowing the caret to move beyond the end of each line.")] - [TypeConverter(typeof(FlagsEnumTypeConverter.FlagsEnumConverter))] + [Editor(typeof(FlagsEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(FlagsConverter))] public VirtualSpace VirtualSpaceOptions { get @@ -6582,7 +6584,8 @@ public int WrapStartIndent [DefaultValue(WrapVisualFlags.None)] [Category("Line Wrapping")] [Description("The visual indicator displayed on a wrapped line.")] - [TypeConverter(typeof(FlagsEnumTypeConverter.FlagsEnumConverter))] + [Editor(typeof(FlagsEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(FlagsConverter))] public WrapVisualFlags WrapVisualFlags { get