using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Drawing.Drawing2D; using GeoSigma.SigmaDrawerUtil; namespace GeoSigma.SigmaDrawerStyle { public delegate void ItemColorChangedEventHandler(GradientColorItem item); public delegate void InsertNewColorItemEventHandler(double itemZ); public delegate void ResetColorItemEventHandler(int itemIndex, GradientColorItem item); public partial class GradientPanel : UserControl { public event ItemColorChangedEventHandler ItemColorChangedEvent; public event InsertNewColorItemEventHandler InsertNewColorEvent; public event ResetColorItemEventHandler ResetColorItemEvent; public event ItemColorChangedEventHandler ItemColorEditFinishedEvent; public List Items { get; set; } = new List(); private double zMin = 0; private double zMax = 100; private int handleHeight = 30; private int paddingY = 2; private int paddingX = 4; private List handles { get; set; } = new List(); private int selectedHandleIndex = -1; private SlowDownTimer _timer = new SlowDownTimer(20); /// /// Initializes a new instance of the class. /// public GradientPanel() { SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); InitializeComponent(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.SmoothingMode = SmoothingMode.HighQuality; Rectangle rectHandler = GetHandlerBound(); foreach (var handler in handles) { handler.Draw(e.Graphics, rectHandler); } } protected override void OnPaintBackground(PaintEventArgs e) { base.OnPaintBackground(e); // ControlPaint.DrawBorder(e.Graphics, Bounds, SystemColors.ControlText, ButtonBorderStyle.Solid); PaintGradientValue(e.Graphics, GetGradientColorBounds(), Items); } public void DrawGradient(List list) { Items = list; if (Items.Count == 0) { return; } zMin = Items.Min(r => r.Z); zMax = Items.Max(r => r.Z); handles = list.Select(item => new GradientHandler(item, zMin, zMax)).ToList(); this.Invalidate(); } private Rectangle GetGradientColorBounds() { var bounds = this.ClientRectangle; bounds.Inflate(-paddingX, (int)(-(paddingY + handleHeight) * 0.5)); bounds.Y = paddingY; return bounds; } private Rectangle GetHandlerBound() { var bounds = this.ClientRectangle; // bounds.Inflate(cx, (int)(-(padingY + handleHeight) * 0.5)); bounds.Inflate(-paddingX, 0); bounds.Y = this.ClientRectangle.Height - handleHeight; bounds.Height = handleHeight; return bounds; } /// /// 在指定画布的指定区域绘制渐变色 /// /// 画布 /// 区域 /// 颜色列表 public static void PaintGradientValue(Graphics g, RectangleF bounds, List list) { if (list == null || list.Count < 2) { return; } double zmin = list.Min(r => r.Z); double zmax = list.Max(r => r.Z); if (zmin == zmax) { return; } LinearGradientBrush br = new LinearGradientBrush(bounds, Color.Black, Color.Black, 0, false); { RectangleF rectFill = bounds; rectFill.Inflate(-0.5f, 0); ColorBlend cb = new ColorBlend(); cb.Colors = list.Select(model => Color.FromArgb(model.T, model.R, model.G, model.B)).ToArray(); List pos = new List(); cb.Positions = new float[cb.Colors.Length]; cb.Positions[0] = 0.0f; cb.Positions[cb.Colors.Length - 1] = 1; for (int i = 1; i < list.Count - 1; i++) { cb.Positions[i] = Convert.ToSingle((list[i].Z - zmin) / (zmax - zmin)); } br.InterpolationColors = cb; // br.RotateTransform(45); g.FillRectangle(br, rectFill); } // 绘制突变 for (int i = 0; i < list.Count - 1; i++) { var item1 = list[i]; var item2 = list[i + 1]; var x1 = Convert.ToInt32(((item1.Z - zmin) / (zmax - zmin) * bounds.Width) + bounds.Left); var x2 = Convert.ToInt32(((item2.Z - zmin) / (zmax - zmin) * bounds.Width) + bounds.Left); var rect = RectangleF.FromLTRB(x1, bounds.Top, x2, bounds.Bottom); if (rect.Width > 0) { if (item1.C == 0) { var brush = new SolidBrush(item1.ColorValue); g.FillRectangle(brush, rect); } } } } /// /// 双击事件,插入控制点,或者修改颜色 /// /// 当前控件 /// 事件参数 private void GradientPanel_MouseDoubleClick(object sender, MouseEventArgs e) { var bounds = GetHandlerBound(); // 双击手柄时的处理 for (int i = 1; i < handles.Count - 1; i++) { GradientHandler handle = handles[i]; // 双击的是控制手柄时 if (handle.GetBounds(bounds).Contains(e.Location)) { ColorDialog dlg = new ColorDialog(); dlg.Color = handle.Item.ColorValue; if (dlg.ShowDialog() == DialogResult.OK) { handle.Item.ColorValue = dlg.Color; ItemColorChangedEvent?.Invoke(handle.Item); this.Invalidate(); } return; } } // 双击其它区域,插入新控制点 if (e.Location.X >= bounds.X && e.Location.X <= bounds.X + bounds.Width) { double dZInsert = (Convert.ToDouble(e.Location.X - bounds.Left) / bounds.Width * (zMax - zMin)) + zMin; InsertNewColorEvent?.Invoke(dZInsert); } } private void GradientPanel_MouseDown(object sender, MouseEventArgs e) { var rectHandleArea = GetHandlerBound(); for (int i = 1; i < handles.Count - 1; i++) { GradientHandler handler = handles[i]; if (handler.GetBounds(rectHandleArea).Contains(e.Location)) { selectedHandleIndex = i; //selectedHandle = handler; //_selected_z_begin = Items[i - 1].Z; //_selected_z_end = Items[i + 1].Z; break; } } } private void GradientPanel_MouseMove(object sender, MouseEventArgs e) { if (selectedHandleIndex > 0) { // 两端的控制点未处理 var bounds = GetHandlerBound(); GradientHandler handler = handles[selectedHandleIndex]; GradientHandler handlerLeft = handles[selectedHandleIndex - 1]; GradientHandler handlerRight = handles[selectedHandleIndex + 1]; double newZ = (Convert.ToDouble(e.X - bounds.Left) / bounds.Width * (zMax - zMin)) + zMin; if (newZ > handlerLeft.Item.Z && newZ < handlerRight.Item.Z) { handler.Item.Z = newZ; this.Invalidate(); int index = selectedHandleIndex; _timer.Invoke(this, () => ResetColorItemEvent(index, handler.Item)); } } } private void ResetColorItem(int itemIndex, GradientColorItem item) { ResetColorItemEvent?.Invoke(selectedHandleIndex, item); } private void GradientPanel_MouseUp(object sender, MouseEventArgs e) { if (selectedHandleIndex > 0) { GradientHandler handle = handles[selectedHandleIndex]; ItemColorEditFinishedEvent?.Invoke(handle.Item); } selectedHandleIndex = -1; } } #region GradientHandler public class GradientHandler { #region Shape private static GraphicsPath Shape; /// /// Initializes a new instance of the class. /// public GradientHandler() { if (Shape == null) { Shape = new GraphicsPath(); Shape.AddLines(new PointF[] { new PointF(0, 0), new PointF(4f, 3f), new PointF(4f, 13f), new PointF(-4f, 13f), new PointF(-4f, 3f), new PointF(0, 0), }); } } #endregion public GradientColorItem Item { get; set; } private SolidBrush _brush; private Pen _pen = new Pen(Color.Black, 1f); private double zMin; private double zMax; /// /// Initializes a new instance of the class. /// /// /// /// public GradientHandler(GradientColorItem item, double zMin, double zMax) : this() { Item = item; this.zMin = zMin; this.zMax = zMax; _brush = new SolidBrush(item.ColorValue); } internal RectangleF GetBounds(Rectangle r) { return GetPath(r).GetBounds(); } private GraphicsPath GetPath(Rectangle r) { var x = ((Item.Z - zMin) / (zMax - zMin) * r.Width) + r.Left; var y = r.Y; var tmp = (GraphicsPath)Shape.Clone(); Matrix translateMatrix = new Matrix(); translateMatrix.Translate((float)x, y); tmp.Transform(translateMatrix); return tmp; } public void Draw(Graphics g, Rectangle r) { var path = GetPath(r); _brush.Color = Item.ColorValue; g.FillPath(_brush, path); g.DrawPath(_pen, path); } public bool Update(Rectangle bounds, Point eLocation, double begin, double end) { double newZ = (Convert.ToDouble(eLocation.X - bounds.Left) / bounds.Width * (zMax - zMin)) + zMin; if (newZ >= begin && newZ <= end) { Item.Z = newZ; return true; } return false; } } #endregion }