using System.Reflection; using Hawkeye.VisionBuilder.Features.ImagePreview; using Hawkeye.VisionBuilder.Features.VisionSteps; using Hawkeye.VisionBuilder.Panels; using Hawkeye.VisionBuilder.Workflow; using Hawkeye.VisionBuilder.Workflow.Datatypes; using Hawkeye.VisionBuilder.Workflow.Links; using Hawkeye.VisionBuilder.Workflow.Operations.Attributes; using Hawkeye.VisionBuilder.Workflow.Operations.Filters; using Rectangle = Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Rectangle.RectangleElement; namespace Hawkeye.VisionBuilder.Features.ToolEditor { public partial class ToolConfigurationPanel : BasePannel { private readonly WorkflowList _workflowList; private readonly VisionStepsPanel _visionStepsPanel; private BaseOperation _selectedOperation; private Dictionary _parameters; public ToolConfigurationPanel(WorkflowList workflowList,VisionStepsPanel visionStepsPanel) { _workflowList = workflowList; _visionStepsPanel = visionStepsPanel; InitializeComponent(); } public void SetOperation(BaseOperation operation) { _selectedOperation=operation; panel2.Enabled=false; //todo: generate header var parameters = operation.GetParameters(); _parameters=parameters; this.flowLayoutPanel1.Controls.Clear(); foreach (var p in parameters) { GenerateParameterField(parameters,p.Key, operation); } } private void GenerateParameterField(Dictionary toolParameter, string pKey, BaseOperation operation) { var value = toolParameter[pKey]; if (value is int i) { var control = new NumericUpDown() { Minimum = -99999999, Maximum = 99999999, Value = i, }; control.TextChanged += (sender, args) => { panel2.Enabled = true; TriggerChanged(); }; control.ValueChanged += (sender, args) => { toolParameter[pKey] = ((int) control.Value); panel2.Enabled = true; TriggerChanged(); }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); }else if (value is double d) { var control = new NumericUpDown() { Minimum = -99999999, Maximum = 99999999, Value = (decimal)d, Increment = (decimal)0.1, DecimalPlaces = 2}; control.TextChanged += (sender, args) => { panel2.Enabled = true; TriggerChanged(); }; control.ValueChanged += (sender, args) => { toolParameter[pKey] = ((double) control.Value); panel2.Enabled = true; TriggerChanged(); }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); }else if (value is string s) { var control = new TextBox() { Text = s }; control.TextChanged += (sender, args) => { toolParameter[pKey] = (control.Text); panel2.Enabled = true; TriggerChanged(); }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); } else if (value is FilePath filePath) { var control = new Button() { Text = filePath.Path, }; control.Click += (sender, args) => { OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = filePath.Format; dialog.FileName = filePath.Path; if (dialog.ShowDialog() == DialogResult.OK) { control.Text = dialog.FileName; filePath.Path = MakeRelative(dialog.FileName,Environment.CurrentDirectory); control.Text = filePath.Path; panel2.Enabled = true; TriggerChanged(); } }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); } else if (value is SelectFromList selectFromList) { var control = new ComboBox() { DropDownStyle = ComboBoxStyle.DropDownList }; control.Items.AddRange(selectFromList.GetList().ToArray()); control.SelectedItem = selectFromList.Value; control.SelectedIndexChanged += (sender, args) => { selectFromList.Value = (control.SelectedItem as string); panel2.Enabled = true; TriggerChanged(); }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); } else if (value is ScriptValue scriptValue) { var control = new TextBox() { Text = scriptValue.Script }; control.TextChanged += (sender, args) => { scriptValue.Script = (control.Text); panel2.Enabled = true; TriggerChanged(); }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); var cc = new CodeCompletionControl(control); cc.NeedSugestions += Cc_NeedSugestions; } else if (value is bool b) { var control = new CheckBox() { Checked = b }; control.CheckedChanged += (sender, args) => { toolParameter[pKey] = (control.Checked); panel2.Enabled = true; TriggerChanged(); }; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); } if (value is Guid refId && pKey.StartsWith("Reference")) { var control = new ComboBox() { DropDownStyle = ComboBoxStyle.DropDownList }; control.SelectedIndexChanged += (sender, args) => { toolParameter[pKey] = ((control.SelectedItem)as BaseOperation)?.Id??NoOrigin.Instance.Id; panel2.Enabled = true; TriggerChanged(); }; var candidates = _workflowList.Operations.TakeWhile(x=> x.Id != operation.Id); control.Items.Add(NoOrigin.Instance); if (pKey.Contains("Edge")) { control.Items.AddRange(candidates.Where(x => x is IHaveEdge).Select(x => x as IHaveEdge).ToArray()); } else { control.Items.AddRange(candidates.Where(x => x is IHaveOrigin ).Select(x => x as IHaveOrigin).ToArray()); } control.DisplayMember = nameof(BaseOperation.Label); control.SelectedItem = candidates.FirstOrDefault(x=>x.Id==refId)?? NoOrigin.Instance; var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); } else if(value is Action a) { var control = new Button() { Text = "Execute" }; control.Click += (sender, args) => a(); var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control); row.Width = flowLayoutPanel1.Width - 50; this.flowLayoutPanel1.Controls.Add(row); } } private static string MakeRelative(string path, string basePath) { var uri = new Uri(path); var baseUri = new Uri(basePath); // if path can't be made relative if (baseUri.Scheme != uri.Scheme) { return path; } var res= baseUri.MakeRelativeUri(uri).ToString(); // ensure windows path separator return "..\\"+res.Replace("/", "\\"); } private void Cc_NeedSugestions(string input, List suggestions) { var start = input.IndexOf("."); if (start == -1) { suggestions.AddRange(_workflowList.Operations.Select(x => x.Label).Where(x=>x.StartsWith(input))); suggestions.Add("config"); return; } var word = input.Substring(0, start); if (word == "config") { GenerateSugestions(input.Substring(start + 1), _workflowList.Configuration, suggestions); return; } var o = _workflowList.Operations.FirstOrDefault(x => x.Label == word); if (o!=null) { GenerateSugestions(input.Substring(start + 1), o, suggestions); } } private IEnumerable GetAllowedProperties(Type type) { return type.GetProperties().Where(x => x.GetCustomAttribute() == null); } private void GenerateSugestions(string input, object o, List suggestions) { var start = input.IndexOf("."); if (start == -1) { var props = GetAllowedProperties(o.GetType()).Where(x => x.Name.StartsWith(input)).ToList(); props.ForEach(x => suggestions.Add(x.Name)); } else { var word = input.Substring(0, start); var prop = GetAllowedProperties(o.GetType()).FirstOrDefault(x => x.Name == word); if (prop != null) { GenerateSugestions(input.Substring(start + 1), prop.GetValue(o), suggestions); } } } private void TriggerChanged() { if(cbAutoApply.Checked) btnOk_Click(null,null); } private void btnOk_Click(object sender, EventArgs e) { _selectedOperation.SetParameters(_parameters); SetOperation(_selectedOperation); _workflowList.ExecuteTill(_selectedOperation); _workflowList.ExecuteOne(_selectedOperation); _visionStepsPanel.UpdateView(); } private void btnCancel_Click(object sender, EventArgs e) { SetOperation(_selectedOperation); } } }