Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved MarqueeText control #548

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions components/MarqueeText/samples/CustomStyleMarqueeTextSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="MarqueeTextExperiment.Samples.CustomStyleMarqueeTextSample"
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:labs="using:CommunityToolkit.Labs.WinUI.MarqueeTextRns"
xmlns:local="MarqueeTextExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d">

<StackPanel Padding="16">
<labs:MarqueeText x:Name="Marquee"
Behavior="Cycle"
FontSize="18"
Text="{x:Bind MQText, Mode=OneWay}">
<labs:MarqueeText.Style>
<Style TargetType="labs:MarqueeText">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="labs:MarqueeText">
<Grid Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">

<Grid.Resources>
<Storyboard x:Name="CyclingAnimation"
Duration="0:0:0.5">
<!-- Animate out -->
<DoubleAnimationUsingKeyFrames x:Name="CycleAnimationTranslationAnimation"
Storyboard.TargetName="MarqueeTransform"
Storyboard.TargetProperty="(CompositeTransform.Rotation)"
Duration="0:0:1.2">
<DiscreteDoubleKeyFrame KeyTime="0:0:0"
Value="0" />
<LinearDoubleKeyFrame x:Name="CycleAnimationFadeOutPosition"
KeyTime="0:0:0.2"
Value="20" />
<DiscreteDoubleKeyFrame x:Name="CycleAnimationFadeInPosition"
KeyTime="0:0:0.3"
Value="-20" />
<LinearDoubleKeyFrame KeyTime="0:0:0.5"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<!-- Animate the opacity -->
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MarqueePanel"
Storyboard.TargetProperty="(UIElement.Opacity)"
Duration="0:0:1.2">
<DiscreteDoubleKeyFrame KeyTime="0:0:0"
Value="1" />
<LinearDoubleKeyFrame KeyTime="0:0:0.2"
Value="0" />
<DiscreteDoubleKeyFrame KeyTime="0:0:0.3"
Value="0" />
<LinearDoubleKeyFrame KeyTime="0:0:0.5"
Value="1" />
</DoubleAnimationUsingKeyFrames>
<!-- Toggle the visible segment between fade out and fade in -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Segment2"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0"
Value="Visible" />
<DiscreteObjectKeyFrame KeyTime="0:0:0.25"
Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Segment1"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0"
Value="Collapsed" />
<DiscreteObjectKeyFrame KeyTime="0:0:0.25"
Value="Visible" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MarqueeStateGroup">
<VisualState x:Name="MarqueeActive" />
<VisualState x:Name="MarqueeStopped">
<VisualState.Setters>
<Setter Target="MarqueeTransform.TranslateX" Value="0.0" />
<Setter Target="MarqueeTransform.TranslateY" Value="0.0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DirectionStateGroup">
<VisualState x:Name="Leftwards">
<VisualState.Setters>
<Setter Target="MarqueePanel.Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Rightwards">
<VisualState.Setters>
<Setter Target="MarqueePanel.Orientation" Value="Horizontal" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Upwards">
<VisualState.Setters>
<Setter Target="MarqueePanel.Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Downwards">
<VisualState.Setters>
<Setter Target="MarqueePanel.Orientation" Value="Vertical" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="BehaviorStateGroup">
<VisualState x:Name="Ticker">
<VisualState.Setters>
<Setter Target="Segment1.Padding" Value="0" />
<Setter Target="Segment2.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Looping">
<VisualState.Setters>
<Setter Target="Segment1.Padding" Value="0,0,32,0" />
<Setter Target="Segment2.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Bouncing">
<VisualState.Setters>
<Setter Target="Segment1.Padding" Value="0" />
<Setter Target="Segment2.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Cycle">
<VisualState.Setters>
<Setter Target="Segment1.Padding" Value="0" />
<Setter Target="Segment2.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<Grid x:Name="MarqueeContainer">
<StackPanel x:Name="MarqueePanel"
Orientation="Horizontal"
RenderTransformOrigin="0,0.5">
<StackPanel.RenderTransform>
<CompositeTransform x:Name="MarqueeTransform" />
</StackPanel.RenderTransform>
<TextBlock x:Name="Segment1"
win:FontStretch="{TemplateBinding FontStretch}"
win:TextDecorations="{TemplateBinding TextDecorations}"
CharacterSpacing="{TemplateBinding CharacterSpacing}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Text}" />
<TextBlock x:Name="Segment2"
win:FontStretch="{TemplateBinding FontStretch}"
win:TextDecorations="{TemplateBinding TextDecorations}"
CharacterSpacing="{TemplateBinding CharacterSpacing}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding SecondaryText}"
Visibility="Collapsed" />
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</labs:MarqueeText.Style>
</labs:MarqueeText>
</StackPanel>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using CommunityToolkit.Labs.WinUI.MarqueeTextRns;

namespace MarqueeTextExperiment.Samples;

