using System; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reactive; using System.Reactive.Linq; using System.Threading.Tasks; using Intromat.PersistentModel; using Intromat.ViewModels.Nodes; using Intromat.ViewModels.Previews; using NodeNetwork.Toolkit.Group; using NodeNetwork.Toolkit.NodeList; using ReactiveUI; namespace Intromat.ViewModels { public class MainViewModel : ReactiveObject { private ProjectViewModel _project; private FileViewModel? _activeFile; private object? _propertiesContext; private DxTexturePreviewViewModel? _preview2dContext; private DxMeshPreviewViewModel? _preview3dContext; public MainViewModel() { AppState = ((AppStateViewModel)RxApp.SuspensionHost.AppState!)!; Explorer = new(this); var desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); var initialProjectPath = Path.Combine(desktopPath, "Project1", "Project1.iproj"); if (File.Exists(initialProjectPath)) { _project = Task.Run(() => ProjectSerializer.LoadProject(this, initialProjectPath)).GetAwaiter().GetResult()!; } else { _project = ProjectViewModel.CreateDefault(this, initialProjectPath, "Project1"); } foreach (var nodeType in typeof(CodeGenNodeViewModel).Assembly.ExportedTypes.Where(t => typeof(CodeGenNodeViewModel).IsAssignableFrom(t) && !t.IsAbstract)) { if (nodeType.Namespace == $"{nameof(Intromat)}.{nameof(Nodes)}") continue; NodeList.AddNodeType(() => (CodeGenNodeViewModel)Activator.CreateInstance(nodeType)!); } Grouper = new NodeGrouper { GroupNodeFactory = subnet => new GroupNodeViewModel { Name = "Group", Subnet = (CodeGenNetworkViewModel)subnet }, EntranceNodeFactory = () => new GroupSubnetIONodeViewModel { IsEntranceNode = true }, ExitNodeFactory = () => new GroupSubnetIONodeViewModel { IsEntranceNode = false }, SubNetworkFactory = parentNet => { var subNetwork = new CodeGenNetworkViewModel(((CodeGenNetworkViewModel)parentNet).Document, "Group") { ParentNetwork = (CodeGenNetworkViewModel)parentNet }; return subNetwork; }, IOBindingFactory = (groupNode, entranceNode, exitNode) => new CodeNodeGroupIOBinding(groupNode, entranceNode, exitNode) }; LoadProject = ReactiveCommand.CreateFromTask(async () => { var file = await OpenProjectFile.Handle(true); if (file == null) return null; var activeFile = ActiveFile; if (activeFile != null) UndoRedo.Purge(activeFile); UndoRedo.Recording = false; try { return await ProjectSerializer.LoadProject(this, file); } catch (Exception) { // ignored, TODO } finally { ActiveFile = null; Files.Clear(); UndoRedo.Recording = true; } return null; }); LoadProject.Where(n => n != null).Subscribe(project => Project = project!); SaveProject = ReactiveCommand.CreateFromTask(async () => { await ProjectSerializer.SaveModel(Project); }); SaveProjectAs = ReactiveCommand.CreateFromTask(() => throw new NotImplementedException()); this.WhenAnyValue(vm => vm.Project).Subscribe(_ => { if (Explorer.TreeRoot.Count == 0) Explorer.TreeRoot.Add(Project); else { Explorer.TreeRoot[0] = Project; } }); this.WhenAnyValue(vm => vm.ActiveFile!.CurrentViewModel).Subscribe(n => PropertiesContext = n); UndoRedo.Recording = true; } public NodeListViewModel NodeList { get; } = new(); public UndoRedoViewModel UndoRedo { get; } = new(); public AppStateViewModel AppState { get; } public ExplorerViewModel Explorer { get; } public ReactiveCommand LoadProject { get; } public ReactiveCommand SaveProject { get; } public ReactiveCommand SaveProjectAs { get; } public Interaction OpenProjectFile { get; } = new(); public Interaction?> SelectTypeAndFileName { get; } = new(); public Interaction SelectName { get; } = new(); public NodeGrouper Grouper { get; } public ProjectViewModel Project { get => _project; set => this.RaiseAndSetIfChanged(ref _project, value); } public ObservableCollection Files { get; } = new(); public FileViewModel? ActiveFile { get => _activeFile; set => this.RaiseAndSetIfChanged(ref _activeFile, value); } public object? PropertiesContext { get => _propertiesContext; set => this.RaiseAndSetIfChanged(ref _propertiesContext, value); } public DxTexturePreviewViewModel? Preview2dContext { get => _preview2dContext; set => this.RaiseAndSetIfChanged(ref _preview2dContext, value); } public DxMeshPreviewViewModel? Preview3dContext { get => _preview3dContext; set => this.RaiseAndSetIfChanged(ref _preview3dContext, value); } } }