├── .github
├── FUNDING.yml
└── workflows
│ └── dotnet.yml
├── SimpleStateMachineNodeEditor
├── StateMachine.ico
├── SimpleStateMachine.png
├── FodyWeavers.xml
├── Helpers
│ ├── Transformations
│ │ ├── CanBeMove.cs
│ │ └── Scale.cs
│ ├── Enums
│ │ ├── DialogType.cs
│ │ ├── Themes.cs
│ │ ├── ImageFormats.cs
│ │ ├── TypeMove.cs
│ │ ├── DialogResult.cs
│ │ ├── SelectMode.cs
│ │ ├── DeleteMode.cs
│ │ ├── NodeCanvasClickMode.cs
│ │ └── TypeMessage.cs
│ ├── Extensions
│ │ ├── EnumExtension.cs
│ │ ├── IObservableExtension.cs
│ │ ├── ReactiveCommandExtension.cs
│ │ ├── ObjectExtension.cs
│ │ ├── MessageBoxResultExtension.cs
│ │ ├── MatrixExtension.cs
│ │ └── FileDialogResultExtension.cs
│ ├── Converters
│ │ ├── InverseBooleanConverter.cs
│ │ └── ConverterBoolAndVisibility.cs
│ └── Commands
│ │ ├── ICommandWithUndoRedo.cs
│ │ └── Command.cs
├── Dictionary1.xaml
├── Styles
│ ├── Menu
│ │ └── MenuTemplate.xaml
│ ├── StyleSelector.xaml
│ ├── ContextMenu
│ │ └── TemplateContextMenu.xaml
│ ├── MyTextBox.xaml
│ ├── Node
│ │ ├── ElementNodeHeader.xaml.cs
│ │ ├── StyleNodeCollapseButton.xaml
│ │ └── ElementNodeHeader.xaml
│ ├── ErrorList
│ │ ├── TemplateListBox.xaml
│ │ ├── StyleListBoxItem.xaml
│ │ ├── StyleLabel.xaml
│ │ ├── StyleScrollViewer.xaml
│ │ ├── StyleLabelWithIcon.xaml
│ │ └── StyleScrollBar.xaml
│ ├── MyTextBox.xaml.cs
│ ├── StyleEmptyTextBox.xaml
│ ├── MainWindow
│ │ ├── ToolBar
│ │ │ ├── TemplateSeparator.xaml
│ │ │ └── StyleRadioButton.xaml
│ │ ├── Header
│ │ │ └── StyleHeaderButton.xaml
│ │ ├── CustomWindowTemplate.cs
│ │ └── CustomWindowTemplate.xaml
│ ├── TableOfTransitions
│ │ └── StyleListBoxTransitionsItem.xaml
│ ├── Tabs
│ │ └── StyleTabItem.xaml
│ ├── Themes
│ │ ├── Light.xaml
│ │ └── Dark.xaml
│ └── Theme.xaml
├── AppSettings.cs
├── ViewModel
│ ├── Message
│ │ └── MessageViewModel.cs
│ ├── Cutter
│ │ ├── CutterCommandsViewModel.cs
│ │ └── CutterViewModel.cs
│ ├── MainWindow
│ │ ├── MainWindowCommandsViewModel.cs
│ │ └── MainWindowViewModel.cs
│ ├── Dialog
│ │ └── DialogViewModel.cs
│ ├── Selector
│ │ └── SelectorViewModel.cs
│ ├── Connect
│ │ └── ConnectViewModel.cs
│ ├── Connector
│ │ └── ConnectorViewModel.cs
│ └── Node
│ │ └── NodeViewModel.cs
├── View
│ ├── Dialog.xaml
│ ├── Selector.xaml
│ ├── Message.xaml
│ ├── Connect.xaml
│ ├── Cutter.xaml
│ ├── LeftConnector.xaml
│ ├── RightConnector.xaml
│ ├── TableOfTransitionsItem.xaml
│ ├── Message.xaml.cs
│ ├── Connect.xaml.cs
│ ├── Node.xaml
│ ├── Dialog.xaml.cs
│ ├── Cutter.xaml.cs
│ ├── Selector.xaml.cs
│ ├── LeftConnector.xaml.cs
│ ├── TableOfTransitionsItem.xaml.cs
│ └── NodesCanvas.xaml
├── Icons
│ ├── Minimize.xaml
│ ├── ErrorList.xaml
│ ├── Maximize.xaml
│ ├── Save.xaml
│ ├── CollapseUpAll.xaml
│ ├── ExpandDownAll.xaml
│ ├── Exit.xaml
│ ├── Close.xaml
│ ├── Copy.xaml
│ ├── Warning.xaml
│ ├── Error.xaml
│ ├── Information.xaml
│ ├── ExpandDown.xaml
│ ├── CollapseUp.xaml
│ ├── StateTo.xaml
│ ├── Restore.xaml
│ ├── SelectAll.xaml
│ ├── AddNode.xaml
│ ├── TransitionName.xaml
│ ├── Update.xaml
│ ├── NewSheme.xaml
│ ├── Select.xaml
│ ├── DeleteNode.xaml
│ ├── StateFrom.xaml
│ ├── DeleteScheme.xaml
│ ├── Redo.xaml
│ ├── SaveAs.xaml
│ ├── ZoomOut.xaml
│ ├── ZoomIn.xaml
│ ├── Debug.xaml
│ ├── ImportScheme.xaml
│ ├── ExportScheme.xaml
│ ├── Cut.xaml
│ ├── Undo.xaml
│ ├── Theme.xaml
│ ├── Loop.xaml
│ ├── SelectedLoop.xaml
│ ├── ZoomOriginalSize.xaml
│ └── Icons.xaml
├── AssemblyInfo.cs
├── README.txt
├── App.xaml.cs
├── FodyWeavers.xsd
├── App.xaml
└── SimpleStateMachineNodeEditor.csproj
├── azure-pipelines.yml
├── LICENSE
├── SimpleStateMachineNodeEditor.sln
└── .gitattributes
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | open_collective: simplestatemachine
4 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/StateMachine.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimpleStateMachine/SimpleStateMachineNodeEditor/HEAD/SimpleStateMachineNodeEditor/StateMachine.ico
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/SimpleStateMachine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SimpleStateMachine/SimpleStateMachineNodeEditor/HEAD/SimpleStateMachineNodeEditor/SimpleStateMachine.png
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Transformations/CanBeMove.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleStateMachineNodeEditor.Helpers.Transformations
2 | {
3 | public interface CanBeMove
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/DialogType.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
2 | {
3 | public enum DialogType
4 | {
5 | noCorrect = 0,
6 | MessageBox,
7 | SaveFileDialog,
8 | OpenFileDialog,
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Dictionary1.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/Themes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
6 | {
7 | public enum Themes
8 | {
9 | noCorrect = 0,
10 | Light,
11 | Dark
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/ImageFormats.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
6 | {
7 | public enum ImageFormats
8 | {
9 | noCorrect = 0,
10 | PNG,
11 | JPEG
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/TypeMove.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
6 | {
7 | public enum TypeMove
8 | {
9 | None = 0,
10 | MoveAll,
11 | MoveSelected,
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/DialogResult.cs:
--------------------------------------------------------------------------------
1 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
2 | {
3 | public enum DialogResult
4 | {
5 | noCorrect = 0,
6 | Yes,
7 | No,
8 | Ok,
9 | Cancel,
10 | None,
11 | Abort,
12 | Retry,
13 | Ignore
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/SelectMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
6 | {
7 | public enum SelectMode
8 | {
9 | noCorrect = 0,
10 | Click,
11 | ClickWithCtrl,
12 | ClickWithShift
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/DeleteMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
6 | {
7 | public enum DeleteMode
8 | {
9 | noCorrect = 0,
10 | DeleteNodes,
11 | DeleteConnects,
12 | DeleteAllSelected
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/NodeCanvasClickMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
6 | {
7 | public enum NodeCanvasClickMode
8 | {
9 | noCorrect = 0,
10 | Default,
11 | AddNode,
12 | Delete,
13 | Select,
14 | Cut
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Enums/TypeMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Windows.Forms;
5 |
6 | namespace SimpleStateMachineNodeEditor.Helpers.Enums
7 | {
8 | public enum TypeMessage
9 | {
10 | NotCorrect = 0,
11 | Debug,
12 | Error,
13 | Information,
14 | Warning,
15 | All
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/EnumExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
6 | {
7 | public static class EnumExtension
8 | {
9 | public static string Name(this Enum enumType)
10 | {
11 | return Enum.GetName(enumType.GetType(), enumType);
12 | }
13 |
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Menu/MenuTemplate.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/AppSettings.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using SimpleStateMachineNodeEditor.Helpers.Enums;
4 |
5 | namespace SimpleStateMachineNodeEditor
6 | {
7 | public class AppSettings
8 | {
9 | public class AppearanceSettings
10 | {
11 | [JsonConverter(typeof(StringEnumConverter))]
12 | public Themes Theme { get; set; }
13 | }
14 |
15 | public AppearanceSettings Appearance { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/IObservableExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reactive;
4 | using System.Reactive.Linq;
5 | using System.Text;
6 |
7 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
8 | {
9 | public static class IObservableExtension
10 | {
11 | public static IObservable WithoutParameter(this IObservable source)
12 | {
13 | return source.Select(_ => Unit.Default);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Message/MessageViewModel.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using ReactiveUI.Fody.Helpers;
3 | using SimpleStateMachineNodeEditor.Helpers.Enums;
4 |
5 | namespace SimpleStateMachineNodeEditor.ViewModel
6 | {
7 | public class MessageViewModel : ReactiveObject
8 | {
9 | public TypeMessage TypeMessage { get; set; }
10 | [Reactive] public string Text { get; set; }
11 | public MessageViewModel(TypeMessage typeMessage, string text)
12 | {
13 | TypeMessage = typeMessage;
14 | Text = text;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET
2 |
3 | on:
4 | push:
5 | branches: [ ToAvaloniaUI ]
6 | pull_request:
7 | branches: [ ToAvaloniaUI ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Setup .NET
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: 5.0.x
20 | - name: Restore dependencies
21 | run: dotnet restore
22 | - name: Build
23 | run: dotnet build --no-restore
24 | - name: Test
25 | run: dotnet test --no-build --verbosity normal
26 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Dialog.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/ReactiveCommandExtension.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using SimpleStateMachineNodeEditor.Helpers.Commands;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
8 | {
9 | public static class ReactiveCommandExtension
10 | {
11 | public static IDisposable ExecuteWithSubscribe(this ReactiveCommand reactiveCommand, TParam parameter = default)
12 | {
13 | return reactiveCommand.Execute(parameter).Subscribe();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Minimize.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ErrorList.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Maximize.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Save.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/CollapseUpAll.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ExpandDownAll.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/ObjectExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
6 | {
7 | public static class ObjectExtension
8 | {
9 | public static T Cast(this object obj)
10 | {
11 | return (obj is T) ? (T)obj : default(T);
12 | }
13 |
14 | public static bool TryCast(this object obj, out T newValue)
15 | {
16 | bool typeCorrect = obj is T;
17 |
18 | newValue = typeCorrect?(T)obj:default(T);
19 |
20 | return typeCorrect;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Exit.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Close.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | - job: Windows
3 | pool:
4 | vmImage: 'windows-2019'
5 | variables:
6 | buildConfiguration: 'Release'
7 | steps:
8 | - task: DotNetCoreInstaller@0
9 | inputs:
10 | version: '3.1.302'
11 | - script: cd $(Build.SourcesDirectory) && dotnet build
12 | displayName: 'Windows Full Build and Tests'
13 | - task: PublishTestResults@2
14 | inputs:
15 | testRunner: VSTest
16 | testResultsFiles: '**/*.trx'
17 | - task: PublishCodeCoverageResults@1
18 | inputs:
19 | summaryFileLocation: $(Build.SourcesDirectory)\artifacts\coverage.cobertura.xml
20 | reportDirectory: $(Build.SourcesDirectory)\artifacts
21 | codecoverageTool: cobertura
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Copy.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Cutter/CutterCommandsViewModel.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Reactive;
5 | using System.Text;
6 | using System.Windows;
7 |
8 | namespace SimpleStateMachineNodeEditor.ViewModel
9 | {
10 | public partial class CutterViewModel
11 | {
12 | public ReactiveCommand CommandStartCut { get; set; }
13 |
14 | private void SetupCommands()
15 | {
16 | CommandStartCut = ReactiveCommand.Create(StartCut);
17 | }
18 |
19 | private void StartCut(Point point)
20 | {
21 | Visible = true;
22 | StartPoint = point;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Warning.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Error.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Information.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ExpandDown.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/StyleSelector.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/CollapseUp.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/StateTo.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ContextMenu/TemplateContextMenu.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MyTextBox.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Node/ElementNodeHeader.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Data;
7 | using System.Windows.Documents;
8 | using System.Windows.Input;
9 | using System.Windows.Media;
10 | using System.Windows.Media.Imaging;
11 | using System.Windows.Navigation;
12 | using System.Windows.Shapes;
13 |
14 | namespace SimpleStateMachineNodeEditor.Styles.Node
15 | {
16 | ///
17 | /// Interaction logic for NodeHeader.xaml
18 | ///
19 | public partial class ElementNodeHeader : UserControl
20 | {
21 | public ElementNodeHeader()
22 | {
23 | InitializeComponent();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Restore.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/SelectAll.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/AddNode.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/TransitionName.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Update.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/README.txt:
--------------------------------------------------------------------------------
1 | Ctrl + A = Select All Nodes
2 | Ctrl + S = Save
3 | Ctrl + Shift + S = Save As
4 | Ctrl + Shift + O = Open
5 | Ctrl + Shift + N = New
6 | Alt + F4 = Exit
7 | Ctrl + Shift + Alt + P = Export to PNG
8 | Ctrl + Shift + Alt + J = Export to JPEG
9 | Ctrl + Z = Undo
10 | Ctrl + Y = Redo
11 | Ctrl + N = Add Node
12 | Ctrl + LMB on Canvas = Start Select
13 | Ctrl + LMB on Connector = Create Loop
14 | LMB on Node = Select one Node
15 | Ctrl + LMB on Node = Select/UnSelect Node
16 | Ctrl + LMB on Transition = Select/UnSelect Transition
17 | Shift + LMB on Transition = Multiple selection
18 | LMB on Connector = Start create Connect
19 | Alt + LMB on Connector = Move Connector in Node
20 | Alt + LMB on Canvas = Start Cut
21 | Delete = Delete Selected Elements
22 | C + Delete = Delete Selected Connector
23 | N + Delete = Delete Selected Nodes
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/NewSheme.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Select.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ErrorList/TemplateListBox.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/DeleteNode.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/MessageBoxResultExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 |
4 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
5 | {
6 | public static class MessageBoxResultExtension
7 | {
8 | public static Helpers.Enums.DialogResult ToDialogResult(this MessageBoxResult messageBoxResult)
9 | {
10 | return messageBoxResult switch
11 | {
12 | MessageBoxResult.Yes => Helpers.Enums.DialogResult.Yes,
13 | MessageBoxResult.No => Helpers.Enums.DialogResult.No,
14 | MessageBoxResult.OK => Helpers.Enums.DialogResult.Ok,
15 | MessageBoxResult.Cancel => Helpers.Enums.DialogResult.Cancel,
16 | MessageBoxResult.None => Helpers.Enums.DialogResult.None,
17 | _ => throw new NotImplementedException()
18 | };
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/StateFrom.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Converters/InverseBooleanConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Windows.Data;
5 |
6 | namespace SimpleStateMachineNodeEditor.Helpers.Converters
7 | {
8 | public class InverseBooleanConverter: IValueConverter
9 | {
10 | #region IValueConverter Members
11 |
12 | public object Convert(object value, Type targetType, object parameter,
13 | System.Globalization.CultureInfo culture)
14 | {
15 | if (targetType != typeof(bool))
16 | throw new InvalidOperationException("The target must be a boolean");
17 |
18 | return !(bool)value;
19 | }
20 |
21 | public object ConvertBack(object value, Type targetType, object parameter,
22 | System.Globalization.CultureInfo culture)
23 | {
24 | throw new NotSupportedException();
25 | }
26 |
27 | #endregion
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/DeleteScheme.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Redo.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/SaveAs.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Microsoft.Extensions.Configuration;
3 | using ReactiveUI;
4 | using Splat;
5 | using SimpleStateMachineNodeEditor.Helpers.Converters;
6 | using WritableJsonConfiguration;
7 | using Application = System.Windows.Application;
8 |
9 | namespace SimpleStateMachineNodeEditor
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | public App()
17 | {
18 | Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
19 | Locator.CurrentMutable.RegisterConstant(new ConverterBoolAndVisibility(), typeof(IBindingTypeConverter));
20 |
21 | IConfigurationRoot configuration;
22 | configuration = WritableJsonConfigurationFabric.Create("Settings.json");
23 | Locator.CurrentMutable.RegisterConstant(configuration, typeof(IConfiguration));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/MainWindow/MainWindowCommandsViewModel.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Reactive;
5 | using System.Text;
6 | using System.Windows;
7 |
8 | namespace SimpleStateMachineNodeEditor.ViewModel
9 | {
10 | public partial class MainWindowViewModel
11 | {
12 | public ReactiveCommand CommandCopyError { get; set; }
13 | public ReactiveCommand CommandCopySchemeName { get; set; }
14 |
15 | private void SetupCommands()
16 | {
17 | CommandCopyError = ReactiveCommand.Create(CopyError);
18 | CommandCopySchemeName = ReactiveCommand.Create(CopySchemeName);
19 |
20 | }
21 |
22 | private void CopyError(string errrorText)
23 | {
24 | Clipboard.SetText(errrorText);
25 | }
26 | private void CopySchemeName()
27 | {
28 | Clipboard.SetText(this.NodesCanvas.SchemePath);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Selector.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ZoomOut.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Message.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ZoomIn.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 SimpleStateMachine
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Connect.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Debug.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/MatrixExtension.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Media;
3 | using static System.Math;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
6 | {
7 | public static class MatrixExtension
8 | {
9 | public static Matrix ScaleAt(double scaleX, double scaleY, double centerX, double centerY)
10 | {
11 | return new Matrix(scaleX, 0, 0, scaleY, centerX - (scaleX * centerX), centerY - (scaleY * centerY));
12 | }
13 |
14 | public static Matrix ScaleAtPrepend(Matrix matrix, double scaleX, double scaleY, double centerX, double centerY)
15 | {
16 | return ScaleAt(scaleX, scaleY, centerX, centerY) * matrix;
17 | }
18 |
19 | public static Matrix ScaleAtPrepend(Matrix matrix, double scaleX, double scaleY)
20 | {
21 | return ScaleAt2(scaleX, scaleY, matrix.OffsetX, matrix.OffsetY) * matrix;
22 | }
23 | public static Matrix ScaleAt2(double scaleX, double scaleY, double centerX, double centerY)
24 | {
25 | return new Matrix(scaleX, 0, 0, scaleY, 1, 1);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Cutter/CutterViewModel.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using ReactiveUI.Fody.Helpers;
3 |
4 |
5 | using System;
6 | using System.Reactive.Linq;
7 | using System.Windows;
8 |
9 | namespace SimpleStateMachineNodeEditor.ViewModel
10 | {
11 | public partial class CutterViewModel : ReactiveObject
12 | {
13 | [Reactive] public NodesCanvasViewModel NodesCanvas { get; set; }
14 | [Reactive] public bool? Visible { get; set; } = false;
15 | [Reactive] public Point StartPoint { get; set;}
16 | [Reactive] public Point EndPoint { get; set; }
17 | [Reactive] public double StrokeThickness { get; set; } = 1;
18 |
19 | public CutterViewModel(NodesCanvasViewModel nodesCanvas)
20 | {
21 | NodesCanvas = nodesCanvas;
22 | SetupCommands();
23 | SetupSubscriptions();
24 |
25 | }
26 |
27 | #region Setup Subscriptions
28 | private void SetupSubscriptions()
29 | {
30 | //this.WhenAnyValue(x => x.NodesCanvas.Scale.Value).Subscribe(value => StrokeThickness = value);
31 | }
32 |
33 | #endregion Setup Subscriptions
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Transformations/Scale.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using ReactiveUI.Fody.Helpers;
3 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
4 | using Splat;
5 | using System;
6 | using System.Reactive.Linq;
7 | using System.Windows;
8 |
9 | namespace SimpleStateMachineNodeEditor.Helpers.Transformations
10 | {
11 | public class Scale : ReactiveObject
12 | {
13 | [Reactive] public Point Scales { get; set; } = new Point(1, 1);
14 | [Reactive] public Point Center { get; set; }
15 |
16 | [Reactive] public double Value { get; set; } = 1.0;
17 |
18 | public double ScaleX
19 | {
20 | get { return Scales.X; }
21 | }
22 | public double ScaleY
23 | {
24 | get { return Scales.Y; }
25 | }
26 |
27 | public double CenterX
28 | {
29 | get { return Center.X; }
30 | }
31 | public double CenterY
32 | {
33 | get { return Center.Y; }
34 | }
35 |
36 | public Scale()
37 | {
38 | this.WhenAnyValue(x => x.Value).Subscribe(value => Scales = PointExtensition.CreatePoint(value));
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Cutter.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ImportScheme.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ErrorList/StyleListBoxItem.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MyTextBox.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Data;
7 | using System.Windows.Documents;
8 | using System.Windows.Input;
9 | using System.Windows.Media;
10 | using System.Windows.Media.Imaging;
11 | using System.Windows.Navigation;
12 | using System.Windows.Shapes;
13 |
14 | namespace SimpleStateMachineNodeEditor.Styles
15 | {
16 | ///
17 | /// Логика взаимодействия для TestBox.xaml
18 | ///
19 | public partial class MyTextBox : TextBox
20 | {
21 | public MyTextBox()
22 | {
23 | InitializeComponent();
24 | this.ContextMenu = null;
25 | }
26 |
27 | protected override void OnDragEnter(DragEventArgs e)
28 | {
29 | if(e.Effects != DragDropEffects.Move)
30 | {
31 | base.OnDragEnter(e);
32 | }
33 | }
34 |
35 |
36 | protected override void OnDragOver(DragEventArgs e)
37 | {
38 | if (e.Effects != DragDropEffects.Move)
39 | {
40 | base.OnDragOver(e);
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29728.190
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleStateMachineNodeEditor", "SimpleStateMachineNodeEditor\SimpleStateMachineNodeEditor.csproj", "{F405DC54-B579-44A4-B414-3925A236A98D}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {F405DC54-B579-44A4-B414-3925A236A98D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {F405DC54-B579-44A4-B414-3925A236A98D}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {F405DC54-B579-44A4-B414-3925A236A98D}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {F405DC54-B579-44A4-B414-3925A236A98D}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {EDBB0752-6D34-465F-901F-878040936ED6}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Extensions/FileDialogResultExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SimpleStateMachineNodeEditor.Helpers.Extensions
4 | {
5 | public static class FileDialogResultExtension
6 | {
7 | public static Enums.DialogResult ToDialogResult(this System.Windows.Forms.DialogResult fileDialogResult)
8 | {
9 | return fileDialogResult switch
10 | {
11 | System.Windows.Forms.DialogResult.Yes => Helpers.Enums.DialogResult.Yes,
12 | System.Windows.Forms.DialogResult.No => Helpers.Enums.DialogResult.No,
13 | System.Windows.Forms.DialogResult.OK => Helpers.Enums.DialogResult.Ok,
14 | System.Windows.Forms.DialogResult.Cancel => Helpers.Enums.DialogResult.Cancel,
15 | System.Windows.Forms.DialogResult.None => Helpers.Enums.DialogResult.None,
16 | System.Windows.Forms.DialogResult.Abort => Helpers.Enums.DialogResult.Abort,
17 | System.Windows.Forms.DialogResult.Retry => Helpers.Enums.DialogResult.Retry,
18 | System.Windows.Forms.DialogResult.Ignore => Helpers.Enums.DialogResult.Ignore,
19 | _ => throw new NotImplementedException(),
20 | };
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
12 |
13 |
14 |
15 |
16 | A comma-separated list of error codes that can be safely ignored in assembly verification.
17 |
18 |
19 |
20 |
21 | 'false' to turn off automatic generation of the XML Schema file.
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/StyleEmptyTextBox.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
22 |
23 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ExportScheme.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/LeftConnector.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/RightConnector.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Commands/ICommandWithUndoRedo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 |
4 | namespace SimpleStateMachineNodeEditor.Helpers.Commands
5 | {
6 | public interface ICommandWithUndoRedo
7 | {
8 | public static Stack StackRedo { get; set; } = new Stack();
9 |
10 | public static Stack StackUndo { get; set; } = new Stack();
11 |
12 | public static void Redo()
13 | {
14 | if (StackRedo.Count > 0)
15 | {
16 | ICommandWithUndoRedo last = StackRedo.Pop();
17 | last.ExecuteWithSubscribe();
18 | }
19 | }
20 |
21 | public static void Undo()
22 | {
23 | if (StackUndo.Count > 0)
24 | {
25 | ICommandWithUndoRedo last = StackUndo.Pop();
26 | last.UnExecute();
27 | }
28 | }
29 |
30 | protected static ICommandWithUndoRedo AddInRedo(ICommandWithUndoRedo command)
31 | {
32 | StackRedo.Push(command);
33 |
34 | return command;
35 | }
36 |
37 | protected static ICommandWithUndoRedo AddInUndo(ICommandWithUndoRedo command)
38 | {
39 | StackUndo.Push(command);
40 |
41 | return command;
42 | }
43 |
44 | protected abstract void ExecuteWithSubscribe();
45 | protected abstract void UnExecute();
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MainWindow/ToolBar/TemplateSeparator.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
23 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Node/StyleNodeCollapseButton.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
25 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Cut.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Converters/ConverterBoolAndVisibility.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using ReactiveUI;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Converters
6 | {
7 | public class ConverterBoolAndVisibility : IBindingTypeConverter
8 | {
9 | public int GetAffinityForObjects(Type fromType, Type toType)
10 | {
11 | bool fromTypeIsCorrect = (fromType == typeof(bool?)) || (fromType == typeof(Visibility));
12 | bool toTypeIsCorrect = (toType == typeof(Visibility)) || (toType == typeof(bool?));
13 | if (!fromTypeIsCorrect || !toTypeIsCorrect)
14 | return 0;
15 |
16 | return 100;
17 | }
18 |
19 | public bool TryConvert(object from, Type toType, object conversionHint, out object result)
20 | {
21 | result = null;
22 | if (toType == typeof(Visibility))
23 | {
24 | bool? value = (bool?)from;
25 | result = Visibility.Collapsed;
26 |
27 | if (value != null)
28 | result = (value.Value) ? Visibility.Visible : Visibility.Hidden;
29 |
30 | return true;
31 | }
32 | else if (toType == typeof(bool?))
33 | {
34 |
35 | Visibility value = (Visibility)from;
36 | result = null;
37 |
38 | if (value != Visibility.Collapsed)
39 | result = (value == Visibility.Visible);
40 |
41 | return true;
42 | }
43 |
44 | return false;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Undo.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Theme.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/TableOfTransitions/StyleListBoxTransitionsItem.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
28 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Loop.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/SelectedLoop.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ErrorList/StyleLabel.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
28 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Node/ElementNodeHeader.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/TableOfTransitionsItem.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/ZoomOriginalSize.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MainWindow/ToolBar/StyleRadioButton.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
30 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Dialog/DialogViewModel.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI.Fody.Helpers;
2 | using ReactiveUI.Validation.Helpers;
3 | using SimpleStateMachineNodeEditor.Helpers.Enums;
4 | using System.Windows;
5 |
6 | namespace SimpleStateMachineNodeEditor.ViewModel
7 | {
8 | public class DialogViewModel : ReactiveValidationObject
9 | {
10 | [Reactive] public bool? Visibility { get; set; }
11 | [Reactive] public DialogType Type { get; set; }
12 | [Reactive] public DialogResult Result { get; set; }
13 | [Reactive] public string Title { get; set; }
14 |
15 |
16 | [Reactive] public string MessageBoxText { get; set; }
17 | [Reactive] public MessageBoxButton MessageBoxButtons{ get; set; }
18 |
19 |
20 | [Reactive] public string FileDialogFilter { get; set; }
21 | [Reactive] public string FileName { get; set; }
22 |
23 | private void Show()
24 | {
25 | Visibility = true;
26 | }
27 | private void Clear()
28 | {
29 | Type = DialogType.noCorrect;
30 | Result = DialogResult.noCorrect;
31 | Title = "";
32 | MessageBoxText = "";
33 | FileDialogFilter = "";
34 | FileName = "";
35 | }
36 | public void ShowMessageBox(string messageBoxText, string caption, MessageBoxButton button)
37 | {
38 | Clear();
39 | MessageBoxText = messageBoxText;
40 | MessageBoxButtons = button;
41 | Type = DialogType.MessageBox;
42 | Title = caption;
43 | Show();
44 | }
45 |
46 | public void ShowOpenFileDialog(string filter, string fileName, string title)
47 | {
48 | Clear();
49 | FileDialogFilter = filter;
50 | FileName = fileName;
51 | Title = title;
52 | Type = DialogType.OpenFileDialog;
53 | Show();
54 | }
55 |
56 | public void ShowSaveFileDialog(string filter, string fileName, string title)
57 | {
58 | Clear();
59 | FileDialogFilter = filter;
60 | FileName = fileName;
61 | Title = title;
62 | Type = DialogType.SaveFileDialog;
63 | Show();
64 | }
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ErrorList/StyleScrollViewer.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
38 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MainWindow/Header/StyleHeaderButton.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
14 |
15 |
37 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Helpers/Commands/Command.cs:
--------------------------------------------------------------------------------
1 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
2 | using System;
3 | using System.Windows.Input;
4 |
5 | namespace SimpleStateMachineNodeEditor.Helpers.Commands
6 | {
7 | public class Command : ICommandWithUndoRedo, ICommand, ICloneable
8 | {
9 | private readonly Func _execute;
10 | private readonly Func _unExecute;
11 | public Action OnExecute { get; set; }
12 | public TParameter Parameters { get; set; }
13 | public TResult Result { get; set; }
14 | public object Clone()
15 | {
16 | return new Command(_execute, _unExecute, OnExecute)
17 | {
18 | Parameters = this.Parameters,
19 | Result = this.Result
20 | };
21 | }
22 |
23 |
24 | public event EventHandler CanExecuteChanged
25 | {
26 | add { CommandManager.RequerySuggested += value; }
27 | remove { CommandManager.RequerySuggested -= value; }
28 | }
29 |
30 | public bool CanExecute(object parameter)
31 | {
32 | return true;
33 | }
34 |
35 | public void Execute(object parameter = default)
36 | {
37 | Parameters = parameter.Cast();
38 |
39 | Result = this._execute(Parameters, Result).Cast();
40 |
41 | ICommandWithUndoRedo.AddInUndo(this.Clone() as ICommandWithUndoRedo);
42 |
43 | ICommandWithUndoRedo.StackRedo.Clear();
44 |
45 | Result = default(TResult);
46 |
47 | Parameters = default(TParameter);
48 |
49 | OnExecute?.Invoke();
50 | }
51 |
52 | void ICommandWithUndoRedo.ExecuteWithSubscribe()
53 | {
54 | this.Result = this._execute(this.Parameters, this.Result);
55 |
56 | ICommandWithUndoRedo.AddInUndo(this.Clone() as ICommandWithUndoRedo);
57 | }
58 |
59 | void ICommandWithUndoRedo.UnExecute()
60 | {
61 | this._unExecute(Parameters, Result);
62 |
63 | ICommandWithUndoRedo.AddInRedo(this.Clone() as ICommandWithUndoRedo);
64 | }
65 |
66 | public Command(Func ExecuteWithSubscribe, Func unExecute, Action onExecute = null)
67 | {
68 | _execute = ExecuteWithSubscribe;
69 |
70 | _unExecute = unExecute;
71 |
72 | OnExecute += onExecute;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Icons/Icons.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Message.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive.Disposables;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Input;
5 | using ReactiveUI;
6 | using System;
7 | using System.Windows.Data;
8 | using System.Windows.Documents;
9 | using System.Windows.Media;
10 | using System.Windows.Media.Imaging;
11 | using System.Windows.Navigation;
12 | using System.Windows.Controls.Primitives;
13 | using System.Reactive.Linq;
14 | using System.Windows.Markup;
15 | using SimpleStateMachineNodeEditor.ViewModel;
16 | using SimpleStateMachineNodeEditor.Helpers;
17 | using SimpleStateMachineNodeEditor.Helpers.Enums;
18 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
19 |
20 | namespace SimpleStateMachineNodeEditor.View
21 | {
22 | ///
23 | /// Interaction logic for ViewError.xaml
24 | ///
25 | public partial class Message : UserControl, IViewFor
26 | {
27 | #region ViewModel
28 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(MessageViewModel), typeof(Message), new PropertyMetadata(null));
29 |
30 | public MessageViewModel ViewModel
31 | {
32 | get { return (MessageViewModel)GetValue(ViewModelProperty); }
33 | set { SetValue(ViewModelProperty, value); }
34 | }
35 |
36 | object IViewFor.ViewModel
37 | {
38 | get { return ViewModel; }
39 | set { ViewModel = (MessageViewModel)value; }
40 | }
41 | #endregion ViewModel
42 | public Message()
43 | {
44 | InitializeComponent();
45 | SetupBinding();
46 | SetupSubscriptions();
47 | }
48 |
49 | #region SetupBinding
50 | private void SetupBinding()
51 | {
52 | this.WhenActivated(disposable =>
53 | {
54 | this.OneWayBind(this.ViewModel, x => x.Text, x => x.TextBlockElement.Text).DisposeWith(disposable);
55 | });
56 | }
57 | #endregion SetupBinding
58 |
59 | #region Setup Subscriptions
60 |
61 | private void SetupSubscriptions()
62 | {
63 | this.WhenActivated(disposable =>
64 | {
65 | this.WhenAnyValue(x => x.ViewModel.TypeMessage).Where(value=>value!=TypeMessage.NotCorrect).Subscribe(value => UpdateIcon(value)).DisposeWith(disposable);
66 | });
67 | }
68 | private void UpdateIcon(TypeMessage type)
69 | {
70 | this.RectangleElement.Fill = Application.Current.Resources["Icon" + type.Name()] as DrawingBrush;
71 | }
72 | #endregion Setup Subscriptions
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Tabs/StyleTabItem.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Selector/SelectorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Reactive.Linq;
4 |
5 | using ReactiveUI;
6 | using ReactiveUI.Fody.Helpers;
7 |
8 | using SimpleStateMachineNodeEditor.Helpers;
9 | using SimpleStateMachineNodeEditor.Helpers.Transformations;
10 | using System.Reactive;
11 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
12 |
13 | namespace SimpleStateMachineNodeEditor.ViewModel
14 | {
15 | public class SelectorViewModel : ReactiveObject
16 | {
17 | [Reactive] public Size Size { get; set; }
18 | [Reactive] public bool? Visible { get; set; } = false;
19 | [Reactive] public Point Point1 { get; set; }
20 | [Reactive] public Point Point2 { get; set; }
21 | [Reactive] public Scale Scale { get; set; } = new Scale();
22 |
23 | public Point Point1WithScale
24 | {
25 | get
26 | {
27 | double X = Point1.X;
28 | double Y = Point1.Y;
29 |
30 | if (Scale.ScaleX < 0)
31 | X -= Size.Width;
32 | if (Scale.ScaleY < 0)
33 | Y -= Size.Height;
34 |
35 | return new Point(X, Y);
36 | }
37 | }
38 | public Point Point2WithScale
39 | {
40 | get
41 | {
42 | double X = Point1.X;
43 | double Y = Point1.Y;
44 |
45 | if (Scale.ScaleX > 0)
46 | X += Size.Width;
47 | if (Scale.ScaleY > 0)
48 | Y += Size.Height;
49 |
50 | return new Point(X, Y);
51 | }
52 | }
53 |
54 |
55 | public SelectorViewModel()
56 | {
57 | SetupCommands();
58 | SetupSubscriptions();
59 | }
60 |
61 | #region Setup Subscriptions
62 |
63 | private void SetupSubscriptions()
64 | {
65 | this.WhenAnyValue(x => x.Point1, x => x.Point2).Subscribe(_ => UpdateSize());
66 | }
67 | private void UpdateSize()
68 | {
69 | Point different = Point2.Subtraction(Point1);
70 | Size = new Size(Math.Abs(different.X), Math.Abs(different.Y));
71 | Scale.Scales = Scale.Scales.CreateNew(((different.X > 0) ? 1 : -1), ((different.Y > 0) ? 1 : -1));
72 | }
73 |
74 | #endregion Setup Subscriptions
75 |
76 | #region Setup Commands
77 | public ReactiveCommand CommandStartSelect { get; set; }
78 |
79 | private void SetupCommands()
80 | {
81 | CommandStartSelect = ReactiveCommand.Create(StartSelect);
82 | }
83 |
84 | private void StartSelect(Point point)
85 | {
86 | Visible = true;
87 | Point1 = point;
88 | }
89 |
90 | #endregion Setup Commands
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Connect.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive.Disposables;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Input;
5 | using ReactiveUI;
6 | using System;
7 | using System.Windows.Data;
8 | using System.Windows.Documents;
9 | using System.Windows.Media;
10 | using System.Windows.Media.Imaging;
11 | using System.Windows.Navigation;
12 | using System.Windows.Controls.Primitives;
13 | using System.Reactive.Linq;
14 | using System.Windows.Markup;
15 | using SimpleStateMachineNodeEditor.ViewModel;
16 | using SimpleStateMachineNodeEditor.Helpers;
17 |
18 | namespace SimpleStateMachineNodeEditor.View
19 | {
20 | ///
21 | /// Interaction logic for ViewConnect.xaml
22 | ///
23 | public partial class Connect : UserControl, IViewFor
24 | {
25 | #region ViewModel
26 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(ConnectViewModel), typeof(Connect), new PropertyMetadata(null));
27 |
28 | public ConnectViewModel ViewModel
29 | {
30 | get { return (ConnectViewModel)GetValue(ViewModelProperty); }
31 | set { SetValue(ViewModelProperty, value); }
32 | }
33 |
34 | object IViewFor.ViewModel
35 | {
36 | get { return ViewModel; }
37 | set { ViewModel = (ConnectViewModel)value; }
38 | }
39 | #endregion ViewModel
40 | public Connect()
41 | {
42 | InitializeComponent();
43 | SetupBinding();
44 | }
45 |
46 | #region SetupBinding
47 | private void SetupBinding()
48 | {
49 | this.WhenActivated(disposable =>
50 | {
51 | Canvas.SetZIndex((UIElement)this.VisualParent, 999);
52 |
53 | this.OneWayBind(this.ViewModel, x => x.Stroke, x => x.PathElement.Stroke).DisposeWith(disposable);
54 |
55 | this.OneWayBind(this.ViewModel, x => x.StartPoint, x => x.PathFigureElement.StartPoint).DisposeWith(disposable);
56 |
57 | this.OneWayBind(this.ViewModel, x => x.Point1, x => x.BezierSegmentElement.Point1).DisposeWith(disposable);
58 |
59 | this.OneWayBind(this.ViewModel, x => x.Point2, x => x.BezierSegmentElement.Point2).DisposeWith(disposable);
60 |
61 | this.OneWayBind(this.ViewModel, x => x.EndPoint, x => x.BezierSegmentElement.Point3).DisposeWith(disposable);
62 |
63 | this.OneWayBind(this.ViewModel, x => x.StrokeDashArray, x => x.PathElement.StrokeDashArray).DisposeWith(disposable);
64 |
65 | //this.OneWayBind(this.ViewModel, x => x.FromConnector.NodesCanvas.Scale.Value, x => x.PathElement.StrokeThickness).DisposeWith(disposable);
66 |
67 | this.WhenAnyValue(x => x.ViewModel.ToConnector).Where(x=>x!=null).Subscribe(_ => UpdateZindex()).DisposeWith(disposable);
68 | });
69 | }
70 |
71 | private void UpdateZindex()
72 | {
73 | int toIndex = this.ViewModel.ToConnector.Node.Zindex;
74 | int fromIndex = this.ViewModel.FromConnector.Node.Zindex;
75 |
76 | Canvas.SetZIndex((UIElement)this.VisualParent, Math.Min(toIndex, fromIndex));
77 | }
78 | #endregion SetupBinding
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MainWindow/CustomWindowTemplate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Interop;
4 | using System.Runtime.InteropServices;
5 | using System.Windows.Input;
6 | using System.Windows.Shapes;
7 |
8 | namespace SimpleStateMachineNodeEditor.Styles
9 | {
10 | public partial class CustomWindowTemplate
11 | {
12 | bool ResizeInProcess = false;
13 | int shift = 0;
14 | private void ResizeStart(object sender, MouseButtonEventArgs e)
15 | {
16 | Rectangle senderRect = sender as Rectangle;
17 | if (senderRect != null)
18 | {
19 | ResizeInProcess = true;
20 | senderRect.CaptureMouse();
21 | }
22 | }
23 |
24 | private void ResizeEnd(object sender, MouseButtonEventArgs e)
25 | {
26 | Rectangle senderRect = sender as Rectangle;
27 | if (senderRect != null)
28 | {
29 | ResizeInProcess = false; ;
30 | senderRect.ReleaseMouseCapture();
31 | }
32 | }
33 |
34 | private void Resizeing_Form(object sender, MouseEventArgs e)
35 | {
36 | if (ResizeInProcess)
37 | {
38 | double temp = 0;
39 | Rectangle senderRect = sender as Rectangle;
40 | Window mainWindow = senderRect.Tag as Window;
41 | if (senderRect != null)
42 | {
43 | double width = e.GetPosition(mainWindow).X;
44 | double height = e.GetPosition(mainWindow).Y;
45 | senderRect.CaptureMouse();
46 | if (senderRect.Name.Contains("right", StringComparison.OrdinalIgnoreCase))
47 | {
48 | width += shift;
49 | if (width > 0)
50 | mainWindow.Width = width;
51 | }
52 | if (senderRect.Name.Contains("left", StringComparison.OrdinalIgnoreCase))
53 | {
54 | width -= shift;
55 | temp = mainWindow.Width - width;
56 | if ((temp > mainWindow.MinWidth) && (temp < mainWindow.MaxWidth))
57 | {
58 | mainWindow.Width = temp;
59 | mainWindow.Left += width;
60 | }
61 | }
62 | if (senderRect.Name.Contains("bottom", StringComparison.OrdinalIgnoreCase))
63 | {
64 | height += shift;
65 | if (height > 0)
66 | mainWindow.Height = height;
67 | }
68 | if (senderRect.Name.ToLower().Contains("top", StringComparison.OrdinalIgnoreCase))
69 | {
70 | height -= shift;
71 | temp = mainWindow.Height - height;
72 | if ((temp > mainWindow.MinHeight) && (temp < mainWindow.MaxHeight))
73 | {
74 | mainWindow.Height = temp;
75 | mainWindow.Top += height;
76 | }
77 | }
78 | }
79 | }
80 | }
81 |
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ErrorList/StyleLabelWithIcon.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
44 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Node.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Dialog.xaml.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using SimpleStateMachineNodeEditor.Helpers.Enums;
3 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
4 | using SimpleStateMachineNodeEditor.ViewModel;
5 | using System;
6 | using System.Reactive.Disposables;
7 | using System.Reactive.Linq;
8 | using System.Windows;
9 | using System.Windows.Forms;
10 |
11 | namespace SimpleStateMachineNodeEditor.View
12 | {
13 | ///
14 | /// Interaction logic for ViewDialog.xaml
15 | ///
16 | public partial class Dialog : System.Windows.Controls.UserControl, IViewFor
17 | {
18 | #region ViewModel
19 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(DialogViewModel), typeof(Dialog), new PropertyMetadata(null));
20 |
21 | public DialogViewModel ViewModel
22 | {
23 | get { return (DialogViewModel)GetValue(ViewModelProperty); }
24 | set { SetValue(ViewModelProperty, value); }
25 | }
26 |
27 | object IViewFor.ViewModel
28 | {
29 | get { return ViewModel; }
30 | set { ViewModel = (DialogViewModel)value; }
31 | }
32 | #endregion ViewModel
33 | public Dialog()
34 | {
35 | InitializeComponent();
36 | SetupBinding();
37 | SetupSubcriptions();
38 | }
39 | private void SetupBinding()
40 | {
41 | this.WhenActivated(disposable =>
42 | {
43 | this.Bind(this.ViewModel, x=>x.Visibility, x=>x.Visibility).DisposeWith(disposable);
44 | });
45 | }
46 | private void SetupSubcriptions()
47 | {
48 | this.WhenActivated(disposable =>
49 | {
50 | this.WhenAnyValue(x => x.Visibility).Where(x => x == Visibility.Visible).Subscribe(_ => Show()).DisposeWith(disposable);
51 | });
52 | }
53 | private void Show()
54 | {
55 | GetAction().Invoke();
56 | this.Visibility = Visibility.Collapsed;
57 | }
58 |
59 | private Action GetAction()
60 | {
61 | return ViewModel.Type switch
62 | {
63 | DialogType.MessageBox => ShowMessageBox,
64 | DialogType.SaveFileDialog => ShowSaveFileDialog,
65 | DialogType.OpenFileDialog => ShowOpenFileDialog,
66 | DialogType.noCorrect => throw new NotImplementedException(),
67 | _ => throw new NotImplementedException()
68 | };
69 | }
70 |
71 | private void ShowMessageBox()
72 | {
73 | ViewModel.Result = System.Windows.MessageBox.Show(ViewModel.MessageBoxText, ViewModel.Title, ViewModel.MessageBoxButtons).ToDialogResult();
74 | }
75 | private void ShowOpenFileDialog()
76 | {
77 | OpenFileDialog dlg = new OpenFileDialog();
78 | dlg.Title = ViewModel.Title;
79 | dlg.FileName = ViewModel.FileName;
80 | dlg.Filter = ViewModel.FileDialogFilter;
81 |
82 | ViewModel.Result = dlg.ShowDialog().ToDialogResult();
83 | ViewModel.FileName = dlg.FileName;
84 |
85 | }
86 | private void ShowSaveFileDialog()
87 | {
88 | SaveFileDialog dlg = new SaveFileDialog();
89 | dlg.Title = ViewModel.Title;
90 | dlg.FileName = ViewModel.FileName;
91 | dlg.Filter = ViewModel.FileDialogFilter;
92 |
93 | ViewModel.Result = dlg.ShowDialog().ToDialogResult();
94 | ViewModel.FileName = dlg.FileName;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Cutter.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Data;
5 | using System.Windows.Documents;
6 | using System.Windows.Input;
7 | using System.Windows.Media;
8 | using System.Windows.Media.Imaging;
9 | using System.Windows.Navigation;
10 | using System.Reactive.Linq;
11 | using System.Reactive.Disposables;
12 |
13 | using ReactiveUI;
14 |
15 | using SimpleStateMachineNodeEditor.Helpers;
16 | using SimpleStateMachineNodeEditor.ViewModel;
17 |
18 |
19 | namespace SimpleStateMachineNodeEditor.View
20 | {
21 | ///
22 | /// Interaction logic for ViewCutter.xaml
23 | ///
24 | public partial class Cutter : UserControl, IViewFor
25 | {
26 | #region ViewModel
27 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(CutterViewModel), typeof(Cutter), new PropertyMetadata(null));
28 |
29 | public CutterViewModel ViewModel
30 | {
31 | get { return (CutterViewModel)GetValue(ViewModelProperty); }
32 | set { SetValue(ViewModelProperty, value); }
33 | }
34 |
35 | object IViewFor.ViewModel
36 | {
37 | get { return ViewModel; }
38 | set { ViewModel = (CutterViewModel)value; }
39 | }
40 | #endregion ViewModel
41 | public Cutter()
42 | {
43 | InitializeComponent();
44 | SetupBinding();
45 | SetupEvents();
46 | }
47 | #region Setup Binding
48 | private void SetupBinding()
49 | {
50 | this.WhenActivated(disposable =>
51 | {
52 |
53 | this.OneWayBind(this.ViewModel, x => x.Visible, x => x.Visibility).DisposeWith(disposable);
54 |
55 | this.OneWayBind(this.ViewModel, x => x.StartPoint.X, x => x.LineElement.X1).DisposeWith(disposable);
56 |
57 | this.OneWayBind(this.ViewModel, x => x.StartPoint.Y, x => x.LineElement.Y1).DisposeWith(disposable);
58 |
59 | this.OneWayBind(this.ViewModel, x => x.EndPoint.X, x => x.LineElement.X2).DisposeWith(disposable);
60 |
61 | this.OneWayBind(this.ViewModel, x => x.EndPoint.Y, x => x.LineElement.Y2).DisposeWith(disposable);
62 |
63 | this.OneWayBind(this.ViewModel, x => x.StrokeThickness, x => x.LineElement.StrokeThickness).DisposeWith(disposable);
64 |
65 | this.WhenAnyValue(x => x.Visibility).Where(x=>x==Visibility.Visible).Subscribe(_ => Update()).DisposeWith(disposable);
66 |
67 | });
68 | }
69 | private void Update()
70 | {
71 | Mouse.Capture(this);
72 | Keyboard.Focus(this);
73 | }
74 |
75 | #endregion Setup Binding
76 |
77 | #region Setup Events
78 |
79 | private void SetupEvents()
80 | {
81 | this.WhenActivated(disposable =>
82 | {
83 | this.Events().MouseMove.Subscribe(e => OnMouseMoves(e)).DisposeWith(disposable);
84 | this.Events().MouseLeftButtonUp.Subscribe(e => OnMouseLeftButtonUp(e)).DisposeWith(disposable);
85 | });
86 | }
87 | private void OnMouseMoves(MouseEventArgs e)
88 | {
89 | NodesCanvas NodesCanvas = MyUtils.FindParent(this);
90 | ViewModel.EndPoint = e.GetPosition(NodesCanvas.CanvasElement);
91 |
92 | e.Handled = true;
93 |
94 | }
95 | private void OnMouseLeftButtonUp(MouseEventArgs e)
96 | {
97 | this.ViewModel.Visible = null;
98 | }
99 |
100 | #endregion Setup Events
101 |
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/MainWindow/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using DynamicData;
2 | using DynamicData.Binding;
3 | using ReactiveUI;
4 | using ReactiveUI.Fody.Helpers;
5 | using System;
6 | using SimpleStateMachineNodeEditor.Helpers.Enums;
7 | using System.Reactive.Linq;
8 | using System.Linq;
9 | using DynamicData.Alias;
10 |
11 | namespace SimpleStateMachineNodeEditor.ViewModel
12 | {
13 | public partial class MainWindowViewModel : ReactiveObject
14 | {
15 | public ObservableCollectionExtended Messages { get; set; } = new ObservableCollectionExtended();
16 |
17 | [Reactive] public NodesCanvasViewModel NodesCanvas { get; set; }
18 | [Reactive] public TypeMessage DisplayMessageType { get; set; }
19 | [Reactive] public bool? DebugEnable { get; set; } = true;
20 |
21 | [Reactive] public int CountError { get; set; }
22 | [Reactive] public int CountWarning { get; set; }
23 | [Reactive] public int CountInformation { get; set; }
24 | [Reactive] public int CountDebug { get; set; }
25 |
26 | private IDisposable ConnectToMessages;
27 | public double DefaultHeightMessagePanel = 150;
28 | public double DefaultWidthTransitionsTable = 350;
29 | public ObservableCollectionExtended Transitions { get; set; } = new ObservableCollectionExtended();
30 |
31 |
32 | public MainWindowViewModel(NodesCanvasViewModel viewModelNodesCanvas)
33 | {
34 | NodesCanvas = viewModelNodesCanvas;
35 | NodesCanvas.Nodes.Connect().TransformMany(x=>x.Transitions).AutoRefresh(x => x.Name).Filter(x=> Filter(x.Name)).Bind(Transitions).Subscribe();
36 | bool Filter(string name)
37 | {
38 | return !string.IsNullOrEmpty(name);
39 | }
40 | SetupCommands();
41 | SetupSubscriptions();
42 | }
43 |
44 | #region Setup Subscriptions
45 |
46 | private void SetupSubscriptions()
47 | {
48 | this.WhenAnyValue(x => x.NodesCanvas.DisplayMessageType).Subscribe(_ => UpdateMessages());
49 | this.WhenAnyValue(x => x.NodesCanvas.Messages.Count).Subscribe(_ => UpdateCountMessages());
50 |
51 | }
52 | private void UpdateMessages()
53 | {
54 | ConnectToMessages?.Dispose();
55 | Messages.Clear();
56 |
57 | bool debugEnable = DebugEnable.HasValue && DebugEnable.Value;
58 | bool displayAll = this.NodesCanvas.DisplayMessageType == TypeMessage.All;
59 |
60 | ConnectToMessages = this.NodesCanvas.Messages.ToObservableChangeSet().Filter(x => CheckForDisplay(x.TypeMessage)).ObserveOnDispatcher().Bind(Messages).DisposeMany().Subscribe();
61 |
62 | bool CheckForDisplay(TypeMessage typeMessage)
63 | {
64 | if (typeMessage == this.NodesCanvas.DisplayMessageType)
65 | {
66 | return true;
67 | }
68 | else if (typeMessage == TypeMessage.Debug)
69 | {
70 | return debugEnable && displayAll;
71 | }
72 |
73 | return displayAll;
74 | }
75 | }
76 | private void UpdateCountMessages()
77 | {
78 | var counts = NodesCanvas.Messages.GroupBy(x => x.TypeMessage).ToDictionary(x => x.Key, x => x.Count());
79 | CountError = counts.Keys.Contains(TypeMessage.Error) ? counts[TypeMessage.Error] : 0;
80 | CountWarning = counts.Keys.Contains(TypeMessage.Warning) ? counts[TypeMessage.Warning] : 0;
81 | CountInformation = counts.Keys.Contains(TypeMessage.Information) ? counts[TypeMessage.Information] : 0;
82 | CountDebug = counts.Keys.Contains(TypeMessage.Debug) ? counts[TypeMessage.Debug] : 0;
83 | }
84 |
85 | #endregion Setup Subscriptions
86 |
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/Selector.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Data;
5 | using System.Windows.Documents;
6 | using System.Windows.Input;
7 | using System.Windows.Media;
8 | using System.Windows.Media.Imaging;
9 | using System.Windows.Navigation;
10 | using System.Reactive.Linq;
11 | using System.Reactive.Disposables;
12 |
13 | using ReactiveUI;
14 |
15 | using SimpleStateMachineNodeEditor.Helpers;
16 | using SimpleStateMachineNodeEditor.ViewModel;
17 |
18 |
19 | namespace SimpleStateMachineNodeEditor.View
20 | {
21 | ///
22 | /// Interaction logic for ViewSelector.xaml
23 | ///
24 | public partial class Selector : UserControl, IViewFor
25 | {
26 | #region ViewModel
27 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
28 | typeof(SelectorViewModel), typeof(Selector), new PropertyMetadata(null));
29 |
30 | public SelectorViewModel ViewModel
31 | {
32 | get { return (SelectorViewModel)GetValue(ViewModelProperty); }
33 | set { SetValue(ViewModelProperty, value); }
34 | }
35 |
36 | object IViewFor.ViewModel
37 | {
38 | get { return ViewModel; }
39 | set { ViewModel = (SelectorViewModel)value; }
40 | }
41 | #endregion ViewModel
42 | public Selector()
43 | {
44 | InitializeComponent();
45 | SetupBinding();
46 | SetupEvents();
47 | }
48 | protected override void OnMouseMove(MouseEventArgs e)
49 | {
50 | base.OnMouseMove(e);
51 |
52 | }
53 | #region Setup Binding
54 | private void SetupBinding()
55 | {
56 | this.WhenActivated(disposable =>
57 | {
58 | this.OneWayBind(this.ViewModel, x => x.Visible, x => x.Visibility).DisposeWith(disposable);
59 |
60 | this.OneWayBind(this.ViewModel, x => x.Size.Width, x => x.Rectangle.Width).DisposeWith(disposable);
61 |
62 | this.OneWayBind(this.ViewModel, x => x.Size.Height, x => x.Rectangle.Height).DisposeWith(disposable);
63 |
64 | this.OneWayBind(this.ViewModel, x => x.Point1.X, x => x.TranslateTransformElement.X).DisposeWith(disposable);
65 |
66 | this.OneWayBind(this.ViewModel, x => x.Point1.Y, x => x.TranslateTransformElement.Y).DisposeWith(disposable);
67 |
68 | this.OneWayBind(this.ViewModel, x => x.Scale.Scales.X, x => x.ScaleTransformElement.ScaleX).DisposeWith(disposable);
69 |
70 | this.OneWayBind(this.ViewModel, x => x.Scale.Scales.Y, x => x.ScaleTransformElement.ScaleY).DisposeWith(disposable);
71 |
72 | this.WhenAnyValue(x => x.Visibility).Where(IsVisible => IsVisible==Visibility.Visible).Subscribe(_ => Update()).DisposeWith(disposable);
73 | });
74 | }
75 |
76 | #endregion Setup Binding
77 |
78 | #region Setup Events
79 |
80 | private void Update()
81 | {
82 | Mouse.Capture(this);
83 | Keyboard.Focus(this);
84 | }
85 | private void SetupEvents()
86 | {
87 | this.WhenActivated(disposable =>
88 | {
89 | this.Events().MouseMove.Subscribe(e => OnMouseMoves(e));
90 | this.Events().MouseLeftButtonUp.Subscribe(e => OnMouseLeftButtonUp(e));
91 |
92 | });
93 | }
94 |
95 | private void OnMouseMoves(MouseEventArgs e)
96 | {
97 | //find canvas
98 | NodesCanvas NodesCanvas = MyUtils.FindParent(this);
99 | ViewModel.Point2 = e.GetPosition(NodesCanvas.CanvasElement);
100 |
101 | e.Handled = true;
102 | }
103 | private void OnMouseLeftButtonUp(MouseEventArgs e)
104 | {
105 | this.ViewModel.Visible = null;
106 | }
107 |
108 | #endregion Setup Events
109 |
110 |
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Themes/Light.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | #E5eeeef2
83 |
84 |
85 |
86 | #414141
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Theme.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/SimpleStateMachineNodeEditor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 | SimpleStateMachineNodeEditor.App
8 | StateMachine.ico
9 | false
10 | 2.0.0
11 | MIT
12 | https://github.com/SimpleStateMachine/SimpleStateMachineNodeEditor
13 | SimpleStateMachine.png
14 | https://github.com/SimpleStateMachine/SimpleStateMachineNodeEditor
15 | statemachine state-machine finite-state-machine
16 | false
17 | Node editor for SimpleStateMachine
18 | 2.0.0.0
19 | 2.0.0.0
20 | Correct scaling
21 | Config for save last selected theme
22 | New format for xml file with schemes
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | True
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | PreserveNewest
81 |
82 |
83 |
84 |
85 |
86 | Designer
87 |
88 |
89 | Designer
90 |
91 |
92 | Designer
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Connect/ConnectViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Windows;
4 | using System.Windows.Media;
5 | using System.Reactive.Linq;
6 |
7 | using ReactiveUI;
8 | using ReactiveUI.Fody.Helpers;
9 |
10 | using SimpleStateMachineNodeEditor.Helpers;
11 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
12 |
13 | namespace SimpleStateMachineNodeEditor.ViewModel
14 | {
15 | public class ConnectViewModel : ReactiveObject
16 | {
17 | [Reactive] public Point StartPoint { get; set; }
18 | [Reactive] public Point EndPoint { get; set; }
19 | [Reactive] public Point Point1 { get; set; }
20 | [Reactive] public Point Point2 { get; set; }
21 |
22 | [Reactive] public Brush Stroke { get; set; } = Application.Current.Resources["ColorConnect"] as SolidColorBrush;
23 |
24 | [Reactive] public ConnectorViewModel FromConnector { get; set; }
25 |
26 | [Reactive] public ConnectorViewModel ToConnector { get; set; }
27 |
28 | [Reactive] public NodesCanvasViewModel NodesCanvas { get; set; }
29 |
30 | [Reactive] public DoubleCollection StrokeDashArray { get; set; } = new DoubleCollection() { 10, 3 };
31 |
32 | [Reactive] public double StrokeThickness { get; set; } = 1;
33 |
34 | private IDisposable subscriptionOnConnectorPositionChange;
35 | private IDisposable subscriptionOnOutputPositionChange;
36 |
37 | public ConnectViewModel(NodesCanvasViewModel viewModelNodesCanvas, ConnectorViewModel fromConnector)
38 | {
39 | Initial(viewModelNodesCanvas, fromConnector);
40 | SetupSubscriptions();
41 | }
42 | #region Setup Subscriptions
43 |
44 | private void SetupSubscriptions()
45 | {
46 | this.WhenAnyValue(x => x.StartPoint, x => x.EndPoint).Subscribe(_ => UpdateMedium());
47 | this.WhenAnyValue(x => x.FromConnector.Node.IsCollapse).Subscribe(value => UpdateSubscriptionForPosition(value));
48 | this.WhenAnyValue(x => x.ToConnector.PositionConnectPoint).Subscribe(value => EndPointUpdate(value));
49 | this.WhenAnyValue(x => x.FromConnector.Selected).Subscribe(value => Select(value));
50 | this.WhenAnyValue(x => x.NodesCanvas.Theme).Subscribe(_ => Select(this.FromConnector.Selected));
51 | this.WhenAnyValue(x => x.ToConnector).Where(x => x != null).Subscribe(_ => StrokeDashArray = null);
52 | }
53 | private void UpdateSubscriptionForPosition(bool nodeIsCollapse)
54 | {
55 | if(!nodeIsCollapse)
56 | {
57 | subscriptionOnOutputPositionChange?.Dispose();
58 | subscriptionOnConnectorPositionChange = this.WhenAnyValue(x => x.FromConnector.PositionConnectPoint).Subscribe(value => StartPointUpdate(value));
59 |
60 | }
61 | else
62 | {
63 | subscriptionOnConnectorPositionChange?.Dispose();
64 | subscriptionOnOutputPositionChange = this.WhenAnyValue(x => x.FromConnector.Node.Output.PositionConnectPoint).Subscribe(value => StartPointUpdate(value));
65 | }
66 | }
67 | private void Initial(NodesCanvasViewModel viewModelNodesCanvas, ConnectorViewModel fromConnector)
68 | {
69 | NodesCanvas = viewModelNodesCanvas;
70 | FromConnector = fromConnector;
71 | FromConnector.Connect = this;
72 | this.EndPoint = fromConnector.PositionConnectPoint;
73 | }
74 | private void Select(bool value)
75 | {
76 | this.Stroke = Application.Current.Resources[value ? "ColorSelectedElement": "ColorConnect"] as SolidColorBrush;
77 | }
78 | private void StartPointUpdate(Point point)
79 | {
80 | StartPoint = point;
81 | }
82 | private void EndPointUpdate(Point point)
83 | {
84 | EndPoint = point;
85 | }
86 | private void UpdateMedium()
87 | {
88 | Point different = EndPoint.Subtraction(StartPoint);
89 | Point1 = new Point(StartPoint.X + 3 * different.X / 8, StartPoint.Y + 1 * different.Y / 8);
90 | Point2 = new Point(StartPoint.X + 5 * different.X / 8, StartPoint.Y + 7 * different.Y / 8);
91 | }
92 |
93 | #endregion Setup Subscriptions
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/Themes/Dark.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | #E52D2D2D
83 |
84 |
85 |
86 |
87 | #90123d6a
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/MainWindow/CustomWindowTemplate.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
69 |
70 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/LeftConnector.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Data;
5 | using System.Windows.Documents;
6 | using System.Windows.Input;
7 | using System.Windows.Media;
8 | using System.Windows.Media.Imaging;
9 | using System.Windows.Navigation;
10 | using System.Reactive.Linq;
11 | using System.Reactive.Disposables;
12 |
13 | using ReactiveUI;
14 |
15 | using SimpleStateMachineNodeEditor.Helpers;
16 | using SimpleStateMachineNodeEditor.ViewModel;
17 | using System.Windows.Shapes;
18 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
19 |
20 | namespace SimpleStateMachineNodeEditor.View
21 | {
22 | ///
23 | /// Interaction logic for ViewLeftConnector.xaml
24 | ///
25 | public partial class LeftConnector : UserControl, IViewFor
26 | {
27 | #region ViewModel
28 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(ConnectorViewModel), typeof(LeftConnector), new PropertyMetadata(null));
29 |
30 | public ConnectorViewModel ViewModel
31 | {
32 | get { return (ConnectorViewModel)GetValue(ViewModelProperty); }
33 | set { SetValue(ViewModelProperty, value); }
34 | }
35 |
36 | object IViewFor.ViewModel
37 | {
38 | get { return ViewModel; }
39 | set { ViewModel = (ConnectorViewModel)value; }
40 | }
41 | #endregion ViewModel
42 | public LeftConnector()
43 | {
44 | InitializeComponent();
45 | SetupBinding();
46 | SetupEvents();
47 | }
48 |
49 | #region SetupBinding
50 | private void SetupBinding()
51 | {
52 | this.WhenActivated(disposable =>
53 | {
54 |
55 | this.OneWayBind(this.ViewModel, x => x.Name, x => x.TextBoxElement.Text).DisposeWith(disposable);
56 |
57 | this.OneWayBind(this.ViewModel, x => x.TextEnable, x => x.TextBoxElement.IsEnabled).DisposeWith(disposable);
58 |
59 | this.OneWayBind(this.ViewModel, x => x.FormEnable, x => x.EllipseElement.IsEnabled).DisposeWith(disposable);
60 |
61 | this.OneWayBind(this.ViewModel, x => x.Foreground, x => x.TextBoxElement.Foreground).DisposeWith(disposable);
62 |
63 | this.OneWayBind(this.ViewModel, x => x.FormStroke, x => x.EllipseElement.Stroke).DisposeWith(disposable);
64 |
65 | this.OneWayBind(this.ViewModel, x => x.FormFill, x => x.EllipseElement.Fill).DisposeWith(disposable);
66 |
67 | this.OneWayBind(this.ViewModel, x => x.Visible, x => x.LeftConnectorElement.Visibility).DisposeWith(disposable);
68 |
69 | });
70 | }
71 | #endregion SetupBinding
72 |
73 | #region SetupEvents
74 | private void SetupEvents()
75 | {
76 | this.WhenActivated(disposable =>
77 | {
78 | this.EllipseElement.Events().Drop.Subscribe(e => OnEventDrop(e)).DisposeWith(disposable);
79 | this.EllipseElement.Events().DragEnter.Subscribe(e => OnEventDragEnter(e)).DisposeWith(disposable);
80 | this.EllipseElement.Events().DragLeave.Subscribe(e => OnEventDragLeave(e)).DisposeWith(disposable);
81 | });
82 | }
83 |
84 | #endregion SetupEvents
85 | private void OnEventDragEnter(DragEventArgs e)
86 | {
87 | this.ViewModel.FormStroke = Application.Current.Resources["ColorConnector"] as SolidColorBrush;
88 | e.Handled = true;
89 | }
90 | private void OnEventDragLeave(DragEventArgs e)
91 | {
92 | this.ViewModel.FormStroke = Application.Current.Resources["ColorNodesCanvasBackground"] as SolidColorBrush;
93 | e.Handled = true;
94 | }
95 | private void OnEventDrop(DragEventArgs e)
96 | {
97 | this.ViewModel.FormStroke = Application.Current.Resources["ColorNodesCanvasBackground"] as SolidColorBrush;
98 | this.ViewModel.CommandConnectPointDrop.ExecuteWithSubscribe();
99 | e.Handled = true;
100 | }
101 | void UpdatePosition()
102 | {
103 | Point positionConnectPoint = EllipseElement.TranslatePoint(new Point(EllipseElement.Width/2, EllipseElement.Height / 2), this);
104 |
105 | NodesCanvas NodesCanvas = MyUtils.FindParent(this);
106 | if (NodesCanvas == null)
107 | return;
108 |
109 | positionConnectPoint = this.TransformToAncestor(NodesCanvas).Transform(positionConnectPoint);
110 |
111 | //this.ViewModel.PositionConnectPoint = positionConnectPoint.Division(this.ViewModel.NodesCanvas.Scale.Value);
112 | this.ViewModel.PositionConnectPoint = positionConnectPoint;
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/TableOfTransitionsItem.xaml.cs:
--------------------------------------------------------------------------------
1 | using ReactiveUI;
2 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
3 | using SimpleStateMachineNodeEditor.ViewModel;
4 | using System;
5 | using System.Reactive.Disposables;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 |
15 | namespace SimpleStateMachineNodeEditor.View
16 | {
17 | ///
18 | /// Логика взаимодействия для Test.xaml
19 | ///
20 | public partial class TableOfTransitionsItem : UserControl, IViewFor
21 | {
22 | #region ViewModel
23 | public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(ConnectorViewModel), typeof(TableOfTransitionsItem), new PropertyMetadata(null));
24 |
25 | public ConnectorViewModel ViewModel
26 | {
27 | get { return (ConnectorViewModel)GetValue(ViewModelProperty); }
28 | set { SetValue(ViewModelProperty, value); }
29 | }
30 |
31 | object IViewFor.ViewModel
32 | {
33 | get { return ViewModel; }
34 | set { ViewModel = (ConnectorViewModel)value; }
35 | }
36 | #endregion ViewModel
37 | public TableOfTransitionsItem()
38 | {
39 | InitializeComponent();
40 | SetupBinding();
41 | SetupEvents();
42 | }
43 |
44 | #region SetupBinding
45 | private void SetupBinding()
46 | {
47 | this.WhenActivated(disposable =>
48 | {
49 | this.OneWayBind(this.ViewModel, x => x.Node.Name, x => x.TextBoxElementStateFrom.Text).DisposeWith(disposable);
50 | this.OneWayBind(this.ViewModel, x => x.Name, x => x.TextBoxElementTransitionName.Text).DisposeWith(disposable);
51 | if (this.ViewModel.ItsLoop)
52 | this.OneWayBind(this.ViewModel, x => x.Node.Name, x => x.TextBoxElementStateTo.Text).DisposeWith(disposable);
53 | else
54 | this.OneWayBind(this.ViewModel, x => x.Connect.ToConnector.Node.Name, x => x.TextBoxElementStateTo.Text).DisposeWith(disposable);
55 | });
56 |
57 | }
58 | #endregion SetupBinding
59 |
60 | #region SetupEvents
61 |
62 | private void SetupEvents()
63 | {
64 | this.WhenActivated(disposable =>
65 | {
66 | this.TextBoxElementTransitionName.Events().LostFocus.Subscribe(e => ValidateTransitionName(e)).DisposeWith(disposable);
67 | this.TextBoxElementStateFrom.Events().LostFocus.Subscribe(e => ValidateStateFrom(e)).DisposeWith(disposable);
68 | this.TextBoxElementStateTo.Events().LostFocus.Subscribe(e => ValidateStateTo(e)).DisposeWith(disposable);
69 | });
70 | }
71 | private void ValidateTransitionName(RoutedEventArgs e)
72 | {
73 | if (TextBoxElementTransitionName.Text != ViewModel.Name)
74 | ViewModel.CommandValidateName.ExecuteWithSubscribe(TextBoxElementTransitionName.Text);
75 | if (TextBoxElementTransitionName.Text != ViewModel.Name)
76 | TextBoxElementTransitionName.Text = ViewModel.Name;
77 | }
78 | private void ValidateStateFrom(RoutedEventArgs e)
79 | {
80 | if (TextBoxElementStateFrom.Text != ViewModel.Node.Name)
81 | ViewModel.Node.CommandValidateName.ExecuteWithSubscribe(TextBoxElementStateFrom.Text);
82 | if (TextBoxElementStateFrom.Text != ViewModel.Node.Name)
83 | TextBoxElementStateFrom.Text = ViewModel.Node.Name;
84 | }
85 | private void ValidateStateTo(RoutedEventArgs e)
86 | {
87 | if (this.ViewModel.ItsLoop)
88 | ValidateStateToLoop();
89 | else
90 | ValidateStateTo();
91 | }
92 | private void ValidateStateToLoop()
93 | {
94 | if (TextBoxElementStateTo.Text != ViewModel.Node.Name)
95 | this.ViewModel.Node.CommandValidateName.ExecuteWithSubscribe(TextBoxElementStateTo.Text);
96 | if (TextBoxElementStateTo.Text != ViewModel.Node.Name)
97 | TextBoxElementStateTo.Text = ViewModel.Node.Name;
98 | }
99 | private void ValidateStateTo()
100 | {
101 | if (TextBoxElementStateTo.Text != this.ViewModel.Connect.ToConnector.Node.Name)
102 | this.ViewModel.Connect.ToConnector.Node.CommandValidateName.ExecuteWithSubscribe(TextBoxElementStateTo.Text);
103 | if (TextBoxElementStateTo.Text != this.ViewModel.Connect.ToConnector.Node.Name)
104 | TextBoxElementStateTo.Text = this.ViewModel.Connect.ToConnector.Node.Name;
105 | }
106 | #endregion SetupEvents
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/View/NodesCanvas.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
51 |
52 |
53 |
54 |
59 |
64 |
65 |
70 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/Styles/ErrorList/StyleScrollBar.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
21 |
32 |
43 |
92 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Connector/ConnectorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Media;
2 | using System.Windows;
3 |
4 | using ReactiveUI.Fody.Helpers;
5 | using ReactiveUI;
6 |
7 | using SimpleStateMachineNodeEditor.Helpers;
8 | using System;
9 | using System.Xml.Linq;
10 | using System.Linq;
11 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
12 | using System.Reactive.Linq;
13 | using DynamicData;
14 |
15 | namespace SimpleStateMachineNodeEditor.ViewModel
16 | {
17 | public partial class ConnectorViewModel : ReactiveObject
18 | {
19 | [Reactive] public Point PositionConnectPoint { get; set; }
20 | [Reactive] public string Name { get; set; }
21 | [Reactive] public bool TextEnable { get; set; } = false;
22 | [Reactive] public bool? Visible { get; set; } = true;
23 | [Reactive] public bool FormEnable { get; set; } = true;
24 | [Reactive] public Brush FormStroke { get; set; }
25 | [Reactive] public Brush FormFill { get; set; }
26 | [Reactive] public Brush Foreground { get; set; }
27 | [Reactive] public double FormStrokeThickness { get; set; } = 1;
28 | [Reactive] public NodeViewModel Node { get; set; }
29 | [Reactive] public ConnectViewModel Connect { get; set; }
30 | [Reactive] public bool ItsLoop { get; set; } = false;
31 | [Reactive] public NodesCanvasViewModel NodesCanvas { get; set; }
32 | [Reactive] public bool Selected { get; set; }
33 |
34 | [Reactive] public SourceList test { get; set; }
35 |
36 | public ConnectorViewModel(NodesCanvasViewModel nodesCanvas, NodeViewModel viewModelNode, string name, Point myPoint)
37 | {
38 | Node = viewModelNode;
39 | NodesCanvas = nodesCanvas;
40 | Name = name;
41 | PositionConnectPoint = myPoint;
42 | SetupCommands();
43 | SetupSubscriptions();
44 | }
45 | #region Setup Subscriptions
46 | private void SetupSubscriptions()
47 | {
48 | this.WhenAnyValue(x => x.Selected).Subscribe(value => Select(value));
49 | this.WhenAnyValue(x => x.NodesCanvas.Theme).Subscribe(_ => UpdateResources());
50 |
51 | if (this.Name!="Input")
52 | {
53 | this.WhenAnyValue(x => x.Node.HeaderWidth).Buffer(2, 1).Subscribe(x => UpdatePositionOnWidthChange(x[1] - x[0]));
54 | if (this.Name != "Output")
55 | {
56 | this.WhenAnyValue(x => x.Node.TransitionsForView.Count).Subscribe(x => UpdatePositionOnTransitionCountChange());
57 | }
58 |
59 | }
60 |
61 | this.WhenAnyValue(x => x.Node.Point1).Buffer(2, 1).Subscribe(value => PositionConnectPoint = PositionConnectPoint.Addition(value[1].Subtraction(value[0])));
62 | }
63 |
64 | private void UpdatePositionOnTransitionCountChange()
65 | {
66 | if (!string.IsNullOrEmpty(Name))
67 | {
68 | int index = Node.Transitions.Items.IndexOf(this);
69 | this.PositionConnectPoint = Node.CurrentConnector.PositionConnectPoint.Addition(0, index*19);
70 | }
71 | }
72 | private void UpdatePositionOnWidthChange(double value)
73 | {
74 | this.PositionConnectPoint = this.PositionConnectPoint.Addition(value, 0);
75 | }
76 | private void UpdateResources()
77 | {
78 | Select(this.Selected);
79 | if (this.ItsLoop)
80 | {
81 | ToLoop();
82 | }
83 | }
84 |
85 |
86 | #endregion Setup Subscriptions
87 | public XElement ToXElement()
88 | {
89 | XElement element = new XElement("Transition");
90 | element.Add(new XAttribute("Name", Name));
91 | element.Add(new XAttribute("From", Node.Name));
92 | var ToConnectorName = this.Connect?.ToConnector?.Node.Name;
93 | element.Add(new XAttribute("To", ToConnectorName?? Node.Name));
94 |
95 | return element;
96 | }
97 |
98 | public static ConnectViewModel FromXElement(NodesCanvasViewModel nodesCanvas,XElement node, out string errorMessage, Func actionForCheck)
99 | {
100 | ConnectViewModel viewModelConnect = null;
101 |
102 | errorMessage = null;
103 | string name = node.Attribute("Name")?.Value;
104 | string from = node.Attribute("From")?.Value;
105 | string to = node.Attribute("To")?.Value;
106 |
107 | if (string.IsNullOrEmpty(name))
108 | {
109 | errorMessage = "Connect without name";
110 | return viewModelConnect;
111 | }
112 | if (string.IsNullOrEmpty(from))
113 | {
114 | errorMessage = "Connect without from point";
115 | return viewModelConnect;
116 | }
117 | if (string.IsNullOrEmpty(to))
118 | {
119 | errorMessage = "Connect without to point";
120 | return viewModelConnect;
121 | }
122 | if (actionForCheck(name))
123 | {
124 | errorMessage = String.Format("Contains more than one connect with name \"{0}\"", name);
125 | return viewModelConnect;
126 | }
127 |
128 | NodeViewModel nodeFrom = nodesCanvas.Nodes.Items.Single(x => x.Name == from);
129 | NodeViewModel nodeTo = nodesCanvas.Nodes.Items.Single(x => x.Name == to);
130 |
131 | nodeFrom.CurrentConnector.Name = name;
132 |
133 |
134 | if (nodeFrom == nodeTo)
135 | {
136 | nodeFrom.CurrentConnector.CommandSetAsLoop.ExecuteWithSubscribe();
137 | }
138 | else
139 | {
140 | viewModelConnect = new ConnectViewModel(nodeFrom.NodesCanvas, nodeFrom.CurrentConnector);
141 | viewModelConnect.ToConnector = nodeTo.Input;
142 | nodeFrom.CommandAddEmptyConnector.ExecuteWithSubscribe();
143 | }
144 |
145 | return viewModelConnect;
146 | }
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/SimpleStateMachineNodeEditor/ViewModel/Node/NodeViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Media;
4 | using System.Reactive.Linq;
5 |
6 | using ReactiveUI;
7 | using ReactiveUI.Fody.Helpers;
8 | using ReactiveUI.Validation.Helpers;
9 |
10 | using DynamicData.Binding;
11 | using System.Linq;
12 | using System.Xml.Linq;
13 | using SimpleStateMachineNodeEditor.Helpers.Extensions;
14 | using DynamicData;
15 | using System.Collections.ObjectModel;
16 |
17 | namespace SimpleStateMachineNodeEditor.ViewModel
18 | {
19 | public partial class NodeViewModel : ReactiveValidationObject
20 | {
21 | [Reactive] public Point Point1 { get; set; }
22 | [Reactive] public Point Point2 { get; set; }
23 | [Reactive] public Size Size { get; set; }
24 | [Reactive] public string Name { get; set; }
25 | [Reactive] public bool NameEnable { get; set; } = true;
26 | [Reactive] public bool Selected { get; set; }
27 | [Reactive] public Brush BorderBrush { get; set; } = Application.Current.Resources["ColorNodeBorder"] as SolidColorBrush;
28 | [Reactive] public bool? TransitionsVisible { get; set; } = true;
29 | [Reactive] public bool? RollUpVisible { get; set; } = true;
30 | [Reactive] public bool CanBeDelete { get; set; } = true;
31 | [Reactive] public bool IsCollapse { get; set; }
32 | [Reactive] public ConnectorViewModel Input { get; set; }
33 | [Reactive] public ConnectorViewModel Output { get; set; }
34 | [Reactive] public ConnectorViewModel CurrentConnector { get; set; }
35 | [Reactive] public NodesCanvasViewModel NodesCanvas { get; set; }
36 | [Reactive] public int IndexStartSelectConnectors { get; set; } = 0;
37 |
38 | [Reactive] public double HeaderWidth { get; set; } = 80;
39 |
40 | public SourceList Transitions { get; set; } = new SourceList();
41 | public ObservableCollectionExtended TransitionsForView = new ObservableCollectionExtended();
42 | public int Zindex { get; private set; }
43 |
44 | private NodeViewModel()
45 | {
46 | SetupCommands();
47 | SetupBinding();
48 | }
49 |
50 |
51 | public NodeViewModel(NodesCanvasViewModel nodesCanvas, string name, Point point = default(Point))
52 | {
53 | NodesCanvas = nodesCanvas;
54 | Name = name;
55 | Zindex = nodesCanvas.Nodes.Count;
56 | Point1 = point;
57 | Transitions.Connect().ObserveOnDispatcher().Bind(TransitionsForView).Subscribe();
58 | SetupConnectors();
59 |
60 | SetupCommands();
61 | SetupBinding();
62 | SetupSubscriptions();
63 | }
64 |
65 | #region SetupBinding
66 | private void SetupBinding()
67 | {
68 | }
69 | #endregion SetupBinding
70 |
71 | #region Setup Subscriptions
72 |
73 | private void SetupSubscriptions()
74 | {
75 | this.WhenAnyValue(x => x.Selected).Subscribe(value => { this.BorderBrush = value ? Application.Current.Resources["ColorSelectedElement"] as SolidColorBrush : Brushes.LightGray; });
76 | this.WhenAnyValue(x => x.TransitionsForView.Count).Buffer(2, 1).Select(x => (Previous: x[0], Current: x[1])).Subscribe(x => UpdateCount(x.Previous, x.Current));
77 | this.WhenAnyValue(x => x.Point1, x => x.Size).Subscribe(_ => UpdatePoint2());
78 | this.WhenAnyValue(x => x.IsCollapse).Subscribe(value => Collapse(value));
79 |
80 | //this.WhenAnyValue(x => x.Transitions.Count).Subscribe(value => UpdateCount(value));
81 | }
82 | private void UpdateCount(int value)
83 | {
84 | NodesCanvas.TransitionsCount++;
85 | }
86 | #endregion Setup Subscriptions
87 | #region Connectors
88 | private void SetupConnectors()
89 | {
90 | Input = new ConnectorViewModel(NodesCanvas, this, "Input", Point1.Addition(0, 30));
91 | Output = new ConnectorViewModel(NodesCanvas, this, "Output", Point1.Addition(80, 54))
92 | {
93 | Visible = null
94 | };
95 | AddEmptyConnector();
96 | }
97 | #endregion Connectors
98 | private void UpdatePoint2()
99 | {
100 | Point2 = Point1.Addition(Size);
101 | }
102 | private void UpdateCount(int oldValue, int newValue)
103 | {
104 | if ((oldValue > 0) && (newValue > oldValue))
105 | {
106 | NodesCanvas.TransitionsCount++;
107 | }
108 | }
109 | private void Collapse(bool value)
110 | {
111 | if (!value)
112 | {
113 |
114 | TransitionsVisible = true;
115 | Output.Visible = null;
116 | }
117 | else
118 | {
119 | TransitionsVisible = null;
120 | Output.Visible = true;
121 | UnSelectedAllConnectors();
122 | }
123 | NotSaved();
124 | }
125 |
126 |
127 | public XElement ToXElement()
128 | {
129 | XElement element = new XElement("State");
130 | element.Add(new XAttribute("Name", Name));
131 | return element;
132 | }
133 | public XElement ToVisualizationXElement()
134 | {
135 | XElement element = ToXElement();
136 | element.Add(new XAttribute("Position", PointExtensition.PointToString(Point1)));
137 | element.Add(new XAttribute("IsCollapse", IsCollapse.ToString()));
138 | return element;
139 | }
140 | public static NodeViewModel FromXElement(NodesCanvasViewModel nodesCanvas, XElement node, out string errorMessage, Func actionForCheck)
141 | {
142 | errorMessage = null;
143 | NodeViewModel viewModelNode = null;
144 | string name = node.Attribute("Name")?.Value;
145 |
146 | if (string.IsNullOrEmpty(name))
147 | {
148 | errorMessage = "Node without name";
149 | return viewModelNode;
150 | }
151 |
152 | if (actionForCheck(name))
153 | {
154 | errorMessage = String.Format("Contains more than one node with name \"{0}\"", name);
155 | return viewModelNode;
156 | }
157 |
158 | viewModelNode = new NodeViewModel(nodesCanvas, name);
159 |
160 | return viewModelNode;
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------