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
3 changes: 2 additions & 1 deletion EVTCAnalytics/Events/BuffEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ namespace GW2Scratch.EVTCAnalytics.Events
/// Note that buffs are internally <see cref="Skill"/>s in the game.
/// </remarks>
public abstract class BuffEvent(long time, Agent agent, Skill buff, Agent sourceAgent)
: AgentEvent(time, agent)
: AgentEvent(time, agent), ISkillEvent
{
public Skill Buff { get; } = buff;
public Skill Skill { get => Buff; }
public Agent SourceAgent { get; internal set; } = sourceAgent;
}

Expand Down
2 changes: 1 addition & 1 deletion EVTCAnalytics/Events/DamageEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public abstract class DamageEvent(
bool isMoving,
bool isNinety,
bool isFlanking)
: Event(time)
: Event(time), ISkillEvent
{
public Skill Skill { get; } = skill;
public Agent Attacker { get; internal set; } = attacker;
Expand Down
14 changes: 12 additions & 2 deletions EVTCAnalytics/Events/SkillEvents.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
using GW2Scratch.EVTCAnalytics.Model.Agents;
using GW2Scratch.EVTCAnalytics.Model.Skills;
using GW2Scratch.EVTCAnalytics.Model;

namespace GW2Scratch.EVTCAnalytics.Events
{
/// <summary>
/// Any event that features a <see cref="Skill"/>
/// </summary>
/// <remarks>
/// Both <see cref="SkillCastEvent"/>s and <see cref="BuffEvent"/>s can contain <see cref="Skill"/>s
/// </remarks>
public interface ISkillEvent
{
public Skill Skill { get; }
}

/// <summary>
/// An event representing a <see cref="Skill"/> cast by an <see cref="Agent"/>.
/// </summary>
/// <remarks>
/// Internally, skill casts are significantly tied to their animations.
/// </remarks>
public abstract class SkillCastEvent(long time, Agent agent, Skill skill, int castingTimeMs)
: AgentEvent(time, agent)
: AgentEvent(time, agent), ISkillEvent
{
public Skill Skill { get; } = skill;
public int CastingTimeMs { get; } = castingTimeMs;
Expand Down
173 changes: 61 additions & 112 deletions EVTCInspector/EventContentFilterControl.cs
Original file line number Diff line number Diff line change
@@ -1,155 +1,104 @@
using System;
using System.Linq;
using Eto.Forms;
using GW2Scratch.EVTCAnalytics.Events;
using System;
using System.Linq;
using System.Linq.Expressions;

namespace GW2Scratch.EVTCInspector
{
public class EventContentFilterControl : Panel
{
private uint BuffId { get; set; }
private bool BuffIdEnabled { get; set; }
private uint BuffDamageId { get; set; }
private bool BuffDamageIdEnabled { get; set; }
private uint IdFilter { get; set; }
private bool IdFilterEnabled { get; set; }
private string NameFilter { get; set; }
private bool NameFilterEnabled { get; set; }

private readonly Control buffLayout;
private readonly Control buffDamageLayout;
private readonly DynamicLayout idLayout;
private readonly DynamicLayout nameLayout;

public EventContentFilterControl()
{
buffLayout = ConstructBuffLayout();
buffDamageLayout = ConstructBuffDamageLayout();
idLayout = ConstructLayout(
() => IdFilter, x => IdFilter = x,
() => IdFilterEnabled, x => IdFilterEnabled = x ?? false,
"Filter events by Skill ID",
"Skill ID"
);
nameLayout = ConstructLayout(
() => NameFilter, x => NameFilter = x,
() => NameFilterEnabled, x => NameFilterEnabled = x ?? false,
"Filter events by Skill Name",
"Skill Name"
);

var layout = new DynamicLayout();
layout.BeginVertical();
{
layout.Add(buffLayout);
layout.Add(buffDamageLayout);
layout.Add(idLayout);
layout.Add(nameLayout);
}
layout.EndVertical();
Content = layout;
}

public void UpdateContent(EventListControl eventList)
private static DynamicLayout ConstructLayout<TValue>(
Expression<Func<TValue>> valueGetterExpr, Action<TValue> valueSetter,
Expression<Func<bool?>> enabledGetterExpr, Action<bool?> enabledSetter,
string groupTitle, string labelText)
{
var selectedTypes = eventList.TypeFilters.Where(x => x.Checked.HasValue && x.Checked.Value).ToArray();
if (selectedTypes.Length == 0)
{
return;
}

var commonAncestor = selectedTypes.First().Type;
foreach (var type in selectedTypes)
{
commonAncestor = GetClosestType(commonAncestor, type.Type);
}
var valueGetter = valueGetterExpr.Compile();
var enabledGetter = enabledGetterExpr.Compile();

buffLayout.Visible = typeof(BuffEvent).IsAssignableFrom(commonAncestor);
buffDamageLayout.Visible = typeof(BuffDamageEvent).IsAssignableFrom(commonAncestor);
Control valueControl;

/*
else if (typeof(AgentEvent).IsAssignableFrom(commonAncestor))
if (typeof(TValue) == typeof(uint))
{
var filterAgentRadioButton = new RadioButton {Text = "Exact Agent"};
var filterAgentDataRadioButton = new RadioButton(filterAgentRadioButton) {Text = "Agent data"};
var agentsDropDown = new DropDown
{
DataStore = agents,
ItemTextBinding = new DelegateBinding<Agent, string>(x => $"{x.Name} ({x.Address})")
};

var filterLayout = new DynamicLayout();
filterLayout.BeginHorizontal();
filterLayout.BeginGroup("Agent filter");
filterLayout.BeginVertical(spacing: new Size(5, 5));
filterLayout.AddRow(filterAgentRadioButton, null, agentsDropDown);
filterLayout.AddRow(filterAgentDataRadioButton, new CheckBox {Text = "Name"}, new TextBox {Text = ""});
filterLayout.AddRow(null, new CheckBox {Text = "Type"},
new DropDown {DataStore = new[] {"Player", "NPC", "Gadget"}});
filterLayout.AddRow(null);
filterLayout.EndVertical();
filterLayout.EndGroup();
filterLayout.EndHorizontal();
filterPanel.Content = filterLayout;
}
*/
}

private Control ConstructBuffLayout()
{
var buffIdTextBox = new NumericMaskedTextBox<uint> {Value = 0};
buffIdTextBox.ValueBinding.Bind(() => BuffId, x => BuffId = x);
// Numberic filter
var numericTextBox = new NumericMaskedTextBox<TValue>();
numericTextBox.ValueBinding.Bind(valueGetter, valueSetter);

var buffIdCheckbox = new CheckBox {Checked = false};
buffIdCheckbox.CheckedBinding.Bind(() => BuffIdEnabled, x => BuffIdEnabled = x ?? false);

var filterLayout = new DynamicLayout();
filterLayout.BeginHorizontal();
{
filterLayout.BeginGroup("Buff");
{
filterLayout.AddRow("Buff ID", buffIdTextBox, buffIdCheckbox, null);
}
filterLayout.EndGroup();
filterLayout.AddRow(null);
valueControl = numericTextBox;
}
filterLayout.EndHorizontal();
return filterLayout;
}

private Control ConstructBuffDamageLayout()
{
var buffIdTextBox = new NumericMaskedTextBox<uint> {Value = 0};
buffIdTextBox.ValueBinding.Bind(() => BuffDamageId, x => BuffDamageId = x);
else
{
// Text filter
var textBox = new TextBox();

var buffIdCheckbox = new CheckBox {Checked = false};
buffIdCheckbox.CheckedBinding.Bind(() => BuffDamageIdEnabled, x => BuffDamageIdEnabled = x ?? false);
textBox.TextBinding.Bind(
() => (string) (object) valueGetter(),
s => valueSetter((TValue) (object) s)
);

var filterLayout = new DynamicLayout();
filterLayout.BeginHorizontal();
{
filterLayout.BeginGroup("Buff damage");
{
filterLayout.AddRow("Buff ID", buffIdTextBox, buffIdCheckbox, null);
}
filterLayout.EndGroup();
filterLayout.AddRow(null);
valueControl = textBox;
}
filterLayout.EndHorizontal();
return filterLayout;
}

public bool FilterEvent(Event e)
{
if (e is BuffEvent buffEvent)
{
if (BuffIdEnabled)
{
return buffEvent.Buff.Id == BuffId;
}
}
var enabledCheckbox = new CheckBox();
enabledCheckbox.CheckedBinding.Bind(enabledGetter, enabledSetter);

if (e is BuffDamageEvent buffDamage)
var layout = new DynamicLayout();
layout.BeginHorizontal();
{
if (BuffDamageIdEnabled)
layout.BeginGroup(groupTitle);
{
return buffDamage.Skill.Id == BuffDamageId;
layout.AddRow(labelText, valueControl, enabledCheckbox, null);
}
layout.EndGroup();
layout.AddRow(null);
}
layout.EndHorizontal();

return true;
return layout;
}

private Type GetClosestType(Type a, Type b)
public bool FilterEvent(Event e)
{
while (a != null)
{
if (a.IsAssignableFrom(b))
return a;
bool anyFilterActive = IdFilterEnabled || NameFilterEnabled;
if (e is not ISkillEvent ev) return !anyFilterActive;

a = a.BaseType;
}
if (IdFilterEnabled && ev.Skill.Id == IdFilter) return true;
if (NameFilterEnabled && ev.Skill.Name.Contains(NameFilter, StringComparison.CurrentCultureIgnoreCase)) return true;

return null;
return !anyFilterActive;
}
}
}
2 changes: 0 additions & 2 deletions EVTCInspector/EventListControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,6 @@ private void InvalidateTree()
private void ApplyFilters()
{
((FilterCollection<Event>) eventGridView.DataStore).Refresh();

contentFilters.UpdateContent(this);
}

private bool FilterByEventType(Event e)
Expand Down
Loading