Last active
April 5, 2024 13:11
Content scaler for Unity Noesis GUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if UNITY_5_3_OR_NEWER | |
#define NOESIS | |
using Noesis; | |
#else | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Media; | |
#endif | |
namespace NoesisGUI.Extensions.Scaling | |
{ | |
using System; | |
public enum ContentMatchMode | |
{ | |
MatchWidthOrHeight, | |
Expand, | |
Shrink | |
} | |
[TemplatePart(Name = "ContentPresenter", Type = typeof(ContentPresenter))] | |
public class ContentScaler : ContentControl | |
{ | |
private const float LogBase = 2; | |
public static readonly DependencyProperty ReferenceWidthProperty = DependencyProperty.Register(nameof(ReferenceWidth), | |
typeof(float), typeof(ContentScaler), new FrameworkPropertyMetadata(1920.0f, FrameworkPropertyMetadataOptions.AffectsMeasure)); | |
public static readonly DependencyProperty ReferenceHeightProperty = DependencyProperty.Register(nameof(ReferenceHeight), | |
typeof(float), typeof(ContentScaler), new FrameworkPropertyMetadata(1080.0f, FrameworkPropertyMetadataOptions.AffectsMeasure)); | |
public static readonly DependencyProperty ContentMatchModeProperty = DependencyProperty.Register(nameof(ContentMatchMode), | |
typeof(ContentMatchMode), typeof(ContentScaler), new FrameworkPropertyMetadata(ContentMatchMode.MatchWidthOrHeight, FrameworkPropertyMetadataOptions.AffectsMeasure)); | |
public static readonly DependencyProperty MatchWidthOrHeightProperty = DependencyProperty.Register(nameof(MatchWidthOrHeight), | |
typeof(float), typeof(ContentScaler), new FrameworkPropertyMetadata(0.0f, FrameworkPropertyMetadataOptions.AffectsMeasure)); | |
private ContentPresenter m_ContentPresenter; | |
private ScaleTransform m_ScaleTransform; | |
public float ReferenceWidth | |
{ | |
get => (float) GetValue(ReferenceWidthProperty); | |
set => SetValue(ReferenceWidthProperty, value); | |
} | |
public float ReferenceHeight | |
{ | |
get => (float) GetValue(ReferenceHeightProperty); | |
set => SetValue(ReferenceHeightProperty, value); | |
} | |
public ContentMatchMode ContentMatchMode | |
{ | |
get => (ContentMatchMode) GetValue(ContentMatchModeProperty); | |
set => SetValue(ContentMatchModeProperty, value); | |
} | |
public float MatchWidthOrHeight | |
{ | |
get => (float) GetValue(MatchWidthOrHeightProperty); | |
set => SetValue(MatchWidthOrHeightProperty, value); | |
} | |
static ContentScaler() | |
{ | |
DefaultStyleKeyProperty.OverrideMetadata(typeof(ContentScaler), new FrameworkPropertyMetadata(typeof(ContentScaler))); | |
} | |
public override void OnApplyTemplate() | |
{ | |
var templateRoot = VisualTreeHelper.GetChild(this, 0) as FrameworkElement; | |
if(templateRoot == null) | |
return; | |
m_ContentPresenter = (ContentPresenter)templateRoot.FindName("ContentPresenter"); | |
m_ScaleTransform = new ScaleTransform(1f, 1f); | |
m_ContentPresenter.LayoutTransform = m_ScaleTransform; | |
m_ContentPresenter.Loaded += (sender, args) => | |
{ | |
InvalidateMeasure(); | |
}; | |
} | |
protected override Size MeasureOverride(Size availableSize) | |
{ | |
if(double.IsPositiveInfinity(availableSize.Width)) | |
availableSize = new Size(ReferenceWidth, availableSize.Height); | |
if(double.IsPositiveInfinity(availableSize.Height)) | |
availableSize = new Size(availableSize.Width, ReferenceHeight); | |
var scale = CalculateScale(availableSize); | |
m_ScaleTransform.ScaleX = scale; | |
m_ScaleTransform.ScaleY = scale; | |
return availableSize; | |
} | |
private float CalculateScale(Size availableSize) | |
{ | |
switch (ContentMatchMode) | |
{ | |
case ContentMatchMode.MatchWidthOrHeight: | |
{ | |
var logWidth = (float) Math.Log(availableSize.Width / ReferenceWidth, LogBase); | |
var logHeight = (float) Math.Log(availableSize.Height / ReferenceHeight, LogBase); | |
var logWeightedAverage = logWidth + (logHeight - logWidth) * MatchWidthOrHeight; | |
return (float)Math.Pow(LogBase, logWeightedAverage); | |
} | |
case ContentMatchMode.Expand: | |
return (float)Math.Min(availableSize.Width / ReferenceWidth, availableSize.Height / ReferenceHeight); | |
case ContentMatchMode.Shrink: | |
return (float)Math.Max(availableSize.Width / ReferenceWidth, availableSize.Height / ReferenceHeight); | |
default: | |
return 1.0f; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ResourceDictionary | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:scaling="clr-namespace:NoesisGUI.Extensions.Scaling"> | |
<Style TargetType="{x:Type scaling:ContentScaler}"> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="{x:Type scaling:ContentScaler}"> | |
<Border> | |
<ContentPresenter x:Name="ContentPresenter"/> | |
</Border> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
</ResourceDictionary> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to use: