Skip to content

Commit fb6260e

Browse files
committed
resolve #24
1 parent ed596e5 commit fb6260e

13 files changed

+206
-93
lines changed

Diff for: SimpleStateMachineNodeEditor/Helpers/Commands/Command.cs

+11-11
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
namespace SimpleStateMachineNodeEditor.Helpers.Commands
66
{
7-
public class Command<TParameter, TResult> : ICommandWithUndoRedo, ICommand, ICloneable
7+
public class Command<TParameter, TResult> : ICommandWithUndoRedo, ICommand, ICloneable
88
{
99
private readonly Func<TParameter, TResult, TResult> _execute;
1010
private readonly Func<TParameter, TResult, TResult> _unExecute;
1111
public Action OnExecute { get; set; }
1212
public TParameter Parameters { get; set; }
1313
public TResult Result { get; set; }
1414
public object Clone()
15-
{
15+
{
1616
return new Command<TParameter, TResult>(_execute, _unExecute, OnExecute)
1717
{
1818
Parameters = this.Parameters,
@@ -32,7 +32,7 @@ public bool CanExecute(object parameter)
3232
return true;
3333
}
3434

35-
public void Execute(object parameter)
35+
public void Execute(object parameter = default)
3636
{
3737
Parameters = parameter.Cast<TParameter>();
3838

@@ -49,18 +49,18 @@ public void Execute(object parameter)
4949
OnExecute?.Invoke();
5050
}
5151

52-
public void UnExecute()
53-
{
54-
this._unExecute(Parameters, Result);
52+
void ICommandWithUndoRedo.ExecuteWithSubscribe()
53+
{
54+
this.Result = this._execute(this.Parameters, this.Result);
5555

56-
ICommandWithUndoRedo.AddInRedo(this.Clone() as ICommandWithUndoRedo);
56+
ICommandWithUndoRedo.AddInUndo(this.Clone() as ICommandWithUndoRedo);
5757
}
5858

59-
public void ExecuteWithSubscribe()
59+
void ICommandWithUndoRedo.UnExecute()
6060
{
61-
this.Result = this._execute(this.Parameters, this.Result);
61+
this._unExecute(Parameters, Result);
6262

63-
ICommandWithUndoRedo.AddInUndo(this.Clone() as ICommandWithUndoRedo);
63+
ICommandWithUndoRedo.AddInRedo(this.Clone() as ICommandWithUndoRedo);
6464
}
6565

6666
public Command(Func<TParameter, TResult, TResult> ExecuteWithSubscribe, Func<TParameter, TResult, TResult> unExecute, Action onExecute = null)
@@ -69,7 +69,7 @@ public Command(Func<TParameter, TResult, TResult> ExecuteWithSubscribe, Func<TPa
6969

7070
_unExecute = unExecute;
7171

72-
OnExecute += onExecute;
72+
OnExecute += onExecute;
7373
}
7474
}
7575
}

Diff for: SimpleStateMachineNodeEditor/Helpers/Commands/ICommandWithUndoRedo.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ public static void Undo()
2727
}
2828
}
2929

30-
public static ICommandWithUndoRedo AddInRedo(ICommandWithUndoRedo command)
30+
protected static ICommandWithUndoRedo AddInRedo(ICommandWithUndoRedo command)
3131
{
3232
StackRedo.Push(command);
3333

3434
return command;
3535
}
3636

37-
public static ICommandWithUndoRedo AddInUndo(ICommandWithUndoRedo command)
37+
protected static ICommandWithUndoRedo AddInUndo(ICommandWithUndoRedo command)
3838
{
3939
StackUndo.Push(command);
4040

4141
return command;
4242
}
4343

44-
public void ExecuteWithSubscribe();
45-
public void UnExecute();
44+
protected abstract void ExecuteWithSubscribe();
45+
protected abstract void UnExecute();
4646

4747
}
4848
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
}

Diff for: SimpleStateMachineNodeEditor/Styles/MainWindow/ToolBar/TemplateCheckBox.xaml

