using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.IO; using System.Windows.Media; using System.Windows.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; using Livia.Models; using Livia.Models.Data; using Livia.Utility; using Livia.Utility.DependencyInjection; using Livia.ViewModels.Utility; using Livia.Views.Utility; using Microsoft.Extensions.DependencyInjection; namespace Livia.ViewModels; public class RoiExpanderControlViewModel : ObservableRecipient, ILiviaModuleViewModel, IRecipient, IRecipient, IRecipient, IRecipient, IRecipient, IRecipient, ISelectableItem { public const int BlinkTime = 3000; public bool IsChecked { get => _checked; set { SetProperty(ref _checked, value); WeakReferenceMessenger.Default.Send(new RoiExpanderToggleMessage(Name, value)); } } public string Name { get => _name; private set => SetProperty(ref _name, value); } public bool NoLocationData => RoiData.Locations.Count == 0; public bool ShowButtons => SubGroups.Count == 0 && !NoLocationData; public float Volume { get => _volume; private set => SetProperty(ref _volume, value); } public SolidColorBrush Color { get => _color; set => SetProperty(ref _color, value); } public bool IsTwoSided { get; } public bool TwoColumnMode { get => _twoColumnMode; set => SetProperty(ref _twoColumnMode, value); } public bool UnfoldButtonState { get => _unfoldButtonState; set => SetProperty(ref _unfoldButtonState, value); } public RoiLocationDisplayMode CurrentRoiLocationDisplayMode { get => _currentRoiLocationDisplayMode; set => SetProperty(ref _currentRoiLocationDisplayMode, value); } public RoiData RoiData { get; set; } public int ZIndex { get; set; } public ObservableCollection Locations { get; } = []; public ObservableCollection SubGroups { get; } = []; public ObservableCollection LeftLocations { get; } = []; public ObservableCollection RightLocations { get; } = []; public ObservableCollection TwoSideLocations { get; } = []; public IImageSeries MaskImageSeries { get; } = new Dicom3DImageSeries(); public BitmapImage? MosaicMask { get; private set; } public bool IsBlinking { get => _isBlinking; set => SetProperty(ref _isBlinking, value); } public bool OtherIsBlinking { get => _otherIsBlinking; set => SetProperty(ref _otherIsBlinking, value); } public string RoiTabId { get; set; } = string.Empty; private string _name = string.Empty; private float _volume; private bool _checked = true; private bool _twoColumnMode; private bool _unfoldButtonState; private SolidColorBrush _color = new(Colors.White); private RoiLocationDisplayMode _currentRoiLocationDisplayMode = RoiLocationDisplayMode.Volume; //default to volume private bool _isBlinking; private bool _otherIsBlinking; private readonly IRoiLegendManager _roiLegendManager; private readonly IDataBlockLoader _dataBlockLoader; private readonly IWarningSystem _warningSystem; private static readonly object DictionaryInsertLock = new(); public RoiExpanderControlViewModel(bool isTwoSided, IRoiLegendManager roiLegendManager, IDataBlockLoader dataBlockLoader, IWarningSystem warningSystem) { IsTwoSided = isTwoSided; _roiLegendManager = roiLegendManager; _dataBlockLoader = dataBlockLoader; _warningSystem = warningSystem; MaskImageSeries.IsMask = true; //only two-sided column cares about this if (isTwoSided) WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); } public void ToggleUnfold() { WeakReferenceMessenger.Default.Send(new UnfoldToggleMessage(!UnfoldButtonState)); } public void ToggleRoiLocationsDisplayMode() { WeakReferenceMessenger.Default.Send(new LocationDisplayModeToggleMessage((RoiLocationDisplayMode)(((int)CurrentRoiLocationDisplayMode + 1) % Enum.GetNames(typeof(RoiLocationDisplayMode)).Length))); } public void ToggleTwoColumnMode() { WeakReferenceMessenger.Default.Send(new TwoColumnModeToggleMessage(!TwoColumnMode)); } private IEnumerable GetAllLocations() { foreach (RoiLocationDataControlViewModel viewModel in Locations) { yield return viewModel; } foreach (RoiLocationDataControlViewModel viewModel in LeftLocations) { yield return viewModel; } foreach (RoiLocationDataControlViewModel viewModel in RightLocations) { yield return viewModel; } foreach (RoiLocationDataControlViewModel viewModel in TwoSideLocations) { yield return viewModel; } } public void Receive(UnfoldToggleMessage message) { UnfoldButtonState = message.Value; foreach (RoiLocationDataControlViewModel viewModel in GetAllLocations()) { viewModel.IsExpanded = message.Value; } } public void Receive(TwoColumnModeToggleMessage message) { TwoColumnMode = message.Value; } public void Receive(LocationDisplayModeToggleMessage message) { CurrentRoiLocationDisplayMode = message.Value; foreach (RoiLocationDataControlViewModel viewModel in GetAllLocations()) { viewModel.UpdateDisplayString(message.Value); } } public void Receive(RoiExpanderToggleMessage message) { if (SubGroups.SelectMany(group => group.RoiViewModelCollection.Items).Select(vm => vm.Name).Contains(message.Value.Item1)) { Volume = SubGroups.Select(vm => vm.SelectedVolume).Sum(); } //if (Name != message.Value.Item1) // return; //if (IsChecked == message.Value.Item2) // return; //IsChecked = message.Value.Item2; } public ReportModulesRoiData GenerateModulesRoiData() { List unfoldList = new(); //TODO::this is disabled for now. Will cause error in server. //if (TwoColumnMode) //{ // unfoldList = (from roiLocationDataControlViewModel in TwoSideLocations // where roiLocationDataControlViewModel.IsExpanded // select roiLocationDataControlViewModel.Name).ToList(); // unfoldList.AddRange(from roiLocationDataControlViewModel in LeftLocations // where roiLocationDataControlViewModel.IsExpanded // select roiLocationDataControlViewModel.Name); // unfoldList.AddRange(from roiLocationDataControlViewModel in RightLocations // where roiLocationDataControlViewModel.IsExpanded // select roiLocationDataControlViewModel.Name); //} //else //{ // unfoldList = (from roiLocationDataControlViewModel in Locations // where roiLocationDataControlViewModel.IsExpanded // select roiLocationDataControlViewModel.Name).ToList(); //} ReportModulesRoiData result = new() { Name = RoiData.FileName, Unfold = unfoldList }; return result; } public async Task LoadData(DataBlock dataBlock) { Volume = RoiData.Volume; Name = LiviaUtility.ParseServerString(RoiData.Name); //load sub groups if (RoiData.SubGroups != null) { foreach (RoiGroup roiGroup in RoiData.SubGroups) { Color color = (Color)ColorConverter.ConvertFromString(roiGroup.Color); if (RoiSummaryControlViewModel.RoiTabIdToTabIndexDictionary == null || !RoiSummaryControlViewModel.RoiTabIdToTabIndexDictionary.TryGetValue(RoiTabId, out int tabIndex)) continue; _roiLegendManager.AddItem(tabIndex, roiGroup.Id, roiGroup.Name, roiGroup.FullName, color); if (roiGroup.Regions.Count == 0) continue; RoiExpanderGroupControlViewModel viewModel = ActivatorUtilities.CreateInstance(ServiceProviderFactory.ServiceProvider, roiGroup.Name, roiGroup.Id, color, IsTwoSided); viewModel.RoiTabId = RoiTabId; viewModel.Regions = roiGroup.Regions; viewModel.ShowHeader = false; await viewModel.LoadData(dataBlock); SubGroups.Add(viewModel); } Volume = SubGroups.Select(vm => vm.SelectedVolume).Sum(); } else { //add data to list according to their side foreach (LocationData locationInfo in RoiData.Locations) { Locations.Add(new RoiLocationDataControlViewModel(locationInfo)); if (!IsTwoSided) continue; if (locationInfo.Name.Contains("_左")) { LeftLocations.Add(new RoiLocationDataControlViewModel(locationInfo)); } else if (locationInfo.Name.Contains("_右")) { RightLocations.Add(new RoiLocationDataControlViewModel(locationInfo)); } else { TwoSideLocations.Add(new RoiLocationDataControlViewModel(locationInfo)); } } } if (RoiData.Mask != null) { await MaskImageSeries.LoadData(Path.Combine(dataBlock.ResultPath, "mosaic", RoiData.Mask)); //save to dictionary if (!string.IsNullOrEmpty(RoiTabId)) { Dictionary> dictionary = _dataBlockLoader.GetSharedData>>("roiCollection"); lock (DictionaryInsertLock) { dictionary.AddToCollectionWithKey(RoiTabId, this); } } } if (RoiData.MosaicMask != null) { MosaicMask = await LiviaUtility.LoadBitmapAsync(Path.Combine(dataBlock.ResultPath, "mosaic", RoiData.MosaicMask)); } } public void Init() { } public void Receive(LocateRoiMessage message) { if (message.Value == this) { if (MaskImageSeries.MaskJumpToIndex is null or < 0) { _warningSystem.ShowDialog(WarningWindowKind.Warning, false, "UnableToLocateRegionWarning"); return; } IsChecked = true; WeakReferenceMessenger.Default.Send(new ImageRotationViewerIndexChangeMessage("structure", MaskImageSeries.MaskJumpToIndex.Value + 1)); IsBlinking = true; Task.Run(async () => { await Task.Delay(BlinkTime); IsBlinking = false; }); } else { //hide all other images to see better OtherIsBlinking = true; Task.Run(async () => { await Task.Delay(BlinkTime); OtherIsBlinking = false; }); } } public void ToggleShowBoundary() { WeakReferenceMessenger.Default.Send(new ShowBoundaryToggleMessage(!MaskImageSeries.ShowBoundary)); } public void Receive(ShowBoundaryToggleMessage message) { MaskImageSeries.ShowBoundary = message.Value; } public void ClearData() { foreach (RoiExpanderGroupControlViewModel viewModel in SubGroups) { viewModel.ClearData(); } MaskImageSeries.Dispose(); MosaicMask = null; WeakReferenceMessenger.Default.UnregisterAll(this); } }