using System.Diagnostics; using System.Drawing.Drawing2D; using System.Windows.Forms; using Hawkeye.VisionBuilder.Features.ImagePreview; using Hawkeye.VisionBuilder.Panels; using Hawkeye.VisionBuilder.Workflow; using Hawkeye.VisionBuilder.Workflow.Datatypes; using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements; using Hawkeye.VisionBuilder.Workflow.Links; using Rectangle = System.Drawing.Rectangle; namespace Hawkeye.VisionBuilder.Features.VisionSteps { public partial class VisionStepsPanel : BasePannel { private readonly WorkflowList _workflowList; private readonly OperationDiscoveryService _discoveryService; private readonly ImagePreviewPanel _imagePreviewPanel; private BindingSource _bindingSource = new BindingSource(); public VisionStepsPanel(Workflow.WorkflowList workflowList, OperationDiscoveryService discoveryService, ImagePreview.ImagePreviewPanel imagePreviewPanel) { _workflowList = workflowList; _discoveryService = discoveryService; _imagePreviewPanel = imagePreviewPanel; InitializeComponent(); dataGridView1.AutoGenerateColumns = false; dataGridView1.DataSource = _bindingSource; dataGridView1.Columns[0].DataPropertyName = nameof(BaseOperationDecorator.Result); dataGridView1.Columns[1].DataPropertyName = nameof(BaseOperationDecorator.IsEnabled); dataGridView1.Columns[2].DataPropertyName = nameof(BaseOperationDecorator.Label); dataGridView1.Columns[2].ReadOnly = false; dataGridView1.ReadOnly = false; dataGridView1.Columns[3].DataPropertyName = nameof(BaseOperationDecorator.ResultString); dataGridView1.Columns[4].DataPropertyName = nameof(BaseOperationDecorator.TypeName); dataGridView1.Columns[5].DataPropertyName = nameof(BaseOperationDecorator.ExecutionTimeString); dataGridView1.DefaultCellStyle.SelectionBackColor = Color.Bisque; dataGridView1.DefaultCellStyle.SelectionForeColor = Color.Black; dataGridView1.CellPainting += DataGridView1_CellPainting; dataGridView1.SelectionChanged += DataGridView1_SelectionChanged; RefreshWorkflow(); //dataGridView1.Paint += DataGridView1_Paint; } public void RefreshWorkflow() { _bindingSource.Clear(); foreach (BaseOperation operation in _workflowList.Operations) { _bindingSource.Add(new BaseOperationDecorator(operation)); } } public event Action OperationSelected = delegate { }; private void DataGridView1_SelectionChanged(object? sender, EventArgs e) { } public void UpdateView() { _imagePreviewPanel.ClearGraphics(); _imagePreviewPanel.SetImage(_workflowList.Context.ActiveImage); _workflowList.Context.GraphicsElements.ForEach(_imagePreviewPanel.AddGraphics); _imagePreviewPanel.Refresh(); Refresh(); } private void DataGridView1_Paint(object? sender, PaintEventArgs e) { } private void DataGridView1_CellPainting(object? sender, DataGridViewCellPaintingEventArgs e) { if (e.RowIndex > -1) { var c1 = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true); var row = dataGridView1.Rows[e.RowIndex]; var rowValue = row.DataBoundItem as BaseOperationDecorator; e.PaintBackground(c1, true); if (e.ColumnIndex == 0 && e.Value != null) { var cx = e.CellBounds.Width / 2 + e.CellBounds.Left; var cy = e.CellBounds.Height / 2 + e.CellBounds.Top; var radius = e.CellBounds.Height / 2 - 3; if ((bool) e.Value) { e.Graphics.FillEllipse(Brushes.Green, cx - radius, cy - radius, radius * 2, radius * 2); } else { e.Graphics.FillEllipse(Brushes.Red, cx - radius, cy - radius, radius * 2, radius * 2); } e.Handled = true; } } } private static ToolStripMenuItem EnsureCategory(ToolStripItemCollection collection, string category) { var name = category.Split("/", StringSplitOptions.RemoveEmptyEntries); ToolStripMenuItem currentCategory = null; foreach (var s in name) { if (currentCategory == null) { if (!collection.ContainsKey(s)) { currentCategory = new ToolStripMenuItem() { Name = s, Text = s }; collection.Add(currentCategory); } else { currentCategory = collection[s] as ToolStripMenuItem; } } else { if (!currentCategory.DropDownItems.ContainsKey(s)) { var newCategory = new ToolStripMenuItem() { Name = s, Text = s }; currentCategory.DropDownItems.Add(newCategory); currentCategory = newCategory; } else { currentCategory = currentCategory.DropDownItems[s] as ToolStripMenuItem; } } } return currentCategory!; } private void button1_Click(object sender, EventArgs e) { var factories = _discoveryService.DiscoverOperations(); var context = new ContextMenuStrip(); foreach (OperationDescription desc in factories) { var descCategory = desc.Category; ToolStripMenuItem currentCategory = EnsureCategory(context.Items, descCategory); currentCategory.DropDownItems.Add(desc.Name).Click += (o, args) => { var operation = _discoveryService.CreateInstance(desc.Type); _workflowList.Operations.Add(operation); int num = 1; while (_workflowList.Operations.Any(x => x.Label == operation.Label + num)) num++;//generate unique name operation.Label += "" + num; _bindingSource.Add(new BaseOperationDecorator(operation)); dataGridView1.ClearSelection(); dataGridView1.Rows[^1].Selected = true; ProcessRowSelection(); }; } context.Show(button1, button1.Location); } private void btnTest_Click(object sender, EventArgs e) { ExecuteWorkflow(); } public WorkflowList WorkflowList => _workflowList; public void ExecuteWorkflow() { _workflowList.Context = new Context(); var sw = Stopwatch.StartNew(); _workflowList.Operations.ForEach(x => x.NeedsUpdate = true); _workflowList.Execute(); sw.Stop(); lblProcessingTime.Text = sw.ElapsedMilliseconds.ToString() + " ms"; _imagePreviewPanel.SetImage(_workflowList.Context.ActiveImage); _imagePreviewPanel.ClearGraphics(); _workflowList.Context.GraphicsElements.ForEach(_imagePreviewPanel.AddGraphics); Refresh(); } private void dataGridView1_MouseUp(object sender, MouseEventArgs e) { ProcessRowSelection(); } public BaseOperation? GetSelectedOperation() { if (dataGridView1.SelectedRows.Count == 0) return null; var rowIndex = dataGridView1.SelectedRows[0].Index; return (_bindingSource[rowIndex] as BaseOperationDecorator)?.Operation; } public void ProcessRowSelection() { if (dataGridView1.SelectedRows.Count == 0) return; var rowIndex = dataGridView1.SelectedRows[0].Index; var x = (_bindingSource[rowIndex] as BaseOperationDecorator); OperationSelected.Invoke(x.Operation); _imagePreviewPanel.ClearGraphics(); foreach (BaseOperation operation in _workflowList.Operations) { if (operation.NeedsUpdate) _workflowList.ExecuteOne(operation); if (operation == x.Operation) break; } UpdateView(); } private void dataGridView1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Delete) { if (dataGridView1.SelectedRows.Count == 0) return; var rowIndex = dataGridView1.SelectedRows[0].Index; _bindingSource.RemoveAt(rowIndex); _workflowList.Operations.RemoveAt(rowIndex); if (rowIndex > 0) { dataGridView1.ClearSelection(); dataGridView1.Rows[rowIndex - 1].Selected = true; ProcessRowSelection(); } } } private Rectangle dragBoxFromMouseDown; private int rowIndexFromMouseDown; private int rowIndexOfItemUnderMouseToDrop; private void dataGridView1_MouseMove(object sender, MouseEventArgs e) { if ((e.Button & MouseButtons.Left) == MouseButtons.Left) { // If the mouse moves outside the rectangle, start the drag. if (dragBoxFromMouseDown != Rectangle.Empty && !dragBoxFromMouseDown.Contains(e.X, e.Y)) { // Proceed with the drag and drop, passing in the list item. DragDropEffects dropEffect = dataGridView1.DoDragDrop( dataGridView1.Rows[rowIndexFromMouseDown], DragDropEffects.Move); } } } private void dataGridView1_MouseDown(object sender, MouseEventArgs e) { // Get the index of the item the mouse is below. rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex; if (rowIndexFromMouseDown != -1) { // Remember the point where the mouse down occurred. // The DragSize indicates the size that the mouse can move // before a drag event should be started. Size dragSize = SystemInformation.DragSize; // Create a rectangle using the DragSize, with the mouse position being // at the center of the rectangle. dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize); } else // Reset the rectangle if the mouse is not over an item in the ListBox. dragBoxFromMouseDown = Rectangle.Empty; } private void dataGridView1_DragOver(object sender, DragEventArgs e) { e.Effect = DragDropEffects.Move; } private void dataGridView1_DragDrop(object sender, DragEventArgs e) { // The mouse locations are relative to the screen, so they must be // converted to client coordinates. Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y)); // Get the row index of the item the mouse is below. rowIndexOfItemUnderMouseToDrop = dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex; var movable = _workflowList.Operations[rowIndexFromMouseDown]; _workflowList.Operations.RemoveAt(rowIndexFromMouseDown); if (rowIndexOfItemUnderMouseToDrop == -1) rowIndexOfItemUnderMouseToDrop = _workflowList.Operations.Count; _workflowList.Operations.Insert(rowIndexOfItemUnderMouseToDrop, movable); dataGridView1.ClearSelection(); RefreshWorkflow(); dataGridView1.Rows[rowIndexOfItemUnderMouseToDrop].Selected = true; ProcessRowSelection(); } } }