A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
SDialogueGraphNode.cpp
Go to the documentation of this file.
1// Copyright Csaba Molnar, Daniel Butum. All Rights Reserved.
3
4#include "Widgets/Layout/SBox.h"
5#include "Widgets/Images/SImage.h"
6#include "Widgets/SToolTip.h"
7#include "GraphEditorSettings.h"
8#include "SCommentBubble.h"
9#include "SLevelOfDetailBranchNode.h"
10#include "IDocumentation.h"
11#include "GraphEditorDragDropAction.h"
12
14#include "SDialogueGraphPin.h"
15#include "DialogueStyle.h"
16
17#define LOCTEXT_NAMESPACE "DialogueEditor"
18
19
21// SDialogueGraphNode
22void SDialogueGraphNode::Construct(const FArguments& InArgs, UDialogueGraphNode* InNode)
23{
24 Super::Construct(Super::FArguments(), InNode);
25 DialogueGraphNode = InNode;
26
27 SetCursor(EMouseCursor::CardinalCross);
29}
30
31FReply SDialogueGraphNode::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
32{
33// const bool bReadOnly = OwnerGraphPanelPtr.IsValid() ? !OwnerGraphPanelPtr.Pin()->IsGraphEditable() : false;
34// const TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
35// if (!Operation.IsValid() || bReadOnly)
36// return FReply::Unhandled();
37
38 // Is someone dropping a connection onto this node?
39// if (Operation->IsOfType<FGraphEditorDragDropAction>())
40// {
41// TSharedPtr<FGraphEditorDragDropAction> DragConnectionOp = StaticCastSharedPtr<FGraphEditorDragDropAction>(Operation);
42// }
43
44 return Super::OnDrop(MyGeometry, DragDropEvent);
45}
46
48// Begin SNodePanel::SNode Interface
49TArray<FOverlayWidgetInfo> SDialogueGraphNode::GetOverlayWidgets(bool bSelected, const FVector2D& WidgetSize) const
50{
51 check(IndexOverlayWidget.IsValid());
52 check(ConditionOverlayWidget.IsValid());
53 check(EventOverlayWidget.IsValid());
54 check(VoiceOverlayWidget.IsValid());
55 check(GenericOverlayWidget.IsValid());
56
57 TArray<FOverlayWidgetInfo> Widgets;
58 static constexpr float DistanceBetweenWidgetsY = 1.5f;
59 FVector2D OriginRightSide(0.0f, 0.0f);
60 FVector2D OriginLeftSide(0.0f, 0.0f);
61
62 // Add Index overlay
63 {
64 // Position on the right of the node
65 FOverlayWidgetInfo Overlay(IndexOverlayWidget);
66 Overlay.OverlayOffset = FVector2D(WidgetSize.X - IndexOverlayWidget->GetDesiredSize().X / 2.0f, OriginRightSide.Y);
67 Widgets.Add(Overlay);
68 OriginRightSide.Y += IndexOverlayWidget->GetDesiredSize().Y + DistanceBetweenWidgetsY;
69 }
70
71 // Add Voice overlay
73 {
74 // Position on the right of the node
75 FOverlayWidgetInfo Overlay(VoiceOverlayWidget);
76 Overlay.OverlayOffset = FVector2D(WidgetSize.X - VoiceOverlayWidget->GetDesiredSize().X / 3.0f, OriginRightSide.Y);
77 Widgets.Add(Overlay);
78 OriginRightSide.Y += VoiceOverlayWidget->GetDesiredSize().Y + DistanceBetweenWidgetsY;
79 }
80
81 // Add Generic overlay
83 {
84 // Position on the right of the node
85 FOverlayWidgetInfo Overlay(GenericOverlayWidget);
86 Overlay.OverlayOffset = FVector2D(WidgetSize.X - GenericOverlayWidget->GetDesiredSize().X / 3.0f, OriginRightSide.Y);
87 Widgets.Add(Overlay);
88 OriginRightSide.Y += GenericOverlayWidget->GetDesiredSize().Y + DistanceBetweenWidgetsY;
89 }
90
91 // Add Condition overlay
93 {
94 // Position on the left of the node
95 FOverlayWidgetInfo Overlay(ConditionOverlayWidget);
96 Overlay.OverlayOffset = FVector2D(-ConditionOverlayWidget->GetDesiredSize().X / 1.5f, OriginLeftSide.Y);
97 Widgets.Add(Overlay);
98 OriginLeftSide.Y += ConditionOverlayWidget->GetDesiredSize().Y + DistanceBetweenWidgetsY;
99 }
100
101 // Add Event overlay
103 {
104 // Position on the left of the node
105 FOverlayWidgetInfo Overlay(EventOverlayWidget);
106 Overlay.OverlayOffset = FVector2D(-EventOverlayWidget->GetDesiredSize().X / 1.5f, OriginLeftSide.Y);
107 Widgets.Add(Overlay);
108 OriginLeftSide.Y += EventOverlayWidget->GetDesiredSize().Y + DistanceBetweenWidgetsY;
109 }
110
111 return Widgets;
112}
113
114void SDialogueGraphNode::GetOverlayBrushes(bool bSelected, const FVector2D WidgetSize, TArray<FOverlayBrushInfo>& Brushes) const
115{
116 Super::GetOverlayBrushes(bSelected, WidgetSize, Brushes);
117}
118
119// End SNodePanel::SNode Interface
121
123// Begin SGraphNode interface
125{
127 SetupErrorReporting();
128
129 // Define other useful variables
130 const FMargin NodePadding = 10.0f;
131
132 // Used in GetOverlayWidgets
134 .OverlayBody(
135 SNew(STextBlock)
136 .Text(this, &Self::GetIndexText)
137 .ColorAndOpacity(FLinearColor::White)
138 .Font(FEditorStyle::GetFontStyle("BTEditor.Graph.BTNode.IndexText"))
139 )
140 .ToolTipText(this, &Self::GetIndexOverlayTooltipText)
141 .Visibility(this, &Self::GetOverlayWidgetVisibility)
142 .OnHoverStateChanged(this, &Self::OnIndexHoverStateChanged)
143 .OnGetBackgroundColor(this, &Self::GetOverlayWidgetBackgroundColor);
144
145 // Fit to content
146 static constexpr int WidthOverride = 24;
147 static constexpr int HeightOverride = 24;
149 .OverlayBody(
150 SNew(SBox)
151 .HAlign(HAlign_Fill)
152 .VAlign(VAlign_Fill)
153 .WidthOverride(WidthOverride)
154 .HeightOverride(HeightOverride)
155 [
156 SNew(SImage)
158 ]
159 )
160 .ToolTipText(this, &Self::GetConditionOverlayTooltipText)
161 .Visibility(this, &Self::GetOverlayWidgetVisibility)
162 .OnGetBackgroundColor(this, &Self::GetOverlayWidgetBackgroundColor);
163
165 .OverlayBody(
166 SNew(SBox)
167 .HAlign(HAlign_Fill)
168 .VAlign(VAlign_Fill)
169 .WidthOverride(WidthOverride)
170 .HeightOverride(HeightOverride)
171 [
172 SNew(SImage)
174 ]
175 )
176 .ToolTipText(this, &Self::GetEventOverlayTooltipText)
177 .Visibility(this, &Self::GetOverlayWidgetVisibility)
178 .OnGetBackgroundColor(this, &Self::GetOverlayWidgetBackgroundColor);
179
181 .OverlayBody(
182 SNew(SBox)
183 .HAlign(HAlign_Fill)
184 .VAlign(VAlign_Fill)
185 .WidthOverride(WidthOverride)
186 .HeightOverride(HeightOverride)
187 [
188 SNew(SImage)
190 ]
191 )
192 .ToolTipText(this, &Self::GetVoiceOverlayTooltipText)
193 .Visibility(this, &Self::GetOverlayWidgetVisibility)
194 .OnGetBackgroundColor(this, &Self::GetOverlayWidgetBackgroundColor);
195
197 .OverlayBody(
198 SNew(SBox)
199 .HAlign(HAlign_Fill)
200 .VAlign(VAlign_Fill)
201 .WidthOverride(WidthOverride)
202 .HeightOverride(HeightOverride)
203 [
204 SNew(SImage)
206 ]
207 )
208 .ToolTipText(this, &Self::GetGenericOverlayTooltipText)
209 .Visibility(this, &Self::GetOverlayWidgetVisibility)
210 .OnGetBackgroundColor(this, &Self::GetOverlayWidgetBackgroundColor);
211
212 // Set Default tooltip
213 if (!SWidget::GetToolTip().IsValid())
214 {
215 TSharedRef<SToolTip> DefaultToolTip = IDocumentation::Get()->CreateToolTip(TAttribute<FText>(this, &Super::GetNodeTooltip), nullptr,
216 GraphNode->GetDocumentationLink(), GraphNode->GetDocumentationExcerptName());
217 SetToolTip(DefaultToolTip);
218 }
219
220 // Setup content
221 {
222 ContentScale.Bind(this, &Super::GetContentScale);
223 GetOrAddSlot(ENodeZone::Center)
224 .HAlign(HAlign_Fill)
225 .VAlign(VAlign_Center)
226 [
227 SNew(SBorder)
228 .BorderImage(FEditorStyle::GetBrush("Graph.StateNode.Body"))
229 .Padding(0)
230 .BorderBackgroundColor(Settings->BorderBackgroundColor)
231 [
232 // PIN AREA, output pin
233 SNew(SOverlay)
234 +SOverlay::Slot()
235 .HAlign(HAlign_Fill)
236 .VAlign(VAlign_Fill)
237 [
238 PinsNodeBox.ToSharedRef()
239 ]
240
241 // Content/Body area
242 +SOverlay::Slot()
243 .HAlign(HAlign_Center)
244 .VAlign(VAlign_Center)
245 .Padding(NodePadding)
246 [
248 ]
249 ]
250 ];
252 }
253
254 // Create comment bubble
255 {
256 TSharedPtr<SCommentBubble> CommentBubble;
257 const FSlateColor CommentColor = GetDefault<UGraphEditorSettings>()->DefaultCommentNodeTitleColor;
258
259 SAssignNew(CommentBubble, SCommentBubble)
260 .GraphNode(GraphNode)
261 .Text(this, &Super::GetNodeComment)
262 .OnTextCommitted(this, &Super::OnCommentTextCommitted)
263 .OnToggled(this, &Super::OnCommentBubbleToggled)
264 .ColorAndOpacity(CommentColor)
265 .AllowPinning(true)
266 .EnableTitleBarBubble(true)
267 .EnableBubbleCtrls(true)
268 .GraphLOD(this, &Super::GetCurrentLOD)
269 .IsGraphNodeHovered(this, &Super::IsHovered);
270
271 // Add it at the top, right above
272 GetOrAddSlot(ENodeZone::TopCenter)
273 .SlotOffset(TAttribute<FVector2D>(CommentBubble.Get(), &SCommentBubble::GetOffset))
274 .SlotSize(TAttribute<FVector2D>(CommentBubble.Get(), &SCommentBubble::GetSize))
275 .AllowScaling(TAttribute<bool>(CommentBubble.Get(), &SCommentBubble::IsScalingAllowed))
276 .VAlign(VAlign_Top)
277 [
278 CommentBubble.ToSharedRef()
279 ];
280 }
281}
282// End SGraphNode interface
284
286// Begin own functions
288{
289 if (NodeBodyWidget.IsValid())
290 {
291 return NodeBodyWidget.ToSharedRef();
292 }
293
294 // Setup a meta tag for this node
295// FGraphNodeMetaData TagMeta(TEXT("UDialogueGraphNode_Base"));
296// PopulateMetaTag(&TagMeta);
297
299 SNew(SBorder)
300 .BorderImage(FEditorStyle::GetBrush("BTEditor.Graph.BTNode.Body"))
301 .BorderBackgroundColor(this, &Self::GetBackgroundColor)
302 .HAlign(HAlign_Center)
303 .VAlign(VAlign_Center)
304 .Padding(1.0f)
305 .Visibility(EVisibility::Visible)
306 [
307 // Main Content
308 SNew(SVerticalBox)
309
310 // Title
311 +SVerticalBox::Slot()
312 .HAlign(HAlign_Fill)
313 .VAlign(VAlign_Fill)
314 .AutoHeight()
315 [
317 ]
318
319 // Description
320 +SVerticalBox::Slot()
321 .HAlign(HAlign_Fill)
322 .VAlign(VAlign_Fill)
323 .AutoHeight()
324 [
326 ]
327 ];
328
329 return NodeBodyWidget.ToSharedRef();
330}
331
333{
334 if (TitleWidget.IsValid())
335 {
336 return TitleWidget.ToSharedRef();
337 }
338
339 // Title
340 TSharedPtr<SNodeTitle> NodeTitleMultipleLines = SNew(SNodeTitle, GraphNode);
341 TWeakPtr<SNodeTitle> WeakNodeTitle = NodeTitleMultipleLines;
342 auto GetNodeTitlePlaceholderWidth = [WeakNodeTitle]() -> FOptionalSize
343 {
344 TSharedPtr<SNodeTitle> NodeTitlePin = WeakNodeTitle.Pin();
345 const float DesiredWidth = NodeTitlePin.IsValid() ? NodeTitlePin->GetTitleSize().X : 0.0f;
346 return FMath::Max(75.0f, DesiredWidth);
347 };
348 auto GetNodeTitlePlaceholderHeight = [WeakNodeTitle]() -> FOptionalSize
349 {
350 TSharedPtr<SNodeTitle> NodeTitlePin = WeakNodeTitle.Pin();
351 const float DesiredHeight = NodeTitlePin.IsValid() ? NodeTitlePin->GetTitleSize().Y : 0.0f;
352 return FMath::Max(22.0f, DesiredHeight);
353 };
354
355 // Icon and tint is set from the node
356 IconColor = FLinearColor::White; // default
357 const FSlateBrush* IconBrush = nullptr;
358 if (GraphNode->ShowPaletteIconOnNode())
359 {
360 IconBrush = GraphNode->GetIconAndTint(IconColor).GetIcon();
361 }
362
363 TitleWidget = SNew(SHorizontalBox)
364 // Error message and title
365 +SHorizontalBox::Slot()
367 .VAlign(VAlign_Top)
368 .AutoWidth()
369 [
370 SNew(SHorizontalBox)
371
372 // Error message
373 +SHorizontalBox::Slot()
374 .AutoWidth()
375 [
376 // POPUP ERROR MESSAGE
377 ErrorReporting->AsWidget()
378 ]
379
380 // Title
381 +SHorizontalBox::Slot()
382 .AutoWidth()
383 [
384 SNew(SLevelOfDetailBranchNode)
385 .UseLowDetailSlot(this, &Self::UseLowDetailNodeTitles)
386 .LowDetail()
387 [
388 SNew(SBox)
389 .WidthOverride_Lambda(GetNodeTitlePlaceholderWidth)
390 .HeightOverride_Lambda(GetNodeTitlePlaceholderHeight)
391 ]
392 .HighDetail()
393 [
394 SNew(SHorizontalBox)
395
396 // Icon
397 +SHorizontalBox::Slot()
398 .AutoWidth()
399 [
400 SNew(SImage)
401 .Image(IconBrush)
402 .ColorAndOpacity(this, &Super::GetNodeTitleIconColor)
403 ]
404
405 // Title content
406 +SHorizontalBox::Slot()
407 .AutoWidth()
408 [
409 SNew(SVerticalBox)
410
411 // Display the first line
412 +SVerticalBox::Slot()
413 .AutoHeight()
414 [
415 SNew(STextBlock)
416 // See FSlateEditorStyle for styles
417 .TextStyle(FEditorStyle::Get(), "Graph.StateNode.NodeTitle")
418 // gets always the first line of the title
419 .Text(NodeTitleMultipleLines.Get(), &SNodeTitle::GetHeadTitle)
420 ]
421
422 // Display the rest of the lines. The usage of SNodeTitle is a lie, the Style argument does not do anything.
423 // This only starts dispalying from line 1 (if there is a multi line title)
424 +SVerticalBox::Slot()
425 .AutoHeight()
426 [
427 NodeTitleMultipleLines.ToSharedRef()
428 ]
429 ]
430 ]
431 ]
432 ];
433
434 return TitleWidget.ToSharedRef();
435}
436
438{
439 if (DescriptionWidget.IsValid())
440 {
441 return DescriptionWidget.ToSharedRef();
442 }
443
445 {
446 TSharedPtr<SVerticalBox> VerticalBox = SNew(SVerticalBox);
447 const int32 SpechSequnceEntriesNum = GetSpeechSequenceEntries().Num();
448
449 for (int32 EntryIndex = 0; EntryIndex < SpechSequnceEntriesNum; EntryIndex++)
450 {
451 VerticalBox->AddSlot()
452 .AutoHeight()
453 [
454 // Black border around each entry
455 SNew(SBorder)
456 .BorderImage(FEditorStyle::GetBrush("PlainBorder"))
457 .BorderBackgroundColor(Settings->BorderBackgroundColor)
458 .Padding(FMargin(0.f, 2.f))
459 [
460 SNew(SVerticalBox)
461
462 // Speaker/Owner name of entry
463 +SVerticalBox::Slot()
465 .VAlign(VAlign_Center)
466 .AutoHeight()
467 [
468 SNew(STextBlock)
469 .Visibility(this, &Self::GetDescriptionVisibility)
470 .Text(this, &Self::GetSpeakerForSpeechSequenceEntryAt, EntryIndex)
471 .TextStyle(FEditorStyle::Get(), "Graph.Node.NodeTitle")
473 ]
474
475 // Text for entry
476 +SVerticalBox::Slot()
477 .AutoHeight()
478 [
479 SNew(STextBlock)
480 .Visibility(this, &Self::GetDescriptionVisibility)
481 .Text(this, &Self::GetDescriptionForSpeechSequenceEntryAt, EntryIndex)
482 .WrapTextAt(Settings->DescriptionWrapTextAt)
484 ]
485 ]
486 ];
487 }
488 DescriptionWidget = VerticalBox;
489 }
490 else
491 {
492 DescriptionWidget = SNew(STextBlock)
493 .Visibility(this, &Self::GetDescriptionVisibility)
494 .Text(this, &Self::GetDescription)
495 .WrapTextAt(Settings->DescriptionWrapTextAt)
497 }
498
499 return DescriptionWidget.ToSharedRef();
500}
501
503{
504 // always hide the index on the root node
506 {
507 return EVisibility::Hidden;
508 }
509
510 // LOD this out once things get too small
511 TSharedPtr<SGraphPanel> MyOwnerPanel = GetOwnerPanel();
512 return !MyOwnerPanel.IsValid() || MyOwnerPanel->GetCurrentLOD() > EGraphRenderingLOD::LowDetail ? EVisibility::Visible : EVisibility::Collapsed;
513}
514
515
517{
518 return LOCTEXT("NodeIndexTooltip", "Node index: this shows the node index in the Dialogue.Nodes Array");
519}
520
522{
523 return LOCTEXT("NodeConditionTooltip", "Node has enter conditions.\nOnly if these conditions are satisfied the node is entered.");
524}
525
527{
528 return LOCTEXT("NodeEventTooltip", "Node has enter events.\nOn node enter this events are executed.");
529}
530
532{
533 return LOCTEXT("NodeVoiceTooltip", "Node has some voice variables set. Either the SoundWave or the DialogueWave.");
534}
535
537{
538 return LOCTEXT("NodeGenericTooltip", "Node has the generic data variable set.");
539}
540
542{
543
544}
545// End own functions
547
548#undef LOCTEXT_NAMESPACE
static const FName PROPERTY_VoiceIcon
static TSharedPtr< ISlateStyle > Get()
static const FName PROPERTY_GenericIcon
static const FName PROPERTY_ConditionIcon
static const FName PROPERTY_EventIcon
const UDlgSystemSettings * Settings
TSharedPtr< SVerticalBox > PinsNodeBox
void Construct(const FArguments &InArgs, UDialogueGraphNode_Base *InNode)
TSharedRef< SWidget > GetNodeBodyWidget()
FText GetGenericOverlayTooltipText() const
UDialogueGraphNode * DialogueGraphNode
FText GetDescriptionForSpeechSequenceEntryAt(int32 SpeechEntryIndex) const
FSlateColor GetBackgroundColor() const
FSlateColor GetOverlayWidgetBackgroundColor(bool bHovered) const
FText GetIndexOverlayTooltipText() const
void UpdateGraphNode() override
TSharedPtr< SWidget > GenericOverlayWidget
FText GetVoiceOverlayTooltipText() const
FReply OnDrop(const FGeometry &MyGeometry, const FDragDropEvent &DragDropEvent) override
void GetOverlayBrushes(bool bSelected, const FVector2D WidgetSize, TArray< FOverlayBrushInfo > &Brushes) const override
TSharedPtr< SBorder > NodeBodyWidget
void Construct(const FArguments &InArgs, UDialogueGraphNode *InNode)
const TArray< FDlgSpeechSequenceEntry > & GetSpeechSequenceEntries() const
FText GetEventOverlayTooltipText() const
TSharedRef< SWidget > GetTitleWidget()
TSharedPtr< SWidget > VoiceOverlayWidget
TSharedRef< SWidget > GetDescriptionWidget()
void OnIndexHoverStateChanged(bool bHovered)
TSharedPtr< SWidget > IndexOverlayWidget
TSharedPtr< SWidget > TitleWidget
TSharedPtr< SWidget > EventOverlayWidget
TSharedPtr< SWidget > ConditionOverlayWidget
TArray< FOverlayWidgetInfo > GetOverlayWidgets(bool bSelected, const FVector2D &WidgetSize) const override
FText GetConditionOverlayTooltipText() const
FText GetSpeakerForSpeechSequenceEntryAt(int32 SpeechEntryIndex) const
EVisibility GetOverlayWidgetVisibility() const
EVisibility GetDescriptionVisibility() const
bool UseLowDetailNodeTitles() const override
FText GetDescription() const
TSharedPtr< SWidget > DescriptionWidget
bool HasEnterEvents() const
bool HasVoicePropertiesSet() const
virtual bool IsRootNode() const
bool IsSpeechSequenceNode() const
bool HasEnterConditions() const
bool bShowHasEnterEventsIcon
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)
bool bShowHasVoiceIcon
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)
TEnumAsByte< EHorizontalAlignment > DescriptionSpeakerHorizontalAlignment
UPROPERTY(Category = "Graph Node Speech Sequence", Config, EditAnywhere)
bool bShowHasGenericDataIcon
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)
bool bShowHasEnterConditionsIcon
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)
TEnumAsByte< EHorizontalAlignment > TitleHorizontalAlignment
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)
FMargin DescriptionSpeakerMargin
UPROPERTY(Category = "Graph Node Speech Sequence", Config, EditAnywhere)
FLinearColor BorderBackgroundColor
UPROPERTY(Category = "Graph Node Color", Config, EditAnywhere)
float DescriptionWrapTextAt
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)
FMargin DescriptionTextMargin
UPROPERTY(Category = "Graph Node", Config, EditAnywhere)