From 1493a8b03f56f7aea4deaa9ababa83698d850ba1 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Thu, 24 Mar 2022 19:07:45 +0800 Subject: [PATCH] add drag to sort --- v2rayN/v2rayN/Base/ListViewFlickerFree.cs | 109 +++++++++++++----- v2rayN/v2rayN/Forms/MainForm.cs | 13 +++ v2rayN/v2rayN/Forms/RoutingRuleSettingForm.cs | 16 ++- v2rayN/v2rayN/Handler/ConfigHandler.cs | 21 +++- v2rayN/v2rayN/Mode/EMove.cs | 3 +- 5 files changed, 124 insertions(+), 38 deletions(-) diff --git a/v2rayN/v2rayN/Base/ListViewFlickerFree.cs b/v2rayN/v2rayN/Base/ListViewFlickerFree.cs index c70ccfc6..91f555c3 100644 --- a/v2rayN/v2rayN/Base/ListViewFlickerFree.cs +++ b/v2rayN/v2rayN/Base/ListViewFlickerFree.cs @@ -1,10 +1,13 @@ -using System.Drawing; +using System; +using System.Drawing; using System.Windows.Forms; namespace v2rayN.Base { class ListViewFlickerFree : ListView { + Action _updateFunc; + public ListViewFlickerFree() { SetStyle(ControlStyles.OptimizedDoubleBuffer @@ -13,40 +16,82 @@ namespace v2rayN.Base UpdateStyles(); } - - public void AutoResizeColumns() + public void RegisterDragEvent(Action _update) { - try - { - this.SuspendLayout(); - Graphics graphics = this.CreateGraphics(); + _updateFunc = _update; + this.AllowDrop = true; - // 原生 ColumnHeaderAutoResizeStyle.ColumnContent 将忽略列头宽度 - this.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); - - for (int i = 0; i < this.Columns.Count; i++) - { - ColumnHeader c = this.Columns[i]; - int cWidth = c.Width; - string MaxStr = ""; - Font font = this.Items[0].SubItems[0].Font; - - foreach (ListViewItem item in this.Items) - { - // 整行视作相同字形,不单独计算每个单元格 - font = item.SubItems[i].Font; - string str = item.SubItems[i].Text; - if (str.Length > MaxStr.Length) // 未考虑非等宽问题 - MaxStr = str; - } - int strWidth = (int)graphics.MeasureString(MaxStr, font).Width; - c.Width = System.Math.Max(cWidth, strWidth); - } - this.ResumeLayout(); - } - catch { } + this.ItemDrag += new ItemDragEventHandler(this.lv_ItemDrag); + this.DragDrop += new DragEventHandler(this.lv_DragDrop); + this.DragEnter += new DragEventHandler(this.lv_DragEnter); + this.DragOver += new DragEventHandler(this.lv_DragOver); + this.DragLeave += new EventHandler(this.lv_DragLeave); } - + private void lv_DragDrop(object sender, DragEventArgs e) + { + int targetIndex = this.InsertionMark.Index; + if (targetIndex == -1) + { + return; + } + if (this.InsertionMark.AppearsAfterItem) + { + targetIndex++; + } + + + if (this.SelectedIndices.Count <= 0) + { + return; + } + + _updateFunc(this.SelectedIndices[0], targetIndex); + + //ListViewItem draggedItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem)); + //this.BeginUpdate(); + //this.Items.Insert(targetIndex, (ListViewItem)draggedItem.Clone()); + //this.Items.Remove(draggedItem); + //this.EndUpdate(); + } + + + private void lv_DragEnter(object sender, DragEventArgs e) + { + e.Effect = e.AllowedEffect; + } + + private void lv_DragLeave(object sender, EventArgs e) + { + this.InsertionMark.Index = -1; + } + + private void lv_DragOver(object sender, DragEventArgs e) + { + Point targetPoint = this.PointToClient(new Point(e.X, e.Y)); + int targetIndex = this.InsertionMark.NearestIndex(targetPoint); + + if (targetIndex > -1) + { + Rectangle itemBounds = this.GetItemRect(targetIndex); + this.EnsureVisible(targetIndex); + + if (targetPoint.Y > itemBounds.Top + (itemBounds.Height / 2)) + { + this.InsertionMark.AppearsAfterItem = true; + } + else + { + this.InsertionMark.AppearsAfterItem = false; + } + } + this.InsertionMark.Index = targetIndex; + } + + private void lv_ItemDrag(object sender, ItemDragEventArgs e) + { + this.DoDragDrop(e.Item, DragDropEffects.Move); + this.InsertionMark.Index = -1; + } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Forms/MainForm.cs b/v2rayN/v2rayN/Forms/MainForm.cs index f741842f..5ec3cdc4 100644 --- a/v2rayN/v2rayN/Forms/MainForm.cs +++ b/v2rayN/v2rayN/Forms/MainForm.cs @@ -225,6 +225,7 @@ namespace v2rayN.Forms lvServers.Scrollable = true; lvServers.MultiSelect = true; lvServers.HeaderStyle = ColumnHeaderStyle.Clickable; + lvServers.RegisterDragEvent(UpdateDragEventHandler); lvServers.Columns.Add("", 30); lvServers.Columns.Add(UIRes.I18N("LvServiceType"), 80); @@ -247,6 +248,18 @@ namespace v2rayN.Forms lvServers.EndUpdate(); } + private void UpdateDragEventHandler(int index, int targetIndex) + { + if (index < 0 || targetIndex < 0) + { + return; + } + if (ConfigHandler.MoveServer(ref config, ref lstVmess, index, EMove.Position, targetIndex) == 0) + { + RefreshServers(); + } + } + /// /// 刷新服务器列表 /// diff --git a/v2rayN/v2rayN/Forms/RoutingRuleSettingForm.cs b/v2rayN/v2rayN/Forms/RoutingRuleSettingForm.cs index 87fe775c..3ae9359f 100644 --- a/v2rayN/v2rayN/Forms/RoutingRuleSettingForm.cs +++ b/v2rayN/v2rayN/Forms/RoutingRuleSettingForm.cs @@ -54,6 +54,7 @@ namespace v2rayN.Forms lvRoutings.View = View.Details; lvRoutings.MultiSelect = true; lvRoutings.HeaderStyle = ColumnHeaderStyle.Clickable; + lvRoutings.RegisterDragEvent(UpdateDragEventHandler); lvRoutings.Columns.Add("", 30); lvRoutings.Columns.Add("outboundTag", 80); @@ -61,11 +62,22 @@ namespace v2rayN.Forms lvRoutings.Columns.Add("protocol", 80); lvRoutings.Columns.Add("inboundTag", 80); lvRoutings.Columns.Add("domain", 160); - lvRoutings.Columns.Add("ip", 160); + lvRoutings.Columns.Add("ip", 160); lvRoutings.Columns.Add("enable", 60); lvRoutings.EndUpdate(); } + private void UpdateDragEventHandler(int index, int targetIndex) + { + if (index < 0 || targetIndex < 0) + { + return; + } + if (ConfigHandler.MoveRoutingRule(ref routingItem, index, EMove.Position, targetIndex) == 0) + { + RefreshRoutingsView(); + } + } private void RefreshRoutingsView() { @@ -353,6 +365,6 @@ namespace v2rayN.Forms #endregion - + } } diff --git a/v2rayN/v2rayN/Handler/ConfigHandler.cs b/v2rayN/v2rayN/Handler/ConfigHandler.cs index fdc6fc4a..8556eb2c 100644 --- a/v2rayN/v2rayN/Handler/ConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/ConfigHandler.cs @@ -15,6 +15,7 @@ namespace v2rayN.Handler class ConfigHandler { private static string configRes = Global.ConfigFileName; + private static object objLock = new object(); #region ConfigHandler @@ -204,7 +205,10 @@ namespace v2rayN.Handler /// private static void ToJsonFile(Config config) { - Utils.ToJsonFile(config, Utils.GetPath(configRes)); + lock (objLock) + { + Utils.ToJsonFile(config, Utils.GetPath(configRes)); + } } #endregion @@ -353,7 +357,7 @@ namespace v2rayN.Handler /// /// /// - public static int MoveServer(ref Config config, ref List lstVmess, int index, EMove eMove) + public static int MoveServer(ref Config config, ref List lstVmess, int index, EMove eMove, int pos = -1) { int count = lstVmess.Count; if (index < 0 || index > lstVmess.Count - 1) @@ -409,6 +413,9 @@ namespace v2rayN.Handler break; } + case EMove.Position: + lstVmess[index].sort = pos * 10 + 1; + break; } ToJsonFile(config); @@ -1258,7 +1265,7 @@ namespace v2rayN.Handler /// /// /// - public static int MoveRoutingRule(ref RoutingItem routingItem, int index, EMove eMove) + public static int MoveRoutingRule(ref RoutingItem routingItem, int index, EMove eMove, int pos = -1) { int count = routingItem.rules.Count; if (index < 0 || index > routingItem.rules.Count - 1) @@ -1316,6 +1323,14 @@ namespace v2rayN.Handler break; } + case EMove.Position: + { + var removeItem = routingItem.rules[index]; + var item = Utils.DeepCopy(routingItem.rules[index]); + routingItem.rules.Insert(pos, item); + routingItem.rules.Remove(removeItem); + break; + } } return 0; diff --git a/v2rayN/v2rayN/Mode/EMove.cs b/v2rayN/v2rayN/Mode/EMove.cs index 7f67d5b1..892a6ab3 100644 --- a/v2rayN/v2rayN/Mode/EMove.cs +++ b/v2rayN/v2rayN/Mode/EMove.cs @@ -6,6 +6,7 @@ namespace v2rayN.Mode Top = 1, Up = 2, Down = 3, - Bottom = 4 + Bottom = 4, + Position = 5 } }