From ed3291c7276d355e43ba104a26107b6caa6a7746 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 12 Apr 2026 22:13:00 +0300 Subject: [PATCH] qwer --- .idea/.idea.MCCAD/.idea/avalonia.xml | 4 + MCCAD/MCCAD.csproj | 11 + MCCAD/Models/CadDBContext.cs | 21 ++ MCCAD/Models/Collaborators.cs | 15 ++ MCCAD/Models/Drawing.cs | 56 +++++ MCCAD/Models/Membership.cs | 14 ++ MCCAD/Models/Team.cs | 20 ++ MCCAD/Models/User.cs | 11 + MCCAD/ViewLocator.cs | 16 ++ MCCAD/ViewModels/DrawingViewModel.cs | 73 ++++++ .../ViewModels/DrawingsCollectionViewModel.cs | 77 ++++++ MCCAD/ViewModels/LineView.cs | 147 ++++++++++- MCCAD/ViewModels/LoginViewModel.cs | 38 +++ MCCAD/ViewModels/MainWindowViewModel.cs | 32 +-- MCCAD/ViewModels/TeamsViewModel.cs | 42 ++++ MCCAD/Views/DrawingView.axaml | 156 ++++++++++++ MCCAD/Views/DrawingView.axaml.cs | 237 ++++++++++++++++++ MCCAD/Views/DrawingsCollectionView.axaml | 44 ++++ MCCAD/Views/DrawingsCollectionView.axaml.cs | 15 ++ MCCAD/Views/LoginView.axaml | 41 +++ MCCAD/Views/LoginView.axaml.cs | 29 +++ MCCAD/Views/MainWindow.axaml | 149 +---------- MCCAD/Views/MainWindow.axaml.cs | 209 --------------- MCCAD/Views/PositionControl.axaml | 14 +- MCCAD/Views/TeamsView.axaml | 28 +++ MCCAD/Views/TeamsView.axaml.cs | 20 ++ 26 files changed, 1128 insertions(+), 391 deletions(-) create mode 100644 MCCAD/Models/CadDBContext.cs create mode 100644 MCCAD/Models/Collaborators.cs create mode 100644 MCCAD/Models/Drawing.cs create mode 100644 MCCAD/Models/Membership.cs create mode 100644 MCCAD/Models/Team.cs create mode 100644 MCCAD/Models/User.cs create mode 100644 MCCAD/ViewModels/DrawingViewModel.cs create mode 100644 MCCAD/ViewModels/DrawingsCollectionViewModel.cs create mode 100644 MCCAD/ViewModels/LoginViewModel.cs create mode 100644 MCCAD/ViewModels/TeamsViewModel.cs create mode 100644 MCCAD/Views/DrawingView.axaml create mode 100644 MCCAD/Views/DrawingView.axaml.cs create mode 100644 MCCAD/Views/DrawingsCollectionView.axaml create mode 100644 MCCAD/Views/DrawingsCollectionView.axaml.cs create mode 100644 MCCAD/Views/LoginView.axaml create mode 100644 MCCAD/Views/LoginView.axaml.cs create mode 100644 MCCAD/Views/TeamsView.axaml create mode 100644 MCCAD/Views/TeamsView.axaml.cs diff --git a/.idea/.idea.MCCAD/.idea/avalonia.xml b/.idea/.idea.MCCAD/.idea/avalonia.xml index d1d87b8..dbe0298 100644 --- a/.idea/.idea.MCCAD/.idea/avalonia.xml +++ b/.idea/.idea.MCCAD/.idea/avalonia.xml @@ -4,8 +4,12 @@ diff --git a/MCCAD/MCCAD.csproj b/MCCAD/MCCAD.csproj index 3768e4d..04797ee 100644 --- a/MCCAD/MCCAD.csproj +++ b/MCCAD/MCCAD.csproj @@ -21,6 +21,17 @@ None All + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/MCCAD/Models/CadDBContext.cs b/MCCAD/Models/CadDBContext.cs new file mode 100644 index 0000000..1aa9888 --- /dev/null +++ b/MCCAD/Models/CadDBContext.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; + +namespace MCCAD.Models; + +public class CadDBContext : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseLazyLoadingProxies() + .UseNpgsql("Host=localhost;User id=postgres;Password=1234;Database=cad_db"); + } + + public DbSet Users { get; set; } + public DbSet Drawings { get; set; } + public DbSet Collaborators { get; set; } + public DbSet Teams { get; set; } + public DbSet Memberships { get; set; } + + public static readonly CadDBContext Instance = new(); + public static User User; +} \ No newline at end of file diff --git a/MCCAD/Models/Collaborators.cs b/MCCAD/Models/Collaborators.cs new file mode 100644 index 0000000..e19f5ba --- /dev/null +++ b/MCCAD/Models/Collaborators.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace MCCAD.Models; + + +public class Collaborators +{ + public int Id { get; set; } + [ForeignKey(nameof(User))] + public int UserId { get; set; } + public virtual User User { get; set; } + [ForeignKey(nameof(Drawing))] + public int DrawingId { get; set; } + public virtual Drawing Drawing { get; set; } +} \ No newline at end of file diff --git a/MCCAD/Models/Drawing.cs b/MCCAD/Models/Drawing.cs new file mode 100644 index 0000000..eca0158 --- /dev/null +++ b/MCCAD/Models/Drawing.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.CompilerServices; + +namespace MCCAD.Models; + +public class Drawing: INotifyPropertyChanged +{ + private string _name; + + [Key] + public int Id { get; set; } + + [Required] + public string Name + { + get => _name; + set + { + if (value == _name) return; + _name = value; + OnPropertyChanged(); + } + } + + public string Data { get; set; } = "[]"; + [ForeignKey(nameof(User))] + public int UserId { get; set; } + public virtual User User { get; set; } + public DateTime CreationDate { get; set; } + public DateTime LastChange { get; set; } + public double Size => double.Round(Data.Length / 1024.0, 2); + + public Drawing() + { + CreationDate = DateTime.Now.ToUniversalTime(); + } + + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + OnPropertyChanged(propertyName); + return true; + } +} \ No newline at end of file diff --git a/MCCAD/Models/Membership.cs b/MCCAD/Models/Membership.cs new file mode 100644 index 0000000..a87796b --- /dev/null +++ b/MCCAD/Models/Membership.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace MCCAD.Models; + +public class Membership +{ + public int Id { get; set; } + [ForeignKey(nameof(User))] + public int UserId { get; set; } + public virtual User User { get; set; } + [ForeignKey(nameof(Team))] + public int TeamId { get; set; } + public virtual Team Team { get; set; } +} \ No newline at end of file diff --git a/MCCAD/Models/Team.cs b/MCCAD/Models/Team.cs new file mode 100644 index 0000000..99e3d16 --- /dev/null +++ b/MCCAD/Models/Team.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; + +namespace MCCAD.Models; + +public class Team +{ + public int Id { get; set; } + [Required] + public string Name { get; set; } + + public string Description { get; set; } = ""; + [ForeignKey(nameof(Creator))] + public int CreatorId { get; set; } + public virtual User Creator { get; set; } + public int MemberCount => CadDBContext.Instance.Memberships.Count(i => i.TeamId == Id); + public DateTime CreatedAt { get; set; } = DateTime.Now.ToUniversalTime(); +} \ No newline at end of file diff --git a/MCCAD/Models/User.cs b/MCCAD/Models/User.cs new file mode 100644 index 0000000..b55e6dc --- /dev/null +++ b/MCCAD/Models/User.cs @@ -0,0 +1,11 @@ +namespace MCCAD.Models; + +public class User +{ + public int Id { get; set; } + public string Name { get; set; } + public string Login { get; set; } + public string Password { get; set; } + public int RoleId { get; set; } + public string Description { get; set; } = ""; +} \ No newline at end of file diff --git a/MCCAD/ViewLocator.cs b/MCCAD/ViewLocator.cs index 8892d45..4b2564b 100644 --- a/MCCAD/ViewLocator.cs +++ b/MCCAD/ViewLocator.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using Avalonia.Controls; using Avalonia.Controls.Templates; using MCCAD.ViewModels; +using ReactiveUI; namespace MCCAD; @@ -34,4 +35,19 @@ public class ViewLocator : IDataTemplate { return data is ViewModelBase; } +} + +public class MainViewLocator : IViewLocator +{ + + private ViewLocator _locator = new ViewLocator(); + public IViewFor? ResolveView(string? contract = null) where TViewModel : class + { + return _locator.Build(contract) as IViewFor; + } + + public IViewFor? ResolveView(object? instance, string? contract = null) + { + return _locator.Build(instance) as IViewFor; + } } \ No newline at end of file diff --git a/MCCAD/ViewModels/DrawingViewModel.cs b/MCCAD/ViewModels/DrawingViewModel.cs new file mode 100644 index 0000000..e7c9744 --- /dev/null +++ b/MCCAD/ViewModels/DrawingViewModel.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text.Json; +using System.Windows.Input; +using MCCAD.Models; +using ReactiveUI; + +namespace MCCAD.ViewModels; + +public class DrawingViewModel : ViewModelBase, IRoutableViewModel +{ + private OvalView _ov; + private PolygonView _pv; + private LineView _lv; + private Drawing _inner; + + private static readonly List _deserializers = + [new LineView.Deserializer(), new PolygonView.Deserializer(), new OvalView.Deserializer()]; + + public DrawingViewModel(IScreen hostScreen, Drawing drawing) + { + HostScreen = hostScreen; + _inner = drawing; + LoadFigures(); + } + + private void LoadFigures() + { + foreach (var figure in JsonSerializer.Deserialize>(_inner.Data)) + foreach (var deserializer in _deserializers) + { + if (deserializer.TryDeserialize(figure, out var view)) + { + Figures.Add(view); + break; + } + } + } + + public OvalView Ov + { + get => _ov; + set => this.RaiseAndSetIfChanged(ref _ov, value); + } + + public PolygonView Pv + { + get => _pv; + set => this.RaiseAndSetIfChanged(ref _pv, value); + } + + public LineView Lv + { + get => _lv; + set => this.RaiseAndSetIfChanged(ref _lv, value); + } + + public ObservableCollection Figures { get; set; } = []; + public string? UrlPathSegment { get; } = Guid.NewGuid().ToString(); + public IScreen HostScreen { get; } + + public ICommand OnSave => ReactiveCommand.Create(() => + { + _inner.Data = JsonSerializer.Serialize(Figures.Select(i => i.Save())); + _inner.LastChange = DateTime.Now.ToUniversalTime(); + CadDBContext.Instance.SaveChanges(); + }); + + public ICommand Back => ReactiveCommand.Create(() => { HostScreen.Router.NavigateBack.Execute(); } + ); +} \ No newline at end of file diff --git a/MCCAD/ViewModels/DrawingsCollectionViewModel.cs b/MCCAD/ViewModels/DrawingsCollectionViewModel.cs new file mode 100644 index 0000000..6c0b5e8 --- /dev/null +++ b/MCCAD/ViewModels/DrawingsCollectionViewModel.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.ObjectModel; +using System.Windows.Input; +using MCCAD.Models; +using ReactiveUI; + +namespace MCCAD.ViewModels; + +public class DrawingsCollectionViewModel : ViewModelBase, IRoutableViewModel +{ + public DrawingsCollectionViewModel(IScreen hostScreen) + { + HostScreen = hostScreen; + User = CadDBContext.User; + } + + public string? UrlPathSegment { get; } = Guid.NewGuid().ToString(); + public IScreen HostScreen { get; } + + public User User { get; set; } + public ObservableCollection Drawings { get; set; } = []; + public Drawing? SelectedDrawing { get; set; } + public ICommand Exit => ReactiveCommand.Create(() => HostScreen.Router.NavigateBack.Execute()); + + public ICommand Open => ReactiveCommand.Create(() => + { + if (SelectedDrawing != null) + HostScreen.Router.Navigate.Execute(new DrawingViewModel(HostScreen, SelectedDrawing!)); + }); + + public ICommand Delete => ReactiveCommand.Create(() => + { + if (SelectedDrawing != null) + { + if (SelectedDrawing.Id != 0) + { + CadDBContext.Instance.Drawings.Remove(SelectedDrawing); + CadDBContext.Instance.SaveChanges(); + } + + Drawings.Remove(SelectedDrawing); + } + }); + + public ICommand Save => ReactiveCommand.Create(() => + { + if (SelectedDrawing == null) return; + if (SelectedDrawing.Id == 0) + { + CadDBContext.Instance.Drawings.Add(SelectedDrawing); + } + else + { + CadDBContext.Instance.Drawings.Update(SelectedDrawing); + } + + CadDBContext.Instance.SaveChanges(); + }); + + public ICommand Create => ReactiveCommand.Create(() => + { + var dr = new Drawing(); + dr.User = User; + Drawings.Add(dr); + SelectedDrawing = dr; + }); + + public string SelectedDrawingName + { + get => (SelectedDrawing ?? new Drawing()).Name; + set + { + if (SelectedDrawing != null) + SelectedDrawing.Name = value; + } + } +} \ No newline at end of file diff --git a/MCCAD/ViewModels/LineView.cs b/MCCAD/ViewModels/LineView.cs index 87c97a4..631f635 100644 --- a/MCCAD/ViewModels/LineView.cs +++ b/MCCAD/ViewModels/LineView.cs @@ -2,8 +2,11 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Text.Json; +using Avalonia.Controls.Shapes; using MCCAD.Models; using ReactiveUI; +using Line = MCCAD.Models.Line; namespace MCCAD.ViewModels; @@ -17,23 +20,37 @@ public interface IFigureView public event ShemeUpdate OnNewSheme; PositionVM Position { get; set; } public string Name { get; set; } + string Save(); +} + +public interface IFigureDeserializer +{ + bool TryDeserialize(string data, out IFigureView view); } public class LineView : ReactiveObject, IFigureView { private static int _counter = 1; - public LineView () { + public LineView() + { Position = new PositionVM { Chanded = Rebuild }; - Name = "Line " + _counter++; + Name = "Line " + _counter++; } + public event ShemeUpdate OnNewSheme; - public PositionVM Position { get; set; } = new (); + public PositionVM Position { get; set; } public string Name { get; set; } + public string Save() + { + var data = new Data() { Angle = Angle, Lenght = lenght, Position = Position, Name = Name }; + return "line " + JsonSerializer.Serialize(data); + } + private double angle = 45; private int lenght = 10; @@ -67,7 +84,32 @@ public class LineView : ReactiveObject, IFigureView shape = shape.Select(i => new IntPoint(i.X, -i.Y)).ToList(); var yMove = shape.Select(p => p.Y).Min(); shape = shape.Select(p => new IntPoint(p.X, p.Y - yMove)).ToList(); - OnNewSheme.Invoke(shape, this); + OnNewSheme?.Invoke(shape, this); + } + + public class Data + { + public string Name { get; set; } + public int Angle { get; set; } + public int Lenght { get; set; } + public PositionVM Position { get; set; } + } + + public class Deserializer : IFigureDeserializer + { + public bool TryDeserialize(string data, out IFigureView? view) + { + if (!data.StartsWith("line")) + { + view = null; + return false; + } + + var parsed = JsonSerializer.Deserialize(data.Substring(data.IndexOf(' ') + 1)); + view = new LineView() + { Name = parsed.Name, Lenght = parsed.Lenght, Position = parsed.Position, Angle = parsed.Angle }; + return true; + } } } @@ -76,20 +118,54 @@ public class PolygonView : ReactiveObject, IFigureView public event ShemeUpdate OnNewSheme; public PositionVM Position { get; set; } public string Name { get; set; } + + public class Data + { + public string Name { get; set; } + public int Corners { get; set; } + public int Radius { get; set; } + public PositionVM Position { get; set; } + } + + public class Deserializer : IFigureDeserializer + { + public bool TryDeserialize(string data, out IFigureView? view) + { + if (!data.StartsWith("polygon")) + { + view = null; + return false; + } + + var parsed = JsonSerializer.Deserialize(data.Substring(data.IndexOf(' ') + 1)); + + view = new PolygonView() + { Name = parsed.Name, radius = parsed.Radius, Position = parsed.Position, corners = parsed.Corners }; + return true; + } + } + + public string Save() + { + var data = new Data { Corners = corners, Radius = Radius, Position = Position, Name = Name }; + return "polygon " + JsonSerializer.Serialize(data); + } + private int corners = 3; private int radius = 5; private int rotate; private static int _counter = 1; - public PolygonView() { + public PolygonView() + { Position = new PositionVM { Chanded = Rebuild }; - Name = "Polygon " + _counter++; + Name = "Polygon " + _counter++; } - + public int Rotate { get { return rotate; } @@ -163,7 +239,7 @@ public class PolygonView : ReactiveObject, IFigureView // start = start.Next; //} //DrawFromTo(vecs.First.Value, vecs.Last.Value); - OnNewSheme.Invoke(shape, this); + OnNewSheme?.Invoke(shape, this); } } @@ -240,10 +316,58 @@ public class OvalView : ReactiveObject, IFigureView } } - public event ShemeUpdate OnNewSheme; + public event ShemeUpdate? OnNewSheme; public PositionVM Position { get; set; } public string Name { get; set; } + public class Data + { + public string Name { get; set; } + public int Height { get; set; } + public int Width { get; set; } + public int Top { get; set; } + public int Bottom { get; set; } + public int Left { get; set; } + public int Right { get; set; } + public PositionVM Position { get; set; } + } + + public class Deserializer : IFigureDeserializer + { + public bool TryDeserialize(string data, out IFigureView? view) + { + if (!data.StartsWith("oval")) + { + view = null; + return false; + } + + var parsed = JsonSerializer.Deserialize(data.Substring(data.IndexOf(' ') + 1)); + view = new OvalView + { + Name = parsed.Name, + bottom = parsed.Bottom, + top = parsed.Top, + heigh = parsed.Height, + left = parsed.Left, + right = parsed.Right, + Position = parsed.Position, + width = parsed.Width, + }; + return true; + } + } + + public string Save() + { + var data = new Data + { + Height = heigh, Width = width, Position = Position, Name = Name, Top = top, Bottom = bottom, Left = left, + Right = right + }; + return "oval " + JsonSerializer.Serialize(data); + } + public double NormalizedLenth(double x, double y) { var hWidth = width / 2; @@ -252,15 +376,16 @@ public class OvalView : ReactiveObject, IFigureView } private static int _counter = 1; - + public OvalView() { Position = new PositionVM { Chanded = Rebuild }; - Name = "Oval " + _counter++; + Name = "Oval " + _counter++; } + public void Rebuild() { int RoundToInt(double value) => (int)Math.Round(value); diff --git a/MCCAD/ViewModels/LoginViewModel.cs b/MCCAD/ViewModels/LoginViewModel.cs new file mode 100644 index 0000000..9fa4524 --- /dev/null +++ b/MCCAD/ViewModels/LoginViewModel.cs @@ -0,0 +1,38 @@ +using System; +using System.Linq; +using System.Windows.Input; +using MCCAD.Models; +using ReactiveUI; + +namespace MCCAD.ViewModels; + +public class LoginViewModel : ViewModelBase, IRoutableViewModel +{ + public LoginViewModel(IScreen hostScreen) + { + HostScreen = hostScreen; + } + + public string? UrlPathSegment { get; } = Guid.NewGuid().ToString(); + public IScreen HostScreen { get; } + public bool InvalidData { get; set; } + public string Login { get; set; } + public string Password { get; set; } + + public ICommand TryAuth => ReactiveCommand.Create(() => + { + if (CadDBContext.Instance.Users.FirstOrDefault(x => x.Login == Login && Password == x.Password) is { } user) + { + CadDBContext.User = user; + switch (user.RoleId) + { + case 1: + HostScreen.Router.Navigate.Execute(new DrawingsCollectionViewModel(HostScreen)); + break; + case 2: + HostScreen.Router.Navigate.Execute(new TeamsViewModel(HostScreen)); + break; + } + } + }); +} \ No newline at end of file diff --git a/MCCAD/ViewModels/MainWindowViewModel.cs b/MCCAD/ViewModels/MainWindowViewModel.cs index 5834d5e..eaca359 100644 --- a/MCCAD/ViewModels/MainWindowViewModel.cs +++ b/MCCAD/ViewModels/MainWindowViewModel.cs @@ -1,35 +1,23 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using MCCAD.Models; using ReactiveUI; namespace MCCAD.ViewModels; -public class MainWindowViewModel : ViewModelBase +public class MainWindowViewModel : ViewModelBase, IScreen { - private OvalView _ov; - private PolygonView _pv; - private LineView _lv; + public RoutingState Router { get; private set; } - public OvalView Ov + public MainWindowViewModel() { - get => _ov; - set => this.RaiseAndSetIfChanged(ref _ov, value); + Router = new RoutingState(); + Router.Navigate.Execute(new LoginViewModel(this)); } - public PolygonView Pv - { - get => _pv; - set => this.RaiseAndSetIfChanged(ref _pv, value); - } + public static string test_data = """ + [ "oval {\"Name\":\"Oval 1\",\"Height\":10,\"Width\":10,\"Top\":0,\"Bottom\":10,\"Left\":0,\"Right\":10,\"Position\":{\"X\":0,\"Y\":0}}", "polygon {\"Name\":\"Polygon 1\",\"Corners\":7,\"Radius\":32,\"Position\":{\"X\":0,\"Y\":0}}", "line {\"Name\":\"Line 1\",\"Angle\":45,\"Lenght\":10,\"Position\":{\"X\":0,\"Y\":0}}" ] + """; - public LineView Lv - { - get => _lv; - set => this.RaiseAndSetIfChanged(ref _lv, value); - } +} - public int A { get; set; } - public string Greeting { get; set; } - - public ObservableCollection Figures { get; set; } = []; -} \ No newline at end of file diff --git a/MCCAD/ViewModels/TeamsViewModel.cs b/MCCAD/ViewModels/TeamsViewModel.cs new file mode 100644 index 0000000..7c16310 --- /dev/null +++ b/MCCAD/ViewModels/TeamsViewModel.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using System.Windows.Input; +using DynamicData; +using MCCAD.Models; +using ReactiveUI; + +namespace MCCAD.ViewModels; + +public class TeamsViewModel : ViewModelBase, IRoutableViewModel +{ + private string _searchString = ""; + + public TeamsViewModel(IScreen hostScreen) + { + HostScreen = hostScreen; + teams = CadDBContext.Instance.Teams.Where(i => i.CreatorId == CadDBContext.User.Id).ToList(); + Teams.AddRange(teams); + } + + private List teams; + public ObservableCollection Teams { get; set; } = []; + public string? UrlPathSegment { get; } = Guid.NewGuid().ToString(); + public IScreen HostScreen { get; } + public ICommand Exit => ReactiveCommand.Create(() => HostScreen.Router.NavigateBack.Execute()); + + public string SearchString + { + get => _searchString; + set + { + _searchString = value; + Teams.Clear(); + Teams.AddRange(string.IsNullOrWhiteSpace(_searchString) + ? teams + : teams.Where(i => i.Name.Contains(SearchString, StringComparison.CurrentCultureIgnoreCase))); + } + } +} \ No newline at end of file diff --git a/MCCAD/Views/DrawingView.axaml b/MCCAD/Views/DrawingView.axaml new file mode 100644 index 0000000..824d32c --- /dev/null +++ b/MCCAD/Views/DrawingView.axaml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + Новый элипс + Новый многоугольник + Новая линия + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Угол + + + Длина + + + + + + + + + + + + + + + + + + + + + + + + + + + Слои + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MCCAD/Views/DrawingView.axaml.cs b/MCCAD/Views/DrawingView.axaml.cs new file mode 100644 index 0000000..83c6473 --- /dev/null +++ b/MCCAD/Views/DrawingView.axaml.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using MCCAD.Models; +using MCCAD.ViewModels; +using ReactiveUI.Avalonia; + +namespace MCCAD.Views; + +public partial class DrawingView : ReactiveUserControl +{ + public Dictionary _cache = new(); + public bool mark = true; + private const int BlockSize = 15; + + private bool _switching; + + public DrawingView() + { + InitializeComponent(); + } + + protected override void OnDataContextChanged(EventArgs e) + { + if (ViewModel != null) + { + foreach (var viewModelFigure in ViewModel.Figures) + { + viewModelFigure.OnNewSheme += DrawShape; + viewModelFigure.Rebuild(); + } + } + } + + + void DrawShape(List points, IFigureView view) + { + if (!_cache.TryGetValue(view, out Canvas canvas)) + { + canvas = new Canvas(); + _cache.Add(view, canvas); + SchemeCanvas.Children.Add(canvas); + } + + canvas.Children.Clear(); + + canvas.Width = points.Select(i => i.X).Max() * BlockSize; + canvas.Height = points.Select(i => i.Y).Max() * BlockSize; + Dictionary markup = new Dictionary(); + + if (mark) + { + var lined = points.OrderBy(i => i.Y).GroupBy(i => i.Y); + foreach (var l in lined) + { + if (l.Count() < 3) + continue; + var line = l.OrderBy(i => i.X).ToList(); + var linePoint = new List { 0 }; + for (int i = 0; i < line.Count; i++) + { + if (i != line.Count - 1 && line[i].X != line[i + 1].X - 1) + { + linePoint.Add(i); + linePoint.Add(i + 1); + } + } + + linePoint.Add(line.Count - 1); + + var linesIds = linePoint.Chunk(2); + foreach (var microLineId in linesIds) + { + var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList(); + if (micloLine.Count > 2) + { + markup.Add(micloLine.First(), "←"); + markup.Add(micloLine.Last(), "→"); + markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString()); + } + } + } + + lined = points.OrderBy(i => i.X).GroupBy(i => i.X); + foreach (var l in lined) + { + if (l.Count() < 3) + continue; + var line = l.OrderBy(i => i.Y).ToList(); + var linePoint = new List() { 0 }; + for (int i = 0; i < line.Count; i++) + { + if (i != line.Count - 1 && line[i].Y != line[i + 1].Y - 1) + { + linePoint.Add(i); + linePoint.Add(i + 1); + } + } + + linePoint.Add(line.Count - 1); + + var linesIds = linePoint.Chunk(2); + foreach (var microLineId in linesIds) + { + var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList(); + if (micloLine.Count > 2) + { + if (!markup.TryAdd(micloLine.First(), "↑")) + { + markup[micloLine.First()] = "+"; + } + + if (!markup.TryAdd(micloLine.Last(), "↓")) + { + markup[micloLine.Last()] = "+"; + } + + markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString()); + } + } + } + } + + foreach (var point in points) + { + Border block = new Border(); + block.Height = BlockSize; + block.Width = BlockSize; + block.BorderThickness = new Thickness(2); + block.Background = new SolidColorBrush(Colors.LightGray); + block.DataContext = point; + block.PointerEntered += (sender, e) => { CurrentBlock.Text = (sender as Border).DataContext.ToString(); }; + if (mark) + { + if (markup.TryGetValue(point, out var text)) + block.Child = new TextBlock + { + Text = text, HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, FontSize = 10 + }; + } + + Canvas.SetLeft(block, (point.X + view.Position.X) * BlockSize); + Canvas.SetTop(block, (point.Y + view.Position.Y) * BlockSize); + canvas.Children.Add(block); + } + + canvas.Width = BlockSize * (points.Select(i => i.X).Max() + 5); + canvas.Height = BlockSize * (points.Select(i => i.Y).Max() + 5); + + TotalTB.Text = points.Count.ToString(); + } + + + private void Slider_ValueChanged(object? sender, RangeBaseValueChangedEventArgs rangeBaseValueChangedEventArgs) + { + if (SchemeCanvas == null) + return; + var e = rangeBaseValueChangedEventArgs; + SchemeCanvas.RenderTransform = new ScaleTransform() { ScaleX = e.NewValue / 100, ScaleY = e.NewValue / 100 }; + ScaleTB.Text = Math.Round(rangeBaseValueChangedEventArgs.NewValue) + "%"; + } + + private void CreateShape(object? sender, RoutedEventArgs routedEventArgs) + { + try + { + var x = (sender as Control).Tag; + switch (x) + { + case "Ov": + ViewModel.Ov = new OvalView(); + ViewModel.Ov.OnNewSheme += DrawShape; + ViewModel.Ov.Rebuild(); + ViewModel.Figures.Add(ViewModel.Ov); + SetupVisiblePanel(0); + break; + case "Pv": + ViewModel.Pv = new PolygonView(); + ViewModel.Pv.OnNewSheme += DrawShape; + ViewModel.Pv.Rebuild(); + ViewModel.Figures.Add(ViewModel.Pv); + SetupVisiblePanel(1); + break; + case "Lv": + ViewModel.Lv = new LineView(); + ViewModel.Lv.OnNewSheme += DrawShape; + ViewModel.Lv.Rebuild(); + ViewModel.Figures.Add(ViewModel.Lv); + SetupVisiblePanel(2); + break; + } + } + catch (Exception exception) + { + } + } + + private void SetupSelected(object? sender, SelectionChangedEventArgs e) + { + if (Layers.SelectedItem == null) + { + return; + } + + _switching = true; + switch (Layers.SelectedItem) + { + case OvalView ov: + ViewModel.Ov = ov; + SetupVisiblePanel(0); + break; + case PolygonView pv: + ViewModel.Pv = pv; + SetupVisiblePanel(1); + break; + case LineView lv: + ViewModel.Lv = lv; + SetupVisiblePanel(2); + break; + } + } + + private void SetupVisiblePanel(int index) + { + for (var i = 0; i < ToolsTab.Children.Count; i++) + { + ToolsTab.Children[i].IsVisible = i == index; + } + } +} \ No newline at end of file diff --git a/MCCAD/Views/DrawingsCollectionView.axaml b/MCCAD/Views/DrawingsCollectionView.axaml new file mode 100644 index 0000000..c68595c --- /dev/null +++ b/MCCAD/Views/DrawingsCollectionView.axaml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + Название + + + + + + + + + \ No newline at end of file diff --git a/MCCAD/Views/DrawingsCollectionView.axaml.cs b/MCCAD/Views/DrawingsCollectionView.axaml.cs new file mode 100644 index 0000000..511b7dc --- /dev/null +++ b/MCCAD/Views/DrawingsCollectionView.axaml.cs @@ -0,0 +1,15 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using MCCAD.ViewModels; +using ReactiveUI.Avalonia; + +namespace MCCAD.Views; + +public partial class DrawingsCollectionView : ReactiveUserControl +{ + public DrawingsCollectionView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/MCCAD/Views/LoginView.axaml b/MCCAD/Views/LoginView.axaml new file mode 100644 index 0000000..ca45402 --- /dev/null +++ b/MCCAD/Views/LoginView.axaml @@ -0,0 +1,41 @@ + + + + + + + + Авторизация + Введите ваш логин и пароль + Логин или пароль неверны + + + + + \ No newline at end of file diff --git a/MCCAD/Views/LoginView.axaml.cs b/MCCAD/Views/LoginView.axaml.cs new file mode 100644 index 0000000..6db62ae --- /dev/null +++ b/MCCAD/Views/LoginView.axaml.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using Avalonia.VisualTree; +using MCCAD.ViewModels; +using ReactiveUI.Avalonia; + +namespace MCCAD.Views; + +public partial class LoginView : ReactiveUserControl +{ + private const double Button_VISIBLE = 30; + + public LoginView() + { + InitializeComponent(); + } + + private void UpdateLoginVisibility(object? sender, TextChangedEventArgs e) + { + LoginButton.Height = string.IsNullOrWhiteSpace(LoginText.Text) || + string.IsNullOrWhiteSpace(PasswordText.Text) || PasswordText.Text.Length < 6 + ? 0 + : Button_VISIBLE; + } +} \ No newline at end of file diff --git a/MCCAD/Views/MainWindow.axaml b/MCCAD/Views/MainWindow.axaml index 55589ff..1e3c03f 100644 --- a/MCCAD/Views/MainWindow.axaml +++ b/MCCAD/Views/MainWindow.axaml @@ -4,152 +4,17 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - xmlns:mcd="using:MCCAD.ViewModels" - xmlns:views="clr-namespace:MCCAD.Views" x:Class="MCCAD.Views.MainWindow" x:DataType="vm:MainWindowViewModel" + xmlns:rui="clr-namespace:ReactiveUI.Avalonia;assembly=ReactiveUI.Avalonia" + xmlns:mccad="clr-namespace:MCCAD" Icon="/Assets/avalonia-logo.ico" Title="MCCAD"> - - - - - - - - - - - - Новый элипс - Новый многоугольник - Новая линия - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Угол - - - Длина - - - - - - - - - - - - - - - - - - - - - - - - - - - Слои - - - - - - - - - - - - + + + + + \ No newline at end of file diff --git a/MCCAD/Views/MainWindow.axaml.cs b/MCCAD/Views/MainWindow.axaml.cs index 8d3e055..98cf828 100644 --- a/MCCAD/Views/MainWindow.axaml.cs +++ b/MCCAD/Views/MainWindow.axaml.cs @@ -14,217 +14,8 @@ namespace MCCAD.Views; public partial class MainWindow : Window { - public Dictionary _cache = new(); - public bool mark = true; - int blockSize = 15; - - private bool switching = false; - private MainWindowViewModel DC => DataContext as MainWindowViewModel; - public MainWindow() { InitializeComponent(); } - - protected override void OnDataContextChanged(EventArgs e) - { - - } - - - void DrawShape(List points, IFigureView view) - { - if (!_cache.TryGetValue(view, out Canvas canvas)) - { - canvas = new Canvas(); - _cache.Add(view, canvas); - ShemeChanvas.Children.Add(canvas); - } - canvas.Children.Clear(); - - canvas.Width = points.Select(i => i.X).Max() * blockSize; - canvas.Height = points.Select(i => i.Y).Max() * blockSize; - Dictionary markup = new Dictionary(); - - if (mark) - { - var lined = points.OrderBy(i => i.Y).GroupBy(i => i.Y); - foreach (var l in lined) - { - if (l.Count() < 3) - continue; - var line = l.OrderBy(i => i.X).ToList(); - var linePoint = new List { 0 }; - for (int i = 0; i < line.Count; i++) - { - if (i != line.Count - 1 && line[i].X != line[i + 1].X - 1) - { - linePoint.Add(i); - linePoint.Add(i + 1); - } - } - - linePoint.Add(line.Count - 1); - - var linesIds = linePoint.Chunk(2); - foreach (var microLineId in linesIds) - { - var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList(); - if (micloLine.Count > 2) - { - markup.Add(micloLine.First(), "←"); - markup.Add(micloLine.Last(), "→"); - markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString()); - } - } - } - - lined = points.OrderBy(i => i.X).GroupBy(i => i.X); - foreach (var l in lined) - { - if (l.Count() < 3) - continue; - var line = l.OrderBy(i => i.Y).ToList(); - var linePoint = new List() { 0 }; - for (int i = 0; i < line.Count; i++) - { - if (i != line.Count - 1 && line[i].Y != line[i + 1].Y - 1) - { - linePoint.Add(i); - linePoint.Add(i + 1); - } - } - - linePoint.Add(line.Count - 1); - - var linesIds = linePoint.Chunk(2); - foreach (var microLineId in linesIds) - { - var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList(); - if (micloLine.Count > 2) - { - if (!markup.TryAdd(micloLine.First(), "↑")) - { - markup[micloLine.First()] = "+"; - } - - if (!markup.TryAdd(micloLine.Last(), "↓")) - { - markup[micloLine.Last()] = "+"; - } - - markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString()); - } - } - } - } - - foreach (var point in points) - { - Border block = new Border(); - block.Height = blockSize; - block.Width = blockSize; - block.BorderThickness = new Thickness(2); - block.Background = new SolidColorBrush(Colors.LightGray); - block.DataContext = point; - block.PointerEntered += (sender, e) => { CurrentBlock.Text = (sender as Border).DataContext.ToString(); }; - if (mark) - { - if (markup.TryGetValue(point, out var text)) - block.Child = new TextBlock - { - Text = text, HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, FontSize = 10 - }; - } - - Canvas.SetLeft(block, (point.X + view.Position.X) * blockSize); - Canvas.SetTop(block, (point.Y + view.Position.Y) * blockSize); - canvas.Children.Add(block); - } - - canvas.Width = blockSize * (points.Select(i => i.X).Max() + 5); - canvas.Height = blockSize * (points.Select(i => i.Y).Max() + 5); - - TotalTB.Text = points.Count.ToString(); - } - - - private void Slider_ValueChanged(object? sender, RangeBaseValueChangedEventArgs rangeBaseValueChangedEventArgs) - { - if (ShemeChanvas == null) - return; - var e = rangeBaseValueChangedEventArgs; - ShemeChanvas.RenderTransform = new ScaleTransform() { ScaleX = e.NewValue / 100, ScaleY = e.NewValue / 100 }; - // ShemeChanvas.transf.LayoutTransform = new ScaleTransform() { ScaleX = e.NewValue / 95, ScaleY = e.NewValue / 95 }; - ScaleTB.Text = Math.Round(rangeBaseValueChangedEventArgs.NewValue) + "%"; - } - - private void CreateShape(object? sender, RoutedEventArgs routedEventArgs) - { - try - { - var x = (sender as Control).Tag; - switch (x) - { - case "Ov": - DC.Ov = new OvalView(); - DC.Ov.OnNewSheme += DrawShape; - DC.Ov.Rebuild(); - DC.Figures.Add(DC.Ov); - SetupVisiblePanel(0); - break; - case "Pv": - DC.Pv = new PolygonView(); - DC.Pv.OnNewSheme += DrawShape; - DC.Pv.Rebuild(); - DC.Figures.Add(DC.Pv); - SetupVisiblePanel(1); - break; - case "Lv": - DC.Lv = new LineView(); - DC.Lv.OnNewSheme += DrawShape; - DC.Lv.Rebuild(); - DC.Figures.Add(DC.Lv); - SetupVisiblePanel(2); - break; - } - } - catch (Exception exception) - { - } - } - - private void SetupSelected(object? sender, SelectionChangedEventArgs e) - { - if (Layers.SelectedItem == null) - { - return; - } - - switching = true; - switch (Layers.SelectedItem) - { - case OvalView ov: - DC.Ov = ov; - SetupVisiblePanel(0); - break; - case PolygonView pv: - DC.Pv = pv; - SetupVisiblePanel(1); - break; - case LineView lv: - DC.Lv = lv; - SetupVisiblePanel(2); - break; - } - } - - private void SetupVisiblePanel(int index) - { - for (var i = 0; i < ToolsTab.Children.Count; i++) - { - ToolsTab.Children[i].IsVisible = i == index; - } - } } \ No newline at end of file diff --git a/MCCAD/Views/PositionControl.axaml b/MCCAD/Views/PositionControl.axaml index 8ad982e..20879ca 100644 --- a/MCCAD/Views/PositionControl.axaml +++ b/MCCAD/Views/PositionControl.axaml @@ -7,11 +7,11 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="MCCAD.Views.PositionControl" x:DataType="viewModels:PositionVM"> - - X: - Y: - - - + + X: + Y: + + + - + \ No newline at end of file diff --git a/MCCAD/Views/TeamsView.axaml b/MCCAD/Views/TeamsView.axaml new file mode 100644 index 0000000..8ea4a4c --- /dev/null +++ b/MCCAD/Views/TeamsView.axaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MCCAD/Views/TeamsView.axaml.cs b/MCCAD/Views/TeamsView.axaml.cs new file mode 100644 index 0000000..ada22ea --- /dev/null +++ b/MCCAD/Views/TeamsView.axaml.cs @@ -0,0 +1,20 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using MCCAD.ViewModels; +using ReactiveUI.Avalonia; + +namespace MCCAD.Views; + +public partial class TeamsView : ReactiveUserControl +{ + public TeamsView() + { + InitializeComponent(); + } + + private void SelectingItemsControl_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) + { + + } +} \ No newline at end of file