Skip to content

Instantly share code, notes, and snippets.

@neoRiley
Last active April 10, 2024 23:08
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neoRiley/b24e9d2332e2989833c03e24770d46d9 to your computer and use it in GitHub Desktop.
Save neoRiley/b24e9d2332e2989833c03e24770d46d9 to your computer and use it in GitHub Desktop.
Extends VisualElement and provides the ability to maintain an aspect ratio as well as add a Label who's font size is scaled with the AspectRatioPanel
using System;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using UnityEngine.UIElements;
namespace N30R1L37
{
[UnityEngine.Scripting.Preserve]
public class AspectRatioButton : Button, IDisposable
{
[UnityEngine.Scripting.Preserve]
public new class UxmlFactory : UxmlFactory<AspectRatioButton, UxmlTraits> {}
[UnityEngine.Scripting.Preserve]
public new class UxmlTraits : VisualElement.UxmlTraits
{
readonly UxmlBoolAttributeDescription maintainAspectRatio = new() { name = "maintain-aspect-ratio", defaultValue = true };
readonly UxmlEnumAttributeDescription<RatioFlexEnum.RatioFlex> ratioFlex = new () { name = "ratio-flex-type", defaultValue = RatioFlexEnum.RatioFlex.Auto};
readonly UxmlFloatAttributeDescription aspectRatio = new() { name = "aspect-ratio", defaultValue = 1.0f };
readonly UxmlFloatAttributeDescription scale = new() { name = "scale", defaultValue = 1.0f };
readonly UxmlStringAttributeDescription label = new() { name = "label", defaultValue = "Button" };
readonly UxmlFloatAttributeDescription fontScale = new() { name = "font-scale", defaultValue = 1.0f };
readonly UxmlIntAttributeDescription maxCharacters = new() { name = "max-characters", defaultValue = 20 };
readonly UxmlFloatAttributeDescription cornerRadius = new() { name = "corner-radius", defaultValue = 0.0f};
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get { yield break; }
}
public override void Init( VisualElement visualElement, IUxmlAttributes attributes, CreationContext creationContext )
{
base.Init( visualElement, attributes, creationContext );
AspectRatioButton element = (AspectRatioButton)visualElement;
if (element != null)
{
element.MaintainAspectRatio = maintainAspectRatio.GetValueFromBag(attributes, creationContext);
element.RatioFlexType = ratioFlex.GetValueFromBag(attributes, creationContext);
element.AspectRatio = aspectRatio.GetValueFromBag( attributes, creationContext ) == 0 ? 1 : aspectRatio.GetValueFromBag( attributes, creationContext );
element.Scale = scale.GetValueFromBag( attributes, creationContext );
element.Label = label.GetValueFromBag(attributes, creationContext);
element.FontScale = fontScale.GetValueFromBag( attributes, creationContext );
element.MaxCharacters = maxCharacters.GetValueFromBag( attributes, creationContext );
element.CornerRadius = cornerRadius.GetValueFromBag(attributes, creationContext);
}
}
}
public bool ScaleFont { get; set; }
private Label _labelElement;
public RatioFlexEnum.RatioFlex RatioFlexType { get; set; } = RatioFlexEnum.RatioFlex.Auto;
public float Scale { get; set; } = 1.0f;
private bool _maintainAspectRatio = true;
public bool MaintainAspectRatio
{
get => _maintainAspectRatio;
set
{
_maintainAspectRatio = value;
if (!value) return;
style.width = StyleKeyword.Auto;
style.height = StyleKeyword.Auto;
style.minWidth = StyleKeyword.Auto;
style.minHeight = StyleKeyword.Auto;
style.maxWidth = StyleKeyword.Auto;
style.maxHeight = StyleKeyword.Auto;
}
}
private float _aspectRatio = 1.0f;
public float AspectRatio
{
get => _aspectRatio;
set
{
_aspectRatio = Mathf.Max(value, 0.01f);
}
}
private float _cornerRadius = 0.0f;
public float CornerRadius
{
get => _cornerRadius;
set
{
_cornerRadius = Mathf.Max(value, 0.0f);
}
}
private int _maxCharacters = 20;
public int MaxCharacters
{
get => _maxCharacters;
set
{
_maxCharacters = value;
_isDirty = true;
}
}
private string _label = "";
public string Label
{
get => _label;
set
{
_label = value;
}
}
public float FontScale { get; set; } = 1;
public void ForceRedraw() => _isDirty = true;
public AspectRatioButton()
{
RegisterCallback<AttachToPanelEvent>( OnAttachToPanelEvent );
}
void OnAttachToPanelEvent( AttachToPanelEvent e )
{
parent?.RegisterCallback<GeometryChangedEvent>( OnGeometryChangedEvent );
MonitorIsDirty();
}
private bool _isDirty = false;
private void MonitorIsDirty()
{
Observable.EveryUpdate().ObserveOnMainThread().Subscribe(_ =>
{
if (!_isDirty) return;
Redraw();
});
}
void OnGeometryChangedEvent( GeometryChangedEvent e )
{
_isDirty = true;
}
void Redraw()
{
if (parent == null || !this.IsInitialized()) return;
var newSize = this.RedrawAspectRatio(
parent.localBound.size,
AspectRatio,
Scale,
MaintainAspectRatio,
RatioFlexType);
newSize *= Scale;
SetBorderRadius(CornerRadius * newSize.magnitude * 0.01f);
if (_label.Length > _maxCharacters)
{
text = _label.Substring(0, _maxCharacters - 3) + "...";
}
else if (_label.Length < 4)
{
text = $" {_label} ";
}
else
{
text = _label;
}
if (ScaleFont)
{
this.ResizeFont(newSize, FontScale, Label);
}
else
{
float fontSize = MaxCharacters * FontScale * newSize.magnitude * 0.01f;
style.fontSize = new StyleLength (fontSize);
}
_isDirty = false;
}
private void SetBorderRadius(float scale)
{
style.borderBottomLeftRadius = scale;
style.borderTopLeftRadius = scale;
style.borderTopRightRadius = scale;
style.borderBottomRightRadius = scale;
}
public void Dispose()
{
parent?.UnregisterCallback<GeometryChangedEvent>( OnGeometryChangedEvent );
UnregisterCallback<AttachToPanelEvent>( OnAttachToPanelEvent );
}
}
}
using System;
using System.Collections.Generic;
using EvolveDM.UI.UIToolKit.Base;
using UniRx;
using UnityEngine;
using UnityEngine.UIElements;
using Zenject;
namespace N30R1L37
{
[UnityEngine.Scripting.Preserve]
public class AspectRatioLabel : Label, IDisposable
{
[UnityEngine.Scripting.Preserve]
public new class UxmlFactory : UxmlFactory<AspectRatioLabel, UxmlTraits> {}
[UnityEngine.Scripting.Preserve]
public new class UxmlTraits : VisualElement.UxmlTraits
{
readonly UxmlBoolAttributeDescription maintainAspectRatio = new() { name = "maintain-aspect-ratio", defaultValue = true };
readonly UxmlEnumAttributeDescription<RatioFlexEnum.RatioFlex> ratioFlex = new () { name = "ratio-flex-type", defaultValue = RatioFlexEnum.RatioFlex.Auto};
readonly UxmlFloatAttributeDescription aspectRatio = new() { name = "aspect-ratio", defaultValue = 1.0f };
readonly UxmlFloatAttributeDescription scale = new() { name = "scale", defaultValue = 1.0f };
readonly UxmlStringAttributeDescription label = new() { name = "label", defaultValue = "Button" };
readonly UxmlEnumAttributeDescription<FontResizeTypeEnum.FontResizeType> fontResizeType = new () { name = "font-resize-type", defaultValue = FontResizeTypeEnum.FontResizeType.None};
readonly UxmlFloatAttributeDescription fontScale = new() { name = "font-scale", defaultValue = 1.0f };
readonly UxmlIntAttributeDescription maxCharacters = new() { name = "max-characters", defaultValue = 20 };
//readonly UxmlFloatAttributeDescription grow = new() { name = "label-grow", defaultValue = 1.0f};
readonly UxmlFloatAttributeDescription cornerRadius = new() { name = "corner-radius", defaultValue = 0.0f};
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get { yield break; }
}
public override void Init( VisualElement visualElement, IUxmlAttributes attributes, CreationContext creationContext )
{
base.Init( visualElement, attributes, creationContext );
AspectRatioLabel element = (AspectRatioLabel)visualElement;
if (element != null)
{
element.MaintainAspectRatio = maintainAspectRatio.GetValueFromBag(attributes, creationContext);
element.RatioFlexType = ratioFlex.GetValueFromBag(attributes, creationContext);
element.FontResizeType = fontResizeType.GetValueFromBag(attributes, creationContext);
element.AspectRatio = aspectRatio.GetValueFromBag( attributes, creationContext ) == 0 ? 1 : aspectRatio.GetValueFromBag( attributes, creationContext );
element.Scale = scale.GetValueFromBag( attributes, creationContext );
element.Label = label.GetValueFromBag(attributes, creationContext);
element.FontScale = fontScale.GetValueFromBag( attributes, creationContext );
element.MaxCharacters = maxCharacters.GetValueFromBag( attributes, creationContext );
element.CornerRadius = cornerRadius.GetValueFromBag(attributes, creationContext);
}
}
}
public FontResizeTypeEnum.FontResizeType FontResizeType { get; set; } = FontResizeTypeEnum.FontResizeType.None;
public RatioFlexEnum.RatioFlex RatioFlexType { get; set; } = RatioFlexEnum.RatioFlex.Auto;
public float Scale { get; set; } = 1.0f;
private bool _maintainAspectRatio = true;
public bool MaintainAspectRatio
{
get => _maintainAspectRatio;
set
{
_maintainAspectRatio = value;
if (!value) return;
style.width = StyleKeyword.Auto;
style.height = StyleKeyword.Auto;
style.minWidth = StyleKeyword.Auto;
style.minHeight = StyleKeyword.Auto;
style.maxWidth = StyleKeyword.Auto;
style.maxHeight = StyleKeyword.Auto;
}
}
private float _aspectRatio = 1.0f;
public float AspectRatio
{
get => _aspectRatio;
set
{
_aspectRatio = Mathf.Max(value, 0.01f);
}
}
private float _cornerRadius = 0.0f;
public float CornerRadius
{
get => _cornerRadius;
set
{
_cornerRadius = Mathf.Max(value, 0.0f);
}
}
private string _label = "";
public string Label
{
get => _label;
set
{
_label = value;
text = value;
}
}
private int _maxCharacters = 20;
public int MaxCharacters
{
get => _maxCharacters;
set
{
_maxCharacters = value;
_isDirty = true;
}
}
public float FontScale { get; set; } = 1;
public void ForceRedraw() => _isDirty = true;
public AspectRatioLabel()
{
RegisterCallback<AttachToPanelEvent>( OnAttachToPanelEvent );
}
void OnAttachToPanelEvent( AttachToPanelEvent e )
{
parent?.RegisterCallback<GeometryChangedEvent>( OnGeometryChangedEvent );
style.width = Length.Percent(100);
style.height = Length.Percent(100);
style.whiteSpace = WhiteSpace.Normal;
style.overflow = Overflow.Hidden;
MonitorIsDirty();
}
private bool _isDirty = false;
private void MonitorIsDirty()
{
Observable.EveryUpdate().ObserveOnMainThread().Subscribe(_ =>
{
if (!_isDirty) return;
Redraw();
});
}
void OnGeometryChangedEvent( GeometryChangedEvent e )
{
_isDirty = true;
}
void Redraw()
{
if (parent == null || !this.IsInitialized()) return;
var newSize = this.RedrawAspectRatio(
parent.localBound.size,
AspectRatio,
Scale,
MaintainAspectRatio,
RatioFlexType);
newSize *= Scale;
SetBorderRadius(CornerRadius * newSize.magnitude * 0.01f);
switch (FontResizeType)
{
case FontResizeTypeEnum.FontResizeType.None:
break;
case FontResizeTypeEnum.FontResizeType.Scale:
this.ResizeFont(newSize, FontScale);
break;
case FontResizeTypeEnum.FontResizeType.Screen:
float fontSize = MaxCharacters * FontScale * /*(newSize.magnitude * 0.01f) */ ScreenCoordinator.ScreenScale;
style.fontSize = new StyleLength (fontSize);
break;
}
_isDirty = false;
}
private void SetBorderRadius(float scale)
{
style.borderBottomLeftRadius = scale;
style.borderTopLeftRadius = scale;
style.borderTopRightRadius = scale;
style.borderBottomRightRadius = scale;
}
public void Dispose()
{
parent?.UnregisterCallback<GeometryChangedEvent>( OnGeometryChangedEvent );
UnregisterCallback<AttachToPanelEvent>( OnAttachToPanelEvent );
}
}
}
/*
This is free and unencumbered software released into the public
domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the
benefit of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using UnityEngine.UIElements;
namespace N30R1L37
{
[UnityEngine.Scripting.Preserve]
public class AspectRatioPanel : VisualElement, IDisposable
{
[UnityEngine.Scripting.Preserve]
public new class UxmlFactory : UxmlFactory<AspectRatioPanel, UxmlTraits> {}
[UnityEngine.Scripting.Preserve]
public new class UxmlTraits : VisualElement.UxmlTraits
{
readonly UxmlBoolAttributeDescription maintainAspectRatio = new() { name = "maintain-aspect-ratio", defaultValue = true };
readonly UxmlEnumAttributeDescription<RatioFlexEnum.RatioFlex> ratioFlex = new () { name = "ratio-flex-type", defaultValue = RatioFlexEnum.RatioFlex.Auto};
readonly UxmlFloatAttributeDescription aspectRatio = new() { name = "aspect-ratio", defaultValue = 1.0f };
readonly UxmlFloatAttributeDescription scale = new() { name = "scale", defaultValue = 1.0f };
readonly UxmlFloatAttributeDescription cornerRadius = new() { name = "corner-radius", defaultValue = 0.0f};
readonly UxmlBoolAttributeDescription addLabel = new() { name = "add-label", defaultValue = false };
readonly UxmlStringAttributeDescription text = new() { name = "text", defaultValue = "Label" };
readonly UxmlFloatAttributeDescription fontScale = new() { name = "font-scale", defaultValue = 1.0f };
readonly UxmlFloatAttributeDescription lableGrow = new() { name = "label-grow", defaultValue = 1.0f};
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get { yield break; }
}
public override void Init( VisualElement visualElement, IUxmlAttributes attributes, CreationContext creationContext )
{
base.Init( visualElement, attributes, creationContext );
AspectRatioPanel element = (AspectRatioPanel)visualElement;
if (element != null)
{
element.MaintainAspectRatio = maintainAspectRatio.GetValueFromBag(attributes, creationContext);
element.RatioFlexType = ratioFlex.GetValueFromBag(attributes, creationContext);
element.AspectRatio = aspectRatio.GetValueFromBag( attributes, creationContext ) == 0 ? 1 : aspectRatio.GetValueFromBag( attributes, creationContext );
element.Scale = scale.GetValueFromBag( attributes, creationContext );
element.Text = text.GetValueFromBag(attributes, creationContext);
element.FontScale = fontScale.GetValueFromBag( attributes, creationContext );
element.AddLabel = addLabel.GetValueFromBag(attributes, creationContext);
element.CornerRadius = cornerRadius.GetValueFromBag(attributes, creationContext);
element.LabelGrow = lableGrow.GetValueFromBag(attributes, creationContext);
element.Redraw();
}
}
}
private Label _label;
public RatioFlexEnum.RatioFlex RatioFlexType { get; set; } = RatioFlexEnum.RatioFlex.Auto;
public float FontScale { get; set; } = 1;
public float Scale { get; set; } = 1.0f;
private bool _maintainAspectRatio = true;
public bool MaintainAspectRatio
{
get => _maintainAspectRatio;
set
{
_maintainAspectRatio = value;
if (!value) return;
style.width = StyleKeyword.Auto;
style.height = StyleKeyword.Auto;
style.minWidth = StyleKeyword.Auto;
style.minHeight = StyleKeyword.Auto;
style.maxWidth = StyleKeyword.Auto;
style.maxHeight = StyleKeyword.Auto;
}
}
private float _labelGrow = 1;
public float LabelGrow
{
get => _labelGrow;
set
{
_labelGrow = value;
if (_label == null) return;
_label.style.flexGrow = _labelGrow;
}
}
private float _aspectRatio = 1.0f;
public float AspectRatio
{
get => _aspectRatio;
set
{
_aspectRatio = Mathf.Max(value, 0.01f);
}
}
private float _cornerRadius = 0.0f;
public float CornerRadius
{
get => _cornerRadius;
set
{
_cornerRadius = Mathf.Max(value, 0.0f);
}
}
private bool _addLabel = false;
public bool AddLabel
{
get => _addLabel;
set
{
_addLabel = value;
if(value && _label == null) AddLabelToView();
else if(!value && _label != null)
{
Remove(_label);
_label = null;
}
}
}
private string _text = "";
public string Text
{
get => _text;
set
{
_text = value;
if (_label != null) _label.text = value;
}
}
public AspectRatioPanel()
{
if(AddLabel) AddLabelToView();
RegisterCallback<AttachToPanelEvent>( OnAttachToPanelEvent );
}
private void AddLabelToView()
{
var length = new StyleLength(0f);
_label = new()
{
style =
{
position = Position.Absolute,
left = length, //StyleInt(0);//StyleKeyword.Auto,
top = length, //StyleKeyword.Auto,
right = length, //StyleKeyword.Auto,
bottom = length, //StyleKeyword.Auto,
flexShrink = 1,
flexGrow = LabelGrow,
whiteSpace = WhiteSpace.Normal
},
text = _text
};
Add(_label);
}
void OnAttachToPanelEvent( AttachToPanelEvent e )
{
parent?.RegisterCallback<GeometryChangedEvent>( OnGeometryChangedEvent );
MonitorIsDirty();
}
private bool _isDirty = false;
private void MonitorIsDirty()
{
// if (Application.isEditor && !Application.isPlaying)
// {
// Redraw();
// return;
// }
Observable.EveryUpdate().ObserveOnMainThread().Subscribe(_ =>
{
if (!_isDirty) return;
Redraw();
});
}
void OnGeometryChangedEvent( GeometryChangedEvent e )
{
_isDirty = true;
}
void Redraw()
{
if (parent == null) return;
var newSize = this.RedrawAspectRatio(
parent.localBound.size,
AspectRatio,
Scale,
MaintainAspectRatio,
RatioFlexType);
newSize *= Scale;
SetBorderRadius(CornerRadius * newSize.magnitude * 0.01f);
if(AddLabel) _label.ResizeFont(newSize, FontScale);
_isDirty = false;
}
private void SetBorderRadius(float scale)
{
style.borderBottomLeftRadius = scale;
style.borderTopLeftRadius = scale;
style.borderTopRightRadius = scale;
style.borderBottomRightRadius = scale;
}
public void Dispose()
{
parent?.UnregisterCallback<GeometryChangedEvent>( OnGeometryChangedEvent );
UnregisterCallback<AttachToPanelEvent>( OnAttachToPanelEvent );
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using DG.Tweening;
using N30R1L37;
using UniRx;
using UnityEngine;
using UnityEngine.UIElements;
using Unit = UniRx.Unit;
public static class UIElementsExtensions
{
//NOTE: if you want to use the click observables, Add UniRX to your project via the Project Manager (it's free)
/*public static IObservable<Unit> OnClickAsObservable(this Button container)
{
Subject<Unit> _subject = new();
container.RegisterCallback<ClickEvent>(evt =>
{
_subject.OnNext(Unit.Default);
});
return _subject.AsUnitObservable();
}
public static IObservable<Unit> OnClickAsObservable(this VisualElement container)
{
Subject<Unit> _subject = new();
container.RegisterCallback<ClickEvent>(evt =>
{
_subject.OnNext(Unit.Default);
});
return _subject.AsUnitObservable();
}
public static IObservable<PointerDownEvent> OnContextClickAsObservable(this VisualElement container)
{
Subject<PointerDownEvent> _subject = new();
container.RegisterCallback<PointerDownEvent>(evt =>
{
if (evt.button == 0) return;
_subject.OnNext(evt);
});
return _subject.AsObservable();
}
public static IObservable<PointerDownEvent> OnMouseDownAsObservable(this VisualElement container)
{
Subject<PointerDownEvent> _subject = new();
container.RegisterCallback<PointerDownEvent>(evt =>
{
_subject.OnNext(evt);
});
return _subject.AsObservable();
}
public static IObservable<PointerMoveEvent> OnMouseMoveAsObservable(this VisualElement container)
{
Subject<PointerMoveEvent> _subject = new();
container.RegisterCallback<PointerMoveEvent>(evt =>
{
_subject.OnNext(evt);
});
return _subject.AsObservable();
}
public static IObservable<PointerUpEvent> OnMouseUpAsObservable(this VisualElement container)
{
Subject<PointerUpEvent> _subject = new();
container.RegisterCallback<PointerUpEvent>(evt =>
{
_subject.OnNext(evt);
});
return _subject.AsObservable();
}
public static IObservable<Unit> OnInitialized(this VisualElement container)
{
return Observable.Create<Unit>(observer =>
{
if (container.IsInitialized())
{
observer.OnNext(Unit.Default);
observer.OnCompleted();
return Disposable.Empty;
}
return container.ObserveEveryValueChanged(x => x.localBound.width).Subscribe(width =>
{
if (!Single.IsNaN(width))
{
observer.OnNext(Unit.Default);
observer.OnCompleted();
}
});
});
}
*/
public static bool IsInitialized(this VisualElement container)
{
return !Single.IsNaN(container.localBound.width);
}
public static void RemoveAllChildren(this VisualElement container)
{
if (container.childCount > 0)
{
List<VisualElement> children = container.Children().ToList();
foreach (var element in children)
{
container.Remove(element);
}
}
}
public static void SetBackgroundImage(this VisualElement container, Sprite image)
{
Background background = container.style.backgroundImage.value;
background.sprite = image;
container.style.backgroundImage = background;
}
public static void SetBackgroundColor(this VisualElement container, Color color, float alpha = -1)
{
StyleColor styleColor = container.style.backgroundColor;
if (alpha > -1)
{
color.a = alpha;
}
styleColor.value = color;
container.style.backgroundColor = styleColor;
}
public static float GetAlpha(this VisualElement container)
{
return container.style.opacity.value;
}
public static void SetAlpha(this VisualElement container, float value)
{
container.style.opacity = value;
}
public static Vector2 GetPosition(this VisualElement container)
{
return new Vector2(container.style.left.value.value, container.style.top.value.value);
}
public static void SetPosition(this VisualElement container, Vector2 position)
{
container.style.left = position.x;
container.style.right = position.y;
}
public static float GetRotation(this VisualElement container)
{
return container.transform.rotation.eulerAngles.z;
}
public static void SetRotation(this VisualElement container, float angle)
{
container.transform.rotation = Quaternion.Euler(0,0,angle);
}
public static void SetDisplay(this VisualElement container, bool visible)
{
var display = container.style.display;
display.value = visible ? DisplayStyle.Flex : DisplayStyle.None;
container.style.display = display;
}
public static void SetVisibility(this VisualElement container, bool visible)
{
var visibility = container.style.visibility;
visibility.value = visible ? Visibility.Visible : Visibility.Hidden;
container.style.visibility = visibility;
}
public static void SetMargin(this VisualElement container, float value)
{
container.style.marginBottom = value;
container.style.marginLeft = value;
container.style.marginRight = value;
container.style.marginTop = value;
}
public static float GetScale(this VisualElement container)
{
return container.style.scale.value.value.x;
}
public static void SetScale(this VisualElement container, float value)
{
var scale = new StyleScale
{
value = new Scale{ value = (Vector2.one * value) }
};
container.style.scale = scale;
}
public static void SetScale(this StyleLength container, float value)
{
container.value = container.value.value * value;
}
public static void SetStyleScale(this StyleLength container, float value)
{
//container.value = container.value.value * value;
container.value = value;
}
public static AspectRatioButton GetButton(this VisualElement container)
{
if (container is Button) return container as AspectRatioButton;
return container.Children().ToList()
.OfType<AspectRatioButton>()
.Select(visualElement => visualElement)
.FirstOrDefault();
}
public static Vector2 RedrawAspectRatio(this VisualElement container,
Vector2 size,
float aspectRatio,
float scale,
bool maintainAspectRatio = true,
RatioFlexEnum.RatioFlex ratioFlexType = RatioFlexEnum.RatioFlex.Auto)
{
var newSize = size;
newSize *= scale;
float targetW = newSize.x;
float targetH = newSize.y;
if (maintainAspectRatio)
{
switch (ratioFlexType)
{
case RatioFlexEnum.RatioFlex.Auto:
targetW = newSize.magnitude / aspectRatio;
targetH = newSize.magnitude * aspectRatio;
break;
case RatioFlexEnum.RatioFlex.ParentWidth:
targetH = targetW / aspectRatio;
break;
case RatioFlexEnum.RatioFlex.ParentHeight:
targetW = targetH / aspectRatio;
break;
}
}
newSize = new Vector2(targetW, targetH);
container.style.width = new StyleLength(newSize.x);
container.style.height = new StyleLength(newSize.y);
return newSize;
}
/// <summary>
/// Pass the object that has text/font - ie: Label, Button
/// </summary>
/// <param name="container"></param>
/// <param name="parentSize">Vector2 - parent.localBound.size</param>
/// <param name="fontScale">float - scale of the font</param>
public static float ResizeFont(this TextElement container,
Vector2 parentSize,
float fontScale,
float fontPadding,
string text = ""
)
{
if (container.resolvedStyle.unityFontDefinition.fontAsset == null) return fontScale;
Vector2 textSize = container.MeasureTextSize(text, 0, VisualElement.MeasureMode.Undefined, 0, VisualElement.MeasureMode.Undefined);
float containerWidthAspectRatio = parentSize.x / textSize.x;
float containerHeightAspectRatio = parentSize.y / textSize.y;
float smallerAspectRatio = Mathf.Min(containerWidthAspectRatio, containerHeightAspectRatio);
fontScale *= smallerAspectRatio * fontPadding;
if (float.IsNaN(fontScale)) return 1.0f;
float fontSize = parentSize.x * fontScale;
container.style.fontSize = new StyleLength(fontSize);
return fontScale;
}
public static void ResizeFont(this VisualElement container, Vector2 parentSize, float fontScale)
{
var ratio = Math.Min(parentSize.x,parentSize.y);
var fontSize = (ratio * 0.01f) * fontScale;
if (float.IsNaN(fontSize) || fontSize == container.style.fontSize) return;
container.style.fontSize = new StyleLength (fontSize);
}
public static void ResizeFont(this TextElement container, Vector2 parentSize, float fontScale, string text)
{
container.style.fontSize = GetCharacterWidth(container, text).x;
Vector2 textSize = container.MeasureTextSize(text, parentSize.x, VisualElement.MeasureMode.Undefined, 0, VisualElement.MeasureMode.Undefined);
float p = 1.0f;
if (textSize.x > parentSize.x)
{
p = (parentSize.x / textSize.x);
}
var ratio = Math.Min(parentSize.x,parentSize.y);
var fontSize = (ratio * 0.1f) * fontScale * p;
if (float.IsNaN(fontSize) || fontSize == container.style.fontSize) return;
container.style.fontSize = new StyleLength (fontSize);
}
public static Vector2 GetCharacterWidth(TextElement textElement, string chr = "SUBMIT")
{
TextElement tempText = new TextElement();
tempText.style.unityFontDefinition = textElement.resolvedStyle.unityFontDefinition;
List<Vector2> list = new();
foreach (var VARIABLE in chr)
{
tempText.text = VARIABLE.ToString();
Vector2 textSize = tempText.MeasureTextSize(VARIABLE.ToString(), 0, VisualElement.MeasureMode.Undefined, 0, VisualElement.MeasureMode.Undefined);
list.Add(textSize);
}
Vector2 averageVector = list.Aggregate(Vector2.zero, (current, vector) => current + vector) / list.Count;
return averageVector;
}
/// <summary>
/// Fades a CanvasGroup to a given value and sets its interactive flags while using a referenced Tweener object for safe tweening from its current alpha value.
/// </summary>
/// <param name="alpha">End Float Value</param>
/// <param name="duration">Optional: duration in seconds. Default is 0.5</param>
/// <param name="isInteractive">Bool of whether or not to be interactive</param>
/// <param name="tweener">Tweener reference. Use this for OnUpdate/OnComplete calls within the caller</param>
public static void FadeToAndSetInteractive(this VisualElement container, float alpha, bool isInteractive, ref Tweener tweener, float duration = 0.5f, Ease easing = Ease.Linear)
{
if (tweener != null && tweener.IsActive())
{
tweener.Pause();
}
tweener = DOTween.To(() => container.GetAlpha(), value =>
{
container.SetAlpha(value);
}, alpha, duration)
.SetEase(easing);
container.pickingMode = isInteractive ? PickingMode.Position : PickingMode.Ignore;
}
/// <summary>
/// Set the size of the canvas and then set it's interactivity
/// </summary>
/// <param name="moveTo">Vector2: representing the final position</param>
/// <param name="interactive">Bool: should this be interactive?</param>
/// <param name="tweener">Tweener reference. Use this for OnUpdate/OnComplete calls within the caller</param>
/// <param name="duration">Optional: duration in seconds. Default is 0.5</param>
/// <param name="easing">Easing to use</param>
public static void MoveToAndSetInteractivity(this VisualElement container, Vector2 moveTo, bool interactive, ref Tweener tweener, float duration = 0.5f, Ease easing = Ease.Linear)
{
if (tweener != null && tweener.IsActive())
{
tweener.Pause();
}
tweener = DOTween.To(container.GetPosition, container.SetPosition, moveTo, duration)
.SetEase(easing);
container.pickingMode = interactive ? PickingMode.Position : PickingMode.Ignore;
}
/// <summary>
/// Set the size of the canvas and then set it's interactivity
/// </summary>
/// <param name="rotateTo">Vector3: representing the final rotation</param>
/// <param name="interactive">Bool: should this be interactive?</param>
/// <param name="tweener">Tweener reference. Use this for OnUpdate/OnComplete calls within the caller</param>
/// <param name="duration">Optional: duration in seconds. Default is 0.5</param>
/// <param name="easing">Easing to use</param>
public static void RotateToAndSetInteractivity(this VisualElement container, float rotateTo, bool interactive, ref Tweener tweener, float duration = 0.5f, Ease easing = Ease.Linear)
{
if (tweener != null && tweener.IsActive())
{
tweener.Pause();
tweener.Complete();
}
float startValue = 0;
float diff = 0;
tweener = DOTween.To(() => startValue, angle =>
{
diff = angle - startValue;
startValue = angle;
container.SetRotation(container.GetRotation() + diff);
}, rotateTo, duration)
.SetEase(easing);
container.pickingMode = interactive ? PickingMode.Position : PickingMode.Ignore;
}
}
@neoRiley
Copy link
Author

