/* * Copyright (c) 2025 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora.Api; using VisionCommon; using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using VisionCommonUI; using VisionCommonUI.Resources; using Aurora.View; using System.Security.Cryptography; namespace VisionUI.Pattern { /// /// 패턴 콤보박스 정보 키 /// public class PatternCbInfoKey { /// Fov Id public eFovId FovId { get; set; } /// Proc 패턴 Id public eProcPatternId ProcPatternId { get; set; } /// /// 생성자 /// /// Fov Id /// Proc 패턴 Id public PatternCbInfoKey(eFovId fovId, eProcPatternId procPatternId) { this.FovId = fovId; this.ProcPatternId = procPatternId; } } /// /// 패턴 콤보박스 정보 값 /// public class PatternCbInfoValue { /// 패턴 이름 public string PatternName { get; set; } /// 패턴 콤보박스 public ComboBox PatternComboBox { get; set; } /// /// 생성자 /// /// 패턴이름 /// 패턴 콤보박스 public PatternCbInfoValue(string patternName, ComboBox patternComboBox) { this.PatternName = patternName; this.PatternComboBox = patternComboBox; } } /// /// 패턴 리스트에 등록된 패턴을 공정 패턴으로 지정 /// public partial class ProcPatternSettingView : UserControl { private const string PATTERN_UNDEFINED = "Undefined"; private Logger _Logger; private SubSysInfo _SubSysInfo; private SubSysRecipe _SubSysRecipe; private Dictionary _PatternCbInfos = new Dictionary(); private Dictionary> _PatternIndexesAll = new Dictionary>(); private string _ProcId; /// /// 생성자 /// /// 서브시스템 정보 /// Proc Id public ProcPatternSettingView(SubSysInfo subSysInfo, string procId) { _Logger = new Logger(typeof(ProcPatternSettingView).Name); _SubSysInfo = subSysInfo; _SubSysRecipe = VisionRecipeManager.GetSubSysRecipe(_SubSysInfo); _ProcId = procId; InitializeComponent(); CreateViews(); } //public ProcPatternSettingView() { // _Logger = new Logger(typeof(ProcPatternSettingView).Name); // InitializeComponent(); //} ///// ///// 초기 생성 후 한번만 설정 해 줄 것 ///// ///// ///// //public void InitView(SubSysInfo subSysInfo, string procId) { // _SubSysInfo = subSysInfo; // _SubSysRecipe = VisionRecipeManager.GetSubSysRecipe(_SubSysInfo); // _FovPatternAgent = FovPatternAgentManager.GetAgent(_SubSysInfo); // _ProcId = procId; // CreateViews(); //} private void CreateViews() { gridProcPatterns.Children.Add(CreateProcPatternScrollView()); } /// /// ProcPatternSettingView를 새로고침 /// /// 서브시스템 정보 /// Proc Id public void RefreshViews(SubSysInfo subSysInfo, string procId) { // Align View에서 저장 시 PrcPatternSettingView를 새로고침한다. _SubSysInfo = subSysInfo; _SubSysRecipe = VisionRecipeManager.GetSubSysRecipe(_SubSysInfo); _ProcId = procId; gridProcPatterns.Children.Clear(); _PatternCbInfos.Clear(); CreateViews(); InitPatternItemsList(); } private ProcPatternInfo CreateNewProcPatternInfo(eFovId fovId, int cnt) { var procPatternInfo = new ProcPatternInfo(); procPatternInfo.ProcId = _ProcId; if (cnt == 1) { procPatternInfo.ProcPatternId = eProcPatternId.ProcPattern1; procPatternInfo.PatternName = fovId.ToString() + "_" + _ProcId.ToString() + "_" + "Proc1"; } else if (cnt == 2) { procPatternInfo.ProcPatternId = eProcPatternId.ProcPattern2; procPatternInfo.PatternName = fovId.ToString() + "_" + _ProcId.ToString() + "_" + "Proc2"; } return procPatternInfo; } private ScrollViewer CreateProcPatternScrollView() { var scrollViewer = new ScrollViewer(); scrollViewer.Visibility = Visibility.Visible; scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; scrollViewer.CanContentScroll = true; scrollViewer.Margin = new Thickness(5); StackPanel spOtherFov = new StackPanel(); spOtherFov.Orientation = Orientation.Vertical; try { // Align Subsystem의 경우 ProcId를 통해 어떤 Align의 ProcPattern을 가져와야 하는지 파악한다. var alignRecipe = new AlignRecipe(); foreach (var recipe in _SubSysRecipe.AlignRecipes) { // Inspect Subsystem의 경우에는 Align1의 ProcFovType을 가져오도록 한다. if (_ProcId == "Inspect") { if (recipe.AlignId == eAlignId.Align1) { alignRecipe = recipe; } } else if (recipe.AlignId.ToString().Equals(_ProcId)) { alignRecipe = recipe; } } foreach (FovRecipe fovRecipe in _SubSysRecipe.FovRecipes) { eFovId fovId = fovRecipe.FovId; //ProcFovType을 보고 필요한 Fov만 보이도록 한다. if (ProcParams.GetFovNum(alignRecipe.ProcParams.ProcFovType) <= (int)fovId) { continue; } StackPanel spSameFov = new StackPanel(); spSameFov.Orientation = Orientation.Vertical; if (fovRecipe.PatternRecipe.ProcPatternInfos.Count > 0) { bool checkProcPattern1 = false; foreach (var procPatternInfo in fovRecipe.PatternRecipe.ProcPatternInfos) { if (procPatternInfo.ProcPatternId == eProcPatternId.ProcPattern1 && procPatternInfo.ProcId.Equals(_ProcId)) { AddNewCb(procPatternInfo, fovId, spSameFov); checkProcPattern1 = true; } } // ProcPatternInfos에 해당 ProcPatternInfo가 없으면 만들어준다. if (!checkProcPattern1) { var procPatternInfo = CreateNewProcPatternInfo(fovId, 1); fovRecipe.PatternRecipe.ProcPatternInfos.Add(procPatternInfo); AddNewCb(procPatternInfo, fovId, spSameFov); } // Align의 종류가 하나의 Fov에서 여러개의 패턴을 가져와야 하는 경우 ProcPattern을 더 가져온다. if (alignRecipe.ProcParams.ProcFovType == eProcFovType.C1_F1_M2R || alignRecipe.ProcParams.ProcFovType == eProcFovType.C1_F1_AP2_A2 || _SubSysRecipe.SubSysType == eSubSysType.Inspect) { bool checkProcPattern2 = false; foreach (var procPatternInfo in fovRecipe.PatternRecipe.ProcPatternInfos) { if (procPatternInfo.ProcPatternId == eProcPatternId.ProcPattern2 && procPatternInfo.ProcId.Equals(_ProcId)) { AddNewCb(procPatternInfo, fovId, spSameFov); checkProcPattern2 = true; } } // ProcPatternInfos에 해당 ProcPatternInfo가 없으면 만들어준다. if (!checkProcPattern2) { var procPatternInfo = CreateNewProcPatternInfo(fovId, 2); fovRecipe.PatternRecipe.ProcPatternInfos.Add(procPatternInfo); AddNewCb(procPatternInfo, fovId, spSameFov); } } } // PatternRecipe에 ProcPatternInfos가 비어있는 경우에는 바로 ProcPatternInfo를 만들어준다 else { var procPatternInfo = CreateNewProcPatternInfo(fovId, 1); fovRecipe.PatternRecipe.ProcPatternInfos.Add(procPatternInfo); AddNewCb(procPatternInfo, fovId, spSameFov); if (alignRecipe.ProcParams.ProcFovType == eProcFovType.C1_F1_M2R || alignRecipe.ProcParams.ProcFovType == eProcFovType.C1_F1_AP2_A2 || _SubSysRecipe.SubSysType == eSubSysType.Inspect) { procPatternInfo = CreateNewProcPatternInfo(fovId, 2); fovRecipe.PatternRecipe.ProcPatternInfos.Add(procPatternInfo); AddNewCb(procPatternInfo, fovId, spSameFov); } } spOtherFov.Children.Add(spSameFov); } } catch (Exception e) { _Logger.FuncE(e.Message); } scrollViewer.Content = spOtherFov; return scrollViewer; } private void AddNewCb(ProcPatternInfo procPatternInfo, eFovId fovId, StackPanel spSameFov) { var spSameFovInside = new StackPanel(); spSameFovInside.Orientation = Orientation.Horizontal; spSameFovInside.Margin = new Thickness(5, 3, 5, 3); TextBlock tbPatternName = GetPatternName(procPatternInfo.PatternName); tbPatternName.TextAlignment = TextAlignment.Left; //tbPatternName.Width = 130; //tbPatternName.Width = 155; spSameFovInside.Children.Add(tbPatternName); ComboBox cbPattern = new ComboBox(); spSameFovInside.Children.Add(cbPattern); SetPatternCbInfos(fovId, procPatternInfo, cbPattern); spSameFov.Children.Add(spSameFovInside); } private TextBlock GetPatternName(string patternName) { var tbPatternName = new TextBlock(); tbPatternName.FontSize = 13; tbPatternName.Style = FindResource("styleTextBlockSubTitleSmall") as Style; tbPatternName.Margin = new Thickness(5, 5, 15, 5); tbPatternName.HorizontalAlignment = HorizontalAlignment.Left; tbPatternName.Text = patternName; return tbPatternName; } private void SetPatternCbInfos(eFovId fovId, ProcPatternInfo procPatternInfo, ComboBox patternComboBox) { var infoKey = new PatternCbInfoKey(fovId, procPatternInfo.ProcPatternId); if (!_PatternCbInfos.ContainsKey(infoKey)) { _PatternCbInfos.Add(infoKey, new PatternCbInfoValue(procPatternInfo.PatternName, patternComboBox)); } } private void InitPatternItemsList() { try { foreach (var key in _PatternCbInfos.Keys.Select((value, index) => (value, index))) { PatternCbInfoKey infoKey = key.value; var index = key.index; AddComboBoxItems(infoKey); SelectComboBoxItem(infoKey, index); } } catch (Exception e) { _Logger.FuncE(e.Message); } } // 콤보박스 항목 추가 private void AddComboBoxItems(PatternCbInfoKey infoKey) { try { ComboBox cb = _PatternCbInfos[infoKey].PatternComboBox; cb.Items.Clear(); var fovInfo = VisionRecipeManager.GetFovInfo(_SubSysInfo.UnitId, _SubSysInfo.SubSysId, infoKey.FovId); var fovRecipe = VisionRecipeManager.GetFovRecipe(_SubSysInfo.UnitId, _SubSysInfo.SubSysId, infoKey.FovId); var patternAgent = PatternAgentManager.GetAgent(fovInfo); if (VisionSettingManager.VisionSetting.UseCamPattern) { // CamPattern을 사용하는 경우에는 Pattern Agent들마다 동기화를 해줘야 하므로 패턴을 다시 불러온다. patternAgent.LoadPatterns(); } var fovPatternInfos = patternAgent.GetMainPatterns(_SubSysInfo, infoKey.FovId); List patternIndexes = new List(); for (int i = 0; i < fovPatternInfos.Count; i++) { patternIndexes.Add(new PatternIndex(_SubSysInfo, fovRecipe.FovId, fovPatternInfos[i].GetPatternId())); cb.Items.Add(PatternUtil.GetPatternDescription(fovPatternInfos[i])); } if (!_PatternIndexesAll.ContainsKey(infoKey)) { _PatternIndexesAll.Add(infoKey, patternIndexes); } else { _PatternIndexesAll[infoKey] = patternIndexes; } } catch (Exception e) { _Logger.FuncE(e.Message); } } // 콤보박스 항목 선택 private void SelectComboBoxItem(PatternCbInfoKey infoKey, int index) { try { var procPatternInfos = _SubSysRecipe.FovRecipes[(int)infoKey.FovId].PatternRecipe.ProcPatternInfos; var procPatternInfo = procPatternInfos.Where(p => p.ProcPatternId.Equals(infoKey.ProcPatternId) && p.ProcId.Equals(_ProcId)).FirstOrDefault().Clone(); for (int i = 0; i < _PatternIndexesAll[infoKey].Count(); i++) { if (_PatternIndexesAll[infoKey][i].PatternId == procPatternInfo.PatternId) { _PatternCbInfos[infoKey].PatternComboBox.SelectedIndex = i; } } } catch (NullReferenceException e) { MessageUtil.ShowErrorToast($"[{_SubSysInfo.SubSysId}][{infoKey.FovId}][{infoKey.ProcPatternId}] Not Found in ProcPatternInfos."); _Logger.FuncE(e.Message); } catch (Exception e) { _Logger.FuncE(e.Message); } } private void PrintRecipeError(FovRecipe fovRecipe, StackPanel spSameFov) { var errMsg = string.Format(StrTokens.RecipeErrorMessage, $"PatternRecipe.ProcPatternInfos of {fovRecipe.FovId}"); spSameFov.Children.Add(new UCRecipeErrorTextBlock(errMsg) { Margin = new Thickness(5), HorizontalContentAlignment = HorizontalAlignment.Left }); ; } private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { bool isVisible = (bool)e.NewValue; if (isVisible == true) { RefreshVisionRecipes(); InitPatternItemsList(); } } /// /// 비전 레시피 Refresh /// public void RefreshVisionRecipes() { _SubSysRecipe = VisionRecipeManager.GetSubSysRecipe(_SubSysInfo); } /// /// UI로 부터 레시피 업데이트 /// public void UpdateRecipeFromUI() { try { foreach (var key in _PatternCbInfos.Keys.Select((value, index) => (value, index))) { PatternCbInfoKey infoKey = key.value; var patternRecipe = VisionRecipeManager.GetPatternRecipe(_SubSysInfo, infoKey.FovId); var procPatternInfos = patternRecipe.ProcPatternInfos; var procPatternInfo = procPatternInfos.Where(p => p.ProcPatternId.Equals(infoKey.ProcPatternId) && p.ProcId.Equals(_ProcId)).FirstOrDefault(); if (_PatternCbInfos[infoKey].PatternName == procPatternInfo.PatternName) { int cbSelectedIdx = _PatternCbInfos[infoKey].PatternComboBox.SelectedIndex; if (!_PatternIndexesAll.ContainsKey(infoKey) || _PatternIndexesAll[infoKey].Count <= cbSelectedIdx) { AddComboBoxItems(infoKey); } List patternIndexes = _PatternIndexesAll[infoKey]; PatternIndex patternIndex = patternIndexes[cbSelectedIdx]; procPatternInfo.PatternId = patternIndex.PatternId; if (VisionSettingManager.VisionSetting.UseCamPattern) { procPatternInfo.IsFovPattern = false; } else { procPatternInfo.IsFovPattern = true; } } } InitPatternItemsList(); } catch (Exception e) { _Logger.FuncE(e.Message); } } } }