// Copyright Epic Games, Inc. All Rights Reserved. #include "STimingViewTrackList.h" #include "EditorFontGlyphs.h" #include "EditorStyleSet.h" #include "Framework/Application/SlateApplication.h" #include "Widgets/Input/SCheckBox.h" #include "Widgets/Input/SSearchBox.h" #include "Widgets/Text/STextBlock.h" #include "Widgets/Layout/SScrollBorder.h" #include "Widgets/SBoxPanel.h" #include "Widgets/Views/SHeaderRow.h" // Insights #include "Insights/ViewModels/BaseTimingTrack.h" #include "Insights/Widgets/STimingView.h" #define LOCTEXT_NAMESPACE "STimingViewTrackList" //////////////////////////////////////////////////////////////////////////////////////////////////// // STimingViewTrackListEntry //////////////////////////////////////////////////////////////////////////////////////////////////// // A list entry widget for a track class STimingViewTrackListEntry: public STableRow> { public: SLATE_BEGIN_ARGS(STimingViewTrackListEntry) {} SLATE_ARGUMENT(TSharedPtr, TimingView) SLATE_ARGUMENT(ETimingTrackLocation, TrackLocation) SLATE_ARGUMENT(TSharedPtr, Track) SLATE_ATTRIBUTE(FText, SearchText) SLATE_END_ARGS() void Construct(const FArguments& InArgs, const TSharedRef& InOwnerTable) { TimingView = InArgs._TimingView; TrackLocation = InArgs._TrackLocation; Track = InArgs._Track; SearchText = InArgs._SearchText; STableRow>::Construct(STableRow>::FArguments(), InOwnerTable); } virtual void ConstructChildren(ETableViewMode::Type InOwnerTableMode, const TAttribute& InPadding, const TSharedRef& InContent) override { ChildSlot [ // SNew(SHorizontalBox) //+ SHorizontalBox::Slot() //.AutoWidth() //.Padding(2.0f) //.HAlign(HAlign_Center) //.VAlign(VAlign_Center) //[ SNew(SCheckBox) .IsChecked_Lambda([this]() { return Track.Pin()->IsVisible() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; }) .OnCheckStateChanged_Lambda([this](ECheckBoxState InCheckBoxState) { Track.Pin()->SetVisibilityFlag(InCheckBoxState == ECheckBoxState::Checked); Track.Pin()->SetDirtyFlag(); TimingView.Pin()->OnTrackVisibilityChanged(); }) .Content()[SNew(STextBlock).Text(FText::FromString(Track.Pin()->GetName())).HighlightText(SearchText)] //] //+ SHorizontalBox::Slot() //.FillWidth(1.0f) //.Padding(2.0f) //.HAlign(HAlign_Right) //.VAlign(VAlign_Center) //[ // SNew(STextBlock) // .Font(FEditorStyle::Get().GetFontStyle("FontAwesome.9")) // .ColorAndOpacity_Lambda([this](){ return FSlateColor(Track.Pin()->GetColor()); }) // .Text(FEditorFontGlyphs::Circle) //] ]; } // The widget containing the track we represent TWeakPtr TimingView; // The location of the track we represent ETimingTrackLocation TrackLocation; // The track we represent TWeakPtr Track; // The search text to highlight TAttribute SearchText; }; //////////////////////////////////////////////////////////////////////////////////////////////////// // STimingViewTrackList //////////////////////////////////////////////////////////////////////////////////////////////////// void STimingViewTrackList::Construct(const FArguments& InArgs, const TSharedRef& InTimingView, ETimingTrackLocation InTrackLocation) { TimingView = InTimingView; TrackLocation = InTrackLocation; FilteredTracks = InTimingView->GetTrackList(TrackLocation); ListView = SNew(SListView>) .IsFocusable(true) .ItemHeight(20.0f) .SelectionMode(ESelectionMode::None) .ListItemsSource(&FilteredTracks) .OnGenerateRow(this, &STimingViewTrackList::OnGenerateRow); ChildSlot [SNew(SVerticalBox) + SVerticalBox::Slot().AutoHeight()[SNew(SHorizontalBox) + SHorizontalBox::Slot().AutoWidth().Padding(2.0f, 0.0f)[ // Checkbox for bulk operations SNew(SCheckBox).IsChecked_Lambda([this]() { int32 NumVisible = 0; for (TSharedPtr Track: FilteredTracks) { if (Track->IsVisible()) { NumVisible++; } } if (NumVisible == 0) { return ECheckBoxState::Unchecked; } else if (NumVisible == FilteredTracks.Num()) { return ECheckBoxState::Checked; } return ECheckBoxState::Undetermined; }) .OnCheckStateChanged_Lambda([this](ECheckBoxState InCheckBoxState) { const bool bVisible = InCheckBoxState != ECheckBoxState::Unchecked; for (TSharedPtr Track: FilteredTracks) { Track->SetVisibilityFlag(bVisible); Track->SetDirtyFlag(); } TimingView.Pin()->OnTrackVisibilityChanged(); })] + SHorizontalBox::Slot().FillWidth(1.0f)[ // Search box allows for filtering SAssignNew(SearchBox, SSearchBox).OnTextChanged_Lambda([this](const FText& InText) { SearchText = InText; RefreshFilter(); })]] + SVerticalBox::Slot().FillHeight(1.0f)[SNew(SScrollBorder, ListView.ToSharedRef())[ListView.ToSharedRef()]]]; // Set focus to the search box on creation FSlateApplication::Get().SetKeyboardFocus(SearchBox); FSlateApplication::Get().SetUserFocus(0, SearchBox); } //////////////////////////////////////////////////////////////////////////////////////////////////// TSharedRef STimingViewTrackList::OnGenerateRow(TSharedPtr Item, const TSharedRef& OwnerTable) { return SNew(STimingViewTrackListEntry, OwnerTable) .TimingView(TimingView.Pin()) .TrackLocation(TrackLocation) .Track(Item) .SearchText_Lambda([this]() { return SearchText; }); } //////////////////////////////////////////////////////////////////////////////////////////////////// void STimingViewTrackList::RefreshFilter() { FilteredTracks.Reset(); for (TSharedPtr Track: TimingView.Pin()->GetTrackList(TrackLocation)) { if (SearchText.IsEmpty() || Track->GetName().Contains(SearchText.ToString())) { FilteredTracks.Add(Track); } } ListView->RequestListRefresh(); } //////////////////////////////////////////////////////////////////////////////////////////////////// #undef LOCTEXT_NAMESPACE