Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion MainDemo.Wpf/ComboBoxes.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@

<ComboBox x:Name="FilledComboBox"
Width="256"
materialDesign:HintAssist.Hint="Some item"
materialDesign:HintAssist.Hint="Some item with a very long hint text that will cut off when floating"
IsEnabled="{Binding Path=IsChecked, ElementName=FilledComboBoxEnabledCheckBox}"
Style="{StaticResource MaterialDesignFilledComboBox}">
<ComboBoxItem Content="Item 1" />
Expand Down
2 changes: 1 addition & 1 deletion MainDemo.Wpf/Fields.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@

<TextBox MaxWidth="400"
VerticalAlignment="Top"
materialDesign:HintAssist.Hint="Floating hint in a box"
materialDesign:HintAssist.Hint="Floating hint in a box that will cut off"
AcceptsReturn="True"
IsEnabled="{Binding Path=IsChecked, ElementName=MaterialDesignFilledTextBoxEnabledComboBox}"
Style="{StaticResource MaterialDesignFilledTextBox}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,81 @@
using MaterialDesignThemes.Wpf.Converters;
using Xunit;

namespace MaterialDesignThemes.Wpf.Tests.Converters
namespace MaterialDesignThemes.Wpf.Tests.Converters;

public class FloatingHintTransformConverterTests
{
public class FloatingHintTransformConverterTests
{
public static IEnumerable<object?[]> InvalidParameters =>
new[]
{
new object?[] {null, null, null, null},
new object?[] {1.0, null, null, null},
new object?[] {null, 1.0, null, null},
new object?[] {null, null, 1.0, null},
new object?[] {null, null, null, new Point()},
new object?[] {1.0, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue},
new object?[] {DependencyProperty.UnsetValue, 1.0, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue},
new object?[] {DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, 1.0, DependencyProperty.UnsetValue},
new object?[] {DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, new Point() },
};

[StaTheory]
[MemberData(nameof(InvalidParameters))]
public void WhenParametersAreNotSetItReturnsIdentity(object? scale, object? lower, object? upper, object? offset)
public static IEnumerable<object?[]> InvalidParameters =>
new[]
{
var converter = new FloatingHintTransformConverter();
new object?[] {null, null, null, null},
new object?[] {1.0, null, null, null},
new object?[] {null, 1.0, null, null},
new object?[] {null, null, 1.0, null},
new object?[] {null, null, null, new Point()},
new object?[] {1.0, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue},
new object?[] {DependencyProperty.UnsetValue, 1.0, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue},
new object?[] {DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, 1.0, DependencyProperty.UnsetValue},
new object?[] {DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, DependencyProperty.UnsetValue, new Point() },
};

var result = converter.Convert(new[] { scale, lower, upper, offset },
typeof(Transform), null, CultureInfo.CurrentUICulture);
[Theory]
[MemberData(nameof(InvalidParameters))]
public void WhenParametersAreNotSetItReturnsIdentity(object? scale, object? lower, object? upper, object? offset)
{
var converter = new FloatingHintTransformConverter();

Assert.Equal(Transform.Identity, result);
}
var result = converter.Convert(new[] { scale, lower, upper, offset },
typeof(Transform), null, CultureInfo.CurrentUICulture);

[StaTheory]
[InlineData(2.0, 1.5, 3.0, 3.0, 4.0)]
[InlineData(1.5, 2.0, 3.0, 2.0, 3.0)]
public void WhenParametersAreSpecifiedItReturnsTransforms(double scale, double lower, double upper, double x, double y)
{
var converter = new FloatingHintTransformConverter();
Assert.Equal(Transform.Identity, result);
}

[Theory]
[InlineData(2.0, 1.5, 3.0, 3.0, 4.0)]
[InlineData(1.5, 2.0, 3.0, 2.0, 3.0)]
public void WhenParametersAreSpecifiedItReturnsTransforms(double scale, double lower, double upper, double x, double y)
{
var converter = new FloatingHintTransformConverter();

var result = (TransformGroup?)converter.Convert(new object?[] { scale, lower, upper, new Point(x, y) }, typeof(Transform), null, CultureInfo.CurrentUICulture);
var result = (TransformGroup?)converter.Convert(new object?[] { scale, lower, upper, new Point(x, y) }, typeof(Transform), null, CultureInfo.CurrentUICulture);

Assert.NotNull(result);
var scaleTransform = (ScaleTransform)result!.Children[0];
var translateTransform = (TranslateTransform)result.Children[1];
Assert.NotNull(result);
var scaleTransform = (ScaleTransform)result!.Children[0];
var translateTransform = (TranslateTransform)result.Children[1];

Assert.Equal(upper + (lower - upper) * scale, scaleTransform.ScaleX);
Assert.Equal(upper + (lower - upper) * scale, scaleTransform.ScaleY);
Assert.Equal(upper + (lower - upper) * scale, scaleTransform.ScaleX);
Assert.Equal(upper + (lower - upper) * scale, scaleTransform.ScaleY);

Assert.Equal(scale * x, translateTransform.X);
Assert.Equal(scale * y, translateTransform.Y);
}
Assert.Equal(scale * x, translateTransform.X);
Assert.Equal(scale * y, translateTransform.Y);
}

[Theory]
[InlineData(2.0, 1.5, 3.0, 3.0, 4.0)]
[InlineData(1.5, 2.0, 3.0, 2.0, 3.0)]
public void WhenParametersAreSpecifiedAndScaleTransformDisabledItReturnsTransforms(double scale, double lower, double upper, double x, double y)
{
var converter = new FloatingHintTransformConverter { ApplyScaleTransform = false };

var result = (TransformGroup?)converter.Convert(new object?[] { scale, lower, upper, new Point(x, y) }, typeof(Transform), null, CultureInfo.CurrentUICulture);

Assert.NotNull(result);
Assert.Single(result.Children);
Assert.IsType<TranslateTransform>(result.Children[0]);
}

[Theory]
[InlineData(2.0, 1.5, 3.0, 3.0, 4.0)]
[InlineData(1.5, 2.0, 3.0, 2.0, 3.0)]
public void WhenParametersAreSpecifiedAndTranslateTransformDisabledItReturnsTransforms(double scale, double lower, double upper, double x, double y)
{
var converter = new FloatingHintTransformConverter { ApplyTranslateTransform = false };

var result = (TransformGroup?)converter.Convert(new object?[] { scale, lower, upper, new Point(x, y) }, typeof(Transform), null, CultureInfo.CurrentUICulture);

Assert.NotNull(result);
Assert.Single(result.Children);
Assert.IsType<ScaleTransform>(result.Children[0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,47 @@
using System.Windows.Data;
using System.Windows.Media;

namespace MaterialDesignThemes.Wpf.Converters
namespace MaterialDesignThemes.Wpf.Converters;

internal class FloatingHintTransformConverter : IMultiValueConverter
{
internal class FloatingHintTransformConverter : IMultiValueConverter
public bool ApplyScaleTransform { get; set; } = true;
public bool ApplyTranslateTransform { get; set; } = true;

public object? Convert(object?[]? values, Type targetType, object? parameter, CultureInfo culture)
{
public object? Convert(object?[]? values, Type targetType, object? parameter, CultureInfo culture)
if (values?.Length != 4
|| values.Any(v => v == null)
|| !double.TryParse(values[0]!.ToString(), out double scale)
|| !double.TryParse(values[1]!.ToString(), out double lower)
|| !double.TryParse(values[2]!.ToString(), out double upper)
|| values[3] is not Point floatingOffset)
{
if (values == null
|| values.Length != 4
|| values.Any(v => v == null)
|| !double.TryParse(values[0]?.ToString(), out double scale)
|| !double.TryParse(values[1]?.ToString(), out double lower)
|| !double.TryParse(values[2]?.ToString(), out double upper)
|| !(values[3] is Point floatingOffset))
{
return Transform.Identity;
}
return Transform.Identity;
}

double result = upper + (lower - upper) * scale;
double result = upper + (lower - upper) * scale;

var transformGroup = new TransformGroup();
var transformGroup = new TransformGroup();
if (ApplyScaleTransform)
{
transformGroup.Children.Add(new ScaleTransform
{
ScaleX = result,
ScaleY = result
});
}
if (ApplyTranslateTransform)
{
transformGroup.Children.Add(new TranslateTransform
{
X = scale * floatingOffset.X,
Y = scale * floatingOffset.Y
});
return transformGroup;
}

public object?[]? ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture)
=> throw new NotImplementedException();
return transformGroup;
}

public object?[]? ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture)
=> throw new NotImplementedException();
}
55 changes: 33 additions & 22 deletions MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.SmartHint.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Expand All @@ -8,12 +8,13 @@
<converters:BooleanToVisibilityConverter x:Key="InverseBoolToVisConverter"
FalseValue="Visible"
TrueValue="Collapsed" />
<converters:FloatingHintTransformConverter x:Key="FloatingHintTransformConverter" />
<converters:FloatingHintTransformConverter x:Key="FloatingHintCanvasTransformConverter" ApplyScaleTransform="False" />
<converters:FloatingHintTransformConverter x:Key="FloatingHintTransformConverter" ApplyTranslateTransform="False" />
<system:Double x:Key="NoContentFloatingScale">1.0</system:Double>
<CubicEase x:Key="AnimationEasingFunction" EasingMode="EaseInOut" />

<Style TargetType="{x:Type wpf:SmartHint}">
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="IsTabStop" Value="False" />
Expand Down Expand Up @@ -138,29 +139,39 @@
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<wpf:ScaleHost x:Name="ScaleHost" />
<ContentControl x:Name="FloatingHintTextBlock"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Hint}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
IsHitTestVisible="False"
IsTabStop="False"
Opacity="{TemplateBinding HintOpacity}"
RenderTransformOrigin="0,0"
Visibility="{TemplateBinding UseFloating, Converter={StaticResource BoolToVisConverter}}">
<ContentControl.Tag>
<system:Double>0.0</system:Double>
</ContentControl.Tag>
<ContentControl.RenderTransform>
<MultiBinding Converter="{StaticResource FloatingHintTransformConverter}">
<Canvas ClipToBounds="True" HorizontalAlignment="Stretch" Height="{Binding ElementName=FloatingHintTextBlock, Path=ActualHeight}">
<Canvas.RenderTransform>
<MultiBinding Converter="{StaticResource FloatingHintCanvasTransformConverter}">
<Binding ElementName="ScaleHost" Path="Scale" />
<Binding Path="FloatingScale" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Source="{StaticResource NoContentFloatingScale}" />
<Binding Path="FloatingOffset" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</ContentControl.RenderTransform>
</ContentControl>
</Canvas.RenderTransform>
<ContentControl x:Name="FloatingHintTextBlock"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Hint}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
IsHitTestVisible="False"
IsTabStop="False"
Opacity="{TemplateBinding HintOpacity}"
RenderTransformOrigin="0,0"
Visibility="{TemplateBinding UseFloating, Converter={StaticResource BoolToVisConverter}}">
<ContentControl.Tag>
<system:Double>0.0</system:Double>
</ContentControl.Tag>
<ContentControl.RenderTransform>
<MultiBinding Converter="{StaticResource FloatingHintTransformConverter}">
<Binding ElementName="ScaleHost" Path="Scale" />
<Binding Path="FloatingScale" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Source="{StaticResource NoContentFloatingScale}" />
<Binding Path="FloatingOffset" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</ContentControl.RenderTransform>
</ContentControl>
</Canvas>
</Grid>
</ControlTemplate>
</Setter.Value>
Expand All @@ -169,4 +180,4 @@
</Style.Triggers>
</Style>

</ResourceDictionary>
</ResourceDictionary>