feat: WIP.
This commit is contained in:
@@ -14,7 +14,6 @@
|
|||||||
<Grid ColumnDefinitions="*, 300">
|
<Grid ColumnDefinitions="*, 300">
|
||||||
<Grid Grid.Column="0">
|
<Grid Grid.Column="0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<u:RatingCharacter />
|
|
||||||
<u:Rating
|
<u:Rating
|
||||||
AllowClear="{Binding AllowClear }"
|
AllowClear="{Binding AllowClear }"
|
||||||
AllowHalf="{Binding AllowHalf }"
|
AllowHalf="{Binding AllowHalf }"
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ public partial class RatingDemoViewModel : ViewModelBase
|
|||||||
[ObservableProperty] private double _value;
|
[ObservableProperty] private double _value;
|
||||||
|
|
||||||
// [ObservableProperty] private object _character;
|
// [ObservableProperty] private object _character;
|
||||||
[ObservableProperty] private int _count = 10;
|
[ObservableProperty] private int _count = 5;
|
||||||
[ObservableProperty] private double _defaultValue = 5.5;
|
[ObservableProperty] private double _defaultValue = 2.3;
|
||||||
|
|
||||||
public ObservableCollection<string> Tooltips { get; set; } = ["1", "2", "3", "4", "5"];
|
public ObservableCollection<string> Tooltips { get; set; } = ["1", "2", "3", "4", "5"];
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
xmlns:u="https://irihi.tech/ursa">
|
xmlns:u="https://irihi.tech/ursa">
|
||||||
<ControlTheme x:Key="{x:Type u:RatingCharacter}" TargetType="u:RatingCharacter">
|
<ControlTheme x:Key="{x:Type u:RatingCharacter}" TargetType="u:RatingCharacter">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource RatingCharacterUnSelectedForeground}" />
|
<Setter Property="Foreground" Value="{DynamicResource RatingCharacterUnSelectedForeground}" />
|
||||||
<Setter Property="Background" Value="{DynamicResource RatingCharacterUnSelectedForeground}" />
|
<Setter Property="Background" Value="{DynamicResource RatingCharacterBackground}" />
|
||||||
<Setter Property="Cursor" Value="Hand" />
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
Data="{DynamicResource RatingStarIconGlyph}"
|
Data="{DynamicResource RatingStarIconGlyph}"
|
||||||
Fill="{TemplateBinding Background}" />
|
Fill="{TemplateBinding Background}" />
|
||||||
<Border Name="{x:Static u:RatingCharacter.PART_IconGlyph}"
|
<Border Name="{x:Static u:RatingCharacter.PART_IconGlyph}"
|
||||||
IsVisible="True"
|
|
||||||
ClipToBounds="True">
|
ClipToBounds="True">
|
||||||
<Path Width="24"
|
<Path Width="24"
|
||||||
Height="24"
|
Height="24"
|
||||||
@@ -32,15 +31,7 @@
|
|||||||
<Setter Property="RenderTransform" Value="scale(1.1)" />
|
<Setter Property="RenderTransform" Value="scale(1.1)" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="^:selected">
|
<Style Selector="^:selected">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource RatingCharacterSelectedForeground}" />
|
<Setter Property="Foreground" Value="{DynamicResource RatingCharacterForeground}" />
|
||||||
</Style>
|
|
||||||
<Style Selector="^:half">
|
|
||||||
<!-- <Setter Property="Foreground"> -->
|
|
||||||
<!-- <LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%"> -->
|
|
||||||
<!-- <GradientStop Color="#6b4c1b" Offset="0" /> -->
|
|
||||||
<!-- <GradientStop Color="#291e10" Offset="1" /> -->
|
|
||||||
<!-- </LinearGradientBrush> -->
|
|
||||||
<!-- </Setter> -->
|
|
||||||
</Style>
|
</Style>
|
||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
<SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Opacity="0.12" Color="White" />
|
<SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Color="Transparent" />
|
||||||
<SolidColorBrush x:Key="RatingCharacterSelectedForeground" Color="#FDDE43" />
|
<SolidColorBrush x:Key="RatingCharacterForeground" Color="#FDDE43" />
|
||||||
|
<SolidColorBrush x:Key="RatingCharacterBackground" Opacity="0.12" Color="White" />
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
<SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Opacity="0.05" Color="#2E3238" />
|
<SolidColorBrush x:Key="RatingCharacterUnSelectedForeground" Color="Transparent" />
|
||||||
<SolidColorBrush x:Key="RatingCharacterSelectedForeground" Color="#FAC800" />
|
<SolidColorBrush x:Key="RatingCharacterForeground" Color="#FAC800" />
|
||||||
|
<SolidColorBrush x:Key="RatingCharacterBackground" Opacity="0.05" Color="#2E3238" />
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
@@ -137,7 +137,11 @@ public class Rating : TemplatedControl
|
|||||||
|
|
||||||
private void OnValueChanged(AvaloniaPropertyChangedEventArgs e)
|
private void OnValueChanged(AvaloniaPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
UpdateItems((int)Value - 1);
|
if (e.NewValue is double newValue)
|
||||||
|
{
|
||||||
|
UpdateItemsByValue(newValue);
|
||||||
|
AdjustWidth(newValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCountChanged(AvaloniaPropertyChangedEventArgs e)
|
private void OnCountChanged(AvaloniaPropertyChangedEventArgs e)
|
||||||
@@ -164,10 +168,8 @@ public class Rating : TemplatedControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Value > newCount)
|
UpdateItemsByValue(Value);
|
||||||
{
|
AdjustWidth(Value);
|
||||||
SetCurrentValue(ValueProperty, Math.Max(newCount, 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
@@ -180,7 +182,6 @@ public class Rating : TemplatedControl
|
|||||||
Items.Add(new RatingCharacter());
|
Items.Add(new RatingCharacter());
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateItems((int)DefaultValue - 1);
|
|
||||||
if (DefaultValue > Count)
|
if (DefaultValue > Count)
|
||||||
{
|
{
|
||||||
SetCurrentValue(ValueProperty, Math.Max(Count, 0));
|
SetCurrentValue(ValueProperty, Math.Max(Count, 0));
|
||||||
@@ -207,15 +208,15 @@ public class Rating : TemplatedControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateItems(index);
|
UpdateItemsByIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPointerExited(PointerEventArgs e)
|
protected override void OnPointerExited(PointerEventArgs e)
|
||||||
{
|
{
|
||||||
UpdateItems((int)Value - 1);
|
UpdateItemsByValue(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Select(RatingCharacter o)
|
public void PointerReleasedHandler(RatingCharacter o)
|
||||||
{
|
{
|
||||||
var index = Items.IndexOf(o);
|
var index = Items.IndexOf(o);
|
||||||
double newValue = index + 1;
|
double newValue = index + 1;
|
||||||
@@ -226,23 +227,25 @@ public class Rating : TemplatedControl
|
|||||||
|
|
||||||
if (AllowClear && Math.Abs(Value - newValue) < Tolerance)
|
if (AllowClear && Math.Abs(Value - newValue) < Tolerance)
|
||||||
{
|
{
|
||||||
UpdateItems(-1);
|
UpdateItemsByValue(-1);
|
||||||
SetCurrentValue(ValueProperty, 0);
|
SetCurrentValue(ValueProperty, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateItems(index);
|
UpdateItemsByValue(newValue);
|
||||||
SetCurrentValue(ValueProperty, newValue);
|
SetCurrentValue(ValueProperty, newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateItems(int index)
|
private void UpdateItemsByIndex(int index)
|
||||||
{
|
{
|
||||||
|
var isInt = Math.Abs(Value - Math.Floor(Value)) < Tolerance;
|
||||||
for (var i = 0; i <= index && i < Items.Count; i++)
|
for (var i = 0; i <= index && i < Items.Count; i++)
|
||||||
{
|
{
|
||||||
if (Items[i] is RatingCharacter item)
|
if (Items[i] is RatingCharacter item)
|
||||||
{
|
{
|
||||||
item.Select(true);
|
item.Select(true);
|
||||||
|
item.IsHalf = !isInt && i == index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,6 +254,34 @@ public class Rating : TemplatedControl
|
|||||||
if (Items[i] is RatingCharacter item)
|
if (Items[i] is RatingCharacter item)
|
||||||
{
|
{
|
||||||
item.Select(false);
|
item.Select(false);
|
||||||
|
item.IsHalf = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateItemsByValue(double newValue)
|
||||||
|
{
|
||||||
|
var index = (int)Math.Ceiling(newValue - 1);
|
||||||
|
UpdateItemsByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdjustWidth(double newValue)
|
||||||
|
{
|
||||||
|
var ratio = Math.Abs(newValue - Math.Floor(newValue));
|
||||||
|
foreach (var character in Items)
|
||||||
|
{
|
||||||
|
if (character is RatingCharacter item)
|
||||||
|
{
|
||||||
|
if (item.IsHalf)
|
||||||
|
{
|
||||||
|
item.Ratio = ratio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Ratio = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.AdjustWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ using Avalonia.LogicalTree;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
[PseudoClasses(PC_Selected, PC_Half)]
|
[PseudoClasses(PC_Selected)]
|
||||||
[TemplatePart(PART_IconGlyph, typeof(Control))]
|
[TemplatePart(PART_IconGlyph, typeof(Control))]
|
||||||
public class RatingCharacter : TemplatedControl
|
public class RatingCharacter : TemplatedControl
|
||||||
{
|
{
|
||||||
public const string PART_IconGlyph = "PART_IconGlyph";
|
public const string PART_IconGlyph = "PART_IconGlyph";
|
||||||
protected const string PC_Selected = ":selected";
|
protected const string PC_Selected = ":selected";
|
||||||
protected const string PC_Half = ":half";
|
|
||||||
|
|
||||||
private Control? _icon;
|
private Control? _icon;
|
||||||
|
|
||||||
@@ -23,13 +22,14 @@ public class RatingCharacter : TemplatedControl
|
|||||||
get => _isHalf;
|
get => _isHalf;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_isHalf == value) return;
|
|
||||||
_isHalf = value;
|
_isHalf = value;
|
||||||
if (_icon is null) return;
|
if (_icon is null) return;
|
||||||
_icon.Width = value ? Bounds.Width / 2 : Bounds.Width;
|
_icon.Width = value ? Bounds.Width * 0.5 : Bounds.Width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal double Ratio { get; set; }
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
@@ -45,32 +45,25 @@ public class RatingCharacter : TemplatedControl
|
|||||||
protected override void OnPointerMoved(PointerEventArgs e)
|
protected override void OnPointerMoved(PointerEventArgs e)
|
||||||
{
|
{
|
||||||
var p = e.GetPosition(this);
|
var p = e.GetPosition(this);
|
||||||
var flag = p.X < Bounds.Width / 2;
|
IsHalf = p.X < Bounds.Width * 0.5;
|
||||||
PseudoClasses.Set(PC_Half, flag);
|
|
||||||
IsHalf = flag;
|
|
||||||
// if (flag)
|
|
||||||
// {
|
|
||||||
// _icon.Width = Bounds.Width / 2;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// _icon.Width = Bounds.Width;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// protected override void OnPointerExited(PointerEventArgs e)
|
|
||||||
// {
|
|
||||||
// // _icon.Width = Bounds.Width;
|
|
||||||
// }
|
|
||||||
|
|
||||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
var parent = this.GetLogicalAncestors().OfType<Rating>().FirstOrDefault();
|
var parent = this.GetLogicalAncestors().OfType<Rating>().FirstOrDefault();
|
||||||
parent?.Select(this);
|
parent?.PointerReleasedHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Select(bool value)
|
public void Select(bool value)
|
||||||
{
|
{
|
||||||
PseudoClasses.Set(PC_Selected, value);
|
PseudoClasses.Set(PC_Selected, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AdjustWidth()
|
||||||
|
{
|
||||||
|
if (_icon is not null)
|
||||||
|
{
|
||||||
|
_icon.Width = Bounds.Width * Ratio;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user