Skip to content

Commit

Permalink
Merge branch 'feat.more-keybinds' of https://github.com/zacharied/Ong…
Browse files Browse the repository at this point in the history
…ekiFumenEditor into batch_mode
  • Loading branch information
MikiraSora committed Oct 26, 2024
2 parents ea80db9 + 910b4b6 commit 330757e
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using OngekiFumenEditor.Properties;
using OngekiFumenEditor.UI.KeyBinding.Input;
using OngekiFumenEditor.Utils;
using Xceed.Wpf.Toolkit.Core.Input;
using EventTrigger = Microsoft.Xaml.Behaviors.EventTrigger;
using TriggerAction = Microsoft.Xaml.Behaviors.TriggerAction;
using TriggerBase = Microsoft.Xaml.Behaviors.TriggerBase;
Expand All @@ -27,7 +28,7 @@ namespace OngekiFumenEditor.Modules.FumenVisualEditor.Behaviors.BatchMode;

public class BatchModeBehavior : Behavior<FumenVisualEditorView>
{
private static readonly ImmutableDictionary<KeyBindingDefinition, BatchModeSubmode> CommandDefinitions =
private static readonly ImmutableDictionary<KeyBindingDefinition, Type> CommandDefinitions =
new Dictionary<KeyBindingDefinition, Type>
{
[KeyBindingDefinitions.KBD_Batch_ModeWallLeft] = typeof(BatchModeInputWallLeft),
Expand All @@ -45,7 +46,7 @@ public class BatchModeBehavior : Behavior<FumenVisualEditorView>
[KeyBindingDefinitions.KBD_Batch_ModeFilterLanes] = typeof(BatchModeFilterLanes),
[KeyBindingDefinitions.KBD_Batch_ModeFilterDockableObjects] = typeof(BatchModeFilterDockableObjects),
[KeyBindingDefinitions.KBD_Batch_ModeFilterFloatingObjects] = typeof(BatchModeFilterFloatingObjects),
}.ToImmutableDictionary(kv => kv.Key, kv => (BatchModeSubmode)Activator.CreateInstance(kv.Value));
}.ToImmutableDictionary();

private static readonly ImmutableDictionary<string, Func<BatchModeBehavior, TriggerAction>> ClickTriggers =
new Dictionary<string, Func<BatchModeBehavior, TriggerAction>>()
Expand Down Expand Up @@ -81,7 +82,7 @@ protected override void OnAttached()

// Create brush key triggers on the FumenVisualEditorView.
// Temporarily delete existing ones that clash with brush keys.
foreach (var (key, submode) in CommandDefinitions) {
foreach (var (key, submodeType) in CommandDefinitions) {
var existingTriggers = triggerCollection.Where(t =>
t is ActionMessageKeyBinding am && am.Definition.Key == key.Key &&
am.Definition.Modifiers == key.Modifiers);
Expand All @@ -91,7 +92,7 @@ protected override void OnAttached()
foreach (var mod in new[] { ModifierKeys.None, ModifierKeys.Shift }) {
// It's useful to hold down shift as we place multiple lanes, so bind everything to Shift+ as well.
var newTrigger = new KeyTrigger() { Key = key.Key, Modifiers = mod };
newTrigger.Actions.Add(new ChangePropertyAction() { TargetObject = this, PropertyName = nameof(CurrentSubmode), Value = submode });
newTrigger.Actions.Add(new ChangePropertyAction() { TargetObject = this, PropertyName = nameof(CurrentSubmode), Value = Activator.CreateInstance(submodeType) });
triggerCollection.Add(newTrigger);
NewKeyTriggers.Add(newTrigger);
}
Expand Down Expand Up @@ -140,6 +141,10 @@ protected override void OnDetaching()
GeneratedClickTriggerActions.Clear();

AssociatedObject.KeyDown -= ConsumeAlt;

if (AssociatedObject.DataContext is FumenVisualEditorViewModel edtior) {
edtior.SelectRegionType = SelectRegionType.Select;
}
}

#region Mouse handling
Expand Down Expand Up @@ -173,11 +178,13 @@ private void MouseDown(MouseButtonEventArgs args)

if (args.ChangedButton == MouseButton.Left) {
// In all sub-modes, Alt forces normal mouse behavior
if ((Keyboard.Modifiers & ModifierKeys.Alt) > 0) {
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt)) {
editor.SelectRegionType = SelectRegionType.Select;
lastLeftClickWasAltClick = true;
editor.SelectionStartPosition = cursor.ToSystemNumericsVector2();
if ((Keyboard.Modifiers & ModifierKeys.Control) > 0) {
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control)) {
editor.SelectRegionType = SelectRegionType.SelectFiltered;
editor.SelectionVisibility = Visibility.Visible;
}
return;
}
Expand All @@ -192,13 +199,13 @@ private void MouseDown(MouseButtonEventArgs args)
args.Handled = true;
} else if (args.ChangedButton == MouseButton.Right) {
editor.SelectionStartPosition = cursor.ToSystemNumericsVector2();
if ((Keyboard.Modifiers & ModifierKeys.Alt) == 0) {
editor.SelectRegionType = SelectRegionType.DeleteFiltered;
}
else {
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt)) {
lastRightClickWasAltClick = true;
editor.SelectRegionType = SelectRegionType.Delete;
}
else {
editor.SelectRegionType = SelectRegionType.DeleteFiltered;
}