[ToolkitSample(id: nameof(CustomStyleMarqueeTextSample), "MarqueeText", description: "A control for scrolling text in a marquee fashion.")]
[ToolkitSampleTextOption("MQText", LoremIpsum, Title = "Text")]
//[ToolkitSampleMultiChoiceOption("MarqueeRepeat", "Repeat", "Forever", "1x", "2x")]
public sealed partial class CustomStyleMarqueeTextSample : Page
{
private const string LoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be an area to improve our tooling -- ToolkitSampleTextOption should take a default value for the text.


public CustomStyleMarqueeTextSample()
{
this.InitializeComponent();
}

private MarqueeDirection ConvertStringToMarqueeDirection(string str) => str switch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the value of each string here matches the enum value name, we shouldn't need a converter. If this doesn't work, it's something we need to investigate fixing.

{
"Left" => MarqueeDirection.Left,
"Up" => MarqueeDirection.Up,
"Right" => MarqueeDirection.Right,
"Down" => MarqueeDirection.Down,
_ => throw new System.NotImplementedException(),
};
}
8 changes: 8 additions & 0 deletions components/MarqueeText/samples/MarqueeText.Samples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,17 @@

<ItemGroup>
<None Remove="Assets\MarqueeText.png" />
<None Remove="CustomStyleMarqueeTextSample.xaml" />
<UpToDateCheckInput Remove="CustomStyleMarqueeTextSample.xaml" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove this since it's done automatically by our tooling


<Content Include="Assets\MarqueeText.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove this since it's done automatically by our tooling

<Compile Update="CustomStyleMarqueeTextSample.xaml.cs">
<DependentUpon>CustomStyleMarqueeTextSample.xaml</DependentUpon>
</Compile>
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions components/MarqueeText/samples/MarqueeText.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ The repeat behavior determines how many times the marquee will loop before the a
The default direction is left, meaning the text will move leftwards, but this can be changed to right, up, or down. Direction changed between left and right or up and down are handled continously, meaning that the animation will resume from its current position if changed between these directions.

> [!Sample MarqueeTextSample]

### Custom Cycle Animations

The cycle animation can be customized using a style.

> [!Sample CustomStyleMarqueeTextSample]
11 changes: 8 additions & 3 deletions components/MarqueeText/samples/MarqueeTextSample.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="MarqueeTextExperiment.Samples.MarqueeTextSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand All @@ -9,11 +9,16 @@
mc:Ignorable="d">

<StackPanel Padding="16">
<labs:MarqueeText Behavior="{x:Bind ConvertStringToMarqueeBehavior(MQBehavior), Mode=OneWay}"
<labs:MarqueeText x:Name="Marquee"
Behavior="{x:Bind ConvertStringToMarqueeBehavior(MQBehavior), Mode=OneWay}"
Direction="{x:Bind ConvertStringToMarqueeDirection(MQDirection), Mode=OneWay}"
FontSize="18"
RepeatBehavior="Forever"
Speed="{x:Bind MQSpeed, Mode=OneWay}"
Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." />
Text="{x:Bind MQText, Mode=OneWay}" />

<Button Margin="0,8"
Click="StartMarquee_Click"
Content="Start Marquee" />
</StackPanel>
</Page>
16 changes: 13 additions & 3 deletions components/MarqueeText/samples/MarqueeTextSample.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
using CommunityToolkit.Labs.WinUI.MarqueeTextRns;

namespace MarqueeTextExperiment.Samples;

[ToolkitSample(id: nameof(MarqueeTextSample), "MarqueeText", description: "A control for scrolling text in a marquee fashion.")]
[ToolkitSampleTextOption("MQText", LoremIpsum, Title = "Text")]
[ToolkitSampleNumericOption("MQSpeed", initial: 96, min: 48, max: 196, step: 1, Title = "Speed")]
[ToolkitSampleMultiChoiceOption("MQDirection", "Left", "Right", "Up", "Down", Title = "Marquee Direction")]
//[ToolkitSampleMultiChoiceOption("MarqueeRepeat", "Repeat", "Forever", "1x", "2x")]
#if !HAS_UNO
[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", "Bouncing", Title = "Marquee Behavior")]
[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", "Bouncing", "Cycle", Title = "Marquee Behavior")]
#else
[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", Title = "Marquee Behavior")]
[ToolkitSampleMultiChoiceOption("MQBehavior", "Ticker", "Looping", "Cycle", Title = "Marquee Behavior")]
#endif
public sealed partial class MarqueeTextSample : Page
{
private const string LoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

public MarqueeTextSample()
{
this.InitializeComponent();
Expand All @@ -28,7 +32,8 @@ public MarqueeTextSample()
#if !HAS_UNO
"Bouncing" => MarqueeBehavior.Bouncing,
#endif
_ => throw new System.NotImplementedException(),
"Cycle" => MarqueeBehavior.Cycle,
_ => throw new NotImplementedException(),
};

private MarqueeDirection ConvertStringToMarqueeDirection(string str) => str switch
Expand All @@ -39,4 +44,9 @@ public MarqueeTextSample()
"Down" => MarqueeDirection.Down,
_ => throw new System.NotImplementedException(),
};

private void StartMarquee_Click(object sender, RoutedEventArgs e)
{
Marquee?.StartMarquee();
}
}
Loading
Loading