feat: add item styles, add color converter.

This commit is contained in:
rabbitism
2023-04-24 22:41:01 +08:00
parent 2a38bb09a2
commit 6e5b3012dc
7 changed files with 183 additions and 24 deletions

View File

@@ -16,9 +16,23 @@
</UserControl.Resources> </UserControl.Resources>
<StackPanel> <StackPanel>
<u:Timeline> <u:Timeline>
<u:TimelineItem Content="Start" Time="2022-01-01" /> <u:TimelineItem
<u:TimelineItem Content="In between" Time="2022-01-02" /> Content="Start"
<u:TimelineItem Content="Finished" Time="2022-01-03" /> ItemType="Warning"
Time="2022-01-01" />
<u:TimelineItem
Content="In between"
ItemType="Ongoing"
Time="2022-01-02" />
<u:TimelineItem
Content="Finished"
ItemType="Error"
Time="2022-01-03" />
<u:TimelineItem
Content="Finished"
IconForeground="Yellow"
ItemType="Default"
Time="2022-01-03" />
</u:Timeline> </u:Timeline>
<u:Timeline HorizontalAlignment="Left" ItemsSource="{Binding Items}"> <u:Timeline HorizontalAlignment="Left" ItemsSource="{Binding Items}">
<u:Timeline.ItemTemplate> <u:Timeline.ItemTemplate>

View File

@@ -1,6 +1,7 @@
<ResourceDictionary <ResourceDictionary
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
xmlns:u="https://irihi.tech/ursa"> xmlns:u="https://irihi.tech/ursa">
<Design.PreviewWith> <Design.PreviewWith>
<StackPanel Width="100" Spacing="20"> <StackPanel Width="100" Spacing="20">
@@ -22,48 +23,64 @@
</Setter> </Setter>
</ControlTheme> </ControlTheme>
<converters:TimelineItemTypeToIconForegroundConverter
x:Key="ForegroundConverter"
DefaultBrush="{DynamicResource DefaultTimelineIconForeground}"
ErrorBrush="{DynamicResource ErrorTimelineIconForeground}"
OngoingBrush="{DynamicResource OngoingTimelineIconForeground}"
SuccessBrush="{DynamicResource SuccessTimelineIconForeground}"
WarningBrush="{DynamicResource WarningTimelineIconForeground}" />
<ControlTheme x:Key="{x:Type u:TimelineItem}" TargetType="u:TimelineItem"> <ControlTheme x:Key="{x:Type u:TimelineItem}" TargetType="u:TimelineItem">
<Setter Property="u:TimelineItem.Template"> <Setter Property="u:TimelineItem.Template">
<ControlTemplate TargetType="u:TimelineItem"> <ControlTemplate TargetType="u:TimelineItem">
<Grid ColumnDefinitions="Auto, *" RowDefinitions="*, Auto, *"> <Grid ColumnDefinitions="Auto, *" RowDefinitions="*, Auto, *">
<Rectangle
Grid.Row="2"
Grid.Column="0"
Width="1"
VerticalAlignment="Stretch"
Classes="end"
Fill="LightGray" />
<Grid <Grid
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="2" Grid.RowSpan="2"
Grid.Column="0" Grid.Column="0"
Width="16"
RowDefinitions="Auto, Auto, *"> RowDefinitions="Auto, Auto, *">
<Rectangle <Rectangle
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Width="1" Width="1"
Height="8" Height="8"
HorizontalAlignment="Center"
VerticalAlignment="Top" VerticalAlignment="Top"
Classes="start" Classes="start"
Fill="LightGray" /> Fill="LightGray" />
<Panel Grid.Row="1">
<Ellipse <Ellipse
Grid.Row="1"
Width="8" Width="8"
Height="8" Height="8"
Margin="2" Margin="2"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Top" VerticalAlignment="Top">
Fill="LightGray" /> <Ellipse.Fill>
<MultiBinding Converter="{StaticResource ForegroundConverter}">
<Binding Path="ItemType" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="IconForeground" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</Ellipse.Fill>
</Ellipse>
</Panel>
<Rectangle <Rectangle
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Width="1" Width="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Classes="end" Classes="end"
Fill="LightGray" /> Fill="LightGray" />
</Grid> </Grid>
<Rectangle
Grid.Row="2"
Grid.Column="0"
Width="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Classes="end"
Fill="LightGray" />
<ContentPresenter <ContentPresenter
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
@@ -81,6 +98,7 @@
Name="content" Name="content"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="0,0,0,16"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Content="{TemplateBinding Content}" Content="{TemplateBinding Content}"

View File