+26
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,30 @@
2121
</Setter.Value>
2222
</Setter>
2323
</Style>
24+
25+
<Style x:Key="StyleRadioButton" TargetType="{x:Type RadioButton}">
26+
<Setter Property="VerticalAlignment" Value="Center"/>
27+
<Setter Property="HorizontalAlignment" Value="Center"/>
28+
<Setter Property="Height" Value="Auto"/>
29+
<Setter Property="Width" Value="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"/>
30+
<Setter Property="BorderBrush" Value="{x:Null}"/>
31+
<Setter Property="Template">
32+
<Setter.Value>
33+
<ControlTemplate TargetType="{x:Type RadioButton}">
34+
35+
<Border x:Name="border" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true" Padding="{TemplateBinding Padding}">
36+
<ContentPresenter x:Name="contentPresenter" Focusable="True" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
37+
</Border>
38+
<ControlTemplate.Triggers>
39+
<Trigger Property="IsMouseOver" Value="True">
40+
<Setter TargetName="border" Property="Background" Value="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
41+
</Trigger>
42+
<Trigger Property="IsChecked" Value="True">
43+
<Setter TargetName="border" Property="Background" Value="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}" />
44+
</Trigger>
45+
</ControlTemplate.Triggers>
46+
</ControlTemplate>
47+
</Setter.Value>
48+
</Setter>
49+
</Style>
2450
</ResourceDictionary>

Diff for: SimpleStateMachineNodeEditor/View/MainWindow.xaml

+12-15
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,18 @@
161161
<Rectangle Fill="{DynamicResource IconExpandDownAll}" Height="13" Width="13"/>
162162
</Button>
163163
<Separator Grid.Column="5" Style="{DynamicResource TemplateSeparator}" Height="Auto" BorderThickness="0,0,1,0" />
164-
<ToggleButton x:Name="ButtonAddNode" ToolTip="Add node" Style="{DynamicResource TemplateToggleButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
165-
<Rectangle Fill="{DynamicResource IconAddNode}" Height="13" Width="13"/>
166-
</ToggleButton>
167-
<ToggleButton Style="{DynamicResource TemplateToggleButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
168-
<Rectangle Fill="{DynamicResource IconDeleteNode}" Height="13" Width="13"/>
169-
</ToggleButton>
170-
<ToggleButton x:Name="ButtonDeleteNode" ToolTip="Delete Node" Style="{DynamicResource TemplateToggleButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
171-
<Rectangle Fill="{DynamicResource IconDeleteNode}" Height="13" Width="13"/>
172-
</ToggleButton>
173-
<ToggleButton x:Name="ButtonStartSelect" ToolTip="Start select" Style="{DynamicResource TemplateToggleButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
174-
<Rectangle Fill="{DynamicResource IconSelect}" Height="13" Width="13"/>
175-
</ToggleButton>
176-
<ToggleButton x:Name="ButtonStartCut" ToolTip="Start cut" Style="{DynamicResource TemplateToggleButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
177-
<Rectangle Fill="{DynamicResource IconCut}" Height="13" Width="13"/>
178-
</ToggleButton>
164+
<RadioButton x:Name="ButtonAddNode" GroupName="ClickMode" ToolTip="Add node (Ctrl+N)" Style="{DynamicResource StyleRadioButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}" >
165+
<Rectangle Fill="{DynamicResource IconAddNode}" Height="15" Width="15"/>
166+
</RadioButton>
167+
<RadioButton x:Name="ButtonDeleteNode" GroupName="ClickMode" ToolTip="Delete Node (N+Delete)" Style="{DynamicResource StyleRadioButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
168+
<Rectangle Fill="{DynamicResource IconDeleteNode}" Height="15" Width="15"/>
169+
</RadioButton>
170+
<RadioButton x:Name="ButtonStartSelect" GroupName="ClickMode" ToolTip="Start select (Ctrl+LMB)" Style="{DynamicResource StyleRadioButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
171+
<Rectangle Fill="{DynamicResource IconSelect}" Height="15" Width="15"/>
172+
</RadioButton>
173+
<RadioButton x:Name="ButtonStartCut" GroupName="ClickMode" ToolTip="Start cut (Alt+LMB)" Style="{DynamicResource StyleRadioButton}" Background="{DynamicResource ColorWindowHeader}" BorderBrush="{DynamicResource ColorWindowHeaderButtonBackgroundMouseOver}">
174+
<Rectangle Fill="{DynamicResource IconCut}" Height="15" Width="15"/>
175+
</RadioButton>
179176
</ToolBar>
180177

181178
</ToolBarTray>

Diff for: SimpleStateMachineNodeEditor/View/MainWindow.xaml.cs