args.Handled = true;
}
Expand All @@ -211,14 +218,43 @@ private void MouseUp(MouseButtonEventArgs args)
return;

if (args.ChangedButton == MouseButton.Left) {
if (editor.IsRangeSelecting) {
// Selection mode
Func<OngekiObjectBase, bool> filterFunc = null;
if (editor.SelectRegionType == SelectRegionType.SelectFiltered && CurrentSubmode is BatchModeFilterSubmode filterSubmode) {
filterFunc = filterSubmode.FilterFunction;
} else if (editor.SelectRegionType == SelectRegionType.SelectFiltered && CurrentSubmode is BatchModeSingleInputSubmode singleInputSubmode) {
filterFunc = o => o.GetType() == singleInputSubmode.ObjectType || o.GetType().IsSubclassOf(singleInputSubmode.ObjectType);
}

if (filterFunc != null) {
editor.SelectionVisibility = Visibility.Hidden;
PerformFilterSelect(filterFunc);
args.Handled = true;
}

editor.SelectRegionType = SelectRegionType.Select;
// otherwise fall through to FumenVisualEditorViewModel click handler
}

if (!lastLeftClickWasAltClick) {
// Can hold alt while releasing to "cancel" the left click
if ((Keyboard.Modifiers & ModifierKeys.Alt) == 0) {
if (CurrentSubmode is BatchModeInputSubmode inputSubmode)
PerformBrush(inputSubmode);
if (CurrentSubmode is BatchModeInputSubmode inputSubmode) {
if (inputSubmode is BatchModeSingleInputSubmode singleInputSubmode
&& editor.GetHits().Where(kv =>
kv.Value.Contains(editor.CurrentCursorPosition!.Value) &&
singleInputSubmode.ObjectType.IsInstanceOfType(kv.Key)).Select(kv => kv.Key)
.FirstOrDefault() is { } hit) {
editor.NotifyObjectClicked(hit);
}
else {
PerformBrush(inputSubmode);
}
}
else if (CurrentSubmode is BatchModeFilterSubmode filterSubmode && editor.IsRangeSelecting) {
editor.SelectionVisibility = Visibility.Hidden;
PerformFilterSelect(filterSubmode);
PerformFilterSelect(filterSubmode.FilterFunction);
}
}
args.Handled = true;
Expand All @@ -243,13 +279,12 @@ private void MouseUp(MouseButtonEventArgs args)
}
}

editor.SelectRegionType = SelectRegionType.Select;
editor.SelectionVisibility = Visibility.Hidden;
}
else {
lastRightClickWasAltClick = false;
if (editor.IsRangeSelecting) {
PerformRemoveGroup(null, "objects");
PerformRemoveGroup(null, Resources.Objects);
}
}

Expand All @@ -276,10 +311,14 @@ private void PerformBrush(BatchModeInputSubmode submode)
ongekiObjects = submode.GenerateObject().ToImmutableList();

if (ongekiObjects.Count == 0) {
if (submode is BatchModeInputClipboard)
editor.ToastNotify(Resources.CannotBatchInputClipboardEmpty);
return;
}

if (ongekiObjects.Count > 1) {
if (submode is BatchModeInputClipboard)
editor.ToastNotify(Resources.CannotBatchInputClipboardNotBrushable);
Log.LogWarn("Multiple object placement is currently not supported");
return;
}
Expand Down Expand Up @@ -318,10 +357,15 @@ void Undo()
}
}

private void PerformFilterSelect(BatchModeFilterSubmode submode)
// TODO Refactor into `SelectionBox` class or something
private void PerformFilterSelect(Func<OngekiObjectBase, bool> filterFunction)
{
var editor = (FumenVisualEditorViewModel)AssociatedObject.DataContext;
var hits = editor.GetRangeObjects().Where(o => submode.FilterFunction(o)).ToList();
var hits = editor.GetRangeObjects().Where(filterFunction).ToList();

if (!Keyboard.Modifiers.HasFlag(ModifierKeys.Shift)) {
editor.ClearSelection();
}

foreach (var hit in hits) {
if (hit is OngekiMovableObjectBase selectable)
Expand Down Expand Up @@ -403,7 +447,7 @@ private static void ConsumeAlt(object sender, KeyEventArgs e)

#region Dependency property

public static readonly DependencyProperty CurrentSubmodeProperty = DependencyProperty.RegisterAttached(nameof(CurrentSubmode), typeof(BatchModeSubmode), typeof(BatchModeBehavior), new PropertyMetadata(CommandDefinitions[KeyBindingDefinitions.KBD_Batch_ModeClipboard]));
public static readonly DependencyProperty CurrentSubmodeProperty = DependencyProperty.RegisterAttached(nameof(CurrentSubmode), typeof(BatchModeSubmode), typeof(BatchModeBehavior), new PropertyMetadata(Activator.CreateInstance(CommandDefinitions[KeyBindingDefinitions.KBD_Batch_ModeClipboard])));

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using OngekiFumenEditor.Base.OngekiObjects.Lane.Base;
using OngekiFumenEditor.Base.OngekiObjects.Wall;
using OngekiFumenEditor.Modules.FumenVisualEditor.Kernel;
using OngekiFumenEditor.Properties;

namespace OngekiFumenEditor.Modules.FumenVisualEditor.Behaviors.BatchMode;

Expand Down Expand Up @@ -38,7 +39,7 @@ public abstract class BatchModeInputSubmode : BatchModeSubmode
public virtual BatchModeObjectModificationAction? ModifyObjectCtrl { get; } = null;
public virtual BatchModeObjectModificationAction? ModifyObjectShift =>
AutoSelect
? new BatchModeObjectModificationAction(null, "Add to selection")
? new BatchModeObjectModificationAction(null, Resources.BatchModeModifierAddToSelection)
: null;
}

Expand All @@ -52,7 +53,7 @@ public BatchModeInputClipboard()
.Select(obj => (OngekiTimelineObjectBase)obj.CopyNew()).ToList();
}