@@ -0,0 +1,82 @@
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Media;
using Ursa.Controls;
namespace Ursa.Themes.Semi.Converters;
public class TimelineItemTypeToIconForegroundConverter: AvaloniaObject, IMultiValueConverter
{
public static readonly StyledProperty<IBrush> DefaultBrushProperty = AvaloniaProperty.Register<TimelineItemTypeToIconForegroundConverter, IBrush>(
nameof(DefaultBrush));
public IBrush DefaultBrush
{
get => GetValue(DefaultBrushProperty);
set => SetValue(DefaultBrushProperty, value);
}
public static readonly StyledProperty<IBrush> OngoingBrushProperty = AvaloniaProperty.Register<TimelineItemTypeToIconForegroundConverter, IBrush>(
nameof(OngoingBrush));
public IBrush OngoingBrush
{
get => GetValue(OngoingBrushProperty);
set => SetValue(OngoingBrushProperty, value);
}
public static readonly StyledProperty<IBrush> SuccessBrushProperty = AvaloniaProperty.Register<TimelineItemTypeToIconForegroundConverter, IBrush>(
nameof(SuccessBrush));
public IBrush SuccessBrush
{
get => GetValue(SuccessBrushProperty);
set => SetValue(SuccessBrushProperty, value);
}
public static readonly StyledProperty<IBrush> WarningBrushProperty = AvaloniaProperty.Register<TimelineItemTypeToIconForegroundConverter, IBrush>(
nameof(WarningBrush));
public IBrush WarningBrush
{
get => GetValue(WarningBrushProperty);
set => SetValue(WarningBrushProperty, value);
}
public static readonly StyledProperty<IBrush> ErrorBrushProperty = AvaloniaProperty.Register<TimelineItemTypeToIconForegroundConverter, IBrush>(
nameof(ErrorBrush));
public IBrush ErrorBrush
{
get => GetValue(ErrorBrushProperty);
set => SetValue(ErrorBrushProperty, value);
}
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if (values[0] is TimelineItemType type)
{
switch (type)
{
case TimelineItemType.Error:
return ErrorBrush;
case TimelineItemType.Warning:
return WarningBrush;
case TimelineItemType.Success:
return SuccessBrush;
case TimelineItemType.Ongoing:
return OngoingBrush;
case TimelineItemType.Default:
if (values[1] is IBrush brush)
{
return brush;
}
return DefaultBrush;
}
}
return AvaloniaProperty.UnsetValue;
}
}

View File

@@ -0,0 +1,8 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="DefaultTimelineIconForeground" Opacity="0.13" Color="#FF2E3238" />
<SolidColorBrush x:Key="OngoingTimelineIconForeground" Color="#FF0077FA" />
<SolidColorBrush x:Key="SuccessTimelineIconForeground" Color="#FF3BB346" />
<SolidColorBrush x:Key="WarningTimelineIconForeground" Color="#FFFC8800" />
<SolidColorBrush x:Key="ErrorTimelineIconForeground" Color="#FFF93920" />
</ResourceDictionary>

View File

@@ -5,5 +5,6 @@
<MergeResourceInclude Source="Banner.axaml" /> <MergeResourceInclude Source="Banner.axaml" />
<MergeResourceInclude Source="Divider.axaml" /> <MergeResourceInclude Source="Divider.axaml" />
<MergeResourceInclude Source="IPv4Box.axaml" /> <MergeResourceInclude Source="IPv4Box.axaml" />
<MergeResourceInclude Source="Timeline.axaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -8,11 +8,25 @@ using Avalonia.Media;
namespace Ursa.Controls; namespace Ursa.Controls;
[PseudoClasses(PC_First, PC_Last)] [PseudoClasses(PC_First, PC_Last, PC_Default, PC_Ongoing, PC_Success, PC_Warning, PC_Error)]
public class TimelineItem: ContentControl public class TimelineItem: ContentControl
{ {
public const string PC_First = ":first"; private const string PC_First = ":first";
public const string PC_Last = ":last"; private const string PC_Last = ":last";
private const string PC_Default = ":default";
private const string PC_Ongoing = ":ongoing";
private const string PC_Success = ":success";
private const string PC_Warning = ":warning";
private const string PC_Error = ":error";
private static readonly IReadOnlyDictionary<TimelineItemType, string> _itemTypeMapping = new Dictionary<TimelineItemType, string>
{
{TimelineItemType.Default, PC_Default},
{TimelineItemType.Ongoing, PC_Ongoing},
{TimelineItemType.Success, PC_Success},
{TimelineItemType.Warning, PC_Warning},
{TimelineItemType.Error, PC_Error},
};
public static readonly StyledProperty<IBrush> IconForegroundProperty = public static readonly StyledProperty<IBrush> IconForegroundProperty =
AvaloniaProperty.Register<TimelineItem, IBrush>(nameof(IconForeground)); AvaloniaProperty.Register<TimelineItem, IBrush>(nameof(IconForeground));
@@ -49,9 +63,32 @@ public class TimelineItem: ContentControl
set => SetValue(DescriptionTemplateProperty, value); set => SetValue(DescriptionTemplateProperty, value);
} }
public static readonly StyledProperty<TimelineItemType> ItemTypeProperty = AvaloniaProperty.Register<TimelineItem, TimelineItemType>(
nameof(ItemType));
public TimelineItemType ItemType
{
get => GetValue(ItemTypeProperty);
set => SetValue(ItemTypeProperty, value);
}
internal void SetIndex(bool isFirst, bool isLast) internal void SetIndex(bool isFirst, bool isLast)
{ {
PseudoClasses.Set(PC_First, isFirst); PseudoClasses.Set(PC_First, isFirst);
PseudoClasses.Set(PC_Last, isLast); PseudoClasses.Set(PC_Last, isLast);
} }
static TimelineItem()
{
ItemTypeProperty.Changed.AddClassHandler<TimelineItem>((o, e) => { o.OnItemTypeChanged(e); });
}
private void OnItemTypeChanged(AvaloniaPropertyChangedEventArgs args)
{
var oldValue = args.GetOldValue<TimelineItemType>();
var newValue = args.GetNewValue<TimelineItemType>();
PseudoClasses.Set(_itemTypeMapping[oldValue], false);
PseudoClasses.Set(_itemTypeMapping[newValue], true);
}
} }

View File

@@ -2,7 +2,6 @@ namespace Ursa.Controls;
public enum TimelineItemType public enum TimelineItemType
{ {
None,
Default, Default,
Ongoing, Ongoing,
Success, Success,