Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using fluXis.Graphics.Containers;
using fluXis.Graphics.Sprites.Icons;
using fluXis.Graphics.Sprites.Outline;
Expand Down Expand Up @@ -145,10 +144,14 @@ protected override bool OnClick(ClickEvent e)
CurrentValue = Animation.ValueStart,
OnValueChanged = t =>
{
if (validate(t.Text)) Animation.ValueStart = t.Text;
if (validate(t.Text, out var parsed)) Animation.ValueStart = parsed;
else t.NotifyError();

map.Update(Animation);
},
OnCommit = t =>
{
if (t is not null && validate(t.Text, out var parsed)) t.Text = parsed;
else { t.Text = Animation.ValueStart; t.NotifyError(); }
}
},
new EditorVariableTextBox
Expand All @@ -157,36 +160,62 @@ protected override bool OnClick(ClickEvent e)
CurrentValue = Animation.ValueEnd,
OnValueChanged = t =>
{
if (validate(t.Text)) Animation.ValueEnd = t.Text;
if (validate(t.Text, out var parsed)) Animation.ValueEnd = parsed;
else t.NotifyError();

map.Update(Animation);
},
OnCommit = t =>
{
if (t is not null && validate(t.Text, out var parsed)) t.Text = parsed;
else { t.Text = Animation.ValueEnd; t.NotifyError(); }
}
},
new EditorVariableEasing<StoryboardAnimation>(map, Animation),
}
}
};

private bool validate(string input)
private Type getAnimPrimitiveType() => Animation.Type switch
{
switch (Animation.Type)
StoryboardAnimationType.MoveX or
StoryboardAnimationType.MoveY or
StoryboardAnimationType.Scale or
StoryboardAnimationType.Width or
StoryboardAnimationType.Height or
StoryboardAnimationType.Rotate or
StoryboardAnimationType.Fade or
StoryboardAnimationType.Border => typeof(float),
_ => null
};

private bool validate(string input, out string outStr)
{
outStr = input;

var evalType = getAnimPrimitiveType();

if (evalType is not null)
{
case StoryboardAnimationType.MoveX:
case StoryboardAnimationType.MoveY:
case StoryboardAnimationType.Scale:
case StoryboardAnimationType.Width:
case StoryboardAnimationType.Height:
case StoryboardAnimationType.Rotate:
case StoryboardAnimationType.Fade:
case StoryboardAnimationType.Border:
return input.TryParseFloatInvariant(out _);
if (!input.TryEvaluateTo(evalType, out var result))
return false;

outStr = result.ToString();
return true;
}

switch (Animation.Type)
{
case StoryboardAnimationType.ScaleVector:
var split = input.Split(",");
if (split.Length != 2) return false;

return split.All(x => x.TryParseFloatInvariant(out _));
if (!split[0].TryEvaluateTo(typeof(float), out var x) ||
!split[1].TryEvaluateTo(typeof(float), out var y))
return false;

outStr = $"{x},{y}";
return true;

case StoryboardAnimationType.Color:
return Colour4.TryParseHex(input, out _);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,34 +469,28 @@ void showError(string text, [CanBeNull] Exception e)
}
else if (parameter.Type == typeof(int))
{
drawables.Add(new EditorVariableTextBox
drawables.Add(new EditorVariableNumber<int>
{
Text = parameter.Title,
CurrentValue = item.GetParameter(parameter.Key, parameter.GetDefaultFallback<int>()).ToString(),
OnValueChanged = box =>
CurrentValue = item.GetParameter(parameter.Key, parameter.GetDefaultFallback<int>()),
OnValueChanged = v =>
{
if (box.Text.TryParseIntInvariant(out var result))
item.Parameters[parameter.Key] = result;
else
box.NotifyError();

item.Parameters[parameter.Key] = v;
map.Update(item);
}
});
}
else if (parameter.Type == typeof(float))
{
drawables.Add(new EditorVariableTextBox
drawables.Add(new EditorVariableNumber<float>
{
Text = parameter.Title,
CurrentValue = item.GetParameter(parameter.Key, parameter.GetDefaultFallback<float>()).ToStringInvariant(),
OnValueChanged = box =>
CurrentValue = item.GetParameter(parameter.Key, parameter.GetDefaultFallback<float>()),
Step = 0.1f,
Formatting = "G7",
OnValueChanged = v =>
{
if (box.Text.TryParseFloatInvariant(out var result))
item.Parameters[parameter.Key] = result;
else
box.NotifyError();

item.Parameters[parameter.Key] = v;
map.Update(item);
}
});
Expand Down
38 changes: 26 additions & 12 deletions fluXis/Screens/Edit/UI/Variable/EditorVariableNumber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Globalization;
using System.Numerics;
using fluXis.Graphics.UserInterface.Text;
using fluXis.Utils;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
Expand All @@ -20,12 +21,14 @@ public partial class EditorVariableNumber<T> : EditorVariableTextBox, IHasCursor
// hide
public new Action<FluXisTextBox> OnCommit { get; private set; }

public override Type CommitEvalType => typeof(T);

public new T CurrentValue
{
set
{
updateValue(value, false);
updateText();
UpdateValue(value, false);
UpdateText();
}
}

Expand All @@ -49,13 +52,13 @@ public EditorVariableNumber()
{
base.OnValueChanged += t =>
{
if (T.TryParse(t.Text, CultureInfo.InvariantCulture, out var val))
updateValue(val, true);
if (t.Text.TryEvaluateTo<T>(out var val))
UpdateValue(val, true);
else
t.NotifyError();
};

base.OnCommit += _ => updateText();
base.OnCommit += _ => UpdateText();
}

[BackgroundDependencyLoader]
Expand Down Expand Up @@ -102,11 +105,11 @@ protected override void OnDrag(DragEvent e)
lastSampleTime = Time.Current;
}

updateValue(bind.Value += change, true);
updateText();
UpdateValue(bind.Value += change, true);
UpdateText();
}

private void updateValue(T newVal, bool notify)
protected void UpdateValue(T newVal, bool notify)
{
if (Min != null)
newVal = T.Max(Min!.Value, newVal);
Expand All @@ -119,12 +122,23 @@ private void updateValue(T newVal, bool notify)
OnValueChanged?.Invoke(bind.Value);
}

private void updateText()
protected void UpdateText()
{
var text = bind.Value.ToString(Formatting, CultureInfo.InvariantCulture);
if (TextBox == null)
Schedule(() => TextBox!.Text = text);
Schedule(() => TextBox.Text = text);
}

protected override void EvalCommit(FluXisTextBox box)
{
if (!box.IsAlive || box is null) return;

if (box.Text.TryEvaluateTo<T>(out var result))
{
UpdateValue(result, true);
}
else
TextBox.Text = text;
box.NotifyError();

UpdateText();
}
}
21 changes: 21 additions & 0 deletions fluXis/Screens/Edit/UI/Variable/EditorVariableTextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using fluXis.Graphics.Sprites.Text;
using fluXis.Graphics.UserInterface.Color;
using fluXis.Graphics.UserInterface.Text;
using fluXis.Utils;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
Expand All @@ -15,6 +16,8 @@ public partial class EditorVariableTextBox : EditorVariableBase
public Action<FluXisTextBox> OnValueChanged { get; set; }
public Action<FluXisTextBox> OnCommit { get; set; }

public virtual Type CommitEvalType { get; set; } = null;

public string ExtraText { get; init; }
public int TextBoxWidth { get; init; } = 210;

Expand Down Expand Up @@ -71,6 +74,7 @@ private void load()
OnCommitAction = () =>
{
OnValueChanged?.Invoke(TextBox);
EvalCommit(TextBox);
OnCommit?.Invoke(TextBox);
}
},
Expand All @@ -94,6 +98,23 @@ private void load()
UpdateLeftTextFlow(leftText);
}

