2025-07-08 16:50:31 +02:00
|
|
|
|
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "Widget/DTFluxAssetModelDetailsWidget.h"
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
#include "DTFluxAssetsEditorModule.h"
|
2025-07-08 16:50:31 +02:00
|
|
|
|
#include "Widgets/Layout/SBorder.h"
|
|
|
|
|
|
#include "Widgets/Layout/SBox.h"
|
|
|
|
|
|
#include "Widgets/Text/STextBlock.h"
|
|
|
|
|
|
#include "Widgets/Input/SButton.h"
|
|
|
|
|
|
#include "Widgets/Views/STableRow.h"
|
|
|
|
|
|
#include "Widgets/Views/SHeaderRow.h"
|
|
|
|
|
|
|
|
|
|
|
|
void SHierarchicalTreeItemRow::Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView)
|
|
|
|
|
|
{
|
|
|
|
|
|
Item = InArgs._Item;
|
|
|
|
|
|
ParentWidget = InArgs._ParentWidget;
|
|
|
|
|
|
|
|
|
|
|
|
SMultiColumnTableRow<TSharedPtr<FHierarchicalTreeItem>>::Construct(
|
|
|
|
|
|
SMultiColumnTableRow<TSharedPtr<FHierarchicalTreeItem>>::FArguments(),
|
|
|
|
|
|
InOwnerTableView
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TSharedRef<SWidget> SHierarchicalTreeItemRow::GenerateWidgetForColumn(const FName& ColumnName)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!Item.IsValid())
|
|
|
|
|
|
{
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Warning, TEXT("GenerateWidgetForColumn: Invalid item for column %s"), *ColumnName.ToString());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return SNew(STextBlock).Text(FText::FromString("Invalid Item"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!ParentWidget)
|
|
|
|
|
|
{
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Warning, TEXT("GenerateWidgetForColumn: Invalid ParentWidget for column %s"),
|
|
|
|
|
|
// *ColumnName.ToString());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return SNew(STextBlock).Text(FText::FromString("Invalid Parent"));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, VeryVerbose, TEXT("GenerateWidgetForColumn: %s for item %s"),
|
|
|
|
|
|
// *ColumnName.ToString(), *Item->Name);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
if (ColumnName == "Name")
|
|
|
|
|
|
{
|
|
|
|
|
|
return SNew(SHorizontalBox)
|
|
|
|
|
|
+ SHorizontalBox::Slot()
|
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
|
.Padding(0, 0, 5, 0)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SImage)
|
|
|
|
|
|
.Image(ParentWidget->GetItemIcon(Item->Type))
|
|
|
|
|
|
.ColorAndOpacity(ParentWidget->GetItemTypeColor(Item->Type))
|
|
|
|
|
|
]
|
|
|
|
|
|
+ SHorizontalBox::Slot()
|
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
|
.VAlign(VAlign_Center)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString(Item->Name))
|
|
|
|
|
|
.ColorAndOpacity(ParentWidget->GetItemTypeColor(Item->Type))
|
|
|
|
|
|
.Font_Lambda([this]() -> FSlateFontInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
return Item->Type == FHierarchicalTreeItem::EItemType::Contest
|
|
|
|
|
|
? FAppStyle::GetFontStyle("HeadingText")
|
|
|
|
|
|
: FAppStyle::GetFontStyle("NormalText");
|
|
|
|
|
|
})
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ColumnName == "ID")
|
|
|
|
|
|
{
|
|
|
|
|
|
return SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString(Item->ID))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("NormalText"))
|
|
|
|
|
|
.Justification(ETextJustify::Center);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ColumnName == "Details")
|
|
|
|
|
|
{
|
|
|
|
|
|
return SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString(Item->Details))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("NormalText"))
|
|
|
|
|
|
.OverflowPolicy(ETextOverflowPolicy::Ellipsis);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ColumnName == "Status")
|
|
|
|
|
|
{
|
|
|
|
|
|
return SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString(Item->Status))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("NormalText"))
|
|
|
|
|
|
.OverflowPolicy(ETextOverflowPolicy::Ellipsis);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ColumnName == "Extra")
|
|
|
|
|
|
{
|
|
|
|
|
|
return SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString(Item->Extra))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("NormalText"))
|
|
|
|
|
|
.OverflowPolicy(ETextOverflowPolicy::Ellipsis);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
UE_LOG(logDTFluxAssetEditor, Warning, TEXT("GenerateWidgetForColumn: Unknown column %s"), *ColumnName.ToString());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return SNew(STextBlock).Text(FText::FromString(FString::Printf(TEXT("Unknown: %s"), *ColumnName.ToString())));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::Construct(const FArguments& InArgs)
|
|
|
|
|
|
{
|
|
|
|
|
|
ModelAsset = InArgs._ModelAsset;
|
|
|
|
|
|
|
|
|
|
|
|
ChildSlot
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SVerticalBox)
|
|
|
|
|
|
|
|
|
|
|
|
// === SECTION STATISTIQUES ===
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
.Padding(5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
|
|
|
|
.Padding(10)
|
|
|
|
|
|
[
|
|
|
|
|
|
SAssignNew(StatsText, STextBlock)
|
|
|
|
|
|
.Text(this, &SDTFluxAssetModelDetailsWidget::GetStatsText)
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("HeadingText"))
|
|
|
|
|
|
.Justification(ETextJustify::Center)
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// === SECTION BOUTONS DE NAVIGATION ===
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
.Padding(5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SHorizontalBox)
|
|
|
|
|
|
+ SHorizontalBox::Slot()
|
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
|
.Padding(0, 0, 5, 0)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SButton)
|
|
|
|
|
|
.ButtonStyle(FAppStyle::Get(), "SimpleButton")
|
|
|
|
|
|
.Text(FText::FromString("Expand All Contests"))
|
|
|
|
|
|
.OnClicked(this, &SDTFluxAssetModelDetailsWidget::OnExpandAllClicked)
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
+ SHorizontalBox::Slot()
|
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
|
.Padding(0, 0, 10, 0)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SButton)
|
|
|
|
|
|
.ButtonStyle(FAppStyle::Get(), "SimpleButton")
|
|
|
|
|
|
.Text(FText::FromString("Collapse All Contests"))
|
|
|
|
|
|
.OnClicked(this, &SDTFluxAssetModelDetailsWidget::OnCollapseAllClicked)
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
+ SHorizontalBox::Slot()
|
|
|
|
|
|
.FillWidth(1.0f)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SSpacer)
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
+ SHorizontalBox::Slot()
|
|
|
|
|
|
.AutoWidth()
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SButton)
|
|
|
|
|
|
.ButtonStyle(FAppStyle::Get(), "PrimaryButton")
|
|
|
|
|
|
.Text(FText::FromString("Refresh"))
|
|
|
|
|
|
.OnClicked(this, &SDTFluxAssetModelDetailsWidget::OnRefreshClicked)
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
#pragma region ListView
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.FillHeight(1.0f)
|
|
|
|
|
|
.Padding(5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
|
|
|
|
|
.Padding(0)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBox)
|
|
|
|
|
|
[
|
|
|
|
|
|
#pragma region ScrollBox
|
|
|
|
|
|
SNew(SScrollBox)
|
|
|
|
|
|
.Orientation(Orient_Vertical)
|
|
|
|
|
|
.ScrollBarVisibility(EVisibility::Visible)
|
|
|
|
|
|
.ConsumeMouseWheel(EConsumeMouseWheel::WhenScrollingPossible)
|
|
|
|
|
|
.ScrollBarAlwaysVisible(true) // Force la scrollbar à être toujours visible
|
|
|
|
|
|
|
|
|
|
|
|
#pragma region ListView.Contest
|
|
|
|
|
|
+ SScrollBox::Slot()
|
|
|
|
|
|
.Padding(0, 0, 0, 10)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SVerticalBox)
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
.Padding(5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
|
|
|
|
|
.Padding(10, 5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString("CONTESTS HIERARCHY"))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("HeadingText"))
|
|
|
|
|
|
.ColorAndOpacity(FLinearColor(0.2f, 0.6f, 1.0f))
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// TreeView Contests
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBox)
|
|
|
|
|
|
[
|
|
|
|
|
|
SAssignNew(ContestTreeView, STreeView<FHierarchicalTreeItemPtr>)
|
|
|
|
|
|
.TreeItemsSource(&RootItems)
|
|
|
|
|
|
.OnGenerateRow(this, &SDTFluxAssetModelDetailsWidget::OnGenerateRowForTree)
|
|
|
|
|
|
.OnGetChildren(this, &SDTFluxAssetModelDetailsWidget::OnGetChildrenForTree)
|
|
|
|
|
|
.OnSelectionChanged(
|
|
|
|
|
|
this, &SDTFluxAssetModelDetailsWidget::OnTreeSelectionChanged)
|
|
|
|
|
|
.OnSetExpansionRecursive(
|
|
|
|
|
|
this, &SDTFluxAssetModelDetailsWidget::OnSetExpansionRecursive)
|
|
|
|
|
|
.SelectionMode(ESelectionMode::Single)
|
|
|
|
|
|
.ConsumeMouseWheel(EConsumeMouseWheel::WhenScrollingPossible)
|
|
|
|
|
|
.HeaderRow
|
|
|
|
|
|
(
|
|
|
|
|
|
SNew(SHeaderRow)
|
|
|
|
|
|
.CanSelectGeneratedColumn(true)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Name")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Contest / Stage / Split"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("ID")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("ID"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
.FillWidth(.02f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Details")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Details"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
.FillWidth(.3f)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Status")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Status / Time"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
.FillWidth(.1f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Extra")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Extra Info"))
|
|
|
|
|
|
.FillWidth(.2f)
|
|
|
|
|
|
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
)
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
|
|
|
#pragma region ListView.Participant
|
|
|
|
|
|
+ SScrollBox::Slot()
|
|
|
|
|
|
.Padding(0, 10, 0, 0)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SVerticalBox)
|
|
|
|
|
|
|
|
|
|
|
|
// Header "Participants"
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
.Padding(5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
|
|
|
|
|
.Padding(10, 5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(STextBlock)
|
|
|
|
|
|
.Text(FText::FromString("PARTICIPANTS LIST"))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("HeadingText"))
|
|
|
|
|
|
.ColorAndOpacity(FLinearColor(0.2f, 0.8f, 0.8f))
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// TreeView Participants
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBox)
|
|
|
|
|
|
[
|
|
|
|
|
|
SAssignNew(ParticipantTreeView, STreeView<FHierarchicalTreeItemPtr>)
|
|
|
|
|
|
.TreeItemsSource(&ParticipantItems)
|
|
|
|
|
|
.OnGenerateRow(this, &SDTFluxAssetModelDetailsWidget::OnGenerateRowForTree)
|
|
|
|
|
|
.OnGetChildren(this, &SDTFluxAssetModelDetailsWidget::OnGetChildrenForTree)
|
|
|
|
|
|
.OnSelectionChanged(
|
|
|
|
|
|
this, &SDTFluxAssetModelDetailsWidget::OnTreeSelectionChanged)
|
|
|
|
|
|
.OnSetExpansionRecursive(
|
|
|
|
|
|
this, &SDTFluxAssetModelDetailsWidget::OnSetExpansionRecursive)
|
|
|
|
|
|
.SelectionMode(ESelectionMode::Single)
|
|
|
|
|
|
.ConsumeMouseWheel(EConsumeMouseWheel::WhenScrollingPossible)
|
|
|
|
|
|
.HeaderRow
|
|
|
|
|
|
(
|
|
|
|
|
|
SNew(SHeaderRow)
|
|
|
|
|
|
.CanSelectGeneratedColumn(true)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Name")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Participant"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("ID")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Bib"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
.FillWidth(.08f)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Details")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Category & Teammates"))
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
.FillWidth(.2f)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Status")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Status"))
|
|
|
|
|
|
.FillWidth(.1f)
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
|
|
|
|
|
|
+ SHeaderRow::Column("Extra")
|
|
|
|
|
|
.DefaultLabel(FText::FromString("Club"))
|
|
|
|
|
|
.FillWidth(.2f)
|
|
|
|
|
|
.SortMode(EColumnSortMode::None)
|
|
|
|
|
|
)
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
]
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
]
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
#pragma region DetailView.Participant
|
|
|
|
|
|
+ SVerticalBox::Slot()
|
|
|
|
|
|
.AutoHeight()
|
|
|
|
|
|
.Padding(5)
|
|
|
|
|
|
[
|
|
|
|
|
|
SNew(SBorder)
|
|
|
|
|
|
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
|
|
|
|
|
|
.Padding(10)
|
|
|
|
|
|
[
|
|
|
|
|
|
SAssignNew(SelectionText, STextBlock)
|
|
|
|
|
|
.Text(FText::FromString("Select an item to see details. Use expand/collapse arrows in the tree."))
|
|
|
|
|
|
.Font(FAppStyle::GetFontStyle("NormalText"))
|
|
|
|
|
|
.AutoWrapText(true)
|
|
|
|
|
|
]
|
|
|
|
|
|
]
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
RefreshData();
|
|
|
|
|
|
|
|
|
|
|
|
RegisterActiveTimer(
|
|
|
|
|
|
0.1f, FWidgetActiveTimerDelegate::CreateSP(this, &SDTFluxAssetModelDetailsWidget::ForceInitialLayout));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== CONSTRUCTION DE LA HIÉRARCHIE =====
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::BuildContestHierarchy()
|
|
|
|
|
|
{
|
|
|
|
|
|
RootItems.Empty();
|
|
|
|
|
|
|
|
|
|
|
|
if (!ModelAsset)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// Construire la hiérarchie Contest → Stages → Splits
|
|
|
|
|
|
for (const auto& ContestPair : ModelAsset->Contests)
|
|
|
|
|
|
{
|
|
|
|
|
|
const FString& ContestName = ContestPair.Key;
|
|
|
|
|
|
const FDTFluxContest& Contest = ContestPair.Value;
|
|
|
|
|
|
|
|
|
|
|
|
// Créer l'élément Contest racine
|
|
|
|
|
|
auto ContestItem = FHierarchicalTreeItem::CreateContest(ContestName, Contest);
|
|
|
|
|
|
|
|
|
|
|
|
// Ajouter les Stages comme enfants
|
|
|
|
|
|
for (const FDTFluxStage& Stage : Contest.Stages)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto StageItem = FHierarchicalTreeItem::CreateStage(Stage, Contest.ContestId);
|
|
|
|
|
|
ContestItem->AddChild(StageItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ajouter les Splits comme enfants directs du Contest
|
|
|
|
|
|
for (const FDTFluxSplit& Split : Contest.Splits)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto SplitItem = FHierarchicalTreeItem::CreateSplit(Split, Contest.ContestId);
|
|
|
|
|
|
ContestItem->AddChild(SplitItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RootItems.Add(ContestItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("Built contest hierarchy with %d root contests"), RootItems.Num());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::BuildParticipantList()
|
|
|
|
|
|
{
|
|
|
|
|
|
ParticipantItems.Empty();
|
|
|
|
|
|
|
|
|
|
|
|
if (!ModelAsset)
|
|
|
|
|
|
{
|
2025-07-14 02:40:03 +02:00
|
|
|
|
UE_LOG(logDTFluxAssetEditor, Warning, TEXT("BuildParticipantList: ModelAsset is null!"));
|
|
|
|
|
|
// return;
|
2025-07-08 16:50:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("BuildParticipantList: ModelAsset has %d participants"), ModelAsset->Participants.Num());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
// Créer la liste des participants (pas de hiérarchie pour les participants)
|
|
|
|
|
|
for (const auto& ParticipantPair : ModelAsset->Participants)
|
|
|
|
|
|
{
|
|
|
|
|
|
const FDTFluxParticipant& Participant = ParticipantPair.Value;
|
|
|
|
|
|
auto ParticipantItem = FHierarchicalTreeItem::CreateParticipant(Participant);
|
|
|
|
|
|
ParticipantItems.Add(ParticipantItem);
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("BuildParticipantList: Added participant %s (Bib: %d)"),
|
|
|
|
|
|
// *ParticipantItem->Name, ParticipantItem->Bib);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("BuildParticipantList: Built participant list with %d participants"),
|
|
|
|
|
|
// ParticipantItems.Num());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== CALLBACKS TREEVIEW =====
|
|
|
|
|
|
|
|
|
|
|
|
TSharedRef<ITableRow> SDTFluxAssetModelDetailsWidget::OnGenerateRowForTree(
|
|
|
|
|
|
FHierarchicalTreeItemPtr Item, const TSharedRef<STableViewBase>& OwnerTable)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!Item.IsValid())
|
|
|
|
|
|
{
|
2025-07-14 02:40:03 +02:00
|
|
|
|
UE_LOG(logDTFluxAssetEditor, Warning, TEXT("OnGenerateRowForTree: Invalid item!"));
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return SNew(STableRow<FHierarchicalTreeItemPtr>, OwnerTable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("OnGenerateRowForTree: Generating row for %s (Type: %d)"),
|
|
|
|
|
|
// *Item->Name, (int32)Item->Type);
|
2025-07-08 16:50:31 +02:00
|
|
|
|
|
|
|
|
|
|
return SNew(SHierarchicalTreeItemRow, OwnerTable)
|
|
|
|
|
|
.Item(Item)
|
|
|
|
|
|
.ParentWidget(this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::OnGetChildrenForTree(FHierarchicalTreeItemPtr Item,
|
|
|
|
|
|
TArray<FHierarchicalTreeItemPtr>& OutChildren)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Item.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
OutChildren = Item->Children;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::OnTreeSelectionChanged(FHierarchicalTreeItemPtr SelectedItem,
|
|
|
|
|
|
ESelectInfo::Type SelectInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SelectionText.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SelectedItem.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
FString TypeString;
|
|
|
|
|
|
switch (SelectedItem->Type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Contest:
|
|
|
|
|
|
TypeString = "Contest";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Stage:
|
|
|
|
|
|
TypeString = "Stage";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Split:
|
|
|
|
|
|
TypeString = "Split";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Participant:
|
|
|
|
|
|
TypeString = "Participant";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
FString SelectionInfo = FString::Printf(
|
|
|
|
|
|
TEXT("📋 Selected: %s (%s)\n🔢 ID: %s\n📄 Details: %s\n📊 Status: %s\n➕ Extra: %s\n🌟 Children: %d"),
|
|
|
|
|
|
*SelectedItem->Name,
|
|
|
|
|
|
*TypeString,
|
|
|
|
|
|
*SelectedItem->ID,
|
|
|
|
|
|
*SelectedItem->Details,
|
|
|
|
|
|
*SelectedItem->Status,
|
|
|
|
|
|
*SelectedItem->Extra,
|
|
|
|
|
|
SelectedItem->Children.Num());
|
|
|
|
|
|
SelectionText->SetText(FText::FromString(SelectionInfo));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
SelectionText->SetText(FText::FromString("Select an item to see details"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::OnSetExpansionRecursive(FHierarchicalTreeItemPtr Item, bool bIsExpanded)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Item.IsValid() && ContestTreeView.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
ContestTreeView->SetItemExpansion(Item, bIsExpanded);
|
|
|
|
|
|
|
|
|
|
|
|
// Expansion récursive des enfants
|
|
|
|
|
|
for (auto Child : Item->Children)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnSetExpansionRecursive(Child, bIsExpanded);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== CALLBACKS DES BOUTONS =====
|
|
|
|
|
|
|
|
|
|
|
|
FReply SDTFluxAssetModelDetailsWidget::OnExpandAllClicked()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ContestTreeView.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
for (auto& RootItem : RootItems)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnSetExpansionRecursive(RootItem, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("Expanded all contests"));
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return FReply::Handled();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FReply SDTFluxAssetModelDetailsWidget::OnCollapseAllClicked()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ContestTreeView.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
for (auto& RootItem : RootItems)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnSetExpansionRecursive(RootItem, false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("Collapsed all contests"));
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return FReply::Handled();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FReply SDTFluxAssetModelDetailsWidget::OnRefreshClicked()
|
|
|
|
|
|
{
|
|
|
|
|
|
RefreshData();
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("Data refreshed"));
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return FReply::Handled();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== REFRESHDATA =====
|
|
|
|
|
|
|
|
|
|
|
|
void SDTFluxAssetModelDetailsWidget::RefreshData()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ModelAsset)
|
|
|
|
|
|
{
|
2025-07-14 02:40:03 +02:00
|
|
|
|
UE_LOG(logDTFluxAssetEditor, Warning, TEXT("ModelAsset is null!"));
|
2025-07-08 16:50:31 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("RefreshData: Starting refresh for ModelAsset %s"), *ModelAsset->GetName());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
RootItems.Empty();
|
|
|
|
|
|
ParticipantItems.Empty();
|
|
|
|
|
|
|
|
|
|
|
|
BuildContestHierarchy();
|
|
|
|
|
|
BuildParticipantList();
|
|
|
|
|
|
|
|
|
|
|
|
if (ContestTreeView.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
ContestTreeView->RequestTreeRefresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ParticipantTreeView.IsValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
ParticipantTreeView->RequestTreeRefresh();
|
|
|
|
|
|
}
|
2025-07-14 02:40:03 +02:00
|
|
|
|
// UE_LOG(logDTFluxAssetEditor, Log, TEXT("RefreshData: Completed successfully - %d contests, %d participants"), RootItems.Num(),
|
|
|
|
|
|
// ParticipantItems.Num());
|
2025-07-08 16:50:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== MÉTHODES UTILITAIRES =====
|
|
|
|
|
|
|
|
|
|
|
|
FSlateColor SDTFluxAssetModelDetailsWidget::GetItemTypeColor(FHierarchicalTreeItem::EItemType Type) const
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (Type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Contest:
|
|
|
|
|
|
return FSlateColor(FLinearColor(0.2f, 0.6f, 1.0f));
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Stage:
|
|
|
|
|
|
return FSlateColor(FLinearColor(0.2f, 0.8f, 0.2f));
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Split:
|
|
|
|
|
|
return FSlateColor(FLinearColor(1.0f, 0.8f, 0.2f));
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Participant:
|
|
|
|
|
|
return FSlateColor(FLinearColor(0.2f, 0.8f, 0.8f));
|
|
|
|
|
|
default:
|
|
|
|
|
|
return FSlateColor(FLinearColor::White);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const FSlateBrush* SDTFluxAssetModelDetailsWidget::GetItemIcon(FHierarchicalTreeItem::EItemType Type) const
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (Type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Contest:
|
|
|
|
|
|
return FAppStyle::GetBrush("TreeArrow_Collapsed");
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Stage:
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Split:
|
|
|
|
|
|
return FAppStyle::GetBrush("TreeArrow_Expanded");
|
|
|
|
|
|
case FHierarchicalTreeItem::EItemType::Participant:
|
|
|
|
|
|
return FAppStyle::GetBrush("Icons.User");
|
|
|
|
|
|
default:
|
|
|
|
|
|
return FAppStyle::GetBrush("Icons.Help");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FText SDTFluxAssetModelDetailsWidget::GetStatsText() const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ModelAsset)
|
|
|
|
|
|
return FText::FromString("No data");
|
|
|
|
|
|
return FText::FromString(FString::Printf(
|
|
|
|
|
|
TEXT("Contests: [%d] Participants: [%d] Persons: [%d]"),
|
|
|
|
|
|
ModelAsset->Contests.Num(),
|
|
|
|
|
|
ModelAsset->Participants.Num(),
|
|
|
|
|
|
ModelAsset->Persons.Num()
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|