groundlaying functionality

This commit is contained in:
Ano-sys
2025-02-19 01:05:22 +01:00
commit 6971b05226
14 changed files with 495 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SimpleDraw.App"
xmlns:local="using:SimpleDraw"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>
+33
View File
@@ -0,0 +1,33 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using SimpleDraw.ViewModels;
using SimpleDraw.Views;
namespace SimpleDraw;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Line below is needed to remove Avalonia data validation.
// Without this line you will get duplicate validations from both Avalonia and CT
BindingPlugins.DataValidators.RemoveAt(0);
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
}
base.OnFrameworkInitializationCompleted();
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

+21
View File
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.ComponentModel;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace SimpleDraw.Models;
public class ColorPickerButton : ObservableObject
{
private SolidColorBrush _color;
public RelayCommand SelectColorCommand { get; set; }
public SolidColorBrush Color
{
get => _color;
set => _color = value;
}
// public event PropertyChangedEventHandler? PropertyChanged;
}
+47
View File
@@ -0,0 +1,47 @@
using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SimpleDraw.Models;
public class DrawingPoints : ObservableObject
{
private ObservableCollection<Point> _drawingPoints = new ObservableCollection<Point>();
// private ObservableCollection<ObservableCollection<Point>> _drawingPointsList = new ObservableCollection<ObservableCollection<Point>>();
private Brush _brush;
private double _brushThickness;
public Brush Brush
{
get => _brush;
set => SetProperty(ref _brush, value);
}
public double BrushThickness
{
get => _brushThickness;
set => SetProperty(ref _brushThickness, value);
}
public ObservableCollection<Point> CurrentDrawingPoints
{
get => _drawingPoints;
set => SetProperty(ref _drawingPoints, value);
}
public DrawingPoints(Brush brush, double brushThickness)
{
Brush = brush;
BrushThickness = brushThickness;
}
/*
public ObservableCollection<ObservableCollection<Point>> DrawingPointsList
{
get => _drawingPointsList;
set => SetProperty(ref _drawingPointsList, value);
}
*/
}
+21
View File
@@ -0,0 +1,21 @@
using Avalonia;
using System;
namespace SimpleDraw;
sealed class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
+25
View File
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.4" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.4" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.4" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.4" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.4" />
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.2.0.8" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1"/>
</ItemGroup>
</Project>
+16
View File
@@ -0,0 +1,16 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleDraw", "SimpleDraw.csproj", "{3BB82696-53EB-4433-BB71-E40A2AC7395D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3BB82696-53EB-4433-BB71-E40A2AC7395D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3BB82696-53EB-4433-BB71-E40A2AC7395D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3BB82696-53EB-4433-BB71-E40A2AC7395D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3BB82696-53EB-4433-BB71-E40A2AC7395D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
+33
View File
@@ -0,0 +1,33 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using SimpleDraw.ViewModels;
namespace SimpleDraw;
public class ViewLocator : IDataTemplate
{
public Control? Build(object? data)
{
if (data is null)
return null;
var name = data.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
var control = (Control)Activator.CreateInstance(type)!;
control.DataContext = data;
return control;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}
+107
View File
@@ -0,0 +1,107 @@
using Avalonia;
using Avalonia.Input;
using Avalonia.Media;
using CommunityToolkit.Mvvm.Input;
using SimpleDraw.Models;
namespace SimpleDraw.ViewModels;
public class MainWindowViewModel : ViewModelBase
{
#pragma warning disable CA1822 // Mark members as static
public MainWindowViewModel()
{
ColorPalette =
[
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 255, g: 255, b: 255, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 0, g: 0, b: 0, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 128, g: 128, b: 128, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 255, g: 0, b: 0, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 0, g: 255, b: 0, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 0, g: 0, b: 255, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 128, g: 0, b: 128, a: 255)),
},
new ColorPickerButton
{
Color = new SolidColorBrush(new Color(r: 128, g: 128, b: 0, a: 255)),
}
];
foreach (ColorPickerButton colorPickerButton in ColorPalette)
{
var currentColor = colorPickerButton.Color;
colorPickerButton.SelectColorCommand = new RelayCommand(() => ChangeSelectedColor(currentColor));
}
Brush = new SolidColorBrush(Colors.Black);
CanvasPointerPressedCommand = new RelayCommand<PointerPressedEventArgs>(OnCanvasPointerPressed);
CanvasPointerMovedCommand = new RelayCommand<PointerEventArgs>(OnCanvasPointerMoved);
CanvasPointerReleasedCommand = new RelayCommand<PointerReleasedEventArgs>(OnCanvasPointerReleased);
}
#pragma warning restore CA1822 // Mark members as static
private void ChangeSelectedColor(SolidColorBrush color)
{
Brush = color;
}
private void OnCanvasPointerPressed(PointerPressedEventArgs? e)
{
if (e == null) return;
IsDrawing = true;
DrawingPoints.Add(new DrawingPoints(Brush, BrushThickness));
DrawingPoint = DrawingPoints[^1];
// DrawingPoints.DrawingPointsList.Add(DrawingPoints.CurrentDrawingPoints);
if (e.Source is Visual visual)
{
var point = e.GetPosition(visual);
DrawingPoint.CurrentDrawingPoints.Add(point);
}
}
private void OnCanvasPointerMoved(PointerEventArgs? e)
{
if (e == null || !IsDrawing) return;
if (e.Source is Visual visual)
{
var point = e.GetPosition(visual);
DrawingPoint?.CurrentDrawingPoints.Add(point);
}
}
private void OnCanvasPointerReleased(PointerReleasedEventArgs? e)
{
IsDrawing = false;
}
}
+35
View File
@@ -0,0 +1,35 @@
using System.Collections.ObjectModel;
using Avalonia.Input;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SimpleDraw.Models;
namespace SimpleDraw.ViewModels;
public class ViewModelBase : ObservableObject
{
public ObservableCollection<ColorPickerButton>? ColorPalette { get; set; }
public IRelayCommand<PointerPressedEventArgs>? CanvasPointerPressedCommand { get; set; }
public IRelayCommand<PointerEventArgs>? CanvasPointerMovedCommand { get; set; }
public IRelayCommand<PointerReleasedEventArgs>? CanvasPointerReleasedCommand { get; set; }
public ObservableCollection<DrawingPoints> DrawingPoints { get; set; } = new();
public DrawingPoints? DrawingPoint { get; set; }
protected bool IsDrawing { get; set; }
private Brush _brush = new SolidColorBrush(new Color(a: 255, r: 0, g: 0, b: 0));
private double _brushThickness = 2.0;
protected Brush Brush
{
get => _brush;
set => SetProperty(ref _brush, value);
}
public double BrushThickness
{
get => _brushThickness;
set => SetProperty(ref _brushThickness, value);
}
}
+111
View File
@@ -0,0 +1,111 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:SimpleDraw.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="clr-namespace:SimpleDraw.Models"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SimpleDraw.Views.MainWindow"
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:behaviors="using:Avalonia.Xaml.Interactions.Core"
xmlns:componentModel="clr-namespace:CommunityToolkit.Mvvm.ComponentModel;assembly=CommunityToolkit.Mvvm"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="SimpleDraw">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<Panel>
<Menu>
<MenuItem>
File
</MenuItem>
<MenuItem>
Edit
</MenuItem>
</Menu>
<Grid Background="Gray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="105"></ColumnDefinition>
<ColumnDefinition Width="1*" MinWidth="300"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="1*" MinHeight="300"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Grid.Column="0" Background="LightGray">
<Grid.RowDefinitions>
<RowDefinition Height="50*"></RowDefinition>
<RowDefinition Height="50*"></RowDefinition>
<RowDefinition Height="50*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBox Text="Select Color:" IsHitTestVisible="False" IsReadOnly="True" BorderThickness="0" Background="Transparent"/>
<ItemsControl ItemsSource="{Binding ColorPalette}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:ColorPickerButton">
<Button Margin="5,0,0,5"
BorderBrush="DimGray"
BorderThickness="2"
CornerRadius="12.5"
Background="{Binding Color}"
Width="20"
Height="20"
Command="{Binding SelectColorCommand}"
CommandParameter="{Binding}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Slider Margin="5" Value="{Binding BrushThickness}" Maximum="50" Minimum="0.5"></Slider>
</StackPanel>
</Grid>
<Canvas Grid.Row="1" Grid.Column="1" Background="White">
<i:Interaction.Behaviors>
<behaviors:EventTriggerBehavior EventName="PointerPressed">
<behaviors:InvokeCommandAction
Command="{Binding CanvasPointerPressedCommand}"
PassEventArgsToCommand="True" />
</behaviors:EventTriggerBehavior>
<behaviors:EventTriggerBehavior EventName="PointerMoved">
<behaviors:InvokeCommandAction
Command="{Binding CanvasPointerMovedCommand}"
PassEventArgsToCommand="True" />
</behaviors:EventTriggerBehavior>
<behaviors:EventTriggerBehavior EventName="PointerReleased">
<behaviors:InvokeCommandAction
Command="{Binding CanvasPointerReleasedCommand}"
PassEventArgsToCommand="True" />
</behaviors:EventTriggerBehavior>
</i:Interaction.Behaviors>
<ItemsControl ItemsSource="{Binding DrawingPoints}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Panel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Polyline Points="{Binding CurrentDrawingPoints}"
Stroke="{Binding Brush}"
StrokeThickness="{Binding BrushThickness}"
>
</Polyline>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Grid>
</Panel>
</Window>
+13
View File
@@ -0,0 +1,13 @@
using Avalonia.Controls;
using SimpleDraw.ViewModels;
namespace SimpleDraw.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="SimpleDraw.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>