A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
DialogueEditor.cpp
Go to the documentation of this file.
1// Copyright Csaba Molnar, Daniel Butum. All Rights Reserved.
2#include "DialogueEditor.h"
3
4#include "Editor.h"
5#include "SSingleObjectDetailsPanel.h"
6#include "Widgets/Docking/SDockTab.h"
7#include "ScopedTransaction.h"
8#include "Framework/Application/SlateApplication.h"
9#include "PropertyEditorModule.h"
10#include "GraphEditor.h"
11#include "Toolkits/IToolkitHost.h"
12#include "IDetailsView.h"
13#include "Framework/Commands/GenericCommands.h"
14#include "GraphEditorActions.h"
15#include "Modules/ModuleManager.h"
16#include "Framework/MultiBox/MultiBoxBuilder.h"
17#include "EdGraphUtilities.h"
18#include "HAL/PlatformApplicationMisc.h"
19
21#include "DlgDialogue.h"
22#include "DlgHelper.h"
23#include "SDialoguePalette.h"
24#include "SDialogueActionMenu.h"
29#include "DialogueCommands.h"
34
35#define LOCTEXT_NAMESPACE "DialogueEditor"
36
37// define constants
38const FName FDialogueEditor::DetailsTabID(TEXT("DialogueEditor_Details"));
39const FName FDialogueEditor::GraphCanvasTabID(TEXT("DialogueEditor_GraphCanvas"));
40const FName FDialogueEditor::PaletteTabId(TEXT("DialogueEditor_Palette"));
41const FName FDialogueEditor::FindInDialogueTabId(TEXT("DialogueEditor_Find"));
42const FName DialogueEditorAppName = FName(TEXT("DialogueEditorAppName"));
43
45// FDialogueEditor
46FDialogueEditor::FDialogueEditor() : DialogueBeingEdited(nullptr)
47{
48 GEditor->RegisterForUndo(this);
49}
50
52{
53 GEditor->UnregisterForUndo(this);
54}
55
57// Begin IToolkit interface
58void FDialogueEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager)
59{
60 WorkspaceMenuCategory = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_DialogueEditor", "Dialogue Editor"));
61 const TSharedRef<FWorkspaceItem> WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef();
62
63 FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
64
65 // spawn tabs
66 InTabManager->RegisterTabSpawner(
68 FOnSpawnTab::CreateSP(this, &Self::SpawnTab_GraphCanvas)
69 )
70 .SetDisplayName(LOCTEXT("GraphCanvasTab", "Viewport"))
71 .SetGroup(WorkspaceMenuCategoryRef)
72 .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "GraphEditor.EventGraph_16x"));
73
74 InTabManager->RegisterTabSpawner(
76 FOnSpawnTab::CreateSP(this, &Self::SpawnTab_Details)
77 )
78 .SetDisplayName(LOCTEXT("DetailsTabLabel", "Details"))
79 .SetGroup(WorkspaceMenuCategoryRef)
80 .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details"));
81
82 InTabManager->RegisterTabSpawner(
84 FOnSpawnTab::CreateSP(this, &Self::SpawnTab_Palette)
85 )
86 .SetDisplayName(LOCTEXT("PaletteTab", "Palette"))
87 .SetGroup(WorkspaceMenuCategoryRef)
88 .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Palette"));
89
90 InTabManager->RegisterTabSpawner(
92 FOnSpawnTab::CreateSP(this, &Self::SpawnTab_FindInDialogue)
93 )
94 .SetDisplayName(LOCTEXT("FindInDialogueTab", "Find Results"))
95 .SetGroup(WorkspaceMenuCategoryRef)
96 .SetIcon(FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.Tabs.FindResults"));
97}
98
99void FDialogueEditor::UnregisterTabSpawners(const TSharedRef<class FTabManager>& InTabManager)
100{
101 FAssetEditorToolkit::UnregisterTabSpawners(InTabManager);
102
103 InTabManager->UnregisterTabSpawner(GraphCanvasTabID);
104 InTabManager->UnregisterTabSpawner(DetailsTabID);
105 InTabManager->UnregisterTabSpawner(PaletteTabId);
106 InTabManager->UnregisterTabSpawner(FindInDialogueTabId);
107}
108
110{
111 return LOCTEXT("DialogueEditorAppLabel", "Dialogue Editor");
112}
113
115{
116 const bool bDirtyState = DialogueBeingEdited->GetOutermost()->IsDirty();
117
118 FFormatNamedArguments Args;
119 Args.Add(TEXT("DialogueName"), FText::FromString(DialogueBeingEdited->GetName()));
120 Args.Add(TEXT("DirtyState"), bDirtyState ? FText::FromString(TEXT("*")) : FText::GetEmpty());
121 return FText::Format(LOCTEXT("DialogueEditorToolkitName", "{DialogueName}{DirtyState}"), Args);
122}
123// End of IToolkit Interface
125
127// Begin FAssetEditorToolkit
129{
130 FAssetEditorToolkit::SaveAsset_Execute();
131}
132
134{
135 FAssetEditorToolkit::SaveAssetAs_Execute();
136}
137// End of FAssetEditorToolkit
139
141// Begin IAssetEditorInstance
143{
144 BringToolkitToFront();
145 JumpToObject(ObjectToFocusOn);
146}
147// End of IAssetEditorInstance
149
151// Begin FEditorUndoClient Interface
152void FDialogueEditor::PostUndo(bool bSuccess)
153{
154 if (bSuccess)
155 {
156 Refresh(false);
157 CheckAll();
158 }
159}
160
161void FDialogueEditor::PostRedo(bool bSuccess)
162{
163 if (bSuccess)
164 {
165 Refresh(false);
166 CheckAll();
167 }
168}
169// End of FEditorUndoClient Interface
171
173// Begin IDialogueEditor
174
175void FDialogueEditor::RefreshDetailsView(bool bRestorePreviousSelection)
176{
177 if (DetailsView.IsValid())
178 {
180 {
181 DetailsView->SetObject(DialogueBeingEdited, true);
182 }
183 else
184 {
185 DetailsView->ForceRefresh();
186 }
187 DetailsView->ClearSearch();
188 }
189
190 if (bRestorePreviousSelection)
191 {
192 // Create local copy because this can be changed by node selection again
193 TArray<TWeakObjectPtr<UObject>> ArrayCopy = PreviousSelectedNodeObjects;
194
195 // Select all previous nodes
196 for (const TWeakObjectPtr<UObject>& WeakObj : ArrayCopy)
197 {
198 if (!WeakObj.IsValid(false))
199 {
200 continue;
201 }
202
203 UObject* Object = WeakObj.Get();
204 if (!IsValid(Object))
205 {
206 continue;
207 }
208
209 UEdGraphNode* GraphNode = Cast<UEdGraphNode>(Object);
210 if (!IsValid(GraphNode))
211 {
212 continue;
213 }
214
215 GraphEditorView->SetNodeSelection(const_cast<UEdGraphNode*>(GraphNode), true);
216 }
217 }
218}
219
220void FDialogueEditor::Refresh(bool bRestorePreviousSelection)
221{
224 RefreshDetailsView(bRestorePreviousSelection);
225 FSlateApplication::Get().DismissAllMenus();
226}
227
229{
230 // Ignore invalid objects
231 if (!IsValid(Object) || !GraphEditorView.IsValid())
232 {
233 return;
234 }
235
236 const UEdGraphNode* GraphNode = Cast<UEdGraphNode>(Object);
237 if (!IsValid(GraphNode))
238 {
239 return;
240 }
241
242 // Are we in the same graph?
243 if (DialogueBeingEdited->GetGraph() != GraphNode->GetGraph())
244 {
245 return;
246 }
247
248 // TODO create custom SGraphEditor
249 // Not part of the graph anymore :(
250 if (!DialogueBeingEdited->GetGraph()->Nodes.Contains(GraphNode))
251 {
252 return;
253 }
254
255 // Jump to the node
256 static constexpr bool bRequestRename = false;
257 static constexpr bool bSelectNode = true;
258 Refresh(false);
259 GraphEditorView->JumpToNode(GraphNode, bRequestRename, bSelectNode);
260
261 // Select from JumpNode seems to be buggy sometimes, WE WILL DO IT OURSELFS!
262 // I know, I know, it is not my fault that SetNodeSelection does not have the graph node as const, sigh
263 GraphEditorView->SetNodeSelection(const_cast<UEdGraphNode*>(GraphNode), bSelectNode);
264}
265// End of IDialogueEditor
267
269// Begin own functions
270void FDialogueEditor::SummonSearchUI(bool bSetFindWithinDialogue, FString NewSearchTerms, bool bSelectFirstResult)
271{
272 TSharedPtr<SFindInDialogues> FindResultsToUse;
273 if (bSetFindWithinDialogue)
274 {
275 // Open local tab
276 FindResultsToUse = FindResultsView;
278 }
279 else
280 {
281 // Open global tab
282 FindResultsToUse = FDialogueSearchManager::Get()->GetGlobalFindResults();
283 }
284
285 if (FindResultsToUse.IsValid())
286 {
288 Filter.SearchString = NewSearchTerms;
289 FindResultsToUse->FocusForUse(bSetFindWithinDialogue, Filter, bSelectFirstResult);
290 }
291}
292
294 EToolkitMode::Type Mode,
295 const TSharedPtr<IToolkitHost>& InitToolkitHost,
296 UDlgDialogue* InitDialogue
297)
298{
299 Settings = GetMutableDefault<UDlgSystemSettings>();
300
301 // close all other editors editing this asset
303 DialogueBeingEdited = InitDialogue;
305
306 // Bind Undo/Redo methods
307 DialogueBeingEdited->SetFlags(RF_Transactional);
308
309 // Gather data for the showing of primary/secondary edges
310 if (GetSettings().bShowPrimarySecondaryEdges)
311 {
312 DialogueBeingEdited->InitialCompileDialogueNodesFromGraphNodes();
313 }
314
315 // Bind commands
316 FGraphEditorCommands::Register();
317 FDialogueCommands::Register();
320
321 // Default layout
322 const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout =
323 FTabManager::NewLayout("Standalone_DialogueEditor_Layout_v1")
324 ->AddArea
325 (
326 FTabManager::NewPrimaryArea()
327 ->SetOrientation(Orient_Vertical)
328 ->Split
329 (
330 // Toolbar
331 FTabManager::NewStack()
332 ->SetSizeCoefficient(0.1f)
333 ->AddTab(GetToolbarTabId(), ETabState::OpenedTab)
334 ->SetHideTabWell(true)
335 )
336 ->Split
337 (
338 // Main Application area
339 FTabManager::NewSplitter()
340 ->SetOrientation(Orient_Horizontal)
341 ->SetSizeCoefficient(0.9f)
342 ->Split
343 (
344 // Left
345 // Details tab
346 FTabManager::NewStack()
347 ->SetSizeCoefficient(0.3f)
348 ->AddTab(DetailsTabID, ETabState::OpenedTab)
349 )
350 ->Split
351 (
352 // Middle
353 FTabManager::NewSplitter()
354 ->SetOrientation(Orient_Vertical)
355 ->SetSizeCoefficient(0.6f)
356 ->Split
357 (
358 // Top
359 // Graph canvas
360 FTabManager::NewStack()
361 ->SetSizeCoefficient(0.8f)
362 ->SetHideTabWell(true)
363 ->AddTab(GraphCanvasTabID, ETabState::OpenedTab)
364 )
365 ->Split
366 (
367 // Bottom
368 // Find Dialogue results
369 FTabManager::NewStack()
370 ->SetSizeCoefficient(0.2f)
371 ->AddTab(FindInDialogueTabId, ETabState::ClosedTab)
372 )
373
374 )
375 ->Split
376 (
377 // Right
378 // Properties tab
379 FTabManager::NewStack()
380 ->SetSizeCoefficient(0.1f)
381 ->AddTab(PaletteTabId, ETabState::OpenedTab)
382 )
383
384 )
385 );
386
387 // Initialize the asset editor and spawn nothing (dummy layout)
388 constexpr bool bCreateDefaultStandaloneMenu = true;
389 constexpr bool bCreateDefaultToolbar = true;
390 constexpr bool bInIsToolbarFocusable = false;
391 FAssetEditorToolkit::InitAssetEditor(Mode, InitToolkitHost, DialogueEditorAppName, StandaloneDefaultLayout,
392 bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, /*ObjectToEdit =*/ InitDialogue, bInIsToolbarFocusable);
393
394 // extend menus and toolbar
395 ExtendMenu();
397 RegenerateMenusAndToolbars();
398
399 // Default show all nodes on editor open
401}
402
404{
405#if DO_CHECK
406 check(DialogueBeingEdited);
408 for (UEdGraphNode* GraphNode : Graph->Nodes)
409 {
410 check(GraphNode);
411 }
412
414 for (UDialogueGraphNode* GraphNode : Graph->GetAllDialogueGraphNodes())
415 {
416 GraphNode->CheckAll();
417 }
418#endif
419}
420
422{
423 // TODO do we need this method?
424
425 // not different or a null poointer, do not set anything
426 if (NewDialogue == DialogueBeingEdited || !IsValid(NewDialogue))
427 return;
428
429 // set to the new dialogue
430 UDlgDialogue* OldDialogue = DialogueBeingEdited;
431 DialogueBeingEdited = NewDialogue;
432
433 // Let the viewport know that we are editing something different
434
435 // Let the editor know that are editing something different
436 RemoveEditingObject(OldDialogue);
437 AddEditingObject(NewDialogue);
438
439 // Update the asset picker to select the new active dialogue
440}
441
442void FDialogueEditor::NotifyPostChange(const FPropertyChangedEvent& PropertyChangedEvent, FNYProperty* PropertyThatChanged)
443{
444 if (GraphEditorView.IsValid() && PropertyChangedEvent.ChangeType != EPropertyChangeType::Interactive)
445 {
446 GraphEditorView->NotifyGraphChanged();
447 }
448}
449
451{
452 // The graph Viewport
454
455 // Details View (properties panel)
456 FDetailsViewArgs DetailsViewArgs;
457 DetailsViewArgs.bUpdatesFromSelection = false;
458 DetailsViewArgs.bLockable = false;
459 DetailsViewArgs.bAllowSearch = true;
460 DetailsViewArgs.NotifyHook = this;
461 DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::ObjectsUseNameArea;
462 DetailsViewArgs.bHideSelectionTip = false;
463
464 FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
465 DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs);
467
468 // Pallete view
470
471 // Find Results
472 FindResultsView = SNew(SFindInDialogues, SharedThis(this));
473}
474
476{
477 check(DialogueBeingEdited);
478 // Customize the appearance of the graph.
479 FGraphAppearanceInfo AppearanceInfo;
480 // The text that appears on the bottom right corner in the graph view.
481 AppearanceInfo.CornerText = LOCTEXT("AppearanceCornerText_DlgDialogue", "DIALOGUE");
482 AppearanceInfo.InstructionText = LOCTEXT("AppearanceInstructionText_DlgDialogue", "Right Click to add new nodes.");
483
484 // Bind graph events actions from the editor
485 SGraphEditor::FGraphEditorEvents InEvents;
486 InEvents.OnTextCommitted = FOnNodeTextCommitted::CreateSP(this, &FDialogueEditor::OnNodeTitleCommitted);
487 InEvents.OnSelectionChanged = SGraphEditor::FOnSelectionChanged::CreateSP(this, &FDialogueEditor::OnSelectedNodesChanged);
488 InEvents.OnCreateActionMenu = SGraphEditor::FOnCreateActionMenu::CreateSP(this, &FDialogueEditor::OnCreateGraphActionMenu);
489
490 return SNew(SGraphEditor)
491 .AdditionalCommands(GraphEditorCommands)
492 .IsEditable(true)
493 .Appearance(AppearanceInfo)
494 .GraphToEdit(DialogueBeingEdited->GetGraph())
495 .GraphEvents(InEvents)
496 .ShowGraphStateOverlay(false);
497}
498
500{
501 // Prevent duplicate assigns. This should never happen
502 if (GraphEditorCommands.IsValid())
503 {
504 return;
505 }
506 GraphEditorCommands = MakeShared<FUICommandList>();
507
508 // Graph Editor Commands
509 // Create comment node on graph. Default when you press the "C" key on the keyboard to create a comment.
510 GraphEditorCommands->MapAction(
511 FGraphEditorCommands::Get().CreateComment,
512 FExecuteAction::CreateLambda([this]
513 {
515 CommentAction.PerformAction(DialogueBeingEdited->GetGraph(), nullptr, GraphEditorView->GetPasteLocation());
516 })
517 );
518
519 GraphEditorCommands->MapAction(
520 FGenericCommands::Get().SelectAll,
521 FExecuteAction::CreateLambda([this] { GraphEditorView->SelectAllNodes(); } ),
522 FCanExecuteAction::CreateLambda([] { return true; })
523 );
524
525 // Edit Node commands
526 const auto DialogueCommands = FDialogueCommands::Get();
527 GraphEditorCommands->MapAction(
528 DialogueCommands.ConvertSpeechSequenceNodeToSpeechNodes,
529 FExecuteAction::CreateSP(this, &Self::OnCommandConvertSpeechSequenceNodeToSpeechNodes),
530 FCanExecuteAction::CreateLambda([this]
531 {
532 return FDialogueEditorUtilities::CanConvertSpeechSequenceNodeToSpeechNodes(GetSelectedNodes());
533 })
534 );
535
536 GraphEditorCommands->MapAction(
537 DialogueCommands.ConvertSpeechNodesToSpeechSequence,
538 FExecuteAction::CreateSP(this, &Self::OnCommandConvertSpeechNodesToSpeechSequence),
539 FCanExecuteAction::CreateLambda([this]
540 {
541 return FDialogueEditorUtilities::CanConvertSpeechNodesToSpeechSequence(GetSelectedNodes());
542 })
543 );
544
545 GraphEditorCommands->MapAction(
546 FGenericCommands::Get().Delete,
547 FExecuteAction::CreateSP(this, &Self::OnCommandDeleteSelectedNodes),
548 FCanExecuteAction::CreateSP(this, &Self::CanDeleteNodes)
549 );
550
551 GraphEditorCommands->MapAction(
552 FGenericCommands::Get().Copy,
553 FExecuteAction::CreateRaw(this, &Self::OnCommandCopySelectedNodes),
554 FCanExecuteAction::CreateRaw(this, &Self::CanCopyNodes)
555 );
556
557 GraphEditorCommands->MapAction(
558 FGenericCommands::Get().Paste,
559 FExecuteAction::CreateRaw(this, &Self::OnCommandPasteNodes),
560 FCanExecuteAction::CreateRaw(this, &Self::CanPasteNodes)
561 );
562
563 // Hide/Unhide nodes
564 GraphEditorCommands->MapAction(
565 DialogueCommands.HideNodes,
566 FExecuteAction::CreateRaw(this, &Self::OnCommandHideSelectedNodes)
567 );
568
569 GraphEditorCommands->MapAction(
570 DialogueCommands.UnHideAllNodes,
571 FExecuteAction::CreateRaw(this, &Self::OnCommandUnHideAllNodes)
572 );
573
574 // Toolikit/Toolbar commands/Menu Commands
575 // Undo Redo menu options
576 ToolkitCommands->MapAction(
577 FGenericCommands::Get().Undo,
578 FExecuteAction::CreateSP(this, &Self::OnCommandUndoGraphAction)
579 );
580
581 ToolkitCommands->MapAction(
582 FGenericCommands::Get().Redo,
583 FExecuteAction::CreateSP(this, &Self::OnCommandRedoGraphAction)
584 );
585
586 // The toolbar reload button
587 ToolkitCommands->MapAction(
588 DialogueCommands.DialogueReloadData,
589 FExecuteAction::CreateSP(this, &Self::OnCommandDialogueReload),
590 FCanExecuteAction::CreateLambda([this]
591 {
592 return GetSettings().DialogueTextFormat != EDlgDialogueTextFormat::None;
593 })
594 );
595
596 // The Show primary/secondary edge buttons
597 ToolkitCommands->MapAction(
598 DialogueCommands.ToggleShowPrimarySecondaryEdges,
599 FExecuteAction::CreateLambda([this]
600 {
601 Settings->SetShowPrimarySecondaryEdges(!GetSettings().bShowPrimarySecondaryEdges);
602 if (GetSettings().bShowPrimarySecondaryEdges)
603 {
604 DialogueBeingEdited->InitialCompileDialogueNodesFromGraphNodes();
605 }
606 }),
607 FCanExecuteAction::CreateLambda([] { return true; } ),
608 FIsActionChecked::CreateLambda([this] { return GetSettings().bShowPrimarySecondaryEdges; })
609 );
610
611 ToolkitCommands->MapAction(
612 DialogueCommands.ToggleDrawPrimaryEdges,
613 FExecuteAction::CreateLambda([this] { Settings->SetDrawPrimaryEdges(!GetSettings().bDrawPrimaryEdges); }),
614 FCanExecuteAction::CreateLambda([this] { return GetSettings().bShowPrimarySecondaryEdges; }),
615 FIsActionChecked::CreateLambda([this] { return GetSettings().bDrawPrimaryEdges; })
616 );
617
618 ToolkitCommands->MapAction(
619 DialogueCommands.ToggleDrawSecondaryEdges,
620 FExecuteAction::CreateLambda([this] { Settings->SetDrawSecondaryEdges(!GetSettings().bDrawSecondaryEdges); }),
621 FCanExecuteAction::CreateLambda([this] { return GetSettings().bShowPrimarySecondaryEdges; }),
622 FIsActionChecked::CreateLambda([this] { return GetSettings().bDrawSecondaryEdges; })
623 );
624
625 // Find in All Dialogues
626 ToolkitCommands->MapAction(
627 FDialogueCommands::Get().FindInAllDialogues,
628 FExecuteAction::CreateLambda([this] { SummonSearchUI(false); })
629 );
630
631 // Find in current Dialogue
632 ToolkitCommands->MapAction(
633 FDialogueCommands::Get().FindInDialogue,
634 FExecuteAction::CreateLambda([this] { SummonSearchUI(true); })
635 );
636
637 // Map the global actions
640
641 ToolkitCommands->MapAction(
642 FDialogueCommands::Get().DeleteCurrentDialogueTextFiles,
643 FExecuteAction::CreateLambda([this]
644 {
645 check(DialogueBeingEdited);
646 const FString Text = TEXT("Delete All text files for this Dialogue?");
647 const EAppReturnType::Type Response = FPlatformMisc::MessageBoxExt(EAppMsgType::YesNo, *Text, *Text);
648 if (Response == EAppReturnType::Yes)
649 {
650 DialogueBeingEdited->DeleteAllTextFiles();
651 }
652 })
653 );
654}
655
657{
658 TSharedPtr<FExtender> MenuExtender = MakeShared<FExtender>();
659
660 // Extend the Edit menu
661 MenuExtender->AddMenuExtension(
662 "EditHistory",
663 EExtensionHook::After,
664 ToolkitCommands,
665 FMenuExtensionDelegate::CreateLambda([this](FMenuBuilder& MenuBuilder)
666 {
667 MenuBuilder.BeginSection("EditSearch", LOCTEXT("EditMenu_SearchHeading", "Search") );
668 {
669 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().FindInDialogue);
670 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().FindInAllDialogues);
671 }
672 MenuBuilder.EndSection();
673 })
674 );
675
676 AddMenuExtender(MenuExtender);
677
678 AddMenuExtender(
680 ToolkitCommands,
681 {FDialogueCommands::Get().DeleteCurrentDialogueTextFiles}
682 )
683 );
684 AddMenuExtender(FDlgSystemEditorModule::CreateHelpMenuExtender(ToolkitCommands));
685}
686
688{
689 constexpr bool bShouldCloseWindowAfterMenuSelection = true;
690 FMenuBuilder MenuBuilder(bShouldCloseWindowAfterMenuSelection, ToolkitCommands, {});
691 MenuBuilder.BeginSection("ViewingOptions", LOCTEXT("PrimarySecondaryEdgesMenu", "Viewing Options"));
692 {
693 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().ToggleDrawPrimaryEdges);
694 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().ToggleDrawSecondaryEdges);
695 }
696 MenuBuilder.EndSection();
697
698 return MenuBuilder.MakeWidget();
699}
700
702{
703 constexpr bool bShouldCloseWindowAfterMenuSelection = true;
704 FMenuBuilder MenuBuilder(bShouldCloseWindowAfterMenuSelection, ToolkitCommands, {});
705 MenuBuilder.BeginSection("OtherURls", LOCTEXT("OtherURLsMenu", "Other URLs"));
706 {
707 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().OpenMarketplace);
708 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().OpenWiki);
709 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().OpenDiscord);
710 MenuBuilder.AddMenuEntry(FDialogueCommands::Get().OpenForum);
711 }
712 MenuBuilder.EndSection();
713
714 return MenuBuilder.MakeWidget();
715}
716
718{
719 // Make toolbar to the right of the Asset Toolbar (Save and Find in content browser buttons).
720 {
721 TSharedPtr<FExtender> ToolbarExtender = MakeShared<FExtender>();
722 ToolbarExtender->AddToolBarExtension(
723 "Asset",
724 EExtensionHook::After,
725 ToolkitCommands,
726 FToolBarExtensionDelegate::CreateLambda([this](FToolBarBuilder& ToolbarBuilder)
727 {
728 ToolbarBuilder.BeginSection("Dialogue");
729 {
730 ToolbarBuilder.AddToolBarButton(FDialogueCommands::Get().DialogueReloadData);
731 ToolbarBuilder.AddToolBarButton(FDialogueCommands::Get().FindInDialogue);
732
733 ToolbarBuilder.AddToolBarButton(FDialogueCommands::Get().ToggleShowPrimarySecondaryEdges);
734 ToolbarBuilder.AddComboButton(
735 FUIAction(
736 FExecuteAction(),
737 FCanExecuteAction::CreateLambda([this] {
738 // only when the show/primary secondary edges is true
740 })
741 ),
742 FOnGetContent::CreateSP(this, &Self::GeneratePrimarySecondaryEdgesMenu),
743 LOCTEXT("PrimarySecondaryEdges", "Viewing Options"),
744 LOCTEXT("PrimarySecondaryEdges_ToolTip", "Viewing settings"),
745 FSlateIcon(),
746 true
747 );
748 }
749 ToolbarBuilder.EndSection();
750 })
751 );
752 AddToolbarExtender(ToolbarExtender);
753 }
754
755 // Add External URLs
756 if (GetSettings().bShowExternalURLsToolbar)
757 {
758 TSharedPtr<FExtender> ExternalToolbarExtender = MakeShared<FExtender>();
759 ExternalToolbarExtender->AddToolBarExtension(
760 "Asset",
761 EExtensionHook::After,
762 ToolkitCommands,
763 FToolBarExtensionDelegate::CreateLambda([this](FToolBarBuilder& ToolbarBuilder)
764 {
765 ToolbarBuilder.BeginSection("DialogueExternal");
766 {
767 ToolbarBuilder.AddToolBarButton(
768 FDialogueCommands::Get().OpenNotYetPlugins,
769 NAME_None,
770 LOCTEXT("NotYetPlugins", "Not Yet: Plugins"),
771 {},
773 );
774 ToolbarBuilder.AddComboButton(
775 FUIAction(),
776 FOnGetContent::CreateSP(this, &Self::GenerateExternalURLsMenu),
777 LOCTEXT("OtherURLs", "Other URLs"),
778 LOCTEXT("OtherURLs_ToolTip", "Other URLs"),
779 FSlateIcon(),
780 true
781 );
782 }
783 ToolbarBuilder.EndSection();
784 })
785 );
786 AddToolbarExtender(ExternalToolbarExtender);
787 }
788}
789
790TSharedRef<SDockTab> FDialogueEditor::SpawnTab_Details(const FSpawnTabArgs& Args) const
791{
792 check(Args.GetTabId() == DetailsTabID);
793 return SNew(SDockTab)
794 // TODO use DialogueEditor.Tabs.Properties
795 .Icon(FEditorStyle::GetBrush("GenericEditor.Tabs.Properties"))
796 .Label(LOCTEXT("DialogueDetailsTitle", "Details"))
797 .TabColorScale(GetTabColorScale())
798 [
799 DetailsView.ToSharedRef()
800 ];
801}
802
803TSharedRef<SDockTab> FDialogueEditor::SpawnTab_GraphCanvas(const FSpawnTabArgs& Args) const
804{
805 check(Args.GetTabId() == GraphCanvasTabID);
806 return SNew(SDockTab)
807 .Label(LOCTEXT("DialogueGraphCanvasTiele", "Viewport"))
808 [
809 GraphEditorView.ToSharedRef()
810 ];
811}
812
813TSharedRef<SDockTab> FDialogueEditor::SpawnTab_Palette(const FSpawnTabArgs& Args) const
814{
815 check(Args.GetTabId() == PaletteTabId);
816 return SNew(SDockTab)
817 .Icon(FEditorStyle::GetBrush("Kismet.Tabs.Palette"))
818 .Label(LOCTEXT("DialoguePaletteTitle", "Palette"))
819 [
820 PaletteView.ToSharedRef()
821 ];
822}
823
824TSharedRef<SDockTab> FDialogueEditor::SpawnTab_FindInDialogue(const FSpawnTabArgs& Args) const
825{
826 check(Args.GetTabId() == FindInDialogueTabId);
827 return SNew(SDockTab)
828 .Icon(FEditorStyle::GetBrush("Kismet.Tabs.FindResults"))
829 .Label(LOCTEXT("FindResultsView", "Find Results"))
830 [
831 FindResultsView.ToSharedRef()
832 ];
833}
834
836{
837 constexpr bool bCanRedo = true;
838 if (!GEditor->UndoTransaction(bCanRedo))
839 {
840 const FText TransactionName = GEditor->Trans->GetUndoContext(true).Title;
841 UE_LOG(LogDlgSystemEditor, Warning, TEXT("Undo Transaction with Name = `%s` failed"), *TransactionName.ToString());
842 }
843}
844
846{
847 // Clear selection, to avoid holding refs to nodes that go away
849 if (!GEditor->RedoTransaction())
850 {
851 const FText TransactionName = GEditor->Trans->GetUndoContext(true).Title;
852 UE_LOG(LogDlgSystemEditor, Warning, TEXT("Redo Transaction with Name = `%s` failed"), *TransactionName.ToString());
853 }
854}
855
857{
858 const TSet<UObject*> SelectedNodes = GetSelectedNodes();
859 check(SelectedNodes.Num() == 1);
860 UDialogueGraphNode* SpeechSequence_GraphNode = CastChecked<UDialogueGraphNode>(*FDlgHelper::GetFirstSetElement(SelectedNodes));
861 check(SpeechSequence_GraphNode->IsSpeechSequenceNode());
862
863 FConvertSpeechSequenceNodeToSpeechNodes_DialogueGraphSchemaAction ConvertAction(SpeechSequence_GraphNode);
864 ConvertAction.PerformAction(DialogueBeingEdited->GetGraph(), nullptr, SpeechSequence_GraphNode->GetPosition(), false);
865}
866
868{
869 const TSet<UObject*> SelectedNodes = GetSelectedNodes();
870 TArray<UDialogueGraphNode*> OutSelectedGraphNodes;
871 if (!FDialogueEditorUtilities::CanConvertSpeechNodesToSpeechSequence(SelectedNodes, OutSelectedGraphNodes))
872 {
873 return;
874 }
875
876 UDialogueGraphNode* Speech_GraphNode = CastChecked<UDialogueGraphNode>(OutSelectedGraphNodes[0]);
877 check(Speech_GraphNode->IsSpeechNode());
878
879 FConvertSpeechNodesToSpeechSequence_DialogueGraphSchemaAction ConvertAction(OutSelectedGraphNodes);
880 ConvertAction.PerformAction(DialogueBeingEdited->GetGraph(), nullptr, Speech_GraphNode->GetPosition(), false);
881}
882
884{
885 const FScopedTransaction Transaction(LOCTEXT("DialogueEditRemoveSelectedNode", "Dialogue Editor: Remove Node"));
886 verify(DialogueBeingEdited->Modify());
887
888 const TSet<UObject*> SelectedNodes = GetSelectedNodes();
889 UDialogueGraph* DialogueGraph = GetDialogueGraph();
890 verify(DialogueGraph->Modify());
891
892 // Keep track of all the node types removed
893 int32 NumNodesRemoved = 0;
894 int32 NumDialogueNodesRemoved = 0;
895 int32 NumBaseDialogueNodesRemoved = 0;
896 int32 NumEdgeDialogueNodesRemoved = 0;
897
898#if DO_CHECK
899 const int32 Initial_DialogueNodesNum = DialogueBeingEdited->GetNodes().Num();
900 const int32 Initial_GraphNodesNum = DialogueGraph->Nodes.Num();
901 const int32 Initial_GraphDialogueNodesNum = DialogueGraph->GetAllDialogueGraphNodes().Num();
902 const int32 Initial_GraphBaseDialogueNodesNum = DialogueGraph->GetAllBaseDialogueGraphNodes().Num();
903 const int32 Initial_GraphEdgeDialogueNodesNum = DialogueGraph->GetAllEdgeDialogueGraphNodes().Num();
904#endif
905
906 // Unselect nodes we are about to delete
908
909 // Disable compiling for optimization
910 DialogueBeingEdited->DisableCompileDialogue();
911
912 // Helper function to also count the number of removed nodes
913 auto RemoveGraphNode = [&NumNodesRemoved](UEdGraphNode* NodeToRemove)
914 {
915 verify(FDialogueEditorUtilities::RemoveNode(NodeToRemove));
916 NumNodesRemoved++;
917 };
918
919 // Keep track of all the removed edges so that we do not attempt double removal
920 TSet<UDialogueGraphNode_Edge*> RemovedEdges;
921 auto AddToRemovedEdges = [&RemovedEdges, &NumBaseDialogueNodesRemoved, &NumEdgeDialogueNodesRemoved](UDialogueGraphNode_Edge* NodeEdge)
922 {
923 RemovedEdges.Add(NodeEdge);
924 NumBaseDialogueNodesRemoved++;
925 NumEdgeDialogueNodesRemoved++;
926 };
927
928 auto RemoveGraphEdgeNode = [&RemovedEdges, &RemoveGraphNode, &AddToRemovedEdges](UDialogueGraphNode_Edge* Edge)
929 {
930 if (!RemovedEdges.Contains(Edge))
931 {
932 RemoveGraphNode(Edge);
933 AddToRemovedEdges(Edge);
934 }
935 };
936
937
938 for (UObject* NodeObject : SelectedNodes)
939 {
940 UEdGraphNode* SelectedNode = CastChecked<UEdGraphNode>(NodeObject);
941 if (!SelectedNode->CanUserDeleteNode())
942 {
943 continue;
944 }
945
946 // Base Node type
947 if (UDialogueGraphNode_Base* NodeBase = Cast<UDialogueGraphNode_Base>(SelectedNode))
948 {
949 if (UDialogueGraphNode* Node = Cast<UDialogueGraphNode>(NodeBase))
950 {
951 // Remove the parent/child edges
952 for (UDialogueGraphNode_Edge* ParentNodeEdge : Node->GetParentEdgeNodes())
953 {
954 RemoveGraphEdgeNode(ParentNodeEdge);
955 }
956
957 for (UDialogueGraphNode_Edge* ChildNodeEdge : Node->GetChildEdgeNodes())
958 {
959 RemoveGraphEdgeNode(ChildNodeEdge);
960 }
961
962 // Remove the Node
963 // No need to recompile as the the break node links step will do that for us
964 RemoveGraphNode(Node);
965 NumBaseDialogueNodesRemoved++;
966 NumDialogueNodesRemoved++;
967 }
968 else
969 {
970 // Edge type
971 UDialogueGraphNode_Edge* NodeEdge = CastChecked<UDialogueGraphNode_Edge>(NodeBase);
972 RemoveGraphEdgeNode(NodeEdge);
973 }
974 }
975 else
976 {
977 // Most likely it is a comment
978 RemoveGraphNode(SelectedNode);
979 }
980 }
981
982 DialogueBeingEdited->EnableCompileDialogue();
983 if (NumBaseDialogueNodesRemoved > 0)
984 {
985 DialogueBeingEdited->CompileDialogueNodesFromGraphNodes();
986 DialogueBeingEdited->PostEditChange();
987 DialogueBeingEdited->MarkPackageDirty();
989 }
990
991#if DO_CHECK
992 // Check if we removed as we counted
993 check(Initial_DialogueNodesNum - NumDialogueNodesRemoved == DialogueBeingEdited->GetNodes().Num());
994 check(Initial_GraphNodesNum - NumNodesRemoved == DialogueGraph->Nodes.Num());
995 check(Initial_GraphDialogueNodesNum - NumDialogueNodesRemoved == DialogueGraph->GetAllDialogueGraphNodes().Num());
996 check(Initial_GraphBaseDialogueNodesNum - NumBaseDialogueNodesRemoved == DialogueGraph->GetAllBaseDialogueGraphNodes().Num());
997 check(Initial_GraphEdgeDialogueNodesNum - NumEdgeDialogueNodesRemoved == DialogueGraph->GetAllEdgeDialogueGraphNodes().Num());
998 check(NumEdgeDialogueNodesRemoved == RemovedEdges.Num());
999#endif
1000}
1001
1003{
1004 const TSet<UObject*>& SelectedNodes = GetSelectedNodes();
1005 // Return false if only root node is selected, as it can't be deleted
1006 if (SelectedNodes.Num() == 1)
1007 {
1008 const UObject* SelectedNode = *FDlgHelper::GetFirstSetElement(SelectedNodes);
1009 return !SelectedNode->IsA(UDialogueGraphNode_Root::StaticClass());
1010 }
1011
1012 return SelectedNodes.Num() > 0;
1013}
1014
1016{
1017 // Export the selected nodes and place the text on the clipboard
1018 const TSet<UObject*>& SelectedNodes = GetSelectedNodes();
1019 for (UObject* Object : SelectedNodes)
1020 {
1021 if (UEdGraphNode* Node = Cast<UEdGraphNode>(Object))
1022 {
1023 Node->PrepareForCopying();
1024 }
1025 }
1026
1027 // Copy to clipboard
1028 FString ExportedText;
1029 FEdGraphUtilities::ExportNodesToText(SelectedNodes, /*out*/ ExportedText);
1030 FPlatformApplicationMisc::ClipboardCopy(*ExportedText);
1031
1032 for (UObject* Object : SelectedNodes)
1033 {
1034 if (UDialogueGraphNode_Base* Node = Cast<UDialogueGraphNode_Base>(Object))
1035 {
1036 Node->PostCopyNode();
1037 }
1038 }
1039}
1040
1042{
1043 // If any of the nodes can be duplicated then we should allow copying
1045 {
1046 UEdGraphNode* Node = Cast<UEdGraphNode>(Object);
1047 if (Node && Node->CanDuplicateNode())
1048 {
1049 return true;
1050 }
1051 }
1052
1053 return false;
1054}
1055
1057{
1058 PasteNodesHere(GraphEditorView->GetPasteLocation());
1059}
1060
1061void FDialogueEditor::PasteNodesHere(const FVector2D& Location)
1062{
1063 // Undo/Redo support
1064 const FScopedTransaction Transaction(FGenericCommands::Get().Paste->GetDescription());
1065 UDialogueGraph* DialogueGraph = GetDialogueGraph();
1066 verify(DialogueBeingEdited->Modify());
1067 verify(DialogueGraph->Modify());
1068
1069 // Clear the selection set (newly pasted stuff will be selected)
1071
1072 // Disable compiling for optimization
1073 DialogueBeingEdited->DisableCompileDialogue();
1074
1075 // Grab the text to paste from the clipboard.
1076 FString TextToImport;
1077 FPlatformApplicationMisc::ClipboardPaste(TextToImport);
1078
1079 // Import the nodes
1080 TSet<UEdGraphNode*> PastedNodes;
1081 FEdGraphUtilities::ImportNodesFromText(DialogueGraph, TextToImport, /*out*/ PastedNodes);
1082
1083 // Step 1. Calculate average position
1084 // Average position of nodes so we can move them while still maintaining relative distances to each other
1085 FVector2D AvgNodePosition(0.0f, 0.0f);
1086 for (UEdGraphNode* Node : PastedNodes)
1087 {
1088 AvgNodePosition.X += Node->NodePosX;
1089 AvgNodePosition.Y += Node->NodePosY;
1090 }
1091 if (PastedNodes.Num() > 0)
1092 {
1093 const float InvNumNodes = 1.0f / float(PastedNodes.Num());
1094 AvgNodePosition.X *= InvNumNodes;
1095 AvgNodePosition.Y *= InvNumNodes;
1096 }
1097
1098 // maps from old index -> new index
1099 // Used to remap node edges (FDlgEdge) and checking if some TargetIndex edges are still valid
1100 TMap<int32, int32> OldToNewIndexMap;
1101 TArray<UDialogueGraphNode*> GraphNodes;
1102
1103 // Step 2. Filter Dialogue nodes and position all valid nodes
1104 for (UEdGraphNode* Node : PastedNodes)
1105 {
1106 bool bAddToSelection = true;
1107 bool bPositionNode = true;
1108
1109
1110 if (auto* GraphNode = Cast<UDialogueGraphNode>(Node))
1111 {
1112 // Add to the dialogue
1113 const int32 OldNodeIndex = GraphNode->GetDialogueNodeIndex();
1114 const int32 NewNodeIndex = DialogueBeingEdited->AddNode(GraphNode->GetMutableDialogueNode());
1115 GraphNode->SetDialogueNodeIndex(NewNodeIndex);
1116
1117 OldToNewIndexMap.Add(OldNodeIndex, NewNodeIndex);
1118 GraphNodes.Add(GraphNode);
1119 }
1120 else if (UDialogueGraphNode_Edge* Edge = Cast<UDialogueGraphNode_Edge>(Node))
1121 {
1122 bPositionNode = false;
1123 bAddToSelection = Edge->HasParentNode() && Edge->HasChildNode();
1124 }
1125
1126 // Select the newly pasted stuff
1127 if (bAddToSelection)
1128 {
1129 GraphEditorView->SetNodeSelection(Node, true);
1130 }
1131
1132 if (bPositionNode)
1133 {
1134 const float NodePosX = (Node->NodePosX - AvgNodePosition.X) + Location.X;
1135 const float NodePosY = (Node->NodePosY - AvgNodePosition.Y) + Location.Y;
1136
1137 if (auto* GraphNodeBase = Cast<UDialogueGraphNode_Base>(Node))
1138 {
1139 GraphNodeBase->SetPosition(NodePosX, NodePosY);
1140 }
1141 else
1142 {
1143 Node->NodePosX = NodePosX;
1144 Node->NodePosY = NodePosY;
1145 }
1146 }
1147
1148 // Assign new ID
1149 Node->CreateNewGuid();
1150 }
1151
1152 // Step 3. Fix Edges and references of Dialogue/Graph nodes
1153 // TODO this is similar to what the compiler does, maybe the compiler is too strict? It should not care what the Dialogues have?
1154 for (UDialogueGraphNode* GraphNode : GraphNodes)
1155 {
1156 UDlgNode* DialogueNode = GraphNode->GetMutableDialogueNode();
1157
1158 const TArray<UDialogueGraphNode_Edge*> GraphNodeChildrenEdges = GraphNode->GetChildEdgeNodes();
1159 const int32 GraphNodeChildrenEdgesNum = GraphNodeChildrenEdges.Num();
1160 if (GraphNodeChildrenEdgesNum == 0)
1161 {
1162 // There are no links copied, delete the edges from the Dialogue Node.
1163 DialogueNode->SetNodeChildren({});
1164 }
1165 else
1166 {
1167 // Fix the dialogue edges
1168 // Remove node edges to target indicies that were not copied (that do not exist)
1169 const TArray<FDlgEdge>& OldNodeEdges = DialogueNode->GetNodeChildren();
1170 TArray<FDlgEdge> NewNodeEdges;
1171 for (const FDlgEdge& OldEdge : OldNodeEdges)
1172 {
1173 // Node was copied over
1174 if (OldToNewIndexMap.Find(OldEdge.TargetIndex) != nullptr)
1175 {
1176 NewNodeEdges.Add(OldEdge);
1177 }
1178 }
1179
1180 DialogueNode->SetNodeChildren(NewNodeEdges);
1181
1182 // Fix graph edges
1183 // Remap old indices
1184 for (int32 ChildIndex = 0; ChildIndex < GraphNodeChildrenEdgesNum; ChildIndex++)
1185 {
1186 UDialogueGraphNode_Edge* ChildEdge = GraphNodeChildrenEdges[ChildIndex];
1187 const int32 OldNodeIndex = ChildEdge->GetDialogueEdge().TargetIndex;
1188 const int32 NewNodeIndex = OldToNewIndexMap.FindChecked(OldNodeIndex);
1189 GraphNode->SetEdgeTargetIndexAt(ChildIndex, NewNodeIndex);
1190 }
1191 }
1192 }
1193
1194 // First fix weak references
1196
1197 // Compile
1198 CheckAll();
1199 DialogueBeingEdited->EnableCompileDialogue();
1200 DialogueBeingEdited->CompileDialogueNodesFromGraphNodes();
1201
1202 // Notify objects of change
1204 DialogueBeingEdited->PostEditChange();
1205 DialogueBeingEdited->MarkPackageDirty();
1206}
1207
1209{
1210 FString ClipboardContent;
1211 FPlatformApplicationMisc::ClipboardPaste(ClipboardContent);
1212
1213 return FEdGraphUtilities::CanImportNodesFromText(DialogueBeingEdited->GetGraph(), ClipboardContent);
1214}
1215
1217{
1218 const TSet<UObject*>& SelectedNodes = GetSelectedNodes();
1219 for (UObject* Object : SelectedNodes)
1220 {
1221 if (UDialogueGraphNode* GraphNode = Cast<UDialogueGraphNode>(Object))
1222 {
1223 if (!GraphNode->IsRootNode())
1224 {
1225 GraphNode->SetForceHideNode(true);
1226 }
1227 }
1228 }
1229}
1230
1232{
1234 for (UDialogueGraphNode* GraphNode : Graph->GetAllDialogueGraphNodes())
1235 {
1236 GraphNode->SetForceHideNode(false);
1237 }
1238}
1239
1241{
1242 // Ignore
1243 if (GetSettings().DialogueTextFormat == EDlgDialogueTextFormat::None)
1244 {
1245 return;
1246 }
1247
1248 check(DialogueBeingEdited);
1249 const EAppReturnType::Type Response = FPlatformMisc::MessageBoxExt(EAppMsgType::YesNo,
1250 TEXT("You are about to overwrite your data in the editor with the data from the text file(.dlg)"),
1251 TEXT("Overwrite graph/dialogue data from text file?"));
1252 if (Response == EAppReturnType::No)
1253 {
1254 return;
1255 }
1256
1257 //const FScopedTransaction Transaction(LOCTEXT("DialogueEditorReloadFromFile", "Dialogue Editor: Reload from file"));
1258
1259 // Opposite of this steps are in the SaveAsset_Execute
1260 // Reload data, text file -> dialogue data
1262
1263 // Update graph, dialogue data -> graph
1264 DialogueBeingEdited->ClearGraph(); // triggers create default graph nodes
1265 DialogueBeingEdited->MarkPackageDirty();
1266}
1267
1268void FDialogueEditor::OnSelectedNodesChanged(const TSet<UObject*>& NewSelection)
1269{
1270 TArray<UObject*> ViewSelection;
1271
1273 if (NewSelection.Num())
1274 {
1275 for (UObject* Selected : NewSelection)
1276 {
1277 PreviousSelectedNodeObjects.Add(Selected);
1278 ViewSelection.Add(Selected);
1279 }
1280 }
1281 else
1282 {
1283 // Nothing selected, view the properties of this Dialogue.
1284 ViewSelection.Add(DialogueBeingEdited);
1285 }
1286
1287 // View the selected objects
1288 if (DetailsView.IsValid())
1289 {
1290 DetailsView->SetObjects(ViewSelection, /*bForceRefresh=*/ true);
1291 }
1292}
1293
1294FActionMenuContent FDialogueEditor::OnCreateGraphActionMenu(UEdGraph* InGraph, const FVector2D& InNodePosition,
1295 const TArray<UEdGraphPin*>& InDraggedPins, bool bAutoExpand, SGraphEditor::FActionMenuClosed InOnMenuClosed)
1296{
1297 const TSharedRef<SDialogueActionMenu> ActionMenu = SNew(SDialogueActionMenu)
1298 .Graph(InGraph)
1299 .NewNodePosition(InNodePosition)
1300 .DraggedFromPins(InDraggedPins)
1301 .AutoExpandActionMenu(bAutoExpand)
1302 .OnClosedCallback(InOnMenuClosed)
1303 .OnCloseReason(this, &Self::OnGraphActionMenuClosed);
1304
1305 return FActionMenuContent(ActionMenu, ActionMenu->GetFilterTextBox());
1306}
1307
1308void FDialogueEditor::OnGraphActionMenuClosed(bool bActionExecuted, bool bGraphPinContext)
1309{
1310 if (!bActionExecuted)
1311 {
1312 // reset previous drag and drop saved edges.
1314 }
1315}
1316
1317void FDialogueEditor::OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged) const
1318{
1319 if (!IsValid(NodeBeingChanged))
1320 {
1321 return;
1322 }
1323
1324 // Rename the node to the new set text.
1325 const FScopedTransaction Transaction(LOCTEXT("RenameNode", "Dialogue Editor: Rename Node"));
1326 verify(NodeBeingChanged->Modify());
1327 NodeBeingChanged->OnRenameNode(NewText.ToString());
1328}
1329// End of own functions
1331
1332#undef LOCTEXT_NAMESPACE
const FName DialogueEditorAppName
UProperty FNYProperty
bool CanPasteNodes() const
void InitDialogueEditor(EToolkitMode::Type Mode, const TSharedPtr< IToolkitHost > &InitToolkitHost, UDlgDialogue *InitDialogue)
virtual ~FDialogueEditor()
void OnCommandDeleteSelectedNodes() const
UDlgSystemSettings * Settings
void OnCommandHideSelectedNodes()
TSharedPtr< IDetailsView > DetailsView
void PasteNodesHere(const FVector2D &Location)
void PostRedo(bool bSuccess) override
static const FName PaletteTabId
void SetDialogueBeingEdited(UDlgDialogue *NewDialogue)
void CheckAll() const
TSharedRef< SGraphEditor > CreateGraphEditorWidget()
TSharedPtr< SGraphEditor > GraphEditorView
TArray< TWeakObjectPtr< UObject > > PreviousSelectedNodeObjects
void NotifyPostChange(const FPropertyChangedEvent &PropertyChangedEvent, FNYProperty *PropertyThatChanged) override
void SummonSearchUI(bool bSetFindWithinDialogue, FString NewSearchTerms=FString(), bool bSelectFirstResult=false)
static const FName GraphCanvasTabID
void SaveAssetAs_Execute() override
bool CanDeleteNodes() const
FText GetBaseToolkitName() const override
bool CanCopyNodes() const
void JumpToObject(const UObject *Object) override
void OnCommandUndoGraphAction() const
void OnCommandRedoGraphAction() const
static const FName DetailsTabID
void PostUndo(bool bSuccess) override
TSet< UObject * > GetSelectedNodes() const override
void RegisterTabSpawners(const TSharedRef< FTabManager > &TabManager) override
void OnCommandConvertSpeechNodesToSpeechSequence() const
TSharedRef< SDockTab > SpawnTab_Palette(const FSpawnTabArgs &Args) const
UDialogueGraph * GetDialogueGraph() const
void SaveAsset_Execute() override
TSharedPtr< SDialoguePalette > PaletteView
const UDlgSystemSettings & GetSettings() const
void ClearViewportSelection() const
UDialogueGraphNode_Edge * LastTargetGraphEdgeBeforeDrag
void OnGraphActionMenuClosed(bool bActionExecuted, bool bGraphPinContext)
void OnSelectedNodesChanged(const TSet< UObject * > &NewSelection)
void RefreshViewport() const
void RefreshDetailsView(bool bRestorePreviousSelection) override
TSharedRef< SDockTab > SpawnTab_FindInDialogue(const FSpawnTabArgs &Args) const
static const FName FindInDialogueTabId
FActionMenuContent OnCreateGraphActionMenu(UEdGraph *InGraph, const FVector2D &InNodePosition, const TArray< UEdGraphPin * > &InDraggedPins, bool bAutoExpand, SGraphEditor::FActionMenuClosed InOnMenuClosed)
TSharedPtr< SFindInDialogues > FindResultsView
FText GetToolkitName() const override
TSharedRef< SDockTab > SpawnTab_GraphCanvas(const FSpawnTabArgs &Args) const
TSharedRef< SWidget > GenerateExternalURLsMenu() const
TSharedRef< SDockTab > SpawnTab_Details(const FSpawnTabArgs &Args) const
void OnCommandCopySelectedNodes() const
void UnregisterTabSpawners(const TSharedRef< FTabManager > &TabManager) override
TSharedPtr< FUICommandList > GraphEditorCommands
void Refresh(bool bRestorePreviousSelection) override
UDlgDialogue * DialogueBeingEdited
void FocusWindow(UObject *ObjectToFocusOn=nullptr) override
void OnCommandConvertSpeechSequenceNodeToSpeechNodes() const
void OnNodeTitleCommitted(const FText &NewText, ETextCommit::Type CommitInfo, UEdGraphNode *NodeBeingChanged) const
void OnCommandDialogueReload() const
TSharedRef< SWidget > GeneratePrimarySecondaryEdgesMenu() const
static void RemapOldIndicesWithNewAndUpdateGUID(const TArray< UDialogueGraphNode * > &GraphNodes, const TMap< int32, int32 > &OldToNewIndexMap)
static bool AreDialogueNodesInSyncWithGraphNodes(const UDlgDialogue *Dialogue)
static void TryToCreateDefaultGraph(UDlgDialogue *Dialogue, bool bPrompt=true)
static void CloseOtherEditors(UObject *Asset, IAssetEditorInstance *OnlyEditor)
static bool CanConvertSpeechNodesToSpeechSequence(const TSet< UObject * > &SelectedNodes, TArray< UDialogueGraphNode * > &OutSelectedGraphNodes)
static bool RemoveNode(UEdGraphNode *NodeToRemove)
static FName GetStyleSetName()
static const FName PROPERTY_NotYetLogoIcon
static TCopyQualifiersFromTo< SetType, typenameSetType::ElementType >::Type * GetFirstSetElement(SetType &Set)
Definition DlgHelper.h:373
static TSharedPtr< SDockTab > InvokeTab(TSharedPtr< FTabManager > TabManager, const FTabId &TabID)
Definition DlgHelper.cpp:90
static TSharedRef< FExtender > CreateHelpMenuExtender(TSharedRef< FUICommandList > Commands)
static void MapActionsForFileMenuExtender(TSharedRef< FUICommandList > Commands)
static void MapActionsForHelpMenuExtender(TSharedRef< FUICommandList > Commands)
static TSharedRef< FExtender > CreateFileMenuExtender(TSharedRef< FUICommandList > Commands, const TArray< TSharedPtr< FUICommandInfo > > &AdditionalMenuEntries={})
bool Modify(bool bAlwaysMarkDirty=true) override
TArray< UDialogueGraphNode_Edge * > GetAllEdgeDialogueGraphNodes() const
TArray< UDialogueGraphNode_Base * > GetAllBaseDialogueGraphNodes() const
TArray< UDialogueGraphNode * > GetAllDialogueGraphNodes() const
virtual FIntPoint GetPosition() const
const FDlgEdge & GetDialogueEdge() const
bool IsSpeechSequenceNode() const
UCLASS(BlueprintType, Meta = (DisplayThumbnail = "true"))
Definition DlgDialogue.h:85
const TArray< UDlgNode * > & GetNodes() const
UFUNCTION(BlueprintPure, Category = "Dialogue")
void ImportFromFile()
int32 AddNode(UDlgNode *NodeToAdd)
TArray< UDlgNode * > Nodes
UPROPERTY(AdvancedDisplay, EditFixedSize, Instanced, Meta = (DlgWriteIndex))
UCLASS(BlueprintType, Abstract, EditInlineNew, ClassGroup = "Dialogue")
Definition DlgNode.h:40
virtual const TArray< FDlgEdge > & GetNodeChildren() const
Gets this nodes children (edges) as a const/mutable array.
Definition DlgNode.h:184
virtual void SetNodeChildren(const TArray< FDlgEdge > &InChildren)
Definition DlgNode.h:185
bool bShowPrimarySecondaryEdges
UPROPERTY(Category = "Graph Edge", Config, EditAnywhere)
UEdGraphNode * PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode=true) override
UEdGraphNode * PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode=false) override
USTRUCT(BlueprintType)
Definition DlgEdge.h:25
int32 TargetIndex
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Dialogue|Edge", Meta = (ClampMin = -1))
Definition DlgEdge.h:126
UEdGraphNode * PerformAction(UEdGraph *ParentGraph, UEdGraphPin *FromPin, const FVector2D Location, bool bSelectNewNode=true) override