using FastReport.Utils; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace FastReport.FastQueryBuilder { internal class Workspace : UserControl { private PosCounter posC = new PosCounter(10, 10); private List tableViews = new List(); private LinkMenu linkMenu; private Link highlightLink; public Workspace() { AllowDrop = true; BackColor = SystemColors.AppWorkspace; linkMenu = new LinkMenu(this); linkMenu.DeleteLink += LinkMenu_DeleteLink; SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); } public List Links { get; set; } public event AddTableEventHandler OnAddTable; public void Clear() { foreach (TableView c in tableViews) { c.Dispose(); } tableViews.Clear(); Refresh(); } public void AddTable(Table table) => AddTable(table, posC.Next); public void AddTable(Table table, Point pos) => OnAddTable?.Invoke(this, new AddTableEventArgs(table, pos)); public ITableView DoAddTable(Table table, Point position) { TableView tbl = new TableView(); tbl.OnDeleteTable += OnDeleteTable; table.TableView = tbl; tbl.Table = table; tbl.Location = new Point(-1000, -1000); tbl.Parent = this; tbl.Scale(new SizeF(this.DpiMultiplier(), this.DpiMultiplier())); tbl.UpdateDpiDependencies(); tbl.Location = position.IsEmpty ? posC.Next : position; tbl.BringToFront(); tableViews.Add(tbl); Refresh(); return tbl; } private void OnDeleteTable(object sender, AddTableEventArgs e) { for (int i = Links.Count - 1; i >= 0; i--) { if ((Links[i].From.Table == e.table) || (Links[i].To.Table == e.table)) Links.RemoveAt(i); } tableViews.Remove((TableView)e.table.TableView); Refresh(); } private void LinkMenu_DeleteLink(object sender, EventArgs e) { Links.Remove(linkMenu.CurrentLink); Refresh(); } private GraphicsPath GetLinkPath(Link link) { LinkPosition lp1, lp2; int cp1 = link.From.Left + link.From.Width / 2; int cp2 = link.To.Left + link.To.Width / 2; if (cp1 > cp2) { if ((link.From.Left) < link.To.Left + link.To.Width) { lp1 = LinkPosition.Right; lp2 = LinkPosition.Right; } else { lp1 = LinkPosition.Left; lp2 = LinkPosition.Right; } } else { if ((link.From.Left + link.From.Width) > link.To.Left) { lp2 = LinkPosition.Left; lp1 = LinkPosition.Left; } else { lp2 = LinkPosition.Left; lp1 = LinkPosition.Right; } } Point pnt1 = link.From.GetPosition(lp1); Point pnt2 = link.To.GetPosition(lp2); int _2 = this.LogicalToDevice(2); int _4 = this.LogicalToDevice(4); int _8 = this.LogicalToDevice(8); var path = new GraphicsPath(); int dx = (lp1 == LinkPosition.Left) ? _8 : -_8; Point pnt3 = new Point(pnt1.X + dx, pnt1.Y); path.AddLine(pnt1, pnt3); path.AddLine(pnt1, pnt2); dx = (lp2 == LinkPosition.Left) ? _4 : -_4; pnt3 = new Point(pnt2.X + dx, pnt2.Y); path.AddLine(pnt2, pnt3); path.AddRectangle(new Rectangle(pnt3.X + dx - _4, pnt3.Y - _2, _4, _4)); return path; } private bool HitTestLink(Link link, Point point) { using (var path = GetLinkPath(link)) using (var pen = new Pen(Color.Black, this.LogicalToDevice(5f))) { path.Widen(pen); return path.IsVisible(point); } } private void DrawLink(Link link, Graphics g, bool highlight) { using (var path = GetLinkPath(link)) using (Pen pen = new Pen(highlight ? SystemColors.Highlight : Color.Black, this.LogicalToDevice(highlight ? 2 : 1))) { g.DrawPath(pen, path); } } protected override void OnDragOver(DragEventArgs e) { base.OnDragOver(e); if (e.Data.GetDataPresent(typeof(Table))) e.Effect = DragDropEffects.Copy; else e.Effect = DragDropEffects.None; } protected override void OnDragDrop(DragEventArgs e) { base.OnDragDrop(e); Table _table = (Table)e.Data.GetData(typeof(Table)); if (_table != null) { AddTable(_table, PointToClient(new Point(e.X, e.Y))); } } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (tableViews.Count == 0) { TextRenderer.DrawText(e.Graphics, Res.Get("Forms,QueryBuilder,Hint"), Font, DisplayRectangle, Color.Black, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); return; } e.Graphics.SmoothingMode = SmoothingMode.HighQuality; foreach (var link in Links) { DrawLink(link, e.Graphics, link == highlightLink); } } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); Link hl = null; foreach (var link in Links) { if (HitTestLink(link, e.Location)) { hl = link; break; } } if (highlightLink != hl) { highlightLink = hl; Cursor = hl == null ? Cursors.Default : Cursors.Hand; Refresh(); } } protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (highlightLink != null) { linkMenu.Show(this, e.Location, highlightLink); } } protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); posC.maxX = Width; posC.maxY = Height; } public void UpdateDpiDependencies() { posC.stepX = posC.stepY = this.LogicalToDevice(200); linkMenu.UpdateDpiDependencies(); foreach (var tv in tableViews) { tv.UpdateDpiDependencies(); } } } }