diff --git a/AssetEditor/Views/MainWindow.xaml.cs b/AssetEditor/Views/MainWindow.xaml.cs index 4bd1fa88e..c77570ff5 100644 --- a/AssetEditor/Views/MainWindow.xaml.cs +++ b/AssetEditor/Views/MainWindow.xaml.cs @@ -134,7 +134,7 @@ private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref b { // Return HTMAXBUTTON when the mouse is over the maximize/restore button var point = PointFromScreen(new Point(lParam.ToInt32() & 0xFFFF, lParam.ToInt32() >> 16)); - if (WpfHelpers.GetElementBoundsRelativeToWindow(maximizeRestoreButton, this).Contains(point)) + if (WindowsTitleMenu.WpfHelpers.GetElementBoundsRelativeToWindow(maximizeRestoreButton, this).Contains(point)) { handled = true; // Apply hover button style diff --git a/Editors/Audio/AudioEditor/Commands/SetAudioFilesCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioFilesExplorer/SetAudioFilesCommand.cs similarity index 91% rename from Editors/Audio/AudioEditor/Commands/SetAudioFilesCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioFilesExplorer/SetAudioFilesCommand.cs index b78454c6e..1d53fa222 100644 --- a/Editors/Audio/AudioEditor/Commands/SetAudioFilesCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioFilesExplorer/SetAudioFilesCommand.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioFilesExplorer; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.AudioProject.Compiler; using Editors.Audio.Shared.AudioProject.Models; using Editors.Audio.Shared.Storage; using Editors.Audio.Shared.Wwise; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioFilesExplorer { public class SetAudioFilesCommand(IAudioEditorStateService audioEditorStateService, IEventHub eventHub, IAudioRepository audioRepository) : IUiCommand { diff --git a/Editors/Audio/AudioEditor/Commands/AddEditorRowToViewerCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectEditor/AddEditorRowToViewerCommand.cs similarity index 80% rename from Editors/Audio/AudioEditor/Commands/AddEditorRowToViewerCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectEditor/AddEditorRowToViewerCommand.cs index a69606884..afba03c92 100644 --- a/Editors/Audio/AudioEditor/Commands/AddEditorRowToViewerCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectEditor/AddEditorRowToViewerCommand.cs @@ -1,9 +1,11 @@ using System.Data; +using Editors.Audio.AudioEditor.Commands.AudioProjectMutation; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectEditor { public class AddEditorRowToViewerCommand( IAudioEditorStateService audioEditorStateService, @@ -16,14 +18,9 @@ public class AddEditorRowToViewerCommand( public void Execute(DataRow row) { - // Store the row data in the Audio Project var selectedAudioProjectExplorerNode = _audioEditorStateService.SelectedAudioProjectExplorerNode; _audioProjectMutationUICommandFactory.Create(MutationType.Add, selectedAudioProjectExplorerNode.Type).Execute(row); - - // Display the row in the Viewer _eventHub.Publish(new ViewerTableRowAddRequestedEvent(row)); - - // Reset the Editor _eventHub.Publish(new EditorTableRowAddedToViewerEvent()); } } diff --git a/Editors/Audio/AudioEditor/Commands/AddActionEventCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddActionEventCommand.cs similarity index 81% rename from Editors/Audio/AudioEditor/Commands/AddActionEventCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddActionEventCommand.cs index 77a3bf529..10cfe93d3 100644 --- a/Editors/Audio/AudioEditor/Commands/AddActionEventCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddActionEventCommand.cs @@ -1,10 +1,10 @@ using System.Data; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class AddActionEventCommand(IAudioEditorStateService audioEditorStateService, IActionEventService actionEventService) : IAudioProjectMutationUICommand { @@ -18,9 +18,9 @@ public void Execute(DataRow row) { var actionEventTypeName = _audioEditorStateService.SelectedAudioProjectExplorerNode.Name; var audioFiles = _audioEditorStateService.AudioFiles; - var settings = _audioEditorStateService.HircSettings; + var hircSettings = _audioEditorStateService.HircSettings; var actionEventName = TableHelpers.GetActionEventNameFromRow(row); - _actionEventService.AddActionEvent(actionEventTypeName, actionEventName, audioFiles, settings); + _actionEventService.AddActionEvent(actionEventTypeName, actionEventName, audioFiles, hircSettings); } } } diff --git a/Editors/Audio/AudioEditor/Commands/AddDialogueEventByPasteCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddDialogueEventByPasteCommand.cs similarity index 92% rename from Editors/Audio/AudioEditor/Commands/AddDialogueEventByPasteCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddDialogueEventByPasteCommand.cs index 3bb0b409f..549d531f0 100644 --- a/Editors/Audio/AudioEditor/Commands/AddDialogueEventByPasteCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddDialogueEventByPasteCommand.cs @@ -2,13 +2,14 @@ using System.Data; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.AudioProject.Models; using Editors.Audio.Shared.Storage; +using Shared.Ui.Common; using HircSettings = Editors.Audio.Shared.AudioProject.Models.HircSettings; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class AddDialogueEventByPasteCommand( IAudioEditorStateService audioEditorStateService, @@ -52,7 +53,7 @@ public void Execute(DataRow row) var statePathList = new List>(); foreach (DataColumn dataColumn in row.Table.Columns) { - var columnNameWithQualifier = TableHelpers.DeduplicateUnderscores(dataColumn.ColumnName); + var columnNameWithQualifier = WpfHelpers.DeduplicateUnderscores(dataColumn.ColumnName); var stateGroupName = TableHelpers.GetStateGroupFromStateGroupWithQualifier(_audioRepository, dialogueEventName, columnNameWithQualifier); var stateName = TableHelpers.GetValueFromRow(row, dataColumn.ColumnName); statePathList.Add(new KeyValuePair(stateGroupName, stateName)); diff --git a/Editors/Audio/AudioEditor/Commands/AddDialogueEventCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddDialogueEventCommand.cs similarity index 83% rename from Editors/Audio/AudioEditor/Commands/AddDialogueEventCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddDialogueEventCommand.cs index a0f225e97..2a83f69bf 100644 --- a/Editors/Audio/AudioEditor/Commands/AddDialogueEventCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddDialogueEventCommand.cs @@ -2,11 +2,12 @@ using System.Data; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.Storage; +using Shared.Ui.Common; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class AddDialogueEventCommand( IAudioEditorStateService audioEditorStateService, @@ -24,19 +25,19 @@ public void Execute(DataRow row) { var dialogueEventName = _audioEditorStateService.SelectedAudioProjectExplorerNode.Name; var audioFiles = _audioEditorStateService.AudioFiles; - var settings = _audioEditorStateService.HircSettings; + var hircSettings = _audioEditorStateService.HircSettings; var statePathList = new List>(); var stateGroupsWithQualifiers = _audioRepository.QualifiedStateGroupByStateGroupByDialogueEvent[dialogueEventName]; foreach (var stateGroupWithQualifier in stateGroupsWithQualifiers) { var stateGroupName = TableHelpers.GetStateGroupFromStateGroupWithQualifier(_audioRepository, dialogueEventName, stateGroupWithQualifier.Key); - var columnName = TableHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); + var columnName = WpfHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); var stateName = TableHelpers.GetValueFromRow(row, columnName); statePathList.Add(new KeyValuePair(stateGroupName, stateName)); } - _dialogueEventService.AddStatePath(dialogueEventName, audioFiles, settings, statePathList); + _dialogueEventService.AddStatePath(dialogueEventName, audioFiles, hircSettings, statePathList); } } } diff --git a/Editors/Audio/AudioEditor/Commands/AddStateCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddStateCommand.cs similarity index 88% rename from Editors/Audio/AudioEditor/Commands/AddStateCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddStateCommand.cs index baea56a47..cc721f781 100644 --- a/Editors/Audio/AudioEditor/Commands/AddStateCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AddStateCommand.cs @@ -1,10 +1,10 @@ using System.Data; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class AddStateCommand(IAudioEditorStateService audioEditorStateService, IStateService stateService) : IAudioProjectMutationUICommand { diff --git a/Editors/Audio/AudioEditor/Commands/AudioProjectMutationUICommandFactory.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AudioProjectMutationUICommandFactory.cs similarity index 91% rename from Editors/Audio/AudioEditor/Commands/AudioProjectMutationUICommandFactory.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AudioProjectMutationUICommandFactory.cs index bc74c0652..b4325dcf1 100644 --- a/Editors/Audio/AudioEditor/Commands/AudioProjectMutationUICommandFactory.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/AudioProjectMutationUICommandFactory.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public enum MutationType { diff --git a/Editors/Audio/AudioEditor/Commands/RemoveActionEventCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveActionEventCommand.cs similarity index 86% rename from Editors/Audio/AudioEditor/Commands/RemoveActionEventCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveActionEventCommand.cs index b313b47a1..e067b115e 100644 --- a/Editors/Audio/AudioEditor/Commands/RemoveActionEventCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveActionEventCommand.cs @@ -1,12 +1,12 @@ using System.Data; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class RemoveActionEventCommand( IAudioEditorStateService audioEditorStateService, diff --git a/Editors/Audio/AudioEditor/Commands/RemoveDialogueEventCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveDialogueEventCommand.cs similarity index 90% rename from Editors/Audio/AudioEditor/Commands/RemoveDialogueEventCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveDialogueEventCommand.cs index dd8c3a195..8092bfdf5 100644 --- a/Editors/Audio/AudioEditor/Commands/RemoveDialogueEventCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveDialogueEventCommand.cs @@ -2,13 +2,13 @@ using System.Windows; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.Storage; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class RemoveDialogueEventCommand( IAudioEditorStateService audioEditorStateService, @@ -36,7 +36,6 @@ public void Execute(DataRow row) var message = "State Path is incomplete probably due to a change to the Dialogue Event by CA. Add the missing State(s)."; MessageBox.Show(message, "Error"); } - } } } diff --git a/Editors/Audio/AudioEditor/Commands/RemoveStateCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveStateCommand.cs similarity index 85% rename from Editors/Audio/AudioEditor/Commands/RemoveStateCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveStateCommand.cs index 1801318c3..1c3a9c615 100644 --- a/Editors/Audio/AudioEditor/Commands/RemoveStateCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectMutation/RemoveStateCommand.cs @@ -1,12 +1,12 @@ using System.Data; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectMutation { public class RemoveStateCommand( IAudioEditorStateService audioEditorStateService, diff --git a/Editors/Audio/AudioEditor/Commands/EditViewerRowCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectViewer/EditViewerRowCommand.cs similarity index 91% rename from Editors/Audio/AudioEditor/Commands/EditViewerRowCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectViewer/EditViewerRowCommand.cs index 42cf5a597..c1bfa1af3 100644 --- a/Editors/Audio/AudioEditor/Commands/EditViewerRowCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectViewer/EditViewerRowCommand.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; using System.Data; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; using Serilog; using Shared.Core.ErrorHandling; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectViewer { public class EditViewerRowCommand( IAudioEditorStateService audioEditorStateService, diff --git a/Editors/Audio/AudioEditor/Commands/PasteViewerRowsCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectViewer/PasteViewerRowsCommand.cs similarity index 82% rename from Editors/Audio/AudioEditor/Commands/PasteViewerRowsCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectViewer/PasteViewerRowsCommand.cs index ae90c072b..169f0b930 100644 --- a/Editors/Audio/AudioEditor/Commands/PasteViewerRowsCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectViewer/PasteViewerRowsCommand.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; using System.Data; +using Editors.Audio.AudioEditor.Commands.AudioProjectMutation; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Enablement; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectViewer { public class PasteViewerRowsCommand( IAudioEditorStateService audioEditorStateService, diff --git a/Editors/Audio/AudioEditor/Commands/RemoveViewerRowsCommand.cs b/Editors/Audio/AudioEditor/Commands/AudioProjectViewer/RemoveViewerRowsCommand.cs similarity index 85% rename from Editors/Audio/AudioEditor/Commands/RemoveViewerRowsCommand.cs rename to Editors/Audio/AudioEditor/Commands/AudioProjectViewer/RemoveViewerRowsCommand.cs index db1a96891..604ac7d63 100644 --- a/Editors/Audio/AudioEditor/Commands/RemoveViewerRowsCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/AudioProjectViewer/RemoveViewerRowsCommand.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; using System.Data; +using Editors.Audio.AudioEditor.Commands.AudioProjectMutation; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Enablement; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.AudioProjectViewer { public class RemoveViewerRowsCommand( IAudioEditorStateService audioEditorStateService, diff --git a/Editors/Audio/AudioEditor/Commands/OpenAudioProjectConverterWindowCommand.cs b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenAudioProjectConverterWindowCommand.cs similarity index 92% rename from Editors/Audio/AudioEditor/Commands/OpenAudioProjectConverterWindowCommand.cs rename to Editors/Audio/AudioEditor/Commands/Dialogs/OpenAudioProjectConverterWindowCommand.cs index 0d0e7048d..1fd9d799d 100644 --- a/Editors/Audio/AudioEditor/Commands/OpenAudioProjectConverterWindowCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenAudioProjectConverterWindowCommand.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.Dialogs { public class OpenAudioProjectConverterWindowCommand(IServiceProvider serviceProvider) : IUiCommand { diff --git a/Editors/Audio/AudioEditor/Commands/OpenAudioProjectMergerWindowCommand.cs b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenAudioProjectMergerWindowCommand.cs similarity index 92% rename from Editors/Audio/AudioEditor/Commands/OpenAudioProjectMergerWindowCommand.cs rename to Editors/Audio/AudioEditor/Commands/Dialogs/OpenAudioProjectMergerWindowCommand.cs index f30163efb..d4c451c59 100644 --- a/Editors/Audio/AudioEditor/Commands/OpenAudioProjectMergerWindowCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenAudioProjectMergerWindowCommand.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.Dialogs { public class OpenAudioProjectMergerWindowCommand(IServiceProvider serviceProvider) : IUiCommand { diff --git a/Editors/Audio/AudioEditor/Commands/OpenDialogueEventMergerWindowCommand.cs b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenDialogueEventMergerWindowCommand.cs similarity index 92% rename from Editors/Audio/AudioEditor/Commands/OpenDialogueEventMergerWindowCommand.cs rename to Editors/Audio/AudioEditor/Commands/Dialogs/OpenDialogueEventMergerWindowCommand.cs index d31e669a0..f71b52db4 100644 --- a/Editors/Audio/AudioEditor/Commands/OpenDialogueEventMergerWindowCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenDialogueEventMergerWindowCommand.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.Dialogs { public class OpenDialogueEventMergerWindowCommand(IServiceProvider serviceProvider) : IUiCommand { diff --git a/Editors/Audio/AudioEditor/Commands/OpenMovieFileSelectionWindowCommand.cs b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenMovieFileSelectionWindowCommand.cs similarity index 82% rename from Editors/Audio/AudioEditor/Commands/OpenMovieFileSelectionWindowCommand.cs rename to Editors/Audio/AudioEditor/Commands/Dialogs/OpenMovieFileSelectionWindowCommand.cs index f4acb182e..14281b360 100644 --- a/Editors/Audio/AudioEditor/Commands/OpenMovieFileSelectionWindowCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenMovieFileSelectionWindowCommand.cs @@ -1,9 +1,10 @@ -using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Enablement; using Shared.Core.Events; using Shared.Core.PackFiles; using Shared.Core.Services; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.Dialogs { public class OpenMovieFileSelectionWindowCommand(IStandardDialogs standardDialogs, IEventHub eventHub, IPackFileService packFileService) : IUiCommand { diff --git a/Editors/Audio/AudioEditor/Commands/OpenNewAudioProjectWindowCommand.cs b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenNewAudioProjectWindowCommand.cs similarity index 93% rename from Editors/Audio/AudioEditor/Commands/OpenNewAudioProjectWindowCommand.cs rename to Editors/Audio/AudioEditor/Commands/Dialogs/OpenNewAudioProjectWindowCommand.cs index 63f66d1ee..f65c3b932 100644 --- a/Editors/Audio/AudioEditor/Commands/OpenNewAudioProjectWindowCommand.cs +++ b/Editors/Audio/AudioEditor/Commands/Dialogs/OpenNewAudioProjectWindowCommand.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Shared.Core.Events; -namespace Editors.Audio.AudioEditor.Commands +namespace Editors.Audio.AudioEditor.Commands.Dialogs { public class OpenNewAudioProjectWindowCommand(IServiceProvider serviceProvider) : IUiCommand { diff --git a/Editors/Audio/AudioEditor/Core/AudioEditorIntegrityService.cs b/Editors/Audio/AudioEditor/Core/AudioEditorIntegrityService.cs index 66e287c1c..d3c71ebf5 100644 --- a/Editors/Audio/AudioEditor/Core/AudioEditorIntegrityService.cs +++ b/Editors/Audio/AudioEditor/Core/AudioEditorIntegrityService.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Windows; +using Editors.Audio.Shared.AudioProject.Compiler; using Editors.Audio.Shared.AudioProject.Models; using Editors.Audio.Shared.GameInformation.Warhammer3; using Editors.Audio.Shared.Storage; @@ -15,6 +16,7 @@ namespace Editors.Audio.AudioEditor.Core public interface IAudioEditorIntegrityService { void UpdateSoundBankNames(AudioProjectFile audioProject, string audioProjectNameWithoutExtension); + void RefreshSourceIds(AudioProjectFile audioProject); void CheckDialogueEventInformationIntegrity(List dialogueEventData); void CheckAudioProjectDialogueEventIntegrity(AudioProjectFile audioProject); void CheckAudioProjectWavFilesIntegrity(AudioProjectFile audioProject); @@ -41,6 +43,31 @@ public void UpdateSoundBankNames(AudioProjectFile audioProject, string audioProj } } + public void RefreshSourceIds(AudioProjectFile audioProject) + { + var audioProjectSourceIds = audioProject.GetAudioFileIds(); + var languageId = WwiseHash.Compute(audioProject.Language); + var languageSourceIds = _audioRepository.GetUsedVanillaSourceIdsByLanguageId(languageId); + + var usedSourceIds = new HashSet(); + usedSourceIds.UnionWith(audioProjectSourceIds); + usedSourceIds.UnionWith(languageSourceIds); + + var audioProjectSounds = audioProject.GetSounds(); + foreach (var audioFile in audioProject.AudioFiles) + { + var audioFileIds = IdGenerator.GenerateIds(usedSourceIds); + usedSourceIds.Add(audioFile.Id); + + foreach (var sound in audioProjectSounds.Where(sound => sound.SourceId == audioFile.Id)) + { + sound.SourceId = audioFileIds.Id; + } + audioFile.Guid = audioFileIds.Guid; + audioFile.Id = audioFileIds.Id; + } + } + public void CheckDialogueEventInformationIntegrity(List information) { var exclusions = new List { "New_Dialogue_Event", "Battle_Individual_Melee_Weapon_Hit" }; diff --git a/Editors/Audio/AudioEditor/Core/AudioEditorStateService.cs b/Editors/Audio/AudioEditor/Core/AudioEditorStateService.cs index 7bcfad2b2..3a74adce6 100644 --- a/Editors/Audio/AudioEditor/Core/AudioEditorStateService.cs +++ b/Editors/Audio/AudioEditor/Core/AudioEditorStateService.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Data; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.AudioProject.Models; namespace Editors.Audio.AudioEditor.Core @@ -24,6 +24,7 @@ public interface IAudioEditorStateService List AudioFiles { get; set; } // Audio Project Viewer + DataRow EditorRow { get; set; } List SelectedViewerRows { get; set; } List CopiedViewerRows { get; set; } @@ -34,7 +35,8 @@ public interface IAudioEditorStateService void StoreCopiedFromAudioProjectExplorerNode(AudioProjectTreeNode node); void StoreModdedStatesOnly(bool moddedStatesOnly); void StoreHircSettings(HircSettings hircSettings); - void StoreAudioFiles(List audioFiles); + void StoreAudioFiles(List audioFiles); + void StoreEditorRow(DataRow row); void StoreSelectedViewerRows(List selectedViewerRows); void StoreCopiedViewerRows(List copiedViewerRows); void Reset(); @@ -50,6 +52,7 @@ public class AudioEditorStateService : IAudioEditorStateService public bool ShowModdedStatesOnly { get; set; } public HircSettings HircSettings { get; set; } public List AudioFiles { get; set; } = []; + public DataRow EditorRow { get; set; } public List SelectedViewerRows { get; set; } public List CopiedViewerRows { get; set; } @@ -69,6 +72,8 @@ public class AudioEditorStateService : IAudioEditorStateService public void StoreAudioFiles(List audioFiles) => AudioFiles = audioFiles; + public void StoreEditorRow(DataRow row) => EditorRow = row; + public void StoreSelectedViewerRows(List selectedViewerRows) => SelectedViewerRows = selectedViewerRows; public void StoreCopiedViewerRows(List copiedViewerRows) => CopiedViewerRows = copiedViewerRows; @@ -83,7 +88,9 @@ public void Reset() ShowModdedStatesOnly = false; HircSettings = null; AudioFiles.Clear(); + EditorRow = null; SelectedViewerRows = null; + CopiedViewerRows = null; } } } diff --git a/Editors/Audio/AudioEditor/Core/ShortcutService.cs b/Editors/Audio/AudioEditor/Core/ShortcutService.cs new file mode 100644 index 000000000..e2ba1ffbc --- /dev/null +++ b/Editors/Audio/AudioEditor/Core/ShortcutService.cs @@ -0,0 +1,66 @@ +using System.Windows.Input; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Shortcuts; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Shortcuts; +using Editors.Audio.AudioEditor.Events.Settings.Shortcuts; +using Shared.Core.Events; + +namespace Editors.Audio.AudioEditor.Core +{ + public interface IShortcutService + { + void HandleShortcut(KeyEventArgs e, bool isTextInputFocussed, bool isSettingsAudioFilesListViewFocussed); + } + + public class ShortcutService(IEventHub eventHub) : IShortcutService + { + private readonly IEventHub _eventHub = eventHub; + + public void HandleShortcut(KeyEventArgs e, bool isTextInputFocussed, bool isSettingsAudioFilesListViewFocussed) + { + // We want these triggered regardless of focus + if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.Q) + { + _eventHub.Publish(new EditorAddRowShortcutActivatedEvent()); + e.Handled = true; + } + else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.E) + { + _eventHub.Publish(new ViewerEditRowShortcutActivatedEvent()); + e.Handled = true; + } + else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.R) + { + _eventHub.Publish(new EditorSetRecommendedVOSettingsShortcutActivatedEvent()); + e.Handled = true; + } + // We want to allow normal copy / paste / delete / backspace functionality when AudioProjectEditor text input is focussed + else if (!isTextInputFocussed && !isSettingsAudioFilesListViewFocussed) + { + if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.C) + { + _eventHub.Publish(new ViewerCopyRowsShortcutActivatedEvent()); + e.Handled = true; + } + else if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V) + { + _eventHub.Publish(new ViewerPasteRowsShortcutActivatedEvent()); + e.Handled = true; + } + else if (e.Key == Key.Delete || e.Key == Key.Back) + { + _eventHub.Publish(new ViewerRemoveRowsShortcutActivatedEvent()); + e.Handled = true; + } + } + // We want the Audio Files list in Settings to have its own delete / backspace functionality + else if (isSettingsAudioFilesListViewFocussed) + { + if (e.Key == Key.Delete || e.Key == Key.Back) + { + _eventHub.Publish(new SettingsRemoveSelectedAudioFilesShortcutActivatedEvent()); + e.Handled = true; + } + } + } + } +} diff --git a/Editors/Audio/AudioEditor/Events/AudioFilesChangedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioFilesExplorer/AudioFilesChangedEvent.cs similarity index 70% rename from Editors/Audio/AudioEditor/Events/AudioFilesChangedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioFilesExplorer/AudioFilesChangedEvent.cs index d78fd9637..a501e35aa 100644 --- a/Editors/Audio/AudioEditor/Events/AudioFilesChangedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioFilesExplorer/AudioFilesChangedEvent.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Editors.Audio.Shared.AudioProject.Models; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioFilesExplorer { - public record AudioFilesChangedEvent(List AudioFiles, bool AddToExistingAudioFiles, bool IsSetFromViewerItem, bool IsSetFromEditedItem); + public record AudioFilesChangedEvent(List AudioFiles, bool AddToExistingAudioFiles, bool IsSetFromViewerItem, bool IsSetFromEditedViewerItem); } diff --git a/Editors/Audio/AudioEditor/Events/AudioFilesExplorerNodeSelectedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioFilesExplorer/AudioFilesExplorerNodeSelectedEvent.cs similarity index 66% rename from Editors/Audio/AudioEditor/Events/AudioFilesExplorerNodeSelectedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioFilesExplorer/AudioFilesExplorerNodeSelectedEvent.cs index 5656490f8..0e9d93183 100644 --- a/Editors/Audio/AudioEditor/Events/AudioFilesExplorerNodeSelectedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioFilesExplorer/AudioFilesExplorerNodeSelectedEvent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioFilesExplorer { public record AudioFilesExplorerNodeSelectedEvent(List WavFilePaths); } diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Enablement/EditorAddRowButtonEnablementUpdateRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Enablement/EditorAddRowButtonEnablementUpdateRequestedEvent.cs new file mode 100644 index 000000000..9e8514272 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Enablement/EditorAddRowButtonEnablementUpdateRequestedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Enablement +{ + public record EditorAddRowButtonEnablementUpdateRequestedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/MovieFileChangedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/MovieFileChangedEvent.cs similarity index 50% rename from Editors/Audio/AudioEditor/Events/MovieFileChangedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectEditor/MovieFileChangedEvent.cs index 27f8cb2fd..db7abdc57 100644 --- a/Editors/Audio/AudioEditor/Events/MovieFileChangedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/MovieFileChangedEvent.cs @@ -1,4 +1,4 @@ -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor { public record MovieFileChangedEvent(string MovieFilePath); } diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Shortcuts/EditorAddRowShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Shortcuts/EditorAddRowShortcutActivatedEvent.cs new file mode 100644 index 000000000..e91ed8372 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Shortcuts/EditorAddRowShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Shortcuts +{ + public record EditorAddRowShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Shortcuts/EditorSetRecommendedVOSettingsShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Shortcuts/EditorSetRecommendedVOSettingsShortcutActivatedEvent.cs new file mode 100644 index 000000000..062b89355 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Shortcuts/EditorSetRecommendedVOSettingsShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Shortcuts +{ + public record EditorSetRecommendedVOSettingsShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/EditorDataGridColumnAddRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorDataGridColumnAddRequestedEvent.cs similarity index 63% rename from Editors/Audio/AudioEditor/Events/EditorDataGridColumnAddRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorDataGridColumnAddRequestedEvent.cs index 5a46628fd..4296893a9 100644 --- a/Editors/Audio/AudioEditor/Events/EditorDataGridColumnAddRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorDataGridColumnAddRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Windows.Controls; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table { public record EditorDataGridColumnAddRequestedEvent(DataGridColumn Column); } diff --git a/Editors/Audio/AudioEditor/Events/EditorDataGridTextboxTextChangedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorDataGridTextboxTextChangedEvent.cs similarity index 51% rename from Editors/Audio/AudioEditor/Events/EditorDataGridTextboxTextChangedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorDataGridTextboxTextChangedEvent.cs index b2980b592..a0482bbc5 100644 --- a/Editors/Audio/AudioEditor/Events/EditorDataGridTextboxTextChangedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorDataGridTextboxTextChangedEvent.cs @@ -1,4 +1,4 @@ -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table { public record EditorDataGridTextboxTextChangedEvent(string Text); } diff --git a/Editors/Audio/AudioEditor/Events/EditorTableColumnAddRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableColumnAddRequestedEvent.cs similarity index 59% rename from Editors/Audio/AudioEditor/Events/EditorTableColumnAddRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableColumnAddRequestedEvent.cs index ba105ca5b..53ba49ca9 100644 --- a/Editors/Audio/AudioEditor/Events/EditorTableColumnAddRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableColumnAddRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table { public record EditorTableColumnAddRequestedEvent(DataColumn Column); } diff --git a/Editors/Audio/AudioEditor/Events/EditorTableRowAddRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableRowAddRequestedEvent.cs similarity index 57% rename from Editors/Audio/AudioEditor/Events/EditorTableRowAddRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableRowAddRequestedEvent.cs index ab38f6860..0c4d58a01 100644 --- a/Editors/Audio/AudioEditor/Events/EditorTableRowAddRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableRowAddRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table { public record EditorTableRowAddRequestedEvent(DataRow Row); } diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableRowAddedToViewerEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableRowAddedToViewerEvent.cs new file mode 100644 index 000000000..920aa19b7 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectEditor/Table/EditorTableRowAddedToViewerEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table +{ + public record EditorTableRowAddedToViewerEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectExplorer/AudioProjectExplorerNodeSelectedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectExplorer/AudioProjectExplorerNodeSelectedEvent.cs new file mode 100644 index 000000000..2854c64e4 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectExplorer/AudioProjectExplorerNodeSelectedEvent.cs @@ -0,0 +1,6 @@ +using Editors.Audio.AudioEditor.Presentation.Shared.Models; + +namespace Editors.Audio.AudioEditor.Events.AudioProjectExplorer +{ + public record AudioProjectExplorerNodeSelectedEvent(AudioProjectTreeNode TreeNode); +} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectExplorerNodeSelectedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectExplorerNodeSelectedEvent.cs deleted file mode 100644 index 32c0d3f25..000000000 --- a/Editors/Audio/AudioEditor/Events/AudioProjectExplorerNodeSelectedEvent.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Editors.Audio.AudioEditor.Presentation.Shared; - -namespace Editors.Audio.AudioEditor.Events -{ - public record AudioProjectExplorerNodeSelectedEvent(AudioProjectTreeNode TreeNode); -} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerCopyRowsShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerCopyRowsShortcutActivatedEvent.cs new file mode 100644 index 000000000..ded346d45 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerCopyRowsShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Shortcuts +{ + public record ViewerCopyRowsShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerEditRowShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerEditRowShortcutActivatedEvent.cs new file mode 100644 index 000000000..d5a3f2698 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerEditRowShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Shortcuts +{ + public record ViewerEditRowShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerPasteRowsShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerPasteRowsShortcutActivatedEvent.cs new file mode 100644 index 000000000..bfc5d9888 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerPasteRowsShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Shortcuts +{ + public record ViewerPasteRowsShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerRemoveRowsShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerRemoveRowsShortcutActivatedEvent.cs new file mode 100644 index 000000000..5a5d7af94 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Shortcuts/ViewerRemoveRowsShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Shortcuts +{ + public record ViewerRemoveRowsShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/ViewerDataGridColumnAddedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerDataGridColumnAddedEvent.cs similarity index 62% rename from Editors/Audio/AudioEditor/Events/ViewerDataGridColumnAddedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerDataGridColumnAddedEvent.cs index da261e915..6a243914e 100644 --- a/Editors/Audio/AudioEditor/Events/ViewerDataGridColumnAddedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerDataGridColumnAddedEvent.cs @@ -1,6 +1,6 @@ using System.Windows.Controls; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table { public record ViewerDataGridColumnAddedEvent(DataGridColumn Column); } diff --git a/Editors/Audio/AudioEditor/Events/ViewerDialogueEventDataGridContextMenuSetEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerDialogueEventDataGridContextMenuSetEvent.cs similarity index 50% rename from Editors/Audio/AudioEditor/Events/ViewerDialogueEventDataGridContextMenuSetEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerDialogueEventDataGridContextMenuSetEvent.cs index 6f986c750..01fa35721 100644 --- a/Editors/Audio/AudioEditor/Events/ViewerDialogueEventDataGridContextMenuSetEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerDialogueEventDataGridContextMenuSetEvent.cs @@ -1,4 +1,4 @@ -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table { public record ViewerDialogueEventDataGridContextMenuSetEvent(); } diff --git a/Editors/Audio/AudioEditor/Events/ViewerTableColumnAddRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableColumnAddRequestedEvent.cs similarity index 59% rename from Editors/Audio/AudioEditor/Events/ViewerTableColumnAddRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableColumnAddRequestedEvent.cs index aa9df00c7..03680ddf5 100644 --- a/Editors/Audio/AudioEditor/Events/ViewerTableColumnAddRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableColumnAddRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table { public record ViewerTableColumnAddRequestedEvent(DataColumn Column); } diff --git a/Editors/Audio/AudioEditor/Events/ViewerTableRowAddRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowAddRequestedEvent.cs similarity index 57% rename from Editors/Audio/AudioEditor/Events/ViewerTableRowAddRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowAddRequestedEvent.cs index 4fe16174e..155a6373e 100644 --- a/Editors/Audio/AudioEditor/Events/ViewerTableRowAddRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowAddRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table { public record ViewerTableRowAddRequestedEvent(DataRow Row); } diff --git a/Editors/Audio/AudioEditor/Events/ViewerTableRowEditedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowEditedEvent.cs similarity index 55% rename from Editors/Audio/AudioEditor/Events/ViewerTableRowEditedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowEditedEvent.cs index 5621b4547..531277870 100644 --- a/Editors/Audio/AudioEditor/Events/ViewerTableRowEditedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowEditedEvent.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table { public record ViewerTableRowEditedEvent(DataRow Row); } diff --git a/Editors/Audio/AudioEditor/Events/ViewerTableRowRemoveRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowRemoveRequestedEvent.cs similarity index 58% rename from Editors/Audio/AudioEditor/Events/ViewerTableRowRemoveRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowRemoveRequestedEvent.cs index 260aea9f6..f3b134a99 100644 --- a/Editors/Audio/AudioEditor/Events/ViewerTableRowRemoveRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowRemoveRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table { public record ViewerTableRowRemoveRequestedEvent(DataRow Row); } diff --git a/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowSelectionChangedEvent.cs b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowSelectionChangedEvent.cs new file mode 100644 index 000000000..9c5e3a123 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/AudioProjectViewer/Table/ViewerTableRowSelectionChangedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table +{ + public record ViewerTableRowSelectionChangedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/EditorAddRowButtonEnablementUpdateRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/EditorAddRowButtonEnablementUpdateRequestedEvent.cs deleted file mode 100644 index 8b2951852..000000000 --- a/Editors/Audio/AudioEditor/Events/EditorAddRowButtonEnablementUpdateRequestedEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Editors.Audio.AudioEditor.Events -{ - public record EditorAddRowButtonEnablementUpdateRequestedEvent(); -} diff --git a/Editors/Audio/AudioEditor/Events/EditorTableRowAddedToViewerEvent.cs b/Editors/Audio/AudioEditor/Events/EditorTableRowAddedToViewerEvent.cs deleted file mode 100644 index 791473f53..000000000 --- a/Editors/Audio/AudioEditor/Events/EditorTableRowAddedToViewerEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Editors.Audio.AudioEditor.Events -{ - public record EditorTableRowAddedToViewerEvent(); -} diff --git a/Editors/Audio/AudioEditor/Events/PasteViewerRowsShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/PasteViewerRowsShortcutActivatedEvent.cs deleted file mode 100644 index 06a063e7c..000000000 --- a/Editors/Audio/AudioEditor/Events/PasteViewerRowsShortcutActivatedEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Editors.Audio.AudioEditor.Events -{ - public record PasteViewerRowsShortcutActivatedEvent(); -} diff --git a/Editors/Audio/AudioEditor/Events/Settings/Shortcuts/SettingsRemoveSelectedAudioFilesShortcutActivatedEvent.cs b/Editors/Audio/AudioEditor/Events/Settings/Shortcuts/SettingsRemoveSelectedAudioFilesShortcutActivatedEvent.cs new file mode 100644 index 000000000..bc75f1628 --- /dev/null +++ b/Editors/Audio/AudioEditor/Events/Settings/Shortcuts/SettingsRemoveSelectedAudioFilesShortcutActivatedEvent.cs @@ -0,0 +1,4 @@ +namespace Editors.Audio.AudioEditor.Events.Settings.Shortcuts +{ + public record SettingsRemoveSelectedAudioFilesShortcutActivatedEvent(); +} diff --git a/Editors/Audio/AudioEditor/Events/ViewerTableRowSelectionChangedEvent.cs b/Editors/Audio/AudioEditor/Events/ViewerTableRowSelectionChangedEvent.cs deleted file mode 100644 index 353acc8ee..000000000 --- a/Editors/Audio/AudioEditor/Events/ViewerTableRowSelectionChangedEvent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Editors.Audio.AudioEditor.Events -{ - public record ViewerTableRowSelectionChangedEvent(); -} diff --git a/Editors/Audio/AudioEditor/Events/CacheWaveformRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/WaveformVisualiser/CacheWaveformRequestedEvent.cs similarity index 64% rename from Editors/Audio/AudioEditor/Events/CacheWaveformRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/WaveformVisualiser/CacheWaveformRequestedEvent.cs index 9bf6be29a..66c6d32c2 100644 --- a/Editors/Audio/AudioEditor/Events/CacheWaveformRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/WaveformVisualiser/CacheWaveformRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.WaveformVisualiser { public record CacheWaveformRequestedEvent(List FilePaths); } diff --git a/Editors/Audio/AudioEditor/Events/DecacheWaveformRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/WaveformVisualiser/DecacheWaveformRequestedEvent.cs similarity index 64% rename from Editors/Audio/AudioEditor/Events/DecacheWaveformRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/WaveformVisualiser/DecacheWaveformRequestedEvent.cs index c60c610c9..13facb04d 100644 --- a/Editors/Audio/AudioEditor/Events/DecacheWaveformRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/WaveformVisualiser/DecacheWaveformRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.WaveformVisualiser { public record DecacheWaveformRequestedEvent(List FilePaths); } diff --git a/Editors/Audio/AudioEditor/Events/PlayAudioRequestedEvent.cs b/Editors/Audio/AudioEditor/Events/WaveformVisualiser/PlayAudioRequestedEvent.cs similarity index 64% rename from Editors/Audio/AudioEditor/Events/PlayAudioRequestedEvent.cs rename to Editors/Audio/AudioEditor/Events/WaveformVisualiser/PlayAudioRequestedEvent.cs index 2f099cc33..e431bcf13 100644 --- a/Editors/Audio/AudioEditor/Events/PlayAudioRequestedEvent.cs +++ b/Editors/Audio/AudioEditor/Events/WaveformVisualiser/PlayAudioRequestedEvent.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Editors.Audio.AudioEditor.Events +namespace Editors.Audio.AudioEditor.Events.WaveformVisualiser { public record PlayAudioRequestedEvent(List WavFilePaths); } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioEditorView.xaml b/Editors/Audio/AudioEditor/Presentation/AudioEditorView.xaml index b532ec75a..d8c233330 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioEditorView.xaml +++ b/Editors/Audio/AudioEditor/Presentation/AudioEditorView.xaml @@ -17,6 +17,10 @@ mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="700"> + + + + + + + + Background="{DynamicResource App.Border}" + Visibility="{Binding IsSettingsBorderVisible, Converter={StaticResource BoolToVisibilityConverter}}"/> DataContext as AudioEditorViewModel; + private Window _window; + public AudioEditorView() { InitializeComponent(); - PreviewKeyDown += OnPreviewKeyDown; + Loaded += OnLoaded; + Unloaded += OnUnloaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + if (DesignerProperties.GetIsInDesignMode(new DependencyObject())) + return; + + _window = Window.GetWindow(this); + if (_window == null) + return; + + _window.AddHandler(Keyboard.PreviewKeyDownEvent, new KeyEventHandler(OnWindowPreviewKeyDown), true); } - private void OnPreviewKeyDown(object sender, KeyEventArgs e) + private void OnUnloaded(object sender, RoutedEventArgs e) { - if (IsPressedWithFocusOnAudioFilesListView(e.OriginalSource as DependencyObject)) + if (_window == null) return; - ViewModel.OnPreviewKeyDown(e); + _window.RemoveHandler(Keyboard.PreviewKeyDownEvent, new KeyEventHandler(OnWindowPreviewKeyDown)); + _window = null; } - private static bool IsPressedWithFocusOnAudioFilesListView(DependencyObject source) + private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e) + { + var focussedViewModel = GetFocussedViewModel(); + + var isTextInputFocussed = Keyboard.FocusedElement is ComboBox comboBox && comboBox.IsEditable || Keyboard.FocusedElement is TextBox textBox && !textBox.IsReadOnly; + + var isSettingsAudioFilesListViewFocussed = false; + if (focussedViewModel == FocussedViewModel.Settings) + isSettingsAudioFilesListViewFocussed = IsAudioFilesListViewFocussed(e.OriginalSource as DependencyObject); + + ViewModel?.OnPreviewKeyDown(e, isTextInputFocussed, isSettingsAudioFilesListViewFocussed); + } + + private static bool IsAudioFilesListViewFocussed(DependencyObject source) { var current = source; while (current != null) @@ -35,5 +82,33 @@ private static bool IsPressedWithFocusOnAudioFilesListView(DependencyObject sour } return false; } + + private static FocussedViewModel GetFocussedViewModel() + { + var currentElement = Keyboard.FocusedElement as DependencyObject; + while (currentElement != null) + { + if (currentElement is UserControl userControl) + { + var dataContext = userControl.DataContext; + if (dataContext is AudioProjectExplorerViewModel) + return FocussedViewModel.AudioProjectExplorer; + else if (dataContext is AudioFilesExplorerViewModel) + return FocussedViewModel.AudioFilesExplorer; + else if (dataContext is AudioProjectEditorViewModel) + return FocussedViewModel.AudioProjectEditor; + else if (dataContext is AudioProjectViewerViewModel) + return FocussedViewModel.AudioProjectViewer; + else if (dataContext is SettingsViewModel) + return FocussedViewModel.Settings; + else if (dataContext is WaveformVisualiserViewModel) + return FocussedViewModel.WaveformVisualiser; + else + return FocussedViewModel.Unknown; + } + currentElement = VisualTreeHelper.GetParent(currentElement); + } + return FocussedViewModel.Unknown; + } } } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioEditorViewModel.cs b/Editors/Audio/AudioEditor/Presentation/AudioEditorViewModel.cs index 93020d9f4..1e8b7de04 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioEditorViewModel.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioEditorViewModel.cs @@ -1,10 +1,10 @@ -using System.Windows.Controls; -using System.Windows.Input; +using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Editors.Audio.AudioEditor.Commands; +using Editors.Audio.AudioEditor.Commands.Dialogs; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectExplorer; using Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer; using Editors.Audio.AudioEditor.Presentation.AudioProjectEditor; using Editors.Audio.AudioEditor.Presentation.AudioProjectExplorer; @@ -16,7 +16,7 @@ using Shared.Core.Events; using Shared.Core.ToolCreation; -namespace Editors.Audio.AudioEditor +namespace Editors.Audio.AudioEditor.Presentation { public partial class AudioEditorViewModel : ObservableObject, IEditorInterface { @@ -25,8 +25,11 @@ public partial class AudioEditorViewModel : ObservableObject, IEditorInterface private readonly IAudioEditorStateService _audioEditorStateService; private readonly IAudioEditorFileService _audioEditorFileService; private readonly IAudioProjectCompilerService _audioProjectCompilerService; + private readonly IAudioEditorIntegrityService _audioEditorIntegrityService; + private readonly IShortcutService _shortcutService; [ObservableProperty] private bool _isAudioProjectLoaded = false; + [ObservableProperty] private bool _isSettingsBorderVisible = false; public AudioEditorViewModel( IUiCommandFactory uiCommandFactory, @@ -34,6 +37,8 @@ public AudioEditorViewModel( IAudioEditorStateService audioEditorStateService, IAudioEditorFileService audioEditorFileService, IAudioProjectCompilerService audioProjectCompilerService, + IAudioEditorIntegrityService audioEditorIntegrityService, + IShortcutService shortcutService, AudioProjectExplorerViewModel audioProjectExplorerViewModel, AudioFilesExplorerViewModel audioFilesExplorerViewModel, AudioProjectEditorViewModel audioProjectEditorViewModel, @@ -46,6 +51,9 @@ public AudioEditorViewModel( _audioEditorStateService = audioEditorStateService; _audioEditorFileService = audioEditorFileService; _audioProjectCompilerService = audioProjectCompilerService; + _audioEditorIntegrityService = audioEditorIntegrityService; + _shortcutService = shortcutService; + AudioProjectExplorerViewModel = audioProjectExplorerViewModel; AudioFilesExplorerViewModel = audioFilesExplorerViewModel; AudioProjectEditorViewModel = audioProjectEditorViewModel; @@ -54,6 +62,7 @@ public AudioEditorViewModel( WaveformVisualiserViewModel = waveformVisualiserViewModel; _eventHub.Register(this, OnAudioProjectLoaded); + _eventHub.Register(this, OnAudioProjectExplorerNodeSelected); } public AudioProjectExplorerViewModel AudioProjectExplorerViewModel { get; } @@ -67,6 +76,14 @@ public AudioEditorViewModel( private void OnAudioProjectLoaded(AudioProjectLoadedEvent e) => IsAudioProjectLoaded = true; + private void OnAudioProjectExplorerNodeSelected(AudioProjectExplorerNodeSelectedEvent e) + { + if (e.TreeNode.IsActionEvent() || e.TreeNode.IsDialogueEvent() || e.TreeNode.IsStateGroup()) + IsSettingsBorderVisible = true; + else + IsSettingsBorderVisible = false; + } + [RelayCommand] public void NewAudioProject() => _uiCommandFactory.Create().Execute(); [RelayCommand] public void SaveAudioProject() @@ -94,22 +111,15 @@ [RelayCommand] public void CompileAudioProject() [RelayCommand] public void OpenAudioProjectConverter() => _uiCommandFactory.Create().Execute(); - public void OnPreviewKeyDown(KeyEventArgs e) + [RelayCommand] public void RefreshSourceIds() + { + _audioEditorIntegrityService.RefreshSourceIds(_audioEditorStateService.AudioProject); + SaveAudioProject(); + } + + public void OnPreviewKeyDown(KeyEventArgs e, bool isTextInputFocussed, bool isSettingsAudioFilesListViewFocussed) { - // This allows us to still paste into for example the Audio Project Editor ComboBoxes - if (Keyboard.FocusedElement is ComboBox comboBox && comboBox.IsEditable) - return; - - // This is here rather than the Audio Project Viewer because the the Viewer DataGrid only recognises key presses when - // you're focussed on the DataGrid and if you delete an item it loses focus whereas this recognises them anywhere. - if (_audioEditorStateService.CopiedViewerRows != null && _audioEditorStateService.CopiedViewerRows.Count != 0 ) - { - if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V) - { - _eventHub.Publish(new PasteViewerRowsShortcutActivatedEvent()); - e.Handled = true; - } - } + _shortcutService.HandleShortcut(e, isTextInputFocussed, isSettingsAudioFilesListViewFocussed); } public void Close() => _audioEditorStateService.Reset(); diff --git a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml index 5ff09893a..b6eb30ce3 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml +++ b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml @@ -4,15 +4,17 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:Converters="clr-namespace:Editors.Audio.Shared.UI.Converters" + xmlns:ValueConverters="clr-namespace:Editors.Audio.Shared.UI.ValueConverters" + xmlns:Models="clr-namespace:Editors.Audio.AudioEditor.Presentation.Shared.Models" + xmlns:Controls="clr-namespace:Editors.Audio.AudioEditor.Presentation.Shared.Controls" xmlns:AudioFilesExplorer="clr-namespace:Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer" - xmlns:Shared="clr-namespace:Editors.Audio.AudioEditor.Presentation.Shared" d:DataContext="{d:DesignInstance Type=AudioFilesExplorer:AudioFilesExplorerViewModel}" mc:Ignorable="d" - d:DesignHeight="250" d:DesignWidth="500"> + d:DesignHeight="250" + d:DesignWidth="500"> - @@ -63,7 +65,8 @@ Margin="5, 0, 0, 0" Width="100" Content="Set Audio Files" - ToolTip="Set the selected audio file(s) as the audio file(s) in the Audio Project Editor." + ToolTip="Set the selected audio files as the audio files in the Settings." + ToolTipService.ShowOnDisabled="True" Command="{Binding SetAudioFilesCommand}" VerticalAlignment="Center" HorizontalAlignment="Left" @@ -74,7 +77,8 @@ Margin="5, 0, 0, 0" Width="120" Content="Add to Audio Files" - ToolTip="Add the selected audio file(s) to the audio file(s) already set in the Audio Project Editor." + ToolTip="Add the selected audio files to the audio files already set in the Settings." + ToolTipService.ShowOnDisabled="True" Command="{Binding AddToAudioFilesCommand}" VerticalAlignment="Center" HorizontalAlignment="Left" @@ -166,7 +170,7 @@ - - + - + - + @@ -220,7 +239,7 @@ Text="{Binding FileName}" /> - - + + diff --git a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml.cs b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml.cs index 93b14b3fc..ae7342f46 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerView.xaml.cs @@ -2,7 +2,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; namespace Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer { @@ -17,21 +17,20 @@ public AudioFilesExplorerView() private void OnClearButtonClick(object sender, RoutedEventArgs e) => FilterTextBoxItem.Focus(); - private void OnNodeDoubleClick(object sender, MouseButtonEventArgs e) + private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e) { var source = e.OriginalSource as DependencyObject; while (source != null && source is not TreeViewItem) source = VisualTreeHelper.GetParent(source); - var treeViewItem = source as TreeViewItem; - if (treeViewItem?.DataContext is not AudioFilesTreeNode node) + if (source is not TreeViewItem treeViewItem) return; - if (node.Type == AudioFilesTreeNodeType.WavFile) - { - ViewModel.PlayWav(); - e.Handled = true; - } + if (treeViewItem.DataContext is not AudioFilesTreeNode node || node.Type != AudioFilesTreeNodeType.WavFile) + return; + + ViewModel.PlayWav(); + e.Handled = true; } } } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerViewModel.cs b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerViewModel.cs index 8fe9e7754..5862adee8 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerViewModel.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesExplorerViewModel.cs @@ -8,15 +8,17 @@ using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Editors.Audio.AudioEditor.Commands; +using Editors.Audio.AudioEditor.Commands.AudioFilesExplorer; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; -using Editors.Audio.AudioEditor.Presentation.Shared.Table; +using Editors.Audio.AudioEditor.Events.AudioFilesExplorer; +using Editors.Audio.AudioEditor.Events.AudioProjectExplorer; +using Editors.Audio.AudioEditor.Events.WaveformVisualiser; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Shared.Core.Events; using Shared.Core.Events.Global; using Shared.Core.PackFiles; using Shared.Core.PackFiles.Models; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer { @@ -36,7 +38,7 @@ public partial class AudioFilesExplorerViewModel : ObservableObject [ObservableProperty] private bool _isPlayAudioButtonEnabled = false; [ObservableProperty] private string _filterQuery; [ObservableProperty] private ObservableCollection _audioFilesTree; - public ObservableCollection SelectedTreeNodes { get; set; } = []; + [ObservableProperty] private ObservableCollection _selectedTreeNodes = []; private CancellationTokenSource _filterQueryDebounceCancellationTokenSource; public AudioFilesExplorerViewModel( @@ -66,11 +68,13 @@ public AudioFilesExplorerViewModel( _globalEventHub.Register(this, x => RefreshAudioFilesTree(x.Container)); _globalEventHub.Register(this, x => RefreshAudioFilesTree(x.Container)); + AudioFilesExplorerLabel = $"Audio Files Explorer"; + var editablePack = _packFileService.GetEditablePack(); if (editablePack == null) return; - AudioFilesExplorerLabel = $"Audio Files Explorer - {TableHelpers.DuplicateUnderscores(editablePack.Name)}"; + AudioFilesExplorerLabel = $"Audio Files Explorer - {WpfHelpers.DuplicateUnderscores(editablePack.Name)}"; AudioFilesTree = _audioFilesTreeBuilder.BuildTree(editablePack); SetupIsExpandedHandlers(AudioFilesTree); @@ -138,7 +142,7 @@ private void OnPackFileContainerSetAsMainEditable(PackFileContainer packFileCont if (packFileContainer == null) return; - AudioFilesExplorerLabel = $"Audio Files Explorer - {TableHelpers.DuplicateUnderscores(packFileContainer.Name)}"; + AudioFilesExplorerLabel = $"Audio Files Explorer - {WpfHelpers.DuplicateUnderscores(packFileContainer.Name)}"; RefreshAudioFilesTree(packFileContainer); } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeBuilderService.cs b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeBuilderService.cs index c7a71110b..0d6c57178 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeBuilderService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeBuilderService.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Shared.Core.PackFiles.Models; namespace Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer diff --git a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeFilterService.cs b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeFilterService.cs index 25fbedf7c..30d4aa873 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeFilterService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/AudioFilesTreeFilterService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; namespace Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer { diff --git a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/MultiSelectTreeView.cs b/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/MultiSelectTreeView.cs deleted file mode 100644 index f3ed1fa7d..000000000 --- a/Editors/Audio/AudioEditor/Presentation/AudioFilesExplorer/MultiSelectTreeView.cs +++ /dev/null @@ -1,313 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; -using System.Windows.Media; -using Editors.Audio.AudioEditor.Presentation.Shared; - -namespace Editors.Audio.AudioEditor.Presentation.AudioFilesExplorer -{ - public class MultiSelectTreeView : TreeView - { - public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectTreeView), new PropertyMetadata(new ArrayList(), OnSelectedItemsChanged)); - public static readonly DependencyProperty IsMultiSelectedProperty = DependencyProperty.RegisterAttached("IsMultiSelected", typeof(bool), typeof(MultiSelectTreeView), new PropertyMetadata(false)); - - private AudioFilesTreeNode _anchorItem; - private AudioFilesTreeNode _pendingClickItem; - private Point _dragStartPoint; - private bool _isDragOperation; - private bool _suppressSelectionChange; - private List _preDragSelectedNodes; - - public IList SelectedItems - { - get { return (IList)GetValue(SelectedItemsProperty); } - set { SetValue(SelectedItemsProperty, value); } - } - - public MultiSelectTreeView() - { - if (SelectedItems is INotifyCollectionChanged collection) - collection.CollectionChanged += OnSelectedItemsCollectionChanged; - - PreviewMouseDown += MultiSelectTreeView_PreviewMouseDown; - PreviewMouseMove += MultiSelectTreeView_PreviewMouseMove; - } - - private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is MultiSelectTreeView treeView) - treeView.UpdateSelectionStates(); - } - - private void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (_suppressSelectionChange) - return; - - UpdateSelectionStates(); - } - - public static bool GetIsMultiSelected(DependencyObject obj) - { - return (bool)obj.GetValue(IsMultiSelectedProperty); - } - - private static void SetIsMultiSelected(DependencyObject obj, bool value) - { - obj.SetValue(IsMultiSelectedProperty, value); - } - - private void MultiSelectTreeView_PreviewMouseDown(object sender, MouseButtonEventArgs e) - { - _dragStartPoint = e.GetPosition(this); - _preDragSelectedNodes = SelectedItems.OfType().ToList(); - _isDragOperation = false; - _pendingClickItem = null; - - var itemUnderMouse = GetTreeViewItemUnderMouse(e); - if (itemUnderMouse != null) - { - var clickTarget = e.OriginalSource as DependencyObject; - var clickedExpander = IsClickOnExpander(clickTarget); - - if (!clickedExpander && - itemUnderMouse.DataContext is AudioFilesTreeNode clickedNode && - SelectedItems.Contains(clickedNode) && - !Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && - !Keyboard.Modifiers.HasFlag(ModifierKeys.Shift)) - { - _pendingClickItem = clickedNode; - e.Handled = true; - } - } - } - - private void MultiSelectTreeView_PreviewMouseMove(object sender, MouseEventArgs e) - { - var currentPos = e.GetPosition(this); - var diff = _dragStartPoint - currentPos; - - if (e.LeftButton == MouseButtonState.Pressed && - (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance || - Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) - { - if (_preDragSelectedNodes?.Count > 0) - { - _isDragOperation = true; - _pendingClickItem = null; - _suppressSelectionChange = true; - - try - { - var data = new DataObject(typeof(IEnumerable), _preDragSelectedNodes); - DragDrop.DoDragDrop(this, data, DragDropEffects.Copy); - } - finally - { - _suppressSelectionChange = false; - Dispatcher.BeginInvoke(UpdateSelectionStates, System.Windows.Threading.DispatcherPriority.Input); - } - } - } - } - - protected override void OnPreviewMouseUp(MouseButtonEventArgs e) - { - base.OnPreviewMouseUp(e); - - if (_pendingClickItem != null && !_isDragOperation) - { - // Treat it as a normal single click - _suppressSelectionChange = true; - try - { - SelectedItems.Clear(); - SelectedItems.Add(_pendingClickItem); - _anchorItem = _pendingClickItem; - } - finally - { - _suppressSelectionChange = false; - UpdateSelectionStates(); - } - } - - // Reset state for the next cycle - _pendingClickItem = null; - _isDragOperation = false; - } - - protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs e) - { - base.OnSelectedItemChanged(e); - - if (_suppressSelectionChange || e.NewValue is not AudioFilesTreeNode current) - return; - - _suppressSelectionChange = true; - try - { - SelectedItems ??= new ArrayList(); - - if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) - { - if (_anchorItem == null) - { - _anchorItem = current; - SelectedItems.Clear(); - SelectedItems.Add(_anchorItem); - } - else - { - SelectRangeFromAnchor(_anchorItem, current); - } - } - else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - if (SelectedItems.Contains(current)) - SelectedItems.Remove(current); - else - SelectedItems.Add(current); - - _anchorItem ??= current; - } - else - { - SelectedItems.Clear(); - SelectedItems.Add(current); - _anchorItem = current; - } - } - finally - { - _suppressSelectionChange = false; - } - - UpdateSelectionStates(); - } - - private void SelectRangeFromAnchor(AudioFilesTreeNode anchor, AudioFilesTreeNode target) - { - var items = GetTreeViewItems(this).Where(i => i.DataContext is AudioFilesTreeNode) - .ToList(); - var a = items.FindIndex(i => i.DataContext == anchor); - var t = items.FindIndex(i => i.DataContext == target); - if (a < 0 || t < 0) return; - - var start = Math.Min(a, t); - var end = Math.Max(a, t); - - _suppressSelectionChange = true; - try - { - for (var i = 0; i < items.Count; i++) - { - var node = (AudioFilesTreeNode)items[i].DataContext; - var shouldBeSelected = i >= start && i <= end; - - if (shouldBeSelected && !SelectedItems.Contains(node)) - SelectedItems.Add(node); - else if (!shouldBeSelected && SelectedItems.Contains(node)) - SelectedItems.Remove(node); - } - } - finally - { - _suppressSelectionChange = false; - } - - UpdateSelectionStates(); - } - - - private void UpdateSelectionStates() - { - if (_suppressSelectionChange) - return; - - _suppressSelectionChange = true; - try - { - foreach (var item in GetTreeViewItems(this)) - { - if (item.DataContext is not AudioFilesTreeNode node) - continue; - - var shouldBeSelected = SelectedItems.Contains(node); - - // If an item is not part of our multi-selection but happens to be WPF’s lead item, turn its flag off so the highlight disappears. - // Don't set IsSelected = true here otherwise we re-enter the single-selection process - if (!shouldBeSelected && item.IsSelected) - item.IsSelected = false; - - SetIsMultiSelected(item, shouldBeSelected); - - if (shouldBeSelected) - { - item.Background = - (Brush)Application.Current.Resources["TreeViewItem.Selected.Background"]; - item.BorderBrush = - (Brush)Application.Current.Resources["TreeViewItem.Selected.Border"]; - item.Foreground = - (Brush)Application.Current.Resources["ABrush.Foreground.Deeper"]; - } - else - { - item.ClearValue(BackgroundProperty); - item.ClearValue(BorderBrushProperty); - item.ClearValue(ForegroundProperty); - } - } - } - finally - { - _suppressSelectionChange = false; - } - } - - - private TreeViewItem GetTreeViewItemUnderMouse(MouseButtonEventArgs e) - { - var clickedPoint = e.GetPosition(this); - var hitTestResult = VisualTreeHelper.HitTest(this, clickedPoint); - var current = hitTestResult?.VisualHit; - while (current != null && current is not TreeViewItem) - current = VisualTreeHelper.GetParent(current); - return current as TreeViewItem; - } - - private static bool IsClickOnExpander(DependencyObject source) - { - while (source != null) - { - if (source is ToggleButton toggle && toggle.Name == "Expander") - return true; - - source = VisualTreeHelper.GetParent(source); - } - - return false; - } - - private static IEnumerable GetTreeViewItems(ItemsControl parent) - { - for (var i = 0; i < parent.Items.Count; i++) - { - var item = (TreeViewItem)parent.ItemContainerGenerator.ContainerFromIndex(i); - if (item != null) - { - yield return item; - - foreach (var childItem in GetTreeViewItems(item)) - yield return childItem; - } - } - } - } -} diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/AudioProjectEditorView.xaml b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/AudioProjectEditorView.xaml index 4688c3c04..830ee87c4 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/AudioProjectEditorView.xaml +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/AudioProjectEditorView.xaml @@ -46,18 +46,32 @@ + (this, OnEditorDataGridTextboxTextChanged); _eventHub.Register(this, OnMovieFileChanged); _eventHub.Register(this, OnEditorAddRowButtonEnablementUpdateRequested); + _eventHub.Register(this, OnEditorAddRowShortcutActivated); } private void OnAudioProjectInitialised(AudioProjectLoadedEvent e) @@ -95,7 +104,7 @@ private void OnAudioProjectExplorerNodeSelected(AudioProjectExplorerNodeSelected else if (selectedAudioProjectExplorerNode.IsDialogueEvent()) { MakeEditorVisible(); - SetEditorLabel(TableHelpers.DuplicateUnderscores(selectedAudioProjectExplorerNode.Name)); + SetEditorLabel(WpfHelpers.DuplicateUnderscores(selectedAudioProjectExplorerNode.Name)); Load(selectedAudioProjectExplorerNode.Type); var moddedStatesCount = _audioEditorStateService.AudioProject.StateGroups.SelectMany(stateGroup => stateGroup.States).Count(); @@ -105,7 +114,7 @@ private void OnAudioProjectExplorerNodeSelected(AudioProjectExplorerNodeSelected else if (selectedAudioProjectExplorerNode.IsStateGroup()) { MakeEditorVisible(); - SetEditorLabel(TableHelpers.DuplicateUnderscores(selectedAudioProjectExplorerNode.Name)); + SetEditorLabel(WpfHelpers.DuplicateUnderscores(selectedAudioProjectExplorerNode.Name)); Load(selectedAudioProjectExplorerNode.Type); } else @@ -184,9 +193,9 @@ private void OnViewerTableRowEdited(ViewerTableRowEditedEvent e) _eventHub.Publish(new EditorTableRowAddRequestedEvent(e.Row)); } - private void OnAudioFilesChanged(AudioFilesChangedEvent e) => SetEventNameFromAudioFile(e.AudioFiles, e.AddToExistingAudioFiles, e.IsSetFromEditedItem); + private void OnAudioFilesChanged(AudioFilesChangedEvent e) => SetEventNameFromAudioFile(e.AudioFiles, e.AddToExistingAudioFiles, e.IsSetFromEditedViewerItem); - private void SetEventNameFromAudioFile(List audioFiles, bool addToExistingAudioFiles, bool isSetFromEditedItem) + private void SetEventNameFromAudioFile(List audioFiles, bool addToExistingAudioFiles, bool isSetFromEditedViewerItem) { var selectedAudioProjectExplorerNode = _audioEditorStateService.SelectedAudioProjectExplorerNode; var isActionEvent = selectedAudioProjectExplorerNode.IsActionEvent(); @@ -194,7 +203,7 @@ private void SetEventNameFromAudioFile(List audioFiles, bool addToExi var hasExistingAudioFiles = _audioEditorStateService.AudioFiles.Count > 0; if (isActionEvent - && !isSetFromEditedItem + && isSetFromEditedViewerItem && isNotMoviesActionEvent && audioFiles.Count == 1 && ((hasExistingAudioFiles && !addToExistingAudioFiles) || (!hasExistingAudioFiles && addToExistingAudioFiles))) @@ -202,7 +211,7 @@ private void SetEventNameFromAudioFile(List audioFiles, bool addToExi var row = Table.Rows[0]; var wavFileName = Path.GetFileNameWithoutExtension(audioFiles[0].WavPackFileName); var eventName = $"Play_{wavFileName}"; - row[TableInfo.EventColumnName] = eventName; + row[TableInformation.EventColumnName] = eventName; } SetAddRowButtonEnablement(); @@ -220,7 +229,7 @@ private void SetMovieFilePath(string movieFilePath) var eventName = $"Play_Movie_{slashesToUnderscores}"; var row = Table.Rows[0]; - row[TableInfo.EventColumnName] = eventName; + row[TableInformation.EventColumnName] = eventName; } public void OnEditorAddRowButtonEnablementUpdateRequested(EditorAddRowButtonEnablementUpdateRequestedEvent e) => SetAddRowButtonEnablement(); @@ -231,6 +240,12 @@ private void Load(AudioProjectTreeNodeType selectedNodeType) tableService.Load(Table); } + private void OnEditorAddRowShortcutActivated(EditorAddRowShortcutActivatedEvent e) + { + if (_audioEditorStateService.EditorRow != null) + AddRowToViewer(); + } + [RelayCommand] public void AddRowToViewer() => _uiCommandFactory.Create().Execute(Table.Rows[0]); partial void OnShowModdedStatesOnlyChanged(bool value) @@ -272,6 +287,7 @@ private void SetAddRowButtonEnablement() else { IsAddRowButtonEnabled = true; + _audioEditorStateService.StoreEditorRow(Table.Rows[0]); return; } } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorActionEventTableService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorActionEventTableService.cs index 2dcc632b8..c5a496c8b 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorActionEventTableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorActionEventTableService.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Data; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.GameInformation.Warhammer3; using Shared.Core.Events; @@ -31,7 +31,7 @@ public void Load(DataTable table) public List DefineSchema() { var schema = new List(); - var columnName = TableInfo.EventColumnName; + var columnName = TableInformation.EventColumnName; schema.Add(columnName); return schema; } @@ -53,7 +53,7 @@ public void ConfigureDataGrid(List schema) var selectedAudioProjectExplorerNode = _audioEditorStateService.SelectedAudioProjectExplorerNode; if (selectedAudioProjectExplorerNode.Name == Wh3ActionEventInformation.GetName(Wh3ActionEventType.Movies)) { - var fileSelectColumnHeader = TableInfo.BrowseMovieColumnName; + var fileSelectColumnHeader = TableInformation.BrowseMovieColumnName; var fileSelectColumn = DataGridTemplates.CreateColumnTemplate(fileSelectColumnHeader, 85, useAbsoluteWidth: true); fileSelectColumn.CellTemplate = DataGridTemplates.CreateFileSelectButtonCellTemplate(_uiCommandFactory); _eventHub.Publish(new EditorDataGridColumnAddRequestedEvent(fileSelectColumn)); @@ -86,7 +86,7 @@ public void InitialiseTable(DataTable editorTable) eventName = "Play_"; var row = editorTable.NewRow(); - row[TableInfo.EventColumnName] = eventName; + row[TableInformation.EventColumnName] = eventName; _eventHub.Publish(new EditorTableRowAddRequestedEvent(row)); } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorDialogueEventTableService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorDialogueEventTableService.cs index d8060fb3c..c47bfb081 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorDialogueEventTableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorDialogueEventTableService.cs @@ -2,11 +2,12 @@ using System.Data; using System.Linq; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.Storage; using Shared.Core.Events; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectEditor.Table { @@ -36,7 +37,7 @@ public List DefineSchema() var stateGroupsWithQualifiers = _audioRepository.QualifiedStateGroupByStateGroupByDialogueEvent[dialogueEventName]; foreach (var stateGroupWithQualifier in stateGroupsWithQualifiers) { - var columnName = TableHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); + var columnName = WpfHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); schema.Add(columnName); } return schema; @@ -59,7 +60,7 @@ public void ConfigureDataGrid(List schema) foreach (var columnName in schema) { - var stateGroupNameWithQualifier = TableHelpers.DeduplicateUnderscores(columnName); + var stateGroupNameWithQualifier = WpfHelpers.DeduplicateUnderscores(columnName); var stateGroupName = TableHelpers.GetStateGroupFromStateGroupWithQualifier(_audioRepository, dialogueEventName, stateGroupNameWithQualifier); var column = DataGridTemplates.CreateColumnTemplate(columnName, columnWidth); @@ -82,8 +83,8 @@ public void InitialiseTable(DataTable table) var stateGroupsWithQualifiers = _audioRepository.QualifiedStateGroupByStateGroupByDialogueEvent[dialogueEvent.Name]; foreach (var stateGroupWithQualifier in stateGroupsWithQualifiers) { - var columnName = TableHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); - var stateGroup = TableHelpers.GetStateGroupFromStateGroupWithQualifier(_audioRepository, dialogueEvent.Name, TableHelpers.DeduplicateUnderscores(columnName)); + var columnName = WpfHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); + var stateGroup = TableHelpers.GetStateGroupFromStateGroupWithQualifier(_audioRepository, dialogueEvent.Name, WpfHelpers.DeduplicateUnderscores(columnName)); if (stateGroupsWithAnyState.ContainsKey(stateGroup)) row[columnName] = "Any"; // Set the cell value to Any as the default value diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorStateGroupTableService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorStateGroupTableService.cs index ece84b756..0ccd392b5 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorStateGroupTableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorStateGroupTableService.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Data; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Shared.Core.Events; @@ -24,7 +24,7 @@ public void Load(DataTable table) public List DefineSchema() { var schema = new List(); - var columnName = TableInfo.StateColumnName; + var columnName = TableInformation.StateColumnName; schema.Add(columnName); return schema; } @@ -52,7 +52,7 @@ public void ConfigureDataGrid(List schema) public void InitialiseTable(DataTable table) { - var columnHeader = TableInfo.StateColumnName; + var columnHeader = TableInformation.StateColumnName; var row = table.NewRow(); row[columnHeader] = string.Empty; _eventHub.Publish(new EditorTableRowAddRequestedEvent(row)); diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorTableServiceFactory.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorTableServiceFactory.cs index e64e61d52..902dde6f5 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorTableServiceFactory.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectEditor/Table/EditorTableServiceFactory.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectEditor.Table diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml index 2cf41dcee..040b0ff6f 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml @@ -5,9 +5,9 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:sys="clr-namespace:System;assembly=netstandard" - xmlns:Converters="clr-namespace:Editors.Audio.Shared.UI.Converters" + xmlns:ValueConverters="clr-namespace:Editors.Audio.Shared.UI.ValueConverters" xmlns:ExtendedWpfToolkit="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit" - xmlns:Shared="clr-namespace:Editors.Audio.AudioEditor.Presentation.Shared" + xmlns:Models="clr-namespace:Editors.Audio.AudioEditor.Presentation.Shared.Models" xmlns:AudioProjectExplorer="clr-namespace:Editors.Audio.AudioEditor.Presentation.AudioProjectExplorer" d:DataContext="{d:DesignInstance Type=AudioProjectExplorer:AudioProjectExplorerViewModel}" mc:Ignorable="d" @@ -16,7 +16,7 @@ 23 - @@ -100,7 +100,8 @@ SelectionChanged="OnWatermarkComboBoxSelectionChanged" IsEnabled="{Binding IsDialogueEventFilterEnabled}" Watermark="Select Dialogue Event Type Filter" - ToolTip="Dialogue Event Type refers to the type of action or trigger in game that the Dialogue Event relates to. Select the Dialogue Event type to filter by that."/> + ToolTip="Dialogue Event Type refers to the type of action or trigger in game that the Dialogue Event relates to. Select the Dialogue Event type to filter by that." + ToolTipService.ShowOnDisabled="True"/> + ToolTip="The Dialogue Event profile refers to the Select the Dialogue Event profile to filter by that" + ToolTipService.ShowOnDisabled="True"/> diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml.cs index 4b847fe35..2e746e5c3 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerView.xaml.cs @@ -1,7 +1,7 @@ using System.Windows; using System.Windows.Controls; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.GameInformation.Warhammer3; -using Editors.Audio.AudioEditor.Presentation.Shared; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectExplorer { diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerViewModel.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerViewModel.cs index 9e19f34e5..98ebf048b 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerViewModel.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectExplorerViewModel.cs @@ -10,10 +10,11 @@ using CommunityToolkit.Mvvm.Input; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; -using Editors.Audio.AudioEditor.Presentation.Shared.Table; +using Editors.Audio.AudioEditor.Events.AudioProjectExplorer; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.GameInformation.Warhammer3; using Shared.Core.Events; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectExplorer { @@ -62,7 +63,7 @@ private void OnAudioProjectInitialised(AudioProjectLoadedEvent e) AudioProjectTree = _audioProjectTreeBuilder.BuildTree(audioProject, ShowEditedItemsOnly); var audioProjectFileName = Path.GetFileNameWithoutExtension(_audioEditorStateService.AudioProjectFileName); - AudioProjectExplorerLabel = $"Audio Project Explorer - {TableHelpers.DuplicateUnderscores(audioProjectFileName)}"; + AudioProjectExplorerLabel = $"Audio Project Explorer - {WpfHelpers.DuplicateUnderscores(audioProjectFileName)}"; } partial void OnSelectedNodeChanged(AudioProjectTreeNode value) diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeBuilderService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeBuilderService.cs index 802a6c621..cce631f26 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeBuilderService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeBuilderService.cs @@ -3,7 +3,7 @@ using System.IO; using System.Linq; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.AudioProject.Models; using Editors.Audio.Shared.GameInformation.Warhammer3; diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeSearchFilterService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeSearchFilterService.cs index 839d4668b..a26b92126 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeSearchFilterService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectExplorer/AudioProjectTreeSearchFilterService.cs @@ -3,7 +3,7 @@ using System.Collections.ObjectModel; using System.Linq; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.GameInformation.Warhammer3; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectExplorer diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml index 63d74ee2f..4f4e6ee1d 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml @@ -42,28 +42,52 @@ - + + diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml.cs index 0d253d58b..ce9cb00b3 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerView.xaml.cs @@ -1,10 +1,6 @@ -using System.ComponentModel; -using System.Data; +using System.Data; using System.Linq; -using System.Windows; using System.Windows.Controls; -using System.Windows.Input; - namespace Editors.Audio.AudioEditor.Presentation.AudioProjectViewer { @@ -15,26 +11,18 @@ public partial class AudioProjectViewerView : UserControl public AudioProjectViewerView() { InitializeComponent(); - Loaded += OnLoaded; - PreviewKeyDown += OnPreviewKeyDown; } - private void OnPreviewKeyDown(object sender, KeyEventArgs e) => ViewModel.OnPreviewKeyDown(e); - - private void OnLoaded(object sender, RoutedEventArgs e) + private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (DesignerProperties.GetIsInDesignMode(new DependencyObject())) + if (ViewModel == null) return; - AudioProjectEditorDataGrid.SelectionChanged += OnDataGridSelectionChanged; - } - - private void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e) - { - var dataGrid = sender as DataGrid; - var selectedViewerRows = dataGrid.SelectedItems.Cast().Select(dataRowView => dataRowView.Row).ToList(); - if (ViewModel != null && selectedViewerRows != null) - ViewModel.SelectedRows = selectedViewerRows; + var dataGrid = (DataGrid)sender; + ViewModel.SelectedRows = dataGrid.SelectedItems + .Cast() + .Select(dataRowView => dataRowView.Row) + .ToList(); } } } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerViewModel.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerViewModel.cs index f8d93cba5..d4bb98abe 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerViewModel.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/AudioProjectViewerViewModel.cs @@ -4,20 +4,23 @@ using System.Data; using System.Linq; using System.Windows.Controls; -using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Editors.Audio.AudioEditor.Commands; +using Editors.Audio.AudioEditor.Commands.AudioProjectViewer; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Events.AudioProjectExplorer; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Shortcuts; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; using Editors.Audio.AudioEditor.Presentation.AudioProjectViewer.Table; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.AudioProject.Models; using Editors.Audio.Shared.Storage; using Serilog; using Shared.Core.ErrorHandling; using Shared.Core.Events; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectViewer { @@ -65,8 +68,11 @@ public AudioProjectViewerViewModel( _eventHub.Register(this, OnViewerTableColumnAddRequested); _eventHub.Register(this, OnViewerTableRowAddRequested); _eventHub.Register(this, OnViewerTableRowRemoveRequested); - _eventHub.Register(this, OnPasteViewerRowsShortcutActivated); + _eventHub.Register(this, OnViewerCopyRowsShortcutActivated); + _eventHub.Register(this, OnViewerPasteRowsShortcutActivated); _eventHub.Register(this, OnViewerDataGridColumnAdded); + _eventHub.Register(this, OnViewerRemoveRowsShortcutActivated); + _eventHub.Register(this, OnViewerEditRowShortcutActivated); } private void OnAudioProjectInitialised(AudioProjectLoadedEvent e) @@ -89,24 +95,24 @@ public void OnAudioProjectExplorerNodeSelected(AudioProjectExplorerNodeSelectedE var selectedExplorerNode = e.TreeNode; if (selectedExplorerNode.IsActionEvent()) { - MakeViewerVisible(); + SetViewerVisible(); SetViewerLabel(selectedExplorerNode.Name); Load(selectedExplorerNode.Type); } else if (selectedExplorerNode.IsDialogueEvent()) { - MakeViewerVisible(); - SetViewerLabel(TableHelpers.DuplicateUnderscores(selectedExplorerNode.Name)); + SetViewerVisible(); + SetViewerLabel(WpfHelpers.DuplicateUnderscores(selectedExplorerNode.Name)); Load(selectedExplorerNode.Type); - SetContextMenuVisibility(); + SetContextMenuVisible(); SetCopyEnablement(); SetPasteEnablement(); } else if (selectedExplorerNode.IsStateGroup()) { - MakeViewerVisible(); - SetViewerLabel(TableHelpers.DuplicateUnderscores(selectedExplorerNode.Name)); + SetViewerVisible(); + SetViewerLabel(WpfHelpers.DuplicateUnderscores(selectedExplorerNode.Name)); Load(selectedExplorerNode.Type); } else @@ -148,18 +154,10 @@ public void RemoveTableRow(DataRow row) _logger.Here().Information($"Removed {selectedAudioProjectExplorerNode.Type} row from Audio Project Viewer table for {selectedAudioProjectExplorerNode.Name}"); } - public void OnPreviewKeyDown(KeyEventArgs e) + public void OnViewerCopyRowsShortcutActivated(ViewerCopyRowsShortcutActivatedEvent e) { if (_audioEditorStateService.SelectedViewerRows != null && _audioEditorStateService.SelectedViewerRows.Count > 0) - { - if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.C) - CopyRows(); - - if (e.Key == Key.Delete || e.Key == Key.Back) - _uiCommandFactory.Create().Execute(_audioEditorStateService.SelectedViewerRows); - - e.Handled = true; - } + CopyRows(); } [RelayCommand] public void CopyRows() @@ -167,12 +165,16 @@ [RelayCommand] public void CopyRows() if (!IsCopyEnabled) return; - _audioEditorStateService.StoreCopiedViewerRows(SelectedRows); + _audioEditorStateService.StoreCopiedViewerRows(_audioEditorStateService.SelectedViewerRows); _audioEditorStateService.StoreCopiedFromAudioProjectExplorerNode(_audioEditorStateService.SelectedAudioProjectExplorerNode); SetPasteEnablement(); } - public void OnPasteViewerRowsShortcutActivated(PasteViewerRowsShortcutActivatedEvent e) => PasteRows(); + public void OnViewerPasteRowsShortcutActivated(ViewerPasteRowsShortcutActivatedEvent e) + { + if (_audioEditorStateService.CopiedViewerRows != null && _audioEditorStateService.CopiedViewerRows.Count != 0) + PasteRows(); + } [RelayCommand] public void PasteRows() { @@ -180,7 +182,6 @@ [RelayCommand] public void PasteRows() return; _uiCommandFactory.Create().Execute(_audioEditorStateService.CopiedViewerRows); - SetPasteEnablement(); } @@ -197,13 +198,12 @@ private void AddDataGridColumns(DataGridColumn column) // Prevent two different instances with the same header text var headerText = column.Header?.ToString() ?? string.Empty; - if (DataGridColumns.Any(col => string.Equals(col.Header?.ToString(), headerText, StringComparison.Ordinal))) + if (DataGridColumns.Any(column => string.Equals(column.Header?.ToString(), headerText, StringComparison.Ordinal))) return; DataGridColumns.Add(column); } - partial void OnSelectedRowsChanged(List value) { _audioEditorStateService.StoreSelectedViewerRows(SelectedRows); @@ -216,15 +216,27 @@ partial void OnSelectedRowsChanged(List value) SetCopyEnablement(); } + public void OnViewerRemoveRowsShortcutActivated(ViewerRemoveRowsShortcutActivatedEvent e) + { + if (_audioEditorStateService.SelectedViewerRows != null && _audioEditorStateService.SelectedViewerRows.Count > 0) + RemoveRow(); + } + [RelayCommand] public void RemoveRow() { - _uiCommandFactory.Create().Execute(SelectedRows); + _uiCommandFactory.Create().Execute(_audioEditorStateService.SelectedViewerRows); SetPasteEnablement(); } + private void OnViewerEditRowShortcutActivated(ViewerEditRowShortcutActivatedEvent e) + { + if (_audioEditorStateService.SelectedViewerRows != null && _audioEditorStateService.SelectedViewerRows.Count == 1) + EditRow(); + } + [RelayCommand] public void EditRow() { - _uiCommandFactory.Create().Execute(SelectedRows); + _uiCommandFactory.Create().Execute(_audioEditorStateService.SelectedViewerRows); SetPasteEnablement(); } @@ -240,7 +252,7 @@ partial void OnTableChanged(DataTable value) SetPasteEnablement(); } - public void SetContextMenuVisibility() + public void SetContextMenuVisible() { IsContextMenuCopyVisible = true; IsContextMenuPasteVisible = true; @@ -248,8 +260,8 @@ public void SetContextMenuVisibility() public void SetCopyEnablement() { - if (SelectedRows != null && IsContextMenuCopyVisible) - IsCopyEnabled = SelectedRows.AsEnumerable().Any(); + if (_audioEditorStateService.SelectedViewerRows != null && IsContextMenuCopyVisible) + IsCopyEnabled = _audioEditorStateService.SelectedViewerRows.AsEnumerable().Any(); } public void SetPasteEnablement() @@ -295,12 +307,12 @@ public void SetPasteEnablement() var areAnyCopiedRowsInDataGrid = _audioEditorStateService.CopiedViewerRows .Any(copied => Table.AsEnumerable() .Any(viewer => viewerColumns - .All(column => Equals(copied[column], viewer[column])))); + .All(column => Equals(copied[column], viewer[column])))); var selectedAudioProjectExplorerNodeName = _audioEditorStateService.SelectedAudioProjectExplorerNode.Name; var dialogueEventStateGroups = _audioRepository .QualifiedStateGroupByStateGroupByDialogueEvent[selectedAudioProjectExplorerNodeName] - .Select(kvp => TableHelpers.DuplicateUnderscores(kvp.Key)) + .Select(kvp => WpfHelpers.DuplicateUnderscores(kvp.Key)) .ToList(); var copiedStateGroups = rowColumns; @@ -312,17 +324,17 @@ public void SetButtonEnablement() { ResetButtonEnablement(); - if (SelectedRows == null) + if (_audioEditorStateService.SelectedViewerRows == null) { IsUpdateRowButtonEnabled = false; IsRemoveRowButtonEnabled = false; } - else if (SelectedRows.Count == 1) + else if (_audioEditorStateService.SelectedViewerRows.Count == 1) { IsUpdateRowButtonEnabled = true; IsRemoveRowButtonEnabled = true; } - else if (SelectedRows.Count > 1) + else if (_audioEditorStateService.SelectedViewerRows.Count > 1) IsRemoveRowButtonEnabled = true; } @@ -349,7 +361,7 @@ public void ResetTable() public void ResetViewerLabel() => ViewerLabel = $"Audio Project Viewer"; - public void MakeViewerVisible() => IsViewerVisible = true; + public void SetViewerVisible() => IsViewerVisible = true; public void ResetViewerVisibility() => IsViewerVisible = false; } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerActionEventTableService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerActionEventTableService.cs index 6c2414fb1..c66dd21ef 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerActionEventTableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerActionEventTableService.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.GameInformation.Warhammer3; using Shared.Core.Events; @@ -30,7 +30,7 @@ public void Load(DataTable table) public List DefineSchema() { var schema = new List(); - var columnName = TableInfo.EventColumnName; + var columnName = TableInformation.EventColumnName; schema.Add(columnName); return schema; } @@ -73,7 +73,7 @@ public void InitialiseTable(DataTable table) continue; var row = table.NewRow(); - row[TableInfo.EventColumnName] = actionEvent.Name; + row[TableInformation.EventColumnName] = actionEvent.Name; _eventHub.Publish(new ViewerTableRowAddRequestedEvent(row)); } } diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerDialogueEventTableService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerDialogueEventTableService.cs index 4e660941b..57ff3190e 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerDialogueEventTableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerDialogueEventTableService.cs @@ -3,11 +3,12 @@ using System.Data; using System.Linq; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.Storage; using Shared.Core.Events; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectViewer.Table { @@ -37,7 +38,7 @@ public List DefineSchema() var stateGroupsWithQualifiers = _audioRepository.QualifiedStateGroupByStateGroupByDialogueEvent[dialogueEventName]; foreach (var stateGroupWithQualifier in stateGroupsWithQualifiers) { - var columnName = TableHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); + var columnName = WpfHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); schema.Add(columnName); } return schema; @@ -83,7 +84,7 @@ public void InitialiseTable(DataTable table) foreach (var stateGroupWithQualifier in orderedStateGroupsWithQualifiers) { - var columnHeader = TableHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); + var columnHeader = WpfHelpers.DuplicateUnderscores(stateGroupWithQualifier.Key); var stateGroupName = stateGroupWithQualifier.Value; if (!occurrenceIndexByStateGroupName.TryGetValue(stateGroupName, out var currentOccurrenceIndex)) diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerStateGroupTableService.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerStateGroupTableService.cs index 1e3023561..f579c7ab1 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerStateGroupTableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerStateGroupTableService.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Data; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Shared.Core.Events; @@ -26,7 +26,7 @@ public void Load(DataTable table) public List DefineSchema() { var schema = new List(); - var columnName = TableInfo.StateColumnName; + var columnName = TableInformation.StateColumnName; schema.Add(columnName); return schema; } @@ -54,7 +54,7 @@ public void ConfigureDataGrid(List schema) public void InitialiseTable(DataTable table) { - var columnHeader = TableInfo.StateColumnName; + var columnHeader = TableInformation.StateColumnName; var stateGroupName = _audioEditorStateService.SelectedAudioProjectExplorerNode.Name; var stateGroup = _audioEditorStateService.AudioProject.GetStateGroup(stateGroupName); foreach (var state in stateGroup.States) diff --git a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerTableServiceFactory.cs b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerTableServiceFactory.cs index 8adf6f2e4..4e3113598 100644 --- a/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerTableServiceFactory.cs +++ b/Editors/Audio/AudioEditor/Presentation/AudioProjectViewer/Table/ViewerTableServiceFactory.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; namespace Editors.Audio.AudioEditor.Presentation.AudioProjectViewer.Table diff --git a/Editors/Audio/AudioEditor/Presentation/NewAudioProject/NewAudioProjectWindow.xaml b/Editors/Audio/AudioEditor/Presentation/NewAudioProject/NewAudioProjectWindow.xaml index 7251e398f..f6d06735c 100644 --- a/Editors/Audio/AudioEditor/Presentation/NewAudioProject/NewAudioProjectWindow.xaml +++ b/Editors/Audio/AudioEditor/Presentation/NewAudioProject/NewAudioProjectWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:sys="clr-namespace:System;assembly=netstandard" - xmlns:Converters="clr-namespace:Editors.Audio.Shared.UI.Converters" + xmlns:ValueConverters="clr-namespace:Editors.Audio.Shared.UI.ValueConverters" xmlns:Local="clr-namespace:Editors.Audio.AudioEditor.Presentation.NewAudioProject" Style="{StaticResource CustomWindowStyle}" d:DataContext="{d:DesignInstance Type=Local:NewAudioProjectViewModel}" @@ -15,7 +15,7 @@ Title="New Audio Project"> - diff --git a/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml b/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml index 9ba33587f..829ccbabb 100644 --- a/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml +++ b/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml @@ -6,7 +6,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:ExtendedWpfToolkit="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit" - xmlns:Converters="clr-namespace:Editors.Audio.Shared.UI.Converters" + xmlns:ValueConverters="clr-namespace:Editors.Audio.Shared.UI.ValueConverters" xmlns:Settings="clr-namespace:Editors.Audio.AudioEditor.Presentation.Settings" d:DataContext="{d:DesignInstance Type=Settings:SettingsViewModel}" mc:Ignorable="d" @@ -16,7 +16,7 @@ - @@ -63,12 +63,14 @@ Width="Auto"/> + - + + + + MouseDoubleClick="OnAudioFilesListViewMouseDoubleClick" + SelectionChanged="OnAudioFilesListViewSelectionChanged"> - + diff --git a/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml.cs b/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml.cs index e0620b4f7..996f60c39 100644 --- a/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml.cs +++ b/Editors/Audio/AudioEditor/Presentation/Settings/SettingsView.xaml.cs @@ -3,7 +3,8 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Presentation.Shared.Controls; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.Shared.AudioProject.Models; namespace Editors.Audio.AudioEditor.Presentation.Settings @@ -19,7 +20,7 @@ public SettingsView() private void OnListViewDragOver(object sender, DragEventArgs e) { - if (e.Data.GetDataPresent(typeof(IEnumerable))) + if (e.Data.GetDataPresent(typeof(IEnumerable))) e.Effects = DragDropEffects.Copy; else e.Effects = DragDropEffects.None; @@ -29,43 +30,35 @@ private void OnListViewDragOver(object sender, DragEventArgs e) private void OnListViewDrop(object sender, DragEventArgs e) { - if (e.Data.GetDataPresent(typeof(IEnumerable))) - { - if (e.Data.GetData(typeof(IEnumerable)) is not IEnumerable droppedNodes) - return; + if (!e.Data.GetDataPresent(typeof(IEnumerable))) + return; - ViewModel.SetAudioFilesViaDrop(droppedNodes); - } + if (e.Data.GetData(typeof(IEnumerable)) is not IEnumerable droppedMultiSelectTreeNodes) + return; + + var droppedAudioFilesTreeNodes = droppedMultiSelectTreeNodes + .OfType() + .Where(node => node.Type == AudioFilesTreeNodeType.WavFile) + .ToList(); + if (droppedAudioFilesTreeNodes.Count == 0) + return; + + ViewModel.SetAudioFilesViaDrop(droppedAudioFilesTreeNodes); } - private void OnAudioFileDoubleClick(object sender, MouseButtonEventArgs e) + private void OnAudioFilesListViewMouseDoubleClick(object sender, MouseButtonEventArgs e) { - if (DataContext is SettingsViewModel viewModel) - { - if (AudioFilesListView.SelectedItem is AudioFile audioFile) - viewModel.PlayWav(audioFile); - } + if (AudioFilesListView.SelectedItem is AudioFile audioFile) + ViewModel.PlayWav(audioFile); } - private void OnAudioFilesListViewPreviewKeyDown(object sender, KeyEventArgs e) + private void OnAudioFilesListViewSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (e.Key == Key.Delete || e.Key == Key.Back) - { - if (ViewModel.ShowSettingsFromAudioProjectViewer) - return; - - var selectedAudioFiles = AudioFilesListView.SelectedItems - .Cast() - .Where(audioFile => audioFile != null) - .ToList(); - - if (selectedAudioFiles.Count == 0) - return; - - ViewModel.RemoveAudioFiles(selectedAudioFiles); - - e.Handled = true; - } + var selectedAudioFiles = AudioFilesListView.SelectedItems + .Cast() + .Where(audioFile => audioFile != null) + .ToList(); + ViewModel.OnSelectedAudioFilesChanged(selectedAudioFiles); } } } diff --git a/Editors/Audio/AudioEditor/Presentation/Settings/SettingsViewModel.cs b/Editors/Audio/AudioEditor/Presentation/Settings/SettingsViewModel.cs index 1f74ffa5d..66a7f526d 100644 --- a/Editors/Audio/AudioEditor/Presentation/Settings/SettingsViewModel.cs +++ b/Editors/Audio/AudioEditor/Presentation/Settings/SettingsViewModel.cs @@ -5,8 +5,14 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Editors.Audio.AudioEditor.Core; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared; +using Editors.Audio.AudioEditor.Events.AudioFilesExplorer; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Shortcuts; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table; +using Editors.Audio.AudioEditor.Events.AudioProjectExplorer; +using Editors.Audio.AudioEditor.Events.AudioProjectViewer.Table; +using Editors.Audio.AudioEditor.Events.Settings.Shortcuts; +using Editors.Audio.AudioEditor.Events.WaveformVisualiser; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Editors.Audio.AudioEditor.Presentation.Shared.Table; using Editors.Audio.Shared.AudioProject.Compiler; using Editors.Audio.Shared.AudioProject.Models; @@ -20,7 +26,6 @@ namespace Editors.Audio.AudioEditor.Presentation.Settings public partial class SettingsViewModel : ObservableObject { private readonly IEventHub _eventHub; - private readonly IUiCommandFactory _uiCommandFactory; private readonly IAudioEditorStateService _audioEditorStateService; private readonly IAudioRepository _audioRepository; @@ -28,6 +33,8 @@ public partial class SettingsViewModel : ObservableObject [ObservableProperty] private bool _isSettingsVisible = false; [ObservableProperty] private bool _showSettingsFromAudioProjectViewer = false; + [ObservableProperty] private bool _isSetRecommendedVOSettingsEnabled = false; + [ObservableProperty] private bool _isRemoveAudioFilesEnabled = false; [ObservableProperty] private ContainerType _containerType; [ObservableProperty] private ObservableCollection _containerTypes = new(Enum.GetValues()); @@ -68,10 +75,11 @@ public partial class SettingsViewModel : ObservableObject [ObservableProperty] private bool _isTransitionDurationEnabled = false; [ObservableProperty] private bool _isTransitionDurationVisible = false; - public SettingsViewModel(IEventHub eventHub, IUiCommandFactory uiCommandFactory, IAudioEditorStateService audioEditorStateService, IAudioRepository audioRepository) + private List _selectedAudioFiles = []; + + public SettingsViewModel(IEventHub eventHub, IAudioEditorStateService audioEditorStateService, IAudioRepository audioRepository) { _eventHub = eventHub; - _uiCommandFactory = uiCommandFactory; _audioEditorStateService = audioEditorStateService; _audioRepository = audioRepository; @@ -82,6 +90,8 @@ public SettingsViewModel(IEventHub eventHub, IUiCommandFactory uiCommandFactory, _eventHub.Register(this, OnAudioFilesChanged); _eventHub.Register(this, OnViewerTableRowSelectionChanged); _eventHub.Register(this, OnViewerRowEdited); + _eventHub.Register(this, OnSettingsRemoveSelectedAudioFilesShortcutActivated); + _eventHub.Register(this, OnEditorSetRecommendedVOSettingsShortcutActivated); } private void OnAudioProjectExplorerNodeSelected(AudioProjectExplorerNodeSelectedEvent e) @@ -116,6 +126,11 @@ private void OnAudioFilesChanged(AudioFilesChangedEvent e) if (e.IsSetFromViewerItem == false) ShowSettingsFromAudioProjectViewer = false; + if (AudioFiles.Count >= 1) + IsSetRecommendedVOSettingsEnabled = true; + else + IsSetRecommendedVOSettingsEnabled = false; + SetSettingsUsabilityAndStore(); } @@ -164,14 +179,33 @@ public void SetAudioFilesViaDrop(IEnumerable audioFilesTreeN _eventHub.Publish(new AudioFilesChangedEvent(audioFiles, false, false, false)); } - public void RemoveAudioFiles(List audioFilesToRemove) + public void OnSelectedAudioFilesChanged(List selectedAudioFiles) + { + _selectedAudioFiles = selectedAudioFiles; + + if (!ShowSettingsFromAudioProjectViewer && selectedAudioFiles.Count >=1) + IsRemoveAudioFilesEnabled = true; + else + IsRemoveAudioFilesEnabled = false; + } + + private void OnSettingsRemoveSelectedAudioFilesShortcutActivated(SettingsRemoveSelectedAudioFilesShortcutActivatedEvent e) + { + if (!ShowSettingsFromAudioProjectViewer && _selectedAudioFiles.Count != 0) + RemoveSelectedAudioFiles(); + } + + [RelayCommand] public void RemoveSelectedAudioFiles() { - if (audioFilesToRemove == null || audioFilesToRemove.Count == 0) + if (_selectedAudioFiles == null || _selectedAudioFiles.Count == 0) return; var audioFiles = AudioFiles.ToList(); - foreach (var audioFileToRemove in audioFilesToRemove.ToList()) - audioFiles.Remove(audioFileToRemove); + foreach (var audioFile in _selectedAudioFiles.ToList()) + { + _selectedAudioFiles.Remove(audioFile); + audioFiles.Remove(audioFile); + } _audioEditorStateService.StoreAudioFiles(audioFiles); @@ -182,10 +216,7 @@ public void RemoveAudioFiles(List audioFilesToRemove) partial void OnShowSettingsFromAudioProjectViewerChanged(bool value) { if (ShowSettingsFromAudioProjectViewer == false) - { - SetInitialSettings(); - SetSettingsUsability(); - } + ResetSettings(); } partial void OnContainerTypeChanged(ContainerType value) => SetSettingsUsabilityAndStore(); @@ -369,106 +400,33 @@ private void SetSettingsFromViewerItem(bool isRowEdited) if (_audioEditorStateService.SelectedViewerRows.Count == 0) return; - var audioProject = _audioEditorStateService.AudioProject; HircSettings hircSettings = null; var audioFiles = new List(); var selectedAudioProjectExplorerNode = _audioEditorStateService.SelectedAudioProjectExplorerNode; if (selectedAudioProjectExplorerNode.IsActionEvent()) - { - var selectedViewerRow = _audioEditorStateService.SelectedViewerRows[0]; - var actionEventName = TableHelpers.GetActionEventNameFromRow(selectedViewerRow); - var actionEvent = _audioEditorStateService.AudioProject.GetActionEvent(actionEventName); - var soundBank = _audioEditorStateService.AudioProject.GetSoundBank(selectedAudioProjectExplorerNode.Parent.Parent.Name); - - var playActions = actionEvent.GetPlayActions(); - if (playActions.Count > 1) - throw new NotSupportedException("Multiple Actions are not supported"); - - foreach (var playAction in playActions) - { - if (playAction.TargetHircTypeIsSound()) - { - var sound = soundBank.GetSound(playAction.TargetHircId); - hircSettings = sound.HircSettings; - - var audioFile = audioProject.GetAudioFile(sound.SourceId); - audioFiles.Add(audioFile); - } - else if (playAction.TargetHircTypeIsRandomSequenceContainer()) - { - var randomSequenceContainer = soundBank.GetRandomSequenceContainer(playAction.TargetHircId); - hircSettings = randomSequenceContainer.HircSettings; - - var sounds = soundBank.GetSounds(randomSequenceContainer.Children); - var orderedSounds = sounds - .OrderBy(sound => sound.PlaylistOrder) - .ToList(); - foreach (var orderedSound in orderedSounds) - { - var audioFile = audioProject.GetAudioFile(orderedSound.SourceId); - audioFiles.Add(audioFile); - } - } - } - - } + GetActionEventSettings(ref hircSettings, ref audioFiles); else if (selectedAudioProjectExplorerNode.IsDialogueEvent()) - { - var selectedViewerRow = _audioEditorStateService.SelectedViewerRows[0]; - var dialogueEvent = _audioEditorStateService.AudioProject.GetDialogueEvent(selectedAudioProjectExplorerNode.Name); - var statePathName = TableHelpers.GetStatePathNameFromRow(selectedViewerRow, _audioRepository, selectedAudioProjectExplorerNode.Name); - var statePath = dialogueEvent.GetStatePath(statePathName); - var soundBank = _audioEditorStateService.AudioProject.GetSoundBank(selectedAudioProjectExplorerNode.Parent.Parent.Name); - - if (statePath.TargetHircTypeIsSound()) - { - var sound = soundBank.GetSound(statePath.TargetHircId); - hircSettings = sound.HircSettings; - - var audioFile = audioProject.GetAudioFile(sound.SourceId); - audioFiles.Add(audioFile); - } - else if (statePath.TargetHircTypeIsRandomSequenceContainer()) - { - var randomSequenceContainer = soundBank.GetRandomSequenceContainer(statePath.TargetHircId); - hircSettings = randomSequenceContainer.HircSettings; - - var sounds = soundBank.GetSounds(randomSequenceContainer.Children); - var orderedSounds = sounds - .OrderBy(sound => sound.PlaylistOrder) - .ToList(); - foreach (var orderedSound in orderedSounds) - { - var audioFile = audioProject.GetAudioFile(orderedSound.SourceId); - audioFiles.Add(audioFile); - } - } - - } + GetDialogueEventSettings(ref hircSettings, ref audioFiles); else if (selectedAudioProjectExplorerNode.IsStateGroup()) return; - SetSettingsFromViewerItem(hircSettings, audioFiles, isRowEdited); + SetAudioFilesFromViewerItem(isRowEdited, audioFiles); + SetHircSettingsFromViewerItem(hircSettings, audioFiles); + + SetSettingsUsability(); } - private void SetSettingsFromViewerItem(HircSettings hircSettings, List audioFiles, bool isRowEdited) + private void SetAudioFilesFromViewerItem(bool isRowEdited, List audioFiles) { - ResetAudioFiles(true); - - ContainerType = ContainerType.Random; - RandomType = RandomType.Standard; - PlaylistEndBehaviour = PlaylistEndBehaviour.Restart; - PlayMode = PlayMode.Step; - EnableRepetitionInterval = false; - RepetitionInterval = 1; - AlwaysResetPlaylist = false; - LoopingType = LoopingType.Disabled; - NumberOfLoops = 1; - TransitionType = TransitionType.Disabled; - TransitionDuration = 1; + AudioFiles = new ObservableCollection(audioFiles); + _audioEditorStateService.StoreAudioFiles(audioFiles); + _eventHub.Publish(new AudioFilesChangedEvent(audioFiles, false, true, isRowEdited)); + } - SetAudioFilesFromViewerItem(audioFiles, isRowEdited); + private void SetHircSettingsFromViewerItem(HircSettings hircSettings, List audioFiles) + { + SetInitialSettings(); if (audioFiles.Count > 1) { @@ -503,15 +461,62 @@ private void SetSettingsFromViewerItem(HircSettings hircSettings, List audioFiles) + { + var audioProject = _audioEditorStateService.AudioProject; + var selectedViewerRow = _audioEditorStateService.SelectedViewerRows[0]; + var selectedAudioProjectExplorerNode = _audioEditorStateService.SelectedAudioProjectExplorerNode; + var soundBank = _audioEditorStateService.AudioProject.GetSoundBank(selectedAudioProjectExplorerNode.Parent.Parent.Name); + + var actionEventName = TableHelpers.GetActionEventNameFromRow(selectedViewerRow); + var actionEvent = _audioEditorStateService.AudioProject.GetActionEvent(actionEventName); + + var playActions = actionEvent.GetPlayActions(); + if (playActions.Count > 1) + throw new NotSupportedException("Multiple Actions are not supported"); + + foreach (var playAction in playActions) + { + if (playAction.TargetHircTypeIsSound()) + { + var sound = soundBank.GetSound(playAction.TargetHircId); + hircSettings = sound.HircSettings; + audioFiles.Add(audioProject.GetAudioFile(sound.SourceId)); + } + else if (playAction.TargetHircTypeIsRandomSequenceContainer()) + { + var randomSequenceContainer = soundBank.GetRandomSequenceContainer(playAction.TargetHircId); + hircSettings = randomSequenceContainer.HircSettings; + audioFiles = audioProject.GetAudioFiles(soundBank, randomSequenceContainer); + } + } } - private void SetAudioFilesFromViewerItem(List audioFiles, bool isRowEdited) + private void GetDialogueEventSettings(ref HircSettings hircSettings, ref List audioFiles) { - AudioFiles = new ObservableCollection(audioFiles); - _audioEditorStateService.StoreAudioFiles(audioFiles); - _eventHub.Publish(new AudioFilesChangedEvent(audioFiles, false, true, isRowEdited)); + var audioProject = _audioEditorStateService.AudioProject; + var selectedViewerRow = _audioEditorStateService.SelectedViewerRows[0]; + var selectedAudioProjectExplorerNode = _audioEditorStateService.SelectedAudioProjectExplorerNode; + var soundBank = _audioEditorStateService.AudioProject.GetSoundBank(selectedAudioProjectExplorerNode.Parent.Parent.Name); + + var dialogueEvent = _audioEditorStateService.AudioProject.GetDialogueEvent(selectedAudioProjectExplorerNode.Name); + var statePathName = TableHelpers.GetStatePathNameFromRow(selectedViewerRow, _audioRepository, selectedAudioProjectExplorerNode.Name); + var statePath = dialogueEvent.GetStatePath(statePathName); + + if (statePath.TargetHircTypeIsSound()) + { + var sound = soundBank.GetSound(statePath.TargetHircId); + hircSettings = sound.HircSettings; + audioFiles.Add(audioProject.GetAudioFile(sound.SourceId)); + } + else if (statePath.TargetHircTypeIsRandomSequenceContainer()) + { + var randomSequenceContainer = soundBank.GetRandomSequenceContainer(statePath.TargetHircId); + hircSettings = randomSequenceContainer.HircSettings; + audioFiles = audioProject.GetAudioFiles(soundBank, randomSequenceContainer); + } } [RelayCommand] public void PlayWav(AudioFile audioFile) @@ -534,7 +539,13 @@ private void SetInitialSettings() TransitionDuration = 1; } - [RelayCommand] public void SetRecommendedSettings() + private void OnEditorSetRecommendedVOSettingsShortcutActivated(EditorSetRecommendedVOSettingsShortcutActivatedEvent e) + { + if (_audioEditorStateService.EditorRow != null && _audioEditorStateService.AudioFiles.Count != 0 && !IsSetRecommendedVOSettingsEnabled) + SetRecommendedVOSettings(); + } + + [RelayCommand] public void SetRecommendedVOSettings() { if (AudioFiles.Count > 1) { @@ -571,15 +582,12 @@ private void DisableAllSettings() [RelayCommand] public void ResetSettings() { SetInitialSettings(); - ResetAudioFiles(false); - SetSettingsUsability(); - } - private void ResetAudioFiles(bool resetForViewerItem) - { AudioFiles.Clear(); _audioEditorStateService.StoreAudioFiles(AudioFiles.ToList()); - _eventHub.Publish(new AudioFilesChangedEvent(AudioFiles.ToList(), false, resetForViewerItem, true)); + _eventHub.Publish(new AudioFilesChangedEvent(_audioEditorStateService.AudioFiles, false, false, false)); + + SetSettingsUsability(); } } } diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/Controls/MultiSelectTreeView.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Controls/MultiSelectTreeView.cs new file mode 100644 index 000000000..cd263c0af --- /dev/null +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Controls/MultiSelectTreeView.cs @@ -0,0 +1,393 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Media; + +namespace Editors.Audio.AudioEditor.Presentation.Shared.Controls +{ + public interface IMultiSelectTreeNode + { + bool IsExpanded { get; set; } + bool IsVisible { get; set; } + IEnumerable Children { get; } + } + + public class MultiSelectTreeView : TreeView + { + public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register( + "SelectedItems", + typeof(IList), + typeof(MultiSelectTreeView), + new PropertyMetadata(null, OnSelectedItemsChanged)); + + public static readonly DependencyProperty IsMultiSelectedProperty = DependencyProperty.RegisterAttached( + "IsMultiSelected", + typeof(bool), + typeof(MultiSelectTreeView), + new PropertyMetadata(false)); + + // The first node clicked (or the nearest to it after removing the initial node by Ctrl + click) + private IMultiSelectTreeNode? _anchorNode; + // The node clicked on mouse down that may become a single-click selection on mouse up + private IMultiSelectTreeNode? _pendingSingleClickNode; + // Used to ignore selection events resulting from the control applying selection changes + private bool _isUpdatingNodeSelection; + private Point _dragStartPoint; + private bool _isDragInProgress; + private List? _selectedNodesOnDrag; + + public IList SelectedItems + { + get { return (IList)GetValue(SelectedItemsProperty); } + set { SetValue(SelectedItemsProperty, value); } + } + + public MultiSelectTreeView() + { + Loaded += OnLoaded; + + PreviewMouseDown += MultiSelectTreeViewPreviewMouseDown; + PreviewMouseMove += MultiSelectTreeViewPreviewMouseMove; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + Loaded -= OnLoaded; + SelectedItems ??= new List(); + } + + private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not MultiSelectTreeView treeView) + return; + + treeView.SetNodeSelectionSafely(); + } + + protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs e) + { + base.OnSelectedItemChanged(e); + + if (_isUpdatingNodeSelection || e.NewValue is not IMultiSelectTreeNode node) + return; + + if (SelectedItems == null) + return; + + _isUpdatingNodeSelection = true; + try + { + var selectedItems = SelectedItems; + + if (IsShiftDown()) + { + if (_anchorNode == null) + SelectSingleClickNode(node); + else + SelectNodesFromAnchor(_anchorNode, node); + } + else if (IsCtrlDown()) + { + if (selectedItems.Contains(node)) + { + selectedItems.Remove(node); + + if (ReferenceEquals(_anchorNode, node)) + _anchorNode = FindNearestSelectedNode(node); + } + else + { + selectedItems.Add(node); + _anchorNode = node; + } + } + else + SelectSingleClickNode(node); + + UpdateNodeSelection(); + } + finally + { + _isUpdatingNodeSelection = false; + } + } + + private void MultiSelectTreeViewPreviewMouseDown(object sender, MouseButtonEventArgs e) + { + _dragStartPoint = e.GetPosition(this); + _pendingSingleClickNode = null; + + if (SelectedItems == null) + return; + + var selectedItems = SelectedItems; + _selectedNodesOnDrag = selectedItems.OfType().ToList(); + + // Ignore double-click here so pending-click and drag detection logic only runs for single-clicks + if (e.ClickCount == 2) + return; + + if (e.OriginalSource is not DependencyObject originalSource) + return; + + if (!TryGetTreeViewItemAndWasExpanderClicked(originalSource, out var treeViewItem, out var wasExpanderClicked)) + return; + + // If the user clicks an already-selected item without Ctrl / Shift it might be the start of a drag so + // we defer changing selection until mouse up so we don't collapse multi-selection before the drag begins. + if (!wasExpanderClicked && + treeViewItem != null && + treeViewItem.DataContext is IMultiSelectTreeNode clickedNode && + selectedItems.Contains(clickedNode) && + !IsCtrlDown() && + !IsShiftDown()) + { + _pendingSingleClickNode = clickedNode; + e.Handled = true; + } + } + + private void MultiSelectTreeViewPreviewMouseMove(object sender, MouseEventArgs e) + { + if (_isDragInProgress) + return; + + var currentPosition = e.GetPosition(this); + var difference = _dragStartPoint - currentPosition; + + if (e.LeftButton == MouseButtonState.Pressed && + (Math.Abs(difference.X) > SystemParameters.MinimumHorizontalDragDistance || + Math.Abs(difference.Y) > SystemParameters.MinimumVerticalDragDistance)) + { + if (_selectedNodesOnDrag?.Count > 0) + { + _isDragInProgress = true; + + _pendingSingleClickNode = null; + _isUpdatingNodeSelection = true; + + try + { + var data = new DataObject(typeof(IEnumerable), _selectedNodesOnDrag); + _selectedNodesOnDrag = null; + DragDrop.DoDragDrop(this, data, DragDropEffects.Copy); + } + finally + { + _isUpdatingNodeSelection = false; + Dispatcher.BeginInvoke(SetNodeSelectionSafely, System.Windows.Threading.DispatcherPriority.Input); + } + } + } + } + + protected override void OnPreviewMouseUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseUp(e); + + if (_pendingSingleClickNode != null) + { + // Clear the current selection and select the clicked item to treat it as a normal single click since no drag occurred + _isUpdatingNodeSelection = true; + try + { + SelectSingleClickNode(_pendingSingleClickNode); + } + finally + { + _isUpdatingNodeSelection = false; + SetNodeSelectionSafely(); + } + } + + _pendingSingleClickNode = null; + _selectedNodesOnDrag = null; + _isDragInProgress = false; + } + + private void SetNodeSelectionSafely() + { + if (_isUpdatingNodeSelection) + return; + + if (SelectedItems == null) + return; + + _isUpdatingNodeSelection = true; + try + { + UpdateNodeSelection(); + } + finally + { + _isUpdatingNodeSelection = false; + } + } + + private void UpdateNodeSelection() + { + var selectedNodes = SelectedItems?.OfType().ToHashSet() ?? []; + + foreach (var item in GetTreeViewItems(this)) + { + if (item.DataContext is not IMultiSelectTreeNode node) + continue; + + var shouldBeSelected = selectedNodes.Contains(node); + + // By default WPF's TreeView always has a selected item for focus and keyboard navigation. + // If that item is not selected by us we set TreeViewItem.IsSelected to false to remove it + // without triggering WPF's internal selection highlight logic again. + if (!shouldBeSelected && item.IsSelected) + item.IsSelected = false; + + SetIsMultiSelected(item, shouldBeSelected); + } + } + + private void SelectSingleClickNode(IMultiSelectTreeNode node) + { + if (SelectedItems == null) + return; + + var selectedItems = SelectedItems; + selectedItems.Clear(); + selectedItems.Add(node); + _anchorNode = node; + } + + private void SelectNodesFromAnchor(IMultiSelectTreeNode anchorNode, IMultiSelectTreeNode targetNode) + { + if (SelectedItems == null) + return; + + var visibleNodesInDisplayOrder = GetVisibleNodes(); + + var anchorIndex = visibleNodesInDisplayOrder.FindIndex(node => ReferenceEquals(node, anchorNode)); + var targetIndex = visibleNodesInDisplayOrder.FindIndex(node => ReferenceEquals(node, targetNode)); + if (anchorIndex < 0 || targetIndex < 0) + return; + + var startIndex = Math.Min(anchorIndex, targetIndex); + var endIndex = Math.Max(anchorIndex, targetIndex); + + var selectedNodes = SelectedItems; + selectedNodes.Clear(); + + for (var i = startIndex; i <= endIndex; i++) + selectedNodes.Add(visibleNodesInDisplayOrder[i]); + } + + private IMultiSelectTreeNode? FindNearestSelectedNode(IMultiSelectTreeNode removedAnchorNode) + { + if (SelectedItems == null) + return null; + + var selectedItems = SelectedItems; + if (selectedItems.Count == 0) + return null; + + var visibleNodesInDisplayOrder = GetVisibleNodes(); + + var removedIndex = visibleNodesInDisplayOrder.FindIndex(node => ReferenceEquals(node, removedAnchorNode)); + if (removedIndex < 0) + return selectedItems.OfType().FirstOrDefault(); + + for (var i = removedIndex + 1; i < visibleNodesInDisplayOrder.Count; i++) + { + if (selectedItems.Contains(visibleNodesInDisplayOrder[i])) + return visibleNodesInDisplayOrder[i]; + } + + for (var i = removedIndex - 1; i >= 0; i--) + { + if (selectedItems.Contains(visibleNodesInDisplayOrder[i])) + return visibleNodesInDisplayOrder[i]; + } + + return null; + } + + private List GetVisibleNodes() + { + var visibleNodes = new List(); + var rootItems = ItemsSource ?? Items; + + foreach (var item in rootItems) + { + if (item is IMultiSelectTreeNode rootNode) + GetVisibleNode(rootNode, visibleNodes); + } + + return visibleNodes; + } + + private static void GetVisibleNode(IMultiSelectTreeNode node, List visibleNodes) + { + if (node == null) + return; + + if (!node.IsVisible) + return; + + visibleNodes.Add(node); + + if (!node.IsExpanded) + return; + + foreach (var childNode in node.Children) + GetVisibleNode(childNode, visibleNodes); + } + + private static IEnumerable GetTreeViewItems(ItemsControl parent) + { + for (var i = 0; i < parent.Items.Count; i++) + { + var item = (TreeViewItem)parent.ItemContainerGenerator.ContainerFromIndex(i); + if (item != null) + { + yield return item; + + foreach (var childItem in GetTreeViewItems(item)) + yield return childItem; + } + } + } + + private static bool TryGetTreeViewItemAndWasExpanderClicked(DependencyObject originalSource, out TreeViewItem? treeViewItem, out bool wasExpanderClicked) + { + treeViewItem = null; + wasExpanderClicked = false; + + var currentVisual = originalSource; + while (currentVisual != null) + { + if (currentVisual is ToggleButton toggleButton && toggleButton.Name == "Expander") + wasExpanderClicked = true; + + if (currentVisual is TreeViewItem typedTreeViewItem) + { + treeViewItem = typedTreeViewItem; + return true; + } + + currentVisual = VisualTreeHelper.GetParent(currentVisual); + } + + return false; + } + + public static bool GetIsMultiSelected(DependencyObject obj) => (bool)obj.GetValue(IsMultiSelectedProperty); + + public static void SetIsMultiSelected(DependencyObject obj, bool value) => obj.SetValue(IsMultiSelectedProperty, value); + + private static bool IsShiftDown() => Keyboard.Modifiers.HasFlag(ModifierKeys.Shift); + + private static bool IsCtrlDown() => Keyboard.Modifiers.HasFlag(ModifierKeys.Control); + } +} diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/AudioFilesTreeNode.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Models/AudioFilesTreeNode.cs similarity index 81% rename from Editors/Audio/AudioEditor/Presentation/Shared/AudioFilesTreeNode.cs rename to Editors/Audio/AudioEditor/Presentation/Shared/Models/AudioFilesTreeNode.cs index 302f1431f..2716bffb0 100644 --- a/Editors/Audio/AudioEditor/Presentation/Shared/AudioFilesTreeNode.cs +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Models/AudioFilesTreeNode.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; +using Editors.Audio.AudioEditor.Presentation.Shared.Controls; -namespace Editors.Audio.AudioEditor.Presentation.Shared +namespace Editors.Audio.AudioEditor.Presentation.Shared.Models { public enum AudioFilesTreeNodeType { @@ -10,7 +12,7 @@ public enum AudioFilesTreeNodeType WavFile } - public partial class AudioFilesTreeNode : ObservableObject + public partial class AudioFilesTreeNode : ObservableObject, IMultiSelectTreeNode { public string FileName { get; set; } public string FilePath { get; set; } @@ -22,6 +24,8 @@ public partial class AudioFilesTreeNode : ObservableObject public event EventHandler NodeIsExpandedChanged; + IEnumerable IMultiSelectTreeNode.Children => Children; + public static AudioFilesTreeNode CreateContainerNode(string name, AudioFilesTreeNodeType nodeType, AudioFilesTreeNode parent = null) { return new AudioFilesTreeNode diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/AudioProjectTreeNode.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Models/AudioProjectTreeNode.cs similarity index 94% rename from Editors/Audio/AudioEditor/Presentation/Shared/AudioProjectTreeNode.cs rename to Editors/Audio/AudioEditor/Presentation/Shared/Models/AudioProjectTreeNode.cs index 937663974..eb386bd08 100644 --- a/Editors/Audio/AudioEditor/Presentation/Shared/AudioProjectTreeNode.cs +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Models/AudioProjectTreeNode.cs @@ -2,9 +2,9 @@ using CommunityToolkit.Mvvm.ComponentModel; using Editors.Audio.AudioEditor.Presentation.AudioProjectExplorer; using Editors.Audio.Shared.GameInformation.Warhammer3; -using static Editors.Audio.AudioEditor.Presentation.Shared.AudioProjectTreeNodeType; +using static Editors.Audio.AudioEditor.Presentation.Shared.Models.AudioProjectTreeNodeType; -namespace Editors.Audio.AudioEditor.Presentation.Shared +namespace Editors.Audio.AudioEditor.Presentation.Shared.Models { public enum AudioProjectTreeNodeType { diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/Table/DataGridTemplates.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Table/DataGridTemplates.cs index f764347ca..928a52750 100644 --- a/Editors/Audio/AudioEditor/Presentation/Shared/Table/DataGridTemplates.cs +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Table/DataGridTemplates.cs @@ -6,8 +6,9 @@ using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; -using Editors.Audio.AudioEditor.Commands; -using Editors.Audio.AudioEditor.Events; +using Editors.Audio.AudioEditor.Commands.Dialogs; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Enablement; +using Editors.Audio.AudioEditor.Events.AudioProjectEditor.Table; using Shared.Core.Events; namespace Editors.Audio.AudioEditor.Presentation.Shared.Table @@ -230,24 +231,6 @@ public static DataTemplate CreateEditableEventTextBoxTemplate(IEventHub eventHub } })); - //factory.AddHandler(UIElement.PreviewKeyDownEvent, new KeyEventHandler((sender, e) => - //{ - // if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V) - // { - // if (sender is TextBox textBox) - // { - // var clipboardText = string.Empty; - // if (Clipboard.ContainsText()) - // clipboardText = Clipboard.GetText(TextDataFormat.UnicodeText); - - // _ = textBox.Dispatcher.BeginInvoke(new Action(() => - // { - // eventHub.Publish(new EditorDataGridTextboxPastedEvent(clipboardText)); - // }), System.Windows.Threading.DispatcherPriority.Background); - // } - // } - //}), handledEventsToo: true); - template.VisualTree = factory; return template; } diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/Table/ITableService.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Table/ITableService.cs index d36a3abde..4a3ae446a 100644 --- a/Editors/Audio/AudioEditor/Presentation/Shared/Table/ITableService.cs +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Table/ITableService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Data; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; namespace Editors.Audio.AudioEditor.Presentation.Shared.Table { diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableHelpers.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableHelpers.cs index bf2d727da..b6b94e57b 100644 --- a/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableHelpers.cs +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableHelpers.cs @@ -6,15 +6,12 @@ using Editors.Audio.Shared.AudioProject.Models; using Editors.Audio.Shared.GameInformation.Warhammer3; using Editors.Audio.Shared.Storage; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.Shared.Table { - internal static class TableHelpers + public static class TableHelpers { - public static string DuplicateUnderscores(string wtfWpf) => wtfWpf.Replace("_", "__"); - - public static string DeduplicateUnderscores(string wtfWpf) => wtfWpf.Replace("__", "_"); - public static List GetStatesForStateGroupColumn(IAudioEditorStateService audioEditorStateService, IAudioRepository audioRepository, string stateGroup) { var states = new List(); @@ -54,7 +51,7 @@ public static string GetStateGroupFromStateGroupWithQualifier(IAudioRepository a public static string GetValueFromRow(DataRow row, string columnName) => row[columnName].ToString(); - public static string GetActionEventNameFromRow(DataRow row) => GetValueFromRow(row, TableInfo.EventColumnName); + public static string GetActionEventNameFromRow(DataRow row) => GetValueFromRow(row, TableInformation.EventColumnName); public static string GetStatePathNameFromRow(DataRow row, IAudioRepository audioRepository, string dialogueEventName) { @@ -72,7 +69,7 @@ public static string GetStatePathNameFromRow(DataRow row, IAudioRepository audio if (string.IsNullOrEmpty(stateName)) continue; - var stateGroupNameWithQualifier = DeduplicateUnderscores(column.ColumnName); + var stateGroupNameWithQualifier = WpfHelpers.DeduplicateUnderscores(column.ColumnName); var stateGroupName = GetStateGroupFromStateGroupWithQualifier(audioRepository, dialogueEventName, stateGroupNameWithQualifier); var statePathNode = new StatePath.Node @@ -87,7 +84,7 @@ public static string GetStatePathNameFromRow(DataRow row, IAudioRepository audio return statePathName; } - public static string GetStateNameFromRow(DataRow row) => GetValueFromRow(row, TableInfo.StateColumnName); + public static string GetStateNameFromRow(DataRow row) => GetValueFromRow(row, TableInformation.StateColumnName); public static void InsertRowAlphabeticallyByStatePathName(DataTable table, DataRow sourceRow, IAudioRepository audioRepository, string dialogueEventName) { diff --git a/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableInfo.cs b/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableInformation.cs similarity index 86% rename from Editors/Audio/AudioEditor/Presentation/Shared/Table/TableInfo.cs rename to Editors/Audio/AudioEditor/Presentation/Shared/Table/TableInformation.cs index 333f982b1..4e5696af4 100644 --- a/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableInfo.cs +++ b/Editors/Audio/AudioEditor/Presentation/Shared/Table/TableInformation.cs @@ -1,6 +1,6 @@ namespace Editors.Audio.AudioEditor.Presentation.Shared.Table { - public static class TableInfo + public static class TableInformation { public const string EventColumnName = "Event"; public const string BrowseMovieColumnName = "Browse Movie"; diff --git a/Editors/Audio/AudioEditor/Presentation/WaveformVisualiser/WavformVisualiserViewModel.cs b/Editors/Audio/AudioEditor/Presentation/WaveformVisualiser/WavformVisualiserViewModel.cs index 8b636936f..fd4d65520 100644 --- a/Editors/Audio/AudioEditor/Presentation/WaveformVisualiser/WavformVisualiserViewModel.cs +++ b/Editors/Audio/AudioEditor/Presentation/WaveformVisualiser/WavformVisualiserViewModel.cs @@ -9,11 +9,12 @@ using System.Windows.Media.Imaging; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using Editors.Audio.AudioEditor.Events; -using Editors.Audio.AudioEditor.Presentation.Shared.Table; +using Editors.Audio.AudioEditor.Events.AudioFilesExplorer; +using Editors.Audio.AudioEditor.Events.WaveformVisualiser; using Editors.Audio.Shared.Wwise; using NAudio.Wave; using Shared.Core.Events; +using Shared.Ui.Common; namespace Editors.Audio.AudioEditor.Presentation.WaveformVisualiser { @@ -415,7 +416,7 @@ private void UpdateWaveformVisualiserLabel() else { var fileName = Path.GetFileName(_currentFilePathKey); - WaveformVisualiserLabel = $"Sound Engine – {TableHelpers.DuplicateUnderscores(fileName)}"; + WaveformVisualiserLabel = $"Sound Engine – {WpfHelpers.DuplicateUnderscores(fileName)}"; } } diff --git a/Editors/Audio/AudioExplorer/AudioExplorerView.xaml b/Editors/Audio/AudioExplorer/AudioExplorerView.xaml index 4bedacfa4..7eaeff587 100644 --- a/Editors/Audio/AudioExplorer/AudioExplorerView.xaml +++ b/Editors/Audio/AudioExplorer/AudioExplorerView.xaml @@ -1,5 +1,5 @@  - diff --git a/Editors/Audio/AudioExplorer/AudioExplorerView.xaml.cs b/Editors/Audio/AudioExplorer/AudioExplorerView.xaml.cs index 271939ed2..6dc4a62ec 100644 --- a/Editors/Audio/AudioExplorer/AudioExplorerView.xaml.cs +++ b/Editors/Audio/AudioExplorer/AudioExplorerView.xaml.cs @@ -1,8 +1,7 @@ using System.Windows.Controls; using System.Windows.Input; -using Editors.Audio.AudioExplorer; -namespace Audio.AudioExplorer +namespace Editors.Audio.AudioExplorer { public partial class AudioExplorerView : UserControl { diff --git a/Editors/Audio/DependencyInjectionContainer.cs b/Editors/Audio/DependencyInjectionContainer.cs index 8f5276109..c22349978 100644 --- a/Editors/Audio/DependencyInjectionContainer.cs +++ b/Editors/Audio/DependencyInjectionContainer.cs @@ -1,6 +1,8 @@ -using Audio.AudioExplorer; -using Editors.Audio.AudioEditor; -using Editors.Audio.AudioEditor.Commands; +using Editors.Audio.AudioEditor.Commands.AudioFilesExplorer; +using Editors.Audio.AudioEditor.Commands.AudioProjectEditor; +using Editors.Audio.AudioEditor.Commands.AudioProjectMutation; +using Editors.Audio.AudioEditor.Commands.AudioProjectViewer; +using Editors.Audio.AudioEditor.Commands.Dialogs; using Editors.Audio.AudioEditor.Core; using Editors.Audio.AudioEditor.Core.AudioProjectMutation; using Editors.Audio.AudioEditor.Presentation; @@ -41,6 +43,7 @@ public override void Register(IServiceCollection serviceCollection) serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); + serviceCollection.AddScoped(); // Audio Editor View Models serviceCollection.AddScoped(); @@ -49,7 +52,7 @@ public override void Register(IServiceCollection serviceCollection) serviceCollection.AddScoped(); serviceCollection.AddScoped(); serviceCollection.AddScoped(); - var serviceCollection1 = serviceCollection.AddScoped(); + serviceCollection.AddScoped(); // New Audio Project serviceCollection.AddTransient(); @@ -108,7 +111,6 @@ public override void Register(IServiceCollection serviceCollection) serviceCollection.AddTransient(); serviceCollection.AddTransient(); - // Audio Project serviceCollection.AddScoped(); serviceCollection.AddSingleton(); diff --git a/Editors/Audio/Shared/AudioProject/Compiler/AudioProjectCompilerService.cs b/Editors/Audio/Shared/AudioProject/Compiler/AudioProjectCompilerService.cs index 8331aecde..9b5782263 100644 --- a/Editors/Audio/Shared/AudioProject/Compiler/AudioProjectCompilerService.cs +++ b/Editors/Audio/Shared/AudioProject/Compiler/AudioProjectCompilerService.cs @@ -239,21 +239,24 @@ private void GenerateSoundBanks(AudioProjectFile audioProject) private void GenerateDatFiles(AudioProjectFile audioProject, string audioProjectNameWithoutExtension) { - // The .dat file is seems to only necessary for Action Events for movies, quest battles or anything triggered via common.trigger_soundevent() + // In WH3 .dat files only seem necessary for Action Events for movies or anything triggered via common.trigger_soundevent() // but without testing all the different types of Action Event sounds it's safer to just make a .dat for all. // We store States in there so we can display them in the Audio Explorer. var actionEvents = audioProject.GetActionEvents(); - if (actionEvents.Count != 0 && audioProject.StateGroups != null && audioProject.StateGroups.Count != 0) + var hasActionEvents = actionEvents != null && actionEvents.Count > 0; + var hasStateGroups = audioProject.StateGroups != null && audioProject.StateGroups.Count > 0; + + if (hasActionEvents && hasStateGroups) { _logger.Here().Information($"Generating event data .dat"); _datGeneratorService.GenerateEventDatFile(audioProjectNameWithoutExtension, actionEvents, audioProject.StateGroups); } - else if (actionEvents.Count != 0 && audioProject.StateGroups == null) + else if (hasActionEvents && !hasStateGroups) { _logger.Here().Information($"Generating event data .dat"); _datGeneratorService.GenerateEventDatFile(audioProjectNameWithoutExtension, actionEvents: actionEvents); } - else if (actionEvents.Count == 0 && audioProject.StateGroups != null && audioProject.StateGroups.Count != 0) + else if (!hasActionEvents && hasStateGroups) { _logger.Here().Information($"Generating event data .dat"); _datGeneratorService.GenerateEventDatFile(audioProjectNameWithoutExtension, stateGroups: audioProject.StateGroups); diff --git a/Editors/Audio/Shared/AudioProject/Models/HircSettings.cs b/Editors/Audio/Shared/AudioProject/Models/HircSettings.cs index a0463bc39..191d40c53 100644 --- a/Editors/Audio/Shared/AudioProject/Models/HircSettings.cs +++ b/Editors/Audio/Shared/AudioProject/Models/HircSettings.cs @@ -40,6 +40,7 @@ public static HircSettings CreateRandomSequenceContainerSettings(HircSettings hi return new HircSettings { ContainerType = hircSettings.ContainerType, + RandomType = hircSettings.RandomType, EnableRepetitionInterval = hircSettings.EnableRepetitionInterval, RepetitionInterval = hircSettings.RepetitionInterval, PlaylistEndBehaviour = hircSettings.PlaylistEndBehaviour, diff --git a/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3ActionEventInformation.cs b/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3ActionEventInformation.cs index a635098dd..b187242e1 100644 --- a/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3ActionEventInformation.cs +++ b/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3ActionEventInformation.cs @@ -39,7 +39,7 @@ public static class Wh3ActionEventInformation new("Battle Advice", Wh3ActionEventType.BattleAdvice, Wh3SoundBank.BattleAdvice, ActorMixerId: 142435894), // Reference: Play_wh2_dlc13_camp_advice_emp_emperors_mandate_001_1 - new("Battle Advice", Wh3ActionEventType.CampaignAdvice, Wh3SoundBank.CampaignAdvice, ActorMixerId: 517250292), + new("Campaign Advice", Wh3ActionEventType.CampaignAdvice, Wh3SoundBank.CampaignAdvice, ActorMixerId: 517250292), // Reference: Battle_Individual_Ability_Storm_Dragon_To_Human_Form_Transform new("Battle Abilities", BattleAbilities, BattleIndividualMagic, ActorMixerId: 140075115), diff --git a/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3DialogueEventInformation.cs b/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3DialogueEventInformation.cs index 22b8c2751..95da035e3 100644 --- a/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3DialogueEventInformation.cs +++ b/Editors/Audio/Shared/GameInformation/Warhammer3/Wh3DialogueEventInformation.cs @@ -47,6 +47,12 @@ public enum Wh3DialogueEventType [Display(Name = "Mechanic - Scrap")] ScrapMechanic, [Display(Name = "Mechanic - Skull Throne")] SkullThroneMechanic, [Display(Name = "Mechanic - Monster Pens")] MonsterPensMechanic, + [Display(Name = "Mechanic - Monstrous Arcanum")] MonstrousArcanumMechanic, + [Display(Name = "Mechanic - Daemonic Attraction")] DaemonicAttraction, + [Display(Name = "Mechanic - Pleasurable Act")] PleasurableActMechanic, + [Display(Name = "Mechanic - Bribe")] BribeMechanic, + [Display(Name = "Mechanic - Dark Ritual")] DarkRitualMechanic, + [Display(Name = "Mechanic - Slaanesh Misc")] SlaaneshMechanicsMisc, [Display(Name = "Unit Movement")] UnitMovement, [Display(Name = "Unit Attack")] UnitAttack, [Display(Name = "Unit Selection")] UnitSelection, @@ -208,7 +214,8 @@ public static class Wh3DialogueEventInformation new("campaign_vo_yes", CampaignVO, [TypeShowAll, CharacterMovement], [ProfileShowAll, ..LordHeroMinimumProfiles]), new("campaign_vo_yes_short", CampaignVO, [TypeShowAll, CharacterMovement], [ProfileShowAll, ..LordHeroMinimumProfiles]), new("campaign_vo_yes_short_aggressive", CampaignVO, [TypeShowAll, CharacterMovement], [ProfileShowAll, ..LordHeroMinimumProfiles]), - + new("campaign_vo_stance_disembark", CampaignVO, [TypeShowAll, CharacterMovement], [ProfileShowAll, ..LordHeroRecommendedProfiles]), + new("campaign_vo_cam_skill_weapon_tree", CampaignVO, [TypeShowAll, CharacterSkillTree], [ProfileShowAll, ..LordHeroCompleteProfiles]), new("campaign_vo_cam_skill_weapon_tree_response", CampaignVO, [TypeShowAll, CharacterSkillTree], [ProfileShowAll, ..LordHeroCompleteProfiles]), @@ -266,6 +273,23 @@ public static class Wh3DialogueEventInformation new("campaign_vo_def_recruit_monster_pens", CampaignVO, [MonsterPensMechanic], [ProfileShowAll, LordComplete]), new("campaign_vo_mounted_creature", CampaignVO, [TypeShowAll, Creature], [ProfileShowAll]), + + new("campaign_vo_nor_monstrous_arcanum_ceremony", CampaignVO, [TypeShowAll, MonstrousArcanumMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_nor_monstrous_arcanum_hunt_killing", CampaignVO, [TypeShowAll, MonstrousArcanumMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_nor_monstrous_arcanum_hunt_taming", CampaignVO, [TypeShowAll, MonstrousArcanumMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_attack_monstrous_arcanum_hunt", CampaignVO, [TypeShowAll, MonstrousArcanumMechanic], [ProfileShowAll, LordComplete]), + + new("campaign_vo_sla_daemonic_attraction_recruit", CampaignVO, [TypeShowAll, DaemonicAttraction], [ProfileShowAll, LordComplete]), + + new("campaign_vo_sla_pleasurable_act_arena", CampaignVO, [TypeShowAll, PleasurableActMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_sla_pleasurable_act_hunt", CampaignVO, [TypeShowAll, PleasurableActMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_sla_pleasurable_act_party", CampaignVO, [TypeShowAll, PleasurableActMechanic], [ProfileShowAll, LordComplete]), + + // These are apparently campaign_vo even though they have campaign_vo_cs in the name, maybe CA put them in the wrong bnk? + new("campaign_vo_cs_dark_ritual_unlock_tier_1", CampaignVO, [TypeShowAll, DarkRitualMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_dark_ritual_unlock_tier_2", CampaignVO, [TypeShowAll, DarkRitualMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_dark_ritual_unlock_tier_3", CampaignVO, [TypeShowAll, DarkRitualMechanic], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_dark_ritual_unlock_tier_4", CampaignVO, [TypeShowAll, DarkRitualMechanic], [ProfileShowAll, LordComplete]), ]; public static List CampaignConversational { get; } = @@ -328,6 +352,23 @@ public static class Wh3DialogueEventInformation new("campaign_vo_cs_post_battle_settlement_kho_blood_for_the_blood_god", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), new("campaign_vo_cs_post_battle_settlement_tze_parasitic", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), new("campaign_vo_cs_post_battle_settlement_tze_symbiotic", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_establish_colony", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_pleasure_palace", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_raze_ulthuan", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_reinstate_lord", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_sack_ulthuan", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_thrall_camp", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_settlement_war_pit", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_nor_crow", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_nor_eagle", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_nor_hound", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_nor_raise_altar", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_nor_serpent", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_nor_undivided", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_warlord_alliance", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_warlord_confederate", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_warlord_execute", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_post_battle_warlord_release", CampaignVOConversational, [TypeShowAll, PostBattleSettlementAction], [ProfileShowAll, LordComplete]), new("campaign_vo_cs_other_character_details_panel_low_loyalty", CampaignVOConversational, [TypeShowAll, CharacterDetails], [ProfileShowAll, LordComplete]), new("campaign_vo_cs_other_character_details_panel_neutral", CampaignVOConversational, [TypeShowAll, CharacterDetails], [ProfileShowAll, LordComplete]), @@ -370,6 +411,11 @@ public static class Wh3DialogueEventInformation new("campaign_vo_cs_ogr_mercenary_contracts", CampaignVOConversational, [TypeShowAll, MercenaryContractsMechanic], [ProfileShowAll, LordComplete]), new("campaign_vo_cs_ogr_meat_status", CampaignVOConversational, [TypeShowAll, MeatMechanic], [ProfileShowAll, LordComplete]), + + new("campaign_vo_cs_bribe", CampaignVOConversational, [TypeShowAll, SlaaneshMechanicsMisc], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_sla_disciple_army", CampaignVOConversational, [TypeShowAll, SlaaneshMechanicsMisc], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_sla_proliferate_cults", CampaignVOConversational, [TypeShowAll, SlaaneshMechanicsMisc], [ProfileShowAll, LordComplete]), + new("campaign_vo_cs_sla_corrupt_units", CampaignVOConversational, [TypeShowAll, SlaaneshMechanicsMisc], [ProfileShowAll, LordComplete]), ]; public static List Battle { get; } = diff --git a/Editors/Audio/Shared/UI/Converters/EnumConverter.cs b/Editors/Audio/Shared/UI/ValueConverters/EnumConverter.cs similarity index 97% rename from Editors/Audio/Shared/UI/Converters/EnumConverter.cs rename to Editors/Audio/Shared/UI/ValueConverters/EnumConverter.cs index 042a390ff..0ece0839c 100644 --- a/Editors/Audio/Shared/UI/Converters/EnumConverter.cs +++ b/Editors/Audio/Shared/UI/ValueConverters/EnumConverter.cs @@ -4,7 +4,7 @@ using Editors.Audio.Shared.GameInformation.Warhammer3; using Editors.Audio.Shared.Wwise; -namespace Editors.Audio.Shared.UI.Converters +namespace Editors.Audio.Shared.UI.ValueConverters { public class EnumConverter : IValueConverter { diff --git a/Editors/Audio/Shared/UI/Converters/ImageConverter.cs b/Editors/Audio/Shared/UI/ValueConverters/ImageConverter.cs similarity index 89% rename from Editors/Audio/Shared/UI/Converters/ImageConverter.cs rename to Editors/Audio/Shared/UI/ValueConverters/ImageConverter.cs index 2fb07c772..d98df912f 100644 --- a/Editors/Audio/Shared/UI/Converters/ImageConverter.cs +++ b/Editors/Audio/Shared/UI/ValueConverters/ImageConverter.cs @@ -1,10 +1,10 @@ using System; using System.Windows.Data; using System.Windows.Media.Imaging; +using Editors.Audio.AudioEditor.Presentation.Shared.Models; using Shared.EmbeddedResources; -using Editors.Audio.AudioEditor.Presentation.Shared; -namespace Editors.Audio.Shared.UI.Converters +namespace Editors.Audio.Shared.UI.ValueConverters { [ValueConversion(typeof(AudioFilesTreeNode), typeof(BitmapImage))] public class ImageConverter : IValueConverter diff --git a/Shared/SharedUI/Common/WpfHelpers.cs b/Shared/SharedUI/Common/WpfHelpers.cs new file mode 100644 index 000000000..1843cb152 --- /dev/null +++ b/Shared/SharedUI/Common/WpfHelpers.cs @@ -0,0 +1,9 @@ +namespace Shared.Ui.Common +{ + public static class WpfHelpers + { + + public static string DeduplicateUnderscores(string wtfWpf) => wtfWpf.Replace("__", "_"); + public static string DuplicateUnderscores(string wtfWpf) => wtfWpf.Replace("_", "__"); + } +}