-
-
Save kg/6a6ba42d5019b546858a2b18751de019 to your computer and use it in GitHub Desktop.
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
internal class VectorEditModal : ModalDialog<VectorEditArguments, Vector4> { | |
public readonly Game Game; | |
private readonly Func<IGlyphSource> GlyphSourceProvider, | |
GlyphSourceProviderSmall; | |
public Canvas Orb; | |
public Vector4 Value; | |
private Vector4? ValueRange; | |
private float UserScale = 1.0f, ValueIncrement = 0.1f; | |
public VectorEditModal (Game game, VectorEditArguments parameters) : base(parameters) { | |
Game = game; | |
GlyphSourceProvider = Game.GetFontProvider(0.8f, Game.FontStyle.Regular); | |
GlyphSourceProviderSmall = Game.GetFontProvider(0.7f, Game.FontStyle.Regular); | |
DynamicContents = VectorEditor_Content; | |
Title = "Edit Vector"; | |
CancelResult = parameters.DefaultValue; | |
SetValue(parameters.DefaultValue, false); | |
if (Parameters.MinValues.HasValue && Parameters.MaxValues.HasValue) { | |
var valueRange = Parameters.MaxValues.Value - Parameters.MinValues.Value; | |
ValueRange = valueRange; | |
var avg = (Math.Abs(valueRange.X) + Math.Abs(valueRange.Y) + | |
Math.Abs(valueRange.Z) + Math.Abs(valueRange.W)) / 4f; | |
if (avg >= 5000) | |
ValueIncrement = 10.0f; | |
else if (avg >= 1000) | |
ValueIncrement = 5.0f; | |
else if (avg >= 100) | |
ValueIncrement = 1.0f; | |
else if (avg >= 10) | |
ValueIncrement = 0.1f; | |
else | |
ValueIncrement = 0.05f; | |
} | |
BackgroundFadeLevel = 0.2f; | |
} | |
private void VectorEditor_Content (ref ContainerBuilder builder) { | |
const float maxWidth = 150f, | |
orbSize = 128f; | |
builder.DefaultGlyphSourceProvider = GlyphSourceProvider; | |
var cflags = ControlFlags.Container_Prevent_Crush | ControlFlags.Container_Row | ControlFlags.Container_Break_Allow | ControlFlags.Container_Align_Start; | |
builder.New<Canvas>() | |
.SetSize(orbSize, orbSize) | |
.StoreInstance(ref Orb); | |
if (!Orb.HasPaintHandler) { | |
Orb.OnPaint += Orb_Paint; | |
Orb.AddEventListener<MouseEventArgs>(null, Orb_OnMouseEvent); | |
} | |
ContainerBuilder columns = builder.NewGroup(containerFlags: cflags), | |
leftCol = columns.NewGroup(layoutFlags: ControlFlags.Layout_Fill, containerFlags: cflags), | |
rightCol = columns.NewGroup(layoutFlags: ControlFlags.Layout_Fill, containerFlags: cflags); | |
rightCol.New<ParameterEditor<float>>(tooltip: "Value for the operator buttons to the right") | |
.SetDescription("rhs") | |
.SetRange<float>(-4f, 16f, false) | |
.SetMaximumSize(width: maxWidth) | |
.SetIncrement(0.1f) | |
.SetForceBreak(true) | |
.Value(ref UserScale, out bool userScaleChanged); | |
if (rightCol.Text<Button>("+", tooltip: "Add") | |
.GetEvent(UIEvents.Click)) | |
ScaleValue(UserScale); | |
if (rightCol.Text<Button>("×", tooltip: "Multiply") | |
.GetEvent(UIEvents.Click)) | |
ScaleValue(UserScale); | |
if (rightCol.Text<Button>("÷", tooltip: "Divide") | |
.GetEvent(UIEvents.Click)) | |
ScaleValue(1.0f / UserScale); | |
if (rightCol.Text<Button>("0", tooltip: "Set value to 0") | |
.SetForceBreak(true) | |
.GetEvent(UIEvents.Click)) | |
SetValue(Vector4.Zero, true); | |
if (rightCol.Text<Button>("1", tooltip: "Set value to 1") | |
.GetEvent(UIEvents.Click)) | |
SetValue(Vector4.One, true); | |
if (rightCol.Text<Button>("Normalize", tooltip: "Normalize the vector") | |
.GetEvent(UIEvents.Click)) | |
NormalizeValue(); | |
bool changedX, changedY, changedZ = false, changedW = false; | |
leftCol.New<ParameterEditor<float>>() | |
.SetForceBreak(true) | |
.SetDescription("X") | |
.SetMaximumSize(width: maxWidth) | |
.SetRange(Parameters.MinValues?.X, Parameters.MaxValues?.X, false) | |
.SetIncrement(ValueIncrement) | |
.Value(ref Value.X, out changedX); | |
leftCol.New<ParameterEditor<float>>() | |
.SetForceBreak(true) | |
.SetDescription("Y") | |
.SetMaximumSize(width: maxWidth) | |
.SetRange(Parameters.MinValues?.Y, Parameters.MaxValues?.Y, false) | |
.SetIncrement(ValueIncrement) | |
.Value(ref Value.Y, out changedY); | |
if (Parameters.ElementCount > 2) | |
leftCol.New<ParameterEditor<float>>() | |
.SetForceBreak(true) | |
.SetDescription("Z") | |
.SetMaximumSize(width: maxWidth) | |
.SetRange(Parameters.MinValues?.Z, Parameters.MaxValues?.Z, false) | |
.SetIncrement(ValueIncrement) | |
.Value(ref Value.Z, out changedZ); | |
if (Parameters.ElementCount > 3) | |
leftCol.New<ParameterEditor<float>>() | |
.SetForceBreak(true) | |
.SetDescription("W") | |
.SetMaximumSize(width: maxWidth) | |
.SetRange(Parameters.MinValues?.W, Parameters.MaxValues?.W, false) | |
.SetIncrement(ValueIncrement) | |
.Value(ref Value.W, out changedW); | |
leftCol.Spacer(true); | |
// FIXME: On manual change, expand min/max values so the orb is more useful | |
if (changedX || changedY || changedZ || changedW) | |
SetValue(Value, true); | |
var buttons = builder.NewGroup(containerFlags: ControlFlags.Container_Row | ControlFlags.Container_Align_Middle); | |
buttons.Properties.SetForceBreak(true); | |
AcceptControl = buttons.Text<Button>("OK"); | |
CancelControl = buttons.Text<Button>("Cancel"); | |
} | |
private void Orb_OnMouseEvent (IEventInfo<MouseEventArgs> e, MouseEventArgs arguments) { | |
if ((arguments.Buttons & MouseButtons.Left) == default) | |
return; | |
Vector4 minValue = Parameters.MinValues ?? new Vector4(-1), | |
maxValue = Parameters.MaxValues ?? new Vector4(1), | |
newValue = new Vector4( | |
Arithmetic.Lerp(minValue.X, maxValue.X, arguments.LocalPosition.X / arguments.ContentBox.Width), | |
Arithmetic.Lerp(minValue.Y, maxValue.Y, arguments.LocalPosition.Y / arguments.ContentBox.Height), | |
0f, 0f | |
); | |
SetValue(newValue, true); | |
e.Consume(); | |
} | |
private void Orb_Paint (ref UIOperationContext context, ref ImperativeRenderer renderer, DecorationSettings settings) { | |
settings.ContentBox.SnapAndInset(out var a, out var b); | |
renderer.RasterizeRectangle(a, b, 3f, Color.Black * 0.2f); | |
renderer.Layer += 1; | |
var r = (Math.Min(b.X - a.X, b.Y - a.Y) / 2f) - 1.5f; | |
var center = (a + b) / 2f; | |
renderer.RasterizeEllipse(center, new Vector2(1.5f), Color.White * 0.5f); | |
renderer.RasterizeEllipse(center, new Vector2(r), 1.5f, Color.Transparent, Color.Transparent, Color.White * 0.5f); | |
// TODO: ValueRange | |
var pos = new Vector3(Value.X, Value.Y, Value.Z); | |
var norm = pos; | |
norm.Normalize(); | |
Vector4 minValue = Parameters.MinValues ?? new Vector4(-1), | |
maxValue = Parameters.MaxValues ?? new Vector4(1), | |
range = maxValue - minValue; | |
Vector2 norm2 = new Vector2( | |
Arithmetic.Lerp(a.X + 2f, b.X - 2f, (norm.X + 1) / 2f), | |
Arithmetic.Lerp(a.Y + 2f, b.Y - 2f, (norm.Y + 1) / 2f) | |
), | |
pos2 = new Vector2( | |
Arithmetic.Lerp(a.X, b.X, Arithmetic.Saturate((pos.X - minValue.X) / range.X)), | |
Arithmetic.Lerp(a.Y, b.Y, Arithmetic.Saturate((pos.Y - minValue.Y) / range.Y)) | |
); | |
var radius2 = Arithmetic.Clamp(1.0f + norm.Z, 0.2f, 2.0f); | |
renderer.RasterizeLineSegment(center, norm2, 1.0f, radius2, 0f, Color.White * 0.5f, Color.White * 0.7f, Color.Transparent); | |
renderer.Layer += 1; | |
renderer.RasterizeEllipse(pos2, new Vector2(3.33f), 1.33f, Color.White, Color.White, Color.Black); | |
} | |
protected Vector2 V2 => new Vector2(Value.X, Value.Y); | |
protected Vector3 V3 => new Vector3(Value.X, Value.Y, Value.Z); | |
private void NormalizeValue () { | |
switch (Parameters.ElementCount) { | |
case 2: | |
var temp = V2; | |
temp.Normalize(); | |
Value = new Vector4(temp, 0, 0); | |
break; | |
case 3: | |
var temp3 = V3; | |
temp3.Normalize(); | |
Value = new Vector4(temp3, 0); | |
break; | |
default: | |
Value.Normalize(); | |
break; | |
} | |
SetValue(Value, true); | |
} | |
private void ScaleValue (float scale) { | |
SetValue(Value * scale, true); | |
} | |
public void SetValue (Vector4 value, bool fireEvent) { | |
if (Parameters.ElementCount < 4) | |
value.W = 0; | |
if (Parameters.ElementCount < 3) | |
value.Z = 0; | |
Value = value; | |
AcceptResult = value; | |
if (fireEvent && (Parameters.OnValueChanged != null)) | |
Parameters.OnValueChanged(AcceptResult); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment