UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SBreadcrumbTrail.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Misc/Attribute.h"
8#include "Layout/Visibility.h"
9#include "Input/Reply.h"
10#include "Widgets/SWidget.h"
11#include "Layout/Margin.h"
12#include "Widgets/SNullWidget.h"
15#include "Widgets/SBoxPanel.h"
16#include "Styling/SlateTypes.h"
17#include "Styling/CoreStyle.h"
22
23// Base class for breadcrumb trail holding methods which are not dependent on the crumb data type.
25{
26public:
29
30protected:
33};
34
38template <typename ItemType>
40{
41private:
43 struct FCrumbItem
44 {
45 int32 CrumbID;
49 TSharedRef<SVerticalBox> DelimiterBox;
50 ItemType CrumbData;
51
53 : CrumbID(InCrumbID)
55 , Delimiter(InDelimiter)
56 , ButtonBox(InButtonBox)
57 , DelimiterBox(InDelimiterBox)
58 , CrumbData(InCrumbData)
59 {}
60 };
61
62public:
64 DECLARE_DELEGATE_OneParam( FOnCrumbPushed, const ItemType& /*CrumbData*/ );
65
67 DECLARE_DELEGATE_OneParam( FOnCrumbPopped, const ItemType& /*CrumbData*/ );
68
70 DECLARE_DELEGATE_OneParam( FOnCrumbClicked, const ItemType& /*CrumbData*/ );
71
73 DECLARE_DELEGATE_RetVal_OneParam( bool, FHasCrumbMenuContent, const ItemType& /*CrumbData*/ );
74
77
80
82 : _ButtonStyle( &FCoreStyle::Get().GetWidgetStyle< FButtonStyle >( "BreadcrumbButton" ) )
83 , _TextStyle( &FCoreStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText") )
85 , _DelimiterImage( FCoreStyle::Get().GetBrush("BreadcrumbTrail.Delimiter") )
90 {}
91
94
95
97
98
99 SLATE_ATTRIBUTE( FMargin, ButtonContentPadding )
100
101
102 SLATE_ATTRIBUTE( const FSlateBrush*, DelimiterImage )
103
104
105 SLATE_ATTRIBUTE( bool, ShowLeadingDelimiter )
106
107
108 SLATE_EVENT( FOnCrumbPushed, OnCrumbPushed )
109
110
111 SLATE_EVENT( FOnCrumbPopped, OnCrumbPopped )
112
113
114 SLATE_EVENT( FOnCrumbClicked, OnCrumbClicked )
115
116
118
120
121 SLATE_EVENT( FGetCrumbMenuContent, GetCrumbMenuContent )
122
124
126
127
128 void Construct( const FArguments& InArgs )
129 {
130 ButtonStyle = InArgs._ButtonStyle;
131 TextStyle = InArgs._TextStyle;
132 ButtonContentPadding = InArgs._ButtonContentPadding;
133 DelimiterImage = InArgs._DelimiterImage;
134 ShowLeadingDelimiter = InArgs._ShowLeadingDelimiter;
135 OnCrumbPushed = InArgs._OnCrumbPushed;
136 OnCrumbPopped = InArgs._OnCrumbPopped;
137 OnCrumbClicked = InArgs._OnCrumbClicked;
138 bHasStaticBreadcrumbs = InArgs._PersistentBreadcrumbs;
139 HasCrumbMenuContentCallback = InArgs._HasCrumbMenuContent;
140 GetCrumbMenuContentCallback = InArgs._GetCrumbMenuContent;
141 GetCrumbButtonContentCallback = InArgs._GetCrumbButtonContent;
142
143 NextValidCrumbID = 0;
144
146 [
148 .Orientation(Orient_Horizontal)
149 .ScrollBarVisibility(EVisibility::Collapsed)
150 ];
151
152 AddLeadingDelimiter();
153 }
154
156 void PushCrumb(const TAttribute<FText>& CrumbText, const ItemType& NewCrumbData)
157 {
158 // Create the crumb and add it to the crumb box
161
164
165 TSharedRef<SWidget> ContentWidget = GetCrumbButtonContentCallback.IsBound() ? GetCrumbButtonContentCallback.Execute(NewCrumbData, TextStyle) : SNullWidget::NullWidget;
166
167 // Add the crumb button
169 [
171
173 .FillHeight( 1.0f )
174 [
175 // Crumb Button
177 .ButtonStyle(ButtonStyle)
178 .ContentPadding(ButtonContentPadding)
179 .TextStyle(TextStyle)
180 .Text(CrumbText)
181 .OnClicked( this, &SBreadcrumbTrail::CrumbButtonClicked, NextValidCrumbID )
182 .Content()
183 [
184 ContentWidget
185 ]
186 ]
187 ];
188
190 if ( GetCrumbMenuContentCallback.IsBound() )
191 {
192 // Crumb Arrow
194 .VAlign(EVerticalAlignment::VAlign_Center)
195 .ButtonStyle(ButtonStyle)
196 .Visibility(this, &SBreadcrumbTrail::GetCrumbDelimiterVisibility, NextValidCrumbID)
197 .OnClicked(this, &SBreadcrumbTrail::OnCrumbDelimiterClicked, NextValidCrumbID)
198 .ContentPadding(FMargin(3, 0))
199 [
200 SNew(SImage)
201 .Image(DelimiterImage)
202 .ColorAndOpacity(FSlateColor::UseForeground())
203 ];
204 }
205 else
206 {
208 .VAlign(EVerticalAlignment::VAlign_Center)
209 .ButtonStyle(ButtonStyle)
210 .Visibility( this, &SBreadcrumbTrail::GetDelimiterVisibility, NextValidCrumbID )
211 .ContentPadding( FMargin(3, 0) )
212 [
213 SNew(SImage)
214 .Image(DelimiterImage)
215 .ColorAndOpacity(FSlateColor::UseForeground())
216 ];
217 }
218
220 [
222
224 .FillHeight(1.0f)
225 [
226 SAssignNew( NewDelimiter, SMenuAnchor )
227 .OnGetMenuContent( this, &SBreadcrumbTrail::GetCrumbMenuContent, NextValidCrumbID )
228 [
230 ]
231 ]
232 ];
233
234 // Push the crumb data
235 CrumbList.Emplace(NextValidCrumbID, NewButton.ToSharedRef(), NewDelimiter.ToSharedRef(), NewButtonBox.ToSharedRef(), NewDelimiterBox.ToSharedRef(), NewCrumbData);
236
237 // Increment the crumb ID for the next crumb
238 NextValidCrumbID = (NextValidCrumbID + 1) % (INT_MAX - 1);
239
240 // Trigger event
241 OnCrumbPushed.ExecuteIfBound(NewCrumbData);
242
243 // We've added a new crumb so defer scrolling to the end to next tick
245 }
246
248 ItemType PopCrumb()
249 {
250 check(HasCrumbs());
251
252 // Remove from the crumb list and box
253 const FCrumbItem& LastCrumbItem = CrumbList.Pop();
254
256 CrumbBox->RemoveSlot(LastCrumbItem.DelimiterBox);
257
258 // Trigger event
259 OnCrumbPopped.ExecuteIfBound(LastCrumbItem.CrumbData);
260
261 // Return the popped crumb's data
262 return LastCrumbItem.CrumbData;
263 }
264
266 ItemType PeekCrumb() const
267 {
268 check(HasCrumbs());
269
270 // Return the last crumb's text
271 return CrumbList.Last().CrumbData;
272 }
273
275 bool HasCrumbs() const
276 {
277 return NumCrumbs() > 0;
278 }
279
282 {
283 return CrumbList.Num();
284 }
285
288 {
290 {
291 while ( HasCrumbs() )
292 {
293 PopCrumb();
294 }
295 }
296 else
297 {
299 CrumbList.Empty();
300
301 AddLeadingDelimiter();
302 }
303 }
304
306 void GetAllCrumbData(TArray<ItemType>& CrumbData) const
307 {
308 for (int32 CrumbIdx = 0; CrumbIdx < NumCrumbs(); ++CrumbIdx)
309 {
310 CrumbData.Add(CrumbList[CrumbIdx].CrumbData);
311 }
312 }
313
314private:
315
316 EVisibility GetCrumbDelimiterVisibility(int32 CrumbID) const
317 {
318 if (HasCrumbs() && CrumbList.Last().CrumbID == CrumbID && HasCrumbMenuContentCallback.IsBound() && !HasCrumbMenuContentCallback.Execute(CrumbList.Last().CrumbData))
319 {
321 }
323 }
324
325 FReply OnCrumbDelimiterClicked( int32 CrumbID )
326 {
327 FReply Reply = FReply::Unhandled();
328
329 if ( GetCrumbMenuContentCallback.IsBound() )
330 {
332 {
333 if (CrumbList[CrumbListIdx].CrumbID == CrumbID)
334 {
335 CrumbList[CrumbListIdx].Delimiter->SetIsOpen( true );
336 Reply = FReply::Handled();
337 break;
338 }
339 }
340 }
341
342 return Reply;
343 }
344
345 TSharedRef< SWidget > GetCrumbMenuContent( int32 CrumbId )
346 {
347 if ( !GetCrumbMenuContentCallback.IsBound() )
348 {
350 }
351
353
355 {
356 if (CrumbList[CrumbListIdx].CrumbID == CrumbId)
357 {
358 if (HasCrumbMenuContentCallback.IsBound() )
359 {
360 if (!HasCrumbMenuContentCallback.Execute( CrumbList[CrumbListIdx].CrumbData ))
361 {
363 }
364 }
365
366 MenuContent = GetCrumbMenuContentCallback.Execute( CrumbList[CrumbListIdx].CrumbData );
367 break;
368 }
369 }
370
371 return MenuContent.ToSharedRef();
372 }
373
375 EVisibility GetDelimiterVisibility(int32 CrumbID) const
376 {
377 if ( HasCrumbs() && CrumbList.Last().CrumbID == CrumbID )
378 {
379 // Collapse the last delimiter
381 }
382
384 }
385
387 EVisibility GetLeadingDelimiterVisibility() const
388 {
389 return ShowLeadingDelimiter.Get() ? EVisibility::Visible : EVisibility::Collapsed;
390 }
391
393 FReply CrumbButtonClicked(int32 CrumbID)
394 {
396
397 if (bHasStaticBreadcrumbs)
398 {
400 {
401 if (CrumbList[CrumbListIdx].CrumbID == CrumbID)
402 {
403 OnCrumbClicked.ExecuteIfBound(CrumbList[CrumbListIdx].CrumbData);
404 break;
405 }
406 }
407 }
408 else
409 {
411 {
412 if (CrumbList[CrumbListIdx].CrumbID == CrumbID)
413 {
415 break;
416 }
417 }
418
419 if ( CrumbIdx != INDEX_NONE )
420 {
421 while (NumCrumbs() - 1 > CrumbIdx)
422 {
423 PopCrumb();
424 }
425
426 OnCrumbClicked.ExecuteIfBound(CrumbList.Last().CrumbData);
427 }
428 }
429 return FReply::Handled();
430 }
431
433 void AddLeadingDelimiter()
434 {
436 .VAlign(VAlign_Center)
437 [
438 SNew(SImage)
439 .Image(DelimiterImage)
440 .Visibility( this, &SBreadcrumbTrail::GetLeadingDelimiterVisibility )
441 ];
442 }
443
444private:
445
447 TArray<FCrumbItem> CrumbList;
448
450 int32 NextValidCrumbID;
451
453 const FButtonStyle* ButtonStyle;
454
456 const FTextBlockStyle* TextStyle;
457
459 TAttribute<FMargin> ButtonContentPadding;
460
463
465 FOnCrumbPushed OnCrumbPushed;
466
468 FOnCrumbPopped OnCrumbPopped;
469
471 FOnCrumbClicked OnCrumbClicked;
472
474 FHasCrumbMenuContent HasCrumbMenuContentCallback;
475
477 FGetCrumbMenuContent GetCrumbMenuContentCallback;
478
480 FGetCrumbButtonContent GetCrumbButtonContentCallback;
481
483 TAttribute<bool> ShowLeadingDelimiter;
484
486 bool bHasStaticBreadcrumbs;
487
488};
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define check(expr)
Definition AssertionMacros.h:314
@ INDEX_NONE
Definition CoreMiscDefines.h:150
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define SLATE_STYLE_ARGUMENT(ArgType, ArgName)
Definition DeclarativeSyntaxSupport.h:280
#define SAssignNew(ExposeAs, WidgetType,...)
Definition DeclarativeSyntaxSupport.h:41
#define SNew(WidgetType,...)
Definition DeclarativeSyntaxSupport.h:37
#define SLATE_ATTRIBUTE(AttrType, AttrName)
Definition DeclarativeSyntaxSupport.h:192
#define SLATE_EVENT(DelegateName, EventName)
Definition DeclarativeSyntaxSupport.h:458
#define SLATE_END_ARGS()
Definition DeclarativeSyntaxSupport.h:116
#define SLATE_ARGUMENT(ArgType, ArgName)
Definition DeclarativeSyntaxSupport.h:208
Definition CoreStyle.h:15
Definition Reply.h:24
static FReply Unhandled()
Definition Reply.h:241
static FReply Handled()
Definition Reply.h:233
Definition SBreadcrumbTrail.h:25
TSharedPtr< SScrollBox > CrumbBox
Definition SBreadcrumbTrail.h:32
SLATE_API void ScrollToStart()
Definition SBreadcrumbTrail.cpp:5
SLATE_API void ScrollToEnd()
Definition SBreadcrumbTrail.cpp:10
Definition SBreadcrumbTrail.h:40
void ClearCrumbs(bool bPopAllCrumbsToClear=false)
Definition SBreadcrumbTrail.h:287
ItemType PopCrumb()
Definition SBreadcrumbTrail.h:248
DECLARE_DELEGATE_RetVal_OneParam(TSharedRef< SWidget >, FGetCrumbMenuContent, const ItemType &)
SLATE_BEGIN_ARGS(SBreadcrumbTrail)
Definition SBreadcrumbTrail.h:81
DECLARE_DELEGATE_OneParam(FOnCrumbPushed, const ItemType &)
void Construct(const FArguments &InArgs)
Definition SBreadcrumbTrail.h:128
void GetAllCrumbData(TArray< ItemType > &CrumbData) const
Definition SBreadcrumbTrail.h:306
bool HasCrumbs() const
Definition SBreadcrumbTrail.h:275
DECLARE_DELEGATE_OneParam(FOnCrumbPopped, const ItemType &)
DECLARE_DELEGATE_RetVal_TwoParams(TSharedRef< SWidget >, FGetCrumbButtonContent, const ItemType &, const FTextBlockStyle *InTextStyle)
int32 NumCrumbs() const
Definition SBreadcrumbTrail.h:281
DECLARE_DELEGATE_OneParam(FOnCrumbClicked, const ItemType &)
DECLARE_DELEGATE_RetVal_OneParam(bool, FHasCrumbMenuContent, const ItemType &)
ItemType PeekCrumb() const
Definition SBreadcrumbTrail.h:266
void PushCrumb(const TAttribute< FText > &CrumbText, const ItemType &NewCrumbData)
Definition SBreadcrumbTrail.h:156
Definition SButton.h:33
Definition SCompoundWidget.h:22
FCompoundWidgetOneChildSlot ChildSlot
Definition SCompoundWidget.h:113
Definition SImage.h:29
static SLATECORE_API TSharedRef< class SWidget > NullWidget
Definition SNullWidget.h:22
Definition SScrollBox.h:76
SLATE_API void ScrollToEnd()
Definition SScrollBox.cpp:457
SLATE_API void RemoveSlot(const TSharedRef< SWidget > &WidgetToRemove)
Definition SScrollBox.cpp:324
SLATE_API void ClearChildren()
Definition SScrollBox.cpp:334
SLATE_API FScopedWidgetSlotArguments AddSlot()
Definition SScrollBox.cpp:302
Definition SBoxPanel.h:322
static FSlot::FSlotArguments Slot()
Definition SBoxPanel.h:424
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_NODEBUG UE_FORCEINLINE_HINT ElementType & Last(SizeType IndexFromTheEnd=0) UE_LIFETIMEBOUND
Definition Array.h:1263
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
ElementType Pop(EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:1196
void Empty(SizeType Slack=0)
Definition Array.h:2273
Definition Attribute.h:17
const ObjectType & Get() const
Definition Attribute.h:241
Definition SharedPointer.h:692
Definition SharedPointer.h:153
@ false
Definition radaudio_common.h:23
Definition Visibility.h:12
static SLATECORE_API const EVisibility Visible
Definition Visibility.h:14
static SLATECORE_API const EVisibility Collapsed
Definition Visibility.h:17
Definition SlateTypes.h:509
Definition Margin.h:17
Definition SlateBrush.h:239
static FSlateColor UseForeground()
Definition SlateColor.h:198
Definition SlateTypes.h:326