Files
UnrealEngine/Engine/Source/Runtime/Slate/Public/Widgets/Views/SHeaderRow.h
2025-05-18 13:04:45 +08:00

406 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/IndirectArray.h"
#include "Misc/Attribute.h"
#include "Layout/Visibility.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Layout/Margin.h"
#include "Styling/SlateTypes.h"
#include "Styling/CoreStyle.h"
#include "Widgets/Layout/SBorder.h"
#include "Styling/SlateWidgetStyleAsset.h"
#include "Widgets/Layout/SSplitter.h"
#include "Framework/SlateDelegates.h"
class FMenuBuilder;
class SScrollBar;
enum class ECheckBoxState : uint8;
namespace EColumnSortPriority
{
enum Type
{
None,
Primary = 0,
Secondary = 1,
Max,
};
};
namespace EColumnSortMode
{
enum Type
{
/** Unsorted */
None = 0,
/** Ascending */
Ascending = 1,
/** Descending */
Descending = 2
};
};
namespace EColumnSizeMode
{
enum Type
{
/** Column stretches to a fraction of the header row */
Fill = 0,
/** Column is fixed width and cannot be resized */
Fixed = 1,
/** Column is set to a width which can be user-sized */
Manual = 2,
/** Column stretches as Fill but is initialized with a width */
FillSized = 3,
};
};
enum class EHeaderComboVisibility
{
/** Always show the drop down at full opacity */
Always,
/** Always show the drop down, but in a ghosted way when not hovered */
Ghosted,
/** Only show the drop down when hovered */
OnHover,
/** Never show the drop down. Context Menu can still be opened with a context click (such as right-click) */
Never
};
/** Callback when sort mode changes */
DECLARE_DELEGATE_ThreeParams( FOnSortModeChanged, EColumnSortPriority::Type, const FName&, EColumnSortMode::Type );
/** Callback when the width of the column changes */
DECLARE_DELEGATE_OneParam( FOnWidthChanged, float );
/** Callback to fetch the max row width for a specified column id */
DECLARE_DELEGATE_RetVal_TwoParams(FVector2D, FOnGetMaxRowSizeForColumn, const FName&, EOrientation);
/**
* The header that appears above lists and trees when they are showing multiple columns.
*/
class SHeaderRow : public SBorder
{
public:
/** Describes a single column header */
class FColumn
{
public:
SLATE_BEGIN_ARGS(FColumn)
: _ColumnId()
, _DefaultLabel()
, _DefaultTooltip()
, _ToolTip()
, _FillWidth( 1.0f )
, _FixedWidth()
, _ManualWidth()
, _OnWidthChanged()
, _HeaderContent()
, _HAlignHeader( HAlign_Fill )
, _VAlignHeader( VAlign_Fill )
, _HeaderContentPadding()
, _HeaderComboVisibility(EHeaderComboVisibility::OnHover)
, _MenuContent()
, _HAlignCell( HAlign_Fill )
, _VAlignCell( VAlign_Fill )
, _InitialSortMode( EColumnSortMode::Ascending )
, _SortMode( EColumnSortMode::None )
, _IsSorting( false )
, _OnSort()
, _OverflowPolicy( ETextOverflowPolicy::Clip)
{}
SLATE_ARGUMENT( FName, ColumnId )
SLATE_ATTRIBUTE( FText, DefaultLabel )
SLATE_ATTRIBUTE( FText, DefaultTooltip )
SLATE_ATTRIBUTE( TSharedPtr< IToolTip >, ToolTip )
/** Set the Column Size Mode to Fill. It's a fraction between 0 and 1 */
SLATE_ATTRIBUTE( float, FillWidth )
/** Set the Column Size Mode to Fixed. */
SLATE_ARGUMENT( TOptional< float >, FixedWidth )
/** Set the Column Size Mode to Manual. */
SLATE_ATTRIBUTE( float, ManualWidth )
/** Set the Column Size Mode to Fill Sized. */
SLATE_ARGUMENT(TOptional< float >, FillSized)
SLATE_EVENT( FOnWidthChanged, OnWidthChanged )
SLATE_DEFAULT_SLOT( FArguments, HeaderContent )
SLATE_ARGUMENT( EHorizontalAlignment, HAlignHeader )
SLATE_ARGUMENT( EVerticalAlignment, VAlignHeader )
SLATE_ARGUMENT( TOptional< FMargin >, HeaderContentPadding )
SLATE_ARGUMENT( EHeaderComboVisibility, HeaderComboVisibility )
SLATE_NAMED_SLOT( FArguments, MenuContent )
SLATE_EVENT( FOnGetContent, OnGetMenuContent )
/** Allow to provide a custom handler when a splitter is double-clicked in Manual column size mode. */
SLATE_EVENT( FPointerEventHandler, OnColumnSplitterDoubleClick )
SLATE_ARGUMENT( EHorizontalAlignment, HAlignCell )
SLATE_ARGUMENT( EVerticalAlignment, VAlignCell )
SLATE_ATTRIBUTE( EColumnSortMode::Type, InitialSortMode )
SLATE_ATTRIBUTE( EColumnSortMode::Type, SortMode )
SLATE_ATTRIBUTE( EColumnSortPriority::Type, SortPriority )
SLATE_ATTRIBUTE( bool, IsSorting )
SLATE_EVENT( FOnSortModeChanged, OnSort )
SLATE_ATTRIBUTE(bool, ShouldGenerateWidget)
SLATE_ARGUMENT(ETextOverflowPolicy, OverflowPolicy)
SLATE_END_ARGS()
FColumn( const FArguments& InArgs )
: ColumnId( InArgs._ColumnId )
, DefaultText( InArgs._DefaultLabel )
, DefaultTooltip( InArgs._DefaultTooltip )
, ToolTip(InArgs._ToolTip)
, Width( 1.0f )
, DefaultWidth( 1.0f )
, OnWidthChanged( InArgs._OnWidthChanged)
, SizeRule( EColumnSizeMode::Fill )
, HeaderContent( InArgs._HeaderContent )
, HeaderMenuContent( InArgs._MenuContent )
, OnGetMenuContent( InArgs._OnGetMenuContent )
, OnColumnSplitterDoubleClick( InArgs._OnColumnSplitterDoubleClick )
, HeaderHAlignment( InArgs._HAlignHeader )
, HeaderVAlignment( InArgs._VAlignHeader )
, HeaderContentPadding( InArgs._HeaderContentPadding )
, HeaderComboVisibility (InArgs._HeaderComboVisibility )
, CellHAlignment( InArgs._HAlignCell )
, CellVAlignment( InArgs._VAlignCell )
, OverflowPolicy(InArgs._OverflowPolicy)
, InitialSortMode( InArgs._InitialSortMode )
, SortMode( InArgs._SortMode )
, SortPriority( InArgs._SortPriority )
, IsSorting( InArgs._IsSorting)
, OnSortModeChanged( InArgs._OnSort )
, ShouldGenerateWidget(InArgs._ShouldGenerateWidget)
, bIsVisible(true)
{
if ( InArgs._FixedWidth.IsSet() )
{
Width = InArgs._FixedWidth.GetValue();
SizeRule = EColumnSizeMode::Fixed;
}
else if ( InArgs._ManualWidth.IsSet() )
{
Width = InArgs._ManualWidth;
SizeRule = EColumnSizeMode::Manual;
}
else if ( InArgs._FillSized.IsSet() )
{
Width = InArgs._FillSized.GetValue();
SizeRule = EColumnSizeMode::FillSized;
}
else
{
Width = InArgs._FillWidth;
SizeRule = EColumnSizeMode::Fill;
}
DefaultWidth = Width.Get();
}
public:
void SetWidth( float NewWidth )
{
if ( OnWidthChanged.IsBound() )
{
OnWidthChanged.Execute( NewWidth );
}
else
{
Width = NewWidth;
}
}
float GetWidth() const
{
return Width.Get();
}
/** A unique ID for this column, so that it can be saved and restored. */
FName ColumnId;
/** Default text to use if no widget is passed in. */
TAttribute< FText > DefaultText;
/** Default tooltip to use if no widget is passed in */
TAttribute< FText > DefaultTooltip;
/** Custom tooltip to use */
TAttribute< TSharedPtr< IToolTip > > ToolTip;
/** A column width in Slate Units */
TAttribute< float > Width;
/** A original column width in Slate Units */
float DefaultWidth;
FOnWidthChanged OnWidthChanged;
EColumnSizeMode::Type SizeRule;
TAlwaysValidWidget HeaderContent;
TAlwaysValidWidget HeaderMenuContent;
FOnGetContent OnGetMenuContent;
FPointerEventHandler OnColumnSplitterDoubleClick;
EHorizontalAlignment HeaderHAlignment;
EVerticalAlignment HeaderVAlignment;
TOptional< FMargin > HeaderContentPadding;
EHeaderComboVisibility HeaderComboVisibility;
EHorizontalAlignment CellHAlignment;
EVerticalAlignment CellVAlignment;
ETextOverflowPolicy OverflowPolicy;
TAttribute< EColumnSortMode::Type > InitialSortMode;
TAttribute< EColumnSortMode::Type > SortMode;
TAttribute< EColumnSortPriority::Type > SortPriority;
TAttribute< bool > IsSorting;
FOnSortModeChanged OnSortModeChanged;
TAttribute<bool> ShouldGenerateWidget;
bool bIsVisible;
};
/** Create a column with the specified ColumnId */
static FColumn::FArguments Column( const FName& InColumnId )
{
FColumn::FArguments NewArgs;
NewArgs.ColumnId( InColumnId );
return NewArgs;
}
DECLARE_EVENT_OneParam( SHeaderRow, FColumnsChanged, const TSharedRef< SHeaderRow >& );
FColumnsChanged* OnColumnsChanged() { return &ColumnsChanged; }
SLATE_BEGIN_ARGS(SHeaderRow)
: _Style( &FAppStyle::Get().GetWidgetStyle<FHeaderRowStyle>("TableView.Header") )
, _ResizeMode(ESplitterResizeMode::Fill)
, _CanSelectGeneratedColumn(false)
{}
SLATE_STYLE_ARGUMENT( FHeaderRowStyle, Style )
SLATE_SUPPORTS_SLOT_WITH_ARGS( FColumn )
SLATE_EVENT( FColumnsChanged::FDelegate, OnColumnsChanged )
SLATE_EVENT( FOnGetMaxRowSizeForColumn, OnGetMaxRowSizeForColumn )
SLATE_ARGUMENT( ESplitterResizeMode::Type, ResizeMode )
SLATE_ARGUMENT( TOptional<float>, SplitterHandleSize )
/**
* Can select the columns generated by right clicking on the header menu.
* FColumn with ShouldGenerateWidget set can not be selected.
* FColumn with MenuContent will still be displayed.
*/
SLATE_ARGUMENT( bool, CanSelectGeneratedColumn )
/** The list of column ids that should not be generated by default. */
SLATE_ARGUMENT( TArray<FName>, HiddenColumnsList )
/** Triggered when columns visibility changed. */
SLATE_EVENT( FSimpleDelegate, OnHiddenColumnsListChanged )
SLATE_END_ARGS()
SLATE_API void Construct( const FArguments& InArgs );
/** Restore the columns to their original width */
SLATE_API void ResetColumnWidths();
/** @return the Columns driven by the column headers */
SLATE_API const TIndirectArray<FColumn>& GetColumns() const;
/** Adds a column to the header */
SLATE_API void AddColumn( const FColumn::FArguments& NewColumnArgs );
SLATE_API void AddColumn( FColumn& NewColumn );
/** Inserts a column at the specified index in the header */
SLATE_API void InsertColumn( const FColumn::FArguments& NewColumnArgs, int32 InsertIdx );
SLATE_API void InsertColumn( FColumn& NewColumn, int32 InsertIdx );
/** Removes a column from the header */
SLATE_API void RemoveColumn( const FName& InColumnId );
/** Force refreshing of the column widgets*/
SLATE_API void RefreshColumns();
/** Removes all columns from the header */
SLATE_API void ClearColumns();
SLATE_API void SetAssociatedVerticalScrollBar( const TSharedRef< SScrollBar >& ScrollBar, const float ScrollBarSize );
/** Sets the column, with the specified name, to the desired width */
SLATE_API void SetColumnWidth( const FName& InColumnId, float InWidth );
/** Will return the size for this row at the specified slot index */
SLATE_API FVector2D GetRowSizeForSlotIndex(int32 SlotIndex) const;
/** Simple function to set the delegate to fetch the max row size for column id */
void SetOnGetMaxRowSizeForColumn(const FOnGetMaxRowSizeForColumn& Delegate) { OnGetMaxRowSizeForColumn = Delegate; }
/** @return The columns id of the header widgets that were not generated */
SLATE_API TArray<FName> GetHiddenColumnIds() const;
/** @return is the header widget should be generated */
SLATE_API bool ShouldGeneratedColumn( const FName& InColumnId ) const;
/** @return is the header widget with the column id is generated */
SLATE_API bool IsColumnGenerated( const FName& InColumnId ) const;
/** @return true if the header widget with the column id is visible */
SLATE_API bool IsColumnVisible( const FName& InColumnId ) const;
//~ Begin SWidget interface
SLATE_API virtual FReply OnMouseButtonUp( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
//~ End SWidget interface
/** Show or Hide a generated column */
SLATE_API void SetShowGeneratedColumn(const FName& InColumnIdm, bool InShow = true);
private:
/** Regenerates all widgets in the header */
SLATE_API void RegenerateWidgets();
void ToggleAllColumns();
bool CanToggleAllColumns() const;
ECheckBoxState GetSelectAllColumnsCheckState() const;
FText GetToggleAllColumnsText() const;
void OnGenerateSelectColumnsSubMenu(FMenuBuilder& InSubMenuBuilder);
SLATE_API void ToggleGeneratedColumn(FName ColumnId);
SLATE_API ECheckBoxState GetGeneratedColumnCheckedState(FName ColumnId) const;
/** Information about the various columns */
TIndirectArray<FColumn> Columns;
TArray<TSharedPtr<class STableColumnHeader>> HeaderWidgets;
FVector2f ScrollBarThickness;
TAttribute< EVisibility > ScrollBarVisibility;
const FHeaderRowStyle* Style;
FColumnsChanged ColumnsChanged;
ESplitterResizeMode::Type ResizeMode;
float SplitterHandleSize;
FOnGetMaxRowSizeForColumn OnGetMaxRowSizeForColumn;
FSimpleDelegate OnHiddenColumnsListChanged;
bool bCanSelectGeneratedColumn;
};