+19
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ private void SetupEvents()
171171
this.LabelDebug.Events().PreviewMouseLeftButtonDown.Subscribe(e => SetDisplayMessageType(e, TypeMessage.Debug)).DisposeWith(disposable);
172172
this.LabelErrorList.Events().PreviewMouseLeftButtonDown.Subscribe(e=> SetDisplayMessageType(e, TypeMessage.All)).DisposeWith(disposable);
173173
this.LabelErrorListUpdate.Events().MouseLeftButtonDown.WithoutParameter().InvokeCommand(NodesCanvas.ViewModel.CommandErrorListUpdate).DisposeWith(disposable);
174+
175+
this.ButtonAddNode.Events().PreviewMouseLeftButtonDown.Subscribe(e=> RadioButtonUnChecked(ButtonAddNode, NodeCanvasClickMode.AddNode, e )).DisposeWith(disposable);
176+
this.ButtonDeleteNode.Events().PreviewMouseLeftButtonDown.Subscribe(e => RadioButtonUnChecked(ButtonDeleteNode, NodeCanvasClickMode.Delete, e)).DisposeWith(disposable);
177+
this.ButtonStartSelect.Events().PreviewMouseLeftButtonDown.Subscribe(e => RadioButtonUnChecked(ButtonStartSelect, NodeCanvasClickMode.Select, e)).DisposeWith(disposable);
178+
this.ButtonStartCut.Events().PreviewMouseLeftButtonDown.Subscribe(e => RadioButtonUnChecked(ButtonStartCut, NodeCanvasClickMode.Cut, e)).DisposeWith(disposable);
174179
});
175180
}
176181

