diff --git a/KaddaOK.AvaloniaApp/App.axaml b/KaddaOK.AvaloniaApp/App.axaml
index 38115a2..f484f1a 100644
--- a/KaddaOK.AvaloniaApp/App.axaml
+++ b/KaddaOK.AvaloniaApp/App.axaml
@@ -127,6 +127,7 @@
+
\ No newline at end of file
diff --git a/KaddaOK.AvaloniaApp/Controls/Dialogs/EditLineTimingDialog.axaml b/KaddaOK.AvaloniaApp/Controls/Dialogs/EditLineTimingDialog.axaml
index 8b4394d..0930a9b 100644
--- a/KaddaOK.AvaloniaApp/Controls/Dialogs/EditLineTimingDialog.axaml
+++ b/KaddaOK.AvaloniaApp/Controls/Dialogs/EditLineTimingDialog.axaml
@@ -11,7 +11,10 @@
xmlns:models="clr-namespace:KaddaOK.AvaloniaApp.Models"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="KaddaOK.AvaloniaApp.Controls.Dialogs.EditLineTimingDialog"
- x:DataType="models:EditingLine">
+ x:DataType="models:EditingLine"
+ Focusable="True"
+ AttachedToVisualTree="UserControl_AttachedToVisualTree"
+ KeyDown="UserControl_KeyDown">
+ Text="{Binding Text, Mode=OneWay}"
+ KeyDown="TextBox_KeyDown"/>
();
+ }
+
+ private void TextBox_KeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ {
+ dialogHost?.CloseDialogCommand.Execute(((TextBox)sender).Text);
+ }
+
+ if (e.Key == Key.Escape)
+ {
+ dialogHost?.CloseDialogCommand.Execute(null);
+ }
+ }
}
}
diff --git a/KaddaOK.AvaloniaApp/ObjectEqualityBooleanConverter.cs b/KaddaOK.AvaloniaApp/ObjectEqualityBooleanConverter.cs
new file mode 100644
index 0000000..92393be
--- /dev/null
+++ b/KaddaOK.AvaloniaApp/ObjectEqualityBooleanConverter.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Avalonia.Data.Converters;
+
+namespace KaddaOK.AvaloniaApp
+{
+ public class ObjectEqualityBooleanConverter : IMultiValueConverter
+ {
+ public object? Convert(IList
diff --git a/KaddaOK.AvaloniaApp/Views/EditLinesView.axaml.cs b/KaddaOK.AvaloniaApp/Views/EditLinesView.axaml.cs
index 6deb8b8..eb38887 100644
--- a/KaddaOK.AvaloniaApp/Views/EditLinesView.axaml.cs
+++ b/KaddaOK.AvaloniaApp/Views/EditLinesView.axaml.cs
@@ -1,16 +1,22 @@
+using System.Linq;
+using Avalonia;
using Avalonia.Controls;
using DialogHostAvalonia;
using KaddaOK.AvaloniaApp.ViewModels;
using Avalonia.Input;
+using Avalonia.LogicalTree;
using KaddaOK.AvaloniaApp.Models;
using KaddaOK.AvaloniaApp.ViewModels.DesignTime;
+using KaddaOK.Library;
using Microsoft.Extensions.DependencyInjection;
+using Avalonia.VisualTree;
namespace KaddaOK.AvaloniaApp.Views
{
public partial class EditLinesView : UserControl
{
private readonly EditLinesViewModel _viewModel;
+ private ItemsRepeater? _phrasesRepeater;
public EditLinesView()
{
InitializeComponent();
@@ -19,6 +25,7 @@ public EditLinesView()
? new DesignTimeEditLinesViewModel()
: App.ServiceProvider.GetRequiredService();
DataContext = _viewModel;
+ _viewModel.EditLinesView = this;
}
private void LayoutSizeChanged(object? sender, SizeChangedEventArgs args)
@@ -37,6 +44,7 @@ private void EditLinesViewDialog_Closing(object? sender, DialogClosingEventArgs
{
if (e.Parameter == null)
{
+ this.Focus();
return;
}
@@ -45,11 +53,50 @@ private void EditLinesViewDialog_Closing(object? sender, DialogClosingEventArgs
{
_viewModel.ApplyLineTimingEdit(e.Parameter);
}
+
+ this.Focus();
}
private void EditLinesView_OnKeyDown(object? sender, KeyEventArgs e)
{
- _viewModel.KeyPressed(e);
+ if (!this.FindDescendantOfType()?.IsOpen ?? false) // leave it alone if dialogs are open
+ {
+ _viewModel.KeyPressed(e);
+ }
+ }
+
+ private void EditLinesView_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
+ {
+ this.Focus();
+ _phrasesRepeater = this.FindNameScope().Find("PhrasesRepeater");
+ }
+
+ private void WordButton_GotFocus(object? sender, GotFocusEventArgs e)
+ {
+ _viewModel.CursorWord = ((Button)sender)?.CommandParameter as LyricWord;
+ }
+
+ private void MenuItem_AttachedToLogicalTree(object? sender, Avalonia.LogicalTree.LogicalTreeAttachmentEventArgs e)
+ {
+ var menuItem = sender as MenuItem;
+ if (menuItem?.InputGesture != null)
+ {
+ var keyBinding = new KeyBinding
+ {
+ Gesture = menuItem.InputGesture,
+ Command = menuItem.Command,
+ CommandParameter = menuItem.CommandParameter
+ };
+ if (!menuItem.KeyBindings.Any())
+ {
+ menuItem.KeyBindings.Add(keyBinding);
+ }
+ var presenter = menuItem?.FindLogicalAncestorOfType();
+ if (presenter != null)
+ {
+ presenter.KeyBindings.AddRange(menuItem.KeyBindings);
+ }
+ }
}
}
}
diff --git a/KaddaOK.Library/LineSplitter.cs b/KaddaOK.Library/LineSplitter.cs
index 8f5ea09..eb35121 100644
--- a/KaddaOK.Library/LineSplitter.cs
+++ b/KaddaOK.Library/LineSplitter.cs
@@ -19,6 +19,11 @@ public void SplitLineAt(ObservableCollection? allLines, LyricWord wor
if (originalLine.Words != null)
{
var originalWordIndex = originalLine.Words.IndexOf(wordToSplit);
+ if (originalWordIndex == 0 && splitBefore)
+ {
+ // can't split before this because it's already the first word; do nothing
+ return;
+ }
var newLine = new LyricLine
{
@@ -41,6 +46,7 @@ public void DeleteWord(ObservableCollection allLines, LyricWord wordT
var indexOf = originalLine.Words.IndexOf(wordToDelete);
if (indexOf > 0)
{
+ // TODO: wait what why? Investigate what the rationale for this trimming was, because it looks wrong as I go by it here rn
originalLine.Words[indexOf - 1].Text = originalLine?.Words[indexOf - 1]?.Text?.TrimEnd();
}
originalLine?.Words.Remove(wordToDelete);
diff --git a/KaddaOK.Library/WordMerger.cs b/KaddaOK.Library/WordMerger.cs
index fb95034..2bcba5e 100644
--- a/KaddaOK.Library/WordMerger.cs
+++ b/KaddaOK.Library/WordMerger.cs
@@ -4,54 +4,51 @@ namespace KaddaOK.Library
{
public interface IWordMerger
{
- void MergeWord(ObservableCollection? allLines, LyricWord wordToMerge, bool withWordBefore);
+ LyricWord MergeWord(ObservableCollection? allLines, LyricWord wordToMerge, bool withWordBefore);
}
public class WordMerger : IWordMerger
{
- public void MergeWord(ObservableCollection? allLines, LyricWord wordToMerge, bool withWordBefore)
+ public LyricWord? MergeWord(ObservableCollection? allLines, LyricWord wordToMerge, bool withWordBefore)
{
var originalLine = allLines?.SingleOrDefault(l => l.Words != null && l.Words.Contains(wordToMerge));
- if (originalLine != null)
+ if (originalLine == null)
{
- var originalLineIndex = allLines!.IndexOf(originalLine);
- if (originalLine.Words != null)
- {
- var originalWordIndex = originalLine.Words.IndexOf(wordToMerge);
- if ((withWordBefore && originalWordIndex < 1)
- || (!withWordBefore && originalWordIndex == originalLine.Words.Count - 1))
- {
- return; // I don't wanna. TODO: I guess this would move the word to the line in question?
- }
-
- if (withWordBefore)
- {
- var prevWordIndex = originalWordIndex - 1;
- var prevWord = originalLine.Words[prevWordIndex];
- var newWord = new LyricWord
- {
- StartSecond = prevWord.StartSecond,
- EndSecond = wordToMerge.EndSecond,
- Text = $"{prevWord.Text.TrimEnd()}{wordToMerge.Text.TrimStart()}"
- };
- originalLine.Words = new ObservableCollection(
- originalLine.Words.Take(prevWordIndex).Concat(new []{newWord}).Concat(originalLine.Words.Skip(originalWordIndex + 1)));
- }
- else
- {
- var nextWordIndex = originalWordIndex + 1;
- var nextWord = originalLine.Words[nextWordIndex];
- var newWord = new LyricWord
- {
- StartSecond = wordToMerge.StartSecond,
- EndSecond = nextWord.EndSecond,
- Text = $"{wordToMerge.Text.TrimEnd()}{nextWord.Text.TrimStart()}"
- };
- originalLine.Words = new ObservableCollection(
- originalLine.Words.Take(originalWordIndex).Concat(new[] { newWord }).Concat(originalLine.Words.Skip(nextWordIndex + 1)));
- }
- }
+ return null;
}
+
+ var originalLineIndex = allLines!.IndexOf(originalLine);
+
+ if (originalLine.Words == null)
+ {
+ return null;
+ }
+
+ var originalWordIndex = originalLine.Words.IndexOf(wordToMerge);
+ if ((withWordBefore && originalWordIndex < 1)
+ || (!withWordBefore && originalWordIndex == originalLine.Words.Count - 1))
+ {
+ return null; // I don't wanna. TODO: I guess this would move the word to the line in question?
+ }
+
+ // either we're merging with the word with the previous index or the next index
+ var firstWordIndex = withWordBefore ? originalWordIndex - 1 : originalWordIndex;
+ var secondWordIndex = withWordBefore ? originalWordIndex : originalWordIndex + 1;
+ var firstWord = originalLine.Words[firstWordIndex];
+ var secondWord = originalLine.Words[secondWordIndex];
+
+ var replacementWord = new LyricWord
+ {
+ StartSecond = firstWord.StartSecond,
+ EndSecond = secondWord.EndSecond,
+ Text = $"{firstWord.Text.TrimEnd()}{secondWord.Text.TrimStart()}"
+ };
+
+ originalLine.Words = new ObservableCollection(
+ originalLine.Words.Take(firstWordIndex).Concat(new[] { replacementWord })
+ .Concat(originalLine.Words.Skip(secondWordIndex + 1)));
+
+ return replacementWord;
}
}
}