add drag to sort

pull/2148/head
2dust 2022-03-24 19:07:45 +08:00
parent d20791bf73
commit 1493a8b03f
5 changed files with 124 additions and 38 deletions

View File

@ -1,10 +1,13 @@
using System.Drawing; using System;
using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
namespace v2rayN.Base namespace v2rayN.Base
{ {
class ListViewFlickerFree : ListView class ListViewFlickerFree : ListView
{ {
Action<int, int> _updateFunc;
public ListViewFlickerFree() public ListViewFlickerFree()
{ {
SetStyle(ControlStyles.OptimizedDoubleBuffer SetStyle(ControlStyles.OptimizedDoubleBuffer
@ -13,40 +16,82 @@ namespace v2rayN.Base
UpdateStyles(); UpdateStyles();
} }
public void RegisterDragEvent(Action<int, int> _update)
public void AutoResizeColumns()
{ {
try _updateFunc = _update;
{ this.AllowDrop = true;
this.SuspendLayout();
Graphics graphics = this.CreateGraphics();
// 原生 ColumnHeaderAutoResizeStyle.ColumnContent 将忽略列头宽度 this.ItemDrag += new ItemDragEventHandler(this.lv_ItemDrag);
this.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); this.DragDrop += new DragEventHandler(this.lv_DragDrop);
this.DragEnter += new DragEventHandler(this.lv_DragEnter);
for (int i = 0; i < this.Columns.Count; i++) this.DragOver += new DragEventHandler(this.lv_DragOver);
{ this.DragLeave += new EventHandler(this.lv_DragLeave);
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 { }
} }
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;
}
} }
} }

View File

@ -225,6 +225,7 @@ namespace v2rayN.Forms
lvServers.Scrollable = true; lvServers.Scrollable = true;
lvServers.MultiSelect = true; lvServers.MultiSelect = true;
lvServers.HeaderStyle = ColumnHeaderStyle.Clickable; lvServers.HeaderStyle = ColumnHeaderStyle.Clickable;
lvServers.RegisterDragEvent(UpdateDragEventHandler);
lvServers.Columns.Add("", 30); lvServers.Columns.Add("", 30);
lvServers.Columns.Add(UIRes.I18N("LvServiceType"), 80); lvServers.Columns.Add(UIRes.I18N("LvServiceType"), 80);
@ -247,6 +248,18 @@ namespace v2rayN.Forms
lvServers.EndUpdate(); 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();
}
}
/// <summary> /// <summary>
/// 刷新服务器列表 /// 刷新服务器列表
/// </summary> /// </summary>

View File

@ -54,6 +54,7 @@ namespace v2rayN.Forms
lvRoutings.View = View.Details; lvRoutings.View = View.Details;
lvRoutings.MultiSelect = true; lvRoutings.MultiSelect = true;
lvRoutings.HeaderStyle = ColumnHeaderStyle.Clickable; lvRoutings.HeaderStyle = ColumnHeaderStyle.Clickable;
lvRoutings.RegisterDragEvent(UpdateDragEventHandler);
lvRoutings.Columns.Add("", 30); lvRoutings.Columns.Add("", 30);
lvRoutings.Columns.Add("outboundTag", 80); lvRoutings.Columns.Add("outboundTag", 80);
@ -61,11 +62,22 @@ namespace v2rayN.Forms
lvRoutings.Columns.Add("protocol", 80); lvRoutings.Columns.Add("protocol", 80);
lvRoutings.Columns.Add("inboundTag", 80); lvRoutings.Columns.Add("inboundTag", 80);
lvRoutings.Columns.Add("domain", 160); lvRoutings.Columns.Add("domain", 160);
lvRoutings.Columns.Add("ip", 160); lvRoutings.Columns.Add("ip", 160);
lvRoutings.Columns.Add("enable", 60); lvRoutings.Columns.Add("enable", 60);
lvRoutings.EndUpdate(); 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() private void RefreshRoutingsView()
{ {
@ -353,6 +365,6 @@ namespace v2rayN.Forms
#endregion #endregion
} }
} }

View File

@ -15,6 +15,7 @@ namespace v2rayN.Handler
class ConfigHandler class ConfigHandler
{ {
private static string configRes = Global.ConfigFileName; private static string configRes = Global.ConfigFileName;
private static object objLock = new object();
#region ConfigHandler #region ConfigHandler
@ -204,7 +205,10 @@ namespace v2rayN.Handler
/// <param name="config"></param> /// <param name="config"></param>
private static void ToJsonFile(Config config) private static void ToJsonFile(Config config)
{ {
Utils.ToJsonFile(config, Utils.GetPath(configRes)); lock (objLock)
{
Utils.ToJsonFile(config, Utils.GetPath(configRes));
}
} }
#endregion #endregion
@ -353,7 +357,7 @@ namespace v2rayN.Handler
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="eMove"></param> /// <param name="eMove"></param>
/// <returns></returns> /// <returns></returns>
public static int MoveServer(ref Config config, ref List<VmessItem> lstVmess, int index, EMove eMove) public static int MoveServer(ref Config config, ref List<VmessItem> lstVmess, int index, EMove eMove, int pos = -1)
{ {
int count = lstVmess.Count; int count = lstVmess.Count;
if (index < 0 || index > lstVmess.Count - 1) if (index < 0 || index > lstVmess.Count - 1)
@ -409,6 +413,9 @@ namespace v2rayN.Handler
break; break;
} }
case EMove.Position:
lstVmess[index].sort = pos * 10 + 1;
break;
} }
ToJsonFile(config); ToJsonFile(config);
@ -1258,7 +1265,7 @@ namespace v2rayN.Handler
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="eMove"></param> /// <param name="eMove"></param>
/// <returns></returns> /// <returns></returns>
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; int count = routingItem.rules.Count;
if (index < 0 || index > routingItem.rules.Count - 1) if (index < 0 || index > routingItem.rules.Count - 1)
@ -1316,6 +1323,14 @@ namespace v2rayN.Handler
break; 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; return 0;

View File

@ -6,6 +6,7 @@ namespace v2rayN.Mode
Top = 1, Top = 1,
Up = 2, Up = 2,
Down = 3, Down = 3,
Bottom = 4 Bottom = 4,
Position = 5
} }
} }