@@ -181,6 +186,20 @@ private void SetDisplayMessageType(MouseButtonEventArgs e, TypeMessage typeMess
181186

182187
this.ViewModel.NodesCanvas.DisplayMessageType = typeMessage;
183188
}
189+
private void RadioButtonUnChecked(RadioButton radioButton, NodeCanvasClickMode clickMode, MouseButtonEventArgs e)
190+
{
191+
if(radioButton.IsChecked==true)
192+
{
193+
radioButton.IsChecked = false;
194+
e.Handled = true;
195+
196+
ViewModel.NodesCanvas.ClickMode = NodeCanvasClickMode.Default;
197+
}
198+
else
199+
{
200+
ViewModel.NodesCanvas.ClickMode = clickMode;
201+
}
202+
}
184203
private void ErrorListCollapse()
185204
{
186205
this.ErrorListSplitter.IsEnabled = false;

Diff for: SimpleStateMachineNodeEditor/View/Node.xaml.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using SimpleStateMachineNodeEditor.Helpers.Transformations;
2121
using SimpleStateMachineNodeEditor.Helpers.Enums;
2222
using SimpleStateMachineNodeEditor.Helpers.Extensions;
23+
using System.Collections.Generic;
2324

2425
namespace SimpleStateMachineNodeEditor.View
2526
{
@@ -121,8 +122,16 @@ private void OnEventMouseOver(bool value)
121122
}
122123
private void OnEventMouseLeftDowns(MouseButtonEventArgs e)
123124
{
124-
Keyboard.Focus(this);
125-
this.ViewModel.CommandSelect.ExecuteWithSubscribe(SelectMode.Click);
125+
NodeCanvasClickMode clickMode = this.ViewModel.NodesCanvas.ClickMode;
126+
if (clickMode == NodeCanvasClickMode.Delete)
127+
{
128+
this.ViewModel.NodesCanvas.CommandDeleteSelectedNodes.Execute(new List<NodeViewModel>() { this.ViewModel });
129+
}
130+
else
131+
{
132+
Keyboard.Focus(this);
133+
this.ViewModel.CommandSelect.ExecuteWithSubscribe(SelectMode.Click);
134+
}
126135
}
127136
private void Validate(RoutedEventArgs e)
128137
{

Diff for: SimpleStateMachineNodeEditor/View/NodesCanvas.xaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,23 @@
5151
</Border>
5252
<UserControl.ContextMenu >
5353
<ContextMenu Template="{DynamicResource TemplateContextMenu}" Background="{DynamicResource ColorMenuBackground}" Foreground="{DynamicResource ColorMenuForeground}" BorderBrush="{DynamicResource ColorMenuBorder}" OpacityMask="{DynamicResource ColorMenuBackgroundMouseOver}" BorderThickness="1" HorizontalAlignment="Left" VerticalAlignment="Center" >
54-
<MenuItem Header="Add" x:Name="ItemAddNode" InputGestureText="Ctrl + N" Style="{DynamicResource StyleContextMenuItem}" >
54+
<MenuItem Header="Add node" x:Name="ItemAddNode" InputGestureText="Ctrl + N" ToolTip="Add new node on left click position" Style="{DynamicResource StyleContextMenuItem}" >
5555
<MenuItem.Icon>
5656
<Rectangle Fill="{DynamicResource IconAddNode}" Height="13" Width="13"/>
5757
</MenuItem.Icon>
5858
</MenuItem>
59-
<MenuItem Header="Delete" x:Name="ItemDelete" InputGestureText="Delete" Style="{DynamicResource StyleContextMenuItem}">
59+
<MenuItem Header="Delete" x:Name="ItemDelete" InputGestureText="Delete" ToolTip="Delete selected elements" Style="{DynamicResource StyleContextMenuItem}">
6060
<MenuItem.Icon>
61-
<Rectangle Fill="{DynamicResource IconDeleteNode}" Height="15" Width="15"/>
61+
<Rectangle Fill="{DynamicResource IconDeleteScheme}" Height="15" Width="15"/>
6262
</MenuItem.Icon>
6363
</MenuItem>
6464
<Separator Background="#333337"/>
65-
<MenuItem Header="Collaps Up" x:Name="ItemCollapsUp" Style="{DynamicResource StyleContextMenuItem}">
65+
<MenuItem Header="Collaps Up" x:Name="ItemCollapsUp" ToolTip="Collapse Up selected nodes" Style="{DynamicResource StyleContextMenuItem}">
6666
<MenuItem.Icon>
6767
<Rectangle Fill="{DynamicResource IconCollapseUp}" Height="13" Width="13"/>
6868
</MenuItem.Icon>
6969
</MenuItem>
70-
<MenuItem Header="Expand Down" x:Name="ItemExpandDown" Style="{DynamicResource StyleContextMenuItem}">
70+
<MenuItem Header="Expand Down" x:Name="ItemExpandDown" ToolTip="Expand Down selected nodes" Style="{DynamicResource StyleContextMenuItem}">
7171
<MenuItem.Icon>
7272
<Rectangle Fill="{DynamicResource IconExpandDown}" Height="13" Width="13"/>
7373
</MenuItem.Icon>

Diff for: SimpleStateMachineNodeEditor/View/NodesCanvas.xaml.cs

+22-5
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,34 @@ private void SetupEvents()
139139
//this.WhenAnyValue(x => x.ViewModel.Scale.Value).Subscribe(value => { this.Canvas.Height /= value; this.Canvas.Width /= value; }).DisposeWith(disposable);
140140
});
141141
}
142+
143+
142144
private void OnEventMouseLeftDown(MouseButtonEventArgs e)
143145
{
144146
PositionMove = Mouse.GetPosition(this.CanvasElement);
145147

146148
if (Mouse.Captured == null)
147149
{
148-
Keyboard.ClearFocus();
149-
this.CaptureMouse();
150-
Keyboard.Focus(this);
151-
152-
this.ViewModel.CommandUnSelectAll.ExecuteWithSubscribe();
150+
NodeCanvasClickMode clickMode = ViewModel.ClickMode;
151+
if (clickMode == NodeCanvasClickMode.Default)
152+
{
153+
Keyboard.ClearFocus();
154+
this.CaptureMouse();
155+
Keyboard.Focus(this);
156+
this.ViewModel.CommandUnSelectAll.ExecuteWithSubscribe();
157+
}
158+
else if (clickMode == NodeCanvasClickMode.AddNode)
159+
{
160+
this.ViewModel.CommandAddNodeWithUndoRedo.Execute(PositionMove);
161+
}
162+
else if (clickMode == NodeCanvasClickMode.Select)
163+
{
164+
this.ViewModel.CommandSelect.ExecuteWithSubscribe(PositionMove);
165+
}
166+
else if (clickMode == NodeCanvasClickMode.Cut)
167+
{
168+
this.ViewModel.CommandCut.ExecuteWithSubscribe(PositionMove);
169+
}
153170
}
154171
}
155172

0 commit comments

Comments
 (0)