mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-05 16:56:34 +08:00
删除几个非mit的引用
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Layout
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// The network whose nodes are to be repositioned.
|
||||
/// </summary>
|
||||
public DiagramViewModel Network
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A time modifier that is used to speed up, or slow down, time during the simulation.
|
||||
/// A greater time modifier speeds up the physics simulation, at the cost of accuracy and stability.
|
||||
/// </summary>
|
||||
public float TimeModifier { get; set; } = 3.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Number of updates per iteration.
|
||||
/// Increasing this number increases the accuracy of the physics simulation at the cost of performance.
|
||||
/// </summary>
|
||||
public int UpdatesPerIteration { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How strongly should nodes push eachother away?
|
||||
/// A greater NodeRepulsionForce increases the distance between nodes.
|
||||
/// </summary>
|
||||
public float NodeRepulsionForce { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// A function that maps each connection onto the equilibrium distance of its corresponding spring.
|
||||
/// A greater equilibrium distance increases the distance between the two connected endpoints.
|
||||
/// </summary>
|
||||
public Func<ConnectionViewModel, double> EquilibriumDistance { get; set; } = conn => 100;
|
||||
|
||||
/// <summary>
|
||||
/// A function that maps each connection onto the springiness/stiffness constant of its corresponding spring.
|
||||
/// (c.f. Hooke's law)
|
||||
/// </summary>
|
||||
public Func<ConnectionViewModel, double> SpringConstant { get; set; } = conn => 1;
|
||||
|
||||
/// <summary>
|
||||
/// A function that maps each connection onto the strength of its row force.
|
||||
/// Since inputs/outputs are on the left/right of a node, networks tend to be layed out horizontally.
|
||||
/// The row force is added onto the endpoints of the connection to make the nodes end up in a more horizontal layout.
|
||||
/// </summary>
|
||||
public Func<ConnectionViewModel, double> RowForce { get; set; } = conn => 100;
|
||||
|
||||
/// <summary>
|
||||
/// A function that maps each node onto its mass in the physics simulation.
|
||||
/// Greater mass makes the node harder to move.
|
||||
/// </summary>
|
||||
public Func<DesignerItemViewModelBase, float> NodeMass { get; set; } = node => 10;
|
||||
|
||||
/// <summary>
|
||||
/// The friction coefficient is used to control friction forces in the simulation.
|
||||
/// Greater friction makes the simulation converge faster, as it slows nodes down when
|
||||
/// they are swinging around. If the friction is too high, the nodes will stop moving before
|
||||
/// they reach their optimal position or might not even move at all.
|
||||
/// </summary>
|
||||
public Func<DesignerItemViewModelBase, float> FrictionCoefficient { get; set; } = node => 2.5f;
|
||||
|
||||
/// <summary>
|
||||
/// A predicate function that specifies whether or not a node is fixed.
|
||||
/// Fixed nodes do not get moved in the simulation.
|
||||
/// </summary>
|
||||
public Func<DesignerItemViewModelBase, bool> IsFixedNode { get; set; } = node => false;
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Layout
|
||||
{
|
||||
internal class Engine
|
||||
{
|
||||
internal void ApplyRandomShift(DiagramViewModel network)
|
||||
{
|
||||
Random random = new Random();
|
||||
foreach (var node in network.Items.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
node.Position = node.Position + new VectorBase(random.NextDouble(), random.NextDouble());
|
||||
}
|
||||
}
|
||||
|
||||
internal void Update(int deltaTMillis, IState state, Configuration config)
|
||||
{
|
||||
// Calculate forces
|
||||
int nodeCount = config.Network.Items.Count;
|
||||
IList<(DesignerItemViewModelBase, VectorBase)> nodeForces = new List<(DesignerItemViewModelBase, VectorBase)>(nodeCount);
|
||||
|
||||
foreach (var node in config.Network.Items.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
if (!config.IsFixedNode(node))
|
||||
{
|
||||
nodeForces.Add((node, CalculateNodeForce(node, state, config)));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply forces
|
||||
foreach (var (node, force) in nodeForces)
|
||||
{
|
||||
VectorBase speed = state.GetNodeSpeed(node);
|
||||
VectorBase pos = state.GetNodePosition(node);
|
||||
double deltaT = deltaTMillis / 1000.0;
|
||||
state.SetNodePosition(node, pos + ((speed * deltaT) + (force * deltaT * deltaT / 2)));
|
||||
state.SetNodeSpeed(node, speed + ((force / config.NodeMass(node)) * deltaT));
|
||||
}
|
||||
}
|
||||
|
||||
private VectorBase CalculateNodeForce(DesignerItemViewModelBase node, IState state, Configuration config)
|
||||
{
|
||||
VectorBase force = new VectorBase();
|
||||
|
||||
// Calculate total force on node from endpoints
|
||||
if (node.InputConnectors.Count > 0 || node.OutputConnectors.Count > 0)
|
||||
{
|
||||
force += node.InputConnectors.Concat(node.OutputConnectors)
|
||||
.Select(e => CalculateEndpointForce(e, state, config))
|
||||
.Aggregate((v1, v2) => v1 + v2);
|
||||
}
|
||||
|
||||
// Apply node repulsion force so nodes don't overlap
|
||||
var nodeCenter = state.GetNodePosition(node) + (new VectorBase(node.Size.Width, node.Size.Height) / 2.0);
|
||||
foreach (var otherNode in config.Network.Items.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
if (node == otherNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var otherNodeCenter = state.GetNodePosition(otherNode) + (new VectorBase(otherNode.Size.Width, otherNode.Size.Height) / 2.0);
|
||||
var thisToOther = otherNodeCenter - nodeCenter;
|
||||
var dist = thisToOther.Length;
|
||||
thisToOther.Normalize();
|
||||
|
||||
var repulsionX = thisToOther.X * (-1 * ((node.Size.Width + otherNode.Size.Width) / 2) / dist);
|
||||
var repulsionY = thisToOther.Y * (-1 * ((node.Size.Height + otherNode.Size.Height) / 2) / dist);
|
||||
force += new VectorBase(repulsionX, repulsionY) * config.NodeRepulsionForce;
|
||||
}
|
||||
|
||||
// Apply friction to make the movement converge to a stable state.
|
||||
float gravity = 9.8f;
|
||||
float normalForce = gravity * config.NodeMass(node);
|
||||
float kineticFriction = normalForce * config.FrictionCoefficient(node);
|
||||
VectorBase frictionVector = new VectorBase();
|
||||
var nodeSpeed = state.GetNodeSpeed(node);
|
||||
if (nodeSpeed.Length > 0)
|
||||
{
|
||||
frictionVector = new VectorBase(nodeSpeed.X, nodeSpeed.Y);
|
||||
frictionVector.Normalize();
|
||||
frictionVector *= -1.0 * kineticFriction;
|
||||
}
|
||||
force += frictionVector;
|
||||
|
||||
return force;
|
||||
}
|
||||
|
||||
private VectorBase CalculateEndpointForce(ConnectorInfoBase endpoint, IState state, Configuration config)
|
||||
{
|
||||
var pos = state.GetEndpointPosition(endpoint);
|
||||
|
||||
VectorBase force = new VectorBase();
|
||||
|
||||
foreach (var conn in config.Network.Items.OfType<ConnectionViewModel>().Where(p => p.SinkConnectorInfo == endpoint || p.SourceConnectorInfo == endpoint).ToList())
|
||||
{
|
||||
var otherSide = conn.SourceConnectorInfo == endpoint ? conn.SinkConnectorInfo : conn.SourceConnectorInfo;
|
||||
var otherSidePos = state.GetEndpointPosition(otherSide);
|
||||
var dist = (otherSidePos - pos).Length;
|
||||
var angle = Math.Acos((otherSidePos.X - pos.X) / dist);
|
||||
if (otherSidePos.Y < pos.Y)
|
||||
{
|
||||
angle *= -1.0;
|
||||
}
|
||||
|
||||
// Put a spring between connected endpoints.
|
||||
var hookForce = (dist - config.EquilibriumDistance(conn)) * config.SpringConstant(conn);
|
||||
force += new VectorBase(Math.Cos(angle), Math.Sin(angle)) * hookForce;
|
||||
|
||||
// Try to 'straighten' out the graph horizontally.
|
||||
var isLeftSide = endpoint.Orientation == ConnectorOrientation.Left;
|
||||
var rowForce = (isLeftSide ? 1 : -1) * config.RowForce(conn);
|
||||
force.X += rowForce;
|
||||
}
|
||||
|
||||
return force;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Layout
|
||||
{
|
||||
/// <summary>
|
||||
/// Reposition the nodes in a network using a physics-based approach.
|
||||
/// The nodes are interpreted as point masses, and the connections are represented
|
||||
/// by springs. This system, along with a few additional forces such as friction and a
|
||||
/// horizontal force, is then simulated to calculate the new position of the nodes.
|
||||
/// </summary>
|
||||
public class ForceDirectedLayouter
|
||||
{
|
||||
/// <summary>
|
||||
/// Layout the nodes in the network.
|
||||
/// </summary>
|
||||
/// <param name="config">The configuration to use.</param>
|
||||
/// <param name="maxIterations">The maximum amount of iterations after which the physics simulation ends.</param>
|
||||
public void Layout(Configuration config, int maxIterations)
|
||||
{
|
||||
var engine = new Engine();
|
||||
var state = new BufferedState();
|
||||
|
||||
// Move each node so no two nodes have the exact same position.
|
||||
engine.ApplyRandomShift(config.Network);
|
||||
|
||||
int deltaT = (int)Math.Ceiling(10.0 / (double)config.UpdatesPerIteration);
|
||||
for (int i = 0; i < maxIterations * config.UpdatesPerIteration; i++)
|
||||
{
|
||||
engine.Update(deltaT, state, config);
|
||||
}
|
||||
|
||||
foreach (var newNodePosition in state.NodePositions)
|
||||
{
|
||||
newNodePosition.Key.Position = new Point(newNodePosition.Value.X, newNodePosition.Value.Y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Layout the nodes in the network, updating the user interface at each iteration.
|
||||
/// This method, contrary to Layout(), lets users see the simulation as it happens.
|
||||
/// The cancellation token should be used to end the simulation.
|
||||
/// </summary>
|
||||
/// <param name="config">The configuration to use.</param>
|
||||
/// <param name="token">A cancellation token to end the layout process.</param>
|
||||
/// <returns>The async task</returns>
|
||||
public async Task LayoutAsync(Configuration config, CancellationToken token)
|
||||
{
|
||||
var engine = new Engine();
|
||||
var state = new LiveState();
|
||||
|
||||
// Move each node so no two nodes have the exact same position.
|
||||
engine.ApplyRandomShift(config.Network);
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
TimeSpan t = TimeSpan.Zero;
|
||||
do
|
||||
{
|
||||
// Current real time
|
||||
var newT = DateTime.Now - start;
|
||||
var deltaT = newT - t;
|
||||
|
||||
// Current modified time
|
||||
//int virtT = (int)(t.Milliseconds * Settings.TimeModifier);
|
||||
int virtDeltaT = (int)(deltaT.Milliseconds * config.TimeModifier);
|
||||
int virtDeltaTPerUpdate = virtDeltaT / config.UpdatesPerIteration;
|
||||
for (int i = 0; i < config.UpdatesPerIteration; i++)
|
||||
{
|
||||
// Modified time in this update step
|
||||
engine.Update(virtDeltaTPerUpdate, state, config);
|
||||
}
|
||||
|
||||
t = newT;
|
||||
|
||||
await Task.Delay(14, token);
|
||||
} while (!token.IsCancellationRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Layout
|
||||
{
|
||||
internal interface IState
|
||||
{
|
||||
VectorBase GetNodePosition(DesignerItemViewModelBase node);
|
||||
void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos);
|
||||
VectorBase GetEndpointPosition(ConnectorInfoBase endpoint);
|
||||
VectorBase GetNodeSpeed(DesignerItemViewModelBase node);
|
||||
void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed);
|
||||
}
|
||||
|
||||
internal class BufferedState : IState
|
||||
{
|
||||
private readonly Dictionary<DesignerItemViewModelBase, VectorBase> _nodePositions = new Dictionary<DesignerItemViewModelBase, VectorBase>();
|
||||
private readonly Dictionary<ConnectorInfoBase, VectorBase> _endpointRelativePositions = new Dictionary<ConnectorInfoBase, VectorBase>();
|
||||
public IEnumerable<KeyValuePair<DesignerItemViewModelBase, VectorBase>> NodePositions => _nodePositions;
|
||||
|
||||
private readonly Dictionary<DesignerItemViewModelBase, VectorBase> _nodeSpeeds = new Dictionary<DesignerItemViewModelBase, VectorBase>();
|
||||
|
||||
public VectorBase GetNodePosition(DesignerItemViewModelBase node)
|
||||
{
|
||||
if (!_nodePositions.TryGetValue(node, out VectorBase result))
|
||||
{
|
||||
result = new VectorBase(node.Position.X, node.Position.Y);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos)
|
||||
{
|
||||
_nodePositions[node] = pos;
|
||||
}
|
||||
|
||||
public VectorBase GetEndpointPosition(ConnectorInfoBase endpoint)
|
||||
{
|
||||
if (!_endpointRelativePositions.TryGetValue(endpoint, out VectorBase result))
|
||||
{
|
||||
result = new VectorBase(endpoint.MiddlePosition.X, endpoint.MiddlePosition.Y) - GetNodePosition(endpoint.Parent as DesignerItemViewModelBase);
|
||||
_endpointRelativePositions[endpoint] = result;
|
||||
}
|
||||
|
||||
return result + GetNodePosition(endpoint.Parent as DesignerItemViewModelBase);
|
||||
}
|
||||
|
||||
public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
|
||||
{
|
||||
if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
|
||||
{
|
||||
result = new VectorBase(0, 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
|
||||
{
|
||||
_nodeSpeeds[node] = speed;
|
||||
}
|
||||
}
|
||||
|
||||
internal class LiveState : IState
|
||||
{
|
||||
private readonly Dictionary<DesignerItemViewModelBase, VectorBase> _nodeSpeeds = new Dictionary<DesignerItemViewModelBase, VectorBase>();
|
||||
|
||||
public VectorBase GetNodePosition(DesignerItemViewModelBase node)
|
||||
{
|
||||
return new VectorBase(node.Position.X, node.Position.Y);
|
||||
}
|
||||
|
||||
public void SetNodePosition(DesignerItemViewModelBase node, VectorBase pos)
|
||||
{
|
||||
node.Position = new Point(pos.X, pos.Y);
|
||||
}
|
||||
|
||||
public VectorBase GetEndpointPosition(ConnectorInfoBase endpoint)
|
||||
{
|
||||
return new VectorBase(endpoint.MiddlePosition.X, endpoint.MiddlePosition.Y);
|
||||
}
|
||||
|
||||
public VectorBase GetNodeSpeed(DesignerItemViewModelBase node)
|
||||
{
|
||||
if (!_nodeSpeeds.TryGetValue(node, out VectorBase result))
|
||||
{
|
||||
result = new VectorBase(0, 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetNodeSpeed(DesignerItemViewModelBase node, VectorBase speed)
|
||||
{
|
||||
_nodeSpeeds[node] = speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
AIStudio.Wpf.DiagramDesigner/Styles/ToggleButton.xaml
Normal file
96
AIStudio.Wpf.DiagramDesigner/Styles/ToggleButton.xaml
Normal file
@@ -0,0 +1,96 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Style x:Key="AIStudio.DiagramDesigner.Styles.ToggleButton.Flat" TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="Background" Value="LightGray" />
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||
<Grid ClipToBounds="True" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal"/>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Duration="0" To="0.38" Storyboard.TargetProperty="(UIElement.Opacity)" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="CheckStates">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition From="*" To="Checked">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Duration="0:0:0.2" Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="CheckedEllipseScale">
|
||||
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.0" />
|
||||
<LinearDoubleKeyFrame Value="1.0" KeyTime="0:0:0.1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Duration="0:0:0.2" Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="CheckedEllipseScale">
|
||||
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.0" />
|
||||
<LinearDoubleKeyFrame Value="1.0" KeyTime="0:0:0.1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="Checked" To="Unchecked">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Duration="0:0:0.2" Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="CheckedEllipseScale">
|
||||
<LinearDoubleKeyFrame Value="1.0" KeyTime="0:0:0.0" />
|
||||
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Duration="0:0:0.2" Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="CheckedEllipseScale">
|
||||
<LinearDoubleKeyFrame Value="1.0" KeyTime="0:0:0.0" />
|
||||
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0.1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="Checked">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Duration="0" Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="CheckedEllipseScale" To="1.0" />
|
||||
<DoubleAnimation Duration="0" Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="CheckedEllipseScale" To="1.0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Unchecked">
|
||||
<Storyboard>
|
||||
<DoubleAnimation Duration="0" Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="CheckedEllipseScale" To="0" />
|
||||
<DoubleAnimation Duration="0" Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="CheckedEllipseScale" To="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<Rectangle Fill="Transparent" x:Name="HoverEllipse" Stroke="Transparent" StrokeThickness="1" />
|
||||
<Rectangle Fill="{TemplateBinding Background}" x:Name="CheckedEllipse" RenderTransformOrigin="0.5, 0.5">
|
||||
<Rectangle.RenderTransform>
|
||||
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.0" ScaleY="1.0" x:Name="CheckedEllipseScale"/>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Stroke" TargetName="HoverEllipse" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter Property="Background" Value="#f1f1f1"/>
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Opacity" Value=".9"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Opacity" Value=".6"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="0.5"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -9,5 +9,6 @@
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Styles/TextBox.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Styles/ZoomBox.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Styles/ComboBox.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Styles/ToggleButton.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -10,10 +10,8 @@ using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
using AIStudio.Wpf.DiagramDesigner.Layout;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
using Newtonsoft.Json;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
@@ -680,17 +678,7 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
return this._fitHeightCommand ?? (this._fitHeightCommand = new SimpleCommand(ExecuteEnable, ExecuteFitHeightCommand));
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _autoLayoutCommand;
|
||||
public ICommand AutoLayoutCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._autoLayoutCommand ?? (this._autoLayoutCommand = new SimpleCommand(ExecuteEnable, ExecuteAutoLayoutCommand));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ICommand _groupCommand;
|
||||
public ICommand GroupCommand
|
||||
@@ -2462,12 +2450,6 @@ namespace AIStudio.Wpf.DiagramDesigner
|
||||
FitViewModel = new FitViewModel() { BoundingRect = DiagramViewModelHelper.GetBoundingRectangle(Items.OfType<DesignerItemViewModelBase>()), FitMode = FitMode.FitHeight };
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteAutoLayoutCommand(object parameter)
|
||||
{
|
||||
ForceDirectedLayouter layouter = new ForceDirectedLayouter();
|
||||
layouter.Layout(new Configuration { Network = this }, 10000);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 分组
|
||||
|
||||
Reference in New Issue
Block a user