using AIStudio.Wpf.DiagramApp.Views; using AIStudio.Wpf.Flowchart; using AIStudio.Wpf.Logical; using ControlzEx.Theming; using Dragablz; using Fluent; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reactive.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Media; using AIStudio.Wpf.DiagramDesigner; using AIStudio.Wpf.DiagramDesigner.Additionals; using AIStudio.Wpf.DiagramDesigner.Additionals.Commands; using AIStudio.Wpf.DiagramDesigner.ViewModels; using AIStudio.Wpf.DiagramDesigner.ViewModels.BaseViewModel; using AIStudio.Wpf.Mind; using AIStudio.Wpf.Mind.Models; using ControlzEx.Controls; namespace AIStudio.Wpf.DiagramApp.ViewModels { public class MainWindowViewModel : BindableBase { private IDiagramServiceProvider _service { get { return DiagramServicesProvider.Instance.Provider; } } private string _history = System.AppDomain.CurrentDomain.BaseDirectory + "history.json"; public MainWindowViewModel() { ToolBoxViewModel = new ToolBoxViewModel(this); PageViewModels = new ObservableCollection(); PageViewModels.Add(new PageViewModel("新建-1", "*", DiagramType.Normal)); PageViewModel = PageViewModels.FirstOrDefault(); StandardColor = GenerateStandardGradients(); if (File.Exists(_history)) { HistoryList = JsonConvert.DeserializeObject>(File.ReadAllText(_history)); } else { HistoryList = new ObservableCollection(); } _service.PropertyChanged += Provider_PropertyChanged; } #region 属性 public ToolBoxViewModel ToolBoxViewModel { get; private set; } private ObservableCollection _pageViewModels; public ObservableCollection PageViewModels { get { return _pageViewModels; } set { SetProperty(ref _pageViewModels, value); } } private PageViewModel _pageViewModel; public PageViewModel PageViewModel { get { return _pageViewModel; } set { if (SetProperty(ref _pageViewModel, value)) { } } } private Models.ColorType _colorType; public Models.ColorType ColorType { get { return _colorType; } set { SetProperty(ref _colorType, value); } } private bool _isOpenBackstage; public bool IsOpenBackstage { get { return _isOpenBackstage; } set { SetProperty(ref _isOpenBackstage, value); } } private ObservableCollection _historyList; public ObservableCollection HistoryList { get { return _historyList; } set { SetProperty(ref _historyList, value); } } public Color[] StandardColor { get; set; } public IDrawModeViewModel DrawModeViewModel { get { return _service.DrawModeViewModel; } } public IFontViewModel FontViewModel { get { return _service.FontViewModel; } } public IColorViewModel ColorViewModel { get { return _service.ColorViewModel; } } public IShapeViewModel ShapeViewModel { get { return _service.ShapeViewModel; } } public IAnimationViewModel AnimationViewModel { get { return _service.AnimationViewModel; } } public IQuickThemeViewModel QuickThemeViewModel { get { return _service.QuickThemeViewModel; } } public ILockObjectViewModel LockObjectViewModel { get { return _service.LockObjectViewModel; } } public SelectableDesignerItemViewModelBase SelectedItemViewModel { get { return _service.SelectedItemViewModel; } } public Color ThemeColor { get => ((SolidColorBrush)Application.Current.Resources["Fluent.Ribbon.Brushes.AccentBaseColorBrush"])?.Color ?? Colors.Pink; set { var solidColorBrush = new SolidColorBrush(value); solidColorBrush.Freeze(); Application.Current.Resources["Fluent.Ribbon.Brushes.AccentBaseColorBrush"] = solidColorBrush; } } public string CurrentBaseColor { get => this.CurrentTheme.BaseColorScheme; set { if (value is null) { return; } ThemeManager.Current.ChangeThemeBaseColor(Application.Current, value); RaisePropertyChanged(nameof(this.CurrentTheme)); } } public Theme CurrentTheme { get => ThemeManager.Current.DetectTheme(Application.Current); set { if (value is null) { return; } ThemeManager.Current.ChangeTheme(Application.Current, value); RaisePropertyChanged(nameof(this.CurrentBaseColor)); } } #endregion public Func NewItemFactory { get { return () => { return new PageViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", DiagramType.Normal); }; } } #region 命令 private ICommand _newCommand; public ICommand NewCommand { get { return this._newCommand ?? (this._newCommand = new DelegateCommand(para => this.New_Executed(para))); } } private ICommand _newMindCommand; public ICommand NewMindCommand { get { return this._newMindCommand ?? (this._newMindCommand = new DelegateCommand(para => this.NewMind_Executed(para))); } } private ICommand _openCommand; public ICommand OpenCommand { get { return this._openCommand ?? (this._openCommand = new DelegateCommand(para => this.OpenExecuted(para))); } } private ICommand _saveCommand; public ICommand SaveCommand { get { return this._saveCommand ?? (this._saveCommand = new CanExecuteDelegateCommand(() => this.SaveExecuted(), () => this.Save_Enable())); } } private ICommand _saveAsCommand; public ICommand SaveAsCommand { get { return this._saveAsCommand ?? (this._saveAsCommand = new CanExecuteDelegateCommand(() => this.SaveAsExecuted(), () => this.Save_Enable())); } } private ICommand _pasteCommand; public ICommand PasteCommand { get { return this._pasteCommand ?? (this._pasteCommand = new CanExecuteDelegateCommand(() => this.PasteExecuted(), () => this.Paste_Enabled())); } } private ICommand _cutCommand; public ICommand CutCommand { get { return this._cutCommand ?? (this._cutCommand = new CanExecuteDelegateCommand(() => this.CutExecuted(), () => this.Cut_Enabled())); } } private ICommand _copyCommand; public ICommand CopyCommand { get { return this._copyCommand ?? (this._copyCommand = new CanExecuteDelegateCommand(() => this.CopyExecuted(), () => Copy_Enabled())); } } private ICommand _exitCommand; public ICommand ExitCommand { get { return this._exitCommand ?? (this._exitCommand = new CanExecuteDelegateCommand(() => this.ExitExecuted())); } } private ICommand _formatCommand; public ICommand FormatCommand { get { return this._formatCommand ?? (this._formatCommand = new CanExecuteDelegateCommand(() => this.FormatExecuted(), () => Format_Enabled())); } } private ICommand _deleteCommand; public ICommand DeleteCommand { get { return this._deleteCommand ?? (this._deleteCommand = new CanExecuteDelegateCommand(() => this.DeleteExecuted(), () => Delete_Enabled())); } } private ICommand _lockCommand; public ICommand LockCommand { get { return this._lockCommand ?? (this._lockCommand = new DelegateCommand(para => this.LockExecuted(para))); } } private ICommand _unlockCommand; public ICommand UnlockCommand { get { return this._unlockCommand ?? (this._unlockCommand = new DelegateCommand(para => this.UnlockExecuted(para))); } } private ICommand _selectedColorCommand; public ICommand SelectedColorCommand { get { return this._selectedColorCommand ?? (this._selectedColorCommand = new DelegateCommand(para => this.SelectedColorExecuted(para))); } } private ICommand _aboutCommand; public ICommand AboutCommand { get { return this._aboutCommand ?? (this._aboutCommand = new DelegateCommand(() => this.AboutExecuted())); } } private ICommand _colorPickerCommand; public ICommand ColorPickerCommand { get { return this._colorPickerCommand ?? (this._colorPickerCommand = new DelegateCommand(() => this.ColorPickerExecuted())); } } private ICommand _screenshotCommand; public ICommand ScreenshotCommand { get { return this._screenshotCommand ?? (this._screenshotCommand = new DelegateCommand(() => this.ScreenshotExecuted())); } } #endregion public ItemActionCallback ClosingTabItemHandler { get { return ClosingTabItemHandlerImpl; } } /// /// Callback to handle tab closing. /// private void ClosingTabItemHandlerImpl(ItemActionCallbackArgs args) { //here's how you can cancel stuff: //args.Cancel(); if (args.DragablzItem.DataContext is PageViewModel viewModel) { viewModel.Dispose(); } } private void Provider_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == nameof(DrawModeViewModel) || e.PropertyName == nameof(FontViewModel) || e.PropertyName == nameof(ColorViewModel) || e.PropertyName == nameof(ShapeViewModel) || e.PropertyName == nameof(AnimationViewModel) || e.PropertyName == nameof(QuickThemeViewModel) || e.PropertyName == nameof(LockObjectViewModel) || e.PropertyName == nameof(SelectedItemViewModel)) { RaisePropertyChanged(e.PropertyName); } if (PageViewModel == null || PageViewModel.DiagramViewModel == null) return; if (sender is IFontViewModel) { PageViewModel.DiagramViewModel.SetFont(sender as IFontViewModel, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } else if (sender is IColorViewModel) { PageViewModel.DiagramViewModel.SetColor(sender as IColorViewModel, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } else if (sender is IShapeViewModel) { PageViewModel.DiagramViewModel.SetSharp(sender as IShapeViewModel, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } else if (sender is IAnimationViewModel) { PageViewModel.DiagramViewModel.SetAnimation(sender as IAnimationViewModel, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } else if (sender is IQuickThemeViewModel) { PageViewModel.DiagramViewModel.SetQuickItem(sender as IQuickThemeViewModel, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } else if (sender is LockObject) { PageViewModel.DiagramViewModel.LockAction(sender as LockObject, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } else if (sender is SelectableDesignerItemViewModelBase designer) { PageViewModel.DiagramViewModel.SetPropertyValue(designer, e.PropertyName, PageViewModel.DiagramViewModel.SelectedItems); } } public bool KeyExecuted(KeyEventArgs e) { var para = e.KeyboardDevice.Modifiers == ModifierKeys.None ? e.Key.ToString() : e.KeyboardDevice.Modifiers.ToString() + "+" + e.Key.ToString(); bool executed = true; switch (para) { case "Control+O": OpenExecuted(); break; case "Control+N": New_Executed(); break; case "Control+S": SaveExecuted(); break; default: executed = false; break; } return executed; } private void OpenExecuted(string para = null) { string filename = string.Empty; if (string.IsNullOrEmpty(para)) { Microsoft.Win32.OpenFileDialog openFile = new Microsoft.Win32.OpenFileDialog(); openFile.Filter = "Designer Files (*.xml;*.json)|*.xml;*.json|All Files (*.*)|*.*"; if (openFile.ShowDialog() == false) { return; } filename = openFile.FileName; } else { filename = para; } var viewmodel = PageViewModels.FirstOrDefault(p => p.FileName == filename); if (viewmodel != null) { PageViewModel = viewmodel; MessageBox.Show("文档已经打开"); return; } var diagram = PageViewModel.OpenFile(filename, Path.GetExtension(filename)); PageViewModel flow; if (diagram.DiagramType == DiagramType.FlowChart) { flow = new FlowchartViewModel(filename, diagram); } else if (diagram.DiagramType == DiagramType.Logical) { flow = new LogicalViewModel(filename, diagram); } else if (diagram.DiagramType == DiagramType.SFC) { flow = new SFCViewModel(filename, diagram); } else if (diagram.DiagramType == DiagramType.Mind) { flow = new MindViewModel(filename, diagram); } else if (diagram.DiagramType == DiagramType.Script) { flow = new ScriptViewModel(filename, diagram); } else if (diagram.DiagramType == DiagramType.Drawing) { flow = new DrawingViewModel(filename, diagram); } else if (diagram.DiagramType == DiagramType.Block) { flow = new BlockViewModel(filename, diagram); } else { flow = new PageViewModel(filename, diagram); } PageViewModels.Add(flow); PageViewModel = flow; if (string.IsNullOrEmpty(para)) { SaveHistory(PageViewModel); } else { IsOpenBackstage = false; } } private void SaveExecuted() { if (PageViewModel == null) return; if (PageViewModel.SaveFile()) { SaveHistory(PageViewModel); } } private void SaveAsExecuted() { if (PageViewModel == null) return; if (PageViewModel.SaveFile(true)) { SaveHistory(PageViewModel); } } private void SaveHistory(PageViewModel diagramsViewModel) { HistoryList.Remove(PageViewModel.FileName); HistoryList.Insert(0, PageViewModel.FileName); File.WriteAllText(_history, JsonConvert.SerializeObject(HistoryList)); } private bool Save_Enable() { return PageViewModel != null; } private void PasteExecuted() { PageViewModel?.DiagramViewModel?.PasteCommand.Execute(null); } private bool Paste_Enabled() { return Clipboard.ContainsData(DataFormats.Serializable); } private void CopyExecuted() { PageViewModel?.DiagramViewModel?.CopyCommand.Execute(null); } private bool Copy_Enabled() { return PageViewModel != null && PageViewModel.DiagramViewModel != null && PageViewModel.DiagramViewModel.SelectedItems.Count() > 0; } private void DeleteExecuted() { PageViewModel?.DiagramViewModel?.DeleteCommand.Execute(null); } private bool Delete_Enabled() { return PageViewModel != null && PageViewModel.DiagramViewModel != null && PageViewModel.DiagramViewModel.SelectedItems.Count() > 0; } private void CutExecuted() { PageViewModel?.DiagramViewModel?.CutCommand.Execute(null); } private bool Cut_Enabled() { return PageViewModel != null && PageViewModel.DiagramViewModel != null && PageViewModel.DiagramViewModel.SelectedItems.Count() > 0; } private void FormatExecuted() { _service.DrawModeViewModel.CursorMode = CursorMode.Format; } private bool Format_Enabled() { return PageViewModel != null && PageViewModel.DiagramViewModel != null && PageViewModel.DiagramViewModel.SelectedItems.Count() == 1; } private void New_Executed(string type = "Normal") { IsOpenBackstage = false; if (type == DiagramType.FlowChart.ToString()) { PageViewModel = new FlowchartViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } else if (type == DiagramType.Logical.ToString()) { PageViewModel = new LogicalViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } else if (type == DiagramType.SFC.ToString()) { PageViewModel = new SFCViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } else if (type == DiagramType.Script.ToString()) { PageViewModel = new ScriptViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } else if (type == DiagramType.Drawing.ToString()) { PageViewModel = new DrawingViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } else if (type == DiagramType.Block.ToString()) { PageViewModel = new BlockViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } else { PageViewModel = new PageViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", (DiagramType)Enum.Parse(typeof(DiagramType), type)); } PageViewModels.Add(PageViewModel); } private void NewMind_Executed(string mindtype = "Mind") { IsOpenBackstage = false; PageViewModel = new MindViewModel(NewNameHelper.GetNewName(PageViewModels.Select(p => p.Title), "新建-"), "*", DiagramType.Mind, mindtype.ToEnum()); PageViewModels.Add(PageViewModel); } private void ExitExecuted() { } private void LockExecuted(object para) { LockObjectViewModel.LockObject[0].IsChecked = true; } private void UnlockExecuted(object para) { LockObjectViewModel.LockObject.ForEach(p => p.IsChecked = false); } private void SelectedColorExecuted(object para) { if (para == null) return; switch (ColorType) { case Models.ColorType.Text: PageViewModel?.DiagramViewModel?.SetFont(new FontViewModel() { FontColor = (Color)para }, "Color", PageViewModel.DiagramViewModel.SelectedItems); break; case Models.ColorType.Fill: PageViewModel?.DiagramViewModel?.SetColor(new ColorViewModel() { FillColor = new ColorObject() { Color = (Color)para } }, "FillColor", PageViewModel.DiagramViewModel.SelectedItems); break; case Models.ColorType.Line: PageViewModel?.DiagramViewModel?.SetColor(new ColorViewModel() { LineColor = new ColorObject() { Color = (Color)para } }, "LineColor", PageViewModel.DiagramViewModel.SelectedItems); break; } } private void AboutExecuted() { AboutWindow aboutWindow = new AboutWindow(); aboutWindow.ShowDialog(); } private void ScreenshotExecuted() { AIStudio.Wpf.ComeCapture.MainWindow window = new AIStudio.Wpf.ComeCapture.MainWindow(); window.Show(); } private void ColorPickerExecuted() { AIStudio.Wpf.ColorPicker.MainWindow window = new AIStudio.Wpf.ColorPicker.MainWindow(); window.Show(); } #region 方法 private Color[] GenerateStandardGradients() { var count = ColorGallery.StandardThemeColors.Length; List result = new List(); for (var i = 0; i < count; i++) { var colors = GetGradient(ColorGallery.StandardThemeColors[i], 10); for (var j = 9; j >= 0; j--) { result.Add(colors[j]); } } { var colors = GetGradient(Colors.Black, 10); for (var j = 9; j >= 0; j--) { result.Add(colors[j]); } } return result.ToArray(); } #endregion #region Gradient Generation /// /// Returns brightness of the given color from 0..1 /// /// Color /// Brightness of the given color from 0..1 private static double GetBrightness(Color color) { var summ = (double)color.R + color.G + color.B; return summ / (255.0 * 3.0); } // Makes the given color lighter private static Color Lighter(Color color, double power) { var totalAvailability = (255.0 * 3.0) - color.R + color.G + color.B; double redAvailability; double greenAvailability; double blueAvailability; double needToBeAdded; if (color.R + color.G + color.B == 0) { redAvailability = 1.0 / 3.0; greenAvailability = 1.0 / 3.0; blueAvailability = 1.0 / 3.0; needToBeAdded = power * 255.0 * 3.0; } else { redAvailability = (255.0 - color.R) / totalAvailability; greenAvailability = (255.0 - color.G) / totalAvailability; blueAvailability = (255.0 - color.B) / totalAvailability; needToBeAdded = ((double)color.R + color.G + color.B) * (power - 1); } var result = Color.FromRgb( (byte)(color.R + (byte)(redAvailability * needToBeAdded)), (byte)(color.G + (byte)(greenAvailability * needToBeAdded)), (byte)(color.B + (byte)(blueAvailability * needToBeAdded))); return result; } // Makes the given color darker private static Color Darker(Color color, double power) { var totalAvailability = (double)color.R + color.G + color.B; var redAvailability = color.R / totalAvailability; var greenAvailability = color.G / totalAvailability; var blueAvailability = color.B / totalAvailability; var needToBeAdded = (double)color.R + color.G + color.B; needToBeAdded = needToBeAdded - (needToBeAdded * power); var result = Color.FromRgb( (byte)(color.R - (byte)(redAvailability * needToBeAdded)), (byte)(color.G - (byte)(greenAvailability * needToBeAdded)), (byte)(color.B - (byte)(blueAvailability * needToBeAdded))); return result; } // Makes a new color from the given with new brightness private static Color Rebright(Color color, double newBrightness) { var currentBrightness = GetBrightness(color); var power = DoubleUtil.AreClose(currentBrightness, 0.0) == false ? newBrightness / currentBrightness : 1.0 + newBrightness; // TODO: round power to make nice numbers // ... if (power > 1.0) { return Lighter(color, power); } return Darker(color, power); } /// /// Makes gradient colors from lighter to darker /// /// Base color /// Count of items in the gradient /// Colors from lighter to darker public static Color[] GetGradient(Color color, int count) { const double lowBrightness = 0.15; const double highBrightness = 0.85; var result = new Color[count]; for (var i = 0; i < count; i++) { var brightness = lowBrightness + (i * (highBrightness - lowBrightness) / count); result[count - i - 1] = Rebright(color, brightness); } return result; } #endregion } }