public override string DisplayName => "Clipboard";
public override string DisplayName => Resources.Clipboard;
public override IEnumerable<OngekiTimelineObjectBase> GenerateObject()
{
return ClipboardContents.Select(obj => (OngekiTimelineObjectBase)obj.CopyNew());
Expand Down Expand Up @@ -83,38 +84,38 @@ public abstract class BatchModeInputLane<T> : BatchModeInputSubmode<T>

public class BatchModeInputLaneLeft : BatchModeInputLane<LaneLeftStart>
{
public override string DisplayName => "LaneLeft";
public override string DisplayName => Resources.LaneLeft;
}

public class BatchModeInputLaneCenter : BatchModeInputLane<LaneCenterStart>
{
public override string DisplayName => "LaneCenter";
public override string DisplayName => Resources.LaneCenter;
}

public class BatchModeInputLaneRight : BatchModeInputLane<LaneRightStart>
{
public override string DisplayName => "LaneRight";
public override string DisplayName => Resources.LaneRight;
}

public class BatchModeInputWallRight : BatchModeInputLane<WallRightStart>
{
public override string DisplayName => "WallRight";
public override string DisplayName => Resources.WallRight;
}

public class BatchModeInputWallLeft : BatchModeInputLane<WallLeftStart>
{
public override string DisplayName => "WallLeft";
public override string DisplayName => Resources.WallLeft;
}

public class BatchModeInputLaneColorful : BatchModeInputLane<ColorfulLaneStart>
{
public override string DisplayName => "LaneColorful";
public override string DisplayName => Resources.LaneColorful;
}

public abstract class BatchModeInputHitSubmode<T> : BatchModeInputSubmode<T>
where T : OngekiTimelineObjectBase, ICriticalableObject
{
public override BatchModeObjectModificationAction ModifyObjectCtrl { get; } = new(CritObject, "Set critical");
public override BatchModeObjectModificationAction ModifyObjectCtrl { get; } = new(CritObject, Resources.BatchModeModifierSetCritical);

private static void CritObject(OngekiObjectBase baseObject)
{
Expand All @@ -124,60 +125,60 @@ private static void CritObject(OngekiObjectBase baseObject)

public class BatchModeInputTap : BatchModeInputHitSubmode<Tap>
{
public override string DisplayName => "Tap";
public override string DisplayName => Resources.Tap;
}

public class BatchModeInputHold : BatchModeInputHitSubmode<Hold>
{
public override string DisplayName => "Hold";
public override string DisplayName => Resources.Hold;
public override bool AutoSelect => true;
}

public class BatchModeInputFlick : BatchModeInputHitSubmode<Flick>
{
public override BatchModeObjectModificationAction ModifyObjectShift { get; } = new(SwitchFlick, "Switch direction");
public override BatchModeObjectModificationAction ModifyObjectShift { get; } = new(SwitchFlick, Resources.BatchModeModifierSwitchDirection);

private static void SwitchFlick(OngekiObjectBase baseObject)
{
((Flick)baseObject).Direction = Flick.FlickDirection.Right;
}

public override string DisplayName => "Flick";
public override string DisplayName => Resources.Flick;
}

public class BatchModeInputLaneBlock : BatchModeInputSubmode<LaneBlockArea>
{
public override BatchModeObjectModificationAction ModifyObjectCtrl { get; } =
new BatchModeObjectModificationAction(SwitchDirection, "Switch direction");
new BatchModeObjectModificationAction(SwitchDirection, Resources.BatchModeModifierSwitchDirection);

private static void SwitchDirection(OngekiObjectBase baseObject)
{
((LaneBlockArea)baseObject).Direction = LaneBlockArea.BlockDirection.Right;
}

public override string DisplayName => "LaneBlock";
public override string DisplayName => Resources.LaneBlock;
}

public class BatchModeInputNormalBell : BatchModeInputSubmode<Bell>
{
public override string DisplayName => "Bell";
public override string DisplayName => Resources.Bell;
}

public class BatchModeFilterLanes : BatchModeFilterSubmode
{
public override string DisplayName => "Lanes";
public override string DisplayName => Resources.ObjectFilterLanes;
public override Func<OngekiObjectBase, bool> FilterFunction => obj => obj is LaneStartBase or LaneNextBase;
}

public class BatchModeFilterDockableObjects : BatchModeFilterSubmode
{
public override string DisplayName => "Dockable objects";
public override string DisplayName => Resources.ObjectFilterDockables;
public override Func<OngekiObjectBase, bool> FilterFunction => obj => obj is Tap or Hold or HoldEnd;
}

public class BatchModeFilterFloatingObjects : BatchModeFilterSubmode
{
public override string DisplayName => "Floating objects";
public override string DisplayName => Resources.ObjectFilterFloating;
public override Func<OngekiObjectBase, bool> FilterFunction => obj => obj is Bell or Bullet or Flick;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ public Point? CurrentCursorPosition
private double startXOffset;
private double startScrollOffset;
private bool isCanvasDragging;
private bool isLeftMouseDown;
private bool isMiddleMouseDown;
private MouseButtonState prevRightButtonState;
private Point contextMenuPosition;
Expand Down Expand Up @@ -1108,7 +1107,6 @@ public void OnMouseUp(ActionExecutionContext e)
}
}

isLeftMouseDown = false;
isSelectRangeDragging = false;
SelectionVisibility = Visibility.Collapsed;
currentDraggingActionId = int.MaxValue;
Expand Down Expand Up @@ -1152,7 +1150,6 @@ public void OnMouseDown(ActionExecutionContext e)
{
position.Y = Math.Max(0, Rect.MaxY - position.Y);

isLeftMouseDown = true;
isSelectRangeDragging = false;

var hitResult = hits.AsParallel().Where(x => x.Value.Contains(position)).Select(x => x.Key).OrderBy(x => x.Id).ToList();
Expand Down Expand Up @@ -1365,7 +1362,7 @@ public async void OnMouseMove(Point pos)
ScrollTo(audioTime);
}

if (EnableDragging)
if (EnableDragging && !IsRangeSelecting)
{
//拖动已选物件
var cp = pos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ public void RecalculateTotalDurationHeight()
}
}

public bool EnableDragging => !IsBatchMode || (Keyboard.Modifiers & ModifierKeys.Alt) != 0;
public bool EnableDragging => !IsBatchMode || (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt) &&
!Keyboard.Modifiers.HasFlag(ModifierKeys.Control) &&
!Keyboard.Modifiers.HasFlag(ModifierKeys.Shift));
private bool isSelectRangeDragging;

private bool isShowCurveControlAlways = false;
Expand Down
Loading

0 comments on commit 330757e

Please sign in to comment.