livia-test/Livia/ViewModels/RoiExpanderControlViewModel.cs
2025-03-28 14:31:53 +08:00

331 lines
12 KiB
C#

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<TwoColumnModeToggleMessage>, IRecipient<LocationDisplayModeToggleMessage>, IRecipient<UnfoldToggleMessage>,
IRecipient<RoiExpanderToggleMessage>, IRecipient<LocateRoiMessage>, IRecipient<ShowBoundaryToggleMessage>, 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<RoiLocationDataControlViewModel> Locations { get; } = [];
public ObservableCollection<RoiExpanderGroupControlViewModel> SubGroups { get; } = [];
public ObservableCollection<RoiLocationDataControlViewModel> LeftLocations { get; } = [];
public ObservableCollection<RoiLocationDataControlViewModel> RightLocations { get; } = [];
public ObservableCollection<RoiLocationDataControlViewModel> 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<TwoColumnModeToggleMessage>(this);
WeakReferenceMessenger.Default.Register<LocationDisplayModeToggleMessage>(this);
WeakReferenceMessenger.Default.Register<UnfoldToggleMessage>(this);
WeakReferenceMessenger.Default.Register<RoiExpanderToggleMessage>(this);
WeakReferenceMessenger.Default.Register<LocateRoiMessage>(this);
WeakReferenceMessenger.Default.Register<ShowBoundaryToggleMessage>(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<RoiLocationDataControlViewModel> 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<string> 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<RoiExpanderGroupControlViewModel>(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<string, ConcurrentBag<RoiExpanderControlViewModel>> dictionary = _dataBlockLoader.GetSharedData<Dictionary<string, ConcurrentBag<RoiExpanderControlViewModel>>>("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);
}
}