using System; using System.Linq; using System.Windows.Input; using AIStudio.Wpf.DiagramDesigner.Geometrys; using AIStudio.Wpf.DiagramDesigner.Models; using SvgPathProperties; namespace AIStudio.Wpf.DiagramDesigner { public class ConnectorLabelModel : ConnectorPointModel, ISelectable { public ConnectorLabelModel(ConnectionViewModel connector, string content, double? distance = null, PointBase? offset = null) : this(null, connector, content, distance, offset) { } public ConnectorLabelModel(IDiagramViewModel root, ConnectionViewModel connector, string content, double? distance = null, PointBase? offset = null) : base(root) { Parent = connector; Text = content; Distance = distance; Offset = offset ?? new PointBase(); } public ConnectorLabelModel(IDiagramViewModel root, ConnectionViewModel connector, SelectableItemBase designer) : base(root, designer) { Parent = connector; } public ConnectorLabelModel(IDiagramViewModel root, ConnectionViewModel connector, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType) { Parent = connector; } public override SelectableItemBase GetSerializableObject() { return new ConnectorLabelItem(this); } public override void Init(IDiagramViewModel root, bool initNew) { base.Init(root, initNew); DeleteLabelCommand = new SimpleCommand(Command_Enable, DeleteLabel); EditCommand = new SimpleCommand(Command_Enable, ExecuteEditCommand); } protected override void InitNew() { InitIsEditing = true; ConnectorWidth = 30; ConnectorHeight = 30; } protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase) { base.LoadDesignerItemViewModel(designerbase); if (designerbase is ConnectorLabelItem designer) { Distance = designer.Distance; Offset = designer.Offset; } } #region 属性 public ConnectionViewModel Connector { get { return Parent as ConnectionViewModel; } } /// /// 3 types of values are possible: /// - A number between 0 and 1: Position relative to the link's length /// - A positive number, greater than 1: Position away from the start /// - A negative number, less than 0: Position away from the end /// public double? Distance { get; set; } public PointBase Offset { get; set; } public ICommand DeleteLabelCommand { get; set; } public ICommand EditCommand { get; private set; } #endregion private bool updating = false; public void UpdatePosition(SvgPath[] paths) { if (paths == null) return; var position = FindPosition(paths); if (position == null) return; updating = true; X = position.Value.X; Y = position.Value.Y; updating = false; } public PointBase? FindPosition(SvgPath[] paths) { var totalLength = paths.Sum(p => p.Length); double length; if (Distance >= 0 && Distance <= 1) { length = Distance.Value * totalLength; } else if (Distance > 1) { length = Distance.Value; } else if (Distance < 0) { length = totalLength + Distance.Value; } else { length = totalLength * (Connector.Labels.IndexOf(this) + 1) / (Connector.Labels.Count + 1); } foreach (var path in paths) { var pathLength = path.Length; if (length < pathLength) { var pt = path.GetPointAtLength(length); return new PointBase(pt.X + Offset.X, pt.Y + Offset.Y); } length -= pathLength; } return null; } public void UpdateOffsetX(double oldvalue, double newvalue) { if (updating == true) return; Offset += new VectorBase(newvalue - oldvalue, 0); } public void UpdateOffsetY(double oldvalue, double newvalue) { if (updating == true) return; Offset += new VectorBase(0, newvalue - oldvalue); } public override void AddToSelection(bool selected, bool clearother) { if (clearother) { foreach (var item in Connector.Labels.ToList()) { if (item != this) { item.IsSelected = false; } } } IsSelected = selected; } protected override void ClearText() { Connector.RemoveLabel(this); } private void DeleteLabel(object parameter) { if (parameter is ConnectorLabelModel label) { Connector.RemoveLabel(label); } } protected virtual void ExecuteEditCommand(object param) { if (IsReadOnly == true) return; RaisePropertyChanged("ShowText"); } } }