Visual properies of cross section were changed
This commit is contained in:
@@ -2,13 +2,15 @@
|
||||
using StructureHelper.Services.Primitives;
|
||||
using StructureHelper.Windows.MainWindow;
|
||||
using StructureHelper.Windows.ViewModels.NdmCrossSections;
|
||||
using StructureHelperCommon.Models.Shapes;
|
||||
using StructureHelperLogics.NdmCalculations.Primitives;
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace StructureHelper.Infrastructure.UI.DataContexts
|
||||
{
|
||||
public abstract class PrimitiveBase : ViewModelBase
|
||||
public abstract class PrimitiveBase : ViewModelBase, IObserver<IRectangleShape>
|
||||
{
|
||||
#region Поля
|
||||
private IPrimitiveRepository primitiveRepository;
|
||||
@@ -236,12 +238,6 @@ namespace StructureHelper.Infrastructure.UI.DataContexts
|
||||
this.primitive = primitive;
|
||||
}
|
||||
|
||||
public void RegisterDeltas(double dx, double dy)
|
||||
{
|
||||
DeltaX = dx;
|
||||
DeltaY = dy;
|
||||
}
|
||||
|
||||
public CrossSectionViewModel OwnerVM { get; private set; }
|
||||
|
||||
public double DeltaX { get; private set; }
|
||||
@@ -253,14 +249,6 @@ namespace StructureHelper.Infrastructure.UI.DataContexts
|
||||
return primitive;
|
||||
}
|
||||
|
||||
//public virtual void RefreshNdmPrimitive()
|
||||
//{
|
||||
//}
|
||||
|
||||
public void RefreshColor()
|
||||
{
|
||||
OnPropertyChanged(nameof(Color));
|
||||
}
|
||||
public virtual void Refresh()
|
||||
{
|
||||
OnPropertyChanged(nameof(Name));
|
||||
@@ -273,5 +261,22 @@ namespace StructureHelper.Infrastructure.UI.DataContexts
|
||||
OnPropertyChanged(nameof(PrimitiveWidth));
|
||||
OnPropertyChanged(nameof(PrimitiveHeight));
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnNext(IRectangleShape value)
|
||||
{
|
||||
DeltaX = value.Width / 2d;
|
||||
DeltaY = value.Height / 2d;
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
123
StructureHelper/Windows/MainWindow/AxisCanvases/AxisCanvasVM.cs
Normal file
123
StructureHelper/Windows/MainWindow/AxisCanvases/AxisCanvasVM.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using StructureHelper.Infrastructure;
|
||||
using StructureHelper.Windows.ViewModels;
|
||||
using StructureHelperCommon.Models.Shapes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace StructureHelper.Windows.MainWindow
|
||||
{
|
||||
public class AxisCanvasVM : OkCancelViewModelBase, IRectangleShape
|
||||
{
|
||||
private double axisLineThickness;
|
||||
private double gridLineThickness;
|
||||
private double gridSize;
|
||||
private double width;
|
||||
private double height;
|
||||
private Color xAxisColor;
|
||||
private Color yAxisColor;
|
||||
private Color gridColor;
|
||||
|
||||
/// <summary>
|
||||
/// Thickness of x-, and y- axis line
|
||||
/// </summary>
|
||||
public double AxisLineThickness
|
||||
{
|
||||
get => axisLineThickness;
|
||||
set
|
||||
{
|
||||
axisLineThickness = value;
|
||||
OnPropertyChanged(nameof(AxisLineThickness));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Thickness of lines of coordinate mesh
|
||||
/// </summary>
|
||||
public double GridLineThickness
|
||||
{
|
||||
get => gridLineThickness;
|
||||
set
|
||||
{
|
||||
gridLineThickness = value;
|
||||
OnPropertyChanged(nameof(GridLineThickness));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Size of coordinate mesh
|
||||
/// </summary>
|
||||
public double GridSize
|
||||
{
|
||||
get => gridSize; set
|
||||
{
|
||||
gridSize = value;
|
||||
OnPropertyChanged(nameof(GridSize));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Width of work plane
|
||||
/// </summary>
|
||||
public double Width
|
||||
{
|
||||
get => width; set
|
||||
{
|
||||
width = value;
|
||||
OnPropertyChanged(nameof(Width));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Height of work plane
|
||||
/// </summary>
|
||||
public double Height
|
||||
{
|
||||
get => height; set
|
||||
{
|
||||
height = value;
|
||||
OnPropertyChanged(nameof(Height));
|
||||
}
|
||||
}
|
||||
|
||||
public double Angle { get; set; }
|
||||
|
||||
public Color XAxisColor
|
||||
{
|
||||
get => xAxisColor; set
|
||||
{
|
||||
xAxisColor = value;
|
||||
OnPropertyChanged(nameof(XAxisColor));
|
||||
}
|
||||
}
|
||||
public Color YAxisColor
|
||||
{
|
||||
get => yAxisColor; set
|
||||
{
|
||||
yAxisColor = value;
|
||||
OnPropertyChanged(nameof(YAxisColor));
|
||||
}
|
||||
}
|
||||
|
||||
public Color GridColor
|
||||
{
|
||||
get => gridColor; set
|
||||
{
|
||||
gridColor = value;
|
||||
OnPropertyChanged(nameof(GridColor));
|
||||
}
|
||||
}
|
||||
|
||||
public AxisCanvasVM()
|
||||
{
|
||||
AxisLineThickness = 2d;
|
||||
GridLineThickness = 0.25d;
|
||||
GridSize = 0.05d;
|
||||
Width = 1.2d;
|
||||
Height = 1.2d;
|
||||
XAxisColor = Colors.Red;
|
||||
YAxisColor = Colors.ForestGreen;
|
||||
GridColor = Colors.DarkGray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,18 @@
|
||||
<Window x:Class="StructureHelper.Windows.MainWindow.VisualPropertyView"
|
||||
<Window x:Class="StructureHelper.Windows.MainWindow.AxisCanvasView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:StructureHelper.Windows.MainWindow"
|
||||
d:DataContext="{d:DesignInstance local:CrossSectionVisualPropertyVM}"
|
||||
d:DataContext="{d:DesignInstance local:AxisCanvasVM}"
|
||||
mc:Ignorable="d"
|
||||
Title="Grid properies" Height="200" Width="300" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="35"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="22"/>
|
||||
<RowDefinition Height="22"/>
|
||||
@@ -27,8 +32,10 @@
|
||||
<TextBlock Grid.Row="2" Text="Grid line thickness"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding GridLineThickness, Converter={StaticResource PlainDouble}, ValidatesOnExceptions=True}"/>
|
||||
<TextBlock Grid.Row="3" Text="Work plane width"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding WorkPlainWidth, Converter={StaticResource LengthConverter}, ValidatesOnExceptions=True}"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Width, Converter={StaticResource LengthConverter}, ValidatesOnExceptions=True}"/>
|
||||
<TextBlock Grid.Row="4" Text="Work plane height"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding WorkPlainHeight, Converter={StaticResource LengthConverter}, ValidatesOnExceptions=True}"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Height, Converter={StaticResource LengthConverter}, ValidatesOnExceptions=True}"/>
|
||||
</Grid>
|
||||
<ContentControl Grid.Row="1" ContentTemplate="{StaticResource OkCancelButtons}" Content="{Binding}"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -17,11 +17,12 @@ namespace StructureHelper.Windows.MainWindow
|
||||
/// <summary>
|
||||
/// Логика взаимодействия для VisualPropertyView.xaml
|
||||
/// </summary>
|
||||
public partial class VisualPropertyView : Window
|
||||
public partial class AxisCanvasView : Window
|
||||
{
|
||||
public VisualPropertyView(CrossSectionVisualPropertyVM vm)
|
||||
public AxisCanvasView(AxisCanvasVM vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
vm.ParentWindow = this;
|
||||
DataContext = vm;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using Autofac.Features.Metadata;
|
||||
using StructureHelper.Infrastructure;
|
||||
using StructureHelper.Infrastructure.UI.DataContexts;
|
||||
using StructureHelper.Windows.ViewModels.NdmCrossSections;
|
||||
using StructureHelperCommon.Models.Shapes;
|
||||
using StructureHelperLogics.NdmCalculations.Primitives;
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace StructureHelper.Windows.MainWindow
|
||||
{
|
||||
public class CrossSectionVisualPropertyVM : ViewModelBase
|
||||
{
|
||||
private double scaleValue;
|
||||
private ICommand previewMouseMove;
|
||||
private double delta = 0.0005;
|
||||
private readonly double scaleRate = 1.1d;
|
||||
|
||||
public AxisCanvasVM AxisCanvasVM { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Thickness of x-, and y- axis line
|
||||
/// </summary>
|
||||
public double AxisLineThickness => AxisCanvasVM.AxisLineThickness / scaleValue;
|
||||
|
||||
/// <summary>
|
||||
/// Thickness of lines of coordinate mesh
|
||||
/// </summary>
|
||||
public double GridLineThickness => AxisCanvasVM.GridLineThickness / scaleValue;
|
||||
|
||||
/// <summary>
|
||||
/// Size of coordinate mesh
|
||||
/// </summary>
|
||||
public double GridSize => AxisCanvasVM.GridSize;
|
||||
/// <summary>
|
||||
/// Width of work plane
|
||||
/// </summary>
|
||||
public double Width => AxisCanvasVM.Width;
|
||||
/// <summary>
|
||||
/// Height of work plane
|
||||
/// </summary>
|
||||
public double Height => AxisCanvasVM.Height;
|
||||
public double HalfOfWidth => AxisCanvasVM.Width / 2d;
|
||||
public double HalfOfHeight => AxisCanvasVM.Height / 2d;
|
||||
|
||||
public string CanvasViewportSize
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = GridSize.ToString();
|
||||
s = s.Replace(',', '.');
|
||||
return $"0,0,{s},{s}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double ScaleValue
|
||||
{
|
||||
get => Math.Round(scaleValue);
|
||||
set
|
||||
{
|
||||
OnPropertyChanged(value, ref scaleValue);
|
||||
OnPropertyChanged(nameof(AxisLineThickness));
|
||||
OnPropertyChanged(nameof(GridLineThickness));
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand PreviewMouseMove
|
||||
{
|
||||
get => previewMouseMove ??= new RelayCommand(o => PreviewMouseMoveMethod(o));
|
||||
}
|
||||
private void PreviewMouseMoveMethod(object o)
|
||||
{
|
||||
if (o is RectangleViewPrimitive rect && rect.BorderCaptured && !rect.ElementLock)
|
||||
{
|
||||
if (rect.PrimitiveWidth % 10d < delta || rect.PrimitiveWidth % 10d >= delta)
|
||||
rect.PrimitiveWidth = Math.Round(PanelX / 10d) * 10d - rect.PrimitiveLeft + 10d;
|
||||
else
|
||||
rect.PrimitiveWidth = PanelX - rect.PrimitiveLeft + 10d;
|
||||
|
||||
if (rect.PrimitiveHeight % 10d < delta || rect.PrimitiveHeight % 10d >= delta)
|
||||
rect.PrimitiveHeight = Math.Round(PanelY / 10d) * 10d - rect.PrimitiveTop + 10d;
|
||||
else
|
||||
rect.PrimitiveHeight = PanelY - rect.PrimitiveTop + 10d;
|
||||
}
|
||||
}
|
||||
|
||||
public Brush XAxisColorBrush => new SolidColorBrush(AxisCanvasVM.XAxisColor);
|
||||
public Brush YAxisColorBrush => new SolidColorBrush(AxisCanvasVM.YAxisColor);
|
||||
public Brush GridColorBrush => new SolidColorBrush(AxisCanvasVM.GridColor);
|
||||
|
||||
internal void Refresh()
|
||||
{
|
||||
OnPropertyChanged(nameof(Width));
|
||||
OnPropertyChanged(nameof(Height));
|
||||
OnPropertyChanged(nameof(HalfOfWidth));
|
||||
OnPropertyChanged(nameof(HalfOfHeight));
|
||||
OnPropertyChanged(nameof(GridSize));
|
||||
OnPropertyChanged(nameof(AxisLineThickness));
|
||||
OnPropertyChanged(nameof(GridLineThickness));
|
||||
OnPropertyChanged(nameof(CanvasViewportSize));
|
||||
OnPropertyChanged(nameof(XAxisColorBrush));
|
||||
OnPropertyChanged(nameof(YAxisColorBrush));
|
||||
OnPropertyChanged(nameof(GridColorBrush));
|
||||
}
|
||||
|
||||
private double panelX, panelY, scrollPanelX, scrollPanelY;
|
||||
private ICommand scaleCanvasDown;
|
||||
private ICommand scaleCanvasUp;
|
||||
|
||||
public double PanelX
|
||||
{
|
||||
get => panelX;
|
||||
set => OnPropertyChanged(value, ref panelX);
|
||||
}
|
||||
public double PanelY
|
||||
{
|
||||
get => panelY;
|
||||
set => OnPropertyChanged(value, ref panelY);
|
||||
}
|
||||
public double ScrollPanelX
|
||||
{
|
||||
get => scrollPanelX;
|
||||
set => OnPropertyChanged(value, ref scrollPanelX);
|
||||
}
|
||||
public double ScrollPanelY
|
||||
{
|
||||
get => scrollPanelY;
|
||||
set => OnPropertyChanged(value, ref scrollPanelY);
|
||||
}
|
||||
|
||||
public ICommand ScaleCanvasDown => scaleCanvasDown ??= new RelayCommand(o =>
|
||||
{
|
||||
ScrollPanelX = PanelX;
|
||||
ScrollPanelY = PanelY;
|
||||
ScaleValue *= scaleRate;
|
||||
});
|
||||
public ICommand ScaleCanvasUp => scaleCanvasUp ??= new RelayCommand(o =>
|
||||
{
|
||||
ScrollPanelX = PanelX;
|
||||
ScrollPanelY = PanelY;
|
||||
ScaleValue /= scaleRate;
|
||||
});
|
||||
|
||||
public CrossSectionViewModel ParentViewModel { get; set; }
|
||||
|
||||
public CrossSectionVisualPropertyVM()
|
||||
{
|
||||
AxisCanvasVM = new();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,11 +362,17 @@
|
||||
<i:InvokeCommandAction Command="{Binding ClearSelection}" CommandParameter="{Binding}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
|
||||
<Canvas Name="WorkPlane" ClipToBounds="True" Width="{Binding VisualProperty.WorkPlainWidth}" Height="{Binding VisualProperty.WorkPlainHeight}">
|
||||
<ScrollViewer
|
||||
DataContext="{Binding VisualProperty}"
|
||||
VerticalScrollBarVisibility="Visible"
|
||||
HorizontalScrollBarVisibility="Visible">
|
||||
<Canvas Name="WorkPlane"
|
||||
ClipToBounds="True"
|
||||
Width="{Binding Width}"
|
||||
Height="{Binding Height}">
|
||||
<Canvas.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Add" DataContext="{Binding PrimitiveLogic}">
|
||||
<MenuItem Header="Add" DataContext="{Binding ParentViewModel.PrimitiveLogic}">
|
||||
<MenuItem Header="Rectangle" Command="{Binding Add}" CommandParameter="{x:Static enums:PrimitiveType.Rectangle}">
|
||||
<MenuItem.Icon>
|
||||
<Image Style="{StaticResource ButtonImage16}" Source="/Windows/MainWindow/Rectangle32.png" />
|
||||
@@ -388,7 +394,7 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Templates" DataContext="{Binding}">
|
||||
<MenuItem Header="Templates" DataContext="{Binding ParentViewModel}">
|
||||
<MenuItem Header="Add Rectangle RC Column" Command="{Binding AddColumnCase}">
|
||||
<MenuItem.Icon>
|
||||
<Image Style="{StaticResource ButtonImage16}" Source="/Windows/MainWindow/RectangleColumn32.png" />
|
||||
@@ -434,15 +440,30 @@
|
||||
Viewport="{Binding CanvasViewportSize}" ViewportUnits="Absolute"
|
||||
Viewbox="{Binding CanvasViewportSize}" ViewboxUnits="Absolute">
|
||||
<VisualBrush.Visual>
|
||||
<Rectangle StrokeThickness="{Binding GridLineThickness}" Height="{Binding GridSize}" Width="{Binding GridSize}" Stroke="Darkgray"/>
|
||||
<Rectangle
|
||||
Height="{Binding GridSize}"
|
||||
Width="{Binding GridSize}"
|
||||
Stroke="{Binding GridColorBrush}"
|
||||
StrokeThickness="{Binding GridLineThickness}"/>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Canvas.Background>
|
||||
<!--Horizontal axis line-->
|
||||
<Line X1="0" X2="{Binding RightLimitX}" Y1="{Binding MiddleLimitY}" Y2="{Binding MiddleLimitY}" Stroke="Red" StrokeThickness="{Binding AxisLineThickness}"/>
|
||||
<Line
|
||||
X1="0" X2="{Binding Width}"
|
||||
Y1="{Binding HalfOfHeight}" Y2="{Binding HalfOfHeight}"
|
||||
Stroke="{Binding XAxisColorBrush}"
|
||||
StrokeThickness="{Binding AxisLineThickness}"/>
|
||||
<!--Vertical axis line-->
|
||||
<Line X1="{Binding MiddleLimitX}" X2="{Binding MiddleLimitX}" Y1="0" Y2="{Binding BottomLimitY}" Stroke="ForestGreen" StrokeThickness="{Binding AxisLineThickness}"/>
|
||||
<ItemsControl DataContext="{Binding PrimitiveLogic}" ItemsSource="{Binding Items}" ContextMenu="{StaticResource PrimitiveCRUD}">
|
||||
<Line
|
||||
X1="{Binding HalfOfWidth}" X2="{Binding HalfOfWidth}"
|
||||
Y1="0" Y2="{Binding Height}"
|
||||
Stroke="{Binding YAxisColorBrush}"
|
||||
StrokeThickness="{Binding AxisLineThickness}"/>
|
||||
<ItemsControl
|
||||
DataContext="{Binding ParentViewModel.PrimitiveLogic}"
|
||||
ItemsSource="{Binding Items}"
|
||||
ContextMenu="{StaticResource PrimitiveCRUD}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas/>
|
||||
@@ -466,7 +487,7 @@
|
||||
<StatusBarItem>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Zoom: "/>
|
||||
<TextBlock Text="{Binding ScaleValue}"/>
|
||||
<TextBlock Text="{Binding VisualProperty.ScaleValue}"/>
|
||||
</StackPanel>
|
||||
</StatusBarItem>
|
||||
<StatusBarItem>
|
||||
@@ -478,7 +499,7 @@
|
||||
<StatusBarItem>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Grid size: "/>
|
||||
<TextBlock Text="{Binding GridSize, Converter={StaticResource LengthConverter}}"/>
|
||||
<TextBlock Text="{Binding VisualProperty.GridSize, Converter={StaticResource LengthConverter}}"/>
|
||||
</StackPanel>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace StructureHelper.Windows.MainWindow
|
||||
{
|
||||
private ICrossSection section;
|
||||
private ICrossSectionRepository repository => section.SectionRepository;
|
||||
private readonly double scaleRate = 1.1d;
|
||||
|
||||
public CrossSectionVisualPropertyVM VisualProperty { get; private set; }
|
||||
|
||||
@@ -44,65 +43,7 @@ namespace StructureHelper.Windows.MainWindow
|
||||
|
||||
private CrossSectionModel Model { get; }
|
||||
|
||||
private double panelX, panelY, scrollPanelX, scrollPanelY;
|
||||
|
||||
public double PanelX
|
||||
{
|
||||
get => panelX;
|
||||
set => OnPropertyChanged(value, ref panelX);
|
||||
}
|
||||
public double PanelY
|
||||
{
|
||||
get => panelY;
|
||||
set => OnPropertyChanged(value, ref panelY);
|
||||
}
|
||||
public double ScrollPanelX
|
||||
{
|
||||
get => scrollPanelX;
|
||||
set => OnPropertyChanged(value, ref scrollPanelX);
|
||||
}
|
||||
public double ScrollPanelY
|
||||
{
|
||||
get => scrollPanelY;
|
||||
set => OnPropertyChanged(value, ref scrollPanelY);
|
||||
}
|
||||
|
||||
private double scaleValue;
|
||||
|
||||
public double ScaleValue
|
||||
{
|
||||
get => Math.Round(scaleValue);
|
||||
set
|
||||
{
|
||||
OnPropertyChanged(value, ref scaleValue);
|
||||
OnPropertyChanged(nameof(AxisLineThickness));
|
||||
OnPropertyChanged(nameof(GridLineThickness));
|
||||
}
|
||||
}
|
||||
|
||||
public double AxisLineThickness
|
||||
{
|
||||
get => VisualProperty.AxisLineThickness / scaleValue;
|
||||
}
|
||||
|
||||
public double GridLineThickness
|
||||
{
|
||||
get => VisualProperty.GridLineThickness / scaleValue;
|
||||
}
|
||||
|
||||
public string CanvasViewportSize
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = VisualProperty.GridSize.ToString();
|
||||
s = s.Replace(',', '.');
|
||||
return $"0,0,{s},{s}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double GridSize => VisualProperty.GridSize;
|
||||
|
||||
public ObservableCollection<IHeadMaterial> HeadMaterials
|
||||
{
|
||||
get
|
||||
@@ -114,24 +55,7 @@ namespace StructureHelper.Windows.MainWindow
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Right edge of work plane, coordinate X
|
||||
/// </summary>
|
||||
public double RightLimitX => VisualProperty.WorkPlainWidth;
|
||||
/// <summary>
|
||||
/// Bottom edge of work plane Y
|
||||
/// </summary>
|
||||
public double BottomLimitY => VisualProperty.WorkPlainHeight;
|
||||
/// <summary>
|
||||
/// Middle of coordinate X
|
||||
/// </summary>
|
||||
public double MiddleLimitX => VisualProperty.WorkPlainWidth / 2d;
|
||||
/// <summary>
|
||||
/// Middle of coordinate Y
|
||||
/// </summary>
|
||||
public double MiddleLimitY => VisualProperty.WorkPlainHeight / 2d;
|
||||
}
|
||||
|
||||
public ICommand Calculate { get; }
|
||||
public ICommand EditCalculationPropertyCommand { get; }
|
||||
@@ -153,7 +77,7 @@ namespace StructureHelper.Windows.MainWindow
|
||||
public ICommand LeftButtonDown { get; }
|
||||
public ICommand LeftButtonUp { get; }
|
||||
public ICommand MovePrimitiveToGravityCenterCommand { get; }
|
||||
public ICommand PreviewMouseMove { get; }
|
||||
|
||||
public ICommand ClearSelection { get; }
|
||||
public ICommand OpenMaterialCatalog { get; }
|
||||
public ICommand OpenMaterialCatalogWithSelection { get; }
|
||||
@@ -161,8 +85,7 @@ namespace StructureHelper.Windows.MainWindow
|
||||
public ICommand SetColor { get; }
|
||||
public ICommand SetInFrontOfAll { get; }
|
||||
public ICommand SetInBackOfAll { get; }
|
||||
public ICommand ScaleCanvasDown { get; }
|
||||
public ICommand ScaleCanvasUp { get; }
|
||||
|
||||
public ICommand SetPopupCanBeClosedTrue { get; }
|
||||
public ICommand SetPopupCanBeClosedFalse { get; }
|
||||
public RelayCommand ShowVisualProperty
|
||||
@@ -172,17 +95,12 @@ namespace StructureHelper.Windows.MainWindow
|
||||
return showVisualProperty ??
|
||||
(showVisualProperty = new RelayCommand(o=>
|
||||
{
|
||||
var wnd = new VisualPropertyView(VisualProperty);
|
||||
var wnd = new AxisCanvasView(VisualProperty.AxisCanvasVM);
|
||||
wnd.ShowDialog();
|
||||
OnPropertyChanged(nameof(AxisLineThickness));
|
||||
OnPropertyChanged(nameof(CanvasViewportSize));
|
||||
OnPropertyChanged(nameof(GridSize));
|
||||
OnPropertyChanged(nameof(RightLimitX));
|
||||
OnPropertyChanged(nameof(BottomLimitY));
|
||||
OnPropertyChanged(nameof(MiddleLimitX));
|
||||
OnPropertyChanged(nameof(MiddleLimitY));
|
||||
PrimitiveLogic.WorkPlaneWidth = VisualProperty.WorkPlainWidth;
|
||||
PrimitiveLogic.WorkPlaneHeight = VisualProperty.WorkPlainHeight;
|
||||
if (wnd.DialogResult == false) { return; }
|
||||
VisualProperty.Refresh();
|
||||
PrimitiveLogic.Width = VisualProperty.Width;
|
||||
PrimitiveLogic.Height = VisualProperty.Height;
|
||||
PrimitiveLogic.Refresh();
|
||||
}));
|
||||
}
|
||||
@@ -192,36 +110,37 @@ namespace StructureHelper.Windows.MainWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
return selectPrimitive ??
|
||||
(selectPrimitive = new RelayCommand(obj=>
|
||||
return selectPrimitive ??= new RelayCommand(obj=>
|
||||
{
|
||||
if (obj is PrimitiveBase)
|
||||
{
|
||||
SelectedPrimitive = obj as PrimitiveBase;
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private double delta = 0.0005;
|
||||
private RelayCommand showVisualProperty;
|
||||
private RelayCommand selectPrimitive;
|
||||
|
||||
public CrossSectionViewModel(CrossSectionModel model)
|
||||
{
|
||||
VisualProperty = new CrossSectionVisualPropertyVM();
|
||||
VisualProperty = new CrossSectionVisualPropertyVM()
|
||||
{
|
||||
ScaleValue = 500d,
|
||||
ParentViewModel = this
|
||||
};
|
||||
Model = model;
|
||||
section = model.Section;
|
||||
CombinationsLogic = new ActionsViewModel(repository);
|
||||
MaterialsLogic = new MaterialsViewModel(repository);
|
||||
MaterialsLogic.AfterItemsEdit += afterMaterialEdit;
|
||||
MaterialsLogic.AfterItemsEdit += AfterMaterialEdit;
|
||||
CalculatorsLogic = new AnalysisVewModelLogic(repository);
|
||||
PrimitiveLogic = new PrimitiveViewModelLogic(section)
|
||||
{
|
||||
WorkPlaneWidth = VisualProperty.WorkPlainWidth,
|
||||
WorkPlaneHeight = VisualProperty.WorkPlainHeight
|
||||
Width = VisualProperty.Width,
|
||||
Height = VisualProperty.Height
|
||||
};
|
||||
scaleValue = 500d;
|
||||
|
||||
LeftButtonUp = new RelayCommand(o =>
|
||||
{
|
||||
@@ -231,35 +150,6 @@ namespace StructureHelper.Windows.MainWindow
|
||||
{
|
||||
if (o is RectangleViewPrimitive rect) rect.BorderCaptured = true;
|
||||
});
|
||||
PreviewMouseMove = new RelayCommand(o =>
|
||||
{
|
||||
if (o is RectangleViewPrimitive rect && rect.BorderCaptured && !rect.ElementLock)
|
||||
{
|
||||
if (rect.PrimitiveWidth % 10d < delta || rect.PrimitiveWidth % 10d >= delta)
|
||||
rect.PrimitiveWidth = Math.Round(PanelX / 10d) * 10d - rect.PrimitiveLeft + 10d;
|
||||
else
|
||||
rect.PrimitiveWidth = PanelX - rect.PrimitiveLeft + 10d;
|
||||
|
||||
if (rect.PrimitiveHeight % 10d < delta || rect.PrimitiveHeight % 10d >= delta)
|
||||
rect.PrimitiveHeight = Math.Round(PanelY / 10d) * 10d - rect.PrimitiveTop + 10d;
|
||||
else
|
||||
rect.PrimitiveHeight = PanelY - rect.PrimitiveTop + 10d;
|
||||
}
|
||||
});
|
||||
|
||||
ScaleCanvasDown = new RelayCommand(o =>
|
||||
{
|
||||
ScrollPanelX = PanelX;
|
||||
ScrollPanelY = PanelY;
|
||||
ScaleValue *= scaleRate;
|
||||
});
|
||||
|
||||
ScaleCanvasUp = new RelayCommand(o =>
|
||||
{
|
||||
ScrollPanelX = PanelX;
|
||||
ScrollPanelY = PanelY;
|
||||
ScaleValue /= scaleRate;
|
||||
});
|
||||
|
||||
AddBeamCase = new RelayCommand(o =>
|
||||
{
|
||||
@@ -301,17 +191,14 @@ namespace StructureHelper.Windows.MainWindow
|
||||
|
||||
SetPopupCanBeClosedFalse = new RelayCommand(o =>
|
||||
{
|
||||
if (!(o is PrimitiveBase primitive)) return;
|
||||
if (o is not PrimitiveBase primitive) return;
|
||||
primitive.PopupCanBeClosed = false;
|
||||
});
|
||||
}
|
||||
|
||||
private void afterMaterialEdit(SelectItemVM<IHeadMaterial> sender, CRUDVMEventArgs e)
|
||||
private void AfterMaterialEdit(SelectItemVM<IHeadMaterial> sender, CRUDVMEventArgs e)
|
||||
{
|
||||
foreach (var primitive in PrimitiveLogic.Items)
|
||||
{
|
||||
primitive.RefreshColor();
|
||||
}
|
||||
PrimitiveLogic.Refresh();
|
||||
}
|
||||
|
||||
private bool CheckMaterials()
|
||||
@@ -338,12 +225,26 @@ namespace StructureHelper.Windows.MainWindow
|
||||
}
|
||||
private IEnumerable<PrimitiveBase> GetColumnCasePrimitives()
|
||||
{
|
||||
var template = new RectangleBeamTemplate(0.5d, 0.5d) { CoverGap = 0.05, WidthCount = 3, HeightCount = 3, TopDiameter = 0.025d, BottomDiameter = 0.025d };
|
||||
var template = new RectangleBeamTemplate(0.5d, 0.5d)
|
||||
{
|
||||
CoverGap = 0.05,
|
||||
WidthCount = 3,
|
||||
HeightCount = 3,
|
||||
TopDiameter = 0.025d,
|
||||
BottomDiameter = 0.025d
|
||||
};
|
||||
return GetCasePrimitives(template);
|
||||
}
|
||||
private IEnumerable<PrimitiveBase> GetSlabCasePrimitives()
|
||||
{
|
||||
var template = new RectangleBeamTemplate(1d, 0.2d) { CoverGap = 0.04, WidthCount = 5, HeightCount = 2, TopDiameter = 0.012d, BottomDiameter = 0.012d };
|
||||
var template = new RectangleBeamTemplate(1d, 0.2d)
|
||||
{
|
||||
CoverGap = 0.04,
|
||||
WidthCount = 5,
|
||||
HeightCount = 2,
|
||||
TopDiameter = 0.012d,
|
||||
BottomDiameter = 0.012d
|
||||
};
|
||||
return GetCasePrimitives(template);
|
||||
}
|
||||
|
||||
@@ -363,11 +264,15 @@ namespace StructureHelper.Windows.MainWindow
|
||||
geometryLogic = new CircleGeometryLogic(circleTemplate);
|
||||
wnd = new CircleView(circleTemplate);
|
||||
}
|
||||
else { throw new StructureHelperException(ErrorStrings.ObjectTypeIsUnknown + $"Was: {nameof(template)}"); }
|
||||
wnd.ShowDialog();
|
||||
if (wnd.DialogResult == true)
|
||||
else
|
||||
{
|
||||
|
||||
throw new StructureHelperException(ErrorStrings.ObjectTypeIsUnknownObj(template));
|
||||
}
|
||||
wnd.ShowDialog();
|
||||
if (wnd.DialogResult == false)
|
||||
{
|
||||
return new List<PrimitiveBase>();
|
||||
}
|
||||
var newSection = new SectionTemplate(geometryLogic).GetCrossSection();
|
||||
var newRepository = newSection.SectionRepository;
|
||||
repository.HeadMaterials.AddRange(newRepository.HeadMaterials);
|
||||
@@ -378,10 +283,6 @@ namespace StructureHelper.Windows.MainWindow
|
||||
CombinationsLogic.AddItems(newRepository.ForceActions);
|
||||
CalculatorsLogic.AddItems(newRepository.CalculatorsList);
|
||||
var primitives = PrimitiveOperations.ConvertNdmPrimitivesToPrimitiveBase(newRepository.Primitives);
|
||||
foreach (var item in primitives)
|
||||
{
|
||||
item.RegisterDeltas(VisualProperty.WorkPlainWidth / 2, VisualProperty.WorkPlainHeight / 2);
|
||||
}
|
||||
PrimitiveLogic.Refresh();
|
||||
foreach (var item in newRepository.HeadMaterials)
|
||||
{
|
||||
@@ -392,8 +293,7 @@ namespace StructureHelper.Windows.MainWindow
|
||||
GlobalRepository.Actions.Create(item);
|
||||
}
|
||||
return primitives;
|
||||
}
|
||||
return new List<PrimitiveBase>();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using StructureHelper.Infrastructure;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace StructureHelper.Windows.MainWindow
|
||||
{
|
||||
public class CrossSectionVisualPropertyVM : ViewModelBase
|
||||
{
|
||||
private double axisLineThickness;
|
||||
private double gridLineThickness;
|
||||
private double gridSize;
|
||||
private double workPlainWidth;
|
||||
private double workPlainHeight;
|
||||
|
||||
/// <summary>
|
||||
/// Thickness of x-, and y- axis line
|
||||
/// </summary>
|
||||
public double AxisLineThickness
|
||||
{
|
||||
get => axisLineThickness; set
|
||||
{
|
||||
axisLineThickness = value;
|
||||
OnPropertyChanged(nameof(AxisLineThickness));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Thickness of lines of coordinate mesh
|
||||
/// </summary>
|
||||
public double GridLineThickness
|
||||
{
|
||||
get => gridLineThickness; set
|
||||
{
|
||||
gridLineThickness = value;
|
||||
OnPropertyChanged(nameof(GridLineThickness));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Size of coordinate mesh
|
||||
/// </summary>
|
||||
public double GridSize
|
||||
{
|
||||
get => gridSize; set
|
||||
{
|
||||
gridSize = value;
|
||||
OnPropertyChanged(nameof(GridSize));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Width of work plane
|
||||
/// </summary>
|
||||
public double WorkPlainWidth
|
||||
{
|
||||
get => workPlainWidth; set
|
||||
{
|
||||
workPlainWidth = value;
|
||||
OnPropertyChanged(nameof(WorkPlainWidth));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Height of work plane
|
||||
/// </summary>
|
||||
public double WorkPlainHeight
|
||||
{
|
||||
get => workPlainHeight; set
|
||||
{
|
||||
workPlainHeight = value;
|
||||
OnPropertyChanged(nameof(WorkPlainHeight));
|
||||
}
|
||||
}
|
||||
|
||||
public CrossSectionVisualPropertyVM()
|
||||
{
|
||||
AxisLineThickness = 2d;
|
||||
GridLineThickness = 0.25d;
|
||||
GridSize = 0.05d;
|
||||
WorkPlainWidth = 1.2d;
|
||||
WorkPlainHeight = 1.2d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,21 @@
|
||||
using StructureHelper.Infrastructure;
|
||||
using StructureHelper.Infrastructure.Enums;
|
||||
using StructureHelper.Infrastructure.UI.DataContexts;
|
||||
using StructureHelper.Services.Settings;
|
||||
using StructureHelper.Windows.PrimitiveProperiesWindow;
|
||||
using StructureHelper.Windows.PrimitiveTemplates.RCs.Beams;
|
||||
using StructureHelper.Windows.PrimitiveTemplates.RCs.RectangleBeam;
|
||||
using StructureHelper.Windows.Services;
|
||||
using StructureHelperCommon.Infrastructures.Exceptions;
|
||||
using StructureHelperCommon.Models.Materials;
|
||||
using StructureHelperCommon.Models.Shapes;
|
||||
using StructureHelperLogics.Models.CrossSections;
|
||||
using StructureHelperLogics.Models.Primitives;
|
||||
using StructureHelperLogics.Models.Templates.CrossSections.RCs;
|
||||
using StructureHelperLogics.Models.Templates.RCs;
|
||||
using StructureHelperLogics.NdmCalculations.Analyses.ByForces;
|
||||
using StructureHelperLogics.NdmCalculations.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
@@ -19,7 +27,7 @@ using System.Windows.Input;
|
||||
|
||||
namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
{
|
||||
public class PrimitiveViewModelLogic : ViewModelBase, ICRUDViewModel<PrimitiveBase>
|
||||
public class PrimitiveViewModelLogic : ViewModelBase, ICRUDViewModel<PrimitiveBase>, IRectangleShape, IObservable<PrimitiveBase>
|
||||
{
|
||||
private ICrossSection section;
|
||||
private ICrossSectionRepository repository => section.SectionRepository;
|
||||
@@ -31,8 +39,9 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
private ICommand setToBack;
|
||||
private ICommand copyToCommand;
|
||||
|
||||
public double WorkPlaneWidth { get; set; }
|
||||
public double WorkPlaneHeight { get; set; }
|
||||
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
|
||||
public PrimitiveBase SelectedItem { get; set; }
|
||||
|
||||
@@ -42,14 +51,12 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
{
|
||||
get
|
||||
{
|
||||
return addCommand ??
|
||||
(
|
||||
addCommand = new RelayCommand(o =>
|
||||
return addCommand ??= new RelayCommand(o =>
|
||||
{
|
||||
if (!(o is PrimitiveType primitiveType)) return;
|
||||
if (o is not PrimitiveType primitiveType) return;
|
||||
AddPrimitive(primitiveType);
|
||||
}
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +103,7 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
viewPrimitive = new CircleViewPrimitive(primitive);
|
||||
}
|
||||
else { throw new StructureHelperException(ErrorStrings.ObjectTypeIsUnknown + nameof(primitiveType)); }
|
||||
viewPrimitive.RegisterDeltas(WorkPlaneWidth / 2, WorkPlaneHeight / 2);
|
||||
viewPrimitive.OnNext(this);
|
||||
repository.Primitives.Add(ndmPrimitive);
|
||||
ndmPrimitive.CrossSection = section;
|
||||
Items.Add(viewPrimitive);
|
||||
@@ -181,12 +188,10 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
{
|
||||
get
|
||||
{
|
||||
return copyCommand ??
|
||||
(
|
||||
copyCommand = new RelayCommand(
|
||||
return copyCommand ??= new RelayCommand(
|
||||
o => CopySelectedItem(SelectedItem.GetNdmPrimitive()),
|
||||
o => SelectedItem != null
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,8 +229,14 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
newPrimitive.Name += " copy";
|
||||
repository.Primitives.Add(newPrimitive);
|
||||
PrimitiveBase primitiveBase;
|
||||
if (newPrimitive is IRectanglePrimitive) { primitiveBase = new RectangleViewPrimitive(newPrimitive as IRectanglePrimitive); }
|
||||
else if (newPrimitive is ICirclePrimitive) { primitiveBase = new CircleViewPrimitive(newPrimitive as ICirclePrimitive); }
|
||||
if (newPrimitive is IRectanglePrimitive)
|
||||
{
|
||||
primitiveBase = new RectangleViewPrimitive(newPrimitive as IRectanglePrimitive);
|
||||
}
|
||||
else if (newPrimitive is ICirclePrimitive)
|
||||
{
|
||||
primitiveBase = new CircleViewPrimitive(newPrimitive as ICirclePrimitive);
|
||||
}
|
||||
else if (newPrimitive is IPointPrimitive)
|
||||
{
|
||||
if (newPrimitive is RebarPrimitive)
|
||||
@@ -236,10 +247,13 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
{
|
||||
primitiveBase = new PointViewPrimitive(newPrimitive as IPointPrimitive);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else throw new StructureHelperException(ErrorStrings.ObjectTypeIsUnknown);
|
||||
primitiveBase.RegisterDeltas(WorkPlaneWidth / 2, WorkPlaneHeight / 2);
|
||||
else
|
||||
{
|
||||
throw new StructureHelperException(ErrorStrings.ObjectTypeIsUnknown);
|
||||
}
|
||||
primitiveBase.OnNext(this);
|
||||
Items.Add(primitiveBase);
|
||||
OnPropertyChanged(nameof(Items));
|
||||
OnPropertyChanged(nameof(PrimitivesCount));
|
||||
@@ -252,13 +266,12 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
{
|
||||
get
|
||||
{
|
||||
return setToFront ??
|
||||
(setToFront = new RelayCommand(o=>
|
||||
return setToFront ??= new RelayCommand(o=>
|
||||
{
|
||||
int maxZIndex = Items.Select(x => x.GetNdmPrimitive().VisualProperty.ZIndex).Max();
|
||||
SelectedItem.ZIndex = maxZIndex + 1;
|
||||
},o => CheckMaxIndex()
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
private bool CheckMaxIndex()
|
||||
@@ -281,16 +294,17 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
{
|
||||
get
|
||||
{
|
||||
return setToBack ??
|
||||
(setToBack = new RelayCommand(o =>
|
||||
return setToBack ??= new RelayCommand(o =>
|
||||
{
|
||||
int minZIndex = Items.Select(x => x.GetNdmPrimitive().VisualProperty.ZIndex).Min();
|
||||
SelectedItem.ZIndex = minZIndex - 1;
|
||||
}, o => CheckMinIndex()
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public double Angle { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public void AddItems(IEnumerable<PrimitiveBase> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
@@ -300,13 +314,22 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
NotifyObservers();
|
||||
OnPropertyChanged(nameof(PrimitivesCount));
|
||||
}
|
||||
|
||||
public void NotifyObservers()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
item.RegisterDeltas(WorkPlaneWidth / 2, WorkPlaneHeight / 2);
|
||||
item.Refresh();
|
||||
item.OnNext(this);
|
||||
}
|
||||
OnPropertyChanged(nameof(PrimitivesCount));
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IObserver<PrimitiveBase> observer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public PrimitiveViewModelLogic(ICrossSection section)
|
||||
@@ -315,5 +338,6 @@ namespace StructureHelper.Windows.ViewModels.NdmCrossSections
|
||||
Items = new ObservableCollection<PrimitiveBase>();
|
||||
AddItems(PrimitiveOperations.ConvertNdmPrimitivesToPrimitiveBase(this.repository.Primitives));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user