protected virtual void EvalCommit(FluXisTextBox box)
{
if (CommitEvalType is null || !box.IsAlive || box is null)
return;

if (box.Text.TryEvaluateTo(CommitEvalType, out var result))
box.Text = result.ToString();
else
box.NotifyError();
}

protected virtual Drawable CreateExtraButton() => Empty().With(d => d.Alpha = 0);
protected virtual void UpdateLeftTextFlow(FillFlowContainer flow) { }

protected override void Dispose(bool isDisposing)
{
if (isDisposing) CommitEvalType = null;
base.Dispose(isDisposing);
}
}
56 changes: 52 additions & 4 deletions fluXis/Utils/StringUtils.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Text;
using NCalc;

namespace fluXis.Utils;

Expand Down Expand Up @@ -48,17 +50,17 @@ public static string TruncateBytes(string value, int maxBytes)
{
if (string.IsNullOrEmpty(value))
return value ?? "";

var encoding = Encoding.UTF8;
if (encoding.GetByteCount(value) <= maxBytes)
return value;

var bytes = encoding.GetBytes(value);
var truncated = encoding.GetString(bytes, 0, Math.Min(bytes.Length, maxBytes));

while (encoding.GetByteCount(truncated) > maxBytes && truncated.Length > 0)
truncated = truncated[..^1];

return truncated;
}

Expand Down Expand Up @@ -132,4 +134,50 @@ public static string ToCamelCase(string str)

return result.ToString();
}

public static bool TryEvaluate<T>(string input, out T result) where T : INumber<T>
{
if (TryEvaluate(input, typeof(T), out var raw))
{
result = (T)raw;
return true;
}

result = T.Zero;
return false;
}

public static bool TryEvaluate(string input, Type type, out object result)
{
result = null;

try
{
var expr = new Expression(input, CultureInfo.InvariantCulture);

if (expr.HasErrors())
return false;

var raw = expr.Evaluate();

result = Convert.ChangeType(raw, type, CultureInfo.InvariantCulture);

switch (result)
{
case double d when !double.IsFinite(d):
case float f when !float.IsFinite(f):
return false;

default:
return true;
}
}
catch
{
return false;
}
}

public static bool TryEvaluateTo<T>(this string value, out T result) where T : INumber<T> => TryEvaluate(value, out result);
public static bool TryEvaluateTo(this string value, Type type, out object result) => TryEvaluate(value, type, out result);
}
1 change: 1 addition & 0 deletions fluXis/fluXis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="NCalcSync" Version="5.12.0" />
<PackageReference Include="NLua" Version="1.7.5" />
<PackageReference Include="flustix.Midori" Version="2025.1028.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
Expand Down