🔍 s&box Package Code Search
Search C# source code, UI razor templates, shaders, and configs across s&box packages.
🔗 Raw Facepunch API Link: https://public.facepunch.com/sbox/code/search/1/?ident=ali3nsystems.lib-metrify&take=20
Showing code results for query:
*
(10 total matches found)
Game
library
using System;
namespace Metrify;
[AttributeUsage( AttributeTargets.Property | AttributeTargets.Field )]
public class MetersAttribute : Attribute
{
}
Editor
library
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Editor;
using Editor.Inspectors;
using Sandbox;
namespace Metrify;
public static class MetricRowInjector
{
private static readonly ConditionalWeakTable<Widget, object> _injected = new();
private static RealTimeSince _sinceLastScan;
[EditorEvent.Frame]
public static void OnFrame()
{
// The UI tree only changes on selection/edit; a 10Hz scan is plenty and keeps the
// recursive traversal off the per-frame cost.
if ( _sinceLastScan < 0.1f ) return;
_sinceLastScan = 0;
var root = EditorWindow;
if ( !root.IsValid() ) return;
foreach ( var inspector in FindDescendants<GameObjectInspector>( root ) )
{
var transformSheet = FindDescendants<ComponentSheet>( inspector )
.FirstOrDefault( s => s.Header?.Title == "Transform" );
if ( !transformSheet.IsValid() ) continue;
var editorWidget = FindDescendants<ComponentEditorWidget>( transformSheet ).FirstOrDefault();
if ( !editorWidget.IsValid() || editorWidget.Layout is null ) continue;
if ( _injected.TryGetValue( editorWidget, out _ ) ) continue;
var metric = BuildMetricProperty( inspector.SerializedObject );
if ( metric is null ) continue;
var sheet = new ControlSheet();
sheet.IncludePropertyNames = true;
sheet.AddRow( metric );
editorWidget.Layout.Add( sheet );
_injected.Add( editorWidget, null );
}
}
private static SerializedProperty BuildMetricProperty( SerializedObject inspectorObject )
{
var transformProp = inspectorObject?.GetProperty( nameof( GameObject.Transform ) );
if ( transformProp is null ) return null;
if ( !transformProp.TryGetAsObject( out var transform ) ) return null;
var localPosition = transform.GetProperty( "LocalPosition" );
if ( localPosition is null ) return null;
var customizable = localPosition.GetCustomizable();
customizable.SetDisplayName( "Local Position (meters)" );
customizable.AddAttribute( new MetersAttribute() );
return customizable;
}
private static IEnumerable<T> FindDescendants<T>( Widget root ) where T : Widget
{
foreach ( var child in root.Children )
{
if ( !child.IsValid() ) continue;
if ( child is T match )
yield return match;
foreach ( var descendant in FindDescendants<T>( child ) )
yield return descendant;
}
}
}
Game
library
using System;
namespace Metrify;
[AttributeUsage( AttributeTargets.Property | AttributeTargets.Field )]
public class MetersAttribute : Attribute
{
}
Game
library
global using static Sandbox.Internal.GlobalGameNamespace;
global using Microsoft.AspNetCore.Components;
global using Microsoft.AspNetCore.Components.Rendering;
[assembly: global::System.Reflection.AssemblyMetadata( "AddonTitle", "Metrify" )]
[assembly: global::System.Reflection.AssemblyMetadata( "AddonIdent", "lib-metrify" )]
[assembly: global::System.Reflection.AssemblyMetadata( "OrgIdent", "ali3nsystems" )]
[assembly: global::System.Reflection.AssemblyMetadata( "Ident", "ali3nsystems.lib-metrify" )]
[assembly: global::System.Reflection.AssemblyMetadata( "EngineVersion", "28" )]
[assembly: global::System.Reflection.AssemblyMetadata( "EngineMinorVersion", "1" )]
[assembly: System.Runtime.Versioning.TargetFramework( ".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0" )]
[assembly: global::System.Reflection.AssemblyMetadata( "CompileTime", "2026-08-05T13:23:28.7534796Z" )]
[assembly: global::System.Reflection.AssemblyVersion("0.0.117.0")]
[assembly: global::System.Reflection.AssemblyFileVersion("0.0.117.0")]
Game
library
using Sandbox;
namespace Metrify;
public static class UnitExtensions
{
/// <summary>Inches (world units) to metres.</summary>
public static float ToMeters( this float inches ) => Units.ToMeters( inches );
/// <summary>Metres to inches (world units).</summary>
public static float ToWorldUnits( this float meters ) => Units.ToInches( meters );
/// <summary>Inches (world units) to metres.</summary>
public static Vector3 ToMeters( this Vector3 inches ) => Units.ToMeters( inches );
/// <summary>Metres to inches (world units).</summary>
public static Vector3 ToWorldUnits( this Vector3 meters ) => Units.ToInches( meters );
/// <summary>This object's world position in metres.</summary>
public static Vector3 WorldPositionMeters( this GameObject go ) => Units.ToMeters( go.WorldPosition );
/// <summary>This object's local position in metres.</summary>
public static Vector3 LocalPositionMeters( this GameObject go ) => Units.ToMeters( go.LocalPosition );
/// <summary>Set this object's world position from metres.</summary>
public static void SetWorldPositionMeters( this GameObject go, Vector3 meters )
=> go.WorldPosition = Units.ToInches( meters );
/// <summary>Set this object's local position from metres.</summary>
public static void SetLocalPositionMeters( this GameObject go, Vector3 meters )
=> go.LocalPosition = Units.ToInches( meters );
}
Editor
library
using Sandbox;
namespace Metrify;
internal sealed class MeterFloatProperty : SerializedProperty.Proxy
{
private readonly SerializedProperty _target;
protected override SerializedProperty ProxyTarget => _target;
public MeterFloatProperty( SerializedProperty target )
{
_target = target;
}
public override T GetValue<T>( T defaultValue = default )
{
if ( typeof( T ) == typeof( float ) || typeof( T ) == typeof( double ) ||
typeof( T ) == typeof( string ) || typeof( T ) == typeof( object ) )
{
var meters = Units.ToMeters( _target.GetValue<float>() );
if ( typeof( T ) == typeof( float ) ) return (T)(object)meters;
if ( typeof( T ) == typeof( double ) ) return (T)(object)(double)meters;
if ( typeof( T ) == typeof( string ) ) return (T)(object)meters.ToString( "0.###" );
return (T)(object)meters;
}
return _target.GetValue( defaultValue );
}
public override void SetValue<T>( T value )
{
switch ( value )
{
case float meters:
_target.SetValue( Units.ToInches( meters ) );
return;
case double meters:
_target.SetValue( Units.ToInches( (float)meters ) );
return;
case string text when float.TryParse( text, out var meters ):
_target.SetValue( Units.ToInches( meters ) );
return;
}
_target.SetValue( value );
}
}
Game
library
namespace Metrify;
public static class Units
{
public const float InchesToMeters = 0.0254f;
public const float MetersToInches = 1f / InchesToMeters;
public static float ToMeters( float inches ) => inches * InchesToMeters;
public static float ToInches( float meters ) => meters * MetersToInches;
public static Vector3 ToMeters( Vector3 inches ) => inches * InchesToMeters;
public static Vector3 ToInches( Vector3 meters ) => meters * MetersToInches;
}
Game
library
using Sandbox;
namespace Metrify;
public static class UnitExtensions
{
/// <summary>Inches (world units) to metres.</summary>
public static float ToMeters( this float inches ) => Units.ToMeters( inches );
/// <summary>Metres to inches (world units).</summary>
public static float ToWorldUnits( this float meters ) => Units.ToInches( meters );
/// <summary>Inches (world units) to metres.</summary>
public static Vector3 ToMeters( this Vector3 inches ) => Units.ToMeters( inches );
/// <summary>Metres to inches (world units).</summary>
public static Vector3 ToWorldUnits( this Vector3 meters ) => Units.ToInches( meters );
/// <summary>This object's world position in metres.</summary>
public static Vector3 WorldPositionMeters( this GameObject go ) => Units.ToMeters( go.WorldPosition );
/// <summary>This object's local position in metres.</summary>
public static Vector3 LocalPositionMeters( this GameObject go ) => Units.ToMeters( go.LocalPosition );
/// <summary>Set this object's world position from metres.</summary>
public static void SetWorldPositionMeters( this GameObject go, Vector3 meters )
=> go.WorldPosition = Units.ToInches( meters );
/// <summary>Set this object's local position from metres.</summary>
public static void SetLocalPositionMeters( this GameObject go, Vector3 meters )
=> go.LocalPosition = Units.ToInches( meters );
}
Game
library
namespace Metrify;
public static class Units
{
public const float InchesToMeters = 0.0254f;
public const float MetersToInches = 1f / InchesToMeters;
public static float ToMeters( float inches ) => inches * InchesToMeters;
public static float ToInches( float meters ) => meters * MetersToInches;
public static Vector3 ToMeters( Vector3 inches ) => inches * InchesToMeters;
public static Vector3 ToInches( Vector3 meters ) => meters * MetersToInches;
}
Editor
library
using Editor;
using Sandbox;
namespace Metrify;
/// <summary>
/// Draws a [Meters] float in metres, with an "m" suffix label.
/// </summary>
[CustomEditor( typeof( float ), WithAllAttributes = new[] { typeof( MetersAttribute ) } )]
public sealed class MeterFloatControlWidget : ControlWidget
{
public override bool SupportsMultiEdit => true;
private readonly FloatControlWidget _control;
public MeterFloatControlWidget( SerializedProperty property ) : base( property )
{
HorizontalSizeMode = SizeMode.CanGrow | SizeMode.Expand;
Layout = Layout.Row();
Layout.Spacing = 2;
_control = Layout.Add( new FloatControlWidget( new MeterFloatProperty( property ) )
{
Label = "m",
HighlightColor = Theme.Green,
ToolTip = "Metres — stored as inches (s&box world units)"
}, 1 );
}
public override void StartEditing() => _control?.StartEditing();
protected override void OnPaint()
{
// child widget paints itself
}
protected override void PaintUnder()
{
// nothing
}
}
/// <summary>
/// Draws a [Meters] Vector3 with each axis in metres.
/// </summary>
[CustomEditor( typeof( Vector3 ), WithAllAttributes = new[] { typeof( MetersAttribute ) } )]
public sealed class MeterVectorControlWidget : ControlWidget
{
public override bool SupportsMultiEdit => true;
private FloatControlWidget _first;
public MeterVectorControlWidget( SerializedProperty property ) : base( property )
{
HorizontalSizeMode = SizeMode.CanGrow | SizeMode.Expand;
if ( !property.TryGetAsObject( out var obj ) )
{
Log.Warning( $"[Meters] could not read {property.Name} as an object" );
return;
}
Layout = Layout.Row();
Layout.Spacing = 2;
_first = AddAxis( obj, "x", Theme.Red, "X" );
AddAxis( obj, "y", Theme.Green, "Y" );
AddAxis( obj, "z", Theme.Blue, "Z" );
}
private FloatControlWidget AddAxis( SerializedObject obj, string name, Color color, string label )
{
var axis = obj.GetProperty( name );
if ( axis is null ) return null;
var control = Layout.Add( new FloatControlWidget( new MeterFloatProperty( axis ) )
{
Label = label,
HighlightColor = color,
ToolTip = "Metres — stored as inches (s&box world units)"
}, 1 );
control.MinimumWidth = Theme.RowHeight;
control.HorizontalSizeMode = SizeMode.CanGrow | SizeMode.Expand;
return control;
}
public override void StartEditing() => _first?.StartEditing();
protected override void OnPaint()
{
// child widgets paint themselves
}
protected override void PaintUnder()
{
// nothing
}
}
Debug: View Raw JSON Response
{
"TotalCount": 10,
"Files": [
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "MetersAttribute.cs",
"FileName": "MetersAttribute.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "using System;\n\nnamespace Metrify;\n\n[AttributeUsage( AttributeTargets.Property | AttributeTargets.Field )]\npublic class MetersAttribute : Attribute\n{\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Editor/MetricRowInjector.cs",
"FileName": "MetricRowInjector.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 338943,
"Code": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing Editor;\nusing Editor.Inspectors;\nusing Sandbox;\n\nnamespace Metrify;\n\npublic static class MetricRowInjector\n{\n\tprivate static readonly ConditionalWeakTable<Widget, object> _injected = new();\n\tprivate static RealTimeSince _sinceLastScan;\n\n\t[EditorEvent.Frame]\n\tpublic static void OnFrame()\n\t{\n\t\t// The UI tree only changes on selection/edit; a 10Hz scan is plenty and keeps the\n\t\t// recursive traversal off the per-frame cost.\n\t\tif ( _sinceLastScan < 0.1f ) return;\n\t\t_sinceLastScan = 0;\n\n\t\tvar root = EditorWindow;\n\t\tif ( !root.IsValid() ) return;\n\n\t\tforeach ( var inspector in FindDescendants<GameObjectInspector>( root ) )\n\t\t{\n\t\t\tvar transformSheet = FindDescendants<ComponentSheet>( inspector )\n\t\t\t\t.FirstOrDefault( s => s.Header?.Title == \"Transform\" );\n\t\t\tif ( !transformSheet.IsValid() ) continue;\n\n\t\t\tvar editorWidget = FindDescendants<ComponentEditorWidget>( transformSheet ).FirstOrDefault();\n\t\t\tif ( !editorWidget.IsValid() || editorWidget.Layout is null ) continue;\n\n\t\t\tif ( _injected.TryGetValue( editorWidget, out _ ) ) continue;\n\n\t\t\tvar metric = BuildMetricProperty( inspector.SerializedObject );\n\t\t\tif ( metric is null ) continue;\n\n\t\t\tvar sheet = new ControlSheet();\n\t\t\tsheet.IncludePropertyNames = true;\n\t\t\tsheet.AddRow( metric );\n\n\t\t\teditorWidget.Layout.Add( sheet );\n\t\t\t_injected.Add( editorWidget, null );\n\t\t}\n\t}\n\n\tprivate static SerializedProperty BuildMetricProperty( SerializedObject inspectorObject )\n\t{\n\t\tvar transformProp = inspectorObject?.GetProperty( nameof( GameObject.Transform ) );\n\t\tif ( transformProp is null ) return null;\n\t\tif ( !transformProp.TryGetAsObject( out var transform ) ) return null;\n\n\t\tvar localPosition = transform.GetProperty( \"LocalPosition\" );\n\t\tif ( localPosition is null ) return null;\n\n\t\tvar customizable = localPosition.GetCustomizable();\n\t\tcustomizable.SetDisplayName( \"Local Position (meters)\" );\n\t\tcustomizable.AddAttribute( new MetersAttribute() );\n\n\t\treturn customizable;\n\t}\n\n\tprivate static IEnumerable<T> FindDescendants<T>( Widget root ) where T : Widget\n\t{\n\t\tforeach ( var child in root.Children )\n\t\t{\n\t\t\tif ( !child.IsValid() ) continue;\n\n\t\t\tif ( child is T match )\n\t\t\t\tyield return match;\n\n\t\t\tforeach ( var descendant in FindDescendants<T>( child ) )\n\t\t\t\tyield return descendant;\n\t\t}\n\t}\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Code/MetersAttribute.cs",
"FileName": "MetersAttribute.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "using System;\n\nnamespace Metrify;\n\n[AttributeUsage( AttributeTargets.Property | AttributeTargets.Field )]\npublic class MetersAttribute : Attribute\n{\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": ".obj/__compiler_extra.cs",
"FileName": "__compiler_extra.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "global using static Sandbox.Internal.GlobalGameNamespace;\r\nglobal using Microsoft.AspNetCore.Components;\r\nglobal using Microsoft.AspNetCore.Components.Rendering;\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"AddonTitle\", \"Metrify\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"AddonIdent\", \"lib-metrify\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"OrgIdent\", \"ali3nsystems\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"Ident\", \"ali3nsystems.lib-metrify\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"EngineVersion\", \"28\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"EngineMinorVersion\", \"1\" )]\r\n\r\n[assembly: System.Runtime.Versioning.TargetFramework( \".NETCoreApp,Version=v9.0\", FrameworkDisplayName = \".NET 9.0\" )]\r\n[assembly: global::System.Reflection.AssemblyMetadata( \"CompileTime\", \"2026-08-05T13:23:28.7534796Z\" )]\r\n[assembly: global::System.Reflection.AssemblyVersion(\"0.0.117.0\")]\r\n[assembly: global::System.Reflection.AssemblyFileVersion(\"0.0.117.0\")]"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Code/UnitExtensions.cs",
"FileName": "UnitExtensions.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "using Sandbox;\n\nnamespace Metrify;\npublic static class UnitExtensions\n{\n\t/// <summary>Inches (world units) to metres.</summary>\n\tpublic static float ToMeters( this float inches ) => Units.ToMeters( inches );\n\n\t/// <summary>Metres to inches (world units).</summary>\n\tpublic static float ToWorldUnits( this float meters ) => Units.ToInches( meters );\n\n\t/// <summary>Inches (world units) to metres.</summary>\n\tpublic static Vector3 ToMeters( this Vector3 inches ) => Units.ToMeters( inches );\n\n\t/// <summary>Metres to inches (world units).</summary>\n\tpublic static Vector3 ToWorldUnits( this Vector3 meters ) => Units.ToInches( meters );\n\n\t/// <summary>This object's world position in metres.</summary>\n\tpublic static Vector3 WorldPositionMeters( this GameObject go ) => Units.ToMeters( go.WorldPosition );\n\n\t/// <summary>This object's local position in metres.</summary>\n\tpublic static Vector3 LocalPositionMeters( this GameObject go ) => Units.ToMeters( go.LocalPosition );\n\n\t/// <summary>Set this object's world position from metres.</summary>\n\tpublic static void SetWorldPositionMeters( this GameObject go, Vector3 meters )\n\t\t=> go.WorldPosition = Units.ToInches( meters );\n\n\t/// <summary>Set this object's local position from metres.</summary>\n\tpublic static void SetLocalPositionMeters( this GameObject go, Vector3 meters )\n\t\t=> go.LocalPosition = Units.ToInches( meters );\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Editor/MeterProperty.cs",
"FileName": "MeterProperty.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 338943,
"Code": "using Sandbox;\n\nnamespace Metrify;\n\ninternal sealed class MeterFloatProperty : SerializedProperty.Proxy\n{\n\tprivate readonly SerializedProperty _target;\n\tprotected override SerializedProperty ProxyTarget => _target;\n\n\tpublic MeterFloatProperty( SerializedProperty target )\n\t{\n\t\t_target = target;\n\t}\n\n\tpublic override T GetValue<T>( T defaultValue = default )\n\t{\n\t\tif ( typeof( T ) == typeof( float ) || typeof( T ) == typeof( double ) ||\n\t\t typeof( T ) == typeof( string ) || typeof( T ) == typeof( object ) )\n\t\t{\n\t\t\tvar meters = Units.ToMeters( _target.GetValue<float>() );\n\n\t\t\tif ( typeof( T ) == typeof( float ) ) return (T)(object)meters;\n\t\t\tif ( typeof( T ) == typeof( double ) ) return (T)(object)(double)meters;\n\t\t\tif ( typeof( T ) == typeof( string ) ) return (T)(object)meters.ToString( \"0.###\" );\n\t\t\treturn (T)(object)meters;\n\t\t}\n\n\t\treturn _target.GetValue( defaultValue );\n\t}\n\n\tpublic override void SetValue<T>( T value )\n\t{\n\t\tswitch ( value )\n\t\t{\n\t\t\tcase float meters:\n\t\t\t\t_target.SetValue( Units.ToInches( meters ) );\n\t\t\t\treturn;\n\n\t\t\tcase double meters:\n\t\t\t\t_target.SetValue( Units.ToInches( (float)meters ) );\n\t\t\t\treturn;\n\n\t\t\tcase string text when float.TryParse( text, out var meters ):\n\t\t\t\t_target.SetValue( Units.ToInches( meters ) );\n\t\t\t\treturn;\n\t\t}\n\n\t\t_target.SetValue( value );\n\t}\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Units.cs",
"FileName": "Units.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "namespace Metrify;\npublic static class Units\n{\n\tpublic const float InchesToMeters = 0.0254f;\n\tpublic const float MetersToInches = 1f / InchesToMeters;\n\n\tpublic static float ToMeters( float inches ) => inches * InchesToMeters;\n\tpublic static float ToInches( float meters ) => meters * MetersToInches;\n\n\tpublic static Vector3 ToMeters( Vector3 inches ) => inches * InchesToMeters;\n\tpublic static Vector3 ToInches( Vector3 meters ) => meters * MetersToInches;\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "UnitExtensions.cs",
"FileName": "UnitExtensions.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "using Sandbox;\n\nnamespace Metrify;\npublic static class UnitExtensions\n{\n\t/// <summary>Inches (world units) to metres.</summary>\n\tpublic static float ToMeters( this float inches ) => Units.ToMeters( inches );\n\n\t/// <summary>Metres to inches (world units).</summary>\n\tpublic static float ToWorldUnits( this float meters ) => Units.ToInches( meters );\n\n\t/// <summary>Inches (world units) to metres.</summary>\n\tpublic static Vector3 ToMeters( this Vector3 inches ) => Units.ToMeters( inches );\n\n\t/// <summary>Metres to inches (world units).</summary>\n\tpublic static Vector3 ToWorldUnits( this Vector3 meters ) => Units.ToInches( meters );\n\n\t/// <summary>This object's world position in metres.</summary>\n\tpublic static Vector3 WorldPositionMeters( this GameObject go ) => Units.ToMeters( go.WorldPosition );\n\n\t/// <summary>This object's local position in metres.</summary>\n\tpublic static Vector3 LocalPositionMeters( this GameObject go ) => Units.ToMeters( go.LocalPosition );\n\n\t/// <summary>Set this object's world position from metres.</summary>\n\tpublic static void SetWorldPositionMeters( this GameObject go, Vector3 meters )\n\t\t=> go.WorldPosition = Units.ToInches( meters );\n\n\t/// <summary>Set this object's local position from metres.</summary>\n\tpublic static void SetLocalPositionMeters( this GameObject go, Vector3 meters )\n\t\t=> go.LocalPosition = Units.ToInches( meters );\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Code/Units.cs",
"FileName": "Units.cs",
"PackageType": "library",
"CodeKind": "Game",
"AssetVersionId": 338943,
"Code": "namespace Metrify;\npublic static class Units\n{\n\tpublic const float InchesToMeters = 0.0254f;\n\tpublic const float MetersToInches = 1f / InchesToMeters;\n\n\tpublic static float ToMeters( float inches ) => inches * InchesToMeters;\n\tpublic static float ToInches( float meters ) => meters * MetersToInches;\n\n\tpublic static Vector3 ToMeters( Vector3 inches ) => inches * InchesToMeters;\n\tpublic static Vector3 ToInches( Vector3 meters ) => meters * MetersToInches;\n}\n"
},
{
"Ident": "ali3nsystems.lib-metrify",
"Path": "Editor/MeterControlWidget.cs",
"FileName": "MeterControlWidget.cs",
"PackageType": "library",
"CodeKind": "Editor",
"AssetVersionId": 338943,
"Code": "using Editor;\nusing Sandbox;\n\nnamespace Metrify;\n\n/// <summary>\n/// Draws a [Meters] float in metres, with an \"m\" suffix label.\n/// </summary>\n[CustomEditor( typeof( float ), WithAllAttributes = new[] { typeof( MetersAttribute ) } )]\npublic sealed class MeterFloatControlWidget : ControlWidget\n{\n\tpublic override bool SupportsMultiEdit => true;\n\n\tprivate readonly FloatControlWidget _control;\n\n\tpublic MeterFloatControlWidget( SerializedProperty property ) : base( property )\n\t{\n\t\tHorizontalSizeMode = SizeMode.CanGrow | SizeMode.Expand;\n\n\t\tLayout = Layout.Row();\n\t\tLayout.Spacing = 2;\n\n\t\t_control = Layout.Add( new FloatControlWidget( new MeterFloatProperty( property ) )\n\t\t{\n\t\t\tLabel = \"m\",\n\t\t\tHighlightColor = Theme.Green,\n\t\t\tToolTip = \"Metres \u2014 stored as inches (s&box world units)\"\n\t\t}, 1 );\n\t}\n\n\tpublic override void StartEditing() => _control?.StartEditing();\n\n\tprotected override void OnPaint()\n\t{\n\t\t// child widget paints itself\n\t}\n\n\tprotected override void PaintUnder()\n\t{\n\t\t// nothing\n\t}\n}\n\n/// <summary>\n/// Draws a [Meters] Vector3 with each axis in metres.\n/// </summary>\n[CustomEditor( typeof( Vector3 ), WithAllAttributes = new[] { typeof( MetersAttribute ) } )]\npublic sealed class MeterVectorControlWidget : ControlWidget\n{\n\tpublic override bool SupportsMultiEdit => true;\n\n\tprivate FloatControlWidget _first;\n\n\tpublic MeterVectorControlWidget( SerializedProperty property ) : base( property )\n\t{\n\t\tHorizontalSizeMode = SizeMode.CanGrow | SizeMode.Expand;\n\n\t\tif ( !property.TryGetAsObject( out var obj ) )\n\t\t{\n\t\t\tLog.Warning( $\"[Meters] could not read {property.Name} as an object\" );\n\t\t\treturn;\n\t\t}\n\n\t\tLayout = Layout.Row();\n\t\tLayout.Spacing = 2;\n\n\t\t_first = AddAxis( obj, \"x\", Theme.Red, \"X\" );\n\t\tAddAxis( obj, \"y\", Theme.Green, \"Y\" );\n\t\tAddAxis( obj, \"z\", Theme.Blue, \"Z\" );\n\t}\n\n\tprivate FloatControlWidget AddAxis( SerializedObject obj, string name, Color color, string label )\n\t{\n\t\tvar axis = obj.GetProperty( name );\n\t\tif ( axis is null ) return null;\n\n\t\tvar control = Layout.Add( new FloatControlWidget( new MeterFloatProperty( axis ) )\n\t\t{\n\t\t\tLabel = label,\n\t\t\tHighlightColor = color,\n\t\t\tToolTip = \"Metres \u2014 stored as inches (s&box world units)\"\n\t\t}, 1 );\n\n\t\tcontrol.MinimumWidth = Theme.RowHeight;\n\t\tcontrol.HorizontalSizeMode = SizeMode.CanGrow | SizeMode.Expand;\n\n\t\treturn control;\n\t}\n\n\tpublic override void StartEditing() => _first?.StartEditing();\n\n\tprotected override void OnPaint()\n\t{\n\t\t// child widgets paint themselves\n\t}\n\n\tprotected override void PaintUnder()\n\t{\n\t\t// nothing\n\t}\n}\n"
}
]
}