7/12/2023 - Fixed a bug with Horizontal sizing with parent

@neoRiley
Copy link
Author

7/13/2023 - Removed hard-coded Position settings!

@neoRiley
Copy link
Author

7/16/2023 - Fixed recursion error / warning about redrawing the component. Fixed widht/height settings when selecting to MaintainAspectRatio

@wfettich
Copy link

wfettich commented Sep 25, 2023

I get this compile error in function SetBorderRadius :

'StyleLength' does not contain a definition for 'Scale' and no accessible extension method 'Scale' accepting a first argument of type 'StyleLength' could be found (are you missing a using directive or an assembly reference?)

@neoRiley
Copy link
Author

@wfettich I'm going to post my extensions class within AspectRatioPanel - I apologize for not thinking of this!

@neoRiley
Copy link
Author

@wfettich ok I added the extensions class and updated AspectRatioPanel to the latest version. Let me know if this works for you

@tiritto
Copy link

tiritto commented Nov 14, 2023

There are plenty of unresolved symbols like FontResizeTypeEnum, ScreenCoordinator, RatioFlexEnum, RatioFlex.
Used depedencies are also unclear, while I was able to find and install UniRx and DoTween as dependencies, I couldn't find EvolveDM.UI.UIToolKit.Base anywhere on the internet. Moreover, is Zenject required for this to work?

@neoRiley
Copy link
Author

Oh @tiritto - I have to apologize, I'll get that out as soon as I can. I have some updates as well and some other classes like AspectRatioLabel, AspectRatioButton. UniRx - yeah, if you want to use OnClickAsObservable() to easily subscribe for mouse click events (or tap), you'd have to use UniRx and subscribe.

Thanks for the heads up, I've been really slammed for time for the past 2 weeks, but I'll try and get this resolved as soon as I can

@Marco-Weder
Copy link

Any updates on the unresolved symbols? I would really like to use this.

@neoRiley
Copy link
Author

I will work on it this week - so sorry for the delay. Just been super tied up with work and